summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig3
-rw-r--r--.github/CODEOWNERS231
-rw-r--r--.github/workflows/android_builds.yml2
-rw-r--r--.github/workflows/ios_builds.yml2
-rw-r--r--.github/workflows/javascript_builds.disabled2
-rw-r--r--.github/workflows/linux_builds.yml45
-rw-r--r--.github/workflows/macos_builds.yml4
-rw-r--r--.github/workflows/static_checks.yml3
-rw-r--r--.github/workflows/windows_builds.yml6
-rw-r--r--.mailmap8
-rw-r--r--AUTHORS.md6
-rw-r--r--CHANGELOG.md4
-rw-r--r--CONTRIBUTING.md28
-rw-r--r--COPYRIGHT.txt23
-rw-r--r--DONORS.md153
-rw-r--r--README.md3
-rw-r--r--SConstruct75
-rw-r--r--core/config/project_settings.cpp249
-rw-r--r--core/config/project_settings.h14
-rw-r--r--core/core_bind.cpp97
-rw-r--r--core/core_bind.h25
-rw-r--r--core/core_constants.cpp44
-rw-r--r--core/core_string_names.cpp3
-rw-r--r--core/core_string_names.h1
-rw-r--r--core/crypto/crypto.cpp9
-rw-r--r--core/crypto/crypto.h2
-rw-r--r--core/debugger/engine_debugger.cpp2
-rw-r--r--core/debugger/remote_debugger.cpp1
-rw-r--r--core/debugger/remote_debugger_peer.cpp7
-rw-r--r--core/error/error_macros.h14
-rw-r--r--core/input/gamecontrollerdb.txt62
-rw-r--r--core/input/godotcontrollerdb.txt1
-rw-r--r--core/input/input.cpp130
-rw-r--r--core/input/input.h23
-rw-r--r--core/input/input_event.cpp117
-rw-r--r--core/input/input_event.h51
-rw-r--r--core/input/input_map.cpp596
-rw-r--r--core/input/input_map.h18
-rw-r--r--core/io/compression.cpp13
-rw-r--r--core/io/config_file.cpp5
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/file_access_compressed.cpp6
-rw-r--r--core/io/file_access_encrypted.cpp7
-rw-r--r--core/io/file_access_memory.cpp7
-rw-r--r--core/io/file_access_network.cpp3
-rw-r--r--core/io/file_access_pack.cpp3
-rw-r--r--core/io/file_access_pack.h3
-rw-r--r--core/io/file_access_zip.cpp5
-rw-r--r--core/io/http_client.cpp7
-rw-r--r--core/io/image.cpp71
-rw-r--r--core/io/image.h2
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/ip.cpp24
-rw-r--r--core/io/json.cpp68
-rw-r--r--core/io/logger.cpp10
-rw-r--r--core/io/logger.h4
-rw-r--r--core/io/marshalls.cpp16
-rw-r--r--core/io/multiplayer_api.cpp10
-rw-r--r--core/io/net_socket.h1
-rw-r--r--core/io/packed_data_container.cpp2
-rw-r--r--core/io/packet_peer_udp.cpp19
-rw-r--r--core/io/packet_peer_udp.h5
-rw-r--r--core/io/resource.cpp44
-rw-r--r--core/io/resource.h4
-rw-r--r--core/io/resource_format_binary.cpp71
-rw-r--r--core/io/resource_format_binary.h4
-rw-r--r--core/io/resource_importer.cpp38
-rw-r--r--core/io/resource_importer.h11
-rw-r--r--core/io/resource_loader.cpp36
-rw-r--r--core/io/resource_loader.h18
-rw-r--r--core/io/stream_peer.cpp4
-rw-r--r--core/io/stream_peer_tcp.cpp43
-rw-r--r--core/io/stream_peer_tcp.h6
-rw-r--r--core/io/tcp_server.cpp8
-rw-r--r--core/io/tcp_server.h1
-rw-r--r--core/io/translation_loader_po.cpp4
-rw-r--r--core/io/translation_loader_po.h2
-rw-r--r--core/io/udp_server.cpp12
-rw-r--r--core/io/udp_server.h5
-rw-r--r--core/io/xml_parser.cpp70
-rw-r--r--core/io/xml_parser.h2
-rw-r--r--core/io/zip_io.cpp4
-rw-r--r--core/math/basis.cpp7
-rw-r--r--core/math/color.cpp53
-rw-r--r--core/math/color.h8
-rw-r--r--core/math/dynamic_bvh.cpp29
-rw-r--r--core/math/dynamic_bvh.h41
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/face3.cpp2
-rw-r--r--core/math/geometry_2d.cpp12
-rw-r--r--core/math/geometry_3d.cpp6
-rw-r--r--core/math/geometry_3d.h33
-rw-r--r--core/math/math_funcs.h3
-rw-r--r--core/math/quat.cpp9
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/random_pcg.cpp2
-rw-r--r--core/math/transform.cpp1
-rw-r--r--core/math/transform.h4
-rw-r--r--core/math/triangulate.cpp2
-rw-r--r--core/math/vector3.h8
-rw-r--r--core/object/callable_method_pointer.h7
-rw-r--r--core/object/class_db.cpp4
-rw-r--r--core/object/method_bind.h1
-rw-r--r--core/object/object.cpp34
-rw-r--r--core/object/object.h26
-rw-r--r--core/object/reference.cpp4
-rw-r--r--core/object/script_language.cpp10
-rw-r--r--core/object/undo_redo.cpp2
-rw-r--r--core/os/dir_access.cpp2
-rw-r--r--core/os/dir_access.h2
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/memory.cpp27
-rw-r--r--core/os/memory.h6
-rw-r--r--core/os/os.cpp28
-rw-r--r--core/os/os.h15
-rw-r--r--core/os/pool_allocator.cpp5
-rw-r--r--core/os/thread.cpp31
-rw-r--r--core/os/thread.h7
-rw-r--r--core/os/threaded_array_processor.h10
-rw-r--r--core/register_core_types.cpp4
-rw-r--r--core/string/node_path.h2
-rw-r--r--core/string/optimized_translation.cpp (renamed from core/string/compressed_translation.cpp)32
-rw-r--r--core/string/optimized_translation.h (renamed from core/string/compressed_translation.h)14
-rw-r--r--core/string/translation.cpp35
-rw-r--r--core/string/translation_po.cpp24
-rw-r--r--core/string/ustring.cpp176
-rw-r--r--core/string/ustring.h5
-rw-r--r--core/templates/command_queue_mt.h5
-rw-r--r--core/templates/cowdata.h43
-rw-r--r--core/templates/list.h2
-rw-r--r--core/templates/local_vector.h5
-rw-r--r--core/templates/map.h2
-rw-r--r--core/templates/oa_hash_map.h1
-rw-r--r--core/templates/rid_owner.cpp2
-rw-r--r--core/templates/rid_owner.h95
-rw-r--r--core/templates/safe_refcount.cpp161
-rw-r--r--core/templates/safe_refcount.h353
-rw-r--r--core/templates/thread_work_pool.h11
-rw-r--r--core/templates/vector.h16
-rw-r--r--core/variant/array.cpp44
-rw-r--r--core/variant/array.h10
-rw-r--r--core/variant/binder_common.h243
-rw-r--r--core/variant/callable.cpp4
-rw-r--r--core/variant/variant.h3
-rw-r--r--core/variant/variant_call.cpp550
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_op.cpp8
-rw-r--r--core/variant/variant_parser.cpp45
-rw-r--r--core/variant/variant_setget.cpp123
-rw-r--r--doc/Makefile11
-rw-r--r--doc/classes/@GlobalScope.xml643
-rw-r--r--doc/classes/AABB.xml48
-rw-r--r--doc/classes/AStar.xml3
-rw-r--r--doc/classes/AStar2D.xml1
-rw-r--r--doc/classes/AnimatedSprite3D.xml5
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml22
-rw-r--r--doc/classes/AnimationPlayer.xml10
-rw-r--r--doc/classes/AnimationTree.xml10
-rw-r--r--doc/classes/Area2D.xml58
-rw-r--r--doc/classes/Area3D.xml58
-rw-r--r--doc/classes/Array.xml65
-rw-r--r--doc/classes/ArrayMesh.xml10
-rw-r--r--doc/classes/AtlasTexture.xml5
-rw-r--r--doc/classes/AudioEffectCapture.xml2
-rw-r--r--doc/classes/BackBufferCopy.xml2
-rw-r--r--doc/classes/BakedLightmapData.xml6
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/BaseMaterial3D.xml80
-rw-r--r--doc/classes/Basis.xml30
-rw-r--r--doc/classes/BoxContainer.xml2
-rw-r--r--doc/classes/Button.xml5
-rw-r--r--doc/classes/Callable.xml42
-rw-r--r--doc/classes/Camera2D.xml8
-rw-r--r--doc/classes/Camera3D.xml2
-rw-r--r--doc/classes/CanvasItem.xml2
-rw-r--r--doc/classes/CapsuleMesh.xml3
-rw-r--r--doc/classes/CharFXTransform.xml2
-rw-r--r--doc/classes/CheckBox.xml14
-rw-r--r--doc/classes/CheckButton.xml6
-rw-r--r--doc/classes/ClippedCamera3D.xml8
-rw-r--r--doc/classes/CodeEdit.xml8
-rw-r--r--doc/classes/CollisionObject2D.xml50
-rw-r--r--doc/classes/CollisionObject3D.xml50
-rw-r--r--doc/classes/CollisionPolygon3D.xml3
-rw-r--r--doc/classes/Color.xml132
-rw-r--r--doc/classes/ColorPicker.xml17
-rw-r--r--doc/classes/ColorPickerButton.xml6
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml5
-rw-r--r--doc/classes/ConfigFile.xml8
-rw-r--r--doc/classes/Control.xml69
-rw-r--r--doc/classes/CryptoKey.xml4
-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/Decal.xml4
-rw-r--r--doc/classes/Dictionary.xml22
-rw-r--r--doc/classes/Directory.xml5
-rw-r--r--doc/classes/DisplayServer.xml38
-rw-r--r--doc/classes/EditorFileSystem.xml2
-rw-r--r--doc/classes/EditorImportPlugin.xml12
-rw-r--r--doc/classes/EditorInspector.xml8
-rw-r--r--doc/classes/EditorInspectorPlugin.xml4
-rw-r--r--doc/classes/EditorInterface.xml17
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml16
-rw-r--r--doc/classes/EditorPlugin.xml10
-rw-r--r--doc/classes/EditorSceneImporter.xml16
-rw-r--r--doc/classes/EditorSceneImporterMesh.xml18
-rw-r--r--doc/classes/EditorScenePostImport.xml7
-rw-r--r--doc/classes/EditorSelection.xml1
-rw-r--r--doc/classes/EditorSettings.xml10
-rw-r--r--doc/classes/EditorVCSInterface.xml2
-rw-r--r--doc/classes/Engine.xml12
-rw-r--r--doc/classes/Environment.xml8
-rw-r--r--doc/classes/File.xml11
-rw-r--r--doc/classes/FileDialog.xml6
-rw-r--r--doc/classes/Font.xml9
-rw-r--r--doc/classes/FontData.xml86
-rw-r--r--doc/classes/GIProbe.xml3
-rw-r--r--doc/classes/GPUParticles3D.xml20
-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/GraphEdit.xml2
-rw-r--r--doc/classes/GraphNode.xml9
-rw-r--r--doc/classes/HTTPClient.xml2
-rw-r--r--doc/classes/HTTPRequest.xml2
-rw-r--r--doc/classes/HeightMapShape3D.xml2
-rw-r--r--doc/classes/IP.xml2
-rw-r--r--doc/classes/Image.xml19
-rw-r--r--doc/classes/ImageTexture.xml6
-rw-r--r--doc/classes/Input.xml26
-rw-r--r--doc/classes/InputEvent.xml8
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventJoypadButton.xml2
-rw-r--r--doc/classes/InputEventJoypadMotion.xml2
-rw-r--r--doc/classes/InputEventKey.xml4
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/InputMap.xml2
-rw-r--r--doc/classes/ItemList.xml27
-rw-r--r--doc/classes/KinematicBody2D.xml5
-rw-r--r--doc/classes/KinematicBody3D.xml5
-rw-r--r--doc/classes/Label.xml2
-rw-r--r--doc/classes/LargeTexture.xml90
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LineEdit.xml86
-rw-r--r--doc/classes/LinkButton.xml6
-rw-r--r--doc/classes/MarginContainer.xml20
-rw-r--r--doc/classes/MenuButton.xml8
-rw-r--r--doc/classes/MeshInstance3D.xml15
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/Navigation2D.xml59
-rw-r--r--doc/classes/Navigation3D.xml84
-rw-r--r--doc/classes/NavigationAgent2D.xml24
-rw-r--r--doc/classes/NavigationAgent3D.xml24
-rw-r--r--doc/classes/NavigationMesh.xml5
-rw-r--r--doc/classes/NavigationObstacle2D.xml18
-rw-r--r--doc/classes/NavigationObstacle3D.xml18
-rw-r--r--doc/classes/NavigationRegion2D.xml9
-rw-r--r--doc/classes/NavigationRegion3D.xml6
-rw-r--r--doc/classes/NavigationServer2D.xml71
-rw-r--r--doc/classes/NavigationServer3D.xml75
-rw-r--r--doc/classes/Node.xml58
-rw-r--r--doc/classes/Node3D.xml4
-rw-r--r--doc/classes/NodePath.xml18
-rw-r--r--doc/classes/OS.xml60
-rw-r--r--doc/classes/Object.xml12
-rw-r--r--doc/classes/Occluder3D.xml19
-rw-r--r--doc/classes/OccluderInstance3D.xml37
-rw-r--r--doc/classes/OptimizedTranslation.xml (renamed from doc/classes/PHashTranslation.xml)2
-rw-r--r--doc/classes/OptionButton.xml6
-rw-r--r--doc/classes/PackedByteArray.xml287
-rw-r--r--doc/classes/PackedColorArray.xml31
-rw-r--r--doc/classes/PackedFloat32Array.xml39
-rw-r--r--doc/classes/PackedFloat64Array.xml31
-rw-r--r--doc/classes/PackedInt32Array.xml31
-rw-r--r--doc/classes/PackedInt64Array.xml31
-rw-r--r--doc/classes/PackedScene.xml2
-rw-r--r--doc/classes/PackedStringArray.xml31
-rw-r--r--doc/classes/PackedVector2Array.xml31
-rw-r--r--doc/classes/PackedVector3Array.xml31
-rw-r--r--doc/classes/PacketPeerUDP.xml51
-rw-r--r--doc/classes/ParticlesMaterial.xml4
-rw-r--r--doc/classes/PhysicalBone3D.xml2
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml8
-rw-r--r--doc/classes/PhysicsBody2D.xml48
-rw-r--r--doc/classes/PhysicsBody3D.xml50
-rw-r--r--doc/classes/PhysicsServer2D.xml112
-rw-r--r--doc/classes/PhysicsServer3D.xml235
-rw-r--r--doc/classes/Plane.xml20
-rw-r--r--doc/classes/PopupMenu.xml16
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProgressBar.xml6
-rw-r--r--doc/classes/ProjectSettings.xml705
-rw-r--r--doc/classes/Quat.xml24
-rw-r--r--doc/classes/RID.xml2
-rw-r--r--doc/classes/RayCast3D.xml7
-rw-r--r--doc/classes/Rect2.xml28
-rw-r--r--doc/classes/Rect2i.xml26
-rw-r--r--doc/classes/RenderingDevice.xml2
-rw-r--r--doc/classes/RenderingServer.xml96
-rw-r--r--doc/classes/ResourceFormatLoader.xml13
-rw-r--r--doc/classes/ResourceLoader.xml10
-rw-r--r--doc/classes/RibbonTrailMesh.xml31
-rw-r--r--doc/classes/RichTextEffect.xml10
-rw-r--r--doc/classes/RichTextLabel.xml27
-rw-r--r--doc/classes/RigidBody2D.xml2
-rw-r--r--doc/classes/SceneTree.xml45
-rw-r--r--doc/classes/SceneTreeTimer.xml14
-rw-r--r--doc/classes/ScriptCreateDialog.xml20
-rw-r--r--doc/classes/Shape3D.xml3
-rw-r--r--doc/classes/Signal.xml14
-rw-r--r--doc/classes/Skeleton3D.xml12
-rw-r--r--doc/classes/Sky.xml6
-rw-r--r--doc/classes/SoftBody3D.xml12
-rw-r--r--doc/classes/SpinBox.xml14
-rw-r--r--doc/classes/Sprite2D.xml29
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml4
-rw-r--r--doc/classes/StreamPeer.xml18
-rw-r--r--doc/classes/StreamPeerTCP.xml25
-rw-r--r--doc/classes/String.xml253
-rw-r--r--doc/classes/StringName.xml2
-rw-r--r--doc/classes/StyleBoxFlat.xml8
-rw-r--r--doc/classes/SubViewport.xml3
-rw-r--r--doc/classes/SurfaceTool.xml35
-rw-r--r--doc/classes/TCP_Server.xml7
-rw-r--r--doc/classes/TabContainer.xml6
-rw-r--r--doc/classes/Tabs.xml11
-rw-r--r--doc/classes/TextEdit.xml25
-rw-r--r--doc/classes/TextParagraph.xml16
-rw-r--r--doc/classes/TextServer.xml125
-rw-r--r--doc/classes/Texture2D.xml12
-rw-r--r--doc/classes/Theme.xml216
-rw-r--r--doc/classes/TileMap.xml19
-rw-r--r--doc/classes/Timer.xml10
-rw-r--r--doc/classes/TouchScreenButton.xml7
-rw-r--r--doc/classes/Transform.xml20
-rw-r--r--doc/classes/Transform2D.xml26
-rw-r--r--doc/classes/Tree.xml58
-rw-r--r--doc/classes/TreeItem.xml6
-rw-r--r--doc/classes/TubeTrailMesh.xml27
-rw-r--r--doc/classes/Tween.xml15
-rw-r--r--doc/classes/UDPServer.xml95
-rw-r--r--doc/classes/UndoRedo.xml39
-rw-r--r--doc/classes/Vector2.xml70
-rw-r--r--doc/classes/Vector2i.xml6
-rw-r--r--doc/classes/Vector3.xml83
-rw-r--r--doc/classes/Vector3i.xml8
-rw-r--r--doc/classes/VideoPlayer.xml1
-rw-r--r--doc/classes/Viewport.xml11
-rw-r--r--doc/classes/VisualShader.xml4
-rw-r--r--doc/classes/VisualShaderNodeComment.xml23
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml2
-rw-r--r--doc/classes/VisualShaderNodeDeterminant.xml2
-rw-r--r--doc/classes/VisualShaderNodeExpression.xml2
-rw-r--r--doc/classes/VisualShaderNodeFaceForward.xml2
-rw-r--r--doc/classes/VisualShaderNodeGroupBase.xml4
-rw-r--r--doc/classes/VisualShaderNodeIf.xml2
-rw-r--r--doc/classes/VisualShaderNodeInput.xml2
-rw-r--r--doc/classes/VisualShaderNodeSDFToScreenUV.xml2
-rw-r--r--doc/classes/VisualShaderNodeScreenUVToSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeSmoothStep.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDF.xml2
-rw-r--r--doc/classes/VisualShaderNodeTextureSDFNormal.xml2
-rw-r--r--doc/classes/Window.xml13
-rw-r--r--doc/classes/World2D.xml3
-rw-r--r--doc/classes/World3D.xml3
-rw-r--r--doc/classes/XRController3D.xml2
-rw-r--r--doc/classes/XRPositionalTracker.xml2
-rw-r--r--doc/classes/XRServer.xml45
-rw-r--r--doc/classes/bool.xml7
-rw-r--r--doc/classes/float.xml45
-rw-r--r--doc/classes/int.xml98
-rwxr-xr-xdoc/tools/makerst.py17
-rw-r--r--doc/translations/README.md1
-rw-r--r--doc/translations/classes.pot14
-rw-r--r--doc/translations/fr.po14
-rw-r--r--drivers/alsa/SCsub3
-rw-r--r--drivers/alsa/asound-so_wrap.c14092
-rw-r--r--drivers/alsa/asound-so_wrap.h5134
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp25
-rw-r--r--drivers/alsa/audio_driver_alsa.h2
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h2
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp60
-rw-r--r--drivers/dummy/rasterizer_dummy.h449
-rw-r--r--drivers/dummy/texture_loader_dummy.cpp2
-rw-r--r--drivers/dummy/texture_loader_dummy.h2
-rw-r--r--drivers/png/image_loader_png.cpp2
-rw-r--r--drivers/png/png_driver_common.cpp4
-rw-r--r--drivers/png/resource_saver_png.cpp2
-rw-r--r--drivers/pulseaudio/SCsub3
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp13
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h2
-rw-r--r--drivers/pulseaudio/pulse-so_wrap.c3950
-rw-r--r--drivers/pulseaudio/pulse-so_wrap.h1446
-rw-r--r--drivers/unix/dir_access_unix.cpp34
-rw-r--r--drivers/unix/dir_access_unix.h2
-rw-r--r--drivers/unix/file_access_unix.cpp2
-rw-r--r--drivers/unix/net_socket_posix.cpp75
-rw-r--r--drivers/unix/net_socket_posix.h7
-rw-r--r--drivers/unix/thread_posix.cpp4
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp51
-rw-r--r--drivers/vulkan/vulkan_context.cpp448
-rw-r--r--drivers/vulkan/vulkan_context.h56
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp2
-rw-r--r--drivers/windows/file_access_windows.cpp2
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp4
-rw-r--r--editor/action_map_editor.cpp1167
-rw-r--r--editor/action_map_editor.h203
-rw-r--r--editor/animation_bezier_editor.cpp20
-rw-r--r--editor/animation_track_editor.cpp121
-rw-r--r--editor/animation_track_editor.h4
-rw-r--r--editor/animation_track_editor_plugins.cpp76
-rw-r--r--editor/array_property_edit.cpp11
-rw-r--r--editor/array_property_edit.h1
-rw-r--r--editor/audio_stream_preview.cpp6
-rw-r--r--editor/audio_stream_preview.h14
-rw-r--r--editor/code_editor.cpp18
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/create_dialog.cpp5
-rw-r--r--editor/debugger/editor_debugger_inspector.h2
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp2
-rw-r--r--editor/debugger/editor_profiler.cpp200
-rw-r--r--editor/debugger/editor_profiler.h6
-rw-r--r--editor/debugger/editor_visual_profiler.cpp4
-rw-r--r--editor/debugger/script_editor_debugger.cpp79
-rw-r--r--editor/debugger/script_editor_debugger.h5
-rw-r--r--editor/dependency_editor.cpp14
-rw-r--r--editor/dictionary_property_edit.cpp11
-rw-r--r--editor/dictionary_property_edit.h1
-rw-r--r--editor/doc_tools.cpp25
-rw-r--r--editor/editor_about.cpp7
-rw-r--r--editor/editor_about.h4
-rw-r--r--editor/editor_audio_buses.cpp16
-rw-r--r--editor/editor_data.cpp56
-rw-r--r--editor/editor_data.h5
-rw-r--r--editor/editor_export.cpp128
-rw-r--r--editor/editor_export.h1
-rw-r--r--editor/editor_feature_profile.cpp6
-rw-r--r--editor/editor_file_dialog.cpp7
-rw-r--r--editor/editor_file_system.cpp175
-rw-r--r--editor/editor_file_system.h27
-rw-r--r--editor/editor_folding.cpp16
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_help_search.cpp27
-rw-r--r--editor/editor_help_search.h1
-rw-r--r--editor/editor_inspector.cpp153
-rw-r--r--editor/editor_inspector.h16
-rw-r--r--editor/editor_node.cpp405
-rw-r--r--editor/editor_node.h22
-rw-r--r--editor/editor_plugin.cpp24
-rw-r--r--editor/editor_plugin.h6
-rw-r--r--editor/editor_properties.cpp90
-rw-r--r--editor/editor_properties.h5
-rw-r--r--editor/editor_properties_array_dict.cpp6
-rw-r--r--editor/editor_properties_array_dict.h8
-rw-r--r--editor/editor_resource_preview.cpp14
-rw-r--r--editor/editor_resource_preview.h5
-rw-r--r--editor/editor_run_native.cpp2
-rw-r--r--editor/editor_sectioned_inspector.cpp12
-rw-r--r--editor/editor_sectioned_inspector.h3
-rw-r--r--editor/editor_settings.cpp168
-rw-r--r--editor/editor_settings.h6
-rw-r--r--editor/editor_spin_slider.cpp20
-rw-r--r--editor/editor_sub_scene.cpp265
-rw-r--r--editor/editor_themes.cpp118
-rw-r--r--editor/editor_themes.h3
-rw-r--r--editor/editor_translation_parser.cpp8
-rw-r--r--editor/export_template_manager.cpp11
-rw-r--r--editor/fileserver/editor_file_server.cpp5
-rw-r--r--editor/fileserver/editor_file_server.h2
-rw-r--r--editor/filesystem_dock.cpp89
-rw-r--r--editor/find_in_files.cpp5
-rw-r--r--editor/icons/ColorPickerBarArrow.svg1
-rw-r--r--editor/icons/FontSize.svg1
-rw-r--r--editor/icons/GPUParticlesAttractorBox.svg1
-rw-r--r--editor/icons/GPUParticlesAttractorSphere.svg1
-rw-r--r--editor/icons/GPUParticlesAttractorVectorField.svg1
-rw-r--r--editor/icons/GPUParticlesCollisionBox.svg1
-rw-r--r--editor/icons/GPUParticlesCollisionHeightField.svg1
-rw-r--r--editor/icons/GPUParticlesCollisionSDF.svg1
-rw-r--r--editor/icons/GPUParticlesCollisionSphere.svg1
-rw-r--r--editor/icons/GuiScrollBg.svg2
-rw-r--r--editor/icons/GuiScrollGrabber.svg2
-rw-r--r--editor/icons/LargeTexture.svg1
-rw-r--r--editor/icons/Logo.svg2
-rw-r--r--editor/icons/NodeDisabled.svg1
-rw-r--r--editor/icons/PickerCursor.svg1
-rw-r--r--editor/icons/ThemeRemoveAllItems.svg1
-rw-r--r--editor/icons/ThemeRemoveCustomItems.svg1
-rw-r--r--editor/import/editor_import_collada.cpp85
-rw-r--r--editor/import/resource_importer_csv_translation.cpp4
-rw-r--r--editor/import/resource_importer_layered_texture.cpp12
-rw-r--r--editor/import/resource_importer_obj.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp1300
-rw-r--r--editor/import/resource_importer_scene.h92
-rw-r--r--editor/import/resource_importer_texture.cpp16
-rw-r--r--editor/import/scene_import_settings.cpp1199
-rw-r--r--editor/import/scene_import_settings.h199
-rw-r--r--editor/import/scene_importer_mesh.cpp357
-rw-r--r--editor/import/scene_importer_mesh.h18
-rw-r--r--editor/import_defaults_editor.cpp216
-rw-r--r--editor/import_defaults_editor.h (renamed from scene/2d/navigation_2d.h)66
-rw-r--r--editor/import_dock.cpp164
-rw-r--r--editor/import_dock.h4
-rw-r--r--editor/input_map_editor.cpp1033
-rw-r--r--editor/localization_editor.cpp167
-rw-r--r--editor/localization_editor.h7
-rw-r--r--editor/node_3d_editor_gizmos.cpp134
-rw-r--r--editor/node_3d_editor_gizmos.h24
-rw-r--r--editor/plugin_config_dialog.cpp8
-rw-r--r--editor/plugin_config_dialog.h2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp12
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp11
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp12
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp69
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp15
-rw-r--r--editor/plugins/audio_stream_editor_plugin.h22
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp231
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h10
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/curve_editor_plugin.cpp8
-rw-r--r--editor/plugins/editor_preview_plugins.cpp77
-rw-r--r--editor/plugins/editor_preview_plugins.h8
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp12
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp636
-rw-r--r--editor/plugins/node_3d_editor_plugin.h65
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp117
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.h (renamed from editor/editor_sub_scene.h)53
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_editor_plugin.cpp20
-rw-r--r--editor/plugins/script_editor_plugin.h2
-rw-r--r--editor/plugins/script_text_editor.cpp50
-rw-r--r--editor/plugins/shader_editor_plugin.cpp38
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp61
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp9
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp30
-rw-r--r--editor/plugins/text_editor.cpp30
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/texture_3d_editor_plugin.h4
-rw-r--r--editor/plugins/texture_editor_plugin.cpp10
-rw-r--r--editor/plugins/texture_editor_plugin.h2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp13
-rw-r--r--editor/plugins/texture_layered_editor_plugin.h3
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp33
-rw-r--r--editor/plugins/texture_region_editor_plugin.h4
-rw-r--r--editor/plugins/theme_editor_plugin.cpp1141
-rw-r--r--editor/plugins/theme_editor_plugin.h108
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp33
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp61
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp292
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h37
-rw-r--r--editor/pot_generator.cpp8
-rw-r--r--editor/project_export.cpp3
-rw-r--r--editor/project_manager.cpp156
-rw-r--r--editor/project_manager.h11
-rw-r--r--editor/project_settings_editor.cpp267
-rw-r--r--editor/project_settings_editor.h25
-rw-r--r--editor/property_editor.cpp25
-rw-r--r--editor/rename_dialog.cpp7
-rw-r--r--editor/scene_tree_dock.cpp366
-rw-r--r--editor/scene_tree_dock.h26
-rw-r--r--editor/scene_tree_editor.cpp44
-rw-r--r--editor/scene_tree_editor.h6
-rw-r--r--editor/script_create_dialog.cpp34
-rw-r--r--editor/script_create_dialog.h2
-rw-r--r--editor/settings_config_dialog.cpp351
-rw-r--r--editor/settings_config_dialog.h33
-rw-r--r--editor/shader_globals_editor.cpp5
-rw-r--r--editor/translations/af.po145
-rw-r--r--editor/translations/ar.po275
-rw-r--r--editor/translations/bg.po274
-rw-r--r--editor/translations/bn.po161
-rw-r--r--editor/translations/br.po125
-rw-r--r--editor/translations/ca.po138
-rw-r--r--editor/translations/cs.po230
-rw-r--r--editor/translations/da.po262
-rw-r--r--editor/translations/de.po173
-rw-r--r--editor/translations/editor.pot125
-rw-r--r--editor/translations/el.po170
-rw-r--r--editor/translations/eo.po932
-rw-r--r--editor/translations/es.po344
-rw-r--r--editor/translations/es_AR.po153
-rw-r--r--editor/translations/et.po206
-rw-r--r--editor/translations/eu.po131
-rw-r--r--editor/translations/fa.po154
-rw-r--r--editor/translations/fi.po154
-rw-r--r--editor/translations/fil.po126
-rw-r--r--editor/translations/fr.po173
-rw-r--r--editor/translations/ga.po125
-rw-r--r--editor/translations/gl.po2851
-rw-r--r--editor/translations/he.po172
-rw-r--r--editor/translations/hi.po134
-rw-r--r--editor/translations/hr.po140
-rw-r--r--editor/translations/hu.po539
-rw-r--r--editor/translations/id.po539
-rw-r--r--editor/translations/is.po128
-rw-r--r--editor/translations/it.po334
-rw-r--r--editor/translations/ja.po193
-rw-r--r--editor/translations/ka.po129
-rw-r--r--editor/translations/km.po12486
-rw-r--r--editor/translations/ko.po508
-rw-r--r--editor/translations/lt.po141
-rw-r--r--editor/translations/lv.po132
-rw-r--r--editor/translations/mi.po125
-rw-r--r--editor/translations/mk.po125
-rw-r--r--editor/translations/ml.po125
-rw-r--r--editor/translations/mr.po125
-rw-r--r--editor/translations/ms.po136
-rw-r--r--editor/translations/nb.po807
-rw-r--r--editor/translations/nl.po239
-rw-r--r--editor/translations/or.po125
-rw-r--r--editor/translations/pl.po180
-rw-r--r--editor/translations/pr.po128
-rw-r--r--editor/translations/pt.po148
-rw-r--r--editor/translations/pt_BR.po189
-rw-r--r--editor/translations/ro.po191
-rw-r--r--editor/translations/ru.po161
-rw-r--r--editor/translations/si.po127
-rw-r--r--editor/translations/sk.po163
-rw-r--r--editor/translations/sl.po138
-rw-r--r--editor/translations/sq.po133
-rw-r--r--editor/translations/sr_Cyrl.po142
-rw-r--r--editor/translations/sr_Latn.po128
-rw-r--r--editor/translations/sv.po770
-rw-r--r--editor/translations/ta.po128
-rw-r--r--editor/translations/te.po125
-rw-r--r--editor/translations/th.po214
-rw-r--r--editor/translations/tr.po173
-rw-r--r--editor/translations/tzm.po125
-rw-r--r--editor/translations/uk.po155
-rw-r--r--editor/translations/ur_PK.po129
-rw-r--r--editor/translations/vi.po3101
-rw-r--r--editor/translations/zh_CN.po232
-rw-r--r--editor/translations/zh_HK.po139
-rw-r--r--editor/translations/zh_TW.po140
-rw-r--r--main/main.cpp287
-rw-r--r--main/main.h2
-rw-r--r--main/main_builders.py5
-rw-r--r--main/performance.cpp2
-rw-r--r--methods.py30
-rw-r--r--misc/dist/html/editor.html301
-rw-r--r--misc/dist/html/full-size.html76
-rw-r--r--misc/dist/html/manifest.json18
-rw-r--r--misc/dist/html/offline-export.html42
-rw-r--r--misc/dist/html/offline.html42
-rw-r--r--misc/dist/html/service-worker.js73
-rw-r--r--misc/dist/linux/org.godotengine.Godot.xml29
-rw-r--r--misc/dist/linux/x-godot-project.xml8
-rw-r--r--misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json2
-rw-r--r--misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json2
-rw-r--r--misc/dist/project_icon.svg2
-rwxr-xr-xmisc/hooks/pre-commit-clang-format5
-rwxr-xr-xmisc/scripts/check_ci_log.py65
-rwxr-xr-xmisc/scripts/clang_format.sh2
-rwxr-xr-xmisc/scripts/file_format.sh11
-rw-r--r--modules/bullet/bullet_physics_server.cpp108
-rw-r--r--modules/bullet/bullet_physics_server.h37
-rw-r--r--modules/bullet/bullet_types_converter.cpp2
-rw-r--r--modules/bullet/collision_object_bullet.cpp8
-rw-r--r--modules/bullet/config.py3
-rw-r--r--modules/bullet/godot_collision_dispatcher.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp18
-rw-r--r--modules/bullet/rigid_body_bullet.h5
-rw-r--r--modules/bullet/shape_bullet.cpp35
-rw-r--r--modules/bullet/shape_bullet.h6
-rw-r--r--modules/bullet/soft_body_bullet.cpp65
-rw-r--r--modules/bullet/soft_body_bullet.h22
-rw-r--r--modules/bullet/space_bullet.cpp6
-rw-r--r--modules/camera/camera_osx.mm24
-rw-r--r--modules/csg/csg.cpp12
-rw-r--r--modules/csg/csg_gizmos.cpp36
-rw-r--r--modules/csg/csg_shape.cpp37
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml3
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp7
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/dds/texture_loader_dds.h2
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml27
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp78
-rw-r--r--modules/enet/networked_multiplayer_enet.h4
-rw-r--r--modules/etc/SCsub48
-rw-r--r--modules/etc/image_compress_etc.cpp226
-rw-r--r--modules/etc/texture_loader_pkm.cpp114
-rw-r--r--modules/etcpak/SCsub36
-rw-r--r--modules/etcpak/config.py (renamed from modules/etc/config.py)0
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp184
-rw-r--r--modules/etcpak/image_compress_etcpak.h52
-rw-r--r--modules/etcpak/register_types.cpp42
-rw-r--r--modules/etcpak/register_types.h (renamed from modules/etc/image_compress_etc.h)11
-rw-r--r--modules/fbx/SCsub3
-rw-r--r--modules/fbx/data/fbx_material.cpp4
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp36
-rw-r--r--modules/fbx/data/fbx_mesh_data.h18
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp2
-rw-r--r--modules/fbx/data/pivot_transform.cpp2
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp64
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h2
-rw-r--r--modules/fbx/fbx_parser/ByteSwapper.h3
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp19
-rw-r--r--modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp41
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp8
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp103
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h131
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp39
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.h7
-rw-r--r--modules/fbx/fbx_parser/FBXImportSettings.h71
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp35
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.h2
-rw-r--r--modules/fbx/fbx_parser/FBXModel.cpp5
-rw-r--r--modules/fbx/fbx_parser/FBXNodeAttribute.cpp11
-rw-r--r--modules/fbx/fbx_parser/FBXParseTools.h2
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp42
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h9
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp47
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.h27
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.cpp4
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.h4
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp8
-rw-r--r--modules/fbx/tools/import_utils.h6
-rw-r--r--modules/fbx/tools/validation_tools.h3
-rw-r--r--modules/gdnative/gdnative.cpp14
-rw-r--r--modules/gdnative/gdnative.h4
-rw-r--r--modules/gdnative/gdnative/aabb.cpp4
-rw-r--r--modules/gdnative/gdnative/array.cpp14
-rw-r--r--modules/gdnative/gdnative/basis.cpp14
-rw-r--r--modules/gdnative/gdnative/callable.cpp4
-rw-r--r--modules/gdnative/gdnative/color.cpp14
-rw-r--r--modules/gdnative/gdnative/dictionary.cpp15
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp11
-rw-r--r--modules/gdnative/gdnative/node_path.cpp4
-rw-r--r--modules/gdnative/gdnative/packed_arrays.cpp154
-rw-r--r--modules/gdnative/gdnative/plane.cpp4
-rw-r--r--modules/gdnative/gdnative/quat.cpp14
-rw-r--r--modules/gdnative/gdnative/rect2.cpp8
-rw-r--r--modules/gdnative/gdnative/rid.cpp4
-rw-r--r--modules/gdnative/gdnative/signal.cpp4
-rw-r--r--modules/gdnative/gdnative/string.cpp44
-rw-r--r--modules/gdnative/gdnative/string_name.cpp4
-rw-r--r--modules/gdnative/gdnative/transform.cpp4
-rw-r--r--modules/gdnative/gdnative/transform2d.cpp14
-rw-r--r--modules/gdnative/gdnative/variant.cpp97
-rw-r--r--modules/gdnative/gdnative/vector2.cpp28
-rw-r--r--modules/gdnative/gdnative/vector3.cpp28
-rw-r--r--modules/gdnative/gdnative_api.json1314
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp2
-rw-r--r--modules/gdnative/include/gdnative/aabb.h1
-rw-r--r--modules/gdnative/include/gdnative/array.h4
-rw-r--r--modules/gdnative/include/gdnative/basis.h3
-rw-r--r--modules/gdnative/include/gdnative/callable.h1
-rw-r--r--modules/gdnative/include/gdnative/color.h3
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h4
-rw-r--r--modules/gdnative/include/gdnative/gdnative.h11
-rw-r--r--modules/gdnative/include/gdnative/node_path.h1
-rw-r--r--modules/gdnative/include/gdnative/packed_arrays.h40
-rw-r--r--modules/gdnative/include/gdnative/plane.h1
-rw-r--r--modules/gdnative/include/gdnative/quat.h3
-rw-r--r--modules/gdnative/include/gdnative/rect2.h2
-rw-r--r--modules/gdnative/include/gdnative/rid.h1
-rw-r--r--modules/gdnative/include/gdnative/signal.h1
-rw-r--r--modules/gdnative/include/gdnative/string.h10
-rw-r--r--modules/gdnative/include/gdnative/transform.h1
-rw-r--r--modules/gdnative/include/gdnative/transform2d.h3
-rw-r--r--modules/gdnative/include/gdnative/variant.h18
-rw-r--r--modules/gdnative/include/gdnative/variant_struct.h (renamed from core/os/copymem.h)31
-rw-r--r--modules/gdnative/include/gdnative/vector2.h6
-rw-r--r--modules/gdnative/include/gdnative/vector3.h6
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h2
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h1
-rw-r--r--modules/gdnative/include/text/godot_text.h11
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp43
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp56
-rw-r--r--modules/gdnative/nativescript/nativescript.h9
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp7
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.h2
-rw-r--r--modules/gdnative/register_types.cpp2
-rw-r--r--modules/gdnative/tests/test_variant.h3
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp52
-rw-r--r--modules/gdnative/text/text_server_gdnative.h13
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.cpp4
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.h2
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.cpp27
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp68
-rw-r--r--modules/gdnavigation/gd_navigation_server.h11
-rw-r--r--modules/gdnavigation/nav_map.cpp526
-rw-r--r--modules/gdnavigation/nav_map.h3
-rw-r--r--modules/gdnavigation/nav_region.cpp30
-rw-r--r--modules/gdnavigation/nav_region.h16
-rw-r--r--modules/gdnavigation/nav_utils.h39
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp50
-rw-r--r--modules/gdscript/gdscript.h3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp456
-rw-r--r--modules/gdscript/gdscript_analyzer.h7
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp405
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h109
-rw-r--r--modules/gdscript/gdscript_codegen.h17
-rw-r--r--modules/gdscript/gdscript_compiler.cpp256
-rw-r--r--modules/gdscript/gdscript_compiler.h6
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp219
-rw-r--r--modules/gdscript/gdscript_editor.cpp61
-rw-r--r--modules/gdscript/gdscript_function.cpp6
-rw-r--r--modules/gdscript/gdscript_function.h137
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp95
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h (renamed from editor/import/resource_importer_csv.h)46
-rw-r--r--modules/gdscript/gdscript_parser.cpp440
-rw-r--r--modules/gdscript/gdscript_parser.h116
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp15
-rw-r--r--modules/gdscript/gdscript_tokenizer.h3
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp565
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp3
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp1
-rw-r--r--modules/gdscript/language_server/lsp.hpp2
-rw-r--r--modules/gdscript/register_types.cpp11
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp584
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h (renamed from modules/mono/editor/script_class_parser.h)134
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h (renamed from modules/etc/texture_loader_pkm.h)34
-rw-r--r--modules/gdscript/tests/scripts/.gitignore2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_argument.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_argument.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_colon.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_colon.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.out7
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_variable.out5
-rw-r--r--modules/gdscript/tests/scripts/project.godot10
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp95
-rw-r--r--modules/gdscript/tests/test_gdscript.h8
-rw-r--r--modules/glslang/register_types.cpp65
-rw-r--r--modules/gltf/config.py24
-rw-r--r--modules/gltf/doc_classes/EditorSceneImporterGLTF.xml (renamed from doc/classes/EditorSceneImporterGLTF.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFAccessor.xml (renamed from doc/classes/GLTFAccessor.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFAnimation.xml (renamed from doc/classes/GLTFAnimation.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFBufferView.xml (renamed from doc/classes/GLTFBufferView.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml (renamed from doc/classes/GLTFCamera.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml (renamed from doc/classes/GLTFDocument.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml (renamed from doc/classes/GLTFLight.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml (renamed from doc/classes/GLTFMesh.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml (renamed from doc/classes/GLTFNode.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml (renamed from doc/classes/GLTFSkeleton.xml)2
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml (renamed from doc/classes/GLTFSkin.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFSpecGloss.xml (renamed from doc/classes/GLTFSpecGloss.xml)0
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml (renamed from doc/classes/GLTFState.xml)20
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml (renamed from doc/classes/GLTFTexture.xml)2
-rw-r--r--modules/gltf/doc_classes/PackedSceneGLTF.xml (renamed from doc/classes/PackedSceneGLTF.xml)0
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp4
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h6
-rw-r--r--modules/gltf/gltf_document.cpp287
-rw-r--r--modules/gltf/gltf_document.h3
-rw-r--r--modules/gltf/gltf_skeleton.cpp2
-rw-r--r--modules/gltf/gltf_skin.cpp2
-rw-r--r--modules/gltf/gltf_state.cpp17
-rw-r--r--modules/gltf/gltf_state.h5
-rw-r--r--modules/gltf/gltf_texture.h2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml7
-rw-r--r--modules/gridmap/grid_map.cpp89
-rw-r--r--modules/gridmap/grid_map.h10
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp29
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp30
-rw-r--r--modules/lightmapper_rd/lm_blendseams.glsl4
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl2
-rw-r--r--modules/lightmapper_rd/lm_raster.glsl4
-rw-r--r--modules/lightmapper_rd/register_types.cpp22
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp6
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp6
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp2
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp10
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp12
-rw-r--r--modules/mono/Directory.Build.props3
-rw-r--r--modules/mono/SdkPackageVersions.props6
-rw-r--r--modules/mono/build_scripts/godot_net_sdk_build.py24
-rw-r--r--modules/mono/csharp_script.cpp146
-rw-r--r--modules/mono/csharp_script.h38
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj43
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec22
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs15
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs11
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj31
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs33
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs89
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj40
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props7
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs182
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs47
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs31
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs86
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs61
-rw-r--r--modules/mono/editor/bindings_generator.cpp262
-rw-r--r--modules/mono/editor/bindings_generator.h1
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp47
-rw-r--r--modules/mono/editor/godotsharp_export.cpp2
-rw-r--r--modules/mono/editor/script_class_parser.cpp753
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs9
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj6
-rw-r--r--modules/mono/godotsharp_dirs.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp5
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp103
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h13
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp13
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h3
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h2
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp4
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm8
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml6
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml1
-rw-r--r--modules/opensimplex/noise_texture.cpp16
-rw-r--r--modules/opensimplex/noise_texture.h6
-rw-r--r--modules/pvr/image_compress_pvrtc.cpp2
-rw-r--r--modules/pvr/texture_loader_pvr.cpp2
-rw-r--r--modules/pvr/texture_loader_pvr.h2
-rw-r--r--modules/raycast/SCsub86
-rw-r--r--modules/raycast/config.py12
-rw-r--r--modules/raycast/godot_update_embree.py260
-rw-r--r--modules/raycast/lightmap_raycaster.cpp202
-rw-r--r--modules/raycast/lightmap_raycaster.h77
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp583
-rw-r--r--modules/raycast/raycast_occlusion_cull.h184
-rw-r--r--modules/raycast/register_types.cpp (renamed from modules/etc/register_types.cpp)23
-rw-r--r--modules/raycast/register_types.h (renamed from modules/etc/register_types.h)9
-rw-r--r--modules/squish/image_decompress_squish.cpp (renamed from modules/squish/image_compress_squish.cpp)84
-rw-r--r--modules/squish/image_decompress_squish.h (renamed from modules/squish/image_compress_squish.h)9
-rw-r--r--modules/squish/register_types.cpp4
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp6
-rw-r--r--modules/text_server_adv/SCsub47
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp111
-rw-r--r--modules/text_server_adv/bitmap_font_adv.h11
-rw-r--r--modules/text_server_adv/config.py2
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp41
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h8
-rw-r--r--modules/text_server_adv/font_adv.h29
-rw-r--r--modules/text_server_adv/script_iterator.cpp6
-rw-r--r--modules/text_server_adv/text_server_adv.cpp102
-rw-r--r--modules/text_server_adv/text_server_adv.h13
-rw-r--r--modules/text_server_fb/bitmap_font_fb.cpp92
-rw-r--r--modules/text_server_fb/bitmap_font_fb.h6
-rw-r--r--modules/text_server_fb/config.py2
-rw-r--r--modules/text_server_fb/dynamic_font_fb.cpp32
-rw-r--r--modules/text_server_fb/dynamic_font_fb.h8
-rw-r--r--modules/text_server_fb/font_fb.h25
-rw-r--r--modules/text_server_fb/text_server_fb.cpp91
-rw-r--r--modules/text_server_fb/text_server_fb.h13
-rw-r--r--modules/theora/video_stream_theora.cpp9
-rw-r--r--modules/theora/video_stream_theora.h5
-rw-r--r--modules/upnp/SCsub15
-rw-r--r--modules/upnp/upnp.cpp6
-rw-r--r--modules/visual_script/visual_script.cpp27
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp2
-rw-r--r--modules/visual_script/visual_script_editor.cpp39
-rw-r--r--modules/visual_script/visual_script_expression.cpp17
-rw-r--r--modules/visual_script/visual_script_expression.h2
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp14
-rw-r--r--modules/visual_script/visual_script_flow_control.h2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp54
-rw-r--r--modules/visual_script/visual_script_nodes.cpp61
-rw-r--r--modules/visual_script/visual_script_nodes.h4
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp12
-rw-r--r--modules/webm/video_stream_webm.cpp6
-rw-r--r--modules/webm/video_stream_webm.h2
-rw-r--r--modules/webp/image_loader_webp.cpp2
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml1
-rw-r--r--modules/websocket/packet_buffer.h5
-rw-r--r--modules/websocket/websocket_client.cpp32
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp26
-rw-r--r--modules/webxr/native/library_godot_webxr.js2
-rw-r--r--modules/webxr/native/webxr.externs.js4
-rw-r--r--modules/webxr/webxr_interface.h2
-rw-r--r--modules/webxr/webxr_interface_js.cpp14
-rw-r--r--modules/webxr/webxr_interface_js.h2
-rw-r--r--modules/xatlas_unwrap/register_types.cpp4
-rw-r--r--platform/android/audio_driver_jandroid.cpp4
-rw-r--r--platform/android/detect.py24
-rw-r--r--platform/android/display_server_android.cpp40
-rw-r--r--platform/android/export/export.cpp307
-rw-r--r--platform/android/export/gradle_export_util.h57
-rw-r--r--platform/android/file_access_android.cpp3
-rw-r--r--platform/android/java/app/AndroidManifest.xml19
-rw-r--r--platform/android/java/app/assets/.gitignore2
-rw-r--r--platform/android/java/app/build.gradle12
-rw-r--r--platform/android/java/app/config.gradle86
-rw-r--r--platform/android/java/app/res/drawable-nodpi/splash.png (renamed from platform/android/java/app/res/drawable/splash.png)bin14766 -> 14766 bytes
-rw-r--r--platform/android/java/app/res/drawable-nodpi/splash_bg_color.png (renamed from platform/android/java/app/res/drawable/splash_bg_color.png)bin1360 -> 1360 bytes
-rw-r--r--platform/android/java/app/res/drawable/splash_drawable.xml2
-rw-r--r--platform/android/java/build.gradle44
-rw-r--r--platform/android/java/gradle.properties2
-rw-r--r--platform/android/java/lib/AndroidManifest.xml5
-rw-r--r--platform/android/java/lib/build.gradle10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java22
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java107
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotHost.java56
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java247
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java13
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java121
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java72
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java38
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java45
-rw-r--r--platform/android/java/nativeSrcsConfigs/README.md2
-rw-r--r--platform/android/java/nativeSrcsConfigs/build.gradle3
-rw-r--r--platform/android/java_class_wrapper.cpp3
-rw-r--r--platform/android/java_godot_io_wrapper.cpp20
-rw-r--r--platform/android/java_godot_lib_jni.cpp15
-rw-r--r--platform/android/java_godot_view_wrapper.cpp7
-rw-r--r--platform/android/java_godot_view_wrapper.h2
-rw-r--r--platform/android/java_godot_wrapper.cpp63
-rw-r--r--platform/android/java_godot_wrapper.h2
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp10
-rw-r--r--platform/android/plugin/godot_plugin_jni.h10
-rw-r--r--platform/android/thread_jandroid.cpp27
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp10
-rw-r--r--platform/android/vulkan/vulkan_context_android.h9
-rw-r--r--platform/iphone/detect.py2
-rw-r--r--platform/iphone/display_layer.mm2
-rw-r--r--platform/iphone/display_server_iphone.mm4
-rw-r--r--platform/iphone/export/export.cpp28
-rw-r--r--platform/iphone/godot_iphone.mm4
-rw-r--r--platform/iphone/godot_view.mm22
-rw-r--r--platform/iphone/ios.mm8
-rw-r--r--platform/iphone/joypad_iphone.mm2
-rw-r--r--platform/iphone/keyboard_input_view.mm6
-rw-r--r--platform/iphone/plugin/godot_plugin_config.h5
-rw-r--r--platform/iphone/vulkan_context_iphone.mm4
-rw-r--r--platform/javascript/.eslintrc.engine.js2
-rw-r--r--platform/javascript/SCsub44
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp20
-rw-r--r--platform/javascript/audio_driver_javascript.cpp4
-rw-r--r--platform/javascript/detect.py49
-rw-r--r--platform/javascript/display_server_javascript.cpp156
-rw-r--r--platform/javascript/display_server_javascript.h9
-rw-r--r--platform/javascript/emscripten_helpers.py89
-rw-r--r--platform/javascript/export/export.cpp681
-rw-r--r--platform/javascript/godot_js.h21
-rw-r--r--platform/javascript/http_client.h.inc13
-rw-r--r--platform/javascript/http_client_javascript.cpp182
-rw-r--r--platform/javascript/http_request.h75
-rw-r--r--platform/javascript/js/engine/config.js337
-rw-r--r--platform/javascript/js/engine/engine.externs.js1
-rw-r--r--platform/javascript/js/engine/engine.js500
-rw-r--r--platform/javascript/js/engine/preloader.js108
-rw-r--r--platform/javascript/js/engine/utils.js58
-rw-r--r--platform/javascript/js/jsdoc2rst/publish.js354
-rw-r--r--platform/javascript/js/libs/library_godot_audio.js5
-rw-r--r--platform/javascript/js/libs/library_godot_display.js441
-rw-r--r--platform/javascript/js/libs/library_godot_fetch.js247
-rw-r--r--platform/javascript/js/libs/library_godot_http_request.js160
-rw-r--r--platform/javascript/js/libs/library_godot_os.js44
-rw-r--r--platform/javascript/js/libs/library_godot_runtime.js16
-rw-r--r--platform/javascript/os_javascript.cpp4
-rw-r--r--platform/javascript/os_javascript.h1
-rw-r--r--platform/javascript/package-lock.json154
-rw-r--r--platform/javascript/package.json12
-rw-r--r--platform/linuxbsd/SCsub3
-rw-r--r--platform/linuxbsd/detect.py55
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp3
-rw-r--r--platform/linuxbsd/display_server_x11.cpp43
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/linuxbsd/joypad_linux.cpp60
-rw-r--r--platform/linuxbsd/joypad_linux.h11
-rw-r--r--platform/linuxbsd/libudev-so_wrap.c1013
-rw-r--r--platform/linuxbsd/libudev-so_wrap.h378
-rw-r--r--platform/osx/crash_handler_osx.mm10
-rw-r--r--platform/osx/detect.py17
-rw-r--r--platform/osx/display_server_osx.h1
-rw-r--r--platform/osx/display_server_osx.mm71
-rw-r--r--platform/osx/export/export.cpp210
-rw-r--r--platform/osx/joypad_osx.cpp4
-rw-r--r--platform/osx/os_osx.mm6
-rw-r--r--platform/osx/vulkan_context_osx.mm4
-rw-r--r--platform/server/detect.py36
-rw-r--r--platform/uwp/app.cpp16
-rw-r--r--platform/uwp/detect.py11
-rw-r--r--platform/uwp/export/export.cpp24
-rw-r--r--platform/uwp/joypad_uwp.cpp4
-rw-r--r--platform/uwp/joypad_uwp.h2
-rw-r--r--platform/uwp/os_uwp.cpp9
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/detect.py17
-rw-r--r--platform/windows/display_server_windows.cpp125
-rw-r--r--platform/windows/display_server_windows.h9
-rw-r--r--platform/windows/godot.natvis10
-rw-r--r--platform/windows/joypad_windows.cpp15
-rw-r--r--platform/windows/joypad_windows.h2
-rw-r--r--platform/windows/os_windows.cpp68
-rw-r--r--platform/windows/os_windows.h8
-rw-r--r--platform/windows/windows_terminal_logger.cpp5
-rw-r--r--scene/2d/animated_sprite_2d.cpp235
-rw-r--r--scene/2d/animated_sprite_2d.h69
-rw-r--r--scene/2d/area_2d.cpp77
-rw-r--r--scene/2d/area_2d.h14
-rw-r--r--scene/2d/audio_stream_player_2d.cpp62
-rw-r--r--scene/2d/audio_stream_player_2d.h11
-rw-r--r--scene/2d/camera_2d.cpp68
-rw-r--r--scene/2d/camera_2d.h40
-rw-r--r--scene/2d/canvas_group.cpp8
-rw-r--r--scene/2d/canvas_group.h12
-rw-r--r--scene/2d/canvas_modulate.cpp23
-rw-r--r--scene/2d/canvas_modulate.h2
-rw-r--r--scene/2d/collision_object_2d.cpp85
-rw-r--r--scene/2d/collision_object_2d.h17
-rw-r--r--scene/2d/collision_polygon_2d.cpp65
-rw-r--r--scene/2d/collision_polygon_2d.h2
-rw-r--r--scene/2d/collision_shape_2d.cpp17
-rw-r--r--scene/2d/collision_shape_2d.h2
-rw-r--r--scene/2d/cpu_particles_2d.cpp231
-rw-r--r--scene/2d/cpu_particles_2d.h56
-rw-r--r--scene/2d/gpu_particles_2d.cpp23
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joints_2d.cpp120
-rw-r--r--scene/2d/joints_2d.h16
-rw-r--r--scene/2d/light_2d.cpp41
-rw-r--r--scene/2d/light_2d.h33
-rw-r--r--scene/2d/light_occluder_2d.cpp16
-rw-r--r--scene/2d/light_occluder_2d.h2
-rw-r--r--scene/2d/line_2d.cpp1
-rw-r--r--scene/2d/line_builder.cpp8
-rw-r--r--scene/2d/mesh_instance_2d.cpp1
-rw-r--r--scene/2d/multimesh_instance_2d.cpp1
-rw-r--r--scene/2d/navigation_2d.cpp92
-rw-r--r--scene/2d/navigation_agent_2d.cpp81
-rw-r--r--scene/2d/navigation_agent_2d.h18
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp124
-rw-r--r--scene/2d/navigation_obstacle_2d.h16
-rw-r--r--scene/2d/navigation_region_2d.cpp133
-rw-r--r--scene/2d/navigation_region_2d.h9
-rw-r--r--scene/2d/node_2d.cpp55
-rw-r--r--scene/2d/node_2d.h40
-rw-r--r--scene/2d/parallax_background.cpp4
-rw-r--r--scene/2d/parallax_background.h6
-rw-r--r--scene/2d/parallax_layer.cpp17
-rw-r--r--scene/2d/parallax_layer.h4
-rw-r--r--scene/2d/path_2d.cpp51
-rw-r--r--scene/2d/path_2d.h22
-rw-r--r--scene/2d/physics_body_2d.cpp90
-rw-r--r--scene/2d/physics_body_2d.h17
-rw-r--r--scene/2d/polygon_2d.cpp26
-rw-r--r--scene/2d/polygon_2d.h17
-rw-r--r--scene/2d/position_2d.cpp10
-rw-r--r--scene/2d/position_2d.h4
-rw-r--r--scene/2d/ray_cast_2d.cpp71
-rw-r--r--scene/2d/ray_cast_2d.h2
-rw-r--r--scene/2d/remote_transform_2d.cpp13
-rw-r--r--scene/2d/remote_transform_2d.h2
-rw-r--r--scene/2d/skeleton_2d.cpp28
-rw-r--r--scene/2d/skeleton_2d.h8
-rw-r--r--scene/2d/sprite_2d.cpp63
-rw-r--r--scene/2d/sprite_2d.h14
-rw-r--r--scene/2d/tile_map.cpp106
-rw-r--r--scene/2d/tile_map.h9
-rw-r--r--scene/2d/touch_screen_button.cpp18
-rw-r--r--scene/2d/visibility_notifier_2d.cpp13
-rw-r--r--scene/2d/visibility_notifier_2d.h2
-rw-r--r--scene/3d/area_3d.cpp83
-rw-r--r--scene/3d/area_3d.h14
-rw-r--r--scene/3d/audio_stream_player_3d.cpp70
-rw-r--r--scene/3d/audio_stream_player_3d.h11
-rw-r--r--scene/3d/baked_lightmap.cpp21
-rw-r--r--scene/3d/camera_3d.cpp32
-rw-r--r--scene/3d/camera_3d.h10
-rw-r--r--scene/3d/collision_object_3d.cpp161
-rw-r--r--scene/3d/collision_object_3d.h26
-rw-r--r--scene/3d/collision_polygon_3d.cpp34
-rw-r--r--scene/3d/collision_polygon_3d.h6
-rw-r--r--scene/3d/collision_shape_3d.cpp53
-rw-r--r--scene/3d/collision_shape_3d.h6
-rw-r--r--scene/3d/cpu_particles_3d.cpp49
-rw-r--r--scene/3d/cpu_particles_3d.h6
-rw-r--r--scene/3d/decal.cpp8
-rw-r--r--scene/3d/decal.h1
-rw-r--r--scene/3d/gi_probe.cpp28
-rw-r--r--scene/3d/gi_probe.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp200
-rw-r--r--scene/3d/gpu_particles_3d.h33
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/light_3d.cpp45
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/lightmapper.cpp9
-rw-r--r--scene/3d/lightmapper.h77
-rw-r--r--scene/3d/mesh_instance_3d.cpp93
-rw-r--r--scene/3d/mesh_instance_3d.h11
-rw-r--r--scene/3d/navigation_3d.cpp117
-rw-r--r--scene/3d/navigation_agent_3d.cpp80
-rw-r--r--scene/3d/navigation_agent_3d.h13
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp139
-rw-r--r--scene/3d/navigation_obstacle_3d.h16
-rw-r--r--scene/3d/navigation_region_3d.cpp76
-rw-r--r--scene/3d/navigation_region_3d.h11
-rw-r--r--scene/3d/node_3d.cpp14
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/occluder_instance_3d.cpp335
-rw-r--r--scene/3d/occluder_instance_3d.h108
-rw-r--r--scene/3d/path_3d.cpp34
-rw-r--r--scene/3d/path_3d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp135
-rw-r--r--scene/3d/physics_body_3d.h17
-rw-r--r--scene/3d/physics_joint_3d.cpp165
-rw-r--r--scene/3d/physics_joint_3d.h20
-rw-r--r--scene/3d/ray_cast_3d.cpp164
-rw-r--r--scene/3d/ray_cast_3d.h17
-rw-r--r--scene/3d/reflection_probe.cpp6
-rw-r--r--scene/3d/remote_transform_3d.cpp13
-rw-r--r--scene/3d/remote_transform_3d.h2
-rw-r--r--scene/3d/skeleton_3d.cpp15
-rw-r--r--scene/3d/skeleton_3d.h1
-rw-r--r--scene/3d/skeleton_ik_3d.cpp111
-rw-r--r--scene/3d/skeleton_ik_3d.h5
-rw-r--r--scene/3d/soft_body_3d.cpp114
-rw-r--r--scene/3d/soft_body_3d.h26
-rw-r--r--scene/3d/sprite_3d.cpp62
-rw-r--r--scene/3d/sprite_3d.h18
-rw-r--r--scene/3d/vehicle_body_3d.cpp18
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/visibility_notifier_3d.cpp1
-rw-r--r--scene/3d/visual_instance_3d.cpp24
-rw-r--r--scene/3d/visual_instance_3d.h4
-rw-r--r--scene/3d/voxelizer.cpp8
-rw-r--r--scene/3d/world_environment.cpp99
-rw-r--r--scene/3d/world_environment.h5
-rw-r--r--scene/3d/xr_nodes.cpp138
-rw-r--r--scene/3d/xr_nodes.h8
-rw-r--r--scene/animation/animation_blend_space_2d.cpp4
-rw-r--r--scene/animation/animation_blend_tree.cpp11
-rw-r--r--scene/animation/animation_blend_tree.h2
-rw-r--r--scene/animation/animation_node_state_machine.cpp18
-rw-r--r--scene/animation/animation_node_state_machine.h2
-rw-r--r--scene/animation/animation_player.cpp51
-rw-r--r--scene/animation/animation_player.h14
-rw-r--r--scene/animation/animation_tree.cpp66
-rw-r--r--scene/animation/animation_tree.h12
-rw-r--r--scene/animation/root_motion_view.cpp4
-rw-r--r--scene/animation/tween.cpp27
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/audio/audio_stream_player.cpp54
-rw-r--r--scene/audio/audio_stream_player.h9
-rw-r--r--scene/debugger/scene_debugger.cpp2
-rw-r--r--scene/gui/base_button.cpp17
-rw-r--r--scene/gui/base_button.h20
-rw-r--r--scene/gui/box_container.cpp15
-rw-r--r--scene/gui/box_container.h6
-rw-r--r--scene/gui/button.cpp20
-rw-r--r--scene/gui/button.h10
-rw-r--r--scene/gui/center_container.cpp4
-rw-r--r--scene/gui/center_container.h2
-rw-r--r--scene/gui/check_box.cpp6
-rw-r--r--scene/gui/color_picker.cpp497
-rw-r--r--scene/gui/color_picker.h86
-rw-r--r--scene/gui/container.cpp13
-rw-r--r--scene/gui/container.h4
-rw-r--r--scene/gui/control.cpp235
-rw-r--r--scene/gui/control.h54
-rw-r--r--scene/gui/dialogs.cpp11
-rw-r--r--scene/gui/dialogs.h4
-rw-r--r--scene/gui/file_dialog.cpp154
-rw-r--r--scene/gui/file_dialog.h18
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/gradient_edit.h4
-rw-r--r--scene/gui/graph_edit.cpp142
-rw-r--r--scene/gui/graph_edit.h47
-rw-r--r--scene/gui/graph_node.cpp151
-rw-r--r--scene/gui/graph_node.h37
-rw-r--r--scene/gui/grid_container.cpp4
-rw-r--r--scene/gui/grid_container.h2
-rw-r--r--scene/gui/item_list.cpp57
-rw-r--r--scene/gui/item_list.h46
-rw-r--r--scene/gui/label.cpp30
-rw-r--r--scene/gui/label.h2
-rw-r--r--scene/gui/line_edit.cpp1107
-rw-r--r--scene/gui/line_edit.h72
-rw-r--r--scene/gui/link_button.cpp11
-rw-r--r--scene/gui/link_button.h2
-rw-r--r--scene/gui/menu_button.cpp3
-rw-r--r--scene/gui/menu_button.h6
-rw-r--r--scene/gui/nine_patch_rect.cpp25
-rw-r--r--scene/gui/nine_patch_rect.h7
-rw-r--r--scene/gui/option_button.cpp1
-rw-r--r--scene/gui/option_button.h2
-rw-r--r--scene/gui/popup_menu.cpp106
-rw-r--r--scene/gui/popup_menu.h59
-rw-r--r--scene/gui/progress_bar.cpp9
-rw-r--r--scene/gui/progress_bar.h2
-rw-r--r--scene/gui/range.cpp28
-rw-r--r--scene/gui/range.h17
-rw-r--r--scene/gui/rich_text_label.cpp226
-rw-r--r--scene/gui/rich_text_label.h111
-rw-r--r--scene/gui/scroll_bar.cpp10
-rw-r--r--scene/gui/scroll_bar.h14
-rw-r--r--scene/gui/scroll_container.cpp36
-rw-r--r--scene/gui/scroll_container.h22
-rw-r--r--scene/gui/separator.h2
-rw-r--r--scene/gui/slider.cpp17
-rw-r--r--scene/gui/slider.h18
-rw-r--r--scene/gui/spin_box.cpp34
-rw-r--r--scene/gui/spin_box.h7
-rw-r--r--scene/gui/split_container.cpp13
-rw-r--r--scene/gui/split_container.h20
-rw-r--r--scene/gui/subviewport_container.cpp6
-rw-r--r--scene/gui/subviewport_container.h4
-rw-r--r--scene/gui/tab_container.cpp31
-rw-r--r--scene/gui/tab_container.h28
-rw-r--r--scene/gui/tabs.cpp109
-rw-r--r--scene/gui/tabs.h54
-rw-r--r--scene/gui/text_edit.cpp2358
-rw-r--r--scene/gui/text_edit.h276
-rw-r--r--scene/gui/texture_button.cpp11
-rw-r--r--scene/gui/texture_button.h10
-rw-r--r--scene/gui/texture_progress_bar.cpp18
-rw-r--r--scene/gui/texture_progress_bar.h14
-rw-r--r--scene/gui/texture_rect.cpp4
-rw-r--r--scene/gui/texture_rect.h8
-rw-r--r--scene/gui/tree.cpp171
-rw-r--r--scene/gui/tree.h194
-rw-r--r--scene/gui/video_player.cpp20
-rw-r--r--scene/gui/video_player.h27
-rw-r--r--scene/main/canvas_item.cpp53
-rw-r--r--scene/main/canvas_item.h40
-rw-r--r--scene/main/canvas_layer.cpp17
-rw-r--r--scene/main/canvas_layer.h19
-rw-r--r--scene/main/http_request.cpp99
-rw-r--r--scene/main/http_request.h37
-rw-r--r--scene/main/node.cpp424
-rw-r--r--scene/main/node.h43
-rw-r--r--scene/main/scene_tree.cpp126
-rw-r--r--scene/main/scene_tree.h18
-rw-r--r--scene/main/shader_globals_override.cpp17
-rw-r--r--scene/main/shader_globals_override.h4
-rw-r--r--scene/main/timer.cpp34
-rw-r--r--scene/main/timer.h22
-rw-r--r--scene/main/viewport.cpp278
-rw-r--r--scene/main/viewport.h151
-rw-r--r--scene/main/window.cpp32
-rw-r--r--scene/main/window.h6
-rw-r--r--scene/register_scene_types.cpp28
-rw-r--r--scene/resources/animation.cpp22
-rw-r--r--scene/resources/animation.h46
-rw-r--r--scene/resources/audio_stream_sample.cpp23
-rw-r--r--scene/resources/audio_stream_sample.h36
-rw-r--r--scene/resources/bit_map.cpp15
-rw-r--r--scene/resources/bit_map.h4
-rw-r--r--scene/resources/box_shape_3d.cpp1
-rw-r--r--scene/resources/camera_effects.cpp13
-rw-r--r--scene/resources/camera_effects.h9
-rw-r--r--scene/resources/capsule_shape_2d.cpp7
-rw-r--r--scene/resources/capsule_shape_2d.h4
-rw-r--r--scene/resources/capsule_shape_3d.cpp4
-rw-r--r--scene/resources/capsule_shape_3d.h4
-rw-r--r--scene/resources/circle_shape_2d.cpp6
-rw-r--r--scene/resources/circle_shape_2d.h2
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp2
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp39
-rw-r--r--scene/resources/concave_polygon_shape_3d.h6
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp13
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp2
-rw-r--r--scene/resources/curve.cpp20
-rw-r--r--scene/resources/curve.h50
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/cylinder_shape_3d.h4
-rw-r--r--scene/resources/default_theme/bar_arrow.pngbin0 -> 208 bytes
-rw-r--r--scene/resources/default_theme/checked_disabled.pngbin0 -> 421 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp139
-rw-r--r--scene/resources/default_theme/picker_cursor.pngbin0 -> 300 bytes
-rw-r--r--scene/resources/default_theme/radio_checked_disabled.pngbin0 -> 235 bytes
-rw-r--r--scene/resources/default_theme/radio_unchecked_disabled.pngbin0 -> 183 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h24
-rw-r--r--scene/resources/default_theme/unchecked_disabled.pngbin0 -> 246 bytes
-rw-r--r--scene/resources/environment.cpp49
-rw-r--r--scene/resources/environment.h10
-rw-r--r--scene/resources/font.cpp98
-rw-r--r--scene/resources/font.h27
-rw-r--r--scene/resources/gradient.cpp1
-rw-r--r--scene/resources/gradient.h4
-rw-r--r--scene/resources/height_map_shape_3d.cpp28
-rw-r--r--scene/resources/height_map_shape_3d.h8
-rw-r--r--scene/resources/line_shape_2d.cpp2
-rw-r--r--scene/resources/line_shape_2d.h4
-rw-r--r--scene/resources/material.cpp109
-rw-r--r--scene/resources/material.h52
-rw-r--r--scene/resources/mesh.cpp43
-rw-r--r--scene/resources/mesh.h19
-rw-r--r--scene/resources/mesh_data_tool.cpp38
-rw-r--r--scene/resources/mesh_data_tool.h8
-rw-r--r--scene/resources/mesh_library.cpp25
-rw-r--r--scene/resources/mesh_library.h1
-rw-r--r--scene/resources/multimesh.cpp7
-rw-r--r--scene/resources/multimesh.h10
-rw-r--r--scene/resources/navigation_mesh.cpp39
-rw-r--r--scene/resources/navigation_mesh.h48
-rw-r--r--scene/resources/packed_scene.cpp28
-rw-r--r--scene/resources/packed_scene.h34
-rw-r--r--scene/resources/particles_material.cpp264
-rw-r--r--scene/resources/particles_material.h6
-rw-r--r--scene/resources/physics_material.h4
-rw-r--r--scene/resources/polygon_path_finder.cpp6
-rw-r--r--scene/resources/polygon_path_finder.h8
-rw-r--r--scene/resources/primitive_meshes.cpp616
-rw-r--r--scene/resources/primitive_meshes.h161
-rw-r--r--scene/resources/ray_shape_2d.cpp30
-rw-r--r--scene/resources/ray_shape_2d.h4
-rw-r--r--scene/resources/ray_shape_3d.cpp7
-rw-r--r--scene/resources/ray_shape_3d.h4
-rw-r--r--scene/resources/rectangle_shape_2d.cpp24
-rw-r--r--scene/resources/resource_format_text.cpp142
-rw-r--r--scene/resources/resource_format_text.h36
-rw-r--r--scene/resources/shader.cpp4
-rw-r--r--scene/resources/shader.h6
-rw-r--r--scene/resources/shape_2d.cpp14
-rw-r--r--scene/resources/shape_2d.h5
-rw-r--r--scene/resources/skin.cpp8
-rw-r--r--scene/resources/skin.h5
-rw-r--r--scene/resources/sky.cpp2
-rw-r--r--scene/resources/sky.h4
-rw-r--r--scene/resources/sky_material.cpp6
-rw-r--r--scene/resources/sphere_shape_3d.cpp1
-rw-r--r--scene/resources/sprite_frames.cpp241
-rw-r--r--scene/resources/sprite_frames.h (renamed from editor/input_map_editor.h)129
-rw-r--r--scene/resources/style_box.cpp85
-rw-r--r--scene/resources/style_box.h45
-rw-r--r--scene/resources/surface_tool.cpp19
-rw-r--r--scene/resources/surface_tool.h17
-rw-r--r--scene/resources/syntax_highlighter.h2
-rw-r--r--scene/resources/text_line.cpp1
-rw-r--r--scene/resources/text_line.h2
-rw-r--r--scene/resources/text_paragraph.cpp19
-rw-r--r--scene/resources/text_paragraph.h5
-rw-r--r--scene/resources/texture.cpp289
-rw-r--r--scene/resources/texture.h139
-rw-r--r--scene/resources/theme.cpp512
-rw-r--r--scene/resources/theme.h49
-rw-r--r--scene/resources/tile_set.cpp17
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp202
-rw-r--r--scene/resources/visual_shader.h84
-rw-r--r--scene/resources/visual_shader_nodes.cpp111
-rw-r--r--scene/resources/visual_shader_nodes.h7
-rw-r--r--scene/resources/world_2d.cpp37
-rw-r--r--scene/resources/world_2d.h6
-rw-r--r--scene/resources/world_3d.cpp15
-rw-r--r--scene/resources/world_3d.h2
-rw-r--r--scene/resources/world_margin_shape_3d.cpp1
-rw-r--r--scene/scene_string_names.cpp4
-rw-r--r--scene/scene_string_names.h4
-rw-r--r--servers/audio/audio_driver_dummy.cpp4
-rw-r--r--servers/audio/audio_rb_resampler.cpp14
-rw-r--r--servers/audio/audio_rb_resampler.h57
-rw-r--r--servers/audio/audio_stream.cpp20
-rw-r--r--servers/audio/effects/audio_effect_capture.cpp10
-rw-r--r--servers/audio/effects/audio_effect_capture.h4
-rw-r--r--servers/audio/effects/audio_effect_chorus.cpp2
-rw-r--r--servers/audio/effects/audio_effect_distortion.cpp3
-rw-r--r--servers/audio_server.cpp19
-rw-r--r--servers/camera/camera_feed.cpp10
-rw-r--r--servers/camera/camera_feed.h6
-rw-r--r--servers/camera_server.cpp2
-rw-r--r--servers/display_server.cpp7
-rw-r--r--servers/display_server.h7
-rw-r--r--servers/navigation_server_2d.cpp43
-rw-r--r--servers/navigation_server_2d.h15
-rw-r--r--servers/navigation_server_3d.cpp11
-rw-r--r--servers/navigation_server_3d.h15
-rw-r--r--servers/physics_2d/area_2d_sw.cpp8
-rw-r--r--servers/physics_2d/body_2d_sw.cpp18
-rw-r--r--servers/physics_2d/body_2d_sw.h13
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp43
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp79
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h11
-rw-r--r--servers/physics_2d/constraint_2d_sw.h8
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp40
-rw-r--r--servers/physics_2d/joints_2d_sw.h25
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp87
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h25
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.cpp24
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h68
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp8
-rw-r--r--servers/physics_2d/space_2d_sw.cpp110
-rw-r--r--servers/physics_2d/step_2d_sw.cpp191
-rw-r--r--servers/physics_2d/step_2d_sw.h13
-rw-r--r--servers/physics_3d/area_3d_sw.cpp8
-rw-r--r--servers/physics_3d/body_3d_sw.cpp48
-rw-r--r--servers/physics_3d/body_3d_sw.h19
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp340
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h85
-rw-r--r--servers/physics_3d/collision_object_3d_sw.cpp10
-rw-r--r--servers/physics_3d/collision_object_3d_sw.h7
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp897
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp197
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h6
-rw-r--r--servers/physics_3d/constraint_3d_sw.h8
-rw-r--r--servers/physics_3d/gjk_epa.cpp198
-rw-r--r--servers/physics_3d/gjk_epa.h2
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.h2
-rw-r--r--servers/physics_3d/joints_3d_sw.h20
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp608
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h138
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.cpp140
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h413
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp692
-rw-r--r--servers/physics_3d/shape_3d_sw.h112
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp1221
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h247
-rw-r--r--servers/physics_3d/space_3d_sw.cpp181
-rw-r--r--servers/physics_3d/space_3d_sw.h6
-rw-r--r--servers/physics_3d/step_3d_sw.cpp222
-rw-r--r--servers/physics_3d/step_3d_sw.h13
-rw-r--r--servers/physics_server_2d.cpp23
-rw-r--r--servers/physics_server_2d.h23
-rw-r--r--servers/physics_server_3d.cpp79
-rw-r--r--servers/physics_server_3d.h102
-rw-r--r--servers/register_server_types.cpp23
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp61
-rw-r--r--servers/rendering/renderer_canvas_cull.h34
-rw-r--r--servers/rendering/renderer_rd/SCsub2
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp30
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/SCsub5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward.cpp)1146
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward.h)231
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp806
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h211
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/SCsub5
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp2163
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h604
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp833
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h203
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp21
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp11
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h5
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp126
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_environment_rd.h155
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp3402
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h671
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp5406
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h1030
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp1492
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.h292
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp678
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h259
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp145
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.h24
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp402
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h60
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub55
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl58
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl102
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_debug.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_store.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/copy.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/copy_to_fb.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/cube_to_dp.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_filter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl18
-rw-r--r--servers/rendering/renderer_rd/shaders/gi.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_debug.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_write.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl83
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl291
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl103
-rw-r--r--servers/rendering/renderer_rd/shaders/resolve.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/roughness_limiter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl58
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward.glsl)1488
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl)35
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl242
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl1023
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl1476
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl220
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl55
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl182
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sky.glsl32
-rw-r--r--servers/rendering/renderer_rd/shaders/sort.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/specular_merge.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_blur.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_downsample.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_interleave.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl5
-rw-r--r--servers/rendering/renderer_scene.h32
-rw-r--r--servers/rendering/renderer_scene_cull.cpp179
-rw-r--r--servers/rendering/renderer_scene_cull.h60
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp192
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.h201
-rw-r--r--servers/rendering/renderer_scene_render.h19
-rw-r--r--servers/rendering/renderer_storage.h92
-rw-r--r--servers/rendering/renderer_viewport.cpp95
-rw-r--r--servers/rendering/renderer_viewport.h24
-rw-r--r--servers/rendering/rendering_device.cpp4
-rw-r--r--servers/rendering/rendering_device.h35
-rw-r--r--servers/rendering/rendering_server_default.cpp112
-rw-r--r--servers/rendering/rendering_server_default.h1224
-rw-r--r--servers/rendering/rendering_server_wrap_mt.cpp174
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h808
-rw-r--r--servers/rendering/shader_language.cpp239
-rw-r--r--servers/rendering/shader_language.h42
-rw-r--r--servers/rendering/shader_types.cpp98
-rw-r--r--servers/rendering_server.cpp305
-rw-r--r--servers/rendering_server.h46
-rw-r--r--servers/server_wrap_mt_common.h860
-rw-r--r--servers/text_server.cpp35
-rw-r--r--servers/text_server.h34
-rw-r--r--servers/xr/xr_positional_tracker.h4
-rw-r--r--servers/xr_server.cpp24
-rw-r--r--servers/xr_server.h10
-rw-r--r--tests/test_array.h186
-rw-r--r--tests/test_class_db.h43
-rw-r--r--tests/test_command_queue.h4
-rw-r--r--tests/test_dictionary.h159
-rw-r--r--tests/test_geometry_2d.h2
-rw-r--r--tests/test_geometry_3d.h417
-rw-r--r--tests/test_hashing_context.h165
-rw-r--r--tests/test_list.h2
-rw-r--r--tests/test_main.cpp7
-rw-r--r--tests/test_path_3d.h (renamed from editor/import/resource_importer_csv.cpp)79
-rw-r--r--tests/test_path_follow_2d.h241
-rw-r--r--tests/test_path_follow_3d.h220
-rw-r--r--tests/test_physics_2d.cpp9
-rw-r--r--tests/test_physics_3d.cpp29
-rw-r--r--tests/test_render.cpp4
-rw-r--r--tests/test_resource.h114
-rw-r--r--tests/test_shader_lang.cpp2
-rw-r--r--tests/test_string.h73
-rw-r--r--tests/test_text_server.h3
-rw-r--r--tests/test_variant.h594
-rw-r--r--tests/test_xml_parser.h (renamed from scene/3d/navigation_3d.h)72
-rw-r--r--thirdparty/README.md69
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp1
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp1
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp1
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_any_of.h55
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp56
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_filter.h93
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp48
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for.h229
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp63
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for_for.h149
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp85
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.h112
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp47
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_map.h85
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp53
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_partition.h283
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp48
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.h85
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp49
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h150
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp43
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_set.h52
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp50
-rw-r--r--thirdparty/embree-aarch64/common/algorithms/parallel_sort.h457
-rw-r--r--thirdparty/embree-aarch64/common/lexers/parsestream.h101
-rw-r--r--thirdparty/embree-aarch64/common/lexers/stream.h215
-rw-r--r--thirdparty/embree-aarch64/common/lexers/streamfilters.h39
-rw-r--r--thirdparty/embree-aarch64/common/lexers/stringstream.cpp51
-rw-r--r--thirdparty/embree-aarch64/common/lexers/stringstream.h29
-rw-r--r--thirdparty/embree-aarch64/common/lexers/tokenstream.cpp181
-rw-r--r--thirdparty/embree-aarch64/common/lexers/tokenstream.h164
-rw-r--r--thirdparty/embree-aarch64/common/math/AVX2NEON.h986
-rw-r--r--thirdparty/embree-aarch64/common/math/SSE2NEON.h1753
-rw-r--r--thirdparty/embree-aarch64/common/math/affinespace.h361
-rw-r--r--thirdparty/embree-aarch64/common/math/bbox.h331
-rw-r--r--thirdparty/embree-aarch64/common/math/col3.h47
-rw-r--r--thirdparty/embree-aarch64/common/math/col4.h47
-rw-r--r--thirdparty/embree-aarch64/common/math/color.h257
-rw-r--r--thirdparty/embree-aarch64/common/math/constants.cpp61
-rw-r--r--thirdparty/embree-aarch64/common/math/constants.h239
-rw-r--r--thirdparty/embree-aarch64/common/math/interval.h161
-rw-r--r--thirdparty/embree-aarch64/common/math/lbbox.h289
-rw-r--r--thirdparty/embree-aarch64/common/math/linearspace2.h148
-rw-r--r--thirdparty/embree-aarch64/common/math/linearspace3.h213
-rw-r--r--thirdparty/embree-aarch64/common/math/math.h451
-rw-r--r--thirdparty/embree-aarch64/common/math/obbox.h39
-rw-r--r--thirdparty/embree-aarch64/common/math/quaternion.h254
-rw-r--r--thirdparty/embree-aarch64/common/math/range.h137
-rw-r--r--thirdparty/embree-aarch64/common/math/transcendental.h525
-rw-r--r--thirdparty/embree-aarch64/common/math/vec2.h235
-rw-r--r--thirdparty/embree-aarch64/common/math/vec2fa.h317
-rw-r--r--thirdparty/embree-aarch64/common/math/vec3.h349
-rw-r--r--thirdparty/embree-aarch64/common/math/vec3ba.h120
-rw-r--r--thirdparty/embree-aarch64/common/math/vec3fa.h810
-rw-r--r--thirdparty/embree-aarch64/common/math/vec3ia.h210
-rw-r--r--thirdparty/embree-aarch64/common/math/vec4.h258
-rw-r--r--thirdparty/embree-aarch64/common/simd/avx.h34
-rw-r--r--thirdparty/embree-aarch64/common/simd/avx512.h41
-rw-r--r--thirdparty/embree-aarch64/common/simd/simd.h110
-rw-r--r--thirdparty/embree-aarch64/common/simd/sse.cpp34
-rw-r--r--thirdparty/embree-aarch64/common/simd/sse.h35
-rw-r--r--thirdparty/embree-aarch64/common/simd/varying.h132
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboold4_avx.h160
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboold4_avx512.h140
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboold8_avx512.h148
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboolf16_avx512.h150
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboolf4_avx512.h143
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboolf4_sse2.h198
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboolf8_avx.h189
-rw-r--r--thirdparty/embree-aarch64/common/simd/vboolf8_avx512.h143
-rw-r--r--thirdparty/embree-aarch64/common/simd/vdouble4_avx.h324
-rw-r--r--thirdparty/embree-aarch64/common/simd/vdouble8_avx512.h356
-rw-r--r--thirdparty/embree-aarch64/common/simd/vfloat16_avx512.h771
-rw-r--r--thirdparty/embree-aarch64/common/simd/vfloat4_sse2.h925
-rw-r--r--thirdparty/embree-aarch64/common/simd/vfloat8_avx.h847
-rw-r--r--thirdparty/embree-aarch64/common/simd/vint16_avx512.h490
-rw-r--r--thirdparty/embree-aarch64/common/simd/vint4_sse2.h681
-rw-r--r--thirdparty/embree-aarch64/common/simd/vint8_avx.h464
-rw-r--r--thirdparty/embree-aarch64/common/simd/vint8_avx2.h512
-rw-r--r--thirdparty/embree-aarch64/common/simd/vllong4_avx2.h358
-rw-r--r--thirdparty/embree-aarch64/common/simd/vllong8_avx512.h381
-rw-r--r--thirdparty/embree-aarch64/common/simd/vuint16_avx512.h443
-rw-r--r--thirdparty/embree-aarch64/common/simd/vuint4_sse2.h499
-rw-r--r--thirdparty/embree-aarch64/common/simd/vuint8_avx.h379
-rw-r--r--thirdparty/embree-aarch64/common/simd/vuint8_avx2.h439
-rw-r--r--thirdparty/embree-aarch64/common/sys/alloc.cpp327
-rw-r--r--thirdparty/embree-aarch64/common/sys/alloc.h164
-rw-r--r--thirdparty/embree-aarch64/common/sys/array.h222
-rw-r--r--thirdparty/embree-aarch64/common/sys/atomic.h59
-rw-r--r--thirdparty/embree-aarch64/common/sys/barrier.cpp289
-rw-r--r--thirdparty/embree-aarch64/common/sys/barrier.h112
-rw-r--r--thirdparty/embree-aarch64/common/sys/condition.cpp81
-rw-r--r--thirdparty/embree-aarch64/common/sys/condition.h31
-rw-r--r--thirdparty/embree-aarch64/common/sys/filename.cpp138
-rw-r--r--thirdparty/embree-aarch64/common/sys/filename.h81
-rw-r--r--thirdparty/embree-aarch64/common/sys/intrinsics.h559
-rw-r--r--thirdparty/embree-aarch64/common/sys/library.cpp83
-rw-r--r--thirdparty/embree-aarch64/common/sys/library.h21
-rw-r--r--thirdparty/embree-aarch64/common/sys/mutex.cpp58
-rw-r--r--thirdparty/embree-aarch64/common/sys/mutex.h98
-rw-r--r--thirdparty/embree-aarch64/common/sys/platform.h387
-rw-r--r--thirdparty/embree-aarch64/common/sys/ref.h122
-rw-r--r--thirdparty/embree-aarch64/common/sys/regression.cpp30
-rw-r--r--thirdparty/embree-aarch64/common/sys/regression.h25
-rw-r--r--thirdparty/embree-aarch64/common/sys/string.cpp42
-rw-r--r--thirdparty/embree-aarch64/common/sys/string.h37
-rw-r--r--thirdparty/embree-aarch64/common/sys/sysinfo.cpp676
-rw-r--r--thirdparty/embree-aarch64/common/sys/sysinfo.h192
-rw-r--r--thirdparty/embree-aarch64/common/sys/thread.cpp429
-rw-r--r--thirdparty/embree-aarch64/common/sys/thread.h46
-rw-r--r--thirdparty/embree-aarch64/common/sys/vector.h242
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskscheduler.h17
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h49
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp426
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h386
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskschedulerppl.h46
-rw-r--r--thirdparty/embree-aarch64/common/tasking/taskschedulertbb.h67
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore.h14
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_buffer.h51
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_builder.h125
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_common.h326
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_config.h57
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_device.h87
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_geometry.h383
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_quaternion.h101
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_ray.h378
-rw-r--r--thirdparty/embree-aarch64/include/embree3/rtcore_scene.h160
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/bvh_builder_hair.h411
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/bvh_builder_morton.h501
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur.h692
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur_hair.h526
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/bvh_builder_sah.h669
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_binning.h972
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_aligned.h205
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_unaligned.h302
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_openmerge_array.h443
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_spatial.h414
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_spatial_array.h552
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_strand_array.h188
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/heuristic_timesplit_array.h237
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/priminfo.h362
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/primrefgen.cpp244
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/primrefgen.h28
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/primrefgen_presplit.h371
-rw-r--r--thirdparty/embree-aarch64/kernels/builders/splitter.h169
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh.cpp190
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh.h235
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.cpp1325
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.h316
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.cpp1165
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.h280
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder.cpp60
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder.h114
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_morton.cpp531
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah.cpp640
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_mb.cpp705
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_spatial.cpp201
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.cpp377
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.h263
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel_internal.h267
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_collider.cpp375
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_collider.h72
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_factory.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.cpp330
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.h37
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1_bvh4.cpp61
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_hybrid.h61
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream.h295
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream_filters.h41
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb.h213
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb.h247
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb4d.h107
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_base.h43
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb.h98
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb_mb.h90
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_qaabb.h265
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_node_ref.h242
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_refit.cpp247
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_refit.h95
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.cpp127
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.h37
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp168
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.h285
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_traverser1.h676
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/bvh_traverser_stream.h154
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/node_intersector.h31
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/node_intersector1.h1788
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/node_intersector_frustum.h269
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet.h843
-rw-r--r--thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet_stream.h215
-rw-r--r--thirdparty/embree-aarch64/kernels/common/accel.h556
-rw-r--r--thirdparty/embree-aarch64/kernels/common/accelinstance.h41
-rw-r--r--thirdparty/embree-aarch64/kernels/common/acceln.cpp232
-rw-r--r--thirdparty/embree-aarch64/kernels/common/acceln.h49
-rw-r--r--thirdparty/embree-aarch64/kernels/common/accelset.cpp17
-rw-r--r--thirdparty/embree-aarch64/kernels/common/accelset.h248
-rw-r--r--thirdparty/embree-aarch64/kernels/common/alloc.cpp82
-rw-r--r--thirdparty/embree-aarch64/kernels/common/alloc.h1006
-rw-r--r--thirdparty/embree-aarch64/kernels/common/buffer.h263
-rw-r--r--thirdparty/embree-aarch64/kernels/common/builder.h60
-rw-r--r--thirdparty/embree-aarch64/kernels/common/context.h131
-rw-r--r--thirdparty/embree-aarch64/kernels/common/default.h273
-rw-r--r--thirdparty/embree-aarch64/kernels/common/device.cpp567
-rw-r--r--thirdparty/embree-aarch64/kernels/common/device.h85
-rw-r--r--thirdparty/embree-aarch64/kernels/common/geometry.cpp259
-rw-r--r--thirdparty/embree-aarch64/kernels/common/geometry.h582
-rw-r--r--thirdparty/embree-aarch64/kernels/common/hit.h114
-rw-r--r--thirdparty/embree-aarch64/kernels/common/instance_stack.h199
-rw-r--r--thirdparty/embree-aarch64/kernels/common/isa.h271
-rw-r--r--thirdparty/embree-aarch64/kernels/common/motion_derivative.h325
-rw-r--r--thirdparty/embree-aarch64/kernels/common/point_query.h136
-rw-r--r--thirdparty/embree-aarch64/kernels/common/primref.h138
-rw-r--r--thirdparty/embree-aarch64/kernels/common/primref_mb.h262
-rw-r--r--thirdparty/embree-aarch64/kernels/common/profile.h159
-rw-r--r--thirdparty/embree-aarch64/kernels/common/ray.h1517
-rw-r--r--thirdparty/embree-aarch64/kernels/common/rtcore.cpp1799
-rw-r--r--thirdparty/embree-aarch64/kernels/common/rtcore.h142
-rw-r--r--thirdparty/embree-aarch64/kernels/common/rtcore_builder.cpp442
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene.cpp976
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene.h390
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_curves.h341
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_grid_mesh.h215
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_instance.h272
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_line_segments.h307
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_points.h282
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_quad_mesh.h277
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_subdiv_mesh.h326
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.cpp243
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.h264
-rw-r--r--thirdparty/embree-aarch64/kernels/common/scene_user_geometry.h77
-rw-r--r--thirdparty/embree-aarch64/kernels/common/stack_item.h125
-rw-r--r--thirdparty/embree-aarch64/kernels/common/stat.cpp128
-rw-r--r--thirdparty/embree-aarch64/kernels/common/stat.h116
-rw-r--r--thirdparty/embree-aarch64/kernels/common/state.cpp543
-rw-r--r--thirdparty/embree-aarch64/kernels/common/state.h197
-rw-r--r--thirdparty/embree-aarch64/kernels/common/vector.h76
-rw-r--r--thirdparty/embree-aarch64/kernels/config.h76
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/cone.h321
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/coneline_intersector.h209
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/conelinei_intersector.h141
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNi.h222
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNi_intersector.h569
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNi_mb.h278
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNi_mb_intersector.h516
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNv.h101
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curveNv_intersector.h181
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector.h98
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_distance.h129
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_oriented.h417
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_precalculations.h49
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_ribbon.h214
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_sweep.h362
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual.h671
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h21
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h22
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/cylinder.h223
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/disc_intersector.h216
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/disci_intersector.h277
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/filter.h204
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/grid_intersector.h99
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/grid_soa.h275
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector1.h207
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector_packet.h445
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/instance.h78
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/instance_intersector.h84
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/intersector_epilog.h1074
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/intersector_iterators.h172
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/line_intersector.h141
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/linei.h709
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/linei_intersector.h124
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/object.h84
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/object_intersector.h127
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/plane.h57
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/pointi.h417
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/primitive.h49
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/primitive4.cpp379
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quad_intersector.h76
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quad_intersector_moeller.h566
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quad_intersector_pluecker.h529
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quadi.h483
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quadi_intersector.h350
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quadv.h165
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/quadv_intersector.h181
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/roundline_intersector.h710
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/roundlinei_intersector.h136
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/sphere_intersector.h183
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/spherei_intersector.h156
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subdivpatch1.h38
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subdivpatch1_intersector.h237
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subgrid.h517
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector.h518
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h493
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h508
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/subgrid_mb_intersector.h236
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle.h162
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle_intersector.h96
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_moeller.h403
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_pluecker.h247
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_woop.h418
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/triangle_triangle_intersector.h132
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglei.h442
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglei_intersector.h336
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglev.h157
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglev_intersector.h206
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglev_mb.h201
-rw-r--r--thirdparty/embree-aarch64/kernels/geometry/trianglev_mb_intersector.h211
-rw-r--r--thirdparty/embree-aarch64/kernels/hash.h5
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/bezier_curve.h669
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/bezier_patch.h372
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/bilinear_patch.h191
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/bspline_curve.h319
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/bspline_patch.h449
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/catmullclark_coefficients.h85
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/catmullclark_patch.h562
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/catmullclark_ring.h826
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/catmullrom_curve.h296
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval.h226
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_grid.h359
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_simd.h186
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/gregory_patch.h893
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/gregory_patch_dense.h113
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/gridrange.h96
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/half_edge.h371
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/hermite_curve.h38
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/linear_bezier_patch.h403
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/patch.h371
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/patch_eval.h129
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/patch_eval_grid.h245
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/patch_eval_simd.h127
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/subdivpatch1base.h156
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/tessellation.h161
-rw-r--r--thirdparty/embree-aarch64/kernels/subdiv/tessellation_cache.h325
-rw-r--r--thirdparty/embree-aarch64/patches/godot-changes.patch630
-rw-r--r--thirdparty/enet/godot.cpp74
-rw-r--r--thirdparty/etc2comp/AUTHORS7
-rw-r--r--thirdparty/etc2comp/Etc.cpp128
-rw-r--r--thirdparty/etc2comp/Etc.h71
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.cpp425
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.h172
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.cpp261
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.h148
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4EncodingBits.h315
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp1281
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h186
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp429
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h122
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp447
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h86
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp1730
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h96
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp1819
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h129
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp474
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h121
-rw-r--r--thirdparty/etc2comp/EtcColor.h64
-rw-r--r--thirdparty/etc2comp/EtcColorFloatRGBA.h321
-rw-r--r--thirdparty/etc2comp/EtcConfig.h67
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.cpp173
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.h97
-rw-r--r--thirdparty/etc2comp/EtcErrorMetric.h54
-rw-r--r--thirdparty/etc2comp/EtcFile.cpp390
-rw-r--r--thirdparty/etc2comp/EtcFile.h136
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.cpp185
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.h146
-rw-r--r--thirdparty/etc2comp/EtcFilter.cpp404
-rw-r--r--thirdparty/etc2comp/EtcFilter.h244
-rw-r--r--thirdparty/etc2comp/EtcImage.cpp685
-rw-r--r--thirdparty/etc2comp/EtcImage.h249
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.cpp85
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.h95
-rw-r--r--thirdparty/etc2comp/EtcMath.cpp64
-rw-r--r--thirdparty/etc2comp/EtcMath.h40
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.cpp228
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.h124
-rw-r--r--thirdparty/etc2comp/LICENSE202
-rw-r--r--thirdparty/etc2comp/README.md197
-rw-r--r--thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch224
-rw-r--r--thirdparty/etcpak/AUTHORS.txt3
-rw-r--r--thirdparty/etcpak/Dither.cpp120
-rw-r--r--thirdparty/etcpak/Dither.hpp21
-rw-r--r--thirdparty/etcpak/ForceInline.hpp20
-rw-r--r--thirdparty/etcpak/LICENSE.txt26
-rw-r--r--thirdparty/etcpak/Math.hpp92
-rw-r--r--thirdparty/etcpak/ProcessCommon.hpp50
-rw-r--r--thirdparty/etcpak/ProcessDxtc.cpp956
-rw-r--r--thirdparty/etcpak/ProcessDxtc.hpp11
-rw-r--r--thirdparty/etcpak/ProcessRGB.cpp3100
-rw-r--r--thirdparty/etcpak/ProcessRGB.hpp13
-rw-r--r--thirdparty/etcpak/Tables.cpp221
-rw-r--r--thirdparty/etcpak/Tables.hpp49
-rw-r--r--thirdparty/etcpak/Vector.hpp222
-rw-r--r--thirdparty/harfbuzz/NEWS15
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-common.hh115
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh32
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.cc22
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.h90
-rw-r--r--thirdparty/harfbuzz/src/hb-algs.hh183
-rw-r--r--thirdparty/harfbuzz/src/hb-array.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-atomic.hh129
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.cc27
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.h12
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer-serialize.cc42
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.cc107
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.h59
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh97
-rw-r--r--thirdparty/harfbuzz/src/hb-common.cc50
-rw-r--r--thirdparty/harfbuzz/src/hb-common.h741
-rw-r--r--thirdparty/harfbuzz/src/hb-coretext.cc18
-rw-r--r--thirdparty/harfbuzz/src/hb-deprecated.h93
-rw-r--r--thirdparty/harfbuzz/src/hb-directwrite.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-dispatch.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-draw.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc14
-rw-r--r--thirdparty/harfbuzz/src/hb-face.h15
-rw-r--r--thirdparty/harfbuzz/src/hb-face.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-font.h167
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc38
-rw-r--r--thirdparty/harfbuzz/src/hb-gdi.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-gobject-structs.h32
-rw-r--r--thirdparty/harfbuzz/src/hb-graphite2.cc7
-rw-r--r--thirdparty/harfbuzz/src/hb-iter.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-machinery.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-map.cc9
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h8
-rw-r--r--thirdparty/harfbuzz/src/hb-map.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-mutex.hh18
-rw-r--r--thirdparty/harfbuzz/src/hb-object.hh17
-rw-r--r--thirdparty/harfbuzz/src/hb-open-file.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh46
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff-common.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff1-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cff2-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-cmap-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color.cc11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-deprecated.h18
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-glyf-table.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-head-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh51
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh124
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh250
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc127
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.h66
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.hh3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-math.h85
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-meta.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-meta.h3
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-metrics.cc31
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-metrics.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-name.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-os2-table.hh9
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc47
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh111
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc112
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh22
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh705
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl113
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc104
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh69
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh89
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc100
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh41
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc15
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh1099
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh (renamed from thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc)95
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc160
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh96
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc61
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-complex.hh44
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc41
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag-table.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-tag.cc29
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var.cc10
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var.h29
-rw-r--r--thirdparty/harfbuzz/src/hb-sanitize.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-serialize.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-set.cc33
-rw-r--r--thirdparty/harfbuzz/src/hb-set.h8
-rw-r--r--thirdparty/harfbuzz/src/hb-set.hh87
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-shape.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-style.cc1
-rw-r--r--thirdparty/harfbuzz/src/hb-style.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc27
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh15
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.cc10
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.h50
-rw-r--r--thirdparty/harfbuzz/src/hb-vector.hh11
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h37
-rw-r--r--thirdparty/harfbuzz/src/hb.hh196
-rw-r--r--thirdparty/icu4c/APIChangeReport.md396
-rw-r--r--thirdparty/icu4c/common/bytestriebuilder.cpp26
-rw-r--r--thirdparty/icu4c/common/charstr.cpp34
-rw-r--r--thirdparty/icu4c/common/charstr.h3
-rw-r--r--thirdparty/icu4c/common/cmemory.h55
-rw-r--r--thirdparty/icu4c/common/dictbe.cpp32
-rw-r--r--thirdparty/icu4c/common/edits.cpp1
-rw-r--r--thirdparty/icu4c/common/filteredbrk.cpp93
-rw-r--r--thirdparty/icu4c/common/hash.h19
-rw-r--r--thirdparty/icu4c/common/localematcher.cpp12
-rw-r--r--thirdparty/icu4c/common/localeprioritylist.cpp11
-rw-r--r--thirdparty/icu4c/common/locdispnames.cpp2
-rw-r--r--thirdparty/icu4c/common/locid.cpp244
-rw-r--r--thirdparty/icu4c/common/loclikelysubtags.cpp3
-rw-r--r--thirdparty/icu4c/common/norm2allmodes.h82
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.cpp152
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.h11
-rw-r--r--thirdparty/icu4c/common/pluralmap.h2
-rw-r--r--thirdparty/icu4c/common/putil.cpp4
-rw-r--r--thirdparty/icu4c/common/putilimp.h2
-rw-r--r--thirdparty/icu4c/common/rbbi.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbi_cache.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbiscan.cpp6
-rw-r--r--thirdparty/icu4c/common/rbbitblb.cpp2
-rw-r--r--thirdparty/icu4c/common/resource.h6
-rw-r--r--thirdparty/icu4c/common/restrace.cpp3
-rw-r--r--thirdparty/icu4c/common/servnotf.h4
-rw-r--r--thirdparty/icu4c/common/ubrk.cpp12
-rw-r--r--thirdparty/icu4c/common/ucase.cpp2
-rw-r--r--thirdparty/icu4c/common/uchar.cpp38
-rw-r--r--thirdparty/icu4c/common/ucnv2022.cpp6
-rw-r--r--thirdparty/icu4c/common/ucnv_bld.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_err.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_lmb.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnv_u7.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnvisci.cpp6
-rw-r--r--thirdparty/icu4c/common/ucurr.cpp4
-rw-r--r--thirdparty/icu4c/common/uhash.cpp81
-rw-r--r--thirdparty/icu4c/common/uhash.h95
-rw-r--r--thirdparty/icu4c/common/uloc.cpp42
-rw-r--r--thirdparty/icu4c/common/uloc_keytype.cpp2
-rw-r--r--thirdparty/icu4c/common/uloc_tag.cpp41
-rw-r--r--thirdparty/icu4c/common/ulocimp.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestream.h6
-rw-r--r--thirdparty/icu4c/common/unicode/bytestrie.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestriebuilder.h5
-rw-r--r--thirdparty/icu4c/common/unicode/docmain.h8
-rw-r--r--thirdparty/icu4c/common/unicode/icuplug.h7
-rw-r--r--thirdparty/icu4c/common/unicode/localematcher.h16
-rw-r--r--thirdparty/icu4c/common/unicode/locid.h4
-rw-r--r--thirdparty/icu4c/common/unicode/normalizer2.h28
-rw-r--r--thirdparty/icu4c/common/unicode/platform.h2
-rw-r--r--thirdparty/icu4c/common/unicode/stringpiece.h26
-rw-r--r--thirdparty/icu4c/common/unicode/ubrk.h21
-rw-r--r--thirdparty/icu4c/common/unicode/ucnv.h4
-rw-r--r--thirdparty/icu4c/common/unicode/ucnvsel.h4
-rw-r--r--thirdparty/icu4c/common/unicode/unifilt.h4
-rw-r--r--thirdparty/icu4c/common/unicode/uniset.h66
-rw-r--r--thirdparty/icu4c/common/unicode/unistr.h8
-rw-r--r--thirdparty/icu4c/common/unicode/urename.h16
-rw-r--r--thirdparty/icu4c/common/unicode/uset.h95
-rw-r--r--thirdparty/icu4c/common/unicode/ushape.h2
-rw-r--r--thirdparty/icu4c/common/unicode/utrace.h17
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h12
-rw-r--r--thirdparty/icu4c/common/uniset.cpp128
-rw-r--r--thirdparty/icu4c/common/uniset_props.cpp116
-rw-r--r--thirdparty/icu4c/common/unisetspan.cpp25
-rw-r--r--thirdparty/icu4c/common/uprops.h52
-rw-r--r--thirdparty/icu4c/common/uresbund.cpp23
-rw-r--r--thirdparty/icu4c/common/uresdata.cpp8
-rw-r--r--thirdparty/icu4c/common/uresimp.h4
-rw-r--r--thirdparty/icu4c/common/uset.cpp35
-rw-r--r--thirdparty/icu4c/common/usprep.cpp2
-rw-r--r--thirdparty/icu4c/common/ustr_wcs.cpp4
-rw-r--r--thirdparty/icu4c/common/utext.cpp6
-rw-r--r--thirdparty/icu4c/common/util.h6
-rw-r--r--thirdparty/icu4c/common/utracimp.h2
-rw-r--r--thirdparty/icu4c/common/uvector.cpp4
-rw-r--r--thirdparty/icu4c/common/wintz.cpp24
-rw-r--r--thirdparty/icu4c/icudt69l.dat (renamed from thirdparty/icu4c/icudt68l.dat)bin3846720 -> 3851952 bytes
-rw-r--r--thirdparty/mbedtls/include/mbedtls/config.h17
-rw-r--r--thirdparty/mbedtls/include/mbedtls/ctr_drbg.h45
-rw-r--r--thirdparty/mbedtls/include/mbedtls/entropy.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/hmac_drbg.h58
-rw-r--r--thirdparty/mbedtls/include/mbedtls/net_sockets.h18
-rw-r--r--thirdparty/mbedtls/include/mbedtls/rsa.h6
-rw-r--r--thirdparty/mbedtls/include/mbedtls/threading.h3
-rw-r--r--thirdparty/mbedtls/include/mbedtls/version.h8
-rw-r--r--thirdparty/mbedtls/library/base64.c131
-rw-r--r--thirdparty/mbedtls/library/bignum.c6
-rw-r--r--thirdparty/mbedtls/library/ctr_drbg.c16
-rw-r--r--thirdparty/mbedtls/library/ecdsa.c8
-rw-r--r--thirdparty/mbedtls/library/ecjpake.c11
-rw-r--r--thirdparty/mbedtls/library/entropy.c7
-rw-r--r--thirdparty/mbedtls/library/hmac_drbg.c20
-rw-r--r--thirdparty/mbedtls/library/net_sockets.c14
-rw-r--r--thirdparty/mbedtls/library/pkwrite.c22
-rw-r--r--thirdparty/mbedtls/library/rsa.c28
-rw-r--r--thirdparty/mbedtls/library/threading.c6
-rw-r--r--thirdparty/mbedtls/library/version_features.c3
-rw-r--r--thirdparty/meshoptimizer/LICENSE.md2
-rw-r--r--thirdparty/meshoptimizer/clusterizer.cpp616
-rw-r--r--thirdparty/meshoptimizer/indexgenerator.cpp206
-rw-r--r--thirdparty/meshoptimizer/meshoptimizer.h104
-rw-r--r--thirdparty/meshoptimizer/simplifier.cpp2
-rw-r--r--thirdparty/meshoptimizer/vertexcodec.cpp14
-rw-r--r--thirdparty/miniupnpc/LICENSE5
-rw-r--r--thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c79
-rw-r--r--thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h14
-rw-r--r--thirdparty/miniupnpc/miniupnpc/connecthostport.c6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/listdevices.c197
-rw-r--r--thirdparty/miniupnpc/miniupnpc/minisoap.c6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/minissdpc.c232
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc.c35
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc.h6
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c721
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/miniwget.c15
-rw-r--r--thirdparty/miniupnpc/miniupnpc/portlistingparse.c2
-rw-r--r--thirdparty/miniupnpc/miniupnpc/receivedata.c10
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnpc.c864
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnpdev.h16
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnperrors.c112
-rw-r--r--thirdparty/miniupnpc/miniupnpc/upnperrors.h26
-rw-r--r--thirdparty/miniupnpc/miniupnpc/win32_snprintf.h71
-rw-r--r--thirdparty/miniupnpc/windows_fix.diff16
2346 files changed, 226147 insertions, 64550 deletions
diff --git a/.editorconfig b/.editorconfig
index 49517a5104..7743622e78 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,7 +17,8 @@ indent_size = 4
indent_style = space
indent_size = 4
-[.travis.yml]
+# YAML requires indentation with spaces instead of tabs.
+[*.{yml,yaml}]
indent_style = space
indent_size = 2
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 7ac70a4367..09ff2454ee 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,56 +2,181 @@
# Each line is a file pattern followed by one or more owners.
# Owners can be @users, @org/teams or emails
-/doc/ @godotengine/documentation
-doc_classes/* @godotengine/documentation
-
-# Rendering
-/drivers/gl_context/ @reduz
-/drivers/gles2/ @reduz
-/drivers/gles3/ @reduz
-
-# Audio
-/drivers/alsa/ @marcelofg55
-/drivers/alsamidi/ @marcelofg55
-/drivers/coreaudio/ @marcelofg55
-/drivers/coremidi/ @marcelofg55
-/drivers/pulseaudio/ @marcelofg55
-/drivers/wasapi/ @marcelofg55
-/drivers/winmidi/ @marcelofg55
-/drivers/xaudio2/ @marcelofg55
-
-/drivers/unix/ @hpvb
-/drivers/windows/ @hpvb
-
-/editor/icons/ @djrm
-
-/misc/ @akien-mga
-
-/modules/bullet/ @AndreaCatania
-/modules/csg/ @BastiaanOlij
-/modules/enet/ @godotengine/network
-/modules/gdnative/*arvr/ @BastiaanOlij
-/modules/gdnative/text/ @bruvzg
-/modules/gdscript/ @vnen
-/modules/mbedtls/ @godotengine/network
-/modules/mobile_vr/ @BastiaanOlij
-/modules/mono/ @neikeq
-/modules/mono/glue/GodotSharp @aaronfranke
-/modules/opensimplex/ @JFonS
-/modules/regex/ @LeeZH
-/modules/text_server_*/ @bruvzg
-/modules/upnp/ @godotengine/network
-/modules/websocket/ @godotengine/network
-
-/platform/javascript/ @eska014
-/platform/uwp/ @vnen
-
-/scene/resources/font.* @bruvzg
-/scene/resources/text_line.* @bruvzg
-/scene/resources/text_paragraph.* @bruvzg
-
-/servers/physics*/ @reduz @AndreaCatania
-/servers/text_server.* @bruvzg
-/servers/visual*/ @reduz
-
-/thirdparty/ @akien-mga
+# Buildsystem
+
+.* @godotengine/buildsystem
+.github/ @godotengine/buildsystem
+*.py @godotengine/buildsystem
+SConstruct @godotengine/buildsystem
+SCsub @godotengine/buildsystem
+
+# Core
+
+/core/ @godotengine/core
+/core/crypto/ @godotengine/network
+/core/debugger/ @godotengine/debugger
+/core/input/ @godotengine/input
+
+# Doc
+
+/doc/ @godotengine/documentation
+doc_classes/* @godotengine/documentation
+
+# Drivers
+
+## Audio
+/drivers/alsa/ @godotengine/audio
+/drivers/alsamidi/ @godotengine/audio
+/drivers/coreaudio/ @godotengine/audio
+/drivers/coremidi/ @godotengine/audio
+/drivers/pulseaudio/ @godotengine/audio
+/drivers/wasapi/ @godotengine/audio
+/drivers/winmidi/ @godotengine/audio
+/drivers/xaudio2/ @godotengine/audio
+
+## Rendering
+/drivers/dummy/ @godotengine/rendering
+/drivers/spirv-reflect/ @godotengine/rendering
+/drivers/vulkan/ @godotengine/rendering
+
+## OS
+/drivers/unix/ @godotengine/_platforms
+/drivers/windows/ @godotengine/windows
+
+## Misc
+/drivers/png/ @godotengine/import
+
+# Editor
+
+/editor/*debugger* @godotengine/debugger
+/editor/icons/ @godotengine/usability
+/editor/import/ @godotengine/import
+/editor/plugins/*2d_*.* @godotengine/2d-editor
+/editor/plugins/*3d_*.* @godotengine/3d-editor
+/editor/plugins/script_*.* @godotengine/script-editor
+/editor/plugins/*shader*.* @godotengine/shaders
+/editor/code_editor.* @godotengine/script-editor
+/editor/*dock*.* @godotengine/docks
+/editor/*shader*.* @godotengine/shaders
+
+# Main
+
+/main/ @godotengine/core
+
+# Misc
+
+/misc/ @godotengine/buildsystem
+
+# Modules
+
+## Audio (+ video)
+/modules/minimp3/ @godotengine/audio
+/modules/ogg/ @godotengine/audio
+/modules/opus/ @godotengine/audio
+/modules/stb_vorbis/ @godotengine/audio
+/modules/theora/ @godotengine/audio
+/modules/vorbis/ @godotengine/audio
+/modules/webm/ @godotengine/audio
+
+## Import
+/modules/basis_universal/ @godotengine/import
+/modules/bmp/ @godotengine/import
+/modules/cvtt/ @godotengine/import
+/modules/dds/ @godotengine/import
+/modules/etc/ @godotengine/import
+/modules/fbx/ @godotengine/import
+/modules/gltf/ @godotengine/import
+/modules/hdr/ @godotengine/import
+/modules/jpg/ @godotengine/import
+/modules/pvr/ @godotengine/import
+/modules/squish/ @godotengine/import
+/modules/svg/ @godotengine/import
+/modules/tga/ @godotengine/import
+/modules/tinyexr/ @godotengine/import
+/modules/webp/ @godotengine/import
+
+## Network
+/modules/enet/ @godotengine/network
+/modules/mbedtls/ @godotengine/network
+/modules/upnp/ @godotengine/network
+/modules/webrtc/ @godotengine/network
+/modules/websocket/ @godotengine/network
+
+## Rendering
+/modules/denoise/ @godotengine/rendering
+/modules/glslang/ @godotengine/rendering
+/modules/lightmapper_rd/ @godotengine/rendering
+/modules/meshoptimizer/ @godotengine/rendering
+/modules/vhacd/ @godotengine/rendering
+/modules/xatlas_unwrap/ @godotengine/rendering
+
+## Scripting
+/modules/gdnative/ @godotengine/gdnative
+/modules/gdscript/ @godotengine/gdscript
+/modules/jsonrpc/ @godotengine/gdscript
+/modules/mono/ @godotengine/mono
+/modules/visual_script/ @godotengine/visualscript
+
+## Text
+/modules/freetype/ @godotengine/buildsystem
+/modules/gdnative/text/ @godotengine/gui-nodes
+/modules/text_server_adv/ @godotengine/gui-nodes
+/modules/text_server_fb/ @godotengine/gui-nodes
+
+## XR
+/modules/camera/ @godotengine/xr
+/modules/gdnative/xr/ @godotengine/xr
+/modules/mobile_vr/ @godotengine/xr
+/modules/webxr/ @godotengine/xr
+
+## Misc
+/modules/bullet/ @godotengine/physics
+/modules/csg/ @godotengine/3d-nodes
+/modules/gdnavigation/ @godotengine/navigation
+/modules/gridmap/ @godotengine/3d-nodes
+/modules/opensimplex/ @godotengine/3d-nodes
+/modules/regex/ @godotengine/core
+
+# Platform
+
+/platform/android/ @godotengine/android
+/platform/iphone/ @godotengine/ios
+/platform/javascript/ @godotengine/html5
+/platform/linuxbsd/ @godotengine/linux-bsd
+/platform/osx/ @godotengine/macos
+/platform/uwp/ @godotengine/uwp
+/platform/windows/ @godotengine/windows
+
+# Scene
+
+/scene/2d/ @godotengine/2d-nodes
+/scene/3d/ @godotengine/3d-nodes
+/scene/animation/ @godotengine/animation
+/scene/audio/ @godotengine/audio
+/scene/debugger/ @godotengine/debugger
+/scene/gui/ @godotengine/gui-nodes
+/scene/main/ @godotengine/core
+/scene/resources/default_theme/ @godotengine/gui-nodes
+/scene/resources/font.* @godotengine/gui-nodes
+/scene/resources/text_line.* @godotengine/gui-nodes
+/scene/resources/text_paragraph.* @godotengine/gui-nodes
+/scene/resources/visual_shader*.* @godotengine/shaders
+
+# Servers
+
+/servers/audio* @godotengine/audio
+/servers/camera* @godotengine/xr
+/servers/display_server.* @godotengine/_platforms
+/servers/navigation_server*.* @godotengine/navigation
+/servers/physics* @godotengine/physics
+/servers/rendering* @godotengine/rendering
+/servers/text_server.* @godotengine/gui-nodes
+/servers/xr* @godotengine/xr
+
+# Tests
+
+/tests/ @godotengine/tests
+
+# Thirdparty
+
+/thirdparty/ @godotengine/buildsystem
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml
index 697600abe3..b24a36beef 100644
--- a/.github/workflows/android_builds.yml
+++ b/.github/workflows/android_builds.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=android verbose=yes warnings=extra werror=yes --jobs=2 module_text_server_fb_enabled=yes
+ SCONSFLAGS: platform=android verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_LIMIT: 4096
ANDROID_NDK_VERSION: 21.1.6352462
diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml
index 73a1b2934e..c4da3cb683 100644
--- a/.github/workflows/ios_builds.yml
+++ b/.github/workflows/ios_builds.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=iphone verbose=yes warnings=extra werror=yes --jobs=2 module_text_server_fb_enabled=yes
+ SCONSFLAGS: platform=iphone verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_LIMIT: 4096
jobs:
diff --git a/.github/workflows/javascript_builds.disabled b/.github/workflows/javascript_builds.disabled
index 015a1f314c..006981f3d4 100644
--- a/.github/workflows/javascript_builds.disabled
+++ b/.github/workflows/javascript_builds.disabled
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=javascript verbose=yes warnings=extra werror=yes --jobs=2
+ SCONSFLAGS: platform=javascript verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2
SCONS_CACHE_LIMIT: 4096
EM_VERSION: 1.39.20
EM_CACHE_FOLDER: 'emsdk-cache'
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index f4c377b921..7b144e6e43 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=linuxbsd verbose=yes warnings=extra werror=yes --jobs=2 module_text_server_fb_enabled=yes
+ SCONSFLAGS: platform=linuxbsd verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_LIMIT: 4096
jobs:
@@ -76,9 +76,9 @@ jobs:
path: bin/*
retention-days: 14
- linux-editor-sanitizers-mono:
+ linux-editor-sanitizers:
runs-on: "ubuntu-20.04"
- name: Editor w/ Mono and sanitizers (target=debug, tools=yes, tests=yes, use_asan=yes, use_ubsan=yes)
+ name: Editor and sanitizers (target=debug, tools=yes, tests=yes, use_asan=yes, use_ubsan=yes)
steps:
- uses: actions/checkout@v2
@@ -94,7 +94,8 @@ jobs:
- name: Configure dependencies
run: |
sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \
- libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm
+ libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm \
+ xvfb wget unzip
# Upload cache on completion and check it out now
- name: Load .scons_cache directory
@@ -126,17 +127,47 @@ jobs:
scons --version
# We should always be explicit with our flags usage here since it's gonna be sure to always set those flags
+ # [Workaround] SwiftShader doesn't support tesselation, so we skip Godot check about it
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
- scons tools=yes tests=yes target=debug module_mono_enabled=yes mono_glue=no use_asan=yes use_ubsan=yes
+ sed -i "s|ERR_FAIL_COND_V(p_rasterization_state.patch_control_points|//ERR_FAIL_COND_V(p_rasterization_state.patch_control_points|" drivers/vulkan/rendering_device_vulkan.cpp
+ scons tools=yes tests=yes target=debug debug_symbols=no use_asan=yes use_ubsan=yes
ls -l bin/
# Execute unit tests for the editor
- name: Unit Tests
run: |
- ./bin/godot.linuxbsd.tools.64s.mono --test
+ ./bin/godot.linuxbsd.tools.64s --test
+
+ # Download, unzip and setup SwiftShader library [d4550ab8d3f]
+ - name: Download SwiftShader
+ run: |
+ wget https://github.com/qarmin/gtk_library_store/releases/download/3.24.0/swiftshader.zip
+ unzip swiftshader.zip
+ rm swiftshader.zip
+ curr="$(pwd)/libvk_swiftshader.so"
+ sed -i "s|PATH_TO_CHANGE|$curr|" vk_swiftshader_icd.json
+
+ # Download and extract zip archive with project, folder is renamed to be able to easy change used project
+ - name: Download test project
+ run: |
+ wget https://github.com/qarmin/RegressionTestProject/archive/4.0.zip
+ unzip 4.0.zip
+ mv "RegressionTestProject-4.0" "test_project"
+
+ # Editor is quite complicated piece of software, so it is easy to introduce bug here
+ - name: Open and close editor
+ run: |
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.tools.64s --audio-driver Dummy -e -q --path test_project 2>&1 | tee sanitizers_log.txt || true
+ misc/scripts/check_ci_log.py sanitizers_log.txt
+
+ # Run test project
+ - name: Run project
+ run: |
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.tools.64s 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true
+ misc/scripts/check_ci_log.py sanitizers_log.txt
linux-template-mono:
runs-on: "ubuntu-20.04"
@@ -191,7 +222,7 @@ jobs:
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
- scons target=release tools=no module_mono_enabled=yes mono_glue=no debug_symbols=no
+ scons target=release tools=no module_mono_enabled=yes mono_glue=no
ls -l bin/
- uses: actions/upload-artifact@v2
diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml
index 803c8f8ec4..a15ab92052 100644
--- a/.github/workflows/macos_builds.yml
+++ b/.github/workflows/macos_builds.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=osx verbose=yes warnings=extra werror=yes --jobs=2 module_text_server_fb_enabled=yes
+ SCONSFLAGS: platform=osx verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_LIMIT: 4096
jobs:
@@ -104,7 +104,7 @@ jobs:
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
- scons target=release tools=no debug_symbols=no
+ scons target=release tools=no
ls -l bin/
- uses: actions/upload-artifact@v2
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 12270a848a..30468034ff 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -35,11 +35,12 @@ jobs:
run: |
bash ./misc/scripts/black_format.sh
- - name: JavaScript style checks via ESLint
+ - name: JavaScript style and documentation checks via ESLint and JSDoc
run: |
cd platform/javascript
npm ci
npm run lint
+ npm run docs -- -d dry-run
- name: Documentation checks
run: |
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index b9bf510c71..b7cc127226 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -5,7 +5,7 @@ on: [push, pull_request]
# SCONS_CACHE for windows must be set in the build environment
env:
GODOT_BASE_BRANCH: master
- SCONSFLAGS: platform=windows verbose=yes warnings=all werror=yes --jobs=2 module_text_server_fb_enabled=yes
+ SCONSFLAGS: platform=windows verbose=yes warnings=all werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_MSVC_CONFIG: true
SCONS_CACHE_LIMIT: 3072
@@ -24,7 +24,7 @@ jobs:
# Editing this is pretty dangerous for Windows since it can break and needs to be properly tested with a fresh cache.
- name: Load .scons_cache directory
id: windows-editor-cache
- uses: RevoluPowered/cache@v2.1
+ uses: actions/cache@v2
with:
path: /.scons_cache/
key: ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
@@ -110,7 +110,7 @@ jobs:
env:
SCONS_CACHE: /.scons_cache/
run: |
- scons target=release tools=no debug_symbols=no
+ scons target=release tools=no
ls -l bin/
- uses: actions/upload-artifact@v2
diff --git a/.mailmap b/.mailmap
index 73128d27db..3cb0a91356 100644
--- a/.mailmap
+++ b/.mailmap
@@ -6,6 +6,7 @@ Anish Bhobe <anishbhobe@hotmail.com>
Anutrix <numaanzaheerahmed@yahoo.com>
Aren Villanueva <arenvillanueva@yomogi-soft.com> <aren@displaysweet.com>
Ariel Manzur <ariel@godotengine.org>
+Ariel Manzur <ariel@godotengine.org> <puntob@gmail.com>
Ariel Manzur <ariel@godotengine.org> <punto@godotengine.org>
Ariel Manzur <ariel@godotengine.org> <ariel@okamstudio.com>
Ariel Manzur <ariel@godotengine.org> <punto@Ariels-Mac-mini.local>
@@ -25,6 +26,7 @@ Daniel J. Ramirez <djrmuv@gmail.com>
Dominik 'dreamsComeTrue' Jasiński <dominikjasinski@o2.pl>
Emmanuel Barroga <emmanuelbarroga@gmail.com>
Eric M <itsjusteza@gmail.com>
+Eric Rybicki <info@ericrybicki.com> <stratos695@googlemail.com>
Erik Selecký <35656626+rxlecky@users.noreply.github.com>
Erik Selecký <35656626+rxlecky@users.noreply.github.com> <35656626+SeleckyErik@users.noreply.github.com>
Fabian <supagu@gmail.com>
@@ -38,6 +40,7 @@ Gilles Roudiere <gilles.roudiere@gmail.com> <gilles.roudiere@laas.fr>
Gordon MacPherson <gordon@gordonite.tech>
Guilherme Felipe <guilhermefelipecgs@gmail.com>
Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
+HaSa1002 <johawitt@outlook.de>
Hein-Pieter van Braam-Stewart <hp@tmm.cx>
Hubert Jarosz <marqin.pl@gmail.com>
Hubert Jarosz <marqin.pl@gmail.com> <marqin.pl+git@gmail.com>
@@ -63,6 +66,7 @@ Juan Linietsky <reduzio@gmail.com> <red@kyoko>
Julian Murgia <the.straton@gmail.com>
Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com>
Kelly Thomas <kelly.thomas@hotmail.com.au>
+Kongfa Waroros <gongpha@hotmail.com>
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
Leon Krause <lk@leonkrause.com> <eska@eska.me>
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
@@ -84,6 +88,7 @@ Mateo Kuruk Miccino <mateomiccino@gmail.com>
Max Hilbrunner <m.hilbrunner@gmail.com>
Max Hilbrunner <m.hilbrunner@gmail.com> <mhilbrunner@users.noreply.github.com>
Michael Alexsander <michaelalexsander@protonmail.com>
+Nathan Franke <natfra@pm.me> <nathanwfranke@gmail.com>
Nathan Lovato <nathan@gdquest.com>
Nathan Warden <nathan@nathanwarden.com> <nathanwardenlee@icloud.com>
Nils ANDRÉ-CHANG <nils@nilsand.re>
@@ -97,7 +102,7 @@ Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
Poommetee Ketson <poommetee@protonmail.com>
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
-Rafał Mikrut <mikrutrafal54@gmail.com>
+Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@users.noreply.github.com>
Ramesh Ravone <ramesh.maran443@gmail.com>
@@ -123,5 +128,6 @@ Wilhem Barbier <nounoursheureux@openmailbox.org> <wilhem.b@free.fr>
Wilhem Barbier <nounoursheureux@openmailbox.org> <schtroumps31@gmail.com>
Will Nations <willnationsdev@gmail.com>
yg2f <yoann@terminajones.com>
+Yuri Sizov <yuris@humnom.net> <pycbouh@users.noreply.github.com>
Zak Stam <zakscomputers@hotmail.com>
Zher Huei Lee <lee.zh.92@gmail.com>
diff --git a/AUTHORS.md b/AUTHORS.md
index 1ebef77509..7c5eb0c56b 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -100,6 +100,7 @@ name is available.
James Buck (jbuck3)
Jérôme Gully (Nutriz)
Jia Jun Chai (SkyLucilfer)
+ jmb462
Joan Fons Sanchez (JFonS)
Johannes Witt (HaSa1002)
Johan Manuel (29jm)
@@ -108,12 +109,14 @@ name is available.
Julian Murgia (StraToN)
Justo Delgado (mrcdk)
Kelly Thomas (KellyThomas)
+ Kongfa Waroros (gongpha)
Kostadin Damyanov (Max-Might)
K. S. Ernest (iFire) Lee (fire)
lawnjelly
Leon Krause (leonkrause)
Liz Haas (27thLiz)
Lucien Menassol (Kanabenki)
+ Lyuma
m4nu3lf
Maganty Rushyendra (mrushyendra)
Marcel Admiraal (madmiraal)
@@ -138,6 +141,7 @@ name is available.
MichiRecRoom (LikeLakers2)
mrezai
muiroc
+ Nathan Franke (nathanfranke)
Nathan Lovato (NathanLovato)
Nathan Warden (NathanWarden)
Nils André-Chang (NilsIrl)
@@ -161,6 +165,7 @@ name is available.
Ray Koopa (RayKoopa)
Rémi Verschelde (akien-mga)
Rhody Lugo (rraallvv)
+ Ricardo Subtil (Ev1lbl0w)
Roberto F. Arroyo (robfram)
Robin Hübner (profan)
romulox-x
@@ -191,6 +196,7 @@ name is available.
Xavier Cho (mysticfall)
yg2f (SuperUserNameMan)
Yuri Roubinsky (Chaosus)
+ Yuri Sizov (pycbouh)
Zak Stam (zaksnet)
Zher Huei Lee (leezh)
ZuBsPaCe
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88c9e1a8a0..fe5631cefd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,7 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Ability to convert visual shaders to text-based shaders.
- See the [complete list of new functions](https://github.com/godotengine/godot/pull/26164).
- Improved visual scripting.
- - Visual scripting now uses an unified graph where all functions are represented.
+ - Visual scripting now uses a unified graph where all functions are represented.
- Nodes can now be edited directly in the graph.
- Support for fuzzy searching.
- The `tool` mode can now be enabled in visual scripts.
@@ -900,7 +900,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Removed many debugging prints in the console.
- Export templates now display an error dialog if no project was found when starting.
- DynamicFont oversampling is now enabled by default.
-- Nodes' internal logic now consistently use internal physics processing.
+- Nodes' internal logic now consistently uses internal physics processing.
- Allow attaching and clearing scripts on multiple nodes at once.
- Default values are no longer saved in scene and resource files.
- The selection rectangle of 2D nodes is now hidden when not pertinent (no more rectangle for collision shapes).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4387750f28..d7a4f976bf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -241,25 +241,21 @@ discussions and support, others more for development discussions.
To communicate with developers (e.g. to discuss a feature you want to implement
or a bug you want to fix), the following channels can be used:
-- [GitHub issues](https://github.com/godotengine/godot/issues): If there is an
- existing issue about a topic you want to discuss, just add a comment to it -
- all developers watch the repository and will get an email notification. You
- can also create a new issue - please keep in mind to create issues only to
- discuss quite specific points about the development, and not general user
- feedback or support requests.
-- [#godotengine-devel IRC channel on
- Freenode](https://webchat.freenode.net/?channels=godotengine-devel): You will
- find most core developers there, so it's the go-to channel for direct chat
+- [Godot Contributors Chat](https://chat.godotengine.org): You will
+ find most core developers there, so it's the go-to platform for direct chat
about Godot Engine development. Feel free to start discussing something there
to get some early feedback before writing up a detailed proposal in a GitHub
issue.
-- [devel@godotengine.org mailing
- list](https://listengine.tuxfamily.org/godotengine.org/devel/): Mailing list
- for Godot developers, used primarily to announce developer meetings on IRC
- and other important discussions that need to reach people directly in their
- mailbox. See the [index
- page](https://listengine.tuxfamily.org/godotengine.org/devel/) for
- subscription instructions.
+- [Bug tracker](https://github.com/godotengine/godot/issues): If there is an
+ existing issue about a topic you want to discuss, just add a comment to it -
+ many developers watch the repository and will get a notification. You can
+ also create a new issue - please keep in mind to create issues only to
+ discuss quite specific points about the development, and not general user
+ feedback or support requests.
+- [Feature proposals](https://github.com/godotengine/godot-proposals/issues):
+ To propose a new feature, we have a dedicated issue tracker for that. Don't
+ hesitate to start by talking about your idea on the Godot Contributors Chat
+ to make sure that it makes sense in Godot's context.
Thanks for your interest in contributing!
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index b9b15abf5d..9e63da3fc4 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -72,6 +72,11 @@ Copyright: 2008-2016, The Android Open Source Project
2002, Google, Inc.
License: Apache-2.0
+Files: ./servers/physics_3d/collision_solver_3d_sat.cpp
+Comment: Open Dynamics Engine
+Copyright: 2001-2003, Russell L. Smith, Alen Ladavac, Nguyen Binh
+License: BSD-3-clause
+
Files: ./servers/physics_3d/gjk_epa.cpp
./servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
./servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -82,6 +87,10 @@ Files: ./servers/physics_3d/gjk_epa.cpp
./servers/physics_3d/joints/pin_joint_3d_sw.h
./servers/physics_3d/joints/slider_joint_3d_sw.cpp
./servers/physics_3d/joints/slider_joint_3d_sw.h
+ ./servers/physics_3d/soft_body_3d_sw.cpp
+ ./servers/physics_3d/soft_body_3d_sw.h
+ ./servers/physics_3d/shape_3d_sw.cpp
+ ./servers/physics_3d/shape_3d_sw.h
Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2003-2008, Erwin Coumans
2007-2021, Juan Linietsky, Ariel Manzur.
@@ -127,10 +136,10 @@ Comment: ENet
Copyright: 2002-2020, Lee Salzman
License: Expat
-Files: ./thirdparty/etc2comp/
-Comment: Etc2Comp
-Copyright: 2015, Etc2Comp Authors
-License: Apache-2.0
+Files: ./thirdparty/etcpak/
+Comment: etcpak
+Copyright: 2013-2021, Bartosz Taudul
+License: BSD-3-clause
Files: ./thirdparty/fonts/DroidSans*.ttf
Comment: DroidSans font
@@ -189,7 +198,7 @@ License: HarfBuzz
Files: ./thirdparty/icu4c/
Comment: International Components for Unicode
-Copyright: 1991-2020, Unicode
+Copyright: 1991-2021, Unicode
License: Unicode
Files: ./thirdparty/jpeg-compressor/
@@ -254,7 +263,7 @@ License: Apache-2.0
Files: ./thirdparty/meshoptimizer/
Comment: meshoptimizer
-Copyright: 2016-2020, Arseny Kapoulkine
+Copyright: 2016-2021, Arseny Kapoulkine
License: Expat
Files: ./thirdparty/minimp3/
@@ -264,7 +273,7 @@ License: CC0-1.0
Files: ./thirdparty/miniupnpc/
Comment: MiniUPnPc
-Copyright: 2005-2019, Thomas Bernard
+Copyright: 2005-2021, Thomas Bernard
License: BSD-3-clause
Files: ./thirdparty/minizip/
diff --git a/DONORS.md b/DONORS.md
index a852f08287..77fa564a1b 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -32,6 +32,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Garry Newman
Gordon MacPherson
Hunter Dickson
+ Kyle Szklenski
## Mini sponsors
@@ -39,6 +40,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Alejandro Saucedo
alex brown
Andrew Dunai
+ anti666
+ Ben Nolan
+ blurp
CD
Christian Baune
Christoffer Sundbom
@@ -48,6 +52,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Digital Grows
Dov Zimring
Edward Flick
+ Florian Neumann
Gamechuck
GameDev.net
Hein-Pieter van Braam
@@ -58,6 +63,7 @@ generous deed immortalized in the next stable release of Godot Engine.
John G Gentzel
Jonah Stich
Justin Arnold
+ Kamil Brzezinski
Marcel Kräml
Matthieu Huvé
Maxim Karsten
@@ -67,14 +73,15 @@ generous deed immortalized in the next stable release of Godot Engine.
Patrick Horn
Patrick Schmidt
Péter Magyar
+ Rami
Ronnie Cheng
Slobodan Milnovic
Stephan Lanfermann
Steve
Thomas Krampl
Tristan Pemble
- VilliHaukka
Violin Iliev
+ Xwdit
## Gold donors
@@ -82,7 +89,7 @@ generous deed immortalized in the next stable release of Godot Engine.
albinaask
Alvaro A Baena R
Asher Glick
- Bernhard Werner
+ Barugon
Carlo Cabanilla
Chris Goddard
Christopher Case
@@ -92,20 +99,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Don B
Ed Morley
Ellen Poe
- Florian Neumann
Florian Rämisch
Forge
Gamejunkey
- Grady
Hoojib
Jakub Grzesik
Javier Roman
- Jeff Nyte
Joan Fons
Johnny IV Young
Jon Woodward
Karl Werf
Klavdij Voncina
+ kuku
Lex Steers
Luke
Maciej Pendolski
@@ -115,13 +120,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Matthew Hillier
Michael
m kaersten
- Mohamed Ikbel Boulabiar
Monster Vial
Officine Pixel S.n.c.
- Pixel Booty
- Rami
Rene
- Rene Tailleur
Retro Village
Rob Messick
Roland Fredenhagen
@@ -142,26 +143,21 @@ generous deed immortalized in the next stable release of Godot Engine.
Xeno Coliseum
Zaven Muradyan
- Aaron Winter
Adam Nakonieczny
Adrian Adamiak
- Aleksey Korotkevich
Alexander J Maynard
Alex de la Mare
Alexey Dyadchenko
Alex Khayrullin
alice gambrell
Andreas Funke
- André Frélicot
Andrew Cunningham
- Anm
Antanas Paskauskas
Antoni Batchelli
Arisaka Mayuki
Arthur S. Muszynski
- Aubin Detrez
- Barugon
Ben Botwin
+ Brandon Hawkinson
Caleb Sizemore
Can Eris
Charlie Whitfield
@@ -170,8 +166,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Chris Petrich
Chris Serino
Christian Leth Jeppesen
- Cody Brooks
- Conrad Curry
Craig Ostrin
Craig Smith
Cristopher
@@ -185,21 +179,21 @@ generous deed immortalized in the next stable release of Godot Engine.
Donn Eddy
Easypete
Edgar Sun
+ Eric Brand
Eugenio Hugo Salgüero Jáñez
+ EXUREI
flesk
F S
Gabrielius Vaiškūnas
Gary Hulst
gavlig
+ General Chicken
GGGames.org
- GiulianoB
- Green Fox
Guilherme Felipe de C. G. da Silva
Harvey Fong
Heath Hayes
Horváth Péter
Hu Hund
- Idilio Alfaro
Jake Burga
James Couzens
Jared
@@ -209,10 +203,12 @@ generous deed immortalized in the next stable release of Godot Engine.
Joel Höglund
Johnathan Kupferer
Jose Malheiro
+ Jose Manuel Muñoz Perez
Joseph Crane
Joshie Sparks
Joshua Flores
Joshua Lesperance
+ Juan T Chen
Juan Velandia
Judd
Julian Todd
@@ -226,18 +222,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Lachie
Lain Ballard
Laszlo Kiss
+ leetNightshade
Leo Fidel R Liban
Liam Smyth
Luc-Frédéric Langis
- luka duren
+ Łukasz Nowak
MadScientistCarl
Marcelo Dornbusch Lopes
Marcus Dobler
Marcus Richter
- Marisa Clardy
+ Marek Belski
Mark Barrett
- Mark Diaz
- Markus Fehr
Martin Eigel
Martin Kotz
Martin Soucek
@@ -247,18 +242,19 @@ generous deed immortalized in the next stable release of Godot Engine.
medecau
Michael
Michael Dürwald
- Michael Noll
Michael Policastro
+ MightyPossum
MikadoSC
MuffinManKen
+ nate etan
Nick Abousselam
- Nick Barovic
+ Nicole Barovic
Oliver Dick
Oscar Campos
- Patrick Brock
Patrick Ting
Paul Hocker
Paul Von Zimmerman
+ Pavel Kotlyar
Pedro Silva
Pete Goodwin
Petr Malac
@@ -266,6 +262,8 @@ generous deed immortalized in the next stable release of Godot Engine.
pl
Raymond Harris
Raz A
+ Rene Tailleur
+ Rhodochrone
Ricardo Alcantara
Robert Larnach
Robert Willes
@@ -277,25 +275,25 @@ generous deed immortalized in the next stable release of Godot Engine.
Ryan Scott
Ryszard Sommefeldt
Samuel Judd
- Scott Pilet
Sean Morgan
Sebastian Hutter
Sébastien
Serban Serafimescu
+ Sergey Fonaryov
Sergey Minakov
Shishir Tandale
SKison
Song Junwoo
- spilldata
+ spacechase0
Stephan Hennion
Steven Landow
Stoned Xander
- TheLevelOfDetail
+ Sven F.
Thomas Bjarnelöf
Thomas Kurz
Tim Howard
- tinyBigGAMES LLC
Tobias Bocanegra
+ Todd Smith
Turntsnaco
tweaklab
Valryia
@@ -303,7 +301,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Vlad Ceru Opran
VoidPointer
voxelv
- William Foster
Wojciech Chojnacki
xzibiting
Yuancheng Zhang
@@ -316,6 +313,7 @@ generous deed immortalized in the next stable release of Godot Engine.
1D_Inc
Abraham Haskins
Adam
+ Adam Brown
Adam Brunnmeier
Adam Carr
Adam Long
@@ -328,7 +326,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Agustinus Arya
Ahmet Kalyoncu
Aidan O'Flannagain
- AJ Austinson
Aki Mimoto
Alan Beauchamp
Alberto Vilches
@@ -341,9 +338,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Alexander Walter (SilvanuZ)
Alexandre Beaudoin
alex clavelle
+ Alex (Well Done Games)
Allan Davis
Allen Schade
- Ancient Phoenix
Anders Marstein Kruke
Andreas Krampitz
Andre Stackhouse
@@ -352,11 +349,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Andrew Thomas
Ano Nim
Anthony Avina
+ Anton Bouwer
aomimezura11
AP Condomines
Arch Toasty
Arda Erol
- Aria
Armin Preiml
Arseniy M
Ashley Claymore
@@ -365,10 +362,10 @@ generous deed immortalized in the next stable release of Godot Engine.
AzulCrescent
Balázs Batári
Bartosz Bielecki
- Bekhoucha Danyl
Benedikt
Ben Vercammen
Bernd Jänichen
+ Bernhard Werner
Bjarne Voigtländer
Black Block
blackjacksike
@@ -383,6 +380,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Bronson Zgeb
Bùi Việt Thành
Burney Waring
+ bwhirt
Caleb Gartner
Cameron Meyer
Carlos Cejudo
@@ -394,15 +392,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Chad Steadman
Charles Alston
Chris Chapin
- Chris Jagusch
Chris Langford
Christian Clavet
Christian Mauduit
Christian Winter
Christoffer Dahlblom
Christophe Gagnier
+ Christopher Chin
Christopher Schmitt
- Christoph Woinke
Chris Truebe
Clay Heaton
Cody Parker
@@ -418,10 +415,13 @@ generous deed immortalized in the next stable release of Godot Engine.
David May
David Maziarka
David Woodard
+ deadwithbread
Devin Carraway
+ Diego Pereira
Dmitry Fisher
Dmytro Korchynskyi
Dominik Wetzel
+ Douglas Plumley
Dragontrapper
Dr Ewan Murray
Dr.Raccoon
@@ -435,29 +435,28 @@ generous deed immortalized in the next stable release of Godot Engine.
Elgenzay
Elias Nykrem
Ephemeral
- Eric Ellingson
+ Eric Stokes
+ Eric Walkingshaw
Eric Williams
Erkki Seppälä
Evan Rose
- Fain
Faisal Alkubaisi
Fancy Ants Studios
+ fby
Fekinox
Felix Bohmann
Flaredown
Forty Doubleu
Francois Holland
Frank
- FuDiggity
- Gadzhi Kharkharov
- gamedev by Celio
Game Endeavor
+ Gareth Knowles
Gary Thomas
George Marques
- Gerard Ruiz Torruella
+ georgios katsanakis
+ GFizz
Greg Lincoln
Greg Olson
- GREGORY C FEIN
Greyson Richey
Grid
Guillaume Audirac
@@ -467,7 +466,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Hal A
helija
Heribert Hirth
- Hieu Thanh
Hunter Jones
Ian Williams
Iiari
@@ -483,19 +481,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Jako Danar
James
James A F Manley
+ James Quincy
James Thomas
- Jamiee H
Jamie Massey
+ Jan Vetulani
JARKKO PARVIAINEN
- Jasiek Vetulani
+ Jason Bolton
Jason Uechi
- Jean-Baptiste LEPESME
Jeff Hungerford
Jennifer Graves
Jesse Dubay
Jhon Adams
Joe Klemmer
John Gabriel
+ Jonah Branch
Jonas
Jonas Bernemann
Jonas Rudlang
@@ -507,21 +506,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Jon Sully
Jordy Goodridge
Jorge Antunes
- Jorge Javier Araya Navarro
+ Jorge Araya Navarro
Jose C. Rubio
Joseph Catrambone
+ Josep Sanchez
Josh Taylor
- Josue David
+ Joshua Heidrich
+ jromkjrom
Juanfran
+ Juan Uys
Jueast
Julian Murgia
June Little
Justin Hamilton
Justin Oaksford
Justin Spedding
+ Justin W. Flory
KaDokta
Kalin
- Kauzig
Keedong Park
Keinan Powers
Keith Bradner
@@ -530,7 +532,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Kenneth Lee
Kent Jofur
Ketafuki
- Kevin McPhillips
Kiri Jolly
Kjetil Haugland
Konstantin Goncharov
@@ -539,8 +540,8 @@ generous deed immortalized in the next stable release of Godot Engine.
KsyTek Games
kycho
Kyle Jacobs
- Kyle Szklenski
Kyuppin
+ Lasse le Dous
Laurent CHEA
Laurent Tréguier
Laxman Pradhan
@@ -548,7 +549,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Leonardo Dimano
Lin Chear
Linus Lind Lundgren
- Lionel Gaillard
Luigi Renna
Luis Gaemperle
Luis M
@@ -558,19 +558,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Malcolm
Marco Lardelli
Mark Jad
- Mark Krenz
Mark Malone
Markus Martin
Markus Michael Egger
Martin FIbik
Martin Holas
- Martin Linklater
Martin Trbola
Marvin
Mathieu
Matt Edwards
Matthew Booe
- Max Brister
+ Matt Sylvia
Max Fiedler
Maxime Blade
Maxwell
@@ -582,17 +580,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Michael Bruce-Lockhart
Michael Haney
Michał Skwarek
+ MidoriBunn 'tis BS
Mikayla
+ Mike
Mike Birkhead
+ Mike Copley
Mike Cunningham
Mitchell J. Wagner
+ MJacred
Molinghu
Molly Jameson
- MoM
MrAZIE
Nathan Fish
Nathaniel
- Natrim
nee
neighty
Neil Blakey-Milner
@@ -600,7 +600,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Nerdforge
Nerdyninja
Nicholas
- Nick Allen
Nick Macholl
Niclas Eriksen
Nicolas Goll-Perrier
@@ -609,33 +608,32 @@ generous deed immortalized in the next stable release of Godot Engine.
Nima Farid
NZ
oceoh
+ Okatima
OKV
Oleg Reva
Oleksandr Kryvonos
- Olivier
Omar Delarosa
+ Oriol Muñoz Princep
Oscar Domingo
- Parinya Teerakasemsuk
- patricio lara briones
- Patrick Dully
+ Patrick Brock
Patrick Nafarrete
Paul Gieske
- Paul Mason
Paweł Kowal
Paweł Łyczkowski
Peter Höglund
+ Peter Richmond
Petrus Prinsloo
Philip Cohoe
- Phillip Zolla
+ Philip Ludington (MrPhil)
+ Pierre Caye
Piotr Góral
- Pipo
Point08
Preethi Vaidyanathan
pwab
- pyacier
Rad Cat
Rafa Laguna
Raffaele Aramo
+ Rami Hanano
RAMupgrade
Remi Rampin
Rémi Verschelde
@@ -652,6 +650,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Ronan
Ross Squires
Ryan Groom
+ Sam Caulfield
Sam Edson
Samuele Zolfanelli
scapegoat57
@@ -659,8 +658,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Scott Longley
Sean Lynch
Sebastian Michailidis
- Sebastian Vetter
SeongWan Kim
+ Sergey
Sergiy Onenko
Shane
Shane Sicienski
@@ -675,6 +674,7 @@ generous deed immortalized in the next stable release of Godot Engine.
smo1704
soft circles
Squirrel
+ Stéphane Roussel
Steve Cloete
summerblind
Sung soo Choi
@@ -693,12 +693,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Tim Erskine
Tim Gleason
Timothy B. MacDonald
- Tobbun
+ TMoney
Tobias Bradtke
+ Tom Coxon
Toni Duran
Tony Zhao
Torgeir Lilleskog
Torsten Crass
+ toupeira
Travis O'Brien
Trent Skinner
tril zerobyte
@@ -712,11 +714,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Uther
Vaughan Ling
Victor
- Vigilant Watch
Viktor Ismagilov
+ Vi Watch
Vladimir Savin
Vladislav Smirnov
- Výrus Hemomancer
+ Vytenis Narušis
waka nya
Wayne Haak
werner mendizabal
@@ -725,13 +727,12 @@ generous deed immortalized in the next stable release of Godot Engine.
William F Siqueira
William Hogben
Wyatt Goodin
- Xaver Fischer
+ x1212
xenomat
Yegor Smirnov
- Zack Yang
Zak Stephens
+ Эльдар Будагов
蕭惟允
- 郝晨煜
## Bronze donors
diff --git a/README.md b/README.md
index 1f2aa00f08..72a85492fd 100644
--- a/README.md
+++ b/README.md
@@ -50,8 +50,7 @@ Godot is not only an engine but an ever-growing community of users and engine
developers. The main community channels are listed [on the homepage](https://godotengine.org/community).
To get in touch with the engine developers, the best way is to join the
-[#godotengine-devel IRC channel](https://webchat.freenode.net/?channels=godotengine-devel)
-on Freenode.
+[Godot Contributors Chat](https://chat.godotengine.org).
To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md).
diff --git a/SConstruct b/SConstruct
index 000c918808..2d9802f293 100644
--- a/SConstruct
+++ b/SConstruct
@@ -55,17 +55,21 @@ custom_tools = ["default"]
platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False))
-if os.name == "nt" and (platform_arg == "android" or ARGUMENTS.get("use_mingw", False)):
+if os.name == "nt" and (platform_arg == "android" or methods.get_cmdline_bool("use_mingw", False)):
custom_tools = ["mingw"]
elif platform_arg == "javascript":
# Use generic POSIX build toolchain for Emscripten.
custom_tools = ["cc", "c++", "ar", "link", "textfile", "zip"]
+# We let SCons build its default ENV as it includes OS-specific things which we don't
+# want to have to pull in manually.
+# Then we prepend PATH to make it take precedence, while preserving SCons' own entries.
env_base = Environment(tools=custom_tools)
-if "TERM" in os.environ:
+env_base.PrependENVPath("PATH", os.getenv("PATH"))
+env_base.PrependENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
+if "TERM" in os.environ: # Used for colored output.
env_base["ENV"]["TERM"] = os.environ["TERM"]
-env_base.AppendENVPath("PATH", os.getenv("PATH"))
-env_base.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
+
env_base.disabled_modules = []
env_base.module_version_string = ""
env_base.msvc = False
@@ -95,7 +99,7 @@ env_base.SConsignFile(".sconsign{0}.dblite".format(pickle.HIGHEST_PROTOCOL))
customs = ["custom.py"]
-profile = ARGUMENTS.get("profile", False)
+profile = ARGUMENTS.get("profile", "")
if profile:
if os.path.isfile(profile):
customs.append(profile)
@@ -111,7 +115,7 @@ opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True
opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
opts.Add("arch", "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", "")
opts.Add(EnumVariable("bits", "Target platform bits", "default", ("default", "32", "64")))
-opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size")))
+opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
@@ -133,6 +137,7 @@ opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all
opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False))
opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False))
+opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True))
opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", False))
opts.Add("system_certs_path", "Use this path as SSL certificates default for editor (for package maintainers)", "")
opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
@@ -242,26 +247,34 @@ for path in module_search_paths:
# Built-in modules don't have nested modules,
# so save the time it takes to parse directories.
modules = methods.detect_modules(path, recursive=False)
- else: # External.
+ else: # Custom.
modules = methods.detect_modules(path, env_base["custom_modules_recursive"])
+ # Provide default include path for both the custom module search `path`
+ # and the base directory containing custom modules, as it may be different
+ # from the built-in "modules" name (e.g. "custom_modules/summator/summator.h"),
+ # so it can be referenced simply as `#include "summator/summator.h"`
+ # independently of where a module is located on user's filesystem.
+ env_base.Prepend(CPPPATH=[path, os.path.dirname(path)])
# Note: custom modules can override built-in ones.
modules_detected.update(modules)
- include_path = os.path.dirname(path)
- if include_path:
- env_base.Prepend(CPPPATH=[include_path])
# Add module options.
for name, path in modules_detected.items():
- enabled = True
- sys.path.insert(0, path)
- import config
-
- try:
- enabled = config.is_enabled()
- except AttributeError:
- pass
- sys.path.remove(path)
- sys.modules.pop("config")
+ if env_base["modules_enabled_by_default"]:
+ enabled = True
+
+ sys.path.insert(0, path)
+ import config
+
+ try:
+ enabled = config.is_enabled()
+ except AttributeError:
+ pass
+ sys.path.remove(path)
+ sys.modules.pop("config")
+ else:
+ enabled = False
+
opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
methods.write_modules(modules_detected)
@@ -295,10 +308,6 @@ if env_base["target"] == "debug":
# http://scons.org/doc/production/HTML/scons-user/ch06s04.html
env_base.SetOption("implicit_cache", 1)
-if not env_base["tools"]:
- # Export templates can't run unit test tool.
- env_base["tests"] = False
-
if env_base["no_editor_splash"]:
env_base.Append(CPPDEFINES=["NO_EDITOR_SPLASH"])
@@ -325,17 +334,17 @@ if selected_platform in platform_list:
env.Alias("compiledb", env.CompilationDatabase())
# 'dev' and 'production' are aliases to set default options if they haven't been set
- # manually by the user. We use `ARGUMENTS.get()` to check if they were manually set.
+ # manually by the user.
if env["dev"]:
- env["verbose"] = ARGUMENTS.get("verbose", True)
+ env["verbose"] = methods.get_cmdline_bool("verbose", True)
env["warnings"] = ARGUMENTS.get("warnings", "extra")
- env["werror"] = ARGUMENTS.get("werror", True)
+ env["werror"] = methods.get_cmdline_bool("werror", True)
if env["tools"]:
- env["tests"] = ARGUMENTS.get("tests", True)
+ env["tests"] = methods.get_cmdline_bool("tests", True)
if env["production"]:
- env["use_static_cpp"] = ARGUMENTS.get("use_static_cpp", True)
- env["use_lto"] = ARGUMENTS.get("use_lto", True)
- env["debug_symbols"] = ARGUMENTS.get("debug_symbols", False)
+ env["use_static_cpp"] = methods.get_cmdline_bool("use_static_cpp", True)
+ env["use_lto"] = methods.get_cmdline_bool("use_lto", True)
+ env["debug_symbols"] = methods.get_cmdline_bool("debug_symbols", False)
if not env["tools"] and env["target"] == "debug":
print(
"WARNING: Requested `production` build with `tools=no target=debug`, "
@@ -381,7 +390,7 @@ if selected_platform in platform_list:
if not (f[0] in ARGUMENTS): # allow command line to override platform flags
env[f[0]] = f[1]
- # Must happen after the flags definition, so that they can be used by platform detect
+ # Must happen after the flags' definition, so that they can be used by platform detect
detect.configure(env)
# Set our C and C++ standard requirements.
@@ -617,7 +626,7 @@ if selected_platform in platform_list:
if env["minizip"]:
env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
- editor_module_list = ["regex"]
+ editor_module_list = ["freetype", "regex"]
if env["tools"] and not env.module_check_dependencies("tools", editor_module_list):
print(
"Build option 'module_"
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 70e8133eaa..25dd408dce 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -32,6 +32,7 @@
#include "core/core_bind.h"
#include "core/core_string_names.h"
+#include "core/input/input_map.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
@@ -124,6 +125,11 @@ void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restar
props[p_name].restart_if_changed = p_restart;
}
+void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) {
+ ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
+ props[p_name].basic = p_basic;
+}
+
void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) {
ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
#ifdef DEBUG_METHODS_ENABLED
@@ -269,6 +275,10 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
}
+ if (v->basic) {
+ vc.flags |= PROPERTY_USAGE_EDITOR_BASIC_SETTING;
+ }
+
if (v->restart_if_changed) {
vc.flags |= PROPERTY_USAGE_RESTART_IF_CHANGED;
}
@@ -278,7 +288,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) {
String prop_info_name = E->get().name;
int dot = prop_info_name.find(".");
- if (dot != -1) {
+ if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
prop_info_name = prop_info_name.substr(0, dot);
}
@@ -383,7 +393,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (exec_path != "") {
// We do several tests sequentially until one succeeds to find a PCK,
- // and if so we attempt loading it at the end.
+ // and if so, we attempt loading it at the end.
// Attempt with PCK bundled into executable.
bool found = _load_resource_pack(exec_path);
@@ -457,16 +467,17 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
d->change_dir(p_path);
String current_dir = d->get_current_dir();
- String candidate = current_dir;
bool found = false;
Error err;
while (true) {
+ // Set the resource path early so things can be resolved when loading.
+ resource_path = current_dir;
+ resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
// Optional, we don't mind if it fails.
_load_settings_text(current_dir.plus_file("override.cfg"));
- candidate = current_dir;
found = true;
break;
}
@@ -483,8 +494,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
}
- resource_path = candidate;
- resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
memdelete(d);
if (!found) {
@@ -597,6 +606,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
return OK;
} else if (err != OK) {
ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -632,7 +642,6 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
} else if (err != ERR_FILE_NOT_FOUND) {
// If the file exists but can't be loaded, we want to know it.
ERR_PRINT("Couldn't load file '" + p_bin_path + "', error code " + itos(err) + ".");
- return err;
}
// Fallback to text-based project.godot file if binary was not found.
@@ -641,7 +650,6 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
return OK;
} else if (err != ERR_FILE_NOT_FOUND) {
ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err) + ".");
- return err;
}
return err;
@@ -676,7 +684,11 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- return save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ if (error == OK) {
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ }
+ return error;
}
Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
@@ -894,7 +906,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
custom_features += f;
}
- if (p_path.ends_with(".godot")) {
+ if (p_path.ends_with(".godot") || p_path.ends_with("override.cfg")) {
return _save_settings_text(p_path, props, p_custom, custom_features);
} else if (p_path.ends_with(".binary")) {
return _save_settings_binary(p_path, props, p_custom, custom_features);
@@ -903,7 +915,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs) {
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic) {
Variant ret;
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
@@ -912,6 +924,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
+ ProjectSettings::get_singleton()->set_as_basic(p_var, p_basic);
ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed);
ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs);
return ret;
@@ -1042,29 +1055,47 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
}
+void ProjectSettings::_add_builtin_input_map() {
+ if (InputMap::get_singleton()) {
+ OrderedHashMap<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
+
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ Array events;
+
+ // Convert list of input events into array
+ for (List<Ref<InputEvent>>::Element *I = E.get().front(); I; I = I->next()) {
+ events.push_back(I->get());
+ }
+
+ Dictionary action;
+ action["deadzone"] = Variant(0.5f);
+ action["events"] = events;
+
+ String action_name = "input/" + E.key();
+ GLOBAL_DEF(action_name, action);
+ input_presets.push_back(action_name);
+ }
+ }
+}
+
ProjectSettings::ProjectSettings() {
// Initialization of engine variables should be done in the setup() method,
// so that the values can be overridden from project.godot or project.binary.
singleton = this;
- Array events;
- Dictionary action;
- Ref<InputEventKey> key;
- Ref<InputEventJoypadButton> joyb;
-
- GLOBAL_DEF("application/config/name", "");
- GLOBAL_DEF("application/config/description", "");
+ GLOBAL_DEF_BASIC("application/config/name", "");
+ GLOBAL_DEF_BASIC("application/config/description", "");
custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
- GLOBAL_DEF("application/run/main_scene", "");
+ GLOBAL_DEF_BASIC("application/run/main_scene", "");
custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res");
GLOBAL_DEF("application/run/disable_stdout", false);
GLOBAL_DEF("application/run/disable_stderr", false);
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
- GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres");
- custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
+ GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
+ custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
PackedStringArray extensions = PackedStringArray();
extensions.push_back("gd");
@@ -1073,174 +1104,18 @@ ProjectSettings::ProjectSettings() {
}
extensions.push_back("shader");
- GLOBAL_DEF("editor/search_in_file_extensions", extensions);
- custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/search_in_file_extensions");
-
- GLOBAL_DEF("editor/script_templates_search_path", "res://script_templates");
- custom_prop_info["editor/script_templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script_templates_search_path", PROPERTY_HINT_DIR);
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_ENTER);
- events.push_back(key);
- key.instance();
- key->set_keycode(KEY_KP_ENTER);
- events.push_back(key);
- key.instance();
- key->set_keycode(KEY_SPACE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_A);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_accept", action);
- input_presets.push_back("input/ui_accept");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_SPACE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_Y);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_select", action);
- input_presets.push_back("input/ui_select");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_ESCAPE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_B);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_cancel", action);
- input_presets.push_back("input/ui_cancel");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_TAB);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_focus_next", action);
- input_presets.push_back("input/ui_focus_next");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_TAB);
- key->set_shift(true);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_focus_prev", action);
- input_presets.push_back("input/ui_focus_prev");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_LEFT);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_LEFT);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_left", action);
- input_presets.push_back("input/ui_left");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_RIGHT);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_RIGHT);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_right", action);
- input_presets.push_back("input/ui_right");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_UP);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_UP);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_up", action);
- input_presets.push_back("input/ui_up");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_DOWN);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_DOWN);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_down", action);
- input_presets.push_back("input/ui_down");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_PAGEUP);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_page_up", action);
- input_presets.push_back("input/ui_page_up");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_PAGEDOWN);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_page_down", action);
- input_presets.push_back("input/ui_page_down");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_HOME);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_home", action);
- input_presets.push_back("input/ui_home");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_END);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_end", action);
- input_presets.push_back("input/ui_end");
+ GLOBAL_DEF("editor/script/search_in_file_extensions", extensions);
+ custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions");
+
+ GLOBAL_DEF("editor/script/templates_search_path", "res://script_templates");
+ custom_prop_info["editor/script/templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR);
+
+ _add_builtin_input_map();
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
- custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
+ custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
+ GLOBAL_DEF("physics/2d/run_on_thread", false);
+ GLOBAL_DEF("physics/3d/run_on_thread", false);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 59c56c23c2..ed8fb19fa0 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -58,6 +58,7 @@ protected:
struct VariantContainer {
int order = 0;
bool persist = false;
+ bool basic = false;
Variant variant;
Variant initial;
bool hide_from_editor = false;
@@ -78,6 +79,8 @@ protected:
int last_order = NO_BUILTIN_ORDER_BASE;
int last_builtin_order = 0;
+ uint64_t last_save_time = 0;
+
Map<StringName, VariantContainer> props;
String resource_path;
Map<StringName, PropertyInfo> custom_prop_info;
@@ -113,6 +116,8 @@ protected:
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
+ void _add_builtin_input_map();
+
protected:
static void _bind_methods();
@@ -127,6 +132,7 @@ public:
String globalize_path(const String &p_path) const;
void set_initial_value(const String &p_name, const Variant &p_value);
+ void set_as_basic(const String &p_name, bool p_basic);
void set_restart_if_changed(const String &p_name, bool p_restart);
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
bool get_ignore_value_in_docs(const String &p_name) const;
@@ -150,6 +156,7 @@ public:
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
const Map<StringName, PropertyInfo> &get_custom_property_info() const;
+ uint64_t get_last_saved_time() { return last_save_time; }
Vector<String> get_optimizer_presets() const;
@@ -172,11 +179,16 @@ public:
};
//not a macro any longer
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false);
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false);
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
+#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
+#define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true)
+#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
+
#endif // PROJECT_SETTINGS_H
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 456a97e5e5..84d8d0d4d3 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -86,9 +86,9 @@ RES _ResourceLoader::load_threaded_get(const String &p_path) {
return res;
}
-RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) {
+RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode) {
Error err = OK;
- RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err);
+ RES ret = ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
return ret;
@@ -135,7 +135,7 @@ void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &_ResourceLoader::load_threaded_get_status, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &_ResourceLoader::load_threaded_get);
- ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies);
@@ -146,6 +146,10 @@ void _ResourceLoader::_bind_methods() {
BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
BIND_ENUM_CONSTANT(THREAD_LOAD_FAILED);
BIND_ENUM_CONSTANT(THREAD_LOAD_LOADED);
+
+ BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
}
////// _ResourceSaver //////
@@ -272,6 +276,10 @@ String _OS::get_environment(const String &p_var) const {
return OS::get_singleton()->get_environment(p_var);
}
+bool _OS::set_environment(const String &p_var, const String &p_value) const {
+ return OS::get_singleton()->set_environment(p_var, p_value);
+}
+
String _OS::get_name() const {
return OS::get_singleton()->get_name();
}
@@ -314,18 +322,6 @@ uint64_t _OS::get_static_memory_peak_usage() const {
return OS::get_singleton()->get_static_memory_peak_usage();
}
-int _OS::get_exit_code() const {
- return OS::get_singleton()->get_exit_code();
-}
-
-void _OS::set_exit_code(int p_code) {
- if (p_code < 0 || p_code > 125) {
- WARN_PRINT("For portability reasons, the exit code should be set between 0 and 125 (inclusive).");
- }
-
- OS::get_singleton()->set_exit_code(p_code);
-}
-
/**
* Get current datetime with consideration for utc and
* dst
@@ -377,6 +373,9 @@ Dictionary _OS::get_time(bool utc) const {
* @return epoch calculated
*/
int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
+ // if datetime is an empty Dictionary throws an error
+ ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
+
// Bunch of conversion constants
static const unsigned int SECONDS_PER_MINUTE = 60;
static const unsigned int MINUTES_PER_HOUR = 60;
@@ -515,11 +514,19 @@ double _OS::get_unix_time() const {
return OS::get_singleton()->get_unix_time();
}
-void _OS::delay_usec(uint32_t p_usec) const {
+/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
+void _OS::delay_usec(int p_usec) const {
+ ERR_FAIL_COND_MSG(
+ p_usec < 0,
+ vformat("Can't sleep for %d microseconds. The delay provided must be greater than or equal to 0 microseconds.", p_usec));
OS::get_singleton()->delay_usec(p_usec);
}
-void _OS::delay_msec(uint32_t p_msec) const {
+/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
+void _OS::delay_msec(int p_msec) const {
+ ERR_FAIL_COND_MSG(
+ p_msec < 0,
+ vformat("Can't sleep for %d milliseconds. The delay provided must be greater than or equal to 0 milliseconds.", p_msec));
OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000);
}
@@ -562,7 +569,7 @@ struct _OSCoreBindImg {
void _OS::print_all_textures_by_size() {
List<_OSCoreBindImg> imgs;
- int total = 0;
+ uint64_t total = 0;
{
List<Ref<Resource>> rsrc;
ResourceCache::get_cached_resources(&rsrc);
@@ -677,22 +684,6 @@ String _OS::get_unique_id() const {
return OS::get_singleton()->get_unique_id();
}
-int _OS::get_tablet_driver_count() const {
- return OS::get_singleton()->get_tablet_driver_count();
-}
-
-String _OS::get_tablet_driver_name(int p_driver) const {
- return OS::get_singleton()->get_tablet_driver_name(p_driver);
-}
-
-String _OS::get_current_tablet_driver() const {
- return OS::get_singleton()->get_current_tablet_driver();
-}
-
-void _OS::set_current_tablet_driver(const String &p_driver) {
- OS::get_singleton()->set_current_tablet_driver(p_driver);
-}
-
_OS *_OS::singleton = nullptr;
void _OS::_bind_methods() {
@@ -715,8 +706,9 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
- ClassDB::bind_method(D_METHOD("get_environment", "environment"), &_OS::get_environment);
- ClassDB::bind_method(D_METHOD("has_environment", "environment"), &_OS::has_environment);
+ ClassDB::bind_method(D_METHOD("get_environment", "variable"), &_OS::get_environment);
+ ClassDB::bind_method(D_METHOD("set_environment", "variable", "value"), &_OS::set_environment);
+ ClassDB::bind_method(D_METHOD("has_environment", "variable"), &_OS::has_environment);
ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args);
@@ -729,9 +721,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime);
- ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code);
- ClassDB::bind_method(D_METHOD("set_exit_code", "code"), &_OS::set_exit_code);
-
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec);
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
@@ -776,19 +765,11 @@ void _OS::_bind_methods() {
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("get_tablet_driver_count"), &_OS::get_tablet_driver_count);
- ClassDB::bind_method(D_METHOD("get_tablet_driver_name", "idx"), &_OS::get_tablet_driver_name);
- ClassDB::bind_method(D_METHOD("get_current_tablet_driver"), &_OS::get_current_tablet_driver);
- ClassDB::bind_method(D_METHOD("set_current_tablet_driver", "name"), &_OS::set_current_tablet_driver);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code");
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");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "tablet_driver"), "set_current_tablet_driver", "get_current_tablet_driver");
// Those default values need to be specified for the docs generator,
// to avoid using values from the documentation writer's own OS instance.
- ADD_PROPERTY_DEFAULT("tablet_driver", "");
ADD_PROPERTY_DEFAULT("exit_code", 0);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
@@ -1250,6 +1231,11 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
return err;
}
+void _File::flush() {
+ ERR_FAIL_COND_MSG(!f, "File must be opened before flushing.");
+ f->flush();
+}
+
void _File::close() {
if (f) {
memdelete(f);
@@ -1348,7 +1334,7 @@ Vector<uint8_t> _File::get_buffer(int p_length) const {
ERR_FAIL_COND_V(len < 0, Vector<uint8_t>());
if (len < p_length) {
- data.resize(p_length);
+ data.resize(len);
}
return data;
@@ -1391,9 +1377,9 @@ Vector<String> _File::get_csv_line(const String &p_delim) const {
return f->get_csv_line(p_delim);
}
-/**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
+/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
* It's not about the current CPU type but file formats.
- * this flags get reset to false (little endian) on each open
+ * These flags get reset to false (little endian) on each open
*/
void _File::set_endian_swap(bool p_swap) {
@@ -1543,6 +1529,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &_File::open_compressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open);
+ ClassDB::bind_method(D_METHOD("flush"), &_File::flush);
ClassDB::bind_method(D_METHOD("close"), &_File::close);
ClassDB::bind_method(D_METHOD("get_path"), &_File::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &_File::get_path_absolute);
@@ -1980,7 +1967,7 @@ void _Thread::_start_func(void *ud) {
}
Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
- ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started.");
+ ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started.");
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
@@ -1989,7 +1976,7 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
target_method = p_method;
target_instance = p_instance;
userdata = p_userdata;
- active = true;
+ active.set();
Ref<_Thread> *ud = memnew(Ref<_Thread>(this));
@@ -2005,14 +1992,14 @@ String _Thread::get_id() const {
}
bool _Thread::is_active() const {
- return active;
+ return active.is_set();
}
Variant _Thread::wait_to_finish() {
- ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion.");
+ ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion.");
thread.wait_to_finish();
Variant r = ret;
- active = false;
+ active.clear();
target_method = StringName();
target_instance = nullptr;
userdata = Variant();
diff --git a/core/core_bind.h b/core/core_bind.h
index 3305c93089..3920116ca4 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -40,6 +40,7 @@
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
class _ResourceLoader : public Object {
GDCLASS(_ResourceLoader, Object);
@@ -56,13 +57,19 @@ public:
THREAD_LOAD_LOADED
};
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
static _ResourceLoader *get_singleton() { return singleton; }
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
RES load_threaded_get(const String &p_path);
- RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false);
+ RES load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
@@ -73,6 +80,7 @@ public:
};
VARIANT_ENUM_CAST(_ResourceLoader::ThreadLoadStatus);
+VARIANT_ENUM_CAST(_ResourceLoader::CacheMode);
class _ResourceSaver : public Object {
GDCLASS(_ResourceSaver, Object);
@@ -164,6 +172,7 @@ public:
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
+ bool set_environment(const String &p_var, const String &p_value) const;
String get_name() const;
Vector<String> get_cmdline_args();
@@ -190,8 +199,6 @@ public:
void set_use_file_access_save_and_swap(bool p_enable);
- int get_exit_code() const;
- void set_exit_code(int p_code);
Dictionary get_date(bool utc) const;
Dictionary get_time(bool utc) const;
Dictionary get_datetime(bool utc) const;
@@ -203,8 +210,8 @@ public:
uint64_t get_static_memory_usage() const;
uint64_t get_static_memory_peak_usage() const;
- void delay_usec(uint32_t p_usec) const;
- void delay_msec(uint32_t p_msec) const;
+ void delay_usec(int p_usec) const;
+ void delay_msec(int p_msec) const;
uint32_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
@@ -240,11 +247,6 @@ public:
bool request_permissions();
Vector<String> get_granted_permissions() const;
- int get_tablet_driver_count() const;
- String get_tablet_driver_name(int p_driver) const;
- String get_current_tablet_driver() const;
- void set_current_tablet_driver(const String &p_driver);
-
static _OS *get_singleton() { return singleton; }
_OS() { singleton = this; }
@@ -379,6 +381,7 @@ public:
Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
+ void flush(); // Flush a file (write its buffer to disk).
void close(); // Close a file.
bool is_open() const; // True when file is open.
@@ -551,7 +554,7 @@ class _Thread : public Reference {
protected:
Variant ret;
Variant userdata;
- volatile bool active = false;
+ SafeFlag active;
Object *target_instance = nullptr;
StringName target_method;
Thread thread;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index ef5dbf17bb..f40928350a 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -104,12 +104,12 @@ static Vector<_CoreConstant> _global_constants;
#endif
-VARIANT_ENUM_CAST(KeyList);
+VARIANT_ENUM_CAST(Key);
VARIANT_ENUM_CAST(KeyModifierMask);
-VARIANT_ENUM_CAST(ButtonList);
-VARIANT_ENUM_CAST(JoyButtonList);
-VARIANT_ENUM_CAST(JoyAxisList);
-VARIANT_ENUM_CAST(MidiMessageList);
+VARIANT_ENUM_CAST(MouseButton);
+VARIANT_ENUM_CAST(JoyButton);
+VARIANT_ENUM_CAST(JoyAxis);
+VARIANT_ENUM_CAST(MIDIMessage);
void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
@@ -125,6 +125,9 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(VERTICAL);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
+ BIND_CORE_ENUM_CONSTANT(CLOCKWISE);
+ BIND_CORE_ENUM_CONSTANT(COUNTERCLOCKWISE);
+
BIND_CORE_ENUM_CONSTANT(HALIGN_LEFT);
BIND_CORE_ENUM_CONSTANT(HALIGN_CENTER);
BIND_CORE_ENUM_CONSTANT(HALIGN_RIGHT);
@@ -394,20 +397,20 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH);
// mouse
- BIND_CORE_ENUM_CONSTANT(BUTTON_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MIDDLE);
- BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON1);
- BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON2);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_UP);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_XBUTTON2);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_UP);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_DOWN);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_XBUTTON2);
// Joypad buttons
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_INVALID);
@@ -518,8 +521,10 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_NAVIGATION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_NAVIGATION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);
@@ -559,6 +564,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_REVERSE);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_VIRTUAL);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_FROM_SCRIPT);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_STATIC);
BIND_CORE_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 18ac2a2d43..ff8569e45d 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -76,5 +76,6 @@ CoreStringNames::CoreStringNames() :
bind(StaticCString::create("bind")),
unbind(StaticCString::create("unbind")),
emit(StaticCString::create("emit")),
- notification(StaticCString::create("notification")) {
+ notification(StaticCString::create("notification")),
+ property_list_changed(StaticCString::create("property_list_changed")) {
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index b4e386f3bc..abe751372e 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -96,6 +96,7 @@ public:
StringName unbind;
StringName emit;
StringName notification;
+ StringName property_list_changed;
};
#endif // CORE_STRING_NAMES_H
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 99f4fb232d..fe913549c9 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -100,7 +100,7 @@ void Crypto::load_default_certificates(String p_path) {
PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg) {
Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create());
- ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available witout mbedtls module.");
+ ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available without mbedtls module.");
Error err = ctx->start(p_hash_type, p_key);
ERR_FAIL_COND_V(err != OK, PackedByteArray());
err = ctx->update(p_msg);
@@ -108,7 +108,7 @@ PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, Packed
return ctx->finish();
}
-// Compares two HMACS for equality without leaking timing information in order to prevent timing attakcs.
+// Compares two HMACS for equality without leaking timing information in order to prevent timing attacks.
// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
bool Crypto::constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received) {
const uint8_t *t = p_trusted.ptr();
@@ -141,7 +141,7 @@ void Crypto::_bind_methods() {
/// Resource loader/saver
-RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCrypto::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) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
@@ -157,8 +157,9 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi
return key;
} else if (el == "pub") {
CryptoKey *key = CryptoKey::create();
- if (key)
+ if (key) {
key->load(p_path, true);
+ }
return key;
}
return nullptr;
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 30d2129e3d..9438fcfea5 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -116,7 +116,7 @@ public:
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index 895b8c23a9..e5dba029c9 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -192,7 +192,7 @@ void EngineDebugger::deinitialize() {
singleton = nullptr;
}
- // Clear profilers/captuers/protocol handlers.
+ // Clear profilers/captures/protocol handlers.
profilers.clear();
captures.clear();
protocols.clear();
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 7392e6b9a6..bdbb7766fa 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -76,6 +76,7 @@ public:
NetworkProfiler() {}
int bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
+ ERR_FAIL_COND_V(p_buffer.size() == 0, 0);
int total_bandwidth = 0;
uint32_t timestamp = OS::get_singleton()->get_ticks_msec();
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 857e3af268..90b0975159 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -190,13 +190,18 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
}
void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
+ const uint64_t min_tick = 100;
RemoteDebuggerPeerTCP *peer = (RemoteDebuggerPeerTCP *)p_ud;
while (peer->running && peer->is_peer_connected()) {
+ uint64_t ticks_usec = OS::get_singleton()->get_ticks_usec();
peer->_poll();
if (!peer->is_peer_connected()) {
break;
}
- peer->tcp_client->poll(NetSocket::POLL_TYPE_IN_OUT, 1);
+ ticks_usec = OS::get_singleton()->get_ticks_usec() - ticks_usec;
+ if (ticks_usec < min_tick) {
+ OS::get_singleton()->delay_usec(min_tick - ticks_usec);
+ }
}
}
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 8eb6217ce8..f909a67d55 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -33,6 +33,8 @@
#include "core/typedefs.h"
+#include "core/templates/safe_refcount.h"
+
class String;
enum ErrorHandlerType {
@@ -577,10 +579,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*/
#define WARN_DEPRECATED \
if (true) { \
- static volatile bool warning_shown = false; \
- if (!warning_shown) { \
+ static SafeFlag warning_shown; \
+ if (!warning_shown.is_set()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \
- warning_shown = true; \
+ warning_shown.set(); \
} \
} else \
((void)0)
@@ -590,10 +592,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*/
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
- static volatile bool warning_shown = false; \
- if (!warning_shown) { \
+ static SafeFlag warning_shown; \
+ if (!warning_shown.is_set()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \
- warning_shown = true; \
+ warning_shown.set(); \
} \
} else \
((void)0)
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 668a531b1f..884fb9550c 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -13,10 +13,8 @@
03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00015900000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00065280000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
@@ -40,6 +38,7 @@
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000006f0e00001413000000000000,Afterglow,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -66,6 +65,7 @@
03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+03000000120c0000210e000000000000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -202,7 +202,7 @@
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,
+030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -290,8 +290,8 @@
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
-03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,righttrigger:b5,platform:Windows,
-03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,rightshoulder:b4,righttrigger:b5,x:b3,y:b0,platform:Windows,
+03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
+03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
030000005e0400008e02000000007801,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -335,7 +335,7 @@
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows,
+0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000007801,Xbox One Elite Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -375,6 +375,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000200e000000010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,
+03000000120c0000210e000000010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -383,6 +385,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008f0e00000300000007010000,GreenAsia Inc. USB Joystick,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -425,7 +428,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
-030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
@@ -460,7 +463,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
-030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -468,6 +471,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
+050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -526,13 +530,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -550,6 +555,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
+03000000120c0000200e000011010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,
+03000000120c0000210e000011010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
@@ -565,6 +572,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -628,7 +636,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
-050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux,
+050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -673,13 +681,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,
+030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b0,y:b3,platform:Linux,
+050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,x:b7,y:b10,back:b5,start:b0,leftstick:b6,leftshoulder:b2,rightshoulder:b4,leftx:a1,lefty:a0~,platform:Linux,
+050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,x:b0,y:b3,back:b9,start:b8,leftstick:b10,leftshoulder:b4,rightshoulder:b6,leftx:a1~,lefty:a0~,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
@@ -690,6 +700,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,
05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
@@ -705,13 +716,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
-05000000491900000204000000000000,PG-9118,x:b76,a:b73,b:b74,y:b77,back:b83,start:b84,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b79,lefttrigger:b81,rightshoulder:b80,righttrigger:b82,leftstick:b86,rightstick:b87,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,
0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000491900000204000000000000,PG-9118,a:b73,b:b74,back:b83,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b79,leftstick:b86,lefttrigger:b81,leftx:a0,lefty:a1,rightshoulder:b80,rightstick:b87,righttrigger:b82,rightx:a2,righty:a3,start:b84,x:b76,y:b77,platform:Linux,
030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d62000000228000001010000,PowerA Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c62400001a54000001010000,PowerA Xbox One Mini Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -783,8 +796,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000010010000,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005f140000c501000010010000,SHANWAN Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000004c050000e60c000011810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000e60c000000006800,Sony DualSense,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b9,rightshoulder:b10,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,
+050000004c050000e60c000000810000,Sony DualSense ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000e60c000000016800,Sony DualSense ,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b9,rightshoulder:b10,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,
03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -792,8 +810,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
@@ -809,7 +827,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
+030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -864,7 +882,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,
# Android
05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
@@ -883,12 +900,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+38383337343564366131323064613561,Brook Mars,a:b1,b:b19,x:b0,y:b2,leftshoulder:b3,rightshoulder:b20,lefttrigger:b9,righttrigger:b10,back:b17,start:b18,leftx:a0,lefty:a1,rightx:a2,righty:a3,leftstick:b15,rightstick:b6,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android,
64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
-7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,
+7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android,
050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -936,8 +954,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
-050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,,platform:iOS,
050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index c43cd6c8ac..db612f04d2 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -28,6 +28,7 @@ MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulde
Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Javascript
+Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
# UWP
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 047aeb47fd..2304c05bf8 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -97,11 +97,11 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
- ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed);
- ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
- ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
- ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
- ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_strength);
+ ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
@@ -240,16 +240,28 @@ bool Input::is_joy_button_pressed(int p_device, int p_button) const {
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
}
-bool Input::is_action_pressed(const StringName &p_action) const {
- return action_state.has(p_action) && action_state[p_action].pressed;
+bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
+ return action_state.has(p_action) && action_state[p_action].pressed && (p_exact ? action_state[p_action].exact : true);
}
-bool Input::is_action_just_pressed(const StringName &p_action) const {
+bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return false;
}
+ if (p_exact && E->get().exact == false) {
+ return false;
+ }
+
if (Engine::get_singleton()->is_in_physics_frame()) {
return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
@@ -257,12 +269,20 @@ bool Input::is_action_just_pressed(const StringName &p_action) const {
}
}
-bool Input::is_action_just_released(const StringName &p_action) const {
+bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return false;
}
+ if (p_exact && E->get().exact == false) {
+ return false;
+ }
+
if (Engine::get_singleton()->is_in_physics_frame()) {
return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
@@ -270,21 +290,33 @@ bool Input::is_action_just_released(const StringName &p_action) const {
}
}
-float Input::get_action_strength(const StringName &p_action) const {
+float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return 0.0f;
}
+ if (p_exact && E->get().exact == false) {
+ return 0.0f;
+ }
+
return E->get().strength;
}
-float Input::get_action_raw_strength(const StringName &p_action) const {
+float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return 0.0f;
}
+ if (p_exact && E->get().exact == false) {
+ return 0.0f;
+ }
+
return E->get().raw_strength;
}
@@ -528,11 +560,11 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_position(st->get_position());
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
- button_event->set_button_index(BUTTON_LEFT);
+ button_event->set_button_index(MOUSE_BUTTON_LEFT);
if (st->is_pressed()) {
- button_event->set_button_mask(mouse_button_mask | (1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_mask(mouse_button_mask | (1 << (MOUSE_BUTTON_LEFT - 1)));
} else {
- button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1)));
}
_parse_input_event_impl(button_event, true);
@@ -588,20 +620,21 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
}
}
- for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) {
- if (InputMap::get_singleton()->event_is_action(p_event, E->key())) {
- // Save the action's state
- if (!p_event->is_echo() && is_action_pressed(E->key()) != p_event->is_action_pressed(E->key())) {
+ for (OrderedHashMap<StringName, InputMap::Action>::ConstElement E = InputMap::get_singleton()->get_action_map().front(); E; E = E.next()) {
+ if (InputMap::get_singleton()->event_is_action(p_event, E.key())) {
+ // If not echo and action pressed state has changed
+ if (!p_event->is_echo() && is_action_pressed(E.key(), false) != p_event->is_action_pressed(E.key())) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.process_frame = Engine::get_singleton()->get_process_frames();
- action.pressed = p_event->is_action_pressed(E->key());
+ action.pressed = p_event->is_action_pressed(E.key());
action.strength = 0.0f;
action.raw_strength = 0.0f;
- action_state[E->key()] = action;
+ action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key(), true);
+ action_state[E.key()] = action;
}
- action_state[E->key()].strength = p_event->get_action_strength(E->key());
- action_state[E->key()].raw_strength = p_event->get_action_raw_strength(E->key());
+ action_state[E.key()].strength = p_event->get_action_strength(E.key());
+ action_state[E.key()].raw_strength = p_event->get_action_raw_strength(E.key());
}
}
@@ -690,7 +723,7 @@ void Input::warp_mouse_position(const Vector2 &p_to) {
Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
// The relative distance reported for the next event after a warp is in the boundaries of the
- // size of the rect on that axis, but it may be greater, in which case there's not problem as fmod()
+ // size of the rect on that axis, but it may be greater, in which case there's no problem as fmod()
// will warp it, but if the pointer has moved in the opposite direction between the pointer relocation
// and the subsequent event, the reported relative distance will be less than the size of the rect
// and thus fmod() will be disabled for handling the situation.
@@ -746,7 +779,7 @@ bool Input::is_emulating_touch_from_mouse() const {
return emulate_touch_from_mouse;
}
-// Calling this whenever the game window is focused helps unstucking the "touch mouse"
+// Calling this whenever the game window is focused helps unsticking the "touch mouse"
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
void Input::ensure_touch_mouse_raised() {
if (mouse_from_touch_index != -1) {
@@ -759,8 +792,8 @@ void Input::ensure_touch_mouse_raised() {
button_event->set_position(mouse_pos);
button_event->set_global_position(mouse_pos);
button_event->set_pressed(false);
- button_event->set_button_index(BUTTON_LEFT);
- button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_index(MOUSE_BUTTON_LEFT);
+ button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1)));
_parse_input_event_impl(button_event, true);
}
@@ -874,7 +907,7 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) {
// no event?
}
-void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
+void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) {
_THREAD_SAFE_METHOD_;
ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX);
@@ -888,12 +921,12 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
//when changing direction quickly, insert fake event to release pending inputmap actions
float last = joy.last_axis[p_axis];
if (p_value.min == 0 && (last < 0.25 || last > 0.75) && (last - 0.5) * (p_value.value - 0.5) < 0) {
- JoyAxis jx;
+ JoyAxisValue jx;
jx.min = p_value.min;
jx.value = p_value.value < 0.5 ? 0.6 : 0.4;
joy_axis(p_device, p_axis, jx);
} else if (ABS(last) > 0.5 && last * p_value.value <= 0) {
- JoyAxis jx;
+ JoyAxisValue jx;
jx.min = p_value.min;
jx.value = last > 0 ? 0.1 : -0.1;
joy_axis(p_device, p_axis, jx);
@@ -1173,22 +1206,22 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J
}
}
-JoyButtonList Input::_get_output_button(String output) {
+JoyButton Input::_get_output_button(String output) {
for (int i = 0; i < JOY_BUTTON_SDL_MAX; i++) {
if (output == _joy_buttons[i]) {
- return JoyButtonList(i);
+ return JoyButton(i);
}
}
- return JoyButtonList::JOY_BUTTON_INVALID;
+ return JoyButton::JOY_BUTTON_INVALID;
}
-JoyAxisList Input::_get_output_axis(String output) {
+JoyAxis Input::_get_output_axis(String output) {
for (int i = 0; i < JOY_AXIS_SDL_MAX; i++) {
if (output == _joy_axes[i]) {
- return JoyAxisList(i);
+ return JoyAxis(i);
}
}
- return JoyAxisList::JOY_AXIS_INVALID;
+ return JoyAxis::JOY_AXIS_INVALID;
}
void Input::parse_mapping(String p_mapping) {
@@ -1246,8 +1279,8 @@ void Input::parse_mapping(String p_mapping) {
input = input.left(input.length() - 1);
}
- JoyButtonList output_button = _get_output_button(output);
- JoyAxisList output_axis = _get_output_axis(output);
+ JoyButton output_button = _get_output_button(output);
+ JoyAxis output_axis = _get_output_axis(output);
ERR_CONTINUE_MSG(output_button == JOY_BUTTON_INVALID && output_axis == JOY_AXIS_INVALID,
String(entry[idx] + "\nUnrecognised output string: " + output));
ERR_CONTINUE_MSG(output_button != JOY_BUTTON_INVALID && output_axis != JOY_AXIS_INVALID,
@@ -1296,9 +1329,10 @@ void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
if (p_update_existing) {
Vector<String> entry = p_mapping.split(",");
String uid = entry[0];
- for (int i = 0; i < joy_names.size(); i++) {
- if (uid == joy_names[i].uid) {
- joy_names[i].mapping = map_db.size() - 1;
+ for (Map<int, Joypad>::Element *E = joy_names.front(); E; E = E->next()) {
+ Joypad &joy = E->get();
+ if (joy.uid == uid) {
+ joy.mapping = map_db.size() - 1;
}
}
}
@@ -1310,9 +1344,10 @@ void Input::remove_joy_mapping(String p_guid) {
map_db.remove(i);
}
}
- for (int i = 0; i < joy_names.size(); i++) {
- if (joy_names[i].uid == p_guid) {
- joy_names[i].mapping = -1;
+ for (Map<int, Joypad>::Element *E = joy_names.front(); E; E = E->next()) {
+ Joypad &joy = E->get();
+ if (joy.uid == p_guid) {
+ joy.mapping = -1;
}
}
}
@@ -1328,8 +1363,13 @@ void Input::set_fallback_mapping(String p_guid) {
//platforms that use the remapping system can override and call to these ones
bool Input::is_joy_known(int p_device) {
- int mapping = joy_names[p_device].mapping;
- return mapping != -1 ? (mapping != fallback_mapping) : false;
+ if (joy_names.has(p_device)) {
+ int mapping = joy_names[p_device].mapping;
+ if (mapping != -1 && mapping != fallback_mapping) {
+ return true;
+ }
+ }
+ return false;
}
String Input::get_joy_guid(int p_device) const {
diff --git a/core/input/input.h b/core/input/input.h
index 445b7ff0cf..99b45db325 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -91,7 +91,7 @@ public:
JOYPADS_MAX = 16,
};
- struct JoyAxis {
+ struct JoyAxisValue {
int min;
float value;
};
@@ -116,6 +116,7 @@ private:
uint64_t physics_frame;
uint64_t process_frame;
bool pressed;
+ bool exact;
float strength;
float raw_strength;
};
@@ -198,10 +199,10 @@ private:
JoyType outputType;
union {
- JoyButtonList button;
+ JoyButton button;
struct {
- JoyAxisList axis;
+ JoyAxis axis;
JoyAxisRange range;
} axis;
@@ -219,8 +220,8 @@ private:
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button);
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value);
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]);
- JoyButtonList _get_output_button(String output);
- JoyAxisList _get_output_axis(String output);
+ JoyButton _get_output_button(String output);
+ JoyAxis _get_output_axis(String output);
void _button_event(int p_device, int p_index, bool p_pressed);
void _axis_event(int p_device, int p_axis, float p_value);
@@ -261,11 +262,11 @@ public:
bool is_key_pressed(int p_keycode) const;
bool is_mouse_button_pressed(int p_button) const;
bool is_joy_button_pressed(int p_device, int p_button) const;
- bool is_action_pressed(const StringName &p_action) const;
- bool is_action_just_pressed(const StringName &p_action) const;
- bool is_action_just_released(const StringName &p_action) const;
- float get_action_strength(const StringName &p_action) const;
- float get_action_raw_strength(const StringName &p_action) const;
+ bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
+ bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
+ bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
+ float get_action_strength(const StringName &p_action, bool p_exact = false) const;
+ float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
@@ -324,7 +325,7 @@ public:
void parse_mapping(String p_mapping);
void joy_button(int p_device, int p_button, bool p_pressed);
- void joy_axis(int p_device, int p_axis, const JoyAxis &p_value);
+ void joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value);
void joy_hat(int p_device, int p_val);
void add_joy_mapping(String p_mapping, bool p_update_existing = false);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index c91dc4d067..99cc51b95e 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -44,31 +44,31 @@ int InputEvent::get_device() const {
return device;
}
-bool InputEvent::is_action(const StringName &p_action) const {
- return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action);
+bool InputEvent::is_action(const StringName &p_action, bool p_exact_match) const {
+ return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match);
}
-bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const {
+bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && pressed && (p_allow_echo || !is_echo());
}
-bool InputEvent::is_action_released(const StringName &p_action) const {
+bool InputEvent::is_action_released(const StringName &p_action, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && !pressed;
}
-float InputEvent::get_action_strength(const StringName &p_action) const {
+float InputEvent::get_action_strength(const StringName &p_action, bool p_exact_match) const {
float strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, &strength, nullptr);
return valid ? strength : 0.0f;
}
-float InputEvent::get_action_raw_strength(const StringName &p_action) const {
+float InputEvent::get_action_raw_strength(const StringName &p_action, bool p_exact_match) const {
float raw_strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, nullptr, &raw_strength);
return valid ? raw_strength : 0.0f;
}
@@ -100,10 +100,10 @@ void InputEvent::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device);
ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device);
- ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action);
- ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released);
- ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength);
+ ClassDB::bind_method(D_METHOD("is_action", "action", "exact_match"), &InputEvent::is_action, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo", "exact_match"), &InputEvent::is_action_pressed, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_released", "action", "exact_match"), &InputEvent::is_action_released, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &InputEvent::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed);
ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo);
@@ -384,6 +384,31 @@ String InputEventKey::to_string() {
return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e);
}
+Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) {
+ Ref<InputEventKey> ie;
+ ie.instance();
+ ie->set_keycode(p_keycode & KEY_CODE_MASK);
+ ie->set_unicode(p_keycode & KEY_CODE_MASK);
+
+ if (p_keycode & KEY_MASK_SHIFT) {
+ ie->set_shift(true);
+ }
+ if (p_keycode & KEY_MASK_ALT) {
+ ie->set_alt(true);
+ }
+ if (p_keycode & KEY_MASK_CTRL) {
+ ie->set_control(true);
+ }
+ if (p_keycode & KEY_MASK_CMD) {
+ ie->set_command(true);
+ }
+ if (p_keycode & KEY_MASK_META) {
+ ie->set_metakey(true);
+ }
+
+ return ie;
+}
+
bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventKey> key = p_event;
if (key.is_null()) {
@@ -594,15 +619,15 @@ String InputEventMouseButton::as_text() const {
// Button
int idx = get_button_index();
switch (idx) {
- case BUTTON_LEFT:
- case BUTTON_RIGHT:
- case BUTTON_MIDDLE:
- case BUTTON_WHEEL_UP:
- case BUTTON_WHEEL_DOWN:
- case BUTTON_WHEEL_LEFT:
- case BUTTON_WHEEL_RIGHT:
- case BUTTON_XBUTTON1:
- case BUTTON_XBUTTON2:
+ case MOUSE_BUTTON_LEFT:
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_MIDDLE:
+ case MOUSE_BUTTON_WHEEL_UP:
+ case MOUSE_BUTTON_WHEEL_DOWN:
+ case MOUSE_BUTTON_WHEEL_LEFT:
+ case MOUSE_BUTTON_WHEEL_RIGHT:
+ case MOUSE_BUTTON_XBUTTON1:
+ case MOUSE_BUTTON_XBUTTON2:
full_string += RTR(_mouse_button_descriptions[idx - 1]); // button index starts from 1, array index starts from 0, so subtract 1
break;
default:
@@ -626,15 +651,15 @@ String InputEventMouseButton::to_string() {
String button_string = itos(idx);
switch (idx) {
- case BUTTON_LEFT:
- case BUTTON_RIGHT:
- case BUTTON_MIDDLE:
- case BUTTON_WHEEL_UP:
- case BUTTON_WHEEL_DOWN:
- case BUTTON_WHEEL_LEFT:
- case BUTTON_WHEEL_RIGHT:
- case BUTTON_XBUTTON1:
- case BUTTON_XBUTTON2:
+ case MOUSE_BUTTON_LEFT:
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_MIDDLE:
+ case MOUSE_BUTTON_WHEEL_UP:
+ case MOUSE_BUTTON_WHEEL_DOWN:
+ case MOUSE_BUTTON_WHEEL_LEFT:
+ case MOUSE_BUTTON_WHEEL_RIGHT:
+ case MOUSE_BUTTON_XBUTTON1:
+ case MOUSE_BUTTON_XBUTTON2:
button_string += " (" + RTR(_mouse_button_descriptions[idx - 1]) + ")"; // button index starts from 1, array index starts from 0, so subtract 1
break;
default:
@@ -736,20 +761,20 @@ String InputEventMouseMotion::to_string() {
int button_mask = get_button_mask();
String button_mask_string = itos(button_mask);
switch (get_button_mask()) {
- case BUTTON_MASK_LEFT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_LEFT - 1]) + ")";
+ case MOUSE_BUTTON_MASK_LEFT:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_LEFT - 1]) + ")";
break;
- case BUTTON_MASK_MIDDLE:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_MIDDLE - 1]) + ")";
+ case MOUSE_BUTTON_MASK_MIDDLE:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_MIDDLE - 1]) + ")";
break;
- case BUTTON_MASK_RIGHT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_RIGHT - 1]) + ")";
+ case MOUSE_BUTTON_MASK_RIGHT:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_RIGHT - 1]) + ")";
break;
- case BUTTON_MASK_XBUTTON1:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON1 - 1]) + ")";
+ case MOUSE_BUTTON_MASK_XBUTTON1:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_XBUTTON1 - 1]) + ")";
break;
- case BUTTON_MASK_XBUTTON2:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON2 - 1]) + ")";
+ case MOUSE_BUTTON_MASK_XBUTTON2:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_XBUTTON2 - 1]) + ")";
break;
default:
break;
@@ -1011,6 +1036,14 @@ String InputEventJoypadButton::to_string() {
return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure));
}
+Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) {
+ Ref<InputEventJoypadButton> ie;
+ ie.instance();
+ ie->set_button_index(p_btn_index);
+
+ return ie;
+}
+
void InputEventJoypadButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_index", "button_index"), &InputEventJoypadButton::set_button_index);
ClassDB::bind_method(D_METHOD("get_button_index"), &InputEventJoypadButton::get_button_index);
diff --git a/core/input/input_event.h b/core/input/input_event.h
index a354119cf9..94aa68db33 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -33,7 +33,6 @@
#include "core/io/resource.h"
#include "core/math/transform_2d.h"
-#include "core/os/copymem.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
@@ -42,24 +41,24 @@
* The events are pretty obvious.
*/
-enum ButtonList {
- BUTTON_LEFT = 1,
- BUTTON_RIGHT = 2,
- BUTTON_MIDDLE = 3,
- BUTTON_WHEEL_UP = 4,
- BUTTON_WHEEL_DOWN = 5,
- BUTTON_WHEEL_LEFT = 6,
- BUTTON_WHEEL_RIGHT = 7,
- BUTTON_XBUTTON1 = 8,
- BUTTON_XBUTTON2 = 9,
- BUTTON_MASK_LEFT = (1 << (BUTTON_LEFT - 1)),
- BUTTON_MASK_RIGHT = (1 << (BUTTON_RIGHT - 1)),
- BUTTON_MASK_MIDDLE = (1 << (BUTTON_MIDDLE - 1)),
- BUTTON_MASK_XBUTTON1 = (1 << (BUTTON_XBUTTON1 - 1)),
- BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1))
+enum MouseButton {
+ MOUSE_BUTTON_LEFT = 1,
+ MOUSE_BUTTON_RIGHT = 2,
+ MOUSE_BUTTON_MIDDLE = 3,
+ MOUSE_BUTTON_WHEEL_UP = 4,
+ MOUSE_BUTTON_WHEEL_DOWN = 5,
+ MOUSE_BUTTON_WHEEL_LEFT = 6,
+ MOUSE_BUTTON_WHEEL_RIGHT = 7,
+ MOUSE_BUTTON_XBUTTON1 = 8,
+ MOUSE_BUTTON_XBUTTON2 = 9,
+ MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)),
+ MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)),
+ MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)),
+ MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)),
+ MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1))
};
-enum JoyButtonList {
+enum JoyButton {
JOY_BUTTON_INVALID = -1,
JOY_BUTTON_A = 0,
JOY_BUTTON_B = 1,
@@ -86,7 +85,7 @@ enum JoyButtonList {
JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons.
};
-enum JoyAxisList {
+enum JoyAxis {
JOY_AXIS_INVALID = -1,
JOY_AXIS_LEFT_X = 0,
JOY_AXIS_LEFT_Y = 1,
@@ -98,7 +97,7 @@ enum JoyAxisList {
JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
};
-enum MidiMessageList {
+enum MIDIMessage {
MIDI_MESSAGE_NOTE_OFF = 0x8,
MIDI_MESSAGE_NOTE_ON = 0x9,
MIDI_MESSAGE_AFTERTOUCH = 0xA,
@@ -128,11 +127,11 @@ public:
void set_device(int p_device);
int get_device() const;
- bool is_action(const StringName &p_action) const;
- bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const;
- bool is_action_released(const StringName &p_action) const;
- float get_action_strength(const StringName &p_action) const;
- float get_action_raw_strength(const StringName &p_action) const;
+ bool is_action(const StringName &p_action, bool p_exact_match = false) const;
+ bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
+ bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
+ float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
+ float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
// To be removed someday, since they do not make sense for all events
virtual bool is_pressed() const;
@@ -260,6 +259,8 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
+ static Ref<InputEventKey> create_reference(uint32_t p_keycode_with_modifier_masks);
+
InputEventKey() {}
};
@@ -406,6 +407,8 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
+ static Ref<InputEventJoypadButton> create_reference(int p_btn_index);
+
InputEventJoypadButton() {}
};
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 53ed925c1f..aab4e6593c 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -50,12 +50,40 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
- ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
+ ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
+/**
+ * Returns an nonexistent action error message with a suggestion of the closest
+ * matching action name (if possible).
+ */
+String InputMap::_suggest_actions(const StringName &p_action) const {
+ List<StringName> actions = get_actions();
+ StringName closest_action;
+ float closest_similarity = 0.0;
+
+ // Find the most action with the most similar name.
+ for (List<StringName>::Element *E = actions.front(); E; E = E->next()) {
+ const float similarity = String(E->get()).similarity(p_action);
+
+ if (similarity > closest_similarity) {
+ closest_action = E->get();
+ closest_similarity = similarity;
+ }
+ }
+
+ String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
+
+ if (closest_similarity >= 0.4) {
+ // Only include a suggestion in the error message if it's similar enough.
+ error_message += vformat(" Did you mean \"%s\"?", closest_action);
+ }
+ return error_message;
+}
+
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\".");
input_map[p_action] = Action();
static int last_id = 1;
input_map[p_action].id = last_id;
@@ -64,7 +92,8 @@ void InputMap::add_action(const StringName &p_action, float p_deadzone) {
}
void InputMap::erase_action(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
+
input_map.erase(p_action);
}
@@ -88,14 +117,14 @@ List<StringName> InputMap::get_actions() const {
return actions;
}
- for (Map<StringName, Action>::Element *E = input_map.front(); E; E = E->next()) {
- actions.push_back(E->key());
+ for (OrderedHashMap<StringName, Action>::Element E = input_map.front(); E; E = E.next()) {
+ actions.push_back(E.key());
}
return actions;
}
-List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
+List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
@@ -106,7 +135,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int device = e->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
- if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
+ if (p_exact_match && e->shortcut_match(p_event)) {
+ return E;
+ } else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
return E;
}
}
@@ -120,21 +151,21 @@ bool InputMap::has_action(const StringName &p_action) const {
}
float InputMap::action_get_deadzone(const StringName &p_action) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, _suggest_actions(p_action));
return input_map[p_action].deadzone;
}
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].deadzone = p_deadzone;
}
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
- if (_find_event(input_map[p_action], p_event)) {
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
+ if (_find_event(input_map[p_action], p_event, true)) {
return; // Already addded.
}
@@ -142,14 +173,14 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
}
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
- return (_find_event(input_map[p_action], p_event) != nullptr);
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, _suggest_actions(p_action));
+ return (_find_event(input_map[p_action], p_event, true) != nullptr);
}
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
- List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event);
+ List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
if (E) {
input_map[p_action].inputs.erase(E);
if (Input::get_singleton()->is_action_pressed(p_action)) {
@@ -159,7 +190,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
}
void InputMap::action_erase_events(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].inputs.clear();
}
@@ -177,21 +208,21 @@ Array InputMap::_action_get_events(const StringName &p_action) {
}
const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
- const Map<StringName, Action>::Element *E = input_map.find(p_action);
+ const OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
if (!E) {
return nullptr;
}
- return &E->get().inputs;
+ return &E.get().inputs;
}
-bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const {
- return event_get_action_status(p_event, p_action);
+bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
+ return event_get_action_status(p_event, p_action, p_exact_match);
}
-bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
- Map<StringName, Action>::Element *E = input_map.find(p_action);
- ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
+ OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
+ ERR_FAIL_COND_V_MSG(!E, false, _suggest_actions(p_action));
Ref<InputEventAction> input_event_action = p_event;
if (input_event_action.is_valid()) {
@@ -207,7 +238,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
bool pressed;
float strength;
float raw_strength;
- List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength);
+ List<Ref<InputEvent>>::Element *event = _find_event(E.get(), p_event, p_exact_match, &pressed, &strength, &raw_strength);
if (event != nullptr) {
if (p_pressed != nullptr) {
*p_pressed = pressed;
@@ -224,7 +255,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
}
}
-const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
+const OrderedHashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
return input_map;
}
@@ -258,84 +289,445 @@ void InputMap::load_from_project_settings() {
}
}
+struct _BuiltinActionDisplayName {
+ const char *name;
+ const char *display_name;
+};
+
+static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
+ /* clang-format off */
+ { "ui_accept", TTRC("Accept") },
+ { "ui_select", TTRC("Select") },
+ { "ui_cancel", TTRC("Cancel") },
+ { "ui_focus_next", TTRC("Focus Next") },
+ { "ui_focus_prev", TTRC("Focus Prev") },
+ { "ui_left", TTRC("Left") },
+ { "ui_right", TTRC("Right") },
+ { "ui_up", TTRC("Up") },
+ { "ui_down", TTRC("Down") },
+ { "ui_page_up", TTRC("Page Up") },
+ { "ui_page_down", TTRC("Page Down") },
+ { "ui_home", TTRC("Home") },
+ { "ui_end", TTRC("End") },
+ { "ui_cut", TTRC("Cut") },
+ { "ui_copy", TTRC("Copy") },
+ { "ui_paste", TTRC("Paste") },
+ { "ui_undo", TTRC("Undo") },
+ { "ui_redo", TTRC("Redo") },
+ { "ui_text_completion_query", TTRC("Completion Query") },
+ { "ui_text_newline", TTRC("New Line") },
+ { "ui_text_newline_blank", TTRC("New Blank Line") },
+ { "ui_text_newline_above", TTRC("New Line Above") },
+ { "ui_text_indent", TTRC("Indent") },
+ { "ui_text_dedent", TTRC("Dedent") },
+ { "ui_text_backspace", TTRC("Backspace") },
+ { "ui_text_backspace_word", TTRC("Backspace Word") },
+ { "ui_text_backspace_word.OSX", TTRC("Backspace Word") },
+ { "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
+ { "ui_text_backspace_all_to_left.OSX", TTRC("Backspace all to Left") },
+ { "ui_text_delete", TTRC("Delete") },
+ { "ui_text_delete_word", TTRC("Delete Word") },
+ { "ui_text_delete_word.OSX", TTRC("Delete Word") },
+ { "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
+ { "ui_text_delete_all_to_right.OSX", TTRC("Delete all to Right") },
+ { "ui_text_caret_left", TTRC("Caret Left") },
+ { "ui_text_caret_word_left", TTRC("Caret Word Left") },
+ { "ui_text_caret_word_left.OSX", TTRC("Caret Word Left") },
+ { "ui_text_caret_right", TTRC("Caret Right") },
+ { "ui_text_caret_word_right", TTRC("Caret Word Right") },
+ { "ui_text_caret_word_right.OSX", TTRC("Caret Word Right") },
+ { "ui_text_caret_up", TTRC("Caret Up") },
+ { "ui_text_caret_down", TTRC("Caret Down") },
+ { "ui_text_caret_line_start", TTRC("Caret Line Start") },
+ { "ui_text_caret_line_start.OSX", TTRC("Caret Line Start") },
+ { "ui_text_caret_line_end", TTRC("Caret Line End") },
+ { "ui_text_caret_line_end.OSX", TTRC("Caret Line End") },
+ { "ui_text_caret_page_up", TTRC("Caret Page Up") },
+ { "ui_text_caret_page_down", TTRC("Caret Page Down") },
+ { "ui_text_caret_document_start", TTRC("Caret Document Start") },
+ { "ui_text_caret_document_start.OSX", TTRC("Caret Document Start") },
+ { "ui_text_caret_document_end", TTRC("Caret Document End") },
+ { "ui_text_caret_document_end.OSX", TTRC("Caret Document End") },
+ { "ui_text_scroll_up", TTRC("Scroll Up") },
+ { "ui_text_scroll_up.OSX", TTRC("Scroll Up") },
+ { "ui_text_scroll_down", TTRC("Scroll Down") },
+ { "ui_text_scroll_down.OSX", TTRC("Scroll Down") },
+ { "ui_text_select_all", TTRC("Select All") },
+ { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
+ { "ui_graph_duplicate", TTRC("Duplicate Nodes") },
+ { "ui_graph_delete", TTRC("Delete Nodes") },
+ { "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
+ { "ui_filedialog_refresh", TTRC("Refresh") },
+ { "ui_filedialog_show_hidden", TTRC("Show Hidden") },
+ { "ui_swap_input_direction ", TTRC("Swap Input Direction") },
+ { "", TTRC("")}
+ /* clang-format on */
+};
+
+String InputMap::get_builtin_display_name(const String &p_name) const {
+ int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName);
+
+ for (int i = 0; i < len; i++) {
+ if (_builtin_action_display_names[i].name == p_name) {
+ return RTR(_builtin_action_display_names[i].display_name);
+ }
+ }
+
+ return p_name;
+}
+
+const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
+ // Return cache if it has already been built.
+ if (default_builtin_cache.size()) {
+ return default_builtin_cache;
+ }
+
+ List<Ref<InputEvent>> inputs;
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE));
+ default_builtin_cache.insert("ui_accept", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_Y));
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE));
+ default_builtin_cache.insert("ui_select", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ESCAPE));
+ default_builtin_cache.insert("ui_cancel", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_focus_next", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_focus_prev", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_LEFT));
+ default_builtin_cache.insert("ui_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_RIGHT));
+ default_builtin_cache.insert("ui_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_UP));
+ default_builtin_cache.insert("ui_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_DOWN));
+ default_builtin_cache.insert("ui_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEUP));
+ default_builtin_cache.insert("ui_page_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEDOWN));
+ default_builtin_cache.insert("ui_page_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME));
+ default_builtin_cache.insert("ui_home", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END));
+ default_builtin_cache.insert("ui_end", inputs);
+
+ // ///// UI basic Shortcuts /////
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_X | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_cut", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_C | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_copy", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_V | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_paste", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_Z | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_undo", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_Z | KEY_MASK_CMD | KEY_MASK_SHIFT));
+ inputs.push_back(InputEventKey::create_reference(KEY_Y | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_redo", inputs);
+
+ // ///// UI Text Input Shortcuts /////
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_completion_query", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_text_completion_accept", inputs);
+
+ // Newlines
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
+ default_builtin_cache.insert("ui_text_newline", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_newline_blank", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER | KEY_MASK_SHIFT | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER | KEY_MASK_SHIFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_newline_above", inputs);
+
+ // Indentation
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_text_indent", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_text_dedent", inputs);
+
+ // Text Backspace and Delete
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE));
+ default_builtin_cache.insert("ui_text_backspace", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_backspace_word", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_backspace_word.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_backspace_all_to_left.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE));
+ default_builtin_cache.insert("ui_text_delete", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_delete_word", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_delete_word.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_delete_all_to_right.OSX", inputs);
+
+ // Text Caret Movement Left/Right
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT));
+ default_builtin_cache.insert("ui_text_caret_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_word_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_caret_word_left.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT));
+ default_builtin_cache.insert("ui_text_caret_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_word_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_caret_word_right.OSX", inputs);
+
+ // Text Caret Movement Up/Down
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP));
+ default_builtin_cache.insert("ui_text_caret_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN));
+ default_builtin_cache.insert("ui_text_caret_down", inputs);
+
+ // Text Caret Movement Line Start/End
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME));
+ default_builtin_cache.insert("ui_text_caret_line_start", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_A | KEY_MASK_CTRL));
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_line_start.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END));
+ default_builtin_cache.insert("ui_text_caret_line_end", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_E | KEY_MASK_CTRL));
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_line_end.OSX", inputs);
+
+ // Text Caret Movement Page Up/Down
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEUP));
+ default_builtin_cache.insert("ui_text_caret_page_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEDOWN));
+ default_builtin_cache.insert("ui_text_caret_page_down", inputs);
+
+ // Text Caret Movement Document Start/End
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_start", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_start.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_end", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_end.OSX", inputs);
+
+ // Text Scrolling
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_scroll_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_scroll_up.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_scroll_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_scroll_down.OSX", inputs);
+
+ // Text Misc
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_A | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_select_all", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT));
+ default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_MENU));
+ default_builtin_cache.insert("ui_menu", inputs);
+
+ // ///// UI Graph Shortcuts /////
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_D | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_graph_duplicate", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE));
+ default_builtin_cache.insert("ui_graph_delete", inputs);
+
+ // ///// UI File Dialog Shortcuts /////
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE));
+ default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_F5));
+ default_builtin_cache.insert("ui_filedialog_refresh", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_H));
+ default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_QUOTELEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_swap_input_direction", inputs);
+
+ return default_builtin_cache;
+}
+
void InputMap::load_default() {
- Ref<InputEventKey> key;
-
- add_action("ui_accept");
- key.instance();
- key->set_keycode(KEY_ENTER);
- action_add_event("ui_accept", key);
-
- key.instance();
- key->set_keycode(KEY_KP_ENTER);
- action_add_event("ui_accept", key);
-
- key.instance();
- key->set_keycode(KEY_SPACE);
- action_add_event("ui_accept", key);
-
- add_action("ui_select");
- key.instance();
- key->set_keycode(KEY_SPACE);
- action_add_event("ui_select", key);
-
- add_action("ui_cancel");
- key.instance();
- key->set_keycode(KEY_ESCAPE);
- action_add_event("ui_cancel", key);
-
- add_action("ui_focus_next");
- key.instance();
- key->set_keycode(KEY_TAB);
- action_add_event("ui_focus_next", key);
-
- add_action("ui_focus_prev");
- key.instance();
- key->set_keycode(KEY_TAB);
- key->set_shift(true);
- action_add_event("ui_focus_prev", key);
-
- add_action("ui_left");
- key.instance();
- key->set_keycode(KEY_LEFT);
- action_add_event("ui_left", key);
-
- add_action("ui_right");
- key.instance();
- key->set_keycode(KEY_RIGHT);
- action_add_event("ui_right", key);
-
- add_action("ui_up");
- key.instance();
- key->set_keycode(KEY_UP);
- action_add_event("ui_up", key);
-
- add_action("ui_down");
- key.instance();
- key->set_keycode(KEY_DOWN);
- action_add_event("ui_down", key);
-
- add_action("ui_page_up");
- key.instance();
- key->set_keycode(KEY_PAGEUP);
- action_add_event("ui_page_up", key);
-
- add_action("ui_page_down");
- key.instance();
- key->set_keycode(KEY_PAGEDOWN);
- action_add_event("ui_page_down", key);
-
- add_action("ui_home");
- key.instance();
- key->set_keycode(KEY_HOME);
- action_add_event("ui_home", key);
-
- add_action("ui_end");
- key.instance();
- key->set_keycode(KEY_END);
- action_add_event("ui_end", key);
-
- //set("display/window/handheld/orientation", "landscape");
+ OrderedHashMap<String, List<Ref<InputEvent>>> builtins = get_builtins();
+
+ // List of Builtins which have an override for OSX.
+ Vector<String> osx_builtins;
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ if (String(E.key()).ends_with(".OSX")) {
+ // Strip .OSX from name: some_input_name.OSX -> some_input_name
+ osx_builtins.push_back(String(E.key()).split(".")[0]);
+ }
+ }
+
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ String fullname = E.key();
+ String name = fullname.split(".")[0];
+ String override_for = fullname.split(".").size() > 1 ? fullname.split(".")[1] : "";
+
+#ifdef APPLE_STYLE_KEYS
+ if (osx_builtins.has(name) && override_for != "OSX") {
+ // Name has osx builtin but this particular one is for non-osx systems - so skip.
+ continue;
+ }
+#else
+ if (override_for == "OSX") {
+ // Override for OSX - not needed on non-osx platforms.
+ continue;
+ }
+#endif
+
+ add_action(name);
+
+ List<Ref<InputEvent>> inputs = E.get();
+ for (List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
+ Ref<InputEventKey> iek = I->get();
+
+ // For the editor, only add keyboard actions.
+ if (iek.is_valid()) {
+ action_add_event(name, I->get());
+ }
+ }
+ }
}
InputMap::InputMap() {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 1646e7fadb..0e0567464a 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -33,6 +33,8 @@
#include "core/input/input_event.h"
#include "core/object/class_db.h"
+#include "core/object/object.h"
+#include "core/templates/ordered_hash_map.h"
class InputMap : public Object {
GDCLASS(InputMap, Object);
@@ -52,12 +54,14 @@ public:
private:
static InputMap *singleton;
- mutable Map<StringName, Action> input_map;
+ mutable OrderedHashMap<StringName, Action> input_map;
+ OrderedHashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
- List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
+ List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
Array _action_get_events(const StringName &p_action);
Array _get_actions();
+ String _suggest_actions(const StringName &p_action) const;
protected:
static void _bind_methods();
@@ -78,13 +82,17 @@ public:
void action_erase_events(const StringName &p_action);
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
- bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const;
- bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
+ bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
+ bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
- const Map<StringName, Action> &get_action_map() const;
+ const OrderedHashMap<StringName, Action> &get_action_map() const;
void load_from_project_settings();
void load_default();
+ String get_builtin_display_name(const String &p_name) const;
+ // Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat.
+ const OrderedHashMap<String, List<Ref<InputEvent>>> &get_builtins();
+
InputMap();
};
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 456023e2a6..6de626db99 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/io/zip_io.h"
-#include "core/os/copymem.h"
#include "thirdparty/misc/fastlz.h"
@@ -44,8 +43,8 @@ int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,
case MODE_FASTLZ: {
if (p_src_size < 16) {
uint8_t src[16];
- zeromem(&src[p_src_size], 16 - p_src_size);
- copymem(src, p_src, p_src_size);
+ memset(&src[p_src_size], 0, 16 - p_src_size);
+ memcpy(src, p_src, p_src_size);
return fastlz_compress(src, 16, p_dst);
} else {
return fastlz_compress(p_src, p_src_size, p_dst);
@@ -136,7 +135,7 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
if (p_dst_max_size < 16) {
uint8_t dst[16];
ret_size = fastlz_decompress(p_src, p_src_size, dst, 16);
- copymem(p_dst, dst, p_dst_max_size);
+ memcpy(p_dst, dst, p_dst_max_size);
} else {
ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
}
@@ -181,8 +180,8 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
}
/**
- This will handle both Gzip and Deflat streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
- This is required for compressed data who's final uncompressed size is unknown, as is the case for HTTP response bodies.
+ This will handle both Gzip and Deflate streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
+ This is required for compressed data whose final uncompressed size is unknown, as is the case for HTTP response bodies.
This is much slower however than using Compression::decompress because it may result in multiple full copies of the output buffer.
*/
int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
@@ -248,7 +247,7 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s
out_mark += gzip_chunk;
- // Encorce max output size
+ // Enforce max output size
if (p_max_dst_size > -1 && strm.total_out > (uint64_t)p_max_dst_size) {
(void)inflateEnd(&strm);
p_dst_vect->resize(0);
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 015c1f0d90..10f68f3cef 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -295,6 +295,9 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
return OK;
}
+void ConfigFile::clear() {
+ values.clear();
+}
void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
@@ -317,4 +320,6 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_encrypted", "path", "key"), &ConfigFile::save_encrypted);
ClassDB::bind_method(D_METHOD("save_encrypted_pass", "path", "password"), &ConfigFile::save_encrypted_pass);
+
+ ClassDB::bind_method(D_METHOD("clear"), &ConfigFile::clear);
}
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 386d304f07..1b28257c60 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -68,6 +68,8 @@ public:
Error load(const String &p_path);
Error parse(const String &p_data);
+ void clear();
+
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
Error load_encrypted_pass(const String &p_path, const String &p_pass);
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 9ec2b27e88..b2440629e3 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -286,8 +286,10 @@ uint8_t FileAccessCompressed::get_8() const {
}
int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
- ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+ ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
+ ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
if (at_end) {
read_eof = true;
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 8b4c57ce64..13377a3a25 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -31,7 +31,6 @@
#include "file_access_encrypted.h"
#include "core/crypto/crypto_core.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#include "core/variant/variant.h"
@@ -151,7 +150,7 @@ void FileAccessEncrypted::_release() {
ERR_FAIL_COND(CryptoCore::md5(data.ptr(), data.size(), hash) != OK); // Bug?
compressed.resize(len);
- zeromem(compressed.ptrw(), len);
+ memset(compressed.ptrw(), 0, len);
for (int i = 0; i < data.size(); i++) {
compressed.write[i] = data[i];
}
@@ -237,7 +236,9 @@ uint8_t FileAccessEncrypted::get_8() const {
}
int FileAccessEncrypted::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+ ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
int to_copy = MIN(p_length, data.size() - pos);
for (int i = 0; i < to_copy; i++) {
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 04270de77f..af155a77a8 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -31,7 +31,6 @@
#include "file_access_memory.h"
#include "core/config/project_settings.h"
-#include "core/os/copymem.h"
#include "core/os/dir_access.h"
#include "core/templates/map.h"
@@ -138,6 +137,8 @@ uint8_t FileAccessMemory::get_8() const {
}
int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!data, -1);
int left = length - pos;
@@ -147,7 +148,7 @@ int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const {
WARN_PRINT("Reading less data than requested");
}
- copymem(p_dst, &data[pos], read);
+ memcpy(p_dst, &data[pos], read);
pos += p_length;
return read;
@@ -174,6 +175,6 @@ void FileAccessMemory::store_buffer(const uint8_t *p_src, int p_length) {
WARN_PRINT("Writing less data than requested");
}
- copymem(&data[pos], p_src, write);
+ memcpy(&data[pos], p_src, write);
pos += p_length;
}
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 97838fd14c..31b7d658d0 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -366,6 +366,9 @@ void FileAccessNetwork::_queue_page(int p_page) const {
}
int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
//bool eof=false;
if (pos + p_length > total_size) {
eof_flag = true;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index faf4fca14f..e24dc40166 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -299,6 +299,9 @@ uint8_t FileAccessPack::get_8() const {
}
int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
if (eof) {
return 0;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 3c84e6b656..955108f455 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -36,6 +36,7 @@
#include "core/string/print_string.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/set.h"
// Godot's packed file magic header ("GDPC" in ASCII).
#define PACK_HEADER_MAGIC 0x43504447
@@ -92,7 +93,7 @@ private:
PathMD5() {}
- PathMD5(const Vector<uint8_t> p_buf) {
+ PathMD5(const Vector<uint8_t> &p_buf) {
a = *((uint64_t *)&p_buf[0]);
b = *((uint64_t *)&p_buf[8]);
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 01f9337a80..397b577612 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -32,7 +32,6 @@
#include "file_access_zip.h"
-#include "core/os/copymem.h"
#include "core/os/file_access.h"
ZipArchive *ZipArchive::instance = nullptr;
@@ -120,7 +119,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
ERR_FAIL_COND_V_MSG(!f, nullptr, "Cannot open file '" + packages[file.package].filename + "'.");
zlib_filefunc_def io;
- zeromem(&io, sizeof(io));
+ memset(&io, 0, sizeof(io));
io.opaque = f;
io.zopen_file = godot_open;
@@ -303,6 +302,8 @@ uint8_t FileAccessZip::get_8() const {
}
int FileAccessZip::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!zfile, -1);
at_eof = unzeof(zfile);
if (at_eof) {
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 18afdc678e..4b053d576c 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -96,6 +96,11 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
+ if (ssl) {
+ ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()),
+ "Connection is not a reference to a valid StreamPeerSSL object.");
+ }
+
if (connection == p_connection) {
return;
}
@@ -628,7 +633,7 @@ PackedByteArray HTTPClient::read_response_body_chunk() {
ret.resize(chunk.size() - 2);
uint8_t *w = ret.ptrw();
- copymem(w, chunk.ptr(), chunk.size() - 2);
+ memcpy(w, chunk.ptr(), chunk.size() - 2);
chunk.clear();
}
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 986c29b539..c36fa6e45f 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -34,7 +34,6 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#include "core/templates/hash_map.h"
@@ -1537,7 +1536,7 @@ void Image::shrink_x2() {
uint8_t *w = new_img.ptrw();
const uint8_t *r = data.ptr();
- copymem(w, &r[ofs], new_size);
+ memcpy(w, &r[ofs], new_size);
}
width = MAX(width / 2, 1);
@@ -1932,7 +1931,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
uint8_t* wr = imgdata.ptrw();
- copymem(wr.ptr(), ptr, size);
+ memcpy(wr.ptr(), ptr, size);
wr = uint8_t*();
Ref<Image> im;
im.instance();
@@ -1982,7 +1981,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
{
uint8_t *w = data.ptrw();
- zeromem(w, size);
+ memset(w, 0, size);
}
width = p_width;
@@ -2985,31 +2984,53 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
_set_color_at_ofs(data.ptrw(), ofs, p_color);
}
+void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
+ uint8_t *w = data.ptrw();
+ uint32_t pixel_size = get_format_pixel_size(format);
+ uint32_t pixel_count = data.size() / pixel_size;
+
+ for (uint32_t i = 0; i < pixel_count; i++) {
+ Color c = _get_color_at_ofs(w, i);
+ Vector3 rgb(c.r, c.g, c.b);
+
+ rgb *= p_brightness;
+ rgb = Vector3(0.5, 0.5, 0.5).lerp(rgb, p_contrast);
+ float center = (rgb.x + rgb.y + rgb.z) / 3.0;
+ rgb = Vector3(center, center, center).lerp(rgb, p_saturation);
+ c.r = rgb.x;
+ c.g = rgb.y;
+ c.b = rgb.z;
+ _set_color_at_ofs(w, i, c);
+ }
+}
+
Image::UsedChannels Image::detect_used_channels(CompressSource p_source) {
ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA);
ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
bool r = false, g = false, b = false, a = false, c = false;
- for (int i = 0; i < width; i++) {
- for (int j = 0; j < height; j++) {
- Color col = get_pixel(i, j);
+ const uint8_t *data_ptr = data.ptr();
- if (col.r > 0.001) {
- r = true;
- }
- if (col.g > 0.001) {
- g = true;
- }
- if (col.b > 0.001) {
- b = true;
- }
- if (col.a < 0.999) {
- a = true;
- }
+ uint32_t data_total = width * height;
- if (col.r != col.b || col.r != col.g || col.b != col.g) {
- c = true;
- }
+ for (uint32_t i = 0; i < data_total; i++) {
+ Color col = _get_color_at_ofs(data_ptr, i);
+
+ if (col.r > 0.001) {
+ r = true;
+ }
+ if (col.g > 0.001) {
+ g = true;
+ }
+ if (col.b > 0.001) {
+ b = true;
+ }
+ if (col.a < 0.999) {
+ a = true;
+ }
+
+ if (col.r != col.b || col.r != col.g || col.b != col.g) {
+ c = true;
}
}
@@ -3132,6 +3153,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv);
ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
+ ClassDB::bind_method(D_METHOD("adjust_bcs", "brightness", "contrast", "saturation"), &Image::adjust_bcs);
+
ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
@@ -3271,7 +3294,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
{
uint8_t *wr = new_data.ptrw();
const uint8_t *rd = data.ptr();
- copymem(wr, rd + ofs, size);
+ memcpy(wr, rd + ofs, size);
}
Ref<Image> image;
@@ -3598,5 +3621,5 @@ Ref<Resource> Image::duplicate(bool p_subresources) const {
}
void Image::set_as_black() {
- zeromem(data.ptrw(), data.size());
+ memset(data.ptrw(), 0, data.size());
}
diff --git a/core/io/image.h b/core/io/image.h
index b894be7df4..df8f9b35a1 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -390,6 +390,8 @@ public:
void set_pixelv(const Point2i &p_point, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
+ void adjust_bcs(float p_brightness, float p_contrast, float p_saturation);
+
void set_as_black();
void copy_internals_from(const Ref<Image> &p_image) {
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 8ca1cb3beb..7de038e6fe 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -122,7 +122,7 @@ void ImageLoader::cleanup() {
/////////////////
-RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderImage::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) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index bf67e1486f..a5d588e0b5 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -72,7 +72,7 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index df95785000..e1d9c19f10 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -40,13 +40,13 @@ VARIANT_ENUM_CAST(IP::ResolverStatus);
struct _IP_ResolverPrivate {
struct QueueItem {
- volatile IP::ResolverStatus status;
+ SafeNumeric<IP::ResolverStatus> status;
IP_Address response;
String hostname;
IP::Type type;
void clear() {
- status = IP::RESOLVER_STATUS_NONE;
+ status.set(IP::RESOLVER_STATUS_NONE);
response = IP_Address();
type = IP::TYPE_NONE;
hostname = "";
@@ -61,7 +61,7 @@ struct _IP_ResolverPrivate {
IP::ResolverID find_empty_id() const {
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
- if (queue[i].status == IP::RESOLVER_STATUS_NONE) {
+ if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE) {
return i;
}
}
@@ -77,15 +77,15 @@ struct _IP_ResolverPrivate {
void resolve_queues() {
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
- if (queue[i].status != IP::RESOLVER_STATUS_WAITING) {
+ if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) {
continue;
}
queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
if (!queue[i].response.is_valid()) {
- queue[i].status = IP::RESOLVER_STATUS_ERROR;
+ queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
} else {
- queue[i].status = IP::RESOLVER_STATUS_DONE;
+ queue[i].status.set(IP::RESOLVER_STATUS_DONE);
}
}
}
@@ -137,10 +137,10 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
resolver->queue[id].type = p_type;
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
resolver->queue[id].response = resolver->cache[key];
- resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
+ resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
} else {
resolver->queue[id].response = IP_Address();
- resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
+ resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
if (resolver->thread.is_started()) {
resolver->sem.post();
} else {
@@ -156,12 +156,12 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
MutexLock lock(resolver->mutex);
- if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
+ if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
resolver->mutex.unlock();
return IP::RESOLVER_STATUS_NONE;
}
- return resolver->queue[p_id].status;
+ return resolver->queue[p_id].status.get();
}
IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
@@ -169,7 +169,7 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
MutexLock lock(resolver->mutex);
- if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
+ if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
resolver->mutex.unlock();
return IP_Address();
@@ -183,7 +183,7 @@ void IP::erase_resolve_item(ResolverID p_id) {
MutexLock lock(resolver->mutex);
- resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
+ resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
}
void IP::clear_cache(const String &p_hostname) {
diff --git a/core/io/json.cpp b/core/io/json.cpp
index bc4527869b..394cf216e8 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -234,6 +234,52 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
}
index += 4; //will add at the end anyway
+ if ((res & 0xfffffc00) == 0xd800) {
+ if (p_str[index + 1] != '\\' || p_str[index + 2] != 'u') {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
+ return ERR_PARSE_ERROR;
+ }
+ index += 2;
+ char32_t trail = 0;
+ for (int j = 0; j < 4; j++) {
+ char32_t c = p_str[index + j + 1];
+ if (c == 0) {
+ r_err_str = "Unterminated String";
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+ r_err_str = "Malformed hex constant in string";
+ return ERR_PARSE_ERROR;
+ }
+ char32_t v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a';
+ v += 10;
+ } else if (c >= 'A' && c <= 'F') {
+ v = c - 'A';
+ v += 10;
+ } else {
+ ERR_PRINT("Bug parsing hex constant.");
+ v = 0;
+ }
+
+ trail <<= 4;
+ trail |= v;
+ }
+ if ((trail & 0xfffffc00) == 0xdc00) {
+ res = (res << 10UL) + trail - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ index += 4; //will add at the end anyway
+ } else {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
+ return ERR_PARSE_ERROR;
+ }
+ } else if ((res & 0xfffffc00) == 0xdc00) {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate";
+ return ERR_PARSE_ERROR;
+ }
+
} break;
default: {
res = next;
@@ -301,7 +347,6 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return err;
}
value = d;
- return OK;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
@@ -309,8 +354,6 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return err;
}
value = a;
- return OK;
-
} else if (token.type == TK_IDENTIFIER) {
String id = token.value;
if (id == "true") {
@@ -323,18 +366,16 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
r_err_str = "Expected 'true','false' or 'null', got '" + id + "'.";
return ERR_PARSE_ERROR;
}
- return OK;
-
} else if (token.type == TK_NUMBER) {
value = token.value;
- return OK;
} else if (token.type == TK_STRING) {
value = token.value;
- return OK;
} else {
r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
return ERR_PARSE_ERROR;
}
+
+ return OK;
}
Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
@@ -453,6 +494,19 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &
err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ // Check if EOF is reached
+ // or it's a type of the next token.
+ if (err == OK && idx < len) {
+ err = _get_token(str, idx, len, token, r_err_line, r_err_str);
+
+ if (err || token.type != TK_EOF) {
+ r_err_str = "Expected 'EOF'";
+ // Reset return value to empty `Variant`
+ r_ret = Variant();
+ return ERR_PARSE_ERROR;
+ }
+ }
+
return err;
}
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index da200f5717..8a07459a1d 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -43,6 +43,12 @@ bool Logger::should_log(bool p_err) {
return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
}
+bool Logger::_flush_stdout_on_print = true;
+
+void Logger::set_flush_stdout_on_print(bool value) {
+ _flush_stdout_on_print = value;
+}
+
void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
if (!should_log(true)) {
return;
@@ -207,7 +213,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
Memory::free_static(buf);
}
- if (p_err || GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ if (p_err || _flush_stdout_on_print) {
// Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds.
file->flush();
@@ -228,7 +234,7 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vfprintf(stderr, p_format, p_list);
} else {
vprintf(p_format, p_list);
- if (GLOBAL_GET("application/run/flush_stdout_on_print")) {
+ if (_flush_stdout_on_print) {
// Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds.
fflush(stdout);
diff --git a/core/io/logger.h b/core/io/logger.h
index b8e615b436..a12945911c 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -41,6 +41,8 @@ class Logger {
protected:
bool should_log(bool p_err);
+ static bool _flush_stdout_on_print;
+
public:
enum ErrorType {
ERR_ERROR,
@@ -49,6 +51,8 @@ public:
ERR_SHADER
};
+ static void set_flush_stdout_on_print(bool value);
+
virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 218a612da2..0282609270 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -851,7 +851,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
if (buf) {
encode_uint32(utf8.length(), buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length());
+ memcpy(buf, utf8.get_data(), utf8.length());
buf += utf8.length();
}
@@ -995,7 +995,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length(), buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length());
+ memcpy(buf, utf8.get_data(), utf8.length());
buf += pad + utf8.length();
}
@@ -1079,7 +1079,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Transform2D val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- copymem(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float));
}
}
}
@@ -1130,7 +1130,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Basis val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- copymem(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float));
}
}
}
@@ -1143,7 +1143,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Transform val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- copymem(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float));
}
}
@@ -1258,7 +1258,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length()+1,buf);
buf+=4;
- copymem(buf,utf8.get_data(),utf8.length()+1);
+ memcpy(buf,utf8.get_data(),utf8.length()+1);
}
r_len+=4+utf8.length()+1;
@@ -1314,7 +1314,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
encode_uint32(datalen, buf);
buf += 4;
const uint8_t *r = data.ptr();
- copymem(buf, &r[0], datalen * datasize);
+ memcpy(buf, &r[0], datalen * datasize);
buf += datalen * datasize;
}
@@ -1412,7 +1412,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length() + 1, buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length() + 1);
+ memcpy(buf, utf8.get_data(), utf8.length() + 1);
buf += utf8.length() + 1;
}
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 6b550e69c8..8414ee7c0c 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -50,7 +50,7 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas
// Do nothing.
} break;
case MultiplayerAPI::RPC_MODE_REMOTE: {
- // Do nothing also. Remote cannot produce a local call.
+ // Do nothing. Remote cannot produce a local call.
} break;
case MultiplayerAPI::RPC_MODE_MASTERSYNC: {
if (is_master) {
@@ -675,7 +675,7 @@ Error MultiplayerAPI::_encode_and_compress_variant(const Variant &p_variant, uin
return err;
}
if (r_buffer) {
- // The first byte is not used by the marshaling, so store the type
+ // The first byte is not used by the marshalling, so store the type
// so we know how to decompress and decode this variant.
r_buffer[0] = p_variant.get_type();
}
@@ -791,7 +791,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
packet_cache.resize(m_amount);
// Encode meta.
- // The meta is composed by a single byte that contains (starting from the least segnificant bit):
+ // The meta is composed by a single byte that contains (starting from the least significant bit):
// - `NetworkCommands` in the first three bits.
// - `NetworkNodeIdCompression` in the next 2 bits.
// - `NetworkNameIdCompression` in the next 1 bit.
@@ -830,7 +830,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 4;
}
} else {
- // The targets doesn't know the node yet, so we need to use 32 bits int.
+ // The targets don't know the node yet, so we need to use 32 bits int.
node_id_compression = NETWORK_NODE_ID_COMPRESSION_32;
MAKE_ROOM(ofs + 4);
encode_uint32(psc->id, &(packet_cache.write[ofs]));
@@ -897,7 +897,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
// Special optimization when only the byte vector is sent.
const Vector<uint8_t> data = *p_arg[0];
MAKE_ROOM(ofs + data.size());
- copymem(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
+ memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
ofs += data.size();
} else {
// Arguments
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index bc09477693..a632ad2ea7 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -67,6 +67,7 @@ public:
virtual bool is_open() const = 0;
virtual int get_available_bytes() const = 0;
+ virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const = 0;
virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully.
virtual void set_blocking_enabled(bool p_enabled) = 0;
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index a0b97772e6..c6354b11b7 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -317,7 +317,7 @@ Error PackedDataContainer::pack(const Variant &p_data) {
datalen = tmpdata.size();
data.resize(tmpdata.size());
uint8_t *w = data.ptrw();
- copymem(w, tmpdata.ptr(), tmpdata.size());
+ memcpy(w, tmpdata.ptr(), tmpdata.size());
return OK;
}
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index d8d63d976f..40e4ce4f77 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -159,10 +159,11 @@ int PacketPeerUDP::get_max_packet_size() const {
return 512; // uhm maybe not
}
-Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
+Error PacketPeerUDP::bind(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -210,6 +211,7 @@ Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
Error err;
@@ -224,7 +226,7 @@ Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
// I see no reason why we should get ERR_BUSY (wouldblock/eagain) here.
// This is UDP, so connect is only used to tell the OS to which socket
- // it shuold deliver packets when multiple are bound on the same address/port.
+ // it should deliver packets when multiple are bound on the same address/port.
if (err != OK) {
close();
ERR_FAIL_V_MSG(FAILED, "Unable to connect");
@@ -316,7 +318,7 @@ Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_b
return OK;
}
-bool PacketPeerUDP::is_listening() const {
+bool PacketPeerUDP::is_bound() const {
return _sock.is_valid() && _sock->is_open();
}
@@ -328,6 +330,12 @@ int PacketPeerUDP::get_packet_port() const {
return packet_port;
}
+int PacketPeerUDP::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
ERR_FAIL_COND_MSG(connected, "Destination address cannot be set for connected sockets");
peer_addr = p_address;
@@ -335,14 +343,15 @@ void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
}
void PacketPeerUDP::_bind_methods() {
- ClassDB::bind_method(D_METHOD("listen", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::listen, DEFVAL("*"), DEFVAL(65536));
+ ClassDB::bind_method(D_METHOD("bind", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::bind, DEFVAL("*"), DEFVAL(65536));
ClassDB::bind_method(D_METHOD("close"), &PacketPeerUDP::close);
ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait);
- ClassDB::bind_method(D_METHOD("is_listening"), &PacketPeerUDP::is_listening);
+ ClassDB::bind_method(D_METHOD("is_bound"), &PacketPeerUDP::is_bound);
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &PacketPeerUDP::connect_to_host);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &PacketPeerUDP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &PacketPeerUDP::get_local_port);
ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address);
ClassDB::bind_method(D_METHOD("set_broadcast_enabled", "enabled"), &PacketPeerUDP::set_broadcast_enabled);
ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group);
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index 4bac6994fc..b9d11c465c 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -70,10 +70,10 @@ protected:
public:
void set_blocking_mode(bool p_enable);
- Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
+ Error bind(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
void close();
Error wait();
- bool is_listening() const;
+ bool is_bound() const;
Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
void disconnect_shared_socket(); // Used by UDPServer
@@ -83,6 +83,7 @@ public:
IP_Address get_packet_address() const;
int get_packet_port() const;
+ int get_local_port() const;
void set_dest_address(const IP_Address &p_address, int p_port);
Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index db79998a90..d46e9edafa 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -87,7 +87,6 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
ResourceCache::lock.write_unlock();
}
- _change_notify("resource_path");
_resource_path_changed();
}
@@ -105,31 +104,34 @@ int Resource::get_subindex() const {
void Resource::set_name(const String &p_name) {
name = p_name;
- _change_notify("resource_name");
}
String Resource::get_name() const {
return name;
}
+void Resource::update_configuration_warning() {
+ if (_update_configuration_warning) {
+ _update_configuration_warning();
+ }
+}
+
bool Resource::editor_can_reload_from_file() {
return true; //by default yes
}
-void Resource::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
+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;
}
- Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), true);
-
- if (!s.is_valid()) {
- return;
- }
+ reset_state(); //may want to reset state
List<PropertyInfo> pi;
- s->get_property_list(&pi);
+ p_resource->get_property_list(&pi);
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
@@ -139,8 +141,23 @@ void Resource::reload_from_file() {
continue; //do not change path
}
- set(E->get().name, s->get(E->get().name));
+ set(E->get().name, p_resource->get(E->get().name));
}
+ return OK;
+}
+void Resource::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+
+ if (!s.is_valid()) {
+ return;
+ }
+
+ copy_from(s);
}
Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
@@ -309,6 +326,7 @@ void Resource::setup_local_to_scene() {
}
Node *(*Resource::_get_local_scene_func)() = nullptr;
+void (*Resource::_update_configuration_warning)() = nullptr;
void Resource::set_as_translation_remapped(bool p_remapped) {
if (remapped_list.in_list() == p_remapped) {
diff --git a/core/io/resource.h b/core/io/resource.h
index d0cd6ea3ac..75a9f928f8 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -88,8 +88,12 @@ protected:
public:
static Node *(*_get_local_scene_func)(); //used by editor
+ static void (*_update_configuration_warning)(); //used by editor
+ void update_configuration_warning();
virtual bool editor_can_reload_from_file();
+ virtual void reset_state(); //for resources that use variable amount of properties, either via _validate_property or _get_property_list, this function needs to be implemented to correctly clear state
+ virtual Error copy_from(const Ref<Resource> &p_resource);
virtual void reload_from_file();
void register_owner(Object *p_owner);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index fad58d65fd..c4eb2a20bb 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -313,17 +313,12 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
uint32_t index = f->get_32();
String path = res_path + "::" + itos(index);
- if (use_nocache) {
- if (!internal_index_cache.has(path)) {
- WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
- }
- r_v = internal_index_cache[path];
+ //always use internal cache for loading internal resources
+ if (!internal_index_cache.has(path)) {
+ WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
+ r_v = Variant();
} else {
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
- WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
- }
- r_v = res;
+ r_v = internal_index_cache[path];
}
} break;
@@ -645,7 +640,7 @@ Error ResourceLoaderBinary::load() {
}
} else {
- Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, local_path);
+ Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
if (err != OK) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
@@ -675,7 +670,7 @@ Error ResourceLoaderBinary::load() {
path = res_path + "::" + path;
}
- if (!use_nocache) {
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
if (ResourceCache::has(path)) {
//already loaded, don't do anything
stage++;
@@ -684,7 +679,7 @@ Error ResourceLoaderBinary::load() {
}
}
} else {
- if (!use_nocache && !ResourceCache::has(res_path)) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
path = res_path;
}
}
@@ -695,26 +690,40 @@ Error ResourceLoaderBinary::load() {
String t = get_unicode_string();
- Object *obj = ClassDB::instance(t);
- if (!obj) {
- error = ERR_FILE_CORRUPT;
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
- }
+ RES res;
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- String obj_class = obj->get_class();
- error = ERR_FILE_CORRUPT;
- memdelete(obj); //bye
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //use the existing one
+ Resource *r = ResourceCache::get(path);
+ if (r->get_class() == t) {
+ r->reset_state();
+ res = Ref<Resource>(r);
+ }
}
- RES res = RES(r);
+ if (res.is_null()) {
+ //did not replace
- if (path != String()) {
- r->set_path(path);
+ Object *obj = ClassDB::instance(t);
+ if (!obj) {
+ error = ERR_FILE_CORRUPT;
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ }
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ String obj_class = obj->get_class();
+ error = ERR_FILE_CORRUPT;
+ memdelete(obj); //bye
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ }
+
+ res = RES(r);
+ if (path != String() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it
+ }
+ r->set_subindex(subindex);
}
- r->set_subindex(subindex);
if (!main) {
internal_index_cache[path] = res;
@@ -961,7 +970,7 @@ ResourceLoaderBinary::~ResourceLoaderBinary() {
}
}
-RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -972,7 +981,7 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
ResourceLoaderBinary loader;
- loader.use_nocache = p_no_cache;
+ loader.cache_mode = p_cache_mode;
loader.use_sub_threads = p_use_sub_threads;
loader.progress = r_progress;
String path = p_original_path != "" ? p_original_path : p_path;
@@ -1236,7 +1245,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
- return ""; //could not rwead
+ return ""; //could not read
}
ResourceLoaderBinary loader;
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 428725f1d2..3592bbdbc4 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -78,7 +78,7 @@ class ResourceLoaderBinary {
Map<String, String> remaps;
Error error = OK;
- bool use_nocache = false;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
friend class ResourceFormatLoaderBinary;
@@ -103,7 +103,7 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index d86877ee14..b503655edd 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -116,7 +116,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
return OK;
}
-RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatImporter::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) {
PathAndType pat;
Error err = _get_path_and_type(p_path, pat);
@@ -128,7 +128,7 @@ RES ResourceFormatImporter::load(const String &p_path, const String &p_original_
return RES();
}
- RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_no_cache, r_error, p_use_sub_threads, r_progress);
+ RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress);
#ifdef TOOLS_ENABLED
if (res.is_valid()) {
@@ -192,6 +192,34 @@ bool ResourceFormatImporter::recognize_path(const String &p_path, const String &
return FileAccess::exists(p_path + ".import");
}
+Error ResourceFormatImporter::get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const {
+ r_order = 0;
+ r_importer = "";
+
+ r_can_threads = false;
+ Ref<ResourceImporter> importer;
+
+ if (FileAccess::exists(p_path + ".import")) {
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path, pat);
+
+ if (err == OK) {
+ importer = get_importer_by_name(pat.importer);
+ }
+ } else {
+ importer = get_importer_by_extension(p_path.get_extension().to_lower());
+ }
+
+ if (importer.is_valid()) {
+ r_order = importer->get_import_order();
+ r_importer = importer->get_importer_name();
+ r_can_threads = importer->can_import_threaded();
+ return OK;
+ } else {
+ return ERR_INVALID_PARAMETER;
+ }
+}
+
int ResourceFormatImporter::get_import_order(const String &p_path) const {
Ref<ResourceImporter> importer;
@@ -352,6 +380,12 @@ void ResourceFormatImporter::get_importers_for_extension(const String &p_extensi
}
}
+void ResourceFormatImporter::get_importers(List<Ref<ResourceImporter>> *r_importers) {
+ for (int i = 0; i < importers.size(); i++) {
+ r_importers->push_back(importers[i]);
+ }
+}
+
Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const String &p_extension) const {
Ref<ResourceImporter> importer;
float priority = 0;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index d31273e3cb..a14d6ba52c 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -57,7 +57,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
@@ -72,6 +72,8 @@ public:
virtual int get_import_order(const String &p_path) const;
+ Error get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const;
+
String get_internal_resource_path(const String &p_path) const;
void get_internal_resource_path_list(const String &p_path, List<String> *r_paths);
@@ -82,6 +84,7 @@ public:
Ref<ResourceImporter> get_importer_by_name(const String &p_name) const;
Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const;
void get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers);
+ void get_importers(List<Ref<ResourceImporter>> *r_importers);
bool are_import_settings_valid(const String &p_path) const;
String get_import_settings_hash() const;
@@ -114,6 +117,9 @@ public:
ImportOption() {}
};
+ virtual bool has_advanced_options() const { return false; }
+ virtual void show_advanced_options(const String &p_path) {}
+
virtual int get_preset_count() const { return 0; }
virtual String get_preset_name(int p_idx) const { return String(); }
@@ -122,6 +128,9 @@ public:
virtual String get_option_group_file() const { return String(); }
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) = 0;
+ virtual bool can_import_threaded() const { return true; }
+ virtual void import_threaded_begin() {}
+ virtual void import_threaded_end() {}
virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant>> &p_source_file_options, const Map<String, String> &p_base_paths) { return ERR_UNAVAILABLE; }
virtual bool are_import_settings_valid(const String &p_path) const { return true; }
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index d66511a39f..dcf71bb4a9 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -113,9 +113,9 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
}
-RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (get_script_instance() && get_script_instance()->has_method("load")) {
- Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads);
+ Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
if (res.get_type() == Variant::INT) {
if (r_error) {
@@ -164,7 +164,7 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<
void ResourceFormatLoader::_bind_methods() {
{
- MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"));
+ MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode"));
info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
ClassDB::add_virtual_method(get_class_static(), info);
}
@@ -174,11 +174,15 @@ void ResourceFormatLoader::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames")));
+
+ BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
}
///////////////////////////////////
-RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress) {
+RES 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) {
bool found = false;
// Try all loaders and pick the first match for the type hint
@@ -187,7 +191,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
continue;
}
found = true;
- RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_no_cache);
+ RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (res.is_null()) {
continue;
}
@@ -211,10 +215,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
load_task.loader_id = Thread::get_caller_id();
if (load_task.semaphore) {
- //this is an actual thread, so wait for Ok fom semaphore
+ //this is an actual thread, so wait for Ok from semaphore
thread_load_semaphore->wait(); //wait until its ok to start loading
}
- load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, false, &load_task.error, load_task.use_sub_threads, &load_task.progress);
+ load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
load_task.progress = 1.0; //it was fully loaded at this point, so force progress to 1.0
@@ -267,7 +271,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex->unlock();
}
-Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, const String &p_source_resource) {
+Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode, const String &p_source_resource) {
String local_path;
if (p_path.is_rel_path()) {
local_path = "res://" + p_path;
@@ -314,6 +318,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.local_path = local_path;
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_use_sub_threads;
{ //must check if resource is already loaded before attempting to load it in a thread
@@ -438,7 +443,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
ThreadLoadTask &load_task = thread_load_tasks[local_path];
- //semaphore still exists, meaning its still loading, request poll
+ //semaphore still exists, meaning it's still loading, request poll
Semaphore *semaphore = load_task.semaphore;
if (semaphore) {
load_task.poll_requests++;
@@ -447,7 +452,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
// As we got a semaphore, this means we are going to have to wait
// until the sub-resource is done loading
//
- // As this thread will become 'blocked' we should "echange" its
+ // As this thread will become 'blocked' we should "exchange" its
// active status with a waiting one, to ensure load continues.
//
// This ensures loading is never blocked and that is also within
@@ -501,7 +506,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
return resource;
}
-RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
+RES ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -513,7 +518,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
}
- if (!p_no_cache) {
+ if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
thread_load_mutex->lock();
//Is it already being loaded? poll until done
@@ -561,6 +566,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
load_task.local_path = local_path;
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode; //ignore
load_task.loader_id = Thread::get_caller_id();
thread_load_tasks[local_path] = load_task;
@@ -581,7 +587,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
print_verbose("Loading resource: " + path);
float p;
- RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error, false, &p);
+ RES res = _load(path, local_path, p_type_hint, p_cache_mode, r_error, false, &p);
if (res.is_null()) {
print_verbose("Failed loading resource: " + path);
@@ -966,11 +972,11 @@ void ResourceLoader::reload_translation_remaps() {
}
void ResourceLoader::load_translation_remaps() {
- if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index dbf6be46c5..914d988caa 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -38,11 +38,18 @@
class ResourceFormatLoader : public Reference {
GDCLASS(ResourceFormatLoader, Reference);
+public:
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
protected:
static void _bind_methods();
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
@@ -59,6 +66,8 @@ public:
virtual ~ResourceFormatLoader() {}
};
+VARIANT_ENUM_CAST(ResourceFormatLoader::CacheMode)
+
typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text);
typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type);
@@ -99,7 +108,7 @@ private:
friend class ResourceFormatImporter;
friend class ResourceInteractiveLoader;
//internal load function
- static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress);
+ static RES _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);
static ResourceLoadedCallback _loaded_callback;
@@ -114,6 +123,7 @@ private:
String type_hint;
float progress = 0.0;
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
Error error = OK;
RES resource;
bool xl_remapped = false;
@@ -136,11 +146,11 @@ private:
static float _dependency_get_progress(const String &p_path);
public:
- static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, const String &p_source_resource = String());
+ static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, const String &p_source_resource = String());
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
static RES load_threaded_get(const String &p_path, Error *r_error = nullptr);
- static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = nullptr);
+ static RES load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
static bool exists(const String &p_path, const String &p_type_hint = "");
static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions);
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 8407d55196..74154321b3 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -433,7 +433,7 @@ Error StreamPeerBuffer::put_data(const uint8_t *p_data, int p_bytes) {
}
uint8_t *w = data.ptrw();
- copymem(&w[pointer], p_data, p_bytes);
+ memcpy(&w[pointer], p_data, p_bytes);
pointer += p_bytes;
return OK;
@@ -466,7 +466,7 @@ Error StreamPeerBuffer::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_
}
const uint8_t *r = data.ptr();
- copymem(p_buffer, r + pointer, r_received);
+ memcpy(p_buffer, r + pointer, r_received);
pointer += r_received;
// FIXME: return what? OK or ERR_*
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index 760710a9eb..9906b9e4c3 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -67,21 +67,40 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint
peer_port = p_port;
}
-Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, uint16_t p_port) {
+Error StreamPeerTCP::bind(int p_port, const IP_Address &p_host) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
- ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
- Error err;
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
+ if (p_host.is_wildcard()) {
+ ip_type = IP::TYPE_ANY;
+ }
+ Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
+ if (err != OK) {
+ return err;
+ }
+ _sock->set_blocking_enabled(false);
+ return _sock->bind(p_host, p_port);
+}
- err = _sock->open(NetSocket::TYPE_TCP, ip_type);
- ERR_FAIL_COND_V(err != OK, FAILED);
+Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, int p_port) {
+ ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(status != STATUS_NONE, ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
- _sock->set_blocking_enabled(false);
+ if (!_sock->is_open()) {
+ IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
+ Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
+ if (err != OK) {
+ return err;
+ }
+ _sock->set_blocking_enabled(false);
+ }
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
- err = _sock->connect_to_host(p_host, p_port);
+ Error err = _sock->connect_to_host(p_host, p_port);
if (err == OK) {
status = STATUS_CONNECTED;
@@ -300,10 +319,16 @@ IP_Address StreamPeerTCP::get_connected_host() const {
return peer_host;
}
-uint16_t StreamPeerTCP::get_connected_port() const {
+int StreamPeerTCP::get_connected_port() const {
return peer_port;
}
+int StreamPeerTCP::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
IP_Address ip;
if (p_address.is_valid_ip_address()) {
@@ -319,11 +344,13 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
}
void StreamPeerTCP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("bind", "port", "host"), &StreamPeerTCP::bind, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &StreamPeerTCP::_connect);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &StreamPeerTCP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &StreamPeerTCP::get_local_port);
ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay);
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 10b90908d4..3bc7b252dc 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -65,10 +65,12 @@ protected:
public:
void accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port);
- Error connect_to_host(const IP_Address &p_host, uint16_t p_port);
+ Error bind(int p_port, const IP_Address &p_host);
+ Error connect_to_host(const IP_Address &p_host, int p_port);
bool is_connected_to_host() const;
IP_Address get_connected_host() const;
- uint16_t get_connected_port() const;
+ int get_connected_port() const;
+ int get_local_port() const;
void disconnect_from_host();
int get_available_bytes() const override;
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index 323d2bbd7f..348be66ba4 100644
--- a/core/io/tcp_server.cpp
+++ b/core/io/tcp_server.cpp
@@ -34,6 +34,7 @@ void TCP_Server::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCP_Server::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("is_connection_available"), &TCP_Server::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &TCP_Server::is_listening);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &TCP_Server::get_local_port);
ClassDB::bind_method(D_METHOD("take_connection"), &TCP_Server::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop);
}
@@ -42,6 +43,7 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -74,6 +76,12 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
return OK;
}
+int TCP_Server::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
bool TCP_Server::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index f06ddd2d99..58c04d87ec 100644
--- a/core/io/tcp_server.h
+++ b/core/io/tcp_server.h
@@ -49,6 +49,7 @@ protected:
public:
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
Ref<StreamPeerTCP> take_connection();
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index ce2c3eb1cd..9adf912224 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -194,7 +194,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
l = l.substr(1, l.length());
// Find final quote, ignoring escaped ones (\").
// The escape_next logic is necessary to properly parse things like \\"
- // where the blackslash is the one being escaped, not the quote.
+ // where the backslash is the one being escaped, not the quote.
int end_pos = -1;
bool escape_next = false;
for (int i = 0; i < l.length(); i++) {
@@ -277,7 +277,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
return translation;
}
-RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index a524972588..36d33fcac3 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -38,7 +38,7 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
static RES load_translation(FileAccess *f, Error *r_error = nullptr);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index f56fb431ef..99642f4af4 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -34,6 +34,7 @@ void UDPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll);
ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &UDPServer::get_local_port);
ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
@@ -90,6 +91,7 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -112,11 +114,15 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
stop();
return err;
}
- bind_address = p_bind_address;
- bind_port = p_port;
return OK;
}
+int UDPServer::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
bool UDPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
@@ -176,8 +182,6 @@ void UDPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
- bind_port = 0;
- bind_address = IP_Address();
List<Peer>::Element *E = peers.front();
while (E) {
E->get().peer->disconnect_shared_socket();
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index bbd2f951c9..298d4d4b63 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -53,21 +53,18 @@ protected:
};
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
- int bind_port = 0;
- IP_Address bind_address;
-
List<Peer> peers;
List<Peer> pending;
int max_pending_connections = 16;
Ref<NetSocket> _sock;
-
static void _bind_methods();
public:
void remove_peer(IP_Address p_ip, int p_port);
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
Error poll();
+ int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
void set_max_pending_connections(int p_max);
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 905be6089d..a1f8e79adc 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -36,63 +36,6 @@
VARIANT_ENUM_CAST(XMLParser::NodeType);
-static bool _equalsn(const char32_t *str1, const char32_t *str2, int len) {
- int i;
- for (i = 0; i < len && str1[i] && str2[i]; ++i) {
- if (str1[i] != str2[i]) {
- return false;
- }
- }
-
- // if one (or both) of the strings was smaller then they
- // are only equal if they have the same length
- return (i == len) || (str1[i] == 0 && str2[i] == 0);
-}
-
-String XMLParser::_replace_special_characters(const String &origstr) {
- int pos = origstr.find("&");
- int oldPos = 0;
-
- if (pos == -1) {
- return origstr;
- }
-
- String newstr;
-
- while (pos != -1 && pos < origstr.length() - 2) {
- // check if it is one of the special characters
-
- int specialChar = -1;
- for (int i = 0; i < (int)special_characters.size(); ++i) {
- const char32_t *p = &origstr[pos] + 1;
-
- if (_equalsn(&special_characters[i][1], p, special_characters[i].length() - 1)) {
- specialChar = i;
- break;
- }
- }
-
- if (specialChar != -1) {
- newstr += (origstr.substr(oldPos, pos - oldPos));
- newstr += (special_characters[specialChar][0]);
- pos += special_characters[specialChar].length();
- } else {
- newstr += (origstr.substr(oldPos, pos - oldPos + 1));
- pos += 1;
- }
-
- // find next &
- oldPos = pos;
- pos = origstr.find("&", pos);
- }
-
- if (oldPos < origstr.length() - 1) {
- newstr += (origstr.substr(oldPos, origstr.length() - oldPos));
- }
-
- return newstr;
-}
-
static inline bool _is_white_space(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
@@ -116,7 +59,7 @@ bool XMLParser::_set_text(char *start, char *end) {
// set current text to the parsed text, and replace xml special characters
String s = String::utf8(start, (int)(end - start));
- node_name = _replace_special_characters(s);
+ node_name = s.xml_unescape();
// current XML node type is text
node_type = NODE_TEXT;
@@ -292,7 +235,7 @@ void XMLParser::_parse_opening_xml_element() {
String s = String::utf8(attributeValueBegin,
(int)(attributeValueEnd - attributeValueBegin));
- attr.value = _replace_special_characters(s);
+ attr.value = s.xml_unescape();
attributes.push_back(attr);
} else {
// tag is closed directly
@@ -401,7 +344,7 @@ void XMLParser::_bind_methods() {
}
Error XMLParser::read() {
- // if not end reached, parse the node
+ // if end not reached, parse the node
if (P && (P - data) < (int64_t)length - 1 && *P != 0) {
_parse_current_node();
return OK;
@@ -490,7 +433,7 @@ Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
length = p_buffer.size();
data = memnew_arr(char, length + 1);
- copymem(data, p_buffer.ptr(), length);
+ memcpy(data, p_buffer.ptr(), length);
data[length] = 0;
P = data;
return OK;
@@ -555,11 +498,6 @@ int XMLParser::get_current_line() const {
}
XMLParser::XMLParser() {
- special_characters.push_back("&amp;");
- special_characters.push_back("<lt;");
- special_characters.push_back(">gt;");
- special_characters.push_back("\"quot;");
- special_characters.push_back("'apos;");
}
XMLParser::~XMLParser() {
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index 01af6a90ad..847edf958d 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -68,8 +68,6 @@ private:
char *data = nullptr;
char *P = nullptr;
uint64_t length = 0;
- void unescape(String &p_str);
- Vector<String> special_characters;
String node_name;
bool node_empty = false;
NodeType node_type = NODE_NONE;
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index 4b4a46e198..fe46868dd0 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -30,8 +30,6 @@
#include "zip_io.h"
-#include "core/os/copymem.h"
-
void *zipio_open(void *data, const char *p_fname, int mode) {
FileAccess *&f = *(FileAccess **)data;
@@ -103,7 +101,7 @@ int zipio_testerror(voidpf opaque, voidpf stream) {
voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) {
voidpf ptr = memalloc(items * size);
- zeromem(ptr, items * size);
+ memset(ptr, 0, items * size);
return ptr;
}
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index cbdd8a8c9f..50299902eb 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -31,7 +31,6 @@
#include "basis.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#define cofac(row1, col1, row2, col2) \
@@ -132,7 +131,7 @@ bool Basis::is_symmetric() const {
Basis Basis::diagonalize() {
//NOTE: only implemented for symmetric matrices
-//with the Jacobi iterative method method
+//with the Jacobi iterative method
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_symmetric(), Basis());
#endif
@@ -317,7 +316,7 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const {
// Multiplies the matrix from left by the rotation matrix: M -> R.M
// Note that this does *not* rotate the matrix itself.
//
-// The main use of Basis is as Transform.basis, which is used a the transformation matrix
+// The main use of Basis is as Transform.basis, which is used by the transformation matrix
// of 3D object. Rotate here refers to rotation of the object (which is R * (*this)),
// not the matrix itself (which is R * (*this) * R.transposed()).
Basis Basis::rotated(const Vector3 &p_axis, real_t p_phi) const {
@@ -881,7 +880,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
if ((Math::abs(elements[1][0] - elements[0][1]) < epsilon) && (Math::abs(elements[2][0] - elements[0][2]) < epsilon) && (Math::abs(elements[2][1] - elements[1][2]) < epsilon)) {
// singularity found
// first check for identity matrix which must have +1 for all terms
- // in leading diagonaland zero in other terms
+ // in leading diagonal and zero in other terms
if ((Math::abs(elements[1][0] + elements[0][1]) < epsilon2) && (Math::abs(elements[2][0] + elements[0][2]) < epsilon2) && (Math::abs(elements[2][1] + elements[1][2]) < epsilon2) && (Math::abs(elements[0][0] + elements[1][1] + elements[2][2] - 3) < epsilon2)) {
// this singularity is identity matrix so angle = 0
r_axis = Vector3(0, 1, 0);
diff --git a/core/math/color.cpp b/core/math/color.cpp
index e1b45cac9c..8affb07e8c 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -452,56 +452,9 @@ String Color::to_html(bool p_alpha) const {
}
Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
- p_h = Math::fmod(p_h * 360.0f, 360.0f);
- if (p_h < 0.0) {
- p_h += 360.0f;
- }
-
- const float h_ = p_h / 60.0f;
- const float c = p_v * p_s;
- const float x = c * (1.0f - Math::abs(Math::fmod(h_, 2.0f) - 1.0f));
- float r, g, b;
-
- switch ((int)h_) {
- case 0: {
- r = c;
- g = x;
- b = 0;
- } break;
- case 1: {
- r = x;
- g = c;
- b = 0;
- } break;
- case 2: {
- r = 0;
- g = c;
- b = x;
- } break;
- case 3: {
- r = 0;
- g = x;
- b = c;
- } break;
- case 4: {
- r = x;
- g = 0;
- b = c;
- } break;
- case 5: {
- r = c;
- g = 0;
- b = x;
- } break;
- default: {
- r = 0;
- g = 0;
- b = 0;
- } break;
- }
-
- const float m = p_v - c;
- return Color(m + r, m + g, m + b, p_a);
+ Color c;
+ c.set_hsv(p_h, p_s, p_v, p_a);
+ return c;
}
Color::operator String() const {
diff --git a/core/math/color.h b/core/math/color.h
index 5eb8b1119a..e404d80c8a 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -197,13 +197,13 @@ struct Color {
// For the binder.
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(r * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(g * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(b * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(a * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); }
_FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); }
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp
index 4639a52278..200095d8cb 100644
--- a/core/math/dynamic_bvh.cpp
+++ b/core/math/dynamic_bvh.cpp
@@ -61,7 +61,7 @@ DynamicBVH::Node *DynamicBVH::_create_node_with_volume(Node *p_parent, const Vol
void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
if (!bvh_root) {
bvh_root = p_leaf;
- p_leaf->parent = 0;
+ p_leaf->parent = nullptr;
} else {
if (!p_root->is_leaf()) {
do {
@@ -71,7 +71,7 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
} while (!p_root->is_leaf());
}
Node *prev = p_root->parent;
- Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), 0);
+ Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), nullptr);
if (prev) {
prev->childs[p_root->get_index_in_parent()] = node;
node->childs[0] = p_root;
@@ -85,7 +85,7 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
break;
}
node = prev;
- } while (0 != (prev = node->parent));
+ } while (nullptr != (prev = node->parent));
} else {
node->childs[0] = p_root;
p_root->parent = node;
@@ -98,8 +98,8 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
if (leaf == bvh_root) {
- bvh_root = 0;
- return (0);
+ bvh_root = nullptr;
+ return (nullptr);
} else {
Node *parent = leaf->parent;
Node *prev = parent->parent;
@@ -113,13 +113,14 @@ DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
if (pb.is_not_equal_to(prev->volume)) {
prev = prev->parent;
- } else
+ } else {
break;
+ }
}
return (prev ? prev : bvh_root);
} else {
bvh_root = sibling;
- sibling->parent = 0;
+ sibling->parent = nullptr;
_delete_node(parent);
return (bvh_root);
}
@@ -262,10 +263,11 @@ DynamicBVH::Node *DynamicBVH::_node_sort(Node *n, Node *&r) {
Node *s = p->childs[j];
Node *q = p->parent;
ERR_FAIL_COND_V(n != p->childs[i], nullptr);
- if (q)
+ if (q) {
q->childs[p->get_index_in_parent()] = n;
- else
+ } else {
r = n;
+ }
s->parent = n;
p->parent = n;
n->parent = q;
@@ -307,8 +309,9 @@ void DynamicBVH::optimize_top_down(int bu_threshold) {
}
void DynamicBVH::optimize_incremental(int passes) {
- if (passes < 0)
+ if (passes < 0) {
passes = total_leaves;
+ }
if (bvh_root && (passes > 0)) {
do {
Node *node = bvh_root;
@@ -345,8 +348,9 @@ void DynamicBVH::_update(Node *leaf, int lookahead) {
for (int i = 0; (i < lookahead) && root->parent; ++i) {
root = root->parent;
}
- } else
+ } else {
root = bvh_root;
+ }
}
_insert_leaf(root, leaf);
}
@@ -370,8 +374,9 @@ bool DynamicBVH::update(const ID &p_id, const AABB &p_box) {
for (int i = 0; (i < lkhd) && base->parent; ++i) {
base = base->parent;
}
- } else
+ } else {
base = bvh_root;
+ }
}
leaf->volume = volume;
_insert_leaf(base, leaf);
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index c71db2d24d..0b6286cd9d 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -87,14 +87,16 @@ private:
_FORCE_INLINE_ Volume merge(const Volume &b) const {
Volume r;
for (int i = 0; i < 3; ++i) {
- if (min[i] < b.min[i])
+ if (min[i] < b.min[i]) {
r.min[i] = min[i];
- else
+ } else {
r.min[i] = b.min[i];
- if (max[i] > b.max[i])
+ }
+ if (max[i] > b.max[i]) {
r.max[i] = max[i];
- else
+ } else {
r.max[i] = b.max[i];
+ }
}
return r;
}
@@ -202,10 +204,11 @@ private:
//
int count_leaves() const {
- if (is_internal())
+ if (is_internal()) {
return childs[0]->count_leaves() + childs[1]->count_leaves();
- else
+ } else {
return (1);
+ }
}
bool is_left_of_axis(const Vector3 &org, const Vector3 &axis) const {
@@ -254,31 +257,37 @@ private:
tymin = (bounds[raySign[1]].y - rayFrom.y) * rayInvDirection.y;
tymax = (bounds[1 - raySign[1]].y - rayFrom.y) * rayInvDirection.y;
- if ((tmin > tymax) || (tymin > tmax))
+ if ((tmin > tymax) || (tymin > tmax)) {
return false;
+ }
- if (tymin > tmin)
+ if (tymin > tmin) {
tmin = tymin;
+ }
- if (tymax < tmax)
+ if (tymax < tmax) {
tmax = tymax;
+ }
tzmin = (bounds[raySign[2]].z - rayFrom.z) * rayInvDirection.z;
tzmax = (bounds[1 - raySign[2]].z - rayFrom.z) * rayInvDirection.z;
- if ((tmin > tzmax) || (tzmin > tmax))
+ if ((tmin > tzmax) || (tzmin > tmax)) {
return false;
- if (tzmin > tmin)
+ }
+ if (tzmin > tmin) {
tmin = tzmin;
- if (tzmax < tmax)
+ }
+ if (tzmax < tmax) {
tmax = tzmax;
+ }
return ((tmin < lambda_max) && (tmax > lambda_min));
}
public:
// Methods
void clear();
- bool is_empty() const { return (0 == bvh_root); }
+ bool is_empty() const { return (nullptr == bvh_root); }
void optimize_bottom_up();
void optimize_top_down(int bu_threshold = 128);
void optimize_incremental(int passes);
@@ -334,7 +343,7 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
@@ -390,7 +399,7 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
@@ -447,7 +456,7 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 636ea601c7..f7ac44d321 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -978,7 +978,7 @@ Expression::ENode *Expression::_parse_expression() {
}
}
- /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+ /* Reduce the set of expressions and place them in an operator tree, respecting precedence */
while (expression.size() > 1) {
int next_op = -1;
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index beb0a8e405..20c316c322 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -169,7 +169,7 @@ Vector3 Face3::get_median_point() const {
}
real_t Face3::get_area() const {
- return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length();
+ return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5;
}
ClockDirection Face3::get_clock_dir() const {
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index 783750b9e6..7b2630b4ff 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -87,13 +87,17 @@ struct _AtlasWorkRectResult {
void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size) {
// Super simple, almost brute force scanline stacking fitter.
// It's pretty basic for now, but it tries to make sure that the aspect ratio of the
- // resulting atlas is somehow square. This is necessary because video cards have limits.
- // On texture size (usually 2048 or 4096), so the more square a texture, the more chances.
- // It will work in every hardware.
+ // resulting atlas is somehow square. This is necessary because video cards have limits
+ // on texture size (usually 2048 or 4096), so the squarer a texture, the more the chances
+ // that it will work in every hardware.
// For example, it will prioritize a 1024x1024 atlas (works everywhere) instead of a
// 256x8192 atlas (won't work anywhere).
ERR_FAIL_COND(p_rects.size() == 0);
+ for (int i = 0; i < p_rects.size(); i++) {
+ ERR_FAIL_COND(p_rects[i].width <= 0);
+ ERR_FAIL_COND(p_rects[i].height <= 0);
+ }
Vector<_AtlasWorkRect> wrects;
wrects.resize(p_rects.size());
@@ -354,7 +358,7 @@ Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size
Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
Vector<stbrp_node> nodes;
nodes.resize(p_atlas_size.width);
- zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size());
+ memset(nodes.ptrw(), 0, sizeof(stbrp_node) * nodes.size());
stbrp_context context;
stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index a4a7463bfd..6628b760e0 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -775,6 +775,8 @@ Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
}
Vector<Plane> Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
const double sides_step = Math_TAU / p_sides;
@@ -796,6 +798,8 @@ Vector<Plane> Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height
}
Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
Vector3 axis;
@@ -827,6 +831,8 @@ Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p
}
Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
Vector3 axis;
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 825817af5e..4ef9b4dbe6 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -252,27 +252,34 @@ public:
return true;
}
- static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr) {
+ static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
if (rel_l < CMP_EPSILON) {
return false; // Both points are the same.
}
+ ERR_FAIL_COND_V(p_cylinder_axis < 0, false);
+ ERR_FAIL_COND_V(p_cylinder_axis > 2, false);
+ Vector3 cylinder_axis;
+ cylinder_axis[p_cylinder_axis] = 1.0;
+
// First check if they are parallel.
Vector3 normal = (rel / rel_l);
- Vector3 crs = normal.cross(Vector3(0, 0, 1));
+ Vector3 crs = normal.cross(cylinder_axis);
real_t crs_l = crs.length();
- Vector3 z_dir;
+ Vector3 axis_dir;
if (crs_l < CMP_EPSILON) {
- z_dir = Vector3(1, 0, 0); // Any x/y vector OK.
+ Vector3 side_axis;
+ side_axis[(p_cylinder_axis + 1) % 3] = 1.0; // Any side axis OK.
+ axis_dir = side_axis;
} else {
- z_dir = crs / crs_l;
+ axis_dir = crs / crs_l;
}
- real_t dist = z_dir.dot(p_from);
+ real_t dist = axis_dir.dot(p_from);
if (dist >= p_radius) {
return false; // Too far away.
@@ -285,10 +292,10 @@ public:
}
Size2 size(Math::sqrt(w2), p_height * 0.5);
- Vector3 x_dir = z_dir.cross(Vector3(0, 0, 1)).normalized();
+ Vector3 side_dir = axis_dir.cross(cylinder_axis).normalized();
- Vector2 from2D(x_dir.dot(p_from), p_from.z);
- Vector2 to2D(x_dir.dot(p_to), p_to.z);
+ Vector2 from2D(side_dir.dot(p_from), p_from[p_cylinder_axis]);
+ Vector2 to2D(side_dir.dot(p_to), p_to[p_cylinder_axis]);
real_t min = 0, max = 1;
@@ -335,10 +342,12 @@ public:
Vector3 res_normal = result;
if (axis == 0) {
- res_normal.z = 0;
+ res_normal[p_cylinder_axis] = 0;
} else {
- res_normal.x = 0;
- res_normal.y = 0;
+ int axis_side = (p_cylinder_axis + 1) % 3;
+ res_normal[axis_side] = 0;
+ axis_side = (axis_side + 1) % 3;
+ res_normal[axis_side] = 0;
}
res_normal.normalize();
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 267f6a4fe2..8cf13efdb6 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -103,6 +103,9 @@ public:
static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); }
static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); }
+ static _ALWAYS_INLINE_ double log2(double p_x) { return ::log2(p_x); }
+ static _ALWAYS_INLINE_ float log2(float p_x) { return ::log2f(p_x); }
+
static _ALWAYS_INLINE_ double exp(double p_x) { return ::exp(p_x); }
static _ALWAYS_INLINE_ float exp(float p_x) { return ::expf(p_x); }
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index a9a21a1ba3..6f13e04027 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -55,10 +55,13 @@ Vector3 Quat::get_euler_yxz() const {
}
void Quat::operator*=(const Quat &p_q) {
- x = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
- y = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
- z = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
+ real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
+ real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
+ real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z;
+ x = xx;
+ y = yy;
+ z = zz;
}
Quat Quat::operator*(const Quat &p_q) const {
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index ad28967d7a..fe18cc3d41 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -268,7 +268,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
for (Map<Edge, FaceConnect>::Element *E = lit_edges.front(); E; E = E->next()) {
FaceConnect &fc = E->get();
if (fc.left && fc.right) {
- continue; //edge is uninteresting, not on horizont
+ continue; //edge is uninteresting, not on horizon
}
//create new face!
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index 9609620469..1152c4e834 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -39,7 +39,7 @@ RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
}
void RandomPCG::randomize() {
- seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64);
+ seed((OS::get_singleton()->get_unix_time() + OS::get_singleton()->get_ticks_usec()) * pcg.state + PCG_DEFAULT_INC_64);
}
double RandomPCG::random(double p_from, double p_to) {
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index fab5d124fa..d4d7ff6d28 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -31,7 +31,6 @@
#include "transform.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
void Transform::affine_invert() {
diff --git a/core/math/transform.h b/core/math/transform.h
index 60da6f5593..1c05dbe554 100644
--- a/core/math/transform.h
+++ b/core/math/transform.h
@@ -51,8 +51,8 @@ public:
void rotate(const Vector3 &p_axis, real_t p_phi);
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
- void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up);
- Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const;
+ void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
+ Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
void scale(const Vector3 &p_scale);
Transform scaled(const Vector3 &p_scale) const;
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index 0047c0705d..fa1588dbc5 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -97,7 +97,7 @@ bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, in
// It can happen that the triangulation ends up with three aligned vertices to deal with.
// In this scenario, making the check below strict may reject the possibility of
- // forming a last triangle with these aligned vertices, preventing the triangulatiom
+ // forming a last triangle with these aligned vertices, preventing the triangulation
// from completing.
// To avoid that we allow zero-area triangles if all else failed.
float threshold = relaxed ? -CMP_EPSILON : CMP_EPSILON;
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 6b4ff3f9a8..377581bb45 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -110,6 +110,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const;
_FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const;
+ _FORCE_INLINE_ real_t signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const;
_FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const;
_FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const;
@@ -230,6 +231,13 @@ real_t Vector3::angle_to(const Vector3 &p_to) const {
return Math::atan2(cross(p_to).length(), dot(p_to));
}
+real_t Vector3::signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const {
+ Vector3 cross_to = cross(p_to);
+ real_t unsigned_angle = Math::atan2(cross_to.length(), dot(p_to));
+ real_t sign = cross_to.dot(p_axis);
+ return (sign < 0) ? -unsigned_angle : unsigned_angle;
+}
+
Vector3 Vector3::direction_to(const Vector3 &p_to) const {
Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z);
ret.normalize();
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 115797a00c..8ba01be4e4 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -32,7 +32,6 @@
#define CALLABLE_METHOD_POINTER_H
#include "core/object/object.h"
-#include "core/os/copymem.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/simple_type.h"
#include "core/variant/binder_common.h"
@@ -98,7 +97,7 @@ public:
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
@@ -153,7 +152,7 @@ public:
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
@@ -208,7 +207,7 @@ public:
}
CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 375ad8fae1..fb7eb42738 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1095,6 +1095,8 @@ bool ClassDB::get_property_info(StringName p_class, StringName p_property, Prope
}
bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) {
+ ERR_FAIL_NULL_V(p_object, false);
+
ClassInfo *type = classes.getptr(p_object->get_class_name());
ClassInfo *check = type;
while (check) {
@@ -1142,6 +1144,8 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
}
bool ClassDB::get_property(Object *p_object, const StringName &p_property, Variant &r_value) {
+ ERR_FAIL_NULL_V(p_object, false);
+
ClassInfo *type = classes.getptr(p_object->get_class_name());
ClassInfo *check = type;
while (check) {
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 7cf4f8d4e8..7030ae201b 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -42,6 +42,7 @@ enum MethodFlags {
METHOD_FLAG_VIRTUAL = 32,
METHOD_FLAG_FROM_SCRIPT = 64,
METHOD_FLAG_VARARG = 128,
+ METHOD_FLAG_STATIC = 256,
METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL,
};
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 171bc4dc2c..413f917518 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -596,7 +596,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
- if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
+ if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
if (!metadata.is_empty()) {
@@ -808,21 +808,6 @@ String Object::to_string() {
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
-void Object::_changed_callback(Object *p_changed, const char *p_prop) {
-}
-
-void Object::add_change_receptor(Object *p_receptor) {
- change_receptors.insert(p_receptor);
-}
-
-void Object::remove_change_receptor(Object *p_receptor) {
- change_receptors.erase(p_receptor);
-}
-
-void Object::property_list_changed_notify() {
- _change_notify();
-}
-
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
@@ -856,7 +841,7 @@ void Object::set_script(const Variant &p_script) {
}
}
- _change_notify(); //scripts may add variables, so refresh is desired
+ notify_property_list_changed(); //scripts may add variables, so refresh is desired
emit_signal(CoreStringNames::get_singleton()->script_changed);
}
@@ -1496,6 +1481,10 @@ void Object::clear_internal_resource_paths() {
}
}
+void Object::notify_property_list_changed() {
+ emit_signal(CoreStringNames::get_singleton()->property_list_changed);
+}
+
void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class);
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
@@ -1562,7 +1551,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
- ClassDB::bind_method(D_METHOD("property_list_changed_notify"), &Object::property_list_changed_notify);
+ ClassDB::bind_method(D_METHOD("notify_property_list_changed"), &Object::notify_property_list_changed);
ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
@@ -1574,6 +1563,7 @@ void Object::_bind_methods() {
ClassDB::add_virtual_method("Object", MethodInfo("free"), false);
ADD_SIGNAL(MethodInfo("script_changed"));
+ ADD_SIGNAL(MethodInfo("property_list_changed"));
BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
@@ -1681,7 +1671,7 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName>
for (int i = 1; i < p_path.size(); i++) {
if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) {
- // We cannot be sure about the type of properties this types can have
+ // We cannot be sure about the type of properties this type can have
if (r_valid) {
*r_valid = false;
}
@@ -1729,15 +1719,15 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr);
#endif
- //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of syncro
+ //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync
//just return the same pointer.
//if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it
- //as it should not really affect performance much (won't be called too often), as in far most caes the condition below will be false afterwards
+ //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards
if (!_script_instance_bindings[p_script_language_index]) {
void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
if (script_data) {
- atomic_increment(&instance_binding_count);
+ instance_binding_count.increment();
_script_instance_bindings[p_script_language_index] = script_data;
}
}
diff --git a/core/object/object.h b/core/object/object.h
index 7e460462cf..448a33d3bc 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -37,6 +37,7 @@
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
#include "core/templates/vmap.h"
#include "core/variant/callable_bind.h"
@@ -65,8 +66,10 @@ enum PropertyHint {
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
PROPERTY_HINT_LAYERS_2D_PHYSICS,
+ PROPERTY_HINT_LAYERS_2D_NAVIGATION,
PROPERTY_HINT_LAYERS_3D_RENDER,
PROPERTY_HINT_LAYERS_3D_PHYSICS,
+ PROPERTY_HINT_LAYERS_3D_NAVIGATION,
PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
PROPERTY_HINT_DIR, ///< a directory path must be passed
PROPERTY_HINT_GLOBAL_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
@@ -125,6 +128,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player
PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor.
+ PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 28, //for project or editor settings, show when basic settings are selected
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,
@@ -454,7 +458,6 @@ private:
#endif
bool _block_signals = false;
int _predelete_ok = 0;
- Set<Object *> change_receptors;
ObjectID _instance_id;
bool _predelete();
void _postinitialize();
@@ -486,7 +489,7 @@ private:
friend class Reference;
bool type_is_reference = false;
- uint32_t instance_binding_count = 0;
+ SafeNumeric<uint32_t> instance_binding_count;
void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
Object(bool p_reference);
@@ -523,9 +526,6 @@ protected:
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
- void property_list_changed_notify();
- virtual void _changed_callback(Object *p_changed, const char *p_prop);
-
//Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
//void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
@@ -555,16 +555,8 @@ public: //should be protected, but bug in clang++
_FORCE_INLINE_ static void register_custom_data_to_otdb() {}
public:
-#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ void _change_notify(const char *p_property = "") {
- _edited = true;
- for (Set<Object *>::Element *E = change_receptors.front(); E; E = E->next()) {
- ((Object *)(E->get()))->_changed_callback(this, p_property);
- }
- }
-#else
- _FORCE_INLINE_ void _change_notify(const char *p_what = "") {}
-#endif
+ void notify_property_list_changed();
+
static void *get_class_ptr_static() {
static int ptr;
return &ptr;
@@ -574,10 +566,6 @@ public:
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
- // this is used for editors
- void add_change_receptor(Object *p_receptor);
- void remove_change_receptor(Object *p_receptor);
-
template <class T>
static T *cast_to(Object *p_object) {
#ifndef NO_SAFE_CAST
diff --git a/core/object/reference.cpp b/core/object/reference.cpp
index 71a52a9ba5..22e4e8a336 100644
--- a/core/object/reference.cpp
+++ b/core/object/reference.cpp
@@ -62,7 +62,7 @@ bool Reference::reference() {
if (get_script_instance()) {
get_script_instance()->refcount_incremented();
}
- if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+ if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
@@ -83,7 +83,7 @@ bool Reference::unreference() {
bool script_ret = get_script_instance()->refcount_decremented();
die = die && script_ret;
}
- if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+ if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index c3f109a147..42fb0a0caf 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -275,6 +275,14 @@ void ScriptServer::save_global_classes() {
gcarr.push_back(d);
}
+ Array old;
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ }
+ if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
+ return;
+ }
+
if (gcarr.is_empty()) {
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
ProjectSettings::get_singleton()->clear("_global_script_classes");
@@ -515,7 +523,7 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c
}
if (owner && owner->get_script_instance() == this) {
- owner->_change_notify();
+ owner->notify_property_list_changed();
}
//change notify
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 3b1165b8f6..e8735e335c 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -532,7 +532,7 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count);
ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action);
- ClassDB::bind_method(D_METHOD("get_action_name"), &UndoRedo::get_action_name);
+ ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name);
ClassDB::bind_method(D_METHOD("clear_history", "increase_version"), &UndoRedo::clear_history, DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name);
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index fb9da9fbed..b7c3a17ba9 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -170,7 +170,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
curpath = curpath.plus_file(subdirs[i]);
Error err = make_dir(curpath);
if (err != OK && err != ERR_ALREADY_EXISTS) {
- ERR_FAIL_V(err);
+ ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
}
}
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index c49c4cc4b8..7f0bcd372d 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -84,6 +84,8 @@ public:
virtual bool file_exists(String p_file) = 0;
virtual bool dir_exists(String p_dir) = 0;
+ virtual bool is_readable(String p_dir) { return true; };
+ virtual bool is_writable(String p_dir) { return true; };
static bool exists(String p_dir);
virtual size_t get_space_left() = 0;
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 5a3df88619..ad234c2d49 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -368,6 +368,8 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
}
int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
int i = 0;
for (i = 0; i < p_length && !eof_reached(); i++) {
p_dst[i] = get_8();
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 3ef70e786f..f6fe5fc070 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -45,7 +45,7 @@ enum {
SPKEY = (1 << 24)
};
-enum KeyList {
+enum Key {
/* CURSOR/FUNCTION/BROWSER/MULTIMEDIA/MISC KEYS */
KEY_ESCAPE = SPKEY | 0x01,
KEY_TAB = SPKEY | 0x02,
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 14808c2ce6..a756c1d5dd 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -31,7 +31,6 @@
#include "memory.h"
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/templates/safe_refcount.h"
#include <stdio.h>
@@ -60,11 +59,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
#endif
#ifdef DEBUG_ENABLED
-uint64_t Memory::mem_usage = 0;
-uint64_t Memory::max_usage = 0;
+SafeNumeric<uint64_t> Memory::mem_usage;
+SafeNumeric<uint64_t> Memory::max_usage;
#endif
-uint64_t Memory::alloc_count = 0;
+SafeNumeric<uint64_t> Memory::alloc_count;
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
@@ -77,7 +76,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
ERR_FAIL_COND_V(!mem, nullptr);
- atomic_increment(&alloc_count);
+ alloc_count.increment();
if (prepad) {
uint64_t *s = (uint64_t *)mem;
@@ -86,8 +85,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
uint8_t *s8 = (uint8_t *)mem;
#ifdef DEBUG_ENABLED
- atomic_add(&mem_usage, p_bytes);
- atomic_exchange_if_greater(&max_usage, mem_usage);
+ uint64_t new_mem_usage = mem_usage.add(p_bytes);
+ max_usage.exchange_if_greater(new_mem_usage);
#endif
return s8 + PAD_ALIGN;
} else {
@@ -114,10 +113,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
if (p_bytes > *s) {
- atomic_add(&mem_usage, p_bytes - *s);
- atomic_exchange_if_greater(&max_usage, mem_usage);
+ uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
+ max_usage.exchange_if_greater(new_mem_usage);
} else {
- atomic_sub(&mem_usage, *s - p_bytes);
+ mem_usage.sub(*s - p_bytes);
}
#endif
@@ -156,14 +155,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
bool prepad = p_pad_align;
#endif
- atomic_decrement(&alloc_count);
+ alloc_count.decrement();
if (prepad) {
mem -= PAD_ALIGN;
#ifdef DEBUG_ENABLED
uint64_t *s = (uint64_t *)mem;
- atomic_sub(&mem_usage, *s);
+ mem_usage.sub(*s);
#endif
free(mem);
@@ -178,7 +177,7 @@ uint64_t Memory::get_mem_available() {
uint64_t Memory::get_mem_usage() {
#ifdef DEBUG_ENABLED
- return mem_usage;
+ return mem_usage.get();
#else
return 0;
#endif
@@ -186,7 +185,7 @@ uint64_t Memory::get_mem_usage() {
uint64_t Memory::get_mem_max_usage() {
#ifdef DEBUG_ENABLED
- return max_usage;
+ return max_usage.get();
#else
return 0;
#endif
diff --git a/core/os/memory.h b/core/os/memory.h
index c2ae3f4ae7..10e678103d 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -43,11 +43,11 @@
class Memory {
Memory();
#ifdef DEBUG_ENABLED
- static uint64_t mem_usage;
- static uint64_t max_usage;
+ static SafeNumeric<uint64_t> mem_usage;
+ static SafeNumeric<uint64_t> max_usage;
#endif
- static uint64_t alloc_count;
+ static SafeNumeric<uint64_t> alloc_count;
public:
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 182bab4058..ca1b798e11 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -106,10 +106,18 @@ void OS::add_logger(Logger *p_logger) {
}
void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) {
+ if (!_stderr_enabled) {
+ return;
+ }
+
_logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
}
void OS::print(const char *p_format, ...) {
+ if (!_stdout_enabled) {
+ return;
+ }
+
va_list argp;
va_start(argp, p_format);
@@ -119,6 +127,10 @@ void OS::print(const char *p_format, ...) {
}
void OS::printerr(const char *p_format, ...) {
+ if (!_stderr_enabled) {
+ return;
+ }
+
va_list argp;
va_start(argp, p_format);
@@ -163,6 +175,22 @@ bool OS::is_stdout_debug_enabled() const {
return _debug_stdout;
}
+bool OS::is_stdout_enabled() const {
+ return _stdout_enabled;
+}
+
+bool OS::is_stderr_enabled() const {
+ return _stderr_enabled;
+}
+
+void OS::set_stdout_enabled(bool p_enabled) {
+ _stdout_enabled = p_enabled;
+}
+
+void OS::set_stderr_enabled(bool p_enabled) {
+ _stderr_enabled = p_enabled;
+}
+
void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
diff --git a/core/os/os.h b/core/os/os.h
index e02ce7d5ec..7198607237 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -40,6 +40,7 @@
#include "core/templates/vector.h"
#include <stdarg.h>
+#include <stdlib.h>
class OS {
static OS *singleton;
@@ -53,12 +54,14 @@ class OS {
bool _debug_stdout = false;
String _local_clipboard;
bool _no_window = false;
- int _exit_code = 0;
+ int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
int _orientation;
bool _allow_hidpi = false;
bool _allow_layered = false;
bool _use_vsync;
bool _vsync_via_compositor;
+ bool _stdout_enabled = true;
+ bool _stderr_enabled = true;
char *last_error;
@@ -149,11 +152,6 @@ public:
bool is_layered_allowed() const { return _allow_layered; }
bool is_hidpi_allowed() const { return _allow_hidpi; }
- virtual int get_tablet_driver_count() const { return 0; };
- virtual String get_tablet_driver_name(int p_driver) const { return ""; };
- virtual String get_current_tablet_driver() const { return ""; };
- virtual void set_current_tablet_driver(const String &p_driver){};
-
void ensure_user_data_dir();
virtual MainLoop *get_main_loop() const = 0;
@@ -223,6 +221,11 @@ public:
bool is_stdout_verbose() const;
bool is_stdout_debug_enabled() const;
+ bool is_stdout_enabled() const;
+ bool is_stderr_enabled() const;
+ void set_stdout_enabled(bool p_enabled);
+ void set_stderr_enabled(bool p_enabled);
+
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index b538ca0c96..74e9c24e04 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -31,7 +31,6 @@
#include "pool_allocator.h"
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -42,7 +41,7 @@
do { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
void *_src = &((unsigned char *)pool)[(m_entry).pos]; \
- movemem(_dst, _src, aligned((m_entry).len)); \
+ memmove(_dst, _src, aligned((m_entry).len)); \
(m_entry).pos = m_to_pos; \
} while (0);
@@ -136,7 +135,7 @@ void PoolAllocator::compact_up(int p_from) {
for (int i = entry_count - 1; i >= p_from; i--) {
Entry &entry = entry_array[entry_indices[i]];
- /* determine hole size to nextious entry */
+ /* determine hole size for next entry */
int hole_size = next_entry_end_pos - (entry.pos + aligned(entry.len));
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index 936e5d5500..73e31bdb3d 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -34,14 +34,20 @@
#if !defined(NO_THREADS)
+#include "core/templates/safe_refcount.h"
+
Error (*Thread::set_name_func)(const String &) = nullptr;
void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
void (*Thread::init_func)() = nullptr;
void (*Thread::term_func)() = nullptr;
-Thread::ID Thread::main_thread_id = 1;
-Thread::ID Thread::last_thread_id = 1;
-thread_local Thread::ID Thread::caller_id = 1;
+uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
+ static std::hash<std::thread::id> hasher;
+ return hasher(p_t);
+}
+
+Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id());
+thread_local Thread::ID Thread::caller_id = 0;
void Thread::_set_platform_funcs(
Error (*p_set_name_func)(const String &),
@@ -55,7 +61,7 @@ void Thread::_set_platform_funcs(
}
void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) {
- Thread::caller_id = p_self->id;
+ Thread::caller_id = _thread_id_hash(p_self->thread.get_id());
if (set_priority_func) {
set_priority_func(p_settings.priority);
}
@@ -71,7 +77,7 @@ void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_cal
}
void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) {
- if (id != 0) {
+ if (id != _thread_id_hash(std::thread::id())) {
#ifdef DEBUG_ENABLED
WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
#endif
@@ -79,21 +85,22 @@ void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_
std::thread empty_thread;
thread.swap(empty_thread);
}
- id = atomic_increment(&last_thread_id);
std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user);
thread.swap(new_thread);
+ id = _thread_id_hash(thread.get_id());
}
bool Thread::is_started() const {
- return id != 0;
+ return id != _thread_id_hash(std::thread::id());
}
void Thread::wait_to_finish() {
- if (id != 0) {
+ if (id != _thread_id_hash(std::thread::id())) {
+ ERR_FAIL_COND_MSG(id == get_caller_id(), "A Thread can't wait for itself to finish.");
thread.join();
std::thread empty_thread;
thread.swap(empty_thread);
- id = 0;
+ id = _thread_id_hash(std::thread::id());
}
}
@@ -105,8 +112,12 @@ Error Thread::set_name(const String &p_name) {
return ERR_UNAVAILABLE;
}
+Thread::Thread() {
+ caller_id = _thread_id_hash(std::this_thread::get_id());
+}
+
Thread::~Thread() {
- if (id != 0) {
+ if (id != _thread_id_hash(std::thread::id())) {
#ifdef DEBUG_ENABLED
WARN_PRINT("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
#endif
diff --git a/core/os/thread.h b/core/os/thread.h
index b5449d2ed6..17ac82c650 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -34,6 +34,7 @@
#include "core/typedefs.h"
#if !defined(NO_THREADS)
+#include "core/templates/safe_refcount.h"
#include <thread>
#endif
@@ -61,9 +62,10 @@ private:
friend class Main;
static ID main_thread_id;
- static ID last_thread_id;
- ID id = 0;
+ static uint64_t _thread_id_hash(const std::thread::id &p_t);
+
+ ID id = _thread_id_hash(std::thread::id());
static thread_local ID caller_id;
std::thread thread;
@@ -96,6 +98,7 @@ public:
///< waits until thread is finished, and deallocates it.
void wait_to_finish();
+ Thread();
~Thread();
#else
_FORCE_INLINE_ ID get_id() const { return 0; }
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
index 9538ac5957..fec6473589 100644
--- a/core/os/threaded_array_processor.h
+++ b/core/os/threaded_array_processor.h
@@ -40,7 +40,7 @@
template <class C, class U>
struct ThreadArrayProcessData {
uint32_t elements;
- uint32_t index;
+ SafeNumeric<uint32_t> index;
C *instance;
U userdata;
void (C::*method)(uint32_t, U);
@@ -56,7 +56,7 @@ template <class T>
void process_array_thread(void *ud) {
T &data = *(T *)ud;
while (true) {
- uint32_t index = atomic_increment(&data.index);
+ uint32_t index = data.index.increment();
if (index >= data.elements) {
break;
}
@@ -70,9 +70,9 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
data.method = p_method;
data.instance = p_instance;
data.userdata = p_userdata;
- data.index = 0;
+ data.index.set(0);
data.elements = p_elements;
- data.process(data.index); //process first, let threads increment for next
+ data.process(0); //process first, let threads increment for next
int thread_count = OS::get_singleton()->get_processor_count();
Thread *threads = memnew_arr(Thread, thread_count);
@@ -95,7 +95,7 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
data.method = p_method;
data.instance = p_instance;
data.userdata = p_userdata;
- data.index = 0;
+ data.index.set(0);
data.elements = p_elements;
for (uint32_t i = 0; i < p_elements; i++) {
data.process(i);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index b58abc81d1..d6a5eff10d 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -68,7 +68,7 @@
#include "core/object/class_db.h"
#include "core/object/undo_redo.h"
#include "core/os/main_loop.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
static Ref<ResourceFormatSaverBinary> resource_saver_binary;
@@ -183,7 +183,7 @@ void register_core_types() {
ClassDB::register_class<MultiplayerAPI>();
ClassDB::register_class<MainLoop>();
ClassDB::register_class<Translation>();
- ClassDB::register_class<PHashTranslation>();
+ ClassDB::register_class<OptimizedTranslation>();
ClassDB::register_class<UndoRedo>();
ClassDB::register_class<HTTPClient>();
ClassDB::register_class<TriangleMesh>();
diff --git a/core/string/node_path.h b/core/string/node_path.h
index 26e15636d9..a277ab26fa 100644
--- a/core/string/node_path.h
+++ b/core/string/node_path.h
@@ -66,8 +66,6 @@ public:
void prepend_period();
- NodePath get_parent() const;
-
_FORCE_INLINE_ uint32_t hash() const {
if (!data) {
return 0;
diff --git a/core/string/compressed_translation.cpp b/core/string/optimized_translation.cpp
index ad90924293..53d0a8924d 100644
--- a/core/string/compressed_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* compressed_translation.cpp */
+/* optimized_translation.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "compressed_translation.h"
+#include "optimized_translation.h"
#include "core/templates/pair.h"
@@ -36,15 +36,15 @@ extern "C" {
#include "thirdparty/misc/smaz.h"
}
-struct _PHashTranslationCmp {
+struct CompressedString {
int orig_len;
CharString compressed;
int offset;
};
-void PHashTranslation::generate(const Ref<Translation> &p_from) {
+void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
// This method compresses a Translation instance.
- // Right now it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
+ // Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
#ifdef TOOLS_ENABLED
List<StringName> keys;
p_from->get_message_list(&keys);
@@ -54,7 +54,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
Vector<Vector<Pair<int, CharString>>> buckets;
Vector<Map<uint32_t, int>> table;
Vector<uint32_t> hfunc_table;
- Vector<_PHashTranslationCmp> compressed;
+ Vector<CompressedString> compressed;
table.resize(size);
hfunc_table.resize(size);
@@ -76,7 +76,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
//compress string
CharString src_s = p_from->get_message(E->get()).operator String().utf8();
- _PHashTranslationCmp ps;
+ CompressedString ps;
ps.orig_len = src_s.size();
ps.offset = total_compression_size;
@@ -182,7 +182,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
#endif
}
-bool PHashTranslation::_set(const StringName &p_name, const Variant &p_value) {
+bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name.operator String();
if (name == "hash_table") {
hash_table = p_value;
@@ -199,7 +199,7 @@ bool PHashTranslation::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
-bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const {
+bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name.operator String();
if (name == "hash_table") {
r_ret = hash_table;
@@ -214,8 +214,8 @@ bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-StringName PHashTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
- // p_context passed in is ignore. The use of context is not yet supported in PHashTranslation.
+StringName OptimizedTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ // p_context passed in is ignore. The use of context is not yet supported in OptimizedTranslation.
int htsize = hash_table.size();
@@ -271,18 +271,18 @@ StringName PHashTranslation::get_message(const StringName &p_src_text, const Str
}
}
-StringName PHashTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
- // The use of plurals translation is not yet supported in PHashTranslation.
+StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ // The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
}
-void PHashTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
+void OptimizedTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table"));
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table"));
p_list->push_back(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "strings"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "load_from", PROPERTY_HINT_RESOURCE_TYPE, "Translation", PROPERTY_USAGE_EDITOR));
}
-void PHashTranslation::_bind_methods() {
- ClassDB::bind_method(D_METHOD("generate", "from"), &PHashTranslation::generate);
+void OptimizedTranslation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("generate", "from"), &OptimizedTranslation::generate);
}
diff --git a/core/string/compressed_translation.h b/core/string/optimized_translation.h
index 0abb770178..bccf932383 100644
--- a/core/string/compressed_translation.h
+++ b/core/string/optimized_translation.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* compressed_translation.h */
+/* optimized_translation.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COMPRESSED_TRANSLATION_H
-#define COMPRESSED_TRANSLATION_H
+#ifndef OPTIMIZED_TRANSLATION_H
+#define OPTIMIZED_TRANSLATION_H
#include "core/string/translation.h"
-class PHashTranslation : public Translation {
- GDCLASS(PHashTranslation, Translation);
+class OptimizedTranslation : public Translation {
+ GDCLASS(OptimizedTranslation, Translation);
//this translation uses a sort of modified perfect hash algorithm
//it requires hashing strings twice and then does a binary search,
@@ -83,7 +83,7 @@ public:
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
void generate(const Ref<Translation> &p_from);
- PHashTranslation() {}
+ OptimizedTranslation() {}
};
-#endif // COMPRESSED_TRANSLATION_H
+#endif // OPTIMIZED_TRANSLATION_H
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 5337d46aa3..153f0190fd 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -39,13 +39,14 @@
#include "main/main.h"
#endif
-// ISO 639-1 language codes, with the addition of glibc locales with their
-// regional identifiers. This list must match the language names (in English)
-// of locale_names.
+// ISO 639-1 language codes (and a couple of three-letter ISO 639-2 codes),
+// with the addition of glibc locales with their regional identifiers.
+// This list must match the language names (in English) of locale_names.
//
// References:
// - https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
// - https://lh.2xlibre.net/locales/
+// - https://iso639-3.sil.org/
static const char *locale_list[] = {
"aa", // Afar
@@ -100,6 +101,7 @@ static const char *locale_list[] = {
"bo", // Tibetan
"bo_CN", // Tibetan (China)
"bo_IN", // Tibetan (India)
+ "br", // Breton
"br_FR", // Breton (France)
"brx_IN", // Bodo (India)
"bs_BA", // Bosnian (Bosnia and Herzegovina)
@@ -201,6 +203,7 @@ static const char *locale_list[] = {
"gd_GB", // Scottish Gaelic (United Kingdom)
"gez_ER", // Geez (Eritrea)
"gez_ET", // Geez (Ethiopia)
+ "gl", // Galician
"gl_ES", // Galician (Spain)
"gu_IN", // Gujarati (India)
"gv_GB", // Manx (United Kingdom)
@@ -273,6 +276,7 @@ static const char *locale_list[] = {
"ml_IN", // Malayalam (India)
"mni_IN", // Manipuri (India)
"mn_MN", // Mongolian (Mongolia)
+ "mr", // Marathi
"mr_IN", // Marathi (India)
"ms", // Malay
"ms_MY", // Malay (Malaysia)
@@ -302,6 +306,7 @@ static const char *locale_list[] = {
"om", // Oromo
"om_ET", // Oromo (Ethiopia)
"om_KE", // Oromo (Kenya)
+ "or", // Oriya
"or_IN", // Oriya (India)
"os_RU", // Ossetian (Russia)
"pa_IN", // Panjabi (India)
@@ -386,6 +391,8 @@ static const char *locale_list[] = {
"tr_TR", // Turkish (Turkey)
"ts_ZA", // Tsonga (South Africa)
"tt_RU", // Tatar (Russia)
+ "tzm", // Central Atlas Tamazight
+ "tzm_MA", // Central Atlas Tamazight (Marrocos)
"ug_CN", // Uighur (China)
"uk", // Ukrainian
"uk_UA", // Ukrainian (Ukraine)
@@ -468,6 +475,7 @@ static const char *locale_names[] = {
"Tibetan",
"Tibetan (China)",
"Tibetan (India)",
+ "Breton",
"Breton (France)",
"Bodo (India)",
"Bosnian (Bosnia and Herzegovina)",
@@ -569,6 +577,7 @@ static const char *locale_names[] = {
"Scottish Gaelic (United Kingdom)",
"Geez (Eritrea)",
"Geez (Ethiopia)",
+ "Galician",
"Galician (Spain)",
"Gujarati (India)",
"Manx (United Kingdom)",
@@ -641,6 +650,7 @@ static const char *locale_names[] = {
"Malayalam (India)",
"Manipuri (India)",
"Mongolian (Mongolia)",
+ "Marathi",
"Marathi (India)",
"Malay",
"Malay (Malaysia)",
@@ -670,6 +680,7 @@ static const char *locale_names[] = {
"Oromo",
"Oromo (Ethiopia)",
"Oromo (Kenya)",
+ "Oriya",
"Oriya (India)",
"Ossetian (Russia)",
"Panjabi (India)",
@@ -754,6 +765,8 @@ static const char *locale_names[] = {
"Turkish (Turkey)",
"Tsonga (South Africa)",
"Tatar (Russia)",
+ "Central Atlas Tamazight",
+ "Central Atlas Tamazight (Marrocos)",
"Uighur (China)",
"Ukrainian",
"Ukrainian (Ukraine)",
@@ -822,7 +835,7 @@ Vector<String> Translation::_get_message_list() const {
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
- for (auto E = keys.front(); E; E = E->next()) {
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
translation_map[E->get()] = p_messages[E->get()];
}
}
@@ -840,7 +853,7 @@ void Translation::set_locale(const String &p_locale) {
locale = univ_locale;
}
- if (OS::get_singleton()->get_main_loop()) {
+ if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(this)) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
}
}
@@ -1191,14 +1204,14 @@ bool TranslationServer::_load_translations(const String &p_from) {
}
void TranslationServer::setup() {
- String test = GLOBAL_DEF("locale/test", "");
+ String test = GLOBAL_DEF("internationalization/locale/test", "");
test = test.strip_edges();
if (test != "") {
set_locale(test);
} else {
set_locale(OS::get_singleton()->get_locale());
}
- fallback = GLOBAL_DEF("locale/fallback", "en");
+ fallback = GLOBAL_DEF("internationalization/locale/fallback", "en");
#ifdef TOOLS_ENABLED
{
String options = "";
@@ -1210,7 +1223,7 @@ void TranslationServer::setup() {
options += locale_list[idx];
idx++;
}
- ProjectSettings::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options));
+ ProjectSettings::get_singleton()->set_custom_property_info("internationalization/locale/fallback", PropertyInfo(Variant::STRING, "internationalization/locale/fallback", PROPERTY_HINT_ENUM, options));
}
#endif
}
@@ -1307,11 +1320,11 @@ void TranslationServer::_bind_methods() {
void TranslationServer::load_translations() {
String locale = get_locale();
- _load_translations("locale/translations"); //all
- _load_translations("locale/translations_" + locale.substr(0, 2));
+ _load_translations("internationalization/locale/translations"); //all
+ _load_translations("internationalization/locale/translations_" + locale.substr(0, 2));
if (locale.substr(0, 2) != locale) {
- _load_translations("locale/translations_" + locale);
+ _load_translations("internationalization/locale/translations_" + locale);
}
}
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 846afe761b..ad768f7140 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -47,14 +47,14 @@ void TranslationPO::print_translation_map() {
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
file->store_line(" ===== Context: " + String::utf8(String(ctx).utf8()) + " ===== ");
const HashMap<StringName, Vector<StringName>> &inner_map = translation_map[ctx];
List<StringName> id_l;
inner_map.get_key_list(&id_l);
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
file->store_line("msgid: " + String::utf8(String(id).utf8()));
for (int i = 0; i < inner_map[id].size(); i++) {
@@ -74,7 +74,7 @@ Dictionary TranslationPO::_get_messages() const {
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
const HashMap<StringName, Vector<StringName>> &id_str_map = translation_map[ctx];
@@ -82,7 +82,7 @@ Dictionary TranslationPO::_get_messages() const {
List<StringName> id_l;
id_str_map.get_key_list(&id_l);
// Save list of id and strs associated with a context in a temporary dictionary.
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
d2[id] = id_str_map[id];
}
@@ -98,14 +98,14 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) {
List<Variant> context_l;
p_messages.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<Variant>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
const Dictionary &id_str_map = p_messages[ctx];
HashMap<StringName, Vector<StringName>> temp_map;
List<Variant> id_l;
id_str_map.get_key_list(&id_l);
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<Variant>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
temp_map[id] = id_str_map[id];
}
@@ -121,7 +121,7 @@ Vector<String> TranslationPO::_get_message_list() const {
get_message_list(&msgs);
Vector<String> v;
- for (auto E = msgs.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = msgs.front(); E; E = E->next()) {
v.push_back(E->get());
}
@@ -158,7 +158,7 @@ int TranslationPO::_get_plural_index(int p_n) const {
void TranslationPO::_cache_plural_tests(const String &p_plural_rule) {
// Some examples of p_plural_rule passed in can have the form:
// "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" (Arabic)
- // "n >= 2" (French) // When evaluating the last, esp careful with this one.
+ // "n >= 2" (French) // When evaluating the last, especially careful with this one.
// "n != 1" (English)
int first_ques_mark = p_plural_rule.find("?");
if (first_ques_mark == -1) {
@@ -275,13 +275,13 @@ void TranslationPO::erase_message(const StringName &p_src_text, const StringName
}
void TranslationPO::get_message_list(List<StringName> *r_messages) const {
- // PHashTranslation uses this function to get the list of msgid.
+ // OptimizedTranslation uses this function to get the list of msgid.
// Return all the keys of translation_map under "" context.
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
if (String(E->get()) != "") {
continue;
}
@@ -289,7 +289,7 @@ void TranslationPO::get_message_list(List<StringName> *r_messages) const {
List<StringName> msgid_l;
translation_map[E->get()].get_key_list(&msgid_l);
- for (auto E2 = msgid_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = msgid_l.front(); E2; E2 = E2->next()) {
r_messages->push_back(E2->get());
}
}
@@ -300,7 +300,7 @@ int TranslationPO::get_message_count() const {
translation_map.get_key_list(&context_l);
int count = 0;
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
count += translation_map[E->get()].size();
}
return count;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 59fda65d43..bdb66526a4 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -240,6 +240,71 @@ String String::word_wrap(int p_chars_per_line) const {
return ret;
}
+Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const {
+ // Splits the URL into scheme, host, port, path. Strip credentials when present.
+ String base = *this;
+ r_scheme = "";
+ r_host = "";
+ r_port = 0;
+ r_path = "";
+ int pos = base.find("://");
+ // Scheme
+ if (pos != -1) {
+ r_scheme = base.substr(0, pos + 3).to_lower();
+ base = base.substr(pos + 3, base.length() - pos - 3);
+ }
+ pos = base.find("/");
+ // Path
+ if (pos != -1) {
+ r_path = base.substr(pos, base.length() - pos);
+ base = base.substr(0, pos);
+ }
+ // Host
+ pos = base.find("@");
+ if (pos != -1) {
+ // Strip credentials
+ base = base.substr(pos + 1, base.length() - pos - 1);
+ }
+ if (base.begins_with("[")) {
+ // Literal IPv6
+ pos = base.rfind("]");
+ if (pos == -1) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_host = base.substr(1, pos - 1);
+ base = base.substr(pos + 1, base.length() - pos - 1);
+ } else {
+ // Anything else
+ if (base.get_slice_count(":") > 1) {
+ return ERR_INVALID_PARAMETER;
+ }
+ pos = base.rfind(":");
+ if (pos == -1) {
+ r_host = base;
+ base = "";
+ } else {
+ r_host = base.substr(0, pos);
+ base = base.substr(pos, base.length() - pos);
+ }
+ }
+ if (r_host.is_empty()) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_host = r_host.to_lower();
+ // Port
+ if (base.begins_with(":")) {
+ base = base.substr(1, base.length() - 1);
+ if (!base.is_valid_integer()) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_port = base.to_int();
+ if (r_port < 1 || r_port > 65535) {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ return OK;
+}
+
void String::copy_from(const char *p_cstr) {
// copy Latin-1 encoded c-string directly
if (!p_cstr) {
@@ -1138,7 +1203,7 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
remaining_len = left_edge;
}
- ret.invert();
+ ret.reverse();
return ret;
}
@@ -1764,7 +1829,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
if (skip) {
_UNICERROR("no space left");
- return true; //not enough spac
+ return true; //not enough space
}
}
@@ -3772,9 +3837,9 @@ String String::uri_encode() const {
} else {
char h_Val[3];
#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(h_Val, 3, "%hhX", ord);
+ snprintf(h_Val, 3, "%02hhX", ord);
#else
- sprintf(h_Val, "%hhX", ord);
+ sprintf(h_Val, "%02hhX", ord);
#endif
res += "%";
res += h_Val;
@@ -3784,27 +3849,28 @@ String String::uri_encode() const {
}
String String::uri_decode() const {
- String res;
- for (int i = 0; i < length(); ++i) {
- if (unicode_at(i) == '%' && i + 2 < length()) {
- char32_t ord1 = unicode_at(i + 1);
+ CharString src = utf8();
+ CharString res;
+ for (int i = 0; i < src.length(); ++i) {
+ if (src[i] == '%' && i + 2 < src.length()) {
+ char ord1 = src[i + 1];
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
- char32_t ord2 = unicode_at(i + 2);
+ char ord2 = src[i + 2];
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16);
i += 2;
}
} else {
- res += unicode_at(i);
+ res += src[i];
}
- } else if (unicode_at(i) == '+') {
+ } else if (src[i] == '+') {
res += ' ';
} else {
- res += unicode_at(i);
+ res += src[i];
}
}
- return String::utf8(res.ascii());
+ return String::utf8(res);
}
String String::c_unescape() const {
@@ -3888,25 +3954,55 @@ static _FORCE_INLINE_ int _xml_unescape(const char32_t *p_src, int p_src_len, ch
if (p_src_len >= 4 && p_src[1] == '#') {
char32_t c = 0;
-
- for (int i = 2; i < p_src_len; i++) {
- eat = i + 1;
- char32_t ct = p_src[i];
- if (ct == ';') {
- break;
- } else if (ct >= '0' && ct <= '9') {
- ct = ct - '0';
- } else if (ct >= 'a' && ct <= 'f') {
- ct = (ct - 'a') + 10;
- } else if (ct >= 'A' && ct <= 'F') {
- ct = (ct - 'A') + 10;
- } else {
- continue;
+ bool overflow = false;
+ if (p_src[2] == 'x') {
+ // Hex entity &#x<num>;
+ for (int i = 3; i < p_src_len; i++) {
+ eat = i + 1;
+ char32_t ct = p_src[i];
+ if (ct == ';') {
+ break;
+ } else if (ct >= '0' && ct <= '9') {
+ ct = ct - '0';
+ } else if (ct >= 'a' && ct <= 'f') {
+ ct = (ct - 'a') + 10;
+ } else if (ct >= 'A' && ct <= 'F') {
+ ct = (ct - 'A') + 10;
+ } else {
+ break;
+ }
+ if (c > (UINT32_MAX >> 4)) {
+ overflow = true;
+ break;
+ }
+ c <<= 4;
+ c |= ct;
+ }
+ } else {
+ // Decimal entity &#<num>;
+ for (int i = 2; i < p_src_len; i++) {
+ eat = i + 1;
+ char32_t ct = p_src[i];
+ if (ct == ';' || ct < '0' || ct > '9') {
+ break;
+ }
+ }
+ if (p_src[eat - 1] == ';') {
+ int64_t val = String::to_int(p_src + 2, eat - 3);
+ if (val > 0 && val <= UINT32_MAX) {
+ c = (char32_t)val;
+ } else {
+ overflow = true;
+ }
}
- c <<= 4;
- c |= ct;
}
+ // Value must be non-zero, in the range of char32_t,
+ // actually end with ';'. If invalid, leave the entity as-is
+ if (c == '\0' || overflow || p_src[eat - 1] != ';') {
+ eat = 1;
+ c = *p_src;
+ }
if (p_dst) {
*p_dst = c;
}
@@ -4364,6 +4460,18 @@ String String::property_name_encode() const {
return *this;
}
+// Changes made to the set of invalid characters must also be reflected in the String documentation.
+const String String::invalid_node_name_characters = ". : @ / \"";
+
+String String::validate_node_name() const {
+ Vector<String> chars = String::invalid_node_name_characters.split(" ");
+ String name = this->replace(chars[0], "");
+ for (int i = 1; i < chars.size(); i++) {
+ name = name.replace(chars[i], "");
+ }
+ return name;
+}
+
String String::get_basename() const {
int pos = rfind(".");
if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) {
@@ -4438,7 +4546,7 @@ String String::sprintf(const Array &values, bool *error) const {
for (; *self; self++) {
const char32_t c = *self;
- if (in_format) { // We have % - lets see what else we get.
+ if (in_format) { // We have % - let's see what else we get.
switch (c) {
case '%': { // Replace %% with %
formatted += chr(c);
@@ -4723,7 +4831,7 @@ Vector<uint8_t> String::to_ascii_buffer() const {
size_t len = charstr.length();
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return retval;
}
@@ -4739,7 +4847,7 @@ Vector<uint8_t> String::to_utf8_buffer() const {
size_t len = charstr.length();
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return retval;
}
@@ -4755,7 +4863,7 @@ Vector<uint8_t> String::to_utf16_buffer() const {
size_t len = charstr.length() * sizeof(char16_t);
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, (const void *)charstr.ptr(), len);
+ memcpy(w, (const void *)charstr.ptr(), len);
return retval;
}
@@ -4770,7 +4878,7 @@ Vector<uint8_t> String::to_utf32_buffer() const {
size_t len = s->length() * sizeof(char32_t);
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, (const void *)s->ptr(), len);
+ memcpy(w, (const void *)s->ptr(), len);
return retval;
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 821941036f..a56845deff 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -416,9 +416,14 @@ public:
String c_unescape() const;
String json_escape() const;
String word_wrap(int p_chars_per_line) const;
+ Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const;
String property_name_encode() const;
+ // node functions
+ static const String invalid_node_name_characters;
+ String validate_node_name() const;
+
bool is_valid_identifier() const;
bool is_valid_integer() const;
bool is_valid_float() const;
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index 7861c76153..0012cea72d 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -498,6 +498,11 @@ public:
flush_one();
}
+ _FORCE_INLINE_ void flush_if_pending() {
+ if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) {
+ flush_all();
+ }
+ }
void flush_all() {
//ERR_FAIL_COND(sync);
lock();
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index 4becb1be59..c985593473 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -45,6 +45,10 @@ class CharString;
template <class T, class V>
class VMap;
+#if !defined(NO_THREADS)
+SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint32_t)
+#endif
+
template <class T>
class CowData {
template <class TV>
@@ -60,12 +64,12 @@ private:
// internal helpers
- _FORCE_INLINE_ uint32_t *_get_refcount() const {
+ _FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
if (!_ptr) {
return nullptr;
}
- return reinterpret_cast<uint32_t *>(_ptr) - 2;
+ return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
}
_FORCE_INLINE_ uint32_t *_get_size() const {
@@ -111,7 +115,7 @@ private:
void _unref(void *p_data);
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
- void _copy_on_write();
+ uint32_t _copy_on_write();
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
@@ -138,7 +142,7 @@ public:
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
- CRASH_BAD_INDEX(p_index, size());
+ ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
_get_data()[p_index] = p_elem;
}
@@ -192,9 +196,9 @@ void CowData<T>::_unref(void *p_data) {
return;
}
- uint32_t *refc = _get_refcount();
+ SafeNumeric<uint32_t> *refc = _get_refcount();
- if (atomic_decrement(refc) > 0) {
+ if (refc->decrement() > 0) {
return; // still in use
}
// clean up
@@ -214,20 +218,21 @@ void CowData<T>::_unref(void *p_data) {
}
template <class T>
-void CowData<T>::_copy_on_write() {
+uint32_t CowData<T>::_copy_on_write() {
if (!_ptr) {
- return;
+ return 0;
}
- uint32_t *refc = _get_refcount();
+ SafeNumeric<uint32_t> *refc = _get_refcount();
- if (unlikely(*refc > 1)) {
+ uint32_t rc = refc->get();
+ if (unlikely(rc > 1)) {
/* in use by more than me */
uint32_t current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
- *(mem_new - 2) = 1; //refcount
+ new (mem_new - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(1); //refcount
*(mem_new - 1) = current_size; //size
T *_data = (T *)(mem_new);
@@ -244,7 +249,10 @@ void CowData<T>::_copy_on_write() {
_unref(_ptr);
_ptr = _data;
+
+ rc = 1;
}
+ return rc;
}
template <class T>
@@ -265,7 +273,7 @@ Error CowData<T>::resize(int p_size) {
}
// possibly changing size, copy on write
- _copy_on_write();
+ uint32_t rc = _copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
@@ -278,13 +286,15 @@ Error CowData<T>::resize(int p_size) {
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; //size, currently none
- *(ptr - 2) = 1; //refcount
+ new (ptr - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(1); //refcount
_ptr = (T *)ptr;
} else {
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ new (_ptrnew - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(rc); //refcount
+
_ptr = (T *)(_ptrnew);
}
}
@@ -311,8 +321,9 @@ Error CowData<T>::resize(int p_size) {
}
if (alloc_size != current_alloc_size) {
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ new (_ptrnew - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(rc); //refcount
_ptr = (T *)(_ptrnew);
}
@@ -359,7 +370,7 @@ void CowData<T>::_ref(const CowData &p_from) {
return; //nothing to do
}
- if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference
+ if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
_ptr = p_from._ptr;
}
}
diff --git a/core/templates/list.h b/core/templates/list.h
index eaf1dbb4a0..010e35eed8 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -492,7 +492,7 @@ public:
_data->last = p_I;
}
- void invert() {
+ void reverse() {
int s = size() / 2;
Element *F = front();
Element *B = back();
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index ffd17b7ee9..5f22e08eb8 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -32,7 +32,6 @@
#define LOCAL_VECTOR_H
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/sort_array.h"
#include "core/templates/vector.h"
@@ -216,7 +215,7 @@ public:
Vector<T> ret;
ret.resize(size());
T *w = ret.ptrw();
- copymem(w, data, sizeof(T) * count);
+ memcpy(w, data, sizeof(T) * count);
return ret;
}
@@ -224,7 +223,7 @@ public:
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
- copymem(w, data, sizeof(T) * count);
+ memcpy(w, data, sizeof(T) * count);
return ret;
}
diff --git a/core/templates/map.h b/core/templates/map.h
index 51a237472d..7dfee13d2c 100644
--- a/core/templates/map.h
+++ b/core/templates/map.h
@@ -32,7 +32,7 @@
#define MAP_H
#include "core/error/error_macros.h"
-#include "core/templates/set.h"
+#include "core/os/memory.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index 1d4176eb10..2c7c64cd78 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -32,7 +32,6 @@
#define OA_HASH_MAP_H
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/hashfuncs.h"
diff --git a/core/templates/rid_owner.cpp b/core/templates/rid_owner.cpp
index f75a2eb9df..56f39ab779 100644
--- a/core/templates/rid_owner.cpp
+++ b/core/templates/rid_owner.cpp
@@ -30,4 +30,4 @@
#include "rid_owner.h"
-volatile uint64_t RID_AllocBase::base_id = 1;
+SafeNumeric<uint64_t> RID_AllocBase::base_id{ 1 };
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index d26c445eb4..c4aa93c394 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -44,7 +44,7 @@
#include <typeinfo>
class RID_AllocBase {
- static volatile uint64_t base_id;
+ static SafeNumeric<uint64_t> base_id;
protected:
static RID _make_from_id(uint64_t p_id) {
@@ -54,7 +54,7 @@ protected:
}
static uint64_t _gen_id() {
- return atomic_increment(&base_id);
+ return base_id.increment();
}
static RID _gen_rid() {
@@ -79,8 +79,7 @@ class RID_Alloc : public RID_AllocBase {
SpinLock spin_lock;
-public:
- RID make_rid(const T &p_value) {
+ _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -115,15 +114,22 @@ public:
uint32_t free_chunk = free_index / elements_in_chunk;
uint32_t free_element = free_index % elements_in_chunk;
- T *ptr = &chunks[free_chunk][free_element];
- memnew_placement(ptr, T(p_value));
+ if (p_initializer) {
+ T *ptr = &chunks[free_chunk][free_element];
+ memnew_placement(ptr, T(*p_initializer));
+ }
- uint32_t validator = (uint32_t)(_gen_id() & 0xFFFFFFFF);
+ uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF);
uint64_t id = validator;
id <<= 32;
id |= free_index;
validator_chunks[free_chunk][free_element] = validator;
+
+ if (!p_initializer) {
+ validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit
+ }
+
alloc_count++;
if (THREAD_SAFE) {
@@ -133,7 +139,20 @@ public:
return _make_from_id(id);
}
- _FORCE_INLINE_ T *getornull(const RID &p_rid) {
+public:
+ RID make_rid(const T &p_value) {
+ return _allocate_rid(&p_value);
+ }
+
+ //allocate but don't initialize, use initialize_rid afterwards
+ RID allocate_rid() {
+ return _allocate_rid(nullptr);
+ }
+
+ _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) {
+ if (p_rid == RID()) {
+ return nullptr;
+ }
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -151,10 +170,32 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+
+ if (unlikely(p_initialize)) {
+ if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
+ }
+
+ if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
+ return nullptr;
+ }
+
+ validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; //initialized
+
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
+ if (validator_chunks[idx_chunk][idx_element] & 0x80000000) {
+ ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
+ }
return nullptr;
}
@@ -166,6 +207,11 @@ public:
return ptr;
}
+ void initialize_rid(RID p_rid, const T &p_value) {
+ T *mem = getornull(p_rid, true);
+ ERR_FAIL_COND(!mem);
+ memnew_placement(mem, T(p_value));
+ }
_FORCE_INLINE_ bool owns(const RID &p_rid) {
if (THREAD_SAFE) {
@@ -186,7 +232,7 @@ public:
uint32_t validator = uint32_t(id >> 32);
- bool owned = validator_chunks[idx_chunk][idx_element] == validator;
+ bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
if (THREAD_SAFE) {
spin_lock.unlock();
@@ -213,7 +259,12 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+ if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
@@ -330,6 +381,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
T **ptr = alloc.getornull(p_rid);
if (unlikely(!ptr)) {
@@ -338,6 +397,12 @@ public:
return *ptr;
}
+ _FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
+ T **ptr = alloc.getornull(p_rid);
+ ERR_FAIL_COND(!ptr);
+ *ptr = p_new_ptr;
+ }
+
_FORCE_INLINE_ bool owns(const RID &p_rid) {
return alloc.owns(p_rid);
}
@@ -379,6 +444,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
return alloc.getornull(p_rid);
}
diff --git a/core/templates/safe_refcount.cpp b/core/templates/safe_refcount.cpp
deleted file mode 100644
index a915ee662f..0000000000
--- a/core/templates/safe_refcount.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*************************************************************************/
-/* safe_refcount.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "safe_refcount.h"
-
-#if defined(_MSC_VER)
-
-/* Implementation for MSVC-Windows */
-
-// don't pollute my namespace!
-#include <windows.h>
-
-#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \
- /* try to increment until it actually works */ \
- /* taken from boost */ \
- while (true) { \
- m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
- if (tmp == 0) { \
- return 0; /* if zero, can't add to it anymore */ \
- } \
- if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) { \
- return tmp + 1; \
- } \
- }
-
-#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \
- while (true) { \
- m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
- if (tmp >= m_val) { \
- return tmp; /* already greater, or equal */ \
- } \
- if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) { \
- return m_val; \
- } \
- }
-
-_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw) {
- ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
- return InterlockedDecrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
- return InterlockedIncrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
- return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
- return InterlockedAdd((LONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val) {
- ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw) {
- ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
- return InterlockedDecrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
- return InterlockedIncrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
- return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
- return InterlockedAdd64((LONGLONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val) {
- ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t);
-}
-
-// The actual advertised functions; they'll call the right implementation
-
-uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
- return _atomic_conditional_increment_impl(pw);
-}
-
-uint32_t atomic_decrement(volatile uint32_t *pw) {
- return _atomic_decrement_impl(pw);
-}
-
-uint32_t atomic_increment(volatile uint32_t *pw) {
- return _atomic_increment_impl(pw);
-}
-
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_sub_impl(pw, val);
-}
-
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_add_impl(pw, val);
-}
-
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_exchange_if_greater_impl(pw, val);
-}
-
-uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
- return _atomic_conditional_increment_impl(pw);
-}
-
-uint64_t atomic_decrement(volatile uint64_t *pw) {
- return _atomic_decrement_impl(pw);
-}
-
-uint64_t atomic_increment(volatile uint64_t *pw) {
- return _atomic_increment_impl(pw);
-}
-
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_sub_impl(pw, val);
-}
-
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_add_impl(pw, val);
-}
-
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_exchange_if_greater_impl(pw, val);
-}
-#endif
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index d94444fad6..e9e5695f80 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -31,167 +31,292 @@
#ifndef SAFE_REFCOUNT_H
#define SAFE_REFCOUNT_H
-#include "core/os/mutex.h"
#include "core/typedefs.h"
-#include "platform_config.h"
-// Atomic functions, these are used for multithread safe reference counters!
+#if !defined(NO_THREADS)
-#ifdef NO_THREADS
+#include <atomic>
+#include <type_traits>
-/* Bogus implementation unaware of multiprocessing */
+// Design goals for these classes:
+// - No automatic conversions or arithmetic operators,
+// to keep explicit the use of atomics everywhere.
+// - Using acquire-release semantics, even to set the first value.
+// The first value may be set relaxedly in many cases, but adding the distinction
+// between relaxed and unrelaxed operation to the interface would make it needlessly
+// flexible. There's negligible waste in having release semantics for the initial
+// value and, as an important benefit, you can be sure the value is properly synchronized
+// even with threads that are already running.
+
+// This is used in very specific areas of the engine where it's critical that these guarantees are held
+#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
+ static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
+ static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
+ static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
- if (*pw == 0) {
- return 0;
+class SafeNumeric {
+ std::atomic<T> value;
+
+ static_assert(std::atomic<T>::is_always_lock_free);
+
+public:
+ _ALWAYS_INLINE_ void set(T p_value) {
+ value.store(p_value, std::memory_order_release);
}
- (*pw)++;
+ _ALWAYS_INLINE_ T get() const {
+ return value.load(std::memory_order_acquire);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T increment() {
+ return value.fetch_add(1, std::memory_order_acq_rel) + 1;
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
- (*pw)--;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postincrement() {
+ return value.fetch_add(1, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T decrement() {
+ return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
- (*pw)++;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postdecrement() {
+ return value.fetch_sub(1, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T add(T p_value) {
+ return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
- (*pw) -= val;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postadd(T p_value) {
+ return value.fetch_add(p_value, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T sub(T p_value) {
+ return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
- (*pw) += val;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postsub(T p_value) {
+ return value.fetch_sub(p_value, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+ while (true) {
+ T tmp = value.load(std::memory_order_acquire);
+ if (tmp >= p_value) {
+ return tmp; // already greater, or equal
+ }
+ if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
+ return p_value;
+ }
+ }
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
- if (val > *pw) {
- *pw = val;
+ _ALWAYS_INLINE_ T conditional_increment() {
+ while (true) {
+ T c = value.load(std::memory_order_acquire);
+ if (c == 0) {
+ return 0;
+ }
+ if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
+ return c + 1;
+ }
+ }
}
- return *pw;
-}
+ _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
+ set(p_value);
+ }
+};
-#elif defined(__GNUC__)
+class SafeFlag {
+ std::atomic_bool flag;
-/* Implementation for GCC & Clang */
+ static_assert(std::atomic_bool::is_always_lock_free);
-// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes.
-// Clang states it supports GCC atomic builtins.
+public:
+ _ALWAYS_INLINE_ bool is_set() const {
+ return flag.load(std::memory_order_acquire);
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
- while (true) {
- T tmp = static_cast<T const volatile &>(*pw);
- if (tmp == 0) {
- return 0; // if zero, can't add to it anymore
- }
- if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp) {
- return tmp + 1;
- }
+ _ALWAYS_INLINE_ void set() {
+ flag.store(true, std::memory_order_release);
}
-}
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
- return __sync_sub_and_fetch(pw, 1);
-}
+ _ALWAYS_INLINE_ void clear() {
+ flag.store(false, std::memory_order_release);
+ }
+
+ _ALWAYS_INLINE_ void set_to(bool p_value) {
+ flag.store(p_value, std::memory_order_release);
+ }
+
+ _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
+ set_to(p_value);
+ }
+};
+
+class SafeRefCount {
+ SafeNumeric<uint32_t> count;
+
+public:
+ _ALWAYS_INLINE_ bool ref() { // true on success
+ return count.conditional_increment() != 0;
+ }
+
+ _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ return count.conditional_increment();
+ }
+
+ _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ return count.decrement() == 0;
+ }
+
+ _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ return count.decrement();
+ }
+
+ _ALWAYS_INLINE_ uint32_t get() const {
+ return count.get();
+ }
+
+ _ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
+ count.set(p_value);
+ }
+};
+
+#else
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
- return __sync_add_and_fetch(pw, 1);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
- return __sync_sub_and_fetch(pw, val);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
- return __sync_add_and_fetch(pw, val);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
- while (true) {
- T tmp = static_cast<T const volatile &>(*pw);
- if (tmp >= val) {
- return tmp; // already greater, or equal
+class SafeNumeric {
+protected:
+ T value;
+
+public:
+ _ALWAYS_INLINE_ void set(T p_value) {
+ value = p_value;
+ }
+
+ _ALWAYS_INLINE_ T get() const {
+ return value;
+ }
+
+ _ALWAYS_INLINE_ T increment() {
+ return ++value;
+ }
+
+ _ALWAYS_INLINE_ T postincrement() {
+ return value++;
+ }
+
+ _ALWAYS_INLINE_ T decrement() {
+ return --value;
+ }
+
+ _ALWAYS_INLINE_ T postdecrement() {
+ return value--;
+ }
+
+ _ALWAYS_INLINE_ T add(T p_value) {
+ return value += p_value;
+ }
+
+ _ALWAYS_INLINE_ T postadd(T p_value) {
+ T old = value;
+ value += p_value;
+ return old;
+ }
+
+ _ALWAYS_INLINE_ T sub(T p_value) {
+ return value -= p_value;
+ }
+
+ _ALWAYS_INLINE_ T postsub(T p_value) {
+ T old = value;
+ value -= p_value;
+ return old;
+ }
+
+ _ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+ if (value < p_value) {
+ value = p_value;
}
- if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) {
- return val;
+ return value;
+ }
+
+ _ALWAYS_INLINE_ T conditional_increment() {
+ if (value == 0) {
+ return 0;
+ } else {
+ return ++value;
}
}
-}
-
-#elif defined(_MSC_VER)
-// For MSVC use a separate compilation unit to prevent windows.h from polluting
-// the global namespace.
-uint32_t atomic_conditional_increment(volatile uint32_t *pw);
-uint32_t atomic_decrement(volatile uint32_t *pw);
-uint32_t atomic_increment(volatile uint32_t *pw);
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
-
-uint64_t atomic_conditional_increment(volatile uint64_t *pw);
-uint64_t atomic_decrement(volatile uint64_t *pw);
-uint64_t atomic_increment(volatile uint64_t *pw);
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
-#else
-//no threads supported?
-#error Must provide atomic functions for this platform or compiler!
-#endif
+ _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
+ value(p_value) {
+ }
+};
-struct SafeRefCount {
- uint32_t count = 0;
+class SafeFlag {
+protected:
+ bool flag;
public:
- // destroy() is called when weak_count_ drops to zero.
-
- _ALWAYS_INLINE_ bool ref() { // true on success
+ _ALWAYS_INLINE_ bool is_set() const {
+ return flag;
+ }
- return atomic_conditional_increment(&count) != 0;
+ _ALWAYS_INLINE_ void set() {
+ flag = true;
}
- _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ _ALWAYS_INLINE_ void clear() {
+ flag = false;
+ }
- return atomic_conditional_increment(&count);
+ _ALWAYS_INLINE_ void set_to(bool p_value) {
+ flag = p_value;
}
- _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
+ flag(p_value) {}
+};
+
+class SafeRefCount {
+ uint32_t count = 0;
- return atomic_decrement(&count) == 0;
+public:
+ _ALWAYS_INLINE_ bool ref() { // true on success
+ if (count != 0) {
+ ++count;
+ return true;
+ } else {
+ return false;
+ }
}
- _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ if (count != 0) {
+ return ++count;
+ } else {
+ return 0;
+ }
+ }
- return atomic_decrement(&count);
+ _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ return --count == 0;
}
- _ALWAYS_INLINE_ uint32_t get() const { // nothrow
+ _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ return --count;
+ }
+ _ALWAYS_INLINE_ uint32_t get() const {
return count;
}
@@ -200,4 +325,6 @@ public:
}
};
+#endif
+
#endif // SAFE_REFCOUNT_H
diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h
index 19ab1dda3a..9f7a692cc5 100644
--- a/core/templates/thread_work_pool.h
+++ b/core/templates/thread_work_pool.h
@@ -83,7 +83,7 @@ public:
ERR_FAIL_COND(!threads); //never initialized
ERR_FAIL_COND(current_work != nullptr);
- index.store(0);
+ index.store(0, std::memory_order_release);
Work<C, M, U> *w = memnew((Work<C, M, U>));
w->instance = p_instance;
@@ -104,8 +104,15 @@ public:
return current_work != nullptr;
}
+ bool is_done_dispatching() const {
+ ERR_FAIL_COND_V(current_work == nullptr, false);
+ return index.load(std::memory_order_acquire) >= current_work->max_elements;
+ }
+
uint32_t get_work_index() const {
- return index;
+ ERR_FAIL_COND_V(current_work == nullptr, 0);
+ uint32_t idx = index.load(std::memory_order_acquire);
+ return MIN(idx, current_work->max_elements);
}
void end_work() {
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 6a8902707c..dae8874a87 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -38,7 +38,6 @@
*/
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/cowdata.h"
#include "core/templates/sort_array.h"
@@ -66,6 +65,7 @@ private:
public:
bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
+ void fill(T p_elem);
void remove(int p_index) { _cowdata.remove(p_index); }
void erase(const T &p_val) {
@@ -74,7 +74,7 @@ public:
remove(idx);
}
}
- void invert();
+ void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
@@ -134,7 +134,7 @@ public:
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
ret.resize(size() * sizeof(T));
- copymem(ret.ptrw(), ptr(), sizeof(T) * size());
+ memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret;
}
@@ -194,7 +194,7 @@ public:
};
template <class T>
-void Vector<T>::invert() {
+void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
@@ -223,4 +223,12 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
+template <class T>
+void Vector<T>::fill(T p_elem) {
+ T *p = ptrw();
+ for (int i = 0; i < size(); i++) {
+ p[i] = p_elem;
+ }
+}
+
#endif // VECTOR_H
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 9a2922a777..2fb2dd4a30 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -139,9 +139,9 @@ uint32_t Array::hash() const {
return h;
}
-void Array::_assign(const Array &p_array) {
+bool Array::_assign(const Array &p_array) {
if (_p->typed.type != Variant::OBJECT && _p->typed.type == p_array._p->typed.type) {
- //same type or untyped, just reference, shuold be fine
+ //same type or untyped, just reference, should be fine
_ref(p_array);
} else if (_p->typed.type == Variant::NIL) { //from typed to untyped, must copy, but this is cheap anyway
_p->array = p_array._p->array;
@@ -150,7 +150,7 @@ void Array::_assign(const Array &p_array) {
//for objects, it needs full validation, either can be converted or fail
for (int i = 0; i < p_array._p->array.size(); i++) {
if (!_p->typed.validate(p_array._p->array[i], "assign")) {
- return;
+ return false;
}
}
_p->array = p_array._p->array; //then just copy, which is cheap anyway
@@ -168,10 +168,10 @@ void Array::_assign(const Array &p_array) {
Callable::CallError ce;
Variant::construct(_p->typed.type, new_array.write[i], (const Variant **)&ptr, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
}
} else {
- ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
}
}
@@ -180,12 +180,13 @@ void Array::_assign(const Array &p_array) {
} else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible
_ref(p_array);
} else {
- ERR_FAIL_MSG("Assignment of arrays of incompatible types.");
+ ERR_FAIL_V_MSG(false, "Assignment of arrays of incompatible types.");
}
+ return true;
}
void Array::operator=(const Array &p_array) {
- _assign(p_array);
+ _ref(p_array);
}
void Array::push_back(const Variant &p_value) {
@@ -207,6 +208,11 @@ void Array::insert(int p_pos, const Variant &p_value) {
_p->array.insert(p_pos, p_value);
}
+void Array::fill(const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "fill"));
+ _p->array.fill(p_value);
+}
+
void Array::erase(const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));
_p->array.erase(p_value);
@@ -445,8 +451,8 @@ int Array::bsearch_custom(const Variant &p_value, Callable p_callable, bool p_be
return bisect(_p->array, p_value, p_before, less);
}
-void Array::invert() {
- _p->array.invert();
+void Array::reverse() {
+ _p->array.reverse();
}
void Array::push_front(const Variant &p_value) {
@@ -528,6 +534,10 @@ Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_nam
_assign(p_from);
}
+bool Array::typed_assign(const Array &p_other) {
+ return _assign(p_other);
+}
+
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
@@ -542,6 +552,22 @@ void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Var
_p->typed.where = "TypedArray";
}
+bool Array::is_typed() const {
+ return _p->typed.type != Variant::NIL;
+}
+
+uint32_t Array::get_typed_builtin() const {
+ return _p->typed.type;
+}
+
+StringName Array::get_typed_class_name() const {
+ return _p->typed.class_name;
+}
+
+Variant Array::get_typed_script() const {
+ return _p->typed.script;
+}
+
Array::Array(const Array &p_from) {
_p = nullptr;
_ref(p_from);
diff --git a/core/variant/array.h b/core/variant/array.h
index d8f2402330..5ce977ee4b 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -48,7 +48,7 @@ class Array {
protected:
Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
- void _assign(const Array &p_array);
+ bool _assign(const Array &p_array);
public:
Variant &operator[](int p_idx);
@@ -74,6 +74,7 @@ public:
void insert(int p_pos, const Variant &p_value);
void remove(int p_pos);
+ void fill(const Variant &p_value);
Variant front() const;
Variant back() const;
@@ -83,7 +84,7 @@ public:
void shuffle();
int bsearch(const Variant &p_value, bool p_before = true);
int bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before = true);
- void invert();
+ void reverse();
int find(const Variant &p_value, int p_from = 0) const;
int rfind(const Variant &p_value, int p_from = -1) const;
@@ -111,7 +112,12 @@ public:
const void *id() const;
+ bool typed_assign(const Array &p_other);
void set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
+ bool is_typed() const;
+ uint32_t get_typed_builtin() const;
+ StringName get_typed_class_name() const;
+ Variant get_typed_script() const;
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 9d8e262cc9..830e0a5cbd 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -88,6 +88,7 @@ VARIANT_ENUM_CAST(Vector3::Axis);
VARIANT_ENUM_CAST(Error);
VARIANT_ENUM_CAST(Side);
+VARIANT_ENUM_CAST(ClockDirection);
VARIANT_ENUM_CAST(Corner);
VARIANT_ENUM_CAST(Orientation);
VARIANT_ENUM_CAST(HAlign);
@@ -121,6 +122,18 @@ struct VariantObjectClassChecker {
}
};
+template <typename T>
+class Ref;
+
+template <typename T>
+struct VariantObjectClassChecker<const Ref<T> &> {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ Object *obj = p_variant;
+ const Ref<T> node = p_variant;
+ return node.ptr() || !obj;
+ }
+};
+
template <>
struct VariantObjectClassChecker<Node *> {
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
@@ -232,11 +245,26 @@ void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const,
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
+template <class T, class... P, size_t... Is>
+void call_with_ptr_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const void **p_args, IndexSequence<Is...>) {
+ p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...);
+}
+
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
+template <class R, class... P, size_t... Is>
+void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class... P, size_t... Is>
+void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
+ p_method(PtrToArg<P>::convert(p_args[Is])...);
+}
+
template <class T, class... P, size_t... Is>
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
(p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
@@ -262,6 +290,21 @@ void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_me
VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
}
+template <class T, class... P, size_t... Is>
+void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
+ p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
+template <class R, class... P, size_t... Is>
+void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class... P, size_t... Is>
+void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
+ p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
template <class T, class... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -450,11 +493,26 @@ void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class T, class... P>
+void call_with_ptr_args_static(T *p_instance, void (*p_method)(T *, P...), const void **p_args) {
+ call_with_ptr_args_static_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class R, class... P>
+void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_ptr_args_static_method(void (*p_method)(P...), const void **p_args) {
+ call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class... P>
void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
@@ -470,11 +528,26 @@ void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...)
call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class T, class... P>
+void call_with_validated_variant_args_static(Variant *base, void (*p_method)(T *, P...), const Variant **p_args) {
+ call_with_validated_variant_args_static_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class... P>
+void call_with_validated_variant_args_static_method(void (*p_method)(P...), const Variant **p_args) {
+ call_with_validated_variant_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
// GCC raises "parameter 'p_args' set but not used" when P = {},
// it's not clever enough to treat other P values as making this branch valid.
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
@@ -565,6 +638,28 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif
}
+template <class R, class... P, size_t... Is>
+void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
+template <class... P, size_t... Is>
+void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
template <class T, class R, class... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -595,6 +690,42 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args;
}
+template <class R, class... P>
+void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
#ifdef DEBUG_METHODS_ENABLED
@@ -659,6 +790,118 @@ void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T
call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
+template <class T, class... P, size_t... Is>
+void call_with_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+
+ (void)p_args;
+}
+
+template <class T, class... P>
+void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, int p_argcount, const Vector<Variant> &default_values, Callable::CallError &r_error) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_static_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_static_ret(p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_static(p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index bd51e2dd1e..a1d9c5ed2f 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -126,7 +126,7 @@ bool Callable::operator==(const Callable &p_callable) const {
if (custom_a == custom_b) {
if (custom_a) {
if (custom == p_callable.custom) {
- return true; //same pointer, dont even compare
+ return true; //same pointer, don't even compare
}
CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
@@ -155,7 +155,7 @@ bool Callable::operator<(const Callable &p_callable) const {
if (custom_a == custom_b) {
if (custom_a) {
if (custom == p_callable.custom) {
- return false; //same pointer, dont even compare
+ return false; //same pointer, don't even compare
}
CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 5050aa24ec..0acafc64fa 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -495,6 +495,7 @@ public:
static bool has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method);
static Variant::Type get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method);
static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method);
+ static bool is_builtin_method_static(Variant::Type p_type, const StringName &p_method);
static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
static int get_builtin_method_count(Variant::Type p_type);
@@ -502,6 +503,8 @@ public:
void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
+ static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
+
static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 8f2cba138b..deaccc6304 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -34,6 +34,7 @@
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/compression.h"
+#include "core/io/marshalls.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"
@@ -42,6 +43,16 @@
typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_static_method_call(R (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_static_ret_dv(method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class... P>
+static _FORCE_INLINE_ void vc_static_method_call(void (*method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_static_dv(method, p_args, p_argcount, r_error, p_defvals);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
@@ -63,6 +74,16 @@ static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant
}
template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_method_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, p_defvals, r_error);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_method_call_static(void (*method)(T *, P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, p_defvals, r_error);
+}
+
+template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_ret(base, method, p_args, r_ret);
}
@@ -82,48 +103,43 @@ static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Vari
}
template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
- call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+static _FORCE_INLINE_ void vc_validated_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_retc(base, method, p_args, r_ret);
}
-template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
- call_with_ptr_args_retc(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call_static(void (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static(base, method, p_args);
}
-template <class T, class... P>
-static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
- call_with_ptr_args(reinterpret_cast<T *>(p_base), method, p_args);
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_validated_static_call(R (*method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method_ret(method, p_args, r_ret);
}
-template <class T, class... P>
-static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
- call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args);
+template <class... P>
+static _FORCE_INLINE_ void vc_validated_static_call(void (*method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_method(method, p_args);
}
template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...), Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
+static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...) const, Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
+static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_retc(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
template <class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...), Variant *v) {
- VariantInternal::clear(v);
+static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args(reinterpret_cast<T *>(p_base), method, p_args);
}
template <class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...) const, Variant *v) {
- VariantInternal::clear(v);
-}
-
-template <class R, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (*method)(P...), Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
+static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args);
}
template <class R, class T, class... P>
@@ -150,6 +166,11 @@ static _FORCE_INLINE_ int vc_get_argument_count(R (*method)(T *, P...)) {
return sizeof...(P);
}
+template <class R, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count_static(R (*method)(P...)) {
+ return sizeof...(P);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...), int p_arg) {
return call_get_argument_type<P...>(p_arg);
@@ -174,6 +195,11 @@ static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (*method)(T *, P...),
return call_get_argument_type<P...>(p_arg);
}
+template <class R, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type_static(R (*method)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
@@ -199,6 +225,11 @@ static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
+template <class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (*method)(P...)) {
+ return Variant::NIL;
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...)) {
return true;
@@ -218,6 +249,16 @@ static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...) const) {
return false;
}
+template <class... P>
+static _FORCE_INLINE_ bool vc_has_return_type_static(void (*method)(P...)) {
+ return false;
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type_static(R (*method)(P...)) {
+ return true;
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...)) {
return false;
@@ -262,7 +303,6 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
vc_method_call(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \
} \
static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
- vc_change_return_type(m_method_ptr, r_ret); \
vc_validated_call(m_method_ptr, base, p_args, r_ret); \
} \
static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
@@ -283,6 +323,9 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
static bool is_const() { \
return vc_is_const(m_method_ptr); \
} \
+ static bool is_static() { \
+ return false; \
+ } \
static bool is_vararg() { \
return false; \
} \
@@ -294,47 +337,104 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
} \
};
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_static_ptrcall(R (*method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method_ret<R, P...>(method, p_args, r_ret);
+}
+
+template <class... P>
+static _FORCE_INLINE_ void vc_static_ptrcall(void (*method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_method<P...>(method, p_args);
+}
+
+#define STATIC_METHOD_CLASS(m_class, m_method_name, m_method_ptr) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ vc_static_method_call(m_method_ptr, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_validated_static_call(m_method_ptr, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_static_ptrcall(m_method_ptr, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count_static(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type_static(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return vc_has_return_type_static(m_method_ptr); \
+ } \
+ static bool is_const() { \
+ return false; \
+ } \
+ static bool is_static() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
-#define FUNCTION_CLASS(m_class, m_method_name, m_method_ptr) \
- struct Method_##m_class##_##m_method_name { \
- static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
- call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<m_class>::get_ptr(base), m_method_ptr, p_args, p_argcount, r_ret, p_defvals, r_error); \
- } \
- static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
- vc_change_return_type(m_method_ptr, r_ret); \
- call_with_validated_variant_args_static_retc(base, m_method_ptr, p_args, r_ret); \
- } \
- static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
- vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
- } \
- static int get_argument_count() { \
- return vc_get_argument_count(m_method_ptr); \
- } \
- static Variant::Type get_argument_type(int p_arg) { \
- return vc_get_argument_type(m_method_ptr, p_arg); \
- } \
- static Variant::Type get_return_type() { \
- return vc_get_return_type(m_method_ptr); \
- } \
- static bool has_return_type() { \
- return true; \
- } \
- static bool is_const() { \
- return true; \
- } \
- static bool is_vararg() { \
- return false; \
- } \
- static Variant::Type get_base_type() { \
- return GetTypeInfo<m_class>::VARIANT_TYPE; \
- } \
- static StringName get_name() { \
- return #m_method_name; \
- } \
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_static<T, P...>(reinterpret_cast<T *>(p_base), method, p_args);
+}
+
+#define FUNCTION_CLASS(m_class, m_method_name, m_method_ptr, m_const) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ vc_method_call_static(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_validated_call_static(m_method_ptr, base, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return vc_has_return_type_static(m_method_ptr); \
+ } \
+ static bool is_const() { \
+ return m_const; \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
};
#define VARARG_CLASS(m_class, m_method_name, m_method_ptr, m_has_return, m_return_type) \
@@ -379,6 +479,9 @@ static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, cons
static bool is_const() { \
return true; \
} \
+ static bool is_static() { \
+ return false; \
+ } \
static bool is_vararg() { \
return true; \
} \
@@ -397,7 +500,7 @@ struct _VariantCall {
const uint8_t *r = p_instance->ptr();
CharString cs;
cs.resize(p_instance->size() + 1);
- copymem(cs.ptrw(), r, p_instance->size());
+ memcpy(cs.ptrw(), r, p_instance->size());
cs[p_instance->size()] = 0;
s = cs.get_data();
@@ -490,6 +593,195 @@ struct _VariantCall {
return s;
}
+ static int64_t func_PackedByteArray_decode_u8(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > int64_t(size) - 1, 0);
+ const uint8_t *r = p_instance->ptr();
+ return r[p_offset];
+ }
+ static int64_t func_PackedByteArray_decode_s8(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > int64_t(size) - 1, 0);
+ const uint8_t *r = p_instance->ptr();
+ return *((const int8_t *)&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u16(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_uint16(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s16(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int16_t)decode_uint16(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u32(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_uint32(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s32(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int32_t)decode_uint32(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u64(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int64_t)decode_uint64(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s64(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int64_t)decode_uint64(&r[p_offset]);
+ }
+ static double func_PackedByteArray_decode_half(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return Math::half_to_float(decode_uint16(&r[p_offset]));
+ }
+ static double func_PackedByteArray_decode_float(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_float(&r[p_offset]);
+ }
+
+ static double func_PackedByteArray_decode_double(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_double(&r[p_offset]);
+ }
+
+ static bool func_PackedByteArray_has_encoded_var(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, false);
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, nullptr, p_allow_objects);
+ return err == OK;
+ }
+
+ static Variant func_PackedByteArray_decode_var(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, Variant());
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, nullptr, p_allow_objects);
+ if (err != OK) {
+ ret = Variant();
+ }
+ return ret;
+ }
+
+ static int64_t func_PackedByteArray_decode_var_size(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, 0);
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ int r_size;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, &r_size, p_allow_objects);
+ if (err == OK) {
+ return r_size;
+ }
+ return 0;
+ }
+
+ static void func_PackedByteArray_encode_u8(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 1);
+ uint8_t *w = p_instance->ptrw();
+ *((uint8_t *)&w[p_offset]) = p_value;
+ }
+ static void func_PackedByteArray_encode_s8(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 1);
+ uint8_t *w = p_instance->ptrw();
+ *((int8_t *)&w[p_offset]) = p_value;
+ }
+
+ static void func_PackedByteArray_encode_u16(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16((uint16_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s16(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16((int16_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_u32(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint32((uint32_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s32(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint32((int32_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_u64(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint64((uint64_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s64(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint64((int64_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_half(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16(Math::make_half_float(p_value), &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_float(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_float(p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_double(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_double(p_value, &w[p_offset]);
+ }
+ static int64_t func_PackedByteArray_encode_var(PackedByteArray *p_instance, int64_t p_offset, const Variant &p_value, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, -1);
+ uint8_t *w = p_instance->ptrw();
+ int len;
+ Error err = encode_variant(p_value, nullptr, len, p_allow_objects);
+ if (err != OK) {
+ return -1;
+ }
+ if (uint64_t(p_offset + len) > size) {
+ return -1; // did not fit
+ }
+ encode_variant(p_value, w + p_offset, len, p_allow_objects);
+
+ return len;
+ }
+
static void func_Callable_call(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
callable->call(p_args, p_argcount, r_ret, r_error);
@@ -549,6 +841,7 @@ struct VariantBuiltInMethodInfo {
Vector<String> argument_names;
bool is_const;
+ bool is_static;
bool has_return_type;
bool is_vararg;
Variant::Type return_type;
@@ -580,6 +873,7 @@ static void register_builtin_method(const Vector<String> &p_argnames, const Vect
imi.argument_names = p_argnames;
imi.is_const = T::is_const();
+ imi.is_static = T::is_static();
imi.is_vararg = T::is_vararg();
imi.has_return_type = T::has_return_type();
imi.return_type = T::get_return_type();
@@ -625,6 +919,24 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg
}
}
+void Variant::call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+ const VariantBuiltInMethodInfo *imf = builtin_method_info[p_type].lookup_ptr(p_method);
+
+ if (!imf) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ if (!imf->is_static) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+ imf->call(nullptr, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
+}
+
bool Variant::has_method(const StringName &p_method) const {
if (type == OBJECT) {
Object *obj = get_validated_object();
@@ -724,6 +1036,13 @@ bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_
return method->is_const;
}
+bool Variant::is_builtin_method_static(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, false);
+ return method->is_static;
+}
+
bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
@@ -759,7 +1078,9 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
if (method->is_vararg) {
mi.flags |= METHOD_FLAG_VARARG;
}
-
+ if (method->is_static) {
+ mi.flags |= METHOD_FLAG_STATIC;
+ }
for (int i = 0; i < method->argument_count; i++) {
PropertyInfo pi;
#ifdef DEBUG_METHODS_ENABLED
@@ -855,6 +1176,16 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
#endif
#ifdef DEBUG_METHODS_ENABLED
+#define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \
+ STATIC_METHOD_CLASS(m_type, m_method, m_type::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args);
+#else
+#define bind_static_method(m_type, m_method, m_arg_names, m_default_args) \
+ STATIC_METHOD_CLASS(m_type, m_method, m_type ::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \
METHOD_CLASS(m_type, m_name, m_method); \
register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
@@ -866,11 +1197,21 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
#ifdef DEBUG_METHODS_ENABLED
#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
- FUNCTION_CLASS(m_type, m_name, m_method); \
+ FUNCTION_CLASS(m_type, m_name, m_method, true); \
register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
#else
#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
- FUNCTION_CLASS(m_type, m_name, m_method); \
+ FUNCTION_CLASS(m_type, m_name, m_method, true); \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+#define bind_functionnc(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method, false); \
+ register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
+#else
+#define bind_functionnc(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method, false); \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
#endif
@@ -956,6 +1297,8 @@ static void _register_variant_builtin_methods() {
bind_method(String, c_unescape, sarray(), varray());
bind_method(String, json_escape, sarray(), varray());
+ bind_method(String, validate_node_name, sarray(), varray());
+
bind_method(String, is_valid_identifier, sarray(), varray());
bind_method(String, is_valid_integer, sarray(), varray());
bind_method(String, is_valid_float, sarray(), varray());
@@ -981,6 +1324,11 @@ static void _register_variant_builtin_methods() {
bind_method(String, to_utf16_buffer, sarray(), varray());
bind_method(String, to_utf32_buffer, sarray(), varray());
+ bind_static_method(String, num_scientific, sarray("number"), varray());
+ bind_static_method(String, num, sarray("number", "decimals"), varray(-1));
+ bind_static_method(String, chr, sarray("char"), varray());
+ bind_static_method(String, humanize_size, sarray("size"), varray());
+
/* Vector2 */
bind_method(Vector2, angle, sarray(), varray());
@@ -1059,6 +1407,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, min_axis, sarray(), varray());
bind_method(Vector3, max_axis, sarray(), varray());
bind_method(Vector3, angle_to, sarray("to"), varray());
+ bind_method(Vector3, signed_angle_to, sarray("to", "axis"), varray());
bind_method(Vector3, direction_to, sarray("b"), varray());
bind_method(Vector3, distance_to, sarray("b"), varray());
bind_method(Vector3, distance_squared_to, sarray("b"), varray());
@@ -1144,6 +1493,17 @@ static void _register_variant_builtin_methods() {
//ADDFUNC4R(COLOR, COLOR, Color, from_hsv, FLOAT, "h", FLOAT, "s", FLOAT, "v", FLOAT, "a", varray(1.0));
bind_method(Color, is_equal_approx, sarray("to"), varray());
+ bind_static_method(Color, hex, sarray("hex"), varray());
+ bind_static_method(Color, hex64, sarray("hex"), varray());
+ bind_static_method(Color, html, sarray("rgba"), varray());
+ bind_static_method(Color, html_is_valid, sarray("color"), varray());
+ bind_static_method(Color, find_named_color, sarray("name"), varray());
+ bind_static_method(Color, get_named_color_count, sarray(), varray());
+ bind_static_method(Color, get_named_color_name, sarray("idx"), varray());
+ bind_static_method(Color, get_named_color, sarray("idx"), varray());
+ bind_static_method(Color, from_string, sarray("str", "default"), varray());
+ bind_static_method(Color, from_rgbe9995, sarray("rgbe"), varray());
+
/* RID */
bind_method(RID, get_id, sarray(), varray());
@@ -1256,7 +1616,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform, rotated, sarray("axis", "phi"), varray());
bind_method(Transform, scaled, sarray("scale"), varray());
bind_method(Transform, translated, sarray("offset"), varray());
- bind_method(Transform, looking_at, sarray("target", "up"), varray());
+ bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform, is_equal_approx, sarray("xform"), varray());
@@ -1287,6 +1647,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, resize, sarray("size"), varray());
bind_method(Array, insert, sarray("position", "value"), varray());
bind_method(Array, remove, sarray("position"), varray());
+ bind_method(Array, fill, sarray("value"), varray());
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
@@ -1302,7 +1663,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, shuffle, sarray(), varray());
bind_method(Array, bsearch, sarray("value", "before"), varray(true));
bind_method(Array, bsearch_custom, sarray("value", "func", "before"), varray(true));
- bind_method(Array, invert, sarray(), varray());
+ bind_method(Array, reverse, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
bind_method(Array, max, sarray(), varray());
@@ -1317,9 +1678,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, append_array, sarray("array"), varray());
bind_method(PackedByteArray, remove, sarray("index"), varray());
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedByteArray, fill, sarray("value"), varray());
bind_method(PackedByteArray, resize, sarray("new_size"), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
- bind_method(PackedByteArray, invert, sarray(), varray());
+ bind_method(PackedByteArray, reverse, sarray(), varray());
bind_method(PackedByteArray, subarray, sarray("from", "to"), varray());
bind_method(PackedByteArray, sort, sarray(), varray());
bind_method(PackedByteArray, duplicate, sarray(), varray());
@@ -1333,6 +1695,34 @@ static void _register_variant_builtin_methods() {
bind_function(PackedByteArray, decompress, _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0));
bind_function(PackedByteArray, decompress_dynamic, _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0));
+ bind_function(PackedByteArray, decode_u8, _VariantCall::func_PackedByteArray_decode_u8, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s8, _VariantCall::func_PackedByteArray_decode_s8, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u16, _VariantCall::func_PackedByteArray_decode_u16, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s16, _VariantCall::func_PackedByteArray_decode_s16, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u32, _VariantCall::func_PackedByteArray_decode_u32, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s32, _VariantCall::func_PackedByteArray_decode_s32, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u64, _VariantCall::func_PackedByteArray_decode_u64, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s64, _VariantCall::func_PackedByteArray_decode_s64, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_half, _VariantCall::func_PackedByteArray_decode_half, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_float, _VariantCall::func_PackedByteArray_decode_float, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_double, _VariantCall::func_PackedByteArray_decode_double, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, has_encoded_var, _VariantCall::func_PackedByteArray_has_encoded_var, sarray("byte_offset", "allow_objects"), varray(false));
+ bind_function(PackedByteArray, decode_var, _VariantCall::func_PackedByteArray_decode_var, sarray("byte_offset", "allow_objects"), varray(false));
+ bind_function(PackedByteArray, decode_var_size, _VariantCall::func_PackedByteArray_decode_var_size, sarray("byte_offset", "allow_objects"), varray(false));
+
+ bind_functionnc(PackedByteArray, encode_u8, _VariantCall::func_PackedByteArray_encode_u8, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s8, _VariantCall::func_PackedByteArray_encode_s8, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u16, _VariantCall::func_PackedByteArray_encode_u16, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s16, _VariantCall::func_PackedByteArray_encode_s16, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u32, _VariantCall::func_PackedByteArray_encode_u32, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s32, _VariantCall::func_PackedByteArray_encode_s32, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u64, _VariantCall::func_PackedByteArray_encode_u64, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s64, _VariantCall::func_PackedByteArray_encode_s64, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_half, _VariantCall::func_PackedByteArray_encode_half, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_float, _VariantCall::func_PackedByteArray_encode_float, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_double, _VariantCall::func_PackedByteArray_encode_double, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_var, _VariantCall::func_PackedByteArray_encode_var, sarray("byte_offset", "value", "allow_objects"), varray(false));
+
/* Int32 Array */
bind_method(PackedInt32Array, size, sarray(), varray());
@@ -1343,9 +1733,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, append_array, sarray("array"), varray());
bind_method(PackedInt32Array, remove, sarray("index"), varray());
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt32Array, fill, sarray("value"), varray());
bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
- bind_method(PackedInt32Array, invert, sarray(), varray());
+ bind_method(PackedInt32Array, reverse, sarray(), varray());
bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
bind_method(PackedInt32Array, sort, sarray(), varray());
@@ -1361,9 +1752,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, append_array, sarray("array"), varray());
bind_method(PackedInt64Array, remove, sarray("index"), varray());
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt64Array, fill, sarray("value"), varray());
bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
- bind_method(PackedInt64Array, invert, sarray(), varray());
+ bind_method(PackedInt64Array, reverse, sarray(), varray());
bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
bind_method(PackedInt64Array, sort, sarray(), varray());
@@ -1379,9 +1771,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, append_array, sarray("array"), varray());
bind_method(PackedFloat32Array, remove, sarray("index"), varray());
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat32Array, fill, sarray("value"), varray());
bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
- bind_method(PackedFloat32Array, invert, sarray(), varray());
+ bind_method(PackedFloat32Array, reverse, sarray(), varray());
bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat32Array, sort, sarray(), varray());
@@ -1397,9 +1790,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, append_array, sarray("array"), varray());
bind_method(PackedFloat64Array, remove, sarray("index"), varray());
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat64Array, fill, sarray("value"), varray());
bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
- bind_method(PackedFloat64Array, invert, sarray(), varray());
+ bind_method(PackedFloat64Array, reverse, sarray(), varray());
bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat64Array, sort, sarray(), varray());
@@ -1415,9 +1809,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, append_array, sarray("array"), varray());
bind_method(PackedStringArray, remove, sarray("index"), varray());
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedStringArray, fill, sarray("value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
- bind_method(PackedStringArray, invert, sarray(), varray());
+ bind_method(PackedStringArray, reverse, sarray(), varray());
bind_method(PackedStringArray, subarray, sarray("from", "to"), varray());
bind_method(PackedStringArray, to_byte_array, sarray(), varray());
bind_method(PackedStringArray, sort, sarray(), varray());
@@ -1433,9 +1828,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, append_array, sarray("array"), varray());
bind_method(PackedVector2Array, remove, sarray("index"), varray());
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector2Array, fill, sarray("value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
- bind_method(PackedVector2Array, invert, sarray(), varray());
+ bind_method(PackedVector2Array, reverse, sarray(), varray());
bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
bind_method(PackedVector2Array, sort, sarray(), varray());
@@ -1451,9 +1847,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, append_array, sarray("array"), varray());
bind_method(PackedVector3Array, remove, sarray("index"), varray());
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector3Array, fill, sarray("value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
- bind_method(PackedVector3Array, invert, sarray(), varray());
+ bind_method(PackedVector3Array, reverse, sarray(), varray());
bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
bind_method(PackedVector3Array, sort, sarray(), varray());
@@ -1469,9 +1866,10 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, append_array, sarray("array"), varray());
bind_method(PackedColorArray, remove, sarray("index"), varray());
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedColorArray, fill, sarray("value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
- bind_method(PackedColorArray, invert, sarray(), varray());
+ bind_method(PackedColorArray, reverse, sarray(), varray());
bind_method(PackedColorArray, subarray, sarray("from", "to"), varray());
bind_method(PackedColorArray, to_byte_array, sarray(), varray());
bind_method(PackedColorArray, sort, sarray(), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 52f9f6060e..f0c9e52b46 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -773,6 +773,7 @@ void Variant::_unregister_variant_constructors() {
}
void Variant::construct(Variant::Type p_type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
uint32_t s = construct_data[p_type].size();
for (uint32_t i = 0; i < s; i++) {
int argc = construct_data[p_type][i].argument_count;
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 99680539a3..8cfa793c0e 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -1381,10 +1381,10 @@ void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p
}
void Variant::_register_variant_operators() {
- zeromem(operator_return_type_table, sizeof(operator_return_type_table));
- zeromem(operator_evaluator_table, sizeof(operator_evaluator_table));
- zeromem(validated_operator_evaluator_table, sizeof(validated_operator_evaluator_table));
- zeromem(ptr_operator_evaluator_table, sizeof(ptr_operator_evaluator_table));
+ memset(operator_return_type_table, 0, sizeof(operator_return_type_table));
+ memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table));
+ memset(validated_operator_evaluator_table, 0, sizeof(validated_operator_evaluator_table));
+ memset(ptr_operator_evaluator_table, 0, sizeof(ptr_operator_evaluator_table));
register_op<OperatorEvaluatorAdd<int64_t, int64_t, int64_t>>(Variant::OP_ADD, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index ed936c626b..edaeddbf27 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -381,7 +381,6 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.value = num.as_int();
}
return OK;
-
} else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
StringBuffer<> id;
bool first = true;
@@ -508,8 +507,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
} else if (id == "nan") {
value = Math_NAN;
} else if (id == "Vector2") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -534,8 +533,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Vector2i(args[0], args[1]);
} else if (id == "Rect2") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -560,8 +559,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Rect2i(args[0], args[1], args[2], args[3]);
} else if (id == "Vector3") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -586,8 +585,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Vector3i(args[0], args[1], args[2]);
} else if (id == "Transform2D" || id == "Matrix32") { //compatibility
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -603,8 +602,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
m[2] = Vector2(args[4], args[5]);
value = m;
} else if (id == "Plane") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -616,8 +615,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Plane(args[0], args[1], args[2], args[3]);
} else if (id == "Quat") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -629,8 +628,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Quat(args[0], args[1], args[2], args[3]);
} else if (id == "AABB" || id == "Rect3") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -642,8 +641,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5]));
} else if (id == "Basis" || id == "Matrix3") { //compatibility
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -655,8 +654,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
} else if (id == "Transform") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -1006,8 +1005,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = arr;
} else if (id == "PackedVector2Array" || id == "PoolVector2Array" || id == "Vector2Array") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -1024,8 +1023,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = arr;
} else if (id == "PackedVector3Array" || id == "PoolVector3Array" || id == "Vector3Array") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index ea8263402a..9ab8602782 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -875,65 +875,66 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
-#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
- struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- return; \
- } \
- *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- *oob = false; \
- } \
- static void ptr_get(const void *base, int64_t index, void *member) { \
- /* avoid ptrconvert for performance*/ \
- const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
- if (index < 0) \
- index += v.size(); \
- OOB_TEST(index, v.size()); \
- PtrToArg<Variant>::encode(v[index], member); \
- } \
- static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- *valid = false; \
- return; \
- } \
- (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- *oob = false; \
- *valid = true; \
- } \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- return; \
- } \
- (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- *oob = false; \
- } \
- static void ptr_set(void *base, int64_t index, const void *member) { \
- /* avoid ptrconvert for performance*/ \
- m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
- if (index < 0) \
- index += v.size(); \
- OOB_TEST(index, v.size()); \
- v[index] = PtrToArg<Variant>::convert(member); \
- } \
- static Variant::Type get_index_type() { return Variant::NIL; } \
- static uint64_t get_indexed_size(const Variant *base) { return 0; } \
- };
+struct VariantIndexedSetGet_Array {
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ return;
+ }
+ *value = (*VariantGetInternalPtr<Array>::get_ptr(base))[index];
+ *oob = false;
+ }
+ static void ptr_get(const void *base, int64_t index, void *member) {
+ /* avoid ptrconvert for performance*/
+ const Array &v = *reinterpret_cast<const Array *>(base);
+ if (index < 0) {
+ index += v.size();
+ }
+ OOB_TEST(index, v.size());
+ PtrToArg<Variant>::encode(v[index], member);
+ }
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ *valid = false;
+ return;
+ }
+ VariantGetInternalPtr<Array>::get_ptr(base)->set(index, *value);
+ *oob = false;
+ *valid = true;
+ }
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ return;
+ }
+ VariantGetInternalPtr<Array>::get_ptr(base)->set(index, *value);
+ *oob = false;
+ }
+ static void ptr_set(void *base, int64_t index, const void *member) {
+ /* avoid ptrconvert for performance*/
+ Array &v = *reinterpret_cast<Array *>(base);
+ if (index < 0) {
+ index += v.size();
+ }
+ OOB_TEST(index, v.size());
+ v.set(index, PtrToArg<Variant>::convert(member));
+ }
+ static Variant::Type get_index_type() { return Variant::NIL; }
+ static uint64_t get_indexed_size(const Variant *base) { return 0; }
+};
#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
@@ -990,7 +991,6 @@ INDEXED_SETGET_STRUCT_TYPED(PackedVector3Array, Vector3)
INDEXED_SETGET_STRUCT_TYPED(PackedStringArray, String)
INDEXED_SETGET_STRUCT_TYPED(PackedColorArray, Color)
-INDEXED_SETGET_STRUCT_VARIANT(Array)
INDEXED_SETGET_STRUCT_DICT(Dictionary)
struct VariantIndexedSetterGetterInfo {
@@ -1045,6 +1045,7 @@ void register_indexed_setters_getters() {
REGISTER_INDEXED_MEMBER(PackedByteArray);
REGISTER_INDEXED_MEMBER(PackedInt32Array);
REGISTER_INDEXED_MEMBER(PackedInt64Array);
+ REGISTER_INDEXED_MEMBER(PackedFloat32Array);
REGISTER_INDEXED_MEMBER(PackedFloat64Array);
REGISTER_INDEXED_MEMBER(PackedVector2Array);
REGISTER_INDEXED_MEMBER(PackedVector3Array);
@@ -2198,7 +2199,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &
}
return;
case STRING: {
- //this is pretty funny and bizarre, but artists like to use it for typewritter effects
+ //this is pretty funny and bizarre, but artists like to use it for typewriter effects
String sa = *reinterpret_cast<const String *>(a._data._mem);
String sb = *reinterpret_cast<const String *>(b._data._mem);
String dst;
diff --git a/doc/Makefile b/doc/Makefile
index 9534da9bd5..d4bc53bcf9 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -2,6 +2,7 @@ BASEDIR = $(CURDIR)
CLASSES = $(BASEDIR)/classes/ $(BASEDIR)/../modules/
OUTPUTDIR = $(BASEDIR)/_build
TOOLSDIR = $(BASEDIR)/tools
+JSDIR = $(BASEDIR)/../platform/javascript
.ONESHELL:
@@ -16,6 +17,10 @@ doxygen:
rst:
rm -rf $(OUTPUTDIR)/rst
mkdir -p $(OUTPUTDIR)/rst
- pushd $(OUTPUTDIR)/rst
- python3 $(TOOLSDIR)/makerst.py $(CLASSES)
- popd
+ python3 $(TOOLSDIR)/makerst.py -o $(OUTPUTDIR)/rst $(CLASSES)
+
+rstjs:
+ rm -rf $(OUTPUTDIR)/rstjs
+ mkdir -p $(OUTPUTDIR)/rstjs
+ npm --prefix $(JSDIR) ci
+ npm --prefix $(JSDIR) run docs -- --destination $(OUTPUTDIR)/rstjs/html5_shell_classref.rst
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index e5bcc773fe..95108f1613 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -50,7 +50,7 @@
<argument index="0" name="x" type="float">
</argument>
<description>
- Returns the arc cosine of [code]x[/code] in radians. Use to get the angle of cosine [code]x[/code].
+ Returns the arc cosine of [code]x[/code] in radians. Use to get the angle of cosine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method acos] will return [constant @GDScript.NAN].
[codeblock]
# c is 0.523599 or 30 degrees if converted with rad2deg(c)
c = acos(0.866025)
@@ -63,7 +63,7 @@
<argument index="0" name="x" type="float">
</argument>
<description>
- Returns the arc sine of [code]x[/code] in radians. Use to get the angle of sine [code]x[/code].
+ Returns the arc sine of [code]x[/code] in radians. Use to get the angle of sine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method asin] will return [constant @GDScript.NAN].
[codeblock]
# s is 0.523599 or 30 degrees if converted with rad2deg(s)
s = asin(0.5)
@@ -777,7 +777,7 @@
<return type="int">
</return>
<description>
- Returns a random unsigned 32 bit integer. Use remainder to obtain a random value in the interval [code][0, N - 1][/code] (where N is smaller than 2^32).
+ Returns a random unsigned 32-bit integer. Use remainder to obtain a random value in the interval [code][0, N - 1][/code] (where N is smaller than 2^32).
[codeblock]
randi() # Returns random integer between 0 and 2^32 - 1
randi() % 20 # Returns random integer between 0 and 19
@@ -804,10 +804,7 @@
<method name="randomize">
<description>
Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [codeblock]
- func _ready():
- randomize()
- [/codeblock]
+ [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="range_lerp">
@@ -935,7 +932,7 @@
<description>
Returns the result of smoothly interpolating the value of [code]x[/code] between [code]0[/code] and [code]1[/code], based on the where [code]x[/code] lies with respect to the edges [code]from[/code] and [code]to[/code].
The return value is [code]0[/code] if [code]x &lt;= from[/code], and [code]1[/code] if [code]x &gt;= to[/code]. If [code]x[/code] lies between [code]from[/code] and [code]to[/code], the returned value follows an S-shaped curve that maps [code]x[/code] between [code]0[/code] and [code]1[/code].
- This S-shaped curve is the cubic Hermite interpolator, given by [code]f(x) = 3*x^2 - 2*x^3[/code].
+ This S-shaped curve is the cubic Hermite interpolator, given by [code]f(y) = 3*y^2 - 2*y^3[/code] where [code]y = (x-from) / (to-from)[/code].
[codeblock]
smoothstep(0, 2, -5.0) # Returns 0.0
smoothstep(0, 2, 0.5) # Returns 0.15625
@@ -1280,6 +1277,10 @@
<constant name="HORIZONTAL" value="0" enum="Orientation">
General horizontal alignment, usually used for [Separator], [ScrollBar], [Slider], etc.
</constant>
+ <constant name="CLOCKWISE" value="0" enum="ClockDirection">
+ </constant>
+ <constant name="COUNTERCLOCKWISE" value="1" enum="ClockDirection">
+ </constant>
<constant name="HALIGN_LEFT" value="0" enum="HAlign">
Horizontal left alignment, usually for text-derived classes.
</constant>
@@ -1304,730 +1305,730 @@
<constant name="SPKEY" value="16777216">
Keycodes with this bit applied are non-printable.
</constant>
- <constant name="KEY_ESCAPE" value="16777217" enum="KeyList">
+ <constant name="KEY_ESCAPE" value="16777217" enum="Key">
Escape key.
</constant>
- <constant name="KEY_TAB" value="16777218" enum="KeyList">
+ <constant name="KEY_TAB" value="16777218" enum="Key">
Tab key.
</constant>
- <constant name="KEY_BACKTAB" value="16777219" enum="KeyList">
+ <constant name="KEY_BACKTAB" value="16777219" enum="Key">
Shift + Tab key.
</constant>
- <constant name="KEY_BACKSPACE" value="16777220" enum="KeyList">
+ <constant name="KEY_BACKSPACE" value="16777220" enum="Key">
Backspace key.
</constant>
- <constant name="KEY_ENTER" value="16777221" enum="KeyList">
+ <constant name="KEY_ENTER" value="16777221" enum="Key">
Return key (on the main keyboard).
</constant>
- <constant name="KEY_KP_ENTER" value="16777222" enum="KeyList">
+ <constant name="KEY_KP_ENTER" value="16777222" enum="Key">
Enter key on the numeric keypad.
</constant>
- <constant name="KEY_INSERT" value="16777223" enum="KeyList">
+ <constant name="KEY_INSERT" value="16777223" enum="Key">
Insert key.
</constant>
- <constant name="KEY_DELETE" value="16777224" enum="KeyList">
+ <constant name="KEY_DELETE" value="16777224" enum="Key">
Delete key.
</constant>
- <constant name="KEY_PAUSE" value="16777225" enum="KeyList">
+ <constant name="KEY_PAUSE" value="16777225" enum="Key">
Pause key.
</constant>
- <constant name="KEY_PRINT" value="16777226" enum="KeyList">
+ <constant name="KEY_PRINT" value="16777226" enum="Key">
Print Screen key.
</constant>
- <constant name="KEY_SYSREQ" value="16777227" enum="KeyList">
+ <constant name="KEY_SYSREQ" value="16777227" enum="Key">
System Request key.
</constant>
- <constant name="KEY_CLEAR" value="16777228" enum="KeyList">
+ <constant name="KEY_CLEAR" value="16777228" enum="Key">
Clear key.
</constant>
- <constant name="KEY_HOME" value="16777229" enum="KeyList">
+ <constant name="KEY_HOME" value="16777229" enum="Key">
Home key.
</constant>
- <constant name="KEY_END" value="16777230" enum="KeyList">
+ <constant name="KEY_END" value="16777230" enum="Key">
End key.
</constant>
- <constant name="KEY_LEFT" value="16777231" enum="KeyList">
+ <constant name="KEY_LEFT" value="16777231" enum="Key">
Left arrow key.
</constant>
- <constant name="KEY_UP" value="16777232" enum="KeyList">
+ <constant name="KEY_UP" value="16777232" enum="Key">
Up arrow key.
</constant>
- <constant name="KEY_RIGHT" value="16777233" enum="KeyList">
+ <constant name="KEY_RIGHT" value="16777233" enum="Key">
Right arrow key.
</constant>
- <constant name="KEY_DOWN" value="16777234" enum="KeyList">
+ <constant name="KEY_DOWN" value="16777234" enum="Key">
Down arrow key.
</constant>
- <constant name="KEY_PAGEUP" value="16777235" enum="KeyList">
+ <constant name="KEY_PAGEUP" value="16777235" enum="Key">
Page Up key.
</constant>
- <constant name="KEY_PAGEDOWN" value="16777236" enum="KeyList">
+ <constant name="KEY_PAGEDOWN" value="16777236" enum="Key">
Page Down key.
</constant>
- <constant name="KEY_SHIFT" value="16777237" enum="KeyList">
+ <constant name="KEY_SHIFT" value="16777237" enum="Key">
Shift key.
</constant>
- <constant name="KEY_CONTROL" value="16777238" enum="KeyList">
+ <constant name="KEY_CONTROL" value="16777238" enum="Key">
Control key.
</constant>
- <constant name="KEY_META" value="16777239" enum="KeyList">
+ <constant name="KEY_META" value="16777239" enum="Key">
Meta key.
</constant>
- <constant name="KEY_ALT" value="16777240" enum="KeyList">
+ <constant name="KEY_ALT" value="16777240" enum="Key">
Alt key.
</constant>
- <constant name="KEY_CAPSLOCK" value="16777241" enum="KeyList">
+ <constant name="KEY_CAPSLOCK" value="16777241" enum="Key">
Caps Lock key.
</constant>
- <constant name="KEY_NUMLOCK" value="16777242" enum="KeyList">
+ <constant name="KEY_NUMLOCK" value="16777242" enum="Key">
Num Lock key.
</constant>
- <constant name="KEY_SCROLLLOCK" value="16777243" enum="KeyList">
+ <constant name="KEY_SCROLLLOCK" value="16777243" enum="Key">
Scroll Lock key.
</constant>
- <constant name="KEY_F1" value="16777244" enum="KeyList">
+ <constant name="KEY_F1" value="16777244" enum="Key">
F1 key.
</constant>
- <constant name="KEY_F2" value="16777245" enum="KeyList">
+ <constant name="KEY_F2" value="16777245" enum="Key">
F2 key.
</constant>
- <constant name="KEY_F3" value="16777246" enum="KeyList">
+ <constant name="KEY_F3" value="16777246" enum="Key">
F3 key.
</constant>
- <constant name="KEY_F4" value="16777247" enum="KeyList">
+ <constant name="KEY_F4" value="16777247" enum="Key">
F4 key.
</constant>
- <constant name="KEY_F5" value="16777248" enum="KeyList">
+ <constant name="KEY_F5" value="16777248" enum="Key">
F5 key.
</constant>
- <constant name="KEY_F6" value="16777249" enum="KeyList">
+ <constant name="KEY_F6" value="16777249" enum="Key">
F6 key.
</constant>
- <constant name="KEY_F7" value="16777250" enum="KeyList">
+ <constant name="KEY_F7" value="16777250" enum="Key">
F7 key.
</constant>
- <constant name="KEY_F8" value="16777251" enum="KeyList">
+ <constant name="KEY_F8" value="16777251" enum="Key">
F8 key.
</constant>
- <constant name="KEY_F9" value="16777252" enum="KeyList">
+ <constant name="KEY_F9" value="16777252" enum="Key">
F9 key.
</constant>
- <constant name="KEY_F10" value="16777253" enum="KeyList">
+ <constant name="KEY_F10" value="16777253" enum="Key">
F10 key.
</constant>
- <constant name="KEY_F11" value="16777254" enum="KeyList">
+ <constant name="KEY_F11" value="16777254" enum="Key">
F11 key.
</constant>
- <constant name="KEY_F12" value="16777255" enum="KeyList">
+ <constant name="KEY_F12" value="16777255" enum="Key">
F12 key.
</constant>
- <constant name="KEY_F13" value="16777256" enum="KeyList">
+ <constant name="KEY_F13" value="16777256" enum="Key">
F13 key.
</constant>
- <constant name="KEY_F14" value="16777257" enum="KeyList">
+ <constant name="KEY_F14" value="16777257" enum="Key">
F14 key.
</constant>
- <constant name="KEY_F15" value="16777258" enum="KeyList">
+ <constant name="KEY_F15" value="16777258" enum="Key">
F15 key.
</constant>
- <constant name="KEY_F16" value="16777259" enum="KeyList">
+ <constant name="KEY_F16" value="16777259" enum="Key">
F16 key.
</constant>
- <constant name="KEY_KP_MULTIPLY" value="16777345" enum="KeyList">
+ <constant name="KEY_KP_MULTIPLY" value="16777345" enum="Key">
Multiply (*) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_DIVIDE" value="16777346" enum="KeyList">
+ <constant name="KEY_KP_DIVIDE" value="16777346" enum="Key">
Divide (/) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_SUBTRACT" value="16777347" enum="KeyList">
+ <constant name="KEY_KP_SUBTRACT" value="16777347" enum="Key">
Subtract (-) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_PERIOD" value="16777348" enum="KeyList">
+ <constant name="KEY_KP_PERIOD" value="16777348" enum="Key">
Period (.) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_ADD" value="16777349" enum="KeyList">
+ <constant name="KEY_KP_ADD" value="16777349" enum="Key">
Add (+) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_0" value="16777350" enum="KeyList">
+ <constant name="KEY_KP_0" value="16777350" enum="Key">
Number 0 on the numeric keypad.
</constant>
- <constant name="KEY_KP_1" value="16777351" enum="KeyList">
+ <constant name="KEY_KP_1" value="16777351" enum="Key">
Number 1 on the numeric keypad.
</constant>
- <constant name="KEY_KP_2" value="16777352" enum="KeyList">
+ <constant name="KEY_KP_2" value="16777352" enum="Key">
Number 2 on the numeric keypad.
</constant>
- <constant name="KEY_KP_3" value="16777353" enum="KeyList">
+ <constant name="KEY_KP_3" value="16777353" enum="Key">
Number 3 on the numeric keypad.
</constant>
- <constant name="KEY_KP_4" value="16777354" enum="KeyList">
+ <constant name="KEY_KP_4" value="16777354" enum="Key">
Number 4 on the numeric keypad.
</constant>
- <constant name="KEY_KP_5" value="16777355" enum="KeyList">
+ <constant name="KEY_KP_5" value="16777355" enum="Key">
Number 5 on the numeric keypad.
</constant>
- <constant name="KEY_KP_6" value="16777356" enum="KeyList">
+ <constant name="KEY_KP_6" value="16777356" enum="Key">
Number 6 on the numeric keypad.
</constant>
- <constant name="KEY_KP_7" value="16777357" enum="KeyList">
+ <constant name="KEY_KP_7" value="16777357" enum="Key">
Number 7 on the numeric keypad.
</constant>
- <constant name="KEY_KP_8" value="16777358" enum="KeyList">
+ <constant name="KEY_KP_8" value="16777358" enum="Key">
Number 8 on the numeric keypad.
</constant>
- <constant name="KEY_KP_9" value="16777359" enum="KeyList">
+ <constant name="KEY_KP_9" value="16777359" enum="Key">
Number 9 on the numeric keypad.
</constant>
- <constant name="KEY_SUPER_L" value="16777260" enum="KeyList">
+ <constant name="KEY_SUPER_L" value="16777260" enum="Key">
Left Super key (Windows key).
</constant>
- <constant name="KEY_SUPER_R" value="16777261" enum="KeyList">
+ <constant name="KEY_SUPER_R" value="16777261" enum="Key">
Right Super key (Windows key).
</constant>
- <constant name="KEY_MENU" value="16777262" enum="KeyList">
+ <constant name="KEY_MENU" value="16777262" enum="Key">
Context menu key.
</constant>
- <constant name="KEY_HYPER_L" value="16777263" enum="KeyList">
+ <constant name="KEY_HYPER_L" value="16777263" enum="Key">
Left Hyper key.
</constant>
- <constant name="KEY_HYPER_R" value="16777264" enum="KeyList">
+ <constant name="KEY_HYPER_R" value="16777264" enum="Key">
Right Hyper key.
</constant>
- <constant name="KEY_HELP" value="16777265" enum="KeyList">
+ <constant name="KEY_HELP" value="16777265" enum="Key">
Help key.
</constant>
- <constant name="KEY_DIRECTION_L" value="16777266" enum="KeyList">
+ <constant name="KEY_DIRECTION_L" value="16777266" enum="Key">
Left Direction key.
</constant>
- <constant name="KEY_DIRECTION_R" value="16777267" enum="KeyList">
+ <constant name="KEY_DIRECTION_R" value="16777267" enum="Key">
Right Direction key.
</constant>
- <constant name="KEY_BACK" value="16777280" enum="KeyList">
+ <constant name="KEY_BACK" value="16777280" enum="Key">
Media back key. Not to be confused with the Back button on an Android device.
</constant>
- <constant name="KEY_FORWARD" value="16777281" enum="KeyList">
+ <constant name="KEY_FORWARD" value="16777281" enum="Key">
Media forward key.
</constant>
- <constant name="KEY_STOP" value="16777282" enum="KeyList">
+ <constant name="KEY_STOP" value="16777282" enum="Key">
Media stop key.
</constant>
- <constant name="KEY_REFRESH" value="16777283" enum="KeyList">
+ <constant name="KEY_REFRESH" value="16777283" enum="Key">
Media refresh key.
</constant>
- <constant name="KEY_VOLUMEDOWN" value="16777284" enum="KeyList">
+ <constant name="KEY_VOLUMEDOWN" value="16777284" enum="Key">
Volume down key.
</constant>
- <constant name="KEY_VOLUMEMUTE" value="16777285" enum="KeyList">
+ <constant name="KEY_VOLUMEMUTE" value="16777285" enum="Key">
Mute volume key.
</constant>
- <constant name="KEY_VOLUMEUP" value="16777286" enum="KeyList">
+ <constant name="KEY_VOLUMEUP" value="16777286" enum="Key">
Volume up key.
</constant>
- <constant name="KEY_BASSBOOST" value="16777287" enum="KeyList">
+ <constant name="KEY_BASSBOOST" value="16777287" enum="Key">
Bass Boost key.
</constant>
- <constant name="KEY_BASSUP" value="16777288" enum="KeyList">
+ <constant name="KEY_BASSUP" value="16777288" enum="Key">
Bass up key.
</constant>
- <constant name="KEY_BASSDOWN" value="16777289" enum="KeyList">
+ <constant name="KEY_BASSDOWN" value="16777289" enum="Key">
Bass down key.
</constant>
- <constant name="KEY_TREBLEUP" value="16777290" enum="KeyList">
+ <constant name="KEY_TREBLEUP" value="16777290" enum="Key">
Treble up key.
</constant>
- <constant name="KEY_TREBLEDOWN" value="16777291" enum="KeyList">
+ <constant name="KEY_TREBLEDOWN" value="16777291" enum="Key">
Treble down key.
</constant>
- <constant name="KEY_MEDIAPLAY" value="16777292" enum="KeyList">
+ <constant name="KEY_MEDIAPLAY" value="16777292" enum="Key">
Media play key.
</constant>
- <constant name="KEY_MEDIASTOP" value="16777293" enum="KeyList">
+ <constant name="KEY_MEDIASTOP" value="16777293" enum="Key">
Media stop key.
</constant>
- <constant name="KEY_MEDIAPREVIOUS" value="16777294" enum="KeyList">
+ <constant name="KEY_MEDIAPREVIOUS" value="16777294" enum="Key">
Previous song key.
</constant>
- <constant name="KEY_MEDIANEXT" value="16777295" enum="KeyList">
+ <constant name="KEY_MEDIANEXT" value="16777295" enum="Key">
Next song key.
</constant>
- <constant name="KEY_MEDIARECORD" value="16777296" enum="KeyList">
+ <constant name="KEY_MEDIARECORD" value="16777296" enum="Key">
Media record key.
</constant>
- <constant name="KEY_HOMEPAGE" value="16777297" enum="KeyList">
+ <constant name="KEY_HOMEPAGE" value="16777297" enum="Key">
Home page key.
</constant>
- <constant name="KEY_FAVORITES" value="16777298" enum="KeyList">
+ <constant name="KEY_FAVORITES" value="16777298" enum="Key">
Favorites key.
</constant>
- <constant name="KEY_SEARCH" value="16777299" enum="KeyList">
+ <constant name="KEY_SEARCH" value="16777299" enum="Key">
Search key.
</constant>
- <constant name="KEY_STANDBY" value="16777300" enum="KeyList">
+ <constant name="KEY_STANDBY" value="16777300" enum="Key">
Standby key.
</constant>
- <constant name="KEY_OPENURL" value="16777301" enum="KeyList">
+ <constant name="KEY_OPENURL" value="16777301" enum="Key">
Open URL / Launch Browser key.
</constant>
- <constant name="KEY_LAUNCHMAIL" value="16777302" enum="KeyList">
+ <constant name="KEY_LAUNCHMAIL" value="16777302" enum="Key">
Launch Mail key.
</constant>
- <constant name="KEY_LAUNCHMEDIA" value="16777303" enum="KeyList">
+ <constant name="KEY_LAUNCHMEDIA" value="16777303" enum="Key">
Launch Media key.
</constant>
- <constant name="KEY_LAUNCH0" value="16777304" enum="KeyList">
+ <constant name="KEY_LAUNCH0" value="16777304" enum="Key">
Launch Shortcut 0 key.
</constant>
- <constant name="KEY_LAUNCH1" value="16777305" enum="KeyList">
+ <constant name="KEY_LAUNCH1" value="16777305" enum="Key">
Launch Shortcut 1 key.
</constant>
- <constant name="KEY_LAUNCH2" value="16777306" enum="KeyList">
+ <constant name="KEY_LAUNCH2" value="16777306" enum="Key">
Launch Shortcut 2 key.
</constant>
- <constant name="KEY_LAUNCH3" value="16777307" enum="KeyList">
+ <constant name="KEY_LAUNCH3" value="16777307" enum="Key">
Launch Shortcut 3 key.
</constant>
- <constant name="KEY_LAUNCH4" value="16777308" enum="KeyList">
+ <constant name="KEY_LAUNCH4" value="16777308" enum="Key">
Launch Shortcut 4 key.
</constant>
- <constant name="KEY_LAUNCH5" value="16777309" enum="KeyList">
+ <constant name="KEY_LAUNCH5" value="16777309" enum="Key">
Launch Shortcut 5 key.
</constant>
- <constant name="KEY_LAUNCH6" value="16777310" enum="KeyList">
+ <constant name="KEY_LAUNCH6" value="16777310" enum="Key">
Launch Shortcut 6 key.
</constant>
- <constant name="KEY_LAUNCH7" value="16777311" enum="KeyList">
+ <constant name="KEY_LAUNCH7" value="16777311" enum="Key">
Launch Shortcut 7 key.
</constant>
- <constant name="KEY_LAUNCH8" value="16777312" enum="KeyList">
+ <constant name="KEY_LAUNCH8" value="16777312" enum="Key">
Launch Shortcut 8 key.
</constant>
- <constant name="KEY_LAUNCH9" value="16777313" enum="KeyList">
+ <constant name="KEY_LAUNCH9" value="16777313" enum="Key">
Launch Shortcut 9 key.
</constant>
- <constant name="KEY_LAUNCHA" value="16777314" enum="KeyList">
+ <constant name="KEY_LAUNCHA" value="16777314" enum="Key">
Launch Shortcut A key.
</constant>
- <constant name="KEY_LAUNCHB" value="16777315" enum="KeyList">
+ <constant name="KEY_LAUNCHB" value="16777315" enum="Key">
Launch Shortcut B key.
</constant>
- <constant name="KEY_LAUNCHC" value="16777316" enum="KeyList">
+ <constant name="KEY_LAUNCHC" value="16777316" enum="Key">
Launch Shortcut C key.
</constant>
- <constant name="KEY_LAUNCHD" value="16777317" enum="KeyList">
+ <constant name="KEY_LAUNCHD" value="16777317" enum="Key">
Launch Shortcut D key.
</constant>
- <constant name="KEY_LAUNCHE" value="16777318" enum="KeyList">
+ <constant name="KEY_LAUNCHE" value="16777318" enum="Key">
Launch Shortcut E key.
</constant>
- <constant name="KEY_LAUNCHF" value="16777319" enum="KeyList">
+ <constant name="KEY_LAUNCHF" value="16777319" enum="Key">
Launch Shortcut F key.
</constant>
- <constant name="KEY_UNKNOWN" value="33554431" enum="KeyList">
+ <constant name="KEY_UNKNOWN" value="33554431" enum="Key">
Unknown key.
</constant>
- <constant name="KEY_SPACE" value="32" enum="KeyList">
+ <constant name="KEY_SPACE" value="32" enum="Key">
Space key.
</constant>
- <constant name="KEY_EXCLAM" value="33" enum="KeyList">
+ <constant name="KEY_EXCLAM" value="33" enum="Key">
! key.
</constant>
- <constant name="KEY_QUOTEDBL" value="34" enum="KeyList">
+ <constant name="KEY_QUOTEDBL" value="34" enum="Key">
" key.
</constant>
- <constant name="KEY_NUMBERSIGN" value="35" enum="KeyList">
+ <constant name="KEY_NUMBERSIGN" value="35" enum="Key">
# key.
</constant>
- <constant name="KEY_DOLLAR" value="36" enum="KeyList">
+ <constant name="KEY_DOLLAR" value="36" enum="Key">
$ key.
</constant>
- <constant name="KEY_PERCENT" value="37" enum="KeyList">
+ <constant name="KEY_PERCENT" value="37" enum="Key">
% key.
</constant>
- <constant name="KEY_AMPERSAND" value="38" enum="KeyList">
+ <constant name="KEY_AMPERSAND" value="38" enum="Key">
&amp; key.
</constant>
- <constant name="KEY_APOSTROPHE" value="39" enum="KeyList">
+ <constant name="KEY_APOSTROPHE" value="39" enum="Key">
' key.
</constant>
- <constant name="KEY_PARENLEFT" value="40" enum="KeyList">
+ <constant name="KEY_PARENLEFT" value="40" enum="Key">
( key.
</constant>
- <constant name="KEY_PARENRIGHT" value="41" enum="KeyList">
+ <constant name="KEY_PARENRIGHT" value="41" enum="Key">
) key.
</constant>
- <constant name="KEY_ASTERISK" value="42" enum="KeyList">
+ <constant name="KEY_ASTERISK" value="42" enum="Key">
* key.
</constant>
- <constant name="KEY_PLUS" value="43" enum="KeyList">
+ <constant name="KEY_PLUS" value="43" enum="Key">
+ key.
</constant>
- <constant name="KEY_COMMA" value="44" enum="KeyList">
+ <constant name="KEY_COMMA" value="44" enum="Key">
, key.
</constant>
- <constant name="KEY_MINUS" value="45" enum="KeyList">
+ <constant name="KEY_MINUS" value="45" enum="Key">
- key.
</constant>
- <constant name="KEY_PERIOD" value="46" enum="KeyList">
+ <constant name="KEY_PERIOD" value="46" enum="Key">
. key.
</constant>
- <constant name="KEY_SLASH" value="47" enum="KeyList">
+ <constant name="KEY_SLASH" value="47" enum="Key">
/ key.
</constant>
- <constant name="KEY_0" value="48" enum="KeyList">
+ <constant name="KEY_0" value="48" enum="Key">
Number 0.
</constant>
- <constant name="KEY_1" value="49" enum="KeyList">
+ <constant name="KEY_1" value="49" enum="Key">
Number 1.
</constant>
- <constant name="KEY_2" value="50" enum="KeyList">
+ <constant name="KEY_2" value="50" enum="Key">
Number 2.
</constant>
- <constant name="KEY_3" value="51" enum="KeyList">
+ <constant name="KEY_3" value="51" enum="Key">
Number 3.
</constant>
- <constant name="KEY_4" value="52" enum="KeyList">
+ <constant name="KEY_4" value="52" enum="Key">
Number 4.
</constant>
- <constant name="KEY_5" value="53" enum="KeyList">
+ <constant name="KEY_5" value="53" enum="Key">
Number 5.
</constant>
- <constant name="KEY_6" value="54" enum="KeyList">
+ <constant name="KEY_6" value="54" enum="Key">
Number 6.
</constant>
- <constant name="KEY_7" value="55" enum="KeyList">
+ <constant name="KEY_7" value="55" enum="Key">
Number 7.
</constant>
- <constant name="KEY_8" value="56" enum="KeyList">
+ <constant name="KEY_8" value="56" enum="Key">
Number 8.
</constant>
- <constant name="KEY_9" value="57" enum="KeyList">
+ <constant name="KEY_9" value="57" enum="Key">
Number 9.
</constant>
- <constant name="KEY_COLON" value="58" enum="KeyList">
+ <constant name="KEY_COLON" value="58" enum="Key">
: key.
</constant>
- <constant name="KEY_SEMICOLON" value="59" enum="KeyList">
+ <constant name="KEY_SEMICOLON" value="59" enum="Key">
; key.
</constant>
- <constant name="KEY_LESS" value="60" enum="KeyList">
+ <constant name="KEY_LESS" value="60" enum="Key">
&lt; key.
</constant>
- <constant name="KEY_EQUAL" value="61" enum="KeyList">
+ <constant name="KEY_EQUAL" value="61" enum="Key">
= key.
</constant>
- <constant name="KEY_GREATER" value="62" enum="KeyList">
+ <constant name="KEY_GREATER" value="62" enum="Key">
&gt; key.
</constant>
- <constant name="KEY_QUESTION" value="63" enum="KeyList">
+ <constant name="KEY_QUESTION" value="63" enum="Key">
? key.
</constant>
- <constant name="KEY_AT" value="64" enum="KeyList">
+ <constant name="KEY_AT" value="64" enum="Key">
@ key.
</constant>
- <constant name="KEY_A" value="65" enum="KeyList">
+ <constant name="KEY_A" value="65" enum="Key">
A key.
</constant>
- <constant name="KEY_B" value="66" enum="KeyList">
+ <constant name="KEY_B" value="66" enum="Key">
B key.
</constant>
- <constant name="KEY_C" value="67" enum="KeyList">
+ <constant name="KEY_C" value="67" enum="Key">
C key.
</constant>
- <constant name="KEY_D" value="68" enum="KeyList">
+ <constant name="KEY_D" value="68" enum="Key">
D key.
</constant>
- <constant name="KEY_E" value="69" enum="KeyList">
+ <constant name="KEY_E" value="69" enum="Key">
E key.
</constant>
- <constant name="KEY_F" value="70" enum="KeyList">
+ <constant name="KEY_F" value="70" enum="Key">
F key.
</constant>
- <constant name="KEY_G" value="71" enum="KeyList">
+ <constant name="KEY_G" value="71" enum="Key">
G key.
</constant>
- <constant name="KEY_H" value="72" enum="KeyList">
+ <constant name="KEY_H" value="72" enum="Key">
H key.
</constant>
- <constant name="KEY_I" value="73" enum="KeyList">
+ <constant name="KEY_I" value="73" enum="Key">
I key.
</constant>
- <constant name="KEY_J" value="74" enum="KeyList">
+ <constant name="KEY_J" value="74" enum="Key">
J key.
</constant>
- <constant name="KEY_K" value="75" enum="KeyList">
+ <constant name="KEY_K" value="75" enum="Key">
K key.
</constant>
- <constant name="KEY_L" value="76" enum="KeyList">
+ <constant name="KEY_L" value="76" enum="Key">
L key.
</constant>
- <constant name="KEY_M" value="77" enum="KeyList">
+ <constant name="KEY_M" value="77" enum="Key">
M key.
</constant>
- <constant name="KEY_N" value="78" enum="KeyList">
+ <constant name="KEY_N" value="78" enum="Key">
N key.
</constant>
- <constant name="KEY_O" value="79" enum="KeyList">
+ <constant name="KEY_O" value="79" enum="Key">
O key.
</constant>
- <constant name="KEY_P" value="80" enum="KeyList">
+ <constant name="KEY_P" value="80" enum="Key">
P key.
</constant>
- <constant name="KEY_Q" value="81" enum="KeyList">
+ <constant name="KEY_Q" value="81" enum="Key">
Q key.
</constant>
- <constant name="KEY_R" value="82" enum="KeyList">
+ <constant name="KEY_R" value="82" enum="Key">
R key.
</constant>
- <constant name="KEY_S" value="83" enum="KeyList">
+ <constant name="KEY_S" value="83" enum="Key">
S key.
</constant>
- <constant name="KEY_T" value="84" enum="KeyList">
+ <constant name="KEY_T" value="84" enum="Key">
T key.
</constant>
- <constant name="KEY_U" value="85" enum="KeyList">
+ <constant name="KEY_U" value="85" enum="Key">
U key.
</constant>
- <constant name="KEY_V" value="86" enum="KeyList">
+ <constant name="KEY_V" value="86" enum="Key">
V key.
</constant>
- <constant name="KEY_W" value="87" enum="KeyList">
+ <constant name="KEY_W" value="87" enum="Key">
W key.
</constant>
- <constant name="KEY_X" value="88" enum="KeyList">
+ <constant name="KEY_X" value="88" enum="Key">
X key.
</constant>
- <constant name="KEY_Y" value="89" enum="KeyList">
+ <constant name="KEY_Y" value="89" enum="Key">
Y key.
</constant>
- <constant name="KEY_Z" value="90" enum="KeyList">
+ <constant name="KEY_Z" value="90" enum="Key">
Z key.
</constant>
- <constant name="KEY_BRACKETLEFT" value="91" enum="KeyList">
+ <constant name="KEY_BRACKETLEFT" value="91" enum="Key">
[ key.
</constant>
- <constant name="KEY_BACKSLASH" value="92" enum="KeyList">
+ <constant name="KEY_BACKSLASH" value="92" enum="Key">
\ key.
</constant>
- <constant name="KEY_BRACKETRIGHT" value="93" enum="KeyList">
+ <constant name="KEY_BRACKETRIGHT" value="93" enum="Key">
] key.
</constant>
- <constant name="KEY_ASCIICIRCUM" value="94" enum="KeyList">
+ <constant name="KEY_ASCIICIRCUM" value="94" enum="Key">
^ key.
</constant>
- <constant name="KEY_UNDERSCORE" value="95" enum="KeyList">
+ <constant name="KEY_UNDERSCORE" value="95" enum="Key">
_ key.
</constant>
- <constant name="KEY_QUOTELEFT" value="96" enum="KeyList">
+ <constant name="KEY_QUOTELEFT" value="96" enum="Key">
` key.
</constant>
- <constant name="KEY_BRACELEFT" value="123" enum="KeyList">
+ <constant name="KEY_BRACELEFT" value="123" enum="Key">
{ key.
</constant>
- <constant name="KEY_BAR" value="124" enum="KeyList">
+ <constant name="KEY_BAR" value="124" enum="Key">
| key.
</constant>
- <constant name="KEY_BRACERIGHT" value="125" enum="KeyList">
+ <constant name="KEY_BRACERIGHT" value="125" enum="Key">
} key.
</constant>
- <constant name="KEY_ASCIITILDE" value="126" enum="KeyList">
+ <constant name="KEY_ASCIITILDE" value="126" enum="Key">
~ key.
</constant>
- <constant name="KEY_NOBREAKSPACE" value="160" enum="KeyList">
+ <constant name="KEY_NOBREAKSPACE" value="160" enum="Key">
Non-breakable space key.
</constant>
- <constant name="KEY_EXCLAMDOWN" value="161" enum="KeyList">
+ <constant name="KEY_EXCLAMDOWN" value="161" enum="Key">
¡ key.
</constant>
- <constant name="KEY_CENT" value="162" enum="KeyList">
+ <constant name="KEY_CENT" value="162" enum="Key">
¢ key.
</constant>
- <constant name="KEY_STERLING" value="163" enum="KeyList">
+ <constant name="KEY_STERLING" value="163" enum="Key">
£ key.
</constant>
- <constant name="KEY_CURRENCY" value="164" enum="KeyList">
+ <constant name="KEY_CURRENCY" value="164" enum="Key">
¤ key.
</constant>
- <constant name="KEY_YEN" value="165" enum="KeyList">
+ <constant name="KEY_YEN" value="165" enum="Key">
¥ key.
</constant>
- <constant name="KEY_BROKENBAR" value="166" enum="KeyList">
+ <constant name="KEY_BROKENBAR" value="166" enum="Key">
¦ key.
</constant>
- <constant name="KEY_SECTION" value="167" enum="KeyList">
+ <constant name="KEY_SECTION" value="167" enum="Key">
§ key.
</constant>
- <constant name="KEY_DIAERESIS" value="168" enum="KeyList">
+ <constant name="KEY_DIAERESIS" value="168" enum="Key">
¨ key.
</constant>
- <constant name="KEY_COPYRIGHT" value="169" enum="KeyList">
+ <constant name="KEY_COPYRIGHT" value="169" enum="Key">
© key.
</constant>
- <constant name="KEY_ORDFEMININE" value="170" enum="KeyList">
+ <constant name="KEY_ORDFEMININE" value="170" enum="Key">
ª key.
</constant>
- <constant name="KEY_GUILLEMOTLEFT" value="171" enum="KeyList">
+ <constant name="KEY_GUILLEMOTLEFT" value="171" enum="Key">
« key.
</constant>
- <constant name="KEY_NOTSIGN" value="172" enum="KeyList">
+ <constant name="KEY_NOTSIGN" value="172" enum="Key">
¬ key.
</constant>
- <constant name="KEY_HYPHEN" value="173" enum="KeyList">
+ <constant name="KEY_HYPHEN" value="173" enum="Key">
Soft hyphen key.
</constant>
- <constant name="KEY_REGISTERED" value="174" enum="KeyList">
+ <constant name="KEY_REGISTERED" value="174" enum="Key">
® key.
</constant>
- <constant name="KEY_MACRON" value="175" enum="KeyList">
+ <constant name="KEY_MACRON" value="175" enum="Key">
¯ key.
</constant>
- <constant name="KEY_DEGREE" value="176" enum="KeyList">
+ <constant name="KEY_DEGREE" value="176" enum="Key">
° key.
</constant>
- <constant name="KEY_PLUSMINUS" value="177" enum="KeyList">
+ <constant name="KEY_PLUSMINUS" value="177" enum="Key">
± key.
</constant>
- <constant name="KEY_TWOSUPERIOR" value="178" enum="KeyList">
+ <constant name="KEY_TWOSUPERIOR" value="178" enum="Key">
² key.
</constant>
- <constant name="KEY_THREESUPERIOR" value="179" enum="KeyList">
+ <constant name="KEY_THREESUPERIOR" value="179" enum="Key">
³ key.
</constant>
- <constant name="KEY_ACUTE" value="180" enum="KeyList">
+ <constant name="KEY_ACUTE" value="180" enum="Key">
´ key.
</constant>
- <constant name="KEY_MU" value="181" enum="KeyList">
+ <constant name="KEY_MU" value="181" enum="Key">
µ key.
</constant>
- <constant name="KEY_PARAGRAPH" value="182" enum="KeyList">
+ <constant name="KEY_PARAGRAPH" value="182" enum="Key">
¶ key.
</constant>
- <constant name="KEY_PERIODCENTERED" value="183" enum="KeyList">
+ <constant name="KEY_PERIODCENTERED" value="183" enum="Key">
· key.
</constant>
- <constant name="KEY_CEDILLA" value="184" enum="KeyList">
+ <constant name="KEY_CEDILLA" value="184" enum="Key">
¸ key.
</constant>
- <constant name="KEY_ONESUPERIOR" value="185" enum="KeyList">
+ <constant name="KEY_ONESUPERIOR" value="185" enum="Key">
¹ key.
</constant>
- <constant name="KEY_MASCULINE" value="186" enum="KeyList">
+ <constant name="KEY_MASCULINE" value="186" enum="Key">
º key.
</constant>
- <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="KeyList">
+ <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="Key">
» key.
</constant>
- <constant name="KEY_ONEQUARTER" value="188" enum="KeyList">
+ <constant name="KEY_ONEQUARTER" value="188" enum="Key">
¼ key.
</constant>
- <constant name="KEY_ONEHALF" value="189" enum="KeyList">
+ <constant name="KEY_ONEHALF" value="189" enum="Key">
½ key.
</constant>
- <constant name="KEY_THREEQUARTERS" value="190" enum="KeyList">
+ <constant name="KEY_THREEQUARTERS" value="190" enum="Key">
¾ key.
</constant>
- <constant name="KEY_QUESTIONDOWN" value="191" enum="KeyList">
+ <constant name="KEY_QUESTIONDOWN" value="191" enum="Key">
¿ key.
</constant>
- <constant name="KEY_AGRAVE" value="192" enum="KeyList">
+ <constant name="KEY_AGRAVE" value="192" enum="Key">
À key.
</constant>
- <constant name="KEY_AACUTE" value="193" enum="KeyList">
+ <constant name="KEY_AACUTE" value="193" enum="Key">
Á key.
</constant>
- <constant name="KEY_ACIRCUMFLEX" value="194" enum="KeyList">
+ <constant name="KEY_ACIRCUMFLEX" value="194" enum="Key">
 key.
</constant>
- <constant name="KEY_ATILDE" value="195" enum="KeyList">
+ <constant name="KEY_ATILDE" value="195" enum="Key">
à key.
</constant>
- <constant name="KEY_ADIAERESIS" value="196" enum="KeyList">
+ <constant name="KEY_ADIAERESIS" value="196" enum="Key">
Ä key.
</constant>
- <constant name="KEY_ARING" value="197" enum="KeyList">
+ <constant name="KEY_ARING" value="197" enum="Key">
Å key.
</constant>
- <constant name="KEY_AE" value="198" enum="KeyList">
+ <constant name="KEY_AE" value="198" enum="Key">
Æ key.
</constant>
- <constant name="KEY_CCEDILLA" value="199" enum="KeyList">
+ <constant name="KEY_CCEDILLA" value="199" enum="Key">
Ç key.
</constant>
- <constant name="KEY_EGRAVE" value="200" enum="KeyList">
+ <constant name="KEY_EGRAVE" value="200" enum="Key">
È key.
</constant>
- <constant name="KEY_EACUTE" value="201" enum="KeyList">
+ <constant name="KEY_EACUTE" value="201" enum="Key">
É key.
</constant>
- <constant name="KEY_ECIRCUMFLEX" value="202" enum="KeyList">
+ <constant name="KEY_ECIRCUMFLEX" value="202" enum="Key">
Ê key.
</constant>
- <constant name="KEY_EDIAERESIS" value="203" enum="KeyList">
+ <constant name="KEY_EDIAERESIS" value="203" enum="Key">
Ë key.
</constant>
- <constant name="KEY_IGRAVE" value="204" enum="KeyList">
+ <constant name="KEY_IGRAVE" value="204" enum="Key">
Ì key.
</constant>
- <constant name="KEY_IACUTE" value="205" enum="KeyList">
+ <constant name="KEY_IACUTE" value="205" enum="Key">
Í key.
</constant>
- <constant name="KEY_ICIRCUMFLEX" value="206" enum="KeyList">
+ <constant name="KEY_ICIRCUMFLEX" value="206" enum="Key">
Î key.
</constant>
- <constant name="KEY_IDIAERESIS" value="207" enum="KeyList">
+ <constant name="KEY_IDIAERESIS" value="207" enum="Key">
Ï key.
</constant>
- <constant name="KEY_ETH" value="208" enum="KeyList">
+ <constant name="KEY_ETH" value="208" enum="Key">
Ð key.
</constant>
- <constant name="KEY_NTILDE" value="209" enum="KeyList">
+ <constant name="KEY_NTILDE" value="209" enum="Key">
Ñ key.
</constant>
- <constant name="KEY_OGRAVE" value="210" enum="KeyList">
+ <constant name="KEY_OGRAVE" value="210" enum="Key">
Ò key.
</constant>
- <constant name="KEY_OACUTE" value="211" enum="KeyList">
+ <constant name="KEY_OACUTE" value="211" enum="Key">
Ó key.
</constant>
- <constant name="KEY_OCIRCUMFLEX" value="212" enum="KeyList">
+ <constant name="KEY_OCIRCUMFLEX" value="212" enum="Key">
Ô key.
</constant>
- <constant name="KEY_OTILDE" value="213" enum="KeyList">
+ <constant name="KEY_OTILDE" value="213" enum="Key">
Õ key.
</constant>
- <constant name="KEY_ODIAERESIS" value="214" enum="KeyList">
+ <constant name="KEY_ODIAERESIS" value="214" enum="Key">
Ö key.
</constant>
- <constant name="KEY_MULTIPLY" value="215" enum="KeyList">
+ <constant name="KEY_MULTIPLY" value="215" enum="Key">
× key.
</constant>
- <constant name="KEY_OOBLIQUE" value="216" enum="KeyList">
+ <constant name="KEY_OOBLIQUE" value="216" enum="Key">
Ø key.
</constant>
- <constant name="KEY_UGRAVE" value="217" enum="KeyList">
+ <constant name="KEY_UGRAVE" value="217" enum="Key">
Ù key.
</constant>
- <constant name="KEY_UACUTE" value="218" enum="KeyList">
+ <constant name="KEY_UACUTE" value="218" enum="Key">
Ú key.
</constant>
- <constant name="KEY_UCIRCUMFLEX" value="219" enum="KeyList">
+ <constant name="KEY_UCIRCUMFLEX" value="219" enum="Key">
Û key.
</constant>
- <constant name="KEY_UDIAERESIS" value="220" enum="KeyList">
+ <constant name="KEY_UDIAERESIS" value="220" enum="Key">
Ü key.
</constant>
- <constant name="KEY_YACUTE" value="221" enum="KeyList">
+ <constant name="KEY_YACUTE" value="221" enum="Key">
Ý key.
</constant>
- <constant name="KEY_THORN" value="222" enum="KeyList">
+ <constant name="KEY_THORN" value="222" enum="Key">
Þ key.
</constant>
- <constant name="KEY_SSHARP" value="223" enum="KeyList">
+ <constant name="KEY_SSHARP" value="223" enum="Key">
ß key.
</constant>
- <constant name="KEY_DIVISION" value="247" enum="KeyList">
+ <constant name="KEY_DIVISION" value="247" enum="Key">
÷ key.
</constant>
- <constant name="KEY_YDIAERESIS" value="255" enum="KeyList">
+ <constant name="KEY_YDIAERESIS" value="255" enum="Key">
ÿ key.
</constant>
<constant name="KEY_CODE_MASK" value="33554431" enum="KeyModifierMask">
@@ -2057,166 +2058,166 @@
<constant name="KEY_MASK_GROUP_SWITCH" value="1073741824" enum="KeyModifierMask">
Group Switch key mask.
</constant>
- <constant name="BUTTON_LEFT" value="1" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_LEFT" value="1" enum="MouseButton">
Left mouse button.
</constant>
- <constant name="BUTTON_RIGHT" value="2" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_RIGHT" value="2" enum="MouseButton">
Right mouse button.
</constant>
- <constant name="BUTTON_MIDDLE" value="3" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MIDDLE" value="3" enum="MouseButton">
Middle mouse button.
</constant>
- <constant name="BUTTON_XBUTTON1" value="8" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_XBUTTON1" value="8" enum="MouseButton">
Extra mouse button 1 (only present on some mice).
</constant>
- <constant name="BUTTON_XBUTTON2" value="9" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_XBUTTON2" value="9" enum="MouseButton">
Extra mouse button 2 (only present on some mice).
</constant>
- <constant name="BUTTON_WHEEL_UP" value="4" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_UP" value="4" enum="MouseButton">
Mouse wheel up.
</constant>
- <constant name="BUTTON_WHEEL_DOWN" value="5" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_DOWN" value="5" enum="MouseButton">
Mouse wheel down.
</constant>
- <constant name="BUTTON_WHEEL_LEFT" value="6" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_LEFT" value="6" enum="MouseButton">
Mouse wheel left button (only present on some mice).
</constant>
- <constant name="BUTTON_WHEEL_RIGHT" value="7" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_RIGHT" value="7" enum="MouseButton">
Mouse wheel right button (only present on some mice).
</constant>
- <constant name="BUTTON_MASK_LEFT" value="1" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_LEFT" value="1" enum="MouseButton">
Left mouse button mask.
</constant>
- <constant name="BUTTON_MASK_RIGHT" value="2" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_RIGHT" value="2" enum="MouseButton">
Right mouse button mask.
</constant>
- <constant name="BUTTON_MASK_MIDDLE" value="4" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_MIDDLE" value="4" enum="MouseButton">
Middle mouse button mask.
</constant>
- <constant name="BUTTON_MASK_XBUTTON1" value="128" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_XBUTTON1" value="128" enum="MouseButton">
Extra mouse button 1 mask.
</constant>
- <constant name="BUTTON_MASK_XBUTTON2" value="256" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_XBUTTON2" value="256" enum="MouseButton">
Extra mouse button 2 mask.
</constant>
- <constant name="JOY_BUTTON_INVALID" value="-1" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_INVALID" value="-1" enum="JoyButton">
An invalid game controller button.
</constant>
- <constant name="JOY_BUTTON_A" value="0" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_A" value="0" enum="JoyButton">
Game controller SDL button A. Corresponds to the bottom action button: Sony Cross, Xbox A, Nintendo B.
</constant>
- <constant name="JOY_BUTTON_B" value="1" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_B" value="1" enum="JoyButton">
Game controller SDL button B. Corresponds to the right action button: Sony Circle, Xbox B, Nintendo A.
</constant>
- <constant name="JOY_BUTTON_X" value="2" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_X" value="2" enum="JoyButton">
Game controller SDL button X. Corresponds to the left action button: Sony Square, Xbox X, Nintendo Y.
</constant>
- <constant name="JOY_BUTTON_Y" value="3" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_Y" value="3" enum="JoyButton">
Game controller SDL button Y. Corresponds to the top action button: Sony Triangle, Xbox Y, Nintendo X.
</constant>
- <constant name="JOY_BUTTON_BACK" value="4" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_BACK" value="4" enum="JoyButton">
Game controller SDL back button. Corresponds to the Sony Select, Xbox Back, Nintendo - button.
</constant>
- <constant name="JOY_BUTTON_GUIDE" value="5" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_GUIDE" value="5" enum="JoyButton">
Game controller SDL guide button. Corresponds to the Sony PS, Xbox Home button.
</constant>
- <constant name="JOY_BUTTON_START" value="6" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_START" value="6" enum="JoyButton">
Game controller SDL start button. Corresponds to the Nintendo + button.
</constant>
- <constant name="JOY_BUTTON_LEFT_STICK" value="7" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_LEFT_STICK" value="7" enum="JoyButton">
Game controller SDL left stick button. Corresponds to the Sony L3, Xbox L/LS button.
</constant>
- <constant name="JOY_BUTTON_RIGHT_STICK" value="8" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_RIGHT_STICK" value="8" enum="JoyButton">
Game controller SDL right stick button. Corresponds to the Sony R3, Xbox R/RS button.
</constant>
- <constant name="JOY_BUTTON_LEFT_SHOULDER" value="9" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_LEFT_SHOULDER" value="9" enum="JoyButton">
Game controller SDL left shoulder button. Corresponds to the Sony L1, Xbox LB button.
</constant>
- <constant name="JOY_BUTTON_RIGHT_SHOULDER" value="10" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_RIGHT_SHOULDER" value="10" enum="JoyButton">
Game controller SDL right shoulder button. Corresponds to the Sony R1, Xbox RB button.
</constant>
- <constant name="JOY_BUTTON_DPAD_UP" value="11" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_UP" value="11" enum="JoyButton">
Game controller D-pad up button.
</constant>
- <constant name="JOY_BUTTON_DPAD_DOWN" value="12" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_DOWN" value="12" enum="JoyButton">
Game controller D-pad down button.
</constant>
- <constant name="JOY_BUTTON_DPAD_LEFT" value="13" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_LEFT" value="13" enum="JoyButton">
Game controller D-pad left button.
</constant>
- <constant name="JOY_BUTTON_DPAD_RIGHT" value="14" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_RIGHT" value="14" enum="JoyButton">
Game controller D-pad right button.
</constant>
- <constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButton">
Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo capture button.
</constant>
- <constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButton">
Game controller SDL paddle 1 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE2" value="17" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE2" value="17" enum="JoyButton">
Game controller SDL paddle 2 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE3" value="18" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE3" value="18" enum="JoyButton">
Game controller SDL paddle 3 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE4" value="19" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE4" value="19" enum="JoyButton">
Game controller SDL paddle 4 button.
</constant>
- <constant name="JOY_BUTTON_TOUCHPAD" value="20" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_TOUCHPAD" value="20" enum="JoyButton">
Game controller SDL touchpad button.
</constant>
- <constant name="JOY_BUTTON_SDL_MAX" value="21" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_SDL_MAX" value="21" enum="JoyButton">
The number of SDL game controller buttons.
</constant>
- <constant name="JOY_BUTTON_MAX" value="36" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_MAX" value="36" enum="JoyButton">
The maximum number of game controller buttons: Android supports up to 36 buttons.
</constant>
- <constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxisList">
+ <constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxis">
An invalid game controller axis.
</constant>
- <constant name="JOY_AXIS_LEFT_X" value="0" enum="JoyAxisList">
+ <constant name="JOY_AXIS_LEFT_X" value="0" enum="JoyAxis">
Game controller left joystick x-axis.
</constant>
- <constant name="JOY_AXIS_LEFT_Y" value="1" enum="JoyAxisList">
+ <constant name="JOY_AXIS_LEFT_Y" value="1" enum="JoyAxis">
Game controller left joystick y-axis.
</constant>
- <constant name="JOY_AXIS_RIGHT_X" value="2" enum="JoyAxisList">
+ <constant name="JOY_AXIS_RIGHT_X" value="2" enum="JoyAxis">
Game controller right joystick x-axis.
</constant>
- <constant name="JOY_AXIS_RIGHT_Y" value="3" enum="JoyAxisList">
+ <constant name="JOY_AXIS_RIGHT_Y" value="3" enum="JoyAxis">
Game controller right joystick y-axis.
</constant>
- <constant name="JOY_AXIS_TRIGGER_LEFT" value="4" enum="JoyAxisList">
+ <constant name="JOY_AXIS_TRIGGER_LEFT" value="4" enum="JoyAxis">
Game controller left trigger axis.
</constant>
- <constant name="JOY_AXIS_TRIGGER_RIGHT" value="5" enum="JoyAxisList">
+ <constant name="JOY_AXIS_TRIGGER_RIGHT" value="5" enum="JoyAxis">
Game controller right trigger axis.
</constant>
- <constant name="JOY_AXIS_SDL_MAX" value="6" enum="JoyAxisList">
+ <constant name="JOY_AXIS_SDL_MAX" value="6" enum="JoyAxis">
The number of SDL game controller axes.
</constant>
- <constant name="JOY_AXIS_MAX" value="10" enum="JoyAxisList">
+ <constant name="JOY_AXIS_MAX" value="10" enum="JoyAxis">
The maximum number of game controller axes: OpenVR supports up to 5 Joysticks making a total of 10 axes.
</constant>
- <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MIDIMessage">
MIDI note OFF message.
</constant>
- <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MIDIMessage">
MIDI note ON message.
</constant>
- <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MIDIMessage">
MIDI aftertouch message.
</constant>
- <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MIDIMessage">
MIDI control change message.
</constant>
- <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MIDIMessage">
MIDI program change message.
</constant>
- <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MIDIMessage">
MIDI channel pressure message.
</constant>
- <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MIDIMessage">
MIDI pitch bend message.
</constant>
<constant name="OK" value="0" enum="Error">
@@ -2405,43 +2406,49 @@
<constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="9" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 2D physics layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="10" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="10" enum="PropertyHint">
+ Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
+ </constant>
+ <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="11" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 3D render layers.
</constant>
- <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="11" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="12" enum="PropertyHint">
Hints that an integer property is a bitmask using the optionally named 3D physics layers.
</constant>
- <constant name="PROPERTY_HINT_FILE" value="12" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="13" enum="PropertyHint">
+ Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
+ </constant>
+ <constant name="PROPERTY_HINT_FILE" value="14" enum="PropertyHint">
Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
- <constant name="PROPERTY_HINT_DIR" value="13" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_DIR" value="15" enum="PropertyHint">
Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_FILE" value="14" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_GLOBAL_FILE" value="16" enum="PropertyHint">
Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_DIR" value="15" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_GLOBAL_DIR" value="17" enum="PropertyHint">
Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
</constant>
- <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="16" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="18" enum="PropertyHint">
Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture2D"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
</constant>
- <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="17" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="19" enum="PropertyHint">
Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
</constant>
- <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="18" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="20" enum="PropertyHint">
Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
</constant>
- <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="19" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="21" enum="PropertyHint">
Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="20" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="22" enum="PropertyHint">
Hints that an image is compressed using lossy compression.
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="21" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint">
Hints that an image is compressed using lossless compression.
</constant>
- <constant name="PROPERTY_HINT_TYPE_STRING" value="23" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_TYPE_STRING" value="25" enum="PropertyHint">
Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
[codeblock]
hint_string = "%s:" % [TYPE_INT] # Array of inteters.
@@ -2520,6 +2527,8 @@
<constant name="METHOD_FLAG_FROM_SCRIPT" value="64" enum="MethodFlags">
Deprecated method flag, unused.
</constant>
+ <constant name="METHOD_FLAG_STATIC" value="256" enum="MethodFlags">
+ </constant>
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags">
Default method flags.
</constant>
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 8cd7e6f5fa..a28bde9946 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -41,14 +41,14 @@
Constructs an [AABB] from a position and size.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="AABB">
</return>
<description>
Returns an AABB with equivalent position and size, modified so that the most-negative corner is the origin and the size is positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
@@ -57,7 +57,7 @@
Returns [code]true[/code] if this [AABB] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="to_point" type="Vector3">
@@ -66,14 +66,14 @@
Returns this [AABB] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="float">
</return>
<description>
Returns the volume of the [AABB].
</description>
</method>
- <method name="get_endpoint">
+ <method name="get_endpoint" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -82,49 +82,49 @@
Gets the position of the 8 endpoints of the [AABB] in space.
</description>
</method>
- <method name="get_longest_axis">
+ <method name="get_longest_axis" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the normalized longest axis of the [AABB].
</description>
</method>
- <method name="get_longest_axis_index">
+ <method name="get_longest_axis_index" qualifiers="const">
<return type="int">
</return>
<description>
Returns the index of the longest axis of the [AABB] (according to [Vector3]'s [code]AXIS_*[/code] constants).
</description>
</method>
- <method name="get_longest_axis_size">
+ <method name="get_longest_axis_size" qualifiers="const">
<return type="float">
</return>
<description>
Returns the scalar length of the longest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis">
+ <method name="get_shortest_axis" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the normalized shortest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis_index">
+ <method name="get_shortest_axis_index" qualifiers="const">
<return type="int">
</return>
<description>
Returns the index of the shortest axis of the [AABB] (according to [Vector3]::AXIS* enum).
</description>
</method>
- <method name="get_shortest_axis_size">
+ <method name="get_shortest_axis_size" qualifiers="const">
<return type="float">
</return>
<description>
Returns the scalar length of the shortest axis of the [AABB].
</description>
</method>
- <method name="get_support">
+ <method name="get_support" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="dir" type="Vector3">
@@ -133,7 +133,7 @@
Returns the support point in a given direction. This is useful for collision detection algorithms.
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="by" type="float">
@@ -142,21 +142,21 @@
Returns a copy of the [AABB] grown a given amount of units towards all the sides.
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [AABB] is flat or empty.
</description>
</method>
- <method name="has_no_surface">
+ <method name="has_no_surface" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [AABB] is empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -165,7 +165,7 @@
Returns [code]true[/code] if the [AABB] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
@@ -174,7 +174,7 @@
Returns the intersection between two [AABB]. An empty AABB (size 0,0,0) is returned on failure.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
@@ -183,7 +183,7 @@
Returns [code]true[/code] if the [AABB] overlaps with another.
</description>
</method>
- <method name="intersects_plane">
+ <method name="intersects_plane" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="plane" type="Plane">
@@ -192,7 +192,7 @@
Returns [code]true[/code] if the [AABB] is on both sides of a plane.
</description>
</method>
- <method name="intersects_ray">
+ <method name="intersects_ray" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -202,7 +202,7 @@
<description>
</description>
</method>
- <method name="intersects_segment">
+ <method name="intersects_segment" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -213,7 +213,7 @@
Returns [code]true[/code] if the [AABB] intersects the line segment between [code]from[/code] and [code]to[/code].
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="aabb" type="AABB">
@@ -222,7 +222,7 @@
Returns [code]true[/code] if this [AABB] and [code]aabb[/code] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
@@ -264,7 +264,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml
index bfdc66623d..fce2b90197 100644
--- a/doc/classes/AStar.xml
+++ b/doc/classes/AStar.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AStar" inherits="Reference" version="4.0">
<brief_description>
- An implementation of A* to find shortest paths among connected points in space.
+ An implementation of A* to find the shortest paths among connected points in space.
</brief_description>
<description>
A* (A star) is a computer algorithm that is widely used in pathfinding and graph traversal, the process of plotting short paths among vertices (points), passing through a given set of edges (segments). It enjoys widespread use due to its performance and accuracy. Godot's A* implementation uses points in three-dimensional space and Euclidean distances by default.
@@ -289,6 +289,7 @@
</argument>
<description>
Returns an array with the points that are in the path found by AStar between the given points. The array is ordered from the starting point to the ending point of the path.
+ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 2a51678209..3efd2f604c 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -258,6 +258,7 @@
</argument>
<description>
Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
+ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector2Array] and will print an error message.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index e1fb78e5b5..02ccab4e05 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -49,6 +49,11 @@
</member>
</members>
<signals>
+ <signal name="animation_finished">
+ <description>
+ Emitted when the animation is finished (when it plays the last frame). If the animation is looping, this signal is emitted every time the last frame is drawn.
+ </description>
+ </signal>
<signal name="frame_changed">
<description>
Emitted when [member frame] changed.
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 9720405ffd..7ceb21d22e 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -710,7 +710,7 @@
[b]Note:[/b] Length is not delimited by the last key, as this one may be before or after the end to ensure correct interpolation and looping.
</member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
- A flag indicating that the animation must loop. This is uses for correct interpolation of animation cycles, and for hinting the player that it must restart the animation.
+ A flag indicating that the animation must loop. This is used for correct interpolation of animation cycles, and for hinting the player that it must restart the animation.
</member>
<member name="step" type="float" setter="set_step" getter="get_step" default="0.1">
The animation step value.
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index eb5335c792..171d65fbe0 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -4,7 +4,27 @@
A time-seeking animation node to be used with [AnimationTree].
</brief_description>
<description>
- This node can be used to cause a seek command to happen to any sub-children of the graph. After setting the time, this value returns to -1.
+ This node can be used to cause a seek command to happen to any sub-children of the animation graph. Use this node type to play an [Animation] from the start or a certain playback position inside the [AnimationNodeBlendTree]. After setting the time and changing the animation playback, the seek node automatically goes into sleep mode on the next process frame by setting its [code]seek_position[/code] value to [code]-1.0[/code].
+ [codeblocks]
+ [gdscript]
+ # Play child animation from the start.
+ animation_tree.set("parameters/Seek/seek_position", 0.0)
+ # Alternative syntax (same result as above).
+ animation_tree["parameters/Seek/seek_position"] = 0.0
+
+ # Play child animation from 12 second timestamp.
+ animation_tree.set("parameters/Seek/seek_position", 12.0)
+ # Alternative syntax (same result as above).
+ animation_tree["parameters/Seek/seek_position"] = 12.0
+ [/gdscript]
+ [csharp]
+ // Play child animation from the start.
+ animationTree.Set("parameters/Seek/seek_position", 0.0);
+
+ // Play child animation from 12 second timestamp.
+ animationTree.Set("parameters/Seek/seek_position", 12.0);
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
<link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index bebff61671..7696f36009 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -237,7 +237,7 @@
</member>
<member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation" default="&quot;&quot;">
The name of the currently playing animation. If no animation is playing, the property's value is an empty string. Changing this value does not restart the animation. See [method play] for more information on playing animations.
- [b]Note[/b]: while this property appears in the inspector, it's not meant to be edited and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
+ [b]Note[/b]: while this property appears in the inspector, it's not meant to be edited, and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
</member>
<member name="current_animation_length" type="float" setter="" getter="get_current_animation_length">
The length (in seconds) of the currently being played animation.
@@ -254,7 +254,7 @@
<member name="playback_default_blend_time" type="float" setter="set_default_blend_time" getter="get_default_blend_time" default="0.0">
The default time in which to blend animations. Ranges from 0 to 4096 with 0.01 precision.
</member>
- <member name="playback_process_mode" type="int" setter="set_animation_process_mode" getter="get_animation_process_mode" enum="AnimationPlayer.AnimationProcessMode" default="1">
+ <member name="playback_process_mode" type="int" setter="set_process_callback" getter="get_process_callback" enum="AnimationPlayer.AnimationProcessCallback" default="1">
The process notification in which to update animations.
</member>
<member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
@@ -299,13 +299,13 @@
</signal>
</signals>
<constants>
- <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
Process animation during the physics process. This is especially useful when animating physics bodies.
</constant>
- <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessCallback">
Process animation during the idle process.
</constant>
- <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessCallback">
Do not process animation. Use [method advance] to process the animation manually.
</constant>
<constant name="ANIMATION_METHOD_CALL_DEFERRED" value="0" enum="AnimationMethodCallMode">
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 262b5addb7..2517941133 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -45,8 +45,8 @@
<member name="anim_player" type="NodePath" setter="set_animation_player" getter="get_animation_player" default="NodePath(&quot;&quot;)">
The path to the [AnimationPlayer] used for animating.
</member>
- <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="AnimationTree.AnimationProcessMode" default="1">
- The process mode of this [AnimationTree]. See [enum AnimationProcessMode] for available modes.
+ <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="AnimationTree.AnimationProcessCallback" default="1">
+ The process mode of this [AnimationTree]. See [enum AnimationProcessCallback] for available modes.
</member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
@@ -57,13 +57,13 @@
</member>
</members>
<constants>
- <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
The animations will progress during the physics frame (i.e. [method Node._physics_process]).
</constant>
- <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessCallback">
The animations will progress during the idle frame (i.e. [method Node._process]).
</constant>
- <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode">
+ <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessCallback">
The animations will only progress manually (see [method advance]).
</constant>
</constants>
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index a02f077cf7..a1e522d146 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area2D" inherits="CollisionObject2D" version="4.0">
<brief_description>
- 2D area for detection and 2D physics influence.
+ 2D area for detection and physics and audio influence.
</brief_description>
<description>
- 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
+ 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to a custom audio bus.
</description>
<tutorials>
<link title="Using Area2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html</link>
@@ -13,24 +13,6 @@
<link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the layer mask. Describes whether other areas will collide with this one on the given layer.
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the collision mask. Describes whether this area will collide with others on the given layer.
- </description>
- </method>
<method name="get_overlapping_areas" qualifiers="const">
<return type="Area2D[]">
</return>
@@ -66,28 +48,6 @@
The [code]body[/code] argument can either be a [PhysicsBody2D] or a [TileMap] instance (while TileMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the collision mask. This makes selecting the areas scanned easier.
- </description>
- </method>
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="1.0">
@@ -100,12 +60,6 @@
<member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false">
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
<member name="gravity" type="float" setter="set_gravity" getter="get_gravity" default="98.0">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
</member>
@@ -187,7 +141,7 @@
</description>
</signal>
<signal name="body_entered">
- <argument index="0" name="body" type="Node">
+ <argument index="0" name="body" type="Node2D">
</argument>
<description>
Emitted when a [PhysicsBody2D] or [TileMap] enters this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
@@ -195,7 +149,7 @@
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node">
+ <argument index="0" name="body" type="Node2D">
</argument>
<description>
Emitted when a [PhysicsBody2D] or [TileMap] exits this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
@@ -205,7 +159,7 @@
<signal name="body_shape_entered">
<argument index="0" name="body_id" type="int">
</argument>
- <argument index="1" name="body" type="Node">
+ <argument index="1" name="body" type="Node2D">
</argument>
<argument index="2" name="body_shape" type="int">
</argument>
@@ -222,7 +176,7 @@
<signal name="body_shape_exited">
<argument index="0" name="body_id" type="int">
</argument>
- <argument index="1" name="body" type="Node">
+ <argument index="1" name="body" type="Node2D">
</argument>
<argument index="2" name="body_shape" type="int">
</argument>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index bd43d619dd..e69a89a836 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -1,34 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area3D" inherits="CollisionObject3D" version="4.0">
<brief_description>
- General-purpose area node for detection and 3D physics influence.
+ 3D area for detection and physics and audio influence.
</brief_description>
<description>
- 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
+ 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses.
</description>
<tutorials>
<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the layer mask.
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the collision mask.
- </description>
- </method>
<method name="get_overlapping_areas" qualifiers="const">
<return type="Area3D[]">
</return>
@@ -64,28 +46,6 @@
The [code]body[/code] argument can either be a [PhysicsBody3D] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the layer mask. This simplifies editing this [Area3D]'s layers.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the collision mask. This simplifies editing which [Area3D] layers this [Area3D] scans.
- </description>
- </method>
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.1">
@@ -98,12 +58,6 @@
<member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false">
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
<member name="gravity" type="float" setter="set_gravity" getter="get_gravity" default="9.8">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
</member>
@@ -197,7 +151,7 @@
</description>
</signal>
<signal name="body_entered">
- <argument index="0" name="body" type="Node">
+ <argument index="0" name="body" type="Node3D">
</argument>
<description>
Emitted when a [PhysicsBody3D] or [GridMap] enters this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
@@ -205,7 +159,7 @@
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node">
+ <argument index="0" name="body" type="Node3D">
</argument>
<description>
Emitted when a [PhysicsBody3D] or [GridMap] exits this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
@@ -215,7 +169,7 @@
<signal name="body_shape_entered">
<argument index="0" name="body_id" type="int">
</argument>
- <argument index="1" name="body" type="Node">
+ <argument index="1" name="body" type="Node3D">
</argument>
<argument index="2" name="body_shape" type="int">
</argument>
@@ -232,7 +186,7 @@
<signal name="body_shape_exited">
<argument index="0" name="body_id" type="int">
</argument>
- <argument index="1" name="body" type="Node">
+ <argument index="1" name="body" type="Node3D">
</argument>
<argument index="2" name="body_shape" type="int">
</argument>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index cea5360234..38b74cb436 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -166,7 +166,7 @@
[/codeblock]
</description>
</method>
- <method name="back">
+ <method name="back" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -197,7 +197,7 @@
</argument>
<description>
Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search and a custom comparison method. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array. The custom method receives two arguments (an element from the array and the value searched for) and must return [code]true[/code] if the first argument is less than the second, and return [code]false[/code] otherwise.
- [b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
+ [b]Note:[/b] Calling [method bsearch_custom] on an unsorted array results in unexpected behavior.
</description>
</method>
<method name="clear">
@@ -207,7 +207,7 @@
Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
</description>
</method>
- <method name="count">
+ <method name="count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="value" type="Variant">
@@ -216,7 +216,7 @@
Returns the number of times an element is in the array.
</description>
</method>
- <method name="duplicate">
+ <method name="duplicate" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="deep" type="bool" default="false">
@@ -237,7 +237,28 @@
[b]Note:[/b] On large arrays, this method will be slower if the removed element is close to the beginning of the array (index 0). This is because all elements placed after the removed element have to be reindexed.
</description>
</method>
- <method name="find">
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Variant">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements:
+ [codeblocks]
+ [gdscript]
+ var array = []
+ array.resize(10)
+ array.fill(0) # Initialize the 10 elements to 0.
+ [/gdscript]
+ [csharp]
+ var array = new Godot.Collections.Array{};
+ array.Resize(10);
+ array.Fill(0); // Initialize the 10 elements to 0.
+ [/csharp]
+ [/codeblocks]
+ </description>
+ </method>
+ <method name="find" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="Variant">
@@ -248,7 +269,7 @@
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
- <method name="find_last">
+ <method name="find_last" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="value" type="Variant">
@@ -257,7 +278,7 @@
Searches the array in reverse order for a value and returns its index or [code]-1[/code] if not found.
</description>
</method>
- <method name="front">
+ <method name="front" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -265,7 +286,7 @@
[b]Note:[/b] Calling this function is not the same as writing [code]array[0][/code]. If the array is empty, accessing by index will pause project execution when running from the editor.
</description>
</method>
- <method name="has">
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="value" type="Variant">
@@ -307,7 +328,7 @@
[/codeblocks]
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
@@ -328,28 +349,21 @@
[b]Note:[/b] On large arrays, this method will be slower if the inserted element is close to the beginning of the array (index 0). This is because all elements placed after the newly inserted element have to be reindexed.
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the array is empty.
</description>
</method>
- <method name="max">
+ <method name="max" qualifiers="const">
<return type="Variant">
</return>
<description>
Returns the maximum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
</description>
</method>
- <method name="min">
+ <method name="min" qualifiers="const">
<return type="Variant">
</return>
<description>
@@ -474,7 +488,14 @@
Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are [code]null[/code].
</description>
</method>
- <method name="rfind">
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
+ <method name="rfind" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="Variant">
@@ -492,14 +513,14 @@
Shuffles the array such that the items will have a random order. This method uses the global random number generator common to methods such as [method @GlobalScope.randi]. Call [method @GlobalScope.randomize] to ensure that a new seed will be used each time if you want non-reproducible shuffling.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
Returns the number of elements in the array.
</description>
</method>
- <method name="slice">
+ <method name="slice" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="begin" type="int">
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index e2c4ed1430..7c1c4656f8 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -128,6 +128,16 @@
Will regenerate normal maps for the [ArrayMesh].
</description>
</method>
+ <method name="set_blend_shape_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="surface_find_by_name" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 5bc077ef49..9865319419 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AtlasTexture" inherits="Texture2D" version="4.0">
<brief_description>
- Packs multiple small textures in a single, bigger one. Helps to optimize video memory costs and render calls.
+ Crops out one part of a texture, such as a texture from a texture atlas.
</brief_description>
<description>
- [Texture2D] resource aimed at managing big textures files that pack multiple smaller textures. Consists of a [Texture2D], a margin that defines the border width, and a region that defines the actual area of the AtlasTexture.
+ [Texture2D] resource that crops out one part of the [member atlas] texture, defined by [member region]. The main use case is cropping out textures from a texture atlas, which is a big texture file that packs multiple smaller textures. Consists of a [Texture2D] for the [member atlas], a [member region] that defines the area of [member atlas] to use, and a [member margin] that defines the border width.
+ [AtlasTexture] cannot be used in an [AnimatedTexture], cannot be tiled in nodes such as [TextureRect], and does not work properly if used inside of other [AtlasTexture] resources. Multiple [AtlasTexture] resources can be used to crop multiple textures from the atlas. Using a texture atlas helps to optimize video memory costs and render calls compared to using multiple small files.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index cf3d87c2e4..c7ee621ca6 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -67,7 +67,7 @@
</methods>
<members>
<member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="0.1">
- Length of the internal ring buffer, in seconds.
+ Length of the internal ring buffer, in seconds. Setting the buffer length will have no effect if already initialized.
</member>
</members>
<constants>
diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml
index 7cc6a5613b..9a70b8f20c 100644
--- a/doc/classes/BackBufferCopy.xml
+++ b/doc/classes/BackBufferCopy.xml
@@ -4,7 +4,7 @@
Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts through the [code]texture(SCREEN_TEXTURE, ...)[/code] function.
</brief_description>
<description>
- Node for back-buffering the currently-displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer.
+ Node for back-buffering the currently-displayed screen. The region defined in the BackBufferCopy node is buffered with the content of the screen it covers, or the entire screen according to the copy mode set. Use the [code]texture(SCREEN_TEXTURE, ...)[/code] function in your shader scripts to access the buffer.
[b]Note:[/b] Since this node inherits from [Node2D] (and not [Control]), anchors and margins won't apply to child [Control]-derived nodes. This can be problematic when resizing the window. To avoid this, add [Control]-derived nodes as [i]siblings[/i] to the BackBufferCopy node instead of adding them as children.
</description>
<tutorials>
diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/BakedLightmapData.xml
index 026477782a..904555c48e 100644
--- a/doc/classes/BakedLightmapData.xml
+++ b/doc/classes/BakedLightmapData.xml
@@ -12,11 +12,11 @@
</return>
<argument index="0" name="path" type="NodePath">
</argument>
- <argument index="1" name="lightmap" type="Rect2">
+ <argument index="1" name="uv_scale" type="Rect2">
</argument>
- <argument index="2" name="offset" type="int">
+ <argument index="2" name="slice_index" type="int">
</argument>
- <argument index="3" name="arg3" type="int">
+ <argument index="3" name="sub_instance" type="int">
</argument>
<description>
</description>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 45ef4cb14c..f7e31f5f9c 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -49,7 +49,7 @@
</member>
<member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" default="1">
Binary mask to choose which mouse buttons this button will respond to.
- To allow both left-click and right-click, use [code]BUTTON_MASK_LEFT | BUTTON_MASK_RIGHT[/code].
+ To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT[/code].
</member>
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
If [code]true[/code], the button is in disabled state and can't be clicked or toggled.
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index 31e6ea5e54..0a7b4c5dab 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -82,7 +82,7 @@
Texture to multiply by [member albedo_color]. Used for basic texturing of objects.
</member>
<member name="alpha_antialiasing_edge" type="float" setter="set_alpha_antialiasing_edge" getter="get_alpha_antialiasing_edge">
- Threshold at which antialiasing will by applied on the alpha channel.
+ Threshold at which antialiasing will be applied on the alpha channel.
</member>
<member name="alpha_antialiasing_mode" type="int" setter="set_alpha_antialiasing" getter="get_alpha_antialiasing" enum="BaseMaterial3D.AlphaAntiAliasing">
The type of alpha antialiasing to apply. See [enum AlphaAntiAliasing].
@@ -93,7 +93,7 @@
<member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold">
Threshold at which the alpha scissor will discard values.
</member>
- <member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy">
+ <member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy" default="0.0">
The strength of the anisotropy effect.
</member>
<member name="anisotropy_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
@@ -105,19 +105,19 @@
<member name="ao_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], ambient occlusion is enabled. Ambient occlusion darkens areas based on the [member ao_texture].
</member>
- <member name="ao_light_affect" type="float" setter="set_ao_light_affect" getter="get_ao_light_affect">
+ <member name="ao_light_affect" type="float" setter="set_ao_light_affect" getter="get_ao_light_affect" default="0.0">
Amount that ambient occlusion affects lighting from lights. If [code]0[/code], ambient occlusion only affects ambient light. If [code]1[/code], ambient occlusion affects lights just as much as it affects ambient light. This can be used to impact the strength of the ambient occlusion effect, but typically looks unrealistic.
</member>
- <member name="ao_on_uv2" type="bool" setter="set_flag" getter="get_flag">
+ <member name="ao_on_uv2" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], use [code]UV2[/code] coordinates to look up from the [member ao_texture].
</member>
<member name="ao_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture that defines the amount of ambient occlusion for a given point on the object.
</member>
- <member name="ao_texture_channel" type="int" setter="set_ao_texture_channel" getter="get_ao_texture_channel" enum="BaseMaterial3D.TextureChannel">
+ <member name="ao_texture_channel" type="int" setter="set_ao_texture_channel" getter="get_ao_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0">
Specifies the channel of the [member ao_texture] in which the ambient occlusion 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="backlight" type="Color" setter="set_backlight" getter="get_backlight">
+ <member name="backlight" type="Color" setter="set_backlight" getter="get_backlight" default="Color( 0, 0, 0, 1 )">
The color used by the backlight effect. Represents the light passing through an object.
</member>
<member name="backlight_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
@@ -127,7 +127,7 @@
Texture used to control the backlight effect per-pixel. Added to [member backlight].
</member>
<member name="billboard_keep_scale" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
+ If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise, the scale is lost when billboarding. Only applies when [member billboard_mode] is [constant BILLBOARD_ENABLED].
</member>
<member name="billboard_mode" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0">
Controls how the object faces the camera. See [enum BillboardMode].
@@ -137,13 +137,14 @@
The material's blend mode.
[b]Note:[/b] Values other than [code]Mix[/code] force the object into the transparent pipeline. See [enum BlendMode].
</member>
- <member name="clearcoat" type="float" setter="set_clearcoat" getter="get_clearcoat">
+ <member name="clearcoat" type="float" setter="set_clearcoat" getter="get_clearcoat" default="1.0">
Sets the strength of the clearcoat effect. Setting to [code]0[/code] looks the same as disabling the clearcoat effect.
</member>
<member name="clearcoat_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], clearcoat rendering is enabled. Adds a secondary transparent pass to the lighting calculation resulting in an added specular blob. This makes materials appear as if they have a clear layer on them that can be either glossy or rough.
+ [b]Note:[/b] Clearcoat rendering is not visible if the material's [member shading_mode] is [constant SHADING_MODE_UNSHADED].
</member>
- <member name="clearcoat_gloss" type="float" setter="set_clearcoat_gloss" getter="get_clearcoat_gloss">
+ <member name="clearcoat_gloss" type="float" setter="set_clearcoat_gloss" getter="get_clearcoat_gloss" default="0.5">
Sets the roughness of the clearcoat pass. A higher value results in a smoother clearcoat while a lower value results in a rougher clearcoat.
</member>
<member name="clearcoat_texture" type="Texture2D" setter="set_texture" getter="get_texture">
@@ -158,7 +159,7 @@
<member name="detail_albedo" type="Texture2D" setter="set_texture" getter="get_texture">
Texture that specifies the color of the detail overlay.
</member>
- <member name="detail_blend_mode" type="int" setter="set_detail_blend_mode" getter="get_detail_blend_mode" enum="BaseMaterial3D.BlendMode">
+ <member name="detail_blend_mode" type="int" setter="set_detail_blend_mode" getter="get_detail_blend_mode" enum="BaseMaterial3D.BlendMode" default="0">
Specifies how the [member detail_albedo] should blend with the current [code]ALBEDO[/code]. See [enum BlendMode] for options.
</member>
<member name="detail_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
@@ -171,7 +172,7 @@
Texture that specifies the per-pixel normal of the detail overlay.
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
- <member name="detail_uv_layer" type="int" setter="set_detail_uv" getter="get_detail_uv" enum="BaseMaterial3D.DetailUV">
+ <member name="detail_uv_layer" type="int" setter="set_detail_uv" getter="get_detail_uv" enum="BaseMaterial3D.DetailUV" default="0">
Specifies whether to use [code]UV[/code] or [code]UV2[/code] for the detail layer. See [enum DetailUV] for options.
</member>
<member name="diffuse_mode" type="int" setter="set_diffuse_mode" getter="get_diffuse_mode" enum="BaseMaterial3D.DiffuseMode" default="0">
@@ -183,30 +184,30 @@
<member name="disable_receive_shadows" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the object receives no shadow that would otherwise be cast onto it.
</member>
- <member name="distance_fade_max_distance" type="float" setter="set_distance_fade_max_distance" getter="get_distance_fade_max_distance">
+ <member name="distance_fade_max_distance" type="float" setter="set_distance_fade_max_distance" getter="get_distance_fade_max_distance" default="10.0">
Distance at which the object appears fully opaque.
[b]Note:[/b] If [code]distance_fade_max_distance[/code] is less than [code]distance_fade_min_distance[/code], the behavior will be reversed. The object will start to fade away at [code]distance_fade_max_distance[/code] and will fully disappear once it reaches [code]distance_fade_min_distance[/code].
</member>
- <member name="distance_fade_min_distance" type="float" setter="set_distance_fade_min_distance" getter="get_distance_fade_min_distance">
+ <member name="distance_fade_min_distance" type="float" setter="set_distance_fade_min_distance" getter="get_distance_fade_min_distance" default="0.0">
Distance at which the object starts to become visible. If the object is less than this distance away, it will be invisible.
[b]Note:[/b] If [code]distance_fade_min_distance[/code] is greater than [code]distance_fade_max_distance[/code], the behavior will be reversed. The object will start to fade away at [code]distance_fade_max_distance[/code] and will fully disappear once it reaches [code]distance_fade_min_distance[/code].
</member>
<member name="distance_fade_mode" type="int" setter="set_distance_fade" getter="get_distance_fade" enum="BaseMaterial3D.DistanceFadeMode" default="0">
Specifies which type of fade to use. Can be any of the [enum DistanceFadeMode]s.
</member>
- <member name="emission" type="Color" setter="set_emission" getter="get_emission">
+ <member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color( 0, 0, 0, 1 )">
The emitted light's color. See [member emission_enabled].
</member>
<member name="emission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [GIProbe] is used and this object is used in baked lighting.
</member>
- <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy">
+ <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0">
The emitted light's strength. See [member emission_enabled].
</member>
- <member name="emission_on_uv2" type="bool" setter="set_flag" getter="get_flag">
+ <member name="emission_on_uv2" type="bool" setter="set_flag" getter="get_flag" default="false">
Use [code]UV2[/code] to read from the [member emission_texture].
</member>
- <member name="emission_operator" type="int" setter="set_emission_operator" getter="get_emission_operator" enum="BaseMaterial3D.EmissionOperator">
+ <member name="emission_operator" type="int" setter="set_emission_operator" getter="get_emission_operator" enum="BaseMaterial3D.EmissionOperator" default="0">
Sets how [member emission] interacts with [member emission_texture]. Can either add or multiply. See [enum EmissionOperator] for options.
</member>
<member name="emission_texture" type="Texture2D" setter="set_texture" getter="get_texture">
@@ -221,21 +222,23 @@
<member name="grow_amount" type="float" setter="set_grow" getter="get_grow" default="0.0">
Grows object vertices in the direction of their normals.
</member>
- <member name="heightmap_deep_parallax" type="bool" setter="set_heightmap_deep_parallax" getter="is_heightmap_deep_parallax_enabled">
+ <member name="heightmap_deep_parallax" type="bool" setter="set_heightmap_deep_parallax" getter="is_heightmap_deep_parallax_enabled" default="false">
</member>
<member name="heightmap_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], height mapping is enabled (also called "parallax mapping" or "depth mapping"). See also [member normal_enabled].
+ [b]Note:[/b] Height mapping is not supported if triplanar mapping is used on the same material. The value of [member heightmap_enabled] will be ignored if [member uv1_triplanar] is enabled.
</member>
- <member name="heightmap_flip_binormal" type="bool" setter="set_heightmap_deep_parallax_flip_binormal" getter="get_heightmap_deep_parallax_flip_binormal">
+ <member name="heightmap_flip_binormal" type="bool" setter="set_heightmap_deep_parallax_flip_binormal" getter="get_heightmap_deep_parallax_flip_binormal" default="false">
</member>
- <member name="heightmap_flip_tangent" type="bool" setter="set_heightmap_deep_parallax_flip_tangent" getter="get_heightmap_deep_parallax_flip_tangent">
+ <member name="heightmap_flip_tangent" type="bool" setter="set_heightmap_deep_parallax_flip_tangent" getter="get_heightmap_deep_parallax_flip_tangent" default="false">
</member>
- <member name="heightmap_flip_texture" type="bool" setter="set_flag" getter="get_flag">
+ <member name="heightmap_flip_texture" type="bool" setter="set_flag" getter="get_flag" default="false">
</member>
<member name="heightmap_max_layers" type="int" setter="set_heightmap_deep_parallax_max_layers" getter="get_heightmap_deep_parallax_max_layers">
</member>
<member name="heightmap_min_layers" type="int" setter="set_heightmap_deep_parallax_min_layers" getter="get_heightmap_deep_parallax_min_layers">
</member>
- <member name="heightmap_scale" type="float" setter="set_heightmap_scale" getter="get_heightmap_scale">
+ <member name="heightmap_scale" type="float" setter="set_heightmap_scale" getter="get_heightmap_scale" default="0.05">
</member>
<member name="heightmap_texture" type="Texture2D" setter="set_texture" getter="get_texture">
</member>
@@ -258,7 +261,7 @@
<member name="normal_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], normal mapping is enabled.
</member>
- <member name="normal_scale" type="float" setter="set_normal_scale" getter="get_normal_scale">
+ <member name="normal_scale" type="float" setter="set_normal_scale" getter="get_normal_scale" default="1.0">
The strength of the normal map's effect.
</member>
<member name="normal_texture" type="Texture2D" setter="set_texture" getter="get_texture">
@@ -279,7 +282,7 @@
<member name="point_size" type="float" setter="set_point_size" getter="get_point_size" default="1.0">
The point size in pixels. See [member use_point_size].
</member>
- <member name="proximity_fade_distance" type="float" setter="set_proximity_fade_distance" getter="get_proximity_fade_distance">
+ <member name="proximity_fade_distance" type="float" setter="set_proximity_fade_distance" getter="get_proximity_fade_distance" default="1.0">
Distance over which the fade effect takes place. The larger the distance the longer it takes for an object to fade.
</member>
<member name="proximity_fade_enable" type="bool" setter="set_proximity_fade" getter="is_proximity_fade_enabled" default="false">
@@ -288,25 +291,26 @@
<member name="refraction_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], the refraction effect is enabled. Distorts transparency based on light from behind the object.
</member>
- <member name="refraction_scale" type="float" setter="set_refraction" getter="get_refraction">
+ <member name="refraction_scale" type="float" setter="set_refraction" getter="get_refraction" default="0.05">
The strength of the refraction effect.
</member>
<member name="refraction_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture that controls the strength of the refraction per-pixel. Multiplied by [member refraction_scale].
</member>
- <member name="refraction_texture_channel" type="int" setter="set_refraction_texture_channel" getter="get_refraction_texture_channel" enum="BaseMaterial3D.TextureChannel">
+ <member name="refraction_texture_channel" type="int" setter="set_refraction_texture_channel" getter="get_refraction_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0">
Specifies the channel of the [member ao_texture] in which the ambient occlusion 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="rim" type="float" setter="set_rim" getter="get_rim">
+ <member name="rim" type="float" setter="set_rim" getter="get_rim" default="1.0">
Sets the strength of the rim lighting effect.
</member>
<member name="rim_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], rim effect is enabled. Rim lighting increases the brightness at glancing angles on an object.
+ [b]Note:[/b] Rim lighting is not visible if the material's [member shading_mode] is [constant SHADING_MODE_UNSHADED].
</member>
<member name="rim_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture used to set the strength of the rim lighting effect per-pixel. Multiplied by [member rim].
</member>
- <member name="rim_tint" type="float" setter="set_rim_tint" getter="get_rim_tint">
+ <member name="rim_tint" type="float" setter="set_rim_tint" getter="get_rim_tint" default="0.5">
The amount of to blend light and albedo color when rendering rim effect. If [code]0[/code] the light color is used, while [code]1[/code] means albedo color is used. An intermediate value generally works best.
</member>
<member name="roughness" type="float" setter="set_roughness" getter="get_roughness" default="1.0">
@@ -330,24 +334,24 @@
<member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges.
</member>
- <member name="subsurf_scatter_skin_mode" type="bool" setter="set_flag" getter="get_flag">
+ <member name="subsurf_scatter_skin_mode" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], subsurface scattering will use a special mode optimized for the color and density of human skin.
</member>
- <member name="subsurf_scatter_strength" type="float" setter="set_subsurface_scattering_strength" getter="get_subsurface_scattering_strength">
+ <member name="subsurf_scatter_strength" type="float" setter="set_subsurface_scattering_strength" getter="get_subsurface_scattering_strength" default="0.0">
The strength of the subsurface scattering effect.
</member>
<member name="subsurf_scatter_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture used to control the subsurface scattering strength. Stored in the red texture channel. Multiplied by [member subsurf_scatter_strength].
</member>
- <member name="subsurf_scatter_transmittance_boost" type="float" setter="set_transmittance_boost" getter="get_transmittance_boost">
+ <member name="subsurf_scatter_transmittance_boost" type="float" setter="set_transmittance_boost" getter="get_transmittance_boost" default="0.0">
</member>
- <member name="subsurf_scatter_transmittance_color" type="Color" setter="set_transmittance_color" getter="get_transmittance_color">
+ <member name="subsurf_scatter_transmittance_color" type="Color" setter="set_transmittance_color" getter="get_transmittance_color" default="Color( 1, 1, 1, 1 )">
</member>
- <member name="subsurf_scatter_transmittance_curve" type="float" setter="set_transmittance_curve" getter="get_transmittance_curve">
+ <member name="subsurf_scatter_transmittance_curve" type="float" setter="set_transmittance_curve" getter="get_transmittance_curve" default="1.0">
</member>
- <member name="subsurf_scatter_transmittance_depth" type="float" setter="set_transmittance_depth" getter="get_transmittance_depth">
+ <member name="subsurf_scatter_transmittance_depth" type="float" setter="set_transmittance_depth" getter="get_transmittance_depth" default="0.1">
</member>
- <member name="subsurf_scatter_transmittance_enabled" type="bool" setter="set_feature" getter="get_feature">
+ <member name="subsurf_scatter_transmittance_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
</member>
<member name="subsurf_scatter_transmittance_texture" type="Texture2D" setter="set_texture" getter="get_texture">
</member>
@@ -360,6 +364,8 @@
<member name="transparency" type="int" setter="set_transparency" getter="get_transparency" enum="BaseMaterial3D.Transparency" default="0">
If [code]true[/code], transparency is enabled on the body. See also [member blend_mode].
</member>
+ <member name="use_particle_trails" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
<member name="use_point_size" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], render point size can be changed.
[b]Note:[/b] this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member point_size].
@@ -651,7 +657,9 @@
<constant name="FLAG_SUBSURFACE_MODE_SKIN" value="18" enum="Flags">
Enables the skin mode for subsurface scattering which is used to improve the look of subsurface scattering when used for human skin.
</constant>
- <constant name="FLAG_MAX" value="19" enum="Flags">
+ <constant name="FLAG_PARTICLE_TRAILS_MODE" value="19" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="20" enum="Flags">
Represents the size of the [enum Flags] enum.
</constant>
<constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode">
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 4c9cd5702e..55ae58ee3a 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -78,7 +78,7 @@
Constructs a basis matrix from 3 axis vectors (matrix columns).
</description>
</method>
- <method name="determinant">
+ <method name="determinant" qualifiers="const">
<return type="float">
</return>
<description>
@@ -86,7 +86,7 @@
A negative determinant means the basis has a negative scale. A zero determinant means the basis isn't invertible, and is usually considered invalid.
</description>
</method>
- <method name="get_euler">
+ <method name="get_euler" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -94,35 +94,35 @@
Consider using the [method get_rotation_quat] method instead, which returns a [Quat] quaternion instead of Euler angles.
</description>
</method>
- <method name="get_orthogonal_index">
+ <method name="get_orthogonal_index" qualifiers="const">
<return type="int">
</return>
<description>
This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code.
</description>
</method>
- <method name="get_rotation_quat">
+ <method name="get_rotation_quat" qualifiers="const">
<return type="Quat">
</return>
<description>
Returns the basis's rotation in the form of a quaternion. See [method get_euler] if you need Euler angles, but keep in mind quaternions should generally be preferred to Euler angles.
</description>
</method>
- <method name="get_scale">
+ <method name="get_scale" qualifiers="const">
<return type="Vector3">
</return>
<description>
Assuming that the matrix is the combination of a rotation and scaling, return the absolute value of scaling factors along each axis.
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Basis">
</return>
<description>
Returns the inverse of the matrix.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Basis">
@@ -171,14 +171,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Basis">
</return>
<description>
Returns the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error for orthogonal matrices). This performs a Gram-Schmidt orthonormalization on the basis of the matrix.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -189,7 +189,7 @@
Introduce an additional rotation around the given axis by phi (radians). The axis must be a normalized vector.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -198,7 +198,7 @@
Introduce an additional scaling specified by the given 3D scaling factor.
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="to" type="Basis">
@@ -209,7 +209,7 @@
Assuming that the matrix is a proper rotation matrix, slerp performs a spherical-linear interpolation with another rotation matrix.
</description>
</method>
- <method name="tdotx">
+ <method name="tdotx" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -218,7 +218,7 @@
Transposed dot product with the X axis of the matrix.
</description>
</method>
- <method name="tdoty">
+ <method name="tdoty" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -227,7 +227,7 @@
Transposed dot product with the Y axis of the matrix.
</description>
</method>
- <method name="tdotz">
+ <method name="tdotz" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -236,7 +236,7 @@
Transposed dot product with the Z axis of the matrix.
</description>
</method>
- <method name="transposed">
+ <method name="transposed" qualifiers="const">
<return type="Basis">
</return>
<description>
diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml
index 0d8233e6ff..ffa7c9066a 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -10,7 +10,7 @@
</tutorials>
<methods>
<method name="add_spacer">
- <return type="void">
+ <return type="Control">
</return>
<argument index="0" name="begin" type="bool">
</argument>
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index 8908c5f830..51c35b15ce 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -34,6 +34,7 @@
[/codeblocks]
Buttons (like all Control nodes) can also be created in the editor, but some situations may require creating them from code.
See also [BaseButton] which contains common properties and methods associated with this node.
+ [b]Note:[/b] Buttons do not interpret touch input and therefore don't support multitouch, since mouse emulation can only press one button at a given time. Use [TouchScreenButton] for buttons that trigger gameplay movement or actions, as [TouchScreenButton] supports multitouch.
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
@@ -128,7 +129,7 @@
Text [Color] used when the [Button] is being hovered and pressed.
</theme_item>
<theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
- Text outline [Color] of the [Button].
+ The tint of text outline of the [Button].
</theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the [Button] is being pressed.
@@ -161,7 +162,7 @@
Default [StyleBox] for the [Button].
</theme_item>
<theme_item name="outline_size" type="int" default="0">
- Size of the [Button]'s text outline.
+ The size of the text outline.
</theme_item>
<theme_item name="pressed" type="StyleBox">
[StyleBox] used when the [Button] is being pressed.
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index f137ede90f..0cfbd0270c 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -8,26 +8,26 @@
[b]Example:[/b]
[codeblocks]
[gdscript]
- var callable = Callable(self, "print_args")
func print_args(arg1, arg2, arg3 = ""):
prints(arg1, arg2, arg3)
func test():
- callable.call("hello", "world") # Prints "hello world".
+ var callable = Callable(self, "print_args")
+ callable.call("hello", "world") # Prints "hello world ".
callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(Node.gd)::print_args".
callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript]
[csharp]
- Callable callable = new Callable(this, "print_args");
- public void PrintArgs(object arg1, object arg2, object arg3 = "")
+ public void PrintArgs(object arg1, object arg2, object arg3 = null)
{
GD.PrintS(arg1, arg2, arg3);
}
public void Test()
{
- callable.Call("hello", "world"); // Prints "hello world".
- callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.gd)::print_args".
+ Callable callable = new Callable(this, nameof(PrintArgs));
+ callable.Call("hello", "world"); // Prints "hello world null".
+ callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs".
callable.Call("invalid"); // Invalid call, should have at least 2 arguments.
}
[/csharp]
@@ -63,69 +63,74 @@
Creates a new [Callable] for the method called [code]method[/code] in the specified [code]object[/code].
</description>
</method>
- <method name="bind" qualifiers="vararg">
+ <method name="bind" qualifiers="vararg const">
<return type="Callable">
</return>
<description>
+ Returns a copy of this [Callable] with the arguments bound. Bound arguments are passed after the arguments supplied by [method call].
</description>
</method>
- <method name="call" qualifiers="vararg">
+ <method name="call" qualifiers="vararg const">
<return type="Variant">
</return>
<description>
Calls the method represented by this [Callable]. Arguments can be passed and should match the method's signature.
</description>
</method>
- <method name="call_deferred" qualifiers="vararg">
+ <method name="call_deferred" qualifiers="vararg const">
<return type="void">
</return>
<description>
Calls the method represented by this [Callable] in deferred mode, i.e. during the idle frame. Arguments can be passed and should match the method's signature.
</description>
</method>
- <method name="get_method">
+ <method name="get_method" qualifiers="const">
<return type="StringName">
</return>
<description>
Returns the name of the method represented by this [Callable].
</description>
</method>
- <method name="get_object">
+ <method name="get_object" qualifiers="const">
<return type="Object">
</return>
<description>
Returns the object on which this [Callable] is called.
</description>
</method>
- <method name="get_object_id">
+ <method name="get_object_id" qualifiers="const">
<return type="int">
</return>
<description>
Returns the ID of this [Callable]'s object (see [method Object.get_instance_id]).
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the hash value of this [Callable]'s object.
</description>
</method>
- <method name="is_custom">
+ <method name="is_custom" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if this [Callable] is a custom callable whose behavior differs based on implementation details. Custom callables are used in the engine for various reasons. If [code]true[/code], you can't use [method get_method].
</description>
</method>
- <method name="is_null">
+ <method name="is_null" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if this [Callable] has no target to call the method on.
</description>
</method>
- <method name="is_standard">
+ <method name="is_standard" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if this [Callable] is a standard callable, referencing an object and a method using a [StringName].
</description>
</method>
<method name="operator !=" qualifiers="operator">
@@ -134,6 +139,7 @@
<argument index="0" name="right" type="Callable">
</argument>
<description>
+ Returns [code]true[/code] if both [Callable]s invoke different targets.
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -142,14 +148,16 @@
<argument index="0" name="right" type="Callable">
</argument>
<description>
+ Returns [code]true[/code] if both [Callable]s invoke the same custom target.
</description>
</method>
- <method name="unbind">
+ <method name="unbind" qualifiers="const">
<return type="Callable">
</return>
<argument index="0" name="argcount" type="int">
</argument>
<description>
+ Returns a copy of this [Callable] with the arguments unbound. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method.
</description>
</method>
</methods>
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index 2a4e726d43..d40567bdcb 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -168,8 +168,8 @@
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
The camera's offset, useful for looking around or camera shake animations.
</member>
- <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Camera2D.Camera2DProcessMode" default="1">
- The camera's process callback. See [enum Camera2DProcessMode].
+ <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="Camera2D.Camera2DProcessCallback" default="1">
+ The camera's process callback. See [enum Camera2DProcessCallback].
</member>
<member name="rotating" type="bool" setter="set_rotating" getter="is_rotating" default="false">
If [code]true[/code], the camera rotates with the target.
@@ -191,10 +191,10 @@
<constant name="ANCHOR_MODE_DRAG_CENTER" value="1" enum="AnchorMode">
The camera's position takes into account vertical/horizontal offsets and the screen size.
</constant>
- <constant name="CAMERA2D_PROCESS_PHYSICS" value="0" enum="Camera2DProcessMode">
+ <constant name="CAMERA2D_PROCESS_PHYSICS" value="0" enum="Camera2DProcessCallback">
The camera updates with the [code]_physics_process[/code] callback.
</constant>
- <constant name="CAMERA2D_PROCESS_IDLE" value="1" enum="Camera2DProcessMode">
+ <constant name="CAMERA2D_PROCESS_IDLE" value="1" enum="Camera2DProcessCallback">
The camera updates with the [code]_process[/code] callback.
</constant>
</constants>
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 034b2e9629..9f1d6d8e31 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -194,7 +194,7 @@
</member>
<member name="fov" type="float" setter="set_fov" getter="get_fov" default="75.0">
The camera's field of view angle (in degrees). Only applicable in perspective mode. Since [member keep_aspect] locks one axis, [code]fov[/code] sets the other axis' field of view angle.
- For reference, the default vertical field of view value ([code]75.0[/code]) is equivalent to an horizontal FOV of:
+ For reference, the default vertical field of view value ([code]75.0[/code]) is equivalent to a horizontal FOV of:
- ~91.31 degrees in a 4:3 viewport
- ~101.67 degrees in a 16:10 viewport
- ~107.51 degrees in a 16:9 viewport
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index d13f431a16..87b157db4e 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -318,7 +318,7 @@
<argument index="9" name="flags" type="int" default="3">
</argument>
<description>
- Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
[b]Example using the default project font:[/b]
[codeblocks]
[gdscript]
diff --git a/doc/classes/CapsuleMesh.xml b/doc/classes/CapsuleMesh.xml
index fab11d44cc..031abd0112 100644
--- a/doc/classes/CapsuleMesh.xml
+++ b/doc/classes/CapsuleMesh.xml
@@ -12,7 +12,8 @@
</methods>
<members>
<member name="mid_height" type="float" setter="set_mid_height" getter="get_mid_height" default="1.0">
- Height of the capsule mesh from the center point.
+ Height of the middle cylindrical part of the capsule (without the hemispherical ends).
+ [b]Note:[/b] The capsule's total height is equal to [member mid_height] + 2 * [member radius].
</member>
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="64">
Number of radial segments on the capsule mesh.
diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml
index b4cb110337..850098f741 100644
--- a/doc/classes/CharFXTransform.xml
+++ b/doc/classes/CharFXTransform.xml
@@ -17,7 +17,7 @@
The color the character will be drawn with.
</member>
<member name="elapsed_time" type="float" setter="set_elapsed_time" getter="get_elapsed_time" default="0.0">
- The time elapsed since the [RichTextLabel] was added to the scene tree (in seconds). Time stops when the project is paused, unless the [RichTextLabel]'s [member Node.pause_mode] is set to [constant Node.PAUSE_MODE_PROCESS].
+ The time elapsed since the [RichTextLabel] was added to the scene tree (in seconds). Time stops when the project is paused depending on the value of the [RichTextLabel]'s [member Node.process_mode].
[b]Note:[/b] Time still passes while the [RichTextLabel] is hidden.
</member>
<member name="env" type="Dictionary" setter="set_environment" getter="get_environment" default="{}">
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index bd91f9ed06..05e412e9da 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -24,6 +24,8 @@
<theme_item name="checked" type="Texture2D">
The check icon to display when the [CheckBox] is checked.
</theme_item>
+ <theme_item name="checked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="disabled" type="StyleBox">
The [StyleBox] to display as a background when the [CheckBox] is disabled.
</theme_item>
@@ -45,6 +47,9 @@
<theme_item name="font_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
The [CheckBox] text's font color when it's hovered and pressed.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [CheckBox].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
The [CheckBox] text's font color when it's pressed.
</theme_item>
@@ -63,17 +68,26 @@
<theme_item name="normal" type="StyleBox">
The [StyleBox] to display as a background.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
The [StyleBox] to display as a background when the [CheckBox] is pressed.
</theme_item>
<theme_item name="radio_checked" type="Texture2D">
If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is checked.
</theme_item>
+ <theme_item name="radio_checked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="radio_unchecked" type="Texture2D">
If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is unchecked.
</theme_item>
+ <theme_item name="radio_unchecked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="unchecked" type="Texture2D">
The check icon to display when the [CheckBox] is unchecked.
</theme_item>
+ <theme_item name="unchecked_disabled" type="Texture2D">
+ </theme_item>
</theme_items>
</class>
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index a05e532d4a..46e590a115 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -42,6 +42,9 @@
<theme_item name="font_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
The [CheckButton] text's font color when it's hovered and pressed.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [CheckButton].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
The [CheckButton] text's font color when it's pressed.
</theme_item>
@@ -84,6 +87,9 @@
<theme_item name="on_mirrored" type="Texture2D">
The icon to display when the [CheckButton] is checked (for right-to-left layouts).
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
The [StyleBox] to display as a background when the [CheckButton] is pressed.
</theme_item>
diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml
index de90247536..9116af19c3 100644
--- a/doc/classes/ClippedCamera3D.xml
+++ b/doc/classes/ClippedCamera3D.xml
@@ -95,15 +95,15 @@
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
The camera's collision margin. The camera can't get closer than this distance to a colliding object.
</member>
- <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="ClippedCamera3D.ProcessMode" default="0">
- The camera's process callback. See [enum ProcessMode].
+ <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="ClippedCamera3D.ClipProcessCallback" default="0">
+ The camera's process callback. See [enum ClipProcessCallback].
</member>
</members>
<constants>
- <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ProcessMode">
+ <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ClipProcessCallback">
The camera updates with the [code]_physics_process[/code] callback.
</constant>
- <constant name="CLIP_PROCESS_IDLE" value="1" enum="ProcessMode">
+ <constant name="CLIP_PROCESS_IDLE" value="1" enum="ClipProcessCallback">
The camera updates with the [code]_process[/code] callback.
</constant>
</constants>
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index f897f2405b..81795abcdd 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -3,7 +3,7 @@
<brief_description>
</brief_description>
<description>
- [b]Note[/b]: By default [CodeEdit] always use left-to-right text direction to correcly display source code.
+ [b]Note[/b]: By default [CodeEdit] always use left-to-right text direction to correctly display source code.
</description>
<tutorials>
</tutorials>
@@ -179,6 +179,9 @@
</theme_item>
<theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [CodeEdit].
+ </theme_item>
<theme_item name="font_readonly_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )">
</theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )">
@@ -194,6 +197,9 @@
</theme_item>
<theme_item name="normal" type="StyleBox">
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="read_only" type="StyleBox">
</theme_item>
<theme_item name="safe_line_number_color" type="Color" default="Color( 0.67, 0.78, 0.67, 0.6 )">
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index e8f7a59e4c..7c4c75bf0f 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -31,6 +31,24 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
+ <method name="get_collision_layer_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ </description>
+ </method>
<method name="get_rid" qualifiers="const">
<return type="RID">
</return>
@@ -81,6 +99,30 @@
Removes the given shape owner.
</description>
</method>
+ <method name="set_collision_layer_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ </description>
+ </method>
<method name="shape_find_owner" qualifiers="const">
<return type="int">
</return>
@@ -216,6 +258,14 @@
</method>
</methods>
<members>
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
+ The physics layers this CollisionObject2D is in. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ </member>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set.
</member>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index f8e897653d..522eec5cbe 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -35,6 +35,24 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
+ <method name="get_collision_layer_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ </description>
+ </method>
<method name="get_rid" qualifiers="const">
<return type="RID">
</return>
@@ -67,6 +85,30 @@
Removes the given shape owner.
</description>
</method>
+ <method name="set_collision_layer_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ </description>
+ </method>
<method name="shape_find_owner" qualifiers="const">
<return type="int">
</return>
@@ -180,6 +222,14 @@
</method>
</methods>
<members>
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
+ The physics layers this CollisionObject3D is in. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this CollisionObject3D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ </member>
<member name="input_capture_on_drag" type="bool" setter="set_capture_input_on_drag" getter="get_capture_input_on_drag" default="false">
If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes.
</member>
diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml
index dd3c57d1d0..38f4c5fe5c 100644
--- a/doc/classes/CollisionPolygon3D.xml
+++ b/doc/classes/CollisionPolygon3D.xml
@@ -17,6 +17,9 @@
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
If [code]true[/code], no collision will be produced.
</member>
+ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
+ The collision margin for the generated [Shape3D]. See [member Shape3D.margin] for more details.
+ </member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )">
Array of vertices which define the polygon.
[b]Note:[/b] The returned value is a copy of the original. Methods which mutate the size or properties of the return value will not impact the original polygon. To change properties of the polygon, assign it to a temporary variable and make changes before reassigning the [code]polygon[/code] member.
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index ce88e0ae88..d645588af2 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -56,10 +56,8 @@
</return>
<argument index="0" name="code" type="String">
</argument>
- <argument index="1" name="alpha" type="float">
- </argument>
<description>
- Constructs a [Color] either from an HTML color code or from a standardized color name, with [code]alpha[/code] on the range of 0 to 1. Supported color names are the same as the constants.
+ Constructs a [Color] either from an HTML color code or from a standardized color name. Supported color names are the same as the constants.
</description>
</method>
<method name="Color" qualifiers="constructor">
@@ -67,8 +65,10 @@
</return>
<argument index="0" name="code" type="String">
</argument>
+ <argument index="1" name="alpha" type="float">
+ </argument>
<description>
- Constructs a [Color] either from an HTML color code or from a standardized color name. Supported color names are the same as the constants.
+ Constructs a [Color] either from an HTML color code or from a standardized color name, with [code]alpha[/code] on the range of 0 to 1. Supported color names are the same as the constants.
</description>
</method>
<method name="Color" qualifiers="constructor">
@@ -80,16 +80,14 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
- <argument index="3" name="a" type="float">
- </argument>
<description>
- Constructs a [Color] from RGBA values, typically between 0 and 1.
+ Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
[codeblocks]
[gdscript]
- var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
+ var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
[/gdscript]
[csharp]
- var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
+ var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
[/csharp]
[/codeblocks]
</description>
@@ -103,19 +101,21 @@
</argument>
<argument index="2" name="b" type="float">
</argument>
+ <argument index="3" name="a" type="float">
+ </argument>
<description>
- Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
+ Constructs a [Color] from RGBA values, typically between 0 and 1.
[codeblocks]
[gdscript]
- var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)`
+ var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)`
[/gdscript]
[csharp]
- var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)`
+ var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)`
[/csharp]
[/codeblocks]
</description>
</method>
- <method name="blend">
+ <method name="blend" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="over" type="Color">
@@ -136,7 +136,7 @@
[/codeblocks]
</description>
</method>
- <method name="darkened">
+ <method name="darkened" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="amount" type="float">
@@ -155,7 +155,87 @@
[/codeblocks]
</description>
</method>
- <method name="inverted">
+ <method name="find_named_color" qualifiers="static">
+ <return type="int">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="from_rgbe9995" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="rgbe" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="from_string" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="str" type="String">
+ </argument>
+ <argument index="1" name="default" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color_count" qualifiers="static">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_named_color_name" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hex" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="hex" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hex64" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="hex" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="html" qualifiers="static">
+ <return type="Color">
+ </return>
+ <argument index="0" name="rgba" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="html_is_valid" qualifiers="static">
+ <return type="bool">
+ </return>
+ <argument index="0" name="color" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="inverted" qualifiers="const">
<return type="Color">
</return>
<description>
@@ -172,7 +252,7 @@
[/codeblocks]
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Color">
@@ -181,7 +261,7 @@
Returns [code]true[/code] if this color and [code]color[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="to" type="Color">
@@ -189,7 +269,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the linear interpolation with another color. The interpolation factor [code]t[/code] is between 0 and 1.
+ Returns the linear interpolation with another color. The interpolation factor [code]weight[/code] is between 0 and 1.
[codeblocks]
[gdscript]
var c1 = Color(1.0, 0.0, 0.0)
@@ -204,7 +284,7 @@
[/codeblocks]
</description>
</method>
- <method name="lightened">
+ <method name="lightened" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="amount" type="float">
@@ -323,7 +403,7 @@
<description>
</description>
</method>
- <method name="to_abgr32">
+ <method name="to_abgr32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -340,7 +420,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_abgr64">
+ <method name="to_abgr64" qualifiers="const">
<return type="int">
</return>
<description>
@@ -357,7 +437,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_argb32">
+ <method name="to_argb32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -374,7 +454,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_argb64">
+ <method name="to_argb64" qualifiers="const">
<return type="int">
</return>
<description>
@@ -391,7 +471,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_html">
+ <method name="to_html" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="with_alpha" type="bool" default="true">
@@ -413,7 +493,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_rgba32">
+ <method name="to_rgba32" qualifiers="const">
<return type="int">
</return>
<description>
@@ -430,7 +510,7 @@
[/codeblocks]
</description>
</method>
- <method name="to_rgba64">
+ <method name="to_rgba64" qualifiers="const">
<return type="int">
</return>
<description>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index aea3542867..fddfd27573 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -51,6 +51,9 @@
If [code]true[/code], allows editing the color with Hue/Saturation/Value sliders.
[b]Note:[/b] Cannot be enabled if raw mode is on.
</member>
+ <member name="picker_shape" type="int" setter="set_picker_shape" getter="get_picker_shape" enum="ColorPicker.PickerShapeType" default="0">
+ The shape of the color space view. See [enum PickerShapeType].
+ </member>
<member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled" default="true">
If [code]true[/code], the "add preset" button is enabled.
</member>
@@ -86,11 +89,23 @@
</signal>
</signals>
<constants>
+ <constant name="SHAPE_HSV_RECTANGLE" value="0" enum="PickerShapeType">
+ HSV Color Model rectangle color space.
+ </constant>
+ <constant name="SHAPE_HSV_WHEEL" value="1" enum="PickerShapeType">
+ HSV Color Model rectangle color space with a wheel.
+ </constant>
+ <constant name="SHAPE_VHS_CIRCLE" value="2" enum="PickerShapeType">
+ HSV Color Model circle color space. Use Saturation as a radius.
+ </constant>
</constants>
<theme_items>
<theme_item name="add_preset" type="Texture2D">
The icon for the "Add Preset" button.
</theme_item>
+ <theme_item name="bar_arrow" type="Texture2D">
+ The texture for the arrow grabber.
+ </theme_item>
<theme_item name="color_hue" type="Texture2D">
Custom texture for the hue selection slider on the right.
</theme_item>
@@ -107,6 +122,8 @@
<theme_item name="overbright_indicator" type="Texture2D">
The indicator used to signalize that the color value is outside the 0-1 range.
</theme_item>
+ <theme_item name="picker_cursor" type="Texture2D">
+ </theme_item>
<theme_item name="preset_bg" type="Texture2D">
</theme_item>
<theme_item name="screen_picker" type="Texture2D">
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index b351faf9ca..e49027e61d 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -79,6 +79,9 @@
<theme_item name="font_hover_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the [ColorPickerButton] is being hovered.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [ColorPickerButton].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 0.8, 0.8, 0.8, 1 )">
Text [Color] used when the [ColorPickerButton] is being pressed.
</theme_item>
@@ -94,6 +97,9 @@
<theme_item name="normal" type="StyleBox">
Default [StyleBox] for the [ColorPickerButton].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
[StyleBox] used when the [ColorPickerButton] is being pressed.
</theme_item>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index 3e83202472..a9687abedc 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -28,6 +28,11 @@
</description>
</method>
</methods>
+ <members>
+ <member name="backface_collision" type="bool" setter="set_backface_collision_enabled" getter="is_backface_collision_enabled" default="false">
+ If set to [code]true[/code], collisions occur on both sides of the concave shape faces. Otherwise they occur only along the face normals.
+ </member>
+ </members>
<constants>
</constants>
</class>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index da17d993e3..38948a2d6e 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -49,6 +49,12 @@
<tutorials>
</tutorials>
<methods>
+ <method name="clear">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="erase_section">
<return type="void">
</return>
@@ -158,7 +164,7 @@
<argument index="0" name="data" type="String">
</argument>
<description>
- Parses the the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on.
+ Parses the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index e5285587eb..c0f918a01f 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -50,7 +50,7 @@
[gdscript]
func _gui_input(event):
if event is InputEventMouseButton:
- if event.button_index == BUTTON_LEFT and event.pressed:
+ if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
print("I've been clicked D:")
[/gdscript]
[csharp]
@@ -150,7 +150,6 @@
</argument>
<description>
Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses.
- [b]Note:[/b] Unlike other theme overrides, there is no way to undo a color override without manually assigning the previous color.
[b]Example of overriding a label's color and resetting it later:[/b]
[codeblocks]
[gdscript]
@@ -178,7 +177,7 @@
<argument index="1" name="constant" type="int">
</argument>
<description>
- Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is [code]0[/code], the override is cleared and the constant from assigned [Theme] is used.
+ Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_font_override">
@@ -189,7 +188,7 @@
<argument index="1" name="font" type="Font">
</argument>
<description>
- Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is [code]null[/code] or invalid, the override is cleared and the font from assigned [Theme] is used.
+ Overrides the font with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_font_size_override">
@@ -200,7 +199,7 @@
<argument index="1" name="font_size" type="int">
</argument>
<description>
- Overrides the font size with given [code]name[/code] in the [member theme] resource the control uses. If [code]font_size[/code] is [code]-1[/code], the override is cleared and the font size from assigned [Theme] is used.
+ Overrides the font size with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_icon_override">
@@ -211,7 +210,7 @@
<argument index="1" name="texture" type="Texture2D">
</argument>
<description>
- Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is [code]null[/code] or invalid, the override is cleared and the icon from assigned [Theme] is used.
+ Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_stylebox_override">
@@ -222,7 +221,7 @@
<argument index="1" name="stylebox" type="StyleBox">
</argument>
<description>
- Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses. If [code]stylebox[/code] is empty or invalid, the override is cleared and the [StyleBox] from assigned [Theme] is used.
+ Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses.
[b]Example of modifying a property in a StyleBox by duplicating it:[/b]
[codeblocks]
[gdscript]
@@ -730,6 +729,60 @@
Give up the focus. No other control will be able to receive keyboard input.
</description>
</method>
+ <method name="remove_theme_color_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [Color] with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_constant_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a constant with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_font_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [Font] with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_font_size_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a font size with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_icon_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for an icon with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_stylebox_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [StyleBox] with the given [code]name[/code].
+ </description>
+ </method>
<method name="set_anchor">
<return type="void">
</return>
@@ -869,7 +922,7 @@
<argument index="0" name="control" type="Control">
</argument>
<description>
- Shows the given control at the mouse pointer. A good time to call this method is in [method get_drag_data]. The control must not be in the scene tree.
+ Shows the given control at the mouse pointer. A good time to call this method is in [method get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended.
[codeblocks]
[gdscript]
export (Color, RGBA) var color = Color(1, 0, 0, 1)
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index 410c2262f9..26b3087b21 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -27,7 +27,7 @@
</argument>
<description>
Loads a key from [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be loaded.
- [b]Note[/b]: [code]path[/code] should should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ [b]Note[/b]: [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="load_from_string">
@@ -50,7 +50,7 @@
</argument>
<description>
Saves a key to the given [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be saved.
- [b]Note[/b]: [code]path[/code] should should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ [b]Note[/b]: [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="save_to_string">
diff --git a/doc/classes/Curve.xml b/doc/classes/Curve.xml
index 26872e1f8e..e47c420a3b 100644
--- a/doc/classes/Curve.xml
+++ b/doc/classes/Curve.xml
@@ -108,7 +108,7 @@
Returns the Y value for the point that would exist at the X position [code]offset[/code] along the curve.
</description>
</method>
- <method name="interpolate_baked">
+ <method name="interpolate_baked" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="offset" type="float">
diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml
index 2d50d98a74..b33f3b4ffc 100644
--- a/doc/classes/Curve2D.xml
+++ b/doc/classes/Curve2D.xml
@@ -63,7 +63,7 @@
<argument index="0" name="to_point" type="Vector2">
</argument>
<description>
- Returns the closest point (in curve's local space) to [code]to_point[/code].
+ Returns the closest baked point (in curve's local space) to [code]to_point[/code].
[code]to_point[/code] must be in this curve's local space.
</description>
</method>
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index bda04f010b..fcd150ad57 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -78,7 +78,7 @@
<argument index="0" name="to_point" type="Vector3">
</argument>
<description>
- Returns the closest point (in curve's local space) to [code]to_point[/code].
+ Returns the closest baked point (in curve's local space) to [code]to_point[/code].
[code]to_point[/code] must be in this curve's local space.
</description>
</method>
diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml
index ca36b2400c..14c35ae6d3 100644
--- a/doc/classes/Decal.xml
+++ b/doc/classes/Decal.xml
@@ -6,7 +6,7 @@
<description>
[Decal]s are used to project a texture onto a [Mesh] in the scene. Use Decals to add detail to a scene without affecting the underlying [Mesh]. They are often used to add weathering to building, add dirt or mud to the ground, or add variety to props. Decals can be moved at any time, making them suitable for things like blob shadows or laser sight dots.
They are made of an [AABB] and a group of [Texture2D]s specifying [Color], normal, ORM (ambient occlusion, roughness, metallic), and emission. Decals are projected within their [AABB] so altering the orientation of the Decal affects the direction in which they are projected. By default, Decals are projected down (i.e. from positive Y to negative Y).
- The [Texture2D]s associated with the Decal are automatically stored in a texture atlas which is used for drawing the decals so all decals can be drawn at once. Godot uses clustered decals, meaning they are stored in cluster data and drawn when the mesh is drawn, they are not drawn as a postprocessing effect after.
+ The [Texture2D]s associated with the Decal are automatically stored in a texture atlas which is used for drawing the decals so all decals can be drawn at once. Godot uses clustered decals, meaning they are stored in cluster data and drawn when the mesh is drawn, they are not drawn as a post-processing effect after.
</description>
<tutorials>
</tutorials>
@@ -65,7 +65,7 @@
Blends the albedo [Color] of the decal with albedo [Color] of the underlying mesh.
</member>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
- Specifies which [member VisualInstance3D.layers] this decal will project on. By default, Decals affect all layers. This is used so you can specify which types of objects receive the Decal and which do not. This is especially useful so you an ensure that dynamic objects don't accidentally receive a Decal intended for the terrain under them.
+ Specifies which [member VisualInstance3D.layers] this decal will project on. By default, Decals affect all layers. This is used so you can specify which types of objects receive the Decal and which do not. This is especially useful so you can ensure that dynamic objects don't accidentally receive a Decal intended for the terrain under them.
</member>
<member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="10.0">
Distance from the camera at which the Decal begins to fade away.
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index d3fcbc9f64..16c4348994 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -4,7 +4,7 @@
Dictionary type.
</brief_description>
<description>
- Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as an hash map or associative array.
+ Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are composed of pairs of keys (which must be unique) and values. Dictionaries will preserve the insertion order when adding elements, even though this may not be reflected when printing the dictionary. In other programming languages, this data structure is sometimes referred to as a hash map or associative array.
You can define a dictionary by placing a comma-separated list of [code]key: value[/code] pairs in curly braces [code]{}[/code].
Erasing elements while iterating over them [b]is not supported[/b] and will result in undefined behavior.
[b]Note:[/b] Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use [method duplicate].
@@ -206,7 +206,7 @@
Clear the dictionary, removing all key/value pairs.
</description>
</method>
- <method name="duplicate">
+ <method name="duplicate" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="deep" type="bool" default="false">
@@ -224,7 +224,7 @@
Erase a dictionary key/value pair by key. Returns [code]true[/code] if the given key was present in the dictionary, [code]false[/code] otherwise. Does not erase elements while iterating over the dictionary.
</description>
</method>
- <method name="get">
+ <method name="get" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="key" type="Variant">
@@ -235,7 +235,7 @@
Returns the current value for the specified key in the [Dictionary]. If the key does not exist, the method returns the value of the optional default argument, or [code]null[/code] if it is omitted.
</description>
</method>
- <method name="has">
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="key" type="Variant">
@@ -260,16 +260,16 @@
This method (like the [code]in[/code] operator) will evaluate to [code]true[/code] as long as the key exists, even if the associated value is [code]null[/code].
</description>
</method>
- <method name="has_all">
+ <method name="has_all" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="keys" type="Array">
</argument>
<description>
- Returns [code]true[/code] if the dictionary has all of the keys in the given array.
+ Returns [code]true[/code] if the dictionary has all the keys in the given array.
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
@@ -292,14 +292,14 @@
[b]Note:[/b] Dictionaries with the same keys/values but in a different order will have a different hash.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the dictionary is empty.
</description>
</method>
- <method name="keys">
+ <method name="keys" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -330,14 +330,14 @@
<description>
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
Returns the number of keys in the dictionary.
</description>
</method>
- <method name="values">
+ <method name="values" qualifiers="const">
<return type="Array">
</return>
<description>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index 2d7292717d..a9d7960501 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -6,6 +6,7 @@
<description>
Directory type. It is used to manage directories and their content (not restricted to the project folder).
When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code].
+ [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
Here is an example on how to iterate through the files of a directory:
[codeblocks]
[gdscript]
@@ -125,7 +126,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). On other platforms, or if the requested drive does not existed, the method returns an empty String.
+ On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). On other platforms, or if the requested drive does not exist, the method returns an empty String.
</description>
</method>
<method name="get_drive_count">
@@ -167,7 +168,7 @@
<return type="void">
</return>
<description>
- Closes the current stream opened with [method list_dir_begin] (whether it has been fully processed with [method get_next] or not does not matter).
+ Closes the current stream opened with [method list_dir_begin] (whether it has been fully processed with [method get_next] does not matter).
</description>
</method>
<method name="make_dir">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index d91ea6528a..91e90d051d 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -492,7 +492,7 @@
</argument>
<argument index="3" name="subtitle_track" type="String">
</argument>
- <argument index="4" name="arg4" type="int">
+ <argument index="4" name="screen" type="int">
</argument>
<description>
</description>
@@ -635,6 +635,42 @@
<description>
</description>
</method>
+ <method name="tablet_get_current_driver" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns current active tablet driver name.
+ [b]Note:[/b] This method is implemented on Windows.
+ </description>
+ </method>
+ <method name="tablet_get_driver_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the total number of available tablet drivers.
+ [b]Note:[/b] This method is implemented on Windows.
+ </description>
+ </method>
+ <method name="tablet_get_driver_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the tablet driver name for the given index.
+ [b]Note:[/b] This method is implemented on Windows.
+ </description>
+ </method>
+ <method name="tablet_set_current_driver">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ Set active tablet driver name.
+ [b]Note:[/b] This method is implemented on Windows.
+ </description>
+ </method>
<method name="virtual_keyboard_get_height" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index 5461dccd27..3a045817c2 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -90,7 +90,7 @@
<argument index="0" name="resources" type="PackedStringArray">
</argument>
<description>
- Remitted if a resource is reimported.
+ Emitted if a resource is reimported.
</description>
</signal>
<signal name="resources_reload">
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index e5401134bf..aa64ab4043 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -16,7 +16,7 @@
return "my.special.plugin"
func get_visible_name():
- return "Special Mesh Importer"
+ return "Special Mesh"
func get_recognized_extensions():
return ["special", "spec"]
@@ -44,8 +44,7 @@
# Fill the Mesh with data read in "file", left as an exercise to the reader.
var filename = save_path + "." + get_save_extension()
- ResourceSaver.save(filename, mesh)
- return OK
+ return ResourceSaver.save(filename, mesh)
[/gdscript]
[csharp]
using Godot;
@@ -60,7 +59,7 @@
public override String GetVisibleName()
{
- return "Special Mesh Importer";
+ return "Special Mesh";
}
public override Godot.Collections.Array GetRecognizedExtensions()
@@ -104,8 +103,7 @@
var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader.
String filename = savePath + "." + GetSaveExtension();
- ResourceSaver.Save(filename, mesh);
- return (int)Error.Ok;
+ return (int)ResourceSaver.Save(filename, mesh);
}
}
[/csharp]
@@ -220,7 +218,7 @@
<return type="String">
</return>
<description>
- Gets the name to display in the import window.
+ Gets the name to display in the import window. You should choose this name as a continuation to "Import as", e.g. "Import as Special Mesh".
</description>
</method>
<method name="import" qualifiers="virtual">
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index 6f03165a97..d85f95baff 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -10,14 +10,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="refresh">
- <return type="void">
- </return>
- <description>
- Refreshes the inspector.
- [b]Note:[/b] To save on CPU resources, calling this method will do nothing if the time specified in [code]docks/property_editor/auto_refresh_interval[/code] editor setting hasn't passed yet since this method was last called. (By default, this interval is set to 0.3 seconds.)
- </description>
- </method>
</methods>
<members>
<member name="scroll_horizontal_enabled" type="bool" setter="set_enable_h_scroll" getter="is_h_scroll_enabled" override="true" default="false" />
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index 3cc624f49b..8204dc931e 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -4,12 +4,12 @@
Plugin for adding custom property editors on inspector.
</brief_description>
<description>
- This plugins allows adding custom property editors to [EditorInspector].
+ These plugins allow adding custom property editors to [EditorInspector].
Plugins are registered via [method EditorPlugin.add_inspector_plugin].
When an object is edited, the [method can_handle] function is called and must return [code]true[/code] if the object type is supported.
If supported, the function [method parse_begin] will be called, allowing to place custom controls at the beginning of the class.
Subsequently, the [method parse_category] and [method parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too.
- Finally [method parse_end] will be called.
+ Finally, [method parse_end] will be called.
On each of these calls, the "add" functions can be called.
</description>
<tutorials>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index b01af71852..a5328ce382 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -10,6 +10,15 @@
<tutorials>
</tutorials>
<methods>
+ <method name="edit_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Node">
+ </argument>
+ <description>
+ Edits the given [Node]. The node will be also selected if it's inside the scene tree.
+ </description>
+ </method>
<method name="edit_resource">
<return type="void">
</return>
@@ -48,6 +57,14 @@
[b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
</description>
</method>
+ <method name="get_editor_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the actual scale of the editor UI ([code]1.0[/code] being 100% scale). This can be used to adjust position and dimensions of the UI added by plugins.
+ [b]Note:[/b] This value is set via the [code]interface/editor/display_scale[/code] and [code]interface/editor/custom_display_scale[/code] editor settings. Editor must be restarted for changes to be properly applied.
+ </description>
+ </method>
<method name="get_editor_settings">
<return type="EditorSettings">
</return>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 322cff4e43..34657a1c08 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -98,6 +98,13 @@
Creates an unshaded material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_mesh] and [method EditorNode3DGizmo.add_lines]. Should not be overridden.
</description>
</method>
+ <method name="get_gizmo_name" qualifiers="virtual">
+ <return type="String">
+ </return>
+ <description>
+ Override this method to provide the name that will appear in the gizmo visibility menu.
+ </description>
+ </method>
<method name="get_handle_name" qualifiers="virtual">
<return type="String">
</return>
@@ -131,13 +138,6 @@
Gets material from the internal list of materials. If an [EditorNode3DGizmo] is provided, it will try to get the corresponding variant (selected and/or editable).
</description>
</method>
- <method name="get_name" qualifiers="virtual">
- <return type="String">
- </return>
- <description>
- Override this method to provide the name that will appear in the gizmo visibility menu.
- </description>
- </method>
<method name="get_priority" qualifiers="virtual">
<return type="int">
</return>
@@ -170,7 +170,7 @@
<return type="bool">
</return>
<description>
- Override this method to define whether Node3D with this gizmo should be selecteble even when the gizmo is hidden.
+ Override this method to define whether Node3D with this gizmo should be selectable even when the gizmo is hidden.
</description>
</method>
<method name="redraw" qualifiers="virtual">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index be21ad65c5..61f1761249 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -169,6 +169,8 @@
<return type="bool">
</return>
<description>
+ This method is called when the editor is about to run the project. The plugin can then perform required operations before the project runs.
+ This method must return a boolean. If this method returns [code]false[/code], the project will not run. The run is aborted immediately, so this also prevents all other plugins' [method build] methods from running.
</description>
</method>
<method name="clear" qualifiers="virtual">
@@ -212,7 +214,7 @@
[gdscript]
func forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
- overlay.draw_circle(overlay.get_local_mouse_position(), 64)
+ overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white)
func forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
@@ -559,7 +561,7 @@
<argument index="0" name="script" type="Script">
</argument>
<description>
- Removes the debugger plugin with given script fromm the Debugger.
+ Removes the debugger plugin with given script from the Debugger.
</description>
</method>
<method name="remove_export_plugin">
@@ -675,6 +677,10 @@
Emitted when user changes the workspace ([b]2D[/b], [b]3D[/b], [b]Script[/b], [b]AssetLib[/b]). Also works with custom screens defined by plugins.
</description>
</signal>
+ <signal name="project_settings_changed">
+ <description>
+ </description>
+ </signal>
<signal name="resource_saved">
<argument index="0" name="resource" type="Resource">
</argument>
diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml
index db85b859e5..aa55a1653d 100644
--- a/doc/classes/EditorSceneImporter.xml
+++ b/doc/classes/EditorSceneImporter.xml
@@ -74,21 +74,11 @@
</constant>
<constant name="IMPORT_ANIMATION" value="2">
</constant>
- <constant name="IMPORT_ANIMATION_DETECT_LOOP" value="4">
+ <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="4">
</constant>
- <constant name="IMPORT_ANIMATION_OPTIMIZE" value="8">
+ <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="8">
</constant>
- <constant name="IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS" value="16">
- </constant>
- <constant name="IMPORT_ANIMATION_KEEP_VALUE_TRACKS" value="32">
- </constant>
- <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="256">
- </constant>
- <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="512">
- </constant>
- <constant name="IMPORT_MATERIALS_IN_INSTANCES" value="1024">
- </constant>
- <constant name="IMPORT_USE_COMPRESSION" value="2048">
+ <constant name="IMPORT_USE_NAMED_SKIN_BINDS" value="16">
</constant>
</constants>
</class>
diff --git a/doc/classes/EditorSceneImporterMesh.xml b/doc/classes/EditorSceneImporterMesh.xml
index 1c903bd889..9daa3f16bc 100644
--- a/doc/classes/EditorSceneImporterMesh.xml
+++ b/doc/classes/EditorSceneImporterMesh.xml
@@ -29,7 +29,7 @@
</argument>
<argument index="4" name="material" type="Material" default="null">
</argument>
- <argument index="5" name="arg5" type="String" default="&quot;&quot;">
+ <argument index="5" name="name" type="String" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -60,9 +60,17 @@
<description>
</description>
</method>
+ <method name="get_lightmap_size_hint" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_mesh">
<return type="ArrayMesh">
</return>
+ <argument index="0" name="arg0" type="Mesh">
+ </argument>
<description>
</description>
</method>
@@ -150,6 +158,14 @@
<description>
</description>
</method>
+ <method name="set_lightmap_size_hint">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{&quot;surfaces&quot;: [ ]}">
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 5cddecffa8..d1cdc4e43e 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -62,13 +62,6 @@
Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]).
</description>
</method>
- <method name="get_source_folder" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the resource folder the imported scene file is located in.
- </description>
- </method>
<method name="post_import" qualifiers="virtual">
<return type="Object">
</return>
diff --git a/doc/classes/EditorSelection.xml b/doc/classes/EditorSelection.xml
index 1ff9744b70..63e89750c3 100644
--- a/doc/classes/EditorSelection.xml
+++ b/doc/classes/EditorSelection.xml
@@ -17,6 +17,7 @@
</argument>
<description>
Adds a node to the selection.
+ [b]Note:[/b] The newly selected node will not be automatically edited in the inspector. If you want to edit a node, use [method EditorInterface.edit_node].
</description>
</method>
<method name="clear">
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 6088ae7a43..016d0128eb 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -160,6 +160,16 @@
Returns the default value of the setting specified by [code]name[/code]. This is the value that would be applied when clicking the Revert button in the Editor Settings.
</description>
</method>
+ <method name="set_builtin_action_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="actions_list" type="Array">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_favorites">
<return type="void">
</return>
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index bb356c2183..0056b5ce16 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -38,7 +38,7 @@
<return type="Dictionary">
</return>
<description>
- Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of a change the corresponding file has experienced.
+ Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of change the corresponding file has experienced.
The following integer values are being used to signify that the detected file is:
- [code]0[/code]: New to the VCS working directory
- [code]1[/code]: Modified
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 02b81ee9b7..1147b52102 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -156,13 +156,21 @@
</methods>
<members>
<member name="editor_hint" type="bool" setter="set_editor_hint" getter="is_editor_hint" default="true">
- If [code]true[/code], it is running inside the editor. Useful for tool scripts.
+ If [code]true[/code], the script is currently running inside the editor. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor:
+ [codeblock]
+ if Engine.editor_hint:
+ draw_gizmos()
+ else:
+ simulate_physics()
+ [/codeblock]
+ See [url=https://docs.godotengine.org/en/latest/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
+ [b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project.
</member>
<member name="iterations_per_second" type="int" setter="set_iterations_per_second" getter="get_iterations_per_second" default="60">
The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around tunneling issues, but keep in mind doing so will increase CPU usage.
</member>
<member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5">
- Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows to smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
+ Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
</member>
<member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0">
The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit.
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index a986ec35c6..6909fac2b7 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -169,11 +169,15 @@
</member>
<member name="reflected_light_source" type="int" setter="set_reflection_source" getter="get_reflection_source" enum="Environment.ReflectionSource" default="0">
</member>
+ <member name="sdfgi_bounce_feedback" type="float" setter="set_sdfgi_bounce_feedback" getter="get_sdfgi_bounce_feedback" default="0.0">
+ </member>
<member name="sdfgi_cascade0_distance" type="float" setter="set_sdfgi_cascade0_distance" getter="get_sdfgi_cascade0_distance" default="12.8">
</member>
<member name="sdfgi_cascades" type="int" setter="set_sdfgi_cascades" getter="get_sdfgi_cascades" enum="Environment.SDFGICascades" default="1">
</member>
<member name="sdfgi_enabled" type="bool" setter="set_sdfgi_enabled" getter="is_sdfgi_enabled" default="false">
+ If [code]true[/code], enables signed distance field global illumination.
+ [b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh.
</member>
<member name="sdfgi_energy" type="float" setter="set_sdfgi_energy" getter="get_sdfgi_energy" default="1.0">
</member>
@@ -187,8 +191,6 @@
</member>
<member name="sdfgi_read_sky_light" type="bool" setter="set_sdfgi_read_sky_light" getter="is_sdfgi_reading_sky_light" default="false">
</member>
- <member name="sdfgi_use_multi_bounce" type="bool" setter="set_sdfgi_use_multi_bounce" getter="is_sdfgi_using_multi_bounce" default="false">
- </member>
<member name="sdfgi_use_occlusion" type="bool" setter="set_sdfgi_use_occlusion" getter="is_sdfgi_using_occlusion" default="false">
</member>
<member name="sdfgi_y_scale" type="int" setter="set_sdfgi_y_scale" getter="get_sdfgi_y_scale" enum="Environment.SDFGIYScale" default="0">
@@ -272,7 +274,7 @@
</members>
<constants>
<constant name="BG_CLEAR_COLOR" value="0" enum="BGMode">
- Clears the background using the clear color defined in [member ProjectSettings.rendering/environment/default_clear_color].
+ Clears the background using the clear color defined in [member ProjectSettings.rendering/environment/defaults/default_clear_color].
</constant>
<constant name="BG_COLOR" value="1" enum="BGMode">
Clears the background using a custom clear color.
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index ff03f44789..e0781e807f 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -42,6 +42,7 @@
[/codeblocks]
In the example above, the file will be saved in the user data folder as specified in the [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] documentation.
[b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [File] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package.
+ [b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [b]Alt + F4[/b]). If you stop the project execution by pressing [b]F8[/b] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals.
</description>
<tutorials>
<link title="File system">https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
@@ -52,7 +53,7 @@
<return type="void">
</return>
<description>
- Closes the currently opened file.
+ Closes the currently opened file and prevents subsequent read/write operations. Use [method flush] to persist the data to disk without closing the file.
</description>
</method>
<method name="eof_reached" qualifiers="const">
@@ -73,6 +74,14 @@
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. See [method ResourceLoader.exists] for an alternative approach that takes resource remapping into account.
</description>
</method>
+ <method name="flush">
+ <return type="void">
+ </return>
+ <description>
+ Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file using [method close]. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully.
+ [b]Note:[/b] Only call [method flush] when you actually need it. Otherwise, it will decrease performance due to constant disk writes.
+ </description>
+ </method>
<method name="get_16" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index ed437aefd5..966be0a981 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -133,6 +133,9 @@
</constant>
</constants>
<theme_items>
+ <theme_item name="back_folder" type="Texture2D">
+ Custom icon for the back arrow.
+ </theme_item>
<theme_item name="file" type="Texture2D">
Custom icon for files.
</theme_item>
@@ -148,6 +151,9 @@
<theme_item name="folder_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )">
The color modulation applied to the folder icon.
</theme_item>
+ <theme_item name="forward_folder" type="Texture2D">
+ Custom icon for the forward arrow.
+ </theme_item>
<theme_item name="parent_folder" type="Texture2D">
Custom icon for the parent folder arrow.
</theme_item>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index edd2bd137f..20d5b6ce9b 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -175,7 +175,7 @@
</argument>
<description>
Returns the size of a character, optionally taking kerning into account if the next character is provided.
- [b]Note:[/b] Do not use this function to calculate width of the string character by character, use [method get_string_size] or [TextLine] instead.
+ [b]Note:[/b] Do not use this function to calculate width of the string character by character, use [method get_string_size] or [TextLine] instead. The height returned is the font height (see also [method get_height]) and has no relation to the glyph height.
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -247,7 +247,8 @@
<argument index="1" name="size" type="int" default="-1">
</argument>
<description>
- Returns the size size of a bounding box of a string, taking kerning and advance into account.
+ Returns the size of a bounding box of a string, taking kerning and advance into account.
+ [b]Note:[/b] Real height of the string is context-dependent and can be significantly different from the value returned by [method get_height].
See also [method draw_string].
</description>
</method>
@@ -329,10 +330,10 @@
</methods>
<members>
<member name="extra_spacing_bottom" type="int" setter="set_spacing" getter="get_spacing" default="0">
- Extra spacing at the bottom in pixels.
+ Extra spacing at the bottom of the line in pixels.
</member>
<member name="extra_spacing_top" type="int" setter="set_spacing" getter="get_spacing" default="0">
- Extra character spacing in pixels.
+ Extra spacing at the top of the line in pixels.
</member>
</members>
<constants>
diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml
index e2c35f9ce7..e426c8fb36 100644
--- a/doc/classes/FontData.xml
+++ b/doc/classes/FontData.xml
@@ -11,6 +11,45 @@
<tutorials>
</tutorials>
<methods>
+ <method name="bitmap_add_char">
+ <return type="void">
+ </return>
+ <argument index="0" name="char" type="int">
+ </argument>
+ <argument index="1" name="texture_idx" type="int">
+ </argument>
+ <argument index="2" name="rect" type="Rect2">
+ </argument>
+ <argument index="3" name="align" type="Vector2">
+ </argument>
+ <argument index="4" name="advance" type="float">
+ </argument>
+ <description>
+ Adds a character to the font, where [code]character[/code] is the Unicode value, [code]texture[/code] is the texture index, [code]rect[/code] is the region in the texture (in pixels!), [code]align[/code] is the (optional) alignment for the character and [code]advance[/code] is the (optional) advance.
+ </description>
+ </method>
+ <method name="bitmap_add_kerning_pair">
+ <return type="void">
+ </return>
+ <argument index="0" name="A" type="int">
+ </argument>
+ <argument index="1" name="B" type="int">
+ </argument>
+ <argument index="2" name="kerning" type="int">
+ </argument>
+ <description>
+ Adds a kerning pair to the bitmap font as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
+ </description>
+ </method>
+ <method name="bitmap_add_texture">
+ <return type="void">
+ </return>
+ <argument index="0" name="texture" type="Texture">
+ </argument>
+ <description>
+ Adds a texture to the bitmap font.
+ </description>
+ </method>
<method name="draw_glyph" qualifiers="const">
<return type="Vector2">
</return>
@@ -154,6 +193,15 @@
Returns list of script support overrides.
</description>
</method>
+ <method name="get_spacing" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="type" type="int">
+ </argument>
+ <description>
+ Returns the spacing for the given [code]type[/code] (see [enum SpacingType]).
+ </description>
+ </method>
<method name="get_supported_chars" qualifiers="const">
<return type="String">
</return>
@@ -256,6 +304,19 @@
Note: For non-scalable fonts [code]base_size[/code] is ignored, use [method get_base_size] to check actual font size.
</description>
</method>
+ <method name="new_bitmap">
+ <return type="void">
+ </return>
+ <argument index="0" name="height" type="float">
+ </argument>
+ <argument index="1" name="ascent" type="float">
+ </argument>
+ <argument index="2" name="base_size" type="int">
+ </argument>
+ <description>
+ Creates new, empty bitmap font.
+ </description>
+ </method>
<method name="remove_language_support_override">
<return type="void">
</return>
@@ -296,6 +357,17 @@
Adds override for [method is_script_supported].
</description>
</method>
+ <method name="set_spacing">
+ <return type="void">
+ </return>
+ <argument index="0" name="type" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ Sets the spacing for [code]type[/code] (see [enum SpacingType]) to [code]value[/code] in pixels (not relative to the font size).
+ </description>
+ </method>
<method name="set_variation">
<return type="void">
</return>
@@ -318,6 +390,14 @@
<member name="distance_field_hint" type="bool" setter="set_distance_field_hint" getter="get_distance_field_hint" default="false">
If [code]true[/code], distance field hint is enabled.
</member>
+ <member name="extra_spacing_glyph" type="int" setter="set_spacing" getter="get_spacing" default="0">
+ Extra spacing for each glyph in pixels.
+ This can be a negative number to make the distance between glyphs smaller.
+ </member>
+ <member name="extra_spacing_space" type="int" setter="set_spacing" getter="get_spacing" default="0">
+ Extra spacing for the space character in pixels.
+ This can be a negative number to make the distance between words smaller.
+ </member>
<member name="force_autohinter" type="bool" setter="set_force_autohinter" getter="get_force_autohinter" default="false">
If [code]true[/code], default autohinter is used for font hinting.
</member>
@@ -326,5 +406,11 @@
</member>
</members>
<constants>
+ <constant name="SPACING_GLYPH" value="0" enum="SpacingType">
+ Spacing for each glyph.
+ </constant>
+ <constant name="SPACING_SPACE" value="1" enum="SpacingType">
+ Spacing for the space character.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/GIProbe.xml b/doc/classes/GIProbe.xml
index 52d3698201..4f56d1ad3e 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/GIProbe.xml
@@ -5,7 +5,8 @@
</brief_description>
<description>
[GIProbe]s are used to provide high-quality real-time indirect light to scenes. They precompute the effect of objects that emit light and the effect of static geometry to simulate the behavior of complex light in real-time. [GIProbe]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked.
- Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/quality/gi_probes/quality].
+ Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/gi_probes/quality].
+ [b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh.
</description>
<tutorials>
<link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index aea106af50..e5d6581ddc 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -87,18 +87,22 @@
<member name="draw_passes" type="int" setter="set_draw_passes" getter="get_draw_passes" default="1">
The number of draw passes when rendering particles.
</member>
+ <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.
</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.
</member>
- <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
+ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
</member>
+ <member name="interpolate" type="bool" setter="set_interpolate" getter="get_interpolate" default="true">
+ </member>
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
@@ -122,6 +126,12 @@
</member>
<member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath(&quot;&quot;)">
</member>
+ <member name="trail_enabled" type="bool" setter="set_enable_trail" getter="is_trail_enabled" default="false">
+ </member>
+ <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
+ </member>
+ <member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0">
+ </member>
<member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB( -4, -4, -4, 8, 8, 8 )">
The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active.
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.
@@ -150,5 +160,13 @@
<constant name="MAX_DRAW_PASSES" value="4">
Maximum number of draw passes supported.
</constant>
+ <constant name="TRANSFORM_ALIGN_DISABLED" value="0" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Z_BILLBOARD" value="1" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Y_TO_VELOCITY" value="2" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY" value="3" enum="TransformAlign">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 2c0d9b54d1..13354ec19e 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -184,7 +184,7 @@
</argument>
<description>
Merges (combines) [code]polygon_a[/code] and [code]polygon_b[/code] and returns an array of merged polygons. This performs [constant OPERATION_UNION] between polygons.
- The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
+ The operation may result in an outer polygon (boundary) and multiple inner polygons (holes) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="offset_polygon">
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index d0b930defb..9f012008e3 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -129,7 +129,7 @@
<argument index="2" name="planes" type="Array">
</argument>
<description>
- Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. If no intersecion is found, an the returned array is empty.
+ Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. Otherwise, returns an empty array.
</description>
</method>
<method name="segment_intersects_cylinder">
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 631a30abab..b2c3bfc3ed 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -48,6 +48,8 @@
</member>
<member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="0">
</member>
+ <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling" default="false">
+ </member>
<member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0">
</member>
<member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 10afa4c339..b4536c0589 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -88,7 +88,7 @@
</return>
<description>
Gets the [HBoxContainer] that contains the zooming and grid snap controls in the top left of the graph.
- Warning: The intended usage of this function is to allow you to reposition or add your own custom controls to the container. This is an internal control and as such should not be freed. If you wish to hide this or any of it's children use their [member CanvasItem.visible] property instead.
+ Warning: The intended usage of this function is to allow you to reposition or add your own custom controls to the container. This is an internal control and as such should not be freed. If you wish to hide this or any of its children, use their [member CanvasItem.visible] property instead.
</description>
</method>
<method name="is_node_connected">
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 4b0ea4dcb1..aae3126c0f 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -6,7 +6,7 @@
<description>
A GraphNode is a container. Each GraphNode can have several input and output slots, sometimes referred to as ports, allowing connections between GraphNodes. To add a slot to GraphNode, add any [Control]-derived child node to it.
After adding at least one child to GraphNode new sections will be automatically created in the Inspector called 'Slot'. When 'Slot' is expanded you will see list with index number for each slot. You can click on each of them to expand further.
- In the Inspector you can enable (show) or disable (hide) slots. By default all slots are disabled so you may not see any slots on your GraphNode initially. You can assign a type to each slot. Only slots of the same type will be able to connect to each other. You can also assign colors to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input connections are on the left and output connections are on the right side of GraphNode. Only enabled slots are counted as connections.
+ In the Inspector you can enable (show) or disable (hide) slots. By default, all slots are disabled so you may not see any slots on your GraphNode initially. You can assign a type to each slot. Only slots of the same type will be able to connect to each other. You can also assign colors to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input connections are on the left and output connections are on the right side of GraphNode. Only enabled slots are counted as connections.
</description>
<tutorials>
</tutorials>
@@ -272,6 +272,13 @@
Emitted when the GraphNode is requested to be resized. Happens on dragging the resizer handle (see [member resizable]).
</description>
</signal>
+ <signal name="slot_updated">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Emitted when any GraphNode's slot is updated.
+ </description>
+ </signal>
</signals>
<constants>
<constant name="OVERLAY_DISABLED" value="0" enum="Overlay">
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 9ff682f79d..ddfcdf7724 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -4,7 +4,7 @@
Low-level hyper-text transfer protocol client.
</brief_description>
<description>
- Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for an higher-level alternative.[/b]
+ Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for a higher-level alternative.[/b]
[b]Note:[/b] This client only needs to connect to a host once (see [method connect_to_host]) to send multiple requests. Because of this, methods that take URLs usually take just the part after the host instead of the full URL, as the client is already connected to a host. See [method request] for a full example and to get started.
A [HTTPClient] should be reused between multiple requests or to connect to different hosts instead of creating one client per request. Supports SSL and SSL server certificate verification. HTTP status codes in the 2xx range indicate success, 3xx redirection (i.e. "try again, but over here"), 4xx something was wrong with the request, and 5xx something went wrong on the server's side.
For more information on HTTP, see https://developer.mozilla.org/en-US/docs/Web/HTTP (or read RFC 2616 to get it straight from the source: https://tools.ietf.org/html/rfc2616).
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index a65f66c72a..25667d8f79 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -229,7 +229,7 @@
<member name="accept_gzip" type="bool" setter="set_accept_gzip" getter="is_accepting_gzip" default="true">
If [code]true[/code], this header will be added to each request: [code]Accept-Encoding: gzip, deflate[/code] telling servers that it's okay to compress response bodies.
Any Response body declaring a [code]Content-Encoding[/code] of either [code]gzip[/code] or [code]deflate[/code] will then be automatically decompressed, and the uncompressed bytes will be delivered via [code]request_completed[/code].
- If the user has specified their own [code]Accept-Encoding[/code] header, then no header will be added regaurdless of [code]accept_gzip[/code].
+ If the user has specified their own [code]Accept-Encoding[/code] header, then no header will be added regardless of [code]accept_gzip[/code].
If [code]false[/code] no header will be added, and no decompression will be performed on response bodies. The raw bytes of the response body will be returned via [code]request_completed[/code].
</member>
<member name="body_size_limit" type="int" setter="set_body_size_limit" getter="get_body_size_limit" default="-1">
diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml
index 6d230bdab8..f6f2a27891 100644
--- a/doc/classes/HeightMapShape3D.xml
+++ b/doc/classes/HeightMapShape3D.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="HeightMapShape3D" inherits="Shape3D" version="4.0">
<brief_description>
- Height map shape for 3D physics (Bullet only).
+ Height map shape for 3D physics.
</brief_description>
<description>
Height map shape resource, which can be added to a [PhysicsBody3D] or [Area3D].
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 152f381a83..849f036bbd 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -31,7 +31,7 @@
<return type="Array">
</return>
<description>
- Returns all of the user's current IPv4 and IPv6 addresses as an array.
+ Returns all the user's current IPv4 and IPv6 addresses as an array.
</description>
</method>
<method name="get_local_interfaces" qualifiers="const">
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 3dba5d13aa..91a07f66e0 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -12,6 +12,18 @@
<link title="Importing images">https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_images.html</link>
</tutorials>
<methods>
+ <method name="adjust_bcs">
+ <return type="void">
+ </return>
+ <argument index="0" name="brightness" type="float">
+ </argument>
+ <argument index="1" name="contrast" type="float">
+ </argument>
+ <argument index="2" name="saturation" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="blend_rect">
<return type="void">
</return>
@@ -174,7 +186,8 @@
<return type="int" enum="Error">
</return>
<description>
- Decompresses the image if it is compressed. Returns an error if decompress function is not available.
+ Decompresses the image if it is VRAM compressed in a supported format. Returns [constant OK] if the format is supported, otherwise [constant ERR_UNAVAILABLE].
+ [b]Note:[/b] The following formats can be decompressed: DXT, RGTC, BPTC, PVRTC1. The formats ETC1 and ETC2 are not supported.
</description>
</method>
<method name="detect_alpha" qualifiers="const">
@@ -228,7 +241,7 @@
<argument index="0" name="renormalize" type="bool" default="false">
</argument>
<description>
- Generates mipmaps for the image. Mipmaps are pre-calculated and lower resolution copies of the image. Mipmaps are automatically used if the image needs to be scaled down when rendered. This improves image quality and the performance of the rendering. Returns an error if the image is compressed, in a custom format or if the image's width/height is 0.
+ Generates mipmaps for the image. Mipmaps are precalculated and lower resolution copies of the image. Mipmaps are automatically used if the image needs to be scaled down when rendered. This improves image quality and the performance of the rendering. Returns an error if the image is compressed, in a custom format or if the image's width/height is 0.
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -548,7 +561,7 @@
</methods>
<members>
<member name="data" type="Dictionary" setter="_set_data" getter="_get_data" default="{&quot;data&quot;: PackedByteArray( ),&quot;format&quot;: &quot;Lum8&quot;,&quot;height&quot;: 0,&quot;mipmaps&quot;: false,&quot;width&quot;: 0}">
- Holds all of the image's color data in a given format. See [enum Format] constants.
+ Holds all the image's color data in a given format. See [enum Format] constants.
</member>
</members>
<constants>
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 2bea482bc1..5fef56e354 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -18,11 +18,11 @@
var texture = load("res://icon.png")
$Sprite2D.texture = texture
[/codeblock]
- This is because images have to be imported as [StreamTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method.
- But do note that the image data can still be retrieved from an imported texture as well using the [method Texture2D.get_data] method, which returns a copy of the data:
+ This is because images have to be imported as a [StreamTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method.
+ [b]Note:[/b] The image can be retrieved from an imported texture using the [method Texture2D.get_image] method, which returns a copy of the image:
[codeblock]
var texture = load("res://icon.png")
- var image : Image = texture.get_data()
+ var image : Image = texture.get_image()
[/codeblock]
An [ImageTexture] is not meant to be operated from within the editor interface directly, and is mostly useful for rendering images on screen dynamically via code. If you need to generate images procedurally from within the editor, consider saving and importing images as custom texture resources implementing a new [EditorImportPlugin].
[b]Note:[/b] The maximum texture size is 16384×16384 pixels due to graphics hardware limitations.
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index cfb3e8d981..d7408cd0ff 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -49,7 +49,7 @@
<return type="Vector3">
</return>
<description>
- Returns the acceleration of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the acceleration in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
@@ -59,6 +59,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns a value between 0 and 1 representing the raw intensity of the given action, ignoring the action's deadzone. In most cases, you should use [method get_action_strength] instead.
</description>
@@ -68,6 +70,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1.
</description>
@@ -81,7 +85,7 @@
</argument>
<description>
Get axis input by specifying two actions, one negative and one positive.
- This is a horthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
+ This is a shorthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
</description>
</method>
<method name="get_connected_joypads">
@@ -102,7 +106,7 @@
<return type="Vector3">
</return>
<description>
- Returns the gravity of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the gravity in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
@@ -122,7 +126,7 @@
<argument index="1" name="axis" type="int">
</argument>
<description>
- Returns the current value of the joypad axis at given index (see [enum JoyAxisList]).
+ Returns the current value of the joypad axis at given index (see [enum JoyAxis]).
</description>
</method>
<method name="get_joy_guid" qualifiers="const">
@@ -172,7 +176,7 @@
<return type="Vector3">
</return>
<description>
- Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ Returns the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
[b]Note:[/b] This method only works on Android, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
@@ -214,6 +218,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] when the user starts pressing the action event, meaning it's [code]true[/code] only on the frame that the user pressed down the button.
This is useful for code that needs to run only once when an action is pressed, instead of every frame while it's pressed.
@@ -224,6 +230,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] when the user stops pressing the action event, meaning it's [code]true[/code] only on the frame that the user released the button.
</description>
@@ -233,6 +241,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] if you are pressing the action event. Note that if an action has multiple buttons assigned and more than one of them is pressed, releasing one button will release the action, even if some other button assigned to this action is still pressed.
</description>
@@ -245,7 +255,7 @@
<argument index="1" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButtonList]).
+ Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButton]).
</description>
</method>
<method name="is_joy_known">
@@ -263,7 +273,7 @@
<argument index="0" name="keycode" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum KeyList] constant.
+ Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum Key] constant.
</description>
</method>
<method name="is_mouse_button_pressed" qualifiers="const">
@@ -272,7 +282,7 @@
<argument index="0" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the mouse button specified with [enum ButtonList].
+ Returns [code]true[/code] if you are pressing the mouse button specified with [enum MouseButton].
</description>
</method>
<method name="joy_connection_changed">
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index 8c6063bd67..28c4773f51 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -35,6 +35,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns a value between 0.0 and 1.0 depending on the given actions' state. Useful for getting the value of events of type [InputEventJoypadMotion].
</description>
@@ -44,6 +46,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] if this input event matches a pre-defined action of any type.
</description>
@@ -55,6 +59,8 @@
</argument>
<argument index="1" name="allow_echo" type="bool" default="false">
</argument>
+ <argument index="2" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
</description>
@@ -64,6 +70,8 @@
</return>
<argument index="0" name="action" type="StringName">
</argument>
+ <argument index="1" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] if the given action is released (i.e. not pressed). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
</description>
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 1fe85a5ae8..ed290fc7e2 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -21,7 +21,7 @@
If [code]true[/code], the action's state is pressed. If [code]false[/code], the action's state is released.
</member>
<member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
- The action's strength between 0 and 1. This value is considered as equal to 0 if pressed is [code]false[/code]. The event strength allows faking analog joypad motion events, by precising how strongly is the joypad axis bent or pressed.
+ The action's strength between 0 and 1. This value is considered as equal to 0 if pressed is [code]false[/code]. The event strength allows faking analog joypad motion events, by specifying how strongly the joypad axis is bent or pressed.
</member>
</members>
<constants>
diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml
index 6ab4942f85..b1f4836f6e 100644
--- a/doc/classes/InputEventJoypadButton.xml
+++ b/doc/classes/InputEventJoypadButton.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
- Button identifier. One of the [enum JoyButtonList] button constants.
+ Button identifier. One of the [enum JoyButton] button constants.
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the button's state is pressed. If [code]false[/code], the button's state is released.
diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml
index 2d7787b568..39fdb14016 100644
--- a/doc/classes/InputEventJoypadMotion.xml
+++ b/doc/classes/InputEventJoypadMotion.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="axis" type="int" setter="set_axis" getter="get_axis" default="0">
- Axis identifier. Use one of the [enum JoyAxisList] axis constants.
+ Axis identifier. Use one of the [enum JoyAxis] axis constants.
</member>
<member name="axis_value" type="float" setter="set_axis_value" getter="get_axis_value" default="0.0">
Current position of the joystick on the given axis. The value ranges from [code]-1.0[/code] to [code]1.0[/code]. A value of [code]0[/code] means the axis is in its resting position.
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index fe91b9c13e..9f2b829823 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -32,11 +32,11 @@
If [code]true[/code], the key was already pressed before this event. It means the user is holding the key down.
</member>
<member name="keycode" type="int" setter="set_keycode" getter="get_keycode" default="0">
- The key keycode, which corresponds to one of the [enum KeyList] constants. Represent key in the current keyboard layout.
+ The key keycode, which corresponds to one of the [enum Key] constants. Represent key in the current keyboard layout.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
</member>
<member name="physical_keycode" type="int" setter="set_physical_keycode" getter="get_physical_keycode" default="0">
- Key physical keycode, which corresponds to one of the [enum KeyList] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard.
+ Key physical keycode, which corresponds to one of the [enum Key] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index 31e82bbaed..e54c3224da 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" default="0">
- The mouse button mask identifier, one of or a bitwise combination of the [enum ButtonList] button masks.
+ The mouse button mask identifier, one of or a bitwise combination of the [enum MouseButton] button masks.
</member>
<member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" default="Vector2( 0, 0 )">
The global mouse position relative to the current [Viewport] when used in [method Control._gui_input], otherwise is at 0,0.
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index d7b64a9a2d..d7e92f8bca 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
- The mouse button identifier, one of the [enum ButtonList] button or button wheel constants.
+ The mouse button identifier, one of the [enum MouseButton] button or button wheel constants.
</member>
<member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick" default="false">
If [code]true[/code], the mouse button's state is a double-click.
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index 49d29b3a53..0fb18d8e81 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -100,6 +100,8 @@
</argument>
<argument index="1" name="action" type="StringName">
</argument>
+ <argument index="2" name="exact_match" type="bool" default="false">
+ </argument>
<description>
Returns [code]true[/code] if the given event is part of an existing action. This method ignores keyboard modifiers if the given [InputEvent] is not pressed (for proper release detection). See [method action_has_event] if you don't want this behavior.
</description>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index abc327e8bb..0020cbf242 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -302,16 +302,7 @@
<argument index="1" name="custom_bg_color" type="Color">
</argument>
<description>
- [codeblocks]
- [gdscript]
- var itemList = ItemList.new()
- some_string.set_item_custom_bg_color(0, Color.red) # This will set the background color of the first item of the control to red.
- [/gdscript]
- [csharp]
- var itemList = new ItemList();
- itemList.SetItemCustomBgColor(0, Colors.Red); // This will set the background color of the first item of the control to red.
- [/csharp]
- [/codeblocks]
+ Sets the background color of the item specified by [code]idx[/code] index to the specified [Color].
</description>
</method>
<method name="set_item_custom_fg_color">
@@ -323,16 +314,6 @@
</argument>
<description>
Sets the foreground color of the item specified by [code]idx[/code] index to the specified [Color].
- [codeblocks]
- [gdscript]
- var item_list = ItemList.new()
- item_list.set_item_custom_fg_color(0, Color.red) # This will set the foreground color of the first item of the control to red.
- [/gdscript]
- [csharp]
- var itemList = new ItemList();
- itemList.SetItemCustomFgColor(0, Colors.Red); // This will set the foreground color of the first item of the control to red.
- [/csharp]
- [/codeblocks]
</description>
</method>
<method name="set_item_disabled">
@@ -615,6 +596,9 @@
<theme_item name="font_color" type="Color" default="Color( 0.63, 0.63, 0.63, 1 )">
Default text [Color] of the item.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the item.
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the item is selected.
</theme_item>
@@ -633,6 +617,9 @@
<theme_item name="line_separation" type="int" default="2">
The vertical spacing between each line of text.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the item text outline.
+ </theme_item>
<theme_item name="selected" type="StyleBox">
[StyleBox] for the selected items, used when the [ItemList] is not being focused.
</theme_item>
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 476b64a336..fdd4db6115 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -162,7 +162,10 @@
</methods>
<members>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
- If the body is at least this close to another body, this body will consider them to be colliding.
+ Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
</member>
<member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method move_and_collide] functions.
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
index a21496de54..efd3f58f88 100644
--- a/doc/classes/KinematicBody3D.xml
+++ b/doc/classes/KinematicBody3D.xml
@@ -177,7 +177,10 @@
Lock the body's Z axis movement.
</member>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
- If the body is at least this close to another body, this body will consider them to be colliding.
+ Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
</member>
</members>
<constants>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index 8574ff9836..76b9686393 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -32,7 +32,7 @@
</argument>
<description>
Returns the height of the line [code]line[/code].
- If [code]line[/code] is set to [code]-1[/code], returns biggest line height.
+ If [code]line[/code] is set to [code]-1[/code], returns the biggest line height.
If there're no lines returns font size in pixels.
</description>
</method>
diff --git a/doc/classes/LargeTexture.xml b/doc/classes/LargeTexture.xml
deleted file mode 100644
index a1d172e4b1..0000000000
--- a/doc/classes/LargeTexture.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LargeTexture" inherits="Texture2D" version="4.0">
- <brief_description>
- A [Texture2D] capable of storing many smaller textures with offsets.
- </brief_description>
- <description>
- A [Texture2D] capable of storing many smaller textures with offsets.
- You can dynamically add pieces ([Texture2D]s) to this [LargeTexture] using different offsets.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_piece">
- <return type="int">
- </return>
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <description>
- Adds [code]texture[/code] to this [LargeTexture], starting on offset [code]ofs[/code].
- </description>
- </method>
- <method name="clear">
- <return type="void">
- </return>
- <description>
- Clears the [LargeTexture].
- </description>
- </method>
- <method name="get_piece_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of pieces currently in this [LargeTexture].
- </description>
- </method>
- <method name="get_piece_offset" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the offset of the piece with the index [code]idx[/code].
- </description>
- </method>
- <method name="get_piece_texture" qualifiers="const">
- <return type="Texture2D">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [Texture2D] of the piece with the index [code]idx[/code].
- </description>
- </method>
- <method name="set_piece_offset">
- <return type="void">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="ofs" type="Vector2">
- </argument>
- <description>
- Sets the offset of the piece with the index [code]idx[/code] to [code]ofs[/code].
- </description>
- </method>
- <method name="set_piece_texture">
- <return type="void">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <description>
- Sets the [Texture2D] of the piece with index [code]idx[/code] to [code]texture[/code].
- </description>
- </method>
- <method name="set_size">
- <return type="void">
- </return>
- <argument index="0" name="size" type="Vector2">
- </argument>
- <description>
- Sets the size of this [LargeTexture].
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 111473e098..6bae612c9f 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -58,7 +58,7 @@
If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
</member>
<member name="light_projector" type="Texture2D" setter="set_projector" getter="get_projector">
- [Texture2D] projected by light. [member shadow_enabled] must be on for the projector to work. Light projectors make the light appear as if it is shining through a colored but transparent object, almost like light shining through stained glass.
+ [Texture2D] projected by light. [member shadow_enabled] must be on for the projector to work. Light projectors make the light appear as if it is shining through a colored but transparent object, almost like light shining through stained-glass.
</member>
<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s. Increasing this value will make the light fade out slower and shadows appear blurrier. This can be used to simulate area lights to an extent.
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 61ecff52e3..7adf19632e 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -12,34 +12,25 @@
- [kbd]Ctrl + Z[/kbd]: Undo
- [kbd]Ctrl + ~[/kbd]: Swap input direction.
- [kbd]Ctrl + Shift + Z[/kbd]: Redo
- - [kbd]Ctrl + U[/kbd]: Delete text from the cursor position to the beginning of the line
- - [kbd]Ctrl + K[/kbd]: Delete text from the cursor position to the end of the line
+ - [kbd]Ctrl + U[/kbd]: Delete text from the caret position to the beginning of the line
+ - [kbd]Ctrl + K[/kbd]: Delete text from the caret position to the end of the line
- [kbd]Ctrl + A[/kbd]: Select all text
- - [kbd]Up Arrow[/kbd]/[kbd]Down Arrow[/kbd]: Move the cursor to the beginning/end of the line
+ - [kbd]Up Arrow[/kbd]/[kbd]Down Arrow[/kbd]: Move the caret to the beginning/end of the line
On macOS, some extra keyboard shortcuts are available:
- - [kbd]Ctrl + F[/kbd]: Same as [kbd]Right Arrow[/kbd], move the cursor one character right
- - [kbd]Ctrl + B[/kbd]: Same as [kbd]Left Arrow[/kbd], move the cursor one character left
- - [kbd]Ctrl + P[/kbd]: Same as [kbd]Up Arrow[/kbd], move the cursor to the previous line
- - [kbd]Ctrl + N[/kbd]: Same as [kbd]Down Arrow[/kbd], move the cursor to the next line
- - [kbd]Ctrl + D[/kbd]: Same as [kbd]Delete[/kbd], delete the character on the right side of cursor
- - [kbd]Ctrl + H[/kbd]: Same as [kbd]Backspace[/kbd], delete the character on the left side of the cursor
- - [kbd]Ctrl + A[/kbd]: Same as [kbd]Home[/kbd], move the cursor to the beginning of the line
- - [kbd]Ctrl + E[/kbd]: Same as [kbd]End[/kbd], move the cursor to the end of the line
- - [kbd]Cmd + Left Arrow[/kbd]: Same as [kbd]Home[/kbd], move the cursor to the beginning of the line
- - [kbd]Cmd + Right Arrow[/kbd]: Same as [kbd]End[/kbd], move the cursor to the end of the line
+ - [kbd]Ctrl + F[/kbd]: Same as [kbd]Right Arrow[/kbd], move the caret one character right
+ - [kbd]Ctrl + B[/kbd]: Same as [kbd]Left Arrow[/kbd], move the caret one character left
+ - [kbd]Ctrl + P[/kbd]: Same as [kbd]Up Arrow[/kbd], move the caret to the previous line
+ - [kbd]Ctrl + N[/kbd]: Same as [kbd]Down Arrow[/kbd], move the caret to the next line
+ - [kbd]Ctrl + D[/kbd]: Same as [kbd]Delete[/kbd], delete the character on the right side of caret
+ - [kbd]Ctrl + H[/kbd]: Same as [kbd]Backspace[/kbd], delete the character on the left side of the caret
+ - [kbd]Ctrl + A[/kbd]: Same as [kbd]Home[/kbd], move the caret to the beginning of the line
+ - [kbd]Ctrl + E[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line
+ - [kbd]Cmd + Left Arrow[/kbd]: Same as [kbd]Home[/kbd], move the caret to the beginning of the line
+ - [kbd]Cmd + Right Arrow[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line
</description>
<tutorials>
</tutorials>
<methods>
- <method name="append_at_cursor">
- <return type="void">
- </return>
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Adds [code]text[/code] after the cursor. If the resulting value is longer than [member max_length], nothing happens.
- </description>
- </method>
<method name="clear">
<return type="void">
</return>
@@ -54,11 +45,11 @@
Removes all OpenType features.
</description>
</method>
- <method name="delete_char_at_cursor">
+ <method name="delete_char_at_caret">
<return type="void">
</return>
<description>
- Deletes one character at the cursor's current position (equivalent to pressing [kbd]Delete[/kbd]).
+ Deletes one character at the caret's current position (equivalent to pressing [kbd]Delete[/kbd]).
</description>
</method>
<method name="delete_text">
@@ -99,7 +90,16 @@
<return type="int">
</return>
<description>
- Returns the scroll offset due to [member caret_position], as a number of characters.
+ Returns the scroll offset due to [member caret_column], as a number of characters.
+ </description>
+ </method>
+ <method name="insert_text_at_caret">
+ <return type="void">
+ </return>
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ Inserts [code]text[/code] at the caret. If the resulting value is longer than [member max_length], nothing happens.
</description>
</method>
<method name="menu_option">
@@ -159,21 +159,21 @@
<member name="align" type="int" setter="set_align" getter="get_align" enum="LineEdit.Align" default="0">
Text alignment as defined in the [enum Align] enum.
</member>
- <member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled" default="false">
- If [code]true[/code], the caret (visual cursor) blinks.
+ <member name="caret_blink" type="bool" setter="set_caret_blink_enabled" getter="is_caret_blink_enabled" default="false">
+ If [code]true[/code], the caret (text cursor) blinks.
</member>
- <member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed" default="0.65">
+ <member name="caret_blink_speed" type="float" setter="set_caret_blink_speed" getter="get_caret_blink_speed" default="0.65">
Duration (in seconds) of a caret's blinking cycle.
</member>
- <member name="caret_force_displayed" type="bool" setter="cursor_set_force_displayed" getter="cursor_get_force_displayed" default="false">
+ <member name="caret_column" type="int" setter="set_caret_column" getter="get_caret_column" default="0">
+ The caret's column position inside the [LineEdit]. When set, the text may scroll to accommodate it.
+ </member>
+ <member name="caret_force_displayed" type="bool" setter="set_caret_force_displayed" getter="is_caret_force_displayed" default="false">
</member>
- <member name="caret_mid_grapheme" type="bool" setter="set_mid_grapheme_caret_enabled" getter="get_mid_grapheme_caret_enabled" default="false">
+ <member name="caret_mid_grapheme" type="bool" setter="set_caret_mid_grapheme_enabled" getter="is_caret_mid_grapheme_enabled" default="false">
Allow moving caret, selecting and removing the individual composite character components.
Note: [kbd]Backspace[/kbd] is always removing individual composite character components.
</member>
- <member name="caret_position" type="int" setter="set_cursor_position" getter="get_cursor_position" default="0">
- The cursor's position inside the [LineEdit]. When set, the text may scroll to accommodate it.
- </member>
<member name="clear_button_enabled" type="bool" setter="set_clear_button_enabled" getter="is_clear_button_enabled" default="false">
If [code]true[/code], the [LineEdit] will show a clear button if [code]text[/code] is not empty, which can be used to clear the text quickly.
</member>
@@ -186,7 +186,7 @@
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true">
If [code]false[/code], existing text cannot be modified and new text cannot be added.
</member>
- <member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length" getter="get_expand_to_text_length" default="false">
+ <member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length_enabled" getter="is_expand_to_text_length_enabled" default="false">
If [code]true[/code], the [LineEdit] width will increase to stay longer than the [member text]. It will [b]not[/b] compress if the [member text] is shortened.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
@@ -276,7 +276,7 @@
Copies the selected text.
</constant>
<constant name="MENU_PASTE" value="2" enum="MenuItems">
- Pastes the clipboard text over the selected text (or at the cursor's position).
+ Pastes the clipboard text over the selected text (or at the caret's position).
Non-printable escape characters are automatically stripped from the OS clipboard via [method String.strip_escapes].
</constant>
<constant name="MENU_CLEAR" value="3" enum="MenuItems">
@@ -359,6 +359,9 @@
</constant>
</constants>
<theme_items>
+ <theme_item name="caret_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
+ Color of the [LineEdit]'s caret (text cursor).
+ </theme_item>
<theme_item name="clear" type="Texture2D">
Texture for the clear button. See [member clear_button_enabled].
</theme_item>
@@ -368,9 +371,6 @@
<theme_item name="clear_button_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )">
Color used for the clear button when it's pressed.
</theme_item>
- <theme_item name="cursor_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
- Color of the [LineEdit]'s visual cursor (caret).
- </theme_item>
<theme_item name="focus" type="StyleBox">
Background used when [LineEdit] has GUI focus.
</theme_item>
@@ -380,6 +380,9 @@
<theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
Default font color.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [LineEdit].
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )">
Font color for selected text (inside the selection rectangle).
</theme_item>
@@ -389,12 +392,15 @@
<theme_item name="font_uneditable_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )">
Font color when editing is disabled.
</theme_item>
- <theme_item name="minimum_spaces" type="int" default="12">
- Minimum horizontal space for the text (not counting the clear button and content margins). This value is measured in count of space characters (i.e. this amount of space characters can be displayed without scrolling).
+ <theme_item name="minimum_character_width" type="int" default="4">
+ Minimum horizontal space for the text (not counting the clear button and content margins). This value is measured in count of 'M' characters (i.e. this amount of 'M' characters can be displayed without scrolling).
</theme_item>
<theme_item name="normal" type="StyleBox">
Default background for the [LineEdit].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="read_only" type="StyleBox">
Background used when [LineEdit] is in read-only mode ([member editable] is set to [code]false[/code]).
</theme_item>
diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml
index 0227870152..6e2f4399b3 100644
--- a/doc/classes/LinkButton.xml
+++ b/doc/classes/LinkButton.xml
@@ -84,12 +84,18 @@
<theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
Text [Color] used when the [LinkButton] is being hovered.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [LinkButton].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the [LinkButton] is being pressed.
</theme_item>
<theme_item name="font_size" type="int">
Font size of the [LinkButton]'s text.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="underline_spacing" type="int" default="2">
The vertical space between the baseline of text and the underline.
</theme_item>
diff --git a/doc/classes/MarginContainer.xml b/doc/classes/MarginContainer.xml
index c8eebd4677..a51632d5f1 100644
--- a/doc/classes/MarginContainer.xml
+++ b/doc/classes/MarginContainer.xml
@@ -5,21 +5,23 @@
</brief_description>
<description>
Adds a top, left, bottom, and right margin to all [Control] nodes that are direct children of the container. To control the [MarginContainer]'s margin, use the [code]margin_*[/code] theme properties listed below.
- [b]Note:[/b] Be careful, [Control] margin values are different than the constant margin values. If you want to change the custom margin values of the [MarginContainer] by code, you should use the following examples:
+ [b]Note:[/b] Be careful, [Control] margin values are different from the constant margin values. If you want to change the custom margin values of the [MarginContainer] by code, you should use the following examples:
[codeblocks]
[gdscript]
+ # This code sample assumes the current script is extending MarginContainer.
var margin_value = 100
- set("custom_constants/margin_top", margin_value)
- set("custom_constants/margin_left", margin_value)
- set("custom_constants/margin_bottom", margin_value)
- set("custom_constants/margin_right", margin_value)
+ add_theme_constant_override("margin_top", margin_value)
+ add_theme_constant_override("margin_left", margin_value)
+ add_theme_constant_override("margin_bottom", margin_value)
+ add_theme_constant_override("margin_right", margin_value)
[/gdscript]
[csharp]
+ // This code sample assumes the current script is extending MarginContainer.
int marginValue = 100;
- Set("custom_constants/margin_top", marginValue);
- Set("custom_constants/margin_left", marginValue);
- Set("custom_constants/margin_bottom", marginValue);
- Set("custom_constants/margin_right", marginValue);
+ AddThemeConstantOverride("margin_top", marginValue);
+ AddThemeConstantOverride("margin_left", marginValue);
+ AddThemeConstantOverride("margin_bottom", marginValue);
+ AddThemeConstantOverride("margin_right", marginValue);
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 1e8874fdc5..7cbf9d3dfe 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Special button that brings up a [PopupMenu] when clicked.
- New items can be created inside this [PopupMenu] using [code]get_popup().add_item("My Item Name")[/code]. You can also create them directly from the editor. To do so, select the [MenuButton] node, then in the toolbar at the top of the 2D editor, click [b]Items[/b] then click [b]Add[/b] in the popup. You will be able to give each items new properties.
+ New items can be created inside this [PopupMenu] using [code]get_popup().add_item("My Item Name")[/code]. You can also create them directly from the editor. To do so, select the [MenuButton] node, then in the toolbar at the top of the 2D editor, click [b]Items[/b] then click [b]Add[/b] in the popup. You will be able to give each item new properties.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
@@ -65,6 +65,9 @@
<theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
Text [Color] used when the [MenuButton] is being hovered.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [MenuButton].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the [MenuButton] is being pressed.
</theme_item>
@@ -80,6 +83,9 @@
<theme_item name="normal" type="StyleBox">
Default [StyleBox] for the [MenuButton].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
[StyleBox] used when the [MenuButton] is being pressed.
</theme_item>
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index 82cd392cd3..b5ab296bd0 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -27,6 +27,13 @@
This helper creates a [MeshInstance3D] child node with gizmos at every vertex calculated from the mesh geometry. It's mainly used for testing.
</description>
</method>
+ <method name="create_multiple_convex_collisions">
+ <return type="void">
+ </return>
+ <description>
+ This helper creates a [StaticBody3D] child node with multiple [ConvexPolygonShape3D] collision shapes calculated from the mesh geometry via convex decomposition. It's mainly used for testing.
+ </description>
+ </method>
<method name="create_trimesh_collision">
<return type="void">
</return>
@@ -43,7 +50,7 @@
Returns the [Material] that will be used by the [Mesh] when drawing. This can return the [member GeometryInstance3D.material_override], the surface override [Material] defined in this [MeshInstance3D], or the surface [Material] defined in the [Mesh]. For example, if [member GeometryInstance3D.material_override] is used, all surfaces will return the override material.
</description>
</method>
- <method name="get_surface_material" qualifiers="const">
+ <method name="get_surface_override_material" qualifiers="const">
<return type="Material">
</return>
<argument index="0" name="surface" type="int">
@@ -52,14 +59,14 @@
Returns the override [Material] for the specified surface of the [Mesh] resource.
</description>
</method>
- <method name="get_surface_material_count" qualifiers="const">
+ <method name="get_surface_override_material_count" qualifiers="const">
<return type="int">
</return>
<description>
- Returns the number of surface materials.
+ Returns the number of surface override materials. This is equivalent to [method Mesh.get_surface_count].
</description>
</method>
- <method name="set_surface_material">
+ <method name="set_surface_override_material">
<return type="void">
</return>
<argument index="0" name="surface" type="int">
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 6ebfc946dc..2adebdb306 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -6,7 +6,7 @@
<description>
MultiMesh provides low-level mesh instancing. Drawing thousands of [MeshInstance3D] nodes can be slow, since each object is submitted to the GPU then drawn individually.
MultiMesh is much faster as it can draw thousands of instances with a single draw call, resulting in less API overhead.
- As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always rendered (they are spatially indexed as one, for the whole object).
+ As a drawback, if the instances are too far away of each other, performance may be reduced as every single instance will always render (they are spatially indexed as one, for the whole object).
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
</description>
<tutorials>
diff --git a/doc/classes/Navigation2D.xml b/doc/classes/Navigation2D.xml
deleted file mode 100644
index abac29bdb7..0000000000
--- a/doc/classes/Navigation2D.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Navigation2D" inherits="Node2D" version="4.0">
- <brief_description>
- 2D navigation and pathfinding node.
- </brief_description>
- <description>
- Navigation2D provides navigation and pathfinding within a 2D area, specified as a collection of [NavigationPolygon] resources. These are automatically collected from child [NavigationRegion2D] nodes.
- </description>
- <tutorials>
- <link title="2D Navigation Demo">https://godotengine.org/asset-library/asset/117</link>
- </tutorials>
- <methods>
- <method name="get_closest_point" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="to_point" type="Vector2">
- </argument>
- <description>
- Returns the point closest to the provided [code]to_point[/code] on the navigation mesh surface.
- </description>
- </method>
- <method name="get_closest_point_owner" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="to_point" type="Vector2">
- </argument>
- <description>
- Returns the owner region RID for the point returned by [method get_closest_point].
- </description>
- </method>
- <method name="get_rid" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="get_simple_path" qualifiers="const">
- <return type="PackedVector2Array">
- </return>
- <argument index="0" name="start" type="Vector2">
- </argument>
- <argument index="1" name="end" type="Vector2">
- </argument>
- <argument index="2" name="optimize" type="bool" default="true">
- </argument>
- <description>
- Returns the path between two given points. Points are in local coordinate space. If [code]optimize[/code] is [code]true[/code] (the default), the path is smoothed by merging path segments where possible.
- </description>
- </method>
- </methods>
- <members>
- <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="10.0">
- </member>
- <member name="edge_connection_margin" type="float" setter="set_edge_connection_margin" getter="get_edge_connection_margin" default="100.0">
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Navigation3D.xml b/doc/classes/Navigation3D.xml
deleted file mode 100644
index e7a4fe3c43..0000000000
--- a/doc/classes/Navigation3D.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Navigation3D" inherits="Node3D" version="4.0">
- <brief_description>
- Mesh-based navigation and pathfinding node.
- </brief_description>
- <description>
- Provides navigation and pathfinding within a collection of [NavigationMesh]es. These will be automatically collected from child [NavigationRegion3D] nodes. In addition to basic pathfinding, this class also assists with aligning navigation agents with the meshes they are navigating on.
- </description>
- <tutorials>
- <link title="3D Navmesh Demo">https://godotengine.org/asset-library/asset/124</link>
- </tutorials>
- <methods>
- <method name="get_closest_point" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the point closest to the provided [code]to_point[/code] on the navigation mesh surface.
- </description>
- </method>
- <method name="get_closest_point_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the normal for the point returned by [method get_closest_point].
- </description>
- </method>
- <method name="get_closest_point_owner" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the owner region RID for the point returned by [method get_closest_point].
- </description>
- </method>
- <method name="get_closest_point_to_segment" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="start" type="Vector3">
- </argument>
- <argument index="1" name="end" type="Vector3">
- </argument>
- <argument index="2" name="use_collision" type="bool" default="false">
- </argument>
- <description>
- Returns the closest point between the navigation surface and the segment.
- </description>
- </method>
- <method name="get_rid" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="get_simple_path" qualifiers="const">
- <return type="PackedVector3Array">
- </return>
- <argument index="0" name="start" type="Vector3">
- </argument>
- <argument index="1" name="end" type="Vector3">
- </argument>
- <argument index="2" name="optimize" type="bool" default="true">
- </argument>
- <description>
- Returns the path between two given points. Points are in local coordinate space. If [code]optimize[/code] is [code]true[/code] (the default), the agent properties associated with each [NavigationMesh] (radius, height, etc.) are considered in the path calculation, otherwise they are ignored.
- </description>
- </method>
- </methods>
- <members>
- <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="0.3">
- </member>
- <member name="edge_connection_margin" type="float" setter="set_edge_connection_margin" getter="get_edge_connection_margin" default="5.0">
- </member>
- <member name="up_vector" type="Vector3" setter="set_up_vector" getter="get_up_vector" default="Vector3( 0, 1, 0 )">
- Defines which direction is up. By default, this is [code](0, 1, 0)[/code], which is the world's "up" direction.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 5a9c31ef67..de81ae4d91 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -4,7 +4,7 @@
2D Agent used in navigation for collision avoidance.
</brief_description>
<description>
- 2D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. This can be done by having the agent as a child of a [Navigation2D] node, or using [method set_navigation]. [NavigationAgent2D] is physics safe.
+ 2D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. [NavigationAgent2D] is physics safe.
</description>
<tutorials>
</tutorials>
@@ -37,18 +37,17 @@
Returns which index the agent is currently on in the navigation path's [PackedVector2Array].
</description>
</method>
- <method name="get_navigation" qualifiers="const">
- <return type="Node">
+ <method name="get_next_location">
+ <return type="Vector2">
</return>
<description>
- Returns the [Navigation2D] node that the agent is using for its navigation system.
+ Returns a [Vector2] in global coordinates, that can be moved to, making sure that there are no static objects in the way. If the agent does not have a navigation path, it will return the position of the agent's parent.
</description>
</method>
- <method name="get_next_location">
- <return type="Vector2">
+ <method name="get_rid" qualifiers="const">
+ <return type="RID">
</return>
<description>
- Returns a [Vector2] in global coordinates, that can be moved to, making sure that there are no static objects in the way. If the agent does not have a navigation path, it will return the position of the agent's parent.
</description>
</method>
<method name="get_target_location" qualifiers="const">
@@ -79,15 +78,6 @@
Returns true if the target location is reached. The target location is set using [method set_target_location]. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
</description>
</method>
- <method name="set_navigation">
- <return type="void">
- </return>
- <argument index="0" name="navigation" type="Node">
- </argument>
- <description>
- Sets the [Navigation2D] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation2D] node.
- </description>
- </method>
<method name="set_target_location">
<return type="void">
</return>
@@ -127,7 +117,7 @@
The distance threshold before a target is considered to be reached. This will allow an agent to not have to hit a point on the path exactly, but in the area.
</member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="20.0">
- The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithim, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
+ The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
</members>
<signals>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index f9df1d390b..8942a37774 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -4,7 +4,7 @@
3D Agent used in navigation for collision avoidance.
</brief_description>
<description>
- 3D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. This can be done by having the agent as a child of a [Navigation3D] node, or using [method set_navigation]. [NavigationAgent3D] is physics safe.
+ 3D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. [NavigationAgent3D] is physics safe.
</description>
<tutorials>
</tutorials>
@@ -37,18 +37,17 @@
Returns which index the agent is currently on in the navigation path's [PackedVector3Array].
</description>
</method>
- <method name="get_navigation" qualifiers="const">
- <return type="Node">
+ <method name="get_next_location">
+ <return type="Vector3">
</return>
<description>
- Returns the [Navigation3D] node that the agent is using for its navigation system.
+ Returns a [Vector3] in global coordinates, that can be moved to, making sure that there are no static objects in the way. If the agent does not have a navigation path, it will return the origin of the agent's parent.
</description>
</method>
- <method name="get_next_location">
- <return type="Vector3">
+ <method name="get_rid" qualifiers="const">
+ <return type="RID">
</return>
<description>
- Returns a [Vector3] in global coordinates, that can be moved to, making sure that there are no static objects in the way. If the agent does not have a navigation path, it will return the origin of the agent's parent.
</description>
</method>
<method name="get_target_location" qualifiers="const">
@@ -79,15 +78,6 @@
Returns true if the target location is reached. The target location is set using [method set_target_location]. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
</description>
</method>
- <method name="set_navigation">
- <return type="void">
- </return>
- <argument index="0" name="navigation" type="Node">
- </argument>
- <description>
- Sets the [Navigation3D] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation3D] node.
- </description>
- </method>
<method name="set_target_location">
<return type="void">
</return>
@@ -133,7 +123,7 @@
The distance threshold before a target is considered to be reached. This will allow an agent to not have to hit a point on the path exactly, but in the area.
</member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="5.0">
- The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithim, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
+ The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
</members>
<signals>
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index dd7464ac0e..871c92798a 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -79,6 +79,7 @@
</methods>
<members>
<member name="agent/height" type="float" setter="set_agent_height" getter="get_agent_height" default="2.0">
+ The minimum Y space needed for navigation to be generated.
</member>
<member name="agent/max_climb" type="float" setter="set_agent_max_climb" getter="get_agent_max_climb" default="0.9">
The maximum height difference between two areas for navigation to be generated between them.
@@ -87,8 +88,10 @@
The maximum angle a slope can be at for navigation to be generated on it.
</member>
<member name="agent/radius" type="float" setter="set_agent_radius" getter="get_agent_radius" default="0.6">
+ Determines where the edge of a navigation mesh is. This way an agent will not overlap with another mesh or stand over nothing.
</member>
<member name="cell/height" type="float" setter="set_cell_height" getter="get_cell_height" default="0.2">
+ The height of a cell.
</member>
<member name="cell/size" type="float" setter="set_cell_size" getter="get_cell_size" default="0.3">
The size of cells in the [NavigationMesh].
@@ -111,7 +114,7 @@
The physics layers used to generate the [NavigationMesh].
</member>
<member name="geometry/parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" default="0">
- What kind of geomerty is used to generate the [NavigationMesh].
+ What kind of geometry is used to generate the [NavigationMesh].
</member>
<member name="geometry/source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" default="0">
Which geometry is used to generate the [NavigationMesh].
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index ddd96975f1..2e94eb0bba 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -4,27 +4,11 @@
2D Obstacle used in navigation for collision avoidance.
</brief_description>
<description>
- 2D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. This can be done by having the obstacle as a child of a [Navigation2D] node, or using [method set_navigation]. [NavigationObstacle2D] is physics safe.
+ 2D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle2D] is physics safe.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="get_navigation" qualifiers="const">
- <return type="Node">
- </return>
- <description>
- Returns the [Navigation2D] node that the obstacle is using for its navigation system.
- </description>
- </method>
- <method name="set_navigation">
- <return type="void">
- </return>
- <argument index="0" name="navigation" type="Node">
- </argument>
- <description>
- Sets the [Navigation2D] node used by the obstacle. Useful when you don't want to make the obstacle a child of a [Navigation2D] node.
- </description>
- </method>
</methods>
<constants>
</constants>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
index e01a40ed73..d7454a7bea 100644
--- a/doc/classes/NavigationObstacle3D.xml
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -4,27 +4,11 @@
3D Obstacle used in navigation for collision avoidance.
</brief_description>
<description>
- 3D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. This can be done by having the obstacle as a child of a [Navigation3D] node, or using [method set_navigation]. [NavigationObstacle3D] is physics safe.
+ 3D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle3D] is physics safe.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="get_navigation" qualifiers="const">
- <return type="Node">
- </return>
- <description>
- Returns the [Navigation3D] node that the obstacle is using for its navigation system.
- </description>
- </method>
- <method name="set_navigation">
- <return type="void">
- </return>
- <argument index="0" name="navigation" type="Node">
- </argument>
- <description>
- Sets the [Navigation3D] node used by the obstacle. Useful when you don't want to make the obstacle a child of a [Navigation3D] node.
- </description>
- </method>
</methods>
<constants>
</constants>
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index aef114e1db..33a3f04c3d 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationRegion2D" inherits="Node2D" version="4.0">
<brief_description>
+ A region of the 2D navigation map.
</brief_description>
<description>
+ A region of the navigation map. It tells the [NavigationServer2D] what can be navigated and what cannot, based on its [NavigationPolygon] resource.
+ Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer2D.map_set_edge_connection_margin].
+ [b]Note:[/b] Overlapping two regions' polygons is not enough for connecting two regions. They must share a similar edge.
</description>
<tutorials>
</tutorials>
@@ -10,8 +14,13 @@
</methods>
<members>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
+ Determines if the [NavigationRegion2D] is enabled or disabled.
+ </member>
+ <member name="layers" type="int" setter="set_layers" getter="get_layers" default="1">
+ A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer2D.map_get_path].
</member>
<member name="navpoly" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon">
+ The [NavigationPolygon] resource to use.
</member>
</members>
<constants>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index b70bfb6596..2904ba4200 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -4,7 +4,8 @@
A region of the navigation map.
</brief_description>
<description>
- A region of the navigation map. It tells the [Navigation3D] node what can be navigated and what cannot, based on the [NavigationMesh] resource. This should be a child of a [Navigation3D] node (even not a direct child).
+ A region of the navigation map. It tells the [NavigationServer3D] what can be navigated and what cannot, based on its [NavigationMesh] resource.
+ Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer3D.map_set_edge_connection_margin].
</description>
<tutorials>
</tutorials>
@@ -21,6 +22,9 @@
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
Determines if the [NavigationRegion3D] is enabled or disabled.
</member>
+ <member name="layers" type="int" setter="set_layers" getter="get_layers" default="1">
+ A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path].
+ </member>
<member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
The [NavigationMesh] resource to use.
</member>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 5f0b04487e..b0a57ed227 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -4,7 +4,12 @@
Server interface for low-level 2D navigation access
</brief_description>
<description>
- NavigationServer2D is the server responsible for all 2D navigation. It creates the agents, maps, and regions for navigation to work as expected. This keeps tracks of any call and executes them during the sync phase. This means that you can request any change to the map, using any thread, without worrying.
+ NavigationServer2D is the server responsible for all 2D navigation. It handles several objects, namely maps, regions and agents.
+ Maps are made up of regions, which are made of navigation polygons. Together, they define the navigable areas in the 2D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ You may assign navigation layers to regions with [method NavigationServer2D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer2D.map_get_path]. This allows allowing or forbidding some areas to 2D objects.
+ To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
+ [b]Note:[/b] the collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
+ This server keeps tracks of any call and executes them during the sync phase. This means that you can request any change to the map, using any thread, without worrying.
</description>
<tutorials>
<link title="2D Navigation Demo">https://godotengine.org/asset-library/asset/117</link>
@@ -207,8 +212,10 @@
</argument>
<argument index="3" name="optimize" type="bool">
</argument>
+ <argument index="4" name="layers" type="int" default="1">
+ </argument>
<description>
- Returns the navigation path to reach the destination from the origin, while avoiding static obstacles.
+ Returns the navigation path to reach the destination from the origin. [code]layers[/code] is a bitmask of all region layers that are allowed to be in the path.
</description>
</method>
<method name="map_is_active" qualifiers="const">
@@ -260,6 +267,57 @@
Creates a new region.
</description>
</method>
+ <method name="region_get_connection_pathway_end" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connection_pathway_start" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connections_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns how many connections this [code]region[/code] has with other regions in the map.
+ </description>
+ </method>
+ <method name="region_get_layers" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns the region's layers.
+ </description>
+ </method>
+ <method name="region_set_layers" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="layers" type="int">
+ </argument>
+ <description>
+ Set the region's layers. This allows selecting regions from a path request (when using [method NavigationServer2D.map_get_path]).
+ </description>
+ </method>
<method name="region_set_map" qualifiers="const">
<return type="void">
</return>
@@ -294,6 +352,15 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="map_changed">
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Emitted when a navigation map is updated, when a region moves or is modified.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 95890c4b4c..b098a7fc20 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -4,7 +4,12 @@
Server interface for low-level 3D navigation access
</brief_description>
<description>
- NavigationServer3D is the server responsible for all 3D navigation. It creates the agents, maps, and regions for navigation to work as expected. This keeps tracks of any call and executes them during the sync phase. This means that you can request any change to the map, using any thread, without worrying.
+ NavigationServer3D is the server responsible for all 3D navigation. It handles several objects, namely maps, regions and agents.
+ Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ You may assign navigation layers to regions with [method NavigationServer3D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer3D.map_get_path]. This allows allowing or forbidding some areas to 3D objects.
+ To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
+ [b]Note:[/b] the collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
+ This server keeps tracks of any call and executes them during the sync phase. This means that you can request any change to the map, using any thread, without worrying.
</description>
<tutorials>
<link title="3D Navmesh Demo">https://godotengine.org/asset-library/asset/124</link>
@@ -219,7 +224,7 @@
<argument index="0" name="map" type="RID">
</argument>
<description>
- Returns the edge connection margin of the map.
+ Returns the edge connection margin of the map. This distance is the minimum vertex distance needed to connect two edges from different regions.
</description>
</method>
<method name="map_get_path" qualifiers="const">
@@ -233,8 +238,10 @@
</argument>
<argument index="3" name="optimize" type="bool">
</argument>
+ <argument index="4" name="layers" type="int" default="1">
+ </argument>
<description>
- Returns the navigation path to reach the destination from the origin.
+ Returns the navigation path to reach the destination from the origin. [code]layers[/code] is a bitmask of all region layers that are allowed to be in the path.
</description>
</method>
<method name="map_get_up" qualifiers="const">
@@ -285,7 +292,7 @@
<argument index="1" name="margin" type="float">
</argument>
<description>
- Set the map edge connection margein used to weld the compatible region edges.
+ Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
<method name="map_set_up" qualifiers="const">
@@ -328,6 +335,57 @@
Creates a new region.
</description>
</method>
+ <method name="region_get_connection_pathway_end" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connection_pathway_start" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="connection" type="int">
+ </argument>
+ <description>
+ Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ </description>
+ </method>
+ <method name="region_get_connections_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns how many connections this [code]region[/code] has with other regions in the map.
+ </description>
+ </method>
+ <method name="region_get_layers" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <description>
+ Returns the region's layers.
+ </description>
+ </method>
+ <method name="region_set_layers" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="layers" type="int">
+ </argument>
+ <description>
+ Set the region's layers. This allows selecting regions from a path request (when using [method NavigationServer3D.map_get_path]).
+ </description>
+ </method>
<method name="region_set_map" qualifiers="const">
<return type="void">
</return>
@@ -371,6 +429,15 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="map_changed">
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Emitted when a navigation map is updated, when a region moves or is modified.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 5f0d6462e2..523f3a0c17 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -37,13 +37,13 @@
Corresponds to the [constant NOTIFICATION_EXIT_TREE] notification in [method Object._notification] and signal [signal tree_exiting]. To get notified when the node has already left the active tree, connect to the [signal tree_exited].
</description>
</method>
- <method name="_get_configuration_warning" qualifiers="virtual">
- <return type="String">
+ <method name="_get_configuration_warnings" qualifiers="virtual">
+ <return type="String[]">
</return>
<description>
- The string returned from this method is displayed as a warning in the Scene Dock if the script that overrides it is a [code]tool[/code] script.
- Returning an empty string produces no warning.
- Call [method update_configuration_warning] when the warning needs to be updated for this node.
+ The elements in the array returned from this method are displayed as warnings in the Scene Dock if the script that overrides it is a [code]tool[/code] script.
+ Returning an empty array produces no warnings.
+ Call [method update_configuration_warnings] when the warnings need to be updated for this node.
</description>
</method>
<method name="_input" qualifiers="virtual">
@@ -128,7 +128,7 @@
</argument>
<description>
Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have an human-readable name based on the name of the node being instanced instead of its type.
+ If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type.
[b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example:
[codeblocks]
[gdscript]
@@ -158,8 +158,8 @@
<argument index="1" name="legible_unique_name" type="bool" default="false">
</argument>
<description>
- Adds a [code]sibling[/code] node to current's node parent, at the the same level as that node, right below it.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have an human-readable name based on the name of the node being instanced instead of its type.
+ Adds a [code]sibling[/code] node to current's node parent, at the same level as that node, right below it.
+ If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type.
Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children.
</description>
</method>
@@ -179,7 +179,7 @@
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the node can process while the scene tree is paused (see [member pause_mode]). Always returns [code]true[/code] if the scene tree is not paused, and [code]false[/code] if the node is not in the tree.
+ Returns [code]true[/code] if the node can process while the scene tree is paused (see [member process_mode]). Always returns [code]true[/code] if the scene tree is not paused, and [code]false[/code] if the node is not in the tree.
</description>
</method>
<method name="duplicate" qualifiers="const">
@@ -245,6 +245,12 @@
Returns an array of references to node's children.
</description>
</method>
+ <method name="get_editor_description" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_groups" qualifiers="const">
<return type="Array">
</return>
@@ -757,6 +763,14 @@
Sets the folded state of the node in the Scene dock.
</description>
</method>
+ <method name="set_editor_description">
+ <return type="void">
+ </return>
+ <argument index="0" name="editor_description" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_network_master">
<return type="void">
</return>
@@ -842,12 +856,12 @@
Sets whether this is an instance load placeholder. See [InstancePlaceholder].
</description>
</method>
- <method name="update_configuration_warning">
+ <method name="update_configuration_warnings">
<return type="void">
</return>
<description>
Updates the warning displayed for this node in the Scene Dock.
- Use [method _get_configuration_warning] to setup the warning message to display.
+ Use [method _get_configuration_warnings] to setup the warning message to display.
</description>
</method>
</methods>
@@ -868,8 +882,8 @@
<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.
</member>
- <member name="pause_mode" type="int" setter="set_pause_mode" getter="get_pause_mode" enum="Node.PauseMode" default="0">
- Pause mode. How the node will behave if the [SceneTree] is paused.
+ <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).
</member>
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0">
The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first.
@@ -1017,14 +1031,20 @@
<constant name="NOTIFICATION_TEXT_SERVER_CHANGED" value="2018">
Notification received when text server is changed.
</constant>
- <constant name="PAUSE_MODE_INHERIT" value="0" enum="PauseMode">
- Inherits pause mode from the node's parent. For the root node, it is equivalent to [constant PAUSE_MODE_STOP]. Default.
+ <constant name="PROCESS_MODE_INHERIT" value="0" enum="ProcessMode">
+ Inherits process mode from the node's parent. For the root node, it is equivalent to [constant PROCESS_MODE_PAUSABLE]. Default.
+ </constant>
+ <constant name="PROCESS_MODE_PAUSABLE" value="1" enum="ProcessMode">
+ Stops processing when the [SceneTree] is paused (process when unpaused). This is the inverse of [constant PROCESS_MODE_WHEN_PAUSED].
+ </constant>
+ <constant name="PROCESS_MODE_WHEN_PAUSED" value="2" enum="ProcessMode">
+ Only process when the [SceneTree] is paused (don't process when unpaused). This is the inverse of [constant PROCESS_MODE_PAUSABLE].
</constant>
- <constant name="PAUSE_MODE_STOP" value="1" enum="PauseMode">
- Stops processing when the [SceneTree] is paused.
+ <constant name="PROCESS_MODE_ALWAYS" value="3" enum="ProcessMode">
+ Always process. Continue processing always, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_DISABLED].
</constant>
- <constant name="PAUSE_MODE_PROCESS" value="2" enum="PauseMode">
- Continue to process regardless of the [SceneTree] pause state.
+ <constant name="PROCESS_MODE_DISABLED" value="4" enum="ProcessMode">
+ Never process. Completely disables processing, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_ALWAYS].
</constant>
<constant name="DUPLICATE_SIGNALS" value="1" enum="DuplicateFlags">
Duplicate the node's signals.
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index 8b56050058..5c29c0d48f 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -103,7 +103,7 @@
</return>
<argument index="0" name="target" type="Vector3">
</argument>
- <argument index="1" name="up" type="Vector3">
+ <argument index="1" name="up" type="Vector3" default="Vector3( 0, 1, 0 )">
</argument>
<description>
Rotates itself so that the local -Z axis points towards the [code]target[/code] position.
@@ -118,7 +118,7 @@
</argument>
<argument index="1" name="target" type="Vector3">
</argument>
- <argument index="2" name="up" type="Vector3">
+ <argument index="2" name="up" type="Vector3" default="Vector3( 0, 1, 0 )">
</argument>
<description>
Moves the node to the specified [code]position[/code], and then rotates itself to point toward the [code]target[/code] as per [method look_at]. Operations take place in global space.
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 36835d9e94..817ccd5160 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -66,11 +66,11 @@
[/codeblock]
</description>
</method>
- <method name="get_as_property_path">
+ <method name="get_as_property_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
- Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the from the current node).
+ Returns a node path with a colon character ([code]:[/code]) prepended, transforming it to a pure property path with no node name (defaults to resolving from the current node).
[codeblocks]
[gdscript]
# This will be parsed as a node path to the "x" property in the "position" node.
@@ -89,7 +89,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_concatenated_subnames">
+ <method name="get_concatenated_subnames" qualifiers="const">
<return type="StringName">
</return>
<description>
@@ -106,7 +106,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_name">
+ <method name="get_name" qualifiers="const">
<return type="StringName">
</return>
<argument index="0" name="idx" type="int">
@@ -129,7 +129,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_name_count">
+ <method name="get_name_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -137,7 +137,7 @@
For example, [code]"Path2D/PathFollow2D/Sprite2D"[/code] has 3 names.
</description>
</method>
- <method name="get_subname">
+ <method name="get_subname" qualifiers="const">
<return type="StringName">
</return>
<argument index="0" name="idx" type="int">
@@ -158,7 +158,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_subname_count">
+ <method name="get_subname_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -166,14 +166,14 @@
For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:load_path"[/code] has 2 subnames.
</description>
</method>
- <method name="is_absolute">
+ <method name="is_absolute" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the node path is absolute (as opposed to relative), which means that it starts with a slash character ([code]/[/code]). Absolute node paths can be used to access the root node ([code]"/root"[/code]) or autoloads (e.g. [code]"/global"[/code] if a "global" autoload was registered).
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 8620de1378..8c90108aef 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -54,7 +54,7 @@
<argument index="0" name="msec" type="int">
</argument>
<description>
- Delay execution of the current thread by [code]msec[/code] milliseconds.
+ Delay execution of the current thread by [code]msec[/code] milliseconds. [code]usec[/code] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_msec] will do nothing and will print an error message.
</description>
</method>
<method name="delay_usec" qualifiers="const">
@@ -63,7 +63,7 @@
<argument index="0" name="usec" type="int">
</argument>
<description>
- Delay execution of the current thread by [code]usec[/code] microseconds.
+ Delay execution of the current thread by [code]usec[/code] microseconds. [code]usec[/code] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_usec] will do nothing and will print an error message.
</description>
</method>
<method name="dump_memory_to_file">
@@ -207,10 +207,11 @@
<method name="get_environment" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="environment" type="String">
+ <argument index="0" name="variable" type="String">
</argument>
<description>
- Returns an environment variable.
+ Returns the value of an environment variable. Returns an empty string if the environment variable doesn't exist.
+ [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
</description>
</method>
<method name="get_executable_path" qualifiers="const">
@@ -243,9 +244,9 @@
</return>
<description>
Returns the host OS locale as a string of the form [code]language_Script_COUNTRY_VARIANT@extra[/code].
- [code]language[/code] - 2 or 3 letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
- [code]Script[/code] - optional, 4 letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
- [code]COUNTRY[/code] - optional, 2 or 3 letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
+ [code]language[/code] - 2 or 3-letter [url=https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes]language code[/url], in lower case.
+ [code]Script[/code] - optional, 4-letter [url=https://en.wikipedia.org/wiki/ISO_15924]script code[/url], in title case.
+ [code]COUNTRY[/code] - optional, 2 or 3-letter [url=https://en.wikipedia.org/wiki/ISO_3166-1]country code[/url], in upper case.
[code]VARIANT[/code] - optional, language variant, region and sort order. Variant can have any number of underscored key words.
[code]extra[/code] - optional, semicolon separated list of additional key words. Currency, calendar, sort order and numbering system information.
</description>
@@ -304,24 +305,6 @@
[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
</description>
</method>
- <method name="get_tablet_driver_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the total number of available tablet drivers.
- [b]Note:[/b] This method is implemented on Windows.
- </description>
- </method>
- <method name="get_tablet_driver_name" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the tablet driver name for the given index.
- [b]Note:[/b] This method is implemented on Windows.
- </description>
- </method>
<method name="get_thread_caller_id" qualifiers="const">
<return type="int">
</return>
@@ -372,7 +355,7 @@
<return type="float">
</return>
<description>
- Returns the current UNIX epoch timestamp.
+ Returns the current UNIX epoch timestamp in seconds.
[b]Important:[/b] This is the system clock that the user can manully set. [b]Never use[/b] this method for precise time calculation since its results are also subject to automatic adjustments by the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease).
</description>
</method>
@@ -384,6 +367,7 @@
<description>
Gets an epoch time value from a dictionary of time values.
[code]datetime[/code] must be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], [code]second[/code].
+ If the dictionary is empty [code]0[/code] is returned.
You can pass the output from [method get_datetime_from_unix_time] directly into this function. Daylight Savings Time ([code]dst[/code]), if present, is ignored.
</description>
</method>
@@ -401,10 +385,11 @@
<method name="has_environment" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="environment" type="String">
+ <argument index="0" name="variable" type="String">
</argument>
<description>
- Returns [code]true[/code] if an environment variable exists.
+ Returns [code]true[/code] if the environment variable with the name [code]variable[/code] exists.
+ [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
</description>
</method>
<method name="has_feature" qualifiers="const">
@@ -519,6 +504,18 @@
[b]Note:[/b] This method is implemented on Android.
</description>
</method>
+ <method name="set_environment" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="variable" type="String">
+ </argument>
+ <argument index="1" name="value" type="String">
+ </argument>
+ <description>
+ Sets the value of the environment variable [code]variable[/code] to [code]value[/code]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
+ [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
+ </description>
+ </method>
<method name="set_thread_name">
<return type="int" enum="Error">
</return>
@@ -553,19 +550,12 @@
</method>
</methods>
<members>
- <member name="exit_code" type="int" setter="set_exit_code" getter="get_exit_code" default="0">
- The exit code passed to the OS when the main loop exits. By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error. For portability reasons, the exit code should be set between 0 and 125 (inclusive).
- [b]Note:[/b] This value will be ignored if using [method SceneTree.quit] with an [code]exit_code[/code] argument passed.
- </member>
<member name="low_processor_usage_mode" type="bool" setter="set_low_processor_usage_mode" getter="is_in_low_processor_usage_mode" default="false">
If [code]true[/code], the engine optimizes for low processor usage by only refreshing the screen if needed. Can improve battery consumption on mobile.
</member>
<member name="low_processor_usage_mode_sleep_usec" type="int" setter="set_low_processor_usage_mode_sleep_usec" getter="get_low_processor_usage_mode_sleep_usec" default="6900">
The amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU usage.
</member>
- <member name="tablet_driver" type="String" setter="set_current_tablet_driver" getter="get_current_tablet_driver" default="&quot;&quot;">
- The current tablet driver in use.
- </member>
</members>
<constants>
<constant name="VIDEO_DRIVER_GLES2" value="0" enum="VideoDriver">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index f55b8597dd..7da9c1ac38 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Object" version="4.0">
<brief_description>
- Base class for all non built-in types.
+ Base class for all non-built-in types.
</brief_description>
<description>
Every class which is not a built-in type inherits from this class.
@@ -179,7 +179,7 @@
</argument>
<description>
Connects a [code]signal[/code] to a [code]callable[/code]. Pass optional [code]binds[/code] to the call as an [Array] of parameters. These parameters will be passed to the [Callable]'s method after any parameter used in the call to [method emit_signal]. Use [code]flags[/code] to set deferred or one-shot connections. See [enum ConnectFlags] constants.
- [b]Note:[/b] This method is the legacy implementation for connecting signals. The recommend modern approach is to use [method Signal.connect] and to use [method Callable.bind] to add and validate parameter binds. Both syntaxes are shown below.
+ [b]Note:[/b] This method is the legacy implementation for connecting signals. The recommended modern approach is to use [method Signal.connect] and to use [method Callable.bind] to add and validate parameter binds. Both syntaxes are shown below.
A signal can only be connected once to a [Callable]. It will throw an error if already connected, unless the signal was connected with [constant CONNECT_REFERENCE_COUNTED]. To avoid this, first, use [method is_connected] to check for existing connections.
If the callable's target is destroyed in the game's lifecycle, the connection will be lost.
[b]Examples with recommended syntax:[/b]
@@ -533,11 +533,11 @@
If [code]reversed[/code] is [code]true[/code], [method _notification] is called first on the object's own class, and then up to its successive parent classes. If [code]reversed[/code] is [code]false[/code], [method _notification] is called first on the highest ancestor ([Object] itself), and then down to its successive inheriting classes.
</description>
</method>
- <method name="property_list_changed_notify">
+ <method name="notify_property_list_changed">
<return type="void">
</return>
<description>
- Notify the editor that the property list has changed, so that editor plugins can take the new values into account. Does nothing on export builds.
+ Notify the editor that the property list has changed by emitting the [signal property_list_changed] signal, so that editor plugins can take the new values into account.
</description>
</method>
<method name="remove_meta">
@@ -680,6 +680,10 @@
</method>
</methods>
<signals>
+ <signal name="property_list_changed">
+ <description>
+ </description>
+ </signal>
<signal name="script_changed">
<description>
Emitted whenever the object's script is changed.
diff --git a/doc/classes/Occluder3D.xml b/doc/classes/Occluder3D.xml
new file mode 100644
index 0000000000..fc676c2b49
--- /dev/null
+++ b/doc/classes/Occluder3D.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Occluder3D" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="indices" type="PackedInt32Array" setter="set_indices" getter="get_indices" default="PackedInt32Array( )">
+ </member>
+ <member name="vertices" type="PackedVector3Array" setter="set_vertices" getter="get_vertices" default="PackedVector3Array( )">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
new file mode 100644
index 0000000000..76b784d21d
--- /dev/null
+++ b/doc/classes/OccluderInstance3D.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OccluderInstance3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_bake_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bake_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
+ </member>
+ <member name="occluder" type="Occluder3D" setter="set_occluder" getter="get_occluder">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PHashTranslation.xml b/doc/classes/OptimizedTranslation.xml
index 30194e9495..a5ca93c7ff 100644
--- a/doc/classes/PHashTranslation.xml
+++ b/doc/classes/OptimizedTranslation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PHashTranslation" inherits="Translation" version="4.0">
+<class name="OptimizedTranslation" inherits="Translation" version="4.0">
<brief_description>
Optimized translation.
</brief_description>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 1a80962751..52da08c02f 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -259,6 +259,9 @@
<theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
Text [Color] used when the [OptionButton] is being hovered.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [OptionButton].
+ </theme_item>
<theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the [OptionButton] is being pressed.
</theme_item>
@@ -280,6 +283,9 @@
<theme_item name="normal_mirrored" type="StyleBox">
Default [StyleBox] for the [OptionButton] (for right-to-left layouts).
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="pressed" type="StyleBox">
[StyleBox] used when the [OptionButton] is being pressed (for left-to-right layouts).
</theme_item>
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 75fb7c1465..0652cf0aa1 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -52,7 +52,7 @@
Appends a [PackedByteArray] at the end of this array.
</description>
</method>
- <method name="compress">
+ <method name="compress" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="compression_mode" type="int" default="0">
@@ -61,7 +61,115 @@
Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
- <method name="decompress">
+ <method name="decode_double" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_float" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_half" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s16" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s32" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s64" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s8" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u16" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u32" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u64" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u8" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_var" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_var_size" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decompress" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="buffer_size" type="int">
@@ -72,7 +180,7 @@
Returns a new [PackedByteArray] with the data decompressed. Set [code]buffer_size[/code] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
- <method name="decompress_dynamic">
+ <method name="decompress_dynamic" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="max_output_size" type="int">
@@ -81,7 +189,7 @@
</argument>
<description>
Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
- This method is potentially slower than [code]decompress[/code], as it may have to re-allocate it's output buffer multiple times while decompressing, where as [code]decompress[/code] knows it's output buffer size from the beginning.
+ This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning.
GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [code]max_output_size[/code]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
</description>
</method>
@@ -92,28 +200,159 @@
Creates a copy of the array, and returns it.
</description>
</method>
- <method name="get_string_from_ascii">
+ <method name="encode_double">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_float">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_half">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s16">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s32">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s64">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s8">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u16">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u32">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u64">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u8">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_var">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="Variant">
+ </argument>
+ <argument index="2" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
+ <method name="get_string_from_ascii" qualifiers="const">
<return type="String">
</return>
<description>
Converts ASCII/Latin-1 encoded array to [String]. Fast alternative to [method get_string_from_utf8] if the content is ASCII/Latin-1 only. Unlike the UTF-8 function this function maps every byte to a character in the array. Multibyte sequences will not be interpreted correctly. For parsing user input always use [method get_string_from_utf8].
</description>
</method>
- <method name="get_string_from_utf16">
+ <method name="get_string_from_utf16" qualifiers="const">
<return type="String">
</return>
<description>
Converts UTF-16 encoded array to [String]. If the BOM is missing, system endianness is assumed. Returns empty string if source array is not valid UTF-16 string.
</description>
</method>
- <method name="get_string_from_utf32">
+ <method name="get_string_from_utf32" qualifiers="const">
<return type="String">
</return>
<description>
Converts UTF-32 encoded array to [String]. System endianness is assumed. Returns empty string if source array is not valid UTF-32 string.
</description>
</method>
- <method name="get_string_from_utf8">
+ <method name="get_string_from_utf8" qualifiers="const">
<return type="String">
</return>
<description>
@@ -129,7 +368,17 @@
Returns [code]true[/code] if the array contains [code]value[/code].
</description>
</method>
- <method name="hex_encode">
+ <method name="has_encoded_var" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hex_encode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -157,14 +406,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -230,6 +472,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -241,7 +490,7 @@
Changes the byte at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -255,7 +504,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedByteArray">
</return>
<argument index="0" name="from" type="int">
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 48d5822f7c..19cfcd7c87 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -59,6 +59,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Color">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -79,14 +88,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -152,6 +154,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -163,7 +172,7 @@
Changes the [Color] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -177,7 +186,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedColorArray">
</return>
<argument index="0" name="from" type="int">
@@ -187,7 +196,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 6598828089..ab97c9a695 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="float">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -118,6 +120,14 @@
<description>
</description>
</method>
+ <method name="operator []" qualifiers="operator">
+ <return type="float">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="push_back">
<return type="bool">
</return>
@@ -145,6 +155,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -156,7 +173,7 @@
Changes the float at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -170,7 +187,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedFloat32Array">
</return>
<argument index="0" name="from" type="int">
@@ -180,7 +197,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index d116c6756b..ad20801b01 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="float">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -153,6 +155,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -164,7 +173,7 @@
Changes the float at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +187,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedFloat64Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +197,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index 2ac7a67b4b..ff4729082e 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -153,6 +155,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -164,7 +173,7 @@
Changes the integer at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +187,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedInt32Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +197,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index a7b6bf0a0f..195b12b129 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -153,6 +155,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -164,7 +173,7 @@
Changes the integer at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +187,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedInt64Array">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +197,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index d15bcfd114..1d9be7f165 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
- Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]).
+ Can be used to save a node to a file. When saving, the node as well as all the nodes it owns get saved (see [code]owner[/code] property on [Node]).
[b]Note:[/b] The node doesn't need to own itself.
[b]Example of loading a saved scene:[/b]
[codeblocks]
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index fb7ed2a906..22458832da 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="String">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -153,6 +155,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -164,7 +173,7 @@
Changes the [String] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -178,7 +187,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="from" type="int">
@@ -188,7 +197,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index eb364ddb18..6c8791f988 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Vector2">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -80,14 +89,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -161,6 +163,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -172,7 +181,7 @@
Changes the [Vector2] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -186,7 +195,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedVector2Array">
</return>
<argument index="0" name="from" type="int">
@@ -196,7 +205,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 08ce187b5c..85d41d7519 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -59,6 +59,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Vector3">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -79,14 +88,7 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -160,6 +162,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
@@ -171,7 +180,7 @@
Changes the [Vector3] at the given index.
</description>
</method>
- <method name="size">
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -185,7 +194,7 @@
Sorts the elements of the array in ascending order.
</description>
</method>
- <method name="subarray">
+ <method name="subarray" qualifiers="const">
<return type="PackedVector3Array">
</return>
<argument index="0" name="from" type="int">
@@ -195,7 +204,7 @@
<description>
</description>
</method>
- <method name="to_byte_array">
+ <method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml
index d7cf6cc8c6..5d059ad3df 100644
--- a/doc/classes/PacketPeerUDP.xml
+++ b/doc/classes/PacketPeerUDP.xml
@@ -9,11 +9,27 @@
<tutorials>
</tutorials>
<methods>
+ <method name="bind">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
+ </argument>
+ <argument index="2" name="recv_buf_size" type="int" default="65536">
+ </argument>
+ <description>
+ Binds this [PacketPeerUDP] to the specified [code]port[/code] and [code]address[/code] with a buffer size [code]recv_buf_size[/code], allowing it to receive incoming packets.
+ If [code]address[/code] is set to [code]"*"[/code] (default), the peer will be bound on all available addresses (both IPv4 and IPv6).
+ If [code]address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will be bound to all available addresses matching that IP type.
+ If [code]address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only be bound to the interface with that addresses (or fail if no interface with the given address exists).
+ </description>
+ </method>
<method name="close">
<return type="void">
</return>
<description>
- Closes the UDP socket the [PacketPeerUDP] is currently listening on.
+ Closes the [PacketPeerUDP]'s underlying UDP socket.
</description>
</method>
<method name="connect_to_host">
@@ -28,6 +44,13 @@
[b]Note:[/b] Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_packet_ip" qualifiers="const">
<return type="String">
</return>
@@ -42,18 +65,18 @@
Returns the port of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]).
</description>
</method>
- <method name="is_connected_to_host" qualifiers="const">
+ <method name="is_bound" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
+ Returns whether this [PacketPeerUDP] is bound to an address and can receive packets.
</description>
</method>
- <method name="is_listening" qualifiers="const">
+ <method name="is_connected_to_host" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns whether this [PacketPeerUDP] is listening.
+ Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
</description>
</method>
<method name="join_multicast_group">
@@ -80,22 +103,6 @@
Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
</description>
</method>
- <method name="listen">
- <return type="int" enum="Error">
- </return>
- <argument index="0" name="port" type="int">
- </argument>
- <argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
- </argument>
- <argument index="2" name="recv_buf_size" type="int" default="65536">
- </argument>
- <description>
- Makes this [PacketPeerUDP] listen on the [code]port[/code] binding to [code]bind_address[/code] with a buffer size [code]recv_buf_size[/code].
- If [code]bind_address[/code] is set to [code]"*"[/code] (default), the peer will listen on all available addresses (both IPv4 and IPv6).
- If [code]bind_address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will listen on all available addresses matching that IP type.
- If [code]bind_address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only listen on the interface with that addresses (or fail if no interface with the given address exists).
- </description>
- </method>
<method name="set_broadcast_enabled">
<return type="void">
</return>
@@ -122,7 +129,7 @@
<return type="int" enum="Error">
</return>
<description>
- Waits for a packet to arrive on the listening port. See [method listen].
+ Waits for a packet to arrive on the bound address. See [method bind].
[b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this:
[codeblocks]
[gdscript]
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index 85058cb9d4..6d7f99a55b 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -181,7 +181,7 @@
The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE].
</member>
<member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0">
- Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane.
+ Amount of [member spread] along the Y axis.
</member>
<member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )">
Gravity applied to every particle.
@@ -251,7 +251,7 @@
Scale randomness ratio.
</member>
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
- Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. Applied to X/Z plane and Y/Z planes.
+ Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
</member>
<member name="sub_emitter_amount_at_end" type="int" setter="set_sub_emitter_amount_at_end" getter="get_sub_emitter_amount_at_end">
</member>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index dcf24c1d32..38d9f722b1 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -91,7 +91,7 @@
The body's bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness).
</member>
<member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
- If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awaken by an external force.
+ If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awakened by an external force.
</member>
<member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0">
The body's friction, from [code]0[/code] (frictionless) to [code]1[/code] (max friction).
diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
index 2e0f9c52f2..381371b973 100644
--- a/doc/classes/PhysicalSkyMaterial.xml
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -23,22 +23,22 @@
Modulates the [Color] on the bottom half of the sky to represent the ground.
</member>
<member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005">
- Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whiteish color around the sun and horizon.
+ Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon.
</member>
<member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color( 0.36, 0.56, 0.82, 1 )">
Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien looking planets.
</member>
<member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8">
- Controls the direction of the mie scattering. A value of [code]1[/code] means that when light hits a particle it passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards.
+ Controls the direction of the mie scattering. A value of [code]1[/code] means that when light hits a particle it's passing through straight forward. A value of [code]-1[/code] means that all light is scatter backwards.
</member>
<member name="night_sky" type="Texture2D" setter="set_night_sky" getter="get_night_sky">
[Texture2D] for the night sky. This is added to the sky, so if it is bright enough, it may be visible during the day.
</member>
<member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0">
- Controls the strength of the rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky.
+ Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky.
</member>
<member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color( 0.056, 0.14, 0.3, 1 )">
- Controls the [Color] of the rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a mars looking atmosphere with a corresponding blue sunset.
+ Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a Mars looking atmosphere with a corresponding blue sunset.
</member>
<member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0">
Sets the size of the sun disk. Default value is based on Sol's perceived size from Earth.
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 9c3c47afba..e43d3bb762 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -26,24 +26,6 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_layer].
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_mask].
- </description>
- </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -53,38 +35,8 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_layer] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_mask] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
</methods>
<members>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The physics layers this area is in.
- Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" />
</members>
<constants>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 7de65603f9..b320d37d23 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -26,24 +26,6 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_layer].
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_mask].
- </description>
- </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -53,39 +35,7 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_layer] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_mask] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
</methods>
- <members>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The physics layers this area is in.
- Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- </members>
<constants>
</constants>
</class>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 6a1508b0e3..229facd08b 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -58,7 +58,7 @@
<return type="RID">
</return>
<description>
- Creates an [Area2D].
+ Creates an [Area2D]. After creating an [Area2D] with this method, assign it to a space using [method area_set_space] to use the created [Area2D] in the physics world.
</description>
</method>
<method name="area_get_canvas_instance_id" qualifiers="const">
@@ -659,11 +659,9 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
@@ -850,21 +848,6 @@
<description>
</description>
</method>
- <method name="damped_spring_joint_create">
- <return type="RID">
- </return>
- <argument index="0" name="anchor_a" type="Vector2">
- </argument>
- <argument index="1" name="anchor_b" type="Vector2">
- </argument>
- <argument index="2" name="body_a" type="RID">
- </argument>
- <argument index="3" name="body_b" type="RID">
- </argument>
- <description>
- Creates a damped spring joint between two bodies. If not specified, the second body is assumed to be the joint itself.
- </description>
- </method>
<method name="damped_spring_joint_get_param" qualifiers="const">
<return type="float">
</return>
@@ -907,21 +890,18 @@
Returns information about the current state of the 2D physics engine. See [enum ProcessInfo] for a list of available states.
</description>
</method>
- <method name="groove_joint_create">
- <return type="RID">
+ <method name="joint_clear">
+ <return type="void">
</return>
- <argument index="0" name="groove1_a" type="Vector2">
- </argument>
- <argument index="1" name="groove2_a" type="Vector2">
- </argument>
- <argument index="2" name="anchor_b" type="Vector2">
- </argument>
- <argument index="3" name="body_a" type="RID">
- </argument>
- <argument index="4" name="body_b" type="RID">
+ <argument index="0" name="joint" type="RID">
</argument>
<description>
- Creates a groove joint between two bodies. If not specified, the bodies are assumed to be the joint itself.
+ </description>
+ </method>
+ <method name="joint_create">
+ <return type="RID">
+ </return>
+ <description>
</description>
</method>
<method name="joint_get_param" qualifiers="const">
@@ -944,36 +924,71 @@
Returns a joint's type (see [enum JointType]).
</description>
</method>
- <method name="joint_set_param">
+ <method name="joint_make_damped_spring">
<return type="void">
</return>
<argument index="0" name="joint" type="RID">
</argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.JointParam">
+ <argument index="1" name="anchor_a" type="Vector2">
</argument>
- <argument index="2" name="value" type="float">
+ <argument index="2" name="anchor_b" type="Vector2">
+ </argument>
+ <argument index="3" name="body_a" type="RID">
+ </argument>
+ <argument index="4" name="body_b" type="RID">
</argument>
<description>
- Sets a joint parameter. See [enum JointParam] for a list of available parameters.
</description>
</method>
- <method name="line_shape_create">
- <return type="RID">
+ <method name="joint_make_groove">
+ <return type="void">
</return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="groove1_a" type="Vector2">
+ </argument>
+ <argument index="2" name="groove2_a" type="Vector2">
+ </argument>
+ <argument index="3" name="anchor_b" type="Vector2">
+ </argument>
+ <argument index="4" name="body_a" type="RID">
+ </argument>
+ <argument index="5" name="body_b" type="RID">
+ </argument>
<description>
</description>
</method>
- <method name="pin_joint_create">
- <return type="RID">
+ <method name="joint_make_pin">
+ <return type="void">
</return>
- <argument index="0" name="anchor" type="Vector2">
+ <argument index="0" name="joint" type="RID">
</argument>
- <argument index="1" name="body_a" type="RID">
+ <argument index="1" name="anchor" type="Vector2">
</argument>
- <argument index="2" name="body_b" type="RID">
+ <argument index="2" name="body_a" type="RID">
+ </argument>
+ <argument index="3" name="body_b" type="RID">
</argument>
<description>
- Creates a pin joint between two bodies. If not specified, the second body is assumed to be the joint itself.
+ </description>
+ </method>
+ <method name="joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.JointParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a joint parameter. See [enum JointParam] for a list of available parameters.
+ </description>
+ </method>
+ <method name="line_shape_create">
+ <return type="RID">
+ </return>
+ <description>
</description>
</method>
<method name="ray_shape_create">
@@ -1233,15 +1248,18 @@
<constant name="BODY_STATE_CAN_SLEEP" value="4" enum="BodyState">
Constant to set/get whether the body can sleep.
</constant>
- <constant name="JOINT_PIN" value="0" enum="JointType">
+ <constant name="JOINT_TYPE_PIN" value="0" enum="JointType">
Constant to create pin joints.
</constant>
- <constant name="JOINT_GROOVE" value="1" enum="JointType">
+ <constant name="JOINT_TYPE_GROOVE" value="1" enum="JointType">
Constant to create groove joints.
</constant>
- <constant name="JOINT_DAMPED_SPRING" value="2" enum="JointType">
+ <constant name="JOINT_TYPE_DAMPED_SPRING" value="2" enum="JointType">
Constant to create damped spring joints.
</constant>
+ <constant name="JOINT_TYPE_MAX" value="3" enum="JointType">
+ Represents the size of the [enum JointType] enum.
+ </constant>
<constant name="JOINT_PARAM_BIAS" value="0" enum="JointParam">
</constant>
<constant name="JOINT_PARAM_MAX_BIAS" value="1" enum="JointParam">
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 5fd3ef5db2..46de9e5282 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -129,15 +129,6 @@
Returns the transform matrix for an area.
</description>
</method>
- <method name="area_is_ray_pickable" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- If [code]true[/code], area collides with rays.
- </description>
- </method>
<method name="area_remove_shape">
<return type="void">
</return>
@@ -421,12 +412,7 @@
<method name="body_create">
<return type="RID">
</return>
- <argument index="0" name="mode" type="int" enum="PhysicsServer3D.BodyMode" default="2">
- </argument>
- <argument index="1" name="init_sleeping" type="bool" default="false">
- </argument>
<description>
- Creates a physics body. The first parameter can be any value from [enum BodyMode] constants, for the type of body created. Additionally, the body can be created in sleeping state to save processing time.
</description>
</method>
<method name="body_get_collision_layer" qualifiers="const">
@@ -582,15 +568,6 @@
Returns whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
</description>
</method>
- <method name="body_is_ray_pickable" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- If [code]true[/code], the body can be detected by rays.
- </description>
- </method>
<method name="body_remove_collision_exception">
<return type="void">
</return>
@@ -676,11 +653,9 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
@@ -815,6 +790,24 @@
Sets a body state (see [enum BodyState] constants).
</description>
</method>
+ <method name="box_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="capsule_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="concave_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="cone_twist_joint_get_param" qualifiers="const">
<return type="float">
</return>
@@ -839,6 +832,24 @@
Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
</description>
</method>
+ <method name="convex_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="custom_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="cylinder_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="free_rid">
<return type="void">
</return>
@@ -848,7 +859,7 @@
Destroys any of the objects created by PhysicsServer3D. If the [RID] passed is not one of the objects that can be created by PhysicsServer3D, an error will be sent to the console.
</description>
</method>
- <method name="generic_6dof_joint_get_flag">
+ <method name="generic_6dof_joint_get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="joint" type="RID">
@@ -861,7 +872,7 @@
Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
</description>
</method>
- <method name="generic_6dof_joint_get_param">
+ <method name="generic_6dof_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -913,6 +924,12 @@
Returns an Info defined by the [enum ProcessInfo] input given.
</description>
</method>
+ <method name="heightmap_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="hinge_joint_get_flag" qualifiers="const">
<return type="bool">
</return>
@@ -961,97 +978,116 @@
Sets a hinge_joint parameter (see [enum HingeJointParam] constants).
</description>
</method>
- <method name="joint_create_cone_twist">
- <return type="RID">
+ <method name="joint_clear">
+ <return type="void">
</return>
- <argument index="0" name="body_A" type="RID">
- </argument>
- <argument index="1" name="local_ref_A" type="Transform">
- </argument>
- <argument index="2" name="body_B" type="RID">
- </argument>
- <argument index="3" name="local_ref_B" type="Transform">
+ <argument index="0" name="joint" type="RID">
</argument>
<description>
- Creates a [ConeTwistJoint3D].
</description>
</method>
- <method name="joint_create_generic_6dof">
+ <method name="joint_create">
<return type="RID">
</return>
- <argument index="0" name="body_A" type="RID">
- </argument>
- <argument index="1" name="local_ref_A" type="Transform">
- </argument>
- <argument index="2" name="body_B" type="RID">
+ <description>
+ </description>
+ </method>
+ <method name="joint_get_solver_priority" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint" type="RID">
</argument>
- <argument index="3" name="local_ref_B" type="Transform">
+ <description>
+ Gets the priority value of the Joint3D.
+ </description>
+ </method>
+ <method name="joint_get_type" qualifiers="const">
+ <return type="int" enum="PhysicsServer3D.JointType">
+ </return>
+ <argument index="0" name="joint" type="RID">
</argument>
<description>
- Creates a [Generic6DOFJoint3D].
+ Returns the type of the Joint3D.
</description>
</method>
- <method name="joint_create_hinge">
- <return type="RID">
+ <method name="joint_make_cone_twist">
+ <return type="void">
</return>
- <argument index="0" name="body_A" type="RID">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="body_A" type="RID">
</argument>
- <argument index="1" name="hinge_A" type="Transform">
+ <argument index="2" name="local_ref_A" type="Transform">
</argument>
- <argument index="2" name="body_B" type="RID">
+ <argument index="3" name="body_B" type="RID">
</argument>
- <argument index="3" name="hinge_B" type="Transform">
+ <argument index="4" name="local_ref_B" type="Transform">
</argument>
<description>
- Creates a [HingeJoint3D].
</description>
</method>
- <method name="joint_create_pin">
- <return type="RID">
+ <method name="joint_make_generic_6dof">
+ <return type="void">
</return>
- <argument index="0" name="body_A" type="RID">
+ <argument index="0" name="joint" type="RID">
</argument>
- <argument index="1" name="local_A" type="Vector3">
+ <argument index="1" name="body_A" type="RID">
+ </argument>
+ <argument index="2" name="local_ref_A" type="Transform">
</argument>
- <argument index="2" name="body_B" type="RID">
+ <argument index="3" name="body_B" type="RID">
</argument>
- <argument index="3" name="local_B" type="Vector3">
+ <argument index="4" name="local_ref_B" type="Transform">
</argument>
<description>
- Creates a [PinJoint3D].
</description>
</method>
- <method name="joint_create_slider">
- <return type="RID">
+ <method name="joint_make_hinge">
+ <return type="void">
</return>
- <argument index="0" name="body_A" type="RID">
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="body_A" type="RID">
</argument>
- <argument index="1" name="local_ref_A" type="Transform">
+ <argument index="2" name="hinge_A" type="Transform">
</argument>
- <argument index="2" name="body_B" type="RID">
+ <argument index="3" name="body_B" type="RID">
</argument>
- <argument index="3" name="local_ref_B" type="Transform">
+ <argument index="4" name="hinge_B" type="Transform">
</argument>
<description>
- Creates a [SliderJoint3D].
</description>
</method>
- <method name="joint_get_solver_priority" qualifiers="const">
- <return type="int">
+ <method name="joint_make_pin">
+ <return type="void">
</return>
<argument index="0" name="joint" type="RID">
</argument>
+ <argument index="1" name="body_A" type="RID">
+ </argument>
+ <argument index="2" name="local_A" type="Vector3">
+ </argument>
+ <argument index="3" name="body_B" type="RID">
+ </argument>
+ <argument index="4" name="local_B" type="Vector3">
+ </argument>
<description>
- Gets the priority value of the Joint3D.
</description>
</method>
- <method name="joint_get_type" qualifiers="const">
- <return type="int" enum="PhysicsServer3D.JointType">
+ <method name="joint_make_slider">
+ <return type="void">
</return>
<argument index="0" name="joint" type="RID">
</argument>
+ <argument index="1" name="body_A" type="RID">
+ </argument>
+ <argument index="2" name="local_ref_A" type="Transform">
+ </argument>
+ <argument index="3" name="body_B" type="RID">
+ </argument>
+ <argument index="4" name="local_ref_B" type="Transform">
+ </argument>
<description>
- Returns the type of the Joint3D.
</description>
</method>
<method name="joint_set_solver_priority">
@@ -1129,22 +1165,25 @@
Sets a pin_joint parameter (see [enum PinJointParam] constants).
</description>
</method>
- <method name="set_active">
- <return type="void">
+ <method name="plane_shape_create">
+ <return type="RID">
</return>
- <argument index="0" name="active" type="bool">
- </argument>
<description>
- Activates or deactivates the 3D physics engine.
</description>
</method>
- <method name="shape_create">
+ <method name="ray_shape_create">
<return type="RID">
</return>
- <argument index="0" name="type" type="int" enum="PhysicsServer3D.ShapeType">
+ <description>
+ </description>
+ </method>
+ <method name="set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
</argument>
<description>
- Creates a shape of a type from [enum ShapeType]. Does not assign it to a body or an area. To do so, you must use [method area_set_shape] or [method body_set_shape].
+ Activates or deactivates the 3D physics engine.
</description>
</method>
<method name="shape_get_data" qualifiers="const">
@@ -1200,6 +1239,14 @@
Gets a slider_joint parameter (see [enum SliderJointParam] constants).
</description>
</method>
+ <method name="soft_body_get_bounds" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="space_create">
<return type="RID">
</return>
@@ -1260,23 +1307,32 @@
Sets the value for a space parameter. A list of available parameters is on the [enum SpaceParameter] constants.
</description>
</method>
+ <method name="sphere_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
- <constant name="JOINT_PIN" value="0" enum="JointType">
+ <constant name="JOINT_TYPE_PIN" value="0" enum="JointType">
The [Joint3D] is a [PinJoint3D].
</constant>
- <constant name="JOINT_HINGE" value="1" enum="JointType">
+ <constant name="JOINT_TYPE_HINGE" value="1" enum="JointType">
The [Joint3D] is a [HingeJoint3D].
</constant>
- <constant name="JOINT_SLIDER" value="2" enum="JointType">
+ <constant name="JOINT_TYPE_SLIDER" value="2" enum="JointType">
The [Joint3D] is a [SliderJoint3D].
</constant>
- <constant name="JOINT_CONE_TWIST" value="3" enum="JointType">
+ <constant name="JOINT_TYPE_CONE_TWIST" value="3" enum="JointType">
The [Joint3D] is a [ConeTwistJoint3D].
</constant>
- <constant name="JOINT_6DOF" value="4" enum="JointType">
+ <constant name="JOINT_TYPE_6DOF" value="4" enum="JointType">
The [Joint3D] is a [Generic6DOFJoint3D].
</constant>
+ <constant name="JOINT_TYPE_MAX" value="5" enum="JointType">
+ Represents the size of the [enum JointType] enum.
+ </constant>
<constant name="PIN_JOINT_BIAS" value="0" enum="PinJointParam">
The strength with which the pinned objects try to stay in positional relation to each other.
The higher, the stronger.
@@ -1493,7 +1549,10 @@
<constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
The [Shape3D] is a [HeightMapShape3D].
</constant>
- <constant name="SHAPE_CUSTOM" value="9" enum="ShapeType">
+ <constant name="SHAPE_SOFT_BODY" value="9" enum="ShapeType">
+ The [Shape3D] is a [SoftBody3D].
+ </constant>
+ <constant name="SHAPE_CUSTOM" value="10" enum="ShapeType">
This constant is used internally by the engine. Any attempt to create this kind of shape results in an error.
</constant>
<constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter">
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index ed96f753c2..2342f00631 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -76,14 +76,14 @@
Creates a plane from the three points, given in clockwise order.
</description>
</method>
- <method name="center">
+ <method name="center" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the center of the plane.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="point" type="Vector3">
@@ -92,7 +92,7 @@
Returns the shortest distance from the plane to the position [code]point[/code].
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -103,7 +103,7 @@
Returns [code]true[/code] if [code]point[/code] is inside the plane. Comparison uses a custom minimum [code]epsilon[/code] threshold.
</description>
</method>
- <method name="intersect_3">
+ <method name="intersect_3" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="b" type="Plane">
@@ -114,7 +114,7 @@
Returns the intersection point of the three planes [code]b[/code], [code]c[/code] and this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="intersects_ray">
+ <method name="intersects_ray" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -125,7 +125,7 @@
Returns the intersection point of a ray consisting of the position [code]from[/code] and the direction normal [code]dir[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="intersects_segment">
+ <method name="intersects_segment" qualifiers="const">
<return type="Variant">
</return>
<argument index="0" name="from" type="Vector3">
@@ -136,7 +136,7 @@
Returns the intersection point of a segment from position [code]begin[/code] to position [code]end[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to_plane" type="Plane">
@@ -145,7 +145,7 @@
Returns [code]true[/code] if this plane and [code]plane[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_point_over">
+ <method name="is_point_over" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="plane" type="Vector3">
@@ -154,7 +154,7 @@
Returns [code]true[/code] if [code]point[/code] is located above the plane.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Plane">
</return>
<description>
@@ -189,7 +189,7 @@
<description>
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="point" type="Vector3">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 47e8e57a4e..418785222e 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -565,7 +565,7 @@
<argument index="1" name="state" type="int">
</argument>
<description>
- Sets the state of an multistate item. See [method add_multistate_item] for details.
+ Sets the state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
<method name="set_item_opentype_feature">
@@ -664,13 +664,13 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Cycle to the next state of an multistate item. See [method add_multistate_item] for details.
+ Cycle to the next state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
</methods>
<members>
<member name="allow_search" type="bool" setter="set_allow_search" getter="get_allow_search" default="true">
- If [code]true[/code], allows to navigate [PopupMenu] with letter keys.
+ If [code]true[/code], allows navigating [PopupMenu] with letter keys.
</member>
<member name="hide_on_checkable_item_selection" type="bool" setter="set_hide_on_checkable_item_selection" getter="is_hide_on_checkable_item_selection" default="true">
If [code]true[/code], hides the [PopupMenu] when a checkbox or radio button is selected.
@@ -729,6 +729,9 @@
<theme_item name="font_hover_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
[Color] used for the hovered text.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the menu item.
+ </theme_item>
<theme_item name="font_separator_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
[Color] used for labeled separators' text. See [method add_separator].
</theme_item>
@@ -741,12 +744,19 @@
<theme_item name="hseparation" type="int" default="4">
The horizontal space between the item's name and the shortcut text/submenu arrow.
</theme_item>
+ <theme_item name="item_end_padding" type="int" default="2">
+ </theme_item>
+ <theme_item name="item_start_padding" type="int" default="2">
+ </theme_item>
<theme_item name="labeled_separator_left" type="StyleBox">
[StyleBox] for the left side of labeled separator. See [method add_separator].
</theme_item>
<theme_item name="labeled_separator_right" type="StyleBox">
[StyleBox] for the right side of labeled separator. See [method add_separator].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the item text outline.
+ </theme_item>
<theme_item name="panel" type="StyleBox">
Default [StyleBox] of the [PopupMenu] items.
</theme_item>
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 25943f6d47..8b73bcb9c1 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -31,7 +31,7 @@
</methods>
<members>
<member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )">
- Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unnexpected culling when using a shader to offset vertices.
+ Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices.
</member>
<member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml
index bb7fd31ee8..160b61c720 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -32,11 +32,17 @@
<theme_item name="font_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
The color of the text.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [ProgressBar].
+ </theme_item>
<theme_item name="font_shadow_color" type="Color" default="Color( 0, 0, 0, 1 )">
The color of the text's shadow.
</theme_item>
<theme_item name="font_size" type="int">
Font size used to draw the fill percentage if [member percent_visible] is [code]true[/code].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
</theme_items>
</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index be72f83406..b123e17576 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -6,7 +6,8 @@
<description>
Contains global variables accessible from everywhere. Use [method get_setting], [method set_setting] or [method has_setting] to access them. Variables stored in [code]project.godot[/code] are also loaded into ProjectSettings, making this object very useful for reading custom game configuration options.
When naming a Project Settings property, use the full path to the setting including the category. For example, [code]"application/config/name"[/code] for the project name. Category and property names can be viewed in the Project Settings dialog.
- [b]Overriding:[/b] Any project setting can be overridden by creating a file named [code]override.cfg[/code] in the project's root directory. This can also be used in exported projects by placing this file in the same directory as the project binary.
+ [b]Feature tags:[/b] Project settings can be overriden for specific platforms and configurations (debug, release, ...) using [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url].
+ [b]Overriding:[/b] Any project setting can be overridden by creating a file named [code]override.cfg[/code] in the project's root directory. This can also be used in exported projects by placing this file in the same directory as the project binary. Overriding will still take the base project settings' [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url] in account. Therefore, make sure to [i]also[/i] override the setting with the desired feature tags if you want them to override base project settings on all platforms and configurations.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
@@ -169,6 +170,7 @@
</return>
<description>
Saves the configuration to the [code]project.godot[/code] file.
+ [b]Note:[/b] This method is intended to be used by editor plugins, as modified [ProjectSettings] can't be loaded back in the running app. If you want to change project settings in exported projects, use [method save_custom] to save [code]override.cfg[/code] file.
</description>
</method>
<method name="save_custom">
@@ -177,7 +179,7 @@
<argument index="0" name="file" type="String">
</argument>
<description>
- Saves the configuration to a custom file. The file extension must be [code].godot[/code] (to save in text-based [ConfigFile] format) or [code].binary[/code] (to save in binary format).
+ Saves the configuration to a custom file. The file extension must be [code].godot[/code] (to save in text-based [ConfigFile] format) or [code].binary[/code] (to save in binary format). You can also save [code]override.cfg[/code] file, which is also text, but can be used in exported projects unlike other formats.
</description>
</method>
<method name="set_initial_value">
@@ -254,8 +256,8 @@
[b]Note:[/b] Changing this value will also change the user data folder's path if [member application/config/use_custom_user_dir] is [code]false[/code]. After renaming the project, you will no longer be able to access existing data in [code]user://[/code] unless you rename the old folder to match the new project name. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] in the documentation for more information.
</member>
<member name="application/config/project_settings_override" type="String" setter="" getter="" default="&quot;&quot;">
- Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code].
- [b]Note:[/b] Regardless of this setting's value, [code]res://override.cfg[/code] will still be read to override the project settings (see this class' description at the top).
+ Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code]. See "Overriding" in the [ProjectSettings] class description at the top for more information.
+ [b]Note:[/b] Regardless of this setting's value, [code]res://override.cfg[/code] will still be read to override the project settings.
</member>
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="" default="false">
If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code].
@@ -273,9 +275,11 @@
If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging.
When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally").
[b]Note:[/b] Regardless of this setting, the standard error stream ([code]stderr[/code]) is always flushed when a line is printed to it.
+ Changes to this setting will only be applied upon restarting the application.
</member>
<member name="application/run/flush_stdout_on_print.debug" type="bool" setter="" getter="" default="true">
Debug build override for [member application/run/flush_stdout_on_print], as performance is less important during debugging.
+ Changes to this setting will only be applied upon restarting the application.
</member>
<member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0">
Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization.
@@ -289,31 +293,31 @@
<member name="application/run/main_scene" type="String" setter="" getter="" default="&quot;&quot;">
Path to the main scene file that will be loaded when the project runs.
</member>
- <member name="audio/channel_disable_threshold_db" type="float" setter="" getter="" default="-60.0">
+ <member name="audio/buses/channel_disable_threshold_db" type="float" setter="" getter="" default="-60.0">
Audio buses will disable automatically when sound goes below a given dB threshold for a given time. This saves CPU as effects assigned to that bus will no longer do any processing.
</member>
- <member name="audio/channel_disable_time" type="float" setter="" getter="" default="2.0">
+ <member name="audio/buses/channel_disable_time" type="float" setter="" getter="" default="2.0">
Audio buses will disable automatically when sound goes below a given dB threshold for a given time. This saves CPU as effects assigned to that bus will no longer do any processing.
</member>
- <member name="audio/default_bus_layout" type="String" setter="" getter="" default="&quot;res://default_bus_layout.tres&quot;">
+ <member name="audio/buses/default_bus_layout" type="String" setter="" getter="" default="&quot;res://default_bus_layout.tres&quot;">
Default [AudioBusLayout] resource file to use in the project, unless overridden by the scene.
</member>
- <member name="audio/driver" type="String" setter="" getter="">
+ <member name="audio/driver/driver" type="String" setter="" getter="">
Specifies the audio driver to use. This setting is platform-dependent as each platform supports different audio drivers. If left empty, the default audio driver will be used.
</member>
- <member name="audio/enable_audio_input" type="bool" setter="" getter="" default="false">
+ <member name="audio/driver/enable_input" type="bool" setter="" getter="" default="false">
If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS.
</member>
- <member name="audio/mix_rate" type="int" setter="" getter="" default="44100">
+ <member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100">
Mixing rate used for audio. In general, it's better to not touch this and leave it to the host operating system.
</member>
- <member name="audio/output_latency" type="int" setter="" getter="" default="15">
+ <member name="audio/driver/output_latency" type="int" setter="" getter="" default="15">
Output latency in milliseconds for audio. Lower values will result in lower audio latency at the cost of increased CPU usage. Low values may result in audible cracking on slower hardware.
</member>
- <member name="audio/output_latency.web" type="int" setter="" getter="" default="50">
- Safer override for [member audio/output_latency] in the Web platform, to avoid audio issues especially on mobile devices.
+ <member name="audio/driver/output_latency.web" type="int" setter="" getter="" default="50">
+ Safer override for [member audio/driver/output_latency] in the Web platform, to avoid audio issues especially on mobile devices.
</member>
- <member name="audio/video_delay_compensation_ms" type="int" setter="" getter="" default="0">
+ <member name="audio/video/video_delay_compensation_ms" type="int" setter="" getter="" default="0">
Setting to hardcode audio delay when playing video. Best to leave this untouched unless you know what you are doing.
</member>
<member name="compression/formats/gzip/compression_level" type="int" setter="" getter="" default="-1">
@@ -331,6 +335,18 @@
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="" default="27">
Largest size limit (in power of 2) allowed when compressing using long-distance matching with Zstandard. Higher values can result in better compression, but will require more memory when compressing and decompressing.
</member>
+ <member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], logs all output to files.
+ </member>
+ <member name="debug/file_logging/enable_file_logging.pc" type="bool" setter="" getter="" default="true">
+ Desktop override for [member debug/file_logging/enable_file_logging], as log files are not readily accessible on mobile/Web platforms.
+ </member>
+ <member name="debug/file_logging/log_path" type="String" setter="" getter="" default="&quot;user://logs/godot.log&quot;">
+ Path to logs within the project. Using an [code]user://[/code] path is recommended.
+ </member>
+ <member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5">
+ Specifies the maximum amount of log files allowed (used for rotation).
+ </member>
<member name="debug/gdscript/completion/autocomplete_setters_and_getters" type="bool" setter="" getter="" default="false">
If [code]true[/code], displays getters and setters in autocompletion results in the script editor. This setting is meant to be used when porting old projects (Godot 2), as using member variables is the preferred style from Godot 3 onwards.
</member>
@@ -428,7 +444,7 @@
<member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0">
Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging.
If [member display/window/vsync/use_vsync] is enabled, it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
- This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non real-time rendering of static frames, or test the project under lag conditions.
+ This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions.
</member>
<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
Maximum call stack allowed for debugging GDScript.
@@ -448,10 +464,13 @@
<member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color( 1, 0.2, 0.1, 0.8 )">
Color of the contact points between collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu.
</member>
+ <member name="debug/shapes/collision/draw_2d_outlines" type="bool" setter="" getter="" default="true">
+ Sets whether 2D physics will display collision outlines in game when "Visible Collision Shapes" is enabled in the Debug menu.
+ </member>
<member name="debug/shapes/collision/max_contacts_displayed" type="int" setter="" getter="" default="10000">
Maximum number of contact points between collision shapes to display when "Visible Collision Shapes" is enabled in the Debug menu.
</member>
- <member name="debug/shapes/collision/shape_color" type="Color" setter="" getter="" default="Color( 0, 0.6, 0.7, 0.5 )">
+ <member name="debug/shapes/collision/shape_color" type="Color" setter="" getter="" default="Color( 0, 0.6, 0.7, 0.42 )">
Color of the collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color( 1, 0.7, 0.1, 0.4 )">
@@ -470,14 +489,11 @@
Position offset for tooltips, relative to the mouse cursor's hotspot.
</member>
<member name="display/window/dpi/allow_hidpi" type="bool" setter="" getter="" default="false">
- If [code]true[/code], allows HiDPI display on Windows and macOS. This setting has no effect on desktop Linux, as DPI-awareness fallbacks are not supported there.
+ If [code]true[/code], allows HiDPI display on Windows, macOS, and the HTML5 platform. This setting has no effect on desktop Linux, as DPI-awareness fallbacks are not supported there.
</member>
<member name="display/window/energy_saving/keep_screen_on" type="bool" setter="" getter="" default="true">
If [code]true[/code], keeps the screen on (even in case of inactivity), so the screensaver does not take over. Works on desktop and mobile platforms.
</member>
- <member name="display/window/force_right_to_left_layout_direction" type="bool" setter="" getter="" default="false">
- Force layout direction and text writing direction to RTL for all locales.
- </member>
<member name="display/window/handheld/orientation" type="String" setter="" getter="" default="&quot;landscape&quot;">
Default orientation on mobile devices.
</member>
@@ -513,12 +529,6 @@
<member name="display/window/size/width" type="int" setter="" getter="" default="1024">
Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
</member>
- <member name="display/window/tablet_driver" type="String" setter="" getter="">
- Specifies the tablet driver to use. If left empty, the default driver will be used.
- </member>
- <member name="display/window/text_name" type="String" setter="" getter="" default="&quot;&quot;">
- Specifies the [TextServer] to use. If left empty, the default will be used.
- </member>
<member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables vertical synchronization. This eliminates tearing that may appear in moving scenes, at the cost of higher input latency and stuttering at lower framerates. If [code]false[/code], vertical synchronization will be disabled, however, many platforms will enforce it regardless (such as mobile platforms and HTML5).
</member>
@@ -526,12 +536,18 @@
If [code]Use Vsync[/code] is enabled and this setting is [code]true[/code], enables vertical synchronization via the operating system's window compositor when in windowed mode and the compositor is enabled. This will prevent stutter in certain situations. (Windows only.)
[b]Note:[/b] This option is experimental and meant to alleviate stutter experienced by some users. However, some users have experienced a Vsync framerate halving (e.g. from 60 FPS to 30 FPS) when using it.
</member>
- <member name="editor/script_templates_search_path" type="String" setter="" getter="" default="&quot;res://script_templates&quot;">
- Search path for project-specific script templates. Godot will search for script templates both in the editor-specific path and in this project-specific path.
+ <member name="editor/node_naming/name_casing" type="int" setter="" getter="" default="0">
+ When creating node names automatically, set the type of casing in this project. This is mostly an editor setting.
+ </member>
+ <member name="editor/node_naming/name_num_separator" type="int" setter="" getter="" default="0">
+ What to use to separate node name from number. This is mostly an editor setting.
</member>
- <member name="editor/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( &quot;gd&quot;, &quot;shader&quot; )">
+ <member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( &quot;gd&quot;, &quot;shader&quot; )">
Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files.
</member>
+ <member name="editor/script/templates_search_path" type="String" setter="" getter="" default="&quot;res://script_templates&quot;">
+ Search path for project-specific script templates. Godot will search for script templates both in the editor-specific path and in this project-specific path.
+ </member>
<member name="gui/common/default_scroll_deadzone" type="int" setter="" getter="" default="0">
Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden.
</member>
@@ -566,6 +582,10 @@
Default [InputEventAction] to discard a modal or pending input.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_copy" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_cut" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_down" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move down in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -574,6 +594,12 @@
Default [InputEventAction] to go to the end position of a [Control] (e.g. last item in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_END] on typical desktop UI systems.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_filedialog_refresh" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_filedialog_show_hidden" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_filedialog_up_one_level" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_focus_next" type="Dictionary" setter="" getter="">
Default [InputEventAction] to focus the next [Control] in the scene. The focus behavior can be configured via [member Control.focus_next].
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -582,6 +608,10 @@
Default [InputEventAction] to focus the previous [Control] in the scene. The focus behavior can be configured via [member Control.focus_previous].
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_graph_delete" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_graph_duplicate" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_home" type="Dictionary" setter="" getter="">
Default [InputEventAction] to go to the start position of a [Control] (e.g. first item in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_HOME] on typical desktop UI systems.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -590,6 +620,8 @@
Default [InputEventAction] to move left in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_menu" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_page_down" type="Dictionary" setter="" getter="">
Default [InputEventAction] to go down a page in a [Control] (e.g. in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_PAGEDOWN] on typical desktop UI systems.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -598,6 +630,10 @@
Default [InputEventAction] to go up a page in a [Control] (e.g. in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_PAGEUP] on typical desktop UI systems.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_paste" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_redo" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_right" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move right in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
@@ -606,10 +642,102 @@
Default [InputEventAction] to select an item in a [Control] (e.g. in an [ItemList] or a [Tree]).
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input/ui_swap_input_direction" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_backspace" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_backspace_all_to_left" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_backspace_all_to_left.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_backspace_word" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_backspace_word.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_document_end" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_document_end.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_document_start" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_document_start.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_down" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_left" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_line_end" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_line_end.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_line_start" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_line_start.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_page_down" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_page_up" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_right" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_up" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_word_left" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_word_left.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_word_right" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_caret_word_right.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_completion_accept" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_completion_query" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_dedent" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_delete" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_delete_all_to_right" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_delete_all_to_right.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_delete_word" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_delete_word.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_indent" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_newline" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_newline_above" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_newline_blank" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_scroll_down" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_scroll_down.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_scroll_up" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_scroll_up.OSX" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_select_all" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_text_toggle_insert_mode" type="Dictionary" setter="" getter="">
+ </member>
+ <member name="input/ui_undo" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_up" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move up in the UI.
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
+ <member name="input_devices/pen_tablet/driver" type="String" setter="" getter="">
+ Specifies the tablet driver to use. If left empty, the default driver will be used.
+ </member>
+ <member name="input_devices/pen_tablet/driver.Windows" type="String" setter="" getter="">
+ Override for [member input_devices/pen_tablet/driver] on Windows.
+ </member>
<member name="input_devices/pointing/emulate_mouse_from_touch" type="bool" setter="" getter="" default="true">
If [code]true[/code], sends mouse input events when tapping or swiping on the touchscreen.
</member>
@@ -619,6 +747,83 @@
<member name="input_devices/pointing/ios/touch_delay" type="float" setter="" getter="" default="0.15">
Default delay for touch events. This only affects iOS devices.
</member>
+ <member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
+ The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
+ </member>
+ <member name="internationalization/locale/include_text_server_data" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], text server break iteration rule sets, dictionaries and other optional data are included in the exported project.
+ [b]Note:[/b] "ICU / HarfBuzz / Graphite" text server data includes dictionaries for Burmese, Chinese, Japanese, Khmer, Lao and Thai as well as Unicode Standard Annex #29 and Unicode Standard Annex #14 word and line breaking rules. Data is about 4 MB large.
+ [b]Note:[/b] "Fallback" text server does not use additional data.
+ </member>
+ <member name="internationalization/locale/test" type="String" setter="" getter="" default="&quot;&quot;">
+ If non-empty, this locale will be used when running the project from the editor.
+ </member>
+ <member name="internationalization/rendering/force_right_to_left_layout_direction" type="bool" setter="" getter="" default="false">
+ Force layout direction and text writing direction to RTL for all locales.
+ </member>
+ <member name="internationalization/rendering/text_driver" type="String" setter="" getter="" default="&quot;&quot;">
+ Specifies the [TextServer] to use. If left empty, the default will be used.
+ </member>
+ <member name="layer_names/2d_navigation/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 0. If left empty, the layer will display as "Layer 0".
+ </member>
+ <member name="layer_names/2d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 1. If left empty, the layer will display as "Layer 1".
+ </member>
+ <member name="layer_names/2d_navigation/layer_10" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 10. If left empty, the layer will display as "Layer 10".
+ </member>
+ <member name="layer_names/2d_navigation/layer_11" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 11. If left empty, the layer will display as "Layer 11".
+ </member>
+ <member name="layer_names/2d_navigation/layer_12" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 12. If left empty, the layer will display as "Layer 12".
+ </member>
+ <member name="layer_names/2d_navigation/layer_13" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 13. If left empty, the layer will display as "Layer 13".
+ </member>
+ <member name="layer_names/2d_navigation/layer_14" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 14. If left empty, the layer will display as "Layer 14".
+ </member>
+ <member name="layer_names/2d_navigation/layer_15" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 15. If left empty, the layer will display as "Layer 15".
+ </member>
+ <member name="layer_names/2d_navigation/layer_16" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 16. If left empty, the layer will display as "Layer 16".
+ </member>
+ <member name="layer_names/2d_navigation/layer_17" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 17. If left empty, the layer will display as "Layer 17".
+ </member>
+ <member name="layer_names/2d_navigation/layer_18" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 18. If left empty, the layer will display as "Layer 18".
+ </member>
+ <member name="layer_names/2d_navigation/layer_19" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 19. If left empty, the layer will display as "Layer 19".
+ </member>
+ <member name="layer_names/2d_navigation/layer_2" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 2. If left empty, the layer will display as "Layer 2".
+ </member>
+ <member name="layer_names/2d_navigation/layer_3" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 3. If left empty, the layer will display as "Layer 3".
+ </member>
+ <member name="layer_names/2d_navigation/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 4. If left empty, the layer will display as "Layer 4".
+ </member>
+ <member name="layer_names/2d_navigation/layer_5" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 5. If left empty, the layer will display as "Layer 5".
+ </member>
+ <member name="layer_names/2d_navigation/layer_6" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 6. If left empty, the layer will display as "Layer 6".
+ </member>
+ <member name="layer_names/2d_navigation/layer_7" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 7. If left empty, the layer will display as "Layer 7".
+ </member>
+ <member name="layer_names/2d_navigation/layer_8" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 8. If left empty, the layer will display as "Layer 8".
+ </member>
+ <member name="layer_names/2d_navigation/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 2D navigation layer 9. If left empty, the layer will display as "Layer 9".
+ </member>
<member name="layer_names/2d_physics/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D physics layer 0. If left empty, the layer will display as "Layer 0".
</member>
@@ -739,6 +944,66 @@
<member name="layer_names/2d_render/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D render layer 9. If left empty, the layer will display as "Layer 9".
</member>
+ <member name="layer_names/3d_navigation/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 0. If left empty, the layer will display as "Layer 0".
+ </member>
+ <member name="layer_names/3d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 1. If left empty, the layer will display as "Layer 1".
+ </member>
+ <member name="layer_names/3d_navigation/layer_10" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 10. If left empty, the layer will display as "Layer 10".
+ </member>
+ <member name="layer_names/3d_navigation/layer_11" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 11. If left empty, the layer will display as "Layer 11".
+ </member>
+ <member name="layer_names/3d_navigation/layer_12" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 12. If left empty, the layer will display as "Layer 12".
+ </member>
+ <member name="layer_names/3d_navigation/layer_13" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 13. If left empty, the layer will display as "Layer 13".
+ </member>
+ <member name="layer_names/3d_navigation/layer_14" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 14. If left empty, the layer will display as "Layer 14".
+ </member>
+ <member name="layer_names/3d_navigation/layer_15" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 15. If left empty, the layer will display as "Layer 15".
+ </member>
+ <member name="layer_names/3d_navigation/layer_16" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 16. If left empty, the layer will display as "Layer 16".
+ </member>
+ <member name="layer_names/3d_navigation/layer_17" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 17. If left empty, the layer will display as "Layer 17".
+ </member>
+ <member name="layer_names/3d_navigation/layer_18" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 18. If left empty, the layer will display as "Layer 18".
+ </member>
+ <member name="layer_names/3d_navigation/layer_19" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 19. If left empty, the layer will display as "Layer 19".
+ </member>
+ <member name="layer_names/3d_navigation/layer_2" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 2. If left empty, the layer will display as "Layer 2".
+ </member>
+ <member name="layer_names/3d_navigation/layer_3" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 3. If left empty, the layer will display as "Layer 3".
+ </member>
+ <member name="layer_names/3d_navigation/layer_4" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 4. If left empty, the layer will display as "Layer 4".
+ </member>
+ <member name="layer_names/3d_navigation/layer_5" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 5. If left empty, the layer will display as "Layer 5".
+ </member>
+ <member name="layer_names/3d_navigation/layer_6" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 6. If left empty, the layer will display as "Layer 6".
+ </member>
+ <member name="layer_names/3d_navigation/layer_7" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 7. If left empty, the layer will display as "Layer 7".
+ </member>
+ <member name="layer_names/3d_navigation/layer_8" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 8. If left empty, the layer will display as "Layer 8".
+ </member>
+ <member name="layer_names/3d_navigation/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
+ Optional name for the 3D navigation layer 9. If left empty, the layer will display as "Layer 9".
+ </member>
<member name="layer_names/3d_physics/layer_0" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D physics layer 0. If left empty, the layer will display as "Layer 0".
</member>
@@ -859,24 +1124,6 @@
<member name="layer_names/3d_render/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D render layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
- The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
- </member>
- <member name="locale/test" type="String" setter="" getter="" default="&quot;&quot;">
- If non-empty, this locale will be used when running the project from the editor.
- </member>
- <member name="logging/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
- If [code]true[/code], logs all output to files.
- </member>
- <member name="logging/file_logging/enable_file_logging.pc" type="bool" setter="" getter="" default="true">
- Desktop override for [member logging/file_logging/enable_file_logging], as log files are not readily accessible on mobile/Web platforms.
- </member>
- <member name="logging/file_logging/log_path" type="String" setter="" getter="" default="&quot;user://logs/godot.log&quot;">
- Path to logs within the project. Using an [code]user://[/code] path is recommended.
- </member>
- <member name="logging/file_logging/max_log_files" type="int" setter="" getter="" default="5">
- Specifies the maximum amount of log files allowed (used for rotation).
- </member>
<member name="memory/limits/command_queue/multithreading_queue_size_kb" type="int" setter="" getter="" default="256">
</member>
<member name="memory/limits/message_queue/max_size_kb" type="int" setter="" getter="" default="4096">
@@ -899,6 +1146,18 @@
</member>
<member name="mono/unhandled_exception_policy" type="int" setter="" getter="" default="0">
</member>
+ <member name="navigation/2d/default_cell_size" type="int" setter="" getter="" default="10">
+ Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size].
+ </member>
+ <member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="5">
+ Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
+ </member>
+ <member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.3">
+ Default cell size for 3D navigation maps. See [method NavigationServer3D.map_set_cell_size].
+ </member>
+ <member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.3">
+ Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
+ </member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
Maximum amount of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>
@@ -930,12 +1189,6 @@
The CA certificates bundle to use for SSL connections. If this is set to a non-empty value, this will [i]override[/i] Godot's default [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]Mozilla certificate bundle[/url]. If left empty, the default certificate bundle will be used.
If in doubt, leave this setting empty.
</member>
- <member name="node/name_casing" type="int" setter="" getter="" default="0">
- When creating node names automatically, set the type of casing in this project. This is mostly an editor setting.
- </member>
- <member name="node/name_num_separator" type="int" setter="" getter="" default="0">
- What to use to separate node name from number. This is mostly an editor setting.
- </member>
<member name="physics/2d/bp_hash_table_size" type="int" setter="" getter="" default="4096">
Size of the hash table used for the broad-phase 2D hash grid algorithm.
</member>
@@ -985,22 +1238,18 @@
Sets which physics engine to use for 2D physics.
"DEFAULT" and "GodotPhysics2D" are the same, as there is currently no alternative 2D physics server implemented.
</member>
+ <member name="physics/2d/run_on_thread" type="bool" setter="" getter="" default="false">
+ Sets whether 2D physics is run on the main thread or a separate one. Running the server on a thread increases performance, but restricts API access to only physics process.
+ </member>
<member name="physics/2d/sleep_threshold_angular" type="float" setter="" getter="" default="0.139626">
Threshold angular velocity under which a 2D physics body will be considered inactive. See [constant PhysicsServer2D.SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD].
</member>
<member name="physics/2d/sleep_threshold_linear" type="float" setter="" getter="" default="2.0">
Threshold linear velocity under which a 2D physics body will be considered inactive. See [constant PhysicsServer2D.SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD].
</member>
- <member name="physics/2d/thread_model" type="int" setter="" getter="" default="1">
- Sets whether physics is run on the main thread or a separate one. Running the server on a thread increases performance, but restricts API access to only physics process.
- [b]Warning:[/b] As of Godot 3.2, there are mixed reports about the use of a Multi-Threaded thread model for physics. Be sure to assess whether it does give you extra performance and no regressions when using it.
- </member>
<member name="physics/2d/time_before_sleep" type="float" setter="" getter="" default="0.5">
Time (in seconds) of inactivity before which a 2D physics body will put to sleep. See [constant PhysicsServer2D.SPACE_PARAM_BODY_TIME_TO_SLEEP].
</member>
- <member name="physics/3d/active_soft_world" type="bool" setter="" getter="" default="true">
- Sets whether the 3D physics world will be created with support for [SoftBody3D] physics. Only applies to the Bullet physics engine.
- </member>
<member name="physics/3d/default_angular_damp" type="float" setter="" getter="" default="0.1">
The default angular damp in 3D.
[b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
@@ -1041,6 +1290,15 @@
Sets which physics engine to use for 3D physics.
"DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics3D" engine is still supported as an alternative.
</member>
+ <member name="physics/3d/run_on_thread" type="bool" setter="" getter="" default="false">
+ Sets whether 3D physics is run on the main thread or a separate one. Running the server on a thread increases performance, but restricts API access to only physics process.
+ </member>
+ <member name="physics/3d/sleep_threshold_angular" type="float" setter="" getter="" default="0.139626">
+ </member>
+ <member name="physics/3d/sleep_threshold_linear" type="float" setter="" getter="" default="0.1">
+ </member>
+ <member name="physics/3d/time_before_sleep" type="float" setter="" getter="" default="0.5">
+ </member>
<member name="physics/common/enable_object_picking" type="bool" setter="" getter="" default="true">
Enables [member Viewport.physics_object_picking] on the root viewport.
</member>
@@ -1052,276 +1310,271 @@
Fix to improve physics jitter, specially on monitors where refresh rate is different than the physics FPS.
[b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_jitter_fix] instead.
</member>
- <member name="rendering/cluster_builder/max_clustered_elements" type="float" setter="" getter="" default="512">
- </member>
- <member name="rendering/environment/default_clear_color" type="Color" setter="" getter="" default="Color( 0.3, 0.3, 0.3, 1 )">
- Default background clear color. Overridable per [Viewport] using its [Environment]. See [member Environment.background_mode] and [member Environment.background_color] in particular. To change this default color programmatically, use [method RenderingServer.set_default_clear_color].
+ <member name="rendering/2d/sdf/oversize" type="int" setter="" getter="" default="1">
</member>
- <member name="rendering/environment/default_environment" type="String" setter="" getter="" default="&quot;&quot;">
- [Environment] that will be used as a fallback environment in case a scene does not specify its own environment. The default environment is loaded in at scene load time regardless of whether you have set an environment or not. If you do not rely on the fallback environment, it is best to delete [code]default_env.tres[/code], or to specify a different default environment here.
+ <member name="rendering/2d/sdf/scale" type="int" setter="" getter="" default="1">
</member>
- <member name="rendering/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500">
+ <member name="rendering/2d/shadow_atlas/size" type="int" setter="" getter="" default="2048">
</member>
- <member name="rendering/gpu_lightmapper/performance/max_rays_per_pass" type="int" setter="" getter="" default="32">
+ <member name="rendering/2d/snap/snap_2d_transforms_to_pixel" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/gpu_lightmapper/performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64">
+ <member name="rendering/2d/snap/snap_2d_vertices_to_pixel" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/gpu_lightmapper/performance/region_size" type="int" setter="" getter="" default="512">
+ <member name="rendering/anti_aliasing/quality/msaa" type="int" setter="" getter="" default="0">
+ Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware.
</member>
- <member name="rendering/gpu_lightmapper/quality/high_quality_probe_ray_count" type="int" setter="" getter="" default="512">
+ <member name="rendering/anti_aliasing/quality/screen_space_aa" type="int" setter="" getter="" default="0">
+ Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry.
+ Another way to combat specular aliasing is to enable [member rendering/anti_aliasing/screen_space_roughness_limiter/enabled].
</member>
- <member name="rendering/gpu_lightmapper/quality/high_quality_ray_count" type="int" setter="" getter="" default="256">
+ <member name="rendering/anti_aliasing/quality/use_debanding" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/gpu_lightmapper/quality/low_quality_probe_ray_count" type="int" setter="" getter="" default="64">
+ <member name="rendering/anti_aliasing/screen_space_roughness_limiter/amount" type="float" setter="" getter="" default="0.25">
</member>
- <member name="rendering/gpu_lightmapper/quality/low_quality_ray_count" type="int" setter="" getter="" default="16">
+ <member name="rendering/anti_aliasing/screen_space_roughness_limiter/enabled" type="bool" setter="" getter="" default="true">
</member>
- <member name="rendering/gpu_lightmapper/quality/medium_quality_probe_ray_count" type="int" setter="" getter="" default="256">
+ <member name="rendering/anti_aliasing/screen_space_roughness_limiter/limit" type="float" setter="" getter="" default="0.18">
</member>
- <member name="rendering/gpu_lightmapper/quality/medium_quality_ray_count" type="int" setter="" getter="" default="64">
+ <member name="rendering/camera/depth_of_field/depth_of_field_bokeh_quality" type="int" setter="" getter="" default="2">
+ Sets the quality of the depth of field effect. Higher quality takes more samples, which is slower but looks smoother.
</member>
- <member name="rendering/gpu_lightmapper/quality/ultra_quality_probe_ray_count" type="int" setter="" getter="" default="2048">
+ <member name="rendering/camera/depth_of_field/depth_of_field_bokeh_shape" type="int" setter="" getter="" default="1">
+ Sets the depth of field shape. Can be Box, Hexagon, or Circle. Box is the fastest. Circle is the most realistic, but also the most expensive to compute.
</member>
- <member name="rendering/gpu_lightmapper/quality/ultra_quality_ray_count" type="int" setter="" getter="" default="1024">
+ <member name="rendering/camera/depth_of_field/depth_of_field_use_jitter" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], jitters DOF samples to make effect slightly blurrier and hide lines created from low sample rates. This can result in a slightly grainy appearance when used with a low number of samples.
</member>
- <member name="rendering/high_end/global_shader_variables_buffer_size" type="int" setter="" getter="" default="65536">
+ <member name="rendering/driver/depth_prepass/disable_for_vendors" type="String" setter="" getter="" default="&quot;PowerVR,Mali,Adreno,Apple&quot;">
+ Disables depth pre-pass for some GPU vendors (usually mobile), as their architecture already does this.
</member>
- <member name="rendering/lightmapper/probe_capture_update_speed" type="float" setter="" getter="" default="15">
+ <member name="rendering/driver/depth_prepass/enable" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], performs a previous depth pass before rendering materials. This increases performance in scenes with high overdraw, when complex materials and lighting are used.
</member>
- <member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
+ <member name="rendering/driver/driver_name" type="String" setter="" getter="" default="&quot;Vulkan&quot;">
+ The video driver to use (currently only "Vulkan" is implemented).
+ [b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument.
+ [b]FIXME:[/b] No longer valid after DisplayServer split:
+ In such cases, this property is not updated, so use [code]OS.get_current_video_driver[/code] to query it at run-time.
</member>
- <member name="rendering/quality/2d/snap_2d_transforms_to_pixel" type="bool" setter="" getter="" default="false">
+ <member name="rendering/driver/threads/thread_model" type="int" setter="" getter="" default="1">
+ Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter.
</member>
- <member name="rendering/quality/2d/snap_2d_vertices_to_pixel" type="bool" setter="" getter="" default="false">
+ <member name="rendering/environment/defaults/default_clear_color" type="Color" setter="" getter="" default="Color( 0.3, 0.3, 0.3, 1 )">
+ Default background clear color. Overridable per [Viewport] using its [Environment]. See [member Environment.background_mode] and [member Environment.background_color] in particular. To change this default color programmatically, use [method RenderingServer.set_default_clear_color].
</member>
- <member name="rendering/quality/2d_sdf/oversize" type="int" setter="" getter="" default="1">
+ <member name="rendering/environment/defaults/default_environment" type="String" setter="" getter="" default="&quot;&quot;">
+ [Environment] that will be used as a fallback environment in case a scene does not specify its own environment. The default environment is loaded in at scene load time regardless of whether you have set an environment or not. If you do not rely on the fallback environment, it is best to delete [code]default_env.tres[/code], or to specify a different default environment here.
</member>
- <member name="rendering/quality/2d_sdf/scale" type="int" setter="" getter="" default="1">
+ <member name="rendering/environment/glow/upscale_mode" type="int" setter="" getter="" default="1">
+ Sets how the glow effect is upscaled before being copied onto the screen. Linear is faster, but looks blocky. Bicubic is slower but looks smooth.
</member>
- <member name="rendering/quality/2d_shadow_atlas/size" type="int" setter="" getter="" default="2048">
+ <member name="rendering/environment/glow/upscale_mode.mobile" type="int" setter="" getter="" default="0">
+ Lower-end override for [member rendering/environment/glow/upscale_mode] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/depth_of_field/depth_of_field_bokeh_quality" type="int" setter="" getter="" default="2">
- Sets the quality of the depth of field effect. Higher quality takes more samples, which is slower but looks smoother.
+ <member name="rendering/environment/glow/use_high_quality" type="bool" setter="" getter="" default="false">
+ Takes more samples during downsample pass of glow. This ensures that single pixels are captured by glow which makes the glow look smoother and more stable during movement. However, it is very expensive and makes the glow post process take twice as long.
</member>
- <member name="rendering/quality/depth_of_field/depth_of_field_bokeh_shape" type="int" setter="" getter="" default="1">
- Sets the depth of field shape. Can be Box, Hexagon, or Circle. Box is the fastest. Circle is the most realistic, but also the most expensive to compute.
+ <member name="rendering/environment/screen_space_reflection/roughness_quality" type="int" setter="" getter="" default="1">
+ Sets the quality for rough screen-space reflections. Turning off will make all screen space reflections sharp, while higher values make rough reflections look better.
</member>
- <member name="rendering/quality/depth_of_field/depth_of_field_use_jitter" type="bool" setter="" getter="" default="false">
- If [code]true[/code], jitters DOF samples to make effect slightly blurrier and hide lines created from low sample rates. This can result in a slightly grainy appearance when used with a low number of samples.
+ <member name="rendering/environment/ssao/adaptive_target" type="float" setter="" getter="" default="0.5">
+ Quality target to use when [member rendering/environment/ssao/quality] is set to [code]ULTRA[/code]. A value of [code]0.0[/code] provides a quality and speed similar to [code]MEDIUM[/code] while a value of [code]1.0[/code] provides much higher quality than any of the other settings at the cost of performance.
</member>
- <member name="rendering/quality/depth_prepass/disable_for_vendors" type="String" setter="" getter="" default="&quot;PowerVR,Mali,Adreno,Apple&quot;">
- Disables depth pre-pass for some GPU vendors (usually mobile), as their architecture already does this.
+ <member name="rendering/environment/ssao/blur_passes" type="int" setter="" getter="" default="2">
+ Number of blur passes to use when computing screen-space ambient occlusion. A higher number will result in a smoother look, but will be slower to compute and will have less high-frequency detail.
</member>
- <member name="rendering/quality/depth_prepass/enable" type="bool" setter="" getter="" default="true">
- If [code]true[/code], performs a previous depth pass before rendering materials. This increases performance in scenes with high overdraw, when complex materials and lighting are used.
+ <member name="rendering/environment/ssao/fadeout_from" type="float" setter="" getter="" default="50.0">
+ Distance at which the screen-space ambient occlusion effect starts to fade out. Use this hide ambient occlusion at great distances.
</member>
- <member name="rendering/quality/directional_shadow/16_bits" type="bool" setter="" getter="" default="true">
+ <member name="rendering/environment/ssao/fadeout_to" type="float" setter="" getter="" default="300.0">
+ Distance at which the screen-space ambient occlusion is fully faded out. Use this hide ambient occlusion at great distances.
</member>
- <member name="rendering/quality/directional_shadow/size" type="int" setter="" getter="" default="4096">
- The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2.
+ <member name="rendering/environment/ssao/half_size" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], screen-space ambient occlusion will be rendered at half size and then upscaled before being added to the scene. This is significantly faster but may miss small details.
</member>
- <member name="rendering/quality/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048">
- Lower-end override for [member rendering/quality/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/environment/ssao/half_size.mobile" type="bool" setter="" getter="" default="true">
+ Lower-end override for [member rendering/environment/ssao/half_size] on mobile devices, due to performance concerns.
</member>
- <member name="rendering/quality/directional_shadow/soft_shadow_quality" type="int" setter="" getter="" default="2">
- Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
+ <member name="rendering/environment/ssao/quality" type="int" setter="" getter="" default="2">
+ Sets the quality of the screen-space ambient occlusion effect. Higher values take more samples and so will result in better quality, at the cost of performance. Setting to [code]ULTRA[/code] will use the [member rendering/environment/ssao/adaptive_target] setting.
</member>
- <member name="rendering/quality/directional_shadow/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
- Lower-end override for [member rendering/quality/directional_shadow/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale" type="float" setter="" getter="" default="0.01">
+ Scales the depth over which the subsurface scattering effect is applied. A high value may allow light to scatter into a part of the mesh or another mesh that is close in screen space but far in depth.
</member>
- <member name="rendering/quality/driver/driver_name" type="String" setter="" getter="" default="&quot;Vulkan&quot;">
- The video driver to use ("GLES2" or "Vulkan").
- [b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument.
- [b]FIXME:[/b] No longer valid after DisplayServer split:
- In such cases, this property is not updated, so use [code]OS.get_current_video_driver[/code] to query it at run-time.
+ <member name="rendering/environment/subsurface_scattering/subsurface_scattering_quality" type="int" setter="" getter="" default="1">
+ Sets the quality of the subsurface scattering effect. Higher values are slower but look nicer.
</member>
- <member name="rendering/quality/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
+ <member name="rendering/environment/subsurface_scattering/subsurface_scattering_scale" type="float" setter="" getter="" default="0.05">
+ Scales the distance over which samples are taken for subsurface scattering effect. Changing this does not impact performance, but higher values will result in significant artifacts as the samples will become obviously spread out. A lower value results in a smaller spread of scattered light.
</member>
- <member name="rendering/quality/gi_probes/anisotropic" type="bool" setter="" getter="" default="false">
- If [code]true[/code], take additional samples when rendering objects affected by a [GIProbe] to reduce artifacts from only sampling in one direction.
+ <member name="rendering/environment/volumetric_fog/use_filter" type="int" setter="" getter="" default="1">
</member>
- <member name="rendering/quality/gi_probes/quality" type="int" setter="" getter="" default="1">
- Sets the number of cone samples taken when rendering objects affected by [GIProbe]s.
+ <member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="128">
</member>
- <member name="rendering/quality/glow/upscale_mode" type="int" setter="" getter="" default="1">
- Sets how the glow effect is upscaled before being copied onto the screen. Linear is faster, but looks blocky. Bicubic is slower but looks smooth.
+ <member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
</member>
- <member name="rendering/quality/glow/upscale_mode.mobile" type="int" setter="" getter="" default="0">
- Lower-end override for [member rendering/quality/glow/upscale_mode] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/quality/glow/use_high_quality" type="bool" setter="" getter="" default="false">
- Takes more samples during downsample pass of glow. This ensures that single pixels are captured by glow which makes the glow look smoother and more stable during movement. However, it is very expensive and makes the glow post process take twice as long.
+ <member name="rendering/global_illumination/gi_probes/anisotropic" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], take additional samples when rendering objects affected by a [GIProbe] to reduce artifacts from only sampling in one direction.
</member>
- <member name="rendering/quality/intended_usage/framebuffer_allocation" type="int" setter="" getter="" default="2">
- Strategy used for framebuffer allocation. The simpler it is, the less resources it uses (but the less features it supports). If set to "2D Without Sampling" or "3D Without Effects", sample buffers will not be allocated. This means [code]SCREEN_TEXTURE[/code] and [code]DEPTH_TEXTURE[/code] will not be available in shaders and post-processing effects will not be available in the [Environment].
+ <member name="rendering/global_illumination/gi_probes/quality" type="int" setter="" getter="" default="1">
+ Sets the number of cone samples taken when rendering objects affected by [GIProbe]s.
</member>
- <member name="rendering/quality/intended_usage/framebuffer_allocation.mobile" type="int" setter="" getter="" default="3">
- Lower-end override for [member rendering/quality/intended_usage/framebuffer_allocation] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/global_illumination/sdfgi/frames_to_converge" type="int" setter="" getter="" default="4">
</member>
- <member name="rendering/quality/mesh_lod/threshold_pixels" type="float" setter="" getter="" default="1.0">
+ <member name="rendering/global_illumination/sdfgi/frames_to_update_lights" type="int" setter="" getter="" default="2">
</member>
- <member name="rendering/quality/rd_renderer/use_low_end_renderer" type="bool" setter="" getter="" default="false">
+ <member name="rendering/global_illumination/sdfgi/probe_ray_count" type="int" setter="" getter="" default="1">
</member>
- <member name="rendering/quality/rd_renderer/use_low_end_renderer.mobile" type="bool" setter="" getter="" default="true">
+ <member name="rendering/lightmapping/bake_performance/max_rays_per_pass" type="int" setter="" getter="" default="32">
</member>
- <member name="rendering/quality/reflection_atlas/reflection_count" type="int" setter="" getter="" default="64">
- Number of cubemaps to store in the reflection atlas. The number of [ReflectionProbe]s in a scene will be limited by this amount. A higher number requires more VRAM.
+ <member name="rendering/lightmapping/bake_performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64">
</member>
- <member name="rendering/quality/reflection_atlas/reflection_size" type="int" setter="" getter="" default="256">
- Size of cubemap faces for [ReflectionProbe]s. A higher number requires more VRAM and may make reflection probe updating slower.
+ <member name="rendering/lightmapping/bake_performance/region_size" type="int" setter="" getter="" default="512">
</member>
- <member name="rendering/quality/reflection_atlas/reflection_size.mobile" type="int" setter="" getter="" default="128">
- Lower-end override for [member rendering/quality/reflection_atlas/reflection_size] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/lightmapping/bake_quality/high_quality_probe_ray_count" type="int" setter="" getter="" default="512">
</member>
- <member name="rendering/quality/reflections/fast_filter_high_quality" type="bool" setter="" getter="" default="false">
- Use a higher quality variant of the fast filtering algorithm. Significantly slower than using default quality, but results in smoother reflections. Should only be used when the scene is especially detailed.
+ <member name="rendering/lightmapping/bake_quality/high_quality_ray_count" type="int" setter="" getter="" default="256">
</member>
- <member name="rendering/quality/reflections/ggx_samples" type="int" setter="" getter="" default="1024">
- Sets the number of samples to take when using importance sampling for [Sky]s and [ReflectionProbe]s. A higher value will result in smoother, higher quality reflections, but increases time to calculate radiance maps. In general, fewer samples are needed for simpler, low dynamic range environments while more samples are needed for HDR environments and environments with a high level of detail.
+ <member name="rendering/lightmapping/bake_quality/low_quality_probe_ray_count" type="int" setter="" getter="" default="64">
</member>
- <member name="rendering/quality/reflections/ggx_samples.mobile" type="int" setter="" getter="" default="128">
- Lower-end override for [member rendering/quality/reflections/ggx_samples] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/lightmapping/bake_quality/low_quality_ray_count" type="int" setter="" getter="" default="16">
</member>
- <member name="rendering/quality/reflections/roughness_layers" type="int" setter="" getter="" default="8">
- Limits the number of layers to use in radiance maps when using importance sampling. A lower number will be slightly faster and take up less VRAM.
+ <member name="rendering/lightmapping/bake_quality/medium_quality_probe_ray_count" type="int" setter="" getter="" default="256">
</member>
- <member name="rendering/quality/reflections/texture_array_reflections" type="bool" setter="" getter="" default="true">
- If [code]true[/code], uses texture arrays instead of mipmaps for reflection probes and panorama backgrounds (sky). This reduces jitter noise and upscaling artifacts on reflections, but is significantly slower to compute and uses [member rendering/quality/reflections/roughness_layers] times more memory.
+ <member name="rendering/lightmapping/bake_quality/medium_quality_ray_count" type="int" setter="" getter="" default="64">
</member>
- <member name="rendering/quality/reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
- Lower-end override for [member rendering/quality/reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count" type="int" setter="" getter="" default="2048">
</member>
- <member name="rendering/quality/screen_filters/msaa" type="int" setter="" getter="" default="0">
- Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware.
- [b]Note:[/b] MSAA is not available on HTML5 export using the GLES2 backend.
+ <member name="rendering/lightmapping/bake_quality/ultra_quality_ray_count" type="int" setter="" getter="" default="1024">
</member>
- <member name="rendering/quality/screen_filters/screen_space_aa" type="int" setter="" getter="" default="0">
- Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry.
- Another way to combat specular aliasing is to enable [member rendering/quality/screen_filters/screen_space_roughness_limiter_enabled].
+ <member name="rendering/lightmapping/probe_capture/update_speed" type="float" setter="" getter="" default="15">
</member>
- <member name="rendering/quality/screen_filters/screen_space_roughness_limiter_amount" type="float" setter="" getter="" default="0.25">
+ <member name="rendering/limits/cluster_builder/max_clustered_elements" type="float" setter="" getter="" default="512">
</member>
- <member name="rendering/quality/screen_filters/screen_space_roughness_limiter_enabled" type="bool" setter="" getter="" default="true">
+ <member name="rendering/limits/forward_renderer/threaded_render_minimum_instances" type="int" setter="" getter="" default="500">
</member>
- <member name="rendering/quality/screen_filters/screen_space_roughness_limiter_limit" type="float" setter="" getter="" default="0.18">
+ <member name="rendering/limits/global_shader_variables/buffer_size" type="int" setter="" getter="" default="65536">
</member>
- <member name="rendering/quality/screen_filters/use_debanding" type="bool" setter="" getter="" default="false">
+ <member name="rendering/limits/spatial_indexer/threaded_cull_minimum_instances" type="int" setter="" getter="" default="1000">
</member>
- <member name="rendering/quality/screen_space_reflection/roughness_quality" type="int" setter="" getter="" default="1">
- Sets the quality for rough screen-space reflections. Turning off will make all screen space reflections sharp, while higher values make rough reflections look better.
+ <member name="rendering/limits/spatial_indexer/update_iterations_per_frame" type="int" setter="" getter="" default="10">
</member>
- <member name="rendering/quality/shading/force_blinn_over_ggx" type="bool" setter="" getter="" default="false">
- If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model.
+ <member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
</member>
- <member name="rendering/quality/shading/force_blinn_over_ggx.mobile" type="bool" setter="" getter="" default="true">
- Lower-end override for [member rendering/quality/shading/force_blinn_over_ggx] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/mesh_lod/lod_change/threshold_pixels" type="float" setter="" getter="" default="1.0">
</member>
- <member name="rendering/quality/shading/force_lambert_over_burley" type="bool" setter="" getter="" default="false">
- If [code]true[/code], uses faster but lower-quality Lambert material lighting model instead of Burley.
+ <member name="rendering/occlusion_culling/bvh_build_quality" type="int" setter="" getter="" default="2">
</member>
- <member name="rendering/quality/shading/force_lambert_over_burley.mobile" type="bool" setter="" getter="" default="true">
- Lower-end override for [member rendering/quality/shading/force_lambert_over_burley] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/occlusion_culling/occlusion_rays_per_thread" type="int" setter="" getter="" default="512">
</member>
- <member name="rendering/quality/shading/force_vertex_shading" type="bool" setter="" getter="" default="false">
- If [code]true[/code], forces vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can be used to optimize performance on low-end mobile devices.
+ <member name="rendering/occlusion_culling/use_occlusion_culling" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/quality/shading/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true">
- Lower-end override for [member rendering/quality/shading/force_vertex_shading] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/reflections/reflection_atlas/reflection_count" type="int" setter="" getter="" default="64">
+ Number of cubemaps to store in the reflection atlas. The number of [ReflectionProbe]s in a scene will be limited by this amount. A higher number requires more VRAM.
</member>
- <member name="rendering/quality/shadow_atlas/16_bits" type="bool" setter="" getter="" default="true">
+ <member name="rendering/reflections/reflection_atlas/reflection_size" type="int" setter="" getter="" default="256">
+ Size of cubemap faces for [ReflectionProbe]s. A higher number requires more VRAM and may make reflection probe updating slower.
</member>
- <member name="rendering/quality/shadow_atlas/quadrant_0_subdiv" type="int" setter="" getter="" default="2">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ <member name="rendering/reflections/reflection_atlas/reflection_size.mobile" type="int" setter="" getter="" default="128">
+ Lower-end override for [member rendering/reflections/reflection_atlas/reflection_size] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/shadow_atlas/quadrant_1_subdiv" type="int" setter="" getter="" default="2">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ <member name="rendering/reflections/sky_reflections/fast_filter_high_quality" type="bool" setter="" getter="" default="false">
+ Use a higher quality variant of the fast filtering algorithm. Significantly slower than using default quality, but results in smoother reflections. Should only be used when the scene is especially detailed.
</member>
- <member name="rendering/quality/shadow_atlas/quadrant_2_subdiv" type="int" setter="" getter="" default="3">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ <member name="rendering/reflections/sky_reflections/ggx_samples" type="int" setter="" getter="" default="1024">
+ Sets the number of samples to take when using importance sampling for [Sky]s and [ReflectionProbe]s. A higher value will result in smoother, higher quality reflections, but increases time to calculate radiance maps. In general, fewer samples are needed for simpler, low dynamic range environments while more samples are needed for HDR environments and environments with a high level of detail.
</member>
- <member name="rendering/quality/shadow_atlas/quadrant_3_subdiv" type="int" setter="" getter="" default="4">
- Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
+ <member name="rendering/reflections/sky_reflections/ggx_samples.mobile" type="int" setter="" getter="" default="128">
+ Lower-end override for [member rendering/reflections/sky_reflections/ggx_samples] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/shadow_atlas/size" type="int" setter="" getter="" default="4096">
- Size for shadow atlas (used for OmniLights and SpotLights). See documentation.
+ <member name="rendering/reflections/sky_reflections/roughness_layers" type="int" setter="" getter="" default="8">
+ Limits the number of layers to use in radiance maps when using importance sampling. A lower number will be slightly faster and take up less VRAM.
</member>
- <member name="rendering/quality/shadow_atlas/size.mobile" type="int" setter="" getter="" default="2048">
- Lower-end override for [member rendering/quality/shadow_atlas/size] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/reflections/sky_reflections/texture_array_reflections" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], uses texture arrays instead of mipmaps for reflection probes and panorama backgrounds (sky). This reduces jitter noise and upscaling artifacts on reflections, but is significantly slower to compute and uses [member rendering/reflections/sky_reflections/roughness_layers] times more memory.
</member>
- <member name="rendering/quality/shadows/soft_shadow_quality" type="int" setter="" getter="" default="2">
- Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
+ <member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
+ Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/shadows/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
- Lower-end override for [member rendering/quality/shadows/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
+ <member name="rendering/shading/overrides/force_blinn_over_ggx" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model.
</member>
- <member name="rendering/quality/ssao/adaptive_target" type="float" setter="" getter="" default="0.5">
- Quality target to use when [member rendering/quality/ssao/quality] is set to [code]ULTRA[/code]. A value of [code]0.0[/code] provides a quality and speed similar to [code]MEDIUM[/code] while a value of [code]1.0[/code] provides much higher quality than any of the other settings at the cost of performance.
+ <member name="rendering/shading/overrides/force_blinn_over_ggx.mobile" type="bool" setter="" getter="" default="true">
+ Lower-end override for [member rendering/shading/overrides/force_blinn_over_ggx] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/ssao/blur_passes" type="int" setter="" getter="" default="2">
- Number of blur passes to use when computing screen-space ambient occlusion. A higher number will result in a smoother look, but will be slower to compute and will have less high-frequency detail.
+ <member name="rendering/shading/overrides/force_lambert_over_burley" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses faster but lower-quality Lambert material lighting model instead of Burley.
</member>
- <member name="rendering/quality/ssao/fadeout_from" type="float" setter="" getter="" default="50.0">
- Distance at which the screen-space ambient occlusion effect starts to fade out. Use this hide ambient occlusion at great distances.
+ <member name="rendering/shading/overrides/force_lambert_over_burley.mobile" type="bool" setter="" getter="" default="true">
+ Lower-end override for [member rendering/shading/overrides/force_lambert_over_burley] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/ssao/fadeout_to" type="float" setter="" getter="" default="300.0">
- Distance at which the screen-space ambient occlusion is fully faded out. Use this hide ambient occlusion at great distances.
+ <member name="rendering/shading/overrides/force_vertex_shading" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], forces vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can be used to optimize performance on low-end mobile devices.
</member>
- <member name="rendering/quality/ssao/half_size" type="bool" setter="" getter="" default="false">
- If [code]true[/code], screen-space ambient occlusion will be rendered at half size and then upscaled before being added to the scene. This is significantly faster but may miss small details.
+ <member name="rendering/shading/overrides/force_vertex_shading.mobile" type="bool" setter="" getter="" default="true">
+ Lower-end override for [member rendering/shading/overrides/force_vertex_shading] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/ssao/half_size.mobile" type="bool" setter="" getter="" default="true">
- Lower-end override for [member rendering/quality/ssao/half_size] on mobile devices, due to performance concerns.
+ <member name="rendering/shadows/directional_shadow/16_bits" type="bool" setter="" getter="" default="true">
</member>
- <member name="rendering/quality/ssao/quality" type="int" setter="" getter="" default="2">
- Sets the quality of the screen-space ambient occlusion effect. Higher values take more samples and so will result in better quality, at the cost of performance. Setting to [code]ULTRA[/code] will use the [member rendering/quality/ssao/adaptive_target] setting.
+ <member name="rendering/shadows/directional_shadow/size" type="int" setter="" getter="" default="4096">
+ The directional shadow's size in pixels. Higher values will result in sharper shadows, at the cost of performance. The value will be rounded up to the nearest power of 2.
</member>
- <member name="rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale" type="float" setter="" getter="" default="0.01">
- Scales the depth over which the subsurface scattering effect is applied. A high value may allow light to scatter into a part of the mesh or another mesh that is close in screen space but far in depth.
+ <member name="rendering/shadows/directional_shadow/size.mobile" type="int" setter="" getter="" default="2048">
+ Lower-end override for [member rendering/shadows/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/subsurface_scattering/subsurface_scattering_quality" type="int" setter="" getter="" default="1">
- Sets the quality of the subsurface scattering effect. Higher values are slower but look nicer.
+ <member name="rendering/shadows/directional_shadow/soft_shadow_quality" type="int" setter="" getter="" default="2">
+ Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
</member>
- <member name="rendering/quality/subsurface_scattering/subsurface_scattering_scale" type="float" setter="" getter="" default="0.05">
- Scales the distance over which samples are taken for subsurface scattering effect. Changing this does not impact performance, but higher values will result in significant artifacts as the samples will become obviously spread out. A lower value results in a smaller spread of scattered light.
+ <member name="rendering/shadows/directional_shadow/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
+ Lower-end override for [member rendering/shadows/directional_shadow/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/quality/texture_filters/anisotropic_filtering_level" type="int" setter="" getter="" default="2">
- Sets the maximum number of samples to take when using anisotropic filtering on textures (as a power of two). A higher sample count will result in sharper textures at oblique angles, but is more expensive to compute. A value of [code]0[/code] forcibly disables anisotropic filtering, even on materials where it is enabled.
+ <member name="rendering/shadows/shadow_atlas/16_bits" type="bool" setter="" getter="" default="true">
</member>
- <member name="rendering/quality/texture_filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false">
- If [code]true[/code], uses nearest-neighbor mipmap filtering when using mipmaps (also called "bilinear filtering"), which will result in visible seams appearing between mipmap stages. This may increase performance in mobile as less memory bandwidth is used. If [code]false[/code], linear mipmap filtering (also called "trilinear filtering") is used.
+ <member name="rendering/shadows/shadow_atlas/quadrant_0_subdiv" type="int" setter="" getter="" default="2">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
</member>
- <member name="rendering/sdfgi/frames_to_converge" type="int" setter="" getter="" default="4">
+ <member name="rendering/shadows/shadow_atlas/quadrant_1_subdiv" type="int" setter="" getter="" default="2">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
</member>
- <member name="rendering/sdfgi/frames_to_update_lights" type="int" setter="" getter="" default="2">
+ <member name="rendering/shadows/shadow_atlas/quadrant_2_subdiv" type="int" setter="" getter="" default="3">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
</member>
- <member name="rendering/sdfgi/probe_ray_count" type="int" setter="" getter="" default="1">
+ <member name="rendering/shadows/shadow_atlas/quadrant_3_subdiv" type="int" setter="" getter="" default="4">
+ Subdivision quadrant size for shadow mapping. See shadow mapping documentation.
</member>
- <member name="rendering/spatial_indexer/threaded_cull_minimum_instances" type="int" setter="" getter="" default="1000">
+ <member name="rendering/shadows/shadow_atlas/size" type="int" setter="" getter="" default="4096">
+ Size for shadow atlas (used for OmniLights and SpotLights). See documentation.
</member>
- <member name="rendering/spatial_indexer/update_iterations_per_frame" type="int" setter="" getter="" default="10">
+ <member name="rendering/shadows/shadow_atlas/size.mobile" type="int" setter="" getter="" default="2048">
+ Lower-end override for [member rendering/shadows/shadow_atlas/size] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/threads/thread_model" type="int" setter="" getter="" default="1">
- Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter.
+ <member name="rendering/shadows/shadows/soft_shadow_quality" type="int" setter="" getter="" default="2">
+ Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
</member>
- <member name="rendering/volumetric_fog/use_filter" type="int" setter="" getter="" default="1">
+ <member name="rendering/shadows/shadows/soft_shadow_quality.mobile" type="int" setter="" getter="" default="0">
+ Lower-end override for [member rendering/shadows/shadows/soft_shadow_quality] on mobile devices, due to performance concerns or driver support.
</member>
- <member name="rendering/volumetric_fog/volume_depth" type="int" setter="" getter="" default="128">
+ <member name="rendering/textures/default_filters/anisotropic_filtering_level" type="int" setter="" getter="" default="2">
+ Sets the maximum number of samples to take when using anisotropic filtering on textures (as a power of two). A higher sample count will result in sharper textures at oblique angles, but is more expensive to compute. A value of [code]0[/code] forcibly disables anisotropic filtering, even on materials where it is enabled.
</member>
- <member name="rendering/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
+ <member name="rendering/textures/default_filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses nearest-neighbor mipmap filtering when using mipmaps (also called "bilinear filtering"), which will result in visible seams appearing between mipmap stages. This may increase performance in mobile as less memory bandwidth is used. If [code]false[/code], linear mipmap filtering (also called "trilinear filtering") is used.
</member>
- <member name="rendering/vram_compression/import_bptc" type="bool" setter="" getter="" default="false">
+ <member name="rendering/textures/vram_compression/import_bptc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the BPTC algorithm. This texture compression algorithm is only supported on desktop platforms, and only when using the Vulkan renderer.
</member>
- <member name="rendering/vram_compression/import_etc" type="bool" setter="" getter="" default="false">
+ <member name="rendering/textures/vram_compression/import_etc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression algorithm. This algorithm doesn't support alpha channels in textures.
</member>
- <member name="rendering/vram_compression/import_etc2" type="bool" setter="" getter="" default="true">
+ <member name="rendering/textures/vram_compression/import_etc2" type="bool" setter="" getter="" default="true">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression 2 algorithm. This texture compression algorithm is only supported when using the Vulkan renderer.
</member>
- <member name="rendering/vram_compression/import_pvrtc" type="bool" setter="" getter="" default="false">
+ <member name="rendering/textures/vram_compression/import_pvrtc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the PowerVR Texture Compression algorithm. This texture compression algorithm is only supported on iOS.
</member>
- <member name="rendering/vram_compression/import_s3tc" type="bool" setter="" getter="" default="true">
+ <member name="rendering/textures/vram_compression/import_s3tc" type="bool" setter="" getter="" default="true">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm. This algorithm is only supported on desktop platforms and consoles.
</member>
<member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index ef83ae7fb9..1c0a3e37c0 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -83,7 +83,7 @@
Constructs a quaternion defined by the given values.
</description>
</method>
- <method name="cubic_slerp">
+ <method name="cubic_slerp" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="b" type="Quat">
@@ -98,7 +98,7 @@
Performs a cubic spherical interpolation between quaternions [code]pre_a[/code], this vector, [code]b[/code], and [code]post_b[/code], by the given amount [code]weight[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Quat">
@@ -107,51 +107,51 @@
Returns the dot product of two quaternions.
</description>
</method>
- <method name="get_euler">
+ <method name="get_euler" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Quat">
</return>
<description>
Returns the inverse of the quaternion.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Quat">
</argument>
<description>
- Returns [code]true[/code] if this quaterion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this quaternion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns whether the quaternion is normalized or not.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length of the quaternion.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length of the quaternion, squared.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Quat">
</return>
<description>
@@ -258,7 +258,7 @@
<description>
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="to" type="Quat">
@@ -270,7 +270,7 @@
[b]Note:[/b] Both quaternions must be normalized.
</description>
</method>
- <method name="slerpni">
+ <method name="slerpni" qualifiers="const">
<return type="Quat">
</return>
<argument index="0" name="to" type="Quat">
diff --git a/doc/classes/RID.xml b/doc/classes/RID.xml
index 0ee34d4194..e686a4b8fd 100644
--- a/doc/classes/RID.xml
+++ b/doc/classes/RID.xml
@@ -25,7 +25,7 @@
Constructs a [RID] as a copy of the given [RID].
</description>
</method>
- <method name="get_id">
+ <method name="get_id" qualifiers="const">
<return type="int">
</return>
<description>
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index d24e86a08b..443890438f 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -136,6 +136,13 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
+ <member name="debug_shape_custom_color" type="Color" setter="set_debug_shape_custom_color" getter="get_debug_shape_custom_color" default="Color( 0, 0, 0, 1 )">
+ The custom color to use to draw the shape in the editor and at run-time if [b]Visible Collision Shapes[/b] is enabled in the [b]Debug[/b] menu. This color will be highlighted at run-time if the [RayCast3D] is colliding with something.
+ If set to [code]Color(0.0, 0.0, 0.0)[/code] (by default), the color set in [member ProjectSettings.debug/shapes/collision/shape_color] is used.
+ </member>
+ <member name="debug_shape_thickness" type="float" setter="set_debug_shape_thickness" getter="get_debug_shape_thickness" default="2.0">
+ If set to [code]1[/code], a line is used as the debug shape. Otherwise, a truncated pyramid is drawn to represent the [RayCast3D]. Requires [b]Visible Collision Shapes[/b] to be enabled in the [b]Debug[/b] menu for the debug shape to be visible at run-time.
+ </member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
If [code]true[/code], collisions will be reported.
</member>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 5d7ff39587..352a18e326 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -65,14 +65,14 @@
Constructs a [Rect2] by x, y, width, and height.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Rect2">
</return>
<description>
Returns a [Rect2] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
@@ -81,7 +81,7 @@
Returns [code]true[/code] if this [Rect2] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -90,14 +90,14 @@
Returns this [Rect2] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="float">
</return>
<description>
Returns the area of the [Rect2].
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="amount" type="float">
@@ -106,7 +106,7 @@
Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on all sides.
</description>
</method>
- <method name="grow_individual">
+ <method name="grow_individual" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="left" type="float">
@@ -121,7 +121,7 @@
Returns a copy of the [Rect2] grown by the specified amount on each side individually.
</description>
</method>
- <method name="grow_side">
+ <method name="grow_side" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="side" type="int">
@@ -132,14 +132,14 @@
Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [Rect2] is flat or empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
@@ -148,7 +148,7 @@
Returns [code]true[/code] if the [Rect2] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
@@ -158,7 +158,7 @@
If the rectangles do not intersect, an empty [Rect2] is returned.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
@@ -170,7 +170,7 @@
If [code]include_borders[/code] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="rect" type="Rect2">
@@ -179,7 +179,7 @@
Returns [code]true[/code] if this [Rect2] and [code]rect[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
@@ -221,7 +221,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index e581ccdb11..84bef9b406 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -63,14 +63,14 @@
Constructs a [Rect2i] by x, y, width, and height.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Rect2i">
</return>
<description>
Returns a [Rect2i] with equivalent position and area, modified so that the top-left corner is the origin and [code]width[/code] and [code]height[/code] are positive.
</description>
</method>
- <method name="encloses">
+ <method name="encloses" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -79,7 +79,7 @@
Returns [code]true[/code] if this [Rect2i] completely encloses another one.
</description>
</method>
- <method name="expand">
+ <method name="expand" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="to" type="Vector2i">
@@ -88,14 +88,14 @@
Returns this [Rect2i] expanded to include a given point.
</description>
</method>
- <method name="get_area">
+ <method name="get_area" qualifiers="const">
<return type="int">
</return>
<description>
Returns the area of the [Rect2i].
</description>
</method>
- <method name="grow">
+ <method name="grow" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="amount" type="int">
@@ -104,7 +104,7 @@
Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on all sides.
</description>
</method>
- <method name="grow_individual">
+ <method name="grow_individual" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="left" type="int">
@@ -119,7 +119,7 @@
Returns a copy of the [Rect2i] grown by the specified amount on each side individually.
</description>
</method>
- <method name="grow_side">
+ <method name="grow_side" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="side" type="int">
@@ -130,14 +130,14 @@
Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on the specified [enum Side].
</description>
</method>
- <method name="has_no_area">
+ <method name="has_no_area" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the [Rect2i] is flat or empty.
</description>
</method>
- <method name="has_point">
+ <method name="has_point" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2i">
@@ -146,7 +146,7 @@
Returns [code]true[/code] if the [Rect2i] contains a point.
</description>
</method>
- <method name="intersection">
+ <method name="intersection" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -156,7 +156,7 @@
If the rectangles do not intersect, an empty [Rect2i] is returned.
</description>
</method>
- <method name="intersects">
+ <method name="intersects" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -166,7 +166,7 @@
If [code]include_borders[/code] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
</description>
</method>
- <method name="merge">
+ <method name="merge" qualifiers="const">
<return type="Rect2i">
</return>
<argument index="0" name="b" type="Rect2i">
@@ -200,7 +200,7 @@
Beginning corner. Typically has values lower than [member end].
</member>
<member name="size" type="Vector2i" setter="" getter="" default="Vector2i( 0, 0 )">
- Size from [member position] to [member end]. Typically all components are positive.
+ Size from [member position] to [member end]. Typically, all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member>
</members>
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 84e307b852..841d2bde72 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -490,7 +490,7 @@
</argument>
<argument index="2" name="data" type="PackedByteArray" default="PackedByteArray( )">
</argument>
- <argument index="3" name="arg3" type="bool" default="false">
+ <argument index="3" name="use_restart_indices" type="bool" default="false">
</argument>
<description>
</description>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index efc751bb94..638b0bb297 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -10,7 +10,7 @@
Resources are created using the [code]*_create[/code] functions.
All objects are drawn to a viewport. You can use the [Viewport] attached to the [SceneTree] or you can create one yourself with [method viewport_create]. When using a custom scenario or canvas, the scenario or canvas needs to be attached to the viewport using [method viewport_set_scenario] or [method viewport_attach_canvas].
In 3D, all visual objects must be associated with a scenario. The scenario is a visual representation of the world. If accessing the rendering server from a running game, the scenario can be accessed from the scene tree from any [Node3D] node with [method Node3D.get_world_3d]. Otherwise, a scenario can be created with [method scenario_create].
- Similarly in 2D, a canvas is needed to draw all canvas items.
+ Similarly, in 2D, a canvas is needed to draw all canvas items.
In 3D, all visible objects are comprised of a resource and an instance. A resource can be a mesh, a particle system, a light, or any other 3D object. In order to be visible resources must be attached to an instance using [method instance_set_base]. The instance must also be attached to the scenario using [method instance_set_scenario] in order to be visible.
In 2D, all visible objects are some form of canvas item. In order to be visible, a canvas item needs to be the child of a canvas attached to a viewport, or it needs to be the child of another canvas item that is eventually attached to the canvas.
</description>
@@ -1292,7 +1292,7 @@
<argument index="1" name="margin" type="float">
</argument>
<description>
- Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
+ Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you to avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
</description>
</method>
<method name="instance_set_layer_mask">
@@ -1317,7 +1317,7 @@
Sets the scenario that the instance is in. The scenario is the 3D world that the objects will be displayed in.
</description>
</method>
- <method name="instance_set_surface_material">
+ <method name="instance_set_surface_override_material">
<return type="void">
</return>
<argument index="0" name="instance" type="RID">
@@ -1327,7 +1327,7 @@
<argument index="2" name="material" type="RID">
</argument>
<description>
- Sets the material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_material].
+ Sets the override material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_override_material].
</description>
</method>
<method name="instance_set_transform">
@@ -1520,7 +1520,7 @@
<argument index="1" name="enabled" type="bool">
</argument>
<description>
- If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double sided shadows with [method instance_geometry_set_cast_shadows_setting]. Equivalent to [member Light3D.shadow_reverse_cull_face].
+ If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double-sided shadows with [method instance_geometry_set_cast_shadows_setting]. Equivalent to [member Light3D.shadow_reverse_cull_face].
</description>
</method>
<method name="light_set_shadow">
@@ -1802,7 +1802,7 @@
Updates a specific region of a vertex buffer for the specified surface. Warning: this function alters the vertex buffer directly with no safety mechanisms, you can easily corrupt your mesh.
</description>
</method>
- <method name="multimesh_allocate">
+ <method name="multimesh_allocate_data">
<return type="void">
</return>
<argument index="0" name="multimesh" type="RID">
@@ -1999,6 +1999,24 @@
Sets the number of instances visible at a given time. If -1, all instances that have been allocated are drawn. Equivalent to [member MultiMesh.visible_instance_count].
</description>
</method>
+ <method name="occluder_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="occluder_set_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="RID">
+ </argument>
+ <argument index="1" name="arg1" type="PackedVector3Array">
+ </argument>
+ <argument index="2" name="arg2" type="PackedInt32Array">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="omni_light_create">
<return type="RID">
</return>
@@ -2204,7 +2222,7 @@
<argument index="1" name="time" type="float">
</argument>
<description>
- Sets the preprocess time for the particles animation. This lets you delay starting an animation until after the particles have begun emitting. Equivalent to [member GPUParticles3D.preprocess].
+ Sets the preprocess time for the particles' animation. This lets you delay starting an animation until after the particles have begun emitting. Equivalent to [member GPUParticles3D.preprocess].
</description>
</method>
<method name="particles_set_process_material">
@@ -2412,6 +2430,16 @@
The scenario is the 3D world that all the visual instances exist in.
</description>
</method>
+ <method name="scenario_set_camera_effects">
+ <return type="void">
+ </return>
+ <argument index="0" name="scenario" type="RID">
+ </argument>
+ <argument index="1" name="effects" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="scenario_set_debug">
<return type="void">
</return>
@@ -2549,7 +2577,7 @@
Sets a shader's default texture. Overwrites the texture given by name.
</description>
</method>
- <method name="skeleton_allocate">
+ <method name="skeleton_allocate_data">
<return type="void">
</return>
<argument index="0" name="skeleton" type="RID">
@@ -2559,7 +2587,6 @@
<argument index="2" name="is_2d_skeleton" type="bool" default="false">
</argument>
<description>
- Allocates the GPU buffers for this skeleton.
</description>
</method>
<method name="skeleton_bone_get_transform" qualifiers="const">
@@ -2705,11 +2732,14 @@
<description>
Copies the viewport to a region of the screen specified by [code]rect[/code]. If [method viewport_set_render_direct_to_screen] is [code]true[/code], then the viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to.
For example, you can set the root viewport to not render at all with the following code:
- [codeblock]
+ FIXME: The method seems to be non-existent.
+ [codeblocks]
+ [gdscript]
func _ready():
get_viewport().set_attach_to_screen_rect(Rect2())
$Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))
- [/codeblock]
+ [/gdscript]
+ [/codeblocks]
Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For a further optimization see, [method viewport_set_render_direct_to_screen].
</description>
</method>
@@ -2895,6 +2925,22 @@
Sets the anti-aliasing mode. See [enum ViewportMSAA] for options.
</description>
</method>
+ <method name="viewport_set_occlusion_culling_build_quality">
+ <return type="void">
+ </return>
+ <argument index="0" name="quality" type="int" enum="RenderingServer.ViewportOcclusionCullingBuildQuality">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="viewport_set_occlusion_rays_per_thread">
+ <return type="void">
+ </return>
+ <argument index="0" name="rays_per_thread" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="viewport_set_parent_viewport">
<return type="void">
</return>
@@ -3000,6 +3046,16 @@
<description>
</description>
</method>
+ <method name="viewport_set_use_occlusion_culling">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="viewport_set_use_xr">
<return type="void">
</return>
@@ -3452,8 +3508,10 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_GI_BUFFER" value="17" enum="ViewportDebugDraw">
</constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_OCCLUDERS" value="23" enum="ViewportDebugDraw">
+ </constant>
<constant name="SKY_MODE_QUALITY" value="1" enum="SkyMode">
- Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant Sky.PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/quality/reflections/ggx_samples].
+ Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant Sky.PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/reflections/sky_reflections/ggx_samples].
</constant>
<constant name="SKY_MODE_REALTIME" value="3" enum="SkyMode">
Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
@@ -3604,6 +3662,12 @@
<constant name="SCENARIO_DEBUG_SHADELESS" value="3" enum="ScenarioDebugMode">
Draw all objects without shading. Equivalent to setting all objects shaders to [code]unshaded[/code].
</constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW" value="0" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM" value="1" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH" value="2" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
<constant name="INSTANCE_NONE" value="0" enum="InstanceType">
The instance does not have a type.
</constant>
@@ -3636,7 +3700,9 @@
<constant name="INSTANCE_LIGHTMAP" value="10" enum="InstanceType">
The instance is a lightmap.
</constant>
- <constant name="INSTANCE_MAX" value="11" enum="InstanceType">
+ <constant name="INSTANCE_OCCLUDER" value="11" enum="InstanceType">
+ </constant>
+ <constant name="INSTANCE_MAX" value="12" enum="InstanceType">
Represents the size of the [enum InstanceType] enum.
</constant>
<constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType">
@@ -3651,7 +3717,9 @@
<constant name="INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="2" enum="InstanceFlags">
When set, manually requests to draw geometry on next frame.
</constant>
- <constant name="INSTANCE_FLAG_MAX" value="3" enum="InstanceFlags">
+ <constant name="INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING" value="3" enum="InstanceFlags">
+ </constant>
+ <constant name="INSTANCE_FLAG_MAX" value="4" enum="InstanceFlags">
Represents the size of the [enum InstanceFlags] enum.
</constant>
<constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index ad0c438f98..9943f644cf 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -6,7 +6,7 @@
<description>
Godot loads resources in the editor or in exported games using ResourceFormatLoaders. They are queried automatically via the [ResourceLoader] singleton, or when a resource with internal dependencies is loaded. Each file type may load as a different resource type, so multiple ResourceFormatLoaders are registered in the engine.
Extending this class allows you to define your own loader. Be sure to respect the documented return types and values. You should give it a global class name with [code]class_name[/code] for it to be registered. Like built-in ResourceFormatLoaders, it will be called automatically when loading resources of its handled type(s). You may also implement a [ResourceFormatSaver].
- [b]Note:[/b] You can also extend [EditorImportPlugin] if the resource type you need exists but Godot is unable to load its format. Choosing one way over another depends if the format is suitable or not for the final exported game. For example, it's better to import [code].png[/code] textures as [code].stex[/code] ([StreamTexture2D]) first, so they can be loaded with better efficiency on the graphics card.
+ [b]Note:[/b] You can also extend [EditorImportPlugin] if the resource type you need exists but Godot is unable to load its format. Choosing one way over another depends on if the format is suitable or not for the final exported game. For example, it's better to import [code].png[/code] textures as [code].stex[/code] ([StreamTexture2D]) first, so they can be loaded with better efficiency on the graphics card.
</description>
<tutorials>
</tutorials>
@@ -57,8 +57,13 @@
</argument>
<argument index="1" name="original_path" type="String">
</argument>
+ <argument index="2" name="use_sub_threads" type="bool">
+ </argument>
+ <argument index="3" name="cache_mode" type="int">
+ </argument>
<description>
Loads a resource when the engine finds this loader to be compatible. If the loaded resource is the result of an import, [code]original_path[/code] will target the source file. Returns a [Resource] object on success, or an [enum Error] constant in case of failure.
+ The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
</description>
</method>
<method name="rename_dependencies" qualifiers="virtual">
@@ -75,5 +80,11 @@
</method>
</methods>
<constants>
+ <constant name="CACHE_MODE_IGNORE" value="0" enum="CacheMode">
+ </constant>
+ <constant name="CACHE_MODE_REUSE" value="1" enum="CacheMode">
+ </constant>
+ <constant name="CACHE_MODE_REPLACE" value="2" enum="CacheMode">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index c55a51c7ae..c81b21333f 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -58,13 +58,13 @@
</argument>
<argument index="1" name="type_hint" type="String" default="&quot;&quot;">
</argument>
- <argument index="2" name="no_cache" type="bool" default="false">
+ <argument index="2" name="cache_mode" type="int" enum="ResourceLoader.CacheMode" default="1">
</argument>
<description>
Loads a resource at the given [code]path[/code], caching the result for further access.
The registered [ResourceFormatLoader]s are queried sequentially to find the first one which can handle the file's extension, and then attempt loading. If loading fails, the remaining ResourceFormatLoaders are also attempted.
An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
- If [code]no_cache[/code] is [code]true[/code], the resource cache will be bypassed and the resource will be loaded anew. Otherwise, the cached resource will be returned if it exists.
+ The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
Returns an empty resource if no [ResourceFormatLoader] could handle the file.
GDScript has a simplified [method @GDScript.load] built-in method which can be used in most situations, leaving the use of [ResourceLoader] for more advanced scenarios.
</description>
@@ -127,5 +127,11 @@
<constant name="THREAD_LOAD_LOADED" value="3" enum="ThreadLoadStatus">
The resource was loaded successfully and can be accessed via [method load_threaded_get].
</constant>
+ <constant name="CACHE_MODE_IGNORE" value="0" enum="CacheMode">
+ </constant>
+ <constant name="CACHE_MODE_REUSE" value="1" enum="CacheMode">
+ </constant>
+ <constant name="CACHE_MODE_REPLACE" value="2" enum="CacheMode">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/RibbonTrailMesh.xml b/doc/classes/RibbonTrailMesh.xml
new file mode 100644
index 0000000000..771f2e444b
--- /dev/null
+++ b/doc/classes/RibbonTrailMesh.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RibbonTrailMesh" inherits="PrimitiveMesh" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve" type="Curve" setter="set_curve" getter="get_curve">
+ </member>
+ <member name="section_length" type="float" setter="set_section_length" getter="get_section_length" default="0.2">
+ </member>
+ <member name="section_segments" type="int" setter="set_section_segments" getter="get_section_segments" default="3">
+ </member>
+ <member name="sections" type="int" setter="set_sections" getter="get_sections" default="5">
+ </member>
+ <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RibbonTrailMesh.Shape" default="1">
+ </member>
+ <member name="size" type="float" setter="set_size" getter="get_size" default="1.0">
+ </member>
+ </members>
+ <constants>
+ <constant name="SHAPE_FLAT" value="0" enum="Shape">
+ </constant>
+ <constant name="SHAPE_CROSS" value="1" enum="Shape">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/RichTextEffect.xml b/doc/classes/RichTextEffect.xml
index 726b26fbc7..edab35f162 100644
--- a/doc/classes/RichTextEffect.xml
+++ b/doc/classes/RichTextEffect.xml
@@ -6,10 +6,16 @@
<description>
A custom effect for use with [RichTextLabel].
[b]Note:[/b] For a [RichTextEffect] to be usable, a BBCode tag must be defined as a member variable called [code]bbcode[/code] in the script.
- [codeblock]
+ [codeblocks]
+ [gdscript]
# The RichTextEffect will be usable like this: `[example]Some text[/example]`
var bbcode = "example"
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ // The RichTextEffect will be usable like this: `[example]Some text[/example]`
+ public string bbcode = "example";
+ [/csharp]
+ [/codeblocks]
[b]Note:[/b] As soon as a [RichTextLabel] contains at least one [RichTextEffect], it will continuously process the effect unless the project is paused. This may impact battery life negatively.
</description>
<tutorials>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 35eae32c7b..7ca70f5a7a 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -80,6 +80,27 @@
Returns the total number of paragraphs (newlines or [code]p[/code] tags in the tag stack's text tags). Considers wrapped text as one paragraph.
</description>
</method>
+ <method name="get_selected_text" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the current selection text. Does not include BBCodes.
+ </description>
+ </method>
+ <method name="get_selection_from" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the current selection first character index if a selection is active, [code]-1[/code] otherwise. Does not include BBCodes.
+ </description>
+ </method>
+ <method name="get_selection_to" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the current selection last character index if a selection is active, [code]-1[/code] otherwise. Does not include BBCodes.
+ </description>
+ </method>
<method name="get_total_character_count" qualifiers="const">
<return type="int">
</return>
@@ -597,6 +618,9 @@
<theme_item name="focus" type="StyleBox">
The background The background used when the [RichTextLabel] is focused.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The default tint of text outline.
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )">
The color of selected text, used when [member selection_enabled] is [code]true[/code].
</theme_item>
@@ -627,6 +651,9 @@
<theme_item name="normal_font_size" type="int">
The default text font size.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="selection_color" type="Color" default="Color( 0.1, 0.1, 1, 0.8 )">
The color of the selection box.
</theme_item>
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 6b27c77f26..ed375a8b1e 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -4,7 +4,7 @@
A body that is controlled by the 2D physics engine.
</brief_description>
<description>
- This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
+ This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
[b]Note:[/b] You should not change a RigidBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime.
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index cfe6e4f738..06800082cb 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
As one of the most important classes, the [SceneTree] manages the hierarchy of nodes in a scene as well as scenes themselves. Nodes can be added, retrieved and removed. The whole scene tree (and thus the current scene) can be paused. Scenes can be loaded, switched and reloaded.
- You can also use the [SceneTree] to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. a "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once.
+ You can also use the [SceneTree] to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. an "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once.
[SceneTree] is the default [MainLoop] implementation used by scenes, and is thus in charge of the game loop.
</description>
<tutorials>
@@ -21,7 +21,8 @@
<argument index="1" name="method" type="StringName">
</argument>
<description>
- Calls [code]method[/code] on each member of the given group.
+ Calls [code]method[/code] on each member of the given group. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
+ [b]Note:[/b] [method call_group] will always call methods with an one-frame delay, in a way similar to [method Object.call_deferred]. To call methods immediately, use [method call_group_flags] with the [constant GROUP_CALL_REALTIME] flag.
</description>
</method>
<method name="call_group_flags" qualifiers="vararg">
@@ -34,7 +35,8 @@
<argument index="2" name="method" type="StringName">
</argument>
<description>
- Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags].
+ Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
+ [b]Note:[/b] Group call flags are used to control the method calling behavior. If the [constant GROUP_CALL_REALTIME] flag is present in the [code]flags[/code] argument, methods will be called immediately. If this flag isn't present in [code]flags[/code], methods will be called with a one-frame delay in a way similar to [method call_group].
</description>
</method>
<method name="change_scene">
@@ -64,20 +66,38 @@
</return>
<argument index="0" name="time_sec" type="float">
</argument>
- <argument index="1" name="pause_mode_process" type="bool" default="true">
+ <argument index="1" name="process_always" type="bool" default="true">
</argument>
<description>
- Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [code]pause_mode_process[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
Commonly used to create a one-shot delay timer as in the following example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
func some_function():
print("start")
yield(get_tree().create_timer(1.0), "timeout")
print("end")
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public async void SomeFunction()
+ {
+ GD.Print("start");
+ await ToSignal(GetTree().CreateTimer(1.0f), "timeout");
+ GD.Print("end");
+ }
+ [/csharp]
+ [/codeblocks]
The timer will be automatically freed after its time elapses.
</description>
</method>
+ <method name="get_first_node_in_group">
+ <return type="Node">
+ </return>
+ <argument index="0" name="group" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="get_frame" qualifiers="const">
<return type="int">
</return>
@@ -181,10 +201,12 @@
<method name="quit">
<return type="void">
</return>
- <argument index="0" name="exit_code" type="int" default="-1">
+ <argument index="0" name="exit_code" type="int" default="0">
</argument>
<description>
- Quits the application at the end of the current iteration. A process [code]exit_code[/code] can optionally be passed as an argument. If this argument is [code]0[/code] or greater, it will override the [member OS.exit_code] defined before quitting the application.
+ Quits the application at the end of the current iteration. Argument [code]exit_code[/code] can optionally be given (defaulting to 0) to customize the exit status code.
+ By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error.
+ For portability reasons, the exit code should be set between 0 and 125 (inclusive).
</description>
</method>
<method name="reload_current_scene">
@@ -361,6 +383,11 @@
Emitted whenever the [SceneTree] hierarchy changed (children being moved or renamed, etc.).
</description>
</signal>
+ <signal name="tree_process_mode_changed">
+ <description>
+ This signal is only emitted in the editor, it allows the editor to update the visibility of disabled nodes. Emitted whenever any node's [member Node.process_mode] is changed.
+ </description>
+ </signal>
</signals>
<constants>
<constant name="GROUP_CALL_DEFAULT" value="0" enum="GroupCallFlags">
diff --git a/doc/classes/SceneTreeTimer.xml b/doc/classes/SceneTreeTimer.xml
index a4a83fa65b..b223bf6821 100644
--- a/doc/classes/SceneTreeTimer.xml
+++ b/doc/classes/SceneTreeTimer.xml
@@ -6,12 +6,22 @@
<description>
A one-shot timer managed by the scene tree, which emits [signal timeout] on completion. See also [method SceneTree.create_timer].
As opposed to [Timer], it does not require the instantiation of a node. Commonly used to create a one-shot delay timer as in the following example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
func some_function():
print("Timer started.")
yield(get_tree().create_timer(1.0), "timeout")
print("Timer ended.")
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public async void SomeFunction()
+ {
+ GD.Print("Timer started.");
+ await ToSignal(GetTree().CreateTimer(1.0f), "timeout");
+ GD.Print("Timer ended.");
+ }
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml
index aa60ecb12b..7185213c44 100644
--- a/doc/classes/ScriptCreateDialog.xml
+++ b/doc/classes/ScriptCreateDialog.xml
@@ -5,12 +5,24 @@
</brief_description>
<description>
The [ScriptCreateDialog] creates script files according to a given template for a given scripting language. The standard use is to configure its fields prior to calling one of the [method Window.popup] methods.
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _ready():
- dialog.config("Node", "res://new_node.gd") # For in-engine types
- dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types
+ var dialog = ScriptCreateDialog.new();
+ dialog.config("Node", "res://new_node.gd") # For in-engine types.
+ dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types.
dialog.popup_centered()
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Ready()
+ {
+ var dialog = new ScriptCreateDialog();
+ dialog.Config("Node", "res://NewNode.cs"); // For in-engine types.
+ dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types.
+ dialog.PopupCentered();
+ }
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index 2d8bb5d051..f8b749aebf 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -13,7 +13,8 @@
</methods>
<members>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
- The collision margin for the shape.
+ The collision margin for the shape. Used in Bullet Physics only.
+ Collision margins allow collision detection to be more efficient by adding an extra shell around shapes. Collision algorithms are more expensive when objects overlap by more than their margin, so a higher value for margins is better for performance, at the cost of accuracy around edges as it makes them less sharp.
</member>
</members>
<constants>
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index b7a2258fc1..84efc974c0 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -57,42 +57,42 @@
Disconnects this signal from the specified [Callable].
</description>
</method>
- <method name="emit" qualifiers="vararg">
+ <method name="emit" qualifiers="vararg const">
<return type="void">
</return>
<description>
Emits this signal to all connected objects.
</description>
</method>
- <method name="get_connections">
+ <method name="get_connections" qualifiers="const">
<return type="Array">
</return>
<description>
Returns the list of [Callable]s connected to this signal.
</description>
</method>
- <method name="get_name">
+ <method name="get_name" qualifiers="const">
<return type="StringName">
</return>
<description>
Returns the name of this signal.
</description>
</method>
- <method name="get_object">
+ <method name="get_object" qualifiers="const">
<return type="Object">
</return>
<description>
Returns the object emitting this signal.
</description>
</method>
- <method name="get_object_id">
+ <method name="get_object_id" qualifiers="const">
<return type="int">
</return>
<description>
Returns the ID of the object emitting this signal (see [method Object.get_instance_id]).
</description>
</method>
- <method name="is_connected">
+ <method name="is_connected" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="callable" type="Callable">
@@ -101,7 +101,7 @@
Returns [code]true[/code] if the specified [Callable] is connected to this signal.
</description>
</method>
- <method name="is_null">
+ <method name="is_null" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index fe2cc1f5ad..c6dd6fb142 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -245,6 +245,16 @@
[b]Note[/b]: The pose transform needs to be in bone space. Use [method world_transform_to_bone_transform] to convert a world transform, like one you can get from a [Node3D], to bone space.
</description>
</method>
+ <method name="set_bone_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_bone_parent">
<return type="void">
</return>
@@ -297,7 +307,7 @@
<argument index="0" name="bone_idx" type="int">
</argument>
<description>
- Unparents the bone at [code]bone_idx[/code] and sets its rest position to that of it's parent prior to being reset.
+ Unparents the bone at [code]bone_idx[/code] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
<method name="world_transform_to_bone_transform">
diff --git a/doc/classes/Sky.xml b/doc/classes/Sky.xml
index a77515b3e6..d9553a3be3 100644
--- a/doc/classes/Sky.xml
+++ b/doc/classes/Sky.xml
@@ -52,13 +52,13 @@
Automatically selects the appropriate process mode based on your sky shader. If your shader uses [code]TIME[/code] or [code]POSITION[/code], this will use [constant PROCESS_MODE_REALTIME]. If your shader uses any of the [code]LIGHT_*[/code] variables or any custom uniforms, this uses [constant PROCESS_MODE_INCREMENTAL]. Otherwise, this defaults to [constant PROCESS_MODE_QUALITY].
</constant>
<constant name="PROCESS_MODE_QUALITY" value="1" enum="ProcessMode">
- Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/quality/reflections/ggx_samples].
+ Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/reflections/sky_reflections/ggx_samples].
</constant>
<constant name="PROCESS_MODE_INCREMENTAL" value="2" enum="ProcessMode">
- Uses the same high quality importance sampling to process the radiance map as [constant PROCESS_MODE_QUALITY], but updates over several frames. The number of frames is determined by [member ProjectSettings.rendering/quality/reflections/roughness_layers]. Use this when you need highest quality radiance maps, but have a sky that updates slowly.
+ Uses the same high quality importance sampling to process the radiance map as [constant PROCESS_MODE_QUALITY], but updates over several frames. The number of frames is determined by [member ProjectSettings.rendering/reflections/sky_reflections/roughness_layers]. Use this when you need highest quality radiance maps, but have a sky that updates slowly.
</constant>
<constant name="PROCESS_MODE_REALTIME" value="3" enum="ProcessMode">
- Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times. If you need better quality, but still need to update the sky every frame, consider turning on [member ProjectSettings.rendering/quality/reflections/fast_filter_high_quality].
+ Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times. If you need better quality, but still need to update the sky every frame, consider turning on [member ProjectSettings.rendering/reflections/sky_reflections/fast_filter_high_quality].
[b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so [member radiance_size] must be set to [constant RADIANCE_SIZE_256].
</constant>
</constants>
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index d3ab955570..7999ad774d 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -44,6 +44,12 @@
Returns an individual bit on the collision mask.
</description>
</method>
+ <method name="get_physics_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -77,8 +83,6 @@
</method>
</methods>
<members>
- <member name="areaAngular_stiffness" type="float" setter="set_areaAngular_stiffness" getter="get_areaAngular_stiffness" default="0.5">
- </member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this SoftBody3D is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
@@ -96,8 +100,6 @@
<member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath(&quot;&quot;)">
[NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping.
</member>
- <member name="pose_matching_coefficient" type="float" setter="set_pose_matching_coefficient" getter="get_pose_matching_coefficient" default="0.0">
- </member>
<member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0">
</member>
<member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
@@ -109,8 +111,6 @@
<member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="1.0">
The SoftBody3D's mass.
</member>
- <member name="volume_stiffness" type="float" setter="set_volume_stiffness" getter="get_volume_stiffness" default="0.5">
- </member>
</members>
<constants>
</constants>
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index e674ceb57e..7e2481f458 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -6,15 +6,25 @@
<description>
SpinBox is a numerical input text field. It allows entering integers and floats.
[b]Example:[/b]
- [codeblock]
+ [codeblocks]
+ [gdscript]
var spin_box = SpinBox.new()
add_child(spin_box)
var line_edit = spin_box.get_line_edit()
line_edit.context_menu_enabled = false
spin_box.align = LineEdit.ALIGN_RIGHT
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ var spinBox = new SpinBox();
+ AddChild(spinBox);
+ var lineEdit = spinBox.GetLineEdit();
+ lineEdit.ContextMenuEnabled = false;
+ spinBox.Align = LineEdit.AlignEnum.Right;
+ [/csharp]
+ [/codeblocks]
The above code will create a [SpinBox], disable context menu on it and set the text alignment to right.
See [Range] class for more options over the [SpinBox].
+ [b]Note:[/b] [SpinBox] relies on an underlying [LineEdit] node. To theme a [SpinBox]'s background, add theme items for [LineEdit] and customize them.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index c56596423d..617ad3a371 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -15,12 +15,29 @@
</return>
<description>
Returns a [Rect2] representing the Sprite2D's boundary in local coordinates. Can be used to detect if the Sprite2D was clicked. Example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _input(event):
- if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
+ if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)):
print("A click!")
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Input(InputEvent inputEvent)
+ {
+ if (inputEvent is InputEventMouseButton inputEventMouse)
+ {
+ if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == (int)ButtonList.Left)
+ {
+ if (GetRect().HasPoint(ToLocal(inputEventMouse.Position)))
+ {
+ GD.Print("A click!");
+ }
+ }
+ }
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="is_pixel_opaque" qualifiers="const">
@@ -56,11 +73,11 @@
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
The texture's drawing offset.
</member>
- <member name="region_enabled" type="bool" setter="set_region" getter="is_region" default="false">
+ <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false">
If [code]true[/code], texture is cut from a larger atlas texture. See [member region_rect].
</member>
- <member name="region_filter_clip" type="bool" setter="set_region_filter_clip" getter="is_region_filter_clip_enabled" default="false">
- If [code]true[/code], the outermost pixels get blurred out.
+ <member name="region_filter_clip_enabled" type="bool" setter="set_region_filter_clip_enabled" getter="is_region_filter_clip_enabled" default="false">
+ If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code].
</member>
<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )">
The region of the atlas texture to display. [member region_enabled] must be [code]true[/code].
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index f9b947fa3d..658fd1a4f2 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -20,7 +20,7 @@
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
The number of columns in the sprite sheet.
</member>
- <member name="region_enabled" type="bool" setter="set_region" getter="is_region" default="false">
+ <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false">
If [code]true[/code], texture will be cut from a larger atlas texture. See [member region_rect].
</member>
<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )">
diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml
index 44b08408c1..06b9c2b042 100644
--- a/doc/classes/SpriteBase3D.xml
+++ b/doc/classes/SpriteBase3D.xml
@@ -73,7 +73,7 @@
The texture's drawing offset.
</member>
<member name="opacity" type="float" setter="set_opacity" getter="get_opacity" default="1.0">
- The objects visibility on a scale from [code]0[/code] fully invisible to [code]1[/code] fully visible.
+ The objects' visibility on a scale from [code]0[/code] fully invisible to [code]1[/code] fully visible.
</member>
<member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.01">
The size of one pixel's width on the sprite to scale it in 3D.
@@ -102,7 +102,7 @@
This mode performs standard alpha blending. It can display translucent areas, but transparency sorting issues may be visible when multiple transparent materials are overlapping.
</constant>
<constant name="ALPHA_CUT_DISCARD" value="1" enum="AlphaCutMode">
- This mode only allows fully transparent or fully opaque pixels. Harsh edges will be visible unless some form of screen-space antialiasing is enabled (see [member ProjectSettings.rendering/quality/screen_filters/screen_space_aa]). On the bright side, this mode doesn't suffer from transparency sorting issues when multiple transparent materials are overlapping. This mode is also known as [i]alpha testing[/i] or [i]1-bit transparency[/i].
+ This mode only allows fully transparent or fully opaque pixels. Harsh edges will be visible unless some form of screen-space antialiasing is enabled (see [member ProjectSettings.rendering/anti_aliasing/quality/screen_space_aa]). On the bright side, this mode doesn't suffer from transparency sorting issues when multiple transparent materials are overlapping. This mode is also known as [i]alpha testing[/i] or [i]1-bit transparency[/i].
</constant>
<constant name="ALPHA_CUT_OPAQUE_PREPASS" value="2" enum="AlphaCutMode">
This mode draws fully opaque pixels in the depth prepass. This is slower than [constant ALPHA_CUT_DISABLED] or [constant ALPHA_CUT_DISCARD], but it allows displaying translucent areas and smooth edges while using proper sorting.
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index a73d3c8212..a1b858acf6 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -212,9 +212,14 @@
<description>
Puts a zero-terminated ASCII string into the stream prepended by a 32-bit unsigned integer representing its size.
Note: To put an ASCII string without prepending its size, you can use [method put_data]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
put_data("Hello world".to_ascii())
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ PutData("Hello World".ToAscii());
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="put_u16">
@@ -261,9 +266,14 @@
<description>
Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits unsigned integer representing its size.
Note: To put an UTF-8 string without prepending its size, you can use [method put_data]:
- [codeblock]
+ [codeblocks]
+ [gdscript]
put_data("Hello world".to_utf8())
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ PutData("Hello World".ToUTF8());
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="put_var">
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index bb85d94bf9..7b7c1d7426 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -9,6 +9,18 @@
<tutorials>
</tutorials>
<methods>
+ <method name="bind">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <argument index="1" name="host" type="String" default="&quot;*&quot;">
+ </argument>
+ <description>
+ Opens the TCP socket, and binds it to the specified local address.
+ This method is generally not needed, and only used to force the subsequent call to [method connect_to_host] to use the specified [code]host[/code] and [code]port[/code] as source address. This can be desired in some NAT punchthrough techniques, or when forcing the source network interface.
+ </description>
+ </method>
<method name="connect_to_host">
<return type="int" enum="Error">
</return>
@@ -17,7 +29,7 @@
<argument index="1" name="port" type="int">
</argument>
<description>
- Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success or [constant FAILED] on failure.
+ Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success.
</description>
</method>
<method name="disconnect_from_host">
@@ -41,6 +53,13 @@
Returns the port of this peer.
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_status">
<return type="int" enum="StreamPeerTCP.Status">
</return>
@@ -61,8 +80,8 @@
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Disables Nagle's algorithm to improve latency for small packets.
- [b]Note:[/b] For applications that send large packets or need to transfer a lot of data, this can decrease the total available bandwidth.
+ If [code]enabled[/code] is [code]true[/code], packets will be sent immediately. If [code]enabled[/code] is [code]false[/code] (the default), packet transfers will be delayed and combined using [url=https://en.wikipedia.org/wiki/Nagle%27s_algorithm]Nagle's algorithm[/url].
+ [b]Note:[/b] It's recommended to leave this disabled for applications that send large packets or need to transfer a lot of data, as enabling this can decrease the total available bandwidth.
</description>
</method>
</methods>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index c03f6357ab..416438e648 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -44,7 +44,7 @@
Constructs a new String from the given [StringName].
</description>
</method>
- <method name="begins_with">
+ <method name="begins_with" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -53,14 +53,14 @@
Returns [code]true[/code] if the string begins with the given string.
</description>
</method>
- <method name="bigrams">
+ <method name="bigrams" qualifiers="const">
<return type="PackedStringArray">
</return>
<description>
Returns the bigrams (pairs of consecutive letters) of this string.
</description>
</method>
- <method name="bin_to_int">
+ <method name="bin_to_int" qualifiers="const">
<return type="int">
</return>
<description>
@@ -77,14 +77,14 @@
[/codeblocks]
</description>
</method>
- <method name="c_escape">
+ <method name="c_escape" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with special characters escaped using the C language standard.
</description>
</method>
- <method name="c_unescape">
+ <method name="c_unescape" qualifiers="const">
<return type="String">
</return>
<description>
@@ -92,14 +92,14 @@
[b]Note:[/b] Unlike the GDScript parser, this method doesn't support the [code]\uXXXX[/code] escape sequence.
</description>
</method>
- <method name="capitalize">
+ <method name="capitalize" qualifiers="const">
<return type="String">
</return>
<description>
Changes the case of some letters. Replaces underscores with spaces, adds spaces before in-word uppercase characters, converts all letters to lowercase, then capitalizes the first letter and every letter following a space character. For [code]capitalize camelCase mixed_with_underscores[/code], it will return [code]Capitalize Camel Case Mixed With Underscores[/code].
</description>
</method>
- <method name="casecmp_to">
+ <method name="casecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -111,7 +111,15 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
- <method name="count">
+ <method name="chr" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="char" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -124,7 +132,7 @@
Returns the number of occurrences of substring [code]what[/code] between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
</description>
</method>
- <method name="countn">
+ <method name="countn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -137,14 +145,14 @@
Returns the number of occurrences of substring [code]what[/code] (ignoring case) between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
</description>
</method>
- <method name="dedent">
+ <method name="dedent" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with indentation (leading tabs and spaces) removed.
</description>
</method>
- <method name="ends_with">
+ <method name="ends_with" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -153,7 +161,7 @@
Returns [code]true[/code] if the string ends with the given string.
</description>
</method>
- <method name="find">
+ <method name="find" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -163,14 +171,18 @@
<description>
Returns the index of the [b]first[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
[b]Note:[/b] If you just want to know whether a string contains a substring, use the [code]in[/code] operator as follows:
- [codeblock]
- # Will evaluate to `false`.
- if "i" in "team":
- pass
- [/codeblock]
+ [codeblocks]
+ [gdscript]
+ print("i" in "team") # Will print `false`.
+ [/gdscript]
+ [csharp]
+ // C# has no in operator, but we can use `Contains()`.
+ GD.Print("team".Contains("i")); // Will print `false`.
+ [/csharp]
+ [/codeblocks]
</description>
</method>
- <method name="findn">
+ <method name="findn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -181,7 +193,7 @@
Returns the index of the [b]first[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
</description>
</method>
- <method name="format">
+ <method name="format" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="values" type="Variant">
@@ -192,42 +204,42 @@
Formats the string by replacing all occurrences of [code]placeholder[/code] with [code]values[/code].
</description>
</method>
- <method name="get_base_dir">
+ <method name="get_base_dir" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the base directory name.
</description>
</method>
- <method name="get_basename">
+ <method name="get_basename" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the full file path without the extension.
</description>
</method>
- <method name="get_extension">
+ <method name="get_extension" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the extension.
</description>
</method>
- <method name="get_file">
+ <method name="get_file" qualifiers="const">
<return type="String">
</return>
<description>
If the string is a valid file path, returns the filename.
</description>
</method>
- <method name="hash">
+ <method name="hash" qualifiers="const">
<return type="int">
</return>
<description>
Hashes the string and returns a 32-bit integer.
</description>
</method>
- <method name="hex_to_int">
+ <method name="hex_to_int" qualifiers="const">
<return type="int">
</return>
<description>
@@ -244,7 +256,15 @@
[/codeblocks]
</description>
</method>
- <method name="insert">
+ <method name="humanize_size" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="size" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="insert" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -255,28 +275,28 @@
Returns a copy of the string with the substring [code]what[/code] inserted at the given position.
</description>
</method>
- <method name="is_abs_path">
+ <method name="is_abs_path" qualifiers="const">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, returns [code]true[/code] if the path is absolute.
</description>
</method>
- <method name="is_empty">
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the length of the string equals [code]0[/code].
</description>
</method>
- <method name="is_rel_path">
+ <method name="is_rel_path" qualifiers="const">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, returns [code]true[/code] if the path is relative.
</description>
</method>
- <method name="is_subsequence_of">
+ <method name="is_subsequence_of" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -285,7 +305,7 @@
Returns [code]true[/code] if this string is a subsequence of the given string.
</description>
</method>
- <method name="is_subsequence_ofi">
+ <method name="is_subsequence_ofi" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -294,7 +314,7 @@
Returns [code]true[/code] if this string is a subsequence of the given string, without considering case.
</description>
</method>
- <method name="is_valid_filename">
+ <method name="is_valid_filename" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -302,14 +322,14 @@
[code]: / \ ? * " | % &lt; &gt;[/code]
</description>
</method>
- <method name="is_valid_float">
+ <method name="is_valid_float" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid float.
</description>
</method>
- <method name="is_valid_hex_number">
+ <method name="is_valid_hex_number" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="with_prefix" type="bool" default="false">
@@ -318,35 +338,35 @@
Returns [code]true[/code] if this string contains a valid hexadecimal number. If [code]with_prefix[/code] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
</description>
</method>
- <method name="is_valid_html_color">
+ <method name="is_valid_html_color" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid color in hexadecimal HTML notation. Other HTML notations such as named colors or [code]hsl()[/code] colors aren't considered valid by this method and will return [code]false[/code].
</description>
</method>
- <method name="is_valid_identifier">
+ <method name="is_valid_identifier" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string is a valid identifier. A valid identifier may contain only letters, digits and underscores ([code]_[/code]) and the first character may not be a digit.
</description>
</method>
- <method name="is_valid_integer">
+ <method name="is_valid_integer" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains a valid integer.
</description>
</method>
- <method name="is_valid_ip_address">
+ <method name="is_valid_ip_address" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if this string contains only a well-formatted IPv4 or IPv6 address. This method considers [url=https://en.wikipedia.org/wiki/Reserved_IP_addresses]reserved IP addresses[/url] such as [code]0.0.0.0[/code] as valid.
</description>
</method>
- <method name="join">
+ <method name="join" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="parts" type="PackedStringArray">
@@ -354,19 +374,24 @@
<description>
Return a [String] which is the concatenation of the [code]parts[/code]. The separator between elements is the string providing this method.
Example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
print(", ".join(["One", "Two", "Three", "Four"]))
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ GD.Print(String.Join(",", new string[] {"One", "Two", "Three", "Four"}));
+ [/csharp]
+ [/codeblocks]
</description>
</method>
- <method name="json_escape">
+ <method name="json_escape" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string with special characters escaped using the JSON standard.
</description>
</method>
- <method name="left">
+ <method name="left" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -375,14 +400,14 @@
Returns a number of characters from the left of the string.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="int">
</return>
<description>
Returns the string's amount of characters.
</description>
</method>
- <method name="lpad">
+ <method name="lpad" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="min_length" type="int">
@@ -393,7 +418,7 @@
Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the left of the string.
</description>
</method>
- <method name="lstrip">
+ <method name="lstrip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="chars" type="String">
@@ -403,7 +428,7 @@
[b]Note:[/b] The [code]chars[/code] is not a prefix. See [method trim_prefix] method that will remove a single prefix string rather than a set of characters.
</description>
</method>
- <method name="match">
+ <method name="match" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -412,7 +437,7 @@
Does a simple case-sensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]).
</description>
</method>
- <method name="matchn">
+ <method name="matchn" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -421,21 +446,21 @@
Does a simple case-insensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]).
</description>
</method>
- <method name="md5_buffer">
+ <method name="md5_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the MD5 hash of the string as an array of bytes.
</description>
</method>
- <method name="md5_text">
+ <method name="md5_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the MD5 hash of the string as a string.
</description>
</method>
- <method name="naturalnocasecmp_to">
+ <method name="naturalnocasecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -448,7 +473,7 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method casecmp_to].
</description>
</method>
- <method name="nocasecmp_to">
+ <method name="nocasecmp_to" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -460,6 +485,24 @@
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
+ <method name="num" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="number" type="float">
+ </argument>
+ <argument index="1" name="decimals" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="num_scientific" qualifiers="static">
+ <return type="String">
+ </return>
+ <argument index="0" name="number" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
@@ -540,7 +583,7 @@
<description>
</description>
</method>
- <method name="pad_decimals">
+ <method name="pad_decimals" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -549,7 +592,7 @@
Formats a number to have an exact number of [code]digits[/code] after the decimal point.
</description>
</method>
- <method name="pad_zeros">
+ <method name="pad_zeros" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -558,7 +601,7 @@
Formats a number to have an exact number of [code]digits[/code] before the decimal point.
</description>
</method>
- <method name="plus_file">
+ <method name="plus_file" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="file" type="String">
@@ -567,7 +610,7 @@
If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
</description>
</method>
- <method name="repeat">
+ <method name="repeat" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="count" type="int">
@@ -576,7 +619,7 @@
Returns original string repeated a number of times. The number of repetitions is given by the argument.
</description>
</method>
- <method name="replace">
+ <method name="replace" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -587,7 +630,7 @@
Replaces occurrences of a case-sensitive substring with the given one inside the string.
</description>
</method>
- <method name="replacen">
+ <method name="replacen" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -598,7 +641,7 @@
Replaces occurrences of a case-insensitive substring with the given one inside the string.
</description>
</method>
- <method name="rfind">
+ <method name="rfind" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -609,7 +652,7 @@
Returns the index of the [b]last[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
- <method name="rfindn">
+ <method name="rfindn" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -620,7 +663,7 @@
Returns the index of the [b]last[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
- <method name="right">
+ <method name="right" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="position" type="int">
@@ -629,7 +672,7 @@
Returns the right side of the string from a given position.
</description>
</method>
- <method name="rpad">
+ <method name="rpad" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="min_length" type="int">
@@ -640,7 +683,7 @@
Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the right of the string.
</description>
</method>
- <method name="rsplit">
+ <method name="rsplit" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="delimiter" type="String">
@@ -654,16 +697,21 @@
The splits in the returned array are sorted in the same order as the original string, from left to right.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split].
Example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var some_string = "One,Two,Three,Four"
var some_array = some_string.rsplit(",", true, 1)
print(some_array.size()) # Prints 2
print(some_array[0]) # Prints "Four"
print(some_array[1]) # Prints "Three,Two,One"
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ // There is no Rsplit.
+ [/csharp]
+ [/codeblocks]
</description>
</method>
- <method name="rstrip">
+ <method name="rstrip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="chars" type="String">
@@ -673,35 +721,35 @@
[b]Note:[/b] The [code]chars[/code] is not a suffix. See [method trim_suffix] method that will remove a single suffix string rather than a set of characters.
</description>
</method>
- <method name="sha1_buffer">
+ <method name="sha1_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the SHA-1 hash of the string as an array of bytes.
</description>
</method>
- <method name="sha1_text">
+ <method name="sha1_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the SHA-1 hash of the string as a string.
</description>
</method>
- <method name="sha256_buffer">
+ <method name="sha256_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Returns the SHA-256 hash of the string as an array of bytes.
</description>
</method>
- <method name="sha256_text">
+ <method name="sha256_text" qualifiers="const">
<return type="String">
</return>
<description>
Returns the SHA-256 hash of the string as a string.
</description>
</method>
- <method name="similarity">
+ <method name="similarity" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="text" type="String">
@@ -710,7 +758,7 @@
Returns the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
</description>
</method>
- <method name="split">
+ <method name="split" qualifiers="const">
<return type="PackedStringArray">
</return>
<argument index="0" name="delimiter" type="String">
@@ -723,17 +771,25 @@
Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split.
Example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var some_string = "One,Two,Three,Four"
var some_array = some_string.split(",", true, 1)
print(some_array.size()) # Prints 2
- print(some_array[0]) # Prints "One"
- print(some_array[1]) # Prints "Two,Three,Four"
- [/codeblock]
+ print(some_array[0]) # Prints "Four"
+ print(some_array[1]) # Prints "Three,Two,One"
+ [/gdscript]
+ [csharp]
+ var someString = "One,Two,Three,Four";
+ var someArray = someString.Split(",", true); // This is as close as it gets to Godots API.
+ GD.Print(someArray[0]); // Prints "Four"
+ GD.Print(someArray[1]); // Prints "Three,Two,One"
+ [/csharp]
+ [/codeblocks]
If you need to split strings with more complex rules, use the [RegEx] class instead.
</description>
</method>
- <method name="split_floats">
+ <method name="split_floats" qualifiers="const">
<return type="PackedFloat32Array">
</return>
<argument index="0" name="delimiter" type="String">
@@ -745,7 +801,7 @@
For example, [code]"1,2.5,3"[/code] will return [code][1,2.5,3][/code] if split by [code]","[/code].
</description>
</method>
- <method name="strip_edges">
+ <method name="strip_edges" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="left" type="bool" default="true">
@@ -756,14 +812,14 @@
Returns a copy of the string stripped of any non-printable character (including tabulations, spaces and line breaks) at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
</description>
</method>
- <method name="strip_escapes">
+ <method name="strip_escapes" qualifiers="const">
<return type="String">
</return>
<description>
Returns a copy of the string stripped of any escape character. These include all non-printable control characters of the first page of the ASCII table (&lt; 32), such as tabulation ([code]\t[/code] in C) and newline ([code]\n[/code] and [code]\r[/code]) characters, but not spaces.
</description>
</method>
- <method name="substr">
+ <method name="substr" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="from" type="int">
@@ -774,63 +830,63 @@
Returns part of the string from the position [code]from[/code] with length [code]len[/code]. Argument [code]len[/code] is optional and using [code]-1[/code] will return remaining characters from given position.
</description>
</method>
- <method name="to_ascii_buffer">
+ <method name="to_ascii_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is a character array) to ASCII/Latin-1 encoded [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8_buffer], as this method assumes that all the characters in the String are ASCII/Latin-1 characters, unsupported characters are replaced with spaces.
</description>
</method>
- <method name="to_float">
+ <method name="to_float" qualifiers="const">
<return type="float">
</return>
<description>
Converts a string containing a decimal number into a [code]float[/code].
</description>
</method>
- <method name="to_int">
+ <method name="to_int" qualifiers="const">
<return type="int">
</return>
<description>
Converts a string containing an integer number into an [code]int[/code].
</description>
</method>
- <method name="to_lower">
+ <method name="to_lower" qualifiers="const">
<return type="String">
</return>
<description>
Returns the string converted to lowercase.
</description>
</method>
- <method name="to_upper">
+ <method name="to_upper" qualifiers="const">
<return type="String">
</return>
<description>
Returns the string converted to uppercase.
</description>
</method>
- <method name="to_utf16_buffer">
+ <method name="to_utf16_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-16 encoded [PackedByteArray] (which is an array of bytes).
</description>
</method>
- <method name="to_utf32_buffer">
+ <method name="to_utf32_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-32 encoded [PackedByteArray] (which is an array of bytes).
</description>
</method>
- <method name="to_utf8_buffer">
+ <method name="to_utf8_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
<description>
Converts the String (which is an array of characters) to UTF-8 encode [PackedByteArray] (which is an array of bytes). The conversion is a bit slower than [method to_ascii_buffer], but supports all UTF-8 characters. Therefore, you should prefer this function over [method to_ascii_buffer].
</description>
</method>
- <method name="trim_prefix">
+ <method name="trim_prefix" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="prefix" type="String">
@@ -839,7 +895,7 @@
Removes a given string from the start if it starts with it or leaves the string unchanged.
</description>
</method>
- <method name="trim_suffix">
+ <method name="trim_suffix" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="suffix" type="String">
@@ -848,7 +904,7 @@
Removes a given string from the end if it ends with it or leaves the string unchanged.
</description>
</method>
- <method name="unicode_at">
+ <method name="unicode_at" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="at" type="int">
@@ -857,7 +913,7 @@
Returns the character code at position [code]at[/code].
</description>
</method>
- <method name="uri_decode">
+ <method name="uri_decode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -872,7 +928,7 @@
[/codeblocks]
</description>
</method>
- <method name="uri_encode">
+ <method name="uri_encode" qualifiers="const">
<return type="String">
</return>
<description>
@@ -887,7 +943,14 @@
[/codeblocks]
</description>
</method>
- <method name="xml_escape">
+ <method name="validate_node_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Removes any characters from the string that are prohibited in [Node] names ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code]).
+ </description>
+ </method>
+ <method name="xml_escape" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="escape_quotes" type="bool" default="false">
@@ -896,7 +959,7 @@
Returns a copy of the string with special characters escaped using the XML standard. If [code]escape_quotes[/code] is [code]true[/code], the single quote ([code]'[/code]) and double quote ([code]"[/code]) characters are also escaped.
</description>
</method>
- <method name="xml_unescape">
+ <method name="xml_unescape" qualifiers="const">
<return type="String">
</return>
<description>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index af0074f080..be32f6a234 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -4,7 +4,7 @@
An optimized string type for unique names.
</brief_description>
<description>
- [StringName]s are immutable strings designed for general-purpose represention of unique names. [StringName] ensures that only one instance of a given name exists (so two [StringName]s with the same value are the same object). Comparing them is much faster than with regular [String]s, because only the pointers are compared, not the whole strings.
+ [StringName]s are immutable strings designed for general-purpose representation of unique names. [StringName] ensures that only one instance of a given name exists (so two [StringName]s with the same value are the same object). Comparing them is much faster than with regular [String]s, because only the pointers are compared, not the whole strings.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index 13ea7df294..d66ae210ec 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -4,12 +4,12 @@
Customizable [StyleBox] with a given set of parameters (no texture required).
</brief_description>
<description>
- This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. Those properties are customizable:
+ This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. The following properties are customizable:
- Color
- Border width (individual width for each border)
- Rounded corners (individual radius for each corner)
- Shadow (with blur and offset)
- Setting corner radius to high values is allowed. As soon as corners would overlap, the stylebox will switch to a relative system. Example:
+ Setting corner radius to high values is allowed. As soon as corners overlap, the stylebox will switch to a relative system. Example:
[codeblock]
height = 30
corner_radius_top_left = 50
@@ -178,8 +178,8 @@
Border width for the top border.
</member>
<member name="corner_detail" type="int" setter="set_corner_detail" getter="get_corner_detail" default="8">
- This sets the amount of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account.
- For corner radii smaller than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii smaller than 30, values between [code]8[/code] and [code]12[/code] should be enough.
+ This sets the number of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account.
+ For corner radii less than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii less than 30, values between [code]8[/code] and [code]12[/code] should be enough.
A corner detail of [code]1[/code] will result in chamfered corners instead of rounded corners, which is useful for some artistic effects.
</member>
<member name="corner_radius_bottom_left" type="int" setter="set_corner_radius" getter="get_corner_radius" default="0">
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index 376082f417..b6e9eda1d1 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -34,9 +34,6 @@
<member name="size_2d_override_stretch" type="bool" setter="set_size_2d_override_stretch" getter="is_size_2d_override_stretch_enabled" default="false">
If [code]true[/code], the 2D size override affects stretch as well.
</member>
- <member name="xr" type="bool" setter="set_use_xr" getter="is_using_xr" default="false">
- If [code]true[/code], the sub-viewport will be used in AR/VR process.
- </member>
</members>
<constants>
<constant name="CLEAR_MODE_ALWAYS" value="0" enum="ClearMode">
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 331de4284e..1195e4aa2b 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -5,13 +5,22 @@
</brief_description>
<description>
The [SurfaceTool] is used to construct a [Mesh] by specifying vertex attributes individually. It can be used to construct a [Mesh] from a script. All properties except indices need to be added before calling [method add_vertex]. For example, to add vertex colors and UVs:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
st.set_color(Color(1, 0, 0))
st.set_uv(Vector2(0, 0))
st.set_vertex(Vector3(0, 0, 0))
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ var st = new SurfaceTool();
+ st.Begin(Mesh.PrimitiveType.Triangles);
+ st.SetColor(new Color(1, 0, 0));
+ st.SetUv(new Vector2(0, 0));
+ st.SetVertex(new Vector3(0, 0, 0));
+ [/csharp]
+ [/codeblocks]
The above [SurfaceTool] now contains one vertex of a triangle which has a UV coordinate and a specified [Color]. If another vertex were added without calling [method set_uv] or [method set_color], then the last values would be used.
Vertex attributes must be passed [b]before[/b] calling [method add_vertex]. Failure to do so will result in an error when committing the vertex information to a mesh.
Additionally, the attributes used before the first vertex is added determine the format of the mesh. For example, if you only add UVs to the first vertex, you cannot add color to any of the subsequent vertices.
@@ -180,6 +189,12 @@
<description>
</description>
</method>
+ <method name="get_primitive" qualifiers="const">
+ <return type="int" enum="Mesh.PrimitiveType">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_skin_weight_count" qualifiers="const">
<return type="int" enum="SurfaceTool.SkinWeightCount">
</return>
@@ -190,7 +205,7 @@
<return type="void">
</return>
<description>
- Shrinks the vertex array by creating an index array (avoids reusing vertices).
+ Shrinks the vertex array by creating an index array. This can improve performance by avoiding vertex reuse.
</description>
</method>
<method name="optimize_indices_for_cache">
@@ -205,7 +220,7 @@
<argument index="0" name="bones" type="PackedInt32Array">
</argument>
<description>
- Specifies an array of bones for the next vertex to use. [code]bones[/code] must contain 4 integers.
+ Specifies an array of bones to use for the [i]next[/i] vertex. [code]bones[/code] must contain 4 integers.
</description>
</method>
<method name="set_color">
@@ -214,7 +229,7 @@
<argument index="0" name="color" type="Color">
</argument>
<description>
- Specifies a [Color] for the next vertex to use.
+ Specifies a [Color] to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
[b]Note:[/b] The material must have [member BaseMaterial3D.vertex_color_use_as_albedo] enabled for the vertex color to be visible.
</description>
</method>
@@ -253,7 +268,7 @@
<argument index="0" name="normal" type="Vector3">
</argument>
<description>
- Specifies a normal for the next vertex to use.
+ Specifies a normal to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_skin_weight_count">
@@ -279,7 +294,7 @@
<argument index="0" name="tangent" type="Plane">
</argument>
<description>
- Specifies a tangent for the next vertex to use.
+ Specifies a tangent to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv">
@@ -288,7 +303,7 @@
<argument index="0" name="uv" type="Vector2">
</argument>
<description>
- Specifies a set of UV coordinates to use for the next vertex.
+ Specifies a set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv2">
@@ -297,7 +312,7 @@
<argument index="0" name="uv2" type="Vector2">
</argument>
<description>
- Specifies an optional second set of UV coordinates to use for the next vertex.
+ Specifies an optional second set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_weights">
@@ -306,7 +321,7 @@
<argument index="0" name="weights" type="PackedFloat32Array">
</argument>
<description>
- Specifies weight values for next vertex to use. [code]weights[/code] must contain 4 values.
+ Specifies weight values to use for the [i]next[/i] vertex. [code]weights[/code] must contain 4 values. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
</methods>
diff --git a/doc/classes/TCP_Server.xml b/doc/classes/TCP_Server.xml
index 72e9ca923d..ec91d75d47 100644
--- a/doc/classes/TCP_Server.xml
+++ b/doc/classes/TCP_Server.xml
@@ -9,6 +9,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port this server is listening to.
+ </description>
+ </method>
<method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 52577e6102..ddf6b465a4 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -201,6 +201,9 @@
<theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )">
Font color of disabled tabs.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the tab name.
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
Font color of the currently selected tab.
</theme_item>
@@ -225,6 +228,9 @@
<theme_item name="menu_highlight" type="Texture2D">
The icon for the menu button (see [method set_popup]) when it's being hovered with the cursor.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the tab text outline.
+ </theme_item>
<theme_item name="panel" type="StyleBox">
The style for the background fill.
</theme_item>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index 0c7b992cbf..d784585e20 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -254,6 +254,9 @@
</method>
</methods>
<members>
+ <member name="clip_tabs" type="bool" setter="set_clip_tabs" getter="get_clip_tabs" default="true">
+ If [code]true[/code], tabs overflowing this node's width will be hidden, displaying two navigation buttons instead. Otherwise, this node's minimum size is updated so that all tabs are visible.
+ </member>
<member name="current_tab" type="int" setter="set_current_tab" getter="get_current_tab" default="0">
Select tab at index [code]tab_idx[/code].
</member>
@@ -261,7 +264,7 @@
If [code]true[/code], tabs can be rearranged with mouse drag.
</member>
<member name="scrolling_enabled" type="bool" setter="set_scrolling_enabled" getter="get_scrolling_enabled" default="true">
- if [code]true[/code], the mouse's scroll wheel cab be used to navigate the scroll view.
+ if [code]true[/code], the mouse's scroll wheel can be used to navigate the scroll view.
</member>
<member name="tab_align" type="int" setter="set_tab_align" getter="get_tab_align" enum="Tabs.TabAlign" default="1">
The alignment of all tabs. See [enum TabAlign] for details.
@@ -362,6 +365,9 @@
<theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )">
Font color of disabled tabs.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the tab name.
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
Font color of the currently selected tab.
</theme_item>
@@ -380,7 +386,8 @@
<theme_item name="increment_highlight" type="Texture2D">
Icon for the right arrow button that appears when there are too many tabs to fit in the container width. Used when the button is being hovered with the cursor.
</theme_item>
- <theme_item name="panel" type="StyleBox">
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the tab text outline.
</theme_item>
<theme_item name="tab_disabled" type="StyleBox">
The style of disabled tabs.
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 539f7afbd8..088bcd1c3c 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -402,13 +402,24 @@
<description>
Perform a search inside the text. Search flags can be specified in the [enum SearchFlags] enum.
Returns an empty [code]Dictionary[/code] if no result was found. Otherwise, returns a [code]Dictionary[/code] containing [code]line[/code] and [code]column[/code] entries, e.g:
- [codeblock]
- var result = search(key, flags, line, column)
- if !result.is_empty():
+ [codeblocks]
+ [gdscript]
+ var result = search("print", SEARCH_WHOLE_WORDS, 0, 0)
+ if !result.empty():
# Result found.
var line_number = result.line
var column_number = result.column
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ int[] result = Search("print", (uint)TextEdit.SearchFlags.WholeWords, 0, 0);
+ if (result.Length &gt; 0)
+ {
+ // Result found.
+ int lineNumber = result[(int)TextEdit.SearchResult.Line];
+ int columnNumber = result[(int)TextEdit.SearchResult.Column];
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="select">
@@ -954,6 +965,9 @@
<theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
Sets the font [Color].
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the [TextEdit].
+ </theme_item>
<theme_item name="font_readonly_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )">
</theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )">
@@ -971,6 +985,9 @@
<theme_item name="normal" type="StyleBox">
Sets the [StyleBox] of this [TextEdit].
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="read_only" type="StyleBox">
Sets the [StyleBox] of this [TextEdit] when [member readonly] is enabled.
</theme_item>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 99eb8b81d4..8df53b8423 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -145,7 +145,7 @@
<argument index="4" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
<description>
- Draw outilines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw outlines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
</description>
</method>
<method name="get_dropcap_lines" qualifiers="const">
@@ -289,6 +289,20 @@
Returns the size of the bounding box of the paragraph.
</description>
</method>
+ <method name="get_spacing_bottom" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns extra spacing at the bottom of the line. See [member Font.extra_spacing_bottom].
+ </description>
+ </method>
+ <method name="get_spacing_top" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns extra spacing at the top of the line. See [member Font.extra_spacing_top].
+ </description>
+ </method>
<method name="hit_test" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 791646000b..fe63e434c9 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -9,6 +9,19 @@
<tutorials>
</tutorials>
<methods>
+ <method name="create_font_bitmap">
+ <return type="RID">
+ </return>
+ <argument index="0" name="height" type="float">
+ </argument>
+ <argument index="1" name="ascent" type="float">
+ </argument>
+ <argument index="2" name="base_size" type="int">
+ </argument>
+ <description>
+ Creates new, empty bitmap font. To free the resulting font, use [method free_rid] method.
+ </description>
+ </method>
<method name="create_font_memory">
<return type="RID">
</return>
@@ -78,6 +91,51 @@
Draws box displaying character hexadecimal code. Used for replacing missing characters.
</description>
</method>
+ <method name="font_bitmap_add_char">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="char" type="int">
+ </argument>
+ <argument index="2" name="texture_idx" type="int">
+ </argument>
+ <argument index="3" name="rect" type="Rect2">
+ </argument>
+ <argument index="4" name="align" type="Vector2">
+ </argument>
+ <argument index="5" name="advance" type="float">
+ </argument>
+ <description>
+ Adds a character to the font, where [code]character[/code] is the Unicode value, [code]texture[/code] is the texture index, [code]rect[/code] is the region in the texture (in pixels!), [code]align[/code] is the (optional) alignment for the character and [code]advance[/code] is the (optional) advance.
+ </description>
+ </method>
+ <method name="font_bitmap_add_kerning_pair">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="A" type="int">
+ </argument>
+ <argument index="2" name="B" type="int">
+ </argument>
+ <argument index="3" name="kerning" type="int">
+ </argument>
+ <description>
+ Adds a kerning pair to the bitmap font as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
+ </description>
+ </method>
+ <method name="font_bitmap_add_texture">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="texture" type="Texture">
+ </argument>
+ <description>
+ Adds a texture to the bitmap font.
+ </description>
+ </method>
<method name="font_draw_glyph" qualifiers="const">
<return type="Vector2">
</return>
@@ -200,6 +258,22 @@
Returns advance of the glyph.
</description>
</method>
+ <method name="font_get_glyph_contours" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="size" type="int">
+ </argument>
+ <argument index="2" name="index" type="int">
+ </argument>
+ <description>
+ Returns outline contours of the glyph in a Dictionary.
+ [code]points[/code] - [PackedVector3Array], containing outline points. [code]x[/code] and [code]y[/code] are point coordinates. [code]z[/code] is the type of the point, using the [enum ContourPointTag] values.
+ [code]contours[/code] - [PackedInt32Array], containing indices the end points of each contour.
+ [code]orientation[/code] - [bool], contour orientation. If [code]true[/code], clockwise contours must be filled.
+ </description>
+ </method>
<method name="font_get_glyph_index" qualifiers="const">
<return type="int">
</return>
@@ -295,6 +369,24 @@
Returns list of script support overrides.
</description>
</method>
+ <method name="font_get_spacing_glyph" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <description>
+ Returns extra spacing for each glyph in pixels.
+ </description>
+ </method>
+ <method name="font_get_spacing_space" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <description>
+ Sets extra spacing for each glyph in pixels.
+ </description>
+ </method>
<method name="font_get_supported_chars" qualifiers="const">
<return type="String">
</return>
@@ -490,6 +582,28 @@
Adds override for [method font_is_script_supported].
</description>
</method>
+ <method name="font_set_spacing_glyph">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ Returns extra spacing for the space character in pixels.
+ </description>
+ </method>
+ <method name="font_set_spacing_space">
+ <return type="void">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ Sets extra spacing for the space character in pixels.
+ </description>
+ </method>
<method name="font_set_variation">
<return type="void">
</return>
@@ -655,7 +769,7 @@
<method name="shaped_text_clear">
<return type="void">
</return>
- <argument index="0" name="arg0" type="RID">
+ <argument index="0" name="rid" type="RID">
</argument>
<description>
Clears text buffer (removes text and inline objects).
@@ -1203,5 +1317,14 @@
<constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
TextServer require external data file for some features.
</constant>
+ <constant name="CONTOUR_CURVE_TAG_ON" value="1" enum="ContourPointTag">
+ Contour point is on the curve.
+ </constant>
+ <constant name="CONTOUR_CURVE_TAG_OFF_CONIC" value="0" enum="ContourPointTag">
+ Contour point isn't on the curve, but serves as a control point for a conic (quadratic) Bézier arc.
+ </constant>
+ <constant name="CONTOUR_CURVE_TAG_OFF_CUBIC" value="2" enum="ContourPointTag">
+ Contour point isn't on the curve, but serves as a control point for a cubic Bézier arc.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 2270b95c63..c33f32c9e4 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -63,18 +63,18 @@
Draws a part of the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
</method>
- <method name="get_data" qualifiers="const">
- <return type="Image">
+ <method name="get_height" qualifiers="const">
+ <return type="int">
</return>
<description>
- Returns an [Image] that is a copy of data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
+ Returns the texture height.
</description>
</method>
- <method name="get_height" qualifiers="const">
- <return type="int">
+ <method name="get_image" qualifiers="const">
+ <return type="Image">
</return>
<description>
- Returns the texture height.
+ Returns an [Image] that is a copy of data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
</description>
</method>
<method name="get_size" qualifiers="const">
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 3f7f22ebcd..3173dddb42 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -84,6 +84,19 @@
Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
+ <method name="clear_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
+ </description>
+ </method>
<method name="copy_default_theme">
<return type="void">
</return>
@@ -194,6 +207,13 @@
Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]node_type[/code].
</description>
</method>
+ <method name="get_font_size_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the font size types as a [PackedStringArray] filled with unique type names, for use in [method get_font_size] and/or [method get_font_size_list].
+ </description>
+ </method>
<method name="get_font_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
@@ -236,7 +256,8 @@
<argument index="1" name="node_type" type="StringName">
</argument>
<description>
- Returns the icon [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
+ Valid [code]name[/code]s may be found using [method get_stylebox_list]. Valid [code]node_type[/code]s may be found using [method get_stylebox_type_list].
</description>
</method>
<method name="get_stylebox_list" qualifiers="const">
@@ -246,6 +267,7 @@
</argument>
<description>
Returns all the [StyleBox]s as a [PackedStringArray] filled with each [StyleBox]'s name, for use in [method get_stylebox], if the theme has [code]node_type[/code].
+ Valid [code]node_type[/code]s may be found using [method get_stylebox_type_list].
</description>
</method>
<method name="get_stylebox_type_list" qualifiers="const">
@@ -255,6 +277,41 @@
Returns all the [StyleBox] types as a [PackedStringArray] filled with unique type names, for use in [method get_stylebox] and/or [method get_stylebox_list].
</description>
</method>
+ <method name="get_theme_item" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
+ Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ </description>
+ </method>
+ <method name="get_theme_item_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="node_type" type="String">
+ </argument>
+ <description>
+ Returns all the theme items of [code]data_type[/code] as a [PackedStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]node_type[/code].
+ Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ </description>
+ </method>
+ <method name="get_theme_item_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <description>
+ Returns all the theme items of [code]data_type[/code] types as a [PackedStringArray] filled with unique type names, for use in [method get_theme_item], [method get_theme_item_list] or data type specific methods.
+ </description>
+ </method>
<method name="get_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
@@ -334,6 +391,113 @@
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
</description>
</method>
+ <method name="has_theme_item" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]node_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ </description>
+ </method>
+ <method name="rename_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_constant">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_font">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_font_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the font size [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_icon">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_stylebox">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="old_name" type="StringName">
+ </argument>
+ <argument index="2" name="name" type="StringName">
+ </argument>
+ <argument index="3" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
<method name="set_color">
<return type="void">
</return>
@@ -345,7 +509,7 @@
</argument>
<description>
Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_constant">
@@ -359,7 +523,7 @@
</argument>
<description>
Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font">
@@ -373,7 +537,7 @@
</argument>
<description>
Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font_size">
@@ -387,7 +551,7 @@
</argument>
<description>
Sets the theme's font size to [code]font_size[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_icon">
@@ -401,7 +565,7 @@
</argument>
<description>
Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_stylebox">
@@ -415,7 +579,24 @@
</argument>
<description>
Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
+ </description>
+ </method>
+ <method name="set_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <argument index="3" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]node_type[/code].
+ Does nothing if the [code]value[/code] type does not match [code]data_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
</methods>
@@ -428,5 +609,26 @@
</member>
</members>
<constants>
+ <constant name="DATA_TYPE_COLOR" value="0" enum="DataType">
+ Theme's [Color] item type.
+ </constant>
+ <constant name="DATA_TYPE_CONSTANT" value="1" enum="DataType">
+ Theme's constant item type.
+ </constant>
+ <constant name="DATA_TYPE_FONT" value="2" enum="DataType">
+ Theme's [Font] item type.
+ </constant>
+ <constant name="DATA_TYPE_FONT_SIZE" value="3" enum="DataType">
+ Theme's font size item type.
+ </constant>
+ <constant name="DATA_TYPE_ICON" value="4" enum="DataType">
+ Theme's icon [Texture2D] item type.
+ </constant>
+ <constant name="DATA_TYPE_STYLEBOX" value="5" enum="DataType">
+ Theme's [StyleBox] item type.
+ </constant>
+ <constant name="DATA_TYPE_MAX" value="6" enum="DataType">
+ Maximum value for the DataType enum.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index a12ef614e3..205b342ba8 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -172,12 +172,22 @@
[b]Note:[/b] Data such as navigation polygons and collision shapes are not immediately updated for performance reasons.
If you need these to be immediately updated, you can call [method update_dirty_quadrants].
Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
- [codeblock]
- func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2())
+ [codeblocks]
+ [gdscript]
+ func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2()):
# Write your custom logic here.
# To call the default method:
.set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public void SetCell(int x, int y, int tile, bool flipX = false, bool flipY = false, bool transpose = false, Vector2 autotileCoord = new Vector2())
+ {
+ // Write your custom logic here.
+ // To call the default method:
+ base.SetCell(x, y, tile, flipX, flipY, transpose, autotileCoord);
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="set_cellv">
@@ -262,6 +272,9 @@
</method>
</methods>
<members>
+ <member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false">
+ If [code]true[/code], this TileMap bakes a navigation region.
+ </member>
<member name="cell_clip_uv" type="bool" setter="set_clip_uv" getter="get_clip_uv" default="false">
If [code]true[/code], the cell's UVs will be clipped.
</member>
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index ab75e21ce8..807d8033c1 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Counts down a specified interval and emits a signal on reaching 0. Can be set to repeat or "one-shot" mode.
- [b]Note:[/b] To create an one-shot timer without instantiating a node, use [method SceneTree.create_timer].
+ [b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
@@ -47,8 +47,8 @@
<member name="paused" type="bool" setter="set_paused" getter="is_paused">
If [code]true[/code], the timer is paused and will not process until it is unpaused again, even if [method start] is called.
</member>
- <member name="process_mode" type="int" setter="set_timer_process_mode" getter="get_timer_process_mode" enum="Timer.TimerProcessMode" default="1">
- Processing mode. See [enum TimerProcessMode].
+ <member name="process_callback" type="int" setter="set_timer_process_callback" getter="get_timer_process_callback" enum="Timer.TimerProcessCallback" default="1">
+ Processing callback. See [enum TimerProcessCallback].
</member>
<member name="time_left" type="float" setter="" getter="get_time_left">
The timer's remaining time in seconds. Returns 0 if the timer is inactive.
@@ -66,10 +66,10 @@
</signal>
</signals>
<constants>
- <constant name="TIMER_PROCESS_PHYSICS" value="0" enum="TimerProcessMode">
+ <constant name="TIMER_PROCESS_PHYSICS" value="0" enum="TimerProcessCallback">
Update the timer during the physics step at each frame (fixed framerate processing).
</constant>
- <constant name="TIMER_PROCESS_IDLE" value="1" enum="TimerProcessMode">
+ <constant name="TIMER_PROCESS_IDLE" value="1" enum="TimerProcessCallback">
Update the timer during the idle time at each frame.
</constant>
</constants>
diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml
index 355804f2a3..bb4c17c531 100644
--- a/doc/classes/TouchScreenButton.xml
+++ b/doc/classes/TouchScreenButton.xml
@@ -4,7 +4,7 @@
Button for touch screen devices for gameplay use.
</brief_description>
<description>
- TouchScreenButton allows you to create on-screen buttons for touch devices. It's intended for gameplay use, such as a unit you have to touch to move.
+ TouchScreenButton allows you to create on-screen buttons for touch devices. It's intended for gameplay use, such as a unit you have to touch to move. Unlike [Button], TouchScreenButton supports multitouch out of the box. Several TouchScreenButtons can be pressed at the same time with touch input.
This node inherits from [Node2D]. Unlike with [Control] nodes, you cannot set anchors on it. If you want to create menus or user interfaces, you may want to use [Button] nodes instead. To make button nodes react to touch events, you can enable the Emulate Mouse option in the Project Settings.
You can configure TouchScreenButton to be visible only on touch devices, helping you develop your game both for desktop and mobile devices.
</description>
@@ -30,7 +30,8 @@
The button's texture for the normal state.
</member>
<member name="passby_press" type="bool" setter="set_passby_press" getter="is_passby_press_enabled" default="false">
- If [code]true[/code], pass-by presses are enabled.
+ If [code]true[/code], the [signal pressed] and [signal released] signals are emitted whenever a pressed finger goes in and out of the button, even if the pressure started outside the active area of the button.
+ [b]Note:[/b] this is a "pass-by" (not "bypass") press mode.
</member>
<member name="pressed" type="Texture2D" setter="set_texture_pressed" getter="get_texture_pressed">
The button's texture for the pressed state.
@@ -42,7 +43,7 @@
If [code]true[/code], the button's shape is centered in the provided texture. If no texture is used, this property has no effect.
</member>
<member name="shape_visible" type="bool" setter="set_shape_visible" getter="is_shape_visible" default="true">
- If [code]true[/code], the button's shape is visible.
+ If [code]true[/code], the button's shape is visible in the editor.
</member>
<member name="visibility_mode" type="int" setter="set_visibility_mode" getter="get_visibility_mode" enum="TouchScreenButton.VisibilityMode" default="0">
The button's visibility mode. See [enum VisibilityMode] for possible values.
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml
index cda69f6a64..9d8721e2de 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform.xml
@@ -58,14 +58,14 @@
Constructs a Transform from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
</description>
</method>
- <method name="affine_inverse">
+ <method name="affine_inverse" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description>
</method>
- <method name="interpolate_with">
+ <method name="interpolate_with" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="xform" type="Transform">
@@ -76,14 +76,14 @@
Interpolates the transform to other Transform by weight amount (on the range of 0.0 to 1.0).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="xform" type="Transform">
@@ -92,12 +92,12 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
- <method name="looking_at">
+ <method name="looking_at" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="target" type="Vector3">
</argument>
- <argument index="1" name="up" type="Vector3">
+ <argument index="1" name="up" type="Vector3" default="Vector3( 0, 1, 0 )">
</argument>
<description>
Returns a copy of the transform rotated such that its -Z axis points towards the [code]target[/code] position.
@@ -153,14 +153,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Transform">
</return>
<description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -171,7 +171,7 @@
Rotates the transform around the given axis by the given angle (in radians), using matrix multiplication. The axis must be a normalized vector.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -180,7 +180,7 @@
Scales basis and origin of the transform by the given scale factor, using matrix multiplication.
</description>
</method>
- <method name="translated">
+ <method name="translated" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="offset" type="Vector3">
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 406774cbfe..6ae7fbcf79 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -54,14 +54,14 @@
Constructs the transform from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three column vectors).
</description>
</method>
- <method name="affine_inverse">
+ <method name="affine_inverse" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description>
</method>
- <method name="basis_xform">
+ <method name="basis_xform" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="v" type="Vector2">
@@ -71,7 +71,7 @@
This method does not account for translation (the origin vector).
</description>
</method>
- <method name="basis_xform_inv">
+ <method name="basis_xform_inv" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="v" type="Vector2">
@@ -81,28 +81,28 @@
This method does not account for translation (the origin vector).
</description>
</method>
- <method name="get_origin">
+ <method name="get_origin" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the transform's origin (translation).
</description>
</method>
- <method name="get_rotation">
+ <method name="get_rotation" qualifiers="const">
<return type="float">
</return>
<description>
Returns the transform's rotation (in radians).
</description>
</method>
- <method name="get_scale">
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the scale.
</description>
</method>
- <method name="interpolate_with">
+ <method name="interpolate_with" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="xform" type="Transform2D">
@@ -113,14 +113,14 @@
Returns a transform interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use [method affine_inverse] for transforms with scaling).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="xform" type="Transform2D">
@@ -185,14 +185,14 @@
<description>
</description>
</method>
- <method name="orthonormalized">
+ <method name="orthonormalized" qualifiers="const">
<return type="Transform2D">
</return>
<description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors (scale of 1 or -1).
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="phi" type="float">
@@ -201,7 +201,7 @@
Rotates the transform by the given angle (in radians), using matrix multiplication.
</description>
</method>
- <method name="scaled">
+ <method name="scaled" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="scale" type="Vector2">
@@ -210,7 +210,7 @@
Scales the transform by the given scale factor, using matrix multiplication.
</description>
</method>
- <method name="translated">
+ <method name="translated" qualifiers="const">
<return type="Transform2D">
</return>
<argument index="0" name="offset" type="Vector2">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 406bda412a..a09f1bf470 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -6,16 +6,30 @@
<description>
This shows a tree of items that can be selected, expanded and collapsed. The tree can have multiple columns with custom controls like text editing, buttons and popups. It can be useful for structured displays and interactions.
Trees are built via code, using [TreeItem] objects to create the structure. They have a single root but multiple roots can be simulated if a dummy hidden root is added.
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _ready():
var tree = Tree.new()
var root = tree.create_item()
- tree.set_hide_root(true)
+ tree.hide_root = true
var child1 = tree.create_item(root)
var child2 = tree.create_item(root)
var subchild1 = tree.create_item(child1)
subchild1.set_text(0, "Subchild1")
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Ready()
+ {
+ var tree = new Tree();
+ TreeItem root = tree.CreateItem();
+ tree.HideRoot = true;
+ TreeItem child1 = tree.CreateItem(root);
+ TreeItem child2 = tree.CreateItem(root);
+ TreeItem subchild1 = tree.CreateItem(child1);
+ subchild1.SetText(0, "Subchild1");
+ }
+ [/csharp]
+ [/codeblocks]
To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_children] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
</description>
<tutorials>
@@ -57,6 +71,13 @@
The new item will be the [code]idx[/code]th child of parent, or it will be the last child if there are not enough siblings.
</description>
</method>
+ <method name="edit_selected">
+ <return type="bool">
+ </return>
+ <description>
+ Edits the selected tree item as if it was clicked. The item must be set editable with [method TreeItem.set_editable]. Returns [code]true[/code] if the item could be edited. Fails if no item is selected.
+ </description>
+ </method>
<method name="ensure_cursor_is_visible">
<return type="void">
</return>
@@ -145,13 +166,26 @@
</return>
<description>
Returns the currently edited item. Can be used with [signal item_edited] to get the item that was modified.
- [codeblock]
+ [codeblocks]
+ [gdscript]
func _ready():
$Tree.item_edited.connect(on_Tree_item_edited)
func on_Tree_item_edited():
print($Tree.get_edited()) # This item just got edited (e.g. checked).
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public override void _Ready()
+ {
+ GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited;
+ }
+
+ public void OnTreeItemEdited()
+ {
+ GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked).
+ }
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_edited_column" qualifiers="const">
@@ -230,6 +264,14 @@
To tell whether a column of an item is selected, use [method TreeItem.is_selected].
</description>
</method>
+ <method name="scroll_to_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_column_expand">
<return type="void">
</return>
@@ -524,6 +566,9 @@
<theme_item name="font_color" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )">
Default text [Color] of the item.
</theme_item>
+ <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The tint of text outline of the item.
+ </theme_item>
<theme_item name="font_selected_color" type="Color" default="Color( 1, 1, 1, 1 )">
Text [Color] used when the item is selected.
</theme_item>
@@ -539,6 +584,9 @@
<theme_item name="item_margin" type="int" default="12">
The horizontal margin at the start of an item. This is used when folding is enabled for the item.
</theme_item>
+ <theme_item name="outline_size" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
<theme_item name="relationship_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
[Color] of the relationship lines.
</theme_item>
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index fd157e5eb9..add23c2ce6 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -741,6 +741,12 @@
Sets the given column's tooltip text.
</description>
</method>
+ <method name="uncollapse_tree">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="collapsed" type="bool" setter="set_collapsed" getter="is_collapsed">
diff --git a/doc/classes/TubeTrailMesh.xml b/doc/classes/TubeTrailMesh.xml
new file mode 100644
index 0000000000..2782791a62
--- /dev/null
+++ b/doc/classes/TubeTrailMesh.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TubeTrailMesh" inherits="PrimitiveMesh" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve" type="Curve" setter="set_curve" getter="get_curve">
+ </member>
+ <member name="radial_steps" type="int" setter="set_radial_steps" getter="get_radial_steps" default="8">
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ </member>
+ <member name="section_length" type="float" setter="set_section_length" getter="get_section_length" default="0.2">
+ </member>
+ <member name="section_rings" type="int" setter="set_section_rings" getter="get_section_rings" default="3">
+ </member>
+ <member name="sections" type="int" setter="set_sections" getter="get_sections" default="5">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 56ccaaf383..00cca40093 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -7,14 +7,23 @@
Tweens are useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them.
[Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween] node; it would be difficult to do the same thing with an [AnimationPlayer] node.
Here is a brief usage example that makes a 2D node move smoothly between two positions:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var tween = get_node("Tween")
tween.interpolate_property($Node2D, "position",
Vector2(0, 0), Vector2(100, 100), 1,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
- [/codeblock]
- Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component.
+ [/gdscript]
+ [csharp]
+ var tween = GetNode&lt;Tween&gt;("Tween");
+ tween.InterpolateProperty(GetNode&lt;Node2D&gt;("Node2D"), "position",
+ new Vector2(0, 0), new Vector2(100, 100), 1,
+ Tween.TransitionType.Linear, Tween.EaseType.InOut);
+ tween.Start();
+ [/csharp]
+ [/codeblocks]
+ Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (e.g. [code]position:x[/code]), where it would only apply to that particular component.
Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url]
</description>
diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml
index aabfed85f0..6f3ccb8a17 100644
--- a/doc/classes/UDPServer.xml
+++ b/doc/classes/UDPServer.xml
@@ -7,8 +7,9 @@
A simple server that opens a UDP socket and returns connected [PacketPeerUDP] upon receiving new packets. See also [method PacketPeerUDP.connect_to_host].
After starting the server ([method listen]), you will need to [method poll] it at regular intervals (e.g. inside [method Node._process]) for it to process new packets, delivering them to the appropriate [PacketPeerUDP], and taking new connections.
Below a small example of how it can be used:
- [codeblock]
- # server.gd
+ [codeblocks]
+ [gdscript]
+ class_name Server
extends Node
var server := UDPServer.new()
@@ -21,20 +22,57 @@
server.poll() # Important!
if server.is_connection_available():
var peer : PacketPeerUDP = server.take_connection()
- var pkt = peer.get_packet()
+ var packet = peer.get_packet()
print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()])
- print("Received data: %s" % [pkt.get_string_from_utf8()])
+ print("Received data: %s" % [packet.get_string_from_utf8()])
# Reply so it knows we received the message.
- peer.put_packet(pkt)
+ peer.put_packet(packet)
# Keep a reference so we can keep contacting the remote peer.
peers.append(peer)
for i in range(0, peers.size()):
pass # Do something with the connected peers.
+ [/gdscript]
+ [csharp]
+ using Godot;
+ using System;
+ using System.Collections.Generic;
- [/codeblock]
- [codeblock]
- # client.gd
+ public class Server : Node
+ {
+ public UDPServer Server = new UDPServer();
+ public List&lt;PacketPeerUDP&gt; Peers = new List&lt;PacketPeerUDP&gt;();
+
+ public override void _Ready()
+ {
+ Server.Listen(4242);
+ }
+
+ public override void _Process(float delta)
+ {
+ Server.Poll(); // Important!
+ if (Server.IsConnectionAvailable())
+ {
+ PacketPeerUDP peer = Server.TakeConnection();
+ byte[] packet = peer.GetPacket();
+ GD.Print($"Accepted Peer: {peer.GetPacketIp()}:{peer.GetPacketPort()}");
+ GD.Print($"Received Data: {packet.GetStringFromUTF8()}");
+ // Reply so it knows we received the message.
+ peer.PutPacket(packet);
+ // Keep a reference so we can keep contacting the remote peer.
+ Peers.Add(peer);
+ }
+ foreach (var peer in Peers)
+ {
+ // Do something with the peers.
+ }
+ }
+ }
+ [/csharp]
+ [/codeblocks]
+ [codeblocks]
+ [gdscript]
+ class_name Client
extends Node
var udp := PacketPeerUDP.new()
@@ -50,11 +88,48 @@
if udp.get_available_packet_count() &gt; 0:
print("Connected: %s" % udp.get_packet().get_string_from_utf8())
connected = true
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ using Godot;
+ using System;
+
+ public class Client : Node
+ {
+ public PacketPeerUDP Udp = new PacketPeerUDP();
+ public bool Connected = false;
+
+ public override void _Ready()
+ {
+ Udp.ConnectToHost("127.0.0.1", 4242);
+ }
+
+ public override void _Process(float delta)
+ {
+ if (!Connected)
+ {
+ // Try to contact server
+ Udp.PutPacket("The Answer Is..42!".ToUTF8());
+ }
+ if (Udp.GetAvailablePacketCount() &gt; 0)
+ {
+ GD.Print($"Connected: {Udp.GetPacket().GetStringFromUTF8()}");
+ Connected = true;
+ }
+ }
+ }
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
</tutorials>
<methods>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port this server is listening to.
+ </description>
+ </method>
<method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
@@ -77,7 +152,7 @@
<argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
</argument>
<description>
- Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.listen].
+ Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.bind].
</description>
</method>
<method name="poll">
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 0e4a76a1a9..aba6183124 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -7,7 +7,8 @@
Helper to manage undo/redo operations in the editor or custom tools. It works by registering methods and property changes inside "actions".
Common behavior is to create an action, then add do/undo calls to functions or property changes, then committing the action.
Here's an example on how to add an action to the Godot editor's own [UndoRedo], from a plugin:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var undo_redo = get_undo_redo() # Method of EditorPlugin.
func do_something():
@@ -24,7 +25,37 @@
undo_redo.add_do_property(node, "position", Vector2(100,100))
undo_redo.add_undo_property(node, "position", node.position)
undo_redo.commit_action()
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ public UndoRedo UndoRedo;
+
+ public override void _Ready()
+ {
+ UndoRedo = GetUndoRedo(); // Method of EditorPlugin.
+ }
+
+ public void DoSomething()
+ {
+ // Put your code here.
+ }
+
+ public void UndoSomething()
+ {
+ // Put here the code that reverts what's done by "DoSomething()".
+ }
+
+ private void OnMyButtonPressed()
+ {
+ var node = GetNode&lt;Node2D&gt;("MyNode2D");
+ UndoRedo.CreateAction("Move the node");
+ UndoRedo.AddDoMethod(this, nameof(DoSomething));
+ UndoRedo.AddUndoMethod(this, nameof(UndoSomething));
+ UndoRedo.AddDoProperty(node, "position", new Vector2(100, 100));
+ UndoRedo.AddUndoProperty(node, "position", node.Position);
+ UndoRedo.CommitAction();
+ }
+ [/csharp]
+ [/codeblocks]
[method create_action], [method add_do_method], [method add_undo_method], [method add_do_property], [method add_undo_property], and [method commit_action] should be called one after the other, like in the example. Not doing so could lead to crashes.
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.
</description>
@@ -131,7 +162,7 @@
<method name="get_action_name">
<return type="String">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="id" type="int">
</argument>
<description>
Gets the action name from its index.
@@ -155,7 +186,7 @@
<return type="int">
</return>
<description>
- Return how many element are in the history.
+ Return how many elements are in the history.
</description>
</method>
<method name="get_version" qualifiers="const">
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 4159a38d96..94d4b1a903 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -53,14 +53,14 @@
Constructs a new [Vector2] from the given [code]x[/code] and [code]y[/code].
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="angle">
+ <method name="angle" qualifiers="const">
<return type="float">
</return>
<description>
@@ -69,7 +69,7 @@
Equivalent to the result of [method @GlobalScope.atan2] when called with the vector's [member y] and [member x] as parameters: [code]atan2(y, x)[/code].
</description>
</method>
- <method name="angle_to">
+ <method name="angle_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -78,7 +78,7 @@
Returns the angle to the given vector, in radians.
</description>
</method>
- <method name="angle_to_point">
+ <method name="angle_to_point" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -87,14 +87,14 @@
Returns the angle between the line connecting the two points and the X axis, in radians.
</description>
</method>
- <method name="aspect">
+ <method name="aspect" qualifiers="const">
<return type="float">
</return>
<description>
Returns the aspect ratio of this vector, the ratio of [member x] to [member y].
</description>
</method>
- <method name="bounce">
+ <method name="bounce" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -103,14 +103,14 @@
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
</method>
- <method name="ceil">
+ <method name="ceil" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded up (towards positive infinity).
</description>
</method>
- <method name="clamped">
+ <method name="clamped" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="length" type="float">
@@ -119,7 +119,7 @@
Returns the vector with a maximum length by limiting its length to [code]length[/code].
</description>
</method>
- <method name="cross">
+ <method name="cross" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector2">
@@ -128,7 +128,7 @@
Returns the cross product of this vector and [code]with[/code].
</description>
</method>
- <method name="cubic_interpolate">
+ <method name="cubic_interpolate" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -143,7 +143,7 @@
Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="direction_to">
+ <method name="direction_to" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -152,7 +152,7 @@
Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
- <method name="distance_squared_to">
+ <method name="distance_squared_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -162,7 +162,7 @@
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -171,7 +171,7 @@
Returns the distance between this vector and [code]to[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector2">
@@ -183,14 +183,14 @@
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description>
</method>
- <method name="floor">
+ <method name="floor" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded down (towards negative infinity).
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Vector2">
@@ -199,21 +199,21 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length (magnitude) of this vector.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
@@ -221,7 +221,7 @@
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -229,10 +229,10 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="move_toward">
+ <method name="move_toward" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -243,7 +243,7 @@
Moves the vector toward [code]to[/code] by the fixed [code]delta[/code] amount.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -390,14 +390,14 @@
<description>
</description>
</method>
- <method name="orthogonal">
+ <method name="orthogonal" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns a perpendicular vector rotated 90 degrees counter-clockwise compared to the original, with the same length.
</description>
</method>
- <method name="posmod">
+ <method name="posmod" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="mod" type="float">
@@ -406,7 +406,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
</description>
</method>
- <method name="posmodv">
+ <method name="posmodv" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="modv" type="Vector2">
@@ -415,7 +415,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -424,7 +424,7 @@
Returns the vector projected onto the vector [code]b[/code].
</description>
</method>
- <method name="reflect">
+ <method name="reflect" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -433,7 +433,7 @@
Returns the vector reflected from a plane defined by the given normal.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="phi" type="float">
@@ -442,21 +442,21 @@
Returns the vector rotated by [code]phi[/code] radians. See also [method @GlobalScope.deg2rad].
</description>
</method>
- <method name="round">
+ <method name="round" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero.
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
- <method name="slerp">
+ <method name="slerp" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="to" type="Vector2">
@@ -464,11 +464,11 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
- <method name="slide">
+ <method name="slide" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="n" type="Vector2">
@@ -477,7 +477,7 @@
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
- <method name="snapped">
+ <method name="snapped" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="step" type="Vector2">
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index a4ea5c2742..b38b968ba3 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -50,14 +50,14 @@
Constructs a new [Vector2i] from the given [code]x[/code] and [code]y[/code].
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector2i">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="aspect">
+ <method name="aspect" qualifiers="const">
<return type="float">
</return>
<description>
@@ -212,7 +212,7 @@
<description>
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector2i">
</return>
<description>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 2d129a2c86..0a86369506 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -55,23 +55,23 @@
Returns a [Vector3] with the given components.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components in absolute values (i.e. positive).
</description>
</method>
- <method name="angle_to">
+ <method name="angle_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="to" type="Vector3">
</argument>
<description>
- Returns the minimum angle to the given vector, in radians.
+ Returns the unsigned minimum angle to the given vector, in radians.
</description>
</method>
- <method name="bounce">
+ <method name="bounce" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -80,14 +80,14 @@
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
</method>
- <method name="ceil">
+ <method name="ceil" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components rounded up (towards positive infinity).
</description>
</method>
- <method name="cross">
+ <method name="cross" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="with" type="Vector3">
@@ -96,7 +96,7 @@
Returns the cross product of this vector and [code]b[/code].
</description>
</method>
- <method name="cubic_interpolate">
+ <method name="cubic_interpolate" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -111,7 +111,7 @@
Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="direction_to">
+ <method name="direction_to" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -120,7 +120,7 @@
Returns the normalized vector pointing from this vector to [code]b[/code]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
- <method name="distance_squared_to">
+ <method name="distance_squared_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -130,7 +130,7 @@
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to">
+ <method name="distance_to" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -139,7 +139,7 @@
Returns the distance between this vector and [code]b[/code].
</description>
</method>
- <method name="dot">
+ <method name="dot" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -151,21 +151,21 @@
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description>
</method>
- <method name="floor">
+ <method name="floor" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a new vector with all components rounded down (towards negative infinity).
</description>
</method>
- <method name="inverse">
+ <method name="inverse" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns the inverse of the vector. This is the same as [code]Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )[/code].
</description>
</method>
- <method name="is_equal_approx">
+ <method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="to" type="Vector3">
@@ -174,21 +174,21 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
- <method name="is_normalized">
+ <method name="is_normalized" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
</description>
</method>
- <method name="length">
+ <method name="length" qualifiers="const">
<return type="float">
</return>
<description>
Returns the length (magnitude) of this vector.
</description>
</method>
- <method name="length_squared">
+ <method name="length_squared" qualifiers="const">
<return type="float">
</return>
<description>
@@ -196,7 +196,7 @@
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
- <method name="lerp">
+ <method name="lerp" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -204,24 +204,24 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
- <method name="max_axis">
+ <method name="max_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
- <method name="min_axis">
+ <method name="min_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_Z].
</description>
</method>
- <method name="move_toward">
+ <method name="move_toward" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -232,7 +232,7 @@
Moves this vector toward [code]to[/code] by the fixed [code]delta[/code] amount.
</description>
</method>
- <method name="normalized">
+ <method name="normalized" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -395,7 +395,7 @@
<description>
</description>
</method>
- <method name="outer">
+ <method name="outer" qualifiers="const">
<return type="Basis">
</return>
<argument index="0" name="with" type="Vector3">
@@ -404,7 +404,7 @@
Returns the outer product with [code]b[/code].
</description>
</method>
- <method name="posmod">
+ <method name="posmod" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="mod" type="float">
@@ -413,7 +413,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
</description>
</method>
- <method name="posmodv">
+ <method name="posmodv" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="modv" type="Vector3">
@@ -422,7 +422,7 @@
Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
</description>
</method>
- <method name="project">
+ <method name="project" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -431,7 +431,7 @@
Returns this vector projected onto another vector [code]b[/code].
</description>
</method>
- <method name="reflect">
+ <method name="reflect" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -440,7 +440,7 @@
Returns this vector reflected from a plane defined by the given normal.
</description>
</method>
- <method name="rotated">
+ <method name="rotated" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="by_axis" type="Vector3">
@@ -451,21 +451,32 @@
Rotates this vector around a given axis by [code]phi[/code] radians. The axis must be a normalized vector.
</description>
</method>
- <method name="round">
+ <method name="round" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns this vector with all components rounded to the nearest integer, with halfway cases rounded away from zero.
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector3">
</return>
<description>
Returns a vector with each component set to one or negative one, depending on the signs of this vector's components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
- <method name="slerp">
+ <method name="signed_angle_to" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="to" type="Vector3">
+ </argument>
+ <argument index="1" name="axis" type="Vector3">
+ </argument>
+ <description>
+ Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and negative in a clockwise direction when viewed from the side specified by the [code]axis[/code].
+ </description>
+ </method>
+ <method name="slerp" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="to" type="Vector3">
@@ -473,11 +484,11 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
- <method name="slide">
+ <method name="slide" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="n" type="Vector3">
@@ -486,7 +497,7 @@
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
- <method name="snapped">
+ <method name="snapped" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="step" type="Vector3">
@@ -495,7 +506,7 @@
Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
</description>
</method>
- <method name="to_diagonal_matrix">
+ <method name="to_diagonal_matrix" qualifiers="const">
<return type="Basis">
</return>
<description>
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index a1ae2aceab..ea5945f5b7 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -52,20 +52,20 @@
Returns a [Vector3i] with the given components.
</description>
</method>
- <method name="abs">
+ <method name="abs" qualifiers="const">
<return type="Vector3i">
</return>
<description>
</description>
</method>
- <method name="max_axis">
+ <method name="max_axis" qualifiers="const">
<return type="int">
</return>
<description>
Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description>
</method>
- <method name="min_axis">
+ <method name="min_axis" qualifiers="const">
<return type="int">
</return>
<description>
@@ -220,7 +220,7 @@
<description>
</description>
</method>
- <method name="sign">
+ <method name="sign" qualifiers="const">
<return type="Vector3i">
</return>
<description>
diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml
index b2ab356b0d..d905ce4054 100644
--- a/doc/classes/VideoPlayer.xml
+++ b/doc/classes/VideoPlayer.xml
@@ -74,6 +74,7 @@
</member>
<member name="stream_position" type="float" setter="set_stream_position" getter="get_stream_position">
The current position of the stream, in seconds.
+ [b]Note:[/b] Changing this value won't have any effect as seeking is not implemented yet, except in video formats implemented by a GDNative add-on.
</member>
<member name="volume" type="float" setter="set_volume" getter="get_volume">
Audio volume as a linear value.
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 8120ae539e..1c33274cb0 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -80,9 +80,9 @@
</return>
<description>
Returns the viewport's texture.
- [b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_data] to flip it back, for example:
+ [b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_image] to flip it back, for example:
[codeblock]
- var img = get_viewport().get_texture().get_data()
+ var img = get_viewport().get_texture().get_image()
img.flip_y()
[/codeblock]
</description>
@@ -267,6 +267,11 @@
</member>
<member name="use_debanding" type="bool" setter="set_use_debanding" getter="is_using_debanding" default="false">
</member>
+ <member name="use_occlusion_culling" type="bool" setter="set_use_occlusion_culling" getter="is_using_occlusion_culling" default="false">
+ </member>
+ <member name="use_xr" type="bool" setter="set_use_xr" getter="is_using_xr" default="false">
+ If [code]true[/code], the viewport will use the primary XR interface to render XR output. When applicable this can result in a stereoscopic image and the resulting render being output to a headset.
+ </member>
<member name="world_2d" type="World2D" setter="set_world_2d" getter="get_world_2d">
The custom [World2D] which can be used as 2D environment source.
</member>
@@ -419,6 +424,8 @@
</constant>
<constant name="DEBUG_DRAW_CLUSTER_REFLECTION_PROBES" value="22" enum="DebugDraw">
</constant>
+ <constant name="DEBUG_DRAW_OCCLUDERS" value="23" enum="DebugDraw">
+ </constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="0" enum="DefaultCanvasItemTextureFilter">
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
</constant>
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index c29c30289a..ff00a848b9 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -228,7 +228,9 @@
</constant>
<constant name="TYPE_END" value="5" enum="Type">
</constant>
- <constant name="TYPE_MAX" value="6" enum="Type">
+ <constant name="TYPE_SKY" value="6" enum="Type">
+ </constant>
+ <constant name="TYPE_MAX" value="7" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="NODE_ID_INVALID" value="-1">
diff --git a/doc/classes/VisualShaderNodeComment.xml b/doc/classes/VisualShaderNodeComment.xml
new file mode 100644
index 0000000000..8970e2fabb
--- /dev/null
+++ b/doc/classes/VisualShaderNodeComment.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeComment" inherits="VisualShaderNodeResizableBase" version="4.0">
+ <brief_description>
+ A comment node to be placed on visual shader graph.
+ </brief_description>
+ <description>
+ A resizable rectangular area with changeable [member title] and [member description] used for better organizing of other visual shader nodes.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="description" type="String" setter="set_description" getter="get_description" default="&quot;&quot;">
+ An additional description which placed below the title.
+ </member>
+ <member name="title" type="String" setter="set_title" getter="get_title" default="&quot;Comment&quot;">
+ A title of the node.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml
index 59b501660a..17fc2f8c4d 100644
--- a/doc/classes/VisualShaderNodeCustom.xml
+++ b/doc/classes/VisualShaderNodeCustom.xml
@@ -20,7 +20,7 @@
<return type="String">
</return>
<description>
- Override this method to define the path to the associated custom node in the Visual Shader Editor's members dialog. The path may looks like [code]"MyGame/MyFunctions/Noise"[/code].
+ Override this method to define the path to the associated custom node in the Visual Shader Editor's members dialog. The path may look like [code]"MyGame/MyFunctions/Noise"[/code].
Defining this method is [b]optional[/b]. If not overridden, the node will be filed under the "Addons" category.
</description>
</method>
diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml
index 72be31872d..6b042f6172 100644
--- a/doc/classes/VisualShaderNodeDeterminant.xml
+++ b/doc/classes/VisualShaderNodeDeterminant.xml
@@ -4,7 +4,7 @@
Calculates the determinant of a [Transform] within the visual shader graph.
</brief_description>
<description>
- Translates to [code]deteminant(x)[/code] in the shader language.
+ Translates to [code]determinant(x)[/code] in the shader language.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml
index f571edaab3..c2cbf41f45 100644
--- a/doc/classes/VisualShaderNodeExpression.xml
+++ b/doc/classes/VisualShaderNodeExpression.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Custom Godot Shading Language expression, with a custom amount of input and output ports.
- The provided code is directly injected into the graph's matching shader function ([code]vertex[/code], [code]fragment[/code], or [code]light[/code]), so it cannot be used to to declare functions, varyings, uniforms, or global constants. See [VisualShaderNodeGlobalExpression] for such global definitions.
+ The provided code is directly injected into the graph's matching shader function ([code]vertex[/code], [code]fragment[/code], or [code]light[/code]), so it cannot be used to declare functions, varyings, uniforms, or global constants. See [VisualShaderNodeGlobalExpression] for such global definitions.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeFaceForward.xml b/doc/classes/VisualShaderNodeFaceForward.xml
index 5ef08ea8c2..48f84e5495 100644
--- a/doc/classes/VisualShaderNodeFaceForward.xml
+++ b/doc/classes/VisualShaderNodeFaceForward.xml
@@ -4,7 +4,7 @@
Returns the vector that points in the same direction as a reference vector within the visual shader graph.
</brief_description>
<description>
- Translates to [code]faceforward(N, I, Nref)[/code] in the shader language. The function has three vector parameters: [code]N[/code], the vector to orient, [code]I[/code], the incident vector, and [code]Nref[/code], the reference vector. If the dot product of [code]I[/code] and [code]Nref[/code] is smaller than zero the return value is [code]N[/code]. Otherwise [code]-N[/code] is returned.
+ Translates to [code]faceforward(N, I, Nref)[/code] in the shader language. The function has three vector parameters: [code]N[/code], the vector to orient, [code]I[/code], the incident vector, and [code]Nref[/code], the reference vector. If the dot product of [code]I[/code] and [code]Nref[/code] is smaller than zero the return value is [code]N[/code]. Otherwise, [code]-N[/code] is returned.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml
index afa14c776e..be3f7f173d 100644
--- a/doc/classes/VisualShaderNodeGroupBase.xml
+++ b/doc/classes/VisualShaderNodeGroupBase.xml
@@ -74,7 +74,7 @@
<return type="String">
</return>
<description>
- Returns a [String] description of the input ports as as colon-separated list using the format [code]id,type,name;[/code] (see [method add_input_port]).
+ Returns a [String] description of the input ports as a colon-separated list using the format [code]id,type,name;[/code] (see [method add_input_port]).
</description>
</method>
<method name="get_output_port_count" qualifiers="const">
@@ -88,7 +88,7 @@
<return type="String">
</return>
<description>
- Returns a [String] description of the output ports as as colon-separated list using the format [code]id,type,name;[/code] (see [method add_output_port]).
+ Returns a [String] description of the output ports as a colon-separated list using the format [code]id,type,name;[/code] (see [method add_output_port]).
</description>
</method>
<method name="has_input_port" qualifiers="const">
diff --git a/doc/classes/VisualShaderNodeIf.xml b/doc/classes/VisualShaderNodeIf.xml
index ad0b21a370..418999863b 100644
--- a/doc/classes/VisualShaderNodeIf.xml
+++ b/doc/classes/VisualShaderNodeIf.xml
@@ -4,7 +4,7 @@
Compares two floating-point numbers in order to return a required vector within the visual shader graph.
</brief_description>
<description>
- First two ports are scalar floatin-point numbers to compare, third is tolerance comparison amount and last three ports represents a vectors returned if [code]a == b[/code], [code]a &gt; b[/code] and [code]a &lt; b[/code] respectively.
+ First two ports are scalar floating-point numbers to compare, third is tolerance comparison amount and last three ports represents a vectors returned if [code]a == b[/code], [code]a &gt; b[/code] and [code]a &lt; b[/code] respectively.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml
index 8e819b011c..067f78dffe 100644
--- a/doc/classes/VisualShaderNodeInput.xml
+++ b/doc/classes/VisualShaderNodeInput.xml
@@ -14,7 +14,7 @@
<return type="String">
</return>
<description>
- Returns a translated name of the current constant in the Godot Shader Language. eg. [code]"ALBEDO"[/code] if the [member input_name] equal to [code]"albedo"[/code].
+ Returns a translated name of the current constant in the Godot Shader Language. E.g. [code]"ALBEDO"[/code] if the [member input_name] equal to [code]"albedo"[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/VisualShaderNodeSDFToScreenUV.xml b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
index ea04180095..40fb66e364 100644
--- a/doc/classes/VisualShaderNodeSDFToScreenUV.xml
+++ b/doc/classes/VisualShaderNodeSDFToScreenUV.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeSDFToScreenUV" inherits="VisualShaderNode" version="4.0">
<brief_description>
- A function to convert a SDF (signed-distance field) to screen UV, to be used within the visual shader graph.
+ A function to convert an SDF (signed-distance field) to screen UV, to be used within the visual shader graph.
</brief_description>
<description>
Translates to [code]sdf_to_screen_uv(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeScreenUVToSDF.xml b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
index 438c8dc67b..2e121ffc54 100644
--- a/doc/classes/VisualShaderNodeScreenUVToSDF.xml
+++ b/doc/classes/VisualShaderNodeScreenUVToSDF.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeScreenUVToSDF" inherits="VisualShaderNode" version="4.0">
<brief_description>
- A function to convert screen UV to a SDF (signed-distance field), to be used within the visual shader graph.
+ A function to convert screen UV to an SDF (signed-distance field), to be used within the visual shader graph.
</brief_description>
<description>
Translates to [code]screen_uv_to_sdf(uv)[/code] in the shader language. If the UV port isn't connected, [code]SCREEN_UV[/code] is used instead.
diff --git a/doc/classes/VisualShaderNodeSmoothStep.xml b/doc/classes/VisualShaderNodeSmoothStep.xml
index fa22d16da8..0ed53a8c26 100644
--- a/doc/classes/VisualShaderNodeSmoothStep.xml
+++ b/doc/classes/VisualShaderNodeSmoothStep.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language.
- Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials.
+ Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise, the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VisualShaderNodeTextureSDF.xml b/doc/classes/VisualShaderNodeTextureSDF.xml
index 7d3d654bd0..b5c89c2c31 100644
--- a/doc/classes/VisualShaderNodeTextureSDF.xml
+++ b/doc/classes/VisualShaderNodeTextureSDF.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTextureSDF" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Performs a SDF (signed-distance field) texture lookup within the visual shader graph.
+ Performs an SDF (signed-distance field) texture lookup within the visual shader graph.
</brief_description>
<description>
Translates to [code]texture_sdf(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeTextureSDFNormal.xml b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
index 5dbf3e545a..25fe1c4b28 100644
--- a/doc/classes/VisualShaderNodeTextureSDFNormal.xml
+++ b/doc/classes/VisualShaderNodeTextureSDFNormal.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTextureSDFNormal" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Performs a SDF (signed-distance field) normal texture lookup within the visual shader graph.
+ Performs an SDF (signed-distance field) normal texture lookup within the visual shader graph.
</brief_description>
<description>
Translates to [code]texture_sdf_normal(sdf_pos)[/code] in the shader language.
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 0f887c7705..b99a251a11 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -276,7 +276,7 @@
<method name="set_ime_active">
<return type="void">
</return>
- <argument index="0" name="arg0" type="bool">
+ <argument index="0" name="active" type="bool">
</argument>
<description>
</description>
@@ -284,7 +284,7 @@
<method name="set_ime_position">
<return type="void">
</return>
- <argument index="0" name="arg0" type="Vector2i">
+ <argument index="0" name="position" type="Vector2i">
</argument>
<description>
</description>
@@ -474,8 +474,17 @@
</theme_item>
<theme_item name="title_font" type="Font">
</theme_item>
+ <theme_item name="title_font_size" type="int">
+ The size of the title font.
+ </theme_item>
<theme_item name="title_height" type="int" default="20">
</theme_item>
+ <theme_item name="title_outline_modulate" type="Color" default="Color( 1, 1, 1, 1 )">
+ The color of the title outline.
+ </theme_item>
+ <theme_item name="title_outline_size" type="int" default="0">
+ The size of the title outline.
+ </theme_item>
<theme_item name="window_panel" type="StyleBox">
</theme_item>
</theme_items>
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index 25033cdb09..20b3afbd0b 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -18,6 +18,9 @@
<member name="direct_space_state" type="PhysicsDirectSpaceState2D" setter="" getter="get_direct_space_state">
Direct access to the world's physics 2D space state. Used for querying current and potential collisions. When using multi-threaded physics, access is limited to [code]_physics_process(delta)[/code] in the main thread.
</member>
+ <member name="navigation_map" type="RID" setter="" getter="get_navigation_map">
+ The [RID] of this world's navigation map. Used by the [NavigationServer2D].
+ </member>
<member name="space" type="RID" setter="" getter="get_space">
The [RID] of this world's physics space resource. Used by the [PhysicsServer2D] for 2D physics, treating it as both a space and an area.
</member>
diff --git a/doc/classes/World3D.xml b/doc/classes/World3D.xml
index fe92077432..610ecacff4 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -23,6 +23,9 @@
<member name="fallback_environment" type="Environment" setter="set_fallback_environment" getter="get_fallback_environment">
The World3D's fallback_environment will be used if the World3D's [Environment] fails or is missing.
</member>
+ <member name="navigation_map" type="RID" setter="" getter="get_navigation_map">
+ The [RID] of this world's navigation map. Used by the [NavigationServer3D].
+ </member>
<member name="scenario" type="RID" setter="" getter="get_scenario">
The World3D's visual scenario.
</member>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
index a4a86cc22a..5d8c23bd6f 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -62,7 +62,7 @@
<argument index="0" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if the button at index [code]button[/code] is pressed. See [enum JoyButtonList].
+ Returns [code]true[/code] if the button at index [code]button[/code] is pressed. See [enum JoyButton].
</description>
</method>
</methods>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index 36cd6e2ea0..5274d952fd 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRPositionalTracker" inherits="Object" version="4.0">
+<class name="XRPositionalTracker" inherits="Reference" version="4.0">
<brief_description>
A tracked object.
</brief_description>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 75a05bef17..d0edf91fed 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -10,6 +10,24 @@
<link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
+ <method name="add_interface">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Registers an [XRInterface] object.
+ </description>
+ </method>
+ <method name="add_tracker">
+ <return type="void">
+ </return>
+ <argument index="0" name="tracker" type="XRPositionalTracker">
+ </argument>
+ <description>
+ Registers a new [XRPositionalTracker] that tracks a spatial location in real space.
+ </description>
+ </method>
<method name="center_on_hmd">
<return type="void">
</return>
@@ -26,6 +44,15 @@
You should call this method after a few seconds have passed. For instance, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
</description>
</method>
+ <method name="clear_primary_interface_if">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Clears our current primary interface if it is set to the provided interface.
+ </description>
+ </method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface">
</return>
@@ -109,6 +136,24 @@
Returns the number of trackers currently registered.
</description>
</method>
+ <method name="remove_interface">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Removes this interface.
+ </description>
+ </method>
+ <method name="remove_tracker">
+ <return type="void">
+ </return>
+ <argument index="0" name="tracker" type="XRPositionalTracker">
+ </argument>
+ <description>
+ Removes this positional tracker.
+ </description>
+ </method>
</methods>
<members>
<member name="primary_interface" type="XRInterface" setter="set_primary_interface" getter="get_primary_interface">
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index 03e8bee7d5..48f336d58c 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -4,7 +4,7 @@
Boolean built-in type.
</brief_description>
<description>
- Boolean is a built-in type. There are two boolean values: [code]true[/code] and [code]false[/code]. You can think of it as an switch with on or off (1 or 0) setting. Booleans are used in programming for logic in condition statements, like [code]if[/code] statements.
+ Boolean is a built-in type. There are two boolean values: [code]true[/code] and [code]false[/code]. You can think of it as a switch with on or off (1 or 0) setting. Booleans are used in programming for logic in condition statements, like [code]if[/code] statements.
Booleans can be directly used in [code]if[/code] statements. The code below demonstrates this on the [code]if can_shoot:[/code] line. You don't need to use [code]== true[/code], you only need [code]if can_shoot:[/code]. Similarly, use [code]if not can_shoot:[/code] rather than [code]== false[/code].
[codeblocks]
[gdscript]
@@ -49,6 +49,7 @@
[/csharp]
[/codeblocks]
The following code will set [code]can_shoot[/code] to [code]false[/code] and start a timer. This will prevent player from shooting until the timer runs out. Next [code]can_shoot[/code] will be set to [code]true[/code] again allowing player to shoot once again.
+ [codeblocks]
[gdscript]
var _can_shoot = true
onready var _cool_down = $CoolDownTimer
@@ -131,6 +132,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if two bools are different, i.e. one is [code]true[/code] and the other is [code]false[/code].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -139,6 +141,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if left operand is [code]false[/code] and right operand is [code]true[/code].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -147,6 +150,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if two bools are equal, i.e. both are [code]true[/code] or both are [code]false[/code].
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -155,6 +159,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if left operand is [code]true[/code] and right operand is [code]false[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 85fe31eec8..11f6d91b05 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -49,6 +49,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if two floats are different from each other.
</description>
</method>
<method name="operator !=" qualifiers="operator">
@@ -57,6 +58,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the integer has different value than the float.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -65,6 +67,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Multiplies two [float]s.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -73,6 +76,10 @@
<argument index="0" name="right" type="Vector2">
</argument>
<description>
+ Multiplies each component of the [Vector2] by the given [float].
+ [codeblock]
+ print(2.5 * Vector2(1, 1)) # Vector2(2.5, 2.5)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -81,6 +88,10 @@
<argument index="0" name="right" type="Vector2i">
</argument>
<description>
+ Multiplies each component of the [Vector2i] by the given [float].
+ [codeblock]
+ print(2.0 * Vector2i(1, 1)) # Vector2i(2.0, 2.0)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -89,6 +100,7 @@
<argument index="0" name="right" type="Vector3">
</argument>
<description>
+ Multiplies each component of the [Vector3] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -97,6 +109,7 @@
<argument index="0" name="right" type="Vector3i">
</argument>
<description>
+ Multiplies each component of the [Vector3i] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -105,6 +118,7 @@
<argument index="0" name="right" type="Quat">
</argument>
<description>
+ Multiplies each component of the [Quat] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -113,6 +127,10 @@
<argument index="0" name="right" type="Color">
</argument>
<description>
+ Multiplies each component of the [Color] by the given [float].
+ [codeblock]
+ print(1.5 * Color(0.5, 0.5, 0.5)) # Color(0.75, 0.75, 0.75)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -121,12 +139,17 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Multiplies a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="float">
</return>
<description>
+ Unary plus operator. Doesn't have any effect.
+ [codeblock]
+ var a = +2.5 # a is 2.5.
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -135,6 +158,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Adds two floats.
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -143,12 +167,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Adds a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="float">
</return>
<description>
+ Unary minus operator. Negates the number.
+ [codeblock]
+ var a = -2.5 # a is -2.5.
+ print(-a) # 2.5
+ [/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -157,6 +187,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Subtracts a float from a float.
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -165,6 +196,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Subtracts an [int] from a [float]. The result is a [float].
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -173,6 +205,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Divides two floats.
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -181,6 +214,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Divides a [float] by an [int]. The result is a [float].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -189,6 +223,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is less than the right one.
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -197,6 +232,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is less than the given [int].
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -205,6 +241,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -213,6 +250,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is less than or equal to the given [int].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -221,6 +259,8 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if both floats are exactly equal.
+ [b]Note:[/b] Due to floating-point precision errors, consider using [method @GlobalScope.is_equal_approx] or [method @GlobalScope.is_zero_approx] instead, which are more reliable.
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -229,6 +269,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the [float] and the given [int] are equal.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -237,6 +278,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is greater than the right one.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -245,6 +287,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is greater than the given [int].
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -253,6 +296,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is greater than or equal to the right one.
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -261,6 +305,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is greater than or equal to the given [int].
</description>
</method>
</methods>
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index a63c509937..119cdf8eeb 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -79,6 +79,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if operands are different from each other.
</description>
</method>
<method name="operator !=" qualifiers="operator">
@@ -87,6 +88,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if operands are different from each other.
</description>
</method>
<method name="operator %" qualifiers="operator">
@@ -95,6 +97,12 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of the modulo operator for two integers, i.e. the remainder after dividing both numbers.
+ [codeblock]
+ print(5 % 2) # 1
+ print(12 % 4) # 0
+ print(12 % 2) # 2
+ [/codeblock]
</description>
</method>
<method name="operator &amp;" qualifiers="operator">
@@ -103,6 +111,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]AND[/code] operation for two integers.
+ [codeblock]
+ print(3 &amp; 1) # 1
+ print(11 &amp; 3) # 3
+ [/codeblock]
+ It's useful to retrieve binary flags from a variable.
+ [codeblock]
+ var flags = 5
+ # Do something if the first bit is enabled.
+ if flags &amp; 1:
+ do_stuff()
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -111,6 +131,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Multiplies an [int] and a [float]. The result is a [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -119,6 +140,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Multiplies two [int]s.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -127,6 +149,10 @@
<argument index="0" name="right" type="Vector2">
</argument>
<description>
+ Multiplies each component of the vector by the given integer.
+ [codeblock]
+ print(2 * Vector2(1, 1)) # Vector2(2, 2)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -135,6 +161,7 @@
<argument index="0" name="right" type="Vector2i">
</argument>
<description>
+ Multiplies each component of the integer vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -143,6 +170,7 @@
<argument index="0" name="right" type="Vector3">
</argument>
<description>
+ Multiplies each component of the vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -151,6 +179,7 @@
<argument index="0" name="right" type="Vector3i">
</argument>
<description>
+ Multiplies each component of the integer vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -159,6 +188,7 @@
<argument index="0" name="right" type="Quat">
</argument>
<description>
+ Multiplies each component of the quaternion by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -167,12 +197,20 @@
<argument index="0" name="right" type="Color">
</argument>
<description>
+ Multiplies each component of the color by the given integer.
+ [codeblock]
+ print(2 * Color(0.5, 0.5, 0.5)) # Color(1, 1, 1)
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="int">
</return>
<description>
+ Unary plus operator. Doesn't have any effect.
+ [codeblock]
+ var a = +1 # a is 1.
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -181,6 +219,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Adds an [int] to a [float]. The result is a [float].
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -189,12 +228,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Adds two integers.
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="int">
</return>
<description>
+ Unary minus operator. Negates the number.
+ [codeblock]
+ var a = -1 # a is -1.
+ print(-a) # 1
+ [/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -203,6 +248,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Subtracts a [float] from an [int]. The result is a [float].
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -211,6 +257,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Subtracts two integers.
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -219,6 +266,10 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Divides an [int] by a [float]. The result is a [float].
+ [codeblock]
+ print(10 / 3.0) # 3.333...
+ [/codeblock]
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -227,6 +278,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Divides two integers. The decimal part of the result is discarded (truncated).
+ [codeblock]
+ print(10 / 2) # 5
+ print(10 / 3) # 3
+ [/codeblock]
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -235,6 +291,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is less than the given [float].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -243,6 +300,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than the right one.
</description>
</method>
<method name="operator &lt;&lt;" qualifiers="operator">
@@ -251,6 +309,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Performs bitwise shift left operation on the integer. Effectively the same as multiplying by a power of 2.
+ [codeblock]
+ print(10 &lt;&lt; 1) # 20
+ print(10 &lt;&lt; 4) # 160
+ [/codeblock]
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -259,6 +322,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is less than or equal to the given [float].
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -267,6 +331,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -275,6 +340,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if the integer is equal to the given [float].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -283,6 +349,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if both integers are equal.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -291,6 +358,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is greater than the given [float].
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -299,6 +367,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is greater than the right one.
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -307,6 +376,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is greater than or equal to the given [float].
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -315,6 +385,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is greater than or equal to the right one.
</description>
</method>
<method name="operator &gt;&gt;" qualifiers="operator">
@@ -323,6 +394,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Performs bitwise shift right operation on the integer. Effectively the same as dividing by a power of 2.
+ [codeblock]
+ print(10 &gt;&gt; 1) # 5
+ print(10 &gt;&gt; 2) # 2
+ [/codeblock]
</description>
</method>
<method name="operator ^" qualifiers="operator">
@@ -331,6 +407,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]XOR[/code] operation for two integers.
+ [codeblock]
+ print(5 ^ 1) # 4
+ print(4 ^ 7) # 3
+ [/codeblock]
</description>
</method>
<method name="operator |" qualifiers="operator">
@@ -339,12 +420,29 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]OR[/code] operation for two integers.
+ [codeblock]
+ print(2 | 4) # 6
+ print(1 | 3) # 3
+ [/codeblock]
+ It's useful to store binary flags in a variable.
+ [codeblock]
+ var flags = 0
+ # Turn first and third bit on.
+ flags |= 1
+ flags |= 4
+ [/codeblock]
</description>
</method>
<method name="operator ~" qualifiers="operator">
<return type="int">
</return>
<description>
+ Returns the result of bitwise [code]NOT[/code] operation for the integer. It's effectively equal to [code]-int + 1[/code].
+ [codeblock]
+ print(~4) # -3
+ print(~7) # -6
+ [/codeblock]
</description>
</method>
</methods>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index 5335116c8a..1c6055f8ca 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -110,6 +110,9 @@ class ClassDef:
self.theme_items = None # type: Optional[OrderedDict[str, List[ThemeItemDef]]]
self.tutorials = [] # type: List[str]
+ # Used to match the class with XML source for output filtering purposes.
+ self.filepath = "" # type: str
+
class State:
def __init__(self): # type: () -> None
@@ -118,11 +121,12 @@ class State:
self.classes = OrderedDict() # type: OrderedDict[str, ClassDef]
self.current_class = "" # type: str
- def parse_class(self, class_root): # type: (ET.Element) -> None
+ def parse_class(self, class_root, filepath): # type: (ET.Element, str) -> None
class_name = class_root.attrib["name"]
class_def = ClassDef(class_name)
self.classes[class_name] = class_def
+ class_def.filepath = filepath
inherits = class_root.get("inherits")
if inherits is not None:
@@ -278,6 +282,7 @@ def parse_arguments(root): # type: (ET.Element) -> List[ParameterDef]
def main(): # type: () -> None
parser = argparse.ArgumentParser()
parser.add_argument("path", nargs="+", help="A path to an XML file or a directory containing XML files to parse.")
+ parser.add_argument("--filter", default="", help="The filepath pattern for XML files to filter.")
group = parser.add_mutually_exclusive_group()
group.add_argument("--output", "-o", default=".", help="The directory to save output .rst files in.")
group.add_argument(
@@ -333,17 +338,21 @@ def main(): # type: () -> None
print_error("Duplicate class '{}'".format(name), state)
continue
- classes[name] = doc
+ classes[name] = (doc, cur_file)
for name, data in classes.items():
try:
- state.parse_class(data)
+ state.parse_class(data[0], data[1])
except Exception as e:
print_error("Exception while parsing class '{}': {}".format(name, e), state)
state.sort_classes()
+ pattern = re.compile(args.filter)
+
for class_name, class_def in state.classes.items():
+ if args.filter and not pattern.search(class_def.filepath):
+ continue
state.current_class = class_name
make_rst_class(class_def, state, args.dry_run, args.output)
@@ -428,7 +437,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for property_def in class_def.properties.values():
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
- if property_def.overridden:
+ if default is not None and property_def.overridden:
ml.append((type_rst, property_def.name, default + " *(parent override)*"))
else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
diff --git a/doc/translations/README.md b/doc/translations/README.md
new file mode 100644
index 0000000000..a941eeaf49
--- /dev/null
+++ b/doc/translations/README.md
@@ -0,0 +1 @@
+These `.po` and `.pot` files come from Weblate. Do not modify them manually.
diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot
index 4cd89924ee..d14b0d9b1f 100644
--- a/doc/translations/classes.pot
+++ b/doc/translations/classes.pot
@@ -25583,7 +25583,7 @@ msgstr ""
#: doc/classes/Input.xml:99
msgid ""
"Returns the current value of the joypad axis at given index (see [enum "
-"JoyAxisList])."
+"JoyAxis])."
msgstr ""
#: doc/classes/Input.xml:108
@@ -25592,7 +25592,7 @@ msgstr ""
#: doc/classes/Input.xml:117
msgid ""
-"Receives a [enum JoyAxisList] axis and returns its equivalent name as a "
+"Receives a [enum JoyAxis] axis and returns its equivalent name as a "
"string."
msgstr ""
@@ -25602,7 +25602,7 @@ msgstr ""
#: doc/classes/Input.xml:135
msgid ""
-"Receives a gamepad button from [enum JoyButtonList] and returns its "
+"Receives a gamepad button from [enum JoyButton] and returns its "
"equivalent name as a string."
msgstr ""
@@ -25677,7 +25677,7 @@ msgstr ""
#: doc/classes/Input.xml:238
msgid ""
"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
-"JoyButtonList])."
+"JoyButton])."
msgstr ""
#: doc/classes/Input.xml:247
@@ -26077,7 +26077,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:16
-msgid "Button identifier. One of the [enum JoyButtonList] button constants."
+msgid "Button identifier. One of the [enum JoyButton] button constants."
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:19
@@ -26105,7 +26105,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:16
-msgid "Axis identifier. Use one of the [enum JoyAxisList] axis constants."
+msgid "Axis identifier. Use one of the [enum JoyAxis] axis constants."
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:19
@@ -60259,7 +60259,7 @@ msgstr ""
#: doc/classes/XRController3D.xml:65
msgid ""
"Returns [code]true[/code] if the button at index [code]button[/code] is "
-"pressed. See [enum JoyButtonList]."
+"pressed. See [enum JoyButton]."
msgstr ""
#: doc/classes/XRController3D.xml:71
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
index c4fe08e67b..f3e26ebc61 100644
--- a/doc/translations/fr.po
+++ b/doc/translations/fr.po
@@ -25946,7 +25946,7 @@ msgstr ""
#: doc/classes/Input.xml:99
msgid ""
"Returns the current value of the joypad axis at given index (see [enum "
-"JoyAxisList])."
+"JoyAxis])."
msgstr ""
#: doc/classes/Input.xml:108
@@ -25955,7 +25955,7 @@ msgstr ""
#: doc/classes/Input.xml:117
msgid ""
-"Receives a [enum JoyAxisList] axis and returns its equivalent name as a "
+"Receives a [enum JoyAxis] axis and returns its equivalent name as a "
"string."
msgstr ""
@@ -25965,7 +25965,7 @@ msgstr ""
#: doc/classes/Input.xml:135
msgid ""
-"Receives a gamepad button from [enum JoyButtonList] and returns its "
+"Receives a gamepad button from [enum JoyButton] and returns its "
"equivalent name as a string."
msgstr ""
@@ -26041,7 +26041,7 @@ msgstr ""
#, fuzzy
msgid ""
"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
-"JoyButtonList])."
+"JoyButton])."
msgstr ""
"Retourne [code]true[/code] (vrai) si la chaîne de caractères finit par la "
"chaîne de caractères donnée."
@@ -26443,7 +26443,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:16
-msgid "Button identifier. One of the [enum JoyButtonList] button constants."
+msgid "Button identifier. One of the [enum JoyButton] button constants."
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:19
@@ -26471,7 +26471,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:16
-msgid "Axis identifier. Use one of the [enum JoyAxisList] axis constants."
+msgid "Axis identifier. Use one of the [enum JoyAxis] axis constants."
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:19
@@ -60738,7 +60738,7 @@ msgstr ""
#, fuzzy
msgid ""
"Returns [code]true[/code] if the button at index [code]button[/code] is "
-"pressed. See [enum JoyButtonList]."
+"pressed. See [enum JoyButton]."
msgstr ""
"Renvoie [code]true[/code] (vrai) si [code]s[/code] vaut zéro ou quasiment "
"zéro."
diff --git a/drivers/alsa/SCsub b/drivers/alsa/SCsub
index 91e1140b75..1d76bb18c4 100644
--- a/drivers/alsa/SCsub
+++ b/drivers/alsa/SCsub
@@ -2,4 +2,7 @@
Import("env")
+if "alsa" in env and env["alsa"]:
+ env.add_source_files(env.drivers_sources, "asound-so_wrap.c")
+
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/alsa/asound-so_wrap.c b/drivers/alsa/asound-so_wrap.c
new file mode 100644
index 0000000000..65624bcb70
--- /dev/null
+++ b/drivers/alsa/asound-so_wrap.c
@@ -0,0 +1,14092 @@
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-22 19:22:12
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/alsa/asoundlib.h --sys-include <alsa/asoundlib.h> --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header asound-so_wrap.h --output-implementation asound-so_wrap.c
+//
+#include <stdint.h>
+
+#define snd_asoundlib_version snd_asoundlib_version_dylibloader_orig_asound
+#define snd_dlpath snd_dlpath_dylibloader_orig_asound
+#define snd_dlopen snd_dlopen_dylibloader_orig_asound
+#define snd_dlsym snd_dlsym_dylibloader_orig_asound
+#define snd_dlclose snd_dlclose_dylibloader_orig_asound
+#define snd_async_add_handler snd_async_add_handler_dylibloader_orig_asound
+#define snd_async_del_handler snd_async_del_handler_dylibloader_orig_asound
+#define snd_async_handler_get_fd snd_async_handler_get_fd_dylibloader_orig_asound
+#define snd_async_handler_get_signo snd_async_handler_get_signo_dylibloader_orig_asound
+#define snd_async_handler_get_callback_private snd_async_handler_get_callback_private_dylibloader_orig_asound
+#define snd_shm_area_create snd_shm_area_create_dylibloader_orig_asound
+#define snd_shm_area_share snd_shm_area_share_dylibloader_orig_asound
+#define snd_shm_area_destroy snd_shm_area_destroy_dylibloader_orig_asound
+#define snd_user_file snd_user_file_dylibloader_orig_asound
+#define snd_input_stdio_open snd_input_stdio_open_dylibloader_orig_asound
+#define snd_input_stdio_attach snd_input_stdio_attach_dylibloader_orig_asound
+#define snd_input_buffer_open snd_input_buffer_open_dylibloader_orig_asound
+#define snd_input_close snd_input_close_dylibloader_orig_asound
+#define snd_input_scanf snd_input_scanf_dylibloader_orig_asound
+#define snd_input_gets snd_input_gets_dylibloader_orig_asound
+#define snd_input_getc snd_input_getc_dylibloader_orig_asound
+#define snd_input_ungetc snd_input_ungetc_dylibloader_orig_asound
+#define snd_output_stdio_open snd_output_stdio_open_dylibloader_orig_asound
+#define snd_output_stdio_attach snd_output_stdio_attach_dylibloader_orig_asound
+#define snd_output_buffer_open snd_output_buffer_open_dylibloader_orig_asound
+#define snd_output_buffer_string snd_output_buffer_string_dylibloader_orig_asound
+#define snd_output_close snd_output_close_dylibloader_orig_asound
+#define snd_output_printf snd_output_printf_dylibloader_orig_asound
+#define snd_output_vprintf snd_output_vprintf_dylibloader_orig_asound
+#define snd_output_puts snd_output_puts_dylibloader_orig_asound
+#define snd_output_putc snd_output_putc_dylibloader_orig_asound
+#define snd_output_flush snd_output_flush_dylibloader_orig_asound
+#define snd_strerror snd_strerror_dylibloader_orig_asound
+#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_orig_asound
+#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_orig_asound
+#define snd_config_topdir snd_config_topdir_dylibloader_orig_asound
+#define snd_config_top snd_config_top_dylibloader_orig_asound
+#define snd_config_load snd_config_load_dylibloader_orig_asound
+#define snd_config_load_override snd_config_load_override_dylibloader_orig_asound
+#define snd_config_save snd_config_save_dylibloader_orig_asound
+#define snd_config_update snd_config_update_dylibloader_orig_asound
+#define snd_config_update_r snd_config_update_r_dylibloader_orig_asound
+#define snd_config_update_free snd_config_update_free_dylibloader_orig_asound
+#define snd_config_update_free_global snd_config_update_free_global_dylibloader_orig_asound
+#define snd_config_update_ref snd_config_update_ref_dylibloader_orig_asound
+#define snd_config_ref snd_config_ref_dylibloader_orig_asound
+#define snd_config_unref snd_config_unref_dylibloader_orig_asound
+#define snd_config_search snd_config_search_dylibloader_orig_asound
+#define snd_config_searchv snd_config_searchv_dylibloader_orig_asound
+#define snd_config_search_definition snd_config_search_definition_dylibloader_orig_asound
+#define snd_config_expand snd_config_expand_dylibloader_orig_asound
+#define snd_config_evaluate snd_config_evaluate_dylibloader_orig_asound
+#define snd_config_add snd_config_add_dylibloader_orig_asound
+#define snd_config_add_before snd_config_add_before_dylibloader_orig_asound
+#define snd_config_add_after snd_config_add_after_dylibloader_orig_asound
+#define snd_config_remove snd_config_remove_dylibloader_orig_asound
+#define snd_config_delete snd_config_delete_dylibloader_orig_asound
+#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_orig_asound
+#define snd_config_copy snd_config_copy_dylibloader_orig_asound
+#define snd_config_make snd_config_make_dylibloader_orig_asound
+#define snd_config_make_integer snd_config_make_integer_dylibloader_orig_asound
+#define snd_config_make_integer64 snd_config_make_integer64_dylibloader_orig_asound
+#define snd_config_make_real snd_config_make_real_dylibloader_orig_asound
+#define snd_config_make_string snd_config_make_string_dylibloader_orig_asound
+#define snd_config_make_pointer snd_config_make_pointer_dylibloader_orig_asound
+#define snd_config_make_compound snd_config_make_compound_dylibloader_orig_asound
+#define snd_config_imake_integer snd_config_imake_integer_dylibloader_orig_asound
+#define snd_config_imake_integer64 snd_config_imake_integer64_dylibloader_orig_asound
+#define snd_config_imake_real snd_config_imake_real_dylibloader_orig_asound
+#define snd_config_imake_string snd_config_imake_string_dylibloader_orig_asound
+#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_orig_asound
+#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_orig_asound
+#define snd_config_get_type snd_config_get_type_dylibloader_orig_asound
+#define snd_config_is_array snd_config_is_array_dylibloader_orig_asound
+#define snd_config_set_id snd_config_set_id_dylibloader_orig_asound
+#define snd_config_set_integer snd_config_set_integer_dylibloader_orig_asound
+#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_orig_asound
+#define snd_config_set_real snd_config_set_real_dylibloader_orig_asound
+#define snd_config_set_string snd_config_set_string_dylibloader_orig_asound
+#define snd_config_set_ascii snd_config_set_ascii_dylibloader_orig_asound
+#define snd_config_set_pointer snd_config_set_pointer_dylibloader_orig_asound
+#define snd_config_get_id snd_config_get_id_dylibloader_orig_asound
+#define snd_config_get_integer snd_config_get_integer_dylibloader_orig_asound
+#define snd_config_get_integer64 snd_config_get_integer64_dylibloader_orig_asound
+#define snd_config_get_real snd_config_get_real_dylibloader_orig_asound
+#define snd_config_get_ireal snd_config_get_ireal_dylibloader_orig_asound
+#define snd_config_get_string snd_config_get_string_dylibloader_orig_asound
+#define snd_config_get_ascii snd_config_get_ascii_dylibloader_orig_asound
+#define snd_config_get_pointer snd_config_get_pointer_dylibloader_orig_asound
+#define snd_config_test_id snd_config_test_id_dylibloader_orig_asound
+#define snd_config_iterator_first snd_config_iterator_first_dylibloader_orig_asound
+#define snd_config_iterator_next snd_config_iterator_next_dylibloader_orig_asound
+#define snd_config_iterator_end snd_config_iterator_end_dylibloader_orig_asound
+#define snd_config_iterator_entry snd_config_iterator_entry_dylibloader_orig_asound
+#define snd_config_get_bool_ascii snd_config_get_bool_ascii_dylibloader_orig_asound
+#define snd_config_get_bool snd_config_get_bool_dylibloader_orig_asound
+#define snd_config_get_ctl_iface_ascii snd_config_get_ctl_iface_ascii_dylibloader_orig_asound
+#define snd_config_get_ctl_iface snd_config_get_ctl_iface_dylibloader_orig_asound
+#define snd_names_list snd_names_list_dylibloader_orig_asound
+#define snd_names_list_free snd_names_list_free_dylibloader_orig_asound
+#define snd_pcm_open snd_pcm_open_dylibloader_orig_asound
+#define snd_pcm_open_lconf snd_pcm_open_lconf_dylibloader_orig_asound
+#define snd_pcm_open_fallback snd_pcm_open_fallback_dylibloader_orig_asound
+#define snd_pcm_close snd_pcm_close_dylibloader_orig_asound
+#define snd_pcm_name snd_pcm_name_dylibloader_orig_asound
+#define snd_pcm_type snd_pcm_type_dylibloader_orig_asound
+#define snd_pcm_stream snd_pcm_stream_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors_count snd_pcm_poll_descriptors_count_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors snd_pcm_poll_descriptors_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors_revents snd_pcm_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_pcm_nonblock snd_pcm_nonblock_dylibloader_orig_asound
+#define snd_async_add_pcm_handler snd_async_add_pcm_handler_dylibloader_orig_asound
+#define snd_async_handler_get_pcm snd_async_handler_get_pcm_dylibloader_orig_asound
+#define snd_pcm_info snd_pcm_info_dylibloader_orig_asound
+#define snd_pcm_hw_params_current snd_pcm_hw_params_current_dylibloader_orig_asound
+#define snd_pcm_hw_params snd_pcm_hw_params_dylibloader_orig_asound
+#define snd_pcm_hw_free snd_pcm_hw_free_dylibloader_orig_asound
+#define snd_pcm_sw_params_current snd_pcm_sw_params_current_dylibloader_orig_asound
+#define snd_pcm_sw_params snd_pcm_sw_params_dylibloader_orig_asound
+#define snd_pcm_prepare snd_pcm_prepare_dylibloader_orig_asound
+#define snd_pcm_reset snd_pcm_reset_dylibloader_orig_asound
+#define snd_pcm_status snd_pcm_status_dylibloader_orig_asound
+#define snd_pcm_start snd_pcm_start_dylibloader_orig_asound
+#define snd_pcm_drop snd_pcm_drop_dylibloader_orig_asound
+#define snd_pcm_drain snd_pcm_drain_dylibloader_orig_asound
+#define snd_pcm_pause snd_pcm_pause_dylibloader_orig_asound
+#define snd_pcm_state snd_pcm_state_dylibloader_orig_asound
+#define snd_pcm_hwsync snd_pcm_hwsync_dylibloader_orig_asound
+#define snd_pcm_delay snd_pcm_delay_dylibloader_orig_asound
+#define snd_pcm_resume snd_pcm_resume_dylibloader_orig_asound
+#define snd_pcm_htimestamp snd_pcm_htimestamp_dylibloader_orig_asound
+#define snd_pcm_avail snd_pcm_avail_dylibloader_orig_asound
+#define snd_pcm_avail_update snd_pcm_avail_update_dylibloader_orig_asound
+#define snd_pcm_avail_delay snd_pcm_avail_delay_dylibloader_orig_asound
+#define snd_pcm_rewindable snd_pcm_rewindable_dylibloader_orig_asound
+#define snd_pcm_rewind snd_pcm_rewind_dylibloader_orig_asound
+#define snd_pcm_forwardable snd_pcm_forwardable_dylibloader_orig_asound
+#define snd_pcm_forward snd_pcm_forward_dylibloader_orig_asound
+#define snd_pcm_writei snd_pcm_writei_dylibloader_orig_asound
+#define snd_pcm_readi snd_pcm_readi_dylibloader_orig_asound
+#define snd_pcm_writen snd_pcm_writen_dylibloader_orig_asound
+#define snd_pcm_readn snd_pcm_readn_dylibloader_orig_asound
+#define snd_pcm_wait snd_pcm_wait_dylibloader_orig_asound
+#define snd_pcm_link snd_pcm_link_dylibloader_orig_asound
+#define snd_pcm_unlink snd_pcm_unlink_dylibloader_orig_asound
+#define snd_pcm_query_chmaps snd_pcm_query_chmaps_dylibloader_orig_asound
+#define snd_pcm_query_chmaps_from_hw snd_pcm_query_chmaps_from_hw_dylibloader_orig_asound
+#define snd_pcm_free_chmaps snd_pcm_free_chmaps_dylibloader_orig_asound
+#define snd_pcm_get_chmap snd_pcm_get_chmap_dylibloader_orig_asound
+#define snd_pcm_set_chmap snd_pcm_set_chmap_dylibloader_orig_asound
+#define snd_pcm_chmap_type_name snd_pcm_chmap_type_name_dylibloader_orig_asound
+#define snd_pcm_chmap_name snd_pcm_chmap_name_dylibloader_orig_asound
+#define snd_pcm_chmap_long_name snd_pcm_chmap_long_name_dylibloader_orig_asound
+#define snd_pcm_chmap_print snd_pcm_chmap_print_dylibloader_orig_asound
+#define snd_pcm_chmap_from_string snd_pcm_chmap_from_string_dylibloader_orig_asound
+#define snd_pcm_chmap_parse_string snd_pcm_chmap_parse_string_dylibloader_orig_asound
+#define snd_pcm_recover snd_pcm_recover_dylibloader_orig_asound
+#define snd_pcm_set_params snd_pcm_set_params_dylibloader_orig_asound
+#define snd_pcm_get_params snd_pcm_get_params_dylibloader_orig_asound
+#define snd_pcm_info_sizeof snd_pcm_info_sizeof_dylibloader_orig_asound
+#define snd_pcm_info_malloc snd_pcm_info_malloc_dylibloader_orig_asound
+#define snd_pcm_info_free snd_pcm_info_free_dylibloader_orig_asound
+#define snd_pcm_info_copy snd_pcm_info_copy_dylibloader_orig_asound
+#define snd_pcm_info_get_device snd_pcm_info_get_device_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevice snd_pcm_info_get_subdevice_dylibloader_orig_asound
+#define snd_pcm_info_get_stream snd_pcm_info_get_stream_dylibloader_orig_asound
+#define snd_pcm_info_get_card snd_pcm_info_get_card_dylibloader_orig_asound
+#define snd_pcm_info_get_id snd_pcm_info_get_id_dylibloader_orig_asound
+#define snd_pcm_info_get_name snd_pcm_info_get_name_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevice_name snd_pcm_info_get_subdevice_name_dylibloader_orig_asound
+#define snd_pcm_info_get_class snd_pcm_info_get_class_dylibloader_orig_asound
+#define snd_pcm_info_get_subclass snd_pcm_info_get_subclass_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevices_count snd_pcm_info_get_subdevices_count_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevices_avail snd_pcm_info_get_subdevices_avail_dylibloader_orig_asound
+#define snd_pcm_info_get_sync snd_pcm_info_get_sync_dylibloader_orig_asound
+#define snd_pcm_info_set_device snd_pcm_info_set_device_dylibloader_orig_asound
+#define snd_pcm_info_set_subdevice snd_pcm_info_set_subdevice_dylibloader_orig_asound
+#define snd_pcm_info_set_stream snd_pcm_info_set_stream_dylibloader_orig_asound
+#define snd_pcm_hw_params_any snd_pcm_hw_params_any_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_mmap_sample_resolution snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_double snd_pcm_hw_params_is_double_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_batch snd_pcm_hw_params_is_batch_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_block_transfer snd_pcm_hw_params_is_block_transfer_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_monotonic snd_pcm_hw_params_is_monotonic_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_overrange snd_pcm_hw_params_can_overrange_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_pause snd_pcm_hw_params_can_pause_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_resume snd_pcm_hw_params_can_resume_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_half_duplex snd_pcm_hw_params_is_half_duplex_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_joint_duplex snd_pcm_hw_params_is_joint_duplex_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_sync_start snd_pcm_hw_params_can_sync_start_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_disable_period_wakeup snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_supports_audio_wallclock_ts snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_orig_asound
+#define snd_pcm_hw_params_supports_audio_ts_type snd_pcm_hw_params_supports_audio_ts_type_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_numden snd_pcm_hw_params_get_rate_numden_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_sbits snd_pcm_hw_params_get_sbits_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_fifo_size snd_pcm_hw_params_get_fifo_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_sizeof snd_pcm_hw_params_sizeof_dylibloader_orig_asound
+#define snd_pcm_hw_params_malloc snd_pcm_hw_params_malloc_dylibloader_orig_asound
+#define snd_pcm_hw_params_free snd_pcm_hw_params_free_dylibloader_orig_asound
+#define snd_pcm_hw_params_copy snd_pcm_hw_params_copy_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_access snd_pcm_hw_params_get_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_access snd_pcm_hw_params_test_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access snd_pcm_hw_params_set_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_first snd_pcm_hw_params_set_access_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_last snd_pcm_hw_params_set_access_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_mask snd_pcm_hw_params_set_access_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_access_mask snd_pcm_hw_params_get_access_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_format snd_pcm_hw_params_get_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_format snd_pcm_hw_params_test_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format snd_pcm_hw_params_set_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_first snd_pcm_hw_params_set_format_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_last snd_pcm_hw_params_set_format_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_mask snd_pcm_hw_params_set_format_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_format_mask snd_pcm_hw_params_get_format_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_subformat snd_pcm_hw_params_get_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_subformat snd_pcm_hw_params_test_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat snd_pcm_hw_params_set_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_first snd_pcm_hw_params_set_subformat_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_last snd_pcm_hw_params_set_subformat_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_mask snd_pcm_hw_params_set_subformat_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_subformat_mask snd_pcm_hw_params_get_subformat_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels snd_pcm_hw_params_get_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels_min snd_pcm_hw_params_get_channels_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels_max snd_pcm_hw_params_get_channels_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_channels snd_pcm_hw_params_test_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels snd_pcm_hw_params_set_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_min snd_pcm_hw_params_set_channels_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_max snd_pcm_hw_params_set_channels_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_minmax snd_pcm_hw_params_set_channels_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_near snd_pcm_hw_params_set_channels_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_first snd_pcm_hw_params_set_channels_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_last snd_pcm_hw_params_set_channels_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate snd_pcm_hw_params_get_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_min snd_pcm_hw_params_get_rate_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_max snd_pcm_hw_params_get_rate_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_rate snd_pcm_hw_params_test_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate snd_pcm_hw_params_set_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_min snd_pcm_hw_params_set_rate_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_max snd_pcm_hw_params_set_rate_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_minmax snd_pcm_hw_params_set_rate_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_near snd_pcm_hw_params_set_rate_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_first snd_pcm_hw_params_set_rate_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_last snd_pcm_hw_params_set_rate_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_resample snd_pcm_hw_params_set_rate_resample_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_resample snd_pcm_hw_params_get_rate_resample_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_export_buffer snd_pcm_hw_params_set_export_buffer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_export_buffer snd_pcm_hw_params_get_export_buffer_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_wakeup snd_pcm_hw_params_set_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_wakeup snd_pcm_hw_params_get_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time snd_pcm_hw_params_get_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time_min snd_pcm_hw_params_get_period_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time_max snd_pcm_hw_params_get_period_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_period_time snd_pcm_hw_params_test_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time snd_pcm_hw_params_set_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_min snd_pcm_hw_params_set_period_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_max snd_pcm_hw_params_set_period_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_minmax snd_pcm_hw_params_set_period_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_near snd_pcm_hw_params_set_period_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_first snd_pcm_hw_params_set_period_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_last snd_pcm_hw_params_set_period_time_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size snd_pcm_hw_params_get_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size_min snd_pcm_hw_params_get_period_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size_max snd_pcm_hw_params_get_period_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_period_size snd_pcm_hw_params_test_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size snd_pcm_hw_params_set_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_min snd_pcm_hw_params_set_period_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_max snd_pcm_hw_params_set_period_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_minmax snd_pcm_hw_params_set_period_size_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_near snd_pcm_hw_params_set_period_size_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_first snd_pcm_hw_params_set_period_size_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_last snd_pcm_hw_params_set_period_size_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_integer snd_pcm_hw_params_set_period_size_integer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods snd_pcm_hw_params_get_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods_min snd_pcm_hw_params_get_periods_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods_max snd_pcm_hw_params_get_periods_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_periods snd_pcm_hw_params_test_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods snd_pcm_hw_params_set_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_min snd_pcm_hw_params_set_periods_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_max snd_pcm_hw_params_set_periods_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_minmax snd_pcm_hw_params_set_periods_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_near snd_pcm_hw_params_set_periods_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_first snd_pcm_hw_params_set_periods_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_last snd_pcm_hw_params_set_periods_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_integer snd_pcm_hw_params_set_periods_integer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time snd_pcm_hw_params_get_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time_min snd_pcm_hw_params_get_buffer_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time_max snd_pcm_hw_params_get_buffer_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_buffer_time snd_pcm_hw_params_test_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time snd_pcm_hw_params_set_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_min snd_pcm_hw_params_set_buffer_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_max snd_pcm_hw_params_set_buffer_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_minmax snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_near snd_pcm_hw_params_set_buffer_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_first snd_pcm_hw_params_set_buffer_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_last snd_pcm_hw_params_set_buffer_time_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size snd_pcm_hw_params_get_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size_min snd_pcm_hw_params_get_buffer_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size_max snd_pcm_hw_params_get_buffer_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_buffer_size snd_pcm_hw_params_test_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size snd_pcm_hw_params_set_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_min snd_pcm_hw_params_set_buffer_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_max snd_pcm_hw_params_set_buffer_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_minmax snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_near snd_pcm_hw_params_set_buffer_size_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_first snd_pcm_hw_params_set_buffer_size_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_last snd_pcm_hw_params_set_buffer_size_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_min_align snd_pcm_hw_params_get_min_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_sizeof snd_pcm_sw_params_sizeof_dylibloader_orig_asound
+#define snd_pcm_sw_params_malloc snd_pcm_sw_params_malloc_dylibloader_orig_asound
+#define snd_pcm_sw_params_free snd_pcm_sw_params_free_dylibloader_orig_asound
+#define snd_pcm_sw_params_copy snd_pcm_sw_params_copy_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_boundary snd_pcm_sw_params_get_boundary_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_tstamp_mode snd_pcm_sw_params_set_tstamp_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_tstamp_mode snd_pcm_sw_params_get_tstamp_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_avail_min snd_pcm_sw_params_set_avail_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_avail_min snd_pcm_sw_params_get_avail_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_period_event snd_pcm_sw_params_set_period_event_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_period_event snd_pcm_sw_params_get_period_event_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_start_threshold snd_pcm_sw_params_set_start_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_start_threshold snd_pcm_sw_params_get_start_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_stop_threshold snd_pcm_sw_params_set_stop_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_stop_threshold snd_pcm_sw_params_get_stop_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_silence_threshold snd_pcm_sw_params_set_silence_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_silence_threshold snd_pcm_sw_params_get_silence_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_silence_size snd_pcm_sw_params_set_silence_size_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_silence_size snd_pcm_sw_params_get_silence_size_dylibloader_orig_asound
+#define snd_pcm_access_mask_sizeof snd_pcm_access_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_access_mask_malloc snd_pcm_access_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_access_mask_free snd_pcm_access_mask_free_dylibloader_orig_asound
+#define snd_pcm_access_mask_copy snd_pcm_access_mask_copy_dylibloader_orig_asound
+#define snd_pcm_access_mask_none snd_pcm_access_mask_none_dylibloader_orig_asound
+#define snd_pcm_access_mask_any snd_pcm_access_mask_any_dylibloader_orig_asound
+#define snd_pcm_access_mask_test snd_pcm_access_mask_test_dylibloader_orig_asound
+#define snd_pcm_access_mask_empty snd_pcm_access_mask_empty_dylibloader_orig_asound
+#define snd_pcm_access_mask_set snd_pcm_access_mask_set_dylibloader_orig_asound
+#define snd_pcm_access_mask_reset snd_pcm_access_mask_reset_dylibloader_orig_asound
+#define snd_pcm_format_mask_sizeof snd_pcm_format_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_format_mask_malloc snd_pcm_format_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_format_mask_free snd_pcm_format_mask_free_dylibloader_orig_asound
+#define snd_pcm_format_mask_copy snd_pcm_format_mask_copy_dylibloader_orig_asound
+#define snd_pcm_format_mask_none snd_pcm_format_mask_none_dylibloader_orig_asound
+#define snd_pcm_format_mask_any snd_pcm_format_mask_any_dylibloader_orig_asound
+#define snd_pcm_format_mask_test snd_pcm_format_mask_test_dylibloader_orig_asound
+#define snd_pcm_format_mask_empty snd_pcm_format_mask_empty_dylibloader_orig_asound
+#define snd_pcm_format_mask_set snd_pcm_format_mask_set_dylibloader_orig_asound
+#define snd_pcm_format_mask_reset snd_pcm_format_mask_reset_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_sizeof snd_pcm_subformat_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_malloc snd_pcm_subformat_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_free snd_pcm_subformat_mask_free_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_copy snd_pcm_subformat_mask_copy_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_none snd_pcm_subformat_mask_none_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_any snd_pcm_subformat_mask_any_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_test snd_pcm_subformat_mask_test_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_empty snd_pcm_subformat_mask_empty_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_set snd_pcm_subformat_mask_set_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_reset snd_pcm_subformat_mask_reset_dylibloader_orig_asound
+#define snd_pcm_status_sizeof snd_pcm_status_sizeof_dylibloader_orig_asound
+#define snd_pcm_status_malloc snd_pcm_status_malloc_dylibloader_orig_asound
+#define snd_pcm_status_free snd_pcm_status_free_dylibloader_orig_asound
+#define snd_pcm_status_copy snd_pcm_status_copy_dylibloader_orig_asound
+#define snd_pcm_status_get_state snd_pcm_status_get_state_dylibloader_orig_asound
+#define snd_pcm_status_get_trigger_tstamp snd_pcm_status_get_trigger_tstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_trigger_htstamp snd_pcm_status_get_trigger_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_tstamp snd_pcm_status_get_tstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_htstamp snd_pcm_status_get_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_audio_htstamp snd_pcm_status_get_audio_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_driver_htstamp snd_pcm_status_get_driver_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_delay snd_pcm_status_get_delay_dylibloader_orig_asound
+#define snd_pcm_status_get_avail snd_pcm_status_get_avail_dylibloader_orig_asound
+#define snd_pcm_status_get_avail_max snd_pcm_status_get_avail_max_dylibloader_orig_asound
+#define snd_pcm_status_get_overrange snd_pcm_status_get_overrange_dylibloader_orig_asound
+#define snd_pcm_type_name snd_pcm_type_name_dylibloader_orig_asound
+#define snd_pcm_stream_name snd_pcm_stream_name_dylibloader_orig_asound
+#define snd_pcm_access_name snd_pcm_access_name_dylibloader_orig_asound
+#define snd_pcm_format_name snd_pcm_format_name_dylibloader_orig_asound
+#define snd_pcm_format_description snd_pcm_format_description_dylibloader_orig_asound
+#define snd_pcm_subformat_name snd_pcm_subformat_name_dylibloader_orig_asound
+#define snd_pcm_subformat_description snd_pcm_subformat_description_dylibloader_orig_asound
+#define snd_pcm_format_value snd_pcm_format_value_dylibloader_orig_asound
+#define snd_pcm_tstamp_mode_name snd_pcm_tstamp_mode_name_dylibloader_orig_asound
+#define snd_pcm_state_name snd_pcm_state_name_dylibloader_orig_asound
+#define snd_pcm_dump snd_pcm_dump_dylibloader_orig_asound
+#define snd_pcm_dump_hw_setup snd_pcm_dump_hw_setup_dylibloader_orig_asound
+#define snd_pcm_dump_sw_setup snd_pcm_dump_sw_setup_dylibloader_orig_asound
+#define snd_pcm_dump_setup snd_pcm_dump_setup_dylibloader_orig_asound
+#define snd_pcm_hw_params_dump snd_pcm_hw_params_dump_dylibloader_orig_asound
+#define snd_pcm_sw_params_dump snd_pcm_sw_params_dump_dylibloader_orig_asound
+#define snd_pcm_status_dump snd_pcm_status_dump_dylibloader_orig_asound
+#define snd_pcm_mmap_begin snd_pcm_mmap_begin_dylibloader_orig_asound
+#define snd_pcm_mmap_commit snd_pcm_mmap_commit_dylibloader_orig_asound
+#define snd_pcm_mmap_writei snd_pcm_mmap_writei_dylibloader_orig_asound
+#define snd_pcm_mmap_readi snd_pcm_mmap_readi_dylibloader_orig_asound
+#define snd_pcm_mmap_writen snd_pcm_mmap_writen_dylibloader_orig_asound
+#define snd_pcm_mmap_readn snd_pcm_mmap_readn_dylibloader_orig_asound
+#define snd_pcm_format_signed snd_pcm_format_signed_dylibloader_orig_asound
+#define snd_pcm_format_unsigned snd_pcm_format_unsigned_dylibloader_orig_asound
+#define snd_pcm_format_linear snd_pcm_format_linear_dylibloader_orig_asound
+#define snd_pcm_format_float snd_pcm_format_float_dylibloader_orig_asound
+#define snd_pcm_format_little_endian snd_pcm_format_little_endian_dylibloader_orig_asound
+#define snd_pcm_format_big_endian snd_pcm_format_big_endian_dylibloader_orig_asound
+#define snd_pcm_format_cpu_endian snd_pcm_format_cpu_endian_dylibloader_orig_asound
+#define snd_pcm_format_width snd_pcm_format_width_dylibloader_orig_asound
+#define snd_pcm_format_physical_width snd_pcm_format_physical_width_dylibloader_orig_asound
+#define snd_pcm_build_linear_format snd_pcm_build_linear_format_dylibloader_orig_asound
+#define snd_pcm_format_size snd_pcm_format_size_dylibloader_orig_asound
+#define snd_pcm_format_silence snd_pcm_format_silence_dylibloader_orig_asound
+#define snd_pcm_format_silence_16 snd_pcm_format_silence_16_dylibloader_orig_asound
+#define snd_pcm_format_silence_32 snd_pcm_format_silence_32_dylibloader_orig_asound
+#define snd_pcm_format_silence_64 snd_pcm_format_silence_64_dylibloader_orig_asound
+#define snd_pcm_format_set_silence snd_pcm_format_set_silence_dylibloader_orig_asound
+#define snd_pcm_bytes_to_frames snd_pcm_bytes_to_frames_dylibloader_orig_asound
+#define snd_pcm_frames_to_bytes snd_pcm_frames_to_bytes_dylibloader_orig_asound
+#define snd_pcm_bytes_to_samples snd_pcm_bytes_to_samples_dylibloader_orig_asound
+#define snd_pcm_samples_to_bytes snd_pcm_samples_to_bytes_dylibloader_orig_asound
+#define snd_pcm_area_silence snd_pcm_area_silence_dylibloader_orig_asound
+#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_orig_asound
+#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_orig_asound
+#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_orig_asound
+#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_orig_asound
+#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_orig_asound
+#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_orig_asound
+#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_orig_asound
+#define snd_pcm_hook_add snd_pcm_hook_add_dylibloader_orig_asound
+#define snd_pcm_hook_remove snd_pcm_hook_remove_dylibloader_orig_asound
+#define snd_pcm_meter_get_bufsize snd_pcm_meter_get_bufsize_dylibloader_orig_asound
+#define snd_pcm_meter_get_channels snd_pcm_meter_get_channels_dylibloader_orig_asound
+#define snd_pcm_meter_get_rate snd_pcm_meter_get_rate_dylibloader_orig_asound
+#define snd_pcm_meter_get_now snd_pcm_meter_get_now_dylibloader_orig_asound
+#define snd_pcm_meter_get_boundary snd_pcm_meter_get_boundary_dylibloader_orig_asound
+#define snd_pcm_meter_add_scope snd_pcm_meter_add_scope_dylibloader_orig_asound
+#define snd_pcm_meter_search_scope snd_pcm_meter_search_scope_dylibloader_orig_asound
+#define snd_pcm_scope_malloc snd_pcm_scope_malloc_dylibloader_orig_asound
+#define snd_pcm_scope_set_ops snd_pcm_scope_set_ops_dylibloader_orig_asound
+#define snd_pcm_scope_set_name snd_pcm_scope_set_name_dylibloader_orig_asound
+#define snd_pcm_scope_get_name snd_pcm_scope_get_name_dylibloader_orig_asound
+#define snd_pcm_scope_get_callback_private snd_pcm_scope_get_callback_private_dylibloader_orig_asound
+#define snd_pcm_scope_set_callback_private snd_pcm_scope_set_callback_private_dylibloader_orig_asound
+#define snd_pcm_scope_s16_open snd_pcm_scope_s16_open_dylibloader_orig_asound
+#define snd_pcm_scope_s16_get_channel_buffer snd_pcm_scope_s16_get_channel_buffer_dylibloader_orig_asound
+#define snd_spcm_init snd_spcm_init_dylibloader_orig_asound
+#define snd_spcm_init_duplex snd_spcm_init_duplex_dylibloader_orig_asound
+#define snd_spcm_init_get_params snd_spcm_init_get_params_dylibloader_orig_asound
+#define snd_pcm_start_mode_name snd_pcm_start_mode_name_dylibloader_orig_asound
+#define snd_pcm_xrun_mode_name snd_pcm_xrun_mode_name_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_start_mode snd_pcm_sw_params_set_start_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_start_mode snd_pcm_sw_params_get_start_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_xrun_mode snd_pcm_sw_params_set_xrun_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_xrun_mode snd_pcm_sw_params_get_xrun_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_xfer_align snd_pcm_sw_params_set_xfer_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_xfer_align snd_pcm_sw_params_get_xfer_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_sleep_min snd_pcm_sw_params_set_sleep_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_sleep_min snd_pcm_sw_params_get_sleep_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time snd_pcm_hw_params_get_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time_min snd_pcm_hw_params_get_tick_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time_max snd_pcm_hw_params_get_tick_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_tick_time snd_pcm_hw_params_test_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time snd_pcm_hw_params_set_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_min snd_pcm_hw_params_set_tick_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_max snd_pcm_hw_params_set_tick_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_minmax snd_pcm_hw_params_set_tick_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_near snd_pcm_hw_params_set_tick_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_first snd_pcm_hw_params_set_tick_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_last snd_pcm_hw_params_set_tick_time_last_dylibloader_orig_asound
+#define snd_rawmidi_open snd_rawmidi_open_dylibloader_orig_asound
+#define snd_rawmidi_open_lconf snd_rawmidi_open_lconf_dylibloader_orig_asound
+#define snd_rawmidi_close snd_rawmidi_close_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors_count snd_rawmidi_poll_descriptors_count_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors snd_rawmidi_poll_descriptors_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors_revents snd_rawmidi_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_rawmidi_nonblock snd_rawmidi_nonblock_dylibloader_orig_asound
+#define snd_rawmidi_info_sizeof snd_rawmidi_info_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_info_malloc snd_rawmidi_info_malloc_dylibloader_orig_asound
+#define snd_rawmidi_info_free snd_rawmidi_info_free_dylibloader_orig_asound
+#define snd_rawmidi_info_copy snd_rawmidi_info_copy_dylibloader_orig_asound
+#define snd_rawmidi_info_get_device snd_rawmidi_info_get_device_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevice snd_rawmidi_info_get_subdevice_dylibloader_orig_asound
+#define snd_rawmidi_info_get_stream snd_rawmidi_info_get_stream_dylibloader_orig_asound
+#define snd_rawmidi_info_get_card snd_rawmidi_info_get_card_dylibloader_orig_asound
+#define snd_rawmidi_info_get_flags snd_rawmidi_info_get_flags_dylibloader_orig_asound
+#define snd_rawmidi_info_get_id snd_rawmidi_info_get_id_dylibloader_orig_asound
+#define snd_rawmidi_info_get_name snd_rawmidi_info_get_name_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevice_name snd_rawmidi_info_get_subdevice_name_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevices_count snd_rawmidi_info_get_subdevices_count_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevices_avail snd_rawmidi_info_get_subdevices_avail_dylibloader_orig_asound
+#define snd_rawmidi_info_set_device snd_rawmidi_info_set_device_dylibloader_orig_asound
+#define snd_rawmidi_info_set_subdevice snd_rawmidi_info_set_subdevice_dylibloader_orig_asound
+#define snd_rawmidi_info_set_stream snd_rawmidi_info_set_stream_dylibloader_orig_asound
+#define snd_rawmidi_info snd_rawmidi_info_dylibloader_orig_asound
+#define snd_rawmidi_params_sizeof snd_rawmidi_params_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_params_malloc snd_rawmidi_params_malloc_dylibloader_orig_asound
+#define snd_rawmidi_params_free snd_rawmidi_params_free_dylibloader_orig_asound
+#define snd_rawmidi_params_copy snd_rawmidi_params_copy_dylibloader_orig_asound
+#define snd_rawmidi_params_set_buffer_size snd_rawmidi_params_set_buffer_size_dylibloader_orig_asound
+#define snd_rawmidi_params_get_buffer_size snd_rawmidi_params_get_buffer_size_dylibloader_orig_asound
+#define snd_rawmidi_params_set_avail_min snd_rawmidi_params_set_avail_min_dylibloader_orig_asound
+#define snd_rawmidi_params_get_avail_min snd_rawmidi_params_get_avail_min_dylibloader_orig_asound
+#define snd_rawmidi_params_set_no_active_sensing snd_rawmidi_params_set_no_active_sensing_dylibloader_orig_asound
+#define snd_rawmidi_params_get_no_active_sensing snd_rawmidi_params_get_no_active_sensing_dylibloader_orig_asound
+#define snd_rawmidi_params snd_rawmidi_params_dylibloader_orig_asound
+#define snd_rawmidi_params_current snd_rawmidi_params_current_dylibloader_orig_asound
+#define snd_rawmidi_status_sizeof snd_rawmidi_status_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_status_malloc snd_rawmidi_status_malloc_dylibloader_orig_asound
+#define snd_rawmidi_status_free snd_rawmidi_status_free_dylibloader_orig_asound
+#define snd_rawmidi_status_copy snd_rawmidi_status_copy_dylibloader_orig_asound
+#define snd_rawmidi_status_get_tstamp snd_rawmidi_status_get_tstamp_dylibloader_orig_asound
+#define snd_rawmidi_status_get_avail snd_rawmidi_status_get_avail_dylibloader_orig_asound
+#define snd_rawmidi_status_get_xruns snd_rawmidi_status_get_xruns_dylibloader_orig_asound
+#define snd_rawmidi_status snd_rawmidi_status_dylibloader_orig_asound
+#define snd_rawmidi_drain snd_rawmidi_drain_dylibloader_orig_asound
+#define snd_rawmidi_drop snd_rawmidi_drop_dylibloader_orig_asound
+#define snd_rawmidi_write snd_rawmidi_write_dylibloader_orig_asound
+#define snd_rawmidi_read snd_rawmidi_read_dylibloader_orig_asound
+#define snd_rawmidi_name snd_rawmidi_name_dylibloader_orig_asound
+#define snd_rawmidi_type snd_rawmidi_type_dylibloader_orig_asound
+#define snd_rawmidi_stream snd_rawmidi_stream_dylibloader_orig_asound
+#define snd_timer_query_open snd_timer_query_open_dylibloader_orig_asound
+#define snd_timer_query_open_lconf snd_timer_query_open_lconf_dylibloader_orig_asound
+#define snd_timer_query_close snd_timer_query_close_dylibloader_orig_asound
+#define snd_timer_query_next_device snd_timer_query_next_device_dylibloader_orig_asound
+#define snd_timer_query_info snd_timer_query_info_dylibloader_orig_asound
+#define snd_timer_query_params snd_timer_query_params_dylibloader_orig_asound
+#define snd_timer_query_status snd_timer_query_status_dylibloader_orig_asound
+#define snd_timer_open snd_timer_open_dylibloader_orig_asound
+#define snd_timer_open_lconf snd_timer_open_lconf_dylibloader_orig_asound
+#define snd_timer_close snd_timer_close_dylibloader_orig_asound
+#define snd_async_add_timer_handler snd_async_add_timer_handler_dylibloader_orig_asound
+#define snd_async_handler_get_timer snd_async_handler_get_timer_dylibloader_orig_asound
+#define snd_timer_poll_descriptors_count snd_timer_poll_descriptors_count_dylibloader_orig_asound
+#define snd_timer_poll_descriptors snd_timer_poll_descriptors_dylibloader_orig_asound
+#define snd_timer_poll_descriptors_revents snd_timer_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_timer_info snd_timer_info_dylibloader_orig_asound
+#define snd_timer_params snd_timer_params_dylibloader_orig_asound
+#define snd_timer_status snd_timer_status_dylibloader_orig_asound
+#define snd_timer_start snd_timer_start_dylibloader_orig_asound
+#define snd_timer_stop snd_timer_stop_dylibloader_orig_asound
+#define snd_timer_continue snd_timer_continue_dylibloader_orig_asound
+#define snd_timer_read snd_timer_read_dylibloader_orig_asound
+#define snd_timer_id_sizeof snd_timer_id_sizeof_dylibloader_orig_asound
+#define snd_timer_id_malloc snd_timer_id_malloc_dylibloader_orig_asound
+#define snd_timer_id_free snd_timer_id_free_dylibloader_orig_asound
+#define snd_timer_id_copy snd_timer_id_copy_dylibloader_orig_asound
+#define snd_timer_id_set_class snd_timer_id_set_class_dylibloader_orig_asound
+#define snd_timer_id_get_class snd_timer_id_get_class_dylibloader_orig_asound
+#define snd_timer_id_set_sclass snd_timer_id_set_sclass_dylibloader_orig_asound
+#define snd_timer_id_get_sclass snd_timer_id_get_sclass_dylibloader_orig_asound
+#define snd_timer_id_set_card snd_timer_id_set_card_dylibloader_orig_asound
+#define snd_timer_id_get_card snd_timer_id_get_card_dylibloader_orig_asound
+#define snd_timer_id_set_device snd_timer_id_set_device_dylibloader_orig_asound
+#define snd_timer_id_get_device snd_timer_id_get_device_dylibloader_orig_asound
+#define snd_timer_id_set_subdevice snd_timer_id_set_subdevice_dylibloader_orig_asound
+#define snd_timer_id_get_subdevice snd_timer_id_get_subdevice_dylibloader_orig_asound
+#define snd_timer_ginfo_sizeof snd_timer_ginfo_sizeof_dylibloader_orig_asound
+#define snd_timer_ginfo_malloc snd_timer_ginfo_malloc_dylibloader_orig_asound
+#define snd_timer_ginfo_free snd_timer_ginfo_free_dylibloader_orig_asound
+#define snd_timer_ginfo_copy snd_timer_ginfo_copy_dylibloader_orig_asound
+#define snd_timer_ginfo_set_tid snd_timer_ginfo_set_tid_dylibloader_orig_asound
+#define snd_timer_ginfo_get_tid snd_timer_ginfo_get_tid_dylibloader_orig_asound
+#define snd_timer_ginfo_get_flags snd_timer_ginfo_get_flags_dylibloader_orig_asound
+#define snd_timer_ginfo_get_card snd_timer_ginfo_get_card_dylibloader_orig_asound
+#define snd_timer_ginfo_get_id snd_timer_ginfo_get_id_dylibloader_orig_asound
+#define snd_timer_ginfo_get_name snd_timer_ginfo_get_name_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution snd_timer_ginfo_get_resolution_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution_min snd_timer_ginfo_get_resolution_min_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution_max snd_timer_ginfo_get_resolution_max_dylibloader_orig_asound
+#define snd_timer_ginfo_get_clients snd_timer_ginfo_get_clients_dylibloader_orig_asound
+#define snd_timer_info_sizeof snd_timer_info_sizeof_dylibloader_orig_asound
+#define snd_timer_info_malloc snd_timer_info_malloc_dylibloader_orig_asound
+#define snd_timer_info_free snd_timer_info_free_dylibloader_orig_asound
+#define snd_timer_info_copy snd_timer_info_copy_dylibloader_orig_asound
+#define snd_timer_info_is_slave snd_timer_info_is_slave_dylibloader_orig_asound
+#define snd_timer_info_get_card snd_timer_info_get_card_dylibloader_orig_asound
+#define snd_timer_info_get_id snd_timer_info_get_id_dylibloader_orig_asound
+#define snd_timer_info_get_name snd_timer_info_get_name_dylibloader_orig_asound
+#define snd_timer_info_get_resolution snd_timer_info_get_resolution_dylibloader_orig_asound
+#define snd_timer_params_sizeof snd_timer_params_sizeof_dylibloader_orig_asound
+#define snd_timer_params_malloc snd_timer_params_malloc_dylibloader_orig_asound
+#define snd_timer_params_free snd_timer_params_free_dylibloader_orig_asound
+#define snd_timer_params_copy snd_timer_params_copy_dylibloader_orig_asound
+#define snd_timer_params_set_auto_start snd_timer_params_set_auto_start_dylibloader_orig_asound
+#define snd_timer_params_get_auto_start snd_timer_params_get_auto_start_dylibloader_orig_asound
+#define snd_timer_params_set_exclusive snd_timer_params_set_exclusive_dylibloader_orig_asound
+#define snd_timer_params_get_exclusive snd_timer_params_get_exclusive_dylibloader_orig_asound
+#define snd_timer_params_set_early_event snd_timer_params_set_early_event_dylibloader_orig_asound
+#define snd_timer_params_get_early_event snd_timer_params_get_early_event_dylibloader_orig_asound
+#define snd_timer_params_set_ticks snd_timer_params_set_ticks_dylibloader_orig_asound
+#define snd_timer_params_get_ticks snd_timer_params_get_ticks_dylibloader_orig_asound
+#define snd_timer_params_set_queue_size snd_timer_params_set_queue_size_dylibloader_orig_asound
+#define snd_timer_params_get_queue_size snd_timer_params_get_queue_size_dylibloader_orig_asound
+#define snd_timer_params_set_filter snd_timer_params_set_filter_dylibloader_orig_asound
+#define snd_timer_params_get_filter snd_timer_params_get_filter_dylibloader_orig_asound
+#define snd_timer_status_sizeof snd_timer_status_sizeof_dylibloader_orig_asound
+#define snd_timer_status_malloc snd_timer_status_malloc_dylibloader_orig_asound
+#define snd_timer_status_free snd_timer_status_free_dylibloader_orig_asound
+#define snd_timer_status_copy snd_timer_status_copy_dylibloader_orig_asound
+#define snd_timer_status_get_timestamp snd_timer_status_get_timestamp_dylibloader_orig_asound
+#define snd_timer_status_get_resolution snd_timer_status_get_resolution_dylibloader_orig_asound
+#define snd_timer_status_get_lost snd_timer_status_get_lost_dylibloader_orig_asound
+#define snd_timer_status_get_overrun snd_timer_status_get_overrun_dylibloader_orig_asound
+#define snd_timer_status_get_queue snd_timer_status_get_queue_dylibloader_orig_asound
+#define snd_timer_info_get_ticks snd_timer_info_get_ticks_dylibloader_orig_asound
+#define snd_hwdep_open snd_hwdep_open_dylibloader_orig_asound
+#define snd_hwdep_close snd_hwdep_close_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors snd_hwdep_poll_descriptors_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors_count snd_hwdep_poll_descriptors_count_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors_revents snd_hwdep_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_hwdep_nonblock snd_hwdep_nonblock_dylibloader_orig_asound
+#define snd_hwdep_info snd_hwdep_info_dylibloader_orig_asound
+#define snd_hwdep_dsp_status snd_hwdep_dsp_status_dylibloader_orig_asound
+#define snd_hwdep_dsp_load snd_hwdep_dsp_load_dylibloader_orig_asound
+#define snd_hwdep_ioctl snd_hwdep_ioctl_dylibloader_orig_asound
+#define snd_hwdep_write snd_hwdep_write_dylibloader_orig_asound
+#define snd_hwdep_read snd_hwdep_read_dylibloader_orig_asound
+#define snd_hwdep_info_sizeof snd_hwdep_info_sizeof_dylibloader_orig_asound
+#define snd_hwdep_info_malloc snd_hwdep_info_malloc_dylibloader_orig_asound
+#define snd_hwdep_info_free snd_hwdep_info_free_dylibloader_orig_asound
+#define snd_hwdep_info_copy snd_hwdep_info_copy_dylibloader_orig_asound
+#define snd_hwdep_info_get_device snd_hwdep_info_get_device_dylibloader_orig_asound
+#define snd_hwdep_info_get_card snd_hwdep_info_get_card_dylibloader_orig_asound
+#define snd_hwdep_info_get_id snd_hwdep_info_get_id_dylibloader_orig_asound
+#define snd_hwdep_info_get_name snd_hwdep_info_get_name_dylibloader_orig_asound
+#define snd_hwdep_info_get_iface snd_hwdep_info_get_iface_dylibloader_orig_asound
+#define snd_hwdep_info_set_device snd_hwdep_info_set_device_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_sizeof snd_hwdep_dsp_status_sizeof_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_malloc snd_hwdep_dsp_status_malloc_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_free snd_hwdep_dsp_status_free_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_copy snd_hwdep_dsp_status_copy_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_version snd_hwdep_dsp_status_get_version_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_id snd_hwdep_dsp_status_get_id_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_num_dsps snd_hwdep_dsp_status_get_num_dsps_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_dsp_loaded snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_chip_ready snd_hwdep_dsp_status_get_chip_ready_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_sizeof snd_hwdep_dsp_image_sizeof_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_malloc snd_hwdep_dsp_image_malloc_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_free snd_hwdep_dsp_image_free_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_copy snd_hwdep_dsp_image_copy_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_index snd_hwdep_dsp_image_get_index_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_name snd_hwdep_dsp_image_get_name_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_image snd_hwdep_dsp_image_get_image_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_length snd_hwdep_dsp_image_get_length_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_index snd_hwdep_dsp_image_set_index_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_name snd_hwdep_dsp_image_set_name_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_image snd_hwdep_dsp_image_set_image_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_length snd_hwdep_dsp_image_set_length_dylibloader_orig_asound
+#define snd_card_load snd_card_load_dylibloader_orig_asound
+#define snd_card_next snd_card_next_dylibloader_orig_asound
+#define snd_card_get_index snd_card_get_index_dylibloader_orig_asound
+#define snd_card_get_name snd_card_get_name_dylibloader_orig_asound
+#define snd_card_get_longname snd_card_get_longname_dylibloader_orig_asound
+#define snd_device_name_hint snd_device_name_hint_dylibloader_orig_asound
+#define snd_device_name_free_hint snd_device_name_free_hint_dylibloader_orig_asound
+#define snd_device_name_get_hint snd_device_name_get_hint_dylibloader_orig_asound
+#define snd_ctl_open snd_ctl_open_dylibloader_orig_asound
+#define snd_ctl_open_lconf snd_ctl_open_lconf_dylibloader_orig_asound
+#define snd_ctl_open_fallback snd_ctl_open_fallback_dylibloader_orig_asound
+#define snd_ctl_close snd_ctl_close_dylibloader_orig_asound
+#define snd_ctl_nonblock snd_ctl_nonblock_dylibloader_orig_asound
+#define snd_async_add_ctl_handler snd_async_add_ctl_handler_dylibloader_orig_asound
+#define snd_async_handler_get_ctl snd_async_handler_get_ctl_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors_count snd_ctl_poll_descriptors_count_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors snd_ctl_poll_descriptors_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors_revents snd_ctl_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_ctl_subscribe_events snd_ctl_subscribe_events_dylibloader_orig_asound
+#define snd_ctl_card_info snd_ctl_card_info_dylibloader_orig_asound
+#define snd_ctl_elem_list snd_ctl_elem_list_dylibloader_orig_asound
+#define snd_ctl_elem_info snd_ctl_elem_info_dylibloader_orig_asound
+#define snd_ctl_elem_read snd_ctl_elem_read_dylibloader_orig_asound
+#define snd_ctl_elem_write snd_ctl_elem_write_dylibloader_orig_asound
+#define snd_ctl_elem_lock snd_ctl_elem_lock_dylibloader_orig_asound
+#define snd_ctl_elem_unlock snd_ctl_elem_unlock_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_read snd_ctl_elem_tlv_read_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_write snd_ctl_elem_tlv_write_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_command snd_ctl_elem_tlv_command_dylibloader_orig_asound
+#define snd_ctl_hwdep_next_device snd_ctl_hwdep_next_device_dylibloader_orig_asound
+#define snd_ctl_hwdep_info snd_ctl_hwdep_info_dylibloader_orig_asound
+#define snd_ctl_pcm_next_device snd_ctl_pcm_next_device_dylibloader_orig_asound
+#define snd_ctl_pcm_info snd_ctl_pcm_info_dylibloader_orig_asound
+#define snd_ctl_pcm_prefer_subdevice snd_ctl_pcm_prefer_subdevice_dylibloader_orig_asound
+#define snd_ctl_rawmidi_next_device snd_ctl_rawmidi_next_device_dylibloader_orig_asound
+#define snd_ctl_rawmidi_info snd_ctl_rawmidi_info_dylibloader_orig_asound
+#define snd_ctl_rawmidi_prefer_subdevice snd_ctl_rawmidi_prefer_subdevice_dylibloader_orig_asound
+#define snd_ctl_set_power_state snd_ctl_set_power_state_dylibloader_orig_asound
+#define snd_ctl_get_power_state snd_ctl_get_power_state_dylibloader_orig_asound
+#define snd_ctl_read snd_ctl_read_dylibloader_orig_asound
+#define snd_ctl_wait snd_ctl_wait_dylibloader_orig_asound
+#define snd_ctl_name snd_ctl_name_dylibloader_orig_asound
+#define snd_ctl_type snd_ctl_type_dylibloader_orig_asound
+#define snd_ctl_elem_type_name snd_ctl_elem_type_name_dylibloader_orig_asound
+#define snd_ctl_elem_iface_name snd_ctl_elem_iface_name_dylibloader_orig_asound
+#define snd_ctl_event_type_name snd_ctl_event_type_name_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_mask snd_ctl_event_elem_get_mask_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_numid snd_ctl_event_elem_get_numid_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_id snd_ctl_event_elem_get_id_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_interface snd_ctl_event_elem_get_interface_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_device snd_ctl_event_elem_get_device_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_subdevice snd_ctl_event_elem_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_name snd_ctl_event_elem_get_name_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_index snd_ctl_event_elem_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_list_alloc_space snd_ctl_elem_list_alloc_space_dylibloader_orig_asound
+#define snd_ctl_elem_list_free_space snd_ctl_elem_list_free_space_dylibloader_orig_asound
+#define snd_ctl_ascii_elem_id_get snd_ctl_ascii_elem_id_get_dylibloader_orig_asound
+#define snd_ctl_ascii_elem_id_parse snd_ctl_ascii_elem_id_parse_dylibloader_orig_asound
+#define snd_ctl_ascii_value_parse snd_ctl_ascii_value_parse_dylibloader_orig_asound
+#define snd_ctl_elem_id_sizeof snd_ctl_elem_id_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_id_malloc snd_ctl_elem_id_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_id_free snd_ctl_elem_id_free_dylibloader_orig_asound
+#define snd_ctl_elem_id_clear snd_ctl_elem_id_clear_dylibloader_orig_asound
+#define snd_ctl_elem_id_copy snd_ctl_elem_id_copy_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_numid snd_ctl_elem_id_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_interface snd_ctl_elem_id_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_device snd_ctl_elem_id_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_subdevice snd_ctl_elem_id_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_name snd_ctl_elem_id_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_index snd_ctl_elem_id_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_numid snd_ctl_elem_id_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_interface snd_ctl_elem_id_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_device snd_ctl_elem_id_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_subdevice snd_ctl_elem_id_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_name snd_ctl_elem_id_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_index snd_ctl_elem_id_set_index_dylibloader_orig_asound
+#define snd_ctl_card_info_sizeof snd_ctl_card_info_sizeof_dylibloader_orig_asound
+#define snd_ctl_card_info_malloc snd_ctl_card_info_malloc_dylibloader_orig_asound
+#define snd_ctl_card_info_free snd_ctl_card_info_free_dylibloader_orig_asound
+#define snd_ctl_card_info_clear snd_ctl_card_info_clear_dylibloader_orig_asound
+#define snd_ctl_card_info_copy snd_ctl_card_info_copy_dylibloader_orig_asound
+#define snd_ctl_card_info_get_card snd_ctl_card_info_get_card_dylibloader_orig_asound
+#define snd_ctl_card_info_get_id snd_ctl_card_info_get_id_dylibloader_orig_asound
+#define snd_ctl_card_info_get_driver snd_ctl_card_info_get_driver_dylibloader_orig_asound
+#define snd_ctl_card_info_get_name snd_ctl_card_info_get_name_dylibloader_orig_asound
+#define snd_ctl_card_info_get_longname snd_ctl_card_info_get_longname_dylibloader_orig_asound
+#define snd_ctl_card_info_get_mixername snd_ctl_card_info_get_mixername_dylibloader_orig_asound
+#define snd_ctl_card_info_get_components snd_ctl_card_info_get_components_dylibloader_orig_asound
+#define snd_ctl_event_sizeof snd_ctl_event_sizeof_dylibloader_orig_asound
+#define snd_ctl_event_malloc snd_ctl_event_malloc_dylibloader_orig_asound
+#define snd_ctl_event_free snd_ctl_event_free_dylibloader_orig_asound
+#define snd_ctl_event_clear snd_ctl_event_clear_dylibloader_orig_asound
+#define snd_ctl_event_copy snd_ctl_event_copy_dylibloader_orig_asound
+#define snd_ctl_event_get_type snd_ctl_event_get_type_dylibloader_orig_asound
+#define snd_ctl_elem_list_sizeof snd_ctl_elem_list_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_list_malloc snd_ctl_elem_list_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_list_free snd_ctl_elem_list_free_dylibloader_orig_asound
+#define snd_ctl_elem_list_clear snd_ctl_elem_list_clear_dylibloader_orig_asound
+#define snd_ctl_elem_list_copy snd_ctl_elem_list_copy_dylibloader_orig_asound
+#define snd_ctl_elem_list_set_offset snd_ctl_elem_list_set_offset_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_used snd_ctl_elem_list_get_used_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_count snd_ctl_elem_list_get_count_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_id snd_ctl_elem_list_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_numid snd_ctl_elem_list_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_interface snd_ctl_elem_list_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_device snd_ctl_elem_list_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_subdevice snd_ctl_elem_list_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_name snd_ctl_elem_list_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_index snd_ctl_elem_list_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_info_sizeof snd_ctl_elem_info_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_info_malloc snd_ctl_elem_info_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_info_free snd_ctl_elem_info_free_dylibloader_orig_asound
+#define snd_ctl_elem_info_clear snd_ctl_elem_info_clear_dylibloader_orig_asound
+#define snd_ctl_elem_info_copy snd_ctl_elem_info_copy_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_type snd_ctl_elem_info_get_type_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_readable snd_ctl_elem_info_is_readable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_writable snd_ctl_elem_info_is_writable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_volatile snd_ctl_elem_info_is_volatile_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_inactive snd_ctl_elem_info_is_inactive_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_locked snd_ctl_elem_info_is_locked_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_readable snd_ctl_elem_info_is_tlv_readable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_writable snd_ctl_elem_info_is_tlv_writable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_commandable snd_ctl_elem_info_is_tlv_commandable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_owner snd_ctl_elem_info_is_owner_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_user snd_ctl_elem_info_is_user_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_owner snd_ctl_elem_info_get_owner_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_count snd_ctl_elem_info_get_count_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_min snd_ctl_elem_info_get_min_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_max snd_ctl_elem_info_get_max_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_step snd_ctl_elem_info_get_step_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_min64 snd_ctl_elem_info_get_min64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_max64 snd_ctl_elem_info_get_max64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_step64 snd_ctl_elem_info_get_step64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_items snd_ctl_elem_info_get_items_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_item snd_ctl_elem_info_set_item_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_item_name snd_ctl_elem_info_get_item_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_dimensions snd_ctl_elem_info_get_dimensions_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_dimension snd_ctl_elem_info_get_dimension_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_dimension snd_ctl_elem_info_set_dimension_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_id snd_ctl_elem_info_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_numid snd_ctl_elem_info_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_interface snd_ctl_elem_info_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_device snd_ctl_elem_info_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_subdevice snd_ctl_elem_info_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_name snd_ctl_elem_info_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_index snd_ctl_elem_info_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_id snd_ctl_elem_info_set_id_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_numid snd_ctl_elem_info_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_interface snd_ctl_elem_info_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_device snd_ctl_elem_info_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_subdevice snd_ctl_elem_info_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_name snd_ctl_elem_info_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_index snd_ctl_elem_info_set_index_dylibloader_orig_asound
+#define snd_ctl_add_integer_elem_set snd_ctl_add_integer_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_integer64_elem_set snd_ctl_add_integer64_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_boolean_elem_set snd_ctl_add_boolean_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_enumerated_elem_set snd_ctl_add_enumerated_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_bytes_elem_set snd_ctl_add_bytes_elem_set_dylibloader_orig_asound
+#define snd_ctl_elem_add_integer snd_ctl_elem_add_integer_dylibloader_orig_asound
+#define snd_ctl_elem_add_integer64 snd_ctl_elem_add_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_add_boolean snd_ctl_elem_add_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_add_enumerated snd_ctl_elem_add_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_add_iec958 snd_ctl_elem_add_iec958_dylibloader_orig_asound
+#define snd_ctl_elem_remove snd_ctl_elem_remove_dylibloader_orig_asound
+#define snd_ctl_elem_value_sizeof snd_ctl_elem_value_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_value_malloc snd_ctl_elem_value_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_value_free snd_ctl_elem_value_free_dylibloader_orig_asound
+#define snd_ctl_elem_value_clear snd_ctl_elem_value_clear_dylibloader_orig_asound
+#define snd_ctl_elem_value_copy snd_ctl_elem_value_copy_dylibloader_orig_asound
+#define snd_ctl_elem_value_compare snd_ctl_elem_value_compare_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_id snd_ctl_elem_value_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_numid snd_ctl_elem_value_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_interface snd_ctl_elem_value_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_device snd_ctl_elem_value_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_subdevice snd_ctl_elem_value_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_name snd_ctl_elem_value_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_index snd_ctl_elem_value_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_id snd_ctl_elem_value_set_id_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_numid snd_ctl_elem_value_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_interface snd_ctl_elem_value_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_device snd_ctl_elem_value_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_subdevice snd_ctl_elem_value_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_name snd_ctl_elem_value_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_index snd_ctl_elem_value_set_index_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_boolean snd_ctl_elem_value_get_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_integer snd_ctl_elem_value_get_integer_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_integer64 snd_ctl_elem_value_get_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_enumerated snd_ctl_elem_value_get_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_byte snd_ctl_elem_value_get_byte_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_boolean snd_ctl_elem_value_set_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_integer snd_ctl_elem_value_set_integer_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_integer64 snd_ctl_elem_value_set_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_enumerated snd_ctl_elem_value_set_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_byte snd_ctl_elem_value_set_byte_dylibloader_orig_asound
+#define snd_ctl_elem_set_bytes snd_ctl_elem_set_bytes_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_bytes snd_ctl_elem_value_get_bytes_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_iec958 snd_ctl_elem_value_get_iec958_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_iec958 snd_ctl_elem_value_set_iec958_dylibloader_orig_asound
+#define snd_tlv_parse_dB_info snd_tlv_parse_dB_info_dylibloader_orig_asound
+#define snd_tlv_get_dB_range snd_tlv_get_dB_range_dylibloader_orig_asound
+#define snd_tlv_convert_to_dB snd_tlv_convert_to_dB_dylibloader_orig_asound
+#define snd_tlv_convert_from_dB snd_tlv_convert_from_dB_dylibloader_orig_asound
+#define snd_ctl_get_dB_range snd_ctl_get_dB_range_dylibloader_orig_asound
+#define snd_ctl_convert_to_dB snd_ctl_convert_to_dB_dylibloader_orig_asound
+#define snd_ctl_convert_from_dB snd_ctl_convert_from_dB_dylibloader_orig_asound
+#define snd_hctl_compare_fast snd_hctl_compare_fast_dylibloader_orig_asound
+#define snd_hctl_open snd_hctl_open_dylibloader_orig_asound
+#define snd_hctl_open_ctl snd_hctl_open_ctl_dylibloader_orig_asound
+#define snd_hctl_close snd_hctl_close_dylibloader_orig_asound
+#define snd_hctl_nonblock snd_hctl_nonblock_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors_count snd_hctl_poll_descriptors_count_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors snd_hctl_poll_descriptors_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors_revents snd_hctl_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_hctl_get_count snd_hctl_get_count_dylibloader_orig_asound
+#define snd_hctl_set_compare snd_hctl_set_compare_dylibloader_orig_asound
+#define snd_hctl_first_elem snd_hctl_first_elem_dylibloader_orig_asound
+#define snd_hctl_last_elem snd_hctl_last_elem_dylibloader_orig_asound
+#define snd_hctl_find_elem snd_hctl_find_elem_dylibloader_orig_asound
+#define snd_hctl_set_callback snd_hctl_set_callback_dylibloader_orig_asound
+#define snd_hctl_set_callback_private snd_hctl_set_callback_private_dylibloader_orig_asound
+#define snd_hctl_get_callback_private snd_hctl_get_callback_private_dylibloader_orig_asound
+#define snd_hctl_load snd_hctl_load_dylibloader_orig_asound
+#define snd_hctl_free snd_hctl_free_dylibloader_orig_asound
+#define snd_hctl_handle_events snd_hctl_handle_events_dylibloader_orig_asound
+#define snd_hctl_name snd_hctl_name_dylibloader_orig_asound
+#define snd_hctl_wait snd_hctl_wait_dylibloader_orig_asound
+#define snd_hctl_ctl snd_hctl_ctl_dylibloader_orig_asound
+#define snd_hctl_elem_next snd_hctl_elem_next_dylibloader_orig_asound
+#define snd_hctl_elem_prev snd_hctl_elem_prev_dylibloader_orig_asound
+#define snd_hctl_elem_info snd_hctl_elem_info_dylibloader_orig_asound
+#define snd_hctl_elem_read snd_hctl_elem_read_dylibloader_orig_asound
+#define snd_hctl_elem_write snd_hctl_elem_write_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_read snd_hctl_elem_tlv_read_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_write snd_hctl_elem_tlv_write_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_command snd_hctl_elem_tlv_command_dylibloader_orig_asound
+#define snd_hctl_elem_get_hctl snd_hctl_elem_get_hctl_dylibloader_orig_asound
+#define snd_hctl_elem_get_id snd_hctl_elem_get_id_dylibloader_orig_asound
+#define snd_hctl_elem_get_numid snd_hctl_elem_get_numid_dylibloader_orig_asound
+#define snd_hctl_elem_get_interface snd_hctl_elem_get_interface_dylibloader_orig_asound
+#define snd_hctl_elem_get_device snd_hctl_elem_get_device_dylibloader_orig_asound
+#define snd_hctl_elem_get_subdevice snd_hctl_elem_get_subdevice_dylibloader_orig_asound
+#define snd_hctl_elem_get_name snd_hctl_elem_get_name_dylibloader_orig_asound
+#define snd_hctl_elem_get_index snd_hctl_elem_get_index_dylibloader_orig_asound
+#define snd_hctl_elem_set_callback snd_hctl_elem_set_callback_dylibloader_orig_asound
+#define snd_hctl_elem_get_callback_private snd_hctl_elem_get_callback_private_dylibloader_orig_asound
+#define snd_hctl_elem_set_callback_private snd_hctl_elem_set_callback_private_dylibloader_orig_asound
+#define snd_sctl_build snd_sctl_build_dylibloader_orig_asound
+#define snd_sctl_free snd_sctl_free_dylibloader_orig_asound
+#define snd_sctl_install snd_sctl_install_dylibloader_orig_asound
+#define snd_sctl_remove snd_sctl_remove_dylibloader_orig_asound
+#define snd_mixer_open snd_mixer_open_dylibloader_orig_asound
+#define snd_mixer_close snd_mixer_close_dylibloader_orig_asound
+#define snd_mixer_first_elem snd_mixer_first_elem_dylibloader_orig_asound
+#define snd_mixer_last_elem snd_mixer_last_elem_dylibloader_orig_asound
+#define snd_mixer_handle_events snd_mixer_handle_events_dylibloader_orig_asound
+#define snd_mixer_attach snd_mixer_attach_dylibloader_orig_asound
+#define snd_mixer_attach_hctl snd_mixer_attach_hctl_dylibloader_orig_asound
+#define snd_mixer_detach snd_mixer_detach_dylibloader_orig_asound
+#define snd_mixer_detach_hctl snd_mixer_detach_hctl_dylibloader_orig_asound
+#define snd_mixer_get_hctl snd_mixer_get_hctl_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors_count snd_mixer_poll_descriptors_count_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors snd_mixer_poll_descriptors_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors_revents snd_mixer_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_mixer_load snd_mixer_load_dylibloader_orig_asound
+#define snd_mixer_free snd_mixer_free_dylibloader_orig_asound
+#define snd_mixer_wait snd_mixer_wait_dylibloader_orig_asound
+#define snd_mixer_set_compare snd_mixer_set_compare_dylibloader_orig_asound
+#define snd_mixer_set_callback snd_mixer_set_callback_dylibloader_orig_asound
+#define snd_mixer_get_callback_private snd_mixer_get_callback_private_dylibloader_orig_asound
+#define snd_mixer_set_callback_private snd_mixer_set_callback_private_dylibloader_orig_asound
+#define snd_mixer_get_count snd_mixer_get_count_dylibloader_orig_asound
+#define snd_mixer_class_unregister snd_mixer_class_unregister_dylibloader_orig_asound
+#define snd_mixer_elem_next snd_mixer_elem_next_dylibloader_orig_asound
+#define snd_mixer_elem_prev snd_mixer_elem_prev_dylibloader_orig_asound
+#define snd_mixer_elem_set_callback snd_mixer_elem_set_callback_dylibloader_orig_asound
+#define snd_mixer_elem_get_callback_private snd_mixer_elem_get_callback_private_dylibloader_orig_asound
+#define snd_mixer_elem_set_callback_private snd_mixer_elem_set_callback_private_dylibloader_orig_asound
+#define snd_mixer_elem_get_type snd_mixer_elem_get_type_dylibloader_orig_asound
+#define snd_mixer_class_register snd_mixer_class_register_dylibloader_orig_asound
+#define snd_mixer_elem_new snd_mixer_elem_new_dylibloader_orig_asound
+#define snd_mixer_elem_add snd_mixer_elem_add_dylibloader_orig_asound
+#define snd_mixer_elem_remove snd_mixer_elem_remove_dylibloader_orig_asound
+#define snd_mixer_elem_free snd_mixer_elem_free_dylibloader_orig_asound
+#define snd_mixer_elem_info snd_mixer_elem_info_dylibloader_orig_asound
+#define snd_mixer_elem_value snd_mixer_elem_value_dylibloader_orig_asound
+#define snd_mixer_elem_attach snd_mixer_elem_attach_dylibloader_orig_asound
+#define snd_mixer_elem_detach snd_mixer_elem_detach_dylibloader_orig_asound
+#define snd_mixer_elem_empty snd_mixer_elem_empty_dylibloader_orig_asound
+#define snd_mixer_elem_get_private snd_mixer_elem_get_private_dylibloader_orig_asound
+#define snd_mixer_class_sizeof snd_mixer_class_sizeof_dylibloader_orig_asound
+#define snd_mixer_class_malloc snd_mixer_class_malloc_dylibloader_orig_asound
+#define snd_mixer_class_free snd_mixer_class_free_dylibloader_orig_asound
+#define snd_mixer_class_copy snd_mixer_class_copy_dylibloader_orig_asound
+#define snd_mixer_class_get_mixer snd_mixer_class_get_mixer_dylibloader_orig_asound
+#define snd_mixer_class_get_event snd_mixer_class_get_event_dylibloader_orig_asound
+#define snd_mixer_class_get_private snd_mixer_class_get_private_dylibloader_orig_asound
+#define snd_mixer_class_get_compare snd_mixer_class_get_compare_dylibloader_orig_asound
+#define snd_mixer_class_set_event snd_mixer_class_set_event_dylibloader_orig_asound
+#define snd_mixer_class_set_private snd_mixer_class_set_private_dylibloader_orig_asound
+#define snd_mixer_class_set_private_free snd_mixer_class_set_private_free_dylibloader_orig_asound
+#define snd_mixer_class_set_compare snd_mixer_class_set_compare_dylibloader_orig_asound
+#define snd_mixer_selem_channel_name snd_mixer_selem_channel_name_dylibloader_orig_asound
+#define snd_mixer_selem_register snd_mixer_selem_register_dylibloader_orig_asound
+#define snd_mixer_selem_get_id snd_mixer_selem_get_id_dylibloader_orig_asound
+#define snd_mixer_selem_get_name snd_mixer_selem_get_name_dylibloader_orig_asound
+#define snd_mixer_selem_get_index snd_mixer_selem_get_index_dylibloader_orig_asound
+#define snd_mixer_find_selem snd_mixer_find_selem_dylibloader_orig_asound
+#define snd_mixer_selem_is_active snd_mixer_selem_is_active_dylibloader_orig_asound
+#define snd_mixer_selem_is_playback_mono snd_mixer_selem_is_playback_mono_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_channel snd_mixer_selem_has_playback_channel_dylibloader_orig_asound
+#define snd_mixer_selem_is_capture_mono snd_mixer_selem_is_capture_mono_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_channel snd_mixer_selem_has_capture_channel_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_group snd_mixer_selem_get_capture_group_dylibloader_orig_asound
+#define snd_mixer_selem_has_common_volume snd_mixer_selem_has_common_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_volume snd_mixer_selem_has_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_volume_joined snd_mixer_selem_has_playback_volume_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_volume snd_mixer_selem_has_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_volume_joined snd_mixer_selem_has_capture_volume_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_common_switch snd_mixer_selem_has_common_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_switch snd_mixer_selem_has_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_switch_joined snd_mixer_selem_has_playback_switch_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch snd_mixer_selem_has_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch_joined snd_mixer_selem_has_capture_switch_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch_exclusive snd_mixer_selem_has_capture_switch_exclusive_dylibloader_orig_asound
+#define snd_mixer_selem_ask_playback_vol_dB snd_mixer_selem_ask_playback_vol_dB_dylibloader_orig_asound
+#define snd_mixer_selem_ask_capture_vol_dB snd_mixer_selem_ask_capture_vol_dB_dylibloader_orig_asound
+#define snd_mixer_selem_ask_playback_dB_vol snd_mixer_selem_ask_playback_dB_vol_dylibloader_orig_asound
+#define snd_mixer_selem_ask_capture_dB_vol snd_mixer_selem_ask_capture_dB_vol_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_volume snd_mixer_selem_get_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_volume snd_mixer_selem_get_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_dB snd_mixer_selem_get_playback_dB_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_dB snd_mixer_selem_get_capture_dB_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_switch snd_mixer_selem_get_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_switch snd_mixer_selem_get_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume snd_mixer_selem_set_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume snd_mixer_selem_set_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_dB snd_mixer_selem_set_playback_dB_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_dB snd_mixer_selem_set_capture_dB_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume_all snd_mixer_selem_set_playback_volume_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume_all snd_mixer_selem_set_capture_volume_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_dB_all snd_mixer_selem_set_playback_dB_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_dB_all snd_mixer_selem_set_capture_dB_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_switch snd_mixer_selem_set_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_switch snd_mixer_selem_set_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_switch_all snd_mixer_selem_set_playback_switch_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_switch_all snd_mixer_selem_set_capture_switch_all_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_volume_range snd_mixer_selem_get_playback_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_dB_range snd_mixer_selem_get_playback_dB_range_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume_range snd_mixer_selem_set_playback_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_volume_range snd_mixer_selem_get_capture_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_dB_range snd_mixer_selem_get_capture_dB_range_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume_range snd_mixer_selem_set_capture_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_is_enumerated snd_mixer_selem_is_enumerated_dylibloader_orig_asound
+#define snd_mixer_selem_is_enum_playback snd_mixer_selem_is_enum_playback_dylibloader_orig_asound
+#define snd_mixer_selem_is_enum_capture snd_mixer_selem_is_enum_capture_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_items snd_mixer_selem_get_enum_items_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_item_name snd_mixer_selem_get_enum_item_name_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_item snd_mixer_selem_get_enum_item_dylibloader_orig_asound
+#define snd_mixer_selem_set_enum_item snd_mixer_selem_set_enum_item_dylibloader_orig_asound
+#define snd_mixer_selem_id_sizeof snd_mixer_selem_id_sizeof_dylibloader_orig_asound
+#define snd_mixer_selem_id_malloc snd_mixer_selem_id_malloc_dylibloader_orig_asound
+#define snd_mixer_selem_id_free snd_mixer_selem_id_free_dylibloader_orig_asound
+#define snd_mixer_selem_id_copy snd_mixer_selem_id_copy_dylibloader_orig_asound
+#define snd_mixer_selem_id_get_name snd_mixer_selem_id_get_name_dylibloader_orig_asound
+#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_orig_asound
+#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_orig_asound
+#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_orig_asound
+#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_orig_asound
+#define snd_seq_open snd_seq_open_dylibloader_orig_asound
+#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_orig_asound
+#define snd_seq_name snd_seq_name_dylibloader_orig_asound
+#define snd_seq_type snd_seq_type_dylibloader_orig_asound
+#define snd_seq_close snd_seq_close_dylibloader_orig_asound
+#define snd_seq_poll_descriptors_count snd_seq_poll_descriptors_count_dylibloader_orig_asound
+#define snd_seq_poll_descriptors snd_seq_poll_descriptors_dylibloader_orig_asound
+#define snd_seq_poll_descriptors_revents snd_seq_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_seq_nonblock snd_seq_nonblock_dylibloader_orig_asound
+#define snd_seq_client_id snd_seq_client_id_dylibloader_orig_asound
+#define snd_seq_get_output_buffer_size snd_seq_get_output_buffer_size_dylibloader_orig_asound
+#define snd_seq_get_input_buffer_size snd_seq_get_input_buffer_size_dylibloader_orig_asound
+#define snd_seq_set_output_buffer_size snd_seq_set_output_buffer_size_dylibloader_orig_asound
+#define snd_seq_set_input_buffer_size snd_seq_set_input_buffer_size_dylibloader_orig_asound
+#define snd_seq_system_info_sizeof snd_seq_system_info_sizeof_dylibloader_orig_asound
+#define snd_seq_system_info_malloc snd_seq_system_info_malloc_dylibloader_orig_asound
+#define snd_seq_system_info_free snd_seq_system_info_free_dylibloader_orig_asound
+#define snd_seq_system_info_copy snd_seq_system_info_copy_dylibloader_orig_asound
+#define snd_seq_system_info_get_queues snd_seq_system_info_get_queues_dylibloader_orig_asound
+#define snd_seq_system_info_get_clients snd_seq_system_info_get_clients_dylibloader_orig_asound
+#define snd_seq_system_info_get_ports snd_seq_system_info_get_ports_dylibloader_orig_asound
+#define snd_seq_system_info_get_channels snd_seq_system_info_get_channels_dylibloader_orig_asound
+#define snd_seq_system_info_get_cur_clients snd_seq_system_info_get_cur_clients_dylibloader_orig_asound
+#define snd_seq_system_info_get_cur_queues snd_seq_system_info_get_cur_queues_dylibloader_orig_asound
+#define snd_seq_system_info snd_seq_system_info_dylibloader_orig_asound
+#define snd_seq_client_info_sizeof snd_seq_client_info_sizeof_dylibloader_orig_asound
+#define snd_seq_client_info_malloc snd_seq_client_info_malloc_dylibloader_orig_asound
+#define snd_seq_client_info_free snd_seq_client_info_free_dylibloader_orig_asound
+#define snd_seq_client_info_copy snd_seq_client_info_copy_dylibloader_orig_asound
+#define snd_seq_client_info_get_client snd_seq_client_info_get_client_dylibloader_orig_asound
+#define snd_seq_client_info_get_type snd_seq_client_info_get_type_dylibloader_orig_asound
+#define snd_seq_client_info_get_name snd_seq_client_info_get_name_dylibloader_orig_asound
+#define snd_seq_client_info_get_broadcast_filter snd_seq_client_info_get_broadcast_filter_dylibloader_orig_asound
+#define snd_seq_client_info_get_error_bounce snd_seq_client_info_get_error_bounce_dylibloader_orig_asound
+#define snd_seq_client_info_get_card snd_seq_client_info_get_card_dylibloader_orig_asound
+#define snd_seq_client_info_get_pid snd_seq_client_info_get_pid_dylibloader_orig_asound
+#define snd_seq_client_info_get_event_filter snd_seq_client_info_get_event_filter_dylibloader_orig_asound
+#define snd_seq_client_info_get_num_ports snd_seq_client_info_get_num_ports_dylibloader_orig_asound
+#define snd_seq_client_info_get_event_lost snd_seq_client_info_get_event_lost_dylibloader_orig_asound
+#define snd_seq_client_info_set_client snd_seq_client_info_set_client_dylibloader_orig_asound
+#define snd_seq_client_info_set_name snd_seq_client_info_set_name_dylibloader_orig_asound
+#define snd_seq_client_info_set_broadcast_filter snd_seq_client_info_set_broadcast_filter_dylibloader_orig_asound
+#define snd_seq_client_info_set_error_bounce snd_seq_client_info_set_error_bounce_dylibloader_orig_asound
+#define snd_seq_client_info_set_event_filter snd_seq_client_info_set_event_filter_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_clear snd_seq_client_info_event_filter_clear_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_add snd_seq_client_info_event_filter_add_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_del snd_seq_client_info_event_filter_del_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_check snd_seq_client_info_event_filter_check_dylibloader_orig_asound
+#define snd_seq_get_client_info snd_seq_get_client_info_dylibloader_orig_asound
+#define snd_seq_get_any_client_info snd_seq_get_any_client_info_dylibloader_orig_asound
+#define snd_seq_set_client_info snd_seq_set_client_info_dylibloader_orig_asound
+#define snd_seq_query_next_client snd_seq_query_next_client_dylibloader_orig_asound
+#define snd_seq_client_pool_sizeof snd_seq_client_pool_sizeof_dylibloader_orig_asound
+#define snd_seq_client_pool_malloc snd_seq_client_pool_malloc_dylibloader_orig_asound
+#define snd_seq_client_pool_free snd_seq_client_pool_free_dylibloader_orig_asound
+#define snd_seq_client_pool_copy snd_seq_client_pool_copy_dylibloader_orig_asound
+#define snd_seq_client_pool_get_client snd_seq_client_pool_get_client_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_pool snd_seq_client_pool_get_output_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_get_input_pool snd_seq_client_pool_get_input_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_room snd_seq_client_pool_get_output_room_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_free snd_seq_client_pool_get_output_free_dylibloader_orig_asound
+#define snd_seq_client_pool_get_input_free snd_seq_client_pool_get_input_free_dylibloader_orig_asound
+#define snd_seq_client_pool_set_output_pool snd_seq_client_pool_set_output_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_set_input_pool snd_seq_client_pool_set_input_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_set_output_room snd_seq_client_pool_set_output_room_dylibloader_orig_asound
+#define snd_seq_get_client_pool snd_seq_get_client_pool_dylibloader_orig_asound
+#define snd_seq_set_client_pool snd_seq_set_client_pool_dylibloader_orig_asound
+#define snd_seq_port_info_sizeof snd_seq_port_info_sizeof_dylibloader_orig_asound
+#define snd_seq_port_info_malloc snd_seq_port_info_malloc_dylibloader_orig_asound
+#define snd_seq_port_info_free snd_seq_port_info_free_dylibloader_orig_asound
+#define snd_seq_port_info_copy snd_seq_port_info_copy_dylibloader_orig_asound
+#define snd_seq_port_info_get_client snd_seq_port_info_get_client_dylibloader_orig_asound
+#define snd_seq_port_info_get_port snd_seq_port_info_get_port_dylibloader_orig_asound
+#define snd_seq_port_info_get_addr snd_seq_port_info_get_addr_dylibloader_orig_asound
+#define snd_seq_port_info_get_name snd_seq_port_info_get_name_dylibloader_orig_asound
+#define snd_seq_port_info_get_capability snd_seq_port_info_get_capability_dylibloader_orig_asound
+#define snd_seq_port_info_get_type snd_seq_port_info_get_type_dylibloader_orig_asound
+#define snd_seq_port_info_get_midi_channels snd_seq_port_info_get_midi_channels_dylibloader_orig_asound
+#define snd_seq_port_info_get_midi_voices snd_seq_port_info_get_midi_voices_dylibloader_orig_asound
+#define snd_seq_port_info_get_synth_voices snd_seq_port_info_get_synth_voices_dylibloader_orig_asound
+#define snd_seq_port_info_get_read_use snd_seq_port_info_get_read_use_dylibloader_orig_asound
+#define snd_seq_port_info_get_write_use snd_seq_port_info_get_write_use_dylibloader_orig_asound
+#define snd_seq_port_info_get_port_specified snd_seq_port_info_get_port_specified_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamping snd_seq_port_info_get_timestamping_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamp_real snd_seq_port_info_get_timestamp_real_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamp_queue snd_seq_port_info_get_timestamp_queue_dylibloader_orig_asound
+#define snd_seq_port_info_set_client snd_seq_port_info_set_client_dylibloader_orig_asound
+#define snd_seq_port_info_set_port snd_seq_port_info_set_port_dylibloader_orig_asound
+#define snd_seq_port_info_set_addr snd_seq_port_info_set_addr_dylibloader_orig_asound
+#define snd_seq_port_info_set_name snd_seq_port_info_set_name_dylibloader_orig_asound
+#define snd_seq_port_info_set_capability snd_seq_port_info_set_capability_dylibloader_orig_asound
+#define snd_seq_port_info_set_type snd_seq_port_info_set_type_dylibloader_orig_asound
+#define snd_seq_port_info_set_midi_channels snd_seq_port_info_set_midi_channels_dylibloader_orig_asound
+#define snd_seq_port_info_set_midi_voices snd_seq_port_info_set_midi_voices_dylibloader_orig_asound
+#define snd_seq_port_info_set_synth_voices snd_seq_port_info_set_synth_voices_dylibloader_orig_asound
+#define snd_seq_port_info_set_port_specified snd_seq_port_info_set_port_specified_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamping snd_seq_port_info_set_timestamping_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamp_real snd_seq_port_info_set_timestamp_real_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamp_queue snd_seq_port_info_set_timestamp_queue_dylibloader_orig_asound
+#define snd_seq_create_port snd_seq_create_port_dylibloader_orig_asound
+#define snd_seq_delete_port snd_seq_delete_port_dylibloader_orig_asound
+#define snd_seq_get_port_info snd_seq_get_port_info_dylibloader_orig_asound
+#define snd_seq_get_any_port_info snd_seq_get_any_port_info_dylibloader_orig_asound
+#define snd_seq_set_port_info snd_seq_set_port_info_dylibloader_orig_asound
+#define snd_seq_query_next_port snd_seq_query_next_port_dylibloader_orig_asound
+#define snd_seq_port_subscribe_sizeof snd_seq_port_subscribe_sizeof_dylibloader_orig_asound
+#define snd_seq_port_subscribe_malloc snd_seq_port_subscribe_malloc_dylibloader_orig_asound
+#define snd_seq_port_subscribe_free snd_seq_port_subscribe_free_dylibloader_orig_asound
+#define snd_seq_port_subscribe_copy snd_seq_port_subscribe_copy_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_sender snd_seq_port_subscribe_get_sender_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_dest snd_seq_port_subscribe_get_dest_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_queue snd_seq_port_subscribe_get_queue_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_exclusive snd_seq_port_subscribe_get_exclusive_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_time_update snd_seq_port_subscribe_get_time_update_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_time_real snd_seq_port_subscribe_get_time_real_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_sender snd_seq_port_subscribe_set_sender_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_dest snd_seq_port_subscribe_set_dest_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_queue snd_seq_port_subscribe_set_queue_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_exclusive snd_seq_port_subscribe_set_exclusive_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_time_update snd_seq_port_subscribe_set_time_update_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_time_real snd_seq_port_subscribe_set_time_real_dylibloader_orig_asound
+#define snd_seq_get_port_subscription snd_seq_get_port_subscription_dylibloader_orig_asound
+#define snd_seq_subscribe_port snd_seq_subscribe_port_dylibloader_orig_asound
+#define snd_seq_unsubscribe_port snd_seq_unsubscribe_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_sizeof snd_seq_query_subscribe_sizeof_dylibloader_orig_asound
+#define snd_seq_query_subscribe_malloc snd_seq_query_subscribe_malloc_dylibloader_orig_asound
+#define snd_seq_query_subscribe_free snd_seq_query_subscribe_free_dylibloader_orig_asound
+#define snd_seq_query_subscribe_copy snd_seq_query_subscribe_copy_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_client snd_seq_query_subscribe_get_client_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_port snd_seq_query_subscribe_get_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_root snd_seq_query_subscribe_get_root_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_type snd_seq_query_subscribe_get_type_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_index snd_seq_query_subscribe_get_index_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_num_subs snd_seq_query_subscribe_get_num_subs_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_addr snd_seq_query_subscribe_get_addr_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_queue snd_seq_query_subscribe_get_queue_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_exclusive snd_seq_query_subscribe_get_exclusive_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_time_update snd_seq_query_subscribe_get_time_update_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_time_real snd_seq_query_subscribe_get_time_real_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_client snd_seq_query_subscribe_set_client_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_port snd_seq_query_subscribe_set_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_root snd_seq_query_subscribe_set_root_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_type snd_seq_query_subscribe_set_type_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_index snd_seq_query_subscribe_set_index_dylibloader_orig_asound
+#define snd_seq_query_port_subscribers snd_seq_query_port_subscribers_dylibloader_orig_asound
+#define snd_seq_queue_info_sizeof snd_seq_queue_info_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_info_malloc snd_seq_queue_info_malloc_dylibloader_orig_asound
+#define snd_seq_queue_info_free snd_seq_queue_info_free_dylibloader_orig_asound
+#define snd_seq_queue_info_copy snd_seq_queue_info_copy_dylibloader_orig_asound
+#define snd_seq_queue_info_get_queue snd_seq_queue_info_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_info_get_name snd_seq_queue_info_get_name_dylibloader_orig_asound
+#define snd_seq_queue_info_get_owner snd_seq_queue_info_get_owner_dylibloader_orig_asound
+#define snd_seq_queue_info_get_locked snd_seq_queue_info_get_locked_dylibloader_orig_asound
+#define snd_seq_queue_info_get_flags snd_seq_queue_info_get_flags_dylibloader_orig_asound
+#define snd_seq_queue_info_set_name snd_seq_queue_info_set_name_dylibloader_orig_asound
+#define snd_seq_queue_info_set_owner snd_seq_queue_info_set_owner_dylibloader_orig_asound
+#define snd_seq_queue_info_set_locked snd_seq_queue_info_set_locked_dylibloader_orig_asound
+#define snd_seq_queue_info_set_flags snd_seq_queue_info_set_flags_dylibloader_orig_asound
+#define snd_seq_create_queue snd_seq_create_queue_dylibloader_orig_asound
+#define snd_seq_alloc_named_queue snd_seq_alloc_named_queue_dylibloader_orig_asound
+#define snd_seq_alloc_queue snd_seq_alloc_queue_dylibloader_orig_asound
+#define snd_seq_free_queue snd_seq_free_queue_dylibloader_orig_asound
+#define snd_seq_get_queue_info snd_seq_get_queue_info_dylibloader_orig_asound
+#define snd_seq_set_queue_info snd_seq_set_queue_info_dylibloader_orig_asound
+#define snd_seq_query_named_queue snd_seq_query_named_queue_dylibloader_orig_asound
+#define snd_seq_get_queue_usage snd_seq_get_queue_usage_dylibloader_orig_asound
+#define snd_seq_set_queue_usage snd_seq_set_queue_usage_dylibloader_orig_asound
+#define snd_seq_queue_status_sizeof snd_seq_queue_status_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_status_malloc snd_seq_queue_status_malloc_dylibloader_orig_asound
+#define snd_seq_queue_status_free snd_seq_queue_status_free_dylibloader_orig_asound
+#define snd_seq_queue_status_copy snd_seq_queue_status_copy_dylibloader_orig_asound
+#define snd_seq_queue_status_get_queue snd_seq_queue_status_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_status_get_events snd_seq_queue_status_get_events_dylibloader_orig_asound
+#define snd_seq_queue_status_get_tick_time snd_seq_queue_status_get_tick_time_dylibloader_orig_asound
+#define snd_seq_queue_status_get_real_time snd_seq_queue_status_get_real_time_dylibloader_orig_asound
+#define snd_seq_queue_status_get_status snd_seq_queue_status_get_status_dylibloader_orig_asound
+#define snd_seq_get_queue_status snd_seq_get_queue_status_dylibloader_orig_asound
+#define snd_seq_queue_tempo_sizeof snd_seq_queue_tempo_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_tempo_malloc snd_seq_queue_tempo_malloc_dylibloader_orig_asound
+#define snd_seq_queue_tempo_free snd_seq_queue_tempo_free_dylibloader_orig_asound
+#define snd_seq_queue_tempo_copy snd_seq_queue_tempo_copy_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_queue snd_seq_queue_tempo_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_tempo snd_seq_queue_tempo_get_tempo_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_ppq snd_seq_queue_tempo_get_ppq_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_skew snd_seq_queue_tempo_get_skew_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_skew_base snd_seq_queue_tempo_get_skew_base_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_tempo snd_seq_queue_tempo_set_tempo_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_ppq snd_seq_queue_tempo_set_ppq_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_skew snd_seq_queue_tempo_set_skew_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_skew_base snd_seq_queue_tempo_set_skew_base_dylibloader_orig_asound
+#define snd_seq_get_queue_tempo snd_seq_get_queue_tempo_dylibloader_orig_asound
+#define snd_seq_set_queue_tempo snd_seq_set_queue_tempo_dylibloader_orig_asound
+#define snd_seq_queue_timer_sizeof snd_seq_queue_timer_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_timer_malloc snd_seq_queue_timer_malloc_dylibloader_orig_asound
+#define snd_seq_queue_timer_free snd_seq_queue_timer_free_dylibloader_orig_asound
+#define snd_seq_queue_timer_copy snd_seq_queue_timer_copy_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_queue snd_seq_queue_timer_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_type snd_seq_queue_timer_get_type_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_id snd_seq_queue_timer_get_id_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_resolution snd_seq_queue_timer_get_resolution_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_type snd_seq_queue_timer_set_type_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_id snd_seq_queue_timer_set_id_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_resolution snd_seq_queue_timer_set_resolution_dylibloader_orig_asound
+#define snd_seq_get_queue_timer snd_seq_get_queue_timer_dylibloader_orig_asound
+#define snd_seq_set_queue_timer snd_seq_set_queue_timer_dylibloader_orig_asound
+#define snd_seq_free_event snd_seq_free_event_dylibloader_orig_asound
+#define snd_seq_event_length snd_seq_event_length_dylibloader_orig_asound
+#define snd_seq_event_output snd_seq_event_output_dylibloader_orig_asound
+#define snd_seq_event_output_buffer snd_seq_event_output_buffer_dylibloader_orig_asound
+#define snd_seq_event_output_direct snd_seq_event_output_direct_dylibloader_orig_asound
+#define snd_seq_event_input snd_seq_event_input_dylibloader_orig_asound
+#define snd_seq_event_input_pending snd_seq_event_input_pending_dylibloader_orig_asound
+#define snd_seq_drain_output snd_seq_drain_output_dylibloader_orig_asound
+#define snd_seq_event_output_pending snd_seq_event_output_pending_dylibloader_orig_asound
+#define snd_seq_extract_output snd_seq_extract_output_dylibloader_orig_asound
+#define snd_seq_drop_output snd_seq_drop_output_dylibloader_orig_asound
+#define snd_seq_drop_output_buffer snd_seq_drop_output_buffer_dylibloader_orig_asound
+#define snd_seq_drop_input snd_seq_drop_input_dylibloader_orig_asound
+#define snd_seq_drop_input_buffer snd_seq_drop_input_buffer_dylibloader_orig_asound
+#define snd_seq_remove_events_sizeof snd_seq_remove_events_sizeof_dylibloader_orig_asound
+#define snd_seq_remove_events_malloc snd_seq_remove_events_malloc_dylibloader_orig_asound
+#define snd_seq_remove_events_free snd_seq_remove_events_free_dylibloader_orig_asound
+#define snd_seq_remove_events_copy snd_seq_remove_events_copy_dylibloader_orig_asound
+#define snd_seq_remove_events_get_condition snd_seq_remove_events_get_condition_dylibloader_orig_asound
+#define snd_seq_remove_events_get_queue snd_seq_remove_events_get_queue_dylibloader_orig_asound
+#define snd_seq_remove_events_get_time snd_seq_remove_events_get_time_dylibloader_orig_asound
+#define snd_seq_remove_events_get_dest snd_seq_remove_events_get_dest_dylibloader_orig_asound
+#define snd_seq_remove_events_get_channel snd_seq_remove_events_get_channel_dylibloader_orig_asound
+#define snd_seq_remove_events_get_event_type snd_seq_remove_events_get_event_type_dylibloader_orig_asound
+#define snd_seq_remove_events_get_tag snd_seq_remove_events_get_tag_dylibloader_orig_asound
+#define snd_seq_remove_events_set_condition snd_seq_remove_events_set_condition_dylibloader_orig_asound
+#define snd_seq_remove_events_set_queue snd_seq_remove_events_set_queue_dylibloader_orig_asound
+#define snd_seq_remove_events_set_time snd_seq_remove_events_set_time_dylibloader_orig_asound
+#define snd_seq_remove_events_set_dest snd_seq_remove_events_set_dest_dylibloader_orig_asound
+#define snd_seq_remove_events_set_channel snd_seq_remove_events_set_channel_dylibloader_orig_asound
+#define snd_seq_remove_events_set_event_type snd_seq_remove_events_set_event_type_dylibloader_orig_asound
+#define snd_seq_remove_events_set_tag snd_seq_remove_events_set_tag_dylibloader_orig_asound
+#define snd_seq_remove_events snd_seq_remove_events_dylibloader_orig_asound
+#define snd_seq_set_bit snd_seq_set_bit_dylibloader_orig_asound
+#define snd_seq_unset_bit snd_seq_unset_bit_dylibloader_orig_asound
+#define snd_seq_change_bit snd_seq_change_bit_dylibloader_orig_asound
+#define snd_seq_get_bit snd_seq_get_bit_dylibloader_orig_asound
+#define snd_seq_control_queue snd_seq_control_queue_dylibloader_orig_asound
+#define snd_seq_create_simple_port snd_seq_create_simple_port_dylibloader_orig_asound
+#define snd_seq_delete_simple_port snd_seq_delete_simple_port_dylibloader_orig_asound
+#define snd_seq_connect_from snd_seq_connect_from_dylibloader_orig_asound
+#define snd_seq_connect_to snd_seq_connect_to_dylibloader_orig_asound
+#define snd_seq_disconnect_from snd_seq_disconnect_from_dylibloader_orig_asound
+#define snd_seq_disconnect_to snd_seq_disconnect_to_dylibloader_orig_asound
+#define snd_seq_set_client_name snd_seq_set_client_name_dylibloader_orig_asound
+#define snd_seq_set_client_event_filter snd_seq_set_client_event_filter_dylibloader_orig_asound
+#define snd_seq_set_client_pool_output snd_seq_set_client_pool_output_dylibloader_orig_asound
+#define snd_seq_set_client_pool_output_room snd_seq_set_client_pool_output_room_dylibloader_orig_asound
+#define snd_seq_set_client_pool_input snd_seq_set_client_pool_input_dylibloader_orig_asound
+#define snd_seq_sync_output_queue snd_seq_sync_output_queue_dylibloader_orig_asound
+#define snd_seq_parse_address snd_seq_parse_address_dylibloader_orig_asound
+#define snd_seq_reset_pool_output snd_seq_reset_pool_output_dylibloader_orig_asound
+#define snd_seq_reset_pool_input snd_seq_reset_pool_input_dylibloader_orig_asound
+#define snd_midi_event_new snd_midi_event_new_dylibloader_orig_asound
+#define snd_midi_event_resize_buffer snd_midi_event_resize_buffer_dylibloader_orig_asound
+#define snd_midi_event_free snd_midi_event_free_dylibloader_orig_asound
+#define snd_midi_event_init snd_midi_event_init_dylibloader_orig_asound
+#define snd_midi_event_reset_encode snd_midi_event_reset_encode_dylibloader_orig_asound
+#define snd_midi_event_reset_decode snd_midi_event_reset_decode_dylibloader_orig_asound
+#define snd_midi_event_no_status snd_midi_event_no_status_dylibloader_orig_asound
+#define snd_midi_event_encode snd_midi_event_encode_dylibloader_orig_asound
+#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_orig_asound
+#define snd_midi_event_decode snd_midi_event_decode_dylibloader_orig_asound
+#include <alsa/asoundlib.h>
+#undef snd_asoundlib_version
+#undef snd_dlpath
+#undef snd_dlopen
+#undef snd_dlsym
+#undef snd_dlclose
+#undef snd_async_add_handler
+#undef snd_async_del_handler
+#undef snd_async_handler_get_fd
+#undef snd_async_handler_get_signo
+#undef snd_async_handler_get_callback_private
+#undef snd_shm_area_create
+#undef snd_shm_area_share
+#undef snd_shm_area_destroy
+#undef snd_user_file
+#undef snd_input_stdio_open
+#undef snd_input_stdio_attach
+#undef snd_input_buffer_open
+#undef snd_input_close
+#undef snd_input_scanf
+#undef snd_input_gets
+#undef snd_input_getc
+#undef snd_input_ungetc
+#undef snd_output_stdio_open
+#undef snd_output_stdio_attach
+#undef snd_output_buffer_open
+#undef snd_output_buffer_string
+#undef snd_output_close
+#undef snd_output_printf
+#undef snd_output_vprintf
+#undef snd_output_puts
+#undef snd_output_putc
+#undef snd_output_flush
+#undef snd_strerror
+#undef snd_lib_error_set_handler
+#undef snd_lib_error_set_local
+#undef snd_config_topdir
+#undef snd_config_top
+#undef snd_config_load
+#undef snd_config_load_override
+#undef snd_config_save
+#undef snd_config_update
+#undef snd_config_update_r
+#undef snd_config_update_free
+#undef snd_config_update_free_global
+#undef snd_config_update_ref
+#undef snd_config_ref
+#undef snd_config_unref
+#undef snd_config_search
+#undef snd_config_searchv
+#undef snd_config_search_definition
+#undef snd_config_expand
+#undef snd_config_evaluate
+#undef snd_config_add
+#undef snd_config_add_before
+#undef snd_config_add_after
+#undef snd_config_remove
+#undef snd_config_delete
+#undef snd_config_delete_compound_members
+#undef snd_config_copy
+#undef snd_config_make
+#undef snd_config_make_integer
+#undef snd_config_make_integer64
+#undef snd_config_make_real
+#undef snd_config_make_string
+#undef snd_config_make_pointer
+#undef snd_config_make_compound
+#undef snd_config_imake_integer
+#undef snd_config_imake_integer64
+#undef snd_config_imake_real
+#undef snd_config_imake_string
+#undef snd_config_imake_safe_string
+#undef snd_config_imake_pointer
+#undef snd_config_get_type
+#undef snd_config_is_array
+#undef snd_config_set_id
+#undef snd_config_set_integer
+#undef snd_config_set_integer64
+#undef snd_config_set_real
+#undef snd_config_set_string
+#undef snd_config_set_ascii
+#undef snd_config_set_pointer
+#undef snd_config_get_id
+#undef snd_config_get_integer
+#undef snd_config_get_integer64
+#undef snd_config_get_real
+#undef snd_config_get_ireal
+#undef snd_config_get_string
+#undef snd_config_get_ascii
+#undef snd_config_get_pointer
+#undef snd_config_test_id
+#undef snd_config_iterator_first
+#undef snd_config_iterator_next
+#undef snd_config_iterator_end
+#undef snd_config_iterator_entry
+#undef snd_config_get_bool_ascii
+#undef snd_config_get_bool
+#undef snd_config_get_ctl_iface_ascii
+#undef snd_config_get_ctl_iface
+#undef snd_names_list
+#undef snd_names_list_free
+#undef snd_pcm_open
+#undef snd_pcm_open_lconf
+#undef snd_pcm_open_fallback
+#undef snd_pcm_close
+#undef snd_pcm_name
+#undef snd_pcm_type
+#undef snd_pcm_stream
+#undef snd_pcm_poll_descriptors_count
+#undef snd_pcm_poll_descriptors
+#undef snd_pcm_poll_descriptors_revents
+#undef snd_pcm_nonblock
+#undef snd_async_add_pcm_handler
+#undef snd_async_handler_get_pcm
+#undef snd_pcm_info
+#undef snd_pcm_hw_params_current
+#undef snd_pcm_hw_params
+#undef snd_pcm_hw_free
+#undef snd_pcm_sw_params_current
+#undef snd_pcm_sw_params
+#undef snd_pcm_prepare
+#undef snd_pcm_reset
+#undef snd_pcm_status
+#undef snd_pcm_start
+#undef snd_pcm_drop
+#undef snd_pcm_drain
+#undef snd_pcm_pause
+#undef snd_pcm_state
+#undef snd_pcm_hwsync
+#undef snd_pcm_delay
+#undef snd_pcm_resume
+#undef snd_pcm_htimestamp
+#undef snd_pcm_avail
+#undef snd_pcm_avail_update
+#undef snd_pcm_avail_delay
+#undef snd_pcm_rewindable
+#undef snd_pcm_rewind
+#undef snd_pcm_forwardable
+#undef snd_pcm_forward
+#undef snd_pcm_writei
+#undef snd_pcm_readi
+#undef snd_pcm_writen
+#undef snd_pcm_readn
+#undef snd_pcm_wait
+#undef snd_pcm_link
+#undef snd_pcm_unlink
+#undef snd_pcm_query_chmaps
+#undef snd_pcm_query_chmaps_from_hw
+#undef snd_pcm_free_chmaps
+#undef snd_pcm_get_chmap
+#undef snd_pcm_set_chmap
+#undef snd_pcm_chmap_type_name
+#undef snd_pcm_chmap_name
+#undef snd_pcm_chmap_long_name
+#undef snd_pcm_chmap_print
+#undef snd_pcm_chmap_from_string
+#undef snd_pcm_chmap_parse_string
+#undef snd_pcm_recover
+#undef snd_pcm_set_params
+#undef snd_pcm_get_params
+#undef snd_pcm_info_sizeof
+#undef snd_pcm_info_malloc
+#undef snd_pcm_info_free
+#undef snd_pcm_info_copy
+#undef snd_pcm_info_get_device
+#undef snd_pcm_info_get_subdevice
+#undef snd_pcm_info_get_stream
+#undef snd_pcm_info_get_card
+#undef snd_pcm_info_get_id
+#undef snd_pcm_info_get_name
+#undef snd_pcm_info_get_subdevice_name
+#undef snd_pcm_info_get_class
+#undef snd_pcm_info_get_subclass
+#undef snd_pcm_info_get_subdevices_count
+#undef snd_pcm_info_get_subdevices_avail
+#undef snd_pcm_info_get_sync
+#undef snd_pcm_info_set_device
+#undef snd_pcm_info_set_subdevice
+#undef snd_pcm_info_set_stream
+#undef snd_pcm_hw_params_any
+#undef snd_pcm_hw_params_can_mmap_sample_resolution
+#undef snd_pcm_hw_params_is_double
+#undef snd_pcm_hw_params_is_batch
+#undef snd_pcm_hw_params_is_block_transfer
+#undef snd_pcm_hw_params_is_monotonic
+#undef snd_pcm_hw_params_can_overrange
+#undef snd_pcm_hw_params_can_pause
+#undef snd_pcm_hw_params_can_resume
+#undef snd_pcm_hw_params_is_half_duplex
+#undef snd_pcm_hw_params_is_joint_duplex
+#undef snd_pcm_hw_params_can_sync_start
+#undef snd_pcm_hw_params_can_disable_period_wakeup
+#undef snd_pcm_hw_params_supports_audio_wallclock_ts
+#undef snd_pcm_hw_params_supports_audio_ts_type
+#undef snd_pcm_hw_params_get_rate_numden
+#undef snd_pcm_hw_params_get_sbits
+#undef snd_pcm_hw_params_get_fifo_size
+#undef snd_pcm_hw_params_sizeof
+#undef snd_pcm_hw_params_malloc
+#undef snd_pcm_hw_params_free
+#undef snd_pcm_hw_params_copy
+#undef snd_pcm_hw_params_get_access
+#undef snd_pcm_hw_params_test_access
+#undef snd_pcm_hw_params_set_access
+#undef snd_pcm_hw_params_set_access_first
+#undef snd_pcm_hw_params_set_access_last
+#undef snd_pcm_hw_params_set_access_mask
+#undef snd_pcm_hw_params_get_access_mask
+#undef snd_pcm_hw_params_get_format
+#undef snd_pcm_hw_params_test_format
+#undef snd_pcm_hw_params_set_format
+#undef snd_pcm_hw_params_set_format_first
+#undef snd_pcm_hw_params_set_format_last
+#undef snd_pcm_hw_params_set_format_mask
+#undef snd_pcm_hw_params_get_format_mask
+#undef snd_pcm_hw_params_get_subformat
+#undef snd_pcm_hw_params_test_subformat
+#undef snd_pcm_hw_params_set_subformat
+#undef snd_pcm_hw_params_set_subformat_first
+#undef snd_pcm_hw_params_set_subformat_last
+#undef snd_pcm_hw_params_set_subformat_mask
+#undef snd_pcm_hw_params_get_subformat_mask
+#undef snd_pcm_hw_params_get_channels
+#undef snd_pcm_hw_params_get_channels_min
+#undef snd_pcm_hw_params_get_channels_max
+#undef snd_pcm_hw_params_test_channels
+#undef snd_pcm_hw_params_set_channels
+#undef snd_pcm_hw_params_set_channels_min
+#undef snd_pcm_hw_params_set_channels_max
+#undef snd_pcm_hw_params_set_channels_minmax
+#undef snd_pcm_hw_params_set_channels_near
+#undef snd_pcm_hw_params_set_channels_first
+#undef snd_pcm_hw_params_set_channels_last
+#undef snd_pcm_hw_params_get_rate
+#undef snd_pcm_hw_params_get_rate_min
+#undef snd_pcm_hw_params_get_rate_max
+#undef snd_pcm_hw_params_test_rate
+#undef snd_pcm_hw_params_set_rate
+#undef snd_pcm_hw_params_set_rate_min
+#undef snd_pcm_hw_params_set_rate_max
+#undef snd_pcm_hw_params_set_rate_minmax
+#undef snd_pcm_hw_params_set_rate_near
+#undef snd_pcm_hw_params_set_rate_first
+#undef snd_pcm_hw_params_set_rate_last
+#undef snd_pcm_hw_params_set_rate_resample
+#undef snd_pcm_hw_params_get_rate_resample
+#undef snd_pcm_hw_params_set_export_buffer
+#undef snd_pcm_hw_params_get_export_buffer
+#undef snd_pcm_hw_params_set_period_wakeup
+#undef snd_pcm_hw_params_get_period_wakeup
+#undef snd_pcm_hw_params_get_period_time
+#undef snd_pcm_hw_params_get_period_time_min
+#undef snd_pcm_hw_params_get_period_time_max
+#undef snd_pcm_hw_params_test_period_time
+#undef snd_pcm_hw_params_set_period_time
+#undef snd_pcm_hw_params_set_period_time_min
+#undef snd_pcm_hw_params_set_period_time_max
+#undef snd_pcm_hw_params_set_period_time_minmax
+#undef snd_pcm_hw_params_set_period_time_near
+#undef snd_pcm_hw_params_set_period_time_first
+#undef snd_pcm_hw_params_set_period_time_last
+#undef snd_pcm_hw_params_get_period_size
+#undef snd_pcm_hw_params_get_period_size_min
+#undef snd_pcm_hw_params_get_period_size_max
+#undef snd_pcm_hw_params_test_period_size
+#undef snd_pcm_hw_params_set_period_size
+#undef snd_pcm_hw_params_set_period_size_min
+#undef snd_pcm_hw_params_set_period_size_max
+#undef snd_pcm_hw_params_set_period_size_minmax
+#undef snd_pcm_hw_params_set_period_size_near
+#undef snd_pcm_hw_params_set_period_size_first
+#undef snd_pcm_hw_params_set_period_size_last
+#undef snd_pcm_hw_params_set_period_size_integer
+#undef snd_pcm_hw_params_get_periods
+#undef snd_pcm_hw_params_get_periods_min
+#undef snd_pcm_hw_params_get_periods_max
+#undef snd_pcm_hw_params_test_periods
+#undef snd_pcm_hw_params_set_periods
+#undef snd_pcm_hw_params_set_periods_min
+#undef snd_pcm_hw_params_set_periods_max
+#undef snd_pcm_hw_params_set_periods_minmax
+#undef snd_pcm_hw_params_set_periods_near
+#undef snd_pcm_hw_params_set_periods_first
+#undef snd_pcm_hw_params_set_periods_last
+#undef snd_pcm_hw_params_set_periods_integer
+#undef snd_pcm_hw_params_get_buffer_time
+#undef snd_pcm_hw_params_get_buffer_time_min
+#undef snd_pcm_hw_params_get_buffer_time_max
+#undef snd_pcm_hw_params_test_buffer_time
+#undef snd_pcm_hw_params_set_buffer_time
+#undef snd_pcm_hw_params_set_buffer_time_min
+#undef snd_pcm_hw_params_set_buffer_time_max
+#undef snd_pcm_hw_params_set_buffer_time_minmax
+#undef snd_pcm_hw_params_set_buffer_time_near
+#undef snd_pcm_hw_params_set_buffer_time_first
+#undef snd_pcm_hw_params_set_buffer_time_last
+#undef snd_pcm_hw_params_get_buffer_size
+#undef snd_pcm_hw_params_get_buffer_size_min
+#undef snd_pcm_hw_params_get_buffer_size_max
+#undef snd_pcm_hw_params_test_buffer_size
+#undef snd_pcm_hw_params_set_buffer_size
+#undef snd_pcm_hw_params_set_buffer_size_min
+#undef snd_pcm_hw_params_set_buffer_size_max
+#undef snd_pcm_hw_params_set_buffer_size_minmax
+#undef snd_pcm_hw_params_set_buffer_size_near
+#undef snd_pcm_hw_params_set_buffer_size_first
+#undef snd_pcm_hw_params_set_buffer_size_last
+#undef snd_pcm_hw_params_get_min_align
+#undef snd_pcm_sw_params_sizeof
+#undef snd_pcm_sw_params_malloc
+#undef snd_pcm_sw_params_free
+#undef snd_pcm_sw_params_copy
+#undef snd_pcm_sw_params_get_boundary
+#undef snd_pcm_sw_params_set_tstamp_mode
+#undef snd_pcm_sw_params_get_tstamp_mode
+#undef snd_pcm_sw_params_set_avail_min
+#undef snd_pcm_sw_params_get_avail_min
+#undef snd_pcm_sw_params_set_period_event
+#undef snd_pcm_sw_params_get_period_event
+#undef snd_pcm_sw_params_set_start_threshold
+#undef snd_pcm_sw_params_get_start_threshold
+#undef snd_pcm_sw_params_set_stop_threshold
+#undef snd_pcm_sw_params_get_stop_threshold
+#undef snd_pcm_sw_params_set_silence_threshold
+#undef snd_pcm_sw_params_get_silence_threshold
+#undef snd_pcm_sw_params_set_silence_size
+#undef snd_pcm_sw_params_get_silence_size
+#undef snd_pcm_access_mask_sizeof
+#undef snd_pcm_access_mask_malloc
+#undef snd_pcm_access_mask_free
+#undef snd_pcm_access_mask_copy
+#undef snd_pcm_access_mask_none
+#undef snd_pcm_access_mask_any
+#undef snd_pcm_access_mask_test
+#undef snd_pcm_access_mask_empty
+#undef snd_pcm_access_mask_set
+#undef snd_pcm_access_mask_reset
+#undef snd_pcm_format_mask_sizeof
+#undef snd_pcm_format_mask_malloc
+#undef snd_pcm_format_mask_free
+#undef snd_pcm_format_mask_copy
+#undef snd_pcm_format_mask_none
+#undef snd_pcm_format_mask_any
+#undef snd_pcm_format_mask_test
+#undef snd_pcm_format_mask_empty
+#undef snd_pcm_format_mask_set
+#undef snd_pcm_format_mask_reset
+#undef snd_pcm_subformat_mask_sizeof
+#undef snd_pcm_subformat_mask_malloc
+#undef snd_pcm_subformat_mask_free
+#undef snd_pcm_subformat_mask_copy
+#undef snd_pcm_subformat_mask_none
+#undef snd_pcm_subformat_mask_any
+#undef snd_pcm_subformat_mask_test
+#undef snd_pcm_subformat_mask_empty
+#undef snd_pcm_subformat_mask_set
+#undef snd_pcm_subformat_mask_reset
+#undef snd_pcm_status_sizeof
+#undef snd_pcm_status_malloc
+#undef snd_pcm_status_free
+#undef snd_pcm_status_copy
+#undef snd_pcm_status_get_state
+#undef snd_pcm_status_get_trigger_tstamp
+#undef snd_pcm_status_get_trigger_htstamp
+#undef snd_pcm_status_get_tstamp
+#undef snd_pcm_status_get_htstamp
+#undef snd_pcm_status_get_audio_htstamp
+#undef snd_pcm_status_get_driver_htstamp
+#undef snd_pcm_status_get_delay
+#undef snd_pcm_status_get_avail
+#undef snd_pcm_status_get_avail_max
+#undef snd_pcm_status_get_overrange
+#undef snd_pcm_type_name
+#undef snd_pcm_stream_name
+#undef snd_pcm_access_name
+#undef snd_pcm_format_name
+#undef snd_pcm_format_description
+#undef snd_pcm_subformat_name
+#undef snd_pcm_subformat_description
+#undef snd_pcm_format_value
+#undef snd_pcm_tstamp_mode_name
+#undef snd_pcm_state_name
+#undef snd_pcm_dump
+#undef snd_pcm_dump_hw_setup
+#undef snd_pcm_dump_sw_setup
+#undef snd_pcm_dump_setup
+#undef snd_pcm_hw_params_dump
+#undef snd_pcm_sw_params_dump
+#undef snd_pcm_status_dump
+#undef snd_pcm_mmap_begin
+#undef snd_pcm_mmap_commit
+#undef snd_pcm_mmap_writei
+#undef snd_pcm_mmap_readi
+#undef snd_pcm_mmap_writen
+#undef snd_pcm_mmap_readn
+#undef snd_pcm_format_signed
+#undef snd_pcm_format_unsigned
+#undef snd_pcm_format_linear
+#undef snd_pcm_format_float
+#undef snd_pcm_format_little_endian
+#undef snd_pcm_format_big_endian
+#undef snd_pcm_format_cpu_endian
+#undef snd_pcm_format_width
+#undef snd_pcm_format_physical_width
+#undef snd_pcm_build_linear_format
+#undef snd_pcm_format_size
+#undef snd_pcm_format_silence
+#undef snd_pcm_format_silence_16
+#undef snd_pcm_format_silence_32
+#undef snd_pcm_format_silence_64
+#undef snd_pcm_format_set_silence
+#undef snd_pcm_bytes_to_frames
+#undef snd_pcm_frames_to_bytes
+#undef snd_pcm_bytes_to_samples
+#undef snd_pcm_samples_to_bytes
+#undef snd_pcm_area_silence
+#undef snd_pcm_areas_silence
+#undef snd_pcm_area_copy
+#undef snd_pcm_areas_copy
+#undef snd_pcm_areas_copy_wrap
+#undef snd_pcm_hook_get_pcm
+#undef snd_pcm_hook_get_private
+#undef snd_pcm_hook_set_private
+#undef snd_pcm_hook_add
+#undef snd_pcm_hook_remove
+#undef snd_pcm_meter_get_bufsize
+#undef snd_pcm_meter_get_channels
+#undef snd_pcm_meter_get_rate
+#undef snd_pcm_meter_get_now
+#undef snd_pcm_meter_get_boundary
+#undef snd_pcm_meter_add_scope
+#undef snd_pcm_meter_search_scope
+#undef snd_pcm_scope_malloc
+#undef snd_pcm_scope_set_ops
+#undef snd_pcm_scope_set_name
+#undef snd_pcm_scope_get_name
+#undef snd_pcm_scope_get_callback_private
+#undef snd_pcm_scope_set_callback_private
+#undef snd_pcm_scope_s16_open
+#undef snd_pcm_scope_s16_get_channel_buffer
+#undef snd_spcm_init
+#undef snd_spcm_init_duplex
+#undef snd_spcm_init_get_params
+#undef snd_pcm_start_mode_name
+#undef snd_pcm_xrun_mode_name
+#undef snd_pcm_sw_params_set_start_mode
+#undef snd_pcm_sw_params_get_start_mode
+#undef snd_pcm_sw_params_set_xrun_mode
+#undef snd_pcm_sw_params_get_xrun_mode
+#undef snd_pcm_sw_params_set_xfer_align
+#undef snd_pcm_sw_params_get_xfer_align
+#undef snd_pcm_sw_params_set_sleep_min
+#undef snd_pcm_sw_params_get_sleep_min
+#undef snd_pcm_hw_params_get_tick_time
+#undef snd_pcm_hw_params_get_tick_time_min
+#undef snd_pcm_hw_params_get_tick_time_max
+#undef snd_pcm_hw_params_test_tick_time
+#undef snd_pcm_hw_params_set_tick_time
+#undef snd_pcm_hw_params_set_tick_time_min
+#undef snd_pcm_hw_params_set_tick_time_max
+#undef snd_pcm_hw_params_set_tick_time_minmax
+#undef snd_pcm_hw_params_set_tick_time_near
+#undef snd_pcm_hw_params_set_tick_time_first
+#undef snd_pcm_hw_params_set_tick_time_last
+#undef snd_rawmidi_open
+#undef snd_rawmidi_open_lconf
+#undef snd_rawmidi_close
+#undef snd_rawmidi_poll_descriptors_count
+#undef snd_rawmidi_poll_descriptors
+#undef snd_rawmidi_poll_descriptors_revents
+#undef snd_rawmidi_nonblock
+#undef snd_rawmidi_info_sizeof
+#undef snd_rawmidi_info_malloc
+#undef snd_rawmidi_info_free
+#undef snd_rawmidi_info_copy
+#undef snd_rawmidi_info_get_device
+#undef snd_rawmidi_info_get_subdevice
+#undef snd_rawmidi_info_get_stream
+#undef snd_rawmidi_info_get_card
+#undef snd_rawmidi_info_get_flags
+#undef snd_rawmidi_info_get_id
+#undef snd_rawmidi_info_get_name
+#undef snd_rawmidi_info_get_subdevice_name
+#undef snd_rawmidi_info_get_subdevices_count
+#undef snd_rawmidi_info_get_subdevices_avail
+#undef snd_rawmidi_info_set_device
+#undef snd_rawmidi_info_set_subdevice
+#undef snd_rawmidi_info_set_stream
+#undef snd_rawmidi_info
+#undef snd_rawmidi_params_sizeof
+#undef snd_rawmidi_params_malloc
+#undef snd_rawmidi_params_free
+#undef snd_rawmidi_params_copy
+#undef snd_rawmidi_params_set_buffer_size
+#undef snd_rawmidi_params_get_buffer_size
+#undef snd_rawmidi_params_set_avail_min
+#undef snd_rawmidi_params_get_avail_min
+#undef snd_rawmidi_params_set_no_active_sensing
+#undef snd_rawmidi_params_get_no_active_sensing
+#undef snd_rawmidi_params
+#undef snd_rawmidi_params_current
+#undef snd_rawmidi_status_sizeof
+#undef snd_rawmidi_status_malloc
+#undef snd_rawmidi_status_free
+#undef snd_rawmidi_status_copy
+#undef snd_rawmidi_status_get_tstamp
+#undef snd_rawmidi_status_get_avail
+#undef snd_rawmidi_status_get_xruns
+#undef snd_rawmidi_status
+#undef snd_rawmidi_drain
+#undef snd_rawmidi_drop
+#undef snd_rawmidi_write
+#undef snd_rawmidi_read
+#undef snd_rawmidi_name
+#undef snd_rawmidi_type
+#undef snd_rawmidi_stream
+#undef snd_timer_query_open
+#undef snd_timer_query_open_lconf
+#undef snd_timer_query_close
+#undef snd_timer_query_next_device
+#undef snd_timer_query_info
+#undef snd_timer_query_params
+#undef snd_timer_query_status
+#undef snd_timer_open
+#undef snd_timer_open_lconf
+#undef snd_timer_close
+#undef snd_async_add_timer_handler
+#undef snd_async_handler_get_timer
+#undef snd_timer_poll_descriptors_count
+#undef snd_timer_poll_descriptors
+#undef snd_timer_poll_descriptors_revents
+#undef snd_timer_info
+#undef snd_timer_params
+#undef snd_timer_status
+#undef snd_timer_start
+#undef snd_timer_stop
+#undef snd_timer_continue
+#undef snd_timer_read
+#undef snd_timer_id_sizeof
+#undef snd_timer_id_malloc
+#undef snd_timer_id_free
+#undef snd_timer_id_copy
+#undef snd_timer_id_set_class
+#undef snd_timer_id_get_class
+#undef snd_timer_id_set_sclass
+#undef snd_timer_id_get_sclass
+#undef snd_timer_id_set_card
+#undef snd_timer_id_get_card
+#undef snd_timer_id_set_device
+#undef snd_timer_id_get_device
+#undef snd_timer_id_set_subdevice
+#undef snd_timer_id_get_subdevice
+#undef snd_timer_ginfo_sizeof
+#undef snd_timer_ginfo_malloc
+#undef snd_timer_ginfo_free
+#undef snd_timer_ginfo_copy
+#undef snd_timer_ginfo_set_tid
+#undef snd_timer_ginfo_get_tid
+#undef snd_timer_ginfo_get_flags
+#undef snd_timer_ginfo_get_card
+#undef snd_timer_ginfo_get_id
+#undef snd_timer_ginfo_get_name
+#undef snd_timer_ginfo_get_resolution
+#undef snd_timer_ginfo_get_resolution_min
+#undef snd_timer_ginfo_get_resolution_max
+#undef snd_timer_ginfo_get_clients
+#undef snd_timer_info_sizeof
+#undef snd_timer_info_malloc
+#undef snd_timer_info_free
+#undef snd_timer_info_copy
+#undef snd_timer_info_is_slave
+#undef snd_timer_info_get_card
+#undef snd_timer_info_get_id
+#undef snd_timer_info_get_name
+#undef snd_timer_info_get_resolution
+#undef snd_timer_params_sizeof
+#undef snd_timer_params_malloc
+#undef snd_timer_params_free
+#undef snd_timer_params_copy
+#undef snd_timer_params_set_auto_start
+#undef snd_timer_params_get_auto_start
+#undef snd_timer_params_set_exclusive
+#undef snd_timer_params_get_exclusive
+#undef snd_timer_params_set_early_event
+#undef snd_timer_params_get_early_event
+#undef snd_timer_params_set_ticks
+#undef snd_timer_params_get_ticks
+#undef snd_timer_params_set_queue_size
+#undef snd_timer_params_get_queue_size
+#undef snd_timer_params_set_filter
+#undef snd_timer_params_get_filter
+#undef snd_timer_status_sizeof
+#undef snd_timer_status_malloc
+#undef snd_timer_status_free
+#undef snd_timer_status_copy
+#undef snd_timer_status_get_timestamp
+#undef snd_timer_status_get_resolution
+#undef snd_timer_status_get_lost
+#undef snd_timer_status_get_overrun
+#undef snd_timer_status_get_queue
+#undef snd_timer_info_get_ticks
+#undef snd_hwdep_open
+#undef snd_hwdep_close
+#undef snd_hwdep_poll_descriptors
+#undef snd_hwdep_poll_descriptors_count
+#undef snd_hwdep_poll_descriptors_revents
+#undef snd_hwdep_nonblock
+#undef snd_hwdep_info
+#undef snd_hwdep_dsp_status
+#undef snd_hwdep_dsp_load
+#undef snd_hwdep_ioctl
+#undef snd_hwdep_write
+#undef snd_hwdep_read
+#undef snd_hwdep_info_sizeof
+#undef snd_hwdep_info_malloc
+#undef snd_hwdep_info_free
+#undef snd_hwdep_info_copy
+#undef snd_hwdep_info_get_device
+#undef snd_hwdep_info_get_card
+#undef snd_hwdep_info_get_id
+#undef snd_hwdep_info_get_name
+#undef snd_hwdep_info_get_iface
+#undef snd_hwdep_info_set_device
+#undef snd_hwdep_dsp_status_sizeof
+#undef snd_hwdep_dsp_status_malloc
+#undef snd_hwdep_dsp_status_free
+#undef snd_hwdep_dsp_status_copy
+#undef snd_hwdep_dsp_status_get_version
+#undef snd_hwdep_dsp_status_get_id
+#undef snd_hwdep_dsp_status_get_num_dsps
+#undef snd_hwdep_dsp_status_get_dsp_loaded
+#undef snd_hwdep_dsp_status_get_chip_ready
+#undef snd_hwdep_dsp_image_sizeof
+#undef snd_hwdep_dsp_image_malloc
+#undef snd_hwdep_dsp_image_free
+#undef snd_hwdep_dsp_image_copy
+#undef snd_hwdep_dsp_image_get_index
+#undef snd_hwdep_dsp_image_get_name
+#undef snd_hwdep_dsp_image_get_image
+#undef snd_hwdep_dsp_image_get_length
+#undef snd_hwdep_dsp_image_set_index
+#undef snd_hwdep_dsp_image_set_name
+#undef snd_hwdep_dsp_image_set_image
+#undef snd_hwdep_dsp_image_set_length
+#undef snd_card_load
+#undef snd_card_next
+#undef snd_card_get_index
+#undef snd_card_get_name
+#undef snd_card_get_longname
+#undef snd_device_name_hint
+#undef snd_device_name_free_hint
+#undef snd_device_name_get_hint
+#undef snd_ctl_open
+#undef snd_ctl_open_lconf
+#undef snd_ctl_open_fallback
+#undef snd_ctl_close
+#undef snd_ctl_nonblock
+#undef snd_async_add_ctl_handler
+#undef snd_async_handler_get_ctl
+#undef snd_ctl_poll_descriptors_count
+#undef snd_ctl_poll_descriptors
+#undef snd_ctl_poll_descriptors_revents
+#undef snd_ctl_subscribe_events
+#undef snd_ctl_card_info
+#undef snd_ctl_elem_list
+#undef snd_ctl_elem_info
+#undef snd_ctl_elem_read
+#undef snd_ctl_elem_write
+#undef snd_ctl_elem_lock
+#undef snd_ctl_elem_unlock
+#undef snd_ctl_elem_tlv_read
+#undef snd_ctl_elem_tlv_write
+#undef snd_ctl_elem_tlv_command
+#undef snd_ctl_hwdep_next_device
+#undef snd_ctl_hwdep_info
+#undef snd_ctl_pcm_next_device
+#undef snd_ctl_pcm_info
+#undef snd_ctl_pcm_prefer_subdevice
+#undef snd_ctl_rawmidi_next_device
+#undef snd_ctl_rawmidi_info
+#undef snd_ctl_rawmidi_prefer_subdevice
+#undef snd_ctl_set_power_state
+#undef snd_ctl_get_power_state
+#undef snd_ctl_read
+#undef snd_ctl_wait
+#undef snd_ctl_name
+#undef snd_ctl_type
+#undef snd_ctl_elem_type_name
+#undef snd_ctl_elem_iface_name
+#undef snd_ctl_event_type_name
+#undef snd_ctl_event_elem_get_mask
+#undef snd_ctl_event_elem_get_numid
+#undef snd_ctl_event_elem_get_id
+#undef snd_ctl_event_elem_get_interface
+#undef snd_ctl_event_elem_get_device
+#undef snd_ctl_event_elem_get_subdevice
+#undef snd_ctl_event_elem_get_name
+#undef snd_ctl_event_elem_get_index
+#undef snd_ctl_elem_list_alloc_space
+#undef snd_ctl_elem_list_free_space
+#undef snd_ctl_ascii_elem_id_get
+#undef snd_ctl_ascii_elem_id_parse
+#undef snd_ctl_ascii_value_parse
+#undef snd_ctl_elem_id_sizeof
+#undef snd_ctl_elem_id_malloc
+#undef snd_ctl_elem_id_free
+#undef snd_ctl_elem_id_clear
+#undef snd_ctl_elem_id_copy
+#undef snd_ctl_elem_id_get_numid
+#undef snd_ctl_elem_id_get_interface
+#undef snd_ctl_elem_id_get_device
+#undef snd_ctl_elem_id_get_subdevice
+#undef snd_ctl_elem_id_get_name
+#undef snd_ctl_elem_id_get_index
+#undef snd_ctl_elem_id_set_numid
+#undef snd_ctl_elem_id_set_interface
+#undef snd_ctl_elem_id_set_device
+#undef snd_ctl_elem_id_set_subdevice
+#undef snd_ctl_elem_id_set_name
+#undef snd_ctl_elem_id_set_index
+#undef snd_ctl_card_info_sizeof
+#undef snd_ctl_card_info_malloc
+#undef snd_ctl_card_info_free
+#undef snd_ctl_card_info_clear
+#undef snd_ctl_card_info_copy
+#undef snd_ctl_card_info_get_card
+#undef snd_ctl_card_info_get_id
+#undef snd_ctl_card_info_get_driver
+#undef snd_ctl_card_info_get_name
+#undef snd_ctl_card_info_get_longname
+#undef snd_ctl_card_info_get_mixername
+#undef snd_ctl_card_info_get_components
+#undef snd_ctl_event_sizeof
+#undef snd_ctl_event_malloc
+#undef snd_ctl_event_free
+#undef snd_ctl_event_clear
+#undef snd_ctl_event_copy
+#undef snd_ctl_event_get_type
+#undef snd_ctl_elem_list_sizeof
+#undef snd_ctl_elem_list_malloc
+#undef snd_ctl_elem_list_free
+#undef snd_ctl_elem_list_clear
+#undef snd_ctl_elem_list_copy
+#undef snd_ctl_elem_list_set_offset
+#undef snd_ctl_elem_list_get_used
+#undef snd_ctl_elem_list_get_count
+#undef snd_ctl_elem_list_get_id
+#undef snd_ctl_elem_list_get_numid
+#undef snd_ctl_elem_list_get_interface
+#undef snd_ctl_elem_list_get_device
+#undef snd_ctl_elem_list_get_subdevice
+#undef snd_ctl_elem_list_get_name
+#undef snd_ctl_elem_list_get_index
+#undef snd_ctl_elem_info_sizeof
+#undef snd_ctl_elem_info_malloc
+#undef snd_ctl_elem_info_free
+#undef snd_ctl_elem_info_clear
+#undef snd_ctl_elem_info_copy
+#undef snd_ctl_elem_info_get_type
+#undef snd_ctl_elem_info_is_readable
+#undef snd_ctl_elem_info_is_writable
+#undef snd_ctl_elem_info_is_volatile
+#undef snd_ctl_elem_info_is_inactive
+#undef snd_ctl_elem_info_is_locked
+#undef snd_ctl_elem_info_is_tlv_readable
+#undef snd_ctl_elem_info_is_tlv_writable
+#undef snd_ctl_elem_info_is_tlv_commandable
+#undef snd_ctl_elem_info_is_owner
+#undef snd_ctl_elem_info_is_user
+#undef snd_ctl_elem_info_get_owner
+#undef snd_ctl_elem_info_get_count
+#undef snd_ctl_elem_info_get_min
+#undef snd_ctl_elem_info_get_max
+#undef snd_ctl_elem_info_get_step
+#undef snd_ctl_elem_info_get_min64
+#undef snd_ctl_elem_info_get_max64
+#undef snd_ctl_elem_info_get_step64
+#undef snd_ctl_elem_info_get_items
+#undef snd_ctl_elem_info_set_item
+#undef snd_ctl_elem_info_get_item_name
+#undef snd_ctl_elem_info_get_dimensions
+#undef snd_ctl_elem_info_get_dimension
+#undef snd_ctl_elem_info_set_dimension
+#undef snd_ctl_elem_info_get_id
+#undef snd_ctl_elem_info_get_numid
+#undef snd_ctl_elem_info_get_interface
+#undef snd_ctl_elem_info_get_device
+#undef snd_ctl_elem_info_get_subdevice
+#undef snd_ctl_elem_info_get_name
+#undef snd_ctl_elem_info_get_index
+#undef snd_ctl_elem_info_set_id
+#undef snd_ctl_elem_info_set_numid
+#undef snd_ctl_elem_info_set_interface
+#undef snd_ctl_elem_info_set_device
+#undef snd_ctl_elem_info_set_subdevice
+#undef snd_ctl_elem_info_set_name
+#undef snd_ctl_elem_info_set_index
+#undef snd_ctl_add_integer_elem_set
+#undef snd_ctl_add_integer64_elem_set
+#undef snd_ctl_add_boolean_elem_set
+#undef snd_ctl_add_enumerated_elem_set
+#undef snd_ctl_add_bytes_elem_set
+#undef snd_ctl_elem_add_integer
+#undef snd_ctl_elem_add_integer64
+#undef snd_ctl_elem_add_boolean
+#undef snd_ctl_elem_add_enumerated
+#undef snd_ctl_elem_add_iec958
+#undef snd_ctl_elem_remove
+#undef snd_ctl_elem_value_sizeof
+#undef snd_ctl_elem_value_malloc
+#undef snd_ctl_elem_value_free
+#undef snd_ctl_elem_value_clear
+#undef snd_ctl_elem_value_copy
+#undef snd_ctl_elem_value_compare
+#undef snd_ctl_elem_value_get_id
+#undef snd_ctl_elem_value_get_numid
+#undef snd_ctl_elem_value_get_interface
+#undef snd_ctl_elem_value_get_device
+#undef snd_ctl_elem_value_get_subdevice
+#undef snd_ctl_elem_value_get_name
+#undef snd_ctl_elem_value_get_index
+#undef snd_ctl_elem_value_set_id
+#undef snd_ctl_elem_value_set_numid
+#undef snd_ctl_elem_value_set_interface
+#undef snd_ctl_elem_value_set_device
+#undef snd_ctl_elem_value_set_subdevice
+#undef snd_ctl_elem_value_set_name
+#undef snd_ctl_elem_value_set_index
+#undef snd_ctl_elem_value_get_boolean
+#undef snd_ctl_elem_value_get_integer
+#undef snd_ctl_elem_value_get_integer64
+#undef snd_ctl_elem_value_get_enumerated
+#undef snd_ctl_elem_value_get_byte
+#undef snd_ctl_elem_value_set_boolean
+#undef snd_ctl_elem_value_set_integer
+#undef snd_ctl_elem_value_set_integer64
+#undef snd_ctl_elem_value_set_enumerated
+#undef snd_ctl_elem_value_set_byte
+#undef snd_ctl_elem_set_bytes
+#undef snd_ctl_elem_value_get_bytes
+#undef snd_ctl_elem_value_get_iec958
+#undef snd_ctl_elem_value_set_iec958
+#undef snd_tlv_parse_dB_info
+#undef snd_tlv_get_dB_range
+#undef snd_tlv_convert_to_dB
+#undef snd_tlv_convert_from_dB
+#undef snd_ctl_get_dB_range
+#undef snd_ctl_convert_to_dB
+#undef snd_ctl_convert_from_dB
+#undef snd_hctl_compare_fast
+#undef snd_hctl_open
+#undef snd_hctl_open_ctl
+#undef snd_hctl_close
+#undef snd_hctl_nonblock
+#undef snd_hctl_poll_descriptors_count
+#undef snd_hctl_poll_descriptors
+#undef snd_hctl_poll_descriptors_revents
+#undef snd_hctl_get_count
+#undef snd_hctl_set_compare
+#undef snd_hctl_first_elem
+#undef snd_hctl_last_elem
+#undef snd_hctl_find_elem
+#undef snd_hctl_set_callback
+#undef snd_hctl_set_callback_private
+#undef snd_hctl_get_callback_private
+#undef snd_hctl_load
+#undef snd_hctl_free
+#undef snd_hctl_handle_events
+#undef snd_hctl_name
+#undef snd_hctl_wait
+#undef snd_hctl_ctl
+#undef snd_hctl_elem_next
+#undef snd_hctl_elem_prev
+#undef snd_hctl_elem_info
+#undef snd_hctl_elem_read
+#undef snd_hctl_elem_write
+#undef snd_hctl_elem_tlv_read
+#undef snd_hctl_elem_tlv_write
+#undef snd_hctl_elem_tlv_command
+#undef snd_hctl_elem_get_hctl
+#undef snd_hctl_elem_get_id
+#undef snd_hctl_elem_get_numid
+#undef snd_hctl_elem_get_interface
+#undef snd_hctl_elem_get_device
+#undef snd_hctl_elem_get_subdevice
+#undef snd_hctl_elem_get_name
+#undef snd_hctl_elem_get_index
+#undef snd_hctl_elem_set_callback
+#undef snd_hctl_elem_get_callback_private
+#undef snd_hctl_elem_set_callback_private
+#undef snd_sctl_build
+#undef snd_sctl_free
+#undef snd_sctl_install
+#undef snd_sctl_remove
+#undef snd_mixer_open
+#undef snd_mixer_close
+#undef snd_mixer_first_elem
+#undef snd_mixer_last_elem
+#undef snd_mixer_handle_events
+#undef snd_mixer_attach
+#undef snd_mixer_attach_hctl
+#undef snd_mixer_detach
+#undef snd_mixer_detach_hctl
+#undef snd_mixer_get_hctl
+#undef snd_mixer_poll_descriptors_count
+#undef snd_mixer_poll_descriptors
+#undef snd_mixer_poll_descriptors_revents
+#undef snd_mixer_load
+#undef snd_mixer_free
+#undef snd_mixer_wait
+#undef snd_mixer_set_compare
+#undef snd_mixer_set_callback
+#undef snd_mixer_get_callback_private
+#undef snd_mixer_set_callback_private
+#undef snd_mixer_get_count
+#undef snd_mixer_class_unregister
+#undef snd_mixer_elem_next
+#undef snd_mixer_elem_prev
+#undef snd_mixer_elem_set_callback
+#undef snd_mixer_elem_get_callback_private
+#undef snd_mixer_elem_set_callback_private
+#undef snd_mixer_elem_get_type
+#undef snd_mixer_class_register
+#undef snd_mixer_elem_new
+#undef snd_mixer_elem_add
+#undef snd_mixer_elem_remove
+#undef snd_mixer_elem_free
+#undef snd_mixer_elem_info
+#undef snd_mixer_elem_value
+#undef snd_mixer_elem_attach
+#undef snd_mixer_elem_detach
+#undef snd_mixer_elem_empty
+#undef snd_mixer_elem_get_private
+#undef snd_mixer_class_sizeof
+#undef snd_mixer_class_malloc
+#undef snd_mixer_class_free
+#undef snd_mixer_class_copy
+#undef snd_mixer_class_get_mixer
+#undef snd_mixer_class_get_event
+#undef snd_mixer_class_get_private
+#undef snd_mixer_class_get_compare
+#undef snd_mixer_class_set_event
+#undef snd_mixer_class_set_private
+#undef snd_mixer_class_set_private_free
+#undef snd_mixer_class_set_compare
+#undef snd_mixer_selem_channel_name
+#undef snd_mixer_selem_register
+#undef snd_mixer_selem_get_id
+#undef snd_mixer_selem_get_name
+#undef snd_mixer_selem_get_index
+#undef snd_mixer_find_selem
+#undef snd_mixer_selem_is_active
+#undef snd_mixer_selem_is_playback_mono
+#undef snd_mixer_selem_has_playback_channel
+#undef snd_mixer_selem_is_capture_mono
+#undef snd_mixer_selem_has_capture_channel
+#undef snd_mixer_selem_get_capture_group
+#undef snd_mixer_selem_has_common_volume
+#undef snd_mixer_selem_has_playback_volume
+#undef snd_mixer_selem_has_playback_volume_joined
+#undef snd_mixer_selem_has_capture_volume
+#undef snd_mixer_selem_has_capture_volume_joined
+#undef snd_mixer_selem_has_common_switch
+#undef snd_mixer_selem_has_playback_switch
+#undef snd_mixer_selem_has_playback_switch_joined
+#undef snd_mixer_selem_has_capture_switch
+#undef snd_mixer_selem_has_capture_switch_joined
+#undef snd_mixer_selem_has_capture_switch_exclusive
+#undef snd_mixer_selem_ask_playback_vol_dB
+#undef snd_mixer_selem_ask_capture_vol_dB
+#undef snd_mixer_selem_ask_playback_dB_vol
+#undef snd_mixer_selem_ask_capture_dB_vol
+#undef snd_mixer_selem_get_playback_volume
+#undef snd_mixer_selem_get_capture_volume
+#undef snd_mixer_selem_get_playback_dB
+#undef snd_mixer_selem_get_capture_dB
+#undef snd_mixer_selem_get_playback_switch
+#undef snd_mixer_selem_get_capture_switch
+#undef snd_mixer_selem_set_playback_volume
+#undef snd_mixer_selem_set_capture_volume
+#undef snd_mixer_selem_set_playback_dB
+#undef snd_mixer_selem_set_capture_dB
+#undef snd_mixer_selem_set_playback_volume_all
+#undef snd_mixer_selem_set_capture_volume_all
+#undef snd_mixer_selem_set_playback_dB_all
+#undef snd_mixer_selem_set_capture_dB_all
+#undef snd_mixer_selem_set_playback_switch
+#undef snd_mixer_selem_set_capture_switch
+#undef snd_mixer_selem_set_playback_switch_all
+#undef snd_mixer_selem_set_capture_switch_all
+#undef snd_mixer_selem_get_playback_volume_range
+#undef snd_mixer_selem_get_playback_dB_range
+#undef snd_mixer_selem_set_playback_volume_range
+#undef snd_mixer_selem_get_capture_volume_range
+#undef snd_mixer_selem_get_capture_dB_range
+#undef snd_mixer_selem_set_capture_volume_range
+#undef snd_mixer_selem_is_enumerated
+#undef snd_mixer_selem_is_enum_playback
+#undef snd_mixer_selem_is_enum_capture
+#undef snd_mixer_selem_get_enum_items
+#undef snd_mixer_selem_get_enum_item_name
+#undef snd_mixer_selem_get_enum_item
+#undef snd_mixer_selem_set_enum_item
+#undef snd_mixer_selem_id_sizeof
+#undef snd_mixer_selem_id_malloc
+#undef snd_mixer_selem_id_free
+#undef snd_mixer_selem_id_copy
+#undef snd_mixer_selem_id_get_name
+#undef snd_mixer_selem_id_get_index
+#undef snd_mixer_selem_id_set_name
+#undef snd_mixer_selem_id_set_index
+#undef snd_mixer_selem_id_parse
+#undef snd_seq_open
+#undef snd_seq_open_lconf
+#undef snd_seq_name
+#undef snd_seq_type
+#undef snd_seq_close
+#undef snd_seq_poll_descriptors_count
+#undef snd_seq_poll_descriptors
+#undef snd_seq_poll_descriptors_revents
+#undef snd_seq_nonblock
+#undef snd_seq_client_id
+#undef snd_seq_get_output_buffer_size
+#undef snd_seq_get_input_buffer_size
+#undef snd_seq_set_output_buffer_size
+#undef snd_seq_set_input_buffer_size
+#undef snd_seq_system_info_sizeof
+#undef snd_seq_system_info_malloc
+#undef snd_seq_system_info_free
+#undef snd_seq_system_info_copy
+#undef snd_seq_system_info_get_queues
+#undef snd_seq_system_info_get_clients
+#undef snd_seq_system_info_get_ports
+#undef snd_seq_system_info_get_channels
+#undef snd_seq_system_info_get_cur_clients
+#undef snd_seq_system_info_get_cur_queues
+#undef snd_seq_system_info
+#undef snd_seq_client_info_sizeof
+#undef snd_seq_client_info_malloc
+#undef snd_seq_client_info_free
+#undef snd_seq_client_info_copy
+#undef snd_seq_client_info_get_client
+#undef snd_seq_client_info_get_type
+#undef snd_seq_client_info_get_name
+#undef snd_seq_client_info_get_broadcast_filter
+#undef snd_seq_client_info_get_error_bounce
+#undef snd_seq_client_info_get_card
+#undef snd_seq_client_info_get_pid
+#undef snd_seq_client_info_get_event_filter
+#undef snd_seq_client_info_get_num_ports
+#undef snd_seq_client_info_get_event_lost
+#undef snd_seq_client_info_set_client
+#undef snd_seq_client_info_set_name
+#undef snd_seq_client_info_set_broadcast_filter
+#undef snd_seq_client_info_set_error_bounce
+#undef snd_seq_client_info_set_event_filter
+#undef snd_seq_client_info_event_filter_clear
+#undef snd_seq_client_info_event_filter_add
+#undef snd_seq_client_info_event_filter_del
+#undef snd_seq_client_info_event_filter_check
+#undef snd_seq_get_client_info
+#undef snd_seq_get_any_client_info
+#undef snd_seq_set_client_info
+#undef snd_seq_query_next_client
+#undef snd_seq_client_pool_sizeof
+#undef snd_seq_client_pool_malloc
+#undef snd_seq_client_pool_free
+#undef snd_seq_client_pool_copy
+#undef snd_seq_client_pool_get_client
+#undef snd_seq_client_pool_get_output_pool
+#undef snd_seq_client_pool_get_input_pool
+#undef snd_seq_client_pool_get_output_room
+#undef snd_seq_client_pool_get_output_free
+#undef snd_seq_client_pool_get_input_free
+#undef snd_seq_client_pool_set_output_pool
+#undef snd_seq_client_pool_set_input_pool
+#undef snd_seq_client_pool_set_output_room
+#undef snd_seq_get_client_pool
+#undef snd_seq_set_client_pool
+#undef snd_seq_port_info_sizeof
+#undef snd_seq_port_info_malloc
+#undef snd_seq_port_info_free
+#undef snd_seq_port_info_copy
+#undef snd_seq_port_info_get_client
+#undef snd_seq_port_info_get_port
+#undef snd_seq_port_info_get_addr
+#undef snd_seq_port_info_get_name
+#undef snd_seq_port_info_get_capability
+#undef snd_seq_port_info_get_type
+#undef snd_seq_port_info_get_midi_channels
+#undef snd_seq_port_info_get_midi_voices
+#undef snd_seq_port_info_get_synth_voices
+#undef snd_seq_port_info_get_read_use
+#undef snd_seq_port_info_get_write_use
+#undef snd_seq_port_info_get_port_specified
+#undef snd_seq_port_info_get_timestamping
+#undef snd_seq_port_info_get_timestamp_real
+#undef snd_seq_port_info_get_timestamp_queue
+#undef snd_seq_port_info_set_client
+#undef snd_seq_port_info_set_port
+#undef snd_seq_port_info_set_addr
+#undef snd_seq_port_info_set_name
+#undef snd_seq_port_info_set_capability
+#undef snd_seq_port_info_set_type
+#undef snd_seq_port_info_set_midi_channels
+#undef snd_seq_port_info_set_midi_voices
+#undef snd_seq_port_info_set_synth_voices
+#undef snd_seq_port_info_set_port_specified
+#undef snd_seq_port_info_set_timestamping
+#undef snd_seq_port_info_set_timestamp_real
+#undef snd_seq_port_info_set_timestamp_queue
+#undef snd_seq_create_port
+#undef snd_seq_delete_port
+#undef snd_seq_get_port_info
+#undef snd_seq_get_any_port_info
+#undef snd_seq_set_port_info
+#undef snd_seq_query_next_port
+#undef snd_seq_port_subscribe_sizeof
+#undef snd_seq_port_subscribe_malloc
+#undef snd_seq_port_subscribe_free
+#undef snd_seq_port_subscribe_copy
+#undef snd_seq_port_subscribe_get_sender
+#undef snd_seq_port_subscribe_get_dest
+#undef snd_seq_port_subscribe_get_queue
+#undef snd_seq_port_subscribe_get_exclusive
+#undef snd_seq_port_subscribe_get_time_update
+#undef snd_seq_port_subscribe_get_time_real
+#undef snd_seq_port_subscribe_set_sender
+#undef snd_seq_port_subscribe_set_dest
+#undef snd_seq_port_subscribe_set_queue
+#undef snd_seq_port_subscribe_set_exclusive
+#undef snd_seq_port_subscribe_set_time_update
+#undef snd_seq_port_subscribe_set_time_real
+#undef snd_seq_get_port_subscription
+#undef snd_seq_subscribe_port
+#undef snd_seq_unsubscribe_port
+#undef snd_seq_query_subscribe_sizeof
+#undef snd_seq_query_subscribe_malloc
+#undef snd_seq_query_subscribe_free
+#undef snd_seq_query_subscribe_copy
+#undef snd_seq_query_subscribe_get_client
+#undef snd_seq_query_subscribe_get_port
+#undef snd_seq_query_subscribe_get_root
+#undef snd_seq_query_subscribe_get_type
+#undef snd_seq_query_subscribe_get_index
+#undef snd_seq_query_subscribe_get_num_subs
+#undef snd_seq_query_subscribe_get_addr
+#undef snd_seq_query_subscribe_get_queue
+#undef snd_seq_query_subscribe_get_exclusive
+#undef snd_seq_query_subscribe_get_time_update
+#undef snd_seq_query_subscribe_get_time_real
+#undef snd_seq_query_subscribe_set_client
+#undef snd_seq_query_subscribe_set_port
+#undef snd_seq_query_subscribe_set_root
+#undef snd_seq_query_subscribe_set_type
+#undef snd_seq_query_subscribe_set_index
+#undef snd_seq_query_port_subscribers
+#undef snd_seq_queue_info_sizeof
+#undef snd_seq_queue_info_malloc
+#undef snd_seq_queue_info_free
+#undef snd_seq_queue_info_copy
+#undef snd_seq_queue_info_get_queue
+#undef snd_seq_queue_info_get_name
+#undef snd_seq_queue_info_get_owner
+#undef snd_seq_queue_info_get_locked
+#undef snd_seq_queue_info_get_flags
+#undef snd_seq_queue_info_set_name
+#undef snd_seq_queue_info_set_owner
+#undef snd_seq_queue_info_set_locked
+#undef snd_seq_queue_info_set_flags
+#undef snd_seq_create_queue
+#undef snd_seq_alloc_named_queue
+#undef snd_seq_alloc_queue
+#undef snd_seq_free_queue
+#undef snd_seq_get_queue_info
+#undef snd_seq_set_queue_info
+#undef snd_seq_query_named_queue
+#undef snd_seq_get_queue_usage
+#undef snd_seq_set_queue_usage
+#undef snd_seq_queue_status_sizeof
+#undef snd_seq_queue_status_malloc
+#undef snd_seq_queue_status_free
+#undef snd_seq_queue_status_copy
+#undef snd_seq_queue_status_get_queue
+#undef snd_seq_queue_status_get_events
+#undef snd_seq_queue_status_get_tick_time
+#undef snd_seq_queue_status_get_real_time
+#undef snd_seq_queue_status_get_status
+#undef snd_seq_get_queue_status
+#undef snd_seq_queue_tempo_sizeof
+#undef snd_seq_queue_tempo_malloc
+#undef snd_seq_queue_tempo_free
+#undef snd_seq_queue_tempo_copy
+#undef snd_seq_queue_tempo_get_queue
+#undef snd_seq_queue_tempo_get_tempo
+#undef snd_seq_queue_tempo_get_ppq
+#undef snd_seq_queue_tempo_get_skew
+#undef snd_seq_queue_tempo_get_skew_base
+#undef snd_seq_queue_tempo_set_tempo
+#undef snd_seq_queue_tempo_set_ppq
+#undef snd_seq_queue_tempo_set_skew
+#undef snd_seq_queue_tempo_set_skew_base
+#undef snd_seq_get_queue_tempo
+#undef snd_seq_set_queue_tempo
+#undef snd_seq_queue_timer_sizeof
+#undef snd_seq_queue_timer_malloc
+#undef snd_seq_queue_timer_free
+#undef snd_seq_queue_timer_copy
+#undef snd_seq_queue_timer_get_queue
+#undef snd_seq_queue_timer_get_type
+#undef snd_seq_queue_timer_get_id
+#undef snd_seq_queue_timer_get_resolution
+#undef snd_seq_queue_timer_set_type
+#undef snd_seq_queue_timer_set_id
+#undef snd_seq_queue_timer_set_resolution
+#undef snd_seq_get_queue_timer
+#undef snd_seq_set_queue_timer
+#undef snd_seq_free_event
+#undef snd_seq_event_length
+#undef snd_seq_event_output
+#undef snd_seq_event_output_buffer
+#undef snd_seq_event_output_direct
+#undef snd_seq_event_input
+#undef snd_seq_event_input_pending
+#undef snd_seq_drain_output
+#undef snd_seq_event_output_pending
+#undef snd_seq_extract_output
+#undef snd_seq_drop_output
+#undef snd_seq_drop_output_buffer
+#undef snd_seq_drop_input
+#undef snd_seq_drop_input_buffer
+#undef snd_seq_remove_events_sizeof
+#undef snd_seq_remove_events_malloc
+#undef snd_seq_remove_events_free
+#undef snd_seq_remove_events_copy
+#undef snd_seq_remove_events_get_condition
+#undef snd_seq_remove_events_get_queue
+#undef snd_seq_remove_events_get_time
+#undef snd_seq_remove_events_get_dest
+#undef snd_seq_remove_events_get_channel
+#undef snd_seq_remove_events_get_event_type
+#undef snd_seq_remove_events_get_tag
+#undef snd_seq_remove_events_set_condition
+#undef snd_seq_remove_events_set_queue
+#undef snd_seq_remove_events_set_time
+#undef snd_seq_remove_events_set_dest
+#undef snd_seq_remove_events_set_channel
+#undef snd_seq_remove_events_set_event_type
+#undef snd_seq_remove_events_set_tag
+#undef snd_seq_remove_events
+#undef snd_seq_set_bit
+#undef snd_seq_unset_bit
+#undef snd_seq_change_bit
+#undef snd_seq_get_bit
+#undef snd_seq_control_queue
+#undef snd_seq_create_simple_port
+#undef snd_seq_delete_simple_port
+#undef snd_seq_connect_from
+#undef snd_seq_connect_to
+#undef snd_seq_disconnect_from
+#undef snd_seq_disconnect_to
+#undef snd_seq_set_client_name
+#undef snd_seq_set_client_event_filter
+#undef snd_seq_set_client_pool_output
+#undef snd_seq_set_client_pool_output_room
+#undef snd_seq_set_client_pool_input
+#undef snd_seq_sync_output_queue
+#undef snd_seq_parse_address
+#undef snd_seq_reset_pool_output
+#undef snd_seq_reset_pool_input
+#undef snd_midi_event_new
+#undef snd_midi_event_resize_buffer
+#undef snd_midi_event_free
+#undef snd_midi_event_init
+#undef snd_midi_event_reset_encode
+#undef snd_midi_event_reset_decode
+#undef snd_midi_event_no_status
+#undef snd_midi_event_encode
+#undef snd_midi_event_encode_byte
+#undef snd_midi_event_decode
+#include <dlfcn.h>
+#include <stdio.h>
+const char* (*snd_asoundlib_version_dylibloader_wrapper_asound)( void);
+int (*snd_dlpath_dylibloader_wrapper_asound)( char*, size_t,const char*);
+void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int, char*, size_t);
+void* (*snd_dlsym_dylibloader_wrapper_asound)( void*,const char*,const char*);
+int (*snd_dlclose_dylibloader_wrapper_asound)( void*);
+int (*snd_async_add_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, int, snd_async_callback_t, void*);
+int (*snd_async_del_handler_dylibloader_wrapper_asound)( snd_async_handler_t*);
+int (*snd_async_handler_get_fd_dylibloader_wrapper_asound)( snd_async_handler_t*);
+int (*snd_async_handler_get_signo_dylibloader_wrapper_asound)( snd_async_handler_t*);
+void* (*snd_async_handler_get_callback_private_dylibloader_wrapper_asound)( snd_async_handler_t*);
+struct snd_shm_area* (*snd_shm_area_create_dylibloader_wrapper_asound)( int, void*);
+struct snd_shm_area* (*snd_shm_area_share_dylibloader_wrapper_asound)(struct snd_shm_area*);
+int (*snd_shm_area_destroy_dylibloader_wrapper_asound)(struct snd_shm_area*);
+int (*snd_user_file_dylibloader_wrapper_asound)(const char*, char**);
+int (*snd_input_stdio_open_dylibloader_wrapper_asound)( snd_input_t**,const char*,const char*);
+int (*snd_input_stdio_attach_dylibloader_wrapper_asound)( snd_input_t**, FILE*, int);
+int (*snd_input_buffer_open_dylibloader_wrapper_asound)( snd_input_t**,const char*, ssize_t);
+int (*snd_input_close_dylibloader_wrapper_asound)( snd_input_t*);
+int (*snd_input_scanf_dylibloader_wrapper_asound)( snd_input_t*,const char*,...);
+char* (*snd_input_gets_dylibloader_wrapper_asound)( snd_input_t*, char*, size_t);
+int (*snd_input_getc_dylibloader_wrapper_asound)( snd_input_t*);
+int (*snd_input_ungetc_dylibloader_wrapper_asound)( snd_input_t*, int);
+int (*snd_output_stdio_open_dylibloader_wrapper_asound)( snd_output_t**,const char*,const char*);
+int (*snd_output_stdio_attach_dylibloader_wrapper_asound)( snd_output_t**, FILE*, int);
+int (*snd_output_buffer_open_dylibloader_wrapper_asound)( snd_output_t**);
+size_t (*snd_output_buffer_string_dylibloader_wrapper_asound)( snd_output_t*, char**);
+int (*snd_output_close_dylibloader_wrapper_asound)( snd_output_t*);
+int (*snd_output_printf_dylibloader_wrapper_asound)( snd_output_t*,const char*,...);
+int (*snd_output_vprintf_dylibloader_wrapper_asound)( snd_output_t*,const char*, va_list);
+int (*snd_output_puts_dylibloader_wrapper_asound)( snd_output_t*,const char*);
+int (*snd_output_putc_dylibloader_wrapper_asound)( snd_output_t*, int);
+int (*snd_output_flush_dylibloader_wrapper_asound)( snd_output_t*);
+const char* (*snd_strerror_dylibloader_wrapper_asound)( int);
+int (*snd_lib_error_set_handler_dylibloader_wrapper_asound)( snd_lib_error_handler_t);
+snd_local_error_handler_t (*snd_lib_error_set_local_dylibloader_wrapper_asound)( snd_local_error_handler_t);
+const char* (*snd_config_topdir_dylibloader_wrapper_asound)( void);
+int (*snd_config_top_dylibloader_wrapper_asound)( snd_config_t**);
+int (*snd_config_load_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
+int (*snd_config_load_override_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
+int (*snd_config_save_dylibloader_wrapper_asound)( snd_config_t*, snd_output_t*);
+int (*snd_config_update_dylibloader_wrapper_asound)( void);
+int (*snd_config_update_r_dylibloader_wrapper_asound)( snd_config_t**, snd_config_update_t**,const char*);
+int (*snd_config_update_free_dylibloader_wrapper_asound)( snd_config_update_t*);
+int (*snd_config_update_free_global_dylibloader_wrapper_asound)( void);
+int (*snd_config_update_ref_dylibloader_wrapper_asound)( snd_config_t**);
+void (*snd_config_ref_dylibloader_wrapper_asound)( snd_config_t*);
+void (*snd_config_unref_dylibloader_wrapper_asound)( snd_config_t*);
+int (*snd_config_search_dylibloader_wrapper_asound)( snd_config_t*,const char*, snd_config_t**);
+int (*snd_config_searchv_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t**,...);
+int (*snd_config_search_definition_dylibloader_wrapper_asound)( snd_config_t*,const char*,const char*, snd_config_t**);
+int (*snd_config_expand_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*,const char*, snd_config_t*, snd_config_t**);
+int (*snd_config_evaluate_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*, snd_config_t*, snd_config_t**);
+int (*snd_config_add_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+int (*snd_config_add_before_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+int (*snd_config_add_after_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+int (*snd_config_remove_dylibloader_wrapper_asound)( snd_config_t*);
+int (*snd_config_delete_dylibloader_wrapper_asound)( snd_config_t*);
+int (*snd_config_delete_compound_members_dylibloader_wrapper_asound)(const snd_config_t*);
+int (*snd_config_copy_dylibloader_wrapper_asound)( snd_config_t**, snd_config_t*);
+int (*snd_config_make_dylibloader_wrapper_asound)( snd_config_t**,const char*, snd_config_type_t);
+int (*snd_config_make_integer_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+int (*snd_config_make_integer64_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+int (*snd_config_make_real_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+int (*snd_config_make_string_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+int (*snd_config_make_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+int (*snd_config_make_compound_dylibloader_wrapper_asound)( snd_config_t**,const char*, int);
+int (*snd_config_imake_integer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const long);
+int (*snd_config_imake_integer64_dylibloader_wrapper_asound)( snd_config_t**,const char*,const long long);
+int (*snd_config_imake_real_dylibloader_wrapper_asound)( snd_config_t**,const char*,const double);
+int (*snd_config_imake_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
+int (*snd_config_imake_safe_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
+int (*snd_config_imake_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const void*);
+snd_config_type_t (*snd_config_get_type_dylibloader_wrapper_asound)(const snd_config_t*);
+int (*snd_config_is_array_dylibloader_wrapper_asound)(const snd_config_t*);
+int (*snd_config_set_id_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+int (*snd_config_set_integer_dylibloader_wrapper_asound)( snd_config_t*, long);
+int (*snd_config_set_integer64_dylibloader_wrapper_asound)( snd_config_t*, long long);
+int (*snd_config_set_real_dylibloader_wrapper_asound)( snd_config_t*, double);
+int (*snd_config_set_string_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+int (*snd_config_set_ascii_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+int (*snd_config_set_pointer_dylibloader_wrapper_asound)( snd_config_t*,const void*);
+int (*snd_config_get_id_dylibloader_wrapper_asound)(const snd_config_t*,const char**);
+int (*snd_config_get_integer_dylibloader_wrapper_asound)(const snd_config_t*, long*);
+int (*snd_config_get_integer64_dylibloader_wrapper_asound)(const snd_config_t*, long long*);
+int (*snd_config_get_real_dylibloader_wrapper_asound)(const snd_config_t*, double*);
+int (*snd_config_get_ireal_dylibloader_wrapper_asound)(const snd_config_t*, double*);
+int (*snd_config_get_string_dylibloader_wrapper_asound)(const snd_config_t*,const char**);
+int (*snd_config_get_ascii_dylibloader_wrapper_asound)(const snd_config_t*, char**);
+int (*snd_config_get_pointer_dylibloader_wrapper_asound)(const snd_config_t*,const void**);
+int (*snd_config_test_id_dylibloader_wrapper_asound)(const snd_config_t*,const char*);
+snd_config_iterator_t (*snd_config_iterator_first_dylibloader_wrapper_asound)(const snd_config_t*);
+snd_config_iterator_t (*snd_config_iterator_next_dylibloader_wrapper_asound)(const snd_config_iterator_t);
+snd_config_iterator_t (*snd_config_iterator_end_dylibloader_wrapper_asound)(const snd_config_t*);
+snd_config_t* (*snd_config_iterator_entry_dylibloader_wrapper_asound)(const snd_config_iterator_t);
+int (*snd_config_get_bool_ascii_dylibloader_wrapper_asound)(const char*);
+int (*snd_config_get_bool_dylibloader_wrapper_asound)(const snd_config_t*);
+int (*snd_config_get_ctl_iface_ascii_dylibloader_wrapper_asound)(const char*);
+int (*snd_config_get_ctl_iface_dylibloader_wrapper_asound)(const snd_config_t*);
+int (*snd_names_list_dylibloader_wrapper_asound)(const char*, snd_devname_t**);
+void (*snd_names_list_free_dylibloader_wrapper_asound)( snd_devname_t*);
+int (*snd_pcm_open_dylibloader_wrapper_asound)( snd_pcm_t**,const char*, snd_pcm_stream_t, int);
+int (*snd_pcm_open_lconf_dylibloader_wrapper_asound)( snd_pcm_t**,const char*, snd_pcm_stream_t, int, snd_config_t*);
+int (*snd_pcm_open_fallback_dylibloader_wrapper_asound)( snd_pcm_t**, snd_config_t*,const char*,const char*, snd_pcm_stream_t, int);
+int (*snd_pcm_close_dylibloader_wrapper_asound)( snd_pcm_t*);
+const char* (*snd_pcm_name_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_type_t (*snd_pcm_type_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_stream_t (*snd_pcm_stream_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_poll_descriptors_count_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_poll_descriptors_dylibloader_wrapper_asound)( snd_pcm_t*,struct pollfd*, unsigned int);
+int (*snd_pcm_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_pcm_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_pcm_nonblock_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+int (*snd_async_add_pcm_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_pcm_t*, snd_async_callback_t, void*);
+snd_pcm_t* (*snd_async_handler_get_pcm_dylibloader_wrapper_asound)( snd_async_handler_t*);
+int (*snd_pcm_info_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_info_t*);
+int (*snd_pcm_hw_params_current_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_free_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_sw_params_current_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*);
+int (*snd_pcm_sw_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*);
+int (*snd_pcm_prepare_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_reset_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_status_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_status_t*);
+int (*snd_pcm_start_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_drop_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_drain_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_pause_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+snd_pcm_state_t (*snd_pcm_state_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_hwsync_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_delay_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t*);
+int (*snd_pcm_resume_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_htimestamp_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t*, snd_htimestamp_t*);
+snd_pcm_sframes_t (*snd_pcm_avail_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_sframes_t (*snd_pcm_avail_update_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_avail_delay_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t*, snd_pcm_sframes_t*);
+snd_pcm_sframes_t (*snd_pcm_rewindable_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_sframes_t (*snd_pcm_rewind_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_forwardable_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_sframes_t (*snd_pcm_forward_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_writei_dylibloader_wrapper_asound)( snd_pcm_t*,const void*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_readi_dylibloader_wrapper_asound)( snd_pcm_t*, void*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_writen_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_readn_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+int (*snd_pcm_wait_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+int (*snd_pcm_link_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_t*);
+int (*snd_pcm_unlink_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_chmap_query_t** (*snd_pcm_query_chmaps_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_chmap_query_t** (*snd_pcm_query_chmaps_from_hw_dylibloader_wrapper_asound)( int, int, int, snd_pcm_stream_t);
+void (*snd_pcm_free_chmaps_dylibloader_wrapper_asound)( snd_pcm_chmap_query_t**);
+snd_pcm_chmap_t* (*snd_pcm_get_chmap_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_set_chmap_dylibloader_wrapper_asound)( snd_pcm_t*,const snd_pcm_chmap_t*);
+const char* (*snd_pcm_chmap_type_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_type);
+const char* (*snd_pcm_chmap_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_position);
+const char* (*snd_pcm_chmap_long_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_position);
+int (*snd_pcm_chmap_print_dylibloader_wrapper_asound)(const snd_pcm_chmap_t*, size_t, char*);
+unsigned int (*snd_pcm_chmap_from_string_dylibloader_wrapper_asound)(const char*);
+snd_pcm_chmap_t* (*snd_pcm_chmap_parse_string_dylibloader_wrapper_asound)(const char*);
+int (*snd_pcm_recover_dylibloader_wrapper_asound)( snd_pcm_t*, int, int);
+int (*snd_pcm_set_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_format_t, snd_pcm_access_t, unsigned int, unsigned int, int, unsigned int);
+int (*snd_pcm_get_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+size_t (*snd_pcm_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_info_malloc_dylibloader_wrapper_asound)( snd_pcm_info_t**);
+void (*snd_pcm_info_free_dylibloader_wrapper_asound)( snd_pcm_info_t*);
+void (*snd_pcm_info_copy_dylibloader_wrapper_asound)( snd_pcm_info_t*,const snd_pcm_info_t*);
+unsigned int (*snd_pcm_info_get_device_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+unsigned int (*snd_pcm_info_get_subdevice_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+snd_pcm_stream_t (*snd_pcm_info_get_stream_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+int (*snd_pcm_info_get_card_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+const char* (*snd_pcm_info_get_id_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+const char* (*snd_pcm_info_get_name_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+const char* (*snd_pcm_info_get_subdevice_name_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+snd_pcm_class_t (*snd_pcm_info_get_class_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+snd_pcm_subclass_t (*snd_pcm_info_get_subclass_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+unsigned int (*snd_pcm_info_get_subdevices_count_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+unsigned int (*snd_pcm_info_get_subdevices_avail_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+snd_pcm_sync_id_t (*snd_pcm_info_get_sync_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+void (*snd_pcm_info_set_device_dylibloader_wrapper_asound)( snd_pcm_info_t*, unsigned int);
+void (*snd_pcm_info_set_subdevice_dylibloader_wrapper_asound)( snd_pcm_info_t*, unsigned int);
+void (*snd_pcm_info_set_stream_dylibloader_wrapper_asound)( snd_pcm_info_t*, snd_pcm_stream_t);
+int (*snd_pcm_hw_params_any_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_double_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_batch_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_block_transfer_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_monotonic_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_overrange_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_pause_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_resume_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_half_duplex_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_is_joint_duplex_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_sync_start_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_supports_audio_ts_type_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, int);
+int (*snd_pcm_hw_params_get_rate_numden_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, unsigned int*);
+int (*snd_pcm_hw_params_get_sbits_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_get_fifo_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+size_t (*snd_pcm_hw_params_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_hw_params_malloc_dylibloader_wrapper_asound)( snd_pcm_hw_params_t**);
+void (*snd_pcm_hw_params_free_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*);
+void (*snd_pcm_hw_params_copy_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*,const snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_get_access_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_access_t*);
+int (*snd_pcm_hw_params_test_access_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t);
+int (*snd_pcm_hw_params_set_access_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t);
+int (*snd_pcm_hw_params_set_access_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t*);
+int (*snd_pcm_hw_params_set_access_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t*);
+int (*snd_pcm_hw_params_set_access_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_mask_t*);
+int (*snd_pcm_hw_params_get_access_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_access_mask_t*);
+int (*snd_pcm_hw_params_get_format_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_format_t*);
+int (*snd_pcm_hw_params_test_format_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t);
+int (*snd_pcm_hw_params_set_format_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t);
+int (*snd_pcm_hw_params_set_format_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t*);
+int (*snd_pcm_hw_params_set_format_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t*);
+int (*snd_pcm_hw_params_set_format_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_mask_t*);
+void (*snd_pcm_hw_params_get_format_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_format_mask_t*);
+int (*snd_pcm_hw_params_get_subformat_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+int (*snd_pcm_hw_params_test_subformat_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t);
+int (*snd_pcm_hw_params_set_subformat_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t);
+int (*snd_pcm_hw_params_set_subformat_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+int (*snd_pcm_hw_params_set_subformat_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+int (*snd_pcm_hw_params_set_subformat_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_mask_t*);
+void (*snd_pcm_hw_params_get_subformat_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_subformat_mask_t*);
+int (*snd_pcm_hw_params_get_channels_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_get_channels_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_get_channels_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_test_channels_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+int (*snd_pcm_hw_params_set_channels_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+int (*snd_pcm_hw_params_set_channels_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_channels_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_channels_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, unsigned int*);
+int (*snd_pcm_hw_params_set_channels_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_channels_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_channels_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_get_rate_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_rate_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_rate_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_test_rate_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_rate_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_rate_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_rate_resample_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+int (*snd_pcm_hw_params_get_rate_resample_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_export_buffer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+int (*snd_pcm_hw_params_get_export_buffer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_set_period_wakeup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+int (*snd_pcm_hw_params_get_period_wakeup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_get_period_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_period_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_period_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_test_period_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_period_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_period_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_period_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_period_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_period_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_period_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_period_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_period_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_get_period_size_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_get_period_size_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_test_period_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t, int);
+int (*snd_pcm_hw_params_set_period_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t, int);
+int (*snd_pcm_hw_params_set_period_size_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+int (*snd_pcm_hw_params_set_period_size_integer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_get_periods_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_periods_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_periods_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_test_periods_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_periods_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_periods_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_periods_integer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+int (*snd_pcm_hw_params_get_buffer_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_buffer_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_buffer_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_test_buffer_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_buffer_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_buffer_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_buffer_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_buffer_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_buffer_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_buffer_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_buffer_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_get_buffer_size_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_get_buffer_size_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_test_buffer_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_hw_params_set_buffer_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_hw_params_set_buffer_size_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_set_buffer_size_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_set_buffer_size_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_set_buffer_size_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_set_buffer_size_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_hw_params_get_min_align_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+size_t (*snd_pcm_sw_params_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_sw_params_malloc_dylibloader_wrapper_asound)( snd_pcm_sw_params_t**);
+void (*snd_pcm_sw_params_free_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*);
+void (*snd_pcm_sw_params_copy_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*,const snd_pcm_sw_params_t*);
+int (*snd_pcm_sw_params_get_boundary_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_tstamp_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_tstamp_t);
+int (*snd_pcm_sw_params_get_tstamp_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_tstamp_t*);
+int (*snd_pcm_sw_params_set_avail_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_avail_min_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_period_event_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, int);
+int (*snd_pcm_sw_params_get_period_event_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, int*);
+int (*snd_pcm_sw_params_set_start_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_start_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_stop_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_stop_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_silence_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_silence_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_silence_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_silence_size_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+size_t (*snd_pcm_access_mask_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_access_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_access_mask_t**);
+void (*snd_pcm_access_mask_free_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+void (*snd_pcm_access_mask_copy_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*,const snd_pcm_access_mask_t*);
+void (*snd_pcm_access_mask_none_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+void (*snd_pcm_access_mask_any_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+int (*snd_pcm_access_mask_test_dylibloader_wrapper_asound)(const snd_pcm_access_mask_t*, snd_pcm_access_t);
+int (*snd_pcm_access_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_access_mask_t*);
+void (*snd_pcm_access_mask_set_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*, snd_pcm_access_t);
+void (*snd_pcm_access_mask_reset_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*, snd_pcm_access_t);
+size_t (*snd_pcm_format_mask_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_format_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_format_mask_t**);
+void (*snd_pcm_format_mask_free_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+void (*snd_pcm_format_mask_copy_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*,const snd_pcm_format_mask_t*);
+void (*snd_pcm_format_mask_none_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+void (*snd_pcm_format_mask_any_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+int (*snd_pcm_format_mask_test_dylibloader_wrapper_asound)(const snd_pcm_format_mask_t*, snd_pcm_format_t);
+int (*snd_pcm_format_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_format_mask_t*);
+void (*snd_pcm_format_mask_set_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*, snd_pcm_format_t);
+void (*snd_pcm_format_mask_reset_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*, snd_pcm_format_t);
+size_t (*snd_pcm_subformat_mask_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_subformat_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t**);
+void (*snd_pcm_subformat_mask_free_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+void (*snd_pcm_subformat_mask_copy_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*,const snd_pcm_subformat_mask_t*);
+void (*snd_pcm_subformat_mask_none_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+void (*snd_pcm_subformat_mask_any_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+int (*snd_pcm_subformat_mask_test_dylibloader_wrapper_asound)(const snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+int (*snd_pcm_subformat_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_subformat_mask_t*);
+void (*snd_pcm_subformat_mask_set_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+void (*snd_pcm_subformat_mask_reset_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+size_t (*snd_pcm_status_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_pcm_status_malloc_dylibloader_wrapper_asound)( snd_pcm_status_t**);
+void (*snd_pcm_status_free_dylibloader_wrapper_asound)( snd_pcm_status_t*);
+void (*snd_pcm_status_copy_dylibloader_wrapper_asound)( snd_pcm_status_t*,const snd_pcm_status_t*);
+snd_pcm_state_t (*snd_pcm_status_get_state_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+void (*snd_pcm_status_get_trigger_tstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_timestamp_t*);
+void (*snd_pcm_status_get_trigger_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+void (*snd_pcm_status_get_tstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_timestamp_t*);
+void (*snd_pcm_status_get_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+void (*snd_pcm_status_get_audio_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+void (*snd_pcm_status_get_driver_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+snd_pcm_sframes_t (*snd_pcm_status_get_delay_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+snd_pcm_uframes_t (*snd_pcm_status_get_avail_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+snd_pcm_uframes_t (*snd_pcm_status_get_avail_max_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+snd_pcm_uframes_t (*snd_pcm_status_get_overrange_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+const char* (*snd_pcm_type_name_dylibloader_wrapper_asound)( snd_pcm_type_t);
+const char* (*snd_pcm_stream_name_dylibloader_wrapper_asound)(const snd_pcm_stream_t);
+const char* (*snd_pcm_access_name_dylibloader_wrapper_asound)(const snd_pcm_access_t);
+const char* (*snd_pcm_format_name_dylibloader_wrapper_asound)(const snd_pcm_format_t);
+const char* (*snd_pcm_format_description_dylibloader_wrapper_asound)(const snd_pcm_format_t);
+const char* (*snd_pcm_subformat_name_dylibloader_wrapper_asound)(const snd_pcm_subformat_t);
+const char* (*snd_pcm_subformat_description_dylibloader_wrapper_asound)(const snd_pcm_subformat_t);
+snd_pcm_format_t (*snd_pcm_format_value_dylibloader_wrapper_asound)(const char*);
+const char* (*snd_pcm_tstamp_mode_name_dylibloader_wrapper_asound)(const snd_pcm_tstamp_t);
+const char* (*snd_pcm_state_name_dylibloader_wrapper_asound)(const snd_pcm_state_t);
+int (*snd_pcm_dump_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+int (*snd_pcm_dump_hw_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+int (*snd_pcm_dump_sw_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+int (*snd_pcm_dump_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+int (*snd_pcm_hw_params_dump_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_output_t*);
+int (*snd_pcm_sw_params_dump_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*, snd_output_t*);
+int (*snd_pcm_status_dump_dylibloader_wrapper_asound)( snd_pcm_status_t*, snd_output_t*);
+int (*snd_pcm_mmap_begin_dylibloader_wrapper_asound)( snd_pcm_t*,const snd_pcm_channel_area_t**, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+snd_pcm_sframes_t (*snd_pcm_mmap_commit_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_mmap_writei_dylibloader_wrapper_asound)( snd_pcm_t*,const void*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_mmap_readi_dylibloader_wrapper_asound)( snd_pcm_t*, void*, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_mmap_writen_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+snd_pcm_sframes_t (*snd_pcm_mmap_readn_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+int (*snd_pcm_format_signed_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_unsigned_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_linear_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_float_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_little_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_big_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_cpu_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_width_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_physical_width_dylibloader_wrapper_asound)( snd_pcm_format_t);
+snd_pcm_format_t (*snd_pcm_build_linear_format_dylibloader_wrapper_asound)( int, int, int, int);
+ssize_t (*snd_pcm_format_size_dylibloader_wrapper_asound)( snd_pcm_format_t, size_t);
+uint8_t (*snd_pcm_format_silence_dylibloader_wrapper_asound)( snd_pcm_format_t);
+uint16_t (*snd_pcm_format_silence_16_dylibloader_wrapper_asound)( snd_pcm_format_t);
+uint32_t (*snd_pcm_format_silence_32_dylibloader_wrapper_asound)( snd_pcm_format_t);
+uint64_t (*snd_pcm_format_silence_64_dylibloader_wrapper_asound)( snd_pcm_format_t);
+int (*snd_pcm_format_set_silence_dylibloader_wrapper_asound)( snd_pcm_format_t, void*, unsigned int);
+snd_pcm_sframes_t (*snd_pcm_bytes_to_frames_dylibloader_wrapper_asound)( snd_pcm_t*, ssize_t);
+ssize_t (*snd_pcm_frames_to_bytes_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t);
+long (*snd_pcm_bytes_to_samples_dylibloader_wrapper_asound)( snd_pcm_t*, ssize_t);
+ssize_t (*snd_pcm_samples_to_bytes_dylibloader_wrapper_asound)( snd_pcm_t*, long);
+int (*snd_pcm_area_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
+int (*snd_pcm_areas_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
+int (*snd_pcm_area_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
+int (*snd_pcm_areas_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
+int (*snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const unsigned int, snd_pcm_uframes_t,const snd_pcm_format_t);
+snd_pcm_t* (*snd_pcm_hook_get_pcm_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+void* (*snd_pcm_hook_get_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+void (*snd_pcm_hook_set_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*, void*);
+int (*snd_pcm_hook_add_dylibloader_wrapper_asound)( snd_pcm_hook_t**, snd_pcm_t*, snd_pcm_hook_type_t, snd_pcm_hook_func_t, void*);
+int (*snd_pcm_hook_remove_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+snd_pcm_uframes_t (*snd_pcm_meter_get_bufsize_dylibloader_wrapper_asound)( snd_pcm_t*);
+unsigned int (*snd_pcm_meter_get_channels_dylibloader_wrapper_asound)( snd_pcm_t*);
+unsigned int (*snd_pcm_meter_get_rate_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_uframes_t (*snd_pcm_meter_get_now_dylibloader_wrapper_asound)( snd_pcm_t*);
+snd_pcm_uframes_t (*snd_pcm_meter_get_boundary_dylibloader_wrapper_asound)( snd_pcm_t*);
+int (*snd_pcm_meter_add_scope_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_scope_t*);
+snd_pcm_scope_t* (*snd_pcm_meter_search_scope_dylibloader_wrapper_asound)( snd_pcm_t*,const char*);
+int (*snd_pcm_scope_malloc_dylibloader_wrapper_asound)( snd_pcm_scope_t**);
+void (*snd_pcm_scope_set_ops_dylibloader_wrapper_asound)( snd_pcm_scope_t*,const snd_pcm_scope_ops_t*);
+void (*snd_pcm_scope_set_name_dylibloader_wrapper_asound)( snd_pcm_scope_t*,const char*);
+const char* (*snd_pcm_scope_get_name_dylibloader_wrapper_asound)( snd_pcm_scope_t*);
+void* (*snd_pcm_scope_get_callback_private_dylibloader_wrapper_asound)( snd_pcm_scope_t*);
+void (*snd_pcm_scope_set_callback_private_dylibloader_wrapper_asound)( snd_pcm_scope_t*, void*);
+int (*snd_pcm_scope_s16_open_dylibloader_wrapper_asound)( snd_pcm_t*,const char*, snd_pcm_scope_t**);
+int16_t* (*snd_pcm_scope_s16_get_channel_buffer_dylibloader_wrapper_asound)( snd_pcm_scope_t*, unsigned int);
+int (*snd_spcm_init_dylibloader_wrapper_asound)( snd_pcm_t*, unsigned int, unsigned int, snd_pcm_format_t, snd_pcm_subformat_t, snd_spcm_latency_t, snd_pcm_access_t, snd_spcm_xrun_type_t);
+int (*snd_spcm_init_duplex_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_t*, unsigned int, unsigned int, snd_pcm_format_t, snd_pcm_subformat_t, snd_spcm_latency_t, snd_pcm_access_t, snd_spcm_xrun_type_t, snd_spcm_duplex_type_t);
+int (*snd_spcm_init_get_params_dylibloader_wrapper_asound)( snd_pcm_t*, unsigned int*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+const char* (*snd_pcm_start_mode_name_dylibloader_wrapper_asound)( snd_pcm_start_t);
+const char* (*snd_pcm_xrun_mode_name_dylibloader_wrapper_asound)( snd_pcm_xrun_t);
+int (*snd_pcm_sw_params_set_start_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_start_t);
+snd_pcm_start_t (*snd_pcm_sw_params_get_start_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*);
+int (*snd_pcm_sw_params_set_xrun_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_xrun_t);
+snd_pcm_xrun_t (*snd_pcm_sw_params_get_xrun_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*);
+int (*snd_pcm_sw_params_set_xfer_align_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+int (*snd_pcm_sw_params_get_xfer_align_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+int (*snd_pcm_sw_params_set_sleep_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, unsigned int);
+int (*snd_pcm_sw_params_get_sleep_min_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, unsigned int*);
+int (*snd_pcm_hw_params_get_tick_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_tick_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_get_tick_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_test_tick_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_tick_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+int (*snd_pcm_hw_params_set_tick_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_tick_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_tick_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_tick_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_tick_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_pcm_hw_params_set_tick_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+int (*snd_rawmidi_open_dylibloader_wrapper_asound)( snd_rawmidi_t**, snd_rawmidi_t**,const char*, int);
+int (*snd_rawmidi_open_lconf_dylibloader_wrapper_asound)( snd_rawmidi_t**, snd_rawmidi_t**,const char*, int, snd_config_t*);
+int (*snd_rawmidi_close_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+int (*snd_rawmidi_poll_descriptors_count_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+int (*snd_rawmidi_poll_descriptors_dylibloader_wrapper_asound)( snd_rawmidi_t*,struct pollfd*, unsigned int);
+int (*snd_rawmidi_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_rawmidi_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_rawmidi_nonblock_dylibloader_wrapper_asound)( snd_rawmidi_t*, int);
+size_t (*snd_rawmidi_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_rawmidi_info_malloc_dylibloader_wrapper_asound)( snd_rawmidi_info_t**);
+void (*snd_rawmidi_info_free_dylibloader_wrapper_asound)( snd_rawmidi_info_t*);
+void (*snd_rawmidi_info_copy_dylibloader_wrapper_asound)( snd_rawmidi_info_t*,const snd_rawmidi_info_t*);
+unsigned int (*snd_rawmidi_info_get_device_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+unsigned int (*snd_rawmidi_info_get_subdevice_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+snd_rawmidi_stream_t (*snd_rawmidi_info_get_stream_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+int (*snd_rawmidi_info_get_card_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+unsigned int (*snd_rawmidi_info_get_flags_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+const char* (*snd_rawmidi_info_get_id_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+const char* (*snd_rawmidi_info_get_name_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+const char* (*snd_rawmidi_info_get_subdevice_name_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+unsigned int (*snd_rawmidi_info_get_subdevices_count_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+unsigned int (*snd_rawmidi_info_get_subdevices_avail_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+void (*snd_rawmidi_info_set_device_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, unsigned int);
+void (*snd_rawmidi_info_set_subdevice_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, unsigned int);
+void (*snd_rawmidi_info_set_stream_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, snd_rawmidi_stream_t);
+int (*snd_rawmidi_info_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_info_t*);
+size_t (*snd_rawmidi_params_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_rawmidi_params_malloc_dylibloader_wrapper_asound)( snd_rawmidi_params_t**);
+void (*snd_rawmidi_params_free_dylibloader_wrapper_asound)( snd_rawmidi_params_t*);
+void (*snd_rawmidi_params_copy_dylibloader_wrapper_asound)( snd_rawmidi_params_t*,const snd_rawmidi_params_t*);
+int (*snd_rawmidi_params_set_buffer_size_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, size_t);
+size_t (*snd_rawmidi_params_get_buffer_size_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+int (*snd_rawmidi_params_set_avail_min_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, size_t);
+size_t (*snd_rawmidi_params_get_avail_min_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+int (*snd_rawmidi_params_set_no_active_sensing_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, int);
+int (*snd_rawmidi_params_get_no_active_sensing_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+int (*snd_rawmidi_params_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*);
+int (*snd_rawmidi_params_current_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*);
+size_t (*snd_rawmidi_status_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_rawmidi_status_malloc_dylibloader_wrapper_asound)( snd_rawmidi_status_t**);
+void (*snd_rawmidi_status_free_dylibloader_wrapper_asound)( snd_rawmidi_status_t*);
+void (*snd_rawmidi_status_copy_dylibloader_wrapper_asound)( snd_rawmidi_status_t*,const snd_rawmidi_status_t*);
+void (*snd_rawmidi_status_get_tstamp_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*, snd_htimestamp_t*);
+size_t (*snd_rawmidi_status_get_avail_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*);
+size_t (*snd_rawmidi_status_get_xruns_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*);
+int (*snd_rawmidi_status_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_status_t*);
+int (*snd_rawmidi_drain_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+int (*snd_rawmidi_drop_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+ssize_t (*snd_rawmidi_write_dylibloader_wrapper_asound)( snd_rawmidi_t*,const void*, size_t);
+ssize_t (*snd_rawmidi_read_dylibloader_wrapper_asound)( snd_rawmidi_t*, void*, size_t);
+const char* (*snd_rawmidi_name_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+snd_rawmidi_type_t (*snd_rawmidi_type_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+snd_rawmidi_stream_t (*snd_rawmidi_stream_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+int (*snd_timer_query_open_dylibloader_wrapper_asound)( snd_timer_query_t**,const char*, int);
+int (*snd_timer_query_open_lconf_dylibloader_wrapper_asound)( snd_timer_query_t**,const char*, int, snd_config_t*);
+int (*snd_timer_query_close_dylibloader_wrapper_asound)( snd_timer_query_t*);
+int (*snd_timer_query_next_device_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_id_t*);
+int (*snd_timer_query_info_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_ginfo_t*);
+int (*snd_timer_query_params_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_gparams_t*);
+int (*snd_timer_query_status_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_gstatus_t*);
+int (*snd_timer_open_dylibloader_wrapper_asound)( snd_timer_t**,const char*, int);
+int (*snd_timer_open_lconf_dylibloader_wrapper_asound)( snd_timer_t**,const char*, int, snd_config_t*);
+int (*snd_timer_close_dylibloader_wrapper_asound)( snd_timer_t*);
+int (*snd_async_add_timer_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_timer_t*, snd_async_callback_t, void*);
+snd_timer_t* (*snd_async_handler_get_timer_dylibloader_wrapper_asound)( snd_async_handler_t*);
+int (*snd_timer_poll_descriptors_count_dylibloader_wrapper_asound)( snd_timer_t*);
+int (*snd_timer_poll_descriptors_dylibloader_wrapper_asound)( snd_timer_t*,struct pollfd*, unsigned int);
+int (*snd_timer_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_timer_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_timer_info_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_info_t*);
+int (*snd_timer_params_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_params_t*);
+int (*snd_timer_status_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_status_t*);
+int (*snd_timer_start_dylibloader_wrapper_asound)( snd_timer_t*);
+int (*snd_timer_stop_dylibloader_wrapper_asound)( snd_timer_t*);
+int (*snd_timer_continue_dylibloader_wrapper_asound)( snd_timer_t*);
+ssize_t (*snd_timer_read_dylibloader_wrapper_asound)( snd_timer_t*, void*, size_t);
+size_t (*snd_timer_id_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_timer_id_malloc_dylibloader_wrapper_asound)( snd_timer_id_t**);
+void (*snd_timer_id_free_dylibloader_wrapper_asound)( snd_timer_id_t*);
+void (*snd_timer_id_copy_dylibloader_wrapper_asound)( snd_timer_id_t*,const snd_timer_id_t*);
+void (*snd_timer_id_set_class_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+int (*snd_timer_id_get_class_dylibloader_wrapper_asound)( snd_timer_id_t*);
+void (*snd_timer_id_set_sclass_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+int (*snd_timer_id_get_sclass_dylibloader_wrapper_asound)( snd_timer_id_t*);
+void (*snd_timer_id_set_card_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+int (*snd_timer_id_get_card_dylibloader_wrapper_asound)( snd_timer_id_t*);
+void (*snd_timer_id_set_device_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+int (*snd_timer_id_get_device_dylibloader_wrapper_asound)( snd_timer_id_t*);
+void (*snd_timer_id_set_subdevice_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+int (*snd_timer_id_get_subdevice_dylibloader_wrapper_asound)( snd_timer_id_t*);
+size_t (*snd_timer_ginfo_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_timer_ginfo_malloc_dylibloader_wrapper_asound)( snd_timer_ginfo_t**);
+void (*snd_timer_ginfo_free_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+void (*snd_timer_ginfo_copy_dylibloader_wrapper_asound)( snd_timer_ginfo_t*,const snd_timer_ginfo_t*);
+int (*snd_timer_ginfo_set_tid_dylibloader_wrapper_asound)( snd_timer_ginfo_t*, snd_timer_id_t*);
+snd_timer_id_t* (*snd_timer_ginfo_get_tid_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+unsigned int (*snd_timer_ginfo_get_flags_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+int (*snd_timer_ginfo_get_card_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+char* (*snd_timer_ginfo_get_id_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+char* (*snd_timer_ginfo_get_name_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+unsigned long (*snd_timer_ginfo_get_resolution_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+unsigned long (*snd_timer_ginfo_get_resolution_min_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+unsigned long (*snd_timer_ginfo_get_resolution_max_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+unsigned int (*snd_timer_ginfo_get_clients_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+size_t (*snd_timer_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_timer_info_malloc_dylibloader_wrapper_asound)( snd_timer_info_t**);
+void (*snd_timer_info_free_dylibloader_wrapper_asound)( snd_timer_info_t*);
+void (*snd_timer_info_copy_dylibloader_wrapper_asound)( snd_timer_info_t*,const snd_timer_info_t*);
+int (*snd_timer_info_is_slave_dylibloader_wrapper_asound)( snd_timer_info_t*);
+int (*snd_timer_info_get_card_dylibloader_wrapper_asound)( snd_timer_info_t*);
+const char* (*snd_timer_info_get_id_dylibloader_wrapper_asound)( snd_timer_info_t*);
+const char* (*snd_timer_info_get_name_dylibloader_wrapper_asound)( snd_timer_info_t*);
+long (*snd_timer_info_get_resolution_dylibloader_wrapper_asound)( snd_timer_info_t*);
+size_t (*snd_timer_params_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_timer_params_malloc_dylibloader_wrapper_asound)( snd_timer_params_t**);
+void (*snd_timer_params_free_dylibloader_wrapper_asound)( snd_timer_params_t*);
+void (*snd_timer_params_copy_dylibloader_wrapper_asound)( snd_timer_params_t*,const snd_timer_params_t*);
+int (*snd_timer_params_set_auto_start_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+int (*snd_timer_params_get_auto_start_dylibloader_wrapper_asound)( snd_timer_params_t*);
+int (*snd_timer_params_set_exclusive_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+int (*snd_timer_params_get_exclusive_dylibloader_wrapper_asound)( snd_timer_params_t*);
+int (*snd_timer_params_set_early_event_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+int (*snd_timer_params_get_early_event_dylibloader_wrapper_asound)( snd_timer_params_t*);
+void (*snd_timer_params_set_ticks_dylibloader_wrapper_asound)( snd_timer_params_t*, long);
+long (*snd_timer_params_get_ticks_dylibloader_wrapper_asound)( snd_timer_params_t*);
+void (*snd_timer_params_set_queue_size_dylibloader_wrapper_asound)( snd_timer_params_t*, long);
+long (*snd_timer_params_get_queue_size_dylibloader_wrapper_asound)( snd_timer_params_t*);
+void (*snd_timer_params_set_filter_dylibloader_wrapper_asound)( snd_timer_params_t*, unsigned int);
+unsigned int (*snd_timer_params_get_filter_dylibloader_wrapper_asound)( snd_timer_params_t*);
+size_t (*snd_timer_status_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_timer_status_malloc_dylibloader_wrapper_asound)( snd_timer_status_t**);
+void (*snd_timer_status_free_dylibloader_wrapper_asound)( snd_timer_status_t*);
+void (*snd_timer_status_copy_dylibloader_wrapper_asound)( snd_timer_status_t*,const snd_timer_status_t*);
+snd_htimestamp_t (*snd_timer_status_get_timestamp_dylibloader_wrapper_asound)( snd_timer_status_t*);
+long (*snd_timer_status_get_resolution_dylibloader_wrapper_asound)( snd_timer_status_t*);
+long (*snd_timer_status_get_lost_dylibloader_wrapper_asound)( snd_timer_status_t*);
+long (*snd_timer_status_get_overrun_dylibloader_wrapper_asound)( snd_timer_status_t*);
+long (*snd_timer_status_get_queue_dylibloader_wrapper_asound)( snd_timer_status_t*);
+long (*snd_timer_info_get_ticks_dylibloader_wrapper_asound)( snd_timer_info_t*);
+int (*snd_hwdep_open_dylibloader_wrapper_asound)( snd_hwdep_t**,const char*, int);
+int (*snd_hwdep_close_dylibloader_wrapper_asound)( snd_hwdep_t*);
+int (*snd_hwdep_poll_descriptors_dylibloader_wrapper_asound)( snd_hwdep_t*,struct pollfd*, unsigned int);
+int (*snd_hwdep_poll_descriptors_count_dylibloader_wrapper_asound)( snd_hwdep_t*);
+int (*snd_hwdep_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_hwdep_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_hwdep_nonblock_dylibloader_wrapper_asound)( snd_hwdep_t*, int);
+int (*snd_hwdep_info_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_info_t*);
+int (*snd_hwdep_dsp_status_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_dsp_status_t*);
+int (*snd_hwdep_dsp_load_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_dsp_image_t*);
+int (*snd_hwdep_ioctl_dylibloader_wrapper_asound)( snd_hwdep_t*, unsigned int, void*);
+ssize_t (*snd_hwdep_write_dylibloader_wrapper_asound)( snd_hwdep_t*,const void*, size_t);
+ssize_t (*snd_hwdep_read_dylibloader_wrapper_asound)( snd_hwdep_t*, void*, size_t);
+size_t (*snd_hwdep_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_hwdep_info_malloc_dylibloader_wrapper_asound)( snd_hwdep_info_t**);
+void (*snd_hwdep_info_free_dylibloader_wrapper_asound)( snd_hwdep_info_t*);
+void (*snd_hwdep_info_copy_dylibloader_wrapper_asound)( snd_hwdep_info_t*,const snd_hwdep_info_t*);
+unsigned int (*snd_hwdep_info_get_device_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+int (*snd_hwdep_info_get_card_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+const char* (*snd_hwdep_info_get_id_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+const char* (*snd_hwdep_info_get_name_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+snd_hwdep_iface_t (*snd_hwdep_info_get_iface_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+void (*snd_hwdep_info_set_device_dylibloader_wrapper_asound)( snd_hwdep_info_t*, unsigned int);
+size_t (*snd_hwdep_dsp_status_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_hwdep_dsp_status_malloc_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t**);
+void (*snd_hwdep_dsp_status_free_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t*);
+void (*snd_hwdep_dsp_status_copy_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t*,const snd_hwdep_dsp_status_t*);
+unsigned int (*snd_hwdep_dsp_status_get_version_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+const char* (*snd_hwdep_dsp_status_get_id_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+unsigned int (*snd_hwdep_dsp_status_get_num_dsps_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+unsigned int (*snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+unsigned int (*snd_hwdep_dsp_status_get_chip_ready_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+size_t (*snd_hwdep_dsp_image_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_hwdep_dsp_image_malloc_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t**);
+void (*snd_hwdep_dsp_image_free_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*);
+void (*snd_hwdep_dsp_image_copy_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*,const snd_hwdep_dsp_image_t*);
+unsigned int (*snd_hwdep_dsp_image_get_index_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+const char* (*snd_hwdep_dsp_image_get_name_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+const void* (*snd_hwdep_dsp_image_get_image_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+size_t (*snd_hwdep_dsp_image_get_length_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+void (*snd_hwdep_dsp_image_set_index_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, unsigned int);
+void (*snd_hwdep_dsp_image_set_name_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*,const char*);
+void (*snd_hwdep_dsp_image_set_image_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, void*);
+void (*snd_hwdep_dsp_image_set_length_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, size_t);
+int (*snd_card_load_dylibloader_wrapper_asound)( int);
+int (*snd_card_next_dylibloader_wrapper_asound)( int*);
+int (*snd_card_get_index_dylibloader_wrapper_asound)(const char*);
+int (*snd_card_get_name_dylibloader_wrapper_asound)( int, char**);
+int (*snd_card_get_longname_dylibloader_wrapper_asound)( int, char**);
+int (*snd_device_name_hint_dylibloader_wrapper_asound)( int,const char*, void***);
+int (*snd_device_name_free_hint_dylibloader_wrapper_asound)( void**);
+char* (*snd_device_name_get_hint_dylibloader_wrapper_asound)(const void*,const char*);
+int (*snd_ctl_open_dylibloader_wrapper_asound)( snd_ctl_t**,const char*, int);
+int (*snd_ctl_open_lconf_dylibloader_wrapper_asound)( snd_ctl_t**,const char*, int, snd_config_t*);
+int (*snd_ctl_open_fallback_dylibloader_wrapper_asound)( snd_ctl_t**, snd_config_t*,const char*,const char*, int);
+int (*snd_ctl_close_dylibloader_wrapper_asound)( snd_ctl_t*);
+int (*snd_ctl_nonblock_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+int (*snd_async_add_ctl_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_ctl_t*, snd_async_callback_t, void*);
+snd_ctl_t* (*snd_async_handler_get_ctl_dylibloader_wrapper_asound)( snd_async_handler_t*);
+int (*snd_ctl_poll_descriptors_count_dylibloader_wrapper_asound)( snd_ctl_t*);
+int (*snd_ctl_poll_descriptors_dylibloader_wrapper_asound)( snd_ctl_t*,struct pollfd*, unsigned int);
+int (*snd_ctl_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_ctl_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_ctl_subscribe_events_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+int (*snd_ctl_card_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_card_info_t*);
+int (*snd_ctl_elem_list_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_list_t*);
+int (*snd_ctl_elem_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_read_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*);
+int (*snd_ctl_elem_write_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*);
+int (*snd_ctl_elem_lock_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+int (*snd_ctl_elem_unlock_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+int (*snd_ctl_elem_tlv_read_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int*, unsigned int);
+int (*snd_ctl_elem_tlv_write_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*,const unsigned int*);
+int (*snd_ctl_elem_tlv_command_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*,const unsigned int*);
+int (*snd_ctl_hwdep_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+int (*snd_ctl_hwdep_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_hwdep_info_t*);
+int (*snd_ctl_pcm_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+int (*snd_ctl_pcm_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_pcm_info_t*);
+int (*snd_ctl_pcm_prefer_subdevice_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+int (*snd_ctl_rawmidi_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+int (*snd_ctl_rawmidi_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_rawmidi_info_t*);
+int (*snd_ctl_rawmidi_prefer_subdevice_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+int (*snd_ctl_set_power_state_dylibloader_wrapper_asound)( snd_ctl_t*, unsigned int);
+int (*snd_ctl_get_power_state_dylibloader_wrapper_asound)( snd_ctl_t*, unsigned int*);
+int (*snd_ctl_read_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_event_t*);
+int (*snd_ctl_wait_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+const char* (*snd_ctl_name_dylibloader_wrapper_asound)( snd_ctl_t*);
+snd_ctl_type_t (*snd_ctl_type_dylibloader_wrapper_asound)( snd_ctl_t*);
+const char* (*snd_ctl_elem_type_name_dylibloader_wrapper_asound)( snd_ctl_elem_type_t);
+const char* (*snd_ctl_elem_iface_name_dylibloader_wrapper_asound)( snd_ctl_elem_iface_t);
+const char* (*snd_ctl_event_type_name_dylibloader_wrapper_asound)( snd_ctl_event_type_t);
+unsigned int (*snd_ctl_event_elem_get_mask_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+unsigned int (*snd_ctl_event_elem_get_numid_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+void (*snd_ctl_event_elem_get_id_dylibloader_wrapper_asound)(const snd_ctl_event_t*, snd_ctl_elem_id_t*);
+snd_ctl_elem_iface_t (*snd_ctl_event_elem_get_interface_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+unsigned int (*snd_ctl_event_elem_get_device_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+unsigned int (*snd_ctl_event_elem_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+const char* (*snd_ctl_event_elem_get_name_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+unsigned int (*snd_ctl_event_elem_get_index_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+int (*snd_ctl_elem_list_alloc_space_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*, unsigned int);
+void (*snd_ctl_elem_list_free_space_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+char* (*snd_ctl_ascii_elem_id_get_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+int (*snd_ctl_ascii_elem_id_parse_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const char*);
+int (*snd_ctl_ascii_value_parse_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*, snd_ctl_elem_info_t*,const char*);
+size_t (*snd_ctl_elem_id_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_elem_id_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_id_t**);
+void (*snd_ctl_elem_id_free_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+void (*snd_ctl_elem_id_clear_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+void (*snd_ctl_elem_id_copy_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_id_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+snd_ctl_elem_iface_t (*snd_ctl_elem_id_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_id_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_id_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+const char* (*snd_ctl_elem_id_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_id_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+void (*snd_ctl_elem_id_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+void (*snd_ctl_elem_id_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, snd_ctl_elem_iface_t);
+void (*snd_ctl_elem_id_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+void (*snd_ctl_elem_id_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+void (*snd_ctl_elem_id_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const char*);
+void (*snd_ctl_elem_id_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+size_t (*snd_ctl_card_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_card_info_malloc_dylibloader_wrapper_asound)( snd_ctl_card_info_t**);
+void (*snd_ctl_card_info_free_dylibloader_wrapper_asound)( snd_ctl_card_info_t*);
+void (*snd_ctl_card_info_clear_dylibloader_wrapper_asound)( snd_ctl_card_info_t*);
+void (*snd_ctl_card_info_copy_dylibloader_wrapper_asound)( snd_ctl_card_info_t*,const snd_ctl_card_info_t*);
+int (*snd_ctl_card_info_get_card_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_id_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_driver_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_name_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_longname_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_mixername_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+const char* (*snd_ctl_card_info_get_components_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+size_t (*snd_ctl_event_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_event_malloc_dylibloader_wrapper_asound)( snd_ctl_event_t**);
+void (*snd_ctl_event_free_dylibloader_wrapper_asound)( snd_ctl_event_t*);
+void (*snd_ctl_event_clear_dylibloader_wrapper_asound)( snd_ctl_event_t*);
+void (*snd_ctl_event_copy_dylibloader_wrapper_asound)( snd_ctl_event_t*,const snd_ctl_event_t*);
+snd_ctl_event_type_t (*snd_ctl_event_get_type_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+size_t (*snd_ctl_elem_list_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_elem_list_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_list_t**);
+void (*snd_ctl_elem_list_free_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+void (*snd_ctl_elem_list_clear_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+void (*snd_ctl_elem_list_copy_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*,const snd_ctl_elem_list_t*);
+void (*snd_ctl_elem_list_set_offset_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*, unsigned int);
+unsigned int (*snd_ctl_elem_list_get_used_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*);
+unsigned int (*snd_ctl_elem_list_get_count_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*);
+void (*snd_ctl_elem_list_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int, snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_list_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+snd_ctl_elem_iface_t (*snd_ctl_elem_list_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+unsigned int (*snd_ctl_elem_list_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+unsigned int (*snd_ctl_elem_list_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+const char* (*snd_ctl_elem_list_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+unsigned int (*snd_ctl_elem_list_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+size_t (*snd_ctl_elem_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_elem_info_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_info_t**);
+void (*snd_ctl_elem_info_free_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*);
+void (*snd_ctl_elem_info_clear_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*);
+void (*snd_ctl_elem_info_copy_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const snd_ctl_elem_info_t*);
+snd_ctl_elem_type_t (*snd_ctl_elem_info_get_type_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_readable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_writable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_volatile_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_inactive_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_locked_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_tlv_readable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_tlv_writable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_tlv_commandable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_owner_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_is_user_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+pid_t (*snd_ctl_elem_info_get_owner_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+unsigned int (*snd_ctl_elem_info_get_count_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long (*snd_ctl_elem_info_get_min_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long (*snd_ctl_elem_info_get_max_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long (*snd_ctl_elem_info_get_step_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long long (*snd_ctl_elem_info_get_min64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long long (*snd_ctl_elem_info_get_max64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+long long (*snd_ctl_elem_info_get_step64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+unsigned int (*snd_ctl_elem_info_get_items_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+void (*snd_ctl_elem_info_set_item_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+const char* (*snd_ctl_elem_info_get_item_name_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_get_dimensions_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+int (*snd_ctl_elem_info_get_dimension_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*, unsigned int);
+int (*snd_ctl_elem_info_set_dimension_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const int [4]);
+void (*snd_ctl_elem_info_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*, snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_info_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+snd_ctl_elem_iface_t (*snd_ctl_elem_info_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+unsigned int (*snd_ctl_elem_info_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+unsigned int (*snd_ctl_elem_info_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+const char* (*snd_ctl_elem_info_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+unsigned int (*snd_ctl_elem_info_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+void (*snd_ctl_elem_info_set_id_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const snd_ctl_elem_id_t*);
+void (*snd_ctl_elem_info_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+void (*snd_ctl_elem_info_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, snd_ctl_elem_iface_t);
+void (*snd_ctl_elem_info_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+void (*snd_ctl_elem_info_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+void (*snd_ctl_elem_info_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const char*);
+void (*snd_ctl_elem_info_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+int (*snd_ctl_add_integer_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, long, long, long);
+int (*snd_ctl_add_integer64_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, long long, long long, long long);
+int (*snd_ctl_add_boolean_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int);
+int (*snd_ctl_add_enumerated_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, unsigned int,const char* []);
+int (*snd_ctl_add_bytes_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int);
+int (*snd_ctl_elem_add_integer_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, long, long, long);
+int (*snd_ctl_elem_add_integer64_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, long long, long long, long long);
+int (*snd_ctl_elem_add_boolean_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int);
+int (*snd_ctl_elem_add_enumerated_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, unsigned int,const char* []);
+int (*snd_ctl_elem_add_iec958_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*);
+int (*snd_ctl_elem_remove_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+size_t (*snd_ctl_elem_value_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_ctl_elem_value_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_value_t**);
+void (*snd_ctl_elem_value_free_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*);
+void (*snd_ctl_elem_value_clear_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*);
+void (*snd_ctl_elem_value_copy_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_value_t*);
+int (*snd_ctl_elem_value_compare_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_value_t*);
+void (*snd_ctl_elem_value_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, snd_ctl_elem_id_t*);
+unsigned int (*snd_ctl_elem_value_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+snd_ctl_elem_iface_t (*snd_ctl_elem_value_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+unsigned int (*snd_ctl_elem_value_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+unsigned int (*snd_ctl_elem_value_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+const char* (*snd_ctl_elem_value_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+unsigned int (*snd_ctl_elem_value_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+void (*snd_ctl_elem_value_set_id_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_id_t*);
+void (*snd_ctl_elem_value_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+void (*snd_ctl_elem_value_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, snd_ctl_elem_iface_t);
+void (*snd_ctl_elem_value_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+void (*snd_ctl_elem_value_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+void (*snd_ctl_elem_value_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const char*);
+void (*snd_ctl_elem_value_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+int (*snd_ctl_elem_value_get_boolean_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+long (*snd_ctl_elem_value_get_integer_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+long long (*snd_ctl_elem_value_get_integer64_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+unsigned int (*snd_ctl_elem_value_get_enumerated_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+unsigned char (*snd_ctl_elem_value_get_byte_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+void (*snd_ctl_elem_value_set_boolean_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long);
+void (*snd_ctl_elem_value_set_integer_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long);
+void (*snd_ctl_elem_value_set_integer64_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long long);
+void (*snd_ctl_elem_value_set_enumerated_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, unsigned int);
+void (*snd_ctl_elem_value_set_byte_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, unsigned char);
+void (*snd_ctl_elem_set_bytes_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, void*, size_t);
+const void* (*snd_ctl_elem_value_get_bytes_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+void (*snd_ctl_elem_value_get_iec958_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, snd_aes_iec958_t*);
+void (*snd_ctl_elem_value_set_iec958_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_aes_iec958_t*);
+int (*snd_tlv_parse_dB_info_dylibloader_wrapper_asound)( unsigned int*, unsigned int, unsigned int**);
+int (*snd_tlv_get_dB_range_dylibloader_wrapper_asound)( unsigned int*, long, long, long*, long*);
+int (*snd_tlv_convert_to_dB_dylibloader_wrapper_asound)( unsigned int*, long, long, long, long*);
+int (*snd_tlv_convert_from_dB_dylibloader_wrapper_asound)( unsigned int*, long, long, long, long*, int);
+int (*snd_ctl_get_dB_range_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long*, long*);
+int (*snd_ctl_convert_to_dB_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long, long*);
+int (*snd_ctl_convert_from_dB_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long, long*, int);
+int (*snd_hctl_compare_fast_dylibloader_wrapper_asound)(const snd_hctl_elem_t*,const snd_hctl_elem_t*);
+int (*snd_hctl_open_dylibloader_wrapper_asound)( snd_hctl_t**,const char*, int);
+int (*snd_hctl_open_ctl_dylibloader_wrapper_asound)( snd_hctl_t**, snd_ctl_t*);
+int (*snd_hctl_close_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_nonblock_dylibloader_wrapper_asound)( snd_hctl_t*, int);
+int (*snd_hctl_poll_descriptors_count_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_poll_descriptors_dylibloader_wrapper_asound)( snd_hctl_t*,struct pollfd*, unsigned int);
+int (*snd_hctl_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_hctl_t*,struct pollfd*, unsigned int, unsigned short*);
+unsigned int (*snd_hctl_get_count_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_set_compare_dylibloader_wrapper_asound)( snd_hctl_t*, snd_hctl_compare_t);
+snd_hctl_elem_t* (*snd_hctl_first_elem_dylibloader_wrapper_asound)( snd_hctl_t*);
+snd_hctl_elem_t* (*snd_hctl_last_elem_dylibloader_wrapper_asound)( snd_hctl_t*);
+snd_hctl_elem_t* (*snd_hctl_find_elem_dylibloader_wrapper_asound)( snd_hctl_t*,const snd_ctl_elem_id_t*);
+void (*snd_hctl_set_callback_dylibloader_wrapper_asound)( snd_hctl_t*, snd_hctl_callback_t);
+void (*snd_hctl_set_callback_private_dylibloader_wrapper_asound)( snd_hctl_t*, void*);
+void* (*snd_hctl_get_callback_private_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_load_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_free_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_handle_events_dylibloader_wrapper_asound)( snd_hctl_t*);
+const char* (*snd_hctl_name_dylibloader_wrapper_asound)( snd_hctl_t*);
+int (*snd_hctl_wait_dylibloader_wrapper_asound)( snd_hctl_t*, int);
+snd_ctl_t* (*snd_hctl_ctl_dylibloader_wrapper_asound)( snd_hctl_t*);
+snd_hctl_elem_t* (*snd_hctl_elem_next_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+snd_hctl_elem_t* (*snd_hctl_elem_prev_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+int (*snd_hctl_elem_info_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_info_t*);
+int (*snd_hctl_elem_read_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_value_t*);
+int (*snd_hctl_elem_write_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_value_t*);
+int (*snd_hctl_elem_tlv_read_dylibloader_wrapper_asound)( snd_hctl_elem_t*, unsigned int*, unsigned int);
+int (*snd_hctl_elem_tlv_write_dylibloader_wrapper_asound)( snd_hctl_elem_t*,const unsigned int*);
+int (*snd_hctl_elem_tlv_command_dylibloader_wrapper_asound)( snd_hctl_elem_t*,const unsigned int*);
+snd_hctl_t* (*snd_hctl_elem_get_hctl_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+void (*snd_hctl_elem_get_id_dylibloader_wrapper_asound)(const snd_hctl_elem_t*, snd_ctl_elem_id_t*);
+unsigned int (*snd_hctl_elem_get_numid_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+snd_ctl_elem_iface_t (*snd_hctl_elem_get_interface_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+unsigned int (*snd_hctl_elem_get_device_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+unsigned int (*snd_hctl_elem_get_subdevice_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+const char* (*snd_hctl_elem_get_name_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+unsigned int (*snd_hctl_elem_get_index_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+void (*snd_hctl_elem_set_callback_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_hctl_elem_callback_t);
+void* (*snd_hctl_elem_get_callback_private_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+void (*snd_hctl_elem_set_callback_private_dylibloader_wrapper_asound)( snd_hctl_elem_t*, void*);
+int (*snd_sctl_build_dylibloader_wrapper_asound)( snd_sctl_t**, snd_ctl_t*, snd_config_t*, snd_config_t*, int);
+int (*snd_sctl_free_dylibloader_wrapper_asound)( snd_sctl_t*);
+int (*snd_sctl_install_dylibloader_wrapper_asound)( snd_sctl_t*);
+int (*snd_sctl_remove_dylibloader_wrapper_asound)( snd_sctl_t*);
+int (*snd_mixer_open_dylibloader_wrapper_asound)( snd_mixer_t**, int);
+int (*snd_mixer_close_dylibloader_wrapper_asound)( snd_mixer_t*);
+snd_mixer_elem_t* (*snd_mixer_first_elem_dylibloader_wrapper_asound)( snd_mixer_t*);
+snd_mixer_elem_t* (*snd_mixer_last_elem_dylibloader_wrapper_asound)( snd_mixer_t*);
+int (*snd_mixer_handle_events_dylibloader_wrapper_asound)( snd_mixer_t*);
+int (*snd_mixer_attach_dylibloader_wrapper_asound)( snd_mixer_t*,const char*);
+int (*snd_mixer_attach_hctl_dylibloader_wrapper_asound)( snd_mixer_t*, snd_hctl_t*);
+int (*snd_mixer_detach_dylibloader_wrapper_asound)( snd_mixer_t*,const char*);
+int (*snd_mixer_detach_hctl_dylibloader_wrapper_asound)( snd_mixer_t*, snd_hctl_t*);
+int (*snd_mixer_get_hctl_dylibloader_wrapper_asound)( snd_mixer_t*,const char*, snd_hctl_t**);
+int (*snd_mixer_poll_descriptors_count_dylibloader_wrapper_asound)( snd_mixer_t*);
+int (*snd_mixer_poll_descriptors_dylibloader_wrapper_asound)( snd_mixer_t*,struct pollfd*, unsigned int);
+int (*snd_mixer_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_mixer_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_mixer_load_dylibloader_wrapper_asound)( snd_mixer_t*);
+void (*snd_mixer_free_dylibloader_wrapper_asound)( snd_mixer_t*);
+int (*snd_mixer_wait_dylibloader_wrapper_asound)( snd_mixer_t*, int);
+int (*snd_mixer_set_compare_dylibloader_wrapper_asound)( snd_mixer_t*, snd_mixer_compare_t);
+void (*snd_mixer_set_callback_dylibloader_wrapper_asound)( snd_mixer_t*, snd_mixer_callback_t);
+void* (*snd_mixer_get_callback_private_dylibloader_wrapper_asound)(const snd_mixer_t*);
+void (*snd_mixer_set_callback_private_dylibloader_wrapper_asound)( snd_mixer_t*, void*);
+unsigned int (*snd_mixer_get_count_dylibloader_wrapper_asound)(const snd_mixer_t*);
+int (*snd_mixer_class_unregister_dylibloader_wrapper_asound)( snd_mixer_class_t*);
+snd_mixer_elem_t* (*snd_mixer_elem_next_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+snd_mixer_elem_t* (*snd_mixer_elem_prev_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+void (*snd_mixer_elem_set_callback_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_elem_callback_t);
+void* (*snd_mixer_elem_get_callback_private_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+void (*snd_mixer_elem_set_callback_private_dylibloader_wrapper_asound)( snd_mixer_elem_t*, void*);
+snd_mixer_elem_type_t (*snd_mixer_elem_get_type_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+int (*snd_mixer_class_register_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_t*);
+int (*snd_mixer_elem_new_dylibloader_wrapper_asound)( snd_mixer_elem_t**, snd_mixer_elem_type_t, int, void*, void*);
+int (*snd_mixer_elem_add_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_class_t*);
+int (*snd_mixer_elem_remove_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+void (*snd_mixer_elem_free_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_elem_info_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_elem_value_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_elem_attach_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_hctl_elem_t*);
+int (*snd_mixer_elem_detach_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_hctl_elem_t*);
+int (*snd_mixer_elem_empty_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+void* (*snd_mixer_elem_get_private_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+size_t (*snd_mixer_class_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_mixer_class_malloc_dylibloader_wrapper_asound)( snd_mixer_class_t**);
+void (*snd_mixer_class_free_dylibloader_wrapper_asound)( snd_mixer_class_t*);
+void (*snd_mixer_class_copy_dylibloader_wrapper_asound)( snd_mixer_class_t*,const snd_mixer_class_t*);
+snd_mixer_t* (*snd_mixer_class_get_mixer_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+snd_mixer_event_t (*snd_mixer_class_get_event_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+void* (*snd_mixer_class_get_private_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+snd_mixer_compare_t (*snd_mixer_class_get_compare_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+int (*snd_mixer_class_set_event_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_event_t);
+int (*snd_mixer_class_set_private_dylibloader_wrapper_asound)( snd_mixer_class_t*, void*);
+int (*snd_mixer_class_set_private_free_dylibloader_wrapper_asound)( snd_mixer_class_t*, void*);
+int (*snd_mixer_class_set_compare_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_compare_t);
+const char* (*snd_mixer_selem_channel_name_dylibloader_wrapper_asound)( snd_mixer_selem_channel_id_t);
+int (*snd_mixer_selem_register_dylibloader_wrapper_asound)( snd_mixer_t*,struct snd_mixer_selem_regopt*, snd_mixer_class_t**);
+void (*snd_mixer_selem_get_id_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_id_t*);
+const char* (*snd_mixer_selem_get_name_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+unsigned int (*snd_mixer_selem_get_index_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+snd_mixer_elem_t* (*snd_mixer_find_selem_dylibloader_wrapper_asound)( snd_mixer_t*,const snd_mixer_selem_id_t*);
+int (*snd_mixer_selem_is_active_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_is_playback_mono_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_playback_channel_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t);
+int (*snd_mixer_selem_is_capture_mono_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_channel_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t);
+int (*snd_mixer_selem_get_capture_group_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_common_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_playback_volume_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_volume_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_common_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_playback_switch_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_switch_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_has_capture_switch_exclusive_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_ask_playback_vol_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long*);
+int (*snd_mixer_selem_ask_capture_vol_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long*);
+int (*snd_mixer_selem_ask_playback_dB_vol_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int, long*);
+int (*snd_mixer_selem_ask_capture_dB_vol_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int, long*);
+int (*snd_mixer_selem_get_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+int (*snd_mixer_selem_get_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+int (*snd_mixer_selem_get_playback_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+int (*snd_mixer_selem_get_capture_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+int (*snd_mixer_selem_get_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int*);
+int (*snd_mixer_selem_get_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int*);
+int (*snd_mixer_selem_set_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long);
+int (*snd_mixer_selem_set_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long);
+int (*snd_mixer_selem_set_playback_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long, int);
+int (*snd_mixer_selem_set_capture_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long, int);
+int (*snd_mixer_selem_set_playback_volume_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long);
+int (*snd_mixer_selem_set_capture_volume_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long);
+int (*snd_mixer_selem_set_playback_dB_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int);
+int (*snd_mixer_selem_set_capture_dB_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int);
+int (*snd_mixer_selem_set_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int);
+int (*snd_mixer_selem_set_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int);
+int (*snd_mixer_selem_set_playback_switch_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, int);
+int (*snd_mixer_selem_set_capture_switch_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, int);
+int (*snd_mixer_selem_get_playback_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+int (*snd_mixer_selem_get_playback_dB_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+int (*snd_mixer_selem_set_playback_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long);
+int (*snd_mixer_selem_get_capture_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+int (*snd_mixer_selem_get_capture_dB_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+int (*snd_mixer_selem_set_capture_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long);
+int (*snd_mixer_selem_is_enumerated_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_is_enum_playback_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_is_enum_capture_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_get_enum_items_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+int (*snd_mixer_selem_get_enum_item_name_dylibloader_wrapper_asound)( snd_mixer_elem_t*, unsigned int, size_t, char*);
+int (*snd_mixer_selem_get_enum_item_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, unsigned int*);
+int (*snd_mixer_selem_set_enum_item_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, unsigned int);
+size_t (*snd_mixer_selem_id_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_mixer_selem_id_malloc_dylibloader_wrapper_asound)( snd_mixer_selem_id_t**);
+void (*snd_mixer_selem_id_free_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*);
+void (*snd_mixer_selem_id_copy_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const snd_mixer_selem_id_t*);
+const char* (*snd_mixer_selem_id_get_name_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
+unsigned int (*snd_mixer_selem_id_get_index_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
+void (*snd_mixer_selem_id_set_name_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
+void (*snd_mixer_selem_id_set_index_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*, unsigned int);
+int (*snd_mixer_selem_id_parse_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
+int (*snd_seq_open_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int);
+int (*snd_seq_open_lconf_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int, snd_config_t*);
+const char* (*snd_seq_name_dylibloader_wrapper_asound)( snd_seq_t*);
+snd_seq_type_t (*snd_seq_type_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_close_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_poll_descriptors_count_dylibloader_wrapper_asound)( snd_seq_t*, short);
+int (*snd_seq_poll_descriptors_dylibloader_wrapper_asound)( snd_seq_t*,struct pollfd*, unsigned int, short);
+int (*snd_seq_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_seq_t*,struct pollfd*, unsigned int, unsigned short*);
+int (*snd_seq_nonblock_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_client_id_dylibloader_wrapper_asound)( snd_seq_t*);
+size_t (*snd_seq_get_output_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*);
+size_t (*snd_seq_get_input_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_set_output_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+int (*snd_seq_set_input_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+size_t (*snd_seq_system_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_system_info_malloc_dylibloader_wrapper_asound)( snd_seq_system_info_t**);
+void (*snd_seq_system_info_free_dylibloader_wrapper_asound)( snd_seq_system_info_t*);
+void (*snd_seq_system_info_copy_dylibloader_wrapper_asound)( snd_seq_system_info_t*,const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_queues_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_clients_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_ports_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_channels_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_cur_clients_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_get_cur_queues_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+int (*snd_seq_system_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_system_info_t*);
+size_t (*snd_seq_client_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_client_info_malloc_dylibloader_wrapper_asound)( snd_seq_client_info_t**);
+void (*snd_seq_client_info_free_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+void (*snd_seq_client_info_copy_dylibloader_wrapper_asound)( snd_seq_client_info_t*,const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_client_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+snd_seq_client_type_t (*snd_seq_client_info_get_type_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+const char* (*snd_seq_client_info_get_name_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_broadcast_filter_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_error_bounce_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_card_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_pid_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+const unsigned char* (*snd_seq_client_info_get_event_filter_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_num_ports_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+int (*snd_seq_client_info_get_event_lost_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+void (*snd_seq_client_info_set_client_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+void (*snd_seq_client_info_set_name_dylibloader_wrapper_asound)( snd_seq_client_info_t*,const char*);
+void (*snd_seq_client_info_set_broadcast_filter_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+void (*snd_seq_client_info_set_error_bounce_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+void (*snd_seq_client_info_set_event_filter_dylibloader_wrapper_asound)( snd_seq_client_info_t*, unsigned char*);
+void (*snd_seq_client_info_event_filter_clear_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+void (*snd_seq_client_info_event_filter_add_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+void (*snd_seq_client_info_event_filter_del_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+int (*snd_seq_client_info_event_filter_check_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+int (*snd_seq_get_client_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+int (*snd_seq_get_any_client_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_client_info_t*);
+int (*snd_seq_set_client_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+int (*snd_seq_query_next_client_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+size_t (*snd_seq_client_pool_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_client_pool_malloc_dylibloader_wrapper_asound)( snd_seq_client_pool_t**);
+void (*snd_seq_client_pool_free_dylibloader_wrapper_asound)( snd_seq_client_pool_t*);
+void (*snd_seq_client_pool_copy_dylibloader_wrapper_asound)( snd_seq_client_pool_t*,const snd_seq_client_pool_t*);
+int (*snd_seq_client_pool_get_client_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+size_t (*snd_seq_client_pool_get_output_pool_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+size_t (*snd_seq_client_pool_get_input_pool_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+size_t (*snd_seq_client_pool_get_output_room_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+size_t (*snd_seq_client_pool_get_output_free_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+size_t (*snd_seq_client_pool_get_input_free_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+void (*snd_seq_client_pool_set_output_pool_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+void (*snd_seq_client_pool_set_input_pool_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+void (*snd_seq_client_pool_set_output_room_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+int (*snd_seq_get_client_pool_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_pool_t*);
+int (*snd_seq_set_client_pool_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_pool_t*);
+size_t (*snd_seq_port_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_port_info_malloc_dylibloader_wrapper_asound)( snd_seq_port_info_t**);
+void (*snd_seq_port_info_free_dylibloader_wrapper_asound)( snd_seq_port_info_t*);
+void (*snd_seq_port_info_copy_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_client_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_port_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+const snd_seq_addr_t* (*snd_seq_port_info_get_addr_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+const char* (*snd_seq_port_info_get_name_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+unsigned int (*snd_seq_port_info_get_capability_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+unsigned int (*snd_seq_port_info_get_type_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_midi_channels_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_midi_voices_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_synth_voices_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_read_use_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_write_use_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_port_specified_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_timestamping_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_timestamp_real_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+int (*snd_seq_port_info_get_timestamp_queue_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+void (*snd_seq_port_info_set_client_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_port_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_addr_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const snd_seq_addr_t*);
+void (*snd_seq_port_info_set_name_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const char*);
+void (*snd_seq_port_info_set_capability_dylibloader_wrapper_asound)( snd_seq_port_info_t*, unsigned int);
+void (*snd_seq_port_info_set_type_dylibloader_wrapper_asound)( snd_seq_port_info_t*, unsigned int);
+void (*snd_seq_port_info_set_midi_channels_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_midi_voices_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_synth_voices_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_port_specified_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_timestamping_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_timestamp_real_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+void (*snd_seq_port_info_set_timestamp_queue_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+int (*snd_seq_create_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_info_t*);
+int (*snd_seq_delete_port_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_get_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_port_info_t*);
+int (*snd_seq_get_any_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, int, snd_seq_port_info_t*);
+int (*snd_seq_set_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_port_info_t*);
+int (*snd_seq_query_next_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_info_t*);
+size_t (*snd_seq_port_subscribe_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_port_subscribe_malloc_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t**);
+void (*snd_seq_port_subscribe_free_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*);
+void (*snd_seq_port_subscribe_copy_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_port_subscribe_t*);
+const snd_seq_addr_t* (*snd_seq_port_subscribe_get_sender_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+const snd_seq_addr_t* (*snd_seq_port_subscribe_get_dest_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+int (*snd_seq_port_subscribe_get_queue_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+int (*snd_seq_port_subscribe_get_exclusive_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+int (*snd_seq_port_subscribe_get_time_update_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+int (*snd_seq_port_subscribe_get_time_real_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+void (*snd_seq_port_subscribe_set_sender_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_addr_t*);
+void (*snd_seq_port_subscribe_set_dest_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_addr_t*);
+void (*snd_seq_port_subscribe_set_queue_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+void (*snd_seq_port_subscribe_set_exclusive_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+void (*snd_seq_port_subscribe_set_time_update_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+void (*snd_seq_port_subscribe_set_time_real_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+int (*snd_seq_get_port_subscription_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+int (*snd_seq_subscribe_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+int (*snd_seq_unsubscribe_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+size_t (*snd_seq_query_subscribe_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_query_subscribe_malloc_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t**);
+void (*snd_seq_query_subscribe_free_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*);
+void (*snd_seq_query_subscribe_copy_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*,const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_client_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_port_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+const snd_seq_addr_t* (*snd_seq_query_subscribe_get_root_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+snd_seq_query_subs_type_t (*snd_seq_query_subscribe_get_type_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_index_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_num_subs_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+const snd_seq_addr_t* (*snd_seq_query_subscribe_get_addr_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_queue_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_exclusive_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_time_update_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+int (*snd_seq_query_subscribe_get_time_real_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+void (*snd_seq_query_subscribe_set_client_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+void (*snd_seq_query_subscribe_set_port_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+void (*snd_seq_query_subscribe_set_root_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*,const snd_seq_addr_t*);
+void (*snd_seq_query_subscribe_set_type_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, snd_seq_query_subs_type_t);
+void (*snd_seq_query_subscribe_set_index_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+int (*snd_seq_query_port_subscribers_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_query_subscribe_t*);
+size_t (*snd_seq_queue_info_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_queue_info_malloc_dylibloader_wrapper_asound)( snd_seq_queue_info_t**);
+void (*snd_seq_queue_info_free_dylibloader_wrapper_asound)( snd_seq_queue_info_t*);
+void (*snd_seq_queue_info_copy_dylibloader_wrapper_asound)( snd_seq_queue_info_t*,const snd_seq_queue_info_t*);
+int (*snd_seq_queue_info_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+const char* (*snd_seq_queue_info_get_name_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+int (*snd_seq_queue_info_get_owner_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+int (*snd_seq_queue_info_get_locked_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+unsigned int (*snd_seq_queue_info_get_flags_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+void (*snd_seq_queue_info_set_name_dylibloader_wrapper_asound)( snd_seq_queue_info_t*,const char*);
+void (*snd_seq_queue_info_set_owner_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, int);
+void (*snd_seq_queue_info_set_locked_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, int);
+void (*snd_seq_queue_info_set_flags_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, unsigned int);
+int (*snd_seq_create_queue_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_queue_info_t*);
+int (*snd_seq_alloc_named_queue_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+int (*snd_seq_alloc_queue_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_free_queue_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_get_queue_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_info_t*);
+int (*snd_seq_set_queue_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_info_t*);
+int (*snd_seq_query_named_queue_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+int (*snd_seq_get_queue_usage_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_set_queue_usage_dylibloader_wrapper_asound)( snd_seq_t*, int, int);
+size_t (*snd_seq_queue_status_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_queue_status_malloc_dylibloader_wrapper_asound)( snd_seq_queue_status_t**);
+void (*snd_seq_queue_status_free_dylibloader_wrapper_asound)( snd_seq_queue_status_t*);
+void (*snd_seq_queue_status_copy_dylibloader_wrapper_asound)( snd_seq_queue_status_t*,const snd_seq_queue_status_t*);
+int (*snd_seq_queue_status_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+int (*snd_seq_queue_status_get_events_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+snd_seq_tick_time_t (*snd_seq_queue_status_get_tick_time_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+const snd_seq_real_time_t* (*snd_seq_queue_status_get_real_time_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+unsigned int (*snd_seq_queue_status_get_status_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+int (*snd_seq_get_queue_status_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_status_t*);
+size_t (*snd_seq_queue_tempo_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_queue_tempo_malloc_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t**);
+void (*snd_seq_queue_tempo_free_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*);
+void (*snd_seq_queue_tempo_copy_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*,const snd_seq_queue_tempo_t*);
+int (*snd_seq_queue_tempo_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+unsigned int (*snd_seq_queue_tempo_get_tempo_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+int (*snd_seq_queue_tempo_get_ppq_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+unsigned int (*snd_seq_queue_tempo_get_skew_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+unsigned int (*snd_seq_queue_tempo_get_skew_base_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+void (*snd_seq_queue_tempo_set_tempo_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+void (*snd_seq_queue_tempo_set_ppq_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, int);
+void (*snd_seq_queue_tempo_set_skew_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+void (*snd_seq_queue_tempo_set_skew_base_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+int (*snd_seq_get_queue_tempo_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_tempo_t*);
+int (*snd_seq_set_queue_tempo_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_tempo_t*);
+size_t (*snd_seq_queue_timer_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_queue_timer_malloc_dylibloader_wrapper_asound)( snd_seq_queue_timer_t**);
+void (*snd_seq_queue_timer_free_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*);
+void (*snd_seq_queue_timer_copy_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*,const snd_seq_queue_timer_t*);
+int (*snd_seq_queue_timer_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+snd_seq_queue_timer_type_t (*snd_seq_queue_timer_get_type_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+const snd_timer_id_t* (*snd_seq_queue_timer_get_id_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+unsigned int (*snd_seq_queue_timer_get_resolution_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+void (*snd_seq_queue_timer_set_type_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*, snd_seq_queue_timer_type_t);
+void (*snd_seq_queue_timer_set_id_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*,const snd_timer_id_t*);
+void (*snd_seq_queue_timer_set_resolution_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*, unsigned int);
+int (*snd_seq_get_queue_timer_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_timer_t*);
+int (*snd_seq_set_queue_timer_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_timer_t*);
+int (*snd_seq_free_event_dylibloader_wrapper_asound)( snd_seq_event_t*);
+ssize_t (*snd_seq_event_length_dylibloader_wrapper_asound)( snd_seq_event_t*);
+int (*snd_seq_event_output_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+int (*snd_seq_event_output_buffer_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+int (*snd_seq_event_output_direct_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+int (*snd_seq_event_input_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t**);
+int (*snd_seq_event_input_pending_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_drain_output_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_event_output_pending_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_extract_output_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t**);
+int (*snd_seq_drop_output_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_drop_output_buffer_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_drop_input_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_drop_input_buffer_dylibloader_wrapper_asound)( snd_seq_t*);
+size_t (*snd_seq_remove_events_sizeof_dylibloader_wrapper_asound)( void);
+int (*snd_seq_remove_events_malloc_dylibloader_wrapper_asound)( snd_seq_remove_events_t**);
+void (*snd_seq_remove_events_free_dylibloader_wrapper_asound)( snd_seq_remove_events_t*);
+void (*snd_seq_remove_events_copy_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_remove_events_t*);
+unsigned int (*snd_seq_remove_events_get_condition_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+int (*snd_seq_remove_events_get_queue_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+const snd_seq_timestamp_t* (*snd_seq_remove_events_get_time_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+const snd_seq_addr_t* (*snd_seq_remove_events_get_dest_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+int (*snd_seq_remove_events_get_channel_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+int (*snd_seq_remove_events_get_event_type_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+int (*snd_seq_remove_events_get_tag_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+void (*snd_seq_remove_events_set_condition_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, unsigned int);
+void (*snd_seq_remove_events_set_queue_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+void (*snd_seq_remove_events_set_time_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_timestamp_t*);
+void (*snd_seq_remove_events_set_dest_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_addr_t*);
+void (*snd_seq_remove_events_set_channel_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+void (*snd_seq_remove_events_set_event_type_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+void (*snd_seq_remove_events_set_tag_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+int (*snd_seq_remove_events_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_remove_events_t*);
+void (*snd_seq_set_bit_dylibloader_wrapper_asound)( int, void*);
+void (*snd_seq_unset_bit_dylibloader_wrapper_asound)( int, void*);
+int (*snd_seq_change_bit_dylibloader_wrapper_asound)( int, void*);
+int (*snd_seq_get_bit_dylibloader_wrapper_asound)( int, void*);
+int (*snd_seq_control_queue_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int, snd_seq_event_t*);
+int (*snd_seq_create_simple_port_dylibloader_wrapper_asound)( snd_seq_t*,const char*, unsigned int, unsigned int);
+int (*snd_seq_delete_simple_port_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_connect_from_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+int (*snd_seq_connect_to_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+int (*snd_seq_disconnect_from_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+int (*snd_seq_disconnect_to_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+int (*snd_seq_set_client_name_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+int (*snd_seq_set_client_event_filter_dylibloader_wrapper_asound)( snd_seq_t*, int);
+int (*snd_seq_set_client_pool_output_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+int (*snd_seq_set_client_pool_output_room_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+int (*snd_seq_set_client_pool_input_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+int (*snd_seq_sync_output_queue_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_parse_address_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_addr_t*,const char*);
+int (*snd_seq_reset_pool_output_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_seq_reset_pool_input_dylibloader_wrapper_asound)( snd_seq_t*);
+int (*snd_midi_event_new_dylibloader_wrapper_asound)( size_t, snd_midi_event_t**);
+int (*snd_midi_event_resize_buffer_dylibloader_wrapper_asound)( snd_midi_event_t*, size_t);
+void (*snd_midi_event_free_dylibloader_wrapper_asound)( snd_midi_event_t*);
+void (*snd_midi_event_init_dylibloader_wrapper_asound)( snd_midi_event_t*);
+void (*snd_midi_event_reset_encode_dylibloader_wrapper_asound)( snd_midi_event_t*);
+void (*snd_midi_event_reset_decode_dylibloader_wrapper_asound)( snd_midi_event_t*);
+void (*snd_midi_event_no_status_dylibloader_wrapper_asound)( snd_midi_event_t*, int);
+long (*snd_midi_event_encode_dylibloader_wrapper_asound)( snd_midi_event_t*,const unsigned char*, long, snd_seq_event_t*);
+int (*snd_midi_event_encode_byte_dylibloader_wrapper_asound)( snd_midi_event_t*, int, snd_seq_event_t*);
+long (*snd_midi_event_decode_dylibloader_wrapper_asound)( snd_midi_event_t*, unsigned char*, long,const snd_seq_event_t*);
+int initialize_asound(int verbose) {
+ void *handle;
+ char *error;
+ handle = dlopen("libasound.so.2", RTLD_LAZY);
+ if (!handle) {
+ if (verbose) {
+ fprintf(stderr, "%s\n", dlerror());
+ }
+ return(1);
+ }
+ dlerror();
+// snd_asoundlib_version
+ *(void **) (&snd_asoundlib_version_dylibloader_wrapper_asound) = dlsym(handle, "snd_asoundlib_version");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_dlpath
+ *(void **) (&snd_dlpath_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlpath");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_dlopen
+ *(void **) (&snd_dlopen_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlopen");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_dlsym
+ *(void **) (&snd_dlsym_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlsym");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_dlclose
+ *(void **) (&snd_dlclose_dylibloader_wrapper_asound) = dlsym(handle, "snd_dlclose");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_add_handler
+ *(void **) (&snd_async_add_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_add_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_del_handler
+ *(void **) (&snd_async_del_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_del_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_fd
+ *(void **) (&snd_async_handler_get_fd_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_fd");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_signo
+ *(void **) (&snd_async_handler_get_signo_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_signo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_callback_private
+ *(void **) (&snd_async_handler_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_shm_area_create
+ *(void **) (&snd_shm_area_create_dylibloader_wrapper_asound) = dlsym(handle, "snd_shm_area_create");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_shm_area_share
+ *(void **) (&snd_shm_area_share_dylibloader_wrapper_asound) = dlsym(handle, "snd_shm_area_share");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_shm_area_destroy
+ *(void **) (&snd_shm_area_destroy_dylibloader_wrapper_asound) = dlsym(handle, "snd_shm_area_destroy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_user_file
+ *(void **) (&snd_user_file_dylibloader_wrapper_asound) = dlsym(handle, "snd_user_file");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_stdio_open
+ *(void **) (&snd_input_stdio_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_stdio_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_stdio_attach
+ *(void **) (&snd_input_stdio_attach_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_stdio_attach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_buffer_open
+ *(void **) (&snd_input_buffer_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_buffer_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_close
+ *(void **) (&snd_input_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_scanf
+ *(void **) (&snd_input_scanf_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_scanf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_gets
+ *(void **) (&snd_input_gets_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_gets");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_getc
+ *(void **) (&snd_input_getc_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_getc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_input_ungetc
+ *(void **) (&snd_input_ungetc_dylibloader_wrapper_asound) = dlsym(handle, "snd_input_ungetc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_stdio_open
+ *(void **) (&snd_output_stdio_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_stdio_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_stdio_attach
+ *(void **) (&snd_output_stdio_attach_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_stdio_attach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_buffer_open
+ *(void **) (&snd_output_buffer_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_buffer_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_buffer_string
+ *(void **) (&snd_output_buffer_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_buffer_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_close
+ *(void **) (&snd_output_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_printf
+ *(void **) (&snd_output_printf_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_printf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_vprintf
+ *(void **) (&snd_output_vprintf_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_vprintf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_puts
+ *(void **) (&snd_output_puts_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_puts");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_putc
+ *(void **) (&snd_output_putc_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_putc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_output_flush
+ *(void **) (&snd_output_flush_dylibloader_wrapper_asound) = dlsym(handle, "snd_output_flush");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_strerror
+ *(void **) (&snd_strerror_dylibloader_wrapper_asound) = dlsym(handle, "snd_strerror");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_lib_error_set_handler
+ *(void **) (&snd_lib_error_set_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_lib_error_set_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_lib_error_set_local
+ *(void **) (&snd_lib_error_set_local_dylibloader_wrapper_asound) = dlsym(handle, "snd_lib_error_set_local");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_topdir
+ *(void **) (&snd_config_topdir_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_topdir");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_top
+ *(void **) (&snd_config_top_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_top");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_load
+ *(void **) (&snd_config_load_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_load_override
+ *(void **) (&snd_config_load_override_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_load_override");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_save
+ *(void **) (&snd_config_save_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_save");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_update
+ *(void **) (&snd_config_update_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_update_r
+ *(void **) (&snd_config_update_r_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_update_r");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_update_free
+ *(void **) (&snd_config_update_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_update_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_update_free_global
+ *(void **) (&snd_config_update_free_global_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_update_free_global");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_update_ref
+ *(void **) (&snd_config_update_ref_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_update_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_ref
+ *(void **) (&snd_config_ref_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_unref
+ *(void **) (&snd_config_unref_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_search
+ *(void **) (&snd_config_search_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_search");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_searchv
+ *(void **) (&snd_config_searchv_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_searchv");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_search_definition
+ *(void **) (&snd_config_search_definition_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_search_definition");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_expand
+ *(void **) (&snd_config_expand_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_expand");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_evaluate
+ *(void **) (&snd_config_evaluate_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_evaluate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_add
+ *(void **) (&snd_config_add_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_add");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_add_before
+ *(void **) (&snd_config_add_before_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_add_before");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_add_after
+ *(void **) (&snd_config_add_after_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_add_after");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_remove
+ *(void **) (&snd_config_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_delete
+ *(void **) (&snd_config_delete_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_delete");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_delete_compound_members
+ *(void **) (&snd_config_delete_compound_members_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_delete_compound_members");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_copy
+ *(void **) (&snd_config_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make
+ *(void **) (&snd_config_make_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_integer
+ *(void **) (&snd_config_make_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_integer64
+ *(void **) (&snd_config_make_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_real
+ *(void **) (&snd_config_make_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_string
+ *(void **) (&snd_config_make_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_pointer
+ *(void **) (&snd_config_make_pointer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_pointer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_make_compound
+ *(void **) (&snd_config_make_compound_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_make_compound");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_integer
+ *(void **) (&snd_config_imake_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_integer64
+ *(void **) (&snd_config_imake_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_real
+ *(void **) (&snd_config_imake_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_string
+ *(void **) (&snd_config_imake_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_safe_string
+ *(void **) (&snd_config_imake_safe_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_safe_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_imake_pointer
+ *(void **) (&snd_config_imake_pointer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_imake_pointer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_type
+ *(void **) (&snd_config_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_is_array
+ *(void **) (&snd_config_is_array_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_is_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_id
+ *(void **) (&snd_config_set_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_integer
+ *(void **) (&snd_config_set_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_integer64
+ *(void **) (&snd_config_set_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_real
+ *(void **) (&snd_config_set_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_string
+ *(void **) (&snd_config_set_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_ascii
+ *(void **) (&snd_config_set_ascii_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_ascii");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_set_pointer
+ *(void **) (&snd_config_set_pointer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_set_pointer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_id
+ *(void **) (&snd_config_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_integer
+ *(void **) (&snd_config_get_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_integer64
+ *(void **) (&snd_config_get_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_real
+ *(void **) (&snd_config_get_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_ireal
+ *(void **) (&snd_config_get_ireal_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_ireal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_string
+ *(void **) (&snd_config_get_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_ascii
+ *(void **) (&snd_config_get_ascii_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_ascii");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_pointer
+ *(void **) (&snd_config_get_pointer_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_pointer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_test_id
+ *(void **) (&snd_config_test_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_test_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_iterator_first
+ *(void **) (&snd_config_iterator_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_iterator_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_iterator_next
+ *(void **) (&snd_config_iterator_next_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_iterator_next");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_iterator_end
+ *(void **) (&snd_config_iterator_end_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_iterator_end");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_iterator_entry
+ *(void **) (&snd_config_iterator_entry_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_iterator_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_bool_ascii
+ *(void **) (&snd_config_get_bool_ascii_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_bool_ascii");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_bool
+ *(void **) (&snd_config_get_bool_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_bool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_ctl_iface_ascii
+ *(void **) (&snd_config_get_ctl_iface_ascii_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_ctl_iface_ascii");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_config_get_ctl_iface
+ *(void **) (&snd_config_get_ctl_iface_dylibloader_wrapper_asound) = dlsym(handle, "snd_config_get_ctl_iface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_names_list
+ *(void **) (&snd_names_list_dylibloader_wrapper_asound) = dlsym(handle, "snd_names_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_names_list_free
+ *(void **) (&snd_names_list_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_names_list_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_open
+ *(void **) (&snd_pcm_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_open_lconf
+ *(void **) (&snd_pcm_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_open_fallback
+ *(void **) (&snd_pcm_open_fallback_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_open_fallback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_close
+ *(void **) (&snd_pcm_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_name
+ *(void **) (&snd_pcm_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_type
+ *(void **) (&snd_pcm_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_stream
+ *(void **) (&snd_pcm_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_poll_descriptors_count
+ *(void **) (&snd_pcm_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_poll_descriptors
+ *(void **) (&snd_pcm_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_poll_descriptors_revents
+ *(void **) (&snd_pcm_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_nonblock
+ *(void **) (&snd_pcm_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_add_pcm_handler
+ *(void **) (&snd_async_add_pcm_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_add_pcm_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_pcm
+ *(void **) (&snd_async_handler_get_pcm_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_pcm");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info
+ *(void **) (&snd_pcm_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_current
+ *(void **) (&snd_pcm_hw_params_current_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_current");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params
+ *(void **) (&snd_pcm_hw_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_free
+ *(void **) (&snd_pcm_hw_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_current
+ *(void **) (&snd_pcm_sw_params_current_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_current");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params
+ *(void **) (&snd_pcm_sw_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_prepare
+ *(void **) (&snd_pcm_prepare_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_prepare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_reset
+ *(void **) (&snd_pcm_reset_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_reset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status
+ *(void **) (&snd_pcm_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_start
+ *(void **) (&snd_pcm_start_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_drop
+ *(void **) (&snd_pcm_drop_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_drop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_drain
+ *(void **) (&snd_pcm_drain_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_drain");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_pause
+ *(void **) (&snd_pcm_pause_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_pause");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_state
+ *(void **) (&snd_pcm_state_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hwsync
+ *(void **) (&snd_pcm_hwsync_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hwsync");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_delay
+ *(void **) (&snd_pcm_delay_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_delay");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_resume
+ *(void **) (&snd_pcm_resume_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_resume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_htimestamp
+ *(void **) (&snd_pcm_htimestamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_htimestamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_avail
+ *(void **) (&snd_pcm_avail_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_avail");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_avail_update
+ *(void **) (&snd_pcm_avail_update_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_avail_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_avail_delay
+ *(void **) (&snd_pcm_avail_delay_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_avail_delay");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_rewindable
+ *(void **) (&snd_pcm_rewindable_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_rewindable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_rewind
+ *(void **) (&snd_pcm_rewind_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_rewind");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_forwardable
+ *(void **) (&snd_pcm_forwardable_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_forwardable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_forward
+ *(void **) (&snd_pcm_forward_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_forward");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_writei
+ *(void **) (&snd_pcm_writei_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_writei");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_readi
+ *(void **) (&snd_pcm_readi_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_readi");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_writen
+ *(void **) (&snd_pcm_writen_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_writen");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_readn
+ *(void **) (&snd_pcm_readn_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_readn");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_wait
+ *(void **) (&snd_pcm_wait_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_wait");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_link
+ *(void **) (&snd_pcm_link_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_link");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_unlink
+ *(void **) (&snd_pcm_unlink_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_unlink");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_query_chmaps
+ *(void **) (&snd_pcm_query_chmaps_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_query_chmaps");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_query_chmaps_from_hw
+ *(void **) (&snd_pcm_query_chmaps_from_hw_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_query_chmaps_from_hw");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_free_chmaps
+ *(void **) (&snd_pcm_free_chmaps_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_free_chmaps");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_get_chmap
+ *(void **) (&snd_pcm_get_chmap_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_get_chmap");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_set_chmap
+ *(void **) (&snd_pcm_set_chmap_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_set_chmap");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_type_name
+ *(void **) (&snd_pcm_chmap_type_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_type_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_name
+ *(void **) (&snd_pcm_chmap_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_long_name
+ *(void **) (&snd_pcm_chmap_long_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_long_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_print
+ *(void **) (&snd_pcm_chmap_print_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_print");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_from_string
+ *(void **) (&snd_pcm_chmap_from_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_chmap_parse_string
+ *(void **) (&snd_pcm_chmap_parse_string_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_chmap_parse_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_recover
+ *(void **) (&snd_pcm_recover_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_recover");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_set_params
+ *(void **) (&snd_pcm_set_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_set_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_get_params
+ *(void **) (&snd_pcm_get_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_get_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_sizeof
+ *(void **) (&snd_pcm_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_malloc
+ *(void **) (&snd_pcm_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_free
+ *(void **) (&snd_pcm_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_copy
+ *(void **) (&snd_pcm_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_device
+ *(void **) (&snd_pcm_info_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_subdevice
+ *(void **) (&snd_pcm_info_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_stream
+ *(void **) (&snd_pcm_info_get_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_card
+ *(void **) (&snd_pcm_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_id
+ *(void **) (&snd_pcm_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_name
+ *(void **) (&snd_pcm_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_subdevice_name
+ *(void **) (&snd_pcm_info_get_subdevice_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_subdevice_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_class
+ *(void **) (&snd_pcm_info_get_class_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_class");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_subclass
+ *(void **) (&snd_pcm_info_get_subclass_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_subclass");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_subdevices_count
+ *(void **) (&snd_pcm_info_get_subdevices_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_subdevices_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_subdevices_avail
+ *(void **) (&snd_pcm_info_get_subdevices_avail_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_subdevices_avail");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_get_sync
+ *(void **) (&snd_pcm_info_get_sync_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_get_sync");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_set_device
+ *(void **) (&snd_pcm_info_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_set_subdevice
+ *(void **) (&snd_pcm_info_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_info_set_stream
+ *(void **) (&snd_pcm_info_set_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_info_set_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_any
+ *(void **) (&snd_pcm_hw_params_any_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_any");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_mmap_sample_resolution
+ *(void **) (&snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_mmap_sample_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_double
+ *(void **) (&snd_pcm_hw_params_is_double_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_double");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_batch
+ *(void **) (&snd_pcm_hw_params_is_batch_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_batch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_block_transfer
+ *(void **) (&snd_pcm_hw_params_is_block_transfer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_block_transfer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_monotonic
+ *(void **) (&snd_pcm_hw_params_is_monotonic_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_monotonic");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_overrange
+ *(void **) (&snd_pcm_hw_params_can_overrange_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_overrange");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_pause
+ *(void **) (&snd_pcm_hw_params_can_pause_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_pause");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_resume
+ *(void **) (&snd_pcm_hw_params_can_resume_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_resume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_half_duplex
+ *(void **) (&snd_pcm_hw_params_is_half_duplex_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_half_duplex");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_is_joint_duplex
+ *(void **) (&snd_pcm_hw_params_is_joint_duplex_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_is_joint_duplex");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_sync_start
+ *(void **) (&snd_pcm_hw_params_can_sync_start_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_sync_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_can_disable_period_wakeup
+ *(void **) (&snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_can_disable_period_wakeup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_supports_audio_wallclock_ts
+ *(void **) (&snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_supports_audio_wallclock_ts");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_supports_audio_ts_type
+ *(void **) (&snd_pcm_hw_params_supports_audio_ts_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_supports_audio_ts_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_rate_numden
+ *(void **) (&snd_pcm_hw_params_get_rate_numden_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_rate_numden");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_sbits
+ *(void **) (&snd_pcm_hw_params_get_sbits_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_sbits");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_fifo_size
+ *(void **) (&snd_pcm_hw_params_get_fifo_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_fifo_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_sizeof
+ *(void **) (&snd_pcm_hw_params_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_malloc
+ *(void **) (&snd_pcm_hw_params_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_free
+ *(void **) (&snd_pcm_hw_params_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_copy
+ *(void **) (&snd_pcm_hw_params_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_access
+ *(void **) (&snd_pcm_hw_params_get_access_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_access");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_access
+ *(void **) (&snd_pcm_hw_params_test_access_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_access");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_access
+ *(void **) (&snd_pcm_hw_params_set_access_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_access");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_access_first
+ *(void **) (&snd_pcm_hw_params_set_access_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_access_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_access_last
+ *(void **) (&snd_pcm_hw_params_set_access_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_access_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_access_mask
+ *(void **) (&snd_pcm_hw_params_set_access_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_access_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_access_mask
+ *(void **) (&snd_pcm_hw_params_get_access_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_access_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_format
+ *(void **) (&snd_pcm_hw_params_get_format_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_format
+ *(void **) (&snd_pcm_hw_params_test_format_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_format
+ *(void **) (&snd_pcm_hw_params_set_format_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_format_first
+ *(void **) (&snd_pcm_hw_params_set_format_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_format_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_format_last
+ *(void **) (&snd_pcm_hw_params_set_format_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_format_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_format_mask
+ *(void **) (&snd_pcm_hw_params_set_format_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_format_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_format_mask
+ *(void **) (&snd_pcm_hw_params_get_format_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_format_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_subformat
+ *(void **) (&snd_pcm_hw_params_get_subformat_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_subformat");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_subformat
+ *(void **) (&snd_pcm_hw_params_test_subformat_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_subformat");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_subformat
+ *(void **) (&snd_pcm_hw_params_set_subformat_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_subformat");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_subformat_first
+ *(void **) (&snd_pcm_hw_params_set_subformat_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_subformat_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_subformat_last
+ *(void **) (&snd_pcm_hw_params_set_subformat_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_subformat_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_subformat_mask
+ *(void **) (&snd_pcm_hw_params_set_subformat_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_subformat_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_subformat_mask
+ *(void **) (&snd_pcm_hw_params_get_subformat_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_subformat_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_channels
+ *(void **) (&snd_pcm_hw_params_get_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_channels_min
+ *(void **) (&snd_pcm_hw_params_get_channels_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_channels_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_channels_max
+ *(void **) (&snd_pcm_hw_params_get_channels_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_channels_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_channels
+ *(void **) (&snd_pcm_hw_params_test_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels
+ *(void **) (&snd_pcm_hw_params_set_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_min
+ *(void **) (&snd_pcm_hw_params_set_channels_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_max
+ *(void **) (&snd_pcm_hw_params_set_channels_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_minmax
+ *(void **) (&snd_pcm_hw_params_set_channels_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_near
+ *(void **) (&snd_pcm_hw_params_set_channels_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_first
+ *(void **) (&snd_pcm_hw_params_set_channels_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_channels_last
+ *(void **) (&snd_pcm_hw_params_set_channels_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_channels_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_rate
+ *(void **) (&snd_pcm_hw_params_get_rate_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_rate_min
+ *(void **) (&snd_pcm_hw_params_get_rate_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_rate_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_rate_max
+ *(void **) (&snd_pcm_hw_params_get_rate_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_rate_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_rate
+ *(void **) (&snd_pcm_hw_params_test_rate_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate
+ *(void **) (&snd_pcm_hw_params_set_rate_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_min
+ *(void **) (&snd_pcm_hw_params_set_rate_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_max
+ *(void **) (&snd_pcm_hw_params_set_rate_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_minmax
+ *(void **) (&snd_pcm_hw_params_set_rate_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_near
+ *(void **) (&snd_pcm_hw_params_set_rate_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_first
+ *(void **) (&snd_pcm_hw_params_set_rate_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_last
+ *(void **) (&snd_pcm_hw_params_set_rate_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_rate_resample
+ *(void **) (&snd_pcm_hw_params_set_rate_resample_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_rate_resample");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_rate_resample
+ *(void **) (&snd_pcm_hw_params_get_rate_resample_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_rate_resample");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_export_buffer
+ *(void **) (&snd_pcm_hw_params_set_export_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_export_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_export_buffer
+ *(void **) (&snd_pcm_hw_params_get_export_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_export_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_wakeup
+ *(void **) (&snd_pcm_hw_params_set_period_wakeup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_wakeup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_wakeup
+ *(void **) (&snd_pcm_hw_params_get_period_wakeup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_wakeup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_time
+ *(void **) (&snd_pcm_hw_params_get_period_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_time_min
+ *(void **) (&snd_pcm_hw_params_get_period_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_time_max
+ *(void **) (&snd_pcm_hw_params_get_period_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_period_time
+ *(void **) (&snd_pcm_hw_params_test_period_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_period_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time
+ *(void **) (&snd_pcm_hw_params_set_period_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_min
+ *(void **) (&snd_pcm_hw_params_set_period_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_max
+ *(void **) (&snd_pcm_hw_params_set_period_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_minmax
+ *(void **) (&snd_pcm_hw_params_set_period_time_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_near
+ *(void **) (&snd_pcm_hw_params_set_period_time_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_first
+ *(void **) (&snd_pcm_hw_params_set_period_time_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_time_last
+ *(void **) (&snd_pcm_hw_params_set_period_time_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_time_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_size
+ *(void **) (&snd_pcm_hw_params_get_period_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_size_min
+ *(void **) (&snd_pcm_hw_params_get_period_size_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_size_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_period_size_max
+ *(void **) (&snd_pcm_hw_params_get_period_size_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_period_size_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_period_size
+ *(void **) (&snd_pcm_hw_params_test_period_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_period_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size
+ *(void **) (&snd_pcm_hw_params_set_period_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_min
+ *(void **) (&snd_pcm_hw_params_set_period_size_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_max
+ *(void **) (&snd_pcm_hw_params_set_period_size_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_minmax
+ *(void **) (&snd_pcm_hw_params_set_period_size_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_near
+ *(void **) (&snd_pcm_hw_params_set_period_size_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_first
+ *(void **) (&snd_pcm_hw_params_set_period_size_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_last
+ *(void **) (&snd_pcm_hw_params_set_period_size_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_period_size_integer
+ *(void **) (&snd_pcm_hw_params_set_period_size_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_period_size_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_periods
+ *(void **) (&snd_pcm_hw_params_get_periods_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_periods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_periods_min
+ *(void **) (&snd_pcm_hw_params_get_periods_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_periods_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_periods_max
+ *(void **) (&snd_pcm_hw_params_get_periods_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_periods_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_periods
+ *(void **) (&snd_pcm_hw_params_test_periods_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_periods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods
+ *(void **) (&snd_pcm_hw_params_set_periods_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_min
+ *(void **) (&snd_pcm_hw_params_set_periods_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_max
+ *(void **) (&snd_pcm_hw_params_set_periods_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_minmax
+ *(void **) (&snd_pcm_hw_params_set_periods_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_near
+ *(void **) (&snd_pcm_hw_params_set_periods_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_first
+ *(void **) (&snd_pcm_hw_params_set_periods_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_last
+ *(void **) (&snd_pcm_hw_params_set_periods_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_periods_integer
+ *(void **) (&snd_pcm_hw_params_set_periods_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_periods_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_time
+ *(void **) (&snd_pcm_hw_params_get_buffer_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_time_min
+ *(void **) (&snd_pcm_hw_params_get_buffer_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_time_max
+ *(void **) (&snd_pcm_hw_params_get_buffer_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_buffer_time
+ *(void **) (&snd_pcm_hw_params_test_buffer_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_buffer_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_min
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_max
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_minmax
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_near
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_first
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_time_last
+ *(void **) (&snd_pcm_hw_params_set_buffer_time_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_time_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_size
+ *(void **) (&snd_pcm_hw_params_get_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_size_min
+ *(void **) (&snd_pcm_hw_params_get_buffer_size_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_size_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_buffer_size_max
+ *(void **) (&snd_pcm_hw_params_get_buffer_size_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_buffer_size_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_buffer_size
+ *(void **) (&snd_pcm_hw_params_test_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_min
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_max
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_minmax
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_near
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_first
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_buffer_size_last
+ *(void **) (&snd_pcm_hw_params_set_buffer_size_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_buffer_size_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_min_align
+ *(void **) (&snd_pcm_hw_params_get_min_align_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_min_align");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_sizeof
+ *(void **) (&snd_pcm_sw_params_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_malloc
+ *(void **) (&snd_pcm_sw_params_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_free
+ *(void **) (&snd_pcm_sw_params_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_copy
+ *(void **) (&snd_pcm_sw_params_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_boundary
+ *(void **) (&snd_pcm_sw_params_get_boundary_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_boundary");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_tstamp_mode
+ *(void **) (&snd_pcm_sw_params_set_tstamp_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_tstamp_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_tstamp_mode
+ *(void **) (&snd_pcm_sw_params_get_tstamp_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_tstamp_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_avail_min
+ *(void **) (&snd_pcm_sw_params_set_avail_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_avail_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_avail_min
+ *(void **) (&snd_pcm_sw_params_get_avail_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_avail_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_period_event
+ *(void **) (&snd_pcm_sw_params_set_period_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_period_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_period_event
+ *(void **) (&snd_pcm_sw_params_get_period_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_period_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_start_threshold
+ *(void **) (&snd_pcm_sw_params_set_start_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_start_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_start_threshold
+ *(void **) (&snd_pcm_sw_params_get_start_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_start_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_stop_threshold
+ *(void **) (&snd_pcm_sw_params_set_stop_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_stop_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_stop_threshold
+ *(void **) (&snd_pcm_sw_params_get_stop_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_stop_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_silence_threshold
+ *(void **) (&snd_pcm_sw_params_set_silence_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_silence_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_silence_threshold
+ *(void **) (&snd_pcm_sw_params_get_silence_threshold_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_silence_threshold");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_silence_size
+ *(void **) (&snd_pcm_sw_params_set_silence_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_silence_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_silence_size
+ *(void **) (&snd_pcm_sw_params_get_silence_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_silence_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_sizeof
+ *(void **) (&snd_pcm_access_mask_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_malloc
+ *(void **) (&snd_pcm_access_mask_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_free
+ *(void **) (&snd_pcm_access_mask_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_copy
+ *(void **) (&snd_pcm_access_mask_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_none
+ *(void **) (&snd_pcm_access_mask_none_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_none");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_any
+ *(void **) (&snd_pcm_access_mask_any_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_any");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_test
+ *(void **) (&snd_pcm_access_mask_test_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_test");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_empty
+ *(void **) (&snd_pcm_access_mask_empty_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_empty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_set
+ *(void **) (&snd_pcm_access_mask_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_mask_reset
+ *(void **) (&snd_pcm_access_mask_reset_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_mask_reset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_sizeof
+ *(void **) (&snd_pcm_format_mask_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_malloc
+ *(void **) (&snd_pcm_format_mask_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_free
+ *(void **) (&snd_pcm_format_mask_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_copy
+ *(void **) (&snd_pcm_format_mask_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_none
+ *(void **) (&snd_pcm_format_mask_none_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_none");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_any
+ *(void **) (&snd_pcm_format_mask_any_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_any");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_test
+ *(void **) (&snd_pcm_format_mask_test_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_test");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_empty
+ *(void **) (&snd_pcm_format_mask_empty_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_empty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_set
+ *(void **) (&snd_pcm_format_mask_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_mask_reset
+ *(void **) (&snd_pcm_format_mask_reset_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_mask_reset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_sizeof
+ *(void **) (&snd_pcm_subformat_mask_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_malloc
+ *(void **) (&snd_pcm_subformat_mask_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_free
+ *(void **) (&snd_pcm_subformat_mask_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_copy
+ *(void **) (&snd_pcm_subformat_mask_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_none
+ *(void **) (&snd_pcm_subformat_mask_none_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_none");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_any
+ *(void **) (&snd_pcm_subformat_mask_any_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_any");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_test
+ *(void **) (&snd_pcm_subformat_mask_test_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_test");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_empty
+ *(void **) (&snd_pcm_subformat_mask_empty_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_empty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_set
+ *(void **) (&snd_pcm_subformat_mask_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_mask_reset
+ *(void **) (&snd_pcm_subformat_mask_reset_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_mask_reset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_sizeof
+ *(void **) (&snd_pcm_status_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_malloc
+ *(void **) (&snd_pcm_status_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_free
+ *(void **) (&snd_pcm_status_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_copy
+ *(void **) (&snd_pcm_status_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_state
+ *(void **) (&snd_pcm_status_get_state_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_trigger_tstamp
+ *(void **) (&snd_pcm_status_get_trigger_tstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_trigger_tstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_trigger_htstamp
+ *(void **) (&snd_pcm_status_get_trigger_htstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_trigger_htstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_tstamp
+ *(void **) (&snd_pcm_status_get_tstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_tstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_htstamp
+ *(void **) (&snd_pcm_status_get_htstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_htstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_audio_htstamp
+ *(void **) (&snd_pcm_status_get_audio_htstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_audio_htstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_driver_htstamp
+ *(void **) (&snd_pcm_status_get_driver_htstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_driver_htstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_delay
+ *(void **) (&snd_pcm_status_get_delay_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_delay");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_avail
+ *(void **) (&snd_pcm_status_get_avail_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_avail");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_avail_max
+ *(void **) (&snd_pcm_status_get_avail_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_avail_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_get_overrange
+ *(void **) (&snd_pcm_status_get_overrange_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_get_overrange");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_type_name
+ *(void **) (&snd_pcm_type_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_type_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_stream_name
+ *(void **) (&snd_pcm_stream_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_stream_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_access_name
+ *(void **) (&snd_pcm_access_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_access_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_name
+ *(void **) (&snd_pcm_format_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_description
+ *(void **) (&snd_pcm_format_description_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_description");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_name
+ *(void **) (&snd_pcm_subformat_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_subformat_description
+ *(void **) (&snd_pcm_subformat_description_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_subformat_description");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_value
+ *(void **) (&snd_pcm_format_value_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_tstamp_mode_name
+ *(void **) (&snd_pcm_tstamp_mode_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_tstamp_mode_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_state_name
+ *(void **) (&snd_pcm_state_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_state_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_dump
+ *(void **) (&snd_pcm_dump_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_dump");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_dump_hw_setup
+ *(void **) (&snd_pcm_dump_hw_setup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_dump_hw_setup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_dump_sw_setup
+ *(void **) (&snd_pcm_dump_sw_setup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_dump_sw_setup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_dump_setup
+ *(void **) (&snd_pcm_dump_setup_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_dump_setup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_dump
+ *(void **) (&snd_pcm_hw_params_dump_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_dump");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_dump
+ *(void **) (&snd_pcm_sw_params_dump_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_dump");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_status_dump
+ *(void **) (&snd_pcm_status_dump_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_status_dump");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_begin
+ *(void **) (&snd_pcm_mmap_begin_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_begin");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_commit
+ *(void **) (&snd_pcm_mmap_commit_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_commit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_writei
+ *(void **) (&snd_pcm_mmap_writei_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_writei");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_readi
+ *(void **) (&snd_pcm_mmap_readi_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_readi");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_writen
+ *(void **) (&snd_pcm_mmap_writen_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_writen");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_mmap_readn
+ *(void **) (&snd_pcm_mmap_readn_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_mmap_readn");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_signed
+ *(void **) (&snd_pcm_format_signed_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_signed");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_unsigned
+ *(void **) (&snd_pcm_format_unsigned_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_unsigned");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_linear
+ *(void **) (&snd_pcm_format_linear_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_linear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_float
+ *(void **) (&snd_pcm_format_float_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_float");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_little_endian
+ *(void **) (&snd_pcm_format_little_endian_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_little_endian");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_big_endian
+ *(void **) (&snd_pcm_format_big_endian_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_big_endian");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_cpu_endian
+ *(void **) (&snd_pcm_format_cpu_endian_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_cpu_endian");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_width
+ *(void **) (&snd_pcm_format_width_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_width");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_physical_width
+ *(void **) (&snd_pcm_format_physical_width_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_physical_width");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_build_linear_format
+ *(void **) (&snd_pcm_build_linear_format_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_build_linear_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_size
+ *(void **) (&snd_pcm_format_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_silence
+ *(void **) (&snd_pcm_format_silence_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_silence");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_silence_16
+ *(void **) (&snd_pcm_format_silence_16_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_silence_16");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_silence_32
+ *(void **) (&snd_pcm_format_silence_32_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_silence_32");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_silence_64
+ *(void **) (&snd_pcm_format_silence_64_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_silence_64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_format_set_silence
+ *(void **) (&snd_pcm_format_set_silence_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_format_set_silence");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_bytes_to_frames
+ *(void **) (&snd_pcm_bytes_to_frames_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_bytes_to_frames");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_frames_to_bytes
+ *(void **) (&snd_pcm_frames_to_bytes_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_frames_to_bytes");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_bytes_to_samples
+ *(void **) (&snd_pcm_bytes_to_samples_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_bytes_to_samples");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_samples_to_bytes
+ *(void **) (&snd_pcm_samples_to_bytes_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_samples_to_bytes");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_area_silence
+ *(void **) (&snd_pcm_area_silence_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_area_silence");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_areas_silence
+ *(void **) (&snd_pcm_areas_silence_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_areas_silence");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_area_copy
+ *(void **) (&snd_pcm_area_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_area_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_areas_copy
+ *(void **) (&snd_pcm_areas_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_areas_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_areas_copy_wrap
+ *(void **) (&snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_areas_copy_wrap");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hook_get_pcm
+ *(void **) (&snd_pcm_hook_get_pcm_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_get_pcm");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hook_get_private
+ *(void **) (&snd_pcm_hook_get_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_get_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hook_set_private
+ *(void **) (&snd_pcm_hook_set_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_set_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hook_add
+ *(void **) (&snd_pcm_hook_add_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_add");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hook_remove
+ *(void **) (&snd_pcm_hook_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hook_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_get_bufsize
+ *(void **) (&snd_pcm_meter_get_bufsize_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_get_bufsize");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_get_channels
+ *(void **) (&snd_pcm_meter_get_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_get_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_get_rate
+ *(void **) (&snd_pcm_meter_get_rate_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_get_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_get_now
+ *(void **) (&snd_pcm_meter_get_now_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_get_now");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_get_boundary
+ *(void **) (&snd_pcm_meter_get_boundary_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_get_boundary");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_add_scope
+ *(void **) (&snd_pcm_meter_add_scope_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_add_scope");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_meter_search_scope
+ *(void **) (&snd_pcm_meter_search_scope_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_meter_search_scope");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_malloc
+ *(void **) (&snd_pcm_scope_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_set_ops
+ *(void **) (&snd_pcm_scope_set_ops_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_set_ops");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_set_name
+ *(void **) (&snd_pcm_scope_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_get_name
+ *(void **) (&snd_pcm_scope_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_get_callback_private
+ *(void **) (&snd_pcm_scope_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_set_callback_private
+ *(void **) (&snd_pcm_scope_set_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_set_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_s16_open
+ *(void **) (&snd_pcm_scope_s16_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_s16_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_scope_s16_get_channel_buffer
+ *(void **) (&snd_pcm_scope_s16_get_channel_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_scope_s16_get_channel_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_spcm_init
+ *(void **) (&snd_spcm_init_dylibloader_wrapper_asound) = dlsym(handle, "snd_spcm_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_spcm_init_duplex
+ *(void **) (&snd_spcm_init_duplex_dylibloader_wrapper_asound) = dlsym(handle, "snd_spcm_init_duplex");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_spcm_init_get_params
+ *(void **) (&snd_spcm_init_get_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_spcm_init_get_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_start_mode_name
+ *(void **) (&snd_pcm_start_mode_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_start_mode_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_xrun_mode_name
+ *(void **) (&snd_pcm_xrun_mode_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_xrun_mode_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_start_mode
+ *(void **) (&snd_pcm_sw_params_set_start_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_start_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_start_mode
+ *(void **) (&snd_pcm_sw_params_get_start_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_start_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_xrun_mode
+ *(void **) (&snd_pcm_sw_params_set_xrun_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_xrun_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_xrun_mode
+ *(void **) (&snd_pcm_sw_params_get_xrun_mode_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_xrun_mode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_xfer_align
+ *(void **) (&snd_pcm_sw_params_set_xfer_align_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_xfer_align");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_xfer_align
+ *(void **) (&snd_pcm_sw_params_get_xfer_align_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_xfer_align");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_set_sleep_min
+ *(void **) (&snd_pcm_sw_params_set_sleep_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_set_sleep_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_sw_params_get_sleep_min
+ *(void **) (&snd_pcm_sw_params_get_sleep_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_sw_params_get_sleep_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_tick_time
+ *(void **) (&snd_pcm_hw_params_get_tick_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_tick_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_tick_time_min
+ *(void **) (&snd_pcm_hw_params_get_tick_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_tick_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_get_tick_time_max
+ *(void **) (&snd_pcm_hw_params_get_tick_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_get_tick_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_test_tick_time
+ *(void **) (&snd_pcm_hw_params_test_tick_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_test_tick_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time
+ *(void **) (&snd_pcm_hw_params_set_tick_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_min
+ *(void **) (&snd_pcm_hw_params_set_tick_time_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_max
+ *(void **) (&snd_pcm_hw_params_set_tick_time_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_minmax
+ *(void **) (&snd_pcm_hw_params_set_tick_time_minmax_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_minmax");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_near
+ *(void **) (&snd_pcm_hw_params_set_tick_time_near_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_near");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_first
+ *(void **) (&snd_pcm_hw_params_set_tick_time_first_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_first");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_pcm_hw_params_set_tick_time_last
+ *(void **) (&snd_pcm_hw_params_set_tick_time_last_dylibloader_wrapper_asound) = dlsym(handle, "snd_pcm_hw_params_set_tick_time_last");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_open
+ *(void **) (&snd_rawmidi_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_open_lconf
+ *(void **) (&snd_rawmidi_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_close
+ *(void **) (&snd_rawmidi_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_poll_descriptors_count
+ *(void **) (&snd_rawmidi_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_poll_descriptors
+ *(void **) (&snd_rawmidi_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_poll_descriptors_revents
+ *(void **) (&snd_rawmidi_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_nonblock
+ *(void **) (&snd_rawmidi_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_sizeof
+ *(void **) (&snd_rawmidi_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_malloc
+ *(void **) (&snd_rawmidi_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_free
+ *(void **) (&snd_rawmidi_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_copy
+ *(void **) (&snd_rawmidi_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_device
+ *(void **) (&snd_rawmidi_info_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_subdevice
+ *(void **) (&snd_rawmidi_info_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_stream
+ *(void **) (&snd_rawmidi_info_get_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_card
+ *(void **) (&snd_rawmidi_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_flags
+ *(void **) (&snd_rawmidi_info_get_flags_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_flags");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_id
+ *(void **) (&snd_rawmidi_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_name
+ *(void **) (&snd_rawmidi_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_subdevice_name
+ *(void **) (&snd_rawmidi_info_get_subdevice_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_subdevice_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_subdevices_count
+ *(void **) (&snd_rawmidi_info_get_subdevices_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_subdevices_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_get_subdevices_avail
+ *(void **) (&snd_rawmidi_info_get_subdevices_avail_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_get_subdevices_avail");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_set_device
+ *(void **) (&snd_rawmidi_info_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_set_subdevice
+ *(void **) (&snd_rawmidi_info_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info_set_stream
+ *(void **) (&snd_rawmidi_info_set_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info_set_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_info
+ *(void **) (&snd_rawmidi_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_sizeof
+ *(void **) (&snd_rawmidi_params_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_malloc
+ *(void **) (&snd_rawmidi_params_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_free
+ *(void **) (&snd_rawmidi_params_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_copy
+ *(void **) (&snd_rawmidi_params_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_set_buffer_size
+ *(void **) (&snd_rawmidi_params_set_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_set_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_get_buffer_size
+ *(void **) (&snd_rawmidi_params_get_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_get_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_set_avail_min
+ *(void **) (&snd_rawmidi_params_set_avail_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_set_avail_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_get_avail_min
+ *(void **) (&snd_rawmidi_params_get_avail_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_get_avail_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_set_no_active_sensing
+ *(void **) (&snd_rawmidi_params_set_no_active_sensing_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_set_no_active_sensing");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_get_no_active_sensing
+ *(void **) (&snd_rawmidi_params_get_no_active_sensing_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_get_no_active_sensing");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params
+ *(void **) (&snd_rawmidi_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_params_current
+ *(void **) (&snd_rawmidi_params_current_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_params_current");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_sizeof
+ *(void **) (&snd_rawmidi_status_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_malloc
+ *(void **) (&snd_rawmidi_status_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_free
+ *(void **) (&snd_rawmidi_status_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_copy
+ *(void **) (&snd_rawmidi_status_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_get_tstamp
+ *(void **) (&snd_rawmidi_status_get_tstamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_get_tstamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_get_avail
+ *(void **) (&snd_rawmidi_status_get_avail_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_get_avail");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status_get_xruns
+ *(void **) (&snd_rawmidi_status_get_xruns_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status_get_xruns");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_status
+ *(void **) (&snd_rawmidi_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_drain
+ *(void **) (&snd_rawmidi_drain_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_drain");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_drop
+ *(void **) (&snd_rawmidi_drop_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_drop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_write
+ *(void **) (&snd_rawmidi_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_read
+ *(void **) (&snd_rawmidi_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_name
+ *(void **) (&snd_rawmidi_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_type
+ *(void **) (&snd_rawmidi_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_rawmidi_stream
+ *(void **) (&snd_rawmidi_stream_dylibloader_wrapper_asound) = dlsym(handle, "snd_rawmidi_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_open
+ *(void **) (&snd_timer_query_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_open_lconf
+ *(void **) (&snd_timer_query_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_close
+ *(void **) (&snd_timer_query_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_next_device
+ *(void **) (&snd_timer_query_next_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_next_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_info
+ *(void **) (&snd_timer_query_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_params
+ *(void **) (&snd_timer_query_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_query_status
+ *(void **) (&snd_timer_query_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_query_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_open
+ *(void **) (&snd_timer_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_open_lconf
+ *(void **) (&snd_timer_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_close
+ *(void **) (&snd_timer_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_add_timer_handler
+ *(void **) (&snd_async_add_timer_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_add_timer_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_timer
+ *(void **) (&snd_async_handler_get_timer_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_timer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_poll_descriptors_count
+ *(void **) (&snd_timer_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_poll_descriptors
+ *(void **) (&snd_timer_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_poll_descriptors_revents
+ *(void **) (&snd_timer_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info
+ *(void **) (&snd_timer_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params
+ *(void **) (&snd_timer_params_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status
+ *(void **) (&snd_timer_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_start
+ *(void **) (&snd_timer_start_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_stop
+ *(void **) (&snd_timer_stop_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_stop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_continue
+ *(void **) (&snd_timer_continue_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_continue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_read
+ *(void **) (&snd_timer_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_sizeof
+ *(void **) (&snd_timer_id_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_malloc
+ *(void **) (&snd_timer_id_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_free
+ *(void **) (&snd_timer_id_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_copy
+ *(void **) (&snd_timer_id_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_set_class
+ *(void **) (&snd_timer_id_set_class_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_set_class");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_get_class
+ *(void **) (&snd_timer_id_get_class_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_get_class");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_set_sclass
+ *(void **) (&snd_timer_id_set_sclass_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_set_sclass");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_get_sclass
+ *(void **) (&snd_timer_id_get_sclass_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_get_sclass");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_set_card
+ *(void **) (&snd_timer_id_set_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_set_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_get_card
+ *(void **) (&snd_timer_id_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_set_device
+ *(void **) (&snd_timer_id_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_get_device
+ *(void **) (&snd_timer_id_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_set_subdevice
+ *(void **) (&snd_timer_id_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_id_get_subdevice
+ *(void **) (&snd_timer_id_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_id_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_sizeof
+ *(void **) (&snd_timer_ginfo_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_malloc
+ *(void **) (&snd_timer_ginfo_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_free
+ *(void **) (&snd_timer_ginfo_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_copy
+ *(void **) (&snd_timer_ginfo_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_set_tid
+ *(void **) (&snd_timer_ginfo_set_tid_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_set_tid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_tid
+ *(void **) (&snd_timer_ginfo_get_tid_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_tid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_flags
+ *(void **) (&snd_timer_ginfo_get_flags_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_flags");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_card
+ *(void **) (&snd_timer_ginfo_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_id
+ *(void **) (&snd_timer_ginfo_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_name
+ *(void **) (&snd_timer_ginfo_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_resolution
+ *(void **) (&snd_timer_ginfo_get_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_resolution_min
+ *(void **) (&snd_timer_ginfo_get_resolution_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_resolution_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_resolution_max
+ *(void **) (&snd_timer_ginfo_get_resolution_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_resolution_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_ginfo_get_clients
+ *(void **) (&snd_timer_ginfo_get_clients_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_ginfo_get_clients");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_sizeof
+ *(void **) (&snd_timer_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_malloc
+ *(void **) (&snd_timer_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_free
+ *(void **) (&snd_timer_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_copy
+ *(void **) (&snd_timer_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_is_slave
+ *(void **) (&snd_timer_info_is_slave_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_is_slave");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_get_card
+ *(void **) (&snd_timer_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_get_id
+ *(void **) (&snd_timer_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_get_name
+ *(void **) (&snd_timer_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_get_resolution
+ *(void **) (&snd_timer_info_get_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_get_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_sizeof
+ *(void **) (&snd_timer_params_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_malloc
+ *(void **) (&snd_timer_params_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_free
+ *(void **) (&snd_timer_params_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_copy
+ *(void **) (&snd_timer_params_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_auto_start
+ *(void **) (&snd_timer_params_set_auto_start_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_auto_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_auto_start
+ *(void **) (&snd_timer_params_get_auto_start_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_auto_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_exclusive
+ *(void **) (&snd_timer_params_set_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_exclusive
+ *(void **) (&snd_timer_params_get_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_early_event
+ *(void **) (&snd_timer_params_set_early_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_early_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_early_event
+ *(void **) (&snd_timer_params_get_early_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_early_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_ticks
+ *(void **) (&snd_timer_params_set_ticks_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_ticks");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_ticks
+ *(void **) (&snd_timer_params_get_ticks_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_ticks");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_queue_size
+ *(void **) (&snd_timer_params_set_queue_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_queue_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_queue_size
+ *(void **) (&snd_timer_params_get_queue_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_queue_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_set_filter
+ *(void **) (&snd_timer_params_set_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_set_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_params_get_filter
+ *(void **) (&snd_timer_params_get_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_params_get_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_sizeof
+ *(void **) (&snd_timer_status_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_malloc
+ *(void **) (&snd_timer_status_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_free
+ *(void **) (&snd_timer_status_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_copy
+ *(void **) (&snd_timer_status_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_get_timestamp
+ *(void **) (&snd_timer_status_get_timestamp_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_get_timestamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_get_resolution
+ *(void **) (&snd_timer_status_get_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_get_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_get_lost
+ *(void **) (&snd_timer_status_get_lost_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_get_lost");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_get_overrun
+ *(void **) (&snd_timer_status_get_overrun_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_get_overrun");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_status_get_queue
+ *(void **) (&snd_timer_status_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_status_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_timer_info_get_ticks
+ *(void **) (&snd_timer_info_get_ticks_dylibloader_wrapper_asound) = dlsym(handle, "snd_timer_info_get_ticks");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_open
+ *(void **) (&snd_hwdep_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_close
+ *(void **) (&snd_hwdep_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_poll_descriptors
+ *(void **) (&snd_hwdep_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_poll_descriptors_count
+ *(void **) (&snd_hwdep_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_poll_descriptors_revents
+ *(void **) (&snd_hwdep_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_nonblock
+ *(void **) (&snd_hwdep_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info
+ *(void **) (&snd_hwdep_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status
+ *(void **) (&snd_hwdep_dsp_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_load
+ *(void **) (&snd_hwdep_dsp_load_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_ioctl
+ *(void **) (&snd_hwdep_ioctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_ioctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_write
+ *(void **) (&snd_hwdep_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_read
+ *(void **) (&snd_hwdep_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_sizeof
+ *(void **) (&snd_hwdep_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_malloc
+ *(void **) (&snd_hwdep_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_free
+ *(void **) (&snd_hwdep_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_copy
+ *(void **) (&snd_hwdep_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_get_device
+ *(void **) (&snd_hwdep_info_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_get_card
+ *(void **) (&snd_hwdep_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_get_id
+ *(void **) (&snd_hwdep_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_get_name
+ *(void **) (&snd_hwdep_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_get_iface
+ *(void **) (&snd_hwdep_info_get_iface_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_get_iface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_info_set_device
+ *(void **) (&snd_hwdep_info_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_info_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_sizeof
+ *(void **) (&snd_hwdep_dsp_status_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_malloc
+ *(void **) (&snd_hwdep_dsp_status_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_free
+ *(void **) (&snd_hwdep_dsp_status_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_copy
+ *(void **) (&snd_hwdep_dsp_status_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_get_version
+ *(void **) (&snd_hwdep_dsp_status_get_version_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_get_version");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_get_id
+ *(void **) (&snd_hwdep_dsp_status_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_get_num_dsps
+ *(void **) (&snd_hwdep_dsp_status_get_num_dsps_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_get_num_dsps");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_get_dsp_loaded
+ *(void **) (&snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_get_dsp_loaded");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_status_get_chip_ready
+ *(void **) (&snd_hwdep_dsp_status_get_chip_ready_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_status_get_chip_ready");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_sizeof
+ *(void **) (&snd_hwdep_dsp_image_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_malloc
+ *(void **) (&snd_hwdep_dsp_image_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_free
+ *(void **) (&snd_hwdep_dsp_image_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_copy
+ *(void **) (&snd_hwdep_dsp_image_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_get_index
+ *(void **) (&snd_hwdep_dsp_image_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_get_name
+ *(void **) (&snd_hwdep_dsp_image_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_get_image
+ *(void **) (&snd_hwdep_dsp_image_get_image_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_get_image");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_get_length
+ *(void **) (&snd_hwdep_dsp_image_get_length_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_get_length");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_set_index
+ *(void **) (&snd_hwdep_dsp_image_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_set_name
+ *(void **) (&snd_hwdep_dsp_image_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_set_image
+ *(void **) (&snd_hwdep_dsp_image_set_image_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_set_image");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hwdep_dsp_image_set_length
+ *(void **) (&snd_hwdep_dsp_image_set_length_dylibloader_wrapper_asound) = dlsym(handle, "snd_hwdep_dsp_image_set_length");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_card_load
+ *(void **) (&snd_card_load_dylibloader_wrapper_asound) = dlsym(handle, "snd_card_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_card_next
+ *(void **) (&snd_card_next_dylibloader_wrapper_asound) = dlsym(handle, "snd_card_next");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_card_get_index
+ *(void **) (&snd_card_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_card_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_card_get_name
+ *(void **) (&snd_card_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_card_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_card_get_longname
+ *(void **) (&snd_card_get_longname_dylibloader_wrapper_asound) = dlsym(handle, "snd_card_get_longname");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_device_name_hint
+ *(void **) (&snd_device_name_hint_dylibloader_wrapper_asound) = dlsym(handle, "snd_device_name_hint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_device_name_free_hint
+ *(void **) (&snd_device_name_free_hint_dylibloader_wrapper_asound) = dlsym(handle, "snd_device_name_free_hint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_device_name_get_hint
+ *(void **) (&snd_device_name_get_hint_dylibloader_wrapper_asound) = dlsym(handle, "snd_device_name_get_hint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_open
+ *(void **) (&snd_ctl_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_open_lconf
+ *(void **) (&snd_ctl_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_open_fallback
+ *(void **) (&snd_ctl_open_fallback_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_open_fallback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_close
+ *(void **) (&snd_ctl_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_nonblock
+ *(void **) (&snd_ctl_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_add_ctl_handler
+ *(void **) (&snd_async_add_ctl_handler_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_add_ctl_handler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_async_handler_get_ctl
+ *(void **) (&snd_async_handler_get_ctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_async_handler_get_ctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_poll_descriptors_count
+ *(void **) (&snd_ctl_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_poll_descriptors
+ *(void **) (&snd_ctl_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_poll_descriptors_revents
+ *(void **) (&snd_ctl_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_subscribe_events
+ *(void **) (&snd_ctl_subscribe_events_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_subscribe_events");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info
+ *(void **) (&snd_ctl_card_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list
+ *(void **) (&snd_ctl_elem_list_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info
+ *(void **) (&snd_ctl_elem_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_read
+ *(void **) (&snd_ctl_elem_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_write
+ *(void **) (&snd_ctl_elem_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_lock
+ *(void **) (&snd_ctl_elem_lock_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_lock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_unlock
+ *(void **) (&snd_ctl_elem_unlock_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_unlock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_tlv_read
+ *(void **) (&snd_ctl_elem_tlv_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_tlv_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_tlv_write
+ *(void **) (&snd_ctl_elem_tlv_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_tlv_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_tlv_command
+ *(void **) (&snd_ctl_elem_tlv_command_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_tlv_command");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_hwdep_next_device
+ *(void **) (&snd_ctl_hwdep_next_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_hwdep_next_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_hwdep_info
+ *(void **) (&snd_ctl_hwdep_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_hwdep_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_pcm_next_device
+ *(void **) (&snd_ctl_pcm_next_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_pcm_next_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_pcm_info
+ *(void **) (&snd_ctl_pcm_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_pcm_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_pcm_prefer_subdevice
+ *(void **) (&snd_ctl_pcm_prefer_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_pcm_prefer_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_rawmidi_next_device
+ *(void **) (&snd_ctl_rawmidi_next_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_rawmidi_next_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_rawmidi_info
+ *(void **) (&snd_ctl_rawmidi_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_rawmidi_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_rawmidi_prefer_subdevice
+ *(void **) (&snd_ctl_rawmidi_prefer_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_rawmidi_prefer_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_set_power_state
+ *(void **) (&snd_ctl_set_power_state_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_set_power_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_get_power_state
+ *(void **) (&snd_ctl_get_power_state_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_get_power_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_read
+ *(void **) (&snd_ctl_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_wait
+ *(void **) (&snd_ctl_wait_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_wait");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_name
+ *(void **) (&snd_ctl_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_type
+ *(void **) (&snd_ctl_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_type_name
+ *(void **) (&snd_ctl_elem_type_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_type_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_iface_name
+ *(void **) (&snd_ctl_elem_iface_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_iface_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_type_name
+ *(void **) (&snd_ctl_event_type_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_type_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_mask
+ *(void **) (&snd_ctl_event_elem_get_mask_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_numid
+ *(void **) (&snd_ctl_event_elem_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_id
+ *(void **) (&snd_ctl_event_elem_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_interface
+ *(void **) (&snd_ctl_event_elem_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_device
+ *(void **) (&snd_ctl_event_elem_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_subdevice
+ *(void **) (&snd_ctl_event_elem_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_name
+ *(void **) (&snd_ctl_event_elem_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_elem_get_index
+ *(void **) (&snd_ctl_event_elem_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_elem_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_alloc_space
+ *(void **) (&snd_ctl_elem_list_alloc_space_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_alloc_space");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_free_space
+ *(void **) (&snd_ctl_elem_list_free_space_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_free_space");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_ascii_elem_id_get
+ *(void **) (&snd_ctl_ascii_elem_id_get_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_ascii_elem_id_get");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_ascii_elem_id_parse
+ *(void **) (&snd_ctl_ascii_elem_id_parse_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_ascii_elem_id_parse");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_ascii_value_parse
+ *(void **) (&snd_ctl_ascii_value_parse_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_ascii_value_parse");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_sizeof
+ *(void **) (&snd_ctl_elem_id_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_malloc
+ *(void **) (&snd_ctl_elem_id_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_free
+ *(void **) (&snd_ctl_elem_id_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_clear
+ *(void **) (&snd_ctl_elem_id_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_copy
+ *(void **) (&snd_ctl_elem_id_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_numid
+ *(void **) (&snd_ctl_elem_id_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_interface
+ *(void **) (&snd_ctl_elem_id_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_device
+ *(void **) (&snd_ctl_elem_id_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_subdevice
+ *(void **) (&snd_ctl_elem_id_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_name
+ *(void **) (&snd_ctl_elem_id_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_get_index
+ *(void **) (&snd_ctl_elem_id_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_numid
+ *(void **) (&snd_ctl_elem_id_set_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_interface
+ *(void **) (&snd_ctl_elem_id_set_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_device
+ *(void **) (&snd_ctl_elem_id_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_subdevice
+ *(void **) (&snd_ctl_elem_id_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_name
+ *(void **) (&snd_ctl_elem_id_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_id_set_index
+ *(void **) (&snd_ctl_elem_id_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_id_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_sizeof
+ *(void **) (&snd_ctl_card_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_malloc
+ *(void **) (&snd_ctl_card_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_free
+ *(void **) (&snd_ctl_card_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_clear
+ *(void **) (&snd_ctl_card_info_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_copy
+ *(void **) (&snd_ctl_card_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_card
+ *(void **) (&snd_ctl_card_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_id
+ *(void **) (&snd_ctl_card_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_driver
+ *(void **) (&snd_ctl_card_info_get_driver_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_driver");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_name
+ *(void **) (&snd_ctl_card_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_longname
+ *(void **) (&snd_ctl_card_info_get_longname_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_longname");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_mixername
+ *(void **) (&snd_ctl_card_info_get_mixername_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_mixername");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_card_info_get_components
+ *(void **) (&snd_ctl_card_info_get_components_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_card_info_get_components");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_sizeof
+ *(void **) (&snd_ctl_event_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_malloc
+ *(void **) (&snd_ctl_event_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_free
+ *(void **) (&snd_ctl_event_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_clear
+ *(void **) (&snd_ctl_event_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_copy
+ *(void **) (&snd_ctl_event_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_event_get_type
+ *(void **) (&snd_ctl_event_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_event_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_sizeof
+ *(void **) (&snd_ctl_elem_list_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_malloc
+ *(void **) (&snd_ctl_elem_list_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_free
+ *(void **) (&snd_ctl_elem_list_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_clear
+ *(void **) (&snd_ctl_elem_list_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_copy
+ *(void **) (&snd_ctl_elem_list_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_set_offset
+ *(void **) (&snd_ctl_elem_list_set_offset_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_set_offset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_used
+ *(void **) (&snd_ctl_elem_list_get_used_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_used");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_count
+ *(void **) (&snd_ctl_elem_list_get_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_id
+ *(void **) (&snd_ctl_elem_list_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_numid
+ *(void **) (&snd_ctl_elem_list_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_interface
+ *(void **) (&snd_ctl_elem_list_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_device
+ *(void **) (&snd_ctl_elem_list_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_subdevice
+ *(void **) (&snd_ctl_elem_list_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_name
+ *(void **) (&snd_ctl_elem_list_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_list_get_index
+ *(void **) (&snd_ctl_elem_list_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_list_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_sizeof
+ *(void **) (&snd_ctl_elem_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_malloc
+ *(void **) (&snd_ctl_elem_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_free
+ *(void **) (&snd_ctl_elem_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_clear
+ *(void **) (&snd_ctl_elem_info_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_copy
+ *(void **) (&snd_ctl_elem_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_type
+ *(void **) (&snd_ctl_elem_info_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_readable
+ *(void **) (&snd_ctl_elem_info_is_readable_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_readable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_writable
+ *(void **) (&snd_ctl_elem_info_is_writable_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_writable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_volatile
+ *(void **) (&snd_ctl_elem_info_is_volatile_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_volatile");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_inactive
+ *(void **) (&snd_ctl_elem_info_is_inactive_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_inactive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_locked
+ *(void **) (&snd_ctl_elem_info_is_locked_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_locked");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_tlv_readable
+ *(void **) (&snd_ctl_elem_info_is_tlv_readable_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_tlv_readable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_tlv_writable
+ *(void **) (&snd_ctl_elem_info_is_tlv_writable_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_tlv_writable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_tlv_commandable
+ *(void **) (&snd_ctl_elem_info_is_tlv_commandable_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_tlv_commandable");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_owner
+ *(void **) (&snd_ctl_elem_info_is_owner_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_owner");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_is_user
+ *(void **) (&snd_ctl_elem_info_is_user_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_is_user");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_owner
+ *(void **) (&snd_ctl_elem_info_get_owner_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_owner");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_count
+ *(void **) (&snd_ctl_elem_info_get_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_min
+ *(void **) (&snd_ctl_elem_info_get_min_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_max
+ *(void **) (&snd_ctl_elem_info_get_max_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_step
+ *(void **) (&snd_ctl_elem_info_get_step_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_step");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_min64
+ *(void **) (&snd_ctl_elem_info_get_min64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_min64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_max64
+ *(void **) (&snd_ctl_elem_info_get_max64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_max64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_step64
+ *(void **) (&snd_ctl_elem_info_get_step64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_step64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_items
+ *(void **) (&snd_ctl_elem_info_get_items_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_items");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_item
+ *(void **) (&snd_ctl_elem_info_set_item_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_item");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_item_name
+ *(void **) (&snd_ctl_elem_info_get_item_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_item_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_dimensions
+ *(void **) (&snd_ctl_elem_info_get_dimensions_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_dimensions");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_dimension
+ *(void **) (&snd_ctl_elem_info_get_dimension_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_dimension");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_dimension
+ *(void **) (&snd_ctl_elem_info_set_dimension_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_dimension");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_id
+ *(void **) (&snd_ctl_elem_info_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_numid
+ *(void **) (&snd_ctl_elem_info_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_interface
+ *(void **) (&snd_ctl_elem_info_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_device
+ *(void **) (&snd_ctl_elem_info_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_subdevice
+ *(void **) (&snd_ctl_elem_info_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_name
+ *(void **) (&snd_ctl_elem_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_get_index
+ *(void **) (&snd_ctl_elem_info_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_id
+ *(void **) (&snd_ctl_elem_info_set_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_numid
+ *(void **) (&snd_ctl_elem_info_set_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_interface
+ *(void **) (&snd_ctl_elem_info_set_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_device
+ *(void **) (&snd_ctl_elem_info_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_subdevice
+ *(void **) (&snd_ctl_elem_info_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_name
+ *(void **) (&snd_ctl_elem_info_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_info_set_index
+ *(void **) (&snd_ctl_elem_info_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_info_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_add_integer_elem_set
+ *(void **) (&snd_ctl_add_integer_elem_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_add_integer_elem_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_add_integer64_elem_set
+ *(void **) (&snd_ctl_add_integer64_elem_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_add_integer64_elem_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_add_boolean_elem_set
+ *(void **) (&snd_ctl_add_boolean_elem_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_add_boolean_elem_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_add_enumerated_elem_set
+ *(void **) (&snd_ctl_add_enumerated_elem_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_add_enumerated_elem_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_add_bytes_elem_set
+ *(void **) (&snd_ctl_add_bytes_elem_set_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_add_bytes_elem_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_add_integer
+ *(void **) (&snd_ctl_elem_add_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_add_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_add_integer64
+ *(void **) (&snd_ctl_elem_add_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_add_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_add_boolean
+ *(void **) (&snd_ctl_elem_add_boolean_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_add_boolean");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_add_enumerated
+ *(void **) (&snd_ctl_elem_add_enumerated_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_add_enumerated");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_add_iec958
+ *(void **) (&snd_ctl_elem_add_iec958_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_add_iec958");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_remove
+ *(void **) (&snd_ctl_elem_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_sizeof
+ *(void **) (&snd_ctl_elem_value_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_malloc
+ *(void **) (&snd_ctl_elem_value_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_free
+ *(void **) (&snd_ctl_elem_value_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_clear
+ *(void **) (&snd_ctl_elem_value_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_copy
+ *(void **) (&snd_ctl_elem_value_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_compare
+ *(void **) (&snd_ctl_elem_value_compare_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_compare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_id
+ *(void **) (&snd_ctl_elem_value_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_numid
+ *(void **) (&snd_ctl_elem_value_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_interface
+ *(void **) (&snd_ctl_elem_value_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_device
+ *(void **) (&snd_ctl_elem_value_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_subdevice
+ *(void **) (&snd_ctl_elem_value_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_name
+ *(void **) (&snd_ctl_elem_value_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_index
+ *(void **) (&snd_ctl_elem_value_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_id
+ *(void **) (&snd_ctl_elem_value_set_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_numid
+ *(void **) (&snd_ctl_elem_value_set_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_interface
+ *(void **) (&snd_ctl_elem_value_set_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_device
+ *(void **) (&snd_ctl_elem_value_set_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_subdevice
+ *(void **) (&snd_ctl_elem_value_set_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_name
+ *(void **) (&snd_ctl_elem_value_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_index
+ *(void **) (&snd_ctl_elem_value_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_boolean
+ *(void **) (&snd_ctl_elem_value_get_boolean_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_boolean");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_integer
+ *(void **) (&snd_ctl_elem_value_get_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_integer64
+ *(void **) (&snd_ctl_elem_value_get_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_enumerated
+ *(void **) (&snd_ctl_elem_value_get_enumerated_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_enumerated");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_byte
+ *(void **) (&snd_ctl_elem_value_get_byte_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_byte");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_boolean
+ *(void **) (&snd_ctl_elem_value_set_boolean_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_boolean");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_integer
+ *(void **) (&snd_ctl_elem_value_set_integer_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_integer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_integer64
+ *(void **) (&snd_ctl_elem_value_set_integer64_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_integer64");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_enumerated
+ *(void **) (&snd_ctl_elem_value_set_enumerated_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_enumerated");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_byte
+ *(void **) (&snd_ctl_elem_value_set_byte_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_byte");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_set_bytes
+ *(void **) (&snd_ctl_elem_set_bytes_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_set_bytes");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_bytes
+ *(void **) (&snd_ctl_elem_value_get_bytes_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_bytes");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_get_iec958
+ *(void **) (&snd_ctl_elem_value_get_iec958_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_get_iec958");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_elem_value_set_iec958
+ *(void **) (&snd_ctl_elem_value_set_iec958_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_elem_value_set_iec958");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_tlv_parse_dB_info
+ *(void **) (&snd_tlv_parse_dB_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_tlv_parse_dB_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_tlv_get_dB_range
+ *(void **) (&snd_tlv_get_dB_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_tlv_get_dB_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_tlv_convert_to_dB
+ *(void **) (&snd_tlv_convert_to_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_tlv_convert_to_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_tlv_convert_from_dB
+ *(void **) (&snd_tlv_convert_from_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_tlv_convert_from_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_get_dB_range
+ *(void **) (&snd_ctl_get_dB_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_get_dB_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_convert_to_dB
+ *(void **) (&snd_ctl_convert_to_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_convert_to_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_ctl_convert_from_dB
+ *(void **) (&snd_ctl_convert_from_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_ctl_convert_from_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_compare_fast
+ *(void **) (&snd_hctl_compare_fast_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_compare_fast");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_open
+ *(void **) (&snd_hctl_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_open_ctl
+ *(void **) (&snd_hctl_open_ctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_open_ctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_close
+ *(void **) (&snd_hctl_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_nonblock
+ *(void **) (&snd_hctl_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_poll_descriptors_count
+ *(void **) (&snd_hctl_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_poll_descriptors
+ *(void **) (&snd_hctl_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_poll_descriptors_revents
+ *(void **) (&snd_hctl_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_get_count
+ *(void **) (&snd_hctl_get_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_get_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_set_compare
+ *(void **) (&snd_hctl_set_compare_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_set_compare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_first_elem
+ *(void **) (&snd_hctl_first_elem_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_first_elem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_last_elem
+ *(void **) (&snd_hctl_last_elem_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_last_elem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_find_elem
+ *(void **) (&snd_hctl_find_elem_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_find_elem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_set_callback
+ *(void **) (&snd_hctl_set_callback_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_set_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_set_callback_private
+ *(void **) (&snd_hctl_set_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_set_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_get_callback_private
+ *(void **) (&snd_hctl_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_load
+ *(void **) (&snd_hctl_load_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_free
+ *(void **) (&snd_hctl_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_handle_events
+ *(void **) (&snd_hctl_handle_events_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_handle_events");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_name
+ *(void **) (&snd_hctl_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_wait
+ *(void **) (&snd_hctl_wait_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_wait");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_ctl
+ *(void **) (&snd_hctl_ctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_ctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_next
+ *(void **) (&snd_hctl_elem_next_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_next");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_prev
+ *(void **) (&snd_hctl_elem_prev_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_prev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_info
+ *(void **) (&snd_hctl_elem_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_read
+ *(void **) (&snd_hctl_elem_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_write
+ *(void **) (&snd_hctl_elem_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_tlv_read
+ *(void **) (&snd_hctl_elem_tlv_read_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_tlv_read");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_tlv_write
+ *(void **) (&snd_hctl_elem_tlv_write_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_tlv_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_tlv_command
+ *(void **) (&snd_hctl_elem_tlv_command_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_tlv_command");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_hctl
+ *(void **) (&snd_hctl_elem_get_hctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_hctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_id
+ *(void **) (&snd_hctl_elem_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_numid
+ *(void **) (&snd_hctl_elem_get_numid_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_numid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_interface
+ *(void **) (&snd_hctl_elem_get_interface_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_interface");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_device
+ *(void **) (&snd_hctl_elem_get_device_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_subdevice
+ *(void **) (&snd_hctl_elem_get_subdevice_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_subdevice");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_name
+ *(void **) (&snd_hctl_elem_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_index
+ *(void **) (&snd_hctl_elem_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_set_callback
+ *(void **) (&snd_hctl_elem_set_callback_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_set_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_get_callback_private
+ *(void **) (&snd_hctl_elem_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_hctl_elem_set_callback_private
+ *(void **) (&snd_hctl_elem_set_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_hctl_elem_set_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_sctl_build
+ *(void **) (&snd_sctl_build_dylibloader_wrapper_asound) = dlsym(handle, "snd_sctl_build");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_sctl_free
+ *(void **) (&snd_sctl_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_sctl_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_sctl_install
+ *(void **) (&snd_sctl_install_dylibloader_wrapper_asound) = dlsym(handle, "snd_sctl_install");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_sctl_remove
+ *(void **) (&snd_sctl_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_sctl_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_open
+ *(void **) (&snd_mixer_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_close
+ *(void **) (&snd_mixer_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_first_elem
+ *(void **) (&snd_mixer_first_elem_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_first_elem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_last_elem
+ *(void **) (&snd_mixer_last_elem_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_last_elem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_handle_events
+ *(void **) (&snd_mixer_handle_events_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_handle_events");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_attach
+ *(void **) (&snd_mixer_attach_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_attach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_attach_hctl
+ *(void **) (&snd_mixer_attach_hctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_attach_hctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_detach
+ *(void **) (&snd_mixer_detach_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_detach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_detach_hctl
+ *(void **) (&snd_mixer_detach_hctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_detach_hctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_get_hctl
+ *(void **) (&snd_mixer_get_hctl_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_get_hctl");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_poll_descriptors_count
+ *(void **) (&snd_mixer_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_poll_descriptors
+ *(void **) (&snd_mixer_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_poll_descriptors_revents
+ *(void **) (&snd_mixer_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_load
+ *(void **) (&snd_mixer_load_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_free
+ *(void **) (&snd_mixer_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_wait
+ *(void **) (&snd_mixer_wait_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_wait");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_set_compare
+ *(void **) (&snd_mixer_set_compare_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_set_compare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_set_callback
+ *(void **) (&snd_mixer_set_callback_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_set_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_get_callback_private
+ *(void **) (&snd_mixer_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_set_callback_private
+ *(void **) (&snd_mixer_set_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_set_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_get_count
+ *(void **) (&snd_mixer_get_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_get_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_unregister
+ *(void **) (&snd_mixer_class_unregister_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_unregister");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_next
+ *(void **) (&snd_mixer_elem_next_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_next");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_prev
+ *(void **) (&snd_mixer_elem_prev_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_prev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_set_callback
+ *(void **) (&snd_mixer_elem_set_callback_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_set_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_get_callback_private
+ *(void **) (&snd_mixer_elem_get_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_get_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_set_callback_private
+ *(void **) (&snd_mixer_elem_set_callback_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_set_callback_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_get_type
+ *(void **) (&snd_mixer_elem_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_register
+ *(void **) (&snd_mixer_class_register_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_register");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_new
+ *(void **) (&snd_mixer_elem_new_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_add
+ *(void **) (&snd_mixer_elem_add_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_add");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_remove
+ *(void **) (&snd_mixer_elem_remove_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_free
+ *(void **) (&snd_mixer_elem_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_info
+ *(void **) (&snd_mixer_elem_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_value
+ *(void **) (&snd_mixer_elem_value_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_attach
+ *(void **) (&snd_mixer_elem_attach_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_attach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_detach
+ *(void **) (&snd_mixer_elem_detach_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_detach");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_empty
+ *(void **) (&snd_mixer_elem_empty_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_empty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_elem_get_private
+ *(void **) (&snd_mixer_elem_get_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_elem_get_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_sizeof
+ *(void **) (&snd_mixer_class_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_malloc
+ *(void **) (&snd_mixer_class_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_free
+ *(void **) (&snd_mixer_class_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_copy
+ *(void **) (&snd_mixer_class_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_get_mixer
+ *(void **) (&snd_mixer_class_get_mixer_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_get_mixer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_get_event
+ *(void **) (&snd_mixer_class_get_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_get_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_get_private
+ *(void **) (&snd_mixer_class_get_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_get_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_get_compare
+ *(void **) (&snd_mixer_class_get_compare_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_get_compare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_set_event
+ *(void **) (&snd_mixer_class_set_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_set_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_set_private
+ *(void **) (&snd_mixer_class_set_private_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_set_private");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_set_private_free
+ *(void **) (&snd_mixer_class_set_private_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_set_private_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_class_set_compare
+ *(void **) (&snd_mixer_class_set_compare_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_class_set_compare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_channel_name
+ *(void **) (&snd_mixer_selem_channel_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_channel_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_register
+ *(void **) (&snd_mixer_selem_register_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_register");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_id
+ *(void **) (&snd_mixer_selem_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_name
+ *(void **) (&snd_mixer_selem_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_index
+ *(void **) (&snd_mixer_selem_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_find_selem
+ *(void **) (&snd_mixer_find_selem_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_find_selem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_active
+ *(void **) (&snd_mixer_selem_is_active_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_playback_mono
+ *(void **) (&snd_mixer_selem_is_playback_mono_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_playback_mono");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_playback_channel
+ *(void **) (&snd_mixer_selem_has_playback_channel_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_playback_channel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_capture_mono
+ *(void **) (&snd_mixer_selem_is_capture_mono_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_capture_mono");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_channel
+ *(void **) (&snd_mixer_selem_has_capture_channel_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_channel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_group
+ *(void **) (&snd_mixer_selem_get_capture_group_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_group");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_common_volume
+ *(void **) (&snd_mixer_selem_has_common_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_common_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_playback_volume
+ *(void **) (&snd_mixer_selem_has_playback_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_playback_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_playback_volume_joined
+ *(void **) (&snd_mixer_selem_has_playback_volume_joined_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_playback_volume_joined");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_volume
+ *(void **) (&snd_mixer_selem_has_capture_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_volume_joined
+ *(void **) (&snd_mixer_selem_has_capture_volume_joined_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_volume_joined");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_common_switch
+ *(void **) (&snd_mixer_selem_has_common_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_common_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_playback_switch
+ *(void **) (&snd_mixer_selem_has_playback_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_playback_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_playback_switch_joined
+ *(void **) (&snd_mixer_selem_has_playback_switch_joined_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_playback_switch_joined");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_switch
+ *(void **) (&snd_mixer_selem_has_capture_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_switch_joined
+ *(void **) (&snd_mixer_selem_has_capture_switch_joined_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_switch_joined");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_has_capture_switch_exclusive
+ *(void **) (&snd_mixer_selem_has_capture_switch_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_has_capture_switch_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_ask_playback_vol_dB
+ *(void **) (&snd_mixer_selem_ask_playback_vol_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_ask_playback_vol_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_ask_capture_vol_dB
+ *(void **) (&snd_mixer_selem_ask_capture_vol_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_ask_capture_vol_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_ask_playback_dB_vol
+ *(void **) (&snd_mixer_selem_ask_playback_dB_vol_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_ask_playback_dB_vol");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_ask_capture_dB_vol
+ *(void **) (&snd_mixer_selem_ask_capture_dB_vol_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_ask_capture_dB_vol");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_playback_volume
+ *(void **) (&snd_mixer_selem_get_playback_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_playback_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_volume
+ *(void **) (&snd_mixer_selem_get_capture_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_playback_dB
+ *(void **) (&snd_mixer_selem_get_playback_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_playback_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_dB
+ *(void **) (&snd_mixer_selem_get_capture_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_playback_switch
+ *(void **) (&snd_mixer_selem_get_playback_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_playback_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_switch
+ *(void **) (&snd_mixer_selem_get_capture_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_volume
+ *(void **) (&snd_mixer_selem_set_playback_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_volume
+ *(void **) (&snd_mixer_selem_set_capture_volume_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_dB
+ *(void **) (&snd_mixer_selem_set_playback_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_dB
+ *(void **) (&snd_mixer_selem_set_capture_dB_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_volume_all
+ *(void **) (&snd_mixer_selem_set_playback_volume_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_volume_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_volume_all
+ *(void **) (&snd_mixer_selem_set_capture_volume_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_volume_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_dB_all
+ *(void **) (&snd_mixer_selem_set_playback_dB_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_dB_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_dB_all
+ *(void **) (&snd_mixer_selem_set_capture_dB_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_dB_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_switch
+ *(void **) (&snd_mixer_selem_set_playback_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_switch
+ *(void **) (&snd_mixer_selem_set_capture_switch_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_switch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_switch_all
+ *(void **) (&snd_mixer_selem_set_playback_switch_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_switch_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_switch_all
+ *(void **) (&snd_mixer_selem_set_capture_switch_all_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_switch_all");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_playback_volume_range
+ *(void **) (&snd_mixer_selem_get_playback_volume_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_playback_volume_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_playback_dB_range
+ *(void **) (&snd_mixer_selem_get_playback_dB_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_playback_dB_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_playback_volume_range
+ *(void **) (&snd_mixer_selem_set_playback_volume_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_playback_volume_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_volume_range
+ *(void **) (&snd_mixer_selem_get_capture_volume_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_volume_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_capture_dB_range
+ *(void **) (&snd_mixer_selem_get_capture_dB_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_capture_dB_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_capture_volume_range
+ *(void **) (&snd_mixer_selem_set_capture_volume_range_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_capture_volume_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_enumerated
+ *(void **) (&snd_mixer_selem_is_enumerated_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_enumerated");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_enum_playback
+ *(void **) (&snd_mixer_selem_is_enum_playback_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_enum_playback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_is_enum_capture
+ *(void **) (&snd_mixer_selem_is_enum_capture_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_is_enum_capture");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_enum_items
+ *(void **) (&snd_mixer_selem_get_enum_items_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_enum_items");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_enum_item_name
+ *(void **) (&snd_mixer_selem_get_enum_item_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_enum_item_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_get_enum_item
+ *(void **) (&snd_mixer_selem_get_enum_item_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_get_enum_item");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_set_enum_item
+ *(void **) (&snd_mixer_selem_set_enum_item_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_set_enum_item");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_sizeof
+ *(void **) (&snd_mixer_selem_id_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_malloc
+ *(void **) (&snd_mixer_selem_id_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_free
+ *(void **) (&snd_mixer_selem_id_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_copy
+ *(void **) (&snd_mixer_selem_id_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_get_name
+ *(void **) (&snd_mixer_selem_id_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_get_index
+ *(void **) (&snd_mixer_selem_id_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_set_name
+ *(void **) (&snd_mixer_selem_id_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_set_index
+ *(void **) (&snd_mixer_selem_id_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_mixer_selem_id_parse
+ *(void **) (&snd_mixer_selem_id_parse_dylibloader_wrapper_asound) = dlsym(handle, "snd_mixer_selem_id_parse");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_open
+ *(void **) (&snd_seq_open_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_open");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_open_lconf
+ *(void **) (&snd_seq_open_lconf_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_open_lconf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_name
+ *(void **) (&snd_seq_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_type
+ *(void **) (&snd_seq_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_close
+ *(void **) (&snd_seq_close_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_close");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_poll_descriptors_count
+ *(void **) (&snd_seq_poll_descriptors_count_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_poll_descriptors_count");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_poll_descriptors
+ *(void **) (&snd_seq_poll_descriptors_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_poll_descriptors");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_poll_descriptors_revents
+ *(void **) (&snd_seq_poll_descriptors_revents_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_poll_descriptors_revents");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_nonblock
+ *(void **) (&snd_seq_nonblock_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_nonblock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_id
+ *(void **) (&snd_seq_client_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_output_buffer_size
+ *(void **) (&snd_seq_get_output_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_output_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_input_buffer_size
+ *(void **) (&snd_seq_get_input_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_input_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_output_buffer_size
+ *(void **) (&snd_seq_set_output_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_output_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_input_buffer_size
+ *(void **) (&snd_seq_set_input_buffer_size_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_input_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_sizeof
+ *(void **) (&snd_seq_system_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_malloc
+ *(void **) (&snd_seq_system_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_free
+ *(void **) (&snd_seq_system_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_copy
+ *(void **) (&snd_seq_system_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_queues
+ *(void **) (&snd_seq_system_info_get_queues_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_queues");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_clients
+ *(void **) (&snd_seq_system_info_get_clients_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_clients");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_ports
+ *(void **) (&snd_seq_system_info_get_ports_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_ports");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_channels
+ *(void **) (&snd_seq_system_info_get_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_cur_clients
+ *(void **) (&snd_seq_system_info_get_cur_clients_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_cur_clients");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info_get_cur_queues
+ *(void **) (&snd_seq_system_info_get_cur_queues_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info_get_cur_queues");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_system_info
+ *(void **) (&snd_seq_system_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_system_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_sizeof
+ *(void **) (&snd_seq_client_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_malloc
+ *(void **) (&snd_seq_client_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_free
+ *(void **) (&snd_seq_client_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_copy
+ *(void **) (&snd_seq_client_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_client
+ *(void **) (&snd_seq_client_info_get_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_type
+ *(void **) (&snd_seq_client_info_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_name
+ *(void **) (&snd_seq_client_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_broadcast_filter
+ *(void **) (&snd_seq_client_info_get_broadcast_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_broadcast_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_error_bounce
+ *(void **) (&snd_seq_client_info_get_error_bounce_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_error_bounce");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_card
+ *(void **) (&snd_seq_client_info_get_card_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_card");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_pid
+ *(void **) (&snd_seq_client_info_get_pid_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_pid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_event_filter
+ *(void **) (&snd_seq_client_info_get_event_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_event_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_num_ports
+ *(void **) (&snd_seq_client_info_get_num_ports_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_num_ports");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_get_event_lost
+ *(void **) (&snd_seq_client_info_get_event_lost_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_get_event_lost");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_set_client
+ *(void **) (&snd_seq_client_info_set_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_set_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_set_name
+ *(void **) (&snd_seq_client_info_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_set_broadcast_filter
+ *(void **) (&snd_seq_client_info_set_broadcast_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_set_broadcast_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_set_error_bounce
+ *(void **) (&snd_seq_client_info_set_error_bounce_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_set_error_bounce");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_set_event_filter
+ *(void **) (&snd_seq_client_info_set_event_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_set_event_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_event_filter_clear
+ *(void **) (&snd_seq_client_info_event_filter_clear_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_event_filter_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_event_filter_add
+ *(void **) (&snd_seq_client_info_event_filter_add_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_event_filter_add");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_event_filter_del
+ *(void **) (&snd_seq_client_info_event_filter_del_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_event_filter_del");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_info_event_filter_check
+ *(void **) (&snd_seq_client_info_event_filter_check_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_info_event_filter_check");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_client_info
+ *(void **) (&snd_seq_get_client_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_client_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_any_client_info
+ *(void **) (&snd_seq_get_any_client_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_any_client_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_info
+ *(void **) (&snd_seq_set_client_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_next_client
+ *(void **) (&snd_seq_query_next_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_next_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_sizeof
+ *(void **) (&snd_seq_client_pool_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_malloc
+ *(void **) (&snd_seq_client_pool_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_free
+ *(void **) (&snd_seq_client_pool_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_copy
+ *(void **) (&snd_seq_client_pool_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_client
+ *(void **) (&snd_seq_client_pool_get_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_output_pool
+ *(void **) (&snd_seq_client_pool_get_output_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_output_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_input_pool
+ *(void **) (&snd_seq_client_pool_get_input_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_input_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_output_room
+ *(void **) (&snd_seq_client_pool_get_output_room_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_output_room");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_output_free
+ *(void **) (&snd_seq_client_pool_get_output_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_output_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_get_input_free
+ *(void **) (&snd_seq_client_pool_get_input_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_get_input_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_set_output_pool
+ *(void **) (&snd_seq_client_pool_set_output_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_set_output_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_set_input_pool
+ *(void **) (&snd_seq_client_pool_set_input_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_set_input_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_client_pool_set_output_room
+ *(void **) (&snd_seq_client_pool_set_output_room_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_client_pool_set_output_room");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_client_pool
+ *(void **) (&snd_seq_get_client_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_client_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_pool
+ *(void **) (&snd_seq_set_client_pool_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_pool");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_sizeof
+ *(void **) (&snd_seq_port_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_malloc
+ *(void **) (&snd_seq_port_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_free
+ *(void **) (&snd_seq_port_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_copy
+ *(void **) (&snd_seq_port_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_client
+ *(void **) (&snd_seq_port_info_get_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_port
+ *(void **) (&snd_seq_port_info_get_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_addr
+ *(void **) (&snd_seq_port_info_get_addr_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_addr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_name
+ *(void **) (&snd_seq_port_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_capability
+ *(void **) (&snd_seq_port_info_get_capability_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_capability");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_type
+ *(void **) (&snd_seq_port_info_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_midi_channels
+ *(void **) (&snd_seq_port_info_get_midi_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_midi_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_midi_voices
+ *(void **) (&snd_seq_port_info_get_midi_voices_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_midi_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_synth_voices
+ *(void **) (&snd_seq_port_info_get_synth_voices_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_synth_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_read_use
+ *(void **) (&snd_seq_port_info_get_read_use_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_read_use");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_write_use
+ *(void **) (&snd_seq_port_info_get_write_use_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_write_use");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_port_specified
+ *(void **) (&snd_seq_port_info_get_port_specified_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_port_specified");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_timestamping
+ *(void **) (&snd_seq_port_info_get_timestamping_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_timestamping");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_timestamp_real
+ *(void **) (&snd_seq_port_info_get_timestamp_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_timestamp_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_get_timestamp_queue
+ *(void **) (&snd_seq_port_info_get_timestamp_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_get_timestamp_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_client
+ *(void **) (&snd_seq_port_info_set_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_port
+ *(void **) (&snd_seq_port_info_set_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_addr
+ *(void **) (&snd_seq_port_info_set_addr_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_addr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_name
+ *(void **) (&snd_seq_port_info_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_capability
+ *(void **) (&snd_seq_port_info_set_capability_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_capability");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_type
+ *(void **) (&snd_seq_port_info_set_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_midi_channels
+ *(void **) (&snd_seq_port_info_set_midi_channels_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_midi_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_midi_voices
+ *(void **) (&snd_seq_port_info_set_midi_voices_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_midi_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_synth_voices
+ *(void **) (&snd_seq_port_info_set_synth_voices_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_synth_voices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_port_specified
+ *(void **) (&snd_seq_port_info_set_port_specified_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_port_specified");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_timestamping
+ *(void **) (&snd_seq_port_info_set_timestamping_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_timestamping");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_timestamp_real
+ *(void **) (&snd_seq_port_info_set_timestamp_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_timestamp_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_info_set_timestamp_queue
+ *(void **) (&snd_seq_port_info_set_timestamp_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_info_set_timestamp_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_create_port
+ *(void **) (&snd_seq_create_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_create_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_delete_port
+ *(void **) (&snd_seq_delete_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_delete_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_port_info
+ *(void **) (&snd_seq_get_port_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_port_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_any_port_info
+ *(void **) (&snd_seq_get_any_port_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_any_port_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_port_info
+ *(void **) (&snd_seq_set_port_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_port_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_next_port
+ *(void **) (&snd_seq_query_next_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_next_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_sizeof
+ *(void **) (&snd_seq_port_subscribe_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_malloc
+ *(void **) (&snd_seq_port_subscribe_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_free
+ *(void **) (&snd_seq_port_subscribe_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_copy
+ *(void **) (&snd_seq_port_subscribe_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_sender
+ *(void **) (&snd_seq_port_subscribe_get_sender_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_sender");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_dest
+ *(void **) (&snd_seq_port_subscribe_get_dest_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_dest");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_queue
+ *(void **) (&snd_seq_port_subscribe_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_exclusive
+ *(void **) (&snd_seq_port_subscribe_get_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_time_update
+ *(void **) (&snd_seq_port_subscribe_get_time_update_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_time_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_get_time_real
+ *(void **) (&snd_seq_port_subscribe_get_time_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_get_time_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_sender
+ *(void **) (&snd_seq_port_subscribe_set_sender_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_sender");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_dest
+ *(void **) (&snd_seq_port_subscribe_set_dest_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_dest");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_queue
+ *(void **) (&snd_seq_port_subscribe_set_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_exclusive
+ *(void **) (&snd_seq_port_subscribe_set_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_time_update
+ *(void **) (&snd_seq_port_subscribe_set_time_update_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_time_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_port_subscribe_set_time_real
+ *(void **) (&snd_seq_port_subscribe_set_time_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_port_subscribe_set_time_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_port_subscription
+ *(void **) (&snd_seq_get_port_subscription_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_port_subscription");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_subscribe_port
+ *(void **) (&snd_seq_subscribe_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_subscribe_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_unsubscribe_port
+ *(void **) (&snd_seq_unsubscribe_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_unsubscribe_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_sizeof
+ *(void **) (&snd_seq_query_subscribe_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_malloc
+ *(void **) (&snd_seq_query_subscribe_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_free
+ *(void **) (&snd_seq_query_subscribe_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_copy
+ *(void **) (&snd_seq_query_subscribe_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_client
+ *(void **) (&snd_seq_query_subscribe_get_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_port
+ *(void **) (&snd_seq_query_subscribe_get_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_root
+ *(void **) (&snd_seq_query_subscribe_get_root_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_root");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_type
+ *(void **) (&snd_seq_query_subscribe_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_index
+ *(void **) (&snd_seq_query_subscribe_get_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_num_subs
+ *(void **) (&snd_seq_query_subscribe_get_num_subs_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_num_subs");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_addr
+ *(void **) (&snd_seq_query_subscribe_get_addr_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_addr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_queue
+ *(void **) (&snd_seq_query_subscribe_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_exclusive
+ *(void **) (&snd_seq_query_subscribe_get_exclusive_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_exclusive");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_time_update
+ *(void **) (&snd_seq_query_subscribe_get_time_update_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_time_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_get_time_real
+ *(void **) (&snd_seq_query_subscribe_get_time_real_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_get_time_real");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_set_client
+ *(void **) (&snd_seq_query_subscribe_set_client_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_set_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_set_port
+ *(void **) (&snd_seq_query_subscribe_set_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_set_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_set_root
+ *(void **) (&snd_seq_query_subscribe_set_root_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_set_root");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_set_type
+ *(void **) (&snd_seq_query_subscribe_set_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_set_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_subscribe_set_index
+ *(void **) (&snd_seq_query_subscribe_set_index_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_subscribe_set_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_port_subscribers
+ *(void **) (&snd_seq_query_port_subscribers_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_port_subscribers");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_sizeof
+ *(void **) (&snd_seq_queue_info_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_malloc
+ *(void **) (&snd_seq_queue_info_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_free
+ *(void **) (&snd_seq_queue_info_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_copy
+ *(void **) (&snd_seq_queue_info_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_get_queue
+ *(void **) (&snd_seq_queue_info_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_get_name
+ *(void **) (&snd_seq_queue_info_get_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_get_owner
+ *(void **) (&snd_seq_queue_info_get_owner_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_get_owner");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_get_locked
+ *(void **) (&snd_seq_queue_info_get_locked_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_get_locked");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_get_flags
+ *(void **) (&snd_seq_queue_info_get_flags_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_get_flags");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_set_name
+ *(void **) (&snd_seq_queue_info_set_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_set_owner
+ *(void **) (&snd_seq_queue_info_set_owner_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_set_owner");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_set_locked
+ *(void **) (&snd_seq_queue_info_set_locked_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_set_locked");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_info_set_flags
+ *(void **) (&snd_seq_queue_info_set_flags_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_info_set_flags");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_create_queue
+ *(void **) (&snd_seq_create_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_create_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_alloc_named_queue
+ *(void **) (&snd_seq_alloc_named_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_alloc_named_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_alloc_queue
+ *(void **) (&snd_seq_alloc_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_alloc_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_free_queue
+ *(void **) (&snd_seq_free_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_free_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_queue_info
+ *(void **) (&snd_seq_get_queue_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_queue_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_queue_info
+ *(void **) (&snd_seq_set_queue_info_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_queue_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_query_named_queue
+ *(void **) (&snd_seq_query_named_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_query_named_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_queue_usage
+ *(void **) (&snd_seq_get_queue_usage_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_queue_usage");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_queue_usage
+ *(void **) (&snd_seq_set_queue_usage_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_queue_usage");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_sizeof
+ *(void **) (&snd_seq_queue_status_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_malloc
+ *(void **) (&snd_seq_queue_status_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_free
+ *(void **) (&snd_seq_queue_status_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_copy
+ *(void **) (&snd_seq_queue_status_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_get_queue
+ *(void **) (&snd_seq_queue_status_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_get_events
+ *(void **) (&snd_seq_queue_status_get_events_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_get_events");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_get_tick_time
+ *(void **) (&snd_seq_queue_status_get_tick_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_get_tick_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_get_real_time
+ *(void **) (&snd_seq_queue_status_get_real_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_get_real_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_status_get_status
+ *(void **) (&snd_seq_queue_status_get_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_status_get_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_queue_status
+ *(void **) (&snd_seq_get_queue_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_queue_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_sizeof
+ *(void **) (&snd_seq_queue_tempo_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_malloc
+ *(void **) (&snd_seq_queue_tempo_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_free
+ *(void **) (&snd_seq_queue_tempo_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_copy
+ *(void **) (&snd_seq_queue_tempo_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_get_queue
+ *(void **) (&snd_seq_queue_tempo_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_get_tempo
+ *(void **) (&snd_seq_queue_tempo_get_tempo_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_get_tempo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_get_ppq
+ *(void **) (&snd_seq_queue_tempo_get_ppq_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_get_ppq");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_get_skew
+ *(void **) (&snd_seq_queue_tempo_get_skew_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_get_skew");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_get_skew_base
+ *(void **) (&snd_seq_queue_tempo_get_skew_base_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_get_skew_base");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_set_tempo
+ *(void **) (&snd_seq_queue_tempo_set_tempo_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_set_tempo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_set_ppq
+ *(void **) (&snd_seq_queue_tempo_set_ppq_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_set_ppq");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_set_skew
+ *(void **) (&snd_seq_queue_tempo_set_skew_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_set_skew");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_tempo_set_skew_base
+ *(void **) (&snd_seq_queue_tempo_set_skew_base_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_tempo_set_skew_base");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_queue_tempo
+ *(void **) (&snd_seq_get_queue_tempo_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_queue_tempo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_queue_tempo
+ *(void **) (&snd_seq_set_queue_tempo_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_queue_tempo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_sizeof
+ *(void **) (&snd_seq_queue_timer_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_malloc
+ *(void **) (&snd_seq_queue_timer_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_free
+ *(void **) (&snd_seq_queue_timer_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_copy
+ *(void **) (&snd_seq_queue_timer_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_get_queue
+ *(void **) (&snd_seq_queue_timer_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_get_type
+ *(void **) (&snd_seq_queue_timer_get_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_get_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_get_id
+ *(void **) (&snd_seq_queue_timer_get_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_get_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_get_resolution
+ *(void **) (&snd_seq_queue_timer_get_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_get_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_set_type
+ *(void **) (&snd_seq_queue_timer_set_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_set_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_set_id
+ *(void **) (&snd_seq_queue_timer_set_id_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_set_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_queue_timer_set_resolution
+ *(void **) (&snd_seq_queue_timer_set_resolution_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_queue_timer_set_resolution");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_queue_timer
+ *(void **) (&snd_seq_get_queue_timer_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_queue_timer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_queue_timer
+ *(void **) (&snd_seq_set_queue_timer_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_queue_timer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_free_event
+ *(void **) (&snd_seq_free_event_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_free_event");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_length
+ *(void **) (&snd_seq_event_length_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_length");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_output
+ *(void **) (&snd_seq_event_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_output_buffer
+ *(void **) (&snd_seq_event_output_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_output_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_output_direct
+ *(void **) (&snd_seq_event_output_direct_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_output_direct");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_input
+ *(void **) (&snd_seq_event_input_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_input");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_input_pending
+ *(void **) (&snd_seq_event_input_pending_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_input_pending");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_drain_output
+ *(void **) (&snd_seq_drain_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_drain_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_event_output_pending
+ *(void **) (&snd_seq_event_output_pending_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_event_output_pending");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_extract_output
+ *(void **) (&snd_seq_extract_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_extract_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_drop_output
+ *(void **) (&snd_seq_drop_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_drop_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_drop_output_buffer
+ *(void **) (&snd_seq_drop_output_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_drop_output_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_drop_input
+ *(void **) (&snd_seq_drop_input_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_drop_input");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_drop_input_buffer
+ *(void **) (&snd_seq_drop_input_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_drop_input_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_sizeof
+ *(void **) (&snd_seq_remove_events_sizeof_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_sizeof");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_malloc
+ *(void **) (&snd_seq_remove_events_malloc_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_malloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_free
+ *(void **) (&snd_seq_remove_events_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_copy
+ *(void **) (&snd_seq_remove_events_copy_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_condition
+ *(void **) (&snd_seq_remove_events_get_condition_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_condition");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_queue
+ *(void **) (&snd_seq_remove_events_get_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_time
+ *(void **) (&snd_seq_remove_events_get_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_dest
+ *(void **) (&snd_seq_remove_events_get_dest_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_dest");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_channel
+ *(void **) (&snd_seq_remove_events_get_channel_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_channel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_event_type
+ *(void **) (&snd_seq_remove_events_get_event_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_event_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_get_tag
+ *(void **) (&snd_seq_remove_events_get_tag_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_get_tag");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_condition
+ *(void **) (&snd_seq_remove_events_set_condition_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_condition");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_queue
+ *(void **) (&snd_seq_remove_events_set_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_time
+ *(void **) (&snd_seq_remove_events_set_time_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_dest
+ *(void **) (&snd_seq_remove_events_set_dest_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_dest");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_channel
+ *(void **) (&snd_seq_remove_events_set_channel_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_channel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_event_type
+ *(void **) (&snd_seq_remove_events_set_event_type_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_event_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events_set_tag
+ *(void **) (&snd_seq_remove_events_set_tag_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events_set_tag");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_remove_events
+ *(void **) (&snd_seq_remove_events_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_remove_events");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_bit
+ *(void **) (&snd_seq_set_bit_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_bit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_unset_bit
+ *(void **) (&snd_seq_unset_bit_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_unset_bit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_change_bit
+ *(void **) (&snd_seq_change_bit_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_change_bit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_get_bit
+ *(void **) (&snd_seq_get_bit_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_get_bit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_control_queue
+ *(void **) (&snd_seq_control_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_control_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_create_simple_port
+ *(void **) (&snd_seq_create_simple_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_create_simple_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_delete_simple_port
+ *(void **) (&snd_seq_delete_simple_port_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_delete_simple_port");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_connect_from
+ *(void **) (&snd_seq_connect_from_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_connect_from");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_connect_to
+ *(void **) (&snd_seq_connect_to_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_connect_to");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_disconnect_from
+ *(void **) (&snd_seq_disconnect_from_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_disconnect_from");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_disconnect_to
+ *(void **) (&snd_seq_disconnect_to_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_disconnect_to");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_name
+ *(void **) (&snd_seq_set_client_name_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_event_filter
+ *(void **) (&snd_seq_set_client_event_filter_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_event_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_pool_output
+ *(void **) (&snd_seq_set_client_pool_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_pool_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_pool_output_room
+ *(void **) (&snd_seq_set_client_pool_output_room_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_pool_output_room");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_set_client_pool_input
+ *(void **) (&snd_seq_set_client_pool_input_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_set_client_pool_input");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_sync_output_queue
+ *(void **) (&snd_seq_sync_output_queue_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_sync_output_queue");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_parse_address
+ *(void **) (&snd_seq_parse_address_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_parse_address");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_reset_pool_output
+ *(void **) (&snd_seq_reset_pool_output_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_reset_pool_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_seq_reset_pool_input
+ *(void **) (&snd_seq_reset_pool_input_dylibloader_wrapper_asound) = dlsym(handle, "snd_seq_reset_pool_input");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_new
+ *(void **) (&snd_midi_event_new_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_resize_buffer
+ *(void **) (&snd_midi_event_resize_buffer_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_resize_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_free
+ *(void **) (&snd_midi_event_free_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_init
+ *(void **) (&snd_midi_event_init_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_reset_encode
+ *(void **) (&snd_midi_event_reset_encode_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_reset_encode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_reset_decode
+ *(void **) (&snd_midi_event_reset_decode_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_reset_decode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_no_status
+ *(void **) (&snd_midi_event_no_status_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_no_status");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_encode
+ *(void **) (&snd_midi_event_encode_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_encode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_encode_byte
+ *(void **) (&snd_midi_event_encode_byte_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_encode_byte");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// snd_midi_event_decode
+ *(void **) (&snd_midi_event_decode_dylibloader_wrapper_asound) = dlsym(handle, "snd_midi_event_decode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+return 0;
+}
diff --git a/drivers/alsa/asound-so_wrap.h b/drivers/alsa/asound-so_wrap.h
new file mode 100644
index 0000000000..5332d74152
--- /dev/null
+++ b/drivers/alsa/asound-so_wrap.h
@@ -0,0 +1,5134 @@
+#ifndef DYLIBLOAD_WRAPPER_ASOUND
+#define DYLIBLOAD_WRAPPER_ASOUND
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-22 19:22:12
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/alsa/asoundlib.h --sys-include <alsa/asoundlib.h> --soname libasound.so.2 --init-name asound --omit-prefix snd_pcm_sw_params_set_tstamp_type --omit-prefix snd_pcm_status_get_audio_htstamp_report --omit-prefix snd_pcm_sw_params_get_tstamp_type --omit-prefix snd_pcm_status_set_audio_htstamp_config --output-header asound-so_wrap.h --output-implementation asound-so_wrap.c
+//
+#include <stdint.h>
+
+#define snd_asoundlib_version snd_asoundlib_version_dylibloader_orig_asound
+#define snd_dlpath snd_dlpath_dylibloader_orig_asound
+#define snd_dlopen snd_dlopen_dylibloader_orig_asound
+#define snd_dlsym snd_dlsym_dylibloader_orig_asound
+#define snd_dlclose snd_dlclose_dylibloader_orig_asound
+#define snd_async_add_handler snd_async_add_handler_dylibloader_orig_asound
+#define snd_async_del_handler snd_async_del_handler_dylibloader_orig_asound
+#define snd_async_handler_get_fd snd_async_handler_get_fd_dylibloader_orig_asound
+#define snd_async_handler_get_signo snd_async_handler_get_signo_dylibloader_orig_asound
+#define snd_async_handler_get_callback_private snd_async_handler_get_callback_private_dylibloader_orig_asound
+#define snd_shm_area_create snd_shm_area_create_dylibloader_orig_asound
+#define snd_shm_area_share snd_shm_area_share_dylibloader_orig_asound
+#define snd_shm_area_destroy snd_shm_area_destroy_dylibloader_orig_asound
+#define snd_user_file snd_user_file_dylibloader_orig_asound
+#define snd_input_stdio_open snd_input_stdio_open_dylibloader_orig_asound
+#define snd_input_stdio_attach snd_input_stdio_attach_dylibloader_orig_asound
+#define snd_input_buffer_open snd_input_buffer_open_dylibloader_orig_asound
+#define snd_input_close snd_input_close_dylibloader_orig_asound
+#define snd_input_scanf snd_input_scanf_dylibloader_orig_asound
+#define snd_input_gets snd_input_gets_dylibloader_orig_asound
+#define snd_input_getc snd_input_getc_dylibloader_orig_asound
+#define snd_input_ungetc snd_input_ungetc_dylibloader_orig_asound
+#define snd_output_stdio_open snd_output_stdio_open_dylibloader_orig_asound
+#define snd_output_stdio_attach snd_output_stdio_attach_dylibloader_orig_asound
+#define snd_output_buffer_open snd_output_buffer_open_dylibloader_orig_asound
+#define snd_output_buffer_string snd_output_buffer_string_dylibloader_orig_asound
+#define snd_output_close snd_output_close_dylibloader_orig_asound
+#define snd_output_printf snd_output_printf_dylibloader_orig_asound
+#define snd_output_vprintf snd_output_vprintf_dylibloader_orig_asound
+#define snd_output_puts snd_output_puts_dylibloader_orig_asound
+#define snd_output_putc snd_output_putc_dylibloader_orig_asound
+#define snd_output_flush snd_output_flush_dylibloader_orig_asound
+#define snd_strerror snd_strerror_dylibloader_orig_asound
+#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_orig_asound
+#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_orig_asound
+#define snd_config_topdir snd_config_topdir_dylibloader_orig_asound
+#define snd_config_top snd_config_top_dylibloader_orig_asound
+#define snd_config_load snd_config_load_dylibloader_orig_asound
+#define snd_config_load_override snd_config_load_override_dylibloader_orig_asound
+#define snd_config_save snd_config_save_dylibloader_orig_asound
+#define snd_config_update snd_config_update_dylibloader_orig_asound
+#define snd_config_update_r snd_config_update_r_dylibloader_orig_asound
+#define snd_config_update_free snd_config_update_free_dylibloader_orig_asound
+#define snd_config_update_free_global snd_config_update_free_global_dylibloader_orig_asound
+#define snd_config_update_ref snd_config_update_ref_dylibloader_orig_asound
+#define snd_config_ref snd_config_ref_dylibloader_orig_asound
+#define snd_config_unref snd_config_unref_dylibloader_orig_asound
+#define snd_config_search snd_config_search_dylibloader_orig_asound
+#define snd_config_searchv snd_config_searchv_dylibloader_orig_asound
+#define snd_config_search_definition snd_config_search_definition_dylibloader_orig_asound
+#define snd_config_expand snd_config_expand_dylibloader_orig_asound
+#define snd_config_evaluate snd_config_evaluate_dylibloader_orig_asound
+#define snd_config_add snd_config_add_dylibloader_orig_asound
+#define snd_config_add_before snd_config_add_before_dylibloader_orig_asound
+#define snd_config_add_after snd_config_add_after_dylibloader_orig_asound
+#define snd_config_remove snd_config_remove_dylibloader_orig_asound
+#define snd_config_delete snd_config_delete_dylibloader_orig_asound
+#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_orig_asound
+#define snd_config_copy snd_config_copy_dylibloader_orig_asound
+#define snd_config_make snd_config_make_dylibloader_orig_asound
+#define snd_config_make_integer snd_config_make_integer_dylibloader_orig_asound
+#define snd_config_make_integer64 snd_config_make_integer64_dylibloader_orig_asound
+#define snd_config_make_real snd_config_make_real_dylibloader_orig_asound
+#define snd_config_make_string snd_config_make_string_dylibloader_orig_asound
+#define snd_config_make_pointer snd_config_make_pointer_dylibloader_orig_asound
+#define snd_config_make_compound snd_config_make_compound_dylibloader_orig_asound
+#define snd_config_imake_integer snd_config_imake_integer_dylibloader_orig_asound
+#define snd_config_imake_integer64 snd_config_imake_integer64_dylibloader_orig_asound
+#define snd_config_imake_real snd_config_imake_real_dylibloader_orig_asound
+#define snd_config_imake_string snd_config_imake_string_dylibloader_orig_asound
+#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_orig_asound
+#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_orig_asound
+#define snd_config_get_type snd_config_get_type_dylibloader_orig_asound
+#define snd_config_is_array snd_config_is_array_dylibloader_orig_asound
+#define snd_config_set_id snd_config_set_id_dylibloader_orig_asound
+#define snd_config_set_integer snd_config_set_integer_dylibloader_orig_asound
+#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_orig_asound
+#define snd_config_set_real snd_config_set_real_dylibloader_orig_asound
+#define snd_config_set_string snd_config_set_string_dylibloader_orig_asound
+#define snd_config_set_ascii snd_config_set_ascii_dylibloader_orig_asound
+#define snd_config_set_pointer snd_config_set_pointer_dylibloader_orig_asound
+#define snd_config_get_id snd_config_get_id_dylibloader_orig_asound
+#define snd_config_get_integer snd_config_get_integer_dylibloader_orig_asound
+#define snd_config_get_integer64 snd_config_get_integer64_dylibloader_orig_asound
+#define snd_config_get_real snd_config_get_real_dylibloader_orig_asound
+#define snd_config_get_ireal snd_config_get_ireal_dylibloader_orig_asound
+#define snd_config_get_string snd_config_get_string_dylibloader_orig_asound
+#define snd_config_get_ascii snd_config_get_ascii_dylibloader_orig_asound
+#define snd_config_get_pointer snd_config_get_pointer_dylibloader_orig_asound
+#define snd_config_test_id snd_config_test_id_dylibloader_orig_asound
+#define snd_config_iterator_first snd_config_iterator_first_dylibloader_orig_asound
+#define snd_config_iterator_next snd_config_iterator_next_dylibloader_orig_asound
+#define snd_config_iterator_end snd_config_iterator_end_dylibloader_orig_asound
+#define snd_config_iterator_entry snd_config_iterator_entry_dylibloader_orig_asound
+#define snd_config_get_bool_ascii snd_config_get_bool_ascii_dylibloader_orig_asound
+#define snd_config_get_bool snd_config_get_bool_dylibloader_orig_asound
+#define snd_config_get_ctl_iface_ascii snd_config_get_ctl_iface_ascii_dylibloader_orig_asound
+#define snd_config_get_ctl_iface snd_config_get_ctl_iface_dylibloader_orig_asound
+#define snd_names_list snd_names_list_dylibloader_orig_asound
+#define snd_names_list_free snd_names_list_free_dylibloader_orig_asound
+#define snd_pcm_open snd_pcm_open_dylibloader_orig_asound
+#define snd_pcm_open_lconf snd_pcm_open_lconf_dylibloader_orig_asound
+#define snd_pcm_open_fallback snd_pcm_open_fallback_dylibloader_orig_asound
+#define snd_pcm_close snd_pcm_close_dylibloader_orig_asound
+#define snd_pcm_name snd_pcm_name_dylibloader_orig_asound
+#define snd_pcm_type snd_pcm_type_dylibloader_orig_asound
+#define snd_pcm_stream snd_pcm_stream_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors_count snd_pcm_poll_descriptors_count_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors snd_pcm_poll_descriptors_dylibloader_orig_asound
+#define snd_pcm_poll_descriptors_revents snd_pcm_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_pcm_nonblock snd_pcm_nonblock_dylibloader_orig_asound
+#define snd_async_add_pcm_handler snd_async_add_pcm_handler_dylibloader_orig_asound
+#define snd_async_handler_get_pcm snd_async_handler_get_pcm_dylibloader_orig_asound
+#define snd_pcm_info snd_pcm_info_dylibloader_orig_asound
+#define snd_pcm_hw_params_current snd_pcm_hw_params_current_dylibloader_orig_asound
+#define snd_pcm_hw_params snd_pcm_hw_params_dylibloader_orig_asound
+#define snd_pcm_hw_free snd_pcm_hw_free_dylibloader_orig_asound
+#define snd_pcm_sw_params_current snd_pcm_sw_params_current_dylibloader_orig_asound
+#define snd_pcm_sw_params snd_pcm_sw_params_dylibloader_orig_asound
+#define snd_pcm_prepare snd_pcm_prepare_dylibloader_orig_asound
+#define snd_pcm_reset snd_pcm_reset_dylibloader_orig_asound
+#define snd_pcm_status snd_pcm_status_dylibloader_orig_asound
+#define snd_pcm_start snd_pcm_start_dylibloader_orig_asound
+#define snd_pcm_drop snd_pcm_drop_dylibloader_orig_asound
+#define snd_pcm_drain snd_pcm_drain_dylibloader_orig_asound
+#define snd_pcm_pause snd_pcm_pause_dylibloader_orig_asound
+#define snd_pcm_state snd_pcm_state_dylibloader_orig_asound
+#define snd_pcm_hwsync snd_pcm_hwsync_dylibloader_orig_asound
+#define snd_pcm_delay snd_pcm_delay_dylibloader_orig_asound
+#define snd_pcm_resume snd_pcm_resume_dylibloader_orig_asound
+#define snd_pcm_htimestamp snd_pcm_htimestamp_dylibloader_orig_asound
+#define snd_pcm_avail snd_pcm_avail_dylibloader_orig_asound
+#define snd_pcm_avail_update snd_pcm_avail_update_dylibloader_orig_asound
+#define snd_pcm_avail_delay snd_pcm_avail_delay_dylibloader_orig_asound
+#define snd_pcm_rewindable snd_pcm_rewindable_dylibloader_orig_asound
+#define snd_pcm_rewind snd_pcm_rewind_dylibloader_orig_asound
+#define snd_pcm_forwardable snd_pcm_forwardable_dylibloader_orig_asound
+#define snd_pcm_forward snd_pcm_forward_dylibloader_orig_asound
+#define snd_pcm_writei snd_pcm_writei_dylibloader_orig_asound
+#define snd_pcm_readi snd_pcm_readi_dylibloader_orig_asound
+#define snd_pcm_writen snd_pcm_writen_dylibloader_orig_asound
+#define snd_pcm_readn snd_pcm_readn_dylibloader_orig_asound
+#define snd_pcm_wait snd_pcm_wait_dylibloader_orig_asound
+#define snd_pcm_link snd_pcm_link_dylibloader_orig_asound
+#define snd_pcm_unlink snd_pcm_unlink_dylibloader_orig_asound
+#define snd_pcm_query_chmaps snd_pcm_query_chmaps_dylibloader_orig_asound
+#define snd_pcm_query_chmaps_from_hw snd_pcm_query_chmaps_from_hw_dylibloader_orig_asound
+#define snd_pcm_free_chmaps snd_pcm_free_chmaps_dylibloader_orig_asound
+#define snd_pcm_get_chmap snd_pcm_get_chmap_dylibloader_orig_asound
+#define snd_pcm_set_chmap snd_pcm_set_chmap_dylibloader_orig_asound
+#define snd_pcm_chmap_type_name snd_pcm_chmap_type_name_dylibloader_orig_asound
+#define snd_pcm_chmap_name snd_pcm_chmap_name_dylibloader_orig_asound
+#define snd_pcm_chmap_long_name snd_pcm_chmap_long_name_dylibloader_orig_asound
+#define snd_pcm_chmap_print snd_pcm_chmap_print_dylibloader_orig_asound
+#define snd_pcm_chmap_from_string snd_pcm_chmap_from_string_dylibloader_orig_asound
+#define snd_pcm_chmap_parse_string snd_pcm_chmap_parse_string_dylibloader_orig_asound
+#define snd_pcm_recover snd_pcm_recover_dylibloader_orig_asound
+#define snd_pcm_set_params snd_pcm_set_params_dylibloader_orig_asound
+#define snd_pcm_get_params snd_pcm_get_params_dylibloader_orig_asound
+#define snd_pcm_info_sizeof snd_pcm_info_sizeof_dylibloader_orig_asound
+#define snd_pcm_info_malloc snd_pcm_info_malloc_dylibloader_orig_asound
+#define snd_pcm_info_free snd_pcm_info_free_dylibloader_orig_asound
+#define snd_pcm_info_copy snd_pcm_info_copy_dylibloader_orig_asound
+#define snd_pcm_info_get_device snd_pcm_info_get_device_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevice snd_pcm_info_get_subdevice_dylibloader_orig_asound
+#define snd_pcm_info_get_stream snd_pcm_info_get_stream_dylibloader_orig_asound
+#define snd_pcm_info_get_card snd_pcm_info_get_card_dylibloader_orig_asound
+#define snd_pcm_info_get_id snd_pcm_info_get_id_dylibloader_orig_asound
+#define snd_pcm_info_get_name snd_pcm_info_get_name_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevice_name snd_pcm_info_get_subdevice_name_dylibloader_orig_asound
+#define snd_pcm_info_get_class snd_pcm_info_get_class_dylibloader_orig_asound
+#define snd_pcm_info_get_subclass snd_pcm_info_get_subclass_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevices_count snd_pcm_info_get_subdevices_count_dylibloader_orig_asound
+#define snd_pcm_info_get_subdevices_avail snd_pcm_info_get_subdevices_avail_dylibloader_orig_asound
+#define snd_pcm_info_get_sync snd_pcm_info_get_sync_dylibloader_orig_asound
+#define snd_pcm_info_set_device snd_pcm_info_set_device_dylibloader_orig_asound
+#define snd_pcm_info_set_subdevice snd_pcm_info_set_subdevice_dylibloader_orig_asound
+#define snd_pcm_info_set_stream snd_pcm_info_set_stream_dylibloader_orig_asound
+#define snd_pcm_hw_params_any snd_pcm_hw_params_any_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_mmap_sample_resolution snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_double snd_pcm_hw_params_is_double_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_batch snd_pcm_hw_params_is_batch_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_block_transfer snd_pcm_hw_params_is_block_transfer_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_monotonic snd_pcm_hw_params_is_monotonic_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_overrange snd_pcm_hw_params_can_overrange_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_pause snd_pcm_hw_params_can_pause_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_resume snd_pcm_hw_params_can_resume_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_half_duplex snd_pcm_hw_params_is_half_duplex_dylibloader_orig_asound
+#define snd_pcm_hw_params_is_joint_duplex snd_pcm_hw_params_is_joint_duplex_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_sync_start snd_pcm_hw_params_can_sync_start_dylibloader_orig_asound
+#define snd_pcm_hw_params_can_disable_period_wakeup snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_supports_audio_wallclock_ts snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_orig_asound
+#define snd_pcm_hw_params_supports_audio_ts_type snd_pcm_hw_params_supports_audio_ts_type_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_numden snd_pcm_hw_params_get_rate_numden_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_sbits snd_pcm_hw_params_get_sbits_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_fifo_size snd_pcm_hw_params_get_fifo_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_sizeof snd_pcm_hw_params_sizeof_dylibloader_orig_asound
+#define snd_pcm_hw_params_malloc snd_pcm_hw_params_malloc_dylibloader_orig_asound
+#define snd_pcm_hw_params_free snd_pcm_hw_params_free_dylibloader_orig_asound
+#define snd_pcm_hw_params_copy snd_pcm_hw_params_copy_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_access snd_pcm_hw_params_get_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_access snd_pcm_hw_params_test_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access snd_pcm_hw_params_set_access_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_first snd_pcm_hw_params_set_access_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_last snd_pcm_hw_params_set_access_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_access_mask snd_pcm_hw_params_set_access_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_access_mask snd_pcm_hw_params_get_access_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_format snd_pcm_hw_params_get_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_format snd_pcm_hw_params_test_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format snd_pcm_hw_params_set_format_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_first snd_pcm_hw_params_set_format_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_last snd_pcm_hw_params_set_format_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_format_mask snd_pcm_hw_params_set_format_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_format_mask snd_pcm_hw_params_get_format_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_subformat snd_pcm_hw_params_get_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_subformat snd_pcm_hw_params_test_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat snd_pcm_hw_params_set_subformat_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_first snd_pcm_hw_params_set_subformat_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_last snd_pcm_hw_params_set_subformat_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_subformat_mask snd_pcm_hw_params_set_subformat_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_subformat_mask snd_pcm_hw_params_get_subformat_mask_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels snd_pcm_hw_params_get_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels_min snd_pcm_hw_params_get_channels_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_channels_max snd_pcm_hw_params_get_channels_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_channels snd_pcm_hw_params_test_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels snd_pcm_hw_params_set_channels_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_min snd_pcm_hw_params_set_channels_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_max snd_pcm_hw_params_set_channels_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_minmax snd_pcm_hw_params_set_channels_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_near snd_pcm_hw_params_set_channels_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_first snd_pcm_hw_params_set_channels_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_channels_last snd_pcm_hw_params_set_channels_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate snd_pcm_hw_params_get_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_min snd_pcm_hw_params_get_rate_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_max snd_pcm_hw_params_get_rate_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_rate snd_pcm_hw_params_test_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate snd_pcm_hw_params_set_rate_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_min snd_pcm_hw_params_set_rate_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_max snd_pcm_hw_params_set_rate_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_minmax snd_pcm_hw_params_set_rate_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_near snd_pcm_hw_params_set_rate_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_first snd_pcm_hw_params_set_rate_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_last snd_pcm_hw_params_set_rate_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_rate_resample snd_pcm_hw_params_set_rate_resample_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_rate_resample snd_pcm_hw_params_get_rate_resample_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_export_buffer snd_pcm_hw_params_set_export_buffer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_export_buffer snd_pcm_hw_params_get_export_buffer_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_wakeup snd_pcm_hw_params_set_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_wakeup snd_pcm_hw_params_get_period_wakeup_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time snd_pcm_hw_params_get_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time_min snd_pcm_hw_params_get_period_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_time_max snd_pcm_hw_params_get_period_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_period_time snd_pcm_hw_params_test_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time snd_pcm_hw_params_set_period_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_min snd_pcm_hw_params_set_period_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_max snd_pcm_hw_params_set_period_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_minmax snd_pcm_hw_params_set_period_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_near snd_pcm_hw_params_set_period_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_first snd_pcm_hw_params_set_period_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_time_last snd_pcm_hw_params_set_period_time_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size snd_pcm_hw_params_get_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size_min snd_pcm_hw_params_get_period_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_period_size_max snd_pcm_hw_params_get_period_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_period_size snd_pcm_hw_params_test_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size snd_pcm_hw_params_set_period_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_min snd_pcm_hw_params_set_period_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_max snd_pcm_hw_params_set_period_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_minmax snd_pcm_hw_params_set_period_size_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_near snd_pcm_hw_params_set_period_size_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_first snd_pcm_hw_params_set_period_size_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_last snd_pcm_hw_params_set_period_size_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_period_size_integer snd_pcm_hw_params_set_period_size_integer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods snd_pcm_hw_params_get_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods_min snd_pcm_hw_params_get_periods_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_periods_max snd_pcm_hw_params_get_periods_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_periods snd_pcm_hw_params_test_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods snd_pcm_hw_params_set_periods_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_min snd_pcm_hw_params_set_periods_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_max snd_pcm_hw_params_set_periods_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_minmax snd_pcm_hw_params_set_periods_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_near snd_pcm_hw_params_set_periods_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_first snd_pcm_hw_params_set_periods_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_last snd_pcm_hw_params_set_periods_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_periods_integer snd_pcm_hw_params_set_periods_integer_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time snd_pcm_hw_params_get_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time_min snd_pcm_hw_params_get_buffer_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_time_max snd_pcm_hw_params_get_buffer_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_buffer_time snd_pcm_hw_params_test_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time snd_pcm_hw_params_set_buffer_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_min snd_pcm_hw_params_set_buffer_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_max snd_pcm_hw_params_set_buffer_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_minmax snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_near snd_pcm_hw_params_set_buffer_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_first snd_pcm_hw_params_set_buffer_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_time_last snd_pcm_hw_params_set_buffer_time_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size snd_pcm_hw_params_get_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size_min snd_pcm_hw_params_get_buffer_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_buffer_size_max snd_pcm_hw_params_get_buffer_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_buffer_size snd_pcm_hw_params_test_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size snd_pcm_hw_params_set_buffer_size_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_min snd_pcm_hw_params_set_buffer_size_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_max snd_pcm_hw_params_set_buffer_size_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_minmax snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_near snd_pcm_hw_params_set_buffer_size_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_first snd_pcm_hw_params_set_buffer_size_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_buffer_size_last snd_pcm_hw_params_set_buffer_size_last_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_min_align snd_pcm_hw_params_get_min_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_sizeof snd_pcm_sw_params_sizeof_dylibloader_orig_asound
+#define snd_pcm_sw_params_malloc snd_pcm_sw_params_malloc_dylibloader_orig_asound
+#define snd_pcm_sw_params_free snd_pcm_sw_params_free_dylibloader_orig_asound
+#define snd_pcm_sw_params_copy snd_pcm_sw_params_copy_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_boundary snd_pcm_sw_params_get_boundary_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_tstamp_mode snd_pcm_sw_params_set_tstamp_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_tstamp_mode snd_pcm_sw_params_get_tstamp_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_avail_min snd_pcm_sw_params_set_avail_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_avail_min snd_pcm_sw_params_get_avail_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_period_event snd_pcm_sw_params_set_period_event_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_period_event snd_pcm_sw_params_get_period_event_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_start_threshold snd_pcm_sw_params_set_start_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_start_threshold snd_pcm_sw_params_get_start_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_stop_threshold snd_pcm_sw_params_set_stop_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_stop_threshold snd_pcm_sw_params_get_stop_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_silence_threshold snd_pcm_sw_params_set_silence_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_silence_threshold snd_pcm_sw_params_get_silence_threshold_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_silence_size snd_pcm_sw_params_set_silence_size_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_silence_size snd_pcm_sw_params_get_silence_size_dylibloader_orig_asound
+#define snd_pcm_access_mask_sizeof snd_pcm_access_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_access_mask_malloc snd_pcm_access_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_access_mask_free snd_pcm_access_mask_free_dylibloader_orig_asound
+#define snd_pcm_access_mask_copy snd_pcm_access_mask_copy_dylibloader_orig_asound
+#define snd_pcm_access_mask_none snd_pcm_access_mask_none_dylibloader_orig_asound
+#define snd_pcm_access_mask_any snd_pcm_access_mask_any_dylibloader_orig_asound
+#define snd_pcm_access_mask_test snd_pcm_access_mask_test_dylibloader_orig_asound
+#define snd_pcm_access_mask_empty snd_pcm_access_mask_empty_dylibloader_orig_asound
+#define snd_pcm_access_mask_set snd_pcm_access_mask_set_dylibloader_orig_asound
+#define snd_pcm_access_mask_reset snd_pcm_access_mask_reset_dylibloader_orig_asound
+#define snd_pcm_format_mask_sizeof snd_pcm_format_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_format_mask_malloc snd_pcm_format_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_format_mask_free snd_pcm_format_mask_free_dylibloader_orig_asound
+#define snd_pcm_format_mask_copy snd_pcm_format_mask_copy_dylibloader_orig_asound
+#define snd_pcm_format_mask_none snd_pcm_format_mask_none_dylibloader_orig_asound
+#define snd_pcm_format_mask_any snd_pcm_format_mask_any_dylibloader_orig_asound
+#define snd_pcm_format_mask_test snd_pcm_format_mask_test_dylibloader_orig_asound
+#define snd_pcm_format_mask_empty snd_pcm_format_mask_empty_dylibloader_orig_asound
+#define snd_pcm_format_mask_set snd_pcm_format_mask_set_dylibloader_orig_asound
+#define snd_pcm_format_mask_reset snd_pcm_format_mask_reset_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_sizeof snd_pcm_subformat_mask_sizeof_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_malloc snd_pcm_subformat_mask_malloc_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_free snd_pcm_subformat_mask_free_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_copy snd_pcm_subformat_mask_copy_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_none snd_pcm_subformat_mask_none_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_any snd_pcm_subformat_mask_any_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_test snd_pcm_subformat_mask_test_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_empty snd_pcm_subformat_mask_empty_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_set snd_pcm_subformat_mask_set_dylibloader_orig_asound
+#define snd_pcm_subformat_mask_reset snd_pcm_subformat_mask_reset_dylibloader_orig_asound
+#define snd_pcm_status_sizeof snd_pcm_status_sizeof_dylibloader_orig_asound
+#define snd_pcm_status_malloc snd_pcm_status_malloc_dylibloader_orig_asound
+#define snd_pcm_status_free snd_pcm_status_free_dylibloader_orig_asound
+#define snd_pcm_status_copy snd_pcm_status_copy_dylibloader_orig_asound
+#define snd_pcm_status_get_state snd_pcm_status_get_state_dylibloader_orig_asound
+#define snd_pcm_status_get_trigger_tstamp snd_pcm_status_get_trigger_tstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_trigger_htstamp snd_pcm_status_get_trigger_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_tstamp snd_pcm_status_get_tstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_htstamp snd_pcm_status_get_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_audio_htstamp snd_pcm_status_get_audio_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_driver_htstamp snd_pcm_status_get_driver_htstamp_dylibloader_orig_asound
+#define snd_pcm_status_get_delay snd_pcm_status_get_delay_dylibloader_orig_asound
+#define snd_pcm_status_get_avail snd_pcm_status_get_avail_dylibloader_orig_asound
+#define snd_pcm_status_get_avail_max snd_pcm_status_get_avail_max_dylibloader_orig_asound
+#define snd_pcm_status_get_overrange snd_pcm_status_get_overrange_dylibloader_orig_asound
+#define snd_pcm_type_name snd_pcm_type_name_dylibloader_orig_asound
+#define snd_pcm_stream_name snd_pcm_stream_name_dylibloader_orig_asound
+#define snd_pcm_access_name snd_pcm_access_name_dylibloader_orig_asound
+#define snd_pcm_format_name snd_pcm_format_name_dylibloader_orig_asound
+#define snd_pcm_format_description snd_pcm_format_description_dylibloader_orig_asound
+#define snd_pcm_subformat_name snd_pcm_subformat_name_dylibloader_orig_asound
+#define snd_pcm_subformat_description snd_pcm_subformat_description_dylibloader_orig_asound
+#define snd_pcm_format_value snd_pcm_format_value_dylibloader_orig_asound
+#define snd_pcm_tstamp_mode_name snd_pcm_tstamp_mode_name_dylibloader_orig_asound
+#define snd_pcm_state_name snd_pcm_state_name_dylibloader_orig_asound
+#define snd_pcm_dump snd_pcm_dump_dylibloader_orig_asound
+#define snd_pcm_dump_hw_setup snd_pcm_dump_hw_setup_dylibloader_orig_asound
+#define snd_pcm_dump_sw_setup snd_pcm_dump_sw_setup_dylibloader_orig_asound
+#define snd_pcm_dump_setup snd_pcm_dump_setup_dylibloader_orig_asound
+#define snd_pcm_hw_params_dump snd_pcm_hw_params_dump_dylibloader_orig_asound
+#define snd_pcm_sw_params_dump snd_pcm_sw_params_dump_dylibloader_orig_asound
+#define snd_pcm_status_dump snd_pcm_status_dump_dylibloader_orig_asound
+#define snd_pcm_mmap_begin snd_pcm_mmap_begin_dylibloader_orig_asound
+#define snd_pcm_mmap_commit snd_pcm_mmap_commit_dylibloader_orig_asound
+#define snd_pcm_mmap_writei snd_pcm_mmap_writei_dylibloader_orig_asound
+#define snd_pcm_mmap_readi snd_pcm_mmap_readi_dylibloader_orig_asound
+#define snd_pcm_mmap_writen snd_pcm_mmap_writen_dylibloader_orig_asound
+#define snd_pcm_mmap_readn snd_pcm_mmap_readn_dylibloader_orig_asound
+#define snd_pcm_format_signed snd_pcm_format_signed_dylibloader_orig_asound
+#define snd_pcm_format_unsigned snd_pcm_format_unsigned_dylibloader_orig_asound
+#define snd_pcm_format_linear snd_pcm_format_linear_dylibloader_orig_asound
+#define snd_pcm_format_float snd_pcm_format_float_dylibloader_orig_asound
+#define snd_pcm_format_little_endian snd_pcm_format_little_endian_dylibloader_orig_asound
+#define snd_pcm_format_big_endian snd_pcm_format_big_endian_dylibloader_orig_asound
+#define snd_pcm_format_cpu_endian snd_pcm_format_cpu_endian_dylibloader_orig_asound
+#define snd_pcm_format_width snd_pcm_format_width_dylibloader_orig_asound
+#define snd_pcm_format_physical_width snd_pcm_format_physical_width_dylibloader_orig_asound
+#define snd_pcm_build_linear_format snd_pcm_build_linear_format_dylibloader_orig_asound
+#define snd_pcm_format_size snd_pcm_format_size_dylibloader_orig_asound
+#define snd_pcm_format_silence snd_pcm_format_silence_dylibloader_orig_asound
+#define snd_pcm_format_silence_16 snd_pcm_format_silence_16_dylibloader_orig_asound
+#define snd_pcm_format_silence_32 snd_pcm_format_silence_32_dylibloader_orig_asound
+#define snd_pcm_format_silence_64 snd_pcm_format_silence_64_dylibloader_orig_asound
+#define snd_pcm_format_set_silence snd_pcm_format_set_silence_dylibloader_orig_asound
+#define snd_pcm_bytes_to_frames snd_pcm_bytes_to_frames_dylibloader_orig_asound
+#define snd_pcm_frames_to_bytes snd_pcm_frames_to_bytes_dylibloader_orig_asound
+#define snd_pcm_bytes_to_samples snd_pcm_bytes_to_samples_dylibloader_orig_asound
+#define snd_pcm_samples_to_bytes snd_pcm_samples_to_bytes_dylibloader_orig_asound
+#define snd_pcm_area_silence snd_pcm_area_silence_dylibloader_orig_asound
+#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_orig_asound
+#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_orig_asound
+#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_orig_asound
+#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_orig_asound
+#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_orig_asound
+#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_orig_asound
+#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_orig_asound
+#define snd_pcm_hook_add snd_pcm_hook_add_dylibloader_orig_asound
+#define snd_pcm_hook_remove snd_pcm_hook_remove_dylibloader_orig_asound
+#define snd_pcm_meter_get_bufsize snd_pcm_meter_get_bufsize_dylibloader_orig_asound
+#define snd_pcm_meter_get_channels snd_pcm_meter_get_channels_dylibloader_orig_asound
+#define snd_pcm_meter_get_rate snd_pcm_meter_get_rate_dylibloader_orig_asound
+#define snd_pcm_meter_get_now snd_pcm_meter_get_now_dylibloader_orig_asound
+#define snd_pcm_meter_get_boundary snd_pcm_meter_get_boundary_dylibloader_orig_asound
+#define snd_pcm_meter_add_scope snd_pcm_meter_add_scope_dylibloader_orig_asound
+#define snd_pcm_meter_search_scope snd_pcm_meter_search_scope_dylibloader_orig_asound
+#define snd_pcm_scope_malloc snd_pcm_scope_malloc_dylibloader_orig_asound
+#define snd_pcm_scope_set_ops snd_pcm_scope_set_ops_dylibloader_orig_asound
+#define snd_pcm_scope_set_name snd_pcm_scope_set_name_dylibloader_orig_asound
+#define snd_pcm_scope_get_name snd_pcm_scope_get_name_dylibloader_orig_asound
+#define snd_pcm_scope_get_callback_private snd_pcm_scope_get_callback_private_dylibloader_orig_asound
+#define snd_pcm_scope_set_callback_private snd_pcm_scope_set_callback_private_dylibloader_orig_asound
+#define snd_pcm_scope_s16_open snd_pcm_scope_s16_open_dylibloader_orig_asound
+#define snd_pcm_scope_s16_get_channel_buffer snd_pcm_scope_s16_get_channel_buffer_dylibloader_orig_asound
+#define snd_spcm_init snd_spcm_init_dylibloader_orig_asound
+#define snd_spcm_init_duplex snd_spcm_init_duplex_dylibloader_orig_asound
+#define snd_spcm_init_get_params snd_spcm_init_get_params_dylibloader_orig_asound
+#define snd_pcm_start_mode_name snd_pcm_start_mode_name_dylibloader_orig_asound
+#define snd_pcm_xrun_mode_name snd_pcm_xrun_mode_name_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_start_mode snd_pcm_sw_params_set_start_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_start_mode snd_pcm_sw_params_get_start_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_xrun_mode snd_pcm_sw_params_set_xrun_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_xrun_mode snd_pcm_sw_params_get_xrun_mode_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_xfer_align snd_pcm_sw_params_set_xfer_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_xfer_align snd_pcm_sw_params_get_xfer_align_dylibloader_orig_asound
+#define snd_pcm_sw_params_set_sleep_min snd_pcm_sw_params_set_sleep_min_dylibloader_orig_asound
+#define snd_pcm_sw_params_get_sleep_min snd_pcm_sw_params_get_sleep_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time snd_pcm_hw_params_get_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time_min snd_pcm_hw_params_get_tick_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_get_tick_time_max snd_pcm_hw_params_get_tick_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_test_tick_time snd_pcm_hw_params_test_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time snd_pcm_hw_params_set_tick_time_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_min snd_pcm_hw_params_set_tick_time_min_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_max snd_pcm_hw_params_set_tick_time_max_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_minmax snd_pcm_hw_params_set_tick_time_minmax_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_near snd_pcm_hw_params_set_tick_time_near_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_first snd_pcm_hw_params_set_tick_time_first_dylibloader_orig_asound
+#define snd_pcm_hw_params_set_tick_time_last snd_pcm_hw_params_set_tick_time_last_dylibloader_orig_asound
+#define snd_rawmidi_open snd_rawmidi_open_dylibloader_orig_asound
+#define snd_rawmidi_open_lconf snd_rawmidi_open_lconf_dylibloader_orig_asound
+#define snd_rawmidi_close snd_rawmidi_close_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors_count snd_rawmidi_poll_descriptors_count_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors snd_rawmidi_poll_descriptors_dylibloader_orig_asound
+#define snd_rawmidi_poll_descriptors_revents snd_rawmidi_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_rawmidi_nonblock snd_rawmidi_nonblock_dylibloader_orig_asound
+#define snd_rawmidi_info_sizeof snd_rawmidi_info_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_info_malloc snd_rawmidi_info_malloc_dylibloader_orig_asound
+#define snd_rawmidi_info_free snd_rawmidi_info_free_dylibloader_orig_asound
+#define snd_rawmidi_info_copy snd_rawmidi_info_copy_dylibloader_orig_asound
+#define snd_rawmidi_info_get_device snd_rawmidi_info_get_device_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevice snd_rawmidi_info_get_subdevice_dylibloader_orig_asound
+#define snd_rawmidi_info_get_stream snd_rawmidi_info_get_stream_dylibloader_orig_asound
+#define snd_rawmidi_info_get_card snd_rawmidi_info_get_card_dylibloader_orig_asound
+#define snd_rawmidi_info_get_flags snd_rawmidi_info_get_flags_dylibloader_orig_asound
+#define snd_rawmidi_info_get_id snd_rawmidi_info_get_id_dylibloader_orig_asound
+#define snd_rawmidi_info_get_name snd_rawmidi_info_get_name_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevice_name snd_rawmidi_info_get_subdevice_name_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevices_count snd_rawmidi_info_get_subdevices_count_dylibloader_orig_asound
+#define snd_rawmidi_info_get_subdevices_avail snd_rawmidi_info_get_subdevices_avail_dylibloader_orig_asound
+#define snd_rawmidi_info_set_device snd_rawmidi_info_set_device_dylibloader_orig_asound
+#define snd_rawmidi_info_set_subdevice snd_rawmidi_info_set_subdevice_dylibloader_orig_asound
+#define snd_rawmidi_info_set_stream snd_rawmidi_info_set_stream_dylibloader_orig_asound
+#define snd_rawmidi_info snd_rawmidi_info_dylibloader_orig_asound
+#define snd_rawmidi_params_sizeof snd_rawmidi_params_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_params_malloc snd_rawmidi_params_malloc_dylibloader_orig_asound
+#define snd_rawmidi_params_free snd_rawmidi_params_free_dylibloader_orig_asound
+#define snd_rawmidi_params_copy snd_rawmidi_params_copy_dylibloader_orig_asound
+#define snd_rawmidi_params_set_buffer_size snd_rawmidi_params_set_buffer_size_dylibloader_orig_asound
+#define snd_rawmidi_params_get_buffer_size snd_rawmidi_params_get_buffer_size_dylibloader_orig_asound
+#define snd_rawmidi_params_set_avail_min snd_rawmidi_params_set_avail_min_dylibloader_orig_asound
+#define snd_rawmidi_params_get_avail_min snd_rawmidi_params_get_avail_min_dylibloader_orig_asound
+#define snd_rawmidi_params_set_no_active_sensing snd_rawmidi_params_set_no_active_sensing_dylibloader_orig_asound
+#define snd_rawmidi_params_get_no_active_sensing snd_rawmidi_params_get_no_active_sensing_dylibloader_orig_asound
+#define snd_rawmidi_params snd_rawmidi_params_dylibloader_orig_asound
+#define snd_rawmidi_params_current snd_rawmidi_params_current_dylibloader_orig_asound
+#define snd_rawmidi_status_sizeof snd_rawmidi_status_sizeof_dylibloader_orig_asound
+#define snd_rawmidi_status_malloc snd_rawmidi_status_malloc_dylibloader_orig_asound
+#define snd_rawmidi_status_free snd_rawmidi_status_free_dylibloader_orig_asound
+#define snd_rawmidi_status_copy snd_rawmidi_status_copy_dylibloader_orig_asound
+#define snd_rawmidi_status_get_tstamp snd_rawmidi_status_get_tstamp_dylibloader_orig_asound
+#define snd_rawmidi_status_get_avail snd_rawmidi_status_get_avail_dylibloader_orig_asound
+#define snd_rawmidi_status_get_xruns snd_rawmidi_status_get_xruns_dylibloader_orig_asound
+#define snd_rawmidi_status snd_rawmidi_status_dylibloader_orig_asound
+#define snd_rawmidi_drain snd_rawmidi_drain_dylibloader_orig_asound
+#define snd_rawmidi_drop snd_rawmidi_drop_dylibloader_orig_asound
+#define snd_rawmidi_write snd_rawmidi_write_dylibloader_orig_asound
+#define snd_rawmidi_read snd_rawmidi_read_dylibloader_orig_asound
+#define snd_rawmidi_name snd_rawmidi_name_dylibloader_orig_asound
+#define snd_rawmidi_type snd_rawmidi_type_dylibloader_orig_asound
+#define snd_rawmidi_stream snd_rawmidi_stream_dylibloader_orig_asound
+#define snd_timer_query_open snd_timer_query_open_dylibloader_orig_asound
+#define snd_timer_query_open_lconf snd_timer_query_open_lconf_dylibloader_orig_asound
+#define snd_timer_query_close snd_timer_query_close_dylibloader_orig_asound
+#define snd_timer_query_next_device snd_timer_query_next_device_dylibloader_orig_asound
+#define snd_timer_query_info snd_timer_query_info_dylibloader_orig_asound
+#define snd_timer_query_params snd_timer_query_params_dylibloader_orig_asound
+#define snd_timer_query_status snd_timer_query_status_dylibloader_orig_asound
+#define snd_timer_open snd_timer_open_dylibloader_orig_asound
+#define snd_timer_open_lconf snd_timer_open_lconf_dylibloader_orig_asound
+#define snd_timer_close snd_timer_close_dylibloader_orig_asound
+#define snd_async_add_timer_handler snd_async_add_timer_handler_dylibloader_orig_asound
+#define snd_async_handler_get_timer snd_async_handler_get_timer_dylibloader_orig_asound
+#define snd_timer_poll_descriptors_count snd_timer_poll_descriptors_count_dylibloader_orig_asound
+#define snd_timer_poll_descriptors snd_timer_poll_descriptors_dylibloader_orig_asound
+#define snd_timer_poll_descriptors_revents snd_timer_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_timer_info snd_timer_info_dylibloader_orig_asound
+#define snd_timer_params snd_timer_params_dylibloader_orig_asound
+#define snd_timer_status snd_timer_status_dylibloader_orig_asound
+#define snd_timer_start snd_timer_start_dylibloader_orig_asound
+#define snd_timer_stop snd_timer_stop_dylibloader_orig_asound
+#define snd_timer_continue snd_timer_continue_dylibloader_orig_asound
+#define snd_timer_read snd_timer_read_dylibloader_orig_asound
+#define snd_timer_id_sizeof snd_timer_id_sizeof_dylibloader_orig_asound
+#define snd_timer_id_malloc snd_timer_id_malloc_dylibloader_orig_asound
+#define snd_timer_id_free snd_timer_id_free_dylibloader_orig_asound
+#define snd_timer_id_copy snd_timer_id_copy_dylibloader_orig_asound
+#define snd_timer_id_set_class snd_timer_id_set_class_dylibloader_orig_asound
+#define snd_timer_id_get_class snd_timer_id_get_class_dylibloader_orig_asound
+#define snd_timer_id_set_sclass snd_timer_id_set_sclass_dylibloader_orig_asound
+#define snd_timer_id_get_sclass snd_timer_id_get_sclass_dylibloader_orig_asound
+#define snd_timer_id_set_card snd_timer_id_set_card_dylibloader_orig_asound
+#define snd_timer_id_get_card snd_timer_id_get_card_dylibloader_orig_asound
+#define snd_timer_id_set_device snd_timer_id_set_device_dylibloader_orig_asound
+#define snd_timer_id_get_device snd_timer_id_get_device_dylibloader_orig_asound
+#define snd_timer_id_set_subdevice snd_timer_id_set_subdevice_dylibloader_orig_asound
+#define snd_timer_id_get_subdevice snd_timer_id_get_subdevice_dylibloader_orig_asound
+#define snd_timer_ginfo_sizeof snd_timer_ginfo_sizeof_dylibloader_orig_asound
+#define snd_timer_ginfo_malloc snd_timer_ginfo_malloc_dylibloader_orig_asound
+#define snd_timer_ginfo_free snd_timer_ginfo_free_dylibloader_orig_asound
+#define snd_timer_ginfo_copy snd_timer_ginfo_copy_dylibloader_orig_asound
+#define snd_timer_ginfo_set_tid snd_timer_ginfo_set_tid_dylibloader_orig_asound
+#define snd_timer_ginfo_get_tid snd_timer_ginfo_get_tid_dylibloader_orig_asound
+#define snd_timer_ginfo_get_flags snd_timer_ginfo_get_flags_dylibloader_orig_asound
+#define snd_timer_ginfo_get_card snd_timer_ginfo_get_card_dylibloader_orig_asound
+#define snd_timer_ginfo_get_id snd_timer_ginfo_get_id_dylibloader_orig_asound
+#define snd_timer_ginfo_get_name snd_timer_ginfo_get_name_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution snd_timer_ginfo_get_resolution_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution_min snd_timer_ginfo_get_resolution_min_dylibloader_orig_asound
+#define snd_timer_ginfo_get_resolution_max snd_timer_ginfo_get_resolution_max_dylibloader_orig_asound
+#define snd_timer_ginfo_get_clients snd_timer_ginfo_get_clients_dylibloader_orig_asound
+#define snd_timer_info_sizeof snd_timer_info_sizeof_dylibloader_orig_asound
+#define snd_timer_info_malloc snd_timer_info_malloc_dylibloader_orig_asound
+#define snd_timer_info_free snd_timer_info_free_dylibloader_orig_asound
+#define snd_timer_info_copy snd_timer_info_copy_dylibloader_orig_asound
+#define snd_timer_info_is_slave snd_timer_info_is_slave_dylibloader_orig_asound
+#define snd_timer_info_get_card snd_timer_info_get_card_dylibloader_orig_asound
+#define snd_timer_info_get_id snd_timer_info_get_id_dylibloader_orig_asound
+#define snd_timer_info_get_name snd_timer_info_get_name_dylibloader_orig_asound
+#define snd_timer_info_get_resolution snd_timer_info_get_resolution_dylibloader_orig_asound
+#define snd_timer_params_sizeof snd_timer_params_sizeof_dylibloader_orig_asound
+#define snd_timer_params_malloc snd_timer_params_malloc_dylibloader_orig_asound
+#define snd_timer_params_free snd_timer_params_free_dylibloader_orig_asound
+#define snd_timer_params_copy snd_timer_params_copy_dylibloader_orig_asound
+#define snd_timer_params_set_auto_start snd_timer_params_set_auto_start_dylibloader_orig_asound
+#define snd_timer_params_get_auto_start snd_timer_params_get_auto_start_dylibloader_orig_asound
+#define snd_timer_params_set_exclusive snd_timer_params_set_exclusive_dylibloader_orig_asound
+#define snd_timer_params_get_exclusive snd_timer_params_get_exclusive_dylibloader_orig_asound
+#define snd_timer_params_set_early_event snd_timer_params_set_early_event_dylibloader_orig_asound
+#define snd_timer_params_get_early_event snd_timer_params_get_early_event_dylibloader_orig_asound
+#define snd_timer_params_set_ticks snd_timer_params_set_ticks_dylibloader_orig_asound
+#define snd_timer_params_get_ticks snd_timer_params_get_ticks_dylibloader_orig_asound
+#define snd_timer_params_set_queue_size snd_timer_params_set_queue_size_dylibloader_orig_asound
+#define snd_timer_params_get_queue_size snd_timer_params_get_queue_size_dylibloader_orig_asound
+#define snd_timer_params_set_filter snd_timer_params_set_filter_dylibloader_orig_asound
+#define snd_timer_params_get_filter snd_timer_params_get_filter_dylibloader_orig_asound
+#define snd_timer_status_sizeof snd_timer_status_sizeof_dylibloader_orig_asound
+#define snd_timer_status_malloc snd_timer_status_malloc_dylibloader_orig_asound
+#define snd_timer_status_free snd_timer_status_free_dylibloader_orig_asound
+#define snd_timer_status_copy snd_timer_status_copy_dylibloader_orig_asound
+#define snd_timer_status_get_timestamp snd_timer_status_get_timestamp_dylibloader_orig_asound
+#define snd_timer_status_get_resolution snd_timer_status_get_resolution_dylibloader_orig_asound
+#define snd_timer_status_get_lost snd_timer_status_get_lost_dylibloader_orig_asound
+#define snd_timer_status_get_overrun snd_timer_status_get_overrun_dylibloader_orig_asound
+#define snd_timer_status_get_queue snd_timer_status_get_queue_dylibloader_orig_asound
+#define snd_timer_info_get_ticks snd_timer_info_get_ticks_dylibloader_orig_asound
+#define snd_hwdep_open snd_hwdep_open_dylibloader_orig_asound
+#define snd_hwdep_close snd_hwdep_close_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors snd_hwdep_poll_descriptors_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors_count snd_hwdep_poll_descriptors_count_dylibloader_orig_asound
+#define snd_hwdep_poll_descriptors_revents snd_hwdep_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_hwdep_nonblock snd_hwdep_nonblock_dylibloader_orig_asound
+#define snd_hwdep_info snd_hwdep_info_dylibloader_orig_asound
+#define snd_hwdep_dsp_status snd_hwdep_dsp_status_dylibloader_orig_asound
+#define snd_hwdep_dsp_load snd_hwdep_dsp_load_dylibloader_orig_asound
+#define snd_hwdep_ioctl snd_hwdep_ioctl_dylibloader_orig_asound
+#define snd_hwdep_write snd_hwdep_write_dylibloader_orig_asound
+#define snd_hwdep_read snd_hwdep_read_dylibloader_orig_asound
+#define snd_hwdep_info_sizeof snd_hwdep_info_sizeof_dylibloader_orig_asound
+#define snd_hwdep_info_malloc snd_hwdep_info_malloc_dylibloader_orig_asound
+#define snd_hwdep_info_free snd_hwdep_info_free_dylibloader_orig_asound
+#define snd_hwdep_info_copy snd_hwdep_info_copy_dylibloader_orig_asound
+#define snd_hwdep_info_get_device snd_hwdep_info_get_device_dylibloader_orig_asound
+#define snd_hwdep_info_get_card snd_hwdep_info_get_card_dylibloader_orig_asound
+#define snd_hwdep_info_get_id snd_hwdep_info_get_id_dylibloader_orig_asound
+#define snd_hwdep_info_get_name snd_hwdep_info_get_name_dylibloader_orig_asound
+#define snd_hwdep_info_get_iface snd_hwdep_info_get_iface_dylibloader_orig_asound
+#define snd_hwdep_info_set_device snd_hwdep_info_set_device_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_sizeof snd_hwdep_dsp_status_sizeof_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_malloc snd_hwdep_dsp_status_malloc_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_free snd_hwdep_dsp_status_free_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_copy snd_hwdep_dsp_status_copy_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_version snd_hwdep_dsp_status_get_version_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_id snd_hwdep_dsp_status_get_id_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_num_dsps snd_hwdep_dsp_status_get_num_dsps_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_dsp_loaded snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_orig_asound
+#define snd_hwdep_dsp_status_get_chip_ready snd_hwdep_dsp_status_get_chip_ready_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_sizeof snd_hwdep_dsp_image_sizeof_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_malloc snd_hwdep_dsp_image_malloc_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_free snd_hwdep_dsp_image_free_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_copy snd_hwdep_dsp_image_copy_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_index snd_hwdep_dsp_image_get_index_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_name snd_hwdep_dsp_image_get_name_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_image snd_hwdep_dsp_image_get_image_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_get_length snd_hwdep_dsp_image_get_length_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_index snd_hwdep_dsp_image_set_index_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_name snd_hwdep_dsp_image_set_name_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_image snd_hwdep_dsp_image_set_image_dylibloader_orig_asound
+#define snd_hwdep_dsp_image_set_length snd_hwdep_dsp_image_set_length_dylibloader_orig_asound
+#define snd_card_load snd_card_load_dylibloader_orig_asound
+#define snd_card_next snd_card_next_dylibloader_orig_asound
+#define snd_card_get_index snd_card_get_index_dylibloader_orig_asound
+#define snd_card_get_name snd_card_get_name_dylibloader_orig_asound
+#define snd_card_get_longname snd_card_get_longname_dylibloader_orig_asound
+#define snd_device_name_hint snd_device_name_hint_dylibloader_orig_asound
+#define snd_device_name_free_hint snd_device_name_free_hint_dylibloader_orig_asound
+#define snd_device_name_get_hint snd_device_name_get_hint_dylibloader_orig_asound
+#define snd_ctl_open snd_ctl_open_dylibloader_orig_asound
+#define snd_ctl_open_lconf snd_ctl_open_lconf_dylibloader_orig_asound
+#define snd_ctl_open_fallback snd_ctl_open_fallback_dylibloader_orig_asound
+#define snd_ctl_close snd_ctl_close_dylibloader_orig_asound
+#define snd_ctl_nonblock snd_ctl_nonblock_dylibloader_orig_asound
+#define snd_async_add_ctl_handler snd_async_add_ctl_handler_dylibloader_orig_asound
+#define snd_async_handler_get_ctl snd_async_handler_get_ctl_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors_count snd_ctl_poll_descriptors_count_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors snd_ctl_poll_descriptors_dylibloader_orig_asound
+#define snd_ctl_poll_descriptors_revents snd_ctl_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_ctl_subscribe_events snd_ctl_subscribe_events_dylibloader_orig_asound
+#define snd_ctl_card_info snd_ctl_card_info_dylibloader_orig_asound
+#define snd_ctl_elem_list snd_ctl_elem_list_dylibloader_orig_asound
+#define snd_ctl_elem_info snd_ctl_elem_info_dylibloader_orig_asound
+#define snd_ctl_elem_read snd_ctl_elem_read_dylibloader_orig_asound
+#define snd_ctl_elem_write snd_ctl_elem_write_dylibloader_orig_asound
+#define snd_ctl_elem_lock snd_ctl_elem_lock_dylibloader_orig_asound
+#define snd_ctl_elem_unlock snd_ctl_elem_unlock_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_read snd_ctl_elem_tlv_read_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_write snd_ctl_elem_tlv_write_dylibloader_orig_asound
+#define snd_ctl_elem_tlv_command snd_ctl_elem_tlv_command_dylibloader_orig_asound
+#define snd_ctl_hwdep_next_device snd_ctl_hwdep_next_device_dylibloader_orig_asound
+#define snd_ctl_hwdep_info snd_ctl_hwdep_info_dylibloader_orig_asound
+#define snd_ctl_pcm_next_device snd_ctl_pcm_next_device_dylibloader_orig_asound
+#define snd_ctl_pcm_info snd_ctl_pcm_info_dylibloader_orig_asound
+#define snd_ctl_pcm_prefer_subdevice snd_ctl_pcm_prefer_subdevice_dylibloader_orig_asound
+#define snd_ctl_rawmidi_next_device snd_ctl_rawmidi_next_device_dylibloader_orig_asound
+#define snd_ctl_rawmidi_info snd_ctl_rawmidi_info_dylibloader_orig_asound
+#define snd_ctl_rawmidi_prefer_subdevice snd_ctl_rawmidi_prefer_subdevice_dylibloader_orig_asound
+#define snd_ctl_set_power_state snd_ctl_set_power_state_dylibloader_orig_asound
+#define snd_ctl_get_power_state snd_ctl_get_power_state_dylibloader_orig_asound
+#define snd_ctl_read snd_ctl_read_dylibloader_orig_asound
+#define snd_ctl_wait snd_ctl_wait_dylibloader_orig_asound
+#define snd_ctl_name snd_ctl_name_dylibloader_orig_asound
+#define snd_ctl_type snd_ctl_type_dylibloader_orig_asound
+#define snd_ctl_elem_type_name snd_ctl_elem_type_name_dylibloader_orig_asound
+#define snd_ctl_elem_iface_name snd_ctl_elem_iface_name_dylibloader_orig_asound
+#define snd_ctl_event_type_name snd_ctl_event_type_name_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_mask snd_ctl_event_elem_get_mask_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_numid snd_ctl_event_elem_get_numid_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_id snd_ctl_event_elem_get_id_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_interface snd_ctl_event_elem_get_interface_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_device snd_ctl_event_elem_get_device_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_subdevice snd_ctl_event_elem_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_name snd_ctl_event_elem_get_name_dylibloader_orig_asound
+#define snd_ctl_event_elem_get_index snd_ctl_event_elem_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_list_alloc_space snd_ctl_elem_list_alloc_space_dylibloader_orig_asound
+#define snd_ctl_elem_list_free_space snd_ctl_elem_list_free_space_dylibloader_orig_asound
+#define snd_ctl_ascii_elem_id_get snd_ctl_ascii_elem_id_get_dylibloader_orig_asound
+#define snd_ctl_ascii_elem_id_parse snd_ctl_ascii_elem_id_parse_dylibloader_orig_asound
+#define snd_ctl_ascii_value_parse snd_ctl_ascii_value_parse_dylibloader_orig_asound
+#define snd_ctl_elem_id_sizeof snd_ctl_elem_id_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_id_malloc snd_ctl_elem_id_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_id_free snd_ctl_elem_id_free_dylibloader_orig_asound
+#define snd_ctl_elem_id_clear snd_ctl_elem_id_clear_dylibloader_orig_asound
+#define snd_ctl_elem_id_copy snd_ctl_elem_id_copy_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_numid snd_ctl_elem_id_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_interface snd_ctl_elem_id_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_device snd_ctl_elem_id_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_subdevice snd_ctl_elem_id_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_name snd_ctl_elem_id_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_id_get_index snd_ctl_elem_id_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_numid snd_ctl_elem_id_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_interface snd_ctl_elem_id_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_device snd_ctl_elem_id_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_subdevice snd_ctl_elem_id_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_name snd_ctl_elem_id_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_id_set_index snd_ctl_elem_id_set_index_dylibloader_orig_asound
+#define snd_ctl_card_info_sizeof snd_ctl_card_info_sizeof_dylibloader_orig_asound
+#define snd_ctl_card_info_malloc snd_ctl_card_info_malloc_dylibloader_orig_asound
+#define snd_ctl_card_info_free snd_ctl_card_info_free_dylibloader_orig_asound
+#define snd_ctl_card_info_clear snd_ctl_card_info_clear_dylibloader_orig_asound
+#define snd_ctl_card_info_copy snd_ctl_card_info_copy_dylibloader_orig_asound
+#define snd_ctl_card_info_get_card snd_ctl_card_info_get_card_dylibloader_orig_asound
+#define snd_ctl_card_info_get_id snd_ctl_card_info_get_id_dylibloader_orig_asound
+#define snd_ctl_card_info_get_driver snd_ctl_card_info_get_driver_dylibloader_orig_asound
+#define snd_ctl_card_info_get_name snd_ctl_card_info_get_name_dylibloader_orig_asound
+#define snd_ctl_card_info_get_longname snd_ctl_card_info_get_longname_dylibloader_orig_asound
+#define snd_ctl_card_info_get_mixername snd_ctl_card_info_get_mixername_dylibloader_orig_asound
+#define snd_ctl_card_info_get_components snd_ctl_card_info_get_components_dylibloader_orig_asound
+#define snd_ctl_event_sizeof snd_ctl_event_sizeof_dylibloader_orig_asound
+#define snd_ctl_event_malloc snd_ctl_event_malloc_dylibloader_orig_asound
+#define snd_ctl_event_free snd_ctl_event_free_dylibloader_orig_asound
+#define snd_ctl_event_clear snd_ctl_event_clear_dylibloader_orig_asound
+#define snd_ctl_event_copy snd_ctl_event_copy_dylibloader_orig_asound
+#define snd_ctl_event_get_type snd_ctl_event_get_type_dylibloader_orig_asound
+#define snd_ctl_elem_list_sizeof snd_ctl_elem_list_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_list_malloc snd_ctl_elem_list_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_list_free snd_ctl_elem_list_free_dylibloader_orig_asound
+#define snd_ctl_elem_list_clear snd_ctl_elem_list_clear_dylibloader_orig_asound
+#define snd_ctl_elem_list_copy snd_ctl_elem_list_copy_dylibloader_orig_asound
+#define snd_ctl_elem_list_set_offset snd_ctl_elem_list_set_offset_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_used snd_ctl_elem_list_get_used_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_count snd_ctl_elem_list_get_count_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_id snd_ctl_elem_list_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_numid snd_ctl_elem_list_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_interface snd_ctl_elem_list_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_device snd_ctl_elem_list_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_subdevice snd_ctl_elem_list_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_name snd_ctl_elem_list_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_list_get_index snd_ctl_elem_list_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_info_sizeof snd_ctl_elem_info_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_info_malloc snd_ctl_elem_info_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_info_free snd_ctl_elem_info_free_dylibloader_orig_asound
+#define snd_ctl_elem_info_clear snd_ctl_elem_info_clear_dylibloader_orig_asound
+#define snd_ctl_elem_info_copy snd_ctl_elem_info_copy_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_type snd_ctl_elem_info_get_type_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_readable snd_ctl_elem_info_is_readable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_writable snd_ctl_elem_info_is_writable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_volatile snd_ctl_elem_info_is_volatile_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_inactive snd_ctl_elem_info_is_inactive_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_locked snd_ctl_elem_info_is_locked_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_readable snd_ctl_elem_info_is_tlv_readable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_writable snd_ctl_elem_info_is_tlv_writable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_tlv_commandable snd_ctl_elem_info_is_tlv_commandable_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_owner snd_ctl_elem_info_is_owner_dylibloader_orig_asound
+#define snd_ctl_elem_info_is_user snd_ctl_elem_info_is_user_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_owner snd_ctl_elem_info_get_owner_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_count snd_ctl_elem_info_get_count_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_min snd_ctl_elem_info_get_min_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_max snd_ctl_elem_info_get_max_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_step snd_ctl_elem_info_get_step_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_min64 snd_ctl_elem_info_get_min64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_max64 snd_ctl_elem_info_get_max64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_step64 snd_ctl_elem_info_get_step64_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_items snd_ctl_elem_info_get_items_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_item snd_ctl_elem_info_set_item_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_item_name snd_ctl_elem_info_get_item_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_dimensions snd_ctl_elem_info_get_dimensions_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_dimension snd_ctl_elem_info_get_dimension_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_dimension snd_ctl_elem_info_set_dimension_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_id snd_ctl_elem_info_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_numid snd_ctl_elem_info_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_interface snd_ctl_elem_info_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_device snd_ctl_elem_info_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_subdevice snd_ctl_elem_info_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_name snd_ctl_elem_info_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_get_index snd_ctl_elem_info_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_id snd_ctl_elem_info_set_id_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_numid snd_ctl_elem_info_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_interface snd_ctl_elem_info_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_device snd_ctl_elem_info_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_subdevice snd_ctl_elem_info_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_name snd_ctl_elem_info_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_info_set_index snd_ctl_elem_info_set_index_dylibloader_orig_asound
+#define snd_ctl_add_integer_elem_set snd_ctl_add_integer_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_integer64_elem_set snd_ctl_add_integer64_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_boolean_elem_set snd_ctl_add_boolean_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_enumerated_elem_set snd_ctl_add_enumerated_elem_set_dylibloader_orig_asound
+#define snd_ctl_add_bytes_elem_set snd_ctl_add_bytes_elem_set_dylibloader_orig_asound
+#define snd_ctl_elem_add_integer snd_ctl_elem_add_integer_dylibloader_orig_asound
+#define snd_ctl_elem_add_integer64 snd_ctl_elem_add_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_add_boolean snd_ctl_elem_add_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_add_enumerated snd_ctl_elem_add_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_add_iec958 snd_ctl_elem_add_iec958_dylibloader_orig_asound
+#define snd_ctl_elem_remove snd_ctl_elem_remove_dylibloader_orig_asound
+#define snd_ctl_elem_value_sizeof snd_ctl_elem_value_sizeof_dylibloader_orig_asound
+#define snd_ctl_elem_value_malloc snd_ctl_elem_value_malloc_dylibloader_orig_asound
+#define snd_ctl_elem_value_free snd_ctl_elem_value_free_dylibloader_orig_asound
+#define snd_ctl_elem_value_clear snd_ctl_elem_value_clear_dylibloader_orig_asound
+#define snd_ctl_elem_value_copy snd_ctl_elem_value_copy_dylibloader_orig_asound
+#define snd_ctl_elem_value_compare snd_ctl_elem_value_compare_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_id snd_ctl_elem_value_get_id_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_numid snd_ctl_elem_value_get_numid_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_interface snd_ctl_elem_value_get_interface_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_device snd_ctl_elem_value_get_device_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_subdevice snd_ctl_elem_value_get_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_name snd_ctl_elem_value_get_name_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_index snd_ctl_elem_value_get_index_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_id snd_ctl_elem_value_set_id_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_numid snd_ctl_elem_value_set_numid_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_interface snd_ctl_elem_value_set_interface_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_device snd_ctl_elem_value_set_device_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_subdevice snd_ctl_elem_value_set_subdevice_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_name snd_ctl_elem_value_set_name_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_index snd_ctl_elem_value_set_index_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_boolean snd_ctl_elem_value_get_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_integer snd_ctl_elem_value_get_integer_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_integer64 snd_ctl_elem_value_get_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_enumerated snd_ctl_elem_value_get_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_byte snd_ctl_elem_value_get_byte_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_boolean snd_ctl_elem_value_set_boolean_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_integer snd_ctl_elem_value_set_integer_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_integer64 snd_ctl_elem_value_set_integer64_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_enumerated snd_ctl_elem_value_set_enumerated_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_byte snd_ctl_elem_value_set_byte_dylibloader_orig_asound
+#define snd_ctl_elem_set_bytes snd_ctl_elem_set_bytes_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_bytes snd_ctl_elem_value_get_bytes_dylibloader_orig_asound
+#define snd_ctl_elem_value_get_iec958 snd_ctl_elem_value_get_iec958_dylibloader_orig_asound
+#define snd_ctl_elem_value_set_iec958 snd_ctl_elem_value_set_iec958_dylibloader_orig_asound
+#define snd_tlv_parse_dB_info snd_tlv_parse_dB_info_dylibloader_orig_asound
+#define snd_tlv_get_dB_range snd_tlv_get_dB_range_dylibloader_orig_asound
+#define snd_tlv_convert_to_dB snd_tlv_convert_to_dB_dylibloader_orig_asound
+#define snd_tlv_convert_from_dB snd_tlv_convert_from_dB_dylibloader_orig_asound
+#define snd_ctl_get_dB_range snd_ctl_get_dB_range_dylibloader_orig_asound
+#define snd_ctl_convert_to_dB snd_ctl_convert_to_dB_dylibloader_orig_asound
+#define snd_ctl_convert_from_dB snd_ctl_convert_from_dB_dylibloader_orig_asound
+#define snd_hctl_compare_fast snd_hctl_compare_fast_dylibloader_orig_asound
+#define snd_hctl_open snd_hctl_open_dylibloader_orig_asound
+#define snd_hctl_open_ctl snd_hctl_open_ctl_dylibloader_orig_asound
+#define snd_hctl_close snd_hctl_close_dylibloader_orig_asound
+#define snd_hctl_nonblock snd_hctl_nonblock_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors_count snd_hctl_poll_descriptors_count_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors snd_hctl_poll_descriptors_dylibloader_orig_asound
+#define snd_hctl_poll_descriptors_revents snd_hctl_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_hctl_get_count snd_hctl_get_count_dylibloader_orig_asound
+#define snd_hctl_set_compare snd_hctl_set_compare_dylibloader_orig_asound
+#define snd_hctl_first_elem snd_hctl_first_elem_dylibloader_orig_asound
+#define snd_hctl_last_elem snd_hctl_last_elem_dylibloader_orig_asound
+#define snd_hctl_find_elem snd_hctl_find_elem_dylibloader_orig_asound
+#define snd_hctl_set_callback snd_hctl_set_callback_dylibloader_orig_asound
+#define snd_hctl_set_callback_private snd_hctl_set_callback_private_dylibloader_orig_asound
+#define snd_hctl_get_callback_private snd_hctl_get_callback_private_dylibloader_orig_asound
+#define snd_hctl_load snd_hctl_load_dylibloader_orig_asound
+#define snd_hctl_free snd_hctl_free_dylibloader_orig_asound
+#define snd_hctl_handle_events snd_hctl_handle_events_dylibloader_orig_asound
+#define snd_hctl_name snd_hctl_name_dylibloader_orig_asound
+#define snd_hctl_wait snd_hctl_wait_dylibloader_orig_asound
+#define snd_hctl_ctl snd_hctl_ctl_dylibloader_orig_asound
+#define snd_hctl_elem_next snd_hctl_elem_next_dylibloader_orig_asound
+#define snd_hctl_elem_prev snd_hctl_elem_prev_dylibloader_orig_asound
+#define snd_hctl_elem_info snd_hctl_elem_info_dylibloader_orig_asound
+#define snd_hctl_elem_read snd_hctl_elem_read_dylibloader_orig_asound
+#define snd_hctl_elem_write snd_hctl_elem_write_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_read snd_hctl_elem_tlv_read_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_write snd_hctl_elem_tlv_write_dylibloader_orig_asound
+#define snd_hctl_elem_tlv_command snd_hctl_elem_tlv_command_dylibloader_orig_asound
+#define snd_hctl_elem_get_hctl snd_hctl_elem_get_hctl_dylibloader_orig_asound
+#define snd_hctl_elem_get_id snd_hctl_elem_get_id_dylibloader_orig_asound
+#define snd_hctl_elem_get_numid snd_hctl_elem_get_numid_dylibloader_orig_asound
+#define snd_hctl_elem_get_interface snd_hctl_elem_get_interface_dylibloader_orig_asound
+#define snd_hctl_elem_get_device snd_hctl_elem_get_device_dylibloader_orig_asound
+#define snd_hctl_elem_get_subdevice snd_hctl_elem_get_subdevice_dylibloader_orig_asound
+#define snd_hctl_elem_get_name snd_hctl_elem_get_name_dylibloader_orig_asound
+#define snd_hctl_elem_get_index snd_hctl_elem_get_index_dylibloader_orig_asound
+#define snd_hctl_elem_set_callback snd_hctl_elem_set_callback_dylibloader_orig_asound
+#define snd_hctl_elem_get_callback_private snd_hctl_elem_get_callback_private_dylibloader_orig_asound
+#define snd_hctl_elem_set_callback_private snd_hctl_elem_set_callback_private_dylibloader_orig_asound
+#define snd_sctl_build snd_sctl_build_dylibloader_orig_asound
+#define snd_sctl_free snd_sctl_free_dylibloader_orig_asound
+#define snd_sctl_install snd_sctl_install_dylibloader_orig_asound
+#define snd_sctl_remove snd_sctl_remove_dylibloader_orig_asound
+#define snd_mixer_open snd_mixer_open_dylibloader_orig_asound
+#define snd_mixer_close snd_mixer_close_dylibloader_orig_asound
+#define snd_mixer_first_elem snd_mixer_first_elem_dylibloader_orig_asound
+#define snd_mixer_last_elem snd_mixer_last_elem_dylibloader_orig_asound
+#define snd_mixer_handle_events snd_mixer_handle_events_dylibloader_orig_asound
+#define snd_mixer_attach snd_mixer_attach_dylibloader_orig_asound
+#define snd_mixer_attach_hctl snd_mixer_attach_hctl_dylibloader_orig_asound
+#define snd_mixer_detach snd_mixer_detach_dylibloader_orig_asound
+#define snd_mixer_detach_hctl snd_mixer_detach_hctl_dylibloader_orig_asound
+#define snd_mixer_get_hctl snd_mixer_get_hctl_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors_count snd_mixer_poll_descriptors_count_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors snd_mixer_poll_descriptors_dylibloader_orig_asound
+#define snd_mixer_poll_descriptors_revents snd_mixer_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_mixer_load snd_mixer_load_dylibloader_orig_asound
+#define snd_mixer_free snd_mixer_free_dylibloader_orig_asound
+#define snd_mixer_wait snd_mixer_wait_dylibloader_orig_asound
+#define snd_mixer_set_compare snd_mixer_set_compare_dylibloader_orig_asound
+#define snd_mixer_set_callback snd_mixer_set_callback_dylibloader_orig_asound
+#define snd_mixer_get_callback_private snd_mixer_get_callback_private_dylibloader_orig_asound
+#define snd_mixer_set_callback_private snd_mixer_set_callback_private_dylibloader_orig_asound
+#define snd_mixer_get_count snd_mixer_get_count_dylibloader_orig_asound
+#define snd_mixer_class_unregister snd_mixer_class_unregister_dylibloader_orig_asound
+#define snd_mixer_elem_next snd_mixer_elem_next_dylibloader_orig_asound
+#define snd_mixer_elem_prev snd_mixer_elem_prev_dylibloader_orig_asound
+#define snd_mixer_elem_set_callback snd_mixer_elem_set_callback_dylibloader_orig_asound
+#define snd_mixer_elem_get_callback_private snd_mixer_elem_get_callback_private_dylibloader_orig_asound
+#define snd_mixer_elem_set_callback_private snd_mixer_elem_set_callback_private_dylibloader_orig_asound
+#define snd_mixer_elem_get_type snd_mixer_elem_get_type_dylibloader_orig_asound
+#define snd_mixer_class_register snd_mixer_class_register_dylibloader_orig_asound
+#define snd_mixer_elem_new snd_mixer_elem_new_dylibloader_orig_asound
+#define snd_mixer_elem_add snd_mixer_elem_add_dylibloader_orig_asound
+#define snd_mixer_elem_remove snd_mixer_elem_remove_dylibloader_orig_asound
+#define snd_mixer_elem_free snd_mixer_elem_free_dylibloader_orig_asound
+#define snd_mixer_elem_info snd_mixer_elem_info_dylibloader_orig_asound
+#define snd_mixer_elem_value snd_mixer_elem_value_dylibloader_orig_asound
+#define snd_mixer_elem_attach snd_mixer_elem_attach_dylibloader_orig_asound
+#define snd_mixer_elem_detach snd_mixer_elem_detach_dylibloader_orig_asound
+#define snd_mixer_elem_empty snd_mixer_elem_empty_dylibloader_orig_asound
+#define snd_mixer_elem_get_private snd_mixer_elem_get_private_dylibloader_orig_asound
+#define snd_mixer_class_sizeof snd_mixer_class_sizeof_dylibloader_orig_asound
+#define snd_mixer_class_malloc snd_mixer_class_malloc_dylibloader_orig_asound
+#define snd_mixer_class_free snd_mixer_class_free_dylibloader_orig_asound
+#define snd_mixer_class_copy snd_mixer_class_copy_dylibloader_orig_asound
+#define snd_mixer_class_get_mixer snd_mixer_class_get_mixer_dylibloader_orig_asound
+#define snd_mixer_class_get_event snd_mixer_class_get_event_dylibloader_orig_asound
+#define snd_mixer_class_get_private snd_mixer_class_get_private_dylibloader_orig_asound
+#define snd_mixer_class_get_compare snd_mixer_class_get_compare_dylibloader_orig_asound
+#define snd_mixer_class_set_event snd_mixer_class_set_event_dylibloader_orig_asound
+#define snd_mixer_class_set_private snd_mixer_class_set_private_dylibloader_orig_asound
+#define snd_mixer_class_set_private_free snd_mixer_class_set_private_free_dylibloader_orig_asound
+#define snd_mixer_class_set_compare snd_mixer_class_set_compare_dylibloader_orig_asound
+#define snd_mixer_selem_channel_name snd_mixer_selem_channel_name_dylibloader_orig_asound
+#define snd_mixer_selem_register snd_mixer_selem_register_dylibloader_orig_asound
+#define snd_mixer_selem_get_id snd_mixer_selem_get_id_dylibloader_orig_asound
+#define snd_mixer_selem_get_name snd_mixer_selem_get_name_dylibloader_orig_asound
+#define snd_mixer_selem_get_index snd_mixer_selem_get_index_dylibloader_orig_asound
+#define snd_mixer_find_selem snd_mixer_find_selem_dylibloader_orig_asound
+#define snd_mixer_selem_is_active snd_mixer_selem_is_active_dylibloader_orig_asound
+#define snd_mixer_selem_is_playback_mono snd_mixer_selem_is_playback_mono_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_channel snd_mixer_selem_has_playback_channel_dylibloader_orig_asound
+#define snd_mixer_selem_is_capture_mono snd_mixer_selem_is_capture_mono_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_channel snd_mixer_selem_has_capture_channel_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_group snd_mixer_selem_get_capture_group_dylibloader_orig_asound
+#define snd_mixer_selem_has_common_volume snd_mixer_selem_has_common_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_volume snd_mixer_selem_has_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_volume_joined snd_mixer_selem_has_playback_volume_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_volume snd_mixer_selem_has_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_volume_joined snd_mixer_selem_has_capture_volume_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_common_switch snd_mixer_selem_has_common_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_switch snd_mixer_selem_has_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_playback_switch_joined snd_mixer_selem_has_playback_switch_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch snd_mixer_selem_has_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch_joined snd_mixer_selem_has_capture_switch_joined_dylibloader_orig_asound
+#define snd_mixer_selem_has_capture_switch_exclusive snd_mixer_selem_has_capture_switch_exclusive_dylibloader_orig_asound
+#define snd_mixer_selem_ask_playback_vol_dB snd_mixer_selem_ask_playback_vol_dB_dylibloader_orig_asound
+#define snd_mixer_selem_ask_capture_vol_dB snd_mixer_selem_ask_capture_vol_dB_dylibloader_orig_asound
+#define snd_mixer_selem_ask_playback_dB_vol snd_mixer_selem_ask_playback_dB_vol_dylibloader_orig_asound
+#define snd_mixer_selem_ask_capture_dB_vol snd_mixer_selem_ask_capture_dB_vol_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_volume snd_mixer_selem_get_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_volume snd_mixer_selem_get_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_dB snd_mixer_selem_get_playback_dB_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_dB snd_mixer_selem_get_capture_dB_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_switch snd_mixer_selem_get_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_switch snd_mixer_selem_get_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume snd_mixer_selem_set_playback_volume_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume snd_mixer_selem_set_capture_volume_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_dB snd_mixer_selem_set_playback_dB_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_dB snd_mixer_selem_set_capture_dB_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume_all snd_mixer_selem_set_playback_volume_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume_all snd_mixer_selem_set_capture_volume_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_dB_all snd_mixer_selem_set_playback_dB_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_dB_all snd_mixer_selem_set_capture_dB_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_switch snd_mixer_selem_set_playback_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_switch snd_mixer_selem_set_capture_switch_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_switch_all snd_mixer_selem_set_playback_switch_all_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_switch_all snd_mixer_selem_set_capture_switch_all_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_volume_range snd_mixer_selem_get_playback_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_playback_dB_range snd_mixer_selem_get_playback_dB_range_dylibloader_orig_asound
+#define snd_mixer_selem_set_playback_volume_range snd_mixer_selem_set_playback_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_volume_range snd_mixer_selem_get_capture_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_get_capture_dB_range snd_mixer_selem_get_capture_dB_range_dylibloader_orig_asound
+#define snd_mixer_selem_set_capture_volume_range snd_mixer_selem_set_capture_volume_range_dylibloader_orig_asound
+#define snd_mixer_selem_is_enumerated snd_mixer_selem_is_enumerated_dylibloader_orig_asound
+#define snd_mixer_selem_is_enum_playback snd_mixer_selem_is_enum_playback_dylibloader_orig_asound
+#define snd_mixer_selem_is_enum_capture snd_mixer_selem_is_enum_capture_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_items snd_mixer_selem_get_enum_items_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_item_name snd_mixer_selem_get_enum_item_name_dylibloader_orig_asound
+#define snd_mixer_selem_get_enum_item snd_mixer_selem_get_enum_item_dylibloader_orig_asound
+#define snd_mixer_selem_set_enum_item snd_mixer_selem_set_enum_item_dylibloader_orig_asound
+#define snd_mixer_selem_id_sizeof snd_mixer_selem_id_sizeof_dylibloader_orig_asound
+#define snd_mixer_selem_id_malloc snd_mixer_selem_id_malloc_dylibloader_orig_asound
+#define snd_mixer_selem_id_free snd_mixer_selem_id_free_dylibloader_orig_asound
+#define snd_mixer_selem_id_copy snd_mixer_selem_id_copy_dylibloader_orig_asound
+#define snd_mixer_selem_id_get_name snd_mixer_selem_id_get_name_dylibloader_orig_asound
+#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_orig_asound
+#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_orig_asound
+#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_orig_asound
+#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_orig_asound
+#define snd_seq_open snd_seq_open_dylibloader_orig_asound
+#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_orig_asound
+#define snd_seq_name snd_seq_name_dylibloader_orig_asound
+#define snd_seq_type snd_seq_type_dylibloader_orig_asound
+#define snd_seq_close snd_seq_close_dylibloader_orig_asound
+#define snd_seq_poll_descriptors_count snd_seq_poll_descriptors_count_dylibloader_orig_asound
+#define snd_seq_poll_descriptors snd_seq_poll_descriptors_dylibloader_orig_asound
+#define snd_seq_poll_descriptors_revents snd_seq_poll_descriptors_revents_dylibloader_orig_asound
+#define snd_seq_nonblock snd_seq_nonblock_dylibloader_orig_asound
+#define snd_seq_client_id snd_seq_client_id_dylibloader_orig_asound
+#define snd_seq_get_output_buffer_size snd_seq_get_output_buffer_size_dylibloader_orig_asound
+#define snd_seq_get_input_buffer_size snd_seq_get_input_buffer_size_dylibloader_orig_asound
+#define snd_seq_set_output_buffer_size snd_seq_set_output_buffer_size_dylibloader_orig_asound
+#define snd_seq_set_input_buffer_size snd_seq_set_input_buffer_size_dylibloader_orig_asound
+#define snd_seq_system_info_sizeof snd_seq_system_info_sizeof_dylibloader_orig_asound
+#define snd_seq_system_info_malloc snd_seq_system_info_malloc_dylibloader_orig_asound
+#define snd_seq_system_info_free snd_seq_system_info_free_dylibloader_orig_asound
+#define snd_seq_system_info_copy snd_seq_system_info_copy_dylibloader_orig_asound
+#define snd_seq_system_info_get_queues snd_seq_system_info_get_queues_dylibloader_orig_asound
+#define snd_seq_system_info_get_clients snd_seq_system_info_get_clients_dylibloader_orig_asound
+#define snd_seq_system_info_get_ports snd_seq_system_info_get_ports_dylibloader_orig_asound
+#define snd_seq_system_info_get_channels snd_seq_system_info_get_channels_dylibloader_orig_asound
+#define snd_seq_system_info_get_cur_clients snd_seq_system_info_get_cur_clients_dylibloader_orig_asound
+#define snd_seq_system_info_get_cur_queues snd_seq_system_info_get_cur_queues_dylibloader_orig_asound
+#define snd_seq_system_info snd_seq_system_info_dylibloader_orig_asound
+#define snd_seq_client_info_sizeof snd_seq_client_info_sizeof_dylibloader_orig_asound
+#define snd_seq_client_info_malloc snd_seq_client_info_malloc_dylibloader_orig_asound
+#define snd_seq_client_info_free snd_seq_client_info_free_dylibloader_orig_asound
+#define snd_seq_client_info_copy snd_seq_client_info_copy_dylibloader_orig_asound
+#define snd_seq_client_info_get_client snd_seq_client_info_get_client_dylibloader_orig_asound
+#define snd_seq_client_info_get_type snd_seq_client_info_get_type_dylibloader_orig_asound
+#define snd_seq_client_info_get_name snd_seq_client_info_get_name_dylibloader_orig_asound
+#define snd_seq_client_info_get_broadcast_filter snd_seq_client_info_get_broadcast_filter_dylibloader_orig_asound
+#define snd_seq_client_info_get_error_bounce snd_seq_client_info_get_error_bounce_dylibloader_orig_asound
+#define snd_seq_client_info_get_card snd_seq_client_info_get_card_dylibloader_orig_asound
+#define snd_seq_client_info_get_pid snd_seq_client_info_get_pid_dylibloader_orig_asound
+#define snd_seq_client_info_get_event_filter snd_seq_client_info_get_event_filter_dylibloader_orig_asound
+#define snd_seq_client_info_get_num_ports snd_seq_client_info_get_num_ports_dylibloader_orig_asound
+#define snd_seq_client_info_get_event_lost snd_seq_client_info_get_event_lost_dylibloader_orig_asound
+#define snd_seq_client_info_set_client snd_seq_client_info_set_client_dylibloader_orig_asound
+#define snd_seq_client_info_set_name snd_seq_client_info_set_name_dylibloader_orig_asound
+#define snd_seq_client_info_set_broadcast_filter snd_seq_client_info_set_broadcast_filter_dylibloader_orig_asound
+#define snd_seq_client_info_set_error_bounce snd_seq_client_info_set_error_bounce_dylibloader_orig_asound
+#define snd_seq_client_info_set_event_filter snd_seq_client_info_set_event_filter_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_clear snd_seq_client_info_event_filter_clear_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_add snd_seq_client_info_event_filter_add_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_del snd_seq_client_info_event_filter_del_dylibloader_orig_asound
+#define snd_seq_client_info_event_filter_check snd_seq_client_info_event_filter_check_dylibloader_orig_asound
+#define snd_seq_get_client_info snd_seq_get_client_info_dylibloader_orig_asound
+#define snd_seq_get_any_client_info snd_seq_get_any_client_info_dylibloader_orig_asound
+#define snd_seq_set_client_info snd_seq_set_client_info_dylibloader_orig_asound
+#define snd_seq_query_next_client snd_seq_query_next_client_dylibloader_orig_asound
+#define snd_seq_client_pool_sizeof snd_seq_client_pool_sizeof_dylibloader_orig_asound
+#define snd_seq_client_pool_malloc snd_seq_client_pool_malloc_dylibloader_orig_asound
+#define snd_seq_client_pool_free snd_seq_client_pool_free_dylibloader_orig_asound
+#define snd_seq_client_pool_copy snd_seq_client_pool_copy_dylibloader_orig_asound
+#define snd_seq_client_pool_get_client snd_seq_client_pool_get_client_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_pool snd_seq_client_pool_get_output_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_get_input_pool snd_seq_client_pool_get_input_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_room snd_seq_client_pool_get_output_room_dylibloader_orig_asound
+#define snd_seq_client_pool_get_output_free snd_seq_client_pool_get_output_free_dylibloader_orig_asound
+#define snd_seq_client_pool_get_input_free snd_seq_client_pool_get_input_free_dylibloader_orig_asound
+#define snd_seq_client_pool_set_output_pool snd_seq_client_pool_set_output_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_set_input_pool snd_seq_client_pool_set_input_pool_dylibloader_orig_asound
+#define snd_seq_client_pool_set_output_room snd_seq_client_pool_set_output_room_dylibloader_orig_asound
+#define snd_seq_get_client_pool snd_seq_get_client_pool_dylibloader_orig_asound
+#define snd_seq_set_client_pool snd_seq_set_client_pool_dylibloader_orig_asound
+#define snd_seq_port_info_sizeof snd_seq_port_info_sizeof_dylibloader_orig_asound
+#define snd_seq_port_info_malloc snd_seq_port_info_malloc_dylibloader_orig_asound
+#define snd_seq_port_info_free snd_seq_port_info_free_dylibloader_orig_asound
+#define snd_seq_port_info_copy snd_seq_port_info_copy_dylibloader_orig_asound
+#define snd_seq_port_info_get_client snd_seq_port_info_get_client_dylibloader_orig_asound
+#define snd_seq_port_info_get_port snd_seq_port_info_get_port_dylibloader_orig_asound
+#define snd_seq_port_info_get_addr snd_seq_port_info_get_addr_dylibloader_orig_asound
+#define snd_seq_port_info_get_name snd_seq_port_info_get_name_dylibloader_orig_asound
+#define snd_seq_port_info_get_capability snd_seq_port_info_get_capability_dylibloader_orig_asound
+#define snd_seq_port_info_get_type snd_seq_port_info_get_type_dylibloader_orig_asound
+#define snd_seq_port_info_get_midi_channels snd_seq_port_info_get_midi_channels_dylibloader_orig_asound
+#define snd_seq_port_info_get_midi_voices snd_seq_port_info_get_midi_voices_dylibloader_orig_asound
+#define snd_seq_port_info_get_synth_voices snd_seq_port_info_get_synth_voices_dylibloader_orig_asound
+#define snd_seq_port_info_get_read_use snd_seq_port_info_get_read_use_dylibloader_orig_asound
+#define snd_seq_port_info_get_write_use snd_seq_port_info_get_write_use_dylibloader_orig_asound
+#define snd_seq_port_info_get_port_specified snd_seq_port_info_get_port_specified_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamping snd_seq_port_info_get_timestamping_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamp_real snd_seq_port_info_get_timestamp_real_dylibloader_orig_asound
+#define snd_seq_port_info_get_timestamp_queue snd_seq_port_info_get_timestamp_queue_dylibloader_orig_asound
+#define snd_seq_port_info_set_client snd_seq_port_info_set_client_dylibloader_orig_asound
+#define snd_seq_port_info_set_port snd_seq_port_info_set_port_dylibloader_orig_asound
+#define snd_seq_port_info_set_addr snd_seq_port_info_set_addr_dylibloader_orig_asound
+#define snd_seq_port_info_set_name snd_seq_port_info_set_name_dylibloader_orig_asound
+#define snd_seq_port_info_set_capability snd_seq_port_info_set_capability_dylibloader_orig_asound
+#define snd_seq_port_info_set_type snd_seq_port_info_set_type_dylibloader_orig_asound
+#define snd_seq_port_info_set_midi_channels snd_seq_port_info_set_midi_channels_dylibloader_orig_asound
+#define snd_seq_port_info_set_midi_voices snd_seq_port_info_set_midi_voices_dylibloader_orig_asound
+#define snd_seq_port_info_set_synth_voices snd_seq_port_info_set_synth_voices_dylibloader_orig_asound
+#define snd_seq_port_info_set_port_specified snd_seq_port_info_set_port_specified_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamping snd_seq_port_info_set_timestamping_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamp_real snd_seq_port_info_set_timestamp_real_dylibloader_orig_asound
+#define snd_seq_port_info_set_timestamp_queue snd_seq_port_info_set_timestamp_queue_dylibloader_orig_asound
+#define snd_seq_create_port snd_seq_create_port_dylibloader_orig_asound
+#define snd_seq_delete_port snd_seq_delete_port_dylibloader_orig_asound
+#define snd_seq_get_port_info snd_seq_get_port_info_dylibloader_orig_asound
+#define snd_seq_get_any_port_info snd_seq_get_any_port_info_dylibloader_orig_asound
+#define snd_seq_set_port_info snd_seq_set_port_info_dylibloader_orig_asound
+#define snd_seq_query_next_port snd_seq_query_next_port_dylibloader_orig_asound
+#define snd_seq_port_subscribe_sizeof snd_seq_port_subscribe_sizeof_dylibloader_orig_asound
+#define snd_seq_port_subscribe_malloc snd_seq_port_subscribe_malloc_dylibloader_orig_asound
+#define snd_seq_port_subscribe_free snd_seq_port_subscribe_free_dylibloader_orig_asound
+#define snd_seq_port_subscribe_copy snd_seq_port_subscribe_copy_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_sender snd_seq_port_subscribe_get_sender_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_dest snd_seq_port_subscribe_get_dest_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_queue snd_seq_port_subscribe_get_queue_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_exclusive snd_seq_port_subscribe_get_exclusive_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_time_update snd_seq_port_subscribe_get_time_update_dylibloader_orig_asound
+#define snd_seq_port_subscribe_get_time_real snd_seq_port_subscribe_get_time_real_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_sender snd_seq_port_subscribe_set_sender_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_dest snd_seq_port_subscribe_set_dest_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_queue snd_seq_port_subscribe_set_queue_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_exclusive snd_seq_port_subscribe_set_exclusive_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_time_update snd_seq_port_subscribe_set_time_update_dylibloader_orig_asound
+#define snd_seq_port_subscribe_set_time_real snd_seq_port_subscribe_set_time_real_dylibloader_orig_asound
+#define snd_seq_get_port_subscription snd_seq_get_port_subscription_dylibloader_orig_asound
+#define snd_seq_subscribe_port snd_seq_subscribe_port_dylibloader_orig_asound
+#define snd_seq_unsubscribe_port snd_seq_unsubscribe_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_sizeof snd_seq_query_subscribe_sizeof_dylibloader_orig_asound
+#define snd_seq_query_subscribe_malloc snd_seq_query_subscribe_malloc_dylibloader_orig_asound
+#define snd_seq_query_subscribe_free snd_seq_query_subscribe_free_dylibloader_orig_asound
+#define snd_seq_query_subscribe_copy snd_seq_query_subscribe_copy_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_client snd_seq_query_subscribe_get_client_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_port snd_seq_query_subscribe_get_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_root snd_seq_query_subscribe_get_root_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_type snd_seq_query_subscribe_get_type_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_index snd_seq_query_subscribe_get_index_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_num_subs snd_seq_query_subscribe_get_num_subs_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_addr snd_seq_query_subscribe_get_addr_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_queue snd_seq_query_subscribe_get_queue_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_exclusive snd_seq_query_subscribe_get_exclusive_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_time_update snd_seq_query_subscribe_get_time_update_dylibloader_orig_asound
+#define snd_seq_query_subscribe_get_time_real snd_seq_query_subscribe_get_time_real_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_client snd_seq_query_subscribe_set_client_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_port snd_seq_query_subscribe_set_port_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_root snd_seq_query_subscribe_set_root_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_type snd_seq_query_subscribe_set_type_dylibloader_orig_asound
+#define snd_seq_query_subscribe_set_index snd_seq_query_subscribe_set_index_dylibloader_orig_asound
+#define snd_seq_query_port_subscribers snd_seq_query_port_subscribers_dylibloader_orig_asound
+#define snd_seq_queue_info_sizeof snd_seq_queue_info_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_info_malloc snd_seq_queue_info_malloc_dylibloader_orig_asound
+#define snd_seq_queue_info_free snd_seq_queue_info_free_dylibloader_orig_asound
+#define snd_seq_queue_info_copy snd_seq_queue_info_copy_dylibloader_orig_asound
+#define snd_seq_queue_info_get_queue snd_seq_queue_info_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_info_get_name snd_seq_queue_info_get_name_dylibloader_orig_asound
+#define snd_seq_queue_info_get_owner snd_seq_queue_info_get_owner_dylibloader_orig_asound
+#define snd_seq_queue_info_get_locked snd_seq_queue_info_get_locked_dylibloader_orig_asound
+#define snd_seq_queue_info_get_flags snd_seq_queue_info_get_flags_dylibloader_orig_asound
+#define snd_seq_queue_info_set_name snd_seq_queue_info_set_name_dylibloader_orig_asound
+#define snd_seq_queue_info_set_owner snd_seq_queue_info_set_owner_dylibloader_orig_asound
+#define snd_seq_queue_info_set_locked snd_seq_queue_info_set_locked_dylibloader_orig_asound
+#define snd_seq_queue_info_set_flags snd_seq_queue_info_set_flags_dylibloader_orig_asound
+#define snd_seq_create_queue snd_seq_create_queue_dylibloader_orig_asound
+#define snd_seq_alloc_named_queue snd_seq_alloc_named_queue_dylibloader_orig_asound
+#define snd_seq_alloc_queue snd_seq_alloc_queue_dylibloader_orig_asound
+#define snd_seq_free_queue snd_seq_free_queue_dylibloader_orig_asound
+#define snd_seq_get_queue_info snd_seq_get_queue_info_dylibloader_orig_asound
+#define snd_seq_set_queue_info snd_seq_set_queue_info_dylibloader_orig_asound
+#define snd_seq_query_named_queue snd_seq_query_named_queue_dylibloader_orig_asound
+#define snd_seq_get_queue_usage snd_seq_get_queue_usage_dylibloader_orig_asound
+#define snd_seq_set_queue_usage snd_seq_set_queue_usage_dylibloader_orig_asound
+#define snd_seq_queue_status_sizeof snd_seq_queue_status_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_status_malloc snd_seq_queue_status_malloc_dylibloader_orig_asound
+#define snd_seq_queue_status_free snd_seq_queue_status_free_dylibloader_orig_asound
+#define snd_seq_queue_status_copy snd_seq_queue_status_copy_dylibloader_orig_asound
+#define snd_seq_queue_status_get_queue snd_seq_queue_status_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_status_get_events snd_seq_queue_status_get_events_dylibloader_orig_asound
+#define snd_seq_queue_status_get_tick_time snd_seq_queue_status_get_tick_time_dylibloader_orig_asound
+#define snd_seq_queue_status_get_real_time snd_seq_queue_status_get_real_time_dylibloader_orig_asound
+#define snd_seq_queue_status_get_status snd_seq_queue_status_get_status_dylibloader_orig_asound
+#define snd_seq_get_queue_status snd_seq_get_queue_status_dylibloader_orig_asound
+#define snd_seq_queue_tempo_sizeof snd_seq_queue_tempo_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_tempo_malloc snd_seq_queue_tempo_malloc_dylibloader_orig_asound
+#define snd_seq_queue_tempo_free snd_seq_queue_tempo_free_dylibloader_orig_asound
+#define snd_seq_queue_tempo_copy snd_seq_queue_tempo_copy_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_queue snd_seq_queue_tempo_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_tempo snd_seq_queue_tempo_get_tempo_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_ppq snd_seq_queue_tempo_get_ppq_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_skew snd_seq_queue_tempo_get_skew_dylibloader_orig_asound
+#define snd_seq_queue_tempo_get_skew_base snd_seq_queue_tempo_get_skew_base_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_tempo snd_seq_queue_tempo_set_tempo_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_ppq snd_seq_queue_tempo_set_ppq_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_skew snd_seq_queue_tempo_set_skew_dylibloader_orig_asound
+#define snd_seq_queue_tempo_set_skew_base snd_seq_queue_tempo_set_skew_base_dylibloader_orig_asound
+#define snd_seq_get_queue_tempo snd_seq_get_queue_tempo_dylibloader_orig_asound
+#define snd_seq_set_queue_tempo snd_seq_set_queue_tempo_dylibloader_orig_asound
+#define snd_seq_queue_timer_sizeof snd_seq_queue_timer_sizeof_dylibloader_orig_asound
+#define snd_seq_queue_timer_malloc snd_seq_queue_timer_malloc_dylibloader_orig_asound
+#define snd_seq_queue_timer_free snd_seq_queue_timer_free_dylibloader_orig_asound
+#define snd_seq_queue_timer_copy snd_seq_queue_timer_copy_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_queue snd_seq_queue_timer_get_queue_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_type snd_seq_queue_timer_get_type_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_id snd_seq_queue_timer_get_id_dylibloader_orig_asound
+#define snd_seq_queue_timer_get_resolution snd_seq_queue_timer_get_resolution_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_type snd_seq_queue_timer_set_type_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_id snd_seq_queue_timer_set_id_dylibloader_orig_asound
+#define snd_seq_queue_timer_set_resolution snd_seq_queue_timer_set_resolution_dylibloader_orig_asound
+#define snd_seq_get_queue_timer snd_seq_get_queue_timer_dylibloader_orig_asound
+#define snd_seq_set_queue_timer snd_seq_set_queue_timer_dylibloader_orig_asound
+#define snd_seq_free_event snd_seq_free_event_dylibloader_orig_asound
+#define snd_seq_event_length snd_seq_event_length_dylibloader_orig_asound
+#define snd_seq_event_output snd_seq_event_output_dylibloader_orig_asound
+#define snd_seq_event_output_buffer snd_seq_event_output_buffer_dylibloader_orig_asound
+#define snd_seq_event_output_direct snd_seq_event_output_direct_dylibloader_orig_asound
+#define snd_seq_event_input snd_seq_event_input_dylibloader_orig_asound
+#define snd_seq_event_input_pending snd_seq_event_input_pending_dylibloader_orig_asound
+#define snd_seq_drain_output snd_seq_drain_output_dylibloader_orig_asound
+#define snd_seq_event_output_pending snd_seq_event_output_pending_dylibloader_orig_asound
+#define snd_seq_extract_output snd_seq_extract_output_dylibloader_orig_asound
+#define snd_seq_drop_output snd_seq_drop_output_dylibloader_orig_asound
+#define snd_seq_drop_output_buffer snd_seq_drop_output_buffer_dylibloader_orig_asound
+#define snd_seq_drop_input snd_seq_drop_input_dylibloader_orig_asound
+#define snd_seq_drop_input_buffer snd_seq_drop_input_buffer_dylibloader_orig_asound
+#define snd_seq_remove_events_sizeof snd_seq_remove_events_sizeof_dylibloader_orig_asound
+#define snd_seq_remove_events_malloc snd_seq_remove_events_malloc_dylibloader_orig_asound
+#define snd_seq_remove_events_free snd_seq_remove_events_free_dylibloader_orig_asound
+#define snd_seq_remove_events_copy snd_seq_remove_events_copy_dylibloader_orig_asound
+#define snd_seq_remove_events_get_condition snd_seq_remove_events_get_condition_dylibloader_orig_asound
+#define snd_seq_remove_events_get_queue snd_seq_remove_events_get_queue_dylibloader_orig_asound
+#define snd_seq_remove_events_get_time snd_seq_remove_events_get_time_dylibloader_orig_asound
+#define snd_seq_remove_events_get_dest snd_seq_remove_events_get_dest_dylibloader_orig_asound
+#define snd_seq_remove_events_get_channel snd_seq_remove_events_get_channel_dylibloader_orig_asound
+#define snd_seq_remove_events_get_event_type snd_seq_remove_events_get_event_type_dylibloader_orig_asound
+#define snd_seq_remove_events_get_tag snd_seq_remove_events_get_tag_dylibloader_orig_asound
+#define snd_seq_remove_events_set_condition snd_seq_remove_events_set_condition_dylibloader_orig_asound
+#define snd_seq_remove_events_set_queue snd_seq_remove_events_set_queue_dylibloader_orig_asound
+#define snd_seq_remove_events_set_time snd_seq_remove_events_set_time_dylibloader_orig_asound
+#define snd_seq_remove_events_set_dest snd_seq_remove_events_set_dest_dylibloader_orig_asound
+#define snd_seq_remove_events_set_channel snd_seq_remove_events_set_channel_dylibloader_orig_asound
+#define snd_seq_remove_events_set_event_type snd_seq_remove_events_set_event_type_dylibloader_orig_asound
+#define snd_seq_remove_events_set_tag snd_seq_remove_events_set_tag_dylibloader_orig_asound
+#define snd_seq_remove_events snd_seq_remove_events_dylibloader_orig_asound
+#define snd_seq_set_bit snd_seq_set_bit_dylibloader_orig_asound
+#define snd_seq_unset_bit snd_seq_unset_bit_dylibloader_orig_asound
+#define snd_seq_change_bit snd_seq_change_bit_dylibloader_orig_asound
+#define snd_seq_get_bit snd_seq_get_bit_dylibloader_orig_asound
+#define snd_seq_control_queue snd_seq_control_queue_dylibloader_orig_asound
+#define snd_seq_create_simple_port snd_seq_create_simple_port_dylibloader_orig_asound
+#define snd_seq_delete_simple_port snd_seq_delete_simple_port_dylibloader_orig_asound
+#define snd_seq_connect_from snd_seq_connect_from_dylibloader_orig_asound
+#define snd_seq_connect_to snd_seq_connect_to_dylibloader_orig_asound
+#define snd_seq_disconnect_from snd_seq_disconnect_from_dylibloader_orig_asound
+#define snd_seq_disconnect_to snd_seq_disconnect_to_dylibloader_orig_asound
+#define snd_seq_set_client_name snd_seq_set_client_name_dylibloader_orig_asound
+#define snd_seq_set_client_event_filter snd_seq_set_client_event_filter_dylibloader_orig_asound
+#define snd_seq_set_client_pool_output snd_seq_set_client_pool_output_dylibloader_orig_asound
+#define snd_seq_set_client_pool_output_room snd_seq_set_client_pool_output_room_dylibloader_orig_asound
+#define snd_seq_set_client_pool_input snd_seq_set_client_pool_input_dylibloader_orig_asound
+#define snd_seq_sync_output_queue snd_seq_sync_output_queue_dylibloader_orig_asound
+#define snd_seq_parse_address snd_seq_parse_address_dylibloader_orig_asound
+#define snd_seq_reset_pool_output snd_seq_reset_pool_output_dylibloader_orig_asound
+#define snd_seq_reset_pool_input snd_seq_reset_pool_input_dylibloader_orig_asound
+#define snd_midi_event_new snd_midi_event_new_dylibloader_orig_asound
+#define snd_midi_event_resize_buffer snd_midi_event_resize_buffer_dylibloader_orig_asound
+#define snd_midi_event_free snd_midi_event_free_dylibloader_orig_asound
+#define snd_midi_event_init snd_midi_event_init_dylibloader_orig_asound
+#define snd_midi_event_reset_encode snd_midi_event_reset_encode_dylibloader_orig_asound
+#define snd_midi_event_reset_decode snd_midi_event_reset_decode_dylibloader_orig_asound
+#define snd_midi_event_no_status snd_midi_event_no_status_dylibloader_orig_asound
+#define snd_midi_event_encode snd_midi_event_encode_dylibloader_orig_asound
+#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_orig_asound
+#define snd_midi_event_decode snd_midi_event_decode_dylibloader_orig_asound
+#include <alsa/asoundlib.h>
+#undef snd_asoundlib_version
+#undef snd_dlpath
+#undef snd_dlopen
+#undef snd_dlsym
+#undef snd_dlclose
+#undef snd_async_add_handler
+#undef snd_async_del_handler
+#undef snd_async_handler_get_fd
+#undef snd_async_handler_get_signo
+#undef snd_async_handler_get_callback_private
+#undef snd_shm_area_create
+#undef snd_shm_area_share
+#undef snd_shm_area_destroy
+#undef snd_user_file
+#undef snd_input_stdio_open
+#undef snd_input_stdio_attach
+#undef snd_input_buffer_open
+#undef snd_input_close
+#undef snd_input_scanf
+#undef snd_input_gets
+#undef snd_input_getc
+#undef snd_input_ungetc
+#undef snd_output_stdio_open
+#undef snd_output_stdio_attach
+#undef snd_output_buffer_open
+#undef snd_output_buffer_string
+#undef snd_output_close
+#undef snd_output_printf
+#undef snd_output_vprintf
+#undef snd_output_puts
+#undef snd_output_putc
+#undef snd_output_flush
+#undef snd_strerror
+#undef snd_lib_error_set_handler
+#undef snd_lib_error_set_local
+#undef snd_config_topdir
+#undef snd_config_top
+#undef snd_config_load
+#undef snd_config_load_override
+#undef snd_config_save
+#undef snd_config_update
+#undef snd_config_update_r
+#undef snd_config_update_free
+#undef snd_config_update_free_global
+#undef snd_config_update_ref
+#undef snd_config_ref
+#undef snd_config_unref
+#undef snd_config_search
+#undef snd_config_searchv
+#undef snd_config_search_definition
+#undef snd_config_expand
+#undef snd_config_evaluate
+#undef snd_config_add
+#undef snd_config_add_before
+#undef snd_config_add_after
+#undef snd_config_remove
+#undef snd_config_delete
+#undef snd_config_delete_compound_members
+#undef snd_config_copy
+#undef snd_config_make
+#undef snd_config_make_integer
+#undef snd_config_make_integer64
+#undef snd_config_make_real
+#undef snd_config_make_string
+#undef snd_config_make_pointer
+#undef snd_config_make_compound
+#undef snd_config_imake_integer
+#undef snd_config_imake_integer64
+#undef snd_config_imake_real
+#undef snd_config_imake_string
+#undef snd_config_imake_safe_string
+#undef snd_config_imake_pointer
+#undef snd_config_get_type
+#undef snd_config_is_array
+#undef snd_config_set_id
+#undef snd_config_set_integer
+#undef snd_config_set_integer64
+#undef snd_config_set_real
+#undef snd_config_set_string
+#undef snd_config_set_ascii
+#undef snd_config_set_pointer
+#undef snd_config_get_id
+#undef snd_config_get_integer
+#undef snd_config_get_integer64
+#undef snd_config_get_real
+#undef snd_config_get_ireal
+#undef snd_config_get_string
+#undef snd_config_get_ascii
+#undef snd_config_get_pointer
+#undef snd_config_test_id
+#undef snd_config_iterator_first
+#undef snd_config_iterator_next
+#undef snd_config_iterator_end
+#undef snd_config_iterator_entry
+#undef snd_config_get_bool_ascii
+#undef snd_config_get_bool
+#undef snd_config_get_ctl_iface_ascii
+#undef snd_config_get_ctl_iface
+#undef snd_names_list
+#undef snd_names_list_free
+#undef snd_pcm_open
+#undef snd_pcm_open_lconf
+#undef snd_pcm_open_fallback
+#undef snd_pcm_close
+#undef snd_pcm_name
+#undef snd_pcm_type
+#undef snd_pcm_stream
+#undef snd_pcm_poll_descriptors_count
+#undef snd_pcm_poll_descriptors
+#undef snd_pcm_poll_descriptors_revents
+#undef snd_pcm_nonblock
+#undef snd_async_add_pcm_handler
+#undef snd_async_handler_get_pcm
+#undef snd_pcm_info
+#undef snd_pcm_hw_params_current
+#undef snd_pcm_hw_params
+#undef snd_pcm_hw_free
+#undef snd_pcm_sw_params_current
+#undef snd_pcm_sw_params
+#undef snd_pcm_prepare
+#undef snd_pcm_reset
+#undef snd_pcm_status
+#undef snd_pcm_start
+#undef snd_pcm_drop
+#undef snd_pcm_drain
+#undef snd_pcm_pause
+#undef snd_pcm_state
+#undef snd_pcm_hwsync
+#undef snd_pcm_delay
+#undef snd_pcm_resume
+#undef snd_pcm_htimestamp
+#undef snd_pcm_avail
+#undef snd_pcm_avail_update
+#undef snd_pcm_avail_delay
+#undef snd_pcm_rewindable
+#undef snd_pcm_rewind
+#undef snd_pcm_forwardable
+#undef snd_pcm_forward
+#undef snd_pcm_writei
+#undef snd_pcm_readi
+#undef snd_pcm_writen
+#undef snd_pcm_readn
+#undef snd_pcm_wait
+#undef snd_pcm_link
+#undef snd_pcm_unlink
+#undef snd_pcm_query_chmaps
+#undef snd_pcm_query_chmaps_from_hw
+#undef snd_pcm_free_chmaps
+#undef snd_pcm_get_chmap
+#undef snd_pcm_set_chmap
+#undef snd_pcm_chmap_type_name
+#undef snd_pcm_chmap_name
+#undef snd_pcm_chmap_long_name
+#undef snd_pcm_chmap_print
+#undef snd_pcm_chmap_from_string
+#undef snd_pcm_chmap_parse_string
+#undef snd_pcm_recover
+#undef snd_pcm_set_params
+#undef snd_pcm_get_params
+#undef snd_pcm_info_sizeof
+#undef snd_pcm_info_malloc
+#undef snd_pcm_info_free
+#undef snd_pcm_info_copy
+#undef snd_pcm_info_get_device
+#undef snd_pcm_info_get_subdevice
+#undef snd_pcm_info_get_stream
+#undef snd_pcm_info_get_card
+#undef snd_pcm_info_get_id
+#undef snd_pcm_info_get_name
+#undef snd_pcm_info_get_subdevice_name
+#undef snd_pcm_info_get_class
+#undef snd_pcm_info_get_subclass
+#undef snd_pcm_info_get_subdevices_count
+#undef snd_pcm_info_get_subdevices_avail
+#undef snd_pcm_info_get_sync
+#undef snd_pcm_info_set_device
+#undef snd_pcm_info_set_subdevice
+#undef snd_pcm_info_set_stream
+#undef snd_pcm_hw_params_any
+#undef snd_pcm_hw_params_can_mmap_sample_resolution
+#undef snd_pcm_hw_params_is_double
+#undef snd_pcm_hw_params_is_batch
+#undef snd_pcm_hw_params_is_block_transfer
+#undef snd_pcm_hw_params_is_monotonic
+#undef snd_pcm_hw_params_can_overrange
+#undef snd_pcm_hw_params_can_pause
+#undef snd_pcm_hw_params_can_resume
+#undef snd_pcm_hw_params_is_half_duplex
+#undef snd_pcm_hw_params_is_joint_duplex
+#undef snd_pcm_hw_params_can_sync_start
+#undef snd_pcm_hw_params_can_disable_period_wakeup
+#undef snd_pcm_hw_params_supports_audio_wallclock_ts
+#undef snd_pcm_hw_params_supports_audio_ts_type
+#undef snd_pcm_hw_params_get_rate_numden
+#undef snd_pcm_hw_params_get_sbits
+#undef snd_pcm_hw_params_get_fifo_size
+#undef snd_pcm_hw_params_sizeof
+#undef snd_pcm_hw_params_malloc
+#undef snd_pcm_hw_params_free
+#undef snd_pcm_hw_params_copy
+#undef snd_pcm_hw_params_get_access
+#undef snd_pcm_hw_params_test_access
+#undef snd_pcm_hw_params_set_access
+#undef snd_pcm_hw_params_set_access_first
+#undef snd_pcm_hw_params_set_access_last
+#undef snd_pcm_hw_params_set_access_mask
+#undef snd_pcm_hw_params_get_access_mask
+#undef snd_pcm_hw_params_get_format
+#undef snd_pcm_hw_params_test_format
+#undef snd_pcm_hw_params_set_format
+#undef snd_pcm_hw_params_set_format_first
+#undef snd_pcm_hw_params_set_format_last
+#undef snd_pcm_hw_params_set_format_mask
+#undef snd_pcm_hw_params_get_format_mask
+#undef snd_pcm_hw_params_get_subformat
+#undef snd_pcm_hw_params_test_subformat
+#undef snd_pcm_hw_params_set_subformat
+#undef snd_pcm_hw_params_set_subformat_first
+#undef snd_pcm_hw_params_set_subformat_last
+#undef snd_pcm_hw_params_set_subformat_mask
+#undef snd_pcm_hw_params_get_subformat_mask
+#undef snd_pcm_hw_params_get_channels
+#undef snd_pcm_hw_params_get_channels_min
+#undef snd_pcm_hw_params_get_channels_max
+#undef snd_pcm_hw_params_test_channels
+#undef snd_pcm_hw_params_set_channels
+#undef snd_pcm_hw_params_set_channels_min
+#undef snd_pcm_hw_params_set_channels_max
+#undef snd_pcm_hw_params_set_channels_minmax
+#undef snd_pcm_hw_params_set_channels_near
+#undef snd_pcm_hw_params_set_channels_first
+#undef snd_pcm_hw_params_set_channels_last
+#undef snd_pcm_hw_params_get_rate
+#undef snd_pcm_hw_params_get_rate_min
+#undef snd_pcm_hw_params_get_rate_max
+#undef snd_pcm_hw_params_test_rate
+#undef snd_pcm_hw_params_set_rate
+#undef snd_pcm_hw_params_set_rate_min
+#undef snd_pcm_hw_params_set_rate_max
+#undef snd_pcm_hw_params_set_rate_minmax
+#undef snd_pcm_hw_params_set_rate_near
+#undef snd_pcm_hw_params_set_rate_first
+#undef snd_pcm_hw_params_set_rate_last
+#undef snd_pcm_hw_params_set_rate_resample
+#undef snd_pcm_hw_params_get_rate_resample
+#undef snd_pcm_hw_params_set_export_buffer
+#undef snd_pcm_hw_params_get_export_buffer
+#undef snd_pcm_hw_params_set_period_wakeup
+#undef snd_pcm_hw_params_get_period_wakeup
+#undef snd_pcm_hw_params_get_period_time
+#undef snd_pcm_hw_params_get_period_time_min
+#undef snd_pcm_hw_params_get_period_time_max
+#undef snd_pcm_hw_params_test_period_time
+#undef snd_pcm_hw_params_set_period_time
+#undef snd_pcm_hw_params_set_period_time_min
+#undef snd_pcm_hw_params_set_period_time_max
+#undef snd_pcm_hw_params_set_period_time_minmax
+#undef snd_pcm_hw_params_set_period_time_near
+#undef snd_pcm_hw_params_set_period_time_first
+#undef snd_pcm_hw_params_set_period_time_last
+#undef snd_pcm_hw_params_get_period_size
+#undef snd_pcm_hw_params_get_period_size_min
+#undef snd_pcm_hw_params_get_period_size_max
+#undef snd_pcm_hw_params_test_period_size
+#undef snd_pcm_hw_params_set_period_size
+#undef snd_pcm_hw_params_set_period_size_min
+#undef snd_pcm_hw_params_set_period_size_max
+#undef snd_pcm_hw_params_set_period_size_minmax
+#undef snd_pcm_hw_params_set_period_size_near
+#undef snd_pcm_hw_params_set_period_size_first
+#undef snd_pcm_hw_params_set_period_size_last
+#undef snd_pcm_hw_params_set_period_size_integer
+#undef snd_pcm_hw_params_get_periods
+#undef snd_pcm_hw_params_get_periods_min
+#undef snd_pcm_hw_params_get_periods_max
+#undef snd_pcm_hw_params_test_periods
+#undef snd_pcm_hw_params_set_periods
+#undef snd_pcm_hw_params_set_periods_min
+#undef snd_pcm_hw_params_set_periods_max
+#undef snd_pcm_hw_params_set_periods_minmax
+#undef snd_pcm_hw_params_set_periods_near
+#undef snd_pcm_hw_params_set_periods_first
+#undef snd_pcm_hw_params_set_periods_last
+#undef snd_pcm_hw_params_set_periods_integer
+#undef snd_pcm_hw_params_get_buffer_time
+#undef snd_pcm_hw_params_get_buffer_time_min
+#undef snd_pcm_hw_params_get_buffer_time_max
+#undef snd_pcm_hw_params_test_buffer_time
+#undef snd_pcm_hw_params_set_buffer_time
+#undef snd_pcm_hw_params_set_buffer_time_min
+#undef snd_pcm_hw_params_set_buffer_time_max
+#undef snd_pcm_hw_params_set_buffer_time_minmax
+#undef snd_pcm_hw_params_set_buffer_time_near
+#undef snd_pcm_hw_params_set_buffer_time_first
+#undef snd_pcm_hw_params_set_buffer_time_last
+#undef snd_pcm_hw_params_get_buffer_size
+#undef snd_pcm_hw_params_get_buffer_size_min
+#undef snd_pcm_hw_params_get_buffer_size_max
+#undef snd_pcm_hw_params_test_buffer_size
+#undef snd_pcm_hw_params_set_buffer_size
+#undef snd_pcm_hw_params_set_buffer_size_min
+#undef snd_pcm_hw_params_set_buffer_size_max
+#undef snd_pcm_hw_params_set_buffer_size_minmax
+#undef snd_pcm_hw_params_set_buffer_size_near
+#undef snd_pcm_hw_params_set_buffer_size_first
+#undef snd_pcm_hw_params_set_buffer_size_last
+#undef snd_pcm_hw_params_get_min_align
+#undef snd_pcm_sw_params_sizeof
+#undef snd_pcm_sw_params_malloc
+#undef snd_pcm_sw_params_free
+#undef snd_pcm_sw_params_copy
+#undef snd_pcm_sw_params_get_boundary
+#undef snd_pcm_sw_params_set_tstamp_mode
+#undef snd_pcm_sw_params_get_tstamp_mode
+#undef snd_pcm_sw_params_set_avail_min
+#undef snd_pcm_sw_params_get_avail_min
+#undef snd_pcm_sw_params_set_period_event
+#undef snd_pcm_sw_params_get_period_event
+#undef snd_pcm_sw_params_set_start_threshold
+#undef snd_pcm_sw_params_get_start_threshold
+#undef snd_pcm_sw_params_set_stop_threshold
+#undef snd_pcm_sw_params_get_stop_threshold
+#undef snd_pcm_sw_params_set_silence_threshold
+#undef snd_pcm_sw_params_get_silence_threshold
+#undef snd_pcm_sw_params_set_silence_size
+#undef snd_pcm_sw_params_get_silence_size
+#undef snd_pcm_access_mask_sizeof
+#undef snd_pcm_access_mask_malloc
+#undef snd_pcm_access_mask_free
+#undef snd_pcm_access_mask_copy
+#undef snd_pcm_access_mask_none
+#undef snd_pcm_access_mask_any
+#undef snd_pcm_access_mask_test
+#undef snd_pcm_access_mask_empty
+#undef snd_pcm_access_mask_set
+#undef snd_pcm_access_mask_reset
+#undef snd_pcm_format_mask_sizeof
+#undef snd_pcm_format_mask_malloc
+#undef snd_pcm_format_mask_free
+#undef snd_pcm_format_mask_copy
+#undef snd_pcm_format_mask_none
+#undef snd_pcm_format_mask_any
+#undef snd_pcm_format_mask_test
+#undef snd_pcm_format_mask_empty
+#undef snd_pcm_format_mask_set
+#undef snd_pcm_format_mask_reset
+#undef snd_pcm_subformat_mask_sizeof
+#undef snd_pcm_subformat_mask_malloc
+#undef snd_pcm_subformat_mask_free
+#undef snd_pcm_subformat_mask_copy
+#undef snd_pcm_subformat_mask_none
+#undef snd_pcm_subformat_mask_any
+#undef snd_pcm_subformat_mask_test
+#undef snd_pcm_subformat_mask_empty
+#undef snd_pcm_subformat_mask_set
+#undef snd_pcm_subformat_mask_reset
+#undef snd_pcm_status_sizeof
+#undef snd_pcm_status_malloc
+#undef snd_pcm_status_free
+#undef snd_pcm_status_copy
+#undef snd_pcm_status_get_state
+#undef snd_pcm_status_get_trigger_tstamp
+#undef snd_pcm_status_get_trigger_htstamp
+#undef snd_pcm_status_get_tstamp
+#undef snd_pcm_status_get_htstamp
+#undef snd_pcm_status_get_audio_htstamp
+#undef snd_pcm_status_get_driver_htstamp
+#undef snd_pcm_status_get_delay
+#undef snd_pcm_status_get_avail
+#undef snd_pcm_status_get_avail_max
+#undef snd_pcm_status_get_overrange
+#undef snd_pcm_type_name
+#undef snd_pcm_stream_name
+#undef snd_pcm_access_name
+#undef snd_pcm_format_name
+#undef snd_pcm_format_description
+#undef snd_pcm_subformat_name
+#undef snd_pcm_subformat_description
+#undef snd_pcm_format_value
+#undef snd_pcm_tstamp_mode_name
+#undef snd_pcm_state_name
+#undef snd_pcm_dump
+#undef snd_pcm_dump_hw_setup
+#undef snd_pcm_dump_sw_setup
+#undef snd_pcm_dump_setup
+#undef snd_pcm_hw_params_dump
+#undef snd_pcm_sw_params_dump
+#undef snd_pcm_status_dump
+#undef snd_pcm_mmap_begin
+#undef snd_pcm_mmap_commit
+#undef snd_pcm_mmap_writei
+#undef snd_pcm_mmap_readi
+#undef snd_pcm_mmap_writen
+#undef snd_pcm_mmap_readn
+#undef snd_pcm_format_signed
+#undef snd_pcm_format_unsigned
+#undef snd_pcm_format_linear
+#undef snd_pcm_format_float
+#undef snd_pcm_format_little_endian
+#undef snd_pcm_format_big_endian
+#undef snd_pcm_format_cpu_endian
+#undef snd_pcm_format_width
+#undef snd_pcm_format_physical_width
+#undef snd_pcm_build_linear_format
+#undef snd_pcm_format_size
+#undef snd_pcm_format_silence
+#undef snd_pcm_format_silence_16
+#undef snd_pcm_format_silence_32
+#undef snd_pcm_format_silence_64
+#undef snd_pcm_format_set_silence
+#undef snd_pcm_bytes_to_frames
+#undef snd_pcm_frames_to_bytes
+#undef snd_pcm_bytes_to_samples
+#undef snd_pcm_samples_to_bytes
+#undef snd_pcm_area_silence
+#undef snd_pcm_areas_silence
+#undef snd_pcm_area_copy
+#undef snd_pcm_areas_copy
+#undef snd_pcm_areas_copy_wrap
+#undef snd_pcm_hook_get_pcm
+#undef snd_pcm_hook_get_private
+#undef snd_pcm_hook_set_private
+#undef snd_pcm_hook_add
+#undef snd_pcm_hook_remove
+#undef snd_pcm_meter_get_bufsize
+#undef snd_pcm_meter_get_channels
+#undef snd_pcm_meter_get_rate
+#undef snd_pcm_meter_get_now
+#undef snd_pcm_meter_get_boundary
+#undef snd_pcm_meter_add_scope
+#undef snd_pcm_meter_search_scope
+#undef snd_pcm_scope_malloc
+#undef snd_pcm_scope_set_ops
+#undef snd_pcm_scope_set_name
+#undef snd_pcm_scope_get_name
+#undef snd_pcm_scope_get_callback_private
+#undef snd_pcm_scope_set_callback_private
+#undef snd_pcm_scope_s16_open
+#undef snd_pcm_scope_s16_get_channel_buffer
+#undef snd_spcm_init
+#undef snd_spcm_init_duplex
+#undef snd_spcm_init_get_params
+#undef snd_pcm_start_mode_name
+#undef snd_pcm_xrun_mode_name
+#undef snd_pcm_sw_params_set_start_mode
+#undef snd_pcm_sw_params_get_start_mode
+#undef snd_pcm_sw_params_set_xrun_mode
+#undef snd_pcm_sw_params_get_xrun_mode
+#undef snd_pcm_sw_params_set_xfer_align
+#undef snd_pcm_sw_params_get_xfer_align
+#undef snd_pcm_sw_params_set_sleep_min
+#undef snd_pcm_sw_params_get_sleep_min
+#undef snd_pcm_hw_params_get_tick_time
+#undef snd_pcm_hw_params_get_tick_time_min
+#undef snd_pcm_hw_params_get_tick_time_max
+#undef snd_pcm_hw_params_test_tick_time
+#undef snd_pcm_hw_params_set_tick_time
+#undef snd_pcm_hw_params_set_tick_time_min
+#undef snd_pcm_hw_params_set_tick_time_max
+#undef snd_pcm_hw_params_set_tick_time_minmax
+#undef snd_pcm_hw_params_set_tick_time_near
+#undef snd_pcm_hw_params_set_tick_time_first
+#undef snd_pcm_hw_params_set_tick_time_last
+#undef snd_rawmidi_open
+#undef snd_rawmidi_open_lconf
+#undef snd_rawmidi_close
+#undef snd_rawmidi_poll_descriptors_count
+#undef snd_rawmidi_poll_descriptors
+#undef snd_rawmidi_poll_descriptors_revents
+#undef snd_rawmidi_nonblock
+#undef snd_rawmidi_info_sizeof
+#undef snd_rawmidi_info_malloc
+#undef snd_rawmidi_info_free
+#undef snd_rawmidi_info_copy
+#undef snd_rawmidi_info_get_device
+#undef snd_rawmidi_info_get_subdevice
+#undef snd_rawmidi_info_get_stream
+#undef snd_rawmidi_info_get_card
+#undef snd_rawmidi_info_get_flags
+#undef snd_rawmidi_info_get_id
+#undef snd_rawmidi_info_get_name
+#undef snd_rawmidi_info_get_subdevice_name
+#undef snd_rawmidi_info_get_subdevices_count
+#undef snd_rawmidi_info_get_subdevices_avail
+#undef snd_rawmidi_info_set_device
+#undef snd_rawmidi_info_set_subdevice
+#undef snd_rawmidi_info_set_stream
+#undef snd_rawmidi_info
+#undef snd_rawmidi_params_sizeof
+#undef snd_rawmidi_params_malloc
+#undef snd_rawmidi_params_free
+#undef snd_rawmidi_params_copy
+#undef snd_rawmidi_params_set_buffer_size
+#undef snd_rawmidi_params_get_buffer_size
+#undef snd_rawmidi_params_set_avail_min
+#undef snd_rawmidi_params_get_avail_min
+#undef snd_rawmidi_params_set_no_active_sensing
+#undef snd_rawmidi_params_get_no_active_sensing
+#undef snd_rawmidi_params
+#undef snd_rawmidi_params_current
+#undef snd_rawmidi_status_sizeof
+#undef snd_rawmidi_status_malloc
+#undef snd_rawmidi_status_free
+#undef snd_rawmidi_status_copy
+#undef snd_rawmidi_status_get_tstamp
+#undef snd_rawmidi_status_get_avail
+#undef snd_rawmidi_status_get_xruns
+#undef snd_rawmidi_status
+#undef snd_rawmidi_drain
+#undef snd_rawmidi_drop
+#undef snd_rawmidi_write
+#undef snd_rawmidi_read
+#undef snd_rawmidi_name
+#undef snd_rawmidi_type
+#undef snd_rawmidi_stream
+#undef snd_timer_query_open
+#undef snd_timer_query_open_lconf
+#undef snd_timer_query_close
+#undef snd_timer_query_next_device
+#undef snd_timer_query_info
+#undef snd_timer_query_params
+#undef snd_timer_query_status
+#undef snd_timer_open
+#undef snd_timer_open_lconf
+#undef snd_timer_close
+#undef snd_async_add_timer_handler
+#undef snd_async_handler_get_timer
+#undef snd_timer_poll_descriptors_count
+#undef snd_timer_poll_descriptors
+#undef snd_timer_poll_descriptors_revents
+#undef snd_timer_info
+#undef snd_timer_params
+#undef snd_timer_status
+#undef snd_timer_start
+#undef snd_timer_stop
+#undef snd_timer_continue
+#undef snd_timer_read
+#undef snd_timer_id_sizeof
+#undef snd_timer_id_malloc
+#undef snd_timer_id_free
+#undef snd_timer_id_copy
+#undef snd_timer_id_set_class
+#undef snd_timer_id_get_class
+#undef snd_timer_id_set_sclass
+#undef snd_timer_id_get_sclass
+#undef snd_timer_id_set_card
+#undef snd_timer_id_get_card
+#undef snd_timer_id_set_device
+#undef snd_timer_id_get_device
+#undef snd_timer_id_set_subdevice
+#undef snd_timer_id_get_subdevice
+#undef snd_timer_ginfo_sizeof
+#undef snd_timer_ginfo_malloc
+#undef snd_timer_ginfo_free
+#undef snd_timer_ginfo_copy
+#undef snd_timer_ginfo_set_tid
+#undef snd_timer_ginfo_get_tid
+#undef snd_timer_ginfo_get_flags
+#undef snd_timer_ginfo_get_card
+#undef snd_timer_ginfo_get_id
+#undef snd_timer_ginfo_get_name
+#undef snd_timer_ginfo_get_resolution
+#undef snd_timer_ginfo_get_resolution_min
+#undef snd_timer_ginfo_get_resolution_max
+#undef snd_timer_ginfo_get_clients
+#undef snd_timer_info_sizeof
+#undef snd_timer_info_malloc
+#undef snd_timer_info_free
+#undef snd_timer_info_copy
+#undef snd_timer_info_is_slave
+#undef snd_timer_info_get_card
+#undef snd_timer_info_get_id
+#undef snd_timer_info_get_name
+#undef snd_timer_info_get_resolution
+#undef snd_timer_params_sizeof
+#undef snd_timer_params_malloc
+#undef snd_timer_params_free
+#undef snd_timer_params_copy
+#undef snd_timer_params_set_auto_start
+#undef snd_timer_params_get_auto_start
+#undef snd_timer_params_set_exclusive
+#undef snd_timer_params_get_exclusive
+#undef snd_timer_params_set_early_event
+#undef snd_timer_params_get_early_event
+#undef snd_timer_params_set_ticks
+#undef snd_timer_params_get_ticks
+#undef snd_timer_params_set_queue_size
+#undef snd_timer_params_get_queue_size
+#undef snd_timer_params_set_filter
+#undef snd_timer_params_get_filter
+#undef snd_timer_status_sizeof
+#undef snd_timer_status_malloc
+#undef snd_timer_status_free
+#undef snd_timer_status_copy
+#undef snd_timer_status_get_timestamp
+#undef snd_timer_status_get_resolution
+#undef snd_timer_status_get_lost
+#undef snd_timer_status_get_overrun
+#undef snd_timer_status_get_queue
+#undef snd_timer_info_get_ticks
+#undef snd_hwdep_open
+#undef snd_hwdep_close
+#undef snd_hwdep_poll_descriptors
+#undef snd_hwdep_poll_descriptors_count
+#undef snd_hwdep_poll_descriptors_revents
+#undef snd_hwdep_nonblock
+#undef snd_hwdep_info
+#undef snd_hwdep_dsp_status
+#undef snd_hwdep_dsp_load
+#undef snd_hwdep_ioctl
+#undef snd_hwdep_write
+#undef snd_hwdep_read
+#undef snd_hwdep_info_sizeof
+#undef snd_hwdep_info_malloc
+#undef snd_hwdep_info_free
+#undef snd_hwdep_info_copy
+#undef snd_hwdep_info_get_device
+#undef snd_hwdep_info_get_card
+#undef snd_hwdep_info_get_id
+#undef snd_hwdep_info_get_name
+#undef snd_hwdep_info_get_iface
+#undef snd_hwdep_info_set_device
+#undef snd_hwdep_dsp_status_sizeof
+#undef snd_hwdep_dsp_status_malloc
+#undef snd_hwdep_dsp_status_free
+#undef snd_hwdep_dsp_status_copy
+#undef snd_hwdep_dsp_status_get_version
+#undef snd_hwdep_dsp_status_get_id
+#undef snd_hwdep_dsp_status_get_num_dsps
+#undef snd_hwdep_dsp_status_get_dsp_loaded
+#undef snd_hwdep_dsp_status_get_chip_ready
+#undef snd_hwdep_dsp_image_sizeof
+#undef snd_hwdep_dsp_image_malloc
+#undef snd_hwdep_dsp_image_free
+#undef snd_hwdep_dsp_image_copy
+#undef snd_hwdep_dsp_image_get_index
+#undef snd_hwdep_dsp_image_get_name
+#undef snd_hwdep_dsp_image_get_image
+#undef snd_hwdep_dsp_image_get_length
+#undef snd_hwdep_dsp_image_set_index
+#undef snd_hwdep_dsp_image_set_name
+#undef snd_hwdep_dsp_image_set_image
+#undef snd_hwdep_dsp_image_set_length
+#undef snd_card_load
+#undef snd_card_next
+#undef snd_card_get_index
+#undef snd_card_get_name
+#undef snd_card_get_longname
+#undef snd_device_name_hint
+#undef snd_device_name_free_hint
+#undef snd_device_name_get_hint
+#undef snd_ctl_open
+#undef snd_ctl_open_lconf
+#undef snd_ctl_open_fallback
+#undef snd_ctl_close
+#undef snd_ctl_nonblock
+#undef snd_async_add_ctl_handler
+#undef snd_async_handler_get_ctl
+#undef snd_ctl_poll_descriptors_count
+#undef snd_ctl_poll_descriptors
+#undef snd_ctl_poll_descriptors_revents
+#undef snd_ctl_subscribe_events
+#undef snd_ctl_card_info
+#undef snd_ctl_elem_list
+#undef snd_ctl_elem_info
+#undef snd_ctl_elem_read
+#undef snd_ctl_elem_write
+#undef snd_ctl_elem_lock
+#undef snd_ctl_elem_unlock
+#undef snd_ctl_elem_tlv_read
+#undef snd_ctl_elem_tlv_write
+#undef snd_ctl_elem_tlv_command
+#undef snd_ctl_hwdep_next_device
+#undef snd_ctl_hwdep_info
+#undef snd_ctl_pcm_next_device
+#undef snd_ctl_pcm_info
+#undef snd_ctl_pcm_prefer_subdevice
+#undef snd_ctl_rawmidi_next_device
+#undef snd_ctl_rawmidi_info
+#undef snd_ctl_rawmidi_prefer_subdevice
+#undef snd_ctl_set_power_state
+#undef snd_ctl_get_power_state
+#undef snd_ctl_read
+#undef snd_ctl_wait
+#undef snd_ctl_name
+#undef snd_ctl_type
+#undef snd_ctl_elem_type_name
+#undef snd_ctl_elem_iface_name
+#undef snd_ctl_event_type_name
+#undef snd_ctl_event_elem_get_mask
+#undef snd_ctl_event_elem_get_numid
+#undef snd_ctl_event_elem_get_id
+#undef snd_ctl_event_elem_get_interface
+#undef snd_ctl_event_elem_get_device
+#undef snd_ctl_event_elem_get_subdevice
+#undef snd_ctl_event_elem_get_name
+#undef snd_ctl_event_elem_get_index
+#undef snd_ctl_elem_list_alloc_space
+#undef snd_ctl_elem_list_free_space
+#undef snd_ctl_ascii_elem_id_get
+#undef snd_ctl_ascii_elem_id_parse
+#undef snd_ctl_ascii_value_parse
+#undef snd_ctl_elem_id_sizeof
+#undef snd_ctl_elem_id_malloc
+#undef snd_ctl_elem_id_free
+#undef snd_ctl_elem_id_clear
+#undef snd_ctl_elem_id_copy
+#undef snd_ctl_elem_id_get_numid
+#undef snd_ctl_elem_id_get_interface
+#undef snd_ctl_elem_id_get_device
+#undef snd_ctl_elem_id_get_subdevice
+#undef snd_ctl_elem_id_get_name
+#undef snd_ctl_elem_id_get_index
+#undef snd_ctl_elem_id_set_numid
+#undef snd_ctl_elem_id_set_interface
+#undef snd_ctl_elem_id_set_device
+#undef snd_ctl_elem_id_set_subdevice
+#undef snd_ctl_elem_id_set_name
+#undef snd_ctl_elem_id_set_index
+#undef snd_ctl_card_info_sizeof
+#undef snd_ctl_card_info_malloc
+#undef snd_ctl_card_info_free
+#undef snd_ctl_card_info_clear
+#undef snd_ctl_card_info_copy
+#undef snd_ctl_card_info_get_card
+#undef snd_ctl_card_info_get_id
+#undef snd_ctl_card_info_get_driver
+#undef snd_ctl_card_info_get_name
+#undef snd_ctl_card_info_get_longname
+#undef snd_ctl_card_info_get_mixername
+#undef snd_ctl_card_info_get_components
+#undef snd_ctl_event_sizeof
+#undef snd_ctl_event_malloc
+#undef snd_ctl_event_free
+#undef snd_ctl_event_clear
+#undef snd_ctl_event_copy
+#undef snd_ctl_event_get_type
+#undef snd_ctl_elem_list_sizeof
+#undef snd_ctl_elem_list_malloc
+#undef snd_ctl_elem_list_free
+#undef snd_ctl_elem_list_clear
+#undef snd_ctl_elem_list_copy
+#undef snd_ctl_elem_list_set_offset
+#undef snd_ctl_elem_list_get_used
+#undef snd_ctl_elem_list_get_count
+#undef snd_ctl_elem_list_get_id
+#undef snd_ctl_elem_list_get_numid
+#undef snd_ctl_elem_list_get_interface
+#undef snd_ctl_elem_list_get_device
+#undef snd_ctl_elem_list_get_subdevice
+#undef snd_ctl_elem_list_get_name
+#undef snd_ctl_elem_list_get_index
+#undef snd_ctl_elem_info_sizeof
+#undef snd_ctl_elem_info_malloc
+#undef snd_ctl_elem_info_free
+#undef snd_ctl_elem_info_clear
+#undef snd_ctl_elem_info_copy
+#undef snd_ctl_elem_info_get_type
+#undef snd_ctl_elem_info_is_readable
+#undef snd_ctl_elem_info_is_writable
+#undef snd_ctl_elem_info_is_volatile
+#undef snd_ctl_elem_info_is_inactive
+#undef snd_ctl_elem_info_is_locked
+#undef snd_ctl_elem_info_is_tlv_readable
+#undef snd_ctl_elem_info_is_tlv_writable
+#undef snd_ctl_elem_info_is_tlv_commandable
+#undef snd_ctl_elem_info_is_owner
+#undef snd_ctl_elem_info_is_user
+#undef snd_ctl_elem_info_get_owner
+#undef snd_ctl_elem_info_get_count
+#undef snd_ctl_elem_info_get_min
+#undef snd_ctl_elem_info_get_max
+#undef snd_ctl_elem_info_get_step
+#undef snd_ctl_elem_info_get_min64
+#undef snd_ctl_elem_info_get_max64
+#undef snd_ctl_elem_info_get_step64
+#undef snd_ctl_elem_info_get_items
+#undef snd_ctl_elem_info_set_item
+#undef snd_ctl_elem_info_get_item_name
+#undef snd_ctl_elem_info_get_dimensions
+#undef snd_ctl_elem_info_get_dimension
+#undef snd_ctl_elem_info_set_dimension
+#undef snd_ctl_elem_info_get_id
+#undef snd_ctl_elem_info_get_numid
+#undef snd_ctl_elem_info_get_interface
+#undef snd_ctl_elem_info_get_device
+#undef snd_ctl_elem_info_get_subdevice
+#undef snd_ctl_elem_info_get_name
+#undef snd_ctl_elem_info_get_index
+#undef snd_ctl_elem_info_set_id
+#undef snd_ctl_elem_info_set_numid
+#undef snd_ctl_elem_info_set_interface
+#undef snd_ctl_elem_info_set_device
+#undef snd_ctl_elem_info_set_subdevice
+#undef snd_ctl_elem_info_set_name
+#undef snd_ctl_elem_info_set_index
+#undef snd_ctl_add_integer_elem_set
+#undef snd_ctl_add_integer64_elem_set
+#undef snd_ctl_add_boolean_elem_set
+#undef snd_ctl_add_enumerated_elem_set
+#undef snd_ctl_add_bytes_elem_set
+#undef snd_ctl_elem_add_integer
+#undef snd_ctl_elem_add_integer64
+#undef snd_ctl_elem_add_boolean
+#undef snd_ctl_elem_add_enumerated
+#undef snd_ctl_elem_add_iec958
+#undef snd_ctl_elem_remove
+#undef snd_ctl_elem_value_sizeof
+#undef snd_ctl_elem_value_malloc
+#undef snd_ctl_elem_value_free
+#undef snd_ctl_elem_value_clear
+#undef snd_ctl_elem_value_copy
+#undef snd_ctl_elem_value_compare
+#undef snd_ctl_elem_value_get_id
+#undef snd_ctl_elem_value_get_numid
+#undef snd_ctl_elem_value_get_interface
+#undef snd_ctl_elem_value_get_device
+#undef snd_ctl_elem_value_get_subdevice
+#undef snd_ctl_elem_value_get_name
+#undef snd_ctl_elem_value_get_index
+#undef snd_ctl_elem_value_set_id
+#undef snd_ctl_elem_value_set_numid
+#undef snd_ctl_elem_value_set_interface
+#undef snd_ctl_elem_value_set_device
+#undef snd_ctl_elem_value_set_subdevice
+#undef snd_ctl_elem_value_set_name
+#undef snd_ctl_elem_value_set_index
+#undef snd_ctl_elem_value_get_boolean
+#undef snd_ctl_elem_value_get_integer
+#undef snd_ctl_elem_value_get_integer64
+#undef snd_ctl_elem_value_get_enumerated
+#undef snd_ctl_elem_value_get_byte
+#undef snd_ctl_elem_value_set_boolean
+#undef snd_ctl_elem_value_set_integer
+#undef snd_ctl_elem_value_set_integer64
+#undef snd_ctl_elem_value_set_enumerated
+#undef snd_ctl_elem_value_set_byte
+#undef snd_ctl_elem_set_bytes
+#undef snd_ctl_elem_value_get_bytes
+#undef snd_ctl_elem_value_get_iec958
+#undef snd_ctl_elem_value_set_iec958
+#undef snd_tlv_parse_dB_info
+#undef snd_tlv_get_dB_range
+#undef snd_tlv_convert_to_dB
+#undef snd_tlv_convert_from_dB
+#undef snd_ctl_get_dB_range
+#undef snd_ctl_convert_to_dB
+#undef snd_ctl_convert_from_dB
+#undef snd_hctl_compare_fast
+#undef snd_hctl_open
+#undef snd_hctl_open_ctl
+#undef snd_hctl_close
+#undef snd_hctl_nonblock
+#undef snd_hctl_poll_descriptors_count
+#undef snd_hctl_poll_descriptors
+#undef snd_hctl_poll_descriptors_revents
+#undef snd_hctl_get_count
+#undef snd_hctl_set_compare
+#undef snd_hctl_first_elem
+#undef snd_hctl_last_elem
+#undef snd_hctl_find_elem
+#undef snd_hctl_set_callback
+#undef snd_hctl_set_callback_private
+#undef snd_hctl_get_callback_private
+#undef snd_hctl_load
+#undef snd_hctl_free
+#undef snd_hctl_handle_events
+#undef snd_hctl_name
+#undef snd_hctl_wait
+#undef snd_hctl_ctl
+#undef snd_hctl_elem_next
+#undef snd_hctl_elem_prev
+#undef snd_hctl_elem_info
+#undef snd_hctl_elem_read
+#undef snd_hctl_elem_write
+#undef snd_hctl_elem_tlv_read
+#undef snd_hctl_elem_tlv_write
+#undef snd_hctl_elem_tlv_command
+#undef snd_hctl_elem_get_hctl
+#undef snd_hctl_elem_get_id
+#undef snd_hctl_elem_get_numid
+#undef snd_hctl_elem_get_interface
+#undef snd_hctl_elem_get_device
+#undef snd_hctl_elem_get_subdevice
+#undef snd_hctl_elem_get_name
+#undef snd_hctl_elem_get_index
+#undef snd_hctl_elem_set_callback
+#undef snd_hctl_elem_get_callback_private
+#undef snd_hctl_elem_set_callback_private
+#undef snd_sctl_build
+#undef snd_sctl_free
+#undef snd_sctl_install
+#undef snd_sctl_remove
+#undef snd_mixer_open
+#undef snd_mixer_close
+#undef snd_mixer_first_elem
+#undef snd_mixer_last_elem
+#undef snd_mixer_handle_events
+#undef snd_mixer_attach
+#undef snd_mixer_attach_hctl
+#undef snd_mixer_detach
+#undef snd_mixer_detach_hctl
+#undef snd_mixer_get_hctl
+#undef snd_mixer_poll_descriptors_count
+#undef snd_mixer_poll_descriptors
+#undef snd_mixer_poll_descriptors_revents
+#undef snd_mixer_load
+#undef snd_mixer_free
+#undef snd_mixer_wait
+#undef snd_mixer_set_compare
+#undef snd_mixer_set_callback
+#undef snd_mixer_get_callback_private
+#undef snd_mixer_set_callback_private
+#undef snd_mixer_get_count
+#undef snd_mixer_class_unregister
+#undef snd_mixer_elem_next
+#undef snd_mixer_elem_prev
+#undef snd_mixer_elem_set_callback
+#undef snd_mixer_elem_get_callback_private
+#undef snd_mixer_elem_set_callback_private
+#undef snd_mixer_elem_get_type
+#undef snd_mixer_class_register
+#undef snd_mixer_elem_new
+#undef snd_mixer_elem_add
+#undef snd_mixer_elem_remove
+#undef snd_mixer_elem_free
+#undef snd_mixer_elem_info
+#undef snd_mixer_elem_value
+#undef snd_mixer_elem_attach
+#undef snd_mixer_elem_detach
+#undef snd_mixer_elem_empty
+#undef snd_mixer_elem_get_private
+#undef snd_mixer_class_sizeof
+#undef snd_mixer_class_malloc
+#undef snd_mixer_class_free
+#undef snd_mixer_class_copy
+#undef snd_mixer_class_get_mixer
+#undef snd_mixer_class_get_event
+#undef snd_mixer_class_get_private
+#undef snd_mixer_class_get_compare
+#undef snd_mixer_class_set_event
+#undef snd_mixer_class_set_private
+#undef snd_mixer_class_set_private_free
+#undef snd_mixer_class_set_compare
+#undef snd_mixer_selem_channel_name
+#undef snd_mixer_selem_register
+#undef snd_mixer_selem_get_id
+#undef snd_mixer_selem_get_name
+#undef snd_mixer_selem_get_index
+#undef snd_mixer_find_selem
+#undef snd_mixer_selem_is_active
+#undef snd_mixer_selem_is_playback_mono
+#undef snd_mixer_selem_has_playback_channel
+#undef snd_mixer_selem_is_capture_mono
+#undef snd_mixer_selem_has_capture_channel
+#undef snd_mixer_selem_get_capture_group
+#undef snd_mixer_selem_has_common_volume
+#undef snd_mixer_selem_has_playback_volume
+#undef snd_mixer_selem_has_playback_volume_joined
+#undef snd_mixer_selem_has_capture_volume
+#undef snd_mixer_selem_has_capture_volume_joined
+#undef snd_mixer_selem_has_common_switch
+#undef snd_mixer_selem_has_playback_switch
+#undef snd_mixer_selem_has_playback_switch_joined
+#undef snd_mixer_selem_has_capture_switch
+#undef snd_mixer_selem_has_capture_switch_joined
+#undef snd_mixer_selem_has_capture_switch_exclusive
+#undef snd_mixer_selem_ask_playback_vol_dB
+#undef snd_mixer_selem_ask_capture_vol_dB
+#undef snd_mixer_selem_ask_playback_dB_vol
+#undef snd_mixer_selem_ask_capture_dB_vol
+#undef snd_mixer_selem_get_playback_volume
+#undef snd_mixer_selem_get_capture_volume
+#undef snd_mixer_selem_get_playback_dB
+#undef snd_mixer_selem_get_capture_dB
+#undef snd_mixer_selem_get_playback_switch
+#undef snd_mixer_selem_get_capture_switch
+#undef snd_mixer_selem_set_playback_volume
+#undef snd_mixer_selem_set_capture_volume
+#undef snd_mixer_selem_set_playback_dB
+#undef snd_mixer_selem_set_capture_dB
+#undef snd_mixer_selem_set_playback_volume_all
+#undef snd_mixer_selem_set_capture_volume_all
+#undef snd_mixer_selem_set_playback_dB_all
+#undef snd_mixer_selem_set_capture_dB_all
+#undef snd_mixer_selem_set_playback_switch
+#undef snd_mixer_selem_set_capture_switch
+#undef snd_mixer_selem_set_playback_switch_all
+#undef snd_mixer_selem_set_capture_switch_all
+#undef snd_mixer_selem_get_playback_volume_range
+#undef snd_mixer_selem_get_playback_dB_range
+#undef snd_mixer_selem_set_playback_volume_range
+#undef snd_mixer_selem_get_capture_volume_range
+#undef snd_mixer_selem_get_capture_dB_range
+#undef snd_mixer_selem_set_capture_volume_range
+#undef snd_mixer_selem_is_enumerated
+#undef snd_mixer_selem_is_enum_playback
+#undef snd_mixer_selem_is_enum_capture
+#undef snd_mixer_selem_get_enum_items
+#undef snd_mixer_selem_get_enum_item_name
+#undef snd_mixer_selem_get_enum_item
+#undef snd_mixer_selem_set_enum_item
+#undef snd_mixer_selem_id_sizeof
+#undef snd_mixer_selem_id_malloc
+#undef snd_mixer_selem_id_free
+#undef snd_mixer_selem_id_copy
+#undef snd_mixer_selem_id_get_name
+#undef snd_mixer_selem_id_get_index
+#undef snd_mixer_selem_id_set_name
+#undef snd_mixer_selem_id_set_index
+#undef snd_mixer_selem_id_parse
+#undef snd_seq_open
+#undef snd_seq_open_lconf
+#undef snd_seq_name
+#undef snd_seq_type
+#undef snd_seq_close
+#undef snd_seq_poll_descriptors_count
+#undef snd_seq_poll_descriptors
+#undef snd_seq_poll_descriptors_revents
+#undef snd_seq_nonblock
+#undef snd_seq_client_id
+#undef snd_seq_get_output_buffer_size
+#undef snd_seq_get_input_buffer_size
+#undef snd_seq_set_output_buffer_size
+#undef snd_seq_set_input_buffer_size
+#undef snd_seq_system_info_sizeof
+#undef snd_seq_system_info_malloc
+#undef snd_seq_system_info_free
+#undef snd_seq_system_info_copy
+#undef snd_seq_system_info_get_queues
+#undef snd_seq_system_info_get_clients
+#undef snd_seq_system_info_get_ports
+#undef snd_seq_system_info_get_channels
+#undef snd_seq_system_info_get_cur_clients
+#undef snd_seq_system_info_get_cur_queues
+#undef snd_seq_system_info
+#undef snd_seq_client_info_sizeof
+#undef snd_seq_client_info_malloc
+#undef snd_seq_client_info_free
+#undef snd_seq_client_info_copy
+#undef snd_seq_client_info_get_client
+#undef snd_seq_client_info_get_type
+#undef snd_seq_client_info_get_name
+#undef snd_seq_client_info_get_broadcast_filter
+#undef snd_seq_client_info_get_error_bounce
+#undef snd_seq_client_info_get_card
+#undef snd_seq_client_info_get_pid
+#undef snd_seq_client_info_get_event_filter
+#undef snd_seq_client_info_get_num_ports
+#undef snd_seq_client_info_get_event_lost
+#undef snd_seq_client_info_set_client
+#undef snd_seq_client_info_set_name
+#undef snd_seq_client_info_set_broadcast_filter
+#undef snd_seq_client_info_set_error_bounce
+#undef snd_seq_client_info_set_event_filter
+#undef snd_seq_client_info_event_filter_clear
+#undef snd_seq_client_info_event_filter_add
+#undef snd_seq_client_info_event_filter_del
+#undef snd_seq_client_info_event_filter_check
+#undef snd_seq_get_client_info
+#undef snd_seq_get_any_client_info
+#undef snd_seq_set_client_info
+#undef snd_seq_query_next_client
+#undef snd_seq_client_pool_sizeof
+#undef snd_seq_client_pool_malloc
+#undef snd_seq_client_pool_free
+#undef snd_seq_client_pool_copy
+#undef snd_seq_client_pool_get_client
+#undef snd_seq_client_pool_get_output_pool
+#undef snd_seq_client_pool_get_input_pool
+#undef snd_seq_client_pool_get_output_room
+#undef snd_seq_client_pool_get_output_free
+#undef snd_seq_client_pool_get_input_free
+#undef snd_seq_client_pool_set_output_pool
+#undef snd_seq_client_pool_set_input_pool
+#undef snd_seq_client_pool_set_output_room
+#undef snd_seq_get_client_pool
+#undef snd_seq_set_client_pool
+#undef snd_seq_port_info_sizeof
+#undef snd_seq_port_info_malloc
+#undef snd_seq_port_info_free
+#undef snd_seq_port_info_copy
+#undef snd_seq_port_info_get_client
+#undef snd_seq_port_info_get_port
+#undef snd_seq_port_info_get_addr
+#undef snd_seq_port_info_get_name
+#undef snd_seq_port_info_get_capability
+#undef snd_seq_port_info_get_type
+#undef snd_seq_port_info_get_midi_channels
+#undef snd_seq_port_info_get_midi_voices
+#undef snd_seq_port_info_get_synth_voices
+#undef snd_seq_port_info_get_read_use
+#undef snd_seq_port_info_get_write_use
+#undef snd_seq_port_info_get_port_specified
+#undef snd_seq_port_info_get_timestamping
+#undef snd_seq_port_info_get_timestamp_real
+#undef snd_seq_port_info_get_timestamp_queue
+#undef snd_seq_port_info_set_client
+#undef snd_seq_port_info_set_port
+#undef snd_seq_port_info_set_addr
+#undef snd_seq_port_info_set_name
+#undef snd_seq_port_info_set_capability
+#undef snd_seq_port_info_set_type
+#undef snd_seq_port_info_set_midi_channels
+#undef snd_seq_port_info_set_midi_voices
+#undef snd_seq_port_info_set_synth_voices
+#undef snd_seq_port_info_set_port_specified
+#undef snd_seq_port_info_set_timestamping
+#undef snd_seq_port_info_set_timestamp_real
+#undef snd_seq_port_info_set_timestamp_queue
+#undef snd_seq_create_port
+#undef snd_seq_delete_port
+#undef snd_seq_get_port_info
+#undef snd_seq_get_any_port_info
+#undef snd_seq_set_port_info
+#undef snd_seq_query_next_port
+#undef snd_seq_port_subscribe_sizeof
+#undef snd_seq_port_subscribe_malloc
+#undef snd_seq_port_subscribe_free
+#undef snd_seq_port_subscribe_copy
+#undef snd_seq_port_subscribe_get_sender
+#undef snd_seq_port_subscribe_get_dest
+#undef snd_seq_port_subscribe_get_queue
+#undef snd_seq_port_subscribe_get_exclusive
+#undef snd_seq_port_subscribe_get_time_update
+#undef snd_seq_port_subscribe_get_time_real
+#undef snd_seq_port_subscribe_set_sender
+#undef snd_seq_port_subscribe_set_dest
+#undef snd_seq_port_subscribe_set_queue
+#undef snd_seq_port_subscribe_set_exclusive
+#undef snd_seq_port_subscribe_set_time_update
+#undef snd_seq_port_subscribe_set_time_real
+#undef snd_seq_get_port_subscription
+#undef snd_seq_subscribe_port
+#undef snd_seq_unsubscribe_port
+#undef snd_seq_query_subscribe_sizeof
+#undef snd_seq_query_subscribe_malloc
+#undef snd_seq_query_subscribe_free
+#undef snd_seq_query_subscribe_copy
+#undef snd_seq_query_subscribe_get_client
+#undef snd_seq_query_subscribe_get_port
+#undef snd_seq_query_subscribe_get_root
+#undef snd_seq_query_subscribe_get_type
+#undef snd_seq_query_subscribe_get_index
+#undef snd_seq_query_subscribe_get_num_subs
+#undef snd_seq_query_subscribe_get_addr
+#undef snd_seq_query_subscribe_get_queue
+#undef snd_seq_query_subscribe_get_exclusive
+#undef snd_seq_query_subscribe_get_time_update
+#undef snd_seq_query_subscribe_get_time_real
+#undef snd_seq_query_subscribe_set_client
+#undef snd_seq_query_subscribe_set_port
+#undef snd_seq_query_subscribe_set_root
+#undef snd_seq_query_subscribe_set_type
+#undef snd_seq_query_subscribe_set_index
+#undef snd_seq_query_port_subscribers
+#undef snd_seq_queue_info_sizeof
+#undef snd_seq_queue_info_malloc
+#undef snd_seq_queue_info_free
+#undef snd_seq_queue_info_copy
+#undef snd_seq_queue_info_get_queue
+#undef snd_seq_queue_info_get_name
+#undef snd_seq_queue_info_get_owner
+#undef snd_seq_queue_info_get_locked
+#undef snd_seq_queue_info_get_flags
+#undef snd_seq_queue_info_set_name
+#undef snd_seq_queue_info_set_owner
+#undef snd_seq_queue_info_set_locked
+#undef snd_seq_queue_info_set_flags
+#undef snd_seq_create_queue
+#undef snd_seq_alloc_named_queue
+#undef snd_seq_alloc_queue
+#undef snd_seq_free_queue
+#undef snd_seq_get_queue_info
+#undef snd_seq_set_queue_info
+#undef snd_seq_query_named_queue
+#undef snd_seq_get_queue_usage
+#undef snd_seq_set_queue_usage
+#undef snd_seq_queue_status_sizeof
+#undef snd_seq_queue_status_malloc
+#undef snd_seq_queue_status_free
+#undef snd_seq_queue_status_copy
+#undef snd_seq_queue_status_get_queue
+#undef snd_seq_queue_status_get_events
+#undef snd_seq_queue_status_get_tick_time
+#undef snd_seq_queue_status_get_real_time
+#undef snd_seq_queue_status_get_status
+#undef snd_seq_get_queue_status
+#undef snd_seq_queue_tempo_sizeof
+#undef snd_seq_queue_tempo_malloc
+#undef snd_seq_queue_tempo_free
+#undef snd_seq_queue_tempo_copy
+#undef snd_seq_queue_tempo_get_queue
+#undef snd_seq_queue_tempo_get_tempo
+#undef snd_seq_queue_tempo_get_ppq
+#undef snd_seq_queue_tempo_get_skew
+#undef snd_seq_queue_tempo_get_skew_base
+#undef snd_seq_queue_tempo_set_tempo
+#undef snd_seq_queue_tempo_set_ppq
+#undef snd_seq_queue_tempo_set_skew
+#undef snd_seq_queue_tempo_set_skew_base
+#undef snd_seq_get_queue_tempo
+#undef snd_seq_set_queue_tempo
+#undef snd_seq_queue_timer_sizeof
+#undef snd_seq_queue_timer_malloc
+#undef snd_seq_queue_timer_free
+#undef snd_seq_queue_timer_copy
+#undef snd_seq_queue_timer_get_queue
+#undef snd_seq_queue_timer_get_type
+#undef snd_seq_queue_timer_get_id
+#undef snd_seq_queue_timer_get_resolution
+#undef snd_seq_queue_timer_set_type
+#undef snd_seq_queue_timer_set_id
+#undef snd_seq_queue_timer_set_resolution
+#undef snd_seq_get_queue_timer
+#undef snd_seq_set_queue_timer
+#undef snd_seq_free_event
+#undef snd_seq_event_length
+#undef snd_seq_event_output
+#undef snd_seq_event_output_buffer
+#undef snd_seq_event_output_direct
+#undef snd_seq_event_input
+#undef snd_seq_event_input_pending
+#undef snd_seq_drain_output
+#undef snd_seq_event_output_pending
+#undef snd_seq_extract_output
+#undef snd_seq_drop_output
+#undef snd_seq_drop_output_buffer
+#undef snd_seq_drop_input
+#undef snd_seq_drop_input_buffer
+#undef snd_seq_remove_events_sizeof
+#undef snd_seq_remove_events_malloc
+#undef snd_seq_remove_events_free
+#undef snd_seq_remove_events_copy
+#undef snd_seq_remove_events_get_condition
+#undef snd_seq_remove_events_get_queue
+#undef snd_seq_remove_events_get_time
+#undef snd_seq_remove_events_get_dest
+#undef snd_seq_remove_events_get_channel
+#undef snd_seq_remove_events_get_event_type
+#undef snd_seq_remove_events_get_tag
+#undef snd_seq_remove_events_set_condition
+#undef snd_seq_remove_events_set_queue
+#undef snd_seq_remove_events_set_time
+#undef snd_seq_remove_events_set_dest
+#undef snd_seq_remove_events_set_channel
+#undef snd_seq_remove_events_set_event_type
+#undef snd_seq_remove_events_set_tag
+#undef snd_seq_remove_events
+#undef snd_seq_set_bit
+#undef snd_seq_unset_bit
+#undef snd_seq_change_bit
+#undef snd_seq_get_bit
+#undef snd_seq_control_queue
+#undef snd_seq_create_simple_port
+#undef snd_seq_delete_simple_port
+#undef snd_seq_connect_from
+#undef snd_seq_connect_to
+#undef snd_seq_disconnect_from
+#undef snd_seq_disconnect_to
+#undef snd_seq_set_client_name
+#undef snd_seq_set_client_event_filter
+#undef snd_seq_set_client_pool_output
+#undef snd_seq_set_client_pool_output_room
+#undef snd_seq_set_client_pool_input
+#undef snd_seq_sync_output_queue
+#undef snd_seq_parse_address
+#undef snd_seq_reset_pool_output
+#undef snd_seq_reset_pool_input
+#undef snd_midi_event_new
+#undef snd_midi_event_resize_buffer
+#undef snd_midi_event_free
+#undef snd_midi_event_init
+#undef snd_midi_event_reset_encode
+#undef snd_midi_event_reset_decode
+#undef snd_midi_event_no_status
+#undef snd_midi_event_encode
+#undef snd_midi_event_encode_byte
+#undef snd_midi_event_decode
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define snd_asoundlib_version snd_asoundlib_version_dylibloader_wrapper_asound
+#define snd_dlpath snd_dlpath_dylibloader_wrapper_asound
+#define snd_dlopen snd_dlopen_dylibloader_wrapper_asound
+#define snd_dlsym snd_dlsym_dylibloader_wrapper_asound
+#define snd_dlclose snd_dlclose_dylibloader_wrapper_asound
+#define snd_async_add_handler snd_async_add_handler_dylibloader_wrapper_asound
+#define snd_async_del_handler snd_async_del_handler_dylibloader_wrapper_asound
+#define snd_async_handler_get_fd snd_async_handler_get_fd_dylibloader_wrapper_asound
+#define snd_async_handler_get_signo snd_async_handler_get_signo_dylibloader_wrapper_asound
+#define snd_async_handler_get_callback_private snd_async_handler_get_callback_private_dylibloader_wrapper_asound
+#define snd_shm_area_create snd_shm_area_create_dylibloader_wrapper_asound
+#define snd_shm_area_share snd_shm_area_share_dylibloader_wrapper_asound
+#define snd_shm_area_destroy snd_shm_area_destroy_dylibloader_wrapper_asound
+#define snd_user_file snd_user_file_dylibloader_wrapper_asound
+#define snd_input_stdio_open snd_input_stdio_open_dylibloader_wrapper_asound
+#define snd_input_stdio_attach snd_input_stdio_attach_dylibloader_wrapper_asound
+#define snd_input_buffer_open snd_input_buffer_open_dylibloader_wrapper_asound
+#define snd_input_close snd_input_close_dylibloader_wrapper_asound
+#define snd_input_scanf snd_input_scanf_dylibloader_wrapper_asound
+#define snd_input_gets snd_input_gets_dylibloader_wrapper_asound
+#define snd_input_getc snd_input_getc_dylibloader_wrapper_asound
+#define snd_input_ungetc snd_input_ungetc_dylibloader_wrapper_asound
+#define snd_output_stdio_open snd_output_stdio_open_dylibloader_wrapper_asound
+#define snd_output_stdio_attach snd_output_stdio_attach_dylibloader_wrapper_asound
+#define snd_output_buffer_open snd_output_buffer_open_dylibloader_wrapper_asound
+#define snd_output_buffer_string snd_output_buffer_string_dylibloader_wrapper_asound
+#define snd_output_close snd_output_close_dylibloader_wrapper_asound
+#define snd_output_printf snd_output_printf_dylibloader_wrapper_asound
+#define snd_output_vprintf snd_output_vprintf_dylibloader_wrapper_asound
+#define snd_output_puts snd_output_puts_dylibloader_wrapper_asound
+#define snd_output_putc snd_output_putc_dylibloader_wrapper_asound
+#define snd_output_flush snd_output_flush_dylibloader_wrapper_asound
+#define snd_strerror snd_strerror_dylibloader_wrapper_asound
+#define snd_lib_error_set_handler snd_lib_error_set_handler_dylibloader_wrapper_asound
+#define snd_lib_error_set_local snd_lib_error_set_local_dylibloader_wrapper_asound
+#define snd_config_topdir snd_config_topdir_dylibloader_wrapper_asound
+#define snd_config_top snd_config_top_dylibloader_wrapper_asound
+#define snd_config_load snd_config_load_dylibloader_wrapper_asound
+#define snd_config_load_override snd_config_load_override_dylibloader_wrapper_asound
+#define snd_config_save snd_config_save_dylibloader_wrapper_asound
+#define snd_config_update snd_config_update_dylibloader_wrapper_asound
+#define snd_config_update_r snd_config_update_r_dylibloader_wrapper_asound
+#define snd_config_update_free snd_config_update_free_dylibloader_wrapper_asound
+#define snd_config_update_free_global snd_config_update_free_global_dylibloader_wrapper_asound
+#define snd_config_update_ref snd_config_update_ref_dylibloader_wrapper_asound
+#define snd_config_ref snd_config_ref_dylibloader_wrapper_asound
+#define snd_config_unref snd_config_unref_dylibloader_wrapper_asound
+#define snd_config_search snd_config_search_dylibloader_wrapper_asound
+#define snd_config_searchv snd_config_searchv_dylibloader_wrapper_asound
+#define snd_config_search_definition snd_config_search_definition_dylibloader_wrapper_asound
+#define snd_config_expand snd_config_expand_dylibloader_wrapper_asound
+#define snd_config_evaluate snd_config_evaluate_dylibloader_wrapper_asound
+#define snd_config_add snd_config_add_dylibloader_wrapper_asound
+#define snd_config_add_before snd_config_add_before_dylibloader_wrapper_asound
+#define snd_config_add_after snd_config_add_after_dylibloader_wrapper_asound
+#define snd_config_remove snd_config_remove_dylibloader_wrapper_asound
+#define snd_config_delete snd_config_delete_dylibloader_wrapper_asound
+#define snd_config_delete_compound_members snd_config_delete_compound_members_dylibloader_wrapper_asound
+#define snd_config_copy snd_config_copy_dylibloader_wrapper_asound
+#define snd_config_make snd_config_make_dylibloader_wrapper_asound
+#define snd_config_make_integer snd_config_make_integer_dylibloader_wrapper_asound
+#define snd_config_make_integer64 snd_config_make_integer64_dylibloader_wrapper_asound
+#define snd_config_make_real snd_config_make_real_dylibloader_wrapper_asound
+#define snd_config_make_string snd_config_make_string_dylibloader_wrapper_asound
+#define snd_config_make_pointer snd_config_make_pointer_dylibloader_wrapper_asound
+#define snd_config_make_compound snd_config_make_compound_dylibloader_wrapper_asound
+#define snd_config_imake_integer snd_config_imake_integer_dylibloader_wrapper_asound
+#define snd_config_imake_integer64 snd_config_imake_integer64_dylibloader_wrapper_asound
+#define snd_config_imake_real snd_config_imake_real_dylibloader_wrapper_asound
+#define snd_config_imake_string snd_config_imake_string_dylibloader_wrapper_asound
+#define snd_config_imake_safe_string snd_config_imake_safe_string_dylibloader_wrapper_asound
+#define snd_config_imake_pointer snd_config_imake_pointer_dylibloader_wrapper_asound
+#define snd_config_get_type snd_config_get_type_dylibloader_wrapper_asound
+#define snd_config_is_array snd_config_is_array_dylibloader_wrapper_asound
+#define snd_config_set_id snd_config_set_id_dylibloader_wrapper_asound
+#define snd_config_set_integer snd_config_set_integer_dylibloader_wrapper_asound
+#define snd_config_set_integer64 snd_config_set_integer64_dylibloader_wrapper_asound
+#define snd_config_set_real snd_config_set_real_dylibloader_wrapper_asound
+#define snd_config_set_string snd_config_set_string_dylibloader_wrapper_asound
+#define snd_config_set_ascii snd_config_set_ascii_dylibloader_wrapper_asound
+#define snd_config_set_pointer snd_config_set_pointer_dylibloader_wrapper_asound
+#define snd_config_get_id snd_config_get_id_dylibloader_wrapper_asound
+#define snd_config_get_integer snd_config_get_integer_dylibloader_wrapper_asound
+#define snd_config_get_integer64 snd_config_get_integer64_dylibloader_wrapper_asound
+#define snd_config_get_real snd_config_get_real_dylibloader_wrapper_asound
+#define snd_config_get_ireal snd_config_get_ireal_dylibloader_wrapper_asound
+#define snd_config_get_string snd_config_get_string_dylibloader_wrapper_asound
+#define snd_config_get_ascii snd_config_get_ascii_dylibloader_wrapper_asound
+#define snd_config_get_pointer snd_config_get_pointer_dylibloader_wrapper_asound
+#define snd_config_test_id snd_config_test_id_dylibloader_wrapper_asound
+#define snd_config_iterator_first snd_config_iterator_first_dylibloader_wrapper_asound
+#define snd_config_iterator_next snd_config_iterator_next_dylibloader_wrapper_asound
+#define snd_config_iterator_end snd_config_iterator_end_dylibloader_wrapper_asound
+#define snd_config_iterator_entry snd_config_iterator_entry_dylibloader_wrapper_asound
+#define snd_config_get_bool_ascii snd_config_get_bool_ascii_dylibloader_wrapper_asound
+#define snd_config_get_bool snd_config_get_bool_dylibloader_wrapper_asound
+#define snd_config_get_ctl_iface_ascii snd_config_get_ctl_iface_ascii_dylibloader_wrapper_asound
+#define snd_config_get_ctl_iface snd_config_get_ctl_iface_dylibloader_wrapper_asound
+#define snd_names_list snd_names_list_dylibloader_wrapper_asound
+#define snd_names_list_free snd_names_list_free_dylibloader_wrapper_asound
+#define snd_pcm_open snd_pcm_open_dylibloader_wrapper_asound
+#define snd_pcm_open_lconf snd_pcm_open_lconf_dylibloader_wrapper_asound
+#define snd_pcm_open_fallback snd_pcm_open_fallback_dylibloader_wrapper_asound
+#define snd_pcm_close snd_pcm_close_dylibloader_wrapper_asound
+#define snd_pcm_name snd_pcm_name_dylibloader_wrapper_asound
+#define snd_pcm_type snd_pcm_type_dylibloader_wrapper_asound
+#define snd_pcm_stream snd_pcm_stream_dylibloader_wrapper_asound
+#define snd_pcm_poll_descriptors_count snd_pcm_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_pcm_poll_descriptors snd_pcm_poll_descriptors_dylibloader_wrapper_asound
+#define snd_pcm_poll_descriptors_revents snd_pcm_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_pcm_nonblock snd_pcm_nonblock_dylibloader_wrapper_asound
+#define snd_async_add_pcm_handler snd_async_add_pcm_handler_dylibloader_wrapper_asound
+#define snd_async_handler_get_pcm snd_async_handler_get_pcm_dylibloader_wrapper_asound
+#define snd_pcm_info snd_pcm_info_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_current snd_pcm_hw_params_current_dylibloader_wrapper_asound
+#define snd_pcm_hw_params snd_pcm_hw_params_dylibloader_wrapper_asound
+#define snd_pcm_hw_free snd_pcm_hw_free_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_current snd_pcm_sw_params_current_dylibloader_wrapper_asound
+#define snd_pcm_sw_params snd_pcm_sw_params_dylibloader_wrapper_asound
+#define snd_pcm_prepare snd_pcm_prepare_dylibloader_wrapper_asound
+#define snd_pcm_reset snd_pcm_reset_dylibloader_wrapper_asound
+#define snd_pcm_status snd_pcm_status_dylibloader_wrapper_asound
+#define snd_pcm_start snd_pcm_start_dylibloader_wrapper_asound
+#define snd_pcm_drop snd_pcm_drop_dylibloader_wrapper_asound
+#define snd_pcm_drain snd_pcm_drain_dylibloader_wrapper_asound
+#define snd_pcm_pause snd_pcm_pause_dylibloader_wrapper_asound
+#define snd_pcm_state snd_pcm_state_dylibloader_wrapper_asound
+#define snd_pcm_hwsync snd_pcm_hwsync_dylibloader_wrapper_asound
+#define snd_pcm_delay snd_pcm_delay_dylibloader_wrapper_asound
+#define snd_pcm_resume snd_pcm_resume_dylibloader_wrapper_asound
+#define snd_pcm_htimestamp snd_pcm_htimestamp_dylibloader_wrapper_asound
+#define snd_pcm_avail snd_pcm_avail_dylibloader_wrapper_asound
+#define snd_pcm_avail_update snd_pcm_avail_update_dylibloader_wrapper_asound
+#define snd_pcm_avail_delay snd_pcm_avail_delay_dylibloader_wrapper_asound
+#define snd_pcm_rewindable snd_pcm_rewindable_dylibloader_wrapper_asound
+#define snd_pcm_rewind snd_pcm_rewind_dylibloader_wrapper_asound
+#define snd_pcm_forwardable snd_pcm_forwardable_dylibloader_wrapper_asound
+#define snd_pcm_forward snd_pcm_forward_dylibloader_wrapper_asound
+#define snd_pcm_writei snd_pcm_writei_dylibloader_wrapper_asound
+#define snd_pcm_readi snd_pcm_readi_dylibloader_wrapper_asound
+#define snd_pcm_writen snd_pcm_writen_dylibloader_wrapper_asound
+#define snd_pcm_readn snd_pcm_readn_dylibloader_wrapper_asound
+#define snd_pcm_wait snd_pcm_wait_dylibloader_wrapper_asound
+#define snd_pcm_link snd_pcm_link_dylibloader_wrapper_asound
+#define snd_pcm_unlink snd_pcm_unlink_dylibloader_wrapper_asound
+#define snd_pcm_query_chmaps snd_pcm_query_chmaps_dylibloader_wrapper_asound
+#define snd_pcm_query_chmaps_from_hw snd_pcm_query_chmaps_from_hw_dylibloader_wrapper_asound
+#define snd_pcm_free_chmaps snd_pcm_free_chmaps_dylibloader_wrapper_asound
+#define snd_pcm_get_chmap snd_pcm_get_chmap_dylibloader_wrapper_asound
+#define snd_pcm_set_chmap snd_pcm_set_chmap_dylibloader_wrapper_asound
+#define snd_pcm_chmap_type_name snd_pcm_chmap_type_name_dylibloader_wrapper_asound
+#define snd_pcm_chmap_name snd_pcm_chmap_name_dylibloader_wrapper_asound
+#define snd_pcm_chmap_long_name snd_pcm_chmap_long_name_dylibloader_wrapper_asound
+#define snd_pcm_chmap_print snd_pcm_chmap_print_dylibloader_wrapper_asound
+#define snd_pcm_chmap_from_string snd_pcm_chmap_from_string_dylibloader_wrapper_asound
+#define snd_pcm_chmap_parse_string snd_pcm_chmap_parse_string_dylibloader_wrapper_asound
+#define snd_pcm_recover snd_pcm_recover_dylibloader_wrapper_asound
+#define snd_pcm_set_params snd_pcm_set_params_dylibloader_wrapper_asound
+#define snd_pcm_get_params snd_pcm_get_params_dylibloader_wrapper_asound
+#define snd_pcm_info_sizeof snd_pcm_info_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_info_malloc snd_pcm_info_malloc_dylibloader_wrapper_asound
+#define snd_pcm_info_free snd_pcm_info_free_dylibloader_wrapper_asound
+#define snd_pcm_info_copy snd_pcm_info_copy_dylibloader_wrapper_asound
+#define snd_pcm_info_get_device snd_pcm_info_get_device_dylibloader_wrapper_asound
+#define snd_pcm_info_get_subdevice snd_pcm_info_get_subdevice_dylibloader_wrapper_asound
+#define snd_pcm_info_get_stream snd_pcm_info_get_stream_dylibloader_wrapper_asound
+#define snd_pcm_info_get_card snd_pcm_info_get_card_dylibloader_wrapper_asound
+#define snd_pcm_info_get_id snd_pcm_info_get_id_dylibloader_wrapper_asound
+#define snd_pcm_info_get_name snd_pcm_info_get_name_dylibloader_wrapper_asound
+#define snd_pcm_info_get_subdevice_name snd_pcm_info_get_subdevice_name_dylibloader_wrapper_asound
+#define snd_pcm_info_get_class snd_pcm_info_get_class_dylibloader_wrapper_asound
+#define snd_pcm_info_get_subclass snd_pcm_info_get_subclass_dylibloader_wrapper_asound
+#define snd_pcm_info_get_subdevices_count snd_pcm_info_get_subdevices_count_dylibloader_wrapper_asound
+#define snd_pcm_info_get_subdevices_avail snd_pcm_info_get_subdevices_avail_dylibloader_wrapper_asound
+#define snd_pcm_info_get_sync snd_pcm_info_get_sync_dylibloader_wrapper_asound
+#define snd_pcm_info_set_device snd_pcm_info_set_device_dylibloader_wrapper_asound
+#define snd_pcm_info_set_subdevice snd_pcm_info_set_subdevice_dylibloader_wrapper_asound
+#define snd_pcm_info_set_stream snd_pcm_info_set_stream_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_any snd_pcm_hw_params_any_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_mmap_sample_resolution snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_double snd_pcm_hw_params_is_double_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_batch snd_pcm_hw_params_is_batch_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_block_transfer snd_pcm_hw_params_is_block_transfer_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_monotonic snd_pcm_hw_params_is_monotonic_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_overrange snd_pcm_hw_params_can_overrange_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_pause snd_pcm_hw_params_can_pause_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_resume snd_pcm_hw_params_can_resume_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_half_duplex snd_pcm_hw_params_is_half_duplex_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_is_joint_duplex snd_pcm_hw_params_is_joint_duplex_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_sync_start snd_pcm_hw_params_can_sync_start_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_can_disable_period_wakeup snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_supports_audio_wallclock_ts snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_supports_audio_ts_type snd_pcm_hw_params_supports_audio_ts_type_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_rate_numden snd_pcm_hw_params_get_rate_numden_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_sbits snd_pcm_hw_params_get_sbits_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_fifo_size snd_pcm_hw_params_get_fifo_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_sizeof snd_pcm_hw_params_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_malloc snd_pcm_hw_params_malloc_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_free snd_pcm_hw_params_free_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_copy snd_pcm_hw_params_copy_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_access snd_pcm_hw_params_get_access_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_access snd_pcm_hw_params_test_access_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_access snd_pcm_hw_params_set_access_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_access_first snd_pcm_hw_params_set_access_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_access_last snd_pcm_hw_params_set_access_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_access_mask snd_pcm_hw_params_set_access_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_access_mask snd_pcm_hw_params_get_access_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_format snd_pcm_hw_params_get_format_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_format snd_pcm_hw_params_test_format_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_format snd_pcm_hw_params_set_format_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_format_first snd_pcm_hw_params_set_format_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_format_last snd_pcm_hw_params_set_format_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_format_mask snd_pcm_hw_params_set_format_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_format_mask snd_pcm_hw_params_get_format_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_subformat snd_pcm_hw_params_get_subformat_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_subformat snd_pcm_hw_params_test_subformat_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_subformat snd_pcm_hw_params_set_subformat_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_subformat_first snd_pcm_hw_params_set_subformat_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_subformat_last snd_pcm_hw_params_set_subformat_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_subformat_mask snd_pcm_hw_params_set_subformat_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_subformat_mask snd_pcm_hw_params_get_subformat_mask_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_channels snd_pcm_hw_params_get_channels_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_channels_min snd_pcm_hw_params_get_channels_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_channels_max snd_pcm_hw_params_get_channels_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_channels snd_pcm_hw_params_test_channels_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels snd_pcm_hw_params_set_channels_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_min snd_pcm_hw_params_set_channels_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_max snd_pcm_hw_params_set_channels_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_minmax snd_pcm_hw_params_set_channels_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_near snd_pcm_hw_params_set_channels_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_first snd_pcm_hw_params_set_channels_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_channels_last snd_pcm_hw_params_set_channels_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_rate snd_pcm_hw_params_get_rate_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_rate_min snd_pcm_hw_params_get_rate_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_rate_max snd_pcm_hw_params_get_rate_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_rate snd_pcm_hw_params_test_rate_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate snd_pcm_hw_params_set_rate_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_min snd_pcm_hw_params_set_rate_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_max snd_pcm_hw_params_set_rate_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_minmax snd_pcm_hw_params_set_rate_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_near snd_pcm_hw_params_set_rate_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_first snd_pcm_hw_params_set_rate_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_last snd_pcm_hw_params_set_rate_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_rate_resample snd_pcm_hw_params_set_rate_resample_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_rate_resample snd_pcm_hw_params_get_rate_resample_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_export_buffer snd_pcm_hw_params_set_export_buffer_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_export_buffer snd_pcm_hw_params_get_export_buffer_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_wakeup snd_pcm_hw_params_set_period_wakeup_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_wakeup snd_pcm_hw_params_get_period_wakeup_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_time snd_pcm_hw_params_get_period_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_time_min snd_pcm_hw_params_get_period_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_time_max snd_pcm_hw_params_get_period_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_period_time snd_pcm_hw_params_test_period_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time snd_pcm_hw_params_set_period_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_min snd_pcm_hw_params_set_period_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_max snd_pcm_hw_params_set_period_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_minmax snd_pcm_hw_params_set_period_time_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_near snd_pcm_hw_params_set_period_time_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_first snd_pcm_hw_params_set_period_time_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_time_last snd_pcm_hw_params_set_period_time_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_size snd_pcm_hw_params_get_period_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_size_min snd_pcm_hw_params_get_period_size_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_period_size_max snd_pcm_hw_params_get_period_size_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_period_size snd_pcm_hw_params_test_period_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size snd_pcm_hw_params_set_period_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_min snd_pcm_hw_params_set_period_size_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_max snd_pcm_hw_params_set_period_size_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_minmax snd_pcm_hw_params_set_period_size_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_near snd_pcm_hw_params_set_period_size_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_first snd_pcm_hw_params_set_period_size_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_last snd_pcm_hw_params_set_period_size_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_period_size_integer snd_pcm_hw_params_set_period_size_integer_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_periods snd_pcm_hw_params_get_periods_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_periods_min snd_pcm_hw_params_get_periods_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_periods_max snd_pcm_hw_params_get_periods_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_periods snd_pcm_hw_params_test_periods_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods snd_pcm_hw_params_set_periods_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_min snd_pcm_hw_params_set_periods_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_max snd_pcm_hw_params_set_periods_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_minmax snd_pcm_hw_params_set_periods_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_near snd_pcm_hw_params_set_periods_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_first snd_pcm_hw_params_set_periods_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_last snd_pcm_hw_params_set_periods_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_periods_integer snd_pcm_hw_params_set_periods_integer_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_time snd_pcm_hw_params_get_buffer_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_time_min snd_pcm_hw_params_get_buffer_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_time_max snd_pcm_hw_params_get_buffer_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_buffer_time snd_pcm_hw_params_test_buffer_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time snd_pcm_hw_params_set_buffer_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_min snd_pcm_hw_params_set_buffer_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_max snd_pcm_hw_params_set_buffer_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_minmax snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_near snd_pcm_hw_params_set_buffer_time_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_first snd_pcm_hw_params_set_buffer_time_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_time_last snd_pcm_hw_params_set_buffer_time_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_size snd_pcm_hw_params_get_buffer_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_size_min snd_pcm_hw_params_get_buffer_size_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_buffer_size_max snd_pcm_hw_params_get_buffer_size_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_buffer_size snd_pcm_hw_params_test_buffer_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size snd_pcm_hw_params_set_buffer_size_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_min snd_pcm_hw_params_set_buffer_size_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_max snd_pcm_hw_params_set_buffer_size_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_minmax snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_near snd_pcm_hw_params_set_buffer_size_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_first snd_pcm_hw_params_set_buffer_size_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_buffer_size_last snd_pcm_hw_params_set_buffer_size_last_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_min_align snd_pcm_hw_params_get_min_align_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_sizeof snd_pcm_sw_params_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_malloc snd_pcm_sw_params_malloc_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_free snd_pcm_sw_params_free_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_copy snd_pcm_sw_params_copy_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_boundary snd_pcm_sw_params_get_boundary_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_tstamp_mode snd_pcm_sw_params_set_tstamp_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_tstamp_mode snd_pcm_sw_params_get_tstamp_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_avail_min snd_pcm_sw_params_set_avail_min_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_avail_min snd_pcm_sw_params_get_avail_min_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_period_event snd_pcm_sw_params_set_period_event_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_period_event snd_pcm_sw_params_get_period_event_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_start_threshold snd_pcm_sw_params_set_start_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_start_threshold snd_pcm_sw_params_get_start_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_stop_threshold snd_pcm_sw_params_set_stop_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_stop_threshold snd_pcm_sw_params_get_stop_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_silence_threshold snd_pcm_sw_params_set_silence_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_silence_threshold snd_pcm_sw_params_get_silence_threshold_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_silence_size snd_pcm_sw_params_set_silence_size_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_silence_size snd_pcm_sw_params_get_silence_size_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_sizeof snd_pcm_access_mask_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_malloc snd_pcm_access_mask_malloc_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_free snd_pcm_access_mask_free_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_copy snd_pcm_access_mask_copy_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_none snd_pcm_access_mask_none_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_any snd_pcm_access_mask_any_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_test snd_pcm_access_mask_test_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_empty snd_pcm_access_mask_empty_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_set snd_pcm_access_mask_set_dylibloader_wrapper_asound
+#define snd_pcm_access_mask_reset snd_pcm_access_mask_reset_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_sizeof snd_pcm_format_mask_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_malloc snd_pcm_format_mask_malloc_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_free snd_pcm_format_mask_free_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_copy snd_pcm_format_mask_copy_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_none snd_pcm_format_mask_none_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_any snd_pcm_format_mask_any_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_test snd_pcm_format_mask_test_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_empty snd_pcm_format_mask_empty_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_set snd_pcm_format_mask_set_dylibloader_wrapper_asound
+#define snd_pcm_format_mask_reset snd_pcm_format_mask_reset_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_sizeof snd_pcm_subformat_mask_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_malloc snd_pcm_subformat_mask_malloc_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_free snd_pcm_subformat_mask_free_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_copy snd_pcm_subformat_mask_copy_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_none snd_pcm_subformat_mask_none_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_any snd_pcm_subformat_mask_any_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_test snd_pcm_subformat_mask_test_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_empty snd_pcm_subformat_mask_empty_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_set snd_pcm_subformat_mask_set_dylibloader_wrapper_asound
+#define snd_pcm_subformat_mask_reset snd_pcm_subformat_mask_reset_dylibloader_wrapper_asound
+#define snd_pcm_status_sizeof snd_pcm_status_sizeof_dylibloader_wrapper_asound
+#define snd_pcm_status_malloc snd_pcm_status_malloc_dylibloader_wrapper_asound
+#define snd_pcm_status_free snd_pcm_status_free_dylibloader_wrapper_asound
+#define snd_pcm_status_copy snd_pcm_status_copy_dylibloader_wrapper_asound
+#define snd_pcm_status_get_state snd_pcm_status_get_state_dylibloader_wrapper_asound
+#define snd_pcm_status_get_trigger_tstamp snd_pcm_status_get_trigger_tstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_trigger_htstamp snd_pcm_status_get_trigger_htstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_tstamp snd_pcm_status_get_tstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_htstamp snd_pcm_status_get_htstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_audio_htstamp snd_pcm_status_get_audio_htstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_driver_htstamp snd_pcm_status_get_driver_htstamp_dylibloader_wrapper_asound
+#define snd_pcm_status_get_delay snd_pcm_status_get_delay_dylibloader_wrapper_asound
+#define snd_pcm_status_get_avail snd_pcm_status_get_avail_dylibloader_wrapper_asound
+#define snd_pcm_status_get_avail_max snd_pcm_status_get_avail_max_dylibloader_wrapper_asound
+#define snd_pcm_status_get_overrange snd_pcm_status_get_overrange_dylibloader_wrapper_asound
+#define snd_pcm_type_name snd_pcm_type_name_dylibloader_wrapper_asound
+#define snd_pcm_stream_name snd_pcm_stream_name_dylibloader_wrapper_asound
+#define snd_pcm_access_name snd_pcm_access_name_dylibloader_wrapper_asound
+#define snd_pcm_format_name snd_pcm_format_name_dylibloader_wrapper_asound
+#define snd_pcm_format_description snd_pcm_format_description_dylibloader_wrapper_asound
+#define snd_pcm_subformat_name snd_pcm_subformat_name_dylibloader_wrapper_asound
+#define snd_pcm_subformat_description snd_pcm_subformat_description_dylibloader_wrapper_asound
+#define snd_pcm_format_value snd_pcm_format_value_dylibloader_wrapper_asound
+#define snd_pcm_tstamp_mode_name snd_pcm_tstamp_mode_name_dylibloader_wrapper_asound
+#define snd_pcm_state_name snd_pcm_state_name_dylibloader_wrapper_asound
+#define snd_pcm_dump snd_pcm_dump_dylibloader_wrapper_asound
+#define snd_pcm_dump_hw_setup snd_pcm_dump_hw_setup_dylibloader_wrapper_asound
+#define snd_pcm_dump_sw_setup snd_pcm_dump_sw_setup_dylibloader_wrapper_asound
+#define snd_pcm_dump_setup snd_pcm_dump_setup_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_dump snd_pcm_hw_params_dump_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_dump snd_pcm_sw_params_dump_dylibloader_wrapper_asound
+#define snd_pcm_status_dump snd_pcm_status_dump_dylibloader_wrapper_asound
+#define snd_pcm_mmap_begin snd_pcm_mmap_begin_dylibloader_wrapper_asound
+#define snd_pcm_mmap_commit snd_pcm_mmap_commit_dylibloader_wrapper_asound
+#define snd_pcm_mmap_writei snd_pcm_mmap_writei_dylibloader_wrapper_asound
+#define snd_pcm_mmap_readi snd_pcm_mmap_readi_dylibloader_wrapper_asound
+#define snd_pcm_mmap_writen snd_pcm_mmap_writen_dylibloader_wrapper_asound
+#define snd_pcm_mmap_readn snd_pcm_mmap_readn_dylibloader_wrapper_asound
+#define snd_pcm_format_signed snd_pcm_format_signed_dylibloader_wrapper_asound
+#define snd_pcm_format_unsigned snd_pcm_format_unsigned_dylibloader_wrapper_asound
+#define snd_pcm_format_linear snd_pcm_format_linear_dylibloader_wrapper_asound
+#define snd_pcm_format_float snd_pcm_format_float_dylibloader_wrapper_asound
+#define snd_pcm_format_little_endian snd_pcm_format_little_endian_dylibloader_wrapper_asound
+#define snd_pcm_format_big_endian snd_pcm_format_big_endian_dylibloader_wrapper_asound
+#define snd_pcm_format_cpu_endian snd_pcm_format_cpu_endian_dylibloader_wrapper_asound
+#define snd_pcm_format_width snd_pcm_format_width_dylibloader_wrapper_asound
+#define snd_pcm_format_physical_width snd_pcm_format_physical_width_dylibloader_wrapper_asound
+#define snd_pcm_build_linear_format snd_pcm_build_linear_format_dylibloader_wrapper_asound
+#define snd_pcm_format_size snd_pcm_format_size_dylibloader_wrapper_asound
+#define snd_pcm_format_silence snd_pcm_format_silence_dylibloader_wrapper_asound
+#define snd_pcm_format_silence_16 snd_pcm_format_silence_16_dylibloader_wrapper_asound
+#define snd_pcm_format_silence_32 snd_pcm_format_silence_32_dylibloader_wrapper_asound
+#define snd_pcm_format_silence_64 snd_pcm_format_silence_64_dylibloader_wrapper_asound
+#define snd_pcm_format_set_silence snd_pcm_format_set_silence_dylibloader_wrapper_asound
+#define snd_pcm_bytes_to_frames snd_pcm_bytes_to_frames_dylibloader_wrapper_asound
+#define snd_pcm_frames_to_bytes snd_pcm_frames_to_bytes_dylibloader_wrapper_asound
+#define snd_pcm_bytes_to_samples snd_pcm_bytes_to_samples_dylibloader_wrapper_asound
+#define snd_pcm_samples_to_bytes snd_pcm_samples_to_bytes_dylibloader_wrapper_asound
+#define snd_pcm_area_silence snd_pcm_area_silence_dylibloader_wrapper_asound
+#define snd_pcm_areas_silence snd_pcm_areas_silence_dylibloader_wrapper_asound
+#define snd_pcm_area_copy snd_pcm_area_copy_dylibloader_wrapper_asound
+#define snd_pcm_areas_copy snd_pcm_areas_copy_dylibloader_wrapper_asound
+#define snd_pcm_areas_copy_wrap snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound
+#define snd_pcm_hook_get_pcm snd_pcm_hook_get_pcm_dylibloader_wrapper_asound
+#define snd_pcm_hook_get_private snd_pcm_hook_get_private_dylibloader_wrapper_asound
+#define snd_pcm_hook_set_private snd_pcm_hook_set_private_dylibloader_wrapper_asound
+#define snd_pcm_hook_add snd_pcm_hook_add_dylibloader_wrapper_asound
+#define snd_pcm_hook_remove snd_pcm_hook_remove_dylibloader_wrapper_asound
+#define snd_pcm_meter_get_bufsize snd_pcm_meter_get_bufsize_dylibloader_wrapper_asound
+#define snd_pcm_meter_get_channels snd_pcm_meter_get_channels_dylibloader_wrapper_asound
+#define snd_pcm_meter_get_rate snd_pcm_meter_get_rate_dylibloader_wrapper_asound
+#define snd_pcm_meter_get_now snd_pcm_meter_get_now_dylibloader_wrapper_asound
+#define snd_pcm_meter_get_boundary snd_pcm_meter_get_boundary_dylibloader_wrapper_asound
+#define snd_pcm_meter_add_scope snd_pcm_meter_add_scope_dylibloader_wrapper_asound
+#define snd_pcm_meter_search_scope snd_pcm_meter_search_scope_dylibloader_wrapper_asound
+#define snd_pcm_scope_malloc snd_pcm_scope_malloc_dylibloader_wrapper_asound
+#define snd_pcm_scope_set_ops snd_pcm_scope_set_ops_dylibloader_wrapper_asound
+#define snd_pcm_scope_set_name snd_pcm_scope_set_name_dylibloader_wrapper_asound
+#define snd_pcm_scope_get_name snd_pcm_scope_get_name_dylibloader_wrapper_asound
+#define snd_pcm_scope_get_callback_private snd_pcm_scope_get_callback_private_dylibloader_wrapper_asound
+#define snd_pcm_scope_set_callback_private snd_pcm_scope_set_callback_private_dylibloader_wrapper_asound
+#define snd_pcm_scope_s16_open snd_pcm_scope_s16_open_dylibloader_wrapper_asound
+#define snd_pcm_scope_s16_get_channel_buffer snd_pcm_scope_s16_get_channel_buffer_dylibloader_wrapper_asound
+#define snd_spcm_init snd_spcm_init_dylibloader_wrapper_asound
+#define snd_spcm_init_duplex snd_spcm_init_duplex_dylibloader_wrapper_asound
+#define snd_spcm_init_get_params snd_spcm_init_get_params_dylibloader_wrapper_asound
+#define snd_pcm_start_mode_name snd_pcm_start_mode_name_dylibloader_wrapper_asound
+#define snd_pcm_xrun_mode_name snd_pcm_xrun_mode_name_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_start_mode snd_pcm_sw_params_set_start_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_start_mode snd_pcm_sw_params_get_start_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_xrun_mode snd_pcm_sw_params_set_xrun_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_xrun_mode snd_pcm_sw_params_get_xrun_mode_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_xfer_align snd_pcm_sw_params_set_xfer_align_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_xfer_align snd_pcm_sw_params_get_xfer_align_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_set_sleep_min snd_pcm_sw_params_set_sleep_min_dylibloader_wrapper_asound
+#define snd_pcm_sw_params_get_sleep_min snd_pcm_sw_params_get_sleep_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_tick_time snd_pcm_hw_params_get_tick_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_tick_time_min snd_pcm_hw_params_get_tick_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_get_tick_time_max snd_pcm_hw_params_get_tick_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_test_tick_time snd_pcm_hw_params_test_tick_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time snd_pcm_hw_params_set_tick_time_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_min snd_pcm_hw_params_set_tick_time_min_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_max snd_pcm_hw_params_set_tick_time_max_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_minmax snd_pcm_hw_params_set_tick_time_minmax_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_near snd_pcm_hw_params_set_tick_time_near_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_first snd_pcm_hw_params_set_tick_time_first_dylibloader_wrapper_asound
+#define snd_pcm_hw_params_set_tick_time_last snd_pcm_hw_params_set_tick_time_last_dylibloader_wrapper_asound
+#define snd_rawmidi_open snd_rawmidi_open_dylibloader_wrapper_asound
+#define snd_rawmidi_open_lconf snd_rawmidi_open_lconf_dylibloader_wrapper_asound
+#define snd_rawmidi_close snd_rawmidi_close_dylibloader_wrapper_asound
+#define snd_rawmidi_poll_descriptors_count snd_rawmidi_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_rawmidi_poll_descriptors snd_rawmidi_poll_descriptors_dylibloader_wrapper_asound
+#define snd_rawmidi_poll_descriptors_revents snd_rawmidi_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_rawmidi_nonblock snd_rawmidi_nonblock_dylibloader_wrapper_asound
+#define snd_rawmidi_info_sizeof snd_rawmidi_info_sizeof_dylibloader_wrapper_asound
+#define snd_rawmidi_info_malloc snd_rawmidi_info_malloc_dylibloader_wrapper_asound
+#define snd_rawmidi_info_free snd_rawmidi_info_free_dylibloader_wrapper_asound
+#define snd_rawmidi_info_copy snd_rawmidi_info_copy_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_device snd_rawmidi_info_get_device_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_subdevice snd_rawmidi_info_get_subdevice_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_stream snd_rawmidi_info_get_stream_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_card snd_rawmidi_info_get_card_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_flags snd_rawmidi_info_get_flags_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_id snd_rawmidi_info_get_id_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_name snd_rawmidi_info_get_name_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_subdevice_name snd_rawmidi_info_get_subdevice_name_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_subdevices_count snd_rawmidi_info_get_subdevices_count_dylibloader_wrapper_asound
+#define snd_rawmidi_info_get_subdevices_avail snd_rawmidi_info_get_subdevices_avail_dylibloader_wrapper_asound
+#define snd_rawmidi_info_set_device snd_rawmidi_info_set_device_dylibloader_wrapper_asound
+#define snd_rawmidi_info_set_subdevice snd_rawmidi_info_set_subdevice_dylibloader_wrapper_asound
+#define snd_rawmidi_info_set_stream snd_rawmidi_info_set_stream_dylibloader_wrapper_asound
+#define snd_rawmidi_info snd_rawmidi_info_dylibloader_wrapper_asound
+#define snd_rawmidi_params_sizeof snd_rawmidi_params_sizeof_dylibloader_wrapper_asound
+#define snd_rawmidi_params_malloc snd_rawmidi_params_malloc_dylibloader_wrapper_asound
+#define snd_rawmidi_params_free snd_rawmidi_params_free_dylibloader_wrapper_asound
+#define snd_rawmidi_params_copy snd_rawmidi_params_copy_dylibloader_wrapper_asound
+#define snd_rawmidi_params_set_buffer_size snd_rawmidi_params_set_buffer_size_dylibloader_wrapper_asound
+#define snd_rawmidi_params_get_buffer_size snd_rawmidi_params_get_buffer_size_dylibloader_wrapper_asound
+#define snd_rawmidi_params_set_avail_min snd_rawmidi_params_set_avail_min_dylibloader_wrapper_asound
+#define snd_rawmidi_params_get_avail_min snd_rawmidi_params_get_avail_min_dylibloader_wrapper_asound
+#define snd_rawmidi_params_set_no_active_sensing snd_rawmidi_params_set_no_active_sensing_dylibloader_wrapper_asound
+#define snd_rawmidi_params_get_no_active_sensing snd_rawmidi_params_get_no_active_sensing_dylibloader_wrapper_asound
+#define snd_rawmidi_params snd_rawmidi_params_dylibloader_wrapper_asound
+#define snd_rawmidi_params_current snd_rawmidi_params_current_dylibloader_wrapper_asound
+#define snd_rawmidi_status_sizeof snd_rawmidi_status_sizeof_dylibloader_wrapper_asound
+#define snd_rawmidi_status_malloc snd_rawmidi_status_malloc_dylibloader_wrapper_asound
+#define snd_rawmidi_status_free snd_rawmidi_status_free_dylibloader_wrapper_asound
+#define snd_rawmidi_status_copy snd_rawmidi_status_copy_dylibloader_wrapper_asound
+#define snd_rawmidi_status_get_tstamp snd_rawmidi_status_get_tstamp_dylibloader_wrapper_asound
+#define snd_rawmidi_status_get_avail snd_rawmidi_status_get_avail_dylibloader_wrapper_asound
+#define snd_rawmidi_status_get_xruns snd_rawmidi_status_get_xruns_dylibloader_wrapper_asound
+#define snd_rawmidi_status snd_rawmidi_status_dylibloader_wrapper_asound
+#define snd_rawmidi_drain snd_rawmidi_drain_dylibloader_wrapper_asound
+#define snd_rawmidi_drop snd_rawmidi_drop_dylibloader_wrapper_asound
+#define snd_rawmidi_write snd_rawmidi_write_dylibloader_wrapper_asound
+#define snd_rawmidi_read snd_rawmidi_read_dylibloader_wrapper_asound
+#define snd_rawmidi_name snd_rawmidi_name_dylibloader_wrapper_asound
+#define snd_rawmidi_type snd_rawmidi_type_dylibloader_wrapper_asound
+#define snd_rawmidi_stream snd_rawmidi_stream_dylibloader_wrapper_asound
+#define snd_timer_query_open snd_timer_query_open_dylibloader_wrapper_asound
+#define snd_timer_query_open_lconf snd_timer_query_open_lconf_dylibloader_wrapper_asound
+#define snd_timer_query_close snd_timer_query_close_dylibloader_wrapper_asound
+#define snd_timer_query_next_device snd_timer_query_next_device_dylibloader_wrapper_asound
+#define snd_timer_query_info snd_timer_query_info_dylibloader_wrapper_asound
+#define snd_timer_query_params snd_timer_query_params_dylibloader_wrapper_asound
+#define snd_timer_query_status snd_timer_query_status_dylibloader_wrapper_asound
+#define snd_timer_open snd_timer_open_dylibloader_wrapper_asound
+#define snd_timer_open_lconf snd_timer_open_lconf_dylibloader_wrapper_asound
+#define snd_timer_close snd_timer_close_dylibloader_wrapper_asound
+#define snd_async_add_timer_handler snd_async_add_timer_handler_dylibloader_wrapper_asound
+#define snd_async_handler_get_timer snd_async_handler_get_timer_dylibloader_wrapper_asound
+#define snd_timer_poll_descriptors_count snd_timer_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_timer_poll_descriptors snd_timer_poll_descriptors_dylibloader_wrapper_asound
+#define snd_timer_poll_descriptors_revents snd_timer_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_timer_info snd_timer_info_dylibloader_wrapper_asound
+#define snd_timer_params snd_timer_params_dylibloader_wrapper_asound
+#define snd_timer_status snd_timer_status_dylibloader_wrapper_asound
+#define snd_timer_start snd_timer_start_dylibloader_wrapper_asound
+#define snd_timer_stop snd_timer_stop_dylibloader_wrapper_asound
+#define snd_timer_continue snd_timer_continue_dylibloader_wrapper_asound
+#define snd_timer_read snd_timer_read_dylibloader_wrapper_asound
+#define snd_timer_id_sizeof snd_timer_id_sizeof_dylibloader_wrapper_asound
+#define snd_timer_id_malloc snd_timer_id_malloc_dylibloader_wrapper_asound
+#define snd_timer_id_free snd_timer_id_free_dylibloader_wrapper_asound
+#define snd_timer_id_copy snd_timer_id_copy_dylibloader_wrapper_asound
+#define snd_timer_id_set_class snd_timer_id_set_class_dylibloader_wrapper_asound
+#define snd_timer_id_get_class snd_timer_id_get_class_dylibloader_wrapper_asound
+#define snd_timer_id_set_sclass snd_timer_id_set_sclass_dylibloader_wrapper_asound
+#define snd_timer_id_get_sclass snd_timer_id_get_sclass_dylibloader_wrapper_asound
+#define snd_timer_id_set_card snd_timer_id_set_card_dylibloader_wrapper_asound
+#define snd_timer_id_get_card snd_timer_id_get_card_dylibloader_wrapper_asound
+#define snd_timer_id_set_device snd_timer_id_set_device_dylibloader_wrapper_asound
+#define snd_timer_id_get_device snd_timer_id_get_device_dylibloader_wrapper_asound
+#define snd_timer_id_set_subdevice snd_timer_id_set_subdevice_dylibloader_wrapper_asound
+#define snd_timer_id_get_subdevice snd_timer_id_get_subdevice_dylibloader_wrapper_asound
+#define snd_timer_ginfo_sizeof snd_timer_ginfo_sizeof_dylibloader_wrapper_asound
+#define snd_timer_ginfo_malloc snd_timer_ginfo_malloc_dylibloader_wrapper_asound
+#define snd_timer_ginfo_free snd_timer_ginfo_free_dylibloader_wrapper_asound
+#define snd_timer_ginfo_copy snd_timer_ginfo_copy_dylibloader_wrapper_asound
+#define snd_timer_ginfo_set_tid snd_timer_ginfo_set_tid_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_tid snd_timer_ginfo_get_tid_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_flags snd_timer_ginfo_get_flags_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_card snd_timer_ginfo_get_card_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_id snd_timer_ginfo_get_id_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_name snd_timer_ginfo_get_name_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_resolution snd_timer_ginfo_get_resolution_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_resolution_min snd_timer_ginfo_get_resolution_min_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_resolution_max snd_timer_ginfo_get_resolution_max_dylibloader_wrapper_asound
+#define snd_timer_ginfo_get_clients snd_timer_ginfo_get_clients_dylibloader_wrapper_asound
+#define snd_timer_info_sizeof snd_timer_info_sizeof_dylibloader_wrapper_asound
+#define snd_timer_info_malloc snd_timer_info_malloc_dylibloader_wrapper_asound
+#define snd_timer_info_free snd_timer_info_free_dylibloader_wrapper_asound
+#define snd_timer_info_copy snd_timer_info_copy_dylibloader_wrapper_asound
+#define snd_timer_info_is_slave snd_timer_info_is_slave_dylibloader_wrapper_asound
+#define snd_timer_info_get_card snd_timer_info_get_card_dylibloader_wrapper_asound
+#define snd_timer_info_get_id snd_timer_info_get_id_dylibloader_wrapper_asound
+#define snd_timer_info_get_name snd_timer_info_get_name_dylibloader_wrapper_asound
+#define snd_timer_info_get_resolution snd_timer_info_get_resolution_dylibloader_wrapper_asound
+#define snd_timer_params_sizeof snd_timer_params_sizeof_dylibloader_wrapper_asound
+#define snd_timer_params_malloc snd_timer_params_malloc_dylibloader_wrapper_asound
+#define snd_timer_params_free snd_timer_params_free_dylibloader_wrapper_asound
+#define snd_timer_params_copy snd_timer_params_copy_dylibloader_wrapper_asound
+#define snd_timer_params_set_auto_start snd_timer_params_set_auto_start_dylibloader_wrapper_asound
+#define snd_timer_params_get_auto_start snd_timer_params_get_auto_start_dylibloader_wrapper_asound
+#define snd_timer_params_set_exclusive snd_timer_params_set_exclusive_dylibloader_wrapper_asound
+#define snd_timer_params_get_exclusive snd_timer_params_get_exclusive_dylibloader_wrapper_asound
+#define snd_timer_params_set_early_event snd_timer_params_set_early_event_dylibloader_wrapper_asound
+#define snd_timer_params_get_early_event snd_timer_params_get_early_event_dylibloader_wrapper_asound
+#define snd_timer_params_set_ticks snd_timer_params_set_ticks_dylibloader_wrapper_asound
+#define snd_timer_params_get_ticks snd_timer_params_get_ticks_dylibloader_wrapper_asound
+#define snd_timer_params_set_queue_size snd_timer_params_set_queue_size_dylibloader_wrapper_asound
+#define snd_timer_params_get_queue_size snd_timer_params_get_queue_size_dylibloader_wrapper_asound
+#define snd_timer_params_set_filter snd_timer_params_set_filter_dylibloader_wrapper_asound
+#define snd_timer_params_get_filter snd_timer_params_get_filter_dylibloader_wrapper_asound
+#define snd_timer_status_sizeof snd_timer_status_sizeof_dylibloader_wrapper_asound
+#define snd_timer_status_malloc snd_timer_status_malloc_dylibloader_wrapper_asound
+#define snd_timer_status_free snd_timer_status_free_dylibloader_wrapper_asound
+#define snd_timer_status_copy snd_timer_status_copy_dylibloader_wrapper_asound
+#define snd_timer_status_get_timestamp snd_timer_status_get_timestamp_dylibloader_wrapper_asound
+#define snd_timer_status_get_resolution snd_timer_status_get_resolution_dylibloader_wrapper_asound
+#define snd_timer_status_get_lost snd_timer_status_get_lost_dylibloader_wrapper_asound
+#define snd_timer_status_get_overrun snd_timer_status_get_overrun_dylibloader_wrapper_asound
+#define snd_timer_status_get_queue snd_timer_status_get_queue_dylibloader_wrapper_asound
+#define snd_timer_info_get_ticks snd_timer_info_get_ticks_dylibloader_wrapper_asound
+#define snd_hwdep_open snd_hwdep_open_dylibloader_wrapper_asound
+#define snd_hwdep_close snd_hwdep_close_dylibloader_wrapper_asound
+#define snd_hwdep_poll_descriptors snd_hwdep_poll_descriptors_dylibloader_wrapper_asound
+#define snd_hwdep_poll_descriptors_count snd_hwdep_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_hwdep_poll_descriptors_revents snd_hwdep_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_hwdep_nonblock snd_hwdep_nonblock_dylibloader_wrapper_asound
+#define snd_hwdep_info snd_hwdep_info_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status snd_hwdep_dsp_status_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_load snd_hwdep_dsp_load_dylibloader_wrapper_asound
+#define snd_hwdep_ioctl snd_hwdep_ioctl_dylibloader_wrapper_asound
+#define snd_hwdep_write snd_hwdep_write_dylibloader_wrapper_asound
+#define snd_hwdep_read snd_hwdep_read_dylibloader_wrapper_asound
+#define snd_hwdep_info_sizeof snd_hwdep_info_sizeof_dylibloader_wrapper_asound
+#define snd_hwdep_info_malloc snd_hwdep_info_malloc_dylibloader_wrapper_asound
+#define snd_hwdep_info_free snd_hwdep_info_free_dylibloader_wrapper_asound
+#define snd_hwdep_info_copy snd_hwdep_info_copy_dylibloader_wrapper_asound
+#define snd_hwdep_info_get_device snd_hwdep_info_get_device_dylibloader_wrapper_asound
+#define snd_hwdep_info_get_card snd_hwdep_info_get_card_dylibloader_wrapper_asound
+#define snd_hwdep_info_get_id snd_hwdep_info_get_id_dylibloader_wrapper_asound
+#define snd_hwdep_info_get_name snd_hwdep_info_get_name_dylibloader_wrapper_asound
+#define snd_hwdep_info_get_iface snd_hwdep_info_get_iface_dylibloader_wrapper_asound
+#define snd_hwdep_info_set_device snd_hwdep_info_set_device_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_sizeof snd_hwdep_dsp_status_sizeof_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_malloc snd_hwdep_dsp_status_malloc_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_free snd_hwdep_dsp_status_free_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_copy snd_hwdep_dsp_status_copy_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_get_version snd_hwdep_dsp_status_get_version_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_get_id snd_hwdep_dsp_status_get_id_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_get_num_dsps snd_hwdep_dsp_status_get_num_dsps_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_get_dsp_loaded snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_status_get_chip_ready snd_hwdep_dsp_status_get_chip_ready_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_sizeof snd_hwdep_dsp_image_sizeof_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_malloc snd_hwdep_dsp_image_malloc_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_free snd_hwdep_dsp_image_free_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_copy snd_hwdep_dsp_image_copy_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_get_index snd_hwdep_dsp_image_get_index_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_get_name snd_hwdep_dsp_image_get_name_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_get_image snd_hwdep_dsp_image_get_image_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_get_length snd_hwdep_dsp_image_get_length_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_set_index snd_hwdep_dsp_image_set_index_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_set_name snd_hwdep_dsp_image_set_name_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_set_image snd_hwdep_dsp_image_set_image_dylibloader_wrapper_asound
+#define snd_hwdep_dsp_image_set_length snd_hwdep_dsp_image_set_length_dylibloader_wrapper_asound
+#define snd_card_load snd_card_load_dylibloader_wrapper_asound
+#define snd_card_next snd_card_next_dylibloader_wrapper_asound
+#define snd_card_get_index snd_card_get_index_dylibloader_wrapper_asound
+#define snd_card_get_name snd_card_get_name_dylibloader_wrapper_asound
+#define snd_card_get_longname snd_card_get_longname_dylibloader_wrapper_asound
+#define snd_device_name_hint snd_device_name_hint_dylibloader_wrapper_asound
+#define snd_device_name_free_hint snd_device_name_free_hint_dylibloader_wrapper_asound
+#define snd_device_name_get_hint snd_device_name_get_hint_dylibloader_wrapper_asound
+#define snd_ctl_open snd_ctl_open_dylibloader_wrapper_asound
+#define snd_ctl_open_lconf snd_ctl_open_lconf_dylibloader_wrapper_asound
+#define snd_ctl_open_fallback snd_ctl_open_fallback_dylibloader_wrapper_asound
+#define snd_ctl_close snd_ctl_close_dylibloader_wrapper_asound
+#define snd_ctl_nonblock snd_ctl_nonblock_dylibloader_wrapper_asound
+#define snd_async_add_ctl_handler snd_async_add_ctl_handler_dylibloader_wrapper_asound
+#define snd_async_handler_get_ctl snd_async_handler_get_ctl_dylibloader_wrapper_asound
+#define snd_ctl_poll_descriptors_count snd_ctl_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_ctl_poll_descriptors snd_ctl_poll_descriptors_dylibloader_wrapper_asound
+#define snd_ctl_poll_descriptors_revents snd_ctl_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_ctl_subscribe_events snd_ctl_subscribe_events_dylibloader_wrapper_asound
+#define snd_ctl_card_info snd_ctl_card_info_dylibloader_wrapper_asound
+#define snd_ctl_elem_list snd_ctl_elem_list_dylibloader_wrapper_asound
+#define snd_ctl_elem_info snd_ctl_elem_info_dylibloader_wrapper_asound
+#define snd_ctl_elem_read snd_ctl_elem_read_dylibloader_wrapper_asound
+#define snd_ctl_elem_write snd_ctl_elem_write_dylibloader_wrapper_asound
+#define snd_ctl_elem_lock snd_ctl_elem_lock_dylibloader_wrapper_asound
+#define snd_ctl_elem_unlock snd_ctl_elem_unlock_dylibloader_wrapper_asound
+#define snd_ctl_elem_tlv_read snd_ctl_elem_tlv_read_dylibloader_wrapper_asound
+#define snd_ctl_elem_tlv_write snd_ctl_elem_tlv_write_dylibloader_wrapper_asound
+#define snd_ctl_elem_tlv_command snd_ctl_elem_tlv_command_dylibloader_wrapper_asound
+#define snd_ctl_hwdep_next_device snd_ctl_hwdep_next_device_dylibloader_wrapper_asound
+#define snd_ctl_hwdep_info snd_ctl_hwdep_info_dylibloader_wrapper_asound
+#define snd_ctl_pcm_next_device snd_ctl_pcm_next_device_dylibloader_wrapper_asound
+#define snd_ctl_pcm_info snd_ctl_pcm_info_dylibloader_wrapper_asound
+#define snd_ctl_pcm_prefer_subdevice snd_ctl_pcm_prefer_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_rawmidi_next_device snd_ctl_rawmidi_next_device_dylibloader_wrapper_asound
+#define snd_ctl_rawmidi_info snd_ctl_rawmidi_info_dylibloader_wrapper_asound
+#define snd_ctl_rawmidi_prefer_subdevice snd_ctl_rawmidi_prefer_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_set_power_state snd_ctl_set_power_state_dylibloader_wrapper_asound
+#define snd_ctl_get_power_state snd_ctl_get_power_state_dylibloader_wrapper_asound
+#define snd_ctl_read snd_ctl_read_dylibloader_wrapper_asound
+#define snd_ctl_wait snd_ctl_wait_dylibloader_wrapper_asound
+#define snd_ctl_name snd_ctl_name_dylibloader_wrapper_asound
+#define snd_ctl_type snd_ctl_type_dylibloader_wrapper_asound
+#define snd_ctl_elem_type_name snd_ctl_elem_type_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_iface_name snd_ctl_elem_iface_name_dylibloader_wrapper_asound
+#define snd_ctl_event_type_name snd_ctl_event_type_name_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_mask snd_ctl_event_elem_get_mask_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_numid snd_ctl_event_elem_get_numid_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_id snd_ctl_event_elem_get_id_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_interface snd_ctl_event_elem_get_interface_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_device snd_ctl_event_elem_get_device_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_subdevice snd_ctl_event_elem_get_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_name snd_ctl_event_elem_get_name_dylibloader_wrapper_asound
+#define snd_ctl_event_elem_get_index snd_ctl_event_elem_get_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_alloc_space snd_ctl_elem_list_alloc_space_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_free_space snd_ctl_elem_list_free_space_dylibloader_wrapper_asound
+#define snd_ctl_ascii_elem_id_get snd_ctl_ascii_elem_id_get_dylibloader_wrapper_asound
+#define snd_ctl_ascii_elem_id_parse snd_ctl_ascii_elem_id_parse_dylibloader_wrapper_asound
+#define snd_ctl_ascii_value_parse snd_ctl_ascii_value_parse_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_sizeof snd_ctl_elem_id_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_malloc snd_ctl_elem_id_malloc_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_free snd_ctl_elem_id_free_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_clear snd_ctl_elem_id_clear_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_copy snd_ctl_elem_id_copy_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_numid snd_ctl_elem_id_get_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_interface snd_ctl_elem_id_get_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_device snd_ctl_elem_id_get_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_subdevice snd_ctl_elem_id_get_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_name snd_ctl_elem_id_get_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_get_index snd_ctl_elem_id_get_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_numid snd_ctl_elem_id_set_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_interface snd_ctl_elem_id_set_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_device snd_ctl_elem_id_set_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_subdevice snd_ctl_elem_id_set_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_name snd_ctl_elem_id_set_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_id_set_index snd_ctl_elem_id_set_index_dylibloader_wrapper_asound
+#define snd_ctl_card_info_sizeof snd_ctl_card_info_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_card_info_malloc snd_ctl_card_info_malloc_dylibloader_wrapper_asound
+#define snd_ctl_card_info_free snd_ctl_card_info_free_dylibloader_wrapper_asound
+#define snd_ctl_card_info_clear snd_ctl_card_info_clear_dylibloader_wrapper_asound
+#define snd_ctl_card_info_copy snd_ctl_card_info_copy_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_card snd_ctl_card_info_get_card_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_id snd_ctl_card_info_get_id_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_driver snd_ctl_card_info_get_driver_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_name snd_ctl_card_info_get_name_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_longname snd_ctl_card_info_get_longname_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_mixername snd_ctl_card_info_get_mixername_dylibloader_wrapper_asound
+#define snd_ctl_card_info_get_components snd_ctl_card_info_get_components_dylibloader_wrapper_asound
+#define snd_ctl_event_sizeof snd_ctl_event_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_event_malloc snd_ctl_event_malloc_dylibloader_wrapper_asound
+#define snd_ctl_event_free snd_ctl_event_free_dylibloader_wrapper_asound
+#define snd_ctl_event_clear snd_ctl_event_clear_dylibloader_wrapper_asound
+#define snd_ctl_event_copy snd_ctl_event_copy_dylibloader_wrapper_asound
+#define snd_ctl_event_get_type snd_ctl_event_get_type_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_sizeof snd_ctl_elem_list_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_malloc snd_ctl_elem_list_malloc_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_free snd_ctl_elem_list_free_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_clear snd_ctl_elem_list_clear_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_copy snd_ctl_elem_list_copy_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_set_offset snd_ctl_elem_list_set_offset_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_used snd_ctl_elem_list_get_used_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_count snd_ctl_elem_list_get_count_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_id snd_ctl_elem_list_get_id_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_numid snd_ctl_elem_list_get_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_interface snd_ctl_elem_list_get_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_device snd_ctl_elem_list_get_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_subdevice snd_ctl_elem_list_get_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_name snd_ctl_elem_list_get_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_list_get_index snd_ctl_elem_list_get_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_sizeof snd_ctl_elem_info_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_malloc snd_ctl_elem_info_malloc_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_free snd_ctl_elem_info_free_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_clear snd_ctl_elem_info_clear_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_copy snd_ctl_elem_info_copy_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_type snd_ctl_elem_info_get_type_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_readable snd_ctl_elem_info_is_readable_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_writable snd_ctl_elem_info_is_writable_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_volatile snd_ctl_elem_info_is_volatile_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_inactive snd_ctl_elem_info_is_inactive_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_locked snd_ctl_elem_info_is_locked_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_tlv_readable snd_ctl_elem_info_is_tlv_readable_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_tlv_writable snd_ctl_elem_info_is_tlv_writable_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_tlv_commandable snd_ctl_elem_info_is_tlv_commandable_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_owner snd_ctl_elem_info_is_owner_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_is_user snd_ctl_elem_info_is_user_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_owner snd_ctl_elem_info_get_owner_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_count snd_ctl_elem_info_get_count_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_min snd_ctl_elem_info_get_min_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_max snd_ctl_elem_info_get_max_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_step snd_ctl_elem_info_get_step_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_min64 snd_ctl_elem_info_get_min64_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_max64 snd_ctl_elem_info_get_max64_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_step64 snd_ctl_elem_info_get_step64_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_items snd_ctl_elem_info_get_items_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_item snd_ctl_elem_info_set_item_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_item_name snd_ctl_elem_info_get_item_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_dimensions snd_ctl_elem_info_get_dimensions_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_dimension snd_ctl_elem_info_get_dimension_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_dimension snd_ctl_elem_info_set_dimension_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_id snd_ctl_elem_info_get_id_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_numid snd_ctl_elem_info_get_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_interface snd_ctl_elem_info_get_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_device snd_ctl_elem_info_get_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_subdevice snd_ctl_elem_info_get_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_name snd_ctl_elem_info_get_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_get_index snd_ctl_elem_info_get_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_id snd_ctl_elem_info_set_id_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_numid snd_ctl_elem_info_set_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_interface snd_ctl_elem_info_set_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_device snd_ctl_elem_info_set_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_subdevice snd_ctl_elem_info_set_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_name snd_ctl_elem_info_set_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_info_set_index snd_ctl_elem_info_set_index_dylibloader_wrapper_asound
+#define snd_ctl_add_integer_elem_set snd_ctl_add_integer_elem_set_dylibloader_wrapper_asound
+#define snd_ctl_add_integer64_elem_set snd_ctl_add_integer64_elem_set_dylibloader_wrapper_asound
+#define snd_ctl_add_boolean_elem_set snd_ctl_add_boolean_elem_set_dylibloader_wrapper_asound
+#define snd_ctl_add_enumerated_elem_set snd_ctl_add_enumerated_elem_set_dylibloader_wrapper_asound
+#define snd_ctl_add_bytes_elem_set snd_ctl_add_bytes_elem_set_dylibloader_wrapper_asound
+#define snd_ctl_elem_add_integer snd_ctl_elem_add_integer_dylibloader_wrapper_asound
+#define snd_ctl_elem_add_integer64 snd_ctl_elem_add_integer64_dylibloader_wrapper_asound
+#define snd_ctl_elem_add_boolean snd_ctl_elem_add_boolean_dylibloader_wrapper_asound
+#define snd_ctl_elem_add_enumerated snd_ctl_elem_add_enumerated_dylibloader_wrapper_asound
+#define snd_ctl_elem_add_iec958 snd_ctl_elem_add_iec958_dylibloader_wrapper_asound
+#define snd_ctl_elem_remove snd_ctl_elem_remove_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_sizeof snd_ctl_elem_value_sizeof_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_malloc snd_ctl_elem_value_malloc_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_free snd_ctl_elem_value_free_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_clear snd_ctl_elem_value_clear_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_copy snd_ctl_elem_value_copy_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_compare snd_ctl_elem_value_compare_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_id snd_ctl_elem_value_get_id_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_numid snd_ctl_elem_value_get_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_interface snd_ctl_elem_value_get_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_device snd_ctl_elem_value_get_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_subdevice snd_ctl_elem_value_get_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_name snd_ctl_elem_value_get_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_index snd_ctl_elem_value_get_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_id snd_ctl_elem_value_set_id_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_numid snd_ctl_elem_value_set_numid_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_interface snd_ctl_elem_value_set_interface_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_device snd_ctl_elem_value_set_device_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_subdevice snd_ctl_elem_value_set_subdevice_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_name snd_ctl_elem_value_set_name_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_index snd_ctl_elem_value_set_index_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_boolean snd_ctl_elem_value_get_boolean_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_integer snd_ctl_elem_value_get_integer_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_integer64 snd_ctl_elem_value_get_integer64_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_enumerated snd_ctl_elem_value_get_enumerated_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_byte snd_ctl_elem_value_get_byte_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_boolean snd_ctl_elem_value_set_boolean_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_integer snd_ctl_elem_value_set_integer_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_integer64 snd_ctl_elem_value_set_integer64_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_enumerated snd_ctl_elem_value_set_enumerated_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_byte snd_ctl_elem_value_set_byte_dylibloader_wrapper_asound
+#define snd_ctl_elem_set_bytes snd_ctl_elem_set_bytes_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_bytes snd_ctl_elem_value_get_bytes_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_get_iec958 snd_ctl_elem_value_get_iec958_dylibloader_wrapper_asound
+#define snd_ctl_elem_value_set_iec958 snd_ctl_elem_value_set_iec958_dylibloader_wrapper_asound
+#define snd_tlv_parse_dB_info snd_tlv_parse_dB_info_dylibloader_wrapper_asound
+#define snd_tlv_get_dB_range snd_tlv_get_dB_range_dylibloader_wrapper_asound
+#define snd_tlv_convert_to_dB snd_tlv_convert_to_dB_dylibloader_wrapper_asound
+#define snd_tlv_convert_from_dB snd_tlv_convert_from_dB_dylibloader_wrapper_asound
+#define snd_ctl_get_dB_range snd_ctl_get_dB_range_dylibloader_wrapper_asound
+#define snd_ctl_convert_to_dB snd_ctl_convert_to_dB_dylibloader_wrapper_asound
+#define snd_ctl_convert_from_dB snd_ctl_convert_from_dB_dylibloader_wrapper_asound
+#define snd_hctl_compare_fast snd_hctl_compare_fast_dylibloader_wrapper_asound
+#define snd_hctl_open snd_hctl_open_dylibloader_wrapper_asound
+#define snd_hctl_open_ctl snd_hctl_open_ctl_dylibloader_wrapper_asound
+#define snd_hctl_close snd_hctl_close_dylibloader_wrapper_asound
+#define snd_hctl_nonblock snd_hctl_nonblock_dylibloader_wrapper_asound
+#define snd_hctl_poll_descriptors_count snd_hctl_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_hctl_poll_descriptors snd_hctl_poll_descriptors_dylibloader_wrapper_asound
+#define snd_hctl_poll_descriptors_revents snd_hctl_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_hctl_get_count snd_hctl_get_count_dylibloader_wrapper_asound
+#define snd_hctl_set_compare snd_hctl_set_compare_dylibloader_wrapper_asound
+#define snd_hctl_first_elem snd_hctl_first_elem_dylibloader_wrapper_asound
+#define snd_hctl_last_elem snd_hctl_last_elem_dylibloader_wrapper_asound
+#define snd_hctl_find_elem snd_hctl_find_elem_dylibloader_wrapper_asound
+#define snd_hctl_set_callback snd_hctl_set_callback_dylibloader_wrapper_asound
+#define snd_hctl_set_callback_private snd_hctl_set_callback_private_dylibloader_wrapper_asound
+#define snd_hctl_get_callback_private snd_hctl_get_callback_private_dylibloader_wrapper_asound
+#define snd_hctl_load snd_hctl_load_dylibloader_wrapper_asound
+#define snd_hctl_free snd_hctl_free_dylibloader_wrapper_asound
+#define snd_hctl_handle_events snd_hctl_handle_events_dylibloader_wrapper_asound
+#define snd_hctl_name snd_hctl_name_dylibloader_wrapper_asound
+#define snd_hctl_wait snd_hctl_wait_dylibloader_wrapper_asound
+#define snd_hctl_ctl snd_hctl_ctl_dylibloader_wrapper_asound
+#define snd_hctl_elem_next snd_hctl_elem_next_dylibloader_wrapper_asound
+#define snd_hctl_elem_prev snd_hctl_elem_prev_dylibloader_wrapper_asound
+#define snd_hctl_elem_info snd_hctl_elem_info_dylibloader_wrapper_asound
+#define snd_hctl_elem_read snd_hctl_elem_read_dylibloader_wrapper_asound
+#define snd_hctl_elem_write snd_hctl_elem_write_dylibloader_wrapper_asound
+#define snd_hctl_elem_tlv_read snd_hctl_elem_tlv_read_dylibloader_wrapper_asound
+#define snd_hctl_elem_tlv_write snd_hctl_elem_tlv_write_dylibloader_wrapper_asound
+#define snd_hctl_elem_tlv_command snd_hctl_elem_tlv_command_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_hctl snd_hctl_elem_get_hctl_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_id snd_hctl_elem_get_id_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_numid snd_hctl_elem_get_numid_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_interface snd_hctl_elem_get_interface_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_device snd_hctl_elem_get_device_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_subdevice snd_hctl_elem_get_subdevice_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_name snd_hctl_elem_get_name_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_index snd_hctl_elem_get_index_dylibloader_wrapper_asound
+#define snd_hctl_elem_set_callback snd_hctl_elem_set_callback_dylibloader_wrapper_asound
+#define snd_hctl_elem_get_callback_private snd_hctl_elem_get_callback_private_dylibloader_wrapper_asound
+#define snd_hctl_elem_set_callback_private snd_hctl_elem_set_callback_private_dylibloader_wrapper_asound
+#define snd_sctl_build snd_sctl_build_dylibloader_wrapper_asound
+#define snd_sctl_free snd_sctl_free_dylibloader_wrapper_asound
+#define snd_sctl_install snd_sctl_install_dylibloader_wrapper_asound
+#define snd_sctl_remove snd_sctl_remove_dylibloader_wrapper_asound
+#define snd_mixer_open snd_mixer_open_dylibloader_wrapper_asound
+#define snd_mixer_close snd_mixer_close_dylibloader_wrapper_asound
+#define snd_mixer_first_elem snd_mixer_first_elem_dylibloader_wrapper_asound
+#define snd_mixer_last_elem snd_mixer_last_elem_dylibloader_wrapper_asound
+#define snd_mixer_handle_events snd_mixer_handle_events_dylibloader_wrapper_asound
+#define snd_mixer_attach snd_mixer_attach_dylibloader_wrapper_asound
+#define snd_mixer_attach_hctl snd_mixer_attach_hctl_dylibloader_wrapper_asound
+#define snd_mixer_detach snd_mixer_detach_dylibloader_wrapper_asound
+#define snd_mixer_detach_hctl snd_mixer_detach_hctl_dylibloader_wrapper_asound
+#define snd_mixer_get_hctl snd_mixer_get_hctl_dylibloader_wrapper_asound
+#define snd_mixer_poll_descriptors_count snd_mixer_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_mixer_poll_descriptors snd_mixer_poll_descriptors_dylibloader_wrapper_asound
+#define snd_mixer_poll_descriptors_revents snd_mixer_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_mixer_load snd_mixer_load_dylibloader_wrapper_asound
+#define snd_mixer_free snd_mixer_free_dylibloader_wrapper_asound
+#define snd_mixer_wait snd_mixer_wait_dylibloader_wrapper_asound
+#define snd_mixer_set_compare snd_mixer_set_compare_dylibloader_wrapper_asound
+#define snd_mixer_set_callback snd_mixer_set_callback_dylibloader_wrapper_asound
+#define snd_mixer_get_callback_private snd_mixer_get_callback_private_dylibloader_wrapper_asound
+#define snd_mixer_set_callback_private snd_mixer_set_callback_private_dylibloader_wrapper_asound
+#define snd_mixer_get_count snd_mixer_get_count_dylibloader_wrapper_asound
+#define snd_mixer_class_unregister snd_mixer_class_unregister_dylibloader_wrapper_asound
+#define snd_mixer_elem_next snd_mixer_elem_next_dylibloader_wrapper_asound
+#define snd_mixer_elem_prev snd_mixer_elem_prev_dylibloader_wrapper_asound
+#define snd_mixer_elem_set_callback snd_mixer_elem_set_callback_dylibloader_wrapper_asound
+#define snd_mixer_elem_get_callback_private snd_mixer_elem_get_callback_private_dylibloader_wrapper_asound
+#define snd_mixer_elem_set_callback_private snd_mixer_elem_set_callback_private_dylibloader_wrapper_asound
+#define snd_mixer_elem_get_type snd_mixer_elem_get_type_dylibloader_wrapper_asound
+#define snd_mixer_class_register snd_mixer_class_register_dylibloader_wrapper_asound
+#define snd_mixer_elem_new snd_mixer_elem_new_dylibloader_wrapper_asound
+#define snd_mixer_elem_add snd_mixer_elem_add_dylibloader_wrapper_asound
+#define snd_mixer_elem_remove snd_mixer_elem_remove_dylibloader_wrapper_asound
+#define snd_mixer_elem_free snd_mixer_elem_free_dylibloader_wrapper_asound
+#define snd_mixer_elem_info snd_mixer_elem_info_dylibloader_wrapper_asound
+#define snd_mixer_elem_value snd_mixer_elem_value_dylibloader_wrapper_asound
+#define snd_mixer_elem_attach snd_mixer_elem_attach_dylibloader_wrapper_asound
+#define snd_mixer_elem_detach snd_mixer_elem_detach_dylibloader_wrapper_asound
+#define snd_mixer_elem_empty snd_mixer_elem_empty_dylibloader_wrapper_asound
+#define snd_mixer_elem_get_private snd_mixer_elem_get_private_dylibloader_wrapper_asound
+#define snd_mixer_class_sizeof snd_mixer_class_sizeof_dylibloader_wrapper_asound
+#define snd_mixer_class_malloc snd_mixer_class_malloc_dylibloader_wrapper_asound
+#define snd_mixer_class_free snd_mixer_class_free_dylibloader_wrapper_asound
+#define snd_mixer_class_copy snd_mixer_class_copy_dylibloader_wrapper_asound
+#define snd_mixer_class_get_mixer snd_mixer_class_get_mixer_dylibloader_wrapper_asound
+#define snd_mixer_class_get_event snd_mixer_class_get_event_dylibloader_wrapper_asound
+#define snd_mixer_class_get_private snd_mixer_class_get_private_dylibloader_wrapper_asound
+#define snd_mixer_class_get_compare snd_mixer_class_get_compare_dylibloader_wrapper_asound
+#define snd_mixer_class_set_event snd_mixer_class_set_event_dylibloader_wrapper_asound
+#define snd_mixer_class_set_private snd_mixer_class_set_private_dylibloader_wrapper_asound
+#define snd_mixer_class_set_private_free snd_mixer_class_set_private_free_dylibloader_wrapper_asound
+#define snd_mixer_class_set_compare snd_mixer_class_set_compare_dylibloader_wrapper_asound
+#define snd_mixer_selem_channel_name snd_mixer_selem_channel_name_dylibloader_wrapper_asound
+#define snd_mixer_selem_register snd_mixer_selem_register_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_id snd_mixer_selem_get_id_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_name snd_mixer_selem_get_name_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_index snd_mixer_selem_get_index_dylibloader_wrapper_asound
+#define snd_mixer_find_selem snd_mixer_find_selem_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_active snd_mixer_selem_is_active_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_playback_mono snd_mixer_selem_is_playback_mono_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_playback_channel snd_mixer_selem_has_playback_channel_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_capture_mono snd_mixer_selem_is_capture_mono_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_channel snd_mixer_selem_has_capture_channel_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_group snd_mixer_selem_get_capture_group_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_common_volume snd_mixer_selem_has_common_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_playback_volume snd_mixer_selem_has_playback_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_playback_volume_joined snd_mixer_selem_has_playback_volume_joined_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_volume snd_mixer_selem_has_capture_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_volume_joined snd_mixer_selem_has_capture_volume_joined_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_common_switch snd_mixer_selem_has_common_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_playback_switch snd_mixer_selem_has_playback_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_playback_switch_joined snd_mixer_selem_has_playback_switch_joined_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_switch snd_mixer_selem_has_capture_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_switch_joined snd_mixer_selem_has_capture_switch_joined_dylibloader_wrapper_asound
+#define snd_mixer_selem_has_capture_switch_exclusive snd_mixer_selem_has_capture_switch_exclusive_dylibloader_wrapper_asound
+#define snd_mixer_selem_ask_playback_vol_dB snd_mixer_selem_ask_playback_vol_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_ask_capture_vol_dB snd_mixer_selem_ask_capture_vol_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_ask_playback_dB_vol snd_mixer_selem_ask_playback_dB_vol_dylibloader_wrapper_asound
+#define snd_mixer_selem_ask_capture_dB_vol snd_mixer_selem_ask_capture_dB_vol_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_playback_volume snd_mixer_selem_get_playback_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_volume snd_mixer_selem_get_capture_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_playback_dB snd_mixer_selem_get_playback_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_dB snd_mixer_selem_get_capture_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_playback_switch snd_mixer_selem_get_playback_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_switch snd_mixer_selem_get_capture_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_volume snd_mixer_selem_set_playback_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_volume snd_mixer_selem_set_capture_volume_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_dB snd_mixer_selem_set_playback_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_dB snd_mixer_selem_set_capture_dB_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_volume_all snd_mixer_selem_set_playback_volume_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_volume_all snd_mixer_selem_set_capture_volume_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_dB_all snd_mixer_selem_set_playback_dB_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_dB_all snd_mixer_selem_set_capture_dB_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_switch snd_mixer_selem_set_playback_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_switch snd_mixer_selem_set_capture_switch_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_switch_all snd_mixer_selem_set_playback_switch_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_switch_all snd_mixer_selem_set_capture_switch_all_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_playback_volume_range snd_mixer_selem_get_playback_volume_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_playback_dB_range snd_mixer_selem_get_playback_dB_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_playback_volume_range snd_mixer_selem_set_playback_volume_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_volume_range snd_mixer_selem_get_capture_volume_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_capture_dB_range snd_mixer_selem_get_capture_dB_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_capture_volume_range snd_mixer_selem_set_capture_volume_range_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_enumerated snd_mixer_selem_is_enumerated_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_enum_playback snd_mixer_selem_is_enum_playback_dylibloader_wrapper_asound
+#define snd_mixer_selem_is_enum_capture snd_mixer_selem_is_enum_capture_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_enum_items snd_mixer_selem_get_enum_items_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_enum_item_name snd_mixer_selem_get_enum_item_name_dylibloader_wrapper_asound
+#define snd_mixer_selem_get_enum_item snd_mixer_selem_get_enum_item_dylibloader_wrapper_asound
+#define snd_mixer_selem_set_enum_item snd_mixer_selem_set_enum_item_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_sizeof snd_mixer_selem_id_sizeof_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_malloc snd_mixer_selem_id_malloc_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_free snd_mixer_selem_id_free_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_copy snd_mixer_selem_id_copy_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_get_name snd_mixer_selem_id_get_name_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_get_index snd_mixer_selem_id_get_index_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_set_name snd_mixer_selem_id_set_name_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_set_index snd_mixer_selem_id_set_index_dylibloader_wrapper_asound
+#define snd_mixer_selem_id_parse snd_mixer_selem_id_parse_dylibloader_wrapper_asound
+#define snd_seq_open snd_seq_open_dylibloader_wrapper_asound
+#define snd_seq_open_lconf snd_seq_open_lconf_dylibloader_wrapper_asound
+#define snd_seq_name snd_seq_name_dylibloader_wrapper_asound
+#define snd_seq_type snd_seq_type_dylibloader_wrapper_asound
+#define snd_seq_close snd_seq_close_dylibloader_wrapper_asound
+#define snd_seq_poll_descriptors_count snd_seq_poll_descriptors_count_dylibloader_wrapper_asound
+#define snd_seq_poll_descriptors snd_seq_poll_descriptors_dylibloader_wrapper_asound
+#define snd_seq_poll_descriptors_revents snd_seq_poll_descriptors_revents_dylibloader_wrapper_asound
+#define snd_seq_nonblock snd_seq_nonblock_dylibloader_wrapper_asound
+#define snd_seq_client_id snd_seq_client_id_dylibloader_wrapper_asound
+#define snd_seq_get_output_buffer_size snd_seq_get_output_buffer_size_dylibloader_wrapper_asound
+#define snd_seq_get_input_buffer_size snd_seq_get_input_buffer_size_dylibloader_wrapper_asound
+#define snd_seq_set_output_buffer_size snd_seq_set_output_buffer_size_dylibloader_wrapper_asound
+#define snd_seq_set_input_buffer_size snd_seq_set_input_buffer_size_dylibloader_wrapper_asound
+#define snd_seq_system_info_sizeof snd_seq_system_info_sizeof_dylibloader_wrapper_asound
+#define snd_seq_system_info_malloc snd_seq_system_info_malloc_dylibloader_wrapper_asound
+#define snd_seq_system_info_free snd_seq_system_info_free_dylibloader_wrapper_asound
+#define snd_seq_system_info_copy snd_seq_system_info_copy_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_queues snd_seq_system_info_get_queues_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_clients snd_seq_system_info_get_clients_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_ports snd_seq_system_info_get_ports_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_channels snd_seq_system_info_get_channels_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_cur_clients snd_seq_system_info_get_cur_clients_dylibloader_wrapper_asound
+#define snd_seq_system_info_get_cur_queues snd_seq_system_info_get_cur_queues_dylibloader_wrapper_asound
+#define snd_seq_system_info snd_seq_system_info_dylibloader_wrapper_asound
+#define snd_seq_client_info_sizeof snd_seq_client_info_sizeof_dylibloader_wrapper_asound
+#define snd_seq_client_info_malloc snd_seq_client_info_malloc_dylibloader_wrapper_asound
+#define snd_seq_client_info_free snd_seq_client_info_free_dylibloader_wrapper_asound
+#define snd_seq_client_info_copy snd_seq_client_info_copy_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_client snd_seq_client_info_get_client_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_type snd_seq_client_info_get_type_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_name snd_seq_client_info_get_name_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_broadcast_filter snd_seq_client_info_get_broadcast_filter_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_error_bounce snd_seq_client_info_get_error_bounce_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_card snd_seq_client_info_get_card_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_pid snd_seq_client_info_get_pid_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_event_filter snd_seq_client_info_get_event_filter_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_num_ports snd_seq_client_info_get_num_ports_dylibloader_wrapper_asound
+#define snd_seq_client_info_get_event_lost snd_seq_client_info_get_event_lost_dylibloader_wrapper_asound
+#define snd_seq_client_info_set_client snd_seq_client_info_set_client_dylibloader_wrapper_asound
+#define snd_seq_client_info_set_name snd_seq_client_info_set_name_dylibloader_wrapper_asound
+#define snd_seq_client_info_set_broadcast_filter snd_seq_client_info_set_broadcast_filter_dylibloader_wrapper_asound
+#define snd_seq_client_info_set_error_bounce snd_seq_client_info_set_error_bounce_dylibloader_wrapper_asound
+#define snd_seq_client_info_set_event_filter snd_seq_client_info_set_event_filter_dylibloader_wrapper_asound
+#define snd_seq_client_info_event_filter_clear snd_seq_client_info_event_filter_clear_dylibloader_wrapper_asound
+#define snd_seq_client_info_event_filter_add snd_seq_client_info_event_filter_add_dylibloader_wrapper_asound
+#define snd_seq_client_info_event_filter_del snd_seq_client_info_event_filter_del_dylibloader_wrapper_asound
+#define snd_seq_client_info_event_filter_check snd_seq_client_info_event_filter_check_dylibloader_wrapper_asound
+#define snd_seq_get_client_info snd_seq_get_client_info_dylibloader_wrapper_asound
+#define snd_seq_get_any_client_info snd_seq_get_any_client_info_dylibloader_wrapper_asound
+#define snd_seq_set_client_info snd_seq_set_client_info_dylibloader_wrapper_asound
+#define snd_seq_query_next_client snd_seq_query_next_client_dylibloader_wrapper_asound
+#define snd_seq_client_pool_sizeof snd_seq_client_pool_sizeof_dylibloader_wrapper_asound
+#define snd_seq_client_pool_malloc snd_seq_client_pool_malloc_dylibloader_wrapper_asound
+#define snd_seq_client_pool_free snd_seq_client_pool_free_dylibloader_wrapper_asound
+#define snd_seq_client_pool_copy snd_seq_client_pool_copy_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_client snd_seq_client_pool_get_client_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_output_pool snd_seq_client_pool_get_output_pool_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_input_pool snd_seq_client_pool_get_input_pool_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_output_room snd_seq_client_pool_get_output_room_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_output_free snd_seq_client_pool_get_output_free_dylibloader_wrapper_asound
+#define snd_seq_client_pool_get_input_free snd_seq_client_pool_get_input_free_dylibloader_wrapper_asound
+#define snd_seq_client_pool_set_output_pool snd_seq_client_pool_set_output_pool_dylibloader_wrapper_asound
+#define snd_seq_client_pool_set_input_pool snd_seq_client_pool_set_input_pool_dylibloader_wrapper_asound
+#define snd_seq_client_pool_set_output_room snd_seq_client_pool_set_output_room_dylibloader_wrapper_asound
+#define snd_seq_get_client_pool snd_seq_get_client_pool_dylibloader_wrapper_asound
+#define snd_seq_set_client_pool snd_seq_set_client_pool_dylibloader_wrapper_asound
+#define snd_seq_port_info_sizeof snd_seq_port_info_sizeof_dylibloader_wrapper_asound
+#define snd_seq_port_info_malloc snd_seq_port_info_malloc_dylibloader_wrapper_asound
+#define snd_seq_port_info_free snd_seq_port_info_free_dylibloader_wrapper_asound
+#define snd_seq_port_info_copy snd_seq_port_info_copy_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_client snd_seq_port_info_get_client_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_port snd_seq_port_info_get_port_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_addr snd_seq_port_info_get_addr_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_name snd_seq_port_info_get_name_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_capability snd_seq_port_info_get_capability_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_type snd_seq_port_info_get_type_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_midi_channels snd_seq_port_info_get_midi_channels_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_midi_voices snd_seq_port_info_get_midi_voices_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_synth_voices snd_seq_port_info_get_synth_voices_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_read_use snd_seq_port_info_get_read_use_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_write_use snd_seq_port_info_get_write_use_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_port_specified snd_seq_port_info_get_port_specified_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_timestamping snd_seq_port_info_get_timestamping_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_timestamp_real snd_seq_port_info_get_timestamp_real_dylibloader_wrapper_asound
+#define snd_seq_port_info_get_timestamp_queue snd_seq_port_info_get_timestamp_queue_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_client snd_seq_port_info_set_client_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_port snd_seq_port_info_set_port_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_addr snd_seq_port_info_set_addr_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_name snd_seq_port_info_set_name_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_capability snd_seq_port_info_set_capability_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_type snd_seq_port_info_set_type_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_midi_channels snd_seq_port_info_set_midi_channels_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_midi_voices snd_seq_port_info_set_midi_voices_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_synth_voices snd_seq_port_info_set_synth_voices_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_port_specified snd_seq_port_info_set_port_specified_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_timestamping snd_seq_port_info_set_timestamping_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_timestamp_real snd_seq_port_info_set_timestamp_real_dylibloader_wrapper_asound
+#define snd_seq_port_info_set_timestamp_queue snd_seq_port_info_set_timestamp_queue_dylibloader_wrapper_asound
+#define snd_seq_create_port snd_seq_create_port_dylibloader_wrapper_asound
+#define snd_seq_delete_port snd_seq_delete_port_dylibloader_wrapper_asound
+#define snd_seq_get_port_info snd_seq_get_port_info_dylibloader_wrapper_asound
+#define snd_seq_get_any_port_info snd_seq_get_any_port_info_dylibloader_wrapper_asound
+#define snd_seq_set_port_info snd_seq_set_port_info_dylibloader_wrapper_asound
+#define snd_seq_query_next_port snd_seq_query_next_port_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_sizeof snd_seq_port_subscribe_sizeof_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_malloc snd_seq_port_subscribe_malloc_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_free snd_seq_port_subscribe_free_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_copy snd_seq_port_subscribe_copy_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_sender snd_seq_port_subscribe_get_sender_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_dest snd_seq_port_subscribe_get_dest_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_queue snd_seq_port_subscribe_get_queue_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_exclusive snd_seq_port_subscribe_get_exclusive_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_time_update snd_seq_port_subscribe_get_time_update_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_get_time_real snd_seq_port_subscribe_get_time_real_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_sender snd_seq_port_subscribe_set_sender_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_dest snd_seq_port_subscribe_set_dest_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_queue snd_seq_port_subscribe_set_queue_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_exclusive snd_seq_port_subscribe_set_exclusive_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_time_update snd_seq_port_subscribe_set_time_update_dylibloader_wrapper_asound
+#define snd_seq_port_subscribe_set_time_real snd_seq_port_subscribe_set_time_real_dylibloader_wrapper_asound
+#define snd_seq_get_port_subscription snd_seq_get_port_subscription_dylibloader_wrapper_asound
+#define snd_seq_subscribe_port snd_seq_subscribe_port_dylibloader_wrapper_asound
+#define snd_seq_unsubscribe_port snd_seq_unsubscribe_port_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_sizeof snd_seq_query_subscribe_sizeof_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_malloc snd_seq_query_subscribe_malloc_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_free snd_seq_query_subscribe_free_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_copy snd_seq_query_subscribe_copy_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_client snd_seq_query_subscribe_get_client_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_port snd_seq_query_subscribe_get_port_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_root snd_seq_query_subscribe_get_root_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_type snd_seq_query_subscribe_get_type_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_index snd_seq_query_subscribe_get_index_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_num_subs snd_seq_query_subscribe_get_num_subs_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_addr snd_seq_query_subscribe_get_addr_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_queue snd_seq_query_subscribe_get_queue_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_exclusive snd_seq_query_subscribe_get_exclusive_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_time_update snd_seq_query_subscribe_get_time_update_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_get_time_real snd_seq_query_subscribe_get_time_real_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_set_client snd_seq_query_subscribe_set_client_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_set_port snd_seq_query_subscribe_set_port_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_set_root snd_seq_query_subscribe_set_root_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_set_type snd_seq_query_subscribe_set_type_dylibloader_wrapper_asound
+#define snd_seq_query_subscribe_set_index snd_seq_query_subscribe_set_index_dylibloader_wrapper_asound
+#define snd_seq_query_port_subscribers snd_seq_query_port_subscribers_dylibloader_wrapper_asound
+#define snd_seq_queue_info_sizeof snd_seq_queue_info_sizeof_dylibloader_wrapper_asound
+#define snd_seq_queue_info_malloc snd_seq_queue_info_malloc_dylibloader_wrapper_asound
+#define snd_seq_queue_info_free snd_seq_queue_info_free_dylibloader_wrapper_asound
+#define snd_seq_queue_info_copy snd_seq_queue_info_copy_dylibloader_wrapper_asound
+#define snd_seq_queue_info_get_queue snd_seq_queue_info_get_queue_dylibloader_wrapper_asound
+#define snd_seq_queue_info_get_name snd_seq_queue_info_get_name_dylibloader_wrapper_asound
+#define snd_seq_queue_info_get_owner snd_seq_queue_info_get_owner_dylibloader_wrapper_asound
+#define snd_seq_queue_info_get_locked snd_seq_queue_info_get_locked_dylibloader_wrapper_asound
+#define snd_seq_queue_info_get_flags snd_seq_queue_info_get_flags_dylibloader_wrapper_asound
+#define snd_seq_queue_info_set_name snd_seq_queue_info_set_name_dylibloader_wrapper_asound
+#define snd_seq_queue_info_set_owner snd_seq_queue_info_set_owner_dylibloader_wrapper_asound
+#define snd_seq_queue_info_set_locked snd_seq_queue_info_set_locked_dylibloader_wrapper_asound
+#define snd_seq_queue_info_set_flags snd_seq_queue_info_set_flags_dylibloader_wrapper_asound
+#define snd_seq_create_queue snd_seq_create_queue_dylibloader_wrapper_asound
+#define snd_seq_alloc_named_queue snd_seq_alloc_named_queue_dylibloader_wrapper_asound
+#define snd_seq_alloc_queue snd_seq_alloc_queue_dylibloader_wrapper_asound
+#define snd_seq_free_queue snd_seq_free_queue_dylibloader_wrapper_asound
+#define snd_seq_get_queue_info snd_seq_get_queue_info_dylibloader_wrapper_asound
+#define snd_seq_set_queue_info snd_seq_set_queue_info_dylibloader_wrapper_asound
+#define snd_seq_query_named_queue snd_seq_query_named_queue_dylibloader_wrapper_asound
+#define snd_seq_get_queue_usage snd_seq_get_queue_usage_dylibloader_wrapper_asound
+#define snd_seq_set_queue_usage snd_seq_set_queue_usage_dylibloader_wrapper_asound
+#define snd_seq_queue_status_sizeof snd_seq_queue_status_sizeof_dylibloader_wrapper_asound
+#define snd_seq_queue_status_malloc snd_seq_queue_status_malloc_dylibloader_wrapper_asound
+#define snd_seq_queue_status_free snd_seq_queue_status_free_dylibloader_wrapper_asound
+#define snd_seq_queue_status_copy snd_seq_queue_status_copy_dylibloader_wrapper_asound
+#define snd_seq_queue_status_get_queue snd_seq_queue_status_get_queue_dylibloader_wrapper_asound
+#define snd_seq_queue_status_get_events snd_seq_queue_status_get_events_dylibloader_wrapper_asound
+#define snd_seq_queue_status_get_tick_time snd_seq_queue_status_get_tick_time_dylibloader_wrapper_asound
+#define snd_seq_queue_status_get_real_time snd_seq_queue_status_get_real_time_dylibloader_wrapper_asound
+#define snd_seq_queue_status_get_status snd_seq_queue_status_get_status_dylibloader_wrapper_asound
+#define snd_seq_get_queue_status snd_seq_get_queue_status_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_sizeof snd_seq_queue_tempo_sizeof_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_malloc snd_seq_queue_tempo_malloc_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_free snd_seq_queue_tempo_free_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_copy snd_seq_queue_tempo_copy_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_get_queue snd_seq_queue_tempo_get_queue_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_get_tempo snd_seq_queue_tempo_get_tempo_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_get_ppq snd_seq_queue_tempo_get_ppq_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_get_skew snd_seq_queue_tempo_get_skew_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_get_skew_base snd_seq_queue_tempo_get_skew_base_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_set_tempo snd_seq_queue_tempo_set_tempo_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_set_ppq snd_seq_queue_tempo_set_ppq_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_set_skew snd_seq_queue_tempo_set_skew_dylibloader_wrapper_asound
+#define snd_seq_queue_tempo_set_skew_base snd_seq_queue_tempo_set_skew_base_dylibloader_wrapper_asound
+#define snd_seq_get_queue_tempo snd_seq_get_queue_tempo_dylibloader_wrapper_asound
+#define snd_seq_set_queue_tempo snd_seq_set_queue_tempo_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_sizeof snd_seq_queue_timer_sizeof_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_malloc snd_seq_queue_timer_malloc_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_free snd_seq_queue_timer_free_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_copy snd_seq_queue_timer_copy_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_get_queue snd_seq_queue_timer_get_queue_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_get_type snd_seq_queue_timer_get_type_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_get_id snd_seq_queue_timer_get_id_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_get_resolution snd_seq_queue_timer_get_resolution_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_set_type snd_seq_queue_timer_set_type_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_set_id snd_seq_queue_timer_set_id_dylibloader_wrapper_asound
+#define snd_seq_queue_timer_set_resolution snd_seq_queue_timer_set_resolution_dylibloader_wrapper_asound
+#define snd_seq_get_queue_timer snd_seq_get_queue_timer_dylibloader_wrapper_asound
+#define snd_seq_set_queue_timer snd_seq_set_queue_timer_dylibloader_wrapper_asound
+#define snd_seq_free_event snd_seq_free_event_dylibloader_wrapper_asound
+#define snd_seq_event_length snd_seq_event_length_dylibloader_wrapper_asound
+#define snd_seq_event_output snd_seq_event_output_dylibloader_wrapper_asound
+#define snd_seq_event_output_buffer snd_seq_event_output_buffer_dylibloader_wrapper_asound
+#define snd_seq_event_output_direct snd_seq_event_output_direct_dylibloader_wrapper_asound
+#define snd_seq_event_input snd_seq_event_input_dylibloader_wrapper_asound
+#define snd_seq_event_input_pending snd_seq_event_input_pending_dylibloader_wrapper_asound
+#define snd_seq_drain_output snd_seq_drain_output_dylibloader_wrapper_asound
+#define snd_seq_event_output_pending snd_seq_event_output_pending_dylibloader_wrapper_asound
+#define snd_seq_extract_output snd_seq_extract_output_dylibloader_wrapper_asound
+#define snd_seq_drop_output snd_seq_drop_output_dylibloader_wrapper_asound
+#define snd_seq_drop_output_buffer snd_seq_drop_output_buffer_dylibloader_wrapper_asound
+#define snd_seq_drop_input snd_seq_drop_input_dylibloader_wrapper_asound
+#define snd_seq_drop_input_buffer snd_seq_drop_input_buffer_dylibloader_wrapper_asound
+#define snd_seq_remove_events_sizeof snd_seq_remove_events_sizeof_dylibloader_wrapper_asound
+#define snd_seq_remove_events_malloc snd_seq_remove_events_malloc_dylibloader_wrapper_asound
+#define snd_seq_remove_events_free snd_seq_remove_events_free_dylibloader_wrapper_asound
+#define snd_seq_remove_events_copy snd_seq_remove_events_copy_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_condition snd_seq_remove_events_get_condition_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_queue snd_seq_remove_events_get_queue_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_time snd_seq_remove_events_get_time_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_dest snd_seq_remove_events_get_dest_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_channel snd_seq_remove_events_get_channel_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_event_type snd_seq_remove_events_get_event_type_dylibloader_wrapper_asound
+#define snd_seq_remove_events_get_tag snd_seq_remove_events_get_tag_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_condition snd_seq_remove_events_set_condition_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_queue snd_seq_remove_events_set_queue_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_time snd_seq_remove_events_set_time_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_dest snd_seq_remove_events_set_dest_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_channel snd_seq_remove_events_set_channel_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_event_type snd_seq_remove_events_set_event_type_dylibloader_wrapper_asound
+#define snd_seq_remove_events_set_tag snd_seq_remove_events_set_tag_dylibloader_wrapper_asound
+#define snd_seq_remove_events snd_seq_remove_events_dylibloader_wrapper_asound
+#define snd_seq_set_bit snd_seq_set_bit_dylibloader_wrapper_asound
+#define snd_seq_unset_bit snd_seq_unset_bit_dylibloader_wrapper_asound
+#define snd_seq_change_bit snd_seq_change_bit_dylibloader_wrapper_asound
+#define snd_seq_get_bit snd_seq_get_bit_dylibloader_wrapper_asound
+#define snd_seq_control_queue snd_seq_control_queue_dylibloader_wrapper_asound
+#define snd_seq_create_simple_port snd_seq_create_simple_port_dylibloader_wrapper_asound
+#define snd_seq_delete_simple_port snd_seq_delete_simple_port_dylibloader_wrapper_asound
+#define snd_seq_connect_from snd_seq_connect_from_dylibloader_wrapper_asound
+#define snd_seq_connect_to snd_seq_connect_to_dylibloader_wrapper_asound
+#define snd_seq_disconnect_from snd_seq_disconnect_from_dylibloader_wrapper_asound
+#define snd_seq_disconnect_to snd_seq_disconnect_to_dylibloader_wrapper_asound
+#define snd_seq_set_client_name snd_seq_set_client_name_dylibloader_wrapper_asound
+#define snd_seq_set_client_event_filter snd_seq_set_client_event_filter_dylibloader_wrapper_asound
+#define snd_seq_set_client_pool_output snd_seq_set_client_pool_output_dylibloader_wrapper_asound
+#define snd_seq_set_client_pool_output_room snd_seq_set_client_pool_output_room_dylibloader_wrapper_asound
+#define snd_seq_set_client_pool_input snd_seq_set_client_pool_input_dylibloader_wrapper_asound
+#define snd_seq_sync_output_queue snd_seq_sync_output_queue_dylibloader_wrapper_asound
+#define snd_seq_parse_address snd_seq_parse_address_dylibloader_wrapper_asound
+#define snd_seq_reset_pool_output snd_seq_reset_pool_output_dylibloader_wrapper_asound
+#define snd_seq_reset_pool_input snd_seq_reset_pool_input_dylibloader_wrapper_asound
+#define snd_midi_event_new snd_midi_event_new_dylibloader_wrapper_asound
+#define snd_midi_event_resize_buffer snd_midi_event_resize_buffer_dylibloader_wrapper_asound
+#define snd_midi_event_free snd_midi_event_free_dylibloader_wrapper_asound
+#define snd_midi_event_init snd_midi_event_init_dylibloader_wrapper_asound
+#define snd_midi_event_reset_encode snd_midi_event_reset_encode_dylibloader_wrapper_asound
+#define snd_midi_event_reset_decode snd_midi_event_reset_decode_dylibloader_wrapper_asound
+#define snd_midi_event_no_status snd_midi_event_no_status_dylibloader_wrapper_asound
+#define snd_midi_event_encode snd_midi_event_encode_dylibloader_wrapper_asound
+#define snd_midi_event_encode_byte snd_midi_event_encode_byte_dylibloader_wrapper_asound
+#define snd_midi_event_decode snd_midi_event_decode_dylibloader_wrapper_asound
+extern const char* (*snd_asoundlib_version_dylibloader_wrapper_asound)( void);
+extern int (*snd_dlpath_dylibloader_wrapper_asound)( char*, size_t,const char*);
+extern void* (*snd_dlopen_dylibloader_wrapper_asound)(const char*, int, char*, size_t);
+extern void* (*snd_dlsym_dylibloader_wrapper_asound)( void*,const char*,const char*);
+extern int (*snd_dlclose_dylibloader_wrapper_asound)( void*);
+extern int (*snd_async_add_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, int, snd_async_callback_t, void*);
+extern int (*snd_async_del_handler_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern int (*snd_async_handler_get_fd_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern int (*snd_async_handler_get_signo_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern void* (*snd_async_handler_get_callback_private_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern struct snd_shm_area* (*snd_shm_area_create_dylibloader_wrapper_asound)( int, void*);
+extern struct snd_shm_area* (*snd_shm_area_share_dylibloader_wrapper_asound)(struct snd_shm_area*);
+extern int (*snd_shm_area_destroy_dylibloader_wrapper_asound)(struct snd_shm_area*);
+extern int (*snd_user_file_dylibloader_wrapper_asound)(const char*, char**);
+extern int (*snd_input_stdio_open_dylibloader_wrapper_asound)( snd_input_t**,const char*,const char*);
+extern int (*snd_input_stdio_attach_dylibloader_wrapper_asound)( snd_input_t**, FILE*, int);
+extern int (*snd_input_buffer_open_dylibloader_wrapper_asound)( snd_input_t**,const char*, ssize_t);
+extern int (*snd_input_close_dylibloader_wrapper_asound)( snd_input_t*);
+extern int (*snd_input_scanf_dylibloader_wrapper_asound)( snd_input_t*,const char*,...);
+extern char* (*snd_input_gets_dylibloader_wrapper_asound)( snd_input_t*, char*, size_t);
+extern int (*snd_input_getc_dylibloader_wrapper_asound)( snd_input_t*);
+extern int (*snd_input_ungetc_dylibloader_wrapper_asound)( snd_input_t*, int);
+extern int (*snd_output_stdio_open_dylibloader_wrapper_asound)( snd_output_t**,const char*,const char*);
+extern int (*snd_output_stdio_attach_dylibloader_wrapper_asound)( snd_output_t**, FILE*, int);
+extern int (*snd_output_buffer_open_dylibloader_wrapper_asound)( snd_output_t**);
+extern size_t (*snd_output_buffer_string_dylibloader_wrapper_asound)( snd_output_t*, char**);
+extern int (*snd_output_close_dylibloader_wrapper_asound)( snd_output_t*);
+extern int (*snd_output_printf_dylibloader_wrapper_asound)( snd_output_t*,const char*,...);
+extern int (*snd_output_vprintf_dylibloader_wrapper_asound)( snd_output_t*,const char*, va_list);
+extern int (*snd_output_puts_dylibloader_wrapper_asound)( snd_output_t*,const char*);
+extern int (*snd_output_putc_dylibloader_wrapper_asound)( snd_output_t*, int);
+extern int (*snd_output_flush_dylibloader_wrapper_asound)( snd_output_t*);
+extern const char* (*snd_strerror_dylibloader_wrapper_asound)( int);
+extern int (*snd_lib_error_set_handler_dylibloader_wrapper_asound)( snd_lib_error_handler_t);
+extern snd_local_error_handler_t (*snd_lib_error_set_local_dylibloader_wrapper_asound)( snd_local_error_handler_t);
+extern const char* (*snd_config_topdir_dylibloader_wrapper_asound)( void);
+extern int (*snd_config_top_dylibloader_wrapper_asound)( snd_config_t**);
+extern int (*snd_config_load_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
+extern int (*snd_config_load_override_dylibloader_wrapper_asound)( snd_config_t*, snd_input_t*);
+extern int (*snd_config_save_dylibloader_wrapper_asound)( snd_config_t*, snd_output_t*);
+extern int (*snd_config_update_dylibloader_wrapper_asound)( void);
+extern int (*snd_config_update_r_dylibloader_wrapper_asound)( snd_config_t**, snd_config_update_t**,const char*);
+extern int (*snd_config_update_free_dylibloader_wrapper_asound)( snd_config_update_t*);
+extern int (*snd_config_update_free_global_dylibloader_wrapper_asound)( void);
+extern int (*snd_config_update_ref_dylibloader_wrapper_asound)( snd_config_t**);
+extern void (*snd_config_ref_dylibloader_wrapper_asound)( snd_config_t*);
+extern void (*snd_config_unref_dylibloader_wrapper_asound)( snd_config_t*);
+extern int (*snd_config_search_dylibloader_wrapper_asound)( snd_config_t*,const char*, snd_config_t**);
+extern int (*snd_config_searchv_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t**,...);
+extern int (*snd_config_search_definition_dylibloader_wrapper_asound)( snd_config_t*,const char*,const char*, snd_config_t**);
+extern int (*snd_config_expand_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*,const char*, snd_config_t*, snd_config_t**);
+extern int (*snd_config_evaluate_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*, snd_config_t*, snd_config_t**);
+extern int (*snd_config_add_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+extern int (*snd_config_add_before_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+extern int (*snd_config_add_after_dylibloader_wrapper_asound)( snd_config_t*, snd_config_t*);
+extern int (*snd_config_remove_dylibloader_wrapper_asound)( snd_config_t*);
+extern int (*snd_config_delete_dylibloader_wrapper_asound)( snd_config_t*);
+extern int (*snd_config_delete_compound_members_dylibloader_wrapper_asound)(const snd_config_t*);
+extern int (*snd_config_copy_dylibloader_wrapper_asound)( snd_config_t**, snd_config_t*);
+extern int (*snd_config_make_dylibloader_wrapper_asound)( snd_config_t**,const char*, snd_config_type_t);
+extern int (*snd_config_make_integer_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+extern int (*snd_config_make_integer64_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+extern int (*snd_config_make_real_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+extern int (*snd_config_make_string_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+extern int (*snd_config_make_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*);
+extern int (*snd_config_make_compound_dylibloader_wrapper_asound)( snd_config_t**,const char*, int);
+extern int (*snd_config_imake_integer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const long);
+extern int (*snd_config_imake_integer64_dylibloader_wrapper_asound)( snd_config_t**,const char*,const long long);
+extern int (*snd_config_imake_real_dylibloader_wrapper_asound)( snd_config_t**,const char*,const double);
+extern int (*snd_config_imake_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
+extern int (*snd_config_imake_safe_string_dylibloader_wrapper_asound)( snd_config_t**,const char*,const char*);
+extern int (*snd_config_imake_pointer_dylibloader_wrapper_asound)( snd_config_t**,const char*,const void*);
+extern snd_config_type_t (*snd_config_get_type_dylibloader_wrapper_asound)(const snd_config_t*);
+extern int (*snd_config_is_array_dylibloader_wrapper_asound)(const snd_config_t*);
+extern int (*snd_config_set_id_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+extern int (*snd_config_set_integer_dylibloader_wrapper_asound)( snd_config_t*, long);
+extern int (*snd_config_set_integer64_dylibloader_wrapper_asound)( snd_config_t*, long long);
+extern int (*snd_config_set_real_dylibloader_wrapper_asound)( snd_config_t*, double);
+extern int (*snd_config_set_string_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+extern int (*snd_config_set_ascii_dylibloader_wrapper_asound)( snd_config_t*,const char*);
+extern int (*snd_config_set_pointer_dylibloader_wrapper_asound)( snd_config_t*,const void*);
+extern int (*snd_config_get_id_dylibloader_wrapper_asound)(const snd_config_t*,const char**);
+extern int (*snd_config_get_integer_dylibloader_wrapper_asound)(const snd_config_t*, long*);
+extern int (*snd_config_get_integer64_dylibloader_wrapper_asound)(const snd_config_t*, long long*);
+extern int (*snd_config_get_real_dylibloader_wrapper_asound)(const snd_config_t*, double*);
+extern int (*snd_config_get_ireal_dylibloader_wrapper_asound)(const snd_config_t*, double*);
+extern int (*snd_config_get_string_dylibloader_wrapper_asound)(const snd_config_t*,const char**);
+extern int (*snd_config_get_ascii_dylibloader_wrapper_asound)(const snd_config_t*, char**);
+extern int (*snd_config_get_pointer_dylibloader_wrapper_asound)(const snd_config_t*,const void**);
+extern int (*snd_config_test_id_dylibloader_wrapper_asound)(const snd_config_t*,const char*);
+extern snd_config_iterator_t (*snd_config_iterator_first_dylibloader_wrapper_asound)(const snd_config_t*);
+extern snd_config_iterator_t (*snd_config_iterator_next_dylibloader_wrapper_asound)(const snd_config_iterator_t);
+extern snd_config_iterator_t (*snd_config_iterator_end_dylibloader_wrapper_asound)(const snd_config_t*);
+extern snd_config_t* (*snd_config_iterator_entry_dylibloader_wrapper_asound)(const snd_config_iterator_t);
+extern int (*snd_config_get_bool_ascii_dylibloader_wrapper_asound)(const char*);
+extern int (*snd_config_get_bool_dylibloader_wrapper_asound)(const snd_config_t*);
+extern int (*snd_config_get_ctl_iface_ascii_dylibloader_wrapper_asound)(const char*);
+extern int (*snd_config_get_ctl_iface_dylibloader_wrapper_asound)(const snd_config_t*);
+extern int (*snd_names_list_dylibloader_wrapper_asound)(const char*, snd_devname_t**);
+extern void (*snd_names_list_free_dylibloader_wrapper_asound)( snd_devname_t*);
+extern int (*snd_pcm_open_dylibloader_wrapper_asound)( snd_pcm_t**,const char*, snd_pcm_stream_t, int);
+extern int (*snd_pcm_open_lconf_dylibloader_wrapper_asound)( snd_pcm_t**,const char*, snd_pcm_stream_t, int, snd_config_t*);
+extern int (*snd_pcm_open_fallback_dylibloader_wrapper_asound)( snd_pcm_t**, snd_config_t*,const char*,const char*, snd_pcm_stream_t, int);
+extern int (*snd_pcm_close_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern const char* (*snd_pcm_name_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_type_t (*snd_pcm_type_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_stream_t (*snd_pcm_stream_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_poll_descriptors_count_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_poll_descriptors_dylibloader_wrapper_asound)( snd_pcm_t*,struct pollfd*, unsigned int);
+extern int (*snd_pcm_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_pcm_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_pcm_nonblock_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+extern int (*snd_async_add_pcm_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_pcm_t*, snd_async_callback_t, void*);
+extern snd_pcm_t* (*snd_async_handler_get_pcm_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern int (*snd_pcm_info_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_info_t*);
+extern int (*snd_pcm_hw_params_current_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_free_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_sw_params_current_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*);
+extern int (*snd_pcm_sw_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*);
+extern int (*snd_pcm_prepare_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_reset_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_status_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_status_t*);
+extern int (*snd_pcm_start_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_drop_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_drain_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_pause_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+extern snd_pcm_state_t (*snd_pcm_state_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_hwsync_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_delay_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t*);
+extern int (*snd_pcm_resume_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_htimestamp_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t*, snd_htimestamp_t*);
+extern snd_pcm_sframes_t (*snd_pcm_avail_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_sframes_t (*snd_pcm_avail_update_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_avail_delay_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t*, snd_pcm_sframes_t*);
+extern snd_pcm_sframes_t (*snd_pcm_rewindable_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_sframes_t (*snd_pcm_rewind_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_forwardable_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_sframes_t (*snd_pcm_forward_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_writei_dylibloader_wrapper_asound)( snd_pcm_t*,const void*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_readi_dylibloader_wrapper_asound)( snd_pcm_t*, void*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_writen_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_readn_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+extern int (*snd_pcm_wait_dylibloader_wrapper_asound)( snd_pcm_t*, int);
+extern int (*snd_pcm_link_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_t*);
+extern int (*snd_pcm_unlink_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_chmap_query_t** (*snd_pcm_query_chmaps_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_chmap_query_t** (*snd_pcm_query_chmaps_from_hw_dylibloader_wrapper_asound)( int, int, int, snd_pcm_stream_t);
+extern void (*snd_pcm_free_chmaps_dylibloader_wrapper_asound)( snd_pcm_chmap_query_t**);
+extern snd_pcm_chmap_t* (*snd_pcm_get_chmap_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_set_chmap_dylibloader_wrapper_asound)( snd_pcm_t*,const snd_pcm_chmap_t*);
+extern const char* (*snd_pcm_chmap_type_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_type);
+extern const char* (*snd_pcm_chmap_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_position);
+extern const char* (*snd_pcm_chmap_long_name_dylibloader_wrapper_asound)(enum snd_pcm_chmap_position);
+extern int (*snd_pcm_chmap_print_dylibloader_wrapper_asound)(const snd_pcm_chmap_t*, size_t, char*);
+extern unsigned int (*snd_pcm_chmap_from_string_dylibloader_wrapper_asound)(const char*);
+extern snd_pcm_chmap_t* (*snd_pcm_chmap_parse_string_dylibloader_wrapper_asound)(const char*);
+extern int (*snd_pcm_recover_dylibloader_wrapper_asound)( snd_pcm_t*, int, int);
+extern int (*snd_pcm_set_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_format_t, snd_pcm_access_t, unsigned int, unsigned int, int, unsigned int);
+extern int (*snd_pcm_get_params_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+extern size_t (*snd_pcm_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_info_malloc_dylibloader_wrapper_asound)( snd_pcm_info_t**);
+extern void (*snd_pcm_info_free_dylibloader_wrapper_asound)( snd_pcm_info_t*);
+extern void (*snd_pcm_info_copy_dylibloader_wrapper_asound)( snd_pcm_info_t*,const snd_pcm_info_t*);
+extern unsigned int (*snd_pcm_info_get_device_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern unsigned int (*snd_pcm_info_get_subdevice_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern snd_pcm_stream_t (*snd_pcm_info_get_stream_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern int (*snd_pcm_info_get_card_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern const char* (*snd_pcm_info_get_id_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern const char* (*snd_pcm_info_get_name_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern const char* (*snd_pcm_info_get_subdevice_name_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern snd_pcm_class_t (*snd_pcm_info_get_class_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern snd_pcm_subclass_t (*snd_pcm_info_get_subclass_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern unsigned int (*snd_pcm_info_get_subdevices_count_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern unsigned int (*snd_pcm_info_get_subdevices_avail_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern snd_pcm_sync_id_t (*snd_pcm_info_get_sync_dylibloader_wrapper_asound)(const snd_pcm_info_t*);
+extern void (*snd_pcm_info_set_device_dylibloader_wrapper_asound)( snd_pcm_info_t*, unsigned int);
+extern void (*snd_pcm_info_set_subdevice_dylibloader_wrapper_asound)( snd_pcm_info_t*, unsigned int);
+extern void (*snd_pcm_info_set_stream_dylibloader_wrapper_asound)( snd_pcm_info_t*, snd_pcm_stream_t);
+extern int (*snd_pcm_hw_params_any_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_mmap_sample_resolution_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_double_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_batch_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_block_transfer_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_monotonic_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_overrange_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_pause_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_resume_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_half_duplex_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_is_joint_duplex_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_sync_start_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_can_disable_period_wakeup_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_supports_audio_wallclock_ts_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_supports_audio_ts_type_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, int);
+extern int (*snd_pcm_hw_params_get_rate_numden_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_sbits_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_get_fifo_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*);
+extern size_t (*snd_pcm_hw_params_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_hw_params_malloc_dylibloader_wrapper_asound)( snd_pcm_hw_params_t**);
+extern void (*snd_pcm_hw_params_free_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*);
+extern void (*snd_pcm_hw_params_copy_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*,const snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_get_access_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_access_t*);
+extern int (*snd_pcm_hw_params_test_access_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t);
+extern int (*snd_pcm_hw_params_set_access_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t);
+extern int (*snd_pcm_hw_params_set_access_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t*);
+extern int (*snd_pcm_hw_params_set_access_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t*);
+extern int (*snd_pcm_hw_params_set_access_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_mask_t*);
+extern int (*snd_pcm_hw_params_get_access_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_access_mask_t*);
+extern int (*snd_pcm_hw_params_get_format_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_format_t*);
+extern int (*snd_pcm_hw_params_test_format_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t);
+extern int (*snd_pcm_hw_params_set_format_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t);
+extern int (*snd_pcm_hw_params_set_format_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t*);
+extern int (*snd_pcm_hw_params_set_format_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t*);
+extern int (*snd_pcm_hw_params_set_format_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_mask_t*);
+extern void (*snd_pcm_hw_params_get_format_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_format_mask_t*);
+extern int (*snd_pcm_hw_params_get_subformat_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+extern int (*snd_pcm_hw_params_test_subformat_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t);
+extern int (*snd_pcm_hw_params_set_subformat_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t);
+extern int (*snd_pcm_hw_params_set_subformat_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+extern int (*snd_pcm_hw_params_set_subformat_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_t*);
+extern int (*snd_pcm_hw_params_set_subformat_mask_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_subformat_mask_t*);
+extern void (*snd_pcm_hw_params_get_subformat_mask_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_pcm_subformat_mask_t*);
+extern int (*snd_pcm_hw_params_get_channels_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_channels_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_channels_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_test_channels_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+extern int (*snd_pcm_hw_params_set_channels_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+extern int (*snd_pcm_hw_params_set_channels_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_channels_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_channels_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_channels_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_channels_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_channels_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_rate_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_rate_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_rate_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_test_rate_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_rate_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_rate_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_rate_resample_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+extern int (*snd_pcm_hw_params_get_rate_resample_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_export_buffer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+extern int (*snd_pcm_hw_params_get_export_buffer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_set_period_wakeup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int);
+extern int (*snd_pcm_hw_params_get_period_wakeup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_period_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_period_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_period_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_test_period_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_period_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_period_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_period_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_period_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_period_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_period_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_period_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_period_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_get_period_size_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_get_period_size_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_test_period_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t, int);
+extern int (*snd_pcm_hw_params_set_period_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t, int);
+extern int (*snd_pcm_hw_params_set_period_size_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int*);
+extern int (*snd_pcm_hw_params_set_period_size_integer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_get_periods_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_periods_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_periods_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_test_periods_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_periods_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_periods_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_periods_integer_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*);
+extern int (*snd_pcm_hw_params_get_buffer_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_buffer_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_buffer_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_test_buffer_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_buffer_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_buffer_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_buffer_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_buffer_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_buffer_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_buffer_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_buffer_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_buffer_size_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_get_buffer_size_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_get_buffer_size_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_test_buffer_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_hw_params_set_buffer_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_hw_params_set_buffer_size_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_set_buffer_size_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_set_buffer_size_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_set_buffer_size_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_set_buffer_size_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_set_buffer_size_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_hw_params_get_min_align_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, snd_pcm_uframes_t*);
+extern size_t (*snd_pcm_sw_params_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_sw_params_malloc_dylibloader_wrapper_asound)( snd_pcm_sw_params_t**);
+extern void (*snd_pcm_sw_params_free_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*);
+extern void (*snd_pcm_sw_params_copy_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*,const snd_pcm_sw_params_t*);
+extern int (*snd_pcm_sw_params_get_boundary_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_tstamp_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_tstamp_t);
+extern int (*snd_pcm_sw_params_get_tstamp_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_tstamp_t*);
+extern int (*snd_pcm_sw_params_set_avail_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_avail_min_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_period_event_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, int);
+extern int (*snd_pcm_sw_params_get_period_event_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, int*);
+extern int (*snd_pcm_sw_params_set_start_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_start_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_stop_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_stop_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_silence_threshold_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_silence_threshold_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_silence_size_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_silence_size_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern size_t (*snd_pcm_access_mask_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_access_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_access_mask_t**);
+extern void (*snd_pcm_access_mask_free_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+extern void (*snd_pcm_access_mask_copy_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*,const snd_pcm_access_mask_t*);
+extern void (*snd_pcm_access_mask_none_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+extern void (*snd_pcm_access_mask_any_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*);
+extern int (*snd_pcm_access_mask_test_dylibloader_wrapper_asound)(const snd_pcm_access_mask_t*, snd_pcm_access_t);
+extern int (*snd_pcm_access_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_access_mask_t*);
+extern void (*snd_pcm_access_mask_set_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*, snd_pcm_access_t);
+extern void (*snd_pcm_access_mask_reset_dylibloader_wrapper_asound)( snd_pcm_access_mask_t*, snd_pcm_access_t);
+extern size_t (*snd_pcm_format_mask_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_format_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_format_mask_t**);
+extern void (*snd_pcm_format_mask_free_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+extern void (*snd_pcm_format_mask_copy_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*,const snd_pcm_format_mask_t*);
+extern void (*snd_pcm_format_mask_none_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+extern void (*snd_pcm_format_mask_any_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*);
+extern int (*snd_pcm_format_mask_test_dylibloader_wrapper_asound)(const snd_pcm_format_mask_t*, snd_pcm_format_t);
+extern int (*snd_pcm_format_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_format_mask_t*);
+extern void (*snd_pcm_format_mask_set_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*, snd_pcm_format_t);
+extern void (*snd_pcm_format_mask_reset_dylibloader_wrapper_asound)( snd_pcm_format_mask_t*, snd_pcm_format_t);
+extern size_t (*snd_pcm_subformat_mask_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_subformat_mask_malloc_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t**);
+extern void (*snd_pcm_subformat_mask_free_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+extern void (*snd_pcm_subformat_mask_copy_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*,const snd_pcm_subformat_mask_t*);
+extern void (*snd_pcm_subformat_mask_none_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+extern void (*snd_pcm_subformat_mask_any_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*);
+extern int (*snd_pcm_subformat_mask_test_dylibloader_wrapper_asound)(const snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+extern int (*snd_pcm_subformat_mask_empty_dylibloader_wrapper_asound)(const snd_pcm_subformat_mask_t*);
+extern void (*snd_pcm_subformat_mask_set_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+extern void (*snd_pcm_subformat_mask_reset_dylibloader_wrapper_asound)( snd_pcm_subformat_mask_t*, snd_pcm_subformat_t);
+extern size_t (*snd_pcm_status_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_pcm_status_malloc_dylibloader_wrapper_asound)( snd_pcm_status_t**);
+extern void (*snd_pcm_status_free_dylibloader_wrapper_asound)( snd_pcm_status_t*);
+extern void (*snd_pcm_status_copy_dylibloader_wrapper_asound)( snd_pcm_status_t*,const snd_pcm_status_t*);
+extern snd_pcm_state_t (*snd_pcm_status_get_state_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+extern void (*snd_pcm_status_get_trigger_tstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_timestamp_t*);
+extern void (*snd_pcm_status_get_trigger_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+extern void (*snd_pcm_status_get_tstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_timestamp_t*);
+extern void (*snd_pcm_status_get_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+extern void (*snd_pcm_status_get_audio_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+extern void (*snd_pcm_status_get_driver_htstamp_dylibloader_wrapper_asound)(const snd_pcm_status_t*, snd_htimestamp_t*);
+extern snd_pcm_sframes_t (*snd_pcm_status_get_delay_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+extern snd_pcm_uframes_t (*snd_pcm_status_get_avail_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+extern snd_pcm_uframes_t (*snd_pcm_status_get_avail_max_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+extern snd_pcm_uframes_t (*snd_pcm_status_get_overrange_dylibloader_wrapper_asound)(const snd_pcm_status_t*);
+extern const char* (*snd_pcm_type_name_dylibloader_wrapper_asound)( snd_pcm_type_t);
+extern const char* (*snd_pcm_stream_name_dylibloader_wrapper_asound)(const snd_pcm_stream_t);
+extern const char* (*snd_pcm_access_name_dylibloader_wrapper_asound)(const snd_pcm_access_t);
+extern const char* (*snd_pcm_format_name_dylibloader_wrapper_asound)(const snd_pcm_format_t);
+extern const char* (*snd_pcm_format_description_dylibloader_wrapper_asound)(const snd_pcm_format_t);
+extern const char* (*snd_pcm_subformat_name_dylibloader_wrapper_asound)(const snd_pcm_subformat_t);
+extern const char* (*snd_pcm_subformat_description_dylibloader_wrapper_asound)(const snd_pcm_subformat_t);
+extern snd_pcm_format_t (*snd_pcm_format_value_dylibloader_wrapper_asound)(const char*);
+extern const char* (*snd_pcm_tstamp_mode_name_dylibloader_wrapper_asound)(const snd_pcm_tstamp_t);
+extern const char* (*snd_pcm_state_name_dylibloader_wrapper_asound)(const snd_pcm_state_t);
+extern int (*snd_pcm_dump_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+extern int (*snd_pcm_dump_hw_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+extern int (*snd_pcm_dump_sw_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+extern int (*snd_pcm_dump_setup_dylibloader_wrapper_asound)( snd_pcm_t*, snd_output_t*);
+extern int (*snd_pcm_hw_params_dump_dylibloader_wrapper_asound)( snd_pcm_hw_params_t*, snd_output_t*);
+extern int (*snd_pcm_sw_params_dump_dylibloader_wrapper_asound)( snd_pcm_sw_params_t*, snd_output_t*);
+extern int (*snd_pcm_status_dump_dylibloader_wrapper_asound)( snd_pcm_status_t*, snd_output_t*);
+extern int (*snd_pcm_mmap_begin_dylibloader_wrapper_asound)( snd_pcm_t*,const snd_pcm_channel_area_t**, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+extern snd_pcm_sframes_t (*snd_pcm_mmap_commit_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_uframes_t, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_mmap_writei_dylibloader_wrapper_asound)( snd_pcm_t*,const void*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_mmap_readi_dylibloader_wrapper_asound)( snd_pcm_t*, void*, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_mmap_writen_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+extern snd_pcm_sframes_t (*snd_pcm_mmap_readn_dylibloader_wrapper_asound)( snd_pcm_t*, void**, snd_pcm_uframes_t);
+extern int (*snd_pcm_format_signed_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_unsigned_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_linear_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_float_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_little_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_big_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_cpu_endian_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_width_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_physical_width_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern snd_pcm_format_t (*snd_pcm_build_linear_format_dylibloader_wrapper_asound)( int, int, int, int);
+extern ssize_t (*snd_pcm_format_size_dylibloader_wrapper_asound)( snd_pcm_format_t, size_t);
+extern uint8_t (*snd_pcm_format_silence_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern uint16_t (*snd_pcm_format_silence_16_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern uint32_t (*snd_pcm_format_silence_32_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern uint64_t (*snd_pcm_format_silence_64_dylibloader_wrapper_asound)( snd_pcm_format_t);
+extern int (*snd_pcm_format_set_silence_dylibloader_wrapper_asound)( snd_pcm_format_t, void*, unsigned int);
+extern snd_pcm_sframes_t (*snd_pcm_bytes_to_frames_dylibloader_wrapper_asound)( snd_pcm_t*, ssize_t);
+extern ssize_t (*snd_pcm_frames_to_bytes_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sframes_t);
+extern long (*snd_pcm_bytes_to_samples_dylibloader_wrapper_asound)( snd_pcm_t*, ssize_t);
+extern ssize_t (*snd_pcm_samples_to_bytes_dylibloader_wrapper_asound)( snd_pcm_t*, long);
+extern int (*snd_pcm_area_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
+extern int (*snd_pcm_areas_silence_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
+extern int (*snd_pcm_area_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_format_t);
+extern int (*snd_pcm_areas_copy_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t, unsigned int, snd_pcm_uframes_t, snd_pcm_format_t);
+extern int (*snd_pcm_areas_copy_wrap_dylibloader_wrapper_asound)(const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const snd_pcm_channel_area_t*, snd_pcm_uframes_t,const snd_pcm_uframes_t,const unsigned int, snd_pcm_uframes_t,const snd_pcm_format_t);
+extern snd_pcm_t* (*snd_pcm_hook_get_pcm_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+extern void* (*snd_pcm_hook_get_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+extern void (*snd_pcm_hook_set_private_dylibloader_wrapper_asound)( snd_pcm_hook_t*, void*);
+extern int (*snd_pcm_hook_add_dylibloader_wrapper_asound)( snd_pcm_hook_t**, snd_pcm_t*, snd_pcm_hook_type_t, snd_pcm_hook_func_t, void*);
+extern int (*snd_pcm_hook_remove_dylibloader_wrapper_asound)( snd_pcm_hook_t*);
+extern snd_pcm_uframes_t (*snd_pcm_meter_get_bufsize_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern unsigned int (*snd_pcm_meter_get_channels_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern unsigned int (*snd_pcm_meter_get_rate_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_uframes_t (*snd_pcm_meter_get_now_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern snd_pcm_uframes_t (*snd_pcm_meter_get_boundary_dylibloader_wrapper_asound)( snd_pcm_t*);
+extern int (*snd_pcm_meter_add_scope_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_scope_t*);
+extern snd_pcm_scope_t* (*snd_pcm_meter_search_scope_dylibloader_wrapper_asound)( snd_pcm_t*,const char*);
+extern int (*snd_pcm_scope_malloc_dylibloader_wrapper_asound)( snd_pcm_scope_t**);
+extern void (*snd_pcm_scope_set_ops_dylibloader_wrapper_asound)( snd_pcm_scope_t*,const snd_pcm_scope_ops_t*);
+extern void (*snd_pcm_scope_set_name_dylibloader_wrapper_asound)( snd_pcm_scope_t*,const char*);
+extern const char* (*snd_pcm_scope_get_name_dylibloader_wrapper_asound)( snd_pcm_scope_t*);
+extern void* (*snd_pcm_scope_get_callback_private_dylibloader_wrapper_asound)( snd_pcm_scope_t*);
+extern void (*snd_pcm_scope_set_callback_private_dylibloader_wrapper_asound)( snd_pcm_scope_t*, void*);
+extern int (*snd_pcm_scope_s16_open_dylibloader_wrapper_asound)( snd_pcm_t*,const char*, snd_pcm_scope_t**);
+extern int16_t* (*snd_pcm_scope_s16_get_channel_buffer_dylibloader_wrapper_asound)( snd_pcm_scope_t*, unsigned int);
+extern int (*snd_spcm_init_dylibloader_wrapper_asound)( snd_pcm_t*, unsigned int, unsigned int, snd_pcm_format_t, snd_pcm_subformat_t, snd_spcm_latency_t, snd_pcm_access_t, snd_spcm_xrun_type_t);
+extern int (*snd_spcm_init_duplex_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_t*, unsigned int, unsigned int, snd_pcm_format_t, snd_pcm_subformat_t, snd_spcm_latency_t, snd_pcm_access_t, snd_spcm_xrun_type_t, snd_spcm_duplex_type_t);
+extern int (*snd_spcm_init_get_params_dylibloader_wrapper_asound)( snd_pcm_t*, unsigned int*, snd_pcm_uframes_t*, snd_pcm_uframes_t*);
+extern const char* (*snd_pcm_start_mode_name_dylibloader_wrapper_asound)( snd_pcm_start_t);
+extern const char* (*snd_pcm_xrun_mode_name_dylibloader_wrapper_asound)( snd_pcm_xrun_t);
+extern int (*snd_pcm_sw_params_set_start_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_start_t);
+extern snd_pcm_start_t (*snd_pcm_sw_params_get_start_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*);
+extern int (*snd_pcm_sw_params_set_xrun_mode_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_xrun_t);
+extern snd_pcm_xrun_t (*snd_pcm_sw_params_get_xrun_mode_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*);
+extern int (*snd_pcm_sw_params_set_xfer_align_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t);
+extern int (*snd_pcm_sw_params_get_xfer_align_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, snd_pcm_uframes_t*);
+extern int (*snd_pcm_sw_params_set_sleep_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_sw_params_t*, unsigned int);
+extern int (*snd_pcm_sw_params_get_sleep_min_dylibloader_wrapper_asound)(const snd_pcm_sw_params_t*, unsigned int*);
+extern int (*snd_pcm_hw_params_get_tick_time_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_tick_time_min_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_get_tick_time_max_dylibloader_wrapper_asound)(const snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_test_tick_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_tick_time_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int, int);
+extern int (*snd_pcm_hw_params_set_tick_time_min_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_tick_time_max_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_tick_time_minmax_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_tick_time_near_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_tick_time_first_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_pcm_hw_params_set_tick_time_last_dylibloader_wrapper_asound)( snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int*, int*);
+extern int (*snd_rawmidi_open_dylibloader_wrapper_asound)( snd_rawmidi_t**, snd_rawmidi_t**,const char*, int);
+extern int (*snd_rawmidi_open_lconf_dylibloader_wrapper_asound)( snd_rawmidi_t**, snd_rawmidi_t**,const char*, int, snd_config_t*);
+extern int (*snd_rawmidi_close_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern int (*snd_rawmidi_poll_descriptors_count_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern int (*snd_rawmidi_poll_descriptors_dylibloader_wrapper_asound)( snd_rawmidi_t*,struct pollfd*, unsigned int);
+extern int (*snd_rawmidi_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_rawmidi_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_rawmidi_nonblock_dylibloader_wrapper_asound)( snd_rawmidi_t*, int);
+extern size_t (*snd_rawmidi_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_rawmidi_info_malloc_dylibloader_wrapper_asound)( snd_rawmidi_info_t**);
+extern void (*snd_rawmidi_info_free_dylibloader_wrapper_asound)( snd_rawmidi_info_t*);
+extern void (*snd_rawmidi_info_copy_dylibloader_wrapper_asound)( snd_rawmidi_info_t*,const snd_rawmidi_info_t*);
+extern unsigned int (*snd_rawmidi_info_get_device_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern unsigned int (*snd_rawmidi_info_get_subdevice_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern snd_rawmidi_stream_t (*snd_rawmidi_info_get_stream_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern int (*snd_rawmidi_info_get_card_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern unsigned int (*snd_rawmidi_info_get_flags_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern const char* (*snd_rawmidi_info_get_id_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern const char* (*snd_rawmidi_info_get_name_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern const char* (*snd_rawmidi_info_get_subdevice_name_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern unsigned int (*snd_rawmidi_info_get_subdevices_count_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern unsigned int (*snd_rawmidi_info_get_subdevices_avail_dylibloader_wrapper_asound)(const snd_rawmidi_info_t*);
+extern void (*snd_rawmidi_info_set_device_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, unsigned int);
+extern void (*snd_rawmidi_info_set_subdevice_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, unsigned int);
+extern void (*snd_rawmidi_info_set_stream_dylibloader_wrapper_asound)( snd_rawmidi_info_t*, snd_rawmidi_stream_t);
+extern int (*snd_rawmidi_info_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_info_t*);
+extern size_t (*snd_rawmidi_params_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_rawmidi_params_malloc_dylibloader_wrapper_asound)( snd_rawmidi_params_t**);
+extern void (*snd_rawmidi_params_free_dylibloader_wrapper_asound)( snd_rawmidi_params_t*);
+extern void (*snd_rawmidi_params_copy_dylibloader_wrapper_asound)( snd_rawmidi_params_t*,const snd_rawmidi_params_t*);
+extern int (*snd_rawmidi_params_set_buffer_size_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, size_t);
+extern size_t (*snd_rawmidi_params_get_buffer_size_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+extern int (*snd_rawmidi_params_set_avail_min_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, size_t);
+extern size_t (*snd_rawmidi_params_get_avail_min_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+extern int (*snd_rawmidi_params_set_no_active_sensing_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*, int);
+extern int (*snd_rawmidi_params_get_no_active_sensing_dylibloader_wrapper_asound)(const snd_rawmidi_params_t*);
+extern int (*snd_rawmidi_params_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*);
+extern int (*snd_rawmidi_params_current_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_params_t*);
+extern size_t (*snd_rawmidi_status_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_rawmidi_status_malloc_dylibloader_wrapper_asound)( snd_rawmidi_status_t**);
+extern void (*snd_rawmidi_status_free_dylibloader_wrapper_asound)( snd_rawmidi_status_t*);
+extern void (*snd_rawmidi_status_copy_dylibloader_wrapper_asound)( snd_rawmidi_status_t*,const snd_rawmidi_status_t*);
+extern void (*snd_rawmidi_status_get_tstamp_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*, snd_htimestamp_t*);
+extern size_t (*snd_rawmidi_status_get_avail_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*);
+extern size_t (*snd_rawmidi_status_get_xruns_dylibloader_wrapper_asound)(const snd_rawmidi_status_t*);
+extern int (*snd_rawmidi_status_dylibloader_wrapper_asound)( snd_rawmidi_t*, snd_rawmidi_status_t*);
+extern int (*snd_rawmidi_drain_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern int (*snd_rawmidi_drop_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern ssize_t (*snd_rawmidi_write_dylibloader_wrapper_asound)( snd_rawmidi_t*,const void*, size_t);
+extern ssize_t (*snd_rawmidi_read_dylibloader_wrapper_asound)( snd_rawmidi_t*, void*, size_t);
+extern const char* (*snd_rawmidi_name_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern snd_rawmidi_type_t (*snd_rawmidi_type_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern snd_rawmidi_stream_t (*snd_rawmidi_stream_dylibloader_wrapper_asound)( snd_rawmidi_t*);
+extern int (*snd_timer_query_open_dylibloader_wrapper_asound)( snd_timer_query_t**,const char*, int);
+extern int (*snd_timer_query_open_lconf_dylibloader_wrapper_asound)( snd_timer_query_t**,const char*, int, snd_config_t*);
+extern int (*snd_timer_query_close_dylibloader_wrapper_asound)( snd_timer_query_t*);
+extern int (*snd_timer_query_next_device_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_id_t*);
+extern int (*snd_timer_query_info_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_ginfo_t*);
+extern int (*snd_timer_query_params_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_gparams_t*);
+extern int (*snd_timer_query_status_dylibloader_wrapper_asound)( snd_timer_query_t*, snd_timer_gstatus_t*);
+extern int (*snd_timer_open_dylibloader_wrapper_asound)( snd_timer_t**,const char*, int);
+extern int (*snd_timer_open_lconf_dylibloader_wrapper_asound)( snd_timer_t**,const char*, int, snd_config_t*);
+extern int (*snd_timer_close_dylibloader_wrapper_asound)( snd_timer_t*);
+extern int (*snd_async_add_timer_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_timer_t*, snd_async_callback_t, void*);
+extern snd_timer_t* (*snd_async_handler_get_timer_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern int (*snd_timer_poll_descriptors_count_dylibloader_wrapper_asound)( snd_timer_t*);
+extern int (*snd_timer_poll_descriptors_dylibloader_wrapper_asound)( snd_timer_t*,struct pollfd*, unsigned int);
+extern int (*snd_timer_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_timer_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_timer_info_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_info_t*);
+extern int (*snd_timer_params_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_params_t*);
+extern int (*snd_timer_status_dylibloader_wrapper_asound)( snd_timer_t*, snd_timer_status_t*);
+extern int (*snd_timer_start_dylibloader_wrapper_asound)( snd_timer_t*);
+extern int (*snd_timer_stop_dylibloader_wrapper_asound)( snd_timer_t*);
+extern int (*snd_timer_continue_dylibloader_wrapper_asound)( snd_timer_t*);
+extern ssize_t (*snd_timer_read_dylibloader_wrapper_asound)( snd_timer_t*, void*, size_t);
+extern size_t (*snd_timer_id_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_timer_id_malloc_dylibloader_wrapper_asound)( snd_timer_id_t**);
+extern void (*snd_timer_id_free_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern void (*snd_timer_id_copy_dylibloader_wrapper_asound)( snd_timer_id_t*,const snd_timer_id_t*);
+extern void (*snd_timer_id_set_class_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+extern int (*snd_timer_id_get_class_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern void (*snd_timer_id_set_sclass_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+extern int (*snd_timer_id_get_sclass_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern void (*snd_timer_id_set_card_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+extern int (*snd_timer_id_get_card_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern void (*snd_timer_id_set_device_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+extern int (*snd_timer_id_get_device_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern void (*snd_timer_id_set_subdevice_dylibloader_wrapper_asound)( snd_timer_id_t*, int);
+extern int (*snd_timer_id_get_subdevice_dylibloader_wrapper_asound)( snd_timer_id_t*);
+extern size_t (*snd_timer_ginfo_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_timer_ginfo_malloc_dylibloader_wrapper_asound)( snd_timer_ginfo_t**);
+extern void (*snd_timer_ginfo_free_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern void (*snd_timer_ginfo_copy_dylibloader_wrapper_asound)( snd_timer_ginfo_t*,const snd_timer_ginfo_t*);
+extern int (*snd_timer_ginfo_set_tid_dylibloader_wrapper_asound)( snd_timer_ginfo_t*, snd_timer_id_t*);
+extern snd_timer_id_t* (*snd_timer_ginfo_get_tid_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern unsigned int (*snd_timer_ginfo_get_flags_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern int (*snd_timer_ginfo_get_card_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern char* (*snd_timer_ginfo_get_id_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern char* (*snd_timer_ginfo_get_name_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern unsigned long (*snd_timer_ginfo_get_resolution_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern unsigned long (*snd_timer_ginfo_get_resolution_min_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern unsigned long (*snd_timer_ginfo_get_resolution_max_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern unsigned int (*snd_timer_ginfo_get_clients_dylibloader_wrapper_asound)( snd_timer_ginfo_t*);
+extern size_t (*snd_timer_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_timer_info_malloc_dylibloader_wrapper_asound)( snd_timer_info_t**);
+extern void (*snd_timer_info_free_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern void (*snd_timer_info_copy_dylibloader_wrapper_asound)( snd_timer_info_t*,const snd_timer_info_t*);
+extern int (*snd_timer_info_is_slave_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern int (*snd_timer_info_get_card_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern const char* (*snd_timer_info_get_id_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern const char* (*snd_timer_info_get_name_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern long (*snd_timer_info_get_resolution_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern size_t (*snd_timer_params_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_timer_params_malloc_dylibloader_wrapper_asound)( snd_timer_params_t**);
+extern void (*snd_timer_params_free_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern void (*snd_timer_params_copy_dylibloader_wrapper_asound)( snd_timer_params_t*,const snd_timer_params_t*);
+extern int (*snd_timer_params_set_auto_start_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+extern int (*snd_timer_params_get_auto_start_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern int (*snd_timer_params_set_exclusive_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+extern int (*snd_timer_params_get_exclusive_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern int (*snd_timer_params_set_early_event_dylibloader_wrapper_asound)( snd_timer_params_t*, int);
+extern int (*snd_timer_params_get_early_event_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern void (*snd_timer_params_set_ticks_dylibloader_wrapper_asound)( snd_timer_params_t*, long);
+extern long (*snd_timer_params_get_ticks_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern void (*snd_timer_params_set_queue_size_dylibloader_wrapper_asound)( snd_timer_params_t*, long);
+extern long (*snd_timer_params_get_queue_size_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern void (*snd_timer_params_set_filter_dylibloader_wrapper_asound)( snd_timer_params_t*, unsigned int);
+extern unsigned int (*snd_timer_params_get_filter_dylibloader_wrapper_asound)( snd_timer_params_t*);
+extern size_t (*snd_timer_status_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_timer_status_malloc_dylibloader_wrapper_asound)( snd_timer_status_t**);
+extern void (*snd_timer_status_free_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern void (*snd_timer_status_copy_dylibloader_wrapper_asound)( snd_timer_status_t*,const snd_timer_status_t*);
+extern snd_htimestamp_t (*snd_timer_status_get_timestamp_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern long (*snd_timer_status_get_resolution_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern long (*snd_timer_status_get_lost_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern long (*snd_timer_status_get_overrun_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern long (*snd_timer_status_get_queue_dylibloader_wrapper_asound)( snd_timer_status_t*);
+extern long (*snd_timer_info_get_ticks_dylibloader_wrapper_asound)( snd_timer_info_t*);
+extern int (*snd_hwdep_open_dylibloader_wrapper_asound)( snd_hwdep_t**,const char*, int);
+extern int (*snd_hwdep_close_dylibloader_wrapper_asound)( snd_hwdep_t*);
+extern int (*snd_hwdep_poll_descriptors_dylibloader_wrapper_asound)( snd_hwdep_t*,struct pollfd*, unsigned int);
+extern int (*snd_hwdep_poll_descriptors_count_dylibloader_wrapper_asound)( snd_hwdep_t*);
+extern int (*snd_hwdep_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_hwdep_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_hwdep_nonblock_dylibloader_wrapper_asound)( snd_hwdep_t*, int);
+extern int (*snd_hwdep_info_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_info_t*);
+extern int (*snd_hwdep_dsp_status_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_dsp_status_t*);
+extern int (*snd_hwdep_dsp_load_dylibloader_wrapper_asound)( snd_hwdep_t*, snd_hwdep_dsp_image_t*);
+extern int (*snd_hwdep_ioctl_dylibloader_wrapper_asound)( snd_hwdep_t*, unsigned int, void*);
+extern ssize_t (*snd_hwdep_write_dylibloader_wrapper_asound)( snd_hwdep_t*,const void*, size_t);
+extern ssize_t (*snd_hwdep_read_dylibloader_wrapper_asound)( snd_hwdep_t*, void*, size_t);
+extern size_t (*snd_hwdep_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_hwdep_info_malloc_dylibloader_wrapper_asound)( snd_hwdep_info_t**);
+extern void (*snd_hwdep_info_free_dylibloader_wrapper_asound)( snd_hwdep_info_t*);
+extern void (*snd_hwdep_info_copy_dylibloader_wrapper_asound)( snd_hwdep_info_t*,const snd_hwdep_info_t*);
+extern unsigned int (*snd_hwdep_info_get_device_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+extern int (*snd_hwdep_info_get_card_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+extern const char* (*snd_hwdep_info_get_id_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+extern const char* (*snd_hwdep_info_get_name_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+extern snd_hwdep_iface_t (*snd_hwdep_info_get_iface_dylibloader_wrapper_asound)(const snd_hwdep_info_t*);
+extern void (*snd_hwdep_info_set_device_dylibloader_wrapper_asound)( snd_hwdep_info_t*, unsigned int);
+extern size_t (*snd_hwdep_dsp_status_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_hwdep_dsp_status_malloc_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t**);
+extern void (*snd_hwdep_dsp_status_free_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t*);
+extern void (*snd_hwdep_dsp_status_copy_dylibloader_wrapper_asound)( snd_hwdep_dsp_status_t*,const snd_hwdep_dsp_status_t*);
+extern unsigned int (*snd_hwdep_dsp_status_get_version_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+extern const char* (*snd_hwdep_dsp_status_get_id_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+extern unsigned int (*snd_hwdep_dsp_status_get_num_dsps_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+extern unsigned int (*snd_hwdep_dsp_status_get_dsp_loaded_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+extern unsigned int (*snd_hwdep_dsp_status_get_chip_ready_dylibloader_wrapper_asound)(const snd_hwdep_dsp_status_t*);
+extern size_t (*snd_hwdep_dsp_image_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_hwdep_dsp_image_malloc_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t**);
+extern void (*snd_hwdep_dsp_image_free_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*);
+extern void (*snd_hwdep_dsp_image_copy_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*,const snd_hwdep_dsp_image_t*);
+extern unsigned int (*snd_hwdep_dsp_image_get_index_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+extern const char* (*snd_hwdep_dsp_image_get_name_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+extern const void* (*snd_hwdep_dsp_image_get_image_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+extern size_t (*snd_hwdep_dsp_image_get_length_dylibloader_wrapper_asound)(const snd_hwdep_dsp_image_t*);
+extern void (*snd_hwdep_dsp_image_set_index_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, unsigned int);
+extern void (*snd_hwdep_dsp_image_set_name_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*,const char*);
+extern void (*snd_hwdep_dsp_image_set_image_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, void*);
+extern void (*snd_hwdep_dsp_image_set_length_dylibloader_wrapper_asound)( snd_hwdep_dsp_image_t*, size_t);
+extern int (*snd_card_load_dylibloader_wrapper_asound)( int);
+extern int (*snd_card_next_dylibloader_wrapper_asound)( int*);
+extern int (*snd_card_get_index_dylibloader_wrapper_asound)(const char*);
+extern int (*snd_card_get_name_dylibloader_wrapper_asound)( int, char**);
+extern int (*snd_card_get_longname_dylibloader_wrapper_asound)( int, char**);
+extern int (*snd_device_name_hint_dylibloader_wrapper_asound)( int,const char*, void***);
+extern int (*snd_device_name_free_hint_dylibloader_wrapper_asound)( void**);
+extern char* (*snd_device_name_get_hint_dylibloader_wrapper_asound)(const void*,const char*);
+extern int (*snd_ctl_open_dylibloader_wrapper_asound)( snd_ctl_t**,const char*, int);
+extern int (*snd_ctl_open_lconf_dylibloader_wrapper_asound)( snd_ctl_t**,const char*, int, snd_config_t*);
+extern int (*snd_ctl_open_fallback_dylibloader_wrapper_asound)( snd_ctl_t**, snd_config_t*,const char*,const char*, int);
+extern int (*snd_ctl_close_dylibloader_wrapper_asound)( snd_ctl_t*);
+extern int (*snd_ctl_nonblock_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+extern int (*snd_async_add_ctl_handler_dylibloader_wrapper_asound)( snd_async_handler_t**, snd_ctl_t*, snd_async_callback_t, void*);
+extern snd_ctl_t* (*snd_async_handler_get_ctl_dylibloader_wrapper_asound)( snd_async_handler_t*);
+extern int (*snd_ctl_poll_descriptors_count_dylibloader_wrapper_asound)( snd_ctl_t*);
+extern int (*snd_ctl_poll_descriptors_dylibloader_wrapper_asound)( snd_ctl_t*,struct pollfd*, unsigned int);
+extern int (*snd_ctl_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_ctl_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_ctl_subscribe_events_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+extern int (*snd_ctl_card_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_card_info_t*);
+extern int (*snd_ctl_elem_list_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_list_t*);
+extern int (*snd_ctl_elem_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_read_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*);
+extern int (*snd_ctl_elem_write_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*);
+extern int (*snd_ctl_elem_lock_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+extern int (*snd_ctl_elem_unlock_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+extern int (*snd_ctl_elem_tlv_read_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int*, unsigned int);
+extern int (*snd_ctl_elem_tlv_write_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*,const unsigned int*);
+extern int (*snd_ctl_elem_tlv_command_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*,const unsigned int*);
+extern int (*snd_ctl_hwdep_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+extern int (*snd_ctl_hwdep_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_hwdep_info_t*);
+extern int (*snd_ctl_pcm_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+extern int (*snd_ctl_pcm_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_pcm_info_t*);
+extern int (*snd_ctl_pcm_prefer_subdevice_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+extern int (*snd_ctl_rawmidi_next_device_dylibloader_wrapper_asound)( snd_ctl_t*, int*);
+extern int (*snd_ctl_rawmidi_info_dylibloader_wrapper_asound)( snd_ctl_t*, snd_rawmidi_info_t*);
+extern int (*snd_ctl_rawmidi_prefer_subdevice_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+extern int (*snd_ctl_set_power_state_dylibloader_wrapper_asound)( snd_ctl_t*, unsigned int);
+extern int (*snd_ctl_get_power_state_dylibloader_wrapper_asound)( snd_ctl_t*, unsigned int*);
+extern int (*snd_ctl_read_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_event_t*);
+extern int (*snd_ctl_wait_dylibloader_wrapper_asound)( snd_ctl_t*, int);
+extern const char* (*snd_ctl_name_dylibloader_wrapper_asound)( snd_ctl_t*);
+extern snd_ctl_type_t (*snd_ctl_type_dylibloader_wrapper_asound)( snd_ctl_t*);
+extern const char* (*snd_ctl_elem_type_name_dylibloader_wrapper_asound)( snd_ctl_elem_type_t);
+extern const char* (*snd_ctl_elem_iface_name_dylibloader_wrapper_asound)( snd_ctl_elem_iface_t);
+extern const char* (*snd_ctl_event_type_name_dylibloader_wrapper_asound)( snd_ctl_event_type_t);
+extern unsigned int (*snd_ctl_event_elem_get_mask_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern unsigned int (*snd_ctl_event_elem_get_numid_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern void (*snd_ctl_event_elem_get_id_dylibloader_wrapper_asound)(const snd_ctl_event_t*, snd_ctl_elem_id_t*);
+extern snd_ctl_elem_iface_t (*snd_ctl_event_elem_get_interface_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern unsigned int (*snd_ctl_event_elem_get_device_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern unsigned int (*snd_ctl_event_elem_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern const char* (*snd_ctl_event_elem_get_name_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern unsigned int (*snd_ctl_event_elem_get_index_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern int (*snd_ctl_elem_list_alloc_space_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*, unsigned int);
+extern void (*snd_ctl_elem_list_free_space_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+extern char* (*snd_ctl_ascii_elem_id_get_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+extern int (*snd_ctl_ascii_elem_id_parse_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const char*);
+extern int (*snd_ctl_ascii_value_parse_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_value_t*, snd_ctl_elem_info_t*,const char*);
+extern size_t (*snd_ctl_elem_id_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_elem_id_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_id_t**);
+extern void (*snd_ctl_elem_id_free_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+extern void (*snd_ctl_elem_id_clear_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*);
+extern void (*snd_ctl_elem_id_copy_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_id_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern snd_ctl_elem_iface_t (*snd_ctl_elem_id_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_id_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_id_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern const char* (*snd_ctl_elem_id_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_id_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_id_t*);
+extern void (*snd_ctl_elem_id_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+extern void (*snd_ctl_elem_id_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, snd_ctl_elem_iface_t);
+extern void (*snd_ctl_elem_id_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+extern void (*snd_ctl_elem_id_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+extern void (*snd_ctl_elem_id_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*,const char*);
+extern void (*snd_ctl_elem_id_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_id_t*, unsigned int);
+extern size_t (*snd_ctl_card_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_card_info_malloc_dylibloader_wrapper_asound)( snd_ctl_card_info_t**);
+extern void (*snd_ctl_card_info_free_dylibloader_wrapper_asound)( snd_ctl_card_info_t*);
+extern void (*snd_ctl_card_info_clear_dylibloader_wrapper_asound)( snd_ctl_card_info_t*);
+extern void (*snd_ctl_card_info_copy_dylibloader_wrapper_asound)( snd_ctl_card_info_t*,const snd_ctl_card_info_t*);
+extern int (*snd_ctl_card_info_get_card_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_id_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_driver_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_name_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_longname_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_mixername_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern const char* (*snd_ctl_card_info_get_components_dylibloader_wrapper_asound)(const snd_ctl_card_info_t*);
+extern size_t (*snd_ctl_event_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_event_malloc_dylibloader_wrapper_asound)( snd_ctl_event_t**);
+extern void (*snd_ctl_event_free_dylibloader_wrapper_asound)( snd_ctl_event_t*);
+extern void (*snd_ctl_event_clear_dylibloader_wrapper_asound)( snd_ctl_event_t*);
+extern void (*snd_ctl_event_copy_dylibloader_wrapper_asound)( snd_ctl_event_t*,const snd_ctl_event_t*);
+extern snd_ctl_event_type_t (*snd_ctl_event_get_type_dylibloader_wrapper_asound)(const snd_ctl_event_t*);
+extern size_t (*snd_ctl_elem_list_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_elem_list_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_list_t**);
+extern void (*snd_ctl_elem_list_free_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+extern void (*snd_ctl_elem_list_clear_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*);
+extern void (*snd_ctl_elem_list_copy_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*,const snd_ctl_elem_list_t*);
+extern void (*snd_ctl_elem_list_set_offset_dylibloader_wrapper_asound)( snd_ctl_elem_list_t*, unsigned int);
+extern unsigned int (*snd_ctl_elem_list_get_used_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*);
+extern unsigned int (*snd_ctl_elem_list_get_count_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*);
+extern void (*snd_ctl_elem_list_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int, snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_list_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern snd_ctl_elem_iface_t (*snd_ctl_elem_list_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern unsigned int (*snd_ctl_elem_list_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern unsigned int (*snd_ctl_elem_list_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern const char* (*snd_ctl_elem_list_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern unsigned int (*snd_ctl_elem_list_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_list_t*, unsigned int);
+extern size_t (*snd_ctl_elem_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_elem_info_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_info_t**);
+extern void (*snd_ctl_elem_info_free_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*);
+extern void (*snd_ctl_elem_info_clear_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*);
+extern void (*snd_ctl_elem_info_copy_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const snd_ctl_elem_info_t*);
+extern snd_ctl_elem_type_t (*snd_ctl_elem_info_get_type_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_readable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_writable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_volatile_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_inactive_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_locked_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_tlv_readable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_tlv_writable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_tlv_commandable_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_owner_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_is_user_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern pid_t (*snd_ctl_elem_info_get_owner_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern unsigned int (*snd_ctl_elem_info_get_count_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long (*snd_ctl_elem_info_get_min_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long (*snd_ctl_elem_info_get_max_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long (*snd_ctl_elem_info_get_step_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long long (*snd_ctl_elem_info_get_min64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long long (*snd_ctl_elem_info_get_max64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern long long (*snd_ctl_elem_info_get_step64_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern unsigned int (*snd_ctl_elem_info_get_items_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern void (*snd_ctl_elem_info_set_item_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+extern const char* (*snd_ctl_elem_info_get_item_name_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_get_dimensions_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern int (*snd_ctl_elem_info_get_dimension_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*, unsigned int);
+extern int (*snd_ctl_elem_info_set_dimension_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const int [4]);
+extern void (*snd_ctl_elem_info_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*, snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_info_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern snd_ctl_elem_iface_t (*snd_ctl_elem_info_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern unsigned int (*snd_ctl_elem_info_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern unsigned int (*snd_ctl_elem_info_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern const char* (*snd_ctl_elem_info_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern unsigned int (*snd_ctl_elem_info_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_info_t*);
+extern void (*snd_ctl_elem_info_set_id_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const snd_ctl_elem_id_t*);
+extern void (*snd_ctl_elem_info_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+extern void (*snd_ctl_elem_info_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, snd_ctl_elem_iface_t);
+extern void (*snd_ctl_elem_info_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+extern void (*snd_ctl_elem_info_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+extern void (*snd_ctl_elem_info_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*,const char*);
+extern void (*snd_ctl_elem_info_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_info_t*, unsigned int);
+extern int (*snd_ctl_add_integer_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, long, long, long);
+extern int (*snd_ctl_add_integer64_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, long long, long long, long long);
+extern int (*snd_ctl_add_boolean_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int);
+extern int (*snd_ctl_add_enumerated_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int, unsigned int,const char* []);
+extern int (*snd_ctl_add_bytes_elem_set_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_info_t*, unsigned int, unsigned int);
+extern int (*snd_ctl_elem_add_integer_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, long, long, long);
+extern int (*snd_ctl_elem_add_integer64_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, long long, long long, long long);
+extern int (*snd_ctl_elem_add_boolean_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int);
+extern int (*snd_ctl_elem_add_enumerated_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, unsigned int, unsigned int,const char* []);
+extern int (*snd_ctl_elem_add_iec958_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*);
+extern int (*snd_ctl_elem_remove_dylibloader_wrapper_asound)( snd_ctl_t*, snd_ctl_elem_id_t*);
+extern size_t (*snd_ctl_elem_value_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_ctl_elem_value_malloc_dylibloader_wrapper_asound)( snd_ctl_elem_value_t**);
+extern void (*snd_ctl_elem_value_free_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*);
+extern void (*snd_ctl_elem_value_clear_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*);
+extern void (*snd_ctl_elem_value_copy_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_value_t*);
+extern int (*snd_ctl_elem_value_compare_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_value_t*);
+extern void (*snd_ctl_elem_value_get_id_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, snd_ctl_elem_id_t*);
+extern unsigned int (*snd_ctl_elem_value_get_numid_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern snd_ctl_elem_iface_t (*snd_ctl_elem_value_get_interface_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern unsigned int (*snd_ctl_elem_value_get_device_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern unsigned int (*snd_ctl_elem_value_get_subdevice_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern const char* (*snd_ctl_elem_value_get_name_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern unsigned int (*snd_ctl_elem_value_get_index_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern void (*snd_ctl_elem_value_set_id_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_ctl_elem_id_t*);
+extern void (*snd_ctl_elem_value_set_numid_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+extern void (*snd_ctl_elem_value_set_interface_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, snd_ctl_elem_iface_t);
+extern void (*snd_ctl_elem_value_set_device_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+extern void (*snd_ctl_elem_value_set_subdevice_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+extern void (*snd_ctl_elem_value_set_name_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const char*);
+extern void (*snd_ctl_elem_value_set_index_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int);
+extern int (*snd_ctl_elem_value_get_boolean_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+extern long (*snd_ctl_elem_value_get_integer_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+extern long long (*snd_ctl_elem_value_get_integer64_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+extern unsigned int (*snd_ctl_elem_value_get_enumerated_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+extern unsigned char (*snd_ctl_elem_value_get_byte_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, unsigned int);
+extern void (*snd_ctl_elem_value_set_boolean_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long);
+extern void (*snd_ctl_elem_value_set_integer_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long);
+extern void (*snd_ctl_elem_value_set_integer64_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, long long);
+extern void (*snd_ctl_elem_value_set_enumerated_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, unsigned int);
+extern void (*snd_ctl_elem_value_set_byte_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, unsigned int, unsigned char);
+extern void (*snd_ctl_elem_set_bytes_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*, void*, size_t);
+extern const void* (*snd_ctl_elem_value_get_bytes_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*);
+extern void (*snd_ctl_elem_value_get_iec958_dylibloader_wrapper_asound)(const snd_ctl_elem_value_t*, snd_aes_iec958_t*);
+extern void (*snd_ctl_elem_value_set_iec958_dylibloader_wrapper_asound)( snd_ctl_elem_value_t*,const snd_aes_iec958_t*);
+extern int (*snd_tlv_parse_dB_info_dylibloader_wrapper_asound)( unsigned int*, unsigned int, unsigned int**);
+extern int (*snd_tlv_get_dB_range_dylibloader_wrapper_asound)( unsigned int*, long, long, long*, long*);
+extern int (*snd_tlv_convert_to_dB_dylibloader_wrapper_asound)( unsigned int*, long, long, long, long*);
+extern int (*snd_tlv_convert_from_dB_dylibloader_wrapper_asound)( unsigned int*, long, long, long, long*, int);
+extern int (*snd_ctl_get_dB_range_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long*, long*);
+extern int (*snd_ctl_convert_to_dB_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long, long*);
+extern int (*snd_ctl_convert_from_dB_dylibloader_wrapper_asound)( snd_ctl_t*,const snd_ctl_elem_id_t*, long, long*, int);
+extern int (*snd_hctl_compare_fast_dylibloader_wrapper_asound)(const snd_hctl_elem_t*,const snd_hctl_elem_t*);
+extern int (*snd_hctl_open_dylibloader_wrapper_asound)( snd_hctl_t**,const char*, int);
+extern int (*snd_hctl_open_ctl_dylibloader_wrapper_asound)( snd_hctl_t**, snd_ctl_t*);
+extern int (*snd_hctl_close_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_nonblock_dylibloader_wrapper_asound)( snd_hctl_t*, int);
+extern int (*snd_hctl_poll_descriptors_count_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_poll_descriptors_dylibloader_wrapper_asound)( snd_hctl_t*,struct pollfd*, unsigned int);
+extern int (*snd_hctl_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_hctl_t*,struct pollfd*, unsigned int, unsigned short*);
+extern unsigned int (*snd_hctl_get_count_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_set_compare_dylibloader_wrapper_asound)( snd_hctl_t*, snd_hctl_compare_t);
+extern snd_hctl_elem_t* (*snd_hctl_first_elem_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern snd_hctl_elem_t* (*snd_hctl_last_elem_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern snd_hctl_elem_t* (*snd_hctl_find_elem_dylibloader_wrapper_asound)( snd_hctl_t*,const snd_ctl_elem_id_t*);
+extern void (*snd_hctl_set_callback_dylibloader_wrapper_asound)( snd_hctl_t*, snd_hctl_callback_t);
+extern void (*snd_hctl_set_callback_private_dylibloader_wrapper_asound)( snd_hctl_t*, void*);
+extern void* (*snd_hctl_get_callback_private_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_load_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_free_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_handle_events_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern const char* (*snd_hctl_name_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern int (*snd_hctl_wait_dylibloader_wrapper_asound)( snd_hctl_t*, int);
+extern snd_ctl_t* (*snd_hctl_ctl_dylibloader_wrapper_asound)( snd_hctl_t*);
+extern snd_hctl_elem_t* (*snd_hctl_elem_next_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+extern snd_hctl_elem_t* (*snd_hctl_elem_prev_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+extern int (*snd_hctl_elem_info_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_info_t*);
+extern int (*snd_hctl_elem_read_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_value_t*);
+extern int (*snd_hctl_elem_write_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_ctl_elem_value_t*);
+extern int (*snd_hctl_elem_tlv_read_dylibloader_wrapper_asound)( snd_hctl_elem_t*, unsigned int*, unsigned int);
+extern int (*snd_hctl_elem_tlv_write_dylibloader_wrapper_asound)( snd_hctl_elem_t*,const unsigned int*);
+extern int (*snd_hctl_elem_tlv_command_dylibloader_wrapper_asound)( snd_hctl_elem_t*,const unsigned int*);
+extern snd_hctl_t* (*snd_hctl_elem_get_hctl_dylibloader_wrapper_asound)( snd_hctl_elem_t*);
+extern void (*snd_hctl_elem_get_id_dylibloader_wrapper_asound)(const snd_hctl_elem_t*, snd_ctl_elem_id_t*);
+extern unsigned int (*snd_hctl_elem_get_numid_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern snd_ctl_elem_iface_t (*snd_hctl_elem_get_interface_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern unsigned int (*snd_hctl_elem_get_device_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern unsigned int (*snd_hctl_elem_get_subdevice_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern const char* (*snd_hctl_elem_get_name_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern unsigned int (*snd_hctl_elem_get_index_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern void (*snd_hctl_elem_set_callback_dylibloader_wrapper_asound)( snd_hctl_elem_t*, snd_hctl_elem_callback_t);
+extern void* (*snd_hctl_elem_get_callback_private_dylibloader_wrapper_asound)(const snd_hctl_elem_t*);
+extern void (*snd_hctl_elem_set_callback_private_dylibloader_wrapper_asound)( snd_hctl_elem_t*, void*);
+extern int (*snd_sctl_build_dylibloader_wrapper_asound)( snd_sctl_t**, snd_ctl_t*, snd_config_t*, snd_config_t*, int);
+extern int (*snd_sctl_free_dylibloader_wrapper_asound)( snd_sctl_t*);
+extern int (*snd_sctl_install_dylibloader_wrapper_asound)( snd_sctl_t*);
+extern int (*snd_sctl_remove_dylibloader_wrapper_asound)( snd_sctl_t*);
+extern int (*snd_mixer_open_dylibloader_wrapper_asound)( snd_mixer_t**, int);
+extern int (*snd_mixer_close_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern snd_mixer_elem_t* (*snd_mixer_first_elem_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern snd_mixer_elem_t* (*snd_mixer_last_elem_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern int (*snd_mixer_handle_events_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern int (*snd_mixer_attach_dylibloader_wrapper_asound)( snd_mixer_t*,const char*);
+extern int (*snd_mixer_attach_hctl_dylibloader_wrapper_asound)( snd_mixer_t*, snd_hctl_t*);
+extern int (*snd_mixer_detach_dylibloader_wrapper_asound)( snd_mixer_t*,const char*);
+extern int (*snd_mixer_detach_hctl_dylibloader_wrapper_asound)( snd_mixer_t*, snd_hctl_t*);
+extern int (*snd_mixer_get_hctl_dylibloader_wrapper_asound)( snd_mixer_t*,const char*, snd_hctl_t**);
+extern int (*snd_mixer_poll_descriptors_count_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern int (*snd_mixer_poll_descriptors_dylibloader_wrapper_asound)( snd_mixer_t*,struct pollfd*, unsigned int);
+extern int (*snd_mixer_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_mixer_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_mixer_load_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern void (*snd_mixer_free_dylibloader_wrapper_asound)( snd_mixer_t*);
+extern int (*snd_mixer_wait_dylibloader_wrapper_asound)( snd_mixer_t*, int);
+extern int (*snd_mixer_set_compare_dylibloader_wrapper_asound)( snd_mixer_t*, snd_mixer_compare_t);
+extern void (*snd_mixer_set_callback_dylibloader_wrapper_asound)( snd_mixer_t*, snd_mixer_callback_t);
+extern void* (*snd_mixer_get_callback_private_dylibloader_wrapper_asound)(const snd_mixer_t*);
+extern void (*snd_mixer_set_callback_private_dylibloader_wrapper_asound)( snd_mixer_t*, void*);
+extern unsigned int (*snd_mixer_get_count_dylibloader_wrapper_asound)(const snd_mixer_t*);
+extern int (*snd_mixer_class_unregister_dylibloader_wrapper_asound)( snd_mixer_class_t*);
+extern snd_mixer_elem_t* (*snd_mixer_elem_next_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern snd_mixer_elem_t* (*snd_mixer_elem_prev_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern void (*snd_mixer_elem_set_callback_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_elem_callback_t);
+extern void* (*snd_mixer_elem_get_callback_private_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+extern void (*snd_mixer_elem_set_callback_private_dylibloader_wrapper_asound)( snd_mixer_elem_t*, void*);
+extern snd_mixer_elem_type_t (*snd_mixer_elem_get_type_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+extern int (*snd_mixer_class_register_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_t*);
+extern int (*snd_mixer_elem_new_dylibloader_wrapper_asound)( snd_mixer_elem_t**, snd_mixer_elem_type_t, int, void*, void*);
+extern int (*snd_mixer_elem_add_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_class_t*);
+extern int (*snd_mixer_elem_remove_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern void (*snd_mixer_elem_free_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_elem_info_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_elem_value_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_elem_attach_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_hctl_elem_t*);
+extern int (*snd_mixer_elem_detach_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_hctl_elem_t*);
+extern int (*snd_mixer_elem_empty_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern void* (*snd_mixer_elem_get_private_dylibloader_wrapper_asound)(const snd_mixer_elem_t*);
+extern size_t (*snd_mixer_class_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_mixer_class_malloc_dylibloader_wrapper_asound)( snd_mixer_class_t**);
+extern void (*snd_mixer_class_free_dylibloader_wrapper_asound)( snd_mixer_class_t*);
+extern void (*snd_mixer_class_copy_dylibloader_wrapper_asound)( snd_mixer_class_t*,const snd_mixer_class_t*);
+extern snd_mixer_t* (*snd_mixer_class_get_mixer_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+extern snd_mixer_event_t (*snd_mixer_class_get_event_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+extern void* (*snd_mixer_class_get_private_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+extern snd_mixer_compare_t (*snd_mixer_class_get_compare_dylibloader_wrapper_asound)(const snd_mixer_class_t*);
+extern int (*snd_mixer_class_set_event_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_event_t);
+extern int (*snd_mixer_class_set_private_dylibloader_wrapper_asound)( snd_mixer_class_t*, void*);
+extern int (*snd_mixer_class_set_private_free_dylibloader_wrapper_asound)( snd_mixer_class_t*, void*);
+extern int (*snd_mixer_class_set_compare_dylibloader_wrapper_asound)( snd_mixer_class_t*, snd_mixer_compare_t);
+extern const char* (*snd_mixer_selem_channel_name_dylibloader_wrapper_asound)( snd_mixer_selem_channel_id_t);
+extern int (*snd_mixer_selem_register_dylibloader_wrapper_asound)( snd_mixer_t*,struct snd_mixer_selem_regopt*, snd_mixer_class_t**);
+extern void (*snd_mixer_selem_get_id_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_id_t*);
+extern const char* (*snd_mixer_selem_get_name_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern unsigned int (*snd_mixer_selem_get_index_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern snd_mixer_elem_t* (*snd_mixer_find_selem_dylibloader_wrapper_asound)( snd_mixer_t*,const snd_mixer_selem_id_t*);
+extern int (*snd_mixer_selem_is_active_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_is_playback_mono_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_playback_channel_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t);
+extern int (*snd_mixer_selem_is_capture_mono_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_channel_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t);
+extern int (*snd_mixer_selem_get_capture_group_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_common_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_playback_volume_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_volume_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_common_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_playback_switch_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_switch_joined_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_has_capture_switch_exclusive_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_ask_playback_vol_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long*);
+extern int (*snd_mixer_selem_ask_capture_vol_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long*);
+extern int (*snd_mixer_selem_ask_playback_dB_vol_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int, long*);
+extern int (*snd_mixer_selem_ask_capture_dB_vol_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int, long*);
+extern int (*snd_mixer_selem_get_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+extern int (*snd_mixer_selem_get_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+extern int (*snd_mixer_selem_get_playback_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+extern int (*snd_mixer_selem_get_capture_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long*);
+extern int (*snd_mixer_selem_get_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int*);
+extern int (*snd_mixer_selem_get_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int*);
+extern int (*snd_mixer_selem_set_playback_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long);
+extern int (*snd_mixer_selem_set_capture_volume_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long);
+extern int (*snd_mixer_selem_set_playback_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long, int);
+extern int (*snd_mixer_selem_set_capture_dB_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, long, int);
+extern int (*snd_mixer_selem_set_playback_volume_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long);
+extern int (*snd_mixer_selem_set_capture_volume_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long);
+extern int (*snd_mixer_selem_set_playback_dB_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int);
+extern int (*snd_mixer_selem_set_capture_dB_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, int);
+extern int (*snd_mixer_selem_set_playback_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int);
+extern int (*snd_mixer_selem_set_capture_switch_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, int);
+extern int (*snd_mixer_selem_set_playback_switch_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, int);
+extern int (*snd_mixer_selem_set_capture_switch_all_dylibloader_wrapper_asound)( snd_mixer_elem_t*, int);
+extern int (*snd_mixer_selem_get_playback_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+extern int (*snd_mixer_selem_get_playback_dB_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+extern int (*snd_mixer_selem_set_playback_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long);
+extern int (*snd_mixer_selem_get_capture_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+extern int (*snd_mixer_selem_get_capture_dB_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long*, long*);
+extern int (*snd_mixer_selem_set_capture_volume_range_dylibloader_wrapper_asound)( snd_mixer_elem_t*, long, long);
+extern int (*snd_mixer_selem_is_enumerated_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_is_enum_playback_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_is_enum_capture_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_get_enum_items_dylibloader_wrapper_asound)( snd_mixer_elem_t*);
+extern int (*snd_mixer_selem_get_enum_item_name_dylibloader_wrapper_asound)( snd_mixer_elem_t*, unsigned int, size_t, char*);
+extern int (*snd_mixer_selem_get_enum_item_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, unsigned int*);
+extern int (*snd_mixer_selem_set_enum_item_dylibloader_wrapper_asound)( snd_mixer_elem_t*, snd_mixer_selem_channel_id_t, unsigned int);
+extern size_t (*snd_mixer_selem_id_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_mixer_selem_id_malloc_dylibloader_wrapper_asound)( snd_mixer_selem_id_t**);
+extern void (*snd_mixer_selem_id_free_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*);
+extern void (*snd_mixer_selem_id_copy_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const snd_mixer_selem_id_t*);
+extern const char* (*snd_mixer_selem_id_get_name_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
+extern unsigned int (*snd_mixer_selem_id_get_index_dylibloader_wrapper_asound)(const snd_mixer_selem_id_t*);
+extern void (*snd_mixer_selem_id_set_name_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
+extern void (*snd_mixer_selem_id_set_index_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*, unsigned int);
+extern int (*snd_mixer_selem_id_parse_dylibloader_wrapper_asound)( snd_mixer_selem_id_t*,const char*);
+extern int (*snd_seq_open_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int);
+extern int (*snd_seq_open_lconf_dylibloader_wrapper_asound)( snd_seq_t**,const char*, int, int, snd_config_t*);
+extern const char* (*snd_seq_name_dylibloader_wrapper_asound)( snd_seq_t*);
+extern snd_seq_type_t (*snd_seq_type_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_close_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_poll_descriptors_count_dylibloader_wrapper_asound)( snd_seq_t*, short);
+extern int (*snd_seq_poll_descriptors_dylibloader_wrapper_asound)( snd_seq_t*,struct pollfd*, unsigned int, short);
+extern int (*snd_seq_poll_descriptors_revents_dylibloader_wrapper_asound)( snd_seq_t*,struct pollfd*, unsigned int, unsigned short*);
+extern int (*snd_seq_nonblock_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_client_id_dylibloader_wrapper_asound)( snd_seq_t*);
+extern size_t (*snd_seq_get_output_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*);
+extern size_t (*snd_seq_get_input_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_set_output_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+extern int (*snd_seq_set_input_buffer_size_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+extern size_t (*snd_seq_system_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_system_info_malloc_dylibloader_wrapper_asound)( snd_seq_system_info_t**);
+extern void (*snd_seq_system_info_free_dylibloader_wrapper_asound)( snd_seq_system_info_t*);
+extern void (*snd_seq_system_info_copy_dylibloader_wrapper_asound)( snd_seq_system_info_t*,const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_queues_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_clients_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_ports_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_channels_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_cur_clients_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_get_cur_queues_dylibloader_wrapper_asound)(const snd_seq_system_info_t*);
+extern int (*snd_seq_system_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_system_info_t*);
+extern size_t (*snd_seq_client_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_client_info_malloc_dylibloader_wrapper_asound)( snd_seq_client_info_t**);
+extern void (*snd_seq_client_info_free_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+extern void (*snd_seq_client_info_copy_dylibloader_wrapper_asound)( snd_seq_client_info_t*,const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_client_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern snd_seq_client_type_t (*snd_seq_client_info_get_type_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern const char* (*snd_seq_client_info_get_name_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_broadcast_filter_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_error_bounce_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_card_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_pid_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern const unsigned char* (*snd_seq_client_info_get_event_filter_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_num_ports_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern int (*snd_seq_client_info_get_event_lost_dylibloader_wrapper_asound)(const snd_seq_client_info_t*);
+extern void (*snd_seq_client_info_set_client_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern void (*snd_seq_client_info_set_name_dylibloader_wrapper_asound)( snd_seq_client_info_t*,const char*);
+extern void (*snd_seq_client_info_set_broadcast_filter_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern void (*snd_seq_client_info_set_error_bounce_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern void (*snd_seq_client_info_set_event_filter_dylibloader_wrapper_asound)( snd_seq_client_info_t*, unsigned char*);
+extern void (*snd_seq_client_info_event_filter_clear_dylibloader_wrapper_asound)( snd_seq_client_info_t*);
+extern void (*snd_seq_client_info_event_filter_add_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern void (*snd_seq_client_info_event_filter_del_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern int (*snd_seq_client_info_event_filter_check_dylibloader_wrapper_asound)( snd_seq_client_info_t*, int);
+extern int (*snd_seq_get_client_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+extern int (*snd_seq_get_any_client_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_client_info_t*);
+extern int (*snd_seq_set_client_info_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+extern int (*snd_seq_query_next_client_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_info_t*);
+extern size_t (*snd_seq_client_pool_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_client_pool_malloc_dylibloader_wrapper_asound)( snd_seq_client_pool_t**);
+extern void (*snd_seq_client_pool_free_dylibloader_wrapper_asound)( snd_seq_client_pool_t*);
+extern void (*snd_seq_client_pool_copy_dylibloader_wrapper_asound)( snd_seq_client_pool_t*,const snd_seq_client_pool_t*);
+extern int (*snd_seq_client_pool_get_client_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern size_t (*snd_seq_client_pool_get_output_pool_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern size_t (*snd_seq_client_pool_get_input_pool_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern size_t (*snd_seq_client_pool_get_output_room_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern size_t (*snd_seq_client_pool_get_output_free_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern size_t (*snd_seq_client_pool_get_input_free_dylibloader_wrapper_asound)(const snd_seq_client_pool_t*);
+extern void (*snd_seq_client_pool_set_output_pool_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+extern void (*snd_seq_client_pool_set_input_pool_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+extern void (*snd_seq_client_pool_set_output_room_dylibloader_wrapper_asound)( snd_seq_client_pool_t*, size_t);
+extern int (*snd_seq_get_client_pool_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_pool_t*);
+extern int (*snd_seq_set_client_pool_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_client_pool_t*);
+extern size_t (*snd_seq_port_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_port_info_malloc_dylibloader_wrapper_asound)( snd_seq_port_info_t**);
+extern void (*snd_seq_port_info_free_dylibloader_wrapper_asound)( snd_seq_port_info_t*);
+extern void (*snd_seq_port_info_copy_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_client_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_port_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern const snd_seq_addr_t* (*snd_seq_port_info_get_addr_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern const char* (*snd_seq_port_info_get_name_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern unsigned int (*snd_seq_port_info_get_capability_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern unsigned int (*snd_seq_port_info_get_type_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_midi_channels_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_midi_voices_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_synth_voices_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_read_use_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_write_use_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_port_specified_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_timestamping_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_timestamp_real_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern int (*snd_seq_port_info_get_timestamp_queue_dylibloader_wrapper_asound)(const snd_seq_port_info_t*);
+extern void (*snd_seq_port_info_set_client_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_port_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_addr_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const snd_seq_addr_t*);
+extern void (*snd_seq_port_info_set_name_dylibloader_wrapper_asound)( snd_seq_port_info_t*,const char*);
+extern void (*snd_seq_port_info_set_capability_dylibloader_wrapper_asound)( snd_seq_port_info_t*, unsigned int);
+extern void (*snd_seq_port_info_set_type_dylibloader_wrapper_asound)( snd_seq_port_info_t*, unsigned int);
+extern void (*snd_seq_port_info_set_midi_channels_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_midi_voices_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_synth_voices_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_port_specified_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_timestamping_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_timestamp_real_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern void (*snd_seq_port_info_set_timestamp_queue_dylibloader_wrapper_asound)( snd_seq_port_info_t*, int);
+extern int (*snd_seq_create_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_info_t*);
+extern int (*snd_seq_delete_port_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_get_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_port_info_t*);
+extern int (*snd_seq_get_any_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, int, snd_seq_port_info_t*);
+extern int (*snd_seq_set_port_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_port_info_t*);
+extern int (*snd_seq_query_next_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_info_t*);
+extern size_t (*snd_seq_port_subscribe_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_port_subscribe_malloc_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t**);
+extern void (*snd_seq_port_subscribe_free_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*);
+extern void (*snd_seq_port_subscribe_copy_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_port_subscribe_t*);
+extern const snd_seq_addr_t* (*snd_seq_port_subscribe_get_sender_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern const snd_seq_addr_t* (*snd_seq_port_subscribe_get_dest_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern int (*snd_seq_port_subscribe_get_queue_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern int (*snd_seq_port_subscribe_get_exclusive_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern int (*snd_seq_port_subscribe_get_time_update_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern int (*snd_seq_port_subscribe_get_time_real_dylibloader_wrapper_asound)(const snd_seq_port_subscribe_t*);
+extern void (*snd_seq_port_subscribe_set_sender_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_addr_t*);
+extern void (*snd_seq_port_subscribe_set_dest_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*,const snd_seq_addr_t*);
+extern void (*snd_seq_port_subscribe_set_queue_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+extern void (*snd_seq_port_subscribe_set_exclusive_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+extern void (*snd_seq_port_subscribe_set_time_update_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+extern void (*snd_seq_port_subscribe_set_time_real_dylibloader_wrapper_asound)( snd_seq_port_subscribe_t*, int);
+extern int (*snd_seq_get_port_subscription_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+extern int (*snd_seq_subscribe_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+extern int (*snd_seq_unsubscribe_port_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_port_subscribe_t*);
+extern size_t (*snd_seq_query_subscribe_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_query_subscribe_malloc_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t**);
+extern void (*snd_seq_query_subscribe_free_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*);
+extern void (*snd_seq_query_subscribe_copy_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*,const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_client_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_port_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern const snd_seq_addr_t* (*snd_seq_query_subscribe_get_root_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern snd_seq_query_subs_type_t (*snd_seq_query_subscribe_get_type_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_index_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_num_subs_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern const snd_seq_addr_t* (*snd_seq_query_subscribe_get_addr_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_queue_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_exclusive_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_time_update_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern int (*snd_seq_query_subscribe_get_time_real_dylibloader_wrapper_asound)(const snd_seq_query_subscribe_t*);
+extern void (*snd_seq_query_subscribe_set_client_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+extern void (*snd_seq_query_subscribe_set_port_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+extern void (*snd_seq_query_subscribe_set_root_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*,const snd_seq_addr_t*);
+extern void (*snd_seq_query_subscribe_set_type_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, snd_seq_query_subs_type_t);
+extern void (*snd_seq_query_subscribe_set_index_dylibloader_wrapper_asound)( snd_seq_query_subscribe_t*, int);
+extern int (*snd_seq_query_port_subscribers_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_query_subscribe_t*);
+extern size_t (*snd_seq_queue_info_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_queue_info_malloc_dylibloader_wrapper_asound)( snd_seq_queue_info_t**);
+extern void (*snd_seq_queue_info_free_dylibloader_wrapper_asound)( snd_seq_queue_info_t*);
+extern void (*snd_seq_queue_info_copy_dylibloader_wrapper_asound)( snd_seq_queue_info_t*,const snd_seq_queue_info_t*);
+extern int (*snd_seq_queue_info_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+extern const char* (*snd_seq_queue_info_get_name_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+extern int (*snd_seq_queue_info_get_owner_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+extern int (*snd_seq_queue_info_get_locked_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+extern unsigned int (*snd_seq_queue_info_get_flags_dylibloader_wrapper_asound)(const snd_seq_queue_info_t*);
+extern void (*snd_seq_queue_info_set_name_dylibloader_wrapper_asound)( snd_seq_queue_info_t*,const char*);
+extern void (*snd_seq_queue_info_set_owner_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, int);
+extern void (*snd_seq_queue_info_set_locked_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, int);
+extern void (*snd_seq_queue_info_set_flags_dylibloader_wrapper_asound)( snd_seq_queue_info_t*, unsigned int);
+extern int (*snd_seq_create_queue_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_queue_info_t*);
+extern int (*snd_seq_alloc_named_queue_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+extern int (*snd_seq_alloc_queue_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_free_queue_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_get_queue_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_info_t*);
+extern int (*snd_seq_set_queue_info_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_info_t*);
+extern int (*snd_seq_query_named_queue_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+extern int (*snd_seq_get_queue_usage_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_set_queue_usage_dylibloader_wrapper_asound)( snd_seq_t*, int, int);
+extern size_t (*snd_seq_queue_status_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_queue_status_malloc_dylibloader_wrapper_asound)( snd_seq_queue_status_t**);
+extern void (*snd_seq_queue_status_free_dylibloader_wrapper_asound)( snd_seq_queue_status_t*);
+extern void (*snd_seq_queue_status_copy_dylibloader_wrapper_asound)( snd_seq_queue_status_t*,const snd_seq_queue_status_t*);
+extern int (*snd_seq_queue_status_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+extern int (*snd_seq_queue_status_get_events_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+extern snd_seq_tick_time_t (*snd_seq_queue_status_get_tick_time_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+extern const snd_seq_real_time_t* (*snd_seq_queue_status_get_real_time_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+extern unsigned int (*snd_seq_queue_status_get_status_dylibloader_wrapper_asound)(const snd_seq_queue_status_t*);
+extern int (*snd_seq_get_queue_status_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_status_t*);
+extern size_t (*snd_seq_queue_tempo_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_queue_tempo_malloc_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t**);
+extern void (*snd_seq_queue_tempo_free_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*);
+extern void (*snd_seq_queue_tempo_copy_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*,const snd_seq_queue_tempo_t*);
+extern int (*snd_seq_queue_tempo_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+extern unsigned int (*snd_seq_queue_tempo_get_tempo_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+extern int (*snd_seq_queue_tempo_get_ppq_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+extern unsigned int (*snd_seq_queue_tempo_get_skew_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+extern unsigned int (*snd_seq_queue_tempo_get_skew_base_dylibloader_wrapper_asound)(const snd_seq_queue_tempo_t*);
+extern void (*snd_seq_queue_tempo_set_tempo_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+extern void (*snd_seq_queue_tempo_set_ppq_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, int);
+extern void (*snd_seq_queue_tempo_set_skew_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+extern void (*snd_seq_queue_tempo_set_skew_base_dylibloader_wrapper_asound)( snd_seq_queue_tempo_t*, unsigned int);
+extern int (*snd_seq_get_queue_tempo_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_tempo_t*);
+extern int (*snd_seq_set_queue_tempo_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_tempo_t*);
+extern size_t (*snd_seq_queue_timer_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_queue_timer_malloc_dylibloader_wrapper_asound)( snd_seq_queue_timer_t**);
+extern void (*snd_seq_queue_timer_free_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*);
+extern void (*snd_seq_queue_timer_copy_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*,const snd_seq_queue_timer_t*);
+extern int (*snd_seq_queue_timer_get_queue_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+extern snd_seq_queue_timer_type_t (*snd_seq_queue_timer_get_type_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+extern const snd_timer_id_t* (*snd_seq_queue_timer_get_id_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+extern unsigned int (*snd_seq_queue_timer_get_resolution_dylibloader_wrapper_asound)(const snd_seq_queue_timer_t*);
+extern void (*snd_seq_queue_timer_set_type_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*, snd_seq_queue_timer_type_t);
+extern void (*snd_seq_queue_timer_set_id_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*,const snd_timer_id_t*);
+extern void (*snd_seq_queue_timer_set_resolution_dylibloader_wrapper_asound)( snd_seq_queue_timer_t*, unsigned int);
+extern int (*snd_seq_get_queue_timer_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_timer_t*);
+extern int (*snd_seq_set_queue_timer_dylibloader_wrapper_asound)( snd_seq_t*, int, snd_seq_queue_timer_t*);
+extern int (*snd_seq_free_event_dylibloader_wrapper_asound)( snd_seq_event_t*);
+extern ssize_t (*snd_seq_event_length_dylibloader_wrapper_asound)( snd_seq_event_t*);
+extern int (*snd_seq_event_output_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+extern int (*snd_seq_event_output_buffer_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+extern int (*snd_seq_event_output_direct_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t*);
+extern int (*snd_seq_event_input_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t**);
+extern int (*snd_seq_event_input_pending_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_drain_output_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_event_output_pending_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_extract_output_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_event_t**);
+extern int (*snd_seq_drop_output_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_drop_output_buffer_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_drop_input_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_drop_input_buffer_dylibloader_wrapper_asound)( snd_seq_t*);
+extern size_t (*snd_seq_remove_events_sizeof_dylibloader_wrapper_asound)( void);
+extern int (*snd_seq_remove_events_malloc_dylibloader_wrapper_asound)( snd_seq_remove_events_t**);
+extern void (*snd_seq_remove_events_free_dylibloader_wrapper_asound)( snd_seq_remove_events_t*);
+extern void (*snd_seq_remove_events_copy_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_remove_events_t*);
+extern unsigned int (*snd_seq_remove_events_get_condition_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern int (*snd_seq_remove_events_get_queue_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern const snd_seq_timestamp_t* (*snd_seq_remove_events_get_time_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern const snd_seq_addr_t* (*snd_seq_remove_events_get_dest_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern int (*snd_seq_remove_events_get_channel_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern int (*snd_seq_remove_events_get_event_type_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern int (*snd_seq_remove_events_get_tag_dylibloader_wrapper_asound)(const snd_seq_remove_events_t*);
+extern void (*snd_seq_remove_events_set_condition_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, unsigned int);
+extern void (*snd_seq_remove_events_set_queue_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+extern void (*snd_seq_remove_events_set_time_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_timestamp_t*);
+extern void (*snd_seq_remove_events_set_dest_dylibloader_wrapper_asound)( snd_seq_remove_events_t*,const snd_seq_addr_t*);
+extern void (*snd_seq_remove_events_set_channel_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+extern void (*snd_seq_remove_events_set_event_type_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+extern void (*snd_seq_remove_events_set_tag_dylibloader_wrapper_asound)( snd_seq_remove_events_t*, int);
+extern int (*snd_seq_remove_events_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_remove_events_t*);
+extern void (*snd_seq_set_bit_dylibloader_wrapper_asound)( int, void*);
+extern void (*snd_seq_unset_bit_dylibloader_wrapper_asound)( int, void*);
+extern int (*snd_seq_change_bit_dylibloader_wrapper_asound)( int, void*);
+extern int (*snd_seq_get_bit_dylibloader_wrapper_asound)( int, void*);
+extern int (*snd_seq_control_queue_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int, snd_seq_event_t*);
+extern int (*snd_seq_create_simple_port_dylibloader_wrapper_asound)( snd_seq_t*,const char*, unsigned int, unsigned int);
+extern int (*snd_seq_delete_simple_port_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_connect_from_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+extern int (*snd_seq_connect_to_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+extern int (*snd_seq_disconnect_from_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+extern int (*snd_seq_disconnect_to_dylibloader_wrapper_asound)( snd_seq_t*, int, int, int);
+extern int (*snd_seq_set_client_name_dylibloader_wrapper_asound)( snd_seq_t*,const char*);
+extern int (*snd_seq_set_client_event_filter_dylibloader_wrapper_asound)( snd_seq_t*, int);
+extern int (*snd_seq_set_client_pool_output_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+extern int (*snd_seq_set_client_pool_output_room_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+extern int (*snd_seq_set_client_pool_input_dylibloader_wrapper_asound)( snd_seq_t*, size_t);
+extern int (*snd_seq_sync_output_queue_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_parse_address_dylibloader_wrapper_asound)( snd_seq_t*, snd_seq_addr_t*,const char*);
+extern int (*snd_seq_reset_pool_output_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_seq_reset_pool_input_dylibloader_wrapper_asound)( snd_seq_t*);
+extern int (*snd_midi_event_new_dylibloader_wrapper_asound)( size_t, snd_midi_event_t**);
+extern int (*snd_midi_event_resize_buffer_dylibloader_wrapper_asound)( snd_midi_event_t*, size_t);
+extern void (*snd_midi_event_free_dylibloader_wrapper_asound)( snd_midi_event_t*);
+extern void (*snd_midi_event_init_dylibloader_wrapper_asound)( snd_midi_event_t*);
+extern void (*snd_midi_event_reset_encode_dylibloader_wrapper_asound)( snd_midi_event_t*);
+extern void (*snd_midi_event_reset_decode_dylibloader_wrapper_asound)( snd_midi_event_t*);
+extern void (*snd_midi_event_no_status_dylibloader_wrapper_asound)( snd_midi_event_t*, int);
+extern long (*snd_midi_event_encode_dylibloader_wrapper_asound)( snd_midi_event_t*,const unsigned char*, long, snd_seq_event_t*);
+extern int (*snd_midi_event_encode_byte_dylibloader_wrapper_asound)( snd_midi_event_t*, int, snd_seq_event_t*);
+extern long (*snd_midi_event_decode_dylibloader_wrapper_asound)( snd_midi_event_t*, unsigned char*, long,const snd_seq_event_t*);
+int initialize_asound(int verbose);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index ea0cba6c52..61475c74e7 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -37,8 +37,14 @@
#include <errno.h>
+#ifdef PULSEAUDIO_ENABLED
+extern "C" {
+extern int initialize_pulse(int verbose);
+}
+#endif
+
Error AudioDriverALSA::init_device() {
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
@@ -104,7 +110,7 @@ Error AudioDriverALSA::init_device() {
// In ALSA the period size seems to be the one that will determine the actual latency
// Ref: https://www.alsa-project.org/main/index.php/FramesPeriods
unsigned int periods = 2;
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
buffer_size = buffer_frames * periods;
period_size = buffer_frames;
@@ -147,6 +153,21 @@ Error AudioDriverALSA::init_device() {
}
Error AudioDriverALSA::init() {
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+#ifdef PULSEAUDIO_ENABLED
+ // On pulse enabled systems Alsa will silently use pulse.
+ // It doesn't matter if this fails as that likely means there is no pulse
+ initialize_pulse(dylibloader_verbose);
+#endif
+
+ if (initialize_asound(dylibloader_verbose)) {
+ return ERR_CANT_OPEN;
+ }
+
active = false;
thread_exited = false;
exit_thread = false;
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index c0233f41e1..ca97e76bc2 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -37,7 +37,7 @@
#include "core/os/thread.h"
#include "servers/audio_server.h"
-#include <alsa/asoundlib.h>
+#include "asound-so_wrap.h"
class AudioDriverALSA : public AudioDriver {
Thread thread;
diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h
index 474f139bd6..c327712ee7 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/midi_driver_alsamidi.h
@@ -38,7 +38,7 @@
#include "core/os/thread.h"
#include "core/templates/vector.h"
-#include <alsa/asoundlib.h>
+#include "../alsa/asound-so_wrap.h"
#include <stdio.h>
class MIDIDriverALSAMidi : public MIDIDriver {
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 6f88107086..4139727422 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -70,7 +70,7 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
Error AudioDriverCoreAudio::init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -97,7 +97,7 @@ Error AudioDriverCoreAudio::init() {
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
UInt32 size = sizeof(strdesc);
result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -116,9 +116,9 @@ Error AudioDriverCoreAudio::init() {
break;
}
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = channels;
@@ -131,7 +131,7 @@ Error AudioDriverCoreAudio::init() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
ERR_FAIL_COND_V(result != noErr, FAILED);
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
@@ -148,7 +148,7 @@ Error AudioDriverCoreAudio::init() {
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::output_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
@@ -157,7 +157,7 @@ Error AudioDriverCoreAudio::init() {
result = AudioUnitInitialize(audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
- if (GLOBAL_GET("audio/enable_audio_input")) {
+ if (GLOBAL_GET("audio/driver/enable_input")) {
return capture_init();
}
return OK;
@@ -173,7 +173,7 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
if (!ad->active || !ad->try_lock()) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
AudioBuffer *abuf = &ioData->mBuffers[i];
- zeromem(abuf->mData, abuf->mDataByteSize);
+ memset(abuf->mData, 0, abuf->mDataByteSize);
};
return 0;
};
@@ -293,7 +293,7 @@ void AudioDriverCoreAudio::finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
@@ -337,7 +337,7 @@ void AudioDriverCoreAudio::finish() {
Error AudioDriverCoreAudio::capture_init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -383,7 +383,7 @@ Error AudioDriverCoreAudio::capture_init() {
#endif
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
size = sizeof(strdesc);
result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -403,9 +403,9 @@ Error AudioDriverCoreAudio::capture_init() {
break;
}
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = capture_channels;
@@ -419,7 +419,7 @@ Error AudioDriverCoreAudio::capture_init() {
ERR_FAIL_COND_V(result != noErr, FAILED);
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::input_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
@@ -436,7 +436,7 @@ void AudioDriverCoreAudio::capture_finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
@@ -506,7 +506,8 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
UInt32 size = 0;
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
- AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
+ AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
+ ERR_FAIL_NULL_V_MSG(audioDevices, list, "Out of memory.");
AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
@@ -515,14 +516,15 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
- AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
+ AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
+ ERR_FAIL_NULL_V_MSG(bufferList, list, "Out of memory.");
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
channelCount += bufferList->mBuffers[j].mNumberChannels;
- free(bufferList);
+ memfree(bufferList);
if (channelCount >= 1) {
CFStringRef cfname;
@@ -534,17 +536,18 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
- char *buffer = (char *)malloc(maxSize);
+ char *buffer = (char *)memalloc(maxSize);
+ ERR_FAIL_NULL_V_MSG(buffer, list, "Out of memory.");
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
// Append the ID to the name in case we have devices with duplicate name
list.push_back(String(buffer) + " (" + itos(audioDevices[i]) + ")");
}
- free(buffer);
+ memfree(buffer);
}
}
- free(audioDevices);
+ memfree(audioDevices);
return list;
}
@@ -561,7 +564,8 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
UInt32 size = 0;
AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
- AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
+ AudioDeviceID *audioDevices = (AudioDeviceID *)memalloc(size);
+ ERR_FAIL_NULL_MSG(audioDevices, "Out of memory.");
AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
@@ -570,14 +574,15 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
- AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
+ AudioBufferList *bufferList = (AudioBufferList *)memalloc(size);
+ ERR_FAIL_NULL_MSG(bufferList, "Out of memory.");
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
channelCount += bufferList->mBuffers[j].mNumberChannels;
- free(bufferList);
+ memfree(bufferList);
if (channelCount >= 1) {
CFStringRef cfname;
@@ -589,7 +594,8 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
- char *buffer = (char *)malloc(maxSize);
+ char *buffer = (char *)memalloc(maxSize);
+ ERR_FAIL_NULL_MSG(buffer, "Out of memory.");
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
String name = String(buffer) + " (" + itos(audioDevices[i]) + ")";
if (name == device) {
@@ -598,11 +604,11 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
}
}
- free(buffer);
+ memfree(buffer);
}
}
- free(audioDevices);
+ memfree(audioDevices);
}
if (!found) {
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 184267734a..64582eb784 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -80,11 +80,11 @@ public:
int sdfgi_get_pending_region_count(RID p_render_buffers) const override { return 0; }
AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); }
uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; }
- void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const Vector<RID> &p_directional_lights, const RID *p_positional_light_instances, uint32_t p_positional_light_count) override {}
/* SKY API */
- RID sky_create() override { return RID(); }
+ RID sky_allocate() override { return RID(); }
+ void sky_initialize(RID p_rid) override {}
void sky_set_radiance_size(RID p_sky, int p_radiance_size) override {}
void sky_set_mode(RID p_sky, RS::SkyMode p_samples) override {}
void sky_set_material(RID p_sky, RID p_material) override {}
@@ -92,8 +92,8 @@ public:
/* ENVIRONMENT API */
- RID environment_create() override { return RID(); }
-
+ RID environment_allocate() override { return RID(); }
+ void environment_initialize(RID p_rid) override {}
void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override {}
void environment_set_sky(RID p_env, RID p_sky) override {}
void environment_set_sky_custom_fov(RID p_env, float p_scale) override {}
@@ -112,7 +112,7 @@ public:
void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override {}
void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {}
- void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {}
+ void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override {}
void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override {}
void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override {}
@@ -123,7 +123,7 @@ public:
void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override {}
void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override {}
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject) override {}
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override {}
void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override {}
void environment_set_volumetric_fog_filter_active(bool p_enable) override {}
@@ -133,8 +133,8 @@ public:
RS::EnvironmentBG environment_get_background(RID p_env) const override { return RS::ENV_BG_KEEP; }
int environment_get_canvas_max_layer(RID p_env) const override { return 0; }
- RID camera_effects_create() override { return RID(); }
-
+ RID camera_effects_allocate() override { return RID(); }
+ void camera_effects_initialize(RID p_rid) override {}
void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override {}
void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override {}
@@ -175,11 +175,8 @@ public:
void gi_probe_set_quality(RS::GIProbeQuality) override {}
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) override {}
- void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) override {}
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {}
void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
- void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) override {}
- void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_lights) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
void set_scene_pass(uint64_t p_pass) override {}
@@ -202,69 +199,54 @@ public:
void update() override {}
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {}
- bool is_low_end() const override { return true; }
-
RasterizerSceneDummy() {}
~RasterizerSceneDummy() {}
};
class RasterizerStorageDummy : public RendererStorage {
public:
+ bool can_create_resources_async() const override { return false; }
+
/* TEXTURE API */
struct DummyTexture {
- int width = 0;
- int height = 0;
- uint32_t flags = 0;
- Image::Format format = Image::Format::FORMAT_MAX;
Ref<Image> image;
- String path;
- };
-
- struct DummySurface {
- uint32_t format = 0;
- RS::PrimitiveType primitive = RS::PrimitiveType::PRIMITIVE_MAX;
- Vector<uint8_t> array;
- int vertex_count = 0;
- Vector<uint8_t> index_array;
- int index_count = 0;
- AABB aabb;
- Vector<Vector<uint8_t>> blend_shapes;
- Vector<AABB> bone_aabbs;
- };
-
- struct DummyMesh {
- Vector<DummySurface> surfaces;
- int blend_shape_count = 0;
- RS::BlendShapeMode blend_shape_mode = RS::BlendShapeMode::BLEND_SHAPE_MODE_NORMALIZED;
};
-
mutable RID_PtrOwner<DummyTexture> texture_owner;
- mutable RID_PtrOwner<DummyMesh> mesh_owner;
- RID texture_2d_create(const Ref<Image> &p_image) override { return RID(); }
- RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override { return RID(); }
- RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override { return RID(); }
- RID texture_proxy_create(RID p_base) override { return RID(); }
+ RID texture_allocate() override {
+ DummyTexture *texture = memnew(DummyTexture);
+ ERR_FAIL_COND_V(!texture, RID());
+ return texture_owner.make_rid(texture);
+ }
+ void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override {
+ DummyTexture *t = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!t);
+ t->image = p_image->duplicate();
+ }
+ void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {}
void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {}
void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {}
+ void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override {}
void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override {}
+ void texture_proxy_initialize(RID p_texture, RID p_base) override {}
void texture_proxy_update(RID p_proxy, RID p_base) override {}
- RID texture_2d_placeholder_create() override { return RID(); }
- RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) override { return RID(); }
- RID texture_3d_placeholder_create() override { return RID(); }
+ void texture_2d_placeholder_initialize(RID p_texture) override {}
+ void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override {}
+ void texture_3d_placeholder_initialize(RID p_texture) override {}
+
+ Ref<Image> texture_2d_get(RID p_texture) const override {
+ DummyTexture *t = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND_V(!t, Ref<Image>());
+ return t->image;
+ }
- Ref<Image> texture_2d_get(RID p_texture) const override { return Ref<Image>(); }
Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); }
Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); }
void texture_replace(RID p_texture, RID p_by_texture) override {}
void texture_set_size_override(RID p_texture, int p_width, int p_height) override {}
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- void texture_bind(RID p_texture, uint32_t p_texture_no) = 0;
-#endif
void texture_set_path(RID p_texture, const String &p_path) override {}
String texture_get_path(RID p_texture) const override { return String(); }
@@ -282,113 +264,18 @@ public:
/* CANVAS TEXTURE API */
- RID canvas_texture_create() override { return RID(); }
+ RID canvas_texture_allocate() override { return RID(); }
+ void canvas_texture_initialize(RID p_rid) override {}
void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override {}
void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override {}
void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override {}
void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override {}
-#if 0
- RID texture_create() override {
- DummyTexture *texture = memnew(DummyTexture);
- ERR_FAIL_COND_V(!texture, RID());
- return texture_owner.make_rid(texture);
- }
-
- void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingServer::TextureType p_type = RS::TEXTURE_TYPE_2D, uint32_t p_flags = RS::TEXTURE_FLAGS_DEFAULT) override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!t);
- t->width = p_width;
- t->height = p_height;
- t->flags = p_flags;
- t->format = p_format;
- t->image = Ref<Image>(memnew(Image));
- t->image->create(p_width, p_height, false, p_format);
- }
- void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!t);
- t->width = p_image->get_width();
- t->height = p_image->get_height();
- t->format = p_image->get_format();
- t->image->create(t->width, t->height, false, t->format, p_image->get_data());
- }
-
- void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) override {
- DummyTexture *t = texture_owner.getornull(p_texture);
-
- ERR_FAIL_COND(!t);
- ERR_FAIL_COND_MSG(p_image.is_null(), "It's not a reference to a valid Image object.");
- ERR_FAIL_COND(t->format != p_image->get_format());
- ERR_FAIL_COND(src_w <= 0 || src_h <= 0);
- ERR_FAIL_COND(src_x < 0 || src_y < 0 || src_x + src_w > p_image->get_width() || src_y + src_h > p_image->get_height());
- ERR_FAIL_COND(dst_x < 0 || dst_y < 0 || dst_x + src_w > t->width || dst_y + src_h > t->height);
-
- t->image->blit_rect(p_image, Rect2(src_x, src_y, src_w, src_h), Vector2(dst_x, dst_y));
- }
-
- Ref<Image> texture_get_data(RID p_texture, int p_level) const override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!t, Ref<Image>());
- return t->image;
- }
- void texture_set_flags(RID p_texture, uint32_t p_flags) override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!t);
- t->flags = p_flags;
- }
- uint32_t texture_get_flags(RID p_texture) const override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!t, 0);
- return t->flags;
- }
- Image::Format texture_get_format(RID p_texture) const override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!t, Image::FORMAT_RGB8);
- return t->format;
- }
-
- RenderingServer::TextureType texture_get_type(RID p_texture) const override { return RS::TEXTURE_TYPE_2D; }
- uint32_t texture_get_texid(RID p_texture) const override { return 0; }
- uint32_t texture_get_width(RID p_texture) const override { return 0; }
- uint32_t texture_get_height(RID p_texture) const override { return 0; }
- uint32_t texture_get_depth(RID p_texture) const override { return 0; }
- void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) override {}
- void texture_bind(RID p_texture, uint32_t p_texture_no) override {}
-
- void texture_set_path(RID p_texture, const String &p_path) override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!t);
- t->path = p_path;
- }
- String texture_get_path(RID p_texture) const override {
- DummyTexture *t = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!t, String());
- return t->path;
- }
-
- void texture_set_shrink_all_x2_on_set_data(bool p_enable) override {}
-
- void texture_debug_usage(List<RS::TextureInfo> *r_info) override {}
-
- RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const override { return RID(); }
-
- void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {}
- void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {}
- void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) override {}
-
- void textures_keep_original(bool p_enable) override {}
-
- void texture_set_proxy(RID p_proxy, RID p_base) override {}
- Size2 texture_size_with_proxy(RID p_texture) const override { return Size2(); }
- void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override {}
-#endif
-
/* SHADER API */
- RID shader_create() override { return RID(); }
-
+ RID shader_allocate() override { return RID(); }
+ void shader_initialize(RID p_rid) override {}
void shader_set_code(RID p_shader, const String &p_code) override {}
String shader_get_code(RID p_shader) const override { return ""; }
void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
@@ -401,8 +288,8 @@ public:
/* COMMON MATERIAL API */
- RID material_create() override { return RID(); }
-
+ RID material_allocate() override { return RID(); }
+ void material_initialize(RID p_rid) override {}
void material_set_render_priority(RID p_material, int priority) override {}
void material_set_shader(RID p_shader_material, RID p_shader) override {}
@@ -418,14 +305,8 @@ public:
/* MESH API */
- RID mesh_create() override {
- DummyMesh *mesh = memnew(DummyMesh);
- ERR_FAIL_COND_V(!mesh, RID());
- mesh->blend_shape_count = 0;
- mesh->blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
- return mesh_owner.make_rid(mesh);
- }
-
+ RID mesh_allocate() override { return RID(); }
+ void mesh_initialize(RID p_rid) override {}
void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
RID mesh_instance_create(RID p_base) override { return RID(); }
@@ -438,127 +319,18 @@ public:
void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
-#if 0
- void mesh_add_surface(RID p_mesh, uint32_t p_format, RS::PrimitiveType p_primitive, const Vector<uint8_t> &p_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<Vector<uint8_t> > &p_blend_shapes = Vector<Vector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()) override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!m);
-
- m->surfaces.push_back(DummySurface());
- DummySurface *s = &m->surfaces.write[m->surfaces.size() - 1];
- s->format = p_format;
- s->primitive = p_primitive;
- s->array = p_array;
- s->vertex_count = p_vertex_count;
- s->index_array = p_index_array;
- s->index_count = p_index_count;
- s->aabb = p_aabb;
- s->blend_shapes = p_blend_shapes;
- s->bone_aabbs = p_bone_aabbs;
- }
-
- void mesh_set_blend_shape_count(RID p_mesh, int p_amount) override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!m);
- m->blend_shape_count = p_amount;
- }
-#endif
+ int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
- int mesh_get_blend_shape_count(RID p_mesh) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, 0);
- return m->blend_shape_count;
- }
-
- void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!m);
- m->blend_shape_mode = p_mode;
- }
- RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, RS::BLEND_SHAPE_MODE_NORMALIZED);
- return m->blend_shape_mode;
- }
+ void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {}
+ RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; }
void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
-#if 0
- int mesh_surface_get_array_len(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, 0);
-
- return m->surfaces[p_surface].vertex_count;
- }
- int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, 0);
-
- return m->surfaces[p_surface].index_count;
- }
-
- Vector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, Vector<uint8_t>());
-
- return m->surfaces[p_surface].array;
- }
- Vector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, Vector<uint8_t>());
-
- return m->surfaces[p_surface].index_array;
- }
-
- uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, 0);
-
- return m->surfaces[p_surface].format;
- }
- RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, RS::PRIMITIVE_POINTS);
-
- return m->surfaces[p_surface].primitive;
- }
-
- AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, AABB());
-
- return m->surfaces[p_surface].aabb;
- }
- Vector<Vector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, Vector<Vector<uint8_t> >());
-
- return m->surfaces[p_surface].blend_shapes;
- }
- Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, Vector<AABB>());
-
- return m->surfaces[p_surface].bone_aabbs;
- }
-
- void mesh_remove_surface(RID p_mesh, int p_index) override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!m);
- ERR_FAIL_COND(p_index >= m->surfaces.size());
-
- m->surfaces.remove(p_index);
- }
-#endif
-
RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); }
- int mesh_get_surface_count(RID p_mesh) const override {
- DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, 0);
- return m->surfaces.size();
- }
+ int mesh_get_surface_count(RID p_mesh) const override { return 0; }
void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
@@ -569,9 +341,9 @@ public:
/* MULTIMESH API */
- RID multimesh_create() override { return RID(); }
-
- void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
+ RID multimesh_allocate() override { return RID(); }
+ void multimesh_initialize(RID p_rid) override {}
+ void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override {}
int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
@@ -595,7 +367,8 @@ public:
/* IMMEDIATE API */
- RID immediate_create() override { return RID(); }
+ RID immediate_allocate() override { return RID(); }
+ void immediate_initialize(RID p_rid) override {}
void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) override {}
void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) override {}
void immediate_normal(RID p_immediate, const Vector3 &p_normal) override {}
@@ -611,8 +384,9 @@ public:
/* SKELETON API */
- RID skeleton_create() override { return RID(); }
- void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
+ RID skeleton_allocate() override { return RID(); }
+ void skeleton_initialize(RID p_rid) override {}
+ void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) override {}
@@ -622,7 +396,14 @@ public:
/* Light API */
- RID light_create(RS::LightType p_type) override { return RID(); }
+ RID directional_light_allocate() override { return RID(); }
+ void directional_light_initialize(RID p_rid) override {}
+ RID omni_light_allocate() override { return RID(); }
+ void omni_light_initialize(RID p_rid) override {}
+ RID spot_light_allocate() override { return RID(); }
+ void spot_light_initialize(RID p_rid) override {}
+ RID reflection_probe_allocate() override { return RID(); }
+ void reflection_probe_initialize(RID p_rid) override {}
void light_set_color(RID p_light, const Color &p_color) override {}
void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override {}
@@ -660,8 +441,6 @@ public:
/* PROBE API */
- RID reflection_probe_create() override { return RID(); }
-
void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override {}
void reflection_probe_set_intensity(RID p_probe, float p_intensity) override {}
void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override {}
@@ -689,7 +468,8 @@ public:
/* DECAL API */
- RID decal_create() override { return RID(); }
+ RID decal_allocate() override { return RID(); }
+ void decal_initialize(RID p_rid) override {}
void decal_set_extents(RID p_decal, const Vector3 &p_extents) override {}
void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override {}
void decal_set_emission_energy(RID p_decal, float p_energy) override {}
@@ -704,9 +484,9 @@ public:
/* GI PROBE API */
- RID gi_probe_create() override { return RID(); }
-
- void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {}
+ RID gi_probe_allocate() override { return RID(); }
+ void gi_probe_initialize(RID p_rid) override {}
+ void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {}
AABB gi_probe_get_bounds(RID p_gi_probe) const override { return AABB(); }
Vector3i gi_probe_get_octree_size(RID p_gi_probe) const override { return Vector3i(); }
@@ -750,72 +530,8 @@ public:
uint32_t gi_probe_get_version(RID p_gi_probe) override { return 0; }
/* LIGHTMAP CAPTURE */
-#if 0
- struct Instantiable {
- SelfList<RendererSceneRender::GeometryInstance>::List instance_list;
-
- _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) override {
- SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first();
- while (instances) override {
- //instances->self()->base_changed(p_aabb, p_materials);
- instances = instances->next();
- }
- }
-
- _FORCE_INLINE_ void instance_remove_deps() override {
- SelfList<RendererSceneRender::GeometryInstance> *instances = instance_list.first();
- while (instances) override {
- SelfList<RendererSceneRender::GeometryInstance> *next = instances->next();
- //instances->self()->base_removed();
- instances = next;
- }
- }
-
- Instantiable() override {}
- ~Instantiable() override {
- }
- };
-
- struct LightmapCapture : public Instantiable {
- Vector<LightmapCaptureOctree> octree;
- AABB bounds;
- Transform cell_xform;
- int cell_subdiv;
- float energy;
- LightmapCapture() override {
- energy = 1.0;
- cell_subdiv = 1;
- }
- };
-
- mutable RID_PtrOwner<LightmapCapture> lightmap_capture_data_owner;
- void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) override {}
- AABB lightmap_capture_get_bounds(RID p_capture) const override { return AABB(); }
- void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) override {}
- RID lightmap_capture_create() override {
- LightmapCapture *capture = memnew(LightmapCapture);
- return lightmap_capture_data_owner.make_rid(capture);
- }
- Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const override {
- const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, Vector<uint8_t>());
- return Vector<uint8_t>();
- }
- void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) override {}
- Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const override { return Transform(); }
- void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) override {}
- int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const override { return 0; }
- void lightmap_capture_set_energy(RID p_capture, float p_energy) override {}
- float lightmap_capture_get_energy(RID p_capture) const override { return 0.0; }
- const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const override {
- const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, nullptr);
- return &capture->octree;
- }
-#endif
-
- RID lightmap_create() override { return RID(); }
-
+ RID lightmap_allocate() override { return RID(); }
+ void lightmap_initialize(RID p_rid) override {}
void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override {}
void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override {}
void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override {}
@@ -830,10 +546,14 @@ public:
void lightmap_set_probe_capture_update_speed(float p_speed) override {}
float lightmap_get_probe_capture_update_speed() const override { return 0; }
- /* PARTICLES */
+ /* OCCLUDER */
- RID particles_create() override { return RID(); }
+ void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {}
+ /* PARTICLES */
+
+ RID particles_allocate() override { return RID(); }
+ void particles_initialize(RID p_rid) override {}
void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
void particles_set_emitting(RID p_particles, bool p_emitting) override {}
void particles_set_amount(RID p_particles, int p_amount) override {}
@@ -875,7 +595,8 @@ public:
/* PARTICLES COLLISION */
- RID particles_collision_create() override { return RID(); }
+ RID particles_collision_allocate() override { return RID(); }
+ void particles_collision_initialize(RID p_rid) override {}
void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override {}
void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override {}
void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) override {}
@@ -934,14 +655,7 @@ public:
void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {}
Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
- RS::InstanceType get_base_type(RID p_rid) const override {
- if (mesh_owner.owns(p_rid)) {
- return RS::INSTANCE_MESH;
- }
-
- return RS::INSTANCE_NONE;
- }
-
+ RS::InstanceType get_base_type(RID p_rid) const override { return RS::INSTANCE_NONE; }
bool free(RID p_rid) override {
if (texture_owner.owns(p_rid)) {
// delete the texture
@@ -949,13 +663,6 @@ public:
texture_owner.free(p_rid);
memdelete(texture);
}
-
- if (mesh_owner.owns(p_rid)) {
- // delete the mesh
- DummyMesh *mesh = mesh_owner.getornull(p_rid);
- mesh_owner.free(p_rid);
- memdelete(mesh);
- }
return true;
}
@@ -969,7 +676,7 @@ public:
void render_info_end_capture() override {}
int get_captured_render_info(RS::RenderInfo p_info) override { return 0; }
- int get_render_info(RS::RenderInfo p_info) override { return 0; }
+ uint64_t get_render_info(RS::RenderInfo p_info) override { return 0; }
String get_video_adapter_name() const override { return String(); }
String get_video_adapter_vendor() const override { return String(); }
diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp
index 2484e6d140..f148e42845 100644
--- a/drivers/dummy/texture_loader_dummy.cpp
+++ b/drivers/dummy/texture_loader_dummy.cpp
@@ -35,7 +35,7 @@
#include <string.h>
-RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatDummyTexture::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) {
unsigned int width = 8;
unsigned int height = 8;
diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h
index 3b71b5824f..00e6b9cc53 100644
--- a/drivers/dummy/texture_loader_dummy.h
+++ b/drivers/dummy/texture_loader_dummy.h
@@ -36,7 +36,7 @@
class ResourceFormatDummyTexture : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 854c6706e6..ded6bbc53e 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -88,7 +88,7 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
{
// must be closed before call to image_to_png
uint8_t *writer = out_buffer.ptrw();
- copymem(writer, "PNG ", 4);
+ memcpy(writer, "PNG ", 4);
}
Error err = PNGDriverCommon::image_to_png(p_image, out_buffer);
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index 9e848a2253..412e17c6b7 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -60,7 +60,7 @@ static bool check_error(const png_image &image) {
Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) {
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
// fetch image properties
@@ -134,7 +134,7 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(source_image->is_compressed(), FAILED);
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
png_img.width = source_image->get_width();
png_img.height = source_image->get_height();
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index f47fc403cc..b737a287d1 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -41,7 +41,7 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32
ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG.");
ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as PNG.");
- Ref<Image> img = texture->get_data();
+ Ref<Image> img = texture->get_image();
Error err = save_image(p_path, img);
diff --git a/drivers/pulseaudio/SCsub b/drivers/pulseaudio/SCsub
index 91e1140b75..467d1448dc 100644
--- a/drivers/pulseaudio/SCsub
+++ b/drivers/pulseaudio/SCsub
@@ -2,4 +2,7 @@
Import("env")
+if "pulseaudio" in env and env["pulseaudio"]:
+ env.add_source_files(env.drivers_sources, "pulse-so_wrap.c")
+
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index a5092c8c5c..5e87bc019b 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -179,7 +179,7 @@ Error AudioDriverPulseAudio::init_device() {
break;
}
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
pa_buffer_size = buffer_frames * pa_map.channels;
@@ -233,11 +233,20 @@ Error AudioDriverPulseAudio::init_device() {
}
Error AudioDriverPulseAudio::init() {
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+ if (initialize_pulse(dylibloader_verbose)) {
+ return ERR_CANT_OPEN;
+ }
+
active = false;
thread_exited = false;
exit_thread = false;
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
pa_ml = pa_mainloop_new();
ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN);
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index 2ddf8d2592..fa9b573d94 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -37,7 +37,7 @@
#include "core/os/thread.h"
#include "servers/audio_server.h"
-#include <pulse/pulseaudio.h>
+#include "pulse-so_wrap.h"
class AudioDriverPulseAudio : public AudioDriver {
Thread thread;
diff --git a/drivers/pulseaudio/pulse-so_wrap.c b/drivers/pulseaudio/pulse-so_wrap.c
new file mode 100644
index 0000000000..12bdcc704e
--- /dev/null
+++ b/drivers/pulseaudio/pulse-so_wrap.c
@@ -0,0 +1,3950 @@
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:31
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/pulse/pulseaudio.h --sys-include <pulse/pulseaudio.h> --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header pulse-so_wrap.h --output-implementation pulse-so_wrap.c
+//
+#include <stdint.h>
+
+#define pa_get_library_version pa_get_library_version_dylibloader_orig_pulse
+#define pa_bytes_per_second pa_bytes_per_second_dylibloader_orig_pulse
+#define pa_frame_size pa_frame_size_dylibloader_orig_pulse
+#define pa_sample_size pa_sample_size_dylibloader_orig_pulse
+#define pa_sample_size_of_format pa_sample_size_of_format_dylibloader_orig_pulse
+#define pa_bytes_to_usec pa_bytes_to_usec_dylibloader_orig_pulse
+#define pa_usec_to_bytes pa_usec_to_bytes_dylibloader_orig_pulse
+#define pa_sample_spec_init pa_sample_spec_init_dylibloader_orig_pulse
+#define pa_sample_format_valid pa_sample_format_valid_dylibloader_orig_pulse
+#define pa_sample_rate_valid pa_sample_rate_valid_dylibloader_orig_pulse
+#define pa_channels_valid pa_channels_valid_dylibloader_orig_pulse
+#define pa_sample_spec_valid pa_sample_spec_valid_dylibloader_orig_pulse
+#define pa_sample_spec_equal pa_sample_spec_equal_dylibloader_orig_pulse
+#define pa_sample_format_to_string pa_sample_format_to_string_dylibloader_orig_pulse
+#define pa_parse_sample_format pa_parse_sample_format_dylibloader_orig_pulse
+#define pa_sample_spec_snprint pa_sample_spec_snprint_dylibloader_orig_pulse
+#define pa_bytes_snprint pa_bytes_snprint_dylibloader_orig_pulse
+#define pa_sample_format_is_le pa_sample_format_is_le_dylibloader_orig_pulse
+#define pa_sample_format_is_be pa_sample_format_is_be_dylibloader_orig_pulse
+#define pa_direction_valid pa_direction_valid_dylibloader_orig_pulse
+#define pa_direction_to_string pa_direction_to_string_dylibloader_orig_pulse
+#define pa_mainloop_api_once pa_mainloop_api_once_dylibloader_orig_pulse
+#define pa_proplist_new pa_proplist_new_dylibloader_orig_pulse
+#define pa_proplist_free pa_proplist_free_dylibloader_orig_pulse
+#define pa_proplist_key_valid pa_proplist_key_valid_dylibloader_orig_pulse
+#define pa_proplist_sets pa_proplist_sets_dylibloader_orig_pulse
+#define pa_proplist_setp pa_proplist_setp_dylibloader_orig_pulse
+#define pa_proplist_setf pa_proplist_setf_dylibloader_orig_pulse
+#define pa_proplist_set pa_proplist_set_dylibloader_orig_pulse
+#define pa_proplist_gets pa_proplist_gets_dylibloader_orig_pulse
+#define pa_proplist_get pa_proplist_get_dylibloader_orig_pulse
+#define pa_proplist_update pa_proplist_update_dylibloader_orig_pulse
+#define pa_proplist_unset pa_proplist_unset_dylibloader_orig_pulse
+#define pa_proplist_unset_many pa_proplist_unset_many_dylibloader_orig_pulse
+#define pa_proplist_iterate pa_proplist_iterate_dylibloader_orig_pulse
+#define pa_proplist_to_string pa_proplist_to_string_dylibloader_orig_pulse
+#define pa_proplist_to_string_sep pa_proplist_to_string_sep_dylibloader_orig_pulse
+#define pa_proplist_from_string pa_proplist_from_string_dylibloader_orig_pulse
+#define pa_proplist_contains pa_proplist_contains_dylibloader_orig_pulse
+#define pa_proplist_clear pa_proplist_clear_dylibloader_orig_pulse
+#define pa_proplist_copy pa_proplist_copy_dylibloader_orig_pulse
+#define pa_proplist_size pa_proplist_size_dylibloader_orig_pulse
+#define pa_proplist_isempty pa_proplist_isempty_dylibloader_orig_pulse
+#define pa_proplist_equal pa_proplist_equal_dylibloader_orig_pulse
+#define pa_channel_map_init pa_channel_map_init_dylibloader_orig_pulse
+#define pa_channel_map_init_mono pa_channel_map_init_mono_dylibloader_orig_pulse
+#define pa_channel_map_init_stereo pa_channel_map_init_stereo_dylibloader_orig_pulse
+#define pa_channel_map_init_auto pa_channel_map_init_auto_dylibloader_orig_pulse
+#define pa_channel_map_init_extend pa_channel_map_init_extend_dylibloader_orig_pulse
+#define pa_channel_position_to_string pa_channel_position_to_string_dylibloader_orig_pulse
+#define pa_channel_position_from_string pa_channel_position_from_string_dylibloader_orig_pulse
+#define pa_channel_position_to_pretty_string pa_channel_position_to_pretty_string_dylibloader_orig_pulse
+#define pa_channel_map_snprint pa_channel_map_snprint_dylibloader_orig_pulse
+#define pa_channel_map_parse pa_channel_map_parse_dylibloader_orig_pulse
+#define pa_channel_map_equal pa_channel_map_equal_dylibloader_orig_pulse
+#define pa_channel_map_valid pa_channel_map_valid_dylibloader_orig_pulse
+#define pa_channel_map_compatible pa_channel_map_compatible_dylibloader_orig_pulse
+#define pa_channel_map_superset pa_channel_map_superset_dylibloader_orig_pulse
+#define pa_channel_map_can_balance pa_channel_map_can_balance_dylibloader_orig_pulse
+#define pa_channel_map_can_fade pa_channel_map_can_fade_dylibloader_orig_pulse
+#define pa_channel_map_can_lfe_balance pa_channel_map_can_lfe_balance_dylibloader_orig_pulse
+#define pa_channel_map_to_name pa_channel_map_to_name_dylibloader_orig_pulse
+#define pa_channel_map_to_pretty_name pa_channel_map_to_pretty_name_dylibloader_orig_pulse
+#define pa_channel_map_has_position pa_channel_map_has_position_dylibloader_orig_pulse
+#define pa_channel_map_mask pa_channel_map_mask_dylibloader_orig_pulse
+#define pa_encoding_to_string pa_encoding_to_string_dylibloader_orig_pulse
+#define pa_encoding_from_string pa_encoding_from_string_dylibloader_orig_pulse
+#define pa_format_info_new pa_format_info_new_dylibloader_orig_pulse
+#define pa_format_info_copy pa_format_info_copy_dylibloader_orig_pulse
+#define pa_format_info_free pa_format_info_free_dylibloader_orig_pulse
+#define pa_format_info_valid pa_format_info_valid_dylibloader_orig_pulse
+#define pa_format_info_is_pcm pa_format_info_is_pcm_dylibloader_orig_pulse
+#define pa_format_info_is_compatible pa_format_info_is_compatible_dylibloader_orig_pulse
+#define pa_format_info_snprint pa_format_info_snprint_dylibloader_orig_pulse
+#define pa_format_info_from_string pa_format_info_from_string_dylibloader_orig_pulse
+#define pa_format_info_from_sample_spec pa_format_info_from_sample_spec_dylibloader_orig_pulse
+#define pa_format_info_to_sample_spec pa_format_info_to_sample_spec_dylibloader_orig_pulse
+#define pa_format_info_get_prop_type pa_format_info_get_prop_type_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int pa_format_info_get_prop_int_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int_range pa_format_info_get_prop_int_range_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int_array pa_format_info_get_prop_int_array_dylibloader_orig_pulse
+#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_orig_pulse
+#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_orig_pulse
+#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_orig_pulse
+#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_orig_pulse
+#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_orig_pulse
+#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_orig_pulse
+#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_orig_pulse
+#define pa_format_info_set_prop_string pa_format_info_set_prop_string_dylibloader_orig_pulse
+#define pa_format_info_set_prop_string_array pa_format_info_set_prop_string_array_dylibloader_orig_pulse
+#define pa_format_info_set_sample_format pa_format_info_set_sample_format_dylibloader_orig_pulse
+#define pa_format_info_set_rate pa_format_info_set_rate_dylibloader_orig_pulse
+#define pa_format_info_set_channels pa_format_info_set_channels_dylibloader_orig_pulse
+#define pa_format_info_set_channel_map pa_format_info_set_channel_map_dylibloader_orig_pulse
+#define pa_operation_ref pa_operation_ref_dylibloader_orig_pulse
+#define pa_operation_unref pa_operation_unref_dylibloader_orig_pulse
+#define pa_operation_cancel pa_operation_cancel_dylibloader_orig_pulse
+#define pa_operation_get_state pa_operation_get_state_dylibloader_orig_pulse
+#define pa_operation_set_state_callback pa_operation_set_state_callback_dylibloader_orig_pulse
+#define pa_context_new pa_context_new_dylibloader_orig_pulse
+#define pa_context_new_with_proplist pa_context_new_with_proplist_dylibloader_orig_pulse
+#define pa_context_unref pa_context_unref_dylibloader_orig_pulse
+#define pa_context_ref pa_context_ref_dylibloader_orig_pulse
+#define pa_context_set_state_callback pa_context_set_state_callback_dylibloader_orig_pulse
+#define pa_context_set_event_callback pa_context_set_event_callback_dylibloader_orig_pulse
+#define pa_context_errno pa_context_errno_dylibloader_orig_pulse
+#define pa_context_is_pending pa_context_is_pending_dylibloader_orig_pulse
+#define pa_context_get_state pa_context_get_state_dylibloader_orig_pulse
+#define pa_context_connect pa_context_connect_dylibloader_orig_pulse
+#define pa_context_disconnect pa_context_disconnect_dylibloader_orig_pulse
+#define pa_context_drain pa_context_drain_dylibloader_orig_pulse
+#define pa_context_exit_daemon pa_context_exit_daemon_dylibloader_orig_pulse
+#define pa_context_set_default_sink pa_context_set_default_sink_dylibloader_orig_pulse
+#define pa_context_set_default_source pa_context_set_default_source_dylibloader_orig_pulse
+#define pa_context_is_local pa_context_is_local_dylibloader_orig_pulse
+#define pa_context_set_name pa_context_set_name_dylibloader_orig_pulse
+#define pa_context_get_server pa_context_get_server_dylibloader_orig_pulse
+#define pa_context_get_protocol_version pa_context_get_protocol_version_dylibloader_orig_pulse
+#define pa_context_get_server_protocol_version pa_context_get_server_protocol_version_dylibloader_orig_pulse
+#define pa_context_proplist_update pa_context_proplist_update_dylibloader_orig_pulse
+#define pa_context_proplist_remove pa_context_proplist_remove_dylibloader_orig_pulse
+#define pa_context_get_index pa_context_get_index_dylibloader_orig_pulse
+#define pa_context_rttime_new pa_context_rttime_new_dylibloader_orig_pulse
+#define pa_context_rttime_restart pa_context_rttime_restart_dylibloader_orig_pulse
+#define pa_context_get_tile_size pa_context_get_tile_size_dylibloader_orig_pulse
+#define pa_context_load_cookie_from_file pa_context_load_cookie_from_file_dylibloader_orig_pulse
+#define pa_cvolume_equal pa_cvolume_equal_dylibloader_orig_pulse
+#define pa_cvolume_init pa_cvolume_init_dylibloader_orig_pulse
+#define pa_cvolume_set pa_cvolume_set_dylibloader_orig_pulse
+#define pa_cvolume_snprint pa_cvolume_snprint_dylibloader_orig_pulse
+#define pa_sw_cvolume_snprint_dB pa_sw_cvolume_snprint_dB_dylibloader_orig_pulse
+#define pa_cvolume_snprint_verbose pa_cvolume_snprint_verbose_dylibloader_orig_pulse
+#define pa_volume_snprint pa_volume_snprint_dylibloader_orig_pulse
+#define pa_sw_volume_snprint_dB pa_sw_volume_snprint_dB_dylibloader_orig_pulse
+#define pa_volume_snprint_verbose pa_volume_snprint_verbose_dylibloader_orig_pulse
+#define pa_cvolume_avg pa_cvolume_avg_dylibloader_orig_pulse
+#define pa_cvolume_avg_mask pa_cvolume_avg_mask_dylibloader_orig_pulse
+#define pa_cvolume_max pa_cvolume_max_dylibloader_orig_pulse
+#define pa_cvolume_max_mask pa_cvolume_max_mask_dylibloader_orig_pulse
+#define pa_cvolume_min pa_cvolume_min_dylibloader_orig_pulse
+#define pa_cvolume_min_mask pa_cvolume_min_mask_dylibloader_orig_pulse
+#define pa_cvolume_valid pa_cvolume_valid_dylibloader_orig_pulse
+#define pa_cvolume_channels_equal_to pa_cvolume_channels_equal_to_dylibloader_orig_pulse
+#define pa_sw_volume_multiply pa_sw_volume_multiply_dylibloader_orig_pulse
+#define pa_sw_cvolume_multiply pa_sw_cvolume_multiply_dylibloader_orig_pulse
+#define pa_sw_cvolume_multiply_scalar pa_sw_cvolume_multiply_scalar_dylibloader_orig_pulse
+#define pa_sw_volume_divide pa_sw_volume_divide_dylibloader_orig_pulse
+#define pa_sw_cvolume_divide pa_sw_cvolume_divide_dylibloader_orig_pulse
+#define pa_sw_cvolume_divide_scalar pa_sw_cvolume_divide_scalar_dylibloader_orig_pulse
+#define pa_sw_volume_from_dB pa_sw_volume_from_dB_dylibloader_orig_pulse
+#define pa_sw_volume_to_dB pa_sw_volume_to_dB_dylibloader_orig_pulse
+#define pa_sw_volume_from_linear pa_sw_volume_from_linear_dylibloader_orig_pulse
+#define pa_sw_volume_to_linear pa_sw_volume_to_linear_dylibloader_orig_pulse
+#define pa_cvolume_remap pa_cvolume_remap_dylibloader_orig_pulse
+#define pa_cvolume_compatible pa_cvolume_compatible_dylibloader_orig_pulse
+#define pa_cvolume_compatible_with_channel_map pa_cvolume_compatible_with_channel_map_dylibloader_orig_pulse
+#define pa_cvolume_get_balance pa_cvolume_get_balance_dylibloader_orig_pulse
+#define pa_cvolume_set_balance pa_cvolume_set_balance_dylibloader_orig_pulse
+#define pa_cvolume_get_fade pa_cvolume_get_fade_dylibloader_orig_pulse
+#define pa_cvolume_set_fade pa_cvolume_set_fade_dylibloader_orig_pulse
+#define pa_cvolume_get_lfe_balance pa_cvolume_get_lfe_balance_dylibloader_orig_pulse
+#define pa_cvolume_set_lfe_balance pa_cvolume_set_lfe_balance_dylibloader_orig_pulse
+#define pa_cvolume_scale pa_cvolume_scale_dylibloader_orig_pulse
+#define pa_cvolume_scale_mask pa_cvolume_scale_mask_dylibloader_orig_pulse
+#define pa_cvolume_set_position pa_cvolume_set_position_dylibloader_orig_pulse
+#define pa_cvolume_get_position pa_cvolume_get_position_dylibloader_orig_pulse
+#define pa_cvolume_merge pa_cvolume_merge_dylibloader_orig_pulse
+#define pa_cvolume_inc_clamp pa_cvolume_inc_clamp_dylibloader_orig_pulse
+#define pa_cvolume_inc pa_cvolume_inc_dylibloader_orig_pulse
+#define pa_cvolume_dec pa_cvolume_dec_dylibloader_orig_pulse
+#define pa_stream_new pa_stream_new_dylibloader_orig_pulse
+#define pa_stream_new_with_proplist pa_stream_new_with_proplist_dylibloader_orig_pulse
+#define pa_stream_new_extended pa_stream_new_extended_dylibloader_orig_pulse
+#define pa_stream_unref pa_stream_unref_dylibloader_orig_pulse
+#define pa_stream_ref pa_stream_ref_dylibloader_orig_pulse
+#define pa_stream_get_state pa_stream_get_state_dylibloader_orig_pulse
+#define pa_stream_get_context pa_stream_get_context_dylibloader_orig_pulse
+#define pa_stream_get_index pa_stream_get_index_dylibloader_orig_pulse
+#define pa_stream_get_device_index pa_stream_get_device_index_dylibloader_orig_pulse
+#define pa_stream_get_device_name pa_stream_get_device_name_dylibloader_orig_pulse
+#define pa_stream_is_suspended pa_stream_is_suspended_dylibloader_orig_pulse
+#define pa_stream_is_corked pa_stream_is_corked_dylibloader_orig_pulse
+#define pa_stream_connect_playback pa_stream_connect_playback_dylibloader_orig_pulse
+#define pa_stream_connect_record pa_stream_connect_record_dylibloader_orig_pulse
+#define pa_stream_disconnect pa_stream_disconnect_dylibloader_orig_pulse
+#define pa_stream_begin_write pa_stream_begin_write_dylibloader_orig_pulse
+#define pa_stream_cancel_write pa_stream_cancel_write_dylibloader_orig_pulse
+#define pa_stream_write pa_stream_write_dylibloader_orig_pulse
+#define pa_stream_write_ext_free pa_stream_write_ext_free_dylibloader_orig_pulse
+#define pa_stream_peek pa_stream_peek_dylibloader_orig_pulse
+#define pa_stream_drop pa_stream_drop_dylibloader_orig_pulse
+#define pa_stream_writable_size pa_stream_writable_size_dylibloader_orig_pulse
+#define pa_stream_readable_size pa_stream_readable_size_dylibloader_orig_pulse
+#define pa_stream_drain pa_stream_drain_dylibloader_orig_pulse
+#define pa_stream_update_timing_info pa_stream_update_timing_info_dylibloader_orig_pulse
+#define pa_stream_set_state_callback pa_stream_set_state_callback_dylibloader_orig_pulse
+#define pa_stream_set_write_callback pa_stream_set_write_callback_dylibloader_orig_pulse
+#define pa_stream_set_read_callback pa_stream_set_read_callback_dylibloader_orig_pulse
+#define pa_stream_set_overflow_callback pa_stream_set_overflow_callback_dylibloader_orig_pulse
+#define pa_stream_get_underflow_index pa_stream_get_underflow_index_dylibloader_orig_pulse
+#define pa_stream_set_underflow_callback pa_stream_set_underflow_callback_dylibloader_orig_pulse
+#define pa_stream_set_started_callback pa_stream_set_started_callback_dylibloader_orig_pulse
+#define pa_stream_set_latency_update_callback pa_stream_set_latency_update_callback_dylibloader_orig_pulse
+#define pa_stream_set_moved_callback pa_stream_set_moved_callback_dylibloader_orig_pulse
+#define pa_stream_set_suspended_callback pa_stream_set_suspended_callback_dylibloader_orig_pulse
+#define pa_stream_set_event_callback pa_stream_set_event_callback_dylibloader_orig_pulse
+#define pa_stream_set_buffer_attr_callback pa_stream_set_buffer_attr_callback_dylibloader_orig_pulse
+#define pa_stream_cork pa_stream_cork_dylibloader_orig_pulse
+#define pa_stream_flush pa_stream_flush_dylibloader_orig_pulse
+#define pa_stream_prebuf pa_stream_prebuf_dylibloader_orig_pulse
+#define pa_stream_trigger pa_stream_trigger_dylibloader_orig_pulse
+#define pa_stream_set_name pa_stream_set_name_dylibloader_orig_pulse
+#define pa_stream_get_time pa_stream_get_time_dylibloader_orig_pulse
+#define pa_stream_get_latency pa_stream_get_latency_dylibloader_orig_pulse
+#define pa_stream_get_timing_info pa_stream_get_timing_info_dylibloader_orig_pulse
+#define pa_stream_get_sample_spec pa_stream_get_sample_spec_dylibloader_orig_pulse
+#define pa_stream_get_channel_map pa_stream_get_channel_map_dylibloader_orig_pulse
+#define pa_stream_get_format_info pa_stream_get_format_info_dylibloader_orig_pulse
+#define pa_stream_get_buffer_attr pa_stream_get_buffer_attr_dylibloader_orig_pulse
+#define pa_stream_set_buffer_attr pa_stream_set_buffer_attr_dylibloader_orig_pulse
+#define pa_stream_update_sample_rate pa_stream_update_sample_rate_dylibloader_orig_pulse
+#define pa_stream_proplist_update pa_stream_proplist_update_dylibloader_orig_pulse
+#define pa_stream_proplist_remove pa_stream_proplist_remove_dylibloader_orig_pulse
+#define pa_stream_set_monitor_stream pa_stream_set_monitor_stream_dylibloader_orig_pulse
+#define pa_stream_get_monitor_stream pa_stream_get_monitor_stream_dylibloader_orig_pulse
+#define pa_context_get_sink_info_by_name pa_context_get_sink_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_sink_info_by_index pa_context_get_sink_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_sink_info_list pa_context_get_sink_info_list_dylibloader_orig_pulse
+#define pa_context_set_sink_volume_by_index pa_context_set_sink_volume_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_volume_by_name pa_context_set_sink_volume_by_name_dylibloader_orig_pulse
+#define pa_context_set_sink_mute_by_index pa_context_set_sink_mute_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_mute_by_name pa_context_set_sink_mute_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_sink_by_name pa_context_suspend_sink_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_sink_by_index pa_context_suspend_sink_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_port_by_index pa_context_set_sink_port_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_port_by_name pa_context_set_sink_port_by_name_dylibloader_orig_pulse
+#define pa_context_get_source_info_by_name pa_context_get_source_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_source_info_by_index pa_context_get_source_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_source_info_list pa_context_get_source_info_list_dylibloader_orig_pulse
+#define pa_context_set_source_volume_by_index pa_context_set_source_volume_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_volume_by_name pa_context_set_source_volume_by_name_dylibloader_orig_pulse
+#define pa_context_set_source_mute_by_index pa_context_set_source_mute_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_mute_by_name pa_context_set_source_mute_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_source_by_name pa_context_suspend_source_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_source_by_index pa_context_suspend_source_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_port_by_index pa_context_set_source_port_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_port_by_name pa_context_set_source_port_by_name_dylibloader_orig_pulse
+#define pa_context_get_server_info pa_context_get_server_info_dylibloader_orig_pulse
+#define pa_context_get_module_info pa_context_get_module_info_dylibloader_orig_pulse
+#define pa_context_get_module_info_list pa_context_get_module_info_list_dylibloader_orig_pulse
+#define pa_context_load_module pa_context_load_module_dylibloader_orig_pulse
+#define pa_context_unload_module pa_context_unload_module_dylibloader_orig_pulse
+#define pa_context_get_client_info pa_context_get_client_info_dylibloader_orig_pulse
+#define pa_context_get_client_info_list pa_context_get_client_info_list_dylibloader_orig_pulse
+#define pa_context_kill_client pa_context_kill_client_dylibloader_orig_pulse
+#define pa_context_get_card_info_by_index pa_context_get_card_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_card_info_by_name pa_context_get_card_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_card_info_list pa_context_get_card_info_list_dylibloader_orig_pulse
+#define pa_context_set_card_profile_by_index pa_context_set_card_profile_by_index_dylibloader_orig_pulse
+#define pa_context_set_card_profile_by_name pa_context_set_card_profile_by_name_dylibloader_orig_pulse
+#define pa_context_set_port_latency_offset pa_context_set_port_latency_offset_dylibloader_orig_pulse
+#define pa_context_get_sink_input_info pa_context_get_sink_input_info_dylibloader_orig_pulse
+#define pa_context_get_sink_input_info_list pa_context_get_sink_input_info_list_dylibloader_orig_pulse
+#define pa_context_move_sink_input_by_name pa_context_move_sink_input_by_name_dylibloader_orig_pulse
+#define pa_context_move_sink_input_by_index pa_context_move_sink_input_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_input_volume pa_context_set_sink_input_volume_dylibloader_orig_pulse
+#define pa_context_set_sink_input_mute pa_context_set_sink_input_mute_dylibloader_orig_pulse
+#define pa_context_kill_sink_input pa_context_kill_sink_input_dylibloader_orig_pulse
+#define pa_context_get_source_output_info pa_context_get_source_output_info_dylibloader_orig_pulse
+#define pa_context_get_source_output_info_list pa_context_get_source_output_info_list_dylibloader_orig_pulse
+#define pa_context_move_source_output_by_name pa_context_move_source_output_by_name_dylibloader_orig_pulse
+#define pa_context_move_source_output_by_index pa_context_move_source_output_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_output_volume pa_context_set_source_output_volume_dylibloader_orig_pulse
+#define pa_context_set_source_output_mute pa_context_set_source_output_mute_dylibloader_orig_pulse
+#define pa_context_kill_source_output pa_context_kill_source_output_dylibloader_orig_pulse
+#define pa_context_stat pa_context_stat_dylibloader_orig_pulse
+#define pa_context_get_sample_info_by_name pa_context_get_sample_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_sample_info_by_index pa_context_get_sample_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_sample_info_list pa_context_get_sample_info_list_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_by_name pa_context_get_autoload_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_by_index pa_context_get_autoload_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_list pa_context_get_autoload_info_list_dylibloader_orig_pulse
+#define pa_context_add_autoload pa_context_add_autoload_dylibloader_orig_pulse
+#define pa_context_remove_autoload_by_name pa_context_remove_autoload_by_name_dylibloader_orig_pulse
+#define pa_context_remove_autoload_by_index pa_context_remove_autoload_by_index_dylibloader_orig_pulse
+#define pa_context_subscribe pa_context_subscribe_dylibloader_orig_pulse
+#define pa_context_set_subscribe_callback pa_context_set_subscribe_callback_dylibloader_orig_pulse
+#define pa_stream_connect_upload pa_stream_connect_upload_dylibloader_orig_pulse
+#define pa_stream_finish_upload pa_stream_finish_upload_dylibloader_orig_pulse
+#define pa_context_remove_sample pa_context_remove_sample_dylibloader_orig_pulse
+#define pa_context_play_sample pa_context_play_sample_dylibloader_orig_pulse
+#define pa_context_play_sample_with_proplist pa_context_play_sample_with_proplist_dylibloader_orig_pulse
+#define pa_strerror pa_strerror_dylibloader_orig_pulse
+#define pa_xmalloc pa_xmalloc_dylibloader_orig_pulse
+#define pa_xmalloc0 pa_xmalloc0_dylibloader_orig_pulse
+#define pa_xrealloc pa_xrealloc_dylibloader_orig_pulse
+#define pa_xfree pa_xfree_dylibloader_orig_pulse
+#define pa_xstrdup pa_xstrdup_dylibloader_orig_pulse
+#define pa_xstrndup pa_xstrndup_dylibloader_orig_pulse
+#define pa_xmemdup pa_xmemdup_dylibloader_orig_pulse
+#define pa_utf8_valid pa_utf8_valid_dylibloader_orig_pulse
+#define pa_ascii_valid pa_ascii_valid_dylibloader_orig_pulse
+#define pa_utf8_filter pa_utf8_filter_dylibloader_orig_pulse
+#define pa_ascii_filter pa_ascii_filter_dylibloader_orig_pulse
+#define pa_utf8_to_locale pa_utf8_to_locale_dylibloader_orig_pulse
+#define pa_locale_to_utf8 pa_locale_to_utf8_dylibloader_orig_pulse
+#define pa_threaded_mainloop_new pa_threaded_mainloop_new_dylibloader_orig_pulse
+#define pa_threaded_mainloop_free pa_threaded_mainloop_free_dylibloader_orig_pulse
+#define pa_threaded_mainloop_start pa_threaded_mainloop_start_dylibloader_orig_pulse
+#define pa_threaded_mainloop_stop pa_threaded_mainloop_stop_dylibloader_orig_pulse
+#define pa_threaded_mainloop_lock pa_threaded_mainloop_lock_dylibloader_orig_pulse
+#define pa_threaded_mainloop_unlock pa_threaded_mainloop_unlock_dylibloader_orig_pulse
+#define pa_threaded_mainloop_wait pa_threaded_mainloop_wait_dylibloader_orig_pulse
+#define pa_threaded_mainloop_signal pa_threaded_mainloop_signal_dylibloader_orig_pulse
+#define pa_threaded_mainloop_accept pa_threaded_mainloop_accept_dylibloader_orig_pulse
+#define pa_threaded_mainloop_get_retval pa_threaded_mainloop_get_retval_dylibloader_orig_pulse
+#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_orig_pulse
+#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_orig_pulse
+#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_orig_pulse
+#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_orig_pulse
+#define pa_mainloop_new pa_mainloop_new_dylibloader_orig_pulse
+#define pa_mainloop_free pa_mainloop_free_dylibloader_orig_pulse
+#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_orig_pulse
+#define pa_mainloop_poll pa_mainloop_poll_dylibloader_orig_pulse
+#define pa_mainloop_dispatch pa_mainloop_dispatch_dylibloader_orig_pulse
+#define pa_mainloop_get_retval pa_mainloop_get_retval_dylibloader_orig_pulse
+#define pa_mainloop_iterate pa_mainloop_iterate_dylibloader_orig_pulse
+#define pa_mainloop_run pa_mainloop_run_dylibloader_orig_pulse
+#define pa_mainloop_get_api pa_mainloop_get_api_dylibloader_orig_pulse
+#define pa_mainloop_quit pa_mainloop_quit_dylibloader_orig_pulse
+#define pa_mainloop_wakeup pa_mainloop_wakeup_dylibloader_orig_pulse
+#define pa_mainloop_set_poll_func pa_mainloop_set_poll_func_dylibloader_orig_pulse
+#define pa_signal_init pa_signal_init_dylibloader_orig_pulse
+#define pa_signal_done pa_signal_done_dylibloader_orig_pulse
+#define pa_signal_new pa_signal_new_dylibloader_orig_pulse
+#define pa_signal_free pa_signal_free_dylibloader_orig_pulse
+#define pa_signal_set_destroy pa_signal_set_destroy_dylibloader_orig_pulse
+#define pa_get_user_name pa_get_user_name_dylibloader_orig_pulse
+#define pa_get_host_name pa_get_host_name_dylibloader_orig_pulse
+#define pa_get_fqdn pa_get_fqdn_dylibloader_orig_pulse
+#define pa_get_home_dir pa_get_home_dir_dylibloader_orig_pulse
+#define pa_get_binary_name pa_get_binary_name_dylibloader_orig_pulse
+#define pa_path_get_filename pa_path_get_filename_dylibloader_orig_pulse
+#define pa_msleep pa_msleep_dylibloader_orig_pulse
+#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_orig_pulse
+#define pa_gettimeofday pa_gettimeofday_dylibloader_orig_pulse
+#define pa_timeval_diff pa_timeval_diff_dylibloader_orig_pulse
+#define pa_timeval_cmp pa_timeval_cmp_dylibloader_orig_pulse
+#define pa_timeval_age pa_timeval_age_dylibloader_orig_pulse
+#define pa_timeval_add pa_timeval_add_dylibloader_orig_pulse
+#define pa_timeval_sub pa_timeval_sub_dylibloader_orig_pulse
+#define pa_timeval_store pa_timeval_store_dylibloader_orig_pulse
+#define pa_timeval_load pa_timeval_load_dylibloader_orig_pulse
+#define pa_rtclock_now pa_rtclock_now_dylibloader_orig_pulse
+#include <pulse/pulseaudio.h>
+#undef pa_get_library_version
+#undef pa_bytes_per_second
+#undef pa_frame_size
+#undef pa_sample_size
+#undef pa_sample_size_of_format
+#undef pa_bytes_to_usec
+#undef pa_usec_to_bytes
+#undef pa_sample_spec_init
+#undef pa_sample_format_valid
+#undef pa_sample_rate_valid
+#undef pa_channels_valid
+#undef pa_sample_spec_valid
+#undef pa_sample_spec_equal
+#undef pa_sample_format_to_string
+#undef pa_parse_sample_format
+#undef pa_sample_spec_snprint
+#undef pa_bytes_snprint
+#undef pa_sample_format_is_le
+#undef pa_sample_format_is_be
+#undef pa_direction_valid
+#undef pa_direction_to_string
+#undef pa_mainloop_api_once
+#undef pa_proplist_new
+#undef pa_proplist_free
+#undef pa_proplist_key_valid
+#undef pa_proplist_sets
+#undef pa_proplist_setp
+#undef pa_proplist_setf
+#undef pa_proplist_set
+#undef pa_proplist_gets
+#undef pa_proplist_get
+#undef pa_proplist_update
+#undef pa_proplist_unset
+#undef pa_proplist_unset_many
+#undef pa_proplist_iterate
+#undef pa_proplist_to_string
+#undef pa_proplist_to_string_sep
+#undef pa_proplist_from_string
+#undef pa_proplist_contains
+#undef pa_proplist_clear
+#undef pa_proplist_copy
+#undef pa_proplist_size
+#undef pa_proplist_isempty
+#undef pa_proplist_equal
+#undef pa_channel_map_init
+#undef pa_channel_map_init_mono
+#undef pa_channel_map_init_stereo
+#undef pa_channel_map_init_auto
+#undef pa_channel_map_init_extend
+#undef pa_channel_position_to_string
+#undef pa_channel_position_from_string
+#undef pa_channel_position_to_pretty_string
+#undef pa_channel_map_snprint
+#undef pa_channel_map_parse
+#undef pa_channel_map_equal
+#undef pa_channel_map_valid
+#undef pa_channel_map_compatible
+#undef pa_channel_map_superset
+#undef pa_channel_map_can_balance
+#undef pa_channel_map_can_fade
+#undef pa_channel_map_can_lfe_balance
+#undef pa_channel_map_to_name
+#undef pa_channel_map_to_pretty_name
+#undef pa_channel_map_has_position
+#undef pa_channel_map_mask
+#undef pa_encoding_to_string
+#undef pa_encoding_from_string
+#undef pa_format_info_new
+#undef pa_format_info_copy
+#undef pa_format_info_free
+#undef pa_format_info_valid
+#undef pa_format_info_is_pcm
+#undef pa_format_info_is_compatible
+#undef pa_format_info_snprint
+#undef pa_format_info_from_string
+#undef pa_format_info_from_sample_spec
+#undef pa_format_info_to_sample_spec
+#undef pa_format_info_get_prop_type
+#undef pa_format_info_get_prop_int
+#undef pa_format_info_get_prop_int_range
+#undef pa_format_info_get_prop_int_array
+#undef pa_format_info_get_prop_string
+#undef pa_format_info_get_prop_string_array
+#undef pa_format_info_free_string_array
+#undef pa_format_info_get_sample_format
+#undef pa_format_info_get_rate
+#undef pa_format_info_get_channels
+#undef pa_format_info_get_channel_map
+#undef pa_format_info_set_prop_int
+#undef pa_format_info_set_prop_int_array
+#undef pa_format_info_set_prop_int_range
+#undef pa_format_info_set_prop_string
+#undef pa_format_info_set_prop_string_array
+#undef pa_format_info_set_sample_format
+#undef pa_format_info_set_rate
+#undef pa_format_info_set_channels
+#undef pa_format_info_set_channel_map
+#undef pa_operation_ref
+#undef pa_operation_unref
+#undef pa_operation_cancel
+#undef pa_operation_get_state
+#undef pa_operation_set_state_callback
+#undef pa_context_new
+#undef pa_context_new_with_proplist
+#undef pa_context_unref
+#undef pa_context_ref
+#undef pa_context_set_state_callback
+#undef pa_context_set_event_callback
+#undef pa_context_errno
+#undef pa_context_is_pending
+#undef pa_context_get_state
+#undef pa_context_connect
+#undef pa_context_disconnect
+#undef pa_context_drain
+#undef pa_context_exit_daemon
+#undef pa_context_set_default_sink
+#undef pa_context_set_default_source
+#undef pa_context_is_local
+#undef pa_context_set_name
+#undef pa_context_get_server
+#undef pa_context_get_protocol_version
+#undef pa_context_get_server_protocol_version
+#undef pa_context_proplist_update
+#undef pa_context_proplist_remove
+#undef pa_context_get_index
+#undef pa_context_rttime_new
+#undef pa_context_rttime_restart
+#undef pa_context_get_tile_size
+#undef pa_context_load_cookie_from_file
+#undef pa_cvolume_equal
+#undef pa_cvolume_init
+#undef pa_cvolume_set
+#undef pa_cvolume_snprint
+#undef pa_sw_cvolume_snprint_dB
+#undef pa_cvolume_snprint_verbose
+#undef pa_volume_snprint
+#undef pa_sw_volume_snprint_dB
+#undef pa_volume_snprint_verbose
+#undef pa_cvolume_avg
+#undef pa_cvolume_avg_mask
+#undef pa_cvolume_max
+#undef pa_cvolume_max_mask
+#undef pa_cvolume_min
+#undef pa_cvolume_min_mask
+#undef pa_cvolume_valid
+#undef pa_cvolume_channels_equal_to
+#undef pa_sw_volume_multiply
+#undef pa_sw_cvolume_multiply
+#undef pa_sw_cvolume_multiply_scalar
+#undef pa_sw_volume_divide
+#undef pa_sw_cvolume_divide
+#undef pa_sw_cvolume_divide_scalar
+#undef pa_sw_volume_from_dB
+#undef pa_sw_volume_to_dB
+#undef pa_sw_volume_from_linear
+#undef pa_sw_volume_to_linear
+#undef pa_cvolume_remap
+#undef pa_cvolume_compatible
+#undef pa_cvolume_compatible_with_channel_map
+#undef pa_cvolume_get_balance
+#undef pa_cvolume_set_balance
+#undef pa_cvolume_get_fade
+#undef pa_cvolume_set_fade
+#undef pa_cvolume_get_lfe_balance
+#undef pa_cvolume_set_lfe_balance
+#undef pa_cvolume_scale
+#undef pa_cvolume_scale_mask
+#undef pa_cvolume_set_position
+#undef pa_cvolume_get_position
+#undef pa_cvolume_merge
+#undef pa_cvolume_inc_clamp
+#undef pa_cvolume_inc
+#undef pa_cvolume_dec
+#undef pa_stream_new
+#undef pa_stream_new_with_proplist
+#undef pa_stream_new_extended
+#undef pa_stream_unref
+#undef pa_stream_ref
+#undef pa_stream_get_state
+#undef pa_stream_get_context
+#undef pa_stream_get_index
+#undef pa_stream_get_device_index
+#undef pa_stream_get_device_name
+#undef pa_stream_is_suspended
+#undef pa_stream_is_corked
+#undef pa_stream_connect_playback
+#undef pa_stream_connect_record
+#undef pa_stream_disconnect
+#undef pa_stream_begin_write
+#undef pa_stream_cancel_write
+#undef pa_stream_write
+#undef pa_stream_write_ext_free
+#undef pa_stream_peek
+#undef pa_stream_drop
+#undef pa_stream_writable_size
+#undef pa_stream_readable_size
+#undef pa_stream_drain
+#undef pa_stream_update_timing_info
+#undef pa_stream_set_state_callback
+#undef pa_stream_set_write_callback
+#undef pa_stream_set_read_callback
+#undef pa_stream_set_overflow_callback
+#undef pa_stream_get_underflow_index
+#undef pa_stream_set_underflow_callback
+#undef pa_stream_set_started_callback
+#undef pa_stream_set_latency_update_callback
+#undef pa_stream_set_moved_callback
+#undef pa_stream_set_suspended_callback
+#undef pa_stream_set_event_callback
+#undef pa_stream_set_buffer_attr_callback
+#undef pa_stream_cork
+#undef pa_stream_flush
+#undef pa_stream_prebuf
+#undef pa_stream_trigger
+#undef pa_stream_set_name
+#undef pa_stream_get_time
+#undef pa_stream_get_latency
+#undef pa_stream_get_timing_info
+#undef pa_stream_get_sample_spec
+#undef pa_stream_get_channel_map
+#undef pa_stream_get_format_info
+#undef pa_stream_get_buffer_attr
+#undef pa_stream_set_buffer_attr
+#undef pa_stream_update_sample_rate
+#undef pa_stream_proplist_update
+#undef pa_stream_proplist_remove
+#undef pa_stream_set_monitor_stream
+#undef pa_stream_get_monitor_stream
+#undef pa_context_get_sink_info_by_name
+#undef pa_context_get_sink_info_by_index
+#undef pa_context_get_sink_info_list
+#undef pa_context_set_sink_volume_by_index
+#undef pa_context_set_sink_volume_by_name
+#undef pa_context_set_sink_mute_by_index
+#undef pa_context_set_sink_mute_by_name
+#undef pa_context_suspend_sink_by_name
+#undef pa_context_suspend_sink_by_index
+#undef pa_context_set_sink_port_by_index
+#undef pa_context_set_sink_port_by_name
+#undef pa_context_get_source_info_by_name
+#undef pa_context_get_source_info_by_index
+#undef pa_context_get_source_info_list
+#undef pa_context_set_source_volume_by_index
+#undef pa_context_set_source_volume_by_name
+#undef pa_context_set_source_mute_by_index
+#undef pa_context_set_source_mute_by_name
+#undef pa_context_suspend_source_by_name
+#undef pa_context_suspend_source_by_index
+#undef pa_context_set_source_port_by_index
+#undef pa_context_set_source_port_by_name
+#undef pa_context_get_server_info
+#undef pa_context_get_module_info
+#undef pa_context_get_module_info_list
+#undef pa_context_load_module
+#undef pa_context_unload_module
+#undef pa_context_get_client_info
+#undef pa_context_get_client_info_list
+#undef pa_context_kill_client
+#undef pa_context_get_card_info_by_index
+#undef pa_context_get_card_info_by_name
+#undef pa_context_get_card_info_list
+#undef pa_context_set_card_profile_by_index
+#undef pa_context_set_card_profile_by_name
+#undef pa_context_set_port_latency_offset
+#undef pa_context_get_sink_input_info
+#undef pa_context_get_sink_input_info_list
+#undef pa_context_move_sink_input_by_name
+#undef pa_context_move_sink_input_by_index
+#undef pa_context_set_sink_input_volume
+#undef pa_context_set_sink_input_mute
+#undef pa_context_kill_sink_input
+#undef pa_context_get_source_output_info
+#undef pa_context_get_source_output_info_list
+#undef pa_context_move_source_output_by_name
+#undef pa_context_move_source_output_by_index
+#undef pa_context_set_source_output_volume
+#undef pa_context_set_source_output_mute
+#undef pa_context_kill_source_output
+#undef pa_context_stat
+#undef pa_context_get_sample_info_by_name
+#undef pa_context_get_sample_info_by_index
+#undef pa_context_get_sample_info_list
+#undef pa_context_get_autoload_info_by_name
+#undef pa_context_get_autoload_info_by_index
+#undef pa_context_get_autoload_info_list
+#undef pa_context_add_autoload
+#undef pa_context_remove_autoload_by_name
+#undef pa_context_remove_autoload_by_index
+#undef pa_context_subscribe
+#undef pa_context_set_subscribe_callback
+#undef pa_stream_connect_upload
+#undef pa_stream_finish_upload
+#undef pa_context_remove_sample
+#undef pa_context_play_sample
+#undef pa_context_play_sample_with_proplist
+#undef pa_strerror
+#undef pa_xmalloc
+#undef pa_xmalloc0
+#undef pa_xrealloc
+#undef pa_xfree
+#undef pa_xstrdup
+#undef pa_xstrndup
+#undef pa_xmemdup
+#undef pa_utf8_valid
+#undef pa_ascii_valid
+#undef pa_utf8_filter
+#undef pa_ascii_filter
+#undef pa_utf8_to_locale
+#undef pa_locale_to_utf8
+#undef pa_threaded_mainloop_new
+#undef pa_threaded_mainloop_free
+#undef pa_threaded_mainloop_start
+#undef pa_threaded_mainloop_stop
+#undef pa_threaded_mainloop_lock
+#undef pa_threaded_mainloop_unlock
+#undef pa_threaded_mainloop_wait
+#undef pa_threaded_mainloop_signal
+#undef pa_threaded_mainloop_accept
+#undef pa_threaded_mainloop_get_retval
+#undef pa_threaded_mainloop_get_api
+#undef pa_threaded_mainloop_in_thread
+#undef pa_threaded_mainloop_set_name
+#undef pa_threaded_mainloop_once_unlocked
+#undef pa_mainloop_new
+#undef pa_mainloop_free
+#undef pa_mainloop_prepare
+#undef pa_mainloop_poll
+#undef pa_mainloop_dispatch
+#undef pa_mainloop_get_retval
+#undef pa_mainloop_iterate
+#undef pa_mainloop_run
+#undef pa_mainloop_get_api
+#undef pa_mainloop_quit
+#undef pa_mainloop_wakeup
+#undef pa_mainloop_set_poll_func
+#undef pa_signal_init
+#undef pa_signal_done
+#undef pa_signal_new
+#undef pa_signal_free
+#undef pa_signal_set_destroy
+#undef pa_get_user_name
+#undef pa_get_host_name
+#undef pa_get_fqdn
+#undef pa_get_home_dir
+#undef pa_get_binary_name
+#undef pa_path_get_filename
+#undef pa_msleep
+#undef pa_thread_make_realtime
+#undef pa_gettimeofday
+#undef pa_timeval_diff
+#undef pa_timeval_cmp
+#undef pa_timeval_age
+#undef pa_timeval_add
+#undef pa_timeval_sub
+#undef pa_timeval_store
+#undef pa_timeval_load
+#undef pa_rtclock_now
+#include <dlfcn.h>
+#include <stdio.h>
+const char* (*pa_get_library_version_dylibloader_wrapper_pulse)( void);
+size_t (*pa_bytes_per_second_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+size_t (*pa_frame_size_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+size_t (*pa_sample_size_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+size_t (*pa_sample_size_of_format_dylibloader_wrapper_pulse)( pa_sample_format_t);
+pa_usec_t (*pa_bytes_to_usec_dylibloader_wrapper_pulse)( uint64_t,const pa_sample_spec*);
+size_t (*pa_usec_to_bytes_dylibloader_wrapper_pulse)( pa_usec_t,const pa_sample_spec*);
+pa_sample_spec* (*pa_sample_spec_init_dylibloader_wrapper_pulse)( pa_sample_spec*);
+int (*pa_sample_format_valid_dylibloader_wrapper_pulse)( unsigned);
+int (*pa_sample_rate_valid_dylibloader_wrapper_pulse)( uint32_t);
+int (*pa_channels_valid_dylibloader_wrapper_pulse)( uint8_t);
+int (*pa_sample_spec_valid_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+int (*pa_sample_spec_equal_dylibloader_wrapper_pulse)(const pa_sample_spec*,const pa_sample_spec*);
+const char* (*pa_sample_format_to_string_dylibloader_wrapper_pulse)( pa_sample_format_t);
+pa_sample_format_t (*pa_parse_sample_format_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_sample_spec_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_sample_spec*);
+char* (*pa_bytes_snprint_dylibloader_wrapper_pulse)( char*, size_t, unsigned);
+int (*pa_sample_format_is_le_dylibloader_wrapper_pulse)( pa_sample_format_t);
+int (*pa_sample_format_is_be_dylibloader_wrapper_pulse)( pa_sample_format_t);
+int (*pa_direction_valid_dylibloader_wrapper_pulse)( pa_direction_t);
+const char* (*pa_direction_to_string_dylibloader_wrapper_pulse)( pa_direction_t);
+void (*pa_mainloop_api_once_dylibloader_wrapper_pulse)( pa_mainloop_api*, void*, void*);
+pa_proplist* (*pa_proplist_new_dylibloader_wrapper_pulse)( void);
+void (*pa_proplist_free_dylibloader_wrapper_pulse)( pa_proplist*);
+int (*pa_proplist_key_valid_dylibloader_wrapper_pulse)(const char*);
+int (*pa_proplist_sets_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*);
+int (*pa_proplist_setp_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+int (*pa_proplist_setf_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*,...);
+int (*pa_proplist_set_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void*, size_t);
+const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+int (*pa_proplist_get_dylibloader_wrapper_pulse)(const pa_proplist*,const char*,const void**, size_t*);
+void (*pa_proplist_update_dylibloader_wrapper_pulse)( pa_proplist*, pa_update_mode_t,const pa_proplist*);
+int (*pa_proplist_unset_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+int (*pa_proplist_unset_many_dylibloader_wrapper_pulse)( pa_proplist*,const char* []);
+const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)(const pa_proplist*, void**);
+char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)(const pa_proplist*);
+char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+pa_proplist* (*pa_proplist_from_string_dylibloader_wrapper_pulse)(const char*);
+int (*pa_proplist_contains_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+void (*pa_proplist_clear_dylibloader_wrapper_pulse)( pa_proplist*);
+pa_proplist* (*pa_proplist_copy_dylibloader_wrapper_pulse)(const pa_proplist*);
+unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)(const pa_proplist*);
+int (*pa_proplist_isempty_dylibloader_wrapper_pulse)(const pa_proplist*);
+int (*pa_proplist_equal_dylibloader_wrapper_pulse)(const pa_proplist*,const pa_proplist*);
+pa_channel_map* (*pa_channel_map_init_dylibloader_wrapper_pulse)( pa_channel_map*);
+pa_channel_map* (*pa_channel_map_init_mono_dylibloader_wrapper_pulse)( pa_channel_map*);
+pa_channel_map* (*pa_channel_map_init_stereo_dylibloader_wrapper_pulse)( pa_channel_map*);
+pa_channel_map* (*pa_channel_map_init_auto_dylibloader_wrapper_pulse)( pa_channel_map*, unsigned, pa_channel_map_def_t);
+pa_channel_map* (*pa_channel_map_init_extend_dylibloader_wrapper_pulse)( pa_channel_map*, unsigned, pa_channel_map_def_t);
+const char* (*pa_channel_position_to_string_dylibloader_wrapper_pulse)( pa_channel_position_t);
+pa_channel_position_t (*pa_channel_position_from_string_dylibloader_wrapper_pulse)(const char*);
+const char* (*pa_channel_position_to_pretty_string_dylibloader_wrapper_pulse)( pa_channel_position_t);
+char* (*pa_channel_map_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_channel_map*);
+pa_channel_map* (*pa_channel_map_parse_dylibloader_wrapper_pulse)( pa_channel_map*,const char*);
+int (*pa_channel_map_equal_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_channel_map*);
+int (*pa_channel_map_valid_dylibloader_wrapper_pulse)(const pa_channel_map*);
+int (*pa_channel_map_compatible_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_sample_spec*);
+int (*pa_channel_map_superset_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_channel_map*);
+int (*pa_channel_map_can_balance_dylibloader_wrapper_pulse)(const pa_channel_map*);
+int (*pa_channel_map_can_fade_dylibloader_wrapper_pulse)(const pa_channel_map*);
+int (*pa_channel_map_can_lfe_balance_dylibloader_wrapper_pulse)(const pa_channel_map*);
+const char* (*pa_channel_map_to_name_dylibloader_wrapper_pulse)(const pa_channel_map*);
+const char* (*pa_channel_map_to_pretty_name_dylibloader_wrapper_pulse)(const pa_channel_map*);
+int (*pa_channel_map_has_position_dylibloader_wrapper_pulse)(const pa_channel_map*, pa_channel_position_t);
+pa_channel_position_mask_t (*pa_channel_map_mask_dylibloader_wrapper_pulse)(const pa_channel_map*);
+const char* (*pa_encoding_to_string_dylibloader_wrapper_pulse)( pa_encoding_t);
+pa_encoding_t (*pa_encoding_from_string_dylibloader_wrapper_pulse)(const char*);
+pa_format_info* (*pa_format_info_new_dylibloader_wrapper_pulse)( void);
+pa_format_info* (*pa_format_info_copy_dylibloader_wrapper_pulse)(const pa_format_info*);
+void (*pa_format_info_free_dylibloader_wrapper_pulse)( pa_format_info*);
+int (*pa_format_info_valid_dylibloader_wrapper_pulse)(const pa_format_info*);
+int (*pa_format_info_is_pcm_dylibloader_wrapper_pulse)(const pa_format_info*);
+int (*pa_format_info_is_compatible_dylibloader_wrapper_pulse)(const pa_format_info*,const pa_format_info*);
+char* (*pa_format_info_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_format_info*);
+pa_format_info* (*pa_format_info_from_string_dylibloader_wrapper_pulse)(const char*);
+pa_format_info* (*pa_format_info_from_sample_spec_dylibloader_wrapper_pulse)(const pa_sample_spec*,const pa_channel_map*);
+int (*pa_format_info_to_sample_spec_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_spec*, pa_channel_map*);
+pa_prop_type_t (*pa_format_info_get_prop_type_dylibloader_wrapper_pulse)(const pa_format_info*,const char*);
+int (*pa_format_info_get_prop_int_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int*);
+int (*pa_format_info_get_prop_int_range_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int*, int*);
+int (*pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int**, int*);
+int (*pa_format_info_get_prop_string_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char**);
+int (*pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char***, int*);
+void (*pa_format_info_free_string_array_dylibloader_wrapper_pulse)( char**, int);
+int (*pa_format_info_get_sample_format_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_format_t*);
+int (*pa_format_info_get_rate_dylibloader_wrapper_pulse)(const pa_format_info*, uint32_t*);
+int (*pa_format_info_get_channels_dylibloader_wrapper_pulse)(const pa_format_info*, uint8_t*);
+int (*pa_format_info_get_channel_map_dylibloader_wrapper_pulse)(const pa_format_info*, pa_channel_map*);
+void (*pa_format_info_set_prop_int_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int);
+void (*pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const int*, int);
+void (*pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int, int);
+void (*pa_format_info_set_prop_string_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const char*);
+void (*pa_format_info_set_prop_string_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const char**, int);
+void (*pa_format_info_set_sample_format_dylibloader_wrapper_pulse)( pa_format_info*, pa_sample_format_t);
+void (*pa_format_info_set_rate_dylibloader_wrapper_pulse)( pa_format_info*, int);
+void (*pa_format_info_set_channels_dylibloader_wrapper_pulse)( pa_format_info*, int);
+void (*pa_format_info_set_channel_map_dylibloader_wrapper_pulse)( pa_format_info*,const pa_channel_map*);
+pa_operation* (*pa_operation_ref_dylibloader_wrapper_pulse)( pa_operation*);
+void (*pa_operation_unref_dylibloader_wrapper_pulse)( pa_operation*);
+void (*pa_operation_cancel_dylibloader_wrapper_pulse)( pa_operation*);
+pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)(const pa_operation*);
+void (*pa_operation_set_state_callback_dylibloader_wrapper_pulse)( pa_operation*, pa_operation_notify_cb_t, void*);
+pa_context* (*pa_context_new_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*);
+pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*,const pa_proplist*);
+void (*pa_context_unref_dylibloader_wrapper_pulse)( pa_context*);
+pa_context* (*pa_context_ref_dylibloader_wrapper_pulse)( pa_context*);
+void (*pa_context_set_state_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
+void (*pa_context_set_event_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_event_cb_t, void*);
+int (*pa_context_errno_dylibloader_wrapper_pulse)(const pa_context*);
+int (*pa_context_is_pending_dylibloader_wrapper_pulse)(const pa_context*);
+pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)(const pa_context*);
+int (*pa_context_connect_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_flags_t,const pa_spawn_api*);
+void (*pa_context_disconnect_dylibloader_wrapper_pulse)( pa_context*);
+pa_operation* (*pa_context_drain_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
+pa_operation* (*pa_context_exit_daemon_dylibloader_wrapper_pulse)( pa_context*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_default_sink_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_default_source_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+int (*pa_context_is_local_dylibloader_wrapper_pulse)(const pa_context*);
+pa_operation* (*pa_context_set_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+const char* (*pa_context_get_server_dylibloader_wrapper_pulse)(const pa_context*);
+uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
+uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
+pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t,const pa_proplist*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_proplist_remove_dylibloader_wrapper_pulse)( pa_context*,const char* [], pa_context_success_cb_t, void*);
+uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)(const pa_context*);
+pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)(const pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
+void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)(const pa_context*, pa_time_event*, pa_usec_t);
+size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)(const pa_context*,const pa_sample_spec*);
+int (*pa_context_load_cookie_from_file_dylibloader_wrapper_pulse)( pa_context*,const char*);
+int (*pa_cvolume_equal_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_cvolume*);
+pa_cvolume* (*pa_cvolume_init_dylibloader_wrapper_pulse)( pa_cvolume*);
+pa_cvolume* (*pa_cvolume_set_dylibloader_wrapper_pulse)( pa_cvolume*, unsigned, pa_volume_t);
+char* (*pa_cvolume_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*);
+char* (*pa_sw_cvolume_snprint_dB_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*);
+char* (*pa_cvolume_snprint_verbose_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*,const pa_channel_map*, int);
+char* (*pa_volume_snprint_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t);
+char* (*pa_sw_volume_snprint_dB_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t);
+char* (*pa_volume_snprint_verbose_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t, int);
+pa_volume_t (*pa_cvolume_avg_dylibloader_wrapper_pulse)(const pa_cvolume*);
+pa_volume_t (*pa_cvolume_avg_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+pa_volume_t (*pa_cvolume_max_dylibloader_wrapper_pulse)(const pa_cvolume*);
+pa_volume_t (*pa_cvolume_max_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+pa_volume_t (*pa_cvolume_min_dylibloader_wrapper_pulse)(const pa_cvolume*);
+pa_volume_t (*pa_cvolume_min_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+int (*pa_cvolume_valid_dylibloader_wrapper_pulse)(const pa_cvolume*);
+int (*pa_cvolume_channels_equal_to_dylibloader_wrapper_pulse)(const pa_cvolume*, pa_volume_t);
+pa_volume_t (*pa_sw_volume_multiply_dylibloader_wrapper_pulse)( pa_volume_t, pa_volume_t);
+pa_cvolume* (*pa_sw_cvolume_multiply_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+pa_cvolume* (*pa_sw_cvolume_multiply_scalar_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*, pa_volume_t);
+pa_volume_t (*pa_sw_volume_divide_dylibloader_wrapper_pulse)( pa_volume_t, pa_volume_t);
+pa_cvolume* (*pa_sw_cvolume_divide_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+pa_cvolume* (*pa_sw_cvolume_divide_scalar_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*, pa_volume_t);
+pa_volume_t (*pa_sw_volume_from_dB_dylibloader_wrapper_pulse)( double);
+double (*pa_sw_volume_to_dB_dylibloader_wrapper_pulse)( pa_volume_t);
+pa_volume_t (*pa_sw_volume_from_linear_dylibloader_wrapper_pulse)( double);
+double (*pa_sw_volume_to_linear_dylibloader_wrapper_pulse)( pa_volume_t);
+pa_cvolume* (*pa_cvolume_remap_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*,const pa_channel_map*);
+int (*pa_cvolume_compatible_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_sample_spec*);
+int (*pa_cvolume_compatible_with_channel_map_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+float (*pa_cvolume_get_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+pa_cvolume* (*pa_cvolume_set_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+float (*pa_cvolume_get_fade_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+pa_cvolume* (*pa_cvolume_set_fade_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+float (*pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+pa_cvolume* (*pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+pa_cvolume* (*pa_cvolume_scale_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t,const pa_channel_map*, pa_channel_position_mask_t);
+pa_cvolume* (*pa_cvolume_set_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t, pa_volume_t);
+pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
+pa_cvolume* (*pa_cvolume_merge_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+pa_cvolume* (*pa_cvolume_inc_clamp_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_volume_t);
+pa_cvolume* (*pa_cvolume_inc_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+pa_cvolume* (*pa_cvolume_dec_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+pa_stream* (*pa_stream_new_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_sample_spec*,const pa_channel_map*);
+pa_stream* (*pa_stream_new_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_sample_spec*,const pa_channel_map*, pa_proplist*);
+pa_stream* (*pa_stream_new_extended_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_format_info**, unsigned int, pa_proplist*);
+void (*pa_stream_unref_dylibloader_wrapper_pulse)( pa_stream*);
+pa_stream* (*pa_stream_ref_dylibloader_wrapper_pulse)( pa_stream*);
+pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)(const pa_stream*);
+pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)(const pa_stream*);
+uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)(const pa_stream*);
+uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)(const pa_stream*);
+const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)(const pa_stream*);
+int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)(const pa_stream*);
+int (*pa_stream_is_corked_dylibloader_wrapper_pulse)(const pa_stream*);
+int (*pa_stream_connect_playback_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t,const pa_cvolume*, pa_stream*);
+int (*pa_stream_connect_record_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t);
+int (*pa_stream_disconnect_dylibloader_wrapper_pulse)( pa_stream*);
+int (*pa_stream_begin_write_dylibloader_wrapper_pulse)( pa_stream*, void**, size_t*);
+int (*pa_stream_cancel_write_dylibloader_wrapper_pulse)( pa_stream*);
+int (*pa_stream_write_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, int64_t, pa_seek_mode_t);
+int (*pa_stream_write_ext_free_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, void*, int64_t, pa_seek_mode_t);
+int (*pa_stream_peek_dylibloader_wrapper_pulse)( pa_stream*,const void**, size_t*);
+int (*pa_stream_drop_dylibloader_wrapper_pulse)( pa_stream*);
+size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+pa_operation* (*pa_stream_drain_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_update_timing_info_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+void (*pa_stream_set_state_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_write_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
+void (*pa_stream_set_read_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
+void (*pa_stream_set_overflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)(const pa_stream*);
+void (*pa_stream_set_underflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_started_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_moved_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_suspended_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+void (*pa_stream_set_event_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_event_cb_t, void*);
+void (*pa_stream_set_buffer_attr_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+pa_operation* (*pa_stream_cork_dylibloader_wrapper_pulse)( pa_stream*, int, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_flush_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_prebuf_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_trigger_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_set_name_dylibloader_wrapper_pulse)( pa_stream*,const char*, pa_stream_success_cb_t, void*);
+int (*pa_stream_get_time_dylibloader_wrapper_pulse)( pa_stream*, pa_usec_t*);
+int (*pa_stream_get_latency_dylibloader_wrapper_pulse)( pa_stream*, pa_usec_t*, int*);
+const pa_timing_info* (*pa_stream_get_timing_info_dylibloader_wrapper_pulse)( pa_stream*);
+const pa_sample_spec* (*pa_stream_get_sample_spec_dylibloader_wrapper_pulse)( pa_stream*);
+const pa_channel_map* (*pa_stream_get_channel_map_dylibloader_wrapper_pulse)( pa_stream*);
+const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)(const pa_stream*);
+const pa_buffer_attr* (*pa_stream_get_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*);
+pa_operation* (*pa_stream_set_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*,const pa_buffer_attr*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_update_sample_rate_dylibloader_wrapper_pulse)( pa_stream*, uint32_t, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_proplist_update_dylibloader_wrapper_pulse)( pa_stream*, pa_update_mode_t, pa_proplist*, pa_stream_success_cb_t, void*);
+pa_operation* (*pa_stream_proplist_remove_dylibloader_wrapper_pulse)( pa_stream*,const char* [], pa_stream_success_cb_t, void*);
+int (*pa_stream_set_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*, uint32_t);
+uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)(const pa_stream*);
+pa_operation* (*pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sink_info_cb_t, void*);
+pa_operation* (*pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_info_cb_t, void*);
+pa_operation* (*pa_context_get_sink_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_info_cb_t, void*);
+pa_operation* (*pa_context_set_sink_volume_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_volume_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_mute_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_mute_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_suspend_sink_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_suspend_sink_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_port_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_port_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_source_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_source_info_cb_t, void*);
+pa_operation* (*pa_context_get_source_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_source_info_cb_t, void*);
+pa_operation* (*pa_context_get_source_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_source_info_cb_t, void*);
+pa_operation* (*pa_context_set_source_volume_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_volume_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_mute_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_mute_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_suspend_source_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_suspend_source_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_port_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_port_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_server_info_dylibloader_wrapper_pulse)( pa_context*, pa_server_info_cb_t, void*);
+pa_operation* (*pa_context_get_module_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_module_info_cb_t, void*);
+pa_operation* (*pa_context_get_module_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_module_info_cb_t, void*);
+pa_operation* (*pa_context_load_module_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_index_cb_t, void*);
+pa_operation* (*pa_context_unload_module_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_client_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_client_info_cb_t, void*);
+pa_operation* (*pa_context_get_client_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_client_info_cb_t, void*);
+pa_operation* (*pa_context_kill_client_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_card_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_card_info_cb_t, void*);
+pa_operation* (*pa_context_get_card_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_card_info_cb_t, void*);
+pa_operation* (*pa_context_get_card_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_card_info_cb_t, void*);
+pa_operation* (*pa_context_set_card_profile_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_card_profile_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_port_latency_offset_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, int64_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_sink_input_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_input_info_cb_t, void*);
+pa_operation* (*pa_context_get_sink_input_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_input_info_cb_t, void*);
+pa_operation* (*pa_context_move_sink_input_by_name_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_move_sink_input_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_input_volume_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_sink_input_mute_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_kill_sink_input_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_get_source_output_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_source_output_info_cb_t, void*);
+pa_operation* (*pa_context_get_source_output_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_source_output_info_cb_t, void*);
+pa_operation* (*pa_context_move_source_output_by_name_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_move_source_output_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_output_volume_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_set_source_output_mute_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_kill_source_output_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_stat_dylibloader_wrapper_pulse)( pa_context*, pa_stat_info_cb_t, void*);
+pa_operation* (*pa_context_get_sample_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sample_info_cb_t, void*);
+pa_operation* (*pa_context_get_sample_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sample_info_cb_t, void*);
+pa_operation* (*pa_context_get_sample_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sample_info_cb_t, void*);
+pa_operation* (*pa_context_get_autoload_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t, pa_autoload_info_cb_t, void*);
+pa_operation* (*pa_context_get_autoload_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_autoload_info_cb_t, void*);
+pa_operation* (*pa_context_get_autoload_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_autoload_info_cb_t, void*);
+pa_operation* (*pa_context_add_autoload_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t,const char*,const char*, pa_context_index_cb_t, void*);
+pa_operation* (*pa_context_remove_autoload_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_remove_autoload_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_subscribe_dylibloader_wrapper_pulse)( pa_context*, pa_subscription_mask_t, pa_context_success_cb_t, void*);
+void (*pa_context_set_subscribe_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_subscribe_cb_t, void*);
+int (*pa_stream_connect_upload_dylibloader_wrapper_pulse)( pa_stream*, size_t);
+int (*pa_stream_finish_upload_dylibloader_wrapper_pulse)( pa_stream*);
+pa_operation* (*pa_context_remove_sample_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_play_sample_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_context_success_cb_t, void*);
+pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t,const pa_proplist*, pa_context_play_sample_cb_t, void*);
+const char* (*pa_strerror_dylibloader_wrapper_pulse)( int);
+void* (*pa_xmalloc_dylibloader_wrapper_pulse)( size_t);
+void* (*pa_xmalloc0_dylibloader_wrapper_pulse)( size_t);
+void* (*pa_xrealloc_dylibloader_wrapper_pulse)( void*, size_t);
+void (*pa_xfree_dylibloader_wrapper_pulse)( void*);
+char* (*pa_xstrdup_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_xstrndup_dylibloader_wrapper_pulse)(const char*, size_t);
+void* (*pa_xmemdup_dylibloader_wrapper_pulse)(const void*, size_t);
+char* (*pa_utf8_valid_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_ascii_valid_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_utf8_filter_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_ascii_filter_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_utf8_to_locale_dylibloader_wrapper_pulse)(const char*);
+char* (*pa_locale_to_utf8_dylibloader_wrapper_pulse)(const char*);
+pa_threaded_mainloop* (*pa_threaded_mainloop_new_dylibloader_wrapper_pulse)( void);
+void (*pa_threaded_mainloop_free_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+int (*pa_threaded_mainloop_start_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_stop_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_lock_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_wait_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_signal_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, int);
+void (*pa_threaded_mainloop_accept_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_threaded_mainloop*);
+pa_mainloop_api* (*pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+int (*pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+void (*pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse)( pa_threaded_mainloop*,const char*);
+void (*pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, void*, void*);
+pa_mainloop* (*pa_mainloop_new_dylibloader_wrapper_pulse)( void);
+void (*pa_mainloop_free_dylibloader_wrapper_pulse)( pa_mainloop*);
+int (*pa_mainloop_prepare_dylibloader_wrapper_pulse)( pa_mainloop*, int);
+int (*pa_mainloop_poll_dylibloader_wrapper_pulse)( pa_mainloop*);
+int (*pa_mainloop_dispatch_dylibloader_wrapper_pulse)( pa_mainloop*);
+int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_mainloop*);
+int (*pa_mainloop_iterate_dylibloader_wrapper_pulse)( pa_mainloop*, int, int*);
+int (*pa_mainloop_run_dylibloader_wrapper_pulse)( pa_mainloop*, int*);
+pa_mainloop_api* (*pa_mainloop_get_api_dylibloader_wrapper_pulse)( pa_mainloop*);
+void (*pa_mainloop_quit_dylibloader_wrapper_pulse)( pa_mainloop*, int);
+void (*pa_mainloop_wakeup_dylibloader_wrapper_pulse)( pa_mainloop*);
+void (*pa_mainloop_set_poll_func_dylibloader_wrapper_pulse)( pa_mainloop*, pa_poll_func, void*);
+int (*pa_signal_init_dylibloader_wrapper_pulse)( pa_mainloop_api*);
+void (*pa_signal_done_dylibloader_wrapper_pulse)( void);
+pa_signal_event* (*pa_signal_new_dylibloader_wrapper_pulse)( int, pa_signal_cb_t, void*);
+void (*pa_signal_free_dylibloader_wrapper_pulse)( pa_signal_event*);
+void (*pa_signal_set_destroy_dylibloader_wrapper_pulse)( pa_signal_event*, pa_signal_destroy_cb_t);
+char* (*pa_get_user_name_dylibloader_wrapper_pulse)( char*, size_t);
+char* (*pa_get_host_name_dylibloader_wrapper_pulse)( char*, size_t);
+char* (*pa_get_fqdn_dylibloader_wrapper_pulse)( char*, size_t);
+char* (*pa_get_home_dir_dylibloader_wrapper_pulse)( char*, size_t);
+char* (*pa_get_binary_name_dylibloader_wrapper_pulse)( char*, size_t);
+char* (*pa_path_get_filename_dylibloader_wrapper_pulse)(const char*);
+int (*pa_msleep_dylibloader_wrapper_pulse)( unsigned long);
+int (*pa_thread_make_realtime_dylibloader_wrapper_pulse)( int);
+struct timeval* (*pa_gettimeofday_dylibloader_wrapper_pulse)(struct timeval*);
+pa_usec_t (*pa_timeval_diff_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
+int (*pa_timeval_cmp_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
+pa_usec_t (*pa_timeval_age_dylibloader_wrapper_pulse)(struct timeval*);
+struct timeval* (*pa_timeval_add_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+struct timeval* (*pa_timeval_sub_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+struct timeval* (*pa_timeval_store_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+pa_usec_t (*pa_timeval_load_dylibloader_wrapper_pulse)(struct timeval*);
+pa_usec_t (*pa_rtclock_now_dylibloader_wrapper_pulse)( void);
+int initialize_pulse(int verbose) {
+ void *handle;
+ char *error;
+ handle = dlopen("libpulse.so.0", RTLD_LAZY);
+ if (!handle) {
+ if (verbose) {
+ fprintf(stderr, "%s\n", dlerror());
+ }
+ return(1);
+ }
+ dlerror();
+// pa_get_library_version
+ *(void **) (&pa_get_library_version_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_library_version");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_bytes_per_second
+ *(void **) (&pa_bytes_per_second_dylibloader_wrapper_pulse) = dlsym(handle, "pa_bytes_per_second");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_frame_size
+ *(void **) (&pa_frame_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_frame_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_size
+ *(void **) (&pa_sample_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_size_of_format
+ *(void **) (&pa_sample_size_of_format_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_size_of_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_bytes_to_usec
+ *(void **) (&pa_bytes_to_usec_dylibloader_wrapper_pulse) = dlsym(handle, "pa_bytes_to_usec");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_usec_to_bytes
+ *(void **) (&pa_usec_to_bytes_dylibloader_wrapper_pulse) = dlsym(handle, "pa_usec_to_bytes");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_spec_init
+ *(void **) (&pa_sample_spec_init_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_spec_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_format_valid
+ *(void **) (&pa_sample_format_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_format_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_rate_valid
+ *(void **) (&pa_sample_rate_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_rate_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channels_valid
+ *(void **) (&pa_channels_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channels_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_spec_valid
+ *(void **) (&pa_sample_spec_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_spec_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_spec_equal
+ *(void **) (&pa_sample_spec_equal_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_spec_equal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_format_to_string
+ *(void **) (&pa_sample_format_to_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_format_to_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_parse_sample_format
+ *(void **) (&pa_parse_sample_format_dylibloader_wrapper_pulse) = dlsym(handle, "pa_parse_sample_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_spec_snprint
+ *(void **) (&pa_sample_spec_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_spec_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_bytes_snprint
+ *(void **) (&pa_bytes_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_bytes_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_format_is_le
+ *(void **) (&pa_sample_format_is_le_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_format_is_le");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sample_format_is_be
+ *(void **) (&pa_sample_format_is_be_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sample_format_is_be");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_direction_valid
+ *(void **) (&pa_direction_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_direction_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_direction_to_string
+ *(void **) (&pa_direction_to_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_direction_to_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_api_once
+ *(void **) (&pa_mainloop_api_once_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_api_once");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_new
+ *(void **) (&pa_proplist_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_free
+ *(void **) (&pa_proplist_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_key_valid
+ *(void **) (&pa_proplist_key_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_key_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_sets
+ *(void **) (&pa_proplist_sets_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_sets");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_setp
+ *(void **) (&pa_proplist_setp_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_setp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_setf
+ *(void **) (&pa_proplist_setf_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_setf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_set
+ *(void **) (&pa_proplist_set_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_gets
+ *(void **) (&pa_proplist_gets_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_gets");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_get
+ *(void **) (&pa_proplist_get_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_get");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_update
+ *(void **) (&pa_proplist_update_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_unset
+ *(void **) (&pa_proplist_unset_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_unset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_unset_many
+ *(void **) (&pa_proplist_unset_many_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_unset_many");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_iterate
+ *(void **) (&pa_proplist_iterate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_iterate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_to_string
+ *(void **) (&pa_proplist_to_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_to_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_to_string_sep
+ *(void **) (&pa_proplist_to_string_sep_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_to_string_sep");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_from_string
+ *(void **) (&pa_proplist_from_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_contains
+ *(void **) (&pa_proplist_contains_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_contains");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_clear
+ *(void **) (&pa_proplist_clear_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_copy
+ *(void **) (&pa_proplist_copy_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_size
+ *(void **) (&pa_proplist_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_isempty
+ *(void **) (&pa_proplist_isempty_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_isempty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_proplist_equal
+ *(void **) (&pa_proplist_equal_dylibloader_wrapper_pulse) = dlsym(handle, "pa_proplist_equal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_init
+ *(void **) (&pa_channel_map_init_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_init_mono
+ *(void **) (&pa_channel_map_init_mono_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_init_mono");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_init_stereo
+ *(void **) (&pa_channel_map_init_stereo_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_init_stereo");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_init_auto
+ *(void **) (&pa_channel_map_init_auto_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_init_auto");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_init_extend
+ *(void **) (&pa_channel_map_init_extend_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_init_extend");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_position_to_string
+ *(void **) (&pa_channel_position_to_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_position_to_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_position_from_string
+ *(void **) (&pa_channel_position_from_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_position_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_position_to_pretty_string
+ *(void **) (&pa_channel_position_to_pretty_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_position_to_pretty_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_snprint
+ *(void **) (&pa_channel_map_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_parse
+ *(void **) (&pa_channel_map_parse_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_parse");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_equal
+ *(void **) (&pa_channel_map_equal_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_equal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_valid
+ *(void **) (&pa_channel_map_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_compatible
+ *(void **) (&pa_channel_map_compatible_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_compatible");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_superset
+ *(void **) (&pa_channel_map_superset_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_superset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_can_balance
+ *(void **) (&pa_channel_map_can_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_can_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_can_fade
+ *(void **) (&pa_channel_map_can_fade_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_can_fade");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_can_lfe_balance
+ *(void **) (&pa_channel_map_can_lfe_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_can_lfe_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_to_name
+ *(void **) (&pa_channel_map_to_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_to_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_to_pretty_name
+ *(void **) (&pa_channel_map_to_pretty_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_to_pretty_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_has_position
+ *(void **) (&pa_channel_map_has_position_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_has_position");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_channel_map_mask
+ *(void **) (&pa_channel_map_mask_dylibloader_wrapper_pulse) = dlsym(handle, "pa_channel_map_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_encoding_to_string
+ *(void **) (&pa_encoding_to_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_encoding_to_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_encoding_from_string
+ *(void **) (&pa_encoding_from_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_encoding_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_new
+ *(void **) (&pa_format_info_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_copy
+ *(void **) (&pa_format_info_copy_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_copy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_free
+ *(void **) (&pa_format_info_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_valid
+ *(void **) (&pa_format_info_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_is_pcm
+ *(void **) (&pa_format_info_is_pcm_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_is_pcm");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_is_compatible
+ *(void **) (&pa_format_info_is_compatible_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_is_compatible");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_snprint
+ *(void **) (&pa_format_info_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_from_string
+ *(void **) (&pa_format_info_from_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_from_sample_spec
+ *(void **) (&pa_format_info_from_sample_spec_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_from_sample_spec");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_to_sample_spec
+ *(void **) (&pa_format_info_to_sample_spec_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_to_sample_spec");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_type
+ *(void **) (&pa_format_info_get_prop_type_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_type");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_int
+ *(void **) (&pa_format_info_get_prop_int_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_int");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_int_range
+ *(void **) (&pa_format_info_get_prop_int_range_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_int_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_int_array
+ *(void **) (&pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_int_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_string
+ *(void **) (&pa_format_info_get_prop_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_prop_string_array
+ *(void **) (&pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_prop_string_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_free_string_array
+ *(void **) (&pa_format_info_free_string_array_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_free_string_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_sample_format
+ *(void **) (&pa_format_info_get_sample_format_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_sample_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_rate
+ *(void **) (&pa_format_info_get_rate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_channels
+ *(void **) (&pa_format_info_get_channels_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_get_channel_map
+ *(void **) (&pa_format_info_get_channel_map_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_get_channel_map");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_prop_int
+ *(void **) (&pa_format_info_set_prop_int_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_int");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_prop_int_array
+ *(void **) (&pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_int_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_prop_int_range
+ *(void **) (&pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_int_range");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_prop_string
+ *(void **) (&pa_format_info_set_prop_string_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_prop_string_array
+ *(void **) (&pa_format_info_set_prop_string_array_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_prop_string_array");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_sample_format
+ *(void **) (&pa_format_info_set_sample_format_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_sample_format");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_rate
+ *(void **) (&pa_format_info_set_rate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_channels
+ *(void **) (&pa_format_info_set_channels_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_channels");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_format_info_set_channel_map
+ *(void **) (&pa_format_info_set_channel_map_dylibloader_wrapper_pulse) = dlsym(handle, "pa_format_info_set_channel_map");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_operation_ref
+ *(void **) (&pa_operation_ref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_operation_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_operation_unref
+ *(void **) (&pa_operation_unref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_operation_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_operation_cancel
+ *(void **) (&pa_operation_cancel_dylibloader_wrapper_pulse) = dlsym(handle, "pa_operation_cancel");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_operation_get_state
+ *(void **) (&pa_operation_get_state_dylibloader_wrapper_pulse) = dlsym(handle, "pa_operation_get_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_operation_set_state_callback
+ *(void **) (&pa_operation_set_state_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_operation_set_state_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_new
+ *(void **) (&pa_context_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_new_with_proplist
+ *(void **) (&pa_context_new_with_proplist_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_new_with_proplist");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_unref
+ *(void **) (&pa_context_unref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_ref
+ *(void **) (&pa_context_ref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_state_callback
+ *(void **) (&pa_context_set_state_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_state_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_event_callback
+ *(void **) (&pa_context_set_event_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_event_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_errno
+ *(void **) (&pa_context_errno_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_errno");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_is_pending
+ *(void **) (&pa_context_is_pending_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_is_pending");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_state
+ *(void **) (&pa_context_get_state_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_connect
+ *(void **) (&pa_context_connect_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_connect");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_disconnect
+ *(void **) (&pa_context_disconnect_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_disconnect");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_drain
+ *(void **) (&pa_context_drain_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_drain");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_exit_daemon
+ *(void **) (&pa_context_exit_daemon_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_exit_daemon");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_default_sink
+ *(void **) (&pa_context_set_default_sink_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_default_sink");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_default_source
+ *(void **) (&pa_context_set_default_source_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_default_source");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_is_local
+ *(void **) (&pa_context_is_local_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_is_local");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_name
+ *(void **) (&pa_context_set_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_server
+ *(void **) (&pa_context_get_server_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_server");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_protocol_version
+ *(void **) (&pa_context_get_protocol_version_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_protocol_version");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_server_protocol_version
+ *(void **) (&pa_context_get_server_protocol_version_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_server_protocol_version");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_proplist_update
+ *(void **) (&pa_context_proplist_update_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_proplist_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_proplist_remove
+ *(void **) (&pa_context_proplist_remove_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_proplist_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_index
+ *(void **) (&pa_context_get_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_rttime_new
+ *(void **) (&pa_context_rttime_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_rttime_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_rttime_restart
+ *(void **) (&pa_context_rttime_restart_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_rttime_restart");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_tile_size
+ *(void **) (&pa_context_get_tile_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_tile_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_load_cookie_from_file
+ *(void **) (&pa_context_load_cookie_from_file_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_load_cookie_from_file");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_equal
+ *(void **) (&pa_cvolume_equal_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_equal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_init
+ *(void **) (&pa_cvolume_init_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_set
+ *(void **) (&pa_cvolume_set_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_set");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_snprint
+ *(void **) (&pa_cvolume_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_cvolume_snprint_dB
+ *(void **) (&pa_sw_cvolume_snprint_dB_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_cvolume_snprint_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_snprint_verbose
+ *(void **) (&pa_cvolume_snprint_verbose_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_snprint_verbose");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_volume_snprint
+ *(void **) (&pa_volume_snprint_dylibloader_wrapper_pulse) = dlsym(handle, "pa_volume_snprint");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_snprint_dB
+ *(void **) (&pa_sw_volume_snprint_dB_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_snprint_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_volume_snprint_verbose
+ *(void **) (&pa_volume_snprint_verbose_dylibloader_wrapper_pulse) = dlsym(handle, "pa_volume_snprint_verbose");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_avg
+ *(void **) (&pa_cvolume_avg_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_avg");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_avg_mask
+ *(void **) (&pa_cvolume_avg_mask_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_avg_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_max
+ *(void **) (&pa_cvolume_max_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_max");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_max_mask
+ *(void **) (&pa_cvolume_max_mask_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_max_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_min
+ *(void **) (&pa_cvolume_min_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_min");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_min_mask
+ *(void **) (&pa_cvolume_min_mask_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_min_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_valid
+ *(void **) (&pa_cvolume_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_channels_equal_to
+ *(void **) (&pa_cvolume_channels_equal_to_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_channels_equal_to");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_multiply
+ *(void **) (&pa_sw_volume_multiply_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_multiply");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_cvolume_multiply
+ *(void **) (&pa_sw_cvolume_multiply_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_cvolume_multiply");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_cvolume_multiply_scalar
+ *(void **) (&pa_sw_cvolume_multiply_scalar_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_cvolume_multiply_scalar");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_divide
+ *(void **) (&pa_sw_volume_divide_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_divide");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_cvolume_divide
+ *(void **) (&pa_sw_cvolume_divide_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_cvolume_divide");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_cvolume_divide_scalar
+ *(void **) (&pa_sw_cvolume_divide_scalar_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_cvolume_divide_scalar");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_from_dB
+ *(void **) (&pa_sw_volume_from_dB_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_from_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_to_dB
+ *(void **) (&pa_sw_volume_to_dB_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_to_dB");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_from_linear
+ *(void **) (&pa_sw_volume_from_linear_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_from_linear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_sw_volume_to_linear
+ *(void **) (&pa_sw_volume_to_linear_dylibloader_wrapper_pulse) = dlsym(handle, "pa_sw_volume_to_linear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_remap
+ *(void **) (&pa_cvolume_remap_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_remap");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_compatible
+ *(void **) (&pa_cvolume_compatible_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_compatible");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_compatible_with_channel_map
+ *(void **) (&pa_cvolume_compatible_with_channel_map_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_compatible_with_channel_map");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_get_balance
+ *(void **) (&pa_cvolume_get_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_get_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_set_balance
+ *(void **) (&pa_cvolume_set_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_set_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_get_fade
+ *(void **) (&pa_cvolume_get_fade_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_get_fade");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_set_fade
+ *(void **) (&pa_cvolume_set_fade_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_set_fade");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_get_lfe_balance
+ *(void **) (&pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_get_lfe_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_set_lfe_balance
+ *(void **) (&pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_set_lfe_balance");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_scale
+ *(void **) (&pa_cvolume_scale_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_scale");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_scale_mask
+ *(void **) (&pa_cvolume_scale_mask_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_scale_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_set_position
+ *(void **) (&pa_cvolume_set_position_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_set_position");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_get_position
+ *(void **) (&pa_cvolume_get_position_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_get_position");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_merge
+ *(void **) (&pa_cvolume_merge_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_merge");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_inc_clamp
+ *(void **) (&pa_cvolume_inc_clamp_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_inc_clamp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_inc
+ *(void **) (&pa_cvolume_inc_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_inc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_cvolume_dec
+ *(void **) (&pa_cvolume_dec_dylibloader_wrapper_pulse) = dlsym(handle, "pa_cvolume_dec");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_new
+ *(void **) (&pa_stream_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_new_with_proplist
+ *(void **) (&pa_stream_new_with_proplist_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_new_with_proplist");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_new_extended
+ *(void **) (&pa_stream_new_extended_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_new_extended");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_unref
+ *(void **) (&pa_stream_unref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_ref
+ *(void **) (&pa_stream_ref_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_state
+ *(void **) (&pa_stream_get_state_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_state");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_context
+ *(void **) (&pa_stream_get_context_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_context");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_index
+ *(void **) (&pa_stream_get_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_device_index
+ *(void **) (&pa_stream_get_device_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_device_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_device_name
+ *(void **) (&pa_stream_get_device_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_device_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_is_suspended
+ *(void **) (&pa_stream_is_suspended_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_is_suspended");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_is_corked
+ *(void **) (&pa_stream_is_corked_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_is_corked");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_connect_playback
+ *(void **) (&pa_stream_connect_playback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_connect_playback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_connect_record
+ *(void **) (&pa_stream_connect_record_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_connect_record");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_disconnect
+ *(void **) (&pa_stream_disconnect_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_disconnect");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_begin_write
+ *(void **) (&pa_stream_begin_write_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_begin_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_cancel_write
+ *(void **) (&pa_stream_cancel_write_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_cancel_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_write
+ *(void **) (&pa_stream_write_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_write");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_write_ext_free
+ *(void **) (&pa_stream_write_ext_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_write_ext_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_peek
+ *(void **) (&pa_stream_peek_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_peek");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_drop
+ *(void **) (&pa_stream_drop_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_drop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_writable_size
+ *(void **) (&pa_stream_writable_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_writable_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_readable_size
+ *(void **) (&pa_stream_readable_size_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_readable_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_drain
+ *(void **) (&pa_stream_drain_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_drain");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_update_timing_info
+ *(void **) (&pa_stream_update_timing_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_update_timing_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_state_callback
+ *(void **) (&pa_stream_set_state_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_state_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_write_callback
+ *(void **) (&pa_stream_set_write_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_write_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_read_callback
+ *(void **) (&pa_stream_set_read_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_read_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_overflow_callback
+ *(void **) (&pa_stream_set_overflow_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_overflow_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_underflow_index
+ *(void **) (&pa_stream_get_underflow_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_underflow_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_underflow_callback
+ *(void **) (&pa_stream_set_underflow_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_underflow_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_started_callback
+ *(void **) (&pa_stream_set_started_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_started_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_latency_update_callback
+ *(void **) (&pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_latency_update_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_moved_callback
+ *(void **) (&pa_stream_set_moved_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_moved_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_suspended_callback
+ *(void **) (&pa_stream_set_suspended_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_suspended_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_event_callback
+ *(void **) (&pa_stream_set_event_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_event_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_buffer_attr_callback
+ *(void **) (&pa_stream_set_buffer_attr_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_buffer_attr_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_cork
+ *(void **) (&pa_stream_cork_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_cork");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_flush
+ *(void **) (&pa_stream_flush_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_flush");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_prebuf
+ *(void **) (&pa_stream_prebuf_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_prebuf");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_trigger
+ *(void **) (&pa_stream_trigger_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_trigger");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_name
+ *(void **) (&pa_stream_set_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_time
+ *(void **) (&pa_stream_get_time_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_time");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_latency
+ *(void **) (&pa_stream_get_latency_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_latency");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_timing_info
+ *(void **) (&pa_stream_get_timing_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_timing_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_sample_spec
+ *(void **) (&pa_stream_get_sample_spec_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_sample_spec");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_channel_map
+ *(void **) (&pa_stream_get_channel_map_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_channel_map");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_format_info
+ *(void **) (&pa_stream_get_format_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_format_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_buffer_attr
+ *(void **) (&pa_stream_get_buffer_attr_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_buffer_attr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_buffer_attr
+ *(void **) (&pa_stream_set_buffer_attr_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_buffer_attr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_update_sample_rate
+ *(void **) (&pa_stream_update_sample_rate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_update_sample_rate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_proplist_update
+ *(void **) (&pa_stream_proplist_update_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_proplist_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_proplist_remove
+ *(void **) (&pa_stream_proplist_remove_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_proplist_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_set_monitor_stream
+ *(void **) (&pa_stream_set_monitor_stream_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_set_monitor_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_get_monitor_stream
+ *(void **) (&pa_stream_get_monitor_stream_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_get_monitor_stream");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sink_info_by_name
+ *(void **) (&pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sink_info_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sink_info_by_index
+ *(void **) (&pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sink_info_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sink_info_list
+ *(void **) (&pa_context_get_sink_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sink_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_volume_by_index
+ *(void **) (&pa_context_set_sink_volume_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_volume_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_volume_by_name
+ *(void **) (&pa_context_set_sink_volume_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_volume_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_mute_by_index
+ *(void **) (&pa_context_set_sink_mute_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_mute_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_mute_by_name
+ *(void **) (&pa_context_set_sink_mute_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_mute_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_suspend_sink_by_name
+ *(void **) (&pa_context_suspend_sink_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_suspend_sink_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_suspend_sink_by_index
+ *(void **) (&pa_context_suspend_sink_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_suspend_sink_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_port_by_index
+ *(void **) (&pa_context_set_sink_port_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_port_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_port_by_name
+ *(void **) (&pa_context_set_sink_port_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_port_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_source_info_by_name
+ *(void **) (&pa_context_get_source_info_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_source_info_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_source_info_by_index
+ *(void **) (&pa_context_get_source_info_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_source_info_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_source_info_list
+ *(void **) (&pa_context_get_source_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_source_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_volume_by_index
+ *(void **) (&pa_context_set_source_volume_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_volume_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_volume_by_name
+ *(void **) (&pa_context_set_source_volume_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_volume_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_mute_by_index
+ *(void **) (&pa_context_set_source_mute_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_mute_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_mute_by_name
+ *(void **) (&pa_context_set_source_mute_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_mute_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_suspend_source_by_name
+ *(void **) (&pa_context_suspend_source_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_suspend_source_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_suspend_source_by_index
+ *(void **) (&pa_context_suspend_source_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_suspend_source_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_port_by_index
+ *(void **) (&pa_context_set_source_port_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_port_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_port_by_name
+ *(void **) (&pa_context_set_source_port_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_port_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_server_info
+ *(void **) (&pa_context_get_server_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_server_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_module_info
+ *(void **) (&pa_context_get_module_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_module_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_module_info_list
+ *(void **) (&pa_context_get_module_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_module_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_load_module
+ *(void **) (&pa_context_load_module_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_load_module");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_unload_module
+ *(void **) (&pa_context_unload_module_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_unload_module");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_client_info
+ *(void **) (&pa_context_get_client_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_client_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_client_info_list
+ *(void **) (&pa_context_get_client_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_client_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_kill_client
+ *(void **) (&pa_context_kill_client_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_kill_client");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_card_info_by_index
+ *(void **) (&pa_context_get_card_info_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_card_info_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_card_info_by_name
+ *(void **) (&pa_context_get_card_info_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_card_info_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_card_info_list
+ *(void **) (&pa_context_get_card_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_card_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_card_profile_by_index
+ *(void **) (&pa_context_set_card_profile_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_card_profile_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_card_profile_by_name
+ *(void **) (&pa_context_set_card_profile_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_card_profile_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_port_latency_offset
+ *(void **) (&pa_context_set_port_latency_offset_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_port_latency_offset");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sink_input_info
+ *(void **) (&pa_context_get_sink_input_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sink_input_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sink_input_info_list
+ *(void **) (&pa_context_get_sink_input_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sink_input_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_move_sink_input_by_name
+ *(void **) (&pa_context_move_sink_input_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_move_sink_input_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_move_sink_input_by_index
+ *(void **) (&pa_context_move_sink_input_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_move_sink_input_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_input_volume
+ *(void **) (&pa_context_set_sink_input_volume_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_input_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_sink_input_mute
+ *(void **) (&pa_context_set_sink_input_mute_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_sink_input_mute");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_kill_sink_input
+ *(void **) (&pa_context_kill_sink_input_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_kill_sink_input");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_source_output_info
+ *(void **) (&pa_context_get_source_output_info_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_source_output_info");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_source_output_info_list
+ *(void **) (&pa_context_get_source_output_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_source_output_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_move_source_output_by_name
+ *(void **) (&pa_context_move_source_output_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_move_source_output_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_move_source_output_by_index
+ *(void **) (&pa_context_move_source_output_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_move_source_output_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_output_volume
+ *(void **) (&pa_context_set_source_output_volume_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_output_volume");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_source_output_mute
+ *(void **) (&pa_context_set_source_output_mute_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_source_output_mute");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_kill_source_output
+ *(void **) (&pa_context_kill_source_output_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_kill_source_output");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_stat
+ *(void **) (&pa_context_stat_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_stat");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sample_info_by_name
+ *(void **) (&pa_context_get_sample_info_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sample_info_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sample_info_by_index
+ *(void **) (&pa_context_get_sample_info_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sample_info_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_sample_info_list
+ *(void **) (&pa_context_get_sample_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_sample_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_autoload_info_by_name
+ *(void **) (&pa_context_get_autoload_info_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_autoload_info_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_autoload_info_by_index
+ *(void **) (&pa_context_get_autoload_info_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_autoload_info_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_get_autoload_info_list
+ *(void **) (&pa_context_get_autoload_info_list_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_get_autoload_info_list");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_add_autoload
+ *(void **) (&pa_context_add_autoload_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_add_autoload");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_remove_autoload_by_name
+ *(void **) (&pa_context_remove_autoload_by_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_remove_autoload_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_remove_autoload_by_index
+ *(void **) (&pa_context_remove_autoload_by_index_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_remove_autoload_by_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_subscribe
+ *(void **) (&pa_context_subscribe_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_subscribe");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_set_subscribe_callback
+ *(void **) (&pa_context_set_subscribe_callback_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_set_subscribe_callback");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_connect_upload
+ *(void **) (&pa_stream_connect_upload_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_connect_upload");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_stream_finish_upload
+ *(void **) (&pa_stream_finish_upload_dylibloader_wrapper_pulse) = dlsym(handle, "pa_stream_finish_upload");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_remove_sample
+ *(void **) (&pa_context_remove_sample_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_remove_sample");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_play_sample
+ *(void **) (&pa_context_play_sample_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_play_sample");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_context_play_sample_with_proplist
+ *(void **) (&pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse) = dlsym(handle, "pa_context_play_sample_with_proplist");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_strerror
+ *(void **) (&pa_strerror_dylibloader_wrapper_pulse) = dlsym(handle, "pa_strerror");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xmalloc
+ *(void **) (&pa_xmalloc_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xmalloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xmalloc0
+ *(void **) (&pa_xmalloc0_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xmalloc0");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xrealloc
+ *(void **) (&pa_xrealloc_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xrealloc");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xfree
+ *(void **) (&pa_xfree_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xfree");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xstrdup
+ *(void **) (&pa_xstrdup_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xstrdup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xstrndup
+ *(void **) (&pa_xstrndup_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xstrndup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_xmemdup
+ *(void **) (&pa_xmemdup_dylibloader_wrapper_pulse) = dlsym(handle, "pa_xmemdup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_utf8_valid
+ *(void **) (&pa_utf8_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_utf8_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_ascii_valid
+ *(void **) (&pa_ascii_valid_dylibloader_wrapper_pulse) = dlsym(handle, "pa_ascii_valid");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_utf8_filter
+ *(void **) (&pa_utf8_filter_dylibloader_wrapper_pulse) = dlsym(handle, "pa_utf8_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_ascii_filter
+ *(void **) (&pa_ascii_filter_dylibloader_wrapper_pulse) = dlsym(handle, "pa_ascii_filter");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_utf8_to_locale
+ *(void **) (&pa_utf8_to_locale_dylibloader_wrapper_pulse) = dlsym(handle, "pa_utf8_to_locale");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_locale_to_utf8
+ *(void **) (&pa_locale_to_utf8_dylibloader_wrapper_pulse) = dlsym(handle, "pa_locale_to_utf8");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_new
+ *(void **) (&pa_threaded_mainloop_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_free
+ *(void **) (&pa_threaded_mainloop_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_start
+ *(void **) (&pa_threaded_mainloop_start_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_start");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_stop
+ *(void **) (&pa_threaded_mainloop_stop_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_stop");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_lock
+ *(void **) (&pa_threaded_mainloop_lock_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_lock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_unlock
+ *(void **) (&pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_unlock");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_wait
+ *(void **) (&pa_threaded_mainloop_wait_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_wait");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_signal
+ *(void **) (&pa_threaded_mainloop_signal_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_signal");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_accept
+ *(void **) (&pa_threaded_mainloop_accept_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_accept");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_get_retval
+ *(void **) (&pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_get_retval");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_get_api
+ *(void **) (&pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_get_api");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_in_thread
+ *(void **) (&pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_in_thread");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_set_name
+ *(void **) (&pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_set_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_threaded_mainloop_once_unlocked
+ *(void **) (&pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse) = dlsym(handle, "pa_threaded_mainloop_once_unlocked");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_new
+ *(void **) (&pa_mainloop_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_free
+ *(void **) (&pa_mainloop_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_prepare
+ *(void **) (&pa_mainloop_prepare_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_prepare");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_poll
+ *(void **) (&pa_mainloop_poll_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_poll");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_dispatch
+ *(void **) (&pa_mainloop_dispatch_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_dispatch");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_get_retval
+ *(void **) (&pa_mainloop_get_retval_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_get_retval");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_iterate
+ *(void **) (&pa_mainloop_iterate_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_iterate");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_run
+ *(void **) (&pa_mainloop_run_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_run");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_get_api
+ *(void **) (&pa_mainloop_get_api_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_get_api");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_quit
+ *(void **) (&pa_mainloop_quit_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_quit");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_wakeup
+ *(void **) (&pa_mainloop_wakeup_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_wakeup");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_mainloop_set_poll_func
+ *(void **) (&pa_mainloop_set_poll_func_dylibloader_wrapper_pulse) = dlsym(handle, "pa_mainloop_set_poll_func");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_signal_init
+ *(void **) (&pa_signal_init_dylibloader_wrapper_pulse) = dlsym(handle, "pa_signal_init");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_signal_done
+ *(void **) (&pa_signal_done_dylibloader_wrapper_pulse) = dlsym(handle, "pa_signal_done");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_signal_new
+ *(void **) (&pa_signal_new_dylibloader_wrapper_pulse) = dlsym(handle, "pa_signal_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_signal_free
+ *(void **) (&pa_signal_free_dylibloader_wrapper_pulse) = dlsym(handle, "pa_signal_free");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_signal_set_destroy
+ *(void **) (&pa_signal_set_destroy_dylibloader_wrapper_pulse) = dlsym(handle, "pa_signal_set_destroy");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_get_user_name
+ *(void **) (&pa_get_user_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_user_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_get_host_name
+ *(void **) (&pa_get_host_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_host_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_get_fqdn
+ *(void **) (&pa_get_fqdn_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_fqdn");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_get_home_dir
+ *(void **) (&pa_get_home_dir_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_home_dir");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_get_binary_name
+ *(void **) (&pa_get_binary_name_dylibloader_wrapper_pulse) = dlsym(handle, "pa_get_binary_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_path_get_filename
+ *(void **) (&pa_path_get_filename_dylibloader_wrapper_pulse) = dlsym(handle, "pa_path_get_filename");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_msleep
+ *(void **) (&pa_msleep_dylibloader_wrapper_pulse) = dlsym(handle, "pa_msleep");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_thread_make_realtime
+ *(void **) (&pa_thread_make_realtime_dylibloader_wrapper_pulse) = dlsym(handle, "pa_thread_make_realtime");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_gettimeofday
+ *(void **) (&pa_gettimeofday_dylibloader_wrapper_pulse) = dlsym(handle, "pa_gettimeofday");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_diff
+ *(void **) (&pa_timeval_diff_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_diff");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_cmp
+ *(void **) (&pa_timeval_cmp_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_cmp");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_age
+ *(void **) (&pa_timeval_age_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_age");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_add
+ *(void **) (&pa_timeval_add_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_add");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_sub
+ *(void **) (&pa_timeval_sub_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_sub");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_store
+ *(void **) (&pa_timeval_store_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_store");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_timeval_load
+ *(void **) (&pa_timeval_load_dylibloader_wrapper_pulse) = dlsym(handle, "pa_timeval_load");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// pa_rtclock_now
+ *(void **) (&pa_rtclock_now_dylibloader_wrapper_pulse) = dlsym(handle, "pa_rtclock_now");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+return 0;
+}
diff --git a/drivers/pulseaudio/pulse-so_wrap.h b/drivers/pulseaudio/pulse-so_wrap.h
new file mode 100644
index 0000000000..7f9a70fae1
--- /dev/null
+++ b/drivers/pulseaudio/pulse-so_wrap.h
@@ -0,0 +1,1446 @@
+#ifndef DYLIBLOAD_WRAPPER_PULSE
+#define DYLIBLOAD_WRAPPER_PULSE
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:31
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/pulse/pulseaudio.h --sys-include <pulse/pulseaudio.h> --soname libpulse.so.0 --omit-prefix _pa_ --init-name pulse --output-header pulse-so_wrap.h --output-implementation pulse-so_wrap.c
+//
+#include <stdint.h>
+
+#define pa_get_library_version pa_get_library_version_dylibloader_orig_pulse
+#define pa_bytes_per_second pa_bytes_per_second_dylibloader_orig_pulse
+#define pa_frame_size pa_frame_size_dylibloader_orig_pulse
+#define pa_sample_size pa_sample_size_dylibloader_orig_pulse
+#define pa_sample_size_of_format pa_sample_size_of_format_dylibloader_orig_pulse
+#define pa_bytes_to_usec pa_bytes_to_usec_dylibloader_orig_pulse
+#define pa_usec_to_bytes pa_usec_to_bytes_dylibloader_orig_pulse
+#define pa_sample_spec_init pa_sample_spec_init_dylibloader_orig_pulse
+#define pa_sample_format_valid pa_sample_format_valid_dylibloader_orig_pulse
+#define pa_sample_rate_valid pa_sample_rate_valid_dylibloader_orig_pulse
+#define pa_channels_valid pa_channels_valid_dylibloader_orig_pulse
+#define pa_sample_spec_valid pa_sample_spec_valid_dylibloader_orig_pulse
+#define pa_sample_spec_equal pa_sample_spec_equal_dylibloader_orig_pulse
+#define pa_sample_format_to_string pa_sample_format_to_string_dylibloader_orig_pulse
+#define pa_parse_sample_format pa_parse_sample_format_dylibloader_orig_pulse
+#define pa_sample_spec_snprint pa_sample_spec_snprint_dylibloader_orig_pulse
+#define pa_bytes_snprint pa_bytes_snprint_dylibloader_orig_pulse
+#define pa_sample_format_is_le pa_sample_format_is_le_dylibloader_orig_pulse
+#define pa_sample_format_is_be pa_sample_format_is_be_dylibloader_orig_pulse
+#define pa_direction_valid pa_direction_valid_dylibloader_orig_pulse
+#define pa_direction_to_string pa_direction_to_string_dylibloader_orig_pulse
+#define pa_mainloop_api_once pa_mainloop_api_once_dylibloader_orig_pulse
+#define pa_proplist_new pa_proplist_new_dylibloader_orig_pulse
+#define pa_proplist_free pa_proplist_free_dylibloader_orig_pulse
+#define pa_proplist_key_valid pa_proplist_key_valid_dylibloader_orig_pulse
+#define pa_proplist_sets pa_proplist_sets_dylibloader_orig_pulse
+#define pa_proplist_setp pa_proplist_setp_dylibloader_orig_pulse
+#define pa_proplist_setf pa_proplist_setf_dylibloader_orig_pulse
+#define pa_proplist_set pa_proplist_set_dylibloader_orig_pulse
+#define pa_proplist_gets pa_proplist_gets_dylibloader_orig_pulse
+#define pa_proplist_get pa_proplist_get_dylibloader_orig_pulse
+#define pa_proplist_update pa_proplist_update_dylibloader_orig_pulse
+#define pa_proplist_unset pa_proplist_unset_dylibloader_orig_pulse
+#define pa_proplist_unset_many pa_proplist_unset_many_dylibloader_orig_pulse
+#define pa_proplist_iterate pa_proplist_iterate_dylibloader_orig_pulse
+#define pa_proplist_to_string pa_proplist_to_string_dylibloader_orig_pulse
+#define pa_proplist_to_string_sep pa_proplist_to_string_sep_dylibloader_orig_pulse
+#define pa_proplist_from_string pa_proplist_from_string_dylibloader_orig_pulse
+#define pa_proplist_contains pa_proplist_contains_dylibloader_orig_pulse
+#define pa_proplist_clear pa_proplist_clear_dylibloader_orig_pulse
+#define pa_proplist_copy pa_proplist_copy_dylibloader_orig_pulse
+#define pa_proplist_size pa_proplist_size_dylibloader_orig_pulse
+#define pa_proplist_isempty pa_proplist_isempty_dylibloader_orig_pulse
+#define pa_proplist_equal pa_proplist_equal_dylibloader_orig_pulse
+#define pa_channel_map_init pa_channel_map_init_dylibloader_orig_pulse
+#define pa_channel_map_init_mono pa_channel_map_init_mono_dylibloader_orig_pulse
+#define pa_channel_map_init_stereo pa_channel_map_init_stereo_dylibloader_orig_pulse
+#define pa_channel_map_init_auto pa_channel_map_init_auto_dylibloader_orig_pulse
+#define pa_channel_map_init_extend pa_channel_map_init_extend_dylibloader_orig_pulse
+#define pa_channel_position_to_string pa_channel_position_to_string_dylibloader_orig_pulse
+#define pa_channel_position_from_string pa_channel_position_from_string_dylibloader_orig_pulse
+#define pa_channel_position_to_pretty_string pa_channel_position_to_pretty_string_dylibloader_orig_pulse
+#define pa_channel_map_snprint pa_channel_map_snprint_dylibloader_orig_pulse
+#define pa_channel_map_parse pa_channel_map_parse_dylibloader_orig_pulse
+#define pa_channel_map_equal pa_channel_map_equal_dylibloader_orig_pulse
+#define pa_channel_map_valid pa_channel_map_valid_dylibloader_orig_pulse
+#define pa_channel_map_compatible pa_channel_map_compatible_dylibloader_orig_pulse
+#define pa_channel_map_superset pa_channel_map_superset_dylibloader_orig_pulse
+#define pa_channel_map_can_balance pa_channel_map_can_balance_dylibloader_orig_pulse
+#define pa_channel_map_can_fade pa_channel_map_can_fade_dylibloader_orig_pulse
+#define pa_channel_map_can_lfe_balance pa_channel_map_can_lfe_balance_dylibloader_orig_pulse
+#define pa_channel_map_to_name pa_channel_map_to_name_dylibloader_orig_pulse
+#define pa_channel_map_to_pretty_name pa_channel_map_to_pretty_name_dylibloader_orig_pulse
+#define pa_channel_map_has_position pa_channel_map_has_position_dylibloader_orig_pulse
+#define pa_channel_map_mask pa_channel_map_mask_dylibloader_orig_pulse
+#define pa_encoding_to_string pa_encoding_to_string_dylibloader_orig_pulse
+#define pa_encoding_from_string pa_encoding_from_string_dylibloader_orig_pulse
+#define pa_format_info_new pa_format_info_new_dylibloader_orig_pulse
+#define pa_format_info_copy pa_format_info_copy_dylibloader_orig_pulse
+#define pa_format_info_free pa_format_info_free_dylibloader_orig_pulse
+#define pa_format_info_valid pa_format_info_valid_dylibloader_orig_pulse
+#define pa_format_info_is_pcm pa_format_info_is_pcm_dylibloader_orig_pulse
+#define pa_format_info_is_compatible pa_format_info_is_compatible_dylibloader_orig_pulse
+#define pa_format_info_snprint pa_format_info_snprint_dylibloader_orig_pulse
+#define pa_format_info_from_string pa_format_info_from_string_dylibloader_orig_pulse
+#define pa_format_info_from_sample_spec pa_format_info_from_sample_spec_dylibloader_orig_pulse
+#define pa_format_info_to_sample_spec pa_format_info_to_sample_spec_dylibloader_orig_pulse
+#define pa_format_info_get_prop_type pa_format_info_get_prop_type_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int pa_format_info_get_prop_int_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int_range pa_format_info_get_prop_int_range_dylibloader_orig_pulse
+#define pa_format_info_get_prop_int_array pa_format_info_get_prop_int_array_dylibloader_orig_pulse
+#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_orig_pulse
+#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_orig_pulse
+#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_orig_pulse
+#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_orig_pulse
+#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_orig_pulse
+#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_orig_pulse
+#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_orig_pulse
+#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_orig_pulse
+#define pa_format_info_set_prop_string pa_format_info_set_prop_string_dylibloader_orig_pulse
+#define pa_format_info_set_prop_string_array pa_format_info_set_prop_string_array_dylibloader_orig_pulse
+#define pa_format_info_set_sample_format pa_format_info_set_sample_format_dylibloader_orig_pulse
+#define pa_format_info_set_rate pa_format_info_set_rate_dylibloader_orig_pulse
+#define pa_format_info_set_channels pa_format_info_set_channels_dylibloader_orig_pulse
+#define pa_format_info_set_channel_map pa_format_info_set_channel_map_dylibloader_orig_pulse
+#define pa_operation_ref pa_operation_ref_dylibloader_orig_pulse
+#define pa_operation_unref pa_operation_unref_dylibloader_orig_pulse
+#define pa_operation_cancel pa_operation_cancel_dylibloader_orig_pulse
+#define pa_operation_get_state pa_operation_get_state_dylibloader_orig_pulse
+#define pa_operation_set_state_callback pa_operation_set_state_callback_dylibloader_orig_pulse
+#define pa_context_new pa_context_new_dylibloader_orig_pulse
+#define pa_context_new_with_proplist pa_context_new_with_proplist_dylibloader_orig_pulse
+#define pa_context_unref pa_context_unref_dylibloader_orig_pulse
+#define pa_context_ref pa_context_ref_dylibloader_orig_pulse
+#define pa_context_set_state_callback pa_context_set_state_callback_dylibloader_orig_pulse
+#define pa_context_set_event_callback pa_context_set_event_callback_dylibloader_orig_pulse
+#define pa_context_errno pa_context_errno_dylibloader_orig_pulse
+#define pa_context_is_pending pa_context_is_pending_dylibloader_orig_pulse
+#define pa_context_get_state pa_context_get_state_dylibloader_orig_pulse
+#define pa_context_connect pa_context_connect_dylibloader_orig_pulse
+#define pa_context_disconnect pa_context_disconnect_dylibloader_orig_pulse
+#define pa_context_drain pa_context_drain_dylibloader_orig_pulse
+#define pa_context_exit_daemon pa_context_exit_daemon_dylibloader_orig_pulse
+#define pa_context_set_default_sink pa_context_set_default_sink_dylibloader_orig_pulse
+#define pa_context_set_default_source pa_context_set_default_source_dylibloader_orig_pulse
+#define pa_context_is_local pa_context_is_local_dylibloader_orig_pulse
+#define pa_context_set_name pa_context_set_name_dylibloader_orig_pulse
+#define pa_context_get_server pa_context_get_server_dylibloader_orig_pulse
+#define pa_context_get_protocol_version pa_context_get_protocol_version_dylibloader_orig_pulse
+#define pa_context_get_server_protocol_version pa_context_get_server_protocol_version_dylibloader_orig_pulse
+#define pa_context_proplist_update pa_context_proplist_update_dylibloader_orig_pulse
+#define pa_context_proplist_remove pa_context_proplist_remove_dylibloader_orig_pulse
+#define pa_context_get_index pa_context_get_index_dylibloader_orig_pulse
+#define pa_context_rttime_new pa_context_rttime_new_dylibloader_orig_pulse
+#define pa_context_rttime_restart pa_context_rttime_restart_dylibloader_orig_pulse
+#define pa_context_get_tile_size pa_context_get_tile_size_dylibloader_orig_pulse
+#define pa_context_load_cookie_from_file pa_context_load_cookie_from_file_dylibloader_orig_pulse
+#define pa_cvolume_equal pa_cvolume_equal_dylibloader_orig_pulse
+#define pa_cvolume_init pa_cvolume_init_dylibloader_orig_pulse
+#define pa_cvolume_set pa_cvolume_set_dylibloader_orig_pulse
+#define pa_cvolume_snprint pa_cvolume_snprint_dylibloader_orig_pulse
+#define pa_sw_cvolume_snprint_dB pa_sw_cvolume_snprint_dB_dylibloader_orig_pulse
+#define pa_cvolume_snprint_verbose pa_cvolume_snprint_verbose_dylibloader_orig_pulse
+#define pa_volume_snprint pa_volume_snprint_dylibloader_orig_pulse
+#define pa_sw_volume_snprint_dB pa_sw_volume_snprint_dB_dylibloader_orig_pulse
+#define pa_volume_snprint_verbose pa_volume_snprint_verbose_dylibloader_orig_pulse
+#define pa_cvolume_avg pa_cvolume_avg_dylibloader_orig_pulse
+#define pa_cvolume_avg_mask pa_cvolume_avg_mask_dylibloader_orig_pulse
+#define pa_cvolume_max pa_cvolume_max_dylibloader_orig_pulse
+#define pa_cvolume_max_mask pa_cvolume_max_mask_dylibloader_orig_pulse
+#define pa_cvolume_min pa_cvolume_min_dylibloader_orig_pulse
+#define pa_cvolume_min_mask pa_cvolume_min_mask_dylibloader_orig_pulse
+#define pa_cvolume_valid pa_cvolume_valid_dylibloader_orig_pulse
+#define pa_cvolume_channels_equal_to pa_cvolume_channels_equal_to_dylibloader_orig_pulse
+#define pa_sw_volume_multiply pa_sw_volume_multiply_dylibloader_orig_pulse
+#define pa_sw_cvolume_multiply pa_sw_cvolume_multiply_dylibloader_orig_pulse
+#define pa_sw_cvolume_multiply_scalar pa_sw_cvolume_multiply_scalar_dylibloader_orig_pulse
+#define pa_sw_volume_divide pa_sw_volume_divide_dylibloader_orig_pulse
+#define pa_sw_cvolume_divide pa_sw_cvolume_divide_dylibloader_orig_pulse
+#define pa_sw_cvolume_divide_scalar pa_sw_cvolume_divide_scalar_dylibloader_orig_pulse
+#define pa_sw_volume_from_dB pa_sw_volume_from_dB_dylibloader_orig_pulse
+#define pa_sw_volume_to_dB pa_sw_volume_to_dB_dylibloader_orig_pulse
+#define pa_sw_volume_from_linear pa_sw_volume_from_linear_dylibloader_orig_pulse
+#define pa_sw_volume_to_linear pa_sw_volume_to_linear_dylibloader_orig_pulse
+#define pa_cvolume_remap pa_cvolume_remap_dylibloader_orig_pulse
+#define pa_cvolume_compatible pa_cvolume_compatible_dylibloader_orig_pulse
+#define pa_cvolume_compatible_with_channel_map pa_cvolume_compatible_with_channel_map_dylibloader_orig_pulse
+#define pa_cvolume_get_balance pa_cvolume_get_balance_dylibloader_orig_pulse
+#define pa_cvolume_set_balance pa_cvolume_set_balance_dylibloader_orig_pulse
+#define pa_cvolume_get_fade pa_cvolume_get_fade_dylibloader_orig_pulse
+#define pa_cvolume_set_fade pa_cvolume_set_fade_dylibloader_orig_pulse
+#define pa_cvolume_get_lfe_balance pa_cvolume_get_lfe_balance_dylibloader_orig_pulse
+#define pa_cvolume_set_lfe_balance pa_cvolume_set_lfe_balance_dylibloader_orig_pulse
+#define pa_cvolume_scale pa_cvolume_scale_dylibloader_orig_pulse
+#define pa_cvolume_scale_mask pa_cvolume_scale_mask_dylibloader_orig_pulse
+#define pa_cvolume_set_position pa_cvolume_set_position_dylibloader_orig_pulse
+#define pa_cvolume_get_position pa_cvolume_get_position_dylibloader_orig_pulse
+#define pa_cvolume_merge pa_cvolume_merge_dylibloader_orig_pulse
+#define pa_cvolume_inc_clamp pa_cvolume_inc_clamp_dylibloader_orig_pulse
+#define pa_cvolume_inc pa_cvolume_inc_dylibloader_orig_pulse
+#define pa_cvolume_dec pa_cvolume_dec_dylibloader_orig_pulse
+#define pa_stream_new pa_stream_new_dylibloader_orig_pulse
+#define pa_stream_new_with_proplist pa_stream_new_with_proplist_dylibloader_orig_pulse
+#define pa_stream_new_extended pa_stream_new_extended_dylibloader_orig_pulse
+#define pa_stream_unref pa_stream_unref_dylibloader_orig_pulse
+#define pa_stream_ref pa_stream_ref_dylibloader_orig_pulse
+#define pa_stream_get_state pa_stream_get_state_dylibloader_orig_pulse
+#define pa_stream_get_context pa_stream_get_context_dylibloader_orig_pulse
+#define pa_stream_get_index pa_stream_get_index_dylibloader_orig_pulse
+#define pa_stream_get_device_index pa_stream_get_device_index_dylibloader_orig_pulse
+#define pa_stream_get_device_name pa_stream_get_device_name_dylibloader_orig_pulse
+#define pa_stream_is_suspended pa_stream_is_suspended_dylibloader_orig_pulse
+#define pa_stream_is_corked pa_stream_is_corked_dylibloader_orig_pulse
+#define pa_stream_connect_playback pa_stream_connect_playback_dylibloader_orig_pulse
+#define pa_stream_connect_record pa_stream_connect_record_dylibloader_orig_pulse
+#define pa_stream_disconnect pa_stream_disconnect_dylibloader_orig_pulse
+#define pa_stream_begin_write pa_stream_begin_write_dylibloader_orig_pulse
+#define pa_stream_cancel_write pa_stream_cancel_write_dylibloader_orig_pulse
+#define pa_stream_write pa_stream_write_dylibloader_orig_pulse
+#define pa_stream_write_ext_free pa_stream_write_ext_free_dylibloader_orig_pulse
+#define pa_stream_peek pa_stream_peek_dylibloader_orig_pulse
+#define pa_stream_drop pa_stream_drop_dylibloader_orig_pulse
+#define pa_stream_writable_size pa_stream_writable_size_dylibloader_orig_pulse
+#define pa_stream_readable_size pa_stream_readable_size_dylibloader_orig_pulse
+#define pa_stream_drain pa_stream_drain_dylibloader_orig_pulse
+#define pa_stream_update_timing_info pa_stream_update_timing_info_dylibloader_orig_pulse
+#define pa_stream_set_state_callback pa_stream_set_state_callback_dylibloader_orig_pulse
+#define pa_stream_set_write_callback pa_stream_set_write_callback_dylibloader_orig_pulse
+#define pa_stream_set_read_callback pa_stream_set_read_callback_dylibloader_orig_pulse
+#define pa_stream_set_overflow_callback pa_stream_set_overflow_callback_dylibloader_orig_pulse
+#define pa_stream_get_underflow_index pa_stream_get_underflow_index_dylibloader_orig_pulse
+#define pa_stream_set_underflow_callback pa_stream_set_underflow_callback_dylibloader_orig_pulse
+#define pa_stream_set_started_callback pa_stream_set_started_callback_dylibloader_orig_pulse
+#define pa_stream_set_latency_update_callback pa_stream_set_latency_update_callback_dylibloader_orig_pulse
+#define pa_stream_set_moved_callback pa_stream_set_moved_callback_dylibloader_orig_pulse
+#define pa_stream_set_suspended_callback pa_stream_set_suspended_callback_dylibloader_orig_pulse
+#define pa_stream_set_event_callback pa_stream_set_event_callback_dylibloader_orig_pulse
+#define pa_stream_set_buffer_attr_callback pa_stream_set_buffer_attr_callback_dylibloader_orig_pulse
+#define pa_stream_cork pa_stream_cork_dylibloader_orig_pulse
+#define pa_stream_flush pa_stream_flush_dylibloader_orig_pulse
+#define pa_stream_prebuf pa_stream_prebuf_dylibloader_orig_pulse
+#define pa_stream_trigger pa_stream_trigger_dylibloader_orig_pulse
+#define pa_stream_set_name pa_stream_set_name_dylibloader_orig_pulse
+#define pa_stream_get_time pa_stream_get_time_dylibloader_orig_pulse
+#define pa_stream_get_latency pa_stream_get_latency_dylibloader_orig_pulse
+#define pa_stream_get_timing_info pa_stream_get_timing_info_dylibloader_orig_pulse
+#define pa_stream_get_sample_spec pa_stream_get_sample_spec_dylibloader_orig_pulse
+#define pa_stream_get_channel_map pa_stream_get_channel_map_dylibloader_orig_pulse
+#define pa_stream_get_format_info pa_stream_get_format_info_dylibloader_orig_pulse
+#define pa_stream_get_buffer_attr pa_stream_get_buffer_attr_dylibloader_orig_pulse
+#define pa_stream_set_buffer_attr pa_stream_set_buffer_attr_dylibloader_orig_pulse
+#define pa_stream_update_sample_rate pa_stream_update_sample_rate_dylibloader_orig_pulse
+#define pa_stream_proplist_update pa_stream_proplist_update_dylibloader_orig_pulse
+#define pa_stream_proplist_remove pa_stream_proplist_remove_dylibloader_orig_pulse
+#define pa_stream_set_monitor_stream pa_stream_set_monitor_stream_dylibloader_orig_pulse
+#define pa_stream_get_monitor_stream pa_stream_get_monitor_stream_dylibloader_orig_pulse
+#define pa_context_get_sink_info_by_name pa_context_get_sink_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_sink_info_by_index pa_context_get_sink_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_sink_info_list pa_context_get_sink_info_list_dylibloader_orig_pulse
+#define pa_context_set_sink_volume_by_index pa_context_set_sink_volume_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_volume_by_name pa_context_set_sink_volume_by_name_dylibloader_orig_pulse
+#define pa_context_set_sink_mute_by_index pa_context_set_sink_mute_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_mute_by_name pa_context_set_sink_mute_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_sink_by_name pa_context_suspend_sink_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_sink_by_index pa_context_suspend_sink_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_port_by_index pa_context_set_sink_port_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_port_by_name pa_context_set_sink_port_by_name_dylibloader_orig_pulse
+#define pa_context_get_source_info_by_name pa_context_get_source_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_source_info_by_index pa_context_get_source_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_source_info_list pa_context_get_source_info_list_dylibloader_orig_pulse
+#define pa_context_set_source_volume_by_index pa_context_set_source_volume_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_volume_by_name pa_context_set_source_volume_by_name_dylibloader_orig_pulse
+#define pa_context_set_source_mute_by_index pa_context_set_source_mute_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_mute_by_name pa_context_set_source_mute_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_source_by_name pa_context_suspend_source_by_name_dylibloader_orig_pulse
+#define pa_context_suspend_source_by_index pa_context_suspend_source_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_port_by_index pa_context_set_source_port_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_port_by_name pa_context_set_source_port_by_name_dylibloader_orig_pulse
+#define pa_context_get_server_info pa_context_get_server_info_dylibloader_orig_pulse
+#define pa_context_get_module_info pa_context_get_module_info_dylibloader_orig_pulse
+#define pa_context_get_module_info_list pa_context_get_module_info_list_dylibloader_orig_pulse
+#define pa_context_load_module pa_context_load_module_dylibloader_orig_pulse
+#define pa_context_unload_module pa_context_unload_module_dylibloader_orig_pulse
+#define pa_context_get_client_info pa_context_get_client_info_dylibloader_orig_pulse
+#define pa_context_get_client_info_list pa_context_get_client_info_list_dylibloader_orig_pulse
+#define pa_context_kill_client pa_context_kill_client_dylibloader_orig_pulse
+#define pa_context_get_card_info_by_index pa_context_get_card_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_card_info_by_name pa_context_get_card_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_card_info_list pa_context_get_card_info_list_dylibloader_orig_pulse
+#define pa_context_set_card_profile_by_index pa_context_set_card_profile_by_index_dylibloader_orig_pulse
+#define pa_context_set_card_profile_by_name pa_context_set_card_profile_by_name_dylibloader_orig_pulse
+#define pa_context_set_port_latency_offset pa_context_set_port_latency_offset_dylibloader_orig_pulse
+#define pa_context_get_sink_input_info pa_context_get_sink_input_info_dylibloader_orig_pulse
+#define pa_context_get_sink_input_info_list pa_context_get_sink_input_info_list_dylibloader_orig_pulse
+#define pa_context_move_sink_input_by_name pa_context_move_sink_input_by_name_dylibloader_orig_pulse
+#define pa_context_move_sink_input_by_index pa_context_move_sink_input_by_index_dylibloader_orig_pulse
+#define pa_context_set_sink_input_volume pa_context_set_sink_input_volume_dylibloader_orig_pulse
+#define pa_context_set_sink_input_mute pa_context_set_sink_input_mute_dylibloader_orig_pulse
+#define pa_context_kill_sink_input pa_context_kill_sink_input_dylibloader_orig_pulse
+#define pa_context_get_source_output_info pa_context_get_source_output_info_dylibloader_orig_pulse
+#define pa_context_get_source_output_info_list pa_context_get_source_output_info_list_dylibloader_orig_pulse
+#define pa_context_move_source_output_by_name pa_context_move_source_output_by_name_dylibloader_orig_pulse
+#define pa_context_move_source_output_by_index pa_context_move_source_output_by_index_dylibloader_orig_pulse
+#define pa_context_set_source_output_volume pa_context_set_source_output_volume_dylibloader_orig_pulse
+#define pa_context_set_source_output_mute pa_context_set_source_output_mute_dylibloader_orig_pulse
+#define pa_context_kill_source_output pa_context_kill_source_output_dylibloader_orig_pulse
+#define pa_context_stat pa_context_stat_dylibloader_orig_pulse
+#define pa_context_get_sample_info_by_name pa_context_get_sample_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_sample_info_by_index pa_context_get_sample_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_sample_info_list pa_context_get_sample_info_list_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_by_name pa_context_get_autoload_info_by_name_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_by_index pa_context_get_autoload_info_by_index_dylibloader_orig_pulse
+#define pa_context_get_autoload_info_list pa_context_get_autoload_info_list_dylibloader_orig_pulse
+#define pa_context_add_autoload pa_context_add_autoload_dylibloader_orig_pulse
+#define pa_context_remove_autoload_by_name pa_context_remove_autoload_by_name_dylibloader_orig_pulse
+#define pa_context_remove_autoload_by_index pa_context_remove_autoload_by_index_dylibloader_orig_pulse
+#define pa_context_subscribe pa_context_subscribe_dylibloader_orig_pulse
+#define pa_context_set_subscribe_callback pa_context_set_subscribe_callback_dylibloader_orig_pulse
+#define pa_stream_connect_upload pa_stream_connect_upload_dylibloader_orig_pulse
+#define pa_stream_finish_upload pa_stream_finish_upload_dylibloader_orig_pulse
+#define pa_context_remove_sample pa_context_remove_sample_dylibloader_orig_pulse
+#define pa_context_play_sample pa_context_play_sample_dylibloader_orig_pulse
+#define pa_context_play_sample_with_proplist pa_context_play_sample_with_proplist_dylibloader_orig_pulse
+#define pa_strerror pa_strerror_dylibloader_orig_pulse
+#define pa_xmalloc pa_xmalloc_dylibloader_orig_pulse
+#define pa_xmalloc0 pa_xmalloc0_dylibloader_orig_pulse
+#define pa_xrealloc pa_xrealloc_dylibloader_orig_pulse
+#define pa_xfree pa_xfree_dylibloader_orig_pulse
+#define pa_xstrdup pa_xstrdup_dylibloader_orig_pulse
+#define pa_xstrndup pa_xstrndup_dylibloader_orig_pulse
+#define pa_xmemdup pa_xmemdup_dylibloader_orig_pulse
+#define pa_utf8_valid pa_utf8_valid_dylibloader_orig_pulse
+#define pa_ascii_valid pa_ascii_valid_dylibloader_orig_pulse
+#define pa_utf8_filter pa_utf8_filter_dylibloader_orig_pulse
+#define pa_ascii_filter pa_ascii_filter_dylibloader_orig_pulse
+#define pa_utf8_to_locale pa_utf8_to_locale_dylibloader_orig_pulse
+#define pa_locale_to_utf8 pa_locale_to_utf8_dylibloader_orig_pulse
+#define pa_threaded_mainloop_new pa_threaded_mainloop_new_dylibloader_orig_pulse
+#define pa_threaded_mainloop_free pa_threaded_mainloop_free_dylibloader_orig_pulse
+#define pa_threaded_mainloop_start pa_threaded_mainloop_start_dylibloader_orig_pulse
+#define pa_threaded_mainloop_stop pa_threaded_mainloop_stop_dylibloader_orig_pulse
+#define pa_threaded_mainloop_lock pa_threaded_mainloop_lock_dylibloader_orig_pulse
+#define pa_threaded_mainloop_unlock pa_threaded_mainloop_unlock_dylibloader_orig_pulse
+#define pa_threaded_mainloop_wait pa_threaded_mainloop_wait_dylibloader_orig_pulse
+#define pa_threaded_mainloop_signal pa_threaded_mainloop_signal_dylibloader_orig_pulse
+#define pa_threaded_mainloop_accept pa_threaded_mainloop_accept_dylibloader_orig_pulse
+#define pa_threaded_mainloop_get_retval pa_threaded_mainloop_get_retval_dylibloader_orig_pulse
+#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_orig_pulse
+#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_orig_pulse
+#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_orig_pulse
+#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_orig_pulse
+#define pa_mainloop_new pa_mainloop_new_dylibloader_orig_pulse
+#define pa_mainloop_free pa_mainloop_free_dylibloader_orig_pulse
+#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_orig_pulse
+#define pa_mainloop_poll pa_mainloop_poll_dylibloader_orig_pulse
+#define pa_mainloop_dispatch pa_mainloop_dispatch_dylibloader_orig_pulse
+#define pa_mainloop_get_retval pa_mainloop_get_retval_dylibloader_orig_pulse
+#define pa_mainloop_iterate pa_mainloop_iterate_dylibloader_orig_pulse
+#define pa_mainloop_run pa_mainloop_run_dylibloader_orig_pulse
+#define pa_mainloop_get_api pa_mainloop_get_api_dylibloader_orig_pulse
+#define pa_mainloop_quit pa_mainloop_quit_dylibloader_orig_pulse
+#define pa_mainloop_wakeup pa_mainloop_wakeup_dylibloader_orig_pulse
+#define pa_mainloop_set_poll_func pa_mainloop_set_poll_func_dylibloader_orig_pulse
+#define pa_signal_init pa_signal_init_dylibloader_orig_pulse
+#define pa_signal_done pa_signal_done_dylibloader_orig_pulse
+#define pa_signal_new pa_signal_new_dylibloader_orig_pulse
+#define pa_signal_free pa_signal_free_dylibloader_orig_pulse
+#define pa_signal_set_destroy pa_signal_set_destroy_dylibloader_orig_pulse
+#define pa_get_user_name pa_get_user_name_dylibloader_orig_pulse
+#define pa_get_host_name pa_get_host_name_dylibloader_orig_pulse
+#define pa_get_fqdn pa_get_fqdn_dylibloader_orig_pulse
+#define pa_get_home_dir pa_get_home_dir_dylibloader_orig_pulse
+#define pa_get_binary_name pa_get_binary_name_dylibloader_orig_pulse
+#define pa_path_get_filename pa_path_get_filename_dylibloader_orig_pulse
+#define pa_msleep pa_msleep_dylibloader_orig_pulse
+#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_orig_pulse
+#define pa_gettimeofday pa_gettimeofday_dylibloader_orig_pulse
+#define pa_timeval_diff pa_timeval_diff_dylibloader_orig_pulse
+#define pa_timeval_cmp pa_timeval_cmp_dylibloader_orig_pulse
+#define pa_timeval_age pa_timeval_age_dylibloader_orig_pulse
+#define pa_timeval_add pa_timeval_add_dylibloader_orig_pulse
+#define pa_timeval_sub pa_timeval_sub_dylibloader_orig_pulse
+#define pa_timeval_store pa_timeval_store_dylibloader_orig_pulse
+#define pa_timeval_load pa_timeval_load_dylibloader_orig_pulse
+#define pa_rtclock_now pa_rtclock_now_dylibloader_orig_pulse
+#include <pulse/pulseaudio.h>
+#undef pa_get_library_version
+#undef pa_bytes_per_second
+#undef pa_frame_size
+#undef pa_sample_size
+#undef pa_sample_size_of_format
+#undef pa_bytes_to_usec
+#undef pa_usec_to_bytes
+#undef pa_sample_spec_init
+#undef pa_sample_format_valid
+#undef pa_sample_rate_valid
+#undef pa_channels_valid
+#undef pa_sample_spec_valid
+#undef pa_sample_spec_equal
+#undef pa_sample_format_to_string
+#undef pa_parse_sample_format
+#undef pa_sample_spec_snprint
+#undef pa_bytes_snprint
+#undef pa_sample_format_is_le
+#undef pa_sample_format_is_be
+#undef pa_direction_valid
+#undef pa_direction_to_string
+#undef pa_mainloop_api_once
+#undef pa_proplist_new
+#undef pa_proplist_free
+#undef pa_proplist_key_valid
+#undef pa_proplist_sets
+#undef pa_proplist_setp
+#undef pa_proplist_setf
+#undef pa_proplist_set
+#undef pa_proplist_gets
+#undef pa_proplist_get
+#undef pa_proplist_update
+#undef pa_proplist_unset
+#undef pa_proplist_unset_many
+#undef pa_proplist_iterate
+#undef pa_proplist_to_string
+#undef pa_proplist_to_string_sep
+#undef pa_proplist_from_string
+#undef pa_proplist_contains
+#undef pa_proplist_clear
+#undef pa_proplist_copy
+#undef pa_proplist_size
+#undef pa_proplist_isempty
+#undef pa_proplist_equal
+#undef pa_channel_map_init
+#undef pa_channel_map_init_mono
+#undef pa_channel_map_init_stereo
+#undef pa_channel_map_init_auto
+#undef pa_channel_map_init_extend
+#undef pa_channel_position_to_string
+#undef pa_channel_position_from_string
+#undef pa_channel_position_to_pretty_string
+#undef pa_channel_map_snprint
+#undef pa_channel_map_parse
+#undef pa_channel_map_equal
+#undef pa_channel_map_valid
+#undef pa_channel_map_compatible
+#undef pa_channel_map_superset
+#undef pa_channel_map_can_balance
+#undef pa_channel_map_can_fade
+#undef pa_channel_map_can_lfe_balance
+#undef pa_channel_map_to_name
+#undef pa_channel_map_to_pretty_name
+#undef pa_channel_map_has_position
+#undef pa_channel_map_mask
+#undef pa_encoding_to_string
+#undef pa_encoding_from_string
+#undef pa_format_info_new
+#undef pa_format_info_copy
+#undef pa_format_info_free
+#undef pa_format_info_valid
+#undef pa_format_info_is_pcm
+#undef pa_format_info_is_compatible
+#undef pa_format_info_snprint
+#undef pa_format_info_from_string
+#undef pa_format_info_from_sample_spec
+#undef pa_format_info_to_sample_spec
+#undef pa_format_info_get_prop_type
+#undef pa_format_info_get_prop_int
+#undef pa_format_info_get_prop_int_range
+#undef pa_format_info_get_prop_int_array
+#undef pa_format_info_get_prop_string
+#undef pa_format_info_get_prop_string_array
+#undef pa_format_info_free_string_array
+#undef pa_format_info_get_sample_format
+#undef pa_format_info_get_rate
+#undef pa_format_info_get_channels
+#undef pa_format_info_get_channel_map
+#undef pa_format_info_set_prop_int
+#undef pa_format_info_set_prop_int_array
+#undef pa_format_info_set_prop_int_range
+#undef pa_format_info_set_prop_string
+#undef pa_format_info_set_prop_string_array
+#undef pa_format_info_set_sample_format
+#undef pa_format_info_set_rate
+#undef pa_format_info_set_channels
+#undef pa_format_info_set_channel_map
+#undef pa_operation_ref
+#undef pa_operation_unref
+#undef pa_operation_cancel
+#undef pa_operation_get_state
+#undef pa_operation_set_state_callback
+#undef pa_context_new
+#undef pa_context_new_with_proplist
+#undef pa_context_unref
+#undef pa_context_ref
+#undef pa_context_set_state_callback
+#undef pa_context_set_event_callback
+#undef pa_context_errno
+#undef pa_context_is_pending
+#undef pa_context_get_state
+#undef pa_context_connect
+#undef pa_context_disconnect
+#undef pa_context_drain
+#undef pa_context_exit_daemon
+#undef pa_context_set_default_sink
+#undef pa_context_set_default_source
+#undef pa_context_is_local
+#undef pa_context_set_name
+#undef pa_context_get_server
+#undef pa_context_get_protocol_version
+#undef pa_context_get_server_protocol_version
+#undef pa_context_proplist_update
+#undef pa_context_proplist_remove
+#undef pa_context_get_index
+#undef pa_context_rttime_new
+#undef pa_context_rttime_restart
+#undef pa_context_get_tile_size
+#undef pa_context_load_cookie_from_file
+#undef pa_cvolume_equal
+#undef pa_cvolume_init
+#undef pa_cvolume_set
+#undef pa_cvolume_snprint
+#undef pa_sw_cvolume_snprint_dB
+#undef pa_cvolume_snprint_verbose
+#undef pa_volume_snprint
+#undef pa_sw_volume_snprint_dB
+#undef pa_volume_snprint_verbose
+#undef pa_cvolume_avg
+#undef pa_cvolume_avg_mask
+#undef pa_cvolume_max
+#undef pa_cvolume_max_mask
+#undef pa_cvolume_min
+#undef pa_cvolume_min_mask
+#undef pa_cvolume_valid
+#undef pa_cvolume_channels_equal_to
+#undef pa_sw_volume_multiply
+#undef pa_sw_cvolume_multiply
+#undef pa_sw_cvolume_multiply_scalar
+#undef pa_sw_volume_divide
+#undef pa_sw_cvolume_divide
+#undef pa_sw_cvolume_divide_scalar
+#undef pa_sw_volume_from_dB
+#undef pa_sw_volume_to_dB
+#undef pa_sw_volume_from_linear
+#undef pa_sw_volume_to_linear
+#undef pa_cvolume_remap
+#undef pa_cvolume_compatible
+#undef pa_cvolume_compatible_with_channel_map
+#undef pa_cvolume_get_balance
+#undef pa_cvolume_set_balance
+#undef pa_cvolume_get_fade
+#undef pa_cvolume_set_fade
+#undef pa_cvolume_get_lfe_balance
+#undef pa_cvolume_set_lfe_balance
+#undef pa_cvolume_scale
+#undef pa_cvolume_scale_mask
+#undef pa_cvolume_set_position
+#undef pa_cvolume_get_position
+#undef pa_cvolume_merge
+#undef pa_cvolume_inc_clamp
+#undef pa_cvolume_inc
+#undef pa_cvolume_dec
+#undef pa_stream_new
+#undef pa_stream_new_with_proplist
+#undef pa_stream_new_extended
+#undef pa_stream_unref
+#undef pa_stream_ref
+#undef pa_stream_get_state
+#undef pa_stream_get_context
+#undef pa_stream_get_index
+#undef pa_stream_get_device_index
+#undef pa_stream_get_device_name
+#undef pa_stream_is_suspended
+#undef pa_stream_is_corked
+#undef pa_stream_connect_playback
+#undef pa_stream_connect_record
+#undef pa_stream_disconnect
+#undef pa_stream_begin_write
+#undef pa_stream_cancel_write
+#undef pa_stream_write
+#undef pa_stream_write_ext_free
+#undef pa_stream_peek
+#undef pa_stream_drop
+#undef pa_stream_writable_size
+#undef pa_stream_readable_size
+#undef pa_stream_drain
+#undef pa_stream_update_timing_info
+#undef pa_stream_set_state_callback
+#undef pa_stream_set_write_callback
+#undef pa_stream_set_read_callback
+#undef pa_stream_set_overflow_callback
+#undef pa_stream_get_underflow_index
+#undef pa_stream_set_underflow_callback
+#undef pa_stream_set_started_callback
+#undef pa_stream_set_latency_update_callback
+#undef pa_stream_set_moved_callback
+#undef pa_stream_set_suspended_callback
+#undef pa_stream_set_event_callback
+#undef pa_stream_set_buffer_attr_callback
+#undef pa_stream_cork
+#undef pa_stream_flush
+#undef pa_stream_prebuf
+#undef pa_stream_trigger
+#undef pa_stream_set_name
+#undef pa_stream_get_time
+#undef pa_stream_get_latency
+#undef pa_stream_get_timing_info
+#undef pa_stream_get_sample_spec
+#undef pa_stream_get_channel_map
+#undef pa_stream_get_format_info
+#undef pa_stream_get_buffer_attr
+#undef pa_stream_set_buffer_attr
+#undef pa_stream_update_sample_rate
+#undef pa_stream_proplist_update
+#undef pa_stream_proplist_remove
+#undef pa_stream_set_monitor_stream
+#undef pa_stream_get_monitor_stream
+#undef pa_context_get_sink_info_by_name
+#undef pa_context_get_sink_info_by_index
+#undef pa_context_get_sink_info_list
+#undef pa_context_set_sink_volume_by_index
+#undef pa_context_set_sink_volume_by_name
+#undef pa_context_set_sink_mute_by_index
+#undef pa_context_set_sink_mute_by_name
+#undef pa_context_suspend_sink_by_name
+#undef pa_context_suspend_sink_by_index
+#undef pa_context_set_sink_port_by_index
+#undef pa_context_set_sink_port_by_name
+#undef pa_context_get_source_info_by_name
+#undef pa_context_get_source_info_by_index
+#undef pa_context_get_source_info_list
+#undef pa_context_set_source_volume_by_index
+#undef pa_context_set_source_volume_by_name
+#undef pa_context_set_source_mute_by_index
+#undef pa_context_set_source_mute_by_name
+#undef pa_context_suspend_source_by_name
+#undef pa_context_suspend_source_by_index
+#undef pa_context_set_source_port_by_index
+#undef pa_context_set_source_port_by_name
+#undef pa_context_get_server_info
+#undef pa_context_get_module_info
+#undef pa_context_get_module_info_list
+#undef pa_context_load_module
+#undef pa_context_unload_module
+#undef pa_context_get_client_info
+#undef pa_context_get_client_info_list
+#undef pa_context_kill_client
+#undef pa_context_get_card_info_by_index
+#undef pa_context_get_card_info_by_name
+#undef pa_context_get_card_info_list
+#undef pa_context_set_card_profile_by_index
+#undef pa_context_set_card_profile_by_name
+#undef pa_context_set_port_latency_offset
+#undef pa_context_get_sink_input_info
+#undef pa_context_get_sink_input_info_list
+#undef pa_context_move_sink_input_by_name
+#undef pa_context_move_sink_input_by_index
+#undef pa_context_set_sink_input_volume
+#undef pa_context_set_sink_input_mute
+#undef pa_context_kill_sink_input
+#undef pa_context_get_source_output_info
+#undef pa_context_get_source_output_info_list
+#undef pa_context_move_source_output_by_name
+#undef pa_context_move_source_output_by_index
+#undef pa_context_set_source_output_volume
+#undef pa_context_set_source_output_mute
+#undef pa_context_kill_source_output
+#undef pa_context_stat
+#undef pa_context_get_sample_info_by_name
+#undef pa_context_get_sample_info_by_index
+#undef pa_context_get_sample_info_list
+#undef pa_context_get_autoload_info_by_name
+#undef pa_context_get_autoload_info_by_index
+#undef pa_context_get_autoload_info_list
+#undef pa_context_add_autoload
+#undef pa_context_remove_autoload_by_name
+#undef pa_context_remove_autoload_by_index
+#undef pa_context_subscribe
+#undef pa_context_set_subscribe_callback
+#undef pa_stream_connect_upload
+#undef pa_stream_finish_upload
+#undef pa_context_remove_sample
+#undef pa_context_play_sample
+#undef pa_context_play_sample_with_proplist
+#undef pa_strerror
+#undef pa_xmalloc
+#undef pa_xmalloc0
+#undef pa_xrealloc
+#undef pa_xfree
+#undef pa_xstrdup
+#undef pa_xstrndup
+#undef pa_xmemdup
+#undef pa_utf8_valid
+#undef pa_ascii_valid
+#undef pa_utf8_filter
+#undef pa_ascii_filter
+#undef pa_utf8_to_locale
+#undef pa_locale_to_utf8
+#undef pa_threaded_mainloop_new
+#undef pa_threaded_mainloop_free
+#undef pa_threaded_mainloop_start
+#undef pa_threaded_mainloop_stop
+#undef pa_threaded_mainloop_lock
+#undef pa_threaded_mainloop_unlock
+#undef pa_threaded_mainloop_wait
+#undef pa_threaded_mainloop_signal
+#undef pa_threaded_mainloop_accept
+#undef pa_threaded_mainloop_get_retval
+#undef pa_threaded_mainloop_get_api
+#undef pa_threaded_mainloop_in_thread
+#undef pa_threaded_mainloop_set_name
+#undef pa_threaded_mainloop_once_unlocked
+#undef pa_mainloop_new
+#undef pa_mainloop_free
+#undef pa_mainloop_prepare
+#undef pa_mainloop_poll
+#undef pa_mainloop_dispatch
+#undef pa_mainloop_get_retval
+#undef pa_mainloop_iterate
+#undef pa_mainloop_run
+#undef pa_mainloop_get_api
+#undef pa_mainloop_quit
+#undef pa_mainloop_wakeup
+#undef pa_mainloop_set_poll_func
+#undef pa_signal_init
+#undef pa_signal_done
+#undef pa_signal_new
+#undef pa_signal_free
+#undef pa_signal_set_destroy
+#undef pa_get_user_name
+#undef pa_get_host_name
+#undef pa_get_fqdn
+#undef pa_get_home_dir
+#undef pa_get_binary_name
+#undef pa_path_get_filename
+#undef pa_msleep
+#undef pa_thread_make_realtime
+#undef pa_gettimeofday
+#undef pa_timeval_diff
+#undef pa_timeval_cmp
+#undef pa_timeval_age
+#undef pa_timeval_add
+#undef pa_timeval_sub
+#undef pa_timeval_store
+#undef pa_timeval_load
+#undef pa_rtclock_now
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define pa_get_library_version pa_get_library_version_dylibloader_wrapper_pulse
+#define pa_bytes_per_second pa_bytes_per_second_dylibloader_wrapper_pulse
+#define pa_frame_size pa_frame_size_dylibloader_wrapper_pulse
+#define pa_sample_size pa_sample_size_dylibloader_wrapper_pulse
+#define pa_sample_size_of_format pa_sample_size_of_format_dylibloader_wrapper_pulse
+#define pa_bytes_to_usec pa_bytes_to_usec_dylibloader_wrapper_pulse
+#define pa_usec_to_bytes pa_usec_to_bytes_dylibloader_wrapper_pulse
+#define pa_sample_spec_init pa_sample_spec_init_dylibloader_wrapper_pulse
+#define pa_sample_format_valid pa_sample_format_valid_dylibloader_wrapper_pulse
+#define pa_sample_rate_valid pa_sample_rate_valid_dylibloader_wrapper_pulse
+#define pa_channels_valid pa_channels_valid_dylibloader_wrapper_pulse
+#define pa_sample_spec_valid pa_sample_spec_valid_dylibloader_wrapper_pulse
+#define pa_sample_spec_equal pa_sample_spec_equal_dylibloader_wrapper_pulse
+#define pa_sample_format_to_string pa_sample_format_to_string_dylibloader_wrapper_pulse
+#define pa_parse_sample_format pa_parse_sample_format_dylibloader_wrapper_pulse
+#define pa_sample_spec_snprint pa_sample_spec_snprint_dylibloader_wrapper_pulse
+#define pa_bytes_snprint pa_bytes_snprint_dylibloader_wrapper_pulse
+#define pa_sample_format_is_le pa_sample_format_is_le_dylibloader_wrapper_pulse
+#define pa_sample_format_is_be pa_sample_format_is_be_dylibloader_wrapper_pulse
+#define pa_direction_valid pa_direction_valid_dylibloader_wrapper_pulse
+#define pa_direction_to_string pa_direction_to_string_dylibloader_wrapper_pulse
+#define pa_mainloop_api_once pa_mainloop_api_once_dylibloader_wrapper_pulse
+#define pa_proplist_new pa_proplist_new_dylibloader_wrapper_pulse
+#define pa_proplist_free pa_proplist_free_dylibloader_wrapper_pulse
+#define pa_proplist_key_valid pa_proplist_key_valid_dylibloader_wrapper_pulse
+#define pa_proplist_sets pa_proplist_sets_dylibloader_wrapper_pulse
+#define pa_proplist_setp pa_proplist_setp_dylibloader_wrapper_pulse
+#define pa_proplist_setf pa_proplist_setf_dylibloader_wrapper_pulse
+#define pa_proplist_set pa_proplist_set_dylibloader_wrapper_pulse
+#define pa_proplist_gets pa_proplist_gets_dylibloader_wrapper_pulse
+#define pa_proplist_get pa_proplist_get_dylibloader_wrapper_pulse
+#define pa_proplist_update pa_proplist_update_dylibloader_wrapper_pulse
+#define pa_proplist_unset pa_proplist_unset_dylibloader_wrapper_pulse
+#define pa_proplist_unset_many pa_proplist_unset_many_dylibloader_wrapper_pulse
+#define pa_proplist_iterate pa_proplist_iterate_dylibloader_wrapper_pulse
+#define pa_proplist_to_string pa_proplist_to_string_dylibloader_wrapper_pulse
+#define pa_proplist_to_string_sep pa_proplist_to_string_sep_dylibloader_wrapper_pulse
+#define pa_proplist_from_string pa_proplist_from_string_dylibloader_wrapper_pulse
+#define pa_proplist_contains pa_proplist_contains_dylibloader_wrapper_pulse
+#define pa_proplist_clear pa_proplist_clear_dylibloader_wrapper_pulse
+#define pa_proplist_copy pa_proplist_copy_dylibloader_wrapper_pulse
+#define pa_proplist_size pa_proplist_size_dylibloader_wrapper_pulse
+#define pa_proplist_isempty pa_proplist_isempty_dylibloader_wrapper_pulse
+#define pa_proplist_equal pa_proplist_equal_dylibloader_wrapper_pulse
+#define pa_channel_map_init pa_channel_map_init_dylibloader_wrapper_pulse
+#define pa_channel_map_init_mono pa_channel_map_init_mono_dylibloader_wrapper_pulse
+#define pa_channel_map_init_stereo pa_channel_map_init_stereo_dylibloader_wrapper_pulse
+#define pa_channel_map_init_auto pa_channel_map_init_auto_dylibloader_wrapper_pulse
+#define pa_channel_map_init_extend pa_channel_map_init_extend_dylibloader_wrapper_pulse
+#define pa_channel_position_to_string pa_channel_position_to_string_dylibloader_wrapper_pulse
+#define pa_channel_position_from_string pa_channel_position_from_string_dylibloader_wrapper_pulse
+#define pa_channel_position_to_pretty_string pa_channel_position_to_pretty_string_dylibloader_wrapper_pulse
+#define pa_channel_map_snprint pa_channel_map_snprint_dylibloader_wrapper_pulse
+#define pa_channel_map_parse pa_channel_map_parse_dylibloader_wrapper_pulse
+#define pa_channel_map_equal pa_channel_map_equal_dylibloader_wrapper_pulse
+#define pa_channel_map_valid pa_channel_map_valid_dylibloader_wrapper_pulse
+#define pa_channel_map_compatible pa_channel_map_compatible_dylibloader_wrapper_pulse
+#define pa_channel_map_superset pa_channel_map_superset_dylibloader_wrapper_pulse
+#define pa_channel_map_can_balance pa_channel_map_can_balance_dylibloader_wrapper_pulse
+#define pa_channel_map_can_fade pa_channel_map_can_fade_dylibloader_wrapper_pulse
+#define pa_channel_map_can_lfe_balance pa_channel_map_can_lfe_balance_dylibloader_wrapper_pulse
+#define pa_channel_map_to_name pa_channel_map_to_name_dylibloader_wrapper_pulse
+#define pa_channel_map_to_pretty_name pa_channel_map_to_pretty_name_dylibloader_wrapper_pulse
+#define pa_channel_map_has_position pa_channel_map_has_position_dylibloader_wrapper_pulse
+#define pa_channel_map_mask pa_channel_map_mask_dylibloader_wrapper_pulse
+#define pa_encoding_to_string pa_encoding_to_string_dylibloader_wrapper_pulse
+#define pa_encoding_from_string pa_encoding_from_string_dylibloader_wrapper_pulse
+#define pa_format_info_new pa_format_info_new_dylibloader_wrapper_pulse
+#define pa_format_info_copy pa_format_info_copy_dylibloader_wrapper_pulse
+#define pa_format_info_free pa_format_info_free_dylibloader_wrapper_pulse
+#define pa_format_info_valid pa_format_info_valid_dylibloader_wrapper_pulse
+#define pa_format_info_is_pcm pa_format_info_is_pcm_dylibloader_wrapper_pulse
+#define pa_format_info_is_compatible pa_format_info_is_compatible_dylibloader_wrapper_pulse
+#define pa_format_info_snprint pa_format_info_snprint_dylibloader_wrapper_pulse
+#define pa_format_info_from_string pa_format_info_from_string_dylibloader_wrapper_pulse
+#define pa_format_info_from_sample_spec pa_format_info_from_sample_spec_dylibloader_wrapper_pulse
+#define pa_format_info_to_sample_spec pa_format_info_to_sample_spec_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_type pa_format_info_get_prop_type_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_int pa_format_info_get_prop_int_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_int_range pa_format_info_get_prop_int_range_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_int_array pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_string pa_format_info_get_prop_string_dylibloader_wrapper_pulse
+#define pa_format_info_get_prop_string_array pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse
+#define pa_format_info_free_string_array pa_format_info_free_string_array_dylibloader_wrapper_pulse
+#define pa_format_info_get_sample_format pa_format_info_get_sample_format_dylibloader_wrapper_pulse
+#define pa_format_info_get_rate pa_format_info_get_rate_dylibloader_wrapper_pulse
+#define pa_format_info_get_channels pa_format_info_get_channels_dylibloader_wrapper_pulse
+#define pa_format_info_get_channel_map pa_format_info_get_channel_map_dylibloader_wrapper_pulse
+#define pa_format_info_set_prop_int pa_format_info_set_prop_int_dylibloader_wrapper_pulse
+#define pa_format_info_set_prop_int_array pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse
+#define pa_format_info_set_prop_int_range pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse
+#define pa_format_info_set_prop_string pa_format_info_set_prop_string_dylibloader_wrapper_pulse
+#define pa_format_info_set_prop_string_array pa_format_info_set_prop_string_array_dylibloader_wrapper_pulse
+#define pa_format_info_set_sample_format pa_format_info_set_sample_format_dylibloader_wrapper_pulse
+#define pa_format_info_set_rate pa_format_info_set_rate_dylibloader_wrapper_pulse
+#define pa_format_info_set_channels pa_format_info_set_channels_dylibloader_wrapper_pulse
+#define pa_format_info_set_channel_map pa_format_info_set_channel_map_dylibloader_wrapper_pulse
+#define pa_operation_ref pa_operation_ref_dylibloader_wrapper_pulse
+#define pa_operation_unref pa_operation_unref_dylibloader_wrapper_pulse
+#define pa_operation_cancel pa_operation_cancel_dylibloader_wrapper_pulse
+#define pa_operation_get_state pa_operation_get_state_dylibloader_wrapper_pulse
+#define pa_operation_set_state_callback pa_operation_set_state_callback_dylibloader_wrapper_pulse
+#define pa_context_new pa_context_new_dylibloader_wrapper_pulse
+#define pa_context_new_with_proplist pa_context_new_with_proplist_dylibloader_wrapper_pulse
+#define pa_context_unref pa_context_unref_dylibloader_wrapper_pulse
+#define pa_context_ref pa_context_ref_dylibloader_wrapper_pulse
+#define pa_context_set_state_callback pa_context_set_state_callback_dylibloader_wrapper_pulse
+#define pa_context_set_event_callback pa_context_set_event_callback_dylibloader_wrapper_pulse
+#define pa_context_errno pa_context_errno_dylibloader_wrapper_pulse
+#define pa_context_is_pending pa_context_is_pending_dylibloader_wrapper_pulse
+#define pa_context_get_state pa_context_get_state_dylibloader_wrapper_pulse
+#define pa_context_connect pa_context_connect_dylibloader_wrapper_pulse
+#define pa_context_disconnect pa_context_disconnect_dylibloader_wrapper_pulse
+#define pa_context_drain pa_context_drain_dylibloader_wrapper_pulse
+#define pa_context_exit_daemon pa_context_exit_daemon_dylibloader_wrapper_pulse
+#define pa_context_set_default_sink pa_context_set_default_sink_dylibloader_wrapper_pulse
+#define pa_context_set_default_source pa_context_set_default_source_dylibloader_wrapper_pulse
+#define pa_context_is_local pa_context_is_local_dylibloader_wrapper_pulse
+#define pa_context_set_name pa_context_set_name_dylibloader_wrapper_pulse
+#define pa_context_get_server pa_context_get_server_dylibloader_wrapper_pulse
+#define pa_context_get_protocol_version pa_context_get_protocol_version_dylibloader_wrapper_pulse
+#define pa_context_get_server_protocol_version pa_context_get_server_protocol_version_dylibloader_wrapper_pulse
+#define pa_context_proplist_update pa_context_proplist_update_dylibloader_wrapper_pulse
+#define pa_context_proplist_remove pa_context_proplist_remove_dylibloader_wrapper_pulse
+#define pa_context_get_index pa_context_get_index_dylibloader_wrapper_pulse
+#define pa_context_rttime_new pa_context_rttime_new_dylibloader_wrapper_pulse
+#define pa_context_rttime_restart pa_context_rttime_restart_dylibloader_wrapper_pulse
+#define pa_context_get_tile_size pa_context_get_tile_size_dylibloader_wrapper_pulse
+#define pa_context_load_cookie_from_file pa_context_load_cookie_from_file_dylibloader_wrapper_pulse
+#define pa_cvolume_equal pa_cvolume_equal_dylibloader_wrapper_pulse
+#define pa_cvolume_init pa_cvolume_init_dylibloader_wrapper_pulse
+#define pa_cvolume_set pa_cvolume_set_dylibloader_wrapper_pulse
+#define pa_cvolume_snprint pa_cvolume_snprint_dylibloader_wrapper_pulse
+#define pa_sw_cvolume_snprint_dB pa_sw_cvolume_snprint_dB_dylibloader_wrapper_pulse
+#define pa_cvolume_snprint_verbose pa_cvolume_snprint_verbose_dylibloader_wrapper_pulse
+#define pa_volume_snprint pa_volume_snprint_dylibloader_wrapper_pulse
+#define pa_sw_volume_snprint_dB pa_sw_volume_snprint_dB_dylibloader_wrapper_pulse
+#define pa_volume_snprint_verbose pa_volume_snprint_verbose_dylibloader_wrapper_pulse
+#define pa_cvolume_avg pa_cvolume_avg_dylibloader_wrapper_pulse
+#define pa_cvolume_avg_mask pa_cvolume_avg_mask_dylibloader_wrapper_pulse
+#define pa_cvolume_max pa_cvolume_max_dylibloader_wrapper_pulse
+#define pa_cvolume_max_mask pa_cvolume_max_mask_dylibloader_wrapper_pulse
+#define pa_cvolume_min pa_cvolume_min_dylibloader_wrapper_pulse
+#define pa_cvolume_min_mask pa_cvolume_min_mask_dylibloader_wrapper_pulse
+#define pa_cvolume_valid pa_cvolume_valid_dylibloader_wrapper_pulse
+#define pa_cvolume_channels_equal_to pa_cvolume_channels_equal_to_dylibloader_wrapper_pulse
+#define pa_sw_volume_multiply pa_sw_volume_multiply_dylibloader_wrapper_pulse
+#define pa_sw_cvolume_multiply pa_sw_cvolume_multiply_dylibloader_wrapper_pulse
+#define pa_sw_cvolume_multiply_scalar pa_sw_cvolume_multiply_scalar_dylibloader_wrapper_pulse
+#define pa_sw_volume_divide pa_sw_volume_divide_dylibloader_wrapper_pulse
+#define pa_sw_cvolume_divide pa_sw_cvolume_divide_dylibloader_wrapper_pulse
+#define pa_sw_cvolume_divide_scalar pa_sw_cvolume_divide_scalar_dylibloader_wrapper_pulse
+#define pa_sw_volume_from_dB pa_sw_volume_from_dB_dylibloader_wrapper_pulse
+#define pa_sw_volume_to_dB pa_sw_volume_to_dB_dylibloader_wrapper_pulse
+#define pa_sw_volume_from_linear pa_sw_volume_from_linear_dylibloader_wrapper_pulse
+#define pa_sw_volume_to_linear pa_sw_volume_to_linear_dylibloader_wrapper_pulse
+#define pa_cvolume_remap pa_cvolume_remap_dylibloader_wrapper_pulse
+#define pa_cvolume_compatible pa_cvolume_compatible_dylibloader_wrapper_pulse
+#define pa_cvolume_compatible_with_channel_map pa_cvolume_compatible_with_channel_map_dylibloader_wrapper_pulse
+#define pa_cvolume_get_balance pa_cvolume_get_balance_dylibloader_wrapper_pulse
+#define pa_cvolume_set_balance pa_cvolume_set_balance_dylibloader_wrapper_pulse
+#define pa_cvolume_get_fade pa_cvolume_get_fade_dylibloader_wrapper_pulse
+#define pa_cvolume_set_fade pa_cvolume_set_fade_dylibloader_wrapper_pulse
+#define pa_cvolume_get_lfe_balance pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse
+#define pa_cvolume_set_lfe_balance pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse
+#define pa_cvolume_scale pa_cvolume_scale_dylibloader_wrapper_pulse
+#define pa_cvolume_scale_mask pa_cvolume_scale_mask_dylibloader_wrapper_pulse
+#define pa_cvolume_set_position pa_cvolume_set_position_dylibloader_wrapper_pulse
+#define pa_cvolume_get_position pa_cvolume_get_position_dylibloader_wrapper_pulse
+#define pa_cvolume_merge pa_cvolume_merge_dylibloader_wrapper_pulse
+#define pa_cvolume_inc_clamp pa_cvolume_inc_clamp_dylibloader_wrapper_pulse
+#define pa_cvolume_inc pa_cvolume_inc_dylibloader_wrapper_pulse
+#define pa_cvolume_dec pa_cvolume_dec_dylibloader_wrapper_pulse
+#define pa_stream_new pa_stream_new_dylibloader_wrapper_pulse
+#define pa_stream_new_with_proplist pa_stream_new_with_proplist_dylibloader_wrapper_pulse
+#define pa_stream_new_extended pa_stream_new_extended_dylibloader_wrapper_pulse
+#define pa_stream_unref pa_stream_unref_dylibloader_wrapper_pulse
+#define pa_stream_ref pa_stream_ref_dylibloader_wrapper_pulse
+#define pa_stream_get_state pa_stream_get_state_dylibloader_wrapper_pulse
+#define pa_stream_get_context pa_stream_get_context_dylibloader_wrapper_pulse
+#define pa_stream_get_index pa_stream_get_index_dylibloader_wrapper_pulse
+#define pa_stream_get_device_index pa_stream_get_device_index_dylibloader_wrapper_pulse
+#define pa_stream_get_device_name pa_stream_get_device_name_dylibloader_wrapper_pulse
+#define pa_stream_is_suspended pa_stream_is_suspended_dylibloader_wrapper_pulse
+#define pa_stream_is_corked pa_stream_is_corked_dylibloader_wrapper_pulse
+#define pa_stream_connect_playback pa_stream_connect_playback_dylibloader_wrapper_pulse
+#define pa_stream_connect_record pa_stream_connect_record_dylibloader_wrapper_pulse
+#define pa_stream_disconnect pa_stream_disconnect_dylibloader_wrapper_pulse
+#define pa_stream_begin_write pa_stream_begin_write_dylibloader_wrapper_pulse
+#define pa_stream_cancel_write pa_stream_cancel_write_dylibloader_wrapper_pulse
+#define pa_stream_write pa_stream_write_dylibloader_wrapper_pulse
+#define pa_stream_write_ext_free pa_stream_write_ext_free_dylibloader_wrapper_pulse
+#define pa_stream_peek pa_stream_peek_dylibloader_wrapper_pulse
+#define pa_stream_drop pa_stream_drop_dylibloader_wrapper_pulse
+#define pa_stream_writable_size pa_stream_writable_size_dylibloader_wrapper_pulse
+#define pa_stream_readable_size pa_stream_readable_size_dylibloader_wrapper_pulse
+#define pa_stream_drain pa_stream_drain_dylibloader_wrapper_pulse
+#define pa_stream_update_timing_info pa_stream_update_timing_info_dylibloader_wrapper_pulse
+#define pa_stream_set_state_callback pa_stream_set_state_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_write_callback pa_stream_set_write_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_read_callback pa_stream_set_read_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_overflow_callback pa_stream_set_overflow_callback_dylibloader_wrapper_pulse
+#define pa_stream_get_underflow_index pa_stream_get_underflow_index_dylibloader_wrapper_pulse
+#define pa_stream_set_underflow_callback pa_stream_set_underflow_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_started_callback pa_stream_set_started_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_latency_update_callback pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_moved_callback pa_stream_set_moved_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_suspended_callback pa_stream_set_suspended_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_event_callback pa_stream_set_event_callback_dylibloader_wrapper_pulse
+#define pa_stream_set_buffer_attr_callback pa_stream_set_buffer_attr_callback_dylibloader_wrapper_pulse
+#define pa_stream_cork pa_stream_cork_dylibloader_wrapper_pulse
+#define pa_stream_flush pa_stream_flush_dylibloader_wrapper_pulse
+#define pa_stream_prebuf pa_stream_prebuf_dylibloader_wrapper_pulse
+#define pa_stream_trigger pa_stream_trigger_dylibloader_wrapper_pulse
+#define pa_stream_set_name pa_stream_set_name_dylibloader_wrapper_pulse
+#define pa_stream_get_time pa_stream_get_time_dylibloader_wrapper_pulse
+#define pa_stream_get_latency pa_stream_get_latency_dylibloader_wrapper_pulse
+#define pa_stream_get_timing_info pa_stream_get_timing_info_dylibloader_wrapper_pulse
+#define pa_stream_get_sample_spec pa_stream_get_sample_spec_dylibloader_wrapper_pulse
+#define pa_stream_get_channel_map pa_stream_get_channel_map_dylibloader_wrapper_pulse
+#define pa_stream_get_format_info pa_stream_get_format_info_dylibloader_wrapper_pulse
+#define pa_stream_get_buffer_attr pa_stream_get_buffer_attr_dylibloader_wrapper_pulse
+#define pa_stream_set_buffer_attr pa_stream_set_buffer_attr_dylibloader_wrapper_pulse
+#define pa_stream_update_sample_rate pa_stream_update_sample_rate_dylibloader_wrapper_pulse
+#define pa_stream_proplist_update pa_stream_proplist_update_dylibloader_wrapper_pulse
+#define pa_stream_proplist_remove pa_stream_proplist_remove_dylibloader_wrapper_pulse
+#define pa_stream_set_monitor_stream pa_stream_set_monitor_stream_dylibloader_wrapper_pulse
+#define pa_stream_get_monitor_stream pa_stream_get_monitor_stream_dylibloader_wrapper_pulse
+#define pa_context_get_sink_info_by_name pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_sink_info_by_index pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse
+#define pa_context_get_sink_info_list pa_context_get_sink_info_list_dylibloader_wrapper_pulse
+#define pa_context_set_sink_volume_by_index pa_context_set_sink_volume_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_sink_volume_by_name pa_context_set_sink_volume_by_name_dylibloader_wrapper_pulse
+#define pa_context_set_sink_mute_by_index pa_context_set_sink_mute_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_sink_mute_by_name pa_context_set_sink_mute_by_name_dylibloader_wrapper_pulse
+#define pa_context_suspend_sink_by_name pa_context_suspend_sink_by_name_dylibloader_wrapper_pulse
+#define pa_context_suspend_sink_by_index pa_context_suspend_sink_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_sink_port_by_index pa_context_set_sink_port_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_sink_port_by_name pa_context_set_sink_port_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_source_info_by_name pa_context_get_source_info_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_source_info_by_index pa_context_get_source_info_by_index_dylibloader_wrapper_pulse
+#define pa_context_get_source_info_list pa_context_get_source_info_list_dylibloader_wrapper_pulse
+#define pa_context_set_source_volume_by_index pa_context_set_source_volume_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_source_volume_by_name pa_context_set_source_volume_by_name_dylibloader_wrapper_pulse
+#define pa_context_set_source_mute_by_index pa_context_set_source_mute_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_source_mute_by_name pa_context_set_source_mute_by_name_dylibloader_wrapper_pulse
+#define pa_context_suspend_source_by_name pa_context_suspend_source_by_name_dylibloader_wrapper_pulse
+#define pa_context_suspend_source_by_index pa_context_suspend_source_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_source_port_by_index pa_context_set_source_port_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_source_port_by_name pa_context_set_source_port_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_server_info pa_context_get_server_info_dylibloader_wrapper_pulse
+#define pa_context_get_module_info pa_context_get_module_info_dylibloader_wrapper_pulse
+#define pa_context_get_module_info_list pa_context_get_module_info_list_dylibloader_wrapper_pulse
+#define pa_context_load_module pa_context_load_module_dylibloader_wrapper_pulse
+#define pa_context_unload_module pa_context_unload_module_dylibloader_wrapper_pulse
+#define pa_context_get_client_info pa_context_get_client_info_dylibloader_wrapper_pulse
+#define pa_context_get_client_info_list pa_context_get_client_info_list_dylibloader_wrapper_pulse
+#define pa_context_kill_client pa_context_kill_client_dylibloader_wrapper_pulse
+#define pa_context_get_card_info_by_index pa_context_get_card_info_by_index_dylibloader_wrapper_pulse
+#define pa_context_get_card_info_by_name pa_context_get_card_info_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_card_info_list pa_context_get_card_info_list_dylibloader_wrapper_pulse
+#define pa_context_set_card_profile_by_index pa_context_set_card_profile_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_card_profile_by_name pa_context_set_card_profile_by_name_dylibloader_wrapper_pulse
+#define pa_context_set_port_latency_offset pa_context_set_port_latency_offset_dylibloader_wrapper_pulse
+#define pa_context_get_sink_input_info pa_context_get_sink_input_info_dylibloader_wrapper_pulse
+#define pa_context_get_sink_input_info_list pa_context_get_sink_input_info_list_dylibloader_wrapper_pulse
+#define pa_context_move_sink_input_by_name pa_context_move_sink_input_by_name_dylibloader_wrapper_pulse
+#define pa_context_move_sink_input_by_index pa_context_move_sink_input_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_sink_input_volume pa_context_set_sink_input_volume_dylibloader_wrapper_pulse
+#define pa_context_set_sink_input_mute pa_context_set_sink_input_mute_dylibloader_wrapper_pulse
+#define pa_context_kill_sink_input pa_context_kill_sink_input_dylibloader_wrapper_pulse
+#define pa_context_get_source_output_info pa_context_get_source_output_info_dylibloader_wrapper_pulse
+#define pa_context_get_source_output_info_list pa_context_get_source_output_info_list_dylibloader_wrapper_pulse
+#define pa_context_move_source_output_by_name pa_context_move_source_output_by_name_dylibloader_wrapper_pulse
+#define pa_context_move_source_output_by_index pa_context_move_source_output_by_index_dylibloader_wrapper_pulse
+#define pa_context_set_source_output_volume pa_context_set_source_output_volume_dylibloader_wrapper_pulse
+#define pa_context_set_source_output_mute pa_context_set_source_output_mute_dylibloader_wrapper_pulse
+#define pa_context_kill_source_output pa_context_kill_source_output_dylibloader_wrapper_pulse
+#define pa_context_stat pa_context_stat_dylibloader_wrapper_pulse
+#define pa_context_get_sample_info_by_name pa_context_get_sample_info_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_sample_info_by_index pa_context_get_sample_info_by_index_dylibloader_wrapper_pulse
+#define pa_context_get_sample_info_list pa_context_get_sample_info_list_dylibloader_wrapper_pulse
+#define pa_context_get_autoload_info_by_name pa_context_get_autoload_info_by_name_dylibloader_wrapper_pulse
+#define pa_context_get_autoload_info_by_index pa_context_get_autoload_info_by_index_dylibloader_wrapper_pulse
+#define pa_context_get_autoload_info_list pa_context_get_autoload_info_list_dylibloader_wrapper_pulse
+#define pa_context_add_autoload pa_context_add_autoload_dylibloader_wrapper_pulse
+#define pa_context_remove_autoload_by_name pa_context_remove_autoload_by_name_dylibloader_wrapper_pulse
+#define pa_context_remove_autoload_by_index pa_context_remove_autoload_by_index_dylibloader_wrapper_pulse
+#define pa_context_subscribe pa_context_subscribe_dylibloader_wrapper_pulse
+#define pa_context_set_subscribe_callback pa_context_set_subscribe_callback_dylibloader_wrapper_pulse
+#define pa_stream_connect_upload pa_stream_connect_upload_dylibloader_wrapper_pulse
+#define pa_stream_finish_upload pa_stream_finish_upload_dylibloader_wrapper_pulse
+#define pa_context_remove_sample pa_context_remove_sample_dylibloader_wrapper_pulse
+#define pa_context_play_sample pa_context_play_sample_dylibloader_wrapper_pulse
+#define pa_context_play_sample_with_proplist pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse
+#define pa_strerror pa_strerror_dylibloader_wrapper_pulse
+#define pa_xmalloc pa_xmalloc_dylibloader_wrapper_pulse
+#define pa_xmalloc0 pa_xmalloc0_dylibloader_wrapper_pulse
+#define pa_xrealloc pa_xrealloc_dylibloader_wrapper_pulse
+#define pa_xfree pa_xfree_dylibloader_wrapper_pulse
+#define pa_xstrdup pa_xstrdup_dylibloader_wrapper_pulse
+#define pa_xstrndup pa_xstrndup_dylibloader_wrapper_pulse
+#define pa_xmemdup pa_xmemdup_dylibloader_wrapper_pulse
+#define pa_utf8_valid pa_utf8_valid_dylibloader_wrapper_pulse
+#define pa_ascii_valid pa_ascii_valid_dylibloader_wrapper_pulse
+#define pa_utf8_filter pa_utf8_filter_dylibloader_wrapper_pulse
+#define pa_ascii_filter pa_ascii_filter_dylibloader_wrapper_pulse
+#define pa_utf8_to_locale pa_utf8_to_locale_dylibloader_wrapper_pulse
+#define pa_locale_to_utf8 pa_locale_to_utf8_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_new pa_threaded_mainloop_new_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_free pa_threaded_mainloop_free_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_start pa_threaded_mainloop_start_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_stop pa_threaded_mainloop_stop_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_lock pa_threaded_mainloop_lock_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_unlock pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_wait pa_threaded_mainloop_wait_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_signal pa_threaded_mainloop_signal_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_accept pa_threaded_mainloop_accept_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_get_retval pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_set_name pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse
+#define pa_threaded_mainloop_once_unlocked pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse
+#define pa_mainloop_new pa_mainloop_new_dylibloader_wrapper_pulse
+#define pa_mainloop_free pa_mainloop_free_dylibloader_wrapper_pulse
+#define pa_mainloop_prepare pa_mainloop_prepare_dylibloader_wrapper_pulse
+#define pa_mainloop_poll pa_mainloop_poll_dylibloader_wrapper_pulse
+#define pa_mainloop_dispatch pa_mainloop_dispatch_dylibloader_wrapper_pulse
+#define pa_mainloop_get_retval pa_mainloop_get_retval_dylibloader_wrapper_pulse
+#define pa_mainloop_iterate pa_mainloop_iterate_dylibloader_wrapper_pulse
+#define pa_mainloop_run pa_mainloop_run_dylibloader_wrapper_pulse
+#define pa_mainloop_get_api pa_mainloop_get_api_dylibloader_wrapper_pulse
+#define pa_mainloop_quit pa_mainloop_quit_dylibloader_wrapper_pulse
+#define pa_mainloop_wakeup pa_mainloop_wakeup_dylibloader_wrapper_pulse
+#define pa_mainloop_set_poll_func pa_mainloop_set_poll_func_dylibloader_wrapper_pulse
+#define pa_signal_init pa_signal_init_dylibloader_wrapper_pulse
+#define pa_signal_done pa_signal_done_dylibloader_wrapper_pulse
+#define pa_signal_new pa_signal_new_dylibloader_wrapper_pulse
+#define pa_signal_free pa_signal_free_dylibloader_wrapper_pulse
+#define pa_signal_set_destroy pa_signal_set_destroy_dylibloader_wrapper_pulse
+#define pa_get_user_name pa_get_user_name_dylibloader_wrapper_pulse
+#define pa_get_host_name pa_get_host_name_dylibloader_wrapper_pulse
+#define pa_get_fqdn pa_get_fqdn_dylibloader_wrapper_pulse
+#define pa_get_home_dir pa_get_home_dir_dylibloader_wrapper_pulse
+#define pa_get_binary_name pa_get_binary_name_dylibloader_wrapper_pulse
+#define pa_path_get_filename pa_path_get_filename_dylibloader_wrapper_pulse
+#define pa_msleep pa_msleep_dylibloader_wrapper_pulse
+#define pa_thread_make_realtime pa_thread_make_realtime_dylibloader_wrapper_pulse
+#define pa_gettimeofday pa_gettimeofday_dylibloader_wrapper_pulse
+#define pa_timeval_diff pa_timeval_diff_dylibloader_wrapper_pulse
+#define pa_timeval_cmp pa_timeval_cmp_dylibloader_wrapper_pulse
+#define pa_timeval_age pa_timeval_age_dylibloader_wrapper_pulse
+#define pa_timeval_add pa_timeval_add_dylibloader_wrapper_pulse
+#define pa_timeval_sub pa_timeval_sub_dylibloader_wrapper_pulse
+#define pa_timeval_store pa_timeval_store_dylibloader_wrapper_pulse
+#define pa_timeval_load pa_timeval_load_dylibloader_wrapper_pulse
+#define pa_rtclock_now pa_rtclock_now_dylibloader_wrapper_pulse
+extern const char* (*pa_get_library_version_dylibloader_wrapper_pulse)( void);
+extern size_t (*pa_bytes_per_second_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+extern size_t (*pa_frame_size_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+extern size_t (*pa_sample_size_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+extern size_t (*pa_sample_size_of_format_dylibloader_wrapper_pulse)( pa_sample_format_t);
+extern pa_usec_t (*pa_bytes_to_usec_dylibloader_wrapper_pulse)( uint64_t,const pa_sample_spec*);
+extern size_t (*pa_usec_to_bytes_dylibloader_wrapper_pulse)( pa_usec_t,const pa_sample_spec*);
+extern pa_sample_spec* (*pa_sample_spec_init_dylibloader_wrapper_pulse)( pa_sample_spec*);
+extern int (*pa_sample_format_valid_dylibloader_wrapper_pulse)( unsigned);
+extern int (*pa_sample_rate_valid_dylibloader_wrapper_pulse)( uint32_t);
+extern int (*pa_channels_valid_dylibloader_wrapper_pulse)( uint8_t);
+extern int (*pa_sample_spec_valid_dylibloader_wrapper_pulse)(const pa_sample_spec*);
+extern int (*pa_sample_spec_equal_dylibloader_wrapper_pulse)(const pa_sample_spec*,const pa_sample_spec*);
+extern const char* (*pa_sample_format_to_string_dylibloader_wrapper_pulse)( pa_sample_format_t);
+extern pa_sample_format_t (*pa_parse_sample_format_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_sample_spec_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_sample_spec*);
+extern char* (*pa_bytes_snprint_dylibloader_wrapper_pulse)( char*, size_t, unsigned);
+extern int (*pa_sample_format_is_le_dylibloader_wrapper_pulse)( pa_sample_format_t);
+extern int (*pa_sample_format_is_be_dylibloader_wrapper_pulse)( pa_sample_format_t);
+extern int (*pa_direction_valid_dylibloader_wrapper_pulse)( pa_direction_t);
+extern const char* (*pa_direction_to_string_dylibloader_wrapper_pulse)( pa_direction_t);
+extern void (*pa_mainloop_api_once_dylibloader_wrapper_pulse)( pa_mainloop_api*, void*, void*);
+extern pa_proplist* (*pa_proplist_new_dylibloader_wrapper_pulse)( void);
+extern void (*pa_proplist_free_dylibloader_wrapper_pulse)( pa_proplist*);
+extern int (*pa_proplist_key_valid_dylibloader_wrapper_pulse)(const char*);
+extern int (*pa_proplist_sets_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*);
+extern int (*pa_proplist_setp_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+extern int (*pa_proplist_setf_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const char*,...);
+extern int (*pa_proplist_set_dylibloader_wrapper_pulse)( pa_proplist*,const char*,const void*, size_t);
+extern const char* (*pa_proplist_gets_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+extern int (*pa_proplist_get_dylibloader_wrapper_pulse)(const pa_proplist*,const char*,const void**, size_t*);
+extern void (*pa_proplist_update_dylibloader_wrapper_pulse)( pa_proplist*, pa_update_mode_t,const pa_proplist*);
+extern int (*pa_proplist_unset_dylibloader_wrapper_pulse)( pa_proplist*,const char*);
+extern int (*pa_proplist_unset_many_dylibloader_wrapper_pulse)( pa_proplist*,const char* []);
+extern const char* (*pa_proplist_iterate_dylibloader_wrapper_pulse)(const pa_proplist*, void**);
+extern char* (*pa_proplist_to_string_dylibloader_wrapper_pulse)(const pa_proplist*);
+extern char* (*pa_proplist_to_string_sep_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+extern pa_proplist* (*pa_proplist_from_string_dylibloader_wrapper_pulse)(const char*);
+extern int (*pa_proplist_contains_dylibloader_wrapper_pulse)(const pa_proplist*,const char*);
+extern void (*pa_proplist_clear_dylibloader_wrapper_pulse)( pa_proplist*);
+extern pa_proplist* (*pa_proplist_copy_dylibloader_wrapper_pulse)(const pa_proplist*);
+extern unsigned (*pa_proplist_size_dylibloader_wrapper_pulse)(const pa_proplist*);
+extern int (*pa_proplist_isempty_dylibloader_wrapper_pulse)(const pa_proplist*);
+extern int (*pa_proplist_equal_dylibloader_wrapper_pulse)(const pa_proplist*,const pa_proplist*);
+extern pa_channel_map* (*pa_channel_map_init_dylibloader_wrapper_pulse)( pa_channel_map*);
+extern pa_channel_map* (*pa_channel_map_init_mono_dylibloader_wrapper_pulse)( pa_channel_map*);
+extern pa_channel_map* (*pa_channel_map_init_stereo_dylibloader_wrapper_pulse)( pa_channel_map*);
+extern pa_channel_map* (*pa_channel_map_init_auto_dylibloader_wrapper_pulse)( pa_channel_map*, unsigned, pa_channel_map_def_t);
+extern pa_channel_map* (*pa_channel_map_init_extend_dylibloader_wrapper_pulse)( pa_channel_map*, unsigned, pa_channel_map_def_t);
+extern const char* (*pa_channel_position_to_string_dylibloader_wrapper_pulse)( pa_channel_position_t);
+extern pa_channel_position_t (*pa_channel_position_from_string_dylibloader_wrapper_pulse)(const char*);
+extern const char* (*pa_channel_position_to_pretty_string_dylibloader_wrapper_pulse)( pa_channel_position_t);
+extern char* (*pa_channel_map_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_channel_map*);
+extern pa_channel_map* (*pa_channel_map_parse_dylibloader_wrapper_pulse)( pa_channel_map*,const char*);
+extern int (*pa_channel_map_equal_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_channel_map*);
+extern int (*pa_channel_map_valid_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern int (*pa_channel_map_compatible_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_sample_spec*);
+extern int (*pa_channel_map_superset_dylibloader_wrapper_pulse)(const pa_channel_map*,const pa_channel_map*);
+extern int (*pa_channel_map_can_balance_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern int (*pa_channel_map_can_fade_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern int (*pa_channel_map_can_lfe_balance_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern const char* (*pa_channel_map_to_name_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern const char* (*pa_channel_map_to_pretty_name_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern int (*pa_channel_map_has_position_dylibloader_wrapper_pulse)(const pa_channel_map*, pa_channel_position_t);
+extern pa_channel_position_mask_t (*pa_channel_map_mask_dylibloader_wrapper_pulse)(const pa_channel_map*);
+extern const char* (*pa_encoding_to_string_dylibloader_wrapper_pulse)( pa_encoding_t);
+extern pa_encoding_t (*pa_encoding_from_string_dylibloader_wrapper_pulse)(const char*);
+extern pa_format_info* (*pa_format_info_new_dylibloader_wrapper_pulse)( void);
+extern pa_format_info* (*pa_format_info_copy_dylibloader_wrapper_pulse)(const pa_format_info*);
+extern void (*pa_format_info_free_dylibloader_wrapper_pulse)( pa_format_info*);
+extern int (*pa_format_info_valid_dylibloader_wrapper_pulse)(const pa_format_info*);
+extern int (*pa_format_info_is_pcm_dylibloader_wrapper_pulse)(const pa_format_info*);
+extern int (*pa_format_info_is_compatible_dylibloader_wrapper_pulse)(const pa_format_info*,const pa_format_info*);
+extern char* (*pa_format_info_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_format_info*);
+extern pa_format_info* (*pa_format_info_from_string_dylibloader_wrapper_pulse)(const char*);
+extern pa_format_info* (*pa_format_info_from_sample_spec_dylibloader_wrapper_pulse)(const pa_sample_spec*,const pa_channel_map*);
+extern int (*pa_format_info_to_sample_spec_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_spec*, pa_channel_map*);
+extern pa_prop_type_t (*pa_format_info_get_prop_type_dylibloader_wrapper_pulse)(const pa_format_info*,const char*);
+extern int (*pa_format_info_get_prop_int_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int*);
+extern int (*pa_format_info_get_prop_int_range_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int*, int*);
+extern int (*pa_format_info_get_prop_int_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, int**, int*);
+extern int (*pa_format_info_get_prop_string_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char**);
+extern int (*pa_format_info_get_prop_string_array_dylibloader_wrapper_pulse)(const pa_format_info*,const char*, char***, int*);
+extern void (*pa_format_info_free_string_array_dylibloader_wrapper_pulse)( char**, int);
+extern int (*pa_format_info_get_sample_format_dylibloader_wrapper_pulse)(const pa_format_info*, pa_sample_format_t*);
+extern int (*pa_format_info_get_rate_dylibloader_wrapper_pulse)(const pa_format_info*, uint32_t*);
+extern int (*pa_format_info_get_channels_dylibloader_wrapper_pulse)(const pa_format_info*, uint8_t*);
+extern int (*pa_format_info_get_channel_map_dylibloader_wrapper_pulse)(const pa_format_info*, pa_channel_map*);
+extern void (*pa_format_info_set_prop_int_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int);
+extern void (*pa_format_info_set_prop_int_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const int*, int);
+extern void (*pa_format_info_set_prop_int_range_dylibloader_wrapper_pulse)( pa_format_info*,const char*, int, int);
+extern void (*pa_format_info_set_prop_string_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const char*);
+extern void (*pa_format_info_set_prop_string_array_dylibloader_wrapper_pulse)( pa_format_info*,const char*,const char**, int);
+extern void (*pa_format_info_set_sample_format_dylibloader_wrapper_pulse)( pa_format_info*, pa_sample_format_t);
+extern void (*pa_format_info_set_rate_dylibloader_wrapper_pulse)( pa_format_info*, int);
+extern void (*pa_format_info_set_channels_dylibloader_wrapper_pulse)( pa_format_info*, int);
+extern void (*pa_format_info_set_channel_map_dylibloader_wrapper_pulse)( pa_format_info*,const pa_channel_map*);
+extern pa_operation* (*pa_operation_ref_dylibloader_wrapper_pulse)( pa_operation*);
+extern void (*pa_operation_unref_dylibloader_wrapper_pulse)( pa_operation*);
+extern void (*pa_operation_cancel_dylibloader_wrapper_pulse)( pa_operation*);
+extern pa_operation_state_t (*pa_operation_get_state_dylibloader_wrapper_pulse)(const pa_operation*);
+extern void (*pa_operation_set_state_callback_dylibloader_wrapper_pulse)( pa_operation*, pa_operation_notify_cb_t, void*);
+extern pa_context* (*pa_context_new_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*);
+extern pa_context* (*pa_context_new_with_proplist_dylibloader_wrapper_pulse)( pa_mainloop_api*,const char*,const pa_proplist*);
+extern void (*pa_context_unref_dylibloader_wrapper_pulse)( pa_context*);
+extern pa_context* (*pa_context_ref_dylibloader_wrapper_pulse)( pa_context*);
+extern void (*pa_context_set_state_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
+extern void (*pa_context_set_event_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_event_cb_t, void*);
+extern int (*pa_context_errno_dylibloader_wrapper_pulse)(const pa_context*);
+extern int (*pa_context_is_pending_dylibloader_wrapper_pulse)(const pa_context*);
+extern pa_context_state_t (*pa_context_get_state_dylibloader_wrapper_pulse)(const pa_context*);
+extern int (*pa_context_connect_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_flags_t,const pa_spawn_api*);
+extern void (*pa_context_disconnect_dylibloader_wrapper_pulse)( pa_context*);
+extern pa_operation* (*pa_context_drain_dylibloader_wrapper_pulse)( pa_context*, pa_context_notify_cb_t, void*);
+extern pa_operation* (*pa_context_exit_daemon_dylibloader_wrapper_pulse)( pa_context*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_default_sink_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_default_source_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+extern int (*pa_context_is_local_dylibloader_wrapper_pulse)(const pa_context*);
+extern pa_operation* (*pa_context_set_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+extern const char* (*pa_context_get_server_dylibloader_wrapper_pulse)(const pa_context*);
+extern uint32_t (*pa_context_get_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
+extern uint32_t (*pa_context_get_server_protocol_version_dylibloader_wrapper_pulse)(const pa_context*);
+extern pa_operation* (*pa_context_proplist_update_dylibloader_wrapper_pulse)( pa_context*, pa_update_mode_t,const pa_proplist*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_proplist_remove_dylibloader_wrapper_pulse)( pa_context*,const char* [], pa_context_success_cb_t, void*);
+extern uint32_t (*pa_context_get_index_dylibloader_wrapper_pulse)(const pa_context*);
+extern pa_time_event* (*pa_context_rttime_new_dylibloader_wrapper_pulse)(const pa_context*, pa_usec_t, pa_time_event_cb_t, void*);
+extern void (*pa_context_rttime_restart_dylibloader_wrapper_pulse)(const pa_context*, pa_time_event*, pa_usec_t);
+extern size_t (*pa_context_get_tile_size_dylibloader_wrapper_pulse)(const pa_context*,const pa_sample_spec*);
+extern int (*pa_context_load_cookie_from_file_dylibloader_wrapper_pulse)( pa_context*,const char*);
+extern int (*pa_cvolume_equal_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_cvolume*);
+extern pa_cvolume* (*pa_cvolume_init_dylibloader_wrapper_pulse)( pa_cvolume*);
+extern pa_cvolume* (*pa_cvolume_set_dylibloader_wrapper_pulse)( pa_cvolume*, unsigned, pa_volume_t);
+extern char* (*pa_cvolume_snprint_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*);
+extern char* (*pa_sw_cvolume_snprint_dB_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*);
+extern char* (*pa_cvolume_snprint_verbose_dylibloader_wrapper_pulse)( char*, size_t,const pa_cvolume*,const pa_channel_map*, int);
+extern char* (*pa_volume_snprint_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t);
+extern char* (*pa_sw_volume_snprint_dB_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t);
+extern char* (*pa_volume_snprint_verbose_dylibloader_wrapper_pulse)( char*, size_t, pa_volume_t, int);
+extern pa_volume_t (*pa_cvolume_avg_dylibloader_wrapper_pulse)(const pa_cvolume*);
+extern pa_volume_t (*pa_cvolume_avg_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+extern pa_volume_t (*pa_cvolume_max_dylibloader_wrapper_pulse)(const pa_cvolume*);
+extern pa_volume_t (*pa_cvolume_max_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+extern pa_volume_t (*pa_cvolume_min_dylibloader_wrapper_pulse)(const pa_cvolume*);
+extern pa_volume_t (*pa_cvolume_min_mask_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_mask_t);
+extern int (*pa_cvolume_valid_dylibloader_wrapper_pulse)(const pa_cvolume*);
+extern int (*pa_cvolume_channels_equal_to_dylibloader_wrapper_pulse)(const pa_cvolume*, pa_volume_t);
+extern pa_volume_t (*pa_sw_volume_multiply_dylibloader_wrapper_pulse)( pa_volume_t, pa_volume_t);
+extern pa_cvolume* (*pa_sw_cvolume_multiply_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+extern pa_cvolume* (*pa_sw_cvolume_multiply_scalar_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*, pa_volume_t);
+extern pa_volume_t (*pa_sw_volume_divide_dylibloader_wrapper_pulse)( pa_volume_t, pa_volume_t);
+extern pa_cvolume* (*pa_sw_cvolume_divide_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+extern pa_cvolume* (*pa_sw_cvolume_divide_scalar_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*, pa_volume_t);
+extern pa_volume_t (*pa_sw_volume_from_dB_dylibloader_wrapper_pulse)( double);
+extern double (*pa_sw_volume_to_dB_dylibloader_wrapper_pulse)( pa_volume_t);
+extern pa_volume_t (*pa_sw_volume_from_linear_dylibloader_wrapper_pulse)( double);
+extern double (*pa_sw_volume_to_linear_dylibloader_wrapper_pulse)( pa_volume_t);
+extern pa_cvolume* (*pa_cvolume_remap_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*,const pa_channel_map*);
+extern int (*pa_cvolume_compatible_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_sample_spec*);
+extern int (*pa_cvolume_compatible_with_channel_map_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+extern float (*pa_cvolume_get_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+extern pa_cvolume* (*pa_cvolume_set_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+extern float (*pa_cvolume_get_fade_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+extern pa_cvolume* (*pa_cvolume_set_fade_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+extern float (*pa_cvolume_get_lfe_balance_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*);
+extern pa_cvolume* (*pa_cvolume_set_lfe_balance_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, float);
+extern pa_cvolume* (*pa_cvolume_scale_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+extern pa_cvolume* (*pa_cvolume_scale_mask_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t,const pa_channel_map*, pa_channel_position_mask_t);
+extern pa_cvolume* (*pa_cvolume_set_position_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_channel_map*, pa_channel_position_t, pa_volume_t);
+extern pa_volume_t (*pa_cvolume_get_position_dylibloader_wrapper_pulse)(const pa_cvolume*,const pa_channel_map*, pa_channel_position_t);
+extern pa_cvolume* (*pa_cvolume_merge_dylibloader_wrapper_pulse)( pa_cvolume*,const pa_cvolume*,const pa_cvolume*);
+extern pa_cvolume* (*pa_cvolume_inc_clamp_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t, pa_volume_t);
+extern pa_cvolume* (*pa_cvolume_inc_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+extern pa_cvolume* (*pa_cvolume_dec_dylibloader_wrapper_pulse)( pa_cvolume*, pa_volume_t);
+extern pa_stream* (*pa_stream_new_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_sample_spec*,const pa_channel_map*);
+extern pa_stream* (*pa_stream_new_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_sample_spec*,const pa_channel_map*, pa_proplist*);
+extern pa_stream* (*pa_stream_new_extended_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_format_info**, unsigned int, pa_proplist*);
+extern void (*pa_stream_unref_dylibloader_wrapper_pulse)( pa_stream*);
+extern pa_stream* (*pa_stream_ref_dylibloader_wrapper_pulse)( pa_stream*);
+extern pa_stream_state_t (*pa_stream_get_state_dylibloader_wrapper_pulse)(const pa_stream*);
+extern pa_context* (*pa_stream_get_context_dylibloader_wrapper_pulse)(const pa_stream*);
+extern uint32_t (*pa_stream_get_index_dylibloader_wrapper_pulse)(const pa_stream*);
+extern uint32_t (*pa_stream_get_device_index_dylibloader_wrapper_pulse)(const pa_stream*);
+extern const char* (*pa_stream_get_device_name_dylibloader_wrapper_pulse)(const pa_stream*);
+extern int (*pa_stream_is_suspended_dylibloader_wrapper_pulse)(const pa_stream*);
+extern int (*pa_stream_is_corked_dylibloader_wrapper_pulse)(const pa_stream*);
+extern int (*pa_stream_connect_playback_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t,const pa_cvolume*, pa_stream*);
+extern int (*pa_stream_connect_record_dylibloader_wrapper_pulse)( pa_stream*,const char*,const pa_buffer_attr*, pa_stream_flags_t);
+extern int (*pa_stream_disconnect_dylibloader_wrapper_pulse)( pa_stream*);
+extern int (*pa_stream_begin_write_dylibloader_wrapper_pulse)( pa_stream*, void**, size_t*);
+extern int (*pa_stream_cancel_write_dylibloader_wrapper_pulse)( pa_stream*);
+extern int (*pa_stream_write_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, int64_t, pa_seek_mode_t);
+extern int (*pa_stream_write_ext_free_dylibloader_wrapper_pulse)( pa_stream*,const void*, size_t, pa_free_cb_t, void*, int64_t, pa_seek_mode_t);
+extern int (*pa_stream_peek_dylibloader_wrapper_pulse)( pa_stream*,const void**, size_t*);
+extern int (*pa_stream_drop_dylibloader_wrapper_pulse)( pa_stream*);
+extern size_t (*pa_stream_writable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+extern size_t (*pa_stream_readable_size_dylibloader_wrapper_pulse)(const pa_stream*);
+extern pa_operation* (*pa_stream_drain_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_update_timing_info_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+extern void (*pa_stream_set_state_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_write_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
+extern void (*pa_stream_set_read_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_request_cb_t, void*);
+extern void (*pa_stream_set_overflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern int64_t (*pa_stream_get_underflow_index_dylibloader_wrapper_pulse)(const pa_stream*);
+extern void (*pa_stream_set_underflow_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_started_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_latency_update_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_moved_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_suspended_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern void (*pa_stream_set_event_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_event_cb_t, void*);
+extern void (*pa_stream_set_buffer_attr_callback_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_notify_cb_t, void*);
+extern pa_operation* (*pa_stream_cork_dylibloader_wrapper_pulse)( pa_stream*, int, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_flush_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_prebuf_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_trigger_dylibloader_wrapper_pulse)( pa_stream*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_set_name_dylibloader_wrapper_pulse)( pa_stream*,const char*, pa_stream_success_cb_t, void*);
+extern int (*pa_stream_get_time_dylibloader_wrapper_pulse)( pa_stream*, pa_usec_t*);
+extern int (*pa_stream_get_latency_dylibloader_wrapper_pulse)( pa_stream*, pa_usec_t*, int*);
+extern const pa_timing_info* (*pa_stream_get_timing_info_dylibloader_wrapper_pulse)( pa_stream*);
+extern const pa_sample_spec* (*pa_stream_get_sample_spec_dylibloader_wrapper_pulse)( pa_stream*);
+extern const pa_channel_map* (*pa_stream_get_channel_map_dylibloader_wrapper_pulse)( pa_stream*);
+extern const pa_format_info* (*pa_stream_get_format_info_dylibloader_wrapper_pulse)(const pa_stream*);
+extern const pa_buffer_attr* (*pa_stream_get_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*);
+extern pa_operation* (*pa_stream_set_buffer_attr_dylibloader_wrapper_pulse)( pa_stream*,const pa_buffer_attr*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_update_sample_rate_dylibloader_wrapper_pulse)( pa_stream*, uint32_t, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_proplist_update_dylibloader_wrapper_pulse)( pa_stream*, pa_update_mode_t, pa_proplist*, pa_stream_success_cb_t, void*);
+extern pa_operation* (*pa_stream_proplist_remove_dylibloader_wrapper_pulse)( pa_stream*,const char* [], pa_stream_success_cb_t, void*);
+extern int (*pa_stream_set_monitor_stream_dylibloader_wrapper_pulse)( pa_stream*, uint32_t);
+extern uint32_t (*pa_stream_get_monitor_stream_dylibloader_wrapper_pulse)(const pa_stream*);
+extern pa_operation* (*pa_context_get_sink_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sink_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sink_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sink_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_info_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_volume_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_volume_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_mute_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_mute_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_suspend_sink_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_suspend_sink_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_port_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_port_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_source_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_source_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_source_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_source_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_source_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_source_info_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_volume_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_volume_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_mute_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_mute_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_suspend_source_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_suspend_source_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_port_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_port_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_server_info_dylibloader_wrapper_pulse)( pa_context*, pa_server_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_module_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_module_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_module_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_module_info_cb_t, void*);
+extern pa_operation* (*pa_context_load_module_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_index_cb_t, void*);
+extern pa_operation* (*pa_context_unload_module_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_client_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_client_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_client_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_client_info_cb_t, void*);
+extern pa_operation* (*pa_context_kill_client_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_card_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_card_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_card_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_card_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_card_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_card_info_cb_t, void*);
+extern pa_operation* (*pa_context_set_card_profile_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_card_profile_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_port_latency_offset_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, int64_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_sink_input_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sink_input_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sink_input_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sink_input_info_cb_t, void*);
+extern pa_operation* (*pa_context_move_sink_input_by_name_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_move_sink_input_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_input_volume_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_sink_input_mute_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_kill_sink_input_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_get_source_output_info_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_source_output_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_source_output_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_source_output_info_cb_t, void*);
+extern pa_operation* (*pa_context_move_source_output_by_name_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_move_source_output_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_output_volume_dylibloader_wrapper_pulse)( pa_context*, uint32_t,const pa_cvolume*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_set_source_output_mute_dylibloader_wrapper_pulse)( pa_context*, uint32_t, int, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_kill_source_output_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_stat_dylibloader_wrapper_pulse)( pa_context*, pa_stat_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sample_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_sample_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sample_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_sample_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_sample_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_sample_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_autoload_info_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t, pa_autoload_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_autoload_info_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_autoload_info_cb_t, void*);
+extern pa_operation* (*pa_context_get_autoload_info_list_dylibloader_wrapper_pulse)( pa_context*, pa_autoload_info_cb_t, void*);
+extern pa_operation* (*pa_context_add_autoload_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t,const char*,const char*, pa_context_index_cb_t, void*);
+extern pa_operation* (*pa_context_remove_autoload_by_name_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_autoload_type_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_remove_autoload_by_index_dylibloader_wrapper_pulse)( pa_context*, uint32_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_subscribe_dylibloader_wrapper_pulse)( pa_context*, pa_subscription_mask_t, pa_context_success_cb_t, void*);
+extern void (*pa_context_set_subscribe_callback_dylibloader_wrapper_pulse)( pa_context*, pa_context_subscribe_cb_t, void*);
+extern int (*pa_stream_connect_upload_dylibloader_wrapper_pulse)( pa_stream*, size_t);
+extern int (*pa_stream_finish_upload_dylibloader_wrapper_pulse)( pa_stream*);
+extern pa_operation* (*pa_context_remove_sample_dylibloader_wrapper_pulse)( pa_context*,const char*, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_play_sample_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t, pa_context_success_cb_t, void*);
+extern pa_operation* (*pa_context_play_sample_with_proplist_dylibloader_wrapper_pulse)( pa_context*,const char*,const char*, pa_volume_t,const pa_proplist*, pa_context_play_sample_cb_t, void*);
+extern const char* (*pa_strerror_dylibloader_wrapper_pulse)( int);
+extern void* (*pa_xmalloc_dylibloader_wrapper_pulse)( size_t);
+extern void* (*pa_xmalloc0_dylibloader_wrapper_pulse)( size_t);
+extern void* (*pa_xrealloc_dylibloader_wrapper_pulse)( void*, size_t);
+extern void (*pa_xfree_dylibloader_wrapper_pulse)( void*);
+extern char* (*pa_xstrdup_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_xstrndup_dylibloader_wrapper_pulse)(const char*, size_t);
+extern void* (*pa_xmemdup_dylibloader_wrapper_pulse)(const void*, size_t);
+extern char* (*pa_utf8_valid_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_ascii_valid_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_utf8_filter_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_ascii_filter_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_utf8_to_locale_dylibloader_wrapper_pulse)(const char*);
+extern char* (*pa_locale_to_utf8_dylibloader_wrapper_pulse)(const char*);
+extern pa_threaded_mainloop* (*pa_threaded_mainloop_new_dylibloader_wrapper_pulse)( void);
+extern void (*pa_threaded_mainloop_free_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern int (*pa_threaded_mainloop_start_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_stop_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_lock_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_unlock_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_wait_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_signal_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, int);
+extern void (*pa_threaded_mainloop_accept_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern int (*pa_threaded_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_threaded_mainloop*);
+extern pa_mainloop_api* (*pa_threaded_mainloop_get_api_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern int (*pa_threaded_mainloop_in_thread_dylibloader_wrapper_pulse)( pa_threaded_mainloop*);
+extern void (*pa_threaded_mainloop_set_name_dylibloader_wrapper_pulse)( pa_threaded_mainloop*,const char*);
+extern void (*pa_threaded_mainloop_once_unlocked_dylibloader_wrapper_pulse)( pa_threaded_mainloop*, void*, void*);
+extern pa_mainloop* (*pa_mainloop_new_dylibloader_wrapper_pulse)( void);
+extern void (*pa_mainloop_free_dylibloader_wrapper_pulse)( pa_mainloop*);
+extern int (*pa_mainloop_prepare_dylibloader_wrapper_pulse)( pa_mainloop*, int);
+extern int (*pa_mainloop_poll_dylibloader_wrapper_pulse)( pa_mainloop*);
+extern int (*pa_mainloop_dispatch_dylibloader_wrapper_pulse)( pa_mainloop*);
+extern int (*pa_mainloop_get_retval_dylibloader_wrapper_pulse)(const pa_mainloop*);
+extern int (*pa_mainloop_iterate_dylibloader_wrapper_pulse)( pa_mainloop*, int, int*);
+extern int (*pa_mainloop_run_dylibloader_wrapper_pulse)( pa_mainloop*, int*);
+extern pa_mainloop_api* (*pa_mainloop_get_api_dylibloader_wrapper_pulse)( pa_mainloop*);
+extern void (*pa_mainloop_quit_dylibloader_wrapper_pulse)( pa_mainloop*, int);
+extern void (*pa_mainloop_wakeup_dylibloader_wrapper_pulse)( pa_mainloop*);
+extern void (*pa_mainloop_set_poll_func_dylibloader_wrapper_pulse)( pa_mainloop*, pa_poll_func, void*);
+extern int (*pa_signal_init_dylibloader_wrapper_pulse)( pa_mainloop_api*);
+extern void (*pa_signal_done_dylibloader_wrapper_pulse)( void);
+extern pa_signal_event* (*pa_signal_new_dylibloader_wrapper_pulse)( int, pa_signal_cb_t, void*);
+extern void (*pa_signal_free_dylibloader_wrapper_pulse)( pa_signal_event*);
+extern void (*pa_signal_set_destroy_dylibloader_wrapper_pulse)( pa_signal_event*, pa_signal_destroy_cb_t);
+extern char* (*pa_get_user_name_dylibloader_wrapper_pulse)( char*, size_t);
+extern char* (*pa_get_host_name_dylibloader_wrapper_pulse)( char*, size_t);
+extern char* (*pa_get_fqdn_dylibloader_wrapper_pulse)( char*, size_t);
+extern char* (*pa_get_home_dir_dylibloader_wrapper_pulse)( char*, size_t);
+extern char* (*pa_get_binary_name_dylibloader_wrapper_pulse)( char*, size_t);
+extern char* (*pa_path_get_filename_dylibloader_wrapper_pulse)(const char*);
+extern int (*pa_msleep_dylibloader_wrapper_pulse)( unsigned long);
+extern int (*pa_thread_make_realtime_dylibloader_wrapper_pulse)( int);
+extern struct timeval* (*pa_gettimeofday_dylibloader_wrapper_pulse)(struct timeval*);
+extern pa_usec_t (*pa_timeval_diff_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
+extern int (*pa_timeval_cmp_dylibloader_wrapper_pulse)(struct timeval*,struct timeval*);
+extern pa_usec_t (*pa_timeval_age_dylibloader_wrapper_pulse)(struct timeval*);
+extern struct timeval* (*pa_timeval_add_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+extern struct timeval* (*pa_timeval_sub_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+extern struct timeval* (*pa_timeval_store_dylibloader_wrapper_pulse)(struct timeval*, pa_usec_t);
+extern pa_usec_t (*pa_timeval_load_dylibloader_wrapper_pulse)(struct timeval*);
+extern pa_usec_t (*pa_rtclock_now_dylibloader_wrapper_pulse)( void);
+int initialize_pulse(int verbose);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index eda929850c..22151b60c1 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -102,6 +102,28 @@ bool DirAccessUnix::dir_exists(String p_dir) {
return (success && S_ISDIR(flags.st_mode));
}
+bool DirAccessUnix::is_readable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), R_OK) == 0);
+}
+
+bool DirAccessUnix::is_writable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), W_OK) == 0);
+}
+
uint64_t DirAccessUnix::get_modified_time(String p_file) {
if (p_file.is_rel_path()) {
p_file = current_dir.plus_file(p_file);
@@ -204,8 +226,9 @@ static void _get_drives(List<String> *list) {
while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) {
// Avoid duplicates
- if (!list->find(mnt.mnt_dir)) {
- list->push_back(mnt.mnt_dir);
+ String name = String::utf8(mnt.mnt_dir);
+ if (!list->find(name)) {
+ list->push_back(name);
}
}
}
@@ -218,8 +241,9 @@ static void _get_drives(List<String> *list) {
const char *home = getenv("HOME");
if (home) {
// Only add if it's not a duplicate
- if (!list->find(home)) {
- list->push_back(home);
+ String home_name = String::utf8(home);
+ if (!list->find(home_name)) {
+ list->push_back(home_name);
}
// Check $HOME/.config/gtk-3.0/bookmarks
@@ -232,7 +256,7 @@ static void _get_drives(List<String> *list) {
// Parse only file:// links
if (strncmp(string, "file://", 7) == 0) {
// Strip any unwanted edges on the strings and push_back if it's not a duplicate
- String fpath = String(string + 7).strip_edges().split_spaces()[0].uri_decode();
+ String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
if (!list->find(fpath)) {
list->push_back(fpath);
}
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index b70df1ca02..54f4a5c312 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -71,6 +71,8 @@ public:
virtual bool file_exists(String p_file);
virtual bool dir_exists(String p_dir);
+ virtual bool is_readable(String p_dir);
+ virtual bool is_writable(String p_dir);
virtual uint64_t get_modified_time(String p_file);
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 6b24a85ff6..4c08380dd0 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -240,6 +240,8 @@ uint8_t FileAccessUnix::get_8() const {
}
int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
int read = fread(p_dst, 1, p_length, f);
check_errors();
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 19753943c8..e2ad352c10 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -106,7 +106,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
if (p_ip.is_valid()) {
- copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
+ memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
} else {
addr6->sin6_addr = in6addr_any;
}
@@ -121,7 +121,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr4->sin_port = htons(p_port); // short, network byte order
if (p_ip.is_valid()) {
- copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
+ memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
} else {
addr4->sin_addr.s_addr = INADDR_ANY;
}
@@ -130,18 +130,23 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
}
}
-void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) {
+void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
-
- r_port = ntohs(addr4->sin_port);
-
+ if (r_ip) {
+ r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
+ }
+ if (r_port) {
+ *r_port = ntohs(addr4->sin_port);
+ }
} else if (p_addr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
- r_ip.set_ipv6(addr6->sin6_addr.s6_addr);
-
- r_port = ntohs(addr6->sin6_port);
+ if (r_ip) {
+ r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
+ }
+ if (r_port) {
+ *r_port = ntohs(addr6->sin6_port);
+ }
};
}
@@ -186,13 +191,21 @@ NetSocketPosix::~NetSocketPosix() {
NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#if defined(WINDOWS_ENABLED)
int err = WSAGetLastError();
-
- if (err == WSAEISCONN)
+ if (err == WSAEISCONN) {
return ERR_NET_IS_CONNECTED;
- if (err == WSAEINPROGRESS || err == WSAEALREADY)
+ }
+ if (err == WSAEINPROGRESS || err == WSAEALREADY) {
return ERR_NET_IN_PROGRESS;
- if (err == WSAEWOULDBLOCK)
+ }
+ if (err == WSAEWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
+ }
+ if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (err == WSAEACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(err));
return ERR_NET_OTHER;
#else
@@ -205,6 +218,12 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
}
+ if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (errno == EACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(errno));
return ERR_NET_OTHER;
#endif
@@ -264,13 +283,13 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
struct ip_mreq greq;
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
- copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
- copymem(&greq.imr_interface, if_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
} else {
struct ipv6_mreq greq;
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
- copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
+ memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
greq.ipv6mr_interface = if_v6id;
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
}
@@ -384,8 +403,8 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
- _get_socket_error();
- print_verbose("Failed to bind socket.");
+ NetError err = _get_socket_error();
+ print_verbose("Failed to bind socket. Error: " + itos(err));
close();
return ERR_UNAVAILABLE;
}
@@ -446,7 +465,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
FD_ZERO(&wr);
FD_ZERO(&ex);
FD_SET(_sock, &ex);
- struct timeval timeout = { p_timeout, 0 };
+ struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
// For blocking operation, pass nullptr timeout pointer to select.
struct timeval *tp = nullptr;
if (p_timeout >= 0) {
@@ -716,6 +735,20 @@ int NetSocketPosix::get_available_bytes() const {
return len;
}
+Error NetSocketPosix::get_socket_address(IP_Address *r_ip, uint16_t *r_port) const {
+ ERR_FAIL_COND_V(!is_open(), FAILED);
+
+ struct sockaddr_storage saddr;
+ socklen_t len = sizeof(saddr);
+ if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
+ _get_socket_error();
+ print_verbose("Error when reading local socket address.");
+ return FAILED;
+ }
+ _set_ip_port(&saddr, r_ip, r_port);
+ return OK;
+}
+
Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out);
@@ -729,7 +762,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return out;
}
- _set_ip_port(&their_addr, r_ip, r_port);
+ _set_ip_port(&their_addr, &r_ip, &r_port);
NetSocketPosix *ns = memnew(NetSocketPosix);
ns->_set_socket(fd, _ip_type, _is_stream);
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index cc6af661c8..dbfe3a524e 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -54,7 +54,9 @@ private:
ERR_NET_WOULD_BLOCK,
ERR_NET_IS_CONNECTED,
ERR_NET_IN_PROGRESS,
- ERR_NET_OTHER
+ ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
+ ERR_NET_UNAUTHORIZED,
+ ERR_NET_OTHER,
};
NetError _get_socket_error() const;
@@ -70,7 +72,7 @@ protected:
public:
static void make_default();
static void cleanup();
- static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port);
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port);
static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type);
virtual Error open(Type p_sock_type, IP::Type &ip_type);
@@ -87,6 +89,7 @@ public:
virtual bool is_open() const;
virtual int get_available_bytes() const;
+ virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const;
virtual Error set_broadcasting_enabled(bool p_enabled);
virtual void set_blocking_enabled(bool p_enabled);
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index 19fab1d475..e47046e3ae 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -35,6 +35,10 @@
#include "core/os/thread.h"
#include "core/string/ustring.h"
+#ifdef PTHREAD_BSD_SET_NAME
+#include <pthread_np.h>
+#endif
+
static Error set_name(const String &p_name) {
#ifdef PTHREAD_NO_RENAME
return ERR_UNAVAILABLE;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 9584dd3f67..b664ccdd3c 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -119,7 +119,7 @@ static void update_external_dependency_for_store(VkSubpassDependency &dependency
}
if (is_depth) {
- // Depth resources have addtional stages that may be interested in them
+ // Depth resources have additional stages that may be interested in them
dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
@@ -1486,7 +1486,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
// possible in a single frame
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
//guess we did.. ok, let's see if we can insert a new block..
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we can, so we are safe
Error err = _insert_staging_block();
if (err) {
@@ -1530,7 +1530,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
} else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) {
//this block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we are still allowed to create a new block, so let's do that and insert it for current pos
Error err = _insert_staging_block();
if (err) {
@@ -1600,7 +1600,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
}
//copy to staging buffer
- copymem(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
+ memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
//unmap
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
@@ -2558,7 +2558,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * line_width;
- copymem(wptr, rptr, line_width);
+ memcpy(wptr, rptr, line_width);
}
} else {
@@ -2566,7 +2566,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
- copymem(wptr, rptr, pixel_size * width);
+ memcpy(wptr, rptr, (uint64_t)pixel_size * width);
}
}
}
@@ -2699,7 +2699,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
{
buffer_data.resize(buffer_size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer_size);
+ memcpy(w, buffer_mem, buffer_size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -3108,7 +3108,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- // NOTE: Perhaps the valid stages/accesses for a given onwner should be a property of the owner. (Here and places like _get_buffer_from_owner)
+ // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner)
const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT;
constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
@@ -3250,7 +3250,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
Vector<VkAttachmentReference> depth_stencil_references;
Vector<VkAttachmentReference> resolve_references;
- // Set up a dependencies from/to external equivalent to the default (implicit) one, and then amend them
+ // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them
const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
@@ -3279,7 +3279,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT;
// For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write
- // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution syncronization vs.
+ // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs.
// the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
// stage
switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) {
@@ -3424,12 +3424,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// NOTE: Big Mallet Approach -- any layout transition causes a full barrier
if (reference.layout != description.initialLayout) {
- // NOTE: this should be smarter based on the textures knowledge of it's previous role
+ // NOTE: this should be smarter based on the texture's knowledge of its previous role
dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
if (reference.layout != description.finalLayout) {
- // NOTE: this should be smarter based on the textures knowledge of it's subsequent role
+ // NOTE: this should be smarter based on the texture's knowledge of its subsequent role
dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
@@ -5151,7 +5151,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
- //if 0, then its sized on link time
+ //if 0, then it's sized on link time
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
@@ -5336,7 +5336,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
}
- // Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below.
+ // Make sure no one is using the buffer -- the "false" gets us to the same command buffer as below.
_buffer_memory_barrier(buffer->buffer, 0, buffer->size, src_stage_mask, src_access_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, false);
VkCommandBuffer command_buffer = frames[frame].setup_command_buffer;
@@ -5359,7 +5359,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
{
buffer_data.resize(buffer->size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer->size);
+ memcpy(w, buffer_mem, buffer->size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -5729,7 +5729,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
#endif
//create ID to associate with this pipeline
RID id = render_pipeline_owner.make_rid(pipeline);
- //now add aall the dependencies
+ //now add all the dependencies
_add_dependency(id, p_shader);
return id;
}
@@ -5780,7 +5780,7 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) {
//create ID to associate with this pipeline
RID id = compute_pipeline_owner.make_rid(pipeline);
- //now add aall the dependencies
+ //now add all the dependencies
_add_dependency(id, p_shader);
return id;
}
@@ -6817,7 +6817,7 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
// To ensure proper synchronization, we must make sure rendering is done before:
// * Some buffer is copied
- // * Another render pass happens (since we may be done
+ // * Another render pass happens (since we may be done)
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
@@ -7780,7 +7780,7 @@ uint64_t RenderingDeviceVulkan::get_memory_usage() const {
void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (local_device.is_valid() && !p_current_frame) {
- return; //flushign previous frames has no effect with local device
+ return; //flushing previous frames has no effect with local device
}
//not doing this crashes RADV (undefined behavior)
if (p_current_frame) {
@@ -7834,6 +7834,18 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
+ // get our device capabilities
+ {
+ device_capabilities.version_major = p_context->get_vulkan_major();
+ device_capabilities.version_minor = p_context->get_vulkan_minor();
+
+ // get info about subgroups
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
+ device_capabilities.subgroup_size = subgroup_capabilities.size;
+ device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
+ device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
+ }
+
context = p_context;
device = p_context->get_device();
if (p_local_device) {
@@ -8253,6 +8265,7 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
}
RenderingDeviceVulkan::RenderingDeviceVulkan() {
+ device_capabilities.device_family = DEVICE_VULKAN;
}
RenderingDeviceVulkan::~RenderingDeviceVulkan() {
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index c564cee757..0a8a5c746f 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -34,12 +34,14 @@
#include "core/config/project_settings.h"
#include "core/string/ustring.h"
#include "core/version.h"
+#include "servers/rendering/rendering_device.h"
#include "vk_enum_string_helper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <vector>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define APP_SHORT_NAME "GodotEngine"
@@ -163,7 +165,36 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
return VK_FALSE;
}
-VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers) {
+VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_report_callback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char *pLayerPrefix,
+ const char *pMessage,
+ void *pUserData) {
+ String debugMessage = String("Vulkan Debug Report: object - ") +
+ String::num_int64(object) + "\n" + pMessage;
+
+ switch (flags) {
+ case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
+ case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
+ print_line(debugMessage);
+ break;
+ case VK_DEBUG_REPORT_WARNING_BIT_EXT:
+ case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
+ WARN_PRINT(debugMessage);
+ break;
+ case VK_DEBUG_REPORT_ERROR_BIT_EXT:
+ ERR_PRINT(debugMessage);
+ break;
+ }
+
+ return VK_FALSE;
+}
+
+VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers) {
for (uint32_t i = 0; i < check_count; i++) {
VkBool32 found = 0;
for (uint32_t j = 0; j < layer_count; j++) {
@@ -180,55 +211,86 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_n
return 1;
}
-Error VulkanContext::_create_validation_layers() {
+Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
+ static const std::vector<std::vector<const char *>> instance_validation_layers_alt{
+ // Preferred set of validation layers
+ { "VK_LAYER_KHRONOS_validation" },
+
+ // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
+ { "VK_LAYER_LUNARG_standard_validation" },
+
+ // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
+ { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
+ };
+
+ // Clear out-arguments
+ *count = 0;
+ if (names != nullptr) {
+ *names = nullptr;
+ }
+
VkResult err;
- const char *instance_validation_layers_alt1[] = { "VK_LAYER_KHRONOS_validation" };
- const char *instance_validation_layers_alt2[] = { "VK_LAYER_LUNARG_standard_validation" };
- const char *instance_validation_layers_alt3[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" };
+ uint32_t instance_layer_count;
- uint32_t instance_layer_count = 0;
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ if (err) {
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
- VkBool32 validation_found = 0;
- uint32_t validation_layer_count = 0;
- const char **instance_validation_layers = nullptr;
- if (instance_layer_count > 0) {
- VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
- err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
- if (err) {
- free(instance_layers);
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
+ if (instance_layer_count < 1) {
+ return OK;
+ }
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
- instance_validation_layers = instance_validation_layers_alt1;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
+ err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
+ if (err) {
+ free(instance_layers);
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
- // use alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
- instance_validation_layers = instance_validation_layers_alt2;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) {
+ if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].data(), instance_layer_count, instance_layers)) {
+ *count = instance_validation_layers_alt[i].size();
+ if (names != nullptr) {
+ *names = instance_validation_layers_alt[i].data();
+ }
+ break;
}
+ }
- // use alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt3);
- instance_validation_layers = instance_validation_layers_alt3;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
- }
+ free(instance_layers);
- free(instance_layers);
- }
+ return OK;
+}
- if (validation_found) {
- enabled_layer_count = validation_layer_count;
- for (uint32_t i = 0; i < validation_layer_count; i++) {
- enabled_layers[i] = instance_validation_layers[i];
+typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);
+
+Error VulkanContext::_obtain_vulkan_version() {
+ // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
+ // for Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
+ _vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
+ if (func != nullptr) {
+ uint32_t api_version;
+ VkResult res = func(&api_version);
+ if (res == VK_SUCCESS) {
+ vulkan_major = VK_VERSION_MAJOR(api_version);
+ vulkan_minor = VK_VERSION_MINOR(api_version);
+ uint32_t vulkan_patch = VK_VERSION_PATCH(api_version);
+
+ print_line("Vulkan API " + itos(vulkan_major) + "." + itos(vulkan_minor) + "." + itos(vulkan_patch));
+ } else {
+ // according to the documentation this shouldn't fail with anything except a memory allocation error
+ // in which case we're in deep trouble anyway
+ ERR_FAIL_V(ERR_CANT_CREATE);
}
} else {
- return ERR_CANT_CREATE;
+ print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0");
+ }
+
+ // we don't go above 1.2
+ if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
+ vulkan_major = 1;
+ vulkan_minor = 2;
}
return OK;
@@ -238,8 +300,8 @@ Error VulkanContext::_initialize_extensions() {
uint32_t instance_extension_count = 0;
enabled_extension_count = 0;
- enabled_layer_count = 0;
enabled_debug_utils = false;
+ enabled_debug_report = false;
/* Look for instance extensions */
VkBool32 surfaceExtFound = 0;
VkBool32 platformSurfaceExtFound = 0;
@@ -266,8 +328,9 @@ Error VulkanContext::_initialize_extensions() {
extension_names[enabled_extension_count++] = _get_platform_surface_extension();
}
if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- if (use_validation_layers) {
+ if (_use_validation_layers()) {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
+ enabled_debug_report = true;
}
}
if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) {
@@ -289,12 +352,195 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}
-Error VulkanContext::_create_physical_device() {
- /* Look for validation layers */
- if (use_validation_layers) {
- _create_validation_layers();
+typedef void(VKAPI_PTR *_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *);
+
+uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
+ uint32_t flags = 0;
+
+ if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_VERTEX_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_CONTROL_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_EVALUATION_BIT;
+ }
+ // if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
+ // flags += RenderingDevice::ShaderStage::SHADER_STAGE_GEOMETRY_BIT;
+ // }
+ if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT;
+ }
+
+ return flags;
+}
+
+String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
+ String res;
+
+ if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
+ res += ", STAGE_VERTEX";
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
+ res += ", STAGE_TESSELLATION_CONTROL";
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
+ res += ", STAGE_TESSELLATION_EVALUATION";
+ }
+ if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
+ res += ", STAGE_GEOMETRY";
+ }
+ if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
+ res += ", STAGE_FRAGMENT";
+ }
+ if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
+ res += ", STAGE_COMPUTE";
+ }
+
+ /* these are not defined on Android GRMBL */
+ if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
+ res += ", STAGE_RAYGEN_KHR";
+ }
+ if (supportedStages & 0x00000200 /* VK_SHADER_STAGE_ANY_HIT_BIT_KHR */) {
+ res += ", STAGE_ANY_HIT_KHR";
+ }
+ if (supportedStages & 0x00000400 /* VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR */) {
+ res += ", STAGE_CLOSEST_HIT_KHR";
+ }
+ if (supportedStages & 0x00000800 /* VK_SHADER_STAGE_MISS_BIT_KHR */) {
+ res += ", STAGE_MISS_KHR";
+ }
+ if (supportedStages & 0x00001000 /* VK_SHADER_STAGE_INTERSECTION_BIT_KHR */) {
+ res += ", STAGE_INTERSECTION_KHR";
+ }
+ if (supportedStages & 0x00002000 /* VK_SHADER_STAGE_CALLABLE_BIT_KHR */) {
+ res += ", STAGE_CALLABLE_KHR";
+ }
+ if (supportedStages & 0x00000040 /* VK_SHADER_STAGE_TASK_BIT_NV */) {
+ res += ", STAGE_TASK_NV";
+ }
+ if (supportedStages & 0x00000080 /* VK_SHADER_STAGE_MESH_BIT_NV */) {
+ res += ", STAGE_MESH_NV";
+ }
+
+ return res.substr(2); // remove first ", "
+}
+
+uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
+ uint32_t flags = 0;
+
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT;
+ }
+
+ return flags;
+}
+
+String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
+ String res;
+
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
+ res += ", FEATURE_BASIC";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
+ res += ", FEATURE_VOTE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
+ res += ", FEATURE_ARITHMETIC";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
+ res += ", FEATURE_BALLOT";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
+ res += ", FEATURE_SHUFFLE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
+ res += ", FEATURE_SHUFFLE_RELATIVE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
+ res += ", FEATURE_CLUSTERED";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
+ res += ", FEATURE_QUAD";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) {
+ res += ", FEATURE_PARTITIONED_NV";
+ }
+
+ return res.substr(2); // remove first ", "
+}
+
+Error VulkanContext::_check_capabilities() {
+ // check subgroups
+ // https://www.khronos.org/blog/vulkan-subgroup-tutorial
+ // for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
+ _vkGetPhysicalDeviceProperties2 func = (_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
+ if (func != nullptr) {
+ VkPhysicalDeviceSubgroupProperties subgroupProperties;
+ subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ subgroupProperties.pNext = nullptr;
+
+ VkPhysicalDeviceProperties2 physicalDeviceProperties;
+ physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ physicalDeviceProperties.pNext = &subgroupProperties;
+
+ func(gpu, &physicalDeviceProperties);
+
+ subgroup_capabilities.size = subgroupProperties.subgroupSize;
+ subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
+ subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
+ // Note: quadOperationsInAllStages will be true if:
+ // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT
+ // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
+ subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
+
+ // only output this when debugging?
+ print_line("- Vulkan subgroup size " + itos(subgroup_capabilities.size));
+ print_line("- Vulkan subgroup stages " + subgroup_capabilities.supported_stages_desc());
+ print_line("- Vulkan subgroup supported ops " + subgroup_capabilities.supported_operations_desc());
+ if (subgroup_capabilities.quadOperationsInAllStages) {
+ print_line("- Vulkan subgroup quad operations in all stages");
+ }
+ } else {
+ subgroup_capabilities.size = 0;
+ subgroup_capabilities.supportedStages = 0;
+ subgroup_capabilities.supportedOperations = 0;
+ subgroup_capabilities.quadOperationsInAllStages = false;
}
+ return OK;
+}
+
+Error VulkanContext::_create_physical_device() {
+ /* obtain version */
+ _obtain_vulkan_version();
+
+ /* initialise extensions */
{
Error err = _initialize_extensions();
if (err != OK) {
@@ -312,18 +558,16 @@ Error VulkanContext::_create_physical_device() {
/*applicationVersion*/ 0,
/*pEngineName*/ namecs.get_data(),
/*engineVersion*/ 0,
- /*apiVersion*/ VK_API_VERSION_1_0,
- };
- VkInstanceCreateInfo inst_info = {
- /*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- /*pNext*/ nullptr,
- /*flags*/ 0,
- /*pApplicationInfo*/ &app,
- /*enabledLayerCount*/ enabled_layer_count,
- /*ppEnabledLayerNames*/ (const char *const *)enabled_layers,
- /*enabledExtensionCount*/ enabled_extension_count,
- /*ppEnabledExtensionNames*/ (const char *const *)extension_names,
+ /*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0)
};
+ VkInstanceCreateInfo inst_info{};
+ inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ inst_info.pApplicationInfo = &app;
+ inst_info.enabledExtensionCount = enabled_extension_count;
+ inst_info.ppEnabledExtensionNames = (const char *const *)extension_names;
+ if (_use_validation_layers()) {
+ _get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames);
+ }
/*
* This is info for a temp callback to use during CreateInstance.
@@ -331,6 +575,7 @@ Error VulkanContext::_create_physical_device() {
* function to register the final callback.
*/
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
+ VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
if (enabled_debug_utils) {
// VK_EXT_debug_utils style
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
@@ -344,6 +589,16 @@ Error VulkanContext::_create_physical_device() {
dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
dbg_messenger_create_info.pUserData = this;
inst_info.pNext = &dbg_messenger_create_info;
+ } else if (enabled_debug_report) {
+ dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
+ dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
+ VK_DEBUG_REPORT_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_ERROR_BIT_EXT |
+ VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+ dbg_report_callback_create_info.pfnCallback = _debug_report_callback;
+ dbg_report_callback_create_info.pUserData = this;
+ inst_info.pNext = &dbg_report_callback_create_info;
}
uint32_t gpu_count;
@@ -532,9 +787,36 @@ Error VulkanContext::_create_physical_device() {
ERR_FAIL_V(ERR_CANT_CREATE);
break;
}
+ } else if (enabled_debug_report) {
+ CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT");
+ DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT");
+ DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT");
+
+ if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) {
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "GetProcAddr: Failed to init VK_EXT_debug_report\n"
+ "GetProcAddr: Failure");
+ }
+
+ err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report);
+ switch (err) {
+ case VK_SUCCESS:
+ break;
+ case VK_ERROR_OUT_OF_HOST_MEMORY:
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "CreateDebugReportCallbackEXT: out of host memory\n"
+ "CreateDebugReportCallbackEXT Failure");
+ break;
+ default:
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "CreateDebugReportCallbackEXT: unknown failure\n"
+ "CreateDebugReportCallbackEXT Failure");
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ break;
+ }
}
- /* Call with NULL data to get count */
+ /* Call with nullptr data to get count */
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
@@ -561,6 +843,14 @@ Error VulkanContext::_create_physical_device() {
GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
+ // get info about what our vulkan driver is capable off
+ {
+ Error res = _check_capabilities();
+ if (res != OK) {
+ return res;
+ }
+ }
+
return OK;
}
@@ -692,16 +982,39 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one
// supported format will be returned.
- if (true || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
+ if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
format = VK_FORMAT_B8G8R8A8_UNORM;
+ color_space = surfFormats[0].colorSpace;
} else {
+ // These should be ordered with the ones we want to use on top and fallback modes further down
+ // we want an 32bit RGBA unsigned normalised buffer or similar
+ const VkFormat allowed_formats[] = {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UNORM
+ };
+ uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
+
if (formatCount < 1) {
free(surfFormats);
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
}
- format = surfFormats[0].format;
+
+ // Find the first format that we support
+ format = VK_FORMAT_UNDEFINED;
+ for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
+ for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
+ if (surfFormats[sf].format == allowed_formats[af]) {
+ format = surfFormats[sf].format;
+ color_space = surfFormats[sf].colorSpace;
+ }
+ }
+ }
+
+ if (format == VK_FORMAT_UNDEFINED) {
+ free(surfFormats);
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
+ }
}
- color_space = surfFormats[0].colorSpace;
free(surfFormats);
@@ -755,6 +1068,10 @@ Error VulkanContext::_create_semaphores() {
return OK;
}
+bool VulkanContext::_use_validation_layers() {
+ return Engine::get_singleton()->is_validation_layers_enabled();
+}
+
Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) {
ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
@@ -1313,13 +1630,13 @@ Error VulkanContext::swap_buffers() {
DemoUpdateTargetIPD(demo);
// Note: a real application would position its geometry to that it's in
- // the correct locatoin for when the next image is presented. It might
+ // the correct location for when the next image is presented. It might
// also wait, so that there's less latency between any input and when
// the next image is rendered/presented. This demo program is so
// simple that it doesn't do either of those.
}
#endif
- // Wait for the image acquired semaphore to be signaled to ensure
+ // Wait for the image acquired semaphore to be signalled to ensure
// that the image won't be rendered to until the presentation
// engine has fully released ownership to the application, and it is
// okay to render to the image.
@@ -1385,7 +1702,7 @@ Error VulkanContext::swap_buffers() {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
- // If we are using separate queues we have to wait for image ownership,
+ // If we are using separate queues, we have to wait for image ownership,
// otherwise wait for draw complete
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
@@ -1686,8 +2003,6 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
}
VulkanContext::VulkanContext() {
- use_validation_layers = Engine::get_singleton()->is_validation_layers_enabled();
-
command_buffer_queue.resize(1); // First one is always the setup command.
command_buffer_queue.write[0] = nullptr;
}
@@ -1705,9 +2020,12 @@ VulkanContext::~VulkanContext() {
vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr);
}
}
- if (inst_initialized && use_validation_layers) {
+ if (inst_initialized && enabled_debug_utils) {
DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
}
+ if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) {
+ DestroyDebugReportCallbackEXT(inst, dbg_debug_report, nullptr);
+ }
vkDestroyDevice(device, nullptr);
}
if (inst_initialized) {
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index dc6b0410bc..88e4f26bb1 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -41,6 +41,20 @@
#include <vulkan/vulkan.h>
class VulkanContext {
+public:
+ struct SubgroupCapabilities {
+ uint32_t size;
+ VkShaderStageFlags supportedStages;
+ VkSubgroupFeatureFlags supportedOperations;
+ VkBool32 quadOperationsInAllStages;
+
+ uint32_t supported_stages_flags_rd() const;
+ String supported_stages_desc() const;
+ uint32_t supported_operations_flags_rd() const;
+ String supported_operations_desc() const;
+ };
+
+private:
enum {
MAX_EXTENSIONS = 128,
MAX_LAYERS = 64,
@@ -57,6 +71,11 @@ class VulkanContext {
bool device_initialized = false;
bool inst_initialized = false;
+ // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
+ uint32_t vulkan_major = 1;
+ uint32_t vulkan_minor = 0;
+ SubgroupCapabilities subgroup_capabilities;
+
String device_vendor;
String device_name;
String pipeline_cache_id;
@@ -126,8 +145,11 @@ class VulkanContext {
const char *extension_names[MAX_EXTENSIONS];
bool enabled_debug_utils = false;
- uint32_t enabled_layer_count = 0;
- const char *enabled_layers[MAX_LAYERS];
+ /**
+ * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
+ * still used if VK_EXT_debug_utils is not available.
+ */
+ bool enabled_debug_report = false;
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
@@ -136,6 +158,9 @@ class VulkanContext {
PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+ PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
@@ -149,17 +174,29 @@ class VulkanContext {
PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE;
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
+ VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
- Error _create_validation_layers();
+ Error _obtain_vulkan_version();
Error _initialize_extensions();
+ Error _check_capabilities();
- VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers);
+ VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData);
+ static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char *pLayerPrefix,
+ const char *pMessage,
+ void *pUserData);
+
Error _create_physical_device();
Error _initialize_queues(VkSurfaceKHR surface);
@@ -176,16 +213,21 @@ class VulkanContext {
protected:
virtual const char *_get_platform_surface_extension() const = 0;
- // Enabled via command line argument.
- bool use_validation_layers = false;
-
virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height);
+ virtual bool _use_validation_layers();
+
+ Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
+
VkInstance _get_instance() {
return inst;
}
public:
+ uint32_t get_vulkan_major() const { return vulkan_major; };
+ uint32_t get_vulkan_minor() const { return vulkan_minor; };
+ SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
+
VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_swapchain_image_count() const;
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index f2d541754f..43c8722b06 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -387,7 +387,7 @@ Error AudioDriverWASAPI::finish_capture_device() {
}
Error AudioDriverWASAPI::init() {
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
Error err = init_render_device();
if (err != OK) {
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 35f61c0623..b1b3fc9092 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -253,6 +253,8 @@ uint8_t FileAccessWindows::get_8() const {
}
int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!f, -1);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == WRITE) {
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 1bb8da769b..1c7bf5d6c6 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -44,12 +44,12 @@ Error AudioDriverXAudio2::init() {
pcm_open = false;
samples_in = nullptr;
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
new file mode 100644
index 0000000000..9949fd8199
--- /dev/null
+++ b/editor/action_map_editor.cpp
@@ -0,0 +1,1167 @@
+/*************************************************************************/
+/* action_map_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "action_map_editor.h"
+#include "core/input/input_map.h"
+#include "core/os/keyboard.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/center_container.h"
+
+/////////////////////////////////////////
+
+// Maps to 2*axis if value is neg, or + 1 if value is pos.
+static const char *_joy_axis_descriptions[JOY_AXIS_MAX * 2] = {
+ TTRC("Left Stick Left, Joystick 0 Left"),
+ TTRC("Left Stick Right, Joystick 0 Right"),
+ TTRC("Left Stick Up, Joystick 0 Up"),
+ TTRC("Left Stick Down, Joystick 0 Down"),
+ TTRC("Right Stick Left, Joystick 1 Left"),
+ TTRC("Right Stick Right, Joystick 1 Right"),
+ TTRC("Right Stick Up, Joystick 1 Up"),
+ TTRC("Right Stick Down, Joystick 1 Down"),
+ TTRC("Joystick 2 Left"),
+ TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"),
+ TTRC("Joystick 2 Up"),
+ TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"),
+ TTRC("Joystick 3 Left"),
+ TTRC("Joystick 3 Right"),
+ TTRC("Joystick 3 Up"),
+ TTRC("Joystick 3 Down"),
+ TTRC("Joystick 4 Left"),
+ TTRC("Joystick 4 Right"),
+ TTRC("Joystick 4 Up"),
+ TTRC("Joystick 4 Down"),
+};
+
+String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent");
+
+ // Joypad motion events will display slighlty differently than what the event->as_text() provides. See #43660.
+ Ref<InputEventJoypadMotion> jpmotion = p_event;
+ if (jpmotion.is_valid()) {
+ String desc = TTR("Unknown Joypad Axis");
+ if (jpmotion->get_axis() < JOY_AXIS_MAX) {
+ desc = RTR(_joy_axis_descriptions[2 * jpmotion->get_axis() + (jpmotion->get_axis_value() < 0 ? 0 : 1)]);
+ }
+
+ return vformat("Joypad Axis %s %s (%s)", itos(jpmotion->get_axis()), jpmotion->get_axis_value() < 0 ? "-" : "+", desc);
+ } else {
+ return p_event->as_text();
+ }
+}
+
+void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
+ if (p_event.is_valid()) {
+ event = p_event;
+
+ // Update Label
+ event_as_text->set_text(get_event_text(event));
+
+ Ref<InputEventKey> k = p_event;
+ Ref<InputEventMouseButton> mb = p_event;
+ Ref<InputEventJoypadButton> joyb = p_event;
+ Ref<InputEventJoypadMotion> joym = p_event;
+ Ref<InputEventWithModifiers> mod = p_event;
+
+ // Update option values and visibility
+ bool show_mods = false;
+ bool show_device = false;
+ bool show_phys_key = false;
+
+ if (mod.is_valid()) {
+ show_mods = true;
+ mod_checkboxes[MOD_ALT]->set_pressed(mod->get_alt());
+ mod_checkboxes[MOD_SHIFT]->set_pressed(mod->get_shift());
+ mod_checkboxes[MOD_COMMAND]->set_pressed(mod->get_command());
+ mod_checkboxes[MOD_CONTROL]->set_pressed(mod->get_control());
+ mod_checkboxes[MOD_META]->set_pressed(mod->get_metakey());
+
+ store_command_checkbox->set_pressed(mod->is_storing_command());
+ }
+
+ if (k.is_valid()) {
+ show_phys_key = true;
+ physical_key_checkbox->set_pressed(k->get_physical_keycode() != 0 && k->get_keycode() == 0);
+
+ } else if (joyb.is_valid() || joym.is_valid() || mb.is_valid()) {
+ show_device = true;
+ _set_current_device(event->get_device());
+ }
+
+ mod_container->set_visible(show_mods);
+ device_container->set_visible(show_device);
+ physical_key_checkbox->set_visible(show_phys_key);
+ additional_options_container->show();
+
+ // Update selected item in input list for keys, joybuttons and joyaxis only (since the mouse cannot be "listened" for).
+ if (k.is_valid() || joyb.is_valid() || joym.is_valid()) {
+ TreeItem *category = input_list_tree->get_root()->get_children();
+ while (category) {
+ TreeItem *input_item = category->get_children();
+
+ // has_type this should be always true, unless the tree structure has been misconfigured.
+ bool has_type = input_item->get_parent()->has_meta("__type");
+ int input_type = input_item->get_parent()->get_meta("__type");
+ if (!has_type) {
+ return;
+ }
+
+ // If event type matches input types of this category.
+ if ((k.is_valid() && input_type == INPUT_KEY) || (joyb.is_valid() && input_type == INPUT_JOY_BUTTON) || (joym.is_valid() && input_type == INPUT_JOY_MOTION)) {
+ // Loop through all items of this category until one matches.
+ while (input_item) {
+ bool key_match = k.is_valid() && (Variant(k->get_keycode()) == input_item->get_meta("__keycode") || Variant(k->get_physical_keycode()) == input_item->get_meta("__keycode"));
+ bool joyb_match = joyb.is_valid() && Variant(joyb->get_button_index()) == input_item->get_meta("__index");
+ bool joym_match = joym.is_valid() && Variant(joym->get_axis()) == input_item->get_meta("__axis") && joym->get_axis_value() == (float)input_item->get_meta("__value");
+ if (key_match || joyb_match || joym_match) {
+ category->set_collapsed(false);
+ input_item->select(0);
+ input_list_tree->ensure_cursor_is_visible();
+ return;
+ }
+ input_item = input_item->get_next();
+ }
+ }
+
+ category->set_collapsed(true); // Event not in this category, so collapse;
+ category = category->get_next();
+ }
+ }
+ } else {
+ // Event is not valid, reset dialog
+ event = p_event;
+ Vector<String> strings;
+
+ // Reset message, promp for input according to which input types are allowed.
+ String text = TTR("Perform an Input (%s).");
+
+ if (allowed_input_types & INPUT_KEY) {
+ strings.append(TTR("Key"));
+ }
+ // We don't check for INPUT_MOUSE_BUTTON since it is ignored in the "Listen Window Input" method.
+
+ if (allowed_input_types & INPUT_JOY_BUTTON) {
+ strings.append(TTR("Joypad Button"));
+ }
+ if (allowed_input_types & INPUT_JOY_MOTION) {
+ strings.append(TTR("Joypad Axis"));
+ }
+
+ if (strings.size() == 0) {
+ text = TTR("Input Event dialog has been misconfigured: No input types are allowed.");
+ event_as_text->set_text(text);
+ } else {
+ String insert_text = String(", ").join(strings);
+ event_as_text->set_text(vformat(text, insert_text));
+ }
+
+ additional_options_container->hide();
+ input_list_tree->deselect_all();
+ _update_input_list();
+ }
+}
+
+void InputEventConfigurationDialog::_tab_selected(int p_tab) {
+ Callable signal_method = callable_mp(this, &InputEventConfigurationDialog::_listen_window_input);
+ if (p_tab == 0) {
+ // Start Listening.
+ if (!is_connected("window_input", signal_method)) {
+ connect("window_input", signal_method);
+ }
+ } else {
+ // Stop Listening.
+ if (is_connected("window_input", signal_method)) {
+ disconnect("window_input", signal_method);
+ }
+ input_list_tree->call_deferred("ensure_cursor_is_visible");
+ if (input_list_tree->get_selected() == nullptr) {
+ // If nothing selected, scroll to top.
+ input_list_tree->scroll_to_item(input_list_tree->get_root());
+ }
+ }
+}
+
+void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &p_event) {
+ // Ignore if echo or not pressed
+ if (p_event->is_echo() || !p_event->is_pressed()) {
+ return;
+ }
+
+ // Ignore mouse
+ Ref<InputEventMouse> m = p_event;
+ if (m.is_valid()) {
+ return;
+ }
+
+ // Check what the type is and if it is allowed.
+ Ref<InputEventKey> k = p_event;
+ Ref<InputEventJoypadButton> joyb = p_event;
+ Ref<InputEventJoypadMotion> joym = p_event;
+
+ int type = k.is_valid() ? INPUT_KEY : joyb.is_valid() ? INPUT_JOY_BUTTON :
+ joym.is_valid() ? INPUT_JOY_MOTION :
+ 0;
+
+ if (!(allowed_input_types & type)) {
+ return;
+ }
+
+ if (joym.is_valid()) {
+ float axis_value = joym->get_axis_value();
+ if (ABS(axis_value) < 0.9) {
+ // Ignore motion below 0.9 magnitude to avoid accidental touches
+ return;
+ } else {
+ // Always make the value 1 or -1 for display consistency
+ joym->set_axis_value(SGN(axis_value));
+ }
+ }
+
+ if (k.is_valid()) {
+ k->set_pressed(false); // to avoid serialisation of 'pressed' property - doesn't matter for actions anyway.
+ // Maintain physical keycode option state
+ if (physical_key_checkbox->is_pressed()) {
+ k->set_physical_keycode(k->get_keycode());
+ k->set_keycode(0);
+ } else {
+ k->set_keycode(k->get_physical_keycode());
+ k->set_physical_keycode(0);
+ }
+ }
+
+ Ref<InputEventWithModifiers> mod = p_event;
+ if (mod.is_valid()) {
+ // Maintain store command option state
+ mod->set_store_command(store_command_checkbox->is_pressed());
+
+ mod->set_window_id(0);
+ }
+
+ _set_event(p_event);
+ set_input_as_handled();
+}
+
+void InputEventConfigurationDialog::_search_term_updated(const String &) {
+ _update_input_list();
+}
+
+void InputEventConfigurationDialog::_update_input_list() {
+ input_list_tree->clear();
+
+ TreeItem *root = input_list_tree->create_item();
+ String search_term = input_list_search->get_text();
+
+ bool collapse = input_list_search->get_text().is_empty();
+
+ if (allowed_input_types & INPUT_KEY) {
+ TreeItem *kb_root = input_list_tree->create_item(root);
+ kb_root->set_text(0, TTR("Keyboard Keys"));
+ kb_root->set_icon(0, icon_cache.keyboard);
+ kb_root->set_collapsed(collapse);
+ kb_root->set_meta("__type", INPUT_KEY);
+
+ for (int i = 0; i < keycode_get_count(); i++) {
+ String name = keycode_get_name_by_index(i);
+
+ if (!search_term.is_empty() && name.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(kb_root);
+ item->set_text(0, name);
+ item->set_meta("__keycode", keycode_get_value_by_index(i));
+ }
+ }
+
+ if (allowed_input_types & INPUT_MOUSE_BUTTON) {
+ TreeItem *mouse_root = input_list_tree->create_item(root);
+ mouse_root->set_text(0, TTR("Mouse Buttons"));
+ mouse_root->set_icon(0, icon_cache.mouse);
+ mouse_root->set_collapsed(collapse);
+ mouse_root->set_meta("__type", INPUT_MOUSE_BUTTON);
+
+ MouseButton mouse_buttons[9] = { MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN, MOUSE_BUTTON_WHEEL_LEFT, MOUSE_BUTTON_WHEEL_RIGHT, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_XBUTTON2 };
+ for (int i = 0; i < 9; i++) {
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_button_index(mouse_buttons[i]);
+ String desc = get_event_text(mb);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(mouse_root);
+ item->set_text(0, desc);
+ item->set_meta("__index", mouse_buttons[i]);
+ }
+ }
+
+ if (allowed_input_types & INPUT_JOY_BUTTON) {
+ TreeItem *joyb_root = input_list_tree->create_item(root);
+ joyb_root->set_text(0, TTR("Joypad Buttons"));
+ joyb_root->set_icon(0, icon_cache.joypad_button);
+ joyb_root->set_collapsed(collapse);
+ joyb_root->set_meta("__type", INPUT_JOY_BUTTON);
+
+ for (int i = 0; i < JOY_BUTTON_MAX; i++) {
+ Ref<InputEventJoypadButton> joyb;
+ joyb.instance();
+ joyb->set_button_index(i);
+ String desc = get_event_text(joyb);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(joyb_root);
+ item->set_text(0, desc);
+ item->set_meta("__index", i);
+ }
+ }
+
+ if (allowed_input_types & INPUT_JOY_MOTION) {
+ TreeItem *joya_root = input_list_tree->create_item(root);
+ joya_root->set_text(0, TTR("Joypad Axes"));
+ joya_root->set_icon(0, icon_cache.joypad_axis);
+ joya_root->set_collapsed(collapse);
+ joya_root->set_meta("__type", INPUT_JOY_MOTION);
+
+ for (int i = 0; i < JOY_AXIS_MAX * 2; i++) {
+ int axis = i / 2;
+ int direction = (i & 1) ? 1 : -1;
+ Ref<InputEventJoypadMotion> joym;
+ joym.instance();
+ joym->set_axis(axis);
+ joym->set_axis_value(direction);
+ String desc = get_event_text(joym);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(joya_root);
+ item->set_text(0, desc);
+ item->set_meta("__axis", i >> 1);
+ item->set_meta("__value", (i & 1) ? 1 : -1);
+ }
+ }
+}
+
+void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
+ Ref<InputEventWithModifiers> ie = event;
+
+ // Not event with modifiers
+ if (ie.is_null()) {
+ return;
+ }
+
+ if (p_index == 0) {
+ ie->set_alt(p_checked);
+ } else if (p_index == 1) {
+ ie->set_shift(p_checked);
+ } else if (p_index == 2) {
+ ie->set_command(p_checked);
+ } else if (p_index == 3) {
+ ie->set_control(p_checked);
+ } else if (p_index == 4) {
+ ie->set_metakey(p_checked);
+ }
+
+ _set_event(ie);
+}
+
+void InputEventConfigurationDialog::_store_command_toggled(bool p_checked) {
+ Ref<InputEventWithModifiers> ie = event;
+ if (ie.is_valid()) {
+ ie->set_store_command(p_checked);
+ _set_event(ie);
+ }
+
+ if (p_checked) {
+ // If storing Command, show it's checkbox and hide Control (Win/Lin) or Meta (Mac)
+#ifdef APPLE_STYLE_KEYS
+ mod_checkboxes[MOD_META]->hide();
+
+ mod_checkboxes[MOD_COMMAND]->show();
+ mod_checkboxes[MOD_COMMAND]->set_text("Meta (Command)");
+#else
+ mod_checkboxes[MOD_CONTROL]->hide();
+
+ mod_checkboxes[MOD_COMMAND]->show();
+ mod_checkboxes[MOD_COMMAND]->set_text("Control (Command)");
+#endif
+ } else {
+ // If not, hide Command, show Control and Meta.
+ mod_checkboxes[MOD_COMMAND]->hide();
+ mod_checkboxes[MOD_CONTROL]->show();
+ mod_checkboxes[MOD_META]->show();
+ }
+}
+
+void InputEventConfigurationDialog::_physical_keycode_toggled(bool p_checked) {
+ Ref<InputEventKey> k = event;
+
+ if (k.is_null()) {
+ return;
+ }
+
+ if (p_checked) {
+ k->set_physical_keycode(k->get_keycode());
+ k->set_keycode(0);
+ } else {
+ k->set_keycode(k->get_physical_keycode());
+ k->set_physical_keycode(0);
+ }
+
+ _set_event(k);
+}
+
+void InputEventConfigurationDialog::_input_list_item_selected() {
+ TreeItem *selected = input_list_tree->get_selected();
+
+ // Invalid tree selection - type only exists on the "category" items, which are not a valid selection.
+ if (selected->has_meta("__type")) {
+ return;
+ }
+
+ int input_type = selected->get_parent()->get_meta("__type");
+
+ switch (input_type) {
+ case InputEventConfigurationDialog::INPUT_KEY: {
+ int kc = selected->get_meta("__keycode");
+ Ref<InputEventKey> k;
+ k.instance();
+
+ if (physical_key_checkbox->is_pressed()) {
+ k->set_physical_keycode(kc);
+ k->set_keycode(0);
+ } else {
+ k->set_physical_keycode(0);
+ k->set_keycode(kc);
+ }
+
+ // Maintain modifier state from checkboxes
+ k->set_alt(mod_checkboxes[MOD_ALT]->is_pressed());
+ k->set_shift(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ k->set_command(mod_checkboxes[MOD_COMMAND]->is_pressed());
+ k->set_control(mod_checkboxes[MOD_CONTROL]->is_pressed());
+ k->set_metakey(mod_checkboxes[MOD_META]->is_pressed());
+ k->set_store_command(store_command_checkbox->is_pressed());
+
+ _set_event(k);
+ } break;
+ case InputEventConfigurationDialog::INPUT_MOUSE_BUTTON: {
+ int idx = selected->get_meta("__index");
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_button_index(idx);
+ // Maintain modifier state from checkboxes
+ mb->set_alt(mod_checkboxes[MOD_ALT]->is_pressed());
+ mb->set_shift(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ mb->set_command(mod_checkboxes[MOD_COMMAND]->is_pressed());
+ mb->set_control(mod_checkboxes[MOD_CONTROL]->is_pressed());
+ mb->set_metakey(mod_checkboxes[MOD_META]->is_pressed());
+ mb->set_store_command(store_command_checkbox->is_pressed());
+
+ _set_event(mb);
+ } break;
+ case InputEventConfigurationDialog::INPUT_JOY_BUTTON: {
+ int idx = selected->get_meta("__index");
+ Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx);
+ _set_event(jb);
+ } break;
+ case InputEventConfigurationDialog::INPUT_JOY_MOTION: {
+ int axis = selected->get_meta("__axis");
+ int value = selected->get_meta("__value");
+
+ Ref<InputEventJoypadMotion> jm;
+ jm.instance();
+ jm->set_axis(axis);
+ jm->set_axis_value(value);
+ _set_event(jm);
+ } break;
+ default:
+ break;
+ }
+}
+
+void InputEventConfigurationDialog::_set_current_device(int i_device) {
+ device_id_option->select(i_device + 1);
+}
+
+int InputEventConfigurationDialog::_get_current_device() const {
+ return device_id_option->get_selected() - 1;
+}
+
+String InputEventConfigurationDialog::_get_device_string(int i_device) const {
+ if (i_device == InputMap::ALL_DEVICES) {
+ return TTR("All Devices");
+ }
+ return TTR("Device") + " " + itos(i_device);
+}
+
+void InputEventConfigurationDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ input_list_search->set_right_icon(input_list_search->get_theme_icon("Search", "EditorIcons"));
+
+ physical_key_checkbox->set_icon(get_theme_icon("KeyboardPhysical", "EditorIcons"));
+
+ icon_cache.keyboard = get_theme_icon("Keyboard", "EditorIcons");
+ icon_cache.mouse = get_theme_icon("Mouse", "EditorIcons");
+ icon_cache.joypad_button = get_theme_icon("JoyButton", "EditorIcons");
+ icon_cache.joypad_axis = get_theme_icon("JoyAxis", "EditorIcons");
+
+ _update_input_list();
+ } break;
+ default:
+ break;
+ }
+}
+
+void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p_event) {
+ if (p_event.is_valid()) {
+ _set_event(p_event);
+ } else {
+ // Clear Event
+ _set_event(p_event);
+
+ // Clear Checkbox Values
+ for (int i = 0; i < MOD_MAX; i++) {
+ mod_checkboxes[i]->set_pressed(false);
+ }
+ physical_key_checkbox->set_pressed(false);
+ store_command_checkbox->set_pressed(true);
+ _set_current_device(0);
+
+ // Switch to "Listen" tab
+ tab_container->set_current_tab(0);
+ }
+
+ popup_centered();
+}
+
+Ref<InputEvent> InputEventConfigurationDialog::get_event() const {
+ return event;
+}
+
+void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) {
+ allowed_input_types = p_type_masks;
+}
+
+InputEventConfigurationDialog::InputEventConfigurationDialog() {
+ allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
+
+ set_title("Event Configuration");
+ set_min_size(Size2i(550 * EDSCALE, 0)); // Min width
+
+ VBoxContainer *main_vbox = memnew(VBoxContainer);
+ add_child(main_vbox);
+
+ tab_container = memnew(TabContainer);
+ tab_container->set_tab_align(TabContainer::TabAlign::ALIGN_LEFT);
+ tab_container->set_use_hidden_tabs_for_min_size(true);
+ tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tab_container->connect("tab_selected", callable_mp(this, &InputEventConfigurationDialog::_tab_selected));
+ main_vbox->add_child(tab_container);
+
+ CenterContainer *cc = memnew(CenterContainer);
+ cc->set_name("Listen for Input");
+ event_as_text = memnew(Label);
+ event_as_text->set_align(Label::ALIGN_CENTER);
+ cc->add_child(event_as_text);
+ tab_container->add_child(cc);
+
+ // List of all input options to manually select from.
+
+ VBoxContainer *manual_vbox = memnew(VBoxContainer);
+ manual_vbox->set_name("Manual Selection");
+ manual_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tab_container->add_child(manual_vbox);
+
+ input_list_search = memnew(LineEdit);
+ input_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ input_list_search->set_placeholder(TTR("Filter Inputs"));
+ input_list_search->set_clear_button_enabled(true);
+ input_list_search->connect("text_changed", callable_mp(this, &InputEventConfigurationDialog::_search_term_updated));
+ manual_vbox->add_child(input_list_search);
+
+ input_list_tree = memnew(Tree);
+ input_list_tree->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); // Min height for tree
+ input_list_tree->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_selected));
+ input_list_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ manual_vbox->add_child(input_list_tree);
+
+ input_list_tree->set_hide_root(true);
+ input_list_tree->set_columns(1);
+
+ _update_input_list();
+
+ // Additional Options
+ additional_options_container = memnew(VBoxContainer);
+ additional_options_container->hide();
+
+ Label *opts_label = memnew(Label);
+ opts_label->set_text("Additional Options");
+ additional_options_container->add_child(opts_label);
+
+ // Device Selection
+ device_container = memnew(HBoxContainer);
+ device_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ Label *device_label = memnew(Label);
+ device_label->set_text("Device:");
+ device_container->add_child(device_label);
+
+ device_id_option = memnew(OptionButton);
+ device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ device_container->add_child(device_id_option);
+
+ for (int i = -1; i < 8; i++) {
+ device_id_option->add_item(_get_device_string(i));
+ }
+ _set_current_device(0);
+ device_container->hide();
+ additional_options_container->add_child(device_container);
+
+ // Modifier Selection
+ mod_container = memnew(HBoxContainer);
+ for (int i = 0; i < MOD_MAX; i++) {
+ String name = mods[i];
+ mod_checkboxes[i] = memnew(CheckBox);
+ mod_checkboxes[i]->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_mod_toggled), varray(i));
+ mod_checkboxes[i]->set_text(name);
+ mod_container->add_child(mod_checkboxes[i]);
+ }
+
+ mod_container->add_child(memnew(VSeparator));
+
+ store_command_checkbox = memnew(CheckBox);
+ store_command_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_store_command_toggled));
+ store_command_checkbox->set_pressed(true);
+ store_command_checkbox->set_text(TTR("Store Command"));
+#ifdef APPLE_STYLE_KEYS
+ store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard."));
+#else
+ store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards."));
+#endif
+ mod_container->add_child(store_command_checkbox);
+
+ mod_container->hide();
+ additional_options_container->add_child(mod_container);
+
+ // Physical Key Checkbox
+
+ physical_key_checkbox = memnew(CheckBox);
+ physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
+ physical_key_checkbox->set_tooltip(TTR("Stores the physical position of the key on the keyboard rather than the keys value. Used for compatibility with non-latin layouts."));
+ physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
+ physical_key_checkbox->hide();
+ additional_options_container->add_child(physical_key_checkbox);
+
+ main_vbox->add_child(additional_options_container);
+
+ // Default to first tab
+ tab_container->set_current_tab(0);
+}
+
+/////////////////////////////////////////
+
+static bool _is_action_name_valid(const String &p_name) {
+ const char32_t *cstr = p_name.get_data();
+ for (int i = 0; cstr[i]; i++) {
+ if (cstr[i] == '/' || cstr[i] == ':' || cstr[i] == '"' ||
+ cstr[i] == '=' || cstr[i] == '\\' || cstr[i] < 32) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ActionMapEditor::_event_config_confirmed() {
+ Ref<InputEvent> ev = event_config_dialog->get_event();
+
+ Dictionary new_action = current_action.duplicate();
+ Array events = new_action["events"];
+
+ if (current_action_event_index == -1) {
+ // Add new event
+ events.push_back(ev);
+ } else {
+ // Edit existing event
+ events[current_action_event_index] = ev;
+ }
+
+ new_action["events"] = events;
+ emit_signal("action_edited", current_action_name, new_action);
+}
+
+void ActionMapEditor::_add_action_pressed() {
+ _add_action(add_edit->get_text());
+}
+
+void ActionMapEditor::_add_action(const String &p_name) {
+ if (!allow_editing_actions) {
+ return;
+ }
+
+ if (p_name == "" || !_is_action_name_valid(p_name)) {
+ show_message(TTR("Invalid action name. it cannot be.is_empty()() nor contain '/', ':', '=', '\\' or '\"'"));
+ return;
+ }
+
+ add_edit->clear();
+ emit_signal("action_added", p_name);
+}
+
+void ActionMapEditor::_action_edited() {
+ if (!allow_editing_actions) {
+ return;
+ }
+
+ TreeItem *ti = action_tree->get_edited();
+ if (!ti) {
+ return;
+ }
+
+ if (action_tree->get_selected_column() == 0) {
+ // Name Edited
+ String new_name = ti->get_text(0);
+ String old_name = ti->get_meta("__name");
+
+ if (new_name == old_name) {
+ return;
+ }
+
+ if (new_name == "" || !_is_action_name_valid(new_name)) {
+ ti->set_text(0, old_name);
+ show_message(TTR("Invalid action name. it cannot be.is_empty()() nor contain '/', ':', '=', '\\' or '\"'"));
+ return;
+ }
+
+ emit_signal("action_renamed", old_name, new_name);
+ } else if (action_tree->get_selected_column() == 1) {
+ // Deadzone Edited
+ String name = ti->get_meta("__name");
+ Dictionary old_action = ti->get_meta("__action");
+ Dictionary new_action = old_action.duplicate();
+ new_action["deadzone"] = ti->get_range(1);
+
+ // Call deferred so that input can finish propagating through tree, allowing re-making of tree to occur.
+ call_deferred("emit_signal", "action_edited", name, new_action);
+ }
+}
+
+void ActionMapEditor::_tree_button_pressed(Object *p_item, int p_column, int p_id) {
+ ItemButton option = (ItemButton)p_id;
+
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ switch (option) {
+ case ActionMapEditor::BUTTON_ADD_EVENT: {
+ current_action = item->get_meta("__action");
+ current_action_name = item->get_meta("__name");
+ current_action_event_index = -1;
+
+ event_config_dialog->popup_and_configure();
+
+ } break;
+ case ActionMapEditor::BUTTON_EDIT_EVENT: {
+ // Action and Action name is located on the parent of the event.
+ current_action = item->get_parent()->get_meta("__action");
+ current_action_name = item->get_parent()->get_meta("__name");
+
+ current_action_event_index = item->get_meta("__index");
+
+ Ref<InputEvent> ie = item->get_meta("__event");
+ if (ie.is_valid()) {
+ event_config_dialog->popup_and_configure(ie);
+ }
+
+ } break;
+ case ActionMapEditor::BUTTON_REMOVE_ACTION: {
+ if (!allow_editing_actions) {
+ break;
+ }
+
+ // Send removed action name
+ String name = item->get_meta("__name");
+ emit_signal("action_removed", name);
+ } break;
+ case ActionMapEditor::BUTTON_REMOVE_EVENT: {
+ // Remove event and send updated action
+ Dictionary action = item->get_parent()->get_meta("__action");
+ String action_name = item->get_parent()->get_meta("__name");
+
+ int event_index = item->get_meta("__index");
+
+ Array events = action["events"];
+ events.remove(event_index);
+ action["events"] = events;
+
+ emit_signal("action_edited", action_name, action);
+ } break;
+ default:
+ break;
+ }
+}
+
+void ActionMapEditor::_tree_item_activated() {
+ TreeItem *item = action_tree->get_selected();
+
+ if (!item || !item->has_meta("__event")) {
+ return;
+ }
+
+ _tree_button_pressed(item, 2, BUTTON_EDIT_EVENT);
+}
+
+void ActionMapEditor::set_show_uneditable(bool p_show) {
+ show_uneditable = p_show;
+ show_uneditable_actions_checkbox->set_pressed(p_show);
+
+ // Prevent unnecessary updates of action list when cache is.is_empty()().
+ if (!actions_cache.is_empty()) {
+ update_action_list();
+ }
+}
+
+void ActionMapEditor::_search_term_updated(const String &) {
+ update_action_list();
+}
+
+Variant ActionMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ TreeItem *selected = action_tree->get_selected();
+ if (!selected) {
+ return Variant();
+ }
+
+ String name = selected->get_text(0);
+ Label *label = memnew(Label(name));
+ label->set_modulate(Color(1, 1, 1, 1.0f));
+ action_tree->set_drag_preview(label);
+
+ Dictionary drag_data;
+
+ if (selected->has_meta("__action")) {
+ drag_data["input_type"] = "action";
+ }
+
+ if (selected->has_meta("__event")) {
+ drag_data["input_type"] = "event";
+ }
+
+ action_tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
+
+ return drag_data;
+}
+
+bool ActionMapEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ Dictionary d = p_data;
+ if (!d.has("input_type")) {
+ return false;
+ }
+
+ TreeItem *selected = action_tree->get_selected();
+ TreeItem *item = action_tree->get_item_at_position(p_point);
+ if (!selected || !item || item == selected) {
+ return false;
+ }
+
+ // Don't allow moving an action in-between events.
+ if (d["input_type"] == "action" && item->has_meta("__event")) {
+ return false;
+ }
+
+ // Don't allow moving an event to a different action.
+ if (d["input_type"] == "event" && item->get_parent() != selected->get_parent()) {
+ return false;
+ }
+
+ return true;
+}
+
+void ActionMapEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
+ return;
+ }
+
+ TreeItem *selected = action_tree->get_selected();
+ TreeItem *target = action_tree->get_item_at_position(p_point);
+ bool drop_above = action_tree->get_drop_section_at_position(p_point) == -1;
+
+ if (!target) {
+ return;
+ }
+
+ Dictionary d = p_data;
+ if (d["input_type"] == "action") {
+ // Change action order.
+ String relative_to = target->get_meta("__name");
+ String action_name = selected->get_meta("__name");
+ emit_signal("action_reordered", action_name, relative_to, drop_above);
+
+ } else if (d["input_type"] == "event") {
+ // Change event order
+ int current_index = selected->get_meta("__index");
+ int target_index = target->get_meta("__index");
+
+ // Construct new events array.
+ Dictionary new_action = selected->get_parent()->get_meta("__action");
+
+ Array events = new_action["events"];
+ Array new_events;
+
+ // The following method was used to perform the array changes since `remove` followed by `insert` was not working properly at time of writing.
+ // Loop thought existing events
+ for (int i = 0; i < events.size(); i++) {
+ // If you come across the current index, just skip it, as it has been moved.
+ if (i == current_index) {
+ continue;
+ } else if (i == target_index) {
+ // We are at the target index. If drop above, add selected event there first, then target, so moved event goes on top.
+ if (drop_above) {
+ new_events.push_back(events[current_index]);
+ new_events.push_back(events[target_index]);
+ } else {
+ new_events.push_back(events[target_index]);
+ new_events.push_back(events[current_index]);
+ }
+ } else {
+ new_events.push_back(events[i]);
+ }
+ }
+
+ new_action["events"] = new_events;
+ emit_signal("action_edited", selected->get_parent()->get_meta("__name"), new_action);
+ }
+}
+
+void ActionMapEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ action_list_search->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ } break;
+ default:
+ break;
+ }
+}
+
+void ActionMapEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &ActionMapEditor::drop_data_fw);
+
+ ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action")));
+ ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("action_renamed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));
+ ADD_SIGNAL(MethodInfo("action_reordered", PropertyInfo(Variant::STRING, "action_name"), PropertyInfo(Variant::STRING, "relative_to"), PropertyInfo(Variant::BOOL, "before")));
+}
+
+LineEdit *ActionMapEditor::get_search_box() const {
+ return action_list_search;
+}
+
+InputEventConfigurationDialog *ActionMapEditor::get_configuration_dialog() {
+ return event_config_dialog;
+}
+
+void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_infos) {
+ if (!p_action_infos.is_empty()) {
+ actions_cache = p_action_infos;
+ }
+
+ action_tree->clear();
+ TreeItem *root = action_tree->create_item();
+
+ int uneditable_count = 0;
+
+ for (int i = 0; i < actions_cache.size(); i++) {
+ ActionInfo action_info = actions_cache[i];
+
+ if (!action_info.editable) {
+ uneditable_count++;
+ }
+
+ String search_term = action_list_search->get_text();
+ if (!search_term.is_empty() && action_info.name.findn(search_term) == -1) {
+ continue;
+ }
+
+ if (!action_info.editable && !show_uneditable) {
+ continue;
+ }
+
+ const Array events = action_info.action["events"];
+ const Variant deadzone = action_info.action["deadzone"];
+
+ // Update Tree...
+
+ TreeItem *action_item = action_tree->create_item(root);
+ action_item->set_meta("__action", action_info.action);
+ action_item->set_meta("__name", action_info.name);
+
+ // First Column - Action Name
+ action_item->set_text(0, action_info.name);
+ action_item->set_editable(0, action_info.editable);
+ action_item->set_icon(0, action_info.icon);
+
+ // Second Column - Deadzone
+ action_item->set_editable(1, true);
+ action_item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
+ action_item->set_range_config(1, 0.0, 1.0, 0.01);
+ action_item->set_range(1, deadzone);
+
+ // Third column - buttons
+ action_item->add_button(2, action_tree->get_theme_icon("Add", "EditorIcons"), BUTTON_ADD_EVENT, false, TTR("Add Event"));
+ action_item->add_button(2, action_tree->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_ACTION, !action_info.editable, action_info.editable ? "Remove Action" : "Cannot Remove Action");
+
+ action_item->set_custom_bg_color(0, action_tree->get_theme_color("prop_subsection", "Editor"));
+ action_item->set_custom_bg_color(1, action_tree->get_theme_color("prop_subsection", "Editor"));
+
+ for (int evnt_idx = 0; evnt_idx < events.size(); evnt_idx++) {
+ Ref<InputEvent> event = events[evnt_idx];
+ if (event.is_null()) {
+ continue;
+ }
+
+ TreeItem *event_item = action_tree->create_item(action_item);
+
+ // First Column - Text
+ event_item->set_text(0, event_config_dialog->get_event_text(event)); // Need to us the special description for JoypadMotion here, so don't use as_text() directly.
+ event_item->set_meta("__event", event);
+ event_item->set_meta("__index", evnt_idx);
+
+ // Third Column - Buttons
+ event_item->add_button(2, action_tree->get_theme_icon("Edit", "EditorIcons"), BUTTON_EDIT_EVENT, false, TTR("Edit Event"));
+ event_item->add_button(2, action_tree->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_EVENT, false, TTR("Remove Event"));
+ event_item->set_button_color(2, 0, Color(1, 1, 1, 0.75));
+ event_item->set_button_color(2, 1, Color(1, 1, 1, 0.75));
+ }
+ }
+}
+
+void ActionMapEditor::show_message(const String &p_message) {
+ message->set_text(p_message);
+ message->popup_centered(Size2(300, 100) * EDSCALE);
+}
+
+void ActionMapEditor::set_allow_editing_actions(bool p_allow) {
+ allow_editing_actions = p_allow;
+ add_hbox->set_visible(p_allow);
+}
+
+void ActionMapEditor::set_toggle_editable_label(const String &p_label) {
+ show_uneditable_actions_checkbox->set_text(p_label);
+}
+
+void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
+ memdelete(action_list_search);
+ action_list_search = p_searchbox;
+ action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
+}
+
+ActionMapEditor::ActionMapEditor() {
+ allow_editing_actions = true;
+ show_uneditable = true;
+
+ // Main Vbox Container
+ VBoxContainer *main_vbox = memnew(VBoxContainer);
+ main_vbox->set_anchors_and_offsets_preset(PRESET_WIDE);
+ add_child(main_vbox);
+
+ HBoxContainer *top_hbox = memnew(HBoxContainer);
+ main_vbox->add_child(top_hbox);
+
+ action_list_search = memnew(LineEdit);
+ action_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_list_search->set_placeholder(TTR("Filter Actions"));
+ action_list_search->set_clear_button_enabled(true);
+ action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
+ top_hbox->add_child(action_list_search);
+
+ show_uneditable_actions_checkbox = memnew(CheckBox);
+ show_uneditable_actions_checkbox->set_pressed(false);
+ show_uneditable_actions_checkbox->set_text(TTR("Show Uneditable Actions"));
+ show_uneditable_actions_checkbox->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_uneditable));
+ top_hbox->add_child(show_uneditable_actions_checkbox);
+
+ // Adding Action line edit + button
+ add_hbox = memnew(HBoxContainer);
+ add_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ add_edit = memnew(LineEdit);
+ add_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ add_edit->set_placeholder(TTR("Add New Action"));
+ add_edit->set_clear_button_enabled(true);
+ add_edit->connect("text_entered", callable_mp(this, &ActionMapEditor::_add_action));
+ add_hbox->add_child(add_edit);
+
+ Button *add_button = memnew(Button);
+ add_button->set_text("Add");
+ add_button->connect("pressed", callable_mp(this, &ActionMapEditor::_add_action_pressed));
+ add_hbox->add_child(add_button);
+
+ main_vbox->add_child(add_hbox);
+
+ // Action Editor Tree
+ action_tree = memnew(Tree);
+ action_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ action_tree->set_columns(3);
+ action_tree->set_hide_root(true);
+ action_tree->set_column_titles_visible(true);
+ action_tree->set_column_title(0, TTR("Action"));
+ action_tree->set_column_title(1, TTR("Deadzone"));
+ action_tree->set_column_expand(1, false);
+ action_tree->set_column_min_width(1, 80 * EDSCALE);
+ action_tree->set_column_expand(2, false);
+ action_tree->set_column_min_width(2, 50 * EDSCALE);
+ action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited));
+ action_tree->connect("item_activated", callable_mp(this, &ActionMapEditor::_tree_item_activated));
+ action_tree->connect("button_pressed", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
+ main_vbox->add_child(action_tree);
+
+ action_tree->set_drag_forwarding(this);
+
+ // Adding event dialog
+ event_config_dialog = memnew(InputEventConfigurationDialog);
+ event_config_dialog->connect("confirmed", callable_mp(this, &ActionMapEditor::_event_config_confirmed));
+ add_child(event_config_dialog);
+
+ message = memnew(AcceptDialog);
+ add_child(message);
+}
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
new file mode 100644
index 0000000000..f1f7bffef4
--- /dev/null
+++ b/editor/action_map_editor.h
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* action_map_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ACTION_MAP_EDITOR_H
+#define ACTION_MAP_EDITOR_H
+
+#include "editor/editor_data.h"
+
+// Confirmation Dialog used when configuring an input event.
+// Separate from ActionMapEditor for code cleanliness and separation of responsibilities.
+class InputEventConfigurationDialog : public ConfirmationDialog {
+ GDCLASS(InputEventConfigurationDialog, ConfirmationDialog);
+
+public:
+ enum InputType {
+ INPUT_KEY = 1,
+ INPUT_MOUSE_BUTTON = 2,
+ INPUT_JOY_BUTTON = 4,
+ INPUT_JOY_MOTION = 8
+ };
+
+private:
+ struct IconCache {
+ Ref<Texture2D> keyboard;
+ Ref<Texture2D> mouse;
+ Ref<Texture2D> joypad_button;
+ Ref<Texture2D> joypad_axis;
+ } icon_cache;
+
+ Ref<InputEvent> event = Ref<InputEvent>();
+
+ TabContainer *tab_container;
+
+ // Listening for input
+ Label *event_as_text;
+
+ // List of All Key/Mouse/Joypad input options.
+ int allowed_input_types;
+ Tree *input_list_tree;
+ LineEdit *input_list_search;
+
+ // Additional Options, shown depending on event selected
+ VBoxContainer *additional_options_container;
+
+ HBoxContainer *device_container;
+ OptionButton *device_id_option;
+
+ HBoxContainer *mod_container; // Contains the subcontainer and the store command checkbox.
+
+ enum ModCheckbox {
+ MOD_ALT,
+ MOD_SHIFT,
+ MOD_COMMAND,
+ MOD_CONTROL,
+ MOD_META,
+ MOD_MAX
+ };
+ String mods[MOD_MAX] = { "Alt", "Shift", "Command", "Control", "Meta" };
+
+ CheckBox *mod_checkboxes[MOD_MAX];
+ CheckBox *store_command_checkbox;
+
+ CheckBox *physical_key_checkbox;
+
+ void _set_event(const Ref<InputEvent> &p_event);
+
+ void _tab_selected(int p_tab);
+ void _listen_window_input(const Ref<InputEvent> &p_event);
+
+ void _search_term_updated(const String &p_term);
+ void _update_input_list();
+ void _input_list_item_selected();
+
+ void _mod_toggled(bool p_checked, int p_index);
+ void _store_command_toggled(bool p_checked);
+ void _physical_keycode_toggled(bool p_checked);
+
+ void _set_current_device(int i_device);
+ int _get_current_device() const;
+ String _get_device_string(int i_device) const;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ // Pass an existing event to configure it. Alternatively, pass no event to start with a blank configuration.
+ void popup_and_configure(const Ref<InputEvent> &p_event = Ref<InputEvent>());
+ Ref<InputEvent> get_event() const;
+ String get_event_text(const Ref<InputEvent> &p_event);
+
+ void set_allowed_input_types(int p_type_masks);
+
+ InputEventConfigurationDialog();
+};
+
+class ActionMapEditor : public Control {
+ GDCLASS(ActionMapEditor, Control);
+
+public:
+ struct ActionInfo {
+ String name = String();
+ Dictionary action = Dictionary();
+
+ Ref<Texture2D> icon = Ref<Texture2D>();
+ bool editable = true;
+ };
+
+private:
+ enum ItemButton {
+ BUTTON_ADD_EVENT,
+ BUTTON_EDIT_EVENT,
+ BUTTON_REMOVE_ACTION,
+ BUTTON_REMOVE_EVENT,
+ };
+
+ Vector<ActionInfo> actions_cache;
+ Tree *action_tree;
+
+ // Storing which action/event is currently being edited in the InputEventConfigurationDialog.
+
+ Dictionary current_action = Dictionary();
+ String current_action_name = String();
+ int current_action_event_index = -1;
+
+ // Popups
+
+ InputEventConfigurationDialog *event_config_dialog;
+ AcceptDialog *message;
+
+ // Filtering and Adding actions
+
+ bool show_uneditable;
+ CheckBox *show_uneditable_actions_checkbox;
+ LineEdit *action_list_search;
+
+ bool allow_editing_actions;
+ HBoxContainer *add_hbox;
+ LineEdit *add_edit;
+
+ void _event_config_confirmed();
+
+ void _add_action_pressed();
+ void _add_action(const String &p_name);
+ void _action_edited();
+
+ void _tree_button_pressed(Object *p_item, int p_column, int p_id);
+ void _tree_item_activated();
+ void _search_term_updated(const String &p_search_term);
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ LineEdit *get_search_box() const;
+ InputEventConfigurationDialog *get_configuration_dialog();
+
+ // Dictionary represents an Action with "events" (Array) and "deadzone" (float) items. Pass with no param to update list from cached action map.
+ void update_action_list(const Vector<ActionInfo> &p_action_infos = Vector<ActionInfo>());
+ void show_message(const String &p_message);
+
+ void set_show_uneditable(bool p_show);
+ void set_allow_editing_actions(bool p_allow);
+
+ void set_toggle_editable_label(const String &p_label);
+
+ void use_external_search_box(LineEdit *p_searchbox);
+
+ ActionMapEditor();
+};
+
+#endif
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 5d2b825c4f..ab8ae71904 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -602,6 +602,8 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
}
void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->is_shortcut(p_event)) {
duplicate_selection();
@@ -615,7 +617,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
float v_zoom_orig = v_zoom;
if (mb->get_command()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
@@ -628,7 +630,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
float v_zoom_orig = v_zoom;
if (mb->get_command()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
@@ -641,7 +643,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_MIDDLE) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
if (mb->is_pressed()) {
int x = mb->get_position().x - timeline->get_name_limit();
panning_timeline_from = x / timeline->get_zoom_scale();
@@ -652,7 +654,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position();
if (menu_insert_key.x >= timeline->get_name_limit() && menu_insert_key.x <= get_size().width - timeline->get_buttons_width()) {
Vector2 popup_pos = get_global_transform().xform(mb->get_position());
@@ -672,7 +674,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (close_icon_rect.has_point(mb->get_position())) {
emit_signal("close_request");
return;
@@ -789,7 +791,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (box_selecting_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (box_selecting_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (box_selecting) {
//do actual select
if (!box_selecting_add) {
@@ -819,7 +821,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
undo_redo->create_action(TTR("Move Bezier Points"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left);
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right);
@@ -831,7 +833,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (moving_selection) {
//combit it
@@ -927,7 +929,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
v_scroll += mm->get_relative().y * v_zoom;
if (v_scroll > 100000) {
v_scroll = 100000;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 5d49290612..9db2f0a287 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -634,7 +634,7 @@ public:
bool use_fps = false;
void notify_change() {
- _change_notify();
+ notify_property_list_changed();
}
Node *get_root_path() {
@@ -643,7 +643,7 @@ public:
void set_use_fps(bool p_enable) {
use_fps = p_enable;
- _change_notify();
+ notify_property_list_changed();
}
};
@@ -1276,7 +1276,7 @@ public:
UndoRedo *undo_redo = nullptr;
void notify_change() {
- _change_notify();
+ notify_property_list_changed();
}
Node *get_root_path() {
@@ -1285,7 +1285,7 @@ public:
void set_use_fps(bool p_enable) {
use_fps = p_enable;
- _change_notify();
+ notify_property_list_changed();
}
};
@@ -1641,26 +1641,28 @@ void AnimationTimelineEdit::_play_position_draw() {
}
void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
dragging_hsize = true;
dragging_hsize_from = mb->get_position().x;
dragging_hsize_at = name_limit;
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && dragging_hsize) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && dragging_hsize) {
dragging_hsize = false;
}
if (mb.is_valid() && mb->get_position().x > get_name_limit() && mb->get_position().x < (get_size().width - get_buttons_width())) {
- if (!panning_timeline && mb->get_button_index() == BUTTON_LEFT) {
+ if (!panning_timeline && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
int x = mb->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
emit_signal("timeline_changed", ofs, false);
dragging_timeline = true;
}
- if (!dragging_timeline && mb->get_button_index() == BUTTON_MIDDLE) {
+ if (!dragging_timeline && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
int x = mb->get_position().x - get_name_limit();
panning_timeline_from = x / get_zoom_scale();
panning_timeline = true;
@@ -1668,11 +1670,11 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (dragging_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (dragging_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
dragging_timeline = false;
}
- if (panning_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_MIDDLE && !mb->is_pressed()) {
+ if (panning_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_MIDDLE && !mb->is_pressed()) {
panning_timeline = false;
}
@@ -2522,6 +2524,8 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->is_shortcut(p_event)) {
emit_signal("duplicate_request");
@@ -2540,7 +2544,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos = mb->get_position();
if (check_rect.has_point(pos)) {
@@ -2683,7 +2687,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
Point2 pos = mb->get_position();
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
// Can do something with menu too! show insert key.
@@ -2713,7 +2717,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && clicking_on_name) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && clicking_on_name) {
if (!path) {
path_popup = memnew(Popup);
path_popup->set_wrap_controls(true);
@@ -2730,12 +2734,12 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
path_popup->set_size(path_rect.size);
path_popup->popup();
path->grab_focus();
- path->set_cursor_position(path->get_text().length());
+ path->set_caret_column(path->get_text().length());
clicking_on_name = false;
}
if (mb.is_valid() && moving_selection_attempt) {
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
moving_selection_attempt = false;
if (moving_selection) {
emit_signal("move_selection_commit");
@@ -2746,7 +2750,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = -1;
}
- if (moving_selection && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (moving_selection && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
moving_selection_attempt = false;
moving_selection = false;
emit_signal("move_selection_cancel");
@@ -2754,7 +2758,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT && moving_selection_attempt) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && moving_selection_attempt) {
if (!moving_selection) {
moving_selection = true;
emit_signal("move_selection_begin");
@@ -4283,7 +4287,6 @@ void AnimationTrackEditor::_animation_update() {
_update_step_spinbox();
emit_signal("animation_step_changed", animation->get_step());
emit_signal("animation_len_changed", animation->get_length());
- EditorNode::get_singleton()->get_inspector()->refresh();
animation_changing_awaiting_update = false;
}
@@ -4440,6 +4443,8 @@ void AnimationTrackEditor::_add_track(int p_type) {
}
adding_track_type = p_type;
pick_track->popup_scenetree_dialog();
+ pick_track->get_filter_line_edit()->clear();
+ pick_track->get_filter_line_edit()->grab_focus();
}
void AnimationTrackEditor::_new_track_property_selected(String p_name) {
@@ -4954,17 +4959,17 @@ void AnimationTrackEditor::_box_selection_draw() {
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
box_selecting = true;
box_selecting_from = scroll->get_global_transform().xform(mb->get_position());
@@ -4992,12 +4997,12 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
timeline->set_value(timeline->get_value() - mm->get_relative().x / timeline->get_zoom_scale());
}
if (mm.is_valid() && box_selecting) {
- if (!(mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+ if (!(mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
//no longer
box_selection->hide();
box_selecting = false;
@@ -5636,6 +5641,70 @@ void AnimationTrackEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_step_changed", PropertyInfo(Variant::FLOAT, "step")));
}
+void AnimationTrackEditor::_pick_track_filter_text_changed(const String &p_newtext) {
+ TreeItem *root_item = pick_track->get_scene_tree()->get_scene_tree()->get_root();
+
+ Vector<Node *> select_candidates;
+ Node *to_select = nullptr;
+
+ String filter = pick_track->get_filter_line_edit()->get_text();
+
+ _pick_track_select_recursive(root_item, filter, select_candidates);
+
+ if (!select_candidates.is_empty()) {
+ for (int i = 0; i < select_candidates.size(); ++i) {
+ Node *candidate = select_candidates[i];
+
+ if (((String)candidate->get_name()).to_lower().begins_with(filter.to_lower())) {
+ to_select = candidate;
+ break;
+ }
+ }
+
+ if (!to_select) {
+ to_select = select_candidates[0];
+ }
+ }
+
+ pick_track->get_scene_tree()->set_selected(to_select);
+}
+
+void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates) {
+ if (!p_item) {
+ return;
+ }
+
+ NodePath np = p_item->get_metadata(0);
+ Node *node = get_node(np);
+
+ if (p_filter != String() && ((String)node->get_name()).findn(p_filter) != -1) {
+ p_select_candidates.push_back(node);
+ }
+
+ TreeItem *c = p_item->get_children();
+
+ while (c) {
+ _pick_track_select_recursive(c, p_filter, p_select_candidates);
+ c = c->get_next();
+ }
+}
+
+void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> k = p_ie;
+
+ if (k.is_valid()) {
+ switch (k->get_keycode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+ pick_track->get_scene_tree()->get_scene_tree()->call("_gui_input", k);
+ pick_track->get_filter_line_edit()->accept_event();
+ } break;
+ }
+ }
+}
+
AnimationTrackEditor::AnimationTrackEditor() {
root = nullptr;
@@ -5806,8 +5875,12 @@ AnimationTrackEditor::AnimationTrackEditor() {
pick_track = memnew(SceneTreeDialog);
add_child(pick_track);
+ pick_track->register_text_enter(pick_track->get_filter_line_edit());
pick_track->set_title(TTR("Pick a node to animate:"));
pick_track->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_node_selected));
+ pick_track->get_filter_line_edit()->connect("text_changed", callable_mp(this, &AnimationTrackEditor::_pick_track_filter_text_changed));
+ pick_track->get_filter_line_edit()->connect("gui_input", callable_mp(this, &AnimationTrackEditor::_pick_track_filter_input));
+
prop_selector = memnew(PropertySelector);
add_child(prop_selector);
prop_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_new_track_property_selected));
@@ -5886,7 +5959,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
optimize_max_angle->set_value(22);
optimize_dialog->get_ok_button()->set_text(TTR("Optimize"));
- optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
+ optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_OPTIMIZE_ANIMATION_CONFIRM));
//
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index e8e4f915fa..c25865effb 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -499,6 +499,10 @@ class AnimationTrackEditor : public VBoxContainer {
void _insert_animation_key(NodePath p_path, const Variant &p_value);
+ void _pick_track_filter_text_changed(const String &p_newtext);
+ void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
+ void _pick_track_filter_input(const Ref<InputEvent> &p_ie);
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 0c0ee2856e..506a327ffc 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -101,47 +101,67 @@ void AnimationTrackEditColor::draw_key_link(int p_index, float p_pixels_sec, int
int font_size = get_theme_font_size("font_size", "Label");
int fh = (font->get_height(font_size) * 0.8);
+ fh /= 3;
+
int x_from = p_x + fh / 2 - 1;
int x_to = p_next_x - fh / 2 + 1;
- fh /= 3;
+ x_from = MAX(x_from, p_clip_left);
+ x_to = MIN(x_to, p_clip_right);
+
+ int y_from = (get_size().height - fh) / 2;
if (x_from > p_clip_right || x_to < p_clip_left) {
return;
}
- Color color = get_animation()->track_get_key_value(get_track(), p_index);
- Color color_next = get_animation()->track_get_key_value(get_track(), p_index + 1);
+ Vector<Color> color_samples;
+ color_samples.append(get_animation()->track_get_key_value(get_track(), p_index));
- if (x_from < p_clip_left) {
- float c = float(p_clip_left - x_from) / (x_to - x_from);
- color = color.lerp(color_next, c);
- x_from = p_clip_left;
- }
+ if (get_animation()->track_get_type(get_track()) == Animation::TYPE_VALUE) {
+ if (get_animation()->track_get_interpolation_type(get_track()) != Animation::INTERPOLATION_NEAREST &&
+ (get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CONTINUOUS ||
+ get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CAPTURE) &&
+ !Math::is_zero_approx(get_animation()->track_get_key_transition(get_track(), p_index))) {
+ float start_time = get_animation()->track_get_key_time(get_track(), p_index);
+ float end_time = get_animation()->track_get_key_time(get_track(), p_index + 1);
- if (x_to > p_clip_right) {
- float c = float(p_clip_right - x_from) / (x_to - x_from);
- color_next = color.lerp(color_next, c);
- x_to = p_clip_right;
- }
+ Color color_next = get_animation()->value_track_interpolate(get_track(), end_time);
- int y_from = (get_size().height - fh) / 2;
+ if (!color_samples[0].is_equal_approx(color_next)) {
+ color_samples.resize(1 + (x_to - x_from) / 64); // Make a color sample every 64 px.
+ for (int i = 1; i < color_samples.size(); i++) {
+ float j = i;
+ color_samples.write[i] = get_animation()->value_track_interpolate(
+ get_track(),
+ Math::lerp(start_time, end_time, j / color_samples.size()));
+ }
+ }
+ color_samples.append(color_next);
+ } else {
+ color_samples.append(color_samples[0]);
+ }
+ } else {
+ color_samples.append(get_animation()->track_get_key_value(get_track(), p_index + 1));
+ }
- Vector<Vector2> points;
- Vector<Color> colors;
+ for (int i = 0; i < color_samples.size() - 1; i++) {
+ Vector<Vector2> points;
+ Vector<Color> colors;
- points.push_back(Vector2(x_from, y_from));
- colors.push_back(color);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from));
+ colors.push_back(color_samples[i]);
- points.push_back(Vector2(x_to, y_from));
- colors.push_back(color_next);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from));
+ colors.push_back(color_samples[i + 1]);
- points.push_back(Vector2(x_to, y_from + fh));
- colors.push_back(color_next);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from + fh));
+ colors.push_back(color_samples[i + 1]);
- points.push_back(Vector2(x_from, y_from + fh));
- colors.push_back(color);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from + fh));
+ colors.push_back(color_samples[i]);
- draw_primitive(points, colors, Vector<Vector2>());
+ draw_primitive(points, colors, Vector<Vector2>());
+ }
}
void AnimationTrackEditColor::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {
@@ -1016,6 +1036,8 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
}
void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
if (!len_resizing && mm.is_valid()) {
bool use_hsize_cursor = false;
@@ -1076,7 +1098,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && get_default_cursor_shape() == CURSOR_HSIZE) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && get_default_cursor_shape() == CURSOR_HSIZE) {
len_resizing = true;
len_resizing_start = mb->get_shift();
len_resizing_from_px = mb->get_position().x;
@@ -1086,7 +1108,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale();
if (len_resizing_start) {
float prev_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index);
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
index 3daee4587c..09defac354 100644
--- a/editor/array_property_edit.cpp
+++ b/editor/array_property_edit.cpp
@@ -49,11 +49,7 @@ Variant ArrayPropertyEdit::get_array() const {
}
void ArrayPropertyEdit::_notif_change() {
- _change_notify();
-}
-
-void ArrayPropertyEdit::_notif_changev(const String &p_v) {
- _change_notify(p_v.utf8().get_data());
+ notify_property_list_changed();
}
void ArrayPropertyEdit::_set_size(int p_size) {
@@ -120,7 +116,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
}
if (pn == "array/page") {
page = p_value;
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -159,8 +155,6 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
ur->create_action(TTR("Change Array Value"));
ur->add_do_method(this, "_set_value", idx, p_value);
ur->add_undo_method(this, "_set_value", idx, value);
- ur->add_do_method(this, "_notif_changev", p_name);
- ur->add_undo_method(this, "_notif_changev", p_name);
ur->commit_action();
return true;
}
@@ -288,7 +282,6 @@ void ArrayPropertyEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_size"), &ArrayPropertyEdit::_set_size);
ClassDB::bind_method(D_METHOD("_set_value"), &ArrayPropertyEdit::_set_value);
ClassDB::bind_method(D_METHOD("_notif_change"), &ArrayPropertyEdit::_notif_change);
- ClassDB::bind_method(D_METHOD("_notif_changev"), &ArrayPropertyEdit::_notif_changev);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &ArrayPropertyEdit::_dont_undo_redo);
}
diff --git a/editor/array_property_edit.h b/editor/array_property_edit.h
index dd495b57f4..fa3dcbe038 100644
--- a/editor/array_property_edit.h
+++ b/editor/array_property_edit.h
@@ -47,7 +47,6 @@ class ArrayPropertyEdit : public Reference {
Variant::Type default_type;
void _notif_change();
- void _notif_changev(const String &p_v);
void _set_size(int p_size);
void _set_value(int p_idx, const Variant &p_value);
diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp
index 8be8735f3e..539657afd7 100644
--- a/editor/audio_stream_preview.cpp
+++ b/editor/audio_stream_preview.cpp
@@ -155,7 +155,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) {
preview->playback->stop();
- preview->generating = false;
+ preview->generating.clear();
}
Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<AudioStream> &p_stream) {
@@ -172,7 +172,7 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref<
Preview *preview = &previews[p_stream->get_instance_id()];
preview->base_stream = p_stream;
preview->playback = preview->base_stream->instance_playback();
- preview->generating = true;
+ preview->generating.set();
preview->id = p_stream->get_instance_id();
float len_s = preview->base_stream->get_length();
@@ -217,7 +217,7 @@ void AudioStreamPreviewGenerator::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
List<ObjectID> to_erase;
for (Map<ObjectID, Preview>::Element *E = previews.front(); E; E = E->next()) {
- if (!E->get().generating) {
+ if (!E->get().generating.is_set()) {
if (E->get().thread) {
E->get().thread->wait_to_finish();
memdelete(E->get().thread);
diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h
index 21c9ea203e..accc7275c0 100644
--- a/editor/audio_stream_preview.h
+++ b/editor/audio_stream_preview.h
@@ -32,6 +32,7 @@
#define AUDIO_STREAM_PREVIEW_H
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
#include "servers/audio/audio_stream.h"
@@ -60,9 +61,20 @@ class AudioStreamPreviewGenerator : public Node {
Ref<AudioStreamPreview> preview;
Ref<AudioStream> base_stream;
Ref<AudioStreamPlayback> playback;
- volatile bool generating = false;
+ SafeFlag generating;
ObjectID id;
Thread *thread = nullptr;
+
+ // Needed for the bookkeeping of the Map
+ Preview &operator=(const Preview &p_rhs) {
+ preview = p_rhs.preview;
+ base_stream = p_rhs.base_stream;
+ playback = p_rhs.playback;
+ generating.set_to(generating.is_set());
+ id = p_rhs.id;
+ thread = p_rhs.thread;
+ return *this;
+ }
};
Map<ObjectID, Preview> previews;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index f4717830bc..1c62c3d3e1 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -109,6 +109,8 @@ void FindReplaceBar::_notification(int p_what) {
}
void FindReplaceBar::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (!k.is_valid() || !k->is_pressed()) {
return;
@@ -140,7 +142,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
bool found = text_editor->search(text, p_flags, p_from_line, p_from_col, line, col);
if (found) {
- if (!preserve_cursor) {
+ if (!preserve_cursor && !is_selection_only()) {
text_editor->unfold_line(line);
text_editor->cursor_set_line(line, false);
text_editor->cursor_set_column(col + text.length(), false);
@@ -486,10 +488,10 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) {
if (!get_search_text().is_empty()) {
if (p_focus_replace) {
replace_text->select_all();
- replace_text->set_cursor_position(replace_text->get_text().length());
+ replace_text->set_caret_column(replace_text->get_text().length());
} else {
search_text->select_all();
- search_text->set_cursor_position(search_text->get_text().length());
+ search_text->set_caret_column(search_text->get_text().length());
}
results_count = -1;
@@ -691,6 +693,8 @@ FindReplaceBar::FindReplaceBar() {
// This function should be used to handle shortcuts that could otherwise
// be handled too late if they weren't handled here.
void CodeTextEditor::_input(const Ref<InputEvent> &event) {
+ ERR_FAIL_COND(event.is_null());
+
const Ref<InputEventKey> key_event = event;
if (!key_event.is_valid() || !key_event->is_pressed() || !text_editor->has_focus()) {
return;
@@ -723,9 +727,9 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_command()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
_zoom_in();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
_zoom_out();
}
}
@@ -1548,7 +1552,7 @@ void CodeTextEditor::validate_script() {
void CodeTextEditor::_warning_label_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_warning_button_pressed();
}
}
@@ -1572,7 +1576,7 @@ void CodeTextEditor::_toggle_scripts_pressed() {
void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
goto_error();
}
}
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 01fa094d38..0c1fb6fe4d 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -98,7 +98,7 @@ public:
}
void notify_changed() {
- _change_notify();
+ notify_property_list_changed();
}
ConnectDialogBinds() {
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 3a63100012..711072f4b2 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -170,6 +170,7 @@ void CreateDialog::_update_search() {
root->set_text(0, base_type);
root->set_icon(0, search_options->get_theme_icon(icon_fallback, "EditorIcons"));
search_options_types[base_type] = root;
+ _configure_search_option_item(root, base_type, ClassDB::class_exists(base_type));
const String search_text = search_box->get_text();
bool empty_search = search_text == "";
@@ -236,7 +237,10 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
bool can_instance = (p_cpp_type && ClassDB::can_instance(p_type)) || !p_cpp_type;
if (!can_instance) {
r_item->set_custom_color(0, search_options->get_theme_color("disabled_font_color", "Editor"));
+ r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, "NodeDisabled"));
r_item->set_selectable(0, false);
+ } else {
+ r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
}
if (search_box->get_text() != "") {
@@ -253,7 +257,6 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
r_item->set_tooltip(0, description);
- r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
if (!p_cpp_type && !script_type) {
Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon;
diff --git a/editor/debugger/editor_debugger_inspector.h b/editor/debugger/editor_debugger_inspector.h
index cf2d81cbf1..6648c99c03 100644
--- a/editor/debugger/editor_debugger_inspector.h
+++ b/editor/debugger/editor_debugger_inspector.h
@@ -58,7 +58,7 @@ public:
prop_values.clear();
}
- void update() { _change_notify(); }
+ void update() { notify_property_list_changed(); }
EditorDebuggerRemoteObject() {}
};
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 3ef9548727..ded0ee3aa7 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -209,7 +209,7 @@ void EditorDebuggerNode::stop() {
// Also close all debugging sessions.
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
if (dbg->is_session_active()) {
- dbg->stop();
+ dbg->_stop_and_notify();
}
});
_break_state_changed();
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 33d08a2f6b..fc0104c07a 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -249,7 +249,7 @@ TreeItem *EditorPerformanceProfiler::_create_monitor_item(const StringName &p_mo
void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector<StringName> active;
for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
if (i.value().item->is_checked(0)) {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 9304b116d0..6befee090b 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -43,28 +43,34 @@ void EditorProfiler::_make_metric_ptrs(Metric &m) {
}
}
+EditorProfiler::Metric EditorProfiler::_get_frame_metric(int index) {
+ return frame_metrics[(frame_metrics.size() + last_metric - (total_metrics - 1) + index) % frame_metrics.size()];
+}
+
void EditorProfiler::add_frame_metric(const Metric &p_metric, bool p_final) {
++last_metric;
if (last_metric >= frame_metrics.size()) {
last_metric = 0;
}
+ total_metrics++;
+ if (total_metrics > frame_metrics.size()) {
+ total_metrics = frame_metrics.size();
+ }
+
frame_metrics.write[last_metric] = p_metric;
_make_metric_ptrs(frame_metrics.write[last_metric]);
updating_frame = true;
- cursor_metric_edit->set_max(frame_metrics[last_metric].frame_number);
- cursor_metric_edit->set_min(MAX(frame_metrics[last_metric].frame_number - frame_metrics.size(), 0));
+ clear_button->set_disabled(false);
+ cursor_metric_edit->set_editable(true);
+ cursor_metric_edit->set_max(p_metric.frame_number);
+ cursor_metric_edit->set_min(_get_frame_metric(0).frame_number);
if (!seeking) {
- cursor_metric_edit->set_value(frame_metrics[last_metric].frame_number);
- if (hover_metric != -1) {
- hover_metric++;
- if (hover_metric >= frame_metrics.size()) {
- hover_metric = 0;
- }
- }
+ cursor_metric_edit->set_value(p_metric.frame_number);
}
+
updating_frame = false;
if (frame_delay->is_stopped()) {
@@ -83,6 +89,7 @@ void EditorProfiler::clear() {
metric_size = CLAMP(metric_size, 60, 1024);
frame_metrics.clear();
frame_metrics.resize(metric_size);
+ total_metrics = 0;
last_metric = -1;
variables->clear();
plot_sigs.clear();
@@ -93,6 +100,7 @@ void EditorProfiler::clear() {
cursor_metric_edit->set_min(0);
cursor_metric_edit->set_max(100); // Doesn't make much sense, but we can't have min == max. Doesn't hurt.
cursor_metric_edit->set_value(0);
+ cursor_metric_edit->set_editable(false);
updating_frame = false;
hover_metric = -1;
seeking = false;
@@ -187,11 +195,8 @@ void EditorProfiler::_update_plot() {
const bool use_self = display_time->get_selected() == DISPLAY_SELF_TIME;
float highest = 0;
- for (int i = 0; i < frame_metrics.size(); i++) {
- const Metric &m = frame_metrics[i];
- if (!m.valid) {
- continue;
- }
+ for (int i = 0; i < total_metrics; i++) {
+ const Metric &m = _get_frame_metric(i);
for (Set<StringName>::Element *E = plot_sigs.front(); E; E = E->next()) {
const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
@@ -220,78 +225,43 @@ void EditorProfiler::_update_plot() {
int *column = columnv.ptrw();
- Map<StringName, int> plot_prev;
- //Map<StringName,int> plot_max;
+ Map<StringName, int> prev_plots;
- for (int i = 0; i < w; i++) {
+ for (int i = 0; i < total_metrics * w / frame_metrics.size() - 1; i++) {
for (int j = 0; j < h * 4; j++) {
column[j] = 0;
}
int current = i * frame_metrics.size() / w;
- int next = (i + 1) * frame_metrics.size() / w;
- if (next > frame_metrics.size()) {
- next = frame_metrics.size();
- }
- if (next == current) {
- next = current + 1; //just because for loop must work
- }
for (Set<StringName>::Element *E = plot_sigs.front(); E; E = E->next()) {
- int plot_pos = -1;
+ const Metric &m = _get_frame_metric(current);
- for (int j = current; j < next; j++) {
- //wrap
- int idx = last_metric + 1 + j;
- while (idx >= frame_metrics.size()) {
- idx -= frame_metrics.size();
- }
-
- //get
- const Metric &m = frame_metrics[idx];
- if (!m.valid) {
- continue; //skip because invalid
- }
+ float value = 0;
- float value = 0;
-
- const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
- if (F) {
- value = F->get()->total_time;
- }
+ const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
+ if (F) {
+ value = F->get()->total_time;
+ }
- const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get());
- if (G) {
- if (use_self) {
- value = G->get()->self;
- } else {
- value = G->get()->total;
- }
+ const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get());
+ if (G) {
+ if (use_self) {
+ value = G->get()->self;
+ } else {
+ value = G->get()->total;
}
-
- plot_pos = MAX(CLAMP(int(value * h / highest), 0, h - 1), plot_pos);
}
+ int plot_pos = CLAMP(int(value * h / highest), 0, h - 1);
+
int prev_plot = plot_pos;
- Map<StringName, int>::Element *H = plot_prev.find(E->get());
+ Map<StringName, int>::Element *H = prev_plots.find(E->get());
if (H) {
prev_plot = H->get();
H->get() = plot_pos;
} else {
- plot_prev[E->get()] = plot_pos;
- }
-
- if (plot_pos == -1 && prev_plot == -1) {
- //don't bother drawing
- continue;
- }
-
- if (prev_plot != -1 && plot_pos == -1) {
- plot_pos = prev_plot;
- }
-
- if (prev_plot == -1 && plot_pos != -1) {
- prev_plot = plot_pos;
+ prev_plots[E->get()] = plot_pos;
}
plot_pos = h - plot_pos - 1;
@@ -352,15 +322,13 @@ void EditorProfiler::_update_plot() {
}
void EditorProfiler::_update_frame() {
- int cursor_metric = _get_cursor_index();
-
- ERR_FAIL_INDEX(cursor_metric, frame_metrics.size());
+ int cursor_metric = cursor_metric_edit->get_value() - _get_frame_metric(0).frame_number;
updating_frame = true;
variables->clear();
TreeItem *root = variables->create_item();
- const Metric &m = frame_metrics[cursor_metric];
+ const Metric &m = _get_frame_metric(cursor_metric);
int dtime = display_time->get_selected();
@@ -410,6 +378,7 @@ void EditorProfiler::_activate_pressed() {
if (activate->is_pressed()) {
activate->set_icon(get_theme_icon("Stop", "EditorIcons"));
activate->set_text(TTR("Stop"));
+ _clear_pressed();
} else {
activate->set_icon(get_theme_icon("Play", "EditorIcons"));
activate->set_text(TTR("Start"));
@@ -418,6 +387,7 @@ void EditorProfiler::_activate_pressed() {
}
void EditorProfiler::_clear_pressed() {
+ clear_button->set_disabled(true);
clear();
_update_plot();
}
@@ -430,30 +400,16 @@ void EditorProfiler::_notification(int p_what) {
}
void EditorProfiler::_graph_tex_draw() {
- if (last_metric < 0) {
+ if (total_metrics == 0) {
return;
}
if (seeking) {
- int max_frames = frame_metrics.size();
- int frame = cursor_metric_edit->get_value() - (frame_metrics[last_metric].frame_number - max_frames + 1);
- if (frame < 0) {
- frame = 0;
- }
-
- int cur_x = frame * graph->get_size().x / max_frames;
-
+ int frame = cursor_metric_edit->get_value() - _get_frame_metric(0).frame_number;
+ int cur_x = (2 * frame + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1;
graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.8));
}
-
- if (hover_metric != -1 && frame_metrics[hover_metric].valid) {
- int max_frames = frame_metrics.size();
- int frame = frame_metrics[hover_metric].frame_number - (frame_metrics[last_metric].frame_number - max_frames + 1);
- if (frame < 0) {
- frame = 0;
- }
-
- int cur_x = frame * graph->get_size().x / max_frames;
-
+ if (hover_metric > -1 && hover_metric < total_metrics) {
+ int cur_x = (2 * hover_metric + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1;
graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.4));
}
}
@@ -482,12 +438,12 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
if (
- (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) ||
+ (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) ||
(mm.is_valid())) {
- int x = me->get_position().x;
+ int x = me->get_position().x - 1;
x = x * frame_metrics.size() / graph->get_size().width;
- bool show_hover = x >= 0 && x < frame_metrics.size();
+ hover_metric = x;
if (x < 0) {
x = 0;
@@ -497,41 +453,11 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
x = frame_metrics.size() - 1;
}
- int metric = frame_metrics.size() - x - 1;
- metric = last_metric - metric;
- while (metric < 0) {
- metric += frame_metrics.size();
- }
-
- if (show_hover) {
- hover_metric = metric;
-
- } else {
- hover_metric = -1;
- }
-
- if (mb.is_valid() || mm->get_button_mask() & BUTTON_MASK_LEFT) {
- //cursor_metric=x;
+ if (mb.is_valid() || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
updating_frame = true;
- //metric may be invalid, so look for closest metric that is valid, this makes snap feel better
- bool valid = false;
- for (int i = 0; i < frame_metrics.size(); i++) {
- if (frame_metrics[metric].valid) {
- valid = true;
- break;
- }
-
- metric++;
- if (metric >= frame_metrics.size()) {
- metric = 0;
- }
- }
-
- if (valid) {
- cursor_metric_edit->set_value(frame_metrics[metric].frame_number);
- }
-
+ if (x < total_metrics)
+ cursor_metric_edit->set_value(_get_frame_metric(x).frame_number);
updating_frame = false;
if (activate->is_pressed()) {
@@ -552,24 +478,6 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
-int EditorProfiler::_get_cursor_index() const {
- if (last_metric < 0) {
- return 0;
- }
- if (!frame_metrics[last_metric].valid) {
- return 0;
- }
-
- int diff = (frame_metrics[last_metric].frame_number - cursor_metric_edit->get_value());
-
- int idx = last_metric - diff;
- while (idx < 0) {
- idx += frame_metrics.size();
- }
-
- return idx;
-}
-
void EditorProfiler::disable_seeking() {
seeking = false;
graph->update();
@@ -659,6 +567,7 @@ EditorProfiler::EditorProfiler() {
clear_button = memnew(Button);
clear_button->set_text(TTR("Clear"));
clear_button->connect("pressed", callable_mp(this, &EditorProfiler::_clear_pressed));
+ clear_button->set_disabled(true);
hb->add_child(clear_button);
hb->add_child(memnew(Label(TTR("Measure:"))));
@@ -687,6 +596,8 @@ EditorProfiler::EditorProfiler() {
cursor_metric_edit = memnew(SpinBox);
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
+ cursor_metric_edit->set_value(0);
+ cursor_metric_edit->set_editable(false);
hb->add_child(cursor_metric_edit);
cursor_metric_edit->connect("value_changed", callable_mp(this, &EditorProfiler::_cursor_metric_changed));
@@ -726,6 +637,7 @@ EditorProfiler::EditorProfiler() {
int metric_size = CLAMP(int(EDITOR_DEF("debugger/profiler_frame_history_size", 600)), 60, 1024);
frame_metrics.resize(metric_size);
+ total_metrics = 0;
last_metric = -1;
hover_metric = -1;
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index e16bde41f6..8880824b87 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -106,13 +106,13 @@ private:
SpinBox *cursor_metric_edit;
Vector<Metric> frame_metrics;
+ int total_metrics;
int last_metric;
int max_functions;
bool updating_frame;
- //int cursor_metric;
int hover_metric;
float graph_height;
@@ -139,14 +139,14 @@ private:
void _graph_tex_draw();
void _graph_tex_input(const Ref<InputEvent> &p_ev);
- int _get_cursor_index() const;
-
Color _get_color_from_signature(const StringName &p_signature) const;
void _cursor_metric_changed(double);
void _combo_changed(int);
+ Metric _get_frame_metric(int index);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index d825a980c7..5bb10b3794 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -517,7 +517,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
if (
- (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) ||
+ (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) ||
(mm.is_valid())) {
int half_w = graph->get_size().width / 2;
int x = me->get_position().x;
@@ -549,7 +549,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
hover_metric = -1;
}
- if (mb.is_valid() || mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mb.is_valid() || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
//cursor_metric=x;
updating_frame = true;
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index be2b98bf1a..1d95161e6c 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -35,6 +35,8 @@
#include "core/debugger/remote_debugger.h"
#include "core/io/marshalls.h"
#include "core/string/ustring.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "editor/debugger/editor_network_profiler.h"
#include "editor/debugger/editor_performance_profiler.h"
#include "editor/debugger/editor_profiler.h"
@@ -343,7 +345,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
DebuggerMarshalls::ResourceUsage usage;
usage.deserialize(p_data);
- int total = 0;
+ uint64_t total = 0;
for (List<DebuggerMarshalls::ResourceInfo>::Element *E = usage.infos.front(); E; E = E->next()) {
TreeItem *it = vmem_tree->create_item(root);
@@ -1371,7 +1373,8 @@ void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
item_menu->set_size(Size2(1, 1));
if (error_tree->is_anything_selected()) {
- item_menu->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), 0);
+ item_menu->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), ACTION_COPY_ERROR);
+ item_menu->add_icon_item(get_theme_icon("Instance", "EditorIcons"), TTR("Open C++ Source on GitHub"), ACTION_OPEN_SOURCE);
}
if (item_menu->get_item_count() > 0) {
@@ -1381,30 +1384,64 @@ void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
}
void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
- TreeItem *ti = error_tree->get_selected();
- while (ti->get_parent() != error_tree->get_root()) {
- ti = ti->get_parent();
- }
+ switch (p_option) {
+ case ACTION_COPY_ERROR: {
+ TreeItem *ti = error_tree->get_selected();
+ while (ti->get_parent() != error_tree->get_root()) {
+ ti = ti->get_parent();
+ }
- String type;
+ String type;
- if (ti->get_icon(0) == get_theme_icon("Warning", "EditorIcons")) {
- type = "W ";
- } else if (ti->get_icon(0) == get_theme_icon("Error", "EditorIcons")) {
- type = "E ";
- }
+ if (ti->get_icon(0) == get_theme_icon("Warning", "EditorIcons")) {
+ type = "W ";
+ } else if (ti->get_icon(0) == get_theme_icon("Error", "EditorIcons")) {
+ type = "E ";
+ }
- String text = ti->get_text(0) + " ";
- int rpad_len = text.length();
+ String text = ti->get_text(0) + " ";
+ int rpad_len = text.length();
- text = type + text + ti->get_text(1) + "\n";
- TreeItem *ci = ti->get_children();
- while (ci) {
- text += " " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
- ci = ci->get_next();
- }
+ text = type + text + ti->get_text(1) + "\n";
+ TreeItem *ci = ti->get_children();
+ while (ci) {
+ text += " " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
+ ci = ci->get_next();
+ }
- DisplayServer::get_singleton()->clipboard_set(text);
+ DisplayServer::get_singleton()->clipboard_set(text);
+ } break;
+
+ case ACTION_OPEN_SOURCE: {
+ TreeItem *ti = error_tree->get_selected();
+ while (ti->get_parent() != error_tree->get_root()) {
+ ti = ti->get_parent();
+ }
+
+ // We only need the first child here (C++ source stack trace).
+ TreeItem *ci = ti->get_children();
+ // Parse back the `file:line @ method()` string.
+ const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
+ ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");
+ const String file = file_line_number[0];
+ const int line_number = file_line_number[1].to_int();
+
+ // Construct a GitHub repository URL and open it in the user's default web browser.
+ if (String(VERSION_HASH).length() >= 1) {
+ // Git commit hash information available; use it for greater accuracy, including for development versions.
+ OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s/%s#L%d",
+ VERSION_HASH,
+ file,
+ line_number));
+ } else {
+ // Git commit hash information unavailable; fall back to tagged releases.
+ OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s-stable/%s#L%d",
+ VERSION_NUMBER,
+ file,
+ line_number));
+ }
+ } break;
+ }
}
void ScriptEditorDebugger::_tab_changed(int p_tab) {
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index e5fb3c35a9..a5731c9f9c 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -74,6 +74,11 @@ private:
PROFILER_SCRIPTS_SERVERS
};
+ enum Actions {
+ ACTION_COPY_ERROR,
+ ACTION_OPEN_SOURCE,
+ };
+
AcceptDialog *msgdialog;
LineEdit *clicked_ctrl;
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 2780b74469..57d44ca56c 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -86,11 +86,11 @@ void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String
String lost = E->key().replace_first("res://", "");
Vector<String> existingv = existing.split("/");
- existingv.invert();
+ existingv.reverse();
Vector<String> currentv = current.split("/");
- currentv.invert();
+ currentv.reverse();
Vector<String> lostv = lost.split("/");
- lostv.invert();
+ lostv.reverse();
int existing_score = 0;
int current_score = 0;
@@ -480,8 +480,8 @@ void DependencyRemoveDialog::ok_pressed() {
if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/boot_splash/image"))) {
ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("rendering/environment/default_environment"))) {
- ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
+ if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("rendering/environment/defaults/default_environment"))) {
+ ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"))) {
ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
@@ -492,8 +492,8 @@ void DependencyRemoveDialog::ok_pressed() {
if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("gui/theme/custom_font"))) {
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("audio/default_bus_layout"))) {
- ProjectSettings::get_singleton()->set("audio/default_bus_layout", "");
+ if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout"))) {
+ ProjectSettings::get_singleton()->set("audio/buses/default_bus_layout", "");
}
String path = OS::get_singleton()->get_resource_dir() + files_to_delete[i].replace_first("res://", "/");
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index 9683003d89..408177e523 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -32,11 +32,7 @@
#include "editor_node.h"
void DictionaryPropertyEdit::_notif_change() {
- _change_notify();
-}
-
-void DictionaryPropertyEdit::_notif_changev(const String &p_v) {
- _change_notify(p_v.utf8().get_data());
+ notify_property_list_changed();
}
void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) {
@@ -107,7 +103,6 @@ void DictionaryPropertyEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key);
ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value);
ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change);
- ClassDB::bind_method(D_METHOD("_notif_changev"), &DictionaryPropertyEdit::_notif_changev);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &DictionaryPropertyEdit::_dont_undo_redo);
}
@@ -128,8 +123,6 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
ur->create_action(TTR("Change Dictionary Key"));
ur->add_do_method(this, "_set_key", key, p_value);
ur->add_undo_method(this, "_set_key", p_value, key);
- ur->add_do_method(this, "_notif_changev", p_name);
- ur->add_undo_method(this, "_notif_changev", p_name);
ur->commit_action();
return true;
@@ -142,8 +135,6 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
ur->create_action(TTR("Change Dictionary Value"));
ur->add_do_method(this, "_set_value", key, p_value);
ur->add_undo_method(this, "_set_value", key, value);
- ur->add_do_method(this, "_notif_changev", p_name);
- ur->add_undo_method(this, "_notif_changev", p_name);
ur->commit_action();
return true;
diff --git a/editor/dictionary_property_edit.h b/editor/dictionary_property_edit.h
index 564bbf205b..e0fd945491 100644
--- a/editor/dictionary_property_edit.h
+++ b/editor/dictionary_property_edit.h
@@ -40,7 +40,6 @@ class DictionaryPropertyEdit : public Reference {
StringName property;
void _notif_change();
- void _notif_changev(const String &p_v);
void _set_key(const Variant &p_old_key, const Variant &p_new_key);
void _set_value(const Variant &p_key, const Variant &p_value);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 47ea8cbe2a..e29c9593c3 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -394,13 +394,22 @@ void DocTools::generate(bool p_basic_types) {
method.qualifiers += " ";
}
method.qualifiers += "const";
- } else if (E->get().flags & METHOD_FLAG_VARARG) {
+ }
+
+ if (E->get().flags & METHOD_FLAG_VARARG) {
if (method.qualifiers != "") {
method.qualifiers += " ";
}
method.qualifiers += "vararg";
}
+ if (E->get().flags & METHOD_FLAG_STATIC) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "static";
+ }
+
for (int i = -1; i < E->get().arguments.size(); i++) {
if (i == -1) {
#ifdef DEBUG_METHODS_ENABLED
@@ -647,6 +656,20 @@ void DocTools::generate(bool p_basic_types) {
method.qualifiers += "vararg";
}
+ if (mi.flags & METHOD_FLAG_CONST) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "const";
+ }
+
+ if (mi.flags & METHOD_FLAG_STATIC) {
+ if (method.qualifiers != "") {
+ method.qualifiers += " ";
+ }
+ method.qualifiers += "static";
+ }
+
c.methods.push_back(method);
}
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 2ed937b6ff..d962658484 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -38,16 +38,15 @@
#include "core/version_hash.gen.h"
void EditorAbout::_theme_changed() {
- Control *base = EditorNode::get_singleton()->get_gui_base();
- Ref<Font> font = base->get_theme_font("source", "EditorFonts");
- int font_size = base->get_theme_font_size("source_size", "EditorFonts");
+ const Ref<Font> font = get_theme_font("source", "EditorFonts");
+ const int font_size = get_theme_font_size("source_size", "EditorFonts");
_tpl_text->add_theme_font_override("normal_font", font);
_tpl_text->add_theme_font_size_override("normal_font_size", font_size);
_tpl_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
_license_text->add_theme_font_override("normal_font", font);
_license_text->add_theme_font_size_override("normal_font_size", font_size);
_license_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
- _logo->set_texture(base->get_theme_icon("Logo", "EditorIcons"));
+ _logo->set_texture(get_theme_icon("Logo", "EditorIcons"));
}
void EditorAbout::_notification(int p_what) {
diff --git a/editor/editor_about.h b/editor/editor_about.h
index efb7245e78..2823220a8a 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -44,6 +44,10 @@
#include "editor_scale.h"
+/**
+ * NOTE: Do not assume the EditorNode singleton to be available in this class' methods.
+ * EditorAbout is also used from the project manager where EditorNode isn't initialized.
+ */
class EditorAbout : public AcceptDialog {
GDCLASS(EditorAbout, AcceptDialog);
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 2eef4636d6..e7934bed0a 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -531,8 +531,10 @@ void EditorAudioBus::_effect_add(int p_which) {
}
void EditorAudioBus::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
Vector2 pos = Vector2(mb->get_position().x, mb->get_position().y);
bus_popup->set_position(get_global_position() + pos);
bus_popup->popup();
@@ -1191,9 +1193,9 @@ void EditorAudioBuses::_load_layout() {
}
void EditorAudioBuses::_load_default_layout() {
- String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
- Ref<AudioBusLayout> state = ResourceLoader::load(layout_path, "", true);
+ Ref<AudioBusLayout> state = ResourceLoader::load(layout_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
if (state.is_null()) {
EditorNode::get_singleton()->show_warning(vformat(TTR("There is no '%s' file."), layout_path));
return;
@@ -1209,7 +1211,7 @@ void EditorAudioBuses::_load_default_layout() {
void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_OPEN_FILE) {
- Ref<AudioBusLayout> state = ResourceLoader::load(p_string, "", true);
+ Ref<AudioBusLayout> state = ResourceLoader::load(p_string, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
if (state.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an audio bus layout."));
return;
@@ -1257,7 +1259,7 @@ EditorAudioBuses::EditorAudioBuses() {
add_child(top_hb);
file = memnew(Label);
- String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
file->set_text(String(TTR("Layout")) + ": " + layout_path.get_file());
file->set_clip_text(true);
file->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1313,7 +1315,7 @@ EditorAudioBuses::EditorAudioBuses() {
set_v_size_flags(SIZE_EXPAND_FILL);
- edited_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+ edited_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
file_dialog = memnew(EditorFileDialog);
List<String> ext;
@@ -1330,7 +1332,7 @@ EditorAudioBuses::EditorAudioBuses() {
void EditorAudioBuses::open_layout(const String &p_path) {
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
- Ref<AudioBusLayout> state = ResourceLoader::load(p_path, "", true);
+ Ref<AudioBusLayout> state = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
if (state.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an audio bus layout."));
return;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 336bf26607..fa4703d425 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -500,6 +500,7 @@ int EditorData::add_edited_scene(int p_at_pos) {
EditedScene es;
es.root = nullptr;
es.path = String();
+ es.file_modified_time = 0;
es.history_current = -1;
es.version = 0;
es.live_edit_root = NodePath(String("/root"));
@@ -656,6 +657,10 @@ void EditorData::set_edited_scene_root(Node *p_root) {
p_root->set_filename(edited_scene[current_edited_scene].path);
}
}
+
+ if (edited_scene[current_edited_scene].path != "") {
+ edited_scene.write[current_edited_scene].file_modified_time = FileAccess::get_modified_time(edited_scene[current_edited_scene].path);
+ }
}
int EditorData::get_edited_scene_count() const {
@@ -687,6 +692,21 @@ uint64_t EditorData::get_scene_version(int p_idx) const {
return edited_scene[p_idx].version;
}
+void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+
+ ERR_FAIL_INDEX(p_idx, edited_scene.size());
+
+ edited_scene.write[p_idx].file_modified_time = p_time;
+}
+
+uint64_t EditorData::get_scene_modified_time(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0);
+ return edited_scene[p_idx].file_modified_time;
+}
+
String EditorData::get_scene_type(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
if (!edited_scene[p_idx].root) {
@@ -721,7 +741,7 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const {
return s;
}
-String EditorData::get_scene_title(int p_idx) const {
+String EditorData::get_scene_title(int p_idx, bool p_always_strip_extension) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
if (!edited_scene[p_idx].root) {
return TTR("[empty]");
@@ -729,12 +749,28 @@ String EditorData::get_scene_title(int p_idx) const {
if (edited_scene[p_idx].root->get_filename() == "") {
return TTR("[unsaved]");
}
- bool show_ext = EDITOR_DEF("interface/scene_tabs/show_extension", false);
- String name = edited_scene[p_idx].root->get_filename().get_file();
- if (!show_ext) {
- name = name.get_basename();
+
+ const String filename = edited_scene[p_idx].root->get_filename().get_file();
+ const String basename = filename.get_basename();
+
+ if (p_always_strip_extension) {
+ return basename;
+ }
+
+ // Return the filename including the extension if there's ambiguity (e.g. both `foo.tscn` and `foo.scn` are being edited).
+ for (int i = 0; i < edited_scene.size(); i++) {
+ if (i == p_idx) {
+ // Don't compare the edited scene against itself.
+ continue;
+ }
+
+ if (edited_scene[i].root && basename == edited_scene[i].root->get_filename().get_file().get_basename()) {
+ return filename;
+ }
}
- return name;
+
+ // Else, return just the basename as there's no ambiguity.
+ return basename;
}
void EditorData::set_scene_path(int p_idx, const String &p_path) {
@@ -922,6 +958,14 @@ void EditorData::script_class_save_icon_paths() {
}
}
+ Dictionary old;
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
+ old = ProjectSettings::get_singleton()->get("_global_script_class_icons");
+ }
+ if ((!old.is_empty() || d.is_empty()) && d.hash() == old.hash()) {
+ return;
+ }
+
if (d.is_empty()) {
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
ProjectSettings::get_singleton()->clear("_global_script_class_icons");
diff --git a/editor/editor_data.h b/editor/editor_data.h
index f14a3fb4e0..dbe729d9d9 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -111,6 +111,7 @@ public:
struct EditedScene {
Node *root = nullptr;
String path;
+ uint64_t file_modified_time = 0;
Dictionary editor_states;
List<Node *> selection;
Vector<EditorHistory::History> history_stored;
@@ -183,13 +184,15 @@ public:
Node *get_edited_scene_root(int p_idx = -1);
int get_edited_scene_count() const;
Vector<EditedScene> get_edited_scenes() const;
- String get_scene_title(int p_idx) const;
+ String get_scene_title(int p_idx, bool p_always_strip_extension = false) const;
String get_scene_path(int p_idx) const;
String get_scene_type(int p_idx) const;
void set_scene_path(int p_idx, const String &p_path);
Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
uint64_t get_scene_version(int p_idx) const;
+ void set_scene_modified_time(int p_idx, uint64_t p_time);
+ uint64_t get_scene_modified_time(int p_idx) const;
void clear_edited_scenes();
void set_edited_scene_live_edit_root(const NodePath &p_root);
NodePath get_edited_scene_live_edit_root();
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 24256b843e..a368a9618e 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -301,6 +301,8 @@ void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags)
}
Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
+
PackData *pd = (PackData *)p_userdata;
SavedData sd;
@@ -368,6 +370,8 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
}
Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+ ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
+
String path = p_path.replace_first("res://", "");
ZipData *zd = (ZipData *)p_userdata;
@@ -507,6 +511,11 @@ void EditorExportPlatform::_edit_files_with_filter(DirAccess *da, const Vector<S
if (dir.begins_with(".")) {
continue;
}
+
+ if (EditorFileSystem::_should_skip_directory(cur_dir + dir)) {
+ continue;
+ }
+
da->change_dir(dir);
_edit_files_with_filter(da, p_filters, r_list, exclude);
da->change_dir("..");
@@ -721,6 +730,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) {
//find stuff
_export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
+ } else if (p_preset->get_export_filter() == EditorExportPreset::EXCLUDE_SELECTED_RESOURCES) {
+ _export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
+ Vector<String> files = p_preset->get_files_to_export();
+ for (int i = 0; i < files.size(); i++) {
+ paths.erase(files[i]);
+ }
} else {
bool scenes_only = p_preset->get_export_filter() == EditorExportPreset::EXPORT_SELECTED_SCENES;
@@ -819,17 +834,25 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
}
+ Error err = OK;
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+
for (int i = 0; i < export_plugins.size(); i++) {
export_plugins.write[i]->set_export_preset(p_preset);
if (p_so_func) {
for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) {
- p_so_func(p_udata, export_plugins[i]->shared_objects[j]);
+ err = p_so_func(p_udata, export_plugins[i]->shared_objects[j]);
+ if (err != OK) {
+ return err;
+ }
}
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
}
export_plugins.write[i]->_clear();
@@ -851,12 +874,26 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
//file is imported, replace by what it imports
Ref<ConfigFile> config;
config.instance();
- Error err = config->load(path + ".import");
+ err = config->load(path + ".import");
if (err != OK) {
ERR_PRINT("Could not parse: '" + path + "', not exported.");
continue;
}
+ String importer_type = config->get_value("remap", "importer");
+
+ if (importer_type == "keep") {
+ //just keep file as-is
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path);
+ err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+
+ if (err != OK) {
+ return err;
+ }
+
+ continue;
+ }
+
List<String> remaps;
config->get_section_keys("remap", &remaps);
@@ -915,12 +952,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
if (p_so_func) {
for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) {
- p_so_func(p_udata, export_plugins[i]->shared_objects[j]);
+ err = p_so_func(p_udata, export_plugins[i]->shared_objects[j]);
+ if (err != OK) {
+ return err;
+ }
}
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
if (export_plugins[i]->extra_files[j].remap) {
do_export = false; //if remap, do not
path_remaps.push_back(path);
@@ -940,7 +983,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
//just store it as it comes
if (do_export) {
Vector<uint8_t> array = FileAccess::get_file_as_array(path);
- p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
}
}
@@ -976,7 +1022,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
new_file.write[j] = utf8[j];
}
- p_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
}
} else {
//old remap mode, will still work, but it's unused because it's not multiple pck export friendly
@@ -989,19 +1038,42 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image");
if (icon != String() && FileAccess::exists(icon)) {
Vector<uint8_t> array = FileAccess::get_file_as_array(icon);
- p_func(p_udata, icon, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, icon, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
}
if (splash != String() && FileAccess::exists(splash) && icon != splash) {
Vector<uint8_t> array = FileAccess::get_file_as_array(splash);
- p_func(p_udata, splash, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_func(p_udata, splash, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
}
- // Store text server data if exists.
+ // Store text server data if it is supported.
if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- String ts_data = "res://" + TS->get_support_data_filename();
- if (FileAccess::exists(ts_data)) {
- Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
- p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ bool use_data = ProjectSettings::get_singleton()->get("internationalization/locale/include_text_server_data");
+ if (use_data) {
+ // Try using user provided data file.
+ String ts_data = "res://" + TS->get_support_data_filename();
+ if (FileAccess::exists(ts_data)) {
+ Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ // Use default text server data.
+ String icu_data_file = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+ TS->save_support_data(icu_data_file);
+ Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ DirAccess::remove_file_or_error(icu_data_file);
+ if (err != OK) {
+ return err;
+ }
+ }
}
}
@@ -1011,9 +1083,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
- p_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key);
-
- return OK;
+ return p_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key);
}
Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObject &p_so) {
@@ -1047,6 +1117,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
if (err != OK) {
DirAccess::remove_file_or_error(tmppath);
+ ERR_PRINT("Failed to export project files");
return err;
}
@@ -1343,6 +1414,10 @@ void EditorExport::_save() {
config->set_value(section, "export_filter", "resources");
save_files = true;
} break;
+ case EditorExportPreset::EXCLUDE_SELECTED_RESOURCES: {
+ config->set_value(section, "export_filter", "exclude");
+ save_files = true;
+ } break;
}
if (save_files) {
@@ -1403,9 +1478,9 @@ void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, in
}
String EditorExportPlatform::test_etc2() const {
- String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
- bool etc_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc");
- bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2");
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ bool etc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc");
+ bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
if (driver == "GLES2" && !etc_supported) {
return TTR("Target platform requires 'ETC' texture compression for GLES2. Enable 'Import Etc' in Project Settings.");
@@ -1417,9 +1492,9 @@ String EditorExportPlatform::test_etc2() const {
}
String EditorExportPlatform::test_etc2_or_pvrtc() const {
- String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
- bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2");
- bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc");
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
+ bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc");
if (driver == "GLES2" && !pvrtc_supported) {
return TTR("Target platform requires 'PVRTC' texture compression for GLES2. Enable 'Import Pvrtc' in Project Settings.");
@@ -1521,6 +1596,9 @@ void EditorExport::load_config() {
} else if (export_filter == "resources") {
preset->set_export_filter(EditorExportPreset::EXPORT_SELECTED_RESOURCES);
get_files = true;
+ } else if (export_filter == "exclude") {
+ preset->set_export_filter(EditorExportPreset::EXCLUDE_SELECTED_RESOURCES);
+ get_files = true;
}
if (get_files) {
@@ -1902,7 +1980,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
return;
}
- bool convert = GLOBAL_GET("editor/convert_text_resources_to_binary_on_export");
+ bool convert = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
if (!convert) {
return;
}
@@ -1922,5 +2000,5 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
}
EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() {
- GLOBAL_DEF("editor/convert_text_resources_to_binary_on_export", false);
+ GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false);
}
diff --git a/editor/editor_export.h b/editor/editor_export.h
index e6026e7aae..c96c8fdbce 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -50,6 +50,7 @@ public:
EXPORT_ALL_RESOURCES,
EXPORT_SELECTED_SCENES,
EXPORT_SELECTED_RESOURCES,
+ EXCLUDE_SELECTED_RESOURCES,
};
enum ScriptExportMode {
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index af02fcaf3c..bd00d86ec8 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -277,11 +277,7 @@ void EditorFeatureProfile::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_MAX);
}
-EditorFeatureProfile::EditorFeatureProfile() {
- for (int i = 0; i < FEATURE_MAX; i++) {
- features_disabled[i] = false;
- }
-}
+EditorFeatureProfile::EditorFeatureProfile() {}
//////////////////////////
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 01aad0c41b..75815fa750 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -125,6 +125,8 @@ void EditorFileDialog::_notification(int p_what) {
}
void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
@@ -1076,9 +1078,9 @@ EditorFileDialog::Access EditorFileDialog::get_access() const {
}
void EditorFileDialog::_make_dir_confirm() {
- Error err = dir_access->make_dir(makedirname->get_text());
+ Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
if (err == OK) {
- dir_access->change_dir(makedirname->get_text());
+ dir_access->change_dir(makedirname->get_text().strip_edges());
invalidate();
update_filters();
update_dir();
@@ -1150,7 +1152,6 @@ void EditorFileDialog::_update_drives() {
void EditorFileDialog::_favorite_selected(int p_idx) {
dir_access->change_dir(favorites->get_item_metadata(p_idx));
- file->set_text("");
update_dir();
invalidate();
_push_history();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 4b68de26e7..495bdd42f7 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -68,6 +68,11 @@ int EditorFileSystemDirectory::find_dir_index(const String &p_dir) const {
return -1;
}
+void EditorFileSystemDirectory::force_update() {
+ // We set modified_time to 0 to force `EditorFileSystem::_scan_fs_changes` to search changes in the directory
+ modified_time = 0;
+}
+
int EditorFileSystemDirectory::get_subdir_count() const {
return subdirs.size();
}
@@ -405,6 +410,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
memdelete(f);
+ if (importer_name == "keep") {
+ return false; //keep mode, do not reimport
+ }
+
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
if (importer->get_format_version() > version) {
@@ -669,10 +678,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
continue;
}
- if (FileAccess::exists(cd.plus_file(f).plus_file("project.godot"))) { // skip if another project inside this
- continue;
- }
- if (FileAccess::exists(cd.plus_file(f).plus_file(".gdignore"))) { // skip if another project inside this
+ if (_should_skip_directory(cd.plus_file(f))) {
continue;
}
@@ -853,9 +859,11 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
//then scan files and directories and check what's different
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ Error ret = da->change_dir(cd);
+ ERR_FAIL_COND_MSG(ret != OK, "Cannot change to '" + cd + "' folder.");
- da->change_dir(cd);
da->list_dir_begin();
while (true) {
String f = da->get_next();
@@ -874,10 +882,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
int idx = p_dir->find_dir_index(f);
if (idx == -1) {
- if (FileAccess::exists(cd.plus_file(f).plus_file("project.godot"))) { // skip if another project inside this
- continue;
- }
- if (FileAccess::exists(cd.plus_file(f).plus_file(".gdignore"))) { // skip if another project inside this
+ if (_should_skip_directory(cd.plus_file(f))) {
continue;
}
@@ -946,7 +951,6 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
}
da->list_dir_end();
- memdelete(da);
}
for (int i = 0; i < p_dir->files.size(); i++) {
@@ -1413,11 +1417,11 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
}
void EditorFileSystem::update_script_classes() {
- if (!update_script_classes_queued) {
+ if (!update_script_classes_queued.is_set()) {
return;
}
- update_script_classes_queued = false;
+ update_script_classes_queued.clear();
ScriptServer::global_classes_clear();
if (get_filesystem()) {
_scan_script_classes(get_filesystem());
@@ -1436,11 +1440,11 @@ void EditorFileSystem::update_script_classes() {
}
void EditorFileSystem::_queue_update_script_classes() {
- if (update_script_classes_queued) {
+ if (update_script_classes_queued.is_set()) {
return;
}
- update_script_classes_queued = true;
+ update_script_classes_queued.set();
call_deferred("update_script_classes");
}
@@ -1538,6 +1542,10 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
source_file_options[p_files[i]] = Map<StringName, Variant>();
importer_name = file_importer_name;
+ if (importer_name == "keep") {
+ continue; //do nothing
+ }
+
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_CORRUPT);
List<ResourceImporter::ImportOption> options;
@@ -1561,6 +1569,10 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
base_paths[p_files[i]] = ResourceFormatImporter::get_singleton()->get_import_base_path(p_files[i]);
}
+ if (importer_name == "keep") {
+ return OK; // (do nothing)
+ }
+
ERR_FAIL_COND_V(importer_name == String(), ERR_UNCONFIGURED);
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
@@ -1674,7 +1686,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
return err;
}
-void EditorFileSystem::_reimport_file(const String &p_file) {
+void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options, const String &p_custom_importer) {
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(p_file, &fs, cpos);
@@ -1683,23 +1695,32 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
//try to obtain existing params
Map<StringName, Variant> params;
- String importer_name;
+ String importer_name; //empty by default though
+
+ if (p_custom_importer != String()) {
+ importer_name = p_custom_importer;
+ }
+ if (p_custom_options != nullptr) {
+ params = *p_custom_options;
+ }
if (FileAccess::exists(p_file + ".import")) {
//use existing
- Ref<ConfigFile> cf;
- cf.instance();
- Error err = cf->load(p_file + ".import");
- if (err == OK) {
- if (cf->has_section("params")) {
- List<String> sk;
- cf->get_section_keys("params", &sk);
- for (List<String>::Element *E = sk.front(); E; E = E->next()) {
- params[E->get()] = cf->get_value("params", E->get());
+ if (p_custom_options == nullptr) {
+ Ref<ConfigFile> cf;
+ cf.instance();
+ Error err = cf->load(p_file + ".import");
+ if (err == OK) {
+ if (cf->has_section("params")) {
+ List<String> sk;
+ cf->get_section_keys("params", &sk);
+ for (List<String>::Element *E = sk.front(); E; E = E->next()) {
+ params[E->get()] = cf->get_value("params", E->get());
+ }
+ }
+ if (p_custom_importer == String() && cf->has_section("remap")) {
+ importer_name = cf->get_value("remap", "importer");
}
- }
- if (cf->has_section("remap")) {
- importer_name = cf->get_value("remap", "importer");
}
}
@@ -1707,6 +1728,16 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
late_added_files.insert(p_file); //imported files do not call update_file(), but just in case..
}
+ if (importer_name == "keep") {
+ //keep files, do nothing.
+ fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
+ fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import");
+ fs->files[cpos]->deps.clear();
+ fs->files[cpos]->type = "";
+ fs->files[cpos]->import_valid = false;
+ EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
+ return;
+ }
Ref<ResourceImporter> importer;
bool load_default = false;
//find the importer
@@ -1893,6 +1924,15 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<Str
}
}
+void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params) {
+ _reimport_file(p_file, &p_custom_params, p_importer);
+}
+
+void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_import_data) {
+ p_import_data->max_index = MAX(p_import_data->reimport_from + int(p_index), p_import_data->max_index);
+ _reimport_file(p_import_data->reimport_files[p_import_data->reimport_from + p_index].path);
+}
+
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
{
// Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
@@ -1910,7 +1950,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
importing = true;
EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size());
- Vector<ImportFile> files;
+ Vector<ImportFile> reimport_files;
+
Set<String> groups_to_reimport;
for (int i = 0; i < p_files.size(); i++) {
@@ -1928,8 +1969,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
//it's a regular file
ImportFile ifile;
ifile.path = p_files[i];
- ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]);
- files.push_back(ifile);
+ ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(p_files[i], ifile.order, ifile.threaded, ifile.importer);
+ reimport_files.push_back(ifile);
}
//group may have changed, so also update group reference
@@ -1940,11 +1981,51 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
}
}
- files.sort();
+ reimport_files.sort();
- for (int i = 0; i < files.size(); i++) {
- pr.step(files[i].path.get_file(), i);
- _reimport_file(files[i].path);
+ bool use_threads = GLOBAL_GET("editor/import/use_multiple_threads");
+
+ int from = 0;
+ for (int i = 0; i < reimport_files.size(); i++) {
+ if (use_threads && reimport_files[i].threaded) {
+ if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) {
+ if (from - i == 0) {
+ //single file, do not use threads
+ pr.step(reimport_files[i].path.get_file(), i);
+ _reimport_file(reimport_files[i].path);
+ } else {
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer);
+ ERR_CONTINUE(!importer.is_valid());
+
+ importer->import_threaded_begin();
+
+ ImportThreadData data;
+ data.max_index = from;
+ data.reimport_from = from;
+ data.reimport_files = reimport_files.ptr();
+
+ import_threads.begin_work(i - from + 1, this, &EditorFileSystem::_reimport_thread, &data);
+ int current_index = from - 1;
+ do {
+ if (current_index < data.max_index) {
+ current_index = data.max_index;
+ pr.step(reimport_files[current_index].path.get_file(), current_index);
+ }
+ OS::get_singleton()->delay_usec(1);
+ } while (!import_threads.is_done_dispatching());
+
+ import_threads.end_work();
+
+ importer->import_threaded_end();
+ }
+
+ from = i + 1;
+ }
+
+ } else {
+ pr.step(reimport_files[i].path.get_file(), i);
+ _reimport_file(reimport_files[i].path);
+ }
}
//reimport groups
@@ -1979,6 +2060,20 @@ Error EditorFileSystem::_resource_import(const String &p_path) {
return OK;
}
+bool EditorFileSystem::_should_skip_directory(const String &p_path) {
+ if (FileAccess::exists(p_path.plus_file("project.godot"))) {
+ // skip if another project inside this
+ return true;
+ }
+
+ if (FileAccess::exists(p_path.plus_file(".gdignore"))) {
+ // skip if a `.gdignore` file is inside this
+ return true;
+ }
+
+ return false;
+}
+
bool EditorFileSystem::is_group_file(const String &p_path) const {
return group_file_cache.has(p_path);
}
@@ -2067,8 +2162,8 @@ void EditorFileSystem::_update_extensions() {
EditorFileSystem::EditorFileSystem() {
ResourceLoader::import = _resource_import;
- reimport_on_missing_imported_files = GLOBAL_DEF("editor/reimport_missing_imported_files", true);
-
+ reimport_on_missing_imported_files = GLOBAL_DEF("editor/import/reimport_missing_imported_files", true);
+ GLOBAL_DEF("editor/import/use_multiple_threads", true);
singleton = this;
filesystem = memnew(EditorFileSystemDirectory); //like, empty
filesystem->parent = nullptr;
@@ -2091,11 +2186,13 @@ EditorFileSystem::EditorFileSystem() {
memdelete(da);
scan_total = 0;
- update_script_classes_queued = false;
+ update_script_classes_queued.clear();
first_scan = true;
scan_changes_pending = false;
revalidate_import_files = false;
+ import_threads.init();
}
EditorFileSystem::~EditorFileSystem() {
+ import_threads.finish();
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index fa0b89e667..855c320856 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -34,8 +34,11 @@
#include "core/os/dir_access.h"
#include "core/os/thread.h"
#include "core/os/thread_safe.h"
+#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
+#include "core/templates/thread_work_pool.h"
#include "scene/main/node.h"
+
class FileAccess;
struct EditorProgressBG;
@@ -99,6 +102,8 @@ public:
int find_file_index(const String &p_file) const;
int find_dir_index(const String &p_dir) const;
+ void force_update();
+
EditorFileSystemDirectory();
~EditorFileSystemDirectory();
};
@@ -202,7 +207,7 @@ class EditorFileSystem : public Node {
void _update_extensions();
- void _reimport_file(const String &p_file);
+ void _reimport_file(const String &p_file, const Map<StringName, Variant> *p_custom_options = nullptr, const String &p_custom_importer = String());
Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);
bool _test_for_reimport(const String &p_path, bool p_only_imported_files);
@@ -213,14 +218,16 @@ class EditorFileSystem : public Node {
struct ImportFile {
String path;
+ String importer;
+ bool threaded = false;
int order = 0;
bool operator<(const ImportFile &p_if) const {
- return order < p_if.order;
+ return order == p_if.order ? (importer < p_if.importer) : (order < p_if.order);
}
};
void _scan_script_classes(EditorFileSystemDirectory *p_dir);
- volatile bool update_script_classes_queued;
+ SafeFlag update_script_classes_queued;
void _queue_update_script_classes();
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
@@ -235,6 +242,16 @@ class EditorFileSystem : public Node {
Set<String> group_file_cache;
+ ThreadWorkPool import_threads;
+
+ struct ImportThreadData {
+ const ImportFile *reimport_files;
+ int reimport_from;
+ int max_index = 0;
+ };
+
+ void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -256,11 +273,15 @@ public:
void reimport_files(const Vector<String> &p_files);
+ void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const Map<StringName, Variant> &p_custom_params);
+
void update_script_classes();
bool is_group_file(const String &p_path) const;
void move_group_file(const String &p_path, const String &p_new_path);
+ static bool _should_skip_directory(const String &p_path);
+
EditorFileSystem();
~EditorFileSystem();
};
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index 9f98795e16..97a2c67c26 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -259,13 +259,17 @@ void EditorFolding::_do_object_unfolds(Object *p_object, Set<RES> &resources) {
}
}
}
- }
- if (E->get().type == Variant::OBJECT) {
- RES res = p_object->get(E->get().name);
- if (res.is_valid() && !resources.has(res) && res->get_path() != String() && !res->get_path().is_resource_file()) {
- resources.insert(res);
- _do_object_unfolds(res.ptr(), resources);
+ if (E->get().type == Variant::OBJECT) {
+ RES res = p_object->get(E->get().name);
+ print_line("res: " + String(E->get().name) + " valid " + itos(res.is_valid()));
+ if (res.is_valid()) {
+ print_line("path " + res->get_path());
+ }
+ if (res.is_valid() && !resources.has(res) && res->get_path() != String() && !res->get_path().is_resource_file()) {
+ resources.insert(res);
+ _do_object_unfolds(res.ptr(), resources);
+ }
}
}
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 283713cd3c..6039f64b7c 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1801,7 +1801,7 @@ void FindBar::popup_search() {
if (!search_text->get_text().is_empty()) {
search_text->select_all();
- search_text->set_cursor_position(search_text->get_text().length());
+ search_text->set_caret_column(search_text->get_text().length());
if (grabbed_focus) {
_search();
}
@@ -1908,6 +1908,8 @@ void FindBar::_hide_bar() {
}
void FindBar::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
if (k->is_pressed() && (rich_text_label->has_focus() || is_a_parent_of(get_focus_owner()))) {
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index a1ff87fe2e..23226ffa9b 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -123,7 +123,7 @@ void EditorHelpSearch::_notification(int p_what) {
if (search->work()) {
// Search done.
- // Only point to the perfect match if it's a new search, and not just reopening a old one.
+ // Only point to the match if it's a new search, and not just reopening a old one.
if (!old_search) {
results_tree->ensure_cursor_is_visible();
} else {
@@ -310,6 +310,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
iterator_doc = EditorHelp::get_doc_data()->class_list.front();
matches.clear();
matched_item = nullptr;
+ match_highest_score = 0;
return true;
}
@@ -460,16 +461,20 @@ bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String
}
void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text) {
- if (!matched_item) {
- if (search_flags & SEARCH_CASE_SENSITIVE) {
- if (p_text.casecmp_to(term) == 0) {
- matched_item = p_item;
- }
- } else {
- if (p_text.nocasecmp_to(term) == 0) {
- matched_item = p_item;
- }
- }
+ float inverse_length = 1.f / float(p_text.length());
+
+ // Favor types where search term is a substring close to the start of the type.
+ float w = 0.5f;
+ int pos = p_text.findn(term);
+ float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w);
+
+ // Favor shorter items: they resemble the search term more.
+ w = 0.1f;
+ score *= (1 - w) + w * (term.length() * inverse_length);
+
+ if (match_highest_score == 0 || score > match_highest_score) {
+ matched_item = p_item;
+ match_highest_score = score;
}
}
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 0e236d523d..350a02315f 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -124,6 +124,7 @@ class EditorHelpSearch::Runner : public Reference {
TreeItem *root_item = nullptr;
Map<String, TreeItem *> class_items;
TreeItem *matched_item = nullptr;
+ float match_highest_score = 0;
bool _is_class_disabled_by_feature_profile(const StringName &p_class);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index ac36b7e762..738b2f9f82 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -81,7 +81,7 @@ Size2 EditorProperty::get_minimum_size() const {
}
if (bottom_editor != nullptr && bottom_editor->is_visible()) {
- ms.height += get_theme_constant("vseparation", "Tree");
+ ms.height += get_theme_constant("vseparation");
Size2 bems = bottom_editor->get_combined_minimum_size();
//bems.width += get_constant("item_margin", "Tree");
ms.height += bems.height;
@@ -95,6 +95,7 @@ void EditorProperty::emit_changed(const StringName &p_property, const Variant &p
Variant args[4] = { p_property, p_value, p_field, p_changing };
const Variant *argptrs[4] = { &args[0], &args[1], &args[2], &args[3] };
+ cache[p_property] = p_value;
emit_signal("property_changed", (const Variant **)argptrs, 4);
}
@@ -148,7 +149,7 @@ void EditorProperty::_notification(int p_what) {
if (bottom_editor) {
int m = 0; //get_constant("item_margin", "Tree");
- bottom_rect = Rect2(m, rect.size.height + get_theme_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height);
+ bottom_rect = Rect2(m, rect.size.height + get_theme_constant("vseparation"), size.width - m, bottom_editor->get_combined_minimum_size().height);
}
if (keying) {
@@ -225,11 +226,15 @@ void EditorProperty::_notification(int p_what) {
size.height = label_reference->get_size().height;
}
+ Ref<StyleBox> sb;
if (selected) {
- Ref<StyleBox> sb = get_theme_stylebox("selected", "Tree");
- draw_style_box(sb, Rect2(Vector2(), size));
+ sb = get_theme_stylebox("bg_selected");
+ } else {
+ sb = get_theme_stylebox("bg");
}
+ draw_style_box(sb, Rect2(Vector2(), size));
+
if (draw_top_bg && right_child_rect != Rect2()) {
draw_rect(right_child_rect, dark_color);
}
@@ -239,15 +244,15 @@ void EditorProperty::_notification(int p_what) {
Color color;
if (draw_red) {
- color = get_theme_color("error_color", "Editor");
+ color = get_theme_color("error_color");
} else {
- color = get_theme_color("property_color", "Editor");
+ color = get_theme_color("property_color");
}
if (label.find(".") != -1) {
color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides
}
- int ofs = 0;
+ int ofs = get_theme_constant("font_offset");
int text_limit = text_size;
if (checkable) {
@@ -677,6 +682,8 @@ bool EditorProperty::is_selected() const {
}
void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (property == StringName()) {
return;
}
@@ -688,7 +695,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
}
- bool button_left = me->get_button_mask() & BUTTON_MASK_LEFT;
+ bool button_left = me->get_button_mask() & MOUSE_BUTTON_MASK_LEFT;
bool new_keying_hover = keying_rect.has_point(mpos) && !button_left;
if (new_keying_hover != keying_hover) {
@@ -717,7 +724,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 mpos = mb->get_position();
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
@@ -805,6 +812,28 @@ void EditorProperty::set_bottom_editor(Control *p_control) {
bottom_editor = p_control;
}
+bool EditorProperty::is_cache_valid() const {
+ if (object) {
+ for (Map<StringName, Variant>::Element *E = cache.front(); E; E = E->next()) {
+ bool valid;
+ Variant value = object->get(E->key(), &valid);
+ if (!valid || value != E->get()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+void EditorProperty::update_cache() {
+ cache.clear();
+ if (object && property != StringName()) {
+ bool valid;
+ Variant value = object->get(property, &valid);
+ if (valid) {
+ cache[property] = value;
+ }
+ }
+}
Variant EditorProperty::get_drag_data(const Point2 &p_point) {
if (property == StringName()) {
return Variant();
@@ -1327,12 +1356,14 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe
}
void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!foldable) {
return;
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Ref<Font> font = get_theme_font("font", "Tree");
int font_size = get_theme_font_size("font_size", "Tree");
if (mb->get_position().y > font->get_height(font_size)) { //clicked outside
@@ -1524,6 +1555,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit
ep->update_property();
ep->update_reload_status();
ep->set_deletable(deletable_properties);
+ ep->update_cache();
}
}
ped->added_editors.clear();
@@ -1661,7 +1693,7 @@ void EditorInspector::update_tree() {
bool valid = true;
//if no properties in category, skip
while (N) {
- if (N->get().usage & PROPERTY_USAGE_EDITOR) {
+ if (N->get().usage & PROPERTY_USAGE_EDITOR && (!restrict_to_basic || (N->get().usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
break;
}
if (N->get().usage & PROPERTY_USAGE_CATEGORY) {
@@ -1729,10 +1761,14 @@ void EditorInspector::update_tree() {
continue;
- } else if (!(p.usage & PROPERTY_USAGE_EDITOR) || _is_property_disabled_by_feature_profile(p.name)) {
+ } else if (!(p.usage & PROPERTY_USAGE_EDITOR) || _is_property_disabled_by_feature_profile(p.name) || (restrict_to_basic && !(p.usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
continue;
}
+ if (p.name == "script") {
+ category_vbox = nullptr; // script should go into its own category
+ }
+
if (p.usage & PROPERTY_USAGE_HIGH_END_GFX && RS::get_singleton()->is_low_end()) {
continue; //do not show this property in low end gfx
}
@@ -1982,6 +2018,7 @@ void EditorInspector::update_tree() {
}
ep->update_property();
ep->update_reload_status();
+ ep->update_cache();
if (current_selected && ep->property == current_selected) {
ep->select(current_focusable);
@@ -2012,6 +2049,7 @@ void EditorInspector::update_property(const String &p_prop) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_prop].front(); E; E = E->next()) {
E->get()->update_property();
E->get()->update_reload_status();
+ E->get()->update_cache();
}
}
@@ -2027,13 +2065,6 @@ void EditorInspector::_clear() {
restart_request_props.clear();
}
-void EditorInspector::refresh() {
- if (refresh_countdown > 0 || changing) {
- return;
- }
- refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval");
-}
-
Object *EditorInspector::get_edited_object() {
return object;
}
@@ -2044,7 +2075,7 @@ void EditorInspector::edit(Object *p_object) {
}
if (object) {
_clear();
- object->remove_change_receptor(this);
+ object->disconnect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
}
object = p_object;
@@ -2054,7 +2085,7 @@ void EditorInspector::edit(Object *p_object) {
if (scroll_cache.has(object->get_instance_id())) { //if exists, set something else
update_scroll_request = scroll_cache[object->get_instance_id()]; //done this way because wait until full size is accommodated
}
- object->add_change_receptor(this);
+ object->connect("property_list_changed", callable_mp(this, &EditorInspector::_changed_callback));
update_tree();
}
}
@@ -2161,17 +2192,30 @@ void EditorInspector::set_use_wide_editors(bool p_enable) {
wide_editors = p_enable;
}
+void EditorInspector::_update_inspector_bg() {
+ if (sub_inspector) {
+ int count_subinspectors = 0;
+ Node *n = get_parent();
+ while (n) {
+ EditorInspector *ei = Object::cast_to<EditorInspector>(n);
+ if (ei && ei->sub_inspector) {
+ count_subinspectors++;
+ }
+ n = n->get_parent();
+ }
+ count_subinspectors = MIN(15, count_subinspectors);
+ add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), "Editor"));
+ } else {
+ add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ }
+}
void EditorInspector::set_sub_inspector(bool p_enable) {
sub_inspector = p_enable;
if (!is_inside_tree()) {
return;
}
- if (sub_inspector) {
- add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
- } else {
- add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
- }
+ _update_inspector_bg();
}
void EditorInspector::set_use_deletable_properties(bool p_enabled) {
@@ -2351,6 +2395,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
E->get()->update_property();
E->get()->update_reload_status();
+ E->get()->update_cache();
}
}
@@ -2394,13 +2439,12 @@ void EditorInspector::_node_removed(Node *p_node) {
void EditorInspector::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
+ set_process(is_visible_in_tree());
+ _update_inspector_bg();
}
if (p_what == NOTIFICATION_ENTER_TREE) {
- if (sub_inspector) {
- add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
- } else {
- add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ if (!sub_inspector) {
get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
}
}
@@ -2414,6 +2458,10 @@ void EditorInspector::_notification(int p_what) {
edit(nullptr);
}
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ set_process(is_visible_in_tree());
+ }
+
if (p_what == NOTIFICATION_PROCESS) {
if (update_scroll_request >= 0) {
get_v_scrollbar()->call_deferred("set_value", update_scroll_request);
@@ -2424,10 +2472,14 @@ void EditorInspector::_notification(int p_what) {
if (refresh_countdown <= 0) {
for (Map<StringName, List<EditorProperty *>>::Element *F = editor_property_map.front(); F; F = F->next()) {
for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
- E->get()->update_property();
- E->get()->update_reload_status();
+ if (!E->get()->is_cache_valid()) {
+ E->get()->update_property();
+ E->get()->update_reload_status();
+ E->get()->update_cache();
+ }
}
}
+ refresh_countdown = float(EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"));
}
}
@@ -2445,6 +2497,7 @@ void EditorInspector::_notification(int p_what) {
for (List<EditorProperty *>::Element *E = editor_property_map[prop].front(); E; E = E->next()) {
E->get()->update_property();
E->get()->update_reload_status();
+ E->get()->update_cache();
}
}
pending.erase(pending.front());
@@ -2455,19 +2508,17 @@ void EditorInspector::_notification(int p_what) {
}
if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- if (sub_inspector) {
- add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
- } else if (is_inside_tree()) {
- add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
- }
+ _update_inspector_bg();
update_tree();
}
}
-void EditorInspector::_changed_callback(Object *p_changed, const char *p_prop) {
- //this is called when property change is notified via _change_notify()
- _edit_request_change(p_changed, p_prop);
+void EditorInspector::_changed_callback() {
+ //this is called when property change is notified via notify_property_list_changed()
+ if (object != nullptr) {
+ _edit_request_change(object, String());
+ }
}
void EditorInspector::_vscroll_changed(double p_offset) {
@@ -2519,9 +2570,9 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li
}
// Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
- List<PropertyInfo>::Element *script_variables = NULL;
- List<PropertyInfo>::Element *bottom = NULL;
- List<PropertyInfo>::Element *insert_here = NULL;
+ List<PropertyInfo>::Element *script_variables = nullptr;
+ List<PropertyInfo>::Element *bottom = nullptr;
+ List<PropertyInfo>::Element *insert_here = nullptr;
for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
PropertyInfo &pi = E->get();
if (pi.name != "Script Variables") {
@@ -2577,11 +2628,14 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li
r_list.erase(bottom);
}
+void EditorInspector::set_restrict_to_basic_settings(bool p_restrict) {
+ restrict_to_basic = p_restrict;
+ update_tree();
+}
+
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
- ClassDB::bind_method("refresh", &EditorInspector::refresh);
-
ADD_SIGNAL(MethodInfo("property_selected", PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING, "property")));
@@ -2613,16 +2667,21 @@ EditorInspector::EditorInspector() {
use_folding = false;
update_all_pending = false;
update_tree_pending = false;
- refresh_countdown = 0;
read_only = false;
search_box = nullptr;
keying = false;
_prop_edited = "property_edited";
- set_process(true);
+ set_process(false);
property_focusable = -1;
sub_inspector = false;
deletable_properties = false;
get_v_scrollbar()->connect("value_changed", callable_mp(this, &EditorInspector::_vscroll_changed));
update_scroll_request = -1;
+ if (EditorSettings::get_singleton()) {
+ refresh_countdown = float(EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"));
+ } else {
+ //used when class is created by the docgen to dump default values of everything bindable, editorsettings may not be created
+ refresh_countdown = 0.33;
+ }
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 81a22d4ff1..18250780be 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -98,6 +98,8 @@ private:
mutable String tooltip_text;
+ Map<StringName, Variant> cache;
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -152,6 +154,8 @@ public:
virtual void collapse_all_folding();
virtual Variant get_drag_data(const Point2 &p_point) override;
+ virtual void update_cache();
+ virtual bool is_cache_valid() const;
void set_selectable(bool p_selectable);
bool is_selectable() const;
@@ -309,6 +313,8 @@ class EditorInspector : public ScrollContainer {
String property_prefix; //used for sectioned inspector
String object_class;
+ bool restrict_to_basic = false;
+
void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field);
void _property_changed(const String &p_path, const Variant &p_value, const String &p_name = "", bool p_changing = false);
@@ -326,7 +332,7 @@ class EditorInspector : public ScrollContainer {
void _node_removed(Node *p_node);
- void _changed_callback(Object *p_changed, const char *p_prop) override;
+ void _changed_callback();
void _edit_request_change(Object *p_object, const String &p_prop);
void _filter_changed(const String &p_text);
@@ -339,6 +345,8 @@ class EditorInspector : public ScrollContainer {
bool _is_property_disabled_by_feature_profile(const StringName &p_property);
+ void _update_inspector_bg();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -356,9 +364,6 @@ public:
void update_tree();
void update_property(const String &p_prop);
-
- void refresh();
-
void edit(Object *p_object);
Object *get_edited_object();
@@ -393,9 +398,12 @@ public:
void set_use_wide_editors(bool p_enable);
void set_sub_inspector(bool p_enable);
+ bool is_sub_inspector() const { return sub_inspector; }
void set_use_deletable_properties(bool p_enabled);
+ void set_restrict_to_basic_settings(bool p_restrict);
+
EditorInspector();
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 12d0d1db08..6137617564 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -92,7 +92,6 @@
#include "editor/filesystem_dock.h"
#include "editor/import/editor_import_collada.h"
#include "editor/import/resource_importer_bitmask.h"
-#include "editor/import/resource_importer_csv.h"
#include "editor/import/resource_importer_csv_translation.h"
#include "editor/import/resource_importer_image.h"
#include "editor/import/resource_importer_layered_texture.h"
@@ -102,6 +101,7 @@
#include "editor/import/resource_importer_texture.h"
#include "editor/import/resource_importer_texture_atlas.h"
#include "editor/import/resource_importer_wav.h"
+#include "editor/import/scene_import_settings.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "editor/import_dock.h"
#include "editor/multi_node_edit.h"
@@ -143,6 +143,7 @@
#include "editor/plugins/multimesh_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "editor/plugins/occluder_instance_3d_editor_plugin.h"
#include "editor/plugins/ot_features_plugin.h"
#include "editor/plugins/packed_scene_translation_parser_plugin.h"
#include "editor/plugins/path_2d_editor_plugin.h"
@@ -390,6 +391,8 @@ void EditorNode::_update_title() {
}
void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
EditorPlugin *old_editor = editor_plugin_screen;
@@ -430,6 +433,74 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
}
}
+void EditorNode::_update_from_settings() {
+ int current_filter = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_filter");
+ if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
+ Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
+ scene_root->set_default_canvas_item_texture_filter(tf);
+ }
+ int current_repeat = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_repeat");
+ if (current_repeat != scene_root->get_default_canvas_item_texture_repeat()) {
+ Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
+ scene_root->set_default_canvas_item_texture_repeat(tr);
+ }
+
+ RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")));
+ RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
+ RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality")));
+ bool dof_jitter = GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter");
+ RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
+ RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
+ RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"));
+ bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
+ RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
+ bool glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality");
+ RS::get_singleton()->environment_glow_set_use_high_quality(glow_high_quality);
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
+ RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
+ RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
+ RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
+ float sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+ float sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
+ RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
+
+ uint32_t directional_shadow_size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
+ uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
+ RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits);
+
+ RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/shadows/soft_shadow_quality")));
+ RS::get_singleton()->shadows_quality_set(shadows_quality);
+ RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_quality")));
+ RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality);
+ float probe_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
+ RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
+ RS::EnvironmentSDFGIFramesToConverge frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(int(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")));
+ RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge);
+ RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")));
+ RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count);
+ RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")));
+ RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
+ RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
+ RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")));
+ RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/2d/shadow_atlas/size"));
+
+ bool use_half_res_gi = GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);
+ RS::get_singleton()->gi_set_use_half_resolution(use_half_res_gi);
+
+ bool snap_2d_transforms = GLOBAL_GET("rendering/2d/snap/snap_2d_transforms_to_pixel");
+ scene_root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
+ bool snap_2d_vertices = GLOBAL_GET("rendering/2d/snap/snap_2d_vertices_to_pixel");
+ scene_root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_GET("rendering/2d/sdf/oversize")));
+ scene_root->set_sdf_oversize(sdf_oversize);
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/2d/sdf/scale")));
+ scene_root->set_sdf_scale(sdf_scale);
+
+ float lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
+ scene_root->set_lod_threshold(lod_threshold);
+}
+
void EditorNode::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PROCESS: {
@@ -468,75 +539,13 @@ void EditorNode::_notification(int p_what) {
editor_selection->update();
- { //TODO should only happen on settings changed
- int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
- if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
- Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
- scene_root->set_default_canvas_item_texture_filter(tf);
- }
- int current_repeat = GLOBAL_GET("rendering/canvas_textures/default_texture_repeat");
- if (current_repeat != scene_root->get_default_canvas_item_texture_repeat()) {
- Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
- scene_root->set_default_canvas_item_texture_repeat(tr);
- }
+ ResourceImporterTexture::get_singleton()->update_imports();
- RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")));
- RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
- RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality")));
- bool dof_jitter = GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter");
- RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
- RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"), GLOBAL_GET("rendering/quality/ssao/adaptive_target"), GLOBAL_GET("rendering/quality/ssao/blur_passes"), GLOBAL_GET("rendering/quality/ssao/fadeout_from"), GLOBAL_GET("rendering/quality/ssao/fadeout_to"));
- RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit"));
- bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
- RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
- bool glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality");
- RS::get_singleton()->environment_glow_set_use_high_quality(glow_high_quality);
- RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
- RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
- RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
- RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
- float sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
- float sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale");
- RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
-
- uint32_t directional_shadow_size = GLOBAL_GET("rendering/quality/directional_shadow/size");
- uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/quality/directional_shadow/16_bits");
- RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits);
-
- RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")));
- RS::get_singleton()->shadows_quality_set(shadows_quality);
- RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")));
- RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality);
- float probe_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed");
- RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
- RS::EnvironmentSDFGIFramesToConverge frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(int(GLOBAL_GET("rendering/sdfgi/frames_to_converge")));
- RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge);
- RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/sdfgi/probe_ray_count")));
- RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count);
- RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/quality/gi_probes/quality")));
- RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
- RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth"));
- RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/volumetric_fog/use_filter")));
- RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/quality/2d_shadow_atlas/size"));
-
- bool use_half_res_gi = GLOBAL_DEF("rendering/quality/gi/use_half_resolution", false);
- RS::get_singleton()->gi_set_use_half_resolution(use_half_res_gi);
-
- bool snap_2d_transforms = GLOBAL_GET("rendering/quality/2d/snap_2d_transforms_to_pixel");
- scene_root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
- bool snap_2d_vertices = GLOBAL_GET("rendering/quality/2d/snap_2d_vertices_to_pixel");
- scene_root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
-
- Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_GET("rendering/quality/2d_sdf/oversize")));
- scene_root->set_sdf_oversize(sdf_oversize);
- Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/quality/2d_sdf/scale")));
- scene_root->set_sdf_scale(sdf_scale);
-
- float lod_threshold = GLOBAL_GET("rendering/quality/mesh_lod/threshold_pixels");
- scene_root->set_lod_threshold(lod_threshold);
+ if (settings_changed) {
+ _update_from_settings();
+ settings_changed = false;
+ emit_signal("project_settings_changed");
}
-
- ResourceImporterTexture::get_singleton()->update_imports();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -586,6 +595,9 @@ void EditorNode::_notification(int p_what) {
_editor_select(EDITOR_3D);
}
+ // Save the project after opening to mark it as last modified.
+ ProjectSettings::get_singleton()->save();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -594,6 +606,7 @@ void EditorNode::_notification(int p_what) {
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
EditorFileSystem::get_singleton()->scan_changes();
+ _scan_external_changes();
} break;
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
@@ -782,17 +795,27 @@ void EditorNode::_fs_changed() {
}
preset.unref();
}
+
if (preset.is_null()) {
- export_error = vformat(
- "Invalid export preset name: %s. Make sure `export_presets.cfg` is present in the current directory.",
- preset_name);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->file_exists("res://export_presets.cfg")) {
+ export_error = vformat(
+ "Invalid export preset name: %s.\nThe following presets were detected in this project's `export_presets.cfg`:\n\n",
+ preset_name);
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); ++i) {
+ // Write the preset name between double quotes since it needs to be written between quotes on the command line if it contains spaces.
+ export_error += vformat(" \"%s\"\n", EditorExport::get_singleton()->get_export_preset(i)->get_name());
+ }
+ } else {
+ export_error = "This project doesn't have an `export_presets.cfg` file at its root.\nCreate an export preset from the \"Project > Export\" dialog and try again.";
+ }
} else {
Ref<EditorExportPlatform> platform = preset->get_platform();
const String export_path = export_defer.path.is_empty() ? preset->get_export_path() : export_defer.path;
if (export_path.is_empty()) {
- export_error = vformat("Export preset '%s' doesn't have a default export path, and none was specified.", preset_name);
+ export_error = vformat("Export preset \"%s\" doesn't have a default export path, and none was specified.", preset_name);
} else if (platform.is_null()) {
- export_error = vformat("Export preset '%s' doesn't have a matching platform.", preset_name);
+ export_error = vformat("Export preset \"%s\" doesn't have a matching platform.", preset_name);
} else {
Error err = OK;
if (export_defer.pack_only) { // Only export .pck or .zip data pack.
@@ -805,7 +828,7 @@ void EditorNode::_fs_changed() {
String config_error;
bool missing_templates;
if (!platform->can_export(preset, config_error, missing_templates)) {
- ERR_PRINT(vformat("Cannot export project with preset '%s' due to configuration errors:\n%s", preset_name, config_error));
+ ERR_PRINT(vformat("Cannot export project with preset \"%s\" due to configuration errors:\n%s", preset_name, config_error));
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
err = platform->export_project(preset, export_defer.debug, export_path);
@@ -815,13 +838,13 @@ void EditorNode::_fs_changed() {
case OK:
break;
case ERR_FILE_NOT_FOUND:
- export_error = vformat("Project export failed for preset '%s', the export template appears to be missing.", preset_name);
+ export_error = vformat("Project export failed for preset \"%s\". The export template appears to be missing.", preset_name);
break;
case ERR_FILE_BAD_PATH:
- export_error = vformat("Project export failed for preset '%s', the target path '%s' appears to be invalid.", preset_name, export_path);
+ export_error = vformat("Project export failed for preset \"%s\". The target path \"%s\" appears to be invalid.", preset_name, export_path);
break;
default:
- export_error = vformat("Project export failed with error code %d for preset '%s'.", (int)err, preset_name);
+ export_error = vformat("Project export failed with error code %d for preset \"%s\".", (int)err, preset_name);
break;
}
}
@@ -886,6 +909,83 @@ void EditorNode::_sources_changed(bool p_exist) {
}
}
+void EditorNode::_scan_external_changes() {
+ disk_changed_list->clear();
+ TreeItem *r = disk_changed_list->create_item();
+ disk_changed_list->set_hide_root(true);
+ bool need_reload = false;
+
+ // Check if any edited scene has changed.
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (editor_data.get_scene_path(i) == "" || !da->file_exists(editor_data.get_scene_path(i))) {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, editor_data.get_scene_path(i).get_file());
+ need_reload = true;
+ }
+ }
+
+ String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+ if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, "project.godot");
+ need_reload = true;
+ }
+
+ if (need_reload) {
+ disk_changed->call_deferred("popup_centered_ratio", 0.5);
+ }
+}
+
+void EditorNode::_resave_scenes(String p_str) {
+ save_all_scenes();
+ ProjectSettings::get_singleton()->save();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_modified_scenes() {
+ int current_idx = editor_data.get_edited_scene();
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) == "") {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ String filename = editor_data.get_scene_path(i);
+ editor_data.set_edited_scene(i);
+ _remove_edited_scene(false);
+
+ Error err = load_scene(filename, false, false, true, false, true);
+ if (err != OK) {
+ ERR_PRINT(vformat("Failed to load scene: %s", filename));
+ }
+ editor_data.move_edited_scene_to_index(i);
+ }
+ }
+
+ get_undo_redo()->clear_history(false);
+ set_current_scene(current_idx);
+ _update_scene_tabs();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_project_settings() {
+ ProjectSettings::get_singleton()->setup(ProjectSettings::get_singleton()->get_resource_path(), String(), true);
+ settings_changed = true;
+}
+
void EditorNode::_vp_resized() {
}
@@ -927,7 +1027,7 @@ Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_d
dependency_errors.clear();
Error err;
- RES res = ResourceLoader::load(p_resource, "", false, &err);
+ RES res = ResourceLoader::load(p_resource, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
ERR_FAIL_COND_V(!res.is_valid(), ERR_CANT_OPEN);
if (!p_ignore_broken_deps && dependency_errors.has(p_resource)) {
@@ -1005,13 +1105,23 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->clear_filters();
List<String> preferred;
- for (int i = 0; i < extensions.size(); i++) {
- if (p_resource->is_class("Script") && (extensions[i] == "tres" || extensions[i] == "res" || extensions[i] == "xml")) {
+ for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
+ if (p_resource->is_class("Script") && (E->get() == "tres" || E->get() == "res")) {
//this serves no purpose and confused people
continue;
}
- file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- preferred.push_back(extensions[i]);
+ file->add_filter("*." + E->get() + " ; " + E->get().to_upper());
+ preferred.push_back(E->get());
+ }
+ // Lowest priority extension
+ List<String>::Element *res_element = preferred.find("res");
+ if (res_element) {
+ preferred.move_to_back(res_element);
+ }
+ // Highest priority extension
+ List<String>::Element *tres_element = preferred.find("tres");
+ if (tres_element) {
+ preferred.move_to_front(tres_element);
}
if (p_at_path != String()) {
@@ -1280,18 +1390,18 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
// which would result in an invalid texture.
if (c3d == 0 && c2d == 0) {
img.instance();
- img->create(1, 1, 0, Image::FORMAT_RGB8);
+ img->create(1, 1, false, Image::FORMAT_RGB8);
} else if (c3d < c2d) {
Ref<ViewportTexture> viewport_texture = scene_root->get_texture();
if (viewport_texture->get_width() > 0 && viewport_texture->get_height() > 0) {
- img = viewport_texture->get_data();
+ img = viewport_texture->get_image();
}
} else {
// The 3D editor may be disabled as a feature, but scenes can still be opened.
// This check prevents the preview from regenerating in case those scenes are then saved.
Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
if (profile.is_valid() && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
- img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data();
+ img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_image();
}
}
@@ -1511,6 +1621,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
} else {
editor_data.set_edited_scene_version(0, idx);
}
+ editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file));
editor_folding.save_scene_folding(scene, p_file);
@@ -1714,7 +1825,7 @@ void EditorNode::_dialog_action(String p_file) {
ObjectID current = editor_history.get_current();
Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!current_obj);
- current_obj->_change_notify();
+ current_obj->notify_property_list_changed();
} break;
case SETTINGS_LAYOUT_SAVE: {
if (p_file.is_empty()) {
@@ -2176,7 +2287,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
List<String> breakpoints;
editor_data.get_editor_breakpoints(&breakpoints);
- args = ProjectSettings::get_singleton()->get("editor/main_run_args");
+ args = ProjectSettings::get_singleton()->get("editor/run/main_run_args");
skip_breakpoints = EditorDebuggerNode::get_singleton()->is_skip_breakpoints();
EditorDebuggerNode::get_singleton()->start();
@@ -2302,11 +2413,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
_scene_tab_changed(tab_closing);
if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
- String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
- save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
- save_confirmation->popup_centered();
- break;
+ Node *scene_root = editor_data.get_edited_scene_root(tab_closing);
+ if (scene_root) {
+ String scene_filename = scene_root->get_filename();
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
+ save_confirmation->popup_centered();
+ break;
+ }
}
} else if (p_option == FILE_CLOSE) {
tab_closing = editor_data.get_edited_scene();
@@ -2436,16 +2550,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
- case FILE_IMPORT_SUBSCENE: {
- if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a selected node."), TTR("OK"));
- break;
- }
-
- scene_tree_dock->import_subscene();
-
- } break;
-
case FILE_EXTERNAL_OPEN_SCENE: {
if (unsaved_cache && !p_confirmed) {
confirmation->get_ok_button()->set_text(TTR("Open"));
@@ -2715,7 +2819,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
- ProjectSettings::get_singleton()->set("rendering/quality/driver/driver_name", video_driver_request);
+ ProjectSettings::get_singleton()->set("rendering/driver/driver_name", video_driver_request);
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -2744,7 +2848,7 @@ void EditorNode::_save_screenshot(NodePath p_path) {
ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport.");
Ref<ViewportTexture> texture = viewport->get_texture();
ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture.");
- Ref<Image> img = texture->get_data();
+ Ref<Image> img = texture->get_image();
ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
@@ -3326,7 +3430,7 @@ int EditorNode::new_scene() {
return idx;
}
-Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) {
+Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported, bool p_silent_change_tab) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
return OK;
@@ -3366,14 +3470,16 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!editor_data.get_edited_scene_root() && editor_data.get_edited_scene_count() == 2) {
_remove_edited_scene();
- } else {
+ } else if (!p_silent_change_tab) {
_scene_tab_changed(idx);
+ } else {
+ set_current_scene(idx);
}
dependency_errors.clear();
Error err;
- Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", true, &err);
+ Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
if (!sdata.is_valid()) {
_dialog_display_load_error(lpath, err);
opening_prev = false;
@@ -4745,15 +4851,15 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
if (mb.is_valid()) {
if (scene_tabs->get_hovered_tab() >= 0) {
- if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed()) {
_scene_tab_closed(scene_tabs->get_hovered_tab());
}
} else {
- if ((mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
_menu_option_confirm(FILE_NEW_SCENE, true);
}
}
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
// context menu
scene_tabs_context_menu->clear();
scene_tabs_context_menu->set_size(Size2(1, 1));
@@ -5015,8 +5121,8 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
{
//todo make proper previews
- Ref<ImageTexture> pic = gui_base->get_theme_icon("FileBigThumb", "EditorIcons");
- Ref<Image> img = pic->get_data();
+ Ref<ImageTexture> texture = gui_base->get_theme_icon("FileBigThumb", "EditorIcons");
+ Ref<Image> img = texture->get_image();
img = img->duplicate();
img->resize(48, 48); //meh
Ref<ImageTexture> resized_pic = Ref<ImageTexture>(memnew(ImageTexture));
@@ -5195,6 +5301,8 @@ void EditorNode::_file_access_close_error_notify(const String &p_str) {
}
void EditorNode::reload_scene(const String &p_path) {
+ /*
+ * No longer necesary since scenes now reset and reload their internal resource if needed.
//first of all, reload internal textures, materials, meshes, etc. as they might have changed on disk
List<Ref<Resource>> cached;
@@ -5212,6 +5320,8 @@ void EditorNode::reload_scene(const String &p_path) {
to_clear.pop_front();
}
+ */
+
int scene_idx = -1;
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
if (editor_data.get_scene_path(i) == p_path) {
@@ -5455,6 +5565,7 @@ void EditorNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("request_help_search"));
ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "args")));
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
+ ADD_SIGNAL(MethodInfo("project_settings_changed"));
}
static Node *_resource_get_edited_scene() {
@@ -5474,7 +5585,8 @@ static void _execute_thread(void *p_ud) {
eta->exitcode = err;
}
- eta->done = true;
+ eta->done.set();
+ ;
}
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
@@ -5488,13 +5600,12 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
eta.path = p_path;
eta.args = p_arguments;
eta.exitcode = 255;
- eta.done = false;
int prev_len = 0;
eta.execute_output_thread.start(_execute_thread, &eta);
- while (!eta.done) {
+ while (!eta.done.is_set()) {
{
MutexLock lock(eta.execute_output_mutex);
if (prev_len != eta.output.length()) {
@@ -5522,6 +5633,10 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
return eta.exitcode;
}
+void EditorNode::notify_settings_changed() {
+ settings_changed = true;
+}
+
EditorNode::EditorNode() {
Input::get_singleton()->set_use_accumulated_input(true);
Resource::_get_local_scene_func = _resource_get_edited_scene;
@@ -5592,6 +5707,10 @@ EditorNode::EditorNode() {
if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
// hiDPI display.
scale = 2.0;
+ } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
+ // Likely a hiDPI display, but we aren't certain due to the returned DPI.
+ // Use an intermediate scale to handle this situation.
+ scale = 1.5;
} else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
// Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
// Icons won't look great, but this is better than having editor elements overflow from its window.
@@ -5675,10 +5794,6 @@ EditorNode::EditorNode() {
import_csv_translation.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation);
- Ref<ResourceImporterCSV> import_csv;
- import_csv.instance();
- ResourceFormatImporter::get_singleton()->add_importer(import_csv);
-
Ref<ResourceImporterWAV> import_wav;
import_wav.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_wav);
@@ -5750,7 +5865,7 @@ EditorNode::EditorNode() {
register_exporters();
- GLOBAL_DEF("editor/main_run_args", "");
+ GLOBAL_DEF("editor/run/main_run_args", "");
ClassDB::set_class_enabled("RootMotionView", true);
@@ -5775,9 +5890,11 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
- EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "StandardMaterial3D,ORMMaterial3D,Script,MeshLibrary,TileSet");
+ EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary,TileSet");
EDITOR_DEF("interface/inspector/default_color_picker_mode", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT));
+ EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle", PROPERTY_USAGE_DEFAULT));
EDITOR_DEF("run/auto_save/save_before_running", true);
theme_base = memnew(Control);
@@ -6076,6 +6193,9 @@ EditorNode::EditorNode() {
project_settings = memnew(ProjectSettingsEditor(&editor_data));
gui_base->add_child(project_settings);
+ scene_import_settings = memnew(SceneImportSettings);
+ gui_base->add_child(scene_import_settings);
+
export_template_manager = memnew(ExportTemplateManager);
gui_base->add_child(export_template_manager);
@@ -6126,8 +6246,8 @@ EditorNode::EditorNode() {
pm_export->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true);
- p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_Z), EDIT_REDO, true);
+ p->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
+ p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
@@ -6263,7 +6383,11 @@ EditorNode::EditorNode() {
p = help_menu->get_popup();
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search")), HELP_SEARCH);
+#ifdef OSX_ENABLED
+ p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_ALT | KEY_SPACE), HELP_SEARCH);
+#else
+ p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F1), HELP_SEARCH);
+#endif
p->add_separator();
p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
@@ -6360,15 +6484,15 @@ EditorNode::EditorNode() {
video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("bold_size", "EditorFonts"));
- // TODO re-enable when GLES2 is ported
- video_driver->set_disabled(true);
+ // TODO: Show again when OpenGL is ported.
+ video_driver->set_visible(false);
right_menu_hb->add_child(video_driver);
#ifndef _MSC_VER
#warning needs to be reimplemented
#endif
#if 0
- String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/driver/driver_name"].hint_string;
+ String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/driver/driver_name"].hint_string;
String current_video_driver = OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
video_driver_current = 0;
for (int i = 0; i < video_drivers.get_slice_count(","); i++) {
@@ -6601,6 +6725,30 @@ EditorNode::EditorNode() {
//plugin stuff
add_editor_plugin(memnew(DebuggerEditorPlugin(this, debug_menu)));
+
+ disk_changed = memnew(ConfirmationDialog);
+ {
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ disk_changed->add_child(vbc);
+
+ Label *dl = memnew(Label);
+ dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?"));
+ vbc->add_child(dl);
+
+ disk_changed_list = memnew(Tree);
+ vbc->add_child(disk_changed_list);
+ disk_changed_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_modified_scenes));
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_project_settings));
+ disk_changed->get_ok_button()->set_text(TTR("Reload"));
+
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
+ disk_changed->connect("custom_action", callable_mp(this, &EditorNode::_resave_scenes));
+ }
+
+ gui_base->add_child(disk_changed);
+
add_editor_plugin(memnew(AnimationPlayerEditorPlugin(this)));
add_editor_plugin(memnew(CanvasItemEditorPlugin(this)));
add_editor_plugin(memnew(Node3DEditorPlugin(this)));
@@ -6653,6 +6801,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
add_editor_plugin(memnew(GIProbeEditorPlugin(this)));
add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
+ add_editor_plugin(memnew(OccluderInstance3DEditorPlugin(this)));
add_editor_plugin(memnew(Path2DEditorPlugin(this)));
add_editor_plugin(memnew(Path3DEditorPlugin(this)));
add_editor_plugin(memnew(Line2DEditorPlugin(this)));
@@ -6830,14 +6979,12 @@ EditorNode::EditorNode() {
ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_ALT | KEY_2);
ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_ALT | KEY_3);
ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_ALT | KEY_4);
- ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_ALT | KEY_SPACE);
#else
// Use the Ctrl modifier so F2 can be used to rename nodes in the scene tree dock.
ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_CTRL | KEY_F1);
ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_CTRL | KEY_F2);
ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_CTRL | KEY_F3);
ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_CTRL | KEY_F4);
- ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F1);
#endif
ED_SHORTCUT("editor/editor_next", TTR("Open the next Editor"));
ED_SHORTCUT("editor/editor_prev", TTR("Open the previous Editor"));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 356ac0caac..7e16936f5d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -31,6 +31,7 @@
#ifndef EDITOR_NODE_H
#define EDITOR_NODE_H
+#include "core/templates/safe_refcount.h"
#include "editor/editor_data.h"
#include "editor/editor_export.h"
#include "editor/editor_folding.h"
@@ -87,6 +88,7 @@ class Button;
class VSplitContainer;
class Window;
class SubViewport;
+class SceneImportSettings;
class EditorNode : public Node {
GDCLASS(EditorNode, Node);
@@ -111,7 +113,7 @@ public:
Thread execute_output_thread;
Mutex execute_output_mutex;
int exitcode = 0;
- volatile bool done = false;
+ SafeFlag done;
};
private:
@@ -128,7 +130,6 @@ private:
FILE_SAVE_ALL_SCENES,
FILE_SAVE_AND_RUN,
FILE_SHOW_IN_FILESYSTEM,
- FILE_IMPORT_SUBSCENE,
FILE_EXPORT_PROJECT,
FILE_EXPORT_MESH_LIBRARY,
FILE_INSTALL_ANDROID_SOURCE,
@@ -312,6 +313,9 @@ private:
EditorSettingsDialog *settings_config_dialog;
ProjectSettingsEditor *project_settings;
+ bool settings_changed = true; //make it update settings on first frame
+ void _update_from_settings();
+
PopupMenu *vcs_actions_menu;
EditorFileDialog *file;
ExportTemplateManager *export_template_manager;
@@ -407,6 +411,7 @@ private:
EditorResourcePreview *resource_preview;
EditorFolding editor_folding;
+ SceneImportSettings *scene_import_settings;
struct BottomPanelItem {
String name;
Control *control = nullptr;
@@ -422,6 +427,9 @@ private:
Label *version_label;
Button *bottom_panel_raise;
+ Tree *disk_changed_list;
+ ConfirmationDialog *disk_changed;
+
void _bottom_panel_raise_toggled(bool);
EditorInterface *editor_interface;
@@ -641,6 +649,10 @@ private:
static void _resource_loaded(RES p_resource, const String &p_path);
void _resources_changed(const Vector<String> &p_resources);
+ void _scan_external_changes();
+ void _reload_modified_scenes();
+ void _reload_project_settings();
+ void _resave_scenes(String p_str);
void _feature_profile_changed();
bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class);
@@ -709,8 +721,6 @@ public:
void save_resource(const Ref<Resource> &p_resource);
void save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path = String());
- void merge_from_scene() { _menu_option_confirm(FILE_IMPORT_SUBSCENE, false); }
-
void show_about() { _menu_option_confirm(HELP_ABOUT, false); }
static bool has_unsaved_changes() { return singleton->unsaved_cache; }
@@ -741,7 +751,7 @@ public:
void fix_dependencies(const String &p_for_file);
void clear_scene() { _cleanup_scene(); }
int new_scene();
- Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false);
+ Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false, bool p_silent_change_tab = false);
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
bool is_scene_open(const String &p_path);
@@ -840,6 +850,8 @@ public:
void save_scene_list(Vector<String> p_scene_filenames);
void restart_editor();
+ void notify_settings_changed();
+
void dim_editor(bool p_dimming, bool p_force_dim = false);
bool is_editor_dimmed() const;
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 840bae35bf..eabcbacd9a 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -160,6 +160,10 @@ void EditorInterface::edit_resource(const Ref<Resource> &p_resource) {
EditorNode::get_singleton()->edit_resource(p_resource);
}
+void EditorInterface::edit_node(Node *p_node) {
+ EditorNode::get_singleton()->edit_node(p_node);
+}
+
void EditorInterface::open_scene_from_path(const String &scene_path) {
if (EditorNode::get_singleton()->is_changing_scene()) {
return;
@@ -262,6 +266,10 @@ Control *EditorInterface::get_base_control() {
return EditorNode::get_singleton()->get_gui_base();
}
+float EditorInterface::get_editor_scale() const {
+ return EDSCALE;
+}
+
void EditorInterface::set_plugin_enabled(const String &p_plugin, bool p_enabled) {
EditorNode::get_singleton()->set_addon_plugin_enabled(p_plugin, p_enabled, true);
}
@@ -306,7 +314,9 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings);
ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor);
ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control);
+ ClassDB::bind_method(D_METHOD("get_editor_scale"), &EditorInterface::get_editor_scale);
ClassDB::bind_method(D_METHOD("edit_resource", "resource"), &EditorInterface::edit_resource);
+ ClassDB::bind_method(D_METHOD("edit_node", "node"), &EditorInterface::edit_node);
ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorInterface::open_scene_from_path);
ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path);
ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene);
@@ -756,7 +766,6 @@ int find(const PackedStringArray &a, const String &v) {
void EditorPlugin::enable_plugin() {
// Called when the plugin gets enabled in project settings, after it's added to the tree.
// You can implement it to register autoloads.
-
if (get_script_instance() && get_script_instance()->has_method("enable_plugin")) {
get_script_instance()->call("enable_plugin");
}
@@ -819,6 +828,18 @@ void EditorPlugin::remove_debugger_plugin(const Ref<Script> &p_script) {
EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_script);
}
+void EditorPlugin::_editor_project_settings_changed() {
+ emit_signal("project_settings_changed");
+}
+void EditorPlugin::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &EditorPlugin::_editor_project_settings_changed));
+ }
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ EditorNode::get_singleton()->disconnect("project_settings_changed", callable_mp(this, &EditorPlugin::_editor_project_settings_changed));
+ }
+}
+
void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container);
ClassDB::bind_method(D_METHOD("add_control_to_bottom_panel", "control", "title"), &EditorPlugin::add_control_to_bottom_panel);
@@ -890,6 +911,7 @@ void EditorPlugin::_bind_methods() {
ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath")));
ADD_SIGNAL(MethodInfo("main_screen_changed", PropertyInfo(Variant::STRING, "screen_name")));
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+ ADD_SIGNAL(MethodInfo("project_settings_changed"));
BIND_ENUM_CONSTANT(CONTAINER_TOOLBAR);
BIND_ENUM_CONSTANT(CONTAINER_SPATIAL_EDITOR_MENU);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 3b741a2f22..67b163eabf 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -71,6 +71,7 @@ public:
Control *get_editor_main_control();
void edit_resource(const Ref<Resource> &p_resource);
+ void edit_node(Node *p_node);
void open_scene_from_path(const String &scene_path);
void reload_scene_from_path(const String &scene_path);
@@ -100,6 +101,7 @@ public:
FileSystemDock *get_file_system_dock();
Control *get_base_control();
+ float get_editor_scale() const;
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
bool is_plugin_enabled(const String &p_plugin) const;
@@ -130,7 +132,11 @@ class EditorPlugin : public Node {
String last_main_screen_name;
+ void _editor_project_settings_changed();
+
protected:
+ void _notification(int p_what);
+
static void _bind_methods();
UndoRedo &get_undo_redo() { return *undo_redo; }
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 111d2666c3..652deb1804 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -38,7 +38,7 @@
#include "scene/main/window.h"
#include "scene/resources/font.h"
-///////////////////// NULL /////////////////////////
+///////////////////// Nil /////////////////////////
void EditorPropertyNil::update_property() {
}
@@ -621,7 +621,7 @@ public:
const Ref<InputEventMouseButton> mb = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) {
// Toggle the flag.
// We base our choice on the hovered flag, so that it always matches the hovered flag.
if (value & (1 << hovered_index)) {
@@ -649,14 +649,16 @@ public:
Color color = get_theme_color("highlight_color", "Editor");
for (int i = 0; i < 2; i++) {
Point2 ofs(4, vofs);
- if (i == 1)
+ if (i == 1) {
ofs.y += bsize + 1;
+ }
ofs += rect.position;
for (int j = 0; j < 10; j++) {
Point2 o = ofs + Point2(j * (bsize + 1), 0);
- if (j >= 5)
+ if (j >= 5) {
o.x += 1;
+ }
const int idx = i * 10 + j;
const bool on = value & (1 << idx);
@@ -716,12 +718,18 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) {
case LAYER_PHYSICS_2D:
basename = "layer_names/2d_physics";
break;
+ case LAYER_NAVIGATION_2D:
+ basename = "layer_names/2d_navigation";
+ break;
case LAYER_RENDER_3D:
basename = "layer_names/3d_render";
break;
case LAYER_PHYSICS_3D:
basename = "layer_names/3d_physics";
break;
+ case LAYER_NAVIGATION_3D:
+ basename = "layer_names/3d_navigation";
+ break;
}
Vector<String> names;
@@ -921,11 +929,11 @@ EditorPropertyFloat::EditorPropertyFloat() {
void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
- if (mb->is_doubleclick() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_doubleclick() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_setup_spin();
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
preset->set_position(easing_draw->get_screen_transform().xform(mb->get_position()));
preset->popup();
@@ -934,7 +942,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
easing_draw->update();
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
dragging = mb->is_pressed();
// Update to display the correct dragging color
easing_draw->update();
@@ -943,7 +951,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float rel = mm->get_relative().x;
if (rel == 0) {
return;
@@ -2182,6 +2190,9 @@ void EditorPropertyColor::_picker_created() {
} else if (default_color_mode == 2) {
picker->get_picker()->set_raw_mode(true);
}
+
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ picker->get_picker()->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
}
void EditorPropertyColor::_picker_opening() {
@@ -2808,7 +2819,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) {
void EditorPropertyResource::_button_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
_update_menu_items();
Vector2 pos = get_screen_position() + mb->get_position();
//pos = assign->get_global_transform().xform(pos);
@@ -2859,6 +2870,41 @@ void EditorPropertyResource::_fold_other_editors(Object *p_self) {
}
}
+void EditorPropertyResource::_update_property_bg() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ updating_theme = true;
+ if (sub_inspector != nullptr) {
+ int count_subinspectors = 0;
+ Node *n = get_parent();
+ while (n) {
+ EditorInspector *ei = Object::cast_to<EditorInspector>(n);
+ if (ei && ei->is_sub_inspector()) {
+ count_subinspectors++;
+ }
+ n = n->get_parent();
+ }
+ count_subinspectors = MIN(15, count_subinspectors);
+
+ add_theme_color_override("property_color", get_theme_color("sub_inspector_property_color", "Editor"));
+ add_theme_style_override("bg_selected", get_theme_stylebox("sub_inspector_property_bg_selected" + itos(count_subinspectors), "Editor"));
+ add_theme_style_override("bg", get_theme_stylebox("sub_inspector_property_bg" + itos(count_subinspectors), "Editor"));
+
+ add_theme_constant_override("font_offset", get_theme_constant("sub_inspector_font_offset", "Editor"));
+ add_theme_constant_override("vseparation", 0);
+ } else {
+ add_theme_color_override("property_color", get_theme_color("property_color", "EditorProperty"));
+ add_theme_style_override("bg_selected", get_theme_stylebox("bg_selected", "EditorProperty"));
+ add_theme_style_override("bg", get_theme_stylebox("bg", "EditorProperty"));
+ add_theme_constant_override("vseparation", get_theme_constant("vseparation", "EditorProperty"));
+ add_theme_constant_override("font_offset", get_theme_constant("font_offset", "EditorProperty"));
+ }
+
+ updating_theme = false;
+ update();
+}
void EditorPropertyResource::update_property() {
RES res = get_edited_object()->get(get_edited_property());
@@ -2874,7 +2920,7 @@ void EditorPropertyResource::update_property() {
sub_inspector->set_use_doc_hints(true);
sub_inspector->set_sub_inspector(true);
- sub_inspector->set_enable_capitalize_paths(true);
+ sub_inspector->set_enable_capitalize_paths(bool(EDITOR_GET("interface/inspector/capitalize_properties")));
sub_inspector->connect("property_keyed", callable_mp(this, &EditorPropertyResource::_sub_inspector_property_keyed));
sub_inspector->connect("resource_selected", callable_mp(this, &EditorPropertyResource::_sub_inspector_resource_selected));
@@ -2907,13 +2953,14 @@ void EditorPropertyResource::update_property() {
}
opened_editor = true;
}
+
+ _update_property_bg();
}
if (res.ptr() != sub_inspector->get_edited_object()) {
sub_inspector->edit(res.ptr());
}
- sub_inspector->refresh();
} else {
if (sub_inspector) {
set_bottom_editor(nullptr);
@@ -2924,6 +2971,7 @@ void EditorPropertyResource::update_property() {
EditorNode::get_singleton()->hide_top_editors();
opened_editor = false;
}
+ _update_property_bg();
}
}
}
@@ -2932,6 +2980,7 @@ void EditorPropertyResource::update_property() {
if (res == RES()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("[empty]"));
+ assign->set_custom_minimum_size(Size2(1, 1));
} else {
assign->set_icon(EditorNode::get_singleton()->get_object_icon(res.operator->(), "Object"));
@@ -2977,8 +3026,12 @@ void EditorPropertyResource::setup(const String &p_base_type) {
void EditorPropertyResource::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ if (updating_theme) {
+ return;
+ }
Ref<Texture2D> t = get_theme_icon("select_arrow", "Tree");
edit->set_icon(t);
+ _update_property_bg();
}
if (p_what == NOTIFICATION_DRAG_BEGIN) {
@@ -3234,7 +3287,7 @@ void EditorInspectorDefaultPlugin::parse_begin(Object *p_object) {
}
bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) {
- float default_float_step = EDITOR_GET("interface/inspector/default_float_step");
+ double default_float_step = EDITOR_GET("interface/inspector/default_float_step");
switch (p_type) {
// atomic types
@@ -3259,7 +3312,12 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
editor->setup(options);
add_property_editor(p_path, editor);
- } else if (p_hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || p_hint == PROPERTY_HINT_LAYERS_2D_RENDER || p_hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || p_hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
+ } else if (p_hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
+ p_hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
+ p_hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
EditorPropertyLayers::LayerType lt = EditorPropertyLayers::LAYER_RENDER_2D;
switch (p_hint) {
case PROPERTY_HINT_LAYERS_2D_RENDER:
@@ -3268,12 +3326,18 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
case PROPERTY_HINT_LAYERS_2D_PHYSICS:
lt = EditorPropertyLayers::LAYER_PHYSICS_2D;
break;
+ case PROPERTY_HINT_LAYERS_2D_NAVIGATION:
+ lt = EditorPropertyLayers::LAYER_NAVIGATION_2D;
+ break;
case PROPERTY_HINT_LAYERS_3D_RENDER:
lt = EditorPropertyLayers::LAYER_RENDER_3D;
break;
case PROPERTY_HINT_LAYERS_3D_PHYSICS:
lt = EditorPropertyLayers::LAYER_PHYSICS_3D;
break;
+ case PROPERTY_HINT_LAYERS_3D_NAVIGATION:
+ lt = EditorPropertyLayers::LAYER_NAVIGATION_3D;
+ break;
default: {
} //compiler could be smarter here and realize this can't happen
}
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 4775259111..07a1e72319 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -239,8 +239,10 @@ public:
enum LayerType {
LAYER_PHYSICS_2D,
LAYER_RENDER_2D,
+ LAYER_NAVIGATION_2D,
LAYER_PHYSICS_3D,
LAYER_RENDER_3D,
+ LAYER_NAVIGATION_3D,
};
private:
@@ -654,6 +656,9 @@ class EditorPropertyResource : public EditorProperty {
bool opened_editor;
+ bool updating_theme = false;
+ void _update_property_bg();
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index a798344973..de688f2709 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -573,8 +573,7 @@ void EditorPropertyArray::_bind_methods() {
EditorPropertyArray::EditorPropertyArray() {
object.instance();
- page_idx = 0;
- page_len = 10;
+ page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1069,8 +1068,7 @@ void EditorPropertyDictionary::_bind_methods() {
EditorPropertyDictionary::EditorPropertyDictionary() {
object.instance();
- page_idx = 0;
- page_len = 10;
+ page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 0359f3d9bc..fa5adc788d 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -84,8 +84,8 @@ class EditorPropertyArray : public EditorProperty {
bool dropping;
Ref<EditorPropertyArrayObject> object;
- int page_len;
- int page_idx;
+ int page_len = 20;
+ int page_idx = 0;
int changing_type_idx;
Button *edit;
VBoxContainer *vbox;
@@ -129,8 +129,8 @@ class EditorPropertyDictionary : public EditorProperty {
bool updating;
Ref<EditorPropertyDictionaryObject> object;
- int page_len;
- int page_idx;
+ int page_len = 20;
+ int page_idx = 0;
int changing_type_idx;
Button *edit;
VBoxContainer *vbox;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 8056846f52..138830cdc6 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -174,7 +174,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
if (!r_small_texture.is_valid() && r_texture.is_valid() && preview_generators[i]->generate_small_preview_automatically()) {
- Ref<Image> small_image = r_texture->get_data();
+ Ref<Image> small_image = r_texture->get_image();
small_image = small_image->duplicate();
small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC);
r_small_texture.instance();
@@ -206,8 +206,8 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
void EditorResourcePreview::_thread() {
- exited = false;
- while (!exit) {
+ exited.clear();
+ while (!exit.is_set()) {
preview_sem.wait();
preview_mutex.lock();
@@ -326,7 +326,7 @@ void EditorResourcePreview::_thread() {
preview_mutex.unlock();
}
}
- exited = true;
+ exited.set();
}
void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
@@ -430,9 +430,9 @@ void EditorResourcePreview::start() {
void EditorResourcePreview::stop() {
if (thread.is_started()) {
- exit = true;
+ exit.set();
preview_sem.post();
- while (!exited) {
+ while (!exited.is_set()) {
OS::get_singleton()->delay_usec(10000);
RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
}
@@ -443,8 +443,6 @@ void EditorResourcePreview::stop() {
EditorResourcePreview::EditorResourcePreview() {
singleton = this;
order = 0;
- exit = false;
- exited = false;
}
EditorResourcePreview::~EditorResourcePreview() {
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 99c48967d8..c4e796dcf1 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -33,6 +33,7 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
@@ -71,8 +72,8 @@ class EditorResourcePreview : public Node {
Mutex preview_mutex;
Semaphore preview_sem;
Thread thread;
- volatile bool exit;
- volatile bool exited;
+ SafeFlag exit;
+ SafeFlag exited;
struct Item {
Ref<Texture2D> preview;
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index 9b92134368..1ffa20d1ea 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -43,7 +43,7 @@ void EditorRunNative::_notification(int p_what) {
}
Ref<ImageTexture> icon = eep->get_run_icon();
if (!icon.is_null()) {
- Ref<Image> im = icon->get_data();
+ Ref<Image> im = icon->get_image();
im = im->duplicate();
im->clear_mipmaps();
if (!im->is_empty()) {
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index a2627f51ac..f81c87be9e 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -116,12 +116,12 @@ public:
void set_section(const String &p_section, bool p_allow_sub) {
section = p_section;
allow_sub = p_allow_sub;
- _change_notify();
+ notify_property_list_changed();
}
void set_edited(Object *p_edited) {
edited = p_edited;
- _change_notify();
+ notify_property_list_changed();
}
};
@@ -226,7 +226,7 @@ void SectionedInspector::update_category_list() {
if (pi.usage & PROPERTY_USAGE_CATEGORY) {
continue;
- } else if (!(pi.usage & PROPERTY_USAGE_EDITOR)) {
+ } else if (!(pi.usage & PROPERTY_USAGE_EDITOR) || (restrict_to_basic && !(pi.usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
continue;
}
@@ -294,6 +294,12 @@ EditorInspector *SectionedInspector::get_inspector() {
return inspector;
}
+void SectionedInspector::set_restrict_to_basic_settings(bool p_restrict) {
+ restrict_to_basic = p_restrict;
+ update_category_list();
+ inspector->set_restrict_to_basic_settings(p_restrict);
+}
+
SectionedInspector::SectionedInspector() :
sections(memnew(Tree)),
filter(memnew(SectionedInspectorFilter)),
diff --git a/editor/editor_sectioned_inspector.h b/editor/editor_sectioned_inspector.h
index 55fb94fecc..1068a4f932 100644
--- a/editor/editor_sectioned_inspector.h
+++ b/editor/editor_sectioned_inspector.h
@@ -51,6 +51,8 @@ class SectionedInspector : public HSplitContainer {
String selected_category;
+ bool restrict_to_basic = false;
+
static void _bind_methods();
void _section_selected();
@@ -65,6 +67,7 @@ public:
void set_current_section(const String &p_section);
String get_current_section() const;
+ void set_restrict_to_basic_settings(bool p_restrict);
void update_category_list();
SectionedInspector();
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 9908f5727e..4ddae7c062 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -31,6 +31,7 @@
#include "editor_settings.h"
#include "core/config/project_settings.h"
+#include "core/input/input_map.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
#include "core/io/config_file.h"
@@ -70,7 +71,7 @@ bool EditorSettings::_set(const StringName &p_name, const Variant &p_value) {
bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value) {
_THREAD_SAFE_METHOD_
- if (p_name.operator String() == "shortcuts") {
+ if (p_name == "shortcuts") {
Array arr = p_value;
ERR_FAIL_COND_V(arr.size() && arr.size() & 1, true);
for (int i = 0; i < arr.size(); i += 2) {
@@ -84,6 +85,24 @@ bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value)
}
return false;
+ } else if (p_name == "builtin_action_overrides") {
+ Array actions_arr = p_value;
+ for (int i = 0; i < actions_arr.size(); i++) {
+ Dictionary action_dict = actions_arr[i];
+
+ String name = action_dict["name"];
+ Array events = action_dict["events"];
+
+ InputMap *im = InputMap::get_singleton();
+ im->action_erase_events(name);
+
+ builtin_action_overrides[name].clear();
+ for (int ev_idx = 0; ev_idx < events.size(); ev_idx++) {
+ im->action_add_event(name, events[ev_idx]);
+ builtin_action_overrides[name].push_back(events[ev_idx]);
+ }
+ }
+ return false;
}
bool changed = false;
@@ -118,11 +137,16 @@ bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value)
bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const {
_THREAD_SAFE_METHOD_
- if (p_name.operator String() == "shortcuts") {
+ if (p_name == "shortcuts") {
Array arr;
for (const Map<String, Ref<Shortcut>>::Element *E = shortcuts.front(); E; E = E->next()) {
Ref<Shortcut> sc = E->get();
+ if (builtin_action_overrides.has(E->key())) {
+ // This shortcut was auto-generated from built in actions: don't save.
+ continue;
+ }
+
if (optimize_save) {
if (!sc->has_meta("original")) {
continue; //this came from settings but is not any longer used
@@ -139,6 +163,27 @@ bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const {
}
r_ret = arr;
return true;
+ } else if (p_name == "builtin_action_overrides") {
+ Array actions_arr;
+ for (Map<String, List<Ref<InputEvent>>>::Element *E = builtin_action_overrides.front(); E; E = E->next()) {
+ List<Ref<InputEvent>> events = E->get();
+
+ // TODO: skip actions which are the same as the builtin.
+ Dictionary action_dict;
+ action_dict["name"] = E->key();
+
+ Array events_arr;
+ for (List<Ref<InputEvent>>::Element *I = events.front(); I; I = I->next()) {
+ events_arr.push_back(I->get());
+ }
+
+ action_dict["events"] = events_arr;
+
+ actions_arr.push_back(action_dict);
+ }
+
+ r_ret = actions_arr;
+ return true;
}
const VariantContainer *v = props.getptr(p_name);
@@ -220,6 +265,7 @@ void EditorSettings::_get_property_list(List<PropertyInfo> *p_list) const {
}
p_list->push_back(PropertyInfo(Variant::ARRAY, "shortcuts", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); //do not edit
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "builtin_action_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
void EditorSettings::_add_property_info_bind(const Dictionary &p_info) {
@@ -337,6 +383,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
// hiDPI display.
scale = 2.0;
+ } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
+ // Likely a hiDPI display, but we aren't certain due to the returned DPI.
+ // Use an intermediate scale to handle this situation.
+ scale = 1.5;
} else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
// Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
// Icons won't look great, but this is better than having editor elements overflow from its window.
@@ -381,6 +431,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/hide_console_window", false);
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
+ // Inspector
+ _initial_set("interface/inspector/max_array_dictionary_items_per_page", 20);
+ hints["interface/inspector/max_array_dictionary_items_per_page"] = PropertyInfo(Variant::INT, "interface/inspector/max_array_dictionary_items_per_page", PROPERTY_HINT_RANGE, "10,100,1", PROPERTY_USAGE_DEFAULT);
+
// Theme
_initial_set("interface/theme/preset", "Default");
hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Alien,Arc,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT);
@@ -392,6 +446,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/theme/accent_color"] = PropertyInfo(Variant::COLOR, "interface/theme/accent_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/contrast", 0.25);
hints["interface/theme/contrast"] = PropertyInfo(Variant::FLOAT, "interface/theme/contrast", PROPERTY_HINT_RANGE, "0.01, 1, 0.01");
+ _initial_set("interface/theme/icon_saturation", 1.0);
+ hints["interface/theme/icon_saturation"] = PropertyInfo(Variant::FLOAT, "interface/theme/icon_saturation", PROPERTY_HINT_RANGE, "0,2,0.01", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/relationship_line_opacity", 0.1);
hints["interface/theme/relationship_line_opacity"] = PropertyInfo(Variant::FLOAT, "interface/theme/relationship_line_opacity", PROPERTY_HINT_RANGE, "0.00, 1, 0.01");
_initial_set("interface/theme/highlight_tabs", false);
@@ -404,7 +460,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT);
// Scene tabs
- _initial_set("interface/scene_tabs/show_extension", false);
_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);
_initial_set("interface/scene_tabs/resize_if_many_tabs", true);
_initial_set("interface/scene_tabs/minimum_width", 50);
@@ -441,7 +496,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("docks/filesystem/always_show_folders", true);
// Property editor
- _initial_set("docks/property_editor/auto_refresh_interval", 0.3);
+ _initial_set("docks/property_editor/auto_refresh_interval", 0.2); //update 5 times per second by default
+ _initial_set("docks/property_editor/subresource_hue_tint", 0.75);
+ hints["docks/property_editor/subresource_hue_tint"] = PropertyInfo(Variant::FLOAT, "docks/property_editor/subresource_hue_tint", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT);
/* Text editor */
@@ -562,8 +619,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// is increased significantly more than it really should need to be.
hints["editors/3d/grid_division_level_max"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_max", PROPERTY_HINT_RANGE, "-1,3,1", PROPERTY_USAGE_DEFAULT);
- // Default smallest grid size is 1cm, 10^-2.
- _initial_set("editors/3d/grid_division_level_min", -2);
+ // Default smallest grid size is 1m, 10^0.
+ _initial_set("editors/3d/grid_division_level_min", 0);
// Lower values produce graphical artifacts regardless of view clipping planes, so limit to -2 as a lower bound.
hints["editors/3d/grid_division_level_min"] = PropertyInfo(Variant::INT, "editors/3d/grid_division_level_min", PROPERTY_HINT_RANGE, "-2,2,1", PROPERTY_USAGE_DEFAULT);
@@ -1277,7 +1334,7 @@ String EditorSettings::get_script_templates_dir() const {
}
String EditorSettings::get_project_script_templates_dir() const {
- return ProjectSettings::get_singleton()->get("editor/script_templates_search_path");
+ return ProjectSettings::get_singleton()->get("editor/script/templates_search_path");
}
// Cache directory
@@ -1531,12 +1588,39 @@ bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_
}
Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const {
- const Map<String, Ref<Shortcut>>::Element *E = shortcuts.find(p_name);
- if (!E) {
- return Ref<Shortcut>();
+ const Map<String, Ref<Shortcut>>::Element *SC = shortcuts.find(p_name);
+ if (SC) {
+ return SC->get();
}
- return E->get();
+ // If no shortcut with the provided name is found in the list, check the built-in shortcuts.
+ // Use the first item in the action list for the shortcut event, since a shortcut can only have 1 linked event.
+
+ Ref<Shortcut> sc;
+ const Map<String, List<Ref<InputEvent>>>::Element *builtin_override = builtin_action_overrides.find(p_name);
+ if (builtin_override) {
+ sc.instance();
+ sc->set_shortcut(builtin_override->get().front()->get());
+ sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
+ }
+
+ // If there was no override, check the default builtins to see if it has an InputEvent for the provided name.
+ if (sc.is_null()) {
+ const OrderedHashMap<String, List<Ref<InputEvent>>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins().find(p_name);
+ if (builtin_default) {
+ sc.instance();
+ sc->set_shortcut(builtin_default.get().front()->get());
+ sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
+ }
+ }
+
+ if (sc.is_valid()) {
+ // Add the shortcut to the list.
+ shortcuts[p_name] = sc;
+ return sc;
+ }
+
+ return Ref<Shortcut>();
}
void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {
@@ -1602,6 +1686,66 @@ Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p
return sc;
}
+void EditorSettings::set_builtin_action_override(const String &p_name, const Array &p_events) {
+ List<Ref<InputEvent>> event_list;
+
+ // Override the whole list, since events may have their order changed or be added, removed or edited.
+ InputMap::get_singleton()->action_erase_events(p_name);
+ for (int i = 0; i < p_events.size(); i++) {
+ event_list.push_back(p_events[i]);
+ InputMap::get_singleton()->action_add_event(p_name, p_events[i]);
+ }
+
+ // Check if the provided event array is same as built-in. If it is, it does not need to be added to the overrides.
+ // Note that event order must also be the same.
+ bool same_as_builtin = true;
+ OrderedHashMap<String, List<Ref<InputEvent>>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins().find(p_name);
+ if (builtin_default) {
+ List<Ref<InputEvent>> builtin_events = builtin_default.get();
+
+ if (p_events.size() == builtin_events.size()) {
+ int event_idx = 0;
+
+ // Check equality of each event.
+ for (List<Ref<InputEvent>>::Element *E = builtin_events.front(); E; E = E->next()) {
+ if (!E->get()->shortcut_match(p_events[event_idx])) {
+ same_as_builtin = false;
+ break;
+ }
+ event_idx++;
+ }
+ } else {
+ same_as_builtin = false;
+ }
+ }
+
+ if (same_as_builtin && builtin_action_overrides.has(p_name)) {
+ builtin_action_overrides.erase(p_name);
+ } else {
+ builtin_action_overrides[p_name] = event_list;
+ }
+
+ // Update the shortcut (if it is used somewhere in the editor) to be the first event of the new list.
+ if (shortcuts.has(p_name)) {
+ shortcuts[p_name]->set_shortcut(event_list.front()->get());
+ }
+}
+
+const Array EditorSettings::get_builtin_action_overrides(const String &p_name) const {
+ const Map<String, List<Ref<InputEvent>>>::Element *AO = builtin_action_overrides.find(p_name);
+ if (AO) {
+ Array event_array;
+
+ List<Ref<InputEvent>> events_list = AO->get();
+ for (List<Ref<InputEvent>>::Element *E = events_list.front(); E; E = E->next()) {
+ event_array.push_back(E->get());
+ }
+ return event_array;
+ }
+
+ return Array();
+}
+
void EditorSettings::notify_changes() {
_THREAD_SAFE_METHOD_
@@ -1640,6 +1784,8 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs);
ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs);
+ ClassDB::bind_method(D_METHOD("set_builtin_action_override", "name", "actions_list"), &EditorSettings::set_builtin_action_override);
+
ADD_SIGNAL(MethodInfo("settings_changed"));
BIND_CONSTANT(NOTIFICATION_EDITOR_SETTINGS_CHANGED);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 616a938a86..e5f8527faf 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -84,7 +84,8 @@ private:
int last_order;
Ref<Resource> clipboard;
- Map<String, Ref<Shortcut>> shortcuts;
+ mutable Map<String, Ref<Shortcut>> shortcuts;
+ Map<String, List<Ref<InputEvent>>> builtin_action_overrides;
String resource_path;
String settings_dir;
@@ -186,6 +187,9 @@ public:
Ref<Shortcut> get_shortcut(const String &p_name) const;
void get_shortcut_list(List<String> *r_shortcuts);
+ void set_builtin_action_override(const String &p_name, const Array &p_events);
+ const Array get_builtin_action_overrides(const String &p_name) const;
+
void notify_changes();
EditorSettings();
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 618d953c56..8577ccb9db 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -47,13 +47,15 @@ String EditorSpinSlider::get_text_value() const {
}
void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (read_only) {
return;
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (updown_offset != -1 && mb->get_position().x > updown_offset) {
//there is an updown, so use it.
@@ -84,7 +86,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
grabbing_spinner_attempt = false;
}
}
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP || mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (grabber->is_visible()) {
call_deferred("update");
}
@@ -146,17 +148,17 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_grabber) {
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
set_value(get_value() + get_step());
mousewheel_over_grabber = true;
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
set_value(get_value() - get_step());
mousewheel_over_grabber = true;
}
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
grabbing_grabber = true;
if (!mousewheel_over_grabber) {
@@ -175,7 +177,9 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range);
+ float scale_x = get_global_transform_with_canvas().get_scale().x;
+ ERR_FAIL_COND(Math::is_zero_approx(scale_x));
+ float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range) / scale_x;
set_as_ratio(grabbing_ratio + grabbing_ofs);
update();
}
@@ -300,8 +304,10 @@ void EditorSpinSlider::_notification(int p_what) {
grabber->set_texture(grabber_tex);
}
+ Vector2 scale = get_global_transform_with_canvas().get_scale();
+ grabber->set_scale(scale);
grabber->set_size(Size2(0, 0));
- grabber->set_position(get_global_position() + grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5);
+ grabber->set_position(get_global_position() + (grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5) * scale);
if (mousewheel_over_grabber) {
Input::get_singleton()->warp_mouse_position(grabber->get_position() + grabber_rect.size);
diff --git a/editor/editor_sub_scene.cpp b/editor/editor_sub_scene.cpp
deleted file mode 100644
index e319fbff52..0000000000
--- a/editor/editor_sub_scene.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*************************************************************************/
-/* editor_sub_scene.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "editor_sub_scene.h"
-
-#include "editor/editor_node.h"
-#include "scene/gui/margin_container.h"
-#include "scene/resources/packed_scene.h"
-
-void EditorSubScene::_path_selected(const String &p_path) {
- path->set_text(p_path);
- _path_changed(p_path);
-}
-
-void EditorSubScene::_path_changed(const String &p_path) {
- tree->clear();
-
- if (scene) {
- memdelete(scene);
- scene = nullptr;
- }
-
- if (p_path == "") {
- return;
- }
-
- Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene");
-
- if (ps.is_null()) {
- return;
- }
-
- scene = ps->instance();
- if (!scene) {
- return;
- }
-
- _fill_tree(scene, nullptr);
-}
-
-void EditorSubScene::_path_browse() {
- file_dialog->popup_file_dialog();
-}
-
-void EditorSubScene::_notification(int p_what) {
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (is_visible() && scene == nullptr) {
- _path_browse();
- }
- }
-}
-
-void EditorSubScene::_fill_tree(Node *p_node, TreeItem *p_parent) {
- TreeItem *it = tree->create_item(p_parent);
- it->set_metadata(0, p_node);
- it->set_text(0, p_node->get_name());
- it->set_editable(0, false);
- it->set_selectable(0, true);
- it->set_icon(0, EditorNode::get_singleton()->get_object_icon(p_node, "Node"));
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *c = p_node->get_child(i);
- if (c->get_owner() != scene) {
- continue;
- }
- _fill_tree(c, it);
- }
-}
-
-void EditorSubScene::_selected_changed() {
- TreeItem *item = tree->get_selected();
- ERR_FAIL_COND(!item);
- Node *n = item->get_metadata(0);
-
- if (!n || !selection.find(n)) {
- selection.clear();
- is_root = false;
- }
-}
-
-void EditorSubScene::_item_multi_selected(Object *p_object, int p_cell, bool p_selected) {
- if (!is_root) {
- TreeItem *item = Object::cast_to<TreeItem>(p_object);
- ERR_FAIL_COND(!item);
-
- Node *n = item->get_metadata(0);
-
- if (!n) {
- return;
- }
- if (p_selected) {
- if (n == scene) {
- is_root = true;
- selection.clear();
- }
- selection.push_back(n);
- } else {
- List<Node *>::Element *E = selection.find(n);
-
- if (E) {
- selection.erase(E);
- }
- }
- }
-}
-
-void EditorSubScene::_item_activated() {
- _ok_pressed(); // From AcceptDialog.
-}
-
-void EditorSubScene::_remove_selection_child(Node *p_node) {
- if (p_node->get_child_count() > 0) {
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *c = p_node->get_child(i);
- List<Node *>::Element *E = selection.find(c);
- if (E) {
- selection.move_to_back(E);
- selection.pop_back();
- }
- if (c->get_child_count() > 0) {
- _remove_selection_child(c);
- }
- }
- }
-}
-
-void EditorSubScene::ok_pressed() {
- if (selection.size() <= 0) {
- return;
- }
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- Node *c = E->get();
- _remove_selection_child(c);
- }
- emit_signal("subscene_selected");
- hide();
- clear();
-}
-
-void EditorSubScene::_reown(Node *p_node, List<Node *> *p_to_reown) {
- if (p_node == scene) {
- scene->set_filename("");
- p_to_reown->push_back(p_node);
- } else if (p_node->get_owner() == scene) {
- p_to_reown->push_back(p_node);
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *c = p_node->get_child(i);
- _reown(c, p_to_reown);
- }
-}
-
-void EditorSubScene::move(Node *p_new_parent, Node *p_new_owner) {
- if (!scene) {
- return;
- }
-
- if (selection.size() <= 0) {
- return;
- }
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- Node *selnode = E->get();
- if (!selnode) {
- return;
- }
- List<Node *> to_reown;
- _reown(selnode, &to_reown);
- if (selnode != scene) {
- selnode->get_parent()->remove_child(selnode);
- }
-
- p_new_parent->add_child(selnode);
- for (List<Node *>::Element *F = to_reown.front(); F; F = F->next()) {
- F->get()->set_owner(p_new_owner);
- }
- }
- if (!is_root) {
- memdelete(scene);
- }
- scene = nullptr;
- //return selnode;
-}
-
-void EditorSubScene::clear() {
- path->set_text("");
- _path_changed("");
-}
-
-void EditorSubScene::_bind_methods() {
- ADD_SIGNAL(MethodInfo("subscene_selected"));
-}
-
-EditorSubScene::EditorSubScene() {
- scene = nullptr;
- is_root = false;
-
- set_title(TTR("Select Node(s) to Import"));
- set_hide_on_ok(false);
-
- VBoxContainer *vb = memnew(VBoxContainer);
- add_child(vb);
- //set_child_rect(vb);
-
- HBoxContainer *hb = memnew(HBoxContainer);
- path = memnew(LineEdit);
- path->connect("text_entered", callable_mp(this, &EditorSubScene::_path_changed));
- hb->add_child(path);
- path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- Button *b = memnew(Button);
- b->set_text(TTR("Browse"));
- hb->add_child(b);
- b->connect("pressed", callable_mp(this, &EditorSubScene::_path_browse));
- vb->add_margin_child(TTR("Scene Path:"), hb);
-
- tree = memnew(Tree);
- tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- vb->add_margin_child(TTR("Import From Node:"), tree, true);
- tree->set_select_mode(Tree::SELECT_MULTI);
- tree->connect("multi_selected", callable_mp(this, &EditorSubScene::_item_multi_selected));
- //tree->connect("nothing_selected", this, "_deselect_items");
- tree->connect("cell_selected", callable_mp(this, &EditorSubScene::_selected_changed));
-
- tree->connect("item_activated", callable_mp(this, &EditorSubScene::_item_activated), make_binds(), CONNECT_DEFERRED);
-
- file_dialog = memnew(EditorFileDialog);
- List<String> extensions;
- ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
-
- for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- file_dialog->add_filter("*." + E->get());
- }
-
- file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- add_child(file_dialog);
- file_dialog->connect("file_selected", callable_mp(this, &EditorSubScene::_path_selected));
-}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 8f877a4762..7cc9ebd63e 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -91,7 +91,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
}
Ref<ImageTexture> texture(memnew(ImageTexture));
- Ref<Image> img = p_texture->get_data();
+ Ref<Image> img = p_texture->get_image();
img = img->duplicate();
if (p_flip_y) {
@@ -106,7 +106,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
}
#ifdef MODULE_SVG_ENABLED
-static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, bool p_force_filter = false) {
+static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, float p_saturation = 1.0) {
Ref<ImageTexture> icon = memnew(ImageTexture);
Ref<Image> img = memnew(Image);
@@ -116,6 +116,9 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale);
ImageLoaderSVG::create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_color);
+ if (p_saturation != 1.0) {
+ img->adjust_bcs(1.0, 1.0, p_saturation);
+ }
icon->create_from_image(img); // in this case filter really helps
return icon;
@@ -126,7 +129,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
#define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color)
#endif
-void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false) {
+void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
#ifdef MODULE_SVG_ENABLED
// The default icon theme is designed to be used for a dark theme.
// This dictionary stores color codes to convert to other colors
@@ -238,15 +241,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
// Generate icons.
if (!p_only_thumbs) {
for (int i = 0; i < editor_icons_count; i++) {
- float icon_scale = EDSCALE;
+ float saturation = p_icon_saturation;
- // Always keep the DefaultProjectIcon at the default size
- if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
- icon_scale = 1.0f;
+ if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0 || strcmp(editor_icons_names[i], "Godot") == 0 || strcmp(editor_icons_names[i], "Logo") == 0) {
+ saturation = 1.0;
}
const int is_exception = exceptions.has(editor_icons_names[i]);
- const Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception, icon_scale);
+ const Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception, EDSCALE, saturation);
p_theme->set_icon(editor_icons_names[i], "EditorIcons", icon);
}
@@ -290,6 +292,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color accent_color = EDITOR_GET("interface/theme/accent_color");
Color base_color = EDITOR_GET("interface/theme/base_color");
float contrast = EDITOR_GET("interface/theme/contrast");
+ float icon_saturation = EDITOR_GET("interface/theme/icon_saturation");
float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity");
String preset = EDITOR_GET("interface/theme/preset");
@@ -393,6 +396,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color highlight_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.2);
+ float prev_icon_saturation = theme->has_color("icon_saturation", "Editor") ? theme->get_color("icon_saturation", "Editor").r : 1.0;
+
+ theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation)); //can't save single float in theme, so using color
theme->set_color("accent_color", "Editor", accent_color);
theme->set_color("highlight_color", "Editor", highlight_color);
theme->set_color("base_color", "Editor", base_color);
@@ -444,13 +450,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
//Register icons + font
// the resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons
- if (p_theme != nullptr && fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme) {
+ if (p_theme != nullptr && fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme && prev_icon_saturation == icon_saturation) {
// register already generated icons
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], "EditorIcons", p_theme->get_icon(editor_icons_names[i], "EditorIcons"));
}
} else {
- editor_register_and_generate_icons(theme, dark_theme, thumb_size);
+ editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
}
// thumbnail size has changed, so we regenerate the medium sizes
if (p_theme != nullptr && fabs((double)p_theme->get_constant("thumb_size", "Editor") - thumb_size) > 0.00001) {
@@ -555,7 +561,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tab_disabled->set_border_color(disabled_color);
// Editor background
- theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
+ Color background_color_opaque = background_color;
+ background_color_opaque.a = 1.0;
+ theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color_opaque, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
// Focus
Ref<StyleBoxFlat> style_focus = style_default->duplicate();
@@ -698,9 +706,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// PopupMenu
const int popup_menu_margin_size = default_margin_size * 1.5 * EDSCALE;
Ref<StyleBoxFlat> style_popup_menu = style_popup->duplicate();
- style_popup_menu->set_default_margin(SIDE_LEFT, popup_menu_margin_size);
+ // Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn
+ // on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted,
+ // and it looks weird. 1px solves this.
+ style_popup_menu->set_default_margin(SIDE_LEFT, 1 * EDSCALE);
style_popup_menu->set_default_margin(SIDE_TOP, popup_menu_margin_size);
- style_popup_menu->set_default_margin(SIDE_RIGHT, popup_menu_margin_size);
+ style_popup_menu->set_default_margin(SIDE_RIGHT, 1 * EDSCALE);
style_popup_menu->set_default_margin(SIDE_BOTTOM, popup_menu_margin_size);
theme->set_stylebox("panel", "PopupMenu", style_popup_menu);
@@ -722,16 +733,63 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("visibility_hidden", "PopupMenu", theme->get_icon("GuiVisibilityHidden", "EditorIcons"));
theme->set_icon("visibility_visible", "PopupMenu", theme->get_icon("GuiVisibilityVisible", "EditorIcons"));
theme->set_icon("visibility_xray", "PopupMenu", theme->get_icon("GuiVisibilityXray", "EditorIcons"));
+
theme->set_constant("vseparation", "PopupMenu", (extra_spacing + default_margin_size + 1) * EDSCALE);
+ theme->set_constant("item_start_padding", "PopupMenu", popup_menu_margin_size * EDSCALE);
+ theme->set_constant("item_end_padding", "PopupMenu", popup_menu_margin_size * EDSCALE);
+
+ for (int i = 0; i < 16; i++) {
+ Color si_base_color = accent_color;
+
+ float hue_rotate = (i * 2 % 16) / 16.0;
+ si_base_color.set_hsv(Math::fmod(float(si_base_color.get_h() + hue_rotate), float(1.0)), si_base_color.get_s(), si_base_color.get_v());
+ si_base_color = accent_color.lerp(si_base_color, float(EDITOR_GET("docks/property_editor/subresource_hue_tint")));
+
+ Ref<StyleBoxFlat> sub_inspector_bg;
- Ref<StyleBoxFlat> sub_inspector_bg = make_flat_stylebox(dark_color_1.lerp(accent_color, 0.08), 2, 0, 2, 2);
- sub_inspector_bg->set_border_width(SIDE_LEFT, 2);
- sub_inspector_bg->set_border_width(SIDE_RIGHT, 2);
- sub_inspector_bg->set_border_width(SIDE_BOTTOM, 2);
- sub_inspector_bg->set_border_color(accent_color * Color(1, 1, 1, 0.3));
- sub_inspector_bg->set_draw_center(true);
+ sub_inspector_bg = make_flat_stylebox(dark_color_1.lerp(si_base_color, 0.08), 2, 0, 2, 2);
+
+ sub_inspector_bg->set_border_width(SIDE_LEFT, 2);
+ sub_inspector_bg->set_border_width(SIDE_RIGHT, 2);
+ sub_inspector_bg->set_border_width(SIDE_BOTTOM, 2);
+ sub_inspector_bg->set_border_width(SIDE_TOP, 2);
+ sub_inspector_bg->set_default_margin(SIDE_LEFT, 3);
+ sub_inspector_bg->set_default_margin(SIDE_RIGHT, 3);
+ sub_inspector_bg->set_default_margin(SIDE_BOTTOM, 10);
+ sub_inspector_bg->set_default_margin(SIDE_TOP, 5);
+ sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8));
+ sub_inspector_bg->set_draw_center(true);
+
+ theme->set_stylebox("sub_inspector_bg" + itos(i), "Editor", sub_inspector_bg);
+
+ Ref<StyleBoxFlat> bg_color;
+ bg_color.instance();
+ bg_color->set_bg_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8));
+ bg_color->set_border_width_all(0);
+
+ Ref<StyleBoxFlat> bg_color_selected;
+ bg_color_selected.instance();
+ bg_color_selected->set_border_width_all(0);
+ bg_color_selected->set_bg_color(si_base_color * Color(0.8, 0.8, 0.8, 0.8));
+
+ theme->set_stylebox("sub_inspector_property_bg" + itos(i), "Editor", bg_color);
+ theme->set_stylebox("sub_inspector_property_bg_selected" + itos(i), "Editor", bg_color_selected);
+ }
+
+ theme->set_color("sub_inspector_property_color", "Editor", dark_theme ? Color(1, 1, 1, 1) : Color(0, 0, 0, 1));
+ theme->set_constant("sub_inspector_font_offset", "Editor", 4 * EDSCALE);
+
+ Ref<StyleBoxFlat> style_property_bg = style_default->duplicate();
+ style_property_bg->set_bg_color(highlight_color);
+ style_property_bg->set_border_width_all(0);
+
+ theme->set_constant("font_offset", "EditorProperty", 1 * EDSCALE);
+ theme->set_stylebox("bg_selected", "EditorProperty", style_property_bg);
+ theme->set_stylebox("bg", "EditorProperty", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
+ theme->set_constant("vseparation", "EditorProperty", (extra_spacing + default_margin_size) * EDSCALE);
+ theme->set_color("error_color", "EditorProperty", error_color);
+ theme->set_color("property_color", "EditorProperty", property_color);
- theme->set_stylebox("sub_inspector_bg", "Editor", sub_inspector_bg);
theme->set_constant("inspector_margin", "Editor", 8 * EDSCALE);
// Tree & ItemList background
@@ -790,7 +848,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_tree_cursor = style_default->duplicate();
style_tree_cursor->set_draw_center(false);
- style_tree_cursor->set_border_width_all(border_width);
+ style_tree_cursor->set_border_width_all(MAX(1, border_width));
style_tree_cursor->set_border_color(contrast_color_1);
Ref<StyleBoxFlat> style_tree_title = style_default->duplicate();
@@ -905,7 +963,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("font_selected_color", "LineEdit", mono_color);
- theme->set_color("cursor_color", "LineEdit", font_color);
+ theme->set_color("caret_color", "LineEdit", font_color);
theme->set_color("selection_color", "LineEdit", selection_color);
theme->set_color("clear_button_color", "LineEdit", font_color);
theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
@@ -1204,6 +1262,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// FileDialog
theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
theme->set_icon("parent_folder", "FileDialog", theme->get_icon("ArrowUp", "EditorIcons"));
+ theme->set_icon("back_folder", "FileDialog", theme->get_icon("Back", "EditorIcons"));
+ theme->set_icon("forward_folder", "FileDialog", theme->get_icon("Forward", "EditorIcons"));
theme->set_icon("reload", "FileDialog", theme->get_icon("Reload", "EditorIcons"));
theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon("GuiVisibilityVisible", "EditorIcons"));
// Use a different color for folder icons to make them easier to distinguish from files.
@@ -1221,6 +1281,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("add_preset", "ColorPicker", theme->get_icon("Add", "EditorIcons"));
theme->set_icon("preset_bg", "ColorPicker", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));
theme->set_icon("overbright_indicator", "ColorPicker", theme->get_icon("OverbrightIndicator", "EditorIcons"));
+ theme->set_icon("bar_arrow", "ColorPicker", theme->get_icon("ColorPickerBarArrow", "EditorIcons"));
+ theme->set_icon("picker_cursor", "ColorPicker", theme->get_icon("PickerCursor", "EditorIcons"));
theme->set_icon("bg", "ColorPickerButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));
@@ -1335,3 +1397,15 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
return theme;
}
+
+Ref<ImageTexture> create_unscaled_default_project_icon() {
+#ifdef MODULE_SVG_ENABLED
+ for (int i = 0; i < editor_icons_count; i++) {
+ // ESCALE should never affect size of the icon
+ if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
+ return editor_generate_icon(i, false, 1.0);
+ }
+ }
+#endif
+ return Ref<ImageTexture>(memnew(ImageTexture));
+}
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 852edf7669..c040654220 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -31,10 +31,13 @@
#ifndef EDITOR_THEMES_H
#define EDITOR_THEMES_H
+#include "scene/resources/texture.h"
#include "scene/resources/theme.h"
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
+Ref<ImageTexture> create_unscaled_default_project_icon();
+
#endif
diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
index 51bd9b3383..49d5cf1fd3 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -38,8 +38,9 @@
EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) {
- if (!get_script_instance())
+ if (!get_script_instance()) {
return ERR_UNAVAILABLE;
+ }
if (get_script_instance()->has_method("parse_file")) {
Array ids;
@@ -70,8 +71,9 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str
}
void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
- if (!get_script_instance())
+ if (!get_script_instance()) {
return;
+ }
if (get_script_instance()->has_method("get_recognized_extensions")) {
Array extensions = get_script_instance()->call("get_recognized_extensions");
@@ -103,7 +105,7 @@ void EditorTranslationParser::get_recognized_extensions(List<String> *r_extensio
for (int i = 0; i < temp.size(); i++) {
extensions.insert(temp[i]);
}
- for (auto E = extensions.front(); E; E = E->next()) {
+ for (Set<String>::Element *E = extensions.front(); E; E = E->next()) {
r_extensions->push_back(E->get());
}
}
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 781d21c370..0f5c01be0e 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -116,13 +116,14 @@ void ExportTemplateManager::_update_template_list() {
}
for (Set<String>::Element *E = templates.back(); E; E = E->prev()) {
- HBoxContainer *hbc = memnew(HBoxContainer);
- Label *version = memnew(Label);
- version->set_modulate(current->get_theme_color("disabled_font_color", "Editor"));
String text = E->get();
if (text == current_version) {
- text += " " + TTR("(Current)");
+ continue;
}
+
+ HBoxContainer *hbc = memnew(HBoxContainer);
+ Label *version = memnew(Label);
+ version->set_modulate(current->get_theme_color("disabled_font_color", "Editor"));
version->set_text(text);
version->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(version);
@@ -653,7 +654,7 @@ ExportTemplateManager::ExportTemplateManager() {
main_vb->add_margin_child(TTR("Current Version:"), current_hb, false);
installed_scroll = memnew(ScrollContainer);
- main_vb->add_margin_child(TTR("Installed Versions:"), installed_scroll, true);
+ main_vb->add_margin_child(TTR("Other Installed Versions:"), installed_scroll, true);
installed_vb = memnew(VBoxContainer);
installed_scroll->add_child(installed_vb);
diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp
index 07edae833d..d80003a12a 100644
--- a/editor/fileserver/editor_file_server.cpp
+++ b/editor/fileserver/editor_file_server.cpp
@@ -43,7 +43,7 @@ void EditorFileServer::_close_client(ClientData *cd) {
cd->connection->disconnect_from_host();
{
MutexLock lock(cd->efs->wait_mutex);
- cd->efs->to_wait.insert(&cd->thread);
+ cd->efs->to_wait.insert(cd->thread);
}
while (cd->files.size()) {
memdelete(cd->files.front()->get());
@@ -278,7 +278,8 @@ void EditorFileServer::_thread_start(void *s) {
cd->connection = self->server->take_connection();
cd->efs = self;
cd->quit = false;
- cd->thread.start(_subthread_start, cd);
+ cd->thread = memnew(Thread);
+ cd->thread->start(_subthread_start, cd);
}
}
diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h
index e4c8327d76..8ffd4f9692 100644
--- a/editor/fileserver/editor_file_server.h
+++ b/editor/fileserver/editor_file_server.h
@@ -47,7 +47,7 @@ class EditorFileServer : public Object {
};
struct ClientData {
- Thread thread;
+ Thread *thread;
Ref<StreamPeerTCP> connection;
Map<int, FileAccess *> files;
EditorFileServer *efs = nullptr;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index e1c66f43b9..09424647fe 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -680,17 +680,17 @@ void FileSystemDock::_sort_file_info_list(List<FileSystemDock::FileInfo> &r_file
break;
case FILE_SORT_TYPE_REVERSE:
r_file_list.sort_custom<FileInfoTypeComparator>();
- r_file_list.invert();
+ r_file_list.reverse();
break;
case FILE_SORT_MODIFIED_TIME:
r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
break;
case FILE_SORT_MODIFIED_TIME_REVERSE:
r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
- r_file_list.invert();
+ r_file_list.reverse();
break;
case FILE_SORT_NAME_REVERSE:
- r_file_list.invert();
+ r_file_list.reverse();
break;
default: // FILE_SORT_NAME
break;
@@ -944,8 +944,41 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
fpath = fpath.substr(0, fpath.length() - 1);
}
} else if (fpath != "Favorites") {
+ if (FileAccess::exists(fpath + ".import")) {
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(fpath + ".import");
+ if (err == OK) {
+ if (config->has_section_key("remap", "importer")) {
+ String importer = config->get_value("remap", "importer");
+ if (importer == "keep") {
+ EditorNode::get_singleton()->show_warning(TTR("Importing has been disabled for this file, so it can't be opened for editing."));
+ return;
+ }
+ }
+ }
+ }
+
if (ResourceLoader::get_resource_type(fpath) == "PackedScene") {
- editor->open_request(fpath);
+ bool is_imported = false;
+
+ {
+ List<String> importer_exts;
+ ResourceImporterScene::get_singleton()->get_recognized_extensions(&importer_exts);
+ String extension = fpath.get_extension();
+ for (List<String>::Element *E = importer_exts.front(); E; E = E->next()) {
+ if (extension.nocasecmp_to(E->get()) == 0) {
+ is_imported = true;
+ break;
+ }
+ }
+ }
+
+ if (is_imported) {
+ ResourceImporterScene::get_singleton()->show_advanced_options(fpath);
+ } else {
+ editor->open_request(fpath);
+ }
} else {
editor->load_resource(fpath);
}
@@ -1411,15 +1444,31 @@ void FileSystemDock::_make_scene_confirm() {
void FileSystemDock::_file_removed(String p_file) {
emit_signal("file_removed", p_file);
- path = "res://";
+ // Find the closest parent directory available, in case multiple items were deleted along the same path.
+ path = p_file.get_base_dir();
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ while (!da->dir_exists(path)) {
+ path = path.get_base_dir();
+ }
+
current_path->set_text(path);
}
void FileSystemDock::_folder_removed(String p_folder) {
emit_signal("folder_removed", p_folder);
- path = "res://";
+ // Find the closest parent directory available, in case multiple items were deleted along the same path.
+ path = p_folder.get_base_dir();
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ while (!da->dir_exists(path)) {
+ path = path.get_base_dir();
+ }
+
current_path->set_text(path);
+ EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(path);
+ if (efd) {
+ efd->force_update();
+ }
}
void FileSystemDock::_rename_operation_confirm() {
@@ -1586,7 +1635,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
print_verbose("FileSystem: saving moved scenes.");
_save_scenes_after_move(file_renames);
- path = "res://";
+ path = p_to_path;
current_path->set_text(path);
}
}
@@ -2576,8 +2625,9 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &f
}
void FileSystemDock::_update_import_dock() {
- if (!import_dock_needs_update)
+ if (!import_dock_needs_update) {
return;
+ }
// List selected.
Vector<String> selected;
@@ -2588,8 +2638,9 @@ void FileSystemDock::_update_import_dock() {
} else {
// Use the file list.
for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i))
+ if (!files->is_selected(i)) {
continue;
+ }
selected.push_back(files->get_item_metadata(i));
}
@@ -2614,7 +2665,10 @@ void FileSystemDock::_update_import_dock() {
break;
}
- String type = cf->get_value("remap", "type");
+ String type;
+ if (cf->has_section_key("remap", "type")) {
+ type = cf->get_value("remap", "type");
+ }
if (import_type == "") {
import_type = type;
} else if (import_type != type) {
@@ -2706,7 +2760,22 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
// `KEY_MASK_CMD | KEY_C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D);
+
+#if defined(WINDOWS_ENABLED)
+ // TRANSLATORS: This string is only used on Windows, as it refers to the system trash
+ // as "Recycle Bin" instead of "Trash". Make sure to use the translation of "Recycle Bin"
+ // recommended by Microsoft for the target language.
+ ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Recycle Bin"), KEY_DELETE);
+#elif defined(OSX_ENABLED)
+ // TRANSLATORS: This string is only used on macOS, as it refers to the system trash
+ // as "Bin" instead of "Trash". Make sure to use the translation of "Bin"
+ // recommended by Apple for the target language.
+ ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Bin"), KEY_DELETE);
+#else
+ // TRANSLATORS: This string is only used on platforms other than Windows and macOS.
ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Trash"), KEY_DELETE);
+#endif
+
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), KEY_F2);
VBoxContainer *top_vbc = memnew(VBoxContainer);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index c2f2254023..47079a92b7 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -463,7 +463,7 @@ void FindInFilesDialog::_notification(int p_what) {
for (int i = 0; i < _filters_container->get_child_count(); i++) {
_filters_container->get_child(i)->queue_delete();
}
- Array exts = ProjectSettings::get_singleton()->get("editor/search_in_file_extensions");
+ Array exts = ProjectSettings::get_singleton()->get("editor/script/search_in_file_extensions");
for (int i = 0; i < exts.size(); ++i) {
CheckBox *cb = memnew(CheckBox);
cb->set_text(exts[i]);
@@ -687,6 +687,9 @@ void FindInFilesPanel::stop_search() {
void FindInFilesPanel::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
_progress_bar->set_as_ratio(_finder->get_progress());
+ } else if (p_what == NOTIFICATION_THEME_CHANGED) {
+ _search_text_label->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
+ _results_display->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
}
}
diff --git a/editor/icons/ColorPickerBarArrow.svg b/editor/icons/ColorPickerBarArrow.svg
new file mode 100644
index 0000000000..9d034106ee
--- /dev/null
+++ b/editor/icons/ColorPickerBarArrow.svg
@@ -0,0 +1 @@
+<svg height="20" viewBox="0 0 16 20" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 16h12l-6-6z" fill="#e0e0e0" stroke-width="2"/></svg>
diff --git a/editor/icons/FontSize.svg b/editor/icons/FontSize.svg
new file mode 100644
index 0000000000..e608d89b6a
--- /dev/null
+++ b/editor/icons/FontSize.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="SmallerT"><rect x="1.047" y="7.127" width="6.025" height="1.2" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="3.452" y="7.127" width="1.214" height="6.508" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="2.238" y="13.171" width="3.643" height="0.465" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M1.477,7.127l0,2.4l-0.43,0l-0,-2.4l0.43,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M7.071,7.127l0,2.4l-0.43,0l0,-2.4l0.43,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M1.477,8.327l0,1.2c0,-0.658 0.389,-1.2 0.861,-1.2l-0.861,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.78,8.327c0.473,0 0.861,0.542 0.861,1.2l0,-1.2l-0.861,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M2.238,13.171c0.666,-0 1.214,-0.42 1.214,-0.93l0,0.93l-1.214,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.88,13.171c-0.666,-0 -1.214,-0.42 -1.214,-0.93l0,0.93l1.214,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/></g><g id="BiggerT"><rect x="4.563" y="2.873" width="10.773" height="1.539" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="9.18" y="2.873" width="1.539" height="10.773" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="7.641" y="12.877" width="4.617" height="0.769" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.332,2.873l0,3.078l-0.769,0l-0,-3.078l0.769,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M15.336,2.873l-0,3.078l-0.77,0l0,-3.078l0.77,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.332,4.412l0,1.539c0,-0.844 0.695,-1.539 1.539,-1.539l-1.539,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M13.027,4.412c0.844,0 1.539,0.695 1.539,1.539l0,-1.539l-1.539,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M7.641,12.877c0.844,-0 1.539,-0.695 1.539,-1.539l-0,1.539l-1.539,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M12.258,12.877c-0.845,-0 -1.539,-0.695 -1.539,-1.539l-0,1.539l1.539,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/></g></svg>
diff --git a/editor/icons/GPUParticlesAttractorBox.svg b/editor/icons/GPUParticlesAttractorBox.svg
new file mode 100644
index 0000000000..3c27b2d3cb
--- /dev/null
+++ b/editor/icons/GPUParticlesAttractorBox.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fc9c9c" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc9c9c" stroke-opacity=".996078"><ellipse cx="8" cy="-8" rx="2.339226" ry="4.949748" transform="rotate(90)"/><ellipse cx="8" cy="8" rx="2.339226" ry="4.949748"/><path d="m1.498906 1.498906h13.002189v13.002188h-13.002189z" stroke-width=".997813"/></g></svg>
diff --git a/editor/icons/GPUParticlesAttractorSphere.svg b/editor/icons/GPUParticlesAttractorSphere.svg
new file mode 100644
index 0000000000..5473a23854
--- /dev/null
+++ b/editor/icons/GPUParticlesAttractorSphere.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-8" cy="-7.999999" fill="none" rx="6.499003" ry="6.499001" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.002" transform="scale(-1)"/><circle cx="8" cy="8" fill="#fc9c9c" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc9c9c" stroke-opacity=".996078"><ellipse cx="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 .70710678 -.70710678 .70710678 0 0)"/><ellipse cy="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 0)"/></g></svg>
diff --git a/editor/icons/GPUParticlesAttractorVectorField.svg b/editor/icons/GPUParticlesAttractorVectorField.svg
new file mode 100644
index 0000000000..93a29789e3
--- /dev/null
+++ b/editor/icons/GPUParticlesAttractorVectorField.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="6.663637" cy="9.245457" fill="#fc9c9c" fill-opacity=".996078" rx="1.030661" ry=".998146"/><ellipse cx="-6.672815" cy="-9.387111" fill="none" rx="2.408711" ry="5.096776" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.99999945 .00104887 .00104887 -.99999945 0 0)"/><ellipse cx="9.387111" cy="-6.672815" fill="none" rx="2.408711" ry="5.096776" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.00104887 .99999945 -.99999945 .00104887 0 0)"/><g fill="#fc9c9c" fill-opacity=".996078"><path d="m11.8 15 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/><path d="m11 6 3-3 1 1v-3h-3l1 1-3 3z"/><path d="m1.8 5 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionBox.svg b/editor/icons/GPUParticlesCollisionBox.svg
new file mode 100644
index 0000000000..f7296b34c3
--- /dev/null
+++ b/editor/icons/GPUParticlesCollisionBox.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c" fill-opacity=".996078"><path d="m7.5 2.8124998-5.5883107 2.7941554v5.7660988l5.5883107 2.794155 5.588311-2.794155v-5.7660988zm0 1.6886278 3.145021 1.5732692-3.145021 1.5717523-3.1450214-1.5717523zm-3.9916505 2.8362274 3.1933204 1.5966602v3.1465378l-3.1933204-1.598256zm7.9833015 0v3.145021l-3.1933209 1.598257v-3.146538z" stroke-width=".851579"/><circle cx="1.875" cy="3.75" r=".9375"/><circle cx="13.124999" cy="3.75" r=".9375"/><circle cx="9.374999" cy="1.875" r=".9375"/><circle cx="5.625" cy="1.875" r=".9375"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionHeightField.svg b/editor/icons/GPUParticlesCollisionHeightField.svg
new file mode 100644
index 0000000000..b483f299e9
--- /dev/null
+++ b/editor/icons/GPUParticlesCollisionHeightField.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c"><path d="m1 10c1-1 3-2 3-4s2-4 4-4 4 2 4 4 2 3 3 4l-7 5z"/><circle cx="2" cy="6" r="1"/><circle cx="14" cy="6" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="4" cy="2" r="1"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionSDF.svg b/editor/icons/GPUParticlesCollisionSDF.svg
new file mode 100644
index 0000000000..6279990f3a
--- /dev/null
+++ b/editor/icons/GPUParticlesCollisionSDF.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 14h-12v-9s3 4 5.9999999 3.9999999c3.0000001-.0000001 6.0000001-3.9999999 6.0000001-3.9999999z" fill="none" stroke="#fc9c9c" stroke-linejoin="round" stroke-opacity=".996078" stroke-width="2"/><g fill="#fc9c9c" fill-opacity=".996078"><circle cx="2" cy="2" r="1"/><circle cx="14" cy="2" r="1"/><circle cx="10" cy="5" r="1"/><circle cx="6" cy="5" r="1"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionSphere.svg b/editor/icons/GPUParticlesCollisionSphere.svg
new file mode 100644
index 0000000000..fc7715445c
--- /dev/null
+++ b/editor/icons/GPUParticlesCollisionSphere.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c" fill-opacity=".996078"><path d="m8 3.0532484c-3.2888554 0-5.9733758 2.6845204-5.9733758 5.9733758 0 3.2889408 2.6845204 5.9733758 5.9733758 5.9733758 3.288855 0 5.973376-2.684435 5.973376-5.9733758 0-3.2888554-2.684521-5.9733758-5.973376-5.9733758zm-.8533394 1.79005v4.1567016c-1.1034532-.0608789-2.2238878-.2544573-3.3650586-.5900074.256693-1.7901354 1.6087154-3.2141029 3.3650586-3.5667027zm1.7066788 0c1.7535276.3520281 3.1035956 1.77213 3.3633516 3.55834-1.113266.3129793-2.2321649.5142138-3.3633516.5866709zm3.2300606 5.3599956c-.434043 1.51792-1.663927 2.690664-3.2300606 3.005035v-2.518376c1.0915918-.0617 2.1691036-.227875 3.2300606-.486668zm-8.161765.015c1.0865571.272147 2.162106.428504 3.2250256.480003v2.510013c-1.5608431-.313338-2.7870065-1.479605-3.2250256-2.990016z" stroke-width=".853339"/><circle cx="2" cy="5" r="1"/><circle cx="14" cy="5" r="1"/><circle cx="10" cy="2" r="1"/><circle cx="6" cy="2" r="1"/></g></svg>
diff --git a/editor/icons/GuiScrollBg.svg b/editor/icons/GuiScrollBg.svg
index dd5c60e534..7cfe647368 100644
--- a/editor/icons/GuiScrollBg.svg
+++ b/editor/icons/GuiScrollBg.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"/>
+<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".082353" r="2"/></svg>
diff --git a/editor/icons/GuiScrollGrabber.svg b/editor/icons/GuiScrollGrabber.svg
index 16edfb567c..935f9361dd 100644
--- a/editor/icons/GuiScrollGrabber.svg
+++ b/editor/icons/GuiScrollGrabber.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".27451" r="2"/></svg>
+<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".294118" r="3"/></svg>
diff --git a/editor/icons/LargeTexture.svg b/editor/icons/LargeTexture.svg
deleted file mode 100644
index 137a761e1d..0000000000
--- a/editor/icons/LargeTexture.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 1v1 2h1v-2h2v-1zm11 0v1h2v2h1v-3zm-3 5v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-1-1h-1v-1zm-8 6v2 1h3v-1h-2v-2zm13 0v2h-2v1h3v-1-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Logo.svg b/editor/icons/Logo.svg
index d7aef39cc9..a4ad488396 100644
--- a/editor/icons/Logo.svg
+++ b/editor/icons/Logo.svg
@@ -1 +1 @@
-<svg height="69" viewBox="0 0 187 69" width="187" xmlns="http://www.w3.org/2000/svg"><path d="m91.912 19.51c-3.5233 0-6.278 1.1097-8.2676 3.3281-1.9911 2.2193-2.9844 5.1004-2.9844 8.6465 0 4.1636 1.0165 7.3207 3.0508 9.4707 2.0379 2.1497 4.7123 3.2227 8.0293 3.2227 1.7838 0 3.3686-.15384 4.752-.46289 1.3848-.30784 2.3038-.62367 2.7617-.94336l.13867-10.736c0-.62388-1.6471-.90785-3.4941-.93945-1.847-.02857-3.9609.35742-3.9609.35742v3.6055h2.125l-.023438 1.6055c0 .59532-.59062.89453-1.7676.89453-1.1785 0-2.2182-.4989-3.1211-1.4941-.90498-.99645-1.3555-2.4517-1.3555-4.3711 0-1.9233.43964-3.3428 1.3203-4.2578.87885-.9141 2.0322-1.3711 3.4492-1.3711.59532 0 1.2107.095008 1.8516.29102.64121.19418 1.0686.37639 1.2871.54688.21667.17534.42435.25781.61914.25781.19388 0 .50715-.22698.94141-.68555.43487-.45735.82427-1.1501 1.168-2.0742.34218-.92899.51367-1.6414.51367-2.1465 0-.50111-.011023-.84501-.033203-1.0273-.48045-.52573-1.3668-.94394-2.6602-1.2539-1.2909-.30906-2.7387-.46289-4.3398-.46289zm21.049 0c-3.2367 0-5.8788 1.0413-7.9258 3.1211-2.0464 2.0826-3.0703 5.1404-3.0703 9.1797 0 4.0369 1.0128 7.1085 3.0352 9.2129 2.0251 2.1026 4.6444 3.1543 7.8574 3.1543 3.2145 0 5.8383-1.0111 7.875-3.0332 2.0367-2.0263 3.0527-5.1142 3.0527-9.2656 0-4.1484-.99433-7.2508-2.9863-9.2969-1.9884-2.05-4.6018-3.0723-7.8379-3.0723zm45.504 0c-3.2379 0-5.8792 1.0413-7.9277 3.1211-2.0461 2.0826-3.0684 5.1404-3.0684 9.1797 0 4.0369 1.0104 7.1085 3.0352 9.2129 2.0233 2.1026 4.6432 3.1543 7.8574 3.1543 3.213 0 5.8373-1.0111 7.873-3.0332 2.0364-2.0263 3.0547-5.1142 3.0547-9.2656 0-4.1484-.9939-7.2508-2.9844-9.2969-1.9908-2.05-4.6031-3.0723-7.8398-3.0723zm-30.105.30859c-.45888 0-.82988.16637-1.1152.49609-.28717.33489-.42969.78715-.42969 1.3594v20.584c0 1.053.58624 1.5781 1.752 1.5781h5.8652c7.1824-.000001 10.773-4.2092 10.773-12.627 0-3.9348-.94335-6.8151-2.832-8.6445-1.8853-1.83-4.6472-2.7461-8.2832-2.7461h-5.7305zm42.807 0c-.38928 0-.66468.52801-.82422 1.5801-.0687.50294-.10157 1.0191-.10157 1.543 0 .52694.03287 1.0409.10157 1.543.15954 1.0548.43494 1.5801.82422 1.5801h4.1152v17.225c0 .45462 1.1351.68555 3.3984.68555 2.2655 0 3.3965-.23093 3.3965-.68555v-17.225h4.0137c.38868 0 .66225-.52528.82422-1.5801.0672-.50202.10156-1.016.10156-1.543.00001-.52391-.03436-1.04-.10156-1.543-.16197-1.0521-.43554-1.5801-.82422-1.5801h-14.924zm-58.291 6.2793c1.0989 0 2.0193.49244 2.7617 1.4746.74331.98339 1.1152 2.3913 1.1152 4.2207 0 1.8309-.35955 3.2363-1.0801 4.2188-.72053.98612-1.6597 1.4785-2.8145 1.4785-1.1554 0-2.0859-.48441-2.7949-1.459-.71019-.97154-1.0644-2.3663-1.0644-4.1875 0-1.8173.37148-3.2302 1.1133-4.2363.74574-1.0053 1.6663-1.5098 2.7637-1.5098zm45.504 0c1.0989 0 2.0181.49244 2.7617 1.4746.74331.98339 1.1152 2.3913 1.1152 4.2207 0 1.8309-.3612 3.2363-1.082 4.2188-.71961.98612-1.6574 1.4785-2.8125 1.4785-1.1554 0-2.0888-.48441-2.7969-1.459-.70806-.97154-1.0625-2.3663-1.0625-4.1875 0-1.8173.37179-3.2302 1.1133-4.2363.74453-1.0053 1.666-1.5098 2.7637-1.5098zm-24.977.23828h.34375c1.4638 0 2.5334.33466 3.209.99805.6722.66157 1.0098 2.0859 1.0098 4.2715 0 2.1847-.32289 3.7447-.97656 4.6816-.65214.9378-1.6059 1.4082-2.8652 1.4082-.34218 0-.54909-.063339-.61719-.18945-.06873-.12672-.10352-.42897-.10352-.9082v-10.262z" fill="#fff"/><path d="m137.91 48.551v1.2109h.85938v-1.2109zm-52.396.58984c-.99736 0-1.7963.32424-2.3926.96484-.59745.64576-.89453 1.5712-.89453 2.7773v3.0742c0 1.2329.31639 2.1765.94727 2.832.6333.66066 1.467.98828 2.5039.98828.78586 0 1.4321-.16147 1.9414-.48633.50993-.32273.8592-.67938 1.0488-1.0684v-3.6875h-3.0059v.74805h2.1465v2.6934c-.13766.30115-.38143.55386-.73242.76172-.34978.2109-.8171.31445-1.3984.31445-.79619 0-1.4265-.2632-1.8945-.78711-.46799-.52786-.70312-1.2936-.70312-2.2988v-3.0918c0-.96941.21778-1.7078.65234-2.2168.43578-.51023 1.0297-.76367 1.7812-.76367.74271 0 1.3056.19019 1.6836.56641.38017.37925.58276.91542.61133 1.6113h.79492l.013672-.041016c-.024311-.90802-.30456-1.6179-.83789-2.127-.53484-.50719-1.2907-.76367-2.2656-.76367zm7.6133 2.6641c-.719 0-1.3111.22524-1.7715.67773-.46222.45371-.68069.96571-.6582 1.5449l.013672.041015.79688.007813c0-.42696.14768-.78487.44336-1.0781.2966-.29508.67455-.44141 1.1328-.44141.4926 0 .87459.15388 1.1523.45898.27198.30906.41016.73655.41016 1.2793v.94531h-1.3418c-.85666 0-1.5379.21084-2.0391.63477-.50142.42392-.75195.99502-.75195 1.707 0 .67372.17358 1.2075.51758 1.6035.34613.39445.83497.5918 1.4707.5918.45462 0 .86723-.12355 1.2383-.37305.37166-.24767.67317-.56424.90625-.94531 0 .17413.01089.34527.03125.51758.02097.16927.053163.38614.095703.65234h.88867c-.062302-.24767-.10234-.49621-.12695-.75391-.02401-.25436-.037109-.52051-.037109-.79492v-3.7676c0-.80622-.21809-1.4265-.65234-1.8613-.43669-.43061-1.0083-.64648-1.7188-.64648zm7.1152 0c-.45462 0-.85109.11505-1.1875.3457-.33519.23369-.60486.56357-.80664.99023l-.074219-1.1934h-.75195v7.6816h.85352v-5.5293c.11791-.47346.31244-.84655.58594-1.1191.27168-.27107.63379-.4082 1.082-.4082.4689 0 .83314.19466 1.0957.58789.26378.39323.39258 1.0508.39258 1.9707v4.498h.85351v-4.6211-.19922c.0623-.64455.23396-1.1785.51172-1.6055.27927-.42696.66855-.63672 1.166-.63672.47285 0 .83879.19223 1.0938.57422.25345.38138.38281 1.0443.38281 1.9863v4.502h.85742v-4.4863c0-1.1332-.18468-1.9728-.55664-2.5195-.37044-.54548-.89268-.81836-1.5664-.81836-.48897 0-.91182.1465-1.2598.43945-.34796.29234-.61537.69589-.80469 1.207-.148-.55369-.38151-.966-.69726-1.2383-.31543-.2732-.70589-.4082-1.1699-.4082zm10.316 0c-.74423-.000001-1.3797.32125-1.9082.96094-.52725.64273-.78906 1.4505-.78906 2.4199v1.2754c0 .96758.26259 1.762.7871 2.3828.52604.62206 1.2032.93359 2.0312.93359.5157 0 .95833-.090281 1.3242-.26562.36679-.17626.66658-.41287.89844-.70703l-.34961-.60547c-.21728.27441-.4784.4836-.7832.63281-.3048.14586-.66987.2207-1.0898.2207-.60443 0-1.0864-.24489-1.4414-.74023-.35433-.49412-.53321-1.1138-.53321-1.8574v-.63867h4.3965v-.84375c0-.96667-.22381-1.7371-.66992-2.3105-.44519-.57253-1.0684-.85742-1.873-.85742zm9.4727 0c-.74423-.000001-1.3782.32125-1.9082.96094-.52603.64273-.79101 1.4505-.79101 2.4199v1.2754c0 .96758.26241 1.762.78906 2.3828.52512.62206 1.2028.93359 2.0312.93359.51601 0 .95639-.090281 1.3223-.26562.36741-.17626.66822-.41287.90039-.70703l-.34766-.60547c-.21972.27441-.4811.4836-.78711.63281-.30389.14586-.66639.2207-1.0879.2207-.60656 0-1.0883-.24489-1.4414-.74023-.35646-.49412-.5332-1.1138-.5332-1.8574v-.63867h4.3945v-.84375c0-.96667-.22338-1.7371-.66797-2.3105-.44398-.57253-1.0699-.85742-1.873-.85742zm6.8672 0c-.45614 0-.85274.12451-1.1894.36914-.33975.24342-.60962.5923-.81445 1.043l-.07031-1.2695h-.76172v7.6816h.85351v-5.4824c.14617-.47923.36569-.85918.66016-1.1445.29325-.28809.65767-.42969 1.0938-.42969.48622 0 .85922.17765 1.1133.5332.25557.35555.38477.96807.38477 1.8457v4.6777h.85937v-4.6855c0-1.0736-.18381-1.866-.55273-2.375-.36497-.50993-.89-.76367-1.5762-.76367zm6.2539 0c-.77674 0-1.386.32888-1.8242.98437-.44186.65883-.66211 1.5326-.66211 2.6211l.00196 1.0508c0 1.0031.21834 1.8072.65625 2.4102.43699.60413 1.0429.90625 1.8144.90625.41602 0 .78387-.091234 1.0996-.27539.31695-.18324.58484-.4491.80273-.79492v.92969c0 .75881-.14785 1.3303-.4414 1.7266-.29235.39111-.74301.58789-1.3535.58789-.30359 0-.59763-.04082-.88086-.125-.28565-.081443-.54279-.19619-.77344-.3457l-.23632.74805c.27047.15164.57916.27315.92773.36523.34795.092075.67388.13867.97656.13867.84208 0 1.494-.27297 1.9531-.81055.45857-.53971.68554-1.3009.68554-2.2852v-7.6895h-.72265l-.08399 1.0684c-.21485-.38533-.48269-.68758-.80664-.89453-.32334-.2109-.70159-.31641-1.1328-.31641zm10.467 0c-.45401 0-.85062.12451-1.1895.36914-.33914.24342-.60902.5923-.81445 1.043l-.07031-1.2695h-.75977v7.6816h.85352v-5.4824c.14556-.47923.3663-.85918.66016-1.1445.29295-.28809.65797-.42969 1.0937-.42969.48775 0 .85711.17765 1.1133.5332.25496.35555.38476.96807.38476 1.8457v4.6777h.85742v-4.6855c0-1.0736-.18081-1.866-.54882-2.375-.36588-.50993-.8939-.76367-1.5801-.76367zm6.4043 0c-.74271-.000001-1.3778.32125-1.9062.96094-.52724.64273-.79101 1.4505-.79101 2.4199v1.2754c0 .96758.26334 1.762.78906 2.3828.52361.62206 1.2007.93359 2.0312.93359.5154 0 .9567-.090281 1.3223-.26562.3668-.17626.6667-.41287.90039-.70703l-.34961-.60547c-.2194.27441-.47958.4836-.78711.63281-.30359.14586-.66597.2207-1.0859.2207-.60717 0-1.089-.24489-1.4434-.74023-.35464-.49412-.5332-1.1138-.5332-1.8574v-.63867h4.3965v-.84375c0-.96667-.22369-1.7371-.66797-2.3105-.44551-.57253-1.0709-.85742-1.875-.85742zm-12.113.14258v7.6816h.85938v-7.6816zm-27.352.60938c.53029 0 .9445.20789 1.2441.62695.29781.41876.44531.94616.44531 1.5801v.33008h-3.543c.01429-.71688.19281-1.3186.53711-1.8066.34401-.48622.78217-.73047 1.3164-.73047zm9.4727 0c.52998 0 .94406.20789 1.2422.62695.29963.41876.44727.94616.44727 1.5801v.33008h-3.543c.0155-.71688.19298-1.3186.53516-1.8066.3437-.48622.7826-.73047 1.3184-.73047zm29.992 0c.53089 0 .94602.20789 1.2441.62695.29902.41876.44532.94616.44532 1.5801v.33008h-3.543c.01519-.71688.19402-1.3186.53711-1.8066.34218-.48622.78064-.73047 1.3164-.73047zm-16.686.015625c.42119 0 .77033.1246 1.0469.375.27684.25466.4967.58706.65625.99609v3.8047c-.16593.39718-.39.70872-.67383.93359-.28475.22488-.63089.33594-1.043.33594-.6014 0-1.0536-.22975-1.3496-.69531-.29964-.4613-.44727-1.0819-.44727-1.8613v-1.0508c0-.84177.15149-1.527.45508-2.0527.30146-.52482.75528-.78516 1.3555-.78516zm-40.057 3.3281h1.3652v1.6621c-.15286.42089-.40964.76752-.77734 1.041-.3671.27228-.78783.40625-1.2598.40625-.39262 0-.69782-.12824-.91602-.38867-.2185-.25952-.32617-.59591-.32617-1.0059 0-.48531.17262-.89402.52148-1.2207.34795-.32881.81215-.49414 1.3926-.49414z" fill="#e0e0e0"/><path d="m27 3c-3.0948.68801-6.1571 1.6452-9.0273 3.0898.06564 2.5344.23035 4.963.5625 7.4297-1.1147.71414-2.287 1.3281-3.3281 2.1641-1.0578.81382-2.1378 1.5912-3.0957 2.543-1.9136-1.2657-3.9389-2.454-6.0254-3.5039-2.2491 2.4205-4.3524 5.0317-6.0703 7.9551 1.2924 2.0908 2.6428 4.0523 4.0996 5.9121h.041016v14.438 1.834 1.6699c.03282.000304.06514.000806.097656.003906l11 1.0605c.57617.05561 1.0282.52027 1.0684 1.0977l.33789 4.8555 9.5957.68359.66016-4.4805c.0857-.58104.58415-1.0117 1.1719-1.0117h11.605c.58742 0 1.0862.43068 1.1719 1.0117l.66016 4.4805 9.5957-.68359.33789-4.8555c.04042-.57739.49219-1.0417 1.0684-1.0977l10.996-1.0605c.032519-.003.064836-.003606.097656-.003906v-1.4316l.003906-.001953v-16.508h.041016c1.4571-1.8598 2.8066-3.8214 4.0996-5.9121-1.7173-2.9234-3.8232-5.5346-6.0723-7.9551-2.0859 1.0499-4.1118 2.2382-6.0254 3.5039-.95756-.95178-2.0363-1.7292-3.0957-2.543-1.0408-.836-2.2136-1.4499-3.3262-2.1641.33124-2.4667.49656-4.8952.5625-7.4297-2.8706-1.4447-5.933-2.4018-9.0293-3.0898-1.2362 2.0777-2.367 4.3278-3.3516 6.5273-1.1675-.1951-2.3391-.26727-3.5137-.28125v-.0019532c-.0082 0-.016447.0019531-.023437.0019532-.0073 0-.014194-.0019532-.021484-.0019532v.0019532c-1.1767.013979-2.3497.086153-3.5176.28125-.98399-2.1996-2.1135-4.4497-3.3516-6.5273zm-22.863 45.904c.0045599 1.063.019531 2.2271.019531 2.459 0 10.446 13.251 15.468 29.715 15.525h.019531.019531c16.464-.05774 29.711-5.0795 29.711-15.525 0-.23612.014661-1.3954.019531-2.459l-9.8867.95312-.3418 4.8809c-.04102.58833-.50933 1.0574-1.0977 1.0996l-11.717.83594c-.02857.0021-.055724.003906-.083984.003906-.58225 0-1.0859-.42704-1.1719-1.0117l-.67188-4.5566h-9.5586l-.67188 4.5566c-.09025.61325-.63836 1.0531-1.2559 1.0078l-11.717-.83594c-.58833-.04224-1.0566-.51128-1.0977-1.0996l-.3418-4.8809-9.8906-.95312z" fill="#478cbf"/><path d="m18.299 29.246c-3.6594 0-6.6289 2.9669-6.6289 6.627 0 3.6625 2.9695 6.6289 6.6289 6.6289 3.6613 0 6.627-2.9664 6.627-6.6289 0-3.66-2.9657-6.627-6.627-6.627zm31.186 0c-3.6619 0-6.6289 2.9669-6.6289 6.627 0 3.6625 2.967 6.6289 6.6289 6.6289 3.6591 0 6.627-2.9664 6.627-6.6289 0-3.66-2.9678-6.627-6.627-6.627zm-15.594 3.8789c-1.1785 0-2.1348.86781-2.1348 1.9375v6.1035c0 1.0706.95628 1.9395 2.1348 1.9395s2.1348-.86885 2.1348-1.9395v-6.1035c0-1.0697-.95628-1.9375-2.1348-1.9375z" fill="#f6f6f6"/><path d="m18.932 31.865c-2.4299 0-4.4004 1.9711-4.4004 4.4004s1.9705 4.3984 4.4004 4.3984c2.4311 0 4.4004-1.9691 4.4004-4.3984s-1.9693-4.4004-4.4004-4.4004zm29.916 0c-2.4293 0-4.3984 1.9711-4.3984 4.4004s1.9691 4.3984 4.3984 4.3984c2.4317 0 4.4004-1.9691 4.4004-4.3984s-1.9687-4.4004-4.4004-4.4004z" fill="#414042"/></svg>
+<svg height="69" viewBox="0 0 187 69" width="187" xmlns="http://www.w3.org/2000/svg"><path d="m91.912 19.51c-3.5233 0-6.278 1.1097-8.2676 3.3281-1.9911 2.2193-2.9844 5.1004-2.9844 8.6465 0 4.1636 1.0165 7.3207 3.0508 9.4707 2.0379 2.1497 4.7123 3.2227 8.0293 3.2227 1.7838 0 3.3686-.15384 4.752-.46289 1.3848-.30784 2.3038-.62367 2.7617-.94336l.13867-10.736c0-.62388-1.6471-.90785-3.4941-.93945-1.847-.02857-3.9609.35742-3.9609.35742v3.6055h2.125l-.023438 1.6055c0 .59532-.59062.89453-1.7676.89453-1.1785 0-2.2182-.4989-3.1211-1.4941-.90498-.99645-1.3555-2.4517-1.3555-4.3711 0-1.9233.43964-3.3428 1.3203-4.2578.87885-.9141 2.0322-1.3711 3.4492-1.3711.59532 0 1.2107.095008 1.8516.29102.64121.19418 1.0686.37639 1.2871.54688.21667.17534.42435.25781.61914.25781.19388 0 .50715-.22698.94141-.68555.43487-.45735.82427-1.1501 1.168-2.0742.34218-.92899.51367-1.6414.51367-2.1465 0-.50111-.011023-.84501-.033203-1.0273-.48045-.52573-1.3668-.94394-2.6602-1.2539-1.2909-.30906-2.7387-.46289-4.3398-.46289zm21.049 0c-3.2367 0-5.8788 1.0413-7.9258 3.1211-2.0464 2.0826-3.0703 5.1404-3.0703 9.1797 0 4.0369 1.0128 7.1085 3.0352 9.2129 2.0251 2.1026 4.6444 3.1543 7.8574 3.1543 3.2145 0 5.8383-1.0111 7.875-3.0332 2.0367-2.0263 3.0527-5.1142 3.0527-9.2656 0-4.1484-.99433-7.2508-2.9863-9.2969-1.9884-2.05-4.6018-3.0723-7.8379-3.0723zm45.504 0c-3.2379 0-5.8792 1.0413-7.9277 3.1211-2.0461 2.0826-3.0684 5.1404-3.0684 9.1797 0 4.0369 1.0104 7.1085 3.0352 9.2129 2.0233 2.1026 4.6432 3.1543 7.8574 3.1543 3.213 0 5.8373-1.0111 7.873-3.0332 2.0364-2.0263 3.0547-5.1142 3.0547-9.2656 0-4.1484-.9939-7.2508-2.9844-9.2969-1.9908-2.05-4.6031-3.0723-7.8398-3.0723zm-30.105.30859c-.45888 0-.82988.16637-1.1152.49609-.28717.33489-.42969.78715-.42969 1.3594v20.584c0 1.053.58624 1.5781 1.752 1.5781h5.8652c7.1824-.000001 10.773-4.2092 10.773-12.627 0-3.9348-.94335-6.8151-2.832-8.6445-1.8853-1.83-4.6472-2.7461-8.2832-2.7461h-5.7305zm42.807 0c-.38928 0-.66468.52801-.82422 1.5801-.0687.50294-.10157 1.0191-.10157 1.543 0 .52694.03287 1.0409.10157 1.543.15954 1.0548.43494 1.5801.82422 1.5801h4.1152v17.225c0 .45462 1.1351.68555 3.3984.68555 2.2655 0 3.3965-.23093 3.3965-.68555v-17.225h4.0137c.38868 0 .66225-.52528.82422-1.5801.0672-.50202.10156-1.016.10156-1.543.00001-.52391-.03436-1.04-.10156-1.543-.16197-1.0521-.43554-1.5801-.82422-1.5801h-14.924zm-58.291 6.2793c1.0989 0 2.0193.49244 2.7617 1.4746.74331.98339 1.1152 2.3913 1.1152 4.2207 0 1.8309-.35955 3.2363-1.0801 4.2188-.72053.98612-1.6597 1.4785-2.8145 1.4785-1.1554 0-2.0859-.48441-2.7949-1.459-.71019-.97154-1.0644-2.3663-1.0644-4.1875 0-1.8173.37148-3.2302 1.1133-4.2363.74574-1.0053 1.6663-1.5098 2.7637-1.5098zm45.504 0c1.0989 0 2.0181.49244 2.7617 1.4746.74331.98339 1.1152 2.3913 1.1152 4.2207 0 1.8309-.3612 3.2363-1.082 4.2188-.71961.98612-1.6574 1.4785-2.8125 1.4785-1.1554 0-2.0888-.48441-2.7969-1.459-.70806-.97154-1.0625-2.3663-1.0625-4.1875 0-1.8173.37179-3.2302 1.1133-4.2363.74453-1.0053 1.666-1.5098 2.7637-1.5098zm-24.977.23828h.34375c1.4638 0 2.5334.33466 3.209.99805.6722.66157 1.0098 2.0859 1.0098 4.2715 0 2.1847-.32289 3.7447-.97656 4.6816-.65214.9378-1.6059 1.4082-2.8652 1.4082-.34218 0-.54909-.063339-.61719-.18945-.06873-.12672-.10352-.42897-.10352-.9082v-10.262z" fill="#fff"/><path d="m137.91 48.551v1.2109h.85938v-1.2109zm-52.396.58984c-.99736 0-1.7963.32424-2.3926.96484-.59745.64576-.89453 1.5712-.89453 2.7773v3.0742c0 1.2329.31639 2.1765.94727 2.832.6333.66066 1.467.98828 2.5039.98828.78586 0 1.4321-.16147 1.9414-.48633.50993-.32273.8592-.67938 1.0488-1.0684v-3.6875h-3.0059v.74805h2.1465v2.6934c-.13766.30115-.38143.55386-.73242.76172-.34978.2109-.8171.31445-1.3984.31445-.79619 0-1.4265-.2632-1.8945-.78711-.46799-.52786-.70312-1.2936-.70312-2.2988v-3.0918c0-.96941.21778-1.7078.65234-2.2168.43578-.51023 1.0297-.76367 1.7812-.76367.74271 0 1.3056.19019 1.6836.56641.38017.37925.58276.91542.61133 1.6113h.79492l.013672-.041016c-.024311-.90802-.30456-1.6179-.83789-2.127-.53484-.50719-1.2907-.76367-2.2656-.76367zm7.6133 2.6641c-.719 0-1.3111.22524-1.7715.67773-.46222.45371-.68069.96571-.6582 1.5449l.013672.041015.79688.007813c0-.42696.14768-.78487.44336-1.0781.2966-.29508.67455-.44141 1.1328-.44141.4926 0 .87459.15388 1.1523.45898.27198.30906.41016.73655.41016 1.2793v.94531h-1.3418c-.85666 0-1.5379.21084-2.0391.63477-.50142.42392-.75195.99502-.75195 1.707 0 .67372.17358 1.2075.51758 1.6035.34613.39445.83497.5918 1.4707.5918.45462 0 .86723-.12355 1.2383-.37305.37166-.24767.67317-.56424.90625-.94531 0 .17413.01089.34527.03125.51758.02097.16927.053163.38614.095703.65234h.88867c-.062302-.24767-.10234-.49621-.12695-.75391-.02401-.25436-.037109-.52051-.037109-.79492v-3.7676c0-.80622-.21809-1.4265-.65234-1.8613-.43669-.43061-1.0083-.64648-1.7188-.64648zm7.1152 0c-.45462 0-.85109.11505-1.1875.3457-.33519.23369-.60486.56357-.80664.99023l-.074219-1.1934h-.75195v7.6816h.85352v-5.5293c.11791-.47346.31244-.84655.58594-1.1191.27168-.27107.63379-.4082 1.082-.4082.4689 0 .83314.19466 1.0957.58789.26378.39323.39258 1.0508.39258 1.9707v4.498h.85351v-4.6211-.19922c.0623-.64455.23396-1.1785.51172-1.6055.27927-.42696.66855-.63672 1.166-.63672.47285 0 .83879.19223 1.0938.57422.25345.38138.38281 1.0443.38281 1.9863v4.502h.85742v-4.4863c0-1.1332-.18468-1.9728-.55664-2.5195-.37044-.54548-.89268-.81836-1.5664-.81836-.48897 0-.91182.1465-1.2598.43945-.34796.29234-.61537.69589-.80469 1.207-.148-.55369-.38151-.966-.69726-1.2383-.31543-.2732-.70589-.4082-1.1699-.4082zm10.316 0c-.74423-.000001-1.3797.32125-1.9082.96094-.52725.64273-.78906 1.4505-.78906 2.4199v1.2754c0 .96758.26259 1.762.7871 2.3828.52604.62206 1.2032.93359 2.0312.93359.5157 0 .95833-.090281 1.3242-.26562.36679-.17626.66658-.41287.89844-.70703l-.34961-.60547c-.21728.27441-.4784.4836-.7832.63281-.3048.14586-.66987.2207-1.0898.2207-.60443 0-1.0864-.24489-1.4414-.74023-.35433-.49412-.53321-1.1138-.53321-1.8574v-.63867h4.3965v-.84375c0-.96667-.22381-1.7371-.66992-2.3105-.44519-.57253-1.0684-.85742-1.873-.85742zm9.4727 0c-.74423-.000001-1.3782.32125-1.9082.96094-.52603.64273-.79101 1.4505-.79101 2.4199v1.2754c0 .96758.26241 1.762.78906 2.3828.52512.62206 1.2028.93359 2.0312.93359.51601 0 .95639-.090281 1.3223-.26562.36741-.17626.66822-.41287.90039-.70703l-.34766-.60547c-.21972.27441-.4811.4836-.78711.63281-.30389.14586-.66639.2207-1.0879.2207-.60656 0-1.0883-.24489-1.4414-.74023-.35646-.49412-.5332-1.1138-.5332-1.8574v-.63867h4.3945v-.84375c0-.96667-.22338-1.7371-.66797-2.3105-.44398-.57253-1.0699-.85742-1.873-.85742zm6.8672 0c-.45614 0-.85274.12451-1.1894.36914-.33975.24342-.60962.5923-.81445 1.043l-.07031-1.2695h-.76172v7.6816h.85351v-5.4824c.14617-.47923.36569-.85918.66016-1.1445.29325-.28809.65767-.42969 1.0938-.42969.48622 0 .85922.17765 1.1133.5332.25557.35555.38477.96807.38477 1.8457v4.6777h.85937v-4.6855c0-1.0736-.18381-1.866-.55273-2.375-.36497-.50993-.89-.76367-1.5762-.76367zm6.2539 0c-.77674 0-1.386.32888-1.8242.98437-.44186.65883-.66211 1.5326-.66211 2.6211l.00196 1.0508c0 1.0031.21834 1.8072.65625 2.4102.43699.60413 1.0429.90625 1.8144.90625.41602 0 .78387-.091234 1.0996-.27539.31695-.18324.58484-.4491.80273-.79492v.92969c0 .75881-.14785 1.3303-.4414 1.7266-.29235.39111-.74301.58789-1.3535.58789-.30359 0-.59763-.04082-.88086-.125-.28565-.081443-.54279-.19619-.77344-.3457l-.23632.74805c.27047.15164.57916.27315.92773.36523.34795.092075.67388.13867.97656.13867.84208 0 1.494-.27297 1.9531-.81055.45857-.53971.68554-1.3009.68554-2.2852v-7.6895h-.72265l-.08399 1.0684c-.21485-.38533-.48269-.68758-.80664-.89453-.32334-.2109-.70159-.31641-1.1328-.31641zm10.467 0c-.45401 0-.85062.12451-1.1895.36914-.33914.24342-.60902.5923-.81445 1.043l-.07031-1.2695h-.75977v7.6816h.85352v-5.4824c.14556-.47923.3663-.85918.66016-1.1445.29295-.28809.65797-.42969 1.0937-.42969.48775 0 .85711.17765 1.1133.5332.25496.35555.38476.96807.38476 1.8457v4.6777h.85742v-4.6855c0-1.0736-.18081-1.866-.54882-2.375-.36588-.50993-.8939-.76367-1.5801-.76367zm6.4043 0c-.74271-.000001-1.3778.32125-1.9062.96094-.52724.64273-.79101 1.4505-.79101 2.4199v1.2754c0 .96758.26334 1.762.78906 2.3828.52361.62206 1.2007.93359 2.0312.93359.5154 0 .9567-.090281 1.3223-.26562.3668-.17626.6667-.41287.90039-.70703l-.34961-.60547c-.2194.27441-.47958.4836-.78711.63281-.30359.14586-.66597.2207-1.0859.2207-.60717 0-1.089-.24489-1.4434-.74023-.35464-.49412-.5332-1.1138-.5332-1.8574v-.63867h4.3965v-.84375c0-.96667-.22369-1.7371-.66797-2.3105-.44551-.57253-1.0709-.85742-1.875-.85742zm-12.113.14258v7.6816h.85938v-7.6816zm-27.352.60938c.53029 0 .9445.20789 1.2441.62695.29781.41876.44531.94616.44531 1.5801v.33008h-3.543c.01429-.71688.19281-1.3186.53711-1.8066.34401-.48622.78217-.73047 1.3164-.73047zm9.4727 0c.52998 0 .94406.20789 1.2422.62695.29963.41876.44727.94616.44727 1.5801v.33008h-3.543c.0155-.71688.19298-1.3186.53516-1.8066.3437-.48622.7826-.73047 1.3184-.73047zm29.992 0c.53089 0 .94602.20789 1.2441.62695.29902.41876.44532.94616.44532 1.5801v.33008h-3.543c.01519-.71688.19402-1.3186.53711-1.8066.34218-.48622.78064-.73047 1.3164-.73047zm-16.686.015625c.42119 0 .77033.1246 1.0469.375.27684.25466.4967.58706.65625.99609v3.8047c-.16593.39718-.39.70872-.67383.93359-.28475.22488-.63089.33594-1.043.33594-.6014 0-1.0536-.22975-1.3496-.69531-.29964-.4613-.44727-1.0819-.44727-1.8613v-1.0508c0-.84177.15149-1.527.45508-2.0527.30146-.52482.75528-.78516 1.3555-.78516zm-40.057 3.3281h1.3652v1.6621c-.15286.42089-.40964.76752-.77734 1.041-.3671.27228-.78783.40625-1.2598.40625-.39262 0-.69782-.12824-.91602-.38867-.2185-.25952-.32617-.59591-.32617-1.0059 0-.48531.17262-.89402.52148-1.2207.34795-.32881.81215-.49414 1.3926-.49414z" fill="#e0e0e0"/><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(.30389749 0 0 -.30389749 63.620953 46.532114)"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164715 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426579-6.973692 9.2079702-13.9828876 13.621-19.449z" fill="#478cbf" transform="matrix(.30389749 0 0 -.30389749 4.154146 28.589689)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(.30389749 0 0 -.30389749 53.752732 49.859089)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(.30389749 0 0 -.30389749 24.925648 35.87311)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(.30389749 0 0 -.30389749 23.330605 36.266305)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(.30389749 0 0 -.30389749 33.889273 43.105751)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(.30389749 0 0 -.30389749 42.854008 35.87311)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(.30389749 0 0 -.30389749 44.449454 36.266305)"/></svg>
diff --git a/editor/icons/NodeDisabled.svg b/editor/icons/NodeDisabled.svg
new file mode 100644
index 0000000000..b2d51fc4fb
--- /dev/null
+++ b/editor/icons/NodeDisabled.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#999"/></svg>
diff --git a/editor/icons/PickerCursor.svg b/editor/icons/PickerCursor.svg
new file mode 100644
index 0000000000..88ee3f55ce
--- /dev/null
+++ b/editor/icons/PickerCursor.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 1a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#fff"/><path d="m8 3a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 5-5 5 5 0 0 0 -5-5zm-.0605469 1a4 4 0 0 1 .0605469 0 4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 3.9394531-4z"/></svg>
diff --git a/editor/icons/ThemeRemoveAllItems.svg b/editor/icons/ThemeRemoveAllItems.svg
new file mode 100644
index 0000000000..47ed624d04
--- /dev/null
+++ b/editor/icons/ThemeRemoveAllItems.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M8,1.745c-0.595,0 -1.084,0.489 -1.084,1.084l0,3.699l-3.851,-1.927c-0.163,-0.08 -0.343,-0.119 -0.525,-0.112c-0.395,0.015 -0.752,0.244 -0.929,0.597c-0.076,0.151 -0.115,0.317 -0.115,0.485c0,0.41 0.233,0.786 0.599,0.97l3.481,1.74l-3.481,1.74c-0.366,0.184 -0.599,0.56 -0.599,0.97c0,0.168 0.039,0.334 0.115,0.485c0.183,0.367 0.559,0.599 0.969,0.599c0.168,0 0.334,-0.039 0.485,-0.114l3.851,-1.927l0,3.111c0,0.594 0.489,1.084 1.084,1.084c0.595,-0 1.084,-0.49 1.084,-1.084l-0,-3.111l3.851,1.927c0.151,0.075 0.317,0.114 0.485,0.114c0.41,0 0.786,-0.232 0.969,-0.599c0.076,-0.151 0.115,-0.317 0.115,-0.485c-0,-0.41 -0.233,-0.786 -0.599,-0.97l-3.481,-1.74l3.481,-1.74c0.366,-0.184 0.599,-0.56 0.599,-0.97c-0,-0.168 -0.039,-0.334 -0.115,-0.485c-0.182,-0.364 -0.554,-0.596 -0.961,-0.599c-0.171,-0.001 -0.34,0.038 -0.493,0.114l-3.851,1.927l-0,-3.699c-0,-0.595 -0.489,-1.084 -1.084,-1.084Z" style="fill:#a5efac;"/><path d="M8,1.745c-0,0 -0,1.783 -0,1.783l-1.084,0l0,-0.699c0,-0.595 0.489,-1.084 1.084,-1.084Z" style="fill:#ff7070;fill-rule:nonzero;"/><path d="M1.528,5.312l2.957,-0l-1.42,-0.711c-0.163,-0.08 -0.343,-0.119 -0.525,-0.112c-0.395,0.015 -0.752,0.244 -0.929,0.597c-0.036,0.072 -0.064,0.148 -0.083,0.226Zm5.388,-1.784l1.084,0l-0,1.784l-1.084,-0l0,-1.784Z" style="fill:#ffeb70;fill-rule:nonzero;"/><path d="M6.916,5.312l1.084,-0l-0,1.783l-4.796,0l-1.109,-0.554c-0.366,-0.184 -0.599,-0.56 -0.599,-0.97c0,-0.088 0.011,-0.175 0.032,-0.259l2.957,-0l2.431,1.216l0,-1.216Z" style="fill:#9dff70;fill-rule:nonzero;"/><path d="M3.204,7.095l4.796,0l-0,1.783l-3.619,0l1.195,-0.597l-2.372,-1.186Z" style="fill:#70ffb9;fill-rule:nonzero;"/><path d="M4.381,8.878l3.619,0l-0,1.784l-1.084,-0l0,-0.628l-1.255,0.628l-4.114,-0c0.088,-0.274 0.283,-0.508 0.548,-0.641l2.286,-1.143Z" style="fill:#70deff;fill-rule:nonzero;"/><path d="M6.916,12.445l1.084,0l-0,1.784l-0,-0c-0.595,-0.001 -1.084,-0.49 -1.084,-1.084l0,-0.7Z" style="fill:#ff70ac;fill-rule:nonzero;"/><path d="M6.916,10.662l1.084,-0l-0,1.783l-1.084,0l0,-1.783Zm-1.255,-0l-4.114,-0c-0.033,0.105 -0.051,0.216 -0.051,0.329c0,0.168 0.039,0.334 0.115,0.485c0.183,0.367 0.559,0.599 0.969,0.599c0.168,0 0.334,-0.039 0.485,-0.114l2.596,-1.299Z" style="fill:#9f70ff;fill-rule:nonzero;"/></svg>
diff --git a/editor/icons/ThemeRemoveCustomItems.svg b/editor/icons/ThemeRemoveCustomItems.svg
new file mode 100644
index 0000000000..bb8a8bd026
--- /dev/null
+++ b/editor/icons/ThemeRemoveCustomItems.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M11.299,3c0.772,0.513 1.42,1.199 1.888,2l-2.553,0c-0.706,-0.621 -1.629,-1 -2.634,-1c-1.005,0 -1.928,0.379 -2.634,1l-2.553,0c0.468,-0.801 1.116,-1.487 1.888,-2l6.598,-0Z" style="fill:#ffeb70;fill-rule:nonzero;"/><path d="M5.366,5c-0.593,0.522 -1.033,1.216 -1.238,2l-2.043,0c0.122,-0.717 0.373,-1.392 0.728,-2l2.553,-0Zm7.821,-0c0.355,0.608 0.606,1.283 0.728,2l-2.043,0c-0.205,-0.784 -0.645,-1.478 -1.238,-2l2.553,-0Z" style="fill:#9dff70;fill-rule:nonzero;"/><path d="M13.915,7c0.056,0.326 0.085,0.66 0.085,1c-0,0.34 -0.029,0.674 -0.085,1l-2.043,0c0.083,-0.32 0.128,-0.655 0.128,-1c0,-0.345 -0.045,-0.68 -0.128,-1l2.043,-0Zm-9.787,0c-0.083,0.32 -0.128,0.655 -0.128,1c0,0.345 0.045,0.68 0.128,1l-2.043,-0c-0.056,-0.326 -0.085,-0.66 -0.085,-1c0,-0.34 0.029,-0.674 0.085,-1l2.043,0Z" style="fill:#70ffb9;fill-rule:nonzero;"/><path d="M4.128,9c0.205,0.784 0.645,1.478 1.238,2l-2.553,0c-0.355,-0.608 -0.606,-1.283 -0.728,-2l2.043,0Zm9.787,0c-0.122,0.717 -0.373,1.392 -0.728,2l-2.553,0c0.593,-0.522 1.033,-1.216 1.238,-2l2.043,0Z" style="fill:#70deff;fill-rule:nonzero;"/><path d="M11.299,13l-6.598,0c0.949,0.631 2.084,1 3.299,1c1.215,0 2.35,-0.369 3.299,-1Z" style="fill:#ff70ac;fill-rule:nonzero;"/><path d="M13.187,11c-0.468,0.801 -1.116,1.487 -1.888,2l-6.598,0c-0.772,-0.513 -1.42,-1.199 -1.888,-2l2.553,0c0.706,0.621 1.629,1 2.634,1c1.005,0 1.928,-0.379 2.634,-1l2.553,0Z" style="fill:#9f70ff;fill-rule:nonzero;"/><path d="M4.701,3l6.598,0c-0.949,-0.631 -2.084,-1 -3.299,-1c-1.215,0 -2.35,0.369 -3.299,1Z" style="fill:#ff7070;fill-rule:nonzero;"/></svg>
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 50b13673fa..d3183e5a8d 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -79,6 +79,9 @@ struct ColladaImport {
Vector<int> valid_animated_properties;
Map<String, bool> bones_with_animation;
+ Set<String> mesh_unique_names;
+ Set<String> material_unique_names;
+
Error _populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
Error _create_scene_skeletons(Collada::Node *p_node);
Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
@@ -326,12 +329,25 @@ Error ColladaImport::_create_material(const String &p_target) {
Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ String base_name;
if (src_mat.name != "") {
- material->set_name(src_mat.name);
+ base_name = src_mat.name;
} else if (effect.name != "") {
- material->set_name(effect.name);
+ base_name = effect.name;
+ } else {
+ base_name = "Material";
}
+ String name = base_name;
+ int counter = 2;
+ while (material_unique_names.has(name)) {
+ name = base_name + itos(counter++);
+ }
+
+ material_unique_names.insert(name);
+
+ material->set_name(name);
+
// DIFFUSE
if (effect.diffuse.texture != "") {
@@ -681,7 +697,8 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
int vertex_index = p.indices[src + vertex_ofs]; //used for index field (later used by controllers)
int vertex_pos = (vertex_src->stride ? vertex_src->stride : 3) * vertex_index;
- ERR_FAIL_INDEX_V(vertex_pos, vertex_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(vertex_pos + 0, vertex_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(vertex_pos + 2, vertex_src->array.size(), ERR_INVALID_DATA);
vertex.vertex = Vector3(vertex_src->array[vertex_pos + 0], vertex_src->array[vertex_pos + 1], vertex_src->array[vertex_pos + 2]);
if (pre_weights.has(vertex_index)) {
@@ -690,16 +707,19 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
if (normal_src) {
int normal_pos = (normal_src->stride ? normal_src->stride : 3) * p.indices[src + normal_ofs];
- ERR_FAIL_INDEX_V(normal_pos, normal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(normal_pos + 0, normal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(normal_pos + 2, normal_src->array.size(), ERR_INVALID_DATA);
vertex.normal = Vector3(normal_src->array[normal_pos + 0], normal_src->array[normal_pos + 1], normal_src->array[normal_pos + 2]);
if (tangent_src && binormal_src) {
int binormal_pos = (binormal_src->stride ? binormal_src->stride : 3) * p.indices[src + binormal_ofs];
- ERR_FAIL_INDEX_V(binormal_pos, binormal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(binormal_pos + 0, binormal_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(binormal_pos + 2, binormal_src->array.size(), ERR_INVALID_DATA);
Vector3 binormal = Vector3(binormal_src->array[binormal_pos + 0], binormal_src->array[binormal_pos + 1], binormal_src->array[binormal_pos + 2]);
int tangent_pos = (tangent_src->stride ? tangent_src->stride : 3) * p.indices[src + tangent_ofs];
- ERR_FAIL_INDEX_V(tangent_pos, tangent_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(tangent_pos + 0, tangent_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(tangent_pos + 2, tangent_src->array.size(), ERR_INVALID_DATA);
Vector3 tangent = Vector3(tangent_src->array[tangent_pos + 0], tangent_src->array[tangent_pos + 1], tangent_src->array[tangent_pos + 2]);
vertex.tangent.normal = tangent;
@@ -709,19 +729,22 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
if (uv_src) {
int uv_pos = (uv_src->stride ? uv_src->stride : 2) * p.indices[src + uv_ofs];
- ERR_FAIL_INDEX_V(uv_pos, uv_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv_pos + 0, uv_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv_pos + 1, uv_src->array.size(), ERR_INVALID_DATA);
vertex.uv = Vector3(uv_src->array[uv_pos + 0], 1.0 - uv_src->array[uv_pos + 1], 0);
}
if (uv2_src) {
int uv2_pos = (uv2_src->stride ? uv2_src->stride : 2) * p.indices[src + uv2_ofs];
- ERR_FAIL_INDEX_V(uv2_pos, uv2_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv2_pos + 0, uv2_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(uv2_pos + 1, uv2_src->array.size(), ERR_INVALID_DATA);
vertex.uv2 = Vector3(uv2_src->array[uv2_pos + 0], 1.0 - uv2_src->array[uv2_pos + 1], 0);
}
if (color_src) {
int color_pos = (color_src->stride ? color_src->stride : 3) * p.indices[src + color_ofs]; // colors are RGB in collada..
- ERR_FAIL_INDEX_V(color_pos, color_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(color_pos + 0, color_src->array.size(), ERR_INVALID_DATA);
+ ERR_FAIL_INDEX_V(color_pos + ((color_src->stride > 3) ? 3 : 2), color_src->array.size(), ERR_INVALID_DATA);
vertex.color = Color(color_src->array[color_pos + 0], color_src->array[color_pos + 1], color_src->array[color_pos + 2], (color_src->stride > 3) ? color_src->array[color_pos + 3] : 1.0);
}
@@ -1121,7 +1144,22 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
- mesh->set_name(meshdata.name);
+ String name = meshdata.name;
+ if (name == "") {
+ name = "Mesh";
+ }
+ int counter = 2;
+ while (mesh_unique_names.has(name)) {
+ name = meshdata.name;
+ if (name == "") {
+ name = "Mesh";
+ }
+ name += itos(counter++);
+ }
+
+ mesh_unique_names.insert(name);
+
+ mesh->set_name(name);
Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials);
ERR_FAIL_COND_V_MSG(err, err, "Cannot create mesh surface.");
@@ -1638,16 +1676,23 @@ void EditorSceneImporterCollada::get_extensions(List<String> *r_extensions) cons
}
Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+ if (r_err) {
+ *r_err = OK;
+ }
ColladaImport state;
uint32_t flags = Collada::IMPORT_FLAG_SCENE;
if (p_flags & IMPORT_ANIMATION) {
flags |= Collada::IMPORT_FLAG_ANIMATION;
}
- state.use_mesh_builtin_materials = !(p_flags & IMPORT_MATERIALS_IN_INSTANCES);
+ state.use_mesh_builtin_materials = true;
state.bake_fps = p_bake_fps;
- Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & EditorSceneImporter::IMPORT_USE_COMPRESSION);
+ Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, false);
+
+ if (r_err) {
+ *r_err = err;
+ }
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
@@ -1667,7 +1712,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
}
if (p_flags & IMPORT_ANIMATION) {
- state.create_animations(p_flags & IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
+ state.create_animations(true, true);
AnimationPlayer *ap = memnew(AnimationPlayer);
for (int i = 0; i < state.animations.size(); i++) {
String name;
@@ -1677,12 +1722,6 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
name = state.animations[i]->get_name();
}
- if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
- if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
- state.animations.write[i]->set_loop(true);
- }
- }
-
ap->add_animation(name, state.animations[i]);
}
state.scene->add_child(ap);
@@ -1700,7 +1739,7 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
- state.create_animations(p_flags & EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS, p_flags & EditorSceneImporter::IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
+ state.create_animations(true, true);
if (state.scene) {
memdelete(state.scene);
}
@@ -1709,12 +1748,6 @@ Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path
return Ref<Animation>();
}
Ref<Animation> anim = state.animations[0];
- String base = p_path.get_basename().to_lower();
- if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) {
- if (base.begins_with("loop") || base.ends_with("loop") || base.begins_with("cycle") || base.ends_with("cycle")) {
- anim->set_loop(true);
- }
- }
return anim;
}
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 7ea39ab3ef..4a4d9d8f06 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -32,7 +32,7 @@
#include "core/io/resource_saver.h"
#include "core/os/file_access.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
String ResourceImporterCSVTranslation::get_importer_name() const {
@@ -126,7 +126,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
Ref<Translation> xlt = translations[i];
if (compress) {
- Ref<PHashTranslation> cxl = memnew(PHashTranslation);
+ Ref<OptimizedTranslation> cxl = memnew(OptimizedTranslation);
cxl->generate(xlt);
xlt = cxl;
}
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index 3139ef5146..6d2215c379 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -391,8 +391,8 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
bool ok_on_pc = false;
bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
- bool can_bptc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc");
- bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc");
+ bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc");
+ bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc");
if (can_bptc) {
formats_imported.push_back("bptc"); //needs to be aded anyway
@@ -447,13 +447,13 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
ok_on_pc = true;
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
+ if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) {
_save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true);
r_platform_variants->push_back("etc2");
formats_imported.push_back("etc2");
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
+ if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc")) {
_save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true);
r_platform_variants->push_back("pvrtc");
formats_imported.push_back("pvrtc");
@@ -492,7 +492,7 @@ String ResourceImporterLayeredTexture::get_import_settings_string() const {
int index = 0;
while (compression_formats[index]) {
- String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]);
+ String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
bool test = ProjectSettings::get_singleton()->get(setting_path);
if (test) {
s += String(compression_formats[index]);
@@ -524,7 +524,7 @@ bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_p
int index = 0;
bool valid = true;
while (compression_formats[index]) {
- String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]);
+ String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
bool test = ProjectSettings::get_singleton()->get(setting_path);
if (test) {
if (formats_imported.find(compression_formats[index]) == -1) {
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 9111252943..dd62c72d8a 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -427,7 +427,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
List<Ref<Mesh>> meshes;
- Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & IMPORT_USE_COMPRESSION, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
+ Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
if (err != OK) {
if (r_err) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 9944712931..4bb56beaeb 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -32,10 +32,12 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
+#include "editor/import/scene_import_settings.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/area_3d.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/navigation_3d.h"
+#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/vehicle_body_3d.h"
#include "scene/animation/animation_player.h"
@@ -111,20 +113,14 @@ void EditorSceneImporter::_bind_methods() {
BIND_CONSTANT(IMPORT_SCENE);
BIND_CONSTANT(IMPORT_ANIMATION);
- BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP);
- BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE);
- BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
- BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
- BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
- BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES);
- BIND_CONSTANT(IMPORT_USE_COMPRESSION);
+ BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
+ BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS);
}
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
- ClassDB::bind_method(D_METHOD("get_source_folder"), &EditorScenePostImport::get_source_folder);
ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
}
@@ -136,16 +132,11 @@ Node *EditorScenePostImport::post_import(Node *p_scene) {
return p_scene;
}
-String EditorScenePostImport::get_source_folder() const {
- return source_folder;
-}
-
String EditorScenePostImport::get_source_file() const {
return source_file;
}
-void EditorScenePostImport::init(const String &p_source_folder, const String &p_source_file) {
- source_folder = p_source_folder;
+void EditorScenePostImport::init(const String &p_source_file) {
source_file = p_source_file;
}
@@ -183,29 +174,9 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
}
-
- if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0) {
- return false;
- }
-
- if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
- return false;
- }
-
- if (p_option.begins_with("animation/clip_")) {
- int max_clip = p_options["animation/clips/amount"];
- int clip = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
- if (clip >= max_clip) {
- return false;
- }
- }
- }
-
- if (p_option == "materials/keep_on_reimport" && int(p_options["materials/storage"]) == 0) {
- return false;
}
- if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
+ if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 3) {
return false;
}
@@ -213,34 +184,11 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
}
int ResourceImporterScene::get_preset_count() const {
- return PRESET_MAX;
+ return 0;
}
String ResourceImporterScene::get_preset_name(int p_idx) const {
- switch (p_idx) {
- case PRESET_SINGLE_SCENE:
- return TTR("Import as Single Scene");
- case PRESET_SEPARATE_ANIMATIONS:
- return TTR("Import with Separate Animations");
- case PRESET_SEPARATE_MATERIALS:
- return TTR("Import with Separate Materials");
- case PRESET_SEPARATE_MESHES:
- return TTR("Import with Separate Objects");
- case PRESET_SEPARATE_MESHES_AND_MATERIALS:
- return TTR("Import with Separate Objects+Materials");
- case PRESET_SEPARATE_MESHES_AND_ANIMATIONS:
- return TTR("Import with Separate Objects+Animations");
- case PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS:
- return TTR("Import with Separate Materials+Animations");
- case PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS:
- return TTR("Import with Separate Objects+Materials+Animations");
- case PRESET_MULTIPLE_SCENES:
- return TTR("Import as Multiple Scenes");
- case PRESET_MULTIPLE_SCENES_AND_MATERIALS:
- return TTR("Import as Multiple Scenes+Materials");
- }
-
- return "";
+ return String();
}
static bool _teststr(const String &p_what, const String &p_str) {
@@ -286,6 +234,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
}
static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+ ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
if (!p_convex) {
Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
@@ -299,10 +248,25 @@ static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_l
}
}
-Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode) {
+static void _pre_gen_shape_list(const Ref<EditorSceneImporterMesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+ ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
+ if (!p_convex) {
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ r_shape_list.push_back(shape);
+ } else {
+ Vector<Ref<Shape3D>> cd = mesh->convex_decompose();
+ if (cd.size()) {
+ for (int i = 0; i < cd.size(); i++) {
+ r_shape_list.push_back(cd[i]);
+ }
+ }
+ }
+}
+
+Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *r = _fix_node(p_node->get_child(i), p_root, collision_map, p_light_bake_mode);
+ Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map);
if (!r) {
i--; //was erased
}
@@ -317,33 +281,29 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return nullptr;
}
- if (Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> m = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
if (m.is_valid()) {
for (int i = 0; i < m->get_surface_count(); i++) {
- Ref<StandardMaterial3D> mat = m->surface_get_material(i);
+ Ref<BaseMaterial3D> mat = m->get_surface_material(i);
if (!mat.is_valid()) {
continue;
}
if (_teststr(mat->get_name(), "alpha")) {
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ mat->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
mat->set_name(_fixstr(mat->get_name(), "alpha"));
}
if (_teststr(mat->get_name(), "vcol")) {
- mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ mat->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(BaseMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
mat->set_name(_fixstr(mat->get_name(), "vcol"));
}
}
}
-
- if (p_light_bake_mode != LIGHT_BAKE_DISABLED) {
- mi->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
- }
}
if (Object::cast_to<AnimationPlayer>(p_node)) {
@@ -367,6 +327,17 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
}
+
+ String animname = E->get();
+ const int loop_string_count = 3;
+ static const char *loop_strings[loop_string_count] = { "loops", "loop", "cycle" };
+ for (int i = 0; i < loop_string_count; i++) {
+ if (_teststr(animname, loop_strings[i])) {
+ anim->set_loop(true);
+ animname = _fixstr(animname, loop_strings[i]);
+ ap->rename_animation(E->get(), animname);
+ }
+ }
}
}
@@ -374,9 +345,9 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (mi) {
- Ref<Mesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -384,10 +355,10 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(name, "colonly")) {
- _gen_shape_list(mesh, shapes, false);
+ _pre_gen_shape_list(mesh, shapes, false);
collision_map[mesh] = shapes;
} else if (_teststr(name, "convcolonly")) {
- _gen_shape_list(mesh, shapes, true);
+ _pre_gen_shape_list(mesh, shapes, true);
collision_map[mesh] = shapes;
}
@@ -407,16 +378,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
memdelete(p_node);
p_node = col;
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(col->get_owner());
- idx++;
- }
+ _add_shapes(col, shapes);
}
}
@@ -433,34 +395,30 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
BoxShape3D *boxShape = memnew(BoxShape3D);
boxShape->set_size(Vector3(2, 2, 2));
colshape->set_shape(boxShape);
- colshape->set_name("BoxShape3D");
} else if (empty_draw_type == "SINGLE_ARROW") {
RayShape3D *rayShape = memnew(RayShape3D);
rayShape->set_length(1);
colshape->set_shape(rayShape);
- colshape->set_name("RayShape3D");
Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
} else if (empty_draw_type == "IMAGE") {
WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
colshape->set_shape(world_margin_shape);
- colshape->set_name("WorldMarginShape3D");
} else {
SphereShape3D *sphereShape = memnew(SphereShape3D);
sphereShape->set_radius(1);
colshape->set_shape(sphereShape);
- colshape->set_name("SphereShape3D");
}
sb->add_child(colshape);
colshape->set_owner(sb->get_owner());
}
- } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (_teststr(name, "rigid") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
- Ref<Mesh> mesh = mi->get_mesh();
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -475,27 +433,17 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
p_node = rigid_body;
- mi->set_name("mesh");
mi->set_transform(Transform());
rigid_body->add_child(mi);
mi->set_owner(rigid_body->get_owner());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- rigid_body->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
- idx++;
- }
+ _add_shapes(rigid_body, shapes);
}
- } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<Mesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape3D>> shapes;
@@ -524,89 +472,38 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (shapes.size()) {
StaticBody3D *col = memnew(StaticBody3D);
- col->set_name("static_collision");
mi->add_child(col);
col->set_owner(mi->get_owner());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
-
- idx++;
- }
+ _add_shapes(col, shapes);
}
}
- } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (_teststr(name, "navmesh") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
if (isroot) {
return p_node;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
ERR_FAIL_COND_V(mesh.is_null(), nullptr);
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
nmi->set_name(_fixstr(name, "navmesh"));
- Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
- nmesh->create_from_mesh(mesh);
+ Ref<NavigationMesh> nmesh = mesh->create_navigation_mesh();
nmi->set_navigation_mesh(nmesh);
Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
p_node->replace_by(nmi);
memdelete(p_node);
p_node = nmi;
- } else if (_teststr(name, "vehicle")) {
- if (isroot) {
- return p_node;
- }
-
- Node *owner = p_node->get_owner();
- Node3D *s = Object::cast_to<Node3D>(p_node);
- VehicleBody3D *bv = memnew(VehicleBody3D);
- String n = _fixstr(p_node->get_name(), "vehicle");
- bv->set_name(n);
- p_node->replace_by(bv);
- p_node->set_name(n);
- bv->add_child(p_node);
- bv->set_owner(owner);
- p_node->set_owner(owner);
- bv->set_transform(s->get_transform());
- s->set_transform(Transform());
-
- p_node = bv;
-
- } else if (_teststr(name, "wheel")) {
- if (isroot) {
- return p_node;
- }
- Node *owner = p_node->get_owner();
- Node3D *s = Object::cast_to<Node3D>(p_node);
- VehicleWheel3D *bv = memnew(VehicleWheel3D);
- String n = _fixstr(p_node->get_name(), "wheel");
- bv->set_name(n);
- p_node->replace_by(bv);
- p_node->set_name(n);
- bv->add_child(p_node);
- bv->set_owner(owner);
- p_node->set_owner(owner);
- bv->set_transform(s->get_transform());
- s->set_transform(Transform());
-
- p_node = bv;
-
- } else if (Object::cast_to<MeshInstance3D>(p_node)) {
+ } else if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<ArrayMesh> mesh = mi->get_mesh();
+ Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
@@ -623,19 +520,268 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (shapes.size()) {
StaticBody3D *col = memnew(StaticBody3D);
- col->set_name("static_collision");
p_node->add_child(col);
col->set_owner(p_node->get_owner());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
+ _add_shapes(col, shapes);
+ }
+ }
+ }
+
+ return p_node;
+}
+
+Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
+ // children first
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps);
+ if (!r) {
+ i--; //was erased
+ }
+ }
+
+ bool isroot = p_node == p_root;
+
+ String import_id;
+
+ if (p_node->has_meta("import_id")) {
+ import_id = p_node->get_meta("import_id");
+ } else {
+ import_id = "PATH:" + p_root->get_path_to(p_node);
+ }
+
+ Dictionary node_settings;
+ if (p_node_data.has(import_id)) {
+ node_settings = p_node_data[import_id];
+ }
+
+ if (!isroot && (node_settings.has("import/skip_import") && bool(node_settings["import/skip_import"]))) {
+ memdelete(p_node);
+ return nullptr;
+ }
+
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+
+ if (m.is_valid()) {
+ if (!r_scanned_meshes.has(m)) {
+ for (int i = 0; i < m->get_surface_count(); i++) {
+ Ref<Material> mat = m->get_surface_material(i);
+ if (mat.is_valid()) {
+ String mat_id;
+ if (mat->has_meta("import_id")) {
+ mat_id = mat->get_meta("import_id");
+ } else {
+ mat_id = mat->get_name();
+ }
+
+ if (mat_id != String() && p_material_data.has(mat_id)) {
+ Dictionary matdata = p_material_data[mat_id];
+ if (matdata.has("use_external/enabled") && bool(matdata["use_external/enabled"]) && matdata.has("use_external/path")) {
+ String path = matdata["use_external/path"];
+ Ref<Material> external_mat = ResourceLoader::load(path);
+ if (external_mat.is_valid()) {
+ m->set_surface_material(i, external_mat);
+ }
+ }
+ }
+ }
+ }
+
+ r_scanned_meshes.insert(m);
+ }
+
+ if (node_settings.has("generate/physics")) {
+ int mesh_physics_mode = node_settings["generate/physics"];
+
+ if (mesh_physics_mode != MESH_PHYSICS_DISABLED) {
+ List<Ref<Shape3D>> shapes;
+
+ if (collision_map.has(m)) {
+ shapes = collision_map[m];
+ } else {
+ switch (mesh_physics_mode) {
+ case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: {
+ _pre_gen_shape_list(m, shapes, false);
+ } break;
+ case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
+ _pre_gen_shape_list(m, shapes, true);
+ } break;
+ case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
+ _pre_gen_shape_list(m, shapes, false);
+ } break;
+ case MESH_PHYSICS_AREA_ONLY: {
+ _pre_gen_shape_list(m, shapes, true);
+ } break;
+ }
+ }
+
+ if (shapes.size()) {
+ CollisionObject3D *base = nullptr;
+ switch (mesh_physics_mode) {
+ case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: {
+ StaticBody3D *col = memnew(StaticBody3D);
+ p_node->add_child(col);
+ base = col;
+ } break;
+ case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
+ rigid_body->set_name(p_node->get_name());
+ p_node->replace_by(rigid_body);
+ rigid_body->set_transform(mi->get_transform());
+ p_node = rigid_body;
+ mi->set_transform(Transform());
+ rigid_body->add_child(mi);
+ mi->set_owner(rigid_body->get_owner());
+ base = rigid_body;
+ } break;
+ case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
+ StaticBody3D *col = memnew(StaticBody3D);
+ col->set_transform(mi->get_transform());
+ col->set_name(p_node->get_name());
+ p_node->replace_by(col);
+ memdelete(p_node);
+ p_node = col;
+ base = col;
+ } break;
+ case MESH_PHYSICS_AREA_ONLY: {
+ Area3D *area = memnew(Area3D);
+ area->set_transform(mi->get_transform());
+ area->set_name(p_node->get_name());
+ p_node->replace_by(area);
+ memdelete(p_node);
+ p_node = area;
+ base = area;
+
+ } break;
+ }
+
+ int idx = 0;
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(E->get());
+ base->add_child(cshape);
+
+ cshape->set_owner(base->get_owner());
+ idx++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //navmesh (node may have changed type above)
+ if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
- idx++;
+ Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+
+ if (m.is_valid()) {
+ if (node_settings.has("generate/navmesh")) {
+ int navmesh_mode = node_settings["generate/navmesh"];
+
+ if (navmesh_mode != NAVMESH_DISABLED) {
+ NavigationRegion3D *nmi = memnew(NavigationRegion3D);
+
+ Ref<NavigationMesh> nmesh = m->create_navigation_mesh();
+ nmi->set_navigation_mesh(nmesh);
+
+ if (navmesh_mode == NAVMESH_NAVMESH_ONLY) {
+ nmi->set_transform(mi->get_transform());
+ p_node->replace_by(nmi);
+ memdelete(p_node);
+ p_node = nmi;
+ } else {
+ mi->add_child(nmi);
+ nmi->set_owner(mi->get_owner());
+ }
+ }
+ }
+ }
+ }
+
+ if (Object::cast_to<AnimationPlayer>(p_node)) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+
+ {
+ //make sure this is unique
+ node_settings = node_settings.duplicate(true);
+ //fill node settings for this node with default values
+ List<ImportOption> iopts;
+ get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
+ for (List<ImportOption>::Element *E = iopts.front(); E; E = E->next()) {
+ if (!node_settings.has(E->get().option.name)) {
+ node_settings[E->get().option.name] = E->get().default_value;
+ }
+ }
+ }
+
+ bool use_optimizer = node_settings["optimizer/enabled"];
+ float anim_optimizer_linerr = node_settings["optimizer/max_linear_error"];
+ float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"];
+ float anim_optimizer_maxang = node_settings["optimizer/max_angle"];
+
+ if (use_optimizer) {
+ _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
+ }
+
+ Array animation_clips;
+ {
+ int clip_count = node_settings["clips/amount"];
+
+ for (int i = 0; i < clip_count; i++) {
+ String name = node_settings["clip_" + itos(i + 1) + "/name"];
+ int from_frame = node_settings["clip_" + itos(i + 1) + "/start_frame"];
+ int end_frame = node_settings["clip_" + itos(i + 1) + "/end_frame"];
+ bool loop = node_settings["clip_" + itos(i + 1) + "/loops"];
+ bool save_to_file = node_settings["clip_" + itos(i + 1) + "/save_to_file/enabled"];
+ bool save_to_path = node_settings["clip_" + itos(i + 1) + "/save_to_file/path"];
+ bool save_to_file_keep_custom = node_settings["clip_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
+
+ animation_clips.push_back(name);
+ animation_clips.push_back(from_frame / p_animation_fps);
+ animation_clips.push_back(end_frame / p_animation_fps);
+ animation_clips.push_back(loop);
+ animation_clips.push_back(save_to_file);
+ animation_clips.push_back(save_to_path);
+ animation_clips.push_back(save_to_file_keep_custom);
+ }
+ }
+
+ if (animation_clips.size()) {
+ _create_clips(ap, animation_clips, true);
+ } else {
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
+ String name = E->get();
+ Ref<Animation> anim = ap->get_animation(name);
+ if (p_animation_data.has(name)) {
+ Dictionary anim_settings = p_animation_data[name];
+ {
+ //fill with default values
+ List<ImportOption> iopts;
+ get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION, &iopts);
+ for (List<ImportOption>::Element *F = iopts.front(); F; F = F->next()) {
+ if (!anim_settings.has(F->get().option.name)) {
+ anim_settings[F->get().option.name] = F->get().default_value;
+ }
+ }
+ }
+
+ anim->set_loop(anim_settings["settings/loops"]);
+ bool save = anim_settings["save_to_file/enabled"];
+ String path = anim_settings["save_to_file/path"];
+ bool keep_custom = anim_settings["save_to_file/keep_custom_tracks"];
+
+ Ref<Animation> saved_anim = _save_animation_to_file(anim, save, path, keep_custom);
+
+ if (saved_anim != anim) {
+ ap->add_animation(name, saved_anim); //replace
+ }
}
}
}
@@ -644,27 +790,52 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return p_node;
}
-void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, bool p_bake_all) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
+Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks) {
+ if (!p_save_to_file || !p_save_to_path.is_resource_file()) {
+ return anim;
}
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
+ if (FileAccess::exists(p_save_to_path) && p_keep_custom_tracks) {
+ // Copy custom animation tracks from previously imported files.
+ Ref<Animation> old_anim = ResourceLoader::load(p_save_to_path, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ if (old_anim.is_valid()) {
+ for (int i = 0; i < old_anim->get_track_count(); i++) {
+ if (!old_anim->track_is_imported(i)) {
+ old_anim->copy_track(i, anim);
+ }
+ }
+ anim->set_loop(old_anim->has_loop());
+ }
+ }
+ if (ResourceCache::has(p_save_to_path)) {
+ Ref<Animation> old_anim = Ref<Resource>(ResourceCache::get(p_save_to_path));
+ if (old_anim.is_valid()) {
+ old_anim->copy_from(anim);
+ anim = old_anim;
+ }
+ }
+ anim->set_path(p_save_to_path, true); // Set path to save externally.
+ Error err = ResourceSaver::save(p_save_to_path, anim, ResourceSaver::FLAG_CHANGE_PATH);
+ ERR_FAIL_COND_V_MSG(err != OK, anim, "Saving of animation failed: " + p_save_to_path);
+ return anim;
+}
+
+void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all) {
if (!anim->has_animation("default")) {
return;
}
Ref<Animation> default_anim = anim->get_animation("default");
- for (int i = 0; i < p_clips.size(); i += 4) {
+ for (int i = 0; i < p_clips.size(); i += 7) {
String name = p_clips[i];
float from = p_clips[i + 1];
float to = p_clips[i + 2];
bool loop = p_clips[i + 3];
+ bool save_to_file = p_clips[i + 4];
+ String save_to_path = p_clips[i + 5];
+ bool keep_current = p_clips[i + 6];
if (from >= to) {
continue;
}
@@ -752,141 +923,17 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
new_anim->set_loop(loop);
new_anim->set_length(to - from);
anim->add_animation(name, new_anim);
- }
-
- anim->remove_animation("default"); //remove default (no longer needed)
-}
-
-void ResourceImporterScene::_filter_anim_tracks(Ref<Animation> anim, Set<String> &keep) {
- Ref<Animation> a = anim;
- ERR_FAIL_COND(!a.is_valid());
-
- for (int j = 0; j < a->get_track_count(); j++) {
- String path = a->track_get_path(j);
- if (!keep.has(path)) {
- a->remove_track(j);
- j--;
+ Ref<Animation> saved_anim = _save_animation_to_file(new_anim, save_to_file, save_to_path, keep_current);
+ if (saved_anim != new_anim) {
+ anim->add_animation(name, saved_anim);
}
}
-}
-
-void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
- }
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
-
- Vector<String> strings = p_text.split("\n");
- for (int i = 0; i < strings.size(); i++) {
- strings.write[i] = strings[i].strip_edges();
- }
-
- List<StringName> anim_names;
- anim->get_animation_list(&anim_names);
- for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
- String name = E->get();
- bool valid_for_this = false;
- bool valid = false;
-
- Set<String> keep;
- Set<String> keep_local;
-
- for (int i = 0; i < strings.size(); i++) {
- if (strings[i].begins_with("@")) {
- valid_for_this = false;
- for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
- keep.insert(F->get());
- }
- keep_local.clear();
-
- Vector<String> filters = strings[i].substr(1, strings[i].length()).split(",");
- for (int j = 0; j < filters.size(); j++) {
- String fname = filters[j].strip_edges();
- if (fname == "") {
- continue;
- }
- int fc = fname[0];
- bool plus;
- if (fc == '+') {
- plus = true;
- } else if (fc == '-') {
- plus = false;
- } else {
- continue;
- }
- String filter = fname.substr(1, fname.length()).strip_edges();
-
- if (!name.matchn(filter)) {
- continue;
- }
- valid_for_this = plus;
- }
-
- if (valid_for_this) {
- valid = true;
- }
-
- } else if (valid_for_this) {
- Ref<Animation> a = anim->get_animation(name);
- if (!a.is_valid()) {
- continue;
- }
-
- for (int j = 0; j < a->get_track_count(); j++) {
- String path = a->track_get_path(j);
-
- String tname = strings[i];
- if (tname == "") {
- continue;
- }
- int fc = tname[0];
- bool plus;
- if (fc == '+') {
- plus = true;
- } else if (fc == '-') {
- plus = false;
- } else {
- continue;
- }
-
- String filter = tname.substr(1, tname.length()).strip_edges();
-
- if (!path.matchn(filter)) {
- continue;
- }
-
- if (plus) {
- keep_local.insert(path);
- } else if (!keep.has(path)) {
- keep_local.erase(path);
- }
- }
- }
- }
-
- if (valid) {
- for (Set<String>::Element *F = keep_local.front(); F; F = F->next()) {
- keep.insert(F->get());
- }
- _filter_anim_tracks(anim->get_animation(name), keep);
- }
- }
+ anim->remove_animation("default"); //remove default (no longer needed)
}
-void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
- if (!scene->has_node(String("AnimationPlayer"))) {
- return;
- }
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!anim);
-
+void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) {
@@ -895,208 +942,99 @@ void ResourceImporterScene::_optimize_animations(Node *scene, float p_max_lin_er
}
}
-static String _make_extname(const String &p_str) {
- String ext_name = p_str.replace(".", "_");
- ext_name = ext_name.replace(":", "_");
- ext_name = ext_name.replace("\"", "_");
- ext_name = ext_name.replace("<", "_");
- ext_name = ext_name.replace(">", "_");
- ext_name = ext_name.replace("/", "_");
- ext_name = ext_name.replace("|", "_");
- ext_name = ext_name.replace("\\", "_");
- ext_name = ext_name.replace("?", "_");
- ext_name = ext_name.replace("*", "_");
-
- return ext_name;
-}
-
-void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
- List<PropertyInfo> pi;
- p_node->get_property_list(&pi);
-
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
-
- if (mi) {
- Ref<ArrayMesh> mesh = mi->get_mesh();
-
- if (mesh.is_valid() && !meshes.has(mesh)) {
- Node3D *s = mi;
- Transform transform;
- while (s) {
- transform = transform * s->get_transform();
- s = Object::cast_to<Node3D>(s->get_parent());
+void ResourceImporterScene::get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const {
+ switch (p_category) {
+ case INTERNAL_IMPORT_CATEGORY_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/physics", PROPERTY_HINT_ENUM, "Disabled,Mesh + Static Collider,Rigid Body + Mesh,Static Collider Only,Area Only"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/navmesh", PROPERTY_HINT_ENUM, "Disabled,Mesh + NavMesh,NavMesh Only"), 0));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/make_streamable"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "settings/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+
+ for (int i = 0; i < 256; i++) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
}
-
- meshes[mesh] = transform;
+ } break;
+ default: {
}
}
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _find_meshes(p_node->get_child(i), meshes);
- }
}
-void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes) {
- List<PropertyInfo> pi;
-
- if (p_make_animations) {
- if (Object::cast_to<AnimationPlayer>(p_node)) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
-
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
- Ref<Animation> anim = ap->get_animation(E->get());
- ERR_CONTINUE(anim.is_null());
-
- if (!p_animations.has(anim)) {
- // Tracks from source file should be set as imported, anything else is a custom track.
- for (int i = 0; i < anim->get_track_count(); i++) {
- anim->track_set_imported(i, true);
- }
-
- String ext_name;
-
- if (p_animations_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim");
- }
-
- if (FileAccess::exists(ext_name) && p_keep_animations) {
- // Copy custom animation tracks from previously imported files.
- Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", true);
- if (old_anim.is_valid()) {
- for (int i = 0; i < old_anim->get_track_count(); i++) {
- if (!old_anim->track_is_imported(i)) {
- old_anim->copy_track(i, anim);
- }
- }
- anim->set_loop(old_anim->has_loop());
- }
- }
-
- anim->set_path(ext_name, true); // Set path to save externally.
- ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
- p_animations[anim] = anim;
- }
+bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const {
+ if (p_options.has("import/skip_import") && p_option != "import/skip_import" && bool(p_options["import/skip_import"])) {
+ return false; //if skip import
+ }
+ switch (p_category) {
+ case INTERNAL_IMPORT_CATEGORY_NODE: {
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE: {
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MESH: {
+ if (p_option == "save_to_file/path" || p_option == "save_to_file/make_streamable") {
+ return p_options["save_to_file/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
+ if (p_option == "use_external/path") {
+ return p_options["use_external/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
+ if (p_option == "save_to_file/path" || p_option == "save_to_file/keep_custom_tracks") {
+ return p_options["save_to_file/enabled"];
+ }
+ } break;
+ case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
+ if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) {
+ return false;
}
- }
- }
-
- p_node->get_property_list(&pi);
-
- for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
- if (E->get().type == Variant::OBJECT) {
- Ref<Material> mat = p_node->get(E->get().name);
-
- if (p_make_materials && mat.is_valid() && mat->get_name() != "") {
- if (!p_materials.has(mat)) {
- String ext_name;
-
- if (p_materials_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
- }
-
- if (p_keep_materials && FileAccess::exists(ext_name)) {
- //if exists, use it
- p_materials[mat] = ResourceLoader::load(ext_name);
- } else {
- ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
- p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
- }
- }
-
- if (p_materials[mat] != mat) {
- p_node->set(E->get().name, p_materials[mat]);
- }
- } else {
- Ref<ArrayMesh> mesh = p_node->get(E->get().name);
-
- if (mesh.is_valid()) {
- bool mesh_just_added = false;
-
- if (p_make_meshes) {
- if (!p_meshes.has(mesh)) {
- //meshes are always overwritten, keeping them is not practical
- String ext_name;
-
- if (p_meshes_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
- }
-
- ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
- p_meshes[mesh] = ResourceLoader::load(ext_name);
- p_node->set(E->get().name, p_meshes[mesh]);
- mesh_just_added = true;
- }
- }
-
- if (p_make_materials) {
- if (mesh_just_added || !p_meshes.has(mesh)) {
- for (int i = 0; i < mesh->get_surface_count(); i++) {
- mat = mesh->surface_get_material(i);
-
- if (!mat.is_valid()) {
- continue;
- }
- if (mat->get_name() == "") {
- continue;
- }
-
- if (!p_materials.has(mat)) {
- String ext_name;
-
- if (p_materials_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mat->get_name()) + ".material");
- }
-
- if (p_keep_materials && FileAccess::exists(ext_name)) {
- //if exists, use it
- p_materials[mat] = ResourceLoader::load(ext_name);
- } else {
- ResourceSaver::save(ext_name, mat, ResourceSaver::FLAG_CHANGE_PATH);
- p_materials[mat] = ResourceLoader::load(ext_name, "", true); // disable loading from the cache.
- }
- }
-
- if (p_materials[mat] != mat) {
- mesh->surface_set_material(i, p_materials[mat]);
-
- //re-save the mesh since a material is now assigned
- if (p_make_meshes) {
- String ext_name;
-
- if (p_meshes_as_text) {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".tres");
- } else {
- ext_name = p_base_path.plus_file(_make_extname(mesh->get_name()) + ".mesh");
- }
-
- ResourceSaver::save(ext_name, mesh, ResourceSaver::FLAG_CHANGE_PATH);
- p_meshes[mesh] = ResourceLoader::load(ext_name);
- }
- }
- }
- if (!p_make_meshes) {
- p_meshes[mesh] = Ref<ArrayMesh>(); //save it anyway, so it won't be checked again
- }
- }
- }
+ if (p_option.begins_with("animation/slice_")) {
+ int max_slice = p_options["animation/slices/amount"];
+ int slice = p_option.get_slice("/", 1).get_slice("_", 1).to_int() - 1;
+ if (slice >= max_slice) {
+ return false;
}
}
+ } break;
+ default: {
}
}
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_animations_as_text, p_keep_animations, p_make_materials, p_materials_as_text, p_keep_materials, p_make_meshes, p_meshes_as_text, p_animations, p_materials, p_meshes);
- }
+ return true;
}
void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, int p_preset) const {
@@ -1115,42 +1053,18 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
script_ext_hint += "*." + E->get();
}
- bool materials_out = p_preset == PRESET_SEPARATE_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
- bool meshes_out = p_preset == PRESET_SEPARATE_MESHES || p_preset == PRESET_SEPARATE_MESHES_AND_MATERIALS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
- bool scenes_out = p_preset == PRESET_MULTIPLE_SCENES || p_preset == PRESET_MULTIPLE_SCENES_AND_MATERIALS;
- bool animations_out = p_preset == PRESET_SEPARATE_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS || p_preset == PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS;
-
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/custom_script", PROPERTY_HINT_FILE, script_ext_hint), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "nodes/storage", PROPERTY_HINT_ENUM, "Single Scene,Instanced Sub-Scenes"), scenes_out ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/location", PROPERTY_HINT_ENUM, "Node,Mesh"), (meshes_out || materials_out) ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "materials/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.material),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), materials_out ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "materials/keep_on_reimport"), materials_out));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Dynamic,Static,Static Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 2));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.anim),Files (.tres)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_linear_error"), 0.05));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angular_error"), 0.01));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/optimizer/max_angle"), 22));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/remove_unused_tracks"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clips/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
- for (int i = 0; i < 256; i++) {
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/clip_" + itos(i + 1) + "/name"), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/start_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clip_" + itos(i + 1) + "/end_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/clip_" + itos(i + 1) + "/loops"), false));
- }
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), Dictionary()));
}
void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner) {
@@ -1222,7 +1136,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
-void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes) {
+void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache) {
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (src_mesh_node) {
//is mesh
@@ -1235,31 +1149,174 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, bool p_generate_lods,
Ref<ArrayMesh> mesh;
if (!src_mesh_node->get_mesh()->has_mesh()) {
//do mesh processing
- if (p_generate_lods) {
+
+ bool generate_lods = p_generate_lods;
+ bool create_shadow_meshes = p_create_shadow_meshes;
+ bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
+ String save_to_file;
+
+ String mesh_id;
+
+ if (src_mesh_node->get_mesh()->has_meta("import_id")) {
+ mesh_id = src_mesh_node->get_mesh()->get_meta("import_id");
+ } else {
+ mesh_id = src_mesh_node->get_mesh()->get_name();
+ }
+
+ if (mesh_id != String() && p_mesh_data.has(mesh_id)) {
+ Dictionary mesh_settings = p_mesh_data[mesh_id];
+
+ if (mesh_settings.has("generate/shadow_meshes")) {
+ int shadow_meshes = mesh_settings["generate/shadow_meshes"];
+ if (shadow_meshes == MESH_OVERRIDE_ENABLE) {
+ create_shadow_meshes = true;
+ } else if (shadow_meshes == MESH_OVERRIDE_DISABLE) {
+ create_shadow_meshes = false;
+ }
+ }
+
+ if (mesh_settings.has("generate/lightmap_uv")) {
+ int lightmap_uv = mesh_settings["generate/lightmap_uv"];
+ if (lightmap_uv == MESH_OVERRIDE_ENABLE) {
+ bake_lightmaps = true;
+ } else if (lightmap_uv == MESH_OVERRIDE_DISABLE) {
+ bake_lightmaps = false;
+ }
+ }
+
+ if (mesh_settings.has("generate/lods")) {
+ int lods = mesh_settings["generate/lods"];
+ if (lods == MESH_OVERRIDE_ENABLE) {
+ generate_lods = true;
+ } else if (lods == MESH_OVERRIDE_DISABLE) {
+ generate_lods = false;
+ }
+ }
+
+ if (mesh_settings.has("save_to_file/enabled") && bool(mesh_settings["save_to_file/enabled"]) && mesh_settings.has("save_to_file/path")) {
+ save_to_file = mesh_settings["save_to_file/path"];
+ if (!save_to_file.is_resource_file()) {
+ save_to_file = "";
+ }
+ }
+ }
+
+ if (generate_lods) {
src_mesh_node->get_mesh()->generate_lods();
}
- if (p_create_shadow_meshes) {
+ if (create_shadow_meshes) {
src_mesh_node->get_mesh()->create_shadow_mesh();
}
+
+ if (bake_lightmaps) {
+ Transform xf;
+ Node3D *n = src_mesh_node;
+ while (n) {
+ xf = n->get_transform() * xf;
+ n = n->get_parent_spatial();
+ }
+
+ //use xf as transform for mesh, and bake it
+ }
+
+ if (save_to_file != String()) {
+ Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file));
+ if (existing.is_valid()) {
+ //if somehow an existing one is useful, create
+ existing->reset_state();
+ }
+ mesh = src_mesh_node->get_mesh()->get_mesh(existing);
+
+ ResourceSaver::save(save_to_file, mesh); //override
+
+ mesh->set_path(save_to_file, true); //takeover existing, if needed
+
+ } else {
+ mesh = src_mesh_node->get_mesh()->get_mesh();
+ }
+ } else {
+ mesh = src_mesh_node->get_mesh()->get_mesh();
}
- mesh = src_mesh_node->get_mesh()->get_mesh();
if (mesh.is_valid()) {
mesh_node->set_mesh(mesh);
for (int i = 0; i < mesh->get_surface_count(); i++) {
- mesh_node->set_surface_material(i, src_mesh_node->get_surface_material(i));
+ mesh_node->set_surface_override_material(i, src_mesh_node->get_surface_material(i));
}
}
}
+
+ switch (p_light_bake_mode) {
+ case LIGHT_BAKE_DISABLED: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DISABLED);
+ } break;
+ case LIGHT_BAKE_DYNAMIC: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_DYNAMIC);
+ } break;
+ case LIGHT_BAKE_STATIC:
+ case LIGHT_BAKE_STATIC_LIGHTMAPS: {
+ mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED);
+ } break;
+ }
+
p_node->replace_by(mesh_node);
memdelete(p_node);
p_node = mesh_node;
}
for (int i = 0; i < p_node->get_child_count(); i++) {
- _generate_meshes(p_node->get_child(i), p_generate_lods, p_create_shadow_meshes);
+ _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_dst_lightmap_cache);
+ }
+}
+
+void ResourceImporterScene::_add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes) {
+ for (const List<Ref<Shape3D>>::Element *E = p_shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(E->get());
+ p_node->add_child(cshape);
+
+ cshape->set_owner(p_node->get_owner());
}
}
+
+Node *ResourceImporterScene::pre_import(const String &p_source_file) {
+ Ref<EditorSceneImporter> importer;
+ String ext = p_source_file.get_extension().to_lower();
+
+ EditorProgress progress("pre-import", TTR("Pre-Import Scene"), 0);
+ progress.step(TTR("Importing Scene..."), 0);
+
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
+ List<String> extensions;
+ E->get()->get_extensions(&extensions);
+
+ for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
+ if (F->get().to_lower() == ext) {
+ importer = E->get();
+ break;
+ }
+ }
+
+ if (importer.is_valid()) {
+ break;
+ }
+ }
+
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
+
+ Error err = OK;
+ Node *scene = importer->import_scene(p_source_file, EditorSceneImporter::IMPORT_ANIMATION | EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 15, nullptr, &err);
+ if (!scene || err != OK) {
+ return nullptr;
+ }
+
+ Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> collision_map;
+
+ _pre_fix_node(scene, scene, collision_map);
+
+ return scene;
+}
+
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
const String &src_path = p_source_file;
@@ -1289,27 +1346,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float fps = p_options["animation/fps"];
- int import_flags = EditorSceneImporter::IMPORT_ANIMATION_DETECT_LOOP;
- if (!bool(p_options["animation/optimizer/remove_unused_tracks"])) {
- import_flags |= EditorSceneImporter::IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS;
- }
+ int import_flags = 0;
if (bool(p_options["animation/import"])) {
import_flags |= EditorSceneImporter::IMPORT_ANIMATION;
}
- if (bool(p_options["meshes/ensure_tangents"])) {
- import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
- }
-
- if (int(p_options["materials/location"]) == 0) {
- import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
- }
-
if (bool(p_options["skins/use_named_skins"])) {
import_flags |= EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
}
+ bool ensure_tangents = p_options["meshes/ensure_tangents"];
+ if (ensure_tangents) {
+ import_flags |= EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
+ }
+
Error err = OK;
List<String> missing_deps; // for now, not much will be done with this
Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err);
@@ -1317,6 +1368,29 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return err;
}
+ Dictionary subresources = p_options["_subresources"];
+
+ Dictionary node_data;
+ if (subresources.has("nodes")) {
+ node_data = subresources["nodes"];
+ }
+
+ Dictionary material_data;
+ if (subresources.has("materials")) {
+ material_data = subresources["materials"];
+ }
+
+ Dictionary animation_data;
+ if (subresources.has("animations")) {
+ animation_data = subresources["animations"];
+ }
+
+ Set<Ref<EditorSceneImporterMesh>> scanned_meshes;
+ Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> collision_map;
+
+ _pre_fix_node(scene, scene, collision_map);
+ _post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);
+
String root_type = p_options["nodes/root_type"];
root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class.
@@ -1354,73 +1428,35 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
bool gen_lods = bool(p_options["meshes/generate_lods"]);
bool create_shadow_meshes = bool(p_options["meshes/create_shadow_meshes"]);
-
- _generate_meshes(scene, gen_lods, create_shadow_meshes);
-
- err = OK;
-
- String animation_filter = String(p_options["animation/filter_script"]).strip_edges();
-
- bool use_optimizer = p_options["animation/optimizer/enabled"];
- float anim_optimizer_linerr = p_options["animation/optimizer/max_linear_error"];
- float anim_optimizer_angerr = p_options["animation/optimizer/max_angular_error"];
- float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
int light_bake_mode = p_options["meshes/light_baking"];
+ float texel_size = p_options["meshes/lightmap_texel_size"];
+ float lightmap_texel_size = MAX(0.001, texel_size);
- Map<Ref<Mesh>, List<Ref<Shape3D>>> collision_map;
-
- scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));
-
- if (use_optimizer) {
- _optimize_animations(scene, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
- }
+ Vector<uint8_t> src_lightmap_cache;
+ Vector<uint8_t> dst_lightmap_cache;
- Array animation_clips;
{
- int clip_count = p_options["animation/clips/amount"];
-
- for (int i = 0; i < clip_count; i++) {
- String name = p_options["animation/clip_" + itos(i + 1) + "/name"];
- int from_frame = p_options["animation/clip_" + itos(i + 1) + "/start_frame"];
- int end_frame = p_options["animation/clip_" + itos(i + 1) + "/end_frame"];
- bool loop = p_options["animation/clip_" + itos(i + 1) + "/loops"];
-
- animation_clips.push_back(name);
- animation_clips.push_back(from_frame / fps);
- animation_clips.push_back(end_frame / fps);
- animation_clips.push_back(loop);
+ src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err);
+ if (err != OK) {
+ src_lightmap_cache.clear();
}
}
- if (animation_clips.size()) {
- _create_clips(scene, animation_clips, !bool(p_options["animation/optimizer/remove_unused_tracks"]));
- }
- if (animation_filter != "") {
- _filter_tracks(scene, animation_filter);
+ Dictionary mesh_data;
+ if (subresources.has("meshes")) {
+ mesh_data = subresources["meshes"];
}
+ _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, dst_lightmap_cache);
- bool external_animations = int(p_options["animation/storage"]) == 1 || int(p_options["animation/storage"]) == 2;
- bool external_animations_as_text = int(p_options["animation/storage"]) == 2;
- bool keep_custom_tracks = p_options["animation/keep_custom_tracks"];
- bool external_materials = int(p_options["materials/storage"]) == 1 || int(p_options["materials/storage"]) == 2;
- bool external_materials_as_text = int(p_options["materials/storage"]) == 2;
- bool external_meshes = int(p_options["meshes/storage"]) == 1 || int(p_options["meshes/storage"]) == 2;
- bool external_meshes_as_text = int(p_options["meshes/storage"]) == 2;
- bool external_scenes = int(p_options["nodes/storage"]) == 1;
-
- String base_path = p_source_file.get_base_dir();
-
- if (external_animations || external_materials || external_meshes || external_scenes) {
- if (bool(p_options["external_files/store_in_subdir"])) {
- String subdir_name = p_source_file.get_file().get_basename();
- DirAccess *da = DirAccess::open(base_path);
- Error err2 = da->make_dir(subdir_name);
- memdelete(da);
- ERR_FAIL_COND_V_MSG(err2 != OK && err2 != ERR_ALREADY_EXISTS, err2, "Cannot make directory '" + subdir_name + "'.");
- base_path = base_path.plus_file(subdir_name);
+ if (dst_lightmap_cache.size()) {
+ FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
+ if (f) {
+ f->store_buffer(dst_lightmap_cache.ptr(), dst_lightmap_cache.size());
}
}
+ err = OK;
+#if 0
if (light_bake_mode == 2 /* || generate LOD */) {
Map<Ref<ArrayMesh>, Transform> meshes;
_find_meshes(scene, meshes);
@@ -1445,9 +1481,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
}
- float texel_size = p_options["meshes/lightmap_texel_size"];
- texel_size = MAX(0.001, texel_size);
-
Map<String, unsigned int> used_unwraps;
EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
@@ -1469,7 +1502,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (err2 != OK) {
EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
} else {
- String hash = String::md5((unsigned char *)ret_cache_data);
+` String hash = String::md5((unsigned char *)ret_cache_data);
used_unwraps.insert(hash, ret_cache_size);
if (!ret_used_cache) {
@@ -1482,7 +1515,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
} else {
int current_size = cache_data.size();
cache_data.resize(cache_data.size() + ret_cache_size);
- unsigned char *ptrw = cache_data.ptrw();
+ unsigned char *ptrw = cache_data.ptrw();
memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
int *data = (int *)ptrw;
data[0] += 1;
@@ -1530,20 +1563,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
file->close();
}
}
-
- if (external_animations || external_materials || external_meshes) {
- Map<Ref<Animation>, Ref<Animation>> anim_map;
- Map<Ref<Material>, Ref<Material>> mat_map;
- Map<Ref<ArrayMesh>, Ref<ArrayMesh>> mesh_map;
-
- bool keep_materials = bool(p_options["materials/keep_on_reimport"]);
-
- _make_external_resources(scene, base_path, external_animations, external_animations_as_text, keep_custom_tracks, external_materials, external_materials_as_text, keep_materials, external_meshes, external_meshes_as_text, anim_map, mat_map, mesh_map);
- }
+#endif
progress.step(TTR("Running Custom Script..."), 2);
- String post_import_script_path = p_options["nodes/custom_script"];
+ String post_import_script_path = p_options["import_script/path"];
Ref<EditorScenePostImport> post_import_script;
if (post_import_script_path != "") {
@@ -1562,7 +1586,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
if (post_import_script.is_valid()) {
- post_import_script->init(base_path, p_source_file);
+ post_import_script->init(p_source_file);
scene = post_import_script->post_import(scene);
if (!scene) {
EditorNode::add_io_error(
@@ -1574,29 +1598,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
progress.step(TTR("Saving..."), 104);
- if (external_scenes) {
- //save sub-scenes as instances!
- for (int i = 0; i < scene->get_child_count(); i++) {
- Node *child = scene->get_child(i);
- if (child->get_owner() != scene) {
- continue; //not a real child probably created by scene type (ig, a scrollbar)
- }
- _replace_owner(child, scene, child);
-
- String cn = String(child->get_name()).strip_edges().replace(".", "_").replace(":", "_");
- if (cn == String()) {
- cn = "ChildNode" + itos(i);
- }
- String path = base_path.plus_file(cn + ".scn");
- child->set_filename(path);
-
- Ref<PackedScene> packer = memnew(PackedScene);
- packer->pack(child);
- err = ResourceSaver::save(path, packer); //do not take over, let the changed files reload themselves
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + path + "'.");
- }
- }
-
Ref<PackedScene> packer = memnew(PackedScene);
packer->pack(scene);
print_verbose("Saving scene to: " + p_save_path + ".scn");
@@ -1613,6 +1614,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
+bool ResourceImporterScene::ResourceImporterScene::has_advanced_options() const {
+ return true;
+}
+void ResourceImporterScene::ResourceImporterScene::show_advanced_options(const String &p_path) {
+ SceneImportSettings::get_singleton()->open_settings(p_path);
+}
+
ResourceImporterScene::ResourceImporterScene() {
singleton = this;
}
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index aced0226ff..00039f2ac6 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -39,7 +39,9 @@
#include "scene/resources/skin.h"
class Material;
+class AnimationPlayer;
+class EditorSceneImporterMesh;
class EditorSceneImporter : public Reference {
GDCLASS(EditorSceneImporter, Reference);
@@ -53,15 +55,9 @@ public:
enum ImportFlags {
IMPORT_SCENE = 1,
IMPORT_ANIMATION = 2,
- IMPORT_ANIMATION_DETECT_LOOP = 4,
- IMPORT_ANIMATION_OPTIMIZE = 8,
- IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS = 16,
- IMPORT_ANIMATION_KEEP_VALUE_TRACKS = 32,
- IMPORT_GENERATE_TANGENT_ARRAYS = 256,
- IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
- IMPORT_MATERIALS_IN_INSTANCES = 1024,
- IMPORT_USE_COMPRESSION = 2048,
- IMPORT_USE_NAMED_SKIN_BINDS = 4096,
+ IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4,
+ IMPORT_GENERATE_TANGENT_ARRAYS = 8,
+ IMPORT_USE_NAMED_SKIN_BINDS = 16,
};
@@ -76,17 +72,15 @@ public:
class EditorScenePostImport : public Reference {
GDCLASS(EditorScenePostImport, Reference);
- String source_folder;
String source_file;
protected:
static void _bind_methods();
public:
- String get_source_folder() const;
String get_source_file() const;
virtual Node *post_import(Node *p_scene);
- virtual void init(const String &p_source_folder, const String &p_source_file);
+ virtual void init(const String &p_source_file);
EditorScenePostImport();
};
@@ -97,31 +91,36 @@ class ResourceImporterScene : public ResourceImporter {
static ResourceImporterScene *singleton;
- enum Presets {
- PRESET_SEPARATE_MATERIALS,
- PRESET_SEPARATE_MESHES,
- PRESET_SEPARATE_ANIMATIONS,
-
- PRESET_SINGLE_SCENE,
+ enum LightBakeMode {
+ LIGHT_BAKE_DISABLED,
+ LIGHT_BAKE_DYNAMIC,
+ LIGHT_BAKE_STATIC,
+ LIGHT_BAKE_STATIC_LIGHTMAPS
+ };
- PRESET_SEPARATE_MESHES_AND_MATERIALS,
- PRESET_SEPARATE_MESHES_AND_ANIMATIONS,
- PRESET_SEPARATE_MATERIALS_AND_ANIMATIONS,
- PRESET_SEPARATE_MESHES_MATERIALS_AND_ANIMATIONS,
+ enum MeshPhysicsMode {
+ MESH_PHYSICS_DISABLED,
+ MESH_PHYSICS_MESH_AND_STATIC_COLLIDER,
+ MESH_PHYSICS_RIGID_BODY_AND_MESH,
+ MESH_PHYSICS_STATIC_COLLIDER_ONLY,
+ MESH_PHYSICS_AREA_ONLY,
+ };
- PRESET_MULTIPLE_SCENES,
- PRESET_MULTIPLE_SCENES_AND_MATERIALS,
- PRESET_MAX
+ enum NavMeshMode {
+ NAVMESH_DISABLED,
+ NAVMESH_MESH_AND_NAVMESH,
+ NAVMESH_NAVMESH_ONLY,
};
- enum LightBakeMode {
- LIGHT_BAKE_DISABLED,
- LIGHT_BAKE_ENABLE,
- LIGHT_BAKE_LIGHTMAPS
+ enum MeshOverride {
+ MESH_OVERRIDE_DEFAULT,
+ MESH_OVERRIDE_ENABLE,
+ MESH_OVERRIDE_DISABLE,
};
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
- void _generate_meshes(Node *p_node, bool p_generate_lods, bool p_create_shadow_meshes);
+ void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache);
+ void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
public:
static ResourceImporterScene *get_singleton() { return singleton; }
@@ -141,26 +140,41 @@ public:
virtual int get_preset_count() const override;
virtual String get_preset_name(int p_idx) const override;
+ enum InternalImportCategory {
+ INTERNAL_IMPORT_CATEGORY_NODE,
+ INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE,
+ INTERNAL_IMPORT_CATEGORY_MESH,
+ INTERNAL_IMPORT_CATEGORY_MATERIAL,
+ INTERNAL_IMPORT_CATEGORY_ANIMATION,
+ INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE,
+ INTERNAL_IMPORT_CATEGORY_MAX
+ };
+
+ void get_internal_import_options(InternalImportCategory p_category, List<ImportOption> *r_options) const;
+ bool get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
+
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
virtual int get_import_order() const override { return 100; } //after everything
- void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
-
- void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_animations_as_text, bool p_keep_animations, bool p_make_materials, bool p_materials_as_text, bool p_keep_materials, bool p_make_meshes, bool p_meshes_as_text, Map<Ref<Animation>, Ref<Animation>> &p_animations, Map<Ref<Material>, Ref<Material>> &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh>> &p_meshes);
+ Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map);
+ Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, List<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
- Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode);
-
- void _create_clips(Node *scene, const Array &p_clips, bool p_bake_all);
- void _filter_anim_tracks(Ref<Animation> anim, Set<String> &keep);
- void _filter_tracks(Node *scene, const String &p_text);
- void _optimize_animations(Node *scene, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
+ void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
+ void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ Node *pre_import(const String &p_source_file);
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
+ virtual bool has_advanced_options() const override;
+ virtual void show_advanced_options(const String &p_path) override;
+
+ virtual bool can_import_threaded() const override { return false; }
+
ResourceImporterScene();
};
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index eb16e873e6..de8031af35 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -172,7 +172,7 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_option, cons
if (compress_mode < COMPRESS_VRAM_COMPRESSED) {
return false;
}
- if (!ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc")) {
+ if (!ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc")) {
return false;
}
}
@@ -473,8 +473,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
bool ok_on_pc = false;
bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
- bool can_bptc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_bptc");
- bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc");
+ bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc");
+ bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc");
if (can_bptc) {
//add to the list anyway
@@ -524,19 +524,19 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
ok_on_pc = true;
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) {
+ if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) {
_save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc2");
formats_imported.push_back("etc2");
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) {
+ if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc")) {
_save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc");
formats_imported.push_back("etc");
}
- if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) {
+ if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc")) {
_save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC1_4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("pvrtc");
formats_imported.push_back("pvrtc");
@@ -574,7 +574,7 @@ String ResourceImporterTexture::get_import_settings_string() const {
int index = 0;
while (compression_formats[index]) {
- String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]);
+ String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
bool test = ProjectSettings::get_singleton()->get(setting_path);
if (test) {
s += String(compression_formats[index]);
@@ -606,7 +606,7 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co
int index = 0;
bool valid = true;
while (compression_formats[index]) {
- String setting_path = "rendering/vram_compression/import_" + String(compression_formats[index]);
+ String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
bool test = ProjectSettings::get_singleton()->get(setting_path);
if (test) {
if (formats_imported.find(compression_formats[index]) == -1) {
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
new file mode 100644
index 0000000000..48340ac242
--- /dev/null
+++ b/editor/import/scene_import_settings.cpp
@@ -0,0 +1,1199 @@
+/*************************************************************************/
+/* scene_import_settings.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "scene_import_settings.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/resources/surface_tool.h"
+
+class SceneImportSettingsData : public Object {
+ GDCLASS(SceneImportSettingsData, Object)
+ friend class SceneImportSettings;
+ Map<StringName, Variant> *settings = nullptr;
+ Map<StringName, Variant> current;
+ Map<StringName, Variant> defaults;
+ List<ResourceImporter::ImportOption> options;
+
+ ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
+
+ bool _set(const StringName &p_name, const Variant &p_value) {
+ if (settings) {
+ if (defaults.has(p_name) && defaults[p_name] == p_value) {
+ settings->erase(p_name);
+ } else {
+ (*settings)[p_name] = p_value;
+ }
+
+ current[p_name] = p_value;
+ return true;
+ }
+ return false;
+ }
+ bool _get(const StringName &p_name, Variant &r_ret) const {
+ if (settings) {
+ if (settings->has(p_name)) {
+ r_ret = (*settings)[p_name];
+ return true;
+ }
+ }
+ if (defaults.has(p_name)) {
+ r_ret = defaults[p_name];
+ return true;
+ }
+ return false;
+ }
+ void _get_property_list(List<PropertyInfo> *p_list) const {
+ for (const List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ if (ResourceImporterScene::get_singleton()->get_internal_option_visibility(category, E->get().option.name, current)) {
+ p_list->push_back(E->get().option);
+ }
+ }
+ }
+};
+
+void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent) {
+ String import_id;
+ bool has_import_id = false;
+
+ if (p_material->has_meta("import_id")) {
+ import_id = p_material->get_meta("import_id");
+ has_import_id = true;
+ } else if (p_material->get_name() != "") {
+ import_id = p_material->get_name();
+ has_import_id = true;
+ } else {
+ import_id = "@MATERIAL:" + itos(material_set.size());
+ }
+
+ if (!material_map.has(import_id)) {
+ MaterialData md;
+ md.has_import_id = has_import_id;
+ md.material = p_material;
+
+ _load_default_subresource_settings(md.settings, "materials", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL);
+
+ material_map[import_id] = md;
+ }
+
+ MaterialData &material_data = material_map[import_id];
+
+ Ref<Texture2D> icon = get_theme_icon("StandardMaterial3D", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_material->get_name());
+ item->set_icon(0, icon);
+
+ bool created = false;
+ if (!material_set.has(p_material)) {
+ material_set.insert(p_material);
+ created = true;
+ }
+
+ item->set_meta("type", "Material");
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_selectable(0, true);
+
+ if (p_tree == scene_tree) {
+ material_data.scene_node = item;
+ } else if (p_tree == mesh_tree) {
+ material_data.mesh_node = item;
+ } else {
+ material_data.material_node = item;
+ }
+
+ if (created) {
+ _fill_material(material_tree, p_material, material_tree->get_root());
+ }
+}
+
+void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent) {
+ String import_id;
+
+ bool has_import_id = false;
+ if (p_mesh->has_meta("import_id")) {
+ import_id = p_mesh->get_meta("import_id");
+ has_import_id = true;
+ } else if (p_mesh->get_name() != String()) {
+ import_id = p_mesh->get_name();
+ has_import_id = true;
+ } else {
+ import_id = "@MESH:" + itos(mesh_set.size());
+ }
+
+ if (!mesh_map.has(import_id)) {
+ MeshData md;
+ md.has_import_id = has_import_id;
+ md.mesh = p_mesh;
+
+ _load_default_subresource_settings(md.settings, "meshes", import_id, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH);
+
+ mesh_map[import_id] = md;
+ }
+
+ MeshData &mesh_data = mesh_map[import_id];
+
+ Ref<Texture2D> icon = get_theme_icon("Mesh", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_mesh->get_name());
+ item->set_icon(0, icon);
+
+ bool created = false;
+ if (!mesh_set.has(p_mesh)) {
+ mesh_set.insert(p_mesh);
+ created = true;
+ }
+
+ item->set_meta("type", "Mesh");
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+
+ item->set_selectable(0, true);
+
+ if (p_tree == scene_tree) {
+ mesh_data.scene_node = item;
+ } else {
+ mesh_data.mesh_node = item;
+ }
+
+ item->set_collapsed(true);
+
+ for (int i = 0; i < p_mesh->get_surface_count(); i++) {
+ Ref<Material> mat = p_mesh->surface_get_material(i);
+ if (mat.is_valid()) {
+ _fill_material(p_tree, mat, item);
+ }
+ }
+
+ if (created) {
+ _fill_mesh(mesh_tree, p_mesh, mesh_tree->get_root());
+ }
+}
+
+void SceneImportSettings::_fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent) {
+ if (!animation_map.has(p_name)) {
+ AnimationData ad;
+ ad.animation = p_anim;
+
+ _load_default_subresource_settings(ad.settings, "animations", p_name, ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION);
+
+ animation_map[p_name] = ad;
+ }
+
+ AnimationData &animation_data = animation_map[p_name];
+
+ Ref<Texture2D> icon = get_theme_icon("Animation", "EditorIcons");
+
+ TreeItem *item = p_tree->create_item(p_parent);
+ item->set_text(0, p_name);
+ item->set_icon(0, icon);
+
+ item->set_meta("type", "Animation");
+ item->set_meta("import_id", p_name);
+
+ item->set_selectable(0, true);
+
+ animation_data.scene_node = item;
+}
+
+void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
+ String import_id;
+
+ if (p_node->has_meta("import_id")) {
+ import_id = p_node->get_meta("import_id");
+ } else {
+ import_id = "PATH:" + String(scene->get_path_to(p_node));
+ p_node->set_meta("import_id", import_id);
+ }
+
+ EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+
+ if (src_mesh_node) {
+ MeshInstance3D *mesh_node = memnew(MeshInstance3D);
+ mesh_node->set_name(src_mesh_node->get_name());
+ mesh_node->set_transform(src_mesh_node->get_transform());
+ mesh_node->set_skin(src_mesh_node->get_skin());
+ mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
+ if (src_mesh_node->get_mesh().is_valid()) {
+ Ref<EditorSceneImporterMesh> editor_mesh = src_mesh_node->get_mesh();
+ mesh_node->set_mesh(editor_mesh->get_mesh());
+ }
+
+ p_node->replace_by(mesh_node);
+ memdelete(p_node);
+ p_node = mesh_node;
+ }
+
+ String type = p_node->get_class();
+
+ if (!has_theme_icon(type, "EditorIcons")) {
+ type = "Node3D";
+ }
+
+ Ref<Texture2D> icon = get_theme_icon(type, "EditorIcons");
+
+ TreeItem *item = scene_tree->create_item(p_parent_item);
+ item->set_text(0, p_node->get_name());
+
+ if (p_node == scene) {
+ icon = get_theme_icon("PackedScene", "EditorIcons");
+ item->set_text(0, "Scene");
+ }
+
+ item->set_icon(0, icon);
+
+ item->set_meta("type", "Node");
+ item->set_meta("class", type);
+ item->set_meta("import_id", import_id);
+ item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
+
+ item->set_selectable(0, true);
+
+ if (!node_map.has(import_id)) {
+ NodeData nd;
+
+ if (p_node != scene) {
+ ResourceImporterScene::InternalImportCategory category;
+ if (src_mesh_node) {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
+ } else if (Object::cast_to<AnimationPlayer>(p_node)) {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
+ } else {
+ category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
+ }
+
+ _load_default_subresource_settings(nd.settings, "nodes", import_id, category);
+ }
+
+ node_map[import_id] = nd;
+ }
+ NodeData &node_data = node_map[import_id];
+
+ node_data.node = p_node;
+ node_data.scene_node = item;
+
+ AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node);
+ if (anim_node) {
+ List<StringName> animations;
+ anim_node->get_animation_list(&animations);
+ for (List<StringName>::Element *E = animations.front(); E; E = E->next()) {
+ _fill_animation(scene_tree, anim_node->get_animation(E->get()), E->get(), item);
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _fill_scene(p_node->get_child(i), item);
+ }
+ MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
+ if (mesh_node && mesh_node->get_mesh().is_valid()) {
+ _fill_mesh(scene_tree, mesh_node->get_mesh(), item);
+
+ Transform accum_xform;
+ Node3D *base = mesh_node;
+ while (base) {
+ accum_xform = base->get_transform() * accum_xform;
+ base = Object::cast_to<Node3D>(base->get_parent());
+ }
+
+ AABB aabb = accum_xform.xform(mesh_node->get_mesh()->get_aabb());
+ if (first_aabb) {
+ contents_aabb = aabb;
+ first_aabb = false;
+ } else {
+ contents_aabb.merge_with(aabb);
+ }
+ }
+}
+
+void SceneImportSettings::_update_scene() {
+ scene_tree->clear();
+ material_tree->clear();
+ mesh_tree->clear();
+
+ //hiden roots
+ material_tree->create_item();
+ mesh_tree->create_item();
+
+ _fill_scene(scene, nullptr);
+}
+
+void SceneImportSettings::_update_camera() {
+ AABB camera_aabb;
+
+ float rot_x = cam_rot_x;
+ float rot_y = cam_rot_y;
+ float zoom = cam_zoom;
+
+ if (selected_type == "Node" || selected_type == "") {
+ camera_aabb = contents_aabb;
+ } else {
+ if (mesh_preview->get_mesh().is_valid()) {
+ camera_aabb = mesh_preview->get_transform().xform(mesh_preview->get_mesh()->get_aabb());
+ } else {
+ camera_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ }
+ if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
+ const MeshData &md = mesh_map[selected_id];
+ rot_x = md.cam_rot_x;
+ rot_y = md.cam_rot_y;
+ zoom = md.cam_zoom;
+ } else if (selected_type == "Material" && material_map.has(selected_id)) {
+ const MaterialData &md = material_map[selected_id];
+ rot_x = md.cam_rot_x;
+ rot_y = md.cam_rot_y;
+ zoom = md.cam_zoom;
+ }
+ }
+
+ Vector3 center = camera_aabb.position + camera_aabb.size * 0.5;
+ float camera_size = camera_aabb.get_longest_axis_size();
+
+ camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);
+
+ Transform xf;
+ xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x);
+ xf.origin = center;
+ xf.translate(0, 0, camera_size);
+
+ camera->set_transform(xf);
+}
+
+void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category) {
+ if (base_subresource_settings.has(p_type)) {
+ Dictionary d = base_subresource_settings[p_type];
+ if (d.has(p_import_id)) {
+ d = d[p_import_id];
+ List<ResourceImporterScene::ImportOption> options;
+ ResourceImporterScene::get_singleton()->get_internal_import_options(p_category, &options);
+ for (List<ResourceImporterScene::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ String key = E->get().option.name;
+ if (d.has(key)) {
+ settings[key] = d[key];
+ }
+ }
+ }
+ }
+}
+
+void SceneImportSettings::open_settings(const String &p_path) {
+ if (scene) {
+ memdelete(scene);
+ scene = nullptr;
+ }
+ scene = ResourceImporterScene::get_singleton()->pre_import(p_path);
+ if (scene == nullptr) {
+ EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
+ return;
+ }
+
+ base_path = p_path;
+
+ material_set.clear();
+ mesh_set.clear();
+ material_map.clear();
+ mesh_map.clear();
+ node_map.clear();
+ defaults.clear();
+
+ selected_id = "";
+ selected_type = "";
+
+ cam_rot_x = -Math_PI / 4;
+ cam_rot_y = -Math_PI / 4;
+ cam_zoom = 1;
+
+ {
+ base_subresource_settings.clear();
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(p_path + ".import");
+ if (err == OK) {
+ List<String> keys;
+ config->get_section_keys("params", &keys);
+ for (List<String>::Element *E = keys.front(); E; E = E->next()) {
+ Variant value = config->get_value("params", E->get());
+ if (E->get() == "_subresources") {
+ base_subresource_settings = value;
+ } else {
+ defaults[E->get()] = value;
+ }
+ }
+ }
+ }
+
+ first_aabb = true;
+
+ _update_scene();
+
+ base_viewport->add_child(scene);
+
+ if (first_aabb) {
+ contents_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ first_aabb = false;
+ }
+
+ popup_centered_ratio();
+ _update_camera();
+
+ set_title(vformat(TTR("Advanced Import Settings for '%s'"), base_path.get_file()));
+}
+
+SceneImportSettings *SceneImportSettings::singleton = nullptr;
+
+SceneImportSettings *SceneImportSettings::get_singleton() {
+ return singleton;
+}
+
+void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
+ selecting = true;
+
+ if (p_type == "Node") {
+ node_selected->hide(); //always hide just in case
+ mesh_preview->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->show();
+ }
+ //NodeData &nd=node_map[p_id];
+ material_tree->deselect_all();
+ mesh_tree->deselect_all();
+ NodeData &nd = node_map[p_id];
+
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(nd.node);
+ if (mi) {
+ Ref<Mesh> base_mesh = mi->get_mesh();
+ if (base_mesh.is_valid()) {
+ AABB aabb = base_mesh->get_aabb();
+ Transform aabb_xf;
+ aabb_xf.basis.scale(aabb.size);
+ aabb_xf.origin = aabb.position;
+
+ aabb_xf = mi->get_global_transform() * aabb_xf;
+ node_selected->set_transform(aabb_xf);
+ node_selected->show();
+ }
+ }
+
+ if (nd.node == scene) {
+ scene_import_settings_data->settings = &defaults;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
+ } else {
+ scene_import_settings_data->settings = &nd.settings;
+ if (mi) {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
+ } else if (Object::cast_to<AnimationPlayer>(nd.node)) {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
+ } else {
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
+ }
+ }
+ } else if (p_type == "Animation") {
+ node_selected->hide(); //always hide just in case
+ mesh_preview->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->show();
+ }
+ //NodeData &nd=node_map[p_id];
+ material_tree->deselect_all();
+ mesh_tree->deselect_all();
+ AnimationData &ad = animation_map[p_id];
+
+ scene_import_settings_data->settings = &ad.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION;
+ } else if (p_type == "Mesh") {
+ node_selected->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->hide();
+ }
+
+ MeshData &md = mesh_map[p_id];
+ if (p_from != mesh_tree) {
+ md.mesh_node->uncollapse_tree();
+ md.mesh_node->select(0);
+ mesh_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != scene_tree) {
+ md.scene_node->uncollapse_tree();
+ md.scene_node->select(0);
+ scene_tree->ensure_cursor_is_visible();
+ }
+
+ mesh_preview->set_mesh(md.mesh);
+ mesh_preview->show();
+
+ material_tree->deselect_all();
+
+ scene_import_settings_data->settings = &md.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH;
+ } else if (p_type == "Material") {
+ node_selected->hide();
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->hide();
+ }
+
+ mesh_preview->show();
+
+ MaterialData &md = material_map[p_id];
+
+ material_preview->set_material(md.material);
+ mesh_preview->set_mesh(material_preview);
+
+ if (p_from != mesh_tree) {
+ md.mesh_node->uncollapse_tree();
+ md.mesh_node->select(0);
+ mesh_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != scene_tree) {
+ md.scene_node->uncollapse_tree();
+ md.scene_node->select(0);
+ scene_tree->ensure_cursor_is_visible();
+ }
+ if (p_from != material_tree) {
+ md.material_node->uncollapse_tree();
+ md.material_node->select(0);
+ material_tree->ensure_cursor_is_visible();
+ }
+
+ scene_import_settings_data->settings = &md.settings;
+ scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MATERIAL;
+ }
+
+ selected_type = p_type;
+ selected_id = p_id;
+
+ selecting = false;
+
+ _update_camera();
+
+ List<ResourceImporter::ImportOption> options;
+
+ if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
+ ResourceImporterScene::get_singleton()->get_import_options(&options);
+ } else {
+ ResourceImporterScene::get_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
+ }
+
+ scene_import_settings_data->defaults.clear();
+ scene_import_settings_data->current.clear();
+
+ for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ scene_import_settings_data->defaults[E->get().option.name] = E->get().default_value;
+ //needed for visibility toggling (fails if something is missing)
+ if (scene_import_settings_data->settings->has(E->get().option.name)) {
+ scene_import_settings_data->current[E->get().option.name] = (*scene_import_settings_data->settings)[E->get().option.name];
+ } else {
+ scene_import_settings_data->current[E->get().option.name] = E->get().default_value;
+ }
+ }
+ scene_import_settings_data->options = options;
+ inspector->edit(scene_import_settings_data);
+ scene_import_settings_data->notify_property_list_changed();
+}
+
+void SceneImportSettings::_material_tree_selected() {
+ if (selecting) {
+ return;
+ }
+ TreeItem *item = material_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(material_tree, type, import_id);
+}
+void SceneImportSettings::_mesh_tree_selected() {
+ if (selecting) {
+ return;
+ }
+
+ TreeItem *item = mesh_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(mesh_tree, type, import_id);
+}
+void SceneImportSettings::_scene_tree_selected() {
+ if (selecting) {
+ return;
+ }
+ TreeItem *item = scene_tree->get_selected();
+ String type = item->get_meta("type");
+ String import_id = item->get_meta("import_id");
+
+ _select(scene_tree, type, import_id);
+}
+
+void SceneImportSettings::_viewport_input(const Ref<InputEvent> &p_input) {
+ float *rot_x = &cam_rot_x;
+ float *rot_y = &cam_rot_y;
+ float *zoom = &cam_zoom;
+
+ if (selected_type == "Mesh" && mesh_map.has(selected_id)) {
+ MeshData &md = mesh_map[selected_id];
+ rot_x = &md.cam_rot_x;
+ rot_y = &md.cam_rot_y;
+ zoom = &md.cam_zoom;
+ } else if (selected_type == "Material" && material_map.has(selected_id)) {
+ MaterialData &md = material_map[selected_id];
+ rot_x = &md.cam_rot_x;
+ rot_y = &md.cam_rot_y;
+ zoom = &md.cam_zoom;
+ }
+ Ref<InputEventMouseMotion> mm = p_input;
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ (*rot_x) -= mm->get_relative().y * 0.01 * EDSCALE;
+ (*rot_y) -= mm->get_relative().x * 0.01 * EDSCALE;
+ (*rot_x) = CLAMP((*rot_x), -Math_PI / 2, Math_PI / 2);
+ _update_camera();
+ }
+ Ref<InputEventMouseButton> mb = p_input;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ (*zoom) *= 1.1;
+ if ((*zoom) > 10.0) {
+ (*zoom) = 10.0;
+ }
+ _update_camera();
+ }
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ (*zoom) /= 1.1;
+ if ((*zoom) < 0.1) {
+ (*zoom) = 0.1;
+ }
+ _update_camera();
+ }
+}
+
+void SceneImportSettings::_re_import() {
+ Map<StringName, Variant> main_settings;
+
+ main_settings = defaults;
+ main_settings.erase("_subresources");
+ Dictionary nodes;
+ Dictionary materials;
+ Dictionary meshes;
+ Dictionary animations;
+
+ Dictionary subresources;
+
+ for (Map<String, NodeData>::Element *E = node_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ nodes[E->key()] = d;
+ }
+ }
+ if (nodes.size()) {
+ subresources["nodes"] = nodes;
+ }
+
+ for (Map<String, MaterialData>::Element *E = material_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ materials[E->key()] = d;
+ }
+ }
+ if (materials.size()) {
+ subresources["materials"] = materials;
+ }
+
+ for (Map<String, MeshData>::Element *E = mesh_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ meshes[E->key()] = d;
+ }
+ }
+ if (meshes.size()) {
+ subresources["meshes"] = meshes;
+ }
+
+ for (Map<String, AnimationData>::Element *E = animation_map.front(); E; E = E->next()) {
+ if (E->get().settings.size()) {
+ Dictionary d;
+ for (Map<StringName, Variant>::Element *F = E->get().settings.front(); F; F = F->next()) {
+ d[String(F->key())] = F->get();
+ }
+ animations[E->key()] = d;
+ }
+ }
+ if (animations.size()) {
+ subresources["animations"] = animations;
+ }
+
+ if (subresources.size()) {
+ main_settings["_subresources"] = subresources;
+ }
+
+ EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, "scene", main_settings);
+}
+
+void SceneImportSettings::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ connect("confirmed", callable_mp(this, &SceneImportSettings::_re_import));
+ }
+}
+
+void SceneImportSettings::_menu_callback(int p_id) {
+ switch (p_id) {
+ case ACTION_EXTRACT_MATERIALS: {
+ save_path->set_text(TTR("Select folder to extract material resources"));
+ external_extension_type->select(0);
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ save_path->set_text(TTR("Select folder where mesh resources will save on import"));
+ external_extension_type->select(1);
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ save_path->set_text(TTR("Select folder where animations will save on import"));
+ external_extension_type->select(1);
+ } break;
+ }
+
+ save_path->set_current_dir(base_path.get_base_dir());
+ current_action = p_id;
+ save_path->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_path_changed(const String &p_path) {
+ save_path_item->set_text(1, p_path);
+
+ if (FileAccess::exists(p_path)) {
+ save_path_item->set_text(2, "Warning: File exists");
+ save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ save_path_item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ save_path_item->set_text(2, "Will create new File");
+ save_path_item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+}
+
+void SceneImportSettings::_browse_save_callback(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+
+ String path = item->get_text(1);
+
+ item_save_path->set_current_file(path);
+ save_path_item = item;
+
+ item_save_path->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_dir_callback(const String &p_path) {
+ external_path_tree->clear();
+ TreeItem *root = external_path_tree->create_item();
+ save_path_items.clear();
+
+ switch (current_action) {
+ case ACTION_EXTRACT_MATERIALS: {
+ for (Map<String, MaterialData>::Element *E = material_map.front(); E; E = E->next()) {
+ MaterialData &md = material_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = md.material_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("StandardMaterial3D", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (md.has_import_id) {
+ if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
+ item->set_text(2, "Already External");
+ item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will create new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ } else {
+ item->set_text(2, "No import ID");
+ item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_icon(2, get_theme_icon("StatusError", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Extract Materials to Resource Files"));
+ external_paths->get_ok_button()->set_text(TTR("Extract"));
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ for (Map<String, MeshData>::Element *E = mesh_map.front(); E; E = E->next()) {
+ MeshData &md = mesh_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = md.mesh_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("Mesh", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (md.has_import_id) {
+ if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
+ item->set_text(2, "Already Saving");
+ item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will save to new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ } else {
+ item->set_text(2, "No import ID");
+ item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_icon(2, get_theme_icon("StatusError", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Set paths to save meshes as resource files on Reimport"));
+ external_paths->get_ok_button()->set_text(TTR("Set Paths"));
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ for (Map<String, AnimationData>::Element *E = animation_map.front(); E; E = E->next()) {
+ AnimationData &ad = animation_map[E->key()];
+
+ TreeItem *item = external_path_tree->create_item(root);
+
+ String name = ad.scene_node->get_text(0);
+
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_icon(0, get_theme_icon("Animation", "EditorIcons"));
+ item->set_text(0, name);
+
+ if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
+ item->set_text(2, "Already Saving");
+ item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken."));
+ } else {
+ item->set_metadata(0, E->key());
+ item->set_editable(0, true);
+ item->set_checked(0, true);
+ String path = p_path.plus_file(name);
+ if (external_extension_type->get_selected() == 0) {
+ path += ".tres";
+ } else {
+ path += ".res";
+ }
+
+ item->set_text(1, path);
+ if (FileAccess::exists(path)) {
+ item->set_text(2, "Warning: File exists");
+ item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_icon(2, get_theme_icon("StatusWarning", "EditorIcons"));
+
+ } else {
+ item->set_text(2, "Will save to new File");
+ item->set_icon(2, get_theme_icon("StatusSuccess", "EditorIcons"));
+ }
+
+ item->add_button(1, get_theme_icon("Folder", "EditorIcons"));
+ }
+
+ save_path_items.push_back(item);
+ }
+
+ external_paths->set_title(TTR("Set paths to save animations as resource files on Reimport"));
+ external_paths->get_ok_button()->set_text(TTR("Set Paths"));
+
+ } break;
+ }
+
+ external_paths->popup_centered_ratio();
+}
+
+void SceneImportSettings::_save_dir_confirm() {
+ for (int i = 0; i < save_path_items.size(); i++) {
+ TreeItem *item = save_path_items[i];
+ if (!item->is_checked(0)) {
+ continue; //ignore
+ }
+ String path = item->get_text(1);
+ if (!path.is_resource_file()) {
+ continue;
+ }
+
+ String id = item->get_metadata(0);
+
+ switch (current_action) {
+ case ACTION_EXTRACT_MATERIALS: {
+ ERR_CONTINUE(!material_map.has(id));
+ MaterialData &md = material_map[id];
+
+ Error err = ResourceSaver::save(path, md.material);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Can't make material external to file, write error:") + "\n\t" + path);
+ continue;
+ }
+
+ md.settings["use_external/enabled"] = true;
+ md.settings["use_external/path"] = path;
+
+ } break;
+ case ACTION_CHOOSE_MESH_SAVE_PATHS: {
+ ERR_CONTINUE(!mesh_map.has(id));
+ MeshData &md = mesh_map[id];
+
+ md.settings["save_to_file/enabled"] = true;
+ md.settings["save_to_file/path"] = path;
+ } break;
+ case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
+ ERR_CONTINUE(!animation_map.has(id));
+ AnimationData &ad = animation_map[id];
+
+ ad.settings["save_to_file/enabled"] = true;
+ ad.settings["save_to_file/path"] = path;
+
+ } break;
+ }
+ }
+
+ if (current_action == ACTION_EXTRACT_MATERIALS) {
+ //as this happens right now, the scene needs to be saved and reimported.
+ _re_import();
+ open_settings(base_path);
+ } else {
+ scene_import_settings_data->notify_property_list_changed();
+ }
+}
+
+SceneImportSettings::SceneImportSettings() {
+ singleton = this;
+
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+ HBoxContainer *menu_hb = memnew(HBoxContainer);
+ main_vb->add_child(menu_hb);
+
+ action_menu = memnew(MenuButton);
+ action_menu->set_text(TTR("Actions..."));
+ menu_hb->add_child(action_menu);
+
+ action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
+ action_menu->get_popup()->add_separator();
+ action_menu->get_popup()->add_item(TTR("Set Animation Save Paths"), ACTION_CHOOSE_ANIMATION_SAVE_PATHS);
+ action_menu->get_popup()->add_item(TTR("Set Mesh Save Paths"), ACTION_CHOOSE_MESH_SAVE_PATHS);
+
+ action_menu->get_popup()->connect("id_pressed", callable_mp(this, &SceneImportSettings::_menu_callback));
+
+ tree_split = memnew(HSplitContainer);
+ main_vb->add_child(tree_split);
+ tree_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ data_mode = memnew(TabContainer);
+ tree_split->add_child(data_mode);
+ data_mode->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
+
+ property_split = memnew(HSplitContainer);
+ tree_split->add_child(property_split);
+ property_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ scene_tree = memnew(Tree);
+ scene_tree->set_name(TTR("Scene"));
+ data_mode->add_child(scene_tree);
+ scene_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_scene_tree_selected));
+
+ mesh_tree = memnew(Tree);
+ mesh_tree->set_name(TTR("Meshes"));
+ data_mode->add_child(mesh_tree);
+ mesh_tree->set_hide_root(true);
+ mesh_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_mesh_tree_selected));
+
+ material_tree = memnew(Tree);
+ material_tree->set_name(TTR("Materials"));
+ data_mode->add_child(material_tree);
+ material_tree->connect("cell_selected", callable_mp(this, &SceneImportSettings::_material_tree_selected));
+
+ material_tree->set_hide_root(true);
+
+ SubViewportContainer *vp_container = memnew(SubViewportContainer);
+ vp_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vp_container->set_custom_minimum_size(Size2(10, 10));
+ vp_container->set_stretch(true);
+ vp_container->connect("gui_input", callable_mp(this, &SceneImportSettings::_viewport_input));
+ property_split->add_child(vp_container);
+
+ base_viewport = memnew(SubViewport);
+ vp_container->add_child(base_viewport);
+
+ base_viewport->set_use_own_world_3d(true);
+
+ camera = memnew(Camera3D);
+ base_viewport->add_child(camera);
+ camera->make_current();
+
+ light = memnew(DirectionalLight3D);
+ light->set_transform(Transform().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
+ base_viewport->add_child(light);
+ light->set_shadow(true);
+
+ {
+ Ref<StandardMaterial3D> selection_mat;
+ selection_mat.instance();
+ selection_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ selection_mat->set_albedo(Color(1, 0.8, 1.0));
+
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_LINES);
+
+ AABB base_aabb;
+ base_aabb.size = Vector3(1, 1, 1);
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ base_aabb.get_edge(i, a, b);
+
+ st->add_vertex(a);
+ st->add_vertex(a.lerp(b, 0.2));
+ st->add_vertex(b);
+ st->add_vertex(b.lerp(a, 0.2));
+ }
+
+ selection_mesh.instance();
+ st->commit(selection_mesh);
+ selection_mesh->surface_set_material(0, selection_mat);
+
+ node_selected = memnew(MeshInstance3D);
+ node_selected->set_mesh(selection_mesh);
+ base_viewport->add_child(node_selected);
+ node_selected->hide();
+ }
+
+ {
+ mesh_preview = memnew(MeshInstance3D);
+ base_viewport->add_child(mesh_preview);
+ mesh_preview->hide();
+
+ material_preview.instance();
+ }
+
+ inspector = memnew(EditorInspector);
+ inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0));
+
+ property_split->add_child(inspector);
+
+ scene_import_settings_data = memnew(SceneImportSettingsData);
+
+ get_ok_button()->set_text(TTR("Reimport"));
+ get_cancel_button()->set_text(TTR("Close"));
+
+ external_paths = memnew(ConfirmationDialog);
+ add_child(external_paths);
+ external_path_tree = memnew(Tree);
+ external_paths->add_child(external_path_tree);
+ external_path_tree->connect("button_pressed", callable_mp(this, &SceneImportSettings::_browse_save_callback));
+ external_paths->connect("confirmed", callable_mp(this, &SceneImportSettings::_save_dir_confirm));
+ external_path_tree->set_columns(3);
+ external_path_tree->set_column_titles_visible(true);
+ external_path_tree->set_column_expand(0, true);
+ external_path_tree->set_column_min_width(0, 100 * EDSCALE);
+ external_path_tree->set_column_title(0, TTR("Resource"));
+ external_path_tree->set_column_expand(1, true);
+ external_path_tree->set_column_min_width(1, 100 * EDSCALE);
+ external_path_tree->set_column_title(1, TTR("Path"));
+ external_path_tree->set_column_expand(2, false);
+ external_path_tree->set_column_min_width(2, 200 * EDSCALE);
+ external_path_tree->set_column_title(2, TTR("Status"));
+ save_path = memnew(EditorFileDialog);
+ save_path->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
+ HBoxContainer *extension_hb = memnew(HBoxContainer);
+ save_path->get_vbox()->add_child(extension_hb);
+ extension_hb->add_spacer();
+ extension_hb->add_child(memnew(Label(TTR("Save Extension: "))));
+ external_extension_type = memnew(OptionButton);
+ extension_hb->add_child(external_extension_type);
+ external_extension_type->add_item(TTR("Text: *.tres"));
+ external_extension_type->add_item(TTR("Binary: *.res"));
+ external_path_tree->set_hide_root(true);
+ add_child(save_path);
+
+ item_save_path = memnew(EditorFileDialog);
+ item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ item_save_path->add_filter("*.tres;Text Resource");
+ item_save_path->add_filter("*.res;Binary Resource");
+ add_child(item_save_path);
+ item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed));
+
+ save_path->connect("dir_selected", callable_mp(this, &SceneImportSettings::_save_dir_callback));
+}
+
+SceneImportSettings::~SceneImportSettings() {
+ memdelete(scene_import_settings_data);
+}
diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h
new file mode 100644
index 0000000000..ddcf4a6d5d
--- /dev/null
+++ b/editor/import/scene_import_settings.h
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* scene_import_settings.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SCENEIMPORTSETTINGS_H
+#define SCENEIMPORTSETTINGS_H
+
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_inspector.h"
+#include "editor/import/resource_importer_scene.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/subviewport_container.h"
+#include "scene/gui/tab_container.h"
+#include "scene/gui/tree.h"
+#include "scene/resources/primitive_meshes.h"
+
+class SceneImportSettingsData;
+
+class SceneImportSettings : public ConfirmationDialog {
+ GDCLASS(SceneImportSettings, ConfirmationDialog)
+
+ static SceneImportSettings *singleton;
+
+ enum Actions {
+ ACTION_EXTRACT_MATERIALS,
+ ACTION_CHOOSE_MESH_SAVE_PATHS,
+ ACTION_CHOOSE_ANIMATION_SAVE_PATHS,
+ };
+
+ Node *scene = nullptr;
+
+ HSplitContainer *tree_split;
+ HSplitContainer *property_split;
+ TabContainer *data_mode;
+ Tree *scene_tree;
+ Tree *mesh_tree;
+ Tree *material_tree;
+
+ EditorInspector *inspector;
+
+ SubViewport *base_viewport;
+
+ Camera3D *camera;
+ bool first_aabb = false;
+ AABB contents_aabb;
+
+ DirectionalLight3D *light;
+ Ref<ArrayMesh> selection_mesh;
+ MeshInstance3D *node_selected;
+
+ MeshInstance3D *mesh_preview;
+ Ref<SphereMesh> material_preview;
+
+ float cam_rot_x;
+ float cam_rot_y;
+ float cam_zoom;
+
+ void _update_scene();
+
+ struct MaterialData {
+ bool has_import_id;
+ Ref<Material> material;
+ TreeItem *scene_node;
+ TreeItem *mesh_node;
+ TreeItem *material_node;
+
+ float cam_rot_x = -Math_PI / 4;
+ float cam_rot_y = -Math_PI / 4;
+ float cam_zoom = 1;
+
+ Map<StringName, Variant> settings;
+ };
+ Map<String, MaterialData> material_map;
+
+ struct MeshData {
+ bool has_import_id;
+ Ref<Mesh> mesh;
+ TreeItem *scene_node;
+ TreeItem *mesh_node;
+
+ float cam_rot_x = -Math_PI / 4;
+ float cam_rot_y = -Math_PI / 4;
+ float cam_zoom = 1;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, MeshData> mesh_map;
+
+ struct AnimationData {
+ Ref<Animation> animation;
+ TreeItem *scene_node;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, AnimationData> animation_map;
+
+ struct NodeData {
+ Node *node;
+ TreeItem *scene_node;
+ Map<StringName, Variant> settings;
+ };
+ Map<String, NodeData> node_map;
+
+ void _fill_material(Tree *p_tree, const Ref<Material> &p_material, TreeItem *p_parent);
+ void _fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, TreeItem *p_parent);
+ void _fill_animation(Tree *p_tree, const Ref<Animation> &p_anim, const String &p_name, TreeItem *p_parent);
+ void _fill_scene(Node *p_node, TreeItem *p_parent_item);
+
+ Set<Ref<Mesh>> mesh_set;
+ Set<Ref<Material>> material_set;
+
+ String selected_type;
+ String selected_id;
+
+ bool selecting = false;
+
+ void _update_camera();
+ void _select(Tree *p_from, String p_type, String p_id);
+ void _material_tree_selected();
+ void _mesh_tree_selected();
+ void _scene_tree_selected();
+
+ void _viewport_input(const Ref<InputEvent> &p_input);
+
+ Map<StringName, Variant> defaults;
+
+ SceneImportSettingsData *scene_import_settings_data;
+
+ void _re_import();
+
+ String base_path;
+
+ MenuButton *action_menu;
+
+ ConfirmationDialog *external_paths;
+ Tree *external_path_tree;
+ EditorFileDialog *save_path;
+ OptionButton *external_extension_type;
+
+ EditorFileDialog *item_save_path;
+
+ void _menu_callback(int p_id);
+ void _save_dir_callback(const String &p_path);
+
+ int current_action;
+
+ Vector<TreeItem *> save_path_items;
+
+ TreeItem *save_path_item = nullptr;
+ void _save_path_changed(const String &p_path);
+ void _browse_save_callback(Object *p_item, int p_column, int p_id);
+ void _save_dir_confirm();
+
+ Dictionary base_subresource_settings;
+
+ void _load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void open_settings(const String &p_path);
+ static SceneImportSettings *get_singleton();
+ SceneImportSettings();
+ ~SceneImportSettings();
+};
+
+#endif // SCENEIMPORTSETTINGS_H
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index 78a7cd84f1..28fdd4ddbd 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -136,6 +136,11 @@ Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const
return surfaces[p_surface].material;
}
+void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_surface, surfaces.size());
+ surfaces.write[p_surface].material = p_material;
+}
+
void EditorSceneImporterMesh::generate_lods() {
if (!SurfaceTool::simplify_func) {
return;
@@ -219,11 +224,20 @@ bool EditorSceneImporterMesh::has_mesh() const {
return mesh.is_valid();
}
-Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
+Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<Mesh> &p_base) {
ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
if (mesh.is_null()) {
- mesh.instance();
+ if (p_base.is_valid()) {
+ mesh = p_base;
+ }
+ if (mesh.is_null()) {
+ mesh.instance();
+ }
+ mesh->set_name(get_name());
+ if (has_meta("import_id")) {
+ mesh->set_meta("import_id", get_meta("import_id"));
+ }
for (int i = 0; i < blend_shapes.size(); i++) {
mesh->add_blend_shape(blend_shapes[i]);
}
@@ -251,6 +265,8 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() {
}
}
+ mesh->set_lightmap_size_hint(lightmap_size_hint);
+
if (shadow_mesh.is_valid()) {
Ref<ArrayMesh> shadow = shadow_mesh->get_mesh();
mesh->set_shadow_mesh(shadow);
@@ -436,6 +452,338 @@ Dictionary EditorSceneImporterMesh::_get_data() const {
return data;
}
+Vector<Face3> EditorSceneImporterMesh::get_faces() const {
+ Vector<Face3> faces;
+ for (int i = 0; i < surfaces.size(); i++) {
+ if (surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
+ Vector<Vector3> vertices = surfaces[i].arrays[Mesh::ARRAY_VERTEX];
+ Vector<int> indices = surfaces[i].arrays[Mesh::ARRAY_INDEX];
+ if (indices.size()) {
+ for (int j = 0; j < indices.size(); j += 3) {
+ Face3 f;
+ f.vertex[0] = vertices[indices[j + 0]];
+ f.vertex[1] = vertices[indices[j + 1]];
+ f.vertex[2] = vertices[indices[j + 2]];
+ faces.push_back(f);
+ }
+ } else {
+ for (int j = 0; j < vertices.size(); j += 3) {
+ Face3 f;
+ f.vertex[0] = vertices[j + 0];
+ f.vertex[1] = vertices[j + 1];
+ f.vertex[2] = vertices[j + 2];
+ faces.push_back(f);
+ }
+ }
+ }
+ }
+
+ return faces;
+}
+
+Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose() const {
+ ERR_FAIL_COND_V(!Mesh::convex_composition_function, Vector<Ref<Shape3D>>());
+
+ const Vector<Face3> faces = get_faces();
+
+ Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces);
+
+ Vector<Ref<Shape3D>> ret;
+
+ for (int i = 0; i < decomposed.size(); i++) {
+ Set<Vector3> points;
+ for (int j = 0; j < decomposed[i].size(); j++) {
+ points.insert(decomposed[i][j].vertex[0]);
+ points.insert(decomposed[i][j].vertex[1]);
+ points.insert(decomposed[i][j].vertex[2]);
+ }
+
+ Vector<Vector3> convex_points;
+ convex_points.resize(points.size());
+ {
+ Vector3 *w = convex_points.ptrw();
+ int idx = 0;
+ for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
+ w[idx++] = E->get();
+ }
+ }
+
+ Ref<ConvexPolygonShape3D> shape;
+ shape.instance();
+ shape->set_points(convex_points);
+ ret.push_back(shape);
+ }
+
+ return ret;
+}
+
+Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
+ Vector<Face3> faces = get_faces();
+ if (faces.size() == 0) {
+ return Ref<Shape3D>();
+ }
+
+ Vector<Vector3> face_points;
+ face_points.resize(faces.size() * 3);
+
+ for (int i = 0; i < face_points.size(); i += 3) {
+ Face3 f = faces.get(i / 3);
+ face_points.set(i, f.vertex[0]);
+ face_points.set(i + 1, f.vertex[1]);
+ face_points.set(i + 2, f.vertex[2]);
+ }
+
+ Ref<ConcavePolygonShape3D> shape = memnew(ConcavePolygonShape3D);
+ shape->set_faces(face_points);
+ return shape;
+}
+
+Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
+ Vector<Face3> faces = get_faces();
+ if (faces.size() == 0) {
+ return Ref<NavigationMesh>();
+ }
+
+ Map<Vector3, int> unique_vertices;
+ LocalVector<int> face_indices;
+
+ for (int i = 0; i < faces.size(); i++) {
+ for (int j = 0; j < 3; j++) {
+ Vector3 v = faces[i].vertex[j];
+ int idx;
+ if (unique_vertices.has(v)) {
+ idx = unique_vertices[v];
+ } else {
+ idx = unique_vertices.size();
+ unique_vertices[v] = idx;
+ }
+ face_indices.push_back(idx);
+ }
+ }
+
+ Vector<Vector3> vertices;
+ vertices.resize(unique_vertices.size());
+ for (Map<Vector3, int>::Element *E = unique_vertices.front(); E; E = E->next()) {
+ vertices.write[E->get()] = E->key();
+ }
+
+ Ref<NavigationMesh> nm;
+ nm.instance();
+ nm->set_vertices(vertices);
+
+ Vector<int> v3;
+ v3.resize(3);
+ for (uint32_t i = 0; i < face_indices.size(); i += 3) {
+ v3.write[0] = face_indices[i + 0];
+ v3.write[1] = face_indices[i + 1];
+ v3.write[2] = face_indices[i + 2];
+ nm->add_polygon(v3);
+ }
+
+ return nm;
+}
+
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+
+struct EditorSceneImporterMeshLightmapSurface {
+ Ref<Material> material;
+ LocalVector<SurfaceTool::Vertex> vertices;
+ Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX;
+ uint32_t format = 0;
+ String name;
+};
+
+Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+ ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
+
+ Vector<float> vertices;
+ Vector<float> normals;
+ Vector<int> indices;
+ Vector<float> uv;
+ Vector<Pair<int, int>> uv_indices;
+
+ Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
+
+ // Keep only the scale
+ Transform transform = p_base_transform;
+ transform.origin = Vector3();
+ transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+
+ Basis normal_basis = transform.basis.inverse().transposed();
+
+ for (int i = 0; i < get_surface_count(); i++) {
+ EditorSceneImporterMeshLightmapSurface s;
+ s.primitive = get_surface_primitive_type(i);
+
+ ERR_FAIL_COND_V_MSG(s.primitive != Mesh::PRIMITIVE_TRIANGLES, ERR_UNAVAILABLE, "Only triangles are supported for lightmap unwrap.");
+ Array arrays = get_surface_arrays(i);
+ s.material = get_surface_material(i);
+ s.name = get_surface_name(i);
+
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
+
+ Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ int vc = rvertices.size();
+ const Vector3 *r = rvertices.ptr();
+
+ Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
+
+ ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
+
+ const Vector3 *rn = rnormals.ptr();
+
+ int vertex_ofs = vertices.size() / 3;
+
+ vertices.resize((vertex_ofs + vc) * 3);
+ normals.resize((vertex_ofs + vc) * 3);
+ uv_indices.resize(vertex_ofs + vc);
+
+ for (int j = 0; j < vc; j++) {
+ Vector3 v = transform.xform(r[j]);
+ Vector3 n = normal_basis.xform(rn[j]).normalized();
+
+ vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ }
+
+ Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ int ic = rindices.size();
+
+ if (ic == 0) {
+ for (int j = 0; j < vc / 3; j++) {
+ if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ continue;
+ }
+
+ indices.push_back(vertex_ofs + j * 3 + 0);
+ indices.push_back(vertex_ofs + j * 3 + 1);
+ indices.push_back(vertex_ofs + j * 3 + 2);
+ }
+
+ } else {
+ const int *ri = rindices.ptr();
+
+ for (int j = 0; j < ic / 3; j++) {
+ if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ continue;
+ }
+ indices.push_back(vertex_ofs + ri[j * 3 + 0]);
+ indices.push_back(vertex_ofs + ri[j * 3 + 1]);
+ indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+ }
+ }
+
+ lightmap_surfaces.push_back(s);
+ }
+
+ //unwrap
+
+ float *gen_uvs;
+ int *gen_vertices;
+ int *gen_indices;
+ int gen_vertex_count;
+ int gen_index_count;
+ int size_x;
+ int size_y;
+
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+
+ if (!ok) {
+ return ERR_CANT_CREATE;
+ }
+
+ //remove surfaces
+ clear();
+
+ //create surfacetools for each surface..
+ Vector<Ref<SurfaceTool>> surfaces_tools;
+
+ for (int i = 0; i < lightmap_surfaces.size(); i++) {
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_TRIANGLES);
+ st->set_material(lightmap_surfaces[i].material);
+ st->set_meta("name", lightmap_surfaces[i].name);
+ surfaces_tools.push_back(st); //stay there
+ }
+
+ print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+ //go through all indices
+ for (int i = 0; i < gen_index_count; i += 3) {
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+
+ ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
+
+ int surface = uv_indices[gen_vertices[gen_indices[i + 0]]].first;
+
+ for (int j = 0; j < 3; j++) {
+ SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
+
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
+ surfaces_tools.write[surface]->set_color(v.color);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
+ surfaces_tools.write[surface]->set_uv(v.uv);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
+ surfaces_tools.write[surface]->set_normal(v.normal);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
+ Plane t;
+ t.normal = v.tangent;
+ t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
+ surfaces_tools.write[surface]->set_tangent(t);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
+ surfaces_tools.write[surface]->set_bones(v.bones);
+ }
+ if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
+ surfaces_tools.write[surface]->set_weights(v.weights);
+ }
+
+ Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
+ surfaces_tools.write[surface]->set_uv2(uv2);
+
+ surfaces_tools.write[surface]->add_vertex(v.vertex);
+ }
+ }
+
+ //generate surfaces
+
+ for (int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools.write[i]->index();
+ Array arrays = surfaces_tools.write[i]->commit_to_arrays();
+ add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
+ }
+
+ set_lightmap_size_hint(Size2(size_x, size_y));
+
+ if (!r_used_cache) {
+ //free stuff
+ ::free(gen_vertices);
+ ::free(gen_indices);
+ ::free(gen_uvs);
+ }
+
+ return OK;
+}
+
+void EditorSceneImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
+ lightmap_size_hint = p_size;
+}
+
+Size2i EditorSceneImporterMesh::get_lightmap_size_hint() const {
+ return lightmap_size_hint;
+}
+
void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
@@ -444,7 +792,7 @@ void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count);
ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type);
@@ -462,5 +810,8 @@ void EditorSceneImporterMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
+ ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &EditorSceneImporterMesh::set_lightmap_size_hint);
+ ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &EditorSceneImporterMesh::get_lightmap_size_hint);
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
}
diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h
index 42507cbe8c..3326fab55d 100644
--- a/editor/import/scene_importer_mesh.h
+++ b/editor/import/scene_importer_mesh.h
@@ -32,7 +32,10 @@
#define EDITOR_SCENE_IMPORTER_MESH_H
#include "core/io/resource.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
#include "scene/resources/mesh.h"
+#include "scene/resources/navigation_mesh.h"
// The following classes are used by importers instead of ArrayMesh and MeshInstance3D
// so the data is not registered (hence, quality loss), importing happens faster and
// its easier to modify before saving
@@ -63,6 +66,8 @@ class EditorSceneImporterMesh : public Resource {
Ref<EditorSceneImporterMesh> shadow_mesh;
+ Size2i lightmap_size_hint;
+
protected:
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
@@ -89,13 +94,24 @@ public:
float get_surface_lod_size(int p_surface, int p_lod) const;
Ref<Material> get_surface_material(int p_surface) const;
+ void set_surface_material(int p_surface, const Ref<Material> &p_material);
+
void generate_lods();
void create_shadow_mesh();
Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
+ Vector<Face3> get_faces() const;
+ Vector<Ref<Shape3D>> convex_decompose() const;
+ Ref<Shape3D> create_trimesh_shape() const;
+ Ref<NavigationMesh> create_navigation_mesh();
+ Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size);
+
+ void set_lightmap_size_hint(const Size2i &p_size);
+ Size2i get_lightmap_size_hint() const;
+
bool has_mesh() const;
- Ref<ArrayMesh> get_mesh();
+ Ref<ArrayMesh> get_mesh(const Ref<Mesh> &p_base = Ref<Mesh>());
void clear();
};
#endif // EDITOR_SCENE_IMPORTER_MESH_H
diff --git a/editor/import_defaults_editor.cpp b/editor/import_defaults_editor.cpp
new file mode 100644
index 0000000000..43b97eb910
--- /dev/null
+++ b/editor/import_defaults_editor.cpp
@@ -0,0 +1,216 @@
+/*************************************************************************/
+/* import_defaults_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "import_defaults_editor.h"
+
+class ImportDefaultsEditorSettings : public Object {
+ GDCLASS(ImportDefaultsEditorSettings, Object)
+ friend class ImportDefaultsEditor;
+ List<PropertyInfo> properties;
+ Map<StringName, Variant> values;
+ Map<StringName, Variant> default_values;
+
+ Ref<ResourceImporter> importer;
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value) {
+ if (values.has(p_name)) {
+ values[p_name] = p_value;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ bool _get(const StringName &p_name, Variant &r_ret) const {
+ if (values.has(p_name)) {
+ r_ret = values[p_name];
+ return true;
+ } else {
+ r_ret = Variant();
+ return false;
+ }
+ }
+ void _get_property_list(List<PropertyInfo> *p_list) const {
+ if (importer.is_null()) {
+ return;
+ }
+ for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ if (importer->get_option_visibility(E->get().name, values)) {
+ p_list->push_back(E->get());
+ }
+ }
+ }
+};
+
+void ImportDefaultsEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_PREDELETE) {
+ inspector->edit(nullptr);
+ }
+}
+
+void ImportDefaultsEditor::_reset() {
+ if (settings->importer.is_valid()) {
+ settings->values = settings->default_values;
+ settings->notify_property_list_changed();
+ }
+}
+
+void ImportDefaultsEditor::_save() {
+ if (settings->importer.is_valid()) {
+ Dictionary modified;
+
+ for (Map<StringName, Variant>::Element *E = settings->values.front(); E; E = E->next()) {
+ if (E->get() != settings->default_values[E->key()]) {
+ modified[E->key()] = E->get();
+ }
+ }
+
+ if (modified.size()) {
+ ProjectSettings::get_singleton()->set("importer_defaults/" + settings->importer->get_importer_name(), modified);
+ } else {
+ ProjectSettings::get_singleton()->set("importer_defaults/" + settings->importer->get_importer_name(), Variant());
+ }
+
+ emit_signal("project_settings_changed");
+ }
+}
+
+void ImportDefaultsEditor::_update_importer() {
+ List<Ref<ResourceImporter>> importer_list;
+ ResourceFormatImporter::get_singleton()->get_importers(&importer_list);
+ Ref<ResourceImporter> importer;
+ for (List<Ref<ResourceImporter>>::Element *E = importer_list.front(); E; E = E->next()) {
+ if (E->get()->get_visible_name() == importers->get_item_text(importers->get_selected())) {
+ importer = E->get();
+ break;
+ }
+ }
+
+ settings->properties.clear();
+ settings->values.clear();
+ settings->importer = importer;
+
+ if (importer.is_valid()) {
+ List<ResourceImporter::ImportOption> options;
+ importer->get_import_options(&options);
+ Dictionary d;
+ if (ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) {
+ d = ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name());
+ }
+
+ for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+ settings->properties.push_back(E->get().option);
+ if (d.has(E->get().option.name)) {
+ settings->values[E->get().option.name] = d[E->get().option.name];
+ } else {
+ settings->values[E->get().option.name] = E->get().default_value;
+ }
+ settings->default_values[E->get().option.name] = E->get().default_value;
+ }
+
+ save_defaults->set_disabled(false);
+ reset_defaults->set_disabled(false);
+
+ } else {
+ save_defaults->set_disabled(true);
+ reset_defaults->set_disabled(true);
+ }
+
+ settings->notify_property_list_changed();
+
+ inspector->edit(settings);
+}
+
+void ImportDefaultsEditor::_importer_selected(int p_index) {
+ _update_importer();
+}
+
+void ImportDefaultsEditor::clear() {
+ String last_selected;
+ if (importers->get_selected() > 0) {
+ last_selected = importers->get_item_text(importers->get_selected());
+ }
+
+ importers->clear();
+
+ importers->add_item("<" + TTR("Select Importer") + ">");
+ importers->set_item_disabled(0, true);
+
+ List<Ref<ResourceImporter>> importer_list;
+ ResourceFormatImporter::get_singleton()->get_importers(&importer_list);
+ Vector<String> names;
+ for (List<Ref<ResourceImporter>>::Element *E = importer_list.front(); E; E = E->next()) {
+ String vn = E->get()->get_visible_name();
+ names.push_back(vn);
+ }
+ names.sort();
+
+ for (int i = 0; i < names.size(); i++) {
+ importers->add_item(names[i]);
+
+ if (names[i] == last_selected) {
+ importers->select(i + 1);
+ }
+ }
+}
+
+void ImportDefaultsEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("project_settings_changed"));
+}
+
+ImportDefaultsEditor::ImportDefaultsEditor() {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->add_child(memnew(Label(TTR("Importer:"))));
+ importers = memnew(OptionButton);
+ hb->add_child(importers);
+ hb->add_spacer();
+ importers->connect("item_selected", callable_mp(this, &ImportDefaultsEditor::_importer_selected));
+ reset_defaults = memnew(Button);
+ reset_defaults->set_text(TTR("Reset to Defaults"));
+ reset_defaults->set_disabled(true);
+ 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);
+ CenterContainer *cc = memnew(CenterContainer);
+ save_defaults = memnew(Button);
+ save_defaults->set_text(TTR("Save"));
+ save_defaults->connect("pressed", callable_mp(this, &ImportDefaultsEditor::_save));
+ cc->add_child(save_defaults);
+ add_child(cc);
+
+ settings = memnew(ImportDefaultsEditorSettings);
+}
+
+ImportDefaultsEditor::~ImportDefaultsEditor() {
+ memdelete(settings);
+}
diff --git a/scene/2d/navigation_2d.h b/editor/import_defaults_editor.h
index 12847e52ac..c1becac5e9 100644
--- a/scene/2d/navigation_2d.h
+++ b/editor/import_defaults_editor.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* navigation_2d.h */
+/* import_defaults_editor.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,44 +28,48 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NAVIGATION_2D_H
-#define NAVIGATION_2D_H
+#ifndef IMPORT_DEFAULTS_EDITOR_H
+#define IMPORT_DEFAULTS_EDITOR_H
-#include "scene/2d/navigation_region_2d.h"
-#include "scene/2d/node_2d.h"
+#include "core/object/undo_redo.h"
+#include "editor/action_map_editor.h"
+#include "editor/editor_data.h"
+#include "editor/editor_plugin_settings.h"
+#include "editor/editor_sectioned_inspector.h"
+#include "editor/localization_editor.h"
+#include "editor/shader_globals_editor.h"
+#include "editor_autoload_settings.h"
+#include "scene/gui/center_container.h"
+#include "scene/gui/option_button.h"
-class Navigation2D : public Node2D {
- GDCLASS(Navigation2D, Node2D);
+class ImportDefaultsEditorSettings;
- RID map;
- real_t cell_size;
- real_t edge_connection_margin;
+class ImportDefaultsEditor : public VBoxContainer {
+ GDCLASS(ImportDefaultsEditor, VBoxContainer)
-protected:
- static void _bind_methods();
- void _notification(int p_what);
+ OptionButton *importers;
+ Button *save_defaults;
+ Button *reset_defaults;
-public:
- RID get_rid() const {
- return map;
- }
+ EditorInspector *inspector;
+
+ ImportDefaultsEditorSettings *settings;
- void set_cell_size(float p_cell_size);
- float get_cell_size() const {
- return cell_size;
- }
+ void _update_importer();
+ void _importer_selected(int p_index);
- void set_edge_connection_margin(float p_edge_connection_margin);
- float get_edge_connection_margin() const {
- return edge_connection_margin;
- }
+ void _reset();
+ void _save();
- Vector<Vector2> get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize = true) const;
- Vector2 get_closest_point(const Vector2 &p_point) const;
- RID get_closest_point_owner(const Vector2 &p_point) const;
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void clear();
- Navigation2D();
- ~Navigation2D();
+ ImportDefaultsEditor();
+ ~ImportDefaultsEditor();
};
-#endif // NAVIGATION_2D_H
+#endif // IMPORT_DEFAULTS_EDITOR_H
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 103e5e81cb..17c51f0f85 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -48,7 +48,7 @@ public:
values[p_name] = p_value;
if (checking) {
checked.insert(p_name);
- _change_notify();
+ notify_property_list_changed();
}
return true;
}
@@ -81,7 +81,7 @@ public:
}
void update() {
- _change_notify();
+ notify_property_list_changed();
}
ImportDockParameters() {
@@ -98,11 +98,9 @@ void ImportDock::set_edit_path(const String &p_path) {
return;
}
- params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(config->get_value("remap", "importer"));
- if (params->importer.is_null()) {
- clear();
- return;
- }
+ String importer_name = config->get_value("remap", "importer");
+
+ params->importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
params->paths.clear();
params->paths.push_back(p_path);
@@ -124,11 +122,18 @@ void ImportDock::set_edit_path(const String &p_path) {
for (List<Pair<String, String>>::Element *E = importer_names.front(); E; E = E->next()) {
import_as->add_item(E->get().first);
import_as->set_item_metadata(import_as->get_item_count() - 1, E->get().second);
- if (E->get().second == params->importer->get_importer_name()) {
+ if (E->get().second == importer_name) {
import_as->select(import_as->get_item_count() - 1);
}
}
+ import_as->add_separator();
+ import_as->add_item(TTR("Keep File (No Import)"));
+ import_as->set_item_metadata(import_as->get_item_count() - 1, "keep");
+ if (importer_name == "keep") {
+ import_as->select(import_as->get_item_count() - 1);
+ }
+
import->set_disabled(false);
import_as->set_disabled(false);
preset->set_disabled(false);
@@ -138,7 +143,10 @@ void ImportDock::set_edit_path(const String &p_path) {
void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
List<ResourceImporter::ImportOption> options;
- params->importer->get_import_options(&options);
+
+ if (params->importer.is_valid()) {
+ params->importer->get_import_options(&options);
+ }
params->properties.clear();
params->values.clear();
@@ -156,6 +164,14 @@ void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
params->update();
_update_preset_menu();
+
+ if (params->importer.is_valid() && params->paths.size() == 1 && params->importer->has_advanced_options()) {
+ advanced->show();
+ advanced_spacer->show();
+ } else {
+ advanced->hide();
+ advanced_spacer->hide();
+ }
}
void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
@@ -178,6 +194,10 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
}
}
+ if (!config->has_section("params")) {
+ continue;
+ }
+
List<String> keys;
config->get_section_keys("params", &keys);
@@ -258,11 +278,26 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
preset->set_disabled(false);
imported->set_text(vformat(TTR("%d Files"), p_paths.size()));
+
+ if (params->paths.size() == 1 && params->importer->has_advanced_options()) {
+ advanced->show();
+ advanced_spacer->show();
+ } else {
+ advanced->hide();
+ advanced_spacer->hide();
+ }
}
void ImportDock::_update_preset_menu() {
preset->get_popup()->clear();
+ if (params->importer.is_null()) {
+ preset->get_popup()->add_item(TTR("Default"));
+ preset->hide();
+ return;
+ }
+ preset->show();
+
if (params->importer->get_preset_count() == 0) {
preset->get_popup()->add_item(TTR("Default"));
} else {
@@ -282,20 +317,25 @@ void ImportDock::_update_preset_menu() {
void ImportDock::_importer_selected(int i_idx) {
String name = import_as->get_selected_metadata();
- Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
- ERR_FAIL_COND(importer.is_null());
+ if (name == "keep") {
+ params->importer.unref();
+ _update_options(Ref<ConfigFile>());
+ } else {
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
+ ERR_FAIL_COND(importer.is_null());
- params->importer = importer;
+ params->importer = importer;
- Ref<ConfigFile> config;
- if (params->paths.size()) {
- config.instance();
- Error err = config->load(params->paths[0] + ".import");
- if (err != OK) {
- config.unref();
+ Ref<ConfigFile> config;
+ if (params->paths.size()) {
+ config.instance();
+ Error err = config->load(params->paths[0] + ".import");
+ if (err != OK) {
+ config.unref();
+ }
}
+ _update_options(config);
}
- _update_options(config);
}
void ImportDock::_preset_selected(int p_idx) {
@@ -391,6 +431,13 @@ static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path)
void ImportDock::_reimport_attempt() {
bool need_restart = false;
bool used_in_resources = false;
+
+ String importer_name;
+ if (params->importer.is_valid()) {
+ importer_name = params->importer->get_importer_name();
+ } else {
+ importer_name = "keep";
+ }
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
config.instance();
@@ -398,7 +445,7 @@ void ImportDock::_reimport_attempt() {
ERR_CONTINUE(err != OK);
String imported_with = config->get_value("remap", "importer");
- if (imported_with != params->importer->get_importer_name()) {
+ if (imported_with != importer_name) {
need_restart = true;
if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) {
used_in_resources = true;
@@ -422,6 +469,11 @@ void ImportDock::_reimport_and_restart() {
EditorNode::get_singleton()->restart_editor();
}
+void ImportDock::_advanced_options() {
+ if (params->paths.size() == 1 && params->importer.is_valid()) {
+ params->importer->show_advanced_options(params->paths[0]);
+ }
+}
void ImportDock::_reimport() {
for (int i = 0; i < params->paths.size(); i++) {
Ref<ConfigFile> config;
@@ -429,38 +481,45 @@ void ImportDock::_reimport() {
Error err = config->load(params->paths[i] + ".import");
ERR_CONTINUE(err != OK);
- String importer_name = params->importer->get_importer_name();
+ if (params->importer.is_valid()) {
+ String importer_name = params->importer->get_importer_name();
- if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) {
- //update only what is edited (checkboxes) if the importer is the same
- for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
- if (params->checked.has(E->get().name)) {
+ if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) {
+ //update only what is edited (checkboxes) if the importer is the same
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
+ if (params->checked.has(E->get().name)) {
+ config->set_value("params", E->get().name, params->values[E->get().name]);
+ }
+ }
+ } else {
+ //override entirely
+ config->set_value("remap", "importer", importer_name);
+ if (config->has_section("params")) {
+ config->erase_section("params");
+ }
+
+ for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
config->set_value("params", E->get().name, params->values[E->get().name]);
}
}
- } else {
- //override entirely
- config->set_value("remap", "importer", importer_name);
- if (config->has_section("params")) {
- config->erase_section("params");
- }
- for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
- config->set_value("params", E->get().name, params->values[E->get().name]);
+ //handle group file
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
+ ERR_CONTINUE(!importer.is_valid());
+ String group_file_property = importer->get_option_group_file();
+ if (group_file_property != String()) {
+ //can import from a group (as in, atlas)
+ ERR_CONTINUE(!params->values.has(group_file_property));
+ String group_file = params->values[group_file_property];
+ config->set_value("remap", "group_file", group_file);
+ } else {
+ config->set_value("remap", "group_file", Variant()); //clear group file if unused
}
- }
- //handle group file
- Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
- ERR_CONTINUE(!importer.is_valid());
- String group_file_property = importer->get_option_group_file();
- if (group_file_property != String()) {
- //can import from a group (as in, atlas)
- ERR_CONTINUE(!params->values.has(group_file_property));
- String group_file = params->values[group_file_property];
- config->set_value("remap", "group_file", group_file);
} else {
- config->set_value("remap", "group_file", Variant()); //clear group file if unused
+ //set to no import
+ config->clear();
+ config->set_value("remap", "importer", "keep");
}
config->save(params->paths[i] + ".import");
@@ -531,10 +590,27 @@ ImportDock::ImportDock() {
import->set_text(TTR("Reimport"));
import->set_disabled(true);
import->connect("pressed", callable_mp(this, &ImportDock::_reimport_attempt));
+ if (!DisplayServer::get_singleton()->get_swap_cancel_ok()) {
+ advanced_spacer = hb->add_spacer();
+ advanced = memnew(Button);
+ advanced->set_text(TTR("Advanced..."));
+ hb->add_child(advanced);
+ }
hb->add_spacer();
hb->add_child(import);
hb->add_spacer();
+ if (DisplayServer::get_singleton()->get_swap_cancel_ok()) {
+ advanced = memnew(Button);
+ advanced->set_text(TTR("Advanced..."));
+ hb->add_child(advanced);
+ advanced_spacer = hb->add_spacer();
+ }
+
+ advanced->hide();
+ advanced_spacer->hide();
+ advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options));
+
reimport_confirm = memnew(ConfirmationDialog);
reimport_confirm->get_ok_button()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
add_child(reimport_confirm);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index 6c5779ddce..2be48dd505 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -57,6 +57,9 @@ class ImportDock : public VBoxContainer {
Label *label_warning;
Button *import;
+ Control *advanced_spacer;
+ Button *advanced;
+
ImportDockParameters *params;
void _preset_selected(int p_idx);
@@ -69,6 +72,7 @@ class ImportDock : public VBoxContainer {
void _reimport_and_restart();
void _reimport();
+ void _advanced_options();
enum {
ITEM_SET_AS_DEFAULT = 100,
ITEM_LOAD_DEFAULT,
diff --git a/editor/input_map_editor.cpp b/editor/input_map_editor.cpp
deleted file mode 100644
index 9a5e7d164c..0000000000
--- a/editor/input_map_editor.cpp
+++ /dev/null
@@ -1,1033 +0,0 @@
-/*************************************************************************/
-/* input_map_editor.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "input_map_editor.h"
-
-#include "core/input/input_map.h"
-#include "core/os/keyboard.h"
-#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
-
-void InputMapEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- action_add_error->add_theme_color_override("font_color", input_editor->get_theme_color("error_color", "Editor"));
- popup_add->add_icon_item(input_editor->get_theme_icon("Keyboard", "EditorIcons"), TTR("Key"), INPUT_KEY);
- popup_add->add_icon_item(input_editor->get_theme_icon("KeyboardPhysical", "EditorIcons"), TTR("Physical Key"), INPUT_KEY_PHYSICAL);
- popup_add->add_icon_item(input_editor->get_theme_icon("JoyButton", "EditorIcons"), TTR("Joy Button"), INPUT_JOY_BUTTON);
- popup_add->add_icon_item(input_editor->get_theme_icon("JoyAxis", "EditorIcons"), TTR("Joy Axis"), INPUT_JOY_MOTION);
- popup_add->add_icon_item(input_editor->get_theme_icon("Mouse", "EditorIcons"), TTR("Mouse Button"), INPUT_MOUSE_BUTTON);
- _update_actions();
- } break;
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- action_add_error->add_theme_color_override("font_color", input_editor->get_theme_color("error_color", "Editor"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), input_editor->get_theme_icon("Keyboard", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY_PHYSICAL), input_editor->get_theme_icon("KeyboardPhysical", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), input_editor->get_theme_icon("JoyButton", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_MOTION), input_editor->get_theme_icon("JoyAxis", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_MOUSE_BUTTON), input_editor->get_theme_icon("Mouse", "EditorIcons"));
- _update_actions();
- } break;
- }
-}
-
-static bool _validate_action_name(const String &p_name) {
- const char32_t *cstr = p_name.get_data();
- for (int i = 0; cstr[i]; i++) {
- if (cstr[i] == '/' || cstr[i] == ':' || cstr[i] == '"' ||
- cstr[i] == '=' || cstr[i] == '\\' || cstr[i] < 32) {
- return false;
- }
- }
- return true;
-}
-
-void InputMapEditor::_action_selected() {
- TreeItem *ti = input_editor->get_selected();
- if (!ti || !ti->is_editable(0)) {
- return;
- }
-
- add_at = "input/" + ti->get_text(0);
- edit_idx = -1;
-}
-
-void InputMapEditor::_action_edited() {
- TreeItem *ti = input_editor->get_selected();
- if (!ti) {
- return;
- }
-
- if (input_editor->get_selected_column() == 0) {
- String new_name = ti->get_text(0);
- String old_name = add_at.substr(add_at.find("/") + 1, add_at.length());
-
- if (new_name == old_name) {
- return;
- }
-
- if (new_name == "" || !_validate_action_name(new_name)) {
- ti->set_text(0, old_name);
- add_at = "input/" + old_name;
-
- message->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
- message->popup_centered(Size2(300, 100) * EDSCALE);
- return;
- }
-
- String action_prop = "input/" + new_name;
-
- if (ProjectSettings::get_singleton()->has_setting(action_prop)) {
- ti->set_text(0, old_name);
- add_at = "input/" + old_name;
-
- message->set_text(vformat(TTR("An action with the name '%s' already exists."), new_name));
- message->popup_centered(Size2(300, 100) * EDSCALE);
- return;
- }
-
- int order = ProjectSettings::get_singleton()->get_order(add_at);
- Dictionary action = ProjectSettings::get_singleton()->get(add_at);
-
- setting = true;
- undo_redo->create_action(TTR("Rename Input Action Event"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", add_at);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_prop, action);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", action_prop, order);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", action_prop);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", add_at, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", add_at, order);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
- setting = false;
-
- add_at = action_prop;
- } else if (input_editor->get_selected_column() == 1) {
- String name = "input/" + ti->get_text(0);
- Dictionary old_action = ProjectSettings::get_singleton()->get(name);
- Dictionary new_action = old_action.duplicate();
- new_action["deadzone"] = ti->get_range(1);
-
- undo_redo->create_action(TTR("Change Action deadzone"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action);
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
- }
-}
-
-void InputMapEditor::_device_input_add() {
- Ref<InputEvent> ie;
- String name = add_at;
- int idx = edit_idx;
- Dictionary old_val = ProjectSettings::get_singleton()->get(name);
- Dictionary action = old_val.duplicate();
- Array events = action["events"];
-
- switch (add_type) {
- case INPUT_MOUSE_BUTTON: {
- Ref<InputEventMouseButton> mb;
- mb.instance();
- mb->set_button_index(device_index->get_selected() + 1);
- mb->set_device(_get_current_device());
-
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEventMouseButton> aie = events[i];
- if (aie.is_null()) {
- continue;
- }
- if (aie->get_device() == mb->get_device() && aie->get_button_index() == mb->get_button_index()) {
- return;
- }
- }
-
- ie = mb;
-
- } break;
- case INPUT_JOY_MOTION: {
- Ref<InputEventJoypadMotion> jm;
- jm.instance();
- jm->set_axis(device_index->get_selected() >> 1);
- jm->set_axis_value((device_index->get_selected() & 1) ? 1 : -1);
- jm->set_device(_get_current_device());
-
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEventJoypadMotion> aie = events[i];
- if (aie.is_null()) {
- continue;
- }
-
- if (aie->get_device() == jm->get_device() && aie->get_axis() == jm->get_axis() && aie->get_axis_value() == jm->get_axis_value()) {
- return;
- }
- }
-
- ie = jm;
-
- } break;
- case INPUT_JOY_BUTTON: {
- Ref<InputEventJoypadButton> jb;
- jb.instance();
-
- jb->set_button_index(device_index->get_selected());
- jb->set_device(_get_current_device());
-
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEventJoypadButton> aie = events[i];
- if (aie.is_null()) {
- continue;
- }
- if (aie->get_device() == jb->get_device() && aie->get_button_index() == jb->get_button_index()) {
- return;
- }
- }
- ie = jb;
-
- } break;
- default: {
- }
- }
-
- if (idx < 0 || idx >= events.size()) {
- events.push_back(ie);
- } else {
- events[idx] = ie;
- }
- action["events"] = events;
-
- undo_redo->create_action(TTR("Add Input Action Event"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
-
- _show_last_added(ie, name);
-}
-
-void InputMapEditor::_set_current_device(int i_device) {
- device_id->select(i_device + 1);
-}
-
-int InputMapEditor::_get_current_device() {
- return device_id->get_selected() - 1;
-}
-
-String InputMapEditor::_get_device_string(int i_device) {
- if (i_device == InputMap::ALL_DEVICES) {
- return TTR("All Devices");
- }
- return TTR("Device") + " " + itos(i_device);
-}
-
-void InputMapEditor::_press_a_key_confirm() {
- if (last_wait_for_key.is_null()) {
- return;
- }
-
- Ref<InputEventKey> ie;
- ie.instance();
- if (press_a_key_physical) {
- ie->set_physical_keycode(last_wait_for_key->get_physical_keycode());
- ie->set_keycode(0);
- } else {
- ie->set_physical_keycode(0);
- ie->set_keycode(last_wait_for_key->get_keycode());
- }
- ie->set_shift(last_wait_for_key->get_shift());
- ie->set_alt(last_wait_for_key->get_alt());
- ie->set_control(last_wait_for_key->get_control());
- ie->set_metakey(last_wait_for_key->get_metakey());
-
- String name = add_at;
- int idx = edit_idx;
-
- Dictionary old_val = ProjectSettings::get_singleton()->get(name);
- Dictionary action = old_val.duplicate();
- Array events = action["events"];
-
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEventKey> aie = events[i];
- if (aie.is_null()) {
- continue;
- }
- if (!press_a_key_physical) {
- if (aie->get_keycode_with_modifiers() == ie->get_keycode_with_modifiers()) {
- return;
- }
- } else {
- if (aie->get_physical_keycode_with_modifiers() == ie->get_physical_keycode_with_modifiers()) {
- return;
- }
- }
- }
-
- if (idx < 0 || idx >= events.size()) {
- events.push_back(ie);
- } else {
- events[idx] = ie;
- }
- action["events"] = events;
-
- undo_redo->create_action(TTR("Add Input Action Event"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
-
- _show_last_added(ie, name);
-}
-
-void InputMapEditor::_show_last_added(const Ref<InputEvent> &p_event, const String &p_name) {
- TreeItem *r = input_editor->get_root();
-
- String name = p_name;
- name.erase(0, 6);
- if (!r) {
- return;
- }
- r = r->get_children();
- if (!r) {
- return;
- }
- bool found = false;
- while (r) {
- if (r->get_text(0) != name) {
- r = r->get_next();
- continue;
- }
- TreeItem *child = r->get_children();
- while (child) {
- Variant input = child->get_meta("__input");
- if (p_event == input) {
- r->set_collapsed(false);
- child->select(0);
- found = true;
- break;
- }
- child = child->get_next();
- }
- if (found) {
- break;
- }
- r = r->get_next();
- }
-
- if (found) {
- input_editor->ensure_cursor_is_visible();
- }
-}
-
-// Maps to 2*axis if value is neg, or + 1 if value is pos.
-static const char *_joy_axis_descriptions[JOY_AXIS_MAX * 2] = {
- TTRC("Left Stick Left, Joystick 0 Left"),
- TTRC("Left Stick Right, Joystick 0 Right"),
- TTRC("Left Stick Up, Joystick 0 Up"),
- TTRC("Left Stick Down, Joystick 0 Down"),
- TTRC("Right Stick Left, Joystick 1 Left"),
- TTRC("Right Stick Right, Joystick 1 Right"),
- TTRC("Right Stick Up, Joystick 1 Up"),
- TTRC("Right Stick Down, Joystick 1 Down"),
- TTRC("Joystick 2 Left"),
- TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"),
- TTRC("Joystick 2 Up"),
- TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"),
- TTRC("Joystick 3 Left"),
- TTRC("Joystick 3 Right"),
- TTRC("Joystick 3 Up"),
- TTRC("Joystick 3 Down"),
- TTRC("Joystick 4 Left"),
- TTRC("Joystick 4 Right"),
- TTRC("Joystick 4 Up"),
- TTRC("Joystick 4 Down"),
-};
-
-// Separate from `InputEvent::as_text()` since the descriptions need to be different for the input map editor. See #43660.
-String InputMapEditor::_get_joypad_motion_event_text(const Ref<InputEventJoypadMotion> &p_event) {
- ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEventJoypadMotion");
-
- String desc = TTR("Unknown Joypad Axis");
- if (p_event->get_axis() < JOY_AXIS_MAX) {
- desc = RTR(_joy_axis_descriptions[2 * p_event->get_axis() + (p_event->get_axis_value() < 0 ? 0 : 1)]);
- }
-
- return vformat("Joypad Axis %s %s (%s)", itos(p_event->get_axis()), p_event->get_axis_value() < 0 ? "-" : "+", desc);
-}
-
-void InputMapEditor::_wait_for_key(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid() && k->is_pressed() && k->get_keycode() != 0) {
- last_wait_for_key = p_event;
- const String str = (press_a_key_physical) ? keycode_get_string(k->get_physical_keycode_with_modifiers()) + TTR(" (Physical)") : keycode_get_string(k->get_keycode_with_modifiers());
-
- press_a_key_label->set_text(str);
- press_a_key->get_ok_button()->set_disabled(false);
- press_a_key->set_input_as_handled();
- }
-}
-
-void InputMapEditor::_edit_item(Ref<InputEvent> p_exiting_event) {
- InputType ie_type;
-
- if ((Ref<InputEventKey>(p_exiting_event)).is_valid()) {
- if ((Ref<InputEventKey>(p_exiting_event))->get_keycode() != 0) {
- ie_type = INPUT_KEY;
- } else {
- ie_type = INPUT_KEY_PHYSICAL;
- }
- } else if ((Ref<InputEventJoypadButton>(p_exiting_event)).is_valid()) {
- ie_type = INPUT_JOY_BUTTON;
- } else if ((Ref<InputEventMouseButton>(p_exiting_event)).is_valid()) {
- ie_type = INPUT_MOUSE_BUTTON;
- } else if ((Ref<InputEventJoypadMotion>(p_exiting_event)).is_valid()) {
- ie_type = INPUT_JOY_MOTION;
- } else {
- return;
- }
-
- _add_item(ie_type, p_exiting_event);
-}
-
-void InputMapEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_event) {
- add_type = InputType(p_item);
-
- switch (add_type) {
- case INPUT_KEY: {
- press_a_key_physical = false;
- press_a_key_label->set_text(TTR("Press a Key..."));
- press_a_key->get_ok_button()->set_disabled(true);
- last_wait_for_key = Ref<InputEvent>();
- press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
- //press_a_key->grab_focus();
-
- } break;
- case INPUT_KEY_PHYSICAL: {
- press_a_key_physical = true;
- press_a_key_label->set_text(TTR("Press a Key..."));
-
- last_wait_for_key = Ref<InputEvent>();
- press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
- press_a_key->grab_focus();
-
- } break;
- case INPUT_MOUSE_BUTTON: {
- device_index_label->set_text(TTR("Mouse Button Index:"));
- device_index->clear();
- device_index->add_item(TTR("Left Button"));
- device_index->add_item(TTR("Right Button"));
- device_index->add_item(TTR("Middle Button"));
- device_index->add_item(TTR("Wheel Up Button"));
- device_index->add_item(TTR("Wheel Down Button"));
- device_index->add_item(TTR("Wheel Left Button"));
- device_index->add_item(TTR("Wheel Right Button"));
- device_index->add_item(TTR("X Button 1"));
- device_index->add_item(TTR("X Button 2"));
- device_input->popup_centered(Size2(350, 95) * EDSCALE);
-
- Ref<InputEventMouseButton> mb = p_exiting_event;
- if (mb.is_valid()) {
- device_index->select(mb->get_button_index() - 1);
- _set_current_device(mb->get_device());
- device_input->get_ok_button()->set_text(TTR("Change"));
- } else {
- _set_current_device(0);
- device_input->get_ok_button()->set_text(TTR("Add"));
- }
-
- } break;
- case INPUT_JOY_MOTION: {
- device_index_label->set_text(TTR("Joypad Axis Index:"));
- device_index->clear();
- for (int i = 0; i < JOY_AXIS_MAX * 2; i++) {
- Ref<InputEventJoypadMotion> jm;
- jm.instance();
- jm->set_axis(i / 2);
- jm->set_axis_value((i & 1) ? 1 : -1);
- device_index->add_item(_get_joypad_motion_event_text(jm));
- }
- device_input->popup_centered(Size2(350, 95) * EDSCALE);
-
- Ref<InputEventJoypadMotion> jm = p_exiting_event;
- if (jm.is_valid()) {
- device_index->select(jm->get_axis() * 2 + (jm->get_axis_value() > 0 ? 1 : 0));
- _set_current_device(jm->get_device());
- device_input->get_ok_button()->set_text(TTR("Change"));
- } else {
- _set_current_device(0);
- device_input->get_ok_button()->set_text(TTR("Add"));
- }
-
- } break;
- case INPUT_JOY_BUTTON: {
- device_index_label->set_text(TTR("Joypad Button Index:"));
- device_index->clear();
- for (int i = 0; i < JOY_BUTTON_MAX; i++) {
- Ref<InputEventJoypadButton> jb;
- jb.instance();
- jb->set_button_index(i);
- device_index->add_item(jb->as_text());
- }
- device_input->popup_centered(Size2(350, 95) * EDSCALE);
-
- Ref<InputEventJoypadButton> jb = p_exiting_event;
- if (jb.is_valid()) {
- device_index->select(jb->get_button_index());
- _set_current_device(jb->get_device());
- device_input->get_ok_button()->set_text(TTR("Change"));
- } else {
- _set_current_device(0);
- device_input->get_ok_button()->set_text(TTR("Add"));
- }
-
- } break;
- default: {
- }
- }
-}
-
-void InputMapEditor::_action_activated() {
- TreeItem *ti = input_editor->get_selected();
-
- if (!ti || ti->get_parent() == input_editor->get_root()) {
- return;
- }
-
- String name = "input/" + ti->get_parent()->get_text(0);
- Dictionary action = ProjectSettings::get_singleton()->get(name);
- Array events = action["events"];
- int idx = ti->get_metadata(0);
-
- ERR_FAIL_INDEX(idx, events.size());
- Ref<InputEvent> event = events[idx];
- if (event.is_null()) {
- return;
- }
-
- add_at = name;
- edit_idx = idx;
- _edit_item(event);
-}
-
-void InputMapEditor::_action_button_pressed(Object *p_obj, int p_column, int p_id) {
- TreeItem *ti = Object::cast_to<TreeItem>(p_obj);
-
- ERR_FAIL_COND(!ti);
-
- if (p_id == 1) {
- // Add action event
- Point2 ofs = input_editor->get_global_position();
- Rect2 ir = input_editor->get_item_rect(ti);
- ir.position.y -= input_editor->get_scroll().y;
- ofs += ir.position + ir.size;
- ofs.x -= 100;
- popup_add->set_position(ofs);
- popup_add->popup();
- add_at = "input/" + ti->get_text(0);
- edit_idx = -1;
-
- } else if (p_id == 2) {
- // Remove
-
- if (ti->get_parent() == input_editor->get_root()) {
- // Remove action
- String name = "input/" + ti->get_text(0);
- Dictionary old_val = ProjectSettings::get_singleton()->get(name);
- int order = ProjectSettings::get_singleton()->get_order(name);
-
- undo_redo->create_action(TTR("Erase Input Action"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", name);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", name, order);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
-
- } else {
- // Remove action event
- String name = "input/" + ti->get_parent()->get_text(0);
- Dictionary old_val = ProjectSettings::get_singleton()->get(name);
- Dictionary action = old_val.duplicate();
- int idx = ti->get_metadata(0);
-
- Array events = action["events"];
- ERR_FAIL_INDEX(idx, events.size());
- events.remove(idx);
- action["events"] = events;
-
- undo_redo->create_action(TTR("Erase Input Action Event"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_val);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
- }
- } else if (p_id == 3) {
- // Edit
-
- if (ti->get_parent() == input_editor->get_root()) {
- // Edit action name
- ti->set_as_cursor(0);
- input_editor->edit_selected();
-
- } else {
- // Edit action event
- String name = "input/" + ti->get_parent()->get_text(0);
- int idx = ti->get_metadata(0);
- Dictionary action = ProjectSettings::get_singleton()->get(name);
-
- Array events = action["events"];
- ERR_FAIL_INDEX(idx, events.size());
-
- Ref<InputEvent> event = events[idx];
-
- if (event.is_null()) {
- return;
- }
-
- ti->set_as_cursor(0);
- add_at = name;
- edit_idx = idx;
- _edit_item(event);
- }
- }
-}
-
-void InputMapEditor::_update_actions() {
- if (setting) {
- return;
- }
-
- Map<String, bool> collapsed;
-
- if (input_editor->get_root() && input_editor->get_root()->get_children()) {
- for (TreeItem *item = input_editor->get_root()->get_children(); item; item = item->get_next()) {
- collapsed[item->get_text(0)] = item->is_collapsed();
- }
- }
-
- input_editor->clear();
- TreeItem *root = input_editor->create_item();
- input_editor->set_hide_root(true);
-
- List<PropertyInfo> props;
- ProjectSettings::get_singleton()->get_property_list(&props);
- for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- const String property_name = E->get().name;
-
- if (!property_name.begins_with("input/")) {
- continue;
- }
-
- const String name = property_name.get_slice("/", 1);
-
- TreeItem *item = input_editor->create_item(root);
- item->set_text(0, name);
- item->set_custom_bg_color(0, input_editor->get_theme_color("prop_subsection", "Editor"));
- if (collapsed.has(name)) {
- item->set_collapsed(collapsed[name]);
- }
-
- item->set_editable(1, true);
- item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
- item->set_range_config(1, 0.0, 1.0, 0.01);
-
- item->set_custom_bg_color(1, input_editor->get_theme_color("prop_subsection", "Editor"));
-
- const bool is_builtin_input = ProjectSettings::get_singleton()->get_input_presets().find(property_name) != nullptr;
- const String tooltip_remove = is_builtin_input ? TTR("Built-in actions can't be removed as they're used for UI navigation.") : TTR("Remove");
- item->add_button(2, input_editor->get_theme_icon("Add", "EditorIcons"), 1, false, TTR("Add Event"));
- item->add_button(2, input_editor->get_theme_icon("Remove", "EditorIcons"), 2, false, tooltip_remove);
-
- if (is_builtin_input) {
- item->set_button_disabled(2, 1, true);
- } else {
- item->set_editable(0, true);
- }
-
- Dictionary action = ProjectSettings::get_singleton()->get(property_name);
- Array events = action["events"];
- item->set_range(1, action["deadzone"]);
-
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEvent> event = events[i];
- if (event.is_null()) {
- continue;
- }
-
- TreeItem *action2 = input_editor->create_item(item);
-
- Ref<InputEventKey> k = event;
- if (k.is_valid()) {
- if (k->get_keycode() != 0) {
- action2->set_text(0, keycode_get_string(k->get_keycode_with_modifiers()));
- action2->set_icon(0, input_editor->get_theme_icon("Keyboard", "EditorIcons"));
- } else {
- action2->set_text(0, keycode_get_string(k->get_physical_keycode_with_modifiers()) + TTR(" (Physical)"));
- action2->set_icon(0, input_editor->get_theme_icon("KeyboardPhysical", "EditorIcons"));
- }
- }
-
- Ref<InputEventJoypadButton> jb = event;
- if (jb.is_valid()) {
- action2->set_text(0, jb->as_text());
- action2->set_icon(0, input_editor->get_theme_icon("JoyButton", "EditorIcons"));
- }
-
- Ref<InputEventMouseButton> mb = event;
- if (mb.is_valid()) {
- String str = _get_device_string(mb->get_device()) + ", ";
- switch (mb->get_button_index()) {
- case BUTTON_LEFT:
- str += TTR("Left Button");
- break;
- case BUTTON_RIGHT:
- str += TTR("Right Button");
- break;
- case BUTTON_MIDDLE:
- str += TTR("Middle Button");
- break;
- case BUTTON_WHEEL_UP:
- str += TTR("Wheel Up");
- break;
- case BUTTON_WHEEL_DOWN:
- str += TTR("Wheel Down");
- break;
- default:
- str += vformat(TTR("%d Button"), mb->get_button_index());
- }
-
- action2->set_text(0, str);
- action2->set_icon(0, input_editor->get_theme_icon("Mouse", "EditorIcons"));
- }
-
- Ref<InputEventJoypadMotion> jm = event;
- if (jm.is_valid()) {
- device_index->add_item(_get_joypad_motion_event_text(jm));
- action2->set_text(0, jm->as_text());
- action2->set_icon(0, input_editor->get_theme_icon("JoyAxis", "EditorIcons"));
- }
- action2->set_metadata(0, i);
- action2->set_meta("__input", event);
-
- action2->add_button(2, input_editor->get_theme_icon("Edit", "EditorIcons"), 3, false, TTR("Edit"));
- action2->add_button(2, input_editor->get_theme_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
- // Fade out the individual event buttons slightly to make the
- // Add/Remove buttons stand out more.
- action2->set_button_color(2, 0, Color(1, 1, 1, 0.75));
- action2->set_button_color(2, 1, Color(1, 1, 1, 0.75));
- }
- }
-
- _action_check(action_name->get_text());
-}
-
-void InputMapEditor::_action_check(String p_action) {
- if (p_action == "") {
- action_add->set_disabled(true);
- } else {
- if (!_validate_action_name(p_action)) {
- action_add_error->set_text(TTR("Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or '\"'."));
- action_add_error->show();
- action_add->set_disabled(true);
- return;
- }
- if (ProjectSettings::get_singleton()->has_setting("input/" + p_action)) {
- action_add_error->set_text(vformat(TTR("An action with the name '%s' already exists."), p_action));
- action_add_error->show();
- action_add->set_disabled(true);
- return;
- }
-
- action_add->set_disabled(false);
- }
-
- action_add_error->hide();
-}
-
-void InputMapEditor::_action_adds(String) {
- if (!action_add->is_disabled()) {
- _action_add();
- }
-}
-
-void InputMapEditor::_action_add() {
- Dictionary action;
- action["events"] = Array();
- action["deadzone"] = 0.5f;
- String name = "input/" + action_name->get_text();
- undo_redo->create_action(TTR("Add Input Action"));
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name);
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
-
- TreeItem *r = input_editor->get_root();
-
- if (!r) {
- return;
- }
- r = r->get_children();
- if (!r) {
- return;
- }
- while (r->get_next()) {
- r = r->get_next();
- }
-
- r->select(0);
- input_editor->ensure_cursor_is_visible();
- action_add_error->hide();
- action_name->clear();
-}
-
-Variant InputMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- TreeItem *selected = input_editor->get_selected();
- if (!selected || selected->get_parent() != input_editor->get_root()) {
- return Variant();
- }
-
- String name = selected->get_text(0);
- VBoxContainer *vb = memnew(VBoxContainer);
- HBoxContainer *hb = memnew(HBoxContainer);
- Label *label = memnew(Label(name));
- hb->set_modulate(Color(1, 1, 1, 1.0f));
- hb->add_child(label);
- vb->add_child(hb);
- input_editor->set_drag_preview(vb);
-
- Dictionary drag_data;
- drag_data["type"] = "nodes";
-
- input_editor->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
-
- return drag_data;
-}
-
-bool InputMapEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- Dictionary d = p_data;
- if (!d.has("type") || d["type"] != "nodes") {
- return false;
- }
-
- TreeItem *selected = input_editor->get_selected();
- TreeItem *item = input_editor->get_item_at_position(p_point);
- if (!selected || !item || item == selected || item->get_parent() == selected) {
- return false;
- }
-
- return true;
-}
-
-void InputMapEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- if (!can_drop_data_fw(p_point, p_data, p_from)) {
- return;
- }
-
- TreeItem *selected = input_editor->get_selected();
- TreeItem *item = input_editor->get_item_at_position(p_point);
- if (!item) {
- return;
- }
- TreeItem *target = item->get_parent() == input_editor->get_root() ? item : item->get_parent();
-
- String selected_name = "input/" + selected->get_text(0);
- int old_order = ProjectSettings::get_singleton()->get_order(selected_name);
- String target_name = "input/" + target->get_text(0);
- int target_order = ProjectSettings::get_singleton()->get_order(target_name);
-
- int order = old_order;
- bool is_below = target_order > old_order;
- TreeItem *iterator = is_below ? selected->get_next() : selected->get_prev();
-
- undo_redo->create_action(TTR("Moved Input Action Event"));
- while (iterator != target) {
- String iterator_name = "input/" + iterator->get_text(0);
- int iterator_order = ProjectSettings::get_singleton()->get_order(iterator_name);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", iterator_name, order);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", iterator_name, iterator_order);
- order = iterator_order;
- iterator = is_below ? iterator->get_next() : iterator->get_prev();
- }
-
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", target_name, order);
- undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", selected_name, target_order);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", target_name, target_order);
- undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", selected_name, old_order);
-
- undo_redo->add_do_method(this, "_update_actions");
- undo_redo->add_undo_method(this, "_update_actions");
- undo_redo->add_do_method(this, "emit_signal", inputmap_changed);
- undo_redo->add_undo_method(this, "emit_signal", inputmap_changed);
- undo_redo->commit_action();
-}
-
-void InputMapEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_actions"), &InputMapEditor::_update_actions);
-
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &InputMapEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &InputMapEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &InputMapEditor::drop_data_fw);
-
- ADD_SIGNAL(MethodInfo("inputmap_changed"));
-}
-
-InputMapEditor::InputMapEditor() {
- undo_redo = EditorNode::get_undo_redo();
- press_a_key_physical = false;
- inputmap_changed = "inputmap_changed";
-
- VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 0);
- vbc->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, 0);
- vbc->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 0);
- vbc->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, 0);
- add_child(vbc);
-
- HBoxContainer *hbc = memnew(HBoxContainer);
- vbc->add_child(hbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Action:"));
- hbc->add_child(l);
-
- action_name = memnew(LineEdit);
- action_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- action_name->connect("text_entered", callable_mp(this, &InputMapEditor::_action_adds));
- action_name->connect("text_changed", callable_mp(this, &InputMapEditor::_action_check));
- hbc->add_child(action_name);
-
- action_add_error = memnew(Label);
- action_add_error->hide();
- hbc->add_child(action_add_error);
-
- Button *add = memnew(Button);
- add->set_text(TTR("Add"));
- add->set_disabled(true);
- add->connect("pressed", callable_mp(this, &InputMapEditor::_action_add));
- hbc->add_child(add);
- action_add = add;
-
- input_editor = memnew(Tree);
- input_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- input_editor->set_columns(3);
- input_editor->set_column_titles_visible(true);
- input_editor->set_column_title(0, TTR("Action"));
- input_editor->set_column_title(1, TTR("Deadzone"));
- input_editor->set_column_expand(1, false);
- input_editor->set_column_min_width(1, 80 * EDSCALE);
- input_editor->set_column_expand(2, false);
- input_editor->set_column_min_width(2, 50 * EDSCALE);
- input_editor->connect("item_edited", callable_mp(this, &InputMapEditor::_action_edited));
- input_editor->connect("item_activated", callable_mp(this, &InputMapEditor::_action_activated));
- input_editor->connect("cell_selected", callable_mp(this, &InputMapEditor::_action_selected));
- input_editor->connect("button_pressed", callable_mp(this, &InputMapEditor::_action_button_pressed));
-#ifndef _MSC_VER
-#warning need to make drag data forwarding to non controls happen
-#endif
- //input_editor->set_drag_forwarding(this);
- vbc->add_child(input_editor);
-
- // Popups
-
- popup_add = memnew(PopupMenu);
- popup_add->connect("id_pressed", callable_mp(this, &InputMapEditor::_add_item), make_binds(Ref<InputEvent>()));
- add_child(popup_add);
-
- press_a_key = memnew(ConfirmationDialog);
- press_a_key->get_ok_button()->set_disabled(true);
- //press_a_key->set_focus_mode(Control::FOCUS_ALL);
- press_a_key->connect("window_input", callable_mp(this, &InputMapEditor::_wait_for_key));
- press_a_key->connect("confirmed", callable_mp(this, &InputMapEditor::_press_a_key_confirm));
- add_child(press_a_key);
-
- l = memnew(Label);
- l->set_text(TTR("Press a Key..."));
- l->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
- l->set_align(Label::ALIGN_CENTER);
- l->set_offset(SIDE_TOP, 20);
- l->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_BEGIN, 30);
- press_a_key->add_child(l);
- press_a_key_label = l;
-
- device_input = memnew(ConfirmationDialog);
- device_input->get_ok_button()->set_text(TTR("Add"));
- device_input->connect("confirmed", callable_mp(this, &InputMapEditor::_device_input_add));
- add_child(device_input);
-
- hbc = memnew(HBoxContainer);
- device_input->add_child(hbc);
-
- VBoxContainer *vbc_left = memnew(VBoxContainer);
- hbc->add_child(vbc_left);
-
- l = memnew(Label);
- l->set_text(TTR("Device:"));
- vbc_left->add_child(l);
-
- device_id = memnew(OptionButton);
- for (int i = -1; i < 8; i++) {
- device_id->add_item(_get_device_string(i));
- }
- _set_current_device(0);
- vbc_left->add_child(device_id);
-
- VBoxContainer *vbc_right = memnew(VBoxContainer);
- vbc_right->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbc->add_child(vbc_right);
-
- l = memnew(Label);
- l->set_text(TTR("Index:"));
- vbc_right->add_child(l);
-
- device_index_label = l;
- device_index = memnew(OptionButton);
- device_index->set_clip_text(true);
- vbc_right->add_child(device_index);
-
- message = memnew(AcceptDialog);
- add_child(message);
-}
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 60553143d5..161f1dde0d 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -37,24 +37,6 @@
#include "scene/gui/control.h"
void LocalizationEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_TEXT_SERVER_CHANGED) {
- ts_name->set_text(TTR("Text server: ") + TS->get_name());
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- ts_data_info->set_text(TTR("Info: ") + TS->get_support_data_info());
- }
if (p_what == NOTIFICATION_ENTER_TREE) {
translation_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_delete));
translation_pot_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_pot_delete));
@@ -84,7 +66,7 @@ void LocalizationEditor::add_translation(const String &p_translation) {
}
void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
- PackedStringArray translations = ProjectSettings::get_singleton()->get("locale/translations");
+ PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
for (int i = 0; i < p_paths.size(); i++) {
if (!translations.has(p_paths[i])) {
// Don't add duplicate translation paths.
@@ -93,8 +75,8 @@ void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
}
undo_redo->create_action(vformat(TTR("Add %d Translations"), p_paths.size()));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations", translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations", ProjectSettings::get_singleton()->get("locale/translations"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", ProjectSettings::get_singleton()->get("internationalization/locale/translations"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -112,15 +94,15 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
int idx = ti->get_metadata(0);
- PackedStringArray translations = ProjectSettings::get_singleton()->get("locale/translations");
+ PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
ERR_FAIL_INDEX(idx, translations.size());
translations.remove(idx);
undo_redo->create_action(TTR("Remove Translation"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations", translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations", ProjectSettings::get_singleton()->get("locale/translations"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", ProjectSettings::get_singleton()->get("internationalization/locale/translations"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -136,8 +118,8 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths)
Variant prev;
Dictionary remaps;
- if (ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
- remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
+ remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
prev = remaps;
}
@@ -149,8 +131,8 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths)
}
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Path(s)"), p_paths.size()));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", prev);
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", prev);
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -163,9 +145,9 @@ void LocalizationEditor::_translation_res_option_file_open() {
}
void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_paths) {
- ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps"));
+ ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps"));
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -180,8 +162,8 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_
remaps[key] = r;
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Remap(s)"), p_paths.size()));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -202,11 +184,11 @@ void LocalizationEditor::_translation_res_option_changed() {
return;
}
- if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -234,8 +216,8 @@ void LocalizationEditor::_translation_res_option_changed() {
updating_translations = true;
undo_redo->create_action(TTR("Change Resource Remap Language"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -249,11 +231,11 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
return;
}
- if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
TreeItem *k = Object::cast_to<TreeItem>(p_item);
@@ -263,8 +245,8 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
remaps.erase(key);
undo_redo->create_action(TTR("Remove Resource Remap"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -277,11 +259,11 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
return;
}
- if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -298,8 +280,8 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
remaps[key] = r;
undo_redo->create_action(TTR("Remove Resource Remap Option"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translation_remaps", ProjectSettings::get_singleton()->get("locale/translation_remaps"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -316,8 +298,8 @@ void LocalizationEditor::_translation_filter_option_changed() {
Variant prev;
Array f_locales_all;
- if (ProjectSettings::get_singleton()->has_setting("locale/locale_filter")) {
- f_locales_all = ProjectSettings::get_singleton()->get("locale/locale_filter");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
+ f_locales_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
prev = f_locales_all;
if (f_locales_all.size() != 2) {
@@ -346,8 +328,8 @@ void LocalizationEditor::_translation_filter_option_changed() {
f_locales.sort();
undo_redo->create_action(TTR("Changed Locale Filter"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/locale_filter", f_locales_all);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/locale_filter", prev);
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", f_locales_all);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", prev);
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -361,8 +343,8 @@ void LocalizationEditor::_translation_filter_mode_changed(int p_mode) {
Variant prev;
Array f_locales_all;
- if (ProjectSettings::get_singleton()->has_setting("locale/locale_filter")) {
- f_locales_all = ProjectSettings::get_singleton()->get("locale/locale_filter");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
+ f_locales_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
prev = f_locales_all;
if (f_locales_all.size() != 2) {
@@ -378,8 +360,8 @@ void LocalizationEditor::_translation_filter_mode_changed(int p_mode) {
}
undo_redo->create_action(TTR("Changed Locale Filter Mode"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/locale_filter", f_locales_all);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/locale_filter", prev);
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", f_locales_all);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter", prev);
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -388,7 +370,7 @@ void LocalizationEditor::_translation_filter_mode_changed(int p_mode) {
}
void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
for (int i = 0; i < p_paths.size(); i++) {
for (int j = 0; j < pot_translations.size(); j++) {
@@ -401,8 +383,8 @@ void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
}
undo_redo->create_action(vformat(TTR("Add %d file(s) for POT generation"), p_paths.size()));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", pot_translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", ProjectSettings::get_singleton()->get("locale/translations_pot_files"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -416,15 +398,15 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button)
int idx = ti->get_metadata(0);
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
ERR_FAIL_INDEX(idx, pot_translations.size());
pot_translations.remove(idx);
undo_redo->create_action(TTR("Remove file from POT generation"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", pot_translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", ProjectSettings::get_singleton()->get("locale/translations_pot_files"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -463,8 +445,8 @@ void LocalizationEditor::update_translations() {
translation_list->clear();
TreeItem *root = translation_list->create_item(nullptr);
translation_list->set_hide_root(true);
- if (ProjectSettings::get_singleton()->has_setting("locale/translations")) {
- PackedStringArray translations = ProjectSettings::get_singleton()->get("locale/translations");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translations")) {
+ PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
for (int i = 0; i < translations.size(); i++) {
TreeItem *t = translation_list->create_item(root);
t->set_editable(0, false);
@@ -482,8 +464,8 @@ void LocalizationEditor::update_translations() {
Array l_filter_all;
bool is_arr_empty = true;
- if (ProjectSettings::get_singleton()->has_setting("locale/locale_filter")) {
- l_filter_all = ProjectSettings::get_singleton()->get("locale/locale_filter");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter")) {
+ l_filter_all = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter");
if (l_filter_all.size() == 2) {
translation_locale_filter_mode->select(l_filter_all[0]);
@@ -573,8 +555,8 @@ void LocalizationEditor::update_translations() {
}
}
- if (ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
List<Variant> rk;
remaps.get_key_list(&rk);
Vector<String> keys;
@@ -631,8 +613,8 @@ void LocalizationEditor::update_translations() {
translation_pot_list->clear();
root = translation_pot_list->create_item(nullptr);
translation_pot_list->set_hide_root(true);
- if (ProjectSettings::get_singleton()->has_setting("locale/translations_pot_files")) {
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translations_pot_files")) {
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
for (int i = 0; i < pot_translations.size(); i++) {
TreeItem *t = translation_pot_list->create_item(root);
t->set_editable(0, false);
@@ -649,26 +631,6 @@ void LocalizationEditor::update_translations() {
updating_translations = false;
}
-void LocalizationEditor::_install_ts_data() {
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- TS->save_support_data("res://" + TS->get_support_data_filename());
- }
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
-}
-
void LocalizationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_translations"), &LocalizationEditor::update_translations);
@@ -838,37 +800,4 @@ LocalizationEditor::LocalizationEditor() {
pot_file_open_dialog->connect("files_selected", callable_mp(this, &LocalizationEditor::_pot_add));
add_child(pot_file_open_dialog);
}
-
- {
- VBoxContainer *tvb = memnew(VBoxContainer);
- tvb->set_name(TTR("Text Server Data"));
- translations->add_child(tvb);
-
- ts_name = memnew(Label(TTR("Text server: ") + TS->get_name()));
- tvb->add_child(ts_name);
-
- ts_data_status = memnew(Label(TTR("Support data: ")));
- tvb->add_child(ts_data_status);
-
- ts_data_info = memnew(Label(TTR("Info: ") + TS->get_support_data_info()));
- tvb->add_child(ts_data_info);
-
- ts_install = memnew(Button(TTR("Install support data...")));
- ts_install->connect("pressed", callable_mp(this, &LocalizationEditor::_install_ts_data));
- tvb->add_child(ts_install);
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- }
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 6e0d7ce61f..23cea06fbe 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -58,11 +58,6 @@ class LocalizationEditor : public VBoxContainer {
Vector<TreeItem *> translation_filter_treeitems;
Vector<int> translation_locales_idxs_remap;
- Label *ts_name;
- Label *ts_data_status;
- Label *ts_data_info;
- Button *ts_install;
-
Tree *translation_pot_list;
EditorFileDialog *pot_file_open_dialog;
EditorFileDialog *pot_generate_dialog;
@@ -94,8 +89,6 @@ class LocalizationEditor : public VBoxContainer {
void _pot_generate(const String &p_file);
void _update_pot_file_extensions();
- void _install_ts_data();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp
index bd825d0802..afafd7d195 100644
--- a/editor/node_3d_editor_gizmos.cpp
+++ b/editor/node_3d_editor_gizmos.cpp
@@ -47,6 +47,7 @@
#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/physics_joint_3d.h"
#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
@@ -176,6 +177,7 @@ void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden)
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, RS::SHADOW_CASTING_SETTING_OFF);
int layer = p_hidden ? 0 : 1 << Node3DEditorViewport::GIZMO_EDIT_LAYER;
RS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
+ RS::get_singleton()->instance_geometry_set_flag(instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const Ref<SkinReference> &p_skin_reference, const Ref<Material> &p_material) {
@@ -198,7 +200,11 @@ void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard,
}
void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
- if (p_lines.is_empty()) {
+ add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate);
+}
+
+void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Ref<Material> &p_material, Mesh::PrimitiveType p_primitive_type, bool p_billboard, const Color &p_modulate) {
+ if (p_vertices.is_empty()) {
return;
}
@@ -209,13 +215,13 @@ void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mate
Array a;
a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = p_lines;
+ a[Mesh::ARRAY_VERTEX] = p_vertices;
Vector<Color> color;
- color.resize(p_lines.size());
+ color.resize(p_vertices.size());
{
Color *w = color.ptrw();
- for (int i = 0; i < p_lines.size(); i++) {
+ for (int i = 0; i < p_vertices.size(); i++) {
if (is_selected()) {
w[i] = Color(1, 1, 1, 0.8) * p_modulate;
} else {
@@ -226,13 +232,13 @@ void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mate
a[Mesh::ARRAY_COLOR] = color;
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
+ mesh->add_surface_from_arrays(p_primitive_type, a);
mesh->surface_set_material(0, p_material);
if (p_billboard) {
float md = 0;
- for (int i = 0; i < p_lines.size(); i++) {
- md = MAX(0, p_lines[i].length());
+ for (int i = 0; i < p_vertices.size(); i++) {
+ md = MAX(0, p_vertices[i].length());
}
if (md) {
mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
@@ -557,7 +563,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
Transform t = spatial_node->get_global_transform();
Vector3 camera_position = p_camera->get_camera_transform().origin;
if (camera_position.distance_squared_to(t.origin) > 0.01) {
- t.set_look_at(t.origin, camera_position, Vector3(0, 1, 0));
+ t.set_look_at(t.origin, camera_position);
}
float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
@@ -574,7 +580,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01 &&
ABS(orig_camera_transform.basis.get_axis(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
- p_camera->look_at(t.origin, Vector3(0, 1, 0));
+ p_camera->look_at(t.origin);
}
Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
@@ -1460,6 +1466,44 @@ void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
/////
+
+OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() {
+ create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1)));
+}
+
+bool OccluderInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<OccluderInstance3D>(p_spatial) != nullptr;
+}
+
+String OccluderInstance3DGizmoPlugin::get_gizmo_name() const {
+ return "OccluderInstance3D";
+}
+
+int OccluderInstance3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ OccluderInstance3D *occluder_instance = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Occluder3D> o = occluder_instance->get_occluder();
+
+ if (!o.is_valid()) {
+ return;
+ }
+
+ Vector<Vector3> lines = o->get_debug_lines();
+ if (!lines.is_empty()) {
+ Ref<Material> material = get_material("line_material", p_gizmo);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ }
+}
+
+/////
+
Sprite3DGizmoPlugin::Sprite3DGizmoPlugin() {
}
@@ -1906,16 +1950,15 @@ void RayCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
- Vector<Vector3> lines;
+ const Ref<StandardMaterial3D> material = raycast->is_enabled() ? raycast->get_debug_material() : get_material("shape_material_disabled");
- lines.push_back(Vector3());
- lines.push_back(raycast->get_target_position());
+ p_gizmo->add_lines(raycast->get_debug_line_vertices(), material);
- const Ref<StandardMaterial3D> material =
- get_material(raycast->is_enabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
+ if (raycast->get_debug_shape_thickness() > 1) {
+ p_gizmo->add_vertices(raycast->get_debug_shape_vertices(), material, Mesh::PRIMITIVE_TRIANGLE_STRIP);
+ }
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_collision_segments(raycast->get_debug_line_vertices());
}
/////
@@ -2070,7 +2113,13 @@ void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh();
Vector<Vector3> points;
- soft_body->get_mesh()->generate_debug_mesh_indices(points);
+ for (int i = 0; i < soft_body->get_mesh()->get_surface_count(); i++) {
+ Array arrays = soft_body->get_mesh()->surface_get_arrays(i);
+ ERR_CONTINUE(arrays.is_empty());
+
+ const Vector<Vector3> &vertices = arrays[Mesh::ARRAY_VERTEX];
+ points.append_array(vertices);
+ }
Ref<Material> material = get_material("shape_material", p_gizmo);
@@ -3505,6 +3554,57 @@ void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
+CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() {
+ const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+ const float gizmo_value = gizmo_color.get_v();
+ const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
+ create_material("shape_material_disabled", gizmo_color_disabled);
+}
+
+bool CollisionObject3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<CollisionObject3D>(p_spatial) != nullptr;
+}
+
+String CollisionObject3DGizmoPlugin::get_gizmo_name() const {
+ return "CollisionObject3D";
+}
+
+int CollisionObject3DGizmoPlugin::get_priority() const {
+ return -2;
+}
+
+void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ List<uint32_t> owners;
+ co->get_shape_owners(&owners);
+ for (List<uint32_t>::Element *E = owners.front(); E; E = E->next()) {
+ uint32_t owner_id = E->get();
+ Transform xform = co->shape_owner_get_transform(owner_id);
+ Object *owner = co->shape_owner_get_owner(owner_id);
+ // Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo.
+ if (!Object::cast_to<CollisionShape3D>(owner) && !Object::cast_to<CollisionPolygon3D>(owner)) {
+ Ref<Material> material = get_material(!co->is_shape_owner_disabled(owner_id) ? "shape_material" : "shape_material_disabled", p_gizmo);
+ for (int shape_id = 0; shape_id < co->shape_owner_get_shape_count(owner_id); shape_id++) {
+ Ref<Shape3D> s = co->shape_owner_get_shape(owner_id, shape_id);
+ if (s.is_null()) {
+ continue;
+ }
+ SurfaceTool st;
+ st.append_from(s->get_debug_mesh(), 0, xform);
+
+ p_gizmo->add_mesh(st.commit(), false, Ref<SkinReference>(), material);
+ p_gizmo->add_collision_segments(s->get_debug_mesh_lines());
+ }
+ }
+ }
+}
+
+////
+
CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
create_material("shape_material", gizmo_color);
diff --git a/editor/node_3d_editor_gizmos.h b/editor/node_3d_editor_gizmos.h
index df4ed15a8e..95344176ad 100644
--- a/editor/node_3d_editor_gizmos.h
+++ b/editor/node_3d_editor_gizmos.h
@@ -100,6 +100,18 @@ public:
MeshInstance3DGizmoPlugin();
};
+class OccluderInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(OccluderInstance3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ OccluderInstance3DGizmoPlugin();
+};
+
class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Sprite3DGizmoPlugin, EditorNode3DGizmoPlugin);
@@ -355,6 +367,18 @@ public:
LightmapProbeGizmoPlugin();
};
+class CollisionObject3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(CollisionObject3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ CollisionObject3DGizmoPlugin();
+};
+
class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 19c9662162..f496811e0a 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -86,7 +86,7 @@ void PluginConfigDialog::_on_confirmed() {
// Hard-coded GDScript template to keep usability until we use script templates.
Ref<Script> gdscript = memnew(GDScript);
gdscript->set_source_code(
- "tool\n"
+ "@tool\n"
"extends EditorPlugin\n"
"\n"
"\n"
@@ -112,7 +112,7 @@ void PluginConfigDialog::_on_confirmed() {
}
#endif
- emit_signal("plugin_ready", script.operator->(), active_edit->is_pressed() ? subfolder_edit->get_text() : "");
+ emit_signal("plugin_ready", script.operator->(), active_edit->is_pressed() ? _to_absolute_plugin_path(subfolder_edit->get_text()) : "");
} else {
EditorNode::get_singleton()->get_project_settings()->update_plugins();
}
@@ -129,6 +129,10 @@ void PluginConfigDialog::_on_required_text_changed(const String &) {
get_ok_button()->set_disabled(script_edit->get_text().get_basename().is_empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().is_empty());
}
+String PluginConfigDialog::_to_absolute_plugin_path(const String &p_plugin_name) {
+ return "res://addons/" + p_plugin_name + "/plugin.cfg";
+}
+
void PluginConfigDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/editor/plugin_config_dialog.h b/editor/plugin_config_dialog.h
index 50ca417d81..f49f14c881 100644
--- a/editor/plugin_config_dialog.h
+++ b/editor/plugin_config_dialog.h
@@ -56,6 +56,8 @@ class PluginConfigDialog : public ConfirmationDialog {
void _on_cancelled();
void _on_required_text_changed(const String &p_text);
+ static String _to_absolute_plugin_path(const String &p_plugin_name);
+
protected:
virtual void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 876b67fa77..80d0a7db60 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -264,7 +264,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (mb->get_control() || mb->get_shift() || mb->get_alt()) {
return false;
@@ -326,7 +326,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -335,7 +335,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
}
} else if (mode == MODE_DELETE) {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -346,7 +346,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
if (mode == MODE_CREATE) {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
if (_is_line()) {
// for lines, we don't have a wip mode, and we can undo each single add point.
Vector<Vector2> vertices = _get_polygon(0);
@@ -384,7 +384,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
_wip_cancel();
}
}
@@ -395,7 +395,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mm.is_valid()) {
Vector2 gpoint = mm->get_position();
- if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) {
+ if (edited_point.valid() && (wip_active || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT))) {
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
//Move the point in a single axis. Should only work when editing a polygon and while holding shift.
@@ -585,11 +585,11 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
edited_point = PosVertex();
hover_point = Vertex();
selected_point = Vertex();
-
- canvas_item_editor->update_viewport();
} else {
_set_node(nullptr);
}
+
+ canvas_item_editor->update_viewport();
}
void AbstractPolygon2DEditor::_bind_methods() {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index d69913cc46..f7c0ebcfaf 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -51,7 +51,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -110,7 +110,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); // why not
// try to see if a point can be selected
@@ -132,7 +132,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (dragging_selected) {
// move
float point = blend_space->get_blend_point_position(selected_point);
@@ -161,7 +161,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
// *set* the blend
- if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -184,7 +184,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
_update_edited_point_pos();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -698,7 +698,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
max_value->set_step(0.01);
label_value = memnew(LineEdit);
- label_value->set_expand_to_text_length(true);
+ label_value->set_expand_to_text_length_enabled(true);
// now add
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 6a57463dbc..e719df53d5 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -79,7 +79,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -134,7 +134,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -174,7 +174,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -209,7 +209,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (dragging_selected) {
//move
Vector2 point = blend_space->get_blend_point_position(selected_point);
@@ -236,7 +236,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 blend_pos = (mb->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -270,7 +270,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
Vector2 blend_pos = (mm->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -942,7 +942,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
left_vbox->add_spacer();
label_y = memnew(LineEdit);
left_vbox->add_child(label_y);
- label_y->set_expand_to_text_length(true);
+ label_y->set_expand_to_text_length_enabled(true);
left_vbox->add_spacer();
min_y_value = memnew(SpinBox);
left_vbox->add_child(min_y_value);
@@ -978,7 +978,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
bottom_vbox->add_spacer();
label_x = memnew(LineEdit);
bottom_vbox->add_child(label_x);
- label_x->set_expand_to_text_length(true);
+ label_x->set_expand_to_text_length_enabled(true);
bottom_vbox->add_spacer();
max_x_value = memnew(SpinBox);
bottom_vbox->add_child(max_x_value);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index e7e069e8b6..48fb507bb1 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -136,10 +136,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E->get()) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E->get());
- name->set_expand_to_text_length(true);
+ name->set_expand_to_text_length_enabled(true);
node->add_child(name);
node->set_slot(0, false, 0, Color(), true, 0, get_theme_color("font_color", "Label"));
- name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode));
+ name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED);
base = 1;
node->set_show_close_button(true);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 56d82acd2f..612a8f30a4 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -78,7 +78,6 @@ void AnimationPlayerEditor::_notification(int p_what) {
}
frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
- EditorNode::get_singleton()->get_inspector()->refresh();
} else if (!player->is_valid()) {
// Reset timeline when the player has been stopped externally
@@ -118,8 +117,8 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons");
reset_icon = get_theme_icon("Reload", "EditorIcons");
{
- Ref<Image> autoplay_img = autoplay_icon->get_data();
- Ref<Image> reset_img = reset_icon->get_data();
+ Ref<Image> autoplay_img = autoplay_icon->get_image();
+ Ref<Image> reset_img = reset_icon->get_image();
Ref<Image> autoplay_reset_img;
Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height());
autoplay_reset_img.instance();
@@ -1072,8 +1071,6 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag)
frame->set_value(Math::snapped(p_pos, _get_editor_step()));
updating = false;
_seek_value_changed(p_pos, !p_drag);
-
- EditorNode::get_singleton()->get_inspector()->refresh();
}
void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
@@ -1222,6 +1219,8 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) {
}
void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->get_alt() && !k->get_control() && !k->get_metakey()) {
switch (k->get_keycode()) {
@@ -1400,7 +1399,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Render every past/future step with the capture shader.
RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid());
- onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/default_clear_color"));
+ onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
onion.capture.material->set_shader_param("differences_only", onion.differences_only);
onion.capture.material->set_shader_param("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index c6d2faf849..a9709bbb16 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -76,7 +76,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
//Add new node
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -124,7 +124,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// select node or push a field inside
- if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_node = StringName();
@@ -216,7 +216,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//end moving node
- if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (dragging_selected) {
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
@@ -237,7 +237,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//connect nodes
- if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
connecting = true;
@@ -250,7 +250,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//end connecting nodes
- if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && connecting && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (connecting_to_node != StringName()) {
if (state_machine->has_transition(connecting_from, connecting_to_node)) {
EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
@@ -284,7 +284,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseMotion> mm = p_event;
//pan window
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index d726cd031e..fd47d9964e 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -144,8 +144,8 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
for (int i = 0; i < preview_images.size(); i++) {
if (preview_images[i].id == p_index) {
if (preview_images[i].is_video) {
- Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_data();
- Ref<Image> thumbnail = p_image->get_data();
+ Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_image();
+ Ref<Image> thumbnail = p_image->get_image();
thumbnail = thumbnail->duplicate();
Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2);
@@ -350,7 +350,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
if (sha256 != download_sha256) {
error_text = TTR("Bad download hash, assuming file has been tampered with.") + "\n";
error_text += TTR("Expected:") + " " + sha256 + "\n" + TTR("Got:") + " " + download_sha256;
- status->set_text(TTR("Failed sha256 hash check"));
+ status->set_text(TTR("Failed SHA-256 hash check"));
}
}
} break;
@@ -359,6 +359,8 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
if (error_text != String()) {
download_error->set_text(TTR("Asset Download Error:") + "\n" + error_text);
download_error->popup_centered();
+ // Let the user retry the download.
+ retry->show();
return;
}
@@ -459,6 +461,9 @@ void EditorAssetLibraryItemDownload::_install() {
}
void EditorAssetLibraryItemDownload::_make_request() {
+ // Hide the Retry button if we've just pressed it.
+ retry->hide();
+
download->cancel_request();
download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
@@ -516,6 +521,8 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
retry = memnew(Button);
retry->set_text(TTR("Retry"));
retry->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request));
+ // Only show the Retry button in case of a failure.
+ retry->hide();
hb2->add_child(retry);
hb2->add_child(install);
@@ -550,8 +557,15 @@ void EditorAssetLibrary::_notification(int p_what) {
error_label->raise();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible() && initial_loading) {
- _repository_changed(0); // Update when shown for the first time.
+ if (is_visible()) {
+ // Focus the search box automatically when switching to the Templates tab (in the Project Manager)
+ // or switching to the AssetLib tab (in the editor).
+ // The Project Manager's project filter box is automatically focused in the project manager code.
+ filter->grab_focus();
+
+ if (initial_loading) {
+ _repository_changed(0); // Update when shown for the first time.
+ }
}
} break;
case NOTIFICATION_PROCESS: {
@@ -577,10 +591,30 @@ void EditorAssetLibrary::_notification(int p_what) {
filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ _update_repository_options();
+ } break;
+ }
+}
+
+void EditorAssetLibrary::_update_repository_options() {
+ Dictionary default_urls;
+ default_urls["godotengine.org"] = "https://godotengine.org/asset-library/api";
+ default_urls["localhost"] = "http://127.0.0.1/asset-library/api";
+ Dictionary available_urls = _EDITOR_DEF("asset_library/available_urls", default_urls, true);
+ repository->clear();
+ Array keys = available_urls.keys();
+ for (int i = 0; i < available_urls.size(); i++) {
+ String key = keys[i];
+ repository->add_item(key);
+ repository->set_item_metadata(i, available_urls[key]);
}
}
void EditorAssetLibrary::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed()) {
@@ -962,14 +996,16 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
for (int i = from; i < to; i++) {
if (i == p_page) {
Button *current = memnew(Button);
- current->set_text(itos(i + 1));
+ // Keep the extended padding for the currently active page (see below).
+ current->set_text(vformat(" %d ", i + 1));
current->set_disabled(true);
current->set_focus_mode(Control::FOCUS_NONE);
hbc->add_child(current);
} else {
Button *current = memnew(Button);
- current->set_text(itos(i + 1));
+ // Add padding to make page number buttons easier to click.
+ current->set_text(vformat(" %d ", i + 1));
current->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(i));
hbc->add_child(current);
@@ -1305,6 +1341,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_main->add_theme_constant_override("separation", 10 * EDSCALE);
filter = memnew(LineEdit);
+ if (templates_only) {
+ filter->set_placeholder(TTR("Search templates, projects, and demos"));
+ } else {
+ filter->set_placeholder(TTR("Search assets (excluding templates, projects, and demos)"));
+ }
search_hb->add_child(filter);
filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->connect("text_changed", callable_mp(this, &EditorAssetLibrary::_search_text_changed));
@@ -1364,18 +1405,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(memnew(Label(TTR("Site:") + " ")));
repository = memnew(OptionButton);
- {
- Dictionary default_urls;
- default_urls["godotengine.org"] = "https://godotengine.org/asset-library/api";
- default_urls["localhost"] = "http://127.0.0.1/asset-library/api";
- Dictionary available_urls = _EDITOR_DEF("asset_library/available_urls", default_urls, true);
- Array keys = available_urls.keys();
- for (int i = 0; i < available_urls.size(); i++) {
- String key = keys[i];
- repository->add_item(key);
- repository->set_item_metadata(i, available_urls[key]);
- }
- }
+ _update_repository_options();
repository->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_repository_changed));
@@ -1387,6 +1417,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
support = memnew(MenuButton);
search_hb2->add_child(support);
support->set_text(TTR("Support"));
+ support->get_popup()->set_hide_on_checkable_item_selection(false);
support->get_popup()->add_check_item(TTR("Official"), SUPPORT_OFFICIAL);
support->get_popup()->add_check_item(TTR("Community"), SUPPORT_COMMUNITY);
support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING);
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 0509145673..11eae9e041 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -176,6 +176,7 @@ class EditorAssetLibrary : public PanelContainer {
void _asset_open();
void _asset_file_selected(const String &p_file);
+ void _update_repository_options();
PanelContainer *library_scroll_bg;
ScrollContainer *library_scroll;
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 1765c99572..3553450672 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -96,7 +96,7 @@ void AudioStreamEditor::_preview_changed(ObjectID p_which) {
}
}
-void AudioStreamEditor::_changed_callback(Object *p_changed, const char *p_prop) {
+void AudioStreamEditor::_audio_changed() {
if (!is_visible()) {
return;
}
@@ -105,6 +105,8 @@ void AudioStreamEditor::_changed_callback(Object *p_changed, const char *p_prop)
void AudioStreamEditor::_play() {
if (_player->is_playing()) {
+ // '_pausing' variable indicates that we want to pause the audio player, not stop it. See '_on_finished()'.
+ _pausing = true;
_player->stop();
_play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
set_process(false);
@@ -125,10 +127,13 @@ void AudioStreamEditor::_stop() {
void AudioStreamEditor::_on_finished() {
_play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
- if (_current == _player->get_stream()->get_length()) {
+ if (!_pausing) {
_current = 0;
_indicator->update();
+ } else {
+ _pausing = false;
}
+ set_process(false);
}
void AudioStreamEditor::_draw_indicator() {
@@ -172,7 +177,7 @@ void AudioStreamEditor::_seek_to(real_t p_x) {
void AudioStreamEditor::edit(Ref<AudioStream> p_stream) {
if (!stream.is_null()) {
- stream->remove_change_receptor(this);
+ stream->disconnect("changed", callable_mp(this, &AudioStreamEditor::_audio_changed));
}
stream = p_stream;
@@ -182,7 +187,7 @@ void AudioStreamEditor::edit(Ref<AudioStream> p_stream) {
_duration_label->set_text(text);
if (!stream.is_null()) {
- stream->add_change_receptor(this);
+ stream->connect("changed", callable_mp(this, &AudioStreamEditor::_audio_changed));
update();
} else {
hide();
@@ -194,8 +199,6 @@ void AudioStreamEditor::_bind_methods() {
AudioStreamEditor::AudioStreamEditor() {
set_custom_minimum_size(Size2(1, 100) * EDSCALE);
- _current = 0;
- _dragging = false;
_player = memnew(AudioStreamPlayer);
_player->connect("finished", callable_mp(this, &AudioStreamEditor::_on_finished));
diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h
index f27add7229..14e829d025 100644
--- a/editor/plugins/audio_stream_editor_plugin.h
+++ b/editor/plugins/audio_stream_editor_plugin.h
@@ -41,17 +41,20 @@ class AudioStreamEditor : public ColorRect {
GDCLASS(AudioStreamEditor, ColorRect);
Ref<AudioStream> stream;
- AudioStreamPlayer *_player;
- ColorRect *_preview;
- Control *_indicator;
- Label *_current_label;
- Label *_duration_label;
+ AudioStreamPlayer *_player = nullptr;
+ ColorRect *_preview = nullptr;
+ Control *_indicator = nullptr;
+ Label *_current_label = nullptr;
+ Label *_duration_label = nullptr;
- Button *_play_button;
- Button *_stop_button;
+ Button *_play_button = nullptr;
+ Button *_stop_button = nullptr;
- float _current;
- bool _dragging;
+ float _current = 0;
+ bool _dragging = false;
+ bool _pausing = false;
+
+ void _audio_changed();
protected:
void _notification(int p_what);
@@ -63,7 +66,6 @@ protected:
void _draw_indicator();
void _on_input_indicator(Ref<InputEvent> p_event);
void _seek_to(real_t p_x);
- void _changed_callback(Object *p_changed, const char *p_prop) override;
static void _bind_methods();
public:
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index d92837b68d..6ac47595dc 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -472,6 +472,8 @@ float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
}
void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (!is_visible_in_tree()) {
@@ -629,9 +631,9 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
Node *node = r_items[i].item;
// Make sure the selected node is in the current scene, or editable
- while (node && node != get_tree()->get_edited_scene_root() && node->get_owner() != scene && !scene->is_editable_instance(node->get_owner())) {
- node = node->get_parent();
- };
+ if (node && node != get_tree()->get_edited_scene_root()) {
+ node = scene->get_deepest_editable_node(node);
+ }
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
if (!p_allow_locked) {
@@ -762,7 +764,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
Node *scene = editor->get_edited_scene();
- bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner());
+ bool editable = p_node == scene || p_node->get_owner() == scene || p_node == scene->get_deepest_editable_node(p_node);
bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
bool locked = _is_node_locked(p_node);
@@ -802,11 +804,15 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append) {
bool still_selected = true;
- if (p_append) {
+ if (p_append && !editor_selection->get_selected_node_list().is_empty()) {
if (editor_selection->is_selected(item)) {
// Already in the selection, remove it from the selected nodes
editor_selection->remove_node(item);
still_selected = false;
+
+ if (editor_selection->get_selected_node_list().size() == 1) {
+ editor->push_item(editor_selection->get_selected_node_list()[0]);
+ }
} else {
// Add the item to the selection
editor_selection->add_node(item);
@@ -955,9 +961,11 @@ void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_it
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- canvas_item->_edit_set_state(se->undo_state);
- if (restore_bones) {
- _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
+ if (se) {
+ canvas_item->_edit_set_state(se->undo_state);
+ if (restore_bones) {
+ _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
+ }
}
}
}
@@ -982,13 +990,15 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
for (List<CanvasItem *>::Element *E = modified_canvas_items.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
- undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state);
- if (commit_bones) {
- for (List<Dictionary>::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) {
- canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
- undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
- undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get());
+ if (se) {
+ undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
+ undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state);
+ if (commit_bones) {
+ for (List<Dictionary>::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) {
+ canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
+ undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
+ undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get());
+ }
}
}
}
@@ -1021,6 +1031,32 @@ void CanvasItemEditor::_selection_menu_hide() {
selection_menu->set_size(Vector2(0, 0));
}
+void CanvasItemEditor::_add_node_pressed(int p_result) {
+ if (p_result == AddNodeOption::ADD_NODE) {
+ editor->get_scene_tree_dock()->open_add_child_dialog();
+ } else if (p_result == AddNodeOption::ADD_INSTANCE) {
+ editor->get_scene_tree_dock()->open_instance_child_dialog();
+ }
+}
+
+void CanvasItemEditor::_node_created(Node *p_node) {
+ if (node_create_position == Point2()) {
+ return;
+ }
+
+ CanvasItem *c = Object::cast_to<CanvasItem>(p_node);
+ if (c) {
+ Transform2D xform = c->get_global_transform_with_canvas().affine_inverse() * c->get_transform();
+ c->_edit_set_position(xform.xform(node_create_position));
+ }
+
+ call_deferred("_reset_create_position"); // Defer the call in case more than one node is added.
+}
+
+void CanvasItemEditor::_reset_create_position() {
+ node_create_position = Point2();
+}
+
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
Ref<InputEventMouseMotion> m = p_event;
@@ -1065,7 +1101,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Start dragging a guide
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
// Press button
if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) {
// Drag a new double guide
@@ -1124,7 +1160,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Release confirms the guide move
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (show_guides && EditorNode::get_singleton()->get_edited_scene()) {
Transform2D xform = viewport_scrollable->get_transform() * transform;
@@ -1238,7 +1274,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
if (pan_on_scroll) {
// Perform horizontal scrolling first so we can check for Shift being held.
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_UP))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP))) {
// Pan left
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1246,7 +1282,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_DOWN))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN))) {
// Pan right
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1254,7 +1290,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
// Scroll or pan down
if (pan_on_scroll) {
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -1269,7 +1305,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
return true;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
// Scroll or pan up
if (pan_on_scroll) {
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -1286,17 +1322,17 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
if (!panning) {
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_MIDDLE ||
- b->get_button_index() == BUTTON_RIGHT ||
- (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
- (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
+ (b->get_button_index() == MOUSE_BUTTON_MIDDLE ||
+ b->get_button_index() == MOUSE_BUTTON_RIGHT ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_PAN) ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
// Pan the viewport
panning = true;
}
}
if (panning) {
- if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != BUTTON_WHEEL_DOWN && b->get_button_index() != BUTTON_WHEEL_UP))) {
+ if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != MOUSE_BUTTON_WHEEL_DOWN && b->get_button_index() != MOUSE_BUTTON_WHEEL_UP))) {
// Stop panning the viewport (for any mouse button press except zooming)
panning = false;
}
@@ -1382,7 +1418,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Drag the pivot (in pivot mode / with V key)
if (drag_type == DRAG_NONE) {
- if ((b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
+ if ((b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -1436,7 +1472,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Confirm the pivot move
if (drag_selection.size() >= 1 &&
- ((b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
+ ((b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && !k->is_pressed() && k->get_keycode() == KEY_V))) {
_commit_canvas_item_state(
drag_selection,
@@ -1450,7 +1486,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1536,7 +1572,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
if ((b->get_command() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -1580,7 +1616,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Confirms the node rotation
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -1604,7 +1640,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1618,7 +1654,7 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
Ref<InputEventMouseButton> b = p_event;
// Open a sub-scene on double-click
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1637,7 +1673,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
// Starts anchor dragging if needed
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
Control *control = Object::cast_to<Control>(selection[0]);
@@ -1757,7 +1793,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Confirms new anchor position
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
_commit_canvas_item_state(
drag_selection,
vformat(TTR("Move CanvasItem \"%s\" Anchor"), drag_selection[0]->get_name()));
@@ -1766,7 +1802,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1782,7 +1818,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1936,7 +1972,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Confirm resize
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
const Node2D *node2d = Object::cast_to<Node2D>(drag_selection[0]);
if (node2d) {
// Extends from Node2D.
@@ -1973,7 +2009,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -1991,7 +2027,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -2087,7 +2123,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
// Confirm resize
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -2112,7 +2148,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -2129,7 +2165,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -2212,17 +2248,19 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
-
- Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
- if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
- real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
- real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
- _solve_IK(node2d, new_pos);
- } else {
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ if (se) {
+ Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+
+ Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
+ if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
+ real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
+ real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
+ _solve_IK(node2d, new_pos);
+ } else {
+ canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ }
}
index++;
}
@@ -2230,7 +2268,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Confirm the move (only if it was moved)
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (transform.affine_inverse().xform(b->get_position()) != drag_from) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
@@ -2263,7 +2301,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection, true);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -2346,17 +2384,19 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
-
- Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
- if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
- real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
- real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
- _solve_IK(node2d, new_pos);
- } else {
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ if (se) {
+ Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+
+ Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
+ if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
+ real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
+ real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
+ node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
+ _solve_IK(node2d, new_pos);
+ } else {
+ canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ }
}
index++;
}
@@ -2401,8 +2441,8 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
if (b.is_valid() &&
- ((b->get_button_index() == BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
- (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
+ ((b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2463,7 +2503,15 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
}
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_control()) {
+ add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+ add_node_menu->set_size(Vector2(1, 1));
+ add_node_menu->popup();
+ node_create_position = transform.affine_inverse().xform((get_local_mouse_position()));
+ return true;
+ }
+
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
// Single item selection
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2529,7 +2577,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
if (drag_type == DRAG_BOX_SELECTION) {
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
// Confirms box selection
Node *scene = editor->get_edited_scene();
if (scene) {
@@ -2545,6 +2593,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
_find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
+ if (selitems.size() == 1 && editor_selection->get_selected_node_list().is_empty()) {
+ editor->push_item(selitems[0]);
+ }
for (List<CanvasItem *>::Element *E = selitems.front(); E; E = E->next()) {
editor_selection->add_node(E->get());
}
@@ -2555,7 +2606,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_RIGHT) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT) {
// Cancel box selection
drag_type = DRAG_NONE;
viewport->update();
@@ -2580,6 +2631,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
if (tool != TOOL_RULER) {
+ ruler_tool_active = false;
return false;
}
@@ -2591,7 +2643,7 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset);
}
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (b->is_pressed()) {
ruler_tool_active = true;
} else {
@@ -2868,21 +2920,22 @@ void CanvasItemEditor::_draw_guides() {
// Dragged guide
Color text_color = get_theme_color("font_color", "Editor");
- text_color.a = 0.5;
+ Color outline_color = text_color.inverted();
+ const float outline_size = 2;
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE) {
String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x)));
- Ref<Font> font = get_theme_font("font", "Label");
- int font_size = get_theme_font_size("font_size", "Label");
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ int font_size = get_theme_font_size("bold_size", "EditorFonts");
Size2 text_size = font->get_string_size(str, font_size);
- viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color);
+ viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color, outline_size, outline_color);
viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
}
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) {
String str = TS->format_number(vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y)));
- Ref<Font> font = get_theme_font("font", "Label");
- int font_size = get_theme_font_size("font_size", "Label");
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ int font_size = get_theme_font_size("bold_size", "EditorFonts");
Size2 text_size = font->get_string_size(str, font_size);
- viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color);
+ viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color, outline_size, outline_color);
viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE));
}
}
@@ -3867,7 +3920,7 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
Node *scene = editor->get_edited_scene();
- if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) {
+ if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && canvas_item != scene->get_deepest_editable_node(canvas_item))) {
return false;
}
@@ -5332,9 +5385,6 @@ void CanvasItemEditor::_focus_selection(int p_op) {
rect = rect.merge(canvas_item_rect);
}
};
- if (count == 0) {
- return;
- }
if (p_op == VIEW_CENTER_TO_SELECTION) {
center = rect.position + rect.size / 2;
@@ -5363,6 +5413,7 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input);
ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list);
ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
+ ClassDB::bind_method("_reset_create_position", &CanvasItemEditor::_reset_create_position);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
@@ -5684,6 +5735,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
+ editor->get_scene_tree_dock()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
+ editor->get_scene_tree_dock()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
+
editor->call_deferred("connect", "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true));
editor->call_deferred("connect", "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false));
@@ -6105,6 +6159,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
selection_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_selection_result_pressed));
selection_menu->connect("popup_hide", callable_mp(this, &CanvasItemEditor::_selection_menu_hide));
+ add_node_menu = memnew(PopupMenu);
+ add_child(add_node_menu);
+ add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon("Add", "EditorIcons"), TTR("Add Node Here"));
+ add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon("Instance", "EditorIcons"), TTR("Instance Scene Here"));
+ add_node_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_add_node_pressed));
+
multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY);
divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE);
pan_view_shortcut = ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), KEY_SPACE);
@@ -6458,8 +6518,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
type == "CurveTexture" ||
type == "GradientTexture" ||
type == "StreamTexture2D" ||
- type == "AtlasTexture" ||
- type == "LargeTexture") {
+ type == "AtlasTexture") {
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
if (!texture.is_valid()) {
continue;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 24149a57b0..62a9b1e162 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -79,6 +79,11 @@ public:
TOOL_MAX
};
+ enum AddNodeOption {
+ ADD_NODE,
+ ADD_INSTANCE,
+ };
+
private:
EditorNode *editor;
@@ -284,6 +289,7 @@ private:
bool ruler_tool_active;
Point2 ruler_tool_origin;
+ Point2 node_create_position;
MenuOption last_option;
@@ -376,6 +382,7 @@ private:
Button *key_auto_insert_button;
PopupMenu *selection_menu;
+ PopupMenu *add_node_menu;
Control *top_ruler;
Control *left_ruler;
@@ -436,6 +443,9 @@ private:
void _snap_changed();
void _selection_result_pressed(int);
void _selection_menu_hide();
+ void _add_node_pressed(int p_result);
+ void _node_created(Node *p_node);
+ void _reset_create_position();
UndoRedo *undo_redo;
bool _build_bones_list(Node *p_node);
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index 0c18975258..b50a497ccf 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -142,7 +142,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
switch (mode) {
case MODE_CREATE: {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
if (!wip_active) {
wip.clear();
wip.push_back(cpoint);
@@ -166,14 +166,14 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
_wip_close();
}
} break;
case MODE_EDIT: {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (mb->get_control()) {
if (poly.size() < 3) {
@@ -267,7 +267,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
}
}
}
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
@@ -301,7 +301,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+ if (edited_point != -1 && (wip_active || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
Vector2 gpoint = mm->get_position();
Vector3 ray_from = p_camera->project_ray_origin(gpoint);
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index a1e7d3d6e0..c38458c37f 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -207,7 +207,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
} break;
}
- node->get_shape()->_change_notify();
+ node->get_shape()->notify_property_list_changed();
}
void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
@@ -325,7 +325,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
if (mb.is_valid()) {
Vector2 gpoint = mb->get_position();
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
for (int i = 0; i < handles.size(); i++) {
if (xform.xform(handles[i]).distance_to(gpoint) < 8) {
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index bff5cb8d2a..db999f50ab 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -115,22 +115,22 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
}
switch (mb.get_button_index()) {
- case BUTTON_RIGHT:
+ case MOUSE_BUTTON_RIGHT:
_context_click_pos = mpos;
open_context_menu(get_global_transform().xform(mpos));
break;
- case BUTTON_MIDDLE:
+ case MOUSE_BUTTON_MIDDLE:
remove_point(_hover_point);
break;
- case BUTTON_LEFT:
+ case MOUSE_BUTTON_LEFT:
_dragging = true;
break;
}
}
- if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) {
+ if (!mb.is_pressed() && _dragging && mb.get_button_index() == MOUSE_BUTTON_LEFT) {
_dragging = false;
if (_has_undo_data) {
UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 63bb785c5e..a319a595c7 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -81,25 +81,22 @@ bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const {
Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
Ref<Image> img;
Ref<AtlasTexture> atex = p_from;
- Ref<LargeTexture> ltex = p_from;
if (atex.is_valid()) {
Ref<Texture2D> tex = atex->get_atlas();
if (!tex.is_valid()) {
return Ref<Texture2D>();
}
- Ref<Image> atlas = tex->get_data();
+ Ref<Image> atlas = tex->get_image();
if (!atlas.is_valid()) {
return Ref<Texture2D>();
}
img = atlas->get_rect(atex->get_region());
- } else if (ltex.is_valid()) {
- img = ltex->to_image();
} else {
Ref<Texture2D> tex = p_from;
if (tex.is_valid()) {
- img = tex->get_data();
+ img = tex->get_image();
if (img.is_valid()) {
img = img->duplicate();
}
@@ -301,7 +298,7 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
//////////////////////////////////////////////////////////////////
void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done = true;
+ preview_done.set();
}
void EditorMaterialPreviewPlugin::_bind_methods() {
@@ -325,10 +322,10 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Si
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
- preview_done = false;
+ preview_done.clear();
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
- while (!preview_done) {
+ while (!preview_done.is_set()) {
OS::get_singleton()->delay_usec(10);
}
@@ -507,6 +504,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
Color keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/keyword_color");
Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color");
Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color");
+ Color comment_color = EditorSettings::get_singleton()->get("text_editor/highlighting/comment_color");
if (bg_color.a == 0) {
bg_color = Color(0, 0, 0, 0);
@@ -526,33 +524,42 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
bool prev_is_text = false;
bool in_keyword = false;
+ bool in_comment = false;
for (int i = 0; i < code.length(); i++) {
char32_t c = code[i];
if (c > 32) {
if (col < thumbnail_size) {
Color color = text_color;
- if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
- //make symbol a little visible
- color = symbol_color;
- in_keyword = false;
- } else if (!prev_is_text && _is_text_char(c)) {
- int pos = i;
+ if (c == '#') {
+ in_comment = true;
+ }
- while (_is_text_char(code[pos])) {
- pos++;
- }
- String word = code.substr(i, pos - i);
- if (keywords.has(word)) {
- in_keyword = true;
+ if (in_comment) {
+ color = comment_color;
+ } else {
+ if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
+ //make symbol a little visible
+ color = symbol_color;
+ in_keyword = false;
+ } else if (!prev_is_text && _is_text_char(c)) {
+ int pos = i;
+
+ while (_is_text_char(code[pos])) {
+ pos++;
+ }
+ String word = code.substr(i, pos - i);
+ if (keywords.has(word)) {
+ in_keyword = true;
+ }
+
+ } else if (!_is_text_char(c)) {
+ in_keyword = false;
}
- } else if (!_is_text_char(c)) {
- in_keyword = false;
- }
-
- if (in_keyword) {
- color = keyword_color;
+ if (in_keyword) {
+ color = keyword_color;
+ }
}
Color ul = color;
@@ -562,11 +569,14 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
prev_is_text = _is_text_char(c);
}
+ col++;
} else {
prev_is_text = false;
in_keyword = false;
if (c == '\n') {
+ in_comment = false;
+
col = x0;
line++;
if (line >= available_height / 2) {
@@ -574,9 +584,10 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
}
} else if (c == '\t') {
col += 3;
+ } else {
+ col++;
}
}
- col++;
}
post_process_preview(img);
@@ -677,7 +688,7 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done = true;
+ preview_done.set();
}
void EditorMeshPreviewPlugin::_bind_methods() {
@@ -714,10 +725,10 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
- preview_done = false;
+ preview_done.clear();
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
- while (!preview_done) {
+ while (!preview_done.is_set()) {
OS::get_singleton()->delay_usec(10);
}
@@ -792,7 +803,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done = true;
+ preview_done.set();
}
void EditorFontPreviewPlugin::_bind_methods() {
@@ -883,11 +894,11 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
font->draw_string(canvas_item, pos, sample, HALIGN_LEFT, -1.f, 50, Color(1, 1, 1));
- preview_done = false;
+ preview_done.clear();
RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
- while (!preview_done) {
+ while (!preview_done.is_set()) {
OS::get_singleton()->delay_usec(10);
}
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 57e2911c89..6e8b9a34cf 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -33,6 +33,8 @@
#include "editor/editor_resource_preview.h"
+#include "core/templates/safe_refcount.h"
+
void post_process_preview(Ref<Image> p_image);
class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
@@ -90,7 +92,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
- mutable volatile bool preview_done = false;
+ mutable SafeFlag preview_done;
void _preview_done(const Variant &p_udata);
@@ -134,7 +136,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
- mutable volatile bool preview_done = false;
+ mutable SafeFlag preview_done;
void _preview_done(const Variant &p_udata);
@@ -156,7 +158,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
RID viewport_texture;
RID canvas;
RID canvas_item;
- mutable volatile bool preview_done = false;
+ mutable SafeFlag preview_done;
void _preview_done(const Variant &p_udata);
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 1aaa98d02e..b447304a3f 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -81,7 +81,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
cpu_particles->set_name(particles->get_name());
cpu_particles->set_transform(particles->get_transform());
cpu_particles->set_visible(particles->is_visible());
- cpu_particles->set_pause_mode(particles->get_pause_mode());
+ cpu_particles->set_process_mode(particles->get_process_mode());
cpu_particles->set_z_index(particles->get_z_index());
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 5b840ddbcf..89d6aaa5f9 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -263,7 +263,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
cpu_particles->set_name(node->get_name());
cpu_particles->set_transform(node->get_transform());
cpu_particles->set_visible(node->is_visible());
- cpu_particles->set_pause_mode(node->get_pause_mode());
+ cpu_particles->set_process_mode(node->get_process_mode());
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles3D"));
@@ -346,7 +346,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
{
uint8_t *iw = point_img.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
+ memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = points.ptr();
float *wf = (float *)iw;
for (int i = 0; i < point_count; i++) {
@@ -374,7 +374,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
{
uint8_t *iw = point_img2.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
+ memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = normals.ptr();
float *wf = (float *)iw;
for (int i = 0; i < point_count; i++) {
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index c0f690bb6a..1ea6630622 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -145,7 +145,7 @@ int ItemListOptionButtonPlugin::get_flags() const {
void ItemListOptionButtonPlugin::add_item() {
ob->add_item(vformat(TTR("Item %d"), ob->get_item_count()));
- _change_notify();
+ notify_property_list_changed();
}
int ItemListOptionButtonPlugin::get_item_count() const {
@@ -154,7 +154,7 @@ int ItemListOptionButtonPlugin::get_item_count() const {
void ItemListOptionButtonPlugin::erase(int p_idx) {
ob->remove_item(p_idx);
- _change_notify();
+ notify_property_list_changed();
}
ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
@@ -181,7 +181,7 @@ int ItemListPopupMenuPlugin::get_flags() const {
void ItemListPopupMenuPlugin::add_item() {
pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
- _change_notify();
+ notify_property_list_changed();
}
int ItemListPopupMenuPlugin::get_item_count() const {
@@ -190,7 +190,7 @@ int ItemListPopupMenuPlugin::get_item_count() const {
void ItemListPopupMenuPlugin::erase(int p_idx) {
pp->remove_item(p_idx);
- _change_notify();
+ notify_property_list_changed();
}
ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
@@ -213,7 +213,7 @@ int ItemListItemListPlugin::get_flags() const {
void ItemListItemListPlugin::add_item() {
pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
- _change_notify();
+ notify_property_list_changed();
}
int ItemListItemListPlugin::get_item_count() const {
@@ -222,7 +222,7 @@ int ItemListItemListPlugin::get_item_count() const {
void ItemListItemListPlugin::erase(int p_idx) {
pp->remove_item(p_idx);
- _change_notify();
+ notify_property_list_changed();
}
ItemListItemListPlugin::ItemListItemListPlugin() {
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 1e4553a967..9d29c31522 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -33,8 +33,10 @@
#include "editor/editor_scale.h"
void MeshEditor::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
rot_x -= mm->get_relative().y * 0.01;
rot_y -= mm->get_relative().x * 0.01;
if (rot_x < -Math_PI / 2) {
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index f8932cd534..6f1f243444 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -93,7 +93,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
mesh = mesh->duplicate();
for (int j = 0; j < mesh->get_surface_count(); ++j) {
- Ref<Material> mat = mi->get_surface_material(j);
+ Ref<Material> mat = mi->get_surface_override_material(j);
if (mat.is_valid()) {
mesh->surface_set_material(j, mat);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index a3009731f9..023d91be30 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -48,6 +48,7 @@
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/visual_instance_3d.h"
+#include "scene/gui/center_container.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/surface_tool.h"
@@ -184,8 +185,10 @@ void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
}
void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 pos = mb->get_position();
if (mb->is_pressed()) {
if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
@@ -535,8 +538,8 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, b
if (dist < closest_dist) {
item = Object::cast_to<Node>(spat);
- while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
- item = item->get_owner();
+ if (item != edited_scene) {
+ item = edited_scene->get_deepest_editable_node(item);
}
closest = item->get_instance_id();
@@ -697,8 +700,8 @@ void Node3DEditorViewport::_select_region() {
}
Node *item = Object::cast_to<Node>(sp);
- while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
- item = item->get_owner();
+ if (item != edited_scene) {
+ item = edited_scene->get_deepest_editable_node(item);
}
// Replace the node by the group if grouped
@@ -1027,7 +1030,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
for (int i = 0; i < selection_results.size(); i++) {
Node3D *item = selection_results[i].item;
- if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
+ if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) {
//invalid result
selection_results.remove(i);
i--;
@@ -1122,23 +1125,21 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
if (is_freelook_active()) {
scale_freelook_speed(zoom_factor);
} else {
scale_cursor_distance(1.0 / zoom_factor);
}
} break;
-
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
if (is_freelook_active()) {
scale_freelook_speed(1.0 / zoom_factor);
} else {
scale_cursor_distance(zoom_factor);
}
} break;
-
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if (b->is_pressed() && _edit.gizmo.is_valid()) {
@@ -1199,7 +1200,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} break;
- case BUTTON_MIDDLE: {
+ case MOUSE_BUTTON_MIDDLE: {
if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
switch (_edit.plane) {
case TRANSFORM_VIEW: {
@@ -1230,7 +1231,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} break;
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_LEFT: {
if (b->is_pressed()) {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->get_alt()) {
@@ -1278,7 +1279,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
clicked_includes_current = false;
- if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
+ if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_command()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
/* HANDLE ROTATION */
if (get_selected_count() == 0) {
break; //bye
@@ -1439,7 +1440,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
set_message(n + ": " + String(v));
- } else if (m->get_button_mask() & BUTTON_MASK_LEFT) {
+ } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_shift()) {
@@ -1473,7 +1474,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 ray_pos = _get_ray_pos(m->get_position());
Vector3 ray = _get_ray(m->get_position());
- float snap = EDITOR_GET("interface/inspector/default_float_step");
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
switch (_edit.mode) {
@@ -1767,7 +1768,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 y_axis = (click - _edit.center).normalized();
Vector3 x_axis = plane.normal.cross(y_axis).normalized();
- float angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
+ double angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_rotate_snap();
@@ -1829,8 +1830,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
}
-
- } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
+ } else if ((m->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
@@ -1839,10 +1839,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_PAN;
}
- } else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
+ const int mod = _get_key_modifier(m);
if (nav_scheme == NAVIGATION_GODOT) {
- const int mod = _get_key_modifier(m);
-
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
@@ -1851,13 +1850,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
// Always allow Alt as a modifier to better support graphic tablets.
nav_mode = NAVIGATION_ORBIT;
}
-
} else if (nav_scheme == NAVIGATION_MAYA) {
- if (m->get_alt()) {
+ if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
}
}
-
} else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) {
// Handle trackpad (no external mouse) use case
const int mod = _get_key_modifier(m);
@@ -2218,6 +2215,12 @@ void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
cursor.distance = CLAMP(cursor.distance * scale, min_distance, max_distance);
}
+ if (cursor.distance == max_distance || cursor.distance == min_distance) {
+ zoom_failed_attempts_count++;
+ } else {
+ zoom_failed_attempts_count = 0;
+ }
+
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
surface->update();
}
@@ -2335,7 +2338,46 @@ void Node3DEditorPlugin::edited_scene_changed() {
}
}
+void Node3DEditorViewport::_project_settings_changed() {
+ //update shadow atlas if changed
+ int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/size");
+ bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/16_bits");
+ int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/quadrant_0_subdiv");
+ int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/quadrant_1_subdiv");
+ int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/quadrant_2_subdiv");
+ int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/shadows/shadow_atlas/quadrant_3_subdiv");
+
+ viewport->set_shadow_atlas_size(shadowmap_size);
+ viewport->set_shadow_atlas_16_bits(shadowmap_16_bits);
+ viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
+ viewport->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
+ viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
+ viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
+
+ bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
+
+ if (shrink != (subviewport_container->get_stretch_shrink() > 1)) {
+ subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
+ }
+
+ // Update MSAA, screen-space AA and debanding if changed
+
+ const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa");
+ viewport->set_msaa(Viewport::MSAA(msaa_mode));
+ const int ssaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/screen_space_aa");
+ viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
+ const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding");
+ viewport->set_use_debanding(use_debanding);
+
+ const bool use_occlusion_culling = GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling");
+ viewport->set_use_occlusion_culling(use_occlusion_culling);
+}
+
void Node3DEditorViewport::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &Node3DEditorViewport::_project_settings_changed));
+ }
+
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
bool visible = is_visible_in_tree();
@@ -2363,6 +2405,7 @@ void Node3DEditorViewport::_notification(int p_what) {
zoom_indicator_delay -= delta;
if (zoom_indicator_delay <= 0) {
surface->update();
+ zoom_limit_label->hide();
}
}
@@ -2442,37 +2485,6 @@ void Node3DEditorViewport::_notification(int p_what) {
}
}
- //update shadow atlas if changed
-
- int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
- bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/16_bits");
- int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv");
- int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv");
- int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv");
- int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv");
-
- viewport->set_shadow_atlas_size(shadowmap_size);
- viewport->set_shadow_atlas_16_bits(shadowmap_16_bits);
- viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
- viewport->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
- viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
- viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
-
- bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
-
- if (shrink != (subviewport_container->get_stretch_shrink() > 1)) {
- subviewport_container->set_stretch_shrink(shrink ? 2 : 1);
- }
-
- // Update MSAA, screen-space AA and debanding if changed
-
- const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa");
- viewport->set_msaa(Viewport::MSAA(msaa_mode));
- const int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa");
- viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
- const bool use_debanding = GLOBAL_GET("rendering/quality/screen_filters/use_debanding");
- viewport->set_use_debanding(use_debanding);
-
bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
if (show_info != info_label->is_visible()) {
info_label->set_visible(show_info);
@@ -2533,6 +2545,8 @@ void Node3DEditorViewport::_notification(int p_what) {
cpu_time += cpu_time_history[i];
}
cpu_time /= FRAME_TIME_HISTORY;
+ // Prevent unrealistically low values.
+ cpu_time = MAX(0.01, cpu_time);
gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid());
gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY;
@@ -2541,16 +2555,19 @@ void Node3DEditorViewport::_notification(int p_what) {
gpu_time += gpu_time_history[i];
}
gpu_time /= FRAME_TIME_HISTORY;
+ // Prevent division by zero for the FPS counter (and unrealistically low values).
+ // This limits the reported FPS to 100000.
+ gpu_time = MAX(0.01, gpu_time);
// Color labels depending on performance level ("good" = green, "OK" = yellow, "bad" = red).
// Middle point is at 15 ms.
- cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), String::num(cpu_time, 1)));
+ cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(1)));
cpu_time_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
Math::range_lerp(cpu_time, 0, 30, 0, 1)));
- gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), String::num(gpu_time, 1)));
+ gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(1)));
// Middle point is at 15 ms.
gpu_time_label->add_theme_color_override(
"font_color",
@@ -2768,6 +2785,7 @@ void Node3DEditorViewport::_draw() {
} else {
// Show zoom
+ zoom_limit_label->set_visible(zoom_failed_attempts_count > 15);
real_t min_distance = MAX(camera->get_near() * 4, ZOOM_FREELOOK_MIN);
real_t max_distance = MIN(camera->get_far() / 4, ZOOM_FREELOOK_MAX);
@@ -3056,7 +3074,8 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS:
case VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS:
case VIEW_DISPLAY_DEBUG_CLUSTER_DECALS:
- case VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES: {
+ case VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES:
+ case VIEW_DISPLAY_DEBUG_OCCLUDERS: {
static const int display_options[] = {
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
@@ -3082,6 +3101,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS,
VIEW_DISPLAY_DEBUG_CLUSTER_DECALS,
VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES,
+ VIEW_DISPLAY_DEBUG_OCCLUDERS,
VIEW_MAX
};
static const Viewport::DebugDraw debug_draw_modes[] = {
@@ -3109,6 +3129,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
Viewport::DEBUG_DRAW_CLUSTER_DECALS,
Viewport::DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ Viewport::DEBUG_DRAW_OCCLUDERS,
};
int idx = 0;
@@ -3158,6 +3179,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
move_plane_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid());
@@ -3165,6 +3187,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
rotate_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
@@ -3172,6 +3195,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
scale_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
@@ -3179,6 +3203,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
scale_plane_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid());
@@ -3186,6 +3211,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
// Rotation white outline
@@ -3195,6 +3221,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[3], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[3], layer);
+ RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[3], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
void Node3DEditorViewport::_finish_gizmo_instances() {
@@ -3545,10 +3572,6 @@ void Node3DEditorViewport::reset() {
}
void Node3DEditorViewport::focus_selection() {
- if (!get_selected_count()) {
- return;
- }
-
Vector3 center;
int count = 0;
@@ -3645,9 +3668,9 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform) {
AABB bounds;
- const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_parent);
- if (mesh_instance) {
- bounds = mesh_instance->get_aabb();
+ const VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(p_parent);
+ if (visual_instance) {
+ bounds = visual_instance->get_aabb();
}
for (int i = 0; i < p_parent->get_child_count(); i++) {
@@ -4032,6 +4055,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("Spot Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
display_submenu->add_radio_check_item(TTR("Decal Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_DECALS);
display_submenu->add_radio_check_item(TTR("Reflection Probe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
+ display_submenu->add_radio_check_item(TTR("Occlusion Culling Buffer"), VIEW_DISPLAY_DEBUG_OCCLUDERS);
display_submenu->set_name("display_advanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
@@ -4130,6 +4154,15 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
locked_label->set_text(TTR("View Rotation Locked"));
locked_label->hide();
+ zoom_limit_label = memnew(Label);
+ zoom_limit_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT);
+ zoom_limit_label->set_offset(Side::SIDE_TOP, -28 * EDSCALE);
+ zoom_limit_label->set_text(TTR("To zoom further, change the camera's clipping planes (View -> Settings...)"));
+ zoom_limit_label->set_name("ZoomLimitMessageLabel");
+ zoom_limit_label->add_theme_color_override("font_color", Color(1, 1, 1, 1));
+ zoom_limit_label->hide();
+ surface->add_child(zoom_limit_label);
+
frame_time_gradient = memnew(Gradient);
// The color is set when the theme changes.
frame_time_gradient->add_point(0.5, Color());
@@ -4192,9 +4225,11 @@ Node3DEditorViewport::~Node3DEditorViewport() {
//////////////////////////////////////////////////////////////
void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
Vector2 size = get_size();
@@ -4577,7 +4612,12 @@ void _update_all_gizmos(Node *p_node) {
void Node3DEditor::update_all_gizmos(Node *p_node) {
if (!p_node) {
- p_node = SceneTree::get_singleton()->get_root();
+ if (SceneTree::get_singleton()) {
+ p_node = SceneTree::get_singleton()->get_root();
+ } else {
+ // No scene tree, so nothing to update.
+ return;
+ }
}
_update_all_gizmos(p_node);
}
@@ -4598,6 +4638,7 @@ Object *Node3DEditor::_get_editor_data(Object *p_what) {
si->sbox_instance,
RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(si->sbox_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(si->sbox_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
si->sbox_instance_xray = RenderingServer::get_singleton()->instance_create2(
selection_box_xray->get_rid(),
sp->get_world_3d()->get_scenario());
@@ -4605,6 +4646,7 @@ Object *Node3DEditor::_get_editor_data(Object *p_what) {
si->sbox_instance_xray,
RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(si->sbox_instance_xray, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(si->sbox_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
return si;
}
@@ -4707,11 +4749,33 @@ Dictionary Node3DEditor::get_state() const {
continue;
}
int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
- String name = gizmo_plugins_by_name[i]->get_name();
+ String name = gizmo_plugins_by_name[i]->get_gizmo_name();
gizmos_status[name] = state;
}
d["gizmos_status"] = gizmos_status;
+ {
+ Dictionary pd;
+
+ pd["sun_rotation"] = sun_rotation;
+
+ pd["environ_sky_color"] = environ_sky_color->get_pick_color();
+ pd["environ_ground_color"] = environ_ground_color->get_pick_color();
+ pd["environ_energy"] = environ_energy->get_value();
+ pd["environ_glow_enabled"] = environ_glow_button->is_pressed();
+ pd["environ_tonemap_enabled"] = environ_tonemap_button->is_pressed();
+ pd["environ_ao_enabled"] = environ_ao_button->is_pressed();
+ pd["environ_gi_enabled"] = environ_gi_button->is_pressed();
+ pd["sun_max_distance"] = sun_max_distance->get_value();
+
+ pd["sun_color"] = sun_color->get_pick_color();
+ pd["sun_energy"] = sun_energy->get_value();
+
+ pd["sun_disabled"] = sun_button->is_pressed();
+ pd["environ_disabled"] = environ_button->is_pressed();
+
+ d["preview_sun_env"] = pd;
+ }
return d;
}
@@ -4811,7 +4875,7 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
}
int state = EditorNode3DGizmoPlugin::VISIBLE;
for (int i = 0; i < keys.size(); i++) {
- if (gizmo_plugins_by_name.write[j]->get_name() == String(keys[i])) {
+ if (gizmo_plugins_by_name.write[j]->get_gizmo_name() == String(keys[i])) {
state = gizmos_status[keys[i]];
break;
}
@@ -4821,6 +4885,38 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
}
_update_gizmos_menu();
}
+
+ if (d.has("preview_sun_env")) {
+ sun_environ_updating = true;
+ Dictionary pd = d["preview_sun_env"];
+ sun_rotation = pd["sun_rotation"];
+
+ environ_sky_color->set_pick_color(pd["environ_sky_color"]);
+ environ_ground_color->set_pick_color(pd["environ_ground_color"]);
+ environ_energy->set_value(pd["environ_energy"]);
+ environ_glow_button->set_pressed(pd["environ_glow_enabled"]);
+ environ_tonemap_button->set_pressed(pd["environ_tonemap_enabled"]);
+ environ_ao_button->set_pressed(pd["environ_ao_enabled"]);
+ environ_gi_button->set_pressed(pd["environ_gi_enabled"]);
+ sun_max_distance->set_value(pd["sun_max_distance"]);
+
+ sun_color->set_pick_color(pd["sun_color"]);
+ sun_energy->set_value(pd["sun_energy"]);
+
+ sun_button->set_pressed(pd["sun_disabled"]);
+ environ_button->set_pressed(pd["environ_disabled"]);
+
+ sun_environ_updating = false;
+
+ _preview_settings_changed();
+ _update_preview_environment();
+ } else {
+ _load_default_preview_settings();
+ sun_button->set_pressed(false);
+ environ_button->set_pressed(false);
+ _preview_settings_changed();
+ _update_preview_environment();
+ }
}
void Node3DEditor::edit(Node3D *p_spatial) {
@@ -5322,6 +5418,7 @@ void Node3DEditor::_init_indicators() {
origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF);
}
@@ -5690,7 +5787,7 @@ void Node3DEditor::_update_gizmos_menu() {
if (!gizmo_plugins_by_name[i]->can_be_hidden()) {
continue;
}
- String plugin_name = gizmo_plugins_by_name[i]->get_name();
+ String plugin_name = gizmo_plugins_by_name[i]->get_gizmo_name();
const int plugin_state = gizmo_plugins_by_name[i]->get_state();
gizmos_menu->add_multistate_item(plugin_name, 3, plugin_state, i);
const int idx = gizmos_menu->get_item_index(i);
@@ -5761,7 +5858,7 @@ void Node3DEditor::_init_grid() {
// Offsets division_level for bigger or smaller grids.
// Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias");
- // Default largest grid size is 100m, 10^2 (default value is 2).
+ // Default largest grid size is 8^2 when primary_grid_steps is 8 (64m apart, so primary grid lines are 512m apart).
int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max");
// Default smallest grid size is 1cm, 10^-2 (default value is -2).
int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min");
@@ -5883,6 +5980,7 @@ void Node3DEditor::_init_grid() {
RenderingServer::get_singleton()->instance_set_visible(grid_instance[c], grid_visible[a]);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[c], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(grid_instance[c], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(grid_instance[c], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
}
@@ -6100,6 +6198,8 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_visible_in_tree()) {
return;
}
@@ -6107,6 +6207,51 @@ void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
}
+void Node3DEditor::_sun_environ_settings_pressed() {
+ Vector2 pos = sun_environ_settings->get_screen_position() + sun_environ_settings->get_size();
+ sun_environ_popup->set_position(pos - Vector2(sun_environ_popup->get_contents_minimum_size().width / 2, 0));
+ sun_environ_popup->popup();
+}
+
+void Node3DEditor::_add_sun_to_scene() {
+ sun_environ_popup->hide();
+
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ EditorNode::get_singleton()->show_warning(TTR("A root node is needed for this operation"));
+ return;
+ }
+ ERR_FAIL_COND(!base);
+ Node *new_sun = preview_sun->duplicate();
+
+ undo_redo->create_action("Add Preview Sun to Scene");
+ undo_redo->add_do_method(base, "add_child", new_sun);
+ undo_redo->add_do_method(new_sun, "set_owner", base);
+ undo_redo->add_undo_method(base, "remove_child", new_sun);
+ undo_redo->add_do_reference(new_sun);
+ undo_redo->commit_action();
+}
+void Node3DEditor::_add_environment_to_scene() {
+ sun_environ_popup->hide();
+
+ Node *base = get_tree()->get_edited_scene_root();
+ if (!base) {
+ EditorNode::get_singleton()->show_warning(TTR("A root node is needed for this operation"));
+ return;
+ }
+ ERR_FAIL_COND(!base);
+
+ WorldEnvironment *new_env = memnew(WorldEnvironment);
+ new_env->set_environment(preview_environment->get_environment()->duplicate(true));
+
+ undo_redo->create_action("Add Preview Environment to Scene");
+ undo_redo->add_do_method(base, "add_child", new_env);
+ undo_redo->add_do_method(new_env, "set_owner", base);
+ undo_redo->add_undo_method(base, "remove_child", new_env);
+ undo_redo->add_do_reference(new_env);
+ undo_redo->commit_action();
+}
+
void Node3DEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
@@ -6135,17 +6280,31 @@ void Node3DEditor::_notification(int p_what) {
_refresh_menu_icons();
get_tree()->connect("node_removed", callable_mp(this, &Node3DEditor::_node_removed));
+ get_tree()->connect("node_added", callable_mp(this, &Node3DEditor::_node_added));
EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
editor_selection->connect("selection_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
editor->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(false));
editor->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(true));
+
+ sun_button->set_icon(get_theme_icon("DirectionalLight3D", "EditorIcons"));
+ environ_button->set_icon(get_theme_icon("WorldEnvironment", "EditorIcons"));
+ sun_environ_settings->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons"));
+
+ _update_preview_environment();
+ sun_title->add_theme_font_override("font", get_theme_font("title_font", "Window"));
+ environ_title->add_theme_font_override("font", get_theme_font("title_font", "Window"));
+
+ sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size());
+ environ_state->set_custom_minimum_size(environ_vb->get_combined_minimum_size());
} else if (p_what == NOTIFICATION_ENTER_TREE) {
_register_all_gizmos();
_update_gizmos_menu();
_init_indicators();
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
_update_gizmos_menu_theme();
+ sun_title->add_theme_font_override("font", get_theme_font("title_font", "Window"));
+ environ_title->add_theme_font_override("font", get_theme_font("title_font", "Window"));
} else if (p_what == NOTIFICATION_EXIT_TREE) {
_finish_indicators();
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
@@ -6282,7 +6441,37 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) {
}
}
+void Node3DEditor::_node_added(Node *p_node) {
+ if (EditorNode::get_singleton()->get_scene_root()->is_a_parent_of(p_node)) {
+ if (Object::cast_to<WorldEnvironment>(p_node)) {
+ world_env_count++;
+ if (world_env_count == 1) {
+ _update_preview_environment();
+ }
+ } else if (Object::cast_to<DirectionalLight3D>(p_node)) {
+ directional_light_count++;
+ if (directional_light_count == 1) {
+ _update_preview_environment();
+ }
+ }
+ }
+}
+
void Node3DEditor::_node_removed(Node *p_node) {
+ if (EditorNode::get_singleton()->get_scene_root()->is_a_parent_of(p_node)) {
+ if (Object::cast_to<WorldEnvironment>(p_node)) {
+ world_env_count--;
+ if (world_env_count == 0) {
+ _update_preview_environment();
+ }
+ } else if (Object::cast_to<DirectionalLight3D>(p_node)) {
+ directional_light_count--;
+ if (directional_light_count == 0) {
+ _update_preview_environment();
+ }
+ }
+ }
+
if (p_node == selected) {
selected = nullptr;
}
@@ -6293,6 +6482,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<Light3DGizmoPlugin>(memnew(Light3DGizmoPlugin)));
add_gizmo_plugin(Ref<AudioStreamPlayer3DGizmoPlugin>(memnew(AudioStreamPlayer3DGizmoPlugin)));
add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin)));
@@ -6309,6 +6499,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
add_gizmo_plugin(Ref<BakedLightmapGizmoPlugin>(memnew(BakedLightmapGizmoPlugin)));
add_gizmo_plugin(Ref<LightmapProbeGizmoPlugin>(memnew(LightmapProbeGizmoPlugin)));
+ add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
@@ -6352,6 +6543,128 @@ void Node3DEditor::clear() {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
}
+void Node3DEditor::_sun_direction_draw() {
+ sun_direction->draw_rect(Rect2(Vector2(), sun_direction->get_size()), Color(1, 1, 1, 1));
+ sun_direction_material->set_shader_param("sun_direction", -preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z));
+ float nrg = sun_energy->get_value();
+ sun_direction_material->set_shader_param("sun_color", Vector3(sun_color->get_pick_color().r * nrg, sun_color->get_pick_color().g * nrg, sun_color->get_pick_color().b * nrg));
+}
+
+void Node3DEditor::_preview_settings_changed() {
+ if (sun_environ_updating) {
+ return;
+ }
+
+ { // preview sun
+ Transform t;
+ t.basis = sun_rotation;
+ preview_sun->set_transform(t);
+ sun_direction->update();
+ preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value());
+ preview_sun->set_param(Light3D::PARAM_SHADOW_MAX_DISTANCE, sun_max_distance->get_value());
+ preview_sun->set_color(sun_color->get_pick_color());
+ }
+
+ { //preview env
+ sky_material->set_sky_energy(environ_energy->get_value());
+ Color hz_color = environ_sky_color->get_pick_color().lerp(environ_ground_color->get_pick_color(), 0.5).lerp(Color(1, 1, 1), 0.5);
+ sky_material->set_sky_top_color(environ_sky_color->get_pick_color());
+ sky_material->set_sky_horizon_color(hz_color);
+ sky_material->set_ground_bottom_color(environ_ground_color->get_pick_color());
+ sky_material->set_ground_horizon_color(hz_color);
+
+ environment->set_ssao_enabled(environ_ao_button->is_pressed());
+ environment->set_glow_enabled(environ_glow_button->is_pressed());
+ environment->set_sdfgi_enabled(environ_gi_button->is_pressed());
+ environment->set_tonemapper(environ_tonemap_button->is_pressed() ? Environment::TONE_MAPPER_FILMIC : Environment::TONE_MAPPER_LINEAR);
+ }
+}
+void Node3DEditor::_load_default_preview_settings() {
+ sun_environ_updating = true;
+
+ sun_rotation = Basis(Vector3(0, 1, 0), Math_PI * 3.0 / 4) * Basis(Vector3(1, 0, 0), -Math_PI / 4);
+
+ sun_direction->update();
+ environ_sky_color->set_pick_color(Color::hex(0x91b2ceff));
+ environ_ground_color->set_pick_color(Color::hex(0x1f1f21ff));
+ environ_energy->set_value(1.0);
+ environ_glow_button->set_pressed(true);
+ environ_tonemap_button->set_pressed(true);
+ environ_ao_button->set_pressed(false);
+ environ_gi_button->set_pressed(false);
+ sun_max_distance->set_value(250);
+
+ sun_color->set_pick_color(Color(1, 1, 1));
+ sun_energy->set_value(1.0);
+
+ sun_environ_updating = false;
+}
+
+void Node3DEditor::_update_preview_environment() {
+ bool disable_light = directional_light_count > 0 || sun_button->is_pressed();
+
+ sun_button->set_disabled(directional_light_count > 0);
+
+ if (disable_light) {
+ if (preview_sun->get_parent()) {
+ preview_sun->get_parent()->remove_child(preview_sun);
+ sun_state->show();
+ sun_vb->hide();
+ }
+
+ if (directional_light_count > 0) {
+ sun_state->set_text(TTR("Scene contains\nDirectionalLight3D.\nPreview disabled."));
+ } else {
+ sun_state->set_text(TTR("Preview disabled."));
+ }
+
+ } else {
+ if (!preview_sun->get_parent()) {
+ add_child(preview_sun);
+ sun_state->hide();
+ sun_vb->show();
+ }
+ }
+
+ bool disable_env = world_env_count > 0 || environ_button->is_pressed();
+
+ environ_button->set_disabled(world_env_count > 0);
+
+ if (disable_env) {
+ if (preview_environment->get_parent()) {
+ preview_environment->get_parent()->remove_child(preview_environment);
+ environ_state->show();
+ environ_vb->hide();
+ }
+ if (world_env_count > 0) {
+ environ_state->set_text(TTR("Scene contains\nWorldEnvironment.\nPreview disabled."));
+ } else {
+ environ_state->set_text(TTR("Preview disabled."));
+ }
+
+ } else {
+ if (!preview_environment->get_parent()) {
+ add_child(preview_environment);
+ environ_state->hide();
+ environ_vb->show();
+ }
+ }
+}
+
+void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ float x = -mm->get_relative().y * 0.02 * EDSCALE;
+ float y = mm->get_relative().x * 0.02 * EDSCALE;
+
+ Basis rot = Basis(Vector3(0, 1, 0), y) * Basis(Vector3(1, 0, 0), x);
+
+ sun_rotation = rot * sun_rotation;
+ sun_rotation.orthonormalize();
+ _preview_settings_changed();
+ }
+}
+
Node3DEditor::Node3DEditor(EditorNode *p_editor) {
gizmo.visible = true;
gizmo.scale = 1.0;
@@ -6489,6 +6802,32 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
_update_camera_override_button(false);
hbc_menu->add_child(memnew(VSeparator));
+ sun_button = memnew(Button);
+ sun_button->set_tooltip(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
+ sun_button->set_toggle_mode(true);
+ sun_button->set_flat(true);
+ sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), varray(), CONNECT_DEFERRED);
+ sun_button->set_disabled(true);
+
+ hbc_menu->add_child(sun_button);
+
+ environ_button = memnew(Button);
+ environ_button->set_tooltip(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled."));
+ environ_button->set_toggle_mode(true);
+ environ_button->set_flat(true);
+ environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), varray(), CONNECT_DEFERRED);
+ environ_button->set_disabled(true);
+
+ hbc_menu->add_child(environ_button);
+
+ sun_environ_settings = memnew(Button);
+ sun_environ_settings->set_tooltip(TTR("Edit Sun and Environment settings."));
+ sun_environ_settings->set_flat(true);
+ sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed));
+
+ hbc_menu->add_child(sun_environ_settings);
+
+ hbc_menu->add_child(memnew(VSeparator));
// Drag and drop support;
preview_node = memnew(Node3D);
@@ -6718,6 +7057,152 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
over_gizmo_handle = -1;
+ {
+ //sun popup
+
+ sun_environ_popup = memnew(PopupPanel);
+ add_child(sun_environ_popup);
+
+ HBoxContainer *sun_environ_hb = memnew(HBoxContainer);
+
+ sun_environ_popup->add_child(sun_environ_hb);
+
+ sun_vb = memnew(VBoxContainer);
+ sun_environ_hb->add_child(sun_vb);
+ sun_vb->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
+ sun_vb->hide();
+
+ sun_title = memnew(Label);
+ sun_vb->add_child(sun_title);
+ sun_title->set_text(TTR("Preview Sun"));
+ sun_title->set_align(Label::ALIGN_CENTER);
+
+ CenterContainer *sun_direction_center = memnew(CenterContainer);
+ sun_direction = memnew(Control);
+ sun_direction->set_custom_minimum_size(Size2i(128, 128) * EDSCALE);
+ sun_direction_center->add_child(sun_direction);
+ sun_vb->add_margin_child(TTR("Sun Direction"), sun_direction_center);
+ sun_direction->connect("gui_input", callable_mp(this, &Node3DEditor::_sun_direction_input));
+ sun_direction->connect("draw", callable_mp(this, &Node3DEditor::_sun_direction_draw));
+ sun_direction->set_default_cursor_shape(CURSOR_MOVE);
+
+ String sun_dir_shader_code = "shader_type canvas_item; uniform vec3 sun_direction; uniform vec3 sun_color; void fragment() { vec3 n; n.xy = UV * 2.0 - 1.0; n.z = sqrt(max(0.0, 1.0 - dot(n.xy, n.xy))); COLOR.rgb = dot(n,sun_direction) * sun_color; COLOR.a = 1.0 - smoothstep(0.99,1.0,length(n.xy)); }";
+ sun_direction_shader.instance();
+ sun_direction_shader->set_code(sun_dir_shader_code);
+ sun_direction_material.instance();
+ sun_direction_material->set_shader(sun_direction_shader);
+ sun_direction_material->set_shader_param("sun_direction", Vector3(0, 0, 1));
+ sun_direction_material->set_shader_param("sun_color", Vector3(1, 1, 1));
+ sun_direction->set_material(sun_direction_material);
+
+ sun_color = memnew(ColorPickerButton);
+ sun_color->set_edit_alpha(false);
+ sun_vb->add_margin_child(TTR("Sun Color"), sun_color);
+ sun_color->connect("color_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+
+ sun_energy = memnew(EditorSpinSlider);
+ sun_vb->add_margin_child(TTR("Sun Energy"), sun_energy);
+ sun_energy->connect("value_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+ sun_energy->set_max(64.0);
+
+ sun_max_distance = memnew(EditorSpinSlider);
+ sun_vb->add_margin_child(TTR("Shadow Max Distance"), sun_max_distance);
+ sun_max_distance->connect("value_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+ sun_max_distance->set_min(1);
+ sun_max_distance->set_max(4096);
+
+ sun_add_to_scene = memnew(Button);
+ sun_add_to_scene->set_text(TTR("Add Sun to Scene"));
+ sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene));
+ sun_vb->add_spacer();
+ sun_vb->add_child(sun_add_to_scene);
+
+ sun_state = memnew(Label);
+ sun_environ_hb->add_child(sun_state);
+ sun_state->set_align(Label::ALIGN_CENTER);
+ sun_state->set_valign(Label::VALIGN_CENTER);
+ sun_state->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ VSeparator *sc = memnew(VSeparator);
+ sc->set_custom_minimum_size(Size2(50 * EDSCALE, 0));
+ sc->set_v_size_flags(SIZE_EXPAND_FILL);
+ sun_environ_hb->add_child(sc);
+
+ environ_vb = memnew(VBoxContainer);
+ sun_environ_hb->add_child(environ_vb);
+ environ_vb->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
+ environ_vb->hide();
+
+ environ_title = memnew(Label);
+ environ_vb->add_child(environ_title);
+ environ_title->set_text(TTR("Preview Environment"));
+ environ_title->set_align(Label::ALIGN_CENTER);
+
+ environ_sky_color = memnew(ColorPickerButton);
+ environ_sky_color->set_edit_alpha(false);
+ environ_sky_color->connect("color_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+ environ_vb->add_margin_child(TTR("Sky Color"), environ_sky_color);
+ environ_ground_color = memnew(ColorPickerButton);
+ environ_ground_color->connect("color_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+ environ_ground_color->set_edit_alpha(false);
+ environ_vb->add_margin_child(TTR("Ground Color"), environ_ground_color);
+ environ_energy = memnew(EditorSpinSlider);
+ environ_energy->connect("value_changed", callable_mp(this, &Node3DEditor::_preview_settings_changed).unbind(1));
+ environ_energy->set_max(8.0);
+ environ_vb->add_margin_child(TTR("Sky Energy"), environ_energy);
+ HBoxContainer *fx_vb = memnew(HBoxContainer);
+ fx_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ environ_ao_button = memnew(Button);
+ environ_ao_button->set_text(TTR("AO"));
+ environ_ao_button->set_toggle_mode(true);
+ environ_ao_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), varray(), CONNECT_DEFERRED);
+ fx_vb->add_child(environ_ao_button);
+ environ_glow_button = memnew(Button);
+ environ_glow_button->set_text(TTR("Glow"));
+ environ_glow_button->set_toggle_mode(true);
+ environ_glow_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), varray(), CONNECT_DEFERRED);
+ fx_vb->add_child(environ_glow_button);
+ environ_tonemap_button = memnew(Button);
+ environ_tonemap_button->set_text(TTR("Tonemap"));
+ environ_tonemap_button->set_toggle_mode(true);
+ environ_tonemap_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), varray(), CONNECT_DEFERRED);
+ fx_vb->add_child(environ_tonemap_button);
+ environ_gi_button = memnew(Button);
+ environ_gi_button->set_text(TTR("GI"));
+ environ_gi_button->set_toggle_mode(true);
+ environ_gi_button->connect("pressed", callable_mp(this, &Node3DEditor::_preview_settings_changed), varray(), CONNECT_DEFERRED);
+ fx_vb->add_child(environ_gi_button);
+ environ_vb->add_margin_child(TTR("Post Process"), fx_vb);
+
+ environ_add_to_scene = memnew(Button);
+ environ_add_to_scene->set_text(TTR("Add Environment to Scene"));
+ environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene));
+ environ_vb->add_spacer();
+ environ_vb->add_child(environ_add_to_scene);
+
+ environ_state = memnew(Label);
+ sun_environ_hb->add_child(environ_state);
+ environ_state->set_align(Label::ALIGN_CENTER);
+ environ_state->set_valign(Label::VALIGN_CENTER);
+ environ_state->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ preview_sun = memnew(DirectionalLight3D);
+ preview_sun->set_shadow(true);
+ preview_sun->set_shadow_mode(DirectionalLight3D::SHADOW_PARALLEL_4_SPLITS);
+ preview_environment = memnew(WorldEnvironment);
+ environment.instance();
+ preview_environment->set_environment(environment);
+ Ref<Sky> sky;
+ sky.instance();
+ sky_material.instance();
+ sky->set_material(sky_material);
+ environment->set_sky(sky);
+ environment->set_background(Environment::BG_SKY);
+
+ _load_default_preview_settings();
+ _preview_settings_changed();
+ }
}
Node3DEditor::~Node3DEditor() {
@@ -6808,7 +7293,7 @@ void Node3DEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
struct _GizmoPluginPriorityComparator {
bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const {
if (p_a->get_priority() == p_b->get_priority()) {
- return p_a->get_name() < p_b->get_name();
+ return p_a->get_gizmo_name() < p_b->get_gizmo_name();
}
return p_a->get_priority() > p_b->get_priority();
}
@@ -6816,7 +7301,7 @@ struct _GizmoPluginPriorityComparator {
struct _GizmoPluginNameComparator {
bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const {
- return p_a->get_name() < p_b->get_name();
+ return p_a->get_gizmo_name() < p_b->get_gizmo_name();
}
};
@@ -6873,6 +7358,7 @@ void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+ material->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
if (p_use_vertex_color) {
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
@@ -7027,7 +7513,7 @@ void EditorNode3DGizmoPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material, DEFVAL(Ref<EditorNode3DGizmo>()));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "get_gizmo_name"));
BIND_VMETHOD(MethodInfo(Variant::INT, "get_priority"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 9fb7488a0f..33f4c32471 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -37,7 +37,10 @@
#include "scene/3d/immediate_geometry_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/visual_instance_3d.h"
+#include "scene/3d/world_environment.h"
#include "scene/gui/panel_container.h"
+#include "scene/resources/environment.h"
+#include "scene/resources/sky_material.h"
class Camera3D;
class Node3DEditor;
@@ -96,6 +99,7 @@ protected:
public:
void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false, const Color &p_modulate = Color(1, 1, 1));
+ void add_vertices(const Vector<Vector3> &p_vertices, const Ref<Material> &p_material, Mesh::PrimitiveType p_primitive_type, bool p_billboard = false, const Color &p_modulate = Color(1, 1, 1));
void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>(), const Ref<Material> &p_material = Ref<Material>());
void add_collision_segments(const Vector<Vector3> &p_lines);
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
@@ -217,6 +221,7 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS,
VIEW_DISPLAY_DEBUG_CLUSTER_DECALS,
VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES,
+ VIEW_DISPLAY_DEBUG_OCCLUDERS,
VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW,
@@ -291,6 +296,7 @@ private:
Label *info_label;
Label *cinema_label;
Label *locked_label;
+ Label *zoom_limit_label;
VBoxContainer *top_right_vbox;
ViewportRotationControl *rotation_control;
@@ -414,6 +420,7 @@ private:
void scale_freelook_speed(real_t scale);
real_t zoom_indicator_delay;
+ int zoom_failed_attempts_count = 0;
RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
@@ -463,6 +470,8 @@ private:
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ void _project_settings_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -730,6 +739,7 @@ private:
static Node3DEditor *singleton;
+ void _node_added(Node *p_node);
void _node_removed(Node *p_node);
Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_priority;
Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_name;
@@ -742,6 +752,61 @@ private:
void _refresh_menu_icons();
+ // Preview Sun and Environment
+
+ uint32_t world_env_count = 0;
+ uint32_t directional_light_count = 0;
+
+ Button *sun_button;
+ Label *sun_state;
+ Label *sun_title;
+ VBoxContainer *sun_vb;
+ Popup *sun_environ_popup;
+ Control *sun_direction;
+ ColorPickerButton *sun_color;
+ EditorSpinSlider *sun_energy;
+ EditorSpinSlider *sun_max_distance;
+ Button *sun_add_to_scene;
+
+ void _sun_direction_draw();
+ void _sun_direction_input(const Ref<InputEvent> &p_event);
+
+ Basis sun_rotation;
+
+ Ref<Shader> sun_direction_shader;
+ Ref<ShaderMaterial> sun_direction_material;
+
+ Button *environ_button;
+ Label *environ_state;
+ Label *environ_title;
+ VBoxContainer *environ_vb;
+ ColorPickerButton *environ_sky_color;
+ ColorPickerButton *environ_ground_color;
+ EditorSpinSlider *environ_energy;
+ Button *environ_ao_button;
+ Button *environ_glow_button;
+ Button *environ_tonemap_button;
+ Button *environ_gi_button;
+ Button *environ_add_to_scene;
+
+ Button *sun_environ_settings;
+
+ DirectionalLight3D *preview_sun;
+ WorldEnvironment *preview_environment;
+ Ref<Environment> environment;
+ Ref<ProceduralSkyMaterial> sky_material;
+
+ bool sun_environ_updating = false;
+
+ void _load_default_preview_settings();
+ void _update_preview_environment();
+
+ void _preview_settings_changed();
+ void _sun_environ_settings_pressed();
+
+ void _add_sun_to_scene();
+ void _add_environment_to_scene();
+
protected:
void _notification(int p_what);
//void _gui_input(InputEvent p_event);
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..0821f140b3
--- /dev/null
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* occluder_instance_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "occluder_instance_3d_editor_plugin.h"
+
+void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
+ if (occluder_instance) {
+ OccluderInstance3D::BakeError err;
+ if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == occluder_instance) {
+ err = occluder_instance->bake(occluder_instance, p_file);
+ } else {
+ err = occluder_instance->bake(occluder_instance->get_parent(), p_file);
+ }
+
+ switch (err) {
+ case OccluderInstance3D::BAKE_ERROR_NO_SAVE_PATH: {
+ String scene_path = occluder_instance->get_filename();
+ if (scene_path == String()) {
+ scene_path = occluder_instance->get_owner()->get_filename();
+ }
+ if (scene_path == String()) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for the occluder.\nSave your scene and try again."));
+ break;
+ }
+ scene_path = scene_path.get_basename() + ".occ";
+
+ file_dialog->set_current_path(scene_path);
+ file_dialog->popup_file_dialog();
+
+ } break;
+ case OccluderInstance3D::BAKE_ERROR_NO_MESHES: {
+ EditorNode::get_singleton()->show_warning(TTR("No meshes to bake."));
+ break;
+ }
+ default: {
+ }
+ }
+ }
+}
+
+void OccluderInstance3DEditorPlugin::_bake() {
+ _bake_select_file("");
+}
+
+void OccluderInstance3DEditorPlugin::edit(Object *p_object) {
+ OccluderInstance3D *s = Object::cast_to<OccluderInstance3D>(p_object);
+ if (!s) {
+ return;
+ }
+
+ occluder_instance = s;
+}
+
+bool OccluderInstance3DEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("OccluderInstance3D");
+}
+
+void OccluderInstance3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ bake->show();
+ } else {
+ bake->hide();
+ }
+}
+
+void OccluderInstance3DEditorPlugin::_bind_methods() {
+ ClassDB::bind_method("_bake", &OccluderInstance3DEditorPlugin::_bake);
+}
+
+OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin(EditorNode *p_node) {
+ editor = p_node;
+ bake = memnew(Button);
+ bake->set_flat(true);
+ bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
+ bake->set_text(TTR("Bake Occluders"));
+ bake->hide();
+ bake->connect("pressed", Callable(this, "_bake"));
+ add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
+ occluder_instance = nullptr;
+
+ file_dialog = memnew(EditorFileDialog);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ file_dialog->add_filter("*.occ ; Occluder3D");
+ file_dialog->set_title(TTR("Select occluder bake file:"));
+ file_dialog->connect("file_selected", callable_mp(this, &OccluderInstance3DEditorPlugin::_bake_select_file));
+ bake->add_child(file_dialog);
+}
+
+OccluderInstance3DEditorPlugin::~OccluderInstance3DEditorPlugin() {
+}
diff --git a/editor/editor_sub_scene.h b/editor/plugins/occluder_instance_3d_editor_plugin.h
index 428bd5a40e..161b17811c 100644
--- a/editor/editor_sub_scene.h
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* editor_sub_scene.h */
+/* occluder_instance_3d_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,44 +28,39 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EDITOR_SUB_SCENE_H
-#define EDITOR_SUB_SCENE_H
+#ifndef OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
+#define OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
-#include "editor/editor_file_dialog.h"
-#include "scene/gui/dialogs.h"
-#include "scene/gui/tree.h"
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/occluder_instance_3d.h"
+#include "scene/resources/material.h"
-class EditorSubScene : public ConfirmationDialog {
- GDCLASS(EditorSubScene, ConfirmationDialog);
+class OccluderInstance3DEditorPlugin : public EditorPlugin {
+ GDCLASS(OccluderInstance3DEditorPlugin, EditorPlugin);
- List<Node *> selection;
- LineEdit *path;
- Tree *tree;
- Node *scene;
- bool is_root;
+ OccluderInstance3D *occluder_instance;
- EditorFileDialog *file_dialog;
+ Button *bake;
+ EditorNode *editor;
- void _fill_tree(Node *p_node, TreeItem *p_parent);
- void _selected_changed();
- void _item_multi_selected(Object *p_object, int p_cell, bool p_selected);
- void _item_activated();
- void _remove_selection_child(Node *p_node);
- void _reown(Node *p_node, List<Node *> *p_to_reown);
+ EditorFileDialog *file_dialog;
- void ok_pressed() override;
+ void _bake_select_file(const String &p_file);
+ void _bake();
protected:
- void _notification(int p_what);
static void _bind_methods();
- void _path_browse();
- void _path_selected(const String &p_path);
- void _path_changed(const String &p_path);
public:
- void move(Node *p_new_parent, Node *p_new_owner);
- void clear();
- EditorSubScene();
+ virtual String get_name() const override { return "OccluderInstance3D"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ OccluderInstance3DEditorPlugin(EditorNode *p_node);
+ ~OccluderInstance3DEditorPlugin();
};
-#endif // EDITOR_SUB_SCENE_H
+#endif
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index 1f20a87565..0a949c8610 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -42,7 +42,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
// These properties are translated with the tr() function in the C++ code when being set or updated.
Error err;
- RES loaded_res = ResourceLoader::load(p_path, "PackedScene", false, &err);
+ RES loaded_res = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
if (err) {
ERR_PRINT("Failed to load " + p_path);
return err;
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 908235f89f..84b4516452 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -88,7 +88,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
real_t dist_to_p_in = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_in(i)));
// Check for point movement start (for point + in/out controls).
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mode == MODE_EDIT && !mb->get_shift() && dist_to_p < grab_threshold) {
// Points can only be moved in edit mode.
@@ -118,7 +118,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point deletion.
- if ((mb->get_button_index() == BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == BUTTON_LEFT && mode == MODE_DELETE)) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
@@ -149,7 +149,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point creation.
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
undo_redo->create_action(TTR("Add Point to Curve"));
@@ -170,7 +170,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for segment split.
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
Vector2 gpoint2 = mb->get_position();
Ref<Curve2D> curve = node->get_curve();
@@ -207,7 +207,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point movement completion.
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && action != ACTION_NONE) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && action != ACTION_NONE) {
Ref<Curve2D> curve = node->get_curve();
Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 3783af8fc6..47bd1114d2 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -316,7 +316,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
set_handle_clicked(false);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) {
//click into curve, break it down
Vector<Vector3> v3a = c->tessellate();
int idx = 0;
@@ -411,7 +411,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
//add new at pos
}
- } else if (mb->is_pressed() && ((mb->get_button_index() == BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == BUTTON_RIGHT && curve_edit->is_pressed()))) {
+ } else if (mb->is_pressed() && ((mb->get_button_index() == MOUSE_BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MOUSE_BUTTON_RIGHT && curve_edit->is_pressed()))) {
for (int i = 0; i < c->get_point_count(); i++) {
real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos);
real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 3d7b01c149..470d897dcc 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -447,7 +447,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
uv_drag_from = snap_point(Vector2(mb->get_position().x, mb->get_position().y));
uv_drag = true;
@@ -759,7 +759,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
bone_painting = false;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
_cancel_editing();
if (bone_painting) {
@@ -768,9 +768,9 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->update();
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * mb->get_factor())));
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * mb->get_factor())));
}
}
@@ -778,7 +778,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if ((mm->get_button_mask() & BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if ((mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
Vector2 drag(mm->get_relative().x, mm->get_relative().y);
uv_hscroll->set_value(uv_hscroll->get_value() - drag.x);
uv_vscroll->set_value(uv_vscroll->get_value() - drag.y);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 216c0c3bef..58e6717a3d 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -755,8 +755,8 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
_save_layout();
}
-void ScriptEditor::_close_current_tab() {
- _close_tab(tab_container->get_current_tab());
+void ScriptEditor::_close_current_tab(bool p_save) {
+ _close_tab(tab_container->get_current_tab(), p_save);
}
void ScriptEditor::_close_discard_current_tab(const String &p_str) {
@@ -802,7 +802,7 @@ void ScriptEditor::_close_other_tabs() {
}
}
- _close_current_tab();
+ _close_current_tab(false);
}
}
@@ -820,7 +820,7 @@ void ScriptEditor::_close_all_tabs() {
}
}
- _close_current_tab();
+ _close_current_tab(false);
}
}
@@ -894,7 +894,7 @@ void ScriptEditor::_reload_scripts() {
Ref<Script> script = edited_res;
if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true);
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_CONTINUE(!rel_script.is_valid());
script->set_source_code(rel_script->get_source_code());
script->set_last_modified_time(rel_script->get_last_modified_time());
@@ -1372,7 +1372,7 @@ void ScriptEditor::_menu_option(int p_option) {
if (current->is_unsaved()) {
_ask_close_current_unsaved_tab(current);
} else {
- _close_current_tab();
+ _close_current_tab(false);
}
} break;
case FILE_COPY_PATH: {
@@ -2706,6 +2706,8 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
void ScriptEditor::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) {
return;
}
@@ -2737,7 +2739,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid() && mb->is_pressed()) {
switch (mb->get_button_index()) {
- case BUTTON_MIDDLE: {
+ case MOUSE_BUTTON_MIDDLE: {
// Right-click selects automatically; middle-click does not.
int idx = script_list->get_item_at_position(mb->get_position(), true);
if (idx >= 0) {
@@ -2747,7 +2749,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
}
} break;
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
_make_script_list_context_menu();
} break;
}
@@ -3497,7 +3499,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
erase_tab_confirm = memnew(ConfirmationDialog);
erase_tab_confirm->get_ok_button()->set_text(TTR("Save"));
erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
- erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab));
+ erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab), varray(true));
erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab));
add_child(erase_tab_confirm);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 09ed3854ea..b2172e7f10 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -325,7 +325,7 @@ class ScriptEditor : public PanelContainer {
void _close_tab(int p_idx, bool p_save = true, bool p_history_back = true);
- void _close_current_tab();
+ void _close_current_tab(bool p_save = true);
void _close_discard_current_tab(const String &p_str);
void _close_docs_tab();
void _close_other_tabs();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index f57c8fbd6b..c982207224 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -601,8 +601,7 @@ void ScriptTextEditor::_bookmark_item_pressed(int p_idx) {
if (p_idx < 4) { // Any item before the separator.
_edit_option(bookmarks_menu->get_item_id(p_idx));
} else {
- code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx));
- code_editor->get_text_editor()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred().
+ code_editor->goto_line_centered(bookmarks_menu->get_item_metadata(p_idx));
}
}
@@ -688,7 +687,7 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
uint64_t date = FileAccess::get_modified_time(script->get_path());
if (last_date != date) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true);
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_CONTINUE(!rel_script.is_valid());
script->set_source_code(rel_script->get_source_code());
script->set_last_modified_time(rel_script->get_last_modified_time());
@@ -791,7 +790,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal("request_open_script_at_line", result.script, result.location - 1);
} else {
emit_signal("request_save_history");
- _goto_line(result.location - 1);
+ goto_line_centered(result.location - 1);
}
} break;
case ScriptLanguage::LookupResult::RESULT_CLASS: {
@@ -1066,7 +1065,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->indent_left();
+ tx->indent_selected_lines_left();
} break;
case EDIT_INDENT_RIGHT: {
Ref<Script> scr = script;
@@ -1074,7 +1073,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
- tx->indent_right();
+ tx->indent_selected_lines_right();
} break;
case EDIT_DELETE_LINE: {
code_editor->delete_lines();
@@ -1517,7 +1516,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
bool create_menu = false;
CodeEdit *tx = code_editor->get_text_editor();
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
local_pos = mb->get_global_position() - tx->get_global_position();
create_menu = true;
} else if (k.is_valid() && k->get_keycode() == KEY_MENU) {
@@ -1632,16 +1631,16 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos) {
context_menu->clear();
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
context_menu->add_separator();
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
context_menu->add_separator();
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
context_menu->add_separator();
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT);
@@ -1722,6 +1721,9 @@ void ScriptTextEditor::_enable_code_editor() {
color_picker->set_raw_mode(true);
}
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
+
quick_open = memnew(ScriptEditorQuickOpen);
quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line));
add_child(quick_open);
@@ -1743,14 +1745,14 @@ void ScriptTextEditor::_enable_code_editor() {
search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_hb->add_child(edit_menu);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
@@ -1763,7 +1765,7 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
@@ -1915,12 +1917,6 @@ static ScriptEditorBase *create_editor(const RES &p_resource) {
}
void ScriptTextEditor::register_editor() {
- ED_SHORTCUT("script_text_editor/undo", TTR("Undo"), KEY_MASK_CMD | KEY_Z);
- ED_SHORTCUT("script_text_editor/redo", TTR("Redo"), KEY_MASK_CMD | KEY_Y);
- ED_SHORTCUT("script_text_editor/cut", TTR("Cut"), KEY_MASK_CMD | KEY_X);
- ED_SHORTCUT("script_text_editor/copy", TTR("Copy"), KEY_MASK_CMD | KEY_C);
- ED_SHORTCUT("script_text_editor/paste", TTR("Paste"), KEY_MASK_CMD | KEY_V);
- ED_SHORTCUT("script_text_editor/select_all", TTR("Select All"), KEY_MASK_CMD | KEY_A);
ED_SHORTCUT("script_text_editor/move_up", TTR("Move Up"), KEY_MASK_ALT | KEY_UP);
ED_SHORTCUT("script_text_editor/move_down", TTR("Move Down"), KEY_MASK_ALT | KEY_DOWN);
ED_SHORTCUT("script_text_editor/delete_line", TTR("Delete Line"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K);
@@ -1936,10 +1932,8 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0);
#ifdef OSX_ENABLED
ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
- ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE);
#else
ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_D);
- ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD | KEY_SPACE);
#endif
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E);
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 05a1561f7d..ed3b746678 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -205,7 +205,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptCo
ShaderLanguage sl;
String calltip;
- sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip);
+ sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip);
get_text_editor()->set_code_hint(calltip);
}
@@ -219,7 +219,7 @@ void ShaderTextEditor::_validate_script() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
if (err != OK) {
String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
@@ -282,7 +282,7 @@ void ShaderEditor::_menu_option(int p_option) {
}
CodeEdit *tx = shader_editor->get_text_editor();
- tx->indent_left();
+ tx->indent_selected_lines_left();
} break;
case EDIT_INDENT_RIGHT: {
@@ -291,7 +291,7 @@ void ShaderEditor::_menu_option(int p_option) {
}
CodeEdit *tx = shader_editor->get_text_editor();
- tx->indent_right();
+ tx->indent_selected_lines_right();
} break;
case EDIT_DELETE_LINE: {
@@ -405,7 +405,7 @@ void ShaderEditor::_check_for_external_edit() {
}
void ShaderEditor::_reload_shader_from_disk() {
- Ref<Shader> rel_shader = ResourceLoader::load(shader->get_path(), shader->get_class(), true);
+ Ref<Shader> rel_shader = ResourceLoader::load(shader->get_path(), shader->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_FAIL_COND(!rel_shader.is_valid());
shader->set_code(rel_shader->get_code());
@@ -460,7 +460,7 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
int col, row;
CodeEdit *tx = shader_editor->get_text_editor();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
@@ -533,15 +533,15 @@ void ShaderEditor::_bookmark_item_pressed(int p_idx) {
void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
context_menu->clear();
if (p_selection) {
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
}
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
context_menu->add_separator();
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
context_menu->add_separator();
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT);
@@ -585,14 +585,14 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
edit_menu->set_text(TTR("Edit"));
edit_menu->set_switch_on_hover(true);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
@@ -602,7 +602,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option));
search_menu = memnew(MenuButton);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index e160e6ca0d..404ef62eca 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -167,16 +167,18 @@ void BoneTransformEditor::_notification(int p_what) {
}
void BoneTransformEditor::_value_changed(const double p_value) {
- if (updating)
+ if (updating) {
return;
+ }
Transform tform = compute_transform_from_vector3s();
_change_transform(tform);
}
void BoneTransformEditor::_value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean) {
- if (updating)
+ if (updating) {
return;
+ }
Transform tform = compute_transform_from_vector3s();
_change_transform(tform);
}
@@ -194,8 +196,9 @@ Transform BoneTransformEditor::compute_transform_from_vector3s() const {
}
void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) {
- if (updating)
+ if (updating) {
return;
+ }
_change_transform(p_transform);
}
@@ -222,11 +225,13 @@ void BoneTransformEditor::update_enabled_checkbox() {
}
void BoneTransformEditor::_update_properties() {
- if (updating)
+ if (updating) {
return;
+ }
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
updating = true;
@@ -235,11 +240,13 @@ void BoneTransformEditor::_update_properties() {
}
void BoneTransformEditor::_update_custom_pose_properties() {
- if (updating)
+ if (updating) {
return;
+ }
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
updating = true;
@@ -287,14 +294,16 @@ void BoneTransformEditor::set_toggle_enabled(const bool p_enabled) {
}
void BoneTransformEditor::_key_button_pressed() {
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
const BoneId bone_id = property.get_slicec('/', 1).to_int();
const String name = skeleton->get_bone_name(bone_id);
- if (name.is_empty())
+ if (name.is_empty()) {
return;
+ }
// Need to normalize the basis before you key it
Transform tform = compute_transform_from_vector3s();
@@ -388,7 +397,7 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
bone_shape->set_transform(capsule_transform);
Transform body_transform;
- body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0));
+ body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin);
body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
Transform joint_transform;
@@ -405,8 +414,9 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
TreeItem *selected = joint_tree->get_selected();
- if (!selected)
+ if (!selected) {
return Variant();
+ }
Ref<Texture> icon = selected->get_icon(0);
@@ -431,27 +441,32 @@ Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_fro
bool Skeleton3DEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
TreeItem *target = joint_tree->get_item_at_position(p_point);
- if (!target)
+ if (!target) {
return false;
+ }
const String path = target->get_metadata(0);
- if (!path.begins_with("bones/"))
+ if (!path.begins_with("bones/")) {
return false;
+ }
TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
- if (target == selected)
+ if (target == selected) {
return false;
+ }
const String path2 = target->get_metadata(0);
- if (!path2.begins_with("bones/"))
+ if (!path2.begins_with("bones/")) {
return false;
+ }
return true;
}
void Skeleton3DEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- if (!can_drop_data_fw(p_point, p_data, p_from))
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
return;
+ }
TreeItem *target = joint_tree->get_item_at_position(p_point);
TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
@@ -500,6 +515,8 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
rest_editor->set_target(bone_path + "rest");
custom_pose_editor->set_target(bone_path + "custom_pose");
+ _update_properties();
+
pose_editor->set_visible(true);
rest_editor->set_visible(true);
custom_pose_editor->set_visible(true);
@@ -510,19 +527,23 @@ void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos) {
}
void Skeleton3DEditor::_update_properties() {
- if (rest_editor)
+ if (rest_editor) {
rest_editor->_update_properties();
- if (pose_editor)
+ }
+ if (pose_editor) {
pose_editor->_update_properties();
- if (custom_pose_editor)
+ }
+ if (custom_pose_editor) {
custom_pose_editor->_update_custom_pose_properties();
+ }
}
void Skeleton3DEditor::update_joint_tree() {
joint_tree->clear();
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
TreeItem *root = joint_tree->create_item();
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 03ddaa2c74..4a7f6c0f7e 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -171,10 +171,15 @@ void Sprite2DEditor::_update_mesh_data() {
return;
}
- Ref<Image> image = texture->get_data();
+ Ref<Image> image = texture->get_image();
ERR_FAIL_COND(image.is_null());
+
+ if (image->is_compressed()) {
+ image->decompress();
+ }
+
Rect2 rect;
- if (node->is_region()) {
+ if (node->is_region_enabled()) {
rect = node->get_region_rect();
} else {
rect.size = Size2(image->get_width(), image->get_height());
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 0547f99079..bd6dac7490 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -105,7 +105,7 @@ void SpriteFramesEditor::_sheet_preview_draw() {
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Size2i size = split_sheet_preview->get_size();
int h = split_sheet_h->get_value();
int v = split_sheet_v->get_value();
@@ -150,11 +150,11 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
_sheet_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
_sheet_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -219,7 +219,8 @@ void SpriteFramesEditor::_sheet_zoom_out() {
}
void SpriteFramesEditor::_sheet_zoom_reset() {
- sheet_zoom = 1.f;
+ // Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
+ sheet_zoom = MAX(1.0, EDSCALE);
Size2 texture_size = split_sheet_preview->get_texture()->get_size();
split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
}
@@ -693,11 +694,11 @@ void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -732,7 +733,7 @@ void SpriteFramesEditor::_zoom_out() {
}
void SpriteFramesEditor::_zoom_reset() {
- thumbnail_zoom = 1.0f;
+ thumbnail_zoom = MAX(1.0, EDSCALE);
tree->set_fixed_column_width(thumbnail_default_size * 3 / 2);
tree->set_fixed_icon_size(Size2(thumbnail_default_size, thumbnail_default_size));
}
@@ -1229,13 +1230,14 @@ SpriteFramesEditor::SpriteFramesEditor() {
// Config scale.
scale_ratio = 1.2f;
- thumbnail_default_size = 96;
- thumbnail_zoom = 1.0f;
- max_thumbnail_zoom = 8.0f;
- min_thumbnail_zoom = 0.1f;
- sheet_zoom = 1.0f;
- max_sheet_zoom = 16.0f;
- min_sheet_zoom = 0.01f;
+ thumbnail_default_size = 96 * MAX(1.0, EDSCALE);
+ thumbnail_zoom = MAX(1.0, EDSCALE);
+ max_thumbnail_zoom = 8.0f * MAX(1.0, EDSCALE);
+ min_thumbnail_zoom = 0.1f * MAX(1.0, EDSCALE);
+ // Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
+ sheet_zoom = MAX(1.0, EDSCALE);
+ max_sheet_zoom = 16.0f * MAX(1.0, EDSCALE);
+ min_sheet_zoom = 0.01f * MAX(1.0, EDSCALE);
_zoom_reset();
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index d45011c8aa..2b8bfe067d 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -363,10 +363,10 @@ void TextEditor::_edit_option(int p_op) {
code_editor->move_lines_down();
} break;
case EDIT_INDENT_LEFT: {
- tx->indent_left();
+ tx->indent_selected_lines_left();
} break;
case EDIT_INDENT_RIGHT: {
- tx->indent_right();
+ tx->indent_selected_lines_right();
} break;
case EDIT_DELETE_LINE: {
code_editor->delete_lines();
@@ -469,7 +469,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
int col, row;
CodeEdit *tx = code_editor->get_text_editor();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
@@ -514,15 +514,15 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) {
context_menu->clear();
if (p_selection) {
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
}
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
context_menu->add_separator();
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
context_menu->add_separator();
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT);
@@ -584,14 +584,14 @@ TextEditor::TextEditor() {
edit_menu->set_switch_on_hover(true);
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("un_redo"), EDIT_REDO);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 04e6aa6fa8..36297c8a4a 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -57,7 +57,7 @@ void Texture3DEditor::_notification(int p_what) {
}
}
-void Texture3DEditor::_changed_callback(Object *p_changed, const char *p_prop) {
+void Texture3DEditor::_texture_changed() {
if (!is_visible()) {
return;
}
@@ -118,7 +118,7 @@ void Texture3DEditor::_texture_rect_update_area() {
void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
if (!texture.is_null()) {
- texture->remove_change_receptor(this);
+ texture->disconnect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
}
texture = p_texture;
@@ -128,7 +128,7 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
_make_shaders();
}
- texture->add_change_receptor(this);
+ texture->connect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
update();
texture_rect->set_material(material);
setting = true;
@@ -184,7 +184,7 @@ Texture3DEditor::Texture3DEditor() {
Texture3DEditor::~Texture3DEditor() {
if (!texture.is_null()) {
- texture->remove_change_receptor(this);
+ texture->disconnect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
}
}
diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h
index 944abf16d9..9d90d3653f 100644
--- a/editor/plugins/texture_3d_editor_plugin.h
+++ b/editor/plugins/texture_3d_editor_plugin.h
@@ -61,10 +61,12 @@ class Texture3DEditor : public Control {
void _texture_rect_update_area();
void _texture_rect_draw();
+ void _texture_changed();
+
protected:
void _notification(int p_what);
void _gui_input(Ref<InputEvent> p_event);
- void _changed_callback(Object *p_changed, const char *p_prop) override;
+
static void _bind_methods();
public:
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 1d3fd668c6..ecf7370834 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -104,7 +104,7 @@ void TextureEditor::_notification(int p_what) {
}
}
-void TextureEditor::_changed_callback(Object *p_changed, const char *p_prop) {
+void TextureEditor::_texture_changed() {
if (!is_visible()) {
return;
}
@@ -113,13 +113,13 @@ void TextureEditor::_changed_callback(Object *p_changed, const char *p_prop) {
void TextureEditor::edit(Ref<Texture2D> p_texture) {
if (!texture.is_null()) {
- texture->remove_change_receptor(this);
+ texture->disconnect("changed", callable_mp(this, &TextureEditor::_texture_changed));
}
texture = p_texture;
if (!texture.is_null()) {
- texture->add_change_receptor(this);
+ texture->connect("changed", callable_mp(this, &TextureEditor::_texture_changed));
update();
} else {
hide();
@@ -137,13 +137,13 @@ TextureEditor::TextureEditor() {
TextureEditor::~TextureEditor() {
if (!texture.is_null()) {
- texture->remove_change_receptor(this);
+ texture->disconnect("changed", callable_mp(this, &TextureEditor::_texture_changed));
}
}
//
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
- return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<LargeTexture>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
+ return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
}
void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h
index 621d737028..ebe8882194 100644
--- a/editor/plugins/texture_editor_plugin.h
+++ b/editor/plugins/texture_editor_plugin.h
@@ -43,7 +43,7 @@ class TextureEditor : public Control {
protected:
void _notification(int p_what);
void _gui_input(Ref<InputEvent> p_event);
- void _changed_callback(Object *p_changed, const char *p_prop) override;
+ void _texture_changed();
static void _bind_methods();
public:
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 2be300ad66..89ed98d53e 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -35,8 +35,10 @@
#include "editor/editor_settings.h"
void TextureLayeredEditor::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
y_rot += -mm->get_relative().x * 0.01;
x_rot += mm->get_relative().y * 0.01;
_update_material();
@@ -63,7 +65,7 @@ void TextureLayeredEditor::_notification(int p_what) {
}
}
-void TextureLayeredEditor::_changed_callback(Object *p_changed, const char *p_prop) {
+void TextureLayeredEditor::_texture_changed() {
if (!is_visible()) {
return;
}
@@ -173,7 +175,7 @@ void TextureLayeredEditor::_texture_rect_update_area() {
void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
if (!texture.is_null()) {
- texture->remove_change_receptor(this);
+ texture->disconnect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
}
texture = p_texture;
@@ -183,7 +185,7 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
_make_shaders();
}
- texture->add_change_receptor(this);
+ texture->connect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
update();
texture_rect->set_material(materials[texture->get_layered_type()]);
setting = true;
@@ -248,9 +250,6 @@ TextureLayeredEditor::TextureLayeredEditor() {
}
TextureLayeredEditor::~TextureLayeredEditor() {
- if (!texture.is_null()) {
- texture->remove_change_receptor(this);
- }
}
//
diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h
index 4bcc8fa1f1..c4ced62fb9 100644
--- a/editor/plugins/texture_layered_editor_plugin.h
+++ b/editor/plugins/texture_layered_editor_plugin.h
@@ -63,10 +63,11 @@ class TextureLayeredEditor : public Control {
void _texture_rect_update_area();
void _texture_rect_draw();
+ void _texture_changed();
+
protected:
void _notification(int p_what);
void _gui_input(Ref<InputEvent> p_event);
- void _changed_callback(Object *p_changed, const char *p_prop) override;
static void _bind_methods();
public:
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 36348f7753..7b927ad98b 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -285,7 +285,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (node_ninepatch || obj_styleBox.is_valid()) {
edited_margin = -1;
@@ -447,7 +447,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
creating = false;
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
if (drag) {
drag = false;
if (edited_margin >= 0) {
@@ -466,9 +466,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
drag_index = -1;
}
}
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
_zoom_on_position(draw_zoom * ((0.95 + (0.05 * mb->get_factor())) / 0.95), mb->get_position());
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
_zoom_on_position(draw_zoom * (1 - (0.05 * mb->get_factor())), mb->get_position());
}
}
@@ -476,7 +476,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
Vector2 dragged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom);
hscroll->set_value(hscroll->get_value() - dragged.x);
vscroll->set_value(vscroll->get_value() - dragged.y);
@@ -863,19 +863,19 @@ Sprite2D *TextureRegionEditor::get_sprite() {
void TextureRegionEditor::edit(Object *p_obj) {
if (node_sprite) {
- node_sprite->remove_change_receptor(this);
+ node_sprite->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (node_sprite_3d) {
- node_sprite_3d->remove_change_receptor(this);
+ node_sprite_3d->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (node_ninepatch) {
- node_ninepatch->remove_change_receptor(this);
+ node_ninepatch->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->remove_change_receptor(this);
+ obj_styleBox->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (atlas_tex.is_valid()) {
- atlas_tex->remove_change_receptor(this);
+ atlas_tex->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (p_obj) {
node_sprite = Object::cast_to<Sprite2D>(p_obj);
@@ -887,7 +887,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
if (Object::cast_to<AtlasTexture>(p_obj)) {
atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj));
}
- p_obj->add_change_receptor(this);
+ p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
_edit_region();
} else {
node_sprite = nullptr;
@@ -897,7 +897,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
atlas_tex = Ref<AtlasTexture>(nullptr);
}
edit_draw->update();
- if ((node_sprite && !node_sprite->is_region()) || (node_sprite_3d && !node_sprite_3d->is_region())) {
+ if ((node_sprite && !node_sprite->is_region_enabled()) || (node_sprite_3d && !node_sprite_3d->is_region_enabled())) {
set_process(true);
}
if (!p_obj) {
@@ -905,14 +905,11 @@ void TextureRegionEditor::edit(Object *p_obj) {
}
}
-void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_prop) {
+void TextureRegionEditor::_texture_changed() {
if (!is_visible()) {
return;
}
- String prop = p_prop;
- if (prop == "atlas" || prop == "texture" || prop == "region") {
- _edit_region();
- }
+ _edit_region();
}
void TextureRegionEditor::_edit_region() {
@@ -1118,7 +1115,7 @@ void TextureRegionEditorPlugin::_editor_visiblity_changed() {
void TextureRegionEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
texture_region_button->show();
- bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region()) || (region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region());
+ bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region_enabled()) || (region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region_enabled());
if ((is_node_configured && !manually_hidden) || texture_region_button->is_pressed()) {
editor->make_bottom_panel_item_visible(region_editor);
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 56ccefb025..d3db0a08a9 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -117,6 +117,8 @@ class TextureRegionEditor : public VBoxContainer {
void _update_rect();
void _update_autoslice();
+ void _texture_changed();
+
protected:
void _notification(int p_what);
void _node_removed(Object *p_obj);
@@ -124,8 +126,6 @@ protected:
Vector2 snap_point(Vector2 p_target) const;
- virtual void _changed_callback(Object *p_changed, const char *p_prop) override;
-
public:
void _edit_region();
void _region_draw();
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index dfa8c04145..c765aa0319 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -31,12 +31,696 @@
#include "theme_editor_plugin.h"
#include "core/os/file_access.h"
+#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor/editor_scale.h"
#include "scene/gui/progress_bar.h"
+void ThemeItemEditorDialog::_dialog_about_to_show() {
+ ERR_FAIL_COND(edited_theme.is_null());
+
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_update_edit_types() {
+ Ref<Theme> base_theme = Theme::get_default();
+
+ List<StringName> theme_types;
+ edited_theme->get_type_list(&theme_types);
+ theme_types.sort_custom<StringName::AlphCompare>();
+
+ bool item_reselected = false;
+ edit_type_list->clear();
+ int e_idx = 0;
+ for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
+ Ref<Texture2D> item_icon;
+ if (E->get() == "") {
+ item_icon = get_theme_icon("NodeDisabled", "EditorIcons");
+ } else {
+ item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
+ }
+ edit_type_list->add_item(E->get(), item_icon);
+
+ if (E->get() == edited_item_type) {
+ edit_type_list->select(e_idx);
+ item_reselected = true;
+ }
+ e_idx++;
+ }
+ if (!item_reselected) {
+ edited_item_type = "";
+
+ if (edit_type_list->get_item_count() > 0) {
+ edit_type_list->select(0);
+ }
+ }
+
+ List<StringName> default_types;
+ base_theme->get_type_list(&default_types);
+ default_types.sort_custom<StringName::AlphCompare>();
+
+ edit_add_class_options->clear();
+ for (List<StringName>::Element *E = default_types.front(); E; E = E->next()) {
+ edit_add_class_options->add_item(E->get());
+ }
+
+ String selected_type = "";
+ Vector<int> selected_ids = edit_type_list->get_selected_items();
+ if (selected_ids.size() > 0) {
+ selected_type = edit_type_list->get_item_text(selected_ids[0]);
+
+ edit_items_add_color->set_disabled(false);
+ edit_items_add_constant->set_disabled(false);
+ edit_items_add_font->set_disabled(false);
+ edit_items_add_font_size->set_disabled(false);
+ edit_items_add_icon->set_disabled(false);
+ edit_items_add_stylebox->set_disabled(false);
+
+ edit_items_remove_class->set_disabled(false);
+ edit_items_remove_custom->set_disabled(false);
+ edit_items_remove_all->set_disabled(false);
+ } else {
+ edit_items_add_color->set_disabled(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_add_stylebox->set_disabled(true);
+
+ edit_items_remove_class->set_disabled(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_remove_all->set_disabled(true);
+ }
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_edited_type_selected(int p_item_idx) {
+ String selected_type = edit_type_list->get_item_text(p_item_idx);
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
+ edited_item_type = p_item_type;
+
+ edit_items_tree->clear();
+ TreeItem *root = edit_items_tree->create_item();
+
+ List<StringName> names;
+
+ {
+ names.clear();
+ edited_theme->get_color_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *color_root = edit_items_tree->create_item(root);
+ color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);
+ color_root->set_icon(0, get_theme_icon("Color", "EditorIcons"));
+ color_root->set_text(0, TTR("Colors"));
+ color_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(color_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_constant_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *constant_root = edit_items_tree->create_item(root);
+ constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);
+ constant_root->set_icon(0, get_theme_icon("MemberConstant", "EditorIcons"));
+ constant_root->set_text(0, TTR("Constants"));
+ constant_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(constant_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_font_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_root = edit_items_tree->create_item(root);
+ font_root->set_metadata(0, Theme::DATA_TYPE_FONT);
+ font_root->set_icon(0, get_theme_icon("Font", "EditorIcons"));
+ font_root->set_text(0, TTR("Fonts"));
+ font_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_font_size_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_size_root = edit_items_tree->create_item(root);
+ font_size_root->set_metadata(0, Theme::DATA_TYPE_FONT_SIZE);
+ font_size_root->set_icon(0, get_theme_icon("FontSize", "EditorIcons"));
+ font_size_root->set_text(0, TTR("Font Sizes"));
+ font_size_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Size Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_size_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_icon_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *icon_root = edit_items_tree->create_item(root);
+ icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);
+ icon_root->set_icon(0, get_theme_icon("ImageTexture", "EditorIcons"));
+ icon_root->set_text(0, TTR("Icons"));
+ icon_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(icon_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_stylebox_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *stylebox_root = edit_items_tree->create_item(root);
+ stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);
+ stylebox_root->set_icon(0, get_theme_icon("StyleBoxFlat", "EditorIcons"));
+ stylebox_root->set_text(0, TTR("Styleboxes"));
+ stylebox_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(stylebox_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ switch (p_id) {
+ case ITEMS_TREE_RENAME_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ _open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);
+ } break;
+ case ITEMS_TREE_REMOVE_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ edited_theme->clear_theme_item((Theme::DataType)data_type, item_name, edited_item_type);
+ } break;
+ case ITEMS_TREE_REMOVE_DATA_TYPE: {
+ int data_type = item->get_metadata(0);
+ _remove_data_type_items((Theme::DataType)data_type, edited_item_type);
+ } break;
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_add_class_type_items() {
+ int selected_idx = edit_add_class_options->get_selected();
+ String type_name = edit_add_class_options->get_item_text(selected_idx);
+ List<StringName> names;
+
+ {
+ names.clear();
+ Theme::get_default()->get_icon_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_icon(E->get(), type_name, Ref<Texture2D>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_stylebox_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_stylebox(E->get(), type_name, Ref<StyleBox>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_font(E->get(), type_name, Ref<Font>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_size_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_font_size(E->get(), type_name, Theme::get_default()->get_font_size(E->get(), type_name));
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_color_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_color(E->get(), type_name, Theme::get_default()->get_color(E->get(), type_name));
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_constant_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_constant(E->get(), type_name, Theme::get_default()->get_constant(E->get(), type_name));
+ }
+ }
+
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_add_custom_type() {
+ edited_theme->add_icon_type(edit_add_custom_value->get_text());
+ edited_theme->add_stylebox_type(edit_add_custom_value->get_text());
+ edited_theme->add_font_type(edit_add_custom_value->get_text());
+ edited_theme->add_font_size_type(edit_add_custom_value->get_text());
+ edited_theme->add_color_type(edit_add_custom_value->get_text());
+ edited_theme->add_constant_type(edit_add_custom_value->get_text());
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_ICON:
+ edited_theme->set_icon(p_item_name, p_item_type, Ref<Texture2D>());
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edited_theme->set_stylebox(p_item_name, p_item_type, Ref<StyleBox>());
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edited_theme->set_font(p_item_name, p_item_type, Ref<Font>());
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edited_theme->set_font_size(p_item_name, p_item_type, -1);
+ break;
+ case Theme::DATA_TYPE_COLOR:
+ edited_theme->set_color(p_item_name, p_item_type, Color());
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edited_theme->set_constant(p_item_name, p_item_type, 0);
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {
+ List<StringName> names;
+
+ edited_theme->get_theme_item_list(p_data_type, p_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->clear_theme_item(p_data_type, E->get(), p_item_type);
+ }
+}
+
+void ThemeItemEditorDialog::_remove_class_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (edited_theme->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_remove_custom_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!Theme::get_default()->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_remove_all_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = CREATE_THEME_ITEM;
+ edit_item_data_type = (Theme::DataType)p_data_type;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Add Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Add Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Add Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Add Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Add Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->hide();
+ theme_item_name->clear();
+ edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = RENAME_THEME_ITEM;
+ edit_item_data_type = p_data_type;
+ edit_item_old_name = p_item_name;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Rename Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->show();
+ theme_item_old_name->set_text(p_item_name);
+ theme_item_name->set_text(p_item_name);
+ edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_confirm_edit_theme_item() {
+ if (item_popup_mode == CREATE_THEME_ITEM) {
+ _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
+ } else if (item_popup_mode == RENAME_THEME_ITEM) {
+ edited_theme->rename_theme_item(edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
+ }
+
+ item_popup_mode = ITEM_POPUP_MODE_MAX;
+ edit_item_data_type = Theme::DATA_TYPE_MAX;
+ edit_item_old_name = "";
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ return;
+ }
+
+ switch (k->get_keycode()) {
+ case KEY_KP_ENTER:
+ case KEY_ENTER: {
+ _confirm_edit_theme_item();
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ case KEY_ESCAPE: {
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ edit_items_add_color->set_icon(get_theme_icon("Color", "EditorIcons"));
+ edit_items_add_constant->set_icon(get_theme_icon("MemberConstant", "EditorIcons"));
+ edit_items_add_font->set_icon(get_theme_icon("Font", "EditorIcons"));
+ edit_items_add_font_size->set_icon(get_theme_icon("FontSize", "EditorIcons"));
+ edit_items_add_icon->set_icon(get_theme_icon("ImageTexture", "EditorIcons"));
+ edit_items_add_stylebox->set_icon(get_theme_icon("StyleBoxFlat", "EditorIcons"));
+
+ edit_items_remove_class->set_icon(get_theme_icon("Control", "EditorIcons"));
+ edit_items_remove_custom->set_icon(get_theme_icon("ThemeRemoveCustomItems", "EditorIcons"));
+ edit_items_remove_all->set_icon(get_theme_icon("ThemeRemoveAllItems", "EditorIcons"));
+ } break;
+ }
+}
+
+void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {
+ edited_theme = p_theme;
+}
+
+ThemeItemEditorDialog::ThemeItemEditorDialog() {
+ set_title(TTR("Edit Theme Items"));
+
+ HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);
+ add_child(edit_dialog_hs);
+
+ VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);
+ edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);
+ edit_dialog_hs->add_child(edit_dialog_side_vb);
+
+ Label *edit_type_label = memnew(Label);
+ edit_type_label->set_text(TTR("Types:"));
+ edit_dialog_side_vb->add_child(edit_type_label);
+
+ edit_type_list = memnew(ItemList);
+ edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_side_vb->add_child(edit_type_list);
+ edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));
+
+ Label *edit_add_class_label = memnew(Label);
+ edit_add_class_label->set_text(TTR("Add Type from Class:"));
+ edit_dialog_side_vb->add_child(edit_add_class_label);
+
+ HBoxContainer *edit_add_class = memnew(HBoxContainer);
+ edit_dialog_side_vb->add_child(edit_add_class);
+ edit_add_class_options = memnew(OptionButton);
+ edit_add_class_options->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_add_class->add_child(edit_add_class_options);
+ Button *edit_add_class_button = memnew(Button);
+ edit_add_class_button->set_text(TTR("Add"));
+ edit_add_class->add_child(edit_add_class_button);
+ edit_add_class_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_class_type_items));
+
+ Label *edit_add_custom_label = memnew(Label);
+ edit_add_custom_label->set_text(TTR("Add Custom Type:"));
+ edit_dialog_side_vb->add_child(edit_add_custom_label);
+
+ HBoxContainer *edit_add_custom = memnew(HBoxContainer);
+ edit_dialog_side_vb->add_child(edit_add_custom);
+ edit_add_custom_value = memnew(LineEdit);
+ edit_add_custom_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_add_custom->add_child(edit_add_custom_value);
+ Button *edit_add_custom_button = memnew(Button);
+ edit_add_custom_button->set_text(TTR("Add"));
+ edit_add_custom->add_child(edit_add_custom_button);
+ edit_add_custom_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_custom_type));
+
+ VBoxContainer *edit_items_vb = memnew(VBoxContainer);
+ edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_hs->add_child(edit_items_vb);
+
+ HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);
+ edit_items_vb->add_child(edit_items_toolbar);
+
+ Label *edit_items_toolbar_add_label = memnew(Label);
+ edit_items_toolbar_add_label->set_text(TTR("Add:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_add_label);
+
+ edit_items_add_color = memnew(Button);
+ edit_items_add_color->set_tooltip(TTR("Add Color Item"));
+ edit_items_add_color->set_flat(true);
+ edit_items_add_color->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_color);
+ edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_COLOR));
+
+ edit_items_add_constant = memnew(Button);
+ edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
+ edit_items_add_constant->set_flat(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_constant);
+ edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_CONSTANT));
+
+ edit_items_add_font = memnew(Button);
+ edit_items_add_font->set_tooltip(TTR("Add Font Item"));
+ edit_items_add_font->set_flat(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font);
+ edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT));
+
+ edit_items_add_font_size = memnew(Button);
+ edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item"));
+ edit_items_add_font_size->set_flat(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font_size);
+ edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT_SIZE));
+
+ edit_items_add_icon = memnew(Button);
+ edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
+ edit_items_add_icon->set_flat(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_icon);
+ edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_ICON));
+
+ edit_items_add_stylebox = memnew(Button);
+ edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
+ edit_items_add_stylebox->set_flat(true);
+ edit_items_add_stylebox->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_stylebox);
+ edit_items_add_stylebox->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_STYLEBOX));
+
+ edit_items_toolbar->add_child(memnew(VSeparator));
+
+ Label *edit_items_toolbar_remove_label = memnew(Label);
+ edit_items_toolbar_remove_label->set_text(TTR("Remove:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
+
+ edit_items_remove_class = memnew(Button);
+ edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
+ edit_items_remove_class->set_flat(true);
+ edit_items_remove_class->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_class);
+ edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));
+
+ edit_items_remove_custom = memnew(Button);
+ edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
+ edit_items_remove_custom->set_flat(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_custom);
+ edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));
+
+ edit_items_remove_all = memnew(Button);
+ edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
+ edit_items_remove_all->set_flat(true);
+ edit_items_remove_all->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_all);
+ edit_items_remove_all->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_all_items));
+
+ edit_items_tree = memnew(Tree);
+ edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_items_tree->set_hide_root(true);
+ edit_items_tree->set_columns(1);
+ edit_items_vb->add_child(edit_items_tree);
+ edit_items_tree->connect("button_pressed", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed));
+
+ edit_theme_item_dialog = memnew(ConfirmationDialog);
+ edit_theme_item_dialog->set_title(TTR("Add Theme Item"));
+ add_child(edit_theme_item_dialog);
+ VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);
+ edit_theme_item_dialog->add_child(edit_theme_item_vb);
+
+ edit_theme_item_old_vb = memnew(VBoxContainer);
+ edit_theme_item_vb->add_child(edit_theme_item_old_vb);
+ Label *edit_theme_item_old = memnew(Label);
+ edit_theme_item_old->set_text(TTR("Old Name:"));
+ edit_theme_item_old_vb->add_child(edit_theme_item_old);
+ theme_item_old_name = memnew(Label);
+ edit_theme_item_old_vb->add_child(theme_item_old_name);
+
+ Label *edit_theme_item_label = memnew(Label);
+ edit_theme_item_label->set_text(TTR("Name:"));
+ edit_theme_item_vb->add_child(edit_theme_item_label);
+ theme_item_name = memnew(LineEdit);
+ edit_theme_item_vb->add_child(theme_item_name);
+ theme_item_name->connect("gui_input", callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input));
+ edit_theme_item_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item));
+}
+
void ThemeEditor::edit(const Ref<Theme> &p_theme) {
theme = p_theme;
+ theme_edit_dialog->set_edited_theme(p_theme);
main_panel->set_theme(p_theme);
main_container->set_theme(p_theme);
}
@@ -58,55 +742,6 @@ void ThemeEditor::_refresh_interval() {
_propagate_redraw(main_container);
}
-void ThemeEditor::_type_menu_cbk(int p_option) {
- type_edit->set_text(type_menu->get_popup()->get_item_text(p_option));
-}
-
-void ThemeEditor::_name_menu_about_to_show() {
- String fromtype = type_edit->get_text();
- List<StringName> names;
-
- if (popup_mode == POPUP_ADD) {
- switch (type_select->get_selected()) {
- case 0:
- Theme::get_default()->get_icon_list(fromtype, &names);
- break;
- case 1:
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- break;
- case 2:
- Theme::get_default()->get_font_list(fromtype, &names);
- break;
- case 3:
- Theme::get_default()->get_font_size_list(fromtype, &names);
- break;
- case 4:
- Theme::get_default()->get_color_list(fromtype, &names);
- break;
- case 5:
- Theme::get_default()->get_constant_list(fromtype, &names);
- break;
- }
- } else if (popup_mode == POPUP_REMOVE) {
- theme->get_icon_list(fromtype, &names);
- theme->get_stylebox_list(fromtype, &names);
- theme->get_font_list(fromtype, &names);
- theme->get_font_size_list(fromtype, &names);
- theme->get_color_list(fromtype, &names);
- theme->get_constant_list(fromtype, &names);
- }
-
- name_menu->get_popup()->clear();
- name_menu->get_popup()->set_size(Size2());
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- name_menu->get_popup()->add_item(E->get());
- }
-}
-
-void ThemeEditor::_name_menu_cbk(int p_option) {
- name_edit->set_text(name_menu->get_popup()->get_item_text(p_option));
-}
-
struct _TECategory {
template <class T>
struct RefItem {
@@ -335,296 +970,71 @@ void ThemeEditor::_save_template_cbk(String fname) {
memdelete(file);
}
-void ThemeEditor::_dialog_cbk() {
- switch (popup_mode) {
- case POPUP_ADD: {
- switch (type_select->get_selected()) {
- case 0:
- theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture2D>());
- break;
- case 1:
- theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>());
- break;
- case 2:
- theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>());
- break;
- case 3:
- theme->set_font_size(name_edit->get_text(), type_edit->get_text(), -1);
- break;
- case 4:
- theme->set_color(name_edit->get_text(), type_edit->get_text(), Color());
- break;
- case 5:
- theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0);
- break;
- }
-
- } break;
- case POPUP_CLASS_ADD: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_icon(E->get(), fromtype, Ref<Texture2D>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), fromtype, Ref<StyleBox>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font(E->get(), fromtype, Ref<Font>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), fromtype, Theme::get_default()->get_font_size(E->get(), fromtype));
- }
- }
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_color(E->get(), fromtype, Theme::get_default()->get_color(E->get(), fromtype));
- }
- }
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_constant(E->get(), fromtype, Theme::get_default()->get_constant(E->get(), fromtype));
- }
- }
- } break;
- case POPUP_REMOVE: {
- switch (type_select->get_selected()) {
- case 0:
- theme->clear_icon(name_edit->get_text(), type_edit->get_text());
- break;
- case 1:
- theme->clear_stylebox(name_edit->get_text(), type_edit->get_text());
- break;
- case 2:
- theme->clear_font(name_edit->get_text(), type_edit->get_text());
- break;
- case 3:
- theme->clear_font_size(name_edit->get_text(), type_edit->get_text());
- break;
- case 4:
- theme->clear_color(name_edit->get_text(), type_edit->get_text());
- break;
- case 5:
- theme->clear_constant(name_edit->get_text(), type_edit->get_text());
- break;
- }
-
- } break;
- case POPUP_CLASS_REMOVE: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_icon(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_stylebox(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font_size(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_color(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_constant(E->get(), fromtype);
- }
- }
-
- } break;
- }
-}
-
-void ThemeEditor::_theme_menu_cbk(int p_option) {
- if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) {
- bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
-
- Ref<Theme> base_theme;
-
- if (p_option == POPUP_CREATE_EMPTY) {
- base_theme = Theme::get_default();
- } else {
- base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
- }
-
- {
- List<StringName> types;
- base_theme->get_type_list(&types);
-
- for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
- StringName type = T->get();
-
- List<StringName> icons;
- base_theme->get_icon_list(type, &icons);
-
- for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
- theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>());
- }
-
- List<StringName> styleboxs;
- base_theme->get_stylebox_list(type, &styleboxs);
-
- for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
- }
-
- List<StringName> fonts;
- base_theme->get_font_list(type, &fonts);
-
- for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
- theme->set_font(E->get(), type, Ref<Font>());
- }
-
- List<StringName> font_sizes;
- base_theme->get_font_size_list(type, &font_sizes);
-
- for (List<StringName>::Element *E = font_sizes.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type));
- }
-
- List<StringName> colors;
- base_theme->get_color_list(type, &colors);
-
- for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
- theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
- }
-
- List<StringName> constants;
- base_theme->get_constant_list(type, &constants);
-
- for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
- }
- }
- }
- return;
- }
+void ThemeEditor::_theme_create_menu_cbk(int p_option) {
+ bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
Ref<Theme> base_theme;
- name_select_label->show();
- name_hbc->show();
- type_select_label->show();
- type_select->show();
-
- if (p_option == POPUP_ADD) { // Add.
-
- add_del_dialog->set_title(TTR("Add Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
-
+ if (p_option == POPUP_CREATE_EMPTY) {
base_theme = Theme::get_default();
+ } else {
+ base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
+ }
- } else if (p_option == POPUP_CLASS_ADD) { // Add.
-
- add_del_dialog->set_title(TTR("Add All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
-
- base_theme = Theme::get_default();
+ {
+ List<StringName> types;
+ base_theme->get_type_list(&types);
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
+ for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
+ StringName type = T->get();
- } else if (p_option == POPUP_REMOVE) {
- add_del_dialog->set_title(TTR("Remove Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
+ List<StringName> icons;
+ base_theme->get_icon_list(type, &icons);
- base_theme = theme;
+ for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
+ theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>());
+ }
- } else if (p_option == POPUP_CLASS_REMOVE) {
- add_del_dialog->set_title(TTR("Remove All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
+ List<StringName> styleboxs;
+ base_theme->get_stylebox_list(type, &styleboxs);
- base_theme = Theme::get_default();
+ for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
+ theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
+ }
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
- }
- popup_mode = p_option;
+ List<StringName> fonts;
+ base_theme->get_font_list(type, &fonts);
- ERR_FAIL_COND(theme.is_null());
+ for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
+ theme->set_font(E->get(), type, Ref<Font>());
+ }
- List<StringName> types;
- base_theme->get_type_list(&types);
+ List<StringName> font_sizes;
+ base_theme->get_font_size_list(type, &font_sizes);
- type_menu->get_popup()->clear();
+ for (List<StringName>::Element *E = font_sizes.front(); E; E = E->next()) {
+ theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type));
+ }
- if (p_option == 0 || p_option == 1) { // Add.
+ List<StringName> colors;
+ base_theme->get_color_list(type, &colors);
- List<StringName> new_types;
- theme->get_type_list(&new_types);
- for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) {
- bool found = false;
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- if (E->get() == F->get()) {
- found = true;
- break;
- }
+ for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
+ theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
}
- if (!found) {
- types.push_back(F->get());
+ List<StringName> constants;
+ base_theme->get_constant_list(type, &constants);
+
+ for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
}
}
}
+}
- types.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- type_menu->get_popup()->add_item(E->get());
- }
+void ThemeEditor::_theme_edit_button_cbk() {
+ theme_edit_dialog->popup_centered(Size2(800, 640) * EDSCALE);
}
void ThemeEditor::_notification(int p_what) {
@@ -636,9 +1046,6 @@ void ThemeEditor::_notification(int p_what) {
_refresh_interval();
}
} break;
- case NOTIFICATION_THEME_CHANGED: {
- theme_menu->set_icon(get_theme_icon("Theme", "EditorIcons"));
- } break;
}
}
@@ -646,27 +1053,28 @@ void ThemeEditor::_bind_methods() {
}
ThemeEditor::ThemeEditor() {
- time_left = 0;
-
HBoxContainer *top_menu = memnew(HBoxContainer);
add_child(top_menu);
top_menu->add_child(memnew(Label(TTR("Preview:"))));
top_menu->add_spacer(false);
- theme_menu = memnew(MenuButton);
- theme_menu->set_text(TTR("Edit Theme"));
- theme_menu->set_tooltip(TTR("Theme editing menu."));
- theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD);
- theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD);
- theme_menu->get_popup()->add_item(TTR("Remove Item"), POPUP_REMOVE);
- theme_menu->get_popup()->add_item(TTR("Remove Class Items"), POPUP_CLASS_REMOVE);
- theme_menu->get_popup()->add_separator();
- theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
- top_menu->add_child(theme_menu);
- theme_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_menu_cbk));
+ theme_create_menu = memnew(MenuButton);
+ theme_create_menu->set_text(TTR("Create Theme..."));
+ theme_create_menu->set_tooltip(TTR("Create a new Theme."));
+ theme_create_menu->get_popup()->add_item(TTR("Empty Template"), POPUP_CREATE_EMPTY);
+ theme_create_menu->get_popup()->add_separator();
+ theme_create_menu->get_popup()->add_item(TTR("Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
+ theme_create_menu->get_popup()->add_item(TTR("From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
+ top_menu->add_child(theme_create_menu);
+ theme_create_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_create_menu_cbk));
+
+ theme_edit_button = memnew(Button);
+ theme_edit_button->set_text(TTR("Edit Theme Items"));
+ theme_edit_button->set_tooltip(TTR("Customize Theme items."));
+ theme_edit_button->set_flat(true);
+ theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
+ top_menu->add_child(theme_edit_button);
ScrollContainer *scroll = memnew(ScrollContainer);
add_child(scroll);
@@ -849,66 +1257,9 @@ ThemeEditor::ThemeEditor() {
main_hb->add_theme_constant_override("separation", 20 * EDSCALE);
- ////////
-
- add_del_dialog = memnew(ConfirmationDialog);
- add_del_dialog->hide();
- add_child(add_del_dialog);
-
- VBoxContainer *dialog_vbc = memnew(VBoxContainer);
- add_del_dialog->add_child(dialog_vbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Type:"));
- dialog_vbc->add_child(l);
-
- type_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(type_hbc);
-
- type_edit = memnew(LineEdit);
- type_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- type_hbc->add_child(type_edit);
- type_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- type_menu->set_text("...");
- type_hbc->add_child(type_menu);
-
- type_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_type_menu_cbk));
-
- l = memnew(Label);
- l->set_text(TTR("Name:"));
- dialog_vbc->add_child(l);
- name_select_label = l;
-
- name_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(name_hbc);
-
- name_edit = memnew(LineEdit);
- name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- name_hbc->add_child(name_edit);
- name_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- name_menu->set_text("...");
- name_hbc->add_child(name_menu);
-
- name_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ThemeEditor::_name_menu_about_to_show));
- name_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_name_menu_cbk));
-
- type_select_label = memnew(Label);
- type_select_label->set_text(TTR("Data Type:"));
- dialog_vbc->add_child(type_select_label);
-
- type_select = memnew(OptionButton);
- type_select->add_item(TTR("Icon"));
- type_select->add_item(TTR("Style"));
- type_select->add_item(TTR("Font"));
- type_select->add_item(TTR("Font Size"));
- type_select->add_item(TTR("Color"));
- type_select->add_item(TTR("Constant"));
-
- dialog_vbc->add_child(type_select);
-
- add_del_dialog->get_ok_button()->connect("pressed", callable_mp(this, &ThemeEditor::_dialog_cbk));
+ theme_edit_dialog = memnew(ThemeItemEditorDialog);
+ theme_edit_dialog->hide();
+ add_child(theme_edit_dialog);
file_dialog = memnew(EditorFileDialog);
file_dialog->add_filter("*.theme ; " + TTR("Theme File"));
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index ab199f8e51..0a840aecd7 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -41,6 +41,77 @@
#include "editor/editor_node.h"
+class ThemeItemEditorDialog : public AcceptDialog {
+ GDCLASS(ThemeItemEditorDialog, AcceptDialog);
+
+ Ref<Theme> edited_theme;
+
+ ItemList *edit_type_list;
+ OptionButton *edit_add_class_options;
+ LineEdit *edit_add_custom_value;
+ String edited_item_type;
+
+ Button *edit_items_add_color;
+ Button *edit_items_add_constant;
+ Button *edit_items_add_font;
+ Button *edit_items_add_font_size;
+ Button *edit_items_add_icon;
+ Button *edit_items_add_stylebox;
+ Button *edit_items_remove_class;
+ Button *edit_items_remove_custom;
+ Button *edit_items_remove_all;
+ Tree *edit_items_tree;
+
+ enum ItemsTreeAction {
+ ITEMS_TREE_RENAME_ITEM,
+ ITEMS_TREE_REMOVE_ITEM,
+ ITEMS_TREE_REMOVE_DATA_TYPE,
+ };
+
+ ConfirmationDialog *edit_theme_item_dialog;
+ VBoxContainer *edit_theme_item_old_vb;
+ Label *theme_item_old_name;
+ LineEdit *theme_item_name;
+
+ enum ItemPopupMode {
+ CREATE_THEME_ITEM,
+ RENAME_THEME_ITEM,
+ ITEM_POPUP_MODE_MAX
+ };
+
+ ItemPopupMode item_popup_mode = ITEM_POPUP_MODE_MAX;
+ String edit_item_old_name;
+ Theme::DataType edit_item_data_type = Theme::DATA_TYPE_MAX;
+
+ void _dialog_about_to_show();
+ void _update_edit_types();
+ void _edited_type_selected(int p_item_idx);
+
+ void _update_edit_item_tree(String p_item_type);
+ void _item_tree_button_pressed(Object *p_item, int p_column, int p_id);
+
+ void _add_class_type_items();
+ void _add_custom_type();
+ void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type);
+ void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type);
+ void _remove_class_items();
+ void _remove_custom_items();
+ void _remove_all_items();
+
+ void _open_add_theme_item_dialog(int p_data_type);
+ void _open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name);
+ void _confirm_edit_theme_item();
+ void _edit_theme_item_gui_input(const Ref<InputEvent> &p_event);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_edited_theme(const Ref<Theme> &p_theme);
+
+ ThemeItemEditorDialog();
+};
+
class ThemeEditor : public VBoxContainer {
GDCLASS(ThemeEditor, VBoxContainer);
@@ -50,40 +121,23 @@ class ThemeEditor : public VBoxContainer {
EditorFileDialog *file_dialog;
- double time_left;
-
- MenuButton *theme_menu;
- ConfirmationDialog *add_del_dialog;
- HBoxContainer *type_hbc;
- MenuButton *type_menu;
- LineEdit *type_edit;
- HBoxContainer *name_hbc;
- MenuButton *name_menu;
- LineEdit *name_edit;
- OptionButton *type_select;
- Label *type_select_label;
- Label *name_select_label;
-
- enum PopupMode {
- POPUP_ADD,
- POPUP_CLASS_ADD,
- POPUP_REMOVE,
- POPUP_CLASS_REMOVE,
+ double time_left = 0;
+
+ Button *theme_edit_button;
+ MenuButton *theme_create_menu;
+ ThemeItemEditorDialog *theme_edit_dialog;
+
+ enum CreatePopupMode {
POPUP_CREATE_EMPTY,
POPUP_CREATE_EDITOR_EMPTY,
- POPUP_IMPORT_EDITOR_THEME
+ POPUP_IMPORT_EDITOR_THEME,
};
- int popup_mode;
-
Tree *test_tree;
void _save_template_cbk(String fname);
- void _dialog_cbk();
- void _type_menu_cbk(int p_option);
- void _name_menu_about_to_show();
- void _name_menu_cbk(int p_option);
- void _theme_menu_cbk(int p_option);
+ void _theme_edit_button_cbk();
+ void _theme_create_menu_cbk(int p_option);
void _propagate_redraw(Control *p_at);
void _refresh_interval();
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 6a16aa28a9..bd721244ea 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -40,9 +40,12 @@
void TileMapEditor::_node_removed(Node *p_node) {
if (p_node == node && node) {
- // Fixes #44824, which describes a situation where you can reselect a TileMap node without first de-selecting it when switching scenes.
- node->disconnect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed));
+ Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
+ if (node->is_connected("settings_changed", callable_tileset_settings_changed)) {
+ // Fixes #44824, which describes a situation where you can reselect a TileMap node without first de-selecting it when switching scenes.
+ node->disconnect("settings_changed", callable_tileset_settings_changed);
+ }
node = nullptr;
}
}
@@ -230,11 +233,11 @@ void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel.
if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
size_slider->set_value(size_slider->get_value() + 0.2);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
size_slider->set_value(size_slider->get_value() - 0.2);
}
}
@@ -963,9 +966,9 @@ void TileMapEditor::_update_copydata() {
tcd.flip_v = node->is_cell_y_flipped(j, i);
tcd.transpose = node->is_cell_transposed(j, i);
tcd.autotile_coord = node->get_cell_autotile_coord(j, i);
- }
- copydata.push_back(tcd);
+ copydata.push_back(tcd);
+ }
}
}
}
@@ -1024,7 +1027,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
return false; // Drag.
@@ -1174,7 +1177,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (mb->is_pressed()) {
if (tool == TOOL_SELECTING || selection_active) {
tool = TOOL_NONE;
@@ -1459,7 +1462,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
- if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
_pick_tile(over_tile);
return true;
@@ -1870,7 +1873,11 @@ void TileMapEditor::edit(Node *p_tile_map) {
}
if (node) {
- node->disconnect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed));
+ Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
+
+ if (node->is_connected("settings_changed", callable_tileset_settings_changed)) {
+ node->disconnect("settings_changed", callable_tileset_settings_changed);
+ }
}
if (p_tile_map) {
node = Object::cast_to<TileMap>(p_tile_map);
@@ -1897,7 +1904,11 @@ void TileMapEditor::edit(Node *p_tile_map) {
}
if (node) {
- node->connect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed));
+ Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
+
+ if (!node->is_connected("settings_changed", callable_tileset_settings_changed)) {
+ node->connect("settings_changed", callable_tileset_settings_changed);
+ }
}
_clear_bucket_cache();
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 5ac7fe262f..f683c4b10d 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -39,7 +39,6 @@
void TileSetEditor::edit(const Ref<TileSet> &p_tileset) {
tileset = p_tileset;
- tileset->add_change_receptor(this);
texture_list->clear();
texture_map.clear();
@@ -81,7 +80,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
Vector2 phys_offset;
Size2 s;
- if (mi->is_region()) {
+ if (mi->is_region_enabled()) {
s = mi->get_region_rect().size;
p_library->tile_set_region(id, mi->get_region_rect());
} else {
@@ -320,7 +319,7 @@ void TileSetEditor::_notification(int p_what) {
tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_theme_icon("Navigation2D", "EditorIcons"));
tool_editmode[EDITMODE_BITMASK]->set_icon(get_theme_icon("PackedDataContainer", "EditorIcons"));
tool_editmode[EDITMODE_PRIORITY]->set_icon(get_theme_icon("MaterialPreviewLight1", "EditorIcons"));
- tool_editmode[EDITMODE_ICON]->set_icon(get_theme_icon("LargeTexture", "EditorIcons"));
+ tool_editmode[EDITMODE_ICON]->set_icon(get_theme_icon("Image", "EditorIcons"));
tool_editmode[EDITMODE_Z_INDEX]->set_icon(get_theme_icon("Sort", "EditorIcons"));
scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
@@ -1247,12 +1246,12 @@ void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
print_line("zooming in");
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
print_line("zooming out");
_zoom_out();
// Don't scroll down after zooming out.
@@ -1281,7 +1280,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
const Ref<InputEventMouseMotion> mm = p_ie;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !creating_shape) {
if (!current_tile_region.has_point(mb->get_position())) {
List<int> *tiles = new List<int>();
tileset->get_tile_list(tiles);
@@ -1305,7 +1304,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
// Drag Middle Mouse
if (mm.is_valid()) {
- if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
@@ -1314,7 +1313,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (edit_mode == EDITMODE_REGION) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) {
dragging = true;
region_from = mb->get_position();
@@ -1323,13 +1322,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
workspace_overlay->update();
return;
}
- } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (dragging && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
dragging = false;
edited_region = Rect2();
workspace->update();
workspace_overlay->update();
return;
- } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (dragging && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
dragging = false;
update_edited_region(mb->get_position());
edited_region.position -= WORKSPACE_MARGIN;
@@ -1429,7 +1428,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
switch (edit_mode) {
case EDITMODE_ICON: {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
undo_redo->create_action(TTR("Set Tile Icon"));
undo_redo->add_do_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), coord);
@@ -1446,9 +1445,9 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (dragging) {
return;
}
- if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT || mb->get_button_index() == MOUSE_BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
- erasing = (mb->get_button_index() == BUTTON_RIGHT);
+ erasing = (mb->get_button_index() == MOUSE_BUTTON_RIGHT);
alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
@@ -1519,7 +1518,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
} else {
- if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
+ if ((erasing && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (!erasing && mb->get_button_index() == MOUSE_BUTTON_LEFT)) {
dragging = false;
erasing = false;
alternative = false;
@@ -1613,7 +1612,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
shape_anchor += current_tile_region.position;
if (tools[TOOL_SELECT]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) {
int grabbed_point = get_grabbed_point(mb->get_position(), grab_threshold);
@@ -1631,7 +1630,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
workspace->update();
- } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (edit_mode == EDITMODE_COLLISION) {
if (dragging_point >= 0) {
dragging_point = -1;
@@ -1706,7 +1705,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
} else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 pos = mb->get_position();
pos = snap_point(pos);
if (creating_shape) {
@@ -1726,7 +1725,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
current_shape.push_back(snap_point(pos));
workspace->update();
}
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (creating_shape) {
creating_shape = false;
_select_edited_shape_coord();
@@ -1740,7 +1739,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
} else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
current_shape.resize(0);
Vector2 pos = mb->get_position();
@@ -1752,13 +1751,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
creating_shape = true;
workspace->update();
return;
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (creating_shape) {
creating_shape = false;
_select_edited_shape_coord();
workspace->update();
}
- } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (creating_shape) {
// if the first two corners are within grabbing distance of one another, expand the rect to fill the tile
if (is_within_grabbing_distance_of_first_point(current_shape[1], grab_threshold)) {
@@ -1859,7 +1858,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
_update_toggle_shape_button();
workspace->update();
workspace_container->update();
- helper->_change_notify("");
+ helper->notify_property_list_changed();
}
} else if (p_tool == SELECT_NEXT) {
_select_next_shape();
@@ -2287,7 +2286,7 @@ void TileSetEditor::_select_next_shape() {
}
workspace->update();
workspace_container->update();
- helper->_change_notify("");
+ helper->notify_property_list_changed();
}
}
@@ -2349,7 +2348,7 @@ void TileSetEditor::_select_previous_shape() {
}
workspace->update();
workspace_container->update();
- helper->_change_notify("");
+ helper->notify_property_list_changed();
}
}
@@ -2929,7 +2928,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
}
if (p_total < 0) {
- points.invert();
+ points.reverse();
}
shape->set_points(points);
@@ -3012,7 +3011,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
undo_redo->add_undo_method(this, "_select_edited_shape_coord");
undo_redo->commit_action();
}
- tileset->_change_notify("");
+ tileset->notify_property_list_changed();
}
void TileSetEditor::select_coord(const Vector2 &coord) {
@@ -3115,7 +3114,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
}
workspace->update();
workspace_container->update();
- helper->_change_notify("");
+ helper->notify_property_list_changed();
}
Vector2 TileSetEditor::snap_point(const Vector2 &point) {
@@ -3225,7 +3224,7 @@ void TileSetEditor::update_texture_list() {
workspace_overlay->update();
}
update_texture_list_icon();
- helper->_change_notify("");
+ helper->notify_property_list_changed();
}
void TileSetEditor::update_texture_list_icon() {
@@ -3389,7 +3388,7 @@ int TileSetEditor::get_current_tile() const {
void TileSetEditor::set_current_tile(int p_id) {
if (current_tile != p_id) {
current_tile = p_id;
- helper->_change_notify("");
+ helper->notify_property_list_changed();
select_coord(Vector2(0, 0));
update_workspace_tile_mode();
if (p_id == -1) {
@@ -3414,7 +3413,7 @@ void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) {
void TilesetEditorContext::set_snap_options_visible(bool p_visible) {
snap_options_visible = p_visible;
- _change_notify("");
+ notify_property_list_changed();
}
bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) {
@@ -3450,7 +3449,7 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value
tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name2, p_value, &v);
}
if (v) {
- tileset->_change_notify("");
+ tileset->notify_property_list_changed();
tileset_editor->workspace->update();
tileset_editor->workspace_overlay->update();
}
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 5061067ded..acc77bd098 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -353,6 +353,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
bool is_expression = !expression_node.is_null();
String expression = "";
+ VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsnode.ptr());
+ if (custom_node) {
+ custom_node->_set_initialized(true);
+ }
+
GraphNode *node = memnew(GraphNode);
register_link(p_type, p_id, vsnode.ptr(), node);
@@ -384,6 +389,20 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
port_offset += 2;
}
+ if (is_resizable) {
+ Ref<VisualShaderNodeComment> comment_node = Object::cast_to<VisualShaderNodeComment>(vsnode.ptr());
+ if (comment_node.is_valid()) {
+ node->set_comment(true);
+
+ Label *comment_label = memnew(Label);
+ node->add_child(comment_label);
+ comment_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ comment_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ comment_label->set_mouse_filter(Control::MouseFilter::MOUSE_FILTER_STOP);
+ comment_label->set_text(comment_node->get_description());
+ }
+ }
+
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (uniform.is_valid()) {
VisualShaderEditor::get_singleton()->graph->add_child(node);
@@ -1023,7 +1042,7 @@ void VisualShaderEditor::_update_options_menu() {
Color unsupported_color = get_theme_color("error_color", "Editor");
Color supported_color = get_theme_color("warning_color", "Editor");
- static bool low_driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES2";
+ static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES2";
Map<String, TreeItem *> folders;
@@ -1119,16 +1138,24 @@ void VisualShaderEditor::_update_options_menu() {
}
void VisualShaderEditor::_set_mode(int p_which) {
- if (p_which == VisualShader::MODE_PARTICLES) {
+ if (p_which == VisualShader::MODE_SKY) {
+ edit_type_standart->set_visible(false);
+ edit_type_particles->set_visible(false);
+ edit_type_sky->set_visible(true);
+ edit_type = edit_type_sky;
+ mode = MODE_FLAGS_SKY;
+ } else if (p_which == VisualShader::MODE_PARTICLES) {
edit_type_standart->set_visible(false);
edit_type_particles->set_visible(true);
+ edit_type_sky->set_visible(false);
edit_type = edit_type_particles;
- particles_mode = true;
+ mode = MODE_FLAGS_PARTICLES;
} else {
edit_type_particles->set_visible(false);
edit_type_standart->set_visible(true);
+ edit_type_sky->set_visible(false);
edit_type = edit_type_standart;
- particles_mode = false;
+ mode = MODE_FLAGS_SPATIAL_CANVASITEM;
}
visual_shader->set_shader_type(get_current_shader_type());
}
@@ -1289,8 +1316,10 @@ void VisualShaderEditor::_update_graph() {
VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
VisualShader::Type type;
- if (particles_mode) {
+ if (mode & MODE_FLAGS_PARTICLES) {
type = VisualShader::Type(edit_type->get_selected() + 3);
+ } else if (mode & MODE_FLAGS_SKY) {
+ type = VisualShader::Type(edit_type->get_selected() + 6);
} else {
type = VisualShader::Type(edit_type->get_selected());
}
@@ -1624,6 +1653,92 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
undo_redo->commit_action();
}
+void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int p_node_id) {
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
+ if (node.is_null()) {
+ return;
+ }
+ comment_title_change_edit->set_text(node->get_title());
+ comment_title_change_popup->set_meta("id", p_node_id);
+ comment_title_change_popup->popup();
+ comment_title_change_popup->set_position(p_position);
+}
+
+void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
+ comment_title_change_edit->set_size(Size2(-1, -1));
+ comment_title_change_popup->set_size(Size2(-1, -1));
+}
+
+void VisualShaderEditor::_comment_title_text_entered(const String &p_new_text) {
+ comment_title_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_title_popup_focus_out() {
+ comment_title_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_title_popup_hide() {
+ ERR_FAIL_COND(!comment_title_change_popup->has_meta("id"));
+ int node_id = (int)comment_title_change_popup->get_meta("id");
+
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
+
+ ERR_FAIL_COND(node.is_null());
+
+ if (node->get_title() == comment_title_change_edit->get_text()) {
+ return; // nothing changed - ignored
+ }
+ undo_redo->create_action(TTR("Set Comment Node Title"));
+ undo_redo->add_do_method(node.ptr(), "set_title", comment_title_change_edit->get_text());
+ undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->commit_action();
+}
+
+void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int p_node_id) {
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
+ if (node.is_null()) {
+ return;
+ }
+ comment_desc_change_edit->set_text(node->get_description());
+ comment_desc_change_popup->set_meta("id", p_node_id);
+ comment_desc_change_popup->popup();
+ comment_desc_change_popup->set_position(p_position);
+}
+
+void VisualShaderEditor::_comment_desc_text_changed() {
+ comment_desc_change_edit->set_size(Size2(-1, -1));
+ comment_desc_change_popup->set_size(Size2(-1, -1));
+}
+
+void VisualShaderEditor::_comment_desc_confirm() {
+ comment_desc_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_desc_popup_hide() {
+ ERR_FAIL_COND(!comment_desc_change_popup->has_meta("id"));
+ int node_id = (int)comment_desc_change_popup->get_meta("id");
+
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
+
+ ERR_FAIL_COND(node.is_null());
+
+ if (node->get_description() == comment_desc_change_edit->get_text()) {
+ return; // nothing changed - ignored
+ }
+ undo_redo->create_action(TTR("Set Comment Node Description"));
+ undo_redo->add_do_method(node.ptr(), "set_description", comment_desc_change_edit->get_text());
+ undo_redo->add_undo_method(node.ptr(), "set_description", node->get_title());
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->commit_action();
+}
+
void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) {
VisualShader::Type type = get_current_shader_type();
@@ -1672,8 +1787,15 @@ void VisualShaderEditor::_port_edited() {
ERR_FAIL_COND(!vsn.is_valid());
undo_redo->create_action(TTR("Set Input Default Port"));
- undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
- undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+
+ Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
+ if (custom.is_valid()) {
+ undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, value);
+ undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+ } else {
+ undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
+ undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+ }
undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, value);
undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port));
undo_redo->commit_action();
@@ -2504,9 +2626,10 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
VisualShader::Type type = get_current_shader_type();
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
selected_constants.clear();
selected_uniforms.clear();
+ selected_comment = -1;
List<int> to_change;
for (int i = 0; i < graph->get_child_count(); i++) {
@@ -2517,17 +2640,27 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
to_change.push_back(id);
Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
- VisualShaderNodeConstant *cnode = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
- if (cnode != nullptr) {
+
+ VisualShaderNodeComment *comment_node = Object::cast_to<VisualShaderNodeComment>(node.ptr());
+ if (comment_node != nullptr) {
+ selected_comment = id;
+ }
+ VisualShaderNodeConstant *constant_node = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
+ if (constant_node != nullptr) {
selected_constants.insert(id);
}
- VisualShaderNodeUniform *unode = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (unode != nullptr) {
+ VisualShaderNodeUniform *uniform_node = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
+ if (uniform_node != nullptr && uniform_node->is_convertible_to_constant()) {
selected_uniforms.insert(id);
}
}
}
}
+
+ if (to_change.size() > 1) {
+ selected_comment = -1;
+ }
+
if (to_change.is_empty() && copy_nodes_buffer.is_empty()) {
_show_members_dialog(true);
} else {
@@ -2548,16 +2681,34 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (temp != -1) {
popup_menu->remove_item(temp);
}
+ temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR3);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
+ temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_TITLE);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
+ temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_DESCRIPTION);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
- if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ if (selected_comment != -1) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
+ popup_menu->add_item(TTR("Set Comment Title"), NodeMenuOptions::SET_COMMENT_TITLE);
+ popup_menu->add_item(TTR("Set Comment Description"), NodeMenuOptions::SET_COMMENT_DESCRIPTION);
+ }
+
+ if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ popup_menu->add_separator("", NodeMenuOptions::SEPARATOR3);
if (selected_constants.size() > 0) {
popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
}
if (selected_uniforms.size() > 0) {
- popup_menu->add_item(TTR("Convert Uniforms(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ popup_menu->add_item(TTR("Convert Uniform(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
}
}
@@ -2896,7 +3047,14 @@ void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2
}
void VisualShaderEditor::_mode_selected(int p_id) {
- visual_shader->set_shader_type(particles_mode ? VisualShader::Type(p_id + 3) : VisualShader::Type(p_id));
+ int offset = 0;
+ if (mode & MODE_FLAGS_PARTICLES) {
+ offset = 3;
+ } else if (mode & MODE_FLAGS_SKY) {
+ offset = 6;
+ }
+
+ visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
_update_options_menu();
_update_graph();
}
@@ -3111,6 +3269,12 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS:
_convert_constants_to_uniforms(true);
break;
+ case NodeMenuOptions::SET_COMMENT_TITLE:
+ _comment_title_popup_show(get_global_mouse_position(), selected_comment);
+ break;
+ case NodeMenuOptions::SET_COMMENT_DESCRIPTION:
+ _comment_desc_popup_show(get_global_mouse_position(), selected_comment);
+ break;
default:
break;
}
@@ -3263,7 +3427,7 @@ void VisualShaderEditor::_update_preview() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
for (int i = 0; i < preview_text->get_line_count(); i++) {
preview_text->set_line_as_marked(i, false);
@@ -3396,10 +3560,17 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_particles->select(0);
edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+ edit_type_sky = memnew(OptionButton);
+ edit_type_sky->add_item(TTR("Sky"));
+ edit_type_sky->select(0);
+ edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+
edit_type = edit_type_standart;
graph->get_zoom_hbox()->add_child(edit_type_particles);
graph->get_zoom_hbox()->move_child(edit_type_particles, 0);
+ graph->get_zoom_hbox()->add_child(edit_type_sky);
+ graph->get_zoom_hbox()->move_child(edit_type_sky, 0);
graph->get_zoom_hbox()->add_child(edit_type_standart);
graph->get_zoom_hbox()->move_child(edit_type_standart, 0);
@@ -3534,6 +3705,35 @@ VisualShaderEditor::VisualShaderEditor() {
alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
add_child(alert);
+ comment_title_change_popup = memnew(PopupPanel);
+ comment_title_change_edit = memnew(LineEdit);
+ comment_title_change_edit->set_expand_to_text_length_enabled(true);
+ comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
+ comment_title_change_edit->connect("text_entered", callable_mp(this, &VisualShaderEditor::_comment_title_text_entered));
+ comment_title_change_popup->add_child(comment_title_change_edit);
+ comment_title_change_edit->set_size(Size2(-1, -1));
+ comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out));
+ comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide));
+ add_child(comment_title_change_popup);
+
+ comment_desc_change_popup = memnew(PopupPanel);
+ VBoxContainer *comment_desc_vbox = memnew(VBoxContainer);
+ comment_desc_change_popup->add_child(comment_desc_vbox);
+ comment_desc_change_edit = memnew(TextEdit);
+ comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed));
+ comment_desc_vbox->add_child(comment_desc_change_edit);
+ comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE));
+ comment_desc_change_edit->set_size(Size2(-1, -1));
+ comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
+ comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide));
+ Button *comment_desc_confirm_button = memnew(Button);
+ comment_desc_confirm_button->set_text(TTR("OK"));
+ comment_desc_vbox->add_child(comment_desc_confirm_button);
+ comment_desc_confirm_button->connect("pressed", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
+ add_child(comment_desc_change_popup);
+
///////////////////////////////////////
// SHADER NODES TREE OPTIONS
///////////////////////////////////////
@@ -3618,6 +3818,7 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.");
const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.");
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
+ const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.");
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
const String input_param_for_emit_shader_mode = TTR("'%s' input parameter for emit shader mode.");
@@ -3747,35 +3948,35 @@ VisualShaderEditor::VisualShaderEditor() {
// SKY INPUTS
- add_options.push_back(AddOption("AtCubeMapPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtHalfResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtQuarterResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("EyeDir", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Position", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Radiance", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("SkyCoords", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Time", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtHalfResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtQuarterResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("EyeDir", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Position", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Radiance", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
// SCALAR
@@ -3971,6 +4172,7 @@ VisualShaderEditor::VisualShaderEditor() {
// SPECIAL
+ add_options.push_back(AddOption("Comment", "Special", "", "VisualShaderNodeComment", TTR("A rectangular area with a description string for better graph organization.")));
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 182bed6ba6..6d57d38cab 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -67,7 +67,7 @@ private:
VisualShader::Type type = VisualShader::Type::TYPE_MAX;
VisualShaderNode *visual_node = nullptr;
GraphNode *graph_node = nullptr;
- bool preview_visible = 0;
+ bool preview_visible = false;
int preview_pos = 0;
Map<int, InputPort> input_ports;
Map<int, Port> output_ports;
@@ -141,6 +141,7 @@ class VisualShaderEditor : public VBoxContainer {
OptionButton *edit_type = nullptr;
OptionButton *edit_type_standart;
OptionButton *edit_type_particles;
+ OptionButton *edit_type_sky;
PanelContainer *error_panel;
Label *error_label;
@@ -161,9 +162,22 @@ class VisualShaderEditor : public VBoxContainer {
PopupMenu *popup_menu;
MenuButton *tools;
+ PopupPanel *comment_title_change_popup = nullptr;
+ LineEdit *comment_title_change_edit = nullptr;
+
+ PopupPanel *comment_desc_change_popup = nullptr;
+ TextEdit *comment_desc_change_edit = nullptr;
+
bool preview_first = true;
bool preview_showed = false;
- bool particles_mode;
+
+ enum ShaderModeFlags {
+ MODE_FLAGS_SPATIAL_CANVASITEM = 1,
+ MODE_FLAGS_SKY = 2,
+ MODE_FLAGS_PARTICLES = 4
+ };
+
+ int mode = MODE_FLAGS_SPATIAL_CANVASITEM;
enum TypeFlags {
TYPE_FLAGS_VERTEX = 1,
@@ -177,6 +191,10 @@ class VisualShaderEditor : public VBoxContainer {
TYPE_FLAGS_END = 4
};
+ enum SkyTypeFlags {
+ TYPE_FLAGS_SKY = 1,
+ };
+
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL
@@ -192,6 +210,9 @@ class VisualShaderEditor : public VBoxContainer {
SEPARATOR2, // ignore
CONVERT_CONSTANTS_TO_UNIFORMS,
CONVERT_UNIFORMS_TO_CONSTANTS,
+ SEPARATOR3, // ignore
+ SET_COMMENT_TITLE,
+ SET_COMMENT_DESCRIPTION,
};
Tree *members;
@@ -325,6 +346,7 @@ class VisualShaderEditor : public VBoxContainer {
Set<int> selected_constants;
Set<int> selected_uniforms;
+ int selected_comment = -1;
void _convert_constants_to_uniforms(bool p_vice_versa);
void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to);
@@ -334,6 +356,17 @@ class VisualShaderEditor : public VBoxContainer {
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
+ void _comment_title_popup_show(const Point2 &p_position, int p_node_id);
+ void _comment_title_popup_hide();
+ void _comment_title_popup_focus_out();
+ void _comment_title_text_changed(const String &p_new_text);
+ void _comment_title_text_entered(const String &p_new_text);
+
+ void _comment_desc_popup_show(const Point2 &p_position, int p_node_id);
+ void _comment_desc_popup_hide();
+ void _comment_desc_confirm();
+ void _comment_desc_text_changed();
+
void _uniform_line_edit_changed(const String &p_text, int p_node_id);
void _uniform_line_edit_focus_out(Object *line_edit, int p_node_id);
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 2d65c00a89..b58b7e4cac 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -39,7 +39,7 @@ POTGenerator *POTGenerator::singleton = nullptr;
#ifdef DEBUG_POT
void POTGenerator::_print_all_translation_strings() {
- for (auto E = all_translation_strings.front(); E; E = E.next()) {
+ for (OrderedHashMap<String, Vector<POTGenerator::MsgidData>>::Element E = all_translation_strings.front(); E; E = E.next()) {
Vector<MsgidData> v_md = all_translation_strings[E.key()];
for (int i = 0; i < v_md.size(); i++) {
print_line("++++++");
@@ -55,7 +55,7 @@ void POTGenerator::_print_all_translation_strings() {
#endif
void POTGenerator::generate_pot(const String &p_file) {
- if (!ProjectSettings::get_singleton()->has_setting("locale/translations_pot_files")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translations_pot_files")) {
WARN_PRINT("No files selected for POT generation.");
return;
}
@@ -63,7 +63,7 @@ void POTGenerator::generate_pot(const String &p_file) {
// Clear all_translation_strings of the previous round.
all_translation_strings.clear();
- Vector<String> files = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ Vector<String> files = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
// Collect all translatable strings according to files order in "POT Generation" setting.
for (int i = 0; i < files.size(); i++) {
@@ -100,7 +100,7 @@ void POTGenerator::_write_to_pot(const String &p_file) {
}
String project_name = ProjectSettings::get_singleton()->get("application/config/name");
- Vector<String> files = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ Vector<String> files = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
String extracted_files = "";
for (int i = 0; i < files.size(); i++) {
extracted_files += "# " + files[i] + "\n";
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 4bcb616fbd..3ede50320a 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -37,7 +37,7 @@
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "editor_data.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -1082,6 +1082,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_filter->add_item(TTR("Export all resources in the project"));
export_filter->add_item(TTR("Export selected scenes (and dependencies)"));
export_filter->add_item(TTR("Export selected resources (and dependencies)"));
+ export_filter->add_item(TTR("Export all resources in the project except resources checked below"));
resources_vb->add_margin_child(TTR("Export Mode:"), export_filter);
export_filter->connect("item_selected", callable_mp(this, &ProjectExportDialog::_export_type_changed));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index afbed0c610..e51e8ee82e 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -100,6 +100,7 @@ private:
FileDialog *fdialog_install;
String zip_path;
String zip_title;
+ String zip_root;
AcceptDialog *dialog_error;
String fav_dir;
@@ -200,7 +201,9 @@ private:
char fname[16384];
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
- if (String(fname).ends_with("project.godot")) {
+ String fname_str = String(fname);
+ if (fname_str.ends_with("project.godot")) {
+ zip_root = fname_str.substr(0, fname_str.rfind("project.godot"));
break;
}
@@ -293,7 +296,7 @@ private:
String sp = _test_path();
if (sp != "") {
// If the project name is empty or default, infer the project name from the selected folder name
- if (project_name->get_text() == "" || project_name->get_text() == TTR("New Game Project")) {
+ if (project_name->get_text().strip_edges() == "" || project_name->get_text().strip_edges() == TTR("New Game Project")) {
sp = sp.replace("\\", "/");
int lidx = sp.rfind("/");
@@ -377,16 +380,17 @@ private:
}
void _create_folder() {
- if (project_name->get_text() == "" || created_folder_path != "" || project_name->get_text().ends_with(".") || project_name->get_text().ends_with(" ")) {
- set_message(TTR("Invalid Project Name."), MESSAGE_WARNING);
+ const String project_name_no_edges = project_name->get_text().strip_edges();
+ if (project_name_no_edges == "" || created_folder_path != "" || project_name_no_edges.ends_with(".")) {
+ set_message(TTR("Invalid project name."), MESSAGE_WARNING);
return;
}
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (d->change_dir(project_path->get_text()) == OK) {
- if (!d->dir_exists(project_name->get_text())) {
- if (d->make_dir(project_name->get_text()) == OK) {
- d->change_dir(project_name->get_text());
+ if (!d->dir_exists(project_name_no_edges)) {
+ if (d->make_dir(project_name_no_edges) == OK) {
+ d->change_dir(project_name_no_edges);
String dir_str = d->get_current_dir();
project_path->set_text(dir_str);
_path_text_changed(dir_str);
@@ -412,7 +416,7 @@ private:
_test_path();
- if (p_text == "") {
+ if (p_text.strip_edges() == "") {
set_message(TTR("It would be a good idea to name your project."), MESSAGE_ERROR);
}
}
@@ -439,7 +443,7 @@ private:
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR);
} else {
ProjectSettings::CustomMap edited_settings;
- edited_settings["application/config/name"] = project_name->get_text();
+ edited_settings["application/config/name"] = project_name->get_text().strip_edges();
if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
@@ -474,20 +478,20 @@ private:
}
ProjectSettings::CustomMap initial_settings;
if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "Vulkan") {
- initial_settings["rendering/quality/driver/driver_name"] = "Vulkan";
+ initial_settings["rendering/driver/driver_name"] = "Vulkan";
} else {
- initial_settings["rendering/quality/driver/driver_name"] = "GLES2";
- initial_settings["rendering/vram_compression/import_etc2"] = false;
- initial_settings["rendering/vram_compression/import_etc"] = true;
+ initial_settings["rendering/driver/driver_name"] = "GLES2";
+ initial_settings["rendering/textures/vram_compression/import_etc2"] = false;
+ initial_settings["rendering/textures/vram_compression/import_etc"] = true;
}
- initial_settings["application/config/name"] = project_name->get_text();
+ initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
- initial_settings["rendering/environment/default_environment"] = "res://default_env.tres";
+ initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
- ResourceSaver::save(dir.plus_file("icon.png"), msg->get_theme_icon("DefaultProjectIcon", "EditorIcons"));
+ ResourceSaver::save(dir.plus_file("icon.png"), create_unscaled_default_project_icon());
FileAccess *f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
if (!f) {
@@ -533,44 +537,34 @@ private:
String path = fname;
- int depth = 1; //stuff from github comes with tag
- bool skip = false;
- while (depth > 0) {
- int pp = path.find("/");
- if (pp == -1) {
- skip = true;
- break;
- }
- path = path.substr(pp + 1, path.length());
- depth--;
- }
-
- if (skip || path == String()) {
+ if (path == String() || path == zip_root || !zip_root.is_subsequence_of(path)) {
//
} else if (path.ends_with("/")) { // a dir
path = path.substr(0, path.length() - 1);
+ String rel_path = path.substr(zip_root.length());
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->make_dir(dir.plus_file(path));
+ da->make_dir(dir.plus_file(rel_path));
memdelete(da);
} else {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
+ String rel_path = path.substr(zip_root.length());
//read
unzOpenCurrentFile(pkg);
unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
- FileAccess *f = FileAccess::open(dir.plus_file(path), FileAccess::WRITE);
+ FileAccess *f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE);
if (f) {
f->store_buffer(data.ptr(), data.size());
memdelete(f);
} else {
- failed_files.push_back(path);
+ failed_files.push_back(rel_path);
}
}
@@ -1038,7 +1032,7 @@ public:
int get_project_count() const;
void select_project(int p_index);
void select_first_visible_project();
- void erase_selected_projects();
+ void erase_selected_projects(bool p_delete_project_contents);
Vector<Item> get_selected_projects() const;
const Set<String> &get_selected_project_keys() const;
void ensure_project_visible(int p_index);
@@ -1693,7 +1687,7 @@ void ProjectList::toggle_select(int p_index) {
item.control->update();
}
-void ProjectList::erase_selected_projects() {
+void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
if (_selected_project_keys.size() == 0) {
return;
}
@@ -1704,6 +1698,10 @@ void ProjectList::erase_selected_projects() {
EditorSettings::get_singleton()->erase("projects/" + item.project_key);
EditorSettings::get_singleton()->erase("favorite_projects/" + item.project_key);
+ if (p_delete_project_contents) {
+ OS::get_singleton()->move_to_trash(item.path);
+ }
+
memdelete(item.control);
_projects.remove(i);
--i;
@@ -1741,7 +1739,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
int clicked_index = p_hb->get_index();
const Item &clicked_project = _projects[clicked_index];
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->get_shift() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
int anchor_index = -1;
for (int i = 0; i < _projects.size(); ++i) {
@@ -1854,6 +1852,9 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_WM_CLOSE_REQUEST: {
_dim_window();
} break;
+ case NOTIFICATION_WM_ABOUT: {
+ _show_about();
+ } break;
}
}
@@ -1889,6 +1890,8 @@ void ProjectManager::_update_project_buttons() {
}
void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (k.is_valid()) {
@@ -2015,6 +2018,10 @@ void ProjectManager::_confirm_update_settings() {
}
void ProjectManager::_open_selected_projects() {
+ // Show loading text to tell the user that the project manager is busy loading.
+ // This is especially important for the HTML5 project manager.
+ loading_label->set_modulate(Color(1, 1, 1));
+
const Set<String> &selected_list = _project_list->get_selected_project_keys();
for (const Set<String>::Element *E = selected_list.front(); E; E = E->next()) {
@@ -2218,7 +2225,7 @@ void ProjectManager::_rename_project() {
}
void ProjectManager::_erase_project_confirm() {
- _project_list->erase_selected_projects();
+ _project_list->erase_selected_projects(delete_project_contents->is_pressed());
_update_project_buttons();
}
@@ -2236,12 +2243,13 @@ void ProjectManager::_erase_project() {
String confirm_message;
if (selected_list.size() >= 2) {
- confirm_message = vformat(TTR("Remove %d projects from the list?\nThe project folders' contents won't be modified."), selected_list.size());
+ confirm_message = vformat(TTR("Remove %d projects from the list?"), selected_list.size());
} else {
- confirm_message = TTR("Remove this project from the list?\nThe project folder's contents won't be modified.");
+ confirm_message = TTR("Remove this project from the list?");
}
- erase_ask->set_text(confirm_message);
+ erase_ask_label->set_text(confirm_message);
+ delete_project_contents->set_pressed(false);
erase_ask->popup_centered();
}
@@ -2250,6 +2258,10 @@ void ProjectManager::_erase_missing_projects() {
erase_missing_ask->popup_centered();
}
+void ProjectManager::_show_about() {
+ about->popup_centered(Size2(780, 500) * EDSCALE);
+}
+
void ProjectManager::_language_selected(int p_id) {
String lang = language_btn->get_item_metadata(p_id);
EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
@@ -2268,11 +2280,6 @@ void ProjectManager::_restart_confirm() {
get_tree()->quit();
}
-void ProjectManager::_exit_dialog() {
- _dim_window();
- get_tree()->quit();
-}
-
void ProjectManager::_install_project(const String &p_zip_path, const String &p_title) {
npdialog->set_mode(ProjectDialog::MODE_INSTALL);
npdialog->set_zip_path(p_zip_path);
@@ -2339,6 +2346,17 @@ void ProjectManager::_on_order_option_changed(int p_idx) {
}
}
+void ProjectManager::_on_tab_changed(int p_tab) {
+ if (p_tab == 0) { // Projects
+ // Automatically grab focus when the user moves from the Templates tab
+ // back to the Projects tab.
+ search_box->grab_focus();
+ }
+
+ // The Templates tab's search field is focused on display in the asset
+ // library editor plugin code.
+}
+
void ProjectManager::_on_search_term_changed(const String &p_term) {
_project_list->set_search_term(p_term);
_project_list->sort_projects();
@@ -2351,7 +2369,6 @@ void ProjectManager::_on_search_term_changed(const String &p_term) {
}
void ProjectManager::_bind_methods() {
- ClassDB::bind_method("_exit_dialog", &ProjectManager::_exit_dialog);
ClassDB::bind_method("_unhandled_key_input", &ProjectManager::_unhandled_key_input);
ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons);
}
@@ -2385,6 +2402,10 @@ ProjectManager::ProjectManager() {
if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
// hiDPI display.
scale = 2.0;
+ } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
+ // Likely a hiDPI display, but we aren't certain due to the returned DPI.
+ // Use an intermediate scale to handle this situation.
+ scale = 1.5;
} else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
// Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
// Icons won't look great, but this is better than having editor elements overflow from its window.
@@ -2423,17 +2444,14 @@ ProjectManager::ProjectManager() {
// Define a minimum window size to prevent UI elements from overlapping or being cut off
DisplayServer::get_singleton()->window_set_min_size(Size2(750, 420) * EDSCALE);
- // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
- DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
+ // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the lines below
+ float scale_factor = MAX(1, EDSCALE);
+ Vector2i window_size = DisplayServer::get_singleton()->window_get_size();
+ DisplayServer::get_singleton()->window_set_size(Vector2i(window_size.x * scale_factor, window_size.y * scale_factor));
}
// TRANSLATORS: This refers to the application where users manage their Godot projects.
- if (TS->is_locale_right_to_left(TranslationServer::get_singleton()->get_tool_locale())) {
- // For RTL languages, embed translated part of the title (using control characters) to ensure correct order.
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + String::chr(0x202B) + TTR("Project Manager") + String::chr(0x202C) + String::chr(0x200E) + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- } else {
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- }
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager"));
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -2459,6 +2477,7 @@ ProjectManager::ProjectManager() {
center_box->add_child(tabs);
tabs->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
+ tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
HBoxContainer *projects_hb = memnew(HBoxContainer);
projects_hb->set_name(TTR("Projects"));
@@ -2475,13 +2494,18 @@ ProjectManager::ProjectManager() {
search_tree_vb->add_child(hb);
search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Search"));
- search_box->set_tooltip(TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+ search_box->set_placeholder(TTR("Filter projects"));
+ search_box->set_tooltip(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(search_box);
- hb->add_spacer();
+ loading_label = memnew(Label(TTR("Loading, please wait...")));
+ loading_label->add_theme_font_override("font", get_theme_font("bold", "EditorFonts"));
+ loading_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->add_child(loading_label);
+ // Hide the label but make it still take up space. This prevents reflows when showing the label.
+ loading_label->set_modulate(Color(0, 0, 0, 0));
Label *sort_label = memnew(Label);
sort_label->set_text(TTR("Sort:"));
@@ -2561,6 +2585,13 @@ ProjectManager::ProjectManager() {
erase_missing_btn->set_text(TTR("Remove Missing"));
erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
tree_vb->add_child(erase_missing_btn);
+
+ tree_vb->add_spacer();
+
+ about_btn = memnew(Button);
+ about_btn->set_text(TTR("About"));
+ about_btn->connect("pressed", callable_mp(this, &ProjectManager::_show_about));
+ tree_vb->add_child(about_btn);
}
{
@@ -2649,6 +2680,16 @@ ProjectManager::ProjectManager() {
erase_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
add_child(erase_ask);
+ VBoxContainer *erase_ask_vb = memnew(VBoxContainer);
+ erase_ask->add_child(erase_ask_vb);
+
+ erase_ask_label = memnew(Label);
+ erase_ask_vb->add_child(erase_ask_label);
+
+ delete_project_contents = memnew(CheckBox);
+ delete_project_contents->set_text(TTR("Also delete project contents (no undo!)"));
+ erase_ask_vb->add_child(delete_project_contents);
+
multi_open_ask = memnew(ConfirmationDialog);
multi_open_ask->get_ok_button()->set_text(TTR("Edit"));
multi_open_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
@@ -2684,6 +2725,9 @@ ProjectManager::ProjectManager() {
open_templates->get_ok_button()->set_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
add_child(open_templates);
+
+ about = memnew(EditorAbout);
+ add_child(about);
}
_load_recent_projects();
diff --git a/editor/project_manager.h b/editor/project_manager.h
index db8cb8410c..a66b7c4ab6 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -31,6 +31,7 @@
#ifndef PROJECT_MANAGER_H
#define PROJECT_MANAGER_H
+#include "editor/editor_about.h"
#include "editor/plugins/asset_library_editor_plugin.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
@@ -54,6 +55,7 @@ class ProjectManager : public Control {
ProjectList *_project_list;
LineEdit *search_box;
+ Label *loading_label;
OptionButton *filter_option;
Button *run_btn;
@@ -61,18 +63,24 @@ class ProjectManager : public Control {
Button *rename_btn;
Button *erase_btn;
Button *erase_missing_btn;
+ Button *about_btn;
EditorAssetLibrary *asset_library;
FileDialog *scan_dir;
ConfirmationDialog *language_restart_ask;
+
ConfirmationDialog *erase_ask;
+ Label *erase_ask_label;
+ CheckBox *delete_project_contents;
+
ConfirmationDialog *erase_missing_ask;
ConfirmationDialog *multi_open_ask;
ConfirmationDialog *multi_run_ask;
ConfirmationDialog *multi_scan_ask;
ConfirmationDialog *ask_update_settings;
ConfirmationDialog *open_templates;
+ EditorAbout *about;
HBoxContainer *settings_hb;
@@ -95,10 +103,10 @@ class ProjectManager : public Control {
void _erase_missing_projects();
void _erase_project_confirm();
void _erase_missing_projects_confirm();
+ void _show_about();
void _update_project_buttons();
void _language_selected(int p_id);
void _restart_confirm();
- void _exit_dialog();
void _confirm_update_settings();
void _nonempty_confirmation_ok_pressed();
@@ -116,6 +124,7 @@ class ProjectManager : public Control {
void _files_dropped(PackedStringArray p_files, int p_screen);
void _on_order_option_changed(int p_idx);
+ void _on_tab_changed(int p_tab);
void _on_search_term_changed(const String &p_term);
protected:
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 4516180fa5..faec3355ac 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -52,9 +52,11 @@ void ProjectSettingsEditor::popup_project_settings() {
localization_editor->update_translations();
autoload_settings->update_autoload();
plugin_settings->update_plugins();
+ import_defaults_editor->clear();
}
void ProjectSettingsEditor::queue_save() {
+ EditorNode::get_singleton()->notify_settings_changed();
timer->start();
}
@@ -74,8 +76,12 @@ void ProjectSettingsEditor::_advanced_pressed() {
if (advanced->is_pressed()) {
_update_advanced_bar();
advanced_bar->show();
+ EditorSettings::get_singleton()->set_project_metadata("project_settings", "advanced_mode", true);
+ inspector->set_restrict_to_basic_settings(false);
} else {
advanced_bar->hide();
+ EditorSettings::get_singleton()->set_project_metadata("project_settings", "advanced_mode", false);
+ inspector->set_restrict_to_basic_settings(true);
}
}
@@ -96,10 +102,9 @@ void ProjectSettingsEditor::_add_setting() {
String setting = _get_setting_name();
// Initialize the property with the default value for the given type.
- // The type list starts at 1 (as we exclude Nil), so add 1 to the selected value.
Callable::CallError ce;
Variant value;
- Variant::construct(Variant::Type(type->get_selected() + 1), value, nullptr, 0, ce);
+ Variant::construct(Variant::Type(type->get_selected_id()), value, nullptr, 0, ce);
undo_redo->create_action(TTR("Add Project Setting"));
undo_redo->add_do_property(ps, setting, value);
@@ -190,9 +195,6 @@ void ProjectSettingsEditor::_update_advanced_bar() {
add_button->set_disabled(disable_add);
del_button->set_disabled(disable_del);
-
- error_label->set_text(error_msg);
- error_label->set_visible(error_msg != "");
}
String ProjectSettingsEditor::_get_setting_name() const {
@@ -255,6 +257,7 @@ void ProjectSettingsEditor::_add_feature_overrides() {
}
void ProjectSettingsEditor::_editor_restart() {
+ ProjectSettings::get_singleton()->save();
EditorNode::get_singleton()->save_all_scenes();
EditorNode::get_singleton()->restart_editor();
}
@@ -267,21 +270,216 @@ void ProjectSettingsEditor::_editor_restart_close() {
restart_container->hide();
}
+void ProjectSettingsEditor::_action_added(const String &p_name) {
+ String name = "input/" + p_name;
+
+ if (ProjectSettings::get_singleton()->has_setting(name)) {
+ action_map->show_message(vformat(TTR("An action with the name '%s' already exists."), name));
+ return;
+ }
+
+ Dictionary action;
+ action["events"] = Array();
+ action["deadzone"] = 0.5f;
+
+ undo_redo->create_action(TTR("Add Input Action"));
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name);
+
+ undo_redo->add_do_method(this, "_update_action_map_editor");
+ undo_redo->add_undo_method(this, "_update_action_map_editor");
+ undo_redo->add_do_method(this, "queue_save");
+ undo_redo->add_undo_method(this, "queue_save");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionary &p_action) {
+ const String property_name = "input/" + p_name;
+ Dictionary old_val = ProjectSettings::get_singleton()->get(property_name);
+
+ if (old_val["deadzone"] != p_action["deadzone"]) {
+ // Deadzone Changed
+ undo_redo->create_action(TTR("Change Action deadzone"));
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", property_name, p_action);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val);
+
+ } else {
+ // Events changed
+ int event_count = ((Array)p_action["events"]).size();
+ int old_event_count = ((Array)old_val["events"]).size();
+
+ if (event_count == old_event_count) {
+ undo_redo->create_action(TTR("Edit Input Action Event"));
+ } else if (event_count > old_event_count) {
+ undo_redo->create_action(TTR("Add Input Action Event"));
+ } else if (event_count < old_event_count) {
+ undo_redo->create_action(TTR("Remove Input Action Event"));
+ }
+
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", property_name, p_action);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val);
+ }
+
+ undo_redo->add_do_method(this, "_update_action_map_editor");
+ undo_redo->add_undo_method(this, "_update_action_map_editor");
+ undo_redo->add_do_method(this, "queue_save");
+ undo_redo->add_undo_method(this, "queue_save");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_action_removed(const String &p_name) {
+ const String property_name = "input/" + p_name;
+
+ Dictionary old_val = ProjectSettings::get_singleton()->get(property_name);
+ int order = ProjectSettings::get_singleton()->get_order(property_name);
+
+ undo_redo->create_action(TTR("Erase Input Action"));
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property_name);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", property_name, order);
+
+ undo_redo->add_do_method(this, "_update_action_map_editor");
+ undo_redo->add_undo_method(this, "_update_action_map_editor");
+ undo_redo->add_do_method(this, "queue_save");
+ undo_redo->add_undo_method(this, "queue_save");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_action_renamed(const String &p_old_name, const String &p_new_name) {
+ const String old_property_name = "input/" + p_old_name;
+ const String new_property_name = "input/" + p_new_name;
+
+ if (ProjectSettings::get_singleton()->has_setting(new_property_name)) {
+ action_map->show_message(vformat(TTR("An action with the name '%s' already exists."), new_property_name));
+ return;
+ }
+
+ int order = ProjectSettings::get_singleton()->get_order(old_property_name);
+ Dictionary action = ProjectSettings::get_singleton()->get(old_property_name);
+
+ undo_redo->create_action(TTR("Rename Input Action Event"));
+ // Do: clear old, set new
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", old_property_name);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", new_property_name, action);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", new_property_name, order);
+ // Undo: clear new, set old
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", new_property_name);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", old_property_name, action);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", old_property_name, order);
+
+ undo_redo->add_do_method(this, "_update_action_map_editor");
+ undo_redo->add_undo_method(this, "_update_action_map_editor");
+ undo_redo->add_do_method(this, "queue_save");
+ undo_redo->add_undo_method(this, "queue_save");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const String &p_relative_to, bool p_before) {
+ const String action_name = "input/" + p_action_name;
+ const String target_name = "input/" + p_relative_to;
+
+ // It is much easier to rebuild the custom "input" properties rather than messing around with the "order" values of them.
+ Variant action_value = ps->get(action_name);
+ Variant target_value = ps->get(target_name);
+
+ List<PropertyInfo> props;
+ OrderedHashMap<String, Variant> action_values;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+
+ undo_redo->create_action(TTR("Update Input Action Order"));
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ PropertyInfo prop = E->get();
+ // Skip builtins and non-inputs
+ if (ProjectSettings::get_singleton()->is_builtin_setting(prop.name) || !prop.name.begins_with("input/")) {
+ continue;
+ }
+
+ action_values.insert(prop.name, ps->get(prop.name));
+
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", prop.name);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", prop.name);
+ }
+
+ for (OrderedHashMap<String, Variant>::Element E = action_values.front(); E; E = E.next()) {
+ String name = E.key();
+ Variant value = E.get();
+
+ if (name == target_name) {
+ if (p_before) {
+ // Insert before target
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_name, action_value);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", target_name, target_value);
+
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", target_name, target_value);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", action_name, action_value);
+ } else {
+ // Insert after target
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", target_name, target_value);
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", action_name, action_value);
+
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", action_name, action_value);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", target_name, target_value);
+ }
+
+ } else if (name != action_name) {
+ undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, value);
+ undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, value);
+ }
+ }
+
+ undo_redo->add_do_method(this, "_update_action_map_editor");
+ undo_redo->add_undo_method(this, "_update_action_map_editor");
+ undo_redo->add_do_method(this, "queue_save");
+ undo_redo->add_undo_method(this, "queue_save");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_update_action_map_editor() {
+ Vector<ActionMapEditor::ActionInfo> actions;
+
+ List<PropertyInfo> props;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+
+ const Ref<Texture2D> builtin_icon = get_theme_icon("PinPressed", "EditorIcons");
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ const String property_name = E->get().name;
+
+ if (!property_name.begins_with("input/")) {
+ continue;
+ }
+
+ // Strip the "input/" from the left.
+ String display_name = property_name.substr(String("input/").size() - 1);
+ Dictionary action = ProjectSettings::get_singleton()->get(property_name);
+
+ ActionMapEditor::ActionInfo action_info;
+ action_info.action = action;
+ action_info.editable = true;
+ action_info.name = display_name;
+
+ const bool is_builtin_input = ProjectSettings::get_singleton()->get_input_presets().find(property_name) != nullptr;
+ if (is_builtin_input) {
+ action_info.editable = false;
+ action_info.icon = builtin_icon;
+ }
+
+ actions.push_back(action_info);
+ }
+
+ action_map->update_action_list(actions);
+}
+
void ProjectSettingsEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", Rect2(get_position(), get_size()));
- if (advanced->is_pressed()) {
- advanced->set_pressed(false);
- advanced_bar->hide();
- }
}
} break;
case NOTIFICATION_ENTER_TREE: {
inspector->edit(ps);
- error_label->add_theme_color_override("font_color", error_label->get_theme_color("error_color", "Editor"));
add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
del_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
@@ -292,6 +490,8 @@ void ProjectSettingsEditor::_notification(int p_what) {
restart_container->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
restart_icon->set_texture(get_theme_icon("StatusWarning", "EditorIcons"));
restart_label->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
+
+ _update_action_map_editor();
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
@@ -302,6 +502,8 @@ void ProjectSettingsEditor::_notification(int p_what) {
void ProjectSettingsEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("queue_save"), &ProjectSettingsEditor::queue_save);
+
+ ClassDB::bind_method(D_METHOD("_update_action_map_editor"), &ProjectSettingsEditor::_update_action_map_editor);
}
ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
@@ -339,23 +541,19 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
search_bar->add_child(search_box);
advanced = memnew(CheckButton);
- advanced->set_text(TTR("Advanced"));
+ advanced->set_text(TTR("Advanced Settings"));
advanced->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_advanced_pressed));
search_bar->add_child(advanced);
}
{
// Advanced bar.
- advanced_bar = memnew(VBoxContainer);
- advanced_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ advanced_bar = memnew(HBoxContainer);
advanced_bar->hide();
header->add_child(advanced_bar);
- advanced_bar->add_child(memnew(HSeparator));
-
- HBoxContainer *hbc = memnew(HBoxContainer);
+ HBoxContainer *hbc = advanced_bar;
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- advanced_bar->add_margin_child(TTR("Add or Remove Custom Project Settings:"), hbc, true);
category_box = memnew(LineEdit);
category_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -364,7 +562,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
hbc->add_child(category_box);
Label *l = memnew(Label);
- l->set_text("/");
+ l->set_text(" / ");
hbc->add_child(l);
property_box = memnew(LineEdit);
@@ -385,7 +583,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
// There's no point in adding Nil types, and Object types
// can't be serialized correctly in the project settings.
if (i != Variant::NIL && i != Variant::OBJECT) {
- type->add_item(Variant::get_type_name(Variant::Type(i)));
+ type->add_item(Variant::get_type_name(Variant::Type(i)), i);
}
}
@@ -407,9 +605,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
del_button->set_flat(true);
del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(false));
hbc->add_child(del_button);
-
- error_label = memnew(Label);
- advanced_bar->add_child(error_label);
}
inspector = memnew(SectionedInspector);
@@ -447,10 +642,16 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
restart_close_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_editor_restart_close));
restart_hb->add_child(restart_close_button);
- inputmap_editor = memnew(InputMapEditor);
- inputmap_editor->set_name(TTR("Input Map"));
- inputmap_editor->connect("inputmap_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
- tab_container->add_child(inputmap_editor);
+ action_map = memnew(ActionMapEditor);
+ action_map->set_name(TTR("Input Map"));
+ action_map->connect("action_added", callable_mp(this, &ProjectSettingsEditor::_action_added));
+ action_map->connect("action_edited", callable_mp(this, &ProjectSettingsEditor::_action_edited));
+ action_map->connect("action_removed", callable_mp(this, &ProjectSettingsEditor::_action_removed));
+ action_map->connect("action_renamed", callable_mp(this, &ProjectSettingsEditor::_action_renamed));
+ action_map->connect("action_reordered", callable_mp(this, &ProjectSettingsEditor::_action_reordered));
+ action_map->set_toggle_editable_label(TTR("Show Built-in Actions"));
+ action_map->set_show_uneditable(false);
+ tab_container->add_child(action_map);
localization_editor = memnew(LocalizationEditor);
localization_editor->set_name(TTR("Localization"));
@@ -483,4 +684,18 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
get_ok_button()->set_text(TTR("Close"));
set_hide_on_ok(true);
+
+ bool use_advanced = EditorSettings::get_singleton()->get_project_metadata("project_settings", "advanced_mode", false);
+
+ if (use_advanced) {
+ advanced->set_pressed(true);
+ advanced_bar->show();
+ }
+
+ inspector->set_restrict_to_basic_settings(!use_advanced);
+
+ import_defaults_editor = memnew(ImportDefaultsEditor);
+ import_defaults_editor->set_name(TTR("Import Defaults"));
+ tab_container->add_child(import_defaults_editor);
+ import_defaults_editor->connect("project_settings_changed", callable_mp(this, &ProjectSettingsEditor::queue_save));
}
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 88c96540ff..cde46ac4c4 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -32,10 +32,11 @@
#define PROJECT_SETTINGS_EDITOR_H
#include "core/object/undo_redo.h"
+#include "editor/action_map_editor.h"
#include "editor/editor_data.h"
#include "editor/editor_plugin_settings.h"
#include "editor/editor_sectioned_inspector.h"
-#include "editor/input_map_editor.h"
+#include "editor/import_defaults_editor.h"
#include "editor/localization_editor.h"
#include "editor/shader_globals_editor.h"
#include "editor_autoload_settings.h"
@@ -44,38 +45,29 @@
class ProjectSettingsEditor : public AcceptDialog {
GDCLASS(ProjectSettingsEditor, AcceptDialog);
- enum InputType {
- INPUT_KEY,
- INPUT_KEY_PHYSICAL,
- INPUT_JOY_BUTTON,
- INPUT_JOY_MOTION,
- INPUT_MOUSE_BUTTON
- };
-
static ProjectSettingsEditor *singleton;
ProjectSettings *ps;
Timer *timer;
TabContainer *tab_container;
SectionedInspector *inspector;
- InputMapEditor *inputmap_editor;
LocalizationEditor *localization_editor;
EditorAutoloadSettings *autoload_settings;
ShaderGlobalsEditor *shaders_global_variables_editor;
EditorPluginSettings *plugin_settings;
+ ActionMapEditor *action_map;
HBoxContainer *search_bar;
LineEdit *search_box;
CheckButton *advanced;
- VBoxContainer *advanced_bar;
+ HBoxContainer *advanced_bar;
LineEdit *category_box;
LineEdit *property_box;
Button *add_button;
Button *del_button;
OptionButton *type;
OptionButton *feature_override;
- Label *error_label;
ConfirmationDialog *del_confirmation;
@@ -84,6 +76,7 @@ class ProjectSettingsEditor : public AcceptDialog {
PanelContainer *restart_container;
Button *restart_close_button;
+ ImportDefaultsEditor *import_defaults_editor;
EditorData *data;
UndoRedo *undo_redo;
@@ -103,6 +96,14 @@ class ProjectSettingsEditor : public AcceptDialog {
void _editor_restart_close();
void _add_feature_overrides();
+
+ void _action_added(const String &p_name);
+ void _action_edited(const String &p_name, const Dictionary &p_action);
+ void _action_removed(const String &p_name);
+ void _action_renamed(const String &p_old_name, const String &p_new_name);
+ void _action_reordered(const String &p_action_name, const String &p_relative_to, bool p_before);
+ void _update_action_map_editor();
+
ProjectSettingsEditor();
protected:
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 07312e42b4..1a010b9168 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -417,7 +417,12 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
updating = false;
return false;
- } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
+ } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
+ hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
+ hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
+ hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
String basename;
switch (hint) {
case PROPERTY_HINT_LAYERS_2D_RENDER:
@@ -426,12 +431,18 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
case PROPERTY_HINT_LAYERS_2D_PHYSICS:
basename = "layer_names/2d_physics";
break;
+ case PROPERTY_HINT_LAYERS_2D_NAVIGATION:
+ basename = "layer_names/2d_navigation";
+ break;
case PROPERTY_HINT_LAYERS_3D_RENDER:
basename = "layer_names/3d_render";
break;
case PROPERTY_HINT_LAYERS_3D_PHYSICS:
basename = "layer_names/3d_physics";
break;
+ case PROPERTY_HINT_LAYERS_3D_NAVIGATION:
+ basename = "layer_names/3d_navigation";
+ break;
}
checks20gc->show();
@@ -821,6 +832,9 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (default_color_mode == 2) {
color_picker->set_raw_mode(true);
}
+
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
}
color_picker->show();
@@ -1153,7 +1167,12 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
emit_signal("variant_changed");
} break;
case Variant::INT: {
- if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
+ if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
+ hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
+ hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
+ hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
uint32_t f = v;
if (checks20[p_which]->is_pressed()) {
f |= (1 << p_which);
@@ -1337,7 +1356,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
void CustomPropertyEditor::_drag_easing(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float rel = mm->get_relative().x;
if (rel == 0) {
return;
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 48aa0471c9..0f15d4b119 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -434,7 +434,10 @@ String RenameDialog::_substitute(const String &subject, const Node *node, int co
}
int current = EditorNode::get_singleton()->get_editor_data().get_edited_scene();
- result = result.replace("${SCENE}", EditorNode::get_singleton()->get_editor_data().get_scene_title(current));
+ // Always request the scene title with the extension stripped.
+ // Otherwise, the result could vary depending on whether a scene with the same name
+ // (but different extension) is currently open.
+ result = result.replace("${SCENE}", EditorNode::get_singleton()->get_editor_data().get_scene_title(current, true));
Node *root_node = SceneTree::get_singleton()->get_edited_scene_root();
if (root_node) {
@@ -629,7 +632,7 @@ void RenameDialog::_insert_text(String text) {
if (_is_main_field(focus_owner)) {
focus_owner->selection_delete();
- focus_owner->append_at_cursor(text);
+ focus_owner->insert_text_at_caret(text);
_update_preview();
}
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index ac1beb1c37..49c231de69 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/resource_saver.h"
+#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_feature_profile.h"
@@ -61,14 +62,18 @@ void SceneTreeDock::_quick_open() {
}
void SceneTreeDock::_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
restore_script_editor_on_drag = false; //lost chance
}
}
void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (get_focus_owner() && get_focus_owner()->is_text_field()) {
return;
}
@@ -87,6 +92,12 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
_tool_selected(TOOL_INSTANCE);
} else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) {
_tool_selected(TOOL_EXPAND_COLLAPSE);
+ } else if (ED_IS_SHORTCUT("scene_tree/cut_node", p_event)) {
+ _tool_selected(TOOL_CUT);
+ } else if (ED_IS_SHORTCUT("scene_tree/copy_node", p_event)) {
+ _tool_selected(TOOL_COPY);
+ } else if (ED_IS_SHORTCUT("scene_tree/paste_node", p_event)) {
+ _tool_selected(TOOL_PASTE);
} else if (ED_IS_SHORTCUT("scene_tree/change_node_type", p_event)) {
_tool_selected(TOOL_REPLACE);
} else if (ED_IS_SHORTCUT("scene_tree/duplicate", p_event)) {
@@ -101,8 +112,6 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
_tool_selected(TOOL_MOVE_DOWN);
} else if (ED_IS_SHORTCUT("scene_tree/reparent", p_event)) {
_tool_selected(TOOL_REPARENT);
- } else if (ED_IS_SHORTCUT("scene_tree/merge_from_scene", p_event)) {
- _tool_selected(TOOL_MERGE_FROM_SCENE);
} else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) {
_tool_selected(TOOL_NEW_SCENE_FROM);
} else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) {
@@ -132,7 +141,11 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren
parent = scene_tree->get_selected();
}
- if (!parent || !edited_scene) {
+ if (!parent) {
+ parent = edited_scene;
+ }
+
+ if (!parent) {
if (p_files.size() == 1) {
accept->set_text(TTR("No parent to instance a child at."));
} else {
@@ -215,6 +228,9 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
editor_data->get_undo_redo().commit_action();
editor->push_item(instances[instances.size() - 1]);
+ for (int i = 0; i < instances.size(); i++) {
+ emit_signal("node_created", instances[i]);
+ }
}
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) {
@@ -343,6 +359,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
+ if (reset_create_dialog) {
+ create_dialog->set_base_type("Node");
+ reset_create_dialog = false;
+ }
+
// Prefer nodes that inherit from the current scene root.
Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();
if (current_edited_scene_root) {
@@ -363,6 +384,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
create_dialog->popup_create(true);
+ if (!p_confirm_override) {
+ emit_signal("add_node_used");
+ }
} break;
case TOOL_INSTANCE: {
if (!profile_allow_editing) {
@@ -377,7 +401,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
quick_open->popup_dialog("PackedScene", true);
quick_open->set_title(TTR("Instance Child Scene"));
-
+ if (!p_confirm_override) {
+ emit_signal("add_node_used");
+ }
} break;
case TOOL_EXPAND_COLLAPSE: {
if (!scene_tree->get_selected()) {
@@ -397,11 +423,127 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
tree->ensure_cursor_is_visible();
} break;
+ case TOOL_CUT:
+ case TOOL_COPY: {
+ if (!edited_scene || !_validate_no_foreign()) {
+ break;
+ }
+
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (selection.size() == 0) {
+ break;
+ }
+
+ if (!node_clipboard.is_empty()) {
+ _clear_clipboard();
+ }
+ clipboard_source_scene = editor->get_edited_scene()->get_filename();
+
+ selection.sort_custom<Node::Comparator>();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node *node = E->get();
+ Map<const Node *, Node *> duplimap;
+ Node *dup = node->duplicate_from_editor(duplimap);
+
+ ERR_CONTINUE(!dup);
+
+ node_clipboard.push_back(dup);
+ }
+
+ if (p_tool == TOOL_CUT) {
+ _delete_confirm(true);
+ }
+ } break;
+ case TOOL_PASTE: {
+ if (node_clipboard.is_empty() || !edited_scene) {
+ break;
+ }
+
+ bool has_cycle = false;
+ if (edited_scene->get_filename() != String()) {
+ for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) {
+ if (edited_scene->get_filename() == E->get()->get_filename()) {
+ has_cycle = true;
+ break;
+ }
+ }
+ }
+
+ if (has_cycle) {
+ current_option = -1;
+ accept->set_text(TTR("Can't paste root node into the same scene."));
+ accept->popup_centered();
+ break;
+ }
+
+ Node *paste_parent = edited_scene;
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (selection.size() > 0) {
+ paste_parent = selection.back()->get();
+ }
+
+ Node *owner = paste_parent->get_owner();
+ if (!owner) {
+ owner = paste_parent;
+ }
+
+ editor_data->get_undo_redo().create_action(TTR("Paste Node(s)"));
+ editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
+
+ Map<RES, RES> resource_remap;
+ String target_scene = editor->get_edited_scene()->get_filename();
+ if (target_scene != clipboard_source_scene) {
+ if (!clipboard_resource_remap.has(target_scene)) {
+ Map<RES, RES> remap;
+ for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) {
+ _create_remap_for_node(E->get(), remap);
+ }
+ clipboard_resource_remap[target_scene] = remap;
+ }
+ resource_remap = clipboard_resource_remap[target_scene];
+ }
+
+ for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) {
+ Node *node = E->get();
+ Map<const Node *, Node *> duplimap;
+
+ Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
+
+ ERR_CONTINUE(!dup);
+
+ editor_data->get_undo_redo().add_do_method(paste_parent, "add_child", dup);
+
+ for (Map<const Node *, Node *>::Element *E2 = duplimap.front(); E2; E2 = E2->next()) {
+ Node *d = E2->value();
+ editor_data->get_undo_redo().add_do_method(d, "set_owner", owner);
+ }
+
+ editor_data->get_undo_redo().add_do_method(dup, "set_owner", owner);
+ editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup);
+ editor_data->get_undo_redo().add_undo_method(paste_parent, "remove_child", dup);
+ editor_data->get_undo_redo().add_do_reference(dup);
+
+ if (node_clipboard.size() == 1) {
+ editor_data->get_undo_redo().add_do_method(editor, "push_item", dup);
+ }
+ }
+
+ editor_data->get_undo_redo().commit_action();
+ } break;
case TOOL_REPLACE: {
if (!profile_allow_editing) {
break;
}
+ if (!_validate_no_foreign()) {
+ break;
+ }
+
+ if (!_validate_no_instance()) {
+ break;
+ }
+
Node *selected = scene_tree->get_selected();
if (!selected && !editor_selection->get_selected_node_list().is_empty()) {
selected = editor_selection->get_selected_node_list().front()->get();
@@ -475,7 +617,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
selection.sort_custom<Node::Comparator>(); // sort by index
if (MOVING_DOWN) {
- selection.invert();
+ selection.reverse();
}
int lowest_id = common_parent->get_child_count() - 1;
@@ -552,7 +694,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
Node *dupsingle = nullptr;
- List<Node *> editable_children;
selection.sort_custom<Node::Comparator>();
@@ -568,10 +709,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Map<const Node *, Node *> duplimap;
Node *dup = node->duplicate_from_editor(duplimap);
- if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node)) {
- editable_children.push_back(dup);
- }
-
ERR_CONTINUE(!dup);
if (selection.size() == 1) {
@@ -606,11 +743,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (dupsingle) {
editor->push_item(dupsingle);
}
-
- for (List<Node *>::Element *E = editable_children.back(); E; E = E->prev()) {
- _toggle_editable_children(E->get());
- }
-
} break;
case TOOL_REPARENT: {
if (!profile_allow_editing) {
@@ -766,13 +898,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
- case TOOL_MERGE_FROM_SCENE: {
- if (!profile_allow_editing) {
- break;
- }
-
- EditorNode::get_singleton()->merge_from_scene();
- } break;
case TOOL_NEW_SCENE_FROM: {
if (!profile_allow_editing) {
break;
@@ -781,7 +906,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *scene = editor_data->get_edited_scene_root();
if (!scene) {
- accept->set_text(TTR("This operation can't be done without a scene."));
+ accept->set_text(TTR("Saving the branch as a scene requires having a scene open in the editor."));
accept->popup_centered();
break;
}
@@ -789,7 +914,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->set_text(TTR("This operation requires a single selected node."));
+ accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), selection.size()));
accept->popup_centered();
break;
}
@@ -797,13 +922,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *tocopy = selection.front()->get();
if (tocopy == scene) {
- accept->set_text(TTR("Can not perform with the root node."));
+ accept->set_text(TTR("Can't save the root node branch as an instanced scene.\nTo create an editable copy of the current scene, duplicate it using the FileSystem dock context menu\nor create an inherited scene using Scene > New Inherited Scene... instead."));
accept->popup_centered();
break;
}
if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") {
- accept->set_text(TTR("This operation can't be done on instanced scenes."));
+ accept->set_text(TTR("Can't save the branch of an already instanced scene.\nTo create a variation of a scene, you can make an inherited scene based on the instanced scene using Scene > New Inherited Scene... instead."));
accept->popup_centered();
break;
}
@@ -1268,7 +1393,7 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
base_path.push_back(n->get_name());
n = n->get_parent();
}
- base_path.invert();
+ base_path.reverse();
Vector<StringName> new_base_path;
if (p_new_parent) {
@@ -1278,7 +1403,7 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
n = n->get_parent();
}
- new_base_path.invert();
+ new_base_path.reverse();
}
_fill_path_renames(base_path, new_base_path, p_node, p_renames);
@@ -1464,7 +1589,7 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
base_path.push_back(n->get_name());
n = n->get_parent();
}
- base_path.invert();
+ base_path.reverse();
Vector<StringName> new_base_path = base_path;
base_path.push_back(p_node->get_name());
@@ -1510,6 +1635,20 @@ bool SceneTreeDock::_validate_no_foreign() {
return true;
}
+bool SceneTreeDock::_validate_no_instance() {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ if (E->get() != edited_scene && E->get()->get_filename() != "") {
+ accept->set_text(TTR("This operation can't be done on instanced scenes."));
+ accept->popup_centered();
+ return false;
+ }
+ }
+
+ return true;
+}
+
void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
Node *new_parent = scene_root->get_node(p_path);
ERR_FAIL_COND(!new_parent);
@@ -1795,7 +1934,7 @@ void SceneTreeDock::_toggle_editable_children(Node *p_node) {
}
}
-void SceneTreeDock::_delete_confirm() {
+void SceneTreeDock::_delete_confirm(bool p_cut) {
List<Node *> remove_list = editor_selection->get_selected_node_list();
if (remove_list.is_empty()) {
@@ -1804,7 +1943,11 @@ void SceneTreeDock::_delete_confirm() {
editor->get_editor_plugins_over()->make_visible(false);
- editor_data->get_undo_redo().create_action(TTR("Remove Node(s)"));
+ if (p_cut) {
+ editor_data->get_undo_redo().create_action(TTR("Cut Node(s)"));
+ } else {
+ editor_data->get_undo_redo().create_action(TTR("Remove Node(s)"));
+ }
bool entire_scene = false;
@@ -1970,6 +2113,8 @@ void SceneTreeDock::_do_create(Node *p_parent) {
}
ct->set_size(ms);
}
+
+ emit_signal("node_created", c);
}
void SceneTreeDock::_create() {
@@ -2173,21 +2318,6 @@ void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) {
scene_tree->set_selected(p_node, p_emit_selected);
}
-void SceneTreeDock::import_subscene() {
- import_subscene_dialog->popup_centered_clamped(Size2(500, 800) * EDSCALE, 0.8);
-}
-
-void SceneTreeDock::_import_subscene() {
- Node *parent = scene_tree->get_selected();
- if (!parent) {
- parent = editor_data->get_edited_scene_root();
- ERR_FAIL_COND(!parent);
- }
-
- import_subscene_dialog->move(parent, edited_scene);
- editor_data->get_undo_redo().clear_history(); //no undo for now..
-}
-
void SceneTreeDock::_new_scene_from(String p_file) {
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -2205,10 +2335,14 @@ void SceneTreeDock::_new_scene_from(String p_file) {
Node *base = selection.front()->get();
- Map<Node *, Node *> reown;
- reown[editor_data->get_edited_scene_root()] = base;
- Node *copy = base->duplicate_and_reown(reown);
+ Map<const Node *, Node *> duplimap;
+ Node *copy = base->duplicate_from_editor(duplimap);
+
if (copy) {
+ for (int i = 0; i < copy->get_child_count(); i++) {
+ _set_node_owner_recursive(copy->get_child(i), copy);
+ }
+
Ref<PackedScene> sdata = memnew(PackedScene);
Error err = sdata->pack(copy);
memdelete(copy);
@@ -2238,6 +2372,16 @@ void SceneTreeDock::_new_scene_from(String p_file) {
}
}
+void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner) {
+ if (!p_node->get_owner()) {
+ p_node->set_owner(p_owner);
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _set_node_owner_recursive(p_node->get_child(i), p_owner);
+ }
+}
+
static bool _is_node_visible(Node *p_node) {
if (!p_node->get_owner()) {
return false;
@@ -2444,6 +2588,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
if (profile_allow_script_editing) {
+ menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
+ menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
+ if (selection.size() == 1 && !node_clipboard.is_empty()) {
+ menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
+ }
+ menu->add_separator();
+
bool add_separator = false;
if (full_selection.size() == 1) {
@@ -2480,7 +2631,18 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (full_selection.size() == 1) {
menu->add_icon_shortcut(get_theme_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME);
}
- menu->add_icon_shortcut(get_theme_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE);
+
+ bool can_replace = true;
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ if (E->get() != edited_scene && (E->get()->get_owner() != edited_scene || E->get()->get_filename() != "")) {
+ can_replace = false;
+ break;
+ }
+ }
+
+ if (can_replace) {
+ menu->add_icon_shortcut(get_theme_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE);
+ }
if (scene_tree->get_selected() != edited_scene) {
menu->add_separator();
@@ -2497,7 +2659,6 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (selection.size() == 1) {
if (profile_allow_editing) {
menu->add_separator();
- menu->add_icon_shortcut(get_theme_icon("Blend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/merge_from_scene"), TOOL_MERGE_FROM_SCENE);
menu->add_icon_shortcut(get_theme_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM);
}
if (full_selection.size() == 1) {
@@ -2643,6 +2804,16 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) {
}
}
+void SceneTreeDock::open_add_child_dialog() {
+ create_dialog->set_base_type("CanvasItem");
+ _tool_selected(TOOL_NEW, true);
+ reset_create_dialog = true;
+}
+
+void SceneTreeDock::open_instance_child_dialog() {
+ _tool_selected(TOOL_INSTANCE, true);
+}
+
void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
ERR_FAIL_COND(remote_tree != nullptr);
add_child(p_remote);
@@ -2775,6 +2946,62 @@ void SceneTreeDock::_feature_profile_changed() {
_update_script_button();
}
+void SceneTreeDock::_clear_clipboard() {
+ for (List<Node *>::Element *E = node_clipboard.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+ node_clipboard.clear();
+ clipboard_resource_remap.clear();
+}
+
+void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) {
+ List<PropertyInfo> props;
+ p_node->get_property_list(&props);
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+
+ Variant v = p_node->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) {
+ _create_remap_for_resource(res, r_remap);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _create_remap_for_node(p_node->get_child(i), r_remap);
+ }
+}
+
+void SceneTreeDock::_create_remap_for_resource(RES p_resource, Map<RES, RES> &r_remap) {
+ r_remap[p_resource] = p_resource->duplicate();
+
+ List<PropertyInfo> props;
+ p_resource->get_property_list(&props);
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+
+ Variant v = p_resource->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) {
+ _create_remap_for_resource(res, r_remap);
+ }
+ }
+ }
+ }
+}
+
void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &SceneTreeDock::_unhandled_key_input);
@@ -2786,9 +3013,20 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node);
ADD_SIGNAL(MethodInfo("remote_tree_selected"));
+ ADD_SIGNAL(MethodInfo("add_node_used"));
+ ADD_SIGNAL(MethodInfo("node_created", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+}
+
+SceneTreeDock *SceneTreeDock::singleton = nullptr;
+
+void SceneTreeDock::_update_configuration_warning() {
+ if (singleton) {
+ MessageQueue::get_singleton()->push_callable(callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning));
+ }
}
SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data) {
+ singleton = this;
set_name("Scene");
editor = p_editor;
edited_scene = nullptr;
@@ -2806,6 +3044,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A);
ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"));
ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All"));
+ ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KEY_MASK_CMD | KEY_X);
+ ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KEY_MASK_CMD | KEY_C);
+ ED_SHORTCUT("scene_tree/paste_node", TTR("Paste"), KEY_MASK_CMD | KEY_V);
ED_SHORTCUT("scene_tree/change_node_type", TTR("Change Type"));
ED_SHORTCUT("scene_tree/attach_script", TTR("Attach Script"));
ED_SHORTCUT("scene_tree/extend_script", TTR("Extend Script"));
@@ -2816,9 +3057,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
ED_SHORTCUT("scene_tree/reparent", TTR("Reparent"));
ED_SHORTCUT("scene_tree/reparent_to_new_node", TTR("Reparent to New Node"));
ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
- ED_SHORTCUT("scene_tree/merge_from_scene", TTR("Merge From Scene"));
ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
- ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KEY_MASK_CMD | KEY_C);
+ ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C);
ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KEY_MASK_SHIFT | KEY_DELETE);
ED_SHORTCUT("scene_tree/delete", TTR("Delete"), KEY_DELETE);
@@ -2841,7 +3081,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
filter->set_h_size_flags(SIZE_EXPAND_FILL);
filter->set_placeholder(TTR("Filter nodes"));
filter_hbc->add_child(filter);
- filter->add_theme_constant_override("minimum_spaces", 0);
+ filter->add_theme_constant_override("minimum_character_width", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed));
button_create_script = memnew(Button);
@@ -2869,6 +3109,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
edit_remote->set_text(TTR("Remote"));
edit_remote->set_toggle_mode(true);
+ edit_remote->set_tooltip(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
@@ -2936,7 +3177,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
delete_dialog = memnew(ConfirmationDialog);
add_child(delete_dialog);
- delete_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_delete_confirm));
+ delete_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_delete_confirm), varray(false));
editable_instance_remove_dialog = memnew(ConfirmationDialog);
add_child(editable_instance_remove_dialog);
@@ -2946,10 +3187,6 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
add_child(placeholder_editable_instance_remove_dialog);
placeholder_editable_instance_remove_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_toggle_placeholder_from_selection));
- import_subscene_dialog = memnew(EditorSubScene);
- add_child(import_subscene_dialog);
- import_subscene_dialog->connect("subscene_selected", callable_mp(this, &SceneTreeDock::_import_subscene));
-
new_scene_from_dialog = memnew(EditorFileDialog);
new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
add_child(new_scene_from_dialog);
@@ -2980,4 +3217,13 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true);
EDITOR_DEF("interface/editors/derive_script_globals_by_name", true);
EDITOR_DEF("_use_favorites_root_selection", false);
+
+ Resource::_update_configuration_warning = _update_configuration_warning;
+}
+
+SceneTreeDock::~SceneTreeDock() {
+ singleton = nullptr;
+ if (!node_clipboard.is_empty()) {
+ _clear_clipboard();
+ }
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 4f8d85f07c..53f31375f8 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -34,7 +34,6 @@
#include "editor/connections_dialog.h"
#include "editor/create_dialog.h"
#include "editor/editor_data.h"
-#include "editor/editor_sub_scene.h"
#include "editor/groups_editor.h"
#include "editor/quick_open.h"
#include "editor/rename_dialog.h"
@@ -58,6 +57,9 @@ class SceneTreeDock : public VBoxContainer {
TOOL_NEW,
TOOL_INSTANCE,
TOOL_EXPAND_COLLAPSE,
+ TOOL_CUT,
+ TOOL_COPY,
+ TOOL_PASTE,
TOOL_RENAME,
TOOL_BATCH_RENAME,
TOOL_REPLACE,
@@ -71,7 +73,6 @@ class SceneTreeDock : public VBoxContainer {
TOOL_REPARENT_TO_NEW_NODE,
TOOL_MAKE_ROOT,
TOOL_NEW_SCENE_FROM,
- TOOL_MERGE_FROM_SCENE,
TOOL_MULTI_EDIT,
TOOL_ERASE,
TOOL_COPY_NODE_PATH,
@@ -99,6 +100,7 @@ class SceneTreeDock : public VBoxContainer {
Vector<ObjectID> subresources;
bool restore_script_editor_on_drag;
+ bool reset_create_dialog = false;
int current_option;
CreateDialog *create_dialog;
@@ -126,6 +128,10 @@ class SceneTreeDock : public VBoxContainer {
EditorData *editor_data;
EditorSelection *editor_selection;
+ List<Node *> node_clipboard;
+ String clipboard_source_scene;
+ HashMap<String, Map<RES, RES>> clipboard_resource_remap;
+
ScriptCreateDialog *script_create_dialog;
AcceptDialog *accept;
ConfirmationDialog *delete_dialog;
@@ -134,7 +140,6 @@ class SceneTreeDock : public VBoxContainer {
ReparentDialog *reparent_dialog;
EditorQuickOpen *quick_open;
- EditorSubScene *import_subscene_dialog;
EditorFileDialog *new_scene_from_dialog;
LineEdit *filter;
@@ -183,7 +188,7 @@ class SceneTreeDock : public VBoxContainer {
void _script_created(Ref<Script> p_script);
void _script_creation_closed();
- void _delete_confirm();
+ void _delete_confirm(bool p_cut = false);
void _toggle_editable_children_from_selection();
void _toggle_editable_children(Node *p_node);
@@ -199,8 +204,10 @@ class SceneTreeDock : public VBoxContainer {
void _import_subscene();
void _new_scene_from(String p_file);
+ void _set_node_owner_recursive(Node *p_node, Node *p_owner);
bool _validate_no_foreign();
+ bool _validate_no_instance();
void _selection_changed();
void _update_script_button();
@@ -230,9 +237,16 @@ class SceneTreeDock : public VBoxContainer {
void _feature_profile_changed();
+ void _clear_clipboard();
+ void _create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap);
+ void _create_remap_for_resource(RES p_resource, Map<RES, RES> &r_remap);
+
bool profile_allow_editing;
bool profile_allow_script_editing;
+ static SceneTreeDock *singleton;
+ static void _update_configuration_warning();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -264,9 +278,13 @@ public:
void attach_script_to_selected(bool p_extend);
void open_script_dialog(Node *p_for_node, bool p_extend);
+ void open_add_child_dialog();
+ void open_instance_child_dialog();
+
ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }
SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data);
+ ~SceneTreeDock();
};
#endif // SCENE_TREE_DOCK_H
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index ce44a4bca1..f979f61196 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -120,7 +120,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
undo_redo->commit_action();
} else if (p_id == BUTTON_WARNING) {
- String config_err = n->get_configuration_warning();
+ String config_err = n->get_configuration_warnings_as_string();
if (config_err == String()) {
return;
}
@@ -236,6 +236,8 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
item->set_text(0, node_name);
item->set_selectable(0, marked_selectable);
item->set_custom_color(0, get_theme_color("accent_color", "Editor"));
+ } else if (!p_node->can_process()) {
+ item->set_custom_color(0, get_theme_color("disabled_font_color", "Editor"));
} else if (!marked_selectable && !marked_children_selectable) {
Node *node = p_node;
while (node) {
@@ -250,9 +252,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
if (can_rename) { //should be can edit..
- String warning = p_node->get_configuration_warning();
+ String warning = p_node->get_configuration_warnings_as_string();
if (!warning.is_empty()) {
- item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
+ item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);
}
int num_connections = p_node->get_persistent_signal_connection_count();
@@ -275,7 +277,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
}
Ref<Texture2D> icon_temp;
- auto signal_temp = BUTTON_SIGNALS;
+ SceneTreeEditorButton signal_temp = BUTTON_SIGNALS;
if (num_connections >= 1 && num_groups >= 1) {
icon_temp = get_theme_icon("SignalsAndGroups", "EditorIcons");
} else if (num_connections >= 1) {
@@ -585,6 +587,11 @@ void SceneTreeEditor::_test_update_tree() {
tree_dirty = true;
}
+void SceneTreeEditor::_tree_process_mode_changed() {
+ MessageQueue::get_singleton()->push_call(this, "_update_tree");
+ tree_dirty = true;
+}
+
void SceneTreeEditor::_tree_changed() {
if (EditorNode::get_singleton()->is_exiting()) {
return; //speed up exit
@@ -619,7 +626,7 @@ void SceneTreeEditor::_selected_changed() {
}
void SceneTreeEditor::_deselect_items() {
- // Clear currently elected items in scene tree dock.
+ // Clear currently selected items in scene tree dock.
if (editor_selection) {
editor_selection->clear();
emit_signal("node_changed");
@@ -655,9 +662,10 @@ void SceneTreeEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
get_tree()->connect("tree_changed", callable_mp(this, &SceneTreeEditor::_tree_changed));
+ get_tree()->connect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed));
get_tree()->connect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed));
get_tree()->connect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed));
- get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed));
+ get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed), varray(), CONNECT_DEFERRED);
tree->connect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed));
@@ -665,6 +673,7 @@ void SceneTreeEditor::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
get_tree()->disconnect("tree_changed", callable_mp(this, &SceneTreeEditor::_tree_changed));
+ get_tree()->disconnect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed));
get_tree()->disconnect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed));
get_tree()->disconnect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed));
tree->disconnect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed));
@@ -767,9 +776,11 @@ void SceneTreeEditor::_renamed() {
return;
}
- String new_name = which->get_text(0);
- if (!Node::_validate_node_name(new_name)) {
- error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + Node::invalid_character);
+ String raw_new_name = which->get_text(0);
+ String new_name = raw_new_name.validate_node_name();
+
+ if (new_name != raw_new_name) {
+ error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + String::invalid_node_name_characters);
error->popup_centered();
if (new_name.is_empty()) {
@@ -983,9 +994,6 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
if (!can_rename) {
return false; //not editable tree
}
- if (filter != String()) {
- return false; //can't rearrange tree with filter turned on
- }
Dictionary d = p_data;
if (!d.has("type")) {
@@ -1038,7 +1046,7 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
}
}
- return String(d["type"]) == "nodes";
+ return String(d["type"]) == "nodes" && filter == String();
}
void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -1094,6 +1102,9 @@ void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) {
emit_signal("rmb_pressed", tree->get_screen_transform().xform(p_pos));
}
+void SceneTreeEditor::update_warning() {
+ _warning_changed(nullptr);
+}
void SceneTreeEditor::_warning_changed(Node *p_for_node) {
//should use a timer
update_timer->start();
@@ -1110,7 +1121,7 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) {
}
void SceneTreeEditor::_bind_methods() {
- ClassDB::bind_method("_update_tree", &SceneTreeEditor::_update_tree); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_update_tree", "scroll_to_selected"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by some connect_compat.
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
@@ -1161,6 +1172,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
tree->set_anchor(SIDE_BOTTOM, ANCHOR_END);
tree->set_begin(Point2(0, p_label ? 18 : 0));
tree->set_end(Point2(0, 0));
+ tree->set_allow_reselect(true);
tree->add_theme_constant_override("button_margin", 0);
add_child(tree);
@@ -1194,7 +1206,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
blocked = 0;
update_timer = memnew(Timer);
- update_timer->connect("timeout", callable_mp(this, &SceneTreeEditor::_update_tree));
+ update_timer->connect("timeout", callable_mp(this, &SceneTreeEditor::_update_tree), varray(false));
update_timer->set_one_shot(true);
update_timer->set_wait_time(0.5);
add_child(update_timer);
@@ -1260,7 +1272,7 @@ SceneTreeDialog::SceneTreeDialog() {
filter = memnew(LineEdit);
filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->set_placeholder(TTR("Filter nodes"));
- filter->add_theme_constant_override("minimum_spaces", 0);
+ filter->add_theme_constant_override("minimum_character_width", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDialog::_filter_changed));
vbc->add_child(filter);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 7d3419516d..acd49e8d92 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -43,7 +43,7 @@ class SceneTreeEditor : public Control {
EditorSelection *editor_selection;
- enum {
+ enum SceneTreeEditorButton {
BUTTON_SUBSCENE = 0,
BUTTON_VISIBILITY = 1,
BUTTON_SCRIPT = 2,
@@ -75,6 +75,7 @@ class SceneTreeEditor : public Control {
void _test_update_tree();
void _update_tree(bool p_scroll_to_selected = false);
void _tree_changed();
+ void _tree_process_mode_changed();
void _node_removed(Node *p_node);
void _node_renamed(Node *p_node);
@@ -156,6 +157,8 @@ public:
Tree *get_scene_tree() { return tree; }
+ void update_warning();
+
SceneTreeEditor(bool p_label = true, bool p_can_rename = false, bool p_can_open_instance = false);
~SceneTreeEditor();
};
@@ -180,6 +183,7 @@ protected:
public:
void popup_scenetree_dialog();
SceneTreeEditor *get_scene_tree() { return tree; }
+ LineEdit *get_filter_line_edit() { return filter; }
SceneTreeDialog();
~SceneTreeDialog();
};
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index b707f6c353..f3addd8904 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -87,8 +87,8 @@ void ScriptCreateDialog::_path_hbox_sorted() {
// First set cursor to the end of line to scroll LineEdit view
// to the right and then set the actual cursor position.
- file_path->set_cursor_position(file_path->get_text().length());
- file_path->set_cursor_position(filename_start_pos);
+ file_path->set_caret_column(file_path->get_text().length());
+ file_path->set_caret_column(filename_start_pos);
file_path->grab_focus();
}
@@ -238,6 +238,14 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
return "";
}
+String ScriptCreateDialog::_get_class_name() const {
+ if (has_named_classes) {
+ return class_name->get_text();
+ } else {
+ return ProjectSettings::get_singleton()->localize_path(file_path->get_text()).get_file().get_basename();
+ }
+}
+
void ScriptCreateDialog::_class_name_changed(const String &p_name) {
if (_validate_class(class_name->get_text())) {
is_class_name_valid = true;
@@ -287,13 +295,7 @@ void ScriptCreateDialog::ok_pressed() {
}
void ScriptCreateDialog::_create_new() {
- String cname_param;
-
- if (has_named_classes) {
- cname_param = class_name->get_text();
- } else {
- cname_param = ProjectSettings::get_singleton()->localize_path(file_path->get_text()).get_file().get_basename();
- }
+ String cname_param = _get_class_name();
Ref<Script> scr;
if (script_template != "") {
@@ -555,7 +557,7 @@ void ScriptCreateDialog::_file_selected(const String &p_file) {
String filename = p.get_file().get_basename();
int select_start = p.rfind(filename);
file_path->select(select_start, select_start + filename.length());
- file_path->set_cursor_position(select_start + filename.length());
+ file_path->set_caret_column(select_start + filename.length());
file_path->grab_focus();
}
}
@@ -687,6 +689,10 @@ void ScriptCreateDialog::_update_dialog() {
builtin_warning_label->set_visible(is_built_in);
+ // Check if the script name is the same as the parent class.
+ // This warning isn't relevant if the script is built-in.
+ script_name_warning_label->set_visible(!is_built_in && _get_class_name() == parent_name->get_text());
+
if (is_built_in) {
get_ok_button()->set_text(TTR("Create"));
parent_name->set_editable(true);
@@ -768,6 +774,14 @@ ScriptCreateDialog::ScriptCreateDialog() {
builtin_warning_label->set_autowrap(true);
builtin_warning_label->hide();
+ script_name_warning_label = memnew(Label);
+ script_name_warning_label->set_text(
+ TTR("Warning: Having the script name be the same as a built-in type is usually not desired."));
+ vb->add_child(script_name_warning_label);
+ script_name_warning_label->add_theme_color_override("font_color", Color(1, 0.85, 0.4));
+ script_name_warning_label->set_autowrap(true);
+ script_name_warning_label->hide();
+
status_panel = memnew(PanelContainer);
status_panel->set_h_size_flags(Control::SIZE_FILL);
status_panel->add_child(vb);
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index e898b6f927..d6417b9d33 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -50,6 +50,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
Label *error_label;
Label *path_error_label;
Label *builtin_warning_label;
+ Label *script_name_warning_label;
PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
@@ -110,6 +111,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
bool _validate_parent(const String &p_string);
bool _validate_class(const String &p_string);
String _validate_path(const String &p_path, bool p_file_must_exist);
+ String _get_class_name() const;
void _class_name_changed(const String &p_name);
void _parent_name_changed(const String &p_parent);
void _template_changed(int p_template = 0);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 1dad3c091d..81af4996ed 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -31,6 +31,7 @@
#include "settings_config_dialog.h"
#include "core/config/project_settings.h"
+#include "core/input/input_map.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor_file_system.h"
@@ -138,12 +139,14 @@ void EditorSettingsDialog::_notification(int p_what) {
}
void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
bool handled = false;
- if (ED_IS_SHORTCUT("editor/undo", p_event)) {
+ if (ED_IS_SHORTCUT("ui_undo", p_event)) {
String action = undo_redo->get_current_action_name();
if (action != "") {
EditorNode::get_log()->add_message("Undo: " + action, EditorLog::MSG_TYPE_EDITOR);
@@ -152,7 +155,7 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
handled = true;
}
- if (ED_IS_SHORTCUT("editor/redo", p_event)) {
+ if (ED_IS_SHORTCUT("ui_redo", p_event)) {
undo_redo->redo();
String action = undo_redo->get_current_action_name();
if (action != "") {
@@ -184,7 +187,52 @@ void EditorSettingsDialog::_update_icons() {
restart_label->add_theme_color_override("font_color", shortcuts->get_theme_color("warning_color", "Editor"));
}
+void EditorSettingsDialog::_event_config_confirmed() {
+ Ref<InputEventKey> k = shortcut_editor->get_event();
+ if (k.is_null()) {
+ return;
+ }
+
+ if (editing_action) {
+ if (current_action_event_index == -1) {
+ // Add new event
+ current_action_events.push_back(k);
+ } else {
+ // Edit existing event
+ current_action_events[current_action_event_index] = k;
+ }
+
+ _update_builtin_action(current_action, current_action_events);
+ } else {
+ k = k->duplicate();
+ Ref<Shortcut> current_sc = EditorSettings::get_singleton()->get_shortcut(shortcut_being_edited);
+
+ undo_redo->create_action(TTR("Change Shortcut") + " '" + shortcut_being_edited + "'");
+ undo_redo->add_do_method(current_sc.ptr(), "set_shortcut", k);
+ undo_redo->add_undo_method(current_sc.ptr(), "set_shortcut", current_sc->get_shortcut());
+ undo_redo->add_do_method(this, "_update_shortcuts");
+ undo_redo->add_undo_method(this, "_update_shortcuts");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+ }
+}
+
+void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Array &p_events) {
+ Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(current_action);
+
+ undo_redo->create_action(TTR("Edit Built-in Action"));
+ undo_redo->add_do_method(EditorSettings::get_singleton(), "set_builtin_action_override", p_name, p_events);
+ undo_redo->add_undo_method(EditorSettings::get_singleton(), "set_builtin_action_override", p_name, old_input_array);
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+
+ _update_shortcuts();
+}
+
void EditorSettingsDialog::_update_shortcuts() {
+ // Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated.
Map<String, bool> collapsed;
if (shortcuts->get_root() && shortcuts->get_root()->get_children()) {
@@ -192,15 +240,93 @@ void EditorSettingsDialog::_update_shortcuts() {
collapsed[item->get_text(0)] = item->is_collapsed();
}
}
-
shortcuts->clear();
- List<String> slist;
- EditorSettings::get_singleton()->get_shortcut_list(&slist);
TreeItem *root = shortcuts->create_item();
-
Map<String, TreeItem *> sections;
+ // Set up section for Common/Built-in actions
+ TreeItem *common_section = shortcuts->create_item(root);
+
+ sections["Common"] = common_section;
+ common_section->set_text(0, TTR("Common"));
+ if (collapsed.has("Common")) {
+ common_section->set_collapsed(collapsed["Common"]);
+ }
+ common_section->set_custom_bg_color(0, shortcuts->get_theme_color("prop_subsection", "Editor"));
+ common_section->set_custom_bg_color(1, shortcuts->get_theme_color("prop_subsection", "Editor"));
+
+ // Get the action map for the editor, and add each item to the "Common" section.
+ OrderedHashMap<StringName, InputMap::Action> action_map = InputMap::get_singleton()->get_action_map();
+ for (OrderedHashMap<StringName, InputMap::Action>::Element E = action_map.front(); E; E = E.next()) {
+ String action_name = E.key();
+
+ if (!shortcut_filter.is_subsequence_ofi(action_name)) {
+ continue;
+ }
+
+ InputMap::Action action = E.get();
+
+ Array events; // Need to get the list of events into an array so it can be set as metadata on the item.
+ Vector<String> event_strings;
+
+ List<Ref<InputEvent>> defaults = InputMap::get_singleton()->get_builtins().find(action_name).value();
+ // Remove all non-key events from the defaults.
+ for (List<Ref<InputEvent>>::Element *I = defaults.front(); I; I = I->next()) {
+ Ref<InputEventKey> k = I->get();
+ if (k.is_null()) {
+ I->erase();
+ }
+ }
+
+ bool same_as_defaults = defaults.size() == action.inputs.size(); // Initially this is set to just whether the arrays are equal. Later we check the events if needed.
+
+ int count = 0;
+ for (List<Ref<InputEvent>>::Element *I = action.inputs.front(); I; I = I->next()) {
+ // Add event and event text to respective arrays.
+ events.push_back(I->get());
+ event_strings.push_back(I->get()->as_text());
+
+ // Only check if the events have been the same so far - once one fails, we don't need to check any more.
+ if (same_as_defaults) {
+ Ref<InputEventKey> k = defaults[count];
+ // Only check keys, since we are in the editor.
+ if (k.is_valid() && !defaults[count]->shortcut_match(I->get())) {
+ same_as_defaults = false;
+ }
+ }
+ count++;
+ }
+
+ // Join the text of the events with a delimiter so they can all be displayed in one cell.
+ String events_display_string = event_strings.is_empty() ? "None" : String("; ").join(event_strings);
+
+ TreeItem *item = shortcuts->create_item(common_section);
+ item->set_text(0, action_name);
+ item->set_text(1, events_display_string);
+
+ if (!same_as_defaults) {
+ item->add_button(1, shortcuts->get_theme_icon("Reload", "EditorIcons"), 2);
+ }
+
+ if (events_display_string == "None") {
+ // Fade out unassigned shortcut labels for easier visual grepping.
+ item->set_custom_color(1, shortcuts->get_theme_color("font_color", "Label") * Color(1, 1, 1, 0.5));
+ }
+
+ item->add_button(1, shortcuts->get_theme_icon("Edit", "EditorIcons"), 0);
+ item->add_button(1, shortcuts->get_theme_icon("Close", "EditorIcons"), 1);
+ item->set_tooltip(0, action_name);
+ item->set_tooltip(1, events_display_string);
+ item->set_metadata(0, "Common");
+ item->set_metadata(1, events);
+ }
+
+ // Editor Shortcuts
+
+ List<String> slist;
+ EditorSettings::get_singleton()->get_shortcut_list(&slist);
+
for (List<String>::Element *E = slist.front(); E; E = E->next()) {
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(E->get());
if (!sc->has_meta("original")) {
@@ -267,84 +393,120 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
ERR_FAIL_COND(!ti);
- String item = ti->get_metadata(0);
- Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(item);
-
- if (p_idx == 0) {
- press_a_key_label->set_text(TTR("Press a Key..."));
- last_wait_for_key = Ref<InputEventKey>();
- press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
- //press_a_key->grab_focus();
- press_a_key->get_ok_button()->set_focus_mode(Control::FOCUS_NONE);
- press_a_key->get_cancel_button()->set_focus_mode(Control::FOCUS_NONE);
- shortcut_configured = item;
-
- } else if (p_idx == 1) { //erase
- if (!sc.is_valid()) {
- return; //pointless, there is nothing
+ button_idx = p_idx;
+
+ if (ti->get_metadata(0) == "Common") {
+ // Editing a Built-in action, which can have multiple bindings.
+ editing_action = true;
+ current_action = ti->get_text(0);
+
+ switch (button_idx) {
+ case SHORTCUT_REVERT: {
+ Array events;
+ List<Ref<InputEvent>> defaults = InputMap::get_singleton()->get_builtins()[current_action];
+
+ // Convert the list to an array, and only keep key events as this is for the editor.
+ for (List<Ref<InputEvent>>::Element *E = defaults.front(); E; E = E->next()) {
+ Ref<InputEventKey> k = E->get();
+ if (k.is_valid()) {
+ events.append(E->get());
+ }
+ }
+
+ _update_builtin_action(current_action, events);
+ } break;
+ case SHORTCUT_EDIT:
+ case SHORTCUT_ERASE: {
+ // For Edit end Delete, we will show a popup which displays each event so the user can select which one to edit/delete.
+ current_action_events = ti->get_metadata(1);
+ action_popup->clear();
+
+ for (int i = 0; i < current_action_events.size(); i++) {
+ Ref<InputEvent> ie = current_action_events[i];
+ action_popup->add_item(ie->as_text());
+ action_popup->set_item_metadata(i, ie);
+ }
+
+ if (button_idx == SHORTCUT_EDIT) {
+ // If editing, add a button which can be used to add an additional event.
+ action_popup->add_icon_item(get_theme_icon("Add", "EditorIcons"), TTR("Add"));
+ }
+
+ action_popup->set_position(get_position() + get_mouse_position());
+ action_popup->take_mouse_focus();
+ action_popup->popup();
+ action_popup->set_as_minsize();
+ } break;
+ default:
+ break;
}
-
- undo_redo->create_action(TTR("Erase Shortcut"));
- undo_redo->add_do_method(sc.ptr(), "set_shortcut", Ref<InputEvent>());
- undo_redo->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
- undo_redo->add_do_method(this, "_update_shortcuts");
- undo_redo->add_undo_method(this, "_update_shortcuts");
- undo_redo->add_do_method(this, "_settings_changed");
- undo_redo->add_undo_method(this, "_settings_changed");
- undo_redo->commit_action();
- } else if (p_idx == 2) { //revert to original
- if (!sc.is_valid()) {
- return; //pointless, there is nothing
+ } else {
+ // Editing an Editor Shortcut, which can only have 1 binding.
+ String item = ti->get_metadata(0);
+ Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(item);
+ editing_action = false;
+
+ switch (button_idx) {
+ case EditorSettingsDialog::SHORTCUT_EDIT:
+ shortcut_editor->popup_and_configure(sc->get_shortcut());
+ shortcut_being_edited = item;
+ break;
+ case EditorSettingsDialog::SHORTCUT_ERASE: {
+ if (!sc.is_valid()) {
+ return; //pointless, there is nothing
+ }
+
+ undo_redo->create_action(TTR("Erase Shortcut"));
+ undo_redo->add_do_method(sc.ptr(), "set_shortcut", Ref<InputEvent>());
+ undo_redo->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
+ undo_redo->add_do_method(this, "_update_shortcuts");
+ undo_redo->add_undo_method(this, "_update_shortcuts");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+ } break;
+ case EditorSettingsDialog::SHORTCUT_REVERT: {
+ if (!sc.is_valid()) {
+ return; //pointless, there is nothing
+ }
+
+ Ref<InputEvent> original = sc->get_meta("original");
+
+ undo_redo->create_action(TTR("Restore Shortcut"));
+ undo_redo->add_do_method(sc.ptr(), "set_shortcut", original);
+ undo_redo->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
+ undo_redo->add_do_method(this, "_update_shortcuts");
+ undo_redo->add_undo_method(this, "_update_shortcuts");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+ } break;
+ default:
+ break;
}
-
- Ref<InputEvent> original = sc->get_meta("original");
-
- undo_redo->create_action(TTR("Restore Shortcut"));
- undo_redo->add_do_method(sc.ptr(), "set_shortcut", original);
- undo_redo->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
- undo_redo->add_do_method(this, "_update_shortcuts");
- undo_redo->add_undo_method(this, "_update_shortcuts");
- undo_redo->add_do_method(this, "_settings_changed");
- undo_redo->add_undo_method(this, "_settings_changed");
- undo_redo->commit_action();
}
}
-void EditorSettingsDialog::_wait_for_key(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid() && k->is_pressed() && k->get_keycode() != 0) {
- last_wait_for_key = k;
- const String str = keycode_get_string(k->get_keycode_with_modifiers());
-
- press_a_key_label->set_text(str);
- press_a_key->set_input_as_handled();
- }
-}
-
-void EditorSettingsDialog::_press_a_key_confirm() {
- if (last_wait_for_key.is_null()) {
- return;
+void EditorSettingsDialog::_builtin_action_popup_index_pressed(int p_index) {
+ switch (button_idx) {
+ case SHORTCUT_EDIT: {
+ if (p_index == action_popup->get_item_count() - 1) {
+ // Selected last item in list (Add button), therefore add new
+ current_action_event_index = -1;
+ shortcut_editor->popup_and_configure();
+ } else {
+ // Configure existing
+ current_action_event_index = p_index;
+ shortcut_editor->popup_and_configure(action_popup->get_item_metadata(p_index));
+ }
+ } break;
+ case SHORTCUT_ERASE: {
+ current_action_events.remove(p_index);
+ _update_builtin_action(current_action, current_action_events);
+ } break;
+ default:
+ break;
}
-
- Ref<InputEventKey> ie;
- ie.instance();
- ie->set_keycode(last_wait_for_key->get_keycode());
- ie->set_shift(last_wait_for_key->get_shift());
- ie->set_control(last_wait_for_key->get_control());
- ie->set_alt(last_wait_for_key->get_alt());
- ie->set_metakey(last_wait_for_key->get_metakey());
-
- Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(shortcut_configured);
-
- undo_redo->create_action(TTR("Change Shortcut") + " '" + shortcut_configured + "'");
- undo_redo->add_do_method(sc.ptr(), "set_shortcut", ie);
- undo_redo->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
- undo_redo->add_do_method(this, "_update_shortcuts");
- undo_redo->add_undo_method(this, "_update_shortcuts");
- undo_redo->add_do_method(this, "_settings_changed");
- undo_redo->add_undo_method(this, "_settings_changed");
- undo_redo->commit_action();
}
void EditorSettingsDialog::_tabs_tab_changed(int p_tab) {
@@ -382,9 +544,14 @@ void EditorSettingsDialog::_editor_restart_close() {
void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_input"), &EditorSettingsDialog::_unhandled_input);
ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
+ ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed);
}
EditorSettingsDialog::EditorSettingsDialog() {
+ action_popup = memnew(PopupMenu);
+ action_popup->connect("index_pressed", callable_mp(this, &EditorSettingsDialog::_builtin_action_popup_index_pressed));
+ add_child(action_popup);
+
set_title(TTR("Editor Settings"));
undo_redo = memnew(UndoRedo);
@@ -442,21 +609,17 @@ EditorSettingsDialog::EditorSettingsDialog() {
// Shortcuts Tab
tab_shortcuts = memnew(VBoxContainer);
+
tabs->add_child(tab_shortcuts);
tab_shortcuts->set_name(TTR("Shortcuts"));
- hbc = memnew(HBoxContainer);
- hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tab_shortcuts->add_child(hbc);
-
shortcut_search_box = memnew(LineEdit);
shortcut_search_box->set_placeholder(TTR("Search"));
shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbc->add_child(shortcut_search_box);
+ tab_shortcuts->add_child(shortcut_search_box);
shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts));
shortcuts = memnew(Tree);
- tab_shortcuts->add_child(shortcuts, true);
shortcuts->set_v_size_flags(Control::SIZE_EXPAND_FILL);
shortcuts->set_columns(2);
shortcuts->set_hide_root(true);
@@ -464,21 +627,13 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts->set_column_title(0, TTR("Name"));
shortcuts->set_column_title(1, TTR("Binding"));
shortcuts->connect("button_pressed", callable_mp(this, &EditorSettingsDialog::_shortcut_button_pressed));
+ tab_shortcuts->add_child(shortcuts);
- press_a_key = memnew(ConfirmationDialog);
- //press_a_key->set_focus_mode(Control::FOCUS_ALL);
- add_child(press_a_key);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Press a Key..."));
- l->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
- l->set_align(Label::ALIGN_CENTER);
- l->set_offset(SIDE_TOP, 20);
- l->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_BEGIN, 30);
- press_a_key_label = l;
- press_a_key->add_child(l);
- press_a_key->connect("window_input", callable_mp(this, &EditorSettingsDialog::_wait_for_key));
- press_a_key->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_press_a_key_confirm));
+ // Adding event dialog
+ shortcut_editor = memnew(InputEventConfigurationDialog);
+ shortcut_editor->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_event_config_confirmed));
+ shortcut_editor->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY);
+ add_child(shortcut_editor);
set_hide_on_ok(true);
diff --git a/editor/settings_config_dialog.h b/editor/settings_config_dialog.h
index b1ee58ae8f..c38fceedf1 100644
--- a/editor/settings_config_dialog.h
+++ b/editor/settings_config_dialog.h
@@ -31,6 +31,7 @@
#ifndef SETTINGS_CONFIG_DIALOG_H
#define SETTINGS_CONFIG_DIALOG_H
+#include "editor/action_map_editor.h"
#include "editor/editor_sectioned_inspector.h"
#include "editor_inspector.h"
#include "scene/gui/dialogs.h"
@@ -52,16 +53,28 @@ class EditorSettingsDialog : public AcceptDialog {
LineEdit *shortcut_search_box;
SectionedInspector *inspector;
+ enum ShortcutButton {
+ SHORTCUT_EDIT,
+ SHORTCUT_ERASE,
+ SHORTCUT_REVERT
+ };
+
+ int button_idx;
+ int current_action_event_index = -1;
+ bool editing_action = false;
+ String current_action;
+ Array current_action_events;
+ PopupMenu *action_popup;
+
Timer *timer;
UndoRedo *undo_redo;
- Tree *shortcuts;
- ConfirmationDialog *press_a_key;
- Label *press_a_key_label;
- Ref<InputEventKey> last_wait_for_key;
- String shortcut_configured;
+ // Shortcuts
String shortcut_filter;
+ Tree *shortcuts;
+ InputEventConfigurationDialog *shortcut_editor;
+ String shortcut_being_edited;
virtual void cancel_pressed() override;
virtual void ok_pressed() override;
@@ -74,20 +87,20 @@ class EditorSettingsDialog : public AcceptDialog {
void _notification(int p_what);
void _update_icons();
- void _press_a_key_confirm();
- void _wait_for_key(const Ref<InputEvent> &p_event);
+ void _event_config_confirmed();
+
+ void _update_builtin_action(const String &p_name, const Array &p_events);
void _tabs_tab_changed(int p_tab);
void _focus_current_search_box();
- void _clear_shortcut_search_box();
- void _clear_search_box();
-
void _filter_shortcuts(const String &p_filter);
void _update_shortcuts();
void _shortcut_button_pressed(Object *p_item, int p_column, int p_idx);
+ void _builtin_action_popup_index_pressed(int p_index);
+
static void _undo_redo_callback(void *p_self, const String &p_name);
Label *restart_label;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 14d305e34f..ebef5be9ed 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -427,7 +427,7 @@ void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
void ShaderGlobalsEditor::_changed() {
emit_signal("globals_changed");
if (!interface->block_update) {
- interface->_change_notify();
+ interface->notify_property_list_changed();
}
}
@@ -483,8 +483,5 @@ ShaderGlobalsEditor::ShaderGlobalsEditor() {
}
ShaderGlobalsEditor::~ShaderGlobalsEditor() {
- if (is_visible_in_tree()) {
- inspector->edit(nullptr);
- }
memdelete(interface);
}
diff --git a/editor/translations/af.po b/editor/translations/af.po
index c537e790e7..1b952d51b6 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -6,12 +6,13 @@
# Julius Stopforth <jjstopforth@gmail.com>, 2018.
# Isa Tippens <isatippens2@gmail.com>, 2019.
# Henry Geyser <thegoat187@gmail.com>, 2020.
+# Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-12-01 20:29+0000\n"
-"Last-Translator: Henry Geyser <thegoat187@gmail.com>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Henry LeRoux <henry.leroux@ocsbstudent.ca>\n"
"Language-Team: Afrikaans <https://hosted.weblate.org/projects/godot-engine/"
"godot/af/>\n"
"Language: af\n"
@@ -19,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -216,14 +217,12 @@ msgid "Animation Playback Track"
msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation length (frames)"
-msgstr "Animasie lengte (in sekondes)."
+msgstr "Animasie lengte (in rame)."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation length (seconds)"
-msgstr "Animasie lengte (in sekondes)."
+msgstr "Animasie lengte (in sekondes)"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -659,7 +658,7 @@ msgstr "Stel Oorgange na:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1913,8 +1912,8 @@ msgid "Open a File or Directory"
msgstr "Open 'n Lêer of Gids"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Stoor"
@@ -2581,7 +2580,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2981,14 +2980,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Soek"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3143,6 +3134,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3349,7 +3356,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3659,6 +3666,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4071,6 +4083,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Skep Vouer"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Ek sien..."
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Laai Verstek"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5069,7 +5100,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5178,7 +5209,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -7006,6 +7036,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Soek"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7058,16 +7096,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7167,8 +7195,8 @@ msgstr "Skep"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7588,6 +7616,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10021,6 +10054,11 @@ msgid "Projects"
msgstr "Projek Stigters"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Laai"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10386,6 +10424,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Laai Verstek"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10636,6 +10679,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Anim Dupliseer Sleutels"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Deursoek Hulp"
@@ -10762,6 +10814,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Anim Dupliseer Sleutels"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10874,6 +10931,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12400,6 +12464,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12655,11 +12727,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 7af493c55a..9051e2cf82 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -46,13 +46,17 @@
# Musab Alasaifer <mousablasefer@gmail.com>, 2020.
# Yassine Oudjana <y.oudjana@protonmail.com>, 2020.
# bruvzg <bruvzg13@gmail.com>, 2020.
-# StarlkYT <mrsstarlkps4@gmail.com>, 2020.
+# StarlkYT <mrsstarlkps4@gmail.com>, 2020, 2021.
+# Games Toon <xxtvgoodxx@gmail.com>, 2021.
+# Kareem Abduljaleel <karemjaleel34@gmail.com>, 2021.
+# ILG - Game <moegypt277@gmail.com>, 2021.
+# Hatim Jamal <hatimjamal8@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-12-29 15:03+0000\n"
-"Last-Translator: StarlkYT <mrsstarlkps4@gmail.com>\n"
+"PO-Revision-Date: 2021-04-16 07:52+0000\n"
+"Last-Translator: Hatim Jamal <hatimjamal8@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -61,7 +65,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.4.1-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -274,7 +278,7 @@ msgstr "تكرار الرسوم المتحركة"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr "الإعدادات:"
+msgstr "الإعدادات:المهام:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
@@ -384,7 +388,7 @@ msgstr "حذف مسار التحريك"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "أنشئ مسار جديد لـ %s و إدخال مفتاح؟"
+msgstr "أنشئ مسار جديد ل %s و إدخال مفتاح؟"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
@@ -684,7 +688,7 @@ msgstr "إختر المقاطع المراد نسخها"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "نسخ"
@@ -997,11 +1001,11 @@ msgstr "الوصف:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr "البحث عن بديل لـ:"
+msgstr "البحث عن بديل ل:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr "تبعيات لـ:"
+msgstr "تبعيات ل:"
#: editor/dependency_editor.cpp
msgid ""
@@ -1393,7 +1397,7 @@ msgstr "تحريك مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr "حفظ تخطيط مسار الصوت كـ…"
+msgstr "حفظ تخطيط مسار الصوت ك…"
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1701,9 +1705,8 @@ msgid "Node Dock"
msgstr "رصيف العُقد"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "نظام الملفات"
+msgstr "إرساء نظام الملفات"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1788,7 +1791,7 @@ msgstr "جديد"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "إستيراد"
+msgstr "استيراد"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1885,8 +1888,8 @@ msgid "Open a File or Directory"
msgstr "إفتح ملف أو وجهة"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "حفظ"
@@ -2018,7 +2021,7 @@ msgstr "التعليمات على الإنترنت"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "خصائص"
+msgstr "خاصيات"
#: editor/editor_help.cpp
msgid "override:"
@@ -2342,6 +2345,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"تم تجاوز اعدادات المحرر الاساسيه.\n"
+"لإستعادة اعدادات المحرر, اذهب إلى خيار 'Delete Layout' من ثم إحفظ الاعدادات "
+"الاساسيه."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2406,7 +2412,7 @@ msgstr "ليس هناك مشهد محدد ليتم تشغيله."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "احفظ المشهد قبل التشغيل..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2450,7 +2456,7 @@ msgstr "يتطلب حفظ المشهد توافر عُقدة رئيسة."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "حفظ المشهد كـ…"
+msgstr "حفظ المشهد ك…"
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
@@ -2551,14 +2557,12 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "غير قادر علي تفعيل إضافة البرنامج المُساعد في: '%s' تحميل الظبط فشل."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"غير قادر علي إيجاد منطقة النص البرمجي من أجل إضافة البرنامج في: 'res://"
-"addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "غير قادر على إيجاد منطقة النص البرمجي من أجل إضافة البرنامج في: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "غير قادر علي تحميل النص البرمجي للإضافة من المسار: '%s'."
+msgstr "غير قادر علي تحميل النص البرمجي للإضافة من المسار: '%s'."
#: editor/editor_node.cpp
msgid ""
@@ -2847,6 +2851,12 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
+"عند تمكين هذا الخيار ، سيؤدي استخدام النشر بنقرة واحدة إلى إجراء المحاولة "
+"القابلة للتنفيذ للاتصال ب IP الخاص بهذا الكمبيوتر بحيث يمكن تصحيح أخطاء "
+"المشروع الجاري تشغيله.\n"
+"الغرض من هذا الخيار هو استخدامه لتصحيح الأخطاء عن بُعد (عادةً باستخدام جهاز "
+"محمول).\n"
+"لا تحتاج إلى تمكينه لاستخدام مصحح أخطاء GDScript محليًا."
#: editor/editor_node.cpp
#, fuzzy
@@ -2854,7 +2864,6 @@ msgid "Small Deploy with Network Filesystem"
msgstr "نشر مصغر مع نظام شبكات الملفات"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2874,7 +2883,6 @@ msgid "Visible Collision Shapes"
msgstr "أشكال إصطدام ظاهرة"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
@@ -2983,14 +2991,6 @@ msgid "Help"
msgstr "مساعدة"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "بحث"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "مستندات الإنترنت"
@@ -3082,7 +3082,7 @@ msgstr "نظام الملفات"
#: editor/editor_node.cpp
msgid "Inspector"
-msgstr "المُراقب"
+msgstr "مُتفحص"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
@@ -3090,7 +3090,7 @@ msgstr "توسيع التبويب السفلي"
#: editor/editor_node.cpp
msgid "Output"
-msgstr "الخرج"
+msgstr "المخرجات"
#: editor/editor_node.cpp
msgid "Don't Save"
@@ -3154,6 +3154,24 @@ msgid "Open & Run a Script"
msgstr "فتح و تشغيل كود"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"الملفات التالية أحدث على القرص.\n"
+"ما الإجراء الذي ينبغي اتخاذه؟"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "إعادة تحميل"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "إعادة حفظ"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "موروث جديد"
@@ -3363,7 +3381,7 @@ msgstr "إجعلة مميزاً"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "لصق"
@@ -3677,6 +3695,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "الحالة: إستيراد الملف فشل. من فضلك أصلح الملف و أعد إستيراده يدوياً."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "تم تعطيل الاستيراد لهذا الملف ، لذا لا يمكن فتحه للتحرير."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "لا يمكن مسح/إعادة تسمية جذر الموارد."
@@ -3721,6 +3744,8 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"تتعارض الملفات أو المجلدات التالية مع العناصر الموجودة في الموقع الهدف\n"
+"هل ترغب في الكتابة عليها؟"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3752,7 +3777,7 @@ msgstr "فتح المَشاهِد"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr "نموذج"
+msgstr "كائن"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
@@ -4062,6 +4087,24 @@ msgstr "هل قمت بإرجاع كائن مشتق من العقدة في دال
msgid "Saving..."
msgstr "جاري الحفظ..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "تحديد الوضع"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "المستورد:"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "تحميل الإفتراضي"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "الاحتفاظ بالملف (بدون استيراد)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d ملفات"
@@ -4142,7 +4185,7 @@ msgstr "إفتح في المساعدة"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr "إنشاء مورد جديد في الذاكرة وتعديله."
+msgstr "انشاء مورد جديد فى الذاكرة و تعديله"
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
@@ -4170,7 +4213,7 @@ msgstr "خصائص العنصر."
#: editor/inspector_dock.cpp
msgid "Filter properties"
-msgstr "تصفية الخصائص"
+msgstr "خصائص التصفية"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4297,7 +4340,7 @@ msgstr "إضافة نقطة العقدة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Animation Point"
-msgstr "أضف نقطة حركة"
+msgstr "أضفة نقطة الرسوم المتحركة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
@@ -4542,7 +4585,7 @@ msgstr "مسح الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
-msgstr "إسم الرسم المتحرك خاطئ!"
+msgstr "اسم حركة خاطئ!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation name already exists!"
@@ -4767,7 +4810,7 @@ msgstr "لم يتم تعيين موارد التشغيل في المسار: %s."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
-msgstr "مُسِحت العقدة"
+msgstr "تمت إزالة الكائن"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition Removed"
@@ -5028,7 +5071,8 @@ msgid "Got:"
msgstr "ما تم الحصول عليه:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "فشل التاكد من ترميز sha256"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5132,7 +5176,6 @@ msgid "Sort:"
msgstr "ترتيب:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "الفئة:"
@@ -5184,32 +5227,33 @@ msgstr "لا يمكن انشاء خرائط الضوء, تاكد من ان ال
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
-msgstr ""
+msgstr "فشل تحديد حجم الخريطة الضوئية. الحجم الأقصى للخريطة المضيئة صغير جدًا؟"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"بعض الشبكات غير صالحة. تأكد من احتواء قيم قناة UV2 داخل منطقة مربعة "
+"[0.0،1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
-msgstr ""
+msgstr "تم تجميع محرر Godot دون دعم لتتبع الأشعة. لا يمكن بناء خرائط الإضاءة."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "إعداد خرائط الضوء"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "حدد ملف القالب"
+msgstr "حدد ملف الخريطة الضوئية:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Preview"
-msgstr "استعراض"
+msgstr "عرض"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
@@ -5273,7 +5317,7 @@ msgstr "إنشاء موجه عمودي وأفقي جديد"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "تعيين إزاحة \"CanvasItem \"%s المحورية إلى (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5292,7 +5336,7 @@ msgstr "تحريك العنصر القماشي"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "تعديل حجم العقدة \"Node2D \"%s إلى (s, %s%)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
@@ -5747,11 +5791,11 @@ msgstr "إخلاء الوضع"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr "ضاعف خطوة الشبكة بـ 2"
+msgstr "ضاعف خطوة الشبكة ب 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr "قسم خطوة الشبكة بـ 2"
+msgstr "قسم خطوة الشبكة ب 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -6057,7 +6101,7 @@ msgstr "أنشئ الحد"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh"
-msgstr "مجسم"
+msgstr "مجسّم"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Body"
@@ -6673,7 +6717,7 @@ msgstr "تمكين المحاذاة"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr "الشبكة"
+msgstr "شبكة"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
@@ -6955,6 +6999,14 @@ msgstr "إغلاق المستندات"
msgid "Run"
msgstr "تشغيل"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "بحث"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "اخط خطوة ضمن"
@@ -7008,16 +7060,6 @@ msgstr ""
"الملفات التالية أحدث على القرص.\n"
"ما الإجراء الذي ينبغي اتخاذه؟:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "إعادة تحميل"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "إعادة حفظ"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "مُنقح الأخطاء"
@@ -7111,8 +7153,8 @@ msgstr "نقاط التكسّر"
msgid "Go To"
msgstr "التوجه إلى"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "قص"
@@ -7335,9 +7377,8 @@ msgid "Yaw"
msgstr "الإنحراف Yaw"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "الحجم: "
+msgstr "الحجم"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7521,6 +7562,11 @@ msgstr "تدوير الرؤية مقفول"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8304,7 +8350,7 @@ msgstr "الإطباق Occlusion"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr "التنقل"
+msgstr "تنقل"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
@@ -8356,7 +8402,7 @@ msgstr "نسخ قناع-البِت."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Paste bitmask."
-msgstr "لصق قناع-البِت"
+msgstr "لصق قناع البِت"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
@@ -10028,6 +10074,11 @@ msgid "Projects"
msgstr "المشاريع"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "يستقبل المرايا، من فضلك إنتظر..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "آخر ما تم تعديله"
@@ -10397,6 +10448,11 @@ msgstr "تحميل تلقائي"
msgid "Plugins"
msgstr "إضافات"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "تحميل الإفتراضي"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "إعداد مُسبق..."
@@ -10458,19 +10514,16 @@ msgid "Batch Rename"
msgstr "إعادة تسمية الدفعة"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "إستبدال: "
+msgstr "إستبدال:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Prefix:"
-msgstr "بادئة"
+msgstr "بادئة:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Suffix:"
-msgstr "لاحقة"
+msgstr "لاحقة:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10517,9 +10570,8 @@ msgid "Per-level Counter"
msgstr "العداد وفق-المستوى"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "إذا تم تحديده فإن العداد سيعيد البدء لكل مجموعة من العُقد الأبناء"
+msgstr "إذا تم تحديده فإن العداد سيعيد البدء لكل مجموعة من العُقد الأبناء."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
@@ -10578,9 +10630,8 @@ msgid "Reset"
msgstr "إعادة تعيين"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "خطأ ذو علاقة بالتعبير الاعتيادي Regular Expression"
+msgstr "خطأ في التعبير العادي:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10649,6 +10700,15 @@ msgid "Instance Child Scene"
msgstr "نمذجة المشهد الابن"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "لا يمكن لصق عقدة الجذر في نفس المشهد."
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "لصق العُقد"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "فصل النص البرمجي"
@@ -10716,7 +10776,7 @@ msgstr "لا يمكن تنفيذ هذا الإجراء على المشاهد ا
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
-msgstr "احفظ المشهد الجديد كـ..."
+msgstr "احفظ المشهد الجديد ك..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10776,6 +10836,11 @@ msgid "Attach Script"
msgstr "إلحاق نص برمجي"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "قص العُقد"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "إزالة عُقدة (عُقد)"
@@ -10887,6 +10952,13 @@ msgid "Remote"
msgstr "عن بعد"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "محلي"
@@ -11397,11 +11469,11 @@ msgstr "مكتبة GDNativeLibrary"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Enabled GDNative Singleton"
-msgstr "تمكين نمط البرمجة Singleton لـ GDNative"
+msgstr "تمكين نمط البرمجة Singleton ل GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Disabled GDNative Singleton"
-msgstr "تعطيل نمط البرمجة Singleton لـ GDNative"
+msgstr "تعطيل نمط البرمجة Singleton ل GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
@@ -11610,9 +11682,8 @@ msgid "Post processing"
msgstr "المعالجة-اللاحقة Post-Process"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "تخطيط الإضاءات:"
+msgstr "تخطيط الإضاءات"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12201,21 +12272,21 @@ msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
-"\"Degrees Of Freedom\" تكون صالحة فقط عندما يكون وضع الـ \"Xr Mode\"هو "
+"\"Degrees Of Freedom\" تكون صالحة فقط عندما يكون وضع ال \"Xr Mode\"هو "
"\"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
-"\"Hand Tracking\" تكون صالحة فقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"\"Hand Tracking\" تكون صالحة فقط عندما يكون وضع ال \"Xr Mode\"هو \"Oculus "
"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
-"\"Focus Awareness\" تكون صالحة فقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"\"Focus Awareness\" تكون صالحة فقط عندما يكون وضع ال \"Xr Mode\"هو \"Oculus "
"Mobile VR\"."
#: platform/android/export/export.cpp
@@ -12432,6 +12503,14 @@ msgstr ""
"مُضلع تصادم ثنائي الأبعاد (CollisionPolygon2D) الفارغ ليس له أي تأثير على "
"التصادم."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12658,9 +12737,8 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "توزيع الأشكال الهندسية..."
+msgstr "تجضير الهندسة (%d/%d)"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12721,8 +12799,8 @@ msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
-"يجب توفير شكل لـ CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل "
-"بالشكل المطلوب. الرجاء تكوين و ضبط الشكل لها."
+"يجب توفير شكل ل CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل بالشكل "
+"المطلوب. الرجاء تكوين و ضبط الشكل لها."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12768,11 +12846,6 @@ msgstr ""
"GIProbes لا يدعم برنامج تشغيل الفيديو GLES2.\n"
"استخدم BakedLightmap بدلاً من ذلك."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "بقعة الضوء بزاوية أكبر من 90 درجة لا يمكنها إلقاء الظلال."
@@ -13022,9 +13095,8 @@ msgid "Must use a valid extension."
msgstr "يجب أن يستخدم صيغة صحيحة."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "تمكين المحاذاة"
+msgstr "تفعيل الخريطة المصغرة للشبكة."
#: scene/gui/popup.cpp
msgid ""
@@ -13037,8 +13109,7 @@ msgstr ""
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
-msgstr ""
-"إذا تم تفعيل الـ\"Exp Edit\" يجب على ان يكون \"Min Value\" اعلى من صفر."
+msgstr "إذا تم تفعيل ال\"Exp Edit\" يجب على ان يكون \"Min Value\" اعلى من صفر."
#: scene/gui/scroll_container.cpp
msgid ""
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index b03e325ec5..548d71df18 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -17,7 +17,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
+"PO-Revision-Date: 2021-03-10 22:14+0000\n"
"Last-Translator: Любомир Василев <lyubomirv@gmx.com>\n"
"Language-Team: Bulgarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/bg/>\n"
@@ -26,7 +26,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -640,7 +640,7 @@ msgstr "Изберете пътечки за копиране"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Копиране"
@@ -1811,8 +1811,8 @@ msgid "Open a File or Directory"
msgstr "Отваряне на файл или папка"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Запазване"
@@ -2446,39 +2446,50 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Не може да бъде намерено полето за скрипт за добавката: „%s“."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "Не може да се зареди скриптът на добавка от: „%s“."
+msgstr "Не може да се зареди добавката-скрипт от: „%s“."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Изглежда има грешка в кода. "
+"Моля, проверете синтаксиса."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Базовият тип не е "
+"„EditorPlugin“."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Не може да се зареди добавката-скрипт от: „%s“. Скриптът не е в режим на "
+"„инструмент“."
#: editor/editor_node.cpp
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
+"Сцената „%s“ е била внесена автоматично и затова не може да се променя.\n"
+"Ако искате да правите промени в нея, може да създадете нова сцена-наследник."
#: editor/editor_node.cpp
msgid ""
"Error loading scene, it must be inside the project path. Use 'Import' to "
"open the scene, then save it inside the project path."
msgstr ""
+"Грешка при зареждането на сцената. Тя трябва да се намира в папката на "
+"проекта. Използвайте „Внасяне“, за да отворите сцената, и след това я "
+"запазете някъде в папката на проекта."
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
@@ -2494,6 +2505,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Няма определена главна сцена. Искате ли да изберете такава сега?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid ""
@@ -2501,6 +2515,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Избраната сцена „%s“ не съществува. Искате ли да изберете друга?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid ""
@@ -2508,6 +2525,10 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Избраната сцена „%s“ не е файл съдържащ сцена. Искате ли да изберете "
+"подходящ файл?\n"
+"Можете да промените това по всяко време в „Настройките на проекта“, в "
+"категорията „Приложение“."
#: editor/editor_node.cpp
msgid "Save Layout"
@@ -2838,14 +2859,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Търсене"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2999,6 +3012,24 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Следните файлове са по-нови на диска.\n"
+"Кое действие трябва да се предприеме?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Презареждане"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Презаписване"
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "New Inherited"
msgstr "Нов скрипт"
@@ -3202,7 +3233,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Поставяне"
@@ -3506,6 +3537,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3883,9 +3919,25 @@ msgstr ""
msgid "Saving..."
msgstr "Запазване..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Изберете метод на внасяне"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Метод на внасяне:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Връщане на стандартните настройки"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
-msgstr "%d Файлове"
+msgstr "%d файла"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
@@ -4841,7 +4893,8 @@ msgid "Got:"
msgstr "Получено:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Неуспешна проверка на хеш от вид „sha256“"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4945,7 +4998,6 @@ msgid "Sort:"
msgstr "Сортиране:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Категория:"
@@ -6744,6 +6796,14 @@ msgstr "Затваряне на документацията"
msgid "Run"
msgstr "Пускане"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Търсене"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6797,16 +6857,6 @@ msgstr ""
"Следните файлове са по-нови на диска.\n"
"Кое действие трябва да се предприеме?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Презареждане"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Презаписване"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Дебъгер"
@@ -6899,8 +6949,8 @@ msgstr "Точки на прекъсване"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Изрязване"
@@ -7308,6 +7358,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7560,7 +7615,7 @@ msgstr "Преобразуване в Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
-msgstr ""
+msgstr "Неправилна геометрия, не може да се създаде полигон."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Polygon2D"
@@ -7568,7 +7623,7 @@ msgstr "Превръщане в Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
-msgstr ""
+msgstr "Неправилна геометрия, не може да се създаде полигон за колизии."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create CollisionPolygon2D Sibling"
@@ -7580,7 +7635,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create LightOccluder2D Sibling"
-msgstr ""
+msgstr "Създаване на съседен LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
@@ -7588,15 +7643,15 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
-msgstr ""
+msgstr "Опростяване: "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Shrink (Pixels): "
-msgstr ""
+msgstr "Смаляване (пиксели): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Grow (Pixels): "
-msgstr ""
+msgstr "Уголемяване (пиксели): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
@@ -7612,11 +7667,11 @@ msgstr "Няма избрани кадри"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr ""
+msgstr "Добавяне на %d кадър/кадри"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
-msgstr ""
+msgstr "Добавяне на кадър"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
@@ -7624,27 +7679,27 @@ msgstr "Изображенията не могат да бъдат зареде
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
-msgstr ""
+msgstr "ГРЕШКА: Не може да се зареди ресурсът с кадъра!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
-msgstr ""
+msgstr "Буферът за обмен на ресурси е празен или не съдържа текстура!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
-msgstr ""
+msgstr "Поставяне на кадър"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Empty"
-msgstr ""
+msgstr "Добавяне на празен"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation FPS"
-msgstr ""
+msgstr "Промяна на скоростта (кадри/сек) на анимацията"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "(empty)"
-msgstr ""
+msgstr "(празно)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move Frame"
@@ -7664,7 +7719,7 @@ msgstr "Скорост:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
-msgstr ""
+msgstr "Повтаряне"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animation Frames:"
@@ -7680,11 +7735,11 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (Before)"
-msgstr ""
+msgstr "Вмъкване на празен (преди)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (After)"
-msgstr ""
+msgstr "Вмъкване на празен (след)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (Before)"
@@ -7692,7 +7747,7 @@ msgstr "Преместване (преди)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (After)"
-msgstr ""
+msgstr "Преместване (след)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select Frames"
@@ -7700,11 +7755,11 @@ msgstr "Избиране на кадри"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
-msgstr ""
+msgstr "Хоризонтала:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Vertical:"
-msgstr ""
+msgstr "Вертикала:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
@@ -7724,40 +7779,40 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Set Margin"
-msgstr ""
+msgstr "Задаване на отстъп"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr ""
+msgstr "Режим на прилепване:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
msgid "None"
-msgstr ""
+msgstr "Няма"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr ""
+msgstr "Прилепване към пикселите"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr ""
+msgstr "Прилепване към решетката"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
-msgstr ""
+msgstr "Автоматично отрязване"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr ""
+msgstr "Отместване:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
-msgstr ""
+msgstr "Стъпка:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Sep.:"
-msgstr ""
+msgstr "Разделител:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "TextureRegion"
@@ -7765,15 +7820,15 @@ msgstr "Текстурна област"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All Items"
-msgstr ""
+msgstr "Добавяне на всички елементи"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All"
-msgstr ""
+msgstr "Добавяне на всичко"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
-msgstr ""
+msgstr "Премахване на всички елементи"
#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
msgid "Remove All"
@@ -7785,7 +7840,7 @@ msgstr "Редактиране на темата"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme editing menu."
-msgstr ""
+msgstr "Меню за редактиране на темата."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Class Items"
@@ -7817,7 +7872,7 @@ msgstr "Заключен бутон"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Item"
-msgstr ""
+msgstr "Елемент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Disabled Item"
@@ -7825,11 +7880,11 @@ msgstr "Заключен елемент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Check Item"
-msgstr ""
+msgstr "Елемент за отметка"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Checked Item"
-msgstr ""
+msgstr "Отметнат елемент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Radio Item"
@@ -7841,27 +7896,27 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Named Sep."
-msgstr ""
+msgstr "Именуван разд."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Submenu"
-msgstr ""
+msgstr "Подменю"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 1"
-msgstr ""
+msgstr "Поделемент 1"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 2"
-msgstr ""
+msgstr "Поделемент 2"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has"
-msgstr ""
+msgstr "Има"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Many"
-msgstr ""
+msgstr "Много"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Disabled LineEdit"
@@ -7869,15 +7924,15 @@ msgstr "Заключено текстово поле"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 1"
-msgstr ""
+msgstr "Раздел 1"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 2"
-msgstr ""
+msgstr "Раздел 2"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 3"
-msgstr ""
+msgstr "Раздел 3"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Editable Item"
@@ -7885,32 +7940,32 @@ msgstr "Редактируем елемент"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subtree"
-msgstr ""
+msgstr "Поддърво"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has,Many,Options"
-msgstr ""
+msgstr "Има,Много,Опции"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
-msgstr ""
+msgstr "Тип на данните:"
#: editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Icon"
-msgstr ""
+msgstr "Иконка"
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Style"
-msgstr ""
+msgstr "Стил"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Font"
-msgstr ""
+msgstr "Шрифт"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Color"
-msgstr ""
+msgstr "Цват"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme File"
@@ -7918,11 +7973,11 @@ msgstr "Файл с тема"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
-msgstr ""
+msgstr "Изтриване на избраното"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Fix Invalid Tiles"
-msgstr ""
+msgstr "Поправка на неправилните плочки"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -9661,6 +9716,11 @@ msgid "Projects"
msgstr "Проекти"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Зареждане…"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10021,6 +10081,11 @@ msgstr ""
msgid "Plugins"
msgstr "Приставки"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Внасяне на преводи"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10264,6 +10329,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Поставяне на възлите"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Разкачане на скрипта"
@@ -10384,6 +10458,11 @@ msgid "Attach Script"
msgstr "Закачане на скрипт"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Изрязване на възлите"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10491,6 +10570,13 @@ msgid "Remote"
msgstr "Отдалечен"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11980,6 +12066,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Празен CollisionPolygon2D не влияе на колизиите."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12258,11 +12352,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12854,9 +12943,6 @@ msgstr "Константите не могат да бъдат променен
#~ msgid "Import Large Texture"
#~ msgstr "Внасяне на голяма текстура"
-#~ msgid "Import Translations"
-#~ msgstr "Внасяне на преводи"
-
#~ msgid "Couldn't import!"
#~ msgstr "Неуспешно внасяне!"
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 53a1d59aa3..21144a829b 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-01 20:53+0000\n"
+"PO-Revision-Date: 2021-02-15 10:51+0000\n"
"Last-Translator: Mokarrom Hossain <mhb2016.bzs@gmail.com>\n"
"Language-Team: Bengali <https://hosted.weblate.org/projects/godot-engine/"
"godot/bn/>\n"
@@ -439,14 +439,12 @@ msgid "Track is not of type Spatial, can't insert key"
msgstr "ট্র্যাক Spatial টাইপের নয়, কী সন্নিবেশ করতে পারে না"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Transform Track Key"
-msgstr "রুপান্তরের ধরণ"
+msgstr "ট্রান্সফর্ম ট্র্যাক কী যুক্ত করুন"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Track Key"
-msgstr "অ্যানিমেশন (Anim) ট্র্যাক যোগ করুন"
+msgstr "ট্র্যাক কী যুক্ত করুন"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
@@ -514,11 +512,11 @@ msgstr "অ্যানিমেশন তৈরি এবং সম্পাদ
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr ""
+msgstr "Tree মধ্যে নির্বাচিত নোডগুলি থেকে কেবল ট্র্যাকগুলি দেখান।"
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
-msgstr ""
+msgstr "নোড দ্বারা গ্রুপ ট্র্যাক করুন বা তাদের সরল তালিকা হিসাবে প্রদর্শন করুন।"
#: editor/animation_track_editor.cpp
msgid "Snap:"
@@ -552,9 +550,8 @@ msgid "Animation properties."
msgstr "অ্যানিমেশন বৈশিষ্ট্য।"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Copy Tracks"
-msgstr "মানসমূহ প্রতিলিপি/কপি করুন"
+msgstr "ট্র্যাকগুলি অনুলিপি করুন"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
@@ -598,7 +595,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
-msgstr ""
+msgstr "বেজিয়ার কার্ভ ব্যবহার করুন"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -645,16 +642,15 @@ msgid "Scale Ratio:"
msgstr "স্কেল/মাপের অনুপাত:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "গুণাগুণ/বৈশিষ্ট্য বাছাই করুন"
+msgstr "গুণাগুণ/বৈশিষ্ট্য copy করুন"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "প্রতিলিপি/কপি করুন"
@@ -1930,8 +1926,8 @@ msgid "Open a File or Directory"
msgstr "ফাইল বা পথ/ডিরেক্টরি খুলুন"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "সংরক্ষন করুন"
@@ -2645,7 +2641,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "অ্যাড-অন প্লাগইন এনাবল করা সম্ভব হয় নি। কনফিগার পার্সিং ('%s') ব্যর্থ হয়েছে।"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"'res://addons/%s' লোকেশনে অ্যাড-অন প্লাগইনের স্ক্রিপ্ট ফাইল খুঁজে পাওয়া যায়নি।"
@@ -3109,14 +3106,6 @@ msgid "Help"
msgstr "হেল্প"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "অনুসন্ধান করুন"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
#, fuzzy
msgid "Online Docs"
@@ -3283,6 +3272,25 @@ msgstr "একটি স্ক্রিপ্ট খুলুন এবং চ
#: editor/editor_node.cpp
#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"নিম্নোক্ত ফাইলসমূহ ডিস্কে নতুনতর।\n"
+"কোন সিধান্তটি নেয়া উচিত হবে?:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "রিলোড"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "পুনঃসংরক্ষণ"
+
+#: editor/editor_node.cpp
+#, fuzzy
msgid "New Inherited"
msgstr "নতুন উত্তরাধিকারী দৃশ্য..."
@@ -3508,7 +3516,7 @@ msgstr "বোন্‌/হাড় তৈরি করুন"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "প্রতিলেপন/পেস্ট করুন"
@@ -3864,6 +3872,11 @@ msgstr ""
"ইম্পোর্ট করুন।"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "ফন্টের উৎস লোড/প্রসেস করা সম্ভব হচ্ছে না।"
@@ -4299,6 +4312,25 @@ msgstr ""
msgid "Saving..."
msgstr "সংরক্ষিত হচ্ছে..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "মোড (Mode) বাছাই করুন"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "ইম্পোর্ট"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "প্রাথমিক sRGB ব্যবহার করুন"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5343,7 +5375,8 @@ msgid "Got:"
msgstr "প্রাপ্ত:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "sha256 হ্যাশ চেক ব্যর্থ হয়েছে"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5459,7 +5492,6 @@ msgid "Sort:"
msgstr "সাজান:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "বিভাগ:"
@@ -7407,6 +7439,14 @@ msgstr "ডকুমেন্টসমূহ বন্ধ করুন"
msgid "Run"
msgstr "চালান"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "অনুসন্ধান করুন"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "পদার্পণ করুন"
@@ -7463,16 +7503,6 @@ msgstr ""
"নিম্নোক্ত ফাইলসমূহ ডিস্কে নতুনতর।\n"
"কোন সিধান্তটি নেয়া উচিত হবে?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "রিলোড"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "পুনঃসংরক্ষণ"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "ডিবাগার"
@@ -7575,8 +7605,8 @@ msgstr "বিন্দু অপসারণ করুন"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "কর্তন/কাট করুন"
@@ -8028,6 +8058,11 @@ msgstr "তথ্য দেখুন"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10615,6 +10650,11 @@ msgid "Projects"
msgstr "নতুন প্রকল্প"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "মিরর রিট্রাইভ করা হচ্ছে, দযা করে অপেক্ষা করুন..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -11001,6 +11041,11 @@ msgstr "স্বয়ংক্রিয়-লোড"
msgid "Plugins"
msgstr "প্লাগইন-সমূহ"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "লোড ডিফল্ট"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "প্রিসেট..."
@@ -11266,6 +11311,16 @@ msgstr "শীষ্য নোড ইন্সট্যান্স করুন
#: editor/scene_tree_dock.cpp
#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "বাহিরের দৃশ্যের নোডে এটি করা সম্ভব হবে না!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "নোড-সমূহ প্রতিলেপন/পেস্ট করুন"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Detach Script"
msgstr "স্ক্রিপ্ট সংযুক্ত করুন"
@@ -11397,6 +11452,11 @@ msgid "Attach Script"
msgstr "স্ক্রিপ্ট সংযুক্ত করুন"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "নোড-সমূহ কর্তন/কাট করুন"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "নোড(সমূহ) অপসারণ করুন"
@@ -11519,6 +11579,13 @@ msgid "Remote"
msgstr "অপসারণ করুন"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Local"
msgstr "ঘটনাস্থল"
@@ -13177,6 +13244,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "সংঘর্ষে ফাঁকা/শুন্য CollisionPolygon2D-এর কোনো প্রভাব নেই।"
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -13468,11 +13543,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -15413,9 +15483,6 @@ msgstr ""
#~ msgid "Use Default Light"
#~ msgstr "প্রাথমিক লাইট ব্যবহার করুন"
-#~ msgid "Use Default sRGB"
-#~ msgstr "প্রাথমিক sRGB ব্যবহার করুন"
-
#~ msgid "Default Light Normal:"
#~ msgstr "লাইটের প্রাথমিক নরমাল:"
diff --git a/editor/translations/br.po b/editor/translations/br.po
index 94fec8b3b1..4d03911bbe 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -643,7 +643,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1812,8 +1812,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2447,7 +2447,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2837,14 +2837,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2998,6 +2990,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3200,7 +3208,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3504,6 +3512,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3881,6 +3894,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4828,7 +4857,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4932,7 +4961,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6699,6 +6727,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6750,16 +6786,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6852,8 +6878,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7259,6 +7285,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9598,6 +9629,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9958,6 +9993,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10201,6 +10240,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10321,6 +10368,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10428,6 +10479,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11895,6 +11953,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12150,11 +12216,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index c728113731..01e60b0fac 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -655,7 +655,7 @@ msgstr "Seleccioneu les Pistes a Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -1871,8 +1871,8 @@ msgid "Open a File or Directory"
msgstr "Obre un Fitxer o Directori"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Desa"
@@ -2547,7 +2547,8 @@ msgstr ""
"configuració."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"No s'ha pogut trobar el camp d'Script per al complement a: 'res: // addons /"
"%s'."
@@ -2987,14 +2988,6 @@ msgid "Help"
msgstr "Ajuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Cerca"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentació en línia"
@@ -3166,6 +3159,25 @@ msgid "Open & Run a Script"
msgstr "Obre i Executa un Script"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"El disc conté versions més recents dels fitxer següents. \n"
+"Quina acció voleu seguir?:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Torna a Carregar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Torna a Desar"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nou Heretat"
@@ -3379,7 +3391,7 @@ msgstr "Fes-lo Únic"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Enganxa"
@@ -3702,6 +3714,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "Estat: No s'ha pogut importar. Corregiu el fitxer i torneu a importar."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No es pot moure/reanomenar l'arrel dels recursos."
@@ -4093,6 +4110,25 @@ msgstr ""
msgid "Saving..."
msgstr "Desant..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Mode de selecció"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importa"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Carrega Valors predeterminats"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fitxers"
@@ -5075,7 +5111,8 @@ msgid "Got:"
msgstr "Rebut:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Ha fallat la comprovació del hash sha256"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5184,7 +5221,6 @@ msgid "Sort:"
msgstr "Ordena:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoria:"
@@ -7071,6 +7107,14 @@ msgstr "Tanca la Documentació"
msgid "Run"
msgstr "Executar"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Cerca"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Pas a Pas (per instruccions)"
@@ -7124,16 +7168,6 @@ msgstr ""
"El disc conté versions més recents dels fitxer següents. \n"
"Quina acció voleu seguir?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Torna a Carregar"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Torna a Desar"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Depurador"
@@ -7232,8 +7266,8 @@ msgstr "Punts d’interrupció"
msgid "Go To"
msgstr "Anar a"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Talla"
@@ -7657,6 +7691,11 @@ msgid "View Rotation Locked"
msgstr "Rotació de la Vista Bloquejada"
#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
@@ -10297,6 +10336,11 @@ msgstr "Projecte"
#: editor/project_manager.cpp
#, fuzzy
+msgid "Loading, please wait..."
+msgstr "S'estan buscant rèpliques..."
+
+#: editor/project_manager.cpp
+#, fuzzy
msgid "Last Modified"
msgstr "Última modificació"
@@ -10669,6 +10713,11 @@ msgstr "Càrrega Automàtica"
msgid "Plugins"
msgstr "Connectors"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Carrega Valors predeterminats"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Configuració..."
@@ -10930,6 +10979,16 @@ msgstr "Instancia una Escena Filla"
#: editor/scene_tree_dock.cpp
#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "No es pot operar en Nodes d'una escena externa!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Enganxa els Nodes"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Detach Script"
msgstr "Adjunta-li un Script"
@@ -11064,6 +11123,11 @@ msgid "Attach Script"
msgstr "Adjunta-li un Script"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Talla els Nodes"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Elimina els Nodes"
@@ -11182,6 +11246,13 @@ msgid "Remote"
msgstr "Remot"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -12796,6 +12867,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D buit no té cap efecte en la col·lisió."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -13117,11 +13196,6 @@ msgstr ""
"Les GIProbes no estan suportades pel controlador de vídeo GLES2.\n"
"Utilitzeu un BakedLightmap en el seu lloc."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
#, fuzzy
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index c3be08c016..79163c835f 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -11,25 +11,26 @@
# zxey <r.hozak@seznam.cz>, 2018.
# Vojtěch Šamla <auzkok@seznam.cz>, 2018, 2019, 2020, 2021.
# Peeter Angelo <contact@peeterangelo.com>, 2019.
-# VojtechBrezina <vojta.brezina@gmail.com>, 2019.
+# VojtechBrezina <vojta.brezina@gmail.com>, 2019, 2021.
# Garrom Orc Shaman <garromorcshaman@gmail.com>, 2019.
# David Husička <davidek251@seznam.cz>, 2019.
# Luboš Nečas <lubosnecas506@seznam.cz>, 2019.
# David Kubeš <kubesdavid@email.cz>, 2019.
-# Emil Jiří Tywoniak <emil.tywoniak@gmail.com>, 2020.
+# Emil Jiří Tywoniak <emil.tywoniak@gmail.com>, 2020, 2021.
# Filip Vincůrek <vincurek.f@gmail.com>, 2020.
# Ondrej Pavelka <ondrej.pavelka@outlook.com>, 2020.
-# Zbyněk <zbynek.fiala@gmail.com>, 2020.
+# Zbyněk <zbynek.fiala@gmail.com>, 2020, 2021.
# Daniel Kříž <Daniel.kriz@protonmail.com>, 2020.
# VladimirBlazek <vblazek042@gmail.com>, 2020.
# kubajz22 <til.jakubesko@seznam.cz>, 2020.
# Václav Blažej <vaclavblazej@seznam.cz>, 2020, 2021.
+# ProfJack <profjackcz@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
-"Last-Translator: Václav Blažej <vaclavblazej@seznam.cz>\n"
+"PO-Revision-Date: 2021-04-21 07:35+0000\n"
+"Last-Translator: Zbyněk <zbynek.fiala@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
"Language: cs\n"
@@ -37,7 +38,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -186,11 +187,11 @@ msgstr "Animace: Změna času klíčových snímků"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
-msgstr "Animace: změna přechodů"
+msgstr "Animace: Změna přechodů"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transform"
-msgstr "Animace: změna transformací"
+msgstr "Animace: Změna transformací"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
@@ -198,7 +199,7 @@ msgstr "Animace: Změnit hodnotu klíčových snímků"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
-msgstr "Animace: změna volání"
+msgstr "Animace: Změna více volání"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -292,7 +293,7 @@ msgstr "Čas (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
-msgstr "Přepínací stopa povolena"
+msgstr "Povolit stopu"
#: editor/animation_track_editor.cpp
msgid "Continuous"
@@ -354,7 +355,7 @@ msgstr "Změnit režim interpolace animace"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr "Změnit režim smyčky animace"
+msgstr "Změnit mód smyčky animace"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
@@ -666,7 +667,7 @@ msgstr "Vybrat stopy ke kopírování"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopírovat"
@@ -676,7 +677,7 @@ msgstr "Vybrat vše/nic"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
-msgstr "Přidat klip audio stopy"
+msgstr "Přidat audio klip"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
@@ -1299,7 +1300,7 @@ msgstr "Přepnout bypass efektů na zvukové sběrnice"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
-msgstr "Vybrat přenos zvukové sběrnice"
+msgstr "Vybrat cíl zvukové sběrnice"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
@@ -1867,8 +1868,8 @@ msgid "Open a File or Directory"
msgstr "Otevřít soubor nebo složku"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Uložit"
@@ -2477,7 +2478,7 @@ msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
-"Tato scéna obsahuje neuložené změny.\n"
+"Aktuální scéna obsahuje neuložené změny.\n"
"Přesto znovu načíst? Tuto akci nelze vrátit zpět."
#: editor/editor_node.cpp
@@ -2538,9 +2539,8 @@ msgstr ""
"Nelze povolit rozšiřující plugin: '%s' parsování konfigurace se nezdařilo."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"Nelze najít záznam skriptu pro rozšiřující plugin v: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Nelze najít záznam skriptu pro rozšiřující plugin v: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2967,14 +2967,6 @@ msgid "Help"
msgstr "Nápověda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Hledat"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online dokumentace"
@@ -3139,6 +3131,24 @@ msgid "Open & Run a Script"
msgstr "Otevřít a spustit skript"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Následující soubory mají novější verzi na disku.\n"
+"Jaká akce se má vykonat?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Znovu načíst"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Znovu uložit"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nové zděděné"
@@ -3349,7 +3359,7 @@ msgstr "Vytvořit unikátní"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Vložit"
@@ -3665,6 +3675,12 @@ msgstr ""
"znovu ručně."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Importování tohoto souboru bylo zakázáno, takže jej nelze otevřít pro úpravy."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nelze přesunout/přejmenovat kořen zdrojů."
@@ -4052,6 +4068,22 @@ msgstr "Vrátili jste objekt, který dědí z Node metodou `post_import()`?"
msgid "Saving..."
msgstr "Ukládání..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Vybrat Importér"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importér:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Obnovit výchozí"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Zachovat soubor (bez importu)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d souborů"
@@ -5014,8 +5046,8 @@ msgid "Got:"
msgstr "Staženo:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Neúspěšná kontrola sha256 hashe"
+msgid "Failed SHA-256 hash check"
+msgstr "Neúspěšná kontrola SHA-256 hashe"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5059,11 +5091,11 @@ msgstr "Stahování tohoto assetu právě probíhá!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr "Naposledy upravené"
+msgstr "Nedávno aktualizované"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr "Naposledy neupravené"
+msgstr "Dlouho neaktualizované"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
@@ -5118,7 +5150,6 @@ msgid "Sort:"
msgstr "Řadit podle:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategorie:"
@@ -5152,7 +5183,7 @@ msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"Nelze určit cestu uložení pro světelnou mapu obrázku.\n"
+"Nelze určit cestu pro uložení obrázků světelné mapy.\n"
"Uložte scénu (obrázky se uloží do stejného adresáře) nebo vyberte cestu pro "
"uložení z vlastnosti BakedLightmap."
@@ -6289,9 +6320,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "Bod lze vložit pouze do process materiálu ParticlesMaterial"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Převést na CPUParticles"
+msgstr "Převést na CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6941,6 +6971,14 @@ msgstr "Zavřít dokumentaci"
msgid "Run"
msgstr "Spustit"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Hledat"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Vstoupit do"
@@ -6994,16 +7032,6 @@ msgstr ""
"Následující soubory mají novější verzi na disku.\n"
"Jaká akce se má vykonat?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Znovu načíst"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Znovu uložit"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Ladicí program"
@@ -7076,7 +7104,7 @@ msgstr "Malá písmena"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
-msgstr "Velká písmena"
+msgstr "Velká Písmena"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
@@ -7096,8 +7124,8 @@ msgstr "Breakpointy"
msgid "Go To"
msgstr "Přejít na"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Vyjmout"
@@ -7140,7 +7168,7 @@ msgstr "Duplikovat dolů"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr "Kompletní symbol"
+msgstr "Doplnit symbol"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
@@ -7320,9 +7348,8 @@ msgid "Yaw"
msgstr "Náklon"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Velikost: "
+msgstr "Velikost"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7506,6 +7533,11 @@ msgstr "Rotace pohledu uzamknuta"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9995,6 +10027,10 @@ msgid "Projects"
msgstr "Projekty"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Načítání, prosím čekejte..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Datum modifikace"
@@ -10365,6 +10401,10 @@ msgstr "Autoload"
msgid "Plugins"
msgstr "Pluginy"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Načíst výchozí"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Předvolba..."
@@ -10613,6 +10653,14 @@ msgid "Instance Child Scene"
msgstr "Přidat instanci scény"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Nelze vložit kořenový uzel do stejné scény."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Vložit uzly"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Odpojit skript"
@@ -10739,6 +10787,10 @@ msgid "Attach Script"
msgstr "Připojit skript"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Vyjmout uzly"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Odstranit uzel/uzly"
@@ -10852,6 +10904,13 @@ msgid "Remote"
msgstr "Vzdálený"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Místní"
@@ -11545,36 +11604,32 @@ msgstr "Přiřaďte uzlu GridMap zdroj MeshLibrary k použití jeho sítě."
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "Začít zapečení"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "Připravování datových struktur"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "Vygenerovat AABB"
+msgstr "Vygenerovat buffery"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Směry"
+msgstr "Přímé osvětlení"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "Odsadit zprava"
+msgstr "Nepřímé osvětlení"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "Následné zpracování"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Vykreslení světel:"
+msgstr "Vykreslování světelných map"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12081,9 +12136,8 @@ msgid "Select device from the list"
msgstr "Vyberte zařízení ze seznamu"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Unable to find the 'apksigner' tool."
-msgstr "Nelze najít nástroj zipalign."
+msgstr "Nelze najít nástroj 'apksigner'."
#: platform/android/export/export.cpp
msgid ""
@@ -12105,14 +12159,12 @@ msgstr ""
"Úložiště klíčů pro vydání je nakonfigurováno nesprávně v profilu exportu."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "Nesprávná cesta Android SDK pro vlastní sestavení v Nastavení editoru."
+msgstr "Je vyžadována platná cesta Android SDK v Nastavení editoru."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "Nesprávná cesta Android SDK pro vlastní sestavení v Nastavení editoru."
+msgstr "Neplatná cesta k Android SDK v Nastavení editoru."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
@@ -12120,12 +12172,11 @@ msgstr "Chybí složka \"platform-tools\"!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Nelze najít příkaz adb z nástrojů platformy Android SDK."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "Nesprávná cesta Android SDK pro vlastní sestavení v Nastavení editoru."
+msgstr "Zkontrolujte ve složce Android SDK uvedené v Nastavení editoru."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
@@ -12133,7 +12184,7 @@ msgstr "Chybí složka \"build-tools\"!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Nelze najít apksigner, nástrojů Android SDK."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12391,6 +12442,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Prázdný CollisionPolygon2D nemá při kolizi žádný efekt."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "Chybný polygon. Alespoň 3 body jsou potřeba v 'Solids' build módu."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "Chybný polygon. Alespoň 2 body jsou potřeba v 'Segments' build módu."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12594,27 +12653,23 @@ msgstr "ARVROrigin musí mít uzel ARVRCamera jako potomka."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "Hledat mřížky a světla"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Parsuji geometrii..."
+msgstr "Připravuji geometrii (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Zobrazit prostředí"
+msgstr "Připravuji prostředí"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "Generování světelné mapy"
+msgstr "Generování snímání"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Generování světelné mapy"
+msgstr "Ukládám světelné mapy"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
@@ -12704,11 +12759,6 @@ msgstr ""
"Video driver GLES2 nepodporuje GIProby.\n"
"Místo toho použijte BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "Uzel InterpolatedCamera je zastaralý a bude odstraněn v Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight s úhlem širším než 90 stupňů nemůže vrhat stíny."
@@ -13017,6 +13067,8 @@ msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
+"Sampler port je připojen, ale není použitý. Zvažte změnu zdroje na "
+"'SamplerPort'."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
@@ -13046,6 +13098,10 @@ msgstr "Odlišnosti mohou být přiřazeny pouze ve vertex funkci."
msgid "Constants cannot be modified."
msgstr "Konstanty není možné upravovat."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "Uzel InterpolatedCamera je zastaralý a bude odstraněn v Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Ne"
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 2231930b01..01d6dbc42e 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
+"PO-Revision-Date: 2021-03-20 04:18+0000\n"
"Last-Translator: snakatk <snaqii@live.dk>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/godot-engine/"
"godot/da/>\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -406,7 +406,7 @@ msgstr "Anim Indsæt Nøgle"
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Change Animation Step"
-msgstr "Ændre Animation Navn:"
+msgstr "Ændre animationsskridt"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -549,7 +549,7 @@ msgstr "Grupper spor efter node eller vis dem som almindelig liste."
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Snap:"
-msgstr "Trin: "
+msgstr "Trin:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -595,8 +595,9 @@ msgid "Duplicate Selection"
msgstr "Duplikér Valgte"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Duplicate Transposed"
-msgstr "Duplicate transposed"
+msgstr "Duplikér Transposed"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -673,14 +674,14 @@ msgstr "Skalaforhold:"
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "Vælg spor til kopiering:"
+msgstr "Vælg spor til kopiering"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopier"
@@ -690,9 +691,8 @@ msgid "Select All/None"
msgstr "Vælg Node"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Add Audio Track Clip"
-msgstr "Lydklip:"
+msgstr "Tilføj lydspor klip"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
@@ -798,7 +798,7 @@ msgstr "Metode i target Node skal angives!"
#: editor/connections_dialog.cpp
#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Navnet er ikke et gyldigt id:"
+msgstr "Metodenavnet er ikke et gyldigt id."
#: editor/connections_dialog.cpp
#, fuzzy
@@ -856,7 +856,7 @@ msgstr "Ekstra Call Argumenter:"
#: editor/connections_dialog.cpp
#, fuzzy
msgid "Receiver Method:"
-msgstr "Vælg Method"
+msgstr "Modtager Metode:"
#: editor/connections_dialog.cpp
#, fuzzy
@@ -936,9 +936,8 @@ msgid "Connect a Signal to a Method"
msgstr "Forbind Signal: "
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Edit Connection:"
-msgstr "Redigere Forbindelse: "
+msgstr "Redigér Forbindelse:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
@@ -1082,14 +1081,15 @@ msgid "Owners Of:"
msgstr "Ejere af:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Fjern de valgte filer fra projektet? (ej fortrydes)"
+msgstr ""
+"Fjern de valgte filer fra projektet? (ej fortrydes)\n"
+"Du kan finde de fjernede filer i systemets skraldespand for at genoprette "
+"dem."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1097,7 +1097,9 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"De filer der fjernes er nødvendige for, at andre ressourcer kan fungere.\n"
-"Fjern dem alligevel? (ej fortrydes)"
+"Fjern dem alligevel? (ej fortrydes)\n"
+"Du kan finde de fjernede filer i systemets skraldespand for at genoprette "
+"dem."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1129,7 +1131,7 @@ msgstr "Fejl ved indlæsning!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Slette %d styk(s) permanent? (ej fortryd)"
+msgstr "Slet %d styk(s) permanent? (ej fortrydes)"
#: editor/dependency_editor.cpp
#, fuzzy
@@ -1204,14 +1206,12 @@ msgid "Gold Sponsors"
msgstr "Guld Sponsorer"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Sølv Donorer"
+msgstr "Sølv Sponsorer"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Bronze Donorer"
+msgstr "Bronze Sponsorer"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1238,22 +1238,21 @@ msgid "License"
msgstr "Licens"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Third-party Licenses"
-msgstr "Tredjeparts Licens"
+msgstr "Tredjepartslicenser"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
-"Godot Engine er afhængig af en række tredjeparts biblioteker som er gratis "
+"Godot Engine er afhængig af en række tredjepartsbiblioteker, som er gratis "
"og open source. Alle bibliotekerne er kompatible med vilkårene i MIT-"
-"licensen. Følgende er en udtømmende liste over alle sådanne tredjeparts "
-"komponenter med deres respektive ophavsretlige udsagn og licensbetingelser."
+"licensen. Følgende er en udtømmende liste over alle sådanne "
+"tredjepartskomponenter med deres respektive ophavsretlige udsagn og "
+"licensbetingelser."
#: editor/editor_about.cpp
msgid "All Components"
@@ -1268,9 +1267,8 @@ msgid "Licenses"
msgstr "Licenser"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file, not in ZIP format."
-msgstr "Fejl ved åbning af pakke fil, ikke i zip format."
+msgstr "Fejl ved åbning af pakkefil, ikke i ZIP-format."
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -1286,9 +1284,8 @@ msgid "The following files failed extraction from package:"
msgstr "De følgende filer kunne ikke trækkes ud af pakken:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "And %s more files."
-msgstr "%d flere filer"
+msgstr "Og %s flere filer."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
@@ -1380,7 +1377,7 @@ msgstr "Bus muligheder"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "Duplikere"
+msgstr "Duplikér"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -1431,12 +1428,10 @@ msgid "Open Audio Bus Layout"
msgstr "Åben Audio Bus Layout"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "There is no '%s' file."
msgstr "Der er ingen '%s' fil."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Layout"
msgstr "Layout"
@@ -1454,9 +1449,8 @@ msgid "Add Bus"
msgstr "Tilføj Bus"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Add a new Audio Bus to this layout."
-msgstr "Gem Audio Bus Layout Som..."
+msgstr "Tilføj en ny Audio Bus til dette layout."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1550,9 +1544,8 @@ msgid "Rearrange Autoloads"
msgstr "Flytte om på Autoloads"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Can't add autoload:"
-msgstr "Kan ikke tilføje autoload:"
+msgstr "Autoload kan ikke tilføjes:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1604,9 +1597,8 @@ msgid "[unsaved]"
msgstr "[ikke gemt]"
#: editor/editor_dir_dialog.cpp
-#, fuzzy
msgid "Please select a base directory first."
-msgstr "Vælg en basis mappe først"
+msgstr "Vælg en basismappe først."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
@@ -1639,9 +1631,8 @@ msgid "Storing File:"
msgstr "Lagrings Fil:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "No export template found at the expected path:"
-msgstr "Ingen eksporterings-skabelon fundet ved den forventede sti:"
+msgstr "Ingen eksporterings-skabelon fundet på den forventede sti:"
#: editor/editor_export.cpp
msgid "Packing"
@@ -1652,12 +1643,16 @@ msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"Målplatform kræver 'ETC' teksturkomprimering for GLES2. Aktivér 'Import Etc' "
+"i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"Målplatform kræver 'ETC2' teksturkomprimering for GLES3. Aktivér 'Import Etc "
+"2' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
@@ -1666,18 +1661,25 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Målplatform kræver 'ETC' teksturkomprimering for driver fallback til GLES2.\n"
+"Aktivér 'Import Etc' i Projektindstillingerne, eller deaktivér 'Driver "
+"Fallback Aktiveret'."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"Målplatform kræver 'PVRTC' teksturkomprimering for GLES2. Aktivér 'Import "
+"Pvrtc' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"Målplatformen kræver 'ETC2' eller 'PVRTC' teksturkomprimering for GLES3. "
+"Aktivér 'Import Etc 2' eller 'Import Pvrtc' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
@@ -1686,19 +1688,22 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Målplatform kræver 'PVRTC' teksturkomprimering for driver fallback til "
+"GLES2.\n"
+"Aktivér 'Import Pvrtc' i Projektindstillingerne, eller deaktivér 'Driver "
+"Fallback Aktiveret'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
-#, fuzzy
msgid "Custom debug template not found."
-msgstr "Skabelonfil ikke fundet:"
+msgstr "Brugerdefineret debug skabelonfil ikke fundet."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr ""
+msgstr "Brugerdefineret release skabelonfil ikke fundet."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
@@ -1706,7 +1711,7 @@ msgstr "Skabelonfil ikke fundet:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
-msgstr ""
+msgstr "Den indlejrede PCK kan ikke overstige 4 GiB ved 32-bit eksport."
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1743,13 +1748,12 @@ msgid "Import Dock"
msgstr "Importer"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Erase profile '%s'? (no undo)"
-msgstr "Erstat Alle"
+msgstr "Slet profil '%s'? (kan ikke fortrydes)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profil skal være et gyldigt filnavn og må ikke indeholde '.'"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1793,7 +1797,7 @@ msgstr "Funktions Liste:"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Enabled Classes:"
-msgstr "Søg Classes"
+msgstr "Aktiverede Classes:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -1828,7 +1832,7 @@ msgstr "(Nuværende)"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "New"
-msgstr ""
+msgstr "Ny"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
@@ -1938,8 +1942,8 @@ msgid "Open a File or Directory"
msgstr "Åben en Fil eller Mappe"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Gem"
@@ -2070,14 +2074,13 @@ msgid "Inherited by:"
msgstr "Arvet af:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Beskrivelse:"
+msgstr "Beskrivelse"
#: editor/editor_help.cpp
#, fuzzy
msgid "Online Tutorials"
-msgstr "Online Undervisning:"
+msgstr "Online Vejledninger"
#: editor/editor_help.cpp
msgid "Properties"
@@ -2088,9 +2091,8 @@ msgid "override:"
msgstr ""
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Standard"
+msgstr "standardindstilling:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2113,9 +2115,8 @@ msgid "Property Descriptions"
msgstr "Egenskab beskrivelser"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Værdi:"
+msgstr "(værdi)"
#: editor/editor_help.cpp
msgid ""
@@ -2626,7 +2627,8 @@ msgstr ""
"mislykkedes."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "Kan ikke finde scriptfelt for addon plugin på: 'res://addons/%s'."
#: editor/editor_node.cpp
@@ -2875,7 +2877,7 @@ msgstr "Projekt Indstillinger"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
msgid "Version Control"
-msgstr "Version:"
+msgstr "Versionskontrol"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
@@ -3072,14 +3074,6 @@ msgid "Help"
msgstr "Hjælp"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Søg"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Dokumentation"
@@ -3240,6 +3234,23 @@ msgid "Open & Run a Script"
msgstr "Åben & Kør et Script"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "De følgende filer kunne ikke trækkes ud af pakken:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Ny Arved"
@@ -3448,7 +3459,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Indsæt"
@@ -3759,14 +3770,17 @@ msgid "Favorites"
msgstr "Favoritter"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
-"\n"
"Status: Import af filen fejlede. Venligst reparer filen og genimporter "
"manuelt."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kan ikke flytte/omdøbe resourcen root."
@@ -4189,6 +4203,25 @@ msgstr ""
msgid "Saving..."
msgstr "Gemmer..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Vælg Node"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importer"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Indlæs Default"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -5217,7 +5250,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5324,7 +5357,6 @@ msgid "Sort:"
msgstr "Sorter:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategori:"
@@ -7180,6 +7212,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Søg"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7233,16 +7273,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7343,8 +7373,8 @@ msgstr "Slet points"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Cut"
@@ -7770,6 +7800,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9968,9 +10003,8 @@ msgid "Export All"
msgstr "Eksporter"
#: editor/project_export.cpp editor/project_manager.cpp
-#, fuzzy
msgid "ZIP File"
-msgstr " Filer"
+msgstr "ZIP-Fil"
#: editor/project_export.cpp
msgid "Godot Game Pack"
@@ -10253,6 +10287,11 @@ msgid "Projects"
msgstr "Projekt"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Henter spejle, vent venligst ..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10625,6 +10664,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Indlæs Default"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Forudindstillet..."
@@ -10880,6 +10924,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Indsæt Node"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Ryd Script"
@@ -11010,6 +11063,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Indsæt Node"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -11125,6 +11183,13 @@ msgid "Remote"
msgstr "Fjern"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12703,6 +12768,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "En tom CollisionPolygon2D har ingen effekt på kollision."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12992,11 +13065,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13554,10 +13622,6 @@ msgstr "Konstanter kan ikke ændres."
#~ msgid "Create folder"
#~ msgstr "Opret mappe"
-#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Indsæt Node"
-
#~ msgid "Invalid Path"
#~ msgstr "Ugyldig sti"
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 79b57dac4e..9b49a15db4 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -62,11 +62,16 @@
# Patric Wust <patric.wust@gmx.de>, 2020.
# Jonathan Hassel <jonathan.hassel@icloud.com>, 2020.
# Artur Schönfeld <schoenfeld.artur@ymail.com>, 2020.
+# kidinashell <kidinashell@protonmail.com>, 2021.
+# Daniel Glocker <mystboy666@gmail.com>, 2021.
+# Raphipod <podraphi@googlemail.com>, 2021.
+# Daniel Plaster <danimineiromc@googlemail.com>, 2021.
+# El Captian <elcaptian@posteo.me>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-16 01:28+0000\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
@@ -75,7 +80,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -707,7 +712,7 @@ msgstr "Zu kopierende Spuren auswählen"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopieren"
@@ -1920,8 +1925,8 @@ msgid "Open a File or Directory"
msgstr "Datei oder Verzeichnis öffnen"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Speichern"
@@ -2442,7 +2447,7 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
-"Dies ist ein nicht-lokales Objekt, Änderungen an ihm werden nicht "
+"Dies ist ein Laufzeit-Objekt Objekt, Änderungen an ihm werden nicht "
"gespeichert.\n"
"Die Dokumentation zum Debugging beschreibt den nötigen Arbeitsablauf."
@@ -2601,7 +2606,7 @@ msgstr ""
"fehlgeschlagen."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Skript-Feld für Erweiterung in ‚res://addons/%s‘ konnte nicht gefunden "
"werden."
@@ -3042,14 +3047,6 @@ msgid "Help"
msgstr "Hilfe"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Suchen"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Internetdokumentation"
@@ -3068,7 +3065,7 @@ msgstr "Dokumentationsvorschläge senden"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr "Community"
+msgstr "Gemeinschaft"
#: editor/editor_node.cpp
msgid "About"
@@ -3215,6 +3212,24 @@ msgid "Open & Run a Script"
msgstr "Skript öffnen und ausführen"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Die folgenden Dateien wurden im Dateisystem verändert.\n"
+"Wie soll weiter vorgegangen werden?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Neu laden"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Erneut speichern"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Neu Geerbte"
@@ -3426,7 +3441,7 @@ msgstr "Einzigartig machen"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Einfügen"
@@ -3743,6 +3758,13 @@ msgstr ""
"Status: Dateiimport fehlgeschlagen. Manuelle Reparatur und Neuimport nötig."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Für diese Datei wurde die Import-Funktion deaktiviert, sie kann folglich "
+"nicht zum Bearbeiten geöffnet werden."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ressourcen-Wurzel kann nicht verschoben oder umbenannt werden."
@@ -4132,6 +4154,22 @@ msgstr ""
msgid "Saving..."
msgstr "Speichere..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Importer auswählen"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importer:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Auf Standardwerte zurücksetzen"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Datei behalten (kein Import)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Dateien"
@@ -4895,7 +4933,7 @@ msgstr "Abspielmodus:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr "AnimationTree"
+msgstr "AnimationsBaum"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -5102,8 +5140,8 @@ msgid "Got:"
msgstr "Erhalten:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Sha256-Prüfung fehlgeschlagen"
+msgid "Failed SHA-256 hash check"
+msgstr "Sha256 Checksummen prüfung fehlgeschlagen"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5206,7 +5244,6 @@ msgid "Sort:"
msgstr "Sortiere:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategorie:"
@@ -5261,7 +5298,7 @@ msgstr ""
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
msgstr ""
"Die Größe des Lightmaps kann nicht bestimmt werden. Möglicherweise ist die "
-"maximale Lightmap-Größe zu klein."
+"maximale Lightmap-Größe zu klein?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -7042,6 +7079,14 @@ msgstr "Dokumentation schließen"
msgid "Run"
msgstr "Ausführen"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Suchen"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Hineinspringen"
@@ -7095,16 +7140,6 @@ msgstr ""
"Die folgenden Dateien wurden im Dateisystem verändert.\n"
"Wie soll weiter vorgegangen werden?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Neu laden"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Erneut speichern"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Debugger"
@@ -7200,8 +7235,8 @@ msgstr "Haltepunkte"
msgid "Go To"
msgstr "Springe zu"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Ausschneiden"
@@ -7343,7 +7378,7 @@ msgstr "Knochen in Ruhe-Pose setzen"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Skeleton2D"
-msgstr "Skeleton2D"
+msgstr "Skelett2D"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Make Rest Pose (From Bones)"
@@ -7426,9 +7461,8 @@ msgid "Yaw"
msgstr "Gieren"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Größe: "
+msgstr "Größe"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7452,7 +7486,7 @@ msgstr "Zeichenaufrufe"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Vertices"
-msgstr "Vertices"
+msgstr "Eckpunkte"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -7613,6 +7647,11 @@ msgstr "Sichtrotation gesperrt"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8505,7 +8544,7 @@ msgstr "Keine Textur zum Entfernen ausgewählt."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from scene? This will overwrite all current tiles."
-msgstr "Aus Szene erstellen? Alle aktuellen Kacheln werden überschrieben!"
+msgstr "Aus Szene erstellen? Alle aktuellen Kacheln werden überschrieben."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Merge from scene?"
@@ -9639,7 +9678,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "VisualShader"
-msgstr "VisualShader"
+msgstr "VisuellerShader"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Edit Visual Property"
@@ -10128,6 +10167,10 @@ msgid "Projects"
msgstr "Projekte"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Projekte werden geladen, bitte warten..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Zuletzt bearbeitet"
@@ -10500,6 +10543,10 @@ msgstr "Autoload"
msgid "Plugins"
msgstr "Erweiterungen"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Standardwerte importieren"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Voreinstellungen..."
@@ -10751,6 +10798,14 @@ msgid "Instance Child Scene"
msgstr "Szene hier instantiieren"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Einfügen der Wurzelnode in dieselbe Szene nicht möglich."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Node(s) einfügen"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Skript loslösen"
@@ -10878,6 +10933,10 @@ msgid "Attach Script"
msgstr "Skript hinzufügen"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Node(s) trennen"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Entferne Node(s)"
@@ -10991,6 +11050,13 @@ msgid "Remote"
msgstr "Fern"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokal"
@@ -11517,7 +11583,7 @@ msgstr "Bibliotheken: "
#: modules/gdnative/register_types.cpp
msgid "GDNative"
-msgstr "GDNative"
+msgstr "GDNativ"
#: modules/gdscript/gdscript_functions.cpp
msgid "Step argument is zero!"
@@ -12548,6 +12614,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Ein leeres CollisionPolygon2D hat keinen Effekt auf Kollisionen."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Ungültiges Polygon. Mindestens drei Punkte werden im ‚Festkörper‘-Baumodus "
+"benötigt."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Ungültiges Polygon. Mindestens zwei Punkte werden im ‚Segment‘-Baumodus "
+"benötigt."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12877,11 +12955,6 @@ msgstr ""
"GIProbes werden vom GLES2-Videotreiber nicht unterstützt.\n"
"BakedLightmaps können als Alternative verwendet werden."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera ist veraltet und wird in Godot 4.0 entfernt werden."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13240,6 +13313,11 @@ msgstr "Varyings können nur in Vertex-Funktion zugewiesen werden."
msgid "Constants cannot be modified."
msgstr "Konstanten können nicht verändert werden."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera ist veraltet und wird in Godot 4.0 entfernt werden."
+
#~ msgid "No"
#~ msgstr "Nein"
@@ -15083,9 +15161,6 @@ msgstr "Konstanten können nicht verändert werden."
#~ msgid "Use Default Light"
#~ msgstr "Nutze Standardlicht"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Nutze Standard-sRGB"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Standardlichtnormale:"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index 5c298ea575..1c44e9dd5c 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -621,7 +621,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1790,8 +1790,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2425,7 +2425,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2815,14 +2815,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2976,6 +2968,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3178,7 +3186,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3482,6 +3490,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3859,6 +3872,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4806,7 +4835,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4910,7 +4939,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6677,6 +6705,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6728,16 +6764,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6830,8 +6856,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7237,6 +7263,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9576,6 +9607,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9936,6 +9971,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10179,6 +10218,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10299,6 +10346,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10406,6 +10457,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11873,6 +11931,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12128,11 +12194,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index abbfbaedfc..4648f83a72 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -10,12 +10,14 @@
# pandektis <pandektis@gmail.com>, 2020.
# KostasMSC <kargyris@athtech.gr>, 2020.
# lawfulRobot <czavantias@gmail.com>, 2020.
+# Michalis <michalisntovas@yahoo.gr>, 2021.
+# leriaz <leriaz@live.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-09-30 12:32+0000\n"
-"Last-Translator: lawfulRobot <czavantias@gmail.com>\n"
+"PO-Revision-Date: 2021-03-29 21:57+0000\n"
+"Last-Translator: leriaz <leriaz@live.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/"
"el/>\n"
"Language: el\n"
@@ -23,7 +25,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -656,7 +658,7 @@ msgstr "Επιλογή Κομματιών για Αντιγραφή"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Αντιγραφή"
@@ -824,7 +826,7 @@ msgstr "Μέθοδος Δέκτη:"
#: editor/connections_dialog.cpp
msgid "Advanced"
-msgstr "Για Προχωρημένους"
+msgstr "Για προχωρημένους"
#: editor/connections_dialog.cpp
msgid "Deferred"
@@ -1040,11 +1042,13 @@ msgid "Owners Of:"
msgstr "Ιδιοκτήτες του:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Αφαίρεση επιλεγμένων αρχείων από το έργο; (Αδυναμία αναίρεσης)"
+msgstr ""
+"Αφαίρεση επιλεγμένων αρχείων από το έργο; (Αδυναμία αναίρεσης)\n"
+"Μπορείτε να βρείτε τα διεγραμμένα αρχεία στον κάδο ανακύκλωσης για να τα "
+"επαναφέρετε."
#: editor/dependency_editor.cpp
#, fuzzy
@@ -1866,8 +1870,8 @@ msgid "Open a File or Directory"
msgstr "Άνοιγμα αρχείου ή φακέλου"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Αποθήκευση"
@@ -1878,7 +1882,7 @@ msgstr "Αποθήκευση αρχείου"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr "Πήγαινε πίσω"
+msgstr "Επιστροφή"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
@@ -2542,7 +2546,8 @@ msgstr ""
"αρχείου ρύθμισης."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Αδύνατη η έυρεση του πεδίου 'script' για την πρόσθετη επέκταση στο: 'res://"
"addons/%s'."
@@ -2983,14 +2988,6 @@ msgid "Help"
msgstr "Βοήθεια"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Αναζήτηση"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Ηλεκτρονική τεκμηρίωση"
@@ -3158,6 +3155,25 @@ msgid "Open & Run a Script"
msgstr "Άνοιξε & Τρέξε μία δέσμη ενεργειών"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Τα ακόλουθα αρχεία είναι νεότερα στον δίσκο.\n"
+"Τι δράση να ληφθεί;:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Επαναφόρτωση"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Επαναποθήκευση"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Νέα κληρονομημένη"
@@ -3368,7 +3384,7 @@ msgstr "Κάνε μοναδικό"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Επικόλληση"
@@ -3687,6 +3703,11 @@ msgstr ""
"επανεισάγετε το χειροκίνητα."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Δεν ήταν δυνατή η μετακίνηση/μετονομασία του πηγαίου καταλόγου."
@@ -3905,7 +3926,7 @@ msgstr "Αντικατάσταση..."
#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
msgid "Cancel"
-msgstr "Ακύρωση"
+msgstr "Άκυρο"
#: editor/find_in_files.cpp
msgid "Find: "
@@ -4075,6 +4096,25 @@ msgstr ""
msgid "Saving..."
msgstr "Αποθήκευση..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Επιλογή Λειτουργίας"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Εισαγωγή"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Χρήση προεπιλεγμένου sRGB"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d αρχεία"
@@ -5045,7 +5085,8 @@ msgid "Got:"
msgstr "Δοσμένο:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Η δοκιμή κατακερματισμού sha256 απέτυχε"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5149,7 +5190,6 @@ msgid "Sort:"
msgstr "Ταξινόμηση:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Κατηγορία:"
@@ -7000,6 +7040,14 @@ msgstr "Κλείσιμο Τεκμηρίωσης"
msgid "Run"
msgstr "Εκτέλεση"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Αναζήτηση"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Βήμα μέσα"
@@ -7015,7 +7063,7 @@ msgstr "Διακοπή"
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
#: editor/script_editor_debugger.cpp
msgid "Continue"
-msgstr "Συνέχιση"
+msgstr "Συνέχεια"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
@@ -7053,16 +7101,6 @@ msgstr ""
"Τα ακόλουθα αρχεία είναι νεότερα στον δίσκο.\n"
"Τι δράση να ληφθεί;:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Επαναφόρτωση"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Επαναποθήκευση"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Αποσφαλματωτής"
@@ -7159,8 +7197,8 @@ msgstr "Σημεία Διακοπής"
msgid "Go To"
msgstr "Πήγαινε Σε"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Αποκοπή"
@@ -7572,6 +7610,11 @@ msgstr "Κλείδωμα Περιστροφής"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8650,7 +8693,7 @@ msgstr "Κανένα αρχείο δεν προστέθηκε στο στάδι
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit"
-msgstr "Δέσμευση"
+msgstr "Υποβολή"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "VCS Addon is not initialized"
@@ -10086,6 +10129,11 @@ msgid "Projects"
msgstr "Έργα"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Ανάκτηση δεδοένων κατοπτρισμού, παρακαλώ περιμένετε..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Τελευταία Τροποποιημένα"
@@ -10456,6 +10504,11 @@ msgstr "Αυτόματη φόρτωση"
msgid "Plugins"
msgstr "Πρόσθετα"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Φόρτωση προεπιλογής"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Διαμόρφωση..."
@@ -10705,6 +10758,16 @@ msgid "Instance Child Scene"
msgstr "Αρχικοποίηση σκηνής ως παιδί"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "Δεν είναι δυνατή η λειτουργία σε κόμβους από ξένη σκηνή!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Επικόλληση κόμβων"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Αποσύνδεση Δέσμης Ενεργειών"
@@ -10837,6 +10900,11 @@ msgid "Attach Script"
msgstr "Σύνδεση Δέσμης Ενεργειών"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Αποκοπή κόμβων"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Αφαίρεση κόμβων"
@@ -10951,6 +11019,13 @@ msgid "Remote"
msgstr "Απομακρυσμένο"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Τοπικό"
@@ -12515,6 +12590,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Ένα άδειο ColisionPollygon2D δεν επηρεάζει τη σύγκρουση."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12842,11 +12925,6 @@ msgstr ""
"Τα GIProbes δεν υποστηρίζονται από το πρόγραμμα οδήγησης οθόνης GLES2.\n"
"Εναλλακτικά, χρησιμοποιήστε ένα BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "Η InterpolatedCamera έχει καταργηθεί και θα αφαιρεθεί στο Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13194,6 +13272,11 @@ msgstr "Τα «varying» μπορούν να ανατεθούν μόνο στη
msgid "Constants cannot be modified."
msgstr "Οι σταθερές δεν μπορούν να τροποποιηθούν."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "Η InterpolatedCamera έχει καταργηθεί και θα αφαιρεθεί στο Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Όχι"
@@ -15022,9 +15105,6 @@ msgstr "Οι σταθερές δεν μπορούν να τροποποιηθο
#~ msgid "Use Default Light"
#~ msgstr "Χρήση προεπιλεγμέου φωτός"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Χρήση προεπιλεγμένου sRGB"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Προεπιλεγμένο διάνυσμα κανονικής ανάκλασης φωτός:"
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 64b727be90..3fe7877be0 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -10,18 +10,21 @@
# Sr Half <flavio05@outlook.com>, 2020.
# Cristian Yepez <cristianyepez@gmail.com>, 2020.
# BinotaLIU <me@binota.org>, 2020.
+# Jakub Fabijan <animatorzPolski@gmail.com>, 2021.
+# mourning20s <mourning20s@protonmail.com>, 2021.
+# Manuel González <mgoopazo@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-11-20 23:08+0000\n"
-"Last-Translator: BinotaLIU <me@binota.org>\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: mourning20s <mourning20s@protonmail.com>\n"
"Language-Team: Esperanto <https://hosted.weblate.org/projects/godot-engine/"
"godot/eo/>\n"
"Language: eo\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -504,7 +507,7 @@ msgstr "Averto: Redaktanti importis animadon"
#: editor/animation_track_editor.cpp
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr ""
+msgstr "Selektu AnimationPlayer nodo por krei kaj redakti animadoj."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
@@ -646,14 +649,13 @@ msgstr "Elekti vojetojn por duplikati"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Duplikati"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select All/None"
-msgstr "Elektaro nur"
+msgstr "Elekti Ĉiuj/Neniuj"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
@@ -688,19 +690,16 @@ msgid "Line Number:"
msgstr "Lineo-Numeron:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Anstataŭigi..."
+msgstr "%d anstataŭiĝis."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d match."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekono."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekonoj."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -729,7 +728,7 @@ msgstr "Norma"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr ""
+msgstr "Baskuli Skriptoj Panelo"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -760,17 +759,15 @@ msgid "Method in target node must be specified."
msgstr "Metodo en celo nodo devas esti specifita."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Metodo en celo nodo devas esti specifita."
+msgstr "La nomo de la metodo devas esti valida identigilo."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"Celo metodo maltrovita. Indiku ekzistanta metodo aŭ ligu la skripto al celo "
+"Cela metodo maltrovitas. Specifu valida metodo aŭ ligu skripto al la cela "
"nodo."
#: editor/connections_dialog.cpp
@@ -816,7 +813,7 @@ msgstr "Aldona argumentoj de alvoko:"
#: editor/connections_dialog.cpp
msgid "Receiver Method:"
-msgstr ""
+msgstr "Ricevila metodo:"
#: editor/connections_dialog.cpp
msgid "Advanced"
@@ -898,20 +895,19 @@ msgstr "Redakti Konekton:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
-msgstr ""
+msgstr "Ĉu vi certe volas forigi ĉiajn konektojn el la \"%s\" signalo?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
msgstr "Signaloj"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Filtri nodojn"
+msgstr "Filtri signalojn"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
-msgstr ""
+msgstr "Ĉu vi certe volas forigi ĉiajn konektojn el la ĉi tiu signalo?"
#: editor/connections_dialog.cpp
msgid "Disconnect All"
@@ -944,7 +940,7 @@ msgstr "Favoritaj:"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
msgid "Recent:"
-msgstr ""
+msgstr "Lastatempe:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
@@ -968,23 +964,27 @@ msgstr "Priskribo:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr ""
+msgstr "Serĉi anstataŭigo por:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr ""
+msgstr "Dependoj por:"
#: editor/dependency_editor.cpp
msgid ""
"Scene '%s' is currently being edited.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"La sceno '%s' redaktadas nune.\n"
+"Ŝanĝoj nur efektiviĝos je reŝargo."
#: editor/dependency_editor.cpp
msgid ""
"Resource '%s' is in use.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"La risurco '%s' en uzo.\n"
+"Ŝanĝoj nur efektiviĝos je reŝargo."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1006,15 +1006,15 @@ msgstr "Dependecoj:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
-msgstr ""
+msgstr "Ripari difekta"
#: editor/dependency_editor.cpp
msgid "Dependency Editor"
-msgstr ""
+msgstr "Redaktilo de Dependoj"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
-msgstr ""
+msgstr "Serĉi anstataŭiga risurco:"
#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
#: editor/editor_help_search.cpp editor/editor_node.cpp
@@ -1024,17 +1024,19 @@ msgstr ""
#: modules/visual_script/visual_script_property_selector.cpp
#: scene/gui/file_dialog.cpp
msgid "Open"
-msgstr ""
+msgstr "Malfermi"
#: editor/dependency_editor.cpp
msgid "Owners Of:"
-msgstr ""
+msgstr "Proprietuloj de:"
#: editor/dependency_editor.cpp
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"Forigi selektajn dosierojn el la projekto? (ne malfaro)\n"
+"Vi povas trovi la forigajn dosierojn en la sistema rubujo por restaŭri ilin."
#: editor/dependency_editor.cpp
msgid ""
@@ -1043,46 +1045,49 @@ msgid ""
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"La forigotaj dosieroj bezonas por ke aliaj risurcoj funkciadi.\n"
+"Forigu ilin iel? (ne malfaro)\n"
+"Vi povas trovi la forigajn dosierojn en la sistema rubujo por restaŭri ilin."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
-msgstr ""
+msgstr "Ne povas forigi:"
#: editor/dependency_editor.cpp
msgid "Error loading:"
-msgstr ""
+msgstr "Eraro dum ŝargado:"
#: editor/dependency_editor.cpp
msgid "Load failed due to missing dependencies:"
-msgstr ""
+msgstr "Ŝargado malplenumis pro mankaj dependoj:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
-msgstr ""
+msgstr "Malfermi iel"
#: editor/dependency_editor.cpp
msgid "Which action should be taken?"
-msgstr ""
+msgstr "Kiu ago devu preni?"
#: editor/dependency_editor.cpp
msgid "Fix Dependencies"
-msgstr ""
+msgstr "Ripari dependojn"
#: editor/dependency_editor.cpp
msgid "Errors loading!"
-msgstr ""
+msgstr "Eraroj dum ŝargado!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr ""
+msgstr "Permanente forigi %d elemento(j)n? (Ne malfaro!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
-msgstr ""
+msgstr "Vidigi Dependojn"
#: editor/dependency_editor.cpp
msgid "Orphan Resource Explorer"
-msgstr ""
+msgstr "Esploranto de orfaj risurcoj"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
@@ -1090,98 +1095,98 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
msgid "Delete"
-msgstr ""
+msgstr "Forigi"
#: editor/dependency_editor.cpp
msgid "Owns"
-msgstr ""
+msgstr "Posede"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Risurcoj sen eksplicita proprieto:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
-msgstr ""
+msgstr "Ŝanĝi la vortaran ŝlosilon"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Value"
-msgstr ""
+msgstr "Ŝanĝi la vortaran valoron"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
-msgstr ""
+msgstr "Dankon de la komunumo de Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr ""
+msgstr "Kontribuantoj de Godot Engine"
#: editor/editor_about.cpp
msgid "Project Founders"
-msgstr ""
+msgstr "Fondintoj de la Projekto"
#: editor/editor_about.cpp
msgid "Lead Developer"
-msgstr ""
+msgstr "Ĉefprogramisto"
#. TRANSLATORS: This refers to a job title.
#. The trailing space is used to distinguish with the project list application,
#. you do not have to keep it in your translation.
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr ""
+msgstr "Projektadministrilo "
#: editor/editor_about.cpp
msgid "Developers"
-msgstr ""
+msgstr "Programistoj"
#: editor/editor_about.cpp
msgid "Authors"
-msgstr ""
+msgstr "Aŭtoroj"
#: editor/editor_about.cpp
msgid "Platinum Sponsors"
-msgstr ""
+msgstr "Platenaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Gold Sponsors"
-msgstr ""
+msgstr "Oraj Sponsoroj"
#: editor/editor_about.cpp
msgid "Silver Sponsors"
-msgstr ""
+msgstr "Arĝentaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Bronze Sponsors"
-msgstr ""
+msgstr "Bronzaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
-msgstr ""
+msgstr "Minisponsoroj"
#: editor/editor_about.cpp
msgid "Gold Donors"
-msgstr ""
+msgstr "Oraj Donacantoj"
#: editor/editor_about.cpp
msgid "Silver Donors"
-msgstr ""
+msgstr "Arĝentaj Donacantoj"
#: editor/editor_about.cpp
msgid "Bronze Donors"
-msgstr ""
+msgstr "Bronzaj Donacantoj"
#: editor/editor_about.cpp
msgid "Donors"
-msgstr ""
+msgstr "Donacantoj"
#: editor/editor_about.cpp
msgid "License"
-msgstr ""
+msgstr "Permesilo"
#: editor/editor_about.cpp
msgid "Third-party Licenses"
-msgstr ""
+msgstr "Permesiloj de eksteraj liverantoj"
#: editor/editor_about.cpp
msgid ""
@@ -1190,181 +1195,185 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
+"Godot Engine fidas al multe liberaj kaj malfermitkodaj bibliotekoj de "
+"ekstera liveranto, ĉio kongruas kun la kondiĉoj de ĝia MIT-permesilo. La "
+"jenoj estas elĉerpa listo de ĉiom tiaj komponantoj de ekstera liveranto kun "
+"iliaj kopirajtaj atentigoj kaj permesilaj kondiĉoj respektive."
#: editor/editor_about.cpp
msgid "All Components"
-msgstr ""
+msgstr "Ĉiaj komponantoj"
#: editor/editor_about.cpp
msgid "Components"
-msgstr ""
+msgstr "Komponantoj"
#: editor/editor_about.cpp
msgid "Licenses"
-msgstr ""
+msgstr "Permesiloj"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Error opening package file, not in ZIP format."
-msgstr ""
+msgstr "Eraro dum malfermi la pakaĵan dosieron, ne de ZIP formato."
#: editor/editor_asset_installer.cpp
msgid "%s (Already Exists)"
-msgstr ""
+msgstr "%s (jam ekzistante)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr ""
+msgstr "Maldensigas havaĵojn"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "La jenaj dosieroj malplenumis malkompaktigi el la pakaĵo:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
-msgstr ""
+msgstr "Kaj %s pli dosieroj."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
-msgstr ""
+msgstr "Pakaĵo instalis sukcese!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Success!"
-msgstr "Sukcesis!"
+msgstr "Sukcese!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
-msgstr ""
+msgstr "Enhavo de pakaĵo:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
-msgstr ""
+msgstr "Instali"
#: editor/editor_asset_installer.cpp
msgid "Package Installer"
-msgstr ""
+msgstr "Pakaĵa instalilo"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
-msgstr ""
+msgstr "Laŭtparolilo"
#: editor/editor_audio_buses.cpp
msgid "Add Effect"
-msgstr ""
+msgstr "Aldoni efekton"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr ""
+msgstr "Renomi aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr ""
+msgstr "Ŝangi la laŭtecon de la aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
-msgstr ""
+msgstr "Baskuli la sola reĝimo de la aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr ""
+msgstr "Baskuli la muta reĝimo de la aŭdia buso"
#: editor/editor_audio_buses.cpp
+#, fuzzy
msgid "Toggle Audio Bus Bypass Effects"
-msgstr ""
+msgstr "Baskuli preterpasajn efektojn de aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
-msgstr ""
+msgstr "Elekti senditon de aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr ""
+msgstr "Aldoni efekton de aŭdia buso"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr ""
+msgstr "Movi busan efekton"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr ""
+msgstr "Forigi busan efekton"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
-msgstr ""
+msgstr "Ŝovi kaj demeti por rearanĝi."
#: editor/editor_audio_buses.cpp
msgid "Solo"
-msgstr ""
+msgstr "Solo"
#: editor/editor_audio_buses.cpp
msgid "Mute"
-msgstr ""
+msgstr "Mute"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Preterpase"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr ""
+msgstr "Busaj agordoj"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr ""
+msgstr "Duobligi"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
-msgstr ""
+msgstr "Rekomencigi la laŭtecon"
#: editor/editor_audio_buses.cpp
msgid "Delete Effect"
-msgstr ""
+msgstr "Forigi la efekton"
#: editor/editor_audio_buses.cpp
msgid "Audio"
-msgstr ""
+msgstr "Aŭdio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr ""
+msgstr "Aldoni aŭdian buson"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr ""
+msgstr "La ĉefan buson ne forigeblas!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr ""
+msgstr "Forigi aŭdian buson"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr ""
+msgstr "Duobligi aŭdian buson"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr ""
+msgstr "Rekomencigi la laŭtecon de buso"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
-msgstr ""
+msgstr "Movi aŭdian buson"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr ""
+msgstr "Konservi aranĝon de aŭdia buso kiel..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
-msgstr ""
+msgstr "Dosierlokigo por nova aranĝo..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr ""
+msgstr "Malfermi aranĝon de aŭdia buso"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "There is no '%s' file."
-msgstr "Neniu '%s' dosiero."
+msgstr "Estas neniu dosiero '%s'."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
@@ -1372,12 +1381,11 @@ msgstr "Aranĝo"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr ""
+msgstr "Malvalida dosiero, ne estas aranĝo de aŭdia buso."
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Error saving file: %s"
-msgstr "Eraro dum ŝargante tiparon."
+msgstr "Eraris konservi dosieron: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
@@ -1385,97 +1393,97 @@ msgstr "Aldoni Buso"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr ""
+msgstr "Aldonu novan Aŭdobuson al ĉi tiu aranĝo."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Load"
-msgstr "Ŝarĝi"
+msgstr "Ŝargi"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr ""
+msgstr "Ŝargi ekzistante busan aranĝon."
#: editor/editor_audio_buses.cpp
msgid "Save As"
-msgstr ""
+msgstr "Konservi kiel"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr ""
+msgstr "Konservi ĉi tiun busan aranĝon al dosiero."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr ""
+msgstr "Ŝargi defaŭlto"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr ""
+msgstr "Ŝargi la defaŭlta busaranĝo."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr ""
+msgstr "Krei nova busaranĝo."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
-msgstr ""
+msgstr "Malvalida nomo."
#: editor/editor_autoload_settings.cpp
msgid "Valid characters:"
-msgstr ""
+msgstr "Validaj signoj:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de motora klaso ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de enkonstruita tipo ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de malloka konstanto ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Ŝlosilvorto ne povas uzi kiel aŭtoŝarga nomo."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr ""
+msgstr "Aŭtoŝarga '%s' jam ekzistas!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr ""
+msgstr "Renomi aŭtoŝargon"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr ""
+msgstr "Baskuli aŭtoŝargajn mallokojn"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
-msgstr ""
+msgstr "Movi aŭtoŝargon"
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Forigi aŭtoŝargon"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
-msgstr ""
+msgstr "Ŝaltita"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
-msgstr ""
+msgstr "Rearanĝi aŭtoŝargojn"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Ne aldoneblas aŭtoŝargon:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr ""
+msgstr "Aldoni aŭtoŝargon"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
@@ -1486,7 +1494,7 @@ msgstr "Vojo:"
#: editor/editor_autoload_settings.cpp
msgid "Node Name:"
-msgstr ""
+msgstr "Nomo de nodo:"
#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
#: editor/editor_profiler.cpp editor/project_manager.cpp
@@ -1496,41 +1504,39 @@ msgstr "Nomo"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr ""
+msgstr "Unuopo"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
-msgstr ""
+msgstr "Alglui parametroj"
#: editor/editor_data.cpp
-#, fuzzy
msgid "Updating Scene"
-msgstr "Aktualas scenon"
+msgstr "Aktualigas la scenon"
#: editor/editor_data.cpp
msgid "Storing local changes..."
-msgstr ""
+msgstr "Memoras lokajn ŝanĝojn..."
#: editor/editor_data.cpp
-#, fuzzy
msgid "Updating scene..."
-msgstr "Aktualas scenon..."
+msgstr "Aktualigas la scenon..."
#: editor/editor_data.cpp editor/editor_properties.cpp
msgid "[empty]"
-msgstr ""
+msgstr "[malplena]"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr ""
+msgstr "[ne konservis]"
#: editor/editor_dir_dialog.cpp
msgid "Please select a base directory first."
-msgstr ""
+msgstr "Bonvolu selekti bazan dosierujon unue."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
-msgstr ""
+msgstr "Elekti dosierujon"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
@@ -1552,31 +1558,35 @@ msgstr "Ne povis krei dosierujon."
#: editor/editor_dir_dialog.cpp
msgid "Choose"
-msgstr ""
+msgstr "Elekti"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr ""
+msgstr "Memoras dosieron:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr ""
+msgstr "Ne eksporta ŝablono trovis al la atenda dosierindiko:"
#: editor/editor_export.cpp
msgid "Packing"
-msgstr ""
+msgstr "Pakas"
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC' teksturan densigon por GLES2. Ebligu 'Import "
+"Etc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC2' teksturan densigon por GLES3. Ebligu 'Import "
+"Etc 2' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
@@ -1585,18 +1595,26 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Cela platformo bezonas 'ETC' teksturan densigon por la retrodefaŭlta pelilo "
+"de GLES2.\n"
+"Ebligu 'Import Etc' en projektaj agordoj, aŭ malŝalti 'Driver Fallback "
+"Enabled'."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'PVRTC' teksturan densigon por GLES2. Ebligu 'Import "
+"Pvrtc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC2' aŭ 'PVRTC' teksturan densigon por GLES3. "
+"Ebligu 'Import Etc 2' aŭ 'Import Pvrtc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
@@ -1605,6 +1623,10 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Cela platformo bezonas 'PVRTC' teksturan densigon por la retrodefaŭlta "
+"pelilo de GLES2.\n"
+"Ebligu 'Import Pvrtc' en projektaj agordoj, aŭ malŝalti 'Driver Fallback "
+"Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1624,10 +1646,9 @@ msgid "Template file not found:"
msgstr "Ŝablonan dosieron ne trovitis:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr ""
-"Sur 32-bita eksportoj la enigita PCK ne eblos esti pli granda ol 4 GiB."
+"Sur 32-bita eksportoj la enigita PCK ne eblas esti pli granda ol 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1643,92 +1664,89 @@ msgstr "Biblioteko de havaĵoj"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr ""
+msgstr "Redaktado de scena arbo"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Doko de nodo"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Dosiersistemo"
+msgstr "Doko de dosiersistemo"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Enporti dokon"
+msgstr "Doko de enporto"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
-msgstr ""
+msgstr "Viŝi profilon '%s'? (ne malfaro)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profilo devas esti valida dosiernomo kaj devas ne enhavi '.'"
#: editor/editor_feature_profile.cpp
msgid "Profile with this name already exists."
-msgstr ""
+msgstr "Profilo kun tia nomo jam ekzistas."
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled, Properties Disabled)"
-msgstr ""
+msgstr "(Redaktilo malŝaltita, Atributoj malŝaltitaj)"
#: editor/editor_feature_profile.cpp
msgid "(Properties Disabled)"
-msgstr ""
+msgstr "(Atributoj malŝaltitaj)"
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled)"
-msgstr ""
+msgstr "(Redaktilo malŝaltita)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr ""
+msgstr "Agordoj de klaso:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
-msgstr ""
+msgstr "Ŝalti kuntekstan redaktilon"
#: editor/editor_feature_profile.cpp
msgid "Enabled Properties:"
-msgstr ""
+msgstr "Ŝaltitaj atributoj:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
-msgstr ""
+msgstr "Ŝaltitaj eblecoj:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Classes:"
-msgstr ""
+msgstr "Ŝaltitaj klasoj:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "File '%s' format is invalid, import aborted."
-msgstr "Dosierformo de la '%s' estas malvalida, enporto ĉesiĝis."
+msgstr "La dosierformo '%s' estas malvalida, enporto ĉesigis."
#: editor/editor_feature_profile.cpp
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
-msgstr ""
+msgstr "Profilo '%s' jam ekzistas. Forigu ĝin antaŭ enporti. Enporto ĉesigis."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr ""
+msgstr "Eraras konservi profilon al dosierindiko: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
-msgstr ""
+msgstr "Malagordi"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
-msgstr ""
+msgstr "Aktuala profilo:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Make Current"
-msgstr "Nuntempigi"
+msgstr "Farigi aktuale"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
@@ -1747,35 +1765,35 @@ msgstr "Eksporti"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
-msgstr ""
+msgstr "Disponeblaj profiloj:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
-msgstr ""
+msgstr "Agordoj de klaso"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr ""
+msgstr "Nomo de nova profilo:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
-msgstr ""
+msgstr "Viŝi profilon"
#: editor/editor_feature_profile.cpp
msgid "Godot Feature Profile"
-msgstr ""
+msgstr "Profilo de funkciaro de Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr ""
+msgstr "Enporti profilo(j)n"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
-msgstr ""
+msgstr "Eksporti profilo(j)n"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Administri profilojn de funkciaro de redaktilo"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1791,7 +1809,7 @@ msgstr "Elekti ĉi tiun dosierujon"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopii vojo"
+msgstr "Kopii dosierindikon"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
@@ -1836,8 +1854,8 @@ msgid "Open a File or Directory"
msgstr "Malfermi dosieron aŭ dosierujon"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Konservi"
@@ -1848,73 +1866,71 @@ msgstr "Konservi dosieron"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr ""
+msgstr "Posteniri"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr ""
+msgstr "Antaŭeniri"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr ""
+msgstr "Supreniri"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Baskuli kaŝitaj dosieroj"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Baskuli favorata"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr ""
+msgstr "Baskuli reĝimon"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr ""
+msgstr "Fokusi al dosierindiko"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr ""
+msgstr "Suprentiri favoraton"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr ""
+msgstr "Subentiri favoraton"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Iri al Antaŭa Paŝo"
+msgstr "Iri al antaŭa dosierujo."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Iri al Neksta Paŝo"
+msgstr "Iri al sekva dosierujo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr ""
+msgstr "Iri al superdosierujo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
-msgstr ""
+msgstr "Aktualigi dosieroj."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
-msgstr ""
+msgstr "(Mal)favoratigi aktualan dosieron."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
-msgstr ""
+msgstr "Baskuli videblo de kaŝitaj dosieroj."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr ""
+msgstr "Vidigi elementoj kiel krado de miniaturoj."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
-msgstr ""
+msgstr "Vidigi elementoj kiel listo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Directories & Files:"
@@ -1924,110 +1940,109 @@ msgstr "Dosierujoj kaj dosieroj:"
#: editor/plugins/style_box_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Preview:"
-msgstr ""
+msgstr "Antaŭrigardo:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File:"
-msgstr ""
+msgstr "Dosiero:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr ""
+msgstr "Esplori fontoj"
#: editor/editor_file_system.cpp
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Estas pluraj enportiloj por malsamaj tipoj almontri dosieron %s, enporto "
+"ĉesigis"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "(Re)enportas havaĵoj"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr ""
+msgstr "Supro"
#: editor/editor_help.cpp
msgid "Class:"
-msgstr ""
+msgstr "Klaso:"
#: editor/editor_help.cpp editor/scene_tree_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Inherits:"
-msgstr ""
+msgstr "Heredato:"
#: editor/editor_help.cpp
msgid "Inherited by:"
-msgstr ""
+msgstr "Heredadas de:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Priskribo:"
+msgstr "Priskribo"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr ""
+msgstr "Retaj Instruiloj"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr ""
+msgstr "Atributoj"
#: editor/editor_help.cpp
+#, fuzzy
msgid "override:"
-msgstr ""
+msgstr "redifino:"
#: editor/editor_help.cpp
msgid "default:"
-msgstr ""
+msgstr "defaŭlto:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr ""
+msgstr "Metodoj"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr ""
+msgstr "Etosaj Atributoj"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr ""
+msgstr "Enumeracioj"
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Konstantoj"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr ""
+msgstr "Priskribo de Atributoj"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Valoro:"
+msgstr "(valoro)"
#: editor/editor_help.cpp
-#, fuzzy
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
-"Tie aktuale ne estas priskribon por ĉi tiun eco. Bonvolu helpi nin per "
-"[color=$color][url=$url]kontribui oni[/url][/color]!"
+"Estas aktuale ne priskribo por ĉi tiu atributo. Bonvolu helpi nin per [color="
+"$color][url=$url]kontribui unu[/url][/color]!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr ""
+msgstr "Metodaj Priskriboj"
#: editor/editor_help.cpp
-#, fuzzy
msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
-"Tie aktuale ne estas priskribon por ĉi tiun metodo. Bonvolu helpi nin per "
-"[color=$color][url=$url]kontribui oni[/url][/color]!"
+"Estas aktuale ne priskribo por ĉi tiu metodo. Bonvolu helpi nin per [color="
+"$color][url=$url]kontribui unu[/url][/color]!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
@@ -2035,93 +2050,89 @@ msgid "Search Help"
msgstr "Serĉi helpon"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Case Sensitive"
-msgstr "Fermi scenon"
+msgstr "Uskleciva"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Show Hierarchy"
-msgstr "Montri helpantoj"
+msgstr "Montri hierarĥion"
#: editor/editor_help_search.cpp
msgid "Display All"
-msgstr ""
+msgstr "Vidigi tutan"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr ""
+msgstr "Nur klasoj"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr ""
+msgstr "Nur metodoj"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr ""
+msgstr "Nur signaloj"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr ""
+msgstr "Nur konstantoj"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr ""
+msgstr "Nur atributoj"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Nur etosaj atributoj"
#: editor/editor_help_search.cpp
msgid "Member Type"
-msgstr ""
+msgstr "Tipo de membro"
#: editor/editor_help_search.cpp
msgid "Class"
-msgstr ""
+msgstr "Klaso"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Method"
-msgstr "Iru al metodo"
+msgstr "Metodo"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr ""
+msgstr "Signalo"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr ""
+msgstr "Konstanto"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Property"
-msgstr "Atributo Vojeto"
+msgstr "Atributo"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Property"
-msgstr "Renomi projekton"
+msgstr "Etosa atributo"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Atributo:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Agordi"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Agordi pluroblan:"
#: editor/editor_log.cpp
+#, fuzzy
msgid "Output:"
-msgstr ""
+msgstr "Eligo:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Copy Selection"
-msgstr ""
+msgstr "Kopii elektaron"
#: editor/editor_log.cpp editor/editor_network_profiler.cpp
#: editor/editor_profiler.cpp editor/editor_properties.cpp
@@ -2131,96 +2142,102 @@ msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Clear"
-msgstr ""
+msgstr "Vakigi"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr ""
+msgstr "Vakigi eligon"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
msgid "Stop"
-msgstr ""
+msgstr "Halti"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Komenci"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
msgid "Down"
-msgstr ""
+msgstr "Elŝuta"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Alŝuta"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
-msgstr ""
+msgstr "Nodo"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "Envena RPC"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "Envena RSET"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "Elira RPC"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "Elira RSET"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Nova Fenestro"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Enportitaj risurcoj ne povas konservi."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "Bone"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Eraras konservi risurcon!"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Ĉi tiu risurco ne konserveblas, ĉar ĝi ne apartenas la redaktita sceno. "
+"Farigu ĝin unikan unue."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
-msgstr ""
+msgstr "Konservi risurcon kiel..."
#: editor/editor_node.cpp
msgid "Can't open file for writing:"
-msgstr ""
+msgstr "Ne malfermeblas dosieron por skribi:"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Requested file format unknown:"
-msgstr ""
+msgstr "Petitan dosierformon senkonatas:"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Error while saving."
-msgstr ""
+msgstr "Eraro dum la konservo."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#, fuzzy
msgid "Can't open '%s'. The file could have been moved or deleted."
-msgstr ""
+msgstr "Ne malfermeblas '%s'. La dosiero estus movita aŭ forigita."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
@@ -2252,7 +2269,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr ""
+msgstr "Ĉi tiu operacio ne farigeblas sen arbradiko."
#: editor/editor_node.cpp
msgid ""
@@ -2491,7 +2508,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2631,7 +2648,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Scene"
-msgstr ""
+msgstr "Sceno"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
@@ -2911,14 +2928,6 @@ msgid "Help"
msgstr "Helpo"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Serĉo"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
#, fuzzy
msgid "Online Docs"
@@ -3075,6 +3084,22 @@ msgid "Open & Run a Script"
msgstr "Malfermi & ruli skripto"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3279,7 +3304,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3585,6 +3610,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3971,6 +4001,24 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Selektu nodo(j)n por enporti"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Enporti"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -4924,7 +4972,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5028,7 +5076,6 @@ msgid "Sort:"
msgstr "Ordigi:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6806,6 +6853,14 @@ msgstr ""
msgid "Run"
msgstr "Ruli"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Serĉo"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6858,16 +6913,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6960,8 +7005,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7368,6 +7413,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9731,6 +9781,10 @@ msgid "Projects"
msgstr "Projektoj"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
#, fuzzy
msgid "Last Modified"
msgstr "Modifita"
@@ -10092,6 +10146,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Enporti dokon"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10153,9 +10212,8 @@ msgid "Batch Rename"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Anstataŭigi: "
+msgstr "Anstataŭigi:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10336,6 +10394,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Skali Elektaron"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Krei skripton"
@@ -10433,19 +10500,19 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr ""
+msgstr "2D Sceno"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr ""
+msgstr "3D Sceno"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
-msgstr ""
+msgstr "Uzanta Interfaco"
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr ""
+msgstr "Alia Nodo"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -10457,15 +10524,19 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Attach Script"
-msgstr ""
+msgstr "Alligi Skripto"
+
+#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Eltondi nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
-msgstr ""
+msgstr "Forigi nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid "Change type of node(s)"
-msgstr ""
+msgstr "Ŝanĝi la tipo de nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10483,23 +10554,24 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Subrisurcoj"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
-msgstr ""
+msgstr "Vakigi heredadon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Editable Children"
-msgstr ""
+msgstr "Redakteblaj infanoj"
#: editor/scene_tree_dock.cpp
msgid "Load As Placeholder"
-msgstr ""
+msgstr "Ŝargi kiel lokokupilo"
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr ""
+msgstr "Malfermi dokumentaro"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10510,31 +10582,34 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
-msgstr ""
+msgstr "Aldoni infanon nodon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Expand/Collapse All"
-msgstr ""
+msgstr "(Mal)etendi tutan"
#: editor/scene_tree_dock.cpp
msgid "Change Type"
-msgstr ""
+msgstr "Ŝanĝi tipon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Reparent to New Node"
-msgstr ""
+msgstr "Repatri al nova nodo"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr ""
+msgstr "Farigi scena radiko"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Merge From Scene"
-msgstr ""
+msgstr "Kunigi el sceno"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Save Branch as Scene"
-msgstr ""
+msgstr "Konservi la branĉon kiel sceno"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
@@ -10542,11 +10617,11 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
-msgstr ""
+msgstr "Forigi (ne konfirmo)"
#: editor/scene_tree_dock.cpp
msgid "Add/Create a New Node."
-msgstr ""
+msgstr "Aldoni/Krei nova nodo."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10564,83 +10639,102 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Remote"
+msgstr "Fora"
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Local"
-msgstr ""
+msgstr "Loka"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
-msgstr ""
+msgstr "Vakigi heredadon? (Ne malfaro!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
-msgstr ""
+msgstr "Baskuli videblon"
#: editor/scene_tree_editor.cpp
msgid "Unlock Node"
-msgstr ""
+msgstr "Malŝlosi nodon"
#: editor/scene_tree_editor.cpp
msgid "Button Group"
-msgstr ""
+msgstr "Grupo de butono"
#: editor/scene_tree_editor.cpp
msgid "(Connecting From)"
-msgstr ""
+msgstr "(Konektas el)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
-msgstr ""
+msgstr "Agorda averto de nodo:"
#: editor/scene_tree_editor.cpp
msgid ""
"Node has %s connection(s) and %s group(s).\n"
"Click to show signals dock."
msgstr ""
+"La nodo havas %s konekto(j)n kaj %s grupo(j)n.\n"
+"Alklaku por vidigi la dokon de signaloj."
#: editor/scene_tree_editor.cpp
msgid ""
"Node has %s connection(s).\n"
"Click to show signals dock."
msgstr ""
+"La nodo havas %s konekto(j)n.\n"
+"Alklaku por vidigi la dokon de signaloj."
#: editor/scene_tree_editor.cpp
msgid ""
"Node is in %s group(s).\n"
"Click to show groups dock."
msgstr ""
+"La nodo havas %s grupo(j)n.\n"
+"Alklaku por vidigi la dokon de grupoj."
#: editor/scene_tree_editor.cpp
msgid "Open Script:"
-msgstr ""
+msgstr "Malfermi skripton:"
#: editor/scene_tree_editor.cpp
msgid ""
"Node is locked.\n"
"Click to unlock it."
msgstr ""
+"Nodo ŝlosis.\n"
+"Alklaku por malŝlosi ĝin."
#: editor/scene_tree_editor.cpp
msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
+"Infanoj ne estas selektebla.\n"
+"Alklaku por farigi selekteblan."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
-msgstr ""
+msgstr "Baskuli videblon"
#: editor/scene_tree_editor.cpp
msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
+"AnimationPlayer estas kejlita.\n"
+"Alklaku por malkejli."
#: editor/scene_tree_editor.cpp
msgid "Invalid node name, the following characters are not allowed:"
-msgstr ""
+msgstr "Malvalida nomo de nodo, la jenaj signoj ne permesas:"
#: editor/scene_tree_editor.cpp
msgid "Rename Node"
@@ -10648,39 +10742,39 @@ msgstr "Renomi nodon"
#: editor/scene_tree_editor.cpp
msgid "Scene Tree (Nodes):"
-msgstr ""
+msgstr "Scena arbo (nodoj):"
#: editor/scene_tree_editor.cpp
msgid "Node Configuration Warning!"
-msgstr ""
+msgstr "Agorda averto de nodo!"
#: editor/scene_tree_editor.cpp
msgid "Select a Node"
-msgstr ""
+msgstr "Elektu nodon"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr ""
+msgstr "La dosierindiko estas malplena."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
-msgstr ""
+msgstr "La dosiernomo estas malplena."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
-msgstr ""
+msgstr "La dosierindiko ne estas loka."
#: editor/script_create_dialog.cpp
msgid "Invalid base path."
-msgstr "Nevalida dosierindiko."
+msgstr "Malvalida baza dosierindiko."
#: editor/script_create_dialog.cpp
msgid "A directory with the same name exists."
-msgstr ""
+msgstr "Dosierujo ekzistas kun la sama nomo."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
-msgstr ""
+msgstr "Dosiero ne ekzistas."
#: editor/script_create_dialog.cpp
msgid "Invalid extension."
@@ -10688,39 +10782,40 @@ msgstr "Nevalida kromprogramo."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
-msgstr ""
+msgstr "Elektinta kromprogramo eraras."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr ""
+msgstr "Eraris ŝargi ŝablono '%s'"
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
-msgstr "Eraro - Ne povis krei skripton en dosiersistemo."
+msgstr "Eraro - Ne povis krei skripton en la dosiersistemo."
#: editor/script_create_dialog.cpp
msgid "Error loading script from %s"
-msgstr ""
+msgstr "Eraris ŝargi skripton de %s"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "Overrides"
-msgstr ""
+msgstr "Redifinoj"
#: editor/script_create_dialog.cpp
msgid "N/A"
-msgstr ""
+msgstr "Neaplikebla"
#: editor/script_create_dialog.cpp
msgid "Open Script / Choose Location"
-msgstr ""
+msgstr "Malfermi skripton / Elekti lokon"
#: editor/script_create_dialog.cpp
msgid "Open Script"
-msgstr ""
+msgstr "Malfermi skripton"
#: editor/script_create_dialog.cpp
msgid "File exists, it will be reused."
-msgstr ""
+msgstr "Dosiero ekzistas, ĝi reuziĝos."
#: editor/script_create_dialog.cpp
msgid "Invalid path."
@@ -10728,212 +10823,208 @@ msgstr "Nevalida dosierindiko."
#: editor/script_create_dialog.cpp
msgid "Invalid class name."
-msgstr ""
+msgstr "Malvalida nomo de klaso."
#: editor/script_create_dialog.cpp
msgid "Invalid inherited parent name or path."
-msgstr ""
+msgstr "Malvalida nomo aŭ dosierindiko de heredita gepatro."
#: editor/script_create_dialog.cpp
msgid "Script path/name is valid."
-msgstr ""
+msgstr "La dosierindiko/nomo de skripto estas valida."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "Permesite: a-z, A-Z, 0-9, _ kaj ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
-msgstr ""
+msgstr "Enkonstruita skripto (en scena dosiero)."
#: editor/script_create_dialog.cpp
msgid "Will create a new script file."
-msgstr ""
+msgstr "Kreos novan dosieron de skripto."
#: editor/script_create_dialog.cpp
msgid "Will load an existing script file."
-msgstr ""
+msgstr "Ŝargos ekzistitan dosieron de skripto."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script file already exists."
-msgstr "Grupa nomo jam ekzistas."
+msgstr "La skripta dosiero jam ekzistas."
#: editor/script_create_dialog.cpp
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
msgstr ""
+"Rimarko: Enkonstruitaj skriptoj havas iom limiĝoj kaj ne redakteblas uzi "
+"ekstera redaktilo."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Nomo:"
+msgstr "Klasa nomo:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Template:"
-msgstr "Ŝablonoj"
+msgstr "Ŝablono:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Konektu al skripto:"
+msgstr "Enkonstruita skripto:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
-msgstr ""
+msgstr "Alligi Noda Skripto"
#: editor/script_editor_debugger.cpp
msgid "Remote "
-msgstr ""
+msgstr "Fora "
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
-msgstr ""
+msgstr "Bitokoj:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Avertoj"
+msgstr "Averto:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "Spegulo"
+msgstr "Eraro:"
#: editor/script_editor_debugger.cpp
msgid "C++ Error"
-msgstr ""
+msgstr "C++ Eraro"
#: editor/script_editor_debugger.cpp
msgid "C++ Error:"
-msgstr ""
+msgstr "C++ Eraro:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source"
-msgstr ""
+msgstr "C++ Fonto"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source:"
-msgstr "Rimedo"
+msgstr "Fonto:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source:"
-msgstr ""
+msgstr "C++ Fonto:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
-msgstr ""
+msgstr "Stakspuro"
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Eraroj"
#: editor/script_editor_debugger.cpp
msgid "Child process connected."
-msgstr ""
+msgstr "Infana procezo konektis."
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr ""
+msgstr "Kopii eraro"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
-msgstr ""
+msgstr "Videomemoro"
#: editor/script_editor_debugger.cpp
msgid "Skip Breakpoints"
-msgstr ""
+msgstr "Pasi preter paŭzpunktojn"
#: editor/script_editor_debugger.cpp
msgid "Inspect Previous Instance"
-msgstr ""
+msgstr "Inspekti antaŭan ekzemplon"
#: editor/script_editor_debugger.cpp
msgid "Inspect Next Instance"
-msgstr ""
+msgstr "Inspekti sekvan ekzemplon"
#: editor/script_editor_debugger.cpp
msgid "Stack Frames"
-msgstr ""
+msgstr "Stakaj Framoj"
#: editor/script_editor_debugger.cpp
msgid "Profiler"
-msgstr ""
+msgstr "Profililo"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
-msgstr ""
+msgstr "Reta Profililo"
#: editor/script_editor_debugger.cpp
msgid "Monitor"
-msgstr ""
+msgstr "Monitoro"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Valoro"
#: editor/script_editor_debugger.cpp
msgid "Monitors"
-msgstr ""
+msgstr "Monitoroj"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr ""
+msgstr "Elektu unu aŭ pli elementojn de la listo por vidigi la diagramon."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr ""
+msgstr "Listo de la Uzo de Videomemoro per Risurco:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
-msgstr ""
+msgstr "Totalo:"
#: editor/script_editor_debugger.cpp
msgid "Export list to a CSV file"
-msgstr ""
+msgstr "Eksporti liston al CSV dosiero"
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
-msgstr ""
+msgstr "Risurca Vojo"
#: editor/script_editor_debugger.cpp
msgid "Type"
-msgstr ""
+msgstr "Tipo"
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Formo"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Uzo"
#: editor/script_editor_debugger.cpp
msgid "Misc"
-msgstr ""
+msgstr "Diversa"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
-msgstr ""
+msgstr "Alklakita stirilo:"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control Type:"
-msgstr ""
+msgstr "Tipo de alklakita stirilo:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Live Edit Root:"
-msgstr ""
+msgstr "Senpere redakta radiko:"
#: editor/script_editor_debugger.cpp
msgid "Set From Tree"
-msgstr ""
+msgstr "Agordi de la Arbo"
#: editor/script_editor_debugger.cpp
msgid "Export measures as CSV"
-msgstr ""
+msgstr "Eksporti mezurojn en CSV"
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
@@ -12053,6 +12144,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12308,11 +12407,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index c6f5ff06d7..e83d33e9fa 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -18,7 +18,7 @@
# Jose Maria Martinez <josemar1992@hotmail.com>, 2018.
# Juan Quiroga <juanquiroga9@gmail.com>, 2017.
# Kiji Pixel <raccoon.fella@gmail.com>, 2017.
-# Lisandro Lorea <lisandrolorea@gmail.com>, 2016-2017, 2019, 2020.
+# Lisandro Lorea <lisandrolorea@gmail.com>, 2016-2017, 2019, 2020, 2021.
# Lonsfor <lotharw@protonmail.com>, 2017-2018.
# Mario Nachbaur <manachbaur@gmail.com>, 2018.
# Oscar Carballal <oscar.carballal@protonmail.com>, 2017-2018.
@@ -58,12 +58,14 @@
# Ricardo Pérez <ricpelo@gmail.com>, 2021.
# A <kaieltroll@gmail.com>, 2021.
# Lucasdelpiero <lucasdelpiero98@gmail.com>, 2021.
+# SteamGoblin <SteamGoblin860@gmail.com>, 2021.
+# Francisco C <pruebasfrancisco17@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-16 01:29+0000\n"
-"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: Francisco C <pruebasfrancisco17@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -71,7 +73,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -210,7 +212,7 @@ msgstr "Cambiar Transformación de la Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr "Cambiar Valor de la Clave de Animación"
+msgstr "Cambiar Valor de Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
@@ -218,7 +220,7 @@ msgstr "Cambiar Llamada de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr "Cambiar Tiempo de Múltiples Keyframes de Animación"
+msgstr "Cambiar Tiempo de Múltiples Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
@@ -230,7 +232,7 @@ msgstr "Cambiar Múltiples Transforms de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
-msgstr "Cambiar Valor de Múltiples Keyframes de Animación"
+msgstr "Cambiar Valor de Múltiples Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
@@ -271,7 +273,7 @@ msgstr "Pista de Reproducción de Animación"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr "Duración de la animación (frames)"
+msgstr "Duración de la animación (fotogramas)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
@@ -577,7 +579,7 @@ msgstr "Agrupar las pistas por nodo o mostrarlas como una lista plana."
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr "Snap:"
+msgstr "Ajuste:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -707,7 +709,7 @@ msgstr "Selecciona las Pistas a Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -1641,7 +1643,7 @@ msgid ""
"Etc' in Project Settings."
msgstr ""
"La plataforma de destino requiere compresión de texturas 'ETC' para GLES2. "
-"Activa 'Import Etc' en Ajustes del Proyecto."
+"Activa 'Import Etc' en Configuración del Proyecto."
#: editor/editor_export.cpp
msgid ""
@@ -1649,7 +1651,7 @@ msgid ""
"'Import Etc 2' in Project Settings."
msgstr ""
"La plataforma de destino requiere compresión de texturas 'ETC2' para GLES3. "
-"Activa 'Import Etc 2' en Ajustes del Proyecto."
+"Activa 'Import Etc 2' en Configuración del Proyecto."
#: editor/editor_export.cpp
msgid ""
@@ -1660,8 +1662,8 @@ msgid ""
msgstr ""
"La plataforma de destino requiere compresión de texturas 'ETC' para usar "
"GLES2 como controlador de respaldo.\n"
-"Activa 'Import Etc' en Ajustes del Proyecto, o desactiva 'Driver Fallback "
-"Enabled'."
+"Activa 'Import Etc' en Configuración del Proyecto, o desactiva 'Driver "
+"Fallback Enabled'."
#: editor/editor_export.cpp
msgid ""
@@ -1669,7 +1671,7 @@ msgid ""
"'Import Pvrtc' in Project Settings."
msgstr ""
"La plataforma de destino requiere compresión de texturas 'PVRTC' para GLES2. "
-"Activa 'Import Pvrtc' en Ajustes del Proyecto."
+"Activa 'Import Pvrtc' en Configuración del Proyecto."
#: editor/editor_export.cpp
msgid ""
@@ -1677,7 +1679,8 @@ msgid ""
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
"La plataforma de destino requiere compresión de texturas 'ETC2' o 'PVRTC' "
-"para GLES3. Activa 'Import Etc 2' o 'Import Pvrtc' en Ajustes del Proyecto."
+"para GLES3. Activa 'Import Etc 2' o 'Import Pvrtc' en Configuración del "
+"Proyecto."
#: editor/editor_export.cpp
msgid ""
@@ -1688,7 +1691,7 @@ msgid ""
msgstr ""
"La plataforma del objetivo requiere compresión de texturas 'PVRTC' para el "
"driver fallback de GLES2.\n"
-"Activa Import Pvrtc' en la Ajustes del Proyecto, o desactiva 'Driver "
+"Activa Import Pvrtc' en Configuración del Proyecto, o desactiva 'Driver "
"Fallback Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
@@ -1823,7 +1826,7 @@ msgstr "Nuevo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importación"
+msgstr "Importar"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1920,8 +1923,8 @@ msgid "Open a File or Directory"
msgstr "Abrir un archivo o directorio"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Guardar"
@@ -1992,7 +1995,7 @@ msgstr "Mostrar/Ocultar archivos ocultos."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr "Ver ítems como un grid de miniaturas."
+msgstr "Ver ítems como una cuadrícula de miniaturas."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
@@ -2599,10 +2602,8 @@ msgstr ""
"configuración de '%s'."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"No se pudo encontrar el campo del script para el plugin addon en: 'res://"
-"addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "No se pudo encontrar el campo script para el plugin de addon en: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2662,8 +2663,8 @@ msgid ""
"category."
msgstr ""
"No se ha definido ninguna escena principal, ¿seleccionar una?\n"
-"Es posible cambiarla más tarde en \"Ajustes del Proyecto\" bajo la categoría "
-"'application'."
+"Es posible cambiarla más tarde en \"Configuración del Proyecto\" bajo la "
+"categoría 'application'."
#: editor/editor_node.cpp
msgid ""
@@ -2672,8 +2673,8 @@ msgid ""
"category."
msgstr ""
"La escena seleccionada '%s' no existe, ¿seleccionar una válida?\n"
-"Es posible cambiarla más tarde en \"Ajustes del Proyecto\" bajo la categoría "
-"'application'."
+"Es posible cambiarla más tarde en \"Configuración del Proyecto\" bajo la "
+"categoría 'application'."
#: editor/editor_node.cpp
msgid ""
@@ -2683,8 +2684,8 @@ msgid ""
msgstr ""
"La escena '%s' seleccionada no es un archivo de escena, ¿seleccionar uno "
"válido?\n"
-"Es posible cambiarla más tarde en \"Ajustes del Proyecto\" bajo la categoría "
-"'application'."
+"Es posible cambiarla más tarde en \"Configuración del Proyecto\" bajo la "
+"categoría 'application'."
#: editor/editor_node.cpp
msgid "Save Layout"
@@ -2845,7 +2846,7 @@ msgstr "Proyecto"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr "Ajustes del Proyecto..."
+msgstr "Configuración del Proyecto..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
@@ -3039,14 +3040,6 @@ msgid "Help"
msgstr "Ayuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Buscar"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentación Online"
@@ -3214,6 +3207,24 @@ msgid "Open & Run a Script"
msgstr "Abrir y Ejecutar un Script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Los siguientes archivos son nuevos en disco.\n"
+"¿Qué acción se debería tomar?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Recargar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Volver a Guardar"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nueva Escena Heredada"
@@ -3304,7 +3315,7 @@ msgstr "Medida:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr "Duración de Frame (seg)"
+msgstr "Duración de Fotogramas (seg)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
@@ -3312,11 +3323,11 @@ msgstr "Tiempo Promedio (seg)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr "Frame %"
+msgstr "Fotograma %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr "Frames de Física %"
+msgstr "Fotogramas de Física %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
@@ -3328,7 +3339,7 @@ msgstr "Propio"
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr "Frame #:"
+msgstr "Fotograma #:"
#: editor/editor_profiler.cpp
msgid "Time"
@@ -3425,7 +3436,7 @@ msgstr "Hacer Único"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Pegar"
@@ -3746,6 +3757,13 @@ msgstr ""
"reimpórtalo manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Se ha desactivado la importación de este archivo, por lo que no se puede "
+"abrir para editarlo."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No se puede mover/renombrar la raíz de los recursos."
@@ -3956,7 +3974,7 @@ msgid ""
"ProjectSettings."
msgstr ""
"Incluye los archivos con las siguientes extensiones. Añádelos o elimínalos "
-"en Ajustes del proyecto."
+"en Configuración del Proyecto."
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
@@ -4134,6 +4152,22 @@ msgstr "¿Devolviste un objeto derivado de Node en el método `post_import()`?"
msgid "Saving..."
msgstr "Guardando..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Seleccionar Importador"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importador:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Restablecer Valores por Defecto"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Mantener Archivo (No Importar)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d archivos"
@@ -4406,7 +4440,7 @@ msgstr "Seleccionar y mover puntos, crear puntos con clic derecho."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr "Activar snap y mostrar grid."
+msgstr "Activar ajuste y mostrar cuadrícula."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -5106,8 +5140,8 @@ msgid "Got:"
msgstr "Tiene:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Fallo en la comprobación del hash sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Fallo en la comprobación del hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5210,7 +5244,6 @@ msgid "Sort:"
msgstr "Ordenar:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoría:"
@@ -5297,15 +5330,15 @@ msgstr "Vista Previa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr "Configurar Snap"
+msgstr "Configurar Ajuste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr "Grid Offset:"
+msgstr "Desplazamiento de Cuadrícula:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr "Grid Step:"
+msgstr "Paso de Cuadrícula:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
@@ -5469,11 +5502,11 @@ msgstr "Ancho Inferior"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
-msgstr "Ancho Centro Vert."
+msgstr "Centro Vert. Ancho"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "HCenter Wide"
-msgstr "Ancho Centro Horiz."
+msgstr "Centro Horiz. Ancho"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
@@ -5633,48 +5666,48 @@ msgstr "Modo de Regla"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr "Alternar acople inteligente."
+msgstr "Act./Desact. ajuste inteligente."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Smart Snap"
-msgstr "Usar Snap Inteligente"
+msgstr "Usar Ajuste Inteligente"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr "Act./Desact. grid snapping."
+msgstr "Act./Desact. ajuste de cuadrícula."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
-msgstr "Usar Grid Snap"
+msgstr "Usar Ajuste de Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr "Opciones de Snapping"
+msgstr "Opciones de Ajuste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr "Usar Snap de Rotación"
+msgstr "Usar Ajuste de Rotación"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Scale Snap"
-msgstr "Usar Snap de Escalado"
+msgstr "Usar Ajuste de Escalado"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr "Snap Relativo"
+msgstr "Ajuste Relativo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr "Usar Pixel Snap"
+msgstr "Usar Ajuste de Píxeles"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr "Snapping Inteligente"
+msgstr "Ajuste Inteligente"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr "Configurar Snap..."
+msgstr "Configurar Ajuste..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
@@ -5743,7 +5776,7 @@ msgstr "Ver"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
-msgstr "Mostrar Siempre el Grid"
+msgstr "Mostrar Siempre la Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
@@ -5775,7 +5808,7 @@ msgstr "Centrar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr "Encuadrar Selección"
+msgstr "Seleccionar Fotogramas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
@@ -5832,11 +5865,11 @@ msgstr "Limpiar Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr "Multiplicar grid step por 2"
+msgstr "Multiplicar paso de cuadrícula por 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr "Dividir grid step por 2"
+msgstr "Dividir paso de cuadrícula por 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -6753,43 +6786,43 @@ msgstr "Limpiar UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Settings"
-msgstr "Configuración del Grid"
+msgstr "Configuración de la Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr "Snap"
+msgstr "Ajuste"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr "Activar Snap"
+msgstr "Activar Ajuste"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr "Grid"
+msgstr "Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
-msgstr "Ver Grid"
+msgstr "Ver Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Configure Grid:"
-msgstr "Configurar Grid:"
+msgstr "Configurar Cuadrícula:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
-msgstr "Grid Offset X:"
+msgstr "Desplazamiento de Cuadrícula en X:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset Y:"
-msgstr "Grid Offset Y:"
+msgstr "Desplazamiento de Cuadrícula en Y:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step X:"
-msgstr "Grid Step X:"
+msgstr "Paso de Cuadrícula en X:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step Y:"
-msgstr "Grid Step Y:"
+msgstr "Paso de Cuadrícula en Y:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Sync Bones to Polygon"
@@ -7047,6 +7080,14 @@ msgstr "Cerrar Documentación"
msgid "Run"
msgstr "Ejecutar"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Buscar"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Entrar En"
@@ -7100,16 +7141,6 @@ msgstr ""
"Los siguientes archivos son nuevos en disco.\n"
"¿Qué es lo que quieres hacer?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Recargar"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Volver a Guardar"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Depurador"
@@ -7205,8 +7236,8 @@ msgstr "Breakpoints"
msgid "Go To"
msgstr "Ir A"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Cortar"
@@ -7426,12 +7457,11 @@ msgstr "Altura"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw"
-msgstr "Yaw"
+msgstr "Guiñada"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamaño: "
+msgstr "Tamaño"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7615,6 +7645,11 @@ msgstr "Bloquear Rotación de Vista"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7757,7 +7792,7 @@ msgstr "Ver Origen"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Grid"
-msgstr "Ver Grid"
+msgstr "Ver Cuadrícula"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -7766,19 +7801,19 @@ msgstr "Configuración..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
-msgstr "Ajustes de Snap"
+msgstr "Configuración de Ajuste"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate Snap:"
-msgstr "Snap de Traslación:"
+msgstr "Ajuste de Traslación:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Snap (deg.):"
-msgstr "Snap de Rotación (grados):"
+msgstr "Ajuste de Rotación (grados):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Snap (%):"
-msgstr "Snap de Escala (%):"
+msgstr "Ajuste de Escala (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
@@ -7927,15 +7962,15 @@ msgstr "Configuración:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "No Frames Selected"
-msgstr "No hay Frames Seleccionados"
+msgstr "No hay Fotogramas Seleccionados"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr "Añadir %d Frame(s)"
+msgstr "Añadir %d Fotograma(s)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
-msgstr "Añadir Frame"
+msgstr "Añadir Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
@@ -7943,7 +7978,7 @@ msgstr "No se pueden cargar las imágenes"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
-msgstr "ERROR: ¡No se pudo cargar el recurso de frames!"
+msgstr "ERROR: ¡No se pudo cargar el recurso de fotogramas!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
@@ -7951,7 +7986,7 @@ msgstr "¡El portapapeles de recursos esta vacío o no es una textura!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
-msgstr "Pegar Frame"
+msgstr "Pegar Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Empty"
@@ -7967,7 +8002,7 @@ msgstr "(vacío)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move Frame"
-msgstr "Mover Frame"
+msgstr "Mover Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animations:"
@@ -7987,7 +8022,7 @@ msgstr "Loop"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animation Frames:"
-msgstr "Frames de Animación:"
+msgstr "Fotogramas de Animación:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add a Texture from File"
@@ -7995,7 +8030,7 @@ msgstr "Añadir Textura desde Archivo"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
-msgstr "Añadir Frames desde un Sprite Sheet"
+msgstr "Añadir Fotogramas desde un Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (Before)"
@@ -8015,7 +8050,7 @@ msgstr "Mover (Después)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select Frames"
-msgstr "Seleccionar Frames"
+msgstr "Seleccionar Fotogramas"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
@@ -8027,11 +8062,11 @@ msgstr "Vertical:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
-msgstr "Seleccionar/Limpiar Todos los Frames"
+msgstr "Seleccionar/Limpiar Todos los Fotogramas"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Create Frames from Sprite Sheet"
-msgstr "Crear Frames a partir de Sprite Sheet"
+msgstr "Crear Fotogramas a partir de un Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "SpriteFrames"
@@ -8047,7 +8082,7 @@ msgstr "Asignar Margen"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr "Modo Snap:"
+msgstr "Modo de Ajuste:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
@@ -8056,11 +8091,11 @@ msgstr "Ninguno"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr "Pixel Snap"
+msgstr "Ajuste de Píxeles"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr "Grid Snap"
+msgstr "Ajuste de Cuadrícula"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -8478,7 +8513,8 @@ msgstr "Mantener el polígono dentro del region Rect."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
-msgstr "Activar snap y mostrar grid (configurable a través del Inspector)."
+msgstr ""
+"Activar ajuste y mostrar cuadrícula (configurable a través del Inspector)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
@@ -9669,7 +9705,7 @@ msgid ""
msgstr ""
"No se pudo exportar el proyecto para la plataforma '%s'.\n"
"Esto puede ser debido a un problema de configuración en el preset de "
-"exportación o en los ajustes de exportación."
+"exportación o en la configuración de exportación."
#: editor/project_export.cpp
msgid "Release"
@@ -10059,8 +10095,8 @@ msgid ""
"the \"Application\" category."
msgstr ""
"No se puede ejecutar el proyecto: no hay una escena principal definida.\n"
-"Por favor, edita el proyecto y configura la escena principal en los Ajustes "
-"del proyecto, en la categoría \"Application\"."
+"Por favor, edita el proyecto y configura la escena principal en "
+"Configuración del Proyecto, en la categoría \"Application\"."
#: editor/project_manager.cpp
msgid ""
@@ -10126,6 +10162,10 @@ msgid "Projects"
msgstr "Proyectos"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Cargando, espera por favor..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Ultima Modificación"
@@ -10402,7 +10442,7 @@ msgstr "Cambiar Modo de Filtro Local"
#: editor/project_settings_editor.cpp
msgid "Project Settings (project.godot)"
-msgstr "Ajustes del Proyecto (project.godot)"
+msgstr "Configuración del Proyecto (project.godot)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "General"
@@ -10496,6 +10536,10 @@ msgstr "AutoLoad"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Valores de Importación por Defecto"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Preset..."
@@ -10746,6 +10790,14 @@ msgid "Instance Child Scene"
msgstr "Instanciar Escena Hija"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "No se puede pegar el nodo raíz en la misma escena."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Pegar Nodo(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Sustraer Script"
@@ -10873,6 +10925,10 @@ msgid "Attach Script"
msgstr "Añadir Script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Cortar Nodos(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Eliminar Nodo(s)"
@@ -10987,6 +11043,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -11285,7 +11348,7 @@ msgstr "Inspeccionar Instancia Siguiente"
#: editor/script_editor_debugger.cpp
msgid "Stack Frames"
-msgstr "Frames del Stack"
+msgstr "Fotogramas Apilados"
#: editor/script_editor_debugger.cpp
msgid "Profiler"
@@ -11581,7 +11644,7 @@ msgstr "Plano:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Delete Selection"
-msgstr "GridMap Eliminar Seleccionados"
+msgstr "Eliminar Selección de GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Fill Selection"
@@ -11589,7 +11652,7 @@ msgstr "Rellenar Selección en GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paste Selection"
-msgstr "Pegar lo Seleccionado en GridMap"
+msgstr "Pegar Selección en GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paint"
@@ -11597,7 +11660,7 @@ msgstr "Pintar GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
-msgstr "Grid Map"
+msgstr "Mapeo de Cuadrícula"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
@@ -11734,7 +11797,7 @@ msgstr "Estableciendo la configuración..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Calculating grid size..."
-msgstr "Calculando tamaño de grid..."
+msgstr "Calculando tamaño la cuadrícula..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating heightfield..."
@@ -12522,7 +12585,7 @@ msgid ""
"order for AnimatedSprite to display frames."
msgstr ""
"Se debe crear o establecer un recurso SpriteFrames en la propiedad \"Frames"
-"\" para que AnimatedSprite pueda mostrar frames."
+"\" para que AnimatedSprite pueda mostrar los fotogramas."
#: scene/2d/canvas_modulate.cpp
msgid ""
@@ -12559,6 +12622,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D vacío no tiene ningún efecto en las colisiones."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Polígono inválido. Se necesitan al menos 3 puntos en modo de construcción "
+"'Solids'."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Polígono inválido. Se necesitan al menos 2 puntos en modo de construcción "
+"'Segments'."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12772,7 +12847,7 @@ msgstr "ARVROrigin requiere un nodo hijo ARVRCamera."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr "Encontrar mallas y luces"
+msgstr "Encontrando mallas y luces"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing geometry (%d/%d)"
@@ -12879,11 +12954,6 @@ msgstr ""
"Las GIProbes no están soportadas por el controlador de vídeo GLES2.\n"
"Usa un BakedLightmap en su lugar."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera ha sido desaprobado y será eliminado en Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13000,7 +13070,7 @@ msgid ""
"order for AnimatedSprite3D to display frames."
msgstr ""
"Se debe crear o establecer un recurso SpriteFrames en la propiedad \"Frames"
-"\" para que AnimatedSprite3D pueda mostrar frames."
+"\" para que AnimatedSprite3D pueda mostrar los fotogramas."
#: scene/3d/vehicle_body.cpp
msgid ""
@@ -13175,7 +13245,7 @@ msgid ""
"Default Environment as specified in Project Settings (Rendering -> "
"Environment -> Default Environment) could not be loaded."
msgstr ""
-"El Entorno por Defecto como se especifica en los Ajustes del Proyecto "
+"El Entorno por Defecto como se especifica en Configuración del Proyecto "
"(Rendering -> Environment -> Default Environment) no se ha podido cargar."
#: scene/main/viewport.cpp
@@ -13233,6 +13303,11 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice."
msgid "Constants cannot be modified."
msgstr "Las constantes no pueden modificarse."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera ha sido desaprobado y será eliminado en Godot 4.0."
+
#~ msgid "No"
#~ msgstr "No"
@@ -15117,9 +15192,6 @@ msgstr "Las constantes no pueden modificarse."
#~ msgid "Use Default Light"
#~ msgstr "Usar iluminación predeterminada"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Usar sRGB predeterminado"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Iluminación por normales predeterminada:"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 4f32171d5f..d9e193da4e 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-29 19:32+0000\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -664,7 +664,7 @@ msgstr "Elegir Pistas a Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -1876,8 +1876,8 @@ msgid "Open a File or Directory"
msgstr "Abrir un Archivo o Directorio"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Guardar"
@@ -2556,10 +2556,8 @@ msgstr ""
"configuración."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"No se pudo encontrar el campo script para el plugin de addon en: 'res://"
-"addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "No se pudo encontrar el campo script para el plugin de addon en: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2994,14 +2992,6 @@ msgid "Help"
msgstr "Ayuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Buscar"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentación Online"
@@ -3169,6 +3159,24 @@ msgid "Open & Run a Script"
msgstr "Abrir y Correr un Script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Los siguientes archivos son nuevos en disco.\n"
+"¿Qué acción se debería tomar?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Volver a Cargar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Volver a Guardar"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nuevo Heredado"
@@ -3379,7 +3387,7 @@ msgstr "Convertir en Unico"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Pegar"
@@ -3700,6 +3708,13 @@ msgstr ""
"reimportá manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Se ha desactivado la importación de este archivo, por lo que no se puede "
+"abrir para editarlo."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No se puede mover/renombrar la raiz de recursos."
@@ -4087,6 +4102,22 @@ msgstr "¿Devolviste un objeto derivado de Node en el método `post_import()`?"
msgid "Saving..."
msgstr "Guardando..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Seleccionar Importador"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importador:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Restablecer Valores Por Defecto"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Mantener Archivo (No Importar)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Archivos"
@@ -5060,8 +5091,8 @@ msgid "Got:"
msgstr "Recibido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Fallo el chequeo del hash sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Fallo el chequeo del hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5164,7 +5195,6 @@ msgid "Sort:"
msgstr "Ordenar:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoría:"
@@ -6995,6 +7025,14 @@ msgstr "Cerrar Docs"
msgid "Run"
msgstr "Ejecutar"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Buscar"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Step Into"
@@ -7048,16 +7086,6 @@ msgstr ""
"Los siguientes archivos son nuevos en disco.\n"
"¿Qué acción se debería tomar?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Volver a Cargar"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Volver a Guardar"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Depurador"
@@ -7153,8 +7181,8 @@ msgstr "Puntos de interrupción"
msgid "Go To"
msgstr "Ir A"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Cortar"
@@ -7377,9 +7405,8 @@ msgid "Yaw"
msgstr "Yaw"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamaño: "
+msgstr "Tamaño"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7563,6 +7590,11 @@ msgstr "Rotación de Vista Trabada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10073,6 +10105,10 @@ msgid "Projects"
msgstr "Proyectos"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Cargando, esperá, por favor..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Ultima Modificación"
@@ -10443,6 +10479,10 @@ msgstr "AutoLoad"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Valores de Importacion Por Defecto"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Preseteo..."
@@ -10693,6 +10733,14 @@ msgid "Instance Child Scene"
msgstr "Instanciar Escena Hija"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "No se puede pegar el nodo raiz en la misma escena."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Pegar Nodo(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Desasignar Script"
@@ -10821,6 +10869,10 @@ msgid "Attach Script"
msgstr "Adjuntar Script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Cortar Nodo(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Quitar Nodo(s)"
@@ -10935,6 +10987,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -12497,6 +12556,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D vacío no tiene efecto en la colisión."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Polígono inválido. Se necesitan al menos 3 puntos en modo de construcción "
+"\"Sólidos\"."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Polígono inválido. Se necesitan al menos 2 puntos en modo de construcción "
+"\"Segmentos\"."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12817,11 +12888,6 @@ msgstr ""
"Las GIProbes no están soportadas por el controlador de video GLES2.\n"
"Usá un BakedLightmap en su lugar."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera ha sido deprecado y será eliminado en Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13166,6 +13232,10 @@ msgstr "Solo se pueden asignar variaciones en funciones de vértice."
msgid "Constants cannot be modified."
msgstr "Las constantes no pueden modificarse."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera ha sido deprecado y será eliminado en Godot 4.0."
+
#~ msgid "No"
#~ msgstr "No"
@@ -14834,9 +14904,6 @@ msgstr "Las constantes no pueden modificarse."
#~ msgid "Use Default Light"
#~ msgstr "Usar Luz por Defecto"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Usar sRGB por Defecto"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Normales de Luces por Defecto:"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index d0eb9f05e4..de0b0360ee 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -10,7 +10,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
+"PO-Revision-Date: 2021-03-07 06:04+0000\n"
"Last-Translator: Kritzmensch <streef.gtx@gmail.com>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/"
"godot/et/>\n"
@@ -18,7 +18,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.5-dev\n"
+"X-Generator: Weblate 4.5.1\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -635,7 +635,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopeeri"
@@ -697,7 +697,7 @@ msgstr ""
#: editor/code_editor.cpp
msgid "Replace"
-msgstr ""
+msgstr "Asenda"
#: editor/code_editor.cpp
msgid "Replace All"
@@ -814,7 +814,7 @@ msgstr ""
#: editor/connections_dialog.cpp
msgid "Oneshot"
-msgstr ""
+msgstr "Ainulaadne"
#: editor/connections_dialog.cpp
msgid "Disconnects the signal after its first emission."
@@ -840,7 +840,7 @@ msgstr "Sulge"
#: editor/connections_dialog.cpp
msgid "Connect"
-msgstr ""
+msgstr "Ühenda"
#: editor/connections_dialog.cpp
msgid "Signal:"
@@ -860,12 +860,12 @@ msgstr ""
#: editor/connections_dialog.cpp
msgid "Connect..."
-msgstr ""
+msgstr "Ühenda..."
#: editor/connections_dialog.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Disconnect"
-msgstr ""
+msgstr "Katkesta ühendus"
#: editor/connections_dialog.cpp
msgid "Connect a Signal to a Method"
@@ -898,7 +898,7 @@ msgstr ""
#: editor/connections_dialog.cpp
msgid "Edit..."
-msgstr ""
+msgstr "Muuda..."
#: editor/connections_dialog.cpp
msgid "Go To Method"
@@ -910,7 +910,7 @@ msgstr ""
#: editor/create_dialog.cpp editor/project_settings_editor.cpp
msgid "Change"
-msgstr ""
+msgstr "Muuda"
#: editor/create_dialog.cpp
msgid "Create New %s"
@@ -968,20 +968,20 @@ msgstr ""
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Dependencies"
-msgstr ""
+msgstr "Sõltuvused"
#: editor/dependency_editor.cpp
msgid "Resource"
-msgstr ""
+msgstr "Ressurss"
#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
#: editor/project_manager.cpp editor/project_settings_editor.cpp
msgid "Path"
-msgstr ""
+msgstr "Tee"
#: editor/dependency_editor.cpp
msgid "Dependencies:"
-msgstr ""
+msgstr "Sõltuvused:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
@@ -1213,7 +1213,7 @@ msgstr ""
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Success!"
-msgstr ""
+msgstr "Õnnestus!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
@@ -1221,7 +1221,7 @@ msgstr ""
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
-msgstr ""
+msgstr "Paigalda"
#: editor/editor_asset_installer.cpp
msgid "Package Installer"
@@ -1285,7 +1285,7 @@ msgstr "Vaigista"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Jäta vahele"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
@@ -1306,7 +1306,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Audio"
-msgstr ""
+msgstr "Heli"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
@@ -1830,8 +1830,8 @@ msgid "Open a File or Directory"
msgstr "Ava kaust või kataloog"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Salvesta"
@@ -2171,7 +2171,7 @@ msgstr "Imporditud ressursse ei saa salvestada."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "Olgu"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
@@ -2427,7 +2427,7 @@ msgstr "Välju"
#: editor/editor_node.cpp
msgid "Yes"
-msgstr ""
+msgstr "Jah"
#: editor/editor_node.cpp
msgid "Exit the editor?"
@@ -2472,8 +2472,9 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Lisa-skripti ei olnud võimalik laadida teelt: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2869,14 +2870,6 @@ msgid "Help"
msgstr "Abi"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Otsi"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Veebidokumentatsioonid"
@@ -3030,6 +3023,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3039,7 +3048,7 @@ msgstr "Laadimisvead"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
-msgstr ""
+msgstr "Vali"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3079,7 +3088,7 @@ msgstr ""
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
-msgstr ""
+msgstr "Pisipilt..."
#: editor/editor_plugin_settings.cpp
msgid "Main Script:"
@@ -3136,7 +3145,7 @@ msgstr ""
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr ""
+msgstr "Kaasav"
#: editor/editor_profiler.cpp
msgid "Self"
@@ -3160,11 +3169,11 @@ msgstr ""
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
-msgstr ""
+msgstr "Sees"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Kiht"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
@@ -3172,11 +3181,11 @@ msgstr ""
#: editor/editor_properties.cpp
msgid "[Empty]"
-msgstr ""
+msgstr "[Tühi]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr ""
+msgstr "Määra..."
#: editor/editor_properties.cpp
msgid "Invalid RID"
@@ -3232,9 +3241,9 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
-msgstr ""
+msgstr "Kleebi"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Convert To %s"
@@ -3246,7 +3255,7 @@ msgstr ""
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
-msgstr ""
+msgstr "Suurus: "
#: editor/editor_properties_array_dict.cpp
msgid "Page: "
@@ -3330,7 +3339,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "(Installed)"
-msgstr ""
+msgstr "(Paigaldatud)"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3343,11 +3352,11 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "(Missing)"
-msgstr ""
+msgstr "(Puudub)"
#: editor/export_template_manager.cpp
msgid "(Current)"
-msgstr ""
+msgstr "(Praegune)"
#: editor/export_template_manager.cpp
msgid "Retrieving mirrors, please wait..."
@@ -3468,7 +3477,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Connected"
-msgstr ""
+msgstr "Ühendatud"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3529,13 +3538,18 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Favorites"
-msgstr ""
+msgstr "Lemmikud"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3913,6 +3927,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Valimisrežiim"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Impordi"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Laadi vaikimisi"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4860,7 +4893,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4964,7 +4997,6 @@ msgid "Sort:"
msgstr "Sordi:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategooria:"
@@ -6731,6 +6763,14 @@ msgstr ""
msgid "Run"
msgstr "Käivita"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Otsi"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Trepi sissepoole"
@@ -6782,16 +6822,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Siluja"
@@ -6884,8 +6914,8 @@ msgstr "Katkepunktid"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7291,6 +7321,11 @@ msgstr "Vaateakna pöördenurk on lukustatud"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9639,6 +9674,10 @@ msgid "Projects"
msgstr "Projektid"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9999,6 +10038,11 @@ msgstr ""
msgid "Plugins"
msgstr "Pistikprogrammid"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Laadi vaikimisi"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10242,6 +10286,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Kustuta sõlm(ed)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10363,6 +10416,11 @@ msgid "Attach Script"
msgstr "Manusta skript"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Kustuta sõlm(ed)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10470,6 +10528,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11320,7 +11385,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
-msgstr ""
+msgstr "Signaalid:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new signal."
@@ -11938,6 +12003,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12194,11 +12267,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12396,7 +12464,7 @@ msgstr ""
#: scene/gui/dialogs.cpp
msgid "Alert!"
-msgstr ""
+msgstr "Tähelepanu!"
#: scene/gui/dialogs.cpp
msgid "Please Confirm..."
@@ -12430,7 +12498,7 @@ msgstr ""
#: scene/gui/tree.cpp
msgid "(Other)"
-msgstr ""
+msgstr "(Muu)"
#: scene/main/scene_tree.cpp
msgid ""
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index f5557a0f3c..421a255054 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -626,7 +626,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1804,8 +1804,8 @@ msgid "Open a File or Directory"
msgstr "Ireki fitxategia edo direktorioa"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Gorde"
@@ -2440,7 +2440,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2830,14 +2830,6 @@ msgid "Help"
msgstr "Laguntza"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Bilatu"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Lineako dokumentuak"
@@ -2991,6 +2983,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3193,7 +3201,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3499,6 +3507,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3878,6 +3891,24 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Hautatu inportatu nahi dituzun nodoak"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Inportatu azala"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d fitxategi"
@@ -4827,7 +4858,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4931,7 +4962,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6699,6 +6729,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Bilatu"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6750,16 +6788,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6852,8 +6880,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7259,6 +7287,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9602,6 +9635,13 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr ""
+"Fitxategiak arakatzen,\n"
+"Itxaron mesedez..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9964,6 +10004,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Inportatu profila(k)"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10208,6 +10253,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Scripta"
@@ -10329,6 +10382,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10436,6 +10493,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11905,6 +11969,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12160,11 +12232,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 7445611ef2..4a1906f4e3 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -19,12 +19,13 @@
# MSKF <walkingdeadstudio@outlook.com>, 2020.
# Ahmad Maftoun <CarCedo.Pro@gmail.com>, 2020.
# ItzMiad44909858f5774b6d <maidggg@gmail.com>, 2020.
+# YASAN <yasandev@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-08 10:26+0000\n"
-"Last-Translator: MSKF <walkingdeadstudio@outlook.com>\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
+"Last-Translator: YASAN <yasandev@gmail.com>\n"
"Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/"
"godot/fa/>\n"
"Language: fa\n"
@@ -32,16 +33,16 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.3.2\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "نوع ورودی برای ()convert نامعتبر است, ثوابت *_TYPE‌ بکار گیرید ."
+msgstr "نوع نامعتبر ورودی برای ()convert، ثوابت *_TYPE‌ را بکار گیرید."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "یک رشته (string) در اندازه 1 (کاراکتر) انتظار می رود."
+msgstr "یک رشته به‌طول 1 ( یک کاراکتر) مورد انتظار است."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -658,7 +659,7 @@ msgstr "انتخاب میسرها جهت تکثیر"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "کپی"
@@ -1040,11 +1041,10 @@ msgid "Owners Of:"
msgstr "مالکانِ:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "آیا پرونده‌های انتخاب شده از طرح حذف شوند؟ (نمی‌توان بازیابی کرد)"
+msgstr "آیا پرونده‌های انتخاب شده از طرح حذف شوند؟ (غیر قابل بازیابی)"
#: editor/dependency_editor.cpp
#, fuzzy
@@ -1846,8 +1846,8 @@ msgid "Open a File or Directory"
msgstr "یک پرونده یا پوشه را باز کن"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "ذخیره"
@@ -2481,8 +2481,9 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "امکان بارگیری اسکریپت افزونه از مسیر وجود ندارد: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2879,14 +2880,6 @@ msgid "Help"
msgstr "راهنما"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "جستجو"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3046,6 +3039,23 @@ msgid "Open & Run a Script"
msgstr "گشودن و اجرای یک اسکریپت"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "استخراج پرونده های زیر از بسته بندی انجام نشد:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "وارث جدید"
@@ -3258,7 +3268,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "چسباندن"
@@ -3575,6 +3585,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3991,6 +4006,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "انتخاب حالت"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "وارد کردن"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "بارگیری پیش فرض"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5003,7 +5037,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5115,7 +5149,6 @@ msgid "Sort:"
msgstr "مرتب‌سازی:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "طبقه‌بندی:"
@@ -6974,6 +7007,14 @@ msgstr ""
msgid "Run"
msgstr "اجرا"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "جستجو"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7028,16 +7069,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7138,8 +7169,8 @@ msgstr "حذف کن"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "برش"
@@ -7573,6 +7604,11 @@ msgstr "بومی‌سازی"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10063,6 +10099,11 @@ msgid "Projects"
msgstr "طرح ها"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "بارگیری"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10441,6 +10482,11 @@ msgstr "AutoLoad"
msgid "Plugins"
msgstr "افزونه‌ها"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "بارگیری پیش فرض"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10699,6 +10745,15 @@ msgid "Instance Child Scene"
msgstr "ارث‌بری صحنهٔ فرزند"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "مسیر به سمت گره:"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "پیوست کردن اسکریپت"
@@ -10830,6 +10885,11 @@ msgid "Attach Script"
msgstr "پیوست کردن اسکریپت"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "ساختن گره"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "حذف گره(ها)"
@@ -10945,6 +11005,13 @@ msgid "Remote"
msgstr "از راه دور"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "محلی"
@@ -12542,6 +12609,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "یک CollisionPolygon2D خالی جلوه بر برخورد ندارد."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12832,11 +12907,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13354,10 +13424,6 @@ msgstr "ثوابت قابل تغییر نیستند."
#~ msgstr "ساختن پوشه"
#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "ساختن گره"
-
-#, fuzzy
#~ msgid "Invalid Path"
#~ msgstr "مسیر نامعتبر."
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 765ce4810c..dd1d5da4e8 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -11,12 +11,13 @@
# Tapani Niemi <tapani.niemi@kapsi.fi>, 2018, 2019, 2020, 2021.
# Tuomas Lähteenmäki <lahtis@gmail.com>, 2019.
# Matti Niskanen <matti.t.niskanen@gmail.com>, 2020.
+# Severi Vidnäs <severi.vidnas@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-21 11:57+0000\n"
-"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Severi Vidnäs <severi.vidnas@gmail.com>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
"Language: fi\n"
@@ -24,7 +25,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -648,7 +649,7 @@ msgstr "Valitse kopioitavat raidat"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopioi"
@@ -1760,7 +1761,7 @@ msgstr "Uusi"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Tuonti"
+msgstr "Tuo"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1857,8 +1858,8 @@ msgid "Open a File or Directory"
msgstr "Avaa tiedosto tai hakemisto"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Tallenna"
@@ -2530,8 +2531,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "Lisäosan '%s' aktivointi epäonnistui, virheellinen asetustiedosto."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "Skriptikenttää ei löytynyt lisäosan tiedostosta: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Skriptikenttää ei löytynyt lisäosan tiedostosta: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2957,14 +2958,6 @@ msgid "Help"
msgstr "Ohje"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Hae"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Dokumentaatio"
@@ -3129,6 +3122,24 @@ msgid "Open & Run a Script"
msgstr "Avaa ja suorita skripti"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Seuraavat tiedostot ovat uudempia levyllä.\n"
+"Mikä toimenpide tulisi suorittaa?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Lataa uudelleen"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Tallenna uudelleen"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Uusi peritty skene"
@@ -3340,7 +3351,7 @@ msgstr "Tee yksilölliseksi"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Liitä"
@@ -3656,6 +3667,13 @@ msgstr ""
"Tila: Tuonti epäonnistui. Ole hyvä, korjaa tiedosto ja tuo se uudelleen."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Tuonti on poistettu käytöstä tälle tiedostolle, joten sitä ei voi avata "
+"muokkausta varten."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ei voitu siirtää/nimetä uudelleen resurssien päätasoa."
@@ -4045,6 +4063,22 @@ msgstr ""
msgid "Saving..."
msgstr "Tallennetaan..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Valitse tuoja"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Tuoja:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Palauta oletusarvoihin"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Pidä tiedosto (ei tuontia)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d tiedostoa"
@@ -5014,8 +5048,8 @@ msgid "Got:"
msgstr "Saatiin:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "sha256-hajautusarvon tarkistus epäonnistui"
+msgid "Failed SHA-256 hash check"
+msgstr "SHA-256 hajautusarvon tarkistus epäonnistui"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5118,7 +5152,6 @@ msgid "Sort:"
msgstr "Lajittele:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategoria:"
@@ -6946,6 +6979,14 @@ msgstr "Sulje dokumentaatio"
msgid "Run"
msgstr "Suorita"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Hae"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Siirry sisään"
@@ -6999,16 +7040,6 @@ msgstr ""
"Seuraavat tiedostot ovat uudempia levyllä.\n"
"Mikä toimenpide tulisi suorittaa?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Lataa uudelleen"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Tallenna uudelleen"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Debuggeri"
@@ -7103,8 +7134,8 @@ msgstr "Keskeytyskohdat"
msgid "Go To"
msgstr "Mene"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Leikkaa"
@@ -7327,9 +7358,8 @@ msgid "Yaw"
msgstr "Käännös (yaw)"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Koko: "
+msgstr "Koko"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7513,6 +7543,11 @@ msgstr "Näkymän kierto lukittu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10014,6 +10049,10 @@ msgid "Projects"
msgstr "Projektit"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Ladataan, hetkinen..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Viimeksi muutettu"
@@ -10383,6 +10422,10 @@ msgstr "Automaattilataus"
msgid "Plugins"
msgstr "Liitännäiset"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Lataa oletusarvot"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Esiasetus..."
@@ -10632,6 +10675,14 @@ msgid "Instance Child Scene"
msgstr "Luo aliskenen ilmentymä"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Juurisolmua ei voida liittää samaan skeneen."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Liitä solmu(t)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Irrota skripti"
@@ -10761,6 +10812,10 @@ msgid "Attach Script"
msgstr "Liitä skripti"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Leikkaa solmu(t)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Poista solmu(t)"
@@ -10875,6 +10930,13 @@ msgid "Remote"
msgstr "Etäinen"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Paikallinen"
@@ -12421,6 +12483,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Tyhjällä CollisionPolygon2D solmulla ei ole vaikutusta törmäyksessä."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Virheellinen polygoni. 'Solids' luontitilassa tarvitaan ainakin kolme "
+"pistettä."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Virheellinen polygoni. 'Segments' luontitilassa tarvitaan ainakin kaksi "
+"pistettä."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12739,11 +12813,6 @@ msgstr ""
"GIProbe ei ole tuettu GLES2 näyttöajurissa.\n"
"Käytä sen sijaan BakedLightmap resurssia."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera on vanhentunut ja poistetaan Godot 4.0 versiossa."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13087,6 +13156,11 @@ msgstr "Varying tyypin voi sijoittaa vain vertex-funktiossa."
msgid "Constants cannot be modified."
msgstr "Vakioita ei voi muokata."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera on vanhentunut ja poistetaan Godot 4.0 versiossa."
+
#~ msgid "No"
#~ msgstr "Ei"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index ef79d29343..99964e6ee8 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -634,7 +634,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopya"
@@ -1804,8 +1804,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2440,7 +2440,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2830,14 +2830,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2992,6 +2984,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3195,7 +3203,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3499,6 +3507,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3876,6 +3889,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4824,7 +4853,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4928,7 +4957,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6699,6 +6727,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6750,16 +6786,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6852,8 +6878,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7259,6 +7285,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9602,6 +9633,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9962,6 +9997,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10206,6 +10245,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Burahin ang (mga) Napiling Key"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10326,6 +10374,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10433,6 +10485,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11905,6 +11964,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12160,11 +12227,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 4493eff913..1ce05a4b93 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -82,7 +82,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
+"PO-Revision-Date: 2021-03-21 12:25+0000\n"
"Last-Translator: Pierre Caye <pierrecaye@laposte.net>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
@@ -91,7 +91,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -728,7 +728,7 @@ msgstr "Sélectionner les pistes à copier"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copier"
@@ -1938,8 +1938,8 @@ msgid "Open a File or Directory"
msgstr "Ouvrir un fichier ou un répertoire"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Enregistrer"
@@ -2619,14 +2619,12 @@ msgstr "Réouvrir la scène fermée"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
-"Impossible d'activer le greffon depuis : « %s », l’analyse syntaxique de la "
+"Impossible d'activer le plugin depuis : « %s », l’analyse syntaxique de la "
"configuration a échoué."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"Impossible de trouver le champ de script pour le plugin dans : « res://"
-"addons/%s »."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Impossible de trouver le champ de script pour le plugin dans : « %s »."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3065,14 +3063,6 @@ msgid "Help"
msgstr "Aide"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Rechercher"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentation en ligne"
@@ -3239,6 +3229,24 @@ msgid "Open & Run a Script"
msgstr "Ouvrir et exécuter un script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Les fichiers suivants sont plus récents sur le disque.\n"
+"Quelle action doit être prise ?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Recharger"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Ré-enregistrer"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nouveau hérité"
@@ -3450,7 +3458,7 @@ msgstr "Rendre unique"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Coller"
@@ -3771,6 +3779,13 @@ msgstr ""
"le réimporter manuellement."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"L'importation a été désactivée pour ce fichier, il ne peut donc pas être "
+"ouvert dans l'éditeur."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossible de déplacer / renommer les ressources root."
@@ -4159,17 +4174,33 @@ msgstr ""
msgid "Saving..."
msgstr "Enregistrement…"
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Sélectionnez un importeur"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importeur :"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Réinitialiser"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Conserver le fichier (non importé)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d fichiers"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
-msgstr "Définir comme défaut pour « %s »"
+msgstr "Définir comme préréglage pour « %s »"
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr "Effacer le préréglage par défaut pour « %s »"
+msgstr "Effacer le préréglage pour « %s »"
#: editor/import_dock.cpp
msgid "Import As:"
@@ -4177,7 +4208,7 @@ msgstr "Importer comme :"
#: editor/import_dock.cpp
msgid "Preset"
-msgstr "Pré-réglage"
+msgstr "Préréglage"
#: editor/import_dock.cpp
msgid "Reimport"
@@ -4290,7 +4321,7 @@ msgstr "Modifier un plugin"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
-msgstr "Créer un Plugin"
+msgstr "Créer un plugin"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
@@ -5134,8 +5165,8 @@ msgid "Got:"
msgstr "A :"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Vérification de brouillage sha256 échouée"
+msgid "Failed SHA-256 hash check"
+msgstr "Vérification du hachage SHA-256 échouée"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5238,7 +5269,6 @@ msgid "Sort:"
msgstr "Trier :"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Catégorie :"
@@ -6021,7 +6051,7 @@ msgstr "Modifier la tangente de courbes"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Curve Preset"
-msgstr "Charger un pré-réglage de courbe"
+msgstr "Charger un préréglage de courbe"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Add Point"
@@ -7080,6 +7110,14 @@ msgstr "Fermer les documentations"
msgid "Run"
msgstr "Lancer"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Rechercher"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Rentrer"
@@ -7133,16 +7171,6 @@ msgstr ""
"Les fichiers suivants sont plus récents sur le disque.\n"
"Quelle action doit être prise ? :"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Recharger"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Ré-enregistrer"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Débogueur"
@@ -7239,8 +7267,8 @@ msgstr "Point d'arrêts"
msgid "Go To"
msgstr "Atteindre"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Couper"
@@ -7650,6 +7678,11 @@ msgstr "Rotation de la vue verrouillée"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9693,7 +9726,7 @@ msgstr "Exécutable"
#: editor/project_export.cpp
msgid "Delete preset '%s'?"
-msgstr "Supprimer le pré-réglage « %s » ?"
+msgstr "Supprimer le préréglage « %s » ?"
#: editor/project_export.cpp
msgid ""
@@ -9731,7 +9764,7 @@ msgstr "Modèles d'exportation manquants ou corrompus pour cette plateforme :"
#: editor/project_export.cpp
msgid "Presets"
-msgstr "Pré-réglages"
+msgstr "Préréglages"
#: editor/project_export.cpp editor/project_settings_editor.cpp
msgid "Add..."
@@ -9742,9 +9775,9 @@ msgid ""
"If checked, the preset will be available for use in one-click deploy.\n"
"Only one preset per platform may be marked as runnable."
msgstr ""
-"Si cette option est activée, le pré-réglage sera disponible pour le "
+"Si cette option est activée, le préréglage sera disponible pour le "
"déploiement en un clic.\n"
-"Un seul pré-réglage par plateforme peut être marqué comme exécutable."
+"Un seul préréglage par plateforme peut être marqué comme exécutable."
#: editor/project_export.cpp
msgid "Export Path"
@@ -10170,6 +10203,10 @@ msgid "Projects"
msgstr "Projets"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Chargement en cours, veuillez patienter..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Dernière modification"
@@ -10540,9 +10577,13 @@ msgstr "AutoLoad"
msgid "Plugins"
msgstr "Extensions"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Préréglage des importeurs"
+
#: editor/property_editor.cpp
msgid "Preset..."
-msgstr "Pré-réglage…"
+msgstr "Préréglage…"
#: editor/property_editor.cpp
msgid "Zero"
@@ -10789,6 +10830,14 @@ msgid "Instance Child Scene"
msgstr "Instancier une scène enfant"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Impossible de copier le nœud racine dans la même scène."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Coller le(s) nœud(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Détacher le script"
@@ -10915,6 +10964,10 @@ msgid "Attach Script"
msgstr "Attacher un script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Couper le(s) nœud(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Supprimer le(s) nœud(s)"
@@ -11030,6 +11083,13 @@ msgid "Remote"
msgstr "Distant"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -12608,6 +12668,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D vide n'a pas d'effet sur les collisions."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Polygone non valide. Il doit avoir au moins trois points en mode de "
+"construction 'Solide'."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Polygone non valide. Il doit y avoir au moins 2 points en mode de "
+"construction 'Segments'."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12932,11 +13004,6 @@ msgstr ""
"Les GIProps ne sont pas supporter par le pilote de vidéos GLES2.\n"
"A la place utilisez une BakedLightMap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera a été déprécié et sera supprimé dans Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13140,7 +13207,7 @@ msgid ""
msgstr ""
"Couleur : #%s\n"
"Clic gauche : Définir la couleur\n"
-"Clic droit : Supprimer le pré-réglage"
+"Clic droit : Supprimer le préréglage"
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
@@ -13160,7 +13227,7 @@ msgstr "Alterner entre les valeurs hexadécimales ou brutes."
#: scene/gui/color_picker.cpp
msgid "Add current color as a preset."
-msgstr "Ajouter la couleur courante comme pré-réglage."
+msgstr "Ajouter la couleur courante comme préréglage."
#: scene/gui/container.cpp
msgid ""
@@ -13290,6 +13357,10 @@ msgstr "Les variations ne peuvent être affectées que dans la fonction vertex."
msgid "Constants cannot be modified."
msgstr "Les constantes ne peuvent être modifiées."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera a été déprécié et sera supprimé dans Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Non"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 206dad7441..8a6c2a3f0b 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -627,7 +627,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1798,8 +1798,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2435,7 +2435,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2825,14 +2825,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2986,6 +2978,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3188,7 +3196,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3492,6 +3500,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3871,6 +3884,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -4821,7 +4850,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4925,7 +4954,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6693,6 +6721,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6744,16 +6780,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6846,8 +6872,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7253,6 +7279,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9597,6 +9628,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9957,6 +9992,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10200,6 +10239,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10320,6 +10367,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10427,6 +10478,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11901,6 +11959,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12156,11 +12222,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index c3efe67d46..771b0f07e6 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -1,13 +1,14 @@
-# LANGUAGE translation of the Godot Engine editor.
+# Galician translation of the Godot Engine editor.
# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
#
# Andy Barcia <andybarcia4@gmail.com>, 2021.
+# PokeGalaico <abloodyfreaks@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
+"PO-Revision-Date: 2021-02-15 10:51+0000\n"
"Last-Translator: Andy Barcia <andybarcia4@gmail.com>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/godot-engine/"
"godot/gl/>\n"
@@ -237,7 +238,7 @@ msgstr "Clips de Audio:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr ""
+msgstr "Clips de Animación:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -281,7 +282,7 @@ msgstr "Discreto"
#: editor/animation_track_editor.cpp
msgid "Trigger"
-msgstr ""
+msgstr "Detonante (Trigger)"
#: editor/animation_track_editor.cpp
msgid "Capture"
@@ -514,7 +515,7 @@ msgstr "Agrupar pistas por nodo ou mostralas coma unha simple lista."
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr ""
+msgstr "Axuste de Cuadrícula:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -644,7 +645,7 @@ msgstr "Selecciona as Pistas a Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -658,11 +659,11 @@ msgstr "Engadir Clip de Pista de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "Cambiar Inicio do Clip na Pista de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "Cambiar Final do Clip na Pista de Audio"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -959,11 +960,11 @@ msgstr "Descrición:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr ""
+msgstr "Buscar Substitución Para:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr ""
+msgstr "Dependencias De:"
#: editor/dependency_editor.cpp
msgid ""
@@ -971,7 +972,7 @@ msgid ""
"Changes will only take effect when reloaded."
msgstr ""
"A escena '%s' agora mesmo está sendo editada.\n"
-"Os cambios so terán efecto cando sexa recargada."
+"Os cambios só terán efecto cando sexa recargada."
#: editor/dependency_editor.cpp
msgid ""
@@ -979,7 +980,7 @@ msgid ""
"Changes will only take effect when reloaded."
msgstr ""
"O recurso '%s' agora mesmo está sendo usado.\n"
-"Os cambios so terán efecto cando sexa recargado."
+"Os cambios só terán efecto cando sexa recargado."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1001,7 +1002,7 @@ msgstr "Dependencias:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
-msgstr ""
+msgstr "Corrixir Erros"
#: editor/dependency_editor.cpp
msgid "Dependency Editor"
@@ -1101,7 +1102,7 @@ msgstr "É Dono de"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Recursos Sen Dono Explícito:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
@@ -1444,15 +1445,15 @@ msgstr "Non debe coincidir co nome dunha constante global xa existente."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Unha palabra clave non pode usarse como nome dun AutoCargador."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr ""
+msgstr "Xa existe un AutoCargador nomeado '%s'!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr ""
+msgstr "Renomear AutoCargador"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
@@ -1460,11 +1461,11 @@ msgstr ""
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
-msgstr ""
+msgstr "Mover AutoCargador"
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Eliminar AutoCargador"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
@@ -1472,15 +1473,15 @@ msgstr "Activar"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
-msgstr ""
+msgstr "Reordenar AutoCargadores"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Non se puido engadir AutoCargador:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr ""
+msgstr "Engadir AutoCargador"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
@@ -1559,7 +1560,7 @@ msgstr "Elixir"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr ""
+msgstr "Gardando Arquivo:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
@@ -1660,77 +1661,78 @@ msgstr "Biblioteca de Assets"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr ""
+msgstr "Edición de Árbore de Escenas"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Panel de Nodos"
#: editor/editor_feature_profile.cpp
msgid "FileSystem Dock"
-msgstr ""
+msgstr "Panel de Sistema de Arquivos"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr ""
+msgstr "Panel de Importación"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
-msgstr ""
+msgstr "Eliminar perfil '%s'? (non se pode deshacer)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Un perfil debe ter un nome de arquivo válido, e non pode conter '.'"
#: editor/editor_feature_profile.cpp
msgid "Profile with this name already exists."
-msgstr ""
+msgstr "Un perfil con este nome xa existe."
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled, Properties Disabled)"
-msgstr ""
+msgstr "(Editor Desactivado, Propiedades Desactivadas)"
#: editor/editor_feature_profile.cpp
msgid "(Properties Disabled)"
-msgstr ""
+msgstr "(Propiedades Desactivadas)"
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled)"
-msgstr ""
+msgstr "(Editor Desactivado)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr ""
+msgstr "Opcións de Clase:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
-msgstr ""
+msgstr "Activar o Editor Contextual"
#: editor/editor_feature_profile.cpp
msgid "Enabled Properties:"
-msgstr ""
+msgstr "Propiedades Activadas:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
-msgstr ""
+msgstr "Características Activadas:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Classes:"
-msgstr ""
+msgstr "Clases Activadas:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr ""
+msgstr "O formato '%s' do arquivo non é válido, a importación foi cancelada."
#: editor/editor_feature_profile.cpp
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
msgstr ""
+"O perfil '%s' xa existe. Elimínao antes de importar; importación abortada."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr ""
+msgstr "Erro gardando o perfil á ruta: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
@@ -1738,151 +1740,152 @@ msgstr ""
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
-msgstr ""
+msgstr "Perfil Actual:"
#: editor/editor_feature_profile.cpp
msgid "Make Current"
-msgstr ""
+msgstr "Convertelo no Actual"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "New"
-msgstr ""
+msgstr "Novo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr ""
+msgstr "Importación"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
-msgstr ""
+msgstr "Exportación"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
-msgstr ""
+msgstr "Perfils Dispoñibles:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
-msgstr ""
+msgstr "Opcións de Clase"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr ""
+msgstr "Nome do novo perfil:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
-msgstr ""
+msgstr "Eliminar Perfil"
#: editor/editor_feature_profile.cpp
msgid "Godot Feature Profile"
-msgstr ""
+msgstr "Perfil de Características de Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr ""
+msgstr "Importar Perfil(s)"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
-msgstr ""
+msgstr "Exportar Perfil"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Administrar Perfils de Características de Godot"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
-msgstr ""
+msgstr "Seleccionar Cartafol Actual"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File Exists, Overwrite?"
-msgstr ""
+msgstr "O arquivo xa existe ¿Queres sobreescribilo?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
-msgstr ""
+msgstr "Seleccionar Este Cartafol"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr ""
+msgstr "Copiar Ruta"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
-msgstr ""
+msgstr "Abrir no Explorador de Arquivos"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
msgid "Show in File Manager"
-msgstr ""
+msgstr "Amosar no Explorador de Arquivos"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "New Folder..."
-msgstr ""
+msgstr "Novo Cartafol..."
#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Refresh"
-msgstr ""
+msgstr "Actualizar"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr ""
+msgstr "Todos Recoñecidos"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
-msgstr ""
+msgstr "Todos os Arquivos (*)"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a File"
-msgstr ""
+msgstr "Abrir un Arquivo"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open File(s)"
-msgstr ""
+msgstr "Abrir Arquivo(s)"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a Directory"
-msgstr ""
+msgstr "Abrir un Directorio"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a File or Directory"
-msgstr ""
+msgstr "Abrir un Arquivo ou Directorio"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
-msgstr ""
+msgstr "Gardar"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Save a File"
-msgstr ""
+msgstr "Gardar un Arquivo"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr ""
+msgstr "Retroceder"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr ""
+msgstr "Avanzar"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr ""
+msgstr "Subir"
#: editor/editor_file_dialog.cpp
+#, fuzzy
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Amosar/Ocultar Arquivos Ocultos"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Act./Desact. Favorito"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr ""
+msgstr "Act./Desact. Modo"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -1890,61 +1893,61 @@ msgstr ""
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr ""
+msgstr "Subir Favorito"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr ""
+msgstr "Baixar Favorito"
#: editor/editor_file_dialog.cpp
msgid "Go to previous folder."
-msgstr ""
+msgstr "Ir ao cartafol anterior."
#: editor/editor_file_dialog.cpp
msgid "Go to next folder."
-msgstr ""
+msgstr "Ir ao cartafol seguinte."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr ""
+msgstr "Ir ao cartafol padre."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
-msgstr ""
+msgstr "Actualizar Arquivos."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
-msgstr ""
+msgstr "Quitar cartafol actual de favoritos."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
-msgstr ""
+msgstr "Amosar/Ocultar arquivos ocultos."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr ""
+msgstr "Ver elementos coma unha cuadrícula de miniaturas."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
-msgstr ""
+msgstr "Ver elementos coma unha lista."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Directories & Files:"
-msgstr ""
+msgstr "Directorios e Arquivos:"
#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
#: editor/plugins/style_box_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Preview:"
-msgstr ""
+msgstr "Vista Previa:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File:"
-msgstr ""
+msgstr "Arquivo:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr ""
+msgstr "Escanear Fontes"
#: editor/editor_file_system.cpp
msgid ""
@@ -1954,52 +1957,53 @@ msgstr ""
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "(Re)Importando Assets"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr ""
+msgstr "Superior"
#: editor/editor_help.cpp
msgid "Class:"
-msgstr ""
+msgstr "Clase:"
#: editor/editor_help.cpp editor/scene_tree_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Inherits:"
-msgstr ""
+msgstr "Herda de:"
#: editor/editor_help.cpp
msgid "Inherited by:"
-msgstr ""
+msgstr "Herdado de:"
#: editor/editor_help.cpp
msgid "Description"
-msgstr ""
+msgstr "Descrición"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr ""
+msgstr "Tutoriales en liña"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr ""
+msgstr "Propiedades"
#: editor/editor_help.cpp
msgid "override:"
-msgstr ""
+msgstr "sobrescribir:"
#: editor/editor_help.cpp
msgid "default:"
-msgstr ""
+msgstr "por defecto:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr ""
+msgstr "Métodos"
#: editor/editor_help.cpp
+#, fuzzy
msgid "Theme Properties"
-msgstr ""
+msgstr "Propiedades do Tema"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2007,120 +2011,124 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Constantes"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr ""
+msgstr "Descrición de Propiedades"
#: editor/editor_help.cpp
msgid "(value)"
-msgstr ""
+msgstr "(valor)"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Actualmente non hai unha descripción desta propiedade. Axúdanos [color="
+"$color][url=$url]contribuíndo cunha descripción[/url][/color]!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr ""
+msgstr "Descrición de Métodos"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Actualmente non hai unha descripción deste método. Axúdanos [color=$color]"
+"[url=$url]contribuíndo cunha descripción[/url][/color]!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr ""
+msgstr "Buscar na Axuda"
#: editor/editor_help_search.cpp
msgid "Case Sensitive"
-msgstr ""
+msgstr "Distinguir Maíusculas e Minúsculas"
#: editor/editor_help_search.cpp
msgid "Show Hierarchy"
-msgstr ""
+msgstr "Amosar Xerarquía"
#: editor/editor_help_search.cpp
msgid "Display All"
-msgstr ""
+msgstr "Amosar Todo"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr ""
+msgstr "Só Clases"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr ""
+msgstr "Só Métodos"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr ""
+msgstr "Só Sinais"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr ""
+msgstr "Só Constantes"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr ""
+msgstr "Só Propiedades"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Só Propiedades de Temas"
#: editor/editor_help_search.cpp
msgid "Member Type"
-msgstr ""
+msgstr "Tipo do Membro"
#: editor/editor_help_search.cpp
msgid "Class"
-msgstr ""
+msgstr "Clase"
#: editor/editor_help_search.cpp
msgid "Method"
-msgstr ""
+msgstr "Método"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr ""
+msgstr "Sinal"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr ""
+msgstr "Constante"
#: editor/editor_help_search.cpp
msgid "Property"
-msgstr ""
+msgstr "Propiedade"
#: editor/editor_help_search.cpp
msgid "Theme Property"
-msgstr ""
+msgstr "Propiedade de Temas"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Propiedade:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Establecer"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Establecer Varios:"
#: editor/editor_log.cpp
msgid "Output:"
-msgstr ""
+msgstr "Saída:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Copy Selection"
-msgstr ""
+msgstr "Copiar Selección"
#: editor/editor_log.cpp editor/editor_network_profiler.cpp
#: editor/editor_profiler.cpp editor/editor_properties.cpp
@@ -2130,144 +2138,152 @@ msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Clear"
-msgstr ""
+msgstr "Limpar"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr ""
+msgstr "Limpar Saída"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
msgid "Stop"
-msgstr ""
+msgstr "Deter"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Iniciar"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
msgid "Down"
-msgstr ""
+msgstr "Baixada"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Subida"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
-msgstr ""
+msgstr "Nodo"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC Entrante"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET Entrante"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC Saínte"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET Saínte"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Nova Xanela"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Os recursos importados non se poden gardar."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "Vale"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Erro gardando o recurso!"
#: editor/editor_node.cpp
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Este recurso non pode gardarse porque non pertence á escena actual. Primero "
+"fágao único."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
-msgstr ""
+msgstr "Gardar Recurso Como..."
#: editor/editor_node.cpp
msgid "Can't open file for writing:"
-msgstr ""
+msgstr "Non se puido abrir o arquivo para escritura:"
#: editor/editor_node.cpp
msgid "Requested file format unknown:"
-msgstr ""
+msgstr "O formato do arquivo solicitado é descoñecido:"
#: editor/editor_node.cpp
msgid "Error while saving."
-msgstr ""
+msgstr "Erro ao gardar."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
msgstr ""
+"Non se puido abrir '%s'. Pode ser que o arquivo fose movido ou eliminado."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr ""
+msgstr "Erro ao analizar sintacticamente '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr ""
+msgstr "Fin de arquivo inesperado en '%s'."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "Non se encontrou '%s' ou as súas dependencias."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
-msgstr ""
+msgstr "Erro ao cargar '%s'."
#: editor/editor_node.cpp
msgid "Saving Scene"
-msgstr ""
+msgstr "Gardando Escena"
#: editor/editor_node.cpp
msgid "Analyzing"
-msgstr ""
+msgstr "Analizando"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
-msgstr ""
+msgstr "Creando Miniatura"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr ""
+msgstr "Esta operación non pode realizarse sen un nodo raíz."
#: editor/editor_node.cpp
msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Esta escena non pode gardarse porque hai unha relación de instanciación "
+"cíclica con outra escena.\n"
+"Por favor, solucione o problema e inténteo de novo."
#: editor/editor_node.cpp
msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
msgstr ""
+"Non se puido gardar a escena. Posiblemente as dependencias (instancias ou "
+"herenzas) non puideron satisfacerse."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "Non se pode sobreescribir escena que sigue aberta!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
@@ -2290,6 +2306,9 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Produciuse un erro mentres se trataba de gardar a disposición das ventás do "
+"editor.\n"
+"Asegúrese de que o cartafol do editor ten dereitos de escritura."
#: editor/editor_node.cpp
msgid ""
@@ -2297,14 +2316,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"A disposición por defecto do editor foi sobreescrita.\n"
+"Para devolver a disposición por defecto a súa configuración orixinal, usa a "
+"opción 'Eliminar Disposición' e elimina a Disposición por defecto."
#: editor/editor_node.cpp
msgid "Layout name not found!"
-msgstr ""
+msgstr "Nome de disposición non encontrada!"
#: editor/editor_node.cpp
msgid "Restored the Default layout to its base settings."
-msgstr ""
+msgstr "Restableceuse a disposición por defecto aos seus valores orixinais."
#: editor/editor_node.cpp
msgid ""
@@ -2312,18 +2334,25 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Este recurso pertence a unha escena importada, polo que non é editable.\n"
+"Por favor; lea a documentación referente a importación de escenas para "
+"entender o fluxo de traballo."
#: editor/editor_node.cpp
msgid ""
"This resource belongs to a scene that was instanced or inherited.\n"
"Changes to it won't be kept when saving the current scene."
msgstr ""
+"Este recurso pertence a unha escena instanciada ou herdada.\n"
+"Os cambios que lle faga non se gardarán cando garde a escena actual."
#: editor/editor_node.cpp
msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
+"Este recurso foi importado, polo que non é editable. Cambia a súa "
+"configuración no panel de importación, e reimportao."
#: editor/editor_node.cpp
msgid ""
@@ -2332,6 +2361,10 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Esta escena foi importada, polo que cambios na escena non serán gardados.\n"
+"Instanciala ou herdala permitirá facerlle cambios permanentes.\n"
+"Por favor, lea a documentación referente a importación de escenas para "
+"entender o fluxo de traballo."
#: editor/editor_node.cpp
msgid ""
@@ -2339,70 +2372,74 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
+"Este é un obxecto remoto, polo que os cambios que lle faga non serán "
+"permanentes.\n"
+"Por favor; lea a documentación referente a depuración para entender o fluxo "
+"de traballo."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
-msgstr ""
+msgstr "Non hai unha escena definida para executar."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Garda a escena antes de executala..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
-msgstr ""
+msgstr "Non se puido iniciar subproceso!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr ""
+msgstr "Abrir Escena"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr ""
+msgstr "Abrir Escena Base"
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr ""
+msgstr "Apertura Rápida..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr ""
+msgstr "Apertura Rápida de Escena..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr ""
+msgstr "Apertura Rápida de Script..."
#: editor/editor_node.cpp
msgid "Save & Close"
-msgstr ""
+msgstr "Gardar e Pechar"
#: editor/editor_node.cpp
msgid "Save changes to '%s' before closing?"
-msgstr ""
+msgstr "Gardar os cambios de '%s' antes de pechar?"
#: editor/editor_node.cpp
msgid "Saved %s modified resource(s)."
-msgstr ""
+msgstr "Gardado(s) %s recurso(s) modificado(s)."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "Necesítase un nodo raíz para gardar a escena."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr ""
+msgstr "Gardar Escena Como..."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
-msgstr ""
+msgstr "Esta operación non pode realizarse se unha escena."
#: editor/editor_node.cpp
msgid "Export Mesh Library"
-msgstr ""
+msgstr "Exportar Biblioteca de Mallas"
#: editor/editor_node.cpp
msgid "This operation can't be done without a root node."
-msgstr ""
+msgstr "Esta operación non pode realizarse sen un nodo raíz."
#: editor/editor_node.cpp
msgid "Export Tile Set"
@@ -2410,122 +2447,145 @@ msgstr ""
#: editor/editor_node.cpp
msgid "This operation can't be done without a selected node."
-msgstr ""
+msgstr "Esta operación non pode realizarse sen un nodo seleccionado."
#: editor/editor_node.cpp
msgid "Current scene not saved. Open anyway?"
-msgstr ""
+msgstr "Escena actual non gardada ¿Abrir de todos os modos?"
#: editor/editor_node.cpp
msgid "Can't reload a scene that was never saved."
-msgstr ""
+msgstr "Non se pode volver a cargar unha escena que nunca foi gardada."
#: editor/editor_node.cpp
msgid "Reload Saved Scene"
-msgstr ""
+msgstr "Recargar Escena Gardada"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"A escena actual ten cambios non gardados.\n"
+"Quere volver a cargar a escena cargada de todos os modos? Esta acción non se "
+"pode deshacer."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
-msgstr ""
+msgstr "Execución Rápida de Escena..."
#: editor/editor_node.cpp
msgid "Quit"
-msgstr ""
+msgstr "Saír"
#: editor/editor_node.cpp
msgid "Yes"
-msgstr ""
+msgstr "Si"
#: editor/editor_node.cpp
msgid "Exit the editor?"
-msgstr ""
+msgstr "Saír do editor?"
#: editor/editor_node.cpp
msgid "Open Project Manager?"
-msgstr ""
+msgstr "Abrir o Administrador de Proxectos?"
#: editor/editor_node.cpp
msgid "Save & Quit"
-msgstr ""
+msgstr "Gardar e Saír"
#: editor/editor_node.cpp
msgid "Save changes to the following scene(s) before quitting?"
-msgstr ""
+msgstr "Gardar os cambios nas seguintes escenas antes de saír?"
#: editor/editor_node.cpp
msgid "Save changes the following scene(s) before opening Project Manager?"
msgstr ""
+"Gardar os cambios nas seguintes escenas antes de abrir o Administrador de "
+"Proxectos?"
#: editor/editor_node.cpp
msgid ""
"This option is deprecated. Situations where refresh must be forced are now "
"considered a bug. Please report."
msgstr ""
+"Esta opción está anticuada. As situacións nas que a actualización debe ser "
+"forzada agora considéranse un erro. Por favor, repórtao."
#: editor/editor_node.cpp
msgid "Pick a Main Scene"
-msgstr ""
+msgstr "Elexir unha Escena Principal"
#: editor/editor_node.cpp
msgid "Close Scene"
-msgstr ""
+msgstr "Pechar Escena"
#: editor/editor_node.cpp
msgid "Reopen Closed Scene"
-msgstr ""
+msgstr "Reabrir Escena Pechada"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
+"Non se puido activar a característica adicional (Plugin): Fallou a análise "
+"sintáctica da configuración de '%s'."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
+"Non se puido encontrar o campo do Script na característica adicional "
+"(Plugin) en 'res://addons/%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
msgstr ""
+"Non se puido cargar Script de característica adicional (Addon) na ruta: '%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"Non se puido cargar Script de característica adicional (Addon) na ruta: "
+"'%s'. Parece que hai un erro no código; por favor, comproba a sintaxe."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Non se puido cargar o Script da característica adicional (Plugin): O tipo "
+"base de %s non é EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Non se puido cargar Script de característica adicional (Addon) na ruta: "
+"'%s'. O script non está en modo ferramenta (tool)."
#: editor/editor_node.cpp
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
+"A escena '%s' foi automáticamente importada, polo que non pode modificarse.\n"
+"Para facerlle cambios pódese crear unha nova escena herdada."
#: editor/editor_node.cpp
msgid ""
"Error loading scene, it must be inside the project path. Use 'Import' to "
"open the scene, then save it inside the project path."
msgstr ""
+"Erro cargando a escena: debe estar dentro da ruta do proxecto. Usa \"Importar"
+"\" para abrir a escena, e despois gardala dentro da ruta do proxecto."
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
-msgstr ""
+msgstr "A escena '%s' ten dependencias rotas:"
#: editor/editor_node.cpp
msgid "Clear Recent Scenes"
-msgstr ""
+msgstr "Limpar Escenas Recentes"
#: editor/editor_node.cpp
msgid ""
@@ -2533,6 +2593,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Nunca se definiu unha escena principal. Seleccionar unha?\n"
+"Podes cambialo despois na \"Configuración do Proxecto\", na categoría "
+"\"Aplicación\"."
#: editor/editor_node.cpp
msgid ""
@@ -2540,6 +2603,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"A escena seleccionada '%s' non existe. Seleccionar unha válida?\n"
+"Podes cambiala despois en \"Configuración do Proxecto\" na categoría "
+"\"aplicación\"."
#: editor/editor_node.cpp
msgid ""
@@ -2547,48 +2613,52 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"A escena seleccionada '%s' non é un arquivo de escenas. Seleccionar un "
+"arquivo válido?\n"
+"Podes cambialo despois en \"Configuración do Proxecto\" na categoría "
+"\"aplicación\"."
#: editor/editor_node.cpp
msgid "Save Layout"
-msgstr ""
+msgstr "Gardar Disposición"
#: editor/editor_node.cpp
msgid "Delete Layout"
-msgstr ""
+msgstr "Eliminar Dispoción"
#: editor/editor_node.cpp editor/import_dock.cpp
#: editor/script_create_dialog.cpp
msgid "Default"
-msgstr ""
+msgstr "Por Defecto"
#: editor/editor_node.cpp editor/editor_properties.cpp
#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
msgid "Show in FileSystem"
-msgstr ""
+msgstr "Amosar no Sistema de Arquivos"
#: editor/editor_node.cpp
msgid "Play This Scene"
-msgstr ""
+msgstr "Reproducir Esta Escena"
#: editor/editor_node.cpp
msgid "Close Tab"
-msgstr ""
+msgstr "Pechar Pestana"
#: editor/editor_node.cpp
msgid "Undo Close Tab"
-msgstr ""
+msgstr "Desfacer Pechar Pestana"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
-msgstr ""
+msgstr "Pechar Outras Pestanas"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr ""
+msgstr "Pechar Pestanas á Dereita"
#: editor/editor_node.cpp
msgid "Close All Tabs"
-msgstr ""
+msgstr "Pechar Todas as Pestanas"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
@@ -2596,87 +2666,87 @@ msgstr ""
#: editor/editor_node.cpp
msgid "%d more files or folders"
-msgstr ""
+msgstr "%d arquivos ou cartafois máis"
#: editor/editor_node.cpp
msgid "%d more folders"
-msgstr ""
+msgstr "%d cartafois máis"
#: editor/editor_node.cpp
msgid "%d more files"
-msgstr ""
+msgstr "%d arquivos máis"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr ""
+msgstr "Posición do Panel"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
-msgstr ""
+msgstr "Modo Sen Distraccións"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr ""
+msgstr "Act./Desact. modo sen distraccións."
#: editor/editor_node.cpp
msgid "Add a new scene."
-msgstr ""
+msgstr "Engadir unha nova escena."
#: editor/editor_node.cpp
msgid "Scene"
-msgstr ""
+msgstr "Escena"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
-msgstr ""
+msgstr "Ir á escena aberta previamente."
#: editor/editor_node.cpp
msgid "Copy Text"
-msgstr ""
+msgstr "Copiar Texto"
#: editor/editor_node.cpp
msgid "Next tab"
-msgstr ""
+msgstr "Seguinte pestana"
#: editor/editor_node.cpp
msgid "Previous tab"
-msgstr ""
+msgstr "Anterior Pestana"
#: editor/editor_node.cpp
msgid "Filter Files..."
-msgstr ""
+msgstr "Filtrar Arquivos..."
#: editor/editor_node.cpp
msgid "Operations with scene files."
-msgstr ""
+msgstr "Operacións con arquivos de escenas."
#: editor/editor_node.cpp
msgid "New Scene"
-msgstr ""
+msgstr "Nova Escena"
#: editor/editor_node.cpp
msgid "New Inherited Scene..."
-msgstr ""
+msgstr "Nova Escena Herdada..."
#: editor/editor_node.cpp
msgid "Open Scene..."
-msgstr ""
+msgstr "Abrir Escena..."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Open Recent"
-msgstr ""
+msgstr "Abrir Recente"
#: editor/editor_node.cpp
msgid "Save Scene"
-msgstr ""
+msgstr "Gardar Escena"
#: editor/editor_node.cpp
msgid "Save All Scenes"
-msgstr ""
+msgstr "Gardar Todas as Escenas"
#: editor/editor_node.cpp
msgid "Convert To..."
-msgstr ""
+msgstr "Converter a..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
@@ -2689,41 +2759,41 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Undo"
-msgstr ""
+msgstr "Desfacer"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr ""
+msgstr "Refacer"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
-msgstr ""
+msgstr "Ferramentas varias do proxecto ou escena."
#: editor/editor_node.cpp editor/project_manager.cpp
#: editor/script_create_dialog.cpp
msgid "Project"
-msgstr ""
+msgstr "Proxecto"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr ""
+msgstr "Axustes do Proxecto..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
-msgstr ""
+msgstr "Control de Versións"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Configurar Control de Versións"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "Desactivar Control de Versións"
#: editor/editor_node.cpp
msgid "Export..."
-msgstr ""
+msgstr "Exportar..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
@@ -2731,28 +2801,28 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
-msgstr ""
+msgstr "Abrir Cartafol de Datos do Proxecto"
#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
msgid "Tools"
-msgstr ""
+msgstr "Ferramentas"
#: editor/editor_node.cpp
msgid "Orphan Resource Explorer..."
-msgstr ""
+msgstr "Explorador de Recursos Orfos..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
-msgstr ""
+msgstr "Saír á Lista de Proxectos"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
msgid "Debug"
-msgstr ""
+msgstr "Depuración"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
-msgstr ""
+msgstr "Exportar con Depuración Remota"
#: editor/editor_node.cpp
msgid ""
@@ -2763,10 +2833,17 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
+"Cando esta opción está activada, usar o despregue dun só clic fará que o "
+"executable intente conectarse a IP deste computador, para poder depurar o "
+"proxecto mentres este está executandose no dispositivo.\n"
+"Esta opción está pensada para ser utilizada coa depuración remota "
+"(normalmente nun dispositivo móbil).\n"
+"Non necesita activar esta opción para utilizar o depurador de GDScript de "
+"forma local."
#: editor/editor_node.cpp
msgid "Small Deploy with Network Filesystem"
-msgstr ""
+msgstr "Exportación Reducida co Sistema de Arquivos en Rede"
#: editor/editor_node.cpp
msgid ""
@@ -2777,6 +2854,12 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
+"Cando esta opción está activada, usar o despregue don só clic para Android "
+"exportará só o executable, sen os datos do proxecto.\n"
+"O sistema de arquivos proporcionarase por o editor na rede.\n"
+"En Android ao despregar a aplicación usarase o USB para obter maior "
+"rendemento. Esta opción acelera o proceso de proba en proxectos con gran "
+"cantidade de Assets."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
@@ -2790,7 +2873,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Navigation"
-msgstr ""
+msgstr "Navegación Visible"
#: editor/editor_node.cpp
msgid ""
@@ -2800,7 +2883,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Synchronize Scene Changes"
-msgstr ""
+msgstr "Sincronizar Cambios na Escena"
#: editor/editor_node.cpp
msgid ""
@@ -2809,10 +2892,14 @@ msgid ""
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
+"Cando esta opción está activada, calquera cambio na escena no editor verase "
+"reflectido no proxecto en execución.\n"
+"Cando é usado remotamente nun dispositivo, é máis eficiente cando o sistema "
+"de arquivos en rede está activado."
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
-msgstr ""
+msgstr "Sincronizar Cambios nos Scripts"
#: editor/editor_node.cpp
msgid ""
@@ -2821,50 +2908,56 @@ msgid ""
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
+"Cando esta opción está activada, calquera script gardada será recargada no "
+"proxecto mentras este está en execución.\n"
+"Cando é usado remotamente nun dispositivo, é máis eficiente cando o sistema "
+"de arquivos en rede está activado."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
-msgstr ""
+msgstr "Editor"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr ""
+msgstr "Configuración do Editor..."
#: editor/editor_node.cpp
msgid "Editor Layout"
-msgstr ""
+msgstr "Disposición das Ventás do Editor"
#: editor/editor_node.cpp
msgid "Take Screenshot"
-msgstr ""
+msgstr "Captura de Pantalla"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
msgstr ""
+"As capturas de pantalla gárdanse no cartafol de Datos/Configuración do "
+"Editor."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr ""
+msgstr "Act./Desact. Pantalla Completa"
#: editor/editor_node.cpp
msgid "Toggle System Console"
-msgstr ""
+msgstr "Act./Desact. Consola do Sistema"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr ""
+msgstr "Abrir Cartafol de Datos/Configuración do Editor"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr ""
+msgstr "Abrir Cartafol de Datos do Editor"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr ""
+msgstr "Abrir Cartafol de Configuración do Editor"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
-msgstr ""
+msgstr "Administrar Características do Editor..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2872,97 +2965,89 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
msgid "Help"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
+msgstr "Axuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
-msgstr ""
+msgstr "Documentación En Liña"
#: editor/editor_node.cpp
msgid "Q&A"
-msgstr ""
+msgstr "Preguntas e Respostas"
#: editor/editor_node.cpp
msgid "Report a Bug"
-msgstr ""
+msgstr "Reportar un Erro"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "Reportar Problema ca Documentación"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr ""
+msgstr "Comunidade"
#: editor/editor_node.cpp
msgid "About"
-msgstr ""
+msgstr "Acerca De"
#: editor/editor_node.cpp
msgid "Play the project."
-msgstr ""
+msgstr "Reproduce o proxecto."
#: editor/editor_node.cpp
msgid "Play"
-msgstr ""
+msgstr "Executar"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
-msgstr ""
+msgstr "Pausa a execución da escena para a depuración."
#: editor/editor_node.cpp
msgid "Pause Scene"
-msgstr ""
+msgstr "Pausar Escena"
#: editor/editor_node.cpp
msgid "Stop the scene."
-msgstr ""
+msgstr "Detén a escena."
#: editor/editor_node.cpp
msgid "Play the edited scene."
-msgstr ""
+msgstr "Reproduce a escena actual."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr ""
+msgstr "Executar Escena"
#: editor/editor_node.cpp
msgid "Play custom scene"
-msgstr ""
+msgstr "Executar escena a elixir"
#: editor/editor_node.cpp
msgid "Play Custom Scene"
-msgstr ""
+msgstr "Executar Escena a Elixir"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr ""
+msgstr "Cambiar o controlador de vídeo require reiniciar o editor."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
msgid "Save & Restart"
-msgstr ""
+msgstr "Gardar e Reinicar"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr ""
+msgstr "Xira cando o editor actualiza a pantalla."
#: editor/editor_node.cpp
msgid "Update Continuously"
-msgstr ""
+msgstr "Actualizar de Maneira Continua"
#: editor/editor_node.cpp
msgid "Update When Changed"
-msgstr ""
+msgstr "Actualizar Cando Sexa Necesario"
#: editor/editor_node.cpp
msgid "Hide Update Spinner"
@@ -2970,23 +3055,23 @@ msgstr ""
#: editor/editor_node.cpp
msgid "FileSystem"
-msgstr ""
+msgstr "Sistema de Arquivos"
#: editor/editor_node.cpp
msgid "Inspector"
-msgstr ""
+msgstr "Inspector"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
-msgstr ""
+msgstr "Estender Panel Inferior"
#: editor/editor_node.cpp
msgid "Output"
-msgstr ""
+msgstr "Saída"
#: editor/editor_node.cpp
msgid "Don't Save"
-msgstr ""
+msgstr "Non Gardar"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
@@ -3025,180 +3110,203 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Export Library"
-msgstr ""
+msgstr "Biblioteca de Exportación"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr ""
+msgstr "Combinar Con Existentes"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
+msgstr "Abrir e Executar un Script"
+
+#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
msgstr ""
+"Este shader foi modificado en disco.\n"
+"Que acción deberían de tomarse?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Recargar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Volver a Gardar"
#: editor/editor_node.cpp
msgid "New Inherited"
-msgstr ""
+msgstr "Nova Escena Herdada"
#: editor/editor_node.cpp
msgid "Load Errors"
-msgstr ""
+msgstr "Erros durante a Carga"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
-msgstr ""
+msgstr "Elixir"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr ""
+msgstr "Abrir Editor 2D"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr ""
+msgstr "Abrir Editor 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr ""
+msgstr "Abrir Editor de Scripts"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
-msgstr ""
+msgstr "Abrir Biblioteca de Assets"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr ""
+msgstr "Abrir o seguinte editor"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr ""
+msgstr "Abrir o anterior editor"
#: editor/editor_node.h
msgid "Warning!"
-msgstr ""
+msgstr "Aviso!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
-msgstr ""
+msgstr "Non se atopou ningún sub-recurso."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
-msgstr ""
+msgstr "Creando Previsualización de Mallas"
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
-msgstr ""
+msgstr "Miniatura..."
#: editor/editor_plugin_settings.cpp
msgid "Main Script:"
-msgstr ""
+msgstr "Script Principal:"
#: editor/editor_plugin_settings.cpp
msgid "Edit Plugin"
-msgstr ""
+msgstr "Editar Característica Adicional (Plugin)"
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr ""
+msgstr "Características Adicionais (Plugins) Instalados:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
-msgstr ""
+msgstr "Actualizar"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Version:"
-msgstr ""
+msgstr "Versión:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Author:"
-msgstr ""
+msgstr "Autor:"
#: editor/editor_plugin_settings.cpp
msgid "Status:"
-msgstr ""
+msgstr "Estado:"
#: editor/editor_plugin_settings.cpp
msgid "Edit:"
-msgstr ""
+msgstr "Editar:"
#: editor/editor_profiler.cpp
msgid "Measure:"
-msgstr ""
+msgstr "Medida:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr ""
+msgstr "Duración de Fotograma (seg)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
-msgstr ""
+msgstr "Tempo Medio (seg)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Fotograma %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr ""
+msgstr "Fotograma de Física %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr ""
+msgstr "Inclusivo"
#: editor/editor_profiler.cpp
msgid "Self"
-msgstr ""
+msgstr "Propio"
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Fotograma #:"
#: editor/editor_profiler.cpp
msgid "Time"
-msgstr ""
+msgstr "Tempo"
#: editor/editor_profiler.cpp
msgid "Calls"
-msgstr ""
+msgstr "Chamadas"
#: editor/editor_properties.cpp
msgid "Edit Text:"
-msgstr ""
+msgstr "Editar Texto:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
-msgstr ""
+msgstr "Activado"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Capa"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
-msgstr ""
+msgstr "Bit %d, valor %d"
#: editor/editor_properties.cpp
msgid "[Empty]"
-msgstr ""
+msgstr "[Baleiro]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr ""
+msgstr "Asignar..."
#: editor/editor_properties.cpp
msgid "Invalid RID"
-msgstr ""
+msgstr "Identificador de Recurso (RID) inválido"
#: editor/editor_properties.cpp
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
msgstr ""
+"O recurso seleccionado (%s) non coincide con ningún tipo esperado para esta "
+"propiedade (%s)."
#: editor/editor_properties.cpp
msgid ""
"Can't create a ViewportTexture on resources saved as a file.\n"
"Resource needs to belong to a scene."
msgstr ""
+"Non se pode crear un ViewportTexture nun recurso gardado coma un arquivo.\n"
+"O recurso ten que pertencer a unha escena."
#: editor/editor_properties.cpp
msgid ""
@@ -3210,23 +3318,23 @@ msgstr ""
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Pick a Viewport"
-msgstr ""
+msgstr "Selecciona unha Mini-Ventá (Viewport)"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New Script"
-msgstr ""
+msgstr "Novo Script"
#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
msgid "Extend Script"
-msgstr ""
+msgstr "Estender Script"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New %s"
-msgstr ""
+msgstr "Novo %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Make Unique"
-msgstr ""
+msgstr "Facer Único"
#: editor/editor_properties.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
@@ -3238,42 +3346,42 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
-msgstr ""
+msgstr "Pegar"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Convert To %s"
-msgstr ""
+msgstr "Converter a %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Selected node is not a Viewport!"
-msgstr ""
+msgstr "O nodo seleccionado non é unha Mini-Ventá (Viewport)!"
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
-msgstr ""
+msgstr "Tamaño: "
#: editor/editor_properties_array_dict.cpp
msgid "Page: "
-msgstr ""
+msgstr "Páxina: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Item"
-msgstr ""
+msgstr "Eliminar Elemento"
#: editor/editor_properties_array_dict.cpp
msgid "New Key:"
-msgstr ""
+msgstr "Nova Chave:"
#: editor/editor_properties_array_dict.cpp
msgid "New Value:"
-msgstr ""
+msgstr "Novo Valor:"
#: editor/editor_properties_array_dict.cpp
msgid "Add Key/Value Pair"
-msgstr ""
+msgstr "Engadir Parella Chave/Valor"
#: editor/editor_run_native.cpp
msgid ""
@@ -3281,67 +3389,72 @@ msgid ""
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
+"Non se encontraron axustes de exportación executables para esta plataforma.\n"
+"Engade uns axustes de exportación executables, ou define algún xa existente "
+"como executable."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
-msgstr ""
+msgstr "Escribe a túa lóxica no método '_run()'."
#: editor/editor_run_script.cpp
msgid "There is an edited scene already."
-msgstr ""
+msgstr "Xa hai unha escena editada."
#: editor/editor_run_script.cpp
msgid "Couldn't instance script:"
-msgstr ""
+msgstr "Non se puido instanciar o script:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr ""
+msgstr "Olvidaches a palabra clave 'tool'?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
-msgstr ""
+msgstr "Non se puido executar o script:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr ""
+msgstr "Olvidaches o método '_run'?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
+"Mantén pulsado Ctrl para redondear a enteiros. Mantén pulsado Shift para "
+"cambios máis precisos."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
-msgstr ""
+msgstr "Selecciona o(s) Nodo(s) a Importar"
#: editor/editor_sub_scene.cpp editor/project_manager.cpp
msgid "Browse"
-msgstr ""
+msgstr "Examinar"
#: editor/editor_sub_scene.cpp
msgid "Scene Path:"
-msgstr ""
+msgstr "Ruta da Escena:"
#: editor/editor_sub_scene.cpp
msgid "Import From Node:"
-msgstr ""
+msgstr "Importar Desde Nodo:"
#: editor/export_template_manager.cpp
msgid "Redownload"
-msgstr ""
+msgstr "Volver a Descargar"
#: editor/export_template_manager.cpp
msgid "Uninstall"
-msgstr ""
+msgstr "Desinstalar"
#: editor/export_template_manager.cpp
msgid "(Installed)"
-msgstr ""
+msgstr "(Instalado)"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download"
-msgstr ""
+msgstr "Descargar"
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
@@ -3349,11 +3462,11 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "(Missing)"
-msgstr ""
+msgstr "(Non encontrado)"
#: editor/export_template_manager.cpp
msgid "(Current)"
-msgstr ""
+msgstr "(Actual)"
#: editor/export_template_manager.cpp
msgid "Retrieving mirrors, please wait..."
@@ -3385,7 +3498,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Importing:"
-msgstr ""
+msgstr "Importando:"
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
@@ -3409,16 +3522,16 @@ msgstr ""
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't connect."
-msgstr ""
+msgstr "Non se pode conectar."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No response."
-msgstr ""
+msgstr "Sen resposta."
#: editor/export_template_manager.cpp
msgid "Request Failed."
-msgstr ""
+msgstr "A Petición Fracasou."
#: editor/export_template_manager.cpp
msgid "Redirect Loop."
@@ -3427,15 +3540,15 @@ msgstr ""
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed:"
-msgstr ""
+msgstr "Fracasado:"
#: editor/export_template_manager.cpp
msgid "Download Complete."
-msgstr ""
+msgstr "Descarga Completa."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
-msgstr ""
+msgstr "Non se pode eliminar o arquivo temporal:"
#: editor/export_template_manager.cpp
msgid ""
@@ -3445,7 +3558,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
-msgstr ""
+msgstr "Erro ao solicitar a URL:"
#: editor/export_template_manager.cpp
msgid "Connecting to Mirror..."
@@ -3453,61 +3566,61 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Disconnected"
-msgstr ""
+msgstr "Desconectado"
#: editor/export_template_manager.cpp
msgid "Resolving"
-msgstr ""
+msgstr "Resolvendo"
#: editor/export_template_manager.cpp
msgid "Can't Resolve"
-msgstr ""
+msgstr "Non se puido Resolver"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connecting..."
-msgstr ""
+msgstr "Conectando..."
#: editor/export_template_manager.cpp
msgid "Can't Connect"
-msgstr ""
+msgstr "Non se Pode Conectar"
#: editor/export_template_manager.cpp
msgid "Connected"
-msgstr ""
+msgstr "Conectado"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Requesting..."
-msgstr ""
+msgstr "Solicitando..."
#: editor/export_template_manager.cpp
msgid "Downloading"
-msgstr ""
+msgstr "Descargando"
#: editor/export_template_manager.cpp
msgid "Connection Error"
-msgstr ""
+msgstr "Erro de Conexión"
#: editor/export_template_manager.cpp
msgid "SSL Handshake Error"
-msgstr ""
+msgstr "Erro SSL Handshake"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr ""
+msgstr "Descomprimindo Recursos de Compilación de Android"
#: editor/export_template_manager.cpp
msgid "Current Version:"
-msgstr ""
+msgstr "Versión Actual:"
#: editor/export_template_manager.cpp
msgid "Installed Versions:"
-msgstr ""
+msgstr "Versións Instaladas:"
#: editor/export_template_manager.cpp
msgid "Install From File"
-msgstr ""
+msgstr "Instalar Dende Arquivo"
#: editor/export_template_manager.cpp
msgid "Remove Template"
@@ -3531,15 +3644,22 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr ""
+msgstr "Seleccione un mirror da lista: (Shift+Clic: Abrir no Navegador)"
#: editor/filesystem_dock.cpp
msgid "Favorites"
-msgstr ""
+msgstr "Favoritos"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
+"Estado: Fallou a importación do arquivo. Por favor, amaña o arquivo e "
+"impórtao manualmente."
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3547,35 +3667,35 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Cannot move a folder into itself."
-msgstr ""
+msgstr "Non se pode mover un cartafol dentro de sí mesmo."
#: editor/filesystem_dock.cpp
msgid "Error moving:"
-msgstr ""
+msgstr "Erro ao mover:"
#: editor/filesystem_dock.cpp
msgid "Error duplicating:"
-msgstr ""
+msgstr "Erro ao duplicar:"
#: editor/filesystem_dock.cpp
msgid "Unable to update dependencies:"
-msgstr ""
+msgstr "Incapaz de actualizar dependencias:"
#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
msgid "No name provided."
-msgstr ""
+msgstr "Nome non proporcionado."
#: editor/filesystem_dock.cpp
msgid "Provided name contains invalid characters."
-msgstr ""
+msgstr "O nome proporcionado contén caracteres inválidos."
#: editor/filesystem_dock.cpp
msgid "A file or folder with this name already exists."
-msgstr ""
+msgstr "Xa existe un arquivo ou cartafol con este nome."
#: editor/filesystem_dock.cpp
msgid "Name contains invalid characters."
-msgstr ""
+msgstr "O nome contén caracteres inválidos."
#: editor/filesystem_dock.cpp
msgid ""
@@ -3586,257 +3706,267 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"Os seguintes arquivos ou cartafois entran en conflicto con elementos da "
+"ubicación de destino '%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Queres sobreescribilos?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
-msgstr ""
+msgstr "Renomeando Arquivo:"
#: editor/filesystem_dock.cpp
msgid "Renaming folder:"
-msgstr ""
+msgstr "Renomeando Cartafol:"
#: editor/filesystem_dock.cpp
msgid "Duplicating file:"
-msgstr ""
+msgstr "Duplicando Arquivo:"
#: editor/filesystem_dock.cpp
msgid "Duplicating folder:"
-msgstr ""
+msgstr "Duplicando Cartafol:"
#: editor/filesystem_dock.cpp
msgid "New Inherited Scene"
-msgstr ""
+msgstr "Nova Escena Herdada"
#: editor/filesystem_dock.cpp
msgid "Set As Main Scene"
-msgstr ""
+msgstr "Establecer coma Escena Principal"
#: editor/filesystem_dock.cpp
msgid "Open Scenes"
-msgstr ""
+msgstr "Abrir Escenas"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr ""
+msgstr "Instanciar"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
-msgstr ""
+msgstr "Engadir a Favoritos"
#: editor/filesystem_dock.cpp
msgid "Remove from Favorites"
-msgstr ""
+msgstr "Eliminar de Favoritos"
#: editor/filesystem_dock.cpp
msgid "Edit Dependencies..."
-msgstr ""
+msgstr "Editar Dependencias..."
#: editor/filesystem_dock.cpp
msgid "View Owners..."
-msgstr ""
+msgstr "Ver Donos..."
#: editor/filesystem_dock.cpp
msgid "Move To..."
-msgstr ""
+msgstr "Mover a..."
#: editor/filesystem_dock.cpp
msgid "New Scene..."
-msgstr ""
+msgstr "Nova Escena..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
-msgstr ""
+msgstr "Novo Script..."
#: editor/filesystem_dock.cpp
msgid "New Resource..."
-msgstr ""
+msgstr "Novo Recurso..."
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Expand All"
-msgstr ""
+msgstr "Expandir Todo"
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Collapse All"
-msgstr ""
+msgstr "Colapsar Todo"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
-msgstr ""
+msgstr "Duplicar..."
#: editor/filesystem_dock.cpp
msgid "Move to Trash"
-msgstr ""
+msgstr "Mover á Papeleira"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
-msgstr ""
+msgstr "Renomear..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
-msgstr ""
+msgstr "Anterior Cartafol/Arquivo"
#: editor/filesystem_dock.cpp
msgid "Next Folder/File"
-msgstr ""
+msgstr "Seguinte Cartafol/Arquivo"
#: editor/filesystem_dock.cpp
msgid "Re-Scan Filesystem"
-msgstr ""
+msgstr "Reexaminar Sistema de Arquivos"
#: editor/filesystem_dock.cpp
msgid "Toggle Split Mode"
-msgstr ""
+msgstr "Act./Desact. Modo Dividido"
#: editor/filesystem_dock.cpp
msgid "Search files"
-msgstr ""
+msgstr "Buscar arquivos"
#: editor/filesystem_dock.cpp
msgid ""
"Scanning Files,\n"
"Please Wait..."
msgstr ""
+"Examinando arquivos,\n"
+"Por favor, espere..."
#: editor/filesystem_dock.cpp
msgid "Move"
-msgstr ""
+msgstr "Mover"
#: editor/filesystem_dock.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/project_manager.cpp editor/rename_dialog.cpp
#: editor/scene_tree_dock.cpp
msgid "Rename"
-msgstr ""
+msgstr "Renomear"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
-msgstr ""
+msgstr "Sobreescribir"
#: editor/filesystem_dock.cpp
msgid "Create Scene"
-msgstr ""
+msgstr "Crear Escena"
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "Create Script"
-msgstr ""
+msgstr "Crear Script"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
msgid "Find in Files"
-msgstr ""
+msgstr "Buscar en Arquivos"
#: editor/find_in_files.cpp
msgid "Find:"
-msgstr ""
+msgstr "Buscar:"
#: editor/find_in_files.cpp
msgid "Folder:"
-msgstr ""
+msgstr "Cartafol:"
#: editor/find_in_files.cpp
msgid "Filters:"
-msgstr ""
+msgstr "Filtros:"
#: editor/find_in_files.cpp
msgid ""
"Include the files with the following extensions. Add or remove them in "
"ProjectSettings."
msgstr ""
+"Inclúe os arquivos coas seguintes extensións. Engádeos ou elimínaos na "
+"Configuración do proxecto."
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find..."
-msgstr ""
+msgstr "Buscar..."
#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
msgid "Replace..."
-msgstr ""
+msgstr "Substituír..."
#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
msgid "Cancel"
-msgstr ""
+msgstr "Cancelar"
#: editor/find_in_files.cpp
msgid "Find: "
-msgstr ""
+msgstr "Buscar: "
#: editor/find_in_files.cpp
msgid "Replace: "
-msgstr ""
+msgstr "Substituír: "
#: editor/find_in_files.cpp
msgid "Replace all (no undo)"
-msgstr ""
+msgstr "Substituír todo (non se pode defacer)"
#: editor/find_in_files.cpp
msgid "Searching..."
-msgstr ""
+msgstr "Procurando..."
#: editor/find_in_files.cpp
msgid "%d match in %d file."
-msgstr ""
+msgstr "%d coincidencia en %d arquivo."
#: editor/find_in_files.cpp
msgid "%d matches in %d file."
-msgstr ""
+msgstr "%d coincidencias en %d arquivo."
#: editor/find_in_files.cpp
msgid "%d matches in %d files."
-msgstr ""
+msgstr "%d coincidencias en %d arquivos."
#: editor/groups_editor.cpp
msgid "Add to Group"
-msgstr ""
+msgstr "Engadir ao Grupo"
#: editor/groups_editor.cpp
msgid "Remove from Group"
-msgstr ""
+msgstr "Eliminar do Grupo"
#: editor/groups_editor.cpp
msgid "Group name already exists."
-msgstr ""
+msgstr "Este nome de grupo xa existe."
#: editor/groups_editor.cpp
msgid "Invalid group name."
-msgstr ""
+msgstr "Nome de grupo inválido."
#: editor/groups_editor.cpp
msgid "Rename Group"
-msgstr ""
+msgstr "Renomear Grupo"
#: editor/groups_editor.cpp
msgid "Delete Group"
-msgstr ""
+msgstr "Eliminar Grupo"
#: editor/groups_editor.cpp editor/node_dock.cpp
msgid "Groups"
-msgstr ""
+msgstr "Grupos"
#: editor/groups_editor.cpp
msgid "Nodes Not in Group"
-msgstr ""
+msgstr "Nodos Fora do Grupo"
#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
#: editor/scene_tree_editor.cpp
msgid "Filter nodes"
-msgstr ""
+msgstr "Filtrar nodos"
#: editor/groups_editor.cpp
msgid "Nodes in Group"
-msgstr ""
+msgstr "Nodos no Grupo"
#: editor/groups_editor.cpp
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Os grupos baleiros serán automaticamente eliminados."
#: editor/groups_editor.cpp
msgid "Group Editor"
-msgstr ""
+msgstr "Editor de Grupos"
#: editor/groups_editor.cpp
msgid "Manage Groups"
-msgstr ""
+msgstr "Administrar Grupos"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Single Scene"
@@ -3844,31 +3974,31 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Animations"
-msgstr ""
+msgstr "Importar con Animacións Separadas"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials"
-msgstr ""
+msgstr "Importar con Materiais Separados"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects"
-msgstr ""
+msgstr "Importar con Obxectos Separados"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials"
-msgstr ""
+msgstr "Importar con Obxectos e Materiais Separados"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Animations"
-msgstr ""
+msgstr "Importar con Obxectos e Animacións Separadas"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials+Animations"
-msgstr ""
+msgstr "Importar con Materiais e Animacións Separadas"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials+Animations"
-msgstr ""
+msgstr "Importar con Obxectos, Materiais, e Animacións Separados"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes"
@@ -3876,16 +4006,16 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes+Materials"
-msgstr ""
+msgstr "Importar como Escenas e Materiales Múltiples"
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import Scene"
-msgstr ""
+msgstr "Importar Escena"
#: editor/import/resource_importer_scene.cpp
msgid "Importing Scene..."
-msgstr ""
+msgstr "Importando Escena..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
@@ -3917,11 +4047,30 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
+msgstr "Gardando..."
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Elixir Modo"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importación"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Cargar Valores por Defecto"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
msgstr ""
#: editor/import_dock.cpp
msgid "%d Files"
-msgstr ""
+msgstr "%d Arquivos"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
@@ -3933,15 +4082,15 @@ msgstr ""
#: editor/import_dock.cpp
msgid "Import As:"
-msgstr ""
+msgstr "Importar Como:"
#: editor/import_dock.cpp
msgid "Preset"
-msgstr ""
+msgstr "Axustes de Importación"
#: editor/import_dock.cpp
msgid "Reimport"
-msgstr ""
+msgstr "Reimportar"
#: editor/import_dock.cpp
msgid "Save Scenes, Re-Import, and Restart"
@@ -3958,24 +4107,24 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
-msgstr ""
+msgstr "Fallou a carga do Recurso."
#: editor/inspector_dock.cpp
msgid "Expand All Properties"
-msgstr ""
+msgstr "Expandir Tódalas Propiedades"
#: editor/inspector_dock.cpp
msgid "Collapse All Properties"
-msgstr ""
+msgstr "Colapsar Tódalas Propiedades"
#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Save As..."
-msgstr ""
+msgstr "Gardar Como..."
#: editor/inspector_dock.cpp
msgid "Copy Params"
-msgstr ""
+msgstr "Copiar Parámetros"
#: editor/inspector_dock.cpp
msgid "Edit Resource Clipboard"
@@ -3983,7 +4132,7 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Copy Resource"
-msgstr ""
+msgstr "Copiar Recurso"
#: editor/inspector_dock.cpp
msgid "Make Built-In"
@@ -3995,7 +4144,7 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Open in Help"
-msgstr ""
+msgstr "Abrir na Axuda"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
@@ -4023,15 +4172,15 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Object properties."
-msgstr ""
+msgstr "Propiedade de Obxectos."
#: editor/inspector_dock.cpp
msgid "Filter properties"
-msgstr ""
+msgstr "Filtrar propiedades"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
-msgstr ""
+msgstr "Os cambios poderían perderse!"
#: editor/multi_node_edit.cpp
msgid "MultiNode Set"
@@ -4039,46 +4188,46 @@ msgstr ""
#: editor/node_dock.cpp
msgid "Select a single node to edit its signals and groups."
-msgstr ""
+msgstr "Seleccione un nodo para editar as súas sinais e grupos."
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Editar unha Característica Adicional (Plugin)"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
-msgstr ""
+msgstr "Crear unha Característica Adicional (Plugin)"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Nome do Plugin:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
-msgstr ""
+msgstr "Subcartafol:"
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
msgid "Language:"
-msgstr ""
+msgstr "Linguaxe:"
#: editor/plugin_config_dialog.cpp
msgid "Script Name:"
-msgstr ""
+msgstr "Nome do Script:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
-msgstr ""
+msgstr "Activar agora?"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon"
-msgstr ""
+msgstr "Crear Polígono"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create points."
-msgstr ""
+msgstr "Crear puntos."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid ""
@@ -4086,27 +4235,30 @@ msgid ""
"LMB: Move Point\n"
"RMB: Erase Point"
msgstr ""
+"Editar puntos.\n"
+"Clic Izq: Mover Punto\n"
+"Clic Der: Eliminar Punto"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Erase points."
-msgstr ""
+msgstr "Borrar puntos."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon"
-msgstr ""
+msgstr "Editar Polígono"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Insert Point"
-msgstr ""
+msgstr "Inserir Punto"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon (Remove Point)"
-msgstr ""
+msgstr "Editar Polígono (Eliminar Punto)"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Remove Polygon And Point"
-msgstr ""
+msgstr "Eliminar Polígono e Punto"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4114,14 +4266,14 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Animation"
-msgstr ""
+msgstr "Engadir Animación"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Load..."
-msgstr ""
+msgstr "Cargar..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4140,7 +4292,7 @@ msgstr ""
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "This type of node can't be used. Only root nodes are allowed."
-msgstr ""
+msgstr "Non se pode usar este tipo de nodo. Só nodos raíz están permitidos."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4168,6 +4320,9 @@ msgid ""
"AnimationTree is inactive.\n"
"Activate to enable playback, check node warnings if activation fails."
msgstr ""
+"O AnimationTree está inactivo.\n"
+"Actívao para permitir a reprodución; e comproba os avisos do nodo se hai un "
+"erro na activación."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4182,18 +4337,18 @@ msgstr ""
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr ""
+msgstr "Activar axuste de cuadrícula e amosar cuadrícula."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Point"
-msgstr ""
+msgstr "Punto"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr ""
+msgstr "Abrir Editor"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4208,7 +4363,7 @@ msgstr ""
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Triangle"
-msgstr ""
+msgstr "Engadir Triángulo"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Change BlendSpace2D Limits"
@@ -4253,16 +4408,16 @@ msgstr ""
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend:"
-msgstr ""
+msgstr "Mezcla:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Parameter Changed"
-msgstr ""
+msgstr "Parámetro Cambiado"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Filters"
-msgstr ""
+msgstr "Editar Flitros"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Output node can't be added to the blend tree."
@@ -4274,7 +4429,7 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Node Moved"
-msgstr ""
+msgstr "Nodo Movido"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Unable to connect, port may be in use or connection may be invalid."
@@ -4283,26 +4438,26 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Connected"
-msgstr ""
+msgstr "Nodos Conectado"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Disconnected"
-msgstr ""
+msgstr "Nodos Desconectados"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Set Animation"
-msgstr ""
+msgstr "Establecer Animación"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Delete Node"
-msgstr ""
+msgstr "Eliminar Nodo"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/scene_tree_dock.cpp
msgid "Delete Node(s)"
-msgstr ""
+msgstr "Eliminar Nodo(s)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Toggle Filter On/Off"
@@ -4310,7 +4465,7 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Change Filter"
-msgstr ""
+msgstr "Cambiar Filtro"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "No animation player set, so unable to retrieve track names."
@@ -4329,25 +4484,25 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Anim Clips"
-msgstr ""
+msgstr "Clips de Animación"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Audio Clips"
-msgstr ""
+msgstr "Clips de Audio"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Functions"
-msgstr ""
+msgstr "Funcións"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Renamed"
-msgstr ""
+msgstr "Nodo Renomeado"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node..."
-msgstr ""
+msgstr "Engadir Nodo..."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
@@ -4360,7 +4515,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Toggle Autoplay"
-msgstr ""
+msgstr "Act./Desact. Auto-reproducción"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Animation Name:"
@@ -4368,7 +4523,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Anim"
-msgstr ""
+msgstr "Nova Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Animation Name:"
@@ -4377,12 +4532,12 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Animation?"
-msgstr ""
+msgstr "Eliminar Animación?"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Remove Animation"
-msgstr ""
+msgstr "Eliminar Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
@@ -4395,7 +4550,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Rename Animation"
-msgstr ""
+msgstr "Renomear Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Next Changed"
@@ -4407,11 +4562,11 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Load Animation"
-msgstr ""
+msgstr "Cargar Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Duplicate Animation"
-msgstr ""
+msgstr "Duplicar Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to copy!"
@@ -4423,11 +4578,11 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
-msgstr ""
+msgstr "Animación Pegada"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Paste Animation"
-msgstr ""
+msgstr "Pegar Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to edit!"
@@ -4463,19 +4618,19 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Tools"
-msgstr ""
+msgstr "Ferramentas de Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
-msgstr ""
+msgstr "Animación"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
-msgstr ""
+msgstr "Editar Transicións..."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Open in Inspector"
-msgstr ""
+msgstr "Abrir no Inspector"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
@@ -4495,19 +4650,19 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Directions"
-msgstr ""
+msgstr "Direccións"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Past"
-msgstr ""
+msgstr "Pasado"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Future"
-msgstr ""
+msgstr "Futuro"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Depth"
-msgstr ""
+msgstr "Profundidad"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "1 step"
@@ -4543,14 +4698,14 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Name:"
-msgstr ""
+msgstr "Nome da Animación:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
msgid "Error!"
-msgstr ""
+msgstr "Erro!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Times:"
@@ -4566,40 +4721,40 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Move Node"
-msgstr ""
+msgstr "Mover Nodo"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition exists!"
-msgstr ""
+msgstr "Existe transición!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
-msgstr ""
+msgstr "Engadir Transición"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node"
-msgstr ""
+msgstr "Engadir Nodo"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
-msgstr ""
+msgstr "Fin"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "Inmediata"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
-msgstr ""
+msgstr "Sincronizar"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
-msgstr ""
+msgstr "Ao Final"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "Viaxe"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
@@ -4611,11 +4766,11 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
-msgstr ""
+msgstr "Nodo Eliminado"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition Removed"
-msgstr ""
+msgstr "Transición Eliminada"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
@@ -4630,11 +4785,11 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Create new nodes."
-msgstr ""
+msgstr "Crear novos nodos."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Connect nodes."
-msgstr ""
+msgstr "Conectar nodos."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Remove selected node or transition."
@@ -4650,11 +4805,11 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition: "
-msgstr ""
+msgstr "Transición: "
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Play Mode:"
-msgstr ""
+msgstr "Modo de Reprodución:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -4663,12 +4818,12 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
-msgstr ""
+msgstr "Novo nome:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Scale:"
-msgstr ""
+msgstr "Escala:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade In (s):"
@@ -4680,19 +4835,19 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend"
-msgstr ""
+msgstr "Mezcla"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Mix"
-msgstr ""
+msgstr "Mezcla"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Auto Restart:"
-msgstr ""
+msgstr "Auto Reinicio:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Restart (s):"
-msgstr ""
+msgstr "Reiniciar (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Random Restart (s):"
@@ -4700,12 +4855,12 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Start!"
-msgstr ""
+msgstr "Comezar!"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Amount:"
-msgstr ""
+msgstr "Cantidade:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend 0:"
@@ -4721,13 +4876,13 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Current:"
-msgstr ""
+msgstr "Actual:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Input"
-msgstr ""
+msgstr "Engadir Entrada"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Clear Auto-Advance"
@@ -4739,7 +4894,7 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Delete Input"
-msgstr ""
+msgstr "Eliminar Entrada"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation tree is valid."
@@ -4751,11 +4906,11 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation Node"
-msgstr ""
+msgstr "Nodo de Animación"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "OneShot Node"
-msgstr ""
+msgstr "Nodo de Execución Única (Oneshot)"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Mix Node"
@@ -4787,27 +4942,27 @@ msgstr ""
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Import Animations..."
-msgstr ""
+msgstr "Importar Animacións..."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Node Filters"
-msgstr ""
+msgstr "Editar Filtros do Nodo"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Filters..."
-msgstr ""
+msgstr "Filtros..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Contents:"
-msgstr ""
+msgstr "Contidos:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "View Files"
-msgstr ""
+msgstr "Ver Arquivos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connection error, please try again."
-msgstr ""
+msgstr "Houbo un erro na conexión; por favor, inténtao de novo."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't connect to host:"
@@ -4815,7 +4970,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No response from host:"
-msgstr ""
+msgstr "Non houbo respota por parte do host:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't resolve hostname:"
@@ -4827,7 +4982,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed."
-msgstr ""
+msgstr "A petición fallou."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Cannot save response to:"
@@ -4835,7 +4990,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr ""
+msgstr "Erro de escritura."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, too many redirects"
@@ -4851,7 +5006,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Timeout."
-msgstr ""
+msgstr "Timeout."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
@@ -4859,14 +5014,14 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Expected:"
-msgstr ""
+msgstr "Esperado:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Got:"
-msgstr ""
+msgstr "Recibido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4875,15 +5030,15 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading (%s / %s)..."
-msgstr ""
+msgstr "Descargando (%s / %s)..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading..."
-msgstr ""
+msgstr "Descargando..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Resolving..."
-msgstr ""
+msgstr "Resolvendo..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Error making request"
@@ -4891,19 +5046,19 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Idle"
-msgstr ""
+msgstr "Ocioso"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Install..."
-msgstr ""
+msgstr "Instalar..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Retry"
-msgstr ""
+msgstr "Reintentar"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download Error"
-msgstr ""
+msgstr "Erro na Descarga"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
@@ -4911,7 +5066,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr ""
+msgstr "Actualizado Recentemente"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
@@ -4919,80 +5074,79 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Nome (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Nome (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "License (A-Z)"
-msgstr ""
+msgstr "Licenza (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "License (Z-A)"
-msgstr ""
+msgstr "Licenza (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "First"
-msgstr ""
+msgstr "Primeiro"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Previous"
-msgstr ""
+msgstr "Anterior"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Next"
-msgstr ""
+msgstr "Seguinte"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Last"
-msgstr ""
+msgstr "Derradeiro"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "All"
-msgstr ""
+msgstr "Todos"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No results for \"%s\"."
-msgstr ""
+msgstr "Non houbo resultado para \"%s\"."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
-msgstr ""
+msgstr "Importar..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Características Adicionais (Plugins)..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
-msgstr ""
+msgstr "Ordenar:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
-msgstr ""
+msgstr "Categoría:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr ""
+msgstr "Sitio:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Support"
-msgstr ""
+msgstr "Soporte"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
-msgstr ""
+msgstr "Oficial"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Testing"
-msgstr ""
+msgstr "Probas"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Loading..."
-msgstr ""
+msgstr "Cargando..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
@@ -5023,6 +5177,8 @@ msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"Algunha malla é inválida. Asegúrese de que o os valores do canle UV2 están "
+"contidos dentro da rexión cadrada ([0.0,1.0], [0.0,1.0])."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5040,11 +5196,11 @@ msgstr ""
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Preview"
-msgstr ""
+msgstr "Vista Previa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr ""
+msgstr "Configurar Axuste de Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
@@ -5076,31 +5232,31 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
-msgstr ""
+msgstr "Mover Guía Vertical"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Vertical Guide"
-msgstr ""
+msgstr "Crear Guía Vertical"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Remove Vertical Guide"
-msgstr ""
+msgstr "Eliminar Guía Vertical"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Horizontal Guide"
-msgstr ""
+msgstr "Mover Guía Horizontal"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal Guide"
-msgstr ""
+msgstr "Crear Guía Horizontal"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Remove Horizontal Guide"
-msgstr ""
+msgstr "Eliminar Guía Horizontal"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal and Vertical Guides"
-msgstr ""
+msgstr "Crear Guías Horizontais e Verticais"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
@@ -5160,83 +5316,83 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Left"
-msgstr ""
+msgstr "Arriba á Esquerda"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Right"
-msgstr ""
+msgstr "Arriba á Dereita"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Right"
-msgstr ""
+msgstr "Abaixo á Dereita"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Left"
-msgstr ""
+msgstr "Abaixo á Esquerda"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Left"
-msgstr ""
+msgstr "Centro á Esquerda"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
-msgstr ""
+msgstr "Centro Arriba"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Right"
-msgstr ""
+msgstr "Centro á Dereita"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Bottom"
-msgstr ""
+msgstr "Centro Abaixo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
-msgstr ""
+msgstr "Centro"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Left Wide"
-msgstr ""
+msgstr "Esquerdo Alto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Wide"
-msgstr ""
+msgstr "Arriba Ancho"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Right Wide"
-msgstr ""
+msgstr "Dereito Alto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Wide"
-msgstr ""
+msgstr "Abaixo Ancho"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
-msgstr ""
+msgstr "CentradoV Alto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "HCenter Wide"
-msgstr ""
+msgstr "CentradoH Ancho"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
-msgstr ""
+msgstr "Recta Completa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Keep Ratio"
-msgstr ""
+msgstr "Manter Relación de Aspecto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
-msgstr ""
+msgstr "Só Áncoras"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors and Margins"
-msgstr ""
+msgstr "Cambiar Áncoras e Marxes"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors"
-msgstr ""
+msgstr "Cambiar Áncoras"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5244,6 +5400,8 @@ msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Substituír a Cámara do Xogo\n"
+"Substitue a cámara do xogo pola cámara da Mini-ventá (Viewport) do editor."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5265,20 +5423,20 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Group Selected"
-msgstr ""
+msgstr "Agrupar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Ungroup Selected"
-msgstr ""
+msgstr "Desagrupar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Paste Pose"
-msgstr ""
+msgstr "Pegar Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Guides"
-msgstr ""
+msgstr "Limpar Guías"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Custom Bone(s) from Node(s)"
@@ -5286,7 +5444,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Bones"
-msgstr ""
+msgstr "Limpar Ósos"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make IK Chain"
@@ -5301,25 +5459,27 @@ msgid ""
"Warning: Children of a container get their position and size determined only "
"by their parent."
msgstr ""
+"Aviso: Os nodos fillos dun contedor (Container) teñen determinada a súa "
+"posición e tamaño unicamente polo seu padre."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom Reset"
-msgstr ""
+msgstr "Restablecer Zoom"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Select Mode"
-msgstr ""
+msgstr "Elixir Modo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Drag: Rotate"
-msgstr ""
+msgstr "Arrastrar: Rotar"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+Drag: Move"
-msgstr ""
+msgstr "Alt+Arrastrar: Mover"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
@@ -5332,17 +5492,17 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Mover Modo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr ""
+msgstr "Modo Rotación"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr ""
+msgstr "Modo Escalado"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5350,10 +5510,12 @@ msgid ""
"Show a list of all objects at the position clicked\n"
"(same as Alt+RMB in select mode)."
msgstr ""
+"Amosa unha lista de obxectos na posición na que se fixo clic\n"
+"(O mesmo que usar Alt+Clic Dereito en modo selección)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Click to change object's rotation pivot."
-msgstr ""
+msgstr "Faga clic para cambiar o pivote de rotación do obxecto."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan Mode"
@@ -5361,96 +5523,96 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Ruler Mode"
-msgstr ""
+msgstr "Modo Regra"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr ""
+msgstr "Act./Desact. axuste intelixente."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Smart Snap"
-msgstr ""
+msgstr "Usar Axuste Intelixente"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr ""
+msgstr "Act./Desact. axuste de cuadrícula."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
-msgstr ""
+msgstr "Usar Axuste de Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr ""
+msgstr "Opcións de Axuste de Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr ""
+msgstr "Empregar Axuste de Rotación"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Scale Snap"
-msgstr ""
+msgstr "Empregar Axuste de Escalado"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr ""
+msgstr "Axuste Relativo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr ""
+msgstr "Empregar Axuste aos Píxeles"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr ""
+msgstr "Axuste Intelixente"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr ""
+msgstr "Configurar Axuste de Cuadrícula..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
-msgstr ""
+msgstr "Axustar ao Pai"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Anchor"
-msgstr ""
+msgstr "Axustar á Áncora do Nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Sides"
-msgstr ""
+msgstr "Axustar aos Laterais do Nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Center"
-msgstr ""
+msgstr "Axustar ao Centro do Nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Other Nodes"
-msgstr ""
+msgstr "Axustar a Outros Nodos"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Guides"
-msgstr ""
+msgstr "Axustar as Guías"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock the selected object in place (can't be moved)."
-msgstr ""
+msgstr "Fixar o obxecto no sitio (non se poderá mover)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr ""
+msgstr "Liberar o obxecto seleccionado (pode moverse)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Makes sure the object's children are not selectable."
-msgstr ""
+msgstr "Asegúrase de que os fillos do obxecto non sexan seleccionables."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Restores the object's children's ability to be selected."
-msgstr ""
+msgstr "Volve a permitir seleccionar os fillos do obxecto."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Skeleton Options"
@@ -5458,11 +5620,11 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Bones"
-msgstr ""
+msgstr "Amosar Ósos"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
-msgstr ""
+msgstr "Crear Óso(s) Personalizados a partir de Nodo(s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
@@ -5471,11 +5633,11 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View"
-msgstr ""
+msgstr "Ver"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
-msgstr ""
+msgstr "Sempre Amosar a Cuadrícula"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
@@ -5483,35 +5645,35 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
-msgstr ""
+msgstr "Amosar Regras"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr ""
+msgstr "Amosar Guías"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Origin"
-msgstr ""
+msgstr "Amosar Orixe"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Viewport"
-msgstr ""
+msgstr "Amosar Mini-Ventá (Viewport)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
-msgstr ""
+msgstr "Amosar Grupo e Bloquear Iconas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
-msgstr ""
+msgstr "Centrar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr ""
+msgstr "Encadrar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr ""
+msgstr "Vista Previa da Escala do Lenzo (Canvas)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
@@ -5536,6 +5698,10 @@ msgid ""
"Keys are only added to existing tracks, no new tracks will be created.\n"
"Keys must be inserted manually for the first time."
msgstr ""
+"Inserción automática de claves cando os obxectos son trasladados, rotados, "
+"ou escalados (depenendo da Máscara).\n"
+"As chaves só engádense a pistas xa existentes; nunca se crean novas pistas.\n"
+"As chaves teñen que insertarse manualmente cando se utiliza por primeira vez."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Auto Insert Key"
@@ -5551,19 +5717,19 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Copy Pose"
-msgstr ""
+msgstr "Copiar Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr ""
+msgstr "Restablecer Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr ""
+msgstr "Multiplicar Dimensión da Cuadrícula por 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr ""
+msgstr "Dividir Dimensión da Cuadrícula por 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -5571,35 +5737,37 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
-msgstr ""
+msgstr "Engadir %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Adding %s..."
-msgstr ""
+msgstr "Engadindo %s..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Cannot instantiate multiple nodes without root."
-msgstr ""
+msgstr "Non se pode instanciar varios nodos sen un nodo raíz."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Create Node"
-msgstr ""
+msgstr "Crear Nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Error instancing scene from %s"
-msgstr ""
+msgstr "Erro instanciado escena desde %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Default Type"
-msgstr ""
+msgstr "Cambiar Tipo por Defecto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Drag & drop + Shift : Add node as sibling\n"
"Drag & drop + Alt : Change node type"
msgstr ""
+"Arrastrar e Soltar + Shift : Engade nodo como irmán\n"
+"Arrastrar e Soltar + Alt : Cambiar tipo de nodo"
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Create Polygon3D"
@@ -5607,11 +5775,11 @@ msgstr ""
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Edit Poly"
-msgstr ""
+msgstr "Editar Polígono"
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Edit Poly (Remove Point)"
-msgstr ""
+msgstr "Editar Polígono (Eliminar Punto)"
#: editor/plugins/collision_shape_2d_editor_plugin.cpp
msgid "Set Handle"
@@ -5627,7 +5795,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Restart"
-msgstr ""
+msgstr "Reiniciar"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5638,12 +5806,12 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Particles"
-msgstr ""
+msgstr "Partículas"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generated Point Count:"
-msgstr ""
+msgstr "Número de Puntos Xerados:"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5677,7 +5845,7 @@ msgstr ""
#: editor/plugins/cpu_particles_editor_plugin.cpp
msgid "CPUParticles"
-msgstr ""
+msgstr "CPUParticles"
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -5723,11 +5891,11 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Add Point"
-msgstr ""
+msgstr "Engadir Punto"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Point"
-msgstr ""
+msgstr "Eliminar Punto"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Left Linear"
@@ -5767,11 +5935,11 @@ msgstr ""
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr ""
+msgstr "Elemento %d"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
-msgstr ""
+msgstr "Elementos"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
@@ -5836,6 +6004,10 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "UV Unwrap failed, mesh may not be manifold?"
msgstr ""
+"Fallo no Unwrap de UV. Posiblemente a malla non é unha variedade (é dicir, "
+"que a malla non forma unha superficie conexa, contínua, e con dous caras "
+"diferenciables). En programas de modelaxe 3D pódese eliminar xeometría que "
+"non sexa unha variedade (\"Non Manifold\") fácilmente."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "No mesh to debug."
@@ -5843,7 +6015,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Model has no UV in this layer"
-msgstr ""
+msgstr "O modelo non ten UVs nesta capa"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
@@ -5867,7 +6039,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh"
-msgstr ""
+msgstr "Malla"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Body"
@@ -5879,6 +6051,9 @@ msgid ""
"automatically.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Crear un nodo StaticBody e asígnalle automáticamente unha forma física "
+"baseada en polígonos.\n"
+"Esta é a forma máis precisa (e máis lenta) de detección de colisións."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Collision Sibling"
@@ -5889,6 +6064,8 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Crea unha formá física baseada en polígonos.\n"
+"Esta é a forma máis precisa (pero máis lenta) de detectar colisións."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Collision Sibling"
@@ -5899,6 +6076,8 @@ msgid ""
"Creates a single convex collision shape.\n"
"This is the fastest (but least accurate) option for collision detection."
msgstr ""
+"Crea unha única forma física convexa.\n"
+"Esta é a maneira más eficiente (pero menos precisa) de detectar colisións."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
@@ -5924,15 +6103,15 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "View UV1"
-msgstr ""
+msgstr "Amosar UV1"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "View UV2"
-msgstr ""
+msgstr "Amosar UV2"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Unwrap UV2 for Lightmap/AO"
-msgstr ""
+msgstr "Facer Unwrap do UV2 para Lightmap/AO"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh"
@@ -5944,7 +6123,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "UV Channel Debug"
-msgstr ""
+msgstr "Depuración do Canle UV"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove item %d?"
@@ -5963,7 +6142,7 @@ msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Item"
-msgstr ""
+msgstr "Engadir Elemento"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove Selected Item"
@@ -6039,15 +6218,15 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "X-Axis"
-msgstr ""
+msgstr "Eixe X"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Y-Axis"
-msgstr ""
+msgstr "Eixe Y"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Z-Axis"
-msgstr ""
+msgstr "Eixe Z"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh Up Axis:"
@@ -6067,7 +6246,7 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate"
-msgstr ""
+msgstr "Encher"
#: editor/plugins/navigation_polygon_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
@@ -6077,7 +6256,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Convert to CPUParticles"
-msgstr ""
+msgstr "Converter a CPUParticles"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generating Visibility Rect"
@@ -6093,7 +6272,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Convert to CPUParticles2D"
-msgstr ""
+msgstr "Converter a CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6138,7 +6317,7 @@ msgstr ""
#: editor/plugins/particles_editor_plugin.cpp
msgid "Volume"
-msgstr ""
+msgstr "Volume"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Emission Source: "
@@ -6192,7 +6371,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Select Points"
-msgstr ""
+msgstr "Seleccionar Puntos"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6225,7 +6404,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Delete Point"
-msgstr ""
+msgstr "Eliminar Puntos"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6236,7 +6415,7 @@ msgstr ""
#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
msgid "Options"
-msgstr ""
+msgstr "Opcións"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6302,20 +6481,24 @@ msgid ""
"No texture in this polygon.\n"
"Set a texture to be able to edit UV."
msgstr ""
+"Non hai unha textura neste polígono.\n"
+"Engada unha textura para editar o UV."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create UV Map"
-msgstr ""
+msgstr "Crear Mapa UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
"Polygon 2D has internal vertices, so it can no longer be edited in the "
"viewport."
msgstr ""
+"O polígono 2D ten vértices internos, polo que xa non se pode editar na Mini-"
+"Ventá (Viewport)."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
-msgstr ""
+msgstr "Crear Polígono e UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Internal Vertex"
@@ -6331,15 +6514,15 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Add Custom Polygon"
-msgstr ""
+msgstr "Engadir Polígono Personalizado"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Remove Custom Polygon"
-msgstr ""
+msgstr "Eliminar Polígono Personalizado"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Transform UV Map"
-msgstr ""
+msgstr "Transformar Mapa UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Transform Polygon"
@@ -6351,31 +6534,31 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Open Polygon 2D UV editor."
-msgstr ""
+msgstr "Abrir Editor UV de Polígonos 2D."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Polygon 2D UV Editor"
-msgstr ""
+msgstr "Editor UV de Polígonos 2D"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "UV"
-msgstr ""
+msgstr "UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Points"
-msgstr ""
+msgstr "Puntos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Polygons"
-msgstr ""
+msgstr "Polígonos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Bones"
-msgstr ""
+msgstr "Ósos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Move Points"
-msgstr ""
+msgstr "Mover Puntos"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Command: Rotate"
@@ -6391,23 +6574,23 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
-msgstr ""
+msgstr "Ctrl: Rotar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Ctrl: Scale"
-msgstr ""
+msgstr "Shift+Ctrl: Escalar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Move Polygon"
-msgstr ""
+msgstr "Mover Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Rotate Polygon"
-msgstr ""
+msgstr "Rotar Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Scale Polygon"
-msgstr ""
+msgstr "Escalar Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create a custom polygon. Enables custom polygon rendering."
@@ -6429,19 +6612,19 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Radius:"
-msgstr ""
+msgstr "Radio:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Copy Polygon to UV"
-msgstr ""
+msgstr "Copiar Polígono a UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Copy UV to Polygon"
-msgstr ""
+msgstr "Copiar UV a Polígono"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
-msgstr ""
+msgstr "Limpar UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Settings"
@@ -6449,23 +6632,23 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr ""
+msgstr "Axuste de Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr ""
+msgstr "Activar Axuste"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr ""
+msgstr "Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
-msgstr ""
+msgstr "Amosar Cuadrícula"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Configure Grid:"
-msgstr ""
+msgstr "Configurar Cuadrícula:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
@@ -6493,16 +6676,16 @@ msgstr ""
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Add Resource"
-msgstr ""
+msgstr "Engadir Recurso"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Rename Resource"
-msgstr ""
+msgstr "Renomear Recurso"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Resource"
-msgstr ""
+msgstr "Eliminar Recurso"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Resource clipboard is empty!"
@@ -6510,19 +6693,19 @@ msgstr ""
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Paste Resource"
-msgstr ""
+msgstr "Pegar Recurso"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_editor.cpp
msgid "Instance:"
-msgstr ""
+msgstr "Instancia:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "Tipo:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
@@ -6531,7 +6714,7 @@ msgstr ""
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Load Resource"
-msgstr ""
+msgstr "Cargar Recurso"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ResourcePreloader"
@@ -6571,7 +6754,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Error Saving"
-msgstr ""
+msgstr "Erro ao Gardar"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error importing theme."
@@ -6579,7 +6762,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Error Importing"
-msgstr ""
+msgstr "Erro ao Importar"
#: editor/plugins/script_editor_plugin.cpp
msgid "New Text File..."
@@ -6587,7 +6770,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Open File"
-msgstr ""
+msgstr "Abrir Arquivo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save File As..."
@@ -6612,7 +6795,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme"
-msgstr ""
+msgstr "Importar Tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme"
@@ -6620,7 +6803,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving"
-msgstr ""
+msgstr "Erro ao gardar"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
@@ -6633,16 +6816,16 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Next"
-msgstr ""
+msgstr "Atopar Seguinte"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr ""
+msgstr "Atopar Anterior"
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter scripts"
-msgstr ""
+msgstr "Filtrar scripts"
#: editor/plugins/script_editor_plugin.cpp
msgid "Toggle alphabetical sorting of the method list."
@@ -6650,11 +6833,11 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter methods"
-msgstr ""
+msgstr "Filtrar métodos"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort"
-msgstr ""
+msgstr "Ordenar"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
@@ -6670,19 +6853,19 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Next script"
-msgstr ""
+msgstr "Seguinte script"
#: editor/plugins/script_editor_plugin.cpp
msgid "Previous script"
-msgstr ""
+msgstr "Anterior script"
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
-msgstr ""
+msgstr "Arquivo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open..."
-msgstr ""
+msgstr "Abrir..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reopen Closed Script"
@@ -6690,7 +6873,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr ""
+msgstr "Gardar Todo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -6711,31 +6894,39 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme"
-msgstr ""
+msgstr "Tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme..."
-msgstr ""
+msgstr "Importar Tema..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
-msgstr ""
+msgstr "Volver a Cargar Tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme"
-msgstr ""
+msgstr "Gardar Tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close All"
-msgstr ""
+msgstr "Pechar Todo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close Docs"
-msgstr ""
+msgstr "Pechar Documentación"
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
msgid "Run"
-msgstr ""
+msgstr "Executar"
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Buscar"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
@@ -6752,7 +6943,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
#: editor/script_editor_debugger.cpp
msgid "Continue"
-msgstr ""
+msgstr "Continuar"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
@@ -6768,19 +6959,19 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr ""
+msgstr "Buscar na documentación de referencia."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
-msgstr ""
+msgstr "Ir ao anterior documento editado."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to next edited document."
-msgstr ""
+msgstr "Ir ao seguinte documento editado."
#: editor/plugins/script_editor_plugin.cpp
msgid "Discard"
-msgstr ""
+msgstr "Descartar"
#: editor/plugins/script_editor_plugin.cpp
msgid ""
@@ -6788,23 +6979,13 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
-msgstr ""
+msgstr "Depurador"
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Results"
-msgstr ""
+msgstr "Resultados de Búsqueda"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Scripts"
@@ -6816,11 +6997,11 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
msgid "Source"
-msgstr ""
+msgstr "Fonte"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
-msgstr ""
+msgstr "Obxectivo"
#: editor/plugins/script_text_editor.cpp
msgid ""
@@ -6829,15 +7010,15 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
-msgstr ""
+msgstr "[Ignorar]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
-msgstr ""
+msgstr "Liña"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function"
-msgstr ""
+msgstr "Ir a Función"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -6854,32 +7035,32 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Pick Color"
-msgstr ""
+msgstr "Elexir Cor"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Convert Case"
-msgstr ""
+msgstr "Converter Maiús./Minús."
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr ""
+msgstr "Maiúscula"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr ""
+msgstr "Minúscula"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
-msgstr ""
+msgstr "Capitalizar"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
-msgstr ""
+msgstr "Marcador de Sintaxe"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Bookmarks"
-msgstr ""
+msgstr "Marcadores"
#: editor/plugins/script_text_editor.cpp
msgid "Breakpoints"
@@ -6888,168 +7069,170 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Go To"
-msgstr ""
+msgstr "Ir a"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
-msgstr ""
+msgstr "Cortar"
#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Select All"
-msgstr ""
+msgstr "Seleccionar Todo"
#: editor/plugins/script_text_editor.cpp
msgid "Delete Line"
-msgstr ""
+msgstr "Eliminar Liña"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
-msgstr ""
+msgstr "Sangrado á Esquerda"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Right"
-msgstr ""
+msgstr "Sangrado á Dereita"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr ""
+msgstr "Comentar/Descomentar"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr ""
+msgstr "Expandir/Colapsar Liña"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
-msgstr ""
+msgstr "Colapsar Tódalas Liñas"
#: editor/plugins/script_text_editor.cpp
msgid "Unfold All Lines"
-msgstr ""
+msgstr "Expandir Tódalas Liñas"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
-msgstr ""
+msgstr "Clonar Liña"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr ""
+msgstr "Completar Símbolo"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
-msgstr ""
+msgstr "Evaluar Selección"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr ""
+msgstr "Eliminar Espazos ao Final da Liña"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
-msgstr ""
+msgstr "Convertir Indentación a Espazos"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Tabs"
-msgstr ""
+msgstr "Convertir Identación a Tabulacións"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
-msgstr ""
+msgstr "Auto Indentar"
#: editor/plugins/script_text_editor.cpp
msgid "Find in Files..."
-msgstr ""
+msgstr "Buscar en Arquivos.."
#: editor/plugins/script_text_editor.cpp
msgid "Contextual Help"
-msgstr ""
+msgstr "Axuda Contextual"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Bookmark"
-msgstr ""
+msgstr "Act./Desact. Marcapáxinas"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Next Bookmark"
-msgstr ""
+msgstr "Ir ao Seguinte Marcapáxinas"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Previous Bookmark"
-msgstr ""
+msgstr "Ir ao Anterior Marcapáxinas"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Bookmarks"
-msgstr ""
+msgstr "Eliminar Tódolos Marcapáxinas"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function..."
-msgstr ""
+msgstr "Ir a Función..."
#: editor/plugins/script_text_editor.cpp
msgid "Go to Line..."
-msgstr ""
+msgstr "Ir a Liña..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Toggle Breakpoint"
-msgstr ""
+msgstr "Act./Desact. Punto de Interrupción (Breakpoint)"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
-msgstr ""
+msgstr "Eliminar Tódolos Puntos de Interrupción (Breakpoints)"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Next Breakpoint"
-msgstr ""
+msgstr "Ir ao Seguinte Punto de Interrupción"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Previous Breakpoint"
-msgstr ""
+msgstr "Ir ao Anterior Punto de Interrupción"
#: editor/plugins/shader_editor_plugin.cpp
msgid ""
"This shader has been modified on on disk.\n"
"What action should be taken?"
msgstr ""
+"Este shader foi modificado en disco.\n"
+"Que acción deberían de tomarse?"
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
-msgstr ""
+msgstr "Shader"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "This skeleton has no bones, create some children Bone2D nodes."
-msgstr ""
+msgstr "Este esqueleto non ten ósos; crea uns nodos fillo Bone2D."
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Create Rest Pose from Bones"
-msgstr ""
+msgstr "Crear Pose de Repouso a partir dos Ósos"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Rest Pose to Bones"
-msgstr ""
+msgstr "Asignar Pose de Repouso aos Ósos"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Skeleton2D"
-msgstr ""
+msgstr "Skeleton2D"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Make Rest Pose (From Bones)"
-msgstr ""
+msgstr "Crear Pose de Repouso (a partir dos Ósos)"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Bones to Rest Pose"
-msgstr ""
+msgstr "Asignar Pose de Repouso aos Ósos"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical bones"
-msgstr ""
+msgstr "Crear ósos físicos"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Skeleton"
-msgstr ""
+msgstr "Esqueleto"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical skeleton"
-msgstr ""
+msgstr "Crear esqueleto físico"
#: editor/plugins/skeleton_ik_editor_plugin.cpp
msgid "Play IK"
@@ -7057,11 +7240,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
-msgstr ""
+msgstr "Ortogonal"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective"
-msgstr ""
+msgstr "Perspetiva"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
@@ -7085,15 +7268,15 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scaling: "
-msgstr ""
+msgstr "Escalado: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translating: "
-msgstr ""
+msgstr "Trasladando: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
-msgstr ""
+msgstr "Rotando % graos."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Keying is disabled (no key inserted)."
@@ -7105,19 +7288,19 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pitch"
-msgstr ""
+msgstr "Cabeceo"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Yaw"
-msgstr ""
+msgstr "Guiñada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Size"
-msgstr ""
+msgstr "Tamaño"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
-msgstr ""
+msgstr "Obxectos Debuxados"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Material Changes"
@@ -7137,71 +7320,71 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Vertices"
-msgstr ""
+msgstr "Vértices"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
-msgstr ""
+msgstr "Vista Superior."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View."
-msgstr ""
+msgstr "Vista Inferior."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom"
-msgstr ""
+msgstr "Inferior"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View."
-msgstr ""
+msgstr "Vista Esquerda."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left"
-msgstr ""
+msgstr "Esquerda"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right View."
-msgstr ""
+msgstr "Vista Dereita."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right"
-msgstr ""
+msgstr "Dereita"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View."
-msgstr ""
+msgstr "Vista Frontal."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front"
-msgstr ""
+msgstr "Frontal"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View."
-msgstr ""
+msgstr "Vista Traseria."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear"
-msgstr ""
+msgstr "Traseira"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Align Transform with View"
-msgstr ""
+msgstr "Aliñar Transformación con Perspectiva"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Align Rotation with View"
-msgstr ""
+msgstr "Aliñar Rotación con Perspectiva"
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "No parent to instance a child at."
-msgstr ""
+msgstr "Non hai un pai ao que instanciarlle un fillo."
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "This operation requires a single selected node."
-msgstr ""
+msgstr "Esta operación precisa un único nodo seleccionado."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Auto Orthogonal Enabled"
-msgstr ""
+msgstr "Auto Ortogonal Activado"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock View Rotation"
@@ -7209,55 +7392,55 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Normal"
-msgstr ""
+msgstr "Mostrar de Forma Normal"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Wireframe"
-msgstr ""
+msgstr "Mostrar Malla"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Overdraw"
-msgstr ""
+msgstr "Mostrar Zonas Redebuxadas (Overdraw)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Unshaded"
-msgstr ""
+msgstr "Mostrar Sen Sombreado"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Environment"
-msgstr ""
+msgstr "Amosar Entorno"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Gizmos"
-msgstr ""
+msgstr "Amosar Gizmos"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Information"
-msgstr ""
+msgstr "Amosar Información"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View FPS"
-msgstr ""
+msgstr "Ver FPS"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Half Resolution"
-msgstr ""
+msgstr "Resolución á Metade"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Audio Listener"
-msgstr ""
+msgstr "Oínte de Son"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Enable Doppler"
-msgstr ""
+msgstr "Activar Efecto Doppler"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Cinematic Preview"
-msgstr ""
+msgstr "Vista Previa Cinemática"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Not available when using the GLES2 renderer."
-msgstr ""
+msgstr "Non dispoñible cando se está usando o renderizador GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
@@ -7297,9 +7480,16 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
+"Nota: o valor dos FPS corresponde aos fotogramas por segundo do editor.\n"
+"Non pode usarse como unha forma fiable de medir o rendemento do xogo."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -7313,14 +7503,20 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Faga clic para cambiar entre estados de visibilidade.\n"
+"\n"
+"Ollo aberto: Gizmo visible.\n"
+"Ollo pechado: Gizmo oculto.\n"
+"Ollo medio aberto, medio pechado: Gizmo visible ao través de superficies "
+"opacas (\"raios x\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
-msgstr ""
+msgstr "Axustar Nodos ao Chan"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Couldn't find a solid floor to snap the selection to."
-msgstr ""
+msgstr "Non se puido encontrar chan sólido no que poder axustar a selección."
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7331,39 +7527,39 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr ""
+msgstr "Usar Espazo Local"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr ""
+msgstr "Usar Axuste de Cuadrícula"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
-msgstr ""
+msgstr "Vista Inferior"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View"
-msgstr ""
+msgstr "Vista Superior"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View"
-msgstr ""
+msgstr "Vista Traseira"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View"
-msgstr ""
+msgstr "Vista Frontal"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View"
-msgstr ""
+msgstr "Vista Esquerda"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right View"
-msgstr ""
+msgstr "Vista Dereita"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
-msgstr ""
+msgstr "Vista Perspectiva/Ortogonal"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
@@ -7384,39 +7580,39 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform"
-msgstr ""
+msgstr "Transformación"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr ""
+msgstr "Axustar Obxecto ao Chan"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
-msgstr ""
+msgstr "Aplicar Transformación..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr ""
+msgstr "1 Ventá"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr ""
+msgstr "2 Ventás"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr ""
+msgstr "2 Ventás (Alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr ""
+msgstr "3 Ventás"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr ""
+msgstr "3 Ventás (Alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr ""
+msgstr "4 Ventás"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -7424,96 +7620,96 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Origin"
-msgstr ""
+msgstr "Amosar Orixe"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Grid"
-msgstr ""
+msgstr "Amosar Cuadrícula"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Settings..."
-msgstr ""
+msgstr "Axustes..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
-msgstr ""
+msgstr "Configuración de Axuste"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate Snap:"
-msgstr ""
+msgstr "Axuste de Translación:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Snap (deg.):"
-msgstr ""
+msgstr "Axuste de Rotación (graos):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Snap (%):"
-msgstr ""
+msgstr "Axuste de Escalado (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
-msgstr ""
+msgstr "Axustes de Visión"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective FOV (deg.):"
-msgstr ""
+msgstr "Campo de Visión (graos):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Z-Near:"
-msgstr ""
+msgstr "Plano Próximo:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Z-Far:"
-msgstr ""
+msgstr "Plano Afastado:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Change"
-msgstr ""
+msgstr "Cambio de Transformación"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate:"
-msgstr ""
+msgstr "Trasladar:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate (deg.):"
-msgstr ""
+msgstr "Rotar (graos):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale (ratio):"
-msgstr ""
+msgstr "Escalar (Razón):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Type"
-msgstr ""
+msgstr "Tipo de Transformación"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pre"
-msgstr ""
+msgstr "Anterior (Pre)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Post"
-msgstr ""
+msgstr "Posterior (Post)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Nameless gizmo"
-msgstr ""
+msgstr "Gizmo sen nome"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create Mesh2D"
-msgstr ""
+msgstr "Crear Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Mesh2D Preview"
-msgstr ""
+msgstr "Vista Previa de Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create Polygon2D"
-msgstr ""
+msgstr "Crear Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Polygon2D Preview"
-msgstr ""
+msgstr "Vista Previa Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create CollisionPolygon2D"
@@ -7553,7 +7749,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Polygon2D"
-msgstr ""
+msgstr "Convertir a Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
@@ -7577,7 +7773,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
-msgstr ""
+msgstr "Simplificación: "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Shrink (Pixels): "
@@ -7593,7 +7789,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Settings:"
-msgstr ""
+msgstr "Axustes:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "No Frames Selected"
@@ -7633,7 +7829,7 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "(empty)"
-msgstr ""
+msgstr "(baleiro)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move Frame"
@@ -7641,7 +7837,7 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animations:"
-msgstr ""
+msgstr "Animacións:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "New Animation"
@@ -7649,11 +7845,11 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
-msgstr ""
+msgstr "Velocidade:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
-msgstr ""
+msgstr "Bucle"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animation Frames:"
@@ -7689,11 +7885,11 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
-msgstr ""
+msgstr "Horizontal:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Vertical:"
-msgstr ""
+msgstr "Vertical:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
@@ -7717,20 +7913,20 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr ""
+msgstr "Modo de Axuste:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
msgid "None"
-msgstr ""
+msgstr "Ningún"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr ""
+msgstr "Axustar aos Píxeles"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr ""
+msgstr "Axuste de Cuadrícula"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -7738,7 +7934,7 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr ""
+msgstr "Offset:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
@@ -7834,7 +8030,7 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Submenu"
-msgstr ""
+msgstr "Submenú"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 1"
@@ -7846,11 +8042,11 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has"
-msgstr ""
+msgstr "Ten"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Many"
-msgstr ""
+msgstr "Moitas"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Disabled LineEdit"
@@ -7874,11 +8070,11 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subtree"
-msgstr ""
+msgstr "Subárbore"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has,Many,Options"
-msgstr ""
+msgstr "Ten,Moitas,Opcións"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
@@ -7887,19 +8083,19 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Icon"
-msgstr ""
+msgstr "Icona"
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Style"
-msgstr ""
+msgstr "Estilo"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Font"
-msgstr ""
+msgstr "Fonte"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Color"
-msgstr ""
+msgstr "Cor"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme File"
@@ -7944,7 +8140,7 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr ""
+msgstr "Transpoñer"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
@@ -8048,27 +8244,27 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region"
-msgstr ""
+msgstr "Rexión"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision"
-msgstr ""
+msgstr "Colisión"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Occlusion"
-msgstr ""
+msgstr "Oclusión"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr ""
+msgstr "Navegación"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
-msgstr ""
+msgstr "Máscara de Bits"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
-msgstr ""
+msgstr "Prioridade"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Z Index"
@@ -8145,6 +8341,7 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
msgstr ""
+"Activar axuste de cuadrícula e amosar cuadrícula (configurable no inspector)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
@@ -8324,7 +8521,7 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
-msgstr ""
+msgstr "Erro"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No files added to stage"
@@ -8344,7 +8541,7 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Initialize"
-msgstr ""
+msgstr "Inicializar"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
@@ -8356,19 +8553,19 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Changes"
-msgstr ""
+msgstr "Cambios"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
-msgstr ""
+msgstr "Modificado"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Renamed"
-msgstr ""
+msgstr "Renomeado"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Deleted"
-msgstr ""
+msgstr "Eliminado"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Typechange"
@@ -8389,7 +8586,7 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Status"
-msgstr ""
+msgstr "Estado"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
@@ -8413,15 +8610,15 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar"
-msgstr ""
+msgstr "Escalar"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
-msgstr ""
+msgstr "Vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
-msgstr ""
+msgstr "Booleano"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sampler"
@@ -8481,20 +8678,20 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Node(s) Moved"
-msgstr ""
+msgstr "Nodo(s) Movido(s)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
-msgstr ""
+msgstr "Duplicar Nodos"
#: editor/plugins/visual_shader_editor_plugin.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste Nodes"
-msgstr ""
+msgstr "Pegar Nodos"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Delete Nodes"
-msgstr ""
+msgstr "Eliminar Nodos"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Visual Shader Input Type Changed"
@@ -8506,11 +8703,11 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
-msgstr ""
+msgstr "Vertex"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Fragment"
-msgstr ""
+msgstr "Fragment"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Light"
@@ -8720,19 +8917,19 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/4 constant (0.785398) or 45 degrees."
-msgstr ""
+msgstr "Constante Pi/4 (0.785398), ou 45 graos."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/2 constant (1.570796) or 90 degrees."
-msgstr ""
+msgstr "Constante Pi/2 (1.570796), ou 90 graos."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi constant (3.141593) or 180 degrees."
-msgstr ""
+msgstr "Constante Pi (3.141593), ou 180 graos."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Tau constant (6.283185) or 360 degrees."
-msgstr ""
+msgstr "Constante Tau (6.283185), ou 360 graos."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sqrt2 constant (1.414214). Square root of 2."
@@ -8789,7 +8986,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in radians to degrees."
-msgstr ""
+msgstr "Converte unha cantidade de radiáns a graos."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-e Exponential."
@@ -8846,7 +9043,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in degrees to radians."
-msgstr ""
+msgstr "Converte unha cantidade de graos a radiáns."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / scalar"
@@ -8888,6 +9085,11 @@ msgid ""
"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
"using Hermite polynomials."
msgstr ""
+"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' é menor que 'edge0' e 1.0 se x é maior que 'edge1'. En "
+"caso contrario devólvese un valor interpolado entre 0.0 e 1.0 usando "
+"polinomios de Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -8895,6 +9097,9 @@ msgid ""
"\n"
"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
msgstr ""
+"Step function( scalar(edge), scalar(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' e menor que 'edge'; e 1.0 en caso contrario."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the tangent of the parameter."
@@ -8970,6 +9175,13 @@ msgid ""
"whose number of rows is the number of components in 'c' and whose number of "
"columns is the number of components in 'r'."
msgstr ""
+"Calcula o produto exterior dun par de vectores.\n"
+"\n"
+"OuterProduct trata o primeiro parámetro 'c' coma un vector columna (matriz "
+"con unha soa columna), e o segundo parámetro 'r' coma un vector fila (matriz "
+"con unha soa fila), e fai a multiplicación alxebráica 'c * r'. Esto devolve "
+"unha matriz cun número de filas igual ao número de compoñentes en 'c', e cun "
+"número de columnas igual ao número de compoñentes en 'r'."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
@@ -9042,6 +9254,11 @@ msgid ""
"incident vector, and Nref, the reference vector. If the dot product of I and "
"Nref is smaller than zero the return value is N. Otherwise -N is returned."
msgstr ""
+"Devolve o vector que ten a mesma dirección que o vector de referencia. A "
+"función ten tres vector como parámetros: N, o vector a orientar; I, o vector "
+"incidente; e Nref, o vector de referencia. Se o produto escalar de I e Nref "
+"é menor que cero (forman un ángulo maior que 90 graos) entón devolve N. En "
+"caso contrario devolve -N."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the length of a vector."
@@ -9072,6 +9289,8 @@ msgid ""
"Returns the vector that points in the direction of reflection ( a : incident "
"vector, b : normal vector )."
msgstr ""
+"Devolve o vector que apunta na dirección de reflexo ( a : vector incidente, "
+"b : vector normal)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the vector that points in the direction of refraction."
@@ -9085,6 +9304,11 @@ msgid ""
"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
"using Hermite polynomials."
msgstr ""
+"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' é menor que 'edge0' e 1.0 se x é maior que 'edge1'. En "
+"caso contrario devólvese un valor interpolado entre 0.0 e 1.0 usando "
+"polinomios de Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9094,6 +9318,11 @@ msgid ""
"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
"using Hermite polynomials."
msgstr ""
+"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' é menor que 'edge0' e 1.0 se x é maior que 'edge1'. En "
+"caso contrario devólvese un valor interpolado entre 0.0 e 1.0 usando "
+"polinomios de Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9101,6 +9330,9 @@ msgid ""
"\n"
"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
msgstr ""
+"Step function( vector(edge), vector(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' e menor que 'edge'; e 1.0 en caso contrario."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9108,6 +9340,9 @@ msgid ""
"\n"
"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
msgstr ""
+"Step function( scalar(edge), vector(x) ).\n"
+"\n"
+"Devolve 0.0 se 'x' e menor que 'edge'; e 1.0 en caso contrario."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds vector to vector."
@@ -9220,11 +9455,11 @@ msgstr ""
#: editor/project_export.cpp
msgid "Runnable"
-msgstr ""
+msgstr "Executable"
#: editor/project_export.cpp
msgid "Delete preset '%s'?"
-msgstr ""
+msgstr "Eliminar axustes de exportación '%s'?"
#: editor/project_export.cpp
msgid ""
@@ -9238,6 +9473,8 @@ msgid ""
"This might be due to a configuration issue in the export preset or your "
"export settings."
msgstr ""
+"Fallou a exportación do proxecto á plataforma '%s'.\n"
+"Esto pode deberse a un problema cos axustes de exportación."
#: editor/project_export.cpp
msgid "Release"
@@ -9257,17 +9494,20 @@ msgstr ""
#: editor/project_export.cpp
msgid "Presets"
-msgstr ""
+msgstr "Axustes de Exportación"
#: editor/project_export.cpp editor/project_settings_editor.cpp
msgid "Add..."
-msgstr ""
+msgstr "Engadir..."
#: editor/project_export.cpp
msgid ""
"If checked, the preset will be available for use in one-click deploy.\n"
"Only one preset per platform may be marked as runnable."
msgstr ""
+"Ao estar activado, estes axustes de exportación estarán dispoñibles para o "
+"usar co despregue dun só clic.\n"
+"Só uns axustes de exportación por plataforma poden marcarse como executables."
#: editor/project_export.cpp
msgid "Export Path"
@@ -9275,11 +9515,11 @@ msgstr ""
#: editor/project_export.cpp
msgid "Resources"
-msgstr ""
+msgstr "Recursos"
#: editor/project_export.cpp
msgid "Export all resources in the project"
-msgstr ""
+msgstr "Exportar tódolos recursos no proxecto"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
@@ -9308,10 +9548,12 @@ msgid ""
"Filters to exclude files/folders from project\n"
"(comma-separated, e.g: *.json, *.txt, docs/*)"
msgstr ""
+"Filtros para excluír arquivos/cartafois de proxectos\n"
+"(separados por coma; exemplo: *json, *.txt, docs*)"
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Características"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -9323,7 +9565,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Script"
-msgstr ""
+msgstr "Script"
#: editor/project_export.cpp
msgid "Script Export Mode:"
@@ -9331,11 +9573,11 @@ msgstr ""
#: editor/project_export.cpp
msgid "Text"
-msgstr ""
+msgstr "Texto"
#: editor/project_export.cpp
msgid "Compiled"
-msgstr ""
+msgstr "Compilado"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
@@ -9355,7 +9597,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Export Project"
-msgstr ""
+msgstr "Exportar Proxecto"
#: editor/project_export.cpp
msgid "Export mode?"
@@ -9397,6 +9639,8 @@ msgstr ""
msgid ""
"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
msgstr ""
+"O arquivo de proxecto '.zip' non é válido; non conteñe ningún arquivo de "
+"configuración 'project.godot'."
#: editor/project_manager.cpp
msgid "Please choose an empty folder."
@@ -9404,23 +9648,23 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Please choose a \"project.godot\" or \".zip\" file."
-msgstr ""
+msgstr "Por favor, elixa un arquivo de tipo 'project.godot' ou '.zip'."
#: editor/project_manager.cpp
msgid "This directory already contains a Godot project."
-msgstr ""
+msgstr "O directorio xa contén un proxecto Godot."
#: editor/project_manager.cpp
msgid "New Game Project"
-msgstr ""
+msgstr "Novo Proxecto de Xogo"
#: editor/project_manager.cpp
msgid "Imported Project"
-msgstr ""
+msgstr "Proxecto Importado"
#: editor/project_manager.cpp
msgid "Invalid Project Name."
-msgstr ""
+msgstr "Nome de Proxecto Inválido."
#: editor/project_manager.cpp
msgid "Couldn't create folder."
@@ -9432,73 +9676,76 @@ msgstr ""
#: editor/project_manager.cpp
msgid "It would be a good idea to name your project."
-msgstr ""
+msgstr "Sería unha boa idea nomear o teu proxecto."
#: editor/project_manager.cpp
msgid "Invalid project path (changed anything?)."
-msgstr ""
+msgstr "A ruta ao proxecto non é valida. Cambiaches algo?"
#: editor/project_manager.cpp
msgid ""
"Couldn't load project.godot in project path (error %d). It may be missing or "
"corrupted."
msgstr ""
+"Non se pudo cargar o arquivo de configuración 'project.godot' na ruta do "
+"proxecto (erro %d). Pode ser que o arquivo non exista; ou que esté "
+"corrompido."
#: editor/project_manager.cpp
msgid "Couldn't edit project.godot in project path."
-msgstr ""
+msgstr "Non se pudo editar o arquivo 'project.godot' na ruta do proxecto."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
-msgstr ""
+msgstr "Non se pudo crear o arquivo 'project.godot' na ruta do proxecto."
#: editor/project_manager.cpp
msgid "Rename Project"
-msgstr ""
+msgstr "Renomear Proxecto"
#: editor/project_manager.cpp
msgid "Import Existing Project"
-msgstr ""
+msgstr "Importar Proxecto Existente"
#: editor/project_manager.cpp
msgid "Import & Edit"
-msgstr ""
+msgstr "Importar e Editar"
#: editor/project_manager.cpp
msgid "Create New Project"
-msgstr ""
+msgstr "Crear Novo Proxecto"
#: editor/project_manager.cpp
msgid "Create & Edit"
-msgstr ""
+msgstr "Crear e Editar"
#: editor/project_manager.cpp
msgid "Install Project:"
-msgstr ""
+msgstr "Instalar Proxecto:"
#: editor/project_manager.cpp
msgid "Install & Edit"
-msgstr ""
+msgstr "Instalar e Editar"
#: editor/project_manager.cpp
msgid "Project Name:"
-msgstr ""
+msgstr "Nome do Proxecto:"
#: editor/project_manager.cpp
msgid "Project Path:"
-msgstr ""
+msgstr "Ruta do Proxecto:"
#: editor/project_manager.cpp
msgid "Project Installation Path:"
-msgstr ""
+msgstr "Ruta de Instalación do Proxecto:"
#: editor/project_manager.cpp
msgid "Renderer:"
-msgstr ""
+msgstr "Renderizador:"
#: editor/project_manager.cpp
msgid "OpenGL ES 3.0"
-msgstr ""
+msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
@@ -9514,7 +9761,7 @@ msgstr ""
#: editor/project_manager.cpp
msgid "OpenGL ES 2.0"
-msgstr ""
+msgstr "OpenGL ES 2.0"
#: editor/project_manager.cpp
msgid ""
@@ -9530,23 +9777,23 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Unnamed Project"
-msgstr ""
+msgstr "Proxecto Sen Nome"
#: editor/project_manager.cpp
msgid "Missing Project"
-msgstr ""
+msgstr "Proxecto Faltante"
#: editor/project_manager.cpp
msgid "Error: Project is missing on the filesystem."
-msgstr ""
+msgstr "Erro: O proxecto non se pode encontrar no sistema de arquivos."
#: editor/project_manager.cpp
msgid "Can't open project at '%s'."
-msgstr ""
+msgstr "Non se pode abrir proxecto en '%s'."
#: editor/project_manager.cpp
msgid "Are you sure to open more than one project?"
-msgstr ""
+msgstr "Está seguro de que quere abrir máis dun proxecto?"
#: editor/project_manager.cpp
msgid ""
@@ -9560,6 +9807,15 @@ msgid ""
"Warning: You won't be able to open the project with previous versions of the "
"engine anymore."
msgstr ""
+"O arquivo de configuración do seguinte proxecto non especifica a versión de "
+"Godot ca cal foi creado.\n"
+"\n"
+"%s\n"
+"\n"
+"Se o abres o arquivo de configuración será convertido ao formato utilizado "
+"na versión actual de Godot.\n"
+"Aviso: Xa non poderás volver a abrir este proxecto con versións anteriores "
+"de Godot."
#: editor/project_manager.cpp
msgid ""
@@ -9572,12 +9828,21 @@ msgid ""
"Warning: You won't be able to open the project with previous versions of the "
"engine anymore."
msgstr ""
+"O arquivo de configuración do seguinte proxecto foi xerado por unha versión "
+"antiga de Godot, e é necesario convertelo á versión actual:\n"
+"\n"
+"%s\n"
+"\n"
+"Queres convertelo?\n"
+"Aviso: Xa non poderás abrir o proxecto con versións anteriores de Godot."
#: editor/project_manager.cpp
msgid ""
"The project settings were created by a newer engine version, whose settings "
"are not compatible with this version."
msgstr ""
+"A configuración do proxecto foi creada por versións máis novas de Godot; "
+"facéndoa incompatible con esta versión."
#: editor/project_manager.cpp
msgid ""
@@ -9585,6 +9850,9 @@ msgid ""
"Please edit the project and set the main scene in the Project Settings under "
"the \"Application\" category."
msgstr ""
+"Non se pode executar o proxecto: non hai unha escena principal definida.\n"
+"Por favor, selecciona unha escena principal en \"Configuración do Proxecto"
+"\", na categoría \"Aplicación\"."
#: editor/project_manager.cpp
msgid ""
@@ -9594,84 +9862,104 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Are you sure to run %d projects at once?"
-msgstr ""
+msgstr "Seguro que queres executar %d proxectos ao mesmo tempo?"
#: editor/project_manager.cpp
msgid ""
"Remove %d projects from the list?\n"
"The project folders' contents won't be modified."
msgstr ""
+"Eliminar %d proxectos da lista?\n"
+"Os contidos da carpeta de proxectos non serán modificados."
#: editor/project_manager.cpp
msgid ""
"Remove this project from the list?\n"
"The project folder's contents won't be modified."
msgstr ""
+"Eliminar este proxecto da lista?\n"
+"Os contidos da carpeta de proxectos non serán modificados."
#: editor/project_manager.cpp
msgid ""
"Remove all missing projects from the list?\n"
"The project folders' contents won't be modified."
msgstr ""
+"Eliminar todos os proxectos faltantes da lista?\n"
+"Os contidos da carpeta de proxectos non serán modificados."
#: editor/project_manager.cpp
msgid ""
"Language changed.\n"
"The interface will update after restarting the editor or project manager."
msgstr ""
+"Linguaxe cambiada.\n"
+"A interface actualizarase despois de reiniciar o editor ou administrador de "
+"proxectos."
#: editor/project_manager.cpp
msgid ""
"Are you sure to scan %s folders for existing Godot projects?\n"
"This could take a while."
msgstr ""
+"Seguro que quere escanear proxectos de Godot en %s cartafois?\n"
+"Esto podería demorarse un tempo."
#. TRANSLATORS: This refers to the application where users manage their Godot projects.
#: editor/project_manager.cpp
msgid "Project Manager"
-msgstr ""
+msgstr "Administrador de Proxectos"
#: editor/project_manager.cpp
msgid "Projects"
+msgstr "Proxectos"
+
+#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
msgstr ""
+"Examinando arquivos,\n"
+"Por favor, espere..."
#: editor/project_manager.cpp
msgid "Last Modified"
-msgstr ""
+msgstr "Derradeira Modificación"
#: editor/project_manager.cpp
msgid "Scan"
-msgstr ""
+msgstr "Escanear"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
-msgstr ""
+msgstr "Seleccionar un Cartafol para Escanear"
#: editor/project_manager.cpp
msgid "New Project"
-msgstr ""
+msgstr "Novo Proxecto"
#: editor/project_manager.cpp
msgid "Remove Missing"
-msgstr ""
+msgstr "Eliminar Faltantes"
#: editor/project_manager.cpp
msgid "Templates"
-msgstr ""
+msgstr "Proxectos Modelo"
#: editor/project_manager.cpp
msgid "Restart Now"
-msgstr ""
+msgstr "Reiniciar Agora"
#: editor/project_manager.cpp
msgid "Can't run project"
-msgstr ""
+msgstr "Non se pode executar proxecto"
#: editor/project_manager.cpp
msgid ""
"You currently don't have any projects.\n"
"Would you like to explore official example projects in the Asset Library?"
msgstr ""
+"Actualmente non tes ningún proxecto.\n"
+"Gustaríalle buscar proxectos de exemplo oficiais na biblioteca de Assets?"
#: editor/project_manager.cpp
msgid ""
@@ -9679,36 +9967,42 @@ msgid ""
"To filter projects by name and full path, the query must contain at least "
"one `/` character."
msgstr ""
+"A barra de búsqueda filtra os proxectos por nome e último compoñente da súa "
+"ruta.\n"
+"Se quere filtrar proxectos por nome e ruta completa, a consulta debe conter "
+"polo menos un carácter '/'."
#: editor/project_settings_editor.cpp
msgid "Key "
-msgstr ""
+msgstr "Botón: "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
-msgstr ""
+msgstr "Botón Joystick"
#: editor/project_settings_editor.cpp
msgid "Joy Axis"
-msgstr ""
+msgstr "Eixe Joystick"
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
-msgstr ""
+msgstr "Botón do Rato"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
+"Nome de acción inválido. O nome non pode estar baleiro, nin conter '/', ':', "
+"'=', '\\' ou '\"'"
#: editor/project_settings_editor.cpp
msgid "An action with the name '%s' already exists."
-msgstr ""
+msgstr "Xa existe unha acción co nome '%s'."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
-msgstr ""
+msgstr "Renomear Evento de Entrada"
#: editor/project_settings_editor.cpp
msgid "Change Action deadzone"
@@ -9716,149 +10010,151 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Input Action Event"
-msgstr ""
+msgstr "Engadir Evento de Entrada"
#: editor/project_settings_editor.cpp
msgid "All Devices"
-msgstr ""
+msgstr "Tódolos Dispositivos"
#: editor/project_settings_editor.cpp
msgid "Device"
-msgstr ""
+msgstr "Dispositivo"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr ""
+msgstr "Pulse algún botón..."
#: editor/project_settings_editor.cpp
msgid "Mouse Button Index:"
-msgstr ""
+msgstr "Índice do Botón do Rato:"
#: editor/project_settings_editor.cpp
msgid "Left Button"
-msgstr ""
+msgstr "Botón Esquerdo"
#: editor/project_settings_editor.cpp
msgid "Right Button"
-msgstr ""
+msgstr "Botón Dereito"
#: editor/project_settings_editor.cpp
msgid "Middle Button"
-msgstr ""
+msgstr "Botón Central"
#: editor/project_settings_editor.cpp
msgid "Wheel Up Button"
-msgstr ""
+msgstr "Mover Roda cara Arriba"
#: editor/project_settings_editor.cpp
msgid "Wheel Down Button"
-msgstr ""
+msgstr "Mover Roda cara Abaixo"
#: editor/project_settings_editor.cpp
msgid "Wheel Left Button"
-msgstr ""
+msgstr "Mover Roda cara a Esquerda"
#: editor/project_settings_editor.cpp
msgid "Wheel Right Button"
-msgstr ""
+msgstr "Mover Roda cara a Dereita"
#: editor/project_settings_editor.cpp
msgid "X Button 1"
-msgstr ""
+msgstr "Botón X 1"
#: editor/project_settings_editor.cpp
msgid "X Button 2"
-msgstr ""
+msgstr "Botón X 2"
#: editor/project_settings_editor.cpp
msgid "Joypad Axis Index:"
-msgstr ""
+msgstr "Índice do Eixe do Joystick:"
#: editor/project_settings_editor.cpp
msgid "Axis"
-msgstr ""
+msgstr "Eixe"
#: editor/project_settings_editor.cpp
msgid "Joypad Button Index:"
-msgstr ""
+msgstr "Índice do Botón do Joystick:"
#: editor/project_settings_editor.cpp
msgid "Erase Input Action"
-msgstr ""
+msgstr "Eliminar Acción de Entrada"
#: editor/project_settings_editor.cpp
msgid "Erase Input Action Event"
-msgstr ""
+msgstr "Eliminar Evento de Entrada"
#: editor/project_settings_editor.cpp
msgid "Add Event"
-msgstr ""
+msgstr "Engadir Evento"
#: editor/project_settings_editor.cpp
msgid "Button"
-msgstr ""
+msgstr "Botón"
#: editor/project_settings_editor.cpp
msgid "Left Button."
-msgstr ""
+msgstr "Botón Esquerdo."
#: editor/project_settings_editor.cpp
msgid "Right Button."
-msgstr ""
+msgstr "Botón Dereito."
#: editor/project_settings_editor.cpp
msgid "Middle Button."
-msgstr ""
+msgstr "Botón Central."
#: editor/project_settings_editor.cpp
msgid "Wheel Up."
-msgstr ""
+msgstr "Roda cara Arriba."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
-msgstr ""
+msgstr "Roda cara Abaixo."
#: editor/project_settings_editor.cpp
msgid "Add Global Property"
-msgstr ""
+msgstr "Engadir Propiedade Global"
#: editor/project_settings_editor.cpp
msgid "Select a setting item first!"
-msgstr ""
+msgstr "Primeiro seleccione un elemento!"
#: editor/project_settings_editor.cpp
msgid "No property '%s' exists."
-msgstr ""
+msgstr "Non existe a propiedade '%s'."
#: editor/project_settings_editor.cpp
msgid "Setting '%s' is internal, and it can't be deleted."
-msgstr ""
+msgstr "A propiedade '%s' é interna, e non pode ser eliminada."
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr ""
+msgstr "Eliminar Elemento"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'."
msgstr ""
+"Nome de acción inválido. Non pode estar baleiro, nin pode conter '/', ':', "
+"'=', '\\' ou '\"'."
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
-msgstr ""
+msgstr "Engadir Acción de Entrada"
#: editor/project_settings_editor.cpp
msgid "Error saving settings."
-msgstr ""
+msgstr "Erro gardando os axustes."
#: editor/project_settings_editor.cpp
msgid "Settings saved OK."
-msgstr ""
+msgstr "Axustes gardados correctamente."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
-msgstr ""
+msgstr "Evento de Entrada Movido"
#: editor/project_settings_editor.cpp
msgid "Override for Feature"
@@ -9866,11 +10162,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Translation"
-msgstr ""
+msgstr "Engadir Tradución"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
-msgstr ""
+msgstr "Eliminar Tradución"
#: editor/project_settings_editor.cpp
msgid "Add Remapped Path"
@@ -9902,11 +10198,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Project Settings (project.godot)"
-msgstr ""
+msgstr "Configuración do Proxecto (project.godot)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "General"
-msgstr ""
+msgstr "Xeral"
#: editor/project_settings_editor.cpp
msgid "Override For..."
@@ -9914,19 +10210,19 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
-msgstr ""
+msgstr "O editor ten que reiniciarse para que os cambios teñan efecto."
#: editor/project_settings_editor.cpp
msgid "Input Map"
-msgstr ""
+msgstr "Mapeado de Entradas"
#: editor/project_settings_editor.cpp
msgid "Action:"
-msgstr ""
+msgstr "Acción:"
#: editor/project_settings_editor.cpp
msgid "Action"
-msgstr ""
+msgstr "Acción"
#: editor/project_settings_editor.cpp
msgid "Deadzone"
@@ -9934,23 +10230,23 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Device:"
-msgstr ""
+msgstr "Dispositivo:"
#: editor/project_settings_editor.cpp
msgid "Index:"
-msgstr ""
+msgstr "Índice:"
#: editor/project_settings_editor.cpp
msgid "Localization"
-msgstr ""
+msgstr "Linguaxe"
#: editor/project_settings_editor.cpp
msgid "Translations"
-msgstr ""
+msgstr "Traducións"
#: editor/project_settings_editor.cpp
msgid "Translations:"
-msgstr ""
+msgstr "Traducións:"
#: editor/project_settings_editor.cpp
msgid "Remaps"
@@ -9958,7 +10254,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Resources:"
-msgstr ""
+msgstr "Recursos:"
#: editor/project_settings_editor.cpp
msgid "Remaps by Locale:"
@@ -9966,35 +10262,40 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr ""
+msgstr "Linguaxe"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
-msgstr ""
+msgstr "Filtrar Linguaxes"
#: editor/project_settings_editor.cpp
msgid "Show All Locales"
-msgstr ""
+msgstr "Amosar Tódolos Linguaxes"
#: editor/project_settings_editor.cpp
msgid "Show Selected Locales Only"
-msgstr ""
+msgstr "Amosar só os Linguaxes Seleccionados"
#: editor/project_settings_editor.cpp
msgid "Filter mode:"
-msgstr ""
+msgstr "Modo de Filtrado:"
#: editor/project_settings_editor.cpp
msgid "Locales:"
-msgstr ""
+msgstr "Linguaxes:"
#: editor/project_settings_editor.cpp
msgid "AutoLoad"
-msgstr ""
+msgstr "AutoCargador"
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr ""
+msgstr "Características Adicionais (Plugins)"
+
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Cargar Valores por Defecto"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10002,7 +10303,7 @@ msgstr ""
#: editor/property_editor.cpp
msgid "Zero"
-msgstr ""
+msgstr "Cero"
#: editor/property_editor.cpp
msgid "Easing In-Out"
@@ -10014,27 +10315,27 @@ msgstr ""
#: editor/property_editor.cpp
msgid "File..."
-msgstr ""
+msgstr "Arquivo..."
#: editor/property_editor.cpp
msgid "Dir..."
-msgstr ""
+msgstr "Directorio..."
#: editor/property_editor.cpp
msgid "Assign"
-msgstr ""
+msgstr "Asignar"
#: editor/property_editor.cpp
msgid "Select Node"
-msgstr ""
+msgstr "Seleccionar Nodos"
#: editor/property_editor.cpp
msgid "Error loading file: Not a resource!"
-msgstr ""
+msgstr "Erro cargando arquivo: Non é un recurso!"
#: editor/property_editor.cpp
msgid "Pick a Node"
-msgstr ""
+msgstr "Elixe un Nodo"
#: editor/property_editor.cpp
msgid "Bit %d, val %d."
@@ -10058,15 +10359,15 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Replace:"
-msgstr ""
+msgstr "Substituír:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
-msgstr ""
+msgstr "Prefixo:"
#: editor/rename_dialog.cpp
msgid "Suffix:"
-msgstr ""
+msgstr "Sufixo:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10078,11 +10379,11 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Substitute"
-msgstr ""
+msgstr "Substituír"
#: editor/rename_dialog.cpp
msgid "Node name"
-msgstr ""
+msgstr "Nome do nodo"
#: editor/rename_dialog.cpp
msgid "Node's parent name, if available"
@@ -10090,7 +10391,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Node type"
-msgstr ""
+msgstr "Tipo de nodo"
#: editor/rename_dialog.cpp
msgid "Current scene name"
@@ -10098,7 +10399,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Root node name"
-msgstr ""
+msgstr "Nome do nodo raíz"
#: editor/rename_dialog.cpp
msgid ""
@@ -10120,7 +10421,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Step"
-msgstr ""
+msgstr "Paso"
#: editor/rename_dialog.cpp
msgid "Amount by which counter is incremented for each node"
@@ -10142,7 +10443,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Keep"
-msgstr ""
+msgstr "Manter"
#: editor/rename_dialog.cpp
msgid "PascalCase to snake_case"
@@ -10154,7 +10455,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Case"
-msgstr ""
+msgstr "Maiús./Minús."
#: editor/rename_dialog.cpp
msgid "To Lowercase"
@@ -10166,7 +10467,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Reset"
-msgstr ""
+msgstr "Restablecer"
#: editor/rename_dialog.cpp
msgid "Regular Expression Error:"
@@ -10178,7 +10479,7 @@ msgstr ""
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
-msgstr ""
+msgstr "Remparentar Nodo"
#: editor/reparent_dialog.cpp
msgid "Reparent Location (Select new Parent):"
@@ -10190,7 +10491,7 @@ msgstr ""
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent"
-msgstr ""
+msgstr "Remparentar"
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
@@ -10239,6 +10540,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Pegar Nodos"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10256,7 +10566,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Duplicate Node(s)"
-msgstr ""
+msgstr "Duplicar Nodo(s)"
#: editor/scene_tree_dock.cpp
msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
@@ -10280,7 +10590,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
-msgstr ""
+msgstr "Eliminar %d nodos?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10292,7 +10602,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\"?"
-msgstr ""
+msgstr "Eliminar nodo \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -10328,7 +10638,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Create Root Node:"
-msgstr ""
+msgstr "Crear nodo raíz:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
@@ -10344,7 +10654,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr ""
+msgstr "Outro Nodo"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -10359,8 +10669,13 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Cortar Nodos"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
-msgstr ""
+msgstr "Eliminar Nodo(s)"
#: editor/scene_tree_dock.cpp
msgid "Change type of node(s)"
@@ -10382,7 +10697,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Sub-Recursos"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
@@ -10409,7 +10724,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
-msgstr ""
+msgstr "Engadir Nodo Fillo"
#: editor/scene_tree_dock.cpp
msgid "Expand/Collapse All"
@@ -10437,7 +10752,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
-msgstr ""
+msgstr "Copiar Ruta do Nodo"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
@@ -10463,11 +10778,18 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Remote"
+msgstr "Remoto"
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Local"
-msgstr ""
+msgstr "Local"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
@@ -10479,7 +10801,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Unlock Node"
-msgstr ""
+msgstr "Desbloquear Nodo"
#: editor/scene_tree_editor.cpp
msgid "Button Group"
@@ -10491,7 +10813,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
-msgstr ""
+msgstr "Aviso sobre a configuración do nodo:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -10543,7 +10865,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Rename Node"
-msgstr ""
+msgstr "Renomear Nodo"
#: editor/scene_tree_editor.cpp
msgid "Scene Tree (Nodes):"
@@ -10555,51 +10877,51 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Select a Node"
-msgstr ""
+msgstr "Seleccione un Nodo"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr ""
+msgstr "A ruta está baleira."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
-msgstr ""
+msgstr "O nome de arquivo está baleiro."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
-msgstr ""
+msgstr "A ruta non é local."
#: editor/script_create_dialog.cpp
msgid "Invalid base path."
-msgstr ""
+msgstr "Ruta base inválida."
#: editor/script_create_dialog.cpp
msgid "A directory with the same name exists."
-msgstr ""
+msgstr "Xa existe un directorio co mesmo nome."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
-msgstr ""
+msgstr "O arquivo non existe."
#: editor/script_create_dialog.cpp
msgid "Invalid extension."
-msgstr ""
+msgstr "Extensión inválida."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
-msgstr ""
+msgstr "Extensión incorrecta elixida."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr ""
+msgstr "Erro cargando o modelo '%s'"
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
-msgstr ""
+msgstr "Erro - Non se puido gardar o Script no sistema de arquivos."
#: editor/script_create_dialog.cpp
msgid "Error loading script from %s"
-msgstr ""
+msgstr "Erro cargando script desde %s"
#: editor/script_create_dialog.cpp
msgid "Overrides"
@@ -10607,113 +10929,115 @@ msgstr ""
#: editor/script_create_dialog.cpp
msgid "N/A"
-msgstr ""
+msgstr "N/A"
#: editor/script_create_dialog.cpp
msgid "Open Script / Choose Location"
-msgstr ""
+msgstr "Abrir Script / Elixir Ubicación"
#: editor/script_create_dialog.cpp
msgid "Open Script"
-msgstr ""
+msgstr "Abrir Script"
#: editor/script_create_dialog.cpp
msgid "File exists, it will be reused."
-msgstr ""
+msgstr "O arquivo xa existe; será reutilizado."
#: editor/script_create_dialog.cpp
msgid "Invalid path."
-msgstr ""
+msgstr "Ruta inválida."
#: editor/script_create_dialog.cpp
msgid "Invalid class name."
-msgstr ""
+msgstr "Nome de clase inválido."
#: editor/script_create_dialog.cpp
msgid "Invalid inherited parent name or path."
-msgstr ""
+msgstr "A ruta ou o nome do pai herdado é inválido."
#: editor/script_create_dialog.cpp
msgid "Script path/name is valid."
-msgstr ""
+msgstr "A ruta e nome do script son válidos."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "Permitido: a-z, A-Z, 0-9,_ e ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
-msgstr ""
+msgstr "Script integrada na escena."
#: editor/script_create_dialog.cpp
msgid "Will create a new script file."
-msgstr ""
+msgstr "Crearase un novo arquivo de script."
#: editor/script_create_dialog.cpp
msgid "Will load an existing script file."
-msgstr ""
+msgstr "Cargarase un arquivo de script xa existente."
#: editor/script_create_dialog.cpp
msgid "Script file already exists."
-msgstr ""
+msgstr "Xa existe un arquivo script na mesma ruta."
#: editor/script_create_dialog.cpp
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
msgstr ""
+"Nota: Os scripts integrados teñen algunhas limitacións, e non poden editarse "
+"usando editores externos."
#: editor/script_create_dialog.cpp
msgid "Class Name:"
-msgstr ""
+msgstr "Nome da Clase:"
#: editor/script_create_dialog.cpp
msgid "Template:"
-msgstr ""
+msgstr "Modelo:"
#: editor/script_create_dialog.cpp
msgid "Built-in Script:"
-msgstr ""
+msgstr "Script Integrado:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
-msgstr ""
+msgstr "Adxuntar Script de Nodo"
#: editor/script_editor_debugger.cpp
msgid "Remote "
-msgstr ""
+msgstr "Remoto "
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
-msgstr ""
+msgstr "Bytes:"
#: editor/script_editor_debugger.cpp
msgid "Warning:"
-msgstr ""
+msgstr "Aviso:"
#: editor/script_editor_debugger.cpp
msgid "Error:"
-msgstr ""
+msgstr "Erro:"
#: editor/script_editor_debugger.cpp
msgid "C++ Error"
-msgstr ""
+msgstr "Erro de C++"
#: editor/script_editor_debugger.cpp
msgid "C++ Error:"
-msgstr ""
+msgstr "Erro de C++:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source"
-msgstr ""
+msgstr "Fonte C++"
#: editor/script_editor_debugger.cpp
msgid "Source:"
-msgstr ""
+msgstr "Fonte:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source:"
-msgstr ""
+msgstr "Fonte C++:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
@@ -10721,7 +11045,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Erros"
#: editor/script_editor_debugger.cpp
msgid "Child process connected."
@@ -10753,23 +11077,23 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Profiler"
-msgstr ""
+msgstr "Analítica de Rendemento"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
-msgstr ""
+msgstr "Analítica de Rendemento de Rede"
#: editor/script_editor_debugger.cpp
msgid "Monitor"
-msgstr ""
+msgstr "Monitor"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Valor"
#: editor/script_editor_debugger.cpp
msgid "Monitors"
-msgstr ""
+msgstr "Monitores"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
@@ -10781,7 +11105,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Total:"
-msgstr ""
+msgstr "Total:"
#: editor/script_editor_debugger.cpp
msgid "Export list to a CSV file"
@@ -10793,19 +11117,19 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Type"
-msgstr ""
+msgstr "Tipo"
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Formato"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Uso"
#: editor/script_editor_debugger.cpp
msgid "Misc"
-msgstr ""
+msgstr "Outros"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
@@ -10845,7 +11169,7 @@ msgstr ""
#: editor/settings_config_dialog.cpp
msgid "Shortcuts"
-msgstr ""
+msgstr "Atallos"
#: editor/settings_config_dialog.cpp
msgid "Binding"
@@ -10941,11 +11265,11 @@ msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform:"
-msgstr ""
+msgstr "Plataforma:"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform"
-msgstr ""
+msgstr "Plataforma"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Dynamic Library"
@@ -10969,15 +11293,15 @@ msgstr ""
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
-msgstr ""
+msgstr "Biblioteca"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Libraries: "
-msgstr ""
+msgstr "Bibliotecas: "
#: modules/gdnative/register_types.cpp
msgid "GDNative"
-msgstr ""
+msgstr "GDNative"
#: modules/gdscript/gdscript_functions.cpp
msgid "Step argument is zero!"
@@ -11025,7 +11349,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Plane:"
-msgstr ""
+msgstr "Plano:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Floor"
@@ -11037,7 +11361,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Floor:"
-msgstr ""
+msgstr "Chan:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Delete Selection"
@@ -11061,7 +11385,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
-msgstr ""
+msgstr "Axustar Vista"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Disabled"
@@ -11213,7 +11537,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Partitioning..."
-msgstr ""
+msgstr "Particionando..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating contours..."
@@ -11237,7 +11561,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Done!"
-msgstr ""
+msgstr "Feito!"
#: modules/visual_script/visual_script.cpp
msgid ""
@@ -11307,7 +11631,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
-msgstr ""
+msgstr "Variables:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new variable."
@@ -11315,7 +11639,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
-msgstr ""
+msgstr "Sinais:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new signal."
@@ -11429,7 +11753,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Move Node(s)"
-msgstr ""
+msgstr "Mover Nodo(s)"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Node"
@@ -11437,11 +11761,11 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Connect Nodes"
-msgstr ""
+msgstr "Conectar Nodos"
#: modules/visual_script/visual_script_editor.cpp
msgid "Disconnect Nodes"
-msgstr ""
+msgstr "Desconectar Nodos"
#: modules/visual_script/visual_script_editor.cpp
msgid "Connect Node Data"
@@ -11453,31 +11777,31 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
-msgstr ""
+msgstr "O script xa ten unha función chamada '%s'"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Input Value"
-msgstr ""
+msgstr "Cambiar Valor de Entrada"
#: modules/visual_script/visual_script_editor.cpp
msgid "Resize Comment"
-msgstr ""
+msgstr "Cambiar Tamaño do Comentario"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't copy the function node."
-msgstr ""
+msgstr "Non se pode copiar o nodo función."
#: modules/visual_script/visual_script_editor.cpp
msgid "Clipboard is empty!"
-msgstr ""
+msgstr "O portapapeis está baleiro!"
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste VisualScript Nodes"
-msgstr ""
+msgstr "Pegar Nodos VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't create function with a function node."
-msgstr ""
+msgstr "Non se pode crear unha función cun nodo función."
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't create function of nodes from nodes of multiple functions."
@@ -11493,71 +11817,71 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Create Function"
-msgstr ""
+msgstr "Crear Función"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Function"
-msgstr ""
+msgstr "Eliminar Función"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Variable"
-msgstr ""
+msgstr "Eliminar Variable"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Variable:"
-msgstr ""
+msgstr "Editando Variable:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Signal"
-msgstr ""
+msgstr "Eliminar Sinal"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Signal:"
-msgstr ""
+msgstr "Editando Sinal:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Tool:"
-msgstr ""
+msgstr "Ferramenta:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Members:"
-msgstr ""
+msgstr "Membros:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Base Type:"
-msgstr ""
+msgstr "Cambiar Tipo Base:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Nodes..."
-msgstr ""
+msgstr "Engadir Nodos..."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Function..."
-msgstr ""
+msgstr "Engadir Función..."
#: modules/visual_script/visual_script_editor.cpp
msgid "function_name"
-msgstr ""
+msgstr "nome_da_funcion"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
-msgstr ""
+msgstr "Seleccione ou cree unha función para editar a sua gráfica."
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
-msgstr ""
+msgstr "Eliminar Selección"
#: modules/visual_script/visual_script_editor.cpp
msgid "Find Node Type"
-msgstr ""
+msgstr "Encontrar Tipo de Nodo"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
-msgstr ""
+msgstr "Copiar Nodos"
#: modules/visual_script/visual_script_editor.cpp
msgid "Cut Nodes"
-msgstr ""
+msgstr "Cortar Nodos"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Function"
@@ -11569,7 +11893,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Edit Member"
-msgstr ""
+msgstr "Editar Membro"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
@@ -11627,7 +11951,7 @@ msgstr ""
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Search VisualScript"
-msgstr ""
+msgstr "Buscar en VisualScript"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Get %s"
@@ -11678,10 +12002,14 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
+"Non está configurado o Keystore de depuración nin na configuración do "
+"editor, nin nos axustes de exportación."
#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
+"O Keystore Release non está configurado correctamente nos axustes de "
+"exportación."
#: platform/android/export/export.cpp
msgid "A valid Android SDK path is required in Editor Settings."
@@ -11728,6 +12056,8 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
msgstr ""
+"\"Use Custom Build\" debe estar activado para usar estas características "
+"adicionais (plugins)."
#: platform/android/export/export.cpp
msgid ""
@@ -11777,13 +12107,17 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
-msgstr ""
+msgstr "Construir Proxecto Android (gradle)"
#: platform/android/export/export.cpp
msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
+"A creación do proxecto para Android fallou; comproba a saída para encontrar "
+"o erro.\n"
+"Ou visita docs.godotengine.org para ver a documentación sobre compilación "
+"para Android."
#: platform/android/export/export.cpp
msgid "Moving output"
@@ -11806,6 +12140,7 @@ msgstr ""
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
msgstr ""
+"ID de App Store Team non especificado - non se pode configurar o proxecto."
#: platform/iphone/export/export.cpp
msgid "Invalid Identifier:"
@@ -11814,6 +12149,7 @@ msgstr ""
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
msgstr ""
+"As iconas requeridas non están especificadas nos axustes de exportación."
#: platform/javascript/export/export.cpp
msgid "Stop HTTP Server"
@@ -11921,6 +12257,10 @@ msgid ""
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
"define its shape."
msgstr ""
+"Este nodo non ten unha forma física definida, polo que non pode colisionar "
+"ou interactuar con outros obxectos.\n"
+"Engade un nodo CollisionShape2D ou CollisionPolygon2D como fillo para "
+"definir a sua forma."
#: scene/2d/collision_polygon_2d.cpp
msgid ""
@@ -11928,17 +12268,31 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"O nodo CollisionPolygon2D só serve para darlle unha forma física a nodos "
+"derivados de CollisionObject2D. É decir, do tipo Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, etc."
#: scene/2d/collision_polygon_2d.cpp
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"O nodo CollisionShape2D só serve para darlle unha forma física a nodos "
+"derivados de CollisionObject2D. É decir, do tipo Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, etc."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -11951,6 +12305,9 @@ msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"As formas físicas baseadas en polígonos non están pensadas para editarse "
+"directamente mediante o nodo CollisionShape2D. Por favor, usa o nodo "
+"CollisionPolygon2D no seu lugar."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
@@ -11960,23 +12317,23 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Os nodo A e B teñen que ser do tipo PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "O nodo A ten que ser un nodo PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "O nodo B ten que ser un nodo PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "A articulación non está conectada a dous nodos PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Os nodos A e B teñen que ser nodos PhysicsBody2D distintos"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12016,6 +12373,10 @@ msgid ""
"Use the CPUParticles2D node instead. You can use the \"Convert to "
"CPUParticles\" option for this purpose."
msgstr ""
+"As partículas baseadas na GPU non están soportas por o controlador de vídeo "
+"de GLES2.\n"
+"Usa o nodo CPUParticles2D no seu lugar. Podes usar a opción \"Converter a "
+"CPUParticles\" con tal motivo."
#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
msgid ""
@@ -12039,6 +12400,10 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Os cambios ao tamaño do RigidBody2D (en modo ríxido ou modo personaxe) serán "
+"sobreescritos por o motor físico cando a aplicación estea executándose.\n"
+"Cambia o tamaño dos nodos fillos (CollisionShape2D e CollisionPolygon2D) no "
+"seu lugar."
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
@@ -12083,6 +12448,8 @@ msgid ""
"The controller ID must not be 0 or this controller won't be bound to an "
"actual controller."
msgstr ""
+"O ID do controlador non pode ser 0, ou o controlador non estará asociado a "
+"ningún controlador real."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRAnchor must have an ARVROrigin node as its parent."
@@ -12093,6 +12460,8 @@ msgid ""
"The anchor ID must not be 0 or this anchor won't be bound to an actual "
"anchor."
msgstr ""
+"O ID da áncora non pode ser 0, ou esta áncora non estará asociada a ningunha "
+"áncora real."
#: scene/3d/arvr_nodes.cpp
msgid "ARVROrigin requires an ARVRCamera child node."
@@ -12120,7 +12489,7 @@ msgstr ""
#: scene/3d/baked_lightmap.cpp
msgid "Done"
-msgstr ""
+msgstr "Feito"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12128,6 +12497,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"Este nodo non ten unha forma física definida, polo que non pode colisionar "
+"ou interactuar con outros obxectos.\n"
+"Engade un nodo CollisionShape ou CollisionPolygon como fillo para definir a "
+"sua forma."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12135,6 +12508,9 @@ msgid ""
"CollisionObject derived node. Please only use it as a child of Area, "
"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
msgstr ""
+"O nodo CollisionPolygon só serve para darlle unha forma física a nodos "
+"derivados de CollisionObject. É decir, do tipo Area, StaticBody, RigidBody, "
+"KinematicBody, etc."
#: scene/3d/collision_polygon.cpp
msgid "An empty CollisionPolygon has no effect on collision."
@@ -12146,6 +12522,9 @@ msgid ""
"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
"KinematicBody, etc. to give them a shape."
msgstr ""
+"O nodo CollisionShape só serve para darlle unha forma física a nodos "
+"derivados de CollisionObject. É decir, do tipo Area, StaticBody, RigidBody, "
+"KinematicBody, etc."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12163,6 +12542,8 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"A forma física ConcavePolygonShape non está soportada en nodos RigidBody en "
+"ningún outro modo que non sexa o estático."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
@@ -12188,11 +12569,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12213,6 +12589,10 @@ msgid ""
"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
"\" option for this purpose."
msgstr ""
+"As partículas baseadas na GPU non están soportas por o controlador de vídeo "
+"de GLES2.\n"
+"Usa o nodo CPUParticles no seu lugar. Podes usar a opción \"Converter a "
+"CPUParticles\" con tal motivo."
#: scene/3d/particles.cpp
msgid ""
@@ -12241,6 +12621,10 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Os cambios ao tamaño do RigidBody (en modo ríxido ou modo personaxe) serán "
+"sobreescritos por o motor físico cando a aplicación estea executándose.\n"
+"Cambia o tamaño dos nodos fillos (CollisionShape e CollisionPolygon) no seu "
+"lugar."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
@@ -12248,11 +12632,11 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "O nodo A ten que ser un nodo PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "O nodo B ten que ser un nodo PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
@@ -12270,7 +12654,7 @@ msgstr ""
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
-msgstr ""
+msgstr "Este corpo será ignorado ata que se lle sea asignado unha malla."
#: scene/3d/soft_body.cpp
msgid ""
@@ -12278,6 +12662,10 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Os cambios ao tamaño do SoftBody serán sobreescritos por o motor físico "
+"cando a aplicación estea executándose.\n"
+"Cambia o tamaño dos nodos fillos (CollisionShape e CollisionPolygon) no seu "
+"lugar."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -12290,6 +12678,8 @@ msgid ""
"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
"it as a child of a VehicleBody."
msgstr ""
+"O nodo VehicleWheel (Roda de Vehículo) serve para proporcionar un sistema de "
+"rodas a un nodo VehicleBody. Por favor; úsao como fillo dun nodo VehicleBody."
#: scene/3d/world_environment.cpp
msgid ""
@@ -12361,11 +12751,11 @@ msgstr ""
#: scene/gui/color_picker.cpp
msgid "HSV"
-msgstr ""
+msgstr "HSV"
#: scene/gui/color_picker.cpp
msgid "Raw"
-msgstr ""
+msgstr "Sen Procesar (Raw)"
#: scene/gui/color_picker.cpp
msgid "Switch between hexadecimal and code values."
@@ -12381,6 +12771,10 @@ msgid ""
"children placement behavior.\n"
"If you don't intend to add a script, use a plain Control node instead."
msgstr ""
+"Un nodo contedor (Container) por sí mesmo non ten ningunha utilidade, salvo "
+"que se lle engada algún Script que configure a colocación dos seus nodos "
+"fillos.\n"
+"Se non tes pensado engadir un Script, utilizada un nodo Control no seu lugar."
#: scene/gui/control.cpp
msgid ""
@@ -12390,11 +12784,11 @@ msgstr ""
#: scene/gui/dialogs.cpp
msgid "Alert!"
-msgstr ""
+msgstr "Alerta!"
#: scene/gui/dialogs.cpp
msgid "Please Confirm..."
-msgstr ""
+msgstr "Por favor, confirma..."
#: scene/gui/file_dialog.cpp
msgid "Must use a valid extension."
@@ -12410,6 +12804,9 @@ msgid ""
"functions. Making them visible for editing is fine, but they will hide upon "
"running."
msgstr ""
+"As ventás emerxentes (Popups) están ocultas por defecto, a non ser que "
+"chames a popup() ou calquera das funcións popup*(). Podes facelas visibles "
+"para editalas, pero ocultarasen ao iniciar a execución."
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
@@ -12424,7 +12821,7 @@ msgstr ""
#: scene/gui/tree.cpp
msgid "(Other)"
-msgstr ""
+msgstr "(Outros)"
#: scene/main/scene_tree.cpp
msgid ""
@@ -12439,10 +12836,16 @@ msgid ""
"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
"texture to some node for display."
msgstr ""
+"Esta Mini-Ventá (Viewport) no está configurada como obxectivo de "
+"renderizado. Se quere que o seu contido se mostre directamente na pantalla, "
+"convértao nun nodo fillo dun nodo Control para que poida recibir dimensións. "
+"Ou ben, fágao un RenderTarget e asigne a súa textura a algún nodo."
#: scene/main/viewport.cpp
msgid "Viewport size must be greater than 0 to render anything."
msgstr ""
+"As dimensións da Mini-Ventá (Viewport) deben de ser maior que 0 para poder "
+"renderizar nada."
#: scene/resources/visual_shader_nodes.cpp
msgid ""
diff --git a/editor/translations/he.po b/editor/translations/he.po
index fc4ba10dc4..2966711057 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -18,12 +18,13 @@
# yariv benj <yariv4400@gmail.com>, 2020.
# Guy Dadon <guydadon14@gmail.com>, 2020.
# bruvzg <bruvzg13@gmail.com>, 2020.
+# Omer I.S. <omeritzicschwartz@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-12-03 19:28+0000\n"
-"Last-Translator: Ziv D <wizdavid@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Omer I.S. <omeritzicschwartz@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
"Language: he\n"
@@ -32,7 +33,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
"n % 10 == 0) ? 2 : 3));\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -379,9 +380,8 @@ msgid "Anim Insert"
msgstr "הוסף הנפשה"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "AnimationPlayer can't animate itself, only other players."
-msgstr "נגן הנפשות לא יכול להנפיש את עצמו, רק שחקנים אחרים."
+msgstr "נגן ההנפשות לא יכול להנפיש את עצמו, רק שחקנים אחרים."
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
@@ -662,7 +662,7 @@ msgstr "בחירת רצועות להעתקה"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "העתקה"
@@ -900,9 +900,8 @@ msgid "Connect a Signal to a Method"
msgstr "שגיאת חיבור"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Edit Connection:"
-msgstr "שגיאת חיבור"
+msgstr "עריכת חיבור:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
@@ -1102,7 +1101,7 @@ msgstr "דפדפן משאבים יתומים"
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
msgid "Delete"
-msgstr "למחוק"
+msgstr "מחיקה"
#: editor/dependency_editor.cpp
msgid "Owns"
@@ -1194,9 +1193,8 @@ msgid "License"
msgstr "רישיון"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Third-party Licenses"
-msgstr "רישיון צד שלישי"
+msgstr "רשיונות צד שלישי"
#: editor/editor_about.cpp
msgid ""
@@ -1250,9 +1248,8 @@ msgid "Success!"
msgstr "הצלחה!"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Package Contents:"
-msgstr "מתקין החבילות"
+msgstr "תוכן החבילה:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1657,9 +1654,8 @@ msgid "Script Editor"
msgstr "פתיחת עורך סקריפטים"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Asset Library"
-msgstr "ייצוא ספריה"
+msgstr "ספריית משאבים"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -1874,8 +1870,8 @@ msgid "Open a File or Directory"
msgstr "פתיחת קובץ או תיקייה"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "שמירה"
@@ -2532,7 +2528,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "לא ניתן לפתוח את תוסף ההרחבות בנתיב: '%s' פענוח ההגדרות נכשל."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "לא ניתן למצוא שדה סקריפט עבור תוסף הרחבה בנתיב 'res://addons/%s'."
#: editor/editor_node.cpp
@@ -2952,14 +2949,6 @@ msgid "Help"
msgstr "עזרה"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "חיפוש"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "מסמכים מקוונים"
@@ -3120,6 +3109,24 @@ msgid "Open & Run a Script"
msgstr "פתיחה והרצה של סקריפט"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"הקבצים הבאים הם חדשים בכונן.\n"
+"באילו פעולות לנקוט?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "רענון"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "שמירה מחדש"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "חדש בירושה"
@@ -3203,9 +3210,8 @@ msgid "Status:"
msgstr "מצב:"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Edit:"
-msgstr "עריכה"
+msgstr "עריכה:"
#: editor/editor_profiler.cpp
msgid "Measure:"
@@ -3328,7 +3334,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "הדבקה"
@@ -3638,6 +3644,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "מצב: ייבוא הקובץ נכשל. נא לתקן את הקובץ ולייבא מחדש ידנית."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "לא ניתן להעביר/לשנות שם למקור של משאבים."
@@ -4047,6 +4058,25 @@ msgstr ""
msgid "Saving..."
msgstr "שמירה…"
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "נא לבחור מפרקים לייצוא"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "ייבוא"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "טעינת בררת המחדל"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d קבצים"
@@ -5030,7 +5060,8 @@ msgid "Got:"
msgstr "התקבל:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "בדיקת האש sha256 נכשלה"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5134,7 +5165,6 @@ msgid "Sort:"
msgstr "מיון:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "קטגוריה:"
@@ -5498,9 +5528,8 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Reset"
-msgstr "להתרחק"
+msgstr "איפוס התקריב"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6987,6 +7016,14 @@ msgstr "סגירת מסמכים"
msgid "Run"
msgstr "הרצה"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "חיפוש"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "לצעוד לתוך"
@@ -7042,16 +7079,6 @@ msgstr ""
"הקבצים הבאים הם חדשים בכונן.\n"
"באילו פעולות לנקוט?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "רענון"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "שמירה מחדש"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "ניפוי שגיאות"
@@ -7150,8 +7177,8 @@ msgstr "מחיקת נקודות"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "גזירה"
@@ -7278,13 +7305,12 @@ msgid "Go to Previous Breakpoint"
msgstr "מעבר לנקודת העצירה הקודמת"
#: editor/plugins/shader_editor_plugin.cpp
-#, fuzzy
msgid ""
"This shader has been modified on on disk.\n"
"What action should be taken?"
msgstr ""
"הקבצים הבאים הם חדשים בכונן.\n"
-"באילו פעולות לנקוט?:"
+"באילו פעולות לנקוט?"
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
@@ -7582,6 +7608,11 @@ msgstr "הצגת מידע"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10057,6 +10088,13 @@ msgid "Projects"
msgstr "מיזם"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr ""
+"הקבצים נסרקים,\n"
+"נא להמתין…"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10427,6 +10465,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "טעינת בררת המחדל"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "ערכה מוגדרת…"
@@ -10686,6 +10729,16 @@ msgid "Instance Child Scene"
msgstr "יצירת מופע לסצנה הצאצאית"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "לא יכול לפעול על מפרקים מסצנה זרה!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "הדבקת מפרקים"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "ניתוק סקריפט"
@@ -10809,6 +10862,11 @@ msgid "Attach Script"
msgstr "חיבור סקריפט"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "גזירת מפרקים"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "הסרת מפרק(ים)"
@@ -10918,6 +10976,13 @@ msgid "Remote"
msgstr "מרוחק"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "מקומי"
@@ -12443,6 +12508,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "ל־CollisionPolygon2D ריק אין השפעה על התנגשות."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12740,11 +12813,6 @@ msgstr ""
"מנהל הווידאו GLES2 אינו תומך ב- GIProbes.\n"
"השתמש ב-BakedLightmap במקום."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight עם זווית רחבה מ-90 מעלות אינו יכול להטיל צללים."
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 08829557bb..6c465ad015 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -649,7 +649,7 @@ msgstr "कॉपी करने के लिए ट्रैक का चय
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "कॉपी"
@@ -1852,8 +1852,8 @@ msgid "Open a File or Directory"
msgstr "फ़ाइल या डायरेक्टरी खोलिये"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "सेव कीजिये"
@@ -2518,7 +2518,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "ऐडऑन प्लगइन को सक्षम करने में असमर्थ: '%' कॉन्फिग का पार्सिंग विफल रहा।"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "ऐडऑन प्लगइन के लिए स्क्रिप्ट फ़ील्ड खोजने में असमर्थ: 'res://addons/% s'।"
#: editor/editor_node.cpp
@@ -2946,14 +2947,6 @@ msgid "Help"
msgstr "मदद"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "ढूंढें"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "ऑनलाइन डॉक्स"
@@ -3117,6 +3110,23 @@ msgid "Open & Run a Script"
msgstr "ओपन एंड रन एक स्क्रिप्ट"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "निम्न फ़ाइलों का निस्सारण नहीं हो पाया:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "नई विरासत में मिली"
@@ -3324,7 +3334,7 @@ msgstr "अद्वितीय बनाओ"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "चिपकाएँ"
@@ -3636,6 +3646,11 @@ msgstr ""
"स्थिति: फाइल का आयात विफल रहा। कृपया फाइल को ठीक करें और मैन्युअल रूप से पुनर्आयात करें।"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "संसाधनों की जड़ को स्थानांतरित/नाम नहीं दे सकते ।"
@@ -4025,6 +4040,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "आयात करने के लिए नोड (एस) का चयन करें"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "इंपोर्ट"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "प्रायिक लोड कीजिये"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4972,7 +5006,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5076,7 +5110,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6863,6 +6896,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "ढूंढें"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6914,16 +6955,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7020,8 +7051,8 @@ msgstr "एक नया बनाएं"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7430,6 +7461,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9839,6 +9875,11 @@ msgid "Projects"
msgstr "परियोजना के संस्थापक"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "दर्पण को पुनः प्राप्त करना, कृपया प्रतीक्षा करें ..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10201,6 +10242,11 @@ msgstr ""
msgid "Plugins"
msgstr "प्लगइन्स"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "प्रायिक लोड कीजिये"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10446,6 +10492,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "प्रतिलिपि"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "नई स्क्रिप्ट"
@@ -10572,6 +10627,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "प्रतिलिपि"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10682,6 +10742,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12190,6 +12257,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12447,11 +12522,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index 95f2844a22..dc71edeec3 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -5,11 +5,11 @@
# Unlimited Creativity <marinosah1@gmail.com>, 2019.
# Patik <patrikfs5@gmail.com>, 2019.
# Nikola Bunjevac <nikola.bunjevac@gmail.com>, 2019, 2020.
-# LeoClose <leoclose575@gmail.com>, 2020.
+# LeoClose <leoclose575@gmail.com>, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-11-17 11:07+0000\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
"Last-Translator: LeoClose <leoclose575@gmail.com>\n"
"Language-Team: Croatian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hr/>\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -631,7 +631,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopiraj"
@@ -1812,8 +1812,8 @@ msgid "Open a File or Directory"
msgstr "Otvori datoteku ili direktorij"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Spremi"
@@ -2447,7 +2447,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2837,14 +2837,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2863,7 +2855,7 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr ""
+msgstr "Zajednica"
#: editor/editor_node.cpp
msgid "About"
@@ -2998,6 +2990,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3200,7 +3208,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3504,6 +3512,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3885,6 +3898,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Odaberi Sve/Ništa"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Uvoz"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Učitaj Zadano"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fajlovi"
@@ -4832,7 +4864,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4936,7 +4968,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6703,6 +6734,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6754,16 +6793,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6856,8 +6885,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7263,6 +7292,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9615,6 +9649,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9885,7 +9923,7 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "General"
-msgstr ""
+msgstr "Općenito"
#: editor/project_settings_editor.cpp
msgid "Override For..."
@@ -9975,6 +10013,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Učitaj Zadano"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10218,6 +10261,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Brisati odabrani ključ/odabrane ključeve"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Odspoji Skriptu"
@@ -10338,6 +10390,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10445,6 +10501,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11921,6 +11984,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12176,11 +12247,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index e774fec26d..2ef5783de9 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -15,12 +15,13 @@
# thekeymethod <csokan.andras87@protonmail.ch>, 2020.
# Czmorek Dávid <czmdav.soft@gmail.com>, 2020.
# Újvári Marcell <mmarci72@gmail.com>, 2021.
+# Gergő Pistai <gergopistai@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
-"Last-Translator: Újvári Marcell <mmarci72@gmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Gergő Pistai <gergopistai@gmail.com>\n"
"Language-Team: Hungarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hu/>\n"
"Language: hu\n"
@@ -28,7 +29,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -663,7 +664,7 @@ msgstr "Másolandó nyomvonalak kiválasztása"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Másolás"
@@ -673,15 +674,15 @@ msgstr "Összes/semmi kijelölése"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
-msgstr ""
+msgstr "Hangsávklip hozzáadása"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "Hangsáv klip eltolt kezdési idejének módosítása"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "Hangsáv klip eltolt befejezési idejének módosítása"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -732,9 +733,8 @@ msgid "Replace All"
msgstr "Összes cseréje"
#: editor/code_editor.cpp
-#, fuzzy
msgid "Selection Only"
-msgstr "Csak a kijelölés"
+msgstr "Csak kijelölés"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -771,7 +771,7 @@ msgstr "Sor és oszlopszámok."
#: editor/connections_dialog.cpp
msgid "Method in target node must be specified."
-msgstr ""
+msgstr "Nevezze el a metódust a cél node-ban."
#: editor/connections_dialog.cpp
msgid "Method name must be a valid identifier."
@@ -915,9 +915,8 @@ msgid "Signals"
msgstr "Jelzések"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Csempék szűrése"
+msgstr "Jelek szűrése"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1045,14 +1044,14 @@ msgid "Owners Of:"
msgstr "Tulajdonosai:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Eltávolítja a kiválasztott fájlokat a projektből? (nem visszavonható)"
+msgstr ""
+"Eltávolítja a kiválasztott fájlokat a projektből? (nem visszavonható)\n"
+"Az eltávolított fájlokat a lomtárban találja, ha visszaállítaná őket."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1060,7 +1059,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Az eltávolítandó fájlokat szükségelik más források a működésükhöz.\n"
-"Eltávolítja őket ennek ellenére? (nem visszavonható)"
+"Eltávolítja őket ennek ellenére? (nem visszavonható)\n"
+"Az eltávolított fájlokat a lomtárban találja, ha visszaállítaná őket."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1202,7 +1202,6 @@ msgid "Third-party Licenses"
msgstr "Harmadik féltől származó licencek"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
@@ -1591,12 +1590,16 @@ msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC' textúra tömörítésre van szüksége GLES2-höz. "
+"Engedélyezze az 'Import Etc' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC2' textúra tömörítésre van szüksége GLES3-höz. "
+"Engedélyezze az 'Import Etc 2' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
@@ -1605,18 +1608,27 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"A célplatformnak 'ETC' textúra tömörítésre van szüksége a tartalék driverhez "
+"GLES2-höz.\n"
+"Engedélyezze az 'Import Etc' beállítást a Projekt Beállításokban, vagy "
+"kapcsolja ki a 'Driver Fallback Enabled' beállítást."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"A célplatformnak 'PVRTC' textúra tömörítésre van szüksége GLES2-höz. "
+"Engedélyezze az 'Import Pvrtc' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC2' vagy 'PVRTC' textúra tömörítésre van szüksége GLES3-"
+"hoz. Engedélyezze az 'Import Etc 2' vagy 'Import Pvrtc' beállítást a Projekt "
+"Beállításokban."
#: editor/editor_export.cpp
msgid ""
@@ -1625,6 +1637,9 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"A célplatformnak 'PVRTC' textúra tömörítésre van szüksége GLES2-höz.\n"
+"Engedélyezze az 'Import Pvrtc' beállítást a Projekt Beállításokban, vagy "
+"kapcsolja ki a 'Driver Fallback Enabled' beállítást."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1644,7 +1659,7 @@ msgstr "Sablon fájl nem található:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
-msgstr ""
+msgstr "32-bites exportokon a beágyazott PCK nem lehet nagyobb mint 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1664,12 +1679,11 @@ msgstr "Jelenetfa szerkesztése"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Node dokk"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Fájlrendszer"
+msgstr "Fájlrendszer dokk"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1810,7 +1824,7 @@ msgstr "Válassza ezt a mappát"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Útvonal másolása"
+msgstr "Útvonal Másolása"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
@@ -1855,8 +1869,8 @@ msgid "Open a File or Directory"
msgstr "Fájl vagy Könyvtár Megnyitása"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Mentés"
@@ -1879,11 +1893,11 @@ msgstr "Ugrás Fel"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Rejtett fálok megjelenítése/elrejtése"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Kedvencek Mutatása/Elrejtése"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
@@ -1891,7 +1905,7 @@ msgstr "Mód váltása"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr ""
+msgstr "Elérési Út Fókuszálása"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
@@ -1926,7 +1940,6 @@ msgid "Toggle the visibility of hidden files."
msgstr "A rejtett fájlok láthatóságának ki- és bekapcsolása."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
-#, fuzzy
msgid "View items as a grid of thumbnails."
msgstr "Az elemek megtekintése bélyegkép-rácsként."
@@ -2117,9 +2130,8 @@ msgid "Property:"
msgstr "Tulajdonság:"
#: editor/editor_inspector.cpp
-#, fuzzy
msgid "Set"
-msgstr "Beállítás"
+msgstr "Beállít"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
@@ -2272,6 +2284,9 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Ezt a jelenetet nem lehet elmenteni, mivel ciklikus peldányosítást "
+"tartalmaz.\n"
+"Kérem oldja meg a problémát, aztán próbáljon meg ismét menteni."
#: editor/editor_node.cpp
msgid ""
@@ -2306,6 +2321,9 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Hiba történt a szerkesztő elrendezésének mentése közben.\n"
+"Bizonyosodjon meg róla, hogy a szerkesztő felhasználói elérési útján "
+"engedélyezve van az írás."
#: editor/editor_node.cpp
msgid ""
@@ -2313,16 +2331,19 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Alapértelmezett szerkesztő elrendezés felülírva.\n"
+"Hogy visszaállítsa az alapértelmezett elrendezést az eredeti beállításokra, "
+"használja az Elrendezés Törlése opciót és törölje az alapértelmezett "
+"elrendezést."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Elrendezés neve nem található!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
msgstr ""
-"Az alapértelmezett elrendezés vissza lett állítva az alap beállításokra."
+"Az alapértelmezett elrendezés vissza lett állítva az eredeti beállításokra."
#: editor/editor_node.cpp
msgid ""
@@ -2382,7 +2403,7 @@ msgstr "Nincs meghatározva Scene a futtatáshoz."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Futtatás előtt mentse a jelenetet..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2390,23 +2411,23 @@ msgstr "Az alprocesszt nem lehetett elindítani!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr "Scene megnyitás"
+msgstr "Jelenet megnyitása"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr "Alap Scene megnyitás"
+msgstr "Alap Jelenet Megnyitása"
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr "Gyors megnyitás..."
+msgstr "Gyors Megnyitás..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr "Jelenet gyors megnyitása..."
+msgstr "Jelenet Gyors Megnyitása..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr "Szkript gyors megnyitás..."
+msgstr "Szkript Gyors Megnyitás..."
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -2422,11 +2443,11 @@ msgstr "%s módosított erőforrás mentve."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "Egy gyökér node szükséges a jelenet mentéséhez."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Scene mentés másként..."
+msgstr "Scene Mentése Másként..."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
@@ -2530,7 +2551,7 @@ msgstr ""
"megbukott."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Nem található szkript mező az addon pluginnak a következő helyen: 'res://"
"addons/%s'."
@@ -2736,7 +2757,7 @@ msgstr "Legutóbbi Megnyitása"
#: editor/editor_node.cpp
msgid "Save Scene"
-msgstr "Scene mentés"
+msgstr "Jelenet Mentése"
#: editor/editor_node.cpp
msgid "Save All Scenes"
@@ -2762,7 +2783,7 @@ msgstr "Visszavonás"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr "Mégis"
+msgstr "Újra"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
@@ -2833,12 +2854,10 @@ msgid ""
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "Kis Telepítés Hálózati FS-sel"
+msgstr "Kis Telepítés Hálózati Fájlrendszerrel"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2859,52 +2878,46 @@ msgid "Visible Collision Shapes"
msgstr "Látható Ütközési Alakzatok"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
-"Az ütközési alakzatok és a fénysugárkövető Node-ok (mind 2D-hez és 3D-hez) "
-"láthatóak lesznek a játék futásakor, ha ez az opció be van kapcsolva."
+"Ha ez az opció be van kapcsolva, az ütközési alakzatok és a sugárkövető Node-"
+"ok (mind 2D-hez és 3D-hez) láthatóak lesznek a játék futásakor."
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "Látható Navigáció"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"A navigációs hálók és sokszögek láthatóak lesznek a játék futásakor, ha ez "
-"az opció be van kapcsolva."
+"Ha ez az opció be van kapcsolva, a navigációs hálók és sokszögek láthatóak "
+"lesznek a játék futásakor."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
-msgstr "Jelenet változtatások szinkronizálása"
+msgstr "Jelenet Változások Szinkronizálása"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any changes made to the scene in the editor "
"will be replicated in the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"Ha ez a beállítás be van kapcsolva, bármilyen változtatás a jeleneten a "
-"szerkesztőben le lesz másolva a futó játékba.\n"
-"Ha egy távoli eszközön használja, sokkal hatékonyabb a hálózati "
-"fájlrendszerrel együtt."
+"Ha ez a beállítás be van kapcsolva, bármely a jeleneten való változtatás a "
+"szerkesztből, a futó projekre is alkalmazva lesz.\n"
+"Távoli eszköz használatakor hatékonyabb, ha a hálózati fájlrendszer opció "
+"engedélyezve van."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
msgstr "Szkript Változtatások Szinkronizálása"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
@@ -2913,8 +2926,8 @@ msgid ""
msgstr ""
"Ha ez a beállítás be van kapcsolva, bármilyen szkript, amit elment, újra "
"betöltődik a futó játékba.\n"
-"Ha egy távoli eszközön használja, sokkal hatékonyabb a hálózati "
-"fájlrendszerrel együtt."
+"Távoli eszköz használatakor hatékonyabb, ha a hálózati fájlrendszer opció "
+"engedélyezve van."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2949,9 +2962,8 @@ msgid "Open Editor Data/Settings Folder"
msgstr "Szerkesztő adatok/beállítások mappa megnyitása"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Editor Data Folder"
-msgstr "A szerkesztő adatmappájának megnyitása"
+msgstr "Szerkesztő Adatmappájának Megnyitása"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
@@ -2970,14 +2982,6 @@ msgid "Help"
msgstr "Súgó"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Keresés"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Dokumentáció"
@@ -2991,9 +2995,8 @@ msgid "Report a Bug"
msgstr "Hiba bejelentése"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Send Docs Feedback"
-msgstr "Visszajelzés a Dokumentumokról"
+msgstr "Visszajelzé Küldése s A Dokumentumokról"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3029,7 +3032,7 @@ msgstr "Szerkesztett Scene futtatása."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr "Scene futtatás"
+msgstr "Scene Futtatása"
#: editor/editor_node.cpp
msgid "Play custom scene"
@@ -3088,6 +3091,7 @@ msgstr "Nincs Mentés"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
msgstr ""
+"Hiányzó Android építési-sablon, kérem telepítse az ide tartozó sablonokat."
#: editor/editor_node.cpp
msgid "Manage Templates"
@@ -3111,6 +3115,10 @@ msgid ""
"Remove the \"res://android/build\" directory manually before attempting this "
"operation again."
msgstr ""
+"Az Android építési-sablon már telepítve van a projektbe és nem lesz "
+"felülírva.\n"
+"Távolítsa el a(z) \"res://android/build\" könyvtárat manuálisan, mivelőtt "
+"újra megkísérelné a műveletet."
#: editor/editor_node.cpp
msgid "Import Templates From ZIP File"
@@ -3133,6 +3141,24 @@ msgid "Open & Run a Script"
msgstr "Szkriptet Megnyit és Futtat"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"A alábbi fájlok újabbak a lemezen.\n"
+"Mit szeretne tenni?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Újratöltés"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Újramentés"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Új Örökölt"
@@ -3142,7 +3168,7 @@ msgstr "Betöltési Hibák"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
-msgstr "Kiválaszt"
+msgstr "Kiválasztás"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3335,7 +3361,7 @@ msgstr "Egyedivé tétel"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Beillesztés"
@@ -3373,14 +3399,13 @@ msgid "Add Key/Value Pair"
msgstr "Kulcs/érték pár hozzáadása"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
"Nem található futtatható exportállomány ehhez a platformhoz.\n"
-"Adjon hozzá egy futtatható exportállományt az export menüben."
+"Kérem adjon hozzá egy futtatható exportállományt az export menüben."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3541,12 +3566,11 @@ msgid "Cannot remove temporary file:"
msgstr "Az ideiglenes fájl nem távolítható el:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid ""
"Templates installation failed.\n"
"The problematic templates archives can be found at '%s'."
msgstr ""
-"A sablonok telepítése nem sikerült.\n"
+"A sablonok telepítése sikertelen.\n"
"A problémás sablonok archívuma megtalálható a következő helyen: '%s'."
#: editor/export_template_manager.cpp
@@ -3651,6 +3675,11 @@ msgstr ""
"újra manuálisan."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Az erőforrások gyökere nem mozgatható vagy átnevezhető."
@@ -3775,9 +3804,8 @@ msgid "Duplicate..."
msgstr "Megkettőzés..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "AutoLoad Áthelyezése"
+msgstr "Lomtárba Helyezés"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3886,19 +3914,16 @@ msgid "Searching..."
msgstr "Keresés…"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d egyezés."
+msgstr "%d egyezés %d fájlban."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d egyezés."
+msgstr "%d egyezés %d fájlban."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d egyezés."
+msgstr "%d egyezések %d fájlban."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4035,6 +4060,22 @@ msgstr ""
msgid "Saving..."
msgstr "Mentés..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Importer Kiválasztása"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importáló:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Visszaállítás Alapértelmezettre"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d fájl"
@@ -4069,7 +4110,6 @@ msgstr ""
"Az importált fájl típusának módosításához a szerkesztőt újra kell indítani."
#: editor/import_dock.cpp
-#, fuzzy
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
@@ -4354,7 +4394,6 @@ msgid "BlendSpace2D does not belong to an AnimationTree node."
msgstr ""
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "No triangles exist, so no blending can take place."
msgstr "Nincsenek háromszögek, így nem történhet keverés."
@@ -4784,7 +4823,7 @@ msgstr "Lejátszási mód:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr ""
+msgstr "AnimációFa"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -4993,8 +5032,8 @@ msgid "Got:"
msgstr "Kapott:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "sha256 hash ellenőrzés megbukott"
+msgid "Failed SHA-256 hash check"
+msgstr "SHA-256 hash ellenőrzés megbukot"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5097,7 +5136,6 @@ msgid "Sort:"
msgstr "Rendezés:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategória:"
@@ -5173,7 +5211,7 @@ msgstr "Fény Besütése"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Válasszon sablonfájlt"
+msgstr "Válasszon fénytérkép sablonfájlt:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5245,19 +5283,17 @@ msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "CanvasItem forgatása"
+msgstr "%d CanvasItem Forgatása"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "CanvasItem forgatása"
+msgstr "\"%s\" CanvasItem Forgatása %d fokra"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "CanvasItem áthelyezése"
+msgstr "CanvasItem \"%s\" Horgony Mozgatása"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
@@ -5268,24 +5304,20 @@ msgid "Resize Control \"%s\" to (%d, %d)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "CanvasItem méretezése"
+msgstr "%d CanvasItem Méretezése"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "CanvasItem méretezése"
+msgstr "\"%s\" CanvasItem Méretezése (%s, %s)-ra/re"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "CanvasItem áthelyezése"
+msgstr "%d CanvasItem Áthelyezése"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "CanvasItem áthelyezése"
+msgstr "%s CanvasItem mozgatása (%d, %d)-ra/re"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5364,9 +5396,8 @@ msgid "HCenter Wide"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Full Rect"
-msgstr "Teljes téglalap"
+msgstr "Teljes Téglalap"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Keep Ratio"
@@ -5386,10 +5417,13 @@ msgstr "Horgonyok Módosítása"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Játék Kamera Felülírás.\n"
+"Felülírja a játék kamerát szerkesztői nézetablak kamerával."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5480,12 +5514,12 @@ msgstr "Alt + Jobb Egérgomb: Mélységi lista választás"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Mozgató Mód"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr "Forgató mód"
+msgstr "Forgató Mód"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5828,7 +5862,6 @@ msgid "Emission Colors"
msgstr "Kibocsátási színek"
#: editor/plugins/cpu_particles_editor_plugin.cpp
-#, fuzzy
msgid "CPUParticles"
msgstr "CPU-részecskék"
@@ -5843,7 +5876,6 @@ msgid "Create Emission Points From Node"
msgstr "Kibocsátási pontok létrehozása a Node alapján"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Flat 0"
msgstr "Lapos 0"
@@ -5892,9 +5924,8 @@ msgid "Right Linear"
msgstr "Jobb lineáris"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Load Preset"
-msgstr "Előre beállított betöltése"
+msgstr "Beállítás Betöltése"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Curve Point"
@@ -6235,7 +6266,6 @@ msgstr "Navigációs Sokszög Létrehozása"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles"
msgstr "Konvertálás CPU-részecskékké"
@@ -6252,9 +6282,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "Csak egy ParticlesMaterial feldolgozó anyagba állíthat pontot"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Konvertálás CPU-részecskékké"
+msgstr "Konvertálás CPUParticles2D-re"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6539,18 +6568,16 @@ msgid "Move Points"
msgstr "Pontok mozgatása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Húzás: Forgatás"
+msgstr "Command: Forgatás"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Mind Mozgatása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift + Ctrl: Skálázás"
+msgstr "Shif+Command: Méretezés"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6595,14 +6622,12 @@ msgid "Radius:"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Sokszög és UV létrehozása"
+msgstr "Sokszög UV-ba másolása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Csontok szinkronizálása a sokszöggel"
+msgstr "UV Másolása Sokszögbe"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -6649,9 +6674,8 @@ msgid "Grid Step Y:"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Sync Bones to Polygon"
-msgstr "Csontok szinkronizálása a sokszöggel"
+msgstr "Csontok Szinkronizálása Sokszögre"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
@@ -6811,7 +6835,6 @@ msgid "Filter scripts"
msgstr "Szkriptek szűrése"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Toggle alphabetical sorting of the method list."
msgstr "Ábécészerinti rendezés változtatása a metóduslistában."
@@ -6904,6 +6927,14 @@ msgstr "Dokumentációs Lapok Bezárása"
msgid "Run"
msgstr "Futtatás"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Keresés"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Belépés"
@@ -6957,16 +6988,6 @@ msgstr ""
"A alábbi fájlok újabbak a lemezen.\n"
"Mit szeretne lépni?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Újratöltés"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Újramentés"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Hibakereső"
@@ -7059,8 +7080,8 @@ msgstr "Töréspontok"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Kivágás"
@@ -7087,7 +7108,7 @@ msgstr "Átváltás Megjegyzésre"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr "Sor Összezárása / Kibontása"
+msgstr "Sor Összezárása/Kibontása"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7107,7 +7128,7 @@ msgstr "Szimbólum Befejezése"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
-msgstr ""
+msgstr "Kijelölés Kiértékelése"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
@@ -7197,7 +7218,6 @@ msgid "Set Rest Pose to Bones"
msgstr ""
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton2D"
msgstr "Csontváz2D"
@@ -7227,27 +7247,27 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
-msgstr ""
+msgstr "Ortogonális"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective"
-msgstr ""
+msgstr "Perspektíva"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
-msgstr ""
+msgstr "Átalakítás Megszakítva."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "X-Axis Transform."
-msgstr ""
+msgstr "X-Tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Y-Axis Transform."
-msgstr ""
+msgstr "Y-tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Z-Axis Transform."
-msgstr "Z-Tengely transzformáció"
+msgstr "Z-Tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Plane Transform."
@@ -7282,9 +7302,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Méret: "
+msgstr "Méret"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7468,6 +7487,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7538,7 +7562,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
-msgstr ""
+msgstr "Animációs Kulcs Beszúrása"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
@@ -7827,9 +7851,8 @@ msgid "Loop"
msgstr "Ciklus"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animation Frames:"
-msgstr "Animációs képkockák:"
+msgstr "Animációs Képkockák:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add a Texture from File"
@@ -7884,9 +7907,8 @@ msgid "Set Region Rect"
msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
-#, fuzzy
msgid "Set Margin"
-msgstr "Margó beállítása"
+msgstr "Margó Beállítása"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
@@ -8010,12 +8032,10 @@ msgid "Submenu"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Subitem 1"
msgstr "Alelem 1"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Subitem 2"
msgstr "Alelem 2"
@@ -8091,7 +8111,7 @@ msgstr "Érvénytelen csempék javítása"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Cut Selection"
-msgstr "Kijelölés kivágása"
+msgstr "Kijelölés Kivágása"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
@@ -8119,16 +8139,15 @@ msgstr "Csempe keresése"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr ""
+msgstr "Transzpozálás"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Enable Priority"
-msgstr "Prioritás engedélyezése"
+msgstr "Prioritás Engedélyezése"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Filter tiles"
@@ -8183,9 +8202,8 @@ msgid "Add Texture(s) to TileSet."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected Texture from TileSet."
-msgstr "Távolítsa el a kijelölt textúrát a csempekészletből."
+msgstr "Kijelölj textúra eltávolítása TileSet-ből."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8224,7 +8242,6 @@ msgid "Select the previous shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region"
msgstr "Régió"
@@ -8241,7 +8258,6 @@ msgid "Navigation"
msgstr "Navigáció"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask"
msgstr "Bitmaszk"
@@ -8302,23 +8318,20 @@ msgid "Create a new rectangle."
msgstr "Új téglalap létrehozása."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Új Scene"
+msgstr "Új Négyszög"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Új sokszög létrehozása."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Sokszög Mozgatása"
+msgstr "Új Sokszög"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Kijelöltek törlése"
+msgstr "Kijelölt Alakzat Törlése"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8642,7 +8655,6 @@ msgid "Remove output port"
msgstr "Kimeneti port eltávolítása"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Set expression"
msgstr "Kifejezés beállítása"
@@ -8663,9 +8675,8 @@ msgid "Add Node to Visual Shader"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Node eltávolítva"
+msgstr "Node(ok) Áthelyezve"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -8685,9 +8696,8 @@ msgid "Visual Shader Input Type Changed"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "A paraméter megváltozott"
+msgstr "UniformRef Név Megváltozott"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -8710,7 +8720,6 @@ msgid "Create Shader Node"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color function."
msgstr "Szín függvény."
@@ -8771,7 +8780,6 @@ msgid "SoftLight operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color constant."
msgstr "Színállandó."
@@ -8846,7 +8854,6 @@ msgid ""
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Boolean constant."
msgstr "Logikai állandó."
@@ -8859,7 +8866,6 @@ msgid "'%s' input parameter for all shader modes."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Input parameter."
msgstr "Bemeneti paraméter."
@@ -8888,12 +8894,10 @@ msgid "'%s' input parameter for vertex and fragment shader mode."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar function."
msgstr "Skalárfüggvény."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar operator."
msgstr "Skalár operátor."
@@ -9120,9 +9124,8 @@ msgid "Subtracts scalar from scalar."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar constant."
-msgstr "Skaláris állandó."
+msgstr "Skalár állandó."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar uniform."
@@ -9200,12 +9203,10 @@ msgid "Transform uniform."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Vektor függvény."
+msgstr "Vektorfüggvény."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector operator."
msgstr "Vektor operátor."
@@ -9324,7 +9325,6 @@ msgid "Subtracts vector from vector."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector constant."
msgstr "Vektor állandó."
@@ -9465,9 +9465,8 @@ msgid ""
msgstr ""
#: editor/project_export.cpp
-#, fuzzy
msgid "Export Path"
-msgstr "Exportálási útvonal"
+msgstr "Exportálási Útvonal"
#: editor/project_export.cpp
msgid "Resources"
@@ -9507,7 +9506,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Funkciók"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -9522,9 +9521,8 @@ msgid "Script"
msgstr "Szkript"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script Export Mode:"
-msgstr "Szkript exportálás módja:"
+msgstr "Szkript Exportálás Mód:"
#: editor/project_export.cpp
msgid "Text"
@@ -9587,9 +9585,8 @@ msgid "The path specified doesn't exist."
msgstr "A megadott útvonal nem létezik."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file (it's not in ZIP format)."
-msgstr "Hiba a csomagfájl megnyitása során (az nem ZIP formátumú)."
+msgstr "Hiba a csomagfájl megnyitása során (nem ZIP formátumú)."
#: editor/project_manager.cpp
msgid ""
@@ -9739,12 +9736,10 @@ msgid "Error: Project is missing on the filesystem."
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Can't open project at '%s'."
msgstr "A projekt nem nyitható meg a(z) %s helyen."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Are you sure to open more than one project?"
msgstr "Biztos, hogy egynél több projektet nyit meg?"
@@ -9836,6 +9831,10 @@ msgid "Projects"
msgstr "Projektek"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Betöltés, kérem várjon..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9928,10 +9927,9 @@ msgstr "Eszköz"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr "Nyomjon le egy billentyűt"
+msgstr "Nyomjon meg egy billentyűt..."
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Mouse Button Index:"
msgstr "Egérgomb index:"
@@ -10012,9 +10010,8 @@ msgid "Middle Button."
msgstr "Középső Egérgomb."
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Wheel Up."
-msgstr "Felfelé görgetés."
+msgstr "Felfelé Görgetés."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
@@ -10143,7 +10140,6 @@ msgid "Index:"
msgstr "Index:"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Localization"
msgstr "Lokalizáció"
@@ -10199,6 +10195,11 @@ msgstr ""
msgid "Plugins"
msgstr "Bővítmények"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Alapértelmezett Betöltése"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Beépített Beállítások..."
@@ -10356,8 +10357,9 @@ msgid "snake_case to PascalCase"
msgstr ""
#: editor/rename_dialog.cpp
+#, fuzzy
msgid "Case"
-msgstr ""
+msgstr "Eset"
#: editor/rename_dialog.cpp
msgid "To Lowercase"
@@ -10376,45 +10378,46 @@ msgid "Regular Expression Error:"
msgstr "Reguláris Kifejezési Hiba:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
msgstr "A(z) %s karakternél"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
-msgstr ""
+msgstr "Node új szülőhöz rendelése"
#: editor/reparent_dialog.cpp
msgid "Reparent Location (Select new Parent):"
-msgstr ""
+msgstr "Helyszín új szülőhöz rendelése (Új szülő kiválasztása):"
#: editor/reparent_dialog.cpp
msgid "Keep Global Transform"
-msgstr ""
+msgstr "Globális Transzformáció Megtartása"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent"
-msgstr ""
+msgstr "Új szülő hozzárendelése"
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
-msgstr ""
+msgstr "Futás Mód:"
#: editor/run_settings_dialog.cpp
+#, fuzzy
msgid "Current Scene"
-msgstr ""
+msgstr "Jelenlegi Jelenet"
#: editor/run_settings_dialog.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "Fő Jelenet"
#: editor/run_settings_dialog.cpp
msgid "Main Scene Arguments:"
-msgstr ""
+msgstr "Fő Jelenet Argumentumok:"
#: editor/run_settings_dialog.cpp
+#, fuzzy
msgid "Scene Run Settings"
-msgstr ""
+msgstr "Jelenet Indítási Beállítások"
#: editor/scene_tree_dock.cpp
msgid "No parent to instance the scenes at."
@@ -10432,15 +10435,24 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Scene(s)"
-msgstr ""
+msgstr "Jelenet(ek) Példányosítása"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Replace with Branch Scene"
-msgstr ""
+msgstr "Kicserélés Ág Jelenettel"
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
-msgstr ""
+msgstr "Gyermek Jelenet Peldányosítása"
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Gyökér node nem illeszthető be azonos jelenetbe."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Node(ok) beillesztése"
#: editor/scene_tree_dock.cpp
msgid "Detach Script"
@@ -10460,7 +10472,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Duplicate Node(s)"
-msgstr ""
+msgstr "Node(ok) Megkettőzése"
#: editor/scene_tree_dock.cpp
msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
@@ -10488,7 +10500,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
-msgstr ""
+msgstr "Gyökér node törlése \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\" and its children?"
@@ -10532,23 +10544,23 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Create Root Node:"
-msgstr "Gyökér node létrehozása:"
+msgstr "Gyökér Node Létrehozása:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr "2D jelenet"
+msgstr "2D Jelenet"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr "3D jelenet"
+msgstr "3D Jelenet"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
-msgstr ""
+msgstr "Felhasználói Felület"
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr ""
+msgstr "Másik Node"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -10563,6 +10575,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Node(ok) Kivágása"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10670,6 +10686,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -10686,14 +10709,12 @@ msgid "Unlock Node"
msgstr "Node feloldása"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Button Group"
msgstr "Gombcsoport"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "(Connecting From)"
-msgstr "(Csatlakozás innen)"
+msgstr "(Csatlakozás Innen)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
@@ -10776,9 +10797,8 @@ msgid "Path is not local."
msgstr "Az útvonal nem helyi."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid base path."
-msgstr "Érvénytelen alapútvonal."
+msgstr "Érvénytelen Alapútvonal."
#: editor/script_create_dialog.cpp
msgid "A directory with the same name exists."
@@ -11036,7 +11056,7 @@ msgstr ""
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
-msgstr ""
+msgstr "Gyorsbillentyű törlése"
#: editor/settings_config_dialog.cpp
msgid "Restore Shortcut"
@@ -11361,29 +11381,24 @@ msgid "Preparing data structures"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "AABB Generálása"
+msgstr "Bufferek Generálása"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Irányok"
+msgstr "Közvetlen megvilágítás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "Behúzás Jobbra"
+msgstr "Közvetett megvilágítás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Kifejezés beállítása"
+msgstr "Utófeldolgozás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Fénytérképek Létrehozása"
+msgstr "Fénytérképek Ábrázolása"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -11595,7 +11610,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
-msgstr ""
+msgstr "VisualScript Node-ok Megkettőzése"
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
@@ -12072,7 +12087,6 @@ msgid "Using default boot splash image."
msgstr ""
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package short name."
msgstr "Érvénytelen rövid csomagnév."
@@ -12081,19 +12095,16 @@ msgid "Invalid package unique name."
msgstr "Érvénytelen egyedi csomagnév."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package publisher display name."
msgstr "Érvénytelen csomagközzétevő megjelenítendő neve."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Érvénytelen termékazonosító."
+msgstr "Érvénytelen termék GUID."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Érvénytelen közzétevői GUID."
+msgstr "Érvénytelen kiadó GUID."
#: platform/uwp/export/export.cpp
msgid "Invalid background color."
@@ -12157,6 +12168,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12327,14 +12346,12 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Geometria Elemzése…"
+msgstr "Geometria Előkészítése (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Geometria Elemzése…"
+msgstr "Környezet előkészítése"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12347,9 +12364,8 @@ msgid "Saving lightmaps"
msgstr "Fénytérképek Létrehozása"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Kész!"
+msgstr "Kész"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12417,11 +12433,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12630,9 +12641,8 @@ msgid "Must use a valid extension."
msgstr "Használjon érvényes kiterjesztést."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Illesztés Engedélyezése"
+msgstr "Rács kistérkép engedélyezése."
#: scene/gui/popup.cpp
msgid ""
@@ -12685,7 +12695,6 @@ msgid ""
msgstr ""
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid source for preview."
msgstr "Érvénytelen forrás az előnézethez."
diff --git a/editor/translations/id.po b/editor/translations/id.po
index 923b836555..e97e193d0f 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -11,7 +11,7 @@
# Khairul Hidayat <khairulcyber4rt@gmail.com>, 2016.
# Reza Hidayat Bayu Prabowo <rh.bayu.prabowo@gmail.com>, 2018, 2019.
# Romi Kusuma Bakti <romikusumab@gmail.com>, 2017, 2018.
-# Sofyan Sugianto <sofyanartem@gmail.com>, 2017-2018, 2019, 2020.
+# Sofyan Sugianto <sofyanartem@gmail.com>, 2017-2018, 2019, 2020, 2021.
# Tito <ijavadroid@gmail.com>, 2018.
# Tom My <tom.asadinawan@gmail.com>, 2017.
# yursan9 <rizal.sagi@gmail.com>, 2016.
@@ -24,16 +24,19 @@
# Modeus Darksono <garuga17@gmail.com>, 2019.
# Akhmad Zulfikar <azuldegratz@gmail.com>, 2020.
# Ade Fikri Malihuddin <ade.fm97@gmail.com>, 2020.
-# zephyroths <ridho.hikaru@gmail.com>, 2020.
+# zephyroths <ridho.hikaru@gmail.com>, 2020, 2021.
# Richard Urban <redasuio1@gmail.com>, 2020.
# yusuf afandi <afandi.yusuf.04@gmail.com>, 2020.
# Habib Rohman <revolusi147id@gmail.com>, 2020.
+# Hanz <hanzhaxors@gmail.com>, 2021.
+# Reza Almanda <rezaalmanda27@gmail.com>, 2021.
+# Naufal Adriansyah <naufaladrn90@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-13 22:59+0000\n"
-"Last-Translator: Habib Rohman <revolusi147id@gmail.com>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Naufal Adriansyah <naufaladrn90@gmail.com>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/"
"godot/id/>\n"
"Language: id\n"
@@ -41,13 +44,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr ""
-"Tipe argumen salah dalam menggunakan convert(), gunakan konstanta TYPE_*."
+msgstr "Tipe argumen salah dalam penggunaan convert(), gunakan konstan TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -57,7 +59,9 @@ msgstr "String dengan panjang 1 (karakter) yang diharapkan."
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Tidak cukup bytes untuk mendekode bytes, atau format tidak valid."
+msgstr ""
+"Tidak memiliki bytes yang cukup untuk merubah bytes ke nilai asal, atau "
+"format tidak valid."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -65,8 +69,7 @@ msgstr "Masukkan tidak sah %i (tidak diberikan) dalam ekspresi"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr ""
-"self tidak dapat digunakan karena tidak memiliki instance (tidak lolos)"
+msgstr "self tidak dapat digunakan karena instance adalah null"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -74,7 +77,7 @@ msgstr "operan salah untuk operator %s, %s dan %s."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr "Tipe index %s tidak valid untuk tipe dasar %s"
+msgstr "Tipe indeks %s tidak valid untuk tipe dasar %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
@@ -533,7 +536,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr "Hanya tampilkan track dari node terpilih dalam tree."
+msgstr "Hanya tampilkan track dari node terpilih dalam tree."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
@@ -596,11 +599,11 @@ msgstr "Hapus Pilihan"
#: editor/animation_track_editor.cpp
msgid "Go to Next Step"
-msgstr "Menuju Langkah Berikutnya"
+msgstr "Pergi ke Langkah Berikutnya"
#: editor/animation_track_editor.cpp
msgid "Go to Previous Step"
-msgstr "Menuju Langkah Sebelumnya"
+msgstr "Pergi ke Langkah Sebelumnya"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -671,7 +674,7 @@ msgstr "Pilih Trek untuk Disalin"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopy"
@@ -1052,14 +1055,14 @@ msgid "Owners Of:"
msgstr "Pemilik Dari:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Hapus berkas yang dipilih dari proyek? (tidak bisa dibatalkan)"
+msgstr ""
+"Hapus berkas yang dipilih dari proyek? (tidak bisa dibatalkan)\n"
+"Anda bisa menemukan berkas yang telah dihapus di tong sampah."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1068,7 +1071,8 @@ msgid ""
msgstr ""
"File-file yang telah dihapus diperlukan oleh resource lain agar mereka dapat "
"bekerja.\n"
-"Hapus saja? (tidak bisa dibatalkan/undo)"
+"Hapus saja? (tidak bisa dibatalkan)\n"
+"Anda bisa menemukan berkas yang telah dihapus di tong sampah."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1621,34 +1625,31 @@ msgstr ""
"Enabled'."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Platform target membutuhkan kompresi tekstur 'ETC' untuk GLES2. Aktifkan "
-"'Impor Lainnya' di Pengaturan Proyek."
+"Platform target membutuhkan kompresi tekstur 'PVRTC' untuk GLES2. Aktifkan "
+"'Impor Pvrtc' di Pengaturan Proyek."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Platform target membutuhkan kompresi tekstur 'ETC2' untuk GLES3. Aktifkan "
-"'Impor Lainnya 2' di Pengaturan Proyek."
+"Platform target membutuhkan kompresi tekstur 'ETC2' atau 'PVRTC' untuk "
+"GLES3. Aktifkan 'Impor Lainnya 2' atau 'Import Pvrtc' di Pengaturan Proyek."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"Platform target membutuhkan kompressi tekstur 'ETC' untuk mengembalikan "
+"Platform target membutuhkan kompressi tekstur 'PVRTC' untuk mengembalikan "
"driver ke GLES2. \n"
-"Aktifkan 'Impor Lainnya' di Pengaturan Proyek, atau matikan 'Driver Fallback "
+"Aktifkan 'Impor Pvrtc' di Pengaturan Proyek, atau matikan 'Driver Fallback "
"Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
@@ -1752,7 +1753,7 @@ msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
msgstr ""
-"Sudah ada profil '%s'. Hapus profil ini terlebih dahulu sebelum mengimpor, "
+"Sudah ada profil '%s'. Hapus profil ini terlebih dahulu sebelum mengimpor, "
"impor dibatalkan."
#: editor/editor_feature_profile.cpp
@@ -1877,8 +1878,8 @@ msgid "Open a File or Directory"
msgstr "Buka sebuah File atau Direktori"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Simpan"
@@ -2330,6 +2331,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Terjadi kesalahan ketika mencoba menyimpan layout editor.\n"
+"Pastikan jalur data pengguna editor dapat ditulis."
#: editor/editor_node.cpp
msgid ""
@@ -2337,13 +2340,15 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Penataan editor default telah dirubah.\n"
+"Untuk mengembalikan penataan editor default ke asalnya, gunakan opsi Hapus "
+"Penataan dan hapus Penataan Default."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Nama layout tidak ditemukan!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
msgstr "Mengembalikan semula layout default ke pengaturan-pengaturan awal."
@@ -2402,7 +2407,7 @@ msgstr "Tidak ada skena yang didefinisikan untuk dijalankan."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Simpan skena sebelum menjalankan..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2481,7 +2486,6 @@ msgid "Reload Saved Scene"
msgstr "Muat ulang scene yang sudah disimpan"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
@@ -2548,9 +2552,9 @@ msgstr ""
"gagal."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
-"Tidak dapat mencari bidang script untuk addon plugin pada: 'res://addons/%s'."
+"Tidak dapat mencari bidang skrip untuk addon plugin pada: 'res://addons/%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2849,17 +2853,15 @@ msgstr ""
"file yang bisa dieksekusi mencoba untuk terhubung ke IP komputer ini, "
"sehingga proyek yang sedang berajalan dapat didebug.\n"
"Pilihan ini dimaksudkan untuk digunakan sebagai cara men-debug jarak jauh "
-"(biasanya menggunakan perangkat selular).\n"
+"(biasanya menggunakan perangkat selular).\n"
"Kamu tidak perlu mengaktifkan ini jika menggunakan GDScript debugger secara "
"lokal."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "Deploy Kecil dengan Jaringan FS"
+msgstr "Deploy Kecil dengan Jaringan Berkas"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2868,9 +2870,9 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"Ketika opsi ini aktif, ekspor atau deploy akan menghasilkan minimal "
-"executable.\n"
-"Berkas sistem akan tersedia dari proyek dari editor melalui jaringan.\n"
+"Ketika opsi ini aktif, menggunakan 'one-click deploy' hanya akan mengekspor "
+"executable tanpa data proyek.\n"
+"Berkas sistem akan tersedia dari proyek oleh editor melalui jaringan.\n"
"Pada Android, deploy akan menggunakan kabel USB untuk performa yang lebih "
"cepat. Opsi ini mempercepat pengujian dengan jejak kaki yang besar."
@@ -2879,34 +2881,29 @@ msgid "Visible Collision Shapes"
msgstr "Collision Shapes Terlihat"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
"Collision shapes dan raycast nodes (untuk 2D dan 3D) akan terlihat pada saat "
-"permainan berjalan jika opsi ini aktif."
+"proyek berjalan jika opsi ini aktif."
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "Navigasi Terlihat"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"Navigasi meshes dan poligon akan terlihat saat game berjalan jika opsi ini "
-"aktif."
+"Navigasi dan poligon akan terlihat saat game berjalan jika opsi ini aktif."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
msgstr "Sinkronkan Perubahan Skena"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any changes made to the scene in the editor "
"will be replicated in the running project.\n"
@@ -2914,17 +2911,15 @@ msgid ""
"filesystem option is enabled."
msgstr ""
"Ketika opsi ini aktif, perubahan yang dibuat pada skena melalui editor akan "
-"direplika pada gim yang sedang berjalan.\n"
+"direplika pada proyek yang sedang berjalan.\n"
"Ketika penggunaan remote pada sebuah perangkat, akan lebih efisien dengan "
-"berkas sistem jaringan."
+"opsi berkas sistem jaringan."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
-msgstr "Sinkronkan Perubahan Script"
+msgstr "Sinkronkan Perubahan skrip"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
@@ -2933,8 +2928,8 @@ msgid ""
msgstr ""
"Ketika opsi ini aktif, perubahan script yang tersimpan akan di muat kembali "
"pada permainan yang sedang berjalan.\n"
-"Ketika penggunaan remote pada sebuah perngakat, akan lebih efisien jika "
-"jaringan filesystem."
+"Ketika penggunaan remote pada sebuah perangakat, akan lebih efisien dengan "
+"opsi jaringan berkas-berkas."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2989,14 +2984,6 @@ msgid "Help"
msgstr "Bantuan"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Cari"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Dokumentasi"
@@ -3161,6 +3148,24 @@ msgid "Open & Run a Script"
msgstr "Buka & Jalankan Skrip"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Berkas berikut lebih baru dalam disk.\n"
+"Aksi apa yang ingin diambil?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Muat Ulang"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Simpan Ulang"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Turunan Baru"
@@ -3372,7 +3377,7 @@ msgstr "Jadikan Unik"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Tempel"
@@ -3410,7 +3415,6 @@ msgid "Add Key/Value Pair"
msgstr "Tambahkan pasangan Key/Value"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
@@ -3444,11 +3448,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Apakah anda lupa dengan fungsi '_run' ?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Tahan Ctrl untuk meletakkan Getter. Tahan Shift untuk meletakkan generic "
-"signature."
+"Tahan Ctrl untuk membulatkan bilangan. Tahan Shift untuk meletakkan bilangan "
+"yang lebih presisi."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3688,6 +3691,13 @@ msgstr ""
"manual."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Mengimpor telah didisable untuk berkas ini, jadi itu tidak bisa dibuka untuk "
+"disunting."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Tidak bisa memindah/mengubah nama resource root."
@@ -3732,6 +3742,11 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"file dan/atau berkas-berkas berikut mempunyai konflik di '%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Apakah Anda ingin melanjutkan (overwrite)?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3763,7 +3778,7 @@ msgstr "Buka Skena"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr "Instansi"
+msgstr "hal"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
@@ -3812,9 +3827,8 @@ msgid "Duplicate..."
msgstr "Gandakan..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "Pindahkan Autoload"
+msgstr "Pindahkan ke tong sampah"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3925,19 +3939,16 @@ msgid "Searching..."
msgstr "Mencari..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
msgstr "Ditemukan %d kecocokan."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
msgstr "Ditemukan %d kecocokan."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "Ditemukan %d kecocokan."
+msgstr "Ditemukan %d kecocokan dalam %d berkas."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4068,11 +4079,28 @@ msgstr "Kesalahan saat menjalankan skrip post-import:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Apakan Anda mengembalikan objek berturunan Node dalam method `post_import()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
msgstr "Menyimpan..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Pilih Importir"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importir:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Kembalikan ke Nilai Baku"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Simpan Berkas (Tanpa Impor)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Berkas"
@@ -5036,8 +5064,8 @@ msgid "Got:"
msgstr "Yang Didapat:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Gagal mengecek hash sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Gagal mengecek hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5140,7 +5168,6 @@ msgid "Sort:"
msgstr "Sortir:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategori:"
@@ -5169,14 +5196,12 @@ msgid "Assets ZIP File"
msgstr "Berkas Aset ZIP"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
"Tidak dapat menentukan lokasi penyimpanan untuk gambar lightmap.\n"
-"Simpan skena Anda (untuk gambar yang akan disimpan di direktori yang sama), "
-"atau pilih lokasi penyimpanan dari properti BakedLightmap."
+"Simpan skena Anda dan coba lagi."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5193,26 +5218,30 @@ msgstr "Gagal membuat gambar lightmap, pastikan path dapat ditulis."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
msgstr ""
+"Gagal menentukan ukuran lightmap. Ukuran lightmap maksimumnya terlalu kecil?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"Banyak mesh tak valid. Pastikan nilai kanal UV2 diisi dalam rentang wilayah "
+"persegi [0.0,1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"Editor Godot di-build tanpa dukungan ray tracing, sehingga lightmaps tidak "
+"dapat di-bake."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "Panggang Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Pilih berkas templat"
+msgstr "Pilih berkas lightmap bake:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5281,50 +5310,43 @@ msgstr "Buat Panduan Horisontal dan Vertikal"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Atur Offset Pivot CanvasItem \"%s\" ke (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Putar CanvasItem"
+msgstr "Putar %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Putar CanvasItem"
+msgstr "Putar CanvasItem \"%s\" menjadi %d derajat"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan Anchor CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Skalakan Node2D \"%s\" menjadi (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Ubah ukuran Control \"%s\" menjadi (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Skalakan CanvasItem"
+msgstr "Skalakan %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Skalakan CanvasItem"
+msgstr "Skalakan CanvasItem \"%s\" menjadi (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan CanvasItem \"%s\" ke (%d,%d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5659,7 +5681,7 @@ msgstr "Tampilkan Tulang-tulang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
-msgstr "Buat Tulang Kustom(satu/lebih) dari Node(satu/lebih)"
+msgstr "Buat Tulang Kustom(satu/lebih) dari Node(satu/lebih)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
@@ -6317,9 +6339,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "Hanya dapat mengatur titik ke dalam material proses ParticlesMaterial"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Konversikan menjadi CPUParticles"
+msgstr "Konversikan menjadi CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6608,18 +6629,16 @@ msgid "Move Points"
msgstr "Geser Titik"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Geser: Putar"
+msgstr "Comand: Putar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Geser Semua"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: Skala"
+msgstr "Shift+Command: Skala"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6666,14 +6685,12 @@ msgid "Radius:"
msgstr "Radius:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Buat Poligon & UV"
+msgstr "Salin Polygon ke UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Konversikan menjadi Polygon2D"
+msgstr "Salin UV ke Polygon"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -6975,6 +6992,14 @@ msgstr "Tutup Dokumentasi"
msgid "Run"
msgstr "Jalankan"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Cari"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Masuki"
@@ -7028,16 +7053,6 @@ msgstr ""
"Berkas berikut lebih baru dalam diska.\n"
"Aksi apa yang ingin diambil?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Muat Ulang"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Simpan Ulang"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Pengawakutu"
@@ -7070,9 +7085,8 @@ msgstr ""
"'%s' ke node '%s'."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(abaikan)"
+msgstr "[abaikan]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -7135,8 +7149,8 @@ msgstr "Breakpoint"
msgid "Go To"
msgstr "Pergi Ke"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Potong"
@@ -7360,9 +7374,8 @@ msgid "Yaw"
msgstr "Oleng"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Ukuran: "
+msgstr "Ukuran"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7546,6 +7559,11 @@ msgstr "Rotasi Tampilan Terkunci"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7564,6 +7582,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Klik untuk mengatur visibilitas.\n"
+"\n"
+"Mata terbuka: Gizmo tampak.\n"
+"Mata tertutup: Gizmo disembunyikan.\n"
+"Mata setengah terbuka: Gizmo juga tampak melalui permukaan tidak tembus "
+"pandang (\"sinar-x\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7903,9 +7927,8 @@ msgid "New Animation"
msgstr "Animasi Baru"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Speed:"
-msgstr "Kecepatan (FPS):"
+msgstr "Kecepatan:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
@@ -8223,13 +8246,12 @@ msgid "Paint Tile"
msgstr "Cat Tile"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
"Shift + Klik Kiri: Menggambar Garis\n"
-"Shift + Ctrl + Klik Kiri: Cat Persegi Panjang"
+"Shift + Command + Klik Kiri: Cat Persegi Panjang"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8384,23 +8406,20 @@ msgid "Create a new rectangle."
msgstr "Buat persegi panjang baru."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Cat Persegi Panjang"
+msgstr "Persegi Panjang Baru"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Buat poligon baru."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Geser Poligon"
+msgstr "Poligon Baru"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Hapus yang Dipilih"
+msgstr "Hapus Shape yang Dipilih"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8765,7 +8784,6 @@ msgid "Add Node to Visual Shader"
msgstr "Tambah Node ke Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
msgstr "Node Dipindahkan"
@@ -8787,9 +8805,8 @@ msgid "Visual Shader Input Type Changed"
msgstr "Tipe Input Visual Shader Berubah"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "Tetapkan Nama Uniform"
+msgstr "Nama UniformRef diubah"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -9214,7 +9231,7 @@ msgstr "Mengembalikan nilai tangen dari parameter."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr "Mengembalikan nilai hiperbolik tangen dari parameter."
+msgstr "Mengembalikan nilai hiperbolik tangen dari parameter."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
@@ -9511,7 +9528,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "A reference to an existing uniform."
-msgstr ""
+msgstr "Referensi ke uniform yang ada."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Scalar derivative function."
@@ -9686,7 +9703,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr "Fitur"
+msgstr "Fitur-fitur"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -9881,7 +9898,7 @@ msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "Tidak didukung oleh driver GPU Anda."
#: editor/project_manager.cpp
msgid ""
@@ -10058,6 +10075,10 @@ msgid "Projects"
msgstr "Proyek"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Memuat, tunggu sejenak..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Terakhir Diubah"
@@ -10362,7 +10383,7 @@ msgstr "Aksi"
#: editor/project_settings_editor.cpp
msgid "Deadzone"
-msgstr "Deadzone"
+msgstr "Zona tidak aktif"
#: editor/project_settings_editor.cpp
msgid "Device:"
@@ -10428,6 +10449,10 @@ msgstr "Muat Otomatis"
msgid "Plugins"
msgstr "Pengaya"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Impor Nilai Baku"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Prasetel..."
@@ -10489,19 +10514,16 @@ msgid "Batch Rename"
msgstr "Ubah Nama Massal"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Ganti: "
+msgstr "Ganti:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Prefix:"
-msgstr "Awalan"
+msgstr "Awalan:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Suffix:"
-msgstr "Akhiran"
+msgstr "Akhiran:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10548,9 +10570,9 @@ msgid "Per-level Counter"
msgstr "Penghitung per Level"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "Jika diatur, penghitung akan dimulai ulang untuk setiap grup node anak"
+msgstr ""
+"Jika diatur, penghitung akan dimulai ulang untuk setiap grup node anak."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
@@ -10609,9 +10631,8 @@ msgid "Reset"
msgstr "Reset"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Kesalahan Ekspresi Reguler"
+msgstr "Kesalahan Ekspresi Reguler:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10682,9 +10703,16 @@ msgid "Instance Child Scene"
msgstr "Instansi Skena Anak"
#: editor/scene_tree_dock.cpp
-#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "Tidak dapat menempelkan node akar ke dalam skena yang sama."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Tempel Node"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
-msgstr "Lampirkan Skrip"
+msgstr "Lepas Skrip"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10721,9 +10749,8 @@ msgid "Make node as Root"
msgstr "Jadikan node sebagai Dasar"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Hapus node \"%s\" dan anak-anaknya?"
+msgstr "Hapus %d node dan semua anaknya?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -10813,6 +10840,10 @@ msgid "Attach Script"
msgstr "Lampirkan Skrip"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Potong Node"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Hapus Node"
@@ -10857,14 +10888,14 @@ msgid "Open Documentation"
msgstr "Buka Dokumentasi"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid ""
"Cannot attach a script: there are no languages registered.\n"
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
-"Tidak dapat melampirkan skrip: tidak ada bahasa yang terdaftar.\n"
-"Ini mungkin karena editor ini dibuat dengan semua modul bahasa dinonaktifkan."
+"Tidak dapat melampirkan skrip: tidak ada bahasa terdaftar.\n"
+"Ini mungkin karena editor ini di-build dengan semua modul bahasa "
+"dinonaktifkan."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10915,20 +10946,25 @@ msgstr ""
"akar."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "Lampirkan skrip baru atau yang sudah ada untuk node yang dipilih."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Bersihkan skrip untuk node yang dipilih."
+msgstr "Lepas skrip dari node yang dipilih."
#: editor/scene_tree_dock.cpp
msgid "Remote"
msgstr "Remot"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokal"
@@ -11623,36 +11659,31 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "Mulai Bake"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "Menyiapkan struktur data"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "Buat AABB"
+msgstr "Ciptakan buffer"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Arah"
+msgstr "PEncahayaan langsung"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "Indentasi Kanan"
+msgstr "Pencahayaan tak langsung"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Pasca Proses"
+msgstr "Pasca pemrosesan"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Plotting Lights:"
+msgstr "Memetakan lightmap"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12168,7 +12199,7 @@ msgstr "Pilih perangkat pada daftar"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr ""
+msgstr "Tak dapat menemukan perkakas 'apksigner'."
#: platform/android/export/export.cpp
msgid ""
@@ -12185,48 +12216,37 @@ msgstr ""
"prasetel proyek."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr ""
-"Berkas debug keystore belum dikonfigurasi dalam Pengaturan Editor maupun di "
-"prasetel proyek."
+msgstr "Berkas keystore rilis belum dikonfigurasi di prasetel ekspor."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+msgstr "Lokasi Android SDK yang valid dibutuhkan di Pengaturan Editor."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+msgstr "Lokasi Android SDK tidak valid di Pengaturan Editor."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "Direktori 'platform-tools' tidak ada!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Tidak dapat menemukan perintah adb di Android SDK platform-tools."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+"Silakan cek direktori Android SDK yang diisikan dalam Pengaturan Editor."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "Direktori 'build-tools' tidak ditemukan!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Tidak dapat menemukan apksigner dalam Android SDK build-tools."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12241,42 +12261,51 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Modul \"GodotPaymentV3\" tidak valid yang dimasukkan dalam pengaturan proyek "
+"\"android/modules\" (diubah di Godot 3.2.2)\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "\"Gunakan Build Custom\" harus diaktifkan untuk menggunakan plugin."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Derajat Kebebasan\" hanya valid ketika \"Mode Xr\" bernilai \"Occulus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Pelacakan Tangan\" hanya valid ketika \"Mode Xr\" bernilai \"Oculus Mobile "
+"VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" hanya valid ketika \"Mode Xr\" bernilai \"Oculus Mobile "
+"VR\"."
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
msgstr ""
+"\"Expor AAB\" hanya bisa valid ketika \"Gunakan Build Custom\" diaktifkan."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
-msgstr ""
+msgstr "Nama berkas tak valid! Android App Bundle memerlukan ekstensi *.aab ."
#: platform/android/export/export.cpp
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "Ekspansi APK tidak kompatibel dengan Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "Nama berkas tidak valid! APK Android memerlukan ekstensi *.apk ."
#: platform/android/export/export.cpp
msgid ""
@@ -12312,13 +12341,15 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Moving output"
-msgstr ""
+msgstr "Memindahkan keluaran"
#: platform/android/export/export.cpp
msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"Tidak dapat menyalin dan mengubah nama berkas ekspor, cek direktori proyek "
+"gradle untuk hasilnya."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12473,6 +12504,18 @@ msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
"Sebuah CollisionPolygon2D yang kosong tidak memiliki efek pada collision."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Poligon tidak valid. Minimal 3 titik dibutuhkan untuk mode pembangunan "
+"'Solid'."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Poligon tidak valid. Minimal 2 titik dibutuhkan untuk mode pembangunan "
+"'Segmen\"."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12493,14 +12536,13 @@ msgstr ""
"ciptakan resource shape untuknya!"
#: scene/2d/collision_shape_2d.cpp
-#, fuzzy
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
-"Bentuk Polygon-based tidak dimaksudkan untuk digunakan atau diedit secara "
-"langsung melalui node CollisionShape2D. Silakan gunakan node "
-"CollisionPolygon2D sebagai gantinya."
+"Bentuk Polygon-based tidak dimaksudkan untuk digunakan atau diedit langsung "
+"melalui node CollisionShape2D. Gunakan node CollisionPolygon2D sebagai "
+"gantinya."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
@@ -12512,23 +12554,23 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Node A dan Node B harus berupa PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Node A harus PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Node B harus PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "Persendian tidak terkoneksi dengan 2 PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody2D yang berbeda"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12687,32 +12729,27 @@ msgstr "ARVROrigin membutuhkan node anak ARVRCamera."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "Mencari mesh dan cahaya"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Mengurai Geometri..."
+msgstr "Menyiapkan geometri (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Tampilkan Lingkungan"
+msgstr "Menyiapkan lingkungan"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "Membuat Pemetaan Cahaya"
+msgstr "Membuat capture"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Membuat Pemetaan Cahaya"
+msgstr "Menyimpan lightmap"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Selesai!"
+msgstr "Selesai"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12720,6 +12757,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"Node ini tidak memiliki shape, jadi tidak bisa bertabrakan atau berinteraksi "
+"dengan objek lain.\n"
+"Pertimbangkan untuk menambah CollisionShape atau CollisionPolygon sebagai "
+"anak untuk mendefinisikan shape-nya."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12760,22 +12801,26 @@ msgid ""
"Plane shapes don't work well and will be removed in future versions. Please "
"don't use them."
msgstr ""
+"Bentuk plane tidak bekerja baik dan akan dihapus dalam versi mendatang. "
+"Mohon untuk tidak menggunakannya."
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape tidak mendukung RigidBody dengan mode selain statis."
#: scene/3d/cpu_particles.cpp
-#, fuzzy
msgid "Nothing is visible because no mesh has been assigned."
-msgstr "Tidak ada yang tampak karena tidak ada mesh yang ditetapkan."
+msgstr "Tidak ada yang tampil karena tidak ada mesh yang ditetapkan."
#: scene/3d/cpu_particles.cpp
msgid ""
"CPUParticles animation requires the usage of a SpatialMaterial whose "
"Billboard Mode is set to \"Particle Billboard\"."
msgstr ""
+"Animasi CPUParticle membutuhkan penggunaan SpatialMaterial yang Mode "
+"Billboard nya diatur ke \"Particle Billboard\"."
#: scene/3d/gi_probe.cpp
msgid "Plotting Meshes"
@@ -12793,14 +12838,10 @@ msgstr ""
"GIProbes tidak didukung oleh driver video GLES2.\n"
"Gunakan BakedLightmap sebagai gantinya."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
+"SpotLight dengan sudut lebih dari 90 derajat tidak dapat memberikan bayangan."
#: scene/3d/navigation_mesh.cpp
msgid "A NavigationMesh resource must be set or created for this node to work."
@@ -12822,17 +12863,24 @@ msgid ""
"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
"\" option for this purpose."
msgstr ""
+"Partikel berbasis GPU tidak didukung oleh driver video GLES2.\n"
+"Gunakan CPUParticles saja. Anda dapat menggunakan opsi \"Konversikan ke "
+"CPUParticles\" untuk ini."
#: scene/3d/particles.cpp
msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr ""
+"Tidak ada yang ditampilkan karena mesh tidak ditetapkan untuk menggambar "
+"lintasan."
#: scene/3d/particles.cpp
msgid ""
"Particles animation requires the usage of a SpatialMaterial whose Billboard "
"Mode is set to \"Particle Billboard\"."
msgstr ""
+"Animasi Partikel memerlukan penggunaan SpatialMaterial dengan Mode Billboard "
+"\"Particle Billboard\"."
#: scene/3d/path.cpp
msgid "PathFollow only works when set as a child of a Path node."
@@ -12854,39 +12902,41 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Perubahan ukuran RigidBody (dalam mode karakter atau rigid) akan ditimpa "
+"oleh mesin fisika ketika dijalankan.\n"
+"Ubah ukuran dari \"collision shape\"-anaknya saja."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "Node A harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "Node B harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
-msgstr ""
+msgstr "Persendian tidak terkoneksi dengan PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be different PhysicsBodies"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody yang berbeda"
#: scene/3d/remote_transform.cpp
-#, fuzzy
msgid ""
"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
"derived node to work."
msgstr ""
-"Properti path harus menunjuk ke sebuah node Particles2D yang sah agar "
-"bekerja."
+"Properti \"Remote Path\" harus menunjuk ke Spatial atau turunannya yang "
+"valid agar bekerja."
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
-msgstr ""
+msgstr "Body ini akan diabaikan hingga Anda mengatur mesh-nya."
#: scene/3d/soft_body.cpp
msgid ""
@@ -12894,6 +12944,8 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Perubahan ukuran SoftBody akan ditimpa oleh mesin fisika ketika dijalankan.\n"
+"Ubah ukurannya melalui \"collision shape\"-anaknya saja."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -12908,6 +12960,8 @@ msgid ""
"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
"it as a child of a VehicleBody."
msgstr ""
+"VehicleWheel berfungsi menyediakan sistem roda ke VehicleBody. Gunakan itu "
+"sebagai anak dari VehicleBody."
#: scene/3d/world_environment.cpp
msgid ""
@@ -13038,9 +13092,8 @@ msgid "Must use a valid extension."
msgstr "Harus menggunakan ekstensi yang sah."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Aktifkan Pengancingan"
+msgstr "Aktifkan peta mini grid."
#: scene/gui/popup.cpp
msgid ""
@@ -13103,6 +13156,8 @@ msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
+"Porta sampler terhubung tapi tidak digunakan. Pertimbangkan untuk mengubah "
+"sumbernya ke 'SamplerPort'."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 8ab4fd9ec3..fd9e23d91b 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -659,7 +659,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1835,8 +1835,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2472,7 +2472,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2865,14 +2865,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3027,6 +3019,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3230,7 +3238,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3534,6 +3542,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3915,6 +3928,23 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Afrita val"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4876,7 +4906,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4980,7 +5010,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6763,6 +6792,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6814,16 +6851,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6916,8 +6943,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7324,6 +7351,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9707,6 +9739,10 @@ msgid "Projects"
msgstr "Verkefna Stjóri"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10069,6 +10105,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10313,6 +10353,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Tvíteknir lyklar"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10437,6 +10486,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Tvíteknir lyklar"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10544,6 +10598,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12026,6 +12087,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12281,11 +12350,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index 3bc0ebac67..d1b39155c9 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -29,8 +29,8 @@
# Giuseppe Guerra <me@nyodev.xyz>, 2019.
# RHC <rhc.throwaway@gmail.com>, 2019, 2020.
# Antonio Giungato <antonio.giungato@gmail.com>, 2019, 2020.
-# Marco Galli <mrcgll98@gmail.com>, 2019, 2020.
-# MassiminoilTrace <omino.gis@gmail.com>, 2019, 2020.
+# Marco Galli <mrcgll98@gmail.com>, 2019, 2020, 2021.
+# MassiminoilTrace <omino.gis@gmail.com>, 2019, 2020, 2021.
# MARCO BANFI <mbanfi@gmail.com>, 2019.
# Marco <rodomar705@gmail.com>, 2019.
# Davide Giuliano <davidegiuliano00@gmail.com>, 2019.
@@ -50,17 +50,19 @@
# J. Lavoie <j.lavoie@net-c.ca>, 2020.
# Andrea Terenziani <andrea.terenziani.at@gmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
-# riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020.
+# riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020, 2021.
# Lorenzo Asolan <brixiumx@gmail.com>, 2020.
# Lorenzo Cerqua <lorenzocerqua@tutanota.com>, 2020, 2021.
# Federico Manzella <ferdiu.manzella@gmail.com>, 2020.
# Ziv D <wizdavid@gmail.com>, 2020.
+# Riteo Siuga <lorenzocerqua@tutanota.com>, 2021.
+# Alessandro Mandelli <mandelli.alessandro@ngi.it>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-01 20:53+0000\n"
-"Last-Translator: Lorenzo Cerqua <lorenzocerqua@tutanota.com>\n"
+"PO-Revision-Date: 2021-04-16 07:52+0000\n"
+"Last-Translator: Marco Galli <mrcgll98@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -68,7 +70,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -191,7 +193,7 @@ msgstr "Elimina delle chiavi d'animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Time"
-msgstr "Cambia Intervallo Fotogramma Principale Animazione"
+msgstr "Cambia il tempo di un fotogramma chiave"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
@@ -203,7 +205,7 @@ msgstr "Cambia la trasformazione di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr "Cambia Valore Fotogramma Principale Animazione"
+msgstr "Cambia il valore del fotogramma chiave di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
@@ -211,32 +213,32 @@ msgstr "Cambia la chiamata di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr "Cambia Multipli Intervalli Fotogramma Principale Animazione"
+msgstr "Cambia il tempo di più fotogrammi chiave"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
-msgstr "Cambi Multipli Transizione Animazione"
+msgstr "Cambia la transizione di più animazioni"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transform"
-msgstr "Cambi Multipli Trasformazione Animazione"
+msgstr "Cambia le trasformazioni di più animazioni"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
-msgstr "Cambia Multipli Valori Fotogramma Principale Animazione"
+msgstr "Cambia il valore di più fotogrammi chiave di un'Animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
-msgstr "Cambi Multipli Chiamata Animazione"
+msgstr "Cambia la chiamata di metodo di più animazioni"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
-msgstr "Cambia Lunghezza Animazione"
+msgstr "Cambia la durata dell'animazione"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr "Cambia Loop Animazione"
+msgstr "Commuta ciclicità animazione"
#: editor/animation_track_editor.cpp
msgid "Property Track"
@@ -293,7 +295,7 @@ msgstr "Clip animazione:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr "Cambia il percorso della traccia"
+msgstr "Cambia Percorso Traccia"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
@@ -309,7 +311,7 @@ msgstr "Modalità d'interpolazione"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr "Modalità Ciclo ad Anello (interpola la fine con l'inizio a ciclo)"
+msgstr "Modalità ciclo ad anello (interpola la fine con l'inizio del ciclo)"
#: editor/animation_track_editor.cpp
msgid "Remove this track."
@@ -333,7 +335,7 @@ msgstr "Discreta"
#: editor/animation_track_editor.cpp
msgid "Trigger"
-msgstr "Attivatore"
+msgstr "Attivazione"
#: editor/animation_track_editor.cpp
msgid "Capture"
@@ -354,24 +356,24 @@ msgstr "Cubica"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
-msgstr "Blocca Interpolazione Ciclo"
+msgstr "Blocca l'interpolazione d'un ciclo"
#: editor/animation_track_editor.cpp
msgid "Wrap Loop Interp"
-msgstr "Avvolgi Interpolazione Ciclo"
+msgstr "Continua l'interpolazione d'un ciclo"
#: editor/animation_track_editor.cpp
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key"
-msgstr "Inserisci Fotogramma Chiave"
+msgstr "Inserisci un fotogramma chiave"
#: editor/animation_track_editor.cpp
msgid "Duplicate Key(s)"
-msgstr "Duplica Fotogrammi Chiave Selezionati"
+msgstr "Duplica i fotogrammi chiave selezionati"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
-msgstr "Elimina Fotogrammi Chiave Selezionati"
+msgstr "Elimina i fotogrammi chiave selezionati"
#: editor/animation_track_editor.cpp
msgid "Change Animation Update Mode"
@@ -383,15 +385,15 @@ msgstr "Cambia la modalità d'interpolazione di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr "Cambia la modalità del ciclo di un'animazione"
+msgstr "Cambia Modalità Loop Animazione"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
-msgstr "Rimuovi la traccia di un'animazione"
+msgstr "Rimuovi una traccia d'animazione"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "Crea NUOVA traccia per %s ed inserire fotogramma chiave?"
+msgstr "Creare una NUOVA traccia per %s e inserire la chiave?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
@@ -472,10 +474,8 @@ msgid "Not possible to add a new track without a root"
msgstr "Non è possibile aggiungere una nuova traccia senza un nodo radice"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr ""
-"Traccia non valida per una curva di Bézier (nessuna sotto-proprietà adatta)"
+msgstr "Traccia non valida per Bezier (nessuna sotto-proprietà valida)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
@@ -498,11 +498,10 @@ msgid "Add Track Key"
msgstr "Aggiungi una chiave a una traccia"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Track path is invalid, so can't add a method key."
msgstr ""
-"La traccia non è valida, quindi non è possibile aggiungere una chiave di "
-"chiamata di metodo."
+"La traccia non è valida, quindi, non è stato possibile aggiungere una chiave "
+"chiamata metodo."
#: editor/animation_track_editor.cpp
msgid "Add Method Track Key"
@@ -522,11 +521,11 @@ msgstr "Gli appunti sono vuoti"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
-msgstr "Incolla delle tracce"
+msgstr "Incolla Tracce"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
-msgstr "Scala delle chiavi d'animazione"
+msgstr "Scala Chiavi Animazione"
#: editor/animation_track_editor.cpp
msgid ""
@@ -536,7 +535,6 @@ msgstr ""
"si tratta di una singola traccia."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid ""
"This animation belongs to an imported scene, so changes to imported tracks "
"will not be saved.\n"
@@ -548,14 +546,14 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
-"Quest'animazione appartiene a una scena importata, eventuali modifiche fatte "
-"alle tracce importate non verranno salvate.\n"
+"Questa animazione appartiene ad una scena importata, quindi i cambiamenti "
+"alle tracce importate non saranno salvate.\n"
"\n"
-"Per abilitare la possibilità di aggiungere ulteriori tracce, andare nelle "
-"impostazioni d'importazione della scena, impostare\n"
-"\"Animation > Storage\" su \"Files\", attivare \"Animation > Keep Custom "
-"Tracks\" e infine reimportare la scena.\n"
-"Altrimenti, usare una preimpostazione che importi le animazioni in file "
+"Per abilitare l'aggiunta di tracce personalizzate, naviga alle impostazioni "
+"d'importazione della scena ed imposta\n"
+"\"Animation > Storage\" a \"Files\", abilita \"Animation > Keep Custom Tracks"
+"\", e poi re-importa.\n"
+"In alternativa, usa un preset d'importo che importa le animazioni da file "
"separati."
#: editor/animation_track_editor.cpp
@@ -622,23 +620,20 @@ msgid "Duplicate Selection"
msgstr "Duplica la selezione"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Duplicate Transposed"
-msgstr "Duplica trasposto"
+msgstr "Duplica Trasposto"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
msgstr "Elimina la selezione"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Go to Next Step"
-msgstr "Va' al passo successivo"
+msgstr "Vai allo Step Successivo"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Go to Previous Step"
-msgstr "Va' al passo precedente"
+msgstr "Vai allo Step Precedente"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -662,15 +657,15 @@ msgstr "Ottimizzatore anim."
#: editor/animation_track_editor.cpp
msgid "Max. Linear Error:"
-msgstr "Max errore lineare:"
+msgstr "Max Errore Lineare:"
#: editor/animation_track_editor.cpp
msgid "Max. Angular Error:"
-msgstr "Max errore angolare:"
+msgstr "Max Errore Angolare:"
#: editor/animation_track_editor.cpp
msgid "Max Optimizable Angle:"
-msgstr "Max angolo ottimizzabile:"
+msgstr "Max Angolo Ottimizzabile:"
#: editor/animation_track_editor.cpp
msgid "Optimize"
@@ -709,47 +704,45 @@ msgstr "Seleziona le tracce da copiare"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copia"
#: editor/animation_track_editor.cpp
msgid "Select All/None"
-msgstr "Seleziona tutto/nulla"
+msgstr "De/Seleziona Tutto"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
msgstr "Aggiungi audio in una traccia di riproduzione audio"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Change Audio Track Clip Start Offset"
-msgstr "Cambia lo scostamento dell'inizio della traccia audio"
+msgstr "Cambia Offset Inizio Clip Traccia Audio"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Change Audio Track Clip End Offset"
-msgstr "Cambia lo scostamento della fine della traccia audio"
+msgstr "Cambia Offset Fine Clip Traccia Audio"
#: editor/array_property_edit.cpp
msgid "Resize Array"
-msgstr "Ridimensiona lista"
+msgstr "Ridimensiona Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value Type"
-msgstr "Cambia il tipo del valore della lista"
+msgstr "Cambia Tipo Valore Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value"
-msgstr "Cambia il valore della lista"
+msgstr "Cambia Valore Array"
#: editor/code_editor.cpp
msgid "Go to Line"
-msgstr "Vai alla linea"
+msgstr "Vai alla Linea"
#: editor/code_editor.cpp
msgid "Line Number:"
-msgstr "Numero della linea:"
+msgstr "Numero Linea:"
#: editor/code_editor.cpp
msgid "%d replaced."
@@ -765,11 +758,11 @@ msgstr "%d corrispondenze."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
-msgstr "Distingui le maiuscole"
+msgstr "Distingui Maiuscole"
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Whole Words"
-msgstr "Parole intere"
+msgstr "Parole Intere"
#: editor/code_editor.cpp
msgid "Replace"
@@ -777,11 +770,11 @@ msgstr "Sostituisci"
#: editor/code_editor.cpp
msgid "Replace All"
-msgstr "Rimpiazza tutti"
+msgstr "Rimpiazza Tutti"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr "Solo selezione"
+msgstr "Solo Selezione"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -790,7 +783,7 @@ msgstr "Standard"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr "Commuta pannello degli script"
+msgstr "Toggle Pannello Script"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -806,23 +799,23 @@ msgstr "Rimpicciolisci"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr "Resetta ingrandimento"
+msgstr "Reimposta ingrandimento"
#: editor/code_editor.cpp
msgid "Warnings"
-msgstr "Avvertenze"
+msgstr "Avvisi"
#: editor/code_editor.cpp
msgid "Line and column numbers."
-msgstr "Numeri di riga e colonna."
+msgstr "Numeri di riga e di colonna."
#: editor/connections_dialog.cpp
msgid "Method in target node must be specified."
-msgstr "Il metodo del nodo designato deve essere specificato."
+msgstr "Il metodo del nodo selezionato deve essere specificato."
#: editor/connections_dialog.cpp
msgid "Method name must be a valid identifier."
-msgstr "Il nome del metodo dev'essere un identificatore valido."
+msgstr "Il nome del metodo deve essere un identificatore valido."
#: editor/connections_dialog.cpp
msgid ""
@@ -1166,7 +1159,7 @@ msgstr "Possiede"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr "Risorse non Possedute Esplicitamente:"
+msgstr "Risorse senza proprietario esplicito:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
@@ -1897,7 +1890,7 @@ msgstr "Aggiorna"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr "Tutti i risconosciuti"
+msgstr "Tutti i formati riconosciuti"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
@@ -1920,8 +1913,8 @@ msgid "Open a File or Directory"
msgstr "Apri un file o una cartella"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Salva"
@@ -2014,7 +2007,7 @@ msgstr "File:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr "Scansiona sorgenti"
+msgstr "Scansiona i sorgenti"
#: editor/editor_file_system.cpp
msgid ""
@@ -2071,7 +2064,7 @@ msgstr "Metodi"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Proprietà Tema"
+msgstr "Proprietà del tema"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2083,7 +2076,7 @@ msgstr "Costanti"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Descrizioni Proprietà"
+msgstr "Descrizioni delle proprietà"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2099,7 +2092,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "Descrizioni Metodo"
+msgstr "Descrizioni del metodo"
#: editor/editor_help.cpp
msgid ""
@@ -2386,8 +2379,8 @@ msgid ""
"option and delete the Default layout."
msgstr ""
"Layout predefinito dell'editor sovrascritto.\n"
-"Per ripristinare il layout predefinito alle impostazioni di base, usa "
-"l'opzione elimina layout ed elimina il layout predefinito."
+"Per ripristinare il layout predefinito alle impostazioni di base, usare "
+"l'opzione elimina layout ed eliminare il layout predefinito."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2601,10 +2594,9 @@ msgstr ""
"configurazione fallita."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
-"Impossibile trovare il campo dello script per il componente aggiuntivo in: "
-"'res://addons/%s'."
+"Impossibile trovare il campo script per il plugin addon in posizione: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3040,14 +3032,6 @@ msgid "Help"
msgstr "Aiuto"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Cerca"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentazione online"
@@ -3173,13 +3157,13 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
-"Questo imposterà il tuo progetto per le build custom per Android, "
-"installando i source templates in \"res://android/build\".\n"
-"Puoi, allora, applicare le modifiche e costruire il tuo APK custom durante "
-"l'esportazione (aggiungere moduli, cambiare il AndroidManifest.xml, ed "
-"altro).\n"
-"Nota che, in ordine per creare le build custom invece di usare gli APK pre-"
-"costruiti, l'opzione \"Use Custom Build\" sarà abilitata nel preset "
+"Questo predisporrà il progetto per le build personalizzate per Android "
+"installando i template sorgente in \"res://android/build\".\n"
+"Potrai allora applicare le modifiche e costruire il tuo APK personalizzato "
+"durante l'esportazione (aggiungere moduli, cambiare l'AndroidManifest.xml, "
+"eccetera).\n"
+"Nota che per creare delle build personalizzate, invece di usare gli APK pre-"
+"costruiti, l'opzione \"Use Custom Build\" va attivata nella preimpostazione "
"d'esportazione per Android."
#: editor/editor_node.cpp
@@ -3189,30 +3173,48 @@ msgid ""
"Remove the \"res://android/build\" directory manually before attempting this "
"operation again."
msgstr ""
-"Il modello della build Android è già installato in questo progetto e non "
-"sarà sovrascritto.\n"
-"Rimuovi la cartella \"res://android/build\" manualmente prima di ritentare "
+"Il template della build Android è già installato in questo progetto e non "
+"verrà sovrascritto.\n"
+"Rimuovi manualmente la cartella \"res://android/build\" prima di ritentare "
"questa operazione."
#: editor/editor_node.cpp
msgid "Import Templates From ZIP File"
-msgstr "Importa template da un file ZIP"
+msgstr "Importa Template Da File ZIP"
#: editor/editor_node.cpp
msgid "Template Package"
-msgstr "Pacchetto Modello"
+msgstr "Pacchetto Template"
#: editor/editor_node.cpp
msgid "Export Library"
-msgstr "Esporta libreria"
+msgstr "Esporta Libreria"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr "Unisci con esistente"
+msgstr "Unisci Con Esistente"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
-msgstr "Apri ed esegui uno script"
+msgstr "Apri ed Esegui uno Script"
+
+#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"I seguenti file sono più recenti sul disco.\n"
+"Quale azione dovrebbe essere presa?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Ricarica"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Risalva"
#: editor/editor_node.cpp
msgid "New Inherited"
@@ -3425,7 +3427,7 @@ msgstr "Rendi Unico"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Incolla"
@@ -3744,6 +3746,11 @@ msgstr ""
"reimportarlo manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossibile spostare/rinominare risorse root."
@@ -4132,6 +4139,22 @@ msgstr ""
msgid "Saving..."
msgstr "Salvataggio..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Seleziona Importatore"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importatore:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Ripristinare le impostazioni predefinite"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d File"
@@ -5104,8 +5127,8 @@ msgid "Got:"
msgstr "Ottenuto:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Check hash sha256 fallito"
+msgid "Failed SHA-256 hash check"
+msgstr "Check has SHA-256 fallito"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5208,7 +5231,6 @@ msgid "Sort:"
msgstr "Ordina:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoria:"
@@ -7048,6 +7070,14 @@ msgstr "Chiudi la documentazione"
msgid "Run"
msgstr "Esegui"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Cerca"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Passo dentro all'istruzione"
@@ -7101,16 +7131,6 @@ msgstr ""
"I file seguenti sono più recenti su disco.\n"
"Che azione deve essere intrapresa?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Ricarica"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Risalva"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Debugger"
@@ -7206,8 +7226,8 @@ msgstr "Punti di interruzione"
msgid "Go To"
msgstr "Vai a"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Taglia"
@@ -7430,9 +7450,8 @@ msgid "Yaw"
msgstr "Imbardata"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Dimensione: "
+msgstr "Dimensione"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7616,6 +7635,11 @@ msgstr "Rotazione Vista Bloccata"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10135,6 +10159,10 @@ msgid "Projects"
msgstr "Progetti"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Caricamento, per favore attendere..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Ultima Modifica"
@@ -10505,6 +10533,10 @@ msgstr "AutoLoad"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Carica Predefiniti"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Preset…"
@@ -10755,6 +10787,14 @@ msgid "Instance Child Scene"
msgstr "Istanzia Scena Figlia"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Non si può incollare il noto root nella stessa scena."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Incolla Nodo(i)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Rimuovi Script"
@@ -10881,6 +10921,10 @@ msgid "Attach Script"
msgstr "Allega Script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Taglia Nodo(i)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Rimuovi nodo(i)"
@@ -10995,6 +11039,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Locale"
@@ -12559,6 +12610,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Un CollisionPolygon2D vuoto non ha effetti sulla collisione."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Poligono non valido. Sono necessari almeno 3 punti nella modalità di "
+"costruzione 'Solidi'."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Poligono non valido. Sono necessari almeno 2 punti nella modalità di "
+"costruzione 'Segmenti'."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12883,11 +12946,6 @@ msgstr ""
"Le GIProbes non sono supportate dal driver video GLES2.\n"
"In alternativa, usa una BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "\"InterpolatedCamera\" è stata deprecata e sarà rimossa in Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13146,9 +13204,9 @@ msgid ""
"functions. Making them visible for editing is fine, but they will hide upon "
"running."
msgstr ""
-"I popup saranno nascosti di predefinita finchè non chiami popup() o una "
-"delle qualsiasi funzioni popup*(). Farli diventare visibili per modificarli "
-"va bene, ma scompariranno all'esecuzione."
+"I popup saranno nascosti di default finchè non chiami popup(), o una delle "
+"qualsiasi funzioni popup*(). Farli diventare visibili per modificarli va "
+"bene, ma scompariranno durante l'esecuzione."
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
@@ -13231,6 +13289,11 @@ msgstr ""
msgid "Constants cannot be modified."
msgstr "Le constanti non possono essere modificate."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "\"InterpolatedCamera\" è stata deprecata e sarà rimossa in Godot 4.0."
+
#~ msgid "No"
#~ msgstr "No"
@@ -14894,9 +14957,6 @@ msgstr "Le constanti non possono essere modificate."
#~ msgid "Use Default Light"
#~ msgstr "Usa Luce Default"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Usa sRGB Default"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Normale Luce di Default:"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index d960e0cc32..2d694989fc 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -31,13 +31,13 @@
# Akihiro Ogoshi <technical@palsystem-game.com>, 2019, 2020.
# Wataru Onuki <bettawat@yahoo.co.jp>, 2020, 2021.
# sporeball <sporeballdev@gmail.com>, 2020.
-# BinotaLIU <me@binota.org>, 2020.
+# BinotaLIU <me@binota.org>, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
-"Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n"
+"PO-Revision-Date: 2021-04-01 02:04+0000\n"
+"Last-Translator: nitenook <admin@alterbaum.net>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
"Language: ja\n"
@@ -45,12 +45,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "convert() の引数の型が無効です。TYPE_* 定数を使ってください。"
+msgstr "convert() の引数の型が無効です。TYPE_* 定数を使用してください。"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -676,7 +676,7 @@ msgstr "コピーするトラックを選択"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "コピー"
@@ -1590,7 +1590,7 @@ msgstr "ファイルの保存:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr "エクスポート テンプレートが予想されたパスに見つかりません:"
+msgstr "エクスポート テンプレートが予期されたパスに見つかりません:"
#: editor/editor_export.cpp
msgid "Packing"
@@ -1881,8 +1881,8 @@ msgid "Open a File or Directory"
msgstr "ファイルまたはディレクトリを開く"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "保存"
@@ -2554,10 +2554,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "アドオンプラグインを有効にできません: '%s' 設定の解析に失敗しました。"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"アドオンプラグインのスクリプトフィールドが 'res://addons/%s' から見つかりませ"
-"ん。"
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "アドオンプラグインのスクリプトフィールドが '%s' で見つかりません。"
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2988,14 +2986,6 @@ msgid "Help"
msgstr "ヘルプ"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "検索"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "オンラインドキュメント"
@@ -3161,6 +3151,24 @@ msgid "Open & Run a Script"
msgstr "スクリプトを開いて実行"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"以下のファイルより新しいものがディスク上に存在します。\n"
+"どうしますか?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "再読込"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "再保存"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "新規の継承"
@@ -3371,7 +3379,7 @@ msgstr "ユニーク化"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "貼り付け"
@@ -3684,6 +3692,11 @@ msgstr ""
"ンポートして下さい。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ルートのリソースは移動/リネームできません。"
@@ -4071,6 +4084,25 @@ msgstr ""
msgid "Saving..."
msgstr "保存中..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "選択モード"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "インポート"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "デフォルトを読込む"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d ファイル"
@@ -5035,8 +5067,8 @@ msgid "Got:"
msgstr "取得:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "sha256 ハッシュチェック失敗"
+msgid "Failed SHA-256 hash check"
+msgstr "SHA-256 ハッシュチェック失敗"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5139,7 +5171,6 @@ msgid "Sort:"
msgstr "ソート:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "カテゴリー:"
@@ -6962,6 +6993,14 @@ msgstr "ドキュメントを閉じる"
msgid "Run"
msgstr "実行"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "検索"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "ステップイン"
@@ -7015,16 +7054,6 @@ msgstr ""
"以下のファイルより新しいものがディスク上に存在します。\n"
"どうしますか?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "再読込"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "再保存"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "デバッガ"
@@ -7121,8 +7150,8 @@ msgstr "ブレークポイント"
msgid "Go To"
msgstr "参照"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "切り取り"
@@ -7345,9 +7374,8 @@ msgid "Yaw"
msgstr "ヨー"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "サイズ: "
+msgstr "サイズ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7531,6 +7559,11 @@ msgstr "ビューの回転を固定中"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10026,6 +10059,10 @@ msgid "Projects"
msgstr "プロジェクト"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "読み込み中、しばらくお待ちください..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "最終更新"
@@ -10396,6 +10433,11 @@ msgstr "自動読み込み"
msgid "Plugins"
msgstr "プラグイン"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "デフォルトを読込む"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "プリセット..."
@@ -10645,6 +10687,14 @@ msgid "Instance Child Scene"
msgstr "子シーンをインスタンス化"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "ルートノードは同じシーンに貼り付けできません。"
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "ノードを貼り付け"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "スクリプトをデタッチ"
@@ -10770,6 +10820,10 @@ msgid "Attach Script"
msgstr "スクリプトをアタッチ"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "ノードを切り取り"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "ノードを除去"
@@ -10841,7 +10895,7 @@ msgstr "親ノードを新規ノードに変更"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr "シーンをルートにする"
+msgstr "シーンのルートにする"
#: editor/scene_tree_dock.cpp
msgid "Merge From Scene"
@@ -10884,6 +10938,13 @@ msgid "Remote"
msgstr "リモート"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "ローカル"
@@ -11209,7 +11270,7 @@ msgstr "グラフを表示するには、リストからアイテムを1つ以
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr "リソースによるビデオメモリーの使用一覧:"
+msgstr "リソースによるビデオメモリーの消費量一覧:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
@@ -11233,7 +11294,7 @@ msgstr "フォーマット"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr "使用法"
+msgstr "消費量"
#: editor/script_editor_debugger.cpp
msgid "Misc"
@@ -11586,24 +11647,20 @@ msgid "Preparing data structures"
msgstr "データ構造の準備"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "AABBを生成"
+msgstr "バッファを生成"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "方向"
+msgstr "直接光"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "右インデント"
+msgstr "間接光"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "ポストプロセス"
+msgstr "後処理"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -12124,9 +12181,8 @@ msgid "Select device from the list"
msgstr "一覧からデバイスを選択"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Unable to find the 'apksigner' tool."
-msgstr "zipalign ツールが見つかりません。"
+msgstr "'apksigner' ツールが見つかりません。"
#: platform/android/export/export.cpp
msgid ""
@@ -12145,14 +12201,12 @@ msgid "Release keystore incorrectly configured in the export preset."
msgstr "エクスポート設定にてリリース キーストアが誤って設定されています。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "エディタ設定のカスタムビルドのAndroid SDKパスが無効です。"
+msgstr "エディタ設定でAndroid SDKパスの指定が必要です。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "エディタ設定のカスタムビルドのAndroid SDKパスが無効です。"
+msgstr "エディタ設定のAndroid SDKパスが無効です。"
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
@@ -12160,12 +12214,11 @@ msgstr "'platform-tools' ディレクトリがありません!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Android SDK platform-toolsのadbコマンドが見つかりません。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "エディタ設定のカスタムビルドのAndroid SDKパスが無効です。"
+msgstr "エディタ設定で指定されたAndroid SDKのディレクトリを確認してください。"
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
@@ -12173,7 +12226,7 @@ msgstr "'build-tools' ディレクトリがありません!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Android SDK build-toolsのapksignerコマンドが見つかりません。"
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12437,6 +12490,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "空の CollisionPolygon2D は、衝突判定を持ちません。"
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12650,9 +12711,8 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "ジオメトリを解析しています..."
+msgstr "ジオメトリを解析しています (%d/%d)"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12759,11 +12819,6 @@ msgstr ""
"GIProbesはGLES2ビデオドライバではサポートされていません。\n"
"代わりにBakedLightmapを使用してください。"
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera は廃止予定であり、Godot 4.0で除去されます。"
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "90度を超える角度のスポットライトは、シャドウを投影できません。"
@@ -13102,6 +13157,10 @@ msgstr "Varying変数は頂点関数にのみ割り当てることができま
msgid "Constants cannot be modified."
msgstr "定数は変更できません。"
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera は廃止予定であり、Godot 4.0で除去されます。"
+
#~ msgid "No"
#~ msgstr "いいえ"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 81e843c723..1894b0e156 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -675,7 +675,7 @@ msgstr "დაყენდეს გადასვლები შემდე
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1900,8 +1900,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2552,7 +2552,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2949,14 +2949,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3111,6 +3103,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3316,7 +3324,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3625,6 +3633,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4020,6 +4033,23 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "წავშალოთ მონიშნული ფაილები?"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4998,7 +5028,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5105,7 +5135,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6918,6 +6947,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6969,16 +7006,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7078,8 +7105,8 @@ msgstr "შექმნა"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7493,6 +7520,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9912,6 +9944,11 @@ msgid "Projects"
msgstr "პროექტის დამფუძნებლები"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "ძებნა:"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10276,6 +10313,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10523,6 +10564,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "ანიმაციის გასაღებების ასლის შექმნა"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "დამოკიდებულებების შემსწორებელი"
@@ -10649,6 +10699,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "ანიმაციის გასაღებების ასლის შექმნა"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10759,6 +10814,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12270,6 +12332,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12525,11 +12595,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/km.po b/editor/translations/km.po
new file mode 100644
index 0000000000..9e167dfe2c
--- /dev/null
+++ b/editor/translations/km.po
@@ -0,0 +1,12486 @@
+# LANGUAGE translation of the Godot Engine editor.
+# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# Withuse <withuse@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine editor\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: Withuse <withuse@gmail.com>\n"
+"Language-Team: Khmer (Central) <https://hosted.weblate.org/projects/godot-"
+"engine/godot/km/>\n"
+"Language: km\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.7-dev\n"
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Invalid type argument to convert(), use TYPE_* constants."
+msgstr "ប្រភេទ argument មិនត្រឹមត្រូវដើម្បី convert() សូមប្រើ TYPE_* constants."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+msgid "Expected a string of length 1 (a character)."
+msgstr "តម្រូវអោយមាន string យ៉ាងតឹច១អក្សរ (មួយ character)."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/mono/glue/gd_glue.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Not enough bytes for decoding bytes, or invalid format."
+msgstr "ចំនួន bytes សម្រាប់ decoding bytes​ មិនគ្រប់គ្រាន់ ឬ format មិនត្រឹមត្រូវ."
+
+#: core/math/expression.cpp
+msgid "Invalid input %i (not passed) in expression"
+msgstr "ការបញ្ចូល %i មានបញ្ហា (មិនបានបញ្ចូល) ក្នុង expression"
+
+#: core/math/expression.cpp
+msgid "self can't be used because instance is null (not passed)"
+msgstr "self មិនអាចប្រើបានទេ ព្រោះ instance វា null (មិនបានបញ្ចូល)"
+
+#: core/math/expression.cpp
+msgid "Invalid operands to operator %s, %s and %s."
+msgstr "operands មិនអាចប្រើជាមួយ operator %s, %s និង %s​ បានទេ."
+
+#: core/math/expression.cpp
+msgid "Invalid index of type %s for base type %s"
+msgstr "index នៃ type %s សម្រាប់ base type %s មិនត្រឺមត្រូវទេ"
+
+#: core/math/expression.cpp
+msgid "Invalid named index '%s' for base type %s"
+msgstr "មិនអាចដាក់ឈ្មោះ index '%s' សម្រាប់ base type %s បានទេ"
+
+#: core/math/expression.cpp
+msgid "Invalid arguments to construct '%s'"
+msgstr "arguments ដែលប្រើសំរាប់រៀប '%s' មិនត្រឹមត្រូវទេ"
+
+#: core/math/expression.cpp
+msgid "On call to '%s':"
+msgstr "កំពុងហៅទៅកាន់ '%s':"
+
+#: core/ustring.cpp
+msgid "B"
+msgstr "B"
+
+#: core/ustring.cpp
+msgid "KiB"
+msgstr "KB"
+
+#: core/ustring.cpp
+msgid "MiB"
+msgstr "MB"
+
+#: core/ustring.cpp
+msgid "GiB"
+msgstr "GB"
+
+#: core/ustring.cpp
+msgid "TiB"
+msgstr "TB"
+
+#: core/ustring.cpp
+msgid "PiB"
+msgstr "PB"
+
+#: core/ustring.cpp
+msgid "EiB"
+msgstr "EB"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Free"
+msgstr "Free"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Balanced"
+msgstr "មានតុល្យភាព"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Mirror"
+msgstr "កញ្ចក់"
+
+#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
+msgid "Time:"
+msgstr "ពេលវេលា:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Value:"
+msgstr "តម្លៃ:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Insert Key Here"
+msgstr "បញ្ចូល Key នៅទីនេះ"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Duplicate Selected Key(s)"
+msgstr "Key(s) ដែលបានជ្រើសស្ទួន"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Delete Selected Key(s)"
+msgstr "លុប Key(s) ដែលបានជ្រើស"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Add Bezier Point"
+msgstr "បន្ថែម Bezier Point"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Move Bezier Points"
+msgstr "ផ្លាស់ទី Bezier Points"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Duplicate Keys"
+msgstr "Anim Keys ស្ទួន"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Delete Keys"
+msgstr "លុប Anim Delete Keys"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Time"
+msgstr "Anim ផ្លាស់ប្តូរ Keyframe ពេលវេលា"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transition"
+msgstr "Anim ផ្លាស់ប្តូរ Transition"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transform"
+msgstr "Anim ផ្លាស់ប្តូរ Transform"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Value"
+msgstr "Anim ផ្លាស់ប្តូរតម្លៃ Keyframe"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Call"
+msgstr "Anim ផ្លាស់ប្តូរ Call"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Anim Multi Change Keyframe Time"
+msgstr "Anim ផ្លាស់ប្តូរ Keyframe ពេលវេលាច្រើន"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transition"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transform"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Keyframe Value"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Call"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Length"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation Loop"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Property Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "3D Transform Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Call Method Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Bezier Curve Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (frames)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (seconds)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Looping"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Functions:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Track Path"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle this track on/off."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Update Mode (How this property is set)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove this track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Time (s): "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle Track Enabled"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Continuous"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Discrete"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Trigger"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Capture"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Nearest"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp
+#: editor/property_editor.cpp
+msgid "Linear"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Cubic"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clamp Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Wrap Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Update Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Loop Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove Anim Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create NEW track for %s and insert key?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create %d NEW tracks and insert keys?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/create_dialog.cpp
+#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "AnimationPlayer can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Create & Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Track & Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Rearrange Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Transform tracks only apply to Spatial-based nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"Audio tracks can only point to nodes of type:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation tracks can only point to AnimationPlayer nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "An animation player can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Not possible to add a new track without a root"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Invalid track for Bezier (no suitable sub-properties)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Bezier Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track is not of type Spatial, can't insert key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Transform Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a method key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Method Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Method not found in object: "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Move Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clipboard is empty"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Paste Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Scale Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This option does not work for Bezier editing, as it's only a single track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To enable the ability to add custom tracks, navigate to the scene's import "
+"settings and set\n"
+"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks"
+"\", then re-import.\n"
+"Alternatively, use an import preset that imports animations to separate "
+"files."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Warning: Editing imported animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select an AnimationPlayer node to create and edit animations."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Only show tracks from nodes selected in tree."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Group tracks by node or display them as plain list."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Snap:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation step value."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Seconds"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "FPS"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_properties.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation properties."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Copy Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale From Cursor"
+msgstr ""
+
+#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Duplicate Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Transposed"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Next Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Previous Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Pick the node that will be animated:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Use Bezier Curves"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim. Optimizer"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Linear Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Angular Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max Optimizable Angle:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove invalid keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove unresolved and empty tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-up all animations"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation(s) (NO UNDO!)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Ratio:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select Tracks to Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_log.cpp
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select All/None"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Add Audio Track Clip"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip Start Offset"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip End Offset"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Resize Array"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value Type"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Go to Line"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line Number:"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "%d replaced."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d match."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d matches."
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Match Case"
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Whole Words"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace All"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Selection Only"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
+#: editor/plugins/text_editor.cpp
+msgid "Standard"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Toggle Scripts Panel"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom In"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Out"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Reset Zoom"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Warnings"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line and column numbers."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method in target node must be specified."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Target method not found. Specify a valid method or attach a script to the "
+"target node."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Node:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Script:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "From Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Scene does not contain any script."
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
+#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+msgid "Add"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/editor_feature_profile.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp
+msgid "Remove"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Add Extra Call Argument:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Extra Call Arguments:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Receiver Method:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Advanced"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Deferred"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Defers the signal, storing it in a queue and only firing it at idle time."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Oneshot"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnects the signal after its first emission."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Cannot connect signal"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/export_template_manager.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Close"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect '%s' to '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect '%s' from '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect all from signal: '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Disconnect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect a Signal to a Method"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit Connection:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
+msgid "Signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Filter signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from this signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect All"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Go To Method"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Change %s Type"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/project_settings_editor.cpp
+msgid "Change"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Create New %s"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp
+msgid "Favorites:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+msgid "Recent:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Matches:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
+#: editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Description:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Scene '%s' is currently being edited.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Resource '%s' is in use.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resource"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
+#: editor/project_manager.cpp editor/project_settings_editor.cpp
+msgid "Path"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Broken"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependency Editor"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement Resource:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Open"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owners Of:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Remove selected files from the project? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"The files being removed are required by other resources in order for them to "
+"work.\n"
+"Remove them anyway? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Cannot remove:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Error loading:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Load failed due to missing dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_node.cpp
+msgid "Open Anyway"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Which action should be taken?"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Errors loading!"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Permanently delete %d item(s)? (No undo!)"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Show Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Orphan Resource Explorer"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
+msgid "Delete"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owns"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resources Without Explicit Ownership:"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Key"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Value"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Thanks from the Godot community!"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Godot Engine contributors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Project Founders"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Lead Developer"
+msgstr ""
+
+#. TRANSLATORS: This refers to a job title.
+#. The trailing space is used to distinguish with the project list application,
+#. you do not have to keep it in your translation.
+#: editor/editor_about.cpp
+msgid "Project Manager "
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Developers"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Authors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Platinum Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Mini Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "License"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Third-party Licenses"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid ""
+"Godot Engine relies on a number of third-party free and open source "
+"libraries, all compatible with the terms of its MIT license. The following "
+"is an exhaustive list of all such third-party components with their "
+"respective copyright statements and license terms."
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "All Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Licenses"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Error opening package file, not in ZIP format."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "%s (Already Exists)"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Uncompressing Assets"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "The following files failed extraction from package:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "And %s more files."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Package installed successfully!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Success!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Contents:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/editor_node.cpp
+msgid "Install"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Installer"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Speakers"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Rename Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Change Audio Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Bypass Effects"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Select Audio Bus Send"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Drag & drop to rearrange."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bypass"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bus options"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Duplicate"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Audio"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Master bus can't be deleted!"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Duplicate Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save Audio Bus Layout As..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Location for New Layout..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Open Audio Bus Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "There is no '%s' file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Invalid file, not an audio bus layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Error saving file: %s"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add a new Audio Bus to this layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Load"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load an existing Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save As"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save this Bus Layout to a file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/import_dock.cpp
+msgid "Load Default"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load the default Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Create a new Bus Layout."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Invalid name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Valid characters:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing engine class name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing built-in type name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing global constant name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Keyword cannot be used as an autoload name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Autoload '%s' already exists!"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rename Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Toggle AutoLoad Globals"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Move Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Remove Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
+msgid "Enable"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rearrange Autoloads"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Can't add autoload:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Add AutoLoad"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Path:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Node Name:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
+#: editor/editor_profiler.cpp editor/project_manager.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Name"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Singleton"
+msgstr ""
+
+#: editor/editor_data.cpp editor/inspector_dock.cpp
+msgid "Paste Params"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating Scene"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Storing local changes..."
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating scene..."
+msgstr ""
+
+#: editor/editor_data.cpp editor/editor_properties.cpp
+msgid "[empty]"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "[unsaved]"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Please select a base directory first."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose a Directory"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Create Folder"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp
+#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp
+msgid "Name:"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp
+msgid "Could not create folder."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Storing File:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "No export template found at the expected path:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Packing"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
+"Etc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' texture compression for GLES3. Enable "
+"'Import Etc 2' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
+"'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
+"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom debug template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom release template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/javascript/export/export.cpp
+msgid "Template file not found:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "3D Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Script Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Asset Library"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Scene Tree Editing"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Node Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "FileSystem Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase profile '%s'? (no undo)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile must be a valid filename and must not contain '.'"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile with this name already exists."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled, Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enable Contextual Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Properties:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Features:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Classes:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "File '%s' format is invalid, import aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid ""
+"Profile '%s' already exists. Remove it first before importing, import "
+"aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Error saving profile to path: '%s'."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Unset"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Current Profile:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Make Current"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "New"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/editor_node.cpp
+#: editor/project_manager.cpp
+msgid "Import"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/project_export.cpp
+msgid "Export"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Available Profiles:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "New profile name:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Godot Feature Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Profile(s)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Export Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Manage Editor Feature Profiles"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select Current Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File Exists, Overwrite?"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select This Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Copy Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Open in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+msgid "Show in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "New Folder..."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Refresh"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Recognized"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Files (*)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open File(s)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File or Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
+msgid "Save"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Save a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Back"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Forward"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Hidden Files"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Favorite"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Mode"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Focus Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Down"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to previous folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to next folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Go to parent folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Refresh files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "(Un)favorite current folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Toggle the visibility of hidden files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a grid of thumbnails."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a list."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Directories & Files:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
+#: editor/plugins/style_box_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Preview:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File:"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "ScanSources"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid ""
+"There are multiple importers for different types pointing to file %s, import "
+"aborted"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "(Re)Importing Assets"
+msgstr ""
+
+#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
+msgid "Top"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Class:"
+msgstr ""
+
+#: editor/editor_help.cpp editor/scene_tree_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Inherits:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Inherited by:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Description"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Online Tutorials"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "override:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "default:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Methods"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Theme Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Enumerations"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Constants"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Property Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "(value)"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this property. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Method Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this method. Please help us by [color="
+"$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Help"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Case Sensitive"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Show Hierarchy"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Display All"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Classes Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Methods Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Signals Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Constants Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Member Type"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Class"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Method"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
+msgid "Signal"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
+msgid "Constant"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Property"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Property"
+msgstr ""
+
+#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
+msgid "Property:"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set Multiple:"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Output:"
+msgstr ""
+
+#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Copy Selection"
+msgstr ""
+
+#: editor/editor_log.cpp editor/editor_network_profiler.cpp
+#: editor/editor_profiler.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/property_editor.cpp editor/scene_tree_dock.cpp
+#: editor/script_editor_debugger.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Clear"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Clear Output"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+#: editor/editor_profiler.cpp
+msgid "Stop"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
+#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
+msgid "Start"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "%s/s"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Down"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Up"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+msgid "Node"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RSET"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RSET"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "New Window"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Imported resources can't be saved."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: scene/gui/dialogs.cpp
+msgid "OK"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Error saving resource!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource can't be saved because it does not belong to the edited scene. "
+"Make it unique first."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Save Resource As..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't open file for writing:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Requested file format unknown:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while saving."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Can't open '%s'. The file could have been moved or deleted."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while parsing '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unexpected end of file '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Missing '%s' or its dependencies."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while loading '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saving Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Analyzing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Creating Thumbnail"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a tree root."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene can't be saved because there is a cyclic instancing inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
+"be satisfied."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "Can't overwrite scene that is still open!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load MeshLibrary for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving MeshLibrary!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load TileSet for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving TileSet!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"An error occurred while trying to save the editor layout.\n"
+"Make sure the editor's user data path is writable."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Default editor layout overridden.\n"
+"To restore the Default layout to its base settings, use the Delete Layout "
+"option and delete the Default layout."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Layout name not found!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Restored the Default layout to its base settings."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was imported, so it's not editable.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was instanced or inherited.\n"
+"Changes to it won't be kept when saving the current scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource was imported, so it's not editable. Change its settings in the "
+"import panel and then re-import."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instancing it or inheriting will allow making changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This is a remote object, so changes to it won't be kept.\n"
+"Please read the documentation relevant to debugging to better understand "
+"this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "There is no defined scene to run."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save scene before running..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Could not start subprocess!"
+msgstr ""
+
+#: editor/editor_node.cpp editor/filesystem_dock.cpp
+msgid "Open Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Base Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Script..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Close"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to '%s' before closing?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saved %s modified resource(s)."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "A root node is required to save the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene As..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "This operation can't be done without a scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Mesh Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a root node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Tile Set"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a selected node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Current scene not saved. Open anyway?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't reload a scene that was never saved."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reload Saved Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The current scene has unsaved changes.\n"
+"Reload the saved scene anyway? This action cannot be undone."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Run Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Yes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Exit the editor?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to the following scene(s) before quitting?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes the following scene(s) before opening Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This option is deprecated. Situations where refresh must be forced are now "
+"considered a bug. Please report."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pick a Main Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reopen Closed Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s' There seems to be an error in "
+"the code, please check the syntax."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Scene '%s' was automatically imported, so it can't be modified.\n"
+"To make changes to it, a new inherited scene can be created."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Error loading scene, it must be inside the project path. Use 'Import' to "
+"open the scene, then save it inside the project path."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene '%s' has broken dependencies:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Clear Recent Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"No main scene has ever been defined, select one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' does not exist, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' is not a scene file, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Delete Layout"
+msgstr ""
+
+#: editor/editor_node.cpp editor/import_dock.cpp
+#: editor/script_create_dialog.cpp
+msgid "Default"
+msgstr ""
+
+#: editor/editor_node.cpp editor/editor_properties.cpp
+#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
+msgid "Show in FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play This Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Undo Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Close Other Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tabs to the Right"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close All Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Switch Scene Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files or folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Dock Position"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Distraction Free Mode"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle distraction-free mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Add a new scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Go to previously opened scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Copy Text"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Next tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Previous tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Filter Files..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Operations with scene files."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Open Recent"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save All Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Convert To..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "MeshLibrary..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "TileSet..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Undo"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Redo"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Miscellaneous project or scene-wide tools."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+#: editor/script_create_dialog.cpp
+msgid "Project"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Project Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Set Up Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Shut Down Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Install Android Build Template..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
+msgid "Tools"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Orphan Resource Explorer..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit to Project List"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/project_export.cpp
+msgid "Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Deploy with Remote Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy will make the executable "
+"attempt to connect to this computer's IP so the running project can be "
+"debugged.\n"
+"This option is intended to be used for remote debugging (typically with a "
+"mobile device).\n"
+"You don't need to enable it to use the GDScript debugger locally."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Small Deploy with Network Filesystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy for Android will only "
+"export an executable without the project data.\n"
+"The filesystem will be provided from the project by the editor over the "
+"network.\n"
+"On Android, deploying will use the USB cable for faster performance. This "
+"option speeds up testing for projects with large assets."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Collision Shapes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, collision shapes and raycast nodes (for 2D and "
+"3D) will be visible in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Navigation"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, navigation meshes and polygons will be visible "
+"in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Scene Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any changes made to the scene in the editor "
+"will be replicated in the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Script Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any script that is saved will be reloaded in "
+"the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp editor/script_create_dialog.cpp
+msgid "Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Take Screenshot"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Screenshots are stored in the Editor Data/Settings Folder."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle Fullscreen"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle System Console"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data/Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Editor Features..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Export Templates..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
+msgid "Help"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Online Docs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Q&A"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Report a Bug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Send Docs Feedback"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
+msgid "Community"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "About"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause the scene execution for debugging."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Stop the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the edited scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play custom scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Custom Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Changing the video driver requires restarting the editor."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_settings_editor.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Save & Restart"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update Continuously"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update When Changed"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Hide Update Spinner"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Inspector"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Expand Bottom Panel"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Output"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Don't Save"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Android build template is missing, please install relevant templates."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Templates"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This will set up your project for custom Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make custom builds instead of using pre-built APKs, "
+"the \"Use Custom Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The Android build template is already installed in this project and it won't "
+"be overwritten.\n"
+"Remove the \"res://android/build\" directory manually before attempting this "
+"operation again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Import Templates From ZIP File"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Template Package"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Merge With Existing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open & Run a Script"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Load Errors"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Select"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 2D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 3D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Script Editor"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "Open Asset Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the next Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the previous Editor"
+msgstr ""
+
+#: editor/editor_node.h
+msgid "Warning!"
+msgstr ""
+
+#: editor/editor_path.cpp
+msgid "No sub-resources found."
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Creating Mesh Previews"
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Thumbnail..."
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Main Script:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit Plugin"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Installed Plugins:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Update"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Version:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Author:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Status:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Measure:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Average Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Physics Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Inclusive"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Self"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame #:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Time"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Calls"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Edit Text:"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/script_create_dialog.cpp
+msgid "On"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Layer"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Bit %d, value %d"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "[Empty]"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
+msgid "Assign..."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Invalid RID"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"The selected resource (%s) does not match any type expected for this "
+"property (%s)."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on resources saved as a file.\n"
+"Resource needs to belong to a scene."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on this resource because it's not set as "
+"local to scene.\n"
+"Please switch on the 'local to scene' property on it (and all resources "
+"containing it up to a node)."
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Pick a Viewport"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
+msgid "Extend Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Make Unique"
+msgstr ""
+
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Paste"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Convert To %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Selected node is not a Viewport!"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Size: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Page: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Item"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Key:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Value:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Add Key/Value Pair"
+msgstr ""
+
+#: editor/editor_run_native.cpp
+msgid ""
+"No runnable export preset found for this platform.\n"
+"Please add a runnable preset in the Export menu or define an existing preset "
+"as runnable."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Write your logic in the _run() method."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "There is an edited scene already."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't instance script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the 'tool' keyword?"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't run script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the '_run' method?"
+msgstr ""
+
+#: editor/editor_spin_slider.cpp
+msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Select Node(s) to Import"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp editor/project_manager.cpp
+msgid "Browse"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Scene Path:"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Import From Node:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redownload"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uninstall"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Installed)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Official export templates aren't available for development builds."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Missing)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Current)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Retrieving mirrors, please wait..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove template version '%s'?"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't open export templates zip."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Invalid version.txt format inside templates: %s."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "No version.txt found inside templates."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error creating path for templates:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Extracting Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Importing:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error getting the list of mirrors."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error parsing JSON of mirror list. Please report this issue!"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"No download links found for this version. Direct download is only available "
+"for official releases."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Request Failed."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redirect Loop."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Complete."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Cannot remove temporary file:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"Templates installation failed.\n"
+"The problematic templates archives can be found at '%s'."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error requesting URL:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connecting to Mirror..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Disconnected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Resolving"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Resolve"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connecting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Connect"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Requesting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Downloading"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connection Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "SSL Handshake Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uncompressing Android Build Sources"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Current Version:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Installed Versions:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Install From File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove Template"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select Template File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Godot Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Export Template Manager"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select mirror from list: (Shift+Click: Open in Browser)"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Status: Import of file failed. Please fix file and reimport manually."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move/rename resources root."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move a folder into itself."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error moving:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error duplicating:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Unable to update dependencies:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
+msgid "No name provided."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Provided name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "A file or folder with this name already exists."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Do you wish to overwrite them?"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Inherited Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Set As Main Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Open Scenes"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Instance"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Add to Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Remove from Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Edit Dependencies..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "View Owners..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move To..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Scene..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "New Script..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Resource..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Expand All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Collapse All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Previous Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Next Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Re-Scan Filesystem"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Toggle Split Mode"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Search files"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Scanning Files,\n"
+"Please Wait..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Overwrite"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Create Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Create Script"
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Find in Files"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Folder:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Filters:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid ""
+"Include the files with the following extensions. Add or remove them in "
+"ProjectSettings."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
+msgid "Replace..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
+msgid "Cancel"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace all (no undo)"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Searching..."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d match in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d files."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Add to Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Remove from Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group name already exists."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Invalid group name."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Rename Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Delete Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/node_dock.cpp
+msgid "Groups"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes Not in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Filter nodes"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Empty groups will be automatically removed."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group Editor"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Manage Groups"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Single Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Importing Scene..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating Lightmaps"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating for Mesh: "
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Running Custom Script..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Couldn't load post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Invalid/broken script for post-import (check console):"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Error running post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Did you return a Node-derived object in the `post_import()` method?"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Saving..."
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "%d Files"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Set as Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Clear Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Import As:"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Preset"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Reimport"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Save Scenes, Re-Import, and Restart"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Changing the type of an imported file requires editor restart."
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid ""
+"WARNING: Assets exist that use this resource, they may stop loading properly."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Failed to load resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Expand All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Collapse All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save As..."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Params"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Edit Resource Clipboard"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Resource"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Built-In"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Sub-Resources Unique"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Open in Help"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Create a new resource in memory and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Load an existing resource from disk and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Save the currently edited resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the previous edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the next edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "History of recently edited objects."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Object properties."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Filter properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Changes may be lost!"
+msgstr ""
+
+#: editor/multi_node_edit.cpp
+msgid "MultiNode Set"
+msgstr ""
+
+#: editor/node_dock.cpp
+msgid "Select a single node to edit its signals and groups."
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Edit a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Create a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Plugin Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Subfolder:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
+msgid "Language:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Script Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Activate now?"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid ""
+"Edit points.\n"
+"LMB: Move Point\n"
+"RMB: Erase Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Erase points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Insert Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon (Remove Point)"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Remove Polygon And Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Load..."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Move Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "This type of node can't be used. Only root nodes are allowed."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Animation Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Remove BlendSpace1D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Move BlendSpace1D Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"AnimationTree is inactive.\n"
+"Activate to enable playback, check node warnings if activation fails."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Set the blending position within the space"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Select and move points, create points with RMB."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
+msgid "Enable snap and show grid."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Open Editor"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Open Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Triangle already exists."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "BlendSpace2D does not belong to an AnimationTree node."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "No triangles exist, so no blending can take place."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Toggle Auto Triangles"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create triangles by connecting points."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Erase points and triangles."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Generate blend triangles automatically (instead of manually)"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Parameter Changed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Filters"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Output node can't be added to the blend tree."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Add Node to BlendTree"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Node Moved"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Unable to connect, port may be in use or connection may be invalid."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Connected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Disconnected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Set Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Delete Node(s)"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Toggle Filter On/Off"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Change Filter"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "No animation player set, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Player path set is invalid, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid ""
+"Animation player has no valid root node path, so unable to retrieve track "
+"names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Anim Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Audio Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Functions"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Renamed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node..."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Edit Filtered Tracks:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Enable Filtering"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Toggle Autoplay"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Anim"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Animation?"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Remove Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Invalid animation name!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation name already exists!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Rename Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Next Changed"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Blend Time"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Load Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Duplicate Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to copy!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation resource on clipboard!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pasted Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Paste Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to edit!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from current pos. (A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from end. (Shift+A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Stop animation playback. (S)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from start. (Shift+D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from current pos. (D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation position (in seconds)."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Scale animation playback globally for the node."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Tools"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Edit Transitions..."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Open in Inspector"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Display list of animations in player."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Autoplay on Load"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Enable Onion Skinning"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Onion Skinning Options"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Directions"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Past"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Future"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Depth"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "1 step"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "2 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "3 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Differences Only"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Force White Modulate"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Include Gizmos (3D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pin AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Create New Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+msgid "Error!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Times:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Next (Auto Queue):"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Cross-Animation Blend Times"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Move Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition exists!"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Add Transition"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Immediate"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Sync"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "At End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Travel"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Start and end nodes are needed for a sub-transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "No playback resource set at path: %s."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set Start Node (Autoplay)"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"Select and move nodes.\n"
+"RMB to add new nodes.\n"
+"Shift+LMB to create connections."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Create new nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Connect nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Remove selected node or transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Toggle autoplay this animation on start, restart or seek to zero."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set the end animation. This is useful for sub-transitions."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition: "
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Play Mode:"
+msgstr ""
+
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "AnimationTree"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "New name:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Scale:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade In (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade Out (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Auto Restart:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Random Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Start!"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Amount:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 0:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 1:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "X-Fade Time (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Current:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Clear Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Set Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Delete Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is valid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is invalid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "OneShot Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend2 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend3 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend4 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeScale Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeSeek Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Transition Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Import Animations..."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Node Filters"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Filters..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Contents:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "View Files"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connection error, please try again."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect to host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response from host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve hostname:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, return code:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Cannot save response to:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Write error."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, too many redirects"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Redirect loop."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, timeout"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Timeout."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Bad download hash, assuming file has been tampered with."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Expected:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Got:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed SHA-256 hash check"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Asset Download Error:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading (%s / %s)..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Resolving..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Error making request"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Idle"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Install..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Retry"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download Error"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download for this asset is already in progress!"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Least Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "First"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Previous"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Next"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Last"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "All"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No results for \"%s\"."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Import..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Plugins..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
+msgid "Sort:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Category:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Site:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Support"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Official"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Testing"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Loading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Assets ZIP File"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Can't determine a save path for lightmap images.\n"
+"Save your scene and try again."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed creating lightmap images, make sure path is writable."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed determining lightmap size. Maximum lightmap size too small?"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Some mesh is invalid. Make sure the UV2 channel values are contained within "
+"the [0.0,1.0] square region."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Godot editor was built without ray tracing support, lightmaps can't be baked."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Bake Lightmaps"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Select lightmap bake file:"
+msgstr ""
+
+#: editor/plugins/camera_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Preview"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Configure Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Primary Line Every:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "steps"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal and Vertical Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate CanvasItem \"%s\" to %d degrees"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Node2D \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Resize Control \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale CanvasItem \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Children of containers have their anchors and margins values overridden by "
+"their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Presets for the anchors and margins values of a Control node."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"margins."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Top"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Bottom"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Left Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Right Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "VCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "HCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Full Rect"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Keep Ratio"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Anchors only"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors and Margins"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"Overrides game camera with editor viewport camera."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"No game instance running."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Group Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Ungroup Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Paste Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Warning: Children of a container get their position and size determined only "
+"by their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Reset"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Select Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Drag: Rotate"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+Drag: Move"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Move Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Show a list of all objects at the position clicked\n"
+"(same as Alt+RMB in select mode)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Click to change object's rotation pivot."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Ruler Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle smart snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Smart Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle grid snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Grid Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snapping Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Rotation Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Scale Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap Relative"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Pixel Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Smart Snapping"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Configure Snap..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Parent"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Sides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Other Nodes"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock the selected object in place (can't be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock the selected object (can be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Makes sure the object's children are not selectable."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Restores the object's children's ability to be selected."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Skeleton Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Custom Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Always Show Grid"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Helpers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Rulers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Origin"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Viewport"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Group And Lock Icons"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Frame Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Preview Canvas Scale"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Translation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert keys (based on mask)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Auto insert keys when objects are translated, rotated or scaled (based on "
+"mask).\n"
+"Keys are only added to existing tracks, no new tracks will be created.\n"
+"Keys must be inserted manually for the first time."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Auto Insert Key"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Animation Key and Pose Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key (Existing Tracks)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Copy Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Multiply grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Divide grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Add %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Adding %s..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Cannot instantiate multiple nodes without root."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Create Node"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Error instancing scene from %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Default Type"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Drag & drop + Shift : Add node as sibling\n"
+"Drag & drop + Alt : Change node type"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Create Polygon3D"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly (Remove Point)"
+msgstr ""
+
+#: editor/plugins/collision_shape_2d_editor_plugin.cpp
+msgid "Set Handle"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Load Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Restart"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Clear Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Particles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generated Point Count:"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Solid Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Directed Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Capture from Pixel"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Colors"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+msgid "CPUParticles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Mesh"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Node"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 0"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 1"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease In"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease Out"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Smoothstep"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Curve Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Add Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Left Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Toggle Curve Linear Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Hold Shift to edit tangents individually"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right click to add point"
+msgstr ""
+
+#: editor/plugins/gi_probe_editor_plugin.cpp
+msgid "Bake GI Probe"
+msgstr ""
+
+#: editor/plugins/gradient_editor_plugin.cpp
+msgid "Gradient Edited"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item %d"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Items"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item List Editor"
+msgstr ""
+
+#: editor/plugins/light_occluder_2d_editor_plugin.cpp
+msgid "Create Occluder Polygon"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh is empty!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a Trimesh collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Static Trimesh Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "This doesn't work on scene root!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create a single convex collision shape for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a single convex collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create multiple convex collision shapes for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create any collision shapes."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Shapes"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Navigation Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Contained Mesh is not of type ArrayMesh."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Unwrap failed, mesh may not be manifold?"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "No mesh to debug."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Model has no UV in this layer"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "MeshInstance lacks a Mesh!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh has not surface to create outlines from!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Could not create outline!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a StaticBody and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a single convex collision shape.\n"
+"This is the fastest (but least accurate) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Collision Siblings"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is a performance middle-ground between the two above options."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh..."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the SpatialMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV1"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV2"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Unwrap UV2 for Lightmap/AO"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Outline Size:"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Channel Debug"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove item %d?"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid ""
+"Update from existing scene?:\n"
+"%s"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Mesh Library"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove Selected Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import from Scene"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Update from Scene"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and no MultiMesh set in node)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and MultiMesh contains no Mesh)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (not a MeshInstance)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (contains no Mesh resource)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No surface source specified."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no geometry)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no faces)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate Surface"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate MultiMesh"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "X-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Y-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Z-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh Up Axis:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Rotation:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Tilt:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Scale:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate"
+msgstr ""
+
+#: editor/plugins/navigation_polygon_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Convert to CPUParticles"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generating Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generate Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Can only set point into a ParticlesMaterial process material"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Convert to CPUParticles2D"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generation Time (sec):"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry's faces don't contain any area."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry doesn't contain any faces."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't inherit from Spatial."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain face geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emitter"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Points:"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points+Normal (Directed)"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Volume"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Source: "
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "A processor material of type 'ParticlesMaterial' is required."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generating AABB"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generate Visibility AABB"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Point from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Out-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove In-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point to Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Split Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Point in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move In-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Out-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Select Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Shift+Drag: Select Control Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Click: Add Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Left Click: Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Right Click: Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Select Control Points (Shift+Drag)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point (in empty space)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Close Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
+msgid "Options"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Angles"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Lengths"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Curve Point #"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Point Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve In Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Out Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Path"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Path Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Out-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove In-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/physical_bone_plugin.cpp
+msgid "Move Joint"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"The skeleton property of the Polygon2D does not point to a Skeleton2D node"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"No texture in this polygon.\n"
+"Set a texture to be able to edit UV."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Polygon 2D has internal vertices, so it can no longer be edited in the "
+"viewport."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon & UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Invalid Polygon (need 3 different vertices)"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Add Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint Bone Weights"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Open Polygon 2D UV editor."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygon 2D UV Editor"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygons"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Command: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift: Move All"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Command: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Ctrl: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Ctrl: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Rotate Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Scale Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create a custom polygon. Enables custom polygon rendering."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Remove a custom polygon. If none remain, custom polygon rendering is "
+"disabled."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Unpaint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Radius:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy Polygon to UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy UV to Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Clear UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Settings"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Enable Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Show Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Configure Grid:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones to Polygon"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ERROR: Couldn't load resource!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Add Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Rename Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Resource clipboard is empty!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Paste Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Instance:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Type:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
+msgid "Open in Editor"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Load Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ResourcePreloader"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "AnimationTree has no path set to an AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Path to AnimationPlayer is invalid"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Files"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close and save changes?"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error writing TextFile:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Could not load file at:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving file!"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error importing theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Importing"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "New Text File..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save File As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Can't obtain the script for running."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script failed reloading, check console for errors."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script is not in tool mode, will not be able to run."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"To run this script, it must inherit EditorScript and be set to tool mode."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "%s Class Reference"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter scripts"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Toggle alphabetical sorting of the method list."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter methods"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Sort"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Up"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Down"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Next script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Previous script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reopen Closed Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Soft Reload Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Copy Script Path"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reload Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close Docs"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+msgid "Run"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Into"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Over"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Break"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Continue"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Keep Debugger Open"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Debug with External Editor"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open Godot online documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search the reference documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to previous edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to next edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Discard"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Debugger"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Results"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Scripts"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Connections to method:"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
+msgid "Source"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Target"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid ""
+"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "[Ignore]"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Only resources from filesystem can be dropped."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't drop nodes because script '%s' is not used in this scene."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Lookup Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Pick Color"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Convert Case"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Uppercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Lowercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Capitalize"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Syntax Highlighter"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Go To"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Cut"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Select All"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Delete Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Left"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Right"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Comment"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold/Unfold Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Unfold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Clone Down"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Complete Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Evaluate Selection"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Trim Trailing Whitespace"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Spaces"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Tabs"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Auto Indent"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Find in Files..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Contextual Help"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Line..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Toggle Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Breakpoint"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid ""
+"This shader has been modified on on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Shader"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "This skeleton has no bones, create some children Bone2D nodes."
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Create Rest Pose from Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Rest Pose to Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Skeleton2D"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Make Rest Pose (From Bones)"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Bones to Rest Pose"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical bones"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_ik_editor_plugin.cpp
+msgid "Play IK"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Orthogonal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Aborted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "X-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Y-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Z-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Plane Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scaling: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translating: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotating %s degrees."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Keying is disabled (no key inserted)."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Animation Key Inserted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pitch"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Yaw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Size"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Objects Drawn"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Material Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Shader Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Surface Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Draw Calls"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Vertices"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Transform with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Rotation with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "No parent to instance a child at."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "This operation requires a single selected node."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Auto Orthogonal Enabled"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock View Rotation"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Normal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Wireframe"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Overdraw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Unshaded"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Environment"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Information"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View FPS"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Half Resolution"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Audio Listener"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Enable Doppler"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Cinematic Preview"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Not available when using the GLES2 renderer."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Forward"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Backwards"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Up"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Down"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Speed Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Slow Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Rotation Locked"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Note: The FPS value displayed is the editor's framerate.\n"
+"It cannot be used as a reliable indication of in-game performance."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "XForm Dialog"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Click to toggle between visibility states.\n"
+"\n"
+"Open eye: Gizmo is visible.\n"
+"Closed eye: Gizmo is hidden.\n"
+"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Nodes To Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Couldn't find a solid floor to snap the selection to."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Drag: Rotate\n"
+"Alt+Drag: Move\n"
+"Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Local Space"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Snap"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Switch Perspective/Orthogonal View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Insert Animation Key"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Toggle Freelook"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Object to Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Dialog..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "1 Viewport"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "4 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Grid"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Settings..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate Snap:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Snap (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Snap (%):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Viewport Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective FOV (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Near:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Far:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Change"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale (ratio):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Type"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pre"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Post"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Nameless gizmo"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Mesh2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Polygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "CollisionPolygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "LightOccluder2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite is empty!"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Can't convert a sprite using animation frames to mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't replace by mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create collision polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create light occluder."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Simplification: "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Shrink (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Grow (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Update Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Settings:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "No Frames Selected"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add %d Frame(s)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Unable to load images"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "ERROR: Couldn't load frame resource!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Resource clipboard is empty or not a texture!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Paste Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Empty"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation FPS"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "(empty)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animations:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "New Animation"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Speed:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Loop"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animation Frames:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add a Texture from File"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frames from a Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Horizontal:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Vertical:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select/Clear All Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Create Frames from Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "SpriteFrames"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Region Rect"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Margin"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Snap Mode:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: scene/resources/visual_shader.cpp
+msgid "None"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Pixel Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Grid Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Auto Slice"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Offset:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Step:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Sep.:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "TextureRegion"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
+msgid "Remove All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Edit Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme editing menu."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Editor Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create From Current Editor Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Toggle Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Check Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Named Sep."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Submenu"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Many"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled LineEdit"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 3"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Editable Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subtree"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has,Many,Options"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Data Type:"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Style"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Font"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Color"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme File"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Fix Invalid Tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cut Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Line Draw"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Bucket Fill"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Find Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Transpose"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Disable Autotile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Enable Priority"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Filter tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Give a TileSet resource to this TileMap to use its tiles."
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Command+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Ctrl+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Pick Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Left"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Right"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Horizontally"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Vertically"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Clear Transform"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Add Texture(s) to TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected Texture from TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Single Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Autotile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Atlas"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Next Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the next shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Previous Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the previous shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Copy bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Erase bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new rectangle."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Rectangle"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete Selected Shape"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Keep polygon inside region Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Enable snap and show grid (configurable via the Inspector)."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Display Tile Names (Hold Alt Key)"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Add or select a texture on the left panel to edit the tiles bound to it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected texture? This will remove all tiles which use it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "You haven't selected a texture to remove."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from scene? This will overwrite all current tiles."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from scene?"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Texture"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "%s file(s) were not added because was already on the list."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Drag handles to edit Rect.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete selected Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select current edited sub-tile.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"LMB: Set bit on.\n"
+"RMB: Set bit off.\n"
+"Shift+LMB: Set wildcard bit.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to use as icon, this will be also used on invalid autotile "
+"bindings.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its priority.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its z index.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Icon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Clear Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "This property can't be changed."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "TileSet"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No VCS addons are available."
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Error"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No files added to stage"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "VCS Addon is not initialized"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control System"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Initialize"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Staging area"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect new changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Modified"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Renamed"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Deleted"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Typechange"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage Selected"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage All"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Status"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "View file diffs before committing them to the latest version"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No file diff is active"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect changes in file diff"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(GLES3 only)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Output"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sampler"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set expression"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Resize VisualShader node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Uniform Name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Input Default Port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node to Visual Shader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Node(s) Moved"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Duplicate Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Input Type Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "UniformRef Name Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vertex"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Fragment"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Light"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Show resulted shader code."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Create Shader Node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Grayscale function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts HSV vector to RGB equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts RGB vector to HSV equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sepia function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Burn operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Darken operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Difference operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Dodge operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "HardLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Lighten operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Overlay operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Screen operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "SoftLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the %s comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Equal (==)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than (>)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than or Equal (>=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided scalars are equal, greater or "
+"less."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between NaN and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than (<)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than or Equal (<=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Not Equal (!=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated scalar if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF (or NaN) and a "
+"scalar parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for all shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Input parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment and light shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for light shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "E constant (2.718282). Represents the base of the natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Epsilon constant (0.00001). Smallest possible scalar number."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Phi constant (1.618034). Golden ratio."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/4 constant (0.785398) or 45 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/2 constant (1.570796) or 90 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi constant (3.141593) or 180 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Tau constant (6.283185) or 360 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sqrt2 constant (1.414214). Square root of 2."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the absolute value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Constrains a value to lie between two further values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in radians to degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-e Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer less than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Computes the fractional part of the argument."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse of the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the greater of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the lesser of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the opposite value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the value of the first parameter raised to the power of the second."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in degrees to radians."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest even integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Clamps the value between 0.0 and 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Extracts the sign of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the truncated value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds scalar to scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts scalar from scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the cubic texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Cubic texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup with triplanar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Calculate the outer product of a pair of vectors.\n"
+"\n"
+"OuterProduct treats the first parameter 'c' as a column vector (matrix with "
+"one column) and the second parameter 'r' as a row vector (matrix with one "
+"row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix "
+"whose number of rows is the number of components in 'c' and whose number of "
+"columns is the number of components in 'r'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes transform from four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes transform to four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the determinant of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the inverse of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the transpose of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies transform by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes vector from three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes vector to three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the cross product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the distance between two points."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the dot product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the same direction as a reference vector. "
+"The function has three vector parameters : N, the vector to orient, I, the "
+"incident vector, and Nref, the reference vector. If the dot product of I and "
+"Nref is smaller than zero the return value is N. Otherwise -N is returned."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the length of a vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors using scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the normalize product of vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the direction of reflection ( a : incident "
+"vector, b : normal vector )."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the vector that points in the direction of refraction."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( vector(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds vector to vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts vector from vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, with custom amount of input and "
+"output ports. This is a direct injection of code into the vertex/fragment/"
+"light function, do not use it to write the function declarations inside."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"resulted shader. You can place various function definitions inside and call "
+"it later in the Expressions. You can also declare varyings, uniforms and "
+"constants."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "A reference to an existing uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Scalar derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Vector derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "VisualShader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Edit Visual Property"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Mode Changed"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Runnable"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Delete preset '%s'?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"Export templates seem to be missing or invalid."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"This might be due to a configuration issue in the export preset or your "
+"export settings."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Release"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Exporting All"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "The given export path doesn't exist:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing/corrupted:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Presets"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_settings_editor.cpp
+msgid "Add..."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"If checked, the preset will be available for use in one-click deploy.\n"
+"Only one preset per platform may be marked as runnable."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Path"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export all resources in the project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected scenes (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected resources (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources to export:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to export non-resource files/folders\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to exclude files/folders from project\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Features"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Custom (comma-separated):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Feature List:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Text"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Compiled"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Encrypted (Provide Key Below)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Invalid Encryption Key (must be 64 characters long)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Encryption Key (256-bits as hex):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export PCK/Zip"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export mode?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export All"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_manager.cpp
+msgid "ZIP File"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Godot Game Pack"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Manage Export Templates"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export With Debug"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "The path specified doesn't exist."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error opening package file (it's not in ZIP format)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose an empty folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose a \"project.godot\" or \".zip\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "This directory already contains a Godot project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Game Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Imported Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid Project Name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "There is already a folder in this path with the specified name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "It would be a good idea to name your project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid project path (changed anything?)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Couldn't load project.godot in project path (error %d). It may be missing or "
+"corrupted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't edit project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Rename Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import Existing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install Project:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Name:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Installation Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 3.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Higher visual quality\n"
+"All features available\n"
+"Incompatible with older hardware\n"
+"Not recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 2.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Lower visual quality\n"
+"Some features not available\n"
+"Works on most hardware\n"
+"Recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer can be changed later, but scenes may need to be adjusted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Unnamed Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Missing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error: Project is missing on the filesystem."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't open project at '%s'."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to open more than one project?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file does not specify the version of Godot "
+"through which it was created.\n"
+"\n"
+"%s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file was generated by an older engine "
+"version, and needs to be converted for this version:\n"
+"\n"
+"%s\n"
+"\n"
+"Do you want to convert it?\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: no main scene defined.\n"
+"Please edit the project and set the main scene in the Project Settings under "
+"the \"Application\" category."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: Assets need to be imported.\n"
+"Please edit the project to trigger the initial import."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to run %d projects at once?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove %d projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove this project from the list?\n"
+"The project folder's contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove all missing projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Language changed.\n"
+"The interface will update after restarting the editor or project manager."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Are you sure to scan %s folders for existing Godot projects?\n"
+"This could take a while."
+msgstr ""
+
+#. TRANSLATORS: This refers to the application where users manage their Godot projects.
+#: editor/project_manager.cpp
+msgid "Project Manager"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Projects"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Last Modified"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Select a Folder to Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Remove Missing"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Templates"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Restart Now"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't run project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"You currently don't have any projects.\n"
+"Would you like to explore official example projects in the Asset Library?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The search box filters projects by name and last path component.\n"
+"To filter projects by name and full path, the query must contain at least "
+"one `/` character."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Key "
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "An action with the name '%s' already exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Rename Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Action deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "All Devices"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Press a Key..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 1"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 2"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Axis Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Global Property"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Select a setting item first!"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "No property '%s' exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Setting '%s' is internal, and it can't be deleted."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Delete Item"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Error saving settings."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Settings saved OK."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Moved Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override for Feature"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Remapped Path"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resource Remap Add Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Resource Remap Language"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap Option"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter Mode"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Project Settings (project.godot)"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "General"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override For..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "The editor must be restarted for changes to take effect."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Input Map"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Localization"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resources:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps by Locale:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locale"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show All Locales"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show Selected Locales Only"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Filter mode:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "AutoLoad"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Plugins"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Preset..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Zero"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing In-Out"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing Out-In"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "File..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Dir..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Assign"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Select Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Error loading file: Not a resource!"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Pick a Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Bit %d, val %d."
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Property"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Virtual Method"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Method"
+msgstr ""
+
+#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Batch Rename"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Replace:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Prefix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Suffix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Use Regular Expressions"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Advanced Options"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Substitute"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node's parent name, if available"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node type"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Current scene name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Root node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Sequential integer counter.\n"
+"Compare counter options."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Per-level Counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "If set, the counter restarts for each group of child nodes."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Initial value for the counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Step"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Amount by which counter is incremented for each node"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Padding"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Minimum number of digits for the counter.\n"
+"Missing digits are padded with leading zeros."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Post-Process"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Keep"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "PascalCase to snake_case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "snake_case to PascalCase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Lowercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Uppercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Reset"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Regular Expression Error:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "At character %s"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent Node"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Reparent Location (Select new Parent):"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Keep Global Transform"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Run Mode:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Current Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene Arguments:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Scene Run Settings"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "No parent to instance the scenes at."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error loading scene from %s"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot instance the scene '%s' because the current scene exists within one "
+"of its nodes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Scene(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Replace with Branch Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Child Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on the tree root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Node In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Nodes In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Duplicate Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Node must belong to the edited scene to become root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instantiated scenes can't become root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make node as Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes and any children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete the root node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\" and its children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can not perform with the root node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on instanced scenes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Save New Scene As..."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Disabling \"editable_instance\" will cause all properties of the node to be "
+"reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Enabling \"Load As Placeholder\" will disable \"Editable Children\" and "
+"cause all properties of the node to be reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "New Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Create Root Node:"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "2D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "3D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "User Interface"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Other Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes from a foreign scene!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes the current scene inherits from!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remove Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change type of node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Couldn't save new scene. Likely dependencies (instances) couldn't be "
+"satisfied."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error saving scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error duplicating scene to save it."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Sub-Resources"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Editable Children"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Load As Placeholder"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Open Documentation"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot attach a script: there are no languages registered.\n"
+"This is probably because this editor was built with all language modules "
+"disabled."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add Child Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Expand/Collapse All"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change Type"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Reparent to New Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Merge From Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Save Branch as Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Copy Node Path"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete (No Confirm)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add/Create a New Node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Instance a scene file as a Node. Creates an inherited scene if no root node "
+"exists."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach a new or existing script to the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach the script from the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remote"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance? (No Undo!)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visible"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Unlock Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Button Group"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "(Connecting From)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node configuration warning:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s) and %s group(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is in %s group(s).\n"
+"Click to show groups dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Open Script:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is locked.\n"
+"Click to unlock it."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Children are not selectable.\n"
+"Click to make selectable."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visibility"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"AnimationPlayer is pinned.\n"
+"Click to unpin."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Invalid node name, the following characters are not allowed:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Rename Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Scene Tree (Nodes):"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node Configuration Warning!"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Select a Node"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Filename is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is not local."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid base path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "A directory with the same name exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File does not exist."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid extension."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Wrong extension chosen."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading template '%s'"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error - Could not create script in filesystem."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading script from %s"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Overrides"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "N/A"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script / Choose Location"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File exists, it will be reused."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid class name."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid inherited parent name or path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script path/name is valid."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Allowed: a-z, A-Z, 0-9, _ and ."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in script (into scene file)."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will create a new script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will load an existing script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script file already exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid ""
+"Note: Built-in scripts have some limitations and can't be edited using an "
+"external editor."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Class Name:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Template:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in Script:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Attach Node Script"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Remote "
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Bytes:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Warning:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Trace"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Errors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Child process connected."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Copy Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Video RAM"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Skip Breakpoints"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Previous Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Next Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Frames"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Network Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitor"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Value"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Pick one or more items from the list to display the graph."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "List of Video Memory Usage by Resource:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Total:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export list to a CSV file"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Resource Path"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Type"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Format"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Usage"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Misc"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control Type:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Live Edit Root:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Set From Tree"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export measures as CSV"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Erase Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Restore Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Change Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Editor Settings"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Shortcuts"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Binding"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Light Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change AudioStreamPlayer3D Emission Angle"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera FOV"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera Size"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Notifier AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Particles AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Probe Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Sphere Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Box Shape Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Ray Shape Length"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Height"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Inner Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Outer Radius"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select the dynamic library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select dependencies of the library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Remove current entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Double click to create a new entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform:"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dynamic Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Add an architecture entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "GDNativeLibrary"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Enabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Disabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Libraries: "
+msgstr ""
+
+#: modules/gdnative/register_types.cpp
+msgid "GDNative"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Step argument is zero!"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not a script with an instance"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a script"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a resource file"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (missing @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (can't load script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (invalid script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary (invalid subclasses)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Object can't provide a length."
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Plane:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Floor:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Delete Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paste Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paint"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Grid Map"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Snap View"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Disabled"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Above"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Below"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit X Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Y Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Z Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Clear Rotation"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Paste Selects"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clear Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Settings"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Pick Distance:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Filter meshes"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Begin Bake"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Preparing data structures"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Generate buffers"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Direct lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Indirect lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Post processing"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Plotting lightmaps"
+msgstr ""
+
+#: modules/mono/csharp_script.cpp
+msgid "Class name can't be a reserved keyword"
+msgstr ""
+
+#: modules/mono/mono_gd/gd_mono_utils.cpp
+msgid "End of inner exception stack trace"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Bake NavMesh"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Clear the navigation mesh."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Setting up Configuration..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Calculating grid size..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Marking walkable triangles..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Constructing compact heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Eroding walkable area..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Partitioning..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating contours..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating polymesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Converting to native navigation mesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Navigation Mesh Generator Setup:"
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Parsing Geometry..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Done!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"A node yielded without working memory, please read the docs on how to yield "
+"properly!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Node yielded, but did not return a function state in the first working "
+"memory."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Return value must be assigned to first element of node working memory! Fix "
+"your node please."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Node returned an invalid sequence output: "
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Found sequence bit but not the node in the stack, report bug!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Stack overflow with stack depth: "
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Signal Arguments"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Default Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Override an existing built-in function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Variables:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new variable."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Signals:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new signal."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name is not a valid identifier:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name already in use by another func/var/signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete input port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Expression"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Duplicate VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Preload Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node(s) From Tree"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid ""
+"Can't drop properties because script '%s' is not used in this scene.\n"
+"Drop holding 'Shift' to just copy the signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Getter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Setter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Move Node(s)"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Disconnect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Data"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Sequence"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Script already has function '%s'"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Input Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Resize Comment"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't copy the function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Clipboard is empty!"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function with a function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function of nodes from nodes of multiple functions."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select at least one node with sequence port."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Try to only have one sequence input in selection."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Variable:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Tool:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Members:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Nodes..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "function_name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select or create a function to edit its graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete Selected"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Find Node Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Copy Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Cut Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Refresh Graph"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit Member"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Input type not iterable: "
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid: "
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name."
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Base object is not a Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Path does not lead Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name '%s' in node %s."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid argument of type: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid arguments: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableGet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableSet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "Custom node has no _step() method, can't process graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ""
+"Invalid return value from _step(), must be integer (seq out), or string "
+"(error)."
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search VisualScript"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Get %s"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Set %s"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package name is missing."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package segments must be of non-zero length."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' is not allowed in Android application package names."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A digit cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The package must have at least one '.' separator."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Select device from the list"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find the 'apksigner' tool."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build template not installed in the project. Install it from the "
+"Project menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Debug keystore not configured in the Editor Settings nor in the preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Release keystore incorrectly configured in the export preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A valid Android SDK path is required in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid Android SDK path in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'platform-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK platform-tools' adb command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Please check in the Android SDK directory specified in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'build-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK build-tools' apksigner command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid public key for APK expansion."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid package name:"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
+"project setting (changed in Godot 3.2.2).\n"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Use Custom Build\" must be enabled to use the plugins."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
+"\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android App Bundle requires the *.aab extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "APK Expansion not compatible with Android App Bundle."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android APK requires the *.apk extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Trying to build from a custom built template, but no version info for it "
+"exists. Please reinstall from the 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build version mismatch:\n"
+" Template installed: %s\n"
+" Godot Version: %s\n"
+"Please reinstall Android build template from 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Building Android Project (gradle)"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Building of Android project failed, check output for the error.\n"
+"Alternatively visit docs.godotengine.org for Android build documentation."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Moving output"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Unable to copy and rename export file, check gradle project directory for "
+"outputs."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Identifier is missing."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "The character '%s' is not allowed in Identifier."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "App Store Team ID not specified - cannot configure the project."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Invalid Identifier:"
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Required icon is not specified in the preset."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Stop HTTP Server"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run in Browser"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run exported HTML in the system's default browser."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not write file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not open template for export:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Invalid export template:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read custom HTML shell:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read boot splash image file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Using default boot splash image."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package short name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package unique name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package publisher display name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid product GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid publisher GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid background color."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid Store Logo image dimensions (should be 50x50)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid splash screen image dimensions (should be 620x300)."
+msgstr ""
+
+#: scene/2d/animated_sprite.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite to display frames."
+msgstr ""
+
+#: scene/2d/canvas_modulate.cpp
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instanced "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+
+#: scene/2d/collision_object_2d.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
+"define its shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "An empty CollisionPolygon2D has no effect on collision."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"CollisionShape2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"A shape must be provided for CollisionShape2D to function. Please create a "
+"shape resource for it!"
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"Polygon-based shapes are not meant be used nor edited directly through the "
+"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
+msgstr ""
+
+#: scene/2d/cpu_particles_2d.cpp
+msgid ""
+"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node B must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Joint is not connected to two PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be different PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/light_2d.cpp
+msgid ""
+"A texture with the shape of the light must be supplied to the \"Texture\" "
+"property."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid ""
+"An occluder polygon must be set (or drawn) for this occluder to take effect."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"A NavigationPolygon resource must be set or created for this node to work. "
+"Please set a property or draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
+"node. It only provides navigation data."
+msgstr ""
+
+#: scene/2d/parallax_layer.cpp
+msgid ""
+"ParallaxLayer node only works when set as child of a ParallaxBackground node."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles2D node instead. You can use the \"Convert to "
+"CPUParticles\" option for this purpose."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
+msgid ""
+"A material to process the particles is not assigned, so no behavior is "
+"imprinted."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"Particles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/path_2d.cpp
+msgid "PathFollow2D only works when set as a child of a Path2D node."
+msgstr ""
+
+#: scene/2d/physics_body_2d.cpp
+msgid ""
+"Size changes to RigidBody2D (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/2d/remote_transform_2d.cpp
+msgid "Path property must point to a valid Node2D node to work."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "This Bone2D chain should end at a Skeleton2D node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid ""
+"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
+msgstr ""
+
+#: scene/2d/tile_map.cpp
+msgid ""
+"TileMap with Use Parent on needs a parent CollisionObject2D to give shapes "
+"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
+"KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/visibility_notifier_2d.cpp
+msgid ""
+"VisibilityEnabler2D works best when used with the edited scene root directly "
+"as parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRCamera must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRController must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The controller ID must not be 0 or this controller won't be bound to an "
+"actual controller."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRAnchor must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The anchor ID must not be 0 or this anchor won't be bound to an actual "
+"anchor."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVROrigin requires an ARVRCamera child node."
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Finding meshes and lights"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing geometry (%d/%d)"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing environment"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Generating capture"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Saving lightmaps"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Done"
+msgstr ""
+
+#: scene/3d/collision_object.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape or CollisionPolygon as a child to define "
+"its shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid ""
+"CollisionPolygon only serves to provide a collision shape to a "
+"CollisionObject derived node. Please only use it as a child of Area, "
+"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid "An empty CollisionPolygon has no effect on collision."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"CollisionShape only serves to provide a collision shape to a CollisionObject "
+"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
+"KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"A shape must be provided for CollisionShape to function. Please create a "
+"shape resource for it."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"Plane shapes don't work well and will be removed in future versions. Please "
+"don't use them."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"ConcavePolygonShape doesn't support RigidBody in another mode than static."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid "Nothing is visible because no mesh has been assigned."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid ""
+"CPUParticles animation requires the usage of a SpatialMaterial whose "
+"Billboard Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Plotting Meshes"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Finishing Plot"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid ""
+"GIProbes are not supported by the GLES2 video driver.\n"
+"Use a BakedLightmap instead."
+msgstr ""
+
+#: scene/3d/light.cpp
+msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid "A NavigationMesh resource must be set or created for this node to work."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid ""
+"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
+"It only provides navigation data."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
+"\" option for this purpose."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Nothing is visible because meshes have not been assigned to draw passes."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Particles animation requires the usage of a SpatialMaterial whose Billboard "
+"Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid "PathFollow only works when set as a child of a Path node."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid ""
+"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
+"parent Path's Curve resource."
+msgstr ""
+
+#: scene/3d/physics_body.cpp
+msgid ""
+"Size changes to RigidBody (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node B must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Joint is not connected to any PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be different PhysicsBodies"
+msgstr ""
+
+#: scene/3d/remote_transform.cpp
+msgid ""
+"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
+"derived node to work."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid "This body will be ignored until you set a mesh."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid ""
+"Size changes to SoftBody will be overridden by the physics engine when "
+"running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/sprite_3d.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite3D to display frames."
+msgstr ""
+
+#: scene/3d/vehicle_body.cpp
+msgid ""
+"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
+"it as a child of a VehicleBody."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"WorldEnvironment requires its \"Environment\" property to contain an "
+"Environment to have a visible effect."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
+"this environment's Background Mode to Canvas (for 2D scenes)."
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "On BlendTree node '%s', animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "Animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "In node '%s', invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Nothing connected to input '%s' of node '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "No root AnimationNode for the graph is set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path to an AnimationPlayer node containing animations is not set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path set for AnimationPlayer does not lead to an AnimationPlayer node."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "The AnimationPlayer root node is not a valid node."
+msgstr ""
+
+#: scene/animation/animation_tree_player.cpp
+msgid "This node has been deprecated. Use AnimationTree instead."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid ""
+"Color: #%s\n"
+"LMB: Set color\n"
+"RMB: Remove preset"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Pick a color from the editor window."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "HSV"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Raw"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Switch between hexadecimal and code values."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Add current color as a preset."
+msgstr ""
+
+#: scene/gui/container.cpp
+msgid ""
+"Container by itself serves no purpose unless a script configures its "
+"children placement behavior.\n"
+"If you don't intend to add a script, use a plain Control node instead."
+msgstr ""
+
+#: scene/gui/control.cpp
+msgid ""
+"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
+"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Alert!"
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Please Confirm..."
+msgstr ""
+
+#: scene/gui/file_dialog.cpp
+msgid "Must use a valid extension."
+msgstr ""
+
+#: scene/gui/graph_edit.cpp
+msgid "Enable grid minimap."
+msgstr ""
+
+#: scene/gui/popup.cpp
+msgid ""
+"Popups will hide by default unless you call popup() or any of the popup*() "
+"functions. Making them visible for editing is fine, but they will hide upon "
+"running."
+msgstr ""
+
+#: scene/gui/range.cpp
+msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
+msgstr ""
+
+#: scene/gui/scroll_container.cpp
+msgid ""
+"ScrollContainer is intended to work with a single child control.\n"
+"Use a container as child (VBox, HBox, etc.), or a Control and set the custom "
+"minimum size manually."
+msgstr ""
+
+#: scene/gui/tree.cpp
+msgid "(Other)"
+msgstr ""
+
+#: scene/main/scene_tree.cpp
+msgid ""
+"Default Environment as specified in Project Settings (Rendering -> "
+"Environment -> Default Environment) could not be loaded."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid ""
+"This viewport is not set as render target. If you intend for it to display "
+"its contents directly to the screen, make it a child of a Control so it can "
+"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
+"texture to some node for display."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid "Viewport size must be greater than 0 to render anything."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid ""
+"The sampler port is connected but not used. Consider changing the source to "
+"'SamplerPort'."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for preview."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for shader."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid comparison function for that type."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to uniform."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Varyings can only be assigned in vertex function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Constants cannot be modified."
+msgstr ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index c5b4f3c701..9770daf14a 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -16,17 +16,18 @@
# Jiyoon Kim <kimjiy@dickinson.edu>, 2019.
# Ervin <zetsmart@gmail.com>, 2019.
# Tilto_ <tilto0822@develable.xyz>, 2020.
-# Myeongjin Lee <aranet100@gmail.com>, 2020.
+# Myeongjin Lee <aranet100@gmail.com>, 2020, 2021.
# Doyun Kwon <caen4516@gmail.com>, 2020.
# Jun Hyung Shin <shmishmi79@gmail.com>, 2020.
# Yongjin Jo <wnrhd114@gmail.com>, 2020.
# Yungjoong Song <yungjoong.song@gmail.com>, 2020.
+# Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-31 23:15+0000\n"
-"Last-Translator: Yungjoong Song <yungjoong.song@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
"Language: ko\n"
@@ -34,7 +35,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.3.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -662,7 +663,7 @@ msgstr "복사할 트랙 선택"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "복사"
@@ -704,7 +705,7 @@ msgstr "행 번호:"
#: editor/code_editor.cpp
msgid "%d replaced."
-msgstr "%d개가 바뀌었습니다."
+msgstr "%d개 찾아 바꿈."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
@@ -1044,22 +1045,23 @@ msgid "Owners Of:"
msgstr "소유자:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "프로젝트에서 선택한 파일을 삭제할까요? (되돌릴 수 없습니다)"
+msgstr ""
+"프로젝트에서 선택된 파일을 제거하시겠습니다? (되돌릴 수 없음)\n"
+"시스템 휴지통에서 제거된 파일을 찾고 복원할 수 있습니다."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
-"삭제하려는 파일은 다른 리소스가 동작하기 위해 필요한 파일입니다.\n"
-"무시하고 삭제할까요? (되돌릴 수 없습니다)"
+"제거하려는 파일은 다른 리소스가 동작하기 위해 필요합니다.\n"
+"무시하고 제거하시겠습니까? (되돌릴 수 없음)\n"
+"시스템 휴지통에서 제거된 파일을 찾고 복원할 수 있습니다."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1864,8 +1866,8 @@ msgid "Open a File or Directory"
msgstr "디렉토리 또는 파일 열기"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "저장"
@@ -2314,6 +2316,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"편집기 레이아웃의 저장을 하려는 동안 오류가 발생했습니다.\n"
+"편집기의 사용자 데이터 경로가 쓰기 가능한지 확인해주세요."
#: editor/editor_node.cpp
msgid ""
@@ -2321,15 +2325,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"기본 편집기 레이아웃이 덮어 쓰여져 있습니디.\n"
+"기본 레이아웃을 원래 설정으로 복구하려면, 레이아웃 삭제 옵션을 사용하여 기본 "
+"레이아웃을 삭제하세요."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "레이아웃 이름을 찾을 수 없습니다!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "기본 레이아웃을 초기화하였습니다."
+msgstr "기본 레이아웃을 원래 설정으로 복구하였습니다."
#: editor/editor_node.cpp
msgid ""
@@ -2384,7 +2390,7 @@ msgstr "실행할 씬이 설정되지 않았습니다."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "씬을 실행하기 전에 저장..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2507,8 +2513,8 @@ msgid ""
"This option is deprecated. Situations where refresh must be forced are now "
"considered a bug. Please report."
msgstr ""
-"이 설정은 제거되었습니다. 강제로 새로고침해야 하는 상황은 이제 버그입니다. 신"
-"고해주세요."
+"이 옵션은 사용되지 않습니다. 강제로 새로 고침해야 하는 상황은 이제 버그로 간"
+"주됩니다. 신고해주세요."
#: editor/editor_node.cpp
msgid "Pick a Main Scene"
@@ -2529,8 +2535,9 @@ msgstr ""
"실패했습니다."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "다음 경로에서 애드온 플러그인을 찾을 수 없음: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr ""
+"다음 경로에서 애드온 플러그인을 위한 스크립트 필드를 찾을 수 없습니다: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2893,17 +2900,16 @@ msgid "Synchronize Script Changes"
msgstr "스크립트 변경사항 동기화"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"이 설정이 활성화된 경우, 어떤 스크립트든 저장하면 실행중인 게임에도 새로고침"
-"되어 반영됩니다.\n"
-"원격 장치에서 사용중인 경우 네트워크 파일 시스템 기능을 활성화하면 더욱 효율"
-"적입니다."
+"이 옵션이 활성화된 경우, 어떤 스크립트든지 저장되면 실행 중인 프로젝트를 다"
+"시 불러오게 됩니다.\n"
+"기기에서 원격으로 사용 중인 경우, 네트워크 파일 시스템 옵션이 활성화되어 있다"
+"면 더욱 효율적입니다."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2958,14 +2964,6 @@ msgid "Help"
msgstr "도움말"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "검색"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "온라인 문서"
@@ -3127,6 +3125,24 @@ msgid "Open & Run a Script"
msgstr "스크립트 열기 & 실행"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"다음 파일은 디스크에 있는 게 더 최신입니다.\n"
+"조치을 어떻게 취해야 합니까?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "새로고침"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "다시 저장"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "새 상속 씬"
@@ -3335,7 +3351,7 @@ msgstr "유일하게 만들기"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "붙여넣기"
@@ -3373,14 +3389,14 @@ msgid "Add Key/Value Pair"
msgstr "키/값 쌍 추가"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
-"이 플랫폼으로 실행할 수 있는 내보내기 프리셋이 없습니다.\n"
-"내보내기 메뉴에서 실행할 수 있는 프리셋을 추가해주세요."
+"이 플랫폼을 위한 실행할 수 있는 내보내기 프리셋이 없습니다.\n"
+"내보내기 메뉴에서 실행할 수 있는 프리셋을 추가하거나 기존 프리셋을 실행할 수 "
+"있도록 지정해주세요."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3649,6 +3665,12 @@ msgstr ""
"요."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"이 파일에 대해 가져 오기가 비활성화되었으며 편집을 위해 열 수 없습니다."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "리소스 루트를 옮기거나 이름을 바꿀 수 없습니다."
@@ -3693,6 +3715,11 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"다음 파일이나 폴더가 대상 위치 '%s'의 항목과 충돌합니다:\n"
+"\n"
+"%s\n"
+"\n"
+"이를 덮어쓰시겠습니까?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3773,9 +3800,8 @@ msgid "Duplicate..."
msgstr "복제..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "오토로드 이동"
+msgstr "휴지통으로 이동"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3886,19 +3912,16 @@ msgid "Searching..."
msgstr "검색 중..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d개 일치."
+msgstr "파일 %d$2개 중 %d$1개 일치."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d개 일치."
+msgstr "파일 %d$2개 중 %d$1개 일치."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d개 일치."
+msgstr "파일 %d$2개 중 %d$1개 일치."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4034,6 +4057,22 @@ msgstr "`post_import()` 메소드에서 Node에서 상속받은 객체를 반환
msgid "Saving..."
msgstr "저장 중..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "임포터 선택"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "임포터:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "기본값으로 재설정"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "파일 유지 (가져오기 없음)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "파일 %d개"
@@ -4997,8 +5036,8 @@ msgid "Got:"
msgstr "받음:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "sha256 해시 확인 실패"
+msgid "Failed SHA-256 hash check"
+msgstr "SHA-256 해시 확인 실패"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5101,7 +5140,6 @@ msgid "Sort:"
msgstr "정렬:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "카테고리:"
@@ -5130,14 +5168,12 @@ msgid "Assets ZIP File"
msgstr "애셋 ZIP 파일"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"라이트맵 이미지의 저장 경로를 파악할 수 없습니다.\n"
-"(같은 경로에 이미지를 저장할 수 있도록) 씬을 저장하거나, BakedLightmap 속성에"
-"서 저장 경로를 지정하세요."
+"라이트맵 이미지를 위한 저장 경로를 결정할 수 없습니다.\n"
+"당신의 씬을 저장하고 다시 시도하세요."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5154,26 +5190,30 @@ msgstr "라이트맵 이미지 생성 실패. 작성 가능한 경로인지 확
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
msgstr ""
+"라이트맵 크기를 결정하는 데 실패했습니다. 최대 라이트맵 크기가 너무 작나요?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"일부 메시가 잘못되었습니다. UV2 채널 값이 [0.0,1.0] 정사각형 영역 안에 포함되"
+"어 있는지 확인해주세요."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"Godot 편집기가 레이 트레이싱 지원 없이 빌드되어 있어, 라이트맵이 구워질 수 없"
+"습니다."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "라이트맵 굽기"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "템플릿 파일 선택"
+msgstr "라이트맵을 구울 파일 선택:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5242,50 +5282,43 @@ msgstr "수평 및 수직 가이드 만들기"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr "CanvasItem \"%s\" Pivot Offset (%d, %d)로 설정"
+msgstr "CanvasItem \"%s\"의 피벗 오프셋을 (%d, %d)로 설정"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "CanvasItem 회전"
+msgstr "CanvasItem %d개 회전"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "CanvasItem 회전"
+msgstr "CanvasItem \"%s\"를 %d도로 회전"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "CanvasItem 이동"
+msgstr "CanvasItem \"%s\" 앵커 이동"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Node2D \"%s\"를 (%s, %s)로 크기 조절"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "컨트롤 \"%s\"를 (%d, %d)로 크기 조절"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "CanvasItem 규모"
+msgstr "CanvasItem %d개 크기 조절"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "CanvasItem 규모"
+msgstr "CanvasItem \"%s\"를 (%s, %s)로 크기 조절"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "CanvasItem 이동"
+msgstr "CanvasItem %d개 이동"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "CanvasItem 이동"
+msgstr "CanvasItem \"%s\"를 (%d, %d)로 이동"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5491,7 +5524,7 @@ msgstr "회전모드"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr "크기조절 모드"
+msgstr "크기 조절 모드"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5540,7 +5573,7 @@ msgstr "회전 스냅 사용"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Scale Snap"
-msgstr "스마트 스냅 사용"
+msgstr "크기 조절 스냅 사용"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
@@ -5658,11 +5691,11 @@ msgstr "선택 항목 중앙으로"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr "선택 항목 전체 화면으로"
+msgstr "프레임 선택"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr "캔버스 규모 미리 보기"
+msgstr "캔버스 크기 조절 미리 보기"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
@@ -5924,7 +5957,7 @@ msgstr "기울기 편집됨"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr "항목 %d"
+msgstr "항목 %d개"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
@@ -6264,9 +6297,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "ParticlesMaterial 프로세스 머티리얼 안에만 점을 설정할 수 있습니다"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "CPU파티클로 변환"
+msgstr "CPUParticles2D로 변환"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6523,7 +6555,7 @@ msgstr "폴리곤 변형"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Paint Bone Weights"
-msgstr "본 가중치 칠"
+msgstr "본 가중치 칠하기"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Open Polygon 2D UV editor."
@@ -6554,18 +6586,16 @@ msgid "Move Points"
msgstr "점 이동"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "드래그: 회전"
+msgstr "Command: 회전"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: 모두 이동"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: 크기 조절"
+msgstr "Shift+Command: 크기 조절"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6612,14 +6642,12 @@ msgid "Radius:"
msgstr "반지름:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "폴리곤 & UV 만들기"
+msgstr "폴리곤을 UV로 복사"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Polygon2D로 변환"
+msgstr "UV를 폴리곤으로 복사"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -6878,7 +6906,7 @@ msgstr "모두 저장"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
-msgstr "스크립트 새로고침"
+msgstr "스크립트 일반 새로고침"
#: editor/plugins/script_editor_plugin.cpp
msgid "Copy Script Path"
@@ -6921,13 +6949,21 @@ msgstr "문서 닫기"
msgid "Run"
msgstr "실행"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "검색"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "프로시저 단위 실행"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
-msgstr "한 단계식 코드 실행"
+msgstr "한 단계씩 코드 실행"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
@@ -6948,11 +6984,11 @@ msgstr "외부 편집기로 디버깅"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr "Godot 온라인 문서를 열."
+msgstr "Godot 온라인 문서를 엽니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr "참조 문서 검색."
+msgstr "참조 문서를 검색합니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
@@ -6974,16 +7010,6 @@ msgstr ""
"해당 파일은 디스크에 있는 게 더 최신입니다.\n"
"어떻게 할 건가요?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "새로고침"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "다시 저장"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "디버거"
@@ -7051,11 +7077,11 @@ msgstr "대소문자 변환"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr "대문자로 바꾸기"
+msgstr "대문자로"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr "소문자로 바꾸기"
+msgstr "소문자로"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
@@ -7079,8 +7105,8 @@ msgstr "중단점"
msgid "Go To"
msgstr "이동"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "잘라내기"
@@ -7107,7 +7133,7 @@ msgstr "주석 토글"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr "행 펼치기/접기"
+msgstr "행 접기/펼치기"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7123,7 +7149,7 @@ msgstr "아래로 복제"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr "자동 완성"
+msgstr "상징 자동 완성"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
@@ -7131,7 +7157,7 @@ msgstr "선택 항목 평가"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr "후행 공백 문자 삭제"
+msgstr "후행 공백 문자 제거"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
@@ -7151,7 +7177,7 @@ msgstr "파일에서 찾기..."
#: editor/plugins/script_text_editor.cpp
msgid "Contextual Help"
-msgstr "상황에 맞는 도움"
+msgstr "상황에 맞는 도움말"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Bookmark"
@@ -7167,7 +7193,7 @@ msgstr "이전 북마크로 이동"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Bookmarks"
-msgstr "모든 북마크 삭제"
+msgstr "모든 북마크 제거"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function..."
@@ -7184,7 +7210,7 @@ msgstr "중단점 토글"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
-msgstr "중단점 모두 삭제"
+msgstr "중단점 모두 제거"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Next Breakpoint"
@@ -7303,9 +7329,8 @@ msgid "Yaw"
msgstr "요"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "크기: "
+msgstr "크기"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7453,27 +7478,27 @@ msgstr "GLES2 렌더러에서 사용할 수 없습니다."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "자유 시점 왼쪽으로 가기"
+msgstr "자유 시점 왼쪽으로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "자유 시점 오른쪽으로 가기"
+msgstr "자유 시점 오른쪽으로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "자유 시점 앞으로 가기"
+msgstr "자유 시점 앞으로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "자유 시점 뒤로 가기"
+msgstr "자유 시점 뒤로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "자유 시점 위로 가기"
+msgstr "자유 시점 위로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "자유 시점 아래로 가기"
+msgstr "자유 시점 아래로"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
@@ -7489,6 +7514,11 @@ msgstr "뷰 회전 잠김"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7533,7 +7563,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr "로컬 스페이스 사용"
+msgstr "로컬 공간 사용"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
@@ -7590,7 +7620,7 @@ msgstr "변형"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr "객체를 바닥에 스냅"
+msgstr "개체를 바닥에 스냅"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -7598,27 +7628,27 @@ msgstr "변형 대화 상자..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr "1개 뷰포트"
+msgstr "뷰포트 1개"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr "2개 뷰포트"
+msgstr "뷰포트 2개"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr "2개 뷰포트 (다른 방식)"
+msgstr "뷰포트 2개 (다른 방식)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr "3개 뷰포트"
+msgstr "뷰포트 3개"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr "3개 뷰포트 (다른 방식)"
+msgstr "뷰포트 3개 (다른 방식)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr "4개 뷰포트"
+msgstr "뷰포트 4개"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -7803,7 +7833,7 @@ msgstr "선택한 프레임 없음"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr "%d개의 프레임 추가"
+msgstr "프레임 %d개 추가"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
@@ -7850,9 +7880,8 @@ msgid "New Animation"
msgstr "새 애니메이션"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Speed:"
-msgstr "속도 (FPS):"
+msgstr "속도:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
@@ -8110,7 +8139,7 @@ msgstr "테마 파일"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
-msgstr "선택 지우기"
+msgstr "선택 항목 지우기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Fix Invalid Tiles"
@@ -8123,7 +8152,7 @@ msgstr "선택 항목 잘라내기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
-msgstr "타일맵 칠"
+msgstr "타일맵 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Line Draw"
@@ -8135,7 +8164,7 @@ msgstr "사각 영역 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Bucket Fill"
-msgstr "채우기"
+msgstr "버킷 채우기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase TileMap"
@@ -8147,7 +8176,7 @@ msgstr "타일 찾기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr "바꾸기"
+msgstr "행렬 맞바꾸기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
@@ -8170,21 +8199,20 @@ msgid "Paint Tile"
msgstr "타일 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
-"Shift+우클릭: 선 그리기\n"
-"Shift+Ctrl+우클릭: 사각 영역 페인트"
+"Shift+좌클릭: 선 그리기\n"
+"Shift+Command+좌클릭: 사각 영역 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Ctrl+LMB: Rectangle Paint"
msgstr ""
-"Shift+우클릭: 선 그리기\n"
-"Shift+Ctrl+우클릭: 사각 영역 페인트"
+"Shift+좌클릭: 선 그리기\n"
+"Shift+Ctrl+좌클릭: 사각 영역 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Pick Tile"
@@ -8216,7 +8244,7 @@ msgstr "TileSet에 텍스처를 추가합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove selected Texture from TileSet."
-msgstr "선택한 텍스처를 TileSet에서 삭제."
+msgstr "선택한 텍스처를 TileSet에서 제거합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8256,7 +8284,7 @@ msgstr "이전 모양, 하위 타일, 혹은 타일을 선택하세요."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region"
-msgstr "지역"
+msgstr "영역"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision"
@@ -8284,7 +8312,7 @@ msgstr "Z 인덱스"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region Mode"
-msgstr "지역 모드"
+msgstr "영역 모드"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision Mode"
@@ -8316,42 +8344,39 @@ msgstr "Z 인덱스 모드"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
-msgstr "비트 마스크 복사."
+msgstr "비트 마스크를 복사합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Paste bitmask."
-msgstr "비트 마스크 붙여넣기."
+msgstr "비트 마스크를 붙여넣습니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
-msgstr "비트 마스크 지우기."
+msgstr "비트 마스크를 지웁니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new rectangle."
-msgstr "새로운 사각형을 만듭니다."
+msgstr "새로운 사각 영역을 만듭니다."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "사각 영역 칠하기"
+msgstr "새 사각 영역"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "새로운 폴리곤을 만듭니다."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "폴리곤 이동"
+msgstr "새 폴리곤"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "선택 항목 삭제"
+msgstr "선택된 모양 삭제"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
-msgstr "사각형 내부에 폴리곤을 유지."
+msgstr "사각형 영역 내에 폴리곤을 유지합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
@@ -8708,7 +8733,6 @@ msgid "Add Node to Visual Shader"
msgstr "노드를 비주얼 셰이더에 추가"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
msgstr "노드 이동됨"
@@ -8730,9 +8754,8 @@ msgid "Visual Shader Input Type Changed"
msgstr "비주얼 셰이더 입력 유형 변경됨"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "Uniform 이름 설정"
+msgstr "UniformRef 이름 변경됨"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -8913,7 +8936,7 @@ msgstr "꼭짓점과 프래그먼트 셰이더 모드에 대한 '%s' 입력 매
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment and light shader modes."
-msgstr "꼭짓점과 프래그먼트 셰이더 모드에 대한 '%s' 입력 매개변수."
+msgstr "프래그먼트과 조명 셰이더 모드에 대한 '%s' 입력 매개변수."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment shader mode."
@@ -9006,7 +9029,7 @@ msgstr "매개변수의 역쌍곡탄젠트 값을 반환합니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
-msgstr "매개변수보다 크거나 같은 가장 가까운 정수를 찾아요."
+msgstr "매개변수보다 크거나 같은 가장 가까운 정수를 찾습니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Constrains a value to lie between two further values."
@@ -9034,7 +9057,7 @@ msgstr "2가 밑인 지수 함수."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
-msgstr "매개변수보다 적거나 같은 가장 가까운 정수를 찾아요."
+msgstr "매개변수보다 적거나 같은 가장 가까운 정수를 찾습니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Computes the fractional part of the argument."
@@ -9087,11 +9110,11 @@ msgstr "1.0 / 스칼라"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer to the parameter."
-msgstr "매개변수에서 가장 가까운 정수를 찾아요."
+msgstr "매개변수에서 가장 가까운 정수를 찾습니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest even integer to the parameter."
-msgstr "매개변수에서 가장 가까운 짝수 정수를 찾아요."
+msgstr "매개변수에서 가장 가까운 짝수 정수를 찾습니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Clamps the value between 0.0 and 1.0."
@@ -9146,7 +9169,7 @@ msgstr "매개변수의 쌍곡탄젠트 값을 반환합니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
-msgstr "매개변수의 절사된 값을 찾아요."
+msgstr "매개변수의 절사된 값을 찾습니다."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds scalar to scalar."
@@ -9730,8 +9753,8 @@ msgid ""
"Couldn't load project.godot in project path (error %d). It may be missing or "
"corrupted."
msgstr ""
-"프로젝트 경로에서 project.godot을 불러올 수 없습니다 (error %d). 누락되거나 "
-"손상된 모양입니다."
+"프로젝트 경로에서 project.godot을 불러올 수 없습니다 (오류 %d). 누락되거나 손"
+"상된 모양입니다."
#: editor/project_manager.cpp
msgid "Couldn't edit project.godot in project path."
@@ -9791,7 +9814,7 @@ msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "당신의 GPU 드라이버에 의해 지원되지 않습니다."
#: editor/project_manager.cpp
msgid ""
@@ -9963,6 +9986,10 @@ msgid "Projects"
msgstr "프로젝트"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "로드 중, 기다려 주세요..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "마지막으로 수정됨"
@@ -10332,6 +10359,10 @@ msgstr "오토로드"
msgid "Plugins"
msgstr "플러그인(Plugin)"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "기본값 가져오기"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "프리셋..."
@@ -10410,7 +10441,7 @@ msgstr "정규 표현식 사용"
#: editor/rename_dialog.cpp
msgid "Advanced Options"
-msgstr "고급 설정"
+msgstr "고급 옵션"
#: editor/rename_dialog.cpp
msgid "Substitute"
@@ -10442,7 +10473,7 @@ msgid ""
"Compare counter options."
msgstr ""
"순차 정수 카운터.\n"
-"카운터 설정과 비교합니다."
+"카운터 옵션과 비교합니다."
#: editor/rename_dialog.cpp
msgid "Per-level Counter"
@@ -10579,6 +10610,14 @@ msgid "Instance Child Scene"
msgstr "자식 씬 인스턴스화"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "루트 노드를 같은 씬 안으로 붙여넣을 수 없습니다."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "노드 붙여넣기"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "스크립트 떼기"
@@ -10704,6 +10743,10 @@ msgid "Attach Script"
msgstr "스크립트 붙이기"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "노드 잘라내기"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "노드 삭제"
@@ -10815,6 +10858,13 @@ msgid "Remote"
msgstr "원격"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "로컬"
@@ -11508,36 +11558,31 @@ msgstr "메시를 사용하려면 이 GridMap에 MeshLibrary 리소스를 주세
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "굽기 시작"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "데이터 구조 준비 중"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "AABB 만들기"
+msgstr "버퍼 생성"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "방향"
+msgstr "조명 방향"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "들여쓰기"
+msgstr "간접 조명"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "후처리"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "구분하는 조명:"
+msgstr "구분하는 조명"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -11549,11 +11594,11 @@ msgstr "내부 예외 스택 추적의 끝"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Bake NavMesh"
-msgstr "NavMesh 베이크"
+msgstr "NavMesh 굽기"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Clear the navigation mesh."
-msgstr "내비게이션 메시 지우기."
+msgstr "내비게이션 메시를 지웁니다."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Setting up Configuration..."
@@ -12051,15 +12096,15 @@ msgstr "목록에서 기기 선택"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr ""
+msgstr "'apksigner' 도구를 찾을 수 없습니다."
#: platform/android/export/export.cpp
msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
msgstr ""
-"프로젝트에 안드로이드 빌드 템플릿을 설치하지 않았습니다. 프로젝트 메뉴에서 설"
-"치하세요."
+"프로젝트에 Android 빌드 템플릿을 설치하지 않았습니다. 프로젝트 메뉴에서 설치"
+"하세요."
#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
@@ -12070,35 +12115,32 @@ msgid "Release keystore incorrectly configured in the export preset."
msgstr "내보내기 프리셋에 배포 keystorke가 잘못 설정되어 있습니다."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "편집기 설정에서 맞춤 빌드에 잘못된 안드로이드 SDK 경로입니다."
+msgstr "편집기 설정에서 올바른 Android SDK 경로가 필요합니다."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "편집기 설정에서 맞춤 빌드에 잘못된 안드로이드 SDK 경로입니다."
+msgstr "편집기 설정에서 잘못된 Android SDK 경로입니다."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "'platform-tools' 디렉터리가 없습니다!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Android SDK platform-tools의 adb 명령을 찾을 수 없습니다."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "편집기 설정에서 맞춤 빌드에 잘못된 안드로이드 SDK 경로입니다."
+msgstr "편집기 설정에서 지정된 Android SDK 디렉터리를 확인해주세요."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "'build-tools' 디렉터리가 없습니다!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Android SDK build-tools의 apksigner 명령을 찾을 수 없습니다."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12162,8 +12204,8 @@ msgid ""
"Trying to build from a custom built template, but no version info for it "
"exists. Please reinstall from the 'Project' menu."
msgstr ""
-"맞춤 빌드 템플릿으로 빌드하려 했으나, 버전 정보가가 없습니다. '프로젝트' 메뉴"
-"에서 다시 설치해주세요."
+"맞춤 빌드 템플릿으로 빌드하려 했으나, 버전 정보가 없습니다. '프로젝트' 메뉴에"
+"서 다시 설치해주세요."
#: platform/android/export/export.cpp
msgid ""
@@ -12172,32 +12214,34 @@ msgid ""
" Godot Version: %s\n"
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"안드로이드 빌드 버전이 맞지 않음:\n"
-" 설치한 템플릿: %s\n"
+"Android 빌드 버전이 맞지 않음:\n"
+" 설치된 템플릿: %s\n"
" Godot 버전: %s\n"
-"'프로젝트' 메뉴에서 안드로이드 빌드 템플릿을 다시 설치해주세요."
+"'프로젝트' 메뉴에서 Android 빌드 템플릿을 다시 설치해주세요."
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
-msgstr "안드로이드 프로젝트 빌드 중 (gradle)"
+msgstr "Android 프로젝트 빌드 중 (gradle)"
#: platform/android/export/export.cpp
msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"안드로이드 프로젝트의 빌드에 실패했, 출력한 오류를 확인하세요.\n"
-"또는 docs.godotengine.org에서 안드로이드 빌드 문서를 찾아 보세요."
+"Android 프로젝트의 빌드에 실패했습니다, 출력된 오류를 확인하세요.\n"
+"또는 docs.godotengine.org에서 Andoid 빌드 문서를 찾아보세요."
#: platform/android/export/export.cpp
msgid "Moving output"
-msgstr ""
+msgstr "출력 이동 중"
#: platform/android/export/export.cpp
msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"내보내기 파일을 복사하고 이름을 바꿀 수 없습니다, 출력에 대한 gradle 프로젝"
+"트 디렉터리를 확인하세요."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12347,6 +12391,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "빈 CollisionPolygon2D는 충돌에 영향을 주지 않습니다."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "잘못된 폴리곤. 적어도 '솔리드' 빌드 모드에서 점 3개가 필요합니다."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "잘못된 폴리곤. 적어도 '세그먼트' 빌드 모드에서 점 2개가 필요합니다."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12383,23 +12435,23 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "노드 A와 노드 B는 PhysicsBody2D여야 합니다"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "노드 A는 PhysicsBody2D여야 합니다"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "노드 B는 PhysicsBody2D여야 합니다"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "관절이 PhysicsBody2D 두 곳과 연결되어 있지 않습니다"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "노드 A와 노드 B는 서로 다른 PhysicsBody2D여야 합니다"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12548,27 +12600,23 @@ msgstr "ARVROrigin은 자식으로 ARVRCamera 노드가 필요합니다."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "메시 및 조명 찾는 중"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "형태 분석 중..."
+msgstr "형태 준비 중 (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "환경 보기"
+msgstr "환경 준비 중"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "라이트맵 생성 중"
+msgstr "캡처 생성 중"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "라이트맵 생성 중"
+msgstr "라이트맵 저장 중"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
@@ -12659,11 +12707,6 @@ msgstr ""
"GIProbe는 GLES2 비디오 드라이버에서 지원하지 않습니다.\n"
"대신 BakedLightmap을 사용하세요."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera는 더 이상 사용되지 않으며 Godot 4.0에서 제거됩니다."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight의 각도를 90도 이상으로 잡게되면 그림자를 투영할 수 없습니다."
@@ -12728,23 +12771,23 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
-msgstr ""
+msgstr "노드 A와 노드 B는 PhysicsBody여야 합니다"
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "노드 A는 PhysicsBody여야 합니다"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "노드 B는 PhysicsBodies여야 합니다"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
-msgstr ""
+msgstr "관절이 어떠한 PhysicsBody에도 연결되어 있지 않습니다"
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be different PhysicsBodies"
-msgstr ""
+msgstr "노드 A와 노드 B는 서로 다른 PhysicsBody여야 합니다"
#: scene/3d/remote_transform.cpp
msgid ""
@@ -12909,9 +12952,8 @@ msgid "Must use a valid extension."
msgstr "올바른 확장자를 사용해야 합니다."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "스냅 켜기"
+msgstr "그리드 미니맵을 활성화합니다."
#: scene/gui/popup.cpp
msgid ""
@@ -12969,6 +13011,8 @@ msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
+"샘플러 포트가 연결되어 있지만 사용되지 않습이다. 소스를 'SamplerPort'로 변경"
+"하는 것을 고려해주세요."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
@@ -12998,6 +13042,11 @@ msgstr "Varying은 꼭짓점 함수에만 지정할 수 있습니다."
msgid "Constants cannot be modified."
msgstr "상수는 수정할 수 없습니다."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera는 더 이상 사용되지 않으며 Godot 4.0에서 제거됩니다."
+
#~ msgid "No"
#~ msgstr "아니오"
@@ -14784,9 +14833,6 @@ msgstr "상수는 수정할 수 없습니다."
#~ msgid "Use Default Light"
#~ msgstr "기본 Light 사용"
-#~ msgid "Use Default sRGB"
-#~ msgstr "기본 sRGB 사용"
-
#~ msgid "Default Light Normal:"
#~ msgstr "기본 라이트 노말:"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index c1c872988f..e5ca1dd50c 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -5,12 +5,12 @@
# Ignas Kiela <ignaskiela@super.lt>, 2017.
# Kornelijus <kornelijus.github@gmail.com>, 2017, 2018.
# Ignotas Gražys <ignotas.gr@gmail.com>, 2020.
-# Kornelijus Tvarijanavičius <kornelitvari@protonmail.com>, 2020.
+# Kornelijus Tvarijanavičius <kornelitvari@protonmail.com>, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-09-28 11:18+0000\n"
+"PO-Revision-Date: 2021-02-21 10:51+0000\n"
"Last-Translator: Kornelijus Tvarijanavičius <kornelitvari@protonmail.com>\n"
"Language-Team: Lithuanian <https://hosted.weblate.org/projects/godot-engine/"
"godot/lt/>\n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n%10>=2 && (n%100<10 || n"
"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.5\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -650,7 +650,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1854,8 +1854,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2504,7 +2504,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2901,14 +2901,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3062,6 +3054,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3271,7 +3279,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3583,6 +3591,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3978,6 +3991,24 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Pasirinkite Nodus, kuriuos norite importuoti"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importuoti Animacijas..."
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -4762,7 +4793,6 @@ msgstr "Naujas pavadinimas:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
-#, fuzzy
msgid "Scale:"
msgstr "Skalė:"
@@ -4964,7 +4994,7 @@ msgid "Got:"
msgstr "Gauta:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5073,7 +5103,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategorija:"
@@ -6888,6 +6917,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6939,16 +6976,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7045,8 +7072,8 @@ msgstr "Sukurti"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7455,6 +7482,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9885,6 +9917,11 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Atsiųsti"
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10247,6 +10284,10 @@ msgstr ""
msgid "Plugins"
msgstr "Priedai"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10494,6 +10535,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Duplikuoti"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Atidaryti Skriptų Editorių"
@@ -10618,6 +10668,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Transition Nodas"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10727,6 +10782,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12239,6 +12301,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12494,11 +12564,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12837,10 +12902,6 @@ msgstr ""
#~ msgid "Path to Node:"
#~ msgstr "Kelias iki Nodo:"
-#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Transition Nodas"
-
#~ msgid "Line:"
#~ msgstr "Linija:"
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 09379f2903..606c690a55 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -649,7 +649,7 @@ msgstr "Izvēlēties Celiņus ko Kopēt"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopēt"
@@ -1841,8 +1841,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2477,7 +2477,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2867,14 +2867,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3028,6 +3020,23 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "Sekojošie faili netika izvilkti no paketes:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3230,7 +3239,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3534,6 +3543,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3914,6 +3928,24 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Izvēlēties Šablona Failu"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Ielādēt Noklusējumu"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Failā"
@@ -4861,7 +4893,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4965,7 +4997,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6742,6 +6773,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6793,16 +6832,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6899,8 +6928,8 @@ msgstr "Izveidot"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7312,6 +7341,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9708,6 +9742,11 @@ msgid "Projects"
msgstr "Projekta Dibinātāji"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Ielādēt..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10070,6 +10109,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Ielādēt Noklusējumu"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10315,6 +10359,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Dublicēt atslēgvietnes"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Galvenais Skripts:"
@@ -10438,6 +10491,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Dublicēt atslēgvietnes"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10546,6 +10604,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12039,6 +12104,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12294,11 +12367,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index 9c110afb2d..1259cbeed4 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -619,7 +619,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1788,8 +1788,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2423,7 +2423,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2813,14 +2813,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2974,6 +2966,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3176,7 +3184,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3480,6 +3488,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3857,6 +3870,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4804,7 +4833,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4908,7 +4937,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6675,6 +6703,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6726,16 +6762,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6828,8 +6854,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7235,6 +7261,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9574,6 +9605,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9934,6 +9969,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10177,6 +10216,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10297,6 +10344,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10404,6 +10455,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11871,6 +11929,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12126,11 +12192,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index 47bb481995..25f0c1bedd 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -626,7 +626,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Копирај"
@@ -1795,8 +1795,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2430,7 +2430,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2820,14 +2820,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2981,6 +2973,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3183,7 +3191,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3487,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3864,6 +3877,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4811,7 +4840,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4915,7 +4944,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6682,6 +6710,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6733,16 +6769,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6835,8 +6861,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7242,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9581,6 +9612,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9941,6 +9976,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10184,6 +10223,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10304,6 +10351,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10411,6 +10462,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11878,6 +11936,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12133,11 +12199,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 0791218b36..2ffb3793b7 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -629,7 +629,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1798,8 +1798,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2435,7 +2435,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2825,14 +2825,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2986,6 +2978,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3188,7 +3196,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3492,6 +3500,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3869,6 +3882,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4819,7 +4848,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4923,7 +4952,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6691,6 +6719,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6742,16 +6778,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6844,8 +6870,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7251,6 +7277,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9591,6 +9622,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9951,6 +9986,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10194,6 +10233,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10314,6 +10361,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10421,6 +10472,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11889,6 +11947,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12144,11 +12210,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 2d2ddb2deb..119e1ce931 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -626,7 +626,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1795,8 +1795,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2430,7 +2430,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2820,14 +2820,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2981,6 +2973,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3183,7 +3191,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3487,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3864,6 +3877,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4811,7 +4840,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4915,7 +4944,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6682,6 +6710,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6733,16 +6769,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6835,8 +6861,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7242,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9582,6 +9613,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9942,6 +9977,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10185,6 +10224,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10305,6 +10352,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10412,6 +10463,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11879,6 +11937,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12134,11 +12200,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index e121414574..127e06c898 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -649,7 +649,7 @@ msgstr "Pilih Trek untuk Disalin"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Salin"
@@ -1865,8 +1865,8 @@ msgid "Open a File or Directory"
msgstr "Buka Fail atau Direktori"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Simpan"
@@ -2542,7 +2542,8 @@ msgstr ""
"gagal."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Tidak dapat mencari medan skrip untuk pemalam addon di: 'res://addons/%s'."
@@ -3022,15 +3023,6 @@ msgid "Help"
msgstr "Bantuan"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-#, fuzzy
-msgid "Search"
-msgstr "Cari"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
#, fuzzy
msgid "Online Docs"
@@ -3214,6 +3206,23 @@ msgstr "Buka & Jalankan Skrip"
#: editor/editor_node.cpp
#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "Fail berikut gagal diekstrak dari pakej:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
+#, fuzzy
msgid "New Inherited"
msgstr "Baru Diwarisi"
@@ -3458,7 +3467,7 @@ msgstr "Buat Unik"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
#, fuzzy
msgid "Paste"
msgstr "Tampal"
@@ -3801,6 +3810,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4183,6 +4197,25 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Pilih Nod(Nod-nod) untuk Diimport"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Import"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Muatkan Lalai"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -5133,7 +5166,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5239,7 +5272,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -7012,6 +7044,15 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+#, fuzzy
+msgid "Search"
+msgstr "Cari"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7063,16 +7104,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7165,8 +7196,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7574,6 +7605,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9929,6 +9965,11 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Mengambil maklumat cermin, sila tunggu..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10289,6 +10330,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Muatkan Lalai"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10533,6 +10579,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Anim Menduakan Kunci"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10654,6 +10709,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Anim Menduakan Kunci"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10761,6 +10821,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12236,6 +12303,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12491,11 +12566,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index b597c27fe1..398330b3e9 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -3,24 +3,26 @@
# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
# Allan Nordhøy <epost@anotheragency.no>, 2017-2018, 2019, 2020, 2021.
-# Anonymous <GentleSaucepan@protonmail.com>, 2017.
+# Anonymous <GentleSaucepan@protonmail.com>, 2017, 2021.
# Elias <eliasnykrem@gmail.com>, 2018.
# flesk <eivindkn@gmail.com>, 2017, 2019.
-# Frank T. Rambol <frank@d-fect.com>, 2018.
+# Frank T. Rambol <frank@d-fect.com>, 2018, 2021.
# Jørgen Aarmo Lund <jorgen.aarmo@gmail.com>, 2016, 2019.
-# NicolaiF <nico-fre@hotmail.com>, 2017-2018, 2019.
+# NicolaiF <nico-fre@hotmail.com>, 2017-2018, 2019, 2021.
# Norwegian Disaster <stian.furu.overbye@gmail.com>, 2017.
# passeride <lukas@passeride.com>, 2017.
# Byzantin <kasper-hoel@hotmail.com>, 2018.
# Hans-Marius Øverås <hansmariusoveras@gmail.com>, 2019.
# Revolution <revosw@gmail.com>, 2019.
# Petter Reinholdtsen <pere-weblate@hungry.com>, 2019, 2020.
+# Patrick Sletvold <patricksletvold@hotmail.com>, 2021.
+# Kristoffer <kskau93@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-12 13:32+0000\n"
-"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Kristoffer <kskau93@gmail.com>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-"
"engine/godot/nb_NO/>\n"
"Language: nb\n"
@@ -28,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.4.1-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -200,7 +202,6 @@ msgid "Change Animation Loop"
msgstr "Endre Animasjonssløyfe"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Property Track"
msgstr "Egenskapsspor"
@@ -209,24 +210,20 @@ msgid "3D Transform Track"
msgstr "3D transformasjonsspor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Call Method Track"
msgstr "Kall metode-spor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Bezier Curve Track"
-msgstr "Bezier-kurvespor"
+msgstr "Bézier-kurvespor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Audio Playback Track"
msgstr "Lydavspillingsspor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation Playback Track"
-msgstr "Stopp avspilling av animasjon. (S)"
+msgstr "Animasjonavspillingspor"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -241,7 +238,6 @@ msgid "Add Track"
msgstr "Legg til Spor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation Looping"
msgstr "Animasjonsløkke"
@@ -260,23 +256,20 @@ msgid "Anim Clips:"
msgstr "Anim-klipp:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Track Path"
-msgstr "Endre Array-verdi"
+msgstr "Endre sporsti"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Toggle this track on/off."
-msgstr "Vis/skjul distraksjonsfri modus."
+msgstr "Slå spor på/av."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
msgstr "Oppdateringsmodus (Hvordan denne egenskapen settes)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Interpolation Mode"
-msgstr "Animasjonsnode"
+msgstr "Interpolasjonsmodus"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
@@ -334,7 +327,7 @@ msgstr "Pakk Inn Sløyfeinterp"
#: editor/animation_track_editor.cpp
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key"
-msgstr "Sett inn Nøkkel"
+msgstr "Sett inn nøkkel"
#: editor/animation_track_editor.cpp
msgid "Duplicate Key(s)"
@@ -345,19 +338,16 @@ msgid "Delete Key(s)"
msgstr "Fjern Nøkler"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Update Mode"
-msgstr "Endre Animasjonsnavn:"
+msgstr "Endre oppdateringsmetode for animasjon"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Interpolation Mode"
-msgstr "Animasjonsnode"
+msgstr "Endre interpolasjonsmodus for animasjon"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Loop Mode"
-msgstr "Endre Anim-Løkke"
+msgstr "Endre løkkemodus for animasjon"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
@@ -412,9 +402,8 @@ msgid "Rearrange Tracks"
msgstr "Omorganiser Spor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr "Transformasjonsspor kan kun brukes på Spatial-baserte noder."
+msgstr "Transformeringsspor virker kun på Spatial-baserte noder."
#: editor/animation_track_editor.cpp
msgid ""
@@ -438,47 +427,40 @@ msgstr ""
"En animansjonsavspiller kan ikke animere seg selv, kun andre avspillere."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Not possible to add a new track without a root"
msgstr "Ikke mulig å legge til et nytt spor uten en rot"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr ""
+msgstr "Ugyldig spor for Bézier (ingen passende underegenskaper)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Bezier Track"
-msgstr "Anim Legg til Spor"
+msgstr "Legg til Bézier-spor"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Track path is invalid, so can't add a key."
msgstr "Sporsti er ugyldig, så kan ikke legge til en nøkkel."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Track is not of type Spatial, can't insert key"
-msgstr "Spor er ikke av type Spatial, kan ikke legge til nøkkel"
+msgstr "Spor er ikke av typen Spatial, kan ikke sette inn nøkkel"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Transform Track Key"
-msgstr "3D transformasjonsspor"
+msgstr "Legg til transformasjons-spornøkkel"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Track Key"
-msgstr "Anim Legg til Spor"
+msgstr "Legg til spornøkkel"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
msgstr "Sporsti er ugyldig, så kan ikke legge til en metodenøkkel."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Method Track Key"
-msgstr "Kall metode-spor"
+msgstr "Legg til metode-spornøkkel"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
@@ -489,26 +471,22 @@ msgid "Anim Move Keys"
msgstr "Anim Flytt Nøkler"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Clipboard is empty"
-msgstr "Ressurs-utklippstavle er tom!"
+msgstr "Utklippstavlen er tom"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Paste Tracks"
-msgstr "Lim inn Parametre"
+msgstr "Sett in spor"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
msgstr "Anim Skalér Nøkler"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr ""
-"Dette valget virker ikke på Bezier-redigering, siden det kun er ett enkelt "
-"spor."
+"Dette valget virker ikke på Bézier-redigering, da det kun er ett enkelt spor."
#: editor/animation_track_editor.cpp
msgid ""
@@ -522,10 +500,19 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
+"Denne animasjonen hører til en importert scene, så endringer på importerte "
+"spor vil ikke bli lagret.\n"
+"\n"
+"For å legge til egendefinerte spor, gå til scenens importinstillinger og "
+"sett\n"
+"\"Animasjon > Lagring\" til \"Filer\", aktiver \"Animasjon > Behold egne spor"
+"\", og importer på nytt.\n"
+"Alternativt, bruk et importoppsett som importerer animasjonen som separate "
+"filer."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
-msgstr ""
+msgstr "Advarsel: Redigerer importert animasjon"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -570,9 +557,8 @@ msgid "Edit"
msgstr "Rediger"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation properties."
-msgstr "Animasjon"
+msgstr "Animasjon egenskaper."
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -589,26 +575,23 @@ msgstr "Skaler Fra Peker"
#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
msgid "Duplicate Selection"
-msgstr "Dupliser Utvalg"
+msgstr "Dupliser utvalg"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Dupliser Transponert"
+msgstr "Dupliser transponert"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Delete Selection"
-msgstr "Slett Valgte"
+msgstr "Slett valgte"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Go to Next Step"
-msgstr "Gå til Neste Steg"
+msgstr "Gå til neste steg"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Go to Previous Step"
-msgstr "Gå til Forrige Steg"
+msgstr "Gå til forrige steg"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -671,18 +654,17 @@ msgid "Scale Ratio:"
msgstr "Skaler Størrelsesforhold:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "Velg spor å kopiere:"
+msgstr "Velg spor å kopiere"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
-msgstr "Lim inn"
+msgstr "Kopier"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -690,9 +672,8 @@ msgid "Select All/None"
msgstr "Kutt Noder"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Add Audio Track Clip"
-msgstr "Lydklipp:"
+msgstr "Legg til lyd-spor klipp"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
@@ -723,19 +704,16 @@ msgid "Line Number:"
msgstr "Linjenummer:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Erstatt..."
+msgstr "%d erstattet."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d match."
-msgstr "%d samsvar."
+msgstr "%d samsvarer."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "Ingen Treff"
+msgstr "%d sammsvarer."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -760,7 +738,7 @@ msgstr "Kun Valgte"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
msgid "Standard"
-msgstr ""
+msgstr "Standard"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
@@ -791,9 +769,8 @@ msgid "Line and column numbers."
msgstr "Linje- og kolonnenummer."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method in target node must be specified."
-msgstr "Metode i mål-Node må spesifiseres!"
+msgstr "Metode i målnoden må spesifiseres."
#: editor/connections_dialog.cpp
#, fuzzy
@@ -820,13 +797,12 @@ msgid "Connect to Script:"
msgstr "Kan ikke koble til tjener:"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "From Signal:"
-msgstr "Signaler:"
+msgstr "Fra signal:"
#: editor/connections_dialog.cpp
msgid "Scene does not contain any script."
-msgstr ""
+msgstr "Scenen inneholder ikke noen skript."
#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
@@ -854,14 +830,12 @@ msgid "Extra Call Arguments:"
msgstr "Ekstra Call Argumenter:"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Receiver Method:"
-msgstr "Lim inn Noder"
+msgstr "Mottakermetode:"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Advanced"
-msgstr "Snapping innstillinger"
+msgstr "Avansert"
#: editor/connections_dialog.cpp
msgid "Deferred"
@@ -1064,9 +1038,8 @@ msgid "Fix Broken"
msgstr "Reparer Ødelagt"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid "Dependency Editor"
-msgstr "Avhengighetsredigeringsverktøy"
+msgstr "Redigeringsverktøy for avhengigheter"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
@@ -1087,14 +1060,15 @@ msgid "Owners Of:"
msgstr "Eiere Av:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Fjerne valgte filer fra prosjektet? (kan ikke angres)"
+msgstr ""
+"Fjerne valgte filer fra prosjektet? (kan ikke angres)\n"
+"Du kan finne de fjernede filene i systemets papirkurv, og gjenopprette dem "
+"derfra."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1102,7 +1076,9 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Filene som fjernes kreves for at andre ressurser skal virke.\n"
-"Fjern dem likevel? (kan ikke angres)"
+"Fjerne dem likevel? (kan ikke angres)\n"
+"Du kan finne de fjernede filene i systemets papirkurv, og gjenopprette dem "
+"derfra."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1163,14 +1139,12 @@ msgid "Resources Without Explicit Ownership:"
msgstr "Ressurser uten eksplisitt eierskap:"
#: editor/dictionary_property_edit.cpp
-#, fuzzy
msgid "Change Dictionary Key"
-msgstr "Endre Ordboksnøkkel"
+msgstr "Endre listenøkkel"
#: editor/dictionary_property_edit.cpp
-#, fuzzy
msgid "Change Dictionary Value"
-msgstr "Endre Ordboksverdi"
+msgstr "Endre listeverdi"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
@@ -1444,7 +1418,6 @@ msgid "There is no '%s' file."
msgstr "Det finnes ingen «%s»-fil"
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Layout"
msgstr "Layout"
@@ -1453,9 +1426,8 @@ msgid "Invalid file, not an audio bus layout."
msgstr "Ugyldig fil, ikke et audio bus oppsett."
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Error saving file: %s"
-msgstr "Error ved lagring av TileSet!"
+msgstr "Feil ved lagring av filen: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
@@ -1620,7 +1592,7 @@ msgstr "Velg en Mappe"
#: editor/filesystem_dock.cpp editor/project_manager.cpp
#: scene/gui/file_dialog.cpp
msgid "Create Folder"
-msgstr "Lag mappe"
+msgstr "Lag Mappe"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
@@ -1643,7 +1615,6 @@ msgid "Storing File:"
msgstr "Lagrer Fil:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "No export template found at the expected path:"
msgstr "Ingen eksportmal funnet på forventet søkesti:"
@@ -1736,9 +1707,8 @@ msgid "3D Editor"
msgstr "Redigeringsverktøy"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Script Editor"
-msgstr "Åpne SkriptEditor"
+msgstr "Skript Redigeringsverktøy"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
@@ -1754,9 +1724,8 @@ msgid "Node Dock"
msgstr "Flytt Modus"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "FilSystem"
+msgstr "FilSystem Panel"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1770,7 +1739,7 @@ msgstr "Erstatt Alle"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profil må være et gyldig filnavn, og kan ikke inneholde '.'"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1797,9 +1766,8 @@ msgid "Class Options:"
msgstr "Beskrivelse:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Enable Contextual Editor"
-msgstr "Åpne den neste Editoren"
+msgstr "Aktiver kontekstavhengig redigeringsverktøy"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1817,7 +1785,7 @@ msgstr "Søk i klasser"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr ""
+msgstr "Filformatet til '%s' er ugyldig, importen ble avbrutt."
#: editor/editor_feature_profile.cpp
msgid ""
@@ -1826,9 +1794,8 @@ msgid ""
msgstr ""
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Error saving profile to path: '%s'."
-msgstr "Error ved lagring av TileSet!"
+msgstr "Feil ved lagring av profilen til stien: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
@@ -1914,7 +1881,7 @@ msgstr "Kutt Noder"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopier Sti"
+msgstr "Kopier Bane"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
#, fuzzy
@@ -1961,8 +1928,8 @@ msgid "Open a File or Directory"
msgstr "Åpne ei fil eller mappe"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Lagre"
@@ -1973,27 +1940,27 @@ msgstr "Lagre ei fil"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr "Gå tilbake"
+msgstr "Gå Tilbake"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr "Gå framover"
+msgstr "Gå Fremover"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr "Gå oppover"
+msgstr "Gå Oppover"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr "Veksle visning av skjulte filer"
+msgstr "Veksle Visning av Skjulte Filer"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr "Veksle favorittmerkering"
+msgstr "Veksle Favorittmarkering"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "Veksle modus"
+msgstr "Veksle Modus"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -2164,7 +2131,7 @@ msgstr ""
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr "Søk hjelp"
+msgstr "Søk Hjelp"
#: editor/editor_help_search.cpp
msgid "Case Sensitive"
@@ -2252,9 +2219,8 @@ msgid "Set"
msgstr "Sett"
#: editor/editor_inspector.cpp
-#, fuzzy
msgid "Set Multiple:"
-msgstr "Sett Mange:"
+msgstr "Sett mange:"
#: editor/editor_log.cpp
msgid "Output:"
@@ -2277,7 +2243,7 @@ msgstr "Tøm"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr "Nullstill resultat"
+msgstr "Nullstill Resultat"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2286,9 +2252,8 @@ msgstr "Stopp"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
-#, fuzzy
msgid "Start"
-msgstr "Start!"
+msgstr "Start"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
@@ -2370,7 +2335,7 @@ msgstr "Kan ikke åpne '%s'. Filen kan ha blitt flyttet eller slettet."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr "Error ved parsing av '%s'."
+msgstr "Feil ved parsing av '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
@@ -2401,7 +2366,6 @@ msgid "This operation can't be done without a tree root."
msgstr "Denne operasjonen kan ikke gjennomføres uten en trerot."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
@@ -2428,7 +2392,7 @@ msgstr "Kan ikke laste MeshLibrary for sammenslåing!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr "Error ved lagring av MeshLibrary!"
+msgstr "Feil ved lagring av MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
@@ -2436,7 +2400,7 @@ msgstr "Kan ikke laste TileSet for sammenslåing!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
-msgstr "Error ved lagring av TileSet!"
+msgstr "Feil ved lagring av TileSet!"
#: editor/editor_node.cpp
msgid ""
@@ -2619,7 +2583,7 @@ msgstr "Ja"
#: editor/editor_node.cpp
msgid "Exit the editor?"
-msgstr "Avslutt editoren?"
+msgstr "Avslutt redigeringsverktøyet?"
#: editor/editor_node.cpp
msgid "Open Project Manager?"
@@ -2654,9 +2618,8 @@ msgid "Close Scene"
msgstr "Lukk Scene"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reopen Closed Scene"
-msgstr "Lukk Scene"
+msgstr "Gjenåpne Lukket Scene"
#: editor/editor_node.cpp
#, fuzzy
@@ -2666,7 +2629,8 @@ msgstr ""
"mislyktes."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "Kunne ikke finne skriptfelt for addon-plugin i: 'res://addons/%s'."
#: editor/editor_node.cpp
@@ -2685,7 +2649,8 @@ msgstr ""
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
-"Kan ikke laste addon skript fra bane: Basistype '%s' er ikke en EditorPlugin."
+"Kan ikke laste addon-skript fra stien: Basistypen '%s' er ikke en "
+"EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
@@ -2875,9 +2840,8 @@ msgid "Save Scene"
msgstr "Lagre Scene"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Save All Scenes"
-msgstr "Lagre alle Scener"
+msgstr "Lagre Alle Scener"
#: editor/editor_node.cpp
msgid "Convert To..."
@@ -2923,7 +2887,7 @@ msgstr "Versjon:"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Sett opp versjonskontroll"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
@@ -2939,9 +2903,8 @@ msgid "Install Android Build Template..."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Project Data Folder"
-msgstr "Åpne ProsjektManager?"
+msgstr "Åpne prosjektdatamappe"
#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
msgid "Tools"
@@ -3028,17 +2991,16 @@ msgid "Synchronize Scene Changes"
msgstr "Synkroniser Sceneendringer"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any changes made to the scene in the editor "
"will be replicated in the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"Når denne innstillingen er aktivert, alle endringer gjort til scenen i "
-"editoren vil bli replikert i det kjørende spillet.\n"
-"Når det brukes eksternt på en enhet, dette er mer effektivt med et "
-"nettverksfilsystem."
+"Når denne innstillingen er aktivert, vil alle endringer gjort i scenen i "
+"redigeringsverktøyet bli gjenspeilet i det kjørende spillet.\n"
+"Når det brukes eksternt på en enhet, er dette mer effektivt med et "
+"nettverksfilsystem aktivert."
#: editor/editor_node.cpp
#, fuzzy
@@ -3071,9 +3033,8 @@ msgid "Editor Layout"
msgstr "Redigeringsverktøy Layout"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Take Screenshot"
-msgstr "Lagre Scene"
+msgstr "Ta Skjermbilde"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
@@ -3081,7 +3042,7 @@ msgstr "Skjermavbildninger lagres i redigeringsdata/innstillingsmappen."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Skru av/på Fullskjerm"
+msgstr "Veksle Fullskjerm"
#: editor/editor_node.cpp
#, fuzzy
@@ -3115,14 +3076,6 @@ msgid "Help"
msgstr "Hjelp"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Søk"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Dokumentasjon"
@@ -3162,7 +3115,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Pause Scene"
-msgstr "Sett scenen på pause"
+msgstr "Sett Scenen På Pause"
#: editor/editor_node.cpp
msgid "Stop the scene."
@@ -3196,9 +3149,8 @@ msgid "Save & Restart"
msgstr "Lagre & Avslutt"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Spins when the editor window redraws."
-msgstr "Snurrer når editorvinduet rendrer om!"
+msgstr "Snurrer når redigeringsvinduet tegner opp på nytt."
#: editor/editor_node.cpp
#, fuzzy
@@ -3224,9 +3176,8 @@ msgid "Inspector"
msgstr "Inspektør"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Expand Bottom Panel"
-msgstr "Utvid alle"
+msgstr "Utvid Nederste Panel"
#: editor/editor_node.cpp
msgid "Output"
@@ -3286,13 +3237,31 @@ msgid "Open & Run a Script"
msgstr "Åpne & Kjør et Skript"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Følgende filer er nyere på disken.\n"
+"Hvilken handling skal utføres?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Gjeninnlat"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Lagre på nytt"
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "New Inherited"
msgstr "Ny Arvet"
#: editor/editor_node.cpp
msgid "Load Errors"
-msgstr "Last Errors"
+msgstr "Last feil"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
@@ -3300,15 +3269,15 @@ msgstr "Velg"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr "Åpne 2D Editor"
+msgstr "Åpne 2D-redigeringsverktøy"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr "Åpne 3D Editor"
+msgstr "Åpne 3D-redigeringsverktøy"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "Åpne SkriptEditor"
+msgstr "Åpne Skriptredigeringsverktøy"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3316,16 +3285,15 @@ msgstr "Åpne Assets-Bibliotek"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr "Åpne den neste Editoren"
+msgstr "Åpne det neste redigeringsverktøyet"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr "Åpne den forrige Editoren"
+msgstr "Åpne det forrige redigeringsverktøy"
#: editor/editor_node.h
-#, fuzzy
msgid "Warning!"
-msgstr "Advarsler"
+msgstr "Advarsel!"
#: editor/editor_path.cpp
#, fuzzy
@@ -3389,9 +3357,8 @@ msgid "Average Time (sec)"
msgstr "Gjennomsnittstid (sek)"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame %"
-msgstr "Frame %"
+msgstr "Bilde %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
@@ -3406,9 +3373,8 @@ msgid "Self"
msgstr "Selv"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Frame #:"
-msgstr "Frame #:"
+msgstr "Bilde #:"
#: editor/editor_profiler.cpp
#, fuzzy
@@ -3506,7 +3472,7 @@ msgstr "Gjør Unik"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Lim inn"
@@ -3585,7 +3551,7 @@ msgstr ""
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
-msgstr "Velg Node(r) for Importering"
+msgstr "Velg node(r) som skal importeres"
#: editor/editor_sub_scene.cpp editor/project_manager.cpp
#, fuzzy
@@ -3635,9 +3601,8 @@ msgid "Retrieving mirrors, please wait..."
msgstr "Henter fillager, vennligst vent..."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Remove template version '%s'?"
-msgstr "Fjern mal versjon '%s'?"
+msgstr "Fjern malversjon '%s'?"
#: editor/export_template_manager.cpp
msgid "Can't open export templates zip."
@@ -3653,9 +3618,8 @@ msgid "No version.txt found inside templates."
msgstr "Ingen version.txt funnet i mal."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for templates:"
-msgstr "Feil ved laging av sti for mal:\n"
+msgstr "Feil ved laging av sti for maler:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3835,19 +3799,22 @@ msgstr ""
"Status: Import av fil feilet. Reparer filen eller importer igjen manuelt."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "Kan ikke flytte/endre navn ressursrot"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Cannot move a folder into itself."
-msgstr "Kan ikke flytte mappe inn i seg selv.\n"
+msgstr "Kan ikke flytte en mappe inn i seg selv."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Error moving:"
-msgstr "Error ved flytting:\n"
+msgstr "Feil ved flytting:"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3855,9 +3822,8 @@ msgid "Error duplicating:"
msgstr "Feil ved innlasting:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Unable to update dependencies:"
-msgstr "Kan ikke oppdatere av avhengigheter:\n"
+msgstr "Kan ikke oppdatere avhengigheter:"
#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
msgid "No name provided."
@@ -4043,9 +4009,8 @@ msgid "Create Script"
msgstr "Opprett skript"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Find in Files"
-msgstr "%d flere filer"
+msgstr "Finn i Filer"
#: editor/find_in_files.cpp
#, fuzzy
@@ -4123,9 +4088,8 @@ msgid "Remove from Group"
msgstr "Fjern fra Gruppe"
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Group name already exists."
-msgstr "ERROR: Animasjonsnavnet finnes allerede!"
+msgstr "Gruppenavnet finnes allerede."
#: editor/groups_editor.cpp
#, fuzzy
@@ -4167,9 +4131,8 @@ msgid "Empty groups will be automatically removed."
msgstr ""
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Group Editor"
-msgstr "Åpne SkriptEditor"
+msgstr "Redigeringsverktøy for grupper"
#: editor/groups_editor.cpp
#, fuzzy
@@ -4227,7 +4190,7 @@ msgstr "Importerer Scene..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
-msgstr "Genererer Lyskart"
+msgstr "Genererer lyskart"
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
@@ -4248,7 +4211,7 @@ msgstr "Ugyldig/ødelagt skript for post-import (sjekk konsoll):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr "Error ved kjøring av post-import script:"
+msgstr "Feil ved kjøring av post-import script:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
@@ -4258,6 +4221,25 @@ msgstr ""
msgid "Saving..."
msgstr "Lagrer..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Velg Modus"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importer"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Last Standard"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -4324,9 +4306,8 @@ msgid "Copy Params"
msgstr "Kopier Parametre"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource Clipboard"
-msgstr "Ressurs-utklippstavle er tom!"
+msgstr "Rediger ressurs-utklippstavlen"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
@@ -4437,16 +4418,14 @@ msgid "Create points."
msgstr "Slett punkter"
#: editor/plugins/abstract_polygon_2d_editor.cpp
-#, fuzzy
msgid ""
"Edit points.\n"
"LMB: Move Point\n"
"RMB: Erase Point"
msgstr ""
-"Endre eksisterende polygon:\n"
-"Venstreklikk: Flytt Punkt.\n"
-"Ctrl+Venstreklikk: Splitt Segment.\n"
-"Høyreklikk: Fjern Punkt."
+"Rediger punkter.\n"
+"Venstreklikk: Flytt punkt\n"
+"Høyreklikk: Fjern punkt"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
@@ -4461,7 +4440,7 @@ msgstr "Rediger Poly"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Insert Point"
-msgstr "Sett inn Punkt"
+msgstr "Sett inn punkt"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#, fuzzy
@@ -4578,9 +4557,8 @@ msgid "Open Animation Node"
msgstr "Animasjonsnode"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Triangle already exists."
-msgstr "ERROR: Animasjonsnavnet finnes allerede!"
+msgstr "Triangelet finnes allerede."
#: editor/plugins/animation_blend_space_2d_editor.cpp
#, fuzzy
@@ -4782,14 +4760,12 @@ msgid "Remove Animation"
msgstr "Fjern Animasjon"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Invalid animation name!"
-msgstr "ERROR: Ugyldig animasjonsnavn!"
+msgstr "Ugyldig animasjonsnavn!"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Animation name already exists!"
-msgstr "ERROR: Animasjonsnavnet finnes allerede!"
+msgstr "Animasjonsnavnet finnes allerede!"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
@@ -4814,14 +4790,12 @@ msgid "Duplicate Animation"
msgstr "Dupliser Animasjon"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation to copy!"
-msgstr "ERROR: Ingen animasjon å kopiere!"
+msgstr "Ingen animasjon å kopiere!"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation resource on clipboard!"
-msgstr "ERROR: Ingen animasjonsressurs på utklippstavlen!"
+msgstr "Ingen animasjonsressurs på utklippstavlen!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
@@ -4832,9 +4806,8 @@ msgid "Paste Animation"
msgstr "Lim inn Animasjon"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation to edit!"
-msgstr "ERROR: Ingen animasjon å endre!"
+msgstr "Ingen animasjon å redigere!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from current pos. (A)"
@@ -4958,7 +4931,7 @@ msgstr "Animasjonsnavn:"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
msgid "Error!"
-msgstr "Error!"
+msgstr "Feil!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Times:"
@@ -4980,9 +4953,8 @@ msgid "Move Node"
msgstr "Flytt Modus"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Overgang"
+msgstr "Overgang eksisterer!"
#: editor/plugins/animation_state_machine_editor.cpp
#, fuzzy
@@ -4992,7 +4964,7 @@ msgstr "Overgang"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node"
-msgstr ""
+msgstr "Legg til node"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
@@ -5298,10 +5270,12 @@ msgid "Got:"
msgstr "Fikk:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Feilet sha256 hash-sjekk"
#: editor/plugins/asset_library_editor_plugin.cpp
+#, fuzzy
msgid "Asset Download Error:"
msgstr "Asset Nedlasting Error:"
@@ -5339,7 +5313,7 @@ msgstr "Prøv på nytt"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download Error"
-msgstr "Nedlastningserror"
+msgstr "Nedlastningsfeil"
#: editor/plugins/asset_library_editor_plugin.cpp
#, fuzzy
@@ -5413,7 +5387,6 @@ msgid "Sort:"
msgstr "Sorter:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategori:"
@@ -5787,9 +5760,8 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Reset"
-msgstr "Zoom Ut"
+msgstr "Zoom Resett"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5825,9 +5797,8 @@ msgstr "Roter Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale Mode"
-msgstr "Velg Modus"
+msgstr "Skaler Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5848,9 +5819,8 @@ msgid "Pan Mode"
msgstr "Panorerings-Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Ruler Mode"
-msgstr "Velg Modus"
+msgstr "Linjal Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5858,9 +5828,8 @@ msgid "Toggle smart snapping."
msgstr "Slå av/på snapping"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Smart Snap"
-msgstr "Bruk Snap"
+msgstr "Bruk Smart Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5868,9 +5837,8 @@ msgid "Toggle grid snapping."
msgstr "Slå av/på snapping"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Grid Snap"
-msgstr "Bruk Snap"
+msgstr "Bruk Rutenett Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5978,13 +5946,12 @@ msgid "View"
msgstr "Visning"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Always Show Grid"
-msgstr "Vis Rutenett"
+msgstr "Alltid Vis Rutenett"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
-msgstr "Vis hjelpere"
+msgstr "Vis Hjelpere"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
@@ -5992,7 +5959,7 @@ msgstr "Vis linjaler"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr "Vis veiledere"
+msgstr "Vis Veiledere"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -6015,7 +5982,7 @@ msgstr "Plasser Utvalg I Midten"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr ""
+msgstr "Bildeutvalg"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
@@ -6066,7 +6033,7 @@ msgstr "Kopier Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr "Fjern Pose"
+msgstr "Fjern Posering"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6077,9 +6044,8 @@ msgid "Divide grid step by 2"
msgstr "Del rutenett-steg med 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Pan View"
-msgstr "Bakvisning"
+msgstr "Panoreringsvisning"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -6101,7 +6067,7 @@ msgstr "Lag Node"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Error instancing scene from %s"
-msgstr "Error ved instansiering av scene fra %s"
+msgstr "Feil ved instansiering av scene fra %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -6127,7 +6093,7 @@ msgstr "Rediger Poly"
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Edit Poly (Remove Point)"
-msgstr "Rediger Poly (Fjern Punkt)"
+msgstr "Rediger Poly (fjern punkt)"
#: editor/plugins/collision_shape_2d_editor_plugin.cpp
#, fuzzy
@@ -6487,11 +6453,12 @@ msgid "Remove item %d?"
msgstr "Fjern element %d?"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid ""
"Update from existing scene?:\n"
"%s"
-msgstr "Oppdater fra Scene"
+msgstr ""
+"Oppdater fra eksisterende scene?:\n"
+"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
#, fuzzy
@@ -6904,9 +6871,8 @@ msgid "Paint Bone Weights"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Open Polygon 2D UV editor."
-msgstr "Åpne 2D Editor"
+msgstr "Åpne 2D-redigeringsverktøy for polygon-UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Polygon 2D UV Editor"
@@ -7058,7 +7024,7 @@ msgstr "Skaler Polygon"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
-msgstr "ERROR: Kunne ikke laste ressurs!"
+msgstr "FEIL: Kunne ikke laste ressurs!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Add Resource"
@@ -7121,16 +7087,12 @@ msgid "Clear Recent Files"
msgstr "Fjern Nylige Filer"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Close and save changes?"
-msgstr ""
-"Lukk og lagre endringer?\n"
-"\""
+msgstr "Lukke og lagre endringer?"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error writing TextFile:"
-msgstr "Error ved lagring av TileSet!"
+msgstr "Feil ved lagring av TextFile:"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7138,29 +7100,24 @@ msgid "Could not load file at:"
msgstr "Kunne ikke opprette mappe."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error saving file!"
-msgstr "Error ved lagring av TileSet!"
+msgstr "Feil ved lagring av filen!"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error while saving theme."
-msgstr "Error ved lasting av tema"
+msgstr "Feil ved lagring av tema"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Saving"
-msgstr "Error ved lagring"
+msgstr "Feil ved lagring"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error importing theme."
-msgstr "Error ved importering av tema"
+msgstr "Feil ved importering av tema."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Importing"
-msgstr "Error ved importering"
+msgstr "Feil ved importering"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7200,11 +7157,11 @@ msgstr "Importer Tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme"
-msgstr "Error ved lasting av tema"
+msgstr "Feil ved lagring av tema"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving"
-msgstr "Error ved lagring"
+msgstr "Feil ved lagring"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
@@ -7218,12 +7175,12 @@ msgstr "%s-klassereferanse"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Next"
-msgstr "Finn neste"
+msgstr "Finn Neste"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr "Finn forrige"
+msgstr "Finn Forrige"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7273,13 +7230,12 @@ msgid "Open..."
msgstr "Åpne"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Reopen Closed Script"
-msgstr "Kjør Skript"
+msgstr "Gjenåpne Lukket Skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr "Lagre Alle"
+msgstr "Lagre Alt"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -7290,9 +7246,8 @@ msgid "Copy Script Path"
msgstr "Kopier Skript-Sti"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "History Previous"
-msgstr "Finn forrige"
+msgstr "Historie Forrige"
#: editor/plugins/script_editor_plugin.cpp
msgid "History Next"
@@ -7328,9 +7283,17 @@ msgstr "Lukk Dokumentasjon"
msgid "Run"
msgstr "Kjør"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Søk"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
-msgstr "Tre inn i"
+msgstr "Tre Inn I"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
@@ -7381,16 +7344,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Gjeninnlat"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Lagre på nytt"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Feilsøking"
@@ -7435,9 +7388,8 @@ msgid "Line"
msgstr "Linje:"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Fjern Funksjon"
+msgstr "Gå til Funksjon"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7462,7 +7414,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr "Store versaler"
+msgstr "Store bokstaver"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
@@ -7491,8 +7443,8 @@ msgstr "Slett punkter"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Klipp ut"
@@ -7502,9 +7454,8 @@ msgid "Select All"
msgstr "Velg Alle"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Delete Line"
-msgstr "Slett Valgte"
+msgstr "Slett Linje"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
@@ -7516,12 +7467,11 @@ msgstr "Innrykk Høyre"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr "Veksle kommentar"
+msgstr "Veksle Kommentar"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Fold/Unfold Line"
-msgstr "Slett Valgte"
+msgstr "Veksle Linjebretting"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7533,34 +7483,31 @@ msgstr "Brett ut alle linjer"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
-msgstr "Klon nedover"
+msgstr "Klon Nedover"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Evaluate Selection"
-msgstr "Skaler Utvalg"
+msgstr "Evaluer Seleksjon"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Convert Indent to Spaces"
-msgstr "Konverter til store versaler"
+msgstr "Konverter Innrykk til Mellomrom"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Convert Indent to Tabs"
-msgstr "Konverter til store versaler"
+msgstr "Konverter Inrykk til Tabs"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
-msgstr "Automatisk innrykk"
+msgstr "Automatisk Innrykk"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7572,19 +7519,16 @@ msgid "Contextual Help"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Toggle Bookmark"
-msgstr "Veksle kommentar"
+msgstr "Veksle Bokmerke"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Bookmark"
-msgstr "Gå til Neste Steg"
+msgstr "Gå til Neste Bokmerke"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Bookmark"
-msgstr "Gå til tidligere redigert dokument."
+msgstr "Gå til Forrige Bokmerke"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7616,9 +7560,8 @@ msgid "Go to Next Breakpoint"
msgstr "Gå til Neste Steg"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Breakpoint"
-msgstr "Gå til tidligere redigert dokument."
+msgstr "Gå til Forrige Steg"
#: editor/plugins/shader_editor_plugin.cpp
msgid ""
@@ -7732,9 +7675,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Størrelse: "
+msgstr "Størrelse"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7925,6 +7867,11 @@ msgstr "Vis Informasjon"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7992,7 +7939,7 @@ msgstr "Høyrevisning"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
-msgstr "Bytt perspektiv/ortogonal fremvisning"
+msgstr "Bytt Perspektiv/Ortogonal Fremvisning"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
@@ -8016,9 +7963,8 @@ msgid "Transform"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Object to Floor"
-msgstr "Snap til rutenett"
+msgstr "Snap Objekt til Gulv"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -8571,9 +8517,8 @@ msgid "Theme File"
msgstr "Tema"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Erase Selection"
-msgstr "Fjern Utvalg"
+msgstr "Fjern Seleksjon"
#: editor/plugins/tile_map_editor_plugin.cpp
#, fuzzy
@@ -8582,9 +8527,8 @@ msgstr "Ugyldig navn."
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Plasser Utvalg I Midten"
+msgstr "Klipp ut Seleksjon"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
@@ -8607,9 +8551,8 @@ msgid "Erase TileMap"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Find Tile"
-msgstr "Finn neste"
+msgstr "Finn Flis"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
@@ -8654,14 +8597,12 @@ msgid "Pick Tile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Left"
-msgstr "Roter Modus"
+msgstr "Roter til Venstre"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Right"
-msgstr "Roter Polygon"
+msgstr "Roter til Høyre"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Horizontally"
@@ -8672,9 +8613,8 @@ msgid "Flip Vertically"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "Anim Forandre Omforming"
+msgstr "Nullstill Transformasjon"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8709,18 +8649,16 @@ msgid "New Atlas"
msgstr "Ny %s"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Next Coordinate"
-msgstr "Neste skript"
+msgstr "Neste Koordinat"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the next shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Previous Coordinate"
-msgstr "Forrige skript"
+msgstr "Forrige Koordinat"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the previous shape, subtile, or Tile."
@@ -8742,9 +8680,8 @@ msgid "Occlusion"
msgstr "Rediger Poly"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation"
-msgstr "Animasjonsnode"
+msgstr "Navigasjon"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8762,44 +8699,36 @@ msgid "Z Index"
msgstr "Panorerings-Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region Mode"
-msgstr "Roter Modus"
+msgstr "Region Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision Mode"
-msgstr "Animasjonsnode"
+msgstr "Kollisjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Occlusion Mode"
-msgstr "Rediger Poly"
+msgstr "Okklusjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation Mode"
-msgstr "Animasjonsnode"
+msgstr "Navigasjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask Mode"
-msgstr "Roter Modus"
+msgstr "Bitmaske Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Priority Mode"
-msgstr "Eksporter Prosjekt"
+msgstr "Prioritet Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Icon Mode"
-msgstr "Panorerings-Modus"
+msgstr "Ikon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Z Index Mode"
-msgstr "Panorerings-Modus"
+msgstr "Z Indeks Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
@@ -8895,11 +8824,12 @@ msgid "Delete selected Rect."
msgstr "Slett valgte filer?"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select current edited sub-tile.\n"
"Click on another Tile to edit it."
-msgstr "Velg Gjeldende Mappe"
+msgstr ""
+"Velg gjeldende redigerte underflis.\n"
+"Klikk på en annen flis for å redigere den."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8907,13 +8837,16 @@ msgid "Delete polygon."
msgstr "Slett punkter"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"LMB: Set bit on.\n"
"RMB: Set bit off.\n"
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
-msgstr "Velg Gjeldende Mappe"
+msgstr ""
+"Venstreklikk: Sett bit på.\n"
+"Høyreklikk: Sett bit av.\n"
+"Skift+venstreklikk: Sett jokertegn-bit.\n"
+"Klikk på en annen flis for å redigere den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8929,11 +8862,12 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select sub-tile to change its z index.\n"
"Click on another Tile to edit it."
-msgstr "Velg Gjeldende Mappe"
+msgstr ""
+"Velg underflis for å endre z-indeksen.\n"
+"Klikk på en annen flis for å redigere den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Region"
@@ -9086,9 +9020,8 @@ msgid "Detect new changes"
msgstr "Lag ny %s"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Changes"
-msgstr "Forandre"
+msgstr "Endringer"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
@@ -10053,7 +9986,7 @@ msgstr "Ressurser"
#: editor/project_export.cpp
msgid "Export all resources in the project"
-msgstr "Eksporter alle ressurser til prosjektet"
+msgstr "Eksporter alle ressurser i prosjektet"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
@@ -10061,7 +9994,7 @@ msgstr "Eksporter valgte scener (og avhengigheter)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr "Exporter valgte ressurs (og avhengigheter)"
+msgstr "Exporter valgte ressurser (og avhengigheter)"
#: editor/project_export.cpp
msgid "Export Mode:"
@@ -10085,7 +10018,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Egenskaper"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -10134,9 +10067,8 @@ msgid "Export Project"
msgstr "Eksporter Prosjekt"
#: editor/project_export.cpp
-#, fuzzy
msgid "Export mode?"
-msgstr "Eksporter Prosjekt"
+msgstr "Eksportmodus?"
#: editor/project_export.cpp
#, fuzzy
@@ -10226,8 +10158,8 @@ msgid ""
"Couldn't load project.godot in project path (error %d). It may be missing or "
"corrupted."
msgstr ""
-"Kunne ikke laste project.godot i prosjekt sti (error %d). Den kan være "
-"manglet eller korruptert."
+"Kunne ikke laste project.godot i prosjektstien (feil %d). Den kan mangle "
+"eller være korrupt."
#: editor/project_manager.cpp
msgid "Couldn't edit project.godot in project path."
@@ -10398,25 +10330,28 @@ msgid "Are you sure to run %d projects at once?"
msgstr "Er du sikker på at du vil kjøre mer enn ett prosjekt?"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Remove %d projects from the list?\n"
"The project folders' contents won't be modified."
-msgstr "Fjern prosjekt fra listen? (Mappeinnhold vil ikke bli modifisert)"
+msgstr ""
+"Fjern %s prosjekter fra listen?\n"
+"Innhold i prosjektmappene vil ikke påvirkes."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Remove this project from the list?\n"
"The project folder's contents won't be modified."
-msgstr "Fjern prosjekt fra listen? (Mappeinnhold vil ikke bli modifisert)"
+msgstr ""
+"Fjern dette prosjektet fra listen?\n"
+"Innhold i prosjektmappen vil ikke påvirkes."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Remove all missing projects from the list?\n"
"The project folders' contents won't be modified."
-msgstr "Fjern prosjekt fra listen? (Mappeinnhold vil ikke bli modifisert)"
+msgstr ""
+"Fjern alle manglende prosjekter fra listen?\n"
+"Innhold i prosjektmappene vil ikke påvirkes."
#: editor/project_manager.cpp
msgid ""
@@ -10443,6 +10378,11 @@ msgid "Projects"
msgstr "Prosjekter"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Henter fillager, vennligst vent..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10511,9 +10451,8 @@ msgid ""
msgstr ""
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "An action with the name '%s' already exists."
-msgstr "ERROR: Animasjonsnavnet finnes allerede!"
+msgstr "En handling med navnet '%s' finnes allerede."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
@@ -10814,10 +10753,14 @@ msgstr ""
msgid "Plugins"
msgstr "Innstikkmoduler"
-#: editor/property_editor.cpp
+#: editor/project_settings_editor.cpp
#, fuzzy
+msgid "Import Defaults"
+msgstr "Last Standard"
+
+#: editor/property_editor.cpp
msgid "Preset..."
-msgstr "Preset..."
+msgstr "Forhåndsinnstilt..."
#: editor/property_editor.cpp
msgid "Zero"
@@ -10873,14 +10816,12 @@ msgid "Select Method"
msgstr ""
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Batch Rename"
-msgstr "Endre navn"
+msgstr "Endre Navn på Parti"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Erstatt: "
+msgstr "Erstatt:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10919,9 +10860,8 @@ msgid "Node type"
msgstr "Finn Node Type"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Current scene name"
-msgstr "Gjeldende scene er ikke lagret. Åpne likevel?"
+msgstr "Navn på gjeldende scene"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -11073,6 +11013,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Lim inn Noder"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Nytt Skript"
@@ -11111,14 +11060,12 @@ msgid "Make node as Root"
msgstr "Lagre Scene"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Kutt Noder"
+msgstr "Slett %d noder og eventuelle barn?"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
-msgstr "Kutt Noder"
+msgstr "Slett %d noder?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -11129,9 +11076,8 @@ msgid "Delete node \"%s\" and its children?"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete node \"%s\"?"
-msgstr "Kutt Noder"
+msgstr "Slett noden \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -11202,6 +11148,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Kutt Noder"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -11285,9 +11236,8 @@ msgid "Save Branch as Scene"
msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Copy Node Path"
-msgstr "Kopier Noder"
+msgstr "Kopier Node-bane"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
@@ -11321,6 +11271,13 @@ msgid "Remote"
msgstr "Fjern Funksjon"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11418,19 +11375,16 @@ msgid "Select a Node"
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is empty."
-msgstr "Ressurs-utklippstavle er tom!"
+msgstr "Stien er tom."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Filename is empty."
-msgstr "Ressurs-utklippstavle er tom!"
+msgstr "Filnavnet er tomt."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is not local."
-msgstr "Sti leder ikke Node!"
+msgstr "Stien er ikke lokal."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11477,9 +11431,8 @@ msgid "N/A"
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Open Script / Choose Location"
-msgstr "Åpne SkriptEditor"
+msgstr "Åpne skript / Velg plassering"
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11574,19 +11527,16 @@ msgid "Warning:"
msgstr "Advarsler:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "Error!"
+msgstr "Feil:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error"
-msgstr "Last Errors"
+msgstr "C++-feil"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error:"
-msgstr "Last Errors"
+msgstr "C++-feil:"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11617,9 +11567,8 @@ msgid "Child process connected."
msgstr "Frakoblet"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Copy Error"
-msgstr "Last Errors"
+msgstr "Kopier feil"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
@@ -11884,7 +11833,7 @@ msgstr ""
#: modules/gdscript/gdscript_functions.cpp
msgid "Not a script with an instance"
-msgstr ""
+msgstr "Ikke et skript med en instans"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a script"
@@ -12250,25 +12199,24 @@ msgid "Name is not a valid identifier:"
msgstr "Navn er ikke en gyldig identifikator:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Name already in use by another func/var/signal:"
-msgstr "Navn er allerede i bruk av en annen func/var/signal:"
+msgstr "Navnet er allerede i bruk av annen funk/var/signal:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Function"
-msgstr ""
+msgstr "Endre navn på funksjonen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Variable"
-msgstr ""
+msgstr "Endre navn på variabelen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Signal"
-msgstr ""
+msgstr "Endre navn på signalet"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Function"
-msgstr ""
+msgstr "Legg til funksjon"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12277,11 +12225,11 @@ msgstr "Fjern punkt"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Variable"
-msgstr ""
+msgstr "Legg til variabel"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Signal"
-msgstr ""
+msgstr "Legg til signal"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12295,7 +12243,7 @@ msgstr "Fjern punkt"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
-msgstr ""
+msgstr "Endre uttrykk"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
@@ -12315,6 +12263,8 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
msgstr ""
+"Hold Ctrl for å slippe en Getter. Hold Skift for å slippe en generisk "
+"signatur."
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12323,7 +12273,7 @@ msgstr "Hold Meta for å slippe en enkel referanse til noden."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a simple reference to the node."
-msgstr "Hold Ctrl for å slippe en simpel referanse til noden."
+msgstr "Hold Ctrl for å slippe en enkel referanse til noden."
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12443,19 +12393,19 @@ msgstr "Fjern Funksjon"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Variable"
-msgstr ""
+msgstr "Fjern variabel"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Variable:"
-msgstr ""
+msgstr "Redigerer variabel:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Signal"
-msgstr ""
+msgstr "Fjern signal"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Signal:"
-msgstr ""
+msgstr "Redigerer signal:"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12504,24 +12454,20 @@ msgid "Copy Nodes"
msgstr "Kopier Noder"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Cut Nodes"
-msgstr "Kutt Noder"
+msgstr "Klipp ut Noder"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "Fjern Funksjon"
+msgstr "Lag Funksjon"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "Oppdater"
+msgstr "Oppdater Graf"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Edit Member"
-msgstr "Medlemmer"
+msgstr "Rediger Medlem"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
@@ -12549,7 +12495,7 @@ msgstr "Sti leder ikke Node!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
-msgstr "Ugyldig indeks egenskap navn '%s' i node %s."
+msgstr "Ugyldig navn for indeksegenskap '%s' i noden %s."
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid argument of type: "
@@ -12899,6 +12845,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -13087,9 +13041,8 @@ msgid "Saving lightmaps"
msgstr "Genererer Lyskart"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Ferdig!"
+msgstr "Ferdig"
#: scene/3d/collision_object.cpp
msgid ""
@@ -13157,11 +13110,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13291,9 +13239,8 @@ msgid "In node '%s', invalid animation: '%s'."
msgstr ""
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Invalid animation: '%s'."
-msgstr "ERROR: Ugyldig animasjonsnavn!"
+msgstr "Ugyldig animasjon: '%s'."
#: scene/animation/animation_tree.cpp
#, fuzzy
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 33362f4e57..e12d8c9324 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -47,7 +47,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-01 20:53+0000\n"
+"PO-Revision-Date: 2021-02-05 23:44+0000\n"
"Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/"
"nl/>\n"
@@ -686,7 +686,7 @@ msgstr "Selecteer sporen om te kopieren"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopiëren"
@@ -1703,7 +1703,7 @@ msgstr "Script Editor"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Asset bibliotheek"
+msgstr "Materiaalbibliotheek"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -1899,8 +1899,8 @@ msgid "Open a File or Directory"
msgstr "Bestand of map openen"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Opslaan"
@@ -2577,7 +2577,8 @@ msgstr ""
"mislukt."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Onmogelijk om scriptveld te vinden voor de plugin op: 'res://addons/%s'."
@@ -2901,7 +2902,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr "Toon collision shapes"
+msgstr "Botsingsvormen tonen"
#: editor/editor_node.cpp
#, fuzzy
@@ -3011,14 +3012,6 @@ msgid "Help"
msgstr "Help"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Zoeken"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Documentatie"
@@ -3185,6 +3178,25 @@ msgid "Open & Run a Script"
msgstr "Voer Een Script Uit"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"De volgende bestanden zijn nieuwer op de schijf.\n"
+"Welke aktie moet worden genomen?:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Herladen"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Heropslaan"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nieuw afgeleid type"
@@ -3210,7 +3222,7 @@ msgstr "Open Script Bewerker"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
-msgstr "Open Asset Bibliotheek"
+msgstr "Open Materiaalbibliotheek"
#: editor/editor_node.cpp
msgid "Open the next Editor"
@@ -3396,7 +3408,7 @@ msgstr "Maak Uniek"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Plakken"
@@ -3714,6 +3726,11 @@ msgstr ""
"handmatig."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kan de hoofdmap voor bronnen niet verplaatsen of van naam veranderen."
@@ -4101,6 +4118,25 @@ msgstr ""
msgid "Saving..."
msgstr "Opslaan..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Selecteermodus"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importeren"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Laad standaard"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Bestanden"
@@ -5068,7 +5104,8 @@ msgid "Got:"
msgstr "Gekregen:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "SHA256-proef mislukt"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5172,7 +5209,6 @@ msgid "Sort:"
msgstr "Sorteren op:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categorie:"
@@ -7002,6 +7038,14 @@ msgstr "Sluit Docs"
msgid "Run"
msgstr "Uitvoeren"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Zoeken"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Stap In"
@@ -7055,16 +7099,6 @@ msgstr ""
"De volgende bestanden zijn nieuwer op de schijf.\n"
"Welke aktie moet worden genomen?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Herladen"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Heropslaan"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Debugger"
@@ -7158,8 +7192,8 @@ msgstr "Breekpunten"
msgid "Go To"
msgstr "Ga Naar"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Knippen"
@@ -7568,6 +7602,11 @@ msgstr "Beeldrotatie vergrendeld"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7799,7 +7838,7 @@ msgstr "Polygon2D Voorbeeldweergave"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create CollisionPolygon2D"
-msgstr "Creëer CollisionPolygon2D"
+msgstr "CollisionPolygon2D aanmaken"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "CollisionPolygon2D Preview"
@@ -7841,11 +7880,11 @@ msgstr "Naar Polygon2D omzetten"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
-msgstr "Ongeldige geometrie, kan geen collision polygoon creëren."
+msgstr "Ongeldige geometrie, kan geen botsingspolygoon aanmaken."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create CollisionPolygon2D Sibling"
-msgstr "Creëer CollisionPolygon2D Sibling"
+msgstr "CollisionPolygon2D aanmaken"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create light occluder."
@@ -8551,7 +8590,7 @@ msgstr "Tegelbitmasker bewerken"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Collision Polygon"
-msgstr "Bewerk Collision Polygon"
+msgstr "Botsingspolygoon aanpassen"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Occlusion Polygon"
@@ -8583,7 +8622,7 @@ msgstr "Verwijder Tile"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Collision Polygon"
-msgstr "Verwijder Collision Polygon"
+msgstr "Botsingsvorm verwijderen"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Occlusion Polygon"
@@ -8611,7 +8650,7 @@ msgstr "Maak concaaf"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create Collision Polygon"
-msgstr "Creëer Collision Polygon"
+msgstr "Botsingsvorm aanmaken"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create Occlusion Polygon"
@@ -10085,6 +10124,11 @@ msgid "Projects"
msgstr "Projecten"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Mirrors ophalen, even wachten a.u.b..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Laatst bewerkt"
@@ -10122,7 +10166,7 @@ msgid ""
"Would you like to explore official example projects in the Asset Library?"
msgstr ""
"U heeft momenteel geen projecten.\n"
-"Wilt u de officiële voorbeeldprojecten verkennen in de Asset Library?"
+"Wilt u officiële voorbeeldprojecten verkennen in de Materiaalbibliotheek?"
#: editor/project_manager.cpp
msgid ""
@@ -10455,6 +10499,11 @@ msgstr "Automatisch Laden"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Laad standaard"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Voorinstelling..."
@@ -10706,6 +10755,16 @@ msgid "Instance Child Scene"
msgstr "Scène instantiëren"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "Kan deze operatie niet uitvoeren op knopen uit een vreemde scène!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Knopen plakken"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Script losmaken"
@@ -10833,6 +10892,11 @@ msgid "Attach Script"
msgstr "Script toevoegen"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Knopen knippen"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Verwijder knoop/knopen"
@@ -10946,6 +11010,13 @@ msgid "Remote"
msgstr "Remote"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokaal"
@@ -12472,10 +12543,10 @@ msgid ""
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
"define its shape."
msgstr ""
-"Deze knoop heeft geen vorm (Shape), dus kan het niet met andere objecten "
-"botsen of interactie hebben.\n"
-"Overweeg om een CollisionShape2D of CollisionPolygon2D als kind toe te "
-"voegen om de vorm ervan vast te leggen."
+"Deze knoop heeft geen botsingsvorm als onderliggende knoop en kan dus niet "
+"met andere objecten botsen of interageren.\n"
+"Plaats hieronder een knoop als CollisionShape2D of CollisionPolygon2D om "
+"deze vorm vast te leggen."
#: scene/2d/collision_polygon_2d.cpp
msgid ""
@@ -12483,13 +12554,22 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
-"CollisionPolygon2D dient enkel om een botsingsvorm te koppelen aan een knoop "
-"afgeleid van CollisionObject2D. Plaats hem onder een Area2D-, StaticBody2D-, "
-"RigidBody2D- of KinematicBody2D-knoop."
+"Een knooppunt van het type CollisionPolygon2D kan alleen een botsingsvorm "
+"keveren aan knopen die zijn afgeleid van CollisionObject2D. Plaats het dus "
+"alleen onder een knoop als Area2D, StaticBody2D, RigidBody2D of "
+"KinematicBody2D."
#: scene/2d/collision_polygon_2d.cpp
msgid "An empty CollisionPolygon2D has no effect on collision."
-msgstr "Een lege CollisionPolygon2D heeft geen effect op botsingen."
+msgstr "Lege CollisionPolygon2D hebben geen botsingsfunctie."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12497,15 +12577,16 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
-"CollisionShape2D dient enkel om een botsingsvorm te koppelen aan een knoop "
-"afgeleid van CollisionObject2D. Plaats hem onder een Area2D-, StaticBody2D-, "
-"RigidBody2D- of KinematicBody2D-knoop."
+"Een knooppunt van het type CollisionShape2D kan alleen een botsingsvorm "
+"keveren aan knopen die zijn afgeleid van CollisionObject2D. Plaats het dus "
+"alleen onder een knoop als Area2D, StaticBody2D, RigidBody2D of "
+"KinematicBody2D."
#: scene/2d/collision_shape_2d.cpp
msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
-msgstr "Een CollisionShape2D heeft een vorm nodig in de Shape-eigenschap!"
+msgstr "Een CollisionShape2D heeft een vorm nodig."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12621,9 +12702,9 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
-"Grootteveranderingen van een RigidBody2D (in Character- of Rigidmodus) zal "
-"overschreven worden door de physics engine als het spel start.\n"
-"Verander in plaats daarvan de grootte van CollisionShapes in de kinderen."
+"De grootte van een RigidBody2D (in Character- of Rigidmodus) wordt "
+"overschreven wanneer het spel start.\n"
+"Verander in plaats daarvan de grootte van de onderliggende botsingsvormen."
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
@@ -12652,10 +12733,9 @@ msgid ""
"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
"KinematicBody2D, etc. to give them a shape."
msgstr ""
-"TileMap met de optie \"Use Parent\" aan heeft een CollisionShape2D-ouder "
-"nodig om vormen aan te geven. De TileMap hoort een kind van een Area2D, "
-"StaticBody2D, RigidBody2D, KinematicBody2D enz. knoop te zijn om ze een vorm "
-"te geven."
+"Een TileMap met de optie \"Use Parent\" ingeschakeld moet knoop afgeleid van "
+"CollisionObject2D (Area2D, StaticBody2D, RigidBody2D of KinematicBody2D) als "
+"ouder hebben."
#: scene/2d/visibility_notifier_2d.cpp
msgid ""
@@ -12732,10 +12812,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
-"Deze knoop heeft geen vorm (Shape), dus het kan niet met andere objecten "
-"botsen of interactie hebben.\n"
-"Overweeg om een CollisionShape of CollisionPolygon als kind toe te voegen om "
-"de vorm ervan vast te leggen."
+"Deze knoop heeft geen botsingsvorm als onderliggende knoop en kan dus niet "
+"met andere objecten botsen of interageren.\n"
+"Plaats hieronder een knoop als CollisionShape of CollisionPolygon om deze "
+"vorm vast te leggen."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12743,13 +12823,13 @@ msgid ""
"CollisionObject derived node. Please only use it as a child of Area, "
"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
msgstr ""
-"CollisionPolygon dient enkel om een botsingsvorm te koppelen aan een knoop "
-"afgeleid van CollisionObject. Plaats hem onder een Area-, StaticBody-, "
-"RigidBody- of KinematicBody-knoop."
+"Een knooppunt van het type CollisionPolygon kan alleen een botsingsvorm "
+"keveren aan knopen die zijn afgeleid van CollisionObject. Plaats het dus "
+"alleen onder een knoop als Area, StaticBody, RigidBody of KinematicBody."
#: scene/3d/collision_polygon.cpp
msgid "An empty CollisionPolygon has no effect on collision."
-msgstr "Een lege CollisionPolygon heeft geen effect op botsingen."
+msgstr "Lege CollisionPolygon hebben geen botsingsfunctie."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12757,17 +12837,15 @@ msgid ""
"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
"KinematicBody, etc. to give them a shape."
msgstr ""
-"CollisionShape dient enkel om een botsingsvorm te koppelen aan een knoop "
-"afgeleid van CollisionObject. Plaats hem onder een Area-, StaticBody-, "
-"RigidBody- of KinematicBody-knoop."
+"Een knooppunt van het type CollisionShape kan alleen een botsingsvorm "
+"keveren aan knopen die zijn afgeleid van CollisionObject2D. Plaats het dus "
+"alleen onder een knoop als Area, StaticBody, RigidBody of KinematicBody."
#: scene/3d/collision_shape.cpp
msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
-msgstr ""
-"Om CollisionShape te laten werken, hoort het een Shape te hebben. Maak "
-"hiervoor alstublieft een Shape bron aan."
+msgstr "Een CollisionShape heeft een vorm nodig."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12810,11 +12888,6 @@ msgstr ""
"GIProbes worden niet ondersteund door het GLES2 grafische stuurprogramma.\n"
"Gebruik in plaats daarvan een BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12876,9 +12949,9 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
-"Grootteveranderingen van een RigidBody (in Character- of Rigidmodus) zal "
-"overschreven worden door de physics engine als het spel start.\n"
-"Verander in plaats daarvan de grootte van CollisionShapes in de kinderen."
+"De grootte van een RigidBody (in Character- of Rigidmodus) wordt "
+"overschreven wanneer het spel start.\n"
+"Verander in plaats daarvan de grootte van de onderliggende botsingsvormen."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
@@ -12918,9 +12991,8 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
-"Grootteveranderingen van een SoftBody (in Character- of Rigidmodus) zal "
-"overschreven worden door de physics engine als het spel start.\n"
-"Verander de grootte van CollisionShapes in de kinderen."
+"De grootte van een SoftBody wordt overschreven wanneer het spel start.\n"
+"Verander in plaats daarvan de grootte van de onderliggende botsingsvormen."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -13065,9 +13137,8 @@ msgid "Must use a valid extension."
msgstr "Een geldige extensie moet gebruikt worden."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Aan raster kleven"
+msgstr "Rasteroverzicht inschakelen."
#: scene/gui/popup.cpp
msgid ""
diff --git a/editor/translations/or.po b/editor/translations/or.po
index 334b5b903e..77e9075f6a 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -625,7 +625,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1794,8 +1794,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2429,7 +2429,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2819,14 +2819,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2980,6 +2972,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3182,7 +3190,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3486,6 +3494,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3863,6 +3876,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4810,7 +4839,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4914,7 +4943,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6681,6 +6709,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6732,16 +6768,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6834,8 +6860,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7241,6 +7267,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9580,6 +9611,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9940,6 +9975,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10183,6 +10222,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10303,6 +10350,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10410,6 +10461,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11877,6 +11935,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12132,11 +12198,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 9d783625b9..122c89f2b6 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -5,7 +5,7 @@
# 8-bit Pixel <dawdejw@gmail.com>, 2016.
# Adam Wolanski <adam.wolanski94@gmail.com>, 2017.
# Adrian Węcławski <weclawskiadrian@gmail.com>, 2016.
-# aelspire <aelspire@gmail.com>, 2017, 2019, 2020.
+# aelspire <aelspire@gmail.com>, 2017, 2019, 2020, 2021.
# Daniel Lewan <vision360.daniel@gmail.com>, 2016-2018, 2020.
# Dariusz Król <rexioweb@gmail.com>, 2018.
# heya10 <igor.gielzak@gmail.com>, 2017.
@@ -26,7 +26,7 @@
# Zatherz <zatherz@linux.pl>, 2017, 2020.
# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021.
# Wojcieh Er Zet <wojcieh.rzepecki@gmail.com>, 2018.
-# Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020.
+# Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020, 2021.
# Szymon Nowakowski <smnbdg13@gmail.com>, 2019.
# Nie Powiem <blazek10@tlen.pl>, 2019.
# Sebastian Hojka <sibibibi1@gmail.com>, 2019.
@@ -43,14 +43,16 @@
# Filip Glura <mcmr.slendy@gmail.com>, 2020.
# Roman Skiba <romanskiba0@gmail.com>, 2020.
# Piotr Grodzki <ziemniakglados@gmail.com>, 2020.
-# Dzejkop <jakubtrad@gmail.com>, 2020.
+# Dzejkop <jakubtrad@gmail.com>, 2020, 2021.
# Mateusz Grzonka <alpinus4@gmail.com>, 2020.
# gnu-ewm <gnu.ewm@protonmail.com>, 2021.
+# vrid <patryksoon@live.com>, 2021.
+# Suchy Talerz <kacperkubis06@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-01 20:54+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -60,7 +62,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -282,7 +284,7 @@ msgstr "Klipy dźwiękowe:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr "Klipy animacji:"
+msgstr "Animacje:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -290,7 +292,7 @@ msgstr "Zmień adres ścieżki"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Włącz/wyłącz tę ścieżkę."
+msgstr "Włącz/wyłącz ścieżkę."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -688,7 +690,7 @@ msgstr "Wybierz ścieżki do skopiowania"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopiuj"
@@ -1496,7 +1498,7 @@ msgstr "Zmień nazwę Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr "Przełącz automatycznie ładowane zmienne globalne"
+msgstr "Globalnie przełącz Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
@@ -1793,7 +1795,7 @@ msgstr "Nowy"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importuj"
+msgstr "Zaimportuj"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1890,8 +1892,8 @@ msgid "Open a File or Directory"
msgstr "Otwórz plik lub katalog"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Zapisz"
@@ -2562,8 +2564,8 @@ msgstr ""
"Nie można włączyć dodatku: \"%s\" - parsowanie konfiguracji nie powiodło się."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "Nie można odnaleźć pola skryptu w dodatku: \"res://addons/%s\"."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Nie można odnaleźć pola skryptu w dodatku: \"%s\"."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2993,14 +2995,6 @@ msgid "Help"
msgstr "Pomoc"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Szukaj"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Dokumentacja online"
@@ -3015,7 +3009,7 @@ msgstr "Zgłoś błąd"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr "Wyślij opinię o dokumentacji"
+msgstr "Oceń dokumentację"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3164,6 +3158,24 @@ msgid "Open & Run a Script"
msgstr "Otwórz i Uruchom Skrypt"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Następujące pliki są nowsze na dysku.\n"
+"Jakie działanie powinno zostać podjęte?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Przeładuj"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Zapisz ponownie"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Nowa dziedzicząca scena"
@@ -3374,7 +3386,7 @@ msgstr "Zrób unikalny"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Wklej"
@@ -3691,6 +3703,13 @@ msgstr ""
"zaimportować ręcznie."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Importowanie zostało wyłączone dla tego pliku, więc nie może być otwarty do "
+"edytowania."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nie można przenieść/zmienić nazwy korzenia zasobów."
@@ -4080,6 +4099,22 @@ msgstr "Czy zwracasz obiekt dziedziczący po Node w metodzie `post_import()`?"
msgid "Saving..."
msgstr "Zapisywanie..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Wybierz importer"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importer:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Resetuj do domyślnych"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Zachowaj plik (brak importu)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d plików"
@@ -5048,8 +5083,8 @@ msgid "Got:"
msgstr "Otrzymano:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Nie udało się przeprowadzić testu integralności sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Test SHA-256 nieudany"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5152,7 +5187,6 @@ msgid "Sort:"
msgstr "Sortuj:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategoria:"
@@ -6979,6 +7013,14 @@ msgstr "Zamknij pliki pomocy"
msgid "Run"
msgstr "Uruchom"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Szukaj"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Krok w"
@@ -7032,16 +7074,6 @@ msgstr ""
"Następujące pliki są nowsze na dysku.\n"
"Jakie działania powinny zostać podjęte?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Przeładuj"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Zapisz ponownie"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Debugger"
@@ -7137,8 +7169,8 @@ msgstr "Punkty wstrzymania"
msgid "Go To"
msgstr "Idź do"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Wytnij"
@@ -7361,9 +7393,8 @@ msgid "Yaw"
msgstr "Odchylenie"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Rozmiar: "
+msgstr "Rozmiar"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7547,6 +7578,11 @@ msgstr "Obroty widoku zablokowane"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7835,7 +7871,7 @@ msgstr "Utwórz równorzędny węzeł LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
-msgstr "Sprite"
+msgstr "Postać"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
@@ -8044,7 +8080,7 @@ msgstr "Dodaj klasę elementów"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Usuń klasę elementów"
+msgstr "Usuń elementy klasy"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
@@ -8541,7 +8577,7 @@ msgstr "Edytuj wielokąt nawigacji"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Paste Tile Bitmask"
-msgstr "Wklej maskę bitową Kafelka"
+msgstr "Wklej maskę bitową kafelka"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Clear Tile Bitmask"
@@ -10051,6 +10087,10 @@ msgid "Projects"
msgstr "Projekty"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Wczytywanie, proszę czekać..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Data modyfikacji"
@@ -10421,6 +10461,10 @@ msgstr "Autoładowanie"
msgid "Plugins"
msgstr "Wtyczki"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Domyślny import"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Ustawienie predefiniowane..."
@@ -10670,6 +10714,14 @@ msgid "Instance Child Scene"
msgstr "Dodaj instancję sceny"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Nie można wkleić korzenia do tej samej sceny."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Wklej węzeł/y"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Odłącz skrypt"
@@ -10796,6 +10848,10 @@ msgid "Attach Script"
msgstr "Dołącz skrypt"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Wytnij węzeł/y"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Usuń węzeł(y)"
@@ -10910,6 +10966,13 @@ msgid "Remote"
msgstr "Zdalny"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokalny"
@@ -11516,7 +11579,7 @@ msgstr "Malowanie GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
-msgstr "Grid Map"
+msgstr "Siatka"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
@@ -12457,6 +12520,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Pusty CollisionPolygon2D nie ma wpływu na kolizje."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Nieprawidłowy wielokąt. Co najmniej 3 punkty są potrzebne do trybu budowania "
+"\"Solids\"."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Nieprawidłowy wielokąt. Co najmniej 3 punkty są potrzebne do trybu budowania "
+"\"Segments\"."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12778,12 +12853,6 @@ msgstr ""
"GIProbes nie są obsługiwane przez sterownik wideo GLES2.\n"
"Zamiast tego użyj BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-"Węzeł InterpolatedCamera jest przestarzały i będzie usunięty w Godocie 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight z kątem szerszym niż 90 stopni nie może rzucać cieni."
@@ -13123,6 +13192,12 @@ msgstr "Varying może być przypisane tylko w funkcji wierzchołków."
msgid "Constants cannot be modified."
msgstr "Stałe nie mogą być modyfikowane."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "Węzeł InterpolatedCamera jest przestarzały i będzie usunięty w Godocie "
+#~ "4.0."
+
#~ msgid "No"
#~ msgstr "Nie"
@@ -14743,9 +14818,6 @@ msgstr "Stałe nie mogą być modyfikowane."
#~ msgid "Use Default Light"
#~ msgstr "Użyj domyślnego światła"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Użyj domyślnie sRGB"
-
#~ msgid "Ambient Light Color:"
#~ msgstr "Kolor światła otoczenia:"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index f8ea72a750..24e2c7146a 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -656,7 +656,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1862,8 +1862,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2510,7 +2510,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2911,14 +2911,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3075,6 +3067,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3283,7 +3291,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3601,6 +3609,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3996,6 +4009,23 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Slit th' Node"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -4979,7 +5009,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5083,7 +5113,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6901,6 +6930,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6953,16 +6990,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7059,8 +7086,8 @@ msgstr "Yar, Blow th' Selected Down!"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7480,6 +7507,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9915,6 +9947,10 @@ msgid "Projects"
msgstr "Rename Function"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10281,6 +10317,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10529,6 +10569,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Paste yer Node"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Discharge ye' Variable"
@@ -10654,6 +10703,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Slit th' Node"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10766,6 +10820,13 @@ msgid "Remote"
msgstr "Discharge ye' Signal"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12322,6 +12383,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12577,11 +12646,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index 0d3524786b..26c28d5a19 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-26 03:28+0000\n"
+"PO-Revision-Date: 2021-04-20 22:25+0000\n"
"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -661,7 +661,7 @@ msgstr "Selecionar Pistas a Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -1867,8 +1867,8 @@ msgid "Open a File or Directory"
msgstr "Abrir um Ficheiro ou Diretoria"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Guardar"
@@ -2542,8 +2542,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "Incapaz de ativar plugin em: '%s' falha de análise ou configuração."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "Incapaz de localizar campo Script para plugin em: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Incapaz de localizar campo script para plugin em: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2975,14 +2975,6 @@ msgid "Help"
msgstr "Ajuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Procurar"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentação Online"
@@ -3147,6 +3139,24 @@ msgid "Open & Run a Script"
msgstr "Abrir & Executar um Script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Os seguintes ficheiros são mais recentes no disco.\n"
+"Que ação deve ser tomada?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Recarregar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Guardar novamente"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Novo Herdado"
@@ -3357,7 +3367,7 @@ msgstr "Fazer único"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Colar"
@@ -3677,6 +3687,13 @@ msgstr ""
"manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"A importação foi desativada para este ficheiro, não podendo ser aberto para "
+"edição."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Não consegui mover/renomear raiz dos recursos."
@@ -4064,6 +4081,22 @@ msgstr "Devolveu um objeto derivado de Nó no método `post_import()`?"
msgid "Saving..."
msgstr "A guardar..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Selecionar Importador"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importador:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Restaurar Predefinições"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Manter Ficheiro (Sem Importação)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Ficheiros"
@@ -5030,8 +5063,8 @@ msgid "Got:"
msgstr "Obtido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Verificação hash sha256 falhada"
+msgid "Failed SHA-256 hash check"
+msgstr "Falhou a verificação hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5134,7 +5167,6 @@ msgid "Sort:"
msgstr "Ordenar:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoria:"
@@ -6955,6 +6987,14 @@ msgstr "Fechar documentos"
msgid "Run"
msgstr "Executar"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Procurar"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Passar Dentro"
@@ -7008,16 +7048,6 @@ msgstr ""
"Os seguintes Ficheiros são mais recentes no disco.\n"
"Que ação deve ser tomada?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Recarregar"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Guardar novamente"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Depurador"
@@ -7110,8 +7140,8 @@ msgstr "Pontos de paragem"
msgid "Go To"
msgstr "Ir Para"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Cortar"
@@ -7334,9 +7364,8 @@ msgid "Yaw"
msgstr "Direção"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamanho: "
+msgstr "Tamanho"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7520,6 +7549,11 @@ msgstr "Rotação da Vista Bloqueada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10018,6 +10052,10 @@ msgid "Projects"
msgstr "Projetos"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "A carregar, espere por favor..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Última modificação"
@@ -10388,6 +10426,10 @@ msgstr "Carregamento automático"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Importar Predefinições"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Predefinição..."
@@ -10637,6 +10679,14 @@ msgid "Instance Child Scene"
msgstr "Instanciar Cena Filha"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Não consigo colar o nó raiz na mesma cena."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Colar Nó(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Separar Script"
@@ -10763,6 +10813,10 @@ msgid "Attach Script"
msgstr "Anexar Script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Cortar Nó(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Remover Nó(s)"
@@ -10877,6 +10931,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -12428,6 +12489,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Um CollisionPolygon2D vazio não tem efeito na colisão."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Polígono inválido. São precisos pelo menos 3 pontos no modo de construção "
+"'Sólidos'."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Polígono inválido. São precisos pelo menos 2 pontos no modo de construção "
+"'Segmentos'."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12741,11 +12814,6 @@ msgstr ""
"Sondas GI não são suportadas pelo driver vídeo GLES2.\n"
"Em vez disso, use um BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamerda foi descontinuada e será removida no Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "Uma SpotLight com ângulo superior a 90 graus não cria sombras."
@@ -13086,6 +13154,10 @@ msgstr "Variações só podem ser atribuídas na função vértice."
msgid "Constants cannot be modified."
msgstr "Constantes não podem ser modificadas."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamerda foi descontinuada e será removida no Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Não"
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index b20cc35809..3509d790d8 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -20,7 +20,7 @@
# MalcomRF <malcomkbk@gmail.com>, 2017.
# Marcus Correia <marknokalt@live.com>, 2017-2018.
# Michael Alexsander Silva Dias <michaelalexsander@protonmail.com>, 2017-2018.
-# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019.
+# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021.
# Rodolfo R Gomes <rodolforg@gmail.com>, 2017-2018, 2019.
# Tiago Almeida <thyagoeap@gmail.com>, 2017.
# Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>, 2018.
@@ -112,12 +112,15 @@
# Lucas Castro <castroclucas@gmail.com>, 2021.
# Ricardo Zamarrenho Carvalho Correa <ricardozcc17@gmail.com>, 2021.
# Diego dos Reis Macedo <diego_dragon97@hotmail.com>, 2021.
+# Lucas E. <lukas.ed45@gmail.com>, 2021.
+# Gabriel Silveira <gabomfim99@gmail.com>, 2021.
+# Arthur Phillip D. Silva <artphil.dev@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2021-02-05 09:20+0000\n"
-"Last-Translator: Lucas Castro <castroclucas@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Arthur Phillip D. Silva <artphil.dev@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -125,7 +128,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -753,7 +756,7 @@ msgstr "Selecionar Trilhas para Copiar"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiar"
@@ -1959,8 +1962,8 @@ msgid "Open a File or Directory"
msgstr "Abrir Arquivo ou Diretório"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Salvar"
@@ -2635,22 +2638,24 @@ msgstr ""
"falhou."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
-"Não foi possível encontrar o campo de script para o plugin em: 'res://addons/"
-"%s'."
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "Não foi possível carregar o script complementar do caminho: '%s'."
+msgstr ""
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
-"Não foi possível carregar o script complementar do caminho: '%s' Parece "
-"haver um erro no código, por favor verifique a sintaxe."
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%s'."
#: editor/editor_node.cpp
msgid ""
@@ -3070,14 +3075,6 @@ msgid "Help"
msgstr "Ajuda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Pesquisar"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentação Online"
@@ -3243,6 +3240,24 @@ msgid "Open & Run a Script"
msgstr "Abrir e Rodar um Script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Os seguintes arquivos são mais recentes no disco.\n"
+"Que ação deve ser tomada?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Recarregar"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Salve novamente"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Novo Herdado"
@@ -3454,7 +3469,7 @@ msgstr "Tornar Único"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Colar"
@@ -3774,6 +3789,13 @@ msgstr ""
"reimporte manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"A importação foi desativada para este arquivo, por isso não pode ser aberto "
+"para edição."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossível mover/renomear raiz dos recursos."
@@ -4161,6 +4183,22 @@ msgstr "Você retornou um objeto derivado de Nó no método `post_import()`?"
msgid "Saving..."
msgstr "Salvando..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Selecione o arquivo para importar"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importar:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Redefinir para os padrões"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Manter Arquivo (Sem Importação)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Arquivos"
@@ -5133,8 +5171,8 @@ msgid "Got:"
msgstr "Obtido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Falha na verificação da hash sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Falha na verificação do hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5237,7 +5275,6 @@ msgid "Sort:"
msgstr "Ordenar:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categoria:"
@@ -5310,7 +5347,7 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
-msgstr "Bake Lightmaps"
+msgstr "Faça mapas de luz"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
@@ -7065,6 +7102,14 @@ msgstr "Fechar Docs"
msgid "Run"
msgstr "Rodar"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Pesquisar"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Passo para dentro"
@@ -7118,16 +7163,6 @@ msgstr ""
"Os seguintes arquivos são mais recentes no disco.\n"
"Que ação deve ser tomada?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Recarregar"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Salve novamente"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Depurador"
@@ -7221,8 +7256,8 @@ msgstr "Breakpoints"
msgid "Go To"
msgstr "Ir Para"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Recortar"
@@ -7422,7 +7457,7 @@ msgstr "Escala: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translating: "
-msgstr "Transladando: "
+msgstr "Transladar: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
@@ -7445,9 +7480,8 @@ msgid "Yaw"
msgstr "Guinada"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Tamanho: "
+msgstr "Tamanho"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7631,6 +7665,11 @@ msgstr "Ver Rotação Bloqueada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8869,7 +8908,7 @@ msgstr "Tipo de Entrada de Shader Visual Alterado"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "UniformRef Name Changed"
-msgstr "UniformRef Name foi altearado"
+msgstr "Ref. Uniforme Nome alterado"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -10133,6 +10172,10 @@ msgid "Projects"
msgstr "Projetos"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Carregando, por favor aguarde."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Ultima Modificação"
@@ -10473,7 +10516,7 @@ msgstr "Remapeamentos por Localidade:"
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr "Locale"
+msgstr "Localizar"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
@@ -10503,6 +10546,10 @@ msgstr "O AutoLoad"
msgid "Plugins"
msgstr "Plugins"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Importar padrões"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Predefinição..."
@@ -10513,11 +10560,11 @@ msgstr "Zero"
#: editor/property_editor.cpp
msgid "Easing In-Out"
-msgstr "Easing In-Out"
+msgstr "Facilitar Entrada-Saída"
#: editor/property_editor.cpp
msgid "Easing Out-In"
-msgstr "Easing Out-In"
+msgstr "Facilitar Saída-Entrada"
#: editor/property_editor.cpp
msgid "File..."
@@ -10752,6 +10799,14 @@ msgid "Instance Child Scene"
msgstr "Instânciar Cena Filha"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Não é possível colar o nó raiz na mesma cena."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Colar Nó(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Remover Script"
@@ -10878,6 +10933,10 @@ msgid "Attach Script"
msgstr "Adicionar Script"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Recortar Nó(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Remover Nó(s)"
@@ -10992,6 +11051,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -11686,7 +11752,6 @@ msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
msgstr "Atribua um recurso MeshLibrary a este GridMap para usar seus meshes."
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Begin Bake"
msgstr "Iniciar pré-cálculo"
@@ -11707,12 +11772,10 @@ msgid "Indirect lighting"
msgstr "Iluminação indireta"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "Pós-processamento"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
msgstr "Traçando mapas de luz"
@@ -12546,6 +12609,18 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Um nó CollisionPolygon2D vazio não é efetivo para colisão."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Polígono inválido. Pelo menos 3 pontos são necessários no modo de construção "
+"\"Sólidos\"."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Polígono inválido. Pelo menos 2 pontos são necessários no modo de construção "
+"\"Segmentos\"."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12759,9 +12834,8 @@ msgid "Finding meshes and lights"
msgstr "Encontrando malhas e luzes"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Analisando Geometria..."
+msgstr "Preparando geometria (%d/%d)"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing environment"
@@ -12772,9 +12846,8 @@ msgid "Generating capture"
msgstr "Gerando captura"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Salvando mapas de luz"
+msgstr "Salvando mapas de luz"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
@@ -12865,11 +12938,6 @@ msgstr ""
"GIProbes não são suportados pelo driver de vídeo GLES2.\n"
"Use um BakedLightmap em vez disso."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "IntepolatedCamera foi depreciada e será removida no Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "Um SpotLight com um ângulo maior que 90 graus não pode criar sombras."
@@ -13213,6 +13281,10 @@ msgstr "Variáveis só podem ser atribuídas na função de vértice."
msgid "Constants cannot be modified."
msgstr "Constantes não podem serem modificadas."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "IntepolatedCamera foi depreciada e será removida no Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Não"
@@ -14872,9 +14944,6 @@ msgstr "Constantes não podem serem modificadas."
#~ msgid "Use Default Light"
#~ msgstr "Usar Luz Padrão"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Usar sRGB Padrão"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Luz Normal Padrão:"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 100afe3cb9..5761aadd1d 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -14,12 +14,13 @@
# Teodor <teo.virghi@yahoo.ro>, 2020.
# f0roots <f0rootss@gmail.com>, 2020.
# Gigel2 <mihalacher02@gmail.com>, 2020.
+# R3ktGamerRO <bluegamermc1@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-22 21:37+0000\n"
-"Last-Translator: Gigel2 <mihalacher02@gmail.com>\n"
+"PO-Revision-Date: 2021-03-20 04:18+0000\n"
+"Last-Translator: R3ktGamerRO <bluegamermc1@gmail.com>\n"
"Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ro/>\n"
"Language: ro\n"
@@ -28,18 +29,16 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
-"X-Generator: Weblate 4.3.1\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
-#, fuzzy
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "Argument invalid pentru transformare(), folosiți constante TYPE_*."
+msgstr "Argument invalid pentru convert(), folosiți constante TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
-#, fuzzy
msgid "Expected a string of length 1 (a character)."
-msgstr "Se așteaptă un șir de lungime 1 (un caracter)."
+msgstr "Se așteaptă un text cu lungime de 1 (un caracter)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -52,9 +51,8 @@ msgid "Invalid input %i (not passed) in expression"
msgstr "Intrare invalida %i (nu a fost transmisă) in expresie"
#: core/math/expression.cpp
-#, fuzzy
msgid "self can't be used because instance is null (not passed)"
-msgstr "insuși nu poate fi folosit deoarece instanța este nulă(nu a trecut)"
+msgstr "insuși nu poate fi folosit deoarece instanța este nulă (nu a trecut)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -314,7 +312,7 @@ msgstr "Linear"
#: editor/animation_track_editor.cpp
msgid "Cubic"
-msgstr "Cubic"
+msgstr "Cub"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
@@ -661,7 +659,7 @@ msgstr "Selectează Pistele de Copiat"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Copiază"
@@ -703,7 +701,7 @@ msgstr "Linia Numărul:"
#: editor/code_editor.cpp
msgid "%d replaced."
-msgstr "%d Înlocuit"
+msgstr "%d Înlocuit."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
@@ -1042,14 +1040,14 @@ msgid "Owners Of:"
msgstr "Stăpâni La:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Ștergeți fișierele selectate din proiect? (Acțiune ireversibilă)"
+msgstr ""
+"Ștergeți fișierele selectate din proiect? (Acțiune ireversibilă)\n"
+"Poți gasi fișierele șterse in coșul de gunoi dacă vrei să le restabilești."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1058,7 +1056,8 @@ msgid ""
msgstr ""
"Fișierele în proces de ștergere sunt necesare pentru alte resurse ca ele să "
"sa funcționeze.\n"
-"Ștergeți oricum? (fără anulare)"
+"Ștergeți oricum? (fără anulare)\n"
+"Poți găsi fișierele șterse in coșul de gunoi dacă vrei să le restabilești."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1874,8 +1873,8 @@ msgid "Open a File or Directory"
msgstr "Deschideți un Fişier sau Director"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Salvați"
@@ -2548,7 +2547,8 @@ msgstr ""
"Nu se poate inițializa plugin-ul la: '%s' analizarea configurației a eșuat."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Nu a putut fi găsit câmpul scriptului pentru plugin la: 'res://addons/%s'."
@@ -2664,9 +2664,8 @@ msgid "Close Other Tabs"
msgstr "Închideți Celelalte File"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close Tabs to the Right"
-msgstr "Închidere file la dreapta"
+msgstr "Închidere file de la dreapta"
#: editor/editor_node.cpp
msgid "Close All Tabs"
@@ -2985,14 +2984,6 @@ msgid "Help"
msgstr "Ajutor"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Căutare"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Documentație Online"
@@ -3148,6 +3139,24 @@ msgid "Open & Run a Script"
msgstr "Deschide și Execută un Script"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Următoarele fișiere sunt mai noi pe disk.\n"
+"Ce măsuri ar trebui luate?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Derivare Nouă"
@@ -3350,7 +3359,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3663,6 +3672,11 @@ msgstr ""
"manual."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nu se poate muta/redenumi rădăcina resurselor."
@@ -4046,6 +4060,24 @@ msgstr ""
msgid "Saving..."
msgstr "Se Salvează..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Selectare mod"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importator:"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Încărcați Implicit"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fișiere"
@@ -5033,7 +5065,8 @@ msgid "Got:"
msgstr "Primit:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Verificare hash sha256 eșuată"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5142,7 +5175,6 @@ msgid "Sort:"
msgstr "Sorare:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Categorie:"
@@ -5214,9 +5246,8 @@ msgid "Bake Lightmaps"
msgstr "Procesează Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Selectare fișier șablon"
+msgstr "Selectare fișier șablon pentru harta de lumină:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7031,6 +7062,14 @@ msgstr ""
msgid "Run"
msgstr "Execută"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Căutare"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7083,16 +7122,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7193,8 +7222,8 @@ msgstr "Șterge puncte"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7616,6 +7645,11 @@ msgstr "Curăță Rotația Cursorului"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10069,6 +10103,11 @@ msgid "Projects"
msgstr "Proiect"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Se recuperează oglinzile, te rog așteaptă..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10437,6 +10476,11 @@ msgstr ""
msgid "Plugins"
msgstr "Plugin-uri"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Încărcați Implicit"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Presetare..."
@@ -10501,7 +10545,7 @@ msgstr "Redenumește"
#: editor/rename_dialog.cpp
#, fuzzy
msgid "Replace:"
-msgstr "Înlocuiți: "
+msgstr "Înlocuiți:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10615,9 +10659,8 @@ msgid "Reset"
msgstr "Resetați Zoom-area"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Folosiți expresii regulate"
+msgstr "Eroare de expresie regulată:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10686,6 +10729,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Lipește Postura"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Curăță Scriptul"
@@ -10815,6 +10867,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Creează Nod"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10928,6 +10985,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12449,6 +12513,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12619,14 +12691,12 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Analiza geometriei..."
+msgstr "Analiza geometriei (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Analiza geometriei..."
+msgstr "Pregătim mediul de lucru"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12639,9 +12709,8 @@ msgid "Saving lightmaps"
msgstr "Se Genereaza Lightmaps"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Efectuat!"
+msgstr "Efectuat"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12709,11 +12778,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12925,9 +12989,8 @@ msgid "Must use a valid extension."
msgstr "Trebuie să utilizaţi o extensie valida."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Activează aliniere"
+msgstr "Activează minimapa in format grilă."
#: scene/gui/popup.cpp
msgid ""
@@ -13258,10 +13321,6 @@ msgstr ""
#~ msgstr "Creează un Corp Static Convex"
#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Creează Nod"
-
-#, fuzzy
#~ msgid "Snap (s): "
#~ msgstr "Pas (s):"
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index 61f4d23157..b12e95793a 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -91,11 +91,13 @@
# Roman Tolkachyov <roman@tolkachyov.name>, 2020.
# Igor Grachev <igorecha.9999@gmail.com>, 2020.
# Dmytro Meleshko <dmytro.meleshko@gmail.com>, 2021.
+# narrnika <narr13niki@gmail.com>, 2021.
+# nec-trou <darya.bilyalova@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-01 20:54+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
@@ -105,7 +107,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -733,7 +735,7 @@ msgstr "Выбрать треки для копирования"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Копировать"
@@ -1938,8 +1940,8 @@ msgid "Open a File or Directory"
msgstr "Открыть каталог или файл"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Сохранить"
@@ -2077,7 +2079,7 @@ msgstr "Свойства"
#: editor/editor_help.cpp
msgid "override:"
-msgstr "Переопределить:"
+msgstr "переопределено:"
#: editor/editor_help.cpp
msgid "default:"
@@ -2614,8 +2616,8 @@ msgstr ""
"конфигурации."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "Не удаётся найти поле script для плагина: «res://addons/%s»."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Не удаётся найти поле script для плагина: «%s»."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3045,14 +3047,6 @@ msgid "Help"
msgstr "Справка"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Поиск"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Онлайн документация"
@@ -3219,6 +3213,24 @@ msgid "Open & Run a Script"
msgstr "Открыть и запустить скрипт"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Следующие файлы изменены на диске.\n"
+"Какое действие следует выполнить?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Перезагрузить"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Пересохранить"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Новая унаследованная сцена"
@@ -3429,7 +3441,7 @@ msgstr "Сделать уникальным"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Вставить"
@@ -3553,7 +3565,7 @@ msgstr "(Текущий)"
#: editor/export_template_manager.cpp
msgid "Retrieving mirrors, please wait..."
-msgstr "Получение зеркал, пожалуйста подождите..."
+msgstr "Получение зеркал, пожалуйста, ждите..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
@@ -3745,6 +3757,13 @@ msgstr ""
"переимпортируйте вручную."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Импорт был отключён для этого файла, поэтому его нельзя открыть для "
+"редактирования."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Нельзя переместить/переименовать корень."
@@ -3908,7 +3927,7 @@ msgid ""
"Please Wait..."
msgstr ""
"Сканирование файлов,\n"
-"пожалуйста, подождите..."
+"пожалуйста, ждите..."
#: editor/filesystem_dock.cpp
msgid "Move"
@@ -4132,6 +4151,22 @@ msgstr "Вы вернули производный от Node объект в м
msgid "Saving..."
msgstr "Сохранение..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Выберите импортёр"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Импортёр:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Сбросить настройки"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Сохранить файл (без импорта)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d файлов"
@@ -5088,7 +5123,7 @@ msgstr "Время ожидания."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
-msgstr "Несовпадение хэша загрузки, возможно файл был изменён."
+msgstr "Несовпадение хеша загрузки, возможно файл был изменён."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Expected:"
@@ -5099,8 +5134,8 @@ msgid "Got:"
msgstr "Получено:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Не удалось проверить sha256 хэш"
+msgid "Failed SHA-256 hash check"
+msgstr "Не удалось проверить хеш SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5203,7 +5238,6 @@ msgid "Sort:"
msgstr "Сортировка:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Категория:"
@@ -7025,6 +7059,14 @@ msgstr "Закрыть документацию"
msgid "Run"
msgstr "Запустить"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Поиск"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Шаг в"
@@ -7078,16 +7120,6 @@ msgstr ""
"Следующие файлы новее на диске.\n"
"Какие меры должны быть приняты?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Перезагрузить"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Пересохранить"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Отладчик"
@@ -7184,8 +7216,8 @@ msgstr "Точки останова"
msgid "Go To"
msgstr "Перейти к"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Вырезать"
@@ -7408,13 +7440,12 @@ msgid "Yaw"
msgstr "Рыскание"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Размер: "
+msgstr "Размер"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
-msgstr "Нарисовано обьектов"
+msgstr "Нарисовано объектов"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Material Changes"
@@ -7594,6 +7625,11 @@ msgstr "Блокировать вращение камеры"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10096,6 +10132,10 @@ msgid "Projects"
msgstr "Проекты"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Загрузка, пожалуйста, ждите..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Последнее изменение"
@@ -10465,6 +10505,10 @@ msgstr "Автозагрузка"
msgid "Plugins"
msgstr "Плагины"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Шаблоны импорта"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Предустановка..."
@@ -10716,6 +10760,14 @@ msgid "Instance Child Scene"
msgstr "Добавить дочернюю сцену"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Невозможно вставить корневой узел в ту же сцену."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Вставить узел(узлы)"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Открепить скрипт"
@@ -10843,6 +10895,10 @@ msgid "Attach Script"
msgstr "Прикрепить скрипт"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Вырезать узел(узлы)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Удалить узел(узлы)"
@@ -10957,6 +11013,13 @@ msgid "Remote"
msgstr "Удаленный"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Локальный"
@@ -12497,6 +12560,16 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Пустой CollisionPolygon2D не влияет на столкновения."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Недопустимый полигон. В режиме «Solids» необходимо по крайней мере 3 точки."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Недопустимый полигон. В режиме «Segments» необходимо по крайней мере 2 точки."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12819,11 +12892,6 @@ msgstr ""
"GIProbes не поддерживаются видеодрайвером GLES2.\n"
"Вместо этого используйте BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera устарела и будет удалена в Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight с углом более 90 градусов не может отбрасывать тени."
@@ -13164,6 +13232,10 @@ msgstr "Изменения могут быть назначены только
msgid "Constants cannot be modified."
msgstr "Константы не могут быть изменены."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera устарела и будет удалена в Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Нет"
@@ -14827,9 +14899,6 @@ msgstr "Константы не могут быть изменены."
#~ msgid "Use Default Light"
#~ msgstr "Использовать стандартный свет"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Использовать sRGB"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Образец стандартного освещения:"
diff --git a/editor/translations/si.po b/editor/translations/si.po
index e7aabd5542..20b9001362 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -647,7 +647,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1818,8 +1818,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2455,7 +2455,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2845,14 +2845,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3007,6 +2999,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3209,7 +3217,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3513,6 +3521,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3892,6 +3905,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4850,7 +4879,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4954,7 +4983,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6734,6 +6762,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6785,16 +6821,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6888,8 +6914,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7295,6 +7321,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9659,6 +9690,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10019,6 +10054,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10262,6 +10301,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "යතුරු පිටපත් කරන්න"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10386,6 +10434,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "යතුරු පිටපත් කරන්න"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10493,6 +10546,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11973,6 +12033,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12228,11 +12296,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index c7839822c9..95b0fc7136 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -10,12 +10,13 @@
# Richard <rgarlik@gmail.com>, 2019.
# Richard Urban <redasuio1@gmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
+# Mario-projects-dev <m.vitek.mv@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-03 15:29+0000\n"
-"Last-Translator: Richard Urban <redasuio1@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Mario-projects-dev <m.vitek.mv@gmail.com>\n"
"Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/"
"godot/sk/>\n"
"Language: sk\n"
@@ -23,7 +24,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -647,7 +648,7 @@ msgstr "Vybrať Track-y na skopírovanie"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopírovať"
@@ -1027,14 +1028,14 @@ msgid "Owners Of:"
msgstr "Majitelia:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Odstrániť vybraté súbory z projektu? (nedá sa vrátiť späť)"
+msgstr ""
+"Odstrániť vybraté súbory z projektu? (nedá sa vrátiť späť)\n"
+"Odstránené súbory nájdete v systémovom koši, aby ste ich mohli obnoviť."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1042,7 +1043,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Súbory ktoré budú odstránené vyžadujú ďalšie zdroje, aby mohli pracovať.\n"
-"Odstrániť aj napriek tomu? (nedá sa vrátiť späť)"
+"Odstrániť aj napriek tomu? (nedá sa vrátiť späť)\n"
+"Odstránené súbory nájdete v systémovom koši, aby ste ich mohli obnoviť."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1851,8 +1853,8 @@ msgid "Open a File or Directory"
msgstr "Otvoriť súbor / priečinok"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Uložiť"
@@ -1978,7 +1980,7 @@ msgstr "Zdedené používateľom:"
#: editor/editor_help.cpp
msgid "Description"
-msgstr "Popisok"
+msgstr "Popis"
#: editor/editor_help.cpp
msgid "Online Tutorials"
@@ -2519,7 +2521,8 @@ msgstr ""
"Addon plugin nie je možné povoliť pri: '% s' analýze konfigurácie zlyhalo."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Nepodarilo sa nájsť script field pre addon plugin v: 'res://addons/%s'."
@@ -2950,14 +2953,6 @@ msgid "Help"
msgstr "Pomoc"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Vyhľadať"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Online Dokumentácie"
@@ -3122,6 +3117,23 @@ msgid "Open & Run a Script"
msgstr "Otvoriť a vykonať skript"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr "Nasledovné súbory sa nepodarilo extrahovať z balíka:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Novo Zdedené"
@@ -3331,7 +3343,7 @@ msgstr "Spraviť Jedinečným"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Vložiť"
@@ -3645,6 +3657,11 @@ msgstr ""
"Status:Import súboru zlihal. Prosím opravte súbor a manuálne reimportujte."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nedá sa presunúť/premenovať \"resources root\"."
@@ -4030,6 +4047,25 @@ msgstr "Vrátili ste Node-derived objekt v `post_import()` metóde?"
msgid "Saving..."
msgstr "Ukladám..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Vybrať Režim"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Import"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Načítať predvolené"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Súbory"
@@ -4994,7 +5030,8 @@ msgid "Got:"
msgstr "Má:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Zlyhalo sha256 hash check"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5098,7 +5135,6 @@ msgid "Sort:"
msgstr "Zoradiť:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategória:"
@@ -6932,6 +6968,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Vyhľadať"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6984,16 +7028,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7092,8 +7126,8 @@ msgstr "Všetky vybrané"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7511,6 +7545,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9963,6 +10002,11 @@ msgid "Projects"
msgstr "Zakladatelia Projektu"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Načítavanie zrkadiel, prosím čakajte..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10332,6 +10376,11 @@ msgstr ""
msgid "Plugins"
msgstr "Pluginy"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Načítať predvolené"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10577,6 +10626,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Vložiť"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Popis:"
@@ -10701,6 +10759,11 @@ msgid "Attach Script"
msgstr "Popis:"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Vložiť"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10812,6 +10875,13 @@ msgid "Remote"
msgstr "Všetky vybrané"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12343,6 +12413,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Prázdny CollisionPolygon2D nemá žiaden efekt na kolíziu."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12614,11 +12692,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -12883,14 +12956,12 @@ msgid "Invalid source for preview."
msgstr "Neplatný zdroj pre predzobrazenie."
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid source for shader."
-msgstr "Nesprávna veľkosť písma."
+msgstr "Neplatný zdroj pre shader."
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid comparison function for that type."
-msgstr "Nesprávna veľkosť písma."
+msgstr "Neplatná funkcia porovnania pre tento typ."
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -13045,10 +13116,6 @@ msgstr ""
#~ msgstr "Vytvoriť adresár"
#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Vložiť"
-
-#, fuzzy
#~ msgid "Create Area"
#~ msgstr "Vytvoriť adresár"
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index ee152a25a3..500b8b1e54 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -681,7 +681,7 @@ msgstr "Izberi Lastnost"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1936,8 +1936,8 @@ msgid "Open a File or Directory"
msgstr "Odpri Datoteko ali Mapo"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Shrani"
@@ -2634,7 +2634,8 @@ msgstr ""
"konfiguracije ni uspelo."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Ni mogoče najti polja skripte za dodatni vtičnik na: 'res://addons/%s'."
@@ -3086,14 +3087,6 @@ msgid "Help"
msgstr "Pomoč"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Iskanje"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Spletna Dokumentacija"
@@ -3256,6 +3249,22 @@ msgid "Open & Run a Script"
msgstr "Odpri & Zaženi Skripto"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Novo Podedovano"
@@ -3464,7 +3473,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3785,6 +3794,11 @@ msgstr ""
"Stanje: Uvoz datoteke ni uspel. Popravi datoteko in ponovno ročno uvozi."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ni mogoče premakniti/preimenovati osnovne vire."
@@ -4200,6 +4214,25 @@ msgstr ""
msgid "Saving..."
msgstr "Shranjevanje..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Izberi Način"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Uvozi"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Naložite Prevzeto"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5225,7 +5258,8 @@ msgid "Got:"
msgstr "Dobil:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Neuspešno preverjanje preizkusa sha256"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5339,7 +5373,6 @@ msgid "Sort:"
msgstr "Razvrsti:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategorija:"
@@ -7228,6 +7261,14 @@ msgstr ""
msgid "Run"
msgstr "Zaženi"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Iskanje"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7281,16 +7322,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Razhroščevalnik"
@@ -7391,8 +7422,8 @@ msgstr "Izbriši točke"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7814,6 +7845,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10306,6 +10342,11 @@ msgid "Projects"
msgstr "Projekt"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Pridobivanje virov, počakajte..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10674,6 +10715,11 @@ msgstr ""
msgid "Plugins"
msgstr "Vtičniki"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Naložite Prevzeto"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Prednastavitev..."
@@ -10929,6 +10975,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Prilepi Pozicijo"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Odstrani Gradnik VizualnaSkripta"
@@ -11059,6 +11114,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Gradnik Prehod"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -11173,6 +11233,13 @@ msgid "Remote"
msgstr "Upravljalnik"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12740,6 +12807,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Prazen CollisionPolygon2D nima vpliva na collision."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -13006,11 +13081,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13569,10 +13639,6 @@ msgstr "Konstante ni možno spreminjati."
#~ msgid "Create folder"
#~ msgstr "Ustvarite mapo"
-#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Gradnik Prehod"
-
#~ msgid "Invalid Path"
#~ msgstr "Neveljavna Pot"
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 90905673c2..7b2fee263a 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -632,7 +632,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1887,8 +1887,8 @@ msgid "Open a File or Directory"
msgstr "Hap një Skedar ose Direktori"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Ruaj"
@@ -2577,7 +2577,8 @@ msgstr ""
"dështoi."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "I paaftë te gjej fushën e shkrimit për shtojcën në: 'res://addons/%s'."
#: editor/editor_node.cpp
@@ -3023,14 +3024,6 @@ msgid "Help"
msgstr "Ndihmë"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Kërko"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Dokumentimi Online"
@@ -3191,6 +3184,22 @@ msgid "Open & Run a Script"
msgstr "Hap & Fillo një Shkrim"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "E Trashëguar e Re"
@@ -3404,7 +3413,7 @@ msgstr "Bëje Unik"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Ngjit"
@@ -3724,6 +3733,11 @@ msgstr ""
"importoje manualisht."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nuk mund të leviz/riemërtoj rrenjën e resurseve."
@@ -4123,6 +4137,25 @@ msgstr ""
msgid "Saving..."
msgstr "Duke Ruajtur..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Zgjidh Nyjet Për ti Importuar"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Importo"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Ngarko të Parazgjedhur"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5088,7 +5121,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5196,7 +5229,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6996,6 +7028,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Kërko"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7047,16 +7087,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7153,8 +7183,8 @@ msgstr "Krijo pika."
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7567,6 +7597,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9963,6 +9998,11 @@ msgid "Projects"
msgstr "Projekti"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Duke marrë pasqyrat, ju lutem prisni..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10325,6 +10365,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Ngarko të Parazgjedhur"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10572,6 +10617,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Dyfisho Nyjet"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Shkrim i Ri"
@@ -10697,6 +10751,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Dyfisho Nyjet"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10808,6 +10867,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12324,6 +12390,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12581,11 +12655,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index eea195210a..cb28a6b876 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -720,7 +720,7 @@ msgstr "Постави прелаз на:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Копирај"
@@ -2030,8 +2030,8 @@ msgid "Open a File or Directory"
msgstr "Отвори датотеку или директоријум"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Сачувај"
@@ -2752,7 +2752,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "Неуспех при прикључивању додатка због конфигурационе датотеке: '%s'."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "Неуспех при налажењу поља за скриптицу у додатку „res://addons/%s“."
#: editor/editor_node.cpp
@@ -3213,14 +3214,6 @@ msgid "Help"
msgstr "Помоћ"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Тражи"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Онлајн документација"
@@ -3400,6 +3393,25 @@ msgid "Open & Run a Script"
msgstr "Отвори и покрени скриптицу"
#: editor/editor_node.cpp
+#, fuzzy
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Следеће датотеке су нове на диску.\n"
+"Која акција се треба предузети?:"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Освежи"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Поново сачувај"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Нова наслеђена"
@@ -3631,7 +3643,7 @@ msgstr "Учини Јединственим"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Налепи"
@@ -3972,6 +3984,11 @@ msgstr ""
"сами."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Не могу померити/преименовати корен ресурса."
@@ -4403,6 +4420,25 @@ msgstr ""
msgid "Saving..."
msgstr "Чување..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Одабери режим"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "Увоз"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Учитај уобичајено"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5480,7 +5516,8 @@ msgid "Got:"
msgstr "Добијено:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+#, fuzzy
+msgid "Failed SHA-256 hash check"
msgstr "Неуспела провера sha256 суме"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5599,7 +5636,6 @@ msgid "Sort:"
msgstr "Сортирање:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Категорија:"
@@ -7619,6 +7655,14 @@ msgstr "Затвори документацију"
msgid "Run"
msgstr "Покрени"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Тражи"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Корак у"
@@ -7674,16 +7718,6 @@ msgstr ""
"Следеће датотеке су нове на диску.\n"
"Која акција се треба предузети?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Освежи"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Поново сачувај"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Дебагер"
@@ -7791,8 +7825,8 @@ msgstr "Тачке прекида"
msgid "Go To"
msgstr "Иди На"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Исеци"
@@ -8235,6 +8269,11 @@ msgid "View Rotation Locked"
msgstr "Прикажи информације"
#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
@@ -11147,6 +11186,11 @@ msgstr "Пројекти"
#: editor/project_manager.cpp
#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Прихватам одредишта, молим сачекајте..."
+
+#: editor/project_manager.cpp
+#, fuzzy
msgid "Last Modified"
msgstr "Задњи Измењен"
@@ -11601,6 +11645,11 @@ msgstr "Ауто-Учитавање"
msgid "Plugins"
msgstr "Прикључци"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Учитај уобичајено"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Поставке..."
@@ -11907,6 +11956,16 @@ msgstr "Инстанца Сцена Дете"
#: editor/scene_tree_dock.cpp
#, fuzzy
+msgid "Can't paste root node into the same scene."
+msgstr "Немогуће оперисати на чвору из стране сцене!"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Налепи Чворове"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Detach Script"
msgstr "Припој Скрипту"
@@ -12062,6 +12121,11 @@ msgstr "Припој Скрипту"
#: editor/scene_tree_dock.cpp
#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Направи чвор"
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Remove Node(s)"
msgstr "Уклони Чвор/ове"
@@ -12194,6 +12258,13 @@ msgid "Remote"
msgstr "Удаљени уређај"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Local"
msgstr "Локално"
@@ -13982,6 +14053,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Непријатењ СударниМногоугао2Д нема утицаја на судар."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
#, fuzzy
msgid ""
@@ -14336,11 +14415,6 @@ msgstr ""
" \n"
"Као замену користи ИспеченеСенкеМапу."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
#, fuzzy
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -15092,10 +15166,6 @@ msgstr "Константе није могуће мењати."
#~ msgstr "CheckBox Radio2"
#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "Направи чвор"
-
-#, fuzzy
#~ msgid "Snap (s): "
#~ msgstr "Један корак (сек.):"
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 9a88a06a25..86ce05a7f2 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -654,7 +654,7 @@ msgstr "Postavi tranzicije na:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1827,8 +1827,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2468,7 +2468,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2860,14 +2860,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3022,6 +3014,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3225,7 +3233,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3529,6 +3537,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3908,6 +3921,23 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Uduplaj Selekciju"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4873,7 +4903,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4977,7 +5007,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6771,6 +6800,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6822,16 +6859,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6926,8 +6953,8 @@ msgstr "Napravi"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7338,6 +7365,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9737,6 +9769,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10100,6 +10136,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10344,6 +10384,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Animacija Uduplaj Ključeve"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10468,6 +10517,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Animacija Uduplaj Ključeve"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10577,6 +10631,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12064,6 +12125,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12319,11 +12388,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 9f812d7b8f..2b3c17e07e 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -15,18 +15,19 @@
# Anonymous <noreply@weblate.org>, 2020.
# Joakim Lundberg <joakim@joakimlundberg.com>, 2020.
# Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020.
-# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020.
+# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020, 2021.
# André Andersson <andre.eric.andersson@gmail.com>, 2020.
# Andreas Westrell <andreas.westrell@gmail.com>, 2020.
# Gustav Andersson <gustav.andersson96@outlook.com>, 2020.
# Shaggy <anton_christoffersson@hotmail.com>, 2020.
# Marcus Toftedahl <marcus.toftedahl@his.se>, 2020.
+# Alex25820 <Alexander_sjogren@hotmail.se>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-04 02:39+0000\n"
-"Last-Translator: Marcus Toftedahl <marcus.toftedahl@his.se>\n"
+"PO-Revision-Date: 2021-03-24 23:44+0000\n"
+"Last-Translator: Jonas Robertsson <jonas.robertsson@posteo.net>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -34,7 +35,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.3.2-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -43,13 +44,13 @@ msgstr "Ogiltligt typargument till convert(), använd TYPE_* konstanter."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Förväntas en string av längden 1 (en karaktär)."
+msgstr "Förväntade en sträng av längden 1 (ett tecken)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Inte tillräckligt med bytes för avkodning byte, eller ogiltigt format."
+msgstr "Inte nog med bytes för att avkoda, eller ogiltigt format."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -579,7 +580,7 @@ msgstr "Fördubbla val"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Fördubbla Transponerade"
+msgstr "Duplicera Transponerade"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -599,7 +600,7 @@ msgstr "Optimera Animation"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation"
-msgstr "Rensa Animation"
+msgstr "Städa-upp Animation"
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
@@ -662,7 +663,7 @@ msgstr "Välj Spår att Kopiera"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopiera"
@@ -844,6 +845,7 @@ msgstr ""
"vilotid."
#: editor/connections_dialog.cpp
+#, fuzzy
msgid "Oneshot"
msgstr "Oneshot"
@@ -1044,14 +1046,14 @@ msgid "Owners Of:"
msgstr "Ägare av:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Ta bort valda filer från projektet? (Kan ej återställas)"
+msgstr ""
+"Ta bort valda filer från projektet? (Kan ej återställas)\n"
+"Du kan hitta de borttagna filerna i systemets papperskorg."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1059,7 +1061,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Filerna som tas bort krävs av andra resurser för att de ska fungera.\n"
-"Ta bort dem ändå? (går inte ångra)"
+"Ta bort dem ändå? (går inte ångra)\n"
+"Du kan hitta de borttagna filerna i systemets papperskorg."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1070,9 +1073,8 @@ msgid "Error loading:"
msgstr "Fel vid laddning:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid "Load failed due to missing dependencies:"
-msgstr "Scenen misslyckades att ladda på grund av att beroenden saknas:"
+msgstr "Inladdning misslyckades på grund av att beroenden saknas:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
@@ -1239,7 +1241,7 @@ msgstr "Dekomprimerar Tillgångar"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr "Följande filer gick inte att packa upp från tillägget:"
+msgstr "Följande filer misslyckades att packas upp från paketet:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
@@ -1256,7 +1258,7 @@ msgstr "Klart!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
-msgstr "Packet Innehåll:"
+msgstr "Paketets Innehåll:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1280,7 +1282,7 @@ msgstr "Byt namn på Ljud-Buss"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr "Växla Ljud-Buss Volum"
+msgstr "Växla Ljud-Buss Volym"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
@@ -1405,7 +1407,7 @@ msgstr "Lägg till Buss"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr "Lägg till en ny Audio-Buss för detta layout"
+msgstr "Lägg till en ny Audio-Buss för denna layout."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1446,21 +1448,16 @@ msgid "Valid characters:"
msgstr "Giltiga tecken:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing engine class name."
-msgstr ""
-"Ogiltigt namn. Får inte vara samma som ett befintligt engine class-namn."
+msgstr "Får inte vara samma som ett befintligt engine class-namn."
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing built-in type name."
-msgstr "Ogiltigt namn. Får inte vara samma som ett befintligt inbyggt typnamn."
+msgstr "Får inte vara samma som ett befintligt inbyggt typ-namn."
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing global constant name."
-msgstr ""
-"Ogiltigt namn. Får inte vara samma som ett befintligt global constant-namn."
+msgstr "Får inte vara samma som ett befintligt globalt konstant-namn."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
@@ -1532,7 +1529,6 @@ msgid "Updating Scene"
msgstr "Uppdaterar Scen"
#: editor/editor_data.cpp
-#, fuzzy
msgid "Storing local changes..."
msgstr "Lagrar lokala ändringar..."
@@ -1541,18 +1537,16 @@ msgid "Updating scene..."
msgstr "Uppdaterar scen..."
#: editor/editor_data.cpp editor/editor_properties.cpp
-#, fuzzy
msgid "[empty]"
-msgstr "(tom)"
+msgstr "[tom]"
#: editor/editor_data.cpp
msgid "[unsaved]"
msgstr "[inte sparad]"
#: editor/editor_dir_dialog.cpp
-#, fuzzy
msgid "Please select a base directory first."
-msgstr "Vänligen välj en baskatalog först"
+msgstr "Vänligen välj en baskatalog först."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
@@ -1639,21 +1633,20 @@ msgstr ""
"Etc 2' i Projektinställningarna."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"Målplattformen kräver 'ETC' texturkomprimering för GLES2. Aktivera 'Import "
-"Etc' i Projektinställningarna."
+"Målplattformen kräver 'ETC' texturkomprimering för GLES2.\n"
+"Aktivera 'Import Etc' i Projektinställningarna."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom debug template not found."
-msgstr "Mallfil hittades inte:"
+msgstr "Mallfil hittades inte."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1684,14 +1677,12 @@ msgid "Asset Library"
msgstr "Tillgångsbibliotek"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Scene Tree Editing"
-msgstr "Scenträd (Noder):"
+msgstr "Scenträd Redigering"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Node Dock"
-msgstr "Node Namn:"
+msgstr "Nod Docka"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1741,22 +1732,20 @@ msgid "Enable Contextual Editor"
msgstr "Aktivera kontextuell redigerare"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Enabled Properties:"
-msgstr "Egenskaper"
+msgstr "Egenskaper:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
msgstr "Aktivera funktioner:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Enabled Classes:"
-msgstr "Sök Klasser"
+msgstr "Aktiverade Klasser:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr "Fil '%s''s format är ogiltig, import avbruten"
+msgstr "Fil '%s''s format är ogiltig, import avbruten."
#: editor/editor_feature_profile.cpp
msgid ""
@@ -1767,9 +1756,8 @@ msgstr ""
"avbruten."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Error saving profile to path: '%s'."
-msgstr "Fel vid laddning av mall '%s'"
+msgstr "Fel vid laddning av mall '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
@@ -1781,9 +1769,8 @@ msgid "Current Profile:"
msgstr "Nuvarande Version:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Make Current"
-msgstr "Nuvarande:"
+msgstr "Gör till Nuvarande"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
@@ -1836,7 +1823,7 @@ msgstr "Exportera Projekt"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Hantera Redigerarens Funktions Profiler"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1852,7 +1839,7 @@ msgstr "Välj Denna Mapp"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopiera Sökvägen"
+msgstr "Kopiera Sökväg"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
#, fuzzy
@@ -1899,8 +1886,8 @@ msgid "Open a File or Directory"
msgstr "Öppna en Fil eller Katalog"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Spara"
@@ -1946,33 +1933,28 @@ msgid "Move Favorite Down"
msgstr "Flytta Favorit Ner"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Gå till överordnad mapp"
+msgstr "Gå till föregående mapp."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Gå till överordnad mapp"
+msgstr "Gå till nästa mapp."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
msgstr "Gå till överordnad mapp."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Refresh files."
-msgstr "Sök Klasser"
+msgstr "Uppdatera filer."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "(Un)favorite current folder."
-msgstr "Kunde inte skapa mapp."
+msgstr "Ta bort nuvarande mapp från favoriter."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Toggle the visibility of hidden files."
-msgstr "Växla Dolda Filer"
+msgstr "Växla synligheten av dolda filer."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
@@ -1998,13 +1980,15 @@ msgstr "Fil:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr "ScanSources"
+msgstr "ScanKällor"
#: editor/editor_file_system.cpp
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Det finns flera importörer för olika typer som pekar på filen %s, import "
+"avbruten"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
@@ -2028,9 +2012,8 @@ msgid "Inherited by:"
msgstr "Ärvd av:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Beskrivning:"
+msgstr "Beskrivning"
#: editor/editor_help.cpp
#, fuzzy
@@ -2043,12 +2026,11 @@ msgstr "Egenskaper"
#: editor/editor_help.cpp
msgid "override:"
-msgstr ""
+msgstr "skriv över:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Standard"
+msgstr "standard:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2068,9 +2050,8 @@ msgid "Constants"
msgstr "Konstanter"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Property Descriptions"
-msgstr "Egenskapsbeskrivning:"
+msgstr "Egenskapsbeskrivningar"
#: editor/editor_help.cpp
#, fuzzy
@@ -2086,9 +2067,8 @@ msgstr ""
"oss genom att [color=$color][url=$url]bidra med en[/url][/color]!"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Method Descriptions"
-msgstr "Metodbeskrivning:"
+msgstr "Metodbeskrivningar"
#: editor/editor_help.cpp
msgid ""
@@ -2183,15 +2163,15 @@ msgstr "Egenskaper"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Egenskap:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Sätt"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Sätt Flera:"
#: editor/editor_log.cpp
msgid "Output:"
@@ -2213,9 +2193,8 @@ msgid "Clear"
msgstr "Rensa"
#: editor/editor_log.cpp
-#, fuzzy
msgid "Clear Output"
-msgstr "Output:"
+msgstr "Rensa Utdata"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2225,11 +2204,11 @@ msgstr "Stanna"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Starta"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
#, fuzzy
@@ -2238,7 +2217,7 @@ msgstr "Ladda ner"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Upp"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2246,27 +2225,27 @@ msgstr "Nod"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "Inkommande RPC"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "Inkommande RSET"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "Utgående RPC"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "Utgående RSET"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Nytt Fönster"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Importerade resurser kan inte sparas."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
@@ -2282,6 +2261,8 @@ msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Resursen kan inte sparas för att den inte hör inte till den redigerade "
+"scenen. Gör den unik först."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2301,7 +2282,7 @@ msgstr "Fel vid sparande."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
-msgstr ""
+msgstr "Kan inte öppna '%s'. Filen kan ha flyttats eller tagits bort."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
@@ -2340,6 +2321,8 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Scenen kan inte sparas för att det finns en cyklisk instansnings inkusion.\n"
+"Försök lösa det och pröva sedan att spara igen."
#: editor/editor_node.cpp
#, fuzzy
@@ -2352,7 +2335,7 @@ msgstr ""
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "Kan inte skriva över en scen som fortfarande är öppen!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
@@ -2375,6 +2358,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Ett fel uppstod medans editor layouten sparades.\n"
+"Se till att editorns användardata sökväg är skriv tillgänglig."
#: editor/editor_node.cpp
msgid ""
@@ -2382,6 +2367,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Standard editor layouten överskriven.\n"
+"För att återställa Standard layouten till sina bas inställningar, använd "
+"Radera Layout valet och radera Standard Layouten."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2389,7 +2377,7 @@ msgstr "Layoutnamn hittades inte!"
#: editor/editor_node.cpp
msgid "Restored the Default layout to its base settings."
-msgstr ""
+msgstr "Återställde Standard layouten till sina bas inställningar."
#: editor/editor_node.cpp
msgid ""
@@ -2448,7 +2436,7 @@ msgstr "Det finns ingen definierad scen att köra."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Spara scenen innan du kör..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2492,7 +2480,7 @@ msgstr "Misslyckades att ladda resurs."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "En root nod krävs för att spara scenen."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2536,6 +2524,8 @@ msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Den aktiva scenen har osparade ändringar.\n"
+"Vill du ladda om den ändå? Detta kan inte ångras."
#: editor/editor_node.cpp
#, fuzzy
@@ -2598,7 +2588,8 @@ msgstr ""
"Kunde inte aktivera addon plugin vid: '%s' parsning av config misslyckades."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr "Kan inte hitta skriptfältet för addon plugin vid: 'res://addons/%s'."
#: editor/editor_node.cpp
@@ -2720,7 +2711,7 @@ msgstr "Stänga Övriga Flikar"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr ""
+msgstr "Stäng flikar till höger"
#: editor/editor_node.cpp
#, fuzzy
@@ -2745,7 +2736,7 @@ msgstr "%d fler filer"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr ""
+msgstr "Dockposition"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
@@ -2835,7 +2826,7 @@ msgstr "Ångra"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr "Ångra"
+msgstr "Återställ"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
@@ -2847,45 +2838,40 @@ msgid "Project"
msgstr "Projekt"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Project Settings..."
-msgstr "Projektinställningar"
+msgstr "Projektinställningar..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Version Control"
-msgstr "Version:"
+msgstr "Versionshantering"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Ställ In Versionshantering"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "Stäng Ner Versionshantering"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Export..."
-msgstr "Exportera"
+msgstr "Exportera..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Project Data Folder"
-msgstr "Öppna Projekthanteraren?"
+msgstr "Öppna Projekthanteraren"
#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
msgid "Tools"
msgstr "Verktyg"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Orphan Resource Explorer..."
-msgstr "Föräldralös Resursutforskare"
+msgstr "Föräldralös Resursutforskare..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -2894,7 +2880,7 @@ msgstr "Avsluta till Projektlistan"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
msgid "Debug"
-msgstr "Debugga"
+msgstr "Felsök"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
@@ -2926,7 +2912,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr ""
+msgstr "Synliga Kollisionsformer"
#: editor/editor_node.cpp
msgid ""
@@ -2975,9 +2961,8 @@ msgid "Editor"
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Editor Settings..."
-msgstr "Övergångar"
+msgstr "Redigerarinställningar..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -2993,7 +2978,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Fullskärm"
+msgstr "Växla Fullskärm"
#: editor/editor_node.cpp
#, fuzzy
@@ -3017,23 +3002,14 @@ msgid "Manage Editor Features..."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Export Templates..."
-msgstr "Mallar"
+msgstr "Hantera exportmallar..."
#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
msgid "Help"
msgstr "Hjälp"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Sök"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Dokumentation Online"
@@ -3193,6 +3169,24 @@ msgid "Open & Run a Script"
msgstr "Öppna & Kör ett Skript"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Följande filer är nyare på disken.\n"
+"Vilka åtgärder ska vidtas?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Ladda om"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Spara om"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3233,9 +3227,8 @@ msgid "Warning!"
msgstr "Varning!"
#: editor/editor_path.cpp
-#, fuzzy
msgid "No sub-resources found."
-msgstr "Resurser"
+msgstr "Inga underresurser hittades."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3247,9 +3240,8 @@ msgid "Thumbnail..."
msgstr "Miniatyr..."
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Main Script:"
-msgstr "Öppna Skript"
+msgstr "Huvud Skript:"
#: editor/editor_plugin_settings.cpp
#, fuzzy
@@ -3278,9 +3270,8 @@ msgid "Status:"
msgstr "Status:"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Edit:"
-msgstr "Redigera"
+msgstr "Redigera:"
#: editor/editor_profiler.cpp
msgid "Measure:"
@@ -3315,18 +3306,16 @@ msgid "Frame #:"
msgstr ""
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Time"
-msgstr "Tid:"
+msgstr "Tid"
#: editor/editor_profiler.cpp
msgid "Calls"
msgstr ""
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Edit Text:"
-msgstr "Redigera tema..."
+msgstr "Redigera Text:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
@@ -3345,9 +3334,8 @@ msgid "[Empty]"
msgstr ""
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
-#, fuzzy
msgid "Assign..."
-msgstr "Tilldela"
+msgstr "Tilldela..."
#: editor/editor_properties.cpp
#, fuzzy
@@ -3405,7 +3393,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Klistra in"
@@ -3546,9 +3534,8 @@ msgid "No version.txt found inside templates."
msgstr ""
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for templates:"
-msgstr "Fel vid laddning av mall '%s'"
+msgstr "Fel vid skapande av sökväg för mallar:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3712,15 +3699,19 @@ msgid "Select mirror from list: (Shift+Click: Open in Browser)"
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Favorites"
-msgstr "Favoriter:"
+msgstr "Favoriter"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3778,9 +3769,8 @@ msgid "Renaming folder:"
msgstr "Byter namn på mappen:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Duplicating file:"
-msgstr "Duplicera"
+msgstr "Duplicerar fil:"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3788,9 +3778,8 @@ msgid "Duplicating folder:"
msgstr "Byter namn på mappen:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Inherited Scene"
-msgstr "Ny Ärvd Scen..."
+msgstr "Ny Ärvd Scen"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3807,9 +3796,8 @@ msgid "Instance"
msgstr "Instans"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Add to Favorites"
-msgstr "Favoriter:"
+msgstr "Lägg till i Favoriter"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3831,14 +3819,12 @@ msgid "Move To..."
msgstr "Flytta Till..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
-msgstr "Ny Scen"
+msgstr "Ny Scen..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "New Script..."
-msgstr "Nytt Skript"
+msgstr "Nytt Skript..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3858,9 +3844,8 @@ msgid "Collapse All"
msgstr "Stäng Alla"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Duplicate..."
-msgstr "Duplicera"
+msgstr "Duplicera..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3932,19 +3917,16 @@ msgid "Find in Files"
msgstr "%d fler filer"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Find:"
-msgstr "Hitta"
+msgstr "Hitta:"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Folder:"
-msgstr "Skapa Mapp"
+msgstr "Mapp:"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Filters:"
-msgstr "Filtrera noder"
+msgstr "Filter:"
#: editor/find_in_files.cpp
msgid ""
@@ -3969,11 +3951,11 @@ msgstr "Avbryt"
#: editor/find_in_files.cpp
msgid "Find: "
-msgstr "Hitta:"
+msgstr "Hitta: "
#: editor/find_in_files.cpp
msgid "Replace: "
-msgstr "Ersätt:"
+msgstr "Ersätt: "
#: editor/find_in_files.cpp
#, fuzzy
@@ -4142,6 +4124,24 @@ msgstr ""
msgid "Saving..."
msgstr "Sparar..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "Välj Node"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Importör:"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Ladda Standard"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -4233,9 +4233,8 @@ msgid "Load an existing resource from disk and edit it."
msgstr ""
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Save the currently edited resource."
-msgstr "Spara den nuvarande animationen"
+msgstr "Spara den nuvarande redigerade resursen."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4290,14 +4289,12 @@ msgid "Subfolder:"
msgstr ""
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
-#, fuzzy
msgid "Language:"
-msgstr "Språk"
+msgstr "Språk:"
#: editor/plugin_config_dialog.cpp
-#, fuzzy
msgid "Script Name:"
-msgstr "Skript giltigt"
+msgstr "Skript Namn:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
@@ -4312,9 +4309,8 @@ msgstr "Skapa Prenumeration"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Create points."
-msgstr "Radera punkter"
+msgstr "Skapa punkter."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid ""
@@ -4325,9 +4321,8 @@ msgstr ""
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Erase points."
-msgstr "Radera punkter"
+msgstr "Radera punkter."
#: editor/plugins/abstract_polygon_2d_editor.cpp
#, fuzzy
@@ -4360,9 +4355,8 @@ msgstr "Lägg till Animation"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Load..."
-msgstr "Ladda"
+msgstr "Ladda..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4525,9 +4519,8 @@ msgid "Add Node to BlendTree"
msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Node Moved"
-msgstr "Node Namn:"
+msgstr "Nod Flyttad"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Unable to connect, port may be in use or connection may be invalid."
@@ -4562,9 +4555,8 @@ msgid "Delete Node(s)"
msgstr "Ta bort Nod(er)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Filter On/Off"
-msgstr "Växla distraktionsfritt läge."
+msgstr "Växla Filter På/Av"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#, fuzzy
@@ -4592,9 +4584,8 @@ msgid "Anim Clips"
msgstr "Animklipp:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Audio Clips"
-msgstr "Ljudklipp:"
+msgstr "Ljudklipp"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Functions"
@@ -4602,21 +4593,18 @@ msgstr "Funktioner"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Node Renamed"
-msgstr "Node Namn:"
+msgstr "Nod har bytt Namn"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Node..."
-msgstr "Lägg Till Node"
+msgstr "Lägg Till Node..."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
-#, fuzzy
msgid "Edit Filtered Tracks:"
-msgstr "Redigera Filter"
+msgstr "Redigera Filtrerade Spår:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#, fuzzy
@@ -4737,9 +4725,8 @@ msgid "Animation"
msgstr "Animation"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Transitions..."
-msgstr "Övergångar"
+msgstr "Ändra Övergångar..."
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4907,14 +4894,12 @@ msgid ""
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Create new nodes."
-msgstr "Skapa Ny"
+msgstr "Skapa nya noder."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Connect nodes."
-msgstr "Anslut Noder"
+msgstr "Anslut noder."
#: editor/plugins/animation_state_machine_editor.cpp
#, fuzzy
@@ -4931,12 +4916,11 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition: "
-msgstr "Övergång:"
+msgstr "Övergång: "
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Play Mode:"
-msgstr "Raw-Läge"
+msgstr "Spel Läge:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5152,7 +5136,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5256,7 +5240,6 @@ msgid "Sort:"
msgstr "Sortera:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategori:"
@@ -5525,9 +5508,8 @@ msgid "Full Rect"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Keep Ratio"
-msgstr "Skalnings förhållande:"
+msgstr "Behåll Förhållande"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
@@ -5841,9 +5823,8 @@ msgid "Scale mask for inserting keys."
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Insert keys (based on mask)."
-msgstr "Anim Infoga Nyckel"
+msgstr "Infoga nycklar (baserat på mask)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -6290,16 +6271,16 @@ msgid "Remove item %d?"
msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid ""
"Update from existing scene?:\n"
"%s"
-msgstr "Uppdatera från scen"
+msgstr ""
+"Uppdatera från existerande scen?:\n"
+"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Mesh Library"
-msgstr "MeshLibrary..."
+msgstr "MeshLibrary"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
@@ -6906,21 +6887,16 @@ msgid "Clear Recent Files"
msgstr ""
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Close and save changes?"
-msgstr ""
-"Stäng och spara ändringar?\n"
-"\""
+msgstr "Stäng och spara ändringar?"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error writing TextFile:"
-msgstr "Fel vid sparande av TileSet!"
+msgstr "Fel vid sparande av TextFil:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Could not load file at:"
-msgstr "Fel - Kunde inte skapa Skript i filsystemet."
+msgstr "Kunde inte ladda filen vid:"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -6943,9 +6919,8 @@ msgid "Error importing theme."
msgstr "Fel vid sparande av scenen."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Importing"
-msgstr "Fel vid laddning:"
+msgstr "Fel vid Importering"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7053,9 +7028,8 @@ msgid "File"
msgstr "Fil"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open..."
-msgstr "Öppen"
+msgstr "Öppna..."
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7090,9 +7064,8 @@ msgid "Theme"
msgstr "Tema"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Import Theme..."
-msgstr "Importera Tema"
+msgstr "Importera Tema..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
@@ -7114,6 +7087,14 @@ msgstr ""
msgid "Run"
msgstr "Kör"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Sök"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7140,9 +7121,8 @@ msgid "Debug with External Editor"
msgstr ""
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open Godot online documentation."
-msgstr "Öppna Senaste"
+msgstr "Öppna Godot online dokumentation."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
@@ -7166,16 +7146,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Ladda om"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Spara om"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7196,33 +7166,30 @@ msgid "Connections to method:"
msgstr "Anslut Till Node:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source"
-msgstr "Källa:"
+msgstr "Källa"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
-msgstr "Anslut '%s' till '%s'"
+msgstr ""
+"Saknar ansluten metod '%s' för signalen '%s' från noden '%s' till noden '%s'."
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Line"
-msgstr "Rad:"
+msgstr "Rad"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Funktion:"
+msgstr "Gå till Funktion"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7276,8 +7243,8 @@ msgstr "Radera punkter"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Klipp"
@@ -7375,14 +7342,12 @@ msgid "Remove All Bookmarks"
msgstr "Ta bort Alla"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function..."
-msgstr "Ta bort Funktion"
+msgstr "Gå till Funktion..."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Line..."
-msgstr "Gå till Rad"
+msgstr "Gå till Rad..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -7705,6 +7670,11 @@ msgstr "Visa Information"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7840,9 +7810,8 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Settings..."
-msgstr "Inställningar"
+msgstr "Inställningar..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
@@ -8012,9 +7981,8 @@ msgid "Update Preview"
msgstr "Förhandsgranska"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Settings:"
-msgstr "Inställningar"
+msgstr "Inställningar:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
#, fuzzy
@@ -8030,9 +7998,8 @@ msgid "Add Frame"
msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Unable to load images"
-msgstr "Misslyckades att ladda resurs."
+msgstr "Det gick inte att läsa in bilder"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
@@ -8064,9 +8031,8 @@ msgid "Move Frame"
msgstr "Flytta Nod(er)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animations:"
-msgstr "Animationer"
+msgstr "Animationer:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
#, fuzzy
@@ -8087,9 +8053,8 @@ msgid "Animation Frames:"
msgstr "Nytt Animationsnamn:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Add a Texture from File"
-msgstr "Flytta nuvarande spår upp."
+msgstr "Lägg till en Textur från en Fil"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
@@ -8200,9 +8165,8 @@ msgid "Remove All"
msgstr "Ta bort Alla"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Theme"
-msgstr "Redigera tema..."
+msgstr "Redigera Tema"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme editing menu."
@@ -8349,9 +8313,8 @@ msgid "Erase Selection"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Fix Invalid Tiles"
-msgstr "Ogiltigt namn."
+msgstr "Fixa Ogiltiga Tiles"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8573,19 +8536,16 @@ msgid "Copy bitmask."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste bitmask."
-msgstr "Klistra in Animation"
+msgstr "Klistra in bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Erase bitmask."
-msgstr "Radera punkter"
+msgstr "Radera bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new rectangle."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny rektangel."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8593,9 +8553,8 @@ msgid "New Rectangle"
msgstr "Ny Scen"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new polygon."
-msgstr "Skapa Prenumeration"
+msgstr "Skapa en ny polygon."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8662,25 +8621,28 @@ msgid "Delete selected Rect."
msgstr "Ta bort valda filer?"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select current edited sub-tile.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"Markera nuvarande redigerad sub-tile.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete polygon."
-msgstr "Radera punkter"
+msgstr "Radera polygon."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"LMB: Set bit on.\n"
"RMB: Set bit off.\n"
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"LMB: Aktivera bit.\n"
+"RMB: Avaktivera bit.\n"
+"Shift+LMB: Aktivera vildkorts bit.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8696,11 +8658,12 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select sub-tile to change its z index.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"Välj sub-tile för att ändra dess z-index.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Region"
@@ -8807,9 +8770,8 @@ msgid "This property can't be changed."
msgstr "Åtgärden kan inte göras utan en scen."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "TileSet"
-msgstr "TileSet..."
+msgstr "TileSet"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No VCS addons are available."
@@ -8910,14 +8872,12 @@ msgid "(GLES3 only)"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Output"
-msgstr "Output:"
+msgstr "Lägg till Utdata"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar"
-msgstr "Skala:"
+msgstr "Skalär"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
@@ -8932,9 +8892,8 @@ msgid "Sampler"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add input port"
-msgstr "Favoriter:"
+msgstr "Lägg till inmatningsport"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add output port"
@@ -8950,9 +8909,8 @@ msgid "Change output port type"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change input port name"
-msgstr "Ändra Animationsnamn:"
+msgstr "Ändra inmatningsport namn"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change output port name"
@@ -8969,9 +8927,8 @@ msgid "Remove output port"
msgstr "Ta Bort Mall"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Set expression"
-msgstr "Nuvarande Version:"
+msgstr "Ställ in uttryck"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Resize VisualShader node"
@@ -8990,9 +8947,8 @@ msgid "Add Node to Visual Shader"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Node Namn:"
+msgstr "Nod(er) Flyttade"
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9032,9 +8988,8 @@ msgid "Light"
msgstr "Höger"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Show resulted shader code."
-msgstr "Skapa Node"
+msgstr "Visa den resulterande skuggningskoden."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9042,18 +8997,16 @@ msgid "Create Shader Node"
msgstr "Skapa Node"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color function."
-msgstr "Funktion:"
+msgstr "Färg funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Color operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Grayscale function."
-msgstr "Skapa Funktion"
+msgstr "Gråskala funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts HSV vector to RGB equivalent."
@@ -9064,9 +9017,8 @@ msgid "Converts RGB vector to HSV equivalent."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Sepia function."
-msgstr "Byt namn på funktion"
+msgstr "Sepia funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Burn operator."
@@ -9105,14 +9057,12 @@ msgid "SoftLight operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color constant."
-msgstr "Konstant"
+msgstr "Färg konstant."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color uniform."
-msgstr "Transformera"
+msgstr "Färg enhetlig."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
@@ -9221,9 +9171,8 @@ msgid "'%s' input parameter for vertex and fragment shader mode."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar function."
-msgstr "Skala urval"
+msgstr "Skalär funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar operator."
@@ -9456,9 +9405,8 @@ msgid "Scalar constant."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar uniform."
-msgstr "Transformera"
+msgstr "Skalär uniform."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Perform the cubic texture lookup."
@@ -9481,9 +9429,8 @@ msgid "2D texture uniform lookup with triplanar."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform function."
-msgstr "Transformera"
+msgstr "Transformera funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9525,19 +9472,16 @@ msgid "Multiplies vector by transform."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform constant."
-msgstr "Transformera"
+msgstr "Transformera konstant."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform uniform."
-msgstr "Transformera"
+msgstr "Transformera uniform."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Ta bort Funktion"
+msgstr "Vektor funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9778,9 +9722,8 @@ msgid "Exporting All"
msgstr "Exportera"
#: editor/project_export.cpp
-#, fuzzy
msgid "The given export path doesn't exist:"
-msgstr "Sökvägen finns inte."
+msgstr "Den angivna export vägen finns inte:"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing/corrupted:"
@@ -9859,9 +9802,8 @@ msgid "Script"
msgstr "Nytt Skript"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script Export Mode:"
-msgstr "Exportera Projekt"
+msgstr "Skript Exporterings Läge:"
#: editor/project_export.cpp
msgid "Text"
@@ -9958,9 +9900,8 @@ msgid "Imported Project"
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid Project Name."
-msgstr "Projektnamn:"
+msgstr "Ogiltigt projektnamn."
#: editor/project_manager.cpp
#, fuzzy
@@ -10093,9 +10034,8 @@ msgid "Error: Project is missing on the filesystem."
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Can't open project at '%s'."
-msgstr "Kan inte öppna projekt"
+msgstr "Kan inte öppna projekt vid '%s'."
#: editor/project_manager.cpp
msgid "Are you sure to open more than one project?"
@@ -10196,6 +10136,11 @@ msgid "Projects"
msgstr "Projekt"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "Laddar..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Senast Ändrad"
@@ -10272,9 +10217,8 @@ msgid "Rename Input Action Event"
msgstr ""
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Change Action deadzone"
-msgstr "Ändra Animationsnamn:"
+msgstr "Ändra Åtgärdens Dödzon"
#: editor/project_settings_editor.cpp
msgid "Add Input Action Event"
@@ -10563,6 +10507,11 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Ladda Standard"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10638,9 +10587,8 @@ msgid "Suffix:"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Use Regular Expressions"
-msgstr "Nuvarande Version:"
+msgstr "Använd Vanliga Uttryck"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10652,18 +10600,16 @@ msgid "Substitute"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Node name"
-msgstr "Node Namn:"
+msgstr "Nod namn"
#: editor/rename_dialog.cpp
msgid "Node's parent name, if available"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Node type"
-msgstr "Node Namn:"
+msgstr "Nod typ"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10694,9 +10640,8 @@ msgid "Initial value for the counter"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Step"
-msgstr "Steg (s):"
+msgstr "Steg"
#: editor/rename_dialog.cpp
msgid "Amount by which counter is incremented for each node"
@@ -10753,9 +10698,8 @@ msgid "Regular Expression Error:"
msgstr "Nuvarande Version:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
-msgstr "Giltiga tecken:"
+msgstr "Vid tecken %s"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
@@ -10820,6 +10764,15 @@ msgid "Instance Child Scene"
msgstr "Instansiera Barn-Scen"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Klistra in Noder"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "Fäst Skript"
@@ -10857,14 +10810,12 @@ msgid "Make node as Root"
msgstr "Gör nod som Rot"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort %d noder och alla barn?"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort %d noder?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10875,9 +10826,8 @@ msgid "Delete node \"%s\" and its children?"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete node \"%s\"?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort nod \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -10914,9 +10864,8 @@ msgid "New Scene Root"
msgstr "Ny Scenrot"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Create Root Node:"
-msgstr "Skapa Node"
+msgstr "Skapa Rot Nod:"
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -10950,6 +10899,11 @@ msgid "Attach Script"
msgstr "Fäst Skript"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Klipp ut Noder"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Ta bort Nod(er)"
@@ -11003,7 +10957,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
-msgstr "Lägg till Barn-Node"
+msgstr "Lägg till Barn-Nod"
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -11033,16 +10987,15 @@ msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
-msgstr "Kopiera Node-Sökväg"
+msgstr "Kopiera Nod-Sökväg"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Add/Create a New Node."
-msgstr "Lägga till/Skapa en Ny Node"
+msgstr "Lägg till/Skapa en Ny Node."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11065,6 +11018,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11115,9 +11075,8 @@ msgid ""
msgstr ""
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Open Script:"
-msgstr "Öppna Skript"
+msgstr "Öppna Skript:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11126,13 +11085,12 @@ msgid ""
msgstr ""
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
"Barn är inte valbara.\n"
-"Klicka för att göra valbara"
+"Klicka för att göra valbara."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
@@ -11165,14 +11123,12 @@ msgid "Select a Node"
msgstr "Välj en Node"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is empty."
-msgstr "Sökvägen är tom"
+msgstr "Sökvägen är tom."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Filename is empty."
-msgstr "Sökvägen är tom"
+msgstr "Filnamn är tom."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
@@ -11184,9 +11140,8 @@ msgid "Invalid base path."
msgstr "Ogiltig Sökväg."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "A directory with the same name exists."
-msgstr "Katalog med samma namn finns redan"
+msgstr "Katalog med samma namn finns redan."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
@@ -11250,14 +11205,12 @@ msgid "Invalid inherited parent name or path."
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script path/name is valid."
-msgstr "Skript giltigt"
+msgstr "Skript väg/namn är ogiltigt."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr "Tillåtna: a-z, a-Z, 0-9 och _"
+msgstr "Tillåtna: a-z, A-Z, 0-9, _ och ."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11265,14 +11218,12 @@ msgid "Built-in script (into scene file)."
msgstr "Åtgärder med scenfiler."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will create a new script file."
-msgstr "Skapa ny Skript-fil"
+msgstr "Kommer att skapa ny skript-fil."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will load an existing script file."
-msgstr "Ladda in befintlig Skript-fil"
+msgstr "Kommer att ladda en befintlig Skript-fil."
#: editor/script_create_dialog.cpp
msgid "Script file already exists."
@@ -11285,19 +11236,16 @@ msgid ""
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Klassnamn"
+msgstr "Klassnamn:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Template:"
-msgstr "Mall"
+msgstr "Mall:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Öppna Skript"
+msgstr "Inbyggd Skript:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
@@ -11312,9 +11260,8 @@ msgid "Bytes:"
msgstr ""
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Varning"
+msgstr "Varning:"
#: editor/script_editor_debugger.cpp
msgid "Error:"
@@ -11331,9 +11278,8 @@ msgid "C++ Error:"
msgstr "Fel:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Source"
-msgstr "Källa:"
+msgstr "C++ Källa"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11354,9 +11300,8 @@ msgid "Errors"
msgstr "Fel"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Child process connected."
-msgstr "Barnprocess Ansluten"
+msgstr "Barnprocess ansluten."
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11569,9 +11514,8 @@ msgid "Select dependencies of the library for this entry"
msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp
-#, fuzzy
msgid "Remove current entry"
-msgstr "Flytta nuvarande spår upp."
+msgstr "Ta bort aktuell post"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Double click to create a new entry"
@@ -11803,18 +11747,16 @@ msgid "Generate buffers"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Sektioner:"
+msgstr "Direkt ljus"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Indirect lighting"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Nuvarande Version:"
+msgstr "Efterbehandling"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -11940,14 +11882,12 @@ msgid "Set Variable Type"
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "Favoriter:"
+msgstr "Lägg till Ingångsport"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "Favoriter:"
+msgstr "Lägg till Utgångsport"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -11955,27 +11895,24 @@ msgid "Override an existing built-in function."
msgstr "Ogiltigt namn. Får inte vara samma som ett befintligt inbyggt typnamn."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new function."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny funktion."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
msgstr "Variabler:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new variable."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny variabel."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "Signaler:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "Skapa Prenumeration"
+msgstr "Skapa en ny signal."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
@@ -12180,33 +12117,28 @@ msgid "Editing Signal:"
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Tool:"
-msgstr "Gör Patch"
+msgstr "Skapa Verktyg:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Members:"
msgstr "Medlemmar:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "Ändra Typ"
+msgstr "Ändra Bas Typ:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Nodes..."
-msgstr "Lägg Till Node"
+msgstr "Lägg Till Noder..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "Lägg till Funktion"
+msgstr "Lägg till Funktion..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "Funktioner:"
+msgstr "funktions_namn"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
@@ -12390,9 +12322,8 @@ msgid "Invalid public key for APK expansion."
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid package name:"
-msgstr "Ogiltigt namn."
+msgstr "Ogiltigt paket namn:"
#: platform/android/export/export.cpp
msgid ""
@@ -12483,9 +12414,8 @@ msgid "App Store Team ID not specified - cannot configure the project."
msgstr ""
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Invalid Identifier:"
-msgstr "Ogiltig teckenstorlek."
+msgstr "Ogiltig identifierare:"
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
@@ -12508,9 +12438,8 @@ msgid "Could not write file:"
msgstr "Kunde inte skriva till filen:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not open template for export:"
-msgstr "Kunde inte skapa mapp."
+msgstr "Kunde inte öppna mall för export:"
#: platform/javascript/export/export.cpp
msgid "Invalid export template:"
@@ -12544,14 +12473,12 @@ msgid "Invalid package publisher display name."
msgstr "Ogiltigt namn."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Projektnamn:"
+msgstr "Ogiltig produkt GUID."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Ogiltig Sökväg"
+msgstr "Ogiltigt GUID utgivare."
#: platform/uwp/export/export.cpp
#, fuzzy
@@ -12619,6 +12546,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "En tom CollisionPolygon2D har ingen effekt på kollision."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12794,9 +12729,8 @@ msgid ""
msgstr ""
#: scene/3d/arvr_nodes.cpp
-#, fuzzy
msgid "ARVROrigin requires an ARVRCamera child node."
-msgstr "ARVROrigin kräver en ARVRCamera Barn-Node"
+msgstr "ARVROrigin kräver en ARVRCamera Barn-Node."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
@@ -12821,9 +12755,8 @@ msgid "Saving lightmaps"
msgstr "Genererar Lightmaps"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Klar!"
+msgstr "Klar"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12897,11 +12830,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13039,9 +12967,8 @@ msgid "Invalid animation: '%s'."
msgstr "Ogiltig animation: '%s'."
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Nothing connected to input '%s' of node '%s'."
-msgstr "Anslut '%s' till '%s'"
+msgstr "Inget anslutet till inmatning '%s' av nod '%s'."
#: scene/animation/animation_tree.cpp
msgid "No root AnimationNode for the graph is set."
@@ -13088,9 +13015,8 @@ msgid "Switch between hexadecimal and code values."
msgstr ""
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Add current color as a preset."
-msgstr "Lägg till nuvarande färg som en förinställning"
+msgstr "Lägg till nuvarande färg som en förinställning."
#: scene/gui/container.cpp
msgid ""
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index b933fe6052..9b57af9595 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -650,7 +650,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1823,8 +1823,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2459,7 +2459,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2851,14 +2851,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3012,6 +3004,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3215,7 +3223,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3519,6 +3527,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3899,6 +3912,23 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "அனைத்து தேர்வுகள்"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4858,7 +4888,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4962,7 +4992,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6738,6 +6767,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6789,16 +6826,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6891,8 +6918,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7299,6 +7326,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9658,6 +9690,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10019,6 +10055,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10263,6 +10303,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "அசைவூட்டு போலிபச்சாவிகள்"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10387,6 +10436,11 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "அசைவூட்டு போலிபச்சாவிகள்"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10494,6 +10548,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11972,6 +12033,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12227,11 +12296,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/te.po b/editor/translations/te.po
index e0ec4b5534..a3c48112a6 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -628,7 +628,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1797,8 +1797,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2432,7 +2432,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2822,14 +2822,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2983,6 +2975,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3185,7 +3193,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3489,6 +3497,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3866,6 +3879,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4813,7 +4842,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4917,7 +4946,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6684,6 +6712,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6735,16 +6771,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6837,8 +6863,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7244,6 +7270,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9584,6 +9615,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9944,6 +9979,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10187,6 +10226,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10307,6 +10354,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10414,6 +10465,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11881,6 +11939,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12136,11 +12202,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 8e083aef79..d865b04b16 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -4,15 +4,15 @@
# This file is distributed under the same license as the Godot source code.
# Kaveeta Vivatchai <goodytong@gmail.com>, 2017.
# Poommetee Ketson (Noshyaar) <poommetee@protonmail.com>, 2017-2018.
-# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020.
+# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020, 2021.
# Anonymous <noreply@weblate.org>, 2020.
# Lon3r <mptube.p@gmail.com>, 2020.
-# Kongfa Warorot <gongpha@hotmail.com>, 2020.
+# Kongfa Warorot <gongpha@hotmail.com>, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-12-31 07:09+0000\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n"
"Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/"
"th/>\n"
@@ -21,7 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.4.1-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -643,7 +643,7 @@ msgstr "เลือกแทร็กที่จะคัดลอก"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "คัดลอก"
@@ -1836,8 +1836,8 @@ msgid "Open a File or Directory"
msgstr "เปิดไฟล์หรือโฟลเดอร์"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "บันทึก"
@@ -2347,7 +2347,7 @@ msgstr "ยังไม่ได้เลือกฉากที่จะเล
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "บันทึกฉากก่อนที่จะทำงาน..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2489,8 +2489,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "ไม่สามารถเปิดใช้งานปลั๊กอิน: '%s'"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "ไม่พบชื่อสคริปต์ในปลั๊กอิน: 'res://addons/%s'"
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "ไม่พบไฟล์สคริปต์สำหรับปลั๊กอินที่: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2907,14 +2907,6 @@ msgid "Help"
msgstr "ช่วยเหลือ"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "ค้นหา"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "คู่มือ"
@@ -3076,6 +3068,24 @@ msgid "Open & Run a Script"
msgstr "เปิดและรันสคริปต์"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"ไฟล์เหล่านี้มีความใหม่กว่าบนดิสก์\n"
+"ต้องจะทำอย่างไรต่อไป?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "โหลดใหม่"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "บันทึกอีกครั้ง"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "สืบทอด"
@@ -3282,7 +3292,7 @@ msgstr "ไม่ใช้ร่วมกับวัตถุอื่น"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "วาง"
@@ -3591,6 +3601,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "สถานะ: นำเข้าไฟล์ล้มเหลว กรุณาแก้ไขไฟล์และนำเข้าใหม่"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "การนำเข้าไฟล์นี้ถูกปิด, ดังนั้นจึงไม่สามารถเปิดเพื่อแก้ไขใดๆได้"
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ไม่สามารถย้าย/เปลี่ยนชื่อโฟลเดอร์ราก"
@@ -3975,6 +3990,22 @@ msgstr "คุณส่งคืนออบเจกต์โหนดย่อ
msgid "Saving..."
msgstr "กำลังบันทึก..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "เลือกตัวนำเข้า"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "ตัวนำเข้า:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "รีเซ็ตเป็นค่าเริ่มต้น"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "เก็บไฟล์ (ไม่นำเข้า)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "ไฟล์ %d"
@@ -4930,8 +4961,8 @@ msgid "Got:"
msgstr "ที่ได้รับ:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "ผิดพลาดในการตรวจสอบแฮช SHA256"
+msgid "Failed SHA-256 hash check"
+msgstr "ผิดพลาดในการตรวจสอบแฮช SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5034,7 +5065,6 @@ msgid "Sort:"
msgstr "เรียงตาม:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "หมวดหมู่:"
@@ -5063,13 +5093,12 @@ msgid "Assets ZIP File"
msgstr "ทรัพยากรไฟล์ ZIP"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"ไม่สามารถเลือกตำแหน่งที่จะบันทึกภาพ lightmap\n"
-"กรุณาบันทึกฉาก (เพื่อบันทึกภาพในโฟลเดอร์เดียวกัน) หรือระบุตำแหน่งในคุณสมบัติของ BakedLightmap"
+"ไม่สามารถกำหนดตำแหน่งการบันทึกสำหรับภาพ lightmap\n"
+"ลองบันทึกฉากของคุณแล้วลองอีกครั้ง"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5084,27 +5113,28 @@ msgstr "ผิดพลาดขณะสร้างภาพ lightmap กร
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
-msgstr ""
+msgstr "การกำหนดขนาด lightmap ล้มเหลว ขนาด lightmap สูงสุดเล็กเกินไป?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
-msgstr ""
+msgstr "mesh บางส่วนไม่ถูกต้อง ตรวจสอบให้แน่ใจว่าค่า UV2 อยู่ในพื้นที่สี่เหลี่ยม [0.0,1.0]"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"เอดิเตอร์ Godot ถูกสร้างโดยไม่ได้สนับสนุน ray tracing ดังนั้นจึงไม่สามารถ bake lightmaps "
+"ได้"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "สร้าง Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "เลือกไฟล์เทมเพลต"
+msgstr "เลือกไฟล์ bake ของ lightmap :"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6184,9 +6214,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "สามารถกำหนดจุดให้แก่ ParticlesMaterial เท่านั้น"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "แปลงเป็น CPUParticles"
+msgstr "แปลงเป็น CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6834,6 +6863,14 @@ msgstr "ปิดคู่มือ"
msgid "Run"
msgstr "เริ่ม"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "ค้นหา"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "คำสั่งต่อไป"
@@ -6887,16 +6924,6 @@ msgstr ""
"ไฟล์ต่อไปนี้ในดิสก์ใหม่กว่า\n"
"จะทำอย่างไรต่อไป?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "โหลดใหม่"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "บันทึกอีกครั้ง"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "ตัวดีบัก"
@@ -6989,8 +7016,8 @@ msgstr "เบรกพอยต์"
msgid "Go To"
msgstr "ไปยัง"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "ตัด"
@@ -7213,9 +7240,8 @@ msgid "Yaw"
msgstr "Yaw"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "ขนาด: "
+msgstr "ขนาด"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7399,6 +7425,11 @@ msgstr "ล็อคการหมุนวิวแล้ว"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9851,6 +9882,10 @@ msgid "Projects"
msgstr "โปรเจกต์"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "กำลังโหลด โปรดรอ..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "แก้ไขล่าสุด"
@@ -10215,6 +10250,10 @@ msgstr "ออโต้โหลด"
msgid "Plugins"
msgstr "ปลั๊กอิน"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "นำเข้าค่าเริ่มต้น"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "พรีเซ็ต..."
@@ -10462,6 +10501,14 @@ msgid "Instance Child Scene"
msgstr "อินสแตนซ์ฉากลูก"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "ไม่สามารถวางโหนดรากในฉากเดียวกัน"
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "วางโหนด"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "ค้นพบสคริปต์"
@@ -10587,6 +10634,10 @@ msgid "Attach Script"
msgstr "แนบสคริปต์"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "ตัดโหนด"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "ลบโหนด"
@@ -10696,6 +10747,13 @@ msgid "Remote"
msgstr "ระยะไกล"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "ระยะใกล้"
@@ -11387,36 +11445,31 @@ msgstr "มอบทรัพยากร MeshLibrary ให้กับ GridMap
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "เริ่มต้น Bake"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "กำลังเตรียมโครงสร้างข้อมูล"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "สร้าง AABB"
+msgstr "สร้างบัฟเฟอร์"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "ทิศทาง"
+msgstr "lighting แบบตรง"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "ย่อหน้าขวา"
+msgstr "lighting แบบอ้อม"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "หลังประมวลผล"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "วางแนวแสง:"
+msgstr "กำลังพล็อต lightmaps"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -11916,9 +11969,8 @@ msgid "Select device from the list"
msgstr "เลือกอุปกรณ์จากรายชื่อ"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Unable to find the 'apksigner' tool."
-msgstr "ไม่สามารถหา zipalign tool"
+msgstr "ไม่สามารถหาเครื่องมือ 'apksigner'"
#: platform/android/export/export.cpp
msgid ""
@@ -11935,14 +11987,12 @@ msgid "Release keystore incorrectly configured in the export preset."
msgstr "Release keystore กำหนดค่าไว้อย่างไม่ถูกต้องในพรีเซ็ตสำหรับการส่งออก"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับการสร้างแบบกำหนดเองในการตั้งค่าเอดิเตอร์"
+msgstr "ต้องการที่อยู่ของ Android SDK ที่ถูกต้อง ในการตั้งค่าเอดิเตอร์"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับการสร้างแบบกำหนดเองในการตั้งค่าเอดิเตอร์"
+msgstr "ที่อยู่ Android SDK ไม่ถูกต้องในตั้งค่าของเอดิเตอร์"
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
@@ -11950,12 +12000,11 @@ msgstr "ไดเร็กทอรี 'platform-tools' หายไป!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "ไม่พบคำสั่ง adb ของ Android SDK platform-tools"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับการสร้างแบบกำหนดเองในการตั้งค่าเอดิเตอร์"
+msgstr "โปรดตรวจสอบในไดเร็กทอรี Android SDK ที่ระบุใตัวตั้งค่าของเอดิเตอร์"
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
@@ -11963,7 +12012,7 @@ msgstr "ไดเร็กทอรี 'build-tools' หายไป!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "ไม่พบคำสั่ง apksigner ของ Android SDK build-tools"
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12209,6 +12258,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "CollisionPolygon2D ที่ว่างเปล่าจะไม่มีผลทางกายภาพ"
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "โพลีกอนไม่ถูกต้อง ต้องมีอย่างน้อย 3 จุด ในโหมดการสร้างแบบ 'Solids'"
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "โพลีกอนไม่ถูกต้อง ต้องมีอย่างน้อย 2 จุด ในโหมดการสร้างแบบ 'Segments'"
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12396,27 +12453,23 @@ msgstr "ARVROrigin จำเป็นต้องมี ARVRCamera เป็น
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "กำลังหา meshes และ lights"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "วิเคราะห์พื้นผิว..."
+msgstr "กำลังเตรียมรูปเรขาคณิต (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "แสดงสภาพแวดล้อม"
+msgstr "กำลังเตรียมสภาพแวดล้อม"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "กำลังสร้าง Lightmaps"
+msgstr "กำลังสร้าง capture"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "กำลังสร้าง Lightmaps"
+msgstr "กำลังบันทึก lightmaps"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
@@ -12498,11 +12551,6 @@ msgstr ""
"ไดรเวอร์วีดีโอ GLES2 ไม่สนับสนุน GIProbe\n"
"ใช้ BakedLightmap แทน"
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera เลิกใช้งานแล้วและจะถูกลบออกใน Godot 4.0"
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight ที่มีมุมมากกว่า 90 ไม่สามารถสร้างเงา"
@@ -12793,7 +12841,7 @@ msgstr "ขนาดวิวพอร์ตจะต้องมากกว่
msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
-msgstr ""
+msgstr "พอร์ตตัวอย่างเชื่อมต่ออยู่แต่ไม่ได้ใช้ ควรที่จะเปลี่ยนเป็น \"SamplerPort\""
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
@@ -12823,6 +12871,10 @@ msgstr "Varyings สามารถกำหนดในังก์ชันเ
msgid "Constants cannot be modified."
msgstr "ค่าคงที่ไม่สามารถแก้ไขได้"
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera เลิกใช้งานแล้วและจะถูกลบออกใน Godot 4.0"
+
#~ msgid "No"
#~ msgstr "ไม่"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 71379593fd..47ac3ea764 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -46,22 +46,23 @@
# Kaan Genç <kaan@kaangenc.me>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
# Güneş Gümüş <gunes.gumus.001@gmail.com>, 2020.
-# Oğuz Ersen <oguzersen@protonmail.com>, 2020.
+# Oğuz Ersen <oguzersen@protonmail.com>, 2020, 2021.
# Vedat Günel <gunel15@itu.edu.tr>, 2020.
# Ahmet Elgün <ahmetelgn@gmail.com>, 2020.
# Efruz Yıldırır <efruzyildirir@gmail.com>, 2020.
# Hazar <duurkak@yandex.com>, 2020.
# Mutlu ORAN <mutlu.oran66@gmail.com>, 2020.
# Yusuf Osman YILMAZ <wolfkan4219@gmail.com>, 2020.
-# furkan atalar <fatalar55@gmail.com>, 2020.
+# furkan atalar <fatalar55@gmail.com>, 2020, 2021.
# Suleyman Poyraz <zaryob.dev@gmail.com>, 2020.
# Çağlar KOPARIR <ckoparir@gmail.com>, 2021.
+# Cem Eren Fukara <cefukara@hotmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
-"Last-Translator: Çağlar KOPARIR <ckoparir@gmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Oğuz Ersen <oguzersen@protonmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -69,7 +70,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -698,7 +699,7 @@ msgstr "Kopyalanacak izleri seç"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Kopyala"
@@ -1720,7 +1721,7 @@ msgstr "Dock Nod"
#: editor/editor_feature_profile.cpp
msgid "FileSystem Dock"
-msgstr "Dosya sistemi"
+msgstr "Dosya Sistemi"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1903,8 +1904,8 @@ msgid "Open a File or Directory"
msgstr "Bir Dosya ya da Dizin Aç"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Kaydet"
@@ -2038,7 +2039,7 @@ msgstr "Çevrimiçi Rehberler"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "Özellikler"
+msgstr "Özellikleri"
#: editor/editor_help.cpp
msgid "override:"
@@ -2050,7 +2051,7 @@ msgstr "varsayılan:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "Yöntemler"
+msgstr "Metotlar"
#: editor/editor_help.cpp
msgid "Theme Properties"
@@ -2578,8 +2579,8 @@ msgstr ""
"başarısız oldu."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "Eklentideki betik alanı bulunamıyor: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Eklentide için betik alanı bulunamıyor: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3009,14 +3010,6 @@ msgid "Help"
msgstr "Yardım"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Ara"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Çevrimiçi Belgeler"
@@ -3182,6 +3175,24 @@ msgid "Open & Run a Script"
msgstr "Aç & Bir Betik Çalıştır"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Aşağıdaki dosyalar diskte daha yeni.\n"
+"Hangi eylem yapılsın?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Yeniden Yükle"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Yeniden Kaydet"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Yeni Örnekleme"
@@ -3393,7 +3404,7 @@ msgstr "Benzersiz Yap"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Yapıştır"
@@ -3710,6 +3721,13 @@ msgstr ""
"aktarın."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"İçe aktarma bu dosya için devre dışı bırakıldı, bu nedenle düzenleme için "
+"açılamıyor."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kaynakların kökü taşınamaz/yeniden adlandırılamaz."
@@ -3953,15 +3971,15 @@ msgstr "Aranıyor..."
#: editor/find_in_files.cpp
msgid "%d match in %d file."
-msgstr "%d dosyada %d eşleşme."
+msgstr "%d eşleşme %d dosyada."
#: editor/find_in_files.cpp
msgid "%d matches in %d file."
-msgstr "%d dosyada %d eşleşme."
+msgstr "%d eşleşme %d dosyada."
#: editor/find_in_files.cpp
msgid "%d matches in %d files."
-msgstr "%d dosyada %d eşleşme."
+msgstr "%d eşleşme %d dosyada."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4099,6 +4117,22 @@ msgstr "`Post_import ()` yönteminde Node türevi bir nesne döndürdünüz mü?
msgid "Saving..."
msgstr "Kaydediliyor..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "İçe Aktarıcı'yı seçin"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "İçe Aktar"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Varsayılanlara dön"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Dosyayı Koru (İçeri Aktarma Yok)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Dosya"
@@ -5066,8 +5100,8 @@ msgid "Got:"
msgstr "Alınan:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Başarısız sha256 hash sınaması"
+msgid "Failed SHA-256 hash check"
+msgstr "SHA-256 hash kontrolü başarısız oldu"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5170,7 +5204,6 @@ msgid "Sort:"
msgstr "Sırala:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Kategori:"
@@ -6990,6 +7023,14 @@ msgstr "Belgeleri Kapat"
msgid "Run"
msgstr "Çalıştır"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Ara"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "İçeri Adımla"
@@ -7043,16 +7084,6 @@ msgstr ""
"Aşağıdaki dosyalar diskte daha yeni.\n"
"Hangi eylem yapılsın?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Yeniden Yükle"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Yeniden Kaydet"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Hata Ayıklayıcı"
@@ -7147,8 +7178,8 @@ msgstr "Hata ayıklama noktaları"
msgid "Go To"
msgstr "Şuna Git"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Kes"
@@ -7371,9 +7402,8 @@ msgid "Yaw"
msgstr "Yalpala"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Boyut: "
+msgstr "Boyut"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7557,6 +7587,11 @@ msgstr "Dönme Kilitli Görünüm"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10056,6 +10091,10 @@ msgid "Projects"
msgstr "Projeler"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Yükleniyor, lütfen bekleyin..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Son Değişiklik"
@@ -10425,6 +10464,10 @@ msgstr "Otomatik Yükle"
msgid "Plugins"
msgstr "Eklentiler"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Öntanımlı İçe Aktarma Ayarları"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Ön ayar..."
@@ -10674,6 +10717,14 @@ msgid "Instance Child Scene"
msgstr "Çocuk Sahnesini Örnekle"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Kök düğüm aynı sahneye yapıştırılamıyor."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Düğümleri Yapıştır"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Betiği Ayır"
@@ -10801,6 +10852,10 @@ msgid "Attach Script"
msgstr "Betik İliştir"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Düğümleri Kes(s)"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Düğümleri Kaldır"
@@ -10913,6 +10968,13 @@ msgid "Remote"
msgstr "Uzak"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Yerel"
@@ -12451,6 +12513,15 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Boş bir CollisionPolygon2D'nin çarpışmaya hiçbir etkisi yoktur."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "Geçersiz çokgen. 'Solids' oluşturma modunda en az 3 nokta gereklidir."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Geçersiz çokgen. 'Segments' oluşturma modunda en az 2 nokta gereklidir."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12770,13 +12841,6 @@ msgstr ""
"GIProbes GLES2 video sürücüsü tarafından desteklenmez.\n"
"Bunun yerine bir BakedLightmap kullanın."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-"InterpolatedCamera kullanımdan kaldırılmıştır ve Godot 4.0'da "
-"kaldırılacaktır."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "90 dereceden geniş açılı SpotIşık gölge oluşturamaz."
@@ -13029,7 +13093,7 @@ msgstr "Geçerli bir uzantı kullanılmalı."
#: scene/gui/graph_edit.cpp
msgid "Enable grid minimap."
-msgstr "Izgara mini haritasını etkinleştir."
+msgstr "Izgara haritasını etkinleştir."
#: scene/gui/popup.cpp
msgid ""
@@ -13120,6 +13184,12 @@ msgstr "varyings yalnızca vertex işlevinde atanabilir."
msgid "Constants cannot be modified."
msgstr "Sabit değerler değiştirilemez."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera kullanımdan kaldırılmıştır ve Godot 4.0'da "
+#~ "kaldırılacaktır."
+
#~ msgid "No"
#~ msgstr "Hayır"
@@ -14753,9 +14823,6 @@ msgstr "Sabit değerler değiştirilemez."
#~ msgid "Use Default Light"
#~ msgstr "Önyüklü Işık Kullan"
-#~ msgid "Use Default sRGB"
-#~ msgstr "Önyüklü sRGB'yi Kullan"
-
#~ msgid "Default Light Normal:"
#~ msgstr "Önyüklü Işığın Olağanı:"
diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po
index ef86476e21..d13e2e5705 100644
--- a/editor/translations/tzm.po
+++ b/editor/translations/tzm.po
@@ -626,7 +626,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1795,8 +1795,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2430,7 +2430,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2820,14 +2820,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -2981,6 +2973,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr ""
@@ -3183,7 +3191,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3487,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3864,6 +3877,22 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -4811,7 +4840,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -4915,7 +4944,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6682,6 +6710,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6733,16 +6769,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6835,8 +6861,8 @@ msgstr ""
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7242,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9581,6 +9612,10 @@ msgid "Projects"
msgstr ""
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -9941,6 +9976,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10184,6 +10223,14 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr ""
@@ -10304,6 +10351,10 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10411,6 +10462,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11878,6 +11936,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12133,11 +12199,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 31aa7794a7..1eed824645 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -12,7 +12,7 @@
# Kirill Omelchenko <kirill.omelchenko@gmail.com>, 2018.
# Александр <ol-vin@mail.ru>, 2018.
# Богдан Матвіїв <bomtvv@gmail.com>, 2019.
-# Tymofij Lytvynenko <till.svit@gmail.com>, 2020.
+# Tymofij Lytvynenko <till.svit@gmail.com>, 2020, 2021.
# Vladislav Glinsky <cl0ne@mithril.org.ua>, 2020.
# Микола Тимошенко <9081@ukr.net>, 2020.
# Miroslav <zinmirx@gmail.com>, 2020.
@@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-16 01:29+0000\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -666,7 +666,7 @@ msgstr "Виберіть доріжки для копіювання"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Копіювати"
@@ -1152,7 +1152,7 @@ msgstr "Ведучий розробник"
#. you do not have to keep it in your translation.
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr "Керівник проектів "
+msgstr "Керівник проєктів "
#: editor/editor_about.cpp
msgid "Developers"
@@ -1873,8 +1873,8 @@ msgid "Open a File or Directory"
msgstr "Відкрити файл або каталог"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Зберегти"
@@ -2548,9 +2548,8 @@ msgstr ""
"налаштування."
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
-"Не вдалося знайти поле скрипт для доповнення плагіну в: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "Не вдалося знайти поле скрипту для додатка тут: «%s»."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2984,14 +2983,6 @@ msgid "Help"
msgstr "Довідка"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Пошук"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Онлайн документація"
@@ -3157,6 +3148,24 @@ msgid "Open & Run a Script"
msgstr "Відкрити і запустити скрипт"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"На диску зберігаються новіші версії вказаних нижче файлів.\n"
+"Що слід зробити?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Перезавантажити"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Перезаписати"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Новий успадкований"
@@ -3368,7 +3377,7 @@ msgstr "Зробити унікальним"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Вставити"
@@ -3686,6 +3695,13 @@ msgstr ""
"імпортуйте вручну."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Імпортування для цього файла вимкнено, тому його не можна відкрити для "
+"редагування."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Неможливо перемістити/перейменувати корінь ресурсів."
@@ -4073,6 +4089,22 @@ msgstr "Повернули об'єкт, що походить від Node, у м
msgid "Saving..."
msgstr "Збереження..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "Виберіть засіб імпортування"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Засіб імпортування:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "Відновити типові параметри"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Зберегти файл (не імпортувати)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d файлів"
@@ -5045,8 +5077,8 @@ msgid "Got:"
msgstr "Отримав:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr "Помилка перевірки хешування sha256"
+msgid "Failed SHA-256 hash check"
+msgstr "Не вдалося пройти перевірку хешу SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5149,7 +5181,6 @@ msgid "Sort:"
msgstr "Сортувати:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Категорія:"
@@ -6977,6 +7008,14 @@ msgstr "Закрити документацію"
msgid "Run"
msgstr "Запустити"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Пошук"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "Крок в"
@@ -7030,16 +7069,6 @@ msgstr ""
"Такі файли на диску новіші.\n"
"Що робити?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "Перезавантажити"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "Перезаписати"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "Зневаджувач"
@@ -7136,8 +7165,8 @@ msgstr "Точки зупину"
msgid "Go To"
msgstr "Перейти"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Вирізати"
@@ -7360,9 +7389,8 @@ msgid "Yaw"
msgstr "Відхилення"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Розмір: "
+msgstr "Розмір"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7546,6 +7574,11 @@ msgstr "Обертання перегляду заблоковано"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10049,13 +10082,17 @@ msgstr ""
#. TRANSLATORS: This refers to the application where users manage their Godot projects.
#: editor/project_manager.cpp
msgid "Project Manager"
-msgstr "Керівник проекту"
+msgstr "Керівник проєкту"
#: editor/project_manager.cpp
msgid "Projects"
msgstr "Проєкти"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Завантаження. Будь ласка, зачекайте..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "Востаннє змінено"
@@ -10425,6 +10462,10 @@ msgstr "Автозавантаження"
msgid "Plugins"
msgstr "Плаґіни (додатки)"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "Типові параметри імпортування"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "Заздалегідь установлений..."
@@ -10676,6 +10717,14 @@ msgid "Instance Child Scene"
msgstr "Створити екземпляр дочірньої сцени"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Не можна вставляти кореневий вузол до сцени цього кореневого вузла."
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "Вставити вузли"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "Від'єднати скрипт"
@@ -10802,6 +10851,10 @@ msgid "Attach Script"
msgstr "Долучити скрипт"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "Вирізати вузли"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Вилучити вузли"
@@ -10916,6 +10969,13 @@ msgid "Remote"
msgstr "Віддалений"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Локальний"
@@ -12480,6 +12540,16 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "Порожній CollisionPolygon2D ніяк не вплине на зіткнення."
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+"Некоректний полігон. У режимі збирання «Solids» потрібно принаймні 3 точки."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+"Некоректний полігон. У режимі збирання «Segments» потрібні принаймні 2 точки."
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12801,12 +12871,6 @@ msgstr ""
"У драйвері GLES2 не передбачено підтримки GIProbes.\n"
"Скористайтеся замість них BakedLightmap."
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-"InterpolatedCamera вважається застарілою, її буде вилучено у Godot 4.0."
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "SpotLight з кутом, який є більшим за 90 градусів, не може давати тіні."
@@ -13152,6 +13216,11 @@ msgstr "Змінні величини можна пов'язувати лише
msgid "Constants cannot be modified."
msgstr "Сталі не можна змінювати."
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr ""
+#~ "InterpolatedCamera вважається застарілою, її буде вилучено у Godot 4.0."
+
#~ msgid "No"
#~ msgstr "Ні"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index bf95b4c01f..697cc3e5a4 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -636,7 +636,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr ""
@@ -1829,8 +1829,8 @@ msgid "Open a File or Directory"
msgstr ""
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr ""
@@ -2480,7 +2480,7 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
@@ -2874,14 +2874,6 @@ msgid "Help"
msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr ""
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr ""
@@ -3037,6 +3029,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "New Inherited"
msgstr "سب سکریپشن بنائیں"
@@ -3244,7 +3252,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr ""
@@ -3553,6 +3561,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3942,6 +3955,24 @@ msgstr ""
msgid "Saving..."
msgstr ""
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr ".تمام کا انتخاب"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr ".سپورٹ"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -4913,7 +4944,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5018,7 +5049,6 @@ msgid "Sort:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr ""
@@ -6835,6 +6865,14 @@ msgstr ""
msgid "Run"
msgstr ""
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6886,16 +6924,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -6992,8 +7020,8 @@ msgstr ".تمام کا انتخاب"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr ""
@@ -7406,6 +7434,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9826,6 +9859,10 @@ msgid "Projects"
msgstr ".تمام کا انتخاب"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10191,6 +10228,10 @@ msgstr ""
msgid "Plugins"
msgstr ""
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10434,6 +10475,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "ایکشن منتقل کریں"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "سب سکریپشن بنائیں"
@@ -10561,6 +10611,11 @@ msgid "Attach Script"
msgstr "سب سکریپشن بنائیں"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "ایکشن منتقل کریں"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -10671,6 +10726,13 @@ msgid "Remote"
msgstr ".تمام کا انتخاب"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12183,6 +12245,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12438,11 +12508,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index c08fca86dd..74d8666e35 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -15,13 +15,15 @@
# Steve Dang <bynguu@outlook.com>, 2020.
# Harry Mitchell <minhyh0987@gmail.com>, 2020.
# HSGamer <huynhqtienvtag@gmail.com>, 2020.
-# LetterC67 <hoangdeptoong@gmail.com>, 2020.
+# LetterC67 <hoangdeptoong@gmail.com>, 2020, 2021.
+# Rev <revolnoom7801@gmail.com>, 2021.
+# SyliawDeV <thanhlongstranger@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
-"Last-Translator: LetterC67 <hoangdeptoong@gmail.com>\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: Rev <revolnoom7801@gmail.com>\n"
"Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/"
"godot/vi/>\n"
"Language: vi\n"
@@ -29,12 +31,13 @@ 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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "Hàm convert() có loại đối số không hợp lệ, sử dụng các hằng TYPE_*."
+msgstr ""
+"Hàm convert() có loại đối số không hợp lệ, hãy sử dụng các hằng TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -48,11 +51,11 @@ msgstr "Không đủ byte để giải mã, hoặc định dạng không hợp l
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "Dữ liệu vào không hợp lệ %i (không được thông qua)"
+msgstr "Đầu vào %i không hợp lệ (không được thông qua) trong biểu thức"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "self không thể sử dụng vì instance là null (không thông qua)"
+msgstr "Không thể sử dụng self vì instance là null (không thông qua)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -72,7 +75,7 @@ msgstr "Đối số không hợp lệ để dựng '%s'"
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr "Khi cuộc gọi đến '%s':"
+msgstr "Khi gọi đến '%s':"
#: core/ustring.cpp
msgid "B"
@@ -171,29 +174,24 @@ msgid "Anim Change Call"
msgstr "Đổi Function Gọi Animation"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Time"
-msgstr "Đổi thời gian khung hình"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transition"
-msgstr "Đổi Transition Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "Đổi Transform Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Value"
-msgstr "Đổi giá trị khung hình"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Đổi Function Gọi Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -206,28 +204,27 @@ msgstr "Chỉnh Vòng Lặp Hoạt Ảnh"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr ""
+msgstr "Theo dõi đặc tính"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
-msgstr ""
+msgstr "Theo dõi chuyển đổi 3D"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr ""
+msgstr "Gọi phương thức theo dõi"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr ""
+msgstr "Theo dõi đường cong Bezier"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr ""
+msgstr "Kênh Âm Thanh"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation Playback Track"
-msgstr "Ngưng chạy animation. (S)"
+msgstr "Kênh Hoạt Ảnh"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -238,7 +235,6 @@ msgid "Animation length (seconds)"
msgstr "Độ dài hoạt ảnh (giây)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Track"
msgstr "Thêm Track Animation"
@@ -257,7 +253,7 @@ msgstr "Âm thanh:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr ""
+msgstr "Hoạt ảnh:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -265,7 +261,7 @@ msgstr "Thay đổi đường dẫn Track"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Bật tắt track này on/off."
+msgstr "Bật/tắt kênh này."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -285,7 +281,7 @@ msgstr "Bỏ track này."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
-msgstr "Bước: "
+msgstr "Thời gian (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
@@ -383,7 +379,7 @@ msgstr "Chèn Anim"
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
-msgstr "AnimationPlayer không thể tự tạo hoạt ảnh, chỉ các player khác."
+msgstr "AnimationPlayer không thể tự tạo hoạt ảnh, phải nhờ các Player khác."
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
@@ -407,7 +403,7 @@ msgstr "Sắp xếp lại Tracks"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr ""
+msgstr "Các chuyển đổi chỉ có thể áp dụng cho các nút dựa trên kiểu Spatial."
#: editor/animation_track_editor.cpp
msgid ""
@@ -416,7 +412,7 @@ msgid ""
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
-"Các bản âm thanh chỉ có thể trỏ đến các nút:\n"
+"Các bản âm thanh chỉ có thể trỏ đến các loại:\n"
"-AudioStreamPlayer\n"
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
@@ -428,10 +424,11 @@ msgstr "Các bản hoạt ảnh chỉ có thể trỏ tới các nút AnimationP
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
msgstr ""
+"Animation player không tự tạo hoạt ảnh được, phải thông qua các player khác."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr ""
+msgstr "Không thể thêm track mới mà không có root"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
@@ -443,7 +440,7 @@ msgstr "Thêm Bezier Track"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr "Đường dẫn không hợp lệ, không thể thêm khoá."
+msgstr "Đường dẫn không hợp lệ, nên không thể thêm khóa."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
@@ -482,14 +479,13 @@ msgid "Paste Tracks"
msgstr "Dán Tracks"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Scale Keys"
-msgstr "Anim Scale Keys"
+msgstr "Key để scale hoạt ảnh"
#: editor/animation_track_editor.cpp
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
-msgstr ""
+msgstr "Tùy chọn này không áp lên Bezier được, vì nó chỉ là một track."
#: editor/animation_track_editor.cpp
msgid ""
@@ -503,15 +499,21 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
+"Hoạt ảnh này thuộc về một Cảnh được Nhập, nên các thay đổi lên track được "
+"Nhập sẽ không được lưu lại.\n"
+"\n"
+"Để bật khả năng thêm track tùy ý, đi đến cài đặt của Cảnh được Nhập rồi đặt\n"
+"\"Hoạt Ảnh > Lưu trữ\" thành \"Tệp\", bật \"Hoạt ảnh > Giữ các track tùy "
+"chỉnh\", sau đó Nhập lại.\n"
+"Hoặc, dùng một Cài đặt trước nhập để Nhập hoạt ảnh ra các tệp khác nhau."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
msgstr "Cảnh bảo: Chỉnh sửa hoạt ảnh đã nhập"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr "Chọn một AnimationPlayer từ Scene Tree để chỉnh sửa animation."
+msgstr "Chọn một AnimationPlayer để tạo và chỉnh sửa Hoạt Ảnh."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
@@ -523,7 +525,7 @@ msgstr "Nhóm các track bởi nút hoặc hiển thị chúng dạng danh sách
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr "Chụp:"
+msgstr "Dính:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -536,7 +538,7 @@ msgstr "Giây"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "FPS"
-msgstr ""
+msgstr "Khung hình(FPS)"
#: editor/animation_track_editor.cpp editor/editor_properties.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -554,7 +556,7 @@ msgstr "Thuộc tính hoạt cảnh."
#: editor/animation_track_editor.cpp
msgid "Copy Tracks"
-msgstr ""
+msgstr "Sao Chép Tracks"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
@@ -570,7 +572,7 @@ msgstr "Nhân đôi lựa chọn"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr ""
+msgstr "Chuyển đổi trùng lặp"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -598,7 +600,7 @@ msgstr "Chọn node để được làm diễn hoạt:"
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
-msgstr ""
+msgstr "Sử dụng đường cong Bezier"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -606,15 +608,15 @@ msgstr "Tối ưu hóa Animation"
#: editor/animation_track_editor.cpp
msgid "Max. Linear Error:"
-msgstr ""
+msgstr "Sai lệch tuyến tính lớn nhất:"
#: editor/animation_track_editor.cpp
msgid "Max. Angular Error:"
-msgstr ""
+msgstr "Sai lệch góc lớn nhất:"
#: editor/animation_track_editor.cpp
msgid "Max Optimizable Angle:"
-msgstr ""
+msgstr "Góc lớn nhất có thể tối ưu:"
#: editor/animation_track_editor.cpp
msgid "Optimize"
@@ -622,7 +624,7 @@ msgstr "Tối ưu"
#: editor/animation_track_editor.cpp
msgid "Remove invalid keys"
-msgstr "Gỡ bỏ các khoá không hợp lệ"
+msgstr "Xóa các khoá không hợp lệ"
#: editor/animation_track_editor.cpp
msgid "Remove unresolved and empty tracks"
@@ -642,26 +644,24 @@ msgstr "Dọn dẹp"
#: editor/animation_track_editor.cpp
msgid "Scale Ratio:"
-msgstr "Tỉ lệ Scale:"
+msgstr "Tỉ lệ phóng đại:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "Chọn các Track để sao chép:"
+msgstr "Chọn các Track để sao chép"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "Sao chép"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select All/None"
-msgstr "Chọn Không có"
+msgstr "Chọn/Bỏ tất cả"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
@@ -669,19 +669,19 @@ msgstr "Thêm Track Âm thanh"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "Thay đổi thời điểm bắt đầu phát track âm thanh"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "Thay đổi thời điểm kết thúc track âm thanh"
#: editor/array_property_edit.cpp
msgid "Resize Array"
-msgstr "Đổi lại size Array"
+msgstr "Thay đổi kích thước mảng"
#: editor/array_property_edit.cpp
msgid "Change Array Value Type"
-msgstr "Đổi loại giá trị Array"
+msgstr "Đổi kiểu giá trị Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value"
@@ -696,19 +696,16 @@ msgid "Line Number:"
msgstr "Dòng số:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Thay thế ..."
+msgstr "Đã thay %d."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d match."
-msgstr "Tìm thấy %d khớp."
+msgstr "%d khớp."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "Tìm thấy %d khớp."
+msgstr "%d khớp."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -728,7 +725,7 @@ msgstr "Thay thế tất cả"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr "Chỉ lựa chọn"
+msgstr "Chỉ chọn"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -737,7 +734,7 @@ msgstr "Chuẩn"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr ""
+msgstr "Hiện/Ẩn bảng Tệp lệnh"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -753,7 +750,7 @@ msgstr "Thu nhỏ"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr "Đặt lại phóng"
+msgstr "Đặt lại độ phóng"
#: editor/code_editor.cpp
msgid "Warnings"
@@ -768,9 +765,8 @@ msgid "Method in target node must be specified."
msgstr "Phương thức trong nút đích phải được chỉ định."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Phương thức trong nút đích phải được chỉ định."
+msgstr "Tên phương thức phải là một định danh hợp lệ."
#: editor/connections_dialog.cpp
msgid ""
@@ -819,12 +815,11 @@ msgstr "Thêm đối số mở rộng:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
-msgstr "Mở rộng Đối số được gọi:"
+msgstr "Đối số mở rộng được gọi:"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Receiver Method:"
-msgstr "Lọc các nút"
+msgstr "Hàm nhận:"
#: editor/connections_dialog.cpp
msgid "Advanced"
@@ -838,7 +833,7 @@ msgstr "Trì hoãn"
msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr ""
-"Trì hoãn tín hiệu, lưu vào một hàng chờ và chỉ kích nó vào thời gian rãnh."
+"Trì hoãn tín hiệu, lưu vào một hàng chờ và chỉ kích nó vào thời gian rảnh."
#: editor/connections_dialog.cpp
msgid "Oneshot"
@@ -846,7 +841,7 @@ msgstr "Một lần"
#: editor/connections_dialog.cpp
msgid "Disconnects the signal after its first emission."
-msgstr "Ngắt kết nối tín hiệu sau lần phát xạ đầu tiên."
+msgstr "Ngắt kết nối tín hiệu sau lần phát đầu tiên."
#: editor/connections_dialog.cpp
msgid "Cannot connect signal"
@@ -864,7 +859,7 @@ msgstr "Không thể kết nối tín hiệu"
#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Close"
-msgstr "Tắt"
+msgstr "Đóng"
#: editor/connections_dialog.cpp
msgid "Connect"
@@ -912,9 +907,8 @@ msgid "Signals"
msgstr "Tín hiệu (Signal)"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Lọc tệp tin ..."
+msgstr "Lọc tín hiệu"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -978,7 +972,6 @@ msgid "Search Replacement For:"
msgstr "Tìm kiếm thay thế cho:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid "Dependencies For:"
msgstr "Phần phụ thuộc cho:"
@@ -1026,7 +1019,7 @@ msgstr "Trình chỉnh sửa Phụ thuộc"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
-msgstr ""
+msgstr "Tìm kiếm tài nguyên thay thế:"
#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
#: editor/editor_help_search.cpp editor/editor_node.cpp
@@ -1043,11 +1036,12 @@ msgid "Owners Of:"
msgstr "Sở hữu của:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "Gỡ bỏ các tệp đã chọn trong dự án? (Không thể khôi phục)"
+msgstr ""
+"Gỡ bỏ các tệp đã chọn trong dự án? (Không thể khôi phục)\n"
+"Bạn có thể khôi phục chúng trong thùng rác của hệ thống."
#: editor/dependency_editor.cpp
msgid ""
@@ -1056,6 +1050,9 @@ msgid ""
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"Các tài nguyên khác cần những tệp bị xóa này mới hoạt động được.\n"
+"Vẫn xóa hả? (không hồi được đâu)\n"
+"Bạn có thể khôi phục chúng trong thùng rác hệ thống."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1067,11 +1064,11 @@ msgstr "Lỗi tải nạp:"
#: editor/dependency_editor.cpp
msgid "Load failed due to missing dependencies:"
-msgstr ""
+msgstr "Tải thất bại do thiếu phần phụ thuộc:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
-msgstr "Luôn mở"
+msgstr "Cứ mở thôi"
#: editor/dependency_editor.cpp
msgid "Which action should be taken?"
@@ -1087,16 +1084,15 @@ msgstr "Lỗi tải nạp!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Xoá vĩnh viễn các đối tượng %d? (Không thể hoàn lại!)"
+msgstr "Xoá vĩnh viễn %d đối tượng? (Không thể hoàn lại!)"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid "Show Dependencies"
-msgstr "Phần phụ thuộc cho:"
+msgstr "Hiện các phần phụ thuộc"
#: editor/dependency_editor.cpp
msgid "Orphan Resource Explorer"
-msgstr ""
+msgstr "Tìm tài nguyên mất gốc"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
@@ -1112,7 +1108,7 @@ msgstr "Sở hữu"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Tài nguyên không có quyền sở hữu rõ ràng:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
@@ -1128,7 +1124,7 @@ msgstr "Cảm ơn từ cộng đồng Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "Đóng góp vào Godot Engine"
+msgstr "Cá nhân đóng góp của Godot Engine"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -1162,14 +1158,12 @@ msgid "Gold Sponsors"
msgstr "Nhà tài trợ Vàng"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Người ủng hộ Bạc"
+msgstr "Nhà tài trợ Bạc"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Người ủng hộ Đồng"
+msgstr "Nhà tài trợ Đồng"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1193,15 +1187,13 @@ msgstr "Người ủng hộ"
#: editor/editor_about.cpp
msgid "License"
-msgstr "Cấp phép"
+msgstr "Giấy phép"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Third-party Licenses"
-msgstr "Cấp phép nhóm thứ ba"
+msgstr "Giấy phép bên thứ ba"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
@@ -1226,27 +1218,24 @@ msgid "Licenses"
msgstr "Các giấy phép"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file, not in ZIP format."
-msgstr "Lỗi không thể mở gói, không phải dạng nén."
+msgstr "Lỗi không thể mở gói, không phải dạng nén ZIP."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (Already Exists)"
-msgstr "Tam giác đã tồn tại."
+msgstr "%s (Đã tồn tại)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr "Giải nén Assets"
+msgstr "Giải nén tài nguyên"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "Không thể lấy các tệp sau khỏi gói:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "And %s more files."
-msgstr "%d thêm các tệp tin"
+msgstr "Và %s tệp nữa."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
@@ -1258,9 +1247,8 @@ msgid "Success!"
msgstr "Thành công!"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Package Contents:"
-msgstr "Nội dung:"
+msgstr "Trong Gói có:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1280,11 +1268,11 @@ msgstr "Thêm hiệu ứng"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr ""
+msgstr "Đổi tên Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr ""
+msgstr "Thay đổi âm lượng Bus"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
@@ -1292,7 +1280,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr ""
+msgstr "Bật/Tắt Âm Thanh của Bus"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Bypass Effects"
@@ -1304,19 +1292,19 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr ""
+msgstr "Thêm hiệu ứng vào Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr ""
+msgstr "Di chuyển hiệu ứng Bus"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr ""
+msgstr "Xóa hiệu ứng của Bus"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
-msgstr ""
+msgstr "Kéo & thả để sắp xếp lại."
#: editor/editor_audio_buses.cpp
msgid "Solo"
@@ -1332,12 +1320,12 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr ""
+msgstr "Tùy chọn Bus"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "Nhân bản"
+msgstr "Nhân đôi"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -1353,23 +1341,23 @@ msgstr "Âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr ""
+msgstr "Thêm Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr ""
+msgstr "Không thể xóa Bus âm thanh chủ!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr ""
+msgstr "Xóa Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr ""
+msgstr "Nhân bản Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr ""
+msgstr "Đặt lại âm lượng Bus"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
@@ -1377,7 +1365,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr ""
+msgstr "Lưu bố cục Bus âm thanh thành..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1385,7 +1373,7 @@ msgstr "Vị trí cho Bố cục mới..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr ""
+msgstr "Mở bố cục Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "There is no '%s' file."
@@ -1397,20 +1385,19 @@ msgstr "Bố trí"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr ""
+msgstr "Sai kiểu tệp, không phải bố cục bus âm thanh."
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Error saving file: %s"
-msgstr "Lỗi tải font."
+msgstr "Lỗi lưu tệp: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
-msgstr ""
+msgstr "Thêm Bus"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr ""
+msgstr "Thêm Bus âm thanh mới cho bố cục."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1420,7 +1407,7 @@ msgstr "Nạp"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr ""
+msgstr "Nạp một bố cục Bus có sẵn."
#: editor/editor_audio_buses.cpp
msgid "Save As"
@@ -1428,7 +1415,7 @@ msgstr "Lưu thành"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr ""
+msgstr "Lưu bố cục Bus này vào tệp."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
@@ -1436,11 +1423,11 @@ msgstr "Nạp mặc định"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr ""
+msgstr "Nạp bố cục Bus mặc định."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr ""
+msgstr "Tạo bố cục Bus mới."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
@@ -1452,27 +1439,27 @@ msgstr "Ký tự hợp lệ:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
+msgstr "Không được trùng tên với một lớp có sẵn của công cụ lập trình."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr ""
+msgstr "Không được trùng với tên một kiểu có sẵn đã tồn tại."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
+msgstr "Không được trùng với tên một hằng số toàn cục đã tồn tại."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Từ khóa không thể dùng làm tên một nạp tự động."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr ""
+msgstr "Nạp tự động '%s' đã tồn tại!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr ""
+msgstr "Đổi tên Nạp tự động"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
@@ -1484,7 +1471,7 @@ msgstr ""
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Xóa Nạp tự động"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
@@ -1496,7 +1483,7 @@ msgstr "Sắp xếp lại Autoloads"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Không thể thêm nạp tự động:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1521,7 +1508,7 @@ msgstr "Tên"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr "Singleton"
+msgstr "Đơn nhất"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
@@ -1545,7 +1532,7 @@ msgstr "[rỗng]"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr "[chưa save]"
+msgstr "[chưa lưu]"
#: editor/editor_dir_dialog.cpp
msgid "Please select a base directory first."
@@ -1583,7 +1570,7 @@ msgstr "Lưu trữ tệp tin:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr ""
+msgstr "Không thấy mẫu xuất nào ở đường dẫn mong đợi:"
#: editor/editor_export.cpp
msgid "Packing"
@@ -1617,22 +1604,20 @@ msgstr ""
"Trình điều khiển Dự phòng'."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Nền tảng yêu cầu dùng kiểu nén 'ETC' cho GLES2. Bật 'Nhập ETC' trong Cài đặt "
-"Dự án."
+"Nền tảng yêu cầu dùng kiểu nén 'PVRTC' cho GLES2. Hãy bật 'Nhập Pvrtc' trong "
+"Cài đặt Dự án."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Nền tảng yêu cầu dùng kiểu nén 'ETC2' cho GLES3. Bật 'Nhập ETC2' trong Cài "
-"đặt Dự án."
+"Nền tảng yêu cầu dùng kiểu nén 'ETC2' hoặc 'PVRTC' cho GLES3. Hãy bật 'Nhập "
+"ETC2' hoặc 'Nhập Pvrtc' trong Cài đặt Dự án."
#: editor/editor_export.cpp
#, fuzzy
@@ -1656,7 +1641,7 @@ msgstr "Không tìm thấy mẫu gỡ lỗi tuỳ chỉnh."
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr ""
+msgstr "Không tìm thấy mẫu phát hành tùy chỉnh."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
@@ -1684,16 +1669,15 @@ msgstr "Chỉnh sửa cảnh"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr "Nút"
+msgstr "Khung nút"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Hệ thống tập tin"
+msgstr "Khung Hệ thống tập tin"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Nhập vào"
+msgstr "Khung Nhập"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
@@ -1721,7 +1705,7 @@ msgstr "(Đã tắt trình chỉnh sửa)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr "Tuỳ chọn lớp:"
+msgstr "Tuỳ chọn Lớp:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
@@ -1744,11 +1728,10 @@ msgid "File '%s' format is invalid, import aborted."
msgstr "Tệp '%s' định dạng không hợp lệ, huỷ nhập vào."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
-msgstr "Hồ sơ '%s' đã tồn tại. Di chuyển hồ sơ trước khi nhập, huỷ nhập."
+msgstr "Hồ sơ '%s' đã tồn tại. Hãy xóa hồ sơ đấy trước khi nhập, đã dừng nhập."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
@@ -1759,9 +1742,8 @@ msgid "Unset"
msgstr "Bỏ đặt"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Current Profile:"
-msgstr "Hồ sơ hiện tại"
+msgstr "Hồ sơ hiện tại:"
#: editor/editor_feature_profile.cpp
msgid "Make Current"
@@ -1776,16 +1758,15 @@ msgstr "Mới"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Nhập vào"
+msgstr "Nhập"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
msgstr "Xuất ra"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Available Profiles:"
-msgstr "Hồ sơ khả dụng"
+msgstr "Hồ sơ khả dụng:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
@@ -1852,7 +1833,7 @@ msgstr "Làm mới"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr ""
+msgstr "Đã nhận diện hết"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
@@ -1875,8 +1856,8 @@ msgid "Open a File or Directory"
msgstr "Mở một tệp tin hoặc thư mục"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "Lưu"
@@ -1915,39 +1896,35 @@ msgstr "Tập trung Đường dẫn"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr "Di chuyển Ưa thích lên"
+msgstr "Di chuyển mục Ưa thích lên"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr "Di chuyển Ưa thích xuống"
+msgstr "Di chuyển mục Ưa thích xuống"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Đến thư mục cha"
+msgstr "Quay lại thư mục trước."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Đến thư mục cha"
+msgstr "Đến thư mục tiếp theo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr "Đến thư mục cha"
+msgstr "Đến thư mục mẹ."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Refresh files."
-msgstr "Tìm kiếm tệp tin"
+msgstr "Làm mới các tệp."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
msgstr "Bỏ yêu thích thư mục hiện tại."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Toggle the visibility of hidden files."
-msgstr "Bật tắt hiện các tệp tin ẩn."
+msgstr "Hiện/ẩn tệp ẩn."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
@@ -1980,10 +1957,12 @@ msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Có nhiều trình nhập cho nhiều loại khác nhau cùng chỉ đến tệp %s, đã ngừng "
+"nhập"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "Nhập lại tài nguyên"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
@@ -2003,28 +1982,24 @@ msgid "Inherited by:"
msgstr "Được thừa kế bởi:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Mô tả:"
+msgstr "Mô tả"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Online Tutorials"
-msgstr "Hướng dẫn trực tuyến:"
+msgstr "Hướng dẫn trực tuyến"
#: editor/editor_help.cpp
msgid "Properties"
msgstr "Thuộc tính"
#: editor/editor_help.cpp
-#, fuzzy
msgid "override:"
-msgstr "Ghi đè"
+msgstr "Ghi đè:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Mặc định"
+msgstr "mặc định:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2032,7 +2007,7 @@ msgstr "Hàm"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr ""
+msgstr "Cài đặt Tông màu"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2040,23 +2015,23 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Hằng số"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Property Descriptions"
-msgstr "Mô tả ngắn gọn:"
+msgstr "Mô tả thuộc tính"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Giá trị:"
+msgstr "(giá trị)"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Hiện thuộc tính này chưa được mô tả. Các bạn [color=$color][url=$url]đóng "
+"góp[/url][/color] giúp chúng mình nha!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
@@ -2067,21 +2042,21 @@ msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Hiện phương thức này chưa được mô tả. Các bạn [color=$color][url=$url]đóng "
+"góp[/url][/color] giúp chúng mình nha!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr "Tìm sự giúp đỡ"
+msgstr "Tìm trợ giúp"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Case Sensitive"
-msgstr "Đóng Cảnh"
+msgstr "Phân biệt hoa thường"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Show Hierarchy"
-msgstr "Tìm kiếm"
+msgstr "Hiện cấp bậc"
#: editor/editor_help_search.cpp
msgid "Display All"
@@ -2089,27 +2064,27 @@ msgstr "Hiển thị tất cả"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr "Chỉ các Lớp"
+msgstr "Chỉ tìm Lớp"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr "Chỉ các Hàm"
+msgstr "Chỉ tìm Hàm"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr "Chỉ các Tín hiệu"
+msgstr "Chỉ tìm Tín hiệu"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr "Chỉ các Định nghĩa"
+msgstr "Chỉ tìm Hằng số"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr "Chỉ các Thuộc tính"
+msgstr "Chỉ tìm Thuộc tính"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Chỉ tìm cài đặt Tông màu"
#: editor/editor_help_search.cpp
msgid "Member Type"
@@ -2120,28 +2095,24 @@ msgid "Class"
msgstr "Lớp"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Method"
msgstr "Hàm"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Signal"
msgstr "Tín hiệu"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr "Cố định"
+msgstr "Hằng số"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Property"
-msgstr "Thuộc tính:"
+msgstr "Thuộc tính"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Property"
-msgstr "Thuộc tính:"
+msgstr "Cài đặt Tông màu"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
@@ -2189,16 +2160,15 @@ msgstr "Bắt đầu"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
-#, fuzzy
msgid "Down"
-msgstr "Tải"
+msgstr "Xuống"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Lên"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2206,23 +2176,23 @@ msgstr "Nút"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC đến"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET đến"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC đi"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET đi"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Cửa sổ mới"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
@@ -2231,19 +2201,19 @@ msgstr "Tài nguyên đã nhập không thể lưu."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "OK"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Lỗi lưu tài nguyên!"
#: editor/editor_node.cpp
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
-"Tài nguyên này không thể lưu vì nó không thuộc cảnh đã chỉnh sửa. Tạo nó là "
-"duy nhất."
+"Không thể lưu tài nguyên này vì nó không thuộc cảnh đã chỉnh sửa. Làm nó độc "
+"nhất đã."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2271,11 +2241,11 @@ msgstr "Lỗi khi đang phân tích '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr ""
+msgstr "Tệp kết thúc bất ngờ '%s'."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "Thiếu '%s' hoặc các phần phụ thuộc."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
@@ -2295,15 +2265,15 @@ msgstr "Tạo hình thu nhỏ"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr "Hoạt động không thể hoàn tất khi không có nút gốc."
+msgstr "Hành động không thể hoàn thành mà không có nút gốc."
#: editor/editor_node.cpp
msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
-"Cảnh này không thể lưu vì đây bao một trường hợp theo chu kỳ.\n"
-"Giải quyết nó và cố gắng lưu lại."
+"Không thể lưu cảnh này vì bạn đang instancing chồng chéo nối vòng nhau.\n"
+"Giải quyết vòng nối đã rồi hãy thử lưu lại sau."
#: editor/editor_node.cpp
msgid ""
@@ -2319,15 +2289,15 @@ msgstr "Không thể ghi đè cảnh vẫn đang mở!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "Không thể nạp MeshLibrary để sáp nhập!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "Lỗi lưu MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "Không thể tải TileSet để sáp nhập!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
@@ -2338,6 +2308,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Có lỗi khi đang lưu bố cục trình chỉnh sửa.\n"
+"Hãy thử kiểm tra quyền ghi lên đường dẫn dữ liệu của người dùng xem."
#: editor/editor_node.cpp
msgid ""
@@ -2345,15 +2317,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Bố cục mặc định của trình chỉnh sửa đã bị ghi đè.\n"
+"Để hồi lại bố cục mặc định về cài đặt gốc, sử dụng tùy chọn \"Xóa bố cục\" "
+"rồi xóa bố cục \"Mặc định\"."
#: editor/editor_node.cpp
msgid "Layout name not found!"
-msgstr "Tên bố cục không tìm thấy!"
+msgstr "Không tìm thấy tên bố cục!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Đã khôi phục bố cục mặc định cho các thiết lập."
+msgstr "Đã khôi phục bố cục mặc định về thiết lập gốc."
#: editor/editor_node.cpp
msgid ""
@@ -2361,8 +2335,8 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"Tài nguyên thuộc về cảnh đã nhập, nó không thể chỉnh sửa.\n"
-"Đọc tài liệu liên quan để cách nhập Cảnh để hiểu rõ quy trình việc này."
+"Tài nguyên thuộc về cảnh đã nhập, nên không thể sửa được.\n"
+"Hãy đọc hướng dẫn về cách nhập Cảnh để hiểu thêm về quy trình này."
#: editor/editor_node.cpp
msgid ""
@@ -2377,8 +2351,8 @@ msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
-"Tài nguyên đã được nhập vào, không thể chỉnh sửa. Thay đổi cài đặt của nó "
-"trong bảng Nhập vào, sau đó nhập vào lại."
+"Tài nguyên này được nhập, nên không thể chỉnh sửa. Thay đổi cài đặt của nó "
+"trong bảng Nhập, sau đó Nhập lại."
#: editor/editor_node.cpp
msgid ""
@@ -2387,10 +2361,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"Cảnh này đã được nhập vào, những thay đổi sẽ không được giữ lại.\n"
-"Tạo thực thể nó hoặc kế thừa sẽ cho phép thực hiện các thay đổi.\n"
-"Đọc tài liệu tài liệu liên quan đến nhập Cảnh để hiểu rõ về quy trình việc "
-"này."
+"Do Cảnh này được nhập, nên những thay đổi sẽ không được giữ lại.\n"
+"Thực hiện khởi tạo đối tượng hoặc kế thừa sẽ cho phép việc chỉnh sửa.\n"
+"Hãy đọc hướng dẫn liên quan đến nhập Cảnh để hiểu thêm về quy trình này."
#: editor/editor_node.cpp
msgid ""
@@ -2407,19 +2380,19 @@ msgstr "Không có cảnh được xác định để chạy."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Lưu cảnh trước khi chạy..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
-msgstr "Không thể bắt đầu quá trình nhỏ!"
+msgstr "Không thể bắt đầu quá trình phụ!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr "Mở Scene"
+msgstr "Mở Cảnh"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr "Mở Scene Mẫu"
+msgstr "Mở Cảnh cơ sở"
#: editor/editor_node.cpp
msgid "Quick Open..."
@@ -2427,11 +2400,11 @@ msgstr "Mở nhanh ..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr "Mở Scene nhanh..."
+msgstr "Mở Nhanh Cảnh..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr "Mở Script nhanh..."
+msgstr "Mở Nhanh Tệp lệnh..."
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -2451,11 +2424,11 @@ msgstr "Yêu cầu một nút gốc khi lưu cảnh."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Lưu Scene với tên..."
+msgstr "Lưu Cảnh thành..."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
-msgstr "Thao tác này phải có scene mới làm được."
+msgstr "Thao tác này phải có Cảnh mới làm được."
#: editor/editor_node.cpp
msgid "Export Mesh Library"
@@ -2475,26 +2448,27 @@ msgstr "Thao tác này phải có node được chọn mới làm được."
#: editor/editor_node.cpp
msgid "Current scene not saved. Open anyway?"
-msgstr "Scene hiện tại chưa save. Kệ mở luôn?"
+msgstr "Cảnh hiện tại chưa lưu. Kệ mở luôn?"
#: editor/editor_node.cpp
msgid "Can't reload a scene that was never saved."
-msgstr "Không thể nạp một cảnh mà chưa lưu bao giờ."
+msgstr "Không thể nạp một cảnh chưa lưu bao giờ."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "Lưu Cảnh"
+msgstr "Tải lại Cảnh đã lưu"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Cảnh hiện tại có thay đổi chưa được lưu.\n"
+"Vẫn tải lại à? Không hoàn tác được đâu."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
-msgstr "Chạy Scene nhanh..."
+msgstr "Chạy nhanh Cảnh..."
#: editor/editor_node.cpp
msgid "Quit"
@@ -2541,32 +2515,35 @@ msgid "Close Scene"
msgstr "Đóng Cảnh"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reopen Closed Scene"
-msgstr "Đóng Cảnh"
+msgstr "Mở lại Cảnh đã đóng"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
+msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr ""
+msgstr "Không thể nạp tệp lệnh bổ trợ từ đường dẫn: '%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"Không thể nạp tệp lệnh bổ trợ từ đường dẫn: '%s' Có vẻ có lỗi trong mã "
+"nguồn, hãy kiểm tra lại cú pháp."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Không thể tải script addon từ đường dẫn: '%s' Kiểu gốc không phải "
+"EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
@@ -2647,77 +2624,75 @@ msgstr "Chạy cảnh này"
#: editor/editor_node.cpp
msgid "Close Tab"
-msgstr "Đóng Tab"
+msgstr "Đóng Cửa sổ"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Undo Close Tab"
-msgstr "Đóng Tab"
+msgstr "Hoàn tác đóng cửa sổ"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
-msgstr "Đóng tất cả Tab khác"
+msgstr "Đóng các cửa sổ khác"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr "Đóng các Tab bên phải"
+msgstr "Đóng các cửa sổ bên phải"
#: editor/editor_node.cpp
msgid "Close All Tabs"
-msgstr "Đóng tất cả"
+msgstr "Đóng hết cửa sổ"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
-msgstr "Chuyển Tab cảnh"
+msgstr "Chuyển Cửa sổ cảnh"
#: editor/editor_node.cpp
msgid "%d more files or folders"
-msgstr "%d thêm các tệp hoặc thư mục."
+msgstr "%d tệp hoặc thư mục nữa"
#: editor/editor_node.cpp
msgid "%d more folders"
-msgstr "%d thêm các thư mục"
+msgstr "%d thư mục nữa"
#: editor/editor_node.cpp
msgid "%d more files"
-msgstr "%d thêm các tệp tin"
+msgstr "%d tệp tin nữa"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr "Vị trí Dock"
+msgstr "Vị trí Khung"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
-msgstr ""
+msgstr "Chế độ tập trung"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr ""
+msgstr "Bật tắt chế độ tập trung."
#: editor/editor_node.cpp
msgid "Add a new scene."
-msgstr "Thêm một cảnh mới."
+msgstr "Thêm cảnh mới."
#: editor/editor_node.cpp
msgid "Scene"
-msgstr "Phân cảnh"
+msgstr "Cảnh"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
msgstr "Trở về cảnh đã mở trước đó."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Copy Text"
-msgstr "Sao chép đường dẫn"
+msgstr "Sao chép văn bản"
#: editor/editor_node.cpp
msgid "Next tab"
-msgstr "Tab tiếp theo"
+msgstr "Cửa sổ tiếp theo"
#: editor/editor_node.cpp
msgid "Previous tab"
-msgstr "Tab trước"
+msgstr "Cửa sổ trước"
#: editor/editor_node.cpp
msgid "Filter Files..."
@@ -2749,19 +2724,19 @@ msgstr "Lưu Cảnh"
#: editor/editor_node.cpp
msgid "Save All Scenes"
-msgstr "Lưu tất cả Cảnh"
+msgstr "Lưu hết các Cảnh"
#: editor/editor_node.cpp
msgid "Convert To..."
-msgstr "Chuyển đổi ..."
+msgstr "Chuyển thành..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr ""
+msgstr "MeshLibrary..."
#: editor/editor_node.cpp
msgid "TileSet..."
-msgstr ""
+msgstr "TileSet..."
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
@@ -2775,7 +2750,7 @@ msgstr "Làm lại"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
-msgstr "Linh tinh dự án hoặc công cụ toàn phân cảnh."
+msgstr "Dự án ngoài lề hoặc các công cụ toàn phân cảnh."
#: editor/editor_node.cpp editor/project_manager.cpp
#: editor/script_create_dialog.cpp
@@ -2784,30 +2759,27 @@ msgstr "Dự Án"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr "Cài đặt Dự Án"
+msgstr "Cài đặt Dự Án..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Version Control"
-msgstr "Phiên bản:"
+msgstr "Theo dõi phiên bản"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Cài đặt trình điều khiển phiên bản"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "Tắt trình điều khiển phiên bản"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Export..."
-msgstr "Xuất ra"
+msgstr "Xuất..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install Android Build Template..."
-msgstr "Cài đặt mẫu xây dựng Android"
+msgstr "Cài đặt mẫu xây dựng Android..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2867,13 +2839,15 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr ""
+msgstr "Các khối va chạm thấy được"
#: editor/editor_node.cpp
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
+"Khi bật tùy chọn này, các khối va chạm và nút chiếu tia (2D và 3D) sẽ được "
+"hiển thị trong dự án đang chạy."
#: editor/editor_node.cpp
msgid "Visible Navigation"
@@ -2884,10 +2858,12 @@ msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
+"Khi bật tùy chọn này, các lưới/đa giác điều hướng sẽ hiển thị trong dự án "
+"đang chạy."
#: editor/editor_node.cpp
msgid "Synchronize Scene Changes"
-msgstr ""
+msgstr "Đồng bộ hóa các thay đổi lên Cảnh"
#: editor/editor_node.cpp
msgid ""
@@ -2899,7 +2875,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
-msgstr ""
+msgstr "Đồng bộ hóa thay đổi trong Tệp lệnh"
#: editor/editor_node.cpp
msgid ""
@@ -2914,9 +2890,8 @@ msgid "Editor"
msgstr "Editor (trình biên tập)"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Editor Settings..."
-msgstr "Cài đặt Trình biên tập"
+msgstr "Cài đặt Trình biên tập..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -2924,12 +2899,12 @@ msgstr "Cài đặt Bố cục"
#: editor/editor_node.cpp
msgid "Take Screenshot"
-msgstr ""
+msgstr "Chụp màn hình"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Screenshots are stored in the Editor Data/Settings Folder."
-msgstr "Mở thư mục dữ liệu Trình biên tập"
+msgstr ""
+"Ảnh chụp màn hình được lưu ở thư mục Dữ liệu/Cài đặt của trình biên tập."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
@@ -2946,16 +2921,15 @@ msgstr "Mở thư mục dữ liệu Trình biên tập"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr ""
+msgstr "Mở thư mục dữ liệu Trình biên tập"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr ""
+msgstr "Mở thư mục Thiết lập Trình biên tập"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Editor Features..."
-msgstr "Quản lý tính năng Trình biên tập"
+msgstr "Quản lý tính năng Trình biên tập..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2966,14 +2940,6 @@ msgid "Help"
msgstr "Trợ giúp"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "Tìm kiếm"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "Tài liệu trực tuyến"
@@ -2983,13 +2949,12 @@ msgid "Q&A"
msgstr "Hỏi và Đáp"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Report a Bug"
-msgstr "Nhập vào lại"
+msgstr "Báo lỗi"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "Gửi ý kiến phản hồi về hướng dẫn"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -2997,7 +2962,7 @@ msgstr "Cộng đồng"
#: editor/editor_node.cpp
msgid "About"
-msgstr "Thông tin chúng tôi"
+msgstr "Về chúng tôi"
#: editor/editor_node.cpp
msgid "Play the project."
@@ -3009,7 +2974,7 @@ msgstr "Chạy"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
-msgstr ""
+msgstr "Dừng chạy Cảnh để gỡ lỗi."
#: editor/editor_node.cpp
msgid "Pause Scene"
@@ -3037,7 +3002,7 @@ msgstr "Chạy Cảnh Tuỳ Chọn"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr "Thay đổi trình điều kiển Video, yêu cầu khởi động lại Trình biên tập."
+msgstr "Thay đổi trình điều khiển Video cần phải khởi động lại Trình biên tập."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
@@ -3046,25 +3011,23 @@ msgstr "Lưu & Khởi động lại"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr ""
+msgstr "Xoay khi cửa sổ trình biên soạn được vẽ lại."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
-msgstr "Liên tục"
+msgstr "Cập nhật Liên tục"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Update When Changed"
-msgstr "Đối số đã thay đổi"
+msgstr "Cập nhật khi có thay đổi"
#: editor/editor_node.cpp
msgid "Hide Update Spinner"
-msgstr ""
+msgstr "Ẩn cái xoay xoay cập nhật"
#: editor/editor_node.cpp
msgid "FileSystem"
-msgstr ""
+msgstr "Hệ thống tệp tin"
#: editor/editor_node.cpp
msgid "Inspector"
@@ -3072,7 +3035,7 @@ msgstr "Quan Sát Viên"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
-msgstr "Mở rộng bảng điều khiển phía dưới"
+msgstr "Mở rộng bảng điều khiển dưới"
#: editor/editor_node.cpp
msgid "Output"
@@ -3101,7 +3064,7 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
-"Điều này sẽ thiết lập dự án của bạn cho các bản dựng Android tùy chỉnh bằng "
+"Việc này sẽ thiết lập dự án của bạn cho các bản dựng Android tùy chỉnh bằng "
"cách cài đặt nguồn mẫu thành \"res://android/build\".\n"
"Bạn có thể áp dụng các sửa đổi và xây dựng APK tùy chỉnh khi xuất (thêm các "
"mô-đun, thay đổi AndroidManifest.xml, ...).\n"
@@ -3133,13 +3096,31 @@ msgstr "Xuất thư viện ra"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr ""
+msgstr "Hợp nhất với Hiện có"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
msgstr "Mở & Chạy mã lệnh"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"Các tệp sau xuất hiện trên ổ cứng gần đây hơn.\n"
+"Bạn muốn làm gì đây?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "Tải lại"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "Lưu lại"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "Kế thừa mới"
@@ -3161,7 +3142,7 @@ msgstr "Mở Trình biên tập 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "Mở Trình biên tập Mã lệnh"
+msgstr "Mở Trình biên soạn Mã lệnh"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3169,41 +3150,39 @@ msgstr "Mở Thư viện Nguyên liệu"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn tiếp theo"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn trước đó"
#: editor/editor_node.h
-#, fuzzy
msgid "Warning!"
-msgstr "Cảnh báo"
+msgstr "Cảnh báo!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
-msgstr ""
+msgstr "Không tìm thấy tài nguyên phụ."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
-msgstr ""
+msgstr "Tạo bản xem trước lưới"
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
-msgstr ""
+msgstr "Ảnh thu nhỏ..."
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Main Script:"
-msgstr "Tạo Script"
+msgstr "Mã lệnh chính:"
#: editor/editor_plugin_settings.cpp
msgid "Edit Plugin"
-msgstr ""
+msgstr "Chỉnh sửa Tiện ích"
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr ""
+msgstr "Các Tiện ích đã cài:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
@@ -3232,23 +3211,23 @@ msgstr "Đo đạc:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr ""
+msgstr "Thời gian khung hình (giây)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
-msgstr ""
+msgstr "Thời gian trung bình (giây)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Khung hình %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr ""
+msgstr "Khung hình Vật lý %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr ""
+msgstr "Bao gồm"
#: editor/editor_profiler.cpp
msgid "Self"
@@ -3256,32 +3235,31 @@ msgstr ""
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Khung hình #:"
#: editor/editor_profiler.cpp
msgid "Time"
-msgstr ""
+msgstr "Thời gian"
#: editor/editor_profiler.cpp
msgid "Calls"
msgstr ""
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Edit Text:"
-msgstr "Lưu Theme"
+msgstr "Sửa văn bản:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
-msgstr ""
+msgstr "Bật"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Lớp"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
-msgstr ""
+msgstr "Bit %d, giá trị %d"
#: editor/editor_properties.cpp
msgid "[Empty]"
@@ -3289,24 +3267,26 @@ msgstr "[Rỗng]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr ""
+msgstr "Gán..."
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Invalid RID"
-msgstr "Đường dẫn sai."
+msgstr "Số RID không hợp lệ"
#: editor/editor_properties.cpp
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
msgstr ""
+"Kiểu của tài nguyên đã chọn (%s) không dùng được cho thuộc tính này (%s)."
#: editor/editor_properties.cpp
msgid ""
"Can't create a ViewportTexture on resources saved as a file.\n"
"Resource needs to belong to a scene."
msgstr ""
+"Không thể tạo ViewportTexture trên các tài nguyên được lưu dưới dạng tệp.\n"
+"Tài nguyên phải thuộc về một cảnh."
#: editor/editor_properties.cpp
msgid ""
@@ -3318,7 +3298,7 @@ msgstr ""
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Pick a Viewport"
-msgstr ""
+msgstr "Chọn cổng xem"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New Script"
@@ -3347,17 +3327,17 @@ msgstr "Duy nhất"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "Dán"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Convert To %s"
-msgstr ""
+msgstr "Chuyển thành %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Selected node is not a Viewport!"
-msgstr ""
+msgstr "Nút được chọn không phải Cổng xem!"
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
@@ -3397,27 +3377,27 @@ msgstr "Ghi logic của bạn trong hàm _run()."
#: editor/editor_run_script.cpp
msgid "There is an edited scene already."
-msgstr ""
+msgstr "Đã có một cảnh được chỉnh sửa."
#: editor/editor_run_script.cpp
msgid "Couldn't instance script:"
-msgstr ""
+msgstr "Không thể tạo tệp lệnh:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr ""
+msgstr "Bạn quên từ khóa 'tool' à?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
-msgstr ""
+msgstr "Không thể chạy tệp lệnh:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr ""
+msgstr "Bạn quên phương thức '_run' à?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
-msgstr ""
+msgstr "Giữ Ctrl để làm tròn về số nguyên. Giữ Shift để sửa tỉ mỉ hơn."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3466,8 +3446,9 @@ msgid "(Current)"
msgstr "(Hiện tại)"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Retrieving mirrors, please wait..."
-msgstr ""
+msgstr "Đang tìm các trang mirror, đợi xíu..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
@@ -3495,21 +3476,24 @@ msgstr "Trích xuất các Mẫu xuất bản"
#: editor/export_template_manager.cpp
msgid "Importing:"
-msgstr ""
+msgstr "Đang Nhập:"
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
-msgstr ""
+msgstr "Có lỗi khi lấy các trang mirror."
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Error parsing JSON of mirror list. Please report this issue!"
-msgstr ""
+msgstr "Có lỗi khi phân tích JSON của danh sách trang mirror. Hãy báo cáo lỗi!"
#: editor/export_template_manager.cpp
msgid ""
"No download links found for this version. Direct download is only available "
"for official releases."
msgstr ""
+"Không tìm thấy liên kết để tải phiên bản này. Chỉ có thể tải trực tiếp các "
+"bản chính thức."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3557,13 +3541,12 @@ msgstr ""
"Các lưu trữ mẫu xuất bản có vấn đề có thể được tìm thấy tại '%s'."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error requesting URL:"
-msgstr "Lỗi khi yêu cầu đường dẫn: "
+msgstr "Lỗi khi yêu cầu đường dẫn:"
#: editor/export_template_manager.cpp
msgid "Connecting to Mirror..."
-msgstr ""
+msgstr "Đang kết nối tới trang Mirror..."
#: editor/export_template_manager.cpp
msgid "Disconnected"
@@ -3609,7 +3592,7 @@ msgstr "Lỗi SSL Handshake"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr ""
+msgstr "Giải nén nguồn xây dựng Android"
#: editor/export_template_manager.cpp
msgid "Current Version:"
@@ -3638,24 +3621,30 @@ msgstr "Các mẫu xuất bản Godot"
#: editor/export_template_manager.cpp
msgid "Export Template Manager"
-msgstr ""
+msgstr "Trình quản lý Mẫu Xuất"
#: editor/export_template_manager.cpp
msgid "Download Templates"
msgstr "Tải Xuống Các Mẫu Xuất Bản"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr ""
+msgstr "Chọn trang mirror từ danh sách: (Shift+Nhấp: Mở trong trình duyệt)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Favorites"
-msgstr "Ưa thích:"
+msgstr "Ưa thích"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
+"Trạng thái: Nhập tệp thất bại. Hãy sửa tệp rồi nhập lại theo cách thủ công."
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3702,6 +3691,11 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"Các tệp hoặc thư mục sau xung đột với các mục ở vị trí đích '%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Bạn có muốn ghi đè không?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3757,9 +3751,8 @@ msgid "Move To..."
msgstr "Di chuyển đến..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
-msgstr "Tạo Cảnh Mới"
+msgstr "Tạo Cảnh Mới..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
@@ -3957,7 +3950,7 @@ msgstr "Các nút trong Nhóm"
#: editor/groups_editor.cpp
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Các nhóm trống sẽ tự động bị xóa."
#: editor/groups_editor.cpp
#, fuzzy
@@ -4011,11 +4004,11 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import Scene"
-msgstr ""
+msgstr "Nhập cảnh"
#: editor/import/resource_importer_scene.cpp
msgid "Importing Scene..."
-msgstr ""
+msgstr "Đang nhập cảnh ..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
@@ -4023,36 +4016,54 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
-msgstr ""
+msgstr "Tạo cho lưới: "
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
-msgstr ""
+msgstr "Chạy Tệp lệnh Tự chọn ..."
#: editor/import/resource_importer_scene.cpp
msgid "Couldn't load post-import script:"
-msgstr ""
+msgstr "Không thể tải tệp lệnh sau nhập:"
#: editor/import/resource_importer_scene.cpp
msgid "Invalid/broken script for post-import (check console):"
-msgstr ""
+msgstr "Tập lệnh sau nhập không hợp lệ/hỏng (hãy xem bảng điều khiển):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr ""
+msgstr "Lỗi khi chạy tập lệnh sau nhập:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Bạn có trả về một vật kế thừa Nút trong phương thức 'post_import' không đấy?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
msgstr "Đang lưu ..."
-#: editor/import_dock.cpp
+#: editor/import_defaults_editor.cpp
#, fuzzy
+msgid "Select Importer"
+msgstr "Chế độ chọn"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "Công cụ nhập:"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "Nạp mặc định"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Giữ tệp (Không Nhập)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
-msgstr " Tệp tin"
+msgstr "%d Tệp"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
@@ -4067,31 +4078,31 @@ msgid "Import As:"
msgstr "Nhập vào với:"
#: editor/import_dock.cpp
-#, fuzzy
msgid "Preset"
-msgstr "Cài sẵn ..."
+msgstr "Cài sẵn"
#: editor/import_dock.cpp
msgid "Reimport"
msgstr "Nhập vào lại"
#: editor/import_dock.cpp
-#, fuzzy
msgid "Save Scenes, Re-Import, and Restart"
-msgstr "Lưu các cảnh, nhập vào lại và khởi động lại"
+msgstr "Lưu các cảnh, nhập lại, rồi tái khởi động"
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
-msgstr ""
+msgstr "Sửa kiểu của tệp đã nhập yêu cầu khởi động lại trình biên soạn."
#: editor/import_dock.cpp
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
+"CẢNH BÁO: Có tài nguyên khác sử dụng tài nguyên này, chúng có thể gặp trục "
+"trặc khi nạp đấy."
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
-msgstr ""
+msgstr "Nạp tài nguyên thất bại."
#: editor/inspector_dock.cpp
msgid "Expand All Properties"
@@ -4124,7 +4135,7 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
-msgstr ""
+msgstr "Biến tài nguyên phụ thành độc nhất"
#: editor/inspector_dock.cpp
msgid "Open in Help"
@@ -4132,11 +4143,11 @@ msgstr "Mở trong Trợ giúp"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr ""
+msgstr "Tạo tài nguyên mới trong bộ nhớ rồi chỉnh sửa."
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
-msgstr ""
+msgstr "Tải tài nguyên có sẵn trong đĩa rồi chỉnh sửa."
#: editor/inspector_dock.cpp
msgid "Save the currently edited resource."
@@ -4144,15 +4155,15 @@ msgstr "Lưu tài nguyên đã chỉnh sửa hiện tại."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
-msgstr ""
+msgstr "Đi tới đối tượng mới chỉnh sửa trước đó trong lịch sử."
#: editor/inspector_dock.cpp
msgid "Go to the next edited object in history."
-msgstr ""
+msgstr "Đi đến đối tượng được chỉnh sửa liền sau trong lịch sử."
#: editor/inspector_dock.cpp
msgid "History of recently edited objects."
-msgstr ""
+msgstr "Lịch sử các đối tượng được chỉnh sửa gần đây."
#: editor/inspector_dock.cpp
msgid "Object properties."
@@ -4176,16 +4187,15 @@ msgstr "Chọn nút duy nhất để chỉnh sửa tính hiệu và nhóm của
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Chỉnh Tiện ích"
#: editor/plugin_config_dialog.cpp
-#, fuzzy
msgid "Create a Plugin"
-msgstr "Tạo & Sửa"
+msgstr "Tạo Tiện ích"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Tên Tiện ích:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
@@ -4243,7 +4253,7 @@ msgstr "Sửa Polygon (Gỡ điểm)"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Remove Polygon And Point"
-msgstr ""
+msgstr "Xóa đa giác và điểm"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4266,14 +4276,12 @@ msgid "Move Node Point"
msgstr "Di chuyển điểm Nút"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Limits"
-msgstr "Đổi Thời gian Chuyển Animation"
+msgstr "Thay đổi giới hạn BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Labels"
-msgstr "Đổi Thời gian Chuyển Animation"
+msgstr "Thay đổi nhãn BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4293,7 +4301,7 @@ msgstr "Thêm điểm Hoạt ảnh"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
-msgstr ""
+msgstr "Xóa điểm BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Move BlendSpace1D Node Point"
@@ -4321,7 +4329,7 @@ msgstr ""
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr "Kích hoạt Snap và hiện Grid."
+msgstr "Bật Dính và hiện lưới."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4332,7 +4340,7 @@ msgstr "Điểm"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4361,7 +4369,7 @@ msgstr "Đổi Thời gian Chuyển Animation"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Point"
-msgstr ""
+msgstr "Xóa điểm BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#, fuzzy
@@ -4383,11 +4391,11 @@ msgstr "Bật tắt Ưa thích"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create triangles by connecting points."
-msgstr ""
+msgstr "Nối các điểm để tạo tam giác."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Erase points and triangles."
-msgstr ""
+msgstr "Xóa tam giác và các điểm."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Generate blend triangles automatically (instead of manually)"
@@ -4473,19 +4481,16 @@ msgstr ""
"Trính phát hoạt ảnh không có đường dẫn nút Gốc, không thể truy xuất tên."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Anim Clips"
-msgstr "Âm thanh:"
+msgstr "Các đoạn hoạt ảnh"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Audio Clips"
-msgstr "Âm thanh:"
+msgstr "Các đoạn âm thanh"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Functions"
-msgstr "Hàm:"
+msgstr "Hàm"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
@@ -4623,7 +4628,7 @@ msgstr "Chỉnh sửa Chuyển tiếp ..."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Open in Inspector"
-msgstr ""
+msgstr "Mở trong Trình kiểm tra"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
@@ -4718,9 +4723,8 @@ msgid "Move Node"
msgstr "Di chuyển Nút"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Chuyển tiếp: "
+msgstr "Chuyển tiếp đã tồn tại!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
@@ -4981,23 +4985,20 @@ msgid "Request failed, return code:"
msgstr "Yêu cầu thất bại, trả lại code:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed."
msgstr "Yêu cầu thất bại."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Cannot save response to:"
-msgstr "Không thể gỡ bỏ:"
+msgstr "Không thể lưu phản hồi tới:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr ""
+msgstr "Ghi bị lỗi."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed, too many redirects"
-msgstr "Yêu cầu thất bại, gửi lại quá nhiều"
+msgstr "Yêu cầu thất bại, chuyển hướng quá nhiều"
#: editor/plugins/asset_library_editor_plugin.cpp
#, fuzzy
@@ -5005,14 +5006,12 @@ msgid "Redirect loop."
msgstr "Chuyển hướng vòng lặp."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed, timeout"
-msgstr "Yêu cầu thất bại, trả lại code:"
+msgstr "Yêu cầu thất bại, quá thời gian chờ"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Timeout."
-msgstr "Thời gian:"
+msgstr "Quá giờ."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
@@ -5027,8 +5026,8 @@ msgid "Got:"
msgstr "Nhận được:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
-msgstr ""
+msgid "Failed SHA-256 hash check"
+msgstr "Kiểm tra băm SHA-256 thất bại"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5055,9 +5054,8 @@ msgid "Idle"
msgstr "Chạy không"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Install..."
-msgstr "Cài đặt"
+msgstr "Cài đặt..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Retry"
@@ -5073,29 +5071,27 @@ msgstr "Tải xuống nguyên liệu này đã được tiến hành!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr ""
+msgstr "Cập nhật gần đây"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr ""
+msgstr "Lâu chưa cập nhật nhất"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Tên (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Tên (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (A-Z)"
-msgstr "Cấp phép"
+msgstr "Giấy phép (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (Z-A)"
-msgstr "Cấp phép"
+msgstr "Giấy phép (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "First"
@@ -5119,34 +5115,31 @@ msgstr "Tất cả"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No results for \"%s\"."
-msgstr ""
+msgstr "Không tìm thấy kết quả cho \"%s\"."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Import..."
-msgstr "Nhập vào"
+msgstr "Nhập..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Tiện ích..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
msgstr "Sắp xếp:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "Danh mục:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr ""
+msgstr "Trang:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Support"
-msgstr "Hỗ trợ ..."
+msgstr "Hỗ trợ"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
@@ -5157,9 +5150,8 @@ msgid "Testing"
msgstr "Kiểm tra"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Loading..."
-msgstr "Nạp ..."
+msgstr "Đang tải..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
@@ -5203,7 +5195,7 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Chọn file template"
+msgstr "Chọn tệp bake lightmap:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5212,24 +5204,23 @@ msgstr "Xem thử"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr "Cấu hình Snap"
+msgstr "Cài đặt Dính"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr ""
+msgstr "Độ lệch lưới:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr ""
+msgstr "Bước lưới:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
-msgstr ""
+msgstr "Đường kẻ chính Mỗi:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "steps"
-msgstr "2 bước"
+msgstr "bước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
@@ -5237,98 +5228,85 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr ""
+msgstr "Bước xoay:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale Step:"
-msgstr "Tỷ lệ:"
+msgstr "Bước thu phóng:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
-msgstr ""
+msgstr "Di chuyển đường căn dọc"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Vertical Guide"
-msgstr "Tạo Folder"
+msgstr "Tạo đường căn dọc"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Vertical Guide"
-msgstr "Xoá Variable"
+msgstr "Xoá đường căn dọc"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Horizontal Guide"
-msgstr ""
+msgstr "Di chuyển đường căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal Guide"
-msgstr "Tạo đường Guide ngang"
+msgstr "Tạo đường căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Horizontal Guide"
-msgstr "Hủy key không đúng chuẩn"
+msgstr "Xóa đường căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal and Vertical Guides"
-msgstr ""
+msgstr "Tạo đường căn ngang và dọc"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Đặt độ dời của CanvasItem \"%s\" tới (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Xoay CanvasItem"
+msgstr "Xoay %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Xoay CanvasItem"
+msgstr "Xoay CanvasItem \"%s\" thành %d độ"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển neo CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Thu phóng Node2D \"%s\" thành (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Chỉnh kích cỡ Nút Điều khiển \"%s\" thành (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Tỉ lệ CanvasItem"
+msgstr "Thu phóng %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Tỉ lệ CanvasItem"
+msgstr "Thu phóng CanvasItem \"%s\" thành (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển CanvasItem \"%s\" tới (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Children of containers have their anchors and margins values overridden by "
"their parent."
-msgstr ""
-"Mục con trong thùng chứa có giá trị neo và lề của chúng được ghi đè bởi cha "
-"chúng."
+msgstr "Các nút Container sẽ ép các nút con theo neo và lề mà nó xác định."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Presets for the anchors and margins values of a Control node."
@@ -5339,28 +5317,28 @@ msgid ""
"When active, moving Control nodes changes their anchors instead of their "
"margins."
msgstr ""
-"Khi hoạt động, các nút Control di chuyển thay đổi các neo thay vì lề của "
-"chúng."
+"Khi bật, di chuyển các nút Control sẽ thay đổi neo thay vì lề của chúng."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Left"
-msgstr ""
+msgstr "Góc trên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Right"
-msgstr ""
+msgstr "Góc trên phải"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Right"
-msgstr ""
+msgstr "Góc dưới phải"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Left"
-msgstr ""
+msgstr "Góc dưới trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Center Left"
-msgstr ""
+msgstr "Trung tâm Bên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
@@ -5406,16 +5384,15 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
-msgstr ""
+msgstr "Rộng hết cỡ"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Keep Ratio"
-msgstr "Tỉ lệ Scale:"
+msgstr "Giữ Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
-msgstr "Chỉ các neo"
+msgstr "Chỉ neo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors and Margins"
@@ -5464,9 +5441,8 @@ msgid "Paste Pose"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Guides"
-msgstr "Xoá khung xương"
+msgstr "Xóa hết đường căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Custom Bone(s) from Node(s)"
@@ -5489,6 +5465,8 @@ msgid ""
"Warning: Children of a container get their position and size determined only "
"by their parent."
msgstr ""
+"Cảnh báo: Nút Container đã xác định kích cỡ và vị trí cho các nút con của nó "
+"rồi."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -5515,7 +5493,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+RMB: Depth list selection"
-msgstr ""
+msgstr "Alt+chuột phải: Chọn theo tầng"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5530,7 +5508,7 @@ msgstr "Chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr "Chế độ Tỉ lệ"
+msgstr "Chế độ căn Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5547,7 +5525,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan Mode"
-msgstr ""
+msgstr "Chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5556,95 +5534,92 @@ msgstr "Chế độ Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr ""
+msgstr "Bật tắt Dính thông minh."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Smart Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính thông minh"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr ""
+msgstr "Bật tắt Dính lưới."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Grid Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr ""
+msgstr "Tùy chọn Dính"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr ""
+msgstr "Dùng Dính ở chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Scale Snap"
-msgstr "Sử dụng Snap"
+msgstr "Dính theo bước tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr ""
+msgstr "Dính tương đối"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr ""
+msgstr "Dính điểm ảnh"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr ""
+msgstr "Dính thông minh"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr ""
+msgstr "Cài đặt Dính..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
-msgstr ""
+msgstr "Dính về nút Mẹ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Anchor"
-msgstr "Snap đến neo của Nút"
+msgstr "Dính nút vào điểm neo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Sides"
-msgstr "Snap sang hai bên nút"
+msgstr "Dính vào các cạnh của Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Center"
-msgstr "Snap đến chính giữa nút"
+msgstr "Dính vào tâm Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Other Nodes"
-msgstr "Snap đế các nút khác"
+msgstr "Dính vào các Nút khác"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Guides"
-msgstr ""
+msgstr "Dính vào Đường căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock the selected object in place (can't be moved)."
-msgstr ""
+msgstr "Khóa vị trí vật (không cho dịch chuyển)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr ""
+msgstr "Thôi khóa vị trí vật (cho phép di chuyển)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Makes sure the object's children are not selectable."
-msgstr ""
+msgstr "Hãy chắc rằng nút con của vật ở trạng thái Không thể chọn."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Restores the object's children's ability to be selected."
-msgstr ""
+msgstr "Khôi phục khả năng được chọn nút con của vật."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Skeleton Options"
@@ -5652,7 +5627,7 @@ msgstr "Cài đặt Khung xương"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Bones"
-msgstr ""
+msgstr "Hiển thị Xương"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
@@ -5674,7 +5649,7 @@ msgstr "Hiện lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
-msgstr ""
+msgstr "Hiển thị trợ giúp"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
@@ -5682,19 +5657,19 @@ msgstr "Hiện thước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr ""
+msgstr "Hiện đường căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Origin"
-msgstr ""
+msgstr "Hiện Gốc"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Viewport"
-msgstr ""
+msgstr "Hiện Cổng xem"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
-msgstr ""
+msgstr "Hiện biểu tượng Nhóm và Khóa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
@@ -5702,7 +5677,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr ""
+msgstr "Lựa chọn khung hình"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
@@ -5723,7 +5698,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
msgid "Insert keys (based on mask)."
-msgstr "Chèn Key Anim"
+msgstr "Chèn Khóa (dựa trên mask)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5749,7 +5724,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Copy Pose"
-msgstr ""
+msgstr "Sao chép Tư thế"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
@@ -5757,11 +5732,11 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr ""
+msgstr "Gấp đôi bước lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr ""
+msgstr "Chia đôi bước lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -5787,7 +5762,7 @@ msgstr "Tạo Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Error instancing scene from %s"
-msgstr ""
+msgstr "Lỗi khởi tạo cảnh từ %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Default Type"
@@ -5815,7 +5790,7 @@ msgstr "Sửa Poly (Xoá điểm)"
#: editor/plugins/collision_shape_2d_editor_plugin.cpp
msgid "Set Handle"
-msgstr ""
+msgstr "Đặt tay nắm"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5826,9 +5801,8 @@ msgstr ""
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
-#, fuzzy
msgid "Restart"
-msgstr "Restart ngay"
+msgstr "Khởi động lại"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5839,7 +5813,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Particles"
-msgstr ""
+msgstr "Hạt"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5854,12 +5828,12 @@ msgstr ""
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Solid Pixels"
-msgstr ""
+msgstr "Điểm ảnh rắn"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Border Pixels"
-msgstr ""
+msgstr "Điểm ảnh viền"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5900,12 +5874,13 @@ msgid "Flat 1"
msgstr ""
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+#, fuzzy
msgid "Ease In"
-msgstr ""
+msgstr "Trườn vào"
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
msgid "Ease Out"
-msgstr ""
+msgstr "Trườn ra"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Smoothstep"
@@ -5913,11 +5888,11 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Modify Curve Point"
-msgstr ""
+msgstr "Sửa điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Modify Curve Tangent"
-msgstr ""
+msgstr "Sửa tiếp tuyến điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Curve Preset"
@@ -5943,11 +5918,11 @@ msgstr "Tịnh tuyến"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Preset"
-msgstr ""
+msgstr "Nạp cài đặt trước"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Curve Point"
-msgstr ""
+msgstr "Xóa điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Toggle Curve Linear Tangent"
@@ -5955,12 +5930,11 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Hold Shift to edit tangents individually"
-msgstr ""
+msgstr "Giữ Shift để sửa từng tiếp tuyến một"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Right click to add point"
-msgstr "Nhấp chuột phải: Xóa Point"
+msgstr "Nhấp chuột phải để thêm điểm"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
@@ -5968,15 +5942,15 @@ msgstr ""
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
-msgstr ""
+msgstr "Dải màu đã được chỉnh sửa"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr ""
+msgstr "Mục %d"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
-msgstr ""
+msgstr "Mục"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
@@ -5988,7 +5962,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh is empty!"
-msgstr ""
+msgstr "Lưới trống!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a Trimesh collision shape."
@@ -6000,7 +5974,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "This doesn't work on scene root!"
-msgstr ""
+msgstr "Không thể áp dụng lên Cảnh gốc!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Shape"
@@ -6024,9 +5998,8 @@ msgid "Can't create multiple convex collision shapes for the scene root."
msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Couldn't create any collision shapes."
-msgstr "Không thể tạo folder."
+msgstr "Không thể tạo bất kì khối va chạm nào."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6035,7 +6008,7 @@ msgstr "Tạo hình dạng lồi"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Navigation Mesh"
-msgstr ""
+msgstr "Tạo lưới điều hướng"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Contained Mesh is not of type ArrayMesh."
@@ -6047,7 +6020,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "No mesh to debug."
-msgstr ""
+msgstr "Không có lưới để gỡ lỗi."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Model has no UV in this layer"
@@ -6055,7 +6028,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
-msgstr ""
+msgstr "MeshInstance thiếu lưới!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh has not surface to create outlines from!"
@@ -6067,15 +6040,15 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Could not create outline!"
-msgstr ""
+msgstr "Không thể tạo đường viền!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline"
-msgstr ""
+msgstr "Tạo đường viền"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh"
-msgstr ""
+msgstr "Lưới"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Body"
@@ -6087,6 +6060,8 @@ msgid ""
"automatically.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Tạo một StaticBody rồi tự động gắn một khối va chạm hình đa giác.\n"
+"Đây là tùy chọn phát hiện va chạm chính xác (nhưng chậm) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Collision Sibling"
@@ -6097,6 +6072,8 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Tạo một khối va chạm đa giác.\n"
+"Đây là cách phát hiện va chạm chính xác (nhưng chậm) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6108,6 +6085,8 @@ msgid ""
"Creates a single convex collision shape.\n"
"This is the fastest (but least accurate) option for collision detection."
msgstr ""
+"Tạo một khối va chạm lồi.\n"
+"Đây là cách phát hiện va chạm nhanh (nhưng ẩu) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6119,10 +6098,12 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between the two above options."
msgstr ""
+"Tạo một khối va chạm đa giác.\n"
+"Đây là tùy chọn có hiệu suất cân bằng so với hai tùy chọn trên."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
-msgstr ""
+msgstr "Tạo lưới viền..."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6146,11 +6127,11 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh"
-msgstr ""
+msgstr "Tạo lưới viền"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Outline Size:"
-msgstr ""
+msgstr "Kích cỡ viền:"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "UV Channel Debug"
@@ -6158,35 +6139,36 @@ msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove item %d?"
-msgstr ""
+msgstr "Xóa mục %d?"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid ""
"Update from existing scene?:\n"
"%s"
msgstr ""
+"Cập nhật từ cảnh hiện có?:\n"
+"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Mesh Library"
-msgstr "Xuất Mesh Library"
+msgstr "Thư viện Lưới"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Item"
-msgstr ""
+msgstr "Thêm mục"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove Selected Item"
-msgstr ""
+msgstr "Xóa mục đã chọn"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import from Scene"
-msgstr ""
+msgstr "Nhập từ Cảnh"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Update from Scene"
-msgstr ""
+msgstr "Cập nhật từ Cảnh"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No mesh source specified (and no MultiMesh set in node)."
@@ -6199,15 +6181,15 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (invalid path)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (đường dẫn không hợp lệ)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (not a MeshInstance)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (không phải MeshInstance)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (contains no Mesh resource)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (không chứa tài nguyên Lưới)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No surface source specified."
@@ -6227,11 +6209,11 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Source Mesh:"
-msgstr ""
+msgstr "Chọn một lưới nguồn:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Target Surface:"
-msgstr ""
+msgstr "Chọn Bề mặt tác động:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate Surface"
@@ -6247,7 +6229,7 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Source Mesh:"
-msgstr ""
+msgstr "Lưới nguồn:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "X-Axis"
@@ -6267,15 +6249,15 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Rotation:"
-msgstr ""
+msgstr "Xoay ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Tilt:"
-msgstr ""
+msgstr "Nghiêng ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Scale:"
-msgstr ""
+msgstr "Thu phóng ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate"
@@ -6289,7 +6271,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Convert to CPUParticles"
-msgstr ""
+msgstr "Chuyển thành CPUParticles"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generating Visibility Rect"
@@ -6304,14 +6286,13 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Xóa Animation"
+msgstr "Chuyển thành CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Generation Time (sec):"
-msgstr ""
+msgstr "Thời gian tạo (giây):"
#: editor/plugins/particles_editor_plugin.cpp
msgid "The geometry's faces don't contain any area."
@@ -6324,7 +6305,7 @@ msgstr "Cảnh không chứa tệp lệnh."
#: editor/plugins/particles_editor_plugin.cpp
msgid "\"%s\" doesn't inherit from Spatial."
-msgstr ""
+msgstr "\"%s\" không kế thừa từ Spatial."
#: editor/plugins/particles_editor_plugin.cpp
msgid "\"%s\" doesn't contain geometry."
@@ -6372,7 +6353,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Remove Point from Curve"
-msgstr ""
+msgstr "Xóa điểm khỏi đường cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Remove Out-Control from Curve"
@@ -6385,7 +6366,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Add Point to Curve"
-msgstr ""
+msgstr "Thêm Điểm vào Đường cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Split Curve"
@@ -6393,7 +6374,7 @@ msgstr "Chia đường Curve"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Move Point in Curve"
-msgstr ""
+msgstr "Di chuyển Điểm trên Đường cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Move In-Control in Curve"
@@ -6420,7 +6401,7 @@ msgstr "Nhấp: Tạo Point"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Left Click: Split Segment (in curve)"
-msgstr ""
+msgstr "Chuột trái: Phân tách các đoạn (trong đường cong)"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6434,7 +6415,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Add Point (in empty space)"
-msgstr ""
+msgstr "Thêm điểm (trong không gian trống)"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6444,31 +6425,33 @@ msgstr "Xóa Point"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Close Curve"
-msgstr ""
+msgstr "Đóng đường cong"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
msgid "Options"
-msgstr ""
+msgstr "Tùy chọn"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
+#, fuzzy
msgid "Mirror Handle Angles"
-msgstr ""
+msgstr "Đối xứng góc tay cầm"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
+#, fuzzy
msgid "Mirror Handle Lengths"
-msgstr ""
+msgstr "Đối xứng độ dài tay cầm"
#: editor/plugins/path_editor_plugin.cpp
msgid "Curve Point #"
-msgstr ""
+msgstr "Điểm uốn #"
#: editor/plugins/path_editor_plugin.cpp
msgid "Set Curve Point Position"
-msgstr ""
+msgstr "Đặt vị trí điểm uốn"
#: editor/plugins/path_editor_plugin.cpp
msgid "Set Curve In Position"
@@ -6480,7 +6463,7 @@ msgstr ""
#: editor/plugins/path_editor_plugin.cpp
msgid "Split Path"
-msgstr ""
+msgstr "Tách đường"
#: editor/plugins/path_editor_plugin.cpp
msgid "Remove Path Point"
@@ -6496,12 +6479,11 @@ msgstr ""
#: editor/plugins/path_editor_plugin.cpp
msgid "Split Segment (in curve)"
-msgstr ""
+msgstr "Phân tách đoạn (trong đường cong)"
#: editor/plugins/physical_bone_plugin.cpp
-#, fuzzy
msgid "Move Joint"
-msgstr "Di chuyển đến..."
+msgstr "Di chuyển Khớp"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
@@ -6510,7 +6492,7 @@ msgstr "Thuộc tính xương của nút Polygon2D không trỏ đến nút Skel
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Sync Bones"
-msgstr ""
+msgstr "Đồng bộ Xương"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
@@ -6523,10 +6505,12 @@ msgid "Create UV Map"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
+#, fuzzy
msgid ""
"Polygon 2D has internal vertices, so it can no longer be edited in the "
"viewport."
msgstr ""
+"Đa giác 2D có đỉnh nằm trong, vì vậy không thể chỉnh sửa trong cổng xem."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
@@ -6542,26 +6526,23 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Invalid Polygon (need 3 different vertices)"
-msgstr ""
+msgstr "Đa giác không hợp lệ (cần 3 đỉnh khác nhau)"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Add Custom Polygon"
-msgstr "Tạo"
+msgstr "Thêm Đa giác Tùy chỉnh"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Polygon"
-msgstr "Xóa Animation"
+msgstr "Xóa Đa giác Tùy chỉnh"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Transform UV Map"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Transform Polygon"
-msgstr "Tạo"
+msgstr "Biến đổi đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Paint Bone Weights"
@@ -6580,56 +6561,52 @@ msgid "UV"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Points"
-msgstr "Di chuyển đến..."
+msgstr "Các Điểm"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Polygons"
-msgstr "Tạo"
+msgstr "Đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Bones"
-msgstr ""
+msgstr "Xương"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Move Points"
-msgstr "Di chuyển đến..."
+msgstr "Di chuyển các điểm"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Kéo: Xoay"
+msgstr "Nút Command: Xoay"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
-msgstr ""
+msgstr "Shift: Di chuyển tất"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Command: Scale"
-msgstr ""
+msgstr "Shift+Command: Thu phóng"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
-msgstr ""
+msgstr "Ctrl: Xoay"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Ctrl: Scale"
-msgstr ""
+msgstr "Shift+Ctrl: Thu phóng"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Move Polygon"
-msgstr ""
+msgstr "Di chuyển đa g"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Rotate Polygon"
-msgstr ""
+msgstr "Xoay đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Scale Polygon"
-msgstr ""
+msgstr "Thu phóng đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create a custom polygon. Enables custom polygon rendering."
@@ -6651,7 +6628,7 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Radius:"
-msgstr ""
+msgstr "Bán kính:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Copy Polygon to UV"
@@ -6668,19 +6645,19 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Settings"
-msgstr ""
+msgstr "Thiết lập lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr ""
+msgstr "Dính"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr ""
+msgstr "Bật Dính"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr ""
+msgstr "Lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
@@ -6688,52 +6665,52 @@ msgstr "Hiện lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Configure Grid:"
-msgstr ""
+msgstr "Cài đặt Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
-msgstr ""
+msgstr "Độ lệch X của Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset Y:"
-msgstr ""
+msgstr "Độ lệch Y của Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step X:"
-msgstr ""
+msgstr "Bước Lưới trục X:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step Y:"
-msgstr ""
+msgstr "Bước Lưới trục Y:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Sync Bones to Polygon"
-msgstr ""
+msgstr "Đồng bộ Xương với Đa giác"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
-msgstr ""
+msgstr "LỖI: Không thể nạp tài nguyên!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Add Resource"
-msgstr ""
+msgstr "Thêm tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Rename Resource"
-msgstr ""
+msgstr "Đổi tên tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Resource"
-msgstr ""
+msgstr "Xóa tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Resource clipboard is empty!"
-msgstr ""
+msgstr "Khay nhớ tạm Tài nguyên trống!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Paste Resource"
-msgstr ""
+msgstr "Dán tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_editor.cpp
@@ -6745,16 +6722,16 @@ msgstr ""
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "Kiểu:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
msgid "Open in Editor"
-msgstr ""
+msgstr "Mở trong Trình biên soạn"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Load Resource"
-msgstr ""
+msgstr "Nạp tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ResourcePreloader"
@@ -6762,72 +6739,63 @@ msgstr ""
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
-msgstr ""
+msgstr "AnimationTree chưa đặt đường dẫn đến AnimationPlayer nào"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "Path to AnimationPlayer is invalid"
-msgstr ""
+msgstr "Đường dẫn tới AnimationPlayer không hợp lệ"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Files"
-msgstr ""
+msgstr "Xóa lịch sử Tệp gần đây"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close and save changes?"
-msgstr ""
+msgstr "Đóng và lưu thay đổi?"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error writing TextFile:"
-msgstr ""
+msgstr "Lỗi viết TextFile:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Could not load file at:"
-msgstr "Không viết được file:"
+msgstr "Không tải được tệp tại:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error saving file!"
-msgstr "Lỗi tải font."
+msgstr "Lỗi lưu tệp!"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error while saving theme."
-msgstr "Lỗi khi lưu scene."
+msgstr "Lỗi khi lưu Tông màu."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Saving"
-msgstr "Lỗi di chuyển:"
+msgstr "Lỗi Khi Lưu"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error importing theme."
-msgstr "Lỗi khi lưu scene."
+msgstr "Lỗi khi nhập Tông màu."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Importing"
-msgstr "Lỗi di chuyển:"
+msgstr "Lỗi Khi Nhập"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "New Text File..."
-msgstr "Thư mục mới ..."
+msgstr "Tệp văn bản mới..."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open File"
-msgstr "Mở"
+msgstr "Mở tệp"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Save File As..."
-msgstr "Lưu Scene với tên..."
+msgstr "Lưu Cảnh thành..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Can't obtain the script for running."
-msgstr ""
+msgstr "Không thể lấy tệp lệnh để chạy."
#: editor/plugins/script_editor_plugin.cpp
msgid "Script failed reloading, check console for errors."
@@ -6844,51 +6812,49 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme"
-msgstr ""
+msgstr "Nhập Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme"
-msgstr ""
+msgstr "Lỗi khi lưu Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving"
-msgstr ""
+msgstr "Lỗi khi lưu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
-msgstr ""
+msgstr "Lưu Tông màu thành..."
#: editor/plugins/script_editor_plugin.cpp
msgid "%s Class Reference"
-msgstr ""
+msgstr "Tham khảo Lớp %s"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Next"
-msgstr "Tìm tiếp theo"
+msgstr "Tìm tiếp"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr ""
+msgstr "Tìm trước đó"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Filter scripts"
-msgstr "Lọc các thuộc tính"
+msgstr "Lọc tệp lệnh"
#: editor/plugins/script_editor_plugin.cpp
msgid "Toggle alphabetical sorting of the method list."
-msgstr ""
+msgstr "Bật/tắt sắp xếp danh sách phương thức theo bảng chữ cái."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Filter methods"
-msgstr "Lọc các nút"
+msgstr "Lọc phương thức"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort"
-msgstr ""
+msgstr "Sắp xếp"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
@@ -6904,29 +6870,27 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Next script"
-msgstr ""
+msgstr "Tệp lệnh tiếp theo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Previous script"
-msgstr ""
+msgstr "Tệp lệnh trước đó"
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
-msgstr ""
+msgstr "Tệp"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open..."
-msgstr "Mở"
+msgstr "Mở..."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Reopen Closed Script"
-msgstr "Tạo Script"
+msgstr "Mở lại tệp lệnh đã đóng"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr ""
+msgstr "Lưu tất cả"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -6934,7 +6898,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Copy Script Path"
-msgstr ""
+msgstr "Sao chép đường dẫn tệp lệnh"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -6948,19 +6912,19 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme"
-msgstr ""
+msgstr "Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme..."
-msgstr ""
+msgstr "Nhập Tông màu..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
-msgstr ""
+msgstr "Tải lại Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme"
-msgstr "Lưu Theme"
+msgstr "Lưu Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close All"
@@ -6974,6 +6938,14 @@ msgstr "Đóng Docs"
msgid "Run"
msgstr "Chạy"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "Tìm kiếm"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -6993,27 +6965,27 @@ msgstr "Tiếp tục"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
-msgstr ""
+msgstr "Giữ Trình gỡ lỗi mở"
#: editor/plugins/script_editor_plugin.cpp
msgid "Debug with External Editor"
-msgstr ""
+msgstr "Gỡ lỗi bằng Trình chỉnh sửa bên ngoài"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr ""
+msgstr "Mở tài liệu Godot trực tuyến."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr ""
+msgstr "Tìm tài liệu tham khảo."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
-msgstr ""
+msgstr "Tới tài liệu được chỉnh sửa trước đó."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to next edited document."
-msgstr ""
+msgstr "Tới tài liệu được chỉnh sửa tiếp theo."
#: editor/plugins/script_editor_plugin.cpp
msgid "Discard"
@@ -7024,30 +6996,20 @@ msgid ""
"The following files are newer on disk.\n"
"What action should be taken?:"
msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
+"Các tệp sau đây mới hơn trên ổ cứng.\n"
+"Hãy chọn hành động của bạn:"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
-msgstr ""
+msgstr "Trình gỡ lỗi"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Search Results"
-msgstr "Tìm sự giúp đỡ"
+msgstr "Kết quả tìm kiếm"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Clear Recent Scripts"
-msgstr "Dọn các cảnh gần đây"
+msgstr "Dọn các tệp lệnh gần đây"
#: editor/plugins/script_text_editor.cpp
msgid "Connections to method:"
@@ -7055,7 +7017,7 @@ msgstr "Kết nối đến phương thức:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
msgid "Source"
-msgstr ""
+msgstr "Nguồn"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
@@ -7069,17 +7031,15 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
-msgstr ""
+msgstr "[Bỏ qua]"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Line"
-msgstr "Dòng:"
+msgstr "Dòng"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Thêm Hàm"
+msgstr "Đi tới Hàm"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7100,15 +7060,15 @@ msgstr "Chọn màu"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Convert Case"
-msgstr ""
+msgstr "Chuyển đổi Hoa thường"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr ""
+msgstr "Chữ hoa"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr ""
+msgstr "Chữ thường"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
@@ -7116,25 +7076,24 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
-msgstr ""
+msgstr "Nổi màu cú pháp"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Bookmarks"
-msgstr ""
+msgstr "Dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Breakpoints"
-msgstr "Tạo các điểm."
+msgstr "Điểm dừng"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Go To"
-msgstr ""
+msgstr "Đi tới"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "Cắt"
@@ -7145,39 +7104,40 @@ msgstr "Chọn Toàn Bộ"
#: editor/plugins/script_text_editor.cpp
msgid "Delete Line"
-msgstr ""
+msgstr "Xóa dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
-msgstr ""
+msgstr "Thụt lề Trái"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Right"
-msgstr ""
+msgstr "Thụt lề phải"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr ""
+msgstr "Bật/tắt chú thích"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr ""
+msgstr "Cuộn/Trải dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
-msgstr ""
+msgstr "Cuộn tất cả các dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Unfold All Lines"
-msgstr ""
+msgstr "Trải tất cả các dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
msgstr ""
#: editor/plugins/script_text_editor.cpp
+#, fuzzy
msgid "Complete Symbol"
-msgstr ""
+msgstr "Hoàn thiện kí hiệu"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7186,128 +7146,120 @@ msgstr "Chọn Scale"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr ""
+msgstr "Xóa khoảng trắng cuối dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
-msgstr ""
+msgstr "Chuyển thụt lề thành Dấu cách"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Tabs"
-msgstr ""
+msgstr "Chuyển thụt lề thành Tab"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
-msgstr ""
+msgstr "Thụt lề Tự động"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Find in Files..."
-msgstr "Tìm..."
+msgstr "Tìm trong Tệp..."
#: editor/plugins/script_text_editor.cpp
msgid "Contextual Help"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Toggle Bookmark"
-msgstr "Bật tắt Chức năng"
+msgstr "Bật tắt Dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Bookmark"
-msgstr "Đến Step tiếp theo"
+msgstr "Đến Dấu trang tiếp theo"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Bookmark"
-msgstr "Đến Step trước đó"
+msgstr "Đến Dấu trang trước đó"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Bookmarks"
-msgstr ""
+msgstr "Xóa hết mọi dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function..."
-msgstr "Xoá Function"
+msgstr "Đi tới Hàm..."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Line..."
-msgstr "Đến Dòng"
+msgstr "Đến Dòng..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Toggle Breakpoint"
-msgstr ""
+msgstr "Tạo điểm dừng"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
-msgstr ""
+msgstr "Xóa hết mọi điểm dừng"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Breakpoint"
-msgstr "Đến Step tiếp theo"
+msgstr "Đến điểm dừng tiếp theo"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Breakpoint"
-msgstr "Đến Step trước đó"
+msgstr "Đến điểm dừng trước đó"
#: editor/plugins/shader_editor_plugin.cpp
msgid ""
"This shader has been modified on on disk.\n"
"What action should be taken?"
msgstr ""
+"Shader này đã bị chỉnh sửa trên bộ nhớ.\n"
+"Hành động nào nên được thực hiện?"
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
-msgstr ""
+msgstr "Shader"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "Bộ xương không có xương, tạo một số nút Bone2D."
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Create Rest Pose from Bones"
-msgstr "Tạo từ Scene"
+msgstr "Tạo tư thế nghỉ từ Xương"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Rest Pose to Bones"
-msgstr ""
+msgstr "Đặt tư thế nghỉ cho Xương"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Skeleton2D"
-msgstr ""
+msgstr "Skeleton2D"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Make Rest Pose (From Bones)"
-msgstr ""
+msgstr "Tạo tư thế nghỉ (Từ Xương)"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Bones to Rest Pose"
-msgstr ""
+msgstr "Đặt Xương thành Tư thế Nghỉ"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical bones"
-msgstr ""
+msgstr "Tạo xương vật lý"
#: editor/plugins/skeleton_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton"
-msgstr "Xóa Point"
+msgstr "Khung xương"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical skeleton"
-msgstr ""
+msgstr "Tạo khung xương vật lý"
#: editor/plugins/skeleton_ik_editor_plugin.cpp
msgid "Play IK"
-msgstr ""
+msgstr "Chạy IK"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
@@ -7319,19 +7271,19 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
-msgstr ""
+msgstr "Hủy Biến đổi."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "X-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục X."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Y-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục Y."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Z-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục Z."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Plane Transform."
@@ -7347,7 +7299,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
-msgstr ""
+msgstr "Xoay %s độ."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Keying is disabled (no key inserted)."
@@ -7355,7 +7307,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Animation Key Inserted."
-msgstr ""
+msgstr "Đã chèn khóa hoạt ảnh."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pitch"
@@ -7366,9 +7318,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Kích thước: "
+msgstr "Kích cỡ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7392,7 +7343,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Vertices"
-msgstr ""
+msgstr "Đỉnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -7448,7 +7399,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "No parent to instance a child at."
-msgstr ""
+msgstr "Không có nút mẹ để khởi tạo nút con."
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "This operation requires a single selected node."
@@ -7460,7 +7411,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock View Rotation"
-msgstr ""
+msgstr "Khóa xoay ở chế độ xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Normal"
@@ -7488,19 +7439,20 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Information"
-msgstr ""
+msgstr "Xem thông tin"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View FPS"
-msgstr ""
+msgstr "Xem tốc độ khung hình"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Half Resolution"
-msgstr ""
+msgstr "Nửa độ phân giải"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Audio Listener"
-msgstr ""
+msgstr "Trình nghe âm thanh"
#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
@@ -7513,7 +7465,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Not available when using the GLES2 renderer."
-msgstr ""
+msgstr "Không khả dụng khi sử dụng trình kết xuất GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
@@ -7549,6 +7501,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
+msgstr "Đã khóa xoay ở chế độ xem"
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7556,6 +7513,8 @@ msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
+"Lưu ý: Tốc độ khung hình được hiển thị là của trình biên soạn.\n"
+"Đừng lấy đó làm mốc để đánh giá hiệu suất."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -7571,8 +7530,9 @@ msgid ""
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Snap Nodes To Floor"
-msgstr "Snap các nút đến Floor"
+msgstr "Dính Nút lên Sàn"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Couldn't find a solid floor to snap the selection to."
@@ -7584,38 +7544,41 @@ msgid ""
"Alt+Drag: Move\n"
"Alt+RMB: Depth list selection"
msgstr ""
+"Kéo: Xoay\n"
+"Alt+Kéo: Di chuyển\n"
+"Alt+Chuột phải: Chọn theo tầng"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr ""
+msgstr "Sử dụng Không gian Cục bộ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
-msgstr ""
+msgstr "Góc nhìn đáy"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View"
-msgstr ""
+msgstr "Góc nhìn đỉnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View"
-msgstr ""
+msgstr "Góc nhìn lưng"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View"
-msgstr ""
+msgstr "Góc nhìn trực diện"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View"
-msgstr ""
+msgstr "Góc nhìn trái"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right View"
-msgstr ""
+msgstr "Góc nhìn phải"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
@@ -7623,7 +7586,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
-msgstr ""
+msgstr "Chèn khóa Hoạt ảnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
@@ -7640,23 +7603,23 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform"
-msgstr ""
+msgstr "Biến đổi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr ""
+msgstr "Dính Vật lên Sàn"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
-msgstr ""
+msgstr "Hộp thoại Biến đổi ..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr ""
+msgstr "1 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr ""
+msgstr "2 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
@@ -7664,7 +7627,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr ""
+msgstr "3 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
@@ -7672,7 +7635,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr ""
+msgstr "4 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -7684,17 +7647,16 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Grid"
-msgstr ""
+msgstr "Xem Lưới"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Settings..."
-msgstr "Đang kết nối..."
+msgstr "Cài đặt..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
-msgstr ""
+msgstr "Thiết lập Dính"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate Snap:"
@@ -7702,15 +7664,15 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Snap (deg.):"
-msgstr ""
+msgstr "Dính theo Bước xoay (độ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Snap (%):"
-msgstr ""
+msgstr "Thu Phóng Dính (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
-msgstr ""
+msgstr "Cài đặt Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective FOV (deg.):"
@@ -7734,70 +7696,63 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate (deg.):"
-msgstr ""
+msgstr "Xoay (theo độ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale (ratio):"
-msgstr ""
+msgstr "Thu phóng (theo tỉ lệ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Type"
-msgstr ""
+msgstr "Kiểu biến đổi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pre"
-msgstr ""
+msgstr "Trước"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Post"
-msgstr ""
+msgstr "Sau"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Nameless gizmo"
msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create Mesh2D"
-msgstr "Tạo %s Mới"
+msgstr "Tạo Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Mesh2D Preview"
-msgstr "Xem thử"
+msgstr "Xem trước Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create Polygon2D"
-msgstr "Tạo"
+msgstr "Tạo Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Polygon2D Preview"
-msgstr ""
+msgstr "Xem trước Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create CollisionPolygon2D"
-msgstr "Tạo"
+msgstr "Tạo CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "CollisionPolygon2D Preview"
-msgstr "Tạo"
+msgstr "Xem trước CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create LightOccluder2D"
-msgstr "Tạo Folder"
+msgstr "Tạo LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "LightOccluder2D Preview"
-msgstr "Tạo Folder"
+msgstr "Xem trước LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite is empty!"
-msgstr ""
+msgstr "Sprite trống!"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Can't convert a sprite using animation frames to mesh."
@@ -7809,16 +7764,15 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Mesh2D"
-msgstr ""
+msgstr "Chuyển thành Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Convert to Polygon2D"
-msgstr "Xóa Animation"
+msgstr "Chuyển thành Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
@@ -7839,15 +7793,15 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
-msgstr ""
+msgstr "Sprite"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
-msgstr ""
+msgstr "Đơn giản hóa: "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Shrink (Pixels): "
-msgstr ""
+msgstr "Thu nhỏ (Điểm ảnh): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Grow (Pixels): "
@@ -7855,131 +7809,123 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
-msgstr ""
+msgstr "Cập nhật bản xem trước"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Settings:"
-msgstr ""
+msgstr "Cài đặt:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "No Frames Selected"
-msgstr "Xoá lựa chọn"
+msgstr "Chưa chọn khung hình nào"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr ""
+msgstr "Thêm %d Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
-msgstr ""
+msgstr "Thêm Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
-msgstr ""
+msgstr "Không tải được hình ảnh"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
-msgstr ""
+msgstr "LỖI: Không thể nạp khung hình!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
-msgstr ""
+msgstr "Khay nhớ tạm tài nguyên bị trống hoặc không chứa họa tiết!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
-msgstr ""
+msgstr "Dán Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Empty"
-msgstr ""
+msgstr "Thêm Rỗng"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation FPS"
-msgstr ""
+msgstr "Thay đổi tốc độ hoạt ảnh"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "(empty)"
-msgstr ""
+msgstr "(trống)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Move Frame"
-msgstr "Di chuyển Nút"
+msgstr "Di chuyển Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animations:"
-msgstr "Các Công cụ Animation"
+msgstr "Các hoạt ảnh:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "New Animation"
-msgstr "Tạo Animation mới"
+msgstr "Tạo Hoạt ảnh mới"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
-msgstr ""
+msgstr "Tốc độ:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
-msgstr ""
+msgstr "Lặp"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animation Frames:"
-msgstr "Tên Animation:"
+msgstr "Khung hình Hoạt ảnh:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Add a Texture from File"
-msgstr "Chèn Texture(s) vào TileSet"
+msgstr "Thêm Họa tiết từ tệp"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
-msgstr ""
+msgstr "Thêm Khung hình từ Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (Before)"
-msgstr ""
+msgstr "Chèn Rỗng (Trước)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (After)"
-msgstr ""
+msgstr "Chèn Rỗng (Sau)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (Before)"
-msgstr ""
+msgstr "Di chuyển (Trước)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (After)"
-msgstr ""
+msgstr "Di chuyển (Sau)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Select Frames"
-msgstr "Chọn Points"
+msgstr "Chọn Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
-msgstr ""
+msgstr "Ngang:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Vertical:"
-msgstr ""
+msgstr "Dọc:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
-msgstr ""
+msgstr "Chọn/Xóa Tất cả Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Create Frames from Sprite Sheet"
-msgstr "Tạo từ Scene"
+msgstr "Tạo Khung hình từ Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "SpriteFrames"
-msgstr ""
+msgstr "SpriteFrames"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Set Region Rect"
@@ -7987,11 +7933,11 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Set Margin"
-msgstr ""
+msgstr "Đặt Lề"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr ""
+msgstr "Chế độ Dính:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
@@ -8000,11 +7946,11 @@ msgstr "Không có"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr ""
+msgstr "Dính Điểm ảnh"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr ""
+msgstr "Dính lưới"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -8012,11 +7958,11 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr ""
+msgstr "Độ dời:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
-msgstr ""
+msgstr "Bước:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Sep.:"
@@ -8024,52 +7970,51 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "TextureRegion"
-msgstr ""
+msgstr "TextureRegion"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All Items"
-msgstr ""
+msgstr "Thêm tất cả các mục"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All"
-msgstr ""
+msgstr "Thêm Tất cả"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
-msgstr ""
+msgstr "Xóa tất cả các mục"
#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
msgid "Remove All"
-msgstr ""
+msgstr "Xoá tất cả"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Theme"
-msgstr "Lưu Theme"
+msgstr "Chỉnh Tông màu"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme editing menu."
-msgstr ""
+msgstr "Menu chỉnh Tông màu."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Class Items"
-msgstr ""
+msgstr "Thêm mục Lớp"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr ""
+msgstr "Xóa mục Lớp"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
-msgstr ""
+msgstr "Tạo Mẫu Trống"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Editor Template"
-msgstr ""
+msgstr "Tạo mẫu Trình biên tập trống"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create From Current Editor Theme"
-msgstr ""
+msgstr "Tạo từ Tông màu Trình biên soạn hiện tại"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8083,20 +8028,19 @@ msgstr "Tắt"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Item"
-msgstr ""
+msgstr "Mục"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Disabled Item"
-msgstr "Tắt"
+msgstr "Các mục tắt"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Check Item"
-msgstr ""
+msgstr "Đánh dấu mục"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Checked Item"
-msgstr ""
+msgstr "Mục đã đánh dấu"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Radio Item"
@@ -8112,23 +8056,23 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Submenu"
-msgstr ""
+msgstr "Menu phụ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 1"
-msgstr ""
+msgstr "Mục phụ 1"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 2"
-msgstr ""
+msgstr "Mục phụ 2"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has"
-msgstr ""
+msgstr "Có"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Many"
-msgstr ""
+msgstr "Nhiều"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8148,13 +8092,12 @@ msgid "Tab 3"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editable Item"
-msgstr "Chỉnh Thời gian Chuyển Animation"
+msgstr "Mục có thể chỉnh sửa"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subtree"
-msgstr ""
+msgstr "Cây con"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has,Many,Options"
@@ -8162,12 +8105,12 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
-msgstr ""
+msgstr "Kiểu Dữ liệu:"
#: editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Icon"
-msgstr ""
+msgstr "Biểu tượng"
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Style"
@@ -8175,38 +8118,36 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Font"
-msgstr ""
+msgstr "Phông chữ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Color"
-msgstr ""
+msgstr "Màu"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme File"
-msgstr "Mở"
+msgstr "Tệp Tông màu"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
-msgstr ""
+msgstr "Xóa Lựa chọn"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Fix Invalid Tiles"
-msgstr ""
+msgstr "Sửa các ô không hợp lệ"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Nhân đôi lựa chọn"
+msgstr "Cắt lựa chọn"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
-msgstr ""
+msgstr "Tô TileMap"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Line Draw"
-msgstr ""
+msgstr "Vẽ đường"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rectangle Paint"
@@ -8218,16 +8159,15 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase TileMap"
-msgstr ""
+msgstr "Xóa TileMap"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Find Tile"
-msgstr "Tìm tiếp theo"
+msgstr "Tìm Ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr ""
+msgstr "Chuyển vị"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
@@ -8238,17 +8178,17 @@ msgid "Enable Priority"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter tiles"
-msgstr "Lọc tệp tin ..."
+msgstr "Lọc ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Give a TileSet resource to this TileMap to use its tiles."
msgstr ""
+"Hãy cung cấp tài nguyên TileSet cho TileMap này để sử dụng các ô của nó."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint Tile"
-msgstr ""
+msgstr "Tô ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8264,38 +8204,35 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Pick Tile"
-msgstr ""
+msgstr "Chọn ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rotate Left"
-msgstr ""
+msgstr "Xoay Trái"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rotate Right"
-msgstr ""
+msgstr "Xoay Phải"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Horizontally"
-msgstr ""
+msgstr "Lật Ngang"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Vertically"
-msgstr ""
+msgstr "Lật Dọc"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "Đổi Transform Animation"
+msgstr "Xóa biến đổi"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Add Texture(s) to TileSet."
-msgstr "Chèn Texture(s) vào TileSet"
+msgstr "Thêm Họa tiết vào TileSet."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected Texture from TileSet."
-msgstr "Xóa Texture hiện tại từ TileSet"
+msgstr "Xóa Họa tiết hiện tại khỏi TileSet."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8307,7 +8244,7 @@ msgstr "Gộp từ Scene"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "New Single Tile"
-msgstr ""
+msgstr "Tạo Ô mới"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8315,22 +8252,20 @@ msgid "New Autotile"
msgstr "Hoạt ảnh mới"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Atlas"
-msgstr "Mới %s"
+msgstr "Tập bản đồ mới"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Next Coordinate"
-msgstr ""
+msgstr "Tọa độ tiếp theo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the next shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Previous Coordinate"
-msgstr "Thư mục trước"
+msgstr "Tọa độ trước"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the previous shape, subtile, or Tile."
@@ -8341,9 +8276,8 @@ msgid "Region"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision"
-msgstr "Tạo"
+msgstr "Va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8352,11 +8286,11 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr ""
+msgstr "Điều hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
-msgstr ""
+msgstr "Bitmask"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
@@ -8371,9 +8305,8 @@ msgid "Region Mode"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision Mode"
-msgstr "Tạo"
+msgstr "Chế độ va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8382,11 +8315,11 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation Mode"
-msgstr "Chế độ Navigation"
+msgstr "Chế độ di chuyển"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask Mode"
-msgstr ""
+msgstr "Chế độ Bitmask"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority Mode"
@@ -8403,40 +8336,35 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
-msgstr ""
+msgstr "Sao chép bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste bitmask."
-msgstr "Dán Animation"
+msgstr "Dán bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
-msgstr ""
+msgstr "Xóa bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new rectangle."
msgstr "Tạo hình chữ nhật mới."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Tạo Cảnh Mới"
+msgstr "Hình chữ nhật mới"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new polygon."
-msgstr "Tạo"
+msgstr "Tạo đa giác mới."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Tạo"
+msgstr "Đa giác mới"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Xoá lựa chọn"
+msgstr "Xoá Hình được chọn"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8444,11 +8372,11 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
-msgstr ""
+msgstr "Bật Dính và hiện lưới (có thể cài đặt thông qua Trình kiểm tra)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
-msgstr ""
+msgstr "Hiển thị tên ô (Giữ phím Alt)"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8456,30 +8384,28 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected texture? This will remove all tiles which use it."
-msgstr "Xóa Texture hiện tại từ TileSet"
+msgstr "Xóa Họa tiết đã chọn? Các ô dùng họa tiết này cũng bốc hơi luôn đó."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "You haven't selected a texture to remove."
-msgstr ""
+msgstr "Bạn chưa chọn họa tiết để xóa."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from scene? This will overwrite all current tiles."
-msgstr ""
+msgstr "Tạo từ Cảnh? Việc này sẽ ghi đè lên tất cả các ô hiện tại."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Merge from scene?"
-msgstr ""
+msgstr "Hợp nhất từ cảnh?"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Texture"
-msgstr "Xóa Template"
+msgstr "Xóa Họa tiết"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "%s file(s) were not added because was already on the list."
-msgstr ""
+msgstr "%s tệp không được thêm vào vì đã có trong danh sách."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8499,9 +8425,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete polygon."
-msgstr "Tạo"
+msgstr "Xóa đa giác."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8535,23 +8460,20 @@ msgid "Set Tile Region"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create Tile"
-msgstr "Tạo Folder"
+msgstr "Tạo Ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Icon"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Tile Bitmask"
-msgstr "Chỉnh Thời gian Chuyển Animation"
+msgstr "Sửa bitmask của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Collision Polygon"
-msgstr "Tạo"
+msgstr "Chỉnh đa giác va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8559,68 +8481,60 @@ msgid "Edit Occlusion Polygon"
msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Navigation Polygon"
-msgstr "Tạo"
+msgstr "Chỉnh đa giác điều hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste Tile Bitmask"
-msgstr "Dán Animation"
+msgstr "Dán bitmask các ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Clear Tile Bitmask"
-msgstr ""
+msgstr "Xóa bitmask của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Make Polygon Concave"
-msgstr ""
+msgstr "Biến thành đa giác lõm"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Polygon Convex"
-msgstr "Tạo"
+msgstr "Làm Lồi Đa Giác"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Tile"
-msgstr "Xóa Template"
+msgstr "Xóa Ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Collision Polygon"
-msgstr ""
+msgstr "Xóa khối va chạm đa giác"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Occlusion Polygon"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Navigation Polygon"
-msgstr "Xóa Animation"
+msgstr "Xóa Đa Giác Điều Hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Tile Priority"
-msgstr ""
+msgstr "Chỉnh độ ưu tiên của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Tile Z Index"
-msgstr ""
+msgstr "Sửa chiều sâu (Z) của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Convex"
-msgstr "Tạo"
+msgstr "Làm Lồi"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Concave"
-msgstr "Tạo"
+msgstr "Làm Lõm"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create Collision Polygon"
-msgstr "Tạo"
+msgstr "Tạo đa giác va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8629,20 +8543,19 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "This property can't be changed."
-msgstr ""
+msgstr "Không thể thay đổi thuộc tính này."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "TileSet"
-msgstr "Xuất Tile Set"
+msgstr "TileSet"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No VCS addons are available."
-msgstr ""
+msgstr "Không có phần mềm kiểm soát phiên bản khả dụng."
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
-msgstr ""
+msgstr "Lỗi"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No files added to stage"
@@ -8659,11 +8572,11 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
-msgstr ""
+msgstr "Phần mềm kiểm soát phiên bản"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Initialize"
-msgstr ""
+msgstr "Khởi tạo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
@@ -8674,23 +8587,20 @@ msgid "Detect new changes"
msgstr "Phát hiện thay đổi mới"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Changes"
-msgstr "Đổi"
+msgstr "Những thay đổi"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
-msgstr ""
+msgstr "Đã sửa đổi"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Renamed"
-msgstr "Đổi tên"
+msgstr "Đã đổi tên"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Deleted"
-msgstr "Xóa"
+msgstr "Đã Xóa"
#: editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
@@ -8715,7 +8625,7 @@ msgstr "Đổi"
#: editor/plugins/version_control_editor_plugin.cpp
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Status"
-msgstr ""
+msgstr "Trạng thái"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
@@ -8731,66 +8641,59 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(GLES3 only)"
-msgstr ""
+msgstr "(Chỉ dành cho GLES3)"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Output"
-msgstr "Thêm Input"
+msgstr "Thêm Đầu Ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar"
-msgstr "Tỷ lệ:"
+msgstr "Tỷ lệ"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
-msgstr ""
+msgstr "Vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
-msgstr ""
+msgstr "Boolean"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sampler"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add input port"
-msgstr "Thêm Input"
+msgstr "Thêm Cổng vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add output port"
-msgstr ""
+msgstr "Thêm cổng đầu ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change input port type"
-msgstr "Đổi dạng mặc định"
+msgstr "Đổi kiểu cổng đầu vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change output port type"
-msgstr "Đổi dạng mặc định"
+msgstr "Đổi kiểu cổng ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change input port name"
-msgstr ""
+msgstr "Đổi tên cổng đầu vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change output port name"
-msgstr ""
+msgstr "Đổi tên cổng đầu ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Remove input port"
-msgstr "Xoá Function"
+msgstr "Xoá Cổng vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Remove output port"
-msgstr "Xóa Template"
+msgstr "Xóa Cổng ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -8807,16 +8710,15 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Set Input Default Port"
-msgstr ""
+msgstr "Đặt cổng đầu vào mặc định"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node to Visual Shader"
msgstr "Thêm nút vào Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Đã di chuyển Nút"
+msgstr "Nút đã di chuyển"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -8842,15 +8744,15 @@ msgstr "Đối số đã thay đổi"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
-msgstr ""
+msgstr "Đỉnh"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Fragment"
-msgstr ""
+msgstr "Mảnh"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Light"
-msgstr ""
+msgstr "Ánh sáng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Show resulted shader code."
@@ -8876,16 +8778,15 @@ msgstr "Tạo Function"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts HSV vector to RGB equivalent."
-msgstr ""
+msgstr "Chuyển đổi vector HSV sang RGB tương đương."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts RGB vector to HSV equivalent."
-msgstr ""
+msgstr "Chuyển đổi vector RGB sang HSV tương đương."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Sepia function."
-msgstr "Đổi tên Hàm"
+msgstr "Hàm Sepia."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Burn operator."
@@ -8936,19 +8837,19 @@ msgstr "Đổi Transform Animation"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
-msgstr ""
+msgstr "Trả về kết quả boolean của phép so sánh %s giữa hai tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Equal (==)"
-msgstr ""
+msgstr "Bằng (==)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Greater Than (>)"
-msgstr ""
+msgstr "Lớn hơn (>)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Greater Than or Equal (>=)"
-msgstr ""
+msgstr "Lớn hơn hoặc Bằng (>=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -8961,24 +8862,28 @@ msgid ""
"Returns the boolean result of the comparison between INF and a scalar "
"parameter."
msgstr ""
+"Trả về kết quả boolean của phép so sánh giữa Vô cùng (INF) và một tham số vô "
+"hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the boolean result of the comparison between NaN and a scalar "
"parameter."
msgstr ""
+"Trả về kết quả boolean so sánh giữa NaN (Không phải số) và một tham số vô "
+"hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Less Than (<)"
-msgstr ""
+msgstr "Nhỏ hơn (<)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Less Than or Equal (<=)"
-msgstr ""
+msgstr "Nhỏ hơn hoặc Bằng (<=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Not Equal (!=)"
-msgstr ""
+msgstr "Không bằng (!=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -8992,17 +8897,19 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the comparison between two parameters."
-msgstr ""
+msgstr "Trả về kết quả boolean so sánh giữa hai tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the boolean result of the comparison between INF (or NaN) and a "
"scalar parameter."
msgstr ""
+"Trả về kết quả boolean của phép so sánh giữa INF (hoặc NaN) và một tham số "
+"vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean constant."
-msgstr ""
+msgstr "Hằng số Boolean."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean uniform."
@@ -9014,7 +8921,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Input parameter."
-msgstr ""
+msgstr "Tham số đầu vào."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex and fragment shader modes."
@@ -9051,43 +8958,43 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "E constant (2.718282). Represents the base of the natural logarithm."
-msgstr ""
+msgstr "Hằng số E (2,718282). Cơ số của logarit tự nhiên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Epsilon constant (0.00001). Smallest possible scalar number."
-msgstr ""
+msgstr "Hằng số Epsilon (0,00001). Số vô hướng nhỏ nhất có thể."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Phi constant (1.618034). Golden ratio."
-msgstr ""
+msgstr "Hằng số Phi (1.618034). Tỷ lệ vàng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/4 constant (0.785398) or 45 degrees."
-msgstr ""
+msgstr "Hằng số Pi/4 (0,785398) hay còn là 45 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/2 constant (1.570796) or 90 degrees."
-msgstr ""
+msgstr "Hằng số Pi/2 (1.570796) hay còn là 90 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi constant (3.141593) or 180 degrees."
-msgstr ""
+msgstr "Hằng số Pi (3,141593) hay còn là 180 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Tau constant (6.283185) or 360 degrees."
-msgstr ""
+msgstr "Hằng số Tau (6,283185) hay còn là 360 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sqrt2 constant (1.414214). Square root of 2."
-msgstr ""
+msgstr "Hằng số Sqrt2 (1,414214). Căn bậc hai của 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the absolute value of the parameter."
-msgstr ""
+msgstr "Trả về giá trị tuyệt đối của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-cosine of the parameter."
-msgstr ""
+msgstr "Trả về arc-cosine của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic cosine of the parameter."
@@ -9095,7 +9002,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-sine of the parameter."
-msgstr ""
+msgstr "Trả về arc-sin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic sine of the parameter."
@@ -9103,11 +9010,11 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameter."
-msgstr ""
+msgstr "Trả về arc-tan của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameters."
-msgstr ""
+msgstr "Trả về arc-tan của các tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic tangent of the parameter."
@@ -9116,7 +9023,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần nhất lớn hơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Constrains a value to lie between two further values."
@@ -9124,7 +9031,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the cosine of the parameter."
-msgstr ""
+msgstr "Trả về cosine của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic cosine of the parameter."
@@ -9132,23 +9039,23 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in radians to degrees."
-msgstr ""
+msgstr "Đổi radian về độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-e Exponential."
-msgstr ""
+msgstr "Lũy thừa cơ số e."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 Exponential."
-msgstr ""
+msgstr "Lũy thừa cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần nhất nhỏ hơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Computes the fractional part of the argument."
-msgstr ""
+msgstr "Tính phần phân số của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse of the square root of the parameter."
@@ -9156,19 +9063,19 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Natural logarithm."
-msgstr ""
+msgstr "Logarit tự nhiên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 logarithm."
-msgstr ""
+msgstr "Logarit cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the greater of two values."
-msgstr ""
+msgstr "Trả về giá trị lớn hơn trong hai giá trị."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the lesser of two values."
-msgstr ""
+msgstr "Trả về giá trị nhỏ hơn trong hai giá trị."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two scalars."
@@ -9176,52 +9083,52 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the opposite value of the parameter."
-msgstr ""
+msgstr "Trả về giá trị đối của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 - scalar"
-msgstr ""
+msgstr "1.0 - vô hướng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the value of the first parameter raised to the power of the second."
-msgstr ""
+msgstr "Trả về lũy thừa cơ số tham số đầu tiên có số mũ tham số thứ hai."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in degrees to radians."
-msgstr ""
+msgstr "Đổi từ độ về radian."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / scalar"
-msgstr ""
+msgstr "1.0 / vô hướng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần tham số nhất."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest even integer to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên chẵn gần tham số nhất."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Clamps the value between 0.0 and 1.0."
-msgstr ""
+msgstr "Kẹp giá trị trong khoảng từ 0.0 đến 1.0."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Extracts the sign of the parameter."
-msgstr ""
+msgstr "Lấy tính âm/dương của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the sine of the parameter."
-msgstr ""
+msgstr "Trả về sin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic sine of the parameter."
-msgstr ""
+msgstr "Trả về sin hyperbolic của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the square root of the parameter."
-msgstr ""
+msgstr "Trả về căn bậc hai của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9241,11 +9148,11 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the tangent of the parameter."
-msgstr ""
+msgstr "Trả về tan của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr ""
+msgstr "Trả về tan hyperbolic của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
@@ -9253,27 +9160,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds scalar to scalar."
-msgstr ""
+msgstr "Cộng hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Divides scalar by scalar."
-msgstr ""
+msgstr "Chia hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies scalar by scalar."
-msgstr ""
+msgstr "Nhân hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the remainder of the two scalars."
-msgstr ""
+msgstr "Trả về phần dư của hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Subtracts scalar from scalar."
-msgstr ""
+msgstr "Trừ hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar constant."
-msgstr ""
+msgstr "Hằng số vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9303,7 +9210,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
msgid "Transform function."
-msgstr "Tạo"
+msgstr "Hàm biến hóa."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9315,39 +9222,44 @@ msgid ""
"whose number of rows is the number of components in 'c' and whose number of "
"columns is the number of components in 'r'."
msgstr ""
+"Tính tích ngoài của một cặp vector.\n"
+"\n"
+"Tích ngoài đặt tham số 'c' đầu tiên làm vector dọc (ma trận 1 cột) và tham "
+"số 'h' thứ hai là vector ngang (ma trận 1 hàng) rồi thực hiện phép nhân ma "
+"trận tuyến tính 'c * h', tạo ra ma trận có số hàng bằng số phần tử trong 'h' "
+"và số cột bằng số phần tử trong 'c'."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
-msgstr ""
+msgstr "Tạo phép biến đổi từ 4 vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Decomposes transform to four vectors."
-msgstr ""
+msgstr "Tách phép biến đổi thành 4 vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the determinant of a transform."
-msgstr ""
+msgstr "Tính định thức của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the inverse of a transform."
-msgstr ""
+msgstr "Tính nghịch đảo của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the transpose of a transform."
-msgstr ""
+msgstr "Tính chuyển vị của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies transform by transform."
-msgstr ""
+msgstr "Nhân hai phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by transform."
-msgstr ""
+msgstr "Nhân vector với phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform constant."
-msgstr "Tạo"
+msgstr "Hằng (số) Phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9355,9 +9267,8 @@ msgid "Transform uniform."
msgstr "Tạo"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Xoá Function"
+msgstr "Hàm Vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9365,23 +9276,23 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes vector from three scalars."
-msgstr ""
+msgstr "Tạo vector từ ba giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Decomposes vector to three scalars."
-msgstr ""
+msgstr "Tách vector thành ba giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr ""
+msgstr "Tính tích chéo của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
-msgstr ""
+msgstr "Trả về khoảng cách giữa hai điểm."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the dot product of two vectors."
-msgstr ""
+msgstr "Tính tích vô hướng của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9393,7 +9304,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the length of a vector."
-msgstr ""
+msgstr "Tính chiều dài vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two vectors."
@@ -9405,25 +9316,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the normalize product of vector."
-msgstr ""
+msgstr "Tính tích chuẩn hóa của vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 - vector"
-msgstr ""
+msgstr "1.0 - vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / vector"
-msgstr ""
+msgstr "1.0 / vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the vector that points in the direction of reflection ( a : incident "
"vector, b : normal vector )."
msgstr ""
+"Trả về vector chỉ hướng phản xạ ( a : vector tia tới, b : vector pháp "
+"tuyến )."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the vector that points in the direction of refraction."
-msgstr ""
+msgstr "Trả về vector chỉ hướng khúc xạ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9459,27 +9372,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds vector to vector."
-msgstr ""
+msgstr "Cộng vector với vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Divides vector by vector."
-msgstr ""
+msgstr "Chia vector cho vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by vector."
-msgstr ""
+msgstr "Nhân vector với vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the remainder of the two vectors."
-msgstr ""
+msgstr "Trả về phần dư của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Subtracts vector from vector."
-msgstr ""
+msgstr "Trừ vector cho vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector constant."
-msgstr ""
+msgstr "Hằng (số) vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector uniform."
@@ -9594,15 +9507,15 @@ msgstr ""
#: editor/project_export.cpp
msgid "Release"
-msgstr ""
+msgstr "Phát hành"
#: editor/project_export.cpp
msgid "Exporting All"
-msgstr ""
+msgstr "Xuất tất cả"
#: editor/project_export.cpp
msgid "The given export path doesn't exist:"
-msgstr ""
+msgstr "Đường dẫn xuất không tồn tại:"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing/corrupted:"
@@ -9614,7 +9527,7 @@ msgstr ""
#: editor/project_export.cpp editor/project_settings_editor.cpp
msgid "Add..."
-msgstr ""
+msgstr "Thêm..."
#: editor/project_export.cpp
msgid ""
@@ -9623,13 +9536,12 @@ msgid ""
msgstr ""
#: editor/project_export.cpp
-#, fuzzy
msgid "Export Path"
-msgstr "Xuất Tile Set"
+msgstr "Đường dẫn xuất"
#: editor/project_export.cpp
msgid "Resources"
-msgstr ""
+msgstr "Tài nguyên"
#: editor/project_export.cpp
msgid "Export all resources in the project"
@@ -9637,25 +9549,27 @@ msgstr "Xuất ra tất cả tài nguyên dùng trong dự án"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
-msgstr ""
+msgstr "Xuất các cảnh đã chọn (cùng các phần phụ thuộc)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr ""
+msgstr "Xuất tài nguyên đã chọn (cùng các phần phụ thuộc)"
#: editor/project_export.cpp
msgid "Export Mode:"
-msgstr ""
+msgstr "Chế độ xuất:"
#: editor/project_export.cpp
msgid "Resources to export:"
-msgstr ""
+msgstr "Tài nguyên để xuất:"
#: editor/project_export.cpp
msgid ""
"Filters to export non-resource files/folders\n"
"(comma-separated, e.g: *.json, *.txt, docs/*)"
msgstr ""
+"Lọc để xuất các tệp/thư mục không phải tài nguyên\n"
+"(phẩy-phân-cách, ví dụ: *.json, *.txt, docs/*)"
#: editor/project_export.cpp
msgid ""
@@ -9667,48 +9581,47 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Tính năng"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
-msgstr ""
+msgstr "Tùy chỉnh (dấu-phẩy-phân-cách):"
#: editor/project_export.cpp
msgid "Feature List:"
-msgstr ""
+msgstr "Danh sách tính năng:"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script"
-msgstr "Tạo Script"
+msgstr "Tệp lệnh"
#: editor/project_export.cpp
msgid "Script Export Mode:"
-msgstr "Chế độ xuất Script:"
+msgstr "Chế độ xuất tệp lệnh:"
#: editor/project_export.cpp
msgid "Text"
-msgstr ""
+msgstr "Văn bản"
#: editor/project_export.cpp
msgid "Compiled"
-msgstr ""
+msgstr "Đã biên dịch"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
-msgstr ""
+msgstr "Đã mã hóa (cung cấp mã mở bên dưới)"
#: editor/project_export.cpp
msgid "Invalid Encryption Key (must be 64 characters long)"
-msgstr ""
+msgstr "Mã mở không hợp lệ (phải dài 64 kí tự)"
#: editor/project_export.cpp
msgid "Script Encryption Key (256-bits as hex):"
-msgstr ""
+msgstr "Mã khóa tệp lệnh (256-bit theo hex):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
-msgstr ""
+msgstr "Xuất PCK/Zip"
#: editor/project_export.cpp
msgid "Export Project"
@@ -9719,18 +9632,16 @@ msgid "Export mode?"
msgstr "Chế độ xuất?"
#: editor/project_export.cpp
-#, fuzzy
msgid "Export All"
-msgstr "Xuất Tile Set"
+msgstr "Xuất tất cả"
#: editor/project_export.cpp editor/project_manager.cpp
-#, fuzzy
msgid "ZIP File"
-msgstr " Tệp tin"
+msgstr "Tệp ZIP"
#: editor/project_export.cpp
msgid "Godot Game Pack"
-msgstr ""
+msgstr "Gói trò chơi Godot"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing:"
@@ -9742,17 +9653,15 @@ msgstr "Quản Lý Các Mẫu Xuất Bản"
#: editor/project_export.cpp
msgid "Export With Debug"
-msgstr ""
+msgstr "Xuất cùng gỡ lỗi"
#: editor/project_manager.cpp
-#, fuzzy
msgid "The path specified doesn't exist."
-msgstr "Tệp không tồn tại."
+msgstr "Đường dẫn đã cho không tồn tại."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file (it's not in ZIP format)."
-msgstr "Lỗi không thể mở gói, không phải dạng nén."
+msgstr "Lỗi mở gói (không phải dạng ZIP)."
#: editor/project_manager.cpp
msgid ""
@@ -9762,7 +9671,7 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Please choose an empty folder."
-msgstr ""
+msgstr "Hãy chọn một thư mục trống."
#: editor/project_manager.cpp
msgid "Please choose a \"project.godot\" or \".zip\" file."
@@ -9786,11 +9695,11 @@ msgstr "Tên dự án không hợp lệ."
#: editor/project_manager.cpp
msgid "Couldn't create folder."
-msgstr ""
+msgstr "Không thể tạo thư mục."
#: editor/project_manager.cpp
msgid "There is already a folder in this path with the specified name."
-msgstr ""
+msgstr "Đã tồn tại một thư mục cùng tên trên đường dẫn này."
#: editor/project_manager.cpp
msgid "It would be a good idea to name your project."
@@ -9826,7 +9735,7 @@ msgstr "Nạp Dự án có sẵn"
#: editor/project_manager.cpp
msgid "Import & Edit"
-msgstr ""
+msgstr "Nhập & Chỉnh sửa"
#: editor/project_manager.cpp
msgid "Create New Project"
@@ -9842,7 +9751,7 @@ msgstr "Cài đặt Dự án:"
#: editor/project_manager.cpp
msgid "Install & Edit"
-msgstr ""
+msgstr "Cài đặt & Chỉnh sửa"
#: editor/project_manager.cpp
msgid "Project Name:"
@@ -9858,15 +9767,15 @@ msgstr "Đường dẫn cài đặt Dự án:"
#: editor/project_manager.cpp
msgid "Renderer:"
-msgstr ""
+msgstr "Trình kết xuất hình ảnh:"
#: editor/project_manager.cpp
msgid "OpenGL ES 3.0"
-msgstr ""
+msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "GPU driver của bạn không hỗ trợ."
#: editor/project_manager.cpp
msgid ""
@@ -9875,10 +9784,14 @@ msgid ""
"Incompatible with older hardware\n"
"Not recommended for web games"
msgstr ""
+"Chất lượng hình ảnh cao hơn\n"
+"Đầy đủ mọi tính năng\n"
+"Không tương thích với các dòng máy cũ\n"
+"Khuyến cáo đối với trò chơi trên web"
#: editor/project_manager.cpp
msgid "OpenGL ES 2.0"
-msgstr ""
+msgstr "OpenGL ES 2.0"
#: editor/project_manager.cpp
msgid ""
@@ -9887,10 +9800,15 @@ msgid ""
"Works on most hardware\n"
"Recommended for web games"
msgstr ""
+"Giảm chất lượng hình ảnh\n"
+"Không hỗ trợ một số tính năng\n"
+"Chạy trên đa số dòng máy\n"
+"Khuyên dùng cho trò chơi trên web"
#: editor/project_manager.cpp
msgid "Renderer can be changed later, but scenes may need to be adjusted."
msgstr ""
+"Trình kết xuất có thể đổi sau, nhưng có thể sẽ phải chỉnh lại các Cảnh."
#: editor/project_manager.cpp
msgid "Unnamed Project"
@@ -9956,8 +9874,8 @@ msgid ""
"The project settings were created by a newer engine version, whose settings "
"are not compatible with this version."
msgstr ""
-"Các cài đặt dự án đã được tạo bởi phiên bản Godot mới, có các cài đặt không "
-"tương thích với phiên bản này."
+"Các cài đặt dự án đã được tạo bởi phiên bản Godot mới và không tương thích "
+"với phiên bản này."
#: editor/project_manager.cpp
msgid ""
@@ -10031,8 +9949,12 @@ msgid "Projects"
msgstr "Dự án"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "Đang tải, đợi xíu..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
-msgstr ""
+msgstr "Sửa đổi lần cuối"
#: editor/project_manager.cpp
msgid "Scan"
@@ -10095,18 +10017,17 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
-msgstr ""
+msgstr "Nút chuột"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
-msgstr ""
+msgstr "Tên hành động không được trống hoặc chứa '/', ':', '=', '\\' hoặc '\"'"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "An action with the name '%s' already exists."
-msgstr "LỖI: Tên animation trùng lặp!"
+msgstr "Hành động với tên '%s' đã tồn tại."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
@@ -10123,15 +10044,15 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "All Devices"
-msgstr ""
+msgstr "Tất cả thiết bị"
#: editor/project_settings_editor.cpp
msgid "Device"
-msgstr ""
+msgstr "Thiết bị"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr ""
+msgstr "Nhấn một phím..."
#: editor/project_settings_editor.cpp
msgid "Mouse Button Index:"
@@ -10139,31 +10060,31 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Left Button"
-msgstr ""
+msgstr "Phím Trái"
#: editor/project_settings_editor.cpp
msgid "Right Button"
-msgstr ""
+msgstr "Phím Phải"
#: editor/project_settings_editor.cpp
msgid "Middle Button"
-msgstr ""
+msgstr "Phím Giữa"
#: editor/project_settings_editor.cpp
msgid "Wheel Up Button"
-msgstr ""
+msgstr "Phím Lăn Lên"
#: editor/project_settings_editor.cpp
msgid "Wheel Down Button"
-msgstr ""
+msgstr "Phím Lăn Xuống"
#: editor/project_settings_editor.cpp
msgid "Wheel Left Button"
-msgstr ""
+msgstr "Phím Lăn Trái"
#: editor/project_settings_editor.cpp
msgid "Wheel Right Button"
-msgstr ""
+msgstr "Phím Lăn Phải"
#: editor/project_settings_editor.cpp
msgid "X Button 1"
@@ -10179,7 +10100,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Axis"
-msgstr ""
+msgstr "Trục"
#: editor/project_settings_editor.cpp
msgid "Joypad Button Index:"
@@ -10195,7 +10116,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Event"
-msgstr ""
+msgstr "Thêm Sự kiện"
#: editor/project_settings_editor.cpp
msgid "Button"
@@ -10203,49 +10124,49 @@ msgstr "Button (nút, phím)"
#: editor/project_settings_editor.cpp
msgid "Left Button."
-msgstr ""
+msgstr "Phím Trái."
#: editor/project_settings_editor.cpp
msgid "Right Button."
-msgstr ""
+msgstr "Phím Phải."
#: editor/project_settings_editor.cpp
msgid "Middle Button."
-msgstr ""
+msgstr "Phím Giữa."
#: editor/project_settings_editor.cpp
msgid "Wheel Up."
-msgstr ""
+msgstr "Lăn Lên."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
-msgstr ""
+msgstr "Lăn Xuống."
#: editor/project_settings_editor.cpp
msgid "Add Global Property"
-msgstr ""
+msgstr "Thêm Thuộc tính Toàn cục"
#: editor/project_settings_editor.cpp
msgid "Select a setting item first!"
-msgstr ""
+msgstr "Chọn một mục cài đặt đã!"
#: editor/project_settings_editor.cpp
msgid "No property '%s' exists."
-msgstr ""
+msgstr "Thuộc tính '%s' không tồn tại."
#: editor/project_settings_editor.cpp
msgid "Setting '%s' is internal, and it can't be deleted."
-msgstr ""
+msgstr "Cài đặt '%s' thuộc nội tại, không thể xóa."
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr ""
+msgstr "Xóa Mục"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'."
-msgstr ""
+msgstr "Tên hành động không thể trống hoặc chứa '/', ':', '=', '\\' hoặc '\"'."
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
@@ -10253,11 +10174,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Error saving settings."
-msgstr ""
+msgstr "Lỗi khi lưu cài đặt."
#: editor/project_settings_editor.cpp
msgid "Settings saved OK."
-msgstr ""
+msgstr "Lưu cài đặt thành công."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
@@ -10269,11 +10190,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Translation"
-msgstr ""
+msgstr "Thêm Bản dịch"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
-msgstr ""
+msgstr "Xóa bản dịch"
#: editor/project_settings_editor.cpp
msgid "Add Remapped Path"
@@ -10317,7 +10238,7 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
-msgstr ""
+msgstr "Thay đổi sẽ được áp dụng sau khi Trình biên tập khởi động lại."
#: editor/project_settings_editor.cpp
msgid "Input Map"
@@ -10325,7 +10246,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Action:"
-msgstr ""
+msgstr "Hành động:"
#: editor/project_settings_editor.cpp
#, fuzzy
@@ -10338,7 +10259,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Device:"
-msgstr ""
+msgstr "Thiết bị:"
#: editor/project_settings_editor.cpp
msgid "Index:"
@@ -10362,7 +10283,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Resources:"
-msgstr ""
+msgstr "Tài nguyên:"
#: editor/project_settings_editor.cpp
msgid "Remaps by Locale:"
@@ -10387,7 +10308,7 @@ msgstr "Chỉ lựa chọn"
#: editor/project_settings_editor.cpp
msgid "Filter mode:"
-msgstr ""
+msgstr "Chế độ lọc:"
#: editor/project_settings_editor.cpp
msgid "Locales:"
@@ -10399,7 +10320,12 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr ""
+msgstr "Tiện ích"
+
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "Nạp mặc định"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10419,15 +10345,15 @@ msgstr ""
#: editor/property_editor.cpp
msgid "File..."
-msgstr ""
+msgstr "Tệp tin..."
#: editor/property_editor.cpp
msgid "Dir..."
-msgstr ""
+msgstr "Thư mục..."
#: editor/property_editor.cpp
msgid "Assign"
-msgstr ""
+msgstr "Gán"
#: editor/property_editor.cpp
msgid "Select Node"
@@ -10435,7 +10361,7 @@ msgstr "Chọn nút"
#: editor/property_editor.cpp
msgid "Error loading file: Not a resource!"
-msgstr ""
+msgstr "Lỗi tải tệp: Không phải tài nguyên!"
#: editor/property_editor.cpp
msgid "Pick a Node"
@@ -10443,11 +10369,11 @@ msgstr "Lấy một nút"
#: editor/property_editor.cpp
msgid "Bit %d, val %d."
-msgstr ""
+msgstr "Bit %d, giá trị %d."
#: editor/property_selector.cpp
msgid "Select Property"
-msgstr ""
+msgstr "Chọn Thuộc tính"
#: editor/property_selector.cpp
msgid "Select Virtual Method"
@@ -10455,7 +10381,7 @@ msgstr ""
#: editor/property_selector.cpp
msgid "Select Method"
-msgstr ""
+msgstr "Chọn Phương thức"
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
#, fuzzy
@@ -10463,30 +10389,28 @@ msgid "Batch Rename"
msgstr "Đổi tên"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Thay thế: "
+msgstr "Thay thế:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
-msgstr ""
+msgstr "Tiền tố:"
#: editor/rename_dialog.cpp
msgid "Suffix:"
-msgstr ""
+msgstr "Hậu tố:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Use Regular Expressions"
-msgstr "Phiên bản hiện tại:"
+msgstr "Dùng Regular Expression"
#: editor/rename_dialog.cpp
msgid "Advanced Options"
-msgstr ""
+msgstr "Tùy chọn Nâng cao"
#: editor/rename_dialog.cpp
msgid "Substitute"
-msgstr ""
+msgstr "Thay thế"
#: editor/rename_dialog.cpp
msgid "Node name"
@@ -10502,7 +10426,7 @@ msgstr "Loại nút"
#: editor/rename_dialog.cpp
msgid "Current scene name"
-msgstr ""
+msgstr "Tên Cảnh hiện tại"
#: editor/rename_dialog.cpp
msgid "Root node name"
@@ -10513,24 +10437,24 @@ msgid ""
"Sequential integer counter.\n"
"Compare counter options."
msgstr ""
+"Bộ đếm số nguyên tuần tự.\n"
+"So sánh giữa các cách đếm."
#: editor/rename_dialog.cpp
msgid "Per-level Counter"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "Nếu đặt bộ đếm khởi động lại cho từng nhóm nút con"
+msgstr "Nếu được đặt, bộ đếm sẽ khởi động lại với từng nhóm nút con."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
-msgstr ""
+msgstr "Giá trị đếm ban đầu"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Step"
-msgstr "Bước (s):"
+msgstr "Bước"
#: editor/rename_dialog.cpp
msgid "Amount by which counter is incremented for each node"
@@ -10538,41 +10462,43 @@ msgstr "Giá trị mà bộ đếm tăng lên cho mỗi nút"
#: editor/rename_dialog.cpp
msgid "Padding"
-msgstr ""
+msgstr "Đệm"
#: editor/rename_dialog.cpp
msgid ""
"Minimum number of digits for the counter.\n"
"Missing digits are padded with leading zeros."
msgstr ""
+"Số chữ số tối thiểu cho bộ đếm.\n"
+"Đệm thêm 0 ở đầu nếu thiếu chữ số."
#: editor/rename_dialog.cpp
msgid "Post-Process"
-msgstr ""
+msgstr "Hậu xử lý"
#: editor/rename_dialog.cpp
msgid "Keep"
-msgstr ""
+msgstr "Giữ"
#: editor/rename_dialog.cpp
msgid "PascalCase to snake_case"
-msgstr ""
+msgstr "KiểuPascal thành kiểu_rắn"
#: editor/rename_dialog.cpp
msgid "snake_case to PascalCase"
-msgstr ""
+msgstr "kiểu_rắn thành KiểuPascal"
#: editor/rename_dialog.cpp
msgid "Case"
-msgstr ""
+msgstr "Kiểu"
#: editor/rename_dialog.cpp
msgid "To Lowercase"
-msgstr ""
+msgstr "Hoa thành Thường"
#: editor/rename_dialog.cpp
msgid "To Uppercase"
-msgstr ""
+msgstr "Thường thành Hoa"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10585,9 +10511,8 @@ msgid "Regular Expression Error:"
msgstr "Phiên bản hiện tại:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
-msgstr "Ký tự hợp lệ:"
+msgstr "Tại kí tự %s"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
@@ -10607,23 +10532,23 @@ msgstr ""
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
-msgstr ""
+msgstr "Chế độ chạy:"
#: editor/run_settings_dialog.cpp
msgid "Current Scene"
-msgstr ""
+msgstr "Cảnh Hiện tại"
#: editor/run_settings_dialog.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "Cảnh chính"
#: editor/run_settings_dialog.cpp
msgid "Main Scene Arguments:"
-msgstr ""
+msgstr "Tham số Cảnh chính:"
#: editor/run_settings_dialog.cpp
msgid "Scene Run Settings"
-msgstr ""
+msgstr "Cài đặt chạy Cảnh"
#: editor/scene_tree_dock.cpp
msgid "No parent to instance the scenes at."
@@ -10631,7 +10556,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Error loading scene from %s"
-msgstr ""
+msgstr "Lỗi tải cảnh từ %s"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10643,7 +10568,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Scene(s)"
-msgstr ""
+msgstr "Khởi tạo Cảnh"
#: editor/scene_tree_dock.cpp
msgid "Replace with Branch Scene"
@@ -10651,7 +10576,16 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
-msgstr ""
+msgstr "Khởi tạo Cảnh con"
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "Không thể dán Nút Gốc vào cùng một Cảnh."
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "Dán các nút"
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -10660,7 +10594,7 @@ msgstr "Đính kèm Script"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
-msgstr ""
+msgstr "Thao tác này không thể áp dụng lên gốc của cây."
#: editor/scene_tree_dock.cpp
msgid "Move Node In Parent"
@@ -10686,7 +10620,7 @@ msgstr "Nút phải thuộc cảnh đã chỉnh sửa để trở thành gốc."
#: editor/scene_tree_dock.cpp
msgid "Instantiated scenes can't become root"
-msgstr ""
+msgstr "Cảnh khởi tạo không thể thành gốc"
#: editor/scene_tree_dock.cpp
msgid "Make node as Root"
@@ -10719,11 +10653,11 @@ msgstr "Không thể thực hiện với nút gốc."
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on instanced scenes."
-msgstr ""
+msgstr "Không thể thực hiện thao tác này trên Cảnh được khởi tạo."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
-msgstr ""
+msgstr "Lưu Cảnh Mới Thành..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10755,11 +10689,11 @@ msgstr "Tạo Nút Gốc:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr "2D Scene"
+msgstr "Cảnh 2D"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr "3D Scene"
+msgstr "Cảnh 3D"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
@@ -10782,6 +10716,11 @@ msgid "Attach Script"
msgstr "Đính kèm Script"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "Cắt các nút"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "Xóa các nút"
@@ -10794,6 +10733,7 @@ msgid ""
"Couldn't save new scene. Likely dependencies (instances) couldn't be "
"satisfied."
msgstr ""
+"Không thể lưu cảnh mới. Có vẻ là do không thỏa mãn được các phần phụ thuộc."
#: editor/scene_tree_dock.cpp
msgid "Error saving scene."
@@ -10801,19 +10741,19 @@ msgstr "Lỗi khi lưu scene."
#: editor/scene_tree_dock.cpp
msgid "Error duplicating scene to save it."
-msgstr ""
+msgstr "Lỗi khi nhân bản cảnh để lưu."
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Tài nguyên phụ"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
-msgstr ""
+msgstr "Xóa Kế thừa"
#: editor/scene_tree_dock.cpp
msgid "Editable Children"
-msgstr ""
+msgstr "Các nút Con có thể sửa"
#: editor/scene_tree_dock.cpp
msgid "Load As Placeholder"
@@ -10821,7 +10761,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr ""
+msgstr "Mở Hướng dẫn"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10829,6 +10769,9 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Không thể đính kèm tệp lệnh: Không ghi nhận thấy ngôn ngữ nào.\n"
+"Vấn đề có thể là do các module ngôn ngữ bị vô hiệu hóa khi trình biên tập "
+"này được xây dựng."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10841,7 +10784,7 @@ msgstr "Thu gọn Tất cả"
#: editor/scene_tree_dock.cpp
msgid "Change Type"
-msgstr ""
+msgstr "Đổi Kiểu"
#: editor/scene_tree_dock.cpp
msgid "Reparent to New Node"
@@ -10849,15 +10792,15 @@ msgstr "Reparent đến nút mới"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr ""
+msgstr "Biến Cảnh thành Gốc"
#: editor/scene_tree_dock.cpp
msgid "Merge From Scene"
-msgstr ""
+msgstr "Hợp nhất từ Cảnh"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Save Branch as Scene"
-msgstr ""
+msgstr "Lưu Nhánh thành Cảnh"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
@@ -10865,7 +10808,7 @@ msgstr "Sao chép đường dẫn nút"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
-msgstr ""
+msgstr "Xóa (Không hỏi lại)"
#: editor/scene_tree_dock.cpp
msgid "Add/Create a New Node."
@@ -10893,12 +10836,19 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
-msgid "Local"
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr "Cục bộ"
+
+#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
-msgstr ""
+msgstr "Xóa Kế thừa? (Mất tăm luôn đấy!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
@@ -10947,9 +10897,8 @@ msgstr ""
"Nhấp để hiện khung nhóm."
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Open Script:"
-msgstr "Tạo Script"
+msgstr "Mở Tệp lệnh:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -10964,6 +10913,8 @@ msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
+"Không thể chọn Con của nút này.\n"
+"Bấm vào đây để có thể chọn chúng."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
@@ -10974,6 +10925,8 @@ msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
+"AnimationPlayer đã được ghim.\n"
+"Bấm để bỏ ghim."
#: editor/scene_tree_editor.cpp
msgid "Invalid node name, the following characters are not allowed:"
@@ -10997,11 +10950,11 @@ msgstr "Chọn một Nút"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr ""
+msgstr "Đường dẫn trống."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
-msgstr ""
+msgstr "Tên tệp trống."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
@@ -11022,25 +10975,24 @@ msgid "File does not exist."
msgstr "Tệp không tồn tại."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid extension."
-msgstr "Phải sử dụng extension có hiệu lực"
+msgstr "Tên đuôi không hợp lệ."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
-msgstr ""
+msgstr "Sai đuôi mở rộng."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr ""
+msgstr "Lỗi nạp mẫu '%s'"
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
-msgstr ""
+msgstr "Lỗi - Không thể tạo tệp lệnh trong hệ thống tệp tin."
#: editor/script_create_dialog.cpp
msgid "Error loading script from %s"
-msgstr ""
+msgstr "Lỗi nạp tệp lệnh từ %s"
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11048,12 +11000,13 @@ msgid "Overrides"
msgstr "Ghi đè"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "N/A"
-msgstr ""
+msgstr "Không có"
#: editor/script_create_dialog.cpp
msgid "Open Script / Choose Location"
-msgstr ""
+msgstr "Mở tệp lệnh / Chọn vị trí"
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11061,8 +11014,9 @@ msgid "Open Script"
msgstr "Tạo Script"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "File exists, it will be reused."
-msgstr ""
+msgstr "Tệp tồn tại, và sẽ được dùng lại."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11070,9 +11024,8 @@ msgid "Invalid path."
msgstr "Đường dẫn sai."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid class name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Tên Lớp không hợp lệ."
#: editor/script_create_dialog.cpp
msgid "Invalid inherited parent name or path."
@@ -11085,11 +11038,11 @@ msgstr "Animation tree khả dụng."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "Được dùng: a-z, A-Z, 0-9, _ và ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
-msgstr ""
+msgstr "Tệp lệnh tích hợp (vào tệp cảnh)."
#: editor/script_create_dialog.cpp
msgid "Will create a new script file."
@@ -11097,7 +11050,7 @@ msgstr "Sẽ tạo một tệp lệnh mới."
#: editor/script_create_dialog.cpp
msgid "Will load an existing script file."
-msgstr ""
+msgstr "Sẽ nạp một tệp lệnh đã tồn tại."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11109,20 +11062,20 @@ msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
msgstr ""
+"Lưu ý: Tệp lệnh tích hợp có một số hạn chế và không thể chỉnh sửa bằng trình "
+"biên soạn bên ngoài."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Lớp:"
+msgstr "Tên Lớp:"
#: editor/script_create_dialog.cpp
msgid "Template:"
msgstr "Bản mẫu:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Tạo Script"
+msgstr "Tệp lệnh có sẵn:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
@@ -11134,27 +11087,23 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
-msgstr ""
+msgstr "Bytes:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Cảnh báo"
+msgstr "Cảnh báo:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "Lỗi!"
+msgstr "Lỗi:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error"
-msgstr "Lỗi!"
+msgstr "Lỗi C++"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error:"
-msgstr "Lỗi!"
+msgstr "Lỗi C++:"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11162,13 +11111,13 @@ msgid "C++ Source"
msgstr "Sao chép Tài nguyên"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source:"
-msgstr "Quét nguồn"
+msgstr "Nguồn:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "C++ Source:"
-msgstr ""
+msgstr "Tệp nguồn C++:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
@@ -11176,25 +11125,23 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Lỗi"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Child process connected."
-msgstr "Các Nút đã ngắt Kết nối"
+msgstr "Đã kết nối tiến trình con."
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr ""
+msgstr "Sao chép lỗi"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
msgstr ""
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Skip Breakpoints"
-msgstr "Tạo các điểm."
+msgstr "Lờ đi điểm dừng"
#: editor/script_editor_debugger.cpp
msgid "Inspect Previous Instance"
@@ -11218,28 +11165,31 @@ msgid "Network Profiler"
msgstr "Xuất hồ sơ"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Monitor"
-msgstr ""
+msgstr "Màn hình"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Giá trị"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Monitors"
-msgstr ""
+msgstr "Màn hình"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr ""
+msgstr "Chọn một hoặc nhiều mục từ danh sách để hiển thị biểu đồ."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr ""
+msgstr "Danh sách sử dụng bộ nhớ của các video theo tài nguyên:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Total:"
-msgstr ""
+msgstr "Tổng:"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11248,23 +11198,24 @@ msgstr "Xuất hồ sơ"
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
-msgstr ""
+msgstr "Đường dẫn Tài nguyên"
#: editor/script_editor_debugger.cpp
msgid "Type"
-msgstr ""
+msgstr "Kiểu"
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Định dạng"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Sử dụng"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Misc"
-msgstr ""
+msgstr "Khác"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
@@ -11288,15 +11239,15 @@ msgstr ""
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
-msgstr ""
+msgstr "Xóa lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Restore Shortcut"
-msgstr ""
+msgstr "Khôi phục lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Change Shortcut"
-msgstr ""
+msgstr "Thay đổi Lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Editor Settings"
@@ -11304,7 +11255,7 @@ msgstr "Cài đặt Trình biên tập"
#: editor/settings_config_dialog.cpp
msgid "Shortcuts"
-msgstr ""
+msgstr "Lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Binding"
@@ -11312,7 +11263,7 @@ msgstr ""
#: editor/spatial_editor_gizmos.cpp
msgid "Change Light Radius"
-msgstr ""
+msgstr "Thay đổi bán kính ánh sáng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -11340,105 +11291,104 @@ msgstr ""
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Sphere Shape Radius"
-msgstr ""
+msgstr "Thay Đổi Bán Kính Hình Cầu"
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Box Shape Extents"
-msgstr ""
+msgstr "Chỉnh chiều dài hình hộp"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Capsule Shape Radius"
-msgstr ""
+msgstr "Chỉnh bán kính hình nhộng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Capsule Shape Height"
-msgstr ""
+msgstr "Chỉnh chiều cao hình nhộng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Cylinder Shape Radius"
-msgstr ""
+msgstr "Chỉnh bán kính hình trụ"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Cylinder Shape Height"
-msgstr ""
+msgstr "Chỉnh chiều cao hình trụ"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Ray Shape Length"
msgstr ""
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Radius"
-msgstr "Đổi Thời gian Chuyển Animation"
+msgstr "Thay Đổi Bán Kính Hình Trụ"
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Height"
-msgstr "Đổi Thời gian Chuyển Animation"
+msgstr "Thay Đổi Chiều Cao Hình Trụ"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Inner Radius"
-msgstr ""
+msgstr "Thay Đổi Bán Kính Trong Của Hình Xuyến"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Outer Radius"
-msgstr ""
+msgstr "Thay Đổi Bán Kính Ngoài Của Hình Xuyến"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Select the dynamic library for this entry"
-msgstr ""
+msgstr "Chọn thư viện động cho mục này"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Select dependencies of the library for this entry"
-msgstr ""
+msgstr "Chọn phần phụ thuộc của thư viện cho mục này"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Remove current entry"
-msgstr ""
+msgstr "Xóa mục hiện tại"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Double click to create a new entry"
-msgstr ""
+msgstr "Nhấp đúp để tạo mục mới"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform:"
-msgstr ""
+msgstr "Nền tảng:"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform"
-msgstr ""
+msgstr "Nền tảng"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Dynamic Library"
-msgstr ""
+msgstr "Thư viện động"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Add an architecture entry"
-msgstr ""
+msgstr "Thêm mục kiến trúc máy"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "GDNativeLibrary"
-msgstr ""
+msgstr "GDNativeLibrary"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
+#, fuzzy
msgid "Enabled GDNative Singleton"
-msgstr ""
+msgstr "Bật đơn nhất GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Disabled GDNative Singleton"
-msgstr ""
+msgstr "Tắt đơn nhất GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
-msgstr ""
+msgstr "Thư viện"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Libraries: "
-msgstr ""
+msgstr "Thư viện: "
#: modules/gdnative/register_types.cpp
msgid "GDNative"
-msgstr ""
+msgstr "GDNative"
#: modules/gdscript/gdscript_functions.cpp
msgid "Step argument is zero!"
@@ -11450,44 +11400,44 @@ msgstr ""
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a script"
-msgstr ""
+msgstr "Không dựa trên tệp lệnh"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a resource file"
-msgstr ""
+msgstr "Không dựa trên tệp tài nguyên"
#: modules/gdscript/gdscript_functions.cpp
+#, fuzzy
msgid "Invalid instance dictionary format (missing @path)"
-msgstr ""
+msgstr "Định dạng từ điển không hợp lệ (thiếu @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (can't load script at @path)"
-msgstr ""
+msgstr "Định dạng từ điển không hợp lệ (Không tải được tệp lệnh ở @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (invalid script at @path)"
-msgstr ""
+msgstr "Định dạng từ điển không hợp lệ (tệp lệnh không hợp lệ ở @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary (invalid subclasses)"
-msgstr ""
+msgstr "Từ điển không hợp lệ (Lớp con không hợp lệ)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Object can't provide a length."
-msgstr ""
+msgstr "Đối tượng không thể cung cấp chiều dài."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
-msgstr ""
+msgstr "Mặt phẳng tiếp theo"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Previous Plane"
-msgstr "Thư mục trước"
+msgstr "Mặt phẳng trước đó"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Plane:"
-msgstr ""
+msgstr "Mặt phẳng:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Floor"
@@ -11521,7 +11471,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
-msgstr ""
+msgstr "Bản đồ Lưới"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
@@ -11541,15 +11491,15 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit X Axis"
-msgstr ""
+msgstr "Chỉnh trục X"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit Y Axis"
-msgstr ""
+msgstr "Chỉnh trục Y"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit Z Axis"
-msgstr ""
+msgstr "Chỉnh trục Z"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Cursor Rotate X"
@@ -11586,7 +11536,7 @@ msgstr "Chọn tất cả"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clear Selection"
-msgstr ""
+msgstr "Xóa Lựa chọn"
#: modules/gridmap/grid_map_editor_plugin.cpp
#, fuzzy
@@ -11595,7 +11545,7 @@ msgstr "Chọn tất cả"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Settings"
-msgstr ""
+msgstr "Cài đặt Bản đồ Lưới"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Pick Distance:"
@@ -11616,11 +11566,11 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "Chuẩn bị cấu trúc dữ liệu"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Generate buffers"
-msgstr ""
+msgstr "Tạo bộ đệm"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -11629,12 +11579,11 @@ msgstr "Hướng đi"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Indirect lighting"
-msgstr ""
+msgstr "Chiếu sáng gián tiếp"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Phiên bản hiện tại:"
+msgstr "Hậu xử lí"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Plotting lightmaps"
@@ -11642,7 +11591,7 @@ msgstr ""
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
-msgstr ""
+msgstr "Tên Lớp không được trùng với từ khóa"
#: modules/mono/mono_gd/gd_mono_utils.cpp
msgid "End of inner exception stack trace"
@@ -11654,15 +11603,15 @@ msgstr ""
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Clear the navigation mesh."
-msgstr ""
+msgstr "Xóa lưới điều hướng."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Setting up Configuration..."
-msgstr ""
+msgstr "Thiết lập cấu hình ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Calculating grid size..."
-msgstr ""
+msgstr "Tính kích thước lưới ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating heightfield..."
@@ -11670,7 +11619,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Marking walkable triangles..."
-msgstr ""
+msgstr "Đánh dấu tam giác có thể đi được..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Constructing compact heightfield..."
@@ -11678,15 +11627,15 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Eroding walkable area..."
-msgstr ""
+msgstr "Làm xói mòn vùng đi được..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Partitioning..."
-msgstr ""
+msgstr "Phân vùng ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating contours..."
-msgstr ""
+msgstr "Tạo đường viền ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating polymesh..."
@@ -11698,7 +11647,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Navigation Mesh Generator Setup:"
-msgstr ""
+msgstr "Thiết lập trình tạo lưới điều hướng:"
#: modules/recast/navigation_mesh_generator.cpp
msgid "Parsing Geometry..."
@@ -11706,7 +11655,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Done!"
-msgstr ""
+msgstr "Xong!"
#: modules/visual_script/visual_script.cpp
msgid ""
@@ -11733,78 +11682,76 @@ msgstr ""
#: modules/visual_script/visual_script.cpp
msgid "Node returned an invalid sequence output: "
-msgstr "Nút trả về đầu ra là chuỗi không hợp lệ: "
+msgstr "Nút trả về chuỗi không hợp lệ: "
#: modules/visual_script/visual_script.cpp
msgid "Found sequence bit but not the node in the stack, report bug!"
-msgstr "Tìm ra chuỗi bit nhưng không phải nút trong ngăn xếp, báo cáo lỗi!"
+msgstr ""
+"Tìm thấy chuỗi bit nhưng không phải là nút trong ngăn xếp, báo cáo lỗi!"
#: modules/visual_script/visual_script.cpp
msgid "Stack overflow with stack depth: "
-msgstr ""
+msgstr "Tràn ngăn xếp ở ngăn xếp tầng: "
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Signal Arguments"
-msgstr ""
+msgstr "Thay đổi đối số tín hiệu"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument Type"
-msgstr ""
+msgstr "Thay đổi loại đối số"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument name"
-msgstr ""
+msgstr "Thay đổi tên đối số"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Default Value"
-msgstr ""
+msgstr "Đặt giá trị mặc định cho biến"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Type"
-msgstr ""
+msgstr "Đặt loại biến"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "Thêm Input"
+msgstr "Thêm cổng vào"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "Thêm Input"
+msgstr "Thêm cổng ra"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
-msgstr ""
+msgstr "Ghi đè một hàm cài sẵn."
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new function."
-msgstr "Tạo một hàm mới."
+msgstr "Tạo hàm mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
-msgstr ""
+msgstr "Biến:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new variable."
-msgstr "Tạo một biến mới."
+msgstr "Tạo biến mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "Tín hiệu:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "Tạo"
+msgstr "Tạo tín hiệu mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
-msgstr ""
+msgstr "Tên không phải định danh hợp lệ:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Name already in use by another func/var/signal:"
-msgstr ""
+msgstr "Tên đã được sử dụng bởi func/var/singal khác:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Function"
@@ -11823,9 +11770,8 @@ msgid "Add Function"
msgstr "Thêm Hàm"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Delete input port"
-msgstr "Xoá Function"
+msgstr "Xoá cổng vào"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Variable"
@@ -11836,22 +11782,20 @@ msgid "Add Signal"
msgstr "Thêm Tín hiệu"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Input Port"
-msgstr "Xoá Function"
+msgstr "Xóa cổng vào"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Output Port"
-msgstr "Xóa Template"
+msgstr "Xóa cổng ra"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
-msgstr ""
+msgstr "Thay đổi biểu thức"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
-msgstr "Gỡ bỏ các nút VisualScript"
+msgstr "Xóa các nút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
@@ -11859,7 +11803,7 @@ msgstr "Nhân bản các nút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
-msgstr ""
+msgstr "Giữ% s để thả Getter. Giữ phím Shift để thả chữ ký chung."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
@@ -11867,27 +11811,27 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a simple reference to the node."
-msgstr "Giữ %s và thả để tham chiếu đơn giản đế nút."
+msgstr "Giữ %s để thả một tham chiếu đơn giản lên nút."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a simple reference to the node."
-msgstr "Giữ Ctrl và thả để tham chiếu đơn giản đến nút."
+msgstr "Giữ Ctrl để thả một tài liệu tham khảo đơn giản đến nút."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Variable Setter."
-msgstr ""
+msgstr "Giữ %s để bỏ Hàm Đặt Biến."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Variable Setter."
-msgstr ""
+msgstr "Giữ Ctrl để bỏ Hàm Đặt Biến."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Preload Node"
-msgstr "Thêm nút Preload"
+msgstr "Thêm nút tải trước"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
-msgstr "Thêm các nút từ cây"
+msgstr "Thêm nút từ cây"
#: modules/visual_script/visual_script_editor.cpp
msgid ""
@@ -11905,7 +11849,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Base Type"
-msgstr ""
+msgstr "Thay đổi loại cơ sở"
#: modules/visual_script/visual_script_editor.cpp
msgid "Move Node(s)"
@@ -11917,7 +11861,7 @@ msgstr "Gỡ bỏ nút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Connect Nodes"
-msgstr "Kết nối các nút"
+msgstr "Kết nối nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Disconnect Nodes"
@@ -11933,15 +11877,15 @@ msgstr "Kết nối trình tự nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
-msgstr ""
+msgstr "Tệp lệnh đã có hàm '%s'"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Input Value"
-msgstr ""
+msgstr "Thay đổi giá trị đầu vào"
#: modules/visual_script/visual_script_editor.cpp
msgid "Resize Comment"
-msgstr ""
+msgstr "Thay đổi kích thước Nhận xét"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't copy the function node."
@@ -11949,7 +11893,7 @@ msgstr "Không thể sao chép nút chức năng."
#: modules/visual_script/visual_script_editor.cpp
msgid "Clipboard is empty!"
-msgstr ""
+msgstr "Clipboard trống!"
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste VisualScript Nodes"
@@ -11972,17 +11916,16 @@ msgid "Try to only have one sequence input in selection."
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create Function"
-msgstr "Đổi tên Hàm"
+msgstr "Tạo Hàm"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Function"
-msgstr "Xoá Function"
+msgstr "Xoá Hàm"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Variable"
-msgstr "Xoá Variable"
+msgstr "Xoá Biến"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Variable:"
@@ -12005,27 +11948,24 @@ msgid "Members:"
msgstr "Những Thành viên:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "Đổi %s Loại"
+msgstr "Đổi Kiểu Gốc:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Nodes..."
msgstr "Thêm các nút..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "Thêm Hàm"
+msgstr "Thêm Hàm..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "Hàm:"
+msgstr "ten_ham"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
-msgstr ""
+msgstr "Chọn hoặc tạo một hàm để chỉnh đồ thị."
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
@@ -12037,21 +11977,19 @@ msgstr "Tìm loại Node"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
-msgstr "Sao chép các nút"
+msgstr "Sao chép nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Cut Nodes"
msgstr "Cắt các nút"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "Đổi tên Hàm"
+msgstr "Tạo Hàm"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "Làm mới"
+msgstr "Làm mới đồ thị"
#: modules/visual_script/visual_script_editor.cpp
msgid "Edit Member"
@@ -12059,19 +11997,19 @@ msgstr ""
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
-msgstr ""
+msgstr "Kiểu đầu vào không lặp được: "
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid"
-msgstr ""
+msgstr "Trỏ lặp không còn hợp lệ"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid: "
-msgstr ""
+msgstr "Trỏ lặp không còn hợp lệ: "
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name."
-msgstr ""
+msgstr "Tên thuộc tính chỉ mục không hợp lệ."
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Base object is not a Node!"
@@ -12079,37 +12017,41 @@ msgstr "Đối tượng cơ sở không phải một nút!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Path does not lead Node!"
-msgstr "Path không chỉ đến Node!"
+msgstr "Đường dẫn không chỉ đến Nút!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
-msgstr ""
+msgstr "Tên thuộc tính chỉ mục '%s' ở nút '%s' không hợp lệ."
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid argument of type: "
-msgstr ""
+msgstr ": Tham số có loại không hợp lệ: "
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid arguments: "
-msgstr ""
+msgstr ": Tham số không hợp lệ: "
#: modules/visual_script/visual_script_nodes.cpp
msgid "VariableGet not found in script: "
-msgstr ""
+msgstr "Không tìm thấy VariableGet trong tệp lệnh: "
#: modules/visual_script/visual_script_nodes.cpp
+#, fuzzy
msgid "VariableSet not found in script: "
-msgstr ""
+msgstr "Không tìm thấy VariableSet trong tệp lệnh: "
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
-msgstr ""
+msgstr "Nút tùy chọn không có phương thức _step(), không thể xử lí đồ thị."
#: modules/visual_script/visual_script_nodes.cpp
+#, fuzzy
msgid ""
"Invalid return value from _step(), must be integer (seq out), or string "
"(error)."
msgstr ""
+"_step() trả giá trị không hợp lệ, phải là số nguyên (seq out), hoặc xâu "
+"(lỗi)."
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Search VisualScript"
@@ -12117,43 +12059,43 @@ msgstr "Tìm VisualScript"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Get %s"
-msgstr ""
+msgstr "Lấy %s"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Set %s"
-msgstr ""
+msgstr "Gán %s"
#: platform/android/export/export.cpp
msgid "Package name is missing."
-msgstr ""
+msgstr "Thiếu tên gói."
#: platform/android/export/export.cpp
msgid "Package segments must be of non-zero length."
-msgstr ""
+msgstr "Các phân đoạn của gói phải có độ dài khác không."
#: platform/android/export/export.cpp
msgid "The character '%s' is not allowed in Android application package names."
-msgstr ""
+msgstr "Không được phép cho kí tự '%s' vào tên gói phần mềm Android."
#: platform/android/export/export.cpp
msgid "A digit cannot be the first character in a package segment."
-msgstr ""
+msgstr "Không thể có chữ số làm kí tự đầu tiên trong một phần của gói."
#: platform/android/export/export.cpp
msgid "The character '%s' cannot be the first character in a package segment."
-msgstr ""
+msgstr "Kí tự '%s' không thể ở đầu trong một phân đoạn của gói."
#: platform/android/export/export.cpp
msgid "The package must have at least one '.' separator."
-msgstr ""
+msgstr "Kí tự phân cách '.' phải xuất hiện ít nhất một lần trong tên gói."
#: platform/android/export/export.cpp
msgid "Select device from the list"
-msgstr ""
+msgstr "Chọn thiết bị trong danh sách"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr ""
+msgstr "Không tìm thấy công cụ 'apksigner'."
#: platform/android/export/export.cpp
msgid ""
@@ -12173,61 +12115,65 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr ""
+msgstr "Cài đặt Trình biên tập yêu cầu một đường dẫn Android SDK hợp lệ."
#: platform/android/export/export.cpp
msgid "Invalid Android SDK path in Editor Settings."
-msgstr ""
+msgstr "Đường dẫn Android SDK không hợp lệ trong Cài đặt Trình biên tập."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "Thiếu thư mục 'platform-tools'!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Không tìm thấy lệnh adb trong bộ Android SDK platform-tools."
#: platform/android/export/export.cpp
msgid "Please check in the Android SDK directory specified in Editor Settings."
msgstr ""
+"Hãy kiểm tra thư mục Android SDK được cung cấp ở Cài đặt Trình biên tập."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "Thiếu thư mục 'build-tools'!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Không tìm thấy lệnh apksigner của bộ Android SDK build-tools."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
-msgstr ""
+msgstr "Khóa công khai của bộ APK mở rộng không hợp lệ."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid package name:"
-msgstr "Kích thước font không hợp lệ."
+msgstr "Tên gói không hợp lệ:"
#: platform/android/export/export.cpp
msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Cài đặt dự án chứa module không hợp lệ \"GodotPaymentV3\" ở mục \"android/"
+"modules\" (đã thay đổi từ Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "\"Sử dụng Bản dựng tùy chỉnh\" phải được bật để sử dụng các tiện ích."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
-msgstr ""
+msgstr "\"Bậc tự do\" chỉ dùng được khi \"Xr Mode\" là \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Theo dõi chuyển động tay\" chỉ dùng được khi \"Xr Mode\" là \"Oculus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
@@ -12237,18 +12183,20 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
msgstr ""
+"\"Xuất AAB\" chỉ dùng được khi \"Sử dụng Bản dựng tùy chỉnh\" được bật."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
-msgstr ""
+msgstr "Tên tệp không hợp lệ! Android App Bundle cần đuôi *.aab ở cuối."
#: platform/android/export/export.cpp
+#, fuzzy
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "Đuôi APK không tương thích với Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "Tên tệp không hợp lệ! Android APK cần đuôi *.apk ở cuối."
#: platform/android/export/export.cpp
msgid ""
@@ -12279,8 +12227,8 @@ msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"Xây dựng dự án Android không thành công, kiểm tra lỗi đầu ra.\n"
-"Hoặc truy cập 'docs.godotengine.org' xem tài liệu xây dựng Android."
+"Xây dựng dự án Android thất bại, hãy kiểm tra đầu ra để biết lỗi.\n"
+"Hoặc truy cập 'docs.godotengine.org' để xem cách xây dựng Android."
#: platform/android/export/export.cpp
msgid "Moving output"
@@ -12291,23 +12239,24 @@ msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"Không thể sao chép và đổi tên tệp xuất, hãy kiểm tra thư mục Gradle của dự "
+"án để xem kết quả."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
-msgstr ""
+msgstr "Thiếu định danh."
#: platform/iphone/export/export.cpp
msgid "The character '%s' is not allowed in Identifier."
-msgstr ""
+msgstr "Không được phép có kí tự '%s' trong Định danh."
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
msgstr "App Store Team ID không được chỉ định - không thể cấu hình dự án."
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Invalid Identifier:"
-msgstr "Kích thước font không hợp lệ."
+msgstr "Định danh không hợp lệ:"
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
@@ -12315,7 +12264,7 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "Stop HTTP Server"
-msgstr ""
+msgstr "Dừng Máy chủ HTTP"
#: platform/javascript/export/export.cpp
msgid "Run in Browser"
@@ -12323,7 +12272,7 @@ msgstr "Chạy trong Trình duyệt web"
#: platform/javascript/export/export.cpp
msgid "Run exported HTML in the system's default browser."
-msgstr ""
+msgstr "Chạy HTML được xuất với trình duyệt mặc định của máy."
#: platform/javascript/export/export.cpp
msgid "Could not write file:"
@@ -12331,11 +12280,11 @@ msgstr "Không viết được file:"
#: platform/javascript/export/export.cpp
msgid "Could not open template for export:"
-msgstr ""
+msgstr "Không thể mở bản mẫu để xuất:"
#: platform/javascript/export/export.cpp
msgid "Invalid export template:"
-msgstr ""
+msgstr "Bản xuất mẫu không hợp lệ:"
#: platform/javascript/export/export.cpp
msgid "Could not read custom HTML shell:"
@@ -12350,74 +12299,72 @@ msgid "Using default boot splash image."
msgstr "Sử dụng hình khởi động mặc định."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package short name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên ngắn không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package unique name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên độc nhất không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package publisher display name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên hiển thị của nhà phát hành không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Kích thước font không hợp lệ."
+msgstr "GUID sản phẩm không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Kích thước font không hợp lệ."
+msgstr "GUID của nhà phát hành không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid background color."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Màu nền không hợp lệ."
#: platform/uwp/export/export.cpp
msgid "Invalid Store Logo image dimensions (should be 50x50)."
-msgstr ""
+msgstr "Kích thước ảnh Logo Store không hợp lệ (phải là 50x50)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 44x44 không hợp lệ (phải là 44x44)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 71x71 không hợp lệ (phải là 71x71)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 150x150 không hợp lệ (phải là 150x150)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 310x310 không hợp lệ (phải là 310x310)."
#: platform/uwp/export/export.cpp
msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
-msgstr ""
+msgstr "Kích thước ảnh logo 310x150 không hợp lệ (phải là 310x150)."
#: platform/uwp/export/export.cpp
msgid "Invalid splash screen image dimensions (should be 620x300)."
-msgstr ""
+msgstr "Ảnh mở màn có kích thước không hợp lệ (phải là 620x300)."
#: scene/2d/animated_sprite.cpp
msgid ""
"A SpriteFrames resource must be created or set in the \"Frames\" property in "
"order for AnimatedSprite to display frames."
msgstr ""
+"Tài nguyên SpriteFrames phải được tạo hoặc đặt trong thuộc tính \"Khung hình"
+"\" thì AnimatedSprite mới hiển thị các khung hình được."
#: scene/2d/canvas_modulate.cpp
msgid ""
"Only one visible CanvasModulate is allowed per scene (or set of instanced "
"scenes). The first created one will work, while the rest will be ignored."
msgstr ""
+"Chỉ cho phép một CanvasModulate (không ẩn) ứng với một Cảnh (hoặc một tập "
+"Cảnh đã được tạo). Cái đầu tiên sẽ chạy, những cái sau sẽ bị lờ đi."
#: scene/2d/collision_object_2d.cpp
msgid ""
@@ -12425,6 +12372,10 @@ msgid ""
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
"define its shape."
msgstr ""
+"Nút này không có hình thù, nên không thể va chạm hoặc tương tác với các vật "
+"khác.\n"
+"Hãy thêm nút con CollisionShape2D hoặc CollisionPolygon2D để định dạng cho "
+"nút này."
#: scene/2d/collision_polygon_2d.cpp
msgid ""
@@ -12432,10 +12383,21 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"CollisionPolygon2D nhằm mục đích tạo khối va chạm cho những nút kế thừa từ "
+"CollisionObject2D. Vậy nên hãy cho nút ấy làm con của Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, ... để tạo khối va chạm."
#: scene/2d/collision_polygon_2d.cpp
msgid "An empty CollisionPolygon2D has no effect on collision."
-msgstr ""
+msgstr "ColiisionPolygon2D rỗng sẽ không phản ứng gì khi có va chạm."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "Đa giác không hợp lệ. Cần ít nhất 3 điểm trong chế độ dựng \"Solids\"."
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "Đa giác không hợp lệ. Cần ít nhất 2 điểm trong chế độ dựng 'Segments'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12443,44 +12405,52 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"CollisionShape2D nhằm mục đích tạo khối va chạm cho những nút kế thừa từ "
+"CollisionObject2D. Vậy nên hãy cho nút ấy làm con của Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, ... để tạo khối va chạm."
#: scene/2d/collision_shape_2d.cpp
msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
msgstr ""
+"CollisionShape2D cần một khối hình mới hoạt động được. Hãy tạo một tài "
+"nguyên khối hình cho nó!"
#: scene/2d/collision_shape_2d.cpp
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"Khối hình đa giác không được nhằm để dùng hoặc chỉnh sửa thông qua nút "
+"CollisionShape2D. Hãy chuyển qua dùng nút CollisionPolygon2D."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
+"Hoạt ảnh CPUParticles2D cần CanvasItemMaterial bật \"Particles Animation\"."
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Nút A và Nút B phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Nút A phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Nút B phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "Khớp nối chưa kết nối tới hai PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Nút A và Nút B phải là 2 PhysicsBody2D khác nhau"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12502,17 +12472,22 @@ msgid ""
"A NavigationPolygon resource must be set or created for this node to work. "
"Please set a property or draw a polygon."
msgstr ""
+"Một tài nguyên Navigation Polygon phải được đặt hoặc tạo thì nút này mới "
+"chạy được. Vui lòng đặt thuộc tính hoặc vẽ một đa giác."
#: scene/2d/navigation_polygon.cpp
msgid ""
"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
"node. It only provides navigation data."
msgstr ""
+"NavigationPolygonInstance phải là nút con hoặc cháu của nút Navigation2D. Nó "
+"chỉ cung cấp dữ liệu điều hướng."
#: scene/2d/parallax_layer.cpp
msgid ""
"ParallaxLayer node only works when set as child of a ParallaxBackground node."
msgstr ""
+"Nút ParallaxLayer chỉ hoạt động khi là con của một nút ParallaxBackground."
#: scene/2d/particles_2d.cpp
msgid ""
@@ -12520,6 +12495,9 @@ msgid ""
"Use the CPUParticles2D node instead. You can use the \"Convert to "
"CPUParticles\" option for this purpose."
msgstr ""
+"Video driver GLES2 không hỗ trợ hạt dựa trên bộ xử lí GPU.\n"
+"Thay vào đó hãy dùng nút CPUParticles2D. Bạn có thể dùng tùy chọn \"Chuyển "
+"thành CPUParticles\" cho mục đích này."
#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
msgid ""
@@ -12532,10 +12510,11 @@ msgid ""
"Particles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
+"Hoạt ảnh Particles2D cần CanvasItemMaterial bật \"Particles Animation\"."
#: scene/2d/path_2d.cpp
msgid "PathFollow2D only works when set as a child of a Path2D node."
-msgstr ""
+msgstr "PathFollow2D chỉ hoạt động khi được đặt làm con của một nút Path2D."
#: scene/2d/physics_body_2d.cpp
msgid ""
@@ -12543,23 +12522,29 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi về kích cỡ của RigidBody2d (trong chế độ Nhân vật hoặc Rắn) sẽ bị "
+"ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
msgstr ""
+"Thuộc tính Đường dẫn phải chỉ đến một nút Node2D hợp lệ thì mới hoạt động "
+"được."
#: scene/2d/skeleton_2d.cpp
msgid "This Bone2D chain should end at a Skeleton2D node."
-msgstr ""
+msgstr "Chuỗi Bone2D này phải kết thúc với một nút Skeleton2D."
#: scene/2d/skeleton_2d.cpp
msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
msgstr ""
+"Bone2D chỉ hoạt động khi là con một nút Skeleton2D hoặc một Bone2D khác ."
#: scene/2d/skeleton_2d.cpp
msgid ""
"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
-msgstr ""
+msgstr "Thanh xương này thiếu dáng NGHỈ. Hãy đặt một dáng tại nút Skeleton2D."
#: scene/2d/tile_map.cpp
msgid ""
@@ -12576,11 +12561,11 @@ msgstr ""
#: scene/3d/arvr_nodes.cpp
msgid "ARVRCamera must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRCamera phải là con nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRController must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRController phải là con nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid ""
@@ -12590,29 +12575,32 @@ msgstr ""
#: scene/3d/arvr_nodes.cpp
msgid "ARVRAnchor must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRAnchor phải là con của nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid ""
"The anchor ID must not be 0 or this anchor won't be bound to an actual "
"anchor."
msgstr ""
+"ID của neo phải là 0, nếu không thì neo này sẽ không bị ràng buộc với neo "
+"thực."
#: scene/3d/arvr_nodes.cpp
msgid "ARVROrigin requires an ARVRCamera child node."
-msgstr ""
+msgstr "ARVROrigin cần một nút con ARVRCamera."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
+#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr ""
+msgstr "Đang xử lí hình học (%s/%d)"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing environment"
-msgstr ""
+msgstr "Xử lí môi trường"
#: scene/3d/baked_lightmap.cpp
msgid "Generating capture"
@@ -12624,7 +12612,7 @@ msgstr ""
#: scene/3d/baked_lightmap.cpp
msgid "Done"
-msgstr ""
+msgstr "Xong"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12632,6 +12620,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"Nút này không có hình dạng, vì vậy nó không thể va chạm hoặc tương tác với "
+"các đối tượng khác.\n"
+"Hãy thêm một nút con CollisionShape hoặc CollisionPolygon để xác định hình "
+"dạng của nó."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12639,10 +12631,13 @@ msgid ""
"CollisionObject derived node. Please only use it as a child of Area, "
"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
msgstr ""
+"CollisionPolygon chỉ nhằm mục đích cung cấp khối va chạm cho một nút kế thừa "
+"CollisionObject. Hãy dùng nó làm nút con của Area, StaticBody, RigidBody, "
+"KinematicBody,... để tạo hình cho chúng."
#: scene/3d/collision_polygon.cpp
msgid "An empty CollisionPolygon has no effect on collision."
-msgstr ""
+msgstr "CollisionPolygon rỗng sẽ chẳng ích gì trong va chạm."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12650,27 +12645,35 @@ msgid ""
"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
"KinematicBody, etc. to give them a shape."
msgstr ""
+"CollisionShape chỉ nhằm mục đích cung cấp khối va chạm cho nút kế thừa từ "
+"CollisionObject. Hãy dùng nó làm nút con cho Area, StaticBody, RigidBody, "
+"KinematicBody, v.v. để tạo hình cho chúng."
#: scene/3d/collision_shape.cpp
msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
+"Một hình phải được cung cấp CollisionShape thì mới hoạt động. Hãy tạo cho nó "
+"một cái."
#: scene/3d/collision_shape.cpp
msgid ""
"Plane shapes don't work well and will be removed in future versions. Please "
"don't use them."
msgstr ""
+"Hình phẳng không chạy tốt và sẽ bị bãi bõ trong tương lai. Đừng dùng chúng."
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape không hỗ trợ RigidBody ở bất kì chế độ nào khác ngoài "
+"chế độ Tĩnh."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
-msgstr ""
+msgstr "Không có gì hiển thị vì không có lưới nào được chỉ định."
#: scene/3d/cpu_particles.cpp
msgid ""
@@ -12692,24 +12695,21 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
#: scene/3d/navigation_mesh.cpp
msgid "A NavigationMesh resource must be set or created for this node to work."
-msgstr ""
+msgstr "Phải tạo hoặc đặt một NavigationMesh cho nút này thì nó mới hoạt động."
#: scene/3d/navigation_mesh.cpp
msgid ""
"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
"It only provides navigation data."
msgstr ""
+"NavigationMeshInstance phải là nút con hoặc cháu một nút Navigation. Nó chỉ "
+"cung cấp dữ liệu điều hướng."
#: scene/3d/particles.cpp
msgid ""
@@ -12745,6 +12745,9 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi về kích cỡ của RigidBody2d (trong chế độ Nhân vật hoặc Rắn) sẽ bị "
+"ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
@@ -12782,6 +12785,8 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi về kích cỡ của SoftBody sẽ bị ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -12863,7 +12868,7 @@ msgstr ""
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
-msgstr "Chọn một màu từ cửa sổ biên tập"
+msgstr "Chọn một màu từ cửa sổ biên tập."
#: scene/gui/color_picker.cpp
msgid "HSV"
@@ -12964,7 +12969,7 @@ msgstr ""
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
-msgstr "nguồn vô hiệu cho xem trước"
+msgstr "Nguồn vô hiệu cho xem trước."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for shader."
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index 938981d022..e5826da638 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -43,7 +43,7 @@
# Song DongHui <14729626293@163.com>, 2019.
# simano clio <sim2cle@gmail.com>, 2019.
# ByonkoGalilei <byonko@qq.com>, 2019.
-# qjyqjyqjyqjy <qjyqjyqjyqjy@sina.com.cn>, 2019.
+# qjyqjyqjyqjy <qjyqjyqjyqjy@sina.com.cn>, 2019, 2021.
# liushuyu011 <liushuyu011@gmail.com>, 2019.
# DS <dseqrasd@126.com>, 2019.
# ZeroAurora <zeroaurora@qq.com>, 2019.
@@ -71,15 +71,18 @@
# MintSoda <lionlxh@qq.com>, 2020.
# Gardner Belgrade <hapenia@sina.com>, 2020.
# godhidden <z2zz2zz@yahoo.com>, 2020.
-# BinotaLIU <me@binota.org>, 2020.
+# BinotaLIU <me@binota.org>, 2020, 2021.
# TakWolf <takwolf@foxmail.com>, 2020.
# twoBornottwoB <305766341@qq.com>, 2021.
# Magian <magian1127@gmail.com>, 2021.
+# Weiduo Xie <xwditfr@gmail.com>, 2021.
+# suplife <2634557184@qq.com>, 2021.
+# luoji <564144019@qq.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2021-01-27 23:21+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -88,7 +91,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -97,13 +100,13 @@ msgstr "convert() 的参数类型无效,请使用 TYPE_* 常量。"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "应为长度 1 的字符串(1 字符)。"
+msgstr "应为长度为 1 的字符串(1 字符)。"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "没有足够的字节可解码或格式无效。"
+msgstr "解码字节数不够,或格式无效。"
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -709,7 +712,7 @@ msgstr "选择要复制的轨道"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "复制"
@@ -788,7 +791,7 @@ msgstr "标准"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr "开启/关闭脚本面板"
+msgstr "切换脚本面板"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -1374,7 +1377,7 @@ msgstr "总线选项"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "拷贝"
+msgstr "制作副本"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -1897,8 +1900,8 @@ msgid "Open a File or Directory"
msgstr "打开文件或目录"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "保存"
@@ -2553,8 +2556,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "无法在 “%s” 上启用加载项插件:配置解析失败。"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "无法在 “res://addons/%s” 中找到加载项插件的脚本字段。"
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "无法在 “%s” 上找到加载项的 script 字段。"
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2694,7 +2697,7 @@ msgstr "专注模式"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr "进入/离开专注模式。"
+msgstr "切换专注模式。"
#: editor/editor_node.cpp
msgid "Add a new scene."
@@ -2934,7 +2937,7 @@ msgstr "截图将保存在编辑器数据或设置文件夹中。"
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "进入/离开全屏模式"
+msgstr "切换全屏模式"
#: editor/editor_node.cpp
msgid "Toggle System Console"
@@ -2965,14 +2968,6 @@ msgid "Help"
msgstr "帮助"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "搜索"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "在线文档"
@@ -3134,6 +3129,24 @@ msgid "Open & Run a Script"
msgstr "打开并运行脚本"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"磁盘中的下列文件较新。\n"
+"应该执行什么操作?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "重新加载"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "重新保存"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "新建继承"
@@ -3340,7 +3353,7 @@ msgstr "唯一化"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "粘贴"
@@ -3648,6 +3661,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "状态:导入文件失败。请手动修复文件后重新导入。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "该文件的导入已被禁用,因此不能打开进行编辑。"
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "无法移动或重命名根资源。"
@@ -4032,6 +4050,22 @@ msgstr "有在 `post_import()` 方法中返回继承了 Node 的对象吗?"
msgid "Saving..."
msgstr "保存中..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "选择导入器"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "导入器:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "重置为默认值"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "保留文件(不导入)"
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d 个文件"
@@ -4692,7 +4726,7 @@ msgstr "过渡已存在!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
-msgstr "添加转换"
+msgstr "添加过渡"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -4733,7 +4767,7 @@ msgstr "节点已移除"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition Removed"
-msgstr "转换已移除"
+msgstr "过渡已移除"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
@@ -4956,7 +4990,7 @@ msgstr "无法将响应保存到:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr "写错误。"
+msgstr "写入错误。"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, too many redirects"
@@ -4987,7 +5021,7 @@ msgid "Got:"
msgstr "获得:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr "SHA-256 哈希值校验失败"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5091,7 +5125,6 @@ msgid "Sort:"
msgstr "排序:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "分类:"
@@ -5159,7 +5192,7 @@ msgstr "烘焙光照贴图"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
-msgstr "选择光照贴图烘焙文件:"
+msgstr "选择光照贴图烘焙文件:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5172,11 +5205,11 @@ msgstr "设置吸附"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr "网格偏移量:"
+msgstr "网格偏移:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr "网格大小:"
+msgstr "网格步长:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
@@ -5188,11 +5221,11 @@ msgstr "步"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr "旋转偏移量:"
+msgstr "旋转偏移:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr "旋转步长:"
+msgstr "旋转步长:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Step:"
@@ -5812,7 +5845,7 @@ msgstr "发射色彩"
#: editor/plugins/cpu_particles_editor_plugin.cpp
msgid "CPUParticles"
-msgstr "CPUParticles"
+msgstr "CPU粒子"
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -5826,11 +5859,11 @@ msgstr "从节点创建发射点"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Flat 0"
-msgstr "Flat 0"
+msgstr "平面 0"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Flat 1"
-msgstr "Flat 1"
+msgstr "平面 1"
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
msgid "Ease In"
@@ -5894,7 +5927,7 @@ msgstr "鼠标右键添加点"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
-msgstr "烘培 GI 探针"
+msgstr "烘焙 GI 探针"
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
@@ -5990,7 +6023,7 @@ msgstr "网格没有可用来创建轮廓的表面!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
-msgstr "Mesh 原始类型不是 PRIMITIVE_TRIANGLES!"
+msgstr "网格的原始类型不是 PRIMITIVE_TRIANGLES!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Could not create outline!"
@@ -6154,7 +6187,7 @@ msgstr "表面的源无效(路径无效)。"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Surface source is invalid (no geometry)."
-msgstr "表面的源无效(无几何)。"
+msgstr "表面的源无效(无几何体)。"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Surface source is invalid (no faces)."
@@ -6194,7 +6227,7 @@ msgstr "Y 轴"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Z-Axis"
-msgstr "Z轴"
+msgstr "Z 轴"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh Up Axis:"
@@ -6240,7 +6273,7 @@ msgstr "只可设为指向 ParticlesMaterial 处理材料"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Convert to CPUParticles2D"
-msgstr "转换为CPUParticles2D"
+msgstr "转换为 CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6269,7 +6302,7 @@ msgstr "“%s” 不包含面几何体。"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Create Emitter"
-msgstr "创建发射器 (Emitter)"
+msgstr "创建发射器"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Emission Points:"
@@ -6886,6 +6919,14 @@ msgstr "关闭文档"
msgid "Run"
msgstr "运行"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "搜索"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "单步进入"
@@ -6939,16 +6980,6 @@ msgstr ""
"磁盘中的下列文件已更新。\n"
"请选择执行哪项操作?:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "重新加载"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "重新保存"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "调试器"
@@ -7041,8 +7072,8 @@ msgstr "断点"
msgid "Go To"
msgstr "转到"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "剪切"
@@ -7265,9 +7296,8 @@ msgid "Yaw"
msgstr "偏航角"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "大小: "
+msgstr "大小"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7451,6 +7481,11 @@ msgstr "锁定视角旋转"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7473,7 +7508,7 @@ msgstr ""
"\n"
"睁眼:Gizmo 可见。\n"
"闭眼:Gizmo 隐藏。\n"
-"半睁眼:Gizmo 也可穿过不透明的表面可见(“X-Ray - X 光”)。"
+"半睁眼:Gizmo 也可穿过不透明的表面可见(“X 光”)。"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7637,7 +7672,7 @@ msgstr "修改变换"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate:"
-msgstr "移动:"
+msgstr "移动:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate (deg.):"
@@ -7902,7 +7937,7 @@ msgstr "自动裁剪"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr "偏移量:"
+msgstr "偏移:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
@@ -8599,7 +8634,7 @@ msgstr "标量"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
-msgstr "矢量"
+msgstr "向量"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
@@ -9159,11 +9194,11 @@ msgid ""
"whose number of rows is the number of components in 'c' and whose number of "
"columns is the number of components in 'r'."
msgstr ""
-"计算一对矢量的外积。\n"
+"计算一对向量的外积。\n"
"\n"
-"OuterProduct 将第一个参数 “c” 视为列矢量(包含一列的矩阵),将第二个参数 “r” "
-"视为行矢量(具有一行的矩阵),并执行线性代数矩阵乘以 “c * r”,生成行数为 “c” "
-"中的组件,其列数是 “r” 中的组件数。"
+"OuterProduct 将第一个参数 “c” 视为列向量(只有一列的矩阵),将第二个参数 “r” "
+"视为行向量(只有一行的矩阵),并执行线性代数矩阵乘法 “c * r”。所生成的矩阵"
+"中,行数为 “c” 中元素的数量,列数为 “r” 中元素的数量。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
@@ -9203,7 +9238,7 @@ msgstr "变换统一。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector function."
-msgstr "向量功能。"
+msgstr "向量函数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9219,7 +9254,7 @@ msgstr "将向量分解为三个标量。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr "计算两个向量的叉乘。"
+msgstr "计算两个向量的叉积。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
@@ -9227,7 +9262,7 @@ msgstr "返回两点之间的距离。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the dot product of two vectors."
-msgstr "计算两个向量的点乘。"
+msgstr "计算两个向量的点积。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9237,7 +9272,7 @@ msgid ""
"Nref is smaller than zero the return value is N. Otherwise -N is returned."
msgstr ""
"返回指向与参考向量相同方向的向量。该函数有三个向量参数:N,方向向量;I,入射"
-"向量;Nref,参考向量。如果 I 和 Nref 的点乘小于零,返回值为 N,否则返回 -N。"
+"向量;Nref,参考向量。如果 I 和 Nref 的点积小于零,返回值为 N,否则返回 -N。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the length of a vector."
@@ -9249,7 +9284,7 @@ msgstr "两个向量之间的线性插值。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two vectors using scalar."
-msgstr "使用标量的两个矢量之间的线性插值。"
+msgstr "使用标量在两个向量之间进行线性插值。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the normalize product of vector."
@@ -9271,7 +9306,7 @@ msgstr "返回指向反射方向的向量(a:入射向量,b:法向量)
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the vector that points in the direction of refraction."
-msgstr "返回指向折射方向的矢量。"
+msgstr "返回指向折射方向的向量。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9382,13 +9417,13 @@ msgstr "(仅限片段/光照模式)标量导数函数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Vector derivative function."
-msgstr "(仅限片段/灯光模式)矢量导数功能。"
+msgstr "(仅限片段/光照模式)向量导数函数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
"differencing."
-msgstr "(仅限片段/光照模式)(矢量)使用局部差分的 “x” 中的导数。"
+msgstr "(仅限片段/光照模式)(向量)使用局部差分的 “x” 中的导数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9400,7 +9435,7 @@ msgstr "(仅限片段/光照模式)(标量)使用本地差分的“ x”
msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
"differencing."
-msgstr "(仅适用于片段/光照模式)(矢量)使用局部差分的'y'导数。"
+msgstr "(仅适用于片段/光照模式)(向量)使用局部差分的'y'导数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9895,6 +9930,10 @@ msgid "Projects"
msgstr "项目"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "正在加载,请稍候..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "修改时间"
@@ -10260,6 +10299,10 @@ msgstr "自动加载"
msgid "Plugins"
msgstr "插件"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "默认导入设置"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "预设..."
@@ -10507,6 +10550,14 @@ msgid "Instance Child Scene"
msgstr "实例化子场景"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "不能将根节点粘贴进相同场景。"
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "粘贴节点"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "分离脚本"
@@ -10629,6 +10680,10 @@ msgid "Attach Script"
msgstr "添加脚本"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "剪切节点"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "移除节点"
@@ -10738,6 +10793,13 @@ msgid "Remote"
msgstr "远程"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "本地"
@@ -11465,7 +11527,7 @@ msgstr "内部异常堆栈追朔结束"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Bake NavMesh"
-msgstr "烘焙导航网"
+msgstr "烘焙导航网格"
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Clear the navigation mesh."
@@ -12240,6 +12302,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "空的 CollisionPolygon2D 不起任何碰撞检测作用。"
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "多边形无效。“Solids”构建模式需要至少三个点。"
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "多边形无效。“Segments”构建模式需要至少两个点。"
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12526,11 +12596,6 @@ msgstr ""
"GLES2 视频驱动程序不支持 GIProbes。\n"
"请改用 BakedLightmap。"
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera 已废弃,将在 Godot 4.0 中删除。"
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "角度宽于 90 度的 SpotLight 无法投射出阴影。"
@@ -12855,6 +12920,10 @@ msgstr "变量只能在顶点函数中指定。"
msgid "Constants cannot be modified."
msgstr "不允许修改常量。"
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera 已废弃,将在 Godot 4.0 中删除。"
+
#~ msgid "No"
#~ msgstr "否"
@@ -14502,9 +14571,6 @@ msgstr "不允许修改常量。"
#~ msgid "Use Default Light"
#~ msgstr "使用默认光照"
-#~ msgid "Use Default sRGB"
-#~ msgstr "使用默认sRGB"
-
#~ msgid "Default Light Normal:"
#~ msgstr "默认光照法线:"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 70487c165e..37e8f6ab61 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -682,7 +682,7 @@ msgstr "選擇模式"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "複製"
@@ -1922,8 +1922,8 @@ msgid "Open a File or Directory"
msgstr "選擇資料夾/檔案"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "儲存"
@@ -2598,8 +2598,9 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr ""
+#, fuzzy
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "載入字形出現錯誤"
#: editor/editor_node.cpp
#, fuzzy
@@ -3029,14 +3030,6 @@ msgid "Help"
msgstr "幫助"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "搜尋"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
#, fuzzy
msgid "Online Docs"
@@ -3199,6 +3192,22 @@ msgid "Open & Run a Script"
msgstr ""
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "New Inherited"
msgstr "下一個腳本"
@@ -3416,7 +3425,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "貼上"
@@ -3755,6 +3764,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "狀態:導入檔案失敗。請修正檔案並再手動導入。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "不能移動/重新命名 resources root."
@@ -4164,6 +4178,25 @@ msgstr ""
msgid "Saving..."
msgstr "儲存中..."
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Select Importer"
+msgstr "選擇模式"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Importer:"
+msgstr "導入"
+
+#: editor/import_defaults_editor.cpp
+#, fuzzy
+msgid "Reset to Defaults"
+msgstr "預設"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
@@ -5190,7 +5223,7 @@ msgid "Got:"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5304,7 +5337,6 @@ msgid "Sort:"
msgstr "排序:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "分類:"
@@ -7164,6 +7196,14 @@ msgstr "關閉場景"
msgid "Run"
msgstr "運行"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "搜尋"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr ""
@@ -7218,16 +7258,6 @@ msgid ""
"What action should be taken?:"
msgstr ""
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr ""
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr ""
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr ""
@@ -7329,8 +7359,8 @@ msgstr "刪除"
msgid "Go To"
msgstr ""
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "剪下"
@@ -7764,6 +7794,11 @@ msgstr "本地化"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10255,6 +10290,11 @@ msgid "Projects"
msgstr "專案"
#: editor/project_manager.cpp
+#, fuzzy
+msgid "Loading, please wait..."
+msgstr "接收 mirrors中, 請稍侯..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr ""
@@ -10631,6 +10671,11 @@ msgstr ""
msgid "Plugins"
msgstr "插件"
+#: editor/project_settings_editor.cpp
+#, fuzzy
+msgid "Import Defaults"
+msgstr "預設"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr ""
@@ -10889,6 +10934,15 @@ msgid "Instance Child Scene"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Paste Node(s)"
+msgstr "貼上"
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Detach Script"
msgstr "腳本"
@@ -11023,6 +11077,11 @@ msgid "Attach Script"
msgstr "腳本"
#: editor/scene_tree_dock.cpp
+#, fuzzy
+msgid "Cut Node(s)"
+msgstr "貼上"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr ""
@@ -11139,6 +11198,13 @@ msgid "Remote"
msgstr "移除"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12709,6 +12775,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr ""
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12966,11 +13040,6 @@ msgid ""
"Use a BakedLightmap instead."
msgstr ""
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr ""
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
@@ -13455,10 +13524,6 @@ msgstr ""
#~ msgstr "新增資料夾"
#, fuzzy
-#~ msgid "Custom Node"
-#~ msgstr "貼上"
-
-#, fuzzy
#~ msgid "Invalid Path"
#~ msgstr "有效的路徑"
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 1dbca29941..50b323130e 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -29,7 +29,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-27 23:21+0000\n"
+"PO-Revision-Date: 2021-03-16 10:40+0000\n"
"Last-Translator: BinotaLIU <me@binota.org>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
@@ -38,7 +38,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.5.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -659,7 +659,7 @@ msgstr "選擇軌道以複製"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
msgstr "複製"
@@ -1851,8 +1851,8 @@ msgid "Open a File or Directory"
msgstr "開啟檔案或資料夾"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
-#: editor/editor_properties.cpp editor/inspector_dock.cpp
-#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
msgstr "保存"
@@ -2505,8 +2505,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "無法在「%s」上啟用擴充功能,解析組態設定失敗。"
#: editor/editor_node.cpp
-msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "無法在擴充功能「res://addons/%s」中無法找到腳本欄位。"
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr "無法在擴充功能「r%s」中找到腳本欄位。"
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2917,14 +2917,6 @@ msgid "Help"
msgstr "說明"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/script_text_editor.cpp
-#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
-#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
-#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
-msgid "Search"
-msgstr "搜尋"
-
-#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Online Docs"
msgstr "線上說明文件"
@@ -3086,6 +3078,24 @@ msgid "Open & Run a Script"
msgstr "開啟並執行腳本"
#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+"磁碟中的下列檔案已更新。\n"
+"要執行什麼操作?"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr "重新載入"
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr "重新保存"
+
+#: editor/editor_node.cpp
msgid "New Inherited"
msgstr "新增繼承"
@@ -3292,7 +3302,7 @@ msgstr "獨立化"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
-#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
msgstr "貼上"
@@ -3600,6 +3610,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "狀態:檔案匯入失敗。請修正檔案並手動重新匯入。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "無法移動或重新命名根資源。"
@@ -3984,6 +3999,22 @@ msgstr "是否有在 `post_import()` 方法內回傳繼承 Node 之物件?"
msgid "Saving..."
msgstr "正在保存..."
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr "選擇匯入程式"
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr "匯入程式:"
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr "重設為預設"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d 個檔案"
@@ -4939,7 +4970,7 @@ msgid "Got:"
msgstr "獲得:"
#: editor/plugins/asset_library_editor_plugin.cpp
-msgid "Failed sha256 hash check"
+msgid "Failed SHA-256 hash check"
msgstr "SHA-256 雜湊檢查失敗"
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -5043,7 +5074,6 @@ msgid "Sort:"
msgstr "排序:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#: editor/project_settings_editor.cpp
msgid "Category:"
msgstr "分類:"
@@ -6839,6 +6869,14 @@ msgstr "關閉說明文件"
msgid "Run"
msgstr "執行"
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr "搜尋"
+
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
msgstr "逐步執行"
@@ -6892,16 +6930,6 @@ msgstr ""
"磁碟中的下列檔案已更新。\n"
"請選擇於執行之操作:"
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Reload"
-msgstr "重新載入"
-
-#: editor/plugins/script_editor_plugin.cpp
-#: editor/plugins/shader_editor_plugin.cpp
-msgid "Resave"
-msgstr "重新保存"
-
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
msgstr "除錯工具"
@@ -6994,8 +7022,8 @@ msgstr "中斷點"
msgid "Go To"
msgstr "跳至"
-#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
-#: scene/gui/text_edit.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
msgstr "剪下"
@@ -7218,9 +7246,8 @@ msgid "Yaw"
msgstr "偏航"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "大小: "
+msgstr "大小"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7404,6 +7431,11 @@ msgstr "視圖旋轉已鎖定"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9849,6 +9881,10 @@ msgid "Projects"
msgstr "專案"
#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr "載入中,請稍後..."
+
+#: editor/project_manager.cpp
msgid "Last Modified"
msgstr "最後修改時間"
@@ -10213,6 +10249,10 @@ msgstr "Autoload"
msgid "Plugins"
msgstr "外掛"
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr "匯入預設"
+
#: editor/property_editor.cpp
msgid "Preset..."
msgstr "預設設定..."
@@ -10460,6 +10500,14 @@ msgid "Instance Child Scene"
msgstr "實體化子場景"
#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr "無法將跟節點貼到相同的場景中。"
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr "貼上節點"
+
+#: editor/scene_tree_dock.cpp
msgid "Detach Script"
msgstr "取消附加腳本"
@@ -10582,6 +10630,10 @@ msgid "Attach Script"
msgstr "附加腳本"
#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr "剪下節點"
+
+#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
msgstr "移除節點"
@@ -10691,6 +10743,13 @@ msgid "Remote"
msgstr "遠端"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "本機"
@@ -12197,6 +12256,14 @@ msgstr ""
msgid "An empty CollisionPolygon2D has no effect on collision."
msgstr "空白的 CollisionPolygon2D 不會產生任何碰撞效果。"
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr "無效的多邊形。至少必須有三個點為「Solids」建構模式。"
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr "無效的多邊形。至少必須有 2 個點為「Segments」建構模式。"
+
#: scene/2d/collision_shape_2d.cpp
msgid ""
"CollisionShape2D only serves to provide a collision shape to a "
@@ -12482,11 +12549,6 @@ msgstr ""
"GLES2 視訊驅動程式不支援 GIProbes。\n"
"請改為使用 BakedLightmap。"
-#: scene/3d/interpolated_camera.cpp
-msgid ""
-"InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
-msgstr "InterpolatedCamera 已停止維護,且將於 Godot 4.0 中移除。"
-
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr "角度大於 90 度的 SpotLight 無法投射出陰影。"
@@ -12812,6 +12874,10 @@ msgstr "Varying 變數只可在頂點函式中指派。"
msgid "Constants cannot be modified."
msgstr "不可修改常數。"
+#~ msgid ""
+#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
+#~ msgstr "InterpolatedCamera 已停止維護,且將於 Godot 4.0 中移除。"
+
#~ msgid "No"
#~ msgstr "否"
diff --git a/main/main.cpp b/main/main.cpp
index d70f0eb291..bb16c49983 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -71,7 +71,6 @@
#include "servers/physics_server_3d.h"
#include "servers/register_server_types.h"
#include "servers/rendering/rendering_server_default.h"
-#include "servers/rendering/rendering_server_wrap_mt.h"
#include "servers/text_server.h"
#include "servers/xr_server.h"
@@ -124,7 +123,9 @@ static bool _start_success = false;
// Drivers
+String tablet_driver = "";
String text_driver = "";
+
static int text_driver_idx = -1;
static int display_driver_idx = -1;
static int audio_driver_idx = -1;
@@ -330,13 +331,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n");
OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n");
OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n");
- OS::get_singleton()->print(" --tablet-driver Tablet input driver (");
- for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) {
- if (i != 0)
- OS::get_singleton()->print(", ");
- OS::get_singleton()->print("'%s'", OS::get_singleton()->get_tablet_driver_name(i).utf8().get_data());
- }
- OS::get_singleton()->print(") (Windows only).\n");
+ OS::get_singleton()->print(" --tablet-driver Pen tablet input driver.\n");
OS::get_singleton()->print("\n");
#endif
@@ -370,7 +365,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n");
OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
- OS::get_singleton()->print(" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
+ OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
#ifdef DEBUG_METHODS_ENABLED
@@ -380,8 +375,8 @@ void Main::print_help(const char *p_binary) {
#ifdef TESTS_ENABLED
OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n");
#endif
- OS::get_singleton()->print("\n");
#endif
+ OS::get_singleton()->print("\n");
}
#ifdef TESTS_ENABLED
@@ -395,11 +390,15 @@ Error Main::test_setup() {
register_core_types();
register_core_driver_types();
+ packed_data = memnew(PackedData);
+
globals = memnew(ProjectSettings);
GLOBAL_DEF("debug/settings/crash_handler/message",
String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
+ translation_server = memnew(TranslationServer);
+
// From `Main::setup2()`.
preregister_module_types();
preregister_server_types();
@@ -407,6 +406,16 @@ Error Main::test_setup() {
register_core_singletons();
register_server_types();
+
+ translation_server->setup(); //register translations, load them, etc.
+ if (locale != "") {
+ translation_server->set_locale(locale);
+ }
+ translation_server->load_translations();
+ ResourceLoader::load_translation_remaps(); //load remaps for resources
+
+ ResourceLoader::load_path_remaps();
+
register_scene_types();
#ifdef TOOLS_ENABLED
@@ -446,9 +455,15 @@ void Main::test_cleanup() {
OS::get_singleton()->finalize();
+ if (translation_server) {
+ memdelete(translation_server);
+ }
if (globals) {
memdelete(globals);
}
+ if (packed_data) {
+ memdelete(packed_data);
+ }
if (engine) {
memdelete(engine);
}
@@ -516,10 +531,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
MAIN_PRINT("Main: Initialize Globals");
- globals = memnew(ProjectSettings);
input_map = memnew(InputMap);
+ globals = memnew(ProjectSettings);
- register_core_settings(); //here globals is present
+ register_core_settings(); //here globals are present
translation_server = memnew(TranslationServer);
performance = memnew(Performance);
@@ -528,8 +543,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Only flush stdout in debug builds by default, as spamming `print()` will
// decrease performance if this is enabled.
- GLOBAL_DEF("application/run/flush_stdout_on_print", false);
- GLOBAL_DEF("application/run/flush_stdout_on_print.debug", true);
+ GLOBAL_DEF_RST("application/run/flush_stdout_on_print", false);
+ GLOBAL_DEF_RST("application/run/flush_stdout_on_print.debug", true);
GLOBAL_DEF("debug/settings/crash_handler/message",
String("Please include this when reporting the bug on https://github.com/godotengine/godot/issues"));
@@ -557,7 +572,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
String display_driver = "";
String audio_driver = "";
- String tablet_driver = "";
String project_path = ".";
bool upwards = false;
String debug_uri = "";
@@ -726,19 +740,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--tablet-driver") {
if (I->next()) {
tablet_driver = I->next()->get();
- bool found = false;
- for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) {
- if (tablet_driver == OS::get_singleton()->get_tablet_driver_name(i)) {
- found = true;
- }
- }
-
- if (!found) {
- OS::get_singleton()->print("Unknown tablet driver '%s', aborting.\n",
- tablet_driver.utf8().get_data());
- goto error;
- }
-
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing tablet driver argument, aborting.\n");
@@ -1126,29 +1127,29 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
#endif
- GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
+ GLOBAL_DEF("debug/file_logging/enable_file_logging", false);
// Only file logging by default on desktop platforms as logs can't be
// accessed easily on mobile/Web platforms (if at all).
// This also prevents logs from being created for the editor instance, as feature tags
// are disabled while in the editor (even if they should logically apply).
- GLOBAL_DEF("logging/file_logging/enable_file_logging.pc", true);
- GLOBAL_DEF("logging/file_logging/log_path", "user://logs/godot.log");
- GLOBAL_DEF("logging/file_logging/max_log_files", 5);
- ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files",
+ GLOBAL_DEF("debug/file_logging/enable_file_logging.pc", true);
+ GLOBAL_DEF("debug/file_logging/log_path", "user://logs/godot.log");
+ GLOBAL_DEF("debug/file_logging/max_log_files", 5);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/file_logging/max_log_files",
PropertyInfo(Variant::INT,
- "logging/file_logging/max_log_files",
+ "debug/file_logging/max_log_files",
PROPERTY_HINT_RANGE,
"0,20,1,or_greater")); //no negative numbers
if (!project_manager && !editor && FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) &&
- GLOBAL_GET("logging/file_logging/enable_file_logging")) {
+ GLOBAL_GET("debug/file_logging/enable_file_logging")) {
// Don't create logs for the project manager as they would be written to
// the current working directory, which is inconvenient.
- String base_path = GLOBAL_GET("logging/file_logging/log_path");
- int max_files = GLOBAL_GET("logging/file_logging/max_log_files");
+ String base_path = GLOBAL_GET("debug/file_logging/log_path");
+ int max_files = GLOBAL_GET("debug/file_logging/max_log_files");
OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files)));
}
- if (main_args.size() == 0 && String(GLOBAL_DEF("application/run/main_scene", "")) == "") {
+ if (main_args.size() == 0 && String(GLOBAL_GET("application/run/main_scene")) == "") {
#ifdef TOOLS_ENABLED
if (!editor && !project_manager) {
#endif
@@ -1178,30 +1179,32 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
_print_line_enabled = false;
}
+ Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
+
OS::get_singleton()->set_cmdline(execpath, main_args);
- GLOBAL_DEF("rendering/quality/driver/driver_name", "Vulkan");
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name",
+ GLOBAL_DEF("rendering/driver/driver_name", "Vulkan");
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
PropertyInfo(Variant::STRING,
- "rendering/quality/driver/driver_name",
+ "rendering/driver/driver_name",
PROPERTY_HINT_ENUM, "Vulkan"));
if (display_driver == "") {
- display_driver = GLOBAL_GET("rendering/quality/driver/driver_name");
+ display_driver = GLOBAL_GET("rendering/driver/driver_name");
}
- GLOBAL_DEF("display/window/size/width", 1024);
+ GLOBAL_DEF_BASIC("display/window/size/width", 1024);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width",
PropertyInfo(Variant::INT, "display/window/size/width",
PROPERTY_HINT_RANGE,
"0,7680,or_greater")); // 8K resolution
- GLOBAL_DEF("display/window/size/height", 600);
+ GLOBAL_DEF_BASIC("display/window/size/height", 600);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/height",
PropertyInfo(Variant::INT, "display/window/size/height",
PROPERTY_HINT_RANGE,
"0,4320,or_greater")); // 8K resolution
- GLOBAL_DEF("display/window/size/resizable", true);
- GLOBAL_DEF("display/window/size/borderless", false);
- GLOBAL_DEF("display/window/size/fullscreen", false);
+ GLOBAL_DEF_BASIC("display/window/size/resizable", true);
+ GLOBAL_DEF_BASIC("display/window/size/borderless", false);
+ GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
GLOBAL_DEF("display/window/size/test_width", 0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_width",
@@ -1249,7 +1252,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
}
- GLOBAL_DEF("display/window/force_right_to_left_layout_direction", false);
+ GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
+ GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
if (!force_lowdpi) {
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
@@ -1268,28 +1272,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor;
- if (tablet_driver == "") { // specified in project.godot
- tablet_driver = GLOBAL_DEF_RST_NOVAL("display/window/tablet_driver", OS::get_singleton()->get_tablet_driver_name(0));
- }
-
- for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) {
- if (tablet_driver == OS::get_singleton()->get_tablet_driver_name(i)) {
- OS::get_singleton()->set_current_tablet_driver(OS::get_singleton()->get_tablet_driver_name(i));
- break;
- }
- }
-
- if (tablet_driver == "") {
- OS::get_singleton()->set_current_tablet_driver(OS::get_singleton()->get_tablet_driver_name(0));
- }
-
/* todo restore
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false);
*/
- GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
- GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
-
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
@@ -1298,7 +1284,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_keep_screen_on = GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
if (rtm == -1) {
- rtm = GLOBAL_DEF("rendering/threads/thread_model", OS::RENDER_THREAD_SAFE);
+ rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE);
}
if (rtm >= 0 && rtm < 3) {
@@ -1326,7 +1312,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (audio_driver == "") { // specified in project.godot
- audio_driver = GLOBAL_DEF_RST_NOVAL("audio/driver", AudioDriverManager::get_driver(0)->get_name());
+ audio_driver = GLOBAL_DEF_RST_NOVAL("audio/driver/driver", AudioDriverManager::get_driver(0)->get_name());
}
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
@@ -1360,7 +1346,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
}
- Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
+ Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60));
ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
PropertyInfo(Variant::INT, "physics/common/physics_fps",
PROPERTY_HINT_RANGE, "1,120,1,or_greater"));
@@ -1477,9 +1463,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
/* Determine text driver */
- GLOBAL_DEF("display/window/text_name", "");
if (text_driver == "") {
- text_driver = GLOBAL_GET("display/window/text_name");
+ text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
}
if (text_driver != "") {
@@ -1508,7 +1493,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
}
}
- printf("Using %s text server...\n", TextServerManager::get_interface_name(text_driver_idx).utf8().get_data());
+ print_verbose("Using \"" + TextServerManager::get_interface_name(text_driver_idx) + "\" text server...");
/* Initialize Text Server */
@@ -1538,7 +1523,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
input = memnew(Input);
- /* Iniitalize Display Server */
+ /* Initialize Display Server */
{
String rendering_driver; // temp broken
@@ -1568,15 +1553,38 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
display_server->screen_set_orientation(window_orientation);
}
- /* Initialize Visual Server */
+ /* Initialize Pen Tablet Driver */
+
+ {
+ GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver", "");
+ GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver.Windows", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pen_tablet/driver.Windows", PropertyInfo(Variant::STRING, "input_devices/pen_tablet/driver.Windows", PROPERTY_HINT_ENUM, "wintab,winink"));
+ }
+
+ if (tablet_driver == "") { // specified in project.godot
+ tablet_driver = GLOBAL_GET("input_devices/pen_tablet/driver");
+ if (tablet_driver == "") {
+ tablet_driver = DisplayServer::get_singleton()->tablet_get_driver_name(0);
+ }
+ }
+
+ for (int i = 0; i < DisplayServer::get_singleton()->tablet_get_driver_count(); i++) {
+ if (tablet_driver == DisplayServer::get_singleton()->tablet_get_driver_name(i)) {
+ DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(i));
+ break;
+ }
+ }
- rendering_server = memnew(RenderingServerDefault);
- if (OS::get_singleton()->get_render_thread_mode() != OS::RENDER_THREAD_UNSAFE) {
- rendering_server = memnew(RenderingServerWrapMT(rendering_server,
- OS::get_singleton()->get_render_thread_mode() ==
- OS::RENDER_SEPARATE_THREAD));
+ if (DisplayServer::get_singleton()->tablet_get_current_driver() == "") {
+ DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(0));
}
+ print_verbose("Using \"" + tablet_driver + "\" pen tablet driver...");
+
+ /* Initialize Visual Server */
+
+ rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD));
+
rendering_server->init();
rendering_server->set_render_loop_enabled(!disable_render_loop);
@@ -1608,7 +1616,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Setup Logo");
-#ifdef JAVASCRIPT_ENABLED
+#if defined(JAVASCRIPT_ENABLED) || defined(ANDROID_ENABLED)
bool show_logo = false;
#else
bool show_logo = true;
@@ -1636,7 +1644,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Load Boot Image");
- Color clear = GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3));
+ Color clear = GLOBAL_DEF("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3));
RenderingServer::get_singleton()->set_default_clear_color(clear);
if (show_logo) { //boot logo!
@@ -1660,7 +1668,13 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
}
- Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
+#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
+ const Color boot_bg_color =
+ GLOBAL_DEF("application/boot_splash/bg_color",
+ (editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
+#else
+ const Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color);
+#endif
if (boot_logo.is_valid()) {
RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale,
boot_logo_filter);
@@ -1689,7 +1703,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: DCC");
RenderingServer::get_singleton()->set_default_clear_color(
- GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3)));
+ GLOBAL_DEF("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3)));
GLOBAL_DEF("application/config/icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon",
@@ -1742,6 +1756,19 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
register_scene_types();
+#ifdef TOOLS_ENABLED
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+ EditorNode::register_editor_types();
+
+ ClassDB::set_current_api(ClassDB::API_CORE);
+
+#endif
+
+ MAIN_PRINT("Main: Load Modules, Physics, Drivers, Scripts");
+
+ register_platform_apis();
+ register_module_types();
+
GLOBAL_DEF("display/mouse_cursor/custom_image", String());
GLOBAL_DEF("display/mouse_cursor/custom_image_hotspot", Vector2());
GLOBAL_DEF("display/mouse_cursor/tooltip_position_offset", Point2(10, 10));
@@ -1758,18 +1785,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
}
}
-#ifdef TOOLS_ENABLED
- ClassDB::set_current_api(ClassDB::API_EDITOR);
- EditorNode::register_editor_types();
-
- ClassDB::set_current_api(ClassDB::API_CORE);
-
-#endif
-
- MAIN_PRINT("Main: Load Modules, Physics, Drivers, Scripts");
-
- register_platform_apis();
- register_module_types();
camera_server = CameraServer::create();
@@ -1793,7 +1808,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (!project_manager) {
// If not running the project manager, and now that the engine is
// able to load resources, load the global shader variables.
- // If running on editor, dont load the textures because the editor
+ // If running on editor, don't load the textures because the editor
// may want to import them first. Editor will reload those later.
rendering_server->global_variables_load_settings(!editor);
}
@@ -1801,7 +1816,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
_start_success = true;
locale = String();
- ClassDB::set_current_api(ClassDB::API_NONE); //no more api is registered at this point
+ ClassDB::set_current_api(ClassDB::API_NONE); //no more APIs are registered at this point
print_verbose("CORE API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_CORE)));
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
@@ -1817,8 +1832,7 @@ bool Main::start() {
ERR_FAIL_COND_V(!_start_success, false);
bool hasicon = false;
- String doc_tool;
- List<String> removal_docs;
+ String doc_tool_path;
String positional_arg;
String game_path;
String script;
@@ -1872,9 +1886,11 @@ bool Main::start() {
script = args[i + 1];
#ifdef TOOLS_ENABLED
} else if (args[i] == "--doctool") {
- doc_tool = args[i + 1];
- for (int j = i + 2; j < args.size(); j++) {
- removal_docs.push_back(args[j]);
+ doc_tool_path = args[i + 1];
+ if (doc_tool_path.begins_with("-")) {
+ // Assuming other command line arg, so default to cwd.
+ doc_tool_path = ".";
+ parsed_pair = false;
}
} else if (args[i] == "--export") {
editor = true; //needs editor
@@ -1895,16 +1911,19 @@ bool Main::start() {
if (parsed_pair) {
i++;
}
+ } else if (args[i] == "--doctool") {
+ // Handle case where no path is given to --doctool.
+ doc_tool_path = ".";
}
}
#ifdef TOOLS_ENABLED
- if (doc_tool != "") {
+ if (doc_tool_path != "") {
Engine::get_singleton()->set_editor_hint(
true); // Needed to instance editor-only classes for their default values
{
- DirAccessRef da = DirAccess::open(doc_tool);
+ DirAccessRef da = DirAccess::open(doc_tool_path);
ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a valid directory path.");
}
@@ -1934,7 +1953,7 @@ bool Main::start() {
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths[i].path;
if (path.is_rel_path()) {
- path = doc_tool.plus_file(path);
+ path = doc_tool_path.plus_file(path);
}
String name = _doc_data_class_paths[i].name;
doc_data_classes[name] = path;
@@ -1951,7 +1970,7 @@ bool Main::start() {
}
}
- String index_path = doc_tool.plus_file("doc/classes");
+ String index_path = doc_tool_path.plus_file("doc/classes");
// Create the main documentation directory if it doesn't exist
DirAccess *da = DirAccess::create_for_path(index_path);
da->make_dir_recursive(index_path);
@@ -1976,8 +1995,8 @@ bool Main::start() {
#endif
- if (script == "" && game_path == "" && String(GLOBAL_DEF("application/run/main_scene", "")) != "") {
- game_path = GLOBAL_DEF("application/run/main_scene", "");
+ if (script == "" && game_path == "" && String(GLOBAL_GET("application/run/main_scene")) != "") {
+ game_path = GLOBAL_GET("application/run/main_scene");
}
MainLoop *main_loop = nullptr;
@@ -1992,7 +2011,7 @@ bool Main::start() {
if (check_only) {
if (!script_res->is_valid()) {
- OS::get_singleton()->set_exit_code(1);
+ OS::get_singleton()->set_exit_code(EXIT_FAILURE);
}
return false;
}
@@ -2152,10 +2171,10 @@ bool Main::start() {
if (!editor && !project_manager) {
//standard helpers that can be changed from main config
- String stretch_mode = GLOBAL_DEF("display/window/stretch/mode", "disabled");
- String stretch_aspect = GLOBAL_DEF("display/window/stretch/aspect", "ignore");
- Size2i stretch_size = Size2i(GLOBAL_DEF("display/window/size/width", 0),
- GLOBAL_DEF("display/window/size/height", 0));
+ String stretch_mode = GLOBAL_DEF_BASIC("display/window/stretch/mode", "disabled");
+ String stretch_aspect = GLOBAL_DEF_BASIC("display/window/stretch/aspect", "ignore");
+ Size2i stretch_size = Size2i(GLOBAL_DEF_BASIC("display/window/size/width", 0),
+ GLOBAL_DEF_BASIC("display/window/size/height", 0));
Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
if (stretch_mode == "canvas_items") {
@@ -2195,30 +2214,30 @@ bool Main::start() {
bool snap_controls = GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
- bool font_oversampling = GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", true);
+ bool font_oversampling = GLOBAL_DEF("gui/fonts/dynamic_fonts/use_oversampling", true);
sml->get_root()->set_use_font_oversampling(font_oversampling);
- int texture_filter = GLOBAL_DEF("rendering/canvas_textures/default_texture_filter", 1);
- int texture_repeat = GLOBAL_DEF("rendering/canvas_textures/default_texture_repeat", 0);
+ int texture_filter = GLOBAL_DEF("rendering/textures/canvas_textures/default_texture_filter", 1);
+ int texture_repeat = GLOBAL_DEF("rendering/textures/canvas_textures/default_texture_repeat", 0);
sml->get_root()->set_default_canvas_item_texture_filter(
Viewport::DefaultCanvasItemTextureFilter(texture_filter));
sml->get_root()->set_default_canvas_item_texture_repeat(
Viewport::DefaultCanvasItemTextureRepeat(texture_repeat));
} else {
- GLOBAL_DEF("display/window/stretch/mode", "disabled");
+ GLOBAL_DEF_BASIC("display/window/stretch/mode", "disabled");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode",
PropertyInfo(Variant::STRING,
"display/window/stretch/mode",
PROPERTY_HINT_ENUM,
"disabled,canvas_items,viewport"));
- GLOBAL_DEF("display/window/stretch/aspect", "ignore");
+ GLOBAL_DEF_BASIC("display/window/stretch/aspect", "ignore");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect",
PropertyInfo(Variant::STRING,
"display/window/stretch/aspect",
PROPERTY_HINT_ENUM,
"ignore,keep,keep_width,keep_height,expand"));
- GLOBAL_DEF("display/window/stretch/shrink", 1.0);
+ GLOBAL_DEF_BASIC("display/window/stretch/shrink", 1.0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink",
PropertyInfo(Variant::FLOAT,
"display/window/stretch/shrink",
@@ -2226,18 +2245,18 @@ bool Main::start() {
"1.0,8.0,0.1"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
- GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
- GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", true);
+ GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
+ GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
- GLOBAL_DEF("rendering/canvas_textures/default_texture_filter", 1);
+ GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_filter", 1);
ProjectSettings::get_singleton()->set_custom_property_info(
- "rendering/canvas_textures/default_texture_filter",
- PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
+ "rendering/textures/canvas_textures/default_texture_filter",
+ PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
"Nearest,Linear,MipmapLinear,MipmapNearest"));
- GLOBAL_DEF("rendering/canvas_textures/default_texture_repeat", 0);
+ GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_repeat", 0);
ProjectSettings::get_singleton()->set_custom_property_info(
- "rendering/canvas_textures/default_texture_repeat",
- PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM,
+ "rendering/textures/canvas_textures/default_texture_repeat",
+ PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM,
"Disable,Enable,Mirror"));
}
@@ -2451,6 +2470,7 @@ bool Main::iteration() {
for (int iters = 0; iters < advance.physics_steps; ++iters) {
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
+ PhysicsServer3D::get_singleton()->sync();
PhysicsServer3D::get_singleton()->flush_queries();
PhysicsServer2D::get_singleton()->sync();
@@ -2465,6 +2485,7 @@ bool Main::iteration() {
message_queue->flush();
+ PhysicsServer3D::get_singleton()->end_sync();
PhysicsServer3D::get_singleton()->step(physics_step * time_scale);
PhysicsServer2D::get_singleton()->end_sync();
@@ -2522,10 +2543,10 @@ bool Main::iteration() {
if (frame > 1000000) {
if (editor || project_manager) {
if (print_fps) {
- print_line("Editor FPS: " + itos(frames));
+ print_line(vformat("Editor FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(1)));
}
} else if (GLOBAL_GET("debug/settings/stdout/print_fps") || print_fps) {
- print_line("Game FPS: " + itos(frames));
+ print_line(vformat("Project FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(1)));
}
Engine::get_singleton()->_fps = frames;
@@ -2574,8 +2595,10 @@ void Main::force_redraw() {
* so that the engine closes cleanly without leaking memory or crashing.
* The order matters as some of those steps are linked with each other.
*/
-void Main::cleanup() {
- ERR_FAIL_COND(!_start_success);
+void Main::cleanup(bool p_force) {
+ if (!p_force) {
+ ERR_FAIL_COND(!_start_success);
+ }
EngineDebugger::deinitialize();
@@ -2599,7 +2622,7 @@ void Main::cleanup() {
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
RenderingServer::get_singleton()->sync();
- //clear global shader variables before scene and other graphics stuff is deinitialized.
+ //clear global shader variables before scene and other graphics stuff are deinitialized.
rendering_server->global_variables_clear();
#ifdef TOOLS_ENABLED
diff --git a/main/main.h b/main/main.h
index 9e606c188d..f4fff6b97e 100644
--- a/main/main.h
+++ b/main/main.h
@@ -59,7 +59,7 @@ public:
static bool is_iterating();
- static void cleanup();
+ static void cleanup(bool p_force = false);
};
// Test main override is for the testing behaviour.
diff --git a/main/main_builders.py b/main/main_builders.py
index aa91201c3e..c880bfa3c4 100644
--- a/main/main_builders.py
+++ b/main/main_builders.py
@@ -17,6 +17,7 @@ def make_splash(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef BOOT_SPLASH_H\n")
g.write("#define BOOT_SPLASH_H\n")
+ # Use a neutral gray color to better fit various kinds of projects.
g.write("static const Color boot_splash_bg_color = Color(0.14, 0.14, 0.14);\n")
g.write("static const unsigned char boot_splash_png[] = {\n")
for i in range(len(buf)):
@@ -36,7 +37,9 @@ def make_splash_editor(target, source, env):
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef BOOT_SPLASH_EDITOR_H\n")
g.write("#define BOOT_SPLASH_EDITOR_H\n")
- g.write("static const Color boot_splash_editor_bg_color = Color(0.14, 0.14, 0.14);\n")
+ # The editor splash background color is taken from the default editor theme's background color.
+ # This helps achieve a visually "smoother" transition between the splash screen and the editor.
+ g.write("static const Color boot_splash_editor_bg_color = Color(0.125, 0.145, 0.192);\n")
g.write("static const unsigned char boot_splash_editor_png[] = {\n")
for i in range(len(buf)):
g.write(str(buf[i]) + ",\n")
diff --git a/main/performance.cpp b/main/performance.cpp
index 1a422dc499..a2e53f2ee2 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -119,7 +119,7 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
"physics_3d/active_objects",
"physics_3d/collision_pairs",
"physics_3d/islands",
- "audio/output_latency",
+ "audio/driver/output_latency",
};
diff --git a/methods.py b/methods.py
index f302500b5d..6f1e7a7279 100644
--- a/methods.py
+++ b/methods.py
@@ -6,9 +6,11 @@ from collections import OrderedDict
# We need to define our own `Action` method to control the verbosity of output
# and whenever we need to run those commands in a subprocess on some platforms.
-from SCons.Script import Action
from SCons import Node
+from SCons.Script import Action
+from SCons.Script import ARGUMENTS
from SCons.Script import Glob
+from SCons.Variables.BoolVariable import _text2bool
from platform_methods import run_in_subprocess
@@ -145,6 +147,17 @@ def parse_cg_file(fname, uniforms, sizes, conditionals):
fs.close()
+def get_cmdline_bool(option, default):
+ """We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
+ and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
+ """
+ cmdline_val = ARGUMENTS.get(option)
+ if cmdline_val is not None:
+ return _text2bool(cmdline_val)
+ else:
+ return default
+
+
def detect_modules(search_path, recursive=False):
"""Detects and collects a list of C++ modules at specified path
@@ -174,9 +187,7 @@ def detect_modules(search_path, recursive=False):
version_path = os.path.join(path, "version.py")
if os.path.exists(version_path):
with open(version_path) as f:
- version = {}
- exec(f.read(), version)
- if version.get("short_name") == "godot":
+ if 'short_name = "godot"' in f.read():
return True
return False
@@ -323,7 +334,7 @@ def use_windows_spawn_fix(self, platform=None):
# On Windows, due to the limited command line length, when creating a static library
# from a very high number of objects SCons will invoke "ar" once per object file;
# that makes object files with same names to be overwritten so the last wins and
- # the library looses symbols defined by overwritten objects.
+ # the library loses symbols defined by overwritten objects.
# By enabling quick append instead of the default mode (replacing), libraries will
# got built correctly regardless the invocation strategy.
# Furthermore, since SCons will rebuild the library from scratch when an object file
@@ -467,7 +478,7 @@ def detect_visual_c_compiler_version(tools_env):
# and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect
# the proper vc version that will be called
- # There is no flag to give to visual c compilers to set the architecture, ie scons bits argument (32,64,ARM etc)
+ # There is no flag to give to visual c compilers to set the architecture, i.e. scons bits argument (32,64,ARM etc)
# There are many different cl.exe files that are run, and each one compiles & links to a different architecture
# As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program()
# is to check the PATH variable and figure out which one will be called first. Code below does that and returns:
@@ -622,7 +633,7 @@ def generate_vs_project(env, num_jobs):
'call "' + batch_file + '" !plat!',
]
- # windows allows us to have spaces in paths, so we need
+ # Windows allows us to have spaces in paths, so we need
# to double quote off the directory. However, the path ends
# in a backslash, so we need to remove this, lest it escape the
# last double quote off, confusing MSBuild
@@ -635,6 +646,9 @@ def generate_vs_project(env, num_jobs):
"-j%s" % num_jobs,
]
+ if env["tests"]:
+ common_build_postfix.append("tests=yes")
+
if env["custom_modules"]:
common_build_postfix.append("custom_modules=%s" % env["custom_modules"])
@@ -647,6 +661,8 @@ def generate_vs_project(env, num_jobs):
add_to_vs_project(env, env.modules_sources)
add_to_vs_project(env, env.scene_sources)
add_to_vs_project(env, env.servers_sources)
+ if env["tests"]:
+ add_to_vs_project(env, env.tests_sources)
add_to_vs_project(env, env.editor_sources)
for header in glob_recursive("**/*.h"):
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html
index 540ab94e51..347c22adf8 100644
--- a/misc/dist/html/editor.html
+++ b/misc/dist/html/editor.html
@@ -1,12 +1,30 @@
<!DOCTYPE html>
-<html xmlns='http://www.w3.org/1999/xhtml' lang='' xml:lang=''>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
- <meta charset='utf-8' />
- <meta name='viewport' content='width=device-width, user-scalable=no' />
- <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' />
- <title>Godot Engine Web Editor ($GODOT_VERSION)</title>
- <style type='text/css'>
-
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
+ <meta name="author" content="Godot Engine" />
+ <meta name="description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
+ <meta name="mobile-web-app-capable" content="yes" />
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <meta name="application-name" content="Godot" />
+ <meta name="apple-mobile-web-app-title" content="Godot" />
+ <meta name="theme-color" content="#478cbf" />
+ <meta name="msapplication-navbutton-color" content="#478cbf" />
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
+ <meta name="msapplication-starturl" content="/latest" />
+ <meta property="og:site_name" content="Godot Engine Web Editor" />
+ <meta property="og:url" name="twitter:url" content="https://editor.godotengine.org/releases/latest/" />
+ <meta property="og:title" name="twitter:title" content="Free and open source 2D and 3D game engine" />
+ <meta property="og:description" name="twitter:description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
+ <meta property="og:image" name="twitter:image" content="https://godotengine.org/themes/godotengine/assets/og_image.png" />
+ <meta property="og:type" content="website" />
+ <meta name="twitter:card" content="summary" />
+ <link id="-gd-engine-icon" rel="icon" type="image/png" href="favicon.png" />
+ <link rel="apple-touch-icon" type="image/png" href="favicon.png" />
+ <link rel="manifest" href="manifest.json" />
+ <title>Godot Engine Web Editor (@GODOT_VERSION@)</title>
+ <style>
*:focus {
/* More visible outline for better keyboard navigation. */
outline: 0.125rem solid hsl(220, 100%, 62.5%);
@@ -40,13 +58,53 @@
filter: brightness(82.5%);
}
+ .welcome-modal {
+ display: none;
+ position: fixed;
+ z-index: 1;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: hsla(0, 0%, 0%, 0.5);
+ }
+
+ .welcome-modal-content {
+ background-color: #333b4f;
+ box-shadow: 0 0.25rem 0.25rem hsla(0, 0%, 0%, 0.5);
+ line-height: 1.5;
+ max-width: 38rem;
+ margin: 4rem auto 0 auto;
+ color: white;
+ border-radius: 0.5rem;
+ padding: 1rem 1rem 2rem 1rem;
+ }
+
+ #tabs-buttons {
+ /* Match the default background color of the editor window for a seamless appearance. */
+ background-color: #202531;
+ }
+
+ #tab-game {
+ /* Use a pure black background to better distinguish the running project */
+ /* from the editor window, and to use a more neutral background color (no tint). */
+ background-color: black;
+ /* Make the background span the entire page height. */
+ min-height: 100vh;
+ }
+
#canvas, #gameCanvas {
display: block;
margin: 0;
color: white;
}
- #canvas:focus, #gameCanvas:focus {
+ /* Don't show distracting focus outlines for the main tabs' contents. */
+ #tab-editor canvas:focus,
+ #tab-game canvas:focus,
+ #canvas:focus,
+ #gameCanvas:focus {
outline: none;
}
@@ -171,6 +229,36 @@
</style>
</head>
<body>
+ <div
+ id="welcome-modal"
+ class="welcome-modal"
+ role="dialog"
+ aria-labelledby="welcome-modal-title"
+ aria-describedby="welcome-modal-description"
+ onclick="if (event.target === this) closeWelcomeModal(false)"
+ >
+ <div class="welcome-modal-content">
+ <h2 id="welcome-modal-title">Important - Please read before continuing</h2>
+ <div id="welcome-modal-description">
+ <p>
+ The Godot Web Editor has some limitations compared to the native version.
+ Its main focus is education and experimentation;
+ <strong>it is not recommended for production</strong>.
+ </p>
+ <p>
+ Refer to the
+ <a
+ href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html"
+ target="_blank"
+ rel="noopener"
+ >Web editor documentation</a> for usage instructions and limitations.
+ </p>
+ </div>
+ <button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
+ OK, don't show again
+ </button>
+ </div>
+ </div>
<div id="tabs-buttons">
<button id="btn-tab-loader" class="btn tab-btn" onclick="showTab('loader')">Loader</button>
<button id="btn-tab-editor" class="btn tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button>
@@ -178,8 +266,8 @@
<button id="btn-tab-game" class="btn tab-btn" disabled="disabled" onclick="showTab('game')">Game</button>
<button id="btn-close-game" class="btn close-btn" disabled="disabled" onclick="closeGame()">×</button>
</div>
- <div id='tabs'>
- <div id='tab-loader'>
+ <div id="tabs">
+ <div id="tab-loader">
<div style="color: #e0e0e0;" id="persistence">
<label for="videoMode" style="display: none;">Select video driver:</label><br />
<select id="videoMode" style="display: none;">
@@ -187,39 +275,41 @@
<option value="GLES3">WebGL 2</option>
</select>
<br />
- <img src="logo.svg" width="1024" height="414" style="width: auto; height: auto; max-width: 85%; max-height: 250px" />
+ <img src="logo.svg" alt="Godot Engine logo" width="1024" height="414" style="width: auto; height: auto; max-width: 85%; max-height: 250px" />
<br />
- $GODOT_VERSION
+ @GODOT_VERSION@
<br />
<a href="releases/">Need an old version?</a>
<br />
<br />
<br />
- <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" id="files" name="files" style="margin-bottom: 1rem"/>
+ <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" name="files" style="margin-bottom: 1rem"/>
<br />
<a href="demo.zip">(Try this for example)</a>
<br />
<br />
- <button id="startButton" class="btn" style="margin-bottom: 4rem">Start Godot editor</button>
+ <button id="startButton" class="btn" style="margin-bottom: 4rem; font-weight: 700">Start Godot editor</button>
<br />
- <button class="btn" onclick="clearPersistence()">Clear persistent data</button>
+ <button class="btn" onclick="clearPersistence()" style="margin-bottom: 1.5rem">Clear persistent data</button>
+ <br />
+ <a href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html">Web editor documentation</a>
</div>
</div>
- <div id='tab-editor' style="display: none;">
- <canvas id='editor-canvas' tabindex="1">
+ <div id="tab-editor" style="display: none;">
+ <canvas id="editor-canvas" tabindex="1">
HTML5 canvas appears to be unsupported in the current browser.<br />
Please try updating or use a different browser.
</canvas>
</div>
- <div id='tab-game' style="display: none;">
- <canvas id='game-canvas' tabindex="2">
+ <div id="tab-game" style="display: none;">
+ <canvas id="game-canvas" tabindex="2">
HTML5 canvas appears to be unsupported in the current browser.<br />
Please try updating or use a different browser.
</canvas>
</div>
- <div id='tab-status' style="display: none;">
- <div id='status-progress' style='display: none;' oncontextmenu='event.preventDefault();'><div id ='status-progress-inner'></div></div>
- <div id='status-indeterminate' style='display: none;' oncontextmenu='event.preventDefault();'>
+ <div id="tab-status" style="display: none;">
+ <div id="status-progress" style="display: none;" oncontextmenu="event.preventDefault();"><div id="status-progress-inner"></div></div>
+ <div id="status-indeterminate" style="display: none;" oncontextmenu="event.preventDefault();">
<div></div>
<div></div>
<div></div>
@@ -229,14 +319,32 @@
<div></div>
<div></div>
</div>
- <div id='status-notice' class='godot' style='display: none;'></div>
+ <div id="status-notice" class="godot" style="display: none;"></div>
</div>
</div>
+ <script>
+ window.addEventListener("load", () => {
+ if ("serviceWorker" in navigator) {
+ navigator.serviceWorker.register("service.worker.js");
+ }
- <script type='text/javascript' src='godot.tools.js'></script>
- <script type='text/javascript'>//<![CDATA[
+ if (localStorage.getItem("welcomeModalDismissed") !== 'true') {
+ document.getElementById("welcome-modal").style.display = "block";
+ document.getElementById("welcome-modal-dismiss").focus();
+ }
+ });
+
+ function closeWelcomeModal(dontShowAgain) {
+ document.getElementById("welcome-modal").style.display = "none";
+ if (dontShowAgain) {
+ localStorage.setItem("welcomeModalDismissed", 'true');
+ }
+ }
+ </script>
+ <script src="godot.tools.js"></script>
+ <script>//<![CDATA[
- var engine = new Engine;
+ var editor = null;
var game = null;
var setStatusMode;
var setStatusNotice;
@@ -258,13 +366,11 @@
});
}
- if (!window.confirm("Are you sure you want to delete all the locally stored files?")) {
+ if (!window.confirm("Are you sure you want to delete all the locally stored files?\nClicking \"OK\" will permanently remove your projects and editor settings!")) {
return;
}
Promise.all([
- deleteDB("/home/web_user/projects"),
- deleteDB("/home/web_user/.config"),
- deleteDB("/home/web_user/.cache"),
+ deleteDB("/home/web_user"),
]).then(function(results) {
alert("Done.");
}).catch(function (err) {
@@ -286,6 +392,10 @@
tabs.forEach(function (elem) {
if (elem.id == 'tab-' + name) {
elem.style.display = 'block';
+ if (name == 'editor' || name == 'game') {
+ const canvas = document.getElementById(name + '-canvas');
+ canvas.focus();
+ }
} else {
elem.style.display = 'none';
}
@@ -319,14 +429,14 @@
function closeEditor() {
closeGame();
- if (engine) {
- engine.requestQuit();
+ if (editor) {
+ editor.requestQuit();
}
}
function startEditor(zip) {
const INDETERMINATE_STATUS_STEP_MS = 100;
- const persistentPaths = ['/home/web_user/'];
+ const persistentPaths = ['/home/web_user'];
var editorCanvas = document.getElementById('editor-canvas');
var gameCanvas = document.getElementById('game-canvas');
@@ -334,6 +444,7 @@
var statusProgressInner = document.getElementById('status-progress-inner');
var statusIndeterminate = document.getElementById('status-indeterminate');
var statusNotice = document.getElementById('status-notice');
+ var headerDiv = document.getElementById('tabs-buttons');
var initializing = true;
var statusMode = 'hidden';
@@ -347,16 +458,23 @@
}
requestAnimationFrame(animate);
+ var lastScale = 0;
+ var lastWidth = 0;
+ var lastHeight = 0;
function adjustCanvasDimensions() {
var scale = window.devicePixelRatio || 1;
- var header = document.getElementById('tabs-buttons');
- var headerHeight = header.offsetHeight + 1;
+ var headerHeight = headerDiv.offsetHeight + 1;
var width = window.innerWidth;
var height = window.innerHeight - headerHeight;
- editorCanvas.width = width * scale;
- editorCanvas.height = height * scale;
- editorCanvas.style.width = width + "px";
- editorCanvas.style.height = height + "px";
+ if (lastScale !== scale || lastWidth !== width || lastHeight !== height) {
+ editorCanvas.width = width * scale;
+ editorCanvas.height = height * scale;
+ editorCanvas.style.width = width + "px";
+ editorCanvas.style.height = height + "px";
+ lastScale = scale;
+ lastWidth = width;
+ lastHeight = height;
+ }
}
animationCallbacks.push(adjustCanvasDimensions);
adjustCanvasDimensions();
@@ -410,24 +528,23 @@
});
};
- engine.setProgressFunc((current, total) => {
- if (total > 0) {
- statusProgressInner.style.width = current/total * 100 + '%';
- setStatusMode('progress');
- if (current === total) {
- // wait for progress bar animation
- setTimeout(() => {
- setStatusMode('indeterminate');
- }, 100);
- }
- } else {
- setStatusMode('indeterminate');
- }
- });
-
- engine.setPersistentPaths(persistentPaths);
+ const gameConfig = {
+ 'persistentPaths': persistentPaths,
+ 'unloadAfterInit': false,
+ 'canvas': gameCanvas,
+ 'canvasResizePolicy': 1,
+ 'onExit': function () {
+ setGameTabEnabled(false);
+ showTab('editor');
+ game = null;
+ },
+ };
- engine.setOnExecute(function(args) {
+ var OnEditorExit = function () {
+ showTab('loader');
+ setLoaderEnabled(true);
+ };
+ function Execute(args) {
const is_editor = args.filter(function(v) { return v == '--editor' || v == '-e' }).length != 0;
const is_project_manager = args.filter(function(v) { return v == '--project-manager' }).length != 0;
const is_game = !is_editor && !is_project_manager;
@@ -440,42 +557,60 @@
return;
}
setGameTabEnabled(true);
- game = new Engine();
- game.setPersistentPaths(persistentPaths);
- game.setUnloadAfterInit(false);
- game.setOnExecute(engine.onExecute);
- game.setCanvas(gameCanvas);
- game.setCanvasResizedOnStart(true);
- game.setOnExit(function() {
- setGameTabEnabled(false);
- showTab('editor');
- game = null;
- });
+ game = new Engine(gameConfig);
showTab('game');
game.init().then(function() {
requestAnimationFrame(function() {
- game.start.apply(game, args).then(function() {
+ game.start({'args': args}).then(function() {
gameCanvas.focus();
});
});
});
} else { // New editor instances will be run in the same canvas. We want to wait for it to exit.
- engine.setOnExit(function(code) {
+ OnEditorExit = function(code) {
setLoaderEnabled(true);
setTimeout(function() {
- engine.init().then(function() {
+ editor.init().then(function() {
setLoaderEnabled(false);
- engine.setOnExit(function() {
+ OnEditorExit = function() {
showTab('loader');
setLoaderEnabled(true);
- });
- engine.start.apply(engine, args);
+ };
+ editor.start({'args': args, 'persistentDrops': is_project_manager});
});
}, 0);
- engine.setOnExit(null);
- });
+ OnEditorExit = null;
+ };
}
- });
+ }
+
+ const editorConfig = {
+ 'unloadAfterInit': false,
+ 'onProgress': function progressFunction (current, total) {
+ if (total > 0) {
+ statusProgressInner.style.width = current/total * 100 + '%';
+ setStatusMode('progress');
+ if (current === total) {
+ // wait for progress bar animation
+ setTimeout(() => {
+ setStatusMode('indeterminate');
+ }, 100);
+ }
+ } else {
+ setStatusMode('indeterminate');
+ }
+ },
+ 'canvas': editorCanvas,
+ 'canvasResizePolicy': 0,
+ 'onExit': function() {
+ if (OnEditorExit) {
+ OnEditorExit();
+ }
+ },
+ 'onExecute': Execute,
+ 'persistentPaths': persistentPaths,
+ };
+ editor = new Engine(editorConfig);
function displayFailureNotice(err) {
var msg = err.message || err;
@@ -489,26 +624,20 @@
displayFailureNotice('WebGL not available');
} else {
setStatusMode('indeterminate');
- engine.setCanvas(editorCanvas);
- engine.setUnloadAfterInit(false); // Don't want to reload when starting game.
- engine.init('godot.tools').then(function() {
+ editor.init('godot.tools').then(function() {
if (zip) {
- engine.copyToFS("/tmp/preload.zip", zip);
+ editor.copyToFS("/tmp/preload.zip", zip);
}
try {
// Avoid user creating project in the persistent root folder.
- engine.copyToFS("/home/web_user/keep", new Uint8Array());
+ editor.copyToFS("/home/web_user/keep", new Uint8Array());
} catch(e) {
// File exists
}
//selectVideoMode();
showTab('editor');
setLoaderEnabled(false);
- engine.setOnExit(function() {
- showTab('loader');
- setLoaderEnabled(true);
- });
- engine.start('--video-driver', video_driver).then(function() {
+ editor.start({'args': ['--project-manager', '--video-driver', video_driver], 'persistentDrops': true}).then(function() {
setStatusMode('hidden');
initializing = false;
});
diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html
index 85c5305b85..7afb6fdb6b 100644
--- a/misc/dist/html/full-size.html
+++ b/misc/dist/html/full-size.html
@@ -3,7 +3,6 @@
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, user-scalable=no' />
- <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' />
<title>$GODOT_PROJECT_NAME</title>
<style type='text/css'>
@@ -134,22 +133,14 @@ $GODOT_HEAD_INCLUDE
<div id='status-notice' class='godot' style='display: none;'></div>
</div>
- <script type='text/javascript' src='$GODOT_BASENAME.js'></script>
+ <script type='text/javascript' src='$GODOT_URL'></script>
<script type='text/javascript'>//<![CDATA[
- var engine = new Engine;
- var setStatusMode;
- var setStatusNotice;
+ const GODOT_CONFIG = $GODOT_CONFIG;
+ var engine = new Engine(GODOT_CONFIG);
(function() {
- const EXECUTABLE_NAME = '$GODOT_BASENAME';
- const MAIN_PACK = '$GODOT_BASENAME.pck';
- const EXTRA_ARGS = JSON.parse('$GODOT_ARGS');
- const GDNATIVE_LIBS = [$GODOT_GDNATIVE_LIBS];
const INDETERMINATE_STATUS_STEP_MS = 100;
- const FULL_WINDOW = $GODOT_FULL_WINDOW;
-
- var canvas = document.getElementById('canvas');
var statusProgress = document.getElementById('status-progress');
var statusProgressInner = document.getElementById('status-progress-inner');
var statusIndeterminate = document.getElementById('status-indeterminate');
@@ -157,9 +148,6 @@ $GODOT_HEAD_INCLUDE
var initializing = true;
var statusMode = 'hidden';
- var lastWidth = 0;
- var lastHeight = 0;
- var lastScale = 0;
var animationCallbacks = [];
function animate(time) {
@@ -168,26 +156,8 @@ $GODOT_HEAD_INCLUDE
}
requestAnimationFrame(animate);
- function adjustCanvasDimensions() {
- const scale = window.devicePixelRatio || 1;
- if (lastWidth != window.innerWidth || lastHeight != window.innerHeight || lastScale != scale) {
- lastScale = scale;
- lastWidth = window.innerWidth;
- lastHeight = window.innerHeight;
- canvas.width = Math.floor(lastWidth * scale);
- canvas.height = Math.floor(lastHeight * scale);
- canvas.style.width = lastWidth + "px";
- canvas.style.height = lastHeight + "px";
- }
- }
- if (FULL_WINDOW) {
- animationCallbacks.push(adjustCanvasDimensions);
- adjustCanvasDimensions();
- } else {
- engine.setCanvasResizedOnStart(true);
- }
+ function setStatusMode(mode) {
- setStatusMode = function setStatusMode(mode) {
if (statusMode === mode || !initializing)
return;
[statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
@@ -213,7 +183,7 @@ $GODOT_HEAD_INCLUDE
throw new Error('Invalid status mode');
}
statusMode = mode;
- };
+ }
function animateStatusIndeterminate(ms) {
var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
@@ -225,7 +195,7 @@ $GODOT_HEAD_INCLUDE
}
}
- setStatusNotice = function setStatusNotice(text) {
+ function setStatusNotice(text) {
while (statusNotice.lastChild) {
statusNotice.removeChild(statusNotice.lastChild);
}
@@ -236,21 +206,6 @@ $GODOT_HEAD_INCLUDE
});
};
- engine.setProgressFunc((current, total) => {
- if (total > 0) {
- statusProgressInner.style.width = current/total * 100 + '%';
- setStatusMode('progress');
- if (current === total) {
- // wait for progress bar animation
- setTimeout(() => {
- setStatusMode('indeterminate');
- }, 500);
- }
- } else {
- setStatusMode('indeterminate');
- }
- });
-
function displayFailureNotice(err) {
var msg = err.message || err;
console.error(msg);
@@ -263,9 +218,22 @@ $GODOT_HEAD_INCLUDE
displayFailureNotice('WebGL not available');
} else {
setStatusMode('indeterminate');
- engine.setCanvas(canvas);
- engine.setGDNativeLibraries(GDNATIVE_LIBS);
- engine.startGame(EXECUTABLE_NAME, MAIN_PACK, EXTRA_ARGS).then(() => {
+ engine.startGame({
+ 'onProgress': function (current, total) {
+ if (total > 0) {
+ statusProgressInner.style.width = current/total * 100 + '%';
+ setStatusMode('progress');
+ if (current === total) {
+ // wait for progress bar animation
+ setTimeout(() => {
+ setStatusMode('indeterminate');
+ }, 500);
+ }
+ } else {
+ setStatusMode('indeterminate');
+ }
+ },
+ }).then(() => {
setStatusMode('hidden');
initializing = false;
}, displayFailureNotice);
diff --git a/misc/dist/html/manifest.json b/misc/dist/html/manifest.json
new file mode 100644
index 0000000000..0ca27b3742
--- /dev/null
+++ b/misc/dist/html/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Godot Engine Web Editor",
+ "short_name": "Godot",
+ "description": "Multi-platform 2D and 3D game engine with a feature-rich editor (Web edition)",
+ "lang": "en",
+ "start_url": "./godot.tools.html",
+ "display": "standalone",
+ "orientation": "landscape",
+ "theme_color": "#478cbf",
+ "icons": [
+ {
+ "src": "favicon.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ }
+ ],
+ "background_color": "#333b4f"
+}
diff --git a/misc/dist/html/offline-export.html b/misc/dist/html/offline-export.html
new file mode 100644
index 0000000000..41ab42b04b
--- /dev/null
+++ b/misc/dist/html/offline-export.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>You are offline</title>
+ <style>
+ html {
+ background-color: #000000;
+ color: #ffffff;
+ }
+
+ body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 2rem;
+ }
+
+ p {
+ margin-block: 1rem;
+ }
+
+ button {
+ display: block;
+ padding: 1rem 2rem;
+ margin: 3rem auto 0;
+ }
+ </style>
+</head>
+<body>
+ <h1>You are offline</h1>
+ <p>This application requires an Internet connection to run for the first time.</p>
+ <p>Press the button below to try reloading:</p>
+ <button type="button">Reload</button>
+
+ <script>
+ document.querySelector("button").addEventListener("click", () => {
+ window.location.reload();
+ });
+ </script>
+</body>
+</html>
diff --git a/misc/dist/html/offline.html b/misc/dist/html/offline.html
new file mode 100644
index 0000000000..000c21b4d3
--- /dev/null
+++ b/misc/dist/html/offline.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>You are offline</title>
+ <style>
+ html {
+ background-color: #333b4f;
+ color: #e0e0e0;
+ }
+
+ body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 2rem;
+ }
+
+ p {
+ margin-block: 1rem;
+ }
+
+ button {
+ display: block;
+ padding: 1rem 2rem;
+ margin: 3rem auto 0;
+ }
+ </style>
+</head>
+<body>
+ <h1>You are offline</h1>
+ <p>This application requires an Internet connection to run for the first time.</p>
+ <p>Press the button below to try reloading:</p>
+ <button type="button">Reload</button>
+
+ <script>
+ document.querySelector("button").addEventListener("click", () => {
+ window.location.reload();
+ });
+ </script>
+</body>
+</html>
diff --git a/misc/dist/html/service-worker.js b/misc/dist/html/service-worker.js
new file mode 100644
index 0000000000..f8dee8cd5b
--- /dev/null
+++ b/misc/dist/html/service-worker.js
@@ -0,0 +1,73 @@
+// This service worker is required to expose an exported Godot project as a
+// Progressive Web App. It provides an offline fallback page telling the user
+// that they need an Internet conneciton to run the project if desired.
+// Incrementing CACHE_VERSION will kick off the install event and force
+// previously cached resources to be updated from the network.
+const CACHE_VERSION = "@GODOT_VERSION@";
+const CACHE_NAME = "@GODOT_NAME@-cache";
+const OFFLINE_URL = "@GODOT_OFFLINE_PAGE@";
+// Files that will be cached on load.
+const CACHED_FILES = @GODOT_CACHE@;
+// Files that we might not want the user to preload, and will only be cached on first load.
+const CACHABLE_FILES = @GODOT_OPT_CACHE@;
+const FULL_CACHE = CACHED_FILES.concat(CACHABLE_FILES);
+
+self.addEventListener("install", (event) => {
+ event.waitUntil(async function () {
+ const cache = await caches.open(CACHE_NAME);
+ // Clear old cache (including optionals).
+ await Promise.all(FULL_CACHE.map(path => cache.delete(path)));
+ // Insert new one.
+ const done = await cache.addAll(CACHED_FILES);
+ return done;
+ }());
+});
+
+self.addEventListener("activate", (event) => {
+ event.waitUntil(async function () {
+ if ("navigationPreload" in self.registration) {
+ await self.registration.navigationPreload.enable();
+ }
+ }());
+ // Tell the active service worker to take control of the page immediately.
+ self.clients.claim();
+});
+
+self.addEventListener("fetch", (event) => {
+ const isNavigate = event.request.mode === "navigate";
+ const url = event.request.url || "";
+ const referrer = event.request.referrer || "";
+ const base = referrer.slice(0, referrer.lastIndexOf("/") + 1);
+ const local = url.startsWith(base) ? url.replace(base, "") : "";
+ const isCachable = FULL_CACHE.some(v => v === local) || (base === referrer && base.endsWith(CACHED_FILES[0]));
+ if (isNavigate || isCachable) {
+ event.respondWith(async function () {
+ try {
+ // Use the preloaded response, if it's there
+ let request = event.request.clone();
+ let response = await event.preloadResponse;
+ if (!response) {
+ // Or, go over network.
+ response = await fetch(event.request);
+ }
+ if (isCachable) {
+ // Update the cache
+ const cache = await caches.open(CACHE_NAME);
+ cache.put(request, response.clone());
+ }
+ return response;
+ } catch (error) {
+ const cache = await caches.open(CACHE_NAME);
+ if (event.request.mode === "navigate") {
+ // Check if we have full cache.
+ const cached = await Promise.all(FULL_CACHE.map(name => cache.match(name)));
+ const missing = cached.some(v => v === undefined);
+ const cachedResponse = missing ? await caches.match(OFFLINE_URL) : await caches.match(CACHED_FILES[0]);
+ return cachedResponse;
+ }
+ const cachedResponse = await caches.match(event.request);
+ return cachedResponse;
+ }
+ }());
+ }
+});
diff --git a/misc/dist/linux/org.godotengine.Godot.xml b/misc/dist/linux/org.godotengine.Godot.xml
new file mode 100644
index 0000000000..2f647f71a6
--- /dev/null
+++ b/misc/dist/linux/org.godotengine.Godot.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-godot-project">
+ <comment>Godot Engine project</comment>
+ <icon name="x-godot-project" />
+ <glob pattern="*.godot"/>
+ </mime-type>
+
+ <mime-type type="application/x-godot-resource">
+ <comment>Godot Engine resource</comment>
+ <icon name="x-godot-resource" />
+ <glob pattern="*.res"/>
+ <glob pattern="*.tres"/>
+ </mime-type>
+
+ <mime-type type="application/x-godot-scene">
+ <comment>Godot Engine scene</comment>
+ <icon name="x-godot-scene" />
+ <glob pattern="*.scn"/>
+ <glob pattern="*.tscn"/>
+ <glob pattern="*.escn"/>
+ </mime-type>
+
+ <mime-type type="application/x-gdscript">
+ <comment>GDScript script</comment>
+ <icon name="x-gdscript" />
+ <glob pattern="*.gd"/>
+ </mime-type>
+</mime-info>
diff --git a/misc/dist/linux/x-godot-project.xml b/misc/dist/linux/x-godot-project.xml
deleted file mode 100644
index 9f28bab2ae..0000000000
--- a/misc/dist/linux/x-godot-project.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0"?>
-<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
- <mime-type type="application/x-godot-project">
- <comment>Godot Engine project</comment>
- <icon name="godot" />
- <glob pattern="*.godot" weight="100" />
- </mime-type>
-</mime-info>
diff --git a/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json b/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
index 6bf2edb02d..c4f8f71d0e 100644
--- a/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
+++ b/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
@@ -2,6 +2,6 @@
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
- "api_version" : "1.0.0"
+ "api_version" : "1.1.0"
}
}
diff --git a/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json b/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
index 6bf2edb02d..c4f8f71d0e 100644
--- a/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
+++ b/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
@@ -2,6 +2,6 @@
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
- "api_version" : "1.0.0"
+ "api_version" : "1.1.0"
}
}
diff --git a/misc/dist/project_icon.svg b/misc/dist/project_icon.svg
index cece381340..39a8cd6332 100644
--- a/misc/dist/project_icon.svg
+++ b/misc/dist/project_icon.svg
@@ -1 +1 @@
-<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -98.519719)"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="106.51972"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164712 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426581-6.973693 9.2079704-13.9828879 13.621-19.449z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 97.676491 522.86238)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.2343801 0 0 -4.2343764 788.7623 819.22103)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 387.09785 624.34645)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 364.87318 629.82505)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 511.99324 725.12292)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.2343801 0 0 -4.2343764 636.90407 624.34645)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.2343801 0 0 -4.2343764 659.13434 629.82505)"/></g></svg>
+<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg"><rect fill="#1e1a21" height="1008" rx="176.28572" stroke="#2e2832" stroke-width="16" width="1008" x="8" y="8.000001"/><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.23438024 0 0 -4.23438024 926.261959 674.345124)"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164715 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426579-6.973692 9.2079702-13.9828876 13.621-19.449z" fill="#478cbf" transform="matrix(4.23438024 0 0 -4.23438024 97.676501 424.342903)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.23438024 0 0 -4.23438024 788.762303 720.701811)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.23438024 0 0 -4.23438024 387.097823 525.827045)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.23438024 0 0 -4.23438024 364.873153 531.305653)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.23438024 0 0 -4.23438024 511.993216 626.603625)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.23438024 0 0 -4.23438024 636.904052 525.827045)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.23438024 0 0 -4.23438024 659.134337 531.305653)"/></svg>
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 6467efe22e..7c6e5fcb42 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -103,7 +103,7 @@ CLANG_FORMAT_VERSION="$(clang-format --version | cut -d' ' -f3)"
CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d'.' -f1)"
if [ "$CLANG_FORMAT_MAJOR" != "$RECOMMENDED_CLANG_FORMAT_MAJOR" ]; then
- echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $CLANG_FORMAT_MAJOR.x.x)."
+ echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x)."
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
@@ -125,6 +125,9 @@ do
if grep -q "platform/android/java/lib/src/com" <<< $file; then
continue;
fi
+ if grep -q "\-so_wrap." <<< $file; then
+ continue;
+ fi
# ignore file if we do check for file extensions and the file
# does not match any of the extensions specified in $FILE_EXTS
diff --git a/misc/scripts/check_ci_log.py b/misc/scripts/check_ci_log.py
new file mode 100755
index 0000000000..f2cdf95c7b
--- /dev/null
+++ b/misc/scripts/check_ci_log.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+
+if len(sys.argv) < 2:
+ print("ERROR: You must run program with file name as argument.")
+ sys.exit(1)
+
+fname = sys.argv[1]
+
+fileread = open(fname.strip(), "r")
+file_contents = fileread.read()
+
+# If find "ERROR: AddressSanitizer:", then happens invalid read or write
+# This is critical bug, so we need to fix this as fast as possible
+
+if file_contents.find("ERROR: AddressSanitizer:") != -1:
+ print("FATAL ERROR: An incorrectly used memory was found.")
+ sys.exit(1)
+
+# There is also possible, that program crashed with or without backtrace.
+
+if (
+ file_contents.find("Program crashed with signal") != -1
+ or file_contents.find("Dumping the backtrace") != -1
+ or file_contents.find("Segmentation fault (core dumped)") != -1
+):
+ print("FATAL ERROR: Godot has been crashed.")
+ sys.exit(1)
+
+# Finding memory leaks in Godot is quite difficult, because we need to take into
+# account leaks also in external libraries. They are usually provided without
+# debugging symbols, so the leak report from it usually has only 2/3 lines,
+# so searching for 5 element - "#4 0x" - should correctly detect the vast
+# majority of memory leaks
+
+if file_contents.find("ERROR: LeakSanitizer:") != -1:
+ if file_contents.find("#4 0x") != -1:
+ print("ERROR: Memory leak was found")
+ sys.exit(1)
+
+# It may happen that Godot detects leaking nodes/resources and removes them, so
+# this possibility should also be handled as a potential error, even if
+# LeakSanitizer doesn't report anything
+
+if file_contents.find("ObjectDB instances leaked at exit") != -1:
+ print("ERROR: Memory leak was found")
+ sys.exit(1)
+
+# In test project may be put several assert functions which will control if
+# project is executed with right parameters etc. which normally will not stop
+# execution of project
+
+if file_contents.find("Assertion failed") != -1:
+ print("ERROR: Assertion failed in project, check exectution log for more info")
+ sys.exit(1)
+
+# For now Godot leaks a lot of rendering stuff so for now we just show info
+# about it and this needs to be reenabled after fixing this memory leaks.
+
+if file_contents.find("were leaked") != -1 or file_contents.find("were never freed") != -1:
+ print("WARNING: Memory leak was found")
+
+sys.exit(0)
diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh
index e686305dea..63c66d41c3 100755
--- a/misc/scripts/clang_format.sh
+++ b/misc/scripts/clang_format.sh
@@ -16,6 +16,8 @@ while IFS= read -rd '' f; do
continue
elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then
continue
+ elif [[ "$f" == *"-so_wrap."* ]]; then
+ continue
fi
for extension in ${CLANG_FORMAT_FILE_EXTS[@]}; do
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
index 0e9db68a90..795431cd28 100755
--- a/misc/scripts/file_format.sh
+++ b/misc/scripts/file_format.sh
@@ -30,6 +30,8 @@ while IFS= read -rd '' f; do
continue
elif [[ "$f" == "platform/android/java/lib/src/com/google"* ]]; then
continue
+ elif [[ "$f" == *"-so_wrap."* ]]; then
+ continue
fi
# Ensure that files are UTF-8 formatted.
recode UTF-8 "$f" 2> /dev/null
@@ -38,15 +40,6 @@ while IFS= read -rd '' f; do
# Remove trailing space characters and ensures that files end
# with newline characters. -l option handles newlines conveniently.
perl -i -ple 's/\s*$//g' "$f"
- # Remove the character sequence "== true" if it has a leading space.
- perl -i -pe 's/\x20== true//g' "$f"
-
- if [[ $(uname) == "Linux" ]] && [[ "$f" != *"xml" ]]; then
- # Remove empty lines after the opening brace of indented blocks.
- sed -z -i 's/\x7B\x0A\x0A\x09/\x7B\x0A\x09/g' "$f"
- # Remove empty lines before the closing brace (in some cases).
- sed -z -i 's/\x0A\x0A\x7D/\x0A\x7D/g' "$f"
- fi
done
git diff > patch.patch
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 9144a781a0..e601884486 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -433,12 +433,6 @@ void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) {
area->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::area_is_ray_pickable(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, false);
- return area->is_ray_pickable();
-}
-
RID BulletPhysicsServer3D::body_create(BodyMode p_mode, bool p_init_sleeping) {
RigidBodyBullet *body = bulletnew(RigidBodyBullet);
body->set_mode(p_mode);
@@ -461,7 +455,7 @@ void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) {
}
if (body->get_space() == space) {
- return; //pointles
+ return; //pointless
}
body->set_space(space);
@@ -617,11 +611,11 @@ uint32_t BulletPhysicsServer3D::body_get_collision_mask(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_user_flags(RID p_body, uint32_t p_flags) {
- // This function si not currently supported
+ // This function is not currently supported
}
uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const {
- // This function si not currently supported
+ // This function is not currently supported
return 0;
}
@@ -830,10 +824,10 @@ bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const
return body->get_omit_forces_integration();
}
-void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -842,12 +836,6 @@ void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::body_is_ray_pickable(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, nullptr);
@@ -880,7 +868,7 @@ RID BulletPhysicsServer3D::soft_body_create(bool p_init_sleeping) {
CreateThenReturnRID(soft_body_owner, body);
}
-void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) {
+void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -898,7 +886,7 @@ void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) {
}
if (body->get_space() == space) {
- return; //pointles
+ return; //pointless
}
body->set_space(space);
@@ -922,6 +910,13 @@ void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
body->set_soft_mesh(p_mesh);
}
+AABB BulletPhysicsServer::soft_body_get_bounds(RID p_body) const {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, AABB());
+
+ return body->get_bounds();
+}
+
void BulletPhysicsServer3D::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -1002,34 +997,19 @@ void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform
body->set_soft_transform(p_transform);
}
-Vector3 BulletPhysicsServer3D::soft_body_get_vertex_position(RID p_body, int vertex_index) const {
- const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- Vector3 pos;
- ERR_FAIL_COND_V(!body, pos);
-
- body->get_node_position(vertex_index, pos);
- return pos;
-}
-
void BulletPhysicsServer3D::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer3D::soft_body_is_ray_pickable(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
void BulletPhysicsServer3D::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_simulation_precision(p_simulation_precision);
}
-int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) {
+int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_simulation_precision();
@@ -1041,13 +1021,13 @@ void BulletPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_
body->set_total_mass(p_total_mass);
}
-real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_total_mass();
}
-void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
+void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_linear_stiffness(p_stiffness);
@@ -1059,61 +1039,25 @@ real_t BulletPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) {
return body->get_linear_stiffness();
}
-void BulletPhysicsServer3D::soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_areaAngular_stiffness(p_stiffness);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_areaAngular_stiffness(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_areaAngular_stiffness();
-}
-
-void BulletPhysicsServer3D::soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_volume_stiffness(p_stiffness);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_volume_stiffness(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_volume_stiffness();
-}
-
void BulletPhysicsServer3D::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_pressure_coefficient(p_pressure_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pressure_coefficient();
}
-void BulletPhysicsServer3D::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- return body->set_pose_matching_coefficient(p_pose_matching_coefficient);
-}
-
-real_t BulletPhysicsServer3D::soft_body_get_pose_matching_coefficient(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0.f);
- return body->get_pose_matching_coefficient();
-}
-
void BulletPhysicsServer3D::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_damping_coefficient(p_damping_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_damping_coefficient();
@@ -1125,7 +1069,7 @@ void BulletPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_
body->set_drag_coefficient(p_drag_coefficient);
}
-real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_drag_coefficient();
@@ -1137,7 +1081,7 @@ void BulletPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index,
body->set_node_position(p_point_index, p_global_position);
}
-Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) {
+Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.));
Vector3 pos;
@@ -1145,14 +1089,6 @@ Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, i
return pos;
}
-Vector3 BulletPhysicsServer3D::soft_body_get_point_offset(RID p_body, int p_point_index) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector3());
- Vector3 res;
- body->get_node_offset(p_point_index, res);
- return res;
-}
-
void BulletPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -1165,7 +1101,7 @@ void BulletPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, b
body->set_node_mass(p_point_index, p_pin ? 0 : 1);
}
-bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) {
+bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_node_mass(p_point_index);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index f2740c9c75..de0379c873 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -163,7 +163,6 @@ public:
virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override;
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
- virtual bool area_is_ray_pickable(RID p_area) const override;
/* RIGID BODY API */
@@ -247,10 +246,9 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override;
virtual bool body_is_omitting_force_integration(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_is_ray_pickable(RID p_body) const override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
@@ -262,13 +260,15 @@ public:
virtual RID soft_body_create(bool p_init_sleeping = false) override;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override;
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override;
virtual void soft_body_set_space(RID p_body, RID p_space) override;
virtual RID soft_body_get_space(RID p_body) const override;
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
+ virtual AABB soft_body_get_bounds(RID p_body) const override;
+
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override;
virtual uint32_t soft_body_get_collision_layer(RID p_body) const override;
@@ -284,46 +284,33 @@ public:
/// Special function. This function has bad performance
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool soft_body_is_ray_pickable(RID p_body) const override;
virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override;
- virtual int soft_body_get_simulation_precision(RID p_body) override;
+ virtual int soft_body_get_simulation_precision(RID p_body) const override;
virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override;
- virtual real_t soft_body_get_total_mass(RID p_body) override;
+ virtual real_t soft_body_get_total_mass(RID p_body) const override;
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_linear_stiffness(RID p_body) override;
-
- virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) override;
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override;
- virtual real_t soft_body_get_volume_stiffness(RID p_body) override;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const override;
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override;
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) override;
-
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override;
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override;
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override;
- virtual real_t soft_body_get_damping_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const override;
virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override;
- virtual real_t soft_body_get_drag_coefficient(RID p_body) override;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const override;
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override;
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) override;
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override;
virtual void soft_body_remove_all_pinned_points(RID p_body) override;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override;
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) override;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override;
/* JOINT API */
diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp
index 7b21e4e4b2..19d4816372 100644
--- a/modules/bullet/bullet_types_converter.cpp
+++ b/modules/bullet/bullet_types_converter.cpp
@@ -116,7 +116,7 @@ void UNSCALE_BT_BASIS(btTransform &scaledBasis) {
}
} else { // Column 1 scale not fuzzy zero.
if (column2.fuzzyZero()) {
- // Create two vectors othogonal to column 1.
+ // Create two vectors orthogonal to column 1.
// Ensure that a default basis is created if column 1 = <0, 1, 0>
column0 = btVector3(column1[1], -column1[0], 0);
column2 = column0.cross(column1);
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index bce8ec8076..d9f5beb5a1 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -148,6 +148,9 @@ void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet
void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
exceptions.erase(p_ignoreCollisionObject->get_self());
+ if (!bt_collision_object) {
+ return;
+ }
bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, false);
if (space) {
space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());
@@ -155,11 +158,14 @@ void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBull
}
bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const {
- return !bt_collision_object->checkCollideWith(p_otherCollisionObject->bt_collision_object);
+ return exceptions.has(p_otherCollisionObject->get_self());
}
void CollisionObjectBullet::set_collision_enabled(bool p_enabled) {
collisionsEnabled = p_enabled;
+ if (!bt_collision_object) {
+ return;
+ }
if (collisionsEnabled) {
bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() & (~btCollisionObject::CF_NO_CONTACT_RESPONSE));
} else {
diff --git a/modules/bullet/config.py b/modules/bullet/config.py
index d22f9454ed..be7cf74f6f 100644
--- a/modules/bullet/config.py
+++ b/modules/bullet/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return True
+ # API Changed and bullet is disabled at the moment
+ return False
def configure(env):
diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp
index 5d1e4d34d8..423166c408 100644
--- a/modules/bullet/godot_collision_dispatcher.cpp
+++ b/modules/bullet/godot_collision_dispatcher.cpp
@@ -43,7 +43,7 @@ GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *col
bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, const btCollisionObject *body1) {
if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
- // Avoide area narrow phase
+ // Avoid area narrow phase
return false;
}
return btCollisionDispatcher::needsCollision(body0, body1);
@@ -51,7 +51,7 @@ bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, co
bool GodotCollisionDispatcher::needsResponse(const btCollisionObject *body0, const btCollisionObject *body1) {
if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
- // Avoide area narrow phase
+ // Avoid area narrow phase
return false;
}
return btCollisionDispatcher::needsResponse(body0, body1);
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 15d625afeb..e92b6c189c 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -113,7 +113,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo
PhysicsDirectSpaceState3D::ShapeResult &result = m_results[count];
- result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
+ result.shape = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is an odd name but contains the compound shape ID
result.rid = gObj->get_self();
result.collider_id = gObj->get_instance_id();
result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id);
@@ -176,7 +176,7 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0)
btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
if (convexResult.m_localShapeInfo) {
- m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is a odd name but contains the compound shape ID
+ m_shapeId = convexResult.m_localShapeInfo->m_triangleIndex; // "m_triangleIndex" Is an odd name but contains the compound shape ID
} else {
m_shapeId = 0;
}
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index a5093afe9d..675da1a597 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -346,16 +346,17 @@ void RigidBodyBullet::dispatch_callbacks() {
Variant variantBodyDirect = bodyDirect;
- Object *obj = ObjectDB::get_instance(force_integration_callback->id);
+ Object *obj = force_integration_callback->callable.get_object();
if (!obj) {
// Remove integration callback
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata };
Callable::CallError responseCallError;
int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(force_integration_callback->method, vp, argc, responseCallError);
+ Variant rv;
+ force_integration_callback->callable.call(vp, argc, rv, responseCallError);
}
}
@@ -371,16 +372,15 @@ void RigidBodyBullet::dispatch_callbacks() {
previousActiveState = btBody->isActive();
}
-void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void RigidBodyBullet::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (force_integration_callback) {
memdelete(force_integration_callback);
force_integration_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
force_integration_callback = memnew(ForceIntegrationCallback);
- force_integration_callback->id = p_id;
- force_integration_callback->method = p_method;
+ force_integration_callback->callable = p_callable;
force_integration_callback->udata = p_udata;
}
}
@@ -515,7 +515,7 @@ real_t RigidBodyBullet::get_param(PhysicsServer3D::BodyParameter p_param) const
}
void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) {
- // This is necessary to block force_integration untile next move
+ // This is necessary to block force_integration until next move
can_integrate_forces = false;
destroy_kinematic_utilities();
// The mode change is relevant to its mass
@@ -725,7 +725,7 @@ void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
// 1 meter in one simulation frame
btBody->setCcdMotionThreshold(1e-7);
- /// Calculate using the rule writte below the CCD swept sphere radius
+ /// Calculate using the rule write below the CCD swept sphere radius
/// CCD works on an embedded sphere of radius, make sure this radius
/// is embedded inside the convex objects, preferably smaller:
/// for an object of dimensions 1 meter, try 0.2
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index a4be7f9e07..843ff4a7af 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -154,8 +154,7 @@ public:
};
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
@@ -240,7 +239,7 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks();
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
void scratch_space_override_modificator();
virtual void on_collision_filters_change();
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 82876ab77c..40e785d699 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -142,7 +142,7 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes
}
}
-btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
+btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
const btScalar ignoredHeightScale(1);
const int YAxis = 1; // 0=X, 1=Y, 2=Z
const bool flipQuadEdges = false;
@@ -375,11 +375,17 @@ ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
}
void ConcavePolygonShapeBullet::set_data(const Variant &p_data) {
- setup(p_data);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("faces"));
+
+ setup(d["faces"]);
}
Variant ConcavePolygonShapeBullet::get_data() const {
- return faces;
+ Dictionary d;
+ d["faces"] = faces;
+
+ return d;
}
PhysicsServer3D::ShapeType ConcavePolygonShapeBullet::get_type() const {
@@ -474,17 +480,10 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
ERR_FAIL_COND_MSG(l_width < 2, "Map width must be at least 2.");
ERR_FAIL_COND_MSG(l_depth < 2, "Map depth must be at least 2.");
- // TODO This code will need adjustments if real_t is set to `double`,
- // because that precision is unnecessary for a heightmap and Bullet doesn't support it...
-
- Vector<real_t> l_heights;
+ Vector<float> l_heights;
Variant l_heights_v = d["heights"];
-#ifdef REAL_T_IS_DOUBLE
- if (l_heights_v.get_type() == Variant::PACKED_FLOAT64_ARRAY) {
-#else
if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
-#endif
// Ready-to-use heights can be passed
l_heights = l_heights_v;
@@ -505,9 +504,9 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
l_heights.resize(l_image->get_width() * l_image->get_height());
- real_t *w = l_heights.ptrw();
+ float *w = l_heights.ptrw();
const uint8_t *r = im_data.ptr();
- real_t *rp = (real_t *)r;
+ float *rp = (float *)r;
// At this point, `rp` could be used directly for Bullet, but I don't know how safe it would be.
for (int i = 0; i < l_heights.size(); ++i) {
@@ -515,11 +514,7 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
}
} else {
-#ifdef REAL_T_IS_DOUBLE
- ERR_FAIL_MSG("Expected PackedFloat64Array or float Image.");
-#else
ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
-#endif
}
ERR_FAIL_COND(l_width <= 0);
@@ -528,11 +523,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
// Compute min and max heights if not specified.
if (!d.has("min_height") && !d.has("max_height")) {
- const real_t *r = l_heights.ptr();
+ const float *r = l_heights.ptr();
int heights_size = l_heights.size();
for (int i = 0; i < heights_size; ++i) {
- real_t h = r[i];
+ float h = r[i];
if (h < l_min_height) {
l_min_height = h;
@@ -553,7 +548,7 @@ PhysicsServer3D::ShapeType HeightMapShapeBullet::get_type() const {
return PhysicsServer3D::SHAPE_HEIGHTMAP;
}
-void HeightMapShapeBullet::setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
+void HeightMapShapeBullet::setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
// TODO cell size must be tweaked using localScaling, which is a shared property for all Bullet shapes
// If this array is resized outside of here, it should be preserved due to CoW
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index bfd95747eb..5080d13d99 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -89,7 +89,7 @@ public:
/// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface();
static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
- static class btHeightfieldTerrainShape *create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
+ static class btHeightfieldTerrainShape *create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope);
};
@@ -212,7 +212,7 @@ private:
class HeightMapShapeBullet : public ShapeBullet {
public:
- Vector<real_t> heights;
+ Vector<float> heights;
int width = 0;
int depth = 0;
real_t min_height = 0.0;
@@ -226,7 +226,7 @@ public:
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
- void setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
+ void setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
};
class RayShapeBullet : public ShapeBullet {
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index a490179964..2c8727baf2 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -65,7 +65,7 @@ void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {}
void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {}
-void SoftBodyBullet::update_rendering_server(SoftBodyRenderingServerHandler *p_rendering_server_handler) {
+void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) {
if (!bt_soft_body) {
return;
}
@@ -141,6 +141,24 @@ void SoftBodyBullet::set_soft_transform(const Transform &p_transform) {
move_all_nodes(p_transform);
}
+AABB SoftBodyBullet::get_bounds() const {
+ if (!bt_soft_body) {
+ return AABB();
+ }
+
+ btVector3 aabb_min;
+ btVector3 aabb_max;
+ bt_soft_body->getAabb(aabb_min, aabb_max);
+
+ btVector3 size(aabb_max - aabb_min);
+
+ AABB aabb;
+ B_TO_G(aabb_min, aabb.position);
+ B_TO_G(size, aabb.size);
+
+ return aabb;
+}
+
void SoftBodyBullet::move_all_nodes(const Transform &p_transform) {
if (!bt_soft_body) {
return;
@@ -169,25 +187,6 @@ void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) co
}
}
-void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const {
- if (soft_mesh.is_null()) {
- return;
- }
-
- Array arrays = soft_mesh->surface_get_arrays(0);
- Vector<Vector3> vertices(arrays[RS::ARRAY_VERTEX]);
-
- if (0 <= p_node_index && vertices.size() > p_node_index) {
- r_offset = vertices[p_node_index];
- }
-}
-
-void SoftBodyBullet::get_node_offset(int p_node_index, btVector3 &r_offset) const {
- Vector3 off;
- get_node_offset(p_node_index, off);
- G_TO_B(off, r_offset);
-}
-
void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) {
if (0 >= p_mass) {
pin_node(node_index);
@@ -259,20 +258,6 @@ void SoftBodyBullet::set_linear_stiffness(real_t p_val) {
}
}
-void SoftBodyBullet::set_areaAngular_stiffness(real_t p_val) {
- areaAngular_stiffness = p_val;
- if (bt_soft_body) {
- mat0->m_kAST = areaAngular_stiffness;
- }
-}
-
-void SoftBodyBullet::set_volume_stiffness(real_t p_val) {
- volume_stiffness = p_val;
- if (bt_soft_body) {
- mat0->m_kVST = volume_stiffness;
- }
-}
-
void SoftBodyBullet::set_simulation_precision(int p_val) {
simulation_precision = p_val;
if (bt_soft_body) {
@@ -290,13 +275,6 @@ void SoftBodyBullet::set_pressure_coefficient(real_t p_val) {
}
}
-void SoftBodyBullet::set_pose_matching_coefficient(real_t p_val) {
- pose_matching_coefficient = p_val;
- if (bt_soft_body) {
- bt_soft_body->m_cfg.kMT = pose_matching_coefficient;
- }
-}
-
void SoftBodyBullet::set_damping_coefficient(real_t p_val) {
damping_coefficient = p_val;
if (bt_soft_body) {
@@ -336,7 +314,7 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector
Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]);
int vertex_id;
if (e) {
- // Already rxisting
+ // Already existing
vertex_id = e->value();
} else {
// Create new one
@@ -409,8 +387,6 @@ void SoftBodyBullet::setup_soft_body() {
bt_soft_body->generateBendingConstraints(2, mat0);
mat0->m_kLST = linear_stiffness;
- mat0->m_kAST = areaAngular_stiffness;
- mat0->m_kVST = volume_stiffness;
// Clusters allow to have Soft vs Soft collision but doesn't work well right now
@@ -430,7 +406,6 @@ void SoftBodyBullet::setup_soft_body() {
bt_soft_body->m_cfg.kDP = damping_coefficient;
bt_soft_body->m_cfg.kDG = drag_coefficient;
bt_soft_body->m_cfg.kPR = pressure_coefficient;
- bt_soft_body->m_cfg.kMT = pose_matching_coefficient;
bt_soft_body->setTotalMass(total_mass);
btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body);
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index 564566d8b8..87023b2517 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -55,6 +55,8 @@
@author AndreaCatania
*/
+class RenderingServerHandler;
+
class SoftBodyBullet : public CollisionObjectBullet {
private:
btSoftBody *bt_soft_body = nullptr;
@@ -67,10 +69,7 @@ private:
int simulation_precision = 5;
real_t total_mass = 1.;
real_t linear_stiffness = 0.5; // [0,1]
- real_t areaAngular_stiffness = 0.5; // [0,1]
- real_t volume_stiffness = 0.5; // [0,1]
real_t pressure_coefficient = 0.; // [-inf,+inf]
- real_t pose_matching_coefficient = 0.; // [0,1]
real_t damping_coefficient = 0.01; // [0,1]
real_t drag_coefficient = 0.; // [0,1]
Vector<int> pinned_nodes;
@@ -99,7 +98,7 @@ public:
_FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; }
- void update_rendering_server(class SoftBodyRenderingServerHandler *p_rendering_server_handler);
+ void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
void set_soft_mesh(const Ref<Mesh> &p_mesh);
void destroy_soft_body();
@@ -107,14 +106,12 @@ public:
// Special function. This function has bad performance
void set_soft_transform(const Transform &p_transform);
+ AABB get_bounds() const;
+
void move_all_nodes(const Transform &p_transform);
void set_node_position(int node_index, const Vector3 &p_global_position);
void set_node_position(int node_index, const btVector3 &p_global_position);
void get_node_position(int node_index, Vector3 &r_position) const;
- // Heavy function, Please cache this info
- void get_node_offset(int node_index, Vector3 &r_offset) const;
- // Heavy function, Please cache this info
- void get_node_offset(int node_index, btVector3 &r_offset) const;
void set_node_mass(int node_index, btScalar p_mass);
btScalar get_node_mass(int node_index) const;
@@ -129,21 +126,12 @@ public:
void set_linear_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
- void set_areaAngular_stiffness(real_t p_val);
- _FORCE_INLINE_ real_t get_areaAngular_stiffness() const { return areaAngular_stiffness; }
-
- void set_volume_stiffness(real_t p_val);
- _FORCE_INLINE_ real_t get_volume_stiffness() const { return volume_stiffness; }
-
void set_simulation_precision(int p_val);
_FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; }
void set_pressure_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
- void set_pose_matching_coefficient(real_t p_val);
- _FORCE_INLINE_ real_t get_pose_matching_coefficient() const { return pose_matching_coefficient; }
-
void set_damping_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 7d337bc4d0..bdaec4a09e 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -81,7 +81,7 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape
btResult.m_collisionFilterMask = p_collision_mask;
space->dynamicsWorld->contactTest(&collision_object_point, btResult);
- // The results is already populated by GodotAllConvexResultCallback
+ // The results are already populated by GodotAllConvexResultCallback
return btResult.m_count;
}
@@ -1235,6 +1235,10 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
continue;
}
+ if (kin_shape.shape->getShapeType() == EMPTY_SHAPE_PROXYTYPE) {
+ continue;
+ }
+
btTransform shape_transform = p_body_position * kin_shape.transform;
shape_transform.getOrigin() += r_delta_recover_movement;
diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm
index 3d2053ad23..9b59b68075 100644
--- a/modules/camera/camera_osx.mm
+++ b/modules/camera/camera_osx.mm
@@ -106,15 +106,15 @@
if (input) {
[self removeInput:input];
// don't release this
- input = NULL;
+ input = nullptr;
}
// free up our output
if (output) {
[self removeOutput:output];
- [output setSampleBufferDelegate:nil queue:NULL];
+ [output setSampleBufferDelegate:nil queue:nullptr];
[output release];
- output = NULL;
+ output = nullptr;
}
[self commitConfiguration];
@@ -141,9 +141,9 @@
// get our buffers
unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
- if (dataY == NULL) {
+ if (dataY == nullptr) {
print_line("Couldn't access Y pixel buffer data");
- } else if (dataCbCr == NULL) {
+ } else if (dataCbCr == nullptr) {
print_line("Couldn't access CbCr pixel buffer data");
} else {
Ref<Image> img[2];
@@ -220,8 +220,8 @@ AVCaptureDevice *CameraFeedOSX::get_device() const {
};
CameraFeedOSX::CameraFeedOSX() {
- device = NULL;
- capture_session = NULL;
+ device = nullptr;
+ capture_session = nullptr;
};
void CameraFeedOSX::set_device(AVCaptureDevice *p_device) {
@@ -240,14 +240,14 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) {
};
CameraFeedOSX::~CameraFeedOSX() {
- if (capture_session != NULL) {
+ if (capture_session != nullptr) {
[capture_session release];
- capture_session = NULL;
+ capture_session = nullptr;
};
- if (device != NULL) {
+ if (device != nullptr) {
[device release];
- device = NULL;
+ device = nullptr;
};
};
@@ -267,7 +267,7 @@ void CameraFeedOSX::deactivate_feed() {
if (capture_session) {
[capture_session cleanup];
[capture_session release];
- capture_session = NULL;
+ capture_session = nullptr;
};
};
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index f0a2f17ba9..7387842259 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -931,7 +931,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// Delete the old faces in reverse index order.
merge_faces_idx.sort();
- merge_faces_idx.invert();
+ merge_faces_idx.reverse();
for (int i = 0; i < merge_faces_idx.size(); ++i) {
faces.remove(merge_faces_idx[i]);
}
@@ -970,7 +970,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
continue;
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
face_points[face_edge_idx],
@@ -1076,7 +1076,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
break;
}
- // If opposite point is on the segemnt, add its index to segment indices too.
+ // If opposite point is on the segment, add its index to segment indices too.
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points);
if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) {
_add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx);
@@ -1137,7 +1137,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
}
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
bool on_edge = false;
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
@@ -1400,7 +1400,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
@@ -1421,7 +1421,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index e23442ef99..8a46dcca65 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -292,27 +292,16 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const {
}
void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
-
p_gizmo->clear();
- Ref<Material> material;
- switch (cs->get_operation()) {
- case CSGShape3D::OPERATION_UNION:
- material = get_material("shape_union_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_INTERSECTION:
- material = get_material("shape_intersection_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_SUBTRACTION:
- material = get_material("shape_subtraction_material", p_gizmo);
- break;
- }
-
- Ref<Material> handles_material = get_material("handles");
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
Vector<Vector3> faces = cs->get_brush_faces();
+ if (faces.size() == 0) {
+ return;
+ }
+
Vector<Vector3> lines;
lines.resize(faces.size() * 2);
{
@@ -328,6 +317,21 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+ Ref<Material> material;
+ switch (cs->get_operation()) {
+ case CSGShape3D::OPERATION_UNION:
+ material = get_material("shape_union_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_INTERSECTION:
+ material = get_material("shape_intersection_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_SUBTRACTION:
+ material = get_material("shape_subtraction_material", p_gizmo);
+ break;
+ }
+
+ Ref<Material> handles_material = get_material("handles");
+
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 82d3ac8b1b..541b7036ac 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -45,7 +45,8 @@ void CSGShape3D::set_use_collision(bool p_enable) {
if (use_collision) {
root_collision_shape.instance();
- root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
+ PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
@@ -58,7 +59,7 @@ void CSGShape3D::set_use_collision(bool p_enable) {
root_collision_instance = RID();
root_collision_shape.unref();
}
- _change_notify();
+ notify_property_list_changed();
}
bool CSGShape3D::is_using_collision() const {
@@ -88,6 +89,7 @@ uint32_t CSGShape3D::get_collision_mask() const {
}
void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -98,20 +100,23 @@ void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ layer |= 1 << p_bit;
} else {
- mask &= ~(1 << p_bit);
+ layer &= ~(1 << p_bit);
}
- set_collision_layer(mask);
+ set_collision_layer(layer);
}
bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
@@ -494,7 +499,8 @@ void CSGShape3D::_notification(int p_what) {
if (use_collision && is_root_shape()) {
root_collision_shape.instance();
- root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
+ PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
@@ -878,7 +884,7 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
}
- _make_dirty();
+ _mesh_changed();
}
Ref<Mesh> CSGMesh3D::get_mesh() {
@@ -1031,7 +1037,6 @@ void CSGSphere3D::set_radius(const float p_radius) {
radius = p_radius;
_make_dirty();
update_gizmo();
- _change_notify("radius");
}
float CSGSphere3D::get_radius() const {
@@ -1159,7 +1164,7 @@ CSGBrush *CSGBox3D::_build_brush() {
materialsw[face] = material;
face++;
- //face 1
+ //face 2
facesw[face * 3 + 0] = face_points[2] * vertex_mul;
facesw[face * 3 + 1] = face_points[3] * vertex_mul;
facesw[face * 3 + 2] = face_points[0] * vertex_mul;
@@ -1201,7 +1206,6 @@ void CSGBox3D::set_size(const Vector3 &p_size) {
size = p_size;
_make_dirty();
update_gizmo();
- _change_notify("size");
}
Vector3 CSGBox3D::get_size() const {
@@ -1383,7 +1387,6 @@ void CSGCylinder3D::set_radius(const float p_radius) {
radius = p_radius;
_make_dirty();
update_gizmo();
- _change_notify("radius");
}
float CSGCylinder3D::get_radius() const {
@@ -1394,7 +1397,6 @@ void CSGCylinder3D::set_height(const float p_height) {
height = p_height;
_make_dirty();
update_gizmo();
- _change_notify("height");
}
float CSGCylinder3D::get_height() const {
@@ -1604,7 +1606,6 @@ void CSGTorus3D::set_inner_radius(const float p_inner_radius) {
inner_radius = p_inner_radius;
_make_dirty();
update_gizmo();
- _change_notify("inner_radius");
}
float CSGTorus3D::get_inner_radius() const {
@@ -1615,7 +1616,6 @@ void CSGTorus3D::set_outer_radius(const float p_outer_radius) {
outer_radius = p_outer_radius;
_make_dirty();
update_gizmo();
- _change_notify("outer_radius");
}
float CSGTorus3D::get_outer_radius() const {
@@ -1683,7 +1683,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
Vector<Point2> final_polygon = polygon;
if (Triangulate::get_area(final_polygon) > 0) {
- final_polygon.invert();
+ final_polygon.reverse();
}
Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
@@ -1745,7 +1745,6 @@ CSGBrush *CSGPolygon3D::_build_brush() {
path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
}
curve = path->get_curve();
if (curve.is_null()) {
@@ -2230,7 +2229,7 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
@@ -2262,7 +2261,7 @@ void CSGPolygon3D::set_mode(Mode p_mode) {
mode = p_mode;
_make_dirty();
update_gizmo();
- _change_notify();
+ notify_property_list_changed();
}
CSGPolygon3D::Mode CSGPolygon3D::get_mode() const {
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 1bab8f4ee9..5fa8427843 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -4,7 +4,7 @@
A CSG Mesh shape that uses a mesh resource.
</brief_description>
<description>
- This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more then two faces.
+ This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces.
</description>
<tutorials>
</tutorials>
@@ -16,6 +16,7 @@
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] resource to use as a CSG shape.
+ [b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel.
</member>
</members>
<constants>
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index dbd6d9e9f9..3beca3d12a 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -33,6 +33,7 @@
#include "core/os/os.h"
#include "core/os/thread.h"
#include "core/string/print_string.h"
+#include "core/templates/safe_refcount.h"
#include <ConvectionKernels.h>
@@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue {
CVTTCompressionJobParams job_params;
const CVTTCompressionRowTask *job_tasks;
uint32_t num_tasks = 0;
- uint32_t current_task = 0;
+ SafeNumeric<uint32_t> current_task;
};
static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
@@ -131,7 +132,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const
static void _digest_job_queue(void *p_job_queue) {
CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
- for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) {
+ for (uint32_t next_task = job_queue->current_task.increment(); next_task <= job_queue->num_tasks; next_task = job_queue->current_task.increment()) {
_digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]);
}
}
@@ -263,7 +264,7 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann
const CVTTCompressionRowTask *tasks_rb = tasks.ptr();
job_queue.job_tasks = &tasks_rb[0];
- job_queue.current_task = 0;
+ job_queue.current_task.set(0);
job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
for (int i = 0; i < num_job_threads; i++) {
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 5415fcc92e..2fef576b77 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -94,7 +94,7 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 }
};
-RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index 605e791969..cf93156423 100644
--- a/modules/dds/texture_loader_dds.h
+++ b/modules/dds/texture_loader_dds.h
@@ -36,7 +36,7 @@
class ResourceFormatDDS : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 6c713fa1ce..f22ff29349 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -33,10 +33,10 @@
</argument>
<argument index="3" name="out_bandwidth" type="int" default="0">
</argument>
- <argument index="4" name="client_port" type="int" default="0">
+ <argument index="4" name="local_port" type="int" default="0">
</argument>
<description>
- Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]client_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
+ Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
</description>
</method>
<method name="create_server">
@@ -72,6 +72,13 @@
Returns the channel of the last packet fetched via [method PacketPeer.get_packet].
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_packet_channel" qualifiers="const">
<return type="int">
</return>
@@ -124,6 +131,22 @@
Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate].
</description>
</method>
+ <method name="set_peer_timeout">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="timeout_limit" type="int">
+ </argument>
+ <argument index="2" name="timeout_min" type="int">
+ </argument>
+ <argument index="3" name="timeout_max" type="int">
+ </argument>
+ <description>
+ Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds.
+ The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the avarage round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
+ </description>
+ </method>
</methods>
<members>
<member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false">
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 91984b8928..1cf77b307d 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -68,7 +68,7 @@ int NetworkedMultiplayerENet::get_last_packet_channel() const {
Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) {
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
- ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive).");
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
@@ -115,46 +115,37 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
connection_status = CONNECTION_CONNECTED;
return OK;
}
-
-Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) {
+Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) {
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
- ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
- if (p_client_port != 0) {
- ENetAddress c_client;
+ ENetAddress c_client;
#ifdef GODOT_ENET
- if (bind_ip.is_wildcard()) {
- c_client.wildcard = 1;
- } else {
- enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
- }
+ if (bind_ip.is_wildcard()) {
+ c_client.wildcard = 1;
+ } else {
+ enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
+ }
#else
- if (bind_ip.is_wildcard()) {
- c_client.host = 0;
- } else {
- ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
- c_client.host = *(uint32_t *)bind_ip.get_ipv4();
- }
+ if (bind_ip.is_wildcard()) {
+ c_client.host = 0;
+ } else {
+ ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
+ c_client.host = *(uint32_t *)bind_ip.get_ipv4();
+ }
#endif
- c_client.port = p_client_port;
+ c_client.port = p_local_port;
- host = enet_host_create(&c_client /* create a client host */,
- 1 /* only allow 1 outgoing connection */,
- channel_count /* allow up to channel_count to be used */,
- p_in_bandwidth /* limit incoming bandwidth if > 0 */,
- p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
- } else {
- host = enet_host_create(nullptr /* create a client host */,
- 1 /* only allow 1 outgoing connection */,
- channel_count /* allow up to channel_count to be used */,
- p_in_bandwidth /* limit incoming bandwidth if > 0 */,
- p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
- }
+ host = enet_host_create(&c_client /* create a client host */,
+ 1 /* only allow 1 outgoing connection */,
+ channel_count /* allow up to channel_count to be used */,
+ p_in_bandwidth /* limit incoming bandwidth if > 0 */,
+ p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host.");
#ifdef GODOT_ENET
@@ -248,7 +239,7 @@ void NetworkedMultiplayerENet::poll() {
int *new_id = memnew(int);
*new_id = event.data;
- if (*new_id == 0) { // Data zero is sent by server (enet won't let you configure this). Server is always 1.
+ if (*new_id == 0) { // Data zero is sent by server (ENet won't let you configure this). Server is always 1.
*new_id = 1;
}
@@ -562,7 +553,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer
ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags);
encode_uint32(unique_id, &packet->data[0]); // Source ID
encode_uint32(target_peer, &packet->data[4]); // Dest ID
- copymem(&packet->data[8], p_buffer, p_buffer_size);
+ memcpy(&packet->data[8], p_buffer, p_buffer_size);
if (server) {
if (target_peer == 0) {
@@ -673,7 +664,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *
while (total) {
for (size_t i = 0; i < inBufferCount; i++) {
int to_copy = MIN(total, int(inBuffers[i].dataLength));
- copymem(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy);
+ memcpy(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy);
ofs += to_copy;
total -= to_copy;
}
@@ -710,7 +701,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *
return 0; // Do not bother
}
- copymem(outData, enet->dst_compressor_mem.ptr(), ret);
+ memcpy(outData, enet->dst_compressor_mem.ptr(), ret);
return ret;
}
@@ -784,6 +775,19 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
#endif
}
+int NetworkedMultiplayerENet::get_local_port() const {
+ ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active.");
+ return host->address.port;
+}
+
+void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
+ ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
+ ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
+ ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
+ ERR_FAIL_COND_MSG(p_timeout_limit > 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");
+ enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max);
+}
+
void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) {
ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel));
ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG));
@@ -824,7 +828,7 @@ bool NetworkedMultiplayerENet::is_server_relay_enabled() const {
void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100));
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode);
@@ -838,6 +842,8 @@ void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &NetworkedMultiplayerENet::get_local_port);
+ ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);
ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel);
diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h
index eb70d71c2c..c589cd9fbf 100644
--- a/modules/enet/networked_multiplayer_enet.h
+++ b/modules/enet/networked_multiplayer_enet.h
@@ -127,9 +127,11 @@ public:
virtual IP_Address get_peer_address(int p_peer_id) const;
virtual int get_peer_port(int p_peer_id) const;
+ virtual int get_local_port() const;
+ void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
- Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0);
+ Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0);
void close_connection(uint32_t wait_usec = 100);
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
deleted file mode 100644
index 9b46f17916..0000000000
--- a/modules/etc/SCsub
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_etc = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-# Not unbundled so far since not widespread as shared library
-thirdparty_dir = "#thirdparty/etc2comp/"
-thirdparty_sources = [
- "EtcBlock4x4.cpp",
- "EtcBlock4x4Encoding.cpp",
- "EtcBlock4x4Encoding_ETC1.cpp",
- "EtcBlock4x4Encoding_R11.cpp",
- "EtcBlock4x4Encoding_RG11.cpp",
- "EtcBlock4x4Encoding_RGB8A1.cpp",
- "EtcBlock4x4Encoding_RGB8.cpp",
- "EtcBlock4x4Encoding_RGBA8.cpp",
- "Etc.cpp",
- "EtcDifferentialTrys.cpp",
- "EtcFilter.cpp",
- "EtcImage.cpp",
- "EtcIndividualTrys.cpp",
- "EtcMath.cpp",
- "EtcSortedBlockList.cpp",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_etc.Prepend(CPPPATH=[thirdparty_dir])
-
-env_thirdparty = env_etc.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-# Godot source files
-
-module_obj = []
-
-env_etc.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_compress_etc.cpp b/modules/etc/image_compress_etc.cpp
deleted file mode 100644
index 41cbbe3f54..0000000000
--- a/modules/etc/image_compress_etc.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*************************************************************************/
-/* image_compress_etc.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "image_compress_etc.h"
-
-#include "core/io/image.h"
-#include "core/os/copymem.h"
-#include "core/os/os.h"
-#include "core/string/print_string.h"
-
-#include <Etc.h>
-#include <EtcFilter.h>
-
-static Image::Format _get_etc2_mode(Image::UsedChannels format) {
- switch (format) {
- case Image::USED_CHANNELS_R:
- return Image::FORMAT_ETC2_R11;
-
- case Image::USED_CHANNELS_RG:
- return Image::FORMAT_ETC2_RG11;
-
- case Image::USED_CHANNELS_RGB:
- return Image::FORMAT_ETC2_RGB8;
-
- case Image::USED_CHANNELS_RGBA:
- return Image::FORMAT_ETC2_RGBA8;
-
- // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551
- default:
- // TODO: Kept for compatibility, but should be investigated whether it's correct or if it should error out
- return Image::FORMAT_ETC2_RGBA8;
- }
-}
-
-static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) {
- switch (format) {
- case Image::FORMAT_ETC:
- return Etc::Image::Format::ETC1;
-
- case Image::FORMAT_ETC2_R11:
- return Etc::Image::Format::R11;
-
- case Image::FORMAT_ETC2_R11S:
- return Etc::Image::Format::SIGNED_R11;
-
- case Image::FORMAT_ETC2_RG11:
- return Etc::Image::Format::RG11;
-
- case Image::FORMAT_ETC2_RG11S:
- return Etc::Image::Format::SIGNED_RG11;
-
- case Image::FORMAT_ETC2_RGB8:
- return Etc::Image::Format::RGB8;
-
- case Image::FORMAT_ETC2_RGBA8:
- return Etc::Image::Format::RGBA8;
-
- case Image::FORMAT_ETC2_RGB8A1:
- return Etc::Image::Format::RGB8A1;
-
- default:
- ERR_FAIL_V(Etc::Image::Format::UNKNOWN);
- }
-}
-
-static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels) {
- Image::Format img_format = p_img->get_format();
-
- if (img_format >= Image::FORMAT_DXT1) {
- return; //do not compress, already compressed
- }
-
- if (img_format > Image::FORMAT_RGBA8) {
- // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually
- return;
- }
-
- // FIXME: Commented out during Vulkan rebase.
- /*
- if (force_etc1_format) {
- // If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8
- // This saves space while maintaining the alpha channel
- if (detected_channels == Image::USED_CHANNELS_RGBA) {
- if (p_img->has_mipmaps()) {
- // Image doesn't support mipmaps with RGBA4444 textures
- p_img->clear_mipmaps();
- }
- p_img->convert(Image::FORMAT_RGBA4444);
- return;
- } else if (detected_channels == Image::USE_CHANNELS_LA) {
- p_img->convert(Image::FORMAT_LA8);
- return;
- }
- }
- */
-
- uint32_t imgw = p_img->get_width(), imgh = p_img->get_height();
-
- Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(p_channels);
-
- Ref<Image> img = p_img->duplicate();
-
- if (img->get_format() != Image::FORMAT_RGBA8) {
- img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
- }
-
- if (img->has_mipmaps()) {
- if (next_power_of_2(imgw) != imgw || next_power_of_2(imgh) != imgh) {
- img->resize_to_po2();
- imgw = img->get_width();
- imgh = img->get_height();
- }
- } else {
- if (imgw % 4 != 0 || imgh % 4 != 0) {
- if (imgw % 4) {
- imgw += 4 - imgw % 4;
- }
- if (imgh % 4) {
- imgh += 4 - imgh % 4;
- }
-
- img->resize(imgw, imgh);
- }
- }
-
- const uint8_t *r = img->get_data().ptr();
- ERR_FAIL_COND(!r);
-
- unsigned int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
- int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
-
- Vector<uint8_t> dst_data;
- dst_data.resize(target_size);
-
- uint8_t *w = dst_data.ptrw();
-
- // prepare parameters to be passed to etc2comp
- int num_cpus = OS::get_singleton()->get_processor_count();
- int encoding_time = 0;
- float effort = 0.0; //default, reasonable time
-
- if (p_lossy_quality > 0.95) {
- effort = 80;
- } else if (p_lossy_quality > 0.85) {
- effort = 60;
- } else if (p_lossy_quality > 0.75) {
- effort = 40;
- }
-
- Etc::ErrorMetric error_metric = Etc::ErrorMetric::RGBX; // NOTE: we can experiment with other error metrics
- Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format);
-
- int wofs = 0;
-
- print_verbose("ETC: Begin encoding, format: " + Image::get_format_name(etc_format));
- uint64_t t = OS::get_singleton()->get_ticks_msec();
- for (int i = 0; i < mmc; i++) {
- // convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF)
- // NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion.
- int mipmap_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0;
- img->get_mipmap_offset_size_and_dimensions(i, mipmap_ofs, mipmap_size, mipmap_w, mipmap_h);
- const uint8_t *src = &r[mipmap_ofs];
-
- Etc::ColorFloatRGBA *src_rgba_f = new Etc::ColorFloatRGBA[mipmap_w * mipmap_h];
- for (int j = 0; j < mipmap_w * mipmap_h; j++) {
- int si = j * 4; // RGBA8
- src_rgba_f[j] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]);
- }
-
- unsigned char *etc_data = nullptr;
- unsigned int etc_data_len = 0;
- unsigned int extended_width = 0, extended_height = 0;
- Etc::Encode((float *)src_rgba_f, mipmap_w, mipmap_h, etc2comp_etc_format, error_metric, effort, num_cpus, num_cpus, &etc_data, &etc_data_len, &extended_width, &extended_height, &encoding_time);
-
- CRASH_COND(wofs + etc_data_len > target_size);
- memcpy(&w[wofs], etc_data, etc_data_len);
- wofs += etc_data_len;
-
- delete[] etc_data;
- delete[] src_rgba_f;
- }
-
- print_verbose("ETC: Time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t));
-
- p_img->create(imgw, imgh, p_img->has_mipmaps(), etc_format, dst_data);
-}
-
-static void _compress_etc1(Image *p_img, float p_lossy_quality) {
- _compress_etc(p_img, p_lossy_quality, true, Image::USED_CHANNELS_RGB);
-}
-
-static void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_channels) {
- _compress_etc(p_img, p_lossy_quality, false, p_channels);
-}
-
-void _register_etc_compress_func() {
- Image::_image_compress_etc1_func = _compress_etc1;
- Image::_image_compress_etc2_func = _compress_etc2;
-}
diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp
deleted file mode 100644
index 456473672d..0000000000
--- a/modules/etc/texture_loader_pkm.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*************************************************************************/
-/* texture_loader_pkm.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "texture_loader_pkm.h"
-
-#include "core/os/file_access.h"
-#include <string.h>
-
-struct ETC1Header {
- char tag[6]; // "PKM 10"
- uint16_t format = 0; // Format == number of mips (== zero)
- uint16_t texWidth = 0; // Texture dimensions, multiple of 4 (big-endian)
- uint16_t texHeight = 0;
- uint16_t origWidth = 0; // Original dimensions (big-endian)
- uint16_t origHeight = 0;
-};
-
-RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
- if (r_error) {
- *r_error = ERR_CANT_OPEN;
- }
-
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
- return RES();
- }
-
- FileAccessRef fref(f);
- if (r_error) {
- *r_error = ERR_FILE_CORRUPT;
- }
-
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open PKM texture file '" + p_path + "'.");
-
- // big endian
- f->set_endian_swap(true);
-
- ETC1Header h;
- f->get_buffer((uint8_t *)&h.tag, sizeof(h.tag));
- ERR_FAIL_COND_V_MSG(strncmp(h.tag, "PKM 10", sizeof(h.tag)), RES(), "Invalid or unsupported PKM texture file '" + p_path + "'.");
-
- h.format = f->get_16();
- h.texWidth = f->get_16();
- h.texHeight = f->get_16();
- h.origWidth = f->get_16();
- h.origHeight = f->get_16();
-
- Vector<uint8_t> src_data;
-
- uint32_t size = h.texWidth * h.texHeight / 2;
- src_data.resize(size);
- uint8_t *wb = src_data.ptrw();
- f->get_buffer(wb, size);
-
- int mipmaps = h.format;
- int width = h.origWidth;
- int height = h.origHeight;
-
- Ref<Image> img = memnew(Image(width, height, mipmaps, Image::FORMAT_ETC, src_data));
-
- Ref<ImageTexture> texture = memnew(ImageTexture);
- texture->create_from_image(img);
-
- if (r_error) {
- *r_error = OK;
- }
-
- f->close();
- memdelete(f);
- return texture;
-}
-
-void ResourceFormatPKM::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("pkm");
-}
-
-bool ResourceFormatPKM::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatPKM::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "pkm") {
- return "ImageTexture";
- }
- return "";
-}
diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub
new file mode 100644
index 0000000000..2d3b69be75
--- /dev/null
+++ b/modules/etcpak/SCsub
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_etcpak = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/etcpak/"
+thirdparty_sources = [
+ "Dither.cpp",
+ "ProcessDxtc.cpp",
+ "ProcessRGB.cpp",
+ "Tables.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_etcpak.Prepend(CPPPATH=[thirdparty_dir])
+
+env_thirdparty = env_etcpak.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_etcpak.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/config.py b/modules/etcpak/config.py
index 53b8f2f2e3..53b8f2f2e3 100644
--- a/modules/etc/config.py
+++ b/modules/etcpak/config.py
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
new file mode 100644
index 0000000000..abc3c26188
--- /dev/null
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* image_compress_etcpak.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "image_compress_etcpak.h"
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include "thirdparty/etcpak/ProcessDxtc.hpp"
+#include "thirdparty/etcpak/ProcessRGB.hpp"
+
+EtcpakType _determine_etc_type(Image::UsedChannels p_channels) {
+ switch (p_channels) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_ETC1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ default:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ }
+}
+
+EtcpakType _determine_dxt_type(Image::UsedChannels p_channels) {
+ switch (p_channels) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_DXT1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ default:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ }
+}
+
+void _compress_etc1(Image *r_img, float p_lossy_quality) {
+ _compress_etcpak(EtcpakType::ETCPAK_TYPE_ETC1, r_img, p_lossy_quality);
+}
+
+void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) {
+ EtcpakType type = _determine_etc_type(p_channels);
+ _compress_etcpak(type, r_img, p_lossy_quality);
+}
+
+void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) {
+ EtcpakType type = _determine_dxt_type(p_channels);
+ _compress_etcpak(type, r_img, p_lossy_quality);
+}
+
+void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ // TODO: See how to handle lossy quality.
+
+ Image::Format img_format = r_img->get_format();
+ if (img_format >= Image::FORMAT_DXT1) {
+ return; // Do not compress, already compressed.
+ }
+ if (img_format > Image::FORMAT_RGBA8) {
+ // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually
+ return;
+ }
+
+ // Use RGBA8 to convert.
+ if (img_format != Image::FORMAT_RGBA8) {
+ r_img->convert(Image::FORMAT_RGBA8);
+ }
+
+ // Determine output format based on Etcpak type.
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) {
+ target_format = Image::FORMAT_ETC;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2) {
+ target_format = Image::FORMAT_ETC2_RGB8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ target_format = Image::FORMAT_ETC2_RA_AS_RG;
+ r_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ target_format = Image::FORMAT_ETC2_RGBA8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ target_format = Image::FORMAT_DXT1;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ target_format = Image::FORMAT_DXT5_RA_AS_RG;
+ r_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) {
+ target_format = Image::FORMAT_DXT5;
+ } else {
+ ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ }
+
+ // Compress image data and (if required) mipmaps.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ const int width = r_img->get_width();
+ const int height = r_img->get_height();
+ const uint8_t *src_read = r_img->get_data().ptr();
+
+ print_verbose(vformat("ETCPAK: Encoding image size %dx%d to format %s.", width, height, Image::get_format_name(target_format)));
+
+ int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps);
+ Vector<uint8_t> dest_data;
+ dest_data.resize(dest_size);
+ uint8_t *dest_write = dest_data.ptrw();
+
+ int mip_count = mipmaps ? Image::get_image_required_mipmaps(width, height, target_format) : 0;
+
+ for (int i = 0; i < mip_count + 1; i++) {
+ // Get write mip metrics for target image.
+ int mip_w, mip_h;
+ int mip_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, mip_w, mip_h);
+ // Ensure that mip offset is a multiple of 8 (etcpak expects uint64_t pointer).
+ ERR_FAIL_COND(mip_ofs % 8 != 0);
+ uint64_t *dest_mip_write = (uint64_t *)&dest_write[mip_ofs];
+
+ // Block size. Align stride to multiple of 4 (RGBA8).
+ mip_w = (mip_w + 3) & ~3;
+ mip_h = (mip_h + 3) & ~3;
+ const uint32_t blocks = mip_w * mip_h / 16;
+
+ // Get mip data from source image for reading.
+ int src_mip_ofs = r_img->get_mipmap_offset(i);
+ const uint32_t *src_mip_read = (const uint32_t *)&src_read[src_mip_ofs];
+
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) {
+ CompressEtc1RgbDither(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2 || p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ CompressEtc2Rgb(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ CompressEtc2Rgba(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else {
+ ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ }
+ }
+
+ // Replace original image with compressed one.
+ r_img->create(width, height, mipmaps, target_format, dest_data);
+
+ print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
diff --git a/modules/etcpak/image_compress_etcpak.h b/modules/etcpak/image_compress_etcpak.h
new file mode 100644
index 0000000000..ccf157fada
--- /dev/null
+++ b/modules/etcpak/image_compress_etcpak.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* image_compress_etcpak.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef IMAGE_COMPRESS_ETCPAK_H
+#define IMAGE_COMPRESS_ETCPAK_H
+
+#include "core/io/image.h"
+
+enum class EtcpakType {
+ ETCPAK_TYPE_ETC1,
+ ETCPAK_TYPE_ETC2,
+ ETCPAK_TYPE_ETC2_ALPHA,
+ ETCPAK_TYPE_ETC2_RA_AS_RG,
+ ETCPAK_TYPE_DXT1,
+ ETCPAK_TYPE_DXT5,
+ ETCPAK_TYPE_DXT5_RA_AS_RG,
+};
+
+void _compress_etc1(Image *r_img, float p_lossy_quality);
+void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels);
+void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels);
+
+void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality);
+
+#endif // IMAGE_COMPRESS_ETCPAK_H
diff --git a/modules/etcpak/register_types.cpp b/modules/etcpak/register_types.cpp
new file mode 100644
index 0000000000..d57d2f747a
--- /dev/null
+++ b/modules/etcpak/register_types.cpp
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+
+#include "image_compress_etcpak.h"
+
+void register_etcpak_types() {
+ Image::_image_compress_etc1_func = _compress_etc1;
+ Image::_image_compress_etc2_func = _compress_etc2;
+ Image::_image_compress_bc_func = _compress_bc;
+}
+
+void unregister_etcpak_types() {
+}
diff --git a/modules/etc/image_compress_etc.h b/modules/etcpak/register_types.h
index 44a06194e9..a9e10a4aae 100644
--- a/modules/etc/image_compress_etc.h
+++ b/modules/etcpak/register_types.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_etc.h */
+/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_COMPRESS_ETC_H
-#define IMAGE_COMPRESS_ETC_H
+#ifndef ETCPAK_REGISTER_TYPES_H
+#define ETCPAK_REGISTER_TYPES_H
-void _register_etc_compress_func();
+void register_etcpak_types();
+void unregister_etcpak_types();
-#endif // IMAGE_COMPRESS_ETC_H
+#endif // ETCPAK_REGISTER_TYPES_H
diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub
index 84220a66fa..0311fddfee 100644
--- a/modules/fbx/SCsub
+++ b/modules/fbx/SCsub
@@ -8,6 +8,9 @@ env_fbx = env_modules.Clone()
# Make includes relative to the folder path specified here so our includes are clean
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
+if env["builtin_zlib"]:
+ env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
+
# Godot's own source files
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp
index 5995097b2f..d54ac86e9f 100644
--- a/modules/fbx/data/fbx_material.cpp
+++ b/modules/fbx/data/fbx_material.cpp
@@ -277,7 +277,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
}
/// ALL below is related to properties
- for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) {
+ for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) {
const std::string name = iter.first;
if (name.empty()) {
@@ -317,7 +317,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
- const FBXDocParser::PropertyTable *tbl = material->Props();
+ const FBXDocParser::PropertyTable *tbl = material;
FBXDocParser::PropertyPtr prop = tbl->Get(name);
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 883651943e..304d1598f6 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -101,20 +101,6 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
return collection;
}
-typedef int Vertex;
-typedef int SurfaceId;
-typedef int PolygonId;
-typedef int DataIndex;
-
-struct SurfaceData {
- Ref<SurfaceTool> surface_tool;
- OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
- LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
- Ref<Material> material;
- HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
- Array morphs;
-};
-
EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
mesh_geometry = p_mesh_geometry;
// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
@@ -307,11 +293,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
// Triangulate the various polygons and add the indices.
for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) {
const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id);
-
triangulate_polygon(
- surface->surface_tool,
+ surface,
*indices,
- surface->vertices_map,
vertices);
}
}
@@ -336,7 +320,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
morph_st->begin(Mesh::PRIMITIVE_TRIANGLES);
for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) {
- const Vertex vertex = surface->vertices_map[vi];
+ const Vertex &vertex = surface->vertices_map[vi];
add_vertex(
state,
morph_st,
@@ -398,6 +382,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
godot_mesh->set_mesh(mesh);
+ const String name = ImportUtils::FBXNodeToName(model->Name());
+ godot_mesh->set_name(name); // hurry up compiling >.<
+ mesh->set_name("mesh3d-" + name);
return godot_mesh;
}
@@ -417,6 +404,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
int bind_id = 0;
for (const FBXDocParser::Cluster *cluster : fbx_skin->Clusters()) {
+ ERR_CONTINUE_MSG(!state.fbx_bone_map.has(cluster->TargetNode()->ID()), "Missing bone map for cluster target node with id " + uitos(cluster->TargetNode()->ID()) + ".");
Ref<FBXBone> bone = state.fbx_bone_map[cluster->TargetNode()->ID()];
skeleton_to_skin_bind_id.insert(bone->godot_bone_id, bind_id);
bind_id++;
@@ -815,8 +803,10 @@ void FBXMeshData::add_vertex(
p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale);
}
-void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, const Vector<Vertex> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const {
+void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const {
+ Ref<SurfaceTool> st(surface->surface_tool);
const int polygon_vertex_count = p_polygon_vertex.size();
+ //const Vector<Vertex>& p_surface_vertex_map
if (polygon_vertex_count == 1) {
// point to triangle
st->add_index(p_polygon_vertex[0]);
@@ -855,9 +845,9 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
is_simple_convex = true;
Vector3 first_vec;
for (int i = 0; i < polygon_vertex_count; i += 1) {
- const Vector3 p1 = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
- const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
- const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
+ const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
+ const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
+ const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
const Vector3 edge1 = p1 - p2;
const Vector3 edge2 = p3 - p2;
@@ -892,7 +882,7 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
std::vector<Vector3> poly_vertices(polygon_vertex_count);
for (int i = 0; i < polygon_vertex_count; i += 1) {
- poly_vertices[i] = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
+ poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
}
const Vector3 poly_norm = get_poly_normal(poly_vertices);
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 77510ff2ec..575f833584 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -32,6 +32,8 @@
#define FBX_MESH_DATA_H
#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/ordered_hash_map.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -47,6 +49,20 @@ struct FBXMeshData;
struct FBXBone;
struct ImportState;
+typedef int Vertex;
+typedef int SurfaceId;
+typedef int PolygonId;
+typedef int DataIndex;
+
+struct SurfaceData {
+ Ref<SurfaceTool> surface_tool;
+ OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
+ LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
+ Ref<Material> material;
+ HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
+ Array morphs;
+};
+
struct VertexWeightMapping {
Vector<real_t> weights;
Vector<int> bones;
@@ -127,7 +143,7 @@ private:
const Vector3 &p_morph_value = Vector3(),
const Vector3 &p_morph_normal = Vector3());
- void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const;
+ void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const;
/// This function is responsible to convert the FBX polygon vertex to
/// vertex index.
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
index 622b589feb..1ac4922acf 100644
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -69,7 +69,7 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
// Make sure the bone name is unique.
const String bone_name = bone->bone_name;
int same_name_count = 0;
- for (int y = x; y < skeleton_bone_count; y++) {
+ for (int y = x + 1; y < skeleton_bone_count; y++) {
Ref<FBXBone> other_bone = skeleton_bones[y];
if (other_bone.is_valid()) {
if (other_bone->bone_name == bone_name) {
diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp
index 1895af6f9f..f4055c830f 100644
--- a/modules/fbx/data/pivot_transform.cpp
+++ b/modules/fbx/data/pivot_transform.cpp
@@ -33,7 +33,7 @@
#include "tools/import_utils.h"
void PivotTransform::ReadTransformChain() {
- const FBXDocParser::PropertyTable *props = fbx_model->Props();
+ const FBXDocParser::PropertyTable *props = fbx_model;
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
inherit_type = inheritType; // copy the inherit type we need it in the second step.
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index 6576147b2b..ccbea21541 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -44,7 +44,6 @@
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/node.h"
#include "scene/resources/material.h"
@@ -94,7 +93,7 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V(!f, NULL);
+ ERR_FAIL_COND_V(!f, nullptr);
{
PackedByteArray data;
@@ -104,6 +103,9 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
bool is_binary = false;
data.resize(f->get_len());
+
+ ERR_FAIL_COND_V(data.size() < 64, nullptr);
+
f->get_buffer(data.ptrw(), data.size());
PackedByteArray fbx_header;
fbx_header.resize(64);
@@ -118,15 +120,27 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
print_verbose("[doc] opening fbx file: " + p_path);
print_verbose("[doc] fbx header: " + fbx_header_string);
+ bool corrupt = false;
// safer to check this way as there can be different formatted headers
if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) {
is_binary = true;
print_verbose("[doc] is binary");
- FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size());
+
+ FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
+
} else {
print_verbose("[doc] is ascii");
- FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size());
+ FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
+ }
+
+ if (corrupt) {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+ ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
+ return memnew(Node3D);
}
// The import process explained:
@@ -138,6 +152,16 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure
FBXDocParser::Parser parser(tokens, is_binary);
+
+ if (parser.IsCorrupt()) {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+ ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
+ return memnew(Node3D);
+ }
+
FBXDocParser::ImportSettings settings;
settings.strictMode = false;
@@ -150,12 +174,10 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// safety for version handling
if (doc.IsSafeToImport()) {
bool is_blender_fbx = false;
- //const FBXDocParser::PropertyPtr app_vendor = p_document->GlobalSettingsPtr()->Props()
- // p_document->Creator()
- const FBXDocParser::PropertyTable *import_props = doc.GetMetadataProperties();
- const FBXDocParser::PropertyPtr app_name = import_props->Get("Original|ApplicationName");
- const FBXDocParser::PropertyPtr app_vendor = import_props->Get("Original|ApplicationVendor");
- const FBXDocParser::PropertyPtr app_version = import_props->Get("Original|ApplicationVersion");
+ const FBXDocParser::PropertyTable &import_props = doc.GetMetadataProperties();
+ const FBXDocParser::PropertyPtr app_name = import_props.Get("Original|ApplicationName");
+ const FBXDocParser::PropertyPtr app_vendor = import_props.Get("Original|ApplicationVendor");
+ const FBXDocParser::PropertyPtr app_version = import_props.Get("Original|ApplicationVersion");
//
if (app_name) {
const FBXDocParser::TypedProperty<std::string> *app_name_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_name);
@@ -197,6 +219,11 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
return spatial;
} else {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+
ERR_PRINT(vformat("Cannot import FBX file: %s. It uses file format %d which is unsupported by Godot. Please re-export it or convert it to a newer format.", p_path, doc.FBXVersion()));
}
}
@@ -260,8 +287,9 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const
//could use binary search, worth it?
int idx = -1;
for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time)
+ if (p_times[i] > p_time) {
break;
+ }
idx++;
}
@@ -334,7 +362,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
ImportState state;
state.is_blender_fbx = p_is_blender_fbx;
state.path = p_path;
- state.animation_player = NULL;
+ state.animation_player = nullptr;
// create new root node for scene
Node3D *scene_root = memnew(Node3D);
@@ -610,8 +638,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
for (const FBXDocParser::Geometry *mesh : geometry) {
print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name);
- if (mesh == nullptr)
+ if (mesh == nullptr) {
continue;
+ }
const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh);
if (mesh_geometry) {
@@ -628,7 +657,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
mesh_data_precached->mesh_node = fbx_node;
// mesh node, mesh id
- mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, (p_flags & IMPORT_USE_COMPRESSION) != 0);
+ mesh_node = mesh_data_precached->create_fbx_mesh(state, mesh_geometry, fbx_node->fbx_model, false);
if (!state.MeshNodes.has(mesh_id)) {
state.MeshNodes.insert(mesh_id, fbx_node);
}
@@ -887,7 +916,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
uint64_t target_id = target->ID();
String target_name = ImportUtils::FBXNodeToName(target->Name());
- const FBXDocParser::PropertyTable *properties = curve_node->Props();
+ const FBXDocParser::PropertyTable *properties = curve_node;
bool got_x = false, got_y = false, got_z = false;
float offset_x = FBXDocParser::PropertyGet<float>(properties, "d|X", got_x);
float offset_y = FBXDocParser::PropertyGet<float>(properties, "d|Y", got_y);
@@ -985,7 +1014,6 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
int track_idx = animation->add_track(Animation::TYPE_TRANSFORM);
// animation->track_set_path(track_idx, node_path);
- // animation->track_set_path(track_idx, node_path);
Ref<FBXBone> bone;
// note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad.
@@ -1042,7 +1070,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
Ref<FBXNode> target_node = state.fbx_target_map[target_id];
const FBXDocParser::Model *model = target_node->fbx_model;
- const FBXDocParser::PropertyTable *props = model->Props();
+ const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model);
Map<StringName, FBXTrack> &track_data = track->value();
FBXTrack &translation_keys = track_data[StringName("T")];
@@ -1132,7 +1160,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
max_duration = animation_track_time;
}
- rot_values.push_back(final_rotation);
+ rot_values.push_back(final_rotation.normalized());
rot_times.push_back(animation_track_time);
}
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index 39f8648b0f..4bb2c9d21b 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -128,7 +128,7 @@ public:
virtual void get_extensions(List<String> *r_extensions) const override;
virtual uint32_t get_import_flags() const override;
- virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) override;
+ virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h
index f759c9117c..5c16383974 100644
--- a/modules/fbx/fbx_parser/ByteSwapper.h
+++ b/modules/fbx/fbx_parser/ByteSwapper.h
@@ -264,8 +264,9 @@ struct Getter {
le = !le;
if (le) {
ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
- } else
+ } else {
ByteSwapper<T, false>()(inout);
+ }
}
};
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp
index b11e2c7f55..0fbff035fd 100644
--- a/modules/fbx/fbx_parser/FBXAnimation.cpp
+++ b/modules/fbx/fbx_parser/FBXAnimation.cpp
@@ -128,11 +128,9 @@ AnimationCurve::~AnimationCurve() {
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
- const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
+ const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) :
Object(id, element, name), target(), doc(doc) {
- const ScopePtr sc = GetRequiredScope(element);
-
// find target node
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
@@ -154,8 +152,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co
prop = con->PropertyName();
break;
}
-
- props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
}
// ------------------------------------------------------------------------------------------------
@@ -187,10 +183,6 @@ const AnimationMap &AnimationCurveNode::Curves() const {
// ------------------------------------------------------------------------------------------------
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name), doc(doc) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // note: the props table here bears little importance and is usually absent
- props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@@ -248,11 +240,6 @@ const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_pro
// ------------------------------------------------------------------------------------------------
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // note: we don't currently use any of these properties so we shouldn't bother if it is missing
- props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
-
// resolve attached animation layers
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
layers.reserve(conns.size());
@@ -282,9 +269,5 @@ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std:
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
index 1d2b7765c5..1eee10b251 100644
--- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
+++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
@@ -130,6 +130,7 @@ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset
line(offset),
column(BINARY_MARKER) {
#ifdef DEBUG_ENABLED
+ // contents is bad.. :/
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
#endif
// calc length
@@ -232,9 +233,11 @@ unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const ch
}
// ------------------------------------------------------------------------------------------------
-void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) {
+void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) {
if (Offset(cursor, end) < 1) {
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
+ corrupt = true;
+ return;
}
const char type = *cursor;
@@ -328,9 +331,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
cursor += comp_len;
break;
- }
-
- // string
+ } // string
case 'S': {
const char *sb, *se;
// 0 characters can legally happen in such strings
@@ -338,11 +339,15 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
break;
}
default:
+ corrupt = true; // must exit
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
+ return;
}
if (cursor > end) {
+ corrupt = true; // must exit
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
+ return;
}
// the type code is contained in the returned range
@@ -350,7 +355,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
// ------------------------------------------------------------------------------------------------
-bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) {
+bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) {
// the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@@ -364,8 +369,12 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (end_offset > Offset(input, end)) {
TokenizeError("block offset is out of range", input, cursor);
+ corrupt = true;
+ return false;
} else if (end_offset < Offset(input, cursor)) {
TokenizeError("block offset is negative out of range", input, cursor);
+ corrupt = true;
+ return false;
}
// the second data word contains the number of properties in the scope
@@ -375,7 +384,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
// now comes the name of the scope/key
- const char *sbeg, *send;
+ const char *sbeg = nullptr, *send = nullptr;
ReadString(sbeg, send, input, cursor, end);
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
@@ -383,7 +392,10 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// now come the individual properties
const char *begin_cursor = cursor;
for (unsigned int i = 0; i < prop_count; ++i) {
- ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
+ ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt);
+ if (corrupt) {
+ return false;
+ }
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
@@ -394,6 +406,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(begin_cursor, cursor) != prop_length) {
TokenizeError("property length not reached, something is wrong", input, cursor);
+ corrupt = true;
+ return false;
}
// at the end of each nested block, there is a NUL record to indicate
@@ -410,13 +424,18 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// XXX this is vulnerable to stack overflowing ..
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
- ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
+ ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt);
+ if (corrupt) {
+ return false;
+ }
}
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
if (cursor[i] != '\0') {
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
+ corrupt = true;
+ return false;
}
}
cursor += sentinel_block_length;
@@ -424,6 +443,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(input, cursor) != end_offset) {
TokenizeError("scope length not reached, something is wrong", input, cursor);
+ corrupt = true;
+ return false;
}
return true;
@@ -432,7 +453,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) {
+void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
if (length < 0x1b) {
//TokenizeError("file is too short",0);
}
@@ -459,7 +480,7 @@ void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length)
const bool is64bits = version >= 7500;
const char *end = input + length;
while (cursor < end) {
- if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
+ if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) {
break;
}
}
diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp
index 4b774e6b2a..039718ae15 100644
--- a/modules/fbx/fbx_parser/FBXDeformer.cpp
+++ b/modules/fbx/fbx_parser/FBXDeformer.cpp
@@ -89,10 +89,6 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
- props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@@ -101,10 +97,6 @@ Deformer::~Deformer() {
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
- // used something.fbx as this is a cache name.
- props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
}
Constraint::~Constraint() {
diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp
index bcf7fa1565..bb85d6ff7c 100644
--- a/modules/fbx/fbx_parser/FBXDocument.cpp
+++ b/modules/fbx/fbx_parser/FBXDocument.cpp
@@ -93,7 +93,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
- doc(doc), element(element), id(id), flags() {
+ doc(doc), element(element), id(id) {
// empty
}
@@ -228,7 +228,7 @@ ObjectPtr LazyObject::LoadObject() {
// ------------------------------------------------------------------------------------------------
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
- element(element), name(name), id(id) {
+ PropertyTable(element), element(element), name(name), id(id) {
}
// ------------------------------------------------------------------------------------------------
@@ -237,22 +237,18 @@ Object::~Object() {
}
// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
- props(props), doc(doc) {
+FileGlobalSettings::FileGlobalSettings(const Document &doc) :
+ PropertyTable(), doc(doc) {
// empty
}
// ------------------------------------------------------------------------------------------------
FileGlobalSettings::~FileGlobalSettings() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
// ------------------------------------------------------------------------------------------------
Document::Document(const Parser &parser, const ImportSettings &settings) :
- settings(settings), parser(parser), SafeToImport(false) {
+ settings(settings), parser(parser) {
// Cannot use array default initialization syntax because vc8 fails on it
for (unsigned int &timeStamp : creationTimeStamp) {
timeStamp = 0;
@@ -287,15 +283,12 @@ Document::~Document() {
delete v.second;
}
- if (metadata_properties != nullptr) {
- delete metadata_properties;
- }
// clear globals import pointer
globals.reset();
}
// ------------------------------------------------------------------------------------------------
-static const unsigned int LowerSupportedVersion = 7300;
+static const unsigned int LowerSupportedVersion = 7100;
static const unsigned int UpperSupportedVersion = 7700;
bool Document::ReadHeader() {
@@ -306,6 +299,11 @@ bool Document::ReadHeader() {
DOMError("no FBXHeaderExtension dictionary found");
}
+ if (parser.IsCorrupt()) {
+ DOMError("File is corrupt");
+ return false;
+ }
+
const ScopePtr shead = ehead->Compound();
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
@@ -325,18 +323,11 @@ bool Document::ReadHeader() {
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
}
- //
// Scene Info
- //
-
const ElementPtr scene_info = shead->GetElement("SceneInfo");
if (scene_info) {
- PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true));
-
- if (fileExportProps) {
- metadata_properties = fileExportProps;
- }
+ metadata_properties.Setup(scene_info);
}
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
@@ -358,23 +349,7 @@ bool Document::ReadHeader() {
void Document::ReadGlobalSettings() {
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
- const ScopePtr sc = parser.GetRootScope();
- const ElementPtr ehead = sc->GetElement("GlobalSettings");
- if (nullptr == ehead || !ehead->Compound()) {
- DOMWarning("no GlobalSettings dictionary found");
- globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
- return;
- }
-
- const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
-
- //double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
-
- if (!props) {
- DOMError("GlobalSettings dictionary contains no property table");
- }
-
- globals = std::make_shared<FileGlobalSettings>(*this, props);
+ globals = std::make_shared<FileGlobalSettings>(*this);
}
// ------------------------------------------------------------------------------------------------
@@ -445,58 +420,6 @@ void Document::ReadObjects() {
// ------------------------------------------------------------------------------------------------
void Document::ReadPropertyTemplates() {
- const ScopePtr sc = parser.GetRootScope();
- // read property templates from "Definitions" section
- const ElementPtr edefs = sc->GetElement("Definitions");
- if (!edefs || !edefs->Compound()) {
- DOMWarning("no Definitions dictionary found");
- return;
- }
-
- const ScopePtr sdefs = edefs->Compound();
- const ElementCollection otypes = sdefs->GetCollection("ObjectType");
- for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
- const ElementPtr el = (*it).second;
- const ScopePtr sc_2 = el->Compound();
- if (!sc_2) {
- DOMWarning("expected nested scope in ObjectType, ignoring", el);
- continue;
- }
-
- const TokenList &tok = el->Tokens();
- if (tok.empty()) {
- DOMWarning("expected name for ObjectType element, ignoring", el);
- continue;
- }
-
- const std::string &oname = ParseTokenAsString(tok[0]);
-
- const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
- for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
- const ElementPtr el_2 = (*iter).second;
- const ScopePtr sc_3 = el_2->Compound();
- if (!sc_3) {
- DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
- continue;
- }
-
- const TokenList &tok_2 = el_2->Tokens();
- if (tok_2.empty()) {
- DOMWarning("expected name for PropertyTemplate element, ignoring", el);
- continue;
- }
-
- const std::string &pname = ParseTokenAsString(tok_2[0]);
-
- const ElementPtr Properties70 = sc_3->GetElement("Properties70");
- if (Properties70) {
- // PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
- const PropertyTable *props = new PropertyTable(Properties70, nullptr);
-
- templates[oname + "." + pname] = props;
- }
- }
- }
}
// ------------------------------------------------------------------------------------------------
diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h
index b810197d7e..9664cd763a 100644
--- a/modules/fbx/fbx_parser/FBXDocument.h
+++ b/modules/fbx/fbx_parser/FBXDocument.h
@@ -130,7 +130,7 @@ private:
};
/** Base class for in-memory (DOM) representations of FBX objects */
-class Object {
+class Object : public PropertyTable {
public:
Object(uint64_t id, const ElementPtr element, const std::string &name);
@@ -149,9 +149,9 @@ public:
}
protected:
- const ElementPtr element;
+ const ElementPtr element = nullptr;
const std::string name;
- const uint64_t id = 0;
+ const uint64_t id;
};
/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table,
@@ -159,22 +159,13 @@ protected:
class NodeAttribute : public Object {
public:
NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~NodeAttribute();
-
- const PropertyTable *Props() const {
- return props;
- }
-
-private:
- const PropertyTable *props;
};
/** DOM base class for FBX camera settings attached to a node */
class CameraSwitcher : public NodeAttribute {
public:
CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~CameraSwitcher();
int CameraID() const {
@@ -190,26 +181,26 @@ public:
}
private:
- int cameraId;
+ int cameraId = 0;
std::string cameraName;
std::string cameraIndexName;
};
#define fbx_stringize(a) #a
-#define fbx_simple_property(name, type, default_value) \
- type name() const { \
- return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
+#define fbx_simple_property(name, type, default_value) \
+ type name() const { \
+ return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \
}
// XXX improve logging
-#define fbx_simple_enum_property(name, type, default_value) \
- type name() const { \
- const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
- if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
- return static_cast<type>(default_value); \
- } \
- return static_cast<type>(ival); \
+#define fbx_simple_enum_property(name, type, default_value) \
+ type name() const { \
+ const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \
+ if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
+ return static_cast<type>(default_value); \
+ } \
+ return static_cast<type>(ival); \
}
class FbxPoseNode;
@@ -256,7 +247,7 @@ public:
}
private:
- uint64_t target_id;
+ uint64_t target_id = 0;
Transform transform;
};
@@ -264,7 +255,6 @@ private:
class Camera : public NodeAttribute {
public:
Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Camera();
fbx_simple_property(Position, Vector3, Vector3(0, 0, 0));
@@ -380,7 +370,6 @@ public:
};
Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Model();
fbx_simple_property(QuaternionInterpolate, int, 0);
@@ -466,10 +455,6 @@ public:
return culling;
}
- const PropertyTable *Props() const {
- return props;
- }
-
/** Get material links */
const std::vector<const Material *> &GetMaterials() const {
return materials;
@@ -498,13 +483,11 @@ private:
std::string shading;
std::string culling;
- const PropertyTable *props = nullptr;
};
class ModelLimbNode : public Model {
public:
ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~ModelLimbNode();
};
@@ -512,7 +495,6 @@ public:
class Texture : public Object {
public:
Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Texture();
const std::string &Type() const {
@@ -539,10 +521,6 @@ public:
return uvScaling;
}
- const PropertyTable *Props() const {
- return props;
- }
-
// return a 4-tuple
const unsigned int *Crop() const {
return crop;
@@ -560,10 +538,8 @@ private:
std::string relativeFileName;
std::string fileName;
std::string alphaSource;
- const PropertyTable *props = nullptr;
unsigned int crop[4] = { 0 };
-
const Video *media = nullptr;
};
@@ -626,8 +602,8 @@ public:
private:
std::vector<const Texture *> textures;
- BlendMode blendMode;
- float alpha;
+ BlendMode blendMode = BlendMode::BlendMode_Additive;
+ float alpha = 0;
};
typedef std::map<std::string, const Texture *> TextureMap;
@@ -656,10 +632,6 @@ public:
return relativeFileName;
}
- const PropertyTable *Props() const {
- return props;
- }
-
const uint8_t *Content() const {
return content;
}
@@ -670,7 +642,7 @@ public:
uint8_t *RelinquishContent() {
uint8_t *ptr = content;
- content = 0;
+ content = nullptr;
return ptr;
}
@@ -687,7 +659,6 @@ private:
std::string type;
std::string relativeFileName;
std::string fileName;
- const PropertyTable *props = nullptr;
uint64_t contentLength = 0;
uint8_t *content = nullptr;
@@ -708,10 +679,6 @@ public:
return multilayer;
}
- const PropertyTable *Props() const {
- return props;
- }
-
const TextureMap &Textures() const {
return textures;
}
@@ -722,8 +689,7 @@ public:
private:
std::string shading;
- bool multilayer;
- const PropertyTable *props;
+ bool multilayer = false;
TextureMap textures;
LayeredTextureMap layeredTextures;
@@ -791,13 +757,9 @@ public:
virtual ~AnimationCurveNode();
- const PropertyTable *Props() const {
- return props;
- }
-
const AnimationMap &Curves() const;
- /** Object the curve is assigned to, this can be NULL if the
+ /** Object the curve is assigned to, this can be nullptr if the
* target object has no DOM representation or could not
* be read for other reasons.*/
Object *Target() const {
@@ -819,7 +781,6 @@ public:
private:
Object *target = nullptr;
- const PropertyTable *props;
mutable AnimationMap curves;
std::string prop;
const Document &doc;
@@ -837,18 +798,12 @@ public:
AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
virtual ~AnimationLayer();
- const PropertyTable *Props() const {
- //ai_assert(props.get());
- return props;
- }
-
/* the optional white list specifies a list of property names for which the caller
wants animations for. Curves not matching this list will not be added to the
animation layer. */
const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
private:
- const PropertyTable *props;
const Document &doc;
};
@@ -863,16 +818,11 @@ public:
fbx_simple_property(ReferenceStart, int64_t, 0L);
fbx_simple_property(ReferenceStop, int64_t, 0L);
- const PropertyTable *Props() const {
- return props;
- }
-
const AnimationLayerList &Layers() const {
return layers;
}
private:
- const PropertyTable *props = nullptr;
AnimationLayerList layers;
};
@@ -881,14 +831,6 @@ class Deformer : public Object {
public:
Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Deformer();
-
- const PropertyTable *Props() const {
- //ai_assert(props.get());
- return props;
- }
-
-private:
- const PropertyTable *props;
};
/** Constraints are from Maya they can help us with BoneAttachments :) **/
@@ -896,9 +838,6 @@ class Constraint : public Object {
public:
Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Constraint();
-
-private:
- const PropertyTable *props;
};
typedef std::vector<float> WeightArray;
@@ -924,7 +863,7 @@ public:
}
private:
- float percent;
+ float percent = 0;
WeightArray fullWeights;
std::vector<const ShapeGeometry *> shapeGeometries;
};
@@ -1006,7 +945,7 @@ private:
Transform transformLink;
Transform transformAssociateModel;
SkinLinkMode link_mode;
- bool valid_transformAssociateModel;
+ bool valid_transformAssociateModel = false;
const Model *node = nullptr;
};
@@ -1037,8 +976,8 @@ public:
}
private:
- float accuracy;
- SkinType skinType;
+ float accuracy = 0;
+ SkinType skinType = SkinType::Skin_Linear;
std::vector<const Cluster *> clusters;
};
@@ -1050,7 +989,7 @@ public:
// note: a connection ensures that the source and dest objects exist, but
// not that they have DOM representations, so the return value of one of
- // these functions can still be NULL.
+ // these functions can still be nullptr.
Object *SourceObject() const;
Object *DestinationObject() const;
@@ -1087,10 +1026,10 @@ public:
}
public:
- uint64_t insertionOrder;
+ uint64_t insertionOrder = 0;
const std::string prop;
- uint64_t src, dest;
+ uint64_t src = 0, dest = 0;
const Document &doc;
};
@@ -1105,15 +1044,10 @@ typedef std::multimap<uint64_t, const Connection *> ConnectionMap;
/** DOM class for global document settings, a single instance per document can
* be accessed via Document.Globals(). */
-class FileGlobalSettings {
+class FileGlobalSettings : public PropertyTable {
public:
- FileGlobalSettings(const Document &doc, const PropertyTable *props);
-
- ~FileGlobalSettings();
-
- const PropertyTable *Props() const {
- return props;
- }
+ FileGlobalSettings(const Document &doc);
+ virtual ~FileGlobalSettings();
const Document &GetDocument() const {
return doc;
@@ -1158,7 +1092,6 @@ public:
fbx_simple_property(CustomFrameRate, float, -1.0f);
private:
- const PropertyTable *props = nullptr;
const Document &doc;
};
@@ -1196,7 +1129,7 @@ public:
return globals.get();
}
- const PropertyTable *GetMetadataProperties() const {
+ const PropertyTable &GetMetadataProperties() const {
return metadata_properties;
}
@@ -1293,7 +1226,7 @@ private:
std::vector<uint64_t> materials;
std::vector<uint64_t> skins;
mutable std::vector<const AnimationStack *> animationStacksResolved;
- PropertyTable *metadata_properties = nullptr;
+ PropertyTable metadata_properties;
std::shared_ptr<FileGlobalSettings> globals = nullptr;
};
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
index 835b66ab23..4a33024969 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
@@ -95,14 +95,14 @@ void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMError(const std::string &message, const Element *element /*= NULL*/) {
+void DOMError(const std::string &message, const Element *element /*= nullptr*/) {
if (element) {
DOMError(message, element->KeyToken());
}
print_error("[FBX-DOM] " + String(message.c_str()));
}
-void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
+void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
if (element) {
DOMError(message, element->KeyToken());
}
@@ -117,7 +117,7 @@ void DOMWarning(const std::string &message, const Token *token) {
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMWarning(const std::string &message, const Element *element /*= NULL*/) {
+void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) {
if (element) {
DOMWarning(message, element->KeyToken());
return;
@@ -129,7 +129,7 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Token> token)
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
+void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
if (element) {
DOMWarning(message, element->KeyToken());
return;
@@ -137,36 +137,5 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Element> eleme
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
}
-// ------------------------------------------------------------------------------------------------
-// fetch a property table and the corresponding property template
-const PropertyTable *GetPropertyTable(const Document &doc,
- const std::string &templateName,
- const ElementPtr element,
- const ScopePtr sc,
- bool no_warn /*= false*/) {
- // todo: make this an abstraction
- const ElementPtr Properties70 = sc->GetElement("Properties70");
- const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
-
- if (templateName.length()) {
- PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
- if (it != doc.Templates().end()) {
- templateProps = (*it).second;
- }
- }
-
- if (!Properties70 || !Properties70->Compound()) {
- if (!no_warn) {
- DOMWarning("property table (Properties70) not found", element);
- }
- if (templateProps) {
- return templateProps;
- } else {
- return new const PropertyTable();
- }
- }
-
- return new PropertyTable(Properties70, templateProps);
-}
} // namespace Util
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h
index daa9de4a33..ba86191c4a 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.h
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h
@@ -98,13 +98,6 @@ void DOMWarning(const std::string &message, const Element *element);
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
-// fetch a property table and the corresponding property template
-const PropertyTable *GetPropertyTable(const Document &doc,
- const std::string &templateName,
- const ElementPtr element,
- const ScopePtr sc,
- bool no_warn = false);
-
// ------------------------------------------------------------------------------------------------
template <typename T>
const T *ProcessSimpleConnection(const Connection &con,
diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h
index 97ce496eaf..b016db174b 100644
--- a/modules/fbx/fbx_parser/FBXImportSettings.h
+++ b/modules/fbx/fbx_parser/FBXImportSettings.h
@@ -80,60 +80,52 @@ namespace FBXDocParser {
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
struct ImportSettings {
- ImportSettings() :
- strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) {
- // empty
- }
-
/** enable strict mode:
* - only accept fbx 2012, 2013 files
* - on the slightest error, give up.
*
* Basically, strict mode means that the fbx file will actually
- * be validated. Strict mode is off by default. */
- bool strictMode;
+ * be validated.*/
+ bool strictMode = true;
/** specifies whether all geometry layers are read and scanned for
* usable data channels. The FBX spec indicates that many readers
* will only read the first channel and that this is in some way
* the recommended way- in reality, however, it happens a lot that
- * vertex data is spread among multiple layers. The default
- * value for this option is true.*/
- bool readAllLayers;
+ * vertex data is spread among multiple layers.*/
+ bool readAllLayers = true;
/** specifies whether all materials are read, or only those that
* are referenced by at least one mesh. Reading all materials
* may make FBX reading a lot slower since all objects
- * need to be processed .
- * This bit is ignored unless readMaterials=true*/
- bool readAllMaterials;
+ * need to be processed.
+ * This bit is ignored unless readMaterials=true.*/
+ bool readAllMaterials = true;
/** import materials (true) or skip them and assign a default
- * material. The default value is true.*/
- bool readMaterials;
+ * material.*/
+ bool readMaterials = true;
- /** import embedded textures? Default value is true.*/
- bool readTextures;
+ /** import embedded textures?*/
+ bool readTextures = true;
- /** import cameras? Default value is true.*/
- bool readCameras;
+ /** import cameras?*/
+ bool readCameras = true;
- /** import light sources? Default value is true.*/
- bool readLights;
+ /** import light sources?*/
+ bool readLights = true;
/** import animations (i.e. animation curves, the node
- * skeleton is always imported). Default value is true. */
- bool readAnimations;
+ * skeleton is always imported).*/
+ bool readAnimations = true;
- /** read bones (vertex weights and deform info).
- * Default value is true. */
- bool readWeights;
+ /** read bones (vertex weights and deform info).*/
+ bool readWeights = true;
/** preserve transformation pivots and offsets. Since these can
* not directly be represented in assimp, additional dummy
* nodes will be generated. Note that settings this to false
- * can make animation import a lot slower. The default value
- * is true.
+ * can make animation import a lot slower.
*
* The naming scheme for the generated nodes is:
* <OriginalName>_$AssimpFbx$_<TransformName>
@@ -149,24 +141,21 @@ struct ImportSettings {
* Scaling
* Rotation
**/
- bool preservePivots;
+ bool preservePivots = true;
/** do not import animation curves that specify a constant
- * values matching the corresponding node transformation.
- * The default value is true. */
- bool optimizeEmptyAnimationCurves;
+ * values matching the corresponding node transformation.*/
+ bool optimizeEmptyAnimationCurves = true;
- /** use legacy naming for embedded textures eg: (*0, *1, *2)
- */
- bool useLegacyEmbeddedTextureNaming;
+ /** use legacy naming for embedded textures eg: (*0, *1, *2).*/
+ bool useLegacyEmbeddedTextureNaming = false;
- /** Empty bones shall be removed
- */
- bool removeEmptyBones;
+ /** Empty bones shall be removed.*/
+ bool removeEmptyBones = true;
- /** Set to true to perform a conversion from cm to meter after the import
- */
- bool convertToMeters;
+ /** Set to true to perform a conversion from cm to meter after
+ * the import.*/
+ bool convertToMeters = false;
};
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp
index 9970a2b0b1..bf8922267e 100644
--- a/modules/fbx/fbx_parser/FBXMaterial.cpp
+++ b/modules/fbx/fbx_parser/FBXMaterial.cpp
@@ -118,8 +118,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
DOMWarning("shading mode not recognized: " + shading, element);
}
- props = GetPropertyTable(doc, templateName, element, sc);
-
// resolve texture links
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
for (const Connection *con : conns) {
@@ -163,15 +161,11 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
// ------------------------------------------------------------------------------------------------
Material::~Material() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
// ------------------------------------------------------------------------------------------------
Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) {
+ Object(id, element, name), uvScaling(1.0f, 1.0f) {
const ScopePtr sc = GetRequiredScope(element);
const ElementPtr Type = sc->GetElement("Type");
@@ -219,17 +213,15 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
}
- props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
-
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
- bool ok;
- const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
+ bool ok = true;
+ const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok);
if (ok) {
uvScaling.x = scaling.x;
uvScaling.y = scaling.y;
}
- const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok);
+ const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok);
if (ok) {
uvTrans.x = trans.x;
uvTrans.y = trans.y;
@@ -254,10 +246,6 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
}
Texture::~Texture() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
@@ -267,10 +255,10 @@ LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Docu
ElementPtr BlendModes = sc->GetElement("BlendModes");
ElementPtr Alphas = sc->GetElement("Alphas");
- if (BlendModes != 0) {
+ if (BlendModes != nullptr) {
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
}
- if (Alphas != 0) {
+ if (Alphas != nullptr) {
alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0));
}
}
@@ -297,7 +285,7 @@ void LayeredTexture::fillTexture(const Document &doc) {
// ------------------------------------------------------------------------------------------------
Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), contentLength(0), content(0) {
+ Object(id, element, name) {
const ScopePtr sc = GetRequiredScope(element);
const ElementPtr Type = sc->GetElement("Type");
@@ -337,7 +325,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s
DOMError("embedded content is not surrounded by quotation marks", element);
} else {
size_t targetLength = 0;
- auto numTokens = Content->Tokens().size();
+ const size_t numTokens = Content->Tokens().size();
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
@@ -390,18 +378,11 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s
// runtimeError.what());
}
}
-
- props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
}
Video::~Video() {
if (content) {
delete[] content;
}
-
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
index ccc06550fe..a28e7565c6 100644
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
@@ -88,7 +88,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Object(id, element, name), skin() {
+ Object(id, element, name) {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
for (const Connection *con : conns) {
const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h
index 710e644c68..05493c4aec 100644
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.h
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.h
@@ -96,7 +96,7 @@ public:
Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
virtual ~Geometry();
- /** Get the Skin attached to this geometry or NULL */
+ /** Get the Skin attached to this geometry or nullptr */
const Skin *DeformerSkin() const;
const std::vector<const BlendShape *> &get_blend_shapes() const;
diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp
index 767994441f..03c9de0c35 100644
--- a/modules/fbx/fbx_parser/FBXModel.cpp
+++ b/modules/fbx/fbx_parser/FBXModel.cpp
@@ -98,16 +98,11 @@ Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const s
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
}
- props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
ResolveLinks(element, doc);
}
// ------------------------------------------------------------------------------------------------
Model::~Model() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
index 2749fc9f4d..15184a0f5d 100644
--- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
+++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
@@ -84,16 +84,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), props() {
- const ScopePtr sc = GetRequiredScope(element);
-
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
-
- // hack on the deriving type but Null/LimbNode attributes are the only case in which
- // the property table is by design absent and no warning should be generated
- // for it.
- const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
- props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
+ Object(id, element, name) {
}
// ------------------------------------------------------------------------------------------------
diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h
index 21472f5b7b..b4003bbec5 100644
--- a/modules/fbx/fbx_parser/FBXParseTools.h
+++ b/modules/fbx/fbx_parser/FBXParseTools.h
@@ -61,7 +61,7 @@ inline bool IsLineEnd(char_t c) {
// Special version of the function, providing higher accuracy and safety
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
// ------------------------------------------------------------------------------------
-inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = 0, unsigned int *max_inout = 0) {
+inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) {
unsigned int cur = 0;
uint64_t value = 0;
diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp
index 44c24ff926..98435b5c0f 100644
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -74,8 +74,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the FBX parser and the rudimentary DOM that we use
*/
-#include "thirdparty/zlib/zlib.h"
#include <stdlib.h> /* strtol */
+#include <zlib.h>
#include "ByteSwapper.h"
#include "FBXParseTools.h"
@@ -131,6 +131,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (!n) {
print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
const TokenType ty = n->Type();
@@ -143,6 +145,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
}
@@ -150,11 +154,17 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
compound = new_Scope(parser);
parser.scopes.push_back(compound);
+ if (parser.corrupt) {
+ return;
+ }
+
// current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken();
if (n && n->Type() != TokenType_CLOSE_BRACKET) {
print_error("expected closing bracket" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
parser.AdvanceToNextToken();
@@ -173,22 +183,31 @@ Scope::Scope(Parser &parser, bool topLevel) {
TokenPtr t = parser.CurrentToken();
if (t->Type() != TokenType_OPEN_BRACKET) {
print_error("expected open bracket" + String(t->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
}
TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) {
print_error("unexpected end of file");
+ parser.corrupt = true;
+ return;
}
// note: empty scopes are allowed
while (n && n->Type() != TokenType_CLOSE_BRACKET) {
if (n->Type() != TokenType_KEY) {
print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
const std::string str = n->StringContents();
+ if (parser.corrupt) {
+ return;
+ }
// std::multimap<std::string, ElementPtr> (key and value)
elements.insert(ElementMap::value_type(str, new_Element(n, parser)));
@@ -216,7 +235,7 @@ Scope::~Scope() {
// ------------------------------------------------------------------------------------------------
Parser::Parser(const TokenList &tokens, bool is_binary) :
- tokens(tokens), last(), current(), cursor(tokens.begin()), is_binary(is_binary) {
+ corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) {
root = new_Scope(*this, true);
scopes.push_back(root);
}
@@ -1187,7 +1206,7 @@ std::string ParseTokenAsString(const TokenPtr t) {
// ------------------------------------------------------------------------------------------------
// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) {
+ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
const ElementPtr el = sc->GetElement(index);
TokenPtr token = el->KeyToken();
ERR_FAIL_COND_V(!token, nullptr);
@@ -1208,7 +1227,7 @@ bool HasElement(const ScopePtr sc, const std::string &index) {
// ------------------------------------------------------------------------------------------------
// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) {
+ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
const ElementPtr el = sc->GetElement(index);
return el;
}
@@ -1231,6 +1250,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) {
}
// ------------------------------------------------------------------------------------------------
+// extract optional compound scope
+ScopePtr GetOptionalScope(const ElementPtr el) {
+ if (el) {
+ ScopePtr s = el->Compound();
+ TokenPtr token = el->KeyToken();
+
+ if (token && s) {
+ return s;
+ }
+ }
+
+ return nullptr;
+}
+
+// ------------------------------------------------------------------------------------------------
// get token at a particular index
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) {
if (el) {
diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h
index 37d27d3dca..8b248e8791 100644
--- a/modules/fbx/fbx_parser/FBXParser.h
+++ b/modules/fbx/fbx_parser/FBXParser.h
@@ -160,7 +160,7 @@ public:
}
ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
- for (auto element = elements.begin(); element != elements.end(); ++element) {
+ for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) {
if (element->first.compare(elementName)) {
return element->second;
}
@@ -199,6 +199,10 @@ public:
return is_binary;
}
+ bool IsCorrupt() const {
+ return corrupt;
+ }
+
private:
friend class Scope;
friend class Element;
@@ -208,6 +212,7 @@ private:
TokenPtr CurrentToken() const;
private:
+ bool corrupt = false;
ScopeList scopes;
const TokenList &tokens;
@@ -249,6 +254,8 @@ bool HasElement(const ScopePtr sc, const std::string &index);
// extract a required element from a scope, abort if the element cannot be found
ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
+ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now)
+
ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
// extract required compound scope
ScopePtr GetRequiredScope(const ElementPtr el);
diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp
index 8ab94e1ef4..37717e9109 100644
--- a/modules/fbx/fbx_parser/FBXProperties.cpp
+++ b/modules/fbx/fbx_parser/FBXProperties.cpp
@@ -94,7 +94,7 @@ Property::~Property() {
namespace {
// ------------------------------------------------------------------------------------------------
-// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
+// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
PropertyPtr ReadTypedProperty(const ElementPtr element) {
//ai_assert(element.KeyToken().StringContents() == "P");
@@ -146,14 +146,32 @@ std::string PeekPropertyName(const Element &element) {
// ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable() :
- templateProps(), element() {
+ element(nullptr) {
+}
+
+// Is used when dealing with FBX Objects not metadata.
+PropertyTable::PropertyTable(const ElementPtr element) :
+ element(element) {
+ Setup(element);
}
// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
- templateProps(templateProps), element(element) {
- const ScopePtr scope = GetRequiredScope(element);
- ERR_FAIL_COND(!scope);
+PropertyTable::~PropertyTable() {
+ for (PropertyMap::value_type &v : props) {
+ delete v.second;
+ }
+}
+
+void PropertyTable::Setup(ElementPtr ptr) {
+ const ScopePtr sc = GetRequiredScope(ptr);
+ const ElementPtr Properties70 = sc->GetElement("Properties70");
+ const ScopePtr scope = GetOptionalScope(Properties70);
+
+ // no scope, no care.
+ if (!scope) {
+ return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it.
+ }
+
for (const ElementMap::value_type &v : scope->Elements()) {
if (v.first != "P") {
DOMWarning("expected only P elements in property table", v.second);
@@ -178,13 +196,6 @@ PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *temp
}
// ------------------------------------------------------------------------------------------------
-PropertyTable::~PropertyTable() {
- for (PropertyMap::value_type &v : props) {
- delete v.second;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
PropertyPtr PropertyTable::Get(const std::string &name) const {
PropertyMap::const_iterator it = props.find(name);
if (it == props.end()) {
@@ -199,10 +210,6 @@ PropertyPtr PropertyTable::Get(const std::string &name) const {
if (it == props.end()) {
// check property template
- if (templateProps) {
- return templateProps->Get(name);
- }
-
return nullptr;
}
}
@@ -216,8 +223,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
// Loop through all the lazy properties (which is all the properties)
for (const LazyPropertyMap::value_type &element : lazyProps) {
// Skip parsed properties
- if (props.end() != props.find(element.first))
+ if (props.end() != props.find(element.first)) {
continue;
+ }
// Read the element's value.
// Wrap the naked pointer (since the call site is required to acquire ownership)
@@ -225,8 +233,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
Property *prop = ReadTypedProperty(element.second);
// Element could not be read. Skip it.
- if (!prop)
+ if (!prop) {
continue;
+ }
// Add to result
result[element.first] = prop;
diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h
index 27cacfaf76..bfd27ac94e 100644
--- a/modules/fbx/fbx_parser/FBXProperties.h
+++ b/modules/fbx/fbx_parser/FBXProperties.h
@@ -137,35 +137,31 @@ class PropertyTable {
public:
// in-memory property table with no source element
PropertyTable();
- PropertyTable(const ElementPtr element, const PropertyTable *templateProps);
- ~PropertyTable();
+ PropertyTable(const ElementPtr element);
+ virtual ~PropertyTable();
PropertyPtr Get(const std::string &name) const;
+ void Setup(ElementPtr ptr);
// PropertyTable's need not be coupled with FBX elements so this can be NULL
- ElementPtr GetElement() const {
+ ElementPtr GetElement() {
return element;
}
- PropertyMap &GetProperties() const {
+ PropertyMap &GetProperties() {
return props;
}
- const LazyPropertyMap &GetLazyProperties() const {
+ const LazyPropertyMap &GetLazyProperties() {
return lazyProps;
}
- const PropertyTable *TemplateProps() const {
- return templateProps;
- }
-
DirectPropertyMap GetUnparsedProperties() const;
private:
LazyPropertyMap lazyProps;
mutable PropertyMap props;
- const PropertyTable *templateProps = nullptr;
- const ElementPtr element = nullptr;
+ ElementPtr element = nullptr;
};
// ------------------------------------------------------------------------------------------------
@@ -190,16 +186,11 @@ template <typename T>
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
PropertyPtr prop = in->Get(name);
if (nullptr == prop) {
- if (!useTemplate) {
- result = false;
- return T();
- }
- const PropertyTable *templ = in->TemplateProps();
- if (nullptr == templ) {
+ if (nullptr == in) {
result = false;
return T();
}
- prop = templ->Get(name);
+ prop = in->Get(name);
if (nullptr == prop) {
result = false;
return T();
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp
index ea4568fe32..81c5b128e8 100644
--- a/modules/fbx/fbx_parser/FBXTokenizer.cpp
+++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp
@@ -141,7 +141,7 @@ void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *
} // namespace
// ------------------------------------------------------------------------------------------------
-void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
+void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
// line and column numbers numbers are one-based
unsigned int line = 1;
unsigned int column = 1;
@@ -185,6 +185,8 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
case '\"':
if (token_begin) {
TokenizeError("unexpected double-quote", line, column);
+ corrupt = true;
+ return;
}
token_begin = cur;
in_double_quotes = true;
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h
index 1e7e5e6535..184d0fd894 100644
--- a/modules/fbx/fbx_parser/FBXTokenizer.h
+++ b/modules/fbx/fbx_parser/FBXTokenizer.h
@@ -187,7 +187,7 @@ typedef std::vector<TokenPtr> TokenList;
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated.
* @print_error if something goes wrong */
-void Tokenize(TokenList &output_tokens, const char *input, size_t length);
+void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
/** Tokenizer function for binary FBX files.
*
@@ -197,7 +197,7 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length);
* @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal.
* @print_error if something goes wrong */
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length);
+void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
} // namespace FBXDocParser
#endif // FBX_TOKENIZER_H
diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp
index 80ea5fab4c..1f14a69099 100644
--- a/modules/fbx/fbx_parser/FBXUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXUtil.cpp
@@ -121,9 +121,10 @@ static const uint8_t base64DecodeTable[128] = {
};
uint8_t DecodeBase64(char ch) {
- const auto idx = static_cast<uint8_t>(ch);
- if (idx > 127)
+ const uint8_t idx = static_cast<uint8_t>(ch);
+ if (idx > 127) {
return 255;
+ }
return base64DecodeTable[idx];
}
@@ -211,8 +212,9 @@ std::string EncodeBase64(const char *data, size_t length) {
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
// add '=' at the end
- for (size_t i = 0; i < 4 * extraBytes / 3; i++)
+ for (size_t i = 0; i < 4 * extraBytes / 3; i++) {
encoded_string[encodedBytes - i - 1] = '=';
+ }
}
return encoded_string;
}
diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h
index 6261138812..cf0f811e35 100644
--- a/modules/fbx/tools/import_utils.h
+++ b/modules/fbx/tools/import_utils.h
@@ -267,7 +267,7 @@ public:
*/
// static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
// ERR_FAIL_COND(texture.is_null());
- // ERR_FAIL_COND(map_mode == NULL);
+ // ERR_FAIL_COND(map_mode == nullptr);
// aiTextureMapMode tex_mode = map_mode[0];
// int32_t flags = Texture::FLAGS_DEFAULT;
@@ -339,7 +339,7 @@ public:
// } else {
// Ref<Texture> texture = ResourceLoader::load(p_path);
// ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
- // Ref<Image> image = texture->get_data();
+ // Ref<Image> image = texture->get_image();
// ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
// state.path_to_image_cache.insert(p_path, image);
// return image;
@@ -382,7 +382,7 @@ public:
// String &path,
// AssimpImageData &image_state) {
// aiString ai_filename = aiString();
- // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
+ // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
// return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
// }
diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h
index ced100aed2..fe0c92b22f 100644
--- a/modules/fbx/tools/validation_tools.h
+++ b/modules/fbx/tools/validation_tools.h
@@ -65,8 +65,9 @@ protected:
Error err;
FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err);
if (!file || err) {
- if (file)
+ if (file) {
memdelete(file);
+ }
print_error("ValidationTracker Error - failed to create file - path: %s\n" + path);
return;
}
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index e3a359e09a..0de6b27d27 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -110,6 +110,16 @@ bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_property) const
return false;
}
+void GDNativeLibrary::reset_state() {
+ config_file.instance();
+ current_library_path = "";
+ current_dependencies.clear();
+ symbol_prefix = default_symbol_prefix;
+ load_once = default_load_once;
+ singleton = default_singleton;
+ reloadable = default_reloadable;
+}
+
void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
// set entries
List<String> entry_key_list;
@@ -149,6 +159,8 @@ void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
}
void GDNativeLibrary::set_config_file(Ref<ConfigFile> p_config_file) {
+ ERR_FAIL_COND(p_config_file.is_null());
+
set_singleton(p_config_file->get_value("general", "singleton", default_singleton));
set_load_once(p_config_file->get_value("general", "load_once", default_load_once));
set_symbol_prefix(p_config_file->get_value("general", "symbol_prefix", default_symbol_prefix));
@@ -508,7 +520,7 @@ Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_
return result;
}
-RES GDNativeLibraryResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES GDNativeLibraryResourceLoader::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<GDNativeLibrary> lib;
lib.instance();
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index 765087d176..a28c58ec0d 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -63,6 +63,8 @@ class GDNativeLibrary : public Resource {
bool reloadable;
public:
+ virtual void reset_state() override;
+
GDNativeLibrary();
~GDNativeLibrary();
@@ -166,7 +168,7 @@ public:
class GDNativeLibraryResourceLoader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, 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;
diff --git a/modules/gdnative/gdnative/aabb.cpp b/modules/gdnative/gdnative/aabb.cpp
index 5d3f224adc..c42b874b4b 100644
--- a/modules/gdnative/gdnative/aabb.cpp
+++ b/modules/gdnative/gdnative/aabb.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_aabb_new(godot_aabb *p_self) {
memnew_placement(p_self, AABB);
}
+void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src) {
+ memnew_placement(r_dest, AABB(*(AABB *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 87a8c8e376..76e131dc06 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -43,10 +43,24 @@ void GDAPI godot_array_new(godot_array *p_self) {
memnew_placement(p_self, Array);
}
+void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src) {
+ memnew_placement(r_dest, Array(*(Array *)p_src));
+}
+
void GDAPI godot_array_destroy(godot_array *p_self) {
((Array *)p_self)->~Array();
}
+godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, godot_int p_index) {
+ Array *self = (Array *)p_self;
+ return (godot_variant *)&self->operator[](p_index);
+}
+
+const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, godot_int p_index) {
+ const Array *self = (const Array *)p_self;
+ return (const godot_variant *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index 86a6d6216c..4641f0bacc 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -42,6 +42,20 @@ void GDAPI godot_basis_new(godot_basis *p_self) {
memnew_placement(p_self, Basis);
}
+void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src) {
+ memnew_placement(r_dest, Basis(*(Basis *)p_src));
+}
+
+godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index) {
+ Basis *self = (Basis *)p_self;
+ return (godot_vector3 *)&self->operator[](p_index);
+}
+
+const godot_vector3 GDAPI *godot_basis_operator_index_const(const godot_basis *p_self, godot_int p_index) {
+ const Basis *self = (const Basis *)p_self;
+ return (const godot_vector3 *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/callable.cpp b/modules/gdnative/gdnative/callable.cpp
index 7c62b5928f..85274e5e22 100644
--- a/modules/gdnative/gdnative/callable.cpp
+++ b/modules/gdnative/gdnative/callable.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_callable_new(godot_callable *p_self) {
memnew_placement(p_self, Callable);
}
+void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src) {
+ memnew_placement(r_dest, Callable(*(Callable *)p_src));
+}
+
void GDAPI godot_callable_destroy(godot_callable *p_self) {
Callable *self = (Callable *)p_self;
self->~Callable();
diff --git a/modules/gdnative/gdnative/color.cpp b/modules/gdnative/gdnative/color.cpp
index 784c8d439e..502f89c027 100644
--- a/modules/gdnative/gdnative/color.cpp
+++ b/modules/gdnative/gdnative/color.cpp
@@ -42,6 +42,20 @@ void GDAPI godot_color_new(godot_color *p_self) {
memnew_placement(p_self, Color);
}
+void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src) {
+ memnew_placement(r_dest, Color(*(Color *)p_src));
+}
+
+float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index) {
+ Color *self = (Color *)p_self;
+ return (float *)&self->operator[](p_index);
+}
+
+const float GDAPI *godot_color_operator_index_const(const godot_color *p_self, godot_int p_index) {
+ const Color *self = (const Color *)p_self;
+ return (const float *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp
index d58e08f4b0..2bfad6e695 100644
--- a/modules/gdnative/gdnative/dictionary.cpp
+++ b/modules/gdnative/gdnative/dictionary.cpp
@@ -31,6 +31,7 @@
#include "gdnative/dictionary.h"
#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
static_assert(sizeof(godot_dictionary) == sizeof(Dictionary), "Dictionary size mismatch");
@@ -42,11 +43,25 @@ void GDAPI godot_dictionary_new(godot_dictionary *p_self) {
memnew_placement(p_self, Dictionary);
}
+void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src) {
+ memnew_placement(r_dest, Dictionary(*(Dictionary *)p_src));
+}
+
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self) {
Dictionary *self = (Dictionary *)p_self;
self->~Dictionary();
}
+godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key) {
+ Dictionary *self = (Dictionary *)p_self;
+ return (godot_variant *)&self->operator[](*((const Variant *)p_key));
+}
+
+const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key) {
+ const Dictionary *self = (const Dictionary *)p_self;
+ return (const godot_variant *)&self->operator[](*((const Variant *)p_key));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index c3d25f81c7..b84ce2d192 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -127,6 +127,17 @@ void GDAPI godot_free(void *p_ptr) {
memfree(p_ptr);
}
+// Helper print functions.
+void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR);
+}
+void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING);
+}
+void GDAPI godot_print_script_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
+ _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_SCRIPT);
+}
+
void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have) {
String message = "Error loading GDNative file ";
GDNativeLibrary *library = (GDNativeLibrary *)p_library;
diff --git a/modules/gdnative/gdnative/node_path.cpp b/modules/gdnative/gdnative/node_path.cpp
index 02c2f9b22b..57d67b9abb 100644
--- a/modules/gdnative/gdnative/node_path.cpp
+++ b/modules/gdnative/gdnative/node_path.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_node_path_new(godot_node_path *p_self) {
memnew_placement(p_self, NodePath);
}
+void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src) {
+ memnew_placement(r_dest, NodePath(*(NodePath *)p_src));
+}
+
void GDAPI godot_node_path_destroy(godot_node_path *p_self) {
NodePath *self = (NodePath *)p_self;
self->~NodePath();
diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp
index 9e4c6e6f38..396109e576 100644
--- a/modules/gdnative/gdnative/packed_arrays.cpp
+++ b/modules/gdnative/gdnative/packed_arrays.cpp
@@ -59,110 +59,264 @@ void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self) {
memnew_placement(p_self, PackedByteArray);
}
+void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src) {
+ memnew_placement(r_dest, PackedByteArray(*(PackedByteArray *)p_src));
+}
+
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self) {
((PackedByteArray *)p_self)->~PackedByteArray();
}
+uint8_t GDAPI *godot_packed_byte_array_operator_index(godot_packed_byte_array *p_self, godot_int p_index) {
+ PackedByteArray *self = (PackedByteArray *)p_self;
+ return (uint8_t *)&self->operator[](p_index);
+}
+
+const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_packed_byte_array *p_self, godot_int p_index) {
+ const PackedByteArray *self = (const PackedByteArray *)p_self;
+ return (const uint8_t *)&self->operator[](p_index);
+}
+
// int32
void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self) {
memnew_placement(p_self, PackedInt32Array);
}
+void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src) {
+ memnew_placement(r_dest, PackedInt32Array(*(PackedInt32Array *)p_src));
+}
+
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self) {
((PackedInt32Array *)p_self)->~PackedInt32Array();
}
+int32_t GDAPI *godot_packed_int32_array_operator_index(godot_packed_int32_array *p_self, godot_int p_index) {
+ PackedInt32Array *self = (PackedInt32Array *)p_self;
+ return (int32_t *)&self->operator[](p_index);
+}
+
+const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_packed_int32_array *p_self, godot_int p_index) {
+ const PackedInt32Array *self = (const PackedInt32Array *)p_self;
+ return (const int32_t *)&self->operator[](p_index);
+}
+
// int64
void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self) {
memnew_placement(p_self, PackedInt64Array);
}
+void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src) {
+ memnew_placement(r_dest, PackedInt64Array(*(PackedInt64Array *)p_src));
+}
+
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self) {
((PackedInt64Array *)p_self)->~PackedInt64Array();
}
+int64_t GDAPI *godot_packed_int64_array_operator_index(godot_packed_int64_array *p_self, godot_int p_index) {
+ PackedInt64Array *self = (PackedInt64Array *)p_self;
+ return (int64_t *)&self->operator[](p_index);
+}
+
+const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_packed_int64_array *p_self, godot_int p_index) {
+ const PackedInt64Array *self = (const PackedInt64Array *)p_self;
+ return (const int64_t *)&self->operator[](p_index);
+}
+
// float32
void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self) {
memnew_placement(p_self, PackedFloat32Array);
}
+void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src) {
+ memnew_placement(r_dest, PackedFloat32Array(*(PackedFloat32Array *)p_src));
+}
+
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self) {
((PackedFloat32Array *)p_self)->~PackedFloat32Array();
}
+float GDAPI *godot_packed_float32_array_operator_index(godot_packed_float32_array *p_self, godot_int p_index) {
+ PackedFloat32Array *self = (PackedFloat32Array *)p_self;
+ return (float *)&self->operator[](p_index);
+}
+
+const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_packed_float32_array *p_self, godot_int p_index) {
+ const PackedFloat32Array *self = (const PackedFloat32Array *)p_self;
+ return (const float *)&self->operator[](p_index);
+}
+
// float64
void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self) {
memnew_placement(p_self, PackedFloat64Array);
}
+void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src) {
+ memnew_placement(r_dest, PackedFloat64Array(*(PackedFloat64Array *)p_src));
+}
+
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self) {
((PackedFloat64Array *)p_self)->~PackedFloat64Array();
}
+double GDAPI *godot_packed_float64_array_operator_index(godot_packed_float64_array *p_self, godot_int p_index) {
+ PackedFloat64Array *self = (PackedFloat64Array *)p_self;
+ return (double *)&self->operator[](p_index);
+}
+
+const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_packed_float64_array *p_self, godot_int p_index) {
+ const PackedFloat64Array *self = (const PackedFloat64Array *)p_self;
+ return (const double *)&self->operator[](p_index);
+}
+
// string
void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self) {
memnew_placement(p_self, PackedStringArray);
}
+void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src) {
+ memnew_placement(r_dest, PackedStringArray(*(PackedStringArray *)p_src));
+}
+
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self) {
((PackedStringArray *)p_self)->~PackedStringArray();
}
+godot_string GDAPI *godot_packed_string_array_operator_index(godot_packed_string_array *p_self, godot_int p_index) {
+ PackedStringArray *self = (PackedStringArray *)p_self;
+ return (godot_string *)&self->operator[](p_index);
+}
+
+const godot_string GDAPI *godot_packed_string_array_operator_index_const(const godot_packed_string_array *p_self, godot_int p_index) {
+ const PackedStringArray *self = (const PackedStringArray *)p_self;
+ return (const godot_string *)&self->operator[](p_index);
+}
+
// vector2
void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self) {
memnew_placement(p_self, PackedVector2Array);
}
+void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src) {
+ memnew_placement(r_dest, PackedVector2Array(*(PackedVector2Array *)p_src));
+}
+
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self) {
((PackedVector2Array *)p_self)->~PackedVector2Array();
}
+godot_vector2 GDAPI *godot_packed_vector2_array_operator_index(godot_packed_vector2_array *p_self, godot_int p_index) {
+ PackedVector2Array *self = (PackedVector2Array *)p_self;
+ return (godot_vector2 *)&self->operator[](p_index);
+}
+
+const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const godot_packed_vector2_array *p_self, godot_int p_index) {
+ const PackedVector2Array *self = (const PackedVector2Array *)p_self;
+ return (const godot_vector2 *)&self->operator[](p_index);
+}
+
// vector2i
void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self) {
memnew_placement(p_self, Vector<Vector2i>);
}
+void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src) {
+ memnew_placement(r_dest, Vector<Vector2i>(*(Vector<Vector2i> *)p_src));
+}
+
void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self) {
((Vector<Vector2i> *)p_self)->~Vector();
}
+godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index(godot_packed_vector2i_array *p_self, godot_int p_index) {
+ Vector<Vector2i> *self = (Vector<Vector2i> *)p_self;
+ return (godot_vector2i *)&self->operator[](p_index);
+}
+
+const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(const godot_packed_vector2i_array *p_self, godot_int p_index) {
+ const Vector<Vector2i> *self = (const Vector<Vector2i> *)p_self;
+ return (const godot_vector2i *)&self->operator[](p_index);
+}
+
// vector3
void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self) {
memnew_placement(p_self, PackedVector3Array);
}
+void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src) {
+ memnew_placement(r_dest, PackedVector3Array(*(PackedVector3Array *)p_src));
+}
+
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self) {
((PackedVector3Array *)p_self)->~PackedVector3Array();
}
+godot_vector3 GDAPI *godot_packed_vector3_array_operator_index(godot_packed_vector3_array *p_self, godot_int p_index) {
+ PackedVector3Array *self = (PackedVector3Array *)p_self;
+ return (godot_vector3 *)&self->operator[](p_index);
+}
+
+const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const godot_packed_vector3_array *p_self, godot_int p_index) {
+ const PackedVector3Array *self = (const PackedVector3Array *)p_self;
+ return (const godot_vector3 *)&self->operator[](p_index);
+}
+
// vector3i
void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self) {
memnew_placement(p_self, Vector<Vector3i>);
}
+void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src) {
+ memnew_placement(r_dest, Vector<Vector3i>(*(Vector<Vector3i> *)p_src));
+}
+
void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self) {
((Vector<Vector3i> *)p_self)->~Vector();
}
+godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index(godot_packed_vector3i_array *p_self, godot_int p_index) {
+ Vector<Vector3i> *self = (Vector<Vector3i> *)p_self;
+ return (godot_vector3i *)&self->operator[](p_index);
+}
+
+const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(const godot_packed_vector3i_array *p_self, godot_int p_index) {
+ const Vector<Vector3i> *self = (const Vector<Vector3i> *)p_self;
+ return (const godot_vector3i *)&self->operator[](p_index);
+}
+
// color
void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self) {
memnew_placement(p_self, PackedColorArray);
}
+void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src) {
+ memnew_placement(r_dest, PackedColorArray(*(PackedColorArray *)p_src));
+}
+
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self) {
((PackedColorArray *)p_self)->~PackedColorArray();
}
+godot_color GDAPI *godot_packed_color_array_operator_index(godot_packed_color_array *p_self, godot_int p_index) {
+ PackedColorArray *self = (PackedColorArray *)p_self;
+ return (godot_color *)&self->operator[](p_index);
+}
+
+const godot_color GDAPI *godot_packed_color_array_operator_index_const(const godot_packed_color_array *p_self, godot_int p_index) {
+ const PackedColorArray *self = (const PackedColorArray *)p_self;
+ return (const godot_color *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/plane.cpp b/modules/gdnative/gdnative/plane.cpp
index 61d5e09fad..8b8e84e3c1 100644
--- a/modules/gdnative/gdnative/plane.cpp
+++ b/modules/gdnative/gdnative/plane.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_plane_new(godot_plane *p_self) {
memnew_placement(p_self, Plane);
}
+void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src) {
+ memnew_placement(r_dest, Plane(*(Plane *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quat.cpp
index 87f1d7d8e5..8ebcf7c91f 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quat.cpp
@@ -42,6 +42,20 @@ void GDAPI godot_quat_new(godot_quat *p_self) {
memnew_placement(p_self, Quat);
}
+void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src) {
+ memnew_placement(r_dest, Quat(*(Quat *)p_src));
+}
+
+godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index) {
+ Quat *self = (Quat *)p_self;
+ return (godot_real_t *)&self->operator[](p_index);
+}
+
+const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index) {
+ const Quat *self = (const Quat *)p_self;
+ return (const godot_real_t *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 086592ec22..a196a63188 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -43,10 +43,18 @@ void GDAPI godot_rect2_new(godot_rect2 *p_self) {
memnew_placement(p_self, Rect2);
}
+void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src) {
+ memnew_placement(r_dest, Rect2(*(Rect2 *)p_src));
+}
+
void GDAPI godot_rect2i_new(godot_rect2i *p_self) {
memnew_placement(p_self, Rect2i);
}
+void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src) {
+ memnew_placement(r_dest, Rect2i(*(Rect2i *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/rid.cpp b/modules/gdnative/gdnative/rid.cpp
index 5cab9a21ed..f8599afcf9 100644
--- a/modules/gdnative/gdnative/rid.cpp
+++ b/modules/gdnative/gdnative/rid.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_rid_new(godot_rid *p_self) {
memnew_placement(p_self, RID);
}
+void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src) {
+ memnew_placement(r_dest, RID(*(RID *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/signal.cpp b/modules/gdnative/gdnative/signal.cpp
index bcb4c93b62..5963c0e6c6 100644
--- a/modules/gdnative/gdnative/signal.cpp
+++ b/modules/gdnative/gdnative/signal.cpp
@@ -43,6 +43,10 @@ void GDAPI godot_signal_new(godot_signal *p_self) {
memnew_placement(p_self, Signal);
}
+void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src) {
+ memnew_placement(r_dest, Signal(*(Signal *)p_src));
+}
+
void GDAPI godot_signal_destroy(godot_signal *p_self) {
Signal *self = (Signal *)p_self;
self->~Signal();
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 19d95f2048..1ad1ea8bdf 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -45,10 +45,7 @@ void GDAPI godot_string_new(godot_string *r_dest) {
}
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src) {
- String *dest = (String *)r_dest;
- const String *src = (const String *)p_src;
- memnew_placement(dest, String);
- *dest = String(*src);
+ memnew_placement(r_dest, String(*(String *)p_src));
}
void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents) {
@@ -125,6 +122,45 @@ void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const
}
}
+const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->ascii(true).get_data();
+}
+
+const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->utf8().get_data();
+}
+
+const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->utf16().get_data();
+}
+
+const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ return self->get_data();
+}
+
+const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self) {
+ String *self = (String *)p_self;
+ if (sizeof(wchar_t) == 2) {
+ return (const wchar_t *)self->utf16().get_data();
+ } else {
+ return (const wchar_t *)self->get_data();
+ }
+}
+
+char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index) {
+ String *self = (String *)p_self;
+ return self->ptrw();
+}
+
+const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index) {
+ const String *self = (const String *)p_self;
+ return self->ptr();
+}
+
void GDAPI godot_string_destroy(godot_string *p_self) {
String *self = (String *)p_self;
self->~String();
diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/gdnative/gdnative/string_name.cpp
index c9d2dd5bc3..bd8f69674e 100644
--- a/modules/gdnative/gdnative/string_name.cpp
+++ b/modules/gdnative/gdnative/string_name.cpp
@@ -44,9 +44,7 @@ void GDAPI godot_string_name_new(godot_string_name *r_dest) {
}
void GDAPI godot_string_name_new_copy(godot_string_name *r_dest, const godot_string_name *p_src) {
- StringName *dest = (StringName *)r_dest;
- const StringName *src = (const StringName *)p_src;
- memnew_placement(dest, StringName(*src));
+ memnew_placement(r_dest, StringName(*(StringName *)p_src));
}
void GDAPI godot_string_name_new_with_latin1_chars(godot_string_name *r_dest, const char *p_contents) {
diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform.cpp
index eae981bd07..bfaaa13db2 100644
--- a/modules/gdnative/gdnative/transform.cpp
+++ b/modules/gdnative/gdnative/transform.cpp
@@ -42,6 +42,10 @@ void GDAPI godot_transform_new(godot_transform *p_self) {
memnew_placement(p_self, Transform);
}
+void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src) {
+ memnew_placement(r_dest, Transform(*(Transform *)p_src));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp
index e2c933f1ea..2864818831 100644
--- a/modules/gdnative/gdnative/transform2d.cpp
+++ b/modules/gdnative/gdnative/transform2d.cpp
@@ -42,6 +42,20 @@ void GDAPI godot_transform2d_new(godot_transform2d *p_self) {
memnew_placement(p_self, Transform2D);
}
+void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src) {
+ memnew_placement(r_dest, Transform2D(*(Transform2D *)p_src));
+}
+
+godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index) {
+ Transform2D *self = (Transform2D *)p_self;
+ return (godot_vector2 *)&self->operator[](p_index);
+}
+
+const godot_vector2 GDAPI *godot_transform2d_operator_index_const(const godot_transform2d *p_self, godot_int p_index) {
+ const Transform2D *self = (const Transform2D *)p_self;
+ return (const godot_vector2 *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index 79f5a536e5..7801e21ab2 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -577,6 +577,54 @@ void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_
}
}
+void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant *self = (Variant *)p_self;
+ const StringName method(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ self->call(method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant::Type type = (Variant::Type)p_type;
+ const StringName *method = (const StringName *)p_method;
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ Variant::call_static(type, *method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
+void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argcount, godot_variant *r_return, godot_variant_call_error *r_error) {
+ Variant::Type type = (Variant::Type)p_type;
+ const StringName method(p_method);
+ const Variant **args = (const Variant **)p_args;
+ Variant ret;
+ Callable::CallError error;
+ Variant::call_static(type, method, args, p_argcount, ret, error);
+ memnew_placement_custom(r_return, Variant, Variant(ret));
+
+ if (r_error) {
+ r_error->error = (godot_variant_call_error_error)error.error;
+ r_error->argument = error.argument;
+ r_error->expected = (godot_variant_type)error.expected;
+ }
+}
+
void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid) {
Variant::Operator op = (Variant::Operator)p_op;
const Variant *a = (const Variant *)p_a;
@@ -593,12 +641,20 @@ void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key,
self->set(*key, *value, r_valid);
}
-void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid) {
+void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_key, const godot_variant *p_value, bool *r_valid) {
Variant *self = (Variant *)p_self;
- const StringName *name = (const StringName *)p_name;
+ const StringName *key = (const StringName *)p_key;
const Variant *value = (const Variant *)p_value;
- self->set_named(*name, *value, *r_valid);
+ self->set_named(*key, *value, *r_valid);
+}
+
+void GDAPI godot_variant_set_named_with_cstring(godot_variant *p_self, const char *p_key, const godot_variant *p_value, bool *r_valid) {
+ Variant *self = (Variant *)p_self;
+ const StringName key(p_key);
+ const Variant *value = (const Variant *)p_value;
+
+ self->set_named(key, *value, *r_valid);
}
void GDAPI godot_variant_set_keyed(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid) {
@@ -638,6 +694,17 @@ godot_variant GDAPI godot_variant_get_named(const godot_variant *p_self, const g
return result;
}
+godot_variant GDAPI godot_variant_get_named_with_cstring(const godot_variant *p_self, const char *p_key, bool *r_valid) {
+ const Variant *self = (const Variant *)p_self;
+ const StringName *key = (const StringName *)p_key;
+ Variant ret;
+
+ ret = self->get_named(*key, *r_valid);
+ godot_variant result;
+ memnew_placement_custom(&result, Variant, Variant(ret));
+ return result;
+}
+
godot_variant GDAPI godot_variant_get_keyed(const godot_variant *p_self, const godot_variant *p_key, bool *r_valid) {
const Variant *self = (const Variant *)p_self;
const Variant *key = (const Variant *)p_key;
@@ -824,6 +891,14 @@ bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type
return Variant::is_builtin_method_const((Variant::Type)p_type, StringName(p_method));
}
+bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method) {
+ return Variant::is_builtin_method_static((Variant::Type)p_type, *((const StringName *)p_method));
+}
+
+bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method) {
+ return Variant::is_builtin_method_static((Variant::Type)p_type, StringName(p_method));
+}
+
bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method) {
return Variant::is_builtin_method_vararg((Variant::Type)p_type, *((const StringName *)p_method));
}
@@ -1065,6 +1140,22 @@ void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_functi
}
}
+godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function(const godot_string_name *p_function) {
+ return (godot_ptr_utility_function)Variant::get_ptr_utility_function(*((const StringName *)p_function));
+}
+
+godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function_with_cstring(const char *p_function) {
+ return (godot_ptr_utility_function)Variant::get_ptr_utility_function(StringName(p_function));
+}
+
+godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function(const godot_string_name *p_function) {
+ return (godot_validated_utility_function)Variant::get_validated_utility_function(*((const StringName *)p_function));
+}
+
+godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function_with_cstring(const char *p_function) {
+ return (godot_validated_utility_function)Variant::get_validated_utility_function(StringName(p_function));
+}
+
godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function) {
return (godot_variant_utility_function_type)Variant::get_utility_function_type(*((const StringName *)p_function));
}
diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp
index e2f957e4f2..6a01a7ad59 100644
--- a/modules/gdnative/gdnative/vector2.cpp
+++ b/modules/gdnative/gdnative/vector2.cpp
@@ -43,10 +43,38 @@ void GDAPI godot_vector2_new(godot_vector2 *p_self) {
memnew_placement(p_self, Vector2);
}
+void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src) {
+ memnew_placement(r_dest, Vector2(*(Vector2 *)p_src));
+}
+
void GDAPI godot_vector2i_new(godot_vector2i *p_self) {
memnew_placement(p_self, Vector2i);
}
+void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src) {
+ memnew_placement(r_dest, Vector2i(*(Vector2i *)p_src));
+}
+
+godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index) {
+ Vector2 *self = (Vector2 *)p_self;
+ return (godot_real_t *)&self->operator[](p_index);
+}
+
+const godot_real_t GDAPI *godot_vector2_operator_index_const(const godot_vector2 *p_self, godot_int p_index) {
+ const Vector2 *self = (const Vector2 *)p_self;
+ return (const godot_real_t *)&self->operator[](p_index);
+}
+
+int32_t GDAPI *godot_vector2i_operator_index(godot_vector2i *p_self, godot_int p_index) {
+ Vector2i *self = (Vector2i *)p_self;
+ return (int32_t *)&self->operator[](p_index);
+}
+
+const int32_t GDAPI *godot_vector2i_operator_index_const(const godot_vector2i *p_self, godot_int p_index) {
+ const Vector2i *self = (const Vector2i *)p_self;
+ return (const int32_t *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/vector3.cpp b/modules/gdnative/gdnative/vector3.cpp
index ee365edaec..fb426c8ac4 100644
--- a/modules/gdnative/gdnative/vector3.cpp
+++ b/modules/gdnative/gdnative/vector3.cpp
@@ -43,10 +43,38 @@ void GDAPI godot_vector3_new(godot_vector3 *p_self) {
memnew_placement(p_self, Vector3);
}
+void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src) {
+ memnew_placement(r_dest, Vector3(*(Vector3 *)p_src));
+}
+
void GDAPI godot_vector3i_new(godot_vector3i *p_self) {
memnew_placement(p_self, Vector3i);
}
+void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src) {
+ memnew_placement(r_dest, Vector3i(*(Vector3i *)p_src));
+}
+
+godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index) {
+ Vector3 *self = (Vector3 *)p_self;
+ return (godot_real_t *)&self->operator[](p_index);
+}
+
+const godot_real_t GDAPI *godot_vector3_operator_index_const(const godot_vector3 *p_self, godot_int p_index) {
+ const Vector3 *self = (const Vector3 *)p_self;
+ return (const godot_real_t *)&self->operator[](p_index);
+}
+
+int32_t GDAPI *godot_vector3i_operator_index(godot_vector3i *p_self, godot_int p_index) {
+ Vector3i *self = (Vector3i *)p_self;
+ return (int32_t *)&self->operator[](p_index);
+}
+
+const int32_t GDAPI *godot_vector3i_operator_index_const(const godot_vector3i *p_self, godot_int p_index) {
+ const Vector3i *self = (const Vector3i *)p_self;
+ return (const int32_t *)&self->operator[](p_index);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 909e91393e..489083e795 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -153,6 +153,72 @@
]
},
{
+ "name": "godot_print_error",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "p_description"
+ ],
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "const char *",
+ "p_file"
+ ],
+ [
+ "int",
+ "p_line"
+ ]
+ ]
+ },
+ {
+ "name": "godot_print_warning",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "p_description"
+ ],
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "const char *",
+ "p_file"
+ ],
+ [
+ "int",
+ "p_line"
+ ]
+ ]
+ },
+ {
+ "name": "godot_print_script_error",
+ "return_type": "void",
+ "arguments": [
+ [
+ "const char *",
+ "p_description"
+ ],
+ [
+ "const char *",
+ "p_function"
+ ],
+ [
+ "const char *",
+ "p_file"
+ ],
+ [
+ "int",
+ "p_line"
+ ]
+ ]
+ },
+ {
"name": "godot_get_class_tag",
"return_type": "void *",
"arguments": [
@@ -1077,6 +1143,36 @@
]
},
{
+ "name": "godot_variant_call_with_cstring",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ],
+ [
+ "const godot_variant **",
+ "p_args"
+ ],
+ [
+ "const godot_int",
+ "p_argument_count"
+ ],
+ [
+ "godot_variant *",
+ "r_return"
+ ],
+ [
+ "godot_variant_call_error *",
+ "r_error"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_evaluate",
"return_type": "void",
"arguments": [
@@ -1134,7 +1230,29 @@
],
[
"const godot_string_name *",
- "p_name"
+ "p_key"
+ ],
+ [
+ "const godot_variant *",
+ "p_value"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_set_named_with_cstring",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_key"
],
[
"const godot_variant *",
@@ -1231,6 +1349,24 @@
]
},
{
+ "name": "godot_variant_get_named_with_cstring",
+ "return_type": "godot_variant",
+ "arguments": [
+ [
+ "const godot_variant *",
+ "p_self"
+ ],
+ [
+ "const char *",
+ "p_key"
+ ],
+ [
+ "bool *",
+ "r_valid"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_get_keyed",
"return_type": "godot_variant",
"arguments": [
@@ -1749,6 +1885,34 @@
]
},
{
+ "name": "godot_variant_is_builtin_method_static",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const godot_string_name *",
+ "p_method"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_is_builtin_method_static_with_cstring",
+ "return_type": "bool",
+ "arguments": [
+ [
+ "godot_variant_type",
+ "p_type"
+ ],
+ [
+ "const char *",
+ "p_method"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_is_builtin_method_vararg",
"return_type": "bool",
"arguments": [
@@ -2371,6 +2535,46 @@
]
},
{
+ "name": "godot_variant_get_ptr_utility_function",
+ "return_type": "godot_ptr_utility_function",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_ptr_utility_function_with_cstring",
+ "return_type": "godot_ptr_utility_function",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_utility_function",
+ "return_type": "godot_validated_utility_function",
+ "arguments": [
+ [
+ "const godot_string_name *",
+ "p_function"
+ ]
+ ]
+ },
+ {
+ "name": "godot_variant_get_validated_utility_function_with_cstring",
+ "return_type": "godot_validated_utility_function",
+ "arguments": [
+ [
+ "const char *",
+ "p_function"
+ ]
+ ]
+ },
+ {
"name": "godot_variant_get_utility_function_type",
"return_type": "godot_variant_utility_function_type",
"arguments": [
@@ -2646,6 +2850,20 @@
]
},
{
+ "name": "godot_aabb_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_aabb *",
+ "r_dest"
+ ],
+ [
+ "const godot_aabb *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_array_new",
"return_type": "void",
"arguments": [
@@ -2656,6 +2874,20 @@
]
},
{
+ "name": "godot_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_array_destroy",
"return_type": "void",
"arguments": [
@@ -2666,6 +2898,34 @@
]
},
{
+ "name": "godot_array_operator_index",
+ "return_type": "godot_variant *",
+ "arguments": [
+ [
+ "godot_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_array_operator_index_const",
+ "return_type": "const godot_variant *",
+ "arguments": [
+ [
+ "const godot_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_basis_new",
"return_type": "void",
"arguments": [
@@ -2676,6 +2936,48 @@
]
},
{
+ "name": "godot_basis_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_basis *",
+ "r_dest"
+ ],
+ [
+ "const godot_basis *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_basis_operator_index",
+ "return_type": "godot_vector3 *",
+ "arguments": [
+ [
+ "godot_basis *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_basis_operator_index_const",
+ "return_type": "const godot_vector3 *",
+ "arguments": [
+ [
+ "const godot_basis *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_callable_new",
"return_type": "void",
"arguments": [
@@ -2686,6 +2988,20 @@
]
},
{
+ "name": "godot_callable_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_callable *",
+ "r_dest"
+ ],
+ [
+ "const godot_callable *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_callable_destroy",
"return_type": "void",
"arguments": [
@@ -2706,6 +3022,48 @@
]
},
{
+ "name": "godot_color_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_color *",
+ "r_dest"
+ ],
+ [
+ "const godot_color *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_color_operator_index",
+ "return_type": "float *",
+ "arguments": [
+ [
+ "godot_color *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_color_operator_index_const",
+ "return_type": "const float *",
+ "arguments": [
+ [
+ "const godot_color *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_dictionary_new",
"return_type": "void",
"arguments": [
@@ -2716,6 +3074,20 @@
]
},
{
+ "name": "godot_dictionary_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_dictionary *",
+ "r_dest"
+ ],
+ [
+ "const godot_dictionary *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_dictionary_destroy",
"return_type": "void",
"arguments": [
@@ -2726,6 +3098,34 @@
]
},
{
+ "name": "godot_dictionary_operator_index",
+ "return_type": "godot_variant *",
+ "arguments": [
+ [
+ "godot_dictionary *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ]
+ ]
+ },
+ {
+ "name": "godot_dictionary_operator_index_const",
+ "return_type": "const godot_variant *",
+ "arguments": [
+ [
+ "const godot_dictionary *",
+ "p_self"
+ ],
+ [
+ "const godot_variant *",
+ "p_key"
+ ]
+ ]
+ },
+ {
"name": "godot_node_path_new",
"return_type": "void",
"arguments": [
@@ -2736,6 +3136,20 @@
]
},
{
+ "name": "godot_node_path_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_node_path *",
+ "r_dest"
+ ],
+ [
+ "const godot_node_path *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_node_path_destroy",
"return_type": "void",
"arguments": [
@@ -2756,6 +3170,20 @@
]
},
{
+ "name": "godot_packed_byte_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_byte_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_byte_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_byte_array_destroy",
"return_type": "void",
"arguments": [
@@ -2766,6 +3194,34 @@
]
},
{
+ "name": "godot_packed_byte_array_operator_index",
+ "return_type": "uint8_t *",
+ "arguments": [
+ [
+ "godot_packed_byte_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_byte_array_operator_index_const",
+ "return_type": "const uint8_t *",
+ "arguments": [
+ [
+ "const godot_packed_byte_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int32_array_new",
"return_type": "void",
"arguments": [
@@ -2776,6 +3232,20 @@
]
},
{
+ "name": "godot_packed_int32_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int32_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int32_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int32_array_destroy",
"return_type": "void",
"arguments": [
@@ -2786,6 +3256,34 @@
]
},
{
+ "name": "godot_packed_int32_array_operator_index",
+ "return_type": "int32_t *",
+ "arguments": [
+ [
+ "godot_packed_int32_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int32_array_operator_index_const",
+ "return_type": "const int32_t *",
+ "arguments": [
+ [
+ "const godot_packed_int32_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int64_array_new",
"return_type": "void",
"arguments": [
@@ -2796,6 +3294,20 @@
]
},
{
+ "name": "godot_packed_int64_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_int64_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_int64_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_int64_array_destroy",
"return_type": "void",
"arguments": [
@@ -2806,6 +3318,34 @@
]
},
{
+ "name": "godot_packed_int64_array_operator_index",
+ "return_type": "int64_t *",
+ "arguments": [
+ [
+ "godot_packed_int64_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_int64_array_operator_index_const",
+ "return_type": "const int64_t *",
+ "arguments": [
+ [
+ "const godot_packed_int64_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float32_array_new",
"return_type": "void",
"arguments": [
@@ -2816,6 +3356,20 @@
]
},
{
+ "name": "godot_packed_float32_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float32_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float32_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float32_array_destroy",
"return_type": "void",
"arguments": [
@@ -2826,6 +3380,34 @@
]
},
{
+ "name": "godot_packed_float32_array_operator_index",
+ "return_type": "float *",
+ "arguments": [
+ [
+ "godot_packed_float32_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float32_array_operator_index_const",
+ "return_type": "const float *",
+ "arguments": [
+ [
+ "const godot_packed_float32_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float64_array_new",
"return_type": "void",
"arguments": [
@@ -2836,6 +3418,20 @@
]
},
{
+ "name": "godot_packed_float64_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_float64_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_float64_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_float64_array_destroy",
"return_type": "void",
"arguments": [
@@ -2846,6 +3442,34 @@
]
},
{
+ "name": "godot_packed_float64_array_operator_index",
+ "return_type": "double *",
+ "arguments": [
+ [
+ "godot_packed_float64_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_float64_array_operator_index_const",
+ "return_type": "const double *",
+ "arguments": [
+ [
+ "const godot_packed_float64_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_string_array_new",
"return_type": "void",
"arguments": [
@@ -2856,6 +3480,20 @@
]
},
{
+ "name": "godot_packed_string_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_string_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_string_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_string_array_destroy",
"return_type": "void",
"arguments": [
@@ -2866,6 +3504,34 @@
]
},
{
+ "name": "godot_packed_string_array_operator_index",
+ "return_type": "godot_string *",
+ "arguments": [
+ [
+ "godot_packed_string_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_string_array_operator_index_const",
+ "return_type": "const godot_string *",
+ "arguments": [
+ [
+ "const godot_packed_string_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2_array_new",
"return_type": "void",
"arguments": [
@@ -2876,6 +3542,20 @@
]
},
{
+ "name": "godot_packed_vector2_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector2_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2_array_destroy",
"return_type": "void",
"arguments": [
@@ -2886,6 +3566,34 @@
]
},
{
+ "name": "godot_packed_vector2_array_operator_index",
+ "return_type": "godot_vector2 *",
+ "arguments": [
+ [
+ "godot_packed_vector2_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2_array_operator_index_const",
+ "return_type": "const godot_vector2 *",
+ "arguments": [
+ [
+ "const godot_packed_vector2_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2i_array_new",
"return_type": "void",
"arguments": [
@@ -2896,6 +3604,20 @@
]
},
{
+ "name": "godot_packed_vector2i_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector2i_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector2i_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector2i_array_destroy",
"return_type": "void",
"arguments": [
@@ -2906,6 +3628,34 @@
]
},
{
+ "name": "godot_packed_vector2i_array_operator_index",
+ "return_type": "godot_vector2i *",
+ "arguments": [
+ [
+ "godot_packed_vector2i_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector2i_array_operator_index_const",
+ "return_type": "const godot_vector2i *",
+ "arguments": [
+ [
+ "const godot_packed_vector2i_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector3_array_new",
"return_type": "void",
"arguments": [
@@ -2916,6 +3666,20 @@
]
},
{
+ "name": "godot_packed_vector3_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector3_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_vector3_array_destroy",
"return_type": "void",
"arguments": [
@@ -2926,6 +3690,96 @@
]
},
{
+ "name": "godot_packed_vector3_array_operator_index",
+ "return_type": "godot_vector3 *",
+ "arguments": [
+ [
+ "godot_packed_vector3_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3_array_operator_index_const",
+ "return_type": "const godot_vector3 *",
+ "arguments": [
+ [
+ "const godot_packed_vector3_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3i_array_new",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3i_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3i_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3i_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_vector3i_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3i_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_vector3i_array *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3i_array_operator_index",
+ "return_type": "godot_vector3i *",
+ "arguments": [
+ [
+ "godot_packed_vector3i_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_vector3i_array_operator_index_const",
+ "return_type": "const godot_vector3i *",
+ "arguments": [
+ [
+ "const godot_packed_vector3i_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_color_array_new",
"return_type": "void",
"arguments": [
@@ -2936,6 +3790,20 @@
]
},
{
+ "name": "godot_packed_color_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_packed_color_array *",
+ "r_dest"
+ ],
+ [
+ "const godot_packed_color_array *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_packed_color_array_destroy",
"return_type": "void",
"arguments": [
@@ -2946,6 +3814,34 @@
]
},
{
+ "name": "godot_packed_color_array_operator_index",
+ "return_type": "godot_color *",
+ "arguments": [
+ [
+ "godot_packed_color_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_packed_color_array_operator_index_const",
+ "return_type": "const godot_color *",
+ "arguments": [
+ [
+ "const godot_packed_color_array *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_plane_new",
"return_type": "void",
"arguments": [
@@ -2956,6 +3852,20 @@
]
},
{
+ "name": "godot_plane_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_plane *",
+ "r_dest"
+ ],
+ [
+ "const godot_plane *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_quat_new",
"return_type": "void",
"arguments": [
@@ -2966,6 +3876,48 @@
]
},
{
+ "name": "godot_quat_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_quat *",
+ "r_dest"
+ ],
+ [
+ "const godot_quat *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_quat_operator_index",
+ "return_type": "godot_real_t *",
+ "arguments": [
+ [
+ "godot_quat *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_quat_operator_index_const",
+ "return_type": "const godot_real_t *",
+ "arguments": [
+ [
+ "const godot_quat *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_rect2_new",
"return_type": "void",
"arguments": [
@@ -2976,6 +3928,20 @@
]
},
{
+ "name": "godot_rect2_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2 *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_rect2i_new",
"return_type": "void",
"arguments": [
@@ -2986,6 +3952,20 @@
]
},
{
+ "name": "godot_rect2i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rect2i *",
+ "r_dest"
+ ],
+ [
+ "const godot_rect2i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_rid_new",
"return_type": "void",
"arguments": [
@@ -2996,6 +3976,20 @@
]
},
{
+ "name": "godot_rid_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_rid *",
+ "r_dest"
+ ],
+ [
+ "const godot_rid *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_signal_new",
"return_type": "void",
"arguments": [
@@ -3006,6 +4000,20 @@
]
},
{
+ "name": "godot_signal_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_signal *",
+ "r_dest"
+ ],
+ [
+ "const godot_signal *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_signal_destroy",
"return_type": "void",
"arguments": [
@@ -3210,6 +4218,84 @@
]
},
{
+ "name": "godot_string_to_latin1_chars",
+ "return_type": "const char *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf8_chars",
+ "return_type": "const char *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf16_chars",
+ "return_type": "const char16_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_utf32_chars",
+ "return_type": "const char32_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_to_wide_chars",
+ "return_type": "const wchar_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index",
+ "return_type": "char32_t *",
+ "arguments": [
+ [
+ "godot_string *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index_const",
+ "return_type": "const char32_t *",
+ "arguments": [
+ [
+ "const godot_string *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_string_name_new",
"return_type": "void",
"arguments": [
@@ -3268,6 +4354,20 @@
]
},
{
+ "name": "godot_transform_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform *",
+ "p_src"
+ ]
+ ]
+ },
+ {
"name": "godot_transform2d_new",
"return_type": "void",
"arguments": [
@@ -3278,6 +4378,48 @@
]
},
{
+ "name": "godot_transform2d_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_transform2d *",
+ "r_dest"
+ ],
+ [
+ "const godot_transform2d *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_transform2d_operator_index",
+ "return_type": "godot_vector2 *",
+ "arguments": [
+ [
+ "godot_transform2d *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_transform2d_operator_index_const",
+ "return_type": "const godot_vector2 *",
+ "arguments": [
+ [
+ "const godot_transform2d *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_vector2_new",
"return_type": "void",
"arguments": [
@@ -3288,6 +4430,48 @@
]
},
{
+ "name": "godot_vector2_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2 *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2_operator_index",
+ "return_type": "godot_real_t *",
+ "arguments": [
+ [
+ "godot_vector2 *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2_operator_index_const",
+ "return_type": "const godot_real_t *",
+ "arguments": [
+ [
+ "const godot_vector2 *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_vector2i_new",
"return_type": "void",
"arguments": [
@@ -3298,6 +4482,48 @@
]
},
{
+ "name": "godot_vector2i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector2i *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector2i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2i_operator_index",
+ "return_type": "int32_t *",
+ "arguments": [
+ [
+ "godot_vector2i *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector2i_operator_index_const",
+ "return_type": "const int32_t *",
+ "arguments": [
+ [
+ "const godot_vector2i *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_vector3_new",
"return_type": "void",
"arguments": [
@@ -3308,6 +4534,48 @@
]
},
{
+ "name": "godot_vector3_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3 *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3 *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3_operator_index",
+ "return_type": "godot_real_t *",
+ "arguments": [
+ [
+ "godot_vector3 *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3_operator_index_const",
+ "return_type": "const godot_real_t *",
+ "arguments": [
+ [
+ "const godot_vector3 *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
"name": "godot_vector3i_new",
"return_type": "void",
"arguments": [
@@ -3316,6 +4584,48 @@
"r_dest"
]
]
+ },
+ {
+ "name": "godot_vector3i_new_copy",
+ "return_type": "void",
+ "arguments": [
+ [
+ "godot_vector3i *",
+ "r_dest"
+ ],
+ [
+ "const godot_vector3i *",
+ "p_src"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3i_operator_index",
+ "return_type": "int32_t *",
+ "arguments": [
+ [
+ "godot_vector3i *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
+ },
+ {
+ "name": "godot_vector3i_operator_index_const",
+ "return_type": "const int32_t *",
+ "arguments": [
+ [
+ "const godot_vector3i *",
+ "p_self"
+ ],
+ [
+ "godot_int",
+ "p_index"
+ ]
+ ]
}
]
},
@@ -4406,7 +5716,7 @@
]
},
{
- "name": "godot_packed_glyph_array_invert",
+ "name": "godot_packed_glyph_array_reverse",
"return_type": "void",
"arguments": [
[
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index d3cca5b1be..dfb26c13e3 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -257,7 +257,7 @@ void GDNativeLibraryEditor::_translate_to_config_file() {
}
}
- library->_change_notify();
+ library->notify_property_list_changed();
}
}
diff --git a/modules/gdnative/include/gdnative/aabb.h b/modules/gdnative/include/gdnative/aabb.h
index be0235221f..860675065d 100644
--- a/modules/gdnative/include/gdnative/aabb.h
+++ b/modules/gdnative/include/gdnative/aabb.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_aabb_new(godot_aabb *p_self);
+void GDAPI godot_aabb_new_copy(godot_aabb *r_dest, const godot_aabb *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index d734d49232..bf4b852449 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -47,9 +47,13 @@ typedef struct {
#endif
#include <gdnative/gdnative.h>
+#include <gdnative/variant_struct.h>
void GDAPI godot_array_new(godot_array *p_self);
+void GDAPI godot_array_new_copy(godot_array *r_dest, const godot_array *p_src);
void GDAPI godot_array_destroy(godot_array *p_self);
+godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, godot_int p_index);
+const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index d40ca3d6a5..5477dbf811 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -49,6 +49,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_basis_new(godot_basis *p_self);
+void GDAPI godot_basis_new_copy(godot_basis *r_dest, const godot_basis *p_src);
+godot_vector3 GDAPI *godot_basis_operator_index(godot_basis *p_self, godot_int p_index);
+const godot_vector3 GDAPI *godot_basis_operator_index_const(const godot_basis *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h
index 6f359ada5e..b84b0c1f1f 100644
--- a/modules/gdnative/include/gdnative/callable.h
+++ b/modules/gdnative/include/gdnative/callable.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_callable_new(godot_callable *p_self);
+void GDAPI godot_callable_new_copy(godot_callable *r_dest, const godot_callable *p_src);
void GDAPI godot_callable_destroy(godot_callable *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 12c4a829bd..3334013147 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -50,6 +50,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_color_new(godot_color *p_self);
+void GDAPI godot_color_new_copy(godot_color *r_dest, const godot_color *p_src);
+float GDAPI *godot_color_operator_index(godot_color *p_self, godot_int p_index);
+const float GDAPI *godot_color_operator_index_const(const godot_color *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index 231d2ef578..b9525fb5e6 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -47,9 +47,13 @@ typedef struct {
#endif
#include <gdnative/gdnative.h>
+#include <gdnative/variant_struct.h>
void GDAPI godot_dictionary_new(godot_dictionary *p_self);
+void GDAPI godot_dictionary_new_copy(godot_dictionary *r_dest, const godot_dictionary *p_src);
void GDAPI godot_dictionary_destroy(godot_dictionary *p_self);
+godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key);
+const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h
index 630966b035..9af9226a79 100644
--- a/modules/gdnative/include/gdnative/gdnative.h
+++ b/modules/gdnative/include/gdnative/gdnative.h
@@ -53,7 +53,9 @@ extern "C" {
#endif
// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!!
-#ifdef _WIN32
+#ifdef __GNUC__
+#define GDN_EXPORT __attribute__((visibility("default")))
+#elif defined(_WIN32)
#define GDN_EXPORT __declspec(dllexport)
#else
#define GDN_EXPORT
@@ -62,8 +64,6 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
-#define GODOT_API_VERSION 1
-
////// Error
typedef enum {
@@ -266,6 +266,11 @@ void GDAPI *godot_alloc(int p_bytes);
void GDAPI *godot_realloc(void *p_ptr, int p_bytes);
void GDAPI godot_free(void *p_ptr);
+// Helper print functions.
+void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line);
+void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line);
+void GDAPI godot_print_script_error(const char *p_description, const char *p_function, const char *p_file, int p_line);
+
//tags used for safe dynamic casting
void GDAPI *godot_get_class_tag(const godot_string_name *p_class);
godot_object GDAPI *godot_object_cast_to(const godot_object *p_object, void *p_class_tag);
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 3c31b9a98f..a4607c0152 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_node_path_new(godot_node_path *p_self);
+void GDAPI godot_node_path_new_copy(godot_node_path *r_dest, const godot_node_path *p_src);
void GDAPI godot_node_path_destroy(godot_node_path *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/packed_arrays.h b/modules/gdnative/include/gdnative/packed_arrays.h
index 1a26d8ed6d..f9e4ba3a8d 100644
--- a/modules/gdnative/include/gdnative/packed_arrays.h
+++ b/modules/gdnative/include/gdnative/packed_arrays.h
@@ -163,55 +163,93 @@ typedef struct {
// Byte.
void GDAPI godot_packed_byte_array_new(godot_packed_byte_array *p_self);
+void GDAPI godot_packed_byte_array_new_copy(godot_packed_byte_array *r_dest, const godot_packed_byte_array *p_src);
void GDAPI godot_packed_byte_array_destroy(godot_packed_byte_array *p_self);
+uint8_t GDAPI *godot_packed_byte_array_operator_index(godot_packed_byte_array *p_self, godot_int p_index);
+const uint8_t GDAPI *godot_packed_byte_array_operator_index_const(const godot_packed_byte_array *p_self, godot_int p_index);
// Int32.
void GDAPI godot_packed_int32_array_new(godot_packed_int32_array *p_self);
+void GDAPI godot_packed_int32_array_new_copy(godot_packed_int32_array *r_dest, const godot_packed_int32_array *p_src);
void GDAPI godot_packed_int32_array_destroy(godot_packed_int32_array *p_self);
+int32_t GDAPI *godot_packed_int32_array_operator_index(godot_packed_int32_array *p_self, godot_int p_index);
+const int32_t GDAPI *godot_packed_int32_array_operator_index_const(const godot_packed_int32_array *p_self, godot_int p_index);
// Int64.
void GDAPI godot_packed_int64_array_new(godot_packed_int64_array *p_self);
+void GDAPI godot_packed_int64_array_new_copy(godot_packed_int64_array *r_dest, const godot_packed_int64_array *p_src);
void GDAPI godot_packed_int64_array_destroy(godot_packed_int64_array *p_self);
+int64_t GDAPI *godot_packed_int64_array_operator_index(godot_packed_int64_array *p_self, godot_int p_index);
+const int64_t GDAPI *godot_packed_int64_array_operator_index_const(const godot_packed_int64_array *p_self, godot_int p_index);
// Float32.
void GDAPI godot_packed_float32_array_new(godot_packed_float32_array *p_self);
+void GDAPI godot_packed_float32_array_new_copy(godot_packed_float32_array *r_dest, const godot_packed_float32_array *p_src);
void GDAPI godot_packed_float32_array_destroy(godot_packed_float32_array *p_self);
+float GDAPI *godot_packed_float32_array_operator_index(godot_packed_float32_array *p_self, godot_int p_index);
+const float GDAPI *godot_packed_float32_array_operator_index_const(const godot_packed_float32_array *p_self, godot_int p_index);
// Float64.
void GDAPI godot_packed_float64_array_new(godot_packed_float64_array *p_self);
+void GDAPI godot_packed_float64_array_new_copy(godot_packed_float64_array *r_dest, const godot_packed_float64_array *p_src);
void GDAPI godot_packed_float64_array_destroy(godot_packed_float64_array *p_self);
+double GDAPI *godot_packed_float64_array_operator_index(godot_packed_float64_array *p_self, godot_int p_index);
+const double GDAPI *godot_packed_float64_array_operator_index_const(const godot_packed_float64_array *p_self, godot_int p_index);
// String.
void GDAPI godot_packed_string_array_new(godot_packed_string_array *p_self);
+void GDAPI godot_packed_string_array_new_copy(godot_packed_string_array *r_dest, const godot_packed_string_array *p_src);
void GDAPI godot_packed_string_array_destroy(godot_packed_string_array *p_self);
+godot_string GDAPI *godot_packed_string_array_operator_index(godot_packed_string_array *p_self, godot_int p_index);
+const godot_string GDAPI *godot_packed_string_array_operator_index_const(const godot_packed_string_array *p_self, godot_int p_index);
// Vector2.
void GDAPI godot_packed_vector2_array_new(godot_packed_vector2_array *p_self);
+void GDAPI godot_packed_vector2_array_new_copy(godot_packed_vector2_array *r_dest, const godot_packed_vector2_array *p_src);
void GDAPI godot_packed_vector2_array_destroy(godot_packed_vector2_array *p_self);
+godot_vector2 GDAPI *godot_packed_vector2_array_operator_index(godot_packed_vector2_array *p_self, godot_int p_index);
+const godot_vector2 GDAPI *godot_packed_vector2_array_operator_index_const(const godot_packed_vector2_array *p_self, godot_int p_index);
// Vector2i.
void GDAPI godot_packed_vector2i_array_new(godot_packed_vector2i_array *p_self);
+void GDAPI godot_packed_vector2i_array_new_copy(godot_packed_vector2i_array *r_dest, const godot_packed_vector2i_array *p_src);
void GDAPI godot_packed_vector2i_array_destroy(godot_packed_vector2i_array *p_self);
+godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index(godot_packed_vector2i_array *p_self, godot_int p_index);
+const godot_vector2i GDAPI *godot_packed_vector2i_array_operator_index_const(const godot_packed_vector2i_array *p_self, godot_int p_index);
// Vector3.
void GDAPI godot_packed_vector3_array_new(godot_packed_vector3_array *p_self);
+void GDAPI godot_packed_vector3_array_new_copy(godot_packed_vector3_array *r_dest, const godot_packed_vector3_array *p_src);
void GDAPI godot_packed_vector3_array_destroy(godot_packed_vector3_array *p_self);
+godot_vector3 GDAPI *godot_packed_vector3_array_operator_index(godot_packed_vector3_array *p_self, godot_int p_index);
+const godot_vector3 GDAPI *godot_packed_vector3_array_operator_index_const(const godot_packed_vector3_array *p_self, godot_int p_index);
+
+// Vector3i.
+
+void GDAPI godot_packed_vector3i_array_new(godot_packed_vector3i_array *p_self);
+void GDAPI godot_packed_vector3i_array_new_copy(godot_packed_vector3i_array *r_dest, const godot_packed_vector3i_array *p_src);
+void GDAPI godot_packed_vector3i_array_destroy(godot_packed_vector3i_array *p_self);
+godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index(godot_packed_vector3i_array *p_self, godot_int p_index);
+const godot_vector3i GDAPI *godot_packed_vector3i_array_operator_index_const(const godot_packed_vector3i_array *p_self, godot_int p_index);
// Color.
void GDAPI godot_packed_color_array_new(godot_packed_color_array *p_self);
+void GDAPI godot_packed_color_array_new_copy(godot_packed_color_array *r_dest, const godot_packed_color_array *p_src);
void GDAPI godot_packed_color_array_destroy(godot_packed_color_array *p_self);
+godot_color GDAPI *godot_packed_color_array_operator_index(godot_packed_color_array *p_self, godot_int p_index);
+const godot_color GDAPI *godot_packed_color_array_operator_index_const(const godot_packed_color_array *p_self, godot_int p_index);
#ifdef __cplusplus
}
#endif
-#endif // GODOT_POOL_ARRAYS_H
+#endif // GODOT_PACKED_ARRAYS_H
diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h
index ed10955e5f..6cd0ed6307 100644
--- a/modules/gdnative/include/gdnative/plane.h
+++ b/modules/gdnative/include/gdnative/plane.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_plane_new(godot_plane *p_self);
+void GDAPI godot_plane_new_copy(godot_plane *r_dest, const godot_plane *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index a87d0bdbe5..00abdb4404 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -49,6 +49,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_quat_new(godot_quat *p_self);
+void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src);
+godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index);
+const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 9e51254cfe..326462be43 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -58,7 +58,9 @@ typedef struct godot_rect2i {
#include <gdnative/gdnative.h>
void GDAPI godot_rect2_new(godot_rect2 *p_self);
+void GDAPI godot_rect2_new_copy(godot_rect2 *r_dest, const godot_rect2 *p_src);
void GDAPI godot_rect2i_new(godot_rect2i *p_self);
+void GDAPI godot_rect2i_new_copy(godot_rect2i *r_dest, const godot_rect2i *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h
index 7ea8cfd174..bc832fbeb9 100644
--- a/modules/gdnative/include/gdnative/rid.h
+++ b/modules/gdnative/include/gdnative/rid.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_rid_new(godot_rid *p_self);
+void GDAPI godot_rid_new_copy(godot_rid *r_dest, const godot_rid *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h
index ad84542677..f4dc17e089 100644
--- a/modules/gdnative/include/gdnative/signal.h
+++ b/modules/gdnative/include/gdnative/signal.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_signal_new(godot_signal *p_self);
+void GDAPI godot_signal_new_copy(godot_signal *r_dest, const godot_signal *p_src);
void GDAPI godot_signal_destroy(godot_signal *p_self);
#ifdef __cplusplus
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index 10fbb2c078..79de52c80f 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -55,6 +55,7 @@ typedef struct {
#endif
#include <gdnative/gdnative.h>
+#include <gdnative/math_defs.h>
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
@@ -72,6 +73,15 @@ void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const
void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size);
void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
+const char GDAPI *godot_string_to_latin1_chars(const godot_string *p_self);
+const char GDAPI *godot_string_to_utf8_chars(const godot_string *p_self);
+const char16_t GDAPI *godot_string_to_utf16_chars(const godot_string *p_self);
+const char32_t GDAPI *godot_string_to_utf32_chars(const godot_string *p_self);
+const wchar_t GDAPI *godot_string_to_wide_chars(const godot_string *p_self);
+
+char32_t GDAPI *godot_string_operator_index(godot_string *p_self, godot_int p_index);
+const char32_t GDAPI *godot_string_operator_index_const(const godot_string *p_self, godot_int p_index);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h
index e67862d140..3861b5683a 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/transform.h
@@ -49,6 +49,7 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_transform_new(godot_transform *p_self);
+void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h
index 85e3a86972..5acb172081 100644
--- a/modules/gdnative/include/gdnative/transform2d.h
+++ b/modules/gdnative/include/gdnative/transform2d.h
@@ -49,6 +49,9 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_transform2d_new(godot_transform2d *p_self);
+void GDAPI godot_transform2d_new_copy(godot_transform2d *r_dest, const godot_transform2d *p_src);
+godot_vector2 GDAPI *godot_transform2d_operator_index(godot_transform2d *p_self, godot_int p_index);
+const godot_vector2 GDAPI *godot_transform2d_operator_index_const(const godot_transform2d *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 82bd030170..3e06ed9aa4 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -36,15 +36,7 @@ extern "C" {
#endif
#include <gdnative/math_defs.h>
-
-#define GODOT_VARIANT_SIZE (sizeof(godot_real_t) * 4 + sizeof(int64_t))
-
-#ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_VARIANT_SIZE];
-} godot_variant;
-#endif
+#include <gdnative/variant_struct.h>
typedef enum godot_variant_type {
GODOT_VARIANT_TYPE_NIL,
@@ -280,6 +272,8 @@ void GDAPI godot_variant_destroy(godot_variant *p_self);
void GDAPI godot_variant_call(godot_variant *p_self, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
void GDAPI godot_variant_call_with_cstring(godot_variant *p_self, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_static(godot_variant_type p_type, const godot_string_name *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
+void GDAPI godot_variant_call_static_with_cstring(godot_variant_type p_type, const char *p_method, const godot_variant **p_args, const godot_int p_argument_count, godot_variant *r_return, godot_variant_call_error *r_error);
void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_variant *p_a, const godot_variant *p_b, godot_variant *r_return, bool *r_valid);
void GDAPI godot_variant_set(godot_variant *p_self, const godot_variant *p_key, const godot_variant *p_value, bool *r_valid);
void GDAPI godot_variant_set_named(godot_variant *p_self, const godot_string_name *p_name, const godot_variant *p_value, bool *r_valid);
@@ -331,6 +325,8 @@ godot_variant_type GDAPI godot_variant_get_builtin_method_return_type(godot_vari
godot_variant_type GDAPI godot_variant_get_builtin_method_return_type_with_cstring(godot_variant_type p_type, const char *p_method);
bool GDAPI godot_variant_is_builtin_method_const(godot_variant_type p_type, const godot_string_name *p_method);
bool GDAPI godot_variant_is_builtin_method_const_with_cstring(godot_variant_type p_type, const char *p_method);
+bool GDAPI godot_variant_is_builtin_method_static(godot_variant_type p_type, const godot_string_name *p_method);
+bool GDAPI godot_variant_is_builtin_method_static_with_cstring(godot_variant_type p_type, const char *p_method);
bool GDAPI godot_variant_is_builtin_method_vararg(godot_variant_type p_type, const godot_string_name *p_method);
bool GDAPI godot_variant_is_builtin_method_vararg_with_cstring(godot_variant_type p_type, const char *p_method);
int GDAPI godot_variant_get_builtin_method_count(godot_variant_type p_type);
@@ -390,6 +386,10 @@ bool GDAPI godot_variant_has_utility_function(const godot_string_name *p_functio
bool GDAPI godot_variant_has_utility_function_with_cstring(const char *p_function);
void GDAPI godot_variant_call_utility_function(const godot_string_name *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error);
void GDAPI godot_variant_call_utility_function_with_cstring(const char *p_function, godot_variant *r_ret, const godot_variant **p_args, int p_argument_count, godot_variant_call_error *r_error);
+godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function(const godot_string_name *p_function);
+godot_ptr_utility_function GDAPI godot_variant_get_ptr_utility_function_with_cstring(const char *p_function);
+godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function(const godot_string_name *p_function);
+godot_validated_utility_function GDAPI godot_variant_get_validated_utility_function_with_cstring(const char *p_function);
godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type(const godot_string_name *p_function);
godot_variant_utility_function_type GDAPI godot_variant_get_utility_function_type_with_cstring(const char *p_function);
int GDAPI godot_variant_get_utility_function_argument_count(const godot_string_name *p_function);
diff --git a/core/os/copymem.h b/modules/gdnative/include/gdnative/variant_struct.h
index 6fd559356c..321c76c206 100644
--- a/core/os/copymem.h
+++ b/modules/gdnative/include/gdnative/variant_struct.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* copymem.h */
+/* variant_struct.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,23 +28,26 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COPYMEM_H
-#define COPYMEM_H
+#ifndef GODOT_VARIANT_STRUCT_H
+#define GODOT_VARIANT_STRUCT_H
-#include "core/typedefs.h"
-
-#ifdef PLATFORM_COPYMEM
-
-#include "platform_copymem.h" // included from platform/<current_platform>/platform_copymem.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
-#else
+#include <gdnative/math_defs.h>
-#include <string.h>
+#define GODOT_VARIANT_SIZE (sizeof(godot_real_t) * 4 + sizeof(int64_t))
-#define copymem(to, from, count) memcpy(to, from, count)
-#define zeromem(to, count) memset(to, 0, count)
-#define movemem(to, from, count) memmove(to, from, count)
+#ifndef GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_VARIANT_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VARIANT_SIZE];
+} godot_variant;
+#endif
+#ifdef __cplusplus
+}
#endif
-#endif // COPYMEM_H
+#endif
diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h
index a21ab304d0..00faffbad7 100644
--- a/modules/gdnative/include/gdnative/vector2.h
+++ b/modules/gdnative/include/gdnative/vector2.h
@@ -58,7 +58,13 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_vector2_new(godot_vector2 *p_self);
+void GDAPI godot_vector2_new_copy(godot_vector2 *r_dest, const godot_vector2 *p_src);
void GDAPI godot_vector2i_new(godot_vector2i *p_self);
+void GDAPI godot_vector2i_new_copy(godot_vector2i *r_dest, const godot_vector2i *p_src);
+godot_real_t GDAPI *godot_vector2_operator_index(godot_vector2 *p_self, godot_int p_index);
+const godot_real_t GDAPI *godot_vector2_operator_index_const(const godot_vector2 *p_self, godot_int p_index);
+int32_t GDAPI *godot_vector2i_operator_index(godot_vector2i *p_self, godot_int p_index);
+const int32_t GDAPI *godot_vector2i_operator_index_const(const godot_vector2i *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h
index 354c7555b6..7db093ce52 100644
--- a/modules/gdnative/include/gdnative/vector3.h
+++ b/modules/gdnative/include/gdnative/vector3.h
@@ -58,7 +58,13 @@ typedef struct {
#include <gdnative/gdnative.h>
void GDAPI godot_vector3_new(godot_vector3 *p_self);
+void GDAPI godot_vector3_new_copy(godot_vector3 *r_dest, const godot_vector3 *p_src);
void GDAPI godot_vector3i_new(godot_vector3i *p_self);
+void GDAPI godot_vector3i_new_copy(godot_vector3i *r_dest, const godot_vector3i *p_src);
+godot_real_t GDAPI *godot_vector3_operator_index(godot_vector3 *p_self, godot_int p_index);
+const godot_real_t GDAPI *godot_vector3_operator_index_const(const godot_vector3 *p_self, godot_int p_index);
+int32_t GDAPI *godot_vector3i_operator_index(godot_vector3i *p_self, godot_int p_index);
+const int32_t GDAPI *godot_vector3i_operator_index_const(const godot_vector3i *p_self, godot_int p_index);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 73b1738b03..c97f5f0389 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -58,8 +58,10 @@ typedef enum {
GODOT_PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
GODOT_PROPERTY_HINT_LAYERS_2D_RENDER,
GODOT_PROPERTY_HINT_LAYERS_2D_PHYSICS,
+ GODOT_PROPERTY_HINT_LAYERS_2D_NAVIGATION,
GODOT_PROPERTY_HINT_LAYERS_3D_RENDER,
GODOT_PROPERTY_HINT_LAYERS_3D_PHYSICS,
+ GODOT_PROPERTY_HINT_LAYERS_3D_NAVIGATION,
GODOT_PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
GODOT_PROPERTY_HINT_DIR, ///< a directory path must be passed
GODOT_PROPERTY_HINT_GLOBAL_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index cbd65e3772..b76f89cc99 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -56,6 +56,7 @@ typedef struct {
int p_argcount, godot_variant_call_error *r_error);
void (*notification)(godot_pluginscript_instance_data *p_data, int p_notification);
+ godot_string (*to_string)(godot_pluginscript_instance_data *p_data, godot_bool *r_valid);
//this is used by script languages that keep a reference counter of their own
//you can make make Ref<> not die when it reaches zero, so deleting the reference
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
index 44fac3c190..f3c50e6f87 100644
--- a/modules/gdnative/include/text/godot_text.h
+++ b/modules/gdnative/include/text/godot_text.h
@@ -74,11 +74,19 @@ typedef struct {
godot_rid (*create_font_system)(void *, const godot_string *, int);
godot_rid (*create_font_resource)(void *, const godot_string *, int);
godot_rid (*create_font_memory)(void *, const uint8_t *, size_t, godot_string *, int);
+ godot_rid (*create_font_bitmap)(void *, float, float, int);
+ void (*font_bitmap_add_texture)(void *, godot_rid *, const godot_object *);
+ void (*font_bitmap_add_char)(void *, godot_rid *, char32_t, int, const godot_rect2 *, const godot_vector2 *, float);
+ void (*font_bitmap_add_kerning_pair)(void *, godot_rid *, char32_t, char32_t, int);
float (*font_get_height)(void *, godot_rid *, int);
float (*font_get_ascent)(void *, godot_rid *, int);
float (*font_get_descent)(void *, godot_rid *, int);
float (*font_get_underline_position)(void *, godot_rid *, int);
float (*font_get_underline_thickness)(void *, godot_rid *, int);
+ int (*font_get_spacing_space)(void *, godot_rid *);
+ void (*font_set_spacing_space)(void *, godot_rid *, int);
+ int (*font_get_spacing_glyph)(void *, godot_rid *);
+ void (*font_set_spacing_glyph)(void *, godot_rid *, int);
void (*font_set_antialiased)(void *, godot_rid *, bool);
bool (*font_get_antialiased)(void *, godot_rid *);
godot_dictionary (*font_get_feature_list)(void *, godot_rid *);
@@ -110,6 +118,7 @@ typedef struct {
godot_vector2 (*font_get_glyph_kerning)(void *, godot_rid *, uint32_t, uint32_t, int);
godot_vector2 (*font_draw_glyph)(void *, godot_rid *, godot_rid *, int, const godot_vector2 *, uint32_t, const godot_color *);
godot_vector2 (*font_draw_glyph_outline)(void *, godot_rid *, godot_rid *, int, int, const godot_vector2 *, uint32_t, const godot_color *);
+ bool (*font_get_glyph_contours)(void *, godot_rid *, int, uint32_t, godot_packed_vector3_array *, godot_packed_int32_array *, bool *);
float (*font_get_oversampling)(void *);
void (*font_set_oversampling)(void *, float);
godot_packed_string_array (*get_system_fonts)(void *);
@@ -205,7 +214,7 @@ godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self,
void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self);
-void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self);
+void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self);
void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 2b824938f2..f184c84615 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -71,6 +71,7 @@ struct MethodAPI {
bool is_editor = false;
bool is_noscript = false;
bool is_const = false;
+ bool is_static = false; // For builtin types.
bool is_reverse = false;
bool is_virtual = false;
bool is_from_script = false;
@@ -122,6 +123,7 @@ struct ClassAPI {
// @Unclear
bool is_reference = false;
bool has_indexing = false; // For builtin types.
+ String indexed_type; // For builtin types.
bool is_keyed = false; // For builtin types.
List<MethodAPI> methods;
@@ -141,7 +143,7 @@ static String get_type_name(const PropertyInfo &info) {
return info.class_name;
}
if (info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- return info.hint_string;
+ return info.class_name;
}
if (info.type == Variant::NIL && (info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
return "Variant";
@@ -196,11 +198,32 @@ List<ClassAPI> generate_c_api_classes() {
global_constants_api.singleton_name = "CoreConstants";
global_constants_api.is_instantiable = false;
const int constants_count = CoreConstants::get_global_constant_count();
+
+ Map<StringName, EnumAPI> enum_api_map;
for (int i = 0; i < constants_count; ++i) {
- ConstantAPI constant_api;
- constant_api.constant_name = CoreConstants::get_global_constant_name(i);
- constant_api.constant_value = CoreConstants::get_global_constant_value(i);
- global_constants_api.constants.push_back(constant_api);
+ StringName enum_name = CoreConstants::get_global_constant_enum(i);
+ String name = String(CoreConstants::get_global_constant_name(i));
+ int value = CoreConstants::get_global_constant_value(i);
+
+ if (enum_name == StringName()) {
+ ConstantAPI constant_api;
+ constant_api.constant_name = name;
+ constant_api.constant_value = value;
+ global_constants_api.constants.push_back(constant_api);
+ } else {
+ EnumAPI enum_api;
+ if (enum_api_map.has(enum_name)) {
+ enum_api = enum_api_map[enum_name];
+ } else {
+ enum_api.name = String(enum_name);
+ }
+ enum_api.values.push_back(Pair(value, name));
+
+ enum_api_map[enum_name] = enum_api;
+ }
+ }
+ for (const Map<StringName, EnumAPI>::Element *E = enum_api_map.front(); E; E = E->next()) {
+ global_constants_api.enums.push_back(E->get());
}
global_constants_api.constants.sort_custom<ConstantAPIComparator>();
api.push_back(global_constants_api);
@@ -308,7 +331,9 @@ List<ClassAPI> generate_c_api_classes() {
property_api.type = p->get().name.get_slice(":", 1);
property_api.name = p->get().name.get_slice(":", 0);
} else {
- property_api.type = get_type_name(p->get());
+ MethodInfo minfo;
+ ClassDB::get_method_info(class_name, property_api.getter, &minfo, true, false);
+ property_api.type = get_type_name(minfo.return_val);
}
property_api.index = ClassDB::get_property_index(class_name, p->get().name);
@@ -370,7 +395,7 @@ List<ClassAPI> generate_c_api_classes() {
arg_type = arg_info.name.get_slice(":", 1);
arg_name = arg_info.name.get_slice(":", 0);
} else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- arg_type = arg_info.hint_string;
+ arg_type = arg_info.class_name;
} else if (arg_info.type == Variant::NIL) {
arg_type = "Variant";
} else if (arg_info.type == Variant::OBJECT) {
@@ -468,6 +493,7 @@ List<ClassAPI> generate_c_builtin_api_types() {
class_api.class_name = Variant::get_type_name(type);
class_api.is_instantiable = true;
class_api.has_indexing = Variant::has_indexing(type);
+ class_api.indexed_type = Variant::get_type_name(Variant::get_indexed_element_type(type));
class_api.is_keyed = Variant::is_keyed(type);
// Types that are passed by reference.
switch (type) {
@@ -503,6 +529,7 @@ List<ClassAPI> generate_c_builtin_api_types() {
method_api.argument_count = Variant::get_builtin_method_argument_count(type, method_name);
method_api.has_varargs = Variant::is_builtin_method_vararg(type, method_name);
method_api.is_const = Variant::is_builtin_method_const(type, method_name);
+ method_api.is_static = Variant::is_builtin_method_static(type, method_name);
for (int i = 0; i < method_api.argument_count; i++) {
method_api.argument_names.push_back(Variant::get_builtin_method_argument_name(type, method_name, i));
@@ -732,6 +759,7 @@ static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_met
append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name));
append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type));
append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false"));
+ append_indented(p_source, vformat(R"("is_static": %s,)", p_method.is_static ? "true" : "false"));
append_indented(p_source, vformat(R"("has_varargs": %s,)", p_method.has_varargs ? "true" : "false"));
append_indented(p_source, R"("arguments": [)");
@@ -768,6 +796,7 @@ static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) {
append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false"));
append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false"));
append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false"));
+ append_indented(source, vformat(R"("indexed_type": "%s",)", class_api.has_indexing && class_api.indexed_type == "Nil" ? "Variant" : class_api.indexed_type));
append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false"));
// Constructors.
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index def020adad..3283f28de5 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -41,6 +41,8 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
+#include "main/main.h"
+
#include "scene/main/scene_tree.h"
#include "scene/resources/resource_format_text.h"
@@ -173,7 +175,7 @@ bool NativeScript::can_instance() const {
#ifdef TOOLS_ENABLED
// Only valid if this is either a tool script or a "regular" script.
- // (so an environment whre scripting is disabled (and not the editor) would not
+ // (so, an environment where scripting is disabled (and not the editor) would not
// create objects).
return script_data && (is_tool() || ScriptServer::is_scripting_enabled());
#else
@@ -1248,6 +1250,7 @@ void NativeScriptLanguage::init() {
if (generate_c_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C API\n");
}
+ Main::cleanup(true);
exit(0);
}
@@ -1257,6 +1260,7 @@ void NativeScriptLanguage::init() {
if (generate_c_builtin_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C builtin API\n");
}
+ Main::cleanup(true);
exit(0);
}
#endif
@@ -1670,7 +1674,7 @@ void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeSc
MutexLock lock(mutex);
libs_to_init.insert(lib);
scripts_to_register.insert(script);
- has_objects_to_register = true;
+ has_objects_to_register.set();
}
#endif
@@ -1728,7 +1732,47 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
library_script_users.erase(S);
Map<String, Ref<GDNative>>::Element *G = library_gdnatives.find(script->lib_path);
- if (G) {
+ if (G && G->get()->get_library()->is_reloadable()) {
+ // ONLY if the library is marked as reloadable, and no more instances of its scripts exist do we unload the library
+
+ // First remove meta data related to the library
+ Map<String, Map<StringName, NativeScriptDesc>>::Element *L = library_classes.find(script->lib_path);
+ if (L) {
+ Map<StringName, NativeScriptDesc> classes = L->get();
+
+ for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
+ // free property stuff first
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
+ if (P.get().getter.free_func) {
+ P.get().getter.free_func(P.get().getter.method_data);
+ }
+
+ if (P.get().setter.free_func) {
+ P.get().setter.free_func(P.get().setter.method_data);
+ }
+ }
+
+ // free method stuff
+ for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) {
+ if (M->get().method.free_func) {
+ M->get().method.free_func(M->get().method.method_data);
+ }
+ }
+
+ // free constructor/destructor
+ if (C->get().create_func.free_func) {
+ C->get().create_func.free_func(C->get().create_func.method_data);
+ }
+
+ if (C->get().destroy_func.free_func) {
+ C->get().destroy_func.free_func(C->get().destroy_func.method_data);
+ }
+ }
+
+ library_classes.erase(script->lib_path);
+ }
+
+ // now unload the library
G->get()->terminate();
library_gdnatives.erase(G);
}
@@ -1759,7 +1803,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
void NativeScriptLanguage::frame() {
#ifndef NO_THREADS
- if (has_objects_to_register) {
+ if (has_objects_to_register.is_set()) {
MutexLock lock(mutex);
for (Set<Ref<GDNativeLibrary>>::Element *L = libs_to_init.front(); L; L = L->next()) {
init_library(L->get());
@@ -1769,7 +1813,7 @@ void NativeScriptLanguage::frame() {
register_script(S->get());
}
scripts_to_register.clear();
- has_objects_to_register = false;
+ has_objects_to_register.clear();
}
#endif
@@ -1940,7 +1984,7 @@ void NativeReloadNode::_notification(int p_what) {
#endif
}
-RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_no_cache) {
return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error);
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index ea7ced6511..4bd54f9c46 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -40,6 +40,7 @@
#include "core/os/thread_safe.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/ordered_hash_map.h"
+#include "core/templates/safe_refcount.h"
#include "core/templates/self_list.h"
#include "scene/main/node.h"
@@ -89,8 +90,8 @@ struct NativeScriptDesc {
bool is_tool = false;
inline NativeScriptDesc() {
- zeromem(&create_func, sizeof(godot_nativescript_instance_create_func));
- zeromem(&destroy_func, sizeof(godot_nativescript_instance_destroy_func));
+ memset(&create_func, 0, sizeof(godot_nativescript_instance_create_func));
+ memset(&destroy_func, 0, sizeof(godot_nativescript_instance_destroy_func));
}
};
@@ -262,7 +263,7 @@ private:
#ifndef NO_THREADS
Set<Ref<GDNativeLibrary>> libs_to_init;
Set<NativeScript *> scripts_to_register;
- volatile bool has_objects_to_register = false; // so that we don't lock mutex every frame - it's rarely needed
+ SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed
void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script);
#endif
@@ -402,7 +403,7 @@ public:
class ResourceFormatLoaderNativeScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 432aa80325..7f8dba0906 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -93,6 +93,13 @@ void PluginScriptInstance::notification(int p_notification) {
_desc->notification(_data, p_notification);
}
+String PluginScriptInstance::to_string(bool *r_valid) {
+ godot_string ret = _desc->to_string(_data, r_valid);
+ String str_ret = *(String *)&ret;
+ godot_string_destroy(&ret);
+ return str_ret;
+}
+
Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
return _script->get_rpc_methods();
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index 536eb550e0..b263c0e62c 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -63,6 +63,7 @@ public:
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual void notification(int p_notification);
+ virtual String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp
index cd1879a13e..f2165cd225 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp
@@ -39,7 +39,7 @@ ResourceFormatLoaderPluginScript::ResourceFormatLoaderPluginScript(PluginScriptL
_language = language;
}
-RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h
index 7b1a7f5423..e5d665c186 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.h
+++ b/modules/gdnative/pluginscript/pluginscript_loader.h
@@ -43,7 +43,7 @@ class ResourceFormatLoaderPluginScript : public ResourceFormatLoader {
public:
ResourceFormatLoaderPluginScript(PluginScriptLanguage *language);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 31f4fecb19..d08bde9e23 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -142,7 +142,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty
}
}
- // Add symbols for staticaly linked libraries on iOS
+ // Add symbols for statically linked libraries on iOS
if (p_features.has("iOS")) {
bool should_fake_dynamic = false;
diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h
index 5284bf26f0..2850036604 100644
--- a/modules/gdnative/tests/test_variant.h
+++ b/modules/gdnative/tests/test_variant.h
@@ -107,7 +107,7 @@ TEST_CASE("[GDNative Variant] Variant call") {
godot_string_name_new_with_latin1_chars(&method, "is_valid_identifier");
godot_variant_call_error error;
- godot_variant_call(&self, &method, NULL, 0, &ret, &error);
+ godot_variant_call(&self, &method, nullptr, 0, &ret, &error);
CHECK(godot_variant_get_type(&ret) == GODOT_VARIANT_TYPE_BOOL);
CHECK(godot_variant_as_bool(&ret));
@@ -124,6 +124,7 @@ TEST_CASE("[GDNative Variant] Variant evaluate") {
godot_variant_new_int(&two, 2);
godot_variant three;
+ godot_variant_new_nil(&three);
bool valid = false;
godot_variant_evaluate(GODOT_VARIANT_OP_ADD, &one, &two, &three, &valid);
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index f7a3cb8135..bc4b1ac134 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -113,6 +113,28 @@ RID TextServerGDNative::create_font_memory(const uint8_t *p_data, size_t p_size,
return rid;
}
+RID TextServerGDNative::create_font_bitmap(float p_height, float p_ascent, int p_base_size) {
+ ERR_FAIL_COND_V(interface == nullptr, RID());
+ godot_rid result = interface->create_font_bitmap(data, p_height, p_ascent, p_base_size);
+ RID rid = *(RID *)&result;
+ return rid;
+}
+
+void TextServerGDNative::font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_bitmap_add_texture(data, (godot_rid *)&p_font, (const godot_object *)p_texture.ptr());
+}
+
+void TextServerGDNative::font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_bitmap_add_char(data, (godot_rid *)&p_font, p_char, p_texture_idx, (const godot_rect2 *)&p_rect, (const godot_vector2 *)&p_align, p_advance);
+}
+
+void TextServerGDNative::font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_bitmap_add_kerning_pair(data, (godot_rid *)&p_font, p_A, p_B, p_kerning);
+}
+
float TextServerGDNative::font_get_height(RID p_font, int p_size) const {
ERR_FAIL_COND_V(interface == nullptr, 0.f);
return interface->font_get_height(data, (godot_rid *)&p_font, p_size);
@@ -138,6 +160,26 @@ float TextServerGDNative::font_get_underline_thickness(RID p_font, int p_size) c
return interface->font_get_underline_thickness(data, (godot_rid *)&p_font, p_size);
}
+int TextServerGDNative::font_get_spacing_space(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0);
+ return interface->font_get_spacing_space(data, (godot_rid *)&p_font);
+}
+
+void TextServerGDNative::font_set_spacing_space(RID p_font, int p_value) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_spacing_space(data, (godot_rid *)&p_font, p_value);
+}
+
+int TextServerGDNative::font_get_spacing_glyph(RID p_font) const {
+ ERR_FAIL_COND_V(interface == nullptr, 0);
+ return interface->font_get_spacing_glyph(data, (godot_rid *)&p_font);
+}
+
+void TextServerGDNative::font_set_spacing_glyph(RID p_font, int p_value) {
+ ERR_FAIL_COND(interface == nullptr);
+ interface->font_set_spacing_glyph(data, (godot_rid *)&p_font, p_value);
+}
+
void TextServerGDNative::font_set_antialiased(RID p_font, bool p_antialiased) {
ERR_FAIL_COND(interface == nullptr);
interface->font_set_antialiased(data, (godot_rid *)&p_font, p_antialiased);
@@ -317,6 +359,12 @@ Vector2 TextServerGDNative::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return advance;
}
+bool TextServerGDNative::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ ERR_FAIL_COND_V(interface->font_get_glyph_contours == nullptr, false);
+ return interface->font_get_glyph_contours(data, (godot_rid *)&p_font, p_size, p_index, (godot_packed_vector3_array *)&r_points, (godot_packed_int32_array *)&r_contours, (bool *)&r_orientation);
+}
+
float TextServerGDNative::font_get_oversampling() const {
ERR_FAIL_COND_V(interface == nullptr, 1.f);
return interface->font_get_oversampling(data);
@@ -799,9 +847,9 @@ void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) {
self->sort();
}
-void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self) {
+void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self) {
Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->invert();
+ self->reverse();
}
void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index 9cbb94217e..7e42b16fe1 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -64,6 +64,11 @@ public:
virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+ virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) override;
+
+ virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) override;
+ virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
+ virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) override;
virtual float font_get_height(RID p_font, int p_size) const override;
virtual float font_get_ascent(RID p_font, int p_size) const override;
@@ -72,6 +77,12 @@ public:
virtual float font_get_underline_position(RID p_font, int p_size) const override;
virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+ virtual int font_get_spacing_space(RID p_font) const override;
+ virtual void font_set_spacing_space(RID p_font, int p_value) override;
+
+ virtual int font_get_spacing_glyph(RID p_font) const override;
+ virtual void font_set_spacing_glyph(RID p_font, int p_value) override;
+
virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
virtual bool font_get_antialiased(RID p_font) const override;
@@ -115,6 +126,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
index 18d26a9528..f2fb0a2fdc 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
@@ -250,7 +250,7 @@ void VideoStreamPlaybackGDNative::play() {
playing = true;
- delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms");
+ delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms");
delay_compensation /= 1000.0;
}
@@ -360,7 +360,7 @@ void VideoStreamGDNative::set_audio_track(int p_track) {
/* --- NOTE ResourceFormatLoaderVideoStreamGDNative starts here. ----- */
-RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderVideoStreamGDNative::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) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h
index 3db5609952..140888cd4b 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.h
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.h
@@ -196,7 +196,7 @@ public:
class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp
index 5bbf70174c..122cb5849b 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.cpp
+++ b/modules/gdnative/xr/xr_interface_gdnative.cpp
@@ -301,7 +301,8 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g
Input *input = Input::get_singleton();
ERR_FAIL_NULL_V(input, 0);
- XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
+ Ref<XRPositionalTracker> new_tracker;
+ new_tracker.instance();
new_tracker->set_tracker_name(p_device_name);
new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
if (p_hand == 1) {
@@ -340,8 +341,8 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (remove_tracker != nullptr) {
+ Ref<XRPositionalTracker> remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (remove_tracker.is_valid()) {
// unset our joystick if applicable
int joyid = remove_tracker->get_joy_id();
if (joyid != -1) {
@@ -351,7 +352,7 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
// remove our tracker from our server
xr_server->remove_tracker(remove_tracker);
- memdelete(remove_tracker);
+ remove_tracker.unref();
}
}
@@ -359,8 +360,8 @@ void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_tr
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
Transform *transform = (Transform *)p_transform;
if (p_tracks_orientation) {
tracker->set_orientation(transform->basis);
@@ -378,8 +379,8 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
input->joy_button(joyid, p_button, p_is_pressed);
@@ -394,11 +395,11 @@ void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_a
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = p_can_be_negative ? -1 : 0;
jx.value = p_value;
input->joy_axis(joyid, p_axis, jx);
@@ -410,8 +411,8 @@ godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
return tracker->get_rumble();
}
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index 4f61ad5040..88ef434e0f 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -122,7 +122,7 @@ GdNavigationServer::~GdNavigationServer() {
}
void GdNavigationServer::add_command(SetCommand *command) const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
{
MutexLock lock(commands_mutex);
mut_this->commands.push_back(command);
@@ -130,7 +130,7 @@ void GdNavigationServer::add_command(SetCommand *command) const {
}
RID GdNavigationServer::map_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
NavMap *space = memnew(NavMap);
RID rid = map_owner.make_rid(space);
@@ -145,9 +145,13 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
if (p_active) {
if (!map_is_active(p_map)) {
active_maps.push_back(map);
+ active_maps_update_id.push_back(map->get_map_update_id());
}
} else {
- active_maps.erase(map);
+ int map_index = active_maps.find(map);
+ ERR_FAIL_COND(map_index < 0);
+ active_maps.remove(map_index);
+ active_maps_update_id.remove(map_index);
}
}
@@ -200,11 +204,11 @@ real_t GdNavigationServer::map_get_edge_connection_margin(RID p_map) const {
return map->get_edge_connection_margin();
}
-Vector<Vector3> GdNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize) const {
+Vector<Vector3> GdNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
const NavMap *map = map_owner.getornull(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
- return map->get_path(p_origin, p_destination, p_optimize);
+ return map->get_path(p_origin, p_destination, p_optimize, p_layers);
}
Vector3 GdNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -236,7 +240,7 @@ RID GdNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_
}
RID GdNavigationServer::region_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
NavRegion *reg = memnew(NavRegion);
RID rid = region_owner.make_rid(reg);
@@ -273,6 +277,20 @@ COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform) {
region->set_transform(p_transform);
}
+COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND(region == nullptr);
+
+ region->set_layers(p_layers);
+}
+
+uint32_t GdNavigationServer::region_get_layers(RID p_region) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_layers();
+}
+
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) {
NavRegion *region = region_owner.getornull(p_region);
ERR_FAIL_COND(region == nullptr);
@@ -290,8 +308,29 @@ void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p
#endif
}
+int GdNavigationServer::region_get_connections_count(RID p_region) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, 0);
+
+ return region->get_connections_count();
+}
+
+Vector3 GdNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, Vector3());
+
+ return region->get_connection_pathway_start(p_connection_id);
+}
+
+Vector3 GdNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const {
+ NavRegion *region = region_owner.getornull(p_region);
+ ERR_FAIL_COND_V(!region, Vector3());
+
+ return region->get_connection_pathway_end(p_connection_id);
+}
+
RID GdNavigationServer::agent_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RvoAgent *agent = memnew(RvoAgent());
RID rid = agent_owner.make_rid(agent);
@@ -429,7 +468,9 @@ COMMAND_1(free, RID, p_object) {
agents[i]->set_map(nullptr);
}
- active_maps.erase(map);
+ int map_index = active_maps.find(map);
+ active_maps.remove(map_index);
+ active_maps_update_id.remove(map_index);
map_owner.free(p_object);
memdelete(map);
@@ -463,7 +504,7 @@ COMMAND_1(free, RID, p_object) {
}
void GdNavigationServer::set_active(bool p_active) const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
mut_this->active = p_active;
}
@@ -490,10 +531,17 @@ void GdNavigationServer::process(real_t p_delta_time) {
// In c++ we can't be sure that this is performed in the main thread
// even with mutable functions.
MutexLock lock(operations_mutex);
- for (int i(0); i < active_maps.size(); i++) {
+ for (uint32_t i(0); i < active_maps.size(); i++) {
active_maps[i]->sync();
active_maps[i]->step(p_delta_time);
active_maps[i]->dispatch_callbacks();
+
+ // Emit a signal if a map changed.
+ const uint32_t new_map_update_id = active_maps[i]->get_map_update_id();
+ if (new_map_update_id != active_maps_update_id[i]) {
+ emit_signal("map_changed", active_maps[i]->get_self());
+ active_maps_update_id[i] = new_map_update_id;
+ }
}
}
diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/gdnavigation/gd_navigation_server.h
index 92f4ccfdd5..2f51f6431e 100644
--- a/modules/gdnavigation/gd_navigation_server.h
+++ b/modules/gdnavigation/gd_navigation_server.h
@@ -31,6 +31,7 @@
#ifndef GD_NAVIGATION_SERVER_H
#define GD_NAVIGATION_SERVER_H
+#include "core/templates/local_vector.h"
#include "core/templates/rid.h"
#include "core/templates/rid_owner.h"
#include "servers/navigation_server_3d.h"
@@ -79,7 +80,8 @@ class GdNavigationServer : public NavigationServer3D {
mutable RID_PtrOwner<RvoAgent> agent_owner;
bool active = true;
- Vector<NavMap *> active_maps;
+ LocalVector<NavMap *> active_maps;
+ LocalVector<uint32_t> active_maps_update_id;
public:
GdNavigationServer();
@@ -100,7 +102,7 @@ public:
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
virtual real_t map_get_edge_connection_margin(RID p_map) const;
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize) const;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const;
@@ -109,9 +111,14 @@ public:
virtual RID region_create() const;
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
+ COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
+ virtual uint32_t region_get_layers(RID p_region) const;
COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
+ virtual int region_get_connections_count(RID p_region) const;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
virtual RID agent_create() const;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 2646a4cc0c..2513c62b6a 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -40,7 +40,7 @@
@author AndreaCatania
*/
-#define USE_ENTRY_POINT
+#define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a)))
void NavMap::set_up(Vector3 p_up) {
up = p_up;
@@ -70,44 +70,52 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
return p;
}
-Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize) const {
+Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
+ // Find the start poly and the end poly on this map.
const gd::Polygon *begin_poly = nullptr;
const gd::Polygon *end_poly = nullptr;
Vector3 begin_point;
Vector3 end_point;
float begin_d = 1e20;
float end_d = 1e20;
-
// Find the initial poly and the end poly on this map.
for (size_t i(0); i < polygons.size(); i++) {
const gd::Polygon &p = polygons[i];
+ // Only consider the polygon if it in a region with compatible layers.
+ if ((p_layers & p.owner->get_layers()) == 0) {
+ continue;
+ }
+
// For each point cast a face and check the distance between the origin/destination
- for (size_t point_id = 2; point_id < p.points.size(); point_id++) {
- Face3 f(p.points[point_id - 2].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
- Vector3 spoint = f.get_closest_point_to(p_origin);
- float dpoint = spoint.distance_to(p_origin);
- if (dpoint < begin_d) {
- begin_d = dpoint;
+ for (size_t point_id = 0; point_id < p.points.size(); point_id++) {
+ const Vector3 p1 = p.points[point_id].pos;
+ const Vector3 p2 = p.points[(point_id + 1) % p.points.size()].pos;
+ const Vector3 p3 = p.points[(point_id + 2) % p.points.size()].pos;
+ const Face3 face(p1, p2, p3);
+
+ Vector3 point = face.get_closest_point_to(p_origin);
+ float distance_to_point = point.distance_to(p_origin);
+ if (distance_to_point < begin_d) {
+ begin_d = distance_to_point;
begin_poly = &p;
- begin_point = spoint;
+ begin_point = point;
}
- spoint = f.get_closest_point_to(p_destination);
- dpoint = spoint.distance_to(p_destination);
- if (dpoint < end_d) {
- end_d = dpoint;
+ point = face.get_closest_point_to(p_destination);
+ distance_to_point = point.distance_to(p_destination);
+ if (distance_to_point < end_d) {
+ end_d = distance_to_point;
end_poly = &p;
- end_point = spoint;
+ end_point = point;
}
}
}
+ // Check for trival cases
if (!begin_poly || !end_poly) {
- // No path
return Vector<Vector3>();
}
-
if (begin_poly == end_poly) {
Vector<Vector3> path;
path.resize(2);
@@ -116,90 +124,89 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
return path;
}
+ // List of all reachable navigation polys.
std::vector<gd::NavigationPoly> navigation_polys;
navigation_polys.reserve(polygons.size() * 0.75);
- // The elements indices in the `navigation_polys`.
- int least_cost_id(-1);
- List<uint32_t> open_list;
- bool found_route = false;
+ // Add the start polygon to the reachable navigation polygons.
+ gd::NavigationPoly begin_navigation_poly = gd::NavigationPoly(begin_poly);
+ begin_navigation_poly.self_id = 0;
+ begin_navigation_poly.entry = begin_point;
+ begin_navigation_poly.back_navigation_edge_pathway_start = begin_point;
+ begin_navigation_poly.back_navigation_edge_pathway_end = begin_point;
+ navigation_polys.push_back(begin_navigation_poly);
- navigation_polys.push_back(gd::NavigationPoly(begin_poly));
- {
- least_cost_id = 0;
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
- least_cost_poly->self_id = least_cost_id;
- least_cost_poly->entry = begin_point;
- }
+ // List of polygon IDs to visit.
+ List<uint32_t> to_visit;
+ to_visit.push_back(0);
- open_list.push_back(0);
+ // This is an implementation of the A* algorithm.
+ int least_cost_id = 0;
+ bool found_route = false;
const gd::Polygon *reachable_end = nullptr;
float reachable_d = 1e30;
bool is_reachable = true;
- while (found_route == false) {
- {
- // Takes the current least_cost_poly neighbors and compute the traveled_distance of each
- for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
+ while (true) {
+ gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
+
+ // Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
+ for (size_t i = 0; i < least_cost_poly->poly->edges.size(); i++) {
+ const gd::Edge &edge = least_cost_poly->poly->edges[i];
+
+ // Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon.
+ for (int connection_index = 0; connection_index < edge.connections.size(); connection_index++) {
+ const gd::Edge::Connection &connection = edge.connections[connection_index];
- const gd::Edge &edge = least_cost_poly->poly->edges[i];
- if (!edge.other_polygon) {
+ // Only consider the connection to another polygon if this polygon is in a region with compatible layers.
+ if ((p_layers & connection.polygon->owner->get_layers()) == 0) {
continue;
}
-#ifdef USE_ENTRY_POINT
- Vector3 edge_line[2] = {
- least_cost_poly->poly->points[i].pos,
- least_cost_poly->poly->points[(i + 1) % least_cost_poly->poly->points.size()].pos
- };
-
- const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, edge_line);
+ Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
+ const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
-#else
- const float new_distance = least_cost_poly->poly->center.distance_to(edge.other_polygon->center) + least_cost_poly->traveled_distance;
-#endif
- auto it = std::find(
+ const std::vector<gd::NavigationPoly>::iterator it = std::find(
navigation_polys.begin(),
navigation_polys.end(),
- gd::NavigationPoly(edge.other_polygon));
+ gd::NavigationPoly(connection.polygon));
if (it != navigation_polys.end()) {
- // Oh this was visited already, can we win the cost?
- if (it->traveled_distance > new_distance) {
- it->prev_navigation_poly_id = least_cost_id;
- it->back_navigation_edge = edge.other_edge;
+ // Polygon already visited, check if we can reduce the travel cost.
+ if (new_distance < it->traveled_distance) {
+ it->back_navigation_poly_id = least_cost_id;
+ it->back_navigation_edge = connection.edge;
+ it->back_navigation_edge_pathway_start = connection.pathway_start;
+ it->back_navigation_edge_pathway_end = connection.pathway_end;
it->traveled_distance = new_distance;
-#ifdef USE_ENTRY_POINT
it->entry = new_entry;
-#endif
}
} else {
- // Add to open neighbours
-
- navigation_polys.push_back(gd::NavigationPoly(edge.other_polygon));
- gd::NavigationPoly *np = &navigation_polys[navigation_polys.size() - 1];
-
- np->self_id = navigation_polys.size() - 1;
- np->prev_navigation_poly_id = least_cost_id;
- np->back_navigation_edge = edge.other_edge;
- np->traveled_distance = new_distance;
-#ifdef USE_ENTRY_POINT
- np->entry = new_entry;
-#endif
- open_list.push_back(navigation_polys.size() - 1);
+ // Add the neighbour polygon to the reachable ones.
+ gd::NavigationPoly new_navigation_poly = gd::NavigationPoly(connection.polygon);
+ new_navigation_poly.self_id = navigation_polys.size();
+ new_navigation_poly.back_navigation_poly_id = least_cost_id;
+ new_navigation_poly.back_navigation_edge = connection.edge;
+ new_navigation_poly.back_navigation_edge_pathway_start = connection.pathway_start;
+ new_navigation_poly.back_navigation_edge_pathway_end = connection.pathway_end;
+ new_navigation_poly.traveled_distance = new_distance;
+ new_navigation_poly.entry = new_entry;
+ navigation_polys.push_back(new_navigation_poly);
+
+ // Add the neighbour polygon to the polygons to visit.
+ to_visit.push_back(navigation_polys.size() - 1);
}
}
}
- // Removes the least cost polygon from the open list so we can advance.
- open_list.erase(least_cost_id);
+ // Removes the least cost polygon from the list of polygons to visit so we can advance.
+ to_visit.erase(least_cost_id);
- if (open_list.size() == 0) {
- // When the open list is empty at this point the End Polygon is not reachable
- // so use the further reachable polygon
+ // When the list of polygons to visit is empty at this point it means the End Polygon is not reachable
+ if (to_visit.size() == 0) {
+ // Thus use the further reachable polygon
ERR_BREAK_MSG(is_reachable == false, "It's not expect to not find the most reachable polygons");
is_reachable = false;
if (reachable_end == nullptr) {
@@ -224,26 +231,21 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
gd::NavigationPoly np = navigation_polys[0];
navigation_polys.clear();
navigation_polys.push_back(np);
- open_list.clear();
- open_list.push_back(0);
+ to_visit.clear();
+ to_visit.push_back(0);
reachable_end = nullptr;
continue;
}
- // Now take the new least_cost_poly from the open list.
+ // Find the polygon with the minimum cost from the list of polygons to visit.
least_cost_id = -1;
float least_cost = 1e30;
-
- for (auto element = open_list.front(); element != nullptr; element = element->next()) {
+ for (List<uint32_t>::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
-#ifdef USE_ENTRY_POINT
cost += np->entry.distance_to(end_point);
-#else
- cost += np->poly->center.distance_to(end_point);
-#endif
if (cost < least_cost) {
least_cost_id = np->self_id;
least_cost = cost;
@@ -263,124 +265,108 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Check if we reached the end
if (navigation_polys[least_cost_id].poly == end_poly) {
- // Yep, done!!
found_route = true;
break;
}
}
- if (found_route) {
- Vector<Vector3> path;
- if (p_optimize) {
- // String pulling
-
- gd::NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
- Vector3 apex_point = end_point;
- Vector3 portal_left = apex_point;
- Vector3 portal_right = apex_point;
- gd::NavigationPoly *left_poly = apex_poly;
- gd::NavigationPoly *right_poly = apex_poly;
- gd::NavigationPoly *p = apex_poly;
-
- path.push_back(end_point);
+ // If we did not find a route, return an empty path.
+ if (!found_route) {
+ return Vector<Vector3>();
+ }
- while (p) {
- Vector3 left;
- Vector3 right;
+ Vector<Vector3> path;
+ // Optimize the path.
+ if (p_optimize) {
+ // Set the apex poly/point to the end point
+ gd::NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
+ Vector3 apex_point = end_point;
-#define CLOCK_TANGENT(m_a, m_b, m_c) (((m_a) - (m_c)).cross((m_a) - (m_b)))
+ gd::NavigationPoly *left_poly = apex_poly;
+ Vector3 left_portal = apex_point;
+ gd::NavigationPoly *right_poly = apex_poly;
+ Vector3 right_portal = apex_point;
- if (p->poly == begin_poly) {
- left = begin_point;
- right = begin_point;
- } else {
- int prev = p->back_navigation_edge;
- int prev_n = (p->back_navigation_edge + 1) % p->poly->points.size();
- left = p->poly->points[prev].pos;
- right = p->poly->points[prev_n].pos;
+ gd::NavigationPoly *p = apex_poly;
- if (p->poly->clockwise) {
- SWAP(left, right);
- }
- }
+ path.push_back(end_point);
- bool skip = false;
-
- if (CLOCK_TANGENT(apex_point, portal_left, left).dot(up) >= 0) {
- //process
- if (portal_left == apex_point || CLOCK_TANGENT(apex_point, left, portal_right).dot(up) > 0) {
- left_poly = p;
- portal_left = left;
- } else {
- clip_path(navigation_polys, path, apex_poly, portal_right, right_poly);
-
- apex_point = portal_right;
- p = right_poly;
- left_poly = p;
- apex_poly = p;
- portal_left = apex_point;
- portal_right = apex_point;
- path.push_back(apex_point);
- skip = true;
- }
- }
+ while (p) {
+ // Set left and right points of the pathway between polygons.
+ Vector3 left = p->back_navigation_edge_pathway_start;
+ Vector3 right = p->back_navigation_edge_pathway_end;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left, right).dot(up) < 0) {
+ SWAP(left, right);
+ }
- if (!skip && CLOCK_TANGENT(apex_point, portal_right, right).dot(up) <= 0) {
- //process
- if (portal_right == apex_point || CLOCK_TANGENT(apex_point, right, portal_left).dot(up) < 0) {
- right_poly = p;
- portal_right = right;
- } else {
- clip_path(navigation_polys, path, apex_poly, portal_left, left_poly);
-
- apex_point = portal_left;
- p = left_poly;
- right_poly = p;
- apex_poly = p;
- portal_right = apex_point;
- portal_left = apex_point;
- path.push_back(apex_point);
- }
+ bool skip = false;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left_portal, left).dot(up) >= 0) {
+ //process
+ if (left_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, left, right_portal).dot(up) > 0) {
+ left_poly = p;
+ left_portal = left;
+ } else {
+ clip_path(navigation_polys, path, apex_poly, right_portal, right_poly);
+
+ apex_point = right_portal;
+ p = right_poly;
+ left_poly = p;
+ apex_poly = p;
+ left_portal = apex_point;
+ right_portal = apex_point;
+ path.push_back(apex_point);
+ skip = true;
}
+ }
- if (p->prev_navigation_poly_id != -1) {
- p = &navigation_polys[p->prev_navigation_poly_id];
+ if (!skip && THREE_POINTS_CROSS_PRODUCT(apex_point, right_portal, right).dot(up) <= 0) {
+ //process
+ if (right_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, right, left_portal).dot(up) < 0) {
+ right_poly = p;
+ right_portal = right;
} else {
- // The end
- p = nullptr;
+ clip_path(navigation_polys, path, apex_poly, left_portal, left_poly);
+
+ apex_point = left_portal;
+ p = left_poly;
+ right_poly = p;
+ apex_poly = p;
+ right_portal = apex_point;
+ left_portal = apex_point;
+ path.push_back(apex_point);
}
}
- if (path[path.size() - 1] != begin_point) {
- path.push_back(begin_point);
+ // Go to the previous polygon.
+ if (p->back_navigation_poly_id != -1) {
+ p = &navigation_polys[p->back_navigation_poly_id];
+ } else {
+ // The end
+ p = nullptr;
}
+ }
- path.invert();
-
- } else {
- path.push_back(end_point);
+ // If the last point is not the begin point, add it to the list.
+ if (path[path.size() - 1] != begin_point) {
+ path.push_back(begin_point);
+ }
- // Add mid points
- int np_id = least_cost_id;
- while (np_id != -1) {
-#ifdef USE_ENTRY_POINT
- Vector3 point = navigation_polys[np_id].entry;
-#else
- int prev = navigation_polys[np_id].back_navigation_edge;
- int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
- Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
-#endif
+ path.reverse();
- path.push_back(point);
- np_id = navigation_polys[np_id].prev_navigation_poly_id;
- }
+ } else {
+ path.push_back(end_point);
- path.invert();
+ // Add mid points
+ int np_id = least_cost_id;
+ while (np_id != -1) {
+ path.push_back(navigation_polys[np_id].entry);
+ np_id = navigation_polys[np_id].back_navigation_poly_id;
}
- return path;
+ path.reverse();
}
- return Vector<Vector3>();
+
+ return path;
}
Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -518,7 +504,7 @@ void NavMap::add_region(NavRegion *p_region) {
}
void NavMap::remove_region(NavRegion *p_region) {
- std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region);
+ const std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region);
if (it != regions.end()) {
regions.erase(it);
regenerate_links = true;
@@ -538,7 +524,7 @@ void NavMap::add_agent(RvoAgent *agent) {
void NavMap::remove_agent(RvoAgent *agent) {
remove_agent_as_controlled(agent);
- auto it = std::find(agents.begin(), agents.end(), agent);
+ const std::vector<RvoAgent *>::iterator it = std::find(agents.begin(), agents.end(), agent);
if (it != agents.end()) {
agents.erase(it);
agents_dirty = true;
@@ -554,13 +540,14 @@ void NavMap::set_agent_as_controlled(RvoAgent *agent) {
}
void NavMap::remove_agent_as_controlled(RvoAgent *agent) {
- auto it = std::find(controlled_agents.begin(), controlled_agents.end(), agent);
+ const std::vector<RvoAgent *>::iterator it = std::find(controlled_agents.begin(), controlled_agents.end(), agent);
if (it != controlled_agents.end()) {
controlled_agents.erase(it);
}
}
void NavMap::sync() {
+ // Check if we need to update the links.
if (regenerate_polygons) {
for (size_t r(0); r < regions.size(); r++) {
regions[r]->scratch_polygons();
@@ -575,27 +562,30 @@ void NavMap::sync() {
}
if (regenerate_links) {
- // Copy all region polygons in the map.
+ // Remove regions connections.
+ for (size_t r(0); r < regions.size(); r++) {
+ regions[r]->get_connections().clear();
+ }
+
+ // Resize the polygon count.
int count = 0;
for (size_t r(0); r < regions.size(); r++) {
count += regions[r]->get_polygons().size();
}
-
polygons.resize(count);
- count = 0;
+ // Copy all region polygons in the map.
+ count = 0;
for (size_t r(0); r < regions.size(); r++) {
std::copy(
regions[r]->get_polygons().data(),
regions[r]->get_polygons().data() + regions[r]->get_polygons().size(),
polygons.begin() + count);
-
count += regions[r]->get_polygons().size();
}
- // Connects the `Edges` of all the `Polygons` of all `Regions` each other.
- Map<gd::EdgeKey, gd::Connection> connections;
-
+ // Group all edges per key.
+ Map<gd::EdgeKey, Vector<gd::Edge::Connection>> connections;
for (size_t poly_id(0); poly_id < polygons.size(); poly_id++) {
gd::Polygon &poly(polygons[poly_id]);
@@ -603,69 +593,40 @@ void NavMap::sync() {
int next_point = (p + 1) % poly.points.size();
gd::EdgeKey ek(poly.points[p].key, poly.points[next_point].key);
- Map<gd::EdgeKey, gd::Connection>::Element *connection = connections.find(ek);
+ Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *connection = connections.find(ek);
if (!connection) {
- // Nothing yet
- gd::Connection c;
- c.A = &poly;
- c.A_edge = p;
- c.B = nullptr;
- c.B_edge = -1;
- connections[ek] = c;
-
- } else if (connection->get().B == nullptr) {
- CRASH_COND(connection->get().A == nullptr); // Unreachable
-
- // Connect the two Polygons by this edge
- connection->get().B = &poly;
- connection->get().B_edge = p;
-
- connection->get().A->edges[connection->get().A_edge].this_edge = connection->get().A_edge;
- connection->get().A->edges[connection->get().A_edge].other_polygon = connection->get().B;
- connection->get().A->edges[connection->get().A_edge].other_edge = connection->get().B_edge;
-
- connection->get().B->edges[connection->get().B_edge].this_edge = connection->get().B_edge;
- connection->get().B->edges[connection->get().B_edge].other_polygon = connection->get().A;
- connection->get().B->edges[connection->get().B_edge].other_edge = connection->get().A_edge;
+ connections[ek] = Vector<gd::Edge::Connection>();
+ }
+ if (connections[ek].size() <= 1) {
+ // Add the polygon/edge tuple to this key.
+ gd::Edge::Connection new_connection;
+ new_connection.polygon = &poly;
+ new_connection.edge = p;
+ new_connection.pathway_start = poly.points[p].pos;
+ new_connection.pathway_end = poly.points[next_point].pos;
+ connections[ek].push_back(new_connection);
} else {
// The edge is already connected with another edge, skip.
- ERR_PRINT("Attempted to merge a navigation mesh triangle edge with another already-merged edge. This happens when the Navigation3D's `cell_size` is different from the one used to generate the navigation mesh. This will cause navigation problem.");
+ ERR_PRINT("Attempted to merge a navigation mesh triangle edge with another already-merged edge. This happens when the current `cell_size` is different from the one used to generate the navigation mesh. This will cause navigation problem.");
}
}
}
- // Takes all the free edges.
- std::vector<gd::FreeEdge> free_edges;
- free_edges.reserve(connections.size());
-
- for (auto connection_element = connections.front(); connection_element; connection_element = connection_element->next()) {
- if (connection_element->get().B == nullptr) {
- CRASH_COND(connection_element->get().A == nullptr); // Unreachable
- CRASH_COND(connection_element->get().A_edge < 0); // Unreachable
-
- // This is a free edge
- uint32_t id(free_edges.size());
- free_edges.push_back(gd::FreeEdge());
- free_edges[id].is_free = true;
- free_edges[id].poly = connection_element->get().A;
- free_edges[id].edge_id = connection_element->get().A_edge;
- uint32_t point_0(free_edges[id].edge_id);
- uint32_t point_1((free_edges[id].edge_id + 1) % free_edges[id].poly->points.size());
- Vector3 pos_0 = free_edges[id].poly->points[point_0].pos;
- Vector3 pos_1 = free_edges[id].poly->points[point_1].pos;
- Vector3 relative = pos_1 - pos_0;
- free_edges[id].edge_center = (pos_0 + pos_1) / 2.0;
- free_edges[id].edge_dir = relative.normalized();
- free_edges[id].edge_len_squared = relative.length_squared();
+ Vector<gd::Edge::Connection> free_edges;
+ for (Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *E = connections.front(); E; E = E->next()) {
+ if (E->get().size() == 2) {
+ // Connect edge that are shared in different polygons.
+ gd::Edge::Connection &c1 = E->get().write[0];
+ gd::Edge::Connection &c2 = E->get().write[1];
+ c1.polygon->edges[c1.edge].connections.push_back(c2);
+ c2.polygon->edges[c2.edge].connections.push_back(c1);
+ // Note: The pathway_start/end are full for those connection and do not need to be modified.
+ } else {
+ CRASH_COND_MSG(E->get().size() != 1, vformat("Number of connection != 1. Found: %d", E->get().size()));
+ free_edges.push_back(E->get()[0]);
}
}
- const float ecm_squared(edge_connection_margin * edge_connection_margin);
-#define LEN_TOLLERANCE 0.1
-#define DIR_TOLLERANCE 0.9
- // In front of tolerance
-#define IFO_TOLLERANCE 0.5
-
// Find the compatible near edges.
//
// Note:
@@ -673,43 +634,67 @@ void NavMap::sync() {
// to be connected, create new polygons to remove that small gap is
// not really useful and would result in wasteful computation during
// connection, integration and path finding.
- for (size_t i(0); i < free_edges.size(); i++) {
- if (!free_edges[i].is_free) {
- continue;
- }
- gd::FreeEdge &edge = free_edges[i];
- for (size_t y(0); y < free_edges.size(); y++) {
- gd::FreeEdge &other_edge = free_edges[y];
- if (i == y || !other_edge.is_free || edge.poly->owner == other_edge.poly->owner) {
+ for (int i = 0; i < free_edges.size(); i++) {
+ const gd::Edge::Connection &free_edge = free_edges[i];
+ Vector3 edge_p1 = free_edge.polygon->points[free_edge.edge].pos;
+ Vector3 edge_p2 = free_edge.polygon->points[(free_edge.edge + 1) % free_edge.polygon->points.size()].pos;
+
+ for (int j = 0; j < free_edges.size(); j++) {
+ const gd::Edge::Connection &other_edge = free_edges[j];
+ if (i == j || free_edge.polygon->owner == other_edge.polygon->owner) {
continue;
}
- Vector3 rel_centers = other_edge.edge_center - edge.edge_center;
- if (ecm_squared > rel_centers.length_squared() // Are enough closer?
- && ABS(edge.edge_len_squared - other_edge.edge_len_squared) < LEN_TOLLERANCE // Are the same length?
- && ABS(edge.edge_dir.dot(other_edge.edge_dir)) > DIR_TOLLERANCE // Are aligned?
- && ABS(rel_centers.normalized().dot(edge.edge_dir)) < IFO_TOLLERANCE // Are one in front the other?
- ) {
- // The edges can be connected
- edge.is_free = false;
- other_edge.is_free = false;
-
- edge.poly->edges[edge.edge_id].this_edge = edge.edge_id;
- edge.poly->edges[edge.edge_id].other_edge = other_edge.edge_id;
- edge.poly->edges[edge.edge_id].other_polygon = other_edge.poly;
-
- other_edge.poly->edges[other_edge.edge_id].this_edge = other_edge.edge_id;
- other_edge.poly->edges[other_edge.edge_id].other_edge = edge.edge_id;
- other_edge.poly->edges[other_edge.edge_id].other_polygon = edge.poly;
+ Vector3 other_edge_p1 = other_edge.polygon->points[other_edge.edge].pos;
+ Vector3 other_edge_p2 = other_edge.polygon->points[(other_edge.edge + 1) % other_edge.polygon->points.size()].pos;
+
+ // Compute the projection of the opposite edge on the current one
+ Vector3 edge_vector = edge_p2 - edge_p1;
+ float projected_p1_ratio = edge_vector.dot(other_edge_p1 - edge_p1) / (edge_vector.length_squared());
+ float projected_p2_ratio = edge_vector.dot(other_edge_p2 - edge_p1) / (edge_vector.length_squared());
+ if ((projected_p1_ratio < 0.0 && projected_p2_ratio < 0.0) || (projected_p1_ratio > 1.0 && projected_p2_ratio > 1.0)) {
+ continue;
+ }
+
+ // Check if the two edges are close to each other enough and compute a pathway between the two regions.
+ Vector3 self1 = edge_vector * CLAMP(projected_p1_ratio, 0.0, 1.0) + edge_p1;
+ Vector3 other1;
+ if (projected_p1_ratio >= 0.0 && projected_p1_ratio <= 1.0) {
+ other1 = other_edge_p1;
+ } else {
+ other1 = other_edge_p1.lerp(other_edge_p2, (1.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
+ if ((self1 - other1).length() > edge_connection_margin) {
+ continue;
+ }
+
+ Vector3 self2 = edge_vector * CLAMP(projected_p2_ratio, 0.0, 1.0) + edge_p1;
+ Vector3 other2;
+ if (projected_p2_ratio >= 0.0 && projected_p2_ratio <= 1.0) {
+ other2 = other_edge_p2;
+ } else {
+ other2 = other_edge_p1.lerp(other_edge_p2, (0.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
+ }
+ if ((self2 - other2).length() > edge_connection_margin) {
+ continue;
+ }
+
+ // The edges can now be connected.
+ gd::Edge::Connection new_connection = other_edge;
+ new_connection.pathway_start = (self1 + other1) / 2.0;
+ new_connection.pathway_end = (self2 + other2) / 2.0;
+ free_edge.polygon->edges[free_edge.edge].connections.push_back(new_connection);
+
+ // Add the connection to the region_connection map.
+ free_edge.polygon->owner->get_connections().push_back(new_connection);
}
}
- }
- if (regenerate_links) {
+ // Update the update ID.
map_update_id = (map_update_id + 1) % 9999999;
}
+ // Update agents tree.
if (agents_dirty) {
std::vector<RVO::Agent *> raw_agents;
raw_agents.reserve(agents.size());
@@ -761,16 +746,15 @@ void NavMap::clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys
cut_plane.d = cut_plane.normal.dot(from);
while (from_poly != p_to_poly) {
- int back_nav_edge = from_poly->back_navigation_edge;
- Vector3 a = from_poly->poly->points[back_nav_edge].pos;
- Vector3 b = from_poly->poly->points[(back_nav_edge + 1) % from_poly->poly->points.size()].pos;
+ Vector3 pathway_start = from_poly->back_navigation_edge_pathway_start;
+ Vector3 pathway_end = from_poly->back_navigation_edge_pathway_end;
- ERR_FAIL_COND(from_poly->prev_navigation_poly_id == -1);
- from_poly = &p_navigation_polys[from_poly->prev_navigation_poly_id];
+ ERR_FAIL_COND(from_poly->back_navigation_poly_id == -1);
+ from_poly = &p_navigation_polys[from_poly->back_navigation_poly_id];
- if (a.distance_to(b) > CMP_EPSILON) {
+ if (pathway_start.distance_to(pathway_end) > CMP_EPSILON) {
Vector3 inters;
- if (cut_plane.intersects_segment(a, b, &inters)) {
+ if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) {
if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(path[path.size() - 1]) > CMP_EPSILON) {
path.push_back(inters);
}
diff --git a/modules/gdnavigation/nav_map.h b/modules/gdnavigation/nav_map.h
index bffc1fbc1a..8e013a72eb 100644
--- a/modules/gdnavigation/nav_map.h
+++ b/modules/gdnavigation/nav_map.h
@@ -34,6 +34,7 @@
#include "nav_rid.h"
#include "core/math/math_defs.h"
+#include "core/templates/map.h"
#include "nav_utils.h"
#include <KdTree.h>
@@ -102,7 +103,7 @@ public:
gd::PointKey get_point_key(const Vector3 &p_pos) const;
- Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize) const;
+ Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const;
Vector3 get_closest_point(const Vector3 &p_point) const;
Vector3 get_closest_point_normal(const Vector3 &p_point) const;
diff --git a/modules/gdnavigation/nav_region.cpp b/modules/gdnavigation/nav_region.cpp
index 383b0f15a6..c1690b2a4b 100644
--- a/modules/gdnavigation/nav_region.cpp
+++ b/modules/gdnavigation/nav_region.cpp
@@ -39,6 +39,17 @@
void NavRegion::set_map(NavMap *p_map) {
map = p_map;
polygons_dirty = true;
+ if (!map) {
+ connections.clear();
+ }
+}
+
+void NavRegion::set_layers(uint32_t p_layers) {
+ layers = p_layers;
+}
+
+uint32_t NavRegion::get_layers() const {
+ return layers;
}
void NavRegion::set_transform(Transform p_transform) {
@@ -51,6 +62,25 @@ void NavRegion::set_mesh(Ref<NavigationMesh> p_mesh) {
polygons_dirty = true;
}
+int NavRegion::get_connections_count() const {
+ if (!map) {
+ return 0;
+ }
+ return connections.size();
+}
+
+Vector3 NavRegion::get_connection_pathway_start(int p_connection_id) const {
+ ERR_FAIL_COND_V(!map, Vector3());
+ ERR_FAIL_INDEX_V(p_connection_id, connections.size(), Vector3());
+ return connections[p_connection_id].pathway_start;
+}
+
+Vector3 NavRegion::get_connection_pathway_end(int p_connection_id) const {
+ ERR_FAIL_COND_V(!map, Vector3());
+ ERR_FAIL_INDEX_V(p_connection_id, connections.size(), Vector3());
+ return connections[p_connection_id].pathway_end;
+}
+
bool NavRegion::sync() {
bool something_changed = polygons_dirty /* || something_dirty? */;
diff --git a/modules/gdnavigation/nav_region.h b/modules/gdnavigation/nav_region.h
index 954780033b..527b2500ac 100644
--- a/modules/gdnavigation/nav_region.h
+++ b/modules/gdnavigation/nav_region.h
@@ -31,10 +31,10 @@
#ifndef NAV_REGION_H
#define NAV_REGION_H
-#include "nav_rid.h"
+#include "scene/resources/navigation_mesh.h"
+#include "nav_rid.h"
#include "nav_utils.h"
-#include "scene/3d/navigation_3d.h"
#include <vector>
/**
@@ -48,6 +48,8 @@ class NavRegion : public NavRid {
NavMap *map = nullptr;
Transform transform;
Ref<NavigationMesh> mesh;
+ uint32_t layers = 1;
+ Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@@ -66,6 +68,9 @@ public:
return map;
}
+ void set_layers(uint32_t p_layers);
+ uint32_t get_layers() const;
+
void set_transform(Transform transform);
const Transform &get_transform() const {
return transform;
@@ -76,6 +81,13 @@ public:
return mesh;
}
+ Vector<gd::Edge::Connection> &get_connections() {
+ return connections;
+ }
+ int get_connections_count() const;
+ Vector3 get_connection_pathway_start(int p_connection_id) const;
+ Vector3 get_connection_pathway_end(int p_connection_id) const;
+
std::vector<gd::Polygon> const &get_polygons() const {
return polygons;
}
diff --git a/modules/gdnavigation/nav_utils.h b/modules/gdnavigation/nav_utils.h
index d257a95ef1..35da391eea 100644
--- a/modules/gdnavigation/nav_utils.h
+++ b/modules/gdnavigation/nav_utils.h
@@ -81,11 +81,14 @@ struct Edge {
/// This edge ID
int this_edge = -1;
- /// Other Polygon
- Polygon *other_polygon = nullptr;
-
- /// The other `Polygon` at this edge id has this `Polygon`.
- int other_edge = -1;
+ /// The gateway in the edge, as, in some case, the whole edge might not be navigable.
+ struct Connection {
+ Polygon *polygon = nullptr;
+ int edge = -1;
+ Vector3 pathway_start;
+ Vector3 pathway_end;
+ };
+ Vector<Connection> connections;
};
struct Polygon {
@@ -104,21 +107,17 @@ struct Polygon {
Vector3 center;
};
-struct Connection {
- Polygon *A = nullptr;
- int A_edge = -1;
- Polygon *B = nullptr;
- int B_edge = -1;
-};
-
struct NavigationPoly {
uint32_t self_id = 0;
/// This poly.
const Polygon *poly;
- /// The previous navigation poly (id in the `navigation_poly` array).
- int prev_navigation_poly_id = -1;
- /// The edge id in this `Poly` to reach the `prev_navigation_poly_id`.
- uint32_t back_navigation_edge = 0;
+
+ /// Those 4 variables are used to travel the path backwards.
+ int back_navigation_poly_id = -1;
+ uint32_t back_navigation_edge = UINT32_MAX;
+ Vector3 back_navigation_edge_pathway_start;
+ Vector3 back_navigation_edge_pathway_end;
+
/// The entry location of this poly.
Vector3 entry;
/// The distance to the destination.
@@ -136,14 +135,6 @@ struct NavigationPoly {
}
};
-struct FreeEdge {
- bool is_free = false;
- Polygon *poly = nullptr;
- uint32_t edge_id = 0;
- Vector3 edge_center;
- Vector3 edge_dir;
- float edge_len_squared = 0.0;
-};
} // namespace gd
#endif // NAV_UTILS_H
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 6e930b6bf4..9d0d91162c 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -44,7 +44,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
// Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc.
Error err;
- RES loaded_res = ResourceLoader::load(p_path, "", false, &err);
+ RES loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
if (err) {
ERR_PRINT("Failed to load " + p_path);
return err;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index f891145988..5f590383d0 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -45,6 +45,10 @@
#include "gdscript_parser.h"
#include "gdscript_warning.h"
+#ifdef TESTS_ENABLED
+#include "tests/gdscript_test_runner.h"
+#endif
+
///////////////////////////
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
@@ -276,7 +280,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
}
msort.sort();
- msort.invert();
+ msort.reverse();
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -1310,21 +1314,29 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return true; //function exists, call was successful
}
} else {
- if (!member->data_type.is_type(p_value)) {
- // Try conversion
- Callable::CallError ce;
- const Variant *value = &p_value;
- Variant converted;
- Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- members.write[member->index] = converted;
- return true;
- } else {
- return false;
+ if (member->data_type.has_type) {
+ if (member->data_type.builtin_type == Variant::ARRAY && member->data_type.has_container_element_type()) {
+ // Typed array.
+ if (p_value.get_type() == Variant::ARRAY) {
+ return VariantInternal::get_array(&members.write[member->index])->typed_assign(p_value);
+ } else {
+ return false;
+ }
+ } else if (!member->data_type.is_type(p_value)) {
+ // Try conversion
+ Callable::CallError ce;
+ const Variant *value = &p_value;
+ Variant converted;
+ Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce);
+ if (ce.error == Callable::CallError::CALL_OK) {
+ members.write[member->index] = converted;
+ return true;
+ } else {
+ return false;
+ }
}
- } else {
- members.write[member->index] = p_value;
}
+ members.write[member->index] = p_value;
}
return true;
}
@@ -1494,7 +1506,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
}
msort.sort();
- msort.invert();
+ msort.reverse();
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -1758,6 +1770,10 @@ void GDScriptLanguage::init() {
for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
_add_global(E->get().name, E->get().ptr);
}
+
+#ifdef TESTS_ENABLED
+ GDScriptTests::GDScriptTestRunner::handle_cmdline();
+#endif
}
String GDScriptLanguage::get_type() const {
@@ -2293,7 +2309,7 @@ GDScriptLanguage::~GDScriptLanguage() {
script->unreference();
}
- singleton = NULL;
+ singleton = nullptr;
}
void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
@@ -2316,7 +2332,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index ee270f6b2f..98da5ad4cb 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -270,6 +270,7 @@ public:
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
+ friend class GDScriptLambdaCallable;
friend class GDScriptCompiler;
friend struct GDScriptUtilityFunctionsDefinitions;
@@ -529,7 +530,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index a6138cc564..17ae52f3ab 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -39,40 +39,6 @@
#include "gdscript.h"
#include "gdscript_utility_functions.h"
-// TODO: Move this to a central location (maybe core?).
-static HashMap<StringName, StringName> underscore_map;
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-static StringName get_real_class_name(const StringName &p_source) {
- if (underscore_map.is_empty()) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- underscore_map[*class_name] = String("_") + *class_name;
- class_name++;
- }
- }
- if (underscore_map.has(p_source)) {
- return underscore_map[p_source];
- }
- return p_source;
-}
-
static MethodInfo info_from_utility_func(const StringName &p_function) {
ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo());
@@ -106,10 +72,6 @@ static MethodInfo info_from_utility_func(const StringName &p_function) {
return info;
}
-void GDScriptAnalyzer::cleanup() {
- underscore_map.clear();
-}
-
static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) {
GDScriptParser::DataType type;
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -150,7 +112,7 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native
type.is_meta_type = true;
List<StringName> enum_values;
- StringName real_native_name = get_real_class_name(p_native_class);
+ StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class);
ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values);
for (const List<StringName>::Element *E = enum_values.front(); E != nullptr; E = E->next()) {
@@ -267,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
- } else if (class_exists(name) && ClassDB::can_instance(get_real_class_name(name))) {
+ } else if (class_exists(name) && ClassDB::can_instance(GDScriptParser::get_real_class_name(name))) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -413,6 +375,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = GDScriptParser::get_builtin_type(first);
+
+ if (result.builtin_type == Variant::ARRAY) {
+ GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type);
+
+ if (container_type.kind != GDScriptParser::DataType::VARIANT) {
+ result.set_container_element_type(container_type);
+ }
+ }
} else if (class_exists(first)) {
// Native engine classes.
result.kind = GDScriptParser::DataType::NATIVE;
@@ -436,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return GDScriptParser::DataType();
}
result = ref->get_parser()->head->get_datatype();
- } else if (ClassDB::has_enum(get_real_class_name(parser->current_class->base_type.native_type), first)) {
+ } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) {
// Native enum in current class.
result = make_native_enum_type(parser->current_class->base_type.native_type, first);
} else {
@@ -499,7 +469,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
+ if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
if (p_type->type_chain.size() > 2) {
push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
} else {
@@ -513,6 +483,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
}
+ if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) {
+ push_error("Only arrays can specify the collection element type.", p_type);
+ }
+
p_type->set_datatype(result);
return result;
}
@@ -535,9 +509,23 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.kind = GDScriptParser::DataType::VARIANT;
datatype.type_source = GDScriptParser::DataType::UNDETECTED;
+ GDScriptParser::DataType specified_type;
+ if (member.variable->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(member.variable->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
if (member.variable->initializer != nullptr) {
member.variable->set_datatype(datatype); // Allow recursive usage.
reduce_expression(member.variable->initializer);
+ if ((member.variable->infer_datatype || (member.variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && member.variable->initializer->type == GDScriptParser::Node::ARRAY) {
+ // Typed array.
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.variable->initializer);
+ // Can only infer typed array if it has elements.
+ if ((member.variable->infer_datatype && array->elements.size() > 0) || member.variable->datatype_specifier != nullptr) {
+ update_array_literal_element_type(specified_type, array);
+ }
+ }
datatype = member.variable->initializer->get_datatype();
if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) {
datatype.type_source = GDScriptParser::DataType::INFERRED;
@@ -545,8 +533,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.variable->datatype_specifier != nullptr) {
- datatype = resolve_datatype(member.variable->datatype_specifier);
- datatype.is_meta_type = false;
+ datatype = specified_type;
if (member.variable->initializer != nullptr) {
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) {
@@ -582,37 +569,32 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.is_constant = false;
member.variable->set_datatype(datatype);
- if (!datatype.has_no_type()) {
- // TODO: Move this out into a routine specific to validate annotations.
- if (member.variable->export_info.hint == PROPERTY_HINT_TYPE_STRING) {
- // @export annotation.
- switch (datatype.kind) {
- case GDScriptParser::DataType::BUILTIN:
- member.variable->export_info.hint_string = Variant::get_type_name(datatype.builtin_type);
- break;
- case GDScriptParser::DataType::NATIVE:
- if (ClassDB::is_parent_class(get_real_class_name(datatype.native_type), "Resource")) {
- member.variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- member.variable->export_info.hint_string = get_real_class_name(datatype.native_type);
- } else {
- push_error(R"(Export type can only be built-in or a resource.)", member.variable);
- }
- break;
- default:
- // TODO: Allow custom user resources.
- push_error(R"(Export type can only be built-in or a resource.)", member.variable);
- break;
- }
- }
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.variable->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.variable);
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
reduce_expression(member.constant->initializer);
+ GDScriptParser::DataType specified_type;
+
+ if (member.constant->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(member.constant->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
GDScriptParser::DataType datatype = member.constant->get_datatype();
if (member.constant->initializer) {
if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
- const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer));
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer);
+ const_fold_array(array);
+
+ // Can only infer typed array if it has elements.
+ if (array->elements.size() > 0 || (member.constant->datatype_specifier != nullptr && specified_type.has_container_element_type())) {
+ update_array_literal_element_type(specified_type, array);
+ }
} else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
}
@@ -622,8 +604,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.constant->datatype_specifier != nullptr) {
- datatype = resolve_datatype(member.constant->datatype_specifier);
- datatype.is_meta_type = false;
+ datatype = specified_type;
if (!is_type_compatible(datatype, member.constant->initializer->get_datatype(), true)) {
push_error(vformat(R"(Value of type "%s" cannot be initialized to constant of type "%s".)", member.constant->initializer->get_datatype().to_string(), datatype.to_string()), member.constant->initializer);
@@ -637,6 +618,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.is_constant = true;
member.constant->set_datatype(datatype);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.constant->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.constant);
+ }
} break;
case GDScriptParser::ClassNode::Member::SIGNAL: {
for (int j = 0; j < member.signal->parameters.size(); j++) {
@@ -651,6 +637,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
signal_type.builtin_type = Variant::SIGNAL;
member.signal->set_datatype(signal_type);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.signal->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.signal);
+ }
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
GDScriptParser::DataType enum_type;
@@ -693,6 +684,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
current_enum = nullptr;
member.m_enum->set_datatype(enum_type);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.m_enum->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.m_enum);
+ }
} break;
case GDScriptParser::ClassNode::Member::FUNCTION:
resolve_function_signature(member.function);
@@ -761,6 +757,11 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
resolve_function_body(member.function);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.function->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.function);
+ }
}
parser->current_class = previous_class;
@@ -855,6 +856,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
case GDScriptParser::Node::DICTIONARY:
case GDScriptParser::Node::GET_NODE:
case GDScriptParser::Node::IDENTIFIER:
+ case GDScriptParser::Node::LAMBDA:
case GDScriptParser::Node::LITERAL:
case GDScriptParser::Node::PRELOAD:
case GDScriptParser::Node::SELF:
@@ -1092,8 +1094,23 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
GDScriptParser::DataType type;
type.kind = GDScriptParser::DataType::VARIANT; // By default.
+ GDScriptParser::DataType specified_type;
+ if (p_variable->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(p_variable->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
if (p_variable->initializer != nullptr) {
reduce_expression(p_variable->initializer);
+ if ((p_variable->infer_datatype || (p_variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && p_variable->initializer->type == GDScriptParser::Node::ARRAY) {
+ // Typed array.
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_variable->initializer);
+ // Can only infer typed array if it has elements.
+ if ((p_variable->infer_datatype && array->elements.size() > 0) || p_variable->datatype_specifier != nullptr) {
+ update_array_literal_element_type(specified_type, array);
+ }
+ }
+
type = p_variable->initializer->get_datatype();
if (p_variable->infer_datatype) {
@@ -1117,7 +1134,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
}
if (p_variable->datatype_specifier != nullptr) {
- type = resolve_datatype(p_variable->datatype_specifier);
+ type = specified_type;
type.is_meta_type = false;
if (p_variable->initializer != nullptr) {
@@ -1362,6 +1379,12 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
if (p_return->return_value != nullptr) {
reduce_expression(p_return->return_value);
+ if (p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ // Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
+ if (parser->current_function->get_datatype().has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(parser->current_function->get_datatype(), static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
+ }
+ }
result = p_return->return_value->get_datatype();
} else {
// Return type is null by default.
@@ -1436,6 +1459,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
case GDScriptParser::Node::IDENTIFIER:
reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_expression));
break;
+ case GDScriptParser::Node::LAMBDA:
+ reduce_lambda(static_cast<GDScriptParser::LambdaNode *>(p_expression));
+ break;
case GDScriptParser::Node::LITERAL:
reduce_literal(static_cast<GDScriptParser::LiteralNode *>(p_expression));
break;
@@ -1498,6 +1524,52 @@ void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) {
p_array->set_datatype(arr_type);
}
+// When an array literal is stored (or passed as function argument) to a typed context, we then assume the array is typed.
+// This function determines which type is that (if any).
+void GDScriptAnalyzer::update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal) {
+ GDScriptParser::DataType array_type = p_array_literal->get_datatype();
+ if (p_array_literal->elements.size() == 0) {
+ // Empty array literal, just make the same type as the storage.
+ array_type.set_container_element_type(p_base_type.get_container_element_type());
+ } else {
+ // Check if elements match.
+ bool all_same_type = true;
+ bool all_have_type = true;
+
+ GDScriptParser::DataType element_type;
+ for (int i = 0; i < p_array_literal->elements.size(); i++) {
+ if (i == 0) {
+ element_type = p_array_literal->elements[0]->get_datatype();
+ } else {
+ GDScriptParser::DataType this_element_type = p_array_literal->elements[i]->get_datatype();
+ if (this_element_type.has_no_type()) {
+ all_same_type = false;
+ all_have_type = false;
+ break;
+ } else if (element_type != this_element_type) {
+ if (!is_type_compatible(element_type, this_element_type, false)) {
+ if (is_type_compatible(this_element_type, element_type, false)) {
+ // This element is a super-type to the previous type, so we use the super-type.
+ element_type = this_element_type;
+ } else {
+ // It's incompatible.
+ all_same_type = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (all_same_type) {
+ array_type.set_container_element_type(element_type);
+ } else if (all_have_type) {
+ push_error(vformat(R"(Variant array is not compatible with an array of type "%s".)", p_base_type.get_container_element_type().to_string()), p_array_literal);
+ }
+ }
+ // Update the type on the value itself.
+ p_array_literal->set_datatype(array_type);
+}
+
void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assignment) {
reduce_expression(p_assignment->assignee);
reduce_expression(p_assignment->assigned_value);
@@ -1506,24 +1578,33 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
return;
}
- if (p_assignment->assignee->get_datatype().is_constant) {
+ GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
+
+ // Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
+ if (assignee_type.has_container_element_type() && p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(assignee_type, static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value));
+ }
+
+ GDScriptParser::DataType assigned_value_type = p_assignment->assigned_value->get_datatype();
+
+ if (assignee_type.is_constant) {
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) {
+ if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) {
bool compatible = true;
- GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype();
+ GDScriptParser::DataType op_type = assigned_value_type;
if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- op_type = get_operation_type(p_assignment->variant_op, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible, p_assignment->assigned_value);
+ op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value);
}
if (compatible) {
- compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true);
+ compatible = is_type_compatible(assignee_type, op_type, true);
if (!compatible) {
- if (p_assignment->assignee->get_datatype().is_hard_type()) {
+ if (assignee_type.is_hard_type()) {
// Try reverse test since it can be a masked subtype.
- if (!is_type_compatible(op_type, p_assignment->assignee->get_datatype(), true)) {
- push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value);
+ if (!is_type_compatible(op_type, assignee_type, true)) {
+ push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
} else {
// TODO: Add warning.
mark_node_unsafe(p_assignment);
@@ -1534,11 +1615,11 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
}
} else {
- push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment);
+ push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", assignee_type.to_string(), assigned_value_type.to_string()), p_assignment);
}
}
- if (p_assignment->assignee->get_datatype().has_no_type() || p_assignment->assigned_value->get_datatype().is_variant()) {
+ if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
mark_node_unsafe(p_assignment);
}
@@ -1558,7 +1639,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: {
GDScriptParser::DataType id_type = identifier->variable_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = p_assignment->assigned_value->get_datatype();
+ id_type = assigned_value_type;
id_type.type_source = GDScriptParser::DataType::INFERRED;
id_type.is_constant = false;
identifier->variable_source->set_datatype(id_type);
@@ -1567,7 +1648,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: {
GDScriptParser::DataType id_type = identifier->bind_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = p_assignment->assigned_value->get_datatype();
+ id_type = assigned_value_type;
id_type.type_source = GDScriptParser::DataType::INFERRED;
id_type.is_constant = false;
identifier->variable_source->set_datatype(id_type);
@@ -1579,12 +1660,10 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
}
- GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
- GDScriptParser::DataType assigned_type = p_assignment->assigned_value->get_datatype();
#ifdef DEBUG_ENABLED
- if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_type.kind == GDScriptParser::DataType::BUILTIN && assigned_type.builtin_type == Variant::NIL) {
+ if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name);
- } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_type.builtin_type == Variant::FLOAT) {
+ } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
}
#endif
@@ -1728,8 +1807,12 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) {
bool all_is_constant = true;
+ Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
for (int i = 0; i < p_call->arguments.size(); i++) {
reduce_expression(p_call->arguments[i]);
+ if (p_call->arguments[i]->type == GDScriptParser::Node::ARRAY) {
+ arrays[i] = static_cast<GDScriptParser::ArrayNode *>(p_call->arguments[i]);
+ }
all_is_constant = all_is_constant && p_call->arguments[i]->is_constant;
}
@@ -1982,6 +2065,12 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
is_self = true;
} else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee);
+ if (subscript->base == nullptr) {
+ // Invalid syntax, error already set on parser.
+ p_call->set_datatype(call_type);
+ mark_node_unsafe(p_call);
+ return;
+ }
if (!subscript->is_attribute) {
// Invalid call. Error already sent in parser.
// TODO: Could check if Callable here.
@@ -2007,10 +2096,19 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
List<GDScriptParser::DataType> par_types;
if (get_function_signature(p_call, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ // If the function require typed arrays we must make literals be typed.
+ for (Map<int, GDScriptParser::ArrayNode *>::Element *E = arrays.front(); E; E = E->next()) {
+ int index = E->key();
+ if (index < par_types.size() && par_types[index].has_container_element_type()) {
+ update_array_literal_element_type(par_types[index], E->get());
+ }
+ }
validate_call_arg(par_types, default_arg_count, is_vararg, p_call);
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
+ } else if (is_self && !is_static && !lambda_stack.is_empty()) {
+ push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
}
call_type = return_type;
@@ -2131,8 +2229,10 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
result.native_type = "Node";
result.builtin_type = Variant::OBJECT;
- if (!ClassDB::is_parent_class(get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
+ if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
+ } else if (!lambda_stack.is_empty()) {
+ push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
}
p_get_node->set_datatype(result);
@@ -2260,6 +2360,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
case GDScriptParser::ClassNode::Member::ENUM_VALUE:
p_identifier->is_constant = true;
p_identifier->reduced_value = member.enum_value.value;
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
break;
case GDScriptParser::ClassNode::Member::VARIABLE:
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE;
@@ -2297,7 +2398,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check native members.
- const StringName &native = get_real_class_name(base.native_type);
+ const StringName &native = GDScriptParser::get_real_class_name(base.native_type);
if (class_exists(native)) {
PropertyInfo prop_info;
@@ -2360,42 +2461,65 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
}
+ bool found_source = false;
// Check if identifier is local.
// If that's the case, the declaration already was solved before.
switch (p_identifier->source) {
case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER:
p_identifier->set_datatype(p_identifier->parameter_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_CONSTANT:
case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
p_identifier->set_datatype(p_identifier->constant_source->get_datatype());
p_identifier->is_constant = true;
// TODO: Constant should have a value on the node itself.
p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value;
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
p_identifier->variable_source->usages++;
[[fallthrough]];
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
p_identifier->set_datatype(p_identifier->variable_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR:
p_identifier->set_datatype(p_identifier->bind_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_BIND: {
GDScriptParser::DataType result = p_identifier->bind_source->get_datatype();
result.is_constant = true;
p_identifier->set_datatype(result);
- return;
- }
+ found_source = true;
+ } break;
case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE:
break;
}
// Not a local, so check members.
- reduce_identifier_from_base(p_identifier);
- if (p_identifier->get_datatype().is_set()) {
- // Found.
+ if (!found_source) {
+ reduce_identifier_from_base(p_identifier);
+ if (p_identifier->source != GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->get_datatype().is_set()) {
+ // Found.
+ found_source = true;
+ }
+ }
+
+ if (found_source) {
+ // If the identifier is local, check if it's any kind of capture by comparing their source function.
+ // Only capture locals and members and enum values. Constants are still accessible from the lambda using the script reference.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT || lambda_stack.is_empty()) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
+ while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
+ function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
+ function_test->source_lambda->captures.push_back(p_identifier);
+ function_test = function_test->source_lambda->parent_function;
+ }
return;
}
@@ -2477,6 +2601,57 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
p_identifier->set_datatype(dummy); // Just so type is set to something.
}
+void GDScriptAnalyzer::reduce_lambda(GDScriptParser::LambdaNode *p_lambda) {
+ // Lambda is always a Callable.
+ GDScriptParser::DataType lambda_type;
+ lambda_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ lambda_type.kind = GDScriptParser::DataType::BUILTIN;
+ lambda_type.builtin_type = Variant::CALLABLE;
+ p_lambda->set_datatype(lambda_type);
+
+ if (p_lambda->function == nullptr) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *previous_function = parser->current_function;
+ parser->current_function = p_lambda->function;
+
+ lambda_stack.push_back(p_lambda);
+
+ for (int i = 0; i < p_lambda->function->parameters.size(); i++) {
+ resolve_parameter(p_lambda->function->parameters[i]);
+ }
+
+ resolve_suite(p_lambda->function->body);
+
+ int captures_amount = p_lambda->captures.size();
+ if (captures_amount > 0) {
+ // Create space for lambda parameters.
+ // At the beginning to not mess with optional parameters.
+ int param_count = p_lambda->function->parameters.size();
+ p_lambda->function->parameters.resize(param_count + captures_amount);
+ for (int i = param_count - 1; i >= 0; i--) {
+ p_lambda->function->parameters.write[i + captures_amount] = p_lambda->function->parameters[i];
+ p_lambda->function->parameters_indices[p_lambda->function->parameters[i]->identifier->name] = i + captures_amount;
+ }
+
+ // Add captures as extra parameters at the beginning.
+ for (int i = 0; i < p_lambda->captures.size(); i++) {
+ GDScriptParser::IdentifierNode *capture = p_lambda->captures[i];
+ GDScriptParser::ParameterNode *capture_param = parser->alloc_node<GDScriptParser::ParameterNode>();
+ capture_param->identifier = capture;
+ capture_param->usages = capture->usages;
+ capture_param->set_datatype(capture->get_datatype());
+
+ p_lambda->function->parameters.write[i] = capture_param;
+ p_lambda->function->parameters_indices[capture->name] = i;
+ }
+ }
+
+ lambda_stack.pop_back();
+ parser->current_function = previous_function;
+}
+
void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) {
p_literal->reduced_value = p_literal->value;
p_literal->is_constant = true;
@@ -2535,25 +2710,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
GDScriptParser::DataType result_type;
- // Reduce index first. If it's a constant StringName, use attribute instead.
- if (!p_subscript->is_attribute) {
- if (p_subscript->index == nullptr) {
- return;
- }
- reduce_expression(p_subscript->index);
-
- if (p_subscript->index->is_constant && p_subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
- GDScriptParser::IdentifierNode *attribute = parser->alloc_node<GDScriptParser::IdentifierNode>();
- // Copy location for better error message.
- attribute->start_line = p_subscript->index->start_line;
- attribute->end_line = p_subscript->index->end_line;
- attribute->leftmost_column = p_subscript->index->leftmost_column;
- attribute->rightmost_column = p_subscript->index->rightmost_column;
- p_subscript->is_attribute = true;
- p_subscript->attribute = attribute;
- }
- }
-
if (p_subscript->is_attribute) {
if (p_subscript->attribute == nullptr) {
return;
@@ -2596,7 +2752,10 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
}
}
} else {
- // Index was already reduced before.
+ if (p_subscript->index == nullptr) {
+ return;
+ }
+ reduce_expression(p_subscript->index);
if (p_subscript->base->is_constant && p_subscript->index->is_constant) {
// Just try to get it.
@@ -2752,11 +2911,20 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::TRANSFORM:
case Variant::PLANE:
case Variant::COLOR:
- case Variant::ARRAY:
case Variant::DICTIONARY:
result_type.kind = GDScriptParser::DataType::VARIANT;
result_type.type_source = GDScriptParser::DataType::UNDETECTED;
break;
+ // Can have an element type.
+ case Variant::ARRAY:
+ if (base_type.has_container_element_type()) {
+ result_type = base_type.get_container_element_type();
+ result_type.type_source = base_type.type_source;
+ } else {
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ result_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ }
+ break;
// Here for completeness.
case Variant::OBJECT:
case Variant::VARIANT_MAX:
@@ -2979,6 +3147,34 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
result.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name;
} else {
result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = p_property.type;
+ if (p_property.type == Variant::ARRAY && p_property.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ // Check element type.
+ StringName elem_type_name = p_property.hint_string;
+ GDScriptParser::DataType elem_type;
+ elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+
+ Variant::Type elem_builtin_type = GDScriptParser::get_builtin_type(elem_type_name);
+ if (elem_builtin_type < Variant::VARIANT_MAX) {
+ // Builtin type.
+ elem_type.kind = GDScriptParser::DataType::BUILTIN;
+ elem_type.builtin_type = elem_builtin_type;
+ } else if (class_exists(elem_type_name)) {
+ elem_type.kind = GDScriptParser::DataType::NATIVE;
+ elem_type.builtin_type = Variant::OBJECT;
+ elem_type.native_type = p_property.hint_string;
+ } else if (ScriptServer::is_global_class(elem_type_name)) {
+ // Just load this as it shouldn't be a GDScript.
+ Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(elem_type_name));
+ elem_type.kind = GDScriptParser::DataType::SCRIPT;
+ elem_type.builtin_type = Variant::OBJECT;
+ elem_type.native_type = script->get_instance_base_type();
+ elem_type.script_type = script;
+ } else {
+ ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array.");
+ }
+ result.set_container_element_type(elem_type);
+ }
}
return result;
}
@@ -3084,7 +3280,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
return true;
}
- StringName real_native = get_real_class_name(base_native);
+ StringName real_native = GDScriptParser::get_real_class_name(base_native);
MethodInfo info;
if (ClassDB::get_method_info(real_native, function_name, &info)) {
@@ -3179,7 +3375,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
StringName parent = base_native;
while (parent != StringName()) {
- StringName real_class_name = get_real_class_name(parent);
+ StringName real_class_name = GDScriptParser::get_real_class_name(parent);
if (ClassDB::has_method(real_class_name, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
@@ -3257,6 +3453,18 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
// Enum value is also integer.
valid = true;
}
+ if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) {
+ // Check the element type.
+ if (p_target.has_container_element_type()) {
+ if (!p_source.has_container_element_type()) {
+ // TODO: Maybe this is valid but unsafe?
+ // Variant array can't be appended to typed array.
+ valid = false;
+ } else {
+ valid = is_type_compatible(p_target.get_container_element_type(), p_source.get_container_element_type(), false);
+ }
+ }
+ }
return valid;
}
@@ -3329,14 +3537,14 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
}
// Get underscore-prefixed version for some classes.
- src_native = get_real_class_name(src_native);
+ src_native = GDScriptParser::get_real_class_name(src_native);
switch (p_target.kind) {
case GDScriptParser::DataType::NATIVE: {
if (p_target.is_meta_type) {
return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static());
}
- StringName tgt_native = get_real_class_name(p_target.native_type);
+ StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type);
return ClassDB::is_parent_class(src_native, tgt_native);
}
case GDScriptParser::DataType::SCRIPT:
@@ -3385,8 +3593,8 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#endif
}
-bool GDScriptAnalyzer::class_exists(const StringName &p_class) {
- StringName real_name = get_real_class_name(p_class);
+bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
+ StringName real_name = GDScriptParser::get_real_class_name(p_class);
return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name);
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index dab5b032a3..aabf407c76 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -42,6 +42,7 @@ class GDScriptAnalyzer {
HashMap<String, Ref<GDScriptParserRef>> depended_parsers;
const GDScriptParser::EnumNode *current_enum = nullptr;
+ List<const GDScriptParser::LambdaNode *> lambda_stack;
Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true);
GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type);
@@ -82,6 +83,7 @@ class GDScriptAnalyzer {
void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node);
void reduce_identifier(GDScriptParser::IdentifierNode *p_identifier, bool can_be_builtin = false);
void reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base = nullptr);
+ void reduce_lambda(GDScriptParser::LambdaNode *p_lambda);
void reduce_literal(GDScriptParser::LiteralNode *p_literal);
void reduce_preload(GDScriptParser::PreloadNode *p_preload);
void reduce_self(GDScriptParser::SelfNode *p_self);
@@ -103,10 +105,11 @@ class GDScriptAnalyzer {
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
+ void update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const;
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
- bool class_exists(const StringName &p_class);
+ bool class_exists(const StringName &p_class) const;
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
#ifdef DEBUG_ENABLED
bool is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context);
@@ -119,8 +122,6 @@ public:
Error analyze();
GDScriptAnalyzer(GDScriptParser *p_parser);
-
- static void cleanup();
};
#endif // GDSCRIPT_ANALYZER_H
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 58c6b31a77..0da99ccee3 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -47,7 +47,8 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool
}
uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) {
- int stack_pos = increase_stack();
+ int stack_pos = locals.size() + RESERVED_STACK;
+ locals.push_back(StackSlot(p_type.builtin_type));
add_stack_identifier(p_name, stack_pos);
return stack_pos;
}
@@ -59,37 +60,94 @@ uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name,
}
uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {
- if (constant_map.has(p_constant)) {
- return constant_map[p_constant];
- }
- int index = constant_map.size();
- constant_map[p_constant] = index;
- return index;
+ return get_constant_pos(p_constant);
}
uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
return get_name_map_pos(p_name);
}
-uint32_t GDScriptByteCodeGenerator::add_temporary() {
- current_temporaries++;
- int idx = increase_stack();
-#ifdef DEBUG_ENABLED
- temp_stack.push_back(idx);
-#endif
- return idx;
+uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) {
+ Variant::Type temp_type = Variant::NIL;
+ if (p_type.has_type) {
+ if (p_type.kind == GDScriptDataType::BUILTIN) {
+ switch (p_type.builtin_type) {
+ case Variant::NIL:
+ case Variant::BOOL:
+ case Variant::INT:
+ case Variant::FLOAT:
+ case Variant::STRING:
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I:
+ case Variant::RECT2:
+ case Variant::RECT2I:
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I:
+ case Variant::TRANSFORM2D:
+ case Variant::PLANE:
+ case Variant::QUAT:
+ case Variant::AABB:
+ case Variant::BASIS:
+ case Variant::TRANSFORM:
+ case Variant::COLOR:
+ case Variant::STRING_NAME:
+ case Variant::NODE_PATH:
+ case Variant::RID:
+ case Variant::OBJECT:
+ case Variant::CALLABLE:
+ case Variant::SIGNAL:
+ case Variant::DICTIONARY:
+ case Variant::ARRAY:
+ temp_type = p_type.builtin_type;
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ case Variant::VARIANT_MAX:
+ // Packed arrays are reference counted, so we don't use the pool for them.
+ temp_type = Variant::NIL;
+ break;
+ }
+ } else {
+ temp_type = Variant::OBJECT;
+ }
+ }
+
+ if (!temporaries_pool.has(temp_type)) {
+ temporaries_pool[temp_type] = List<int>();
+ }
+
+ List<int> &pool = temporaries_pool[temp_type];
+ if (pool.is_empty()) {
+ StackSlot new_temp(temp_type);
+ int idx = temporaries.size();
+ pool.push_back(idx);
+ temporaries.push_back(new_temp);
+
+ // First time using this, so adjust to the proper type.
+ if (temp_type != Variant::NIL) {
+ Address addr(Address::TEMPORARY, idx, p_type);
+ write_type_adjust(addr, temp_type);
+ }
+ }
+ int slot = pool.front()->get();
+ pool.pop_front();
+ used_temporaries.push_back(slot);
+ return slot;
}
void GDScriptByteCodeGenerator::pop_temporary() {
- ERR_FAIL_COND(current_temporaries == 0);
- current_stack_size--;
-#ifdef DEBUG_ENABLED
- if (temp_stack.back()->get() != current_stack_size) {
- ERR_PRINT("Mismatched popping of temporary value");
- }
- temp_stack.pop_back();
-#endif
- current_temporaries--;
+ ERR_FAIL_COND(used_temporaries.is_empty());
+ int slot_idx = used_temporaries.back()->get();
+ const StackSlot &slot = temporaries[slot_idx];
+ temporaries_pool[slot.type].push_back(slot_idx);
+ used_temporaries.pop_back();
}
void GDScriptByteCodeGenerator::start_parameters() {
@@ -100,7 +158,7 @@ void GDScriptByteCodeGenerator::start_parameters() {
}
void GDScriptByteCodeGenerator::end_parameters() {
- function->default_arguments.invert();
+ function->default_arguments.reverse();
}
void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) {
@@ -124,12 +182,18 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName
GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
#ifdef DEBUG_ENABLED
- if (current_temporaries != 0) {
- ERR_PRINT("Non-zero temporary variables at end of function: " + itos(current_temporaries));
+ if (!used_temporaries.is_empty()) {
+ ERR_PRINT("Non-zero temporary variables at end of function: " + itos(used_temporaries.size()));
}
#endif
append(GDScriptFunction::OPCODE_END, 0);
+ for (int i = 0; i < temporaries.size(); i++) {
+ for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) {
+ opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ }
+ }
+
if (constant_map.size()) {
function->_constant_count = constant_map.size();
function->constants.resize(constant_map.size());
@@ -319,10 +383,22 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_methods_count = 0;
}
+ if (lambdas_map.size()) {
+ function->lambdas.resize(lambdas_map.size());
+ function->_lambdas_ptr = function->lambdas.ptrw();
+ function->_lambdas_count = lambdas_map.size();
+ for (const Map<GDScriptFunction *, int>::Element *E = lambdas_map.front(); E; E = E->next()) {
+ function->lambdas.write[E->get()] = E->key();
+ }
+ } else {
+ function->_lambdas_ptr = nullptr;
+ function->_lambdas_count = 0;
+ }
+
if (debug_stack) {
function->stack_debug = stack_debug;
}
- function->_stack_size = stack_max;
+ function->_stack_size = RESERVED_STACK + max_locals + temporaries.size();
function->_instruction_args_size = instr_args_max;
function->_ptrcall_args_size = ptrcall_max;
@@ -346,6 +422,117 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
#define IS_BUILTIN_TYPE(m_var, m_type) \
(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type)
+void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Variant::Type p_new_type) {
+ switch (p_new_type) {
+ case Variant::BOOL:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_BOOL, 1);
+ break;
+ case Variant::INT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_INT, 1);
+ break;
+ case Variant::FLOAT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_FLOAT, 1);
+ break;
+ case Variant::STRING:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING, 1);
+ break;
+ case Variant::VECTOR2:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2, 1);
+ break;
+ case Variant::VECTOR2I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2I, 1);
+ break;
+ case Variant::RECT2:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2, 1);
+ break;
+ case Variant::RECT2I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2I, 1);
+ break;
+ case Variant::VECTOR3:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3, 1);
+ break;
+ case Variant::VECTOR3I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I, 1);
+ break;
+ case Variant::TRANSFORM2D:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM2D, 1);
+ break;
+ case Variant::PLANE:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE, 1);
+ break;
+ case Variant::QUAT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUAT, 1);
+ break;
+ case Variant::AABB:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB, 1);
+ break;
+ case Variant::BASIS:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1);
+ break;
+ case Variant::TRANSFORM:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1);
+ break;
+ case Variant::COLOR:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1);
+ break;
+ case Variant::STRING_NAME:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING_NAME, 1);
+ break;
+ case Variant::NODE_PATH:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_NODE_PATH, 1);
+ break;
+ case Variant::RID:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RID, 1);
+ break;
+ case Variant::OBJECT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_OBJECT, 1);
+ break;
+ case Variant::CALLABLE:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_CALLABLE, 1);
+ break;
+ case Variant::SIGNAL:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_SIGNAL, 1);
+ break;
+ case Variant::DICTIONARY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_DICTIONARY, 1);
+ break;
+ case Variant::ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_ARRAY, 1);
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, 1);
+ break;
+ case Variant::PACKED_INT32_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, 1);
+ break;
+ case Variant::PACKED_INT64_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, 1);
+ break;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, 1);
+ break;
+ case Variant::PACKED_FLOAT64_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, 1);
+ break;
+ case Variant::PACKED_STRING_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, 1);
+ break;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, 1);
+ break;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, 1);
+ break;
+ case Variant::PACKED_COLOR_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, 1);
+ break;
+ case Variant::NIL:
+ case Variant::VARIANT_MAX:
+ return;
+ }
+ append(p_target);
+}
+
void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {
if (HAS_BUILTIN_TYPE(p_left_operand)) {
// Gather specific operator.
@@ -396,7 +583,7 @@ void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const A
}
void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) {
- append(GDScriptFunction::OPCODE_IS_BUILTIN, 3);
+ append(GDScriptFunction::OPCODE_IS_BUILTIN, 2);
append(p_source);
append(p_target);
append(p_type);
@@ -599,14 +786,21 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
// Typed assignment.
switch (p_target.type.kind) {
case GDScriptDataType::BUILTIN: {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
- append(p_target);
- append(p_source);
- append(p_target.type.builtin_type);
+ if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ append(p_target);
+ append(p_source);
+ } else {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
+ append(p_target);
+ append(p_source);
+ append(p_target.type.builtin_type);
+ }
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+ class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
append(p_target);
append(p_source);
@@ -615,8 +809,7 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_target.type.script_type;
- int idx = get_constant_pos(script);
- idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
append(p_target);
@@ -633,7 +826,11 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
}
}
} else {
- if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
+ if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ append(p_target);
+ append(p_source);
+ } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
// Need conversion..
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
append(p_target);
@@ -663,6 +860,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_
function->default_arguments.push_back(opcodes.size());
}
+void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {
+ append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1);
+ append(p_dst);
+ append(p_global);
+}
+
void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
int index = 0;
@@ -673,16 +876,14 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3);
- index = class_idx;
+ index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
} break;
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_type.script_type;
- int idx = get_constant_pos(script);
- idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
-
+ int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3);
index = idx;
} break;
@@ -797,6 +998,14 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target,
return;
}
+ if (p_target.mode == Address::TEMPORARY) {
+ Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);
+ Variant::Type temp_type = temporaries[p_target.address].type;
+ if (result_type != temp_type) {
+ write_type_adjust(p_target, result_type);
+ }
+ }
+
append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -893,7 +1102,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
- append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
append(p_target);
append(p_arguments.size());
append(p_function_name);
@@ -904,7 +1113,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
- append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::ADDR_SELF);
append(p_target);
append(p_arguments.size());
append(p_function_name);
@@ -921,6 +1130,17 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ
append(p_function_name);
}
+void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) {
+ append(GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
+ for (int i = 0; i < p_captures.size(); i++) {
+ append(p_captures[i]);
+ }
+
+ append(p_target);
+ append(p_captures.size());
+ append(p_function);
+}
+
void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {
// Try to find an appropriate constructor.
bool all_have_type = true;
@@ -980,6 +1200,25 @@ void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, c
append(p_arguments.size());
}
+void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ if (p_element_type.script_type) {
+ Variant script_type = Ref<Script>(p_element_type.script_type);
+ int addr = get_constant_pos(script_type);
+ addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS;
+ append(addr);
+ } else {
+ append(Address()); // null.
+ }
+ append(p_arguments.size());
+ append(p_element_type.builtin_type);
+ append(p_element_type.native_type);
+}
+
void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {
append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1257,8 +1496,84 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
}
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
- append(GDScriptFunction::OPCODE_RETURN, 1);
- append(p_return_value);
+ if (!function->return_type.has_type || p_return_value.type.has_type) {
+ // Either the function is untyped or the return value is also typed.
+
+ // If this is a typed function, then we need to check for potential conversions.
+ if (function->return_type.has_type) {
+ if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
+ // Typed array.
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
+ append(p_return_value);
+ append(script_idx);
+ append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
+ append(element_type.native_type);
+ } else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
+ // Add conversion.
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
+ append(p_return_value);
+ append(function->return_type.builtin_type);
+ } else {
+ // Just assign.
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ }
+ } else {
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ }
+ } else {
+ switch (function->return_type.kind) {
+ case GDScriptDataType::BUILTIN: {
+ if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script);
+ script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
+ append(p_return_value);
+ append(script_idx);
+ append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
+ append(element_type.native_type);
+ } else {
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
+ append(p_return_value);
+ append(function->return_type.builtin_type);
+ }
+ } break;
+ case GDScriptDataType::NATIVE: {
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
+ append(p_return_value);
+ int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+ class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+ append(class_idx);
+ } break;
+ case GDScriptDataType::GDSCRIPT:
+ case GDScriptDataType::SCRIPT: {
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
+ append(p_return_value);
+ append(script_idx);
+ } break;
+ default: {
+ ERR_PRINT("Compiler bug: unresolved return.");
+
+ // Shouldn't get here, but fail-safe to a regular return;
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ } break;
+ }
+ }
}
void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 1e66af269a..c060476f39 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -37,6 +37,17 @@
#include "gdscript_utility_functions.h"
class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
+ struct StackSlot {
+ Variant::Type type = Variant::NIL;
+ Vector<int> bytecode_indices;
+
+ StackSlot() = default;
+ StackSlot(Variant::Type p_type) :
+ type(p_type) {}
+ };
+
+ const static int RESERVED_STACK = 3; // For self, class, and nil.
+
bool ended = false;
GDScriptFunction *function = nullptr;
bool debug_stack = false;
@@ -47,15 +58,17 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<int> stack_identifiers_counts;
Map<StringName, int> local_constants;
+ Vector<StackSlot> locals;
+ Vector<StackSlot> temporaries;
+ List<int> used_temporaries;
+ Map<Variant::Type, List<int>> temporaries_pool;
+
List<GDScriptFunction::StackDebug> stack_debug;
List<Map<StringName, int>> block_identifier_stack;
Map<StringName, int> block_identifiers;
- int current_stack_size = 0;
- int current_temporaries = 0;
- int current_locals = 0;
+ int max_locals = 0;
int current_line = 0;
- int stack_max = 0;
int instr_args_max = 0;
int ptrcall_max = 0;
@@ -80,6 +93,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedUtilityFunction, int> utilities_map;
Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
Map<MethodBind *, int> method_bind_map;
+ Map<GDScriptFunction *, int> lambdas_map;
// Lists since these can be nested.
List<int> if_jmp_addrs;
@@ -102,7 +116,9 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<List<int>> match_continues_to_patch;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
- current_locals++;
+ if (locals.size() > max_locals) {
+ max_locals = locals.size();
+ }
stack_identifiers[p_id] = p_stackpos;
if (debug_stack) {
block_identifiers[p_id] = p_stackpos;
@@ -116,7 +132,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
void push_stack_identifiers() {
- stack_identifiers_counts.push_back(current_locals);
+ stack_identifiers_counts.push_back(locals.size());
stack_id_stack.push_back(stack_identifiers);
if (debug_stack) {
Map<StringName, int> block_ids(block_identifiers);
@@ -126,17 +142,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
void pop_stack_identifiers() {
- current_locals = stack_identifiers_counts.back()->get();
+ int current_locals = stack_identifiers_counts.back()->get();
stack_identifiers_counts.pop_back();
stack_identifiers = stack_id_stack.back()->get();
stack_id_stack.pop_back();
#ifdef DEBUG_ENABLED
- if (current_temporaries != 0) {
- ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries));
+ if (!used_temporaries.is_empty()) {
+ ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(used_temporaries.size()));
}
#endif
- current_stack_size = current_locals;
-
+ locals.resize(current_locals);
if (debug_stack) {
for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
GDScriptFunction::StackDebug sd;
@@ -163,64 +178,72 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
int get_constant_pos(const Variant &p_constant) {
- if (constant_map.has(p_constant))
+ if (constant_map.has(p_constant)) {
return constant_map[p_constant];
+ }
int pos = constant_map.size();
constant_map[p_constant] = pos;
return pos;
}
int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) {
- if (operator_func_map.has(p_operation))
+ if (operator_func_map.has(p_operation)) {
return operator_func_map[p_operation];
+ }
int pos = operator_func_map.size();
operator_func_map[p_operation] = pos;
return pos;
}
int get_setter_pos(const Variant::ValidatedSetter p_setter) {
- if (setters_map.has(p_setter))
+ if (setters_map.has(p_setter)) {
return setters_map[p_setter];
+ }
int pos = setters_map.size();
setters_map[p_setter] = pos;
return pos;
}
int get_getter_pos(const Variant::ValidatedGetter p_getter) {
- if (getters_map.has(p_getter))
+ if (getters_map.has(p_getter)) {
return getters_map[p_getter];
+ }
int pos = getters_map.size();
getters_map[p_getter] = pos;
return pos;
}
int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) {
- if (keyed_setters_map.has(p_keyed_setter))
+ if (keyed_setters_map.has(p_keyed_setter)) {
return keyed_setters_map[p_keyed_setter];
+ }
int pos = keyed_setters_map.size();
keyed_setters_map[p_keyed_setter] = pos;
return pos;
}
int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) {
- if (keyed_getters_map.has(p_keyed_getter))
+ if (keyed_getters_map.has(p_keyed_getter)) {
return keyed_getters_map[p_keyed_getter];
+ }
int pos = keyed_getters_map.size();
keyed_getters_map[p_keyed_getter] = pos;
return pos;
}
int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) {
- if (indexed_setters_map.has(p_indexed_setter))
+ if (indexed_setters_map.has(p_indexed_setter)) {
return indexed_setters_map[p_indexed_setter];
+ }
int pos = indexed_setters_map.size();
indexed_setters_map[p_indexed_setter] = pos;
return pos;
}
int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) {
- if (indexed_getters_map.has(p_indexed_getter))
+ if (indexed_getters_map.has(p_indexed_getter)) {
return indexed_getters_map[p_indexed_getter];
+ }
int pos = indexed_getters_map.size();
indexed_getters_map[p_indexed_getter] = pos;
return pos;
@@ -271,45 +294,39 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
- void alloc_stack(int p_level) {
- if (p_level >= stack_max)
- stack_max = p_level + 1;
- }
-
- int increase_stack() {
- int top = current_stack_size++;
- alloc_stack(current_stack_size);
- return top;
+ int get_lambda_function_pos(GDScriptFunction *p_lambda_function) {
+ if (lambdas_map.has(p_lambda_function)) {
+ return lambdas_map[p_lambda_function];
+ }
+ int pos = lambdas_map.size();
+ lambdas_map[p_lambda_function] = pos;
+ return pos;
}
void alloc_ptrcall(int p_params) {
- if (p_params >= ptrcall_max)
+ if (p_params >= ptrcall_max) {
ptrcall_max = p_params;
+ }
}
int address_of(const Address &p_address) {
switch (p_address.mode) {
case Address::SELF:
- return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_SELF;
case Address::CLASS:
- return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_CLASS;
case Address::MEMBER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
- case Address::CLASS_CONSTANT:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS);
- case Address::LOCAL_CONSTANT:
case Address::CONSTANT:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
case Address::LOCAL_VARIABLE:
- case Address::TEMPORARY:
case Address::FUNCTION_PARAMETER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- case Address::GLOBAL:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
- case Address::NAMED_GLOBAL:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
+ case Address::TEMPORARY:
+ temporaries.write[p_address.address].bytecode_indices.push_back(opcodes.size());
+ return -1;
case Address::NIL:
- return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_NIL;
}
return -1; // Unreachable.
}
@@ -379,6 +396,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_method_bind_pos(p_method));
}
+ void append(GDScriptFunction *p_lambda_function) {
+ opcodes.push_back(get_lambda_function_pos(p_lambda_function));
+ }
+
void patch_jump(int p_address) {
opcodes.write[p_address] = opcodes.size();
}
@@ -389,7 +410,7 @@ public:
virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override;
virtual uint32_t add_or_get_constant(const Variant &p_constant) override;
virtual uint32_t add_or_get_name(const StringName &p_name) override;
- virtual uint32_t add_temporary() override;
+ virtual uint32_t add_temporary(const GDScriptDataType &p_type) override;
virtual void pop_temporary() override;
virtual void start_parameters() override;
@@ -406,6 +427,7 @@ public:
#endif
virtual void set_initial_line(int p_line) override;
+ virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) override;
virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override;
virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override;
@@ -431,6 +453,7 @@ public:
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
+ virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
@@ -443,8 +466,10 @@ public:
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
+ virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) override;
virtual void write_await(const Address &p_target, const Address &p_operand) override;
virtual void write_if(const Address &p_condition) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index d72bd12033..ae9a8ede5e 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -45,13 +45,9 @@ public:
CLASS,
MEMBER,
CONSTANT,
- CLASS_CONSTANT,
- LOCAL_CONSTANT,
LOCAL_VARIABLE,
FUNCTION_PARAMETER,
TEMPORARY,
- GLOBAL,
- NAMED_GLOBAL,
NIL,
};
AddressMode mode = NIL;
@@ -75,7 +71,7 @@ public:
virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) = 0;
virtual uint32_t add_or_get_constant(const Variant &p_constant) = 0;
virtual uint32_t add_or_get_name(const StringName &p_name) = 0;
- virtual uint32_t add_temporary() = 0;
+ virtual uint32_t add_temporary(const GDScriptDataType &p_type) = 0;
virtual void pop_temporary() = 0;
virtual void start_parameters() = 0;
@@ -84,9 +80,6 @@ public:
virtual void start_block() = 0;
virtual void end_block() = 0;
- // virtual int get_max_stack_level() = 0;
- // virtual int get_max_function_arguments() = 0;
-
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0;
virtual GDScriptFunction *write_end() = 0;
@@ -95,9 +88,7 @@ public:
#endif
virtual void set_initial_line(int p_line) = 0;
- // virtual void alloc_stack(int p_level) = 0; // Is this needed?
- // virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions.
-
+ virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) = 0;
virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) = 0;
virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0;
@@ -123,6 +114,7 @@ public:
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
+ virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
@@ -135,12 +127,13 @@ public:
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
+ virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) = 0;
virtual void write_await(const Address &p_target, const Address &p_operand) = 0;
virtual void write_if(const Address &p_condition) = 0;
- // virtual void write_elseif(const Address &p_condition) = 0; This kind of makes things more difficult for no real benefit.
virtual void write_else() = 0;
virtual void write_endif() = 0;
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index b491440d4c..37ce8ae2cb 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -137,22 +137,22 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
}
} break;
+ case GDScriptParser::DataType::ENUM:
case GDScriptParser::DataType::ENUM_VALUE:
result.has_type = true;
result.kind = GDScriptDataType::BUILTIN;
result.builtin_type = Variant::INT;
break;
- case GDScriptParser::DataType::ENUM:
- result.has_type = true;
- result.kind = GDScriptDataType::BUILTIN;
- result.builtin_type = Variant::DICTIONARY;
- break;
case GDScriptParser::DataType::UNRESOLVED: {
ERR_PRINT("Parser bug: converting unresolved type.");
return GDScriptDataType();
}
}
+ if (p_datatype.has_container_element_type()) {
+ result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type()));
+ }
+
// Only hold strong reference to the script if it's not the owner of the
// element qualified with this type, to avoid cyclic references (leaks).
if (result.script_type && result.script_type == p_owner) {
@@ -255,36 +255,59 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
// Try class constants.
- GDScript *owner = codegen.script;
- while (owner) {
- GDScript *scr = owner;
- GDScriptNativeClass *nc = nullptr;
- while (scr) {
- if (scr->constants.has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here.
+ {
+ GDScript *owner = codegen.script;
+ while (owner) {
+ GDScript *scr = owner;
+ GDScriptNativeClass *nc = nullptr;
+ while (scr) {
+ if (scr->constants.has(identifier)) {
+ return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
+ }
+ if (scr->native.is_valid()) {
+ nc = scr->native.ptr();
+ }
+ scr = scr->_base;
}
- if (scr->native.is_valid()) {
- nc = scr->native.ptr();
+
+ // Class C++ integer constant.
+ if (nc) {
+ bool success = false;
+ int constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
+ if (success) {
+ return codegen.add_constant(constant);
+ }
}
- scr = scr->_base;
+
+ owner = owner->_owner;
}
+ }
- // Class C++ integer constant.
- if (nc) {
- bool success = false;
- int constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
- if (success) {
- return codegen.add_constant(constant);
+ // Try signals and methods (can be made callables).
+ {
+ if (codegen.class_node->members_indices.has(identifier)) {
+ const GDScriptParser::ClassNode::Member &member = codegen.class_node->members[codegen.class_node->members_indices[identifier]];
+ if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ // Get like it was a property.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
+ GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
+
+ gen->write_get_named(temp, identifier, self);
+ return temp;
}
}
- owner = owner->_owner;
- }
+ // Try in native base.
+ GDScript *scr = codegen.script;
+ GDScriptNativeClass *nc = nullptr;
+ while (scr) {
+ if (scr->native.is_valid()) {
+ nc = scr->native.ptr();
+ }
+ scr = scr->_base;
+ }
- // Try signals and methods (can be made callables);
- if (codegen.class_node->members_indices.has(identifier)) {
- const GDScriptParser::ClassNode::Member &member = codegen.class_node->members[codegen.class_node->members_indices[identifier]];
- if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
// Get like it was a property.
GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
@@ -296,7 +319,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type.
+ Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ return codegen.add_constant(global); // TODO: Get type.
}
// Try global classes.
@@ -324,7 +348,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
#ifdef TOOLS_ENABLED
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type.
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
+ gen->write_store_named_global(global, identifier);
+ return global;
}
#endif
@@ -353,10 +379,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
Vector<GDScriptCodeGenerator::Address> values;
// Create the result temporary first since it's the last to be killed.
- GDScriptDataType array_type;
- array_type.has_type = true;
- array_type.kind = GDScriptDataType::BUILTIN;
- array_type.builtin_type = Variant::ARRAY;
+ GDScriptDataType array_type = _gdtype_from_datatype(an->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type);
for (int i = 0; i < an->elements.size(); i++) {
@@ -367,7 +390,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
values.push_back(val);
}
- gen->write_construct_array(result, values);
+ if (array_type.has_container_element_type()) {
+ gen->write_construct_typed_array(result, array_type.get_container_element_type(), values);
+ } else {
+ gen->write_construct_array(result, values);
+ }
for (int i = 0; i < values.size(); i++) {
if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -400,8 +427,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
break;
case GDScriptParser::DictionaryNode::LUA_TABLE:
- // Lua-style: key is an identifier interpreted as string.
- String key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
+ // Lua-style: key is an identifier interpreted as StringName.
+ StringName key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
element = codegen.add_constant(key);
break;
}
@@ -653,9 +680,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
name = subscript->attribute->name;
named = true;
} else {
- if (subscript->index->type == GDScriptParser::Node::LITERAL && static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value.get_type() == Variant::STRING) {
+ if (subscript->index->is_constant && subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
// Also, somehow, named (speed up anyway).
- name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value;
+ name = subscript->index->reduced_value;
named = true;
} else {
// Regular indexing.
@@ -684,7 +711,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::UNARY_OPERATOR: {
const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype()));
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand);
if (r_error) {
@@ -702,7 +729,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::BINARY_OPERATOR: {
const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype()));
switch (binary->operation) {
case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: {
@@ -754,6 +781,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->pop_temporary();
}
}
+
+ if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} break;
default: {
GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
@@ -1060,6 +1091,34 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
} break;
+ case GDScriptParser::Node::LAMBDA: {
+ const GDScriptParser::LambdaNode *lambda = static_cast<const GDScriptParser::LambdaNode *>(p_expression);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(lambda->get_datatype()));
+
+ Vector<GDScriptCodeGenerator::Address> captures;
+ captures.resize(lambda->captures.size());
+ for (int i = 0; i < lambda->captures.size(); i++) {
+ captures.write[i] = _parse_expression(codegen, r_error, lambda->captures[i]);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ }
+
+ GDScriptFunction *function = _parse_function(r_error, codegen.script, codegen.class_node, lambda->function, false, true);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+
+ gen->write_lambda(result, function, captures);
+
+ for (int i = 0; i < captures.size(); i++) {
+ if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ }
+
+ return result;
+ } break;
default: {
ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code.
} break;
@@ -1153,7 +1212,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
codegen.generator->write_and_left_operand(result_addr);
// Check value equality.
- codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
+ codegen.generator->write_binary_operator(equality_test_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
codegen.generator->write_and_right_operand(equality_test_addr);
// AND both type and value equality.
@@ -1488,17 +1547,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.start_block();
// Evaluate the match expression.
- GDScriptCodeGenerator::Address value_local = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
- GDScriptCodeGenerator::Address value = _parse_expression(codegen, error, match->test);
+ GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
+ GDScriptCodeGenerator::Address value_expr = _parse_expression(codegen, error, match->test);
if (error) {
return error;
}
// Assign to local.
// TODO: This can be improved by passing the target to parse_expression().
- gen->write_assign(value_local, value);
+ gen->write_assign(value, value_expr);
- if (value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ if (value_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -1710,8 +1769,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s);
// Should be already in stack when the block began.
GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name];
+ GDScriptParser::DataType local_type = lv->get_datatype();
if (lv->initializer != nullptr) {
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (local_type.is_hard_type() && local_type.builtin_type == Variant::ARRAY) {
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else {
+ codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>());
+ }
+ }
GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer);
if (error) {
return error;
@@ -1720,6 +1788,14 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (lv->get_datatype().is_hard_type()) {
+ // Initialize with default for type.
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (local_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
} break;
case GDScriptParser::Node::CONSTANT: {
@@ -1756,8 +1832,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
return OK;
}
-Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
- Error error = OK;
+GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready, bool p_for_lambda) {
+ r_error = OK;
CodeGen codegen;
codegen.generator = memnew(GDScriptByteCodeGenerator);
@@ -1774,7 +1850,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return_type.builtin_type = Variant::NIL;
if (p_func) {
- func_name = p_func->identifier->name;
+ if (p_func->identifier) {
+ func_name = p_func->identifier->name;
+ } else {
+ func_name = "<anonymous lambda>";
+ }
is_static = p_func->is_static;
rpc_mode = p_func->rpc_mode;
return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
@@ -1805,11 +1885,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
}
// Parse initializer if applies.
- bool is_implicit_initializer = !p_for_ready && !p_func;
- bool is_initializer = p_func && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
- bool is_for_ready = p_for_ready || (p_func && String(p_func->identifier->name) == "_ready");
+ bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
+ bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
+ bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready");
- if (is_implicit_initializer || is_for_ready) {
+ if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) {
// Initialize class fields.
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
@@ -1821,21 +1901,41 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
continue;
}
+ GDScriptParser::DataType field_type = field->get_datatype();
+
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
if (field->initializer) {
// Emit proper line change.
codegen.generator->write_newline(field->initializer->start_line);
- GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true);
- if (error) {
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) {
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else {
+ codegen.generator->write_construct_array(dst_address, Vector<GDScriptCodeGenerator::Address>());
+ }
+ }
+ GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true);
+ if (r_error) {
memdelete(codegen.generator);
- return error;
+ return nullptr;
}
- GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
codegen.generator->write_assign(dst_address, src_address);
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (field->get_datatype().is_hard_type()) {
+ codegen.generator->write_newline(field->start_line);
+
+ // Initialize with default for type.
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (field_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
}
}
@@ -1846,10 +1946,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->start_parameters();
for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {
const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
- GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, error, parameter->default_value, true);
- if (error) {
+ GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true);
+ if (r_error) {
memdelete(codegen.generator);
- return error;
+ return nullptr;
}
GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
@@ -1860,10 +1960,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->end_parameters();
}
- Error err = _parse_block(codegen, p_func->body);
- if (err) {
+ r_error = _parse_block(codegen, p_func->body);
+ if (r_error) {
memdelete(codegen.generator);
- return err;
+ return nullptr;
}
}
@@ -1889,6 +1989,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
signature += "::" + String(func_name);
}
+ if (p_for_lambda) {
+ signature += "(lambda)";
+ }
+
codegen.generator->set_signature(signature);
}
#endif
@@ -1896,8 +2000,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (p_func) {
codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_func->start_line;
- p_script->doc_functions[func_name] = p_func->doc_description;
+ if (!p_for_lambda) {
+ p_script->member_lines[func_name] = p_func->start_line;
+ p_script->doc_functions[func_name] = p_func->doc_description;
+ }
#endif
} else {
codegen.generator->set_initial_line(0);
@@ -1926,11 +2032,13 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
#endif
}
- p_script->member_functions[func_name] = gd_function;
+ if (!p_for_lambda) {
+ p_script->member_functions[func_name] = gd_function;
+ }
memdelete(codegen.generator);
- return OK;
+ return gd_function;
}
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
@@ -1949,6 +2057,8 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
func_name = "@" + p_variable->identifier->name + "_getter";
}
+ codegen.function_name = func_name;
+
GDScriptDataType return_type;
if (p_is_setter) {
return_type.has_type = true;
@@ -2153,9 +2263,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
prop_info.usage = export_info.usage;
- } else {
- prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
+ prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
#ifdef TOOLS_ENABLED
p_script->doc_variables[name] = variable->doc_description;
#endif
@@ -2322,7 +2431,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && function->identifier->name == "_ready") {
has_ready = true;
}
- Error err = _parse_function(p_script, p_class, function);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, function);
if (err) {
return err;
}
@@ -2347,7 +2457,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
{
// Create an implicit constructor in any case.
- Error err = _parse_function(p_script, p_class, nullptr);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr);
if (err) {
return err;
}
@@ -2355,7 +2466,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && p_class->onready_used) {
//create a _ready constructor
- Error err = _parse_function(p_script, p_class, nullptr, true);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr, true);
if (err) {
return err;
}
@@ -2396,7 +2508,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
p_script->initializer->call(instance, nullptr, 0, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- //well, tough luck, not goinna do anything here
+ //well, tough luck, not gonna do anything here
}
}
#endif
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 651391f972..7d5bee93ac 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -61,12 +61,12 @@ class GDScriptCompiler {
GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) {
uint32_t addr = generator->add_local_constant(p_name, p_value);
- locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr);
+ locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr);
return locals[p_name];
}
GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) {
- uint32_t addr = generator->add_temporary();
+ uint32_t addr = generator->add_temporary(p_type);
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type);
}
@@ -128,7 +128,7 @@ class GDScriptCompiler {
GDScriptCodeGenerator::Address _parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested);
void _add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block);
Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals = true);
- Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
+ GDScriptFunction *_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false, bool p_for_lambda = false);
Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter);
Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 17cb5e3c96..789af57b4c 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -69,35 +69,23 @@ static String _disassemble_address(const GDScript *p_script, const GDScriptFunct
int addr = p_address & GDScriptFunction::ADDR_MASK;
switch (p_address >> GDScriptFunction::ADDR_BITS) {
- case GDScriptFunction::ADDR_TYPE_SELF: {
- return "self";
- } break;
- case GDScriptFunction::ADDR_TYPE_CLASS: {
- return "class";
- } break;
case GDScriptFunction::ADDR_TYPE_MEMBER: {
return "member(" + p_script->debug_get_member_by_index(addr) + ")";
} break;
- case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
- return "class_const(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+ case GDScriptFunction::ADDR_TYPE_CONSTANT: {
return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_STACK: {
- return "stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
- return "var_stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_GLOBAL: {
- return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
- return "named_global(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NIL: {
- return "nil";
+ switch (addr) {
+ case GDScriptFunction::ADDR_STACK_SELF:
+ return "self";
+ case GDScriptFunction::ADDR_STACK_CLASS:
+ return "class";
+ case GDScriptFunction::ADDR_STACK_NIL:
+ return "nil";
+ default:
+ return "stack(" + itos(addr) + ")";
+ }
} break;
}
@@ -322,6 +310,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 4;
} break;
+ case OPCODE_ASSIGN_TYPED_ARRAY: {
+ text += "assign typed array ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 3;
+ } break;
case OPCODE_ASSIGN_TYPED_NATIVE: {
text += "assign typed native (";
text += DADDR(3);
@@ -385,8 +381,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += Variant::get_type_name(t) + "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(i + 1);
}
text += ")";
@@ -402,8 +399,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "<unkown type>(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(i + 1);
}
text += ")";
@@ -417,8 +415,43 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += " = [";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+
+ text += "]";
+
+ incr += 3 + argc;
+ } break;
+ case OPCODE_CONSTRUCT_TYPED_ARRAY: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ Ref<Script> script_type = get_constant(_code_ptr[ip + argc + 2]);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + argc + 4];
+ StringName native_type = get_global_name(_code_ptr[ip + argc + 5]);
+
+ String type_name;
+ if (script_type.is_valid() && script_type->is_valid()) {
+ type_name = script_type->get_path();
+ } else if (native_type != StringName()) {
+ type_name = native_type;
+ } else {
+ type_name = Variant::get_type_name(builtin_type);
+ }
+
+ text += " make_typed_array (";
+ text += type_name;
+ text += ") ";
+
+ text += DADDR(1 + argc);
+ text += " = [";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
text += DADDR(1 + i);
}
@@ -433,8 +466,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += " = {";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i * 2 + 0);
text += ": ";
text += DADDR(1 + i * 2 + 1);
@@ -468,8 +502,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -498,8 +533,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -518,8 +554,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -595,8 +632,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -613,8 +651,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -631,8 +670,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -649,8 +689,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -667,8 +708,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -679,7 +721,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "await ";
text += DADDR(1);
- incr += 2;
+ incr = 2;
} break;
case OPCODE_AWAIT_RESUME: {
text += "await resume ";
@@ -687,6 +729,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 2;
} break;
+ case OPCODE_CREATE_LAMBDA: {
+ int captures_count = _code_ptr[ip + 1 + instr_var_args];
+ GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ text += DADDR(1 + captures_count);
+ text += "create lambda from ";
+ text += lambda->name.operator String();
+ text += "function, captures (";
+
+ for (int i = 0; i < captures_count; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 3 + captures_count;
+ } break;
case OPCODE_JUMP: {
text += "jump ";
text += itos(_code_ptr[ip + 1]);
@@ -720,6 +781,39 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 2;
} break;
+ case OPCODE_RETURN_TYPED_BUILTIN: {
+ text += "return typed builtin (";
+ text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 2]);
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
+ case OPCODE_RETURN_TYPED_ARRAY: {
+ text += "return typed array ";
+ text += DADDR(1);
+
+ incr += 5;
+ } break;
+ case OPCODE_RETURN_TYPED_NATIVE: {
+ text += "return typed native (";
+ text += DADDR(2);
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
+ case OPCODE_RETURN_TYPED_SCRIPT: {
+ Variant script = _constants_ptr[_code_ptr[ip + 2]];
+ Script *sc = Object::cast_to<Script>(script.operator Object *());
+
+ text += "return typed script (";
+ text += sc->get_path();
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
#define DISASSEMBLE_ITERATE(m_type) \
case OPCODE_ITERATE_##m_type: { \
@@ -798,6 +892,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
+ case OPCODE_STORE_NAMED_GLOBAL: {
+ text += "store named global ";
+ text += DADDR(1);
+ text += " = ";
+ text += String(_global_names_ptr[_code_ptr[ip + 2]]);
+
+ incr += 3;
+ } break;
case OPCODE_LINE: {
int line = _code_ptr[ip + 1] - 1;
if (line >= 0 && line < p_code_lines.size()) {
@@ -811,6 +913,51 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 2;
} break;
+
+#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \
+ case OPCODE_TYPE_ADJUST_##m_v_type: { \
+ text += "type adjust ("; \
+ text += #m_v_type; \
+ text += ") "; \
+ text += DADDR(1); \
+ incr += 2; \
+ } break
+
+ DISASSEMBLE_TYPE_ADJUST(BOOL);
+ DISASSEMBLE_TYPE_ADJUST(INT);
+ DISASSEMBLE_TYPE_ADJUST(FLOAT);
+ DISASSEMBLE_TYPE_ADJUST(STRING);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR2);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR2I);
+ DISASSEMBLE_TYPE_ADJUST(RECT2);
+ DISASSEMBLE_TYPE_ADJUST(RECT2I);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR3);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR3I);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D);
+ DISASSEMBLE_TYPE_ADJUST(PLANE);
+ DISASSEMBLE_TYPE_ADJUST(QUAT);
+ DISASSEMBLE_TYPE_ADJUST(AABB);
+ DISASSEMBLE_TYPE_ADJUST(BASIS);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM);
+ DISASSEMBLE_TYPE_ADJUST(COLOR);
+ DISASSEMBLE_TYPE_ADJUST(STRING_NAME);
+ DISASSEMBLE_TYPE_ADJUST(NODE_PATH);
+ DISASSEMBLE_TYPE_ADJUST(RID);
+ DISASSEMBLE_TYPE_ADJUST(OBJECT);
+ DISASSEMBLE_TYPE_ADJUST(CALLABLE);
+ DISASSEMBLE_TYPE_ADJUST(SIGNAL);
+ DISASSEMBLE_TYPE_ADJUST(DICTIONARY);
+ DISASSEMBLE_TYPE_ADJUST(ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_BYTE_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_INT32_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_INT64_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_STRING_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY);
+
case OPCODE_ASSERT: {
text += "assert (";
text += DADDR(1);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index b17971cf93..f70020d165 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -500,36 +500,6 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
};
-// TODO: Move this to a central location (maybe core?).
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-static StringName _get_real_class_name(const StringName &p_source) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- if (p_source == *class_name) {
- return String("_") + p_source;
- }
- class_name++;
- }
- return p_source;
-}
-
static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) {
if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
String enum_name = p_info.class_name;
@@ -930,7 +900,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName type = _get_real_class_name(base_type.native_type);
+ StringName type = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(type)) {
return;
}
@@ -1067,7 +1037,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords[] = {
"false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
"break", "continue", "pass", "return",
- 0
+ nullptr
};
const char **kw = _keywords;
@@ -1080,7 +1050,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords_with_space[] = {
"and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await",
"const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
- 0
+ nullptr
};
const char **kws = _keywords_with_space;
@@ -1093,7 +1063,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords_with_args[] = {
"assert", "preload",
- 0
+ nullptr
};
const char **kwa = _keywords_with_args;
@@ -1775,15 +1745,15 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
return true;
}
}
- base_type = base_type.class_type->base_type;
}
+ base_type = base_type.class_type->base_type;
break;
case GDScriptParser::DataType::NATIVE: {
if (id_type.is_set() && !id_type.is_variant()) {
base_type = GDScriptParser::DataType();
break;
}
- StringName real_native = _get_real_class_name(base_type.native_type);
+ StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type);
MethodInfo info;
if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) {
for (const List<PropertyInfo>::Element *E = info.arguments.front(); E; E = E->next()) {
@@ -1854,7 +1824,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
// Check ClassDB.
- StringName class_name = _get_real_class_name(p_identifier);
+ StringName class_name = GDScriptParser::get_real_class_name(p_identifier);
if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.kind = GDScriptParser::DataType::NATIVE;
@@ -1970,7 +1940,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
return false;
}
@@ -2133,7 +2103,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName native = _get_real_class_name(base_type.native_type);
+ StringName native = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(native)) {
return false;
}
@@ -2230,7 +2200,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2261,10 +2231,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
r_arghint = _make_arguments_hint(info, p_argidx);
- return;
}
- if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) {
+ if (p_argidx == 0 && ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node")) {
// Get autoloads
List<PropertyInfo> props;
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -2616,7 +2585,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
break;
}
- StringName class_name = _get_real_class_name(native_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type);
if (!ClassDB::class_exists(class_name)) {
break;
}
@@ -2845,7 +2814,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2923,7 +2892,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
v = v_ref;
} else {
Callable::CallError err;
- Variant::construct(base_type.builtin_type, v, NULL, 0, err);
+ Variant::construct(base_type.builtin_type, v, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
break;
}
@@ -3101,7 +3070,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
// We cannot determine the exact nature of the identifier here
// Otherwise these codes would work
StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true);
- if (enumName != NULL) {
+ if (enumName != nullptr) {
r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM;
r_result.class_name = "@GlobalScope";
r_result.class_member = enumName;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index c6c9a439df..78399114a5 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -150,6 +150,10 @@ GDScriptFunction::GDScriptFunction() {
}
GDScriptFunction::~GDScriptFunction() {
+ for (int i = 0; i < lambdas.size(); i++) {
+ memdelete(lambdas[i]);
+ }
+
#ifdef DEBUG_ENABLED
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
@@ -244,7 +248,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
bool completed = true;
// If the return value is a GDScriptFunctionState reference,
- // then the function did awaited again after resuming.
+ // then the function did await again after resuming.
if (ret.is_ref()) {
GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret);
if (gdfs && gdfs->function == function) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index e64630a743..70b62ced6d 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -43,7 +43,11 @@
class GDScriptInstance;
class GDScript;
-struct GDScriptDataType {
+class GDScriptDataType {
+private:
+ GDScriptDataType *container_element_type = nullptr;
+
+public:
enum Kind {
UNINITIALIZED,
BUILTIN,
@@ -71,7 +75,24 @@ struct GDScriptDataType {
case BUILTIN: {
Variant::Type var_type = p_variant.get_type();
bool valid = builtin_type == var_type;
- if (!valid && p_allow_implicit_conversion) {
+ if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) {
+ Array array = p_variant;
+ if (array.is_typed()) {
+ Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin();
+ StringName array_native_type = array.get_typed_class_name();
+ Ref<Script> array_script_type_ref = array.get_typed_script();
+
+ if (array_script_type_ref.is_valid()) {
+ valid = (container_element_type->kind == SCRIPT || container_element_type->kind == GDSCRIPT) && container_element_type->script_type == array_script_type_ref.ptr();
+ } else if (array_native_type != StringName()) {
+ valid = container_element_type->kind == NATIVE && container_element_type->native_type == array_native_type;
+ } else {
+ valid = container_element_type->kind == BUILTIN && container_element_type->builtin_type == array_builtin_type;
+ }
+ } else {
+ valid = false;
+ }
+ } else if (!valid && p_allow_implicit_conversion) {
valid = Variant::can_convert_strict(var_type, builtin_type);
}
return valid;
@@ -153,7 +174,49 @@ struct GDScriptDataType {
return info;
}
- GDScriptDataType() {}
+ void set_container_element_type(const GDScriptDataType &p_element_type) {
+ container_element_type = memnew(GDScriptDataType(p_element_type));
+ }
+
+ GDScriptDataType get_container_element_type() const {
+ ERR_FAIL_COND_V(container_element_type == nullptr, GDScriptDataType());
+ return *container_element_type;
+ }
+
+ bool has_container_element_type() const {
+ return container_element_type != nullptr;
+ }
+
+ void unset_container_element_type() {
+ if (container_element_type) {
+ memdelete(container_element_type);
+ }
+ container_element_type = nullptr;
+ }
+
+ GDScriptDataType() = default;
+
+ GDScriptDataType &operator=(const GDScriptDataType &p_other) {
+ kind = p_other.kind;
+ has_type = p_other.has_type;
+ builtin_type = p_other.builtin_type;
+ native_type = p_other.native_type;
+ script_type = p_other.script_type;
+ script_type_ref = p_other.script_type_ref;
+ unset_container_element_type();
+ if (p_other.has_container_element_type()) {
+ set_container_element_type(p_other.get_container_element_type());
+ }
+ return *this;
+ }
+
+ GDScriptDataType(const GDScriptDataType &p_other) {
+ *this = p_other;
+ }
+
+ ~GDScriptDataType() {
+ unset_container_element_type();
+ }
};
class GDScriptFunction {
@@ -179,6 +242,7 @@ public:
OPCODE_ASSIGN_TRUE,
OPCODE_ASSIGN_FALSE,
OPCODE_ASSIGN_TYPED_BUILTIN,
+ OPCODE_ASSIGN_TYPED_ARRAY,
OPCODE_ASSIGN_TYPED_NATIVE,
OPCODE_ASSIGN_TYPED_SCRIPT,
OPCODE_CAST_TO_BUILTIN,
@@ -187,6 +251,7 @@ public:
OPCODE_CONSTRUCT, // Only for basic types!
OPCODE_CONSTRUCT_VALIDATED, // Only for basic types!
OPCODE_CONSTRUCT_ARRAY,
+ OPCODE_CONSTRUCT_TYPED_ARRAY,
OPCODE_CONSTRUCT_DICTIONARY,
OPCODE_CALL,
OPCODE_CALL_RETURN,
@@ -236,11 +301,16 @@ public:
OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
+ OPCODE_CREATE_LAMBDA,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
OPCODE_JUMP_TO_DEF_ARGUMENT,
OPCODE_RETURN,
+ OPCODE_RETURN_TYPED_BUILTIN,
+ OPCODE_RETURN_TYPED_ARRAY,
+ OPCODE_RETURN_TYPED_NATIVE,
+ OPCODE_RETURN_TYPED_SCRIPT,
OPCODE_ITERATE_BEGIN,
OPCODE_ITERATE_BEGIN_INT,
OPCODE_ITERATE_BEGIN_FLOAT,
@@ -281,6 +351,41 @@ public:
OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_OBJECT,
+ OPCODE_STORE_NAMED_GLOBAL,
+ OPCODE_TYPE_ADJUST_BOOL,
+ OPCODE_TYPE_ADJUST_INT,
+ OPCODE_TYPE_ADJUST_FLOAT,
+ OPCODE_TYPE_ADJUST_STRING,
+ OPCODE_TYPE_ADJUST_VECTOR2,
+ OPCODE_TYPE_ADJUST_VECTOR2I,
+ OPCODE_TYPE_ADJUST_RECT2,
+ OPCODE_TYPE_ADJUST_RECT2I,
+ OPCODE_TYPE_ADJUST_VECTOR3,
+ OPCODE_TYPE_ADJUST_VECTOR3I,
+ OPCODE_TYPE_ADJUST_TRANSFORM2D,
+ OPCODE_TYPE_ADJUST_PLANE,
+ OPCODE_TYPE_ADJUST_QUAT,
+ OPCODE_TYPE_ADJUST_AABB,
+ OPCODE_TYPE_ADJUST_BASIS,
+ OPCODE_TYPE_ADJUST_TRANSFORM,
+ OPCODE_TYPE_ADJUST_COLOR,
+ OPCODE_TYPE_ADJUST_STRING_NAME,
+ OPCODE_TYPE_ADJUST_NODE_PATH,
+ OPCODE_TYPE_ADJUST_RID,
+ OPCODE_TYPE_ADJUST_OBJECT,
+ OPCODE_TYPE_ADJUST_CALLABLE,
+ OPCODE_TYPE_ADJUST_SIGNAL,
+ OPCODE_TYPE_ADJUST_DICTIONARY,
+ OPCODE_TYPE_ADJUST_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY,
OPCODE_ASSERT,
OPCODE_BREAKPOINT,
OPCODE_LINE,
@@ -291,16 +396,18 @@ public:
ADDR_BITS = 24,
ADDR_MASK = ((1 << ADDR_BITS) - 1),
ADDR_TYPE_MASK = ~ADDR_MASK,
- ADDR_TYPE_SELF = 0,
- ADDR_TYPE_CLASS = 1,
+ ADDR_TYPE_STACK = 0,
+ ADDR_TYPE_CONSTANT = 1,
ADDR_TYPE_MEMBER = 2,
- ADDR_TYPE_CLASS_CONSTANT = 3,
- ADDR_TYPE_LOCAL_CONSTANT = 4,
- ADDR_TYPE_STACK = 5,
- ADDR_TYPE_STACK_VARIABLE = 6,
- ADDR_TYPE_GLOBAL = 7,
- ADDR_TYPE_NAMED_GLOBAL = 8,
- ADDR_TYPE_NIL = 9
+ };
+
+ enum FixedAddresses {
+ ADDR_STACK_SELF = 0,
+ ADDR_STACK_CLASS = 1,
+ ADDR_STACK_NIL = 2,
+ ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS),
+ ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS),
+ ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS),
};
enum Instruction {
@@ -353,6 +460,8 @@ private:
const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
int _methods_count = 0;
MethodBind **_methods_ptr = nullptr;
+ int _lambdas_count = 0;
+ GDScriptFunction **_lambdas_ptr = nullptr;
const int *_code_ptr = nullptr;
int _code_size = 0;
int _argument_count = 0;
@@ -382,6 +491,7 @@ private:
Vector<Variant::ValidatedUtilityFunction> utilities;
Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
Vector<MethodBind *> methods;
+ Vector<GDScriptFunction *> lambdas;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
@@ -393,7 +503,7 @@ private:
List<StackDebug> stack_debug;
- _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const;
+ _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const;
_FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
friend class GDScriptLanguage;
@@ -428,7 +538,6 @@ public:
#endif
Vector<uint8_t> stack;
int stack_size = 0;
- Variant self;
uint32_t alloca_size = 0;
int ip = 0;
int line = 0;
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
new file mode 100644
index 0000000000..0bc109b6e1
--- /dev/null
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* gdscript_lambda_callable.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_lambda_callable.h"
+
+#include "core/templates/hashfuncs.h"
+#include "gdscript.h"
+
+bool GDScriptLambdaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a == p_b;
+}
+
+bool GDScriptLambdaCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a < p_b;
+}
+
+uint32_t GDScriptLambdaCallable::hash() const {
+ return h;
+}
+
+String GDScriptLambdaCallable::get_as_text() const {
+ if (function->get_name() != StringName()) {
+ return function->get_name().operator String() + "(lambda)";
+ }
+ return "(anonymous lambda)";
+}
+
+CallableCustom::CompareEqualFunc GDScriptLambdaCallable::get_compare_equal_func() const {
+ return compare_equal;
+}
+
+CallableCustom::CompareLessFunc GDScriptLambdaCallable::get_compare_less_func() const {
+ return compare_less;
+}
+
+ObjectID GDScriptLambdaCallable::get_object() const {
+ return script->get_instance_id();
+}
+
+void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ int captures_amount = captures.size();
+
+ if (captures_amount > 0) {
+ Vector<const Variant *> args;
+ args.resize(p_argcount + captures_amount);
+ for (int i = 0; i < captures_amount; i++) {
+ args.write[i] = &captures[i];
+ }
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i + captures_amount] = p_arguments[i];
+ }
+
+ r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
+ r_call_error.argument -= captures_amount;
+ } else {
+ r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error);
+ }
+}
+
+GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ script = p_script;
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
diff --git a/editor/import/resource_importer_csv.h b/modules/gdscript/gdscript_lambda_callable.h
index 0f137624b9..357c845250 100644
--- a/editor/import/resource_importer_csv.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* resource_importer_csv.h */
+/* gdscript_lambda_callable.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,30 +28,38 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RESOURCEIMPORTERCSV_H
-#define RESOURCEIMPORTERCSV_H
+#ifndef GDSCRIPT_LAMBDA_CALLABLE
+#define GDSCRIPT_LAMBDA_CALLABLE
-#include "core/io/resource_importer.h"
+#include "core/object/reference.h"
+#include "core/templates/vector.h"
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
-class ResourceImporterCSV : public ResourceImporter {
- GDCLASS(ResourceImporterCSV, ResourceImporter);
+class GDScript;
+class GDScriptFunction;
+class GDScriptInstance;
-public:
- virtual String get_importer_name() const override;
- virtual String get_visible_name() const override;
- virtual void get_recognized_extensions(List<String> *p_extensions) const override;
- virtual String get_save_extension() const override;
- virtual String get_resource_type() const override;
+class GDScriptLambdaCallable : public CallableCustom {
+ GDScriptFunction *function = nullptr;
+ Ref<GDScript> script;
+ uint32_t h;
- virtual int get_preset_count() const override;
- virtual String get_preset_name(int p_idx) const override;
+ Vector<Variant> captures;
- virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
- virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
- virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+public:
+ uint32_t hash() const override;
+ String get_as_text() const override;
+ CompareEqualFunc get_compare_equal_func() const override;
+ CompareLessFunc get_compare_less_func() const override;
+ ObjectID get_object() const override;
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- ResourceImporterCSV();
+ GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ virtual ~GDScriptLambdaCallable() = default;
};
-#endif // RESOURCEIMPORTERCSV_H
+#endif // GDSCRIPT_LAMBDA_CALLABLE
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a77fb14064..f9027c3a87 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -94,8 +94,43 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX;
}
+// TODO: Move this to a central location (maybe core?).
+static HashMap<StringName, StringName> underscore_map;
+static const char *underscore_classes[] = {
+ "ClassDB",
+ "Directory",
+ "Engine",
+ "File",
+ "Geometry",
+ "GodotSharp",
+ "JSON",
+ "Marshalls",
+ "Mutex",
+ "OS",
+ "ResourceLoader",
+ "ResourceSaver",
+ "Semaphore",
+ "Thread",
+ "VisualScriptEditor",
+ nullptr,
+};
+StringName GDScriptParser::get_real_class_name(const StringName &p_source) {
+ if (underscore_map.is_empty()) {
+ const char **class_name = underscore_classes;
+ while (*class_name != nullptr) {
+ underscore_map[*class_name] = String("_") + *class_name;
+ class_name++;
+ }
+ }
+ if (underscore_map.has(p_source)) {
+ return underscore_map[p_source];
+ }
+ return p_source;
+}
+
void GDScriptParser::cleanup() {
builtin_types.clear();
+ underscore_map.clear();
}
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
@@ -109,12 +144,11 @@ void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const
GDScriptParser::GDScriptParser() {
// Register valid annotations.
// TODO: Should this be static?
- // TODO: Validate applicable types (e.g. a VARIABLE annotation that only applies to string variables).
register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation);
register_annotation(MethodInfo("@icon", { Variant::STRING, "icon_path" }), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation);
register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
// Export annotations.
- register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_TYPE_STRING, Variant::NIL>);
+ register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
register_annotation(MethodInfo("@export_enum", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true);
register_annotation(MethodInfo("@export_file", { Variant::STRING, "filter" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true);
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
@@ -130,8 +164,10 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, 0, true);
register_annotation(MethodInfo("@export_flags_2d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_RENDER, Variant::INT>);
register_annotation(MethodInfo("@export_flags_2d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_PHYSICS, Variant::INT>);
+ register_annotation(MethodInfo("@export_flags_2d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_NAVIGATION, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
+ register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
// Networking.
register_annotation(MethodInfo("@remote"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_REMOTE>);
register_annotation(MethodInfo("@master"), AnnotationInfo::VARIABLE | AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>);
@@ -366,6 +402,8 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
}
GDScriptTokenizer::Token GDScriptParser::advance() {
+ lambda_ended = false; // Empty marker since we're past the end in any case.
+
if (current.type == GDScriptTokenizer::Token::TK_EOF) {
ERR_FAIL_COND_V_MSG(current.type == GDScriptTokenizer::Token::TK_EOF, current, "GDScript parser bug: Trying to advance past the end of stream.");
}
@@ -392,7 +430,7 @@ bool GDScriptParser::match(GDScriptTokenizer::Token::Type p_token_type) {
return true;
}
-bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) {
+bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) const {
if (p_token_type == GDScriptTokenizer::Token::IDENTIFIER) {
return current.is_identifier();
}
@@ -407,7 +445,7 @@ bool GDScriptParser::consume(GDScriptTokenizer::Token::Type p_token_type, const
return false;
}
-bool GDScriptParser::is_at_end() {
+bool GDScriptParser::is_at_end() const {
return check(GDScriptTokenizer::Token::TK_EOF);
}
@@ -458,16 +496,34 @@ void GDScriptParser::pop_multiline() {
tokenizer.set_multiline_mode(multiline_stack.size() > 0 ? multiline_stack.back()->get() : false);
}
-bool GDScriptParser::is_statement_end() {
+bool GDScriptParser::is_statement_end_token() const {
return check(GDScriptTokenizer::Token::NEWLINE) || check(GDScriptTokenizer::Token::SEMICOLON) || check(GDScriptTokenizer::Token::TK_EOF);
}
+bool GDScriptParser::is_statement_end() const {
+ return lambda_ended || in_lambda || is_statement_end_token();
+}
+
void GDScriptParser::end_statement(const String &p_context) {
bool found = false;
while (is_statement_end() && !is_at_end()) {
// Remove sequential newlines/semicolons.
+ if (is_statement_end_token()) {
+ // Only consume if this is an actual token.
+ advance();
+ } else if (lambda_ended) {
+ lambda_ended = false; // Consume this "token".
+ found = true;
+ break;
+ } else {
+ if (!found) {
+ lambda_ended = true; // Mark the lambda as done since we found something else to end the statement.
+ found = true;
+ }
+ break;
+ }
+
found = true;
- advance();
}
if (!found && !is_at_end()) {
push_error(vformat(R"(Expected end of statement after %s, found "%s" instead.)", p_context, current.get_name()));
@@ -678,7 +734,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
- last_annotation->apply(this, member);
member->annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
@@ -776,6 +831,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
VariableNode *variable = alloc_node<VariableNode>();
variable->identifier = parse_identifier();
+ variable->export_info.name = variable->identifier->name;
if (match(GDScriptTokenizer::Token::COLON)) {
if (check(GDScriptTokenizer::Token::NEWLINE)) {
@@ -809,6 +865,9 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
if (match(GDScriptTokenizer::Token::EQUAL)) {
// Initializer.
variable->initializer = parse_expression(false);
+ if (variable->initializer == nullptr) {
+ push_error(R"(Expected expression for variable initial value after "=".)");
+ }
variable->assignments++;
}
@@ -822,8 +881,6 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
end_statement("variable declaration");
- variable->export_info.name = variable->identifier->name;
-
return variable;
}
@@ -1145,36 +1202,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
return enum_node;
}
-GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
- bool _static = false;
- if (previous.type == GDScriptTokenizer::Token::STATIC) {
- // TODO: Improve message if user uses "static" with "var" or "const"
- if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) {
- return nullptr;
- }
- _static = true;
- }
-
- FunctionNode *function = alloc_node<FunctionNode>();
- make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
-
- if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
- return nullptr;
- }
-
- FunctionNode *previous_function = current_function;
- current_function = function;
-
- function->identifier = parse_identifier();
- function->is_static = _static;
-
- push_multiline(true);
- consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
-
- SuiteNode *body = alloc_node<SuiteNode>();
- SuiteNode *previous_suite = current_suite;
- current_suite = body;
-
+void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type) {
if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
bool default_used = false;
do {
@@ -1194,29 +1222,61 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
continue;
}
}
- if (function->parameters_indices.has(parameter->identifier->name)) {
- push_error(vformat(R"(Parameter with name "%s" was already declared for this function.)", parameter->identifier->name));
+ if (p_function->parameters_indices.has(parameter->identifier->name)) {
+ push_error(vformat(R"(Parameter with name "%s" was already declared for this %s.)", parameter->identifier->name, p_type));
} else {
- function->parameters_indices[parameter->identifier->name] = function->parameters.size();
- function->parameters.push_back(parameter);
- body->add_local(parameter);
+ p_function->parameters_indices[parameter->identifier->name] = p_function->parameters.size();
+ p_function->parameters.push_back(parameter);
+ p_body->add_local(parameter, current_function);
}
} while (match(GDScriptTokenizer::Token::COMMA));
}
pop_multiline();
- consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after function parameters.)*");
+ consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, vformat(R"*(Expected closing ")" after %s parameters.)*", p_type));
if (match(GDScriptTokenizer::Token::FORWARD_ARROW)) {
- make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, function);
- function->return_type = parse_type(true);
- if (function->return_type == nullptr) {
+ make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, p_function);
+ p_function->return_type = parse_type(true);
+ if (p_function->return_type == nullptr) {
push_error(R"(Expected return type or "void" after "->".)");
}
}
// TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens.
- consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after function declaration.)");
+ consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":" after %s declaration.)", p_type));
+}
+
+GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
+ bool _static = false;
+ if (previous.type == GDScriptTokenizer::Token::STATIC) {
+ // TODO: Improve message if user uses "static" with "var" or "const"
+ if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) {
+ return nullptr;
+ }
+ _static = true;
+ }
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
+
+ if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
+ return nullptr;
+ }
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ function->identifier = parse_identifier();
+ function->is_static = _static;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ SuiteNode *previous_suite = current_suite;
+ current_suite = body;
+
+ push_multiline(true);
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
+ parse_function_signature(function, body, "function");
current_suite = previous_suite;
function->body = parse_suite("function declaration", body);
@@ -1302,29 +1362,34 @@ bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_ta
return true;
}
-GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite) {
+GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite, bool p_for_lambda) {
SuiteNode *suite = p_suite != nullptr ? p_suite : alloc_node<SuiteNode>();
suite->parent_block = current_suite;
+ suite->parent_function = current_function;
current_suite = suite;
bool multiline = false;
- if (check(GDScriptTokenizer::Token::NEWLINE)) {
+ if (match(GDScriptTokenizer::Token::NEWLINE)) {
multiline = true;
}
if (multiline) {
- consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after %s.)", p_context));
-
if (!consume(GDScriptTokenizer::Token::INDENT, vformat(R"(Expected indented block after %s.)", p_context))) {
current_suite = suite->parent_block;
return suite;
}
}
+ int error_count = 0;
+
do {
Node *statement = parse_statement();
if (statement == nullptr) {
+ if (error_count++ > 100) {
+ push_error("Too many statement errors.", suite);
+ break;
+ }
continue;
}
suite->statements.push_back(statement);
@@ -1337,7 +1402,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
if (local.type != SuiteNode::Local::UNDEFINED) {
push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), variable->identifier->name));
}
- current_suite->add_local(variable);
+ current_suite->add_local(variable, current_function);
break;
}
case Node::CONSTANT: {
@@ -1352,19 +1417,29 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
}
push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", name, constant->identifier->name));
}
- current_suite->add_local(constant);
+ current_suite->add_local(constant, current_function);
break;
}
default:
break;
}
- } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !is_at_end());
+ } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end());
if (multiline) {
- consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context));
+ if (!lambda_ended) {
+ consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context));
+
+ } else {
+ match(GDScriptTokenizer::Token::DEDENT);
+ }
+ } else if (previous.type == GDScriptTokenizer::Token::SEMICOLON) {
+ consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after ";" at the end of %s.)", p_context));
}
+ if (p_for_lambda) {
+ lambda_ended = true;
+ }
current_suite = suite->parent_block;
return suite;
}
@@ -1421,6 +1496,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
push_error(R"(Constructor cannot return a value.)");
}
n_return->return_value = parse_expression(false);
+ } else if (in_lambda && !is_statement_end_token()) {
+ // Try to parse it anyway as this might not be the statement end in a lambda.
+ // If this fails the expression will be nullptr, but that's the same as no return, so it's fine.
+ n_return->return_value = parse_expression(false);
}
result = n_return;
@@ -1449,10 +1528,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
default: {
// Expression statement.
ExpressionNode *expression = parse_expression(true); // Allow assignment here.
+ bool has_ended_lambda = false;
if (expression == nullptr) {
- push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name()));
+ if (in_lambda) {
+ // If it's not a valid expression beginning, it might be the continuation of the outer expression where this lambda is.
+ lambda_ended = true;
+ has_ended_lambda = true;
+ } else {
+ push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name()));
+ }
}
end_statement("expression");
+ lambda_ended = lambda_ended || has_ended_lambda;
result = expression;
#ifdef DEBUG_ENABLED
@@ -1476,7 +1563,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
if (current_function) {
- push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier ? current_function->identifier->name : "<anonymous lambda>");
} else {
// TODO: Properties setters and getters with unreachable code are not being warned
}
@@ -1561,7 +1648,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
SuiteNode *suite = alloc_node<SuiteNode>();
if (n_for->variable) {
- suite->add_local(SuiteNode::Local(n_for->variable));
+ suite->add_local(SuiteNode::Local(n_for->variable, current_function));
}
suite->parent_for = n_for;
@@ -1716,7 +1803,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
branch->patterns[0]->binds.get_key_list(&binds);
for (List<StringName>::Element *E = binds.front(); E != nullptr; E = E->next()) {
- SuiteNode::Local local(branch->patterns[0]->binds[E->get()]);
+ SuiteNode::Local local(branch->patterns[0]->binds[E->get()], current_function);
suite->add_local(local);
}
}
@@ -1916,7 +2003,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
// Completion can appear whenever an expression is expected.
make_completion_context(COMPLETION_IDENTIFIER, nullptr);
- GDScriptTokenizer::Token token = advance();
+ GDScriptTokenizer::Token token = current;
ParseFunction prefix_rule = get_rule(token.type)->prefix;
if (prefix_rule == nullptr) {
@@ -1924,6 +2011,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
return nullptr;
}
+ advance(); // Only consume the token if there's a valid rule.
+
ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign);
while (p_precedence <= get_rule(current.type)->precedence) {
@@ -1965,6 +2054,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode
if (current_suite != nullptr && current_suite->has_local(identifier->name)) {
const SuiteNode::Local &declaration = current_suite->get_local(identifier->name);
+
+ identifier->source_function = declaration.source_function;
switch (declaration.type) {
case SuiteNode::Local::CONSTANT:
identifier->source = IdentifierNode::LOCAL_CONSTANT;
@@ -2018,6 +2109,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre
if (current_function && current_function->is_static) {
push_error(R"(Cannot use "self" inside a static function.)");
}
+ if (in_lambda) {
+ push_error(R"(Cannot use "self" inside a lambda.)");
+ }
SelfNode *self = alloc_node<SelfNode>();
self->current_class = current_class;
return self;
@@ -2080,6 +2174,17 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_unary_operator(ExpressionN
return operation;
}
+GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_not_in_operator(ExpressionNode *p_previous_operand, bool p_can_assign) {
+ // check that NOT is followed by IN by consuming it before calling parse_binary_operator which will only receive a plain IN
+ consume(GDScriptTokenizer::Token::IN, R"(Expected "in" after "not" in content-test operator.)");
+ ExpressionNode *in_operation = parse_binary_operator(p_previous_operand, p_can_assign);
+ UnaryOpNode *operation = alloc_node<UnaryOpNode>();
+ operation->operation = UnaryOpNode::OP_LOGIC_NOT;
+ operation->variant_op = Variant::OP_NOT;
+ operation->operand = in_operation;
+ return operation;
+}
+
GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(ExpressionNode *p_previous_operand, bool p_can_assign) {
GDScriptTokenizer::Token op = previous;
BinaryOpNode *operation = alloc_node<BinaryOpNode>();
@@ -2392,6 +2497,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
push_error(R"(Expected "=" after dictionary key.)");
}
}
+ key->is_constant = true;
+ key->reduced_value = static_cast<IdentifierNode *>(key)->name;
break;
case DictionaryNode::PYTHON_DICT:
if (!match(GDScriptTokenizer::Token::COLON)) {
@@ -2438,7 +2545,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode *
if (for_completion) {
bool is_builtin = false;
- if (p_previous_operand->type == Node::IDENTIFIER) {
+ if (p_previous_operand && p_previous_operand->type == Node::IDENTIFIER) {
const IdentifierNode *id = static_cast<const IdentifierNode *>(p_previous_operand);
Variant::Type builtin_type = get_builtin_type(id->name);
if (builtin_type < Variant::VARIANT_MAX) {
@@ -2625,6 +2732,65 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_
return preload;
}
+GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign) {
+ LambdaNode *lambda = alloc_node<LambdaNode>();
+ lambda->parent_function = current_function;
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->source_lambda = lambda;
+
+ function->is_static = current_function != nullptr ? current_function->is_static : false;
+
+ if (match(GDScriptTokenizer::Token::IDENTIFIER)) {
+ function->identifier = parse_identifier();
+ }
+
+ bool multiline_context = multiline_stack.back()->get();
+
+ // Reset the multiline stack since we don't want the multiline mode one in the lambda body.
+ push_multiline(false);
+ if (multiline_context) {
+ tokenizer.push_expression_indented_block();
+ }
+
+ push_multiline(true); // For the parameters.
+ if (function->identifier) {
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after lambda name.)");
+ } else {
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after "func".)");
+ }
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ SuiteNode *previous_suite = current_suite;
+ current_suite = body;
+
+ parse_function_signature(function, body, "lambda");
+
+ current_suite = previous_suite;
+
+ bool previous_in_lambda = in_lambda;
+ in_lambda = true;
+
+ function->body = parse_suite("lambda declaration", body, true);
+
+ pop_multiline();
+
+ if (multiline_context) {
+ // If we're in multiline mode, we want to skip the spurious DEDENT and NEWLINE tokens.
+ while (check(GDScriptTokenizer::Token::DEDENT) || check(GDScriptTokenizer::Token::INDENT) || check(GDScriptTokenizer::Token::NEWLINE)) {
+ current = tokenizer.scan(); // Not advance() since we don't want to change the previous token.
+ }
+ tokenizer.pop_expression_indented_block();
+ }
+
+ current_function = previous_function;
+ in_lambda = previous_in_lambda;
+ lambda->function = function;
+ return lambda;
+}
+
GDScriptParser::ExpressionNode *GDScriptParser::parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign) {
// Just for better error messages.
GDScriptTokenizer::Token::Type invalid = previous.type;
@@ -2661,6 +2827,19 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) {
type->type_chain.push_back(type_element);
+ if (match(GDScriptTokenizer::Token::BRACKET_OPEN)) {
+ // Typed collection (like Array[int]).
+ type->container_type = parse_type(false); // Don't allow void for array element type.
+ if (type->container_type == nullptr) {
+ push_error(R"(Expected type for collection after "[".)");
+ type = nullptr;
+ } else if (type->container_type->container_type != nullptr) {
+ push_error("Nested typed collections are not supported.");
+ }
+ consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)");
+ return type;
+ }
+
int chain_index = 1;
while (match(GDScriptTokenizer::Token::PERIOD)) {
make_completion_context(COMPLETION_TYPE_ATTRIBUTE, type, chain_index++);
@@ -2906,7 +3085,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
// Logical
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_AND }, // AND,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_OR }, // OR,
- { &GDScriptParser::parse_unary_operator, nullptr, PREC_NONE }, // NOT,
+ { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_not_in_operator, PREC_CONTENT_TEST }, // NOT,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_AND }, // AMPERSAND_AMPERSAND,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_LOGIC_OR }, // PIPE_PIPE,
{ &GDScriptParser::parse_unary_operator, nullptr, PREC_NONE }, // BANG,
@@ -2956,7 +3135,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, nullptr, PREC_NONE }, // CONST,
{ nullptr, nullptr, PREC_NONE }, // ENUM,
{ nullptr, nullptr, PREC_NONE }, // EXTENDS,
- { nullptr, nullptr, PREC_NONE }, // FUNC,
+ { &GDScriptParser::parse_lambda, nullptr, PREC_NONE }, // FUNC,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_CONTENT_TEST }, // IN,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_TYPE_TEST }, // IS,
{ nullptr, nullptr, PREC_NONE }, // NAMESPACE,
@@ -3005,7 +3184,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
// Avoid desync.
static_assert(sizeof(rules) / sizeof(rules[0]) == GDScriptTokenizer::Token::TK_MAX, "Amount of parse rules don't match the amount of token types.");
- // Let's assume this this never invalid, since nothing generates a TK_MAX.
+ // Let's assume this is never invalid, since nothing generates a TK_MAX.
return &rules[p_token_type];
}
@@ -3147,24 +3326,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
variable->exported = true;
- // TODO: Improving setting type, especially for range hints, which can be int or float.
+
variable->export_info.type = t_type;
variable->export_info.hint = t_hint;
- if (p_annotation->name == "@export") {
- if (variable->datatype_specifier == nullptr) {
- if (variable->initializer == nullptr) {
- push_error(R"(Cannot use "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation);
- return false;
- }
- if (variable->initializer->type != Node::LITERAL) {
- push_error(R"(To use "@export" annotation with type-less variable, the default value must be a literal.)", p_annotation);
- return false;
- }
- variable->export_info.type = static_cast<LiteralNode *>(variable->initializer)->value.get_type();
- } // else: Actual type will be set by the analyzer, which can infer the proper type.
- }
-
String hint_string;
for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
if (i > 0) {
@@ -3175,6 +3340,86 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = hint_string;
+ // This is called after tne analyzer is done finding the type, so this should be set here.
+ DataType export_type = variable->get_datatype();
+
+ if (p_annotation->name == "@export") {
+ if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) {
+ push_error(R"(Cannot use simple "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation);
+ return false;
+ }
+
+ bool is_array = false;
+
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) {
+ export_type = export_type.get_container_element_type(); // Use inner type for.
+ is_array = true;
+ }
+
+ if (export_type.is_variant() || export_type.has_no_type()) {
+ push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation);
+ return false;
+ }
+
+ switch (export_type.kind) {
+ case GDScriptParser::DataType::BUILTIN:
+ variable->export_info.type = export_type.builtin_type;
+ variable->export_info.hint = PROPERTY_HINT_NONE;
+ variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
+ break;
+ case GDScriptParser::DataType::NATIVE:
+ if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) {
+ variable->export_info.type = Variant::OBJECT;
+ variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ variable->export_info.hint_string = get_real_class_name(export_type.native_type);
+ } else {
+ push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
+ return false;
+ }
+ break;
+ case GDScriptParser::DataType::ENUM: {
+ variable->export_info.type = Variant::INT;
+ variable->export_info.hint = PROPERTY_HINT_ENUM;
+
+ String enum_hint_string;
+ for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
+ enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ enum_hint_string += ":";
+ enum_hint_string += String::num_int64(E->get()).xml_escape();
+
+ if (E->next()) {
+ enum_hint_string += ",";
+ }
+ }
+
+ variable->export_info.hint_string = enum_hint_string;
+ } break;
+ default:
+ // TODO: Allow custom user resources.
+ push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
+ break;
+ }
+
+ if (is_array) {
+ String hint_prefix = itos(variable->export_info.type);
+ if (variable->export_info.hint) {
+ hint_prefix += "/" + itos(variable->export_info.hint);
+ }
+ variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
+ variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
+ variable->export_info.type = Variant::ARRAY;
+ }
+ } else {
+ // Validate variable type with export.
+ if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) {
+ // Allow float/int conversion.
+ if ((t_type != Variant::FLOAT || export_type.builtin_type != Variant::INT) && (t_type != Variant::INT || export_type.builtin_type != Variant::FLOAT)) {
+ push_error(vformat(R"("%s" annotation requires a variable of type "%s" but type "%s" was given instead.)", p_annotation->name.operator String(), Variant::get_type_name(t_type), export_type.to_string()), variable);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -3260,6 +3505,9 @@ String GDScriptParser::DataType::to_string() const {
if (builtin_type == Variant::NIL) {
return "null";
}
+ if (builtin_type == Variant::ARRAY && has_container_element_type()) {
+ return vformat("Array[%s]", container_element_type->to_string());
+ }
return Variant::get_type_name(builtin_type);
case NATIVE:
if (is_meta_type) {
@@ -3623,6 +3871,10 @@ void GDScriptParser::TreePrinter::print_dictionary(DictionaryNode *p_dictionary)
}
void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression) {
+ if (p_expression == nullptr) {
+ push_text("<invalid expression>");
+ return;
+ }
switch (p_expression->type) {
case Node::ARRAY:
print_array(static_cast<ArrayNode *>(p_expression));
@@ -3651,6 +3903,9 @@ void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression)
case Node::IDENTIFIER:
print_identifier(static_cast<IdentifierNode *>(p_expression));
break;
+ case Node::LAMBDA:
+ print_lambda(static_cast<LambdaNode *>(p_expression));
+ break;
case Node::LITERAL:
print_literal(static_cast<LiteralNode *>(p_expression));
break;
@@ -3710,12 +3965,17 @@ void GDScriptParser::TreePrinter::print_for(ForNode *p_for) {
decrease_indent();
}
-void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function) {
+void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const String &p_context) {
for (const List<AnnotationNode *>::Element *E = p_function->annotations.front(); E != nullptr; E = E->next()) {
print_annotation(E->get());
}
- push_text("Function ");
- print_identifier(p_function->identifier);
+ push_text(p_context);
+ push_text(" ");
+ if (p_function->identifier) {
+ print_identifier(p_function->identifier);
+ } else {
+ push_text("<anonymous>");
+ }
push_text("( ");
for (int i = 0; i < p_function->parameters.size(); i++) {
if (i > 0) {
@@ -3769,6 +4029,18 @@ void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) {
}
}
+void GDScriptParser::TreePrinter::print_lambda(LambdaNode *p_lambda) {
+ print_function(p_lambda->function, "Lambda");
+ push_text("| captures [ ");
+ for (int i = 0; i < p_lambda->captures.size(); i++) {
+ if (i > 0) {
+ push_text(" , ");
+ }
+ push_text(p_lambda->captures[i]->name.operator String());
+ }
+ push_line(" ]");
+}
+
void GDScriptParser::TreePrinter::print_literal(LiteralNode *p_literal) {
// Prefix for string types.
switch (p_literal->value.get_type()) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index d59b68b602..b1b29a7bd1 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -76,6 +76,7 @@ public:
struct GetNodeNode;
struct IdentifierNode;
struct IfNode;
+ struct LambdaNode;
struct LiteralNode;
struct MatchNode;
struct MatchBranchNode;
@@ -94,7 +95,12 @@ public:
struct VariableNode;
struct WhileNode;
- struct DataType {
+ class DataType {
+ private:
+ // Private access so we can control memory management.
+ DataType *container_element_type = nullptr;
+
+ public:
enum Kind {
BUILTIN,
NATIVE,
@@ -104,7 +110,6 @@ public:
ENUM_VALUE, // Value from enumeration.
VARIANT, // Can be any type.
UNRESOLVED,
- // TODO: Enum
};
Kind kind = UNRESOLVED;
@@ -128,7 +133,7 @@ public:
ClassNode *class_type = nullptr;
MethodInfo method_info; // For callable/signals.
- HashMap<StringName, int> enum_values; // For enums.
+ Map<StringName, int> enum_values; // For enums.
_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
@@ -136,6 +141,26 @@ public:
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
String to_string() const;
+ _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
+ container_element_type = memnew(DataType(p_type));
+ }
+
+ _FORCE_INLINE_ DataType get_container_element_type() const {
+ ERR_FAIL_COND_V(container_element_type == nullptr, DataType());
+ return *container_element_type;
+ }
+
+ _FORCE_INLINE_ bool has_container_element_type() const {
+ return container_element_type != nullptr;
+ }
+
+ _FORCE_INLINE_ void unset_container_element_type() {
+ if (container_element_type) {
+ memdelete(container_element_type);
+ };
+ container_element_type = nullptr;
+ }
+
bool operator==(const DataType &p_other) const {
if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) {
return true; // Can be consireded equal for parsing purposes.
@@ -173,6 +198,37 @@ public:
bool operator!=(const DataType &p_other) const {
return !(this->operator==(p_other));
}
+
+ DataType &operator=(const DataType &p_other) {
+ kind = p_other.kind;
+ type_source = p_other.type_source;
+ is_constant = p_other.is_constant;
+ is_meta_type = p_other.is_meta_type;
+ is_coroutine = p_other.is_coroutine;
+ builtin_type = p_other.builtin_type;
+ native_type = p_other.native_type;
+ enum_type = p_other.enum_type;
+ script_type = p_other.script_type;
+ script_path = p_other.script_path;
+ class_type = p_other.class_type;
+ method_info = p_other.method_info;
+ enum_values = p_other.enum_values;
+ unset_container_element_type();
+ if (p_other.has_container_element_type()) {
+ set_container_element_type(p_other.get_container_element_type());
+ }
+ return *this;
+ }
+
+ DataType() = default;
+
+ DataType(const DataType &p_other) {
+ *this = p_other;
+ }
+
+ ~DataType() {
+ unset_container_element_type();
+ }
};
struct ParserError {
@@ -212,6 +268,7 @@ public:
GET_NODE,
IDENTIFIER,
IF,
+ LAMBDA,
LITERAL,
MATCH,
MATCH_BRANCH,
@@ -673,6 +730,7 @@ public:
bool is_coroutine = false;
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
MethodInfo info;
+ LambdaNode *source_lambda = nullptr;
#ifdef TOOLS_ENABLED
Vector<Variant> default_arg_values;
String doc_description;
@@ -716,6 +774,7 @@ public:
VariableNode *variable_source;
IdentifierNode *bind_source;
};
+ FunctionNode *source_function = nullptr;
int usages = 0; // Useful for binds/iterator variable.
@@ -734,6 +793,21 @@ public:
}
};
+ struct LambdaNode : public ExpressionNode {
+ FunctionNode *function = nullptr;
+ FunctionNode *parent_function = nullptr;
+ Vector<IdentifierNode *> captures;
+ Map<StringName, int> captures_indices;
+
+ bool has_name() const {
+ return function && function->identifier;
+ }
+
+ LambdaNode() {
+ type = LAMBDA;
+ }
+ };
+
struct LiteralNode : public ExpressionNode {
Variant value;
@@ -887,6 +961,7 @@ public:
IdentifierNode *bind;
};
StringName name;
+ FunctionNode *source_function = nullptr;
int start_line = 0, end_line = 0;
int start_column = 0, end_column = 0;
@@ -896,10 +971,11 @@ public:
String get_name() const;
Local() {}
- Local(ConstantNode *p_constant) {
+ Local(ConstantNode *p_constant, FunctionNode *p_source_function) {
type = CONSTANT;
constant = p_constant;
name = p_constant->identifier->name;
+ source_function = p_source_function;
start_line = p_constant->start_line;
end_line = p_constant->end_line;
@@ -908,10 +984,11 @@ public:
leftmost_column = p_constant->leftmost_column;
rightmost_column = p_constant->rightmost_column;
}
- Local(VariableNode *p_variable) {
+ Local(VariableNode *p_variable, FunctionNode *p_source_function) {
type = VARIABLE;
variable = p_variable;
name = p_variable->identifier->name;
+ source_function = p_source_function;
start_line = p_variable->start_line;
end_line = p_variable->end_line;
@@ -920,10 +997,11 @@ public:
leftmost_column = p_variable->leftmost_column;
rightmost_column = p_variable->rightmost_column;
}
- Local(ParameterNode *p_parameter) {
+ Local(ParameterNode *p_parameter, FunctionNode *p_source_function) {
type = PARAMETER;
parameter = p_parameter;
name = p_parameter->identifier->name;
+ source_function = p_source_function;
start_line = p_parameter->start_line;
end_line = p_parameter->end_line;
@@ -932,10 +1010,11 @@ public:
leftmost_column = p_parameter->leftmost_column;
rightmost_column = p_parameter->rightmost_column;
}
- Local(IdentifierNode *p_identifier) {
+ Local(IdentifierNode *p_identifier, FunctionNode *p_source_function) {
type = FOR_VARIABLE;
bind = p_identifier;
name = p_identifier->name;
+ source_function = p_source_function;
start_line = p_identifier->start_line;
end_line = p_identifier->end_line;
@@ -960,9 +1039,9 @@ public:
bool has_local(const StringName &p_name) const;
const Local &get_local(const StringName &p_name) const;
template <class T>
- void add_local(T *p_local) {
+ void add_local(T *p_local, FunctionNode *p_source_function) {
locals_indices[p_local->identifier->name] = locals.size();
- locals.push_back(Local(p_local));
+ locals.push_back(Local(p_local, p_source_function));
}
void add_local(const Local &p_local) {
locals_indices[p_local.name] = locals.size();
@@ -987,6 +1066,7 @@ public:
struct TypeNode : public Node {
Vector<IdentifierNode *> type_chain;
+ TypeNode *container_type = nullptr;
TypeNode() {
type = TYPE;
@@ -1135,6 +1215,8 @@ private:
CompletionCall completion_call;
List<CompletionCall> completion_call_stack;
bool passed_cursor = false;
+ bool in_lambda = false;
+ bool lambda_ended = false; // Marker for when a lambda ends, to apply an end of statement if needed.
typedef bool (GDScriptParser::*AnnotationAction)(const AnnotationNode *p_annotation, Node *p_target);
struct AnnotationInfo {
@@ -1222,10 +1304,11 @@ private:
GDScriptTokenizer::Token advance();
bool match(GDScriptTokenizer::Token::Type p_token_type);
- bool check(GDScriptTokenizer::Token::Type p_token_type);
+ bool check(GDScriptTokenizer::Token::Type p_token_type) const;
bool consume(GDScriptTokenizer::Token::Type p_token_type, const String &p_error_message);
- bool is_at_end();
- bool is_statement_end();
+ bool is_at_end() const;
+ bool is_statement_end_token() const;
+ bool is_statement_end() const;
void end_statement(const String &p_context);
void synchronize();
void push_multiline(bool p_state);
@@ -1243,7 +1326,8 @@ private:
EnumNode *parse_enum();
ParameterNode *parse_parameter();
FunctionNode *parse_function();
- SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr);
+ void parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type);
+ SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false);
// Annotations
AnnotationNode *parse_annotation(uint32_t p_valid_targets);
bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments = 0, bool p_is_vararg = false);
@@ -1285,6 +1369,7 @@ private:
ExpressionNode *parse_builtin_constant(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_unary_operator(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_binary_operator(ExpressionNode *p_previous_operand, bool p_can_assign);
+ ExpressionNode *parse_binary_not_in_operator(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_ternary_operator(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_assignment(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_array(ExpressionNode *p_previous_operand, bool p_can_assign);
@@ -1297,6 +1382,7 @@ private:
ExpressionNode *parse_await(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_attribute(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign);
+ ExpressionNode *parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign);
TypeNode *parse_type(bool p_allow_void = false);
#ifdef TOOLS_ENABLED
@@ -1312,6 +1398,7 @@ public:
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
+ static StringName get_real_class_name(const StringName &p_source);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
@@ -1357,10 +1444,11 @@ public:
void print_expression(ExpressionNode *p_expression);
void print_enum(EnumNode *p_enum);
void print_for(ForNode *p_for);
- void print_function(FunctionNode *p_function);
+ void print_function(FunctionNode *p_function, const String &p_context = "Function");
void print_get_node(GetNodeNode *p_get_node);
void print_if(IfNode *p_if, bool p_is_elif = false);
void print_identifier(IdentifierNode *p_identifier);
+ void print_lambda(LambdaNode *p_lambda);
void print_literal(LiteralNode *p_literal);
void print_match(MatchNode *p_match);
void print_match_branch(MatchBranchNode *p_match_branch);
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 315b8ee3b4..2e6388d92f 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -242,6 +242,16 @@ void GDScriptTokenizer::set_multiline_mode(bool p_state) {
multiline_mode = p_state;
}
+void GDScriptTokenizer::push_expression_indented_block() {
+ indent_stack_stack.push_back(indent_stack);
+}
+
+void GDScriptTokenizer::pop_expression_indented_block() {
+ ERR_FAIL_COND(indent_stack_stack.size() == 0);
+ indent_stack = indent_stack_stack.back()->get();
+ indent_stack_stack.pop_back();
+}
+
int GDScriptTokenizer::get_cursor_line() const {
return cursor_line;
}
@@ -898,6 +908,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
_advance();
_advance();
break;
+ } else {
+ // Not a multiline string termination, add consumed quote.
+ result += quote_char;
}
} else {
// Ended single-line string.
@@ -1169,7 +1182,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (pending_newline) {
pending_newline = false;
if (!multiline_mode) {
- // Don't return newline tokens on multine mode.
+ // Don't return newline tokens on multiline mode.
return last_newline;
}
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index bea4b14019..84b82c07f0 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -217,6 +217,7 @@ private:
Token last_newline;
int pending_indents = 0;
List<int> indent_stack;
+ List<List<int>> indent_stack_stack; // For lambdas, which require manipulating the indentation point.
List<char32_t> paren_stack;
char32_t indent_char = '\0';
int position = 0;
@@ -263,6 +264,8 @@ public:
void set_multiline_mode(bool p_state);
bool is_past_cursor() const;
static String get_token_name(Token::Type p_token_type);
+ void push_expression_indented_block(); // For lambdas, or blocks inside expressions.
+ void pop_expression_indented_block(); // For lambdas, or blocks inside expressions.
GDScriptTokenizer();
};
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 348d221352..64c629662c 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -298,7 +298,7 @@ struct GDScriptUtilityFunctionsDefinitions {
sname.push_back(p->name);
p = p->_owner;
}
- sname.invert();
+ sname.reverse();
if (!p->path.is_resource_file()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 4e098d7a6d..4757ec6ca9 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -33,23 +33,24 @@
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "gdscript.h"
+#include "gdscript_lambda_callable.h"
-Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
+Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
//sequential table (jump table generated by compiler)
switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
- case ADDR_TYPE_SELF: {
+ case ADDR_TYPE_STACK: {
#ifdef DEBUG_ENABLED
- if (unlikely(!p_instance)) {
- r_error = "Cannot access self without instance.";
- return nullptr;
- }
+ ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
#endif
- return &self;
+ return &p_stack[address];
} break;
- case ADDR_TYPE_CLASS: {
- return &static_ref;
+ case ADDR_TYPE_CONSTANT: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
+#endif
+ return &_constants_ptr[address];
} break;
case ADDR_TYPE_MEMBER: {
#ifdef DEBUG_ENABLED
@@ -61,65 +62,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
//member indexing is O(1)
return &p_instance->members.write[address];
} break;
- case ADDR_TYPE_CLASS_CONSTANT: {
- //todo change to index!
- GDScript *s = p_script;
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- const StringName *sn = &_global_names_ptr[address];
-
- while (s) {
- GDScript *o = s;
- while (o) {
- Map<StringName, Variant>::Element *E = o->constants.find(*sn);
- if (E) {
- return &E->get();
- }
- o = o->_owner;
- }
- s = s->_base;
- }
-
- ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
- } break;
- case ADDR_TYPE_LOCAL_CONSTANT: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
-#endif
- return &_constants_ptr[address];
- } break;
- case ADDR_TYPE_STACK:
- case ADDR_TYPE_STACK_VARIABLE: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
-#endif
- return &p_stack[address];
- } break;
- case ADDR_TYPE_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
-#endif
- return &GDScriptLanguage::get_singleton()->get_global_array()[address];
- } break;
-#ifdef TOOLS_ENABLED
- case ADDR_TYPE_NAMED_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- StringName id = _global_names_ptr[address];
-
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
- return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
- } else {
- r_error = "Autoload singleton '" + String(id) + "' has been removed.";
- return nullptr;
- }
- } break;
-#endif
- case ADDR_TYPE_NIL: {
- return &nil;
- } break;
}
ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
@@ -127,6 +69,17 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
}
#ifdef DEBUG_ENABLED
+static String _get_script_name(const Ref<Script> p_script) {
+ Ref<GDScript> gdscript = p_script;
+ if (gdscript.is_valid()) {
+ return gdscript->get_script_class_name();
+ } else if (p_script->get_name().is_empty()) {
+ return p_script->get_path().get_file();
+ } else {
+ return p_script->get_name();
+ }
+}
+
static String _get_var_type(const Variant *p_var) {
String basestr;
@@ -140,15 +93,30 @@ static String _get_var_type(const Variant *p_var) {
basestr = "previously freed";
}
} else {
+ basestr = bobj->get_class();
if (bobj->get_script_instance()) {
- basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")";
- } else {
- basestr = bobj->get_class();
+ basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
}
}
} else {
- basestr = Variant::get_type_name(p_var->get_type());
+ if (p_var->get_type() == Variant::ARRAY) {
+ basestr = "Array";
+ const Array *p_array = VariantInternal::get_array(p_var);
+ Variant::Type builtin_type = (Variant::Type)p_array->get_typed_builtin();
+ StringName native_type = p_array->get_typed_class_name();
+ Ref<Script> script_type = p_array->get_typed_script();
+
+ if (script_type.is_valid() && script_type->is_valid()) {
+ basestr += "[" + _get_script_name(script_type) + "]";
+ } else if (native_type != StringName()) {
+ basestr += "[" + native_type.operator String() + "]";
+ } else if (builtin_type != Variant::NIL) {
+ basestr += "[" + Variant::get_type_name(builtin_type) + "]";
+ }
+ } else {
+ basestr = Variant::get_type_name(p_var->get_type());
+ }
}
return basestr;
@@ -207,6 +175,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
+ &&OPCODE_ASSIGN_TYPED_ARRAY, \
&&OPCODE_ASSIGN_TYPED_NATIVE, \
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
&&OPCODE_CAST_TO_BUILTIN, \
@@ -215,6 +184,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CONSTRUCT, \
&&OPCODE_CONSTRUCT_VALIDATED, \
&&OPCODE_CONSTRUCT_ARRAY, \
+ &&OPCODE_CONSTRUCT_TYPED_ARRAY, \
&&OPCODE_CONSTRUCT_DICTIONARY, \
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
@@ -263,11 +233,16 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
+ &&OPCODE_CREATE_LAMBDA, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
&&OPCODE_RETURN, \
+ &&OPCODE_RETURN_TYPED_BUILTIN, \
+ &&OPCODE_RETURN_TYPED_ARRAY, \
+ &&OPCODE_RETURN_TYPED_NATIVE, \
+ &&OPCODE_RETURN_TYPED_SCRIPT, \
&&OPCODE_ITERATE_BEGIN, \
&&OPCODE_ITERATE_BEGIN_INT, \
&&OPCODE_ITERATE_BEGIN_FLOAT, \
@@ -308,6 +283,41 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_OBJECT, \
+ &&OPCODE_STORE_NAMED_GLOBAL, \
+ &&OPCODE_TYPE_ADJUST_BOOL, \
+ &&OPCODE_TYPE_ADJUST_INT, \
+ &&OPCODE_TYPE_ADJUST_FLOAT, \
+ &&OPCODE_TYPE_ADJUST_STRING, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2I, \
+ &&OPCODE_TYPE_ADJUST_RECT2, \
+ &&OPCODE_TYPE_ADJUST_RECT2I, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3I, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
+ &&OPCODE_TYPE_ADJUST_PLANE, \
+ &&OPCODE_TYPE_ADJUST_QUAT, \
+ &&OPCODE_TYPE_ADJUST_AABB, \
+ &&OPCODE_TYPE_ADJUST_BASIS, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM, \
+ &&OPCODE_TYPE_ADJUST_COLOR, \
+ &&OPCODE_TYPE_ADJUST_STRING_NAME, \
+ &&OPCODE_TYPE_ADJUST_NODE_PATH, \
+ &&OPCODE_TYPE_ADJUST_RID, \
+ &&OPCODE_TYPE_ADJUST_OBJECT, \
+ &&OPCODE_TYPE_ADJUST_CALLABLE, \
+ &&OPCODE_TYPE_ADJUST_SIGNAL, \
+ &&OPCODE_TYPE_ADJUST_DICTIONARY, \
+ &&OPCODE_TYPE_ADJUST_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
&&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \
@@ -383,11 +393,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_OK;
- Variant self;
- Variant static_ref;
Variant retvalue;
Variant *stack = nullptr;
- Variant **instruction_args;
+ Variant **instruction_args = nullptr;
const void **call_args_ptr = nullptr;
int defarg = 0;
@@ -412,7 +420,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
script = p_state->script;
p_instance = p_state->instance;
defarg = p_state->defarg;
- self = p_state->self;
} else {
if (p_argcount != _argument_count) {
@@ -430,55 +437,49 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
}
- alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
+ // Add 3 here for self, class, and nil.
+ alloca_size = sizeof(Variant *) * 3 + sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
- if (alloca_size) {
- uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+ uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+ stack = (Variant *)aptr;
- if (_stack_size) {
- stack = (Variant *)aptr;
- for (int i = 0; i < p_argcount; i++) {
- if (!argument_types[i].has_type) {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- continue;
- }
-
- if (!argument_types[i].is_type(*p_args[i], true)) {
- r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_err.argument = i;
- r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
- return Variant();
- }
- if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
- Variant arg;
- Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
- memnew_placement(&stack[i], Variant(arg));
- } else {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- }
- }
- for (int i = p_argcount; i < _stack_size; i++) {
- memnew_placement(&stack[i], Variant);
- }
- } else {
- stack = nullptr;
+ for (int i = 0; i < p_argcount; i++) {
+ if (!argument_types[i].has_type) {
+ memnew_placement(&stack[i + 3], Variant(*p_args[i]));
+ continue;
}
- if (_instruction_args_size) {
- instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
+ if (!argument_types[i].is_type(*p_args[i], true)) {
+ r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_err.argument = i;
+ r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
+ return Variant();
+ }
+ if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
+ Variant arg;
+ Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
+ memnew_placement(&stack[i + 3], Variant(arg));
} else {
- instruction_args = nullptr;
+ memnew_placement(&stack[i + 3], Variant(*p_args[i]));
}
+ }
+ for (int i = p_argcount + 3; i < _stack_size; i++) {
+ memnew_placement(&stack[i], Variant);
+ }
+ memnew_placement(&stack[ADDR_STACK_NIL], Variant);
+
+ if (_instruction_args_size) {
+ instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
- stack = nullptr;
instruction_args = nullptr;
}
if (p_instance) {
- self = p_instance->owner;
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr();
} else {
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script;
}
}
@@ -488,7 +489,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
call_args_ptr = nullptr;
}
- static_ref = script;
+ memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
String err_text;
@@ -509,10 +510,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space) \
GD_ERR_BREAK((ip + m_space) > _code_size)
-#define GET_VARIANT_PTR(m_v, m_code_ofs) \
- Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
- if (unlikely(!m_v)) \
+#define GET_VARIANT_PTR(m_v, m_code_ofs) \
+ Variant *m_v; \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); \
+ if (unlikely(!m_v)) \
OPCODE_BREAK;
#else
@@ -520,7 +521,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text);
#endif
@@ -544,7 +545,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
OPCODE_WHILE(ip < _code_size) {
- int last_opcode = _code_ptr[ip];
+ int last_opcode = _code_ptr[ip] & INSTR_MASK;
#else
OPCODE_WHILE(true) {
#endif
@@ -649,7 +650,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (scr_B) {
//if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this shoul return false.
+ //in other situation, this should return false.
if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
@@ -1077,6 +1078,31 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_ASSIGN_TYPED_ARRAY) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+ Array *dst_arr = VariantInternal::get_array(dst);
+
+ if (src->get_type() != Variant::ARRAY) {
+#ifdef DEBUG_ENABLED
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + +"'.";
+#endif
+ OPCODE_BREAK;
+ }
+ if (!dst_arr->typed_assign(*src)) {
+#ifdef DEBUG_ENABLED
+ err_text = "Trying to assign a typed array with an array of different type.'";
+#endif
+ OPCODE_BREAK;
+ }
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(dst, 0);
@@ -1308,6 +1334,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
GET_INSTRUCTION_ARG(dst, argc);
+ *dst = Variant(); // Clear potential previous typed array.
*dst = array;
@@ -1315,6 +1342,35 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CONSTRUCT_TYPED_ARRAY) {
+ CHECK_SPACE(3 + instr_arg_count);
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+
+ GET_INSTRUCTION_ARG(script_type, argc + 1);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 2];
+ int native_type_idx = _code_ptr[ip + 3];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
+
+ Array array;
+ array.set_typed(builtin_type, native_type, script_type);
+ array.resize(argc);
+
+ for (int i = 0; i < argc; i++) {
+ array[i] = *(instruction_args[i]);
+ }
+
+ GET_INSTRUCTION_ARG(dst, argc);
+ *dst = Variant(); // Clear potential previous typed array.
+
+ *dst = array;
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
CHECK_SPACE(2 + instr_arg_count);
@@ -1398,13 +1454,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (err.error != Callable::CallError::CALL_OK) {
String methodstr = *methodname;
String basestr = _get_var_type(base);
+ bool is_callable = false;
if (methodstr == "call") {
- if (argc >= 1) {
+ if (argc >= 1 && base->get_type() != Variant::CALLABLE) {
methodstr = String(*argptrs[0]) + " (via call)";
if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
err.argument += 1;
}
+ } else {
+ methodstr = base->operator String() + " (Callable)";
+ is_callable = true;
}
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
@@ -1424,7 +1484,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
}
}
- err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
+ err_text = _get_call_error(err, "function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs);
OPCODE_BREAK;
}
#endif
@@ -1951,7 +2011,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
}
gdfs->state.stack_size = _stack_size;
- gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
gdfs->state.ip = ip + 2;
gdfs->state.line = line;
@@ -2004,6 +2063,34 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CREATE_LAMBDA) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int captures_count = _code_ptr[ip + 1];
+ GD_ERR_BREAK(captures_count < 0);
+
+ int lambda_index = _code_ptr[ip + 2];
+ GD_ERR_BREAK(lambda_index < 0 || lambda_index >= _lambdas_count);
+ GDScriptFunction *lambda = _lambdas_ptr[lambda_index];
+
+ Vector<Variant> captures;
+ captures.resize(captures_count);
+ for (int i = 0; i < captures_count; i++) {
+ GET_INSTRUCTION_ARG(arg, i);
+ captures.write[i] = *arg;
+ }
+
+ GDScriptLambdaCallable *callable = memnew(GDScriptLambdaCallable(Ref<GDScript>(script), lambda, captures));
+
+ GET_INSTRUCTION_ARG(result, captures_count);
+ *result = Callable(callable);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
@@ -2063,6 +2150,183 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
+ OPCODE(OPCODE_RETURN_TYPED_BUILTIN) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ Variant::Type ret_type = (Variant::Type)_code_ptr[ip + 2];
+ GD_ERR_BREAK(ret_type < 0 || ret_type >= Variant::VARIANT_MAX);
+
+ if (r->get_type() != ret_type) {
+ if (Variant::can_convert_strict(r->get_type(), ret_type)) {
+ Callable::CallError ce;
+ Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce);
+ } else {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type));
+#endif // DEBUG_ENABLED
+
+ // Construct a base type anyway so type constraints are met.
+ Callable::CallError ce;
+ Variant::construct(ret_type, retvalue, nullptr, 0, ce);
+ OPCODE_BREAK;
+ }
+ } else {
+ retvalue = *r;
+ }
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_ARRAY) {
+ CHECK_SPACE(5);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(script_type, 1);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 3];
+ int native_type_idx = _code_ptr[ip + 4];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
+
+ if (r->get_type() != Variant::ARRAY) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "Array[%s]".)",
+ Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type));
+#endif
+ OPCODE_BREAK;
+ }
+
+ Array array;
+ array.set_typed(builtin_type, native_type, script_type);
+
+#ifdef DEBUG_ENABLED
+ bool valid = array.typed_assign(*VariantInternal::get_array(r));
+#else
+ array.typed_assign(*VariantInternal::get_array(r));
+#endif // DEBUG_ENABLED
+
+ // Assign the return value anyway since we want it to be the valid type.
+ retvalue = array;
+
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Trying to return a typed array with an array of different type.'";
+ OPCODE_BREAK;
+ }
+
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_NATIVE) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(type, 1);
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
+ GD_ERR_BREAK(!nc);
+
+ if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), nc->get_name());
+ OPCODE_BREAK;
+ }
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *ret_obj = r->get_validated_object_with_check(freed);
+
+ if (freed) {
+ err_text = "Trying to return a previously freed instance.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *ret_obj = r->operator Object *();
+#endif // DEBUG_ENABLED
+ if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ ret_obj->get_class_name(), nc->get_name());
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+ retvalue = *r;
+
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_SCRIPT) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(type, 1);
+ Script *base_type = Object::cast_to<Script>(type->operator Object *());
+ GD_ERR_BREAK(!base_type);
+
+ if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), _get_script_name(Ref<Script>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *ret_obj = r->get_validated_object_with_check(freed);
+
+ if (freed) {
+ err_text = "Trying to return a previously freed instance.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *ret_obj = r->operator Object *();
+#endif // DEBUG_ENABLED
+
+ if (ret_obj) {
+ ScriptInstance *ret_inst = ret_obj->get_script_instance();
+ if (!ret_inst) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ ret_obj->get_class_name(), _get_script_name(Ref<GDScript>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ Script *ret_type = ret_obj->get_script_instance()->get_script().ptr();
+ bool valid = false;
+
+ while (ret_type) {
+ if (ret_type == base_type) {
+ valid = true;
+ break;
+ }
+ ret_type = ret_type->get_base_script().ptr();
+ }
+
+ if (!valid) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ _get_script_name(ret_obj->get_script_instance()->get_script()), _get_script_name(Ref<GDScript>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+ }
+ retvalue = *r;
+
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
OPCODE(OPCODE_ITERATE_BEGIN) {
CHECK_SPACE(8); // Space for this and a regular iterate.
@@ -2764,6 +3028,63 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_STORE_NAMED_GLOBAL) {
+ CHECK_SPACE(3);
+ int globalname_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(globalname_idx < 0 || globalname_idx >= _global_names_count);
+ const StringName *globalname = &_global_names_ptr[globalname_idx];
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ *dst = GDScriptLanguage::get_singleton()->get_named_globals_map()[*globalname];
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+#define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \
+ OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \
+ CHECK_SPACE(2); \
+ GET_INSTRUCTION_ARG(arg, 0); \
+ VariantTypeAdjust<m_c_type>::adjust(arg); \
+ ip += 2; \
+ } \
+ DISPATCH_OPCODE
+
+ OPCODE_TYPE_ADJUST(BOOL, bool);
+ OPCODE_TYPE_ADJUST(INT, int64_t);
+ OPCODE_TYPE_ADJUST(FLOAT, double);
+ OPCODE_TYPE_ADJUST(STRING, String);
+ OPCODE_TYPE_ADJUST(VECTOR2, Vector2);
+ OPCODE_TYPE_ADJUST(VECTOR2I, Vector2i);
+ OPCODE_TYPE_ADJUST(RECT2, Rect2);
+ OPCODE_TYPE_ADJUST(RECT2I, Rect2i);
+ OPCODE_TYPE_ADJUST(VECTOR3, Vector3);
+ OPCODE_TYPE_ADJUST(VECTOR3I, Vector3i);
+ OPCODE_TYPE_ADJUST(TRANSFORM2D, Transform2D);
+ OPCODE_TYPE_ADJUST(PLANE, Plane);
+ OPCODE_TYPE_ADJUST(QUAT, Quat);
+ OPCODE_TYPE_ADJUST(AABB, AABB);
+ OPCODE_TYPE_ADJUST(BASIS, Basis);
+ OPCODE_TYPE_ADJUST(TRANSFORM, Transform);
+ OPCODE_TYPE_ADJUST(COLOR, Color);
+ OPCODE_TYPE_ADJUST(STRING_NAME, StringName);
+ OPCODE_TYPE_ADJUST(NODE_PATH, NodePath);
+ OPCODE_TYPE_ADJUST(RID, RID);
+ OPCODE_TYPE_ADJUST(OBJECT, Object *);
+ OPCODE_TYPE_ADJUST(CALLABLE, Callable);
+ OPCODE_TYPE_ADJUST(SIGNAL, Signal);
+ OPCODE_TYPE_ADJUST(DICTIONARY, Dictionary);
+ OPCODE_TYPE_ADJUST(ARRAY, Array);
+ OPCODE_TYPE_ADJUST(PACKED_BYTE_ARRAY, PackedByteArray);
+ OPCODE_TYPE_ADJUST(PACKED_INT32_ARRAY, PackedInt32Array);
+ OPCODE_TYPE_ADJUST(PACKED_INT64_ARRAY, PackedInt64Array);
+ OPCODE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY, PackedFloat32Array);
+ OPCODE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY, PackedFloat64Array);
+ OPCODE_TYPE_ADJUST(PACKED_STRING_ARRAY, PackedStringArray);
+ OPCODE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY, PackedVector2Array);
+ OPCODE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY, PackedVector3Array);
+ OPCODE_TYPE_ADJUST(PACKED_COLOR_ARRAY, PackedColorArray);
+
OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(3);
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 5e3d6213d3..0432e7caea 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/io/json.h"
-#include "core/os/copymem.h"
#include "editor/doc_tools.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@@ -163,7 +162,7 @@ void GDScriptLanguageProtocol::_bind_methods() {
ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized);
ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected);
ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected);
- ClassDB::bind_method(D_METHOD("notify_client", "method", "params"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("notify_client", "method", "params", "client_id"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 9f2373bf56..030633274c 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -400,6 +400,7 @@ GDScriptTextDocument::~GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
+ EditorFileSystem::get_singleton()->update_file(path);
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 96744a15d7..6635098be2 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -1661,7 +1661,7 @@ struct ServerCapabilities {
signatureHelpProvider.triggerCharacters.push_back(",");
signatureHelpProvider.triggerCharacters.push_back("(");
dict["signatureHelpProvider"] = signatureHelpProvider.to_json();
- dict["codeLensProvider"] = false; // codeLensProvider.to_json();
+ //dict["codeLensProvider"] = codeLensProvider.to_json();
dict["documentOnTypeFormattingProvider"] = documentOnTypeFormattingProvider.to_json();
dict["renameProvider"] = renameProvider.to_json();
dict["documentLinkProvider"] = documentLinkProvider.to_json();
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index e90475a60e..2d2f94f5e0 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -85,7 +85,7 @@ public:
return;
}
- // TODO: Readd compiled GDScript on export.
+ // TODO: Re-add compiled GDScript on export.
return;
}
};
@@ -158,25 +158,24 @@ void unregister_gdscript_types() {
#endif // TOOLS_ENABLED
GDScriptParser::cleanup();
- GDScriptAnalyzer::cleanup();
GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
void test_tokenizer() {
- TestGDScript::test(TestGDScript::TestType::TEST_TOKENIZER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_TOKENIZER);
}
void test_parser() {
- TestGDScript::test(TestGDScript::TestType::TEST_PARSER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_PARSER);
}
void test_compiler() {
- TestGDScript::test(TestGDScript::TestType::TEST_COMPILER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_COMPILER);
}
void test_bytecode() {
- TestGDScript::test(TestGDScript::TestType::TEST_BYTECODE);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_BYTECODE);
}
REGISTER_TEST_COMMAND("gdscript-tokenizer", &test_tokenizer);
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
new file mode 100644
index 0000000000..76ae43e792
--- /dev/null
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -0,0 +1,584 @@
+/*************************************************************************/
+/* gdscript_test_runner.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_test_runner.h"
+
+#include "../gdscript.h"
+#include "../gdscript_analyzer.h"
+#include "../gdscript_compiler.h"
+#include "../gdscript_parser.h"
+
+#include "core/config/project_settings.h"
+#include "core/core_string_names.h"
+#include "core/io/file_access_pack.h"
+#include "core/os/dir_access.h"
+#include "core/os/os.h"
+#include "core/string/string_builder.h"
+#include "scene/resources/packed_scene.h"
+
+#include "tests/test_macros.h"
+
+namespace GDScriptTests {
+
+void init_autoloads() {
+ Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+ // First pass, add the constants so they exist before any script is loaded.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (info.is_singleton) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
+ }
+ }
+ }
+
+ // Second pass, load into global constants.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (!info.is_singleton) {
+ // Skip non-singletons since we don't have a scene tree here anyway.
+ continue;
+ }
+
+ RES res = ResourceLoader::load(info.path);
+ ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
+ Node *n = nullptr;
+ if (res->is_class("PackedScene")) {
+ Ref<PackedScene> ps = res;
+ n = ps->instance();
+ } else if (res->is_class("Script")) {
+ Ref<Script> script_res = res;
+ StringName ibt = script_res->get_instance_base_type();
+ bool valid_type = ClassDB::is_parent_class(ibt, "Node");
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+
+ Object *obj = ClassDB::instance(ibt);
+
+ ERR_CONTINUE_MSG(obj == nullptr,
+ "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
+ String(ibt));
+
+ n = Object::cast_to<Node>(obj);
+ n->set_script(script_res);
+ }
+
+ ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
+ n->set_name(info.name);
+
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, n);
+ }
+ }
+}
+
+void init_language(const String &p_base_path) {
+ // Setup project settings since it's needed by the languages to get the global scripts.
+ // This also sets up the base resource path.
+ Error err = ProjectSettings::get_singleton()->setup(p_base_path, String(), true);
+ if (err) {
+ print_line("Could not load project settings.");
+ // Keep going since some scripts still work without this.
+ }
+
+ // Initialize the language for the test routine.
+ GDScriptLanguage::get_singleton()->init();
+ init_autoloads();
+}
+
+void finish_language() {
+ GDScriptLanguage::get_singleton()->finish();
+ ScriptServer::global_classes_clear();
+}
+
+StringName GDScriptTestRunner::test_function_name;
+
+GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_language) {
+ test_function_name = StaticCString::create("test");
+ do_init_languages = p_init_language;
+
+ source_dir = p_source_dir;
+ if (!source_dir.ends_with("/")) {
+ source_dir += "/";
+ }
+
+ if (do_init_languages) {
+ init_language(p_source_dir);
+
+ // Enable all warnings for GDScript, so we can test them.
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
+ }
+ }
+
+ // Enable printing to show results
+ _print_line_enabled = true;
+ _print_error_enabled = true;
+}
+
+GDScriptTestRunner::~GDScriptTestRunner() {
+ test_function_name = StringName();
+ if (do_init_languages) {
+ finish_language();
+ }
+}
+
+int GDScriptTestRunner::run_tests() {
+ if (!make_tests()) {
+ FAIL("An error occurred while making the tests.");
+ return -1;
+ }
+
+ if (!generate_class_index()) {
+ FAIL("An error occurred while generating class index.");
+ return -1;
+ }
+
+ int failed = 0;
+ for (int i = 0; i < tests.size(); i++) {
+ GDScriptTest test = tests[i];
+ GDScriptTest::TestResult result = test.run_test();
+
+ String expected = FileAccess::get_file_as_string(test.get_output_file());
+ INFO(test.get_source_file());
+ if (!result.passed) {
+ INFO(expected);
+ failed++;
+ }
+
+ CHECK_MESSAGE(result.passed, (result.passed ? String() : result.output));
+ }
+
+ return failed;
+}
+
+bool GDScriptTestRunner::generate_outputs() {
+ is_generating = true;
+
+ if (!make_tests()) {
+ print_line("Failed to generate a test output.");
+ return false;
+ }
+
+ if (!generate_class_index()) {
+ return false;
+ }
+
+ for (int i = 0; i < tests.size(); i++) {
+ OS::get_singleton()->print(".");
+ GDScriptTest test = tests[i];
+ bool result = test.generate_output();
+
+ if (!result) {
+ print_line("\nCould not generate output for " + test.get_source_file());
+ return false;
+ }
+ }
+ print_line("\nGenerated output files for " + itos(tests.size()) + " tests successfully.");
+
+ return true;
+}
+
+bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
+ Error err = OK;
+ DirAccessRef dir(DirAccess::open(p_dir, &err));
+
+ if (err != OK) {
+ return false;
+ }
+
+ String current_dir = dir->get_current_dir();
+
+ dir->list_dir_begin();
+ String next = dir->get_next();
+
+ while (!next.is_empty()) {
+ if (dir->current_is_dir()) {
+ if (next == "." || next == "..") {
+ next = dir->get_next();
+ continue;
+ }
+ if (!make_tests_for_dir(current_dir.plus_file(next))) {
+ return false;
+ }
+ } else {
+ if (next.get_extension().to_lower() == "gd") {
+ String out_file = next.get_basename() + ".out";
+ if (!is_generating && !dir->file_exists(out_file)) {
+ ERR_FAIL_V_MSG(false, "Could not find output file for " + next);
+ }
+ GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir);
+ tests.push_back(test);
+ }
+ }
+
+ next = dir->get_next();
+ }
+
+ dir->list_dir_end();
+
+ return true;
+}
+
+bool GDScriptTestRunner::make_tests() {
+ Error err = OK;
+ DirAccessRef dir(DirAccess::open(source_dir, &err));
+
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory.");
+
+ return make_tests_for_dir(dir->get_current_dir());
+}
+
+bool GDScriptTestRunner::generate_class_index() {
+ StringName gdscript_name = GDScriptLanguage::get_singleton()->get_name();
+ for (int i = 0; i < tests.size(); i++) {
+ GDScriptTest test = tests[i];
+ String base_type;
+
+ String class_name = GDScriptLanguage::get_singleton()->get_global_class_name(test.get_source_file(), &base_type);
+ if (class_name == String()) {
+ continue;
+ }
+ ERR_FAIL_COND_V_MSG(ScriptServer::is_global_class(class_name), false,
+ "Class name '" + class_name + "' from " + test.get_source_file() + " is already used in " + ScriptServer::get_global_class_path(class_name));
+
+ ScriptServer::add_global_class(class_name, base_type, gdscript_name, test.get_source_file());
+ }
+ return true;
+}
+
+GDScriptTest::GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir) {
+ source_file = p_source_path;
+ output_file = p_output_path;
+ base_dir = p_base_dir;
+ _print_handler.printfunc = print_handler;
+ _error_handler.errfunc = error_handler;
+}
+
+void GDScriptTestRunner::handle_cmdline() {
+ List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
+ // TODO: this could likely be ported to use test commands:
+ // https://github.com/godotengine/godot/pull/41355
+ // Currently requires to startup the whole engine, which is slow.
+ String test_cmd = "--gdscript-test";
+ String gen_cmd = "--gdscript-generate-tests";
+
+ for (List<String>::Element *E = cmdline_args.front(); E != nullptr; E = E->next()) {
+ String &cmd = E->get();
+ if (cmd == test_cmd || cmd == gen_cmd) {
+ if (E->next() == nullptr) {
+ ERR_PRINT("Needed a path for the test files.");
+ exit(-1);
+ }
+
+ const String &path = E->next()->get();
+
+ GDScriptTestRunner runner(path, false);
+ int failed = 0;
+ if (cmd == test_cmd) {
+ failed = runner.run_tests();
+ } else {
+ bool completed = runner.generate_outputs();
+ failed = completed ? 0 : -1;
+ }
+ exit(failed);
+ }
+ }
+}
+
+void GDScriptTest::enable_stdout() {
+ // TODO: this could likely be handled by doctest or `tests/test_macros.h`.
+ OS::get_singleton()->set_stdout_enabled(true);
+ OS::get_singleton()->set_stderr_enabled(true);
+}
+
+void GDScriptTest::disable_stdout() {
+ // TODO: this could likely be handled by doctest or `tests/test_macros.h`.
+ OS::get_singleton()->set_stdout_enabled(false);
+ OS::get_singleton()->set_stderr_enabled(false);
+}
+
+void GDScriptTest::print_handler(void *p_this, const String &p_message, bool p_error) {
+ TestResult *result = (TestResult *)p_this;
+ result->output += p_message + "\n";
+}
+
+void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type) {
+ ErrorHandlerData *data = (ErrorHandlerData *)p_this;
+ GDScriptTest *self = data->self;
+ TestResult *result = data->result;
+
+ result->status = GDTEST_RUNTIME_ERROR;
+
+ StringBuilder builder;
+ builder.append(">> ");
+ switch (p_type) {
+ case ERR_HANDLER_ERROR:
+ builder.append("ERROR");
+ break;
+ case ERR_HANDLER_WARNING:
+ builder.append("WARNING");
+ break;
+ case ERR_HANDLER_SCRIPT:
+ builder.append("SCRIPT ERROR");
+ break;
+ case ERR_HANDLER_SHADER:
+ builder.append("SHADER ERROR");
+ break;
+ default:
+ builder.append("Unknown error type");
+ break;
+ }
+
+ builder.append("\n>> ");
+ builder.append(p_function);
+ builder.append("\n>> ");
+ builder.append(p_function);
+ builder.append("\n>> ");
+ builder.append(String(p_file).trim_prefix(self->base_dir));
+ builder.append("\n>> ");
+ builder.append(itos(p_line));
+ builder.append("\n>> ");
+ builder.append(p_error);
+ if (strlen(p_explanation) > 0) {
+ builder.append("\n>> ");
+ builder.append(p_explanation);
+ }
+ builder.append("\n");
+
+ result->output = builder.as_string();
+}
+
+bool GDScriptTest::check_output(const String &p_output) const {
+ Error err = OK;
+ String expected = FileAccess::get_file_as_string(output_file, &err);
+
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Error when opening the output file.");
+
+ String got = p_output.strip_edges(); // TODO: may be hacky.
+ got += "\n"; // Make sure to insert newline for CI static checks.
+
+ return got == expected;
+}
+
+String GDScriptTest::get_text_for_status(GDScriptTest::TestStatus p_status) const {
+ switch (p_status) {
+ case GDTEST_OK:
+ return "GDTEST_OK";
+ case GDTEST_LOAD_ERROR:
+ return "GDTEST_LOAD_ERROR";
+ case GDTEST_PARSER_ERROR:
+ return "GDTEST_PARSER_ERROR";
+ case GDTEST_ANALYZER_ERROR:
+ return "GDTEST_ANALYZER_ERROR";
+ case GDTEST_COMPILER_ERROR:
+ return "GDTEST_COMPILER_ERROR";
+ case GDTEST_RUNTIME_ERROR:
+ return "GDTEST_RUNTIME_ERROR";
+ }
+ return "";
+}
+
+GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
+ disable_stdout();
+
+ TestResult result;
+ result.status = GDTEST_OK;
+ result.output = String();
+
+ Error err = OK;
+
+ // Create script.
+ Ref<GDScript> script;
+ script.instance();
+ script->set_path(source_file);
+ script->set_script_path(source_file);
+ err = script->load_source_code(source_file);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not load source code for: '" + source_file + "'");
+ }
+
+ // Test parsing.
+ GDScriptParser parser;
+ err = parser.parse(script->get_source_code(), source_file, false);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_PARSER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) {
+ result.output += E->get().message + "\n"; // TODO: line, column?
+ break; // Only the first error since the following might be cascading.
+ }
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ // Test type-checking.
+ GDScriptAnalyzer analyzer(&parser);
+ err = analyzer.analyze();
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_ANALYZER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) {
+ result.output += E->get().message + "\n"; // TODO: line, column?
+ break; // Only the first error since the following might be cascading.
+ }
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ StringBuilder warning_string;
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E != nullptr; E = E->next()) {
+ const GDScriptWarning warning = E->get();
+ warning_string.append(">> WARNING");
+ warning_string.append("\n>> Line: ");
+ warning_string.append(itos(warning.start_line));
+ warning_string.append("\n>> ");
+ warning_string.append(warning.get_name());
+ warning_string.append("\n>> ");
+ warning_string.append(warning.get_message());
+ warning_string.append("\n");
+ }
+ result.output += warning_string.as_string();
+
+ // Test compiling.
+ GDScriptCompiler compiler;
+ err = compiler.compile(&parser, script.ptr(), false);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_COMPILER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+ result.output = compiler.get_error();
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ // Test running.
+ const Map<StringName, GDScriptFunction *>::Element *test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name);
+ if (test_function_element == nullptr) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.output = "";
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not find test function on: '" + source_file + "'");
+ }
+
+ script->reload();
+
+ // Create object instance for test.
+ Object *obj = ClassDB::instance(script->get_native()->get_name());
+ Ref<Reference> obj_ref;
+ if (obj->is_reference()) {
+ obj_ref = Ref<Reference>(Object::cast_to<Reference>(obj));
+ }
+ obj->set_script(script);
+ GDScriptInstance *instance = static_cast<GDScriptInstance *>(obj->get_script_instance());
+
+ // Setup output handlers.
+ ErrorHandlerData error_data(&result, this);
+
+ _print_handler.userdata = &result;
+ _error_handler.userdata = &error_data;
+ add_print_handler(&_print_handler);
+ add_error_handler(&_error_handler);
+
+ // Call test function.
+ Callable::CallError call_err;
+ instance->call(GDScriptTestRunner::test_function_name, nullptr, 0, call_err);
+
+ // Tear down output handlers.
+ remove_print_handler(&_print_handler);
+ remove_error_handler(&_error_handler);
+
+ // Check results.
+ if (call_err.error != Callable::CallError::CALL_OK) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not call test function on: '" + source_file + "'");
+ }
+
+ result.output = get_text_for_status(result.status) + "\n" + result.output;
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+
+ if (obj_ref.is_null()) {
+ memdelete(obj);
+ }
+
+ enable_stdout();
+ return result;
+}
+
+GDScriptTest::TestResult GDScriptTest::run_test() {
+ return execute_test_code(false);
+}
+
+bool GDScriptTest::generate_output() {
+ TestResult result = execute_test_code(true);
+ if (result.status == GDTEST_LOAD_ERROR) {
+ return false;
+ }
+
+ Error err = OK;
+ FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return false;
+ }
+
+ String output = result.output.strip_edges(); // TODO: may be hacky.
+ output += "\n"; // Make sure to insert newline for CI static checks.
+
+ out_file->store_string(output);
+ out_file->close();
+
+ return true;
+}
+
+} // namespace GDScriptTests
diff --git a/modules/mono/editor/script_class_parser.h b/modules/gdscript/tests/gdscript_test_runner.h
index 75a46bb4e5..9b2d14a371 100644
--- a/modules/mono/editor/script_class_parser.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* script_class_parser.h */
+/* gdscript_test_runner.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,81 +28,99 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCRIPT_CLASS_PARSER_H
-#define SCRIPT_CLASS_PARSER_H
+#ifndef GDSCRIPT_TEST_H
+#define GDSCRIPT_TEST_H
+#include "../gdscript.h"
+#include "core/error/error_macros.h"
+#include "core/string/print_string.h"
#include "core/string/ustring.h"
#include "core/templates/vector.h"
-#include "core/variant/variant.h"
-class ScriptClassParser {
+namespace GDScriptTests {
+
+void init_autoloads();
+void init_language(const String &p_base_path);
+void finish_language();
+
+// Single test instance in a suite.
+class GDScriptTest {
public:
- struct NameDecl {
- enum Type {
- NAMESPACE_DECL,
- CLASS_DECL,
- STRUCT_DECL
- };
-
- String name;
- Type type = NAMESPACE_DECL;
+ enum TestStatus {
+ GDTEST_OK,
+ GDTEST_LOAD_ERROR,
+ GDTEST_PARSER_ERROR,
+ GDTEST_ANALYZER_ERROR,
+ GDTEST_COMPILER_ERROR,
+ GDTEST_RUNTIME_ERROR,
};
- struct ClassDecl {
- String name;
- String namespace_;
- Vector<String> base;
- bool nested = false;
+ struct TestResult {
+ TestStatus status;
+ String output;
+ bool passed;
};
private:
- String code;
- int idx = 0;
- int line = 0;
- String error_str;
- bool error = false;
- Variant value;
-
- Vector<ClassDecl> classes;
-
- enum Token {
- TK_BRACKET_OPEN,
- TK_BRACKET_CLOSE,
- TK_CURLY_BRACKET_OPEN,
- TK_CURLY_BRACKET_CLOSE,
- TK_PERIOD,
- TK_COLON,
- TK_COMMA,
- TK_SYMBOL,
- TK_IDENTIFIER,
- TK_STRING,
- TK_NUMBER,
- TK_OP_LESS,
- TK_OP_GREATER,
- TK_EOF,
- TK_ERROR,
- TK_MAX
+ struct ErrorHandlerData {
+ TestResult *result;
+ GDScriptTest *self;
+ ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) {
+ result = p_result;
+ self = p_this;
+ }
};
- static const char *token_names[TK_MAX];
- static String get_token_name(Token p_token);
+ String source_file;
+ String output_file;
+ String base_dir;
- Token get_token();
+ PrintHandlerList _print_handler;
+ ErrorHandlerList _error_handler;
- Error _skip_generic_type_params();
+ void enable_stdout();
+ void disable_stdout();
+ bool check_output(const String &p_output) const;
+ String get_text_for_status(TestStatus p_status) const;
- Error _parse_type_full_name(String &r_full_name);
- Error _parse_class_base(Vector<String> &r_base);
- Error _parse_type_constraints();
- Error _parse_namespace_name(String &r_name, int &r_curly_stack);
+ TestResult execute_test_code(bool p_is_generating);
public:
- Error parse(const String &p_code);
- Error parse_file(const String &p_filepath);
+ static void print_handler(void *p_this, const String &p_message, bool p_error);
+ static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type);
+ TestResult run_test();
+ bool generate_output();
- String get_error();
+ const String &get_source_file() const { return source_file; }
+ const String &get_output_file() const { return output_file; }
- Vector<ClassDecl> get_classes();
+ GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir);
+ GDScriptTest() :
+ GDScriptTest(String(), String(), String()) {} // Needed to use in Vector.
};
-#endif // SCRIPT_CLASS_PARSER_H
+class GDScriptTestRunner {
+ String source_dir;
+ Vector<GDScriptTest> tests;
+
+ bool is_generating = false;
+ bool do_init_languages = false;
+
+ bool make_tests();
+ bool make_tests_for_dir(const String &p_dir);
+ bool generate_class_index();
+
+public:
+ static StringName test_function_name;
+
+ static void handle_cmdline();
+ int run_tests();
+ bool generate_outputs();
+
+ GDScriptTestRunner(const String &p_source_dir, bool p_init_language);
+ ~GDScriptTestRunner();
+};
+
+} // namespace GDScriptTests
+
+#endif // GDSCRIPT_TEST_H
diff --git a/modules/etc/texture_loader_pkm.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index 67fbee3a7e..136907b316 100644
--- a/modules/etc/texture_loader_pkm.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_loader_pkm.h */
+/* gdscript_test_runner_suite.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,20 +28,26 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTURE_LOADER_PKM_H
-#define TEXTURE_LOADER_PKM_H
+#ifndef GDSCRIPT_TEST_RUNNER_SUITE_H
+#define GDSCRIPT_TEST_RUNNER_SUITE_H
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
+#include "gdscript_test_runner.h"
+#include "tests/test_macros.h"
-class ResourceFormatPKM : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+namespace GDScriptTests {
- virtual ~ResourceFormatPKM() {}
-};
+TEST_SUITE("[Modules][GDScript]") {
+ // GDScript 2.0 is still under heavy construction.
+ // Allow the tests to fail, but do not ignore errors during development.
+ // Update the scripts and expected output as needed.
+ TEST_CASE("Script compilation and runtime") {
+ GDScriptTestRunner runner("modules/gdscript/tests/scripts", true);
+ int fail_count = runner.run_tests();
+ INFO("Make sure `*.out` files have expected results.");
+ REQUIRE_MESSAGE(fail_count == 0, "All GDScript tests should pass.");
+ }
+}
-#endif // TEXTURE_LOADER_PKM_H
+} // namespace GDScriptTests
+
+#endif // GDSCRIPT_TEST_RUNNER_SUITE_H
diff --git a/modules/gdscript/tests/scripts/.gitignore b/modules/gdscript/tests/scripts/.gitignore
new file mode 100644
index 0000000000..94c5b1bf6b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/.gitignore
@@ -0,0 +1,2 @@
+# Ignore metadata if someone open this on Godot.
+/.godot
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
new file mode 100644
index 0000000000..c56ad94095
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
@@ -0,0 +1,6 @@
+func args(a, b):
+ print(a)
+ print(b)
+
+func test():
+ args(1,)
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out
new file mode 100644
index 0000000000..fc2a891109
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Too few arguments for "args()" call. Expected at least 2 but received 1.
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
new file mode 100644
index 0000000000..a1077e1985
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
@@ -0,0 +1,2 @@
+func test():
+ var a = ("missing paren ->"
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out
new file mode 100644
index 0000000000..7326afa33d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected closing ")" after grouping expression.
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
new file mode 100644
index 0000000000..62cb633e9e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
@@ -0,0 +1,3 @@
+func test():
+ if true # Missing colon here.
+ print("true")
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.out b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out
new file mode 100644
index 0000000000..687b963bc8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected ":" after "if" condition.
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
new file mode 100644
index 0000000000..116b0151da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
@@ -0,0 +1,6 @@
+func args(a, b):
+ print(a)
+ print(b)
+
+func test():
+ args(1,2
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out
new file mode 100644
index 0000000000..34ea7ac323
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected closing ")" after call arguments.
diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd
new file mode 100644
index 0000000000..9ad77f1432
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd
@@ -0,0 +1,3 @@
+func test():
+ print("Using spaces")
+ print("Using tabs")
diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
new file mode 100644
index 0000000000..6390de9788
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Used "\t" for indentation instead " " as used before in the file.
diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
new file mode 100644
index 0000000000..3875ce3936
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ var a = $ # Expected some node path.
diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
new file mode 100644
index 0000000000..b3dc181a22
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
new file mode 100644
index 0000000000..6fd2692d47
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ $23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
new file mode 100644
index 0000000000..b3dc181a22
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
new file mode 100644
index 0000000000..1836d42226
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ $MyNode/23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
new file mode 100644
index 0000000000..dcb4ccecb0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path after "/".
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
new file mode 100644
index 0000000000..08f2eedb2d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
@@ -0,0 +1,2 @@
+func test():
+ print("A"); print("B")
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
new file mode 100644
index 0000000000..fc03f3efe8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+A
+B
diff --git a/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd
new file mode 100644
index 0000000000..6097b11b10
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd
@@ -0,0 +1,7 @@
+# See https://github.com/godotengine/godot/issues/41066.
+
+func f(p, ): ## <-- no errors
+ print(p)
+
+func test():
+ f(0, ) ## <-- no error
diff --git a/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out
new file mode 100644
index 0000000000..94e2ec2af8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+0
diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
new file mode 100644
index 0000000000..3b48f10ca7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
@@ -0,0 +1,12 @@
+var a # No init.
+var b = 42 # Init.
+
+func test():
+ var c # No init, local.
+ var d = 23 # Init, local.
+
+ a = 1
+ c = 2
+
+ prints(a, b, c, d)
+ print("OK")
diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.out b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
new file mode 100644
index 0000000000..2e0a63c024
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+>> WARNING
+>> Line: 5
+>> UNASSIGNED_VARIABLE
+>> The variable 'c' was used but never assigned a value.
+1 42 2 23
+OK
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
new file mode 100644
index 0000000000..68e3bd424f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
@@ -0,0 +1,2 @@
+func test():
+ var unused = "not used"
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out
new file mode 100644
index 0000000000..270e0e69c0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'unused' is declared but never used in the block. If this is intended, prefix it with an underscore: '_unused'
diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot
new file mode 100644
index 0000000000..25b49c0abd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/project.godot
@@ -0,0 +1,10 @@
+; This is not an actual project.
+; This config only exists to properly set up the test environment.
+; It also helps for opening Godot to edit the scripts, but please don't
+; let the editor changes be saved.
+
+config_version=4
+
+[application]
+
+config/name="GDScript Integration Test Suite"
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 898ac653f5..36da64bbaa 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -47,7 +47,7 @@
#include "editor/editor_settings.h"
#endif
-namespace TestGDScript {
+namespace GDScriptTests {
static void test_tokenizer(const String &p_code, const Vector<String> &p_lines) {
GDScriptTokenizer tokenizer;
@@ -66,7 +66,7 @@ static void test_tokenizer(const String &p_code, const Vector<String> &p_lines)
StringBuilder token;
token += " --> "; // Padding for line number.
- for (int l = current.start_line; l <= current.end_line; l++) {
+ for (int l = current.start_line; l <= current.end_line && l <= p_lines.size(); l++) {
print_line(vformat("%04d %s", l, p_lines[l - 1]).replace("\t", tab));
}
@@ -119,9 +119,21 @@ static void test_parser(const String &p_code, const String &p_script_path, const
}
}
- GDScriptParser::TreePrinter printer;
+ GDScriptAnalyzer analyzer(&parser);
+ analyzer.analyze();
+
+ if (err != OK) {
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) {
+ const GDScriptParser::ParserError &error = E->get();
+ print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
+ }
+ }
+#ifdef TOOLS_ENABLED
+ GDScriptParser::TreePrinter printer;
printer.print_tree(parser);
+#endif
}
static void test_compiler(const String &p_code, const String &p_script_path, const Vector<String> &p_lines) {
@@ -175,67 +187,14 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
signature += func->get_argument_name(i);
}
print_line(signature + ")");
-
+#ifdef TOOLS_ENABLED
func->disassemble(p_lines);
+#endif
print_line("");
print_line("");
}
}
-void init_autoloads() {
- Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
- // First pass, add the constants so they exist before any script is loaded.
- for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- const ProjectSettings::AutoloadInfo &info = E->get();
-
- if (info.is_singleton) {
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
- }
- }
- }
-
- // Second pass, load into global constants.
- for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- const ProjectSettings::AutoloadInfo &info = E->get();
-
- if (!info.is_singleton) {
- // Skip non-singletons since we don't have a scene tree here anyway.
- continue;
- }
-
- RES res = ResourceLoader::load(info.path);
- ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
- Node *n = nullptr;
- if (res->is_class("PackedScene")) {
- Ref<PackedScene> ps = res;
- n = ps->instance();
- } else if (res->is_class("Script")) {
- Ref<Script> script_res = res;
- StringName ibt = script_res->get_instance_base_type();
- bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
-
- Object *obj = ClassDB::instance(ibt);
-
- ERR_CONTINUE_MSG(obj == nullptr,
- "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
- String(ibt));
-
- n = Object::cast_to<Node>(obj);
- n->set_script(script_res);
- }
-
- ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
- n->set_name(info.name);
-
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(info.name, n);
- }
- }
-}
-
void test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
@@ -252,20 +211,8 @@ void test(TestType p_type) {
FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
- // Init PackedData since it's used by ProjectSettings.
- PackedData *packed_data = memnew(PackedData);
-
- // Setup project settings since it's needed by the languages to get the global scripts.
- // This also sets up the base resource path.
- Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true);
- if (err) {
- print_line("Could not load project settings.");
- // Keep going since some scripts still work without this.
- }
-
// Initialize the language for the test routine.
- ScriptServer::init_languages();
- init_autoloads();
+ init_language(fa->get_path_absolute().get_base_dir());
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -299,8 +246,6 @@ void test(TestType p_type) {
print_line("Not implemented.");
}
- // Destroy stuff we set up earlier.
- ScriptServer::finish_languages();
- memdelete(packed_data);
+ finish_language();
}
-} // namespace TestGDScript
+} // namespace GDScriptTests
diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index bbda46cdad..c7ee5a2208 100644
--- a/modules/gdscript/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -31,7 +31,10 @@
#ifndef TEST_GDSCRIPT_H
#define TEST_GDSCRIPT_H
-namespace TestGDScript {
+#include "gdscript_test_runner.h"
+#include "tests/test_macros.h"
+
+namespace GDScriptTests {
enum TestType {
TEST_TOKENIZER,
@@ -41,6 +44,7 @@ enum TestType {
};
void test(TestType p_type);
-} // namespace TestGDScript
+
+} // namespace GDScriptTests
#endif // TEST_GDSCRIPT_H
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 545aa68747..4331daadfc 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -37,7 +37,7 @@
#include <glslang/Include/Types.h>
#include <glslang/Public/ShaderLang.h>
-static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error) {
+static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice::Capabilities *p_capabilities) {
Vector<uint8_t> ret;
ERR_FAIL_COND_V(p_language == RenderingDevice::SHADER_LANGUAGE_HLSL, ret);
@@ -51,20 +51,75 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
};
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
+ bool check_subgroup_support = true; // assume we support subgroups
- glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0;
- glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_3;
+ glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2;
+ glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
glslang::TShader::ForbidIncluder includer;
+ if (p_capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
+ if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 0) {
+ ClientVersion = glslang::EShTargetVulkan_1_0;
+ TargetVersion = glslang::EShTargetSpv_1_0;
+ check_subgroup_support = false; // subgroups are not supported in Vulkan 1.0
+ } else if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 1) {
+ ClientVersion = glslang::EShTargetVulkan_1_1;
+ TargetVersion = glslang::EShTargetSpv_1_3;
+ } else {
+ // use defaults
+ }
+ } else {
+ // once we support other backends we'll need to do something here
+ if (r_error) {
+ (*r_error) = "GLSLANG - Unsupported device family";
+ }
+ return ret;
+ }
+
glslang::TShader shader(stages[p_stage]);
CharString cs = p_source_code.ascii();
const char *cs_strings = cs.get_data();
+ std::string preamble = "";
shader.setStrings(&cs_strings, 1);
shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion);
- shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
+ shader.setEnvClient(glslang::EShClientVulkan, ClientVersion);
shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion);
+ if (check_subgroup_support) {
+ uint32_t stage_bit = 1 << p_stage;
+
+ if ((p_capabilities->subgroup_in_shaders & stage_bit) == stage_bit) {
+ // stage supports subgroups
+ preamble += "#define has_GL_KHR_shader_subgroup_basic 1\n";
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_VOTE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_vote 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_ARITHMETIC_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_arithmetic 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_BALLOT_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_ballot 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_shuffle 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_RELATIVE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_shuffle_relative 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_CLUSTERED_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_clustered 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_QUAD_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_quad 1\n";
+ }
+ }
+ }
+
+ if (preamble != "") {
+ shader.setPreamble(preamble.c_str());
+ }
+
EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
const int DefaultVersion = 100;
std::string pre_processed_code;
@@ -118,7 +173,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
ret.resize(SpirV.size() * sizeof(uint32_t));
{
uint8_t *w = ret.ptrw();
- copymem(w, &SpirV[0], SpirV.size() * sizeof(uint32_t));
+ memcpy(w, &SpirV[0], SpirV.size() * sizeof(uint32_t));
}
return ret;
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index 1505a456d7..a4ee871eff 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -4,3 +4,27 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "EditorSceneImporterGLTF",
+ "GLTFAccessor",
+ "GLTFAnimation",
+ "GLTFBufferView",
+ "GLTFCamera",
+ "GLTFDocument",
+ "GLTFLight",
+ "GLTFMesh",
+ "GLTFNode",
+ "GLTFSkeleton",
+ "GLTFSkin",
+ "GLTFSpecGloss",
+ "GLTFState",
+ "GLTFTexture",
+ "PackedSceneGLTF",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/doc/classes/EditorSceneImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
index e717b30f73..e717b30f73 100644
--- a/doc/classes/EditorSceneImporterGLTF.xml
+++ b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
diff --git a/doc/classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml
index a1f596f7dd..a1f596f7dd 100644
--- a/doc/classes/GLTFAccessor.xml
+++ b/modules/gltf/doc_classes/GLTFAccessor.xml
diff --git a/doc/classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml
index 5c1fa02f11..5c1fa02f11 100644
--- a/doc/classes/GLTFAnimation.xml
+++ b/modules/gltf/doc_classes/GLTFAnimation.xml
diff --git a/doc/classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml
index edaad85e0a..edaad85e0a 100644
--- a/doc/classes/GLTFBufferView.xml
+++ b/modules/gltf/doc_classes/GLTFBufferView.xml
diff --git a/doc/classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml
index 0b95f2c802..0b95f2c802 100644
--- a/doc/classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
diff --git a/doc/classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 04c40dd752..04c40dd752 100644
--- a/doc/classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
diff --git a/doc/classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index bfeaf9a86e..bfeaf9a86e 100644
--- a/doc/classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
diff --git a/doc/classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index 55f79d2c55..55f79d2c55 100644
--- a/doc/classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
diff --git a/doc/classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 5b7d4fadec..5b7d4fadec 100644
--- a/doc/classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
diff --git a/doc/classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index e27c838648..9680c27705 100644
--- a/doc/classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
@@ -10,7 +10,7 @@
<method name="get_bone_attachment">
<return type="BoneAttachment3D">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
diff --git a/doc/classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml
index 5a80c7097a..5a80c7097a 100644
--- a/doc/classes/GLTFSkin.xml
+++ b/modules/gltf/doc_classes/GLTFSkin.xml
diff --git a/doc/classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml
index 68cc7c845d..68cc7c845d 100644
--- a/doc/classes/GLTFSpecGloss.xml
+++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml
diff --git a/doc/classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index f7763efdb1..8255cd73d0 100644
--- a/doc/classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -16,7 +16,7 @@
<method name="get_animation_player">
<return type="AnimationPlayer">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
@@ -24,7 +24,7 @@
<method name="get_animation_players_count">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
@@ -80,7 +80,7 @@
<method name="get_scene_node">
<return type="Node">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
@@ -109,6 +109,12 @@
<description>
</description>
</method>
+ <method name="get_unique_animation_names">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_unique_names">
<return type="Array">
</return>
@@ -219,6 +225,14 @@
<description>
</description>
</method>
+ <method name="set_unique_animation_names">
+ <return type="void">
+ </return>
+ <argument index="0" name="unique_animation_names" type="Array">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_unique_names">
<return type="void">
</return>
diff --git a/doc/classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index c7f94ab0da..33bd8fddeb 100644
--- a/doc/classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="4">
+ <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0">
</member>
</members>
<constants>
diff --git a/doc/classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml
index a04c6ef0b6..a04c6ef0b6 100644
--- a/doc/classes/PackedSceneGLTF.xml
+++ b/modules/gltf/doc_classes/PackedSceneGLTF.xml
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index 6ea722a216..35f44ca122 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -99,7 +99,9 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
Ref<GLTFDocument> gltf_document;
gltf_document.instance();
Error err = gltf_document->parse(r_state, p_path);
- *r_err = err;
+ if (r_err) {
+ *r_err = err;
+ }
ERR_FAIL_COND_V(err != Error::OK, nullptr);
Node3D *root = memnew(Node3D);
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index db961e591d..af1a885f2b 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -64,8 +64,8 @@ public:
virtual void get_extensions(List<String> *r_extensions) const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
int p_bake_fps,
- List<String> *r_missing_deps = NULL,
- Error *r_err = NULL) override;
+ List<String> *r_missing_deps = nullptr,
+ Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path,
uint32_t p_flags, int p_bake_fps) override;
};
@@ -80,7 +80,7 @@ protected:
public:
virtual void save_scene(Node *p_node, const String &p_path, const String &p_src_path,
uint32_t p_flags, int p_bake_fps,
- List<String> *r_missing_deps, Error *r_err = NULL);
+ List<String> *r_missing_deps, Error *r_err = nullptr);
virtual void _build_parent_hierachy(Ref<GLTFState> state);
virtual Error export_gltf(Node *p_root, String p_path, int32_t p_flags = 0,
real_t p_bake_fps = 1000.0f);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 4868347a74..e67e29f7b4 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -63,7 +63,6 @@
#ifdef MODULE_GRIDMAP_ENABLED
#include "modules/gridmap/grid_map.h"
#endif // MODULE_GRIDMAP_ENABLED
-#include "modules/regex/regex.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
@@ -72,6 +71,7 @@
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
+#include "scene/main/node.h"
#include "scene/resources/surface_tool.h"
#include <limits>
@@ -449,14 +449,8 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
return OK;
}
-String GLTFDocument::_sanitize_scene_name(const String &name) {
- RegEx regex("([^a-zA-Z0-9_ -]+)");
- String p_name = regex.sub(name, "", true);
- return p_name;
-}
-
String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name) {
- const String s_name = _sanitize_scene_name(p_name);
+ const String s_name = p_name.validate_node_name();
String name;
int index = 1;
@@ -464,7 +458,7 @@ String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name
name = s_name;
if (index > 1) {
- name += " " + itos(index);
+ name += itos(index);
}
if (!state->unique_names.has(name)) {
break;
@@ -477,25 +471,44 @@ String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name
return name;
}
-String GLTFDocument::_sanitize_bone_name(const String &name) {
- String p_name = name.camelcase_to_underscore(true);
+String GLTFDocument::_sanitize_animation_name(const String &p_name) {
+ // Animations disallow the normal node invalid characters as well as "," and "["
+ // (See animation/animation_player.cpp::add_animation)
- RegEx pattern_nocolon(":");
- p_name = pattern_nocolon.sub(p_name, "_", true);
+ // TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node.
+ String name = p_name.validate_node_name();
+ name = name.replace(",", "");
+ name = name.replace("[", "");
+ return name;
+}
- RegEx pattern_noslash("/");
- p_name = pattern_noslash.sub(p_name, "_", true);
+String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const String &p_name) {
+ const String s_name = _sanitize_animation_name(p_name);
- RegEx pattern_nospace(" +");
- p_name = pattern_nospace.sub(p_name, "_", true);
+ String name;
+ int index = 1;
+ while (true) {
+ name = s_name;
+
+ if (index > 1) {
+ name += itos(index);
+ }
+ if (!state->unique_animation_names.has(name)) {
+ break;
+ }
+ index++;
+ }
- RegEx pattern_multiple("_+");
- p_name = pattern_multiple.sub(p_name, "_", true);
+ state->unique_animation_names.insert(name);
- RegEx pattern_padded("0+(\\d+)");
- p_name = pattern_padded.sub(p_name, "$1", true);
+ return name;
+}
- return p_name;
+String GLTFDocument::_sanitize_bone_name(const String &p_name) {
+ String name = p_name;
+ name = name.replace(":", "_");
+ name = name.replace("/", "_");
+ return name;
}
String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) {
@@ -541,10 +554,10 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
state->root_nodes.push_back(nodes[j]);
}
- if (s.has("name") && s["name"] != "") {
+ if (s.has("name") && !String(s["name"]).is_empty() && !((String)s["name"]).begins_with("Scene")) {
state->scene_name = _gen_unique_name(state, s["name"]);
} else {
- state->scene_name = _gen_unique_name(state, "Scene");
+ state->scene_name = _gen_unique_name(state, state->filename);
}
}
@@ -927,22 +940,29 @@ String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type
}
GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) {
- if (p_string == "SCALAR")
+ if (p_string == "SCALAR") {
return GLTFDocument::TYPE_SCALAR;
+ }
- if (p_string == "VEC2")
+ if (p_string == "VEC2") {
return GLTFDocument::TYPE_VEC2;
- if (p_string == "VEC3")
+ }
+ if (p_string == "VEC3") {
return GLTFDocument::TYPE_VEC3;
- if (p_string == "VEC4")
+ }
+ if (p_string == "VEC4") {
return GLTFDocument::TYPE_VEC4;
+ }
- if (p_string == "MAT2")
+ if (p_string == "MAT2") {
return GLTFDocument::TYPE_MAT2;
- if (p_string == "MAT3")
+ }
+ if (p_string == "MAT3") {
return GLTFDocument::TYPE_MAT3;
- if (p_string == "MAT4")
+ }
+ if (p_string == "MAT4") {
return GLTFDocument::TYPE_MAT4;
+ }
ERR_FAIL_V(GLTFDocument::TYPE_SCALAR);
}
@@ -1137,7 +1157,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t));
bv->byte_length = buffer.size() * sizeof(int8_t);
} break;
case COMPONENT_TYPE_UNSIGNED_BYTE: {
@@ -1183,7 +1203,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t));
bv->byte_length = buffer.size() * sizeof(int16_t);
} break;
case COMPONENT_TYPE_UNSIGNED_SHORT: {
@@ -1207,7 +1227,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t));
bv->byte_length = buffer.size() * sizeof(uint16_t);
} break;
case COMPONENT_TYPE_INT: {
@@ -1227,7 +1247,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t));
bv->byte_length = buffer.size() * sizeof(int32_t);
} break;
case COMPONENT_TYPE_FLOAT: {
@@ -1247,7 +1267,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(float)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float));
bv->byte_length = buffer.size() * sizeof(float);
} break;
}
@@ -1421,8 +1441,9 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>());
const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
} else {
//fill with zeros, as bufferview is not defined.
for (int i = 0; i < (a->count * component_count); i++) {
@@ -1437,14 +1458,16 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type);
Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
Vector<double> data;
data.resize(component_count * a->sparse_count);
err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
for (int i = 0; i < indices.size(); i++) {
const int write_offset = int(indices[i]) * component_count;
@@ -1515,8 +1538,9 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const G
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<int> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
@@ -1533,8 +1557,9 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<float> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
@@ -1807,8 +1832,9 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Vector2> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -1985,8 +2011,9 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Vector3> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -2004,8 +2031,9 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Color> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const int type = state->accessors[p_accessor]->type;
ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
@@ -2029,8 +2057,9 @@ Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Quat> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -2047,8 +2076,9 @@ Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> sta
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform2D> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
ret.resize(attribs.size() / 4);
@@ -2063,8 +2093,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Basis> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
ret.resize(attribs.size() / 9);
@@ -2080,8 +2111,9 @@ Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state,
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
ret.resize(attribs.size() / 16);
@@ -2357,9 +2389,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
for (int i = 0; i < ret_size; i++) {
Color tangent;
tangent.r = tarr[(i * 4) + 0];
- tangent.r = tarr[(i * 4) + 1];
- tangent.r = tarr[(i * 4) + 2];
- tangent.r = tarr[(i * 4) + 3];
+ tangent.g = tarr[(i * 4) + 1];
+ tangent.b = tarr[(i * 4) + 2];
+ tangent.a = tarr[(i * 4) + 3];
}
t["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
}
@@ -2436,6 +2468,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary();
Ref<EditorSceneImporterMesh> import_mesh;
import_mesh.instance();
+ String mesh_name = "mesh";
+ if (d.has("name") && !String(d["name"]).is_empty()) {
+ mesh_name = d["name"];
+ }
+ import_mesh->set_name(_gen_unique_name(state, vformat("%s_%s", state->scene_name, mesh_name)));
+
for (int j = 0; j < primitives.size(); j++) {
Dictionary p = primitives[j];
@@ -2802,7 +2840,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
ERR_CONTINUE(state->images[i].is_null());
- Ref<Image> image = state->images[i]->get_data();
+ Ref<Image> image = state->images[i]->get_image();
ERR_CONTINUE(image.is_null());
if (p_path.to_lower().ends_with("glb")) {
@@ -2819,14 +2857,14 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
Vector<uint8_t> buffer;
Ref<ImageTexture> img_tex = image;
if (img_tex.is_valid()) {
- image = img_tex->get_data();
+ image = img_tex->get_image();
}
Error err = PNGDriverCommon::image_to_png(image, buffer);
ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG.");
bv->byte_length = buffer.size();
state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length);
- copymem(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
+ memcpy(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
state->buffer_views.push_back(bv);
@@ -3027,8 +3065,9 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
- if (!state->json.has("textures"))
+ if (!state->json.has("textures")) {
return OK;
+ }
const Array &textures = state->json["textures"];
for (GLTFTextureIndex i = 0; i < textures.size(); i++) {
@@ -3049,7 +3088,7 @@ GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D>
ERR_FAIL_COND_V(p_texture.is_null(), -1);
Ref<GLTFTexture> gltf_texture;
gltf_texture.instance();
- ERR_FAIL_COND_V(p_texture->get_data().is_null(), -1);
+ ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1);
GLTFImageIndex gltf_src_image_i = state->images.size();
state->images.push_back(p_texture);
gltf_texture->set_src_image(gltf_src_image_i);
@@ -3096,7 +3135,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
GLTFTextureIndex gltf_texture_index = -1;
- if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
albedo_texture->set_name(material->get_name() + "_albedo");
gltf_texture_index = _set_texture(state, albedo_texture);
}
@@ -3109,9 +3148,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
mr["metallicFactor"] = material->get_metallic();
mr["roughnessFactor"] = material->get_roughness();
- bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_data().is_valid();
+ bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid();
bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
- bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_data().is_valid();
+ bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid();
if (has_ao || has_roughness || has_metalness) {
Dictionary mrt;
Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
@@ -3130,10 +3169,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_ao) {
height = ao_texture->get_height();
width = ao_texture->get_width();
- ao_image = ao_texture->get_data();
+ ao_image = ao_texture->get_image();
Ref<ImageTexture> img_tex = ao_image;
if (img_tex.is_valid()) {
- ao_image = img_tex->get_data();
+ ao_image = img_tex->get_image();
}
if (ao_image->is_compressed()) {
ao_image->decompress();
@@ -3143,10 +3182,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_roughness) {
height = roughness_texture->get_height();
width = roughness_texture->get_width();
- roughness_image = roughness_texture->get_data();
+ roughness_image = roughness_texture->get_image();
Ref<ImageTexture> img_tex = roughness_image;
if (img_tex.is_valid()) {
- roughness_image = img_tex->get_data();
+ roughness_image = img_tex->get_image();
}
if (roughness_image->is_compressed()) {
roughness_image->decompress();
@@ -3156,17 +3195,17 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_metalness) {
height = metallic_texture->get_height();
width = metallic_texture->get_width();
- metallness_image = metallic_texture->get_data();
+ metallness_image = metallic_texture->get_image();
Ref<ImageTexture> img_tex = metallness_image;
if (img_tex.is_valid()) {
- metallness_image = img_tex->get_data();
+ metallness_image = img_tex->get_image();
}
if (metallness_image->is_compressed()) {
metallness_image->decompress();
}
}
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
- if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
height = albedo_texture->get_height();
width = albedo_texture->get_width();
}
@@ -3247,13 +3286,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
{
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
// Code for uncompressing RG normal maps
- Ref<Image> img = normal_texture->get_data();
+ Ref<Image> img = normal_texture->get_image();
Ref<ImageTexture> img_tex = img;
if (img_tex.is_valid()) {
- img = img_tex->get_data();
+ img = img_tex->get_image();
}
img->decompress();
img->convert(Image::FORMAT_RGBA8);
+ img->convert_ra_rgba8_to_rg();
for (int32_t y = 0; y < img->get_height(); y++) {
for (int32_t x = 0; x < img->get_width(); x++) {
Color c = img->get_pixel(x, y);
@@ -3269,7 +3309,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
GLTFTextureIndex gltf_texture_index = -1;
- if (tex.is_valid() && tex->get_data().is_valid()) {
+ if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal");
gltf_texture_index = _set_texture(state, tex);
}
@@ -3292,7 +3332,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary et;
Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
GLTFTextureIndex gltf_texture_index = -1;
- if (emission_texture.is_valid() && emission_texture->get_data().is_valid()) {
+ if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) {
emission_texture->set_name(material->get_name() + "_emission");
gltf_texture_index = _set_texture(state, emission_texture);
}
@@ -3321,8 +3361,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
- if (!state->json.has("materials"))
+ if (!state->json.has("materials")) {
return OK;
+ }
const Array &materials = state->json["materials"];
for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
@@ -3330,8 +3371,10 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
Ref<StandardMaterial3D> material;
material.instance();
- if (d.has("name")) {
+ if (d.has("name") && !String(d["name"]).is_empty()) {
material->set_name(d["name"]);
+ } else {
+ material->set_name(vformat("material_%s", itos(i)));
}
material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
Dictionary pbr_spec_gloss_extensions;
@@ -3349,7 +3392,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (diffuse_texture_dict.has("index")) {
Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]);
if (diffuse_texture.is_valid()) {
- spec_gloss->diffuse_img = diffuse_texture->get_data();
+ spec_gloss->diffuse_img = diffuse_texture->get_image();
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture);
}
}
@@ -3377,7 +3420,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (spec_gloss_texture.has("index")) {
const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]);
if (orig_texture.is_valid()) {
- spec_gloss->spec_gloss_img = orig_texture->get_data();
+ spec_gloss->spec_gloss_img = orig_texture->get_image();
}
}
}
@@ -3837,8 +3880,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
}
Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
- if (!state->json.has("skins"))
+ if (!state->json.has("skins")) {
return OK;
+ }
const Array &skins = state->json["skins"];
@@ -3868,8 +3912,10 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
state->nodes.write[node]->joint = true;
}
- if (d.has("name")) {
+ if (d.has("name") && !String(d["name"]).is_empty()) {
skin->set_name(d["name"]);
+ } else {
+ skin->set_name(vformat("skin_%s", itos(i)));
}
if (d.has("skeleton")) {
@@ -4085,8 +4131,9 @@ Error GLTFDocument::_reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkelet
state->nodes.push_back(fake_joint);
// We better not be a joint, or we messed up in our logic
- if (node->joint)
+ if (node->joint) {
return FAILED;
+ }
fake_joint->translation = node->translation;
fake_joint->rotation = node->rotation;
@@ -4505,8 +4552,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
- if (!state->json.has("cameras"))
+ if (!state->json.has("cameras")) {
return OK;
+ }
const Array cameras = state->json["cameras"];
@@ -4707,8 +4755,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
- if (!state->json.has("animations"))
+ if (!state->json.has("animations")) {
return OK;
+ }
const Array &animations = state->json["animations"];
@@ -4718,8 +4767,9 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
Ref<GLTFAnimation> animation;
animation.instance();
- if (!d.has("channels") || !d.has("samplers"))
+ if (!d.has("channels") || !d.has("samplers")) {
continue;
+ }
Array channels = d["channels"];
Array samplers = d["samplers"];
@@ -4729,13 +4779,14 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) {
animation->set_loop(true);
}
- animation->set_name(_sanitize_scene_name(name));
+ animation->set_name(_gen_unique_animation_name(state, name));
}
for (int j = 0; j < channels.size(); j++) {
const Dictionary &c = channels[j];
- if (!c.has("target"))
+ if (!c.has("target")) {
continue;
+ }
const Dictionary &t = c["target"];
if (!t.has("node") || !t.has("path")) {
@@ -4845,8 +4896,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
Ref<GLTFNode> n = state->nodes[i];
// Any joints get unique names generated when the skeleton is made, unique to the skeleton
- if (n->skeleton >= 0)
+ if (n->skeleton >= 0) {
continue;
+ }
if (n->get_name().is_empty()) {
if (n->mesh >= 0) {
@@ -4907,8 +4959,8 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns
if (godot_array_mesh.is_valid()) {
surface_name = godot_array_mesh->surface_get_name(surface_i);
}
- if (p_mesh_instance->get_surface_material(surface_i).is_valid()) {
- mat = p_mesh_instance->get_surface_material(surface_i);
+ if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
+ mat = p_mesh_instance->get_surface_override_material(surface_i);
}
if (p_mesh_instance->get_material_override().is_valid()) {
mat = p_mesh_instance->get_material_override();
@@ -5492,8 +5544,9 @@ T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T>
//could use binary search, worth it?
int idx = -1;
for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time)
+ if (p_times[i] > p_time) {
break;
+ }
idx++;
}
@@ -5620,8 +5673,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->track_set_path(track_idx, node_path);
//first determine animation length
- const float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ const double increment = 1.0 / bake_fps;
+ double time = 0.0;
Vector3 base_pos;
Quat base_rot;
@@ -5711,8 +5764,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
} else {
// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
- const float increment = 1.0 / float(bake_fps);
- float time = 0.0;
+ const double increment = 1.0 / bake_fps;
+ double time = 0.0;
bool last = false;
while (true) {
_interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
@@ -6333,16 +6386,21 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
//binary file
//text file
err = _parse_glb(p_path, state);
- if (err)
+ if (err) {
return FAILED;
+ }
} else {
//text file
err = _parse_json(p_path, state);
- if (err)
+ if (err) {
return FAILED;
+ }
}
f->close();
+ // get file's name, use for scene name if none
+ state->filename = p_path.get_file().get_slice(".", 0);
+
ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED);
Dictionary asset = state->json["asset"];
@@ -6356,68 +6414,81 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
/* STEP 0 PARSE SCENE */
err = _parse_scenes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 1 PARSE NODES */
err = _parse_nodes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 2 PARSE BUFFERS */
err = _parse_buffers(state, p_path.get_base_dir());
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 3 PARSE BUFFER VIEWS */
err = _parse_buffer_views(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 4 PARSE ACCESSORS */
err = _parse_accessors(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 5 PARSE IMAGES */
err = _parse_images(state, p_path.get_base_dir());
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 6 PARSE TEXTURES */
err = _parse_textures(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 7 PARSE TEXTURES */
err = _parse_materials(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 9 PARSE SKINS */
err = _parse_skins(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 10 DETERMINE SKELETONS */
err = _determine_skeletons(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 11 CREATE SKELETONS */
err = _create_skeletons(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 12 CREATE SKINS */
err = _create_skins(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 13 PARSE MESHES (we have enough info now) */
err = _parse_meshes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 14 PARSE LIGHTS */
err = _parse_lights(state);
@@ -6427,13 +6498,15 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
/* STEP 15 PARSE CAMERAS */
err = _parse_cameras(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 16 PARSE ANIMATIONS */
err = _parse_animations(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 17 ASSIGN SCENE NAMES */
_assign_scene_names(state);
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index ddf307e6a7..bda1ce87d6 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -162,8 +162,9 @@ private:
Error _parse_nodes(Ref<GLTFState> state);
String _get_type_name(const GLTFType p_component);
String _get_accessor_type_name(const GLTFDocument::GLTFType p_type);
- String _sanitize_scene_name(const String &name);
String _gen_unique_name(Ref<GLTFState> state, const String &p_name);
+ String _sanitize_animation_name(const String &name);
+ String _gen_unique_animation_name(Ref<GLTFState> state, const String &p_name);
String _sanitize_bone_name(const String &name);
String _gen_unique_bone_name(Ref<GLTFState> state,
const GLTFSkeletonIndex skel_i,
diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp
index 739779d3bd..d6c7a25eaf 100644
--- a/modules/gltf/gltf_skeleton.cpp
+++ b/modules/gltf/gltf_skeleton.cpp
@@ -41,7 +41,7 @@ void GLTFSkeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_godot_bone_node"), &GLTFSkeleton::get_godot_bone_node);
ClassDB::bind_method(D_METHOD("set_godot_bone_node", "godot_bone_node"), &GLTFSkeleton::set_godot_bone_node);
ClassDB::bind_method(D_METHOD("get_bone_attachment_count"), &GLTFSkeleton::get_bone_attachment_count);
- ClassDB::bind_method(D_METHOD("get_bone_attachment"), &GLTFSkeleton::get_bone_attachment);
+ ClassDB::bind_method(D_METHOD("get_bone_attachment", "idx"), &GLTFSkeleton::get_bone_attachment);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp
index fd39e4f45a..5a61e5778c 100644
--- a/modules/gltf/gltf_skin.cpp
+++ b/modules/gltf/gltf_skin.cpp
@@ -142,7 +142,7 @@ void GLTFSkin::set_joint_i_to_name(Dictionary p_joint_i_to_name) {
joint_i_to_name = Map<int, StringName>();
Array keys = p_joint_i_to_name.keys();
for (int i = 0; i < keys.size(); i++) {
- joint_i_to_name[keys[i]] = joint_i_to_name[keys[i]];
+ joint_i_to_name[keys[i]] = p_joint_i_to_name[keys[i]];
}
}
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index eedc743330..ff9778e7d8 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -51,8 +51,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_accessors", "accessors"), &GLTFState::set_accessors);
ClassDB::bind_method(D_METHOD("get_meshes"), &GLTFState::get_meshes);
ClassDB::bind_method(D_METHOD("set_meshes", "meshes"), &GLTFState::set_meshes);
- ClassDB::bind_method(D_METHOD("get_animation_players_count"), &GLTFState::get_animation_players_count);
- ClassDB::bind_method(D_METHOD("get_animation_player"), &GLTFState::get_animation_player);
+ ClassDB::bind_method(D_METHOD("get_animation_players_count", "idx"), &GLTFState::get_animation_players_count);
+ ClassDB::bind_method(D_METHOD("get_animation_player", "idx"), &GLTFState::get_animation_player);
ClassDB::bind_method(D_METHOD("get_materials"), &GLTFState::get_materials);
ClassDB::bind_method(D_METHOD("set_materials", "materials"), &GLTFState::set_materials);
ClassDB::bind_method(D_METHOD("get_scene_name"), &GLTFState::get_scene_name);
@@ -71,13 +71,15 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lights", "lights"), &GLTFState::set_lights);
ClassDB::bind_method(D_METHOD("get_unique_names"), &GLTFState::get_unique_names);
ClassDB::bind_method(D_METHOD("set_unique_names", "unique_names"), &GLTFState::set_unique_names);
+ ClassDB::bind_method(D_METHOD("get_unique_animation_names"), &GLTFState::get_unique_animation_names);
+ ClassDB::bind_method(D_METHOD("set_unique_animation_names", "unique_animation_names"), &GLTFState::set_unique_animation_names);
ClassDB::bind_method(D_METHOD("get_skeletons"), &GLTFState::get_skeletons);
ClassDB::bind_method(D_METHOD("set_skeletons", "skeletons"), &GLTFState::set_skeletons);
ClassDB::bind_method(D_METHOD("get_skeleton_to_node"), &GLTFState::get_skeleton_to_node);
ClassDB::bind_method(D_METHOD("set_skeleton_to_node", "skeleton_to_node"), &GLTFState::set_skeleton_to_node);
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
- ClassDB::bind_method(D_METHOD("get_scene_node"), &GLTFState::get_scene_node);
+ ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary
ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int
@@ -98,6 +100,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "cameras", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_cameras", "get_cameras"); // Vector<Ref<GLTFCamera>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lights", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_lights", "get_lights"); // Vector<Ref<GLTFLight>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // Map<GLTFSkeletonIndex,
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
@@ -255,6 +258,14 @@ void GLTFState::set_unique_names(Array p_unique_names) {
GLTFDocument::set_from_array(unique_names, p_unique_names);
}
+Array GLTFState::get_unique_animation_names() {
+ return GLTFDocument::to_array(unique_animation_names);
+}
+
+void GLTFState::set_unique_animation_names(Array p_unique_animation_names) {
+ GLTFDocument::set_from_array(unique_animation_names, p_unique_animation_names);
+}
+
Array GLTFState::get_skeletons() {
return GLTFDocument::to_array(skeletons);
}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 4ce5aa9491..ba6bf8a533 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -53,6 +53,7 @@ class GLTFState : public Resource {
friend class GLTFDocument;
friend class PackedSceneGLTF;
+ String filename;
Dictionary json;
int major_version = 0;
int minor_version = 0;
@@ -80,6 +81,7 @@ class GLTFState : public Resource {
Vector<Ref<GLTFCamera>> cameras;
Vector<Ref<GLTFLight>> lights;
Set<String> unique_names;
+ Set<String> unique_animation_names;
Vector<Ref<GLTFSkeleton>> skeletons;
Map<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node;
@@ -147,6 +149,9 @@ public:
Array get_unique_names();
void set_unique_names(Array p_unique_names);
+ Array get_unique_animation_names();
+ void set_unique_animation_names(Array p_unique_names);
+
Array get_skeletons();
void set_skeletons(Array p_skeletons);
diff --git a/modules/gltf/gltf_texture.h b/modules/gltf/gltf_texture.h
index e1d0407fb4..4659725502 100644
--- a/modules/gltf/gltf_texture.h
+++ b/modules/gltf/gltf_texture.h
@@ -38,7 +38,7 @@ class GLTFTexture : public Resource {
GDCLASS(GLTFTexture, Resource);
private:
- GLTFImageIndex src_image;
+ GLTFImageIndex src_image = 0;
protected:
static void _bind_methods();
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 134aadb75e..9b6fa138e5 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -41,6 +41,7 @@
<return type="Array">
</return>
<description>
+ Returns an array of [ArrayMesh]es and [Transform] references of all bake meshes that exist within the current GridMap.
</description>
</method>
<method name="get_cell_item" qualifiers="const">
@@ -183,6 +184,9 @@
</method>
</methods>
<members>
+ <member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false">
+ If [code]true[/code], this GridMap bakes a navigation region.
+ </member>
<member name="cell_center_x" type="bool" setter="set_center_x" getter="get_center_x" default="true">
If [code]true[/code], grid items are centered on the X axis.
</member>
@@ -213,6 +217,9 @@
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
The assigned [MeshLibrary].
</member>
+ <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
+ The navigation layers the GridMap generates its navigable regions in.
+ </member>
</members>
<signals>
<signal name="cell_size_changed">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 323b025774..eaceaac33c 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -152,6 +152,7 @@ uint32_t GridMap::get_collision_mask() const {
}
void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -162,23 +163,44 @@ void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool GridMap::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void GridMap::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ layer |= 1 << p_bit;
} else {
- mask &= ~(1 << p_bit);
+ layer &= ~(1 << p_bit);
}
- set_collision_layer(mask);
+ set_collision_layer(layer);
}
bool GridMap::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
+void GridMap::set_bake_navigation(bool p_bake_navigation) {
+ bake_navigation = p_bake_navigation;
+ _recreate_octant_data();
+}
+
+bool GridMap::is_baking_navigation() {
+ return bake_navigation;
+}
+
+void GridMap::set_navigation_layers(uint32_t p_layers) {
+ navigation_layers = p_layers;
+ _recreate_octant_data();
+}
+
+uint32_t GridMap::get_navigation_layers() {
+ return navigation_layers;
+}
+
void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
if (!mesh_library.is_null()) {
mesh_library->unregister_owner(this);
@@ -189,7 +211,6 @@ void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
}
_recreate_octant_data();
- _change_notify("mesh_library");
}
Ref<MeshLibrary> GridMap::get_mesh_library() const {
@@ -286,7 +307,8 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) {
//create octant because it does not exist
Octant *g = memnew(Octant);
g->dirty = true;
- g->static_body = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ g->static_body = PhysicsServer3D::get_singleton()->body_create();
+ PhysicsServer3D::get_singleton()->body_set_mode(g->static_body, PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id());
PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer);
PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);
@@ -474,13 +496,15 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
Octant::NavMesh nm;
nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item);
- if (navigation) {
+ if (bake_navigation) {
RID region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh);
- NavigationServer3D::get_singleton()->region_set_transform(region, navigation->get_global_transform() * nm.xform);
- NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid());
+ NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * mesh_library->get_item_navmesh_transform(c.item));
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
nm.region = region;
}
+
g.navmesh_ids[E->get()] = nm;
}
}
@@ -491,7 +515,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
Octant::MultimeshInstance mmi;
RID mm = RS::get_singleton()->multimesh_create();
- RS::get_singleton()->multimesh_allocate(mm, E->get().size(), RS::MULTIMESH_TRANSFORM_3D);
+ RS::get_singleton()->multimesh_allocate_data(mm, E->get().size(), RS::MULTIMESH_TRANSFORM_3D);
RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid());
int idx = 0;
@@ -564,15 +588,17 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
- if (navigation && mesh_library.is_valid()) {
+ if (bake_navigation && mesh_library.is_valid()) {
for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
if (cell_map.has(F->key()) && F->get().region.is_valid() == false) {
Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F->key()].item);
if (nm.is_valid()) {
RID region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, nm);
- NavigationServer3D::get_singleton()->region_set_transform(region, navigation->get_global_transform() * F->get().xform);
- NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid());
+ NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F->get().xform);
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
+
F->get().region = region;
}
}
@@ -594,12 +620,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
}
- if (navigation) {
- for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
- if (F->get().region.is_valid()) {
- NavigationServer3D::get_singleton()->free(F->get().region);
- F->get().region = RID();
- }
+ for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
+ if (F->get().region.is_valid()) {
+ NavigationServer3D::get_singleton()->free(F->get().region);
+ F->get().region = RID();
}
}
}
@@ -635,16 +659,6 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
void GridMap::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- Node3D *c = this;
- while (c) {
- navigation = Object::cast_to<Navigation3D>(c);
- if (navigation) {
- break;
- }
-
- c = Object::cast_to<Node3D>(c->get_parent());
- }
-
last_transform = get_global_transform();
for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
@@ -679,8 +693,6 @@ void GridMap::_notification(int p_what) {
_octant_exit_world(E->key());
}
- navigation = nullptr;
-
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
//_update_octants_callback();
//_update_area_instances();
@@ -700,8 +712,6 @@ void GridMap::_update_visibility() {
return;
}
- _change_notify("visible");
-
for (Map<OctantKey, Octant *>::Element *e = octant_map.front(); e; e = e->next()) {
Octant *octant = e->value();
for (int i = 0; i < octant->multimesh_instances.size(); i++) {
@@ -709,6 +719,10 @@ void GridMap::_update_visibility() {
RS::get_singleton()->instance_set_visible(mi.instance, is_visible_in_tree());
}
}
+
+ for (int i = 0; i < baked_meshes.size(); i++) {
+ RS::get_singleton()->instance_set_visible(baked_meshes[i].instance, is_visible_in_tree());
+ }
}
void GridMap::_queue_octants_dirty() {
@@ -787,6 +801,12 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation);
+ ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation);
+
+ ClassDB::bind_method(D_METHOD("set_navigation_layers", "layers"), &GridMap::set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("get_navigation_layers"), &GridMap::get_navigation_layers);
+
ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library);
ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library);
@@ -840,6 +860,9 @@ void GridMap::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_GROUP("Navigation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
BIND_CONSTANT(INVALID_CELL_ITEM);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index e5ec4bb602..4c04d492f7 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -31,7 +31,6 @@
#ifndef GRID_MAP_H
#define GRID_MAP_H
-#include "scene/3d/navigation_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/multimesh.h"
@@ -135,6 +134,8 @@ class GridMap : public Node3D {
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ bool bake_navigation = false;
+ uint32_t navigation_layers = 1;
Transform last_transform;
@@ -145,7 +146,6 @@ class GridMap : public Node3D {
bool center_y = true;
bool center_z = true;
float cell_scale = 1.0;
- Navigation3D *navigation = nullptr;
bool clip = false;
bool clip_above = true;
@@ -223,6 +223,12 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+ void set_bake_navigation(bool p_bake_navigation);
+ bool is_baking_navigation();
+
+ void set_navigation_layers(uint32_t p_layers);
+ uint32_t get_navigation_layers();
+
void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
Ref<MeshLibrary> get_mesh_library() const;
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 565830c16f..74ae45a46e 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -386,13 +386,13 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b
}
int cell[3];
- float cell_size[3] = { node->get_cell_size().x, node->get_cell_size().y, node->get_cell_size().z };
+ Vector3 cell_size = node->get_cell_size();
for (int i = 0; i < 3; i++) {
if (i == edit_axis) {
cell[i] = edit_floor[i];
} else {
- cell[i] = inters[i] / node->get_cell_size()[i];
+ cell[i] = inters[i] / cell_size[i];
if (inters[i] < 0) {
cell[i] -= 1; // Compensate negative.
}
@@ -436,6 +436,7 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b
}
return true;
}
+
if (input_action == INPUT_PAINT) {
SetItem si;
si.position = Vector3i(cell[0], cell[1], cell[2]);
@@ -545,7 +546,7 @@ void GridMapEditor::_update_paste_indicator() {
return;
}
- Vector3 center = 0.5 * Vector3(float(node->get_center_x()), float(node->get_center_y()), float(node->get_center_z()));
+ Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z()));
Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size();
Transform xf;
xf.scale(scale);
@@ -614,13 +615,13 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() + mb->get_factor());
}
return true; // Eaten.
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
@@ -631,7 +632,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->get_alt()) {
input_action = INPUT_NONE;
- } else if (mb->get_button_index() == BUTTON_LEFT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool can_edit = (node && node->get_mesh_library().is_valid());
if (input_action == INPUT_PASTE) {
_do_paste();
@@ -646,7 +647,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
input_action = INPUT_PAINT;
set_items.clear();
}
- } else if (mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (input_action == INPUT_PASTE) {
_clear_clipboard_data();
input_action = INPUT_NONE;
@@ -665,7 +666,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true);
} else {
- if ((mb->get_button_index() == BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == BUTTON_LEFT && input_action == INPUT_PAINT)) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
undo_redo->create_action(TTR("GridMap Paint"));
for (List<SetItem>::Element *E = set_items.front(); E; E = E->next()) {
@@ -684,19 +685,19 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
return set_items.size() > 0;
}
- if (mb->get_button_index() == BUTTON_LEFT && input_action == INPUT_SELECT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) {
undo_redo->create_action("GridMap Selection");
undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);
undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);
undo_redo->commit_action();
}
- if (mb->get_button_index() == BUTTON_LEFT && input_action != INPUT_NONE) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action != INPUT_NONE) {
set_items.clear();
input_action = INPUT_NONE;
return true;
}
- if (mb->get_button_index() == BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
input_action = INPUT_NONE;
return true;
}
@@ -810,11 +811,11 @@ void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {
// Zoom in/out using Ctrl + mouse wheel
if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
size_slider->set_value(size_slider->get_value() + 0.2);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
size_slider->set_value(size_slider->get_value() - 0.2);
}
}
@@ -1172,7 +1173,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
floor->set_min(-32767);
floor->set_max(32767);
floor->set_step(1);
- floor->get_line_edit()->add_theme_constant_override("minimum_spaces", 16);
+ floor->get_line_edit()->add_theme_constant_override("minimum_character_width", 16);
spatial_editor_hb->add_child(floor);
floor->connect("value_changed", callable_mp(this, &GridMapEditor::_floor_changed));
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 82aaa492fc..9394e5c47e 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -432,10 +432,10 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
triangle_indices.resize(triangle_sort.size());
Vector<uint32_t> grid_indices;
grid_indices.resize(grid_size * grid_size * grid_size * 2);
- zeromem(grid_indices.ptrw(), grid_indices.size() * sizeof(uint32_t));
+ memset(grid_indices.ptrw(), 0, grid_indices.size() * sizeof(uint32_t));
Vector<bool> solid;
solid.resize(grid_size * grid_size * grid_size);
- zeromem(solid.ptrw(), solid.size() * sizeof(bool));
+ memset(solid.ptrw(), 0, solid.size() * sizeof(bool));
{
uint32_t *tiw = triangle_indices.ptrw();
@@ -1225,23 +1225,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
switch (p_quality) {
case BAKE_QUALITY_LOW: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/low_quality_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_ray_count");
} break;
case BAKE_QUALITY_MEDIUM: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/medium_quality_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_ray_count");
} break;
case BAKE_QUALITY_HIGH: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/high_quality_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_ray_count");
} break;
case BAKE_QUALITY_ULTRA: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/ultra_quality_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_ray_count");
} break;
}
push_constant.ray_count = CLAMP(push_constant.ray_count, 16, 8192);
- int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/gpu_lightmapper/performance/region_size")));
- int max_rays = GLOBAL_GET("rendering/gpu_lightmapper/performance/max_rays_per_pass");
+ int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size")));
+ int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass");
int x_regions = (atlas_size.width - 1) / max_region_size + 1;
int y_regions = (atlas_size.height - 1) / max_region_size + 1;
@@ -1347,23 +1347,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
switch (p_quality) {
case BAKE_QUALITY_LOW: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/low_quality_probe_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_probe_ray_count");
} break;
case BAKE_QUALITY_MEDIUM: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/medium_quality_probe_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_probe_ray_count");
} break;
case BAKE_QUALITY_HIGH: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/high_quality_probe_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_probe_ray_count");
} break;
case BAKE_QUALITY_ULTRA: {
- push_constant.ray_count = GLOBAL_GET("rendering/gpu_lightmapper/quality/ultra_quality_probe_ray_count");
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count");
} break;
}
push_constant.atlas_size[0] = probe_positions.size();
push_constant.ray_count = CLAMP(push_constant.ray_count, 16, 8192);
- int max_rays = GLOBAL_GET("rendering/gpu_lightmapper/performance/max_rays_per_probe_pass");
+ int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_probe_pass");
int ray_iterations = (push_constant.ray_count - 1) / max_rays + 1;
for (int i = 0; i < ray_iterations; i++) {
@@ -1674,7 +1674,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (probe_positions.size() > 0) {
probe_values.resize(probe_positions.size() * 9);
Vector<uint8_t> probe_data = rd->buffer_get_data(light_probe_buffer);
- copymem(probe_values.ptrw(), probe_data.ptr(), probe_data.size());
+ memcpy(probe_values.ptrw(), probe_data.ptr(), probe_data.size());
rd->free(light_probe_buffer);
#ifdef DEBUG_TEXTURES
@@ -1743,7 +1743,7 @@ Vector<Color> LightmapperRD::get_bake_probe_sh(int p_probe) const {
ERR_FAIL_INDEX_V(p_probe, probe_positions.size(), Vector<Color>());
Vector<Color> ret;
ret.resize(9);
- copymem(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9);
+ memcpy(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9);
return ret;
}
diff --git a/modules/lightmapper_rd/lm_blendseams.glsl b/modules/lightmapper_rd/lm_blendseams.glsl
index e47e5fcc51..374c48082e 100644
--- a/modules/lightmapper_rd/lm_blendseams.glsl
+++ b/modules/lightmapper_rd/lm_blendseams.glsl
@@ -7,7 +7,7 @@ triangles = "#define MODE_TRIANGLES";
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
@@ -74,7 +74,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index eb9d817f99..3dd96893fb 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -10,7 +10,7 @@ light_probes = "#define MODE_LIGHT_PROBES";
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
// One 2D local group focusing in one layer at a time, though all
// in parallel (no barriers) makes more sense than a 3D local group
diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl
index 6c2904192b..55ca193cc1 100644
--- a/modules/lightmapper_rd/lm_raster.glsl
+++ b/modules/lightmapper_rd/lm_raster.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
@@ -56,7 +56,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index a7b8c063fd..191bb3d765 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -41,18 +41,18 @@ static Lightmapper *create_lightmapper_rd() {
#endif
void register_lightmapper_rd_types() {
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/low_quality_ray_count", 16);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/medium_quality_ray_count", 64);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/high_quality_ray_count", 256);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/ultra_quality_ray_count", 1024);
- GLOBAL_DEF("rendering/gpu_lightmapper/performance/max_rays_per_pass", 32);
- GLOBAL_DEF("rendering/gpu_lightmapper/performance/region_size", 512);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 16);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 64);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 256);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_ray_count", 1024);
+ GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_pass", 32);
+ GLOBAL_DEF("rendering/lightmapping/bake_performance/region_size", 512);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/low_quality_probe_ray_count", 64);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/medium_quality_probe_ray_count", 256);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/high_quality_probe_ray_count", 512);
- GLOBAL_DEF("rendering/gpu_lightmapper/quality/ultra_quality_probe_ray_count", 2048);
- GLOBAL_DEF("rendering/gpu_lightmapper/performance/max_rays_per_probe_pass", 64);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_probe_ray_count", 64);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_probe_ray_count", 256);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512);
+ GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048);
+ GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64);
#ifndef _3D_DISABLED
ClassDB::register_class<LightmapperRD>();
Lightmapper::create_gpu = create_lightmapper_rd;
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index 73931b0365..987306af2a 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -409,7 +409,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector
int ret = mbedtls_pk_sign(&(key->pkey), type, p_hash.ptr(), size, buf, &sig_size, mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while signing: " + itos(ret));
out.resize(sig_size);
- copymem(out.ptrw(), buf, sig_size);
+ memcpy(out.ptrw(), buf, sig_size);
return out;
}
@@ -432,7 +432,7 @@ Vector<uint8_t> CryptoMbedTLS::encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_p
int ret = mbedtls_pk_encrypt(&(key->pkey), p_plaintext.ptr(), p_plaintext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while encrypting: " + itos(ret));
out.resize(size);
- copymem(out.ptrw(), buf, size);
+ memcpy(out.ptrw(), buf, size);
return out;
}
@@ -446,6 +446,6 @@ Vector<uint8_t> CryptoMbedTLS::decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_c
int ret = mbedtls_pk_decrypt(&(key->pkey), p_ciphertext.ptr(), p_ciphertext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while decrypting: " + itos(ret));
out.resize(size);
- copymem(out.ptrw(), buf, size);
+ memcpy(out.ptrw(), buf, size);
return out;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 8a6cdfb131..342ded6ea1 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -74,7 +74,7 @@ int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
if (err != OK) {
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
- copymem(buf, buffer, buffer_size);
+ memcpy(buf, buffer, buffer_size);
return buffer_size;
}
@@ -89,8 +89,8 @@ int PacketPeerMbedDTLS::_set_cookie() {
uint8_t client_id[18];
IP_Address addr = base->get_packet_address();
uint16_t port = base->get_packet_port();
- copymem(client_id, addr.get_ipv6(), 16);
- copymem(&client_id[16], (uint8_t *)&port, 2);
+ memcpy(client_id, addr.get_ipv6(), 16);
+ memcpy(&client_id[16], (uint8_t *)&port, 2);
return mbedtls_ssl_set_client_transport_id(ssl_ctx->get_context(), client_id, 18);
}
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index d7597aa435..8e40451806 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -242,7 +242,7 @@ void StreamPeerMbedTLS::poll() {
return;
}
- // We could pass NULL as second parameter, but some behaviour sanitizers doesn't seem to like that.
+ // We could pass nullptr as second parameter, but some behaviour sanitizers don't seem to like that.
// Passing a 1 byte buffer to workaround it.
uint8_t byte;
int ret = mbedtls_ssl_read(ssl_ctx->get_context(), &byte, 0);
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index 8627f71987..24ec206191 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -99,8 +99,9 @@ float AudioStreamPlaybackMP3::get_playback_position() const {
}
void AudioStreamPlaybackMP3::seek(float p_time) {
- if (!active)
+ if (!active) {
return;
+ }
if (p_time >= mp3_stream->get_length()) {
p_time = 0;
@@ -159,7 +160,8 @@ void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) {
const uint8_t *src_datar = p_data.ptr();
mp3dec_ex_t mp3d;
- mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE);
+ int err = mp3dec_ex_open_buf(&mp3d, src_datar, src_data_len, MP3D_SEEK_TO_SAMPLE);
+ ERR_FAIL_COND(err != 0);
channels = mp3d.info.channels;
sample_rate = mp3d.info.hz;
@@ -170,7 +172,7 @@ void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) {
clear_data();
data = memalloc(src_data_len);
- copymem(data, src_datar, src_data_len);
+ memcpy(data, src_datar, src_data_len);
data_len = src_data_len;
}
@@ -181,7 +183,7 @@ Vector<uint8_t> AudioStreamMP3::get_data() const {
vdata.resize(data_len);
{
uint8_t *w = vdata.ptrw();
- copymem(w, data, data_len);
+ memcpy(w, data, data_len);
}
}
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 25b110dc62..5140cfbbaf 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -153,8 +153,8 @@ void MobileVRInterface::set_position_from_sensors() {
last_magnetometer_data = magneto;
if (grav.length() < 0.1) {
- // not ideal but use our accelerometer, this will contain shakey shakey user behaviour
- // maybe look into some math but I'm guessing that if this isn't available, its because we lack the gyro sensor to actually work out
+ // not ideal but use our accelerometer, this will contain shaky user behaviour
+ // maybe look into some math but I'm guessing that if this isn't available, it's because we lack the gyro sensor to actually work out
// what a stable gravity vector is
grav = acc;
if (grav.length() > 0.1) {
@@ -181,8 +181,8 @@ void MobileVRInterface::set_position_from_sensors() {
tracking_state = XRInterface::XR_NORMAL_TRACKING;
};
- ///@TODO improve this, the magnetometer is very fidgity sometimes flipping the axis for no apparent reason (probably a bug on my part)
- // if you have a gyro + accelerometer that combo tends to be better then combining all three but without a gyro you need the magnetometer..
+ ///@TODO improve this, the magnetometer is very fidgety sometimes flipping the axis for no apparent reason (probably a bug on my part)
+ // if you have a gyro + accelerometer that combo tends to be better than combining all three but without a gyro you need the magnetometer..
if (has_magneto && has_grav && !has_gyro) {
// convert to quaternions, easier to smooth those out
Quat transform_quat(orientation);
@@ -372,7 +372,7 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons
if (initialized) {
float world_scale = xr_server->get_world_scale();
- // we don't need to check for the existence of our HMD, doesn't effect our values...
+ // we don't need to check for the existence of our HMD, doesn't affect our values...
// note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
if (p_eye == XRInterface::EYE_LEFT) {
transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
@@ -402,7 +402,7 @@ CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye,
CameraMatrix eye;
if (p_eye == XRInterface::EYE_MONO) {
- ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real cameras properties
+ ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real camera's properties
// which probably means implementing a specific class for iOS and Android. For now this is purely here as an example.
// Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface
// to position a stock standard Godot camera and have control over this.
diff --git a/modules/mono/Directory.Build.props b/modules/mono/Directory.Build.props
new file mode 100644
index 0000000000..fbf864b11b
--- /dev/null
+++ b/modules/mono/Directory.Build.props
@@ -0,0 +1,3 @@
+<Project>
+ <Import Project="$(MSBuildThisFileDirectory)\SdkPackageVersions.props" />
+</Project>
diff --git a/modules/mono/SdkPackageVersions.props b/modules/mono/SdkPackageVersions.props
new file mode 100644
index 0000000000..df3ebe581c
--- /dev/null
+++ b/modules/mono/SdkPackageVersions.props
@@ -0,0 +1,6 @@
+<Project>
+ <PropertyGroup>
+ <PackageVersion_Godot_NET_Sdk>4.0.0-dev5</PackageVersion_Godot_NET_Sdk>
+ <PackageVersion_Godot_SourceGenerators>4.0.0-dev2</PackageVersion_Godot_SourceGenerators>
+ </PropertyGroup>
+</Project>
diff --git a/modules/mono/build_scripts/godot_net_sdk_build.py b/modules/mono/build_scripts/godot_net_sdk_build.py
index 3bfba0f0f6..8c5a60d2db 100644
--- a/modules/mono/build_scripts/godot_net_sdk_build.py
+++ b/modules/mono/build_scripts/godot_net_sdk_build.py
@@ -21,6 +21,18 @@ def build_godot_net_sdk(source, target, env):
# No need to copy targets. The Godot.NET.Sdk csproj takes care of copying them.
+def get_nupkgs_versions(props_file):
+ import xml.etree.ElementTree as ET
+
+ tree = ET.parse(props_file)
+ root = tree.getroot()
+
+ return {
+ "Godot.NET.Sdk": root.find("./PropertyGroup/PackageVersion_Godot_NET_Sdk").text.strip(),
+ "Godot.SourceGenerators": root.find("./PropertyGroup/PackageVersion_Godot_SourceGenerators").text.strip(),
+ }
+
+
def build(env_mono):
assert env_mono["tools"]
@@ -30,14 +42,12 @@ def build(env_mono):
module_dir = os.getcwd()
- package_version_file = os.path.join(
- module_dir, "editor", "Godot.NET.Sdk", "Godot.NET.Sdk", "Godot.NET.Sdk_PackageVersion.txt"
- )
-
- with open(package_version_file, mode="r") as f:
- version = f.read().strip()
+ nupkgs_versions = get_nupkgs_versions(os.path.join(module_dir, "SdkPackageVersions.props"))
- target_filenames = ["Godot.NET.Sdk.%s.nupkg" % version]
+ target_filenames = [
+ "Godot.NET.Sdk.%s.nupkg" % nupkgs_versions["Godot.NET.Sdk"],
+ "Godot.SourceGenerators.%s.nupkg" % nupkgs_versions["Godot.SourceGenerators"],
+ ]
targets = [os.path.join(nupkgs_dir, filename) for filename in target_filenames]
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index bd29dc1876..09f3ea1f50 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -31,6 +31,7 @@
#include "csharp_script.h"
#include <mono/metadata/threads.h>
+#include <mono/metadata/tokentype.h>
#include <stdint.h>
#include "core/config/project_settings.h"
@@ -327,7 +328,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin
String script_template = "using " BINDINGS_NAMESPACE ";\n"
"using System;\n"
"\n"
- "public class %CLASS% : %BASE%\n"
+ "public partial class %CLASS% : %BASE%\n"
"{\n"
" // Declare member variables here. Examples:\n"
" // private int a = 2;\n"
@@ -1182,46 +1183,56 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#endif
-void CSharpLanguage::_load_scripts_metadata() {
- scripts_metadata.clear();
+void CSharpLanguage::lookup_script_for_class(GDMonoClass *p_class) {
+ if (!p_class->has_attribute(CACHED_CLASS(ScriptPathAttribute))) {
+ return;
+ }
- String scripts_metadata_filename = "scripts_metadata.";
+ MonoObject *attr = p_class->get_attribute(CACHED_CLASS(ScriptPathAttribute));
+ String path = CACHED_FIELD(ScriptPathAttribute, path)->get_string_value(attr);
-#ifdef TOOLS_ENABLED
- scripts_metadata_filename += Engine::get_singleton()->is_editor_hint() ? "editor" : "editor_player";
-#else
-#ifdef DEBUG_ENABLED
- scripts_metadata_filename += "debug";
-#else
- scripts_metadata_filename += "release";
-#endif
-#endif
+ dotnet_script_lookup_map[path] = DotNetScriptLookupInfo(
+ p_class->get_namespace(), p_class->get_name(), p_class);
+}
- String scripts_metadata_path = GodotSharpDirs::get_res_metadata_dir().plus_file(scripts_metadata_filename);
+void CSharpLanguage::lookup_scripts_in_assembly(GDMonoAssembly *p_assembly) {
+ if (p_assembly->has_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute))) {
+ MonoObject *attr = p_assembly->get_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute));
+ bool requires_lookup = CACHED_FIELD(AssemblyHasScriptsAttribute, requiresLookup)->get_bool_value(attr);
- if (FileAccess::exists(scripts_metadata_path)) {
- String old_json;
+ if (requires_lookup) {
+ // This is supported for scenarios where specifying all types would be cumbersome,
+ // such as when disabling C# source generators (for whatever reason) or when using a
+ // language other than C# that has nothing similar to source generators to automate it.
+ MonoImage *image = p_assembly->get_image();
- Error ferr = read_all_file_utf8(scripts_metadata_path, old_json);
+ int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
- ERR_FAIL_COND(ferr != OK);
+ for (int i = 1; i < rows; i++) {
+ // We don't search inner classes, only top-level.
+ MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
- Variant old_dict_var;
- String err_str;
- int err_line;
- Error json_err = JSON::parse(old_json, old_dict_var, err_str, err_line);
- if (json_err != OK) {
- ERR_PRINT("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ").");
- return;
- }
+ if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class)) {
+ continue;
+ }
- scripts_metadata = old_dict_var.operator Dictionary();
- scripts_metadata_invalidated = false;
+ GDMonoClass *current = p_assembly->get_class(mono_class);
+ if (current) {
+ lookup_script_for_class(current);
+ }
+ }
+ } else {
+ // This is the most likely scenario as we use C# source generators
+ MonoArray *script_types = (MonoArray *)CACHED_FIELD(AssemblyHasScriptsAttribute, scriptTypes)->get_value(attr);
- print_verbose("Successfully loaded scripts metadata");
- } else {
- if (!Engine::get_singleton()->is_editor_hint()) {
- ERR_PRINT("Missing scripts metadata file.");
+ int length = mono_array_length(script_types);
+
+ for (int i = 0; i < length; i++) {
+ MonoReflectionType *reftype = mono_array_get(script_types, MonoReflectionType *, i);
+ ManagedType type = ManagedType::from_reftype(reftype);
+ ERR_CONTINUE(!type.type_class);
+ lookup_script_for_class(type.type_class);
+ }
}
}
}
@@ -1300,7 +1311,7 @@ void CSharpLanguage::_on_scripts_domain_unloaded() {
}
#endif
- scripts_metadata_invalidated = true;
+ dotnet_script_lookup_map.clear();
}
#ifdef TOOLS_ENABLED
@@ -2005,24 +2016,22 @@ void CSharpInstance::connect_event_signals() {
StringName signal_name = event_signal.field->get_name();
// TODO: Use pooling for ManagedCallable instances.
- auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
- owner->connect(signal_name, Callable(event_signal_callable));
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
}
}
void CSharpInstance::disconnect_event_signals() {
- for (const Map<StringName, CSharpScript::EventSignal>::Element *E = script->event_signals.front(); E; E = E->next()) {
- const CSharpScript::EventSignal &event_signal = E->value();
-
- StringName signal_name = event_signal.field->get_name();
-
- // TODO: It would be great if we could store this EventSignalCallable on the stack.
- // The problem is that Callable memdeletes it when it's destructed...
- auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
-
- owner->disconnect(signal_name, Callable(event_signal_callable));
+ for (const List<Callable>::Element *E = connected_event_signals.front(); E; E = E->next()) {
+ const Callable &callable = E->get();
+ const EventSignalCallable *event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom());
+ owner->disconnect(event_signal_callable->get_signal(), callable);
}
+
+ connected_event_signals.clear();
}
void CSharpInstance::refcount_incremented() {
@@ -3356,45 +3365,34 @@ Error CSharpScript::reload(bool p_keep_state) {
GD_MONO_SCOPE_THREAD_ATTACH;
- GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly();
-
- if (project_assembly) {
- const Variant *script_metadata_var = CSharpLanguage::get_singleton()->get_scripts_metadata().getptr(get_path());
- if (script_metadata_var) {
- Dictionary script_metadata = script_metadata_var->operator Dictionary()["class"];
- const Variant *namespace_ = script_metadata.getptr("namespace");
- const Variant *class_name = script_metadata.getptr("class_name");
- ERR_FAIL_NULL_V(namespace_, ERR_BUG);
- ERR_FAIL_NULL_V(class_name, ERR_BUG);
- GDMonoClass *klass = project_assembly->get_class(namespace_->operator String(), class_name->operator String());
- if (klass && CACHED_CLASS(GodotObject)->is_assignable_from(klass)) {
- script_class = klass;
- }
- } else {
- // Missing script metadata. Fallback to legacy method
- script_class = project_assembly->get_object_derived_class(name);
+ const DotNetScriptLookupInfo *lookup_info =
+ CSharpLanguage::get_singleton()->lookup_dotnet_script(get_path());
+
+ if (lookup_info) {
+ GDMonoClass *klass = lookup_info->script_class;
+ if (klass) {
+ ERR_FAIL_COND_V(!CACHED_CLASS(GodotObject)->is_assignable_from(klass), FAILED);
+ script_class = klass;
}
+ }
- valid = script_class != nullptr;
+ valid = script_class != nullptr;
- if (script_class) {
+ if (script_class) {
#ifdef DEBUG_ENABLED
- print_verbose("Found class " + script_class->get_full_name() + " for script " + get_path());
+ print_verbose("Found class " + script_class->get_full_name() + " for script " + get_path());
#endif
- native = GDMonoUtils::get_class_native_base(script_class);
-
- CRASH_COND(native == nullptr);
+ native = GDMonoUtils::get_class_native_base(script_class);
- update_script_class_info(this);
+ CRASH_COND(native == nullptr);
- _update_exports();
- }
+ update_script_class_info(this);
- return OK;
+ _update_exports();
}
- return ERR_FILE_MISSING_DEPENDENCIES;
+ return OK;
}
ScriptLanguage *CSharpScript::get_language() const {
@@ -3644,7 +3642,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 85edd8b9c6..dd93a86d7a 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -66,6 +66,18 @@ TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
+struct DotNetScriptLookupInfo {
+ String class_namespace;
+ String class_name;
+ GDMonoClass *script_class = nullptr;
+
+ DotNetScriptLookupInfo() {} // Required by HashMap...
+
+ DotNetScriptLookupInfo(const String &p_class_namespace, const String &p_class_name, GDMonoClass *p_script_class) :
+ class_namespace(p_class_namespace), class_name(p_class_name), script_class(p_script_class) {
+ }
+};
+
class CSharpScript : public Script {
GDCLASS(CSharpScript, Script);
@@ -259,6 +271,8 @@ class CSharpInstance : public ScriptInstance {
Ref<CSharpScript> script;
MonoGCHandleData gchandle;
+ List<Callable> connected_event_signals;
+
bool _reference_owner_unsafe();
/*
@@ -390,16 +404,15 @@ class CSharpLanguage : public ScriptLanguage {
int lang_idx = -1;
- Dictionary scripts_metadata;
- bool scripts_metadata_invalidated = true;
+ HashMap<String, DotNetScriptLookupInfo> dotnet_script_lookup_map;
+
+ void lookup_script_for_class(GDMonoClass *p_class);
// For debug_break and debug_break_parse
int _debug_parse_err_line = -1;
String _debug_parse_err_file;
String _debug_error;
- void _load_scripts_metadata();
-
friend class GDMono;
void _on_scripts_domain_unloaded();
@@ -436,18 +449,13 @@ public:
void reload_assemblies(bool p_soft_reload);
#endif
- _FORCE_INLINE_ Dictionary get_scripts_metadata_or_nothing() {
- return scripts_metadata_invalidated ? Dictionary() : scripts_metadata;
- }
+ _FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const { return managed_callable_middleman; }
- _FORCE_INLINE_ const Dictionary &get_scripts_metadata() {
- if (scripts_metadata_invalidated) {
- _load_scripts_metadata();
- }
- return scripts_metadata;
- }
+ void lookup_scripts_in_assembly(GDMonoAssembly *p_assembly);
- _FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const { return managed_callable_middleman; }
+ const DotNetScriptLookupInfo *lookup_dotnet_script(const String &p_script_path) const {
+ return dotnet_script_lookup_map.getptr(p_script_path);
+ }
String get_name() const override;
@@ -542,7 +550,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false) override;
+ RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
void get_recognized_extensions(List<String> *p_extensions) const override;
bool handles_type(const String &p_type) const override;
String get_resource_type(const String &p_path) const override;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
index 56c0cb7703..d1868f52ef 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
@@ -2,6 +2,12 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.NET.Sdk", "Godot.NET.Sdk\Godot.NET.Sdk.csproj", "{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators", "Godot.SourceGenerators\Godot.SourceGenerators.csproj", "{32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Sample", "Godot.SourceGenerators.Sample\Godot.SourceGenerators.Sample.csproj", "{7297A614-8DF5-43DE-9EAD-99671B26BD1F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "..\..\glue\GodotSharp\GodotSharp\GodotSharp.csproj", "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -12,5 +18,17 @@ Global
{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32D31B23-2A45-4099-B4F5-95B4C8FF7D9F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7297A614-8DF5-43DE-9EAD-99671B26BD1F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
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 8304d9e321..4e9e7184da 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -8,43 +8,34 @@
<PackageId>Godot.NET.Sdk</PackageId>
<Version>4.0.0</Version>
- <PackageProjectUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</PackageProjectUrl>
+ <PackageVersion>$(PackageVersion_Godot_NET_Sdk)</PackageVersion>
+ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/editor/Godot.NET.Sdk</RepositoryUrl>
+ <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
<PackageType>MSBuildSdk</PackageType>
<PackageTags>MSBuildSdk</PackageTags>
+ <PackageLicenseExpression>MIT</PackageLicenseExpression>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
- </PropertyGroup>
- <PropertyGroup>
- <NuspecFile>Godot.NET.Sdk.nuspec</NuspecFile>
- <GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);SetNuSpecProperties</GenerateNuspecDependsOn>
+ <!-- Exclude target framework from the package dependencies as we don't include the build output -->
+ <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
+ <IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
- <Target Name="ReadGodotNETSdkVersion" BeforeTargets="BeforeBuild;BeforeRebuild;CoreCompile">
- <PropertyGroup>
- <PackageVersion>$([System.IO.File]::ReadAllText('$(ProjectDir)Godot.NET.Sdk_PackageVersion.txt').Trim())</PackageVersion>
- </PropertyGroup>
- </Target>
-
- <Target Name="SetNuSpecProperties" Condition=" Exists('$(NuspecFile)') " DependsOnTargets="ReadGodotNETSdkVersion">
- <PropertyGroup>
- <NuspecProperties>
- id=$(PackageId);
- description=$(Description);
- authors=$(Authors);
- version=$(PackageVersion);
- packagetype=$(PackageType);
- tags=$(PackageTags);
- projecturl=$(PackageProjectUrl)
- </NuspecProperties>
- </PropertyGroup>
- </Target>
+ <ItemGroup>
+ <!-- Package Sdk\Sdk.props and Sdk\Sdk.targets file -->
+ <None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" />
+ <None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" />
+ <!-- SdkPackageVersions.props -->
+ <None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk">
+ <Link>Sdk\SdkPackageVersions.props</Link>
+ </None>
+ </ItemGroup>
<Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
<PropertyGroup>
<GodotSourceRootPath>$(SolutionDir)\..\..\..\..\</GodotSourceRootPath>
<GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
</PropertyGroup>
- <Copy SourceFiles="$(OutputPath)$(PackageId).$(PackageVersion).nupkg"
- DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
+ <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
</Target>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec
deleted file mode 100644
index ba68a4da43..0000000000
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.nuspec
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<package xmlns="http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd">
- <metadata>
- <id>$id$</id>
- <version>$version$</version>
- <description>$description$</description>
- <authors>$authors$</authors>
- <owners>$authors$</owners>
- <projectUrl>$projecturl$</projectUrl>
- <requireLicenseAcceptance>false</requireLicenseAcceptance>
- <license type="expression">MIT</license>
- <licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
- <tags>$tags$</tags>
- <packageTypes>
- <packageType name="$packagetype$" />
- </packageTypes>
- <repository url="$projecturl$" />
- </metadata>
- <files>
- <file src="Sdk\**" target="Sdk" />
- </files>
-</package>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt
deleted file mode 100644
index 34749489b9..0000000000
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt
+++ /dev/null
@@ -1 +0,0 @@
-4.0.0-dev3
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 5febcf3175..0128f5c706 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
@@ -1,4 +1,6 @@
<Project>
+ <Import Project="$(MSBuildThisFileDirectory)\SdkPackageVersions.props" />
+
<PropertyGroup>
<!-- Determines if we should import Microsoft.NET.Sdk, if it wasn't already imported. -->
<GodotSdkImportsMicrosoftNetSdk Condition=" '$(UsingMicrosoftNETSdk)' != 'true' ">true</GodotSdkImportsMicrosoftNetSdk>
@@ -94,6 +96,7 @@
<DefineConstants>$(GodotDefineConstants);$(DefineConstants)</DefineConstants>
</PropertyGroup>
+ <!-- Godot API references -->
<ItemGroup>
<!--
TODO:
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index f5afd75505..92e299d2f3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -14,4 +14,9 @@
-->
<DefineConstants Condition=" '$(GodotRealTIsDouble)' == 'true' ">GODOT_REAL_T_IS_DOUBLE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
+
+ <!-- C# source generators -->
+ <ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
+ <PackageReference Include="Godot.SourceGenerators" Version="$(PackageVersion_Godot_SourceGenerators)" />
+ </ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs
new file mode 100644
index 0000000000..5eaebc4474
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs
@@ -0,0 +1,15 @@
+namespace Godot.SourceGenerators.Sample
+{
+ partial class Bar : Godot.Object
+ {
+ }
+
+ // Foo in another file
+ partial class Foo
+ {
+ }
+
+ partial class NotSameNameAsFile : Godot.Object
+ {
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs
new file mode 100644
index 0000000000..21a5bfe560
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs
@@ -0,0 +1,11 @@
+namespace Godot.SourceGenerators.Sample
+{
+ partial class Foo : Godot.Object
+ {
+ }
+
+ // Foo again in the same file
+ partial class Foo
+ {
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
new file mode 100644
index 0000000000..24f7909861
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.1</TargetFramework>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <!-- $(GodotProjectDir) would normally be defined by the Godot.NET.Sdk -->
+ <GodotProjectDir>$(MSBuildProjectDirectory)</GodotProjectDir>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <!-- The emitted files are not part of the compilation nor design.
+ They're only for peeking at the generated sources. Sometimes the
+ emitted files get corrupted, but that won't break anything. -->
+ <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
+ <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\glue\GodotSharp\GodotSharp\GodotSharp.csproj">
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\Godot.SourceGenerators\Godot.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ </ItemGroup>
+
+ <!-- This file is imported automatically when using PackageReference to
+ reference Godot.SourceGenerators, but not when using ProjectReference -->
+ <Import Project="..\Godot.SourceGenerators\Godot.SourceGenerators.props" />
+
+</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
new file mode 100644
index 0000000000..4867c986e6
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -0,0 +1,33 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Godot.SourceGenerators
+{
+ public static class Common
+ {
+ public static void ReportNonPartialGodotScriptClass(
+ GeneratorExecutionContext context,
+ ClassDeclarationSyntax cds, INamedTypeSymbol symbol
+ )
+ {
+ string message =
+ "Missing partial modifier on declaration of type '" +
+ $"{symbol.FullQualifiedName()}' which is a subclass of '{GodotClasses.Object}'";
+
+ string description = $"{message}. Subclasses of '{GodotClasses.Object}' must be " +
+ "declared with the partial modifier or annotated with the " +
+ $"attribute '{GodotClasses.DisableGodotGeneratorsAttr}'.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GODOT-G0001",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ cds.GetLocation(),
+ cds.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
new file mode 100644
index 0000000000..e16f72f43a
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -0,0 +1,89 @@
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Godot.SourceGenerators
+{
+ static class ExtensionMethods
+ {
+ public static bool TryGetGlobalAnalyzerProperty(
+ this GeneratorExecutionContext context, string property, out string? value
+ ) => context.AnalyzerConfigOptions.GlobalOptions
+ .TryGetValue("build_property." + property, out value);
+
+ private static bool InheritsFrom(this INamedTypeSymbol? symbol, string baseName)
+ {
+ if (symbol == null)
+ return false;
+
+ while (true)
+ {
+ if (symbol.ToString() == baseName)
+ {
+ return true;
+ }
+
+ if (symbol.BaseType != null)
+ {
+ symbol = symbol.BaseType;
+ continue;
+ }
+
+ break;
+ }
+
+ return false;
+ }
+
+ private static bool IsGodotScriptClass(
+ this ClassDeclarationSyntax cds, Compilation compilation,
+ out INamedTypeSymbol? symbol
+ )
+ {
+ var sm = compilation.GetSemanticModel(cds.SyntaxTree);
+
+ var classTypeSymbol = sm.GetDeclaredSymbol(cds);
+
+ if (classTypeSymbol?.BaseType == null
+ || !classTypeSymbol.BaseType.InheritsFrom(GodotClasses.Object))
+ {
+ symbol = null;
+ return false;
+ }
+
+ symbol = classTypeSymbol;
+ return true;
+ }
+
+ public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectGodotScriptClasses(
+ this IEnumerable<ClassDeclarationSyntax> source,
+ Compilation compilation
+ )
+ {
+ foreach (var cds in source)
+ {
+ if (cds.IsGodotScriptClass(compilation, out var symbol))
+ yield return (cds, symbol!);
+ }
+ }
+
+ public static bool IsPartial(this ClassDeclarationSyntax cds)
+ => cds.Modifiers.Any(SyntaxKind.PartialKeyword);
+
+ public static bool HasDisableGeneratorsAttribute(this INamedTypeSymbol symbol)
+ => symbol.GetAttributes().Any(attr =>
+ attr.AttributeClass?.ToString() == GodotClasses.DisableGodotGeneratorsAttr);
+
+ private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
+ SymbolDisplayFormat.FullyQualifiedFormat
+ .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
+
+ public static string FullQualifiedName(this INamedTypeSymbol symbol)
+ => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
+
+ public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
+ => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
new file mode 100644
index 0000000000..224d7e5b5a
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
@@ -0,0 +1,40 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ <LangVersion>8.0</LangVersion>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Description>Core C# source generator for Godot projects.</Description>
+ <Authors>Godot Engine contributors</Authors>
+
+ <PackageId>Godot.SourceGenerators</PackageId>
+ <Version>4.0.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>
+ <PackageLicenseExpression>MIT</PackageLicenseExpression>
+
+ <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build -->
+ <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency -->
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.1" PrivateAssets="all" />
+ </ItemGroup>
+ <ItemGroup>
+ <!-- Package the generator in the analyzer directory of the nuget package -->
+ <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
+
+ <!-- Package the props file -->
+ <None Include="Godot.SourceGenerators.props" Pack="true" PackagePath="build" Visible="false" />
+ </ItemGroup>
+
+ <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
+ <PropertyGroup>
+ <GodotSourceRootPath>$(SolutionDir)\..\..\..\..\</GodotSourceRootPath>
+ <GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
+ </PropertyGroup>
+ <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
+ </Target>
+</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
new file mode 100644
index 0000000000..f9b47ad5b1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
@@ -0,0 +1,7 @@
+<Project>
+ <ItemGroup>
+ <!-- $(GodotProjectDir) is defined by Godot.NET.Sdk -->
+ <CompilerVisibleProperty Include="GodotProjectDir" />
+ <CompilerVisibleProperty Include="GodotScriptPathAttributeGenerator" />
+ </ItemGroup>
+</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
new file mode 100644
index 0000000000..29e41d155a
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
@@ -0,0 +1,9 @@
+namespace Godot.SourceGenerators
+{
+ public static class GodotClasses
+ {
+ public const string Object = "Godot.Object";
+ public const string DisableGodotGeneratorsAttr = "Godot.DisableGodotGeneratorsAttribute";
+ public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute";
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
new file mode 100644
index 0000000000..a51728e221
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptPathAttributeGenerator : ISourceGenerator
+ {
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.TryGetGlobalAnalyzerProperty("GodotScriptPathAttributeGenerator", out string? toggle)
+ && toggle == "disabled")
+ {
+ return;
+ }
+
+ // NOTE: IsNullOrEmpty doesn't work well with nullable checks
+ // ReSharper disable once ReplaceWithStringIsNullOrEmpty
+ if (!context.TryGetGlobalAnalyzerProperty("GodotProjectDir", out string? godotProjectDir)
+ || godotProjectDir!.Length == 0)
+ {
+ throw new InvalidOperationException("Property 'GodotProjectDir' is null or empty.");
+ }
+
+ var godotClasses = context.Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ // Ignore inner classes
+ .Where(cds => !(cds.Parent is ClassDeclarationSyntax))
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial() || x.symbol.HasDisableGeneratorsAttribute())
+ return true;
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ )
+ // Ignore classes whose name is not the same as the file name
+ .Where(x => Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name)
+ .GroupBy(x => x.symbol)
+ .ToDictionary(g => g.Key, g => g.Select(x => x.cds));
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, godotProjectDir,
+ symbol: godotClass.Key,
+ classDeclarations: godotClass.Value);
+ }
+
+ if (godotClasses.Count <= 0)
+ return;
+
+ AddScriptTypesAssemblyAttr(context, godotClasses);
+ }
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ string godotProjectDir,
+ INamedTypeSymbol symbol,
+ IEnumerable<ClassDeclarationSyntax> classDeclarations
+ )
+ {
+ var attributes = new StringBuilder();
+
+ // Remember syntax trees for which we already added an attribute, to prevent unnecessary duplicates.
+ var attributedTrees = new List<SyntaxTree>();
+
+ foreach (var cds in classDeclarations)
+ {
+ if (attributedTrees.Contains(cds.SyntaxTree))
+ continue;
+
+ attributedTrees.Add(cds.SyntaxTree);
+
+ if (attributes.Length != 0)
+ attributes.Append("\n");
+
+ attributes.Append(@"[ScriptPathAttribute(""res://");
+ attributes.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir));
+ attributes.Append(@""")]");
+ }
+
+ string className = symbol.Name;
+
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ string uniqueName = hasNamespace ?
+ classNs + "." + className + "_ScriptPath_Generated" :
+ className + "_ScriptPath_Generated";
+
+ var source = new StringBuilder();
+
+ // using Godot;
+ // namespace {classNs} {
+ // {attributesBuilder}
+ // partial class {className} { }
+ // }
+
+ source.Append("using Godot;\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ source.Append(attributes);
+ source.Append("\n partial class ");
+ source.Append(className);
+ source.Append("\n{\n}\n");
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueName, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
+ Dictionary<INamedTypeSymbol, IEnumerable<ClassDeclarationSyntax>> godotClasses)
+ {
+ var sourceBuilder = new StringBuilder();
+
+ sourceBuilder.Append("[assembly:");
+ sourceBuilder.Append(GodotClasses.AssemblyHasScriptsAttr);
+ sourceBuilder.Append("(new System.Type[] {");
+
+ bool first = true;
+
+ foreach (var godotClass in godotClasses)
+ {
+ var qualifiedName = godotClass.Key.ToDisplayString(
+ NullableFlowState.NotNull, SymbolDisplayFormat.FullyQualifiedFormat);
+ if (!first)
+ sourceBuilder.Append(", ");
+ first = false;
+ sourceBuilder.Append("typeof(");
+ sourceBuilder.Append(qualifiedName);
+ sourceBuilder.Append(")");
+ }
+
+ sourceBuilder.Append("})]\n");
+
+ context.AddSource("AssemblyScriptTypes_Generated",
+ SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
+ }
+
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ private static string RelativeToDir(string path, string dir)
+ {
+ // Make sure the directory ends with a path separator
+ dir = Path.Combine(dir, " ").TrimEnd();
+
+ if (Path.DirectorySeparatorChar == '\\')
+ dir = dir.Replace("/", "\\") + "\\";
+
+ var fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
+ var relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);
+
+ // MakeRelativeUri converts spaces to %20, hence why we need UnescapeDataString
+ return Uri.UnescapeDataString(relRoot.MakeRelativeUri(fullPath).ToString());
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index 4e2c0f17cc..cdac9acb25 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -1,11 +1,5 @@
using System;
-using GodotTools.Core;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
using Microsoft.Build.Construction;
-using Microsoft.Build.Globbing;
namespace GodotTools.ProjectEditor
{
@@ -31,47 +25,6 @@ namespace GodotTools.ProjectEditor
return root != null ? new MSBuildProject(root) : null;
}
- private static List<string> GetAllFilesRecursive(string rootDirectory, string mask)
- {
- string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories);
-
- // We want relative paths
- for (int i = 0; i < files.Length; i++)
- {
- files[i] = files[i].RelativeToPath(rootDirectory);
- }
-
- return new List<string>(files);
- }
-
- // NOTE: Assumes auto-including items. Only used by the scripts metadata generator, which will be replaced with source generators in the future.
- public static IEnumerable<string> GetIncludeFiles(string projectPath, string itemType)
- {
- var excluded = new List<string>();
- var includedFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs");
-
- var root = ProjectRootElement.Open(projectPath);
- Debug.Assert(root != null);
-
- foreach (var item in root.Items)
- {
- if (string.IsNullOrEmpty(item.Condition))
- continue;
-
- if (item.ItemType != itemType)
- continue;
-
- string normalizedRemove = item.Remove.NormalizePath();
-
- var glob = MSBuildGlob.Parse(normalizedRemove);
- excluded.AddRange(includedFiles.Where(includedFile => glob.IsMatch(includedFile)));
- }
-
- includedFiles.RemoveAll(f => excluded.Contains(f));
-
- return includedFiles;
- }
-
public static void MigrateToProjectSdksStyle(MSBuildProject project, string projectName)
{
var origRoot = project.Root;
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
index 1d382dcb43..aab2d73bdd 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
@@ -3,7 +3,6 @@
<Target Name="SetPropertiesForGenerateGodotNupkgsVersions">
<PropertyGroup>
- <GodotNETSdkPackageVersionFile>$(SolutionDir)..\Godot.NET.Sdk\Godot.NET.Sdk\Godot.NET.Sdk_PackageVersion.txt</GodotNETSdkPackageVersionFile>
<GeneratedGodotNupkgsVersionsFile>$(IntermediateOutputPath)GodotNupkgsVersions.g.cs</GeneratedGodotNupkgsVersionsFile>
</PropertyGroup>
</Target>
@@ -18,13 +17,14 @@
</Target>
<Target Name="_GenerateGodotNupkgsVersionsFile"
DependsOnTargets="SetPropertiesForGenerateGodotNupkgsVersions"
- Inputs="$(MSBuildProjectFile);@(GodotNETSdkPackageVersionFile)"
+ Inputs="$(MSBuildProjectFile);$(MSBuildThisFileDirectory);$(MSBuildProjectFile)\..\..\..\SdkPackageVersions.props"
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
<PropertyGroup>
<GenerateGodotNupkgsVersionsCode><![CDATA[
namespace $(RootNamespace) {
public class GeneratedGodotNupkgsVersions {
- public const string GodotNETSdk = "$([System.IO.File]::ReadAllText('$(GodotNETSdkPackageVersionFile)').Trim())"%3b
+ public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
+ public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
}
}
]]></GenerateGodotNupkgsVersionsCode>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index b96b0c8175..2b6f972529 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -218,43 +218,12 @@ namespace GodotTools.Build
Godot.GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
- GenerateEditorScriptMetadata();
-
if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
return true; // Requested play from an external editor/IDE which already built the project
return BuildProjectBlocking("Debug");
}
- // NOTE: This will be replaced with C# source generators in 4.0
- public static void GenerateEditorScriptMetadata()
- {
- string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
- string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");
-
- CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);
-
- if (!File.Exists(editorScriptsMetadataPath))
- return;
-
- try
- {
- File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
- }
- catch (IOException e)
- {
- throw new IOException("Failed to copy scripts metadata file.", innerException: e);
- }
- }
-
- // NOTE: This will be replaced with C# source generators in 4.0
- public static string GenerateExportedGameScriptMetadata(bool isDebug)
- {
- string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
- CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
- return scriptsMetadataPath;
- }
-
public static void Initialize()
{
// Build tool settings
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 708ec73454..ed69c2b833 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -43,8 +43,6 @@ namespace GodotTools.Build
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
- BuildManager.GenerateEditorScriptMetadata();
-
if (!BuildManager.BuildProjectBlocking("Debug"))
return; // Build failed
@@ -74,8 +72,6 @@ namespace GodotTools.Build
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
- BuildManager.GenerateEditorScriptMetadata();
-
if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Rebuild"}))
return; // Build failed
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index 793ef7fd71..16dd1c8c6b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -290,7 +290,8 @@ namespace GodotTools.Build
private static readonly (string packageId, string packageVersion)[] PackagesToAdd =
{
- ("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk)
+ ("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
+ ("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
};
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
index 1d800b8151..e43f10804d 100644
--- a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
@@ -1,11 +1,6 @@
using Godot;
using System;
-using System.Linq;
-using Godot.Collections;
-using GodotTools.Internals;
using GodotTools.ProjectEditor;
-using File = GodotTools.Utils.File;
-using Directory = GodotTools.Utils.Directory;
namespace GodotTools
{
@@ -23,86 +18,5 @@ namespace GodotTools
return string.Empty;
}
}
-
- private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-
- private static ulong ConvertToTimestamp(this DateTime value)
- {
- TimeSpan elapsedTime = value - Epoch;
- return (ulong)elapsedTime.TotalSeconds;
- }
-
- private static bool TryParseFileMetadata(string includeFile, ulong modifiedTime, out Dictionary fileMetadata)
- {
- fileMetadata = null;
-
- var parseError = ScriptClassParser.ParseFile(includeFile, out var classes, out string errorStr);
-
- if (parseError != Error.Ok)
- {
- GD.PushError($"Failed to determine namespace and class for script: {includeFile}. Parse error: {errorStr ?? parseError.ToString()}");
- return false;
- }
-
- string searchName = System.IO.Path.GetFileNameWithoutExtension(includeFile);
-
- var firstMatch = classes.FirstOrDefault(classDecl =>
- classDecl.BaseCount != 0 && // If it doesn't inherit anything, it can't be a Godot.Object.
- classDecl.SearchName == searchName // Filter by the name we're looking for
- );
-
- if (firstMatch == null)
- return false; // Not found
-
- fileMetadata = new Dictionary
- {
- ["modified_time"] = $"{modifiedTime}",
- ["class"] = new Dictionary
- {
- ["namespace"] = firstMatch.Namespace,
- ["class_name"] = firstMatch.Name,
- ["nested"] = firstMatch.Nested
- }
- };
-
- return true;
- }
-
- public static void GenerateScriptsMetadata(string projectPath, string outputPath)
- {
- var metadataDict = Internal.GetScriptsMetadataOrNothing().Duplicate();
-
- bool IsUpToDate(string includeFile, ulong modifiedTime)
- {
- return metadataDict.TryGetValue(includeFile, out var oldFileVar) &&
- ulong.TryParse(((Dictionary)oldFileVar)["modified_time"] as string,
- out ulong storedModifiedTime) && storedModifiedTime == modifiedTime;
- }
-
- var outdatedFiles = ProjectUtils.GetIncludeFiles(projectPath, "Compile")
- .Select(path => ("res://" + path).SimplifyGodotPath())
- .ToDictionary(path => path, path => File.GetLastWriteTime(path).ConvertToTimestamp())
- .Where(pair => !IsUpToDate(includeFile: pair.Key, modifiedTime: pair.Value))
- .ToArray();
-
- foreach (var pair in outdatedFiles)
- {
- metadataDict.Remove(pair.Key);
-
- string includeFile = pair.Key;
-
- if (TryParseFileMetadata(includeFile, modifiedTime: pair.Value, out var fileMetadata))
- metadataDict[includeFile] = fileMetadata;
- }
-
- string json = metadataDict.Count <= 0 ? "{}" : JSON.Print(metadataDict);
-
- string baseDir = outputPath.GetBaseDir();
-
- if (!Directory.Exists(baseDir))
- Directory.CreateDirectory(baseDir);
-
- File.WriteAllText(outputPath, json);
- }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index e9bb701562..270be8b6bf 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -157,9 +157,6 @@ namespace GodotTools.Export
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
- string scriptsMetadataPath = BuildManager.GenerateExportedGameScriptMetadata(isDebug);
- AddFile(scriptsMetadataPath, scriptsMetadataPath);
-
if (!BuildManager.BuildProjectBlocking(buildConfig, platform: platform))
throw new Exception("Failed to build project");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 7e5049e4b7..77370090ec 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -1,7 +1,5 @@
-using System;
using System.Runtime.CompilerServices;
using Godot;
-using Godot.Collections;
using GodotTools.IdeMessaging.Requests;
namespace GodotTools.Internals
@@ -42,9 +40,6 @@ namespace GodotTools.Internals
public static void EditorNodeShowScriptScreen() => internal_EditorNodeShowScriptScreen();
- public static Dictionary<string, object> GetScriptsMetadataOrNothing() =>
- internal_GetScriptsMetadataOrNothing(typeof(Dictionary<string, object>));
-
public static string MonoWindowsInstallRoot => internal_MonoWindowsInstallRoot();
public static void EditorRunPlay() => internal_EditorRunPlay();
@@ -101,9 +96,6 @@ namespace GodotTools.Internals
private static extern void internal_EditorNodeShowScriptScreen();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern Dictionary<string, object> internal_GetScriptsMetadataOrNothing(Type dictType);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
private static extern string internal_MonoWindowsInstallRoot();
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs
deleted file mode 100644
index c72a84c513..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/ScriptClassParser.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using Godot;
-using Godot.Collections;
-
-namespace GodotTools.Internals
-{
- public static class ScriptClassParser
- {
- public class ClassDecl
- {
- public string Name { get; }
- public string Namespace { get; }
- public bool Nested { get; }
- public long BaseCount { get; }
-
- public string SearchName => Nested ?
- Name.Substring(Name.LastIndexOf(".", StringComparison.Ordinal) + 1) :
- Name;
-
- public ClassDecl(string name, string @namespace, bool nested, long baseCount)
- {
- Name = name;
- Namespace = @namespace;
- Nested = nested;
- BaseCount = baseCount;
- }
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern Error internal_ParseFile(string filePath, Array<Dictionary> classes, out string errorStr);
-
- public static Error ParseFile(string filePath, out IEnumerable<ClassDecl> classes, out string errorStr)
- {
- var classesArray = new Array<Dictionary>();
- var error = internal_ParseFile(filePath, classesArray, out errorStr);
- if (error != Error.Ok)
- {
- classes = null;
- return error;
- }
-
- var classesList = new List<ClassDecl>();
-
- foreach (var classDeclDict in classesArray)
- {
- classesList.Add(new ClassDecl(
- (string)classDeclDict["name"],
- (string)classDeclDict["namespace"],
- (bool)classDeclDict["nested"],
- (long)classDeclDict["base_count"]
- ));
- }
-
- classes = classesList;
-
- return Error.Ok;
- }
- }
-}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 38e403b2e1..b48e5df9eb 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -39,6 +39,7 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/string/ucaps.h"
+#include "main/main.h"
#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_defs.h"
@@ -783,6 +784,72 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
}
}
+void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
+ p_output.append("using System;\n\n");
+ p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ // The class where we put the extensions doesn't matter, so just use "GD".
+ p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+
+#define ARRAY_IS_EMPTY(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Returns true if this " #m_type " array is empty or doesn't exist.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array check.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>Whether or not the array is empty.</returns>\n"); \
+ p_output.append(INDENT2 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return instance == null || instance.Length == 0;\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_JOIN(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Converts this " #m_type " array to a string delimited by the given string.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"delimiter\">The delimiter to use between items.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT2 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return String.Join(delimiter, instance);\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_STRINGIFY(m_type) \
+ p_output.append("\n" INDENT2 "/// <summary>\n"); \
+ p_output.append(INDENT2 "/// Converts this " #m_type " array to a string with brackets.\n"); \
+ p_output.append(INDENT2 "/// </summary>\n"); \
+ p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT2 "public static string Stringify(this " #m_type "[] instance)\n"); \
+ p_output.append(INDENT2 OPEN_BLOCK); \
+ p_output.append(INDENT3 "return \"[\" + instance.Join() + \"]\";\n"); \
+ p_output.append(INDENT2 CLOSE_BLOCK);
+
+#define ARRAY_ALL(m_type) \
+ ARRAY_IS_EMPTY(m_type) \
+ ARRAY_JOIN(m_type) \
+ ARRAY_STRINGIFY(m_type)
+
+ ARRAY_ALL(byte);
+ ARRAY_ALL(int);
+ ARRAY_ALL(long);
+ ARRAY_ALL(float);
+ ARRAY_ALL(double);
+ ARRAY_ALL(string);
+ ARRAY_ALL(Color);
+ ARRAY_ALL(Vector2);
+ ARRAY_ALL(Vector2i);
+ ARRAY_ALL(Vector3);
+ ARRAY_ALL(Vector3i);
+
+#undef ARRAY_ALL
+#undef ARRAY_IS_EMPTY
+#undef ARRAY_JOIN
+#undef ARRAY_STRINGIFY
+
+ p_output.append(INDENT1 CLOSE_BLOCK); // End of GD class.
+ p_output.append(CLOSE_BLOCK); // End of namespace.
+}
+
void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
// Constants (in partial GD class)
@@ -926,6 +993,19 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
+ // Generate source file for array extensions
+ {
+ StringBuilder extensions_source;
+ _generate_array_extensions(extensions_source);
+ String output_file = path::join(base_gen_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_extensions.cs");
+ Error save_err = _save_file(output_file, extensions_source);
+ if (save_err != OK) {
+ return save_err;
+ }
+
+ compile_items.push_back(output_file);
+ }
+
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
const TypeInterface &itype = E.get();
@@ -1479,6 +1559,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
ERR_FAIL_COND_V_MSG(prop_itype->is_singleton, ERR_BUG,
"Property type is a singleton: '" + p_itype.name + "." + String(p_iprop.cname) + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(prop_itype->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Property '" + p_itype.name + "." + String(p_iprop.cname) + "' has type '" + prop_itype->name +
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
@@ -1575,6 +1661,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
ERR_FAIL_COND_V_MSG(return_type->is_singleton, ERR_BUG,
"Method return type is a singleton: '" + p_itype.name + "." + p_imethod.name + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(return_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Method '" + p_itype.name + "." + p_imethod.name + "' has return type '" + return_type->name +
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
String method_bind_field = "__method_bind_" + itos(p_method_bind_count);
String arguments_sig;
@@ -1593,6 +1685,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(arg_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Argument '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "' has type '" +
+ arg_type->name + "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+
if (iarg.default_argument.size()) {
CRASH_COND_MSG(!_arg_default_value_is_assignable_to_type(iarg.def_param_value, *arg_type),
"Invalid default value for parameter '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1806,7 +1904,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
- "Argument type is a singleton: '" + iarg.name + "' of signal" + p_itype.name + "." + p_isignal.name + "'.");
+ "Argument type is a singleton: '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "'.");
+
+ if (p_itype.api_type == ClassDB::API_CORE) {
+ ERR_FAIL_COND_V_MSG(arg_type->api_type == ClassDB::API_EDITOR, ERR_BUG,
+ "Argument '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "' has type '" +
+ arg_type->name + "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
// Add the current arguments to the signature
@@ -2932,9 +3036,9 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
}
break;
case Variant::FLOAT:
-#ifndef REAL_T_IS_DOUBLE
- r_iarg.default_argument += "f";
-#endif
+ if (r_iarg.type.cname == name_cache.type_float) {
+ r_iarg.default_argument += "f";
+ }
break;
case Variant::STRING:
case Variant::STRING_NAME:
@@ -2947,23 +3051,32 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
}
break;
- case Variant::TRANSFORM:
- if (p_val.operator Transform() == Transform()) {
- r_iarg.default_argument.clear();
- }
- r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")";
+ case Variant::PLANE: {
+ Plane plane = p_val.operator Plane();
+ r_iarg.default_argument = "new Plane(new Vector3(" + plane.normal.operator String() + "), " + rtos(plane.d) + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
- break;
- case Variant::PLANE:
- case Variant::AABB:
+ } break;
+ case Variant::AABB: {
+ AABB aabb = p_val.operator ::AABB();
+ r_iarg.default_argument = "new AABB(new Vector3(" + aabb.position.operator String() + "), new Vector3(" + aabb.position.operator String() + "))";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
+ case Variant::RECT2: {
+ Rect2 rect = p_val.operator Rect2();
+ r_iarg.default_argument = "new Rect2(new Vector2(" + rect.position.operator String() + "), new Vector2(" + rect.position.operator String() + "))";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
+ case Variant::RECT2I: {
+ Rect2i rect = p_val.operator Rect2i();
+ r_iarg.default_argument = "new Rect2i(new Vector2i(" + rect.position.operator String() + "), new Vector2i(" + rect.position.operator String() + "))";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
case Variant::COLOR:
- r_iarg.default_argument = "new Color(1, 1, 1, 1)";
+ r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
break;
case Variant::VECTOR2:
case Variant::VECTOR2I:
- case Variant::RECT2:
- case Variant::RECT2I:
case Variant::VECTOR3:
case Variant::VECTOR3I:
r_iarg.default_argument = "new %s" + r_iarg.default_argument;
@@ -3001,12 +3114,43 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "new %s {}";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
break;
- case Variant::TRANSFORM2D:
- case Variant::BASIS:
- case Variant::QUAT:
- r_iarg.default_argument = Variant::get_type_name(p_val.get_type()) + ".Identity";
+ case Variant::TRANSFORM2D: {
+ Transform2D transform = p_val.operator Transform2D();
+ if (transform == Transform2D()) {
+ r_iarg.default_argument = "Transform2D.Identity";
+ } else {
+ r_iarg.default_argument = "new Transform2D(new Vector2" + transform.elements[0].operator String() + ", new Vector2" + transform.elements[1].operator String() + ", new Vector2" + transform.elements[2].operator String() + ")";
+ }
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
- break;
+ } break;
+ case Variant::TRANSFORM: {
+ Transform transform = p_val.operator Transform();
+ if (transform == Transform()) {
+ r_iarg.default_argument = "Transform.Identity";
+ } else {
+ Basis basis = transform.basis;
+ r_iarg.default_argument = "new Transform(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")";
+ }
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
+ case Variant::BASIS: {
+ Basis basis = p_val.operator Basis();
+ if (basis == Basis()) {
+ r_iarg.default_argument = "Basis.Identity";
+ } else {
+ r_iarg.default_argument = "new Basis(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ")";
+ }
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
+ case Variant::QUAT: {
+ Quat quat = p_val.operator Quat();
+ if (quat == Quat()) {
+ r_iarg.default_argument = "Quat.Identity";
+ } else {
+ r_iarg.default_argument = "new Quat" + quat.operator String();
+ }
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ } break;
case Variant::CALLABLE:
case Variant::SIGNAL:
CRASH_NOW_MSG("Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value.");
@@ -3487,11 +3631,44 @@ void BindingsGenerator::_initialize() {
initialized = true;
}
+static String generate_all_glue_option = "--generate-mono-glue";
+static String generate_cs_glue_option = "--generate-mono-cs-glue";
+static String generate_cpp_glue_option = "--generate-mono-cpp-glue";
+
+static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, String cpp_dir_path) {
+ BindingsGenerator bindings_generator;
+ bindings_generator.set_log_print_enabled(true);
+
+ if (!bindings_generator.is_initialized()) {
+ ERR_PRINT("Failed to initialize the bindings generator");
+ return;
+ }
+
+ if (glue_dir_path.length()) {
+ if (bindings_generator.generate_glue(glue_dir_path) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
+ }
+
+ if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
+ }
+ }
+
+ if (cs_dir_path.length()) {
+ if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
+ ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
+ }
+ }
+
+ if (cpp_dir_path.length()) {
+ if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
+ ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
+ }
+ }
+}
+
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
const int NUM_OPTIONS = 2;
- String generate_all_glue_option = "--generate-mono-glue";
- String generate_cs_glue_option = "--generate-mono-cs-glue";
- String generate_cpp_glue_option = "--generate-mono-cpp-glue";
String glue_dir_path;
String cs_dir_path;
@@ -3499,6 +3676,8 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
int options_left = NUM_OPTIONS;
+ bool exit_godot = false;
+
const List<String>::Element *elem = p_cmdline_args.front();
while (elem && options_left) {
@@ -3510,6 +3689,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue').");
+ exit_godot = true;
}
--options_left;
@@ -3521,6 +3701,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_cs_glue_option + ": No output directory specified.");
+ exit_godot = true;
}
--options_left;
@@ -3532,6 +3713,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_cpp_glue_option + ": No output directory specified.");
+ exit_godot = true;
}
--options_left;
@@ -3541,37 +3723,13 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
}
if (glue_dir_path.length() || cs_dir_path.length() || cpp_dir_path.length()) {
- BindingsGenerator bindings_generator;
- bindings_generator.set_log_print_enabled(true);
-
- if (!bindings_generator.initialized) {
- ERR_PRINT("Failed to initialize the bindings generator");
- ::exit(0);
- }
-
- if (glue_dir_path.length()) {
- if (bindings_generator.generate_glue(glue_dir_path) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
- }
-
- if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
- }
- }
-
- if (cs_dir_path.length()) {
- if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
- ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
- }
- }
-
- if (cpp_dir_path.length()) {
- if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
- ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
- }
- }
+ handle_cmdline_options(glue_dir_path, cs_dir_path, cpp_dir_path);
+ exit_godot = true;
+ }
+ if (exit_godot) {
// Exit once done
+ Main::cleanup(true);
::exit(0);
}
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index b18dfb0ec4..876046176b 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -661,6 +661,7 @@ class BindingsGenerator {
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);
+ void _generate_array_extensions(StringBuilder &p_output);
void _generate_global_constants(StringBuilder &p_output);
Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output);
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 667e4a3879..21efd58938 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -49,7 +49,6 @@
#include "../utils/osx_utils.h"
#include "code_completion.h"
#include "godotsharp_export.h"
-#include "script_class_parser.h"
MonoString *godot_icall_GodotSharpDirs_ResDataDir() {
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_data_dir());
@@ -172,36 +171,6 @@ MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_st
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes, MonoString **r_error_str) {
- *r_error_str = nullptr;
-
- String filepath = GDMonoMarshal::mono_string_to_godot(p_filepath);
-
- ScriptClassParser scp;
- Error err = scp.parse_file(filepath);
- if (err == OK) {
- Array classes = GDMonoMarshal::mono_object_to_variant(p_classes);
- const Vector<ScriptClassParser::ClassDecl> &class_decls = scp.get_classes();
-
- for (int i = 0; i < class_decls.size(); i++) {
- const ScriptClassParser::ClassDecl &classDecl = class_decls[i];
-
- Dictionary classDeclDict;
- classDeclDict["name"] = classDecl.name;
- classDeclDict["namespace"] = classDecl.namespace_;
- classDeclDict["nested"] = classDecl.nested;
- classDeclDict["base_count"] = classDecl.base.size();
- classes.push_back(classDeclDict);
- }
- } else {
- String error_str = scp.get_error();
- if (!error_str.is_empty()) {
- *r_error_str = GDMonoMarshal::mono_string_from_godot(error_str);
- }
- }
- return err;
-}
-
uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_assemblies,
MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_assembly_dependencies) {
Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_assemblies);
@@ -289,18 +258,6 @@ void godot_icall_Internal_EditorNodeShowScriptScreen() {
EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
}
-MonoObject *godot_icall_Internal_GetScriptsMetadataOrNothing(MonoReflectionType *p_dict_reftype) {
- Dictionary maybe_metadata = CSharpLanguage::get_singleton()->get_scripts_metadata_or_nothing();
-
- MonoType *dict_type = mono_reflection_type_get_type(p_dict_reftype);
-
- int type_encoding = mono_type_get_type(dict_type);
- MonoClass *type_class_raw = mono_class_from_mono_type(dict_type);
- GDMonoClass *type_class = GDMono::get_singleton()->get_class(type_class_raw);
-
- return GDMonoMarshal::variant_to_mono_object(maybe_metadata, ManagedType(type_encoding, type_class));
-}
-
MonoString *godot_icall_Internal_MonoWindowsInstallRoot() {
#ifdef WINDOWS_ENABLED
String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
@@ -395,9 +352,6 @@ void register_editor_internal_calls() {
GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
- // ScriptClassParser
- GDMonoUtils::add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", godot_icall_ScriptClassParser_ParseFile);
-
// ExportPlugin
GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
@@ -416,7 +370,6 @@ void register_editor_internal_calls() {
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", godot_icall_Internal_GetScriptsMetadataOrNothing);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 4b858c0e82..54dbaebf38 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -91,7 +91,7 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *re
mono_assembly_get_assemblyref(image, i, reusable_aname);
- GDMonoAssembly *ref_assembly = NULL;
+ GDMonoAssembly *ref_assembly = nullptr;
if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) {
ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
}
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
deleted file mode 100644
index e81cbe4ebd..0000000000
--- a/modules/mono/editor/script_class_parser.cpp
+++ /dev/null
@@ -1,753 +0,0 @@
-/*************************************************************************/
-/* script_class_parser.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "script_class_parser.h"
-
-#include "core/os/os.h"
-#include "core/templates/map.h"
-
-#include "../utils/string_utils.h"
-
-const char *ScriptClassParser::token_names[ScriptClassParser::TK_MAX] = {
- "[",
- "]",
- "{",
- "}",
- ".",
- ":",
- ",",
- "Symbol",
- "Identifier",
- "String",
- "Number",
- "<",
- ">",
- "EOF",
- "Error"
-};
-
-String ScriptClassParser::get_token_name(ScriptClassParser::Token p_token) {
- ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>");
- return token_names[p_token];
-}
-
-ScriptClassParser::Token ScriptClassParser::get_token() {
- while (true) {
- switch (code[idx]) {
- case '\n': {
- line++;
- idx++;
- break;
- };
- case 0: {
- return TK_EOF;
- } break;
- case '{': {
- idx++;
- return TK_CURLY_BRACKET_OPEN;
- };
- case '}': {
- idx++;
- return TK_CURLY_BRACKET_CLOSE;
- };
- case '[': {
- idx++;
- return TK_BRACKET_OPEN;
- };
- case ']': {
- idx++;
- return TK_BRACKET_CLOSE;
- };
- case '<': {
- idx++;
- return TK_OP_LESS;
- };
- case '>': {
- idx++;
- return TK_OP_GREATER;
- };
- case ':': {
- idx++;
- return TK_COLON;
- };
- case ',': {
- idx++;
- return TK_COMMA;
- };
- case '.': {
- idx++;
- return TK_PERIOD;
- };
- case '#': {
- //compiler directive
- while (code[idx] != '\n' && code[idx] != 0) {
- idx++;
- }
- continue;
- } break;
- case '/': {
- switch (code[idx + 1]) {
- case '*': { // block comment
- idx += 2;
- while (true) {
- if (code[idx] == 0) {
- error_str = "Unterminated comment";
- error = true;
- return TK_ERROR;
- } else if (code[idx] == '*' && code[idx + 1] == '/') {
- idx += 2;
- break;
- } else if (code[idx] == '\n') {
- line++;
- }
-
- idx++;
- }
-
- } break;
- case '/': { // line comment skip
- while (code[idx] != '\n' && code[idx] != 0) {
- idx++;
- }
-
- } break;
- default: {
- value = "/";
- idx++;
- return TK_SYMBOL;
- }
- }
-
- continue; // a comment
- } break;
- case '\'':
- case '"': {
- bool verbatim = idx != 0 && code[idx - 1] == '@';
-
- char32_t begin_str = code[idx];
- idx++;
- String tk_string = String();
- while (true) {
- if (code[idx] == 0) {
- error_str = "Unterminated String";
- error = true;
- return TK_ERROR;
- } else if (code[idx] == begin_str) {
- if (verbatim && code[idx + 1] == '"') { // '""' is verbatim string's '\"'
- idx += 2; // skip next '"' as well
- continue;
- }
-
- idx += 1;
- break;
- } else if (code[idx] == '\\' && !verbatim) {
- //escaped characters...
- idx++;
- char32_t next = code[idx];
- if (next == 0) {
- error_str = "Unterminated String";
- error = true;
- return TK_ERROR;
- }
- char32_t res = 0;
-
- switch (next) {
- case 'b':
- res = 8;
- break;
- case 't':
- res = 9;
- break;
- case 'n':
- res = 10;
- break;
- case 'f':
- res = 12;
- break;
- case 'r':
- res = 13;
- break;
- case '\"':
- res = '\"';
- break;
- case '\\':
- res = '\\';
- break;
- default: {
- res = next;
- } break;
- }
-
- tk_string += res;
-
- } else {
- if (code[idx] == '\n') {
- line++;
- }
- tk_string += code[idx];
- }
- idx++;
- }
-
- value = tk_string;
-
- return TK_STRING;
- } break;
- default: {
- if (code[idx] <= 32) {
- idx++;
- break;
- }
-
- if ((code[idx] >= 33 && code[idx] <= 47) || (code[idx] >= 58 && code[idx] <= 63) || (code[idx] >= 91 && code[idx] <= 94) || code[idx] == 96 || (code[idx] >= 123 && code[idx] <= 127)) {
- value = String::chr(code[idx]);
- idx++;
- return TK_SYMBOL;
- }
-
- if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
- //a number
- const char32_t *rptr;
- double number = String::to_float(&code[idx], &rptr);
- idx += (rptr - &code[idx]);
- value = number;
- return TK_NUMBER;
-
- } else if ((code[idx] == '@' && code[idx + 1] != '"') || code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
- String id;
-
- id += code[idx];
- idx++;
-
- while (code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || (code[idx] >= '0' && code[idx] <= '9') || code[idx] > 127) {
- id += code[idx];
- idx++;
- }
-
- value = id;
- return TK_IDENTIFIER;
- } else if (code[idx] == '@' && code[idx + 1] == '"') {
- // begin of verbatim string
- idx++;
- } else {
- error_str = "Unexpected character.";
- error = true;
- return TK_ERROR;
- }
- }
- }
- }
-}
-
-Error ScriptClassParser::_skip_generic_type_params() {
- Token tk;
-
- while (true) {
- tk = get_token();
-
- if (tk == TK_IDENTIFIER) {
- tk = get_token();
- // Type specifications can end with "?" to denote nullable types, such as IList<int?>
- if (tk == TK_SYMBOL) {
- tk = get_token();
- if (value.operator String() != "?") {
- error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found unexpected symbol '" + value + "'";
- error = true;
- return ERR_PARSE_ERROR;
- }
- if (tk != TK_OP_GREATER && tk != TK_COMMA) {
- error_str = "Nullable type symbol '?' is only allowed after an identifier, but found " + get_token_name(tk) + " next.";
- error = true;
- return ERR_PARSE_ERROR;
- }
- }
-
- if (tk == TK_PERIOD) {
- while (true) {
- tk = get_token();
-
- if (tk != TK_IDENTIFIER) {
- error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- tk = get_token();
-
- if (tk != TK_PERIOD) {
- break;
- }
- }
- }
-
- if (tk == TK_OP_LESS) {
- Error err = _skip_generic_type_params();
- if (err) {
- return err;
- }
- tk = get_token();
- }
-
- if (tk == TK_OP_GREATER) {
- return OK;
- } else if (tk != TK_COMMA) {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
- } else if (tk == TK_OP_LESS) {
- error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS);
- error = true;
- return ERR_PARSE_ERROR;
- } else if (tk == TK_OP_GREATER) {
- return OK;
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
- }
-}
-
-Error ScriptClassParser::_parse_type_full_name(String &r_full_name) {
- Token tk = get_token();
-
- if (tk != TK_IDENTIFIER) {
- error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- r_full_name += String(value);
-
- if (code[idx] == '<') {
- idx++;
-
- // We don't mind if the base is generic, but we skip it any ways since this information is not needed
- Error err = _skip_generic_type_params();
- if (err) {
- return err;
- }
- }
-
- if (code[idx] != '.') { // We only want to take the next token if it's a period
- return OK;
- }
-
- tk = get_token();
-
- CRASH_COND(tk != TK_PERIOD); // Assertion
-
- r_full_name += ".";
-
- return _parse_type_full_name(r_full_name);
-}
-
-Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
- String name;
-
- Error err = _parse_type_full_name(name);
- if (err) {
- return err;
- }
-
- Token tk = get_token();
-
- if (tk == TK_COMMA) {
- err = _parse_class_base(r_base);
- if (err) {
- return err;
- }
- } else if (tk == TK_IDENTIFIER && String(value) == "where") {
- err = _parse_type_constraints();
- if (err) {
- return err;
- }
-
- // An open curly bracket was parsed by _parse_type_constraints, so we can exit
- } else if (tk == TK_CURLY_BRACKET_OPEN) {
- // we are finished when we hit the open curly bracket
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- r_base.push_back(name);
-
- return OK;
-}
-
-Error ScriptClassParser::_parse_type_constraints() {
- Token tk = get_token();
- if (tk != TK_IDENTIFIER) {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- tk = get_token();
- if (tk != TK_COLON) {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- while (true) {
- tk = get_token();
- if (tk == TK_IDENTIFIER) {
- if (String(value) == "where") {
- return _parse_type_constraints();
- }
-
- tk = get_token();
- if (tk == TK_PERIOD) {
- while (true) {
- tk = get_token();
-
- if (tk != TK_IDENTIFIER) {
- error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- tk = get_token();
-
- if (tk != TK_PERIOD) {
- break;
- }
- }
- }
- }
-
- if (tk == TK_COMMA) {
- continue;
- } else if (tk == TK_IDENTIFIER && String(value) == "where") {
- return _parse_type_constraints();
- } else if (tk == TK_SYMBOL && String(value) == "(") {
- tk = get_token();
- if (tk != TK_SYMBOL || String(value) != ")") {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
- } else if (tk == TK_OP_LESS) {
- Error err = _skip_generic_type_params();
- if (err) {
- return err;
- }
- } else if (tk == TK_CURLY_BRACKET_OPEN) {
- return OK;
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
- }
-}
-
-Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
- Token tk = get_token();
-
- if (tk == TK_IDENTIFIER) {
- r_name += String(value);
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- tk = get_token();
-
- if (tk == TK_PERIOD) {
- r_name += ".";
- return _parse_namespace_name(r_name, r_curly_stack);
- } else if (tk == TK_CURLY_BRACKET_OPEN) {
- r_curly_stack++;
- return OK;
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
-}
-
-Error ScriptClassParser::parse(const String &p_code) {
- code = p_code;
- idx = 0;
- line = 0;
- error_str = String();
- error = false;
- value = Variant();
- classes.clear();
-
- Token tk = get_token();
-
- Map<int, NameDecl> name_stack;
- int curly_stack = 0;
- int type_curly_stack = 0;
-
- while (!error && tk != TK_EOF) {
- String identifier = value;
- if (tk == TK_IDENTIFIER && (identifier == "class" || identifier == "struct")) {
- bool is_class = identifier == "class";
-
- tk = get_token();
-
- if (tk == TK_IDENTIFIER) {
- String name = value;
- int at_level = curly_stack;
-
- ClassDecl class_decl;
-
- for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) {
- const NameDecl &name_decl = E->value();
-
- if (name_decl.type == NameDecl::NAMESPACE_DECL) {
- if (E != name_stack.front()) {
- class_decl.namespace_ += ".";
- }
- class_decl.namespace_ += name_decl.name;
- } else {
- class_decl.name += name_decl.name + ".";
- }
- }
-
- class_decl.name += name;
- class_decl.nested = type_curly_stack > 0;
-
- bool generic = false;
-
- while (true) {
- tk = get_token();
-
- if (tk == TK_COLON) {
- Error err = _parse_class_base(class_decl.base);
- if (err) {
- return err;
- }
-
- curly_stack++;
- type_curly_stack++;
-
- break;
- } else if (tk == TK_CURLY_BRACKET_OPEN) {
- curly_stack++;
- type_curly_stack++;
- break;
- } else if (tk == TK_OP_LESS && !generic) {
- generic = true;
-
- Error err = _skip_generic_type_params();
- if (err) {
- return err;
- }
- } else if (tk == TK_IDENTIFIER && String(value) == "where") {
- Error err = _parse_type_constraints();
- if (err) {
- return err;
- }
-
- // An open curly bracket was parsed by _parse_type_constraints, so we can exit
- curly_stack++;
- type_curly_stack++;
- break;
- } else {
- error_str = "Unexpected token: " + get_token_name(tk);
- error = true;
- return ERR_PARSE_ERROR;
- }
- }
-
- NameDecl name_decl;
- name_decl.name = name;
- name_decl.type = is_class ? NameDecl::CLASS_DECL : NameDecl::STRUCT_DECL;
- name_stack[at_level] = name_decl;
-
- if (is_class) {
- if (!generic) { // no generics, thanks
- classes.push_back(class_decl);
- } else if (OS::get_singleton()->is_stdout_verbose()) {
- String full_name = class_decl.namespace_;
- if (full_name.length()) {
- full_name += ".";
- }
- full_name += class_decl.name;
- OS::get_singleton()->print("Ignoring generic class declaration: %s\n", full_name.utf8().get_data());
- }
- }
- }
- } else if (tk == TK_IDENTIFIER && identifier == "namespace") {
- if (type_curly_stack > 0) {
- error_str = "Found namespace nested inside type.";
- error = true;
- return ERR_PARSE_ERROR;
- }
-
- String name;
- int at_level = curly_stack;
-
- Error err = _parse_namespace_name(name, curly_stack);
- if (err) {
- return err;
- }
-
- NameDecl name_decl;
- name_decl.name = name;
- name_decl.type = NameDecl::NAMESPACE_DECL;
- name_stack[at_level] = name_decl;
- } else if (tk == TK_CURLY_BRACKET_OPEN) {
- curly_stack++;
- } else if (tk == TK_CURLY_BRACKET_CLOSE) {
- curly_stack--;
- if (name_stack.has(curly_stack)) {
- if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL) {
- type_curly_stack--;
- }
- name_stack.erase(curly_stack);
- }
- }
-
- tk = get_token();
- }
-
- if (!error && tk == TK_EOF && curly_stack > 0) {
- error_str = "Reached EOF with missing close curly brackets.";
- error = true;
- }
-
- if (error) {
- return ERR_PARSE_ERROR;
- }
-
- return OK;
-}
-
-static String get_preprocessor_directive(const String &p_line, int p_from) {
- CRASH_COND(p_line[p_from] != '#');
- p_from++;
- int i = p_from;
- while (i < p_line.length() && (p_line[i] == '_' || (p_line[i] >= 'A' && p_line[i] <= 'Z') ||
- (p_line[i] >= 'a' && p_line[i] <= 'z') || p_line[i] > 127)) {
- i++;
- }
- return p_line.substr(p_from, i - p_from);
-}
-
-static void run_dummy_preprocessor(String &r_source, const String &p_filepath) {
- Vector<String> lines = r_source.split("\n", /* p_allow_empty: */ true);
-
- bool *include_lines = memnew_arr(bool, lines.size());
-
- int if_level = -1;
- Vector<bool> is_branch_being_compiled;
-
- for (int i = 0; i < lines.size(); i++) {
- const String &line = lines[i];
-
- const int line_len = line.length();
-
- int j;
- for (j = 0; j < line_len; j++) {
- if (line[j] != ' ' && line[j] != '\t') {
- if (line[j] == '#') {
- // First non-whitespace char of the line is '#'
- include_lines[i] = false;
-
- String directive = get_preprocessor_directive(line, j);
-
- if (directive == "if") {
- if_level++;
- is_branch_being_compiled.push_back(if_level == 0 || is_branch_being_compiled[if_level - 1]);
- } else if (directive == "elif") {
- ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#elif' directive. File: '" + p_filepath + "'.");
- is_branch_being_compiled.write[if_level] = false;
- } else if (directive == "else") {
- ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#else' directive. File: '" + p_filepath + "'.");
- is_branch_being_compiled.write[if_level] = false;
- } else if (directive == "endif") {
- ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#endif' directive. File: '" + p_filepath + "'.");
- is_branch_being_compiled.remove(if_level);
- if_level--;
- }
-
- break;
- } else {
- // First non-whitespace char of the line is not '#'
- include_lines[i] = if_level == -1 || is_branch_being_compiled[if_level];
- break;
- }
- }
- }
-
- if (j == line_len) {
- // Loop ended without finding a non-whitespace character.
- // Either the line was empty or it only contained whitespaces.
- include_lines[i] = if_level == -1 || is_branch_being_compiled[if_level];
- }
- }
-
- r_source.clear();
-
- // Custom join ignoring lines removed by the preprocessor
- for (int i = 0; i < lines.size(); i++) {
- if (i > 0 && include_lines[i - 1]) {
- r_source += '\n';
- }
-
- if (include_lines[i]) {
- r_source += lines[i];
- }
- }
-}
-
-Error ScriptClassParser::parse_file(const String &p_filepath) {
- String source;
-
- Error ferr = read_all_file_utf8(p_filepath, source);
-
- ERR_FAIL_COND_V_MSG(ferr != OK, ferr,
- ferr == ERR_INVALID_DATA ?
- "File '" + p_filepath + "' contains invalid unicode (UTF-8), so it was not loaded."
- " Please ensure that scripts are saved in valid UTF-8 unicode." :
- "Failed to read file: '" + p_filepath + "'.");
-
- run_dummy_preprocessor(source, p_filepath);
-
- return parse(source);
-}
-
-String ScriptClassParser::get_error() {
- return error_str;
-}
-
-Vector<ScriptClassParser::ClassDecl> ScriptClassParser::get_classes() {
- return classes;
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
new file mode 100644
index 0000000000..ef135da51a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Assembly)]
+ public class AssemblyHasScriptsAttribute : Attribute
+ {
+ private readonly bool requiresLookup;
+ private readonly System.Type[] scriptTypes;
+
+ public AssemblyHasScriptsAttribute()
+ {
+ requiresLookup = true;
+ }
+
+ public AssemblyHasScriptsAttribute(System.Type[] scriptTypes)
+ {
+ requiresLookup = false;
+ this.scriptTypes = scriptTypes;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
new file mode 100644
index 0000000000..ac6cffceb2
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class DisableGodotGeneratorsAttribute : Attribute
+ {
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
new file mode 100644
index 0000000000..12eb1035c3
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class ScriptPathAttribute : Attribute
+ {
+ private string path;
+
+ public ScriptPathAttribute(string path)
+ {
+ this.path = path;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
new file mode 100644
index 0000000000..763f470504
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
@@ -0,0 +1,27 @@
+namespace Godot
+{
+ public partial class PackedScene
+ {
+ /// <summary>
+ /// Instantiates the scene's node hierarchy, erroring on failure.
+ /// Triggers child scene instantiation(s). Triggers a
+ /// `Node.NotificationInstanced` notification on the root node.
+ /// </summary>
+ /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam>
+ public T Instance<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class
+ {
+ return (T)(object)Instance(editState);
+ }
+
+ /// <summary>
+ /// Instantiates the scene's node hierarchy, returning null on failure.
+ /// Triggers child scene instantiation(s). Triggers a
+ /// `Node.NotificationInstanced` notification on the root node.
+ /// </summary>
+ /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam>
+ public T InstanceOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class
+ {
+ return Instance(editState) as T;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
index 5f64c09a89..74fa05d1fd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
@@ -2,7 +2,7 @@ namespace Godot
{
public static partial class ResourceLoader
{
- public static T Load<T>(string path, string typeHint = null, bool noCache = false) where T : class
+ public static T Load<T>(string path, string typeHint = null, CacheMode noCache = CacheMode.Reuse) where T : class
{
return (T)(object)Load(path, typeHint, noCache);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs
new file mode 100644
index 0000000000..702a6c76ba
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Godot
+{
+ public static partial class GD
+ {
+ /// <summary>
+ /// Fires when an unhandled exception occurs, regardless of project settings.
+ /// </summary>
+ public static event EventHandler<UnhandledExceptionArgs> UnhandledException;
+
+ private static void OnUnhandledException(Exception e)
+ {
+ UnhandledException?.Invoke(null, new UnhandledExceptionArgs(e));
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs
new file mode 100644
index 0000000000..be01674568
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Event arguments for when unhandled exceptions occur.
+ /// </summary>
+ public class UnhandledExceptionArgs
+ {
+ /// <summary>
+ /// Exception object
+ /// </summary>
+ public Exception Exception { get; private set; }
+
+ internal UnhandledExceptionArgs(Exception exception)
+ {
+ Exception = exception;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 42dbdf25c3..3b895bbbf6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -111,10 +111,10 @@ namespace Godot
}
/// <summary>
- /// Returns the minimum angle to the given vector, in radians.
+ /// Returns the unsigned minimum angle to the given vector, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
+ /// <returns>The unsigned angle between the two vectors, in radians.</returns>
public real_t AngleTo(Vector3 to)
{
return Mathf.Atan2(Cross(to).Length(), Dot(to));
@@ -469,6 +469,23 @@ namespace Godot
}
/// <summary>
+ /// Returns the signed angle to the given vector, in radians.
+ /// The sign of the angle is positive in a counter-clockwise
+ /// direction and negative in a clockwise direction when viewed
+ /// from the side specified by the `axis`.
+ /// </summary>
+ /// <param name="to">The other vector to compare this vector to.</param>
+ /// <param name="axis">The reference axis to use for the angle sign.</param>
+ /// <returns>The signed angle between the two vectors, in radians.</returns>
+ public real_t SignedAngleTo(Vector3 to, Vector3 axis)
+ {
+ Vector3 crossTo = Cross(to);
+ real_t unsignedAngle = Mathf.Atan2(crossTo.Length(), Dot(to));
+ real_t sign = crossTo.Dot(axis);
+ return (sign < 0) ? -unsignedAngle : unsignedAngle;
+ }
+
+ /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this vector and `to` by amount `weight`.
///
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 86a16c17f1..54aaaf1f92 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -14,9 +14,12 @@
<ItemGroup>
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Array.cs" />
+ <Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
+ <Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.cs" />
<Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
<Compile Include="Core\Attributes\RPCAttributes.cs" />
+ <Compile Include="Core\Attributes\ScriptPathAttribute.cs" />
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
<Compile Include="Core\Basis.cs" />
@@ -30,12 +33,14 @@
<Compile Include="Core\DynamicObject.cs" />
<Compile Include="Core\Extensions\NodeExtensions.cs" />
<Compile Include="Core\Extensions\ObjectExtensions.cs" />
+ <Compile Include="Core\Extensions\PackedSceneExtensions.cs" />
<Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" />
<Compile Include="Core\Extensions\SceneTreeExtensions.cs" />
<Compile Include="Core\GD.cs" />
<Compile Include="Core\GodotSynchronizationContext.cs" />
<Compile Include="Core\GodotTaskScheduler.cs" />
<Compile Include="Core\GodotTraceListener.cs" />
+ <Compile Include="Core\GodotUnhandledExceptionEvent.cs" />
<Compile Include="Core\Interfaces\IAwaitable.cs" />
<Compile Include="Core\Interfaces\IAwaiter.cs" />
<Compile Include="Core\Interfaces\ISerializationListener.cs" />
@@ -55,6 +60,7 @@
<Compile Include="Core\StringName.cs" />
<Compile Include="Core\Transform.cs" />
<Compile Include="Core\Transform2D.cs" />
+ <Compile Include="Core\UnhandledExceptionArgs.cs" />
<Compile Include="Core\Vector2.cs" />
<Compile Include="Core\Vector2i.cs" />
<Compile Include="Core\Vector3.cs" />
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index a39a6fe381..020a40575c 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -179,16 +179,16 @@ private:
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
- data_editor_tools_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Tools");
+ data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools");
}
if (!DirAccess::exists(data_editor_prebuilt_api_dir)) {
- data_editor_prebuilt_api_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Api");
+ data_editor_prebuilt_api_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
}
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib");
+ data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
}
#endif
@@ -218,11 +218,11 @@ private:
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib");
+ data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
}
if (!DirAccess::exists(data_game_assemblies_dir)) {
- data_game_assemblies_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Assemblies");
+ data_game_assemblies_dir = exe_dir.plus_file("../Resources/GodotSharp/Assemblies");
}
#endif
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 43a39a4966..c523d381f6 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -119,11 +119,11 @@ void gd_mono_profiler_init() {
const String env_var_name = "MONO_ENV_OPTIONS";
if (OS::get_singleton()->has_environment(env_var_name)) {
- const auto mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
+ const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
// Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467
const String prefix = "--profile=";
if (mono_env_ops.begins_with(prefix)) {
- const auto ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
+ const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
mono_profiler_load(ops.utf8());
}
}
@@ -1006,6 +1006,7 @@ bool GDMono::_load_project_assembly() {
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
+ CSharpLanguage::get_singleton()->lookup_scripts_in_assembly(project_assembly);
}
return success;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 1fe06bfbee..a1556bace5 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -345,6 +345,45 @@ String GDMonoAssembly::get_path() const {
return String::utf8(mono_image_get_filename(image));
}
+bool GDMonoAssembly::has_attribute(GDMonoClass *p_attr_class) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_NULL_V(p_attr_class, false);
+#endif
+
+ if (!attrs_fetched) {
+ fetch_attributes();
+ }
+
+ if (!attributes) {
+ return false;
+ }
+
+ return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
+}
+
+MonoObject *GDMonoAssembly::get_attribute(GDMonoClass *p_attr_class) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_NULL_V(p_attr_class, nullptr);
+#endif
+
+ if (!attrs_fetched) {
+ fetch_attributes();
+ }
+
+ if (!attributes) {
+ return nullptr;
+ }
+
+ return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
+}
+
+void GDMonoAssembly::fetch_attributes() {
+ ERR_FAIL_COND(attributes != nullptr);
+
+ attributes = mono_custom_attrs_from_assembly(assembly);
+ attrs_fetched = true;
+}
+
GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
ERR_FAIL_NULL_V(image, nullptr);
@@ -390,70 +429,6 @@ GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
return wrapped_class;
}
-GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) {
- GDMonoClass *match = nullptr;
-
- if (gdobject_class_cache_updated) {
- Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class);
-
- if (result) {
- match = result->get();
- }
- } else {
- List<GDMonoClass *> nested_classes;
-
- int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
-
- for (int i = 1; i < rows; i++) {
- MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
-
- if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class)) {
- continue;
- }
-
- GDMonoClass *current = get_class(mono_class);
-
- if (!current) {
- continue;
- }
-
- nested_classes.push_back(current);
-
- if (!match && current->get_name() == p_class) {
- match = current;
- }
-
- while (!nested_classes.is_empty()) {
- GDMonoClass *current_nested = nested_classes.front()->get();
- nested_classes.pop_front();
-
- void *iter = nullptr;
-
- while (true) {
- MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_mono_ptr(), &iter);
-
- if (!raw_nested) {
- break;
- }
-
- GDMonoClass *nested_class = get_class(raw_nested);
-
- if (nested_class) {
- gdobject_class_cache.insert(nested_class->get_name(), nested_class);
- nested_classes.push_back(nested_class);
- }
- }
- }
-
- gdobject_class_cache.insert(current->get_name(), current);
- }
-
- gdobject_class_cache_updated = true;
- }
-
- return match;
-}
-
GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
if (GDMono::get_singleton()->get_corlib_assembly() && (p_name == "mscorlib" || p_name == "mscorlib.dll")) {
return GDMono::get_singleton()->get_corlib_assembly();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 350fcf3210..6191c491f4 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -71,13 +71,13 @@ class GDMonoAssembly {
MonoImage *image;
MonoAssembly *assembly;
+ bool attrs_fetched = false;
+ MonoCustomAttrInfo *attributes = nullptr;
+
#ifdef GD_MONO_HOT_RELOAD
uint64_t modified_time = 0;
#endif
- bool gdobject_class_cache_updated = false;
- Map<StringName, GDMonoClass *> gdobject_class_cache;
-
HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
Map<MonoClass *, GDMonoClass *> cached_raw;
@@ -111,11 +111,14 @@ public:
String get_path() const;
+ bool has_attribute(GDMonoClass *p_attr_class);
+ MonoObject *get_attribute(GDMonoClass *p_attr_class);
+
+ void fetch_attributes();
+
GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
GDMonoClass *get_class(MonoClass *p_mono_class);
- GDMonoClass *get_object_derived_class(const StringName &p_class);
-
static String find_assembly(const String &p_name);
static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index aea467660f..d66cc29b9a 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -148,6 +148,11 @@ void CachedData::clear_godot_api_cache() {
class_PuppetSyncAttribute = nullptr;
class_GodotMethodAttribute = nullptr;
field_GodotMethodAttribute_methodName = nullptr;
+ class_ScriptPathAttribute = nullptr;
+ field_ScriptPathAttribute_path = nullptr;
+ class_AssemblyHasScriptsAttribute = nullptr;
+ field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
+ field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
field_GodotObject_ptr = nullptr;
field_StringName_ptr = nullptr;
@@ -272,6 +277,11 @@ void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute));
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
+ CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
+ CACHE_FIELD_AND_CHECK(ScriptPathAttribute, path, CACHED_CLASS(ScriptPathAttribute)->get_field("path"));
+ CACHE_CLASS_AND_CHECK(AssemblyHasScriptsAttribute, GODOT_API_CLASS(AssemblyHasScriptsAttribute));
+ CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, requiresLookup, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("requiresLookup"));
+ CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes"));
CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
CACHE_FIELD_AND_CHECK(StringName, ptr, CACHED_CLASS(StringName)->get_field(BINDINGS_PTR_FIELD));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index fb75cb4b1c..51370da452 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -119,6 +119,11 @@ struct CachedData {
GDMonoClass *class_PuppetSyncAttribute;
GDMonoClass *class_GodotMethodAttribute;
GDMonoField *field_GodotMethodAttribute_methodName;
+ GDMonoClass *class_ScriptPathAttribute;
+ GDMonoField *field_ScriptPathAttribute_path;
+ GDMonoClass *class_AssemblyHasScriptsAttribute;
+ GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup;
+ GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes;
GDMonoField *field_GodotObject_ptr;
GDMonoField *field_StringName_ptr;
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index 65e2680905..fa93c6533a 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -43,7 +43,6 @@
#include <mono/metadata/exception.h>
namespace GDMonoInternals {
-
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
// This method should not fail
@@ -113,9 +112,11 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
void unhandled_exception(MonoException *p_exc) {
mono_print_unhandled_exception((MonoObject *)p_exc);
+ gd_unhandled_exception_event(p_exc);
if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) {
// Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
+ mono_unhandled_exception((MonoObject *)p_exc);
GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr);
GD_UNREACHABLE();
} else {
@@ -127,4 +128,14 @@ void unhandled_exception(MonoException *p_exc) {
#endif
}
}
+
+void gd_unhandled_exception_event(MonoException *p_exc) {
+ MonoImage *mono_image = GDMono::get_singleton()->get_core_api_assembly()->get_image();
+
+ MonoClass *gd_klass = mono_class_from_name(mono_image, "Godot", "GD");
+ MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", -1);
+ void *args[1];
+ args[0] = p_exc;
+ mono_runtime_invoke(unhandled_exception_method, nullptr, (void **)args, nullptr);
+}
} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
index 34d2d35b2d..26eb270eee 100644
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -38,7 +38,6 @@
#include "core/object/class_db.h"
namespace GDMonoInternals {
-
void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
/**
@@ -46,6 +45,8 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
*/
void unhandled_exception(MonoException *p_exc);
+
+void gd_unhandled_exception_event(MonoException *p_exc);
} // namespace GDMonoInternals
#endif // GD_MONO_INTERNALS_H
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
index 159a2ed7b6..366662ff81 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -176,7 +176,7 @@ T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
} else if constexpr (cookie == 'F') {
return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
} else if constexpr (cookie == 'D') {
- return (T)(size_t)p_margs->fargs[p_idx];
+ return (T)p_margs->fargs[p_idx];
}
}
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index cba29d63cd..c65353dfd1 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -415,8 +415,7 @@ GD_PINVOKE_EXPORT int32_t monodroid_get_system_property(const char *p_name, char
if (r_value) {
if (len >= 0) {
*r_value = (char *)malloc(len + 1);
- if (!*r_value)
- return -1;
+ ERR_FAIL_NULL_V_MSG(*r_value, -1, "Out of memory.");
memcpy(*r_value, prop_value_str, len);
(*r_value)[len] = '\0';
} else {
@@ -637,6 +636,7 @@ GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array)
if (dns_servers_count > 0) {
size_t ret_size = sizeof(char *) * (size_t)dns_servers_count;
*r_dns_servers_array = malloc(ret_size); // freed by the BCL
+ ERR_FAIL_NULL_V_MSG(*r_dns_servers_array, -1, "Out of memory.");
memcpy(*r_dns_servers_array, dns_servers, ret_size);
}
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
index cdee04edcf..23424fbaf9 100644
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -57,9 +57,9 @@ void ios_mono_log_callback(const char *log_domain, const char *log_level, const
}
void initialize() {
- mono_dllmap_insert(NULL, "System.Native", NULL, "__Internal", NULL);
- mono_dllmap_insert(NULL, "System.IO.Compression.Native", NULL, "__Internal", NULL);
- mono_dllmap_insert(NULL, "System.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL);
+ mono_dllmap_insert(nullptr, "System.Native", nullptr, "__Internal", nullptr);
+ mono_dllmap_insert(nullptr, "System.IO.Compression.Native", nullptr, "__Internal", nullptr);
+ mono_dllmap_insert(nullptr, "System.Security.Cryptography.Native.Apple", nullptr, "__Internal", nullptr);
#ifdef IOS_DEVICE
// This function is defined in an auto-generated source file
@@ -85,7 +85,7 @@ void cleanup() {
GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
- if (countryCode == NULL) {
+ if (countryCode == nullptr) {
return strdup("US");
}
return strdup([countryCode UTF8String]);
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index 7df261d2ba..38c5138482 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -6,11 +6,12 @@
<description>
Uses an [OpenSimplexNoise] to fill the texture data. You can specify the texture size but keep in mind that larger textures will take longer to generate and seamless noise only works with square sized textures.
NoiseTexture can also generate normal map textures.
- The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the data:
+ The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
[codeblock]
var texture = preload("res://noise.tres")
yield(texture, "changed")
- var image = texture.get_data()
+ var image = texture.get_image()
+ var data = image.get_data()
[/codeblock]
</description>
<tutorials>
@@ -32,6 +33,7 @@
</member>
<member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate.
+ [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise.
</member>
<member name="width" type="int" setter="set_width" getter="get_width" default="512">
Width of the generated texture.
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index dcda5c2324..ad82f87213 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -109,6 +109,7 @@
</argument>
<description>
Generate a tileable noise image in [constant Image.FORMAT_L8] format, based on the current noise parameters. Generated seamless images are always square ([code]size[/code] × [code]size[/code]).
+ [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise.
</description>
</method>
</methods>
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index 98381ca144..7272d32fac 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -81,9 +81,9 @@ void NoiseTexture::_validate_property(PropertyInfo &property) const {
}
}
-void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
- data = p_image;
- if (data.is_valid()) {
+void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) {
+ image = p_image;
+ if (image.is_valid()) {
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_2d_create(p_image);
RS::get_singleton()->texture_replace(texture, new_texture);
@@ -95,7 +95,7 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
}
void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
- _set_texture_data(p_image);
+ _set_texture_image(p_image);
noise_thread.wait_to_finish();
if (regen_queued) {
noise_thread.start(_thread_function, this);
@@ -159,7 +159,7 @@ void NoiseTexture::_update_texture() {
} else {
Ref<Image> image = _generate_texture();
- _set_texture_data(image);
+ _set_texture_image(image);
}
update_queued = false;
}
@@ -216,7 +216,7 @@ void NoiseTexture::set_as_normal_map(bool p_as_normal_map) {
}
as_normal_map = p_as_normal_map;
_queue_update();
- _change_notify();
+ notify_property_list_changed();
}
bool NoiseTexture::is_normal_map() {
@@ -253,6 +253,6 @@ RID NoiseTexture::get_rid() const {
return texture;
}
-Ref<Image> NoiseTexture::get_data() const {
- return data;
+Ref<Image> NoiseTexture::get_image() const {
+ return image;
}
diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h
index e89479d962..6983ae18fe 100644
--- a/modules/opensimplex/noise_texture.h
+++ b/modules/opensimplex/noise_texture.h
@@ -43,7 +43,7 @@ class NoiseTexture : public Texture2D {
GDCLASS(NoiseTexture, Texture2D);
private:
- Ref<Image> data;
+ Ref<Image> image;
Thread noise_thread;
@@ -66,7 +66,7 @@ private:
void _queue_update();
Ref<Image> _generate_texture();
void _update_texture();
- void _set_texture_data(const Ref<Image> &p_image);
+ void _set_texture_image(const Ref<Image> &p_image);
protected:
static void _bind_methods();
@@ -94,7 +94,7 @@ public:
virtual RID get_rid() const override;
virtual bool has_alpha() const override { return false; }
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
NoiseTexture();
virtual ~NoiseTexture();
diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp
index d2d8976694..6cb9837f49 100644
--- a/modules/pvr/image_compress_pvrtc.cpp
+++ b/modules/pvr/image_compress_pvrtc.cpp
@@ -65,7 +65,7 @@ static void _compress_pvrtc1_4bpp(Image *p_img) {
img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
Javelin::RgbaBitmap bm(w, h);
void *dst = (void *)bm.GetData();
- copymem(dst, &r[ofs], size);
+ memcpy(dst, &r[ofs], size);
Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
for (int j = 0; j < size / 4; j++) {
// Red and blue colors are swapped.
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 056a923a2d..83f032ca2b 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -46,7 +46,7 @@ enum PVRFLags {
PVR_VFLIP = 0x00010000
};
-RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h
index da425c3237..26071ce30f 100644
--- a/modules/pvr/texture_loader_pvr.h
+++ b/modules/pvr/texture_loader_pvr.h
@@ -36,7 +36,7 @@
class ResourceFormatPVR : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
new file mode 100644
index 0000000000..68e9df5263
--- /dev/null
+++ b/modules/raycast/SCsub
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+embree_src = [
+ "common/sys/sysinfo.cpp",
+ "common/sys/alloc.cpp",
+ "common/sys/filename.cpp",
+ "common/sys/library.cpp",
+ "common/sys/thread.cpp",
+ "common/sys/string.cpp",
+ "common/sys/regression.cpp",
+ "common/sys/mutex.cpp",
+ "common/sys/condition.cpp",
+ "common/sys/barrier.cpp",
+ "common/math/constants.cpp",
+ "common/simd/sse.cpp",
+ "common/lexers/stringstream.cpp",
+ "common/lexers/tokenstream.cpp",
+ "common/tasking/taskschedulerinternal.cpp",
+ "common/algorithms/parallel_for.cpp",
+ "common/algorithms/parallel_reduce.cpp",
+ "common/algorithms/parallel_prefix_sum.cpp",
+ "common/algorithms/parallel_for_for.cpp",
+ "common/algorithms/parallel_for_for_prefix_sum.cpp",
+ "common/algorithms/parallel_partition.cpp",
+ "common/algorithms/parallel_sort.cpp",
+ "common/algorithms/parallel_set.cpp",
+ "common/algorithms/parallel_map.cpp",
+ "common/algorithms/parallel_filter.cpp",
+ "kernels/common/device.cpp",
+ "kernels/common/stat.cpp",
+ "kernels/common/acceln.cpp",
+ "kernels/common/accelset.cpp",
+ "kernels/common/state.cpp",
+ "kernels/common/rtcore.cpp",
+ "kernels/common/rtcore_builder.cpp",
+ "kernels/common/scene.cpp",
+ "kernels/common/alloc.cpp",
+ "kernels/common/geometry.cpp",
+ "kernels/common/scene_triangle_mesh.cpp",
+ "kernels/geometry/primitive4.cpp",
+ "kernels/builders/primrefgen.cpp",
+ "kernels/bvh/bvh.cpp",
+ "kernels/bvh/bvh_statistics.cpp",
+ "kernels/bvh/bvh4_factory.cpp",
+ "kernels/bvh/bvh8_factory.cpp",
+ "kernels/bvh/bvh_collider.cpp",
+ "kernels/bvh/bvh_rotate.cpp",
+ "kernels/bvh/bvh_refit.cpp",
+ "kernels/bvh/bvh_builder.cpp",
+ "kernels/bvh/bvh_builder_morton.cpp",
+ "kernels/bvh/bvh_builder_sah.cpp",
+ "kernels/bvh/bvh_builder_sah_spatial.cpp",
+ "kernels/bvh/bvh_builder_sah_mb.cpp",
+ "kernels/bvh/bvh_builder_twolevel.cpp",
+ "kernels/bvh/bvh_intersector1_bvh4.cpp",
+]
+
+embree_dir = "#thirdparty/embree-aarch64/"
+
+env_embree = env_modules.Clone()
+embree_sources = [embree_dir + file for file in embree_src]
+env_embree.Prepend(CPPPATH=[embree_dir, embree_dir + "include"])
+env_embree.Append(CPPFLAGS=["-DEMBREE_TARGET_SSE2", "-DEMBREE_LOWEST_ISA", "-DTASKING_INTERNAL", "-DNDEBUG"])
+
+if not env_embree.msvc:
+ env_embree.Append(CPPFLAGS=["-msse2", "-mxsave"])
+ if env["platform"] == "windows":
+ env_embree.Append(CPPFLAGS=["-mstackrealign"])
+
+if env["platform"] == "windows":
+ if env.msvc:
+ env.Append(LINKFLAGS=["psapi.lib"])
+ env_embree.Append(CPPFLAGS=["-D__SSE2__", "-D__SSE__"])
+ else:
+ env.Append(LIBS=["psapi"])
+
+env_embree.disable_warnings()
+env_embree.add_source_files(env.modules_sources, embree_sources)
+
+env_raycast = env_modules.Clone()
+env_raycast.Prepend(CPPPATH=[embree_dir, embree_dir + "include", embree_dir + "common"])
+
+env_raycast.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
new file mode 100644
index 0000000000..26493da41b
--- /dev/null
+++ b/modules/raycast/config.py
@@ -0,0 +1,12 @@
+def can_build(env, platform):
+ if platform == "android":
+ return env["android_arch"] in ["arm64v8", "x86", "x86_64"]
+
+ if platform == "javascript":
+ return False # No SIMD support yet
+
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py
new file mode 100644
index 0000000000..db4fa95c21
--- /dev/null
+++ b/modules/raycast/godot_update_embree.py
@@ -0,0 +1,260 @@
+import glob, os, shutil, subprocess, re
+
+include_dirs = [
+ "common/tasking",
+ "kernels/bvh",
+ "kernels/builders",
+ "common/sys",
+ "kernels",
+ "kernels/common",
+ "common/math",
+ "common/algorithms",
+ "common/lexers",
+ "common/simd",
+ "include/embree3",
+ "kernels/subdiv",
+ "kernels/geometry",
+]
+
+cpp_files = [
+ "common/sys/sysinfo.cpp",
+ "common/sys/alloc.cpp",
+ "common/sys/filename.cpp",
+ "common/sys/library.cpp",
+ "common/sys/thread.cpp",
+ "common/sys/string.cpp",
+ "common/sys/regression.cpp",
+ "common/sys/mutex.cpp",
+ "common/sys/condition.cpp",
+ "common/sys/barrier.cpp",
+ "common/math/constants.cpp",
+ "common/simd/sse.cpp",
+ "common/lexers/stringstream.cpp",
+ "common/lexers/tokenstream.cpp",
+ "common/tasking/taskschedulerinternal.cpp",
+ "common/algorithms/parallel_for.cpp",
+ "common/algorithms/parallel_reduce.cpp",
+ "common/algorithms/parallel_prefix_sum.cpp",
+ "common/algorithms/parallel_for_for.cpp",
+ "common/algorithms/parallel_for_for_prefix_sum.cpp",
+ "common/algorithms/parallel_partition.cpp",
+ "common/algorithms/parallel_sort.cpp",
+ "common/algorithms/parallel_set.cpp",
+ "common/algorithms/parallel_map.cpp",
+ "common/algorithms/parallel_filter.cpp",
+ "kernels/common/device.cpp",
+ "kernels/common/stat.cpp",
+ "kernels/common/acceln.cpp",
+ "kernels/common/accelset.cpp",
+ "kernels/common/state.cpp",
+ "kernels/common/rtcore.cpp",
+ "kernels/common/rtcore_builder.cpp",
+ "kernels/common/scene.cpp",
+ "kernels/common/alloc.cpp",
+ "kernels/common/geometry.cpp",
+ "kernels/common/scene_triangle_mesh.cpp",
+ "kernels/geometry/primitive4.cpp",
+ "kernels/builders/primrefgen.cpp",
+ "kernels/bvh/bvh.cpp",
+ "kernels/bvh/bvh_statistics.cpp",
+ "kernels/bvh/bvh4_factory.cpp",
+ "kernels/bvh/bvh8_factory.cpp",
+ "kernels/bvh/bvh_collider.cpp",
+ "kernels/bvh/bvh_rotate.cpp",
+ "kernels/bvh/bvh_refit.cpp",
+ "kernels/bvh/bvh_builder.cpp",
+ "kernels/bvh/bvh_builder_morton.cpp",
+ "kernels/bvh/bvh_builder_sah.cpp",
+ "kernels/bvh/bvh_builder_sah_spatial.cpp",
+ "kernels/bvh/bvh_builder_sah_mb.cpp",
+ "kernels/bvh/bvh_builder_twolevel.cpp",
+ "kernels/bvh/bvh_intersector1.cpp",
+ "kernels/bvh/bvh_intersector1_bvh4.cpp",
+]
+
+os.chdir("../../thirdparty")
+
+dir_name = "embree-aarch64"
+if os.path.exists(dir_name):
+ shutil.rmtree(dir_name)
+
+subprocess.run(["git", "clone", "https://github.com/lighttransport/embree-aarch64.git", "embree-tmp"])
+os.chdir("embree-tmp")
+
+commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip()
+
+all_files = set(cpp_files)
+
+dest_dir = os.path.join("..", dir_name)
+for include_dir in include_dirs:
+ headers = glob.iglob(os.path.join(include_dir, "*.h"))
+ all_files.update(headers)
+
+for f in all_files:
+ d = os.path.join(dest_dir, os.path.dirname(f))
+ if not os.path.exists(d):
+ os.makedirs(d)
+ shutil.copy2(f, d)
+
+with open(os.path.join(dest_dir, "kernels/hash.h"), "w") as hash_file:
+ hash_file.write(
+ f"""
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_HASH "{commit_hash}"
+"""
+ )
+
+with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file:
+ config_file.write(
+ """
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+/* #undef EMBREE_RAY_MASK */
+/* #undef EMBREE_STAT_COUNTERS */
+/* #undef EMBREE_BACKFACE_CULLING */
+/* #undef EMBREE_BACKFACE_CULLING_CURVES */
+#define EMBREE_FILTER_FUNCTION
+/* #undef EMBREE_IGNORE_INVALID_RAYS */
+#define EMBREE_GEOMETRY_TRIANGLE
+/* #undef EMBREE_GEOMETRY_QUAD */
+/* #undef EMBREE_GEOMETRY_CURVE */
+/* #undef EMBREE_GEOMETRY_SUBDIVISION */
+/* #undef EMBREE_GEOMETRY_USER */
+/* #undef EMBREE_GEOMETRY_INSTANCE */
+/* #undef EMBREE_GEOMETRY_GRID */
+/* #undef EMBREE_GEOMETRY_POINT */
+/* #undef EMBREE_RAY_PACKETS */
+/* #undef EMBREE_COMPACT_POLYS */
+
+#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ #define IF_ENABLED_TRIS(x) x
+#else
+ #define IF_ENABLED_TRIS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ #define IF_ENABLED_QUADS(x) x
+#else
+ #define IF_ENABLED_QUADS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_CURVES_OR_POINTS(x) x
+#else
+ #define IF_ENABLED_CURVES_OR_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ #define IF_ENABLED_CURVES(x) x
+#else
+ #define IF_ENABLED_CURVES(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_POINTS(x) x
+#else
+ #define IF_ENABLED_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ #define IF_ENABLED_SUBDIV(x) x
+#else
+ #define IF_ENABLED_SUBDIV(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ #define IF_ENABLED_USER(x) x
+#else
+ #define IF_ENABLED_USER(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ #define IF_ENABLED_INSTANCE(x) x
+#else
+ #define IF_ENABLED_INSTANCE(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ #define IF_ENABLED_GRIDS(x) x
+#else
+ #define IF_ENABLED_GRIDS(x)
+#endif
+"""
+ )
+
+
+with open("CMakeLists.txt", "r") as cmake_file:
+ cmake_content = cmake_file.read()
+ major_version = int(re.compile(r"EMBREE_VERSION_MAJOR\s(\d+)").findall(cmake_content)[0])
+ minor_version = int(re.compile(r"EMBREE_VERSION_MINOR\s(\d+)").findall(cmake_content)[0])
+ patch_version = int(re.compile(r"EMBREE_VERSION_PATCH\s(\d+)").findall(cmake_content)[0])
+
+with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file:
+ config_file.write(
+ f"""
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define RTC_VERSION_MAJOR {major_version}
+#define RTC_VERSION_MINOR {minor_version}
+#define RTC_VERSION_PATCH {patch_version}
+#define RTC_VERSION {major_version}{minor_version:02d}{patch_version:02d}
+#define RTC_VERSION_STRING "{major_version}.{minor_version}.{patch_version}"
+
+#define RTC_MAX_INSTANCE_LEVEL_COUNT 1
+
+#define EMBREE_MIN_WIDTH 0
+#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+
+#define EMBREE_STATIC_LIB
+/* #undef EMBREE_API_NAMESPACE */
+
+#if defined(EMBREE_API_NAMESPACE)
+# define RTC_NAMESPACE
+# define RTC_NAMESPACE_BEGIN namespace {{
+# define RTC_NAMESPACE_END }}
+# define RTC_NAMESPACE_USE using namespace ;
+# define RTC_API_EXTERN_C
+# undef EMBREE_API_NAMESPACE
+#else
+# define RTC_NAMESPACE_BEGIN
+# define RTC_NAMESPACE_END
+# define RTC_NAMESPACE_USE
+# if defined(__cplusplus)
+# define RTC_API_EXTERN_C extern "C"
+# else
+# define RTC_API_EXTERN_C
+# endif
+#endif
+
+#if defined(ISPC)
+# define RTC_API_IMPORT extern "C" unmasked
+# define RTC_API_EXPORT extern "C" unmasked
+#elif defined(EMBREE_STATIC_LIB)
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C
+#elif defined(_WIN32)
+# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport)
+# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport)
+#else
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default")))
+#endif
+
+#if defined(RTC_EXPORT_API)
+# define RTC_API RTC_API_EXPORT
+#else
+# define RTC_API RTC_API_IMPORT
+#endif
+"""
+ )
+
+os.chdir("..")
+shutil.rmtree("embree-tmp")
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
new file mode 100644
index 0000000000..9039622d3d
--- /dev/null
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -0,0 +1,202 @@
+/*************************************************************************/
+/* lightmap_raycaster.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+
+#include "lightmap_raycaster.h"
+
+// From Embree.
+#include <math/vec2.h>
+#include <math/vec3.h>
+
+#include <pmmintrin.h>
+
+using namespace embree;
+
+LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() {
+ return memnew(LightmapRaycasterEmbree);
+}
+
+void LightmapRaycasterEmbree::make_default_raycaster() {
+ create_function = create_embree_raycaster;
+}
+
+void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArguments *p_args) {
+ RTCHit *hit = (RTCHit *)p_args->hit;
+
+ unsigned int geomID = hit->geomID;
+ float u = hit->u;
+ float v = hit->v;
+
+ LightmapRaycasterEmbree *scene = (LightmapRaycasterEmbree *)p_args->geometryUserPtr;
+ RTCGeometry geom = rtcGetGeometry(scene->embree_scene, geomID);
+
+ rtcInterpolate0(geom, hit->primID, hit->u, hit->v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, &hit->u, 2);
+
+ if (scene->alpha_textures.has(geomID)) {
+ const AlphaTextureData &alpha_texture = scene->alpha_textures[geomID];
+
+ if (alpha_texture.sample(hit->u, hit->v) < 128) {
+ p_args->valid[0] = 0;
+ return;
+ }
+ }
+
+ rtcInterpolate0(geom, hit->primID, u, v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, &hit->Ng_x, 3);
+}
+
+bool LightmapRaycasterEmbree::intersect(Ray &r_ray) {
+ RTCIntersectContext context;
+
+ rtcInitIntersectContext(&context);
+
+ rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray);
+ return r_ray.geomID != RTC_INVALID_GEOMETRY_ID;
+}
+
+void LightmapRaycasterEmbree::intersect(Vector<Ray> &r_rays) {
+ Ray *rays = r_rays.ptrw();
+ for (int i = 0; i < r_rays.size(); ++i) {
+ intersect(rays[i]);
+ }
+}
+
+void LightmapRaycasterEmbree::set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) {
+ if (p_alpha_texture.is_valid() && p_alpha_texture->get_size() != Vector2i()) {
+ AlphaTextureData tex;
+ tex.size = p_alpha_texture->get_size();
+ tex.data = p_alpha_texture->get_data();
+ alpha_textures.insert(p_id, tex);
+ }
+}
+
+float blerp(float c00, float c10, float c01, float c11, float tx, float ty) {
+ return Math::lerp(Math::lerp(c00, c10, tx), Math::lerp(c01, c11, tx), ty);
+}
+
+uint8_t LightmapRaycasterEmbree::AlphaTextureData::sample(float u, float v) const {
+ float x = u * size.x;
+ float y = v * size.y;
+ int xi = (int)x;
+ int yi = (int)y;
+
+ uint8_t texels[4];
+
+ for (int i = 0; i < 4; ++i) {
+ int sample_x = CLAMP(xi + i % 2, 0, size.x - 1);
+ int sample_y = CLAMP(yi + i / 2, 0, size.y - 1);
+ texels[i] = data[sample_y * size.x + sample_x];
+ }
+
+ return Math::round(blerp(texels[0], texels[1], texels[2], texels[3], x - xi, y - yi));
+}
+
+void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) {
+ RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+
+ rtcSetGeometryVertexAttributeCount(embree_mesh, 2);
+
+ int vertex_count = p_vertices.size();
+
+ ERR_FAIL_COND(vertex_count % 3 != 0);
+ ERR_FAIL_COND(vertex_count != p_uv2s.size());
+
+ Vec3fa *embree_vertices = (Vec3fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vec3fa), vertex_count);
+ Vec2fa *embree_light_uvs = (Vec2fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vec2fa), vertex_count);
+ uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
+
+ Vec3fa *embree_normals = nullptr;
+ if (!p_normals.is_empty()) {
+ embree_normals = (Vec3fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vec3fa), vertex_count);
+ }
+
+ for (int i = 0; i < vertex_count; i++) {
+ embree_vertices[i] = Vec3fa(p_vertices[i].x, p_vertices[i].y, p_vertices[i].z);
+ embree_light_uvs[i] = Vec2fa(p_uv2s[i].x, p_uv2s[i].y);
+ if (embree_normals != nullptr) {
+ embree_normals[i] = Vec3fa(p_normals[i].x, p_normals[i].y, p_normals[i].z);
+ }
+ embree_triangles[i] = i;
+ }
+
+ rtcCommitGeometry(embree_mesh);
+ rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function);
+ rtcSetGeometryUserData(embree_mesh, this);
+ rtcAttachGeometryByID(embree_scene, embree_mesh, p_id);
+ rtcReleaseGeometry(embree_mesh);
+}
+
+void LightmapRaycasterEmbree::commit() {
+ rtcCommitScene(embree_scene);
+}
+
+void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
+ for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
+ rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes = p_mesh_ids;
+}
+
+void LightmapRaycasterEmbree::clear_mesh_filter() {
+ for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
+ rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes.clear();
+}
+
+void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
+ print_error("Embree error: " + String(p_str));
+}
+
+LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+
+ embree_device = rtcNewDevice(nullptr);
+ rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
+ embree_scene = rtcNewScene(embree_device);
+}
+
+LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
+
+ if (embree_scene != nullptr) {
+ rtcReleaseScene(embree_scene);
+ }
+
+ if (embree_device != nullptr) {
+ rtcReleaseDevice(embree_device);
+ }
+}
+
+#endif
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h
new file mode 100644
index 0000000000..4c3de27837
--- /dev/null
+++ b/modules/raycast/lightmap_raycaster.h
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* lightmap_raycaster.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+
+#include "core/object/object.h"
+#include "scene/3d/lightmapper.h"
+#include "scene/resources/mesh.h"
+
+#include <embree3/rtcore.h>
+
+class LightmapRaycasterEmbree : public LightmapRaycaster {
+ GDCLASS(LightmapRaycasterEmbree, LightmapRaycaster);
+
+private:
+ struct AlphaTextureData {
+ Vector<uint8_t> data;
+ Vector2i size;
+
+ uint8_t sample(float u, float v) const;
+ };
+
+ RTCDevice embree_device;
+ RTCScene embree_scene;
+
+ static void filter_function(const struct RTCFilterFunctionNArguments *p_args);
+
+ Map<unsigned int, AlphaTextureData> alpha_textures;
+ Set<int> filter_meshes;
+
+public:
+ virtual bool intersect(Ray &p_ray) override;
+
+ virtual void intersect(Vector<Ray> &r_rays) override;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) override;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override;
+ virtual void commit() override;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override;
+ virtual void clear_mesh_filter() override;
+
+ static LightmapRaycaster *create_embree_raycaster();
+ static void make_default_raycaster();
+
+ LightmapRaycasterEmbree();
+ ~LightmapRaycasterEmbree();
+};
+
+#endif
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
new file mode 100644
index 0000000000..66558efa8c
--- /dev/null
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -0,0 +1,583 @@
+/*************************************************************************/
+/* raycast_occlusion_cull.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "raycast_occlusion_cull.h"
+#include "core/config/project_settings.h"
+#include "core/templates/local_vector.h"
+
+#ifdef __SSE2__
+#include <pmmintrin.h>
+#endif
+
+RaycastOcclusionCull *RaycastOcclusionCull::raycast_singleton = nullptr;
+
+void RaycastOcclusionCull::RaycastHZBuffer::clear() {
+ HZBuffer::clear();
+
+ camera_rays.clear();
+ camera_ray_masks.clear();
+ packs_size = Size2i();
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) {
+ if (p_size == Size2i()) {
+ clear();
+ return;
+ }
+
+ if (!sizes.is_empty() && p_size == sizes[0]) {
+ return; // Size didn't change
+ }
+
+ HZBuffer::resize(p_size);
+
+ packs_size = Size2i(Math::ceil(p_size.x / (float)TILE_SIZE), Math::ceil(p_size.y / (float)TILE_SIZE));
+ int ray_packets_count = packs_size.x * packs_size.y;
+ camera_rays.resize(ray_packets_count);
+ camera_ray_masks.resize(ray_packets_count * TILE_SIZE * TILE_SIZE);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) {
+ CameraRayThreadData td;
+ td.camera_matrix = p_cam_projection;
+ td.camera_transform = p_cam_transform;
+ td.camera_orthogonal = p_cam_orthogonal;
+ td.thread_count = p_thread_work_pool.get_thread_count();
+
+ p_thread_work_pool.do_work(td.thread_count, this, &RaycastHZBuffer::_camera_rays_threaded, &td);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thread, RaycastOcclusionCull::RaycastHZBuffer::CameraRayThreadData *p_data) {
+ uint32_t packs_total = camera_rays.size();
+ uint32_t total_threads = p_data->thread_count;
+ uint32_t from = p_thread * packs_total / total_threads;
+ uint32_t to = (p_thread + 1 == total_threads) ? packs_total : ((p_thread + 1) * packs_total / total_threads);
+ _generate_camera_rays(p_data->camera_transform, p_data->camera_matrix, p_data->camera_orthogonal, from, to);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) {
+ Size2i buffer_size = sizes[0];
+
+ CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
+ float z_far = p_cam_projection.get_z_far() * 1.05f;
+ debug_tex_range = z_far;
+
+ RayPacket *ray_packets = camera_rays.ptr();
+ uint32_t *ray_masks = camera_ray_masks.ptr();
+
+ for (int i = p_from; i < p_to; i++) {
+ RayPacket &packet = ray_packets[i];
+ int tile_x = (i % packs_size.x) * TILE_SIZE;
+ int tile_y = (i / packs_size.x) * TILE_SIZE;
+
+ for (int j = 0; j < TILE_RAYS; j++) {
+ float x = tile_x + j % TILE_SIZE;
+ float y = tile_y + j / TILE_SIZE;
+
+ ray_masks[i * TILE_RAYS + j] = ~0U;
+
+ if (x >= buffer_size.x || y >= buffer_size.y) {
+ ray_masks[i * TILE_RAYS + j] = 0U;
+ } else {
+ float u = x / (buffer_size.x - 1);
+ float v = y / (buffer_size.y - 1);
+ u = u * 2.0f - 1.0f;
+ v = v * 2.0f - 1.0f;
+
+ Plane pixel_proj = Plane(u, v, -1.0, 1.0);
+ Plane pixel_view = inv_camera_matrix.xform4(pixel_proj);
+ Vector3 pixel_world = p_cam_transform.xform(pixel_view.normal);
+
+ Vector3 dir;
+ if (p_cam_orthogonal) {
+ dir = -p_cam_transform.basis.get_axis(2);
+ } else {
+ dir = (pixel_world - p_cam_transform.origin).normalized();
+ }
+
+ packet.ray.org_x[j] = pixel_world.x;
+ packet.ray.org_y[j] = pixel_world.y;
+ packet.ray.org_z[j] = pixel_world.z;
+
+ packet.ray.dir_x[j] = dir.x;
+ packet.ray.dir_y[j] = dir.y;
+ packet.ray.dir_z[j] = dir.z;
+
+ packet.ray.tnear[j] = 0.0f;
+
+ packet.ray.time[j] = 0.0f;
+
+ packet.ray.flags[j] = 0;
+ packet.ray.mask[j] = -1;
+ packet.hit.geomID[j] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ packet.ray.tfar[j] = z_far;
+ }
+ }
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::sort_rays() {
+ if (is_empty()) {
+ return;
+ }
+
+ Size2i buffer_size = sizes[0];
+ for (int i = 0; i < packs_size.y; i++) {
+ for (int j = 0; j < packs_size.x; j++) {
+ for (int tile_i = 0; tile_i < TILE_SIZE; tile_i++) {
+ for (int tile_j = 0; tile_j < TILE_SIZE; tile_j++) {
+ int x = j * TILE_SIZE + tile_j;
+ int y = i * TILE_SIZE + tile_i;
+ if (x >= buffer_size.x || y >= buffer_size.y) {
+ continue;
+ }
+ int k = tile_i * TILE_SIZE + tile_j;
+ int packet_index = i * packs_size.x + j;
+ mips[0][y * buffer_size.x + x] = camera_rays[packet_index].ray.tfar[k];
+ }
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////
+
+bool RaycastOcclusionCull::is_occluder(RID p_rid) {
+ return occluder_owner.owns(p_rid);
+}
+
+RID RaycastOcclusionCull::occluder_allocate() {
+ return occluder_owner.allocate_rid();
+}
+
+void RaycastOcclusionCull::occluder_initialize(RID p_occluder) {
+ Occluder *occluder = memnew(Occluder);
+ occluder_owner.initialize_rid(p_occluder, occluder);
+}
+
+void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->vertices = p_vertices;
+ occluder->indices = p_indices;
+
+ for (Set<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) {
+ RID scenario_rid = E->get().scenario;
+ RID instance_rid = E->get().instance;
+ ERR_CONTINUE(!scenarios.has(scenario_rid));
+ Scenario &scenario = scenarios[scenario_rid];
+ ERR_CONTINUE(!scenario.instances.has(instance_rid));
+
+ if (!scenario.dirty_instances.has(instance_rid)) {
+ scenario.dirty_instances.insert(instance_rid);
+ scenario.dirty_instances_array.push_back(instance_rid);
+ }
+ }
+}
+
+void RaycastOcclusionCull::free_occluder(RID p_occluder) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+ memdelete(occluder);
+ occluder_owner.free(p_occluder);
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::add_scenario(RID p_scenario) {
+ if (scenarios.has(p_scenario)) {
+ scenarios[p_scenario].removed = false;
+ } else {
+ scenarios[p_scenario] = Scenario();
+ }
+}
+
+void RaycastOcclusionCull::remove_scenario(RID p_scenario) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+ scenario.removed = true;
+}
+
+void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+
+ if (!scenario.instances.has(p_instance)) {
+ scenario.instances[p_instance] = OccluderInstance();
+ }
+
+ OccluderInstance &instance = scenario.instances[p_instance];
+
+ if (instance.removed) {
+ instance.removed = false;
+ scenario.removed_instances.erase(p_instance);
+ }
+
+ bool changed = false;
+
+ if (instance.occluder != p_occluder) {
+ Occluder *old_occluder = occluder_owner.getornull(instance.occluder);
+ if (old_occluder) {
+ old_occluder->users.erase(InstanceID(p_scenario, p_instance));
+ }
+
+ instance.occluder = p_occluder;
+
+ if (p_occluder.is_valid()) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+ occluder->users.insert(InstanceID(p_scenario, p_instance));
+ }
+ changed = true;
+ }
+
+ if (instance.xform != p_xform) {
+ scenario.instances[p_instance].xform = p_xform;
+ changed = true;
+ }
+
+ if (instance.enabled != p_enabled) {
+ instance.enabled = p_enabled;
+ scenario.dirty = true; // The scenario needs a scene re-build, but the instance doesn't need update
+ }
+
+ if (changed && !scenario.dirty_instances.has(p_instance)) {
+ scenario.dirty_instances.insert(p_instance);
+ scenario.dirty_instances_array.push_back(p_instance);
+ scenario.dirty = true;
+ }
+}
+
+void RaycastOcclusionCull::scenario_remove_instance(RID p_scenario, RID p_instance) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+
+ if (scenario.instances.has(p_instance)) {
+ OccluderInstance &instance = scenario.instances[p_instance];
+
+ if (!instance.removed) {
+ Occluder *occluder = occluder_owner.getornull(instance.occluder);
+ if (occluder) {
+ occluder->users.erase(InstanceID(p_scenario, p_instance));
+ }
+
+ scenario.removed_instances.push_back(p_instance);
+ instance.removed = true;
+ }
+ }
+}
+
+void RaycastOcclusionCull::Scenario::_update_dirty_instance_thread(int p_idx, RID *p_instances) {
+ _update_dirty_instance(p_idx, p_instances, nullptr);
+}
+
+void RaycastOcclusionCull::Scenario::_update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool) {
+ OccluderInstance *occ_inst = instances.getptr(p_instances[p_idx]);
+
+ if (!occ_inst) {
+ return;
+ }
+
+ Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+
+ if (!occ) {
+ return;
+ }
+
+ int vertices_size = occ->vertices.size();
+
+ // Embree requires the last element to be readable by a 16-byte SSE load instruction, so we add padding to be safe.
+ occ_inst->xformed_vertices.resize(vertices_size + 1);
+
+ const Vector3 *read_ptr = occ->vertices.ptr();
+ Vector3 *write_ptr = occ_inst->xformed_vertices.ptr();
+
+ if (p_thread_pool && vertices_size > 1024) {
+ TransformThreadData td;
+ td.xform = occ_inst->xform;
+ td.read = read_ptr;
+ td.write = write_ptr;
+ td.vertex_count = vertices_size;
+ td.thread_count = p_thread_pool->get_thread_count();
+ p_thread_pool->do_work(td.thread_count, this, &Scenario::_transform_vertices_thread, &td);
+ } else {
+ _transform_vertices_range(read_ptr, write_ptr, occ_inst->xform, 0, vertices_size);
+ }
+
+ occ_inst->indices.resize(occ->indices.size());
+ memcpy(occ_inst->indices.ptr(), occ->indices.ptr(), occ->indices.size() * sizeof(int32_t));
+}
+
+void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data) {
+ uint32_t vertex_total = p_data->vertex_count;
+ uint32_t total_threads = p_data->thread_count;
+ uint32_t from = p_thread * vertex_total / total_threads;
+ uint32_t to = (p_thread + 1 == total_threads) ? vertex_total : ((p_thread + 1) * vertex_total / total_threads);
+ _transform_vertices_range(p_data->read, p_data->write, p_data->xform, from, to);
+}
+
+void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform &p_xform, int p_from, int p_to) {
+ for (int i = p_from; i < p_to; i++) {
+ p_write[i] = p_xform.xform(p_read[i]);
+ }
+}
+
+void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) {
+ Scenario *scenario = (Scenario *)p_ud;
+ int commit_idx = 1 - (scenario->current_scene_idx);
+ rtcCommitScene(scenario->ebr_scene[commit_idx]);
+ scenario->commit_done = true;
+}
+
+bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) {
+ ERR_FAIL_COND_V(singleton == nullptr, false);
+
+ if (commit_thread == nullptr) {
+ commit_thread = memnew(Thread);
+ }
+
+ if (commit_thread->is_started()) {
+ if (commit_done) {
+ commit_thread->wait_to_finish();
+ current_scene_idx = 1 - current_scene_idx;
+ } else {
+ return false;
+ }
+ }
+
+ if (removed) {
+ if (ebr_scene[0]) {
+ rtcReleaseScene(ebr_scene[0]);
+ }
+ if (ebr_scene[1]) {
+ rtcReleaseScene(ebr_scene[1]);
+ }
+ return true;
+ }
+
+ if (!dirty && removed_instances.is_empty() && dirty_instances_array.is_empty()) {
+ return false;
+ }
+
+ for (unsigned int i = 0; i < removed_instances.size(); i++) {
+ instances.erase(removed_instances[i]);
+ }
+
+ if (dirty_instances_array.size() / p_thread_pool.get_thread_count() > 128) {
+ // Lots of instances, use per-instance threading
+ p_thread_pool.do_work(dirty_instances_array.size(), this, &Scenario::_update_dirty_instance_thread, dirty_instances_array.ptr());
+ } else {
+ // Few instances, use threading on the vertex transforms
+ for (unsigned int i = 0; i < dirty_instances_array.size(); i++) {
+ _update_dirty_instance(i, dirty_instances_array.ptr(), &p_thread_pool);
+ }
+ }
+
+ dirty_instances.clear();
+ dirty_instances_array.clear();
+ removed_instances.clear();
+
+ if (raycast_singleton->ebr_device == nullptr) {
+ raycast_singleton->_init_embree();
+ }
+
+ int next_scene_idx = 1 - current_scene_idx;
+ RTCScene &next_scene = ebr_scene[next_scene_idx];
+
+ if (next_scene) {
+ rtcReleaseScene(next_scene);
+ }
+
+ next_scene = rtcNewScene(raycast_singleton->ebr_device);
+ rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality));
+
+ const RID *inst_rid = nullptr;
+ while ((inst_rid = instances.next(inst_rid))) {
+ OccluderInstance *occ_inst = instances.getptr(*inst_rid);
+ Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+
+ if (!occ || !occ_inst->enabled) {
+ continue;
+ }
+
+ RTCGeometry geom = rtcNewGeometry(raycast_singleton->ebr_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+ rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, occ_inst->xformed_vertices.ptr(), 0, sizeof(Vector3), occ_inst->xformed_vertices.size());
+ rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, occ_inst->indices.ptr(), 0, sizeof(uint32_t) * 3, occ_inst->indices.size() / 3);
+ rtcCommitGeometry(geom);
+ rtcAttachGeometry(next_scene, geom);
+ rtcReleaseGeometry(geom);
+ }
+
+ dirty = false;
+ commit_done = false;
+ commit_thread->start(&Scenario::_commit_scene, this);
+ return false;
+}
+
+void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThreadData *p_raycast_data) const {
+ RTCIntersectContext ctx;
+ rtcInitIntersectContext(&ctx);
+ ctx.flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT;
+
+ rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &ctx, &p_raycast_data->rays[p_idx]);
+}
+
+void RaycastOcclusionCull::Scenario::raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const {
+ ERR_FAIL_COND(singleton == nullptr);
+ if (raycast_singleton->ebr_device == nullptr) {
+ return; // Embree is initialized on demand when there is some scenario with occluders in it.
+ }
+
+ if (ebr_scene[current_scene_idx] == nullptr) {
+ return;
+ }
+
+ RaycastThreadData td;
+ td.rays = r_rays.ptr();
+ td.masks = p_valid_masks.ptr();
+
+ p_thread_pool.do_work(r_rays.size(), this, &Scenario::_raycast, &td);
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::add_buffer(RID p_buffer) {
+ ERR_FAIL_COND(buffers.has(p_buffer));
+ buffers[p_buffer] = RaycastHZBuffer();
+}
+
+void RaycastOcclusionCull::remove_buffer(RID p_buffer) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ buffers.erase(p_buffer);
+}
+
+void RaycastOcclusionCull::buffer_set_scenario(RID p_buffer, RID p_scenario) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ ERR_FAIL_COND(p_scenario.is_valid() && !scenarios.has(p_scenario));
+ buffers[p_buffer].scenario_rid = p_scenario;
+}
+
+void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ buffers[p_buffer].resize(p_size);
+}
+
+void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {
+ if (!buffers.has(p_buffer)) {
+ return;
+ }
+
+ RaycastHZBuffer &buffer = buffers[p_buffer];
+
+ if (buffer.is_empty() || !scenarios.has(buffer.scenario_rid)) {
+ return;
+ }
+
+ Scenario &scenario = scenarios[buffer.scenario_rid];
+
+ bool removed = scenario.update(p_thread_pool);
+
+ if (removed) {
+ scenarios.erase(buffer.scenario_rid);
+ return;
+ }
+
+ buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_thread_pool);
+
+ scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks, p_thread_pool);
+ buffer.sort_rays();
+ buffer.update_mips();
+}
+
+RaycastOcclusionCull::HZBuffer *RaycastOcclusionCull::buffer_get_ptr(RID p_buffer) {
+ if (!buffers.has(p_buffer)) {
+ return nullptr;
+ }
+ return &buffers[p_buffer];
+}
+
+RID RaycastOcclusionCull::buffer_get_debug_texture(RID p_buffer) {
+ ERR_FAIL_COND_V(!buffers.has(p_buffer), RID());
+ return buffers[p_buffer].get_debug_texture();
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {
+ if (build_quality == p_quality) {
+ return;
+ }
+
+ build_quality = p_quality;
+
+ const RID *scenario_rid = nullptr;
+ while ((scenario_rid = scenarios.next(scenario_rid))) {
+ scenarios[*scenario_rid].dirty = true;
+ }
+}
+
+void RaycastOcclusionCull::_init_embree() {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+#endif
+
+ String settings = vformat("threads=%d", MAX(1, OS::get_singleton()->get_processor_count() - 2));
+ ebr_device = rtcNewDevice(settings.utf8().ptr());
+}
+
+RaycastOcclusionCull::RaycastOcclusionCull() {
+ raycast_singleton = this;
+ int default_quality = GLOBAL_GET("rendering/occlusion_culling/bvh_build_quality");
+ build_quality = RS::ViewportOcclusionCullingBuildQuality(default_quality);
+}
+
+RaycastOcclusionCull::~RaycastOcclusionCull() {
+ const RID *scenario_rid = nullptr;
+ while ((scenario_rid = scenarios.next(scenario_rid))) {
+ Scenario &scenario = scenarios[*scenario_rid];
+ if (scenario.commit_thread) {
+ scenario.commit_thread->wait_to_finish();
+ memdelete(scenario.commit_thread);
+ }
+ }
+
+ if (ebr_device != nullptr) {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
+#endif
+ rtcReleaseDevice(ebr_device);
+ }
+
+ raycast_singleton = nullptr;
+}
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
new file mode 100644
index 0000000000..acaceb9459
--- /dev/null
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* raycast_occlusion_cull.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUSION_CULL_RAYCASTER_H
+#define OCCLUSION_CULL_RAYCASTER_H
+
+#include "core/io/image.h"
+#include "core/math/camera_matrix.h"
+#include "core/object/object.h"
+#include "core/object/reference.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "scene/resources/mesh.h"
+#include "servers/rendering/renderer_scene_occlusion_cull.h"
+
+#include <embree3/rtcore.h>
+
+class RaycastOcclusionCull : public RendererSceneOcclusionCull {
+ typedef RTCRayHit16 RayPacket;
+
+public:
+ class RaycastHZBuffer : public HZBuffer {
+ private:
+ Size2i packs_size;
+
+ struct CameraRayThreadData {
+ CameraMatrix camera_matrix;
+ Transform camera_transform;
+ bool camera_orthogonal;
+ int thread_count;
+ Size2i buffer_size;
+ };
+
+ void _camera_rays_threaded(uint32_t p_thread, CameraRayThreadData *p_data);
+ void _generate_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to);
+
+ public:
+ LocalVector<RayPacket> camera_rays;
+ LocalVector<uint32_t> camera_ray_masks;
+ RID scenario_rid;
+
+ virtual void clear() override;
+ virtual void resize(const Size2i &p_size) override;
+ void sort_rays();
+ void update_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool);
+ };
+
+private:
+ struct InstanceID {
+ RID scenario;
+ RID instance;
+
+ bool operator<(const InstanceID &rhs) const {
+ if (instance == rhs.instance) {
+ return rhs.scenario < scenario;
+ }
+ return instance < rhs.instance;
+ }
+
+ InstanceID() {}
+ InstanceID(RID s, RID i) :
+ scenario(s), instance(i) {}
+ };
+
+ struct Occluder {
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+ Set<InstanceID> users;
+ };
+
+ struct OccluderInstance {
+ RID occluder;
+ LocalVector<uint32_t> indices;
+ LocalVector<Vector3> xformed_vertices;
+ Transform xform;
+ bool enabled = true;
+ bool removed = false;
+ };
+
+ struct Scenario {
+ struct RaycastThreadData {
+ RayPacket *rays;
+ const uint32_t *masks;
+ };
+
+ struct TransformThreadData {
+ uint32_t thread_count;
+ uint32_t vertex_count;
+ Transform xform;
+ const Vector3 *read;
+ Vector3 *write;
+ };
+
+ Thread *commit_thread = nullptr;
+ bool commit_done = true;
+ bool dirty = false;
+ bool removed = false;
+
+ RTCScene ebr_scene[2] = { nullptr, nullptr };
+ int current_scene_idx = 0;
+
+ HashMap<RID, OccluderInstance> instances;
+ Set<RID> dirty_instances; // To avoid duplicates
+ LocalVector<RID> dirty_instances_array; // To iterate and split into threads
+ LocalVector<RID> removed_instances;
+
+ void _update_dirty_instance_thread(int p_idx, RID *p_instances);
+ void _update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool);
+ void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data);
+ void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform &p_xform, int p_from, int p_to);
+ static void _commit_scene(void *p_ud);
+ bool update(ThreadWorkPool &p_thread_pool);
+
+ void _raycast(uint32_t p_thread, const RaycastThreadData *p_raycast_data) const;
+ void raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const;
+ };
+
+ static RaycastOcclusionCull *raycast_singleton;
+
+ static const int TILE_SIZE = 4;
+ static const int TILE_RAYS = TILE_SIZE * TILE_SIZE;
+
+ RTCDevice ebr_device = nullptr;
+ RID_PtrOwner<Occluder> occluder_owner;
+ HashMap<RID, Scenario> scenarios;
+ HashMap<RID, RaycastHZBuffer> buffers;
+ RS::ViewportOcclusionCullingBuildQuality build_quality;
+
+ void _init_embree();
+
+public:
+ virtual bool is_occluder(RID p_rid) override;
+ virtual RID occluder_allocate() override;
+ virtual void occluder_initialize(RID p_occluder) override;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) override;
+ virtual void free_occluder(RID p_occluder) override;
+
+ virtual void add_scenario(RID p_scenario) override;
+ virtual void remove_scenario(RID p_scenario) override;
+ virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) override;
+ virtual void scenario_remove_instance(RID p_scenario, RID p_instance) override;
+
+ virtual void add_buffer(RID p_buffer) override;
+ virtual void remove_buffer(RID p_buffer) override;
+ virtual HZBuffer *buffer_get_ptr(RID p_buffer) override;
+ virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) override;
+ virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) override;
+ virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) override;
+ virtual RID buffer_get_debug_texture(RID p_buffer) override;
+
+ virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) override;
+
+ RaycastOcclusionCull();
+ ~RaycastOcclusionCull();
+};
+
+#endif // OCCLUSION_CULL_RAYCASTER_H
diff --git a/modules/etc/register_types.cpp b/modules/raycast/register_types.cpp
index b165bccb3e..78ca91309f 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/raycast/register_types.cpp
@@ -30,19 +30,20 @@
#include "register_types.h"
-#include "image_compress_etc.h"
-#include "texture_loader_pkm.h"
+#include "lightmap_raycaster.h"
+#include "raycast_occlusion_cull.h"
-static Ref<ResourceFormatPKM> resource_loader_pkm;
+RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
-void register_etc_types() {
- resource_loader_pkm.instance();
- ResourceLoader::add_resource_format_loader(resource_loader_pkm);
-
- _register_etc_compress_func();
+void register_raycast_types() {
+#ifdef TOOLS_ENABLED
+ LightmapRaycasterEmbree::make_default_raycaster();
+#endif
+ raycast_occlusion_cull = memnew(RaycastOcclusionCull);
}
-void unregister_etc_types() {
- ResourceLoader::remove_resource_format_loader(resource_loader_pkm);
- resource_loader_pkm.unref();
+void unregister_raycast_types() {
+ if (raycast_occlusion_cull) {
+ memdelete(raycast_occlusion_cull);
+ }
}
diff --git a/modules/etc/register_types.h b/modules/raycast/register_types.h
index e8cbb635ae..789604a491 100644
--- a/modules/etc/register_types.h
+++ b/modules/raycast/register_types.h
@@ -28,10 +28,5 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ETC_REGISTER_TYPES_H
-#define ETC_REGISTER_TYPES_H
-
-void register_etc_types();
-void unregister_etc_types();
-
-#endif // ETC_REGISTER_TYPES_H
+void register_raycast_types();
+void unregister_raycast_types();
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_decompress_squish.cpp
index cce08034df..1450b0fe88 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_decompress_squish.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_squish.cpp */
+/* image_decompress_squish.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "image_compress_squish.h"
+#include "image_decompress_squish.h"
#include <squish.h>
@@ -76,83 +76,3 @@ void image_decompress_squish(Image *p_image) {
p_image->convert_ra_rgba8_to_rg();
}
}
-
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels) {
- if (p_image->get_format() >= Image::FORMAT_DXT1) {
- return; //do not compress, already compressed
- }
-
- int w = p_image->get_width();
- int h = p_image->get_height();
-
- if (p_image->get_format() <= Image::FORMAT_RGBA8) {
- int squish_comp = squish::kColourRangeFit;
-
- if (p_lossy_quality > 0.85) {
- squish_comp = squish::kColourIterativeClusterFit;
- } else if (p_lossy_quality > 0.75) {
- squish_comp = squish::kColourClusterFit;
- }
-
- Image::Format target_format = Image::FORMAT_RGBA8;
-
- p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
-
- switch (p_channels) {
- case Image::USED_CHANNELS_L: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_LA: {
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
- } break;
- case Image::USED_CHANNELS_R: {
- target_format = Image::FORMAT_RGTC_R;
- squish_comp |= squish::kBc4;
- } break;
- case Image::USED_CHANNELS_RG: {
- target_format = Image::FORMAT_RGTC_RG;
- squish_comp |= squish::kBc5;
- } break;
- case Image::USED_CHANNELS_RGB: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_RGBA: {
- //TODO, should convert both, then measure which one does a better job
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
-
- } break;
- default: {
- ERR_PRINT("Unknown image format, defaulting to RGBA8");
- break;
- }
- }
-
- Vector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
- int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
- data.resize(target_size);
- int shift = Image::get_format_pixel_rshift(target_format);
-
- const uint8_t *rb = p_image->get_data().ptr();
- uint8_t *wb = data.ptrw();
-
- int dst_ofs = 0;
-
- for (int i = 0; i <= mm_count; i++) {
- int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
- int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
-
- int src_ofs = p_image->get_mipmap_offset(i);
- squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp);
- dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
- w = MAX(w / 2, 1);
- h = MAX(h / 2, 1);
- }
-
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
- }
-}
diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_decompress_squish.h
index 301d30fcf1..fff5839ac4 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/squish/image_decompress_squish.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_squish.h */
+/* image_decompress_squish.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_COMPRESS_SQUISH_H
-#define IMAGE_COMPRESS_SQUISH_H
+#ifndef IMAGE_DECOMPRESS_SQUISH_H
+#define IMAGE_DECOMPRESS_SQUISH_H
#include "core/io/image.h"
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels);
void image_decompress_squish(Image *p_image);
-#endif // IMAGE_COMPRESS_SQUISH_H
+#endif // IMAGE_DECOMPRESS_SQUISH_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index 451e9d8e93..51aab040e7 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -29,10 +29,10 @@
/*************************************************************************/
#include "register_types.h"
-#include "image_compress_squish.h"
+
+#include "image_decompress_squish.h"
void register_squish_types() {
- Image::set_compress_bc_func(image_compress_squish);
Image::_image_decompress_bc = image_decompress_squish;
}
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index f7bf650354..e8e481de2d 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -47,7 +47,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, buffer, todo * 2);
if (vorbis_stream->channels == 1 && mixed > 0) {
//mix mono to stereo
- for (int i = start_buffer; i < mixed; i++) {
+ for (int i = start_buffer; i < start_buffer + mixed; i++) {
p_buffer[i].r = p_buffer[i].l;
}
}
@@ -204,7 +204,7 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
clear_data();
data = memalloc(src_data_len);
- copymem(data, src_datar, src_data_len);
+ memcpy(data, src_datar, src_data_len);
data_len = src_data_len;
break;
@@ -221,7 +221,7 @@ Vector<uint8_t> AudioStreamOGGVorbis::get_data() const {
vdata.resize(data_len);
{
uint8_t *w = vdata.ptrw();
- copymem(w, data, data_len);
+ memcpy(w, data, data_len);
}
}
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 3589c8546d..a55b6dc283 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -38,6 +38,7 @@ def make_icu_data(target, source, env):
# Thirdparty source files
thirdparty_obj = []
+freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"])
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
@@ -57,11 +58,9 @@ if env["builtin_harfbuzz"]:
"src/hb-face.cc",
"src/hb-fallback-shape.cc",
"src/hb-font.cc",
- "src/hb-ft.cc",
#'src/hb-gdi.cc',
#'src/hb-glib.cc',
#'src/hb-gobject-structs.cc',
- "src/hb-graphite2.cc",
"src/hb-icu.cc",
"src/hb-map.cc",
"src/hb-number.cc",
@@ -84,8 +83,8 @@ if env["builtin_harfbuzz"]:
"src/hb-ot-shape-complex-indic.cc",
"src/hb-ot-shape-complex-khmer.cc",
"src/hb-ot-shape-complex-myanmar.cc",
+ "src/hb-ot-shape-complex-syllabic.cc",
"src/hb-ot-shape-complex-thai.cc",
- "src/hb-ot-shape-complex-use-table.cc",
"src/hb-ot-shape-complex-use.cc",
"src/hb-ot-shape-complex-vowel-constraints.cc",
"src/hb-ot-shape-fallback.cc",
@@ -109,17 +108,29 @@ if env["builtin_harfbuzz"]:
"src/hb-unicode.cc",
#'src/hb-uniscribe.cc'
]
+
+ if freetype_enabled:
+ thirdparty_sources += [
+ "src/hb-ft.cc",
+ "src/hb-graphite2.cc",
+ ]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_harfbuzz.Append(
CPPPATH=[
"#thirdparty/harfbuzz/src",
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
"#thirdparty/icu4c/common/",
]
)
+ if freetype_enabled:
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ ]
+ )
+
if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
@@ -133,12 +144,18 @@ if env["builtin_harfbuzz"]:
CCFLAGS=[
"-DHAVE_ICU_BUILTIN",
"-DHAVE_ICU",
- "-DHAVE_FREETYPE",
- "-DHAVE_GRAPHITE2",
- "-DGRAPHITE2_STATIC",
]
)
+ if freetype_enabled:
+ env_harfbuzz.Append(
+ CCFLAGS=[
+ "-DHAVE_FREETYPE",
+ "-DHAVE_GRAPHITE2",
+ "-DGRAPHITE2_STATIC",
+ ]
+ )
+
lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
thirdparty_obj += lib
@@ -156,7 +173,7 @@ if env["builtin_harfbuzz"]:
env.Append(LIBS=[lib])
-if env["builtin_graphite"]:
+if env["builtin_graphite"] and freetype_enabled:
env_graphite = env_modules.Clone()
env_graphite.disable_warnings()
@@ -431,7 +448,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt68l.dat"
+ icu_data_name = "icudt69l.dat"
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
@@ -488,12 +505,18 @@ if env_text_server_adv["tools"]:
env_text_server_adv.Append(
CPPPATH=[
"#thirdparty/harfbuzz/src",
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
"#thirdparty/icu4c/common/",
]
)
+if freetype_enabled:
+ env_text_server_adv.Append(
+ CPPPATH=[
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ ]
+ )
+
env_text_server_adv.add_source_files(module_obj, "*.cpp")
env.modules_sources += module_obj
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
index df771301e6..df7b42eac6 100644
--- a/modules/text_server_adv/bitmap_font_adv.cpp
+++ b/modules/text_server_adv/bitmap_font_adv.cpp
@@ -361,67 +361,71 @@ Error BitmapFontDataAdvanced::load_from_file(const String &p_filename, int p_bas
base_size = height;
}
+ if (hb_handle) {
+ hb_font_destroy(hb_handle);
+ }
+ hb_handle = hb_bmp_font_create(this, base_size, nullptr);
valid = true;
memdelete(f);
return OK;
}
-Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(p_data == nullptr, ERR_CANT_CREATE);
- ERR_FAIL_COND_V(p_size != sizeof(TextServer::BitmapFontData), ERR_CANT_CREATE);
-
- const TextServer::BitmapFontData *data = (const TextServer::BitmapFontData *)p_data;
-
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> image = memnew(Image(data->img));
- Ref<ImageTexture> tex = memnew(ImageTexture);
- tex->create_from_image(image);
+Error BitmapFontDataAdvanced::bitmap_new(float p_height, float p_ascent, int p_base_size) {
+ height = p_height;
+ ascent = p_ascent;
- textures.push_back(tex);
+ base_size = p_base_size;
+ if (base_size == 0) {
+ base_size = height;
}
- for (int i = 0; i < data->charcount; i++) {
- const int *c = &data->char_rects[i * 8];
-
- Character chr;
- chr.rect.position.x = c[1];
- chr.rect.position.y = c[2];
- chr.rect.size.x = c[3];
- chr.rect.size.y = c[4];
- if (c[7] < 0) {
- chr.advance.x = c[3];
- } else {
- chr.advance.x = c[7];
- }
- chr.align = Vector2(c[6], c[5]);
- char_map[c[0]] = chr;
+ char_map.clear();
+ textures.clear();
+ kerning_map.clear();
+ if (hb_handle) {
+ hb_font_destroy(hb_handle);
}
+ hb_handle = hb_bmp_font_create(this, base_size, nullptr);
+ valid = true;
- for (int i = 0; i < data->kerning_count; i++) {
- KerningPairKey kpk;
- kpk.A = data->kernings[i * 3 + 0];
- kpk.B = data->kernings[i * 3 + 1];
+ return OK;
+}
- if (data->kernings[i * 3 + 2] == 0 && kerning_map.has(kpk)) {
- kerning_map.erase(kpk);
- } else {
- kerning_map[kpk] = data->kernings[i * 3 + 2];
- }
- }
+void BitmapFontDataAdvanced::bitmap_add_texture(const Ref<Texture> &p_texture) {
+ ERR_FAIL_COND(!valid);
+ ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object.");
- height = data->height;
- ascent = data->ascent;
+ textures.push_back(p_texture);
+}
- base_size = p_base_size;
- if (base_size == 0) {
- base_size = height;
+void BitmapFontDataAdvanced::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ ERR_FAIL_COND(!valid);
+
+ Character chr;
+ chr.rect = p_rect;
+ chr.texture_idx = p_texture_idx;
+ if (p_advance < 0) {
+ chr.advance.x = chr.rect.size.x;
+ } else {
+ chr.advance.x = p_advance;
}
+ chr.align = p_align;
+ char_map[p_char] = chr;
+}
- valid = true;
+void BitmapFontDataAdvanced::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) {
+ ERR_FAIL_COND(!valid);
- return OK;
+ KerningPairKey kpk;
+ kpk.A = p_A;
+ kpk.B = p_B;
+
+ if (p_kerning == 0 && kerning_map.has(kpk)) {
+ kerning_map.erase(kpk);
+ } else {
+ kerning_map[kpk] = p_kerning;
+ }
}
float BitmapFontDataAdvanced::get_height(int p_size) const {
@@ -464,10 +468,7 @@ float BitmapFontDataAdvanced::get_base_size() const {
hb_font_t *BitmapFontDataAdvanced::get_hb_handle(int p_size) {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!valid, nullptr);
- if (!cache.has(p_size)) {
- cache[p_size] = hb_bmp_font_create(this, p_size, nullptr);
- }
- return cache[p_size];
+ return hb_handle;
}
bool BitmapFontDataAdvanced::has_char(char32_t p_char) const {
@@ -514,6 +515,10 @@ Vector2 BitmapFontDataAdvanced::get_size(uint32_t p_char, int p_size) const {
return c->rect.size * (float(p_size) / float(base_size));
}
+float BitmapFontDataAdvanced::get_font_scale(int p_size) const {
+ return float(p_size) / float(base_size);
+}
+
Vector2 BitmapFontDataAdvanced::get_kerning(uint32_t p_char, uint32_t p_next, int p_size) const {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!valid, Vector2());
@@ -541,13 +546,13 @@ Vector2 BitmapFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vecto
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
if (c->texture_idx != -1) {
Point2i cpos = p_pos;
- cpos += c->align * (float(p_size) / float(base_size));
- cpos.y -= ascent * (float(p_size) / float(base_size));
+ cpos += (c->align + Vector2(0, -ascent)) * (float(p_size) / float(base_size));
+ Size2i csize = c->rect.size * (float(p_size) / float(base_size));
if (RenderingServer::get_singleton() != nullptr) {
//if (distance_field_hint) { // Not implemented.
// RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, true);
//}
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, c->rect.size * (float(p_size) / float(base_size))), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
//if (distance_field_hint) {
// RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, false);
//}
@@ -574,7 +579,7 @@ Vector2 BitmapFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, int
}
BitmapFontDataAdvanced::~BitmapFontDataAdvanced() {
- for (Map<float, hb_font_t *>::Element *E = cache.front(); E; E = E->next()) {
- hb_font_destroy(E->get());
+ if (hb_handle) {
+ hb_font_destroy(hb_handle);
}
}
diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h
index c314f1b087..7b620021e1 100644
--- a/modules/text_server_adv/bitmap_font_adv.h
+++ b/modules/text_server_adv/bitmap_font_adv.h
@@ -63,18 +63,22 @@ private:
HashMap<uint32_t, Character> char_map;
Map<KerningPairKey, int> kerning_map;
- Map<float, hb_font_t *> cache;
+ hb_font_t *hb_handle = nullptr;
float height = 0.f;
float ascent = 0.f;
- float base_size = 0.f;
+ int base_size = 0;
bool distance_field_hint = false;
public:
virtual void clear_cache() override{};
virtual Error load_from_file(const String &p_filename, int p_base_size) override;
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+ virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) override;
+
+ virtual void bitmap_add_texture(const Ref<Texture> &p_texture) override;
+ virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
+ virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) override;
virtual float get_height(int p_size) const override;
virtual float get_ascent(int p_size) const override;
@@ -97,6 +101,7 @@ public:
virtual bool has_outline() const override { return false; };
virtual float get_base_size() const override;
+ virtual float get_font_scale(int p_size) const override;
virtual hb_font_t *get_hb_handle(int p_size) override;
diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py
index 22482fce24..d22f9454ed 100644
--- a/modules/text_server_adv/config.py
+++ b/modules/text_server_adv/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return env.module_check_dependencies("text_server_adv", ["freetype"])
+ return True
def configure(env):
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 5a16158c0f..326af7f0ee 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -30,6 +30,8 @@
#include "dynamic_font_adv.h"
+#ifdef MODULE_FREETYPE_ENABLED
+
#include FT_STROKER_H
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
@@ -124,10 +126,10 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
fds->size = p_size;
fds->ascent = (fds->face->size->metrics.ascender / 64.0) / oversampling * fds->scale_color_font;
fds->descent = (-fds->face->size->metrics.descender / 64.0) / oversampling * fds->scale_color_font;
- fds->underline_position = -fds->face->underline_position / 64.0 / oversampling * fds->scale_color_font;
- fds->underline_thickness = fds->face->underline_thickness / 64.0 / oversampling * fds->scale_color_font;
+ fds->underline_position = (-FT_MulFix(fds->face->underline_position, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
+ fds->underline_thickness = (FT_MulFix(fds->face->underline_thickness, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
- //Load os2 TTF pable
+ //Load os2 TTF table
fds->os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fds->face, FT_SFNT_OS2);
fds->hb_handle = hb_ft_font_create(fds->face, nullptr);
@@ -229,7 +231,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
Dictionary out;
// Read feature flags.
- unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags);
@@ -238,7 +240,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
}
memfree(feature_tags);
}
- count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags);
@@ -637,7 +639,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
ERR_FAIL_COND_V(fds == nullptr, false);
- unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags);
@@ -649,7 +651,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
}
memfree(script_tags);
}
- count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags);
@@ -995,9 +997,34 @@ Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, in
return advance;
}
+bool DynamicFontDataAdvanced::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, false);
+
+ r_points.clear();
+ r_contours.clear();
+
+ float h = fds->ascent;
+ float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font;
+ for (short i = 0; i < fds->face->glyph->outline.n_points; i++) {
+ r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i])));
+ }
+ for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) {
+ r_contours.push_back(fds->face->glyph->outline.contours[i]);
+ }
+ r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ return true;
+}
+
DynamicFontDataAdvanced::~DynamicFontDataAdvanced() {
clear_cache();
if (library != nullptr) {
FT_Done_FreeType(library);
}
}
+
+#endif // MODULE_FREETYPE_ENABLED
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
index cd538cb8e1..1292966f0c 100644
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -33,6 +33,10 @@
#include "font_adv.h"
+#include "modules/modules_enabled.gen.h"
+
+#ifdef MODULE_FREETYPE_ENABLED
+
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_TRUETYPE_TABLES_H
@@ -182,7 +186,11 @@ public:
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual ~DynamicFontDataAdvanced() override;
};
+#endif // MODULE_FREETYPE_ENABLED
+
#endif // DYNAMIC_FONT_ADV_H
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
index 4bbd2dd4bf..4fadefc569 100644
--- a/modules/text_server_adv/font_adv.h
+++ b/modules/text_server_adv/font_adv.h
@@ -39,11 +39,18 @@ struct FontDataAdvanced {
Map<String, bool> lang_support_overrides;
Map<String, bool> script_support_overrides;
bool valid = false;
+ int spacing_space = 0;
+ int spacing_glyph = 0;
virtual void clear_cache() = 0;
- virtual Error load_from_file(const String &p_filename, int p_base_size) = 0;
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) = 0;
+ virtual Error load_from_file(const String &p_filename, int p_base_size) { return ERR_CANT_CREATE; };
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) { return ERR_CANT_CREATE; };
+ virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) { return ERR_CANT_CREATE; };
+
+ virtual void bitmap_add_texture(const Ref<Texture> &p_texture) { ERR_FAIL_MSG("Not supported."); };
+ virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { ERR_FAIL_MSG("Not supported."); };
+ virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { ERR_FAIL_MSG("Not supported."); };
virtual float get_height(int p_size) const = 0;
virtual float get_ascent(int p_size) const = 0;
@@ -58,6 +65,18 @@ struct FontDataAdvanced {
virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
+ virtual int get_spacing_space() const { return spacing_space; };
+ virtual void set_spacing_space(int p_value) {
+ spacing_space = p_value;
+ clear_cache();
+ };
+
+ virtual int get_spacing_glyph() const { return spacing_glyph; };
+ virtual void set_spacing_glyph(int p_value) {
+ spacing_glyph = p_value;
+ clear_cache();
+ };
+
virtual void set_antialiased(bool p_antialiased) = 0;
virtual bool get_antialiased() const = 0;
@@ -73,8 +92,8 @@ struct FontDataAdvanced {
virtual bool has_outline() const = 0;
virtual float get_base_size() const = 0;
- virtual bool is_lang_supported(const String &p_lang) const { return false; };
- virtual bool is_script_supported(uint32_t p_script) const { return false; };
+ virtual bool is_lang_supported(const String &p_lang) const { return true; };
+ virtual bool is_script_supported(uint32_t p_script) const { return true; };
virtual bool has_char(char32_t p_char) const = 0;
virtual String get_supported_chars() const = 0;
@@ -88,6 +107,8 @@ struct FontDataAdvanced {
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; };
+
virtual ~FontDataAdvanced(){};
};
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 8f23bb9e02..f9bbd25a5f 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -75,10 +75,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) {
paren_sp -= 1;
}
- if (paren_sp < start_sp)
+ if (paren_sp < start_sp) {
start_sp = paren_sp;
- if (paren_sp >= 0)
+ }
+ if (paren_sp >= 0) {
sc = paren_stack[paren_sp].script_code;
+ }
}
}
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 8e4771685d..8b8b6b7cd3 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -166,7 +166,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
#ifdef ICU_STATIC_DATA
if (icu_data == nullptr) {
UErrorCode err = U_ZERO_ERROR;
- u_init(&err); // Do not check for errors, since we only load part the of data.
+ u_init(&err); // Do not check for errors, since we only load part of the data.
icu_data = (uint8_t *)&U_ICUDATA_ENTRY_POINT;
}
#else
@@ -244,7 +244,7 @@ struct FeatureInfo {
};
static FeatureInfo feature_set[] = {
- // Registred OpenType feature tags.
+ // Registered OpenType feature tags.
{ HB_TAG('a', 'a', 'l', 't'), "access_all_alternates" },
{ HB_TAG('a', 'b', 'v', 'f'), "above_base_forms" },
{ HB_TAG('a', 'b', 'v', 'm'), "above_base_mark_positioning" },
@@ -484,7 +484,7 @@ static FeatureInfo feature_set[] = {
{ HB_TAG('v', 'r', 't', '2'), "vertical_alternates_and_rotation" },
{ HB_TAG('v', 'r', 't', 'r'), "vertical_alternates_for_rotation" },
{ HB_TAG('z', 'e', 'r', 'o'), "slashed_zero" },
- // Registred OpenType variation tags.
+ // Registered OpenType variation tags.
{ HB_TAG('i', 't', 'a', 'l'), "italic" },
{ HB_TAG('o', 'p', 's', 'z'), "optical_size" },
{ HB_TAG('s', 'l', 'n', 't'), "slant" },
@@ -529,10 +529,12 @@ RID TextServerAdvanced::create_font_system(const String &p_name, int p_base_size
RID TextServerAdvanced::create_font_resource(const String &p_filename, int p_base_size) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = nullptr;
- if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
- fd = memnew(DynamicFontDataAdvanced);
- } else if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
+ if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
fd = memnew(BitmapFontDataAdvanced);
+#ifdef MODULE_FREETYPE_ENABLED
+ } else if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
+ fd = memnew(DynamicFontDataAdvanced);
+#endif
} else {
return RID();
}
@@ -549,10 +551,12 @@ RID TextServerAdvanced::create_font_resource(const String &p_filename, int p_bas
RID TextServerAdvanced::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = nullptr;
- if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
- fd = memnew(DynamicFontDataAdvanced);
- } else if (p_type == "fnt" || p_type == "font") {
+ if (p_type == "fnt" || p_type == "font") {
fd = memnew(BitmapFontDataAdvanced);
+#ifdef MODULE_FREETYPE_ENABLED
+ } else if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
+ fd = memnew(DynamicFontDataAdvanced);
+#endif
} else {
return RID();
}
@@ -566,6 +570,39 @@ RID TextServerAdvanced::create_font_memory(const uint8_t *p_data, size_t p_size,
return font_owner.make_rid(fd);
}
+RID TextServerAdvanced::create_font_bitmap(float p_height, float p_ascent, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = memnew(BitmapFontDataAdvanced);
+ Error err = fd->bitmap_new(p_height, p_ascent, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+void TextServerAdvanced::font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_texture(p_texture);
+}
+
+void TextServerAdvanced::font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_char(p_char, p_texture_idx, p_rect, p_align, p_advance);
+}
+
+void TextServerAdvanced::font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_kerning_pair(p_A, p_B, p_kerning);
+}
+
float TextServerAdvanced::font_get_height(RID p_font, int p_size) const {
_THREAD_SAFE_METHOD_
const FontDataAdvanced *fd = font_owner.getornull(p_font);
@@ -601,6 +638,34 @@ float TextServerAdvanced::font_get_underline_thickness(RID p_font, int p_size) c
return fd->get_underline_thickness(p_size);
}
+int TextServerAdvanced::font_get_spacing_space(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_spacing_space();
+}
+
+void TextServerAdvanced::font_set_spacing_space(RID p_font, int p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_spacing_space(p_value);
+}
+
+int TextServerAdvanced::font_get_spacing_glyph(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_spacing_glyph();
+}
+
+void TextServerAdvanced::font_set_spacing_glyph(RID p_font, int p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_spacing_glyph(p_value);
+}
+
void TextServerAdvanced::font_set_antialiased(RID p_font, bool p_antialiased) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
@@ -841,6 +906,13 @@ Vector2 TextServerAdvanced::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
}
+bool TextServerAdvanced::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation);
+}
+
float TextServerAdvanced::font_get_oversampling() const {
return oversampling;
}
@@ -1595,7 +1667,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
}
if (sd->line_breaks_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
const UChar *data = sd->utf16.ptr();
@@ -1760,8 +1832,9 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
}
}
}
- if (!is_transparent(c))
+ if (!is_transparent(c)) {
pc = c;
+ }
i++;
}
@@ -1780,7 +1853,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
}
if (sd->justification_ops_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
const UChar *data = sd->utf16.ptr();
@@ -2049,6 +2122,11 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
}
+ if (fd->get_spacing_space() && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
+ gl.advance += fd->get_spacing_space();
+ } else {
+ gl.advance += fd->get_spacing_glyph();
+ }
if (p_sd->preserve_control) {
last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || is_whitespace(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster]));
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 89fae477f9..4ad23ca059 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -126,6 +126,11 @@ public:
virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+ virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) override;
+
+ virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) override;
+ virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
+ virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) override;
virtual float font_get_height(RID p_font, int p_size) const override;
virtual float font_get_ascent(RID p_font, int p_size) const override;
@@ -134,6 +139,12 @@ public:
virtual float font_get_underline_position(RID p_font, int p_size) const override;
virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+ virtual int font_get_spacing_space(RID p_font) const override;
+ virtual void font_set_spacing_space(RID p_font, int p_value) override;
+
+ virtual int font_get_spacing_glyph(RID p_font) const override;
+ virtual void font_set_spacing_glyph(RID p_font, int p_value) override;
+
virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
virtual bool font_get_antialiased(RID p_font) const override;
@@ -177,6 +188,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp
index c9a9cc6eba..313f170f04 100644
--- a/modules/text_server_fb/bitmap_font_fb.cpp
+++ b/modules/text_server_fb/bitmap_font_fb.cpp
@@ -175,61 +175,58 @@ Error BitmapFontDataFallback::load_from_file(const String &p_filename, int p_bas
return OK;
}
-Error BitmapFontDataFallback::load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) {
- _THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(p_data == nullptr, ERR_CANT_CREATE);
- ERR_FAIL_COND_V(p_size != sizeof(TextServer::BitmapFontData), ERR_CANT_CREATE);
+Error BitmapFontDataFallback::bitmap_new(float p_height, float p_ascent, int p_base_size) {
+ height = p_height;
+ ascent = p_ascent;
- const TextServer::BitmapFontData *data = (const TextServer::BitmapFontData *)p_data;
+ base_size = p_base_size;
+ if (base_size == 0) {
+ base_size = height;
+ }
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> image = memnew(Image(data->img));
- Ref<ImageTexture> tex = memnew(ImageTexture);
- tex->create_from_image(image);
+ char_map.clear();
+ textures.clear();
+ kerning_map.clear();
- textures.push_back(tex);
- }
+ valid = true;
- for (int i = 0; i < data->charcount; i++) {
- const int *c = &data->char_rects[i * 8];
-
- Character chr;
- chr.rect.position.x = c[1];
- chr.rect.position.y = c[2];
- chr.rect.size.x = c[3];
- chr.rect.size.y = c[4];
- if (c[7] < 0) {
- chr.advance.x = c[3];
- } else {
- chr.advance.x = c[7];
- }
- chr.align = Vector2(c[6], c[5]);
- char_map[c[0]] = chr;
- }
+ return OK;
+}
- for (int i = 0; i < data->kerning_count; i++) {
- KerningPairKey kpk;
- kpk.A = data->kernings[i * 3 + 0];
- kpk.B = data->kernings[i * 3 + 1];
+void BitmapFontDataFallback::bitmap_add_texture(const Ref<Texture> &p_texture) {
+ ERR_FAIL_COND(!valid);
+ ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object.");
- if (data->kernings[i * 3 + 2] == 0 && kerning_map.has(kpk)) {
- kerning_map.erase(kpk);
- } else {
- kerning_map[kpk] = data->kernings[i * 3 + 2];
- }
- }
+ textures.push_back(p_texture);
+}
- height = data->height;
- ascent = data->ascent;
+void BitmapFontDataFallback::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ ERR_FAIL_COND(!valid);
- base_size = p_base_size;
- if (base_size == 0) {
- base_size = height;
+ Character chr;
+ chr.rect = p_rect;
+ chr.texture_idx = p_texture_idx;
+ if (p_advance < 0) {
+ chr.advance.x = chr.rect.size.x;
+ } else {
+ chr.advance.x = p_advance;
}
+ chr.align = p_align;
+ char_map[p_char] = chr;
+}
- valid = true;
+void BitmapFontDataFallback::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) {
+ ERR_FAIL_COND(!valid);
- return OK;
+ KerningPairKey kpk;
+ kpk.A = p_A;
+ kpk.B = p_B;
+
+ if (p_kerning == 0 && kerning_map.has(kpk)) {
+ kerning_map.erase(kpk);
+ } else {
+ kerning_map[kpk] = p_kerning;
+ }
}
float BitmapFontDataFallback::get_height(int p_size) const {
@@ -322,14 +319,13 @@ Vector2 BitmapFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vecto
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2());
if (c->texture_idx != -1) {
Point2i cpos = p_pos;
- cpos += c->align * (float(p_size) / float(base_size));
- cpos.y -= ascent * (float(p_size) / float(base_size));
-
+ cpos += (c->align + Vector2(0, -ascent)) * (float(p_size) / float(base_size));
+ Size2i csize = c->rect.size * (float(p_size) / float(base_size));
if (RenderingServer::get_singleton() != nullptr) {
//if (distance_field_hint) { // Not implemented.
// RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, true);
//}
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, c->rect.size * (float(p_size) / float(base_size))), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), textures[c->texture_idx]->get_rid(), c->rect, p_color, false, false);
//if (distance_field_hint) {
// RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(p_canvas, false);
//}
diff --git a/modules/text_server_fb/bitmap_font_fb.h b/modules/text_server_fb/bitmap_font_fb.h
index 33401b85fa..7cd7507ebc 100644
--- a/modules/text_server_fb/bitmap_font_fb.h
+++ b/modules/text_server_fb/bitmap_font_fb.h
@@ -70,7 +70,11 @@ public:
virtual void clear_cache() override{};
virtual Error load_from_file(const String &p_filename, int p_base_size) override;
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) override;
+ virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) override;
+
+ virtual void bitmap_add_texture(const Ref<Texture> &p_texture) override;
+ virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
+ virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) override;
virtual float get_height(int p_size) const override;
virtual float get_ascent(int p_size) const override;
diff --git a/modules/text_server_fb/config.py b/modules/text_server_fb/config.py
index 491377a369..7a73080ae9 100644
--- a/modules/text_server_fb/config.py
+++ b/modules/text_server_fb/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return env.module_check_dependencies("text_server_fb", ["freetype"])
+ return True
def configure(env):
diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp
index df7756cbd0..dec1d6f83f 100644
--- a/modules/text_server_fb/dynamic_font_fb.cpp
+++ b/modules/text_server_fb/dynamic_font_fb.cpp
@@ -30,6 +30,8 @@
#include "dynamic_font_fb.h"
+#ifdef MODULE_FREETYPE_ENABLED
+
#include FT_STROKER_H
#include FT_ADVANCES_H
@@ -124,8 +126,9 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
fds->size = p_size;
fds->ascent = (fds->face->size->metrics.ascender / 64.0) / oversampling * fds->scale_color_font;
fds->descent = (-fds->face->size->metrics.descender / 64.0) / oversampling * fds->scale_color_font;
- fds->underline_position = -fds->face->underline_position / 64.0 / oversampling * fds->scale_color_font;
- fds->underline_thickness = fds->face->underline_thickness / 64.0 / oversampling * fds->scale_color_font;
+ fds->underline_position = (-FT_MulFix(fds->face->underline_position, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
+ fds->underline_thickness = (FT_MulFix(fds->face->underline_thickness, fds->face->size->metrics.y_scale) / 64.0) / oversampling * fds->scale_color_font;
+
if (p_outline_size != 0) {
size_cache_outline[id] = fds;
} else {
@@ -677,9 +680,34 @@ Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, in
return advance;
}
+bool DynamicFontDataFallback::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, false);
+
+ r_points.clear();
+ r_contours.clear();
+
+ float h = fds->ascent;
+ float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font;
+ for (short i = 0; i < fds->face->glyph->outline.n_points; i++) {
+ r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i])));
+ }
+ for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) {
+ r_contours.push_back(fds->face->glyph->outline.contours[i]);
+ }
+ r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ return true;
+}
+
DynamicFontDataFallback::~DynamicFontDataFallback() {
clear_cache();
if (library != nullptr) {
FT_Done_FreeType(library);
}
}
+
+#endif // MODULE_FREETYPE_ENABLED
diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h
index 81b18f6af3..b34c8cbed5 100644
--- a/modules/text_server_fb/dynamic_font_fb.h
+++ b/modules/text_server_fb/dynamic_font_fb.h
@@ -33,6 +33,10 @@
#include "font_fb.h"
+#include "modules/modules_enabled.gen.h"
+
+#ifdef MODULE_FREETYPE_ENABLED
+
#include <ft2build.h>
#include FT_FREETYPE_H
@@ -160,7 +164,11 @@ public:
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual ~DynamicFontDataFallback() override;
};
+#endif // MODULE_FREETYPE_ENABLED
+
#endif // DYNAMIC_FONT_FALLBACK_H
diff --git a/modules/text_server_fb/font_fb.h b/modules/text_server_fb/font_fb.h
index cc72919542..fe9888b7f4 100644
--- a/modules/text_server_fb/font_fb.h
+++ b/modules/text_server_fb/font_fb.h
@@ -37,11 +37,18 @@ struct FontDataFallback {
Map<String, bool> lang_support_overrides;
Map<String, bool> script_support_overrides;
bool valid = false;
+ int spacing_space = 0;
+ int spacing_glyph = 0;
virtual void clear_cache() = 0;
- virtual Error load_from_file(const String &p_filename, int p_base_size) = 0;
- virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) = 0;
+ virtual Error load_from_file(const String &p_filename, int p_base_size) { return ERR_CANT_CREATE; };
+ virtual Error load_from_memory(const uint8_t *p_data, size_t p_size, int p_base_size) { return ERR_CANT_CREATE; };
+ virtual Error bitmap_new(float p_height, float p_ascent, int p_base_size) { return ERR_CANT_CREATE; };
+
+ virtual void bitmap_add_texture(const Ref<Texture> &p_texture) { ERR_FAIL_MSG("Not supported."); };
+ virtual void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { ERR_FAIL_MSG("Not supported."); };
+ virtual void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { ERR_FAIL_MSG("Not supported."); };
virtual float get_height(int p_size) const = 0;
virtual float get_ascent(int p_size) const = 0;
@@ -50,6 +57,18 @@ struct FontDataFallback {
virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
+ virtual int get_spacing_space() const { return spacing_space; };
+ virtual void set_spacing_space(int p_value) {
+ spacing_space = p_value;
+ clear_cache();
+ };
+
+ virtual int get_spacing_glyph() const { return spacing_glyph; };
+ virtual void set_spacing_glyph(int p_value) {
+ spacing_glyph = p_value;
+ clear_cache();
+ };
+
virtual void set_antialiased(bool p_antialiased) = 0;
virtual bool get_antialiased() const = 0;
@@ -74,6 +93,8 @@ struct FontDataFallback {
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; };
+
virtual ~FontDataFallback(){};
};
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index e60d269408..98a67ef309 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -107,10 +107,12 @@ RID TextServerFallback::create_font_system(const String &p_name, int p_base_size
RID TextServerFallback::create_font_resource(const String &p_filename, int p_base_size) {
_THREAD_SAFE_METHOD_
FontDataFallback *fd = nullptr;
- if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
- fd = memnew(DynamicFontDataFallback);
- } else if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
+ if (p_filename.get_extension() == "fnt" || p_filename.get_extension() == "font") {
fd = memnew(BitmapFontDataFallback);
+#ifdef MODULE_FREETYPE_ENABLED
+ } else if (p_filename.get_extension() == "ttf" || p_filename.get_extension() == "otf" || p_filename.get_extension() == "woff") {
+ fd = memnew(DynamicFontDataFallback);
+#endif
} else {
return RID();
}
@@ -127,10 +129,12 @@ RID TextServerFallback::create_font_resource(const String &p_filename, int p_bas
RID TextServerFallback::create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size) {
_THREAD_SAFE_METHOD_
FontDataFallback *fd = nullptr;
- if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
- fd = memnew(DynamicFontDataFallback);
- } else if (p_type == "fnt" || p_type == "font") {
+ if (p_type == "fnt" || p_type == "font") {
fd = memnew(BitmapFontDataFallback);
+#ifdef MODULE_FREETYPE_ENABLED
+ } else if (p_type == "ttf" || p_type == "otf" || p_type == "woff") {
+ fd = memnew(DynamicFontDataFallback);
+#endif
} else {
return RID();
}
@@ -144,6 +148,39 @@ RID TextServerFallback::create_font_memory(const uint8_t *p_data, size_t p_size,
return font_owner.make_rid(fd);
}
+RID TextServerFallback::create_font_bitmap(float p_height, float p_ascent, int p_base_size) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = memnew(BitmapFontDataFallback);
+ Error err = fd->bitmap_new(p_height, p_ascent, p_base_size);
+ if (err != OK) {
+ memdelete(fd);
+ return RID();
+ }
+
+ return font_owner.make_rid(fd);
+}
+
+void TextServerFallback::font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_texture(p_texture);
+}
+
+void TextServerFallback::font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_char(p_char, p_texture_idx, p_rect, p_align, p_advance);
+}
+
+void TextServerFallback::font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->bitmap_add_kerning_pair(p_A, p_B, p_kerning);
+}
+
float TextServerFallback::font_get_height(RID p_font, int p_size) const {
_THREAD_SAFE_METHOD_
const FontDataFallback *fd = font_owner.getornull(p_font);
@@ -179,6 +216,34 @@ float TextServerFallback::font_get_underline_thickness(RID p_font, int p_size) c
return fd->get_underline_thickness(p_size);
}
+int TextServerFallback::font_get_spacing_space(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_spacing_space();
+}
+
+void TextServerFallback::font_set_spacing_space(RID p_font, int p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_spacing_space(p_value);
+}
+
+int TextServerFallback::font_get_spacing_glyph(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_spacing_glyph();
+}
+
+void TextServerFallback::font_set_spacing_glyph(RID p_font, int p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_spacing_glyph(p_value);
+}
+
void TextServerFallback::font_set_antialiased(RID p_font, bool p_antialiased) {
_THREAD_SAFE_METHOD_
FontDataFallback *fd = font_owner.getornull(p_font);
@@ -387,6 +452,13 @@ Vector2 TextServerFallback::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
}
+bool TextServerFallback::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation);
+}
+
float TextServerFallback::font_get_oversampling() const {
return oversampling;
}
@@ -1026,7 +1098,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
}
if (sd->line_breaks_valid) {
- return true; // Noting to do.
+ return true; // Nothing to do.
}
int sd_size = sd->glyphs.size();
@@ -1184,6 +1256,11 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
}
}
+ if (fd->get_spacing_space() && is_whitespace(sd->text[j])) {
+ gl.advance += fd->get_spacing_space();
+ } else {
+ gl.advance += fd->get_spacing_glyph();
+ }
sd->upos = MAX(sd->upos, fd->get_underline_position(gl.font_size));
sd->uthk = MAX(sd->uthk, fd->get_underline_thickness(gl.font_size));
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index d142b320e4..8f5eb1d315 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -81,6 +81,11 @@ public:
virtual RID create_font_system(const String &p_name, int p_base_size = 16) override;
virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) override;
virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) override;
+ virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) override;
+
+ virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) override;
+ virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) override;
+ virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) override;
virtual float font_get_height(RID p_font, int p_size) const override;
virtual float font_get_ascent(RID p_font, int p_size) const override;
@@ -89,6 +94,12 @@ public:
virtual float font_get_underline_position(RID p_font, int p_size) const override;
virtual float font_get_underline_thickness(RID p_font, int p_size) const override;
+ virtual int font_get_spacing_space(RID p_font) const override;
+ virtual void font_set_spacing_space(RID p_font, int p_value) override;
+
+ virtual int font_get_spacing_glyph(RID p_font) const override;
+ virtual void font_set_spacing_glyph(RID p_font, int p_value) override;
+
virtual void font_set_antialiased(RID p_font, bool p_antialiased) override;
virtual bool font_get_antialiased(RID p_font) const override;
@@ -126,6 +137,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index afe26d4a5f..54f5b3f424 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -225,7 +225,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
/* identify the codec: try theora */
if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) {
/* it is theora */
- copymem(&to, &test, sizeof(test));
+ memcpy(&to, &test, sizeof(test));
theora_p = 1;
} else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) {
/* it is vorbis */
@@ -238,7 +238,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
audio_track_skip--;
} else {
- copymem(&vo, &test, sizeof(test));
+ memcpy(&vo, &test, sizeof(test));
vorbis_p = 1;
}
} else {
@@ -554,7 +554,7 @@ void VideoStreamPlaybackTheora::play() {
}
playing = true;
- delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms");
+ delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms");
delay_compensation /= 1000.0;
};
@@ -603,6 +603,7 @@ float VideoStreamPlaybackTheora::get_playback_position() const {
};
void VideoStreamPlaybackTheora::seek(float p_time) {
+ WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
}
void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
@@ -677,7 +678,7 @@ void VideoStreamTheora::_bind_methods() {
////////////
-RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderTheora::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) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 71e56e2ee8..2685a8a013 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -36,6 +36,7 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/ring_buffer.h"
+#include "core/templates/safe_refcount.h"
#include "scene/resources/video_stream.h"
#include "servers/audio_server.h"
@@ -113,7 +114,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
bool thread_eof = false;
Semaphore *thread_sem;
Thread thread;
- volatile bool thread_exit = false;
+ SafeFlag thread_exit;
static void _streaming_thread(void *ud);
@@ -185,7 +186,7 @@ public:
class ResourceFormatLoaderTheora : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index bc0b215be3..b2fed0cb23 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -12,18 +12,19 @@ thirdparty_obj = []
if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
+ "igd_desc_parse.c",
"miniupnpc.c",
- "upnpcommands.c",
+ "minixml.c",
+ "minisoap.c",
+ "minissdpc.c",
"miniwget.c",
+ "upnpcommands.c",
"upnpdev.c",
- "igd_desc_parse.c",
- "minissdpc.c",
- "minisoap.c",
- "minixml.c",
+ "upnpreplyparse.c",
"connecthostport.c",
- "receivedata.c",
"portlistingparse.c",
- "upnpreplyparse.c",
+ "receivedata.c",
+ "addr_is_reserved.c",
]
thirdparty_sources = [thirdparty_dir + "miniupnpc/" + file for file in thirdparty_sources]
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index cff13251ce..8e4e833d45 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -52,10 +52,12 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) {
int error = 0;
struct UPNPDev *devlist;
+ CharString cs = discover_multicast_if.utf8();
+ const char *m_if = cs.length() ? cs.get_data() : nullptr;
if (is_common_device(device_filter)) {
- devlist = upnpDiscover(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
} else {
- devlist = upnpDiscoverAll(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
}
if (error != UPNPDISCOVER_SUCCESS) {
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 2517b17168..765a5fe023 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -784,8 +784,9 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) {
variables.get_key_list(&keys);
for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) {
- if (!variables[E->get()]._export)
+ if (!variables[E->get()]._export) {
continue;
+ }
PropertyInfo p = variables[E->get()].info;
p.name = String(E->get());
@@ -1369,7 +1370,7 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
// Is a default value (unassigned input port).
input_args[i] = &default_values[index];
} else {
- // Rregular temporary in stack.
+ // Regular temporary in stack.
input_args[i] = &variant_stack[index];
}
}
@@ -1391,7 +1392,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
ERR_FAIL_COND_V(!F, Variant());
Function *f = &F->get();
- // This call goes separate, so it can e yielded and suspended.
+ // This call goes separate, so it can be yielded and suspended.
Variant *variant_stack = (Variant *)p_stack;
bool *sequence_bits = (bool *)(variant_stack + f->max_stack);
const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
@@ -1536,7 +1537,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
state->flow_stack_pos = flow_stack_pos;
state->stack.resize(p_stack_size);
state->pass = p_pass;
- copymem(state->stack.ptrw(), p_stack, p_stack_size);
+ memcpy(state->stack.ptrw(), p_stack, p_stack_size);
// Step 2, run away, return directly.
r_error.error = Callable::CallError::CALL_OK;
@@ -1606,7 +1607,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
next = node->sequence_outputs[output];
- VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "NULL"));
+ VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "Null"));
}
if (flow_stack) {
@@ -1801,7 +1802,7 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
sequence_bits[i] = false; // All starts as false.
}
- zeromem(pass_stack, f->pass_stack_size * sizeof(int));
+ memset(pass_stack, 0, f->pass_stack_size * sizeof(int));
Map<int, VisualScriptNodeInstance *>::Element *E = instances.find(f->node);
if (!E) {
@@ -2050,12 +2051,12 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
instance->id = F->get();
instance->input_port_count = node->get_input_value_port_count();
- instance->input_ports = NULL;
+ instance->input_ports = nullptr;
instance->output_port_count = node->get_output_value_port_count();
- instance->output_ports = NULL;
+ instance->output_ports = nullptr;
instance->sequence_output_count = node->get_output_sequence_port_count();
instance->sequence_index = function.node_count++;
- instance->sequence_outputs = NULL;
+ instance->sequence_outputs = nullptr;
instance->pass_idx = -1;
if (instance->input_port_count) {
@@ -2075,7 +2076,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
if (instance->sequence_output_count) {
instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count);
for (int i = 0; i < instance->sequence_output_count; i++) {
- instance->sequence_outputs[i] = NULL; // If it remains null, flow ends here.
+ instance->sequence_outputs[i] = nullptr; // If it remains null, flow ends here.
}
}
@@ -2085,10 +2086,11 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
StringName var_name;
- if (Object::cast_to<VisualScriptLocalVar>(*node))
+ if (Object::cast_to<VisualScriptLocalVar>(*node)) {
var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges();
- else
+ } else {
var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges();
+ }
if (!local_var_indices.has(var_name)) {
local_var_indices[var_name] = function.max_stack;
@@ -2252,6 +2254,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int
}
void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds) {
+ ERR_FAIL_NULL(p_obj);
Vector<Variant> binds;
for (int i = 0; i < p_binds.size(); i++) {
binds.push_back(p_binds[i]);
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index b96311ba6c..7ca14fbca8 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -647,7 +647,7 @@ String VisualScriptBuiltinFunc::get_caption() const {
void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) {
ERR_FAIL_INDEX(p_which, FUNC_MAX);
func = p_which;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 92b83f3db0..02ec9ccd06 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -61,7 +61,7 @@ protected:
}
void _sig_changed() {
- _change_notify();
+ notify_property_list_changed();
emit_signal("changed");
}
@@ -172,7 +172,7 @@ protected:
public:
void edit(const StringName &p_sig) {
sig = p_sig;
- _change_notify();
+ notify_property_list_changed();
}
VisualScriptEditorSignalEdit() { undo_redo = nullptr; }
@@ -195,11 +195,10 @@ protected:
}
void _var_changed() {
- _change_notify();
+ notify_property_list_changed();
emit_signal("changed");
}
void _var_value_changed() {
- _change_notify("value"); // So the whole tree is not redrawn, makes editing smoother in general.
emit_signal("changed");
}
@@ -331,7 +330,7 @@ protected:
public:
void edit(const StringName &p_var) {
var = p_var;
- _change_notify();
+ notify_property_list_changed();
}
VisualScriptEditorVariableEdit() { undo_redo = nullptr; }
@@ -711,7 +710,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
has_gnode_text = true;
LineEdit *line_edit = memnew(LineEdit);
line_edit->set_text(node->get_text());
- line_edit->set_expand_to_text_length(true);
+ line_edit->set_expand_to_text_length_enabled(true);
line_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
gnode->add_child(line_edit);
line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get()));
@@ -844,7 +843,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
hbc->add_child(name_box);
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
name_box->set_text(left_name);
- name_box->set_expand_to_text_length(true);
+ name_box->set_expand_to_text_length_enabled(true);
name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true));
} else {
@@ -939,7 +938,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
hbc->add_child(name_box);
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
name_box->set_text(right_name);
- name_box->set_expand_to_text_length(true);
+ name_box->set_expand_to_text_length_enabled(true);
name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false));
} else {
@@ -1827,6 +1826,8 @@ void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool n
}
void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
// GUI input for VS Editor Plugin
Ref<InputEventMouseButton> key = p_event;
@@ -1838,7 +1839,7 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> key = p_event;
- if (key.is_valid() && key->is_pressed() && key->get_button_mask() == BUTTON_RIGHT) {
+ if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MOUSE_BUTTON_RIGHT) {
saved_position = graph->get_local_mouse_position();
Point2 gpos = Input::get_singleton()->get_mouse_position();
@@ -3016,9 +3017,9 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro
if (!vsn.is_valid()) {
return;
}
- if (vsn->get_output_value_port_count())
-
+ if (vsn->get_output_value_port_count()) {
port_action_pos = p_release_pos;
+ }
if (p_from_slot < vsn->get_output_sequence_port_count()) {
port_action_node = p_from.to_int();
@@ -3959,7 +3960,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
if (start_node == -1) {
// If we still don't have a start node then,
// run through the nodes and select the first tree node,
- // ie node without any input sequence but output sequence.
+ // i.e. node without any input sequence but output sequence.
for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {
if (!nodes_to.has(E->get())) {
start_node = E->get();
@@ -4275,13 +4276,13 @@ VisualScriptEditor::VisualScriptEditor() {
edit_menu->set_shortcut_context(this);
edit_menu->set_text(TTR("Edit"));
edit_menu->set_switch_on_hover(true);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_graph_delete"), EDIT_DELETE_NODES);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/copy_nodes"), EDIT_COPY_NODES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT_NODES);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE_NODES);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/create_function"), EDIT_CREATE_FUNCTION);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/refresh_nodes"), REFRESH_GRAPH);
@@ -4321,7 +4322,7 @@ VisualScriptEditor::VisualScriptEditor() {
function_name_box = memnew(LineEdit);
function_name_edit->add_child(function_name_box);
function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input));
- function_name_box->set_expand_to_text_length(true);
+ function_name_box->set_expand_to_text_length_enabled(true);
add_child(function_name_edit);
/// Actual Graph ///
@@ -4521,12 +4522,8 @@ void VisualScriptEditor::free_clipboard() {
static void register_editor_callback() {
ScriptEditor::register_create_script_editor_function(create_editor);
- ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"), KEY_DELETE);
ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD + KEY_F);
- ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD + KEY_C);
- ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD + KEY_X);
- ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD + KEY_V);
ED_SHORTCUT("visual_script_editor/create_function", TTR("Make Function"), KEY_MASK_CMD + KEY_G);
ED_SHORTCUT("visual_script_editor/refresh_nodes", TTR("Refresh Graph"), KEY_MASK_CMD + KEY_R);
ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KEY_MASK_CMD + KEY_E);
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index 469367ab59..cb4230bea9 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -63,7 +63,7 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val
}
expression_dirty = true;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -1054,7 +1054,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
}
}
- /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+ /* Reduce the set of expressions and place them in an operator tree, respecting precedence */
while (expression.size() > 1) {
int next_op = -1;
@@ -1506,6 +1506,19 @@ VisualScriptNodeInstance *VisualScriptExpression::instance(VisualScriptInstance
return instance;
}
+void VisualScriptExpression::reset_state() {
+ if (nodes) {
+ memdelete(nodes);
+ nodes = nullptr;
+ root = nullptr;
+ }
+
+ error_str = String();
+ error_set = false;
+ str_ofs = 0;
+ inputs.clear();
+}
+
VisualScriptExpression::VisualScriptExpression() {
}
diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h
index bbf76cef3b..c35075ea53 100644
--- a/modules/visual_script/visual_script_expression.h
+++ b/modules/visual_script/visual_script_expression.h
@@ -256,6 +256,8 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
+ virtual void reset_state() override;
+
virtual int get_output_sequence_port_count() const override;
virtual bool has_input_sequence_port() const override;
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index 0049e254c4..e977f9c96b 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -628,7 +628,7 @@ VisualScriptNodeInstance *VisualScriptSwitch::instance(VisualScriptInstance *p_i
bool VisualScriptSwitch::_set(const StringName &p_name, const Variant &p_value) {
if (String(p_name) == "case_count") {
case_values.resize(p_value);
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
return true;
}
@@ -638,7 +638,7 @@ bool VisualScriptSwitch::_set(const StringName &p_name, const Variant &p_value)
ERR_FAIL_INDEX_V(idx, case_values.size(), false);
case_values.write[idx].type = Variant::Type(int(p_value));
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
return true;
@@ -677,6 +677,10 @@ void VisualScriptSwitch::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void VisualScriptSwitch::reset_state() {
+ case_values.clear();
+}
+
void VisualScriptSwitch::_bind_methods() {
}
@@ -733,7 +737,7 @@ void VisualScriptTypeCast::set_base_type(const StringName &p_type) {
}
base_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -747,7 +751,7 @@ void VisualScriptTypeCast::set_base_script(const String &p_path) {
}
script = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -796,7 +800,7 @@ public:
}
if (!ResourceCache::has(script)) {
- //if the script is not in use by anyone, we can safely assume whathever we got is not casting to it.
+ //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it.
return 1;
}
Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h
index 46a72bb92d..d9c4dedafd 100644
--- a/modules/visual_script/visual_script_flow_control.h
+++ b/modules/visual_script/visual_script_flow_control.h
@@ -202,6 +202,8 @@ protected:
static void _bind_methods();
public:
+ virtual void reset_state() override;
+
virtual int get_output_sequence_port_count() const override;
virtual bool has_input_sequence_port() const override;
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index d016b938de..9310b86627 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -281,7 +281,7 @@ void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) {
}
basic_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -295,7 +295,7 @@ void VisualScriptFunctionCall::set_base_type(const StringName &p_type) {
}
base_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -309,7 +309,7 @@ void VisualScriptFunctionCall::set_base_script(const String &p_path) {
}
base_script = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -328,7 +328,7 @@ void VisualScriptFunctionCall::set_singleton(const StringName &p_type) {
base_type = obj->get_class();
}
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -425,7 +425,7 @@ void VisualScriptFunctionCall::set_function(const StringName &p_type) {
_update_method_cache();
}
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -439,7 +439,7 @@ void VisualScriptFunctionCall::set_base_path(const NodePath &p_type) {
}
base_path = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -453,7 +453,7 @@ void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) {
}
call_mode = p_mode;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -476,7 +476,7 @@ void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCa
}
rpc_call_mode = p_mode;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const {
@@ -547,7 +547,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
@@ -1067,7 +1067,7 @@ void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) {
}
basic_type = p_type;
- _change_notify();
+ notify_property_list_changed();
_update_base_type();
ports_changed_notify();
}
@@ -1082,7 +1082,7 @@ void VisualScriptPropertySet::set_base_type(const StringName &p_type) {
}
base_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1096,7 +1096,7 @@ void VisualScriptPropertySet::set_base_script(const String &p_path) {
}
base_script = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1191,7 +1191,7 @@ void VisualScriptPropertySet::set_property(const StringName &p_type) {
property = p_type;
index = StringName();
_update_cache();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1206,7 +1206,7 @@ void VisualScriptPropertySet::set_base_path(const NodePath &p_type) {
base_path = p_type;
_update_base_type();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1221,7 +1221,7 @@ void VisualScriptPropertySet::set_call_mode(CallMode p_mode) {
call_mode = p_mode;
_update_base_type();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1243,7 +1243,7 @@ void VisualScriptPropertySet::set_index(const StringName &p_type) {
}
index = p_type;
_update_cache();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1259,7 +1259,7 @@ void VisualScriptPropertySet::set_assign_op(AssignOp p_op) {
assign_op = p_op;
_update_cache();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1292,7 +1292,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
@@ -1760,7 +1760,7 @@ void VisualScriptPropertyGet::set_base_type(const StringName &p_type) {
}
base_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1774,7 +1774,7 @@ void VisualScriptPropertyGet::set_base_script(const String &p_path) {
}
base_script = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1871,7 +1871,7 @@ void VisualScriptPropertyGet::set_property(const StringName &p_type) {
property = p_type;
_update_cache();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1885,7 +1885,7 @@ void VisualScriptPropertyGet::set_base_path(const NodePath &p_type) {
}
base_path = p_type;
- _change_notify();
+ notify_property_list_changed();
_update_base_type();
ports_changed_notify();
}
@@ -1900,7 +1900,7 @@ void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) {
}
call_mode = p_mode;
- _change_notify();
+ notify_property_list_changed();
_update_base_type();
ports_changed_notify();
}
@@ -1915,7 +1915,7 @@ void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) {
}
basic_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1937,7 +1937,7 @@ void VisualScriptPropertyGet::set_index(const StringName &p_type) {
}
index = p_type;
_update_cache();
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1970,7 +1970,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
@@ -2261,7 +2261,7 @@ void VisualScriptEmitSignal::set_signal(const StringName &p_type) {
name = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index ae2b548f21..fed6637acb 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -57,7 +57,7 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value
arguments.write[i].type = Variant::NIL;
}
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
return true;
}
if (String(p_name).begins_with("argument_")) {
@@ -303,6 +303,14 @@ VisualScriptNodeInstance *VisualScriptFunction::instance(VisualScriptInstance *p
return instance;
}
+void VisualScriptFunction::reset_state() {
+ arguments.clear();
+ stack_size = 256;
+ stack_less = false;
+ sequenced = true;
+ rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+}
+
VisualScriptFunction::VisualScriptFunction() {
stack_size = 256;
stack_less = false;
@@ -312,7 +320,7 @@ VisualScriptFunction::VisualScriptFunction() {
void VisualScriptFunction::set_stack_less(bool p_enable) {
stack_less = p_enable;
- _change_notify();
+ notify_property_list_changed();
}
bool VisualScriptFunction::is_stack_less() const {
@@ -421,7 +429,7 @@ bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) {
inputports.write[i].type = Variant::NIL;
}
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
return true;
}
if (String(p_name).begins_with("input_") && is_input_port_editable()) {
@@ -457,7 +465,7 @@ bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) {
outputports.write[i].type = Variant::NIL;
}
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
return true;
}
if (String(p_name).begins_with("output_") && is_output_port_editable()) {
@@ -578,7 +586,7 @@ void VisualScriptLists::add_input_data_port(Variant::Type p_type, const String &
}
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type) {
@@ -590,7 +598,7 @@ void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type
inputports.write[p_idx].type = p_type;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name) {
@@ -602,7 +610,7 @@ void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name
inputports.write[p_idx].name = p_name;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::remove_input_data_port(int p_argidx) {
@@ -615,7 +623,7 @@ void VisualScriptLists::remove_input_data_port(int p_argidx) {
inputports.remove(p_argidx);
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
// output data port interaction
@@ -634,7 +642,7 @@ void VisualScriptLists::add_output_data_port(Variant::Type p_type, const String
}
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_type) {
@@ -646,7 +654,7 @@ void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_typ
outputports.write[p_idx].type = p_type;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_name) {
@@ -658,7 +666,7 @@ void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_nam
outputports.write[p_idx].name = p_name;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
void VisualScriptLists::remove_output_data_port(int p_argidx) {
@@ -671,7 +679,7 @@ void VisualScriptLists::remove_output_data_port(int p_argidx) {
outputports.remove(p_argidx);
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
// sequences
@@ -687,6 +695,13 @@ bool VisualScriptLists::is_sequenced() const {
return sequenced;
}
+void VisualScriptLists::reset_state() {
+ inputports.clear();
+ outputports.clear();
+ sequenced = false;
+ flags = 0;
+}
+
VisualScriptLists::VisualScriptLists() {
// initialize
sequenced = false;
@@ -1433,7 +1448,7 @@ void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
Callable::CallError ce;
Variant::construct(type, value, nullptr, 0, ce);
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
Variant::Type VisualScriptConstant::get_constant_type() const {
@@ -1764,7 +1779,7 @@ String VisualScriptGlobalConstant::get_caption() const {
void VisualScriptGlobalConstant::set_global_constant(int p_which) {
index = p_which;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1850,7 +1865,7 @@ String VisualScriptClassConstant::get_caption() const {
void VisualScriptClassConstant::set_class_constant(const StringName &p_which) {
name = p_which;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1876,7 +1891,7 @@ void VisualScriptClassConstant::set_base_type(const StringName &p_which) {
} else {
name = "";
}
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -1983,7 +1998,7 @@ String VisualScriptBasicTypeConstant::get_text() const {
void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName &p_which) {
name = p_which;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -2010,7 +2025,7 @@ void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) {
} else {
name = "";
}
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -2140,7 +2155,7 @@ String VisualScriptMathConstant::get_caption() const {
void VisualScriptMathConstant::set_math_constant(MathConstant p_which) {
constant = p_which;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -2233,7 +2248,7 @@ String VisualScriptEngineSingleton::get_caption() const {
void VisualScriptEngineSingleton::set_singleton(const String &p_string) {
singleton = p_string;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -2342,7 +2357,7 @@ String VisualScriptSceneNode::get_caption() const {
void VisualScriptSceneNode::set_node_path(const NodePath &p_path) {
path = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -2620,7 +2635,7 @@ String VisualScriptResourcePath::get_caption() const {
void VisualScriptResourcePath::set_resource_path(const String &p_path) {
path = p_path;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -3748,7 +3763,7 @@ void VisualScriptDeconstruct::set_deconstruct_type(Variant::Type p_type) {
type = p_type;
_update_elements();
ports_changed_notify();
- _change_notify(); //to make input appear/disappear
+ notify_property_list_changed(); //to make input appear/disappear
}
Variant::Type VisualScriptDeconstruct::get_deconstruct_type() const {
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index ae5e04d096..7392443e4e 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -99,6 +99,8 @@ public:
virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override;
+ virtual void reset_state() override;
+
VisualScriptFunction();
};
@@ -134,6 +136,8 @@ protected:
static void _bind_methods();
public:
+ virtual void reset_state() override;
+
virtual bool is_output_port_editable() const;
virtual bool is_output_port_name_editable() const;
virtual bool is_output_port_type_editable() const;
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index 6c9af4e600..52fe659983 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -152,7 +152,7 @@ void VisualScriptYield::set_yield_mode(YieldMode p_mode) {
}
yield_mode = p_mode;
ports_changed_notify();
- _change_notify();
+ notify_property_list_changed();
}
VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() {
@@ -359,7 +359,7 @@ void VisualScriptYieldSignal::set_base_type(const StringName &p_type) {
base_type = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -374,7 +374,7 @@ void VisualScriptYieldSignal::set_signal(const StringName &p_type) {
signal = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -389,7 +389,7 @@ void VisualScriptYieldSignal::set_base_path(const NodePath &p_type) {
base_path = p_type;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -404,7 +404,7 @@ void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) {
call_mode = p_mode;
- _change_notify();
+ notify_property_list_changed();
ports_changed_notify();
}
@@ -425,7 +425,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const {
} else {
Node *bnode = _get_base_node();
if (bnode) {
- property.hint_string = bnode->get_path(); //convert to loong string
+ property.hint_string = bnode->get_path(); //convert to long string
}
}
}
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 5d8245c64c..a6b64b342e 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -156,7 +156,7 @@ void VideoStreamPlaybackWebm::stop() {
void VideoStreamPlaybackWebm::play() {
stop();
- delay_compensation = ProjectSettings::get_singleton()->get("audio/video_delay_compensation_ms");
+ delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms");
delay_compensation /= 1000.0;
playing = true;
@@ -194,7 +194,7 @@ float VideoStreamPlaybackWebm::get_playback_position() const {
}
void VideoStreamPlaybackWebm::seek(float p_time) {
- //Not implemented
+ WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
}
void VideoStreamPlaybackWebm::set_audio_track(int p_idx) {
@@ -429,7 +429,7 @@ void VideoStreamWebm::set_audio_track(int p_track) {
////////////
-RES ResourceFormatLoaderWebm::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderWebm::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) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index cb3cf58850..60e02ab38b 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -126,7 +126,7 @@ public:
class ResourceFormatLoaderWebm : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index b304c4824f..6e62840a3e 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -68,7 +68,7 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali
w[1] = 'E';
w[2] = 'B';
w[3] = 'P';
- copymem(&w[4], dst_buff, dst_size);
+ memcpy(&w[4], dst_buff, dst_size);
free(dst_buff);
return dst;
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index 45db49c913..d362bcc10f 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -28,6 +28,7 @@
If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request.
+ [b]Note:[/b] To avoid mixed content warnings or errors in HTML5, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's SSL certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the SSL certificate.
[b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in HTML5 exports due to browsers restrictions.
</description>
</method>
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index ed756363cf..e99a379767 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -31,7 +31,6 @@
#ifndef PACKET_BUFFER_H
#define PACKET_BUFFER_H
-#include "core/os/copymem.h"
#include "core/templates/ring_buffer.h"
template <class T>
@@ -66,7 +65,7 @@ public:
if (p_info) {
_Packet p;
p.size = p_size;
- copymem(&p.info, p_info, sizeof(T));
+ memcpy(&p.info, p_info, sizeof(T));
_packets.write(p);
}
@@ -86,7 +85,7 @@ public:
ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY);
r_read = p.size;
- copymem(r_info, &p.info, sizeof(T));
+ memcpy(r_info, &p.info, sizeof(T));
_payload.read(r_payload, p.size);
return OK;
}
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index 425013f811..1e9183ebfa 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -43,34 +43,18 @@ Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_proto
String host = p_url;
String path = "/";
- int p_len = -1;
+ String scheme = "";
int port = 80;
- bool ssl = false;
- if (host.begins_with("wss://")) {
- ssl = true; // we should implement this
- host = host.substr(6, host.length() - 6);
- port = 443;
- } else {
- ssl = false;
- if (host.begins_with("ws://")) {
- host = host.substr(5, host.length() - 5);
- }
- }
+ Error err = p_url.parse_url(scheme, host, port, path);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url);
- // Path
- p_len = host.find("/");
- if (p_len != -1) {
- path = host.substr(p_len, host.length() - p_len);
- host = host.substr(0, p_len);
+ bool ssl = false;
+ if (scheme == "wss://") {
+ ssl = true;
}
-
- // Port
- p_len = host.rfind(":");
- if (p_len != -1 && p_len == host.find(":")) {
- port = host.substr(p_len, host.length() - p_len).to_int();
- host = host.substr(0, p_len);
+ if (port == 0) {
+ port = ssl ? 443 : 80;
}
-
return connect_to_host(host, path, port, ssl, p_protocols, p_custom_headers);
}
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 011cb86535..fa0ef7060f 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -53,7 +53,7 @@ int WebSocketMultiplayerPeer::_gen_unique_id() const {
(uint32_t)((uint64_t)this), hash); //rely on aslr heap
hash = hash_djb2_one_32(
(uint32_t)((uint64_t)&hash), hash); //rely on aslr stack
- hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion
+ hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negative id is used for exclusion
}
return hash;
@@ -99,6 +99,8 @@ Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buff
_current_packet.data = nullptr;
}
+ ERR_FAIL_COND_V(_incoming_packets.size() == 0, ERR_UNAVAILABLE);
+
_current_packet = _incoming_packets.front()->get();
_incoming_packets.pop_front();
@@ -168,10 +170,10 @@ Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_fr
out.resize(PROTO_SIZE + p_data_size);
uint8_t *w = out.ptrw();
- copymem(&w[0], &p_type, 1);
- copymem(&w[1], &p_from, 4);
- copymem(&w[5], &p_to, 4);
- copymem(&w[PROTO_SIZE], p_data, p_data_size);
+ memcpy(&w[0], &p_type, 1);
+ memcpy(&w[1], &p_from, 4);
+ memcpy(&w[5], &p_to, 4);
+ memcpy(&w[PROTO_SIZE], p_data, p_data_size);
return out;
}
@@ -186,7 +188,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
int32_t id = E->key();
if (p_peer_id == id) {
- continue; // Skip the newwly added peer (already confirmed)
+ continue; // Skip the newly added peer (already confirmed)
}
// Send new peer to others
@@ -211,7 +213,7 @@ void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, cons
packet.size = p_data_size;
packet.source = p_source;
packet.destination = p_dest;
- copymem(packet.data, &p_data[PROTO_SIZE], p_data_size);
+ memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size);
_incoming_packets.push_back(packet);
emit_signal("peer_packet", p_source);
}
@@ -263,9 +265,9 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
uint8_t type = 0;
uint32_t from = 0;
int32_t to = 0;
- copymem(&type, in_buffer, 1);
- copymem(&from, &in_buffer[1], 4);
- copymem(&to, &in_buffer[5], 4);
+ memcpy(&type, in_buffer, 1);
+ memcpy(&from, &in_buffer[1], 4);
+ memcpy(&to, &in_buffer[5], 4);
if (is_server()) { // Server can resend
@@ -299,7 +301,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
// System message
ERR_FAIL_COND(data_size < 4);
int id = 0;
- copymem(&id, &in_buffer[PROTO_SIZE], 4);
+ memcpy(&id, &in_buffer[PROTO_SIZE], 4);
switch (type) {
case SYS_ADD: // Add peer
@@ -314,7 +316,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
_peer_map.erase(id);
emit_signal("peer_disconnected", id);
break;
- case SYS_ID: // Helo, server assigned ID
+ case SYS_ID: // Hello, server assigned ID
_peer_id = id;
break;
default:
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index 8e9ef8a73c..6e19a8ac6e 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -71,10 +71,8 @@ const GodotWebXR = {
// enabled or disabled. When using the WebXR API Emulator, this
// gets picked up automatically, however, in the Oculus Browser
// on the Quest, we need to pause and resume the main loop.
- Browser.pauseAsyncCallbacks();
Browser.mainLoop.pause();
window.setTimeout(function () {
- Browser.resumeAsyncCallbacks();
Browser.mainLoop.resume();
}, 0);
},
diff --git a/modules/webxr/native/webxr.externs.js b/modules/webxr/native/webxr.externs.js
index 03dc05bc83..9ea105aa93 100644
--- a/modules/webxr/native/webxr.externs.js
+++ b/modules/webxr/native/webxr.externs.js
@@ -33,7 +33,7 @@ XR.prototype.ondevicechanged;
*
* @return {!Promise<boolean>}
*/
-XR.prototype.isSessionSupported = function(mode) {}
+XR.prototype.isSessionSupported = function(mode) {};
/**
* @param {string} mode
@@ -41,7 +41,7 @@ XR.prototype.isSessionSupported = function(mode) {}
*
* @return {!Promise<XRSession>}
*/
-XR.prototype.requestSession = function(mode, options) {}
+XR.prototype.requestSession = function(mode, options) {};
/**
* @constructor
diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h
index c5b2dc8d73..366235fcd5 100644
--- a/modules/webxr/webxr_interface.h
+++ b/modules/webxr/webxr_interface.h
@@ -57,7 +57,7 @@ public:
virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0;
virtual String get_requested_reference_space_types() const = 0;
virtual String get_reference_space_type() const = 0;
- virtual XRPositionalTracker *get_controller(int p_controller_id) const = 0;
+ virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const = 0;
virtual String get_visibility_state() const = 0;
virtual PackedVector3Array get_bounds_geometry() const = 0;
};
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 74789fc98e..06f3fe6284 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -160,7 +160,7 @@ String WebXRInterfaceJS::get_reference_space_type() const {
return reference_space_type;
}
-XRPositionalTracker *WebXRInterfaceJS::get_controller(int p_controller_id) const {
+Ref<XRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, nullptr);
@@ -253,7 +253,7 @@ bool WebXRInterfaceJS::initialize() {
void WebXRInterfaceJS::uninitialize() {
if (initialized) {
XRServer *xr_server = XRServer::get_singleton();
- if (xr_server != NULL) {
+ if (xr_server != nullptr) {
// no longer our primary interface
xr_server->clear_primary_interface_if(this);
}
@@ -380,10 +380,10 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
if (godot_webxr_is_controller_connected(p_controller_id)) {
- if (tracker == nullptr) {
- tracker = memnew(XRPositionalTracker);
+ if (tracker.is_null()) {
+ tracker.instance();
tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
// Controller id's 0 and 1 are always the left and right hands.
if (p_controller_id < 2) {
@@ -416,14 +416,14 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
int *axes = godot_webxr_get_controller_axes(p_controller_id);
if (axes) {
for (int i = 0; i < axes[0]; i++) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = -1;
joy_axis.value = *((float *)axes + (i + 1));
input->joy_axis(p_controller_id + 100, i, joy_axis);
}
free(axes);
}
- } else if (tracker) {
+ } else if (tracker.is_valid()) {
xr_server->remove_tracker(tracker);
}
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index 49299b252f..7c841c1911 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -71,7 +71,7 @@ public:
virtual String get_requested_reference_space_types() const override;
void _set_reference_space_type(String p_reference_space_type);
virtual String get_reference_space_type() const override;
- virtual XRPositionalTracker *get_controller(int p_controller_id) const override;
+ virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const override;
virtual String get_visibility_state() const override;
virtual PackedVector3Array get_bounds_geometry() const override;
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 880fe2df61..e1f9521a48 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -154,14 +154,18 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
float h = *r_size_hint_y;
if (w == 0 || h == 0) {
+ xatlas::Destroy(atlas);
return false; //could not bake because there is no area
}
const xatlas::Mesh &output = atlas->meshes[0];
*r_vertices = (int *)malloc(sizeof(int) * output.vertexCount);
+ ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory.");
*r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2);
+ ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory.");
*r_indices = (int *)malloc(sizeof(int) * output.indexCount);
+ ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory.");
float max_x = 0.0;
float max_y = 0.0;
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index ee28959adc..3a2ccac481 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -73,9 +73,9 @@ Error AudioDriverAndroid::init() {
// __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
JNIEnv *env = get_jni_env();
- int mix_rate = GLOBAL_GET("audio/mix_rate");
+ int mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000);
print_verbose("Audio buffer size: " + itos(buffer_size));
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 0e696024a9..2a80a3c45b 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -13,7 +13,7 @@ def get_name():
def can_build():
- return ("ANDROID_NDK_ROOT" in os.environ) or ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ)
+ return ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ)
def get_platform(platform):
@@ -43,15 +43,12 @@ def get_android_sdk_root():
# Return the ANDROID_NDK_ROOT environment variable.
-# If the env variable is already defined, we use it with the expectation that
-# the user knows what they're doing (e.g: testing a new NDK version).
-# Otherwise, we generate one for this build using the ANDROID_SDK_ROOT env
+# We generate one for this build using the ANDROID_SDK_ROOT env
# variable and the project ndk version.
+# If the env variable is already defined, we override it with
+# our own to match what the project expects.
def get_android_ndk_root():
- if "ANDROID_NDK_ROOT" in os.environ:
- return os.environ.get("ANDROID_NDK_ROOT", 0)
- else:
- return get_android_sdk_root() + "/ndk/" + get_project_ndk_version()
+ return get_android_sdk_root() + "/ndk/" + get_project_ndk_version()
def get_flags():
@@ -200,12 +197,11 @@ def configure(env):
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(LINKFLAGS=["-O2"])
env.Append(CCFLAGS=["-O2", "-fomit-frame-pointer"])
- env.Append(CPPDEFINES=["NDEBUG"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os"])
- env.Append(CPPDEFINES=["NDEBUG"])
env.Append(LINKFLAGS=["-Os"])
+ env.Append(CPPDEFINES=["NDEBUG"])
if can_vectorize:
env.Append(CCFLAGS=["-ftree-vectorize"])
if env["target"] == "release_debug":
@@ -262,8 +258,10 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
# Disable exceptions and rtti on non-tools (template) builds
- if env["tools"] or env["builtin_icu"]:
+ if env["tools"]:
env.Append(CXXFLAGS=["-frtti"])
+ elif env["builtin_icu"]:
+ env.Append(CXXFLAGS=["-frtti", "-fno-exceptions"])
else:
env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
# Don't use dynamic_cast, necessary with no-rtti.
@@ -373,7 +371,7 @@ def configure(env):
# Return the project NDK version.
# This is kept in sync with the value in 'platform/android/java/app/config.gradle'.
def get_project_ndk_version():
- return "21.3.6528147"
+ return "21.4.7075529"
# Return NDK version string in source.properties (adapted from the Chromium project).
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 5f7e5eaa83..dd001baba9 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -477,7 +477,7 @@ void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p
Input::get_singleton()->joy_button(p_event.device, p_event.index, p_event.pressed);
break;
case JOY_EVENT_AXIS:
- Input::JoyAxis value;
+ Input::JoyAxisValue value;
value.min = -1;
value.value = p_event.value;
Input::get_singleton()->joy_axis(p_event.device, p_event.index, value);
@@ -741,15 +741,15 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_UP, event_vertical_factor);
} else if (event_vertical_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_DOWN, -event_vertical_factor);
}
if (event_horizontal_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_RIGHT, event_horizontal_factor);
} else if (event_horizontal_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_LEFT, -event_horizontal_factor);
}
} break;
}
@@ -784,16 +784,16 @@ void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Poi
int DisplayServerAndroid::_button_index_from_mask(int button_mask) {
switch (button_mask) {
- case BUTTON_MASK_LEFT:
- return BUTTON_LEFT;
- case BUTTON_MASK_RIGHT:
- return BUTTON_RIGHT;
- case BUTTON_MASK_MIDDLE:
- return BUTTON_MIDDLE;
- case BUTTON_MASK_XBUTTON1:
- return BUTTON_XBUTTON1;
- case BUTTON_MASK_XBUTTON2:
- return BUTTON_XBUTTON2;
+ case MOUSE_BUTTON_MASK_LEFT:
+ return MOUSE_BUTTON_LEFT;
+ case MOUSE_BUTTON_MASK_RIGHT:
+ return MOUSE_BUTTON_RIGHT;
+ case MOUSE_BUTTON_MASK_MIDDLE:
+ return MOUSE_BUTTON_MIDDLE;
+ case MOUSE_BUTTON_MASK_XBUTTON1:
+ return MOUSE_BUTTON_XBUTTON1;
+ case MOUSE_BUTTON_MASK_XBUTTON2:
+ return MOUSE_BUTTON_XBUTTON2;
default:
return 0;
}
@@ -854,19 +854,19 @@ int DisplayServerAndroid::mouse_get_button_state() const {
int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) {
int godot_button_mask = 0;
if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
- godot_button_mask |= BUTTON_MASK_LEFT;
+ godot_button_mask |= MOUSE_BUTTON_MASK_LEFT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
- godot_button_mask |= BUTTON_MASK_RIGHT;
+ godot_button_mask |= MOUSE_BUTTON_MASK_RIGHT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
- godot_button_mask |= BUTTON_MASK_MIDDLE;
+ godot_button_mask |= MOUSE_BUTTON_MASK_MIDDLE;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
- godot_button_mask |= BUTTON_MASK_XBUTTON1;
+ godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
- godot_button_mask |= BUTTON_MASK_XBUTTON2;
+ godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2;
}
return godot_button_mask;
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index a963c5a741..cd3f00f935 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -37,6 +37,7 @@
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
+#include "core/templates/safe_refcount.h"
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "editor/editor_export.h"
@@ -200,8 +201,23 @@ static const char *android_perms[] = {
nullptr
};
-static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable/splash.png";
-static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png";
+static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi/splash.png";
+static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v4/splash.png";
+static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
+static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
+static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
+
+const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/splash_bg_color" />
+ <item>
+ <bitmap
+ android:gravity="center"
+ android:filter="%s"
+ android:src="@drawable/splash" />
+ </item>
+</layer-list>
+)SPLASH";
struct LauncherIcon {
const char *export_path;
@@ -264,38 +280,38 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<PluginConfigAndroid> plugins;
String last_plugin_names;
uint64_t last_custom_build_time = 0;
- volatile bool plugins_changed;
+ SafeFlag plugins_changed;
Mutex plugins_lock;
Vector<Device> devices;
- volatile bool devices_changed;
+ SafeFlag devices_changed;
Mutex device_lock;
Thread check_for_changes_thread;
- volatile bool quit_request;
+ SafeFlag quit_request;
static void _check_for_changes_poll_thread(void *ud) {
EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud;
- while (!ea->quit_request) {
+ while (!ea->quit_request.is_set()) {
// Check for plugins updates
{
// Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_changed) {
+ if (!ea->plugins_changed.is_set()) {
Vector<PluginConfigAndroid> loaded_plugins = get_plugins();
MutexLock lock(ea->plugins_lock);
if (ea->plugins.size() != loaded_plugins.size()) {
- ea->plugins_changed = true;
+ 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_changed = true;
+ ea->plugins_changed.set();
break;
}
}
}
- if (ea->plugins_changed) {
+ if (ea->plugins_changed.is_set()) {
ea->plugins = loaded_plugins;
}
}
@@ -409,7 +425,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
ea->devices = ndevices;
- ea->devices_changed = true;
+ ea->devices_changed.set();
}
}
@@ -418,7 +434,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
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) {
+ if (ea->quit_request.is_set()) {
break;
}
}
@@ -775,6 +791,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug) {
+ print_verbose("Building temporary manifest..");
String manifest_text =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
@@ -791,10 +808,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
manifest_text += _get_xr_features_tag(p_preset);
manifest_text += _get_instrumentation_tag(p_preset);
- String plugins_names = get_plugins_names(get_enabled_plugins(p_preset));
- manifest_text += _get_application_tag(p_preset, plugins_names);
+ manifest_text += _get_application_tag(p_preset);
manifest_text += "</manifest>\n";
String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
+
+ print_verbose("Storing manifest into " + manifest_path + ": " + "\n" + manifest_text);
store_string_at_path(manifest_path, manifest_text);
}
@@ -837,9 +855,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
bool screen_support_xlarge = p_preset->get("screen/support_xlarge");
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- bool focus_awareness = p_preset->get("xr_features/focus_awareness");
-
- String plugins_names = get_plugins_names(get_enabled_plugins(p_preset));
Vector<String> perms;
// Write permissions into the perms variable.
@@ -905,7 +920,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String tname = string_table[name];
uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]);
iofs += 28;
- bool is_focus_aware_metadata = false;
for (uint32_t i = 0; i < attrcount; i++) {
uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]);
@@ -957,33 +971,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
- // FIXME: `attr_value != 0xFFFFFFFF` below added as a stopgap measure for GH-32553,
- // but the issue should be debugged further and properly addressed.
- if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") {
- // Update the meta-data 'android:name' attribute based on the selected XR mode.
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- string_table.write[attr_value] = "com.samsung.android.vr.application.mode";
- }
- }
-
- if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") {
- // Update the meta-data 'android:value' attribute based on the selected XR mode.
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- string_table.write[attr_value] = "vr_only";
- }
- }
-
- if (tname == "meta-data" && attrname == "value" && is_focus_aware_metadata) {
- // Update the focus awareness meta-data value
- encode_uint32(xr_mode_index == /* XRMode.OVR */ 1 && focus_awareness ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
- }
-
- if (tname == "meta-data" && attrname == "value" && value == "plugins_value" && !plugins_names.is_empty()) {
- // Update the meta-data 'android:value' attribute with the list of enabled plugins.
- string_table.write[attr_value] = plugins_names;
- }
-
- is_focus_aware_metadata = tname == "meta-data" && attrname == "name" && value == "com.oculus.vr.focusaware";
iofs += 20;
}
@@ -999,15 +986,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<int> feature_versions;
if (xr_mode_index == 1 /* XRMode.OVR */) {
- // Check for degrees of freedom
- int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
-
- if (dof_index > 0) {
- feature_names.push_back("android.hardware.vr.headtracking");
- feature_required_list.push_back(dof_index == 2);
- feature_versions.push_back(1);
- }
-
// Check for hand tracking
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index > 0) {
@@ -1470,23 +1448,44 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
- void load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
- // TODO: Figure out how to handle remaining boot splash parameters (e.g: fullsize, filter)
+ String load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
+ bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
if (!project_splash_path.is_empty()) {
splash_image.instance();
+ print_verbose("Loading splash image: " + project_splash_path);
const Error err = ImageLoader::load_image(project_splash_path, splash_image);
if (err) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("- unable to load splash image from " + project_splash_path + " (" + itos(err) + ")");
+ }
splash_image.unref();
}
}
if (splash_image.is_null()) {
// Use the default
+ print_verbose("Using default splash image.");
splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
}
+ if (scale_splash) {
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ int width, height;
+ if (screen_size.width > screen_size.height) {
+ // scale horizontally
+ height = screen_size.height;
+ width = splash_image->get_width() * screen_size.height / splash_image->get_height();
+ } else {
+ // scale vertically
+ width = screen_size.width;
+ height = splash_image->get_height() * screen_size.width / splash_image->get_width();
+ }
+ splash_image->resize(width, height);
+ }
+
// Setup the splash bg color
bool bg_color_valid;
Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
@@ -1494,9 +1493,13 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
bg_color = boot_splash_bg_color;
}
+ print_verbose("Creating splash background color image.");
splash_bg_color_image.instance();
splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
splash_bg_color_image->fill(bg_color);
+
+ String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, bool_to_string(apply_filter));
+ return processed_splash_config_xml;
}
void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
@@ -1508,19 +1511,24 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
// Regular icon: user selection -> project icon -> default.
String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges();
+ print_verbose("Loading regular icon from " + path);
if (path.is_empty() || ImageLoader::load_image(path, icon) != OK) {
+ print_verbose("- falling back to project icon: " + project_icon_path);
ImageLoader::load_image(project_icon_path, icon);
}
// Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default).
path = static_cast<String>(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges();
+ print_verbose("Loading adaptive foreground icon from " + path);
if (path.is_empty() || ImageLoader::load_image(path, foreground) != OK) {
+ print_verbose("- falling back to using the regular icon");
foreground = icon;
}
// Adaptive background: user selection -> default.
path = static_cast<String>(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges();
if (!path.is_empty()) {
+ print_verbose("Loading adaptive background icon from " + path);
ImageLoader::load_image(path, background);
}
}
@@ -1535,13 +1543,21 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
void _copy_icons_to_gradle_project(const Ref<EditorExportPreset> &p_preset,
+ const String &processed_splash_config_xml,
const Ref<Image> &splash_image,
const Ref<Image> &splash_bg_color_image,
const Ref<Image> &main_image,
const Ref<Image> &foreground,
const Ref<Image> &background) {
+ // Store the splash configuration
+ if (!processed_splash_config_xml.is_empty()) {
+ print_verbose("Storing processed splash configuration: " + String("\n") + processed_splash_config_xml);
+ store_string_at_path(SPLASH_CONFIG_PATH, processed_splash_config_xml);
+ }
+
// Store the splash image
if (splash_image.is_valid() && !splash_image->is_empty()) {
+ print_verbose("Storing splash image in " + String(SPLASH_IMAGE_EXPORT_PATH));
Vector<uint8_t> data;
_load_image_data(splash_image, data);
store_image(SPLASH_IMAGE_EXPORT_PATH, data);
@@ -1549,6 +1565,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
// Store the splash bg color image
if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
+ print_verbose("Storing splash background image in " + String(SPLASH_BG_COLOR_PATH));
Vector<uint8_t> data;
_load_image_data(splash_bg_color_image, data);
store_image(SPLASH_BG_COLOR_PATH, data);
@@ -1559,12 +1576,14 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
for (int i = 0; i < icon_densities_count; ++i) {
if (main_image.is_valid() && !main_image->is_empty()) {
+ print_verbose("Processing launcher icon for dimension " + itos(launcher_icons[i].dimensions) + " into " + launcher_icons[i].export_path);
Vector<uint8_t> data;
_process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data);
store_image(launcher_icons[i], data);
}
if (foreground.is_valid() && !foreground->is_empty()) {
+ print_verbose("Processing launcher adaptive icon foreground for dimension " + itos(launcher_adaptive_icon_foregrounds[i].dimensions) + " into " + launcher_adaptive_icon_foregrounds[i].export_path);
Vector<uint8_t> data;
_process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground,
launcher_adaptive_icon_foregrounds[i].dimensions, data);
@@ -1572,6 +1591,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
if (background.is_valid() && !background->is_empty()) {
+ print_verbose("Processing launcher adaptive icon background for dimension " + itos(launcher_adaptive_icon_backgrounds[i].dimensions) + " into " + launcher_adaptive_icon_backgrounds[i].export_path);
Vector<uint8_t> data;
_process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background,
launcher_adaptive_icon_backgrounds[i].dimensions, data);
@@ -1597,7 +1617,7 @@ public:
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override {
- String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
if (driver == "GLES2") {
r_features->push_back("etc");
}
@@ -1623,7 +1643,7 @@ public:
print_verbose("Found Android plugin " + plugins_configs[i].name);
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false));
}
- plugins_changed = false;
+ plugins_changed.clear();
Vector<String> abis = get_abis();
for (int i = 0; i < abis.size(); ++i) {
@@ -1655,9 +1675,7 @@ public:
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,Oculus Mobile VR"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "xr_features/focus_awareness"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@@ -1693,19 +1711,19 @@ public:
}
virtual bool should_update_export_options() override {
- bool export_options_changed = plugins_changed;
+ bool export_options_changed = plugins_changed.is_set();
if (export_options_changed) {
// don't clear unless we're reporting true, to avoid race
- plugins_changed = false;
+ plugins_changed.clear();
}
return export_options_changed;
}
virtual bool poll_export() override {
- bool dc = devices_changed;
+ bool dc = devices_changed.is_set();
if (dc) {
// don't clear unless we're reporting true, to avoid race
- devices_changed = false;
+ devices_changed.clear();
}
return dc;
}
@@ -1766,7 +1784,7 @@ public:
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
}
- String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.apk");
+ String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -1783,6 +1801,7 @@ public:
List<String> args;
int rv;
+ String output;
bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
String version_name = p_preset->get("version/name");
@@ -1800,7 +1819,9 @@ public:
args.push_back("uninstall");
args.push_back(get_package_name(package_name));
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
}
print_line("Installing to device (please wait...): " + devices[p_device].name);
@@ -1815,7 +1836,9 @@ public:
args.push_back("-r");
args.push_back(tmp_export_path);
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (err || rv != 0) {
EditorNode::add_io_error("Could not install to device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -1832,7 +1855,9 @@ public:
args.push_back(devices[p_device].id);
args.push_back("reverse");
args.push_back("--remove-all");
- OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
@@ -1843,7 +1868,9 @@ public:
args.push_back("tcp:" + itos(dbg_port));
args.push_back("tcp:" + itos(dbg_port));
- OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
print_line("Reverse result: " + itos(rv));
}
@@ -1857,7 +1884,9 @@ public:
args.push_back("tcp:" + itos(fs_port));
args.push_back("tcp:" + itos(fs_port));
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
print_line("Reverse result2: " + itos(rv));
}
} else {
@@ -1885,7 +1914,9 @@ public:
args.push_back("-n");
args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (err || rv != 0) {
EditorNode::add_io_error("Could not execute on device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -1958,6 +1989,7 @@ public:
String template_err;
bool dvalid = false;
bool rvalid = false;
+ bool has_export_templates = false;
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -1965,7 +1997,7 @@ public:
template_err += TTR("Custom debug template not found.") + "\n";
}
} else {
- dvalid = exists_export_template("android_debug.apk", &template_err);
+ has_export_templates |= exists_export_template("android_debug.apk", &template_err);
}
if (p_preset->get("custom_template/release") != "") {
@@ -1974,22 +2006,24 @@ public:
template_err += TTR("Custom release template not found.") + "\n";
}
} else {
- rvalid = exists_export_template("android_release.apk", &template_err);
+ has_export_templates |= exists_export_template("android_release.apk", &template_err);
}
- valid = dvalid || rvalid;
+ r_missing_templates = !has_export_templates;
+ valid = dvalid || rvalid || has_export_templates;
if (!valid) {
err += template_err;
}
} else {
- valid = exists_export_template("android_source.zip", &err);
+ r_missing_templates = !exists_export_template("android_source.zip", &err);
- if (!FileAccess::exists("res://android/build/build.gradle")) {
+ bool installed_android_build_template = FileAccess::exists("res://android/build/build.gradle");
+ if (!installed_android_build_template) {
err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n";
- valid = false;
}
+
+ valid = installed_android_build_template && !r_missing_templates;
}
- r_missing_templates = !valid;
// Validate the rest of the configuration.
@@ -2090,27 +2124,13 @@ public:
// Validate the Xr features are properly populated
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- int degrees_of_freedom = p_preset->get("xr_features/degrees_of_freedom");
int hand_tracking = p_preset->get("xr_features/hand_tracking");
- bool focus_awareness = p_preset->get("xr_features/focus_awareness");
if (xr_mode_index != /* XRMode.OVR*/ 1) {
- if (degrees_of_freedom > 0) {
- valid = false;
- err += TTR("\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
- err += "\n";
- }
-
if (hand_tracking > 0) {
valid = false;
err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
err += "\n";
}
-
- if (focus_awareness) {
- valid = false;
- err += TTR("\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
- err += "\n";
- }
}
if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB &&
@@ -2222,11 +2242,12 @@ public:
CharString command_line_argument = command_line_strings[i].utf8();
int base = r_command_line_flags.size();
int length = command_line_argument.length();
- if (length == 0)
+ if (length == 0) {
continue;
+ }
r_command_line_flags.resize(base + 4 + length);
encode_uint32(length, &r_command_line_flags.write[base]);
- copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
+ memcpy(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
}
}
}
@@ -2239,6 +2260,7 @@ public:
String release_password = p_preset->get("keystore/release_password");
String apksigner = get_apksigner_path();
+ print_verbose("Starting signing of the " + export_label + " binary using " + apksigner);
if (!FileAccess::exists(apksigner)) {
EditorNode::add_io_error("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting " + export_label + " is unsigned.");
return OK;
@@ -2277,6 +2299,7 @@ public:
return ERR_FILE_CANT_OPEN;
}
+ String output;
List<String> args;
args.push_back("sign");
args.push_back("--verbose");
@@ -2287,8 +2310,14 @@ public:
args.push_back("--ks-key-alias");
args.push_back(user);
args.push_back(export_path);
+ if (p_debug) {
+ // We only print verbose logs for debug builds to avoid leaking release keystore credentials.
+ print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
+ }
int retval;
- OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
if (retval) {
EditorNode::add_io_error("'apksigner' returned with error #" + itos(retval));
return ERR_CANT_CREATE;
@@ -2302,24 +2331,43 @@ public:
args.push_back("verify");
args.push_back("--verbose");
args.push_back(export_path);
+ if (p_debug) {
+ print_verbose("Verifying signed build using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
+ }
- OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
if (retval) {
EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed.");
return ERR_CANT_CREATE;
}
+
+ print_verbose("Successfully completed signing build.");
return OK;
}
void _clear_assets_directory() {
DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da_res->dir_exists("res://android/build/assets")) {
+ print_verbose("Clearing assets directory..");
DirAccessRef da_assets = DirAccess::open("res://android/build/assets");
da_assets->erase_contents_recursive();
da_res->remove("res://android/build/assets");
}
}
+ String join_list(List<String> parts, const String &separator) const {
+ String ret;
+ for (int i = 0; i < parts.size(); ++i) {
+ if (i > 0) {
+ ret += separator;
+ }
+ ret += parts[i];
+ }
+ return ret;
+ }
+
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
int export_format = int(p_preset->get("custom_template/export_format"));
bool should_sign = p_preset->get("package/signed");
@@ -2339,9 +2387,21 @@ public:
bool apk_expansion = p_preset->get("apk_expansion/enable");
Vector<String> enabled_abis = get_enabled_abis(p_preset);
+ print_verbose("Exporting for Android...");
+ print_verbose("- debug build: " + bool_to_string(p_debug));
+ print_verbose("- export path: " + p_path);
+ print_verbose("- export format: " + itos(export_format));
+ print_verbose("- sign build: " + bool_to_string(should_sign));
+ print_verbose("- custom build enabled: " + bool_to_string(use_custom_build));
+ print_verbose("- apk expansion enabled: " + bool_to_string(apk_expansion));
+ print_verbose("- enabled abis: " + String(",").join(enabled_abis));
+ print_verbose("- export filter: " + itos(p_preset->get_export_filter()));
+ print_verbose("- include filter: " + p_preset->get_include_filter());
+ print_verbose("- exclude filter: " + p_preset->get_exclude_filter());
+
Ref<Image> splash_image;
Ref<Image> splash_bg_color_image;
- load_splash_refs(splash_image, splash_bg_color_image);
+ String processed_splash_config_xml = load_splash_refs(splash_image, splash_bg_color_image);
Ref<Image> main_image;
Ref<Image> foreground;
@@ -2374,14 +2434,17 @@ public:
}
if (use_custom_build) {
+ print_verbose("Starting custom build..");
//test that installed build version is alright
{
+ print_verbose("Checking build version..");
FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ);
if (!f) {
EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu."));
return ERR_UNCONFIGURED;
}
String version = f->get_line().strip_edges();
+ print_verbose("- build version: " + version);
f->close();
if (version != VERSION_FULL_CONFIG) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG));
@@ -2389,7 +2452,8 @@ public:
}
}
String sdk_path = EDITOR_GET("export/android/android_sdk_path");
- ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
+ ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'.");
+ print_verbose("Android sdk path: " + sdk_path);
// TODO: should we use "package/name" or "application/config/name"?
String project_name = get_project_name(p_preset->get("package/name"));
@@ -2398,27 +2462,31 @@ public:
EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name");
}
// Copies the project icon files into the appropriate Gradle project directory.
- _copy_icons_to_gradle_project(p_preset, splash_image, splash_bg_color_image, main_image, foreground, background);
+ _copy_icons_to_gradle_project(p_preset, processed_splash_config_xml, splash_image, splash_bg_color_image, main_image, foreground, background);
// Write an AndroidManifest.xml file into the Gradle project directory.
_write_tmp_manifest(p_preset, p_give_internet, p_debug);
//stores all the project files inside the Gradle project directory. Also includes all ABIs
_clear_assets_directory();
if (!apk_expansion) {
- err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file);
+ print_verbose("Exporting project files..");
+ err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, nullptr, ignore_so_file);
if (err != OK) {
EditorNode::add_io_error("Could not export project files to gradle project\n");
return err;
}
} else {
+ print_verbose("Saving apk expansion file..");
err = save_apk_expansion_file(p_preset, p_path);
if (err != OK) {
EditorNode::add_io_error("Could not write expansion package file!");
return err;
}
}
+ print_verbose("Storing command line flags..");
store_file_at_path("res://android/build/assets/_cl_", command_line_flags);
+ print_verbose("Updating ANDROID_HOME environment to " + sdk_path);
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
String build_command;
@@ -2458,6 +2526,8 @@ public:
cmdline.push_back(apk_build_command);
}
+ cmdline.push_back("-p"); // argument to specify the start directory.
+ cmdline.push_back(build_path); // start directory.
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code.
cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name.
@@ -2467,6 +2537,14 @@ public:
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("-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));
+
+ // NOTE: The release keystore is not included in the verbose logging
+ // to avoid accidentally leaking sensitive information when sharing verbose logs for troubleshooting.
+ // Any non-sensitive additions to the command line arguments must be done above this section.
+ // Sensitive additions must be done below the logging statement.
+ print_verbose("Build Android project using gradle command: " + String("\n") + build_command + " " + join_list(cmdline, String(" ")));
+
if (should_sign && !p_debug) {
// Pass the release keystore info as well
String release_keystore = p_preset->get("keystore/release");
@@ -2481,8 +2559,6 @@ public:
cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias.
cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specity the release keystore password.
}
- cmdline.push_back("-p"); // argument to specify the start directory.
- cmdline.push_back(build_path); // start directory.
int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline);
if (result != 0) {
@@ -2513,19 +2589,23 @@ public:
copy_args.push_back("-Pexport_path=file:" + export_path);
copy_args.push_back("-Pexport_filename=" + export_filename);
+ print_verbose("Copying Android binary using gradle command: " + String("\n") + build_command + " " + join_list(copy_args, String(" ")));
int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args);
if (copy_result != 0) {
EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs."));
return ERR_CANT_CREATE;
}
+ print_verbose("Successfully completed Android custom build.");
return OK;
}
// This is the start of the Legacy build system
- if (p_debug)
+ print_verbose("Starting legacy build system..");
+ if (p_debug) {
src_apk = p_preset->get("custom_template/debug");
- else
+ } else {
src_apk = p_preset->get("custom_template/release");
+ }
src_apk = src_apk.strip_edges();
if (src_apk == "") {
if (p_debug) {
@@ -2562,7 +2642,7 @@ public:
FileAccess *dst_f = nullptr;
io2.opaque = &dst_f;
- String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk");
+ String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -2607,12 +2687,12 @@ public:
}
// Process the splash image
- if (file == SPLASH_IMAGE_EXPORT_PATH && splash_image.is_valid() && !splash_image->is_empty()) {
+ if ((file == SPLASH_IMAGE_EXPORT_PATH || file == LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH) && splash_image.is_valid() && !splash_image->is_empty()) {
_load_image_data(splash_image, data);
}
// Process the splash bg color image
- if (file == SPLASH_BG_COLOR_PATH && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
+ if ((file == SPLASH_BG_COLOR_PATH || file == LEGACY_BUILD_SPLASH_BG_COLOR_PATH) && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
_load_image_data(splash_bg_color_image, data);
}
@@ -2720,11 +2800,11 @@ public:
zipOpenNewFileInZip(unaligned_apk,
"assets/_cl_",
&zipfi,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0, // No compress (little size gain and potentially slower startup)
Z_DEFAULT_COMPRESSION);
zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size());
@@ -2845,14 +2925,13 @@ public:
run_icon.instance();
run_icon->create_from_image(img);
- devices_changed = true;
- plugins_changed = true;
- quit_request = false;
+ devices_changed.set();
+ plugins_changed.set();
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
}
~EditorExportPlatformAndroid() {
- quit_request = true;
+ quit_request.set();
check_for_changes_thread.wait_to_finish();
}
};
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index fc54b65d26..bbbb526af9 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -47,20 +47,21 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
DisplayServer::ScreenOrientation _get_screen_orientation() {
String orientation_settings = ProjectSettings::get_singleton()->get("display/window/handheld/orientation");
DisplayServer::ScreenOrientation screen_orientation;
- if (orientation_settings == "portrait")
+ if (orientation_settings == "portrait") {
screen_orientation = DisplayServer::SCREEN_PORTRAIT;
- else if (orientation_settings == "reverse_landscape")
+ } else if (orientation_settings == "reverse_landscape") {
screen_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE;
- else if (orientation_settings == "reverse_portrait")
+ } else if (orientation_settings == "reverse_portrait") {
screen_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT;
- else if (orientation_settings == "sensor_landscape")
+ } else if (orientation_settings == "sensor_landscape") {
screen_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE;
- else if (orientation_settings == "sensor_portrait")
+ } else if (orientation_settings == "sensor_portrait") {
screen_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT;
- else if (orientation_settings == "sensor")
+ } else if (orientation_settings == "sensor") {
screen_orientation = DisplayServer::SCREEN_SENSOR;
- else
+ } else {
screen_orientation = DisplayServer::SCREEN_LANDSCAPE;
+ }
return screen_orientation;
}
@@ -146,6 +147,9 @@ Error store_string_at_path(const String &p_path, const String &p_data) {
String dir = p_path.get_base_dir();
Error err = create_directory(dir);
if (err != OK) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("Unable to write data into " + p_path);
+ }
return err;
}
FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE);
@@ -162,12 +166,14 @@ Error store_string_at_path(const String &p_path, const String &p_data) {
// This method will be called ONLY when custom build is enabled.
Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
String dst_path = p_path.replace_first("res://", "res://android/build/assets/");
+ print_verbose("Saving project files from " + p_path + " into " + dst_path);
Error err = store_file_at_path(dst_path, p_data);
return err;
}
// Creates strings.xml files inside the gradle project for different locales.
Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name) {
+ print_verbose("Creating strings resources for supported locales for project " + project_name);
// Stores the string into the default values directory.
String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true));
store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string);
@@ -175,6 +181,9 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
// Searches the Gradle project res/ directory to find all supported locales
DirAccessRef da = DirAccess::open("res://android/build/res");
if (!da) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_error("Unable to open Android resources directory.");
+ }
return ERR_CANT_OPEN;
}
da->list_dir_begin();
@@ -193,6 +202,7 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
if (ProjectSettings::get_singleton()->has_setting(property_name)) {
String locale_project_name = ProjectSettings::get_singleton()->get(property_name);
String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true));
+ print_verbose("Storing project name for locale " + locale + " under " + locale_directory);
store_string_at_path(locale_directory, processed_xml_string);
} else {
// TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch
@@ -208,8 +218,8 @@ String bool_to_string(bool v) {
}
String _get_gles_tag() {
- bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" &&
- !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2");
+ bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" &&
+ !ProjectSettings::get_singleton()->get("rendering/driver/fallback_to_gles2");
return min_gles3 ? " <uses-feature android:glEsVersion=\"0x00030000\" android:required=\"true\" />\n" : "";
}
@@ -231,12 +241,6 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_xr_features;
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
if (uses_xr) {
- int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
- if (dof_index == 1) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"false\" android:version=\"1\" />\n";
- } else if (dof_index == 2) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
- }
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index == 1) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
@@ -260,14 +264,6 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
return manifest_instrumentation_text;
}
-String _get_plugins_tag(const String &plugins_names) {
- if (!plugins_names.is_empty()) {
- return vformat(" <meta-data tools:node=\"replace\" android:name=\"plugins\" android:value=\"%s\" />\n", plugins_names);
- } else {
- return " <meta-data tools:node=\"remove\" android:name=\"plugins\" />\n";
- }
-}
-
String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
String orientation = _get_android_orientation_label(_get_screen_orientation());
@@ -276,28 +272,19 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
"tools:replace=\"android:screenOrientation\" "
"android:screenOrientation=\"%s\">\n",
orientation);
- if (uses_xr) {
- String focus_awareness = bool_to_string(p_preset->get("xr_features/focus_awareness"));
- manifest_activity_text += vformat(" <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"%s\" />\n", focus_awareness);
- } else {
+ if (!uses_xr) {
manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
}
manifest_activity_text += " </activity>\n";
return manifest_activity_text;
}
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset, const String &plugins_names) {
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_application_text =
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"false\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
- " android:icon=\"@mipmap/icon\">\n\n"
- " <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n";
+ " android:icon=\"@mipmap/icon\">\n\n";
- manifest_application_text += _get_plugins_tag(plugins_names);
- if (uses_xr) {
- manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n";
- }
manifest_application_text += _get_activity_tag(p_preset);
manifest_application_text += " </application>\n";
return manifest_application_text;
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index 165d5da3ae..705891713f 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -114,6 +114,9 @@ uint8_t FileAccessAndroid::get_8() const {
}
int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V(p_length < 0, -1);
+
off_t r = AAsset_read(a, p_dst, p_length);
if (pos + p_length > len) {
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index e94681659c..15feea15a4 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -22,18 +22,13 @@
tools:ignore="GoogleAppIndexingWarning"
android:icon="@mipmap/icon" >
- <!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
- <!-- Do these changes in the export preset. Adding new ones is fine. -->
-
- <!-- XR mode metadata. This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. -->
+ <!-- Records the version of the Godot editor used for building -->
<meta-data
- android:name="xr_mode_metadata_name"
- android:value="xr_mode_metadata_value" />
+ android:name="org.godotengine.editor.version"
+ android:value="${godotEditorVersion}" />
- <!-- Metadata populated at export time and used by Godot to figure out which plugins must be enabled. -->
- <meta-data
- android:name="plugins"
- android:value="plugins_value"/>
+ <!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
+ <!-- Do these changes in the export preset. Adding new ones is fine. -->
<activity
android:name=".GodotApp"
@@ -45,8 +40,8 @@
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
- <!-- Focus awareness metadata is updated at export time if the user enables it in the 'Xr Features' section. -->
- <meta-data android:name="com.oculus.vr.focusaware" android:value="false" />
+ <!-- Focus awareness metadata is removed at export time if the xr mode is not VR. -->
+ <meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/platform/android/java/app/assets/.gitignore b/platform/android/java/app/assets/.gitignore
new file mode 100644
index 0000000000..d6b7ef32c8
--- /dev/null
+++ b/platform/android/java/app/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 814cc30613..1b1fb47bd8 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -77,7 +77,7 @@ android {
defaultConfig {
// The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
aaptOptions {
- ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
+ ignoreAssetsPattern "!.svn:!.git:!.gitignore:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
}
ndk {
@@ -85,6 +85,8 @@ android {
abiFilters export_abi_list
}
+ manifestPlaceholders = [godotEditorVersion: getGodotEditorVersion()]
+
// Feel free to modify the application id to your own.
applicationId getExportPackageName()
versionCode getExportVersionCode()
@@ -104,8 +106,10 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
+ // 'doNotStrip' is enabled for development within Android Studio
+ if (shouldNotStrip()) {
+ doNotStrip '**/*.so'
+ }
}
signingConfigs {
@@ -153,7 +157,7 @@ android {
aidl.srcDirs = ['aidl']
assets.srcDirs = ['assets']
}
- debug.jniLibs.srcDirs = ['libs/debug']
+ debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
release.jniLibs.srcDirs = ['libs/release']
}
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 8d3aa8a6b0..b278d15bdf 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,14 +1,14 @@
ext.versions = [
- androidGradlePlugin: '4.1.0',
+ androidGradlePlugin: '4.0.1',
compileSdk : 29,
minSdk : 18,
targetSdk : 29,
- buildTools : '30.0.1',
+ buildTools : '30.0.3',
supportCoreUtils : '1.0.0',
kotlinVersion : '1.4.10',
v4Support : '1.0.0',
javaVersion : 1.8,
- ndkVersion : '21.3.6528147' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated.
+ ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated.
]
@@ -50,7 +50,56 @@ ext.getExportVersionName = { ->
return versionName
}
-final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|"
+ext.getGodotEditorVersion = { ->
+ String editorVersion = project.hasProperty("godot_editor_version") ? project.property("godot_editor_version") : ""
+ if (editorVersion == null || editorVersion.isEmpty()) {
+ // Try the library version first
+ editorVersion = getGodotLibraryVersion()
+
+ if (editorVersion.isEmpty()) {
+ // Fallback value.
+ editorVersion = "custom_build"
+ }
+ }
+ return editorVersion
+}
+
+ext.getGodotLibraryVersion = { ->
+ // Attempt to read the version from the `version.py` file.
+ String libraryVersion = ""
+
+ File versionFile = new File("../../../version.py")
+ if (versionFile.isFile()) {
+ List<String> requiredKeys = ["major", "minor", "patch", "status", "module_config"]
+ def map = [:]
+
+ List<String> lines = versionFile.readLines()
+ for (String line in lines) {
+ String[] keyValue = line.split("=")
+ String key = keyValue[0].trim()
+ String value = keyValue[1].trim().replaceAll("\"", "")
+
+ if (requiredKeys.contains(key)) {
+ if (!value.isEmpty()) {
+ map[key] = value
+ }
+ requiredKeys.remove(key)
+ }
+ }
+
+ if (requiredKeys.empty) {
+ libraryVersion = map.values().join(".")
+ }
+ }
+
+ if (libraryVersion.isEmpty()) {
+ // Fallback value in case we're unable to read the file.
+ libraryVersion = "custom_build"
+ }
+ return libraryVersion
+}
+
+final String VALUE_SEPARATOR_REGEX = "\\|"
// get the list of ABIs the project should be exported to
ext.getExportEnabledABIs = { ->
@@ -59,7 +108,7 @@ ext.getExportEnabledABIs = { ->
enabledABIs = "armeabi-v7a|arm64-v8a|x86|x86_64|"
}
Set<String> exportAbiFilter = [];
- for (String abi_name : enabledABIs.split(PLUGIN_VALUE_SEPARATOR_REGEX)) {
+ for (String abi_name : enabledABIs.split(VALUE_SEPARATOR_REGEX)) {
if (!abi_name.trim().isEmpty()){
exportAbiFilter.add(abi_name);
}
@@ -94,7 +143,7 @@ ext.getGodotPluginsMavenRepos = { ->
if (project.hasProperty("plugins_maven_repos")) {
String mavenReposProperty = project.property("plugins_maven_repos")
if (mavenReposProperty != null && !mavenReposProperty.trim().isEmpty()) {
- for (String mavenRepoUrl : mavenReposProperty.split(PLUGIN_VALUE_SEPARATOR_REGEX)) {
+ for (String mavenRepoUrl : mavenReposProperty.split(VALUE_SEPARATOR_REGEX)) {
mavenRepos += mavenRepoUrl.trim()
}
}
@@ -114,7 +163,7 @@ ext.getGodotPluginsRemoteBinaries = { ->
if (project.hasProperty("plugins_remote_binaries")) {
String remoteDepsList = project.property("plugins_remote_binaries")
if (remoteDepsList != null && !remoteDepsList.trim().isEmpty()) {
- for (String dep: remoteDepsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) {
+ for (String dep: remoteDepsList.split(VALUE_SEPARATOR_REGEX)) {
remoteDeps += dep.trim()
}
}
@@ -133,7 +182,7 @@ ext.getGodotPluginsLocalBinaries = { ->
if (project.hasProperty("plugins_local_binaries")) {
String pluginsList = project.property("plugins_local_binaries")
if (pluginsList != null && !pluginsList.trim().isEmpty()) {
- for (String plugin : pluginsList.split(PLUGIN_VALUE_SEPARATOR_REGEX)) {
+ for (String plugin : pluginsList.split(VALUE_SEPARATOR_REGEX)) {
binDeps += plugin.trim()
}
}
@@ -160,10 +209,19 @@ ext.getReleaseKeyAlias = { ->
return keyAlias
}
+ext.isAndroidStudio = { ->
+ def sysProps = System.getProperties()
+ return sysProps != null && sysProps['idea.platform.prefix'] != null
+}
+
ext.shouldZipAlign = { ->
String zipAlignFlag = project.hasProperty("perform_zipalign") ? project.property("perform_zipalign") : ""
if (zipAlignFlag == null || zipAlignFlag.isEmpty()) {
- zipAlignFlag = "false"
+ if (isAndroidStudio()) {
+ zipAlignFlag = "true"
+ } else {
+ zipAlignFlag = "false"
+ }
}
return Boolean.parseBoolean(zipAlignFlag)
}
@@ -171,7 +229,15 @@ ext.shouldZipAlign = { ->
ext.shouldSign = { ->
String signFlag = project.hasProperty("perform_signing") ? project.property("perform_signing") : ""
if (signFlag == null || signFlag.isEmpty()) {
- signFlag = "false"
+ if (isAndroidStudio()) {
+ signFlag = "true"
+ } else {
+ signFlag = "false"
+ }
}
return Boolean.parseBoolean(signFlag)
}
+
+ext.shouldNotStrip = { ->
+ return isAndroidStudio() || project.hasProperty("doNotStrip")
+}
diff --git a/platform/android/java/app/res/drawable/splash.png b/platform/android/java/app/res/drawable-nodpi/splash.png
index 7bddd4325a..7bddd4325a 100644
--- a/platform/android/java/app/res/drawable/splash.png
+++ b/platform/android/java/app/res/drawable-nodpi/splash.png
Binary files differ
diff --git a/platform/android/java/app/res/drawable/splash_bg_color.png b/platform/android/java/app/res/drawable-nodpi/splash_bg_color.png
index 004b6fd508..004b6fd508 100644
--- a/platform/android/java/app/res/drawable/splash_bg_color.png
+++ b/platform/android/java/app/res/drawable-nodpi/splash_bg_color.png
Binary files differ
diff --git a/platform/android/java/app/res/drawable/splash_drawable.xml b/platform/android/java/app/res/drawable/splash_drawable.xml
index 2794a40817..30627b998c 100644
--- a/platform/android/java/app/res/drawable/splash_drawable.xml
+++ b/platform/android/java/app/res/drawable/splash_drawable.xml
@@ -6,7 +6,7 @@
<item>
<bitmap
android:gravity="center"
+ android:filter="false"
android:src="@drawable/splash" />
</item>
-
</layer-list>
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 73c136ed0e..a7fe500be2 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -112,7 +112,7 @@ task copyReleaseAARToBin(type: Copy) {
* The zip file also includes some gradle tools to allow building of the custom build.
*/
task zipCustomBuild(type: Zip) {
- dependsOn ':generateGodotTemplates'
+ onlyIf { generateGodotTemplates.state.executed || generateDevTemplate.state.executed }
doFirst {
logger.lifecycle("Generating Godot custom build template")
}
@@ -122,16 +122,17 @@ task zipCustomBuild(type: Zip) {
destinationDir(file(binDir))
}
-/**
- * Master task used to coordinate the tasks defined above to generate the set of Godot templates.
- */
-task generateGodotTemplates(type: GradleBuild) {
+def templateExcludedBuildTask() {
// We exclude these gradle tasks so we can run the scons command manually.
+ def excludedTasks = []
for (String buildType : supportedTargets) {
- startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType)
+ excludedTasks += ":lib:" + getSconsTaskName(buildType)
}
+ return excludedTasks
+}
- tasks = []
+def templateBuildTasks() {
+ def tasks = []
// Only build the apks and aar files for which we have native shared libraries.
for (String target : supportedTargets) {
@@ -152,6 +153,29 @@ task generateGodotTemplates(type: GradleBuild) {
}
}
+ return tasks
+}
+
+/**
+ * Master task used to coordinate the tasks defined above to generate the set of Godot templates.
+ */
+task generateGodotTemplates(type: GradleBuild) {
+ startParameter.excludedTaskNames = templateExcludedBuildTask()
+ tasks = templateBuildTasks()
+
+ finalizedBy 'zipCustomBuild'
+}
+
+/**
+ * Generates the same output as generateGodotTemplates but with dev symbols
+ */
+task generateDevTemplate (type: GradleBuild) {
+ // add parameter to set symbols to true
+ startParameter.projectProperties += [doNotStrip: true]
+
+ startParameter.excludedTaskNames = templateExcludedBuildTask()
+ tasks = templateBuildTasks()
+
finalizedBy 'zipCustomBuild'
}
@@ -165,12 +189,6 @@ task cleanGodotTemplates(type: Delete) {
// Delete the library generated AAR files
delete("lib/build/outputs/aar")
- // Delete the godotpayment libs directory contents
- delete("plugins/godotpayment/libs")
-
- // Delete the generated godotpayment aar
- delete("plugins/godotpayment/build/outputs/aar")
-
// Delete the app libs directory contents
delete("app/libs")
diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties
index 2dc069ad2f..6b3b62a9da 100644
--- a/platform/android/java/gradle.properties
+++ b/platform/android/java/gradle.properties
@@ -12,7 +12,7 @@ android.useAndroidX=true
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
+org.gradle.jvmargs=-Xmx4536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml
index fa39bc0f1d..3034794d69 100644
--- a/platform/android/java/lib/AndroidManifest.xml
+++ b/platform/android/java/lib/AndroidManifest.xml
@@ -6,6 +6,11 @@
<application>
+ <!-- Records the version of the Godot library -->
+ <meta-data
+ android:name="org.godotengine.library.version"
+ android:value="${godotLibraryVersion}" />
+
<service android:name=".GodotDownloaderService" />
</application>
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 6260cadffb..663ba73d40 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -13,9 +13,13 @@ android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
+ ndkVersion versions.ndkVersion
+
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
+
+ manifestPlaceholders = [godotLibraryVersion: getGodotLibraryVersion()]
}
compileOptions {
@@ -32,8 +36,10 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
+ // 'doNotStrip' is enabled for development within Android Studio
+ if (shouldNotStrip()) {
+ doNotStrip '**/*.so'
+ }
}
sourceSets {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index 4e67402c63..1ed16e04ca 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -34,6 +34,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
+import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
@@ -44,7 +45,7 @@ import androidx.fragment.app.FragmentActivity;
* It's also a reference implementation for how to setup and use the {@link Godot} fragment
* within an Android app.
*/
-public abstract class FullScreenGodotApp extends FragmentActivity {
+public abstract class FullScreenGodotApp extends FragmentActivity implements GodotHost {
@Nullable
private Godot godotFragment;
@@ -62,11 +63,30 @@ public abstract class FullScreenGodotApp extends FragmentActivity {
@Override
public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
if (godotFragment != null) {
godotFragment.onNewIntent(intent);
}
}
+ @CallSuper
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (godotFragment != null) {
+ godotFragment.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ @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) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 7d396b402e..0c16214c8a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -103,6 +103,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -131,6 +132,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
private boolean activityResumed;
private int mState;
+ private GodotHost godotHost;
private GodotPluginRegistry pluginRegistry;
static private Intent mCurrentIntent;
@@ -178,7 +180,25 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public ResultCallback result_callback;
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (getParentFragment() instanceof GodotHost) {
+ godotHost = (GodotHost)getParentFragment();
+ } else if (getActivity() instanceof GodotHost) {
+ godotHost = (GodotHost)getActivity();
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ godotHost = null;
+ }
+
+ @CallSuper
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
if (result_callback != null) {
result_callback.callback(requestCode, resultCode, data);
result_callback = null;
@@ -189,8 +209,10 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
}
+ @CallSuper
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainRequestPermissionsResult(requestCode, permissions, grantResults);
}
@@ -201,6 +223,20 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
};
/**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ @CallSuper
+ protected void onGodotSetupCompleted() {
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGodotSetupCompleted();
+ }
+
+ if (godotHost != null) {
+ godotHost.onGodotSetupCompleted();
+ }
+ }
+
+ /**
* Invoked on the render thread when the Godot main loop has started.
*/
@CallSuper
@@ -208,6 +244,10 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGodotMainLoopStarted();
}
+
+ if (godotHost != null) {
+ godotHost.onGodotMainLoopStarted();
+ }
}
/**
@@ -228,7 +268,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
GodotLib.setup(command_line);
- final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name");
+ final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name");
if (videoDriver.equals("Vulkan")) {
mRenderView = new GodotVulkanRenderView(activity, this);
} else {
@@ -301,7 +341,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(durationMs, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
- //deprecated in API 26
+ // deprecated in API 26
v.vibrate(durationMs);
}
}
@@ -356,6 +396,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
@CallSuper
protected String[] getCommandLine() {
+ String[] original = parseCommandLine();
+ String[] updated;
+ List<String> hostCommandLine = godotHost != null ? godotHost.getCommandLine() : null;
+ if (hostCommandLine == null || hostCommandLine.isEmpty()) {
+ updated = original;
+ } else {
+ updated = Arrays.copyOf(original, original.length + hostCommandLine.size());
+ for (int i = 0; i < hostCommandLine.size(); i++) {
+ updated[original.length + i] = hostCommandLine.get(i);
+ }
+ }
+ return updated;
+ }
+
+ private String[] parseCommandLine() {
InputStream is;
try {
is = getActivity().getAssets().open("_cl_");
@@ -464,14 +519,16 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) {
+ public void onCreate(Bundle icicle) {
+ 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
+ // check for apk expansion API
boolean md5mismatch = false;
command_line = getCommandLine();
String main_pack_md5 = null;
@@ -527,9 +584,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
command_line = new_args.toArray(new String[new_args.size()]);
}
if (use_apk_expansion && main_pack_md5 != null && main_pack_key != null) {
- //check that environment is ok!
+ // check that environment is ok!
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- //show popup and die
+ // show popup and die
}
// Build the full path to the app's expansion files
@@ -572,24 +629,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
// This is where you do set up to display the download
- // progress (next step)
+ // progress (next step in onCreateView)
mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
GodotDownloaderService.class);
- 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;
}
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
@@ -600,6 +644,27 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
mCurrentIntent = activity.getIntent();
initializeGodot();
+ }
+
+ @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;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
new file mode 100644
index 0000000000..317fd13535
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* GodotHost.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+package org.godotengine.godot;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Denotate a component (e.g: Activity, Fragment) that hosts the {@link Godot} fragment.
+ */
+public interface GodotHost {
+ /**
+ * Provides a set of command line parameters to setup the engine.
+ */
+ default List<String> getCommandLine() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ default void onGodotSetupCompleted() {}
+
+ /**
+ * Invoked on the render thread when the Godot main loop has started.
+ */
+ default void onGodotMainLoopStarted() {}
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 3368363ce7..435b8b325f 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
@@ -38,6 +38,8 @@ import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
import android.os.Build;
import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.InputDevice;
import android.view.InputDevice.MotionRange;
import android.view.KeyEvent;
@@ -46,17 +48,24 @@ import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Handles input related events for the {@link GodotRenderView} view.
*/
public class GodotInputHandler implements InputDeviceListener {
- private final ArrayList<Joystick> mJoysticksDevices = new ArrayList<Joystick>();
-
private final GodotRenderView mRenderView;
private final InputManagerCompat mInputManager;
+ private final String tag = this.getClass().getSimpleName();
+
+ private final SparseIntArray mJoystickIds = new SparseIntArray(4);
+ private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<Joystick>(4);
+
public GodotInputHandler(GodotRenderView godotView) {
mRenderView = godotView;
mInputManager = InputManagerCompat.Factory.getInputManager(mRenderView.getView().getContext());
@@ -82,19 +91,20 @@ public class GodotInputHandler implements InputDeviceListener {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
return false;
- };
+ }
int source = event.getSource();
if (isKeyEvent_GameDevice(source)) {
- final int button = getGodotButton(keyCode);
- final int device_id = findJoystickDevice(event.getDeviceId());
-
// Check if the device exists
- if (device_id > -1) {
+ final int deviceId = event.getDeviceId();
+ if (mJoystickIds.indexOfKey(deviceId) >= 0) {
+ final int button = getGodotButton(keyCode);
+ final int godotJoyId = mJoystickIds.get(deviceId);
+
queueEvent(new Runnable() {
@Override
public void run() {
- GodotLib.joybutton(device_id, button, false);
+ GodotLib.joybutton(godotJoyId, button, false);
}
});
}
@@ -107,7 +117,7 @@ public class GodotInputHandler implements InputDeviceListener {
GodotLib.key(keyCode, scanCode, chr, false);
}
});
- };
+ }
return true;
}
@@ -122,24 +132,25 @@ public class GodotInputHandler implements InputDeviceListener {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
return false;
- };
+ }
int source = event.getSource();
//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
+ final int deviceId = event.getDeviceId();
+ // Check if source is a game device and that the device is a registered gamepad
if (isKeyEvent_GameDevice(source)) {
if (event.getRepeatCount() > 0) // ignore key echo
return true;
- final int button = getGodotButton(keyCode);
- final int device_id = findJoystickDevice(event.getDeviceId());
+ if (mJoystickIds.indexOfKey(deviceId) >= 0) {
+ final int button = getGodotButton(keyCode);
+ final int godotJoyId = mJoystickIds.get(deviceId);
- // Check if the device exists
- if (device_id > -1) {
queueEvent(new Runnable() {
@Override
public void run() {
- GodotLib.joybutton(device_id, button, true);
+ GodotLib.joybutton(godotJoyId, button, true);
}
});
}
@@ -152,7 +163,7 @@ public class GodotInputHandler implements InputDeviceListener {
GodotLib.key(keyCode, scanCode, chr, true);
}
});
- };
+ }
return true;
}
@@ -203,38 +214,52 @@ public class GodotInputHandler implements InputDeviceListener {
}
public boolean onGenericMotionEvent(MotionEvent event) {
- if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
- final int device_id = findJoystickDevice(event.getDeviceId());
-
+ if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getAction() == MotionEvent.ACTION_MOVE) {
// Check if the device exists
- if (device_id > -1) {
- Joystick joy = mJoysticksDevices.get(device_id);
-
- for (int i = 0; i < joy.axes.size(); i++) {
- InputDevice.MotionRange range = joy.axes.get(i);
- final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
- final int idx = i;
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyaxis(device_id, idx, value);
- }
- });
+ final int deviceId = event.getDeviceId();
+ if (mJoystickIds.indexOfKey(deviceId) >= 0) {
+ final int godotJoyId = mJoystickIds.get(deviceId);
+ Joystick joystick = mJoysticksDevices.get(deviceId);
+
+ for (int i = 0; i < joystick.axes.size(); i++) {
+ final int axis = joystick.axes.get(i);
+ final float value = event.getAxisValue(axis);
+ /**
+ * As all axes are polled for each event, only fire an axis event if the value has actually changed.
+ * Prevents flooding Godot with repeated events.
+ */
+ if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) {
+ // save value to prevent repeats
+ joystick.axesValues.put(axis, value);
+ final int godotAxisIdx = i;
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyaxis(godotJoyId, godotAxisIdx, value);
+ //Log.i(tag, "GodotLib.joyaxis("+godotJoyId+", "+godotAxisIdx+", "+value+");");
+ }
+ });
+ }
}
- for (int i = 0; i < joy.hats.size(); i += 2) {
- final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis()));
- final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis()));
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyhat(device_id, hatX, hatY);
- }
- });
+ if (joystick.hasAxisHat) {
+ final int hatX = Math.round(event.getAxisValue(MotionEvent.AXIS_HAT_X));
+ final int hatY = Math.round(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
+ if (joystick.hatX != hatX || joystick.hatY != hatY) {
+ joystick.hatX = hatX;
+ joystick.hatY = hatY;
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyhat(godotJoyId, hatX, hatY);
+ //Log.i(tag, "GodotLib.joyhat("+godotJoyId+", "+hatX+", "+hatY+");");
+ }
+ });
+ }
}
return true;
}
- } else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
+ } else if (event.isFromSource(InputDevice.SOURCE_STYLUS)) {
final float x = event.getX();
final float y = event.getY();
final int type = event.getAction();
@@ -245,6 +270,7 @@ public class GodotInputHandler implements InputDeviceListener {
}
});
return true;
+
} else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return handleMouseEvent(event);
@@ -266,67 +292,98 @@ public class GodotInputHandler implements InputDeviceListener {
}
}
+ private int assignJoystickIdNumber(int deviceId) {
+ int godotJoyId = 0;
+ while (mJoystickIds.indexOfValue(godotJoyId) >= 0) {
+ godotJoyId++;
+ }
+ mJoystickIds.put(deviceId, godotJoyId);
+ return godotJoyId;
+ }
+
@Override
public void onInputDeviceAdded(int deviceId) {
- int id = findJoystickDevice(deviceId);
-
// Check if the device has not been already added
- if (id < 0) {
- InputDevice device = mInputManager.getInputDevice(deviceId);
- //device can be null if deviceId is not found
- if (device != null) {
- int sources = device.getSources();
- if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
- ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) {
- id = mJoysticksDevices.size();
-
- Joystick joy = new Joystick();
- joy.device_id = deviceId;
- joy.name = device.getName();
- joy.axes = new ArrayList<InputDevice.MotionRange>();
- joy.hats = new ArrayList<InputDevice.MotionRange>();
-
- List<InputDevice.MotionRange> ranges = device.getMotionRanges();
- Collections.sort(ranges, new RangeComparator());
-
- for (InputDevice.MotionRange range : ranges) {
- if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
- joy.hats.add(range);
- } else {
- joy.axes.add(range);
- }
- }
- mJoysticksDevices.add(joy);
+ if (mJoystickIds.indexOfKey(deviceId) >= 0) {
+ return;
+ }
+
+ InputDevice device = mInputManager.getInputDevice(deviceId);
+ //device can be null if deviceId is not found
+ if (device == null) {
+ return;
+ }
+
+ int sources = device.getSources();
+
+ // Device may not be a joystick or gamepad
+ if ((sources & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD &&
+ (sources & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK) {
+ return;
+ }
+
+ // Assign first available number. Re-use numbers where possible.
+ final int id = assignJoystickIdNumber(deviceId);
+
+ final Joystick joystick = new Joystick();
+ joystick.device_id = deviceId;
+ joystick.name = device.getName();
+
+ //Helps with creating new joypad mappings.
+ Log.i(tag, "=== New Input Device: " + joystick.name);
- final int device_id = id;
- final String name = joy.name;
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyconnectionchanged(device_id, true, name);
- }
- });
+ Set<Integer> already = new HashSet<Integer>();
+ for (InputDevice.MotionRange range : device.getMotionRanges()) {
+ boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK);
+ boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD);
+ //Log.i(tag, "axis: "+range.getAxis()+ ", isJoystick: "+isJoystick+", isGamepad: "+isGamepad);
+ if (!isJoystick && !isGamepad) {
+ continue;
+ }
+ final int axis = range.getAxis();
+ if (axis == MotionEvent.AXIS_HAT_X || axis == MotionEvent.AXIS_HAT_Y) {
+ joystick.hasAxisHat = true;
+ } else {
+ if (!already.contains(axis)) {
+ already.add(axis);
+ joystick.axes.add(axis);
+ } else {
+ Log.w(tag, " - DUPLICATE AXIS VALUE IN LIST: " + axis);
}
}
}
+ Collections.sort(joystick.axes);
+ for (int idx = 0; idx < joystick.axes.size(); idx++) {
+ //Helps with creating new joypad mappings.
+ Log.i(tag, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx);
+ }
+ mJoysticksDevices.put(deviceId, joystick);
+
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyconnectionchanged(id, true, joystick.name);
+ }
+ });
}
@Override
public void onInputDeviceRemoved(int deviceId) {
- final int device_id = findJoystickDevice(deviceId);
-
- // Check if the evice has not been already removed
- if (device_id > -1) {
- mJoysticksDevices.remove(device_id);
-
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.joyconnectionchanged(device_id, false, "");
- }
- });
+ // Check if the device has not been already removed
+ if (mJoystickIds.indexOfKey(deviceId) < 0) {
+ return;
}
+ final int godotJoyId = mJoystickIds.get(deviceId);
+ mJoystickIds.delete(deviceId);
+ mJoysticksDevices.delete(deviceId);
+
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.joyconnectionchanged(godotJoyId, false, "");
+ }
+ });
}
@Override
@@ -407,16 +464,6 @@ public class GodotInputHandler implements InputDeviceListener {
return button;
}
- private int findJoystickDevice(int device_id) {
- for (int i = 0; i < mJoysticksDevices.size(); i++) {
- if (mJoysticksDevices.get(i).device_id == device_id) {
- return i;
- }
- }
-
- return -1;
- }
-
private boolean handleMouseEvent(final MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java
index 82bd45ee3f..4b7318c718 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java
@@ -30,9 +30,10 @@
package org.godotengine.godot.input;
-import android.view.InputDevice.MotionRange;
+import android.util.SparseArray;
import java.util.ArrayList;
+import java.util.List;
/**
* POJO class to represent a Joystick input device.
@@ -40,6 +41,12 @@ import java.util.ArrayList;
class Joystick {
int device_id;
String name;
- ArrayList<MotionRange> axes;
- ArrayList<MotionRange> hats;
+ List<Integer> axes = new ArrayList<Integer>();
+ protected boolean hasAxisHat = false;
+ /*
+ * Keep track of values so we can prevent flooding the engine with useless events.
+ */
+ protected final SparseArray axesValues = new SparseArray<Float>(4);
+ protected int hatX;
+ protected int hatY;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index a22b80761d..6c8a3d4219 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -46,7 +46,10 @@ import androidx.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -107,23 +110,52 @@ public abstract class GodotPlugin {
* This method is invoked on the render thread.
*/
public final void onRegisterPluginWithGodotNative() {
- nativeRegisterSingleton(getPluginName());
+ registeredSignals.putAll(
+ registerPluginWithGodotNative(this, getPluginName(), getPluginMethods(), getPluginSignals(),
+ getPluginGDNativeLibrariesPaths()));
+ }
+
+ /**
+ * Register the plugin with Godot native code.
+ *
+ * This method must be invoked on the render thread.
+ */
+ public static void registerPluginWithGodotNative(Object pluginObject,
+ GodotPluginInfoProvider pluginInfoProvider) {
+ registerPluginWithGodotNative(pluginObject, pluginInfoProvider.getPluginName(),
+ Collections.emptyList(), pluginInfoProvider.getPluginSignals(),
+ pluginInfoProvider.getPluginGDNativeLibrariesPaths());
+
+ // Notify that registration is complete.
+ pluginInfoProvider.onPluginRegistered();
+ }
+
+ private static Map<String, SignalInfo> registerPluginWithGodotNative(Object pluginObject,
+ String pluginName, List<String> pluginMethods, Set<SignalInfo> pluginSignals,
+ Set<String> pluginGDNativeLibrariesPaths) {
+ nativeRegisterSingleton(pluginName, pluginObject);
+
+ Set<Method> filteredMethods = new HashSet<>();
+ Class clazz = pluginObject.getClass();
- Class clazz = getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
- boolean found = false;
-
- for (String s : getPluginMethods()) {
- if (s.equals(method.getName())) {
- found = true;
- break;
+ // Check if the method is annotated with {@link UsedByGodot}.
+ if (method.getAnnotation(UsedByGodot.class) != null) {
+ filteredMethods.add(method);
+ } else {
+ // For backward compatibility, process the methods from the given <pluginMethods> argument.
+ for (String methodName : pluginMethods) {
+ if (methodName.equals(method.getName())) {
+ filteredMethods.add(method);
+ break;
+ }
}
}
- if (!found)
- continue;
+ }
- List<String> ptr = new ArrayList<String>();
+ for (Method method : filteredMethods) {
+ List<String> ptr = new ArrayList<>();
Class[] paramTypes = method.getParameterTypes();
for (Class c : paramTypes) {
@@ -133,26 +165,28 @@ public abstract class GodotPlugin {
String[] pt = new String[ptr.size()];
ptr.toArray(pt);
- nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt);
+ nativeRegisterMethod(pluginName, method.getName(), method.getReturnType().getName(), pt);
}
// Register the signals for this plugin.
- for (SignalInfo signalInfo : getPluginSignals()) {
+ Map<String, SignalInfo> registeredSignals = new HashMap<>();
+ for (SignalInfo signalInfo : pluginSignals) {
String signalName = signalInfo.getName();
- nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames());
+ nativeRegisterSignal(pluginName, signalName, signalInfo.getParamTypesNames());
registeredSignals.put(signalName, signalInfo);
}
// Get the list of gdnative libraries to register.
- Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths();
- if (!gdnativeLibrariesPaths.isEmpty()) {
- nativeRegisterGDNativeLibraries(gdnativeLibrariesPaths.toArray(new String[0]));
+ if (!pluginGDNativeLibrariesPaths.isEmpty()) {
+ nativeRegisterGDNativeLibraries(pluginGDNativeLibrariesPaths.toArray(new String[0]));
}
+
+ return registeredSignals;
}
/**
* Invoked once during the Godot Android initialization process after creation of the
- * {@link org.godotengine.godot.GodotView} view.
+ * {@link org.godotengine.godot.GodotRenderView} view.
* <p>
* The plugin can return a non-null {@link View} layout in order to add it to the Godot view
* hierarchy.
@@ -198,6 +232,11 @@ public abstract class GodotPlugin {
public boolean onMainBackPressed() { return false; }
/**
+ * Invoked on the render thread when the Godot setup is complete.
+ */
+ public void onGodotSetupCompleted() {}
+
+ /**
* Invoked on the render thread when the Godot main loop has started.
*/
public void onGodotMainLoopStarted() {}
@@ -244,8 +283,11 @@ public abstract class GodotPlugin {
/**
* Returns the list of methods to be exposed to Godot.
+ *
+ * @deprecated Used the {@link UsedByGodot} annotation instead.
*/
@NonNull
+ @Deprecated
public List<String> getPluginMethods() {
return Collections.emptyList();
}
@@ -290,8 +332,8 @@ public abstract class GodotPlugin {
/**
* Emit a registered Godot signal.
- * @param signalName
- * @param signalArgs
+ * @param signalName Name of the signal to emit. It will be validated against the set of registered signals.
+ * @param signalArgs Arguments used to populate the emitted signal. The arguments will be validated against the {@link SignalInfo} matching the registered signalName parameter.
*/
protected void emitSignal(final String signalName, final Object... signalArgs) {
try {
@@ -301,6 +343,27 @@ public abstract class GodotPlugin {
throw new IllegalArgumentException(
"Signal " + signalName + " is not registered for this plugin.");
}
+ emitSignal(getGodot(), getPluginName(), signalInfo, signalArgs);
+ } catch (IllegalArgumentException exception) {
+ Log.w(TAG, exception.getMessage());
+ if (BuildConfig.DEBUG) {
+ throw exception;
+ }
+ }
+ }
+
+ /**
+ * Emit a Godot signal.
+ * @param godot
+ * @param pluginName Name of the Godot plugin the signal will be emitted from. The plugin must already be registered with the Godot engine.
+ * @param signalInfo Information about the signal to emit.
+ * @param signalArgs Arguments used to populate the emitted signal. The arguments will be validated against the given {@link SignalInfo} parameter.
+ */
+ public static void emitSignal(Godot godot, String pluginName, SignalInfo signalInfo, final Object... signalArgs) {
+ try {
+ if (signalInfo == null) {
+ throw new IllegalArgumentException("Signal must be non null.");
+ }
// Validate the arguments count.
Class<?>[] signalParamTypes = signalInfo.getParamTypes();
@@ -317,12 +380,8 @@ public abstract class GodotPlugin {
}
}
- runOnRenderThread(new Runnable() {
- @Override
- public void run() {
- nativeEmitSignal(getPluginName(), signalName, signalArgs);
- }
- });
+ godot.runOnRenderThread(() -> nativeEmitSignal(pluginName, signalInfo.getName(), signalArgs));
+
} catch (IllegalArgumentException exception) {
Log.w(TAG, exception.getMessage());
if (BuildConfig.DEBUG) {
@@ -335,7 +394,7 @@ public abstract class GodotPlugin {
* Used to setup a {@link GodotPlugin} instance.
* @param p_name Name of the instance.
*/
- private native void nativeRegisterSingleton(String p_name);
+ private static native void nativeRegisterSingleton(String p_name, Object object);
/**
* Used to complete registration of the {@link GodotPlugin} instance's methods.
@@ -344,13 +403,13 @@ public abstract class GodotPlugin {
* @param p_ret Return type of the registered method
* @param p_params Method parameters types
*/
- private native void nativeRegisterMethod(String p_sname, String p_name, String p_ret, String[] p_params);
+ private static native void nativeRegisterMethod(String p_sname, String p_name, String p_ret, String[] p_params);
/**
* Used to register gdnative libraries bundled by the plugin.
* @param gdnlibPaths Paths to the libraries relative to the 'assets' directory.
*/
- private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
+ private static native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
/**
* Used to complete registration of the {@link GodotPlugin} instance's methods.
@@ -358,7 +417,7 @@ public abstract class GodotPlugin {
* @param signalName Name of the signal to register
* @param signalParamTypes Signal parameters types
*/
- private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
+ private static native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
/**
* Used to emit signal by {@link GodotPlugin} instance.
@@ -366,5 +425,5 @@ public abstract class GodotPlugin {
* @param signalName Name of the signal to emit
* @param signalParams Signal parameters
*/
- private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
+ private static native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java
new file mode 100644
index 0000000000..09366384c2
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginInfoProvider.java
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* GodotPluginInfoProvider.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import androidx.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Provides the set of information expected from a Godot plugin.
+ */
+public interface GodotPluginInfoProvider {
+ /**
+ * Returns the name of the plugin.
+ */
+ @NonNull
+ String getPluginName();
+
+ /**
+ * Returns the list of signals to be exposed to Godot.
+ */
+ @NonNull
+ default Set<SignalInfo> getPluginSignals() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns the paths for the plugin's gdnative libraries (if any).
+ *
+ * The paths must be relative to the 'assets' directory and point to a '*.gdnlib' file.
+ */
+ @NonNull
+ default Set<String> getPluginGDNativeLibrariesPaths() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * This is invoked on the render thread when the plugin described by this instance has been
+ * registered.
+ */
+ default void onPluginRegistered() {
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java
index 99811f72ed..5b41205253 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java
@@ -44,8 +44,6 @@ import androidx.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -56,13 +54,6 @@ public final class GodotPluginRegistry {
private static final String GODOT_PLUGIN_V1_NAME_PREFIX = "org.godotengine.plugin.v1.";
- /**
- * Name for the metadata containing the list of Godot plugins to enable.
- */
- private static final String GODOT_ENABLED_PLUGINS_LABEL = "plugins";
-
- private static final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|";
-
private static GodotPluginRegistry instance;
private final ConcurrentHashMap<String, GodotPlugin> registry;
@@ -132,37 +123,11 @@ public final class GodotPluginRegistry {
return;
}
- // When using the Godot editor for building and exporting the apk, this is used to check
- // which plugins to enable.
- // When using a custom process to generate the apk, the metadata is not needed since
- // it's assumed that the developer is aware of the dependencies included in the apk.
- final Set<String> enabledPluginsSet;
- if (metaData.containsKey(GODOT_ENABLED_PLUGINS_LABEL)) {
- String enabledPlugins = metaData.getString(GODOT_ENABLED_PLUGINS_LABEL, "");
- String[] enabledPluginsList = enabledPlugins.split(PLUGIN_VALUE_SEPARATOR_REGEX);
- if (enabledPluginsList.length == 0) {
- // No plugins to enable. Aborting early.
- return;
- }
-
- enabledPluginsSet = new HashSet<>();
- for (String enabledPlugin : enabledPluginsList) {
- enabledPluginsSet.add(enabledPlugin.trim());
- }
- } else {
- enabledPluginsSet = null;
- }
-
int godotPluginV1NamePrefixLength = GODOT_PLUGIN_V1_NAME_PREFIX.length();
for (String metaDataName : metaData.keySet()) {
// Parse the meta-data looking for entry with the Godot plugin name prefix.
if (metaDataName.startsWith(GODOT_PLUGIN_V1_NAME_PREFIX)) {
String pluginName = metaDataName.substring(godotPluginV1NamePrefixLength).trim();
- if (enabledPluginsSet != null && !enabledPluginsSet.contains(pluginName)) {
- Log.w(TAG, "Plugin " + pluginName + " is listed in the dependencies but is not enabled.");
- continue;
- }
-
Log.i(TAG, "Initializing Godot plugin " + pluginName);
// Retrieve the plugin class full name.
@@ -177,8 +142,7 @@ public final class GodotPluginRegistry {
.getConstructor(Godot.class);
GodotPlugin pluginHandle = pluginConstructor.newInstance(godot);
- // Load the plugin initializer into the registry using the plugin name
- // as key.
+ // Load the plugin initializer into the registry using the plugin name as key.
if (!pluginName.equals(pluginHandle.getPluginName())) {
Log.w(TAG,
"Meta-data plugin name does not match the value returned by the plugin handle: " + pluginName + " =/= " + pluginHandle.getPluginName());
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java
new file mode 100644
index 0000000000..04c091d944
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/UsedByGodot.java
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* UsedByGodot.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate a method is being invoked from the Godot game logic.
+ *
+ * At runtime, annotated plugin methods are detected and automatically registered.
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UsedByGodot {}
diff --git a/platform/android/java/nativeSrcsConfigs/README.md b/platform/android/java/nativeSrcsConfigs/README.md
index e48505ccda..9d884415cc 100644
--- a/platform/android/java/nativeSrcsConfigs/README.md
+++ b/platform/android/java/nativeSrcsConfigs/README.md
@@ -1,4 +1,4 @@
## Native sources configs
-This is a non functional Android library used to provide Android Studio editor support to the Godot project native files.
+This is a non-functional Android library used to provide Android Studio editor support to the Godot project native files.
Nothing else should be added to this library.
diff --git a/platform/android/java/nativeSrcsConfigs/build.gradle b/platform/android/java/nativeSrcsConfigs/build.gradle
index 66077060ea..158bb2b98e 100644
--- a/platform/android/java/nativeSrcsConfigs/build.gradle
+++ b/platform/android/java/nativeSrcsConfigs/build.gradle
@@ -20,9 +20,6 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
-
- // Should be uncommented for development purpose within Android Studio
- // doNotStrip '**/*.so'
}
sourceSets {
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index ab03599dc3..f49b0e843a 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -38,6 +38,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
return false;
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
MethodInfo *method = nullptr;
for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) {
@@ -965,6 +966,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
return class_cache[p_class];
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, Ref<JavaClass>());
jclass bclass = env->FindClass(p_class.utf8().get_data());
ERR_FAIL_COND_V(!bclass, Ref<JavaClass>());
@@ -1149,6 +1151,7 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
singleton = this;
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jclass activityClass = env->FindClass("android/app/Activity");
jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 4ee4427aa0..ec3b6f8ac0 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -73,6 +73,7 @@ jobject GodotIOJavaWrapper::get_instance() {
Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
if (_open_URI) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, ERR_UNAVAILABLE);
jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
} else {
@@ -83,6 +84,7 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
String GodotIOJavaWrapper::get_user_data_dir() {
if (_get_data_dir) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
return jstring_to_string(s, env);
} else {
@@ -93,6 +95,7 @@ String GodotIOJavaWrapper::get_user_data_dir() {
String GodotIOJavaWrapper::get_locale() {
if (_get_locale) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale);
return jstring_to_string(s, env);
} else {
@@ -103,6 +106,7 @@ String GodotIOJavaWrapper::get_locale() {
String GodotIOJavaWrapper::get_model() {
if (_get_model) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model);
return jstring_to_string(s, env);
} else {
@@ -113,6 +117,7 @@ String GodotIOJavaWrapper::get_model() {
int GodotIOJavaWrapper::get_screen_dpi() {
if (_get_screen_DPI) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 160);
return env->CallIntMethod(godot_io_instance, _get_screen_DPI);
} else {
return 160;
@@ -122,6 +127,7 @@ int GodotIOJavaWrapper::get_screen_dpi() {
void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
if (_screen_get_usable_rect) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _screen_get_usable_rect);
ERR_FAIL_COND(env->GetArrayLength(returnArray) != 4);
jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE);
@@ -135,6 +141,7 @@ void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
String GodotIOJavaWrapper::get_unique_id() {
if (_get_unique_id) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_id);
return jstring_to_string(s, env);
} else {
@@ -149,6 +156,7 @@ bool GodotIOJavaWrapper::has_vk() {
void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
}
@@ -157,6 +165,7 @@ void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int
void GodotIOJavaWrapper::hide_vk() {
if (_hide_keyboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(godot_io_instance, _hide_keyboard);
}
}
@@ -164,6 +173,7 @@ void GodotIOJavaWrapper::hide_vk() {
void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
if (_set_screen_orientation) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
}
}
@@ -171,6 +181,7 @@ void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
int GodotIOJavaWrapper::get_screen_orientation() {
if (_get_screen_orientation) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 0);
return env->CallIntMethod(godot_io_instance, _get_screen_orientation);
} else {
return 0;
@@ -180,6 +191,7 @@ int GodotIOJavaWrapper::get_screen_orientation() {
String GodotIOJavaWrapper::get_system_dir(int p_dir) {
if (_get_system_dir) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String("."));
jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
return jstring_to_string(s, env);
} else {
@@ -187,14 +199,14 @@ String GodotIOJavaWrapper::get_system_dir(int p_dir) {
}
}
-// volatile because it can be changed from non-main thread and we need to
+// SafeNumeric because it can be changed from non-main thread and we need to
// ensure the change is immediately visible to other threads.
-static volatile int virtual_keyboard_height;
+static SafeNumeric<int> virtual_keyboard_height;
int GodotIOJavaWrapper::get_vk_height() {
- return virtual_keyboard_height;
+ return virtual_keyboard_height.get();
}
void GodotIOJavaWrapper::set_vk_height(int p_height) {
- virtual_keyboard_height = p_height;
+ virtual_keyboard_height.set(p_height);
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index bb22162879..0c342dc280 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -127,9 +127,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
- cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *));
+ cmdline = (const char **)memalloc((cmdlen + 1) * sizeof(const char *));
+ ERR_FAIL_NULL_MSG(cmdline, "Out of memory.");
cmdline[cmdlen] = nullptr;
- j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring));
+ j_cmdline = (jstring *)memalloc(cmdlen * sizeof(jstring));
+ ERR_FAIL_NULL_MSG(j_cmdline, "Out of memory.");
for (int i = 0; i < cmdlen; i++) {
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
@@ -147,13 +149,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
for (int i = 0; i < cmdlen; ++i) {
env->ReleaseStringUTFChars(j_cmdline[i], cmdline[i]);
}
- free(j_cmdline);
+ memfree(j_cmdline);
}
- free(cmdline);
+ memfree(cmdline);
}
if (err != OK) {
- return; //should exit instead and print the error
+ return; // should exit instead and print the error
}
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
@@ -215,9 +217,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
if (step == 1) {
if (!Main::start()) {
- return; //should exit instead and print the error
+ return; // should exit instead and print the error
}
+ godot_java->on_godot_setup_completed(env);
os_android->main_loop_begin();
godot_java->on_godot_main_loop_started(env);
++step;
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 5b638300ef..6b5e44f371 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -34,6 +34,7 @@
GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
_godot_view = env->NewGlobalRef(godot_view);
@@ -48,6 +49,8 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
void GodotJavaViewWrapper::request_pointer_capture() {
if (_request_pointer_capture != 0) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(_godot_view, _request_pointer_capture);
}
}
@@ -55,12 +58,16 @@ void GodotJavaViewWrapper::request_pointer_capture() {
void GodotJavaViewWrapper::release_pointer_capture() {
if (_request_pointer_capture != 0) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(_godot_view, _release_pointer_capture);
}
}
GodotJavaViewWrapper::~GodotJavaViewWrapper() {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->DeleteGlobalRef(_godot_view);
env->DeleteGlobalRef(_cls);
}
diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h
index 548c278292..bfb4369fb8 100644
--- a/platform/android/java_godot_view_wrapper.h
+++ b/platform/android/java_godot_view_wrapper.h
@@ -34,6 +34,8 @@
#include <android/log.h>
#include <jni.h>
+#include "string_android.h"
+
// Class that makes functions in java/src/org/godotengine/godot/GodotView.java callable from C++
class GodotJavaViewWrapper {
private:
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 759980373a..bfd93345f3 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -74,6 +74,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_is_activity_resumed = p_env->GetMethodID(godot_class, "isActivityResumed", "()Z");
_vibrate = p_env->GetMethodID(godot_class, "vibrate", "(I)V");
_get_input_fallback_mapping = p_env->GetMethodID(godot_class, "getInputFallbackMapping", "()Ljava/lang/String;");
+ _on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
// get some Activity method pointers...
@@ -93,6 +94,8 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND_V(p_env == nullptr, nullptr);
+
jfieldID fid = p_env->GetStaticFieldID(godot_class, p_name, p_class);
return p_env->GetStaticObjectField(godot_class, fid);
} else {
@@ -103,6 +106,8 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl
jobject GodotJavaWrapper::get_class_loader() {
if (_get_class_loader) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
return env->CallObjectMethod(activity, _get_class_loader);
} else {
return nullptr;
@@ -114,17 +119,30 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
return _godot_view;
}
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
_godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter));
return _godot_view;
}
void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
- if (_on_video_init)
+ if (_on_video_init) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _on_video_init);
+ p_env->CallVoidMethod(godot_instance, _on_video_init);
+ }
+}
+
+void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) {
+ if (_on_godot_setup_completed) {
+ if (p_env == nullptr) {
+ p_env = get_jni_env();
+ }
+ p_env->CallVoidMethod(godot_instance, _on_godot_setup_completed);
+ }
}
void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
@@ -132,29 +150,36 @@ void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
if (p_env == nullptr) {
p_env = get_jni_env();
}
+ ERR_FAIL_COND(p_env == nullptr);
+ p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
}
- p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
}
void GodotJavaWrapper::restart(JNIEnv *p_env) {
- if (_restart)
+ if (_restart) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _restart);
+ p_env->CallVoidMethod(godot_instance, _restart);
+ }
}
void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
- if (_finish)
+ if (_finish) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
- p_env->CallVoidMethod(godot_instance, _finish);
+ p_env->CallVoidMethod(godot_instance, _finish);
+ }
}
void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
if (_set_keep_screen_on) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled);
}
}
@@ -162,6 +187,8 @@ void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
if (_alert) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
@@ -170,6 +197,8 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
int GodotJavaWrapper::get_gles_version_code() {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, 0);
+
if (_get_GLES_version_code) {
return env->CallIntMethod(godot_instance, _get_GLES_version_code);
}
@@ -184,6 +213,8 @@ bool GodotJavaWrapper::has_get_clipboard() {
String GodotJavaWrapper::get_clipboard() {
if (_get_clipboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
+
jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard);
return jstring_to_string(s, env);
} else {
@@ -194,6 +225,8 @@ String GodotJavaWrapper::get_clipboard() {
String GodotJavaWrapper::get_input_fallback_mapping() {
if (_get_input_fallback_mapping) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
+
jstring fallback_mapping = (jstring)env->CallObjectMethod(godot_instance, _get_input_fallback_mapping);
return jstring_to_string(fallback_mapping, env);
} else {
@@ -208,6 +241,8 @@ bool GodotJavaWrapper::has_set_clipboard() {
void GodotJavaWrapper::set_clipboard(const String &p_text) {
if (_set_clipboard) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
}
@@ -216,6 +251,8 @@ void GodotJavaWrapper::set_clipboard(const String &p_text) {
bool GodotJavaWrapper::request_permission(const String &p_name) {
if (_request_permission) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
} else {
@@ -226,6 +263,8 @@ bool GodotJavaWrapper::request_permission(const String &p_name) {
bool GodotJavaWrapper::request_permissions() {
if (_request_permissions) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
return env->CallBooleanMethod(godot_instance, _request_permissions);
} else {
return false;
@@ -236,6 +275,8 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
Vector<String> permissions_list;
if (_get_granted_permissions) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, permissions_list);
+
jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions);
jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object);
@@ -254,6 +295,8 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
void GodotJavaWrapper::init_input_devices() {
if (_init_input_devices) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _init_input_devices);
}
}
@@ -261,6 +304,8 @@ void GodotJavaWrapper::init_input_devices() {
jobject GodotJavaWrapper::get_surface() {
if (_get_surface) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, nullptr);
+
return env->CallObjectMethod(godot_instance, _get_surface);
} else {
return nullptr;
@@ -270,6 +315,8 @@ jobject GodotJavaWrapper::get_surface() {
bool GodotJavaWrapper::is_activity_resumed() {
if (_is_activity_resumed) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, false);
+
return env->CallBooleanMethod(godot_instance, _is_activity_resumed);
} else {
return false;
@@ -279,6 +326,8 @@ bool GodotJavaWrapper::is_activity_resumed() {
void GodotJavaWrapper::vibrate(int p_duration_ms) {
if (_vibrate) {
JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms);
}
}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 99a60dffa1..0e20747a16 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -66,6 +66,7 @@ private:
jmethodID _is_activity_resumed = 0;
jmethodID _vibrate = 0;
jmethodID _get_input_fallback_mapping = 0;
+ jmethodID _on_godot_setup_completed = 0;
jmethodID _on_godot_main_loop_started = 0;
jmethodID _get_class_loader = 0;
@@ -80,6 +81,7 @@ public:
GodotJavaViewWrapper *get_godot_view();
void on_video_init(JNIEnv *p_env = nullptr);
+ void on_godot_setup_completed(JNIEnv *p_env = nullptr);
void on_godot_main_loop_started(JNIEnv *p_env = nullptr);
void restart(JNIEnv *p_env = nullptr);
void force_quit(JNIEnv *p_env = nullptr);
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index f602e99e61..ba3e9fa20f 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -41,7 +41,7 @@ static HashMap<String, JNISingleton *> jni_singletons;
extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jclass clazz, jstring name, jobject obj) {
String singname = jstring_to_string(name, env);
JNISingleton *s = (JNISingleton *)ClassDB::instance("JNISingleton");
s->set_instance(env->NewGlobalRef(obj));
@@ -51,7 +51,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
ProjectSettings::get_singleton()->set(singname, s);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jclass clazz, jstring sname, jstring name, jstring ret, jobjectArray args) {
String singname = jstring_to_string(sname, env);
ERR_FAIL_COND(!jni_singletons.has(singname));
@@ -83,7 +83,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
s->add_method(mname, mid, types, get_jni_type(retval));
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types) {
String singleton_name = jstring_to_string(j_plugin_name, env);
ERR_FAIL_COND(!jni_singletons.has(singleton_name));
@@ -104,7 +104,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
singleton->add_signal(signal_name, types);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params) {
String singleton_name = jstring_to_string(j_plugin_name, env);
ERR_FAIL_COND(!jni_singletons.has(singleton_name));
@@ -129,7 +129,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
singleton->emit_signal(signal_name, args, count);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jclass clazz, jobjectArray gdnlib_paths) {
int gdnlib_count = env->GetArrayLength(gdnlib_paths);
if (gdnlib_count == 0) {
return;
diff --git a/platform/android/plugin/godot_plugin_jni.h b/platform/android/plugin/godot_plugin_jni.h
index 8a08ec3709..b87f922e03 100644
--- a/platform/android/plugin/godot_plugin_jni.h
+++ b/platform/android/plugin/godot_plugin_jni.h
@@ -35,11 +35,11 @@
#include <jni.h>
extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jobject obj, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jclass clazz, jstring name, jobject obj);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jclass clazz, jstring sname, jstring name, jstring ret, jobjectArray args);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_param_types);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitSignal(JNIEnv *env, jclass clazz, jstring j_plugin_name, jstring j_signal_name, jobjectArray j_signal_params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jclass clazz, jobjectArray gdnlib_paths);
}
#endif // GODOT_PLUGIN_JNI_H
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index afcc7294f2..ba379c8d43 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -30,17 +30,34 @@
#include "thread_jandroid.h"
+#include <android/log.h>
+
#include "core/os/thread.h"
static JavaVM *java_vm = nullptr;
static thread_local JNIEnv *env = nullptr;
+// The logic here need to improve, init_thread/term_tread are designed to work with Thread::callback
+// Calling init_thread from setup_android_thread and get_jni_env to setup an env we're keeping and not detaching
+// could cause issues on app termination.
+//
+// We should be making sure that any thread started calls a nice cleanup function when it's done,
+// especially now that we use many more threads.
+
static void init_thread() {
+ if (env) {
+ // thread never detached! just keep using...
+ return;
+ }
+
java_vm->AttachCurrentThread(&env, nullptr);
}
static void term_thread() {
java_vm->DetachCurrentThread();
+
+ // this is no longer valid, must called init_thread to re-establish
+ env = nullptr;
}
void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
@@ -50,9 +67,17 @@ void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
}
void setup_android_thread() {
- init_thread();
+ if (!env) {
+ // !BAS! see remarks above
+ init_thread();
+ }
}
JNIEnv *get_jni_env() {
+ if (!env) {
+ // !BAS! see remarks above
+ init_thread();
+ }
+
return env;
}
diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
index 1bf85f07f1..63f2026fae 100644
--- a/platform/android/vulkan/vulkan_context_android.cpp
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -52,10 +52,10 @@ int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, in
return _window_create(DisplayServer::MAIN_WINDOW_ID, surface, p_width, p_height);
}
-VulkanContextAndroid::VulkanContextAndroid() {
- // TODO: fix validation layers
- use_validation_layers = false;
-}
+bool VulkanContextAndroid::_use_validation_layers() {
+ uint32_t count = 0;
+ _get_preferred_validation_layers(&count, nullptr);
-VulkanContextAndroid::~VulkanContextAndroid() {
+ // On Android, we use validation layers automatically if they were explicitly linked with the app.
+ return count > 0;
}
diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h
index c608f2d665..5a84eaf8f3 100644
--- a/platform/android/vulkan/vulkan_context_android.h
+++ b/platform/android/vulkan/vulkan_context_android.h
@@ -36,13 +36,16 @@
struct ANativeWindow;
class VulkanContextAndroid : public VulkanContext {
- virtual const char *_get_platform_surface_extension() const;
+ virtual const char *_get_platform_surface_extension() const override;
public:
int window_create(ANativeWindow *p_window, int p_width, int p_height);
- VulkanContextAndroid();
- ~VulkanContextAndroid();
+ VulkanContextAndroid() = default;
+ ~VulkanContextAndroid() override = default;
+
+protected:
+ bool _use_validation_layers() override;
};
#endif // VULKAN_CONTEXT_ANDROID_H
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 17796beb6f..cf358e0878 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -54,7 +54,7 @@ def configure(env):
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["-O2", "-ftree-vectorize", "-fomit-frame-pointer"])
env.Append(LINKFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(LINKFLAGS=["-Os"])
diff --git a/platform/iphone/display_layer.mm b/platform/iphone/display_layer.mm
index fb57db4518..b8df81b89a 100644
--- a/platform/iphone/display_layer.mm
+++ b/platform/iphone/display_layer.mm
@@ -89,7 +89,7 @@
// FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
// Create GL ES 2 context
- if (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES2") {
+ if (GLOBAL_GET("rendering/driver/driver_name") == "GLES2") {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
NSLog(@"Setting up an OpenGL ES 2.0 context.");
if (!context) {
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index 05dc78bb4d..b590ce065c 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -136,13 +136,13 @@ DisplayServerIPhone::~DisplayServerIPhone() {
if (rendering_device_vulkan) {
rendering_device_vulkan->finalize();
memdelete(rendering_device_vulkan);
- rendering_device_vulkan = NULL;
+ rendering_device_vulkan = nullptr;
}
if (context_vulkan) {
context_vulkan->window_destroy(MAIN_WINDOW_ID);
memdelete(context_vulkan);
- context_vulkan = NULL;
+ context_vulkan = nullptr;
}
}
#endif
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 91cecdd704..c585c2afbe 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -37,6 +37,7 @@
#include "core/io/zip_io.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
+#include "core/templates/safe_refcount.h"
#include "core/version.h"
#include "editor/editor_export.h"
#include "editor/editor_node.h"
@@ -56,9 +57,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Ref<ImageTexture> logo;
// Plugins
- volatile bool plugins_changed;
+ SafeFlag plugins_changed;
Thread check_for_changes_thread;
- volatile bool quit_request;
+ SafeFlag quit_request;
Mutex plugins_lock;
Vector<PluginConfigIOS> plugins;
@@ -141,19 +142,19 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
static void _check_for_changes_poll_thread(void *ud) {
EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud;
- while (!ea->quit_request) {
+ while (!ea->quit_request.is_set()) {
// Nothing to do if we already know the plugins have changed.
- if (!ea->plugins_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 = true;
+ 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 = true;
+ ea->plugins_changed.set();
break;
}
}
@@ -165,7 +166,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
OS::get_singleton()->delay_usec(300000);
- if (ea->quit_request) {
+ if (ea->quit_request.is_set()) {
break;
}
}
@@ -182,10 +183,10 @@ public:
virtual Ref<Texture2D> get_logo() const override { return logo; }
virtual bool should_update_export_options() override {
- bool export_options_changed = plugins_changed;
+ bool export_options_changed = plugins_changed.is_set();
if (export_options_changed) {
// don't clear unless we're reporting true, to avoid race
- plugins_changed = false;
+ plugins_changed.clear();
}
return export_options_changed;
}
@@ -291,7 +292,7 @@ public:
};
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
- String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
r_features->push_back("pvrtc");
if (driver == "Vulkan") {
// FIXME: Review if this is correct.
@@ -364,7 +365,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
for (int i = 0; i < found_plugins.size(); i++) {
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false));
}
- plugins_changed = false;
+ plugins_changed.clear();
plugins = found_plugins;
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
@@ -1967,14 +1968,13 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() {
logo.instance();
logo->create_from_image(img);
- plugins_changed = true;
- quit_request = false;
+ plugins_changed.set();
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
}
EditorExportPlatformIOS::~EditorExportPlatformIOS() {
- quit_request = true;
+ quit_request.set();
check_for_changes_thread.wait_to_finish();
}
diff --git a/platform/iphone/godot_iphone.mm b/platform/iphone/godot_iphone.mm
index 62bc2e6e52..6c3e1eabde 100644
--- a/platform/iphone/godot_iphone.mm
+++ b/platform/iphone/godot_iphone.mm
@@ -50,7 +50,7 @@ int add_path(int p_argc, char **p_args) {
p_args[p_argc++] = (char *)"--path";
p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding];
- p_args[p_argc] = NULL;
+ p_args[p_argc] = nullptr;
return p_argc;
};
@@ -69,7 +69,7 @@ int add_cmdline(int p_argc, char **p_args) {
p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding];
};
- p_args[p_argc] = NULL;
+ p_args[p_argc] = nullptr;
return p_argc;
};
diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm
index 887297848e..00a88d79c5 100644
--- a/platform/iphone/godot_view.mm
+++ b/platform/iphone/godot_view.mm
@@ -39,6 +39,7 @@
#import <CoreMotion/CoreMotion.h>
static const int max_touches = 8;
+static const float earth_gravity = 9.80665;
@interface GodotView () {
UITouch *godot_touches[max_touches];
@@ -290,14 +291,14 @@ static const int max_touches = 8;
- (void)initTouches {
for (int i = 0; i < max_touches; i++) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
}
}
- (int)getTouchIDForTouch:(UITouch *)p_touch {
int first = -1;
for (int i = 0; i < max_touches; i++) {
- if (first == -1 && godot_touches[i] == NULL) {
+ if (first == -1 && godot_touches[i] == nullptr) {
first = i;
continue;
}
@@ -317,11 +318,11 @@ static const int max_touches = 8;
- (int)removeTouch:(UITouch *)p_touch {
int remaining = 0;
for (int i = 0; i < max_touches; i++) {
- if (godot_touches[i] == NULL) {
+ if (godot_touches[i] == nullptr) {
continue;
}
if (godot_touches[i] == p_touch) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
} else {
++remaining;
}
@@ -331,7 +332,7 @@ static const int max_touches = 8;
- (void)clearTouches {
for (int i = 0; i < max_touches; i++) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
}
}
@@ -402,10 +403,19 @@ static const int max_touches = 8;
// https://developer.apple.com/reference/coremotion/cmmotionmanager?language=objc
// Apple splits our accelerometer date into a gravity and user movement
- // component. We add them back together
+ // component. We add them back together.
CMAcceleration gravity = self.motionManager.deviceMotion.gravity;
CMAcceleration acceleration = self.motionManager.deviceMotion.userAcceleration;
+ // To be consistent with Android we convert the unit of measurement from g (Earth's gravity)
+ // to m/s^2.
+ gravity.x *= earth_gravity;
+ gravity.y *= earth_gravity;
+ gravity.z *= earth_gravity;
+ acceleration.x *= earth_gravity;
+ acceleration.y *= earth_gravity;
+ acceleration.z *= earth_gravity;
+
///@TODO We don't seem to be getting data here, is my device broken or
/// is this code incorrect?
CMMagneticField magnetic = self.motionManager.deviceMotion.magneticField.field;
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index cef03534c4..3430a9cba7 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -56,16 +56,16 @@ void iOS::alert(const char *p_alert, const char *p_title) {
String iOS::get_model() const {
// [[UIDevice currentDevice] model] only returns "iPad" or "iPhone".
size_t size;
- sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+ sysctlbyname("hw.machine", nullptr, &size, nullptr, 0);
char *model = (char *)malloc(size);
- if (model == NULL) {
+ if (model == nullptr) {
return "";
}
- sysctlbyname("hw.machine", model, &size, NULL, 0);
+ sysctlbyname("hw.machine", model, &size, nullptr, 0);
NSString *platform = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
free(model);
const char *str = [platform UTF8String];
- return String(str != NULL ? str : "");
+ return String(str != nullptr ? str : "");
}
String iOS::get_rate_url(int p_app_id) const {
diff --git a/platform/iphone/joypad_iphone.mm b/platform/iphone/joypad_iphone.mm
index a0f0eee5d3..45842b38aa 100644
--- a/platform/iphone/joypad_iphone.mm
+++ b/platform/iphone/joypad_iphone.mm
@@ -287,7 +287,7 @@ void JoypadIPhone::start_processing() {
gamepad.dpad.right.isPressed);
};
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = -1;
if (element == gamepad.leftThumbstick) {
jx.value = gamepad.leftThumbstick.xAxis.value;
diff --git a/platform/iphone/keyboard_input_view.mm b/platform/iphone/keyboard_input_view.mm
index 1408f78e90..0e5a98a3e6 100644
--- a/platform/iphone/keyboard_input_view.mm
+++ b/platform/iphone/keyboard_input_view.mm
@@ -88,13 +88,15 @@
self.text = existingString;
self.previousText = existingString;
+ NSInteger safeStartIndex = MAX(start, 0);
+
NSRange textRange;
// Either a simple cursor or a selection.
if (end > 0) {
- textRange = NSMakeRange(start, end - start);
+ textRange = NSMakeRange(safeStartIndex, end - start);
} else {
- textRange = NSMakeRange(start, 0);
+ textRange = NSMakeRange(safeStartIndex, 0);
}
self.selectedRange = textRange;
diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h
index f4e30c8349..e2546e733c 100644
--- a/platform/iphone/plugin/godot_plugin_config.h
+++ b/platform/iphone/plugin/godot_plugin_config.h
@@ -218,8 +218,9 @@ static inline uint64_t get_plugin_modification_time(const PluginConfigIOS &plugi
} else {
String file_path = plugin_config.binary.get_base_dir();
String file_name = plugin_config.binary.get_basename().get_file();
- String release_file_name = file_path.plus_file(file_name + ".release.a");
- String debug_file_name = file_path.plus_file(file_name + ".debug.a");
+ String plugin_extension = plugin_config.binary.get_extension();
+ String release_file_name = file_path.plus_file(file_name + ".release." + plugin_extension);
+ String debug_file_name = file_path.plus_file(file_name + ".debug." + plugin_extension);
last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name));
last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name));
diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm
index b980ae99f0..08c9007fbb 100644
--- a/platform/iphone/vulkan_context_iphone.mm
+++ b/platform/iphone/vulkan_context_iphone.mm
@@ -38,13 +38,13 @@ const char *VulkanContextIPhone::_get_platform_surface_extension() const {
Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height) {
VkIOSSurfaceCreateInfoMVK createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
- createInfo.pNext = NULL;
+ createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pView = (__bridge const void *)p_metal_layer;
VkSurfaceKHR surface;
VkResult err =
- vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface);
+ vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return _window_create(p_window_id, surface, p_width, p_height);
diff --git a/platform/javascript/.eslintrc.engine.js b/platform/javascript/.eslintrc.engine.js
index 00f0f147a9..78df6d41d9 100644
--- a/platform/javascript/.eslintrc.engine.js
+++ b/platform/javascript/.eslintrc.engine.js
@@ -3,8 +3,8 @@ module.exports = {
"./.eslintrc.js",
],
"globals": {
+ "InternalConfig": true,
"Godot": true,
"Preloader": true,
- "Utils": true,
},
};
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 11a45d2811..a760e36982 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -17,7 +17,7 @@ sys_env.AddJSLibraries(
[
"js/libs/library_godot_audio.js",
"js/libs/library_godot_display.js",
- "js/libs/library_godot_http_request.js",
+ "js/libs/library_godot_fetch.js",
"js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js",
]
@@ -73,7 +73,7 @@ sys_env.Depends(build[0], sys_env["JS_EXTERNS"])
engine = [
"js/engine/preloader.js",
- "js/engine/utils.js",
+ "js/engine/config.js",
"js/engine/engine.js",
]
externs = [env.File("#platform/javascript/js/engine/engine.externs.js")]
@@ -86,40 +86,6 @@ wrap_list = [
]
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
-zip_dir = env.Dir("#bin/.javascript_zip")
-binary_name = "godot.tools" if env["tools"] else "godot"
-out_files = [
- zip_dir.File(binary_name + ".js"),
- zip_dir.File(binary_name + ".wasm"),
- zip_dir.File(binary_name + ".html"),
- zip_dir.File(binary_name + ".audio.worklet.js"),
-]
-html_file = "#misc/dist/html/full-size.html"
-if env["tools"]:
- subst_dict = {"\$GODOT_VERSION": env.GetBuildVersion()}
- html_file = env.Substfile(
- target="#bin/godot${PROGSUFFIX}.html", source="#misc/dist/html/editor.html", SUBST_DICT=subst_dict
- )
-
-in_files = [js_wrapped, build[1], html_file, "#platform/javascript/js/libs/audio.worklet.js"]
-if env["gdnative_enabled"]:
- in_files.append(build[2]) # Runtime
- out_files.append(zip_dir.File(binary_name + ".side.wasm"))
-elif env["threads_enabled"]:
- in_files.append(build[2]) # Worker
- out_files.append(zip_dir.File(binary_name + ".worker.js"))
-
-if env["tools"]:
- in_files.append("#misc/dist/html/logo.svg")
- out_files.append(zip_dir.File("logo.svg"))
- in_files.append("#icon.png")
- out_files.append(zip_dir.File("favicon.png"))
-
-zip_files = env.InstallAs(out_files, in_files)
-env.Zip(
- "#bin/godot",
- zip_files,
- ZIPROOT=zip_dir,
- ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
- ZIPCOMSTR="Archiving $SOURCES as $TARGET",
-)
+# Extra will be the thread worker, or the GDNative side, or None
+extra = build[2] if len(build) > 2 else None
+env.CreateTemplateZip(js_wrapped, build[1], extra)
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index 8355faccc2..7a2c2b2335 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -65,10 +65,10 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
FileAccess *src_f;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- zipFile zip = zipOpen2("/tmp/project.zip", APPEND_STATUS_CREATE, NULL, &io);
+ zipFile zip = zipOpen2("/tmp/project.zip", APPEND_STATUS_CREATE, nullptr, &io);
String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
_zip_recursive(resource_path, base_path, zip);
- zipClose(zip, NULL);
+ zipClose(zip, nullptr);
godot_js_editor_download_file("/tmp/project.zip", "project.zip", "application/zip");
}
@@ -88,12 +88,12 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z
String path = p_path.replace_first(p_base_path, "");
zipOpenNewFileInZip(p_zip,
path.utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
zipWriteInFileInZip(p_zip, data.ptr(), data.size());
@@ -116,12 +116,12 @@ void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_pa
String path = cs.replace_first(p_base_path, "") + "/";
zipOpenNewFileInZip(p_zip,
path.utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
zipCloseFileInZip(p_zip);
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index f7cc9e6540..478e848675 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -105,8 +105,8 @@ void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) {
}
Error AudioDriverJavaScript::init() {
- mix_rate = GLOBAL_GET("audio/mix_rate");
- int latency = GLOBAL_GET("audio/output_latency");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
channel_count = godot_audio_init(mix_rate, latency, &_state_change_callback, &_latency_update_callback);
buffer_length = closest_power_of_2((latency * mix_rate / 1000));
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 653d18f791..d01e8a8bd4 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -7,7 +7,7 @@ from emscripten_helpers import (
add_js_libraries,
add_js_pre,
add_js_externs,
- get_build_version,
+ create_template_zip,
)
from methods import get_compiler_version
from SCons.Util import WhereIs
@@ -64,21 +64,21 @@ def configure(env):
sys.exit(255)
## Build type
- if env["target"] == "release":
+ if env["target"].startswith("release"):
# Use -Os to prioritize optimizing for reduced file size. This is
# particularly valuable for the web platform because it directly
# decreases download time.
# -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
# 100 KiB over -Os, which does not justify the negative impact on
# run-time performance.
- env.Append(CCFLAGS=["-Os"])
- env.Append(LINKFLAGS=["-Os"])
- elif env["target"] == "release_debug":
- env.Append(CCFLAGS=["-Os"])
- env.Append(LINKFLAGS=["-Os"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
- # Retain function names for backtraces at the cost of file size.
- env.Append(LINKFLAGS=["--profiling-funcs"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["-Os"])
+ env.Append(LINKFLAGS=["-Os"])
+
+ if env["target"] == "release_debug":
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ # Retain function names for backtraces at the cost of file size.
+ env.Append(LINKFLAGS=["--profiling-funcs"])
else: # "debug"
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(CCFLAGS=["-O1", "-g"])
@@ -92,11 +92,12 @@ def configure(env):
if not env["threads_enabled"]:
print("Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option")
sys.exit(255)
- if env["initial_memory"] < 32:
- print("Editor build requires at least 32MiB of initial memory. Forcing it.")
- env["initial_memory"] = 32
- elif env["builtin_icu"]:
+ if env["initial_memory"] < 64:
+ print("Editor build requires at least 64MiB of initial memory. Forcing it.")
+ env["initial_memory"] = 64
env.Append(CCFLAGS=["-frtti"])
+ elif env["builtin_icu"]:
+ env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.
@@ -147,12 +148,12 @@ def configure(env):
env.AddMethod(add_js_pre, "AddJSPre")
env.AddMethod(add_js_externs, "AddJSExterns")
- # Add method for getting build version string.
- env.AddMethod(get_build_version, "GetBuildVersion")
-
# Add method that joins/compiles our Engine files.
env.AddMethod(create_engine_file, "CreateEngineFile")
+ # Add method for creating the final zip file
+ env.AddMethod(create_template_zip, "CreateTemplateZip")
+
# Closure compiler extern and support for ecmascript specs (const, let, etc).
env["ENV"]["EMCC_CLOSURE_ARGS"] = "--language_in ECMASCRIPT6"
@@ -174,7 +175,7 @@ def configure(env):
# Program() output consists of multiple files, so specify suffixes manually at builder.
env["PROGSUFFIX"] = ""
env["LIBPREFIX"] = "lib"
- env["LIBSUFFIX"] = ".bc"
+ env["LIBSUFFIX"] = ".a"
env["LIBPREFIXES"] = ["$LIBPREFIX"]
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
@@ -228,8 +229,16 @@ def configure(env):
# Allow use to take control of swapping WebGL buffers.
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
- # callMain for manual start.
- env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"])
+ # callMain for manual start, cwrap for the mono version.
+ env.Append(LINKFLAGS=["-s", "EXPORTED_RUNTIME_METHODS=['callMain','cwrap']"])
# Add code that allow exiting runtime.
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
+
+ # TODO remove once we have GLES support back (temporary fix undefined symbols due to dead code elimination).
+ env.Append(
+ LINKFLAGS=[
+ "-s",
+ "EXPORTED_FUNCTIONS=['_main', '_emscripten_webgl_get_current_context']",
+ ]
+ )
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index cfe093693f..0031650360 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -59,34 +59,13 @@ bool DisplayServerJavaScript::is_canvas_focused() {
}
bool DisplayServerJavaScript::check_size_force_redraw() {
- int canvas_width;
- int canvas_height;
- emscripten_get_canvas_element_size(DisplayServerJavaScript::canvas_id, &canvas_width, &canvas_height);
- if (last_width != canvas_width || last_height != canvas_height) {
- last_width = canvas_width;
- last_height = canvas_height;
- // Update the framebuffer size for redraw.
- emscripten_set_canvas_element_size(DisplayServerJavaScript::canvas_id, canvas_width, canvas_height);
- return true;
- }
- return false;
+ return godot_js_display_size_update() != 0;
}
Point2 DisplayServerJavaScript::compute_position_in_canvas(int p_x, int p_y) {
- DisplayServerJavaScript *display = get_singleton();
- int canvas_x;
- int canvas_y;
- godot_js_display_canvas_bounding_rect_position_get(&canvas_x, &canvas_y);
- int canvas_width;
- int canvas_height;
- emscripten_get_canvas_element_size(display->canvas_id, &canvas_width, &canvas_height);
-
- double element_width;
- double element_height;
- emscripten_get_element_css_size(display->canvas_id, &element_width, &element_height);
-
- return Point2((int)(canvas_width / element_width * (p_x - canvas_x)),
- (int)(canvas_height / element_height * (p_y - canvas_y)));
+ int point[2];
+ godot_js_display_compute_position(p_x, p_y, point, point + 1);
+ return Point2(point[0], point[1]);
}
EM_BOOL DisplayServerJavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) {
@@ -210,19 +189,19 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E
switch (p_event->button) {
case DOM_BUTTON_LEFT:
- ev->set_button_index(BUTTON_LEFT);
+ ev->set_button_index(MOUSE_BUTTON_LEFT);
break;
case DOM_BUTTON_MIDDLE:
- ev->set_button_index(BUTTON_MIDDLE);
+ ev->set_button_index(MOUSE_BUTTON_MIDDLE);
break;
case DOM_BUTTON_RIGHT:
- ev->set_button_index(BUTTON_RIGHT);
+ ev->set_button_index(MOUSE_BUTTON_RIGHT);
break;
case DOM_BUTTON_XBUTTON1:
- ev->set_button_index(BUTTON_XBUTTON1);
+ ev->set_button_index(MOUSE_BUTTON_XBUTTON1);
break;
case DOM_BUTTON_XBUTTON2:
- ev->set_button_index(BUTTON_XBUTTON2);
+ ev->set_button_index(MOUSE_BUTTON_XBUTTON2);
break;
default:
return false;
@@ -362,7 +341,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -385,7 +364,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -420,7 +399,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), png.ptr(), len, p_hotspot.x, p_hotspot.y);
} else {
- godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), NULL, 0, 0, 0);
+ godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), nullptr, 0, 0, 0);
}
cursor_set_shape(cursor_shape);
@@ -482,13 +461,13 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript
ev->set_metakey(input->is_key_pressed(KEY_META));
if (p_event->deltaY < 0)
- ev->set_button_index(BUTTON_WHEEL_UP);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_UP);
else if (p_event->deltaY > 0)
- ev->set_button_index(BUTTON_WHEEL_DOWN);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
else if (p_event->deltaX > 0)
- ev->set_button_index(BUTTON_WHEEL_LEFT);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
else if (p_event->deltaX < 0)
- ev->set_button_index(BUTTON_WHEEL_RIGHT);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
else
return false;
@@ -557,6 +536,43 @@ bool DisplayServerJavaScript::screen_is_touchscreen(int p_screen) const {
return godot_js_display_touchscreen_is_available();
}
+// Virtual Keybaord
+void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_cursor) {
+ DisplayServerJavaScript *ds = DisplayServerJavaScript::get_singleton();
+ if (!ds || ds->input_text_callback.is_null()) {
+ return;
+ }
+ // Call input_text
+ Variant event = String(p_text);
+ Variant *eventp = &event;
+ Variant ret;
+ Callable::CallError ce;
+ ds->input_text_callback.call((const Variant **)&eventp, 1, ret, ce);
+ // Insert key right to reach position.
+ Input *input = Input::get_singleton();
+ Ref<InputEventKey> k;
+ for (int i = 0; i < p_cursor; i++) {
+ k.instance();
+ k->set_pressed(true);
+ k->set_echo(false);
+ k->set_keycode(KEY_RIGHT);
+ input->parse_input_event(k);
+ k.instance();
+ k->set_pressed(false);
+ k->set_echo(false);
+ k->set_keycode(KEY_RIGHT);
+ input->parse_input_event(k);
+ }
+}
+
+void DisplayServerJavaScript::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_multiline, p_cursor_start, p_cursor_end);
+}
+
+void DisplayServerJavaScript::virtual_keyboard_hide() {
+ godot_js_display_vk_hide();
+}
+
// Gamepad
void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) {
Input *input = Input::get_singleton();
@@ -585,7 +601,7 @@ void DisplayServerJavaScript::process_joypads() {
// Buttons 6 and 7 in the standard mapping need to be
// axis to be handled as JOY_AXIS_TRIGGER by Godot.
if (s_standard && (b == 6 || b == 7)) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = 0;
joy_axis.value = value;
int a = b == 6 ? JOY_AXIS_TRIGGER_LEFT : JOY_AXIS_TRIGGER_RIGHT;
@@ -595,7 +611,7 @@ void DisplayServerJavaScript::process_joypads() {
}
}
for (int a = 0; a < s_axes_num; a++) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = -1;
joy_axis.value = s_axes[a];
input->joy_axis(idx, a, joy_axis);
@@ -703,6 +719,9 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
// Ensure the canvas ID.
godot_js_config_canvas_id_get(canvas_id, 256);
+ // Handle contextmenu, webglcontextlost
+ godot_js_display_setup_canvas(p_resolution.x, p_resolution.y, p_mode == WINDOW_MODE_FULLSCREEN, OS::get_singleton()->is_hidpi_allowed() ? 1 : 0);
+
// Check if it's windows.
swap_cancel_ok = godot_js_display_is_swap_ok_cancel() == 1;
@@ -745,11 +764,6 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
video_driver_index = p_video_driver;
#endif
- window_set_mode(p_mode);
- if (godot_js_config_is_resize_on_start()) {
- window_set_size(p_resolution);
- }
-
EMSCRIPTEN_RESULT result;
#define EM_CHECK(ev) \
if (result != EMSCRIPTEN_RESULT_SUCCESS) \
@@ -757,8 +771,8 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
#define SET_EM_CALLBACK(target, ev, cb) \
result = emscripten_set_##ev##_callback(target, nullptr, true, &cb); \
EM_CHECK(ev)
-#define SET_EM_WINDOW_CALLBACK(ev, cb) \
- result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, &cb); \
+#define SET_EM_WINDOW_CALLBACK(ev, cb) \
+ result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, false, &cb); \
EM_CHECK(ev)
// These callbacks from Emscripten's html5.h suffice to access most
// JavaScript APIs.
@@ -787,6 +801,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
godot_js_display_paste_cb(update_clipboard_callback);
godot_js_display_drop_files_cb(drop_files_js_callback);
godot_js_display_gamepad_cb(&DisplayServerJavaScript::gamepad_callback);
+ godot_js_display_vk_cb(&vk_input_text_callback);
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_event);
}
@@ -816,7 +831,8 @@ bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
//case FEATURE_WINDOW_TRANSPARENCY:
//case FEATURE_KEEP_SCREEN_ON:
//case FEATURE_ORIENTATION:
- //case FEATURE_VIRTUAL_KEYBOARD:
+ case FEATURE_VIRTUAL_KEYBOARD:
+ return godot_js_display_vk_available() != 0;
default:
return false;
}
@@ -839,20 +855,23 @@ Point2i DisplayServerJavaScript::screen_get_position(int p_screen) const {
}
Size2i DisplayServerJavaScript::screen_get_size(int p_screen) const {
- EmscriptenFullscreenChangeEvent ev;
- EMSCRIPTEN_RESULT result = emscripten_get_fullscreen_status(&ev);
- ERR_FAIL_COND_V(result != EMSCRIPTEN_RESULT_SUCCESS, Size2i());
- return Size2i(ev.screenWidth, ev.screenHeight);
+ int size[2];
+ godot_js_display_screen_size_get(size, size + 1);
+ return Size2(size[0], size[1]);
}
Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const {
- int canvas[2];
- emscripten_get_canvas_element_size(canvas_id, canvas, canvas + 1);
- return Rect2i(0, 0, canvas[0], canvas[1]);
+ int size[2];
+ godot_js_display_window_size_get(size, size + 1);
+ return Rect2i(0, 0, size[0], size[1]);
}
int DisplayServerJavaScript::screen_get_dpi(int p_screen) const {
- return 96; // TODO maybe check pixel ratio via window.devicePixelRatio * 96? Inexact.
+ return godot_js_display_screen_dpi_get();
+}
+
+float DisplayServerJavaScript::screen_get_scale(int p_screen) const {
+ return godot_js_display_pixel_ratio_get();
}
Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const {
@@ -886,7 +905,7 @@ void DisplayServerJavaScript::window_set_input_event_callback(const Callable &p_
}
void DisplayServerJavaScript::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
- input_text_callback = p_callable; // TODO unused... do I need this?
+ input_text_callback = p_callable;
}
void DisplayServerJavaScript::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
@@ -934,17 +953,13 @@ Size2i DisplayServerJavaScript::window_get_min_size(WindowID p_window) const {
}
void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_window) {
- last_width = p_size.x;
- last_height = p_size.y;
- double scale = godot_js_display_pixel_ratio_get();
- emscripten_set_canvas_element_size(canvas_id, p_size.x, p_size.y);
- emscripten_set_element_css_size(canvas_id, p_size.x / scale, p_size.y / scale);
+ godot_js_display_desired_size_set(p_size.x, p_size.y);
}
Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const {
- int canvas[2];
- emscripten_get_canvas_element_size(canvas_id, canvas, canvas + 1);
- return Size2(canvas[0], canvas[1]);
+ int size[2];
+ godot_js_display_window_size_get(size, size + 1);
+ return Size2i(size[0], size[1]);
}
Size2i DisplayServerJavaScript::window_get_real_size(WindowID p_window) const {
@@ -958,20 +973,13 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind
switch (p_mode) {
case WINDOW_MODE_WINDOWED: {
if (window_mode == WINDOW_MODE_FULLSCREEN) {
- emscripten_exit_fullscreen();
+ godot_js_display_fullscreen_exit();
}
window_mode = WINDOW_MODE_WINDOWED;
- window_set_size(Size2i(last_width, last_height));
} break;
case WINDOW_MODE_FULLSCREEN: {
- EmscriptenFullscreenStrategy strategy;
- strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
- strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
- strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
- strategy.canvasResizedCallback = nullptr;
- EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(canvas_id, false, &strategy);
- ERR_FAIL_COND_MSG(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED, "Enabling fullscreen is only possible from an input callback for the HTML5 platform.");
- ERR_FAIL_COND_MSG(result != EMSCRIPTEN_RESULT_SUCCESS, "Enabling fullscreen is only possible from an input callback for the HTML5 platform.");
+ int result = godot_js_display_fullscreen_request();
+ ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform.");
} break;
case WINDOW_MODE_MAXIMIZED:
case WINDOW_MODE_MINIMIZED:
diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h
index e28fbc56f3..ece38f1a95 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/javascript/display_server_javascript.h
@@ -57,9 +57,6 @@ private:
double last_click_ms = 0;
int last_click_button_index = -1;
- int last_width = 0;
- int last_height = 0;
-
bool swap_cancel_ok = false;
// utilities
@@ -78,6 +75,8 @@ private:
static EM_BOOL keypress_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
static EM_BOOL keyup_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data);
+ static void vk_input_text_callback(const char *p_text, int p_cursor);
+
static EM_BOOL mousemove_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
static EM_BOOL mouse_button_callback(int p_event_type, const EmscriptenMouseEvent *p_event, void *p_user_data);
@@ -136,6 +135,10 @@ public:
Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+ float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+
+ void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
+ void virtual_keyboard_hide() override;
// windows
Vector<DisplayServer::WindowID> get_window_list() const override;
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index d08555916b..ab98838e20 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -1,4 +1,4 @@
-import os
+import os, json
from SCons.Util import WhereIs
@@ -15,13 +15,17 @@ def run_closure_compiler(target, source, env, for_signature):
return " ".join(cmd)
-def get_build_version(env):
+def get_build_version():
import version
name = "custom_build"
if os.getenv("BUILD_NAME") != None:
name = os.getenv("BUILD_NAME")
- return "%d.%d.%d.%s.%s" % (version.major, version.minor, version.patch, version.status, name)
+ v = "%d.%d" % (version.major, version.minor)
+ if version.patch > 0:
+ v += ".%d" % version.patch
+ v += ".%s.%s" % (version.status, name)
+ return v
def create_engine_file(env, target, source, externs):
@@ -30,6 +34,85 @@ def create_engine_file(env, target, source, externs):
return env.Textfile(target, [env.File(s) for s in source])
+def create_template_zip(env, js, wasm, extra):
+ binary_name = "godot.tools" if env["tools"] else "godot"
+ zip_dir = env.Dir("#bin/.javascript_zip")
+ in_files = [
+ js,
+ wasm,
+ "#platform/javascript/js/libs/audio.worklet.js",
+ ]
+ out_files = [
+ zip_dir.File(binary_name + ".js"),
+ zip_dir.File(binary_name + ".wasm"),
+ zip_dir.File(binary_name + ".audio.worklet.js"),
+ ]
+ # GDNative/Threads specific
+ if env["gdnative_enabled"]:
+ in_files.append(extra) # Runtime
+ out_files.append(zip_dir.File(binary_name + ".side.wasm"))
+ elif env["threads_enabled"]:
+ in_files.append(extra) # Worker
+ out_files.append(zip_dir.File(binary_name + ".worker.js"))
+
+ service_worker = "#misc/dist/html/service-worker.js"
+ if env["tools"]:
+ # HTML
+ html = "#misc/dist/html/editor.html"
+ cache = [
+ "godot.tools.html",
+ "offline.html",
+ "godot.tools.js",
+ "godot.tools.worker.js",
+ "godot.tools.audio.worklet.js",
+ "logo.svg",
+ "favicon.png",
+ ]
+ opt_cache = ["godot.tools.wasm"]
+ subst_dict = {
+ "@GODOT_VERSION@": get_build_version(),
+ "@GODOT_NAME@": "GodotEngine",
+ "@GODOT_CACHE@": json.dumps(cache),
+ "@GODOT_OPT_CACHE@": json.dumps(opt_cache),
+ "@GODOT_OFFLINE_PAGE@": "offline.html",
+ }
+ html = env.Substfile(target="#bin/godot${PROGSUFFIX}.html", source=html, SUBST_DICT=subst_dict)
+ in_files.append(html)
+ out_files.append(zip_dir.File(binary_name + ".html"))
+ # And logo/favicon
+ in_files.append("#misc/dist/html/logo.svg")
+ out_files.append(zip_dir.File("logo.svg"))
+ in_files.append("#icon.png")
+ out_files.append(zip_dir.File("favicon.png"))
+ # PWA
+ service_worker = env.Substfile(
+ target="#bin/godot${PROGSUFFIX}.service.worker.js", source=service_worker, SUBST_DICT=subst_dict
+ )
+ in_files.append(service_worker)
+ out_files.append(zip_dir.File("service.worker.js"))
+ in_files.append("#misc/dist/html/manifest.json")
+ out_files.append(zip_dir.File("manifest.json"))
+ in_files.append("#misc/dist/html/offline.html")
+ out_files.append(zip_dir.File("offline.html"))
+ else:
+ # HTML
+ in_files.append("#misc/dist/html/full-size.html")
+ out_files.append(zip_dir.File(binary_name + ".html"))
+ in_files.append(service_worker)
+ out_files.append(zip_dir.File(binary_name + ".service.worker.js"))
+ in_files.append("#misc/dist/html/offline-export.html")
+ out_files.append(zip_dir.File("godot.offline.html"))
+
+ zip_files = env.InstallAs(out_files, in_files)
+ env.Zip(
+ "#bin/godot",
+ zip_files,
+ ZIPROOT=zip_dir,
+ ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
+ ZIPCOMSTR="Archiving $SOURCES as $TARGET",
+ )
+
+
def add_js_libraries(env, libraries):
env.Append(JS_LIBS=env.File(libraries))
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index f5d8a68994..14e279b45b 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -28,7 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "core/io/image_loader.h"
#include "core/io/json.h"
+#include "core/io/stream_peer_ssl.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
#include "editor/editor_export.h"
@@ -40,20 +42,55 @@
class EditorHTTPServer : public Reference {
private:
Ref<TCP_Server> server;
- Ref<StreamPeerTCP> connection;
+ Map<String, String> mimes;
+ Ref<StreamPeerTCP> tcp;
+ Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeer> peer;
+ Ref<CryptoKey> key;
+ Ref<X509Certificate> cert;
+ bool use_ssl = false;
uint64_t time = 0;
uint8_t req_buf[4096];
int req_pos = 0;
void _clear_client() {
- connection = Ref<StreamPeerTCP>();
+ peer = Ref<StreamPeer>();
+ ssl = Ref<StreamPeerSSL>();
+ tcp = Ref<StreamPeerTCP>();
memset(req_buf, 0, sizeof(req_buf));
time = 0;
req_pos = 0;
}
+ void _set_internal_certs(Ref<Crypto> p_crypto) {
+ const String cache_path = EditorSettings::get_singleton()->get_cache_dir();
+ const String key_path = cache_path.plus_file("html5_server.key");
+ const String crt_path = cache_path.plus_file("html5_server.crt");
+ bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
+ if (!regen) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ if (key->load(key_path) != OK || cert->load(crt_path) != OK) {
+ regen = true;
+ }
+ }
+ if (regen) {
+ key = p_crypto->generate_rsa(2048);
+ key->save(key_path);
+ cert = p_crypto->generate_self_signed_certificate(key, "CN=godot-debug.local,O=A Game Dev,C=XXA", "20140101000000", "20340101000000");
+ cert->save(crt_path);
+ }
+ }
+
public:
EditorHTTPServer() {
+ mimes["html"] = "text/html";
+ mimes["js"] = "application/javascript";
+ mimes["json"] = "application/json";
+ mimes["pck"] = "application/octet-stream";
+ mimes["png"] = "image/png";
+ mimes["svg"] = "image/svg";
+ mimes["wasm"] = "application/wasm";
server.instance();
stop();
}
@@ -63,7 +100,24 @@ public:
_clear_client();
}
- Error listen(int p_port, IP_Address p_address) {
+ Error listen(int p_port, IP_Address p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
+ use_ssl = p_use_ssl;
+ if (use_ssl) {
+ Ref<Crypto> crypto = Crypto::create();
+ if (crypto.is_null()) {
+ return ERR_UNAVAILABLE;
+ }
+ if (!p_ssl_key.is_empty() && !p_ssl_cert.is_empty()) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ Error err = key->load(p_ssl_key);
+ ERR_FAIL_COND_V(err != OK, err);
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ err = cert->load(p_ssl_cert);
+ ERR_FAIL_COND_V(err != OK, err);
+ } else {
+ _set_internal_certs(crypto);
+ }
+ }
return server->listen(p_port, p_address);
}
@@ -82,51 +136,21 @@ public:
// Wrong protocol
ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
- const String cache_path = EditorSettings::get_singleton()->get_cache_dir();
- const String basereq = "/tmp_js_export";
- String filepath;
- String ctype;
- if (req[1] == basereq + ".html") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "text/html";
- } else if (req[1] == basereq + ".js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".audio.worklet.js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".worker.js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".pck") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/octet-stream";
- } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") {
- // Also allow serving the generated favicon for a smoother loading experience.
- if (req[1] == "/favicon.png") {
- filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png");
- } else {
- filepath = basereq + ".png";
- }
- ctype = "image/png";
- } else if (req[1] == basereq + ".side.wasm") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/wasm";
- } else if (req[1] == basereq + ".wasm") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/wasm";
- } else if (req[1].ends_with(".wasm")) {
- filepath = cache_path.plus_file(req[1].get_file()); // TODO dangerous?
- ctype = "application/wasm";
- }
- if (filepath.is_empty() || !FileAccess::exists(filepath)) {
+ const String req_file = req[1].get_file();
+ const String req_ext = req[1].get_extension();
+ const String cache_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("web");
+ const String filepath = cache_path.plus_file(req_file);
+
+ if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
String s = "HTTP/1.1 404 Not Found\r\n";
s += "Connection: Close\r\n";
s += "\r\n";
CharString cs = s.utf8();
- connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
return;
}
+ const String ctype = mimes[req_ext];
+
FileAccess *f = FileAccess::open(filepath, FileAccess::READ);
ERR_FAIL_COND(!f);
String s = "HTTP/1.1 200 OK\r\n";
@@ -138,7 +162,7 @@ public:
s += "Cache-Control: no-store, max-age=0\r\n";
s += "\r\n";
CharString cs = s.utf8();
- Error err = connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
if (err != OK) {
memdelete(f);
ERR_FAIL();
@@ -150,7 +174,7 @@ public:
if (read < 1) {
break;
}
- err = connection->put_data(bytes, read);
+ err = peer->put_data(bytes, read);
if (err != OK) {
memdelete(f);
ERR_FAIL();
@@ -163,21 +187,43 @@ public:
if (!server->is_listening()) {
return;
}
- if (connection.is_null()) {
+ if (tcp.is_null()) {
if (!server->is_connection_available()) {
return;
}
- connection = server->take_connection();
+ tcp = server->take_connection();
+ peer = tcp;
time = OS::get_singleton()->get_ticks_usec();
}
if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
_clear_client();
return;
}
- if (connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
return;
}
+ if (use_ssl) {
+ if (ssl.is_null()) {
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ peer = ssl;
+ ssl->set_blocking_handshake_enabled(false);
+ if (ssl->accept_stream(tcp, key, cert) != OK) {
+ _clear_client();
+ return;
+ }
+ }
+ ssl->poll();
+ if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ // Still handshaking, keep waiting.
+ return;
+ }
+ if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ _clear_client();
+ return;
+ }
+ }
+
while (true) {
char *r = (char *)req_buf;
int l = req_pos - 1;
@@ -189,7 +235,7 @@ public:
int read = 0;
ERR_FAIL_COND(req_pos >= 4096);
- Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
+ Error err = peer->get_partial_data(&req_buf[req_pos], 1, read);
if (err != OK) {
// Got an error
_clear_client();
@@ -242,7 +288,32 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
return name;
}
- void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects);
+ Ref<Image> _get_project_icon() const {
+ Ref<Image> icon;
+ icon.instance();
+ const String icon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
+ if (icon_path.is_empty() || ImageLoader::load_image(icon_path, icon) != OK) {
+ return EditorNode::get_singleton()->get_editor_theme()->get_icon("DefaultProjectIcon", "EditorIcons")->get_image();
+ }
+ return icon;
+ }
+
+ Ref<Image> _get_project_splash() const {
+ Ref<Image> splash;
+ splash.instance();
+ const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
+ if (splash_path.is_empty() || ImageLoader::load_image(splash_path, splash) != OK) {
+ return Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+ return splash;
+ }
+
+ Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa);
+ void _replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template);
+ void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
+ Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr);
+ Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
+ Error _write_or_error(const uint8_t *p_content, int p_len, String p_path);
static void _server_thread_poll(void *data);
@@ -281,45 +352,275 @@ public:
~EditorExportPlatformJavaScript();
};
-void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects) {
- String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size());
- String str_export;
- Vector<String> lines = str_template.split("\n");
- Vector<String> flags;
- String flags_json;
- gen_export_flags(flags, p_flags);
- flags_json = JSON::print(flags);
- String libs;
- for (int i = 0; i < p_shared_objects.size(); i++) {
- libs += "\"" + p_shared_objects[i].path.get_file() + "\",";
+Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
+
+ if (!pkg) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ if (unzGoToFirstFile(pkg) != UNZ_OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
+ unzClose(pkg);
+ return ERR_FILE_CORRUPT;
}
+ do {
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String file = fname;
+
+ // Skip service worker and offline page if not exporting pwa.
+ if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
+ continue;
+ }
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+ String dst = p_dir.plus_file(file.replace("godot", p_name));
+ FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
+ unzClose(pkg);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(data.ptr(), data.size());
+ memdelete(f);
+
+ } while (unzGoToNextFile(pkg) == UNZ_OK);
+ unzClose(pkg);
+ return OK;
+}
+
+Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
+ FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(p_content, p_size);
+ memdelete(f);
+ return OK;
+}
+
+void EditorExportPlatformJavaScript::_replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template) {
+ String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
+ String out;
+ Vector<String> lines = str_template.split("\n");
for (int i = 0; i < lines.size(); i++) {
String current_line = lines[i];
- current_line = current_line.replace("$GODOT_BASENAME", p_name);
- current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name"));
- current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
- current_line = current_line.replace("$GODOT_FULL_WINDOW", p_preset->get("html/full_window_size") ? "true" : "false");
- current_line = current_line.replace("$GODOT_GDNATIVE_LIBS", libs);
- current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false");
- current_line = current_line.replace("$GODOT_ARGS", flags_json);
- str_export += current_line + "\n";
- }
-
- CharString cs = str_export.utf8();
- p_html.resize(cs.length());
+ for (Map<String, String>::Element *E = p_replaces.front(); E; E = E->next()) {
+ current_line = current_line.replace(E->key(), E->get());
+ }
+ out += current_line + "\n";
+ }
+ CharString cs = out.utf8();
+ r_template.resize(cs.length());
for (int i = 0; i < cs.length(); i++) {
- p_html.write[i] = cs[i];
+ r_template.write[i] = cs[i];
}
}
+void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
+ // Engine.js config
+ Dictionary config;
+ Array libs;
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ libs.push_back(p_shared_objects[i].path.get_file());
+ }
+ Vector<String> flags;
+ gen_export_flags(flags, p_flags & (~DEBUG_FLAG_DUMB_CLIENT));
+ Array args;
+ for (int i = 0; i < flags.size(); i++) {
+ args.push_back(flags[i]);
+ }
+ config["canvasResizePolicy"] = p_preset->get("html/canvas_resize_policy");
+ config["experimentalVK"] = p_preset->get("html/experimental_virtual_keyboard");
+ config["gdnativeLibs"] = libs;
+ config["executable"] = p_name;
+ config["args"] = args;
+ config["fileSizes"] = p_file_sizes;
+
+ String head_include;
+ if (p_preset->get("html/export_icon")) {
+ head_include += "<link id='-gd-engine-icon' rel='icon' type='image/png' href='" + p_name + ".icon.png' />\n";
+ head_include += "<link rel='apple-touch-icon' href='" + p_name + ".apple-touch-icon.png'/>\n";
+ }
+ if (p_preset->get("progressive_web_app/enabled")) {
+ head_include += "<link rel='manifest' href='" + p_name + ".manifest.json'>\n";
+ head_include += "<script type='application/javascript'>window.addEventListener('load', () => {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('" +
+ p_name + ".service.worker.js');}});</script>\n";
+ }
+
+ // Replaces HTML string
+ const String str_config = JSON::print(config);
+ const String custom_head_include = p_preset->get("html/head_include");
+ Map<String, String> replaces;
+ replaces["$GODOT_URL"] = p_name + ".js";
+ replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
+ replaces["$GODOT_CONFIG"] = str_config;
+ _replace_strings(replaces, p_html);
+}
+
+Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
+ const String name = p_path.get_file().get_basename();
+ const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
+ const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
+
+ Ref<Image> icon;
+ if (!p_icon.is_empty()) {
+ icon.instance();
+ const Error err = ImageLoader::load_image(p_icon, icon);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
+ return err;
+ }
+ if (icon->get_width() != p_size || icon->get_height() != p_size) {
+ icon->resize(p_size, p_size);
+ }
+ } else {
+ icon = _get_project_icon();
+ icon->resize(p_size, p_size);
+ }
+ const Error err = icon->save_png(icon_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
+ return err;
+ }
+ Dictionary icon_dict;
+ icon_dict["sizes"] = vformat("%dx%d", p_size, p_size);
+ icon_dict["type"] = "image/png";
+ icon_dict["src"] = icon_name;
+ r_arr.push_back(icon_dict);
+ return err;
+}
+
+Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
+ // Service worker
+ const String dir = p_path.get_base_dir();
+ const String name = p_path.get_file().get_basename();
+ const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ Map<String, String> replaces;
+ replaces["@GODOT_VERSION@"] = "1";
+ replaces["@GODOT_NAME@"] = name;
+ replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html";
+ Array files;
+ replaces["@GODOT_OPT_CACHE@"] = JSON::print(files);
+ files.push_back(name + ".html");
+ files.push_back(name + ".js");
+ files.push_back(name + ".wasm");
+ files.push_back(name + ".pck");
+ files.push_back(name + ".offline.html");
+ if (p_preset->get("html/export_icon")) {
+ files.push_back(name + ".icon.png");
+ files.push_back(name + ".apple-touch-icon.png");
+ }
+ if (mode == EXPORT_MODE_THREADS) {
+ files.push_back(name + ".worker.js");
+ files.push_back(name + ".audio.worklet.js");
+ } else if (mode == EXPORT_MODE_GDNATIVE) {
+ files.push_back(name + ".side.wasm");
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ files.push_back(p_shared_objects[i].path.get_file());
+ }
+ }
+ replaces["@GODOT_CACHE@"] = JSON::print(files);
+
+ const String sw_path = dir.plus_file(name + ".service.worker.js");
+ Vector<uint8_t> sw;
+ {
+ FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
+ return ERR_FILE_CANT_READ;
+ }
+ sw.resize(f->get_len());
+ f->get_buffer(sw.ptrw(), sw.size());
+ memdelete(f);
+ f = nullptr;
+ }
+ _replace_strings(replaces, sw);
+ Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
+ if (err != OK) {
+ return err;
+ }
+
+ // Custom offline page
+ const String offline_page = p_preset->get("progressive_web_app/offline_page");
+ if (!offline_page.is_empty()) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String offline_dest = dir.plus_file(name + ".offline.html");
+ err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
+ return err;
+ }
+ }
+
+ // Manifest
+ const char *modes[4] = { "fullscreen", "standalone", "minimal-ui", "browser" };
+ const char *orientations[3] = { "any", "landscape", "portrait" };
+ const int display = CLAMP(int(p_preset->get("progressive_web_app/display")), 0, 4);
+ const int orientation = CLAMP(int(p_preset->get("progressive_web_app/orientation")), 0, 3);
+
+ Dictionary manifest;
+ String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ if (proj_name.is_empty()) {
+ proj_name = "Godot Game";
+ }
+ manifest["name"] = proj_name;
+ manifest["start_url"] = "./" + name + ".html";
+ manifest["display"] = String::utf8(modes[display]);
+ manifest["orientation"] = String::utf8(orientations[orientation]);
+ manifest["background_color"] = "#" + p_preset->get("progressive_web_app/background_color").operator Color().to_html(false);
+
+ Array icons_arr;
+ const String icon144_path = p_preset->get("progressive_web_app/icon_144x144");
+ err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
+ err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
+ err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ manifest["icons"] = icons_arr;
+
+ CharString cs = JSON::print(manifest).utf8();
+ err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
if (p_preset->get("vram_texture_compression/for_desktop")) {
r_features->push_back("s3tc");
}
if (p_preset->get("vram_texture_compression/for_mobile")) {
- String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
+ String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
if (driver == "GLES2") {
r_features->push_back("etc");
} else if (driver == "Vulkan") {
@@ -343,9 +644,19 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/export_icon"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/full_window_size"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "progressive_web_app/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/display", PROPERTY_HINT_ENUM, "Fullscreen,Standalone,Minimal Ui,Browser"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/orientation", PROPERTY_HINT_ENUM, "Any,Landscape,Portrait"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
}
String EditorExportPlatformJavaScript::get_name() const {
@@ -411,20 +722,25 @@ List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<Edi
Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
- String custom_debug = p_preset->get("custom_template/debug");
- String custom_release = p_preset->get("custom_template/release");
- String custom_html = p_preset->get("html/custom_html_shell");
+ const String custom_debug = p_preset->get("custom_template/debug");
+ const String custom_release = p_preset->get("custom_template/release");
+ const String custom_html = p_preset->get("html/custom_html_shell");
+ const bool export_icon = p_preset->get("html/export_icon");
+ const bool pwa = p_preset->get("progressive_web_app/enabled");
- String template_path = p_debug ? custom_debug : custom_release;
+ const String base_dir = p_path.get_base_dir();
+ const String base_path = p_path.get_basename();
+ const String base_name = p_path.get_file().get_basename();
+ // Find the correct template
+ String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges();
-
if (template_path == String()) {
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
template_path = find_export_template(_get_template_name(mode, p_debug));
}
- if (!DirAccess::exists(p_path.get_base_dir())) {
+ if (!DirAccess::exists(base_dir)) {
return ERR_FILE_BAD_PATH;
}
@@ -433,8 +749,9 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return ERR_FILE_NOT_FOUND;
}
+ // Export pck and shared objects
Vector<SharedObject> shared_objects;
- String pck_path = p_path.get_basename() + ".pck";
+ String pck_path = base_path + ".pck";
Error error = save_pack(p_preset, pck_path, &shared_objects);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
@@ -442,7 +759,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
- String dst = p_path.get_base_dir().plus_file(shared_objects[i].path.get_file());
+ String dst = base_dir.plus_file(shared_objects[i].path.get_file());
error = da->copy(shared_objects[i].path, dst);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
@@ -451,111 +768,54 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
}
memdelete(da);
+ da = nullptr;
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io);
-
- if (!pkg) {
- EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + template_path);
- return ERR_FILE_NOT_FOUND;
- }
-
- if (unzGoToFirstFile(pkg) != UNZ_OK) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + template_path);
- unzClose(pkg);
- return ERR_FILE_CORRUPT;
+ // Extract templates.
+ error = _extract_template(template_path, base_dir, base_name, pwa);
+ if (error) {
+ return error;
}
- do {
- //get filename
- unz_file_info info;
- char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- String file = fname;
-
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- //read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
- unzCloseCurrentFile(pkg);
-
- //write
-
- if (file == "godot.html") {
- if (!custom_html.is_empty()) {
- continue;
- }
- _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
- file = p_path.get_file();
-
- } else if (file == "godot.js") {
- file = p_path.get_file().get_basename() + ".js";
-
- } else if (file == "godot.worker.js") {
- file = p_path.get_file().get_basename() + ".worker.js";
-
- } else if (file == "godot.side.wasm") {
- file = p_path.get_file().get_basename() + ".side.wasm";
-
- } else if (file == "godot.audio.worklet.js") {
- file = p_path.get_file().get_basename() + ".audio.worklet.js";
-
- } else if (file == "godot.wasm") {
- file = p_path.get_file().get_basename() + ".wasm";
- }
-
- String dst = p_path.get_base_dir().plus_file(file);
- FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
- unzClose(pkg);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(data.ptr(), data.size());
- memdelete(f);
-
- } while (unzGoToNextFile(pkg) == UNZ_OK);
- unzClose(pkg);
-
- if (!custom_html.is_empty()) {
- FileAccess *f = FileAccess::open(custom_html, FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:") + "\n" + custom_html);
- return ERR_FILE_CANT_READ;
- }
- Vector<uint8_t> buf;
- buf.resize(f->get_len());
- f->get_buffer(buf.ptrw(), buf.size());
+ // Parse generated file sizes (pck and wasm, to help show a meaningful loading bar).
+ Dictionary file_sizes;
+ FileAccess *f = nullptr;
+ f = FileAccess::open(pck_path, FileAccess::READ);
+ if (f) {
+ file_sizes[pck_path.get_file()] = (uint64_t)f->get_len();
memdelete(f);
- _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects);
-
- f = FileAccess::open(p_path, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(buf.ptr(), buf.size());
+ f = nullptr;
+ }
+ f = FileAccess::open(base_path + ".wasm", FileAccess::READ);
+ if (f) {
+ file_sizes[base_name + ".wasm"] = (uint64_t)f->get_len();
memdelete(f);
+ f = nullptr;
}
- Ref<Image> splash;
- const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
- if (!splash_path.is_empty()) {
- splash.instance();
- const Error err = splash->load(splash_path);
- if (err) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:") + "\n" + splash_path + "\n" + TTR("Using default boot splash image."));
- splash.unref();
- }
+ // Read the HTML shell file (custom or from template).
+ const String html_path = custom_html.is_empty() ? base_path + ".html" : custom_html;
+ Vector<uint8_t> html;
+ f = FileAccess::open(html_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
+ return ERR_FILE_CANT_READ;
}
- if (splash.is_null()) {
- splash = Ref<Image>(memnew(Image(boot_splash_png)));
+ html.resize(f->get_len());
+ f->get_buffer(html.ptrw(), html.size());
+ memdelete(f);
+ f = nullptr;
+
+ // Generate HTML file with replaced strings.
+ _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
+ Error err = _write_or_error(html.ptr(), html.size(), p_path);
+ if (err != OK) {
+ return err;
}
- const String splash_png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png");
+ html.resize(0);
+
+ // Export splash (why?)
+ Ref<Image> splash = _get_project_splash();
+ const String splash_png_path = base_path + ".png";
if (splash->save_png(splash_png_path) != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
return ERR_FILE_CANT_WRITE;
@@ -563,22 +823,27 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
// Save a favicon that can be accessed without waiting for the project to finish loading.
// This way, the favicon can be displayed immediately when loading the page.
- Ref<Image> favicon;
- const String favicon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
- if (!favicon_path.is_empty()) {
- favicon.instance();
- const Error err = favicon->load(favicon_path);
- if (err) {
- favicon.unref();
- }
- }
-
- if (favicon.is_valid()) {
- const String favicon_png_path = p_path.get_base_dir().plus_file("favicon.png");
+ if (export_icon) {
+ Ref<Image> favicon = _get_project_icon();
+ const String favicon_png_path = base_path + ".icon.png";
if (favicon->save_png(favicon_png_path) != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
return ERR_FILE_CANT_WRITE;
}
+ favicon->resize(180, 180);
+ const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
+ if (favicon->save_png(apple_icon_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
+ // Generate the PWA worker and manifest
+ if (pwa) {
+ err = _build_pwa(p_preset, p_path, shared_objects);
+ if (err != OK) {
+ return err;
+ }
}
return OK;
@@ -623,19 +888,31 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
return OK;
}
- const String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
+ const String dest = EditorSettings::get_singleton()->get_cache_dir().plus_file("web");
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
+ return err;
+ }
+ }
+ const String basepath = dest.plus_file("tmp_js_export");
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
// Export generates several files, clean them up on failure.
DirAccess::remove_file_or_error(basepath + ".html");
+ DirAccess::remove_file_or_error(basepath + ".offline.html");
DirAccess::remove_file_or_error(basepath + ".js");
DirAccess::remove_file_or_error(basepath + ".worker.js");
DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
+ DirAccess::remove_file_or_error(basepath + ".service.worker.js");
DirAccess::remove_file_or_error(basepath + ".pck");
DirAccess::remove_file_or_error(basepath + ".png");
DirAccess::remove_file_or_error(basepath + ".side.wasm");
DirAccess::remove_file_or_error(basepath + ".wasm");
- DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"));
+ DirAccess::remove_file_or_error(basepath + ".icon.png");
+ DirAccess::remove_file_or_error(basepath + ".apple-touch-icon.png");
return err;
}
@@ -650,16 +927,23 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
}
ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
+ const bool use_ssl = EDITOR_GET("export/web/use_ssl");
+ const String ssl_key = EDITOR_GET("export/web/ssl_key");
+ const String ssl_cert = EDITOR_GET("export/web/ssl_certificate");
+
// Restart server.
{
MutexLock lock(server_lock);
server->stop();
- err = server->listen(bind_port, bind_ip);
+ err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
+ }
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
+ return err;
}
- ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to start HTTP server.");
- OS::get_singleton()->shell_open(String("http://" + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
+ OS::get_singleton()->shell_open(String((use_ssl ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
// FIXME: Find out how to clean up export files after running the successfully
// exported game. Might not be trivial.
return OK;
@@ -709,7 +993,12 @@ EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
void register_javascript_exporter() {
EDITOR_DEF("export/web/http_host", "localhost");
EDITOR_DEF("export/web/http_port", 8060);
+ EDITOR_DEF("export/web/use_ssl", false);
+ EDITOR_DEF("export/web/ssl_key", "");
+ EDITOR_DEF("export/web/ssl_certificate", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/web/http_port", PROPERTY_HINT_RANGE, "1,65535,1"));
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_key", PROPERTY_HINT_GLOBAL_FILE, "*.key"));
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem"));
Ref<EditorExportPlatformJavaScript> platform;
platform.instance();
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 0006848756..8927a83cb3 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -40,7 +40,6 @@ extern "C" {
// Config
extern void godot_js_config_locale_get(char *p_ptr, int p_ptr_max);
extern void godot_js_config_canvas_id_get(char *p_ptr, int p_ptr_max);
-extern int godot_js_config_is_resize_on_start();
// OS
extern void godot_js_os_finish_async(void (*p_callback)());
@@ -49,8 +48,10 @@ extern int godot_js_os_fs_is_persistent();
extern void godot_js_os_fs_sync(void (*p_callback)());
extern int godot_js_os_execute(const char *p_json);
extern void godot_js_os_shell_open(const char *p_uri);
+extern int godot_js_os_hw_concurrency_get();
// Display
+extern int godot_js_display_screen_dpi_get();
extern double godot_js_display_pixel_ratio_get();
extern void godot_js_display_alert(const char *p_text);
extern int godot_js_display_touchscreen_is_available();
@@ -59,12 +60,18 @@ extern int godot_js_display_is_swap_ok_cancel();
// Display canvas
extern void godot_js_display_canvas_focus();
extern int godot_js_display_canvas_is_focused();
-extern void godot_js_display_canvas_bounding_rect_position_get(int32_t *p_x, int32_t *p_y);
// Display window
-extern void godot_js_display_window_request_fullscreen();
+extern void godot_js_display_desired_size_set(int p_width, int p_height);
+extern int godot_js_display_size_update();
+extern void godot_js_display_window_size_get(int32_t *p_x, int32_t *p_y);
+extern void godot_js_display_screen_size_get(int32_t *p_x, int32_t *p_y);
+extern int godot_js_display_fullscreen_request();
+extern int godot_js_display_fullscreen_exit();
+extern void godot_js_display_compute_position(int p_x, int p_y, int32_t *r_x, int32_t *r_y);
extern void godot_js_display_window_title_set(const char *p_text);
extern void godot_js_display_window_icon_set(const uint8_t *p_ptr, int p_len);
+extern int godot_js_display_has_webgl(int p_version);
// Display clipboard
extern int godot_js_display_clipboard_set(const char *p_text);
@@ -86,6 +93,14 @@ extern int godot_js_display_gamepad_sample_get(int p_idx, float r_btns[16], int3
extern void godot_js_display_notification_cb(void (*p_callback)(int p_notification), int p_enter, int p_exit, int p_in, int p_out);
extern void godot_js_display_paste_cb(void (*p_callback)(const char *p_text));
extern void godot_js_display_drop_files_cb(void (*p_callback)(char **p_filev, int p_filec));
+extern void godot_js_display_setup_canvas(int p_width, int p_height, int p_fullscreen, int p_hidpi);
+
+// Display Virtual Keyboard
+extern int godot_js_display_vk_available();
+extern void godot_js_display_vk_cb(void (*p_input)(const char *p_text, int p_cursor));
+extern void godot_js_display_vk_show(const char *p_text, int p_multiline, int p_start, int p_end);
+extern void godot_js_display_vk_hide();
+
#ifdef __cplusplus
}
#endif
diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc
index 2ef1ad5b83..842a93fcba 100644
--- a/platform/javascript/http_client.h.inc
+++ b/platform/javascript/http_client.h.inc
@@ -30,24 +30,21 @@
// HTTPClient's additional private members in the javascript platform
-Error prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers);
+Error make_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len);
+static void _parse_headers(int p_len, const char **p_headers, void *p_ref);
-int xhr_id;
+int js_id = 0;
int read_limit = 4096;
-int response_read_offset = 0;
Status status = STATUS_DISCONNECTED;
String host;
int port = -1;
bool use_tls = false;
-String username;
-String password;
int polled_response_code = 0;
-String polled_response_header;
-PackedByteArray polled_response;
+Vector<String> response_headers;
+Vector<uint8_t> response_buffer;
#ifdef DEBUG_ENABLED
-bool has_polled = false;
uint64_t last_polling_frame = 0;
#endif
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
index c8c48dd582..a6cf4b0eb8 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/javascript/http_client_javascript.cpp
@@ -30,7 +30,38 @@
#include "core/io/http_client.h"
-#include "http_request.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stddef.h"
+
+typedef enum {
+ GODOT_JS_FETCH_STATE_REQUESTING = 0,
+ GODOT_JS_FETCH_STATE_BODY = 1,
+ GODOT_JS_FETCH_STATE_DONE = 2,
+ GODOT_JS_FETCH_STATE_ERROR = -1,
+} godot_js_fetch_state_t;
+
+extern int godot_js_fetch_create(const char *p_method, const char *p_url, const char **p_headers, int p_headers_len, const uint8_t *p_body, int p_body_len);
+extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_size, const char **p_headers, void *p_ref), void *p_ref);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+void HTTPClient::_parse_headers(int p_len, const char **p_headers, void *p_ref) {
+ HTTPClient *client = static_cast<HTTPClient *>(p_ref);
+ for (int i = 0; i < p_len; i++) {
+ client->response_headers.push_back(String::utf8(p_headers[i]));
+ }
+}
Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
close();
@@ -74,7 +105,7 @@ Ref<StreamPeer> HTTPClient::get_connection() const {
ERR_FAIL_V_MSG(REF(), "Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform.");
}
-Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers) {
+Error HTTPClient::make_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the HTML5 platform.");
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
@@ -83,37 +114,33 @@ Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Ve
ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
String url = (use_tls ? "https://" : "http://") + host + ":" + itos(port) + p_url;
- godot_xhr_reset(xhr_id);
- godot_xhr_open(xhr_id, _methods[p_method], url.utf8().get_data(),
- username.is_empty() ? nullptr : username.utf8().get_data(),
- password.is_empty() ? nullptr : password.utf8().get_data());
-
+ Vector<CharString> keeper;
+ Vector<const char *> c_strings;
for (int i = 0; i < p_headers.size(); i++) {
- int header_separator = p_headers[i].find(": ");
- ERR_FAIL_COND_V(header_separator < 0, ERR_INVALID_PARAMETER);
- godot_xhr_set_request_header(xhr_id,
- p_headers[i].left(header_separator).utf8().get_data(),
- p_headers[i].right(header_separator + 2).utf8().get_data());
+ keeper.push_back(p_headers[i].utf8());
+ c_strings.push_back(keeper[i].get_data());
+ }
+ if (js_id) {
+ godot_js_fetch_free(js_id);
}
- response_read_offset = 0;
+ js_id = godot_js_fetch_create(_methods[p_method], url.utf8().get_data(), c_strings.ptrw(), c_strings.size(), p_body, p_body_len);
status = STATUS_REQUESTING;
return OK;
}
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) {
- Error err = prepare_request(p_method, p_url, p_headers);
- if (err != OK)
- return err;
- godot_xhr_send_data(xhr_id, p_body.ptr(), p_body.size());
- return OK;
+ if (p_body.is_empty()) {
+ return make_request(p_method, p_url, p_headers, nullptr, 0);
+ }
+ return make_request(p_method, p_url, p_headers, p_body.ptr(), p_body.size());
}
Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
- Error err = prepare_request(p_method, p_url, p_headers);
- if (err != OK)
- return err;
- godot_xhr_send_string(xhr_id, p_body.utf8().get_data());
- return OK;
+ if (p_body.is_empty()) {
+ return make_request(p_method, p_url, p_headers, nullptr, 0);
+ }
+ const CharString cs = p_body.utf8();
+ return make_request(p_method, p_url, p_headers, (const uint8_t *)cs.get_data(), cs.size() - 1);
}
void HTTPClient::close() {
@@ -121,10 +148,13 @@ void HTTPClient::close() {
port = -1;
use_tls = false;
status = STATUS_DISCONNECTED;
- polled_response.resize(0);
polled_response_code = 0;
- polled_response_header = String();
- godot_xhr_reset(xhr_id);
+ response_headers.resize(0);
+ response_buffer.resize(0);
+ if (js_id) {
+ godot_js_fetch_free(js_id);
+ js_id = 0;
+ }
}
HTTPClient::Status HTTPClient::get_status() const {
@@ -132,12 +162,11 @@ HTTPClient::Status HTTPClient::get_status() const {
}
bool HTTPClient::has_response() const {
- return !polled_response_header.is_empty();
+ return response_headers.size() > 0;
}
bool HTTPClient::is_response_chunked() const {
- // TODO evaluate using moz-chunked-arraybuffer, fetch & ReadableStream
- return false;
+ return godot_js_fetch_is_chunked(js_id);
}
int HTTPClient::get_response_code() const {
@@ -145,36 +174,42 @@ int HTTPClient::get_response_code() const {
}
Error HTTPClient::get_response_headers(List<String> *r_response) {
- if (polled_response_header.is_empty())
+ if (!response_headers.size()) {
return ERR_INVALID_PARAMETER;
-
- Vector<String> header_lines = polled_response_header.split("\r\n", false);
- for (int i = 0; i < header_lines.size(); ++i) {
- r_response->push_back(header_lines[i]);
}
- polled_response_header = String();
+ for (int i = 0; i < response_headers.size(); i++) {
+ r_response->push_back(response_headers[i]);
+ }
+ response_headers.clear();
return OK;
}
int HTTPClient::get_response_body_length() const {
- return polled_response.size();
+ return godot_js_fetch_body_length_get(js_id);
}
PackedByteArray HTTPClient::read_response_body_chunk() {
ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray());
- int to_read = MIN(read_limit, polled_response.size() - response_read_offset);
- PackedByteArray chunk;
- chunk.resize(to_read);
- memcpy(chunk.ptrw(), polled_response.ptr() + response_read_offset, to_read);
- response_read_offset += to_read;
-
- if (response_read_offset == polled_response.size()) {
- status = STATUS_CONNECTED;
- polled_response.resize(0);
- godot_xhr_reset(xhr_id);
+ if (response_buffer.size() != read_limit) {
+ response_buffer.resize(read_limit);
+ }
+ int read = godot_js_fetch_read_chunk(js_id, response_buffer.ptrw(), read_limit);
+
+ // Check if the stream is over.
+ godot_js_fetch_state_t state = godot_js_fetch_state_get(js_id);
+ if (state == GODOT_JS_FETCH_STATE_DONE) {
+ status = STATUS_DISCONNECTED;
+ } else if (state != GODOT_JS_FETCH_STATE_BODY) {
+ status = STATUS_CONNECTION_ERROR;
}
+ PackedByteArray chunk;
+ if (!read) {
+ return chunk;
+ }
+ chunk.resize(read);
+ memcpy(chunk.ptrw(), response_buffer.ptr(), read);
return chunk;
}
@@ -208,48 +243,48 @@ Error HTTPClient::poll() {
return OK;
case STATUS_CONNECTED:
- case STATUS_BODY:
return OK;
+ case STATUS_BODY: {
+ godot_js_fetch_state_t state = godot_js_fetch_state_get(js_id);
+ if (state == GODOT_JS_FETCH_STATE_DONE) {
+ status = STATUS_DISCONNECTED;
+ } else if (state != GODOT_JS_FETCH_STATE_BODY) {
+ status = STATUS_CONNECTION_ERROR;
+ return ERR_CONNECTION_ERROR;
+ }
+ return OK;
+ }
+
case STATUS_CONNECTION_ERROR:
return ERR_CONNECTION_ERROR;
case STATUS_REQUESTING: {
#ifdef DEBUG_ENABLED
- if (!has_polled) {
- has_polled = true;
- } else {
- // forcing synchronous requests is not possible on the web
- if (last_polling_frame == Engine::get_singleton()->get_process_frames()) {
- WARN_PRINT("HTTPClient polled multiple times in one frame, "
- "but request cannot progress more than once per "
- "frame on the HTML5 platform.");
- }
+ // forcing synchronous requests is not possible on the web
+ if (last_polling_frame == Engine::get_singleton()->get_process_frames()) {
+ WARN_PRINT("HTTPClient polled multiple times in one frame, "
+ "but request cannot progress more than once per "
+ "frame on the HTML5 platform.");
}
last_polling_frame = Engine::get_singleton()->get_process_frames();
#endif
- polled_response_code = godot_xhr_get_status(xhr_id);
- if (godot_xhr_get_ready_state(xhr_id) != XHR_READY_STATE_DONE) {
+ polled_response_code = godot_js_fetch_http_status_get(js_id);
+ godot_js_fetch_state_t js_state = godot_js_fetch_state_get(js_id);
+ if (js_state == GODOT_JS_FETCH_STATE_REQUESTING) {
return OK;
- } else if (!polled_response_code) {
+ } else if (js_state == GODOT_JS_FETCH_STATE_ERROR) {
+ // Fetch is in error state.
+ status = STATUS_CONNECTION_ERROR;
+ return ERR_CONNECTION_ERROR;
+ }
+ if (godot_js_fetch_read_headers(js_id, &_parse_headers, this)) {
+ // Failed to parse headers.
status = STATUS_CONNECTION_ERROR;
return ERR_CONNECTION_ERROR;
}
-
status = STATUS_BODY;
-
- PackedByteArray bytes;
- int len = godot_xhr_get_response_headers_length(xhr_id);
- bytes.resize(len + 1);
-
- godot_xhr_get_response_headers(xhr_id, reinterpret_cast<char *>(bytes.ptrw()), len);
- bytes.ptrw()[len] = 0;
-
- polled_response_header = String::utf8(reinterpret_cast<const char *>(bytes.ptr()));
-
- polled_response.resize(godot_xhr_get_response_length(xhr_id));
- godot_xhr_get_response(xhr_id, polled_response.ptrw(), polled_response.size());
break;
}
@@ -260,9 +295,8 @@ Error HTTPClient::poll() {
}
HTTPClient::HTTPClient() {
- xhr_id = godot_xhr_new();
}
HTTPClient::~HTTPClient() {
- godot_xhr_free(xhr_id);
+ close();
}
diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h
deleted file mode 100644
index d32b2f265e..0000000000
--- a/platform/javascript/http_request.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*************************************************************************/
-/* http_request.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef HTTP_REQUEST_H
-#define HTTP_REQUEST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "stddef.h"
-
-typedef enum {
- XHR_READY_STATE_UNSENT = 0,
- XHR_READY_STATE_OPENED = 1,
- XHR_READY_STATE_HEADERS_RECEIVED = 2,
- XHR_READY_STATE_LOADING = 3,
- XHR_READY_STATE_DONE = 4,
-} godot_xhr_ready_state_t;
-
-extern int godot_xhr_new();
-extern void godot_xhr_reset(int p_xhr_id);
-extern void godot_xhr_free(int p_xhr_id);
-
-extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = nullptr, const char *p_password = nullptr);
-
-extern void godot_xhr_set_request_header(int p_xhr_id, const char *p_header, const char *p_value);
-
-extern void godot_xhr_send_null(int p_xhr_id);
-extern void godot_xhr_send_string(int p_xhr_id, const char *p_data);
-extern void godot_xhr_send_data(int p_xhr_id, const void *p_data, int p_len);
-extern void godot_xhr_abort(int p_xhr_id);
-
-/* this is an HTTPClient::ResponseCode, not ::Status */
-extern int godot_xhr_get_status(int p_xhr_id);
-extern godot_xhr_ready_state_t godot_xhr_get_ready_state(int p_xhr_id);
-
-extern int godot_xhr_get_response_headers_length(int p_xhr_id);
-extern void godot_xhr_get_response_headers(int p_xhr_id, char *r_dst, int p_len);
-
-extern int godot_xhr_get_response_length(int p_xhr_id);
-extern void godot_xhr_get_response(int p_xhr_id, void *r_dst, int p_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HTTP_REQUEST_H */
diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js
new file mode 100644
index 0000000000..6072782875
--- /dev/null
+++ b/platform/javascript/js/engine/config.js
@@ -0,0 +1,337 @@
+/**
+ * An object used to configure the Engine instance based on godot export options, and to override those in custom HTML
+ * templates if needed.
+ *
+ * @header Engine configuration
+ * @summary The Engine configuration object. This is just a typedef, create it like a regular object, e.g.:
+ *
+ * ``const MyConfig = { executable: 'godot', unloadAfterInit: false }``
+ *
+ * @typedef {Object} EngineConfig
+ */
+const EngineConfig = {}; // eslint-disable-line no-unused-vars
+
+/**
+ * @struct
+ * @constructor
+ * @ignore
+ */
+const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-vars
+ const cfg = /** @lends {InternalConfig.prototype} */ {
+ /**
+ * Whether the unload the engine automatically after the instance is initialized.
+ *
+ * @memberof EngineConfig
+ * @default
+ * @type {boolean}
+ */
+ unloadAfterInit: true,
+ /**
+ * The HTML DOM Canvas object to use.
+ *
+ * By default, the first canvas element in the document will be used is none is specified.
+ *
+ * @memberof EngineConfig
+ * @default
+ * @type {?HTMLCanvasElement}
+ */
+ canvas: null,
+ /**
+ * The name of the WASM file without the extension. (Set by Godot Editor export process).
+ *
+ * @memberof EngineConfig
+ * @default
+ * @type {string}
+ */
+ executable: '',
+ /**
+ * An alternative name for the game pck to load. The executable name is used otherwise.
+ *
+ * @memberof EngineConfig
+ * @default
+ * @type {?string}
+ */
+ mainPack: null,
+ /**
+ * Specify a language code to select the proper localization for the game.
+ *
+ * The browser locale will be used if none is specified. See complete list of
+ * :ref:`supported locales <doc_locales>`.
+ *
+ * @memberof EngineConfig
+ * @type {?string}
+ * @default
+ */
+ locale: null,
+ /**
+ * The canvas resize policy determines how the canvas should be resized by Godot.
+ *
+ * ``0`` means Godot won't do any resizing. This is useful if you want to control the canvas size from
+ * javascript code in your template.
+ *
+ * ``1`` means Godot will resize the canvas on start, and when changing window size via engine functions.
+ *
+ * ``2`` means Godot will adapt the canvas size to match the whole browser window.
+ *
+ * @memberof EngineConfig
+ * @type {number}
+ * @default
+ */
+ canvasResizePolicy: 2,
+ /**
+ * The arguments to be passed as command line arguments on startup.
+ *
+ * See :ref:`command line tutorial <doc_command_line_tutorial>`.
+ *
+ * **Note**: :js:meth:`startGame <Engine.prototype.startGame>` will always add the ``--main-pack`` argument.
+ *
+ * @memberof EngineConfig
+ * @type {Array<string>}
+ * @default
+ */
+ args: [],
+ /**
+ * When enabled, this will turn on experimental virtual keyboard support on mobile.
+ *
+ * @memberof EngineConfig
+ * @type {boolean}
+ * @default
+ */
+ experimentalVK: false,
+ /**
+ * @ignore
+ * @type {Array.<string>}
+ */
+ persistentPaths: ['/userfs'],
+ /**
+ * @ignore
+ * @type {boolean}
+ */
+ persistentDrops: false,
+ /**
+ * @ignore
+ * @type {Array.<string>}
+ */
+ gdnativeLibs: [],
+ /**
+ * @ignore
+ * @type {Array.<string>}
+ */
+ fileSizes: [],
+ /**
+ * A callback function for handling Godot's ``OS.execute`` calls.
+ *
+ * This is for example used in the Web Editor template to switch between project manager and editor, and for running the game.
+ *
+ * @callback EngineConfig.onExecute
+ * @param {string} path The path that Godot's wants executed.
+ * @param {Array.<string>} args The arguments of the "command" to execute.
+ */
+ /**
+ * @ignore
+ * @type {?function(string, Array.<string>)}
+ */
+ onExecute: null,
+ /**
+ * A callback function for being notified when the Godot instance quits.
+ *
+ * **Note**: This function will not be called if the engine crashes or become unresponsive.
+ *
+ * @callback EngineConfig.onExit
+ * @param {number} status_code The status code returned by Godot on exit.
+ */
+ /**
+ * @ignore
+ * @type {?function(number)}
+ */
+ onExit: null,
+ /**
+ * A callback function for displaying download progress.
+ *
+ * The function is called once per frame while downloading files, so the usage of ``requestAnimationFrame()``
+ * is not necessary.
+ *
+ * If the callback function receives a total amount of bytes as 0, this means that it is impossible to calculate.
+ * Possible reasons include:
+ *
+ * - Files are delivered with server-side chunked compression
+ * - Files are delivered with server-side compression on Chromium
+ * - Not all file downloads have started yet (usually on servers without multi-threading)
+ *
+ * @callback EngineConfig.onProgress
+ * @param {number} current The current amount of downloaded bytes so far.
+ * @param {number} total The total amount of bytes to be downloaded.
+ */
+ /**
+ * @ignore
+ * @type {?function(number, number)}
+ */
+ onProgress: null,
+ /**
+ * A callback function for handling the standard output stream. This method should usually only be used in debug pages.
+ *
+ * By default, ``console.log()`` is used.
+ *
+ * @callback EngineConfig.onPrint
+ * @param {...*} [var_args] A variadic number of arguments to be printed.
+ */
+ /**
+ * @ignore
+ * @type {?function(...*)}
+ */
+ onPrint: function () {
+ console.log.apply(console, Array.from(arguments)); // eslint-disable-line no-console
+ },
+ /**
+ * A callback function for handling the standard error stream. This method should usually only be used in debug pages.
+ *
+ * By default, ``console.error()`` is used.
+ *
+ * @callback EngineConfig.onPrintError
+ * @param {...*} [var_args] A variadic number of arguments to be printed as errors.
+ */
+ /**
+ * @ignore
+ * @type {?function(...*)}
+ */
+ onPrintError: function (var_args) {
+ console.error.apply(console, Array.from(arguments)); // eslint-disable-line no-console
+ },
+ };
+
+ /**
+ * @ignore
+ * @struct
+ * @constructor
+ * @param {EngineConfig} opts
+ */
+ function Config(opts) {
+ this.update(opts);
+ }
+
+ Config.prototype = cfg;
+
+ /**
+ * @ignore
+ * @param {EngineConfig} opts
+ */
+ Config.prototype.update = function (opts) {
+ const config = opts || {};
+ function parse(key, def) {
+ if (typeof (config[key]) === 'undefined') {
+ return def;
+ }
+ return config[key];
+ }
+ // Module config
+ this.unloadAfterInit = parse('unloadAfterInit', this.unloadAfterInit);
+ this.onPrintError = parse('onPrintError', this.onPrintError);
+ this.onPrint = parse('onPrint', this.onPrint);
+ this.onProgress = parse('onProgress', this.onProgress);
+
+ // Godot config
+ this.canvas = parse('canvas', this.canvas);
+ this.executable = parse('executable', this.executable);
+ this.mainPack = parse('mainPack', this.mainPack);
+ this.locale = parse('locale', this.locale);
+ this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy);
+ this.persistentPaths = parse('persistentPaths', this.persistentPaths);
+ this.persistentDrops = parse('persistentDrops', this.persistentDrops);
+ this.experimentalVK = parse('experimentalVK', this.experimentalVK);
+ this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs);
+ this.fileSizes = parse('fileSizes', this.fileSizes);
+ this.args = parse('args', this.args);
+ this.onExecute = parse('onExecute', this.onExecute);
+ this.onExit = parse('onExit', this.onExit);
+ };
+
+ /**
+ * @ignore
+ * @param {string} loadPath
+ * @param {Response} response
+ */
+ Config.prototype.getModuleConfig = function (loadPath, response) {
+ let r = response;
+ return {
+ 'print': this.onPrint,
+ 'printErr': this.onPrintError,
+ 'thisProgram': this.executable,
+ 'noExitRuntime': true,
+ 'dynamicLibraries': [`${loadPath}.side.wasm`],
+ 'instantiateWasm': function (imports, onSuccess) {
+ function done(result) {
+ onSuccess(result['instance'], result['module']);
+ }
+ if (typeof (WebAssembly.instantiateStreaming) !== 'undefined') {
+ WebAssembly.instantiateStreaming(Promise.resolve(r), imports).then(done);
+ } else {
+ r.arrayBuffer().then(function (buffer) {
+ WebAssembly.instantiate(buffer, imports).then(done);
+ });
+ }
+ r = null;
+ return {};
+ },
+ 'locateFile': function (path) {
+ if (path.endsWith('.worker.js')) {
+ return `${loadPath}.worker.js`;
+ } else if (path.endsWith('.audio.worklet.js')) {
+ return `${loadPath}.audio.worklet.js`;
+ } else if (path.endsWith('.js')) {
+ return `${loadPath}.js`;
+ } else if (path.endsWith('.side.wasm')) {
+ return `${loadPath}.side.wasm`;
+ } else if (path.endsWith('.wasm')) {
+ return `${loadPath}.wasm`;
+ }
+ return path;
+ },
+ };
+ };
+
+ /**
+ * @ignore
+ * @param {function()} cleanup
+ */
+ Config.prototype.getGodotConfig = function (cleanup) {
+ // Try to find a canvas
+ if (!(this.canvas instanceof HTMLCanvasElement)) {
+ const nodes = document.getElementsByTagName('canvas');
+ if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
+ this.canvas = nodes[0];
+ }
+ if (!this.canvas) {
+ throw new Error('No canvas found in page');
+ }
+ }
+ // Canvas can grab focus on click, or key events won't work.
+ if (this.canvas.tabIndex < 0) {
+ this.canvas.tabIndex = 0;
+ }
+
+ // Browser locale, or custom one if defined.
+ let locale = this.locale;
+ if (!locale) {
+ locale = navigator.languages ? navigator.languages[0] : navigator.language;
+ locale = locale.split('.')[0];
+ }
+ const onExit = this.onExit;
+
+ // Godot configuration.
+ return {
+ 'canvas': this.canvas,
+ 'canvasResizePolicy': this.canvasResizePolicy,
+ 'locale': locale,
+ 'persistentDrops': this.persistentDrops,
+ 'virtualKeyboard': this.experimentalVK,
+ 'onExecute': this.onExecute,
+ 'onExit': function (p_code) {
+ cleanup(); // We always need to call the cleanup callback to free memory.
+ if (typeof (onExit) === 'function') {
+ onExit(p_code);
+ }
+ },
+ };
+ };
+ return new Config(initConfig);
+};
diff --git a/platform/javascript/js/engine/engine.externs.js b/platform/javascript/js/engine/engine.externs.js
index 1a94dd15ec..35a66a93ae 100644
--- a/platform/javascript/js/engine/engine.externs.js
+++ b/platform/javascript/js/engine/engine.externs.js
@@ -1,3 +1,4 @@
var Godot;
var WebAssembly = {};
WebAssembly.instantiate = function(buffer, imports) {};
+WebAssembly.instantiateStreaming = function(response, imports) {};
diff --git a/platform/javascript/js/engine/engine.js b/platform/javascript/js/engine/engine.js
index 01232cbece..17a8df9e29 100644
--- a/platform/javascript/js/engine/engine.js
+++ b/platform/javascript/js/engine/engine.js
@@ -1,291 +1,277 @@
+/**
+ * Projects exported for the Web expose the :js:class:`Engine` class to the JavaScript environment, that allows
+ * fine control over the engine's start-up process.
+ *
+ * This API is built in an asynchronous manner and requires basic understanding
+ * of `Promises <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises>`__.
+ *
+ * @module Engine
+ * @header HTML5 shell class reference
+ */
const Engine = (function () {
const preloader = new Preloader();
- let wasmExt = '.wasm';
- let unloadAfterInit = true;
- let loadPath = '';
let loadPromise = null;
+ let loadPath = '';
let initPromise = null;
- let stderr = null;
- let stdout = null;
- let progressFunc = null;
- function load(basePath) {
+ /**
+ * @classdesc The ``Engine`` class provides methods for loading and starting exported projects on the Web. For default export
+ * settings, this is already part of the exported HTML page. To understand practical use of the ``Engine`` class,
+ * see :ref:`Custom HTML page for Web export <doc_customizing_html5_shell>`.
+ *
+ * @description Create a new Engine instance with the given configuration.
+ *
+ * @global
+ * @constructor
+ * @param {EngineConfig} initConfig The initial config for this instance.
+ */
+ function Engine(initConfig) { // eslint-disable-line no-shadow
+ this.config = new InternalConfig(initConfig);
+ this.rtenv = null;
+ }
+
+ /**
+ * Load the engine from the specified base path.
+ *
+ * @param {string} basePath Base path of the engine to load.
+ * @param {number=} [size=0] The file size if known.
+ * @returns {Promise} A Promise that resolves once the engine is loaded.
+ *
+ * @function Engine.load
+ */
+ Engine.load = function (basePath, size) {
if (loadPromise == null) {
loadPath = basePath;
- loadPromise = preloader.loadPromise(basePath + wasmExt);
- preloader.setProgressFunc(progressFunc);
+ loadPromise = preloader.loadPromise(`${loadPath}.wasm`, size, true);
requestAnimationFrame(preloader.animateProgress);
}
return loadPromise;
- }
+ };
- function unload() {
+ /**
+ * Unload the engine to free memory.
+ *
+ * This method will be called automatically depending on the configuration. See :js:attr:`unloadAfterInit`.
+ *
+ * @function Engine.unload
+ */
+ Engine.unload = function () {
loadPromise = null;
- }
-
- /** @constructor */
- function Engine() { // eslint-disable-line no-shadow
- this.canvas = null;
- this.executableName = '';
- this.rtenv = null;
- this.customLocale = null;
- this.resizeCanvasOnStart = false;
- this.onExecute = null;
- this.onExit = null;
- this.persistentPaths = ['/userfs'];
- this.gdnativeLibs = [];
- }
-
- Engine.prototype.init = /** @param {string=} basePath */ function (basePath) {
- if (initPromise) {
- return initPromise;
- }
- if (loadPromise == null) {
- if (!basePath) {
- initPromise = Promise.reject(new Error('A base path must be provided when calling `init` and the engine is not loaded.'));
- return initPromise;
- }
- load(basePath);
- }
- let config = {};
- if (typeof stdout === 'function') {
- config.print = stdout;
- }
- if (typeof stderr === 'function') {
- config.printErr = stderr;
- }
- const me = this;
- initPromise = new Promise(function (resolve, reject) {
- config['locateFile'] = Utils.createLocateRewrite(loadPath);
- config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
- // Emscripten configuration.
- config['thisProgram'] = me.executableName;
- config['noExitRuntime'] = true;
- config['dynamicLibraries'] = [`${me.executableName}.side.wasm`].concat(me.gdnativeLibs);
- Godot(config).then(function (module) {
- module['initFS'](me.persistentPaths).then(function (fs_err) {
- me.rtenv = module;
- if (unloadAfterInit) {
- unload();
- }
- resolve();
- config = null;
- });
- });
- });
- return initPromise;
};
- /** @type {function(string, string):Object} */
- Engine.prototype.preloadFile = function (file, path) {
- return preloader.preload(file, path);
+ /**
+ * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for.
+ *
+ * @param {number=} [majorVersion=1] The major WebGL version to check for.
+ * @returns {boolean} If the given major version of WebGL is available.
+ * @function Engine.isWebGLAvailable
+ */
+ Engine.isWebGLAvailable = function (majorVersion = 1) {
+ try {
+ return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]);
+ } catch (e) { /* Not available */ }
+ return false;
};
- /** @type {function(...string):Object} */
- Engine.prototype.start = function () {
- // Start from arguments.
- const args = [];
- for (let i = 0; i < arguments.length; i++) {
- args.push(arguments[i]);
- }
- const me = this;
- return me.init().then(function () {
- if (!me.rtenv) {
- return Promise.reject(new Error('The engine must be initialized before it can be started'));
- }
-
- if (!(me.canvas instanceof HTMLCanvasElement)) {
- me.canvas = Utils.findCanvas();
- if (!me.canvas) {
- return Promise.reject(new Error('No canvas found in page'));
+ /**
+ * Safe Engine constructor, creates a new prototype for every new instance to avoid prototype pollution.
+ * @ignore
+ * @constructor
+ */
+ function SafeEngine(initConfig) {
+ const proto = /** @lends Engine.prototype */ {
+ /**
+ * Initialize the engine instance. Optionally, pass the base path to the engine to load it,
+ * if it hasn't been loaded yet. See :js:meth:`Engine.load`.
+ *
+ * @param {string=} basePath Base path of the engine to load.
+ * @return {Promise} A ``Promise`` that resolves once the engine is loaded and initialized.
+ */
+ init: function (basePath) {
+ if (initPromise) {
+ return initPromise;
}
- }
-
- // Canvas can grab focus on click, or key events won't work.
- if (me.canvas.tabIndex < 0) {
- me.canvas.tabIndex = 0;
- }
-
- // Disable right-click context menu.
- me.canvas.addEventListener('contextmenu', function (ev) {
- ev.preventDefault();
- }, false);
+ if (loadPromise == null) {
+ if (!basePath) {
+ initPromise = Promise.reject(new Error('A base path must be provided when calling `init` and the engine is not loaded.'));
+ return initPromise;
+ }
+ Engine.load(basePath, this.config.fileSizes[`${basePath}.wasm`]);
+ }
+ const me = this;
+ function doInit(promise) {
+ // Care! Promise chaining is bogus with old emscripten versions.
+ // This caused a regression with the Mono build (which uses an older emscripten version).
+ // Make sure to test that when refactoring.
+ return new Promise(function (resolve, reject) {
+ promise.then(function (response) {
+ const cloned = new Response(response.clone().body, { 'headers': [['content-type', 'application/wasm']] });
+ Godot(me.config.getModuleConfig(loadPath, cloned)).then(function (module) {
+ const paths = me.config.persistentPaths;
+ module['initFS'](paths).then(function (err) {
+ me.rtenv = module;
+ if (me.config.unloadAfterInit) {
+ Engine.unload();
+ }
+ resolve();
+ });
+ });
+ });
+ });
+ }
+ preloader.setProgressFunc(this.config.onProgress);
+ initPromise = doInit(loadPromise);
+ return initPromise;
+ },
- // Until context restoration is implemented warn the user of context loss.
- me.canvas.addEventListener('webglcontextlost', function (ev) {
- alert('WebGL context lost, please reload the page'); // eslint-disable-line no-alert
- ev.preventDefault();
- }, false);
+ /**
+ * Load a file so it is available in the instance's file system once it runs. Must be called **before** starting the
+ * instance.
+ *
+ * If not provided, the ``path`` is derived from the URL of the loaded file.
+ *
+ * @param {string|ArrayBuffer} file The file to preload.
+ *
+ * If a ``string`` the file will be loaded from that path.
+ *
+ * If an ``ArrayBuffer`` or a view on one, the buffer will used as the content of the file.
+ *
+ * @param {string=} path Path by which the file will be accessible. Required, if ``file`` is not a string.
+ *
+ * @returns {Promise} A Promise that resolves once the file is loaded.
+ */
+ preloadFile: function (file, path) {
+ return preloader.preload(file, path, this.config.fileSizes[file]);
+ },
- // Browser locale, or custom one if defined.
- let locale = me.customLocale;
- if (!locale) {
- locale = navigator.languages ? navigator.languages[0] : navigator.language;
- locale = locale.split('.')[0];
- }
- // Godot configuration.
- me.rtenv['initConfig']({
- 'resizeCanvasOnStart': me.resizeCanvasOnStart,
- 'canvas': me.canvas,
- 'locale': locale,
- 'onExecute': function (p_args) {
- if (me.onExecute) {
- me.onExecute(p_args);
- return 0;
+ /**
+ * Start the engine instance using the given override configuration (if any).
+ * :js:meth:`startGame <Engine.prototype.startGame>` can be used in typical cases instead.
+ *
+ * This will initialize the instance if it is not initialized. For manual initialization, see :js:meth:`init <Engine.prototype.init>`.
+ * The engine must be loaded beforehand.
+ *
+ * Fails if a canvas cannot be found on the page, or not specified in the configuration.
+ *
+ * @param {EngineConfig} override An optional configuration override.
+ * @return {Promise} Promise that resolves once the engine started.
+ */
+ start: function (override) {
+ this.config.update(override);
+ const me = this;
+ return me.init().then(function () {
+ if (!me.rtenv) {
+ return Promise.reject(new Error('The engine must be initialized before it can be started'));
}
- return 1;
- },
- 'onExit': function (p_code) {
- me.rtenv['deinitFS']();
- if (me.onExit) {
- me.onExit(p_code);
+
+ let config = {};
+ try {
+ config = me.config.getGodotConfig(function () {
+ me.rtenv = null;
+ });
+ } catch (e) {
+ return Promise.reject(e);
}
- me.rtenv = null;
- },
- });
+ // Godot configuration.
+ me.rtenv['initConfig'](config);
- return new Promise(function (resolve, reject) {
- preloader.preloadedFiles.forEach(function (file) {
- me.rtenv['copyToFS'](file.path, file.buffer);
+ // Preload GDNative libraries.
+ const libs = [];
+ me.config.gdnativeLibs.forEach(function (lib) {
+ libs.push(me.rtenv['loadDynamicLibrary'](lib, { 'loadAsync': true }));
+ });
+ return Promise.all(libs).then(function () {
+ return new Promise(function (resolve, reject) {
+ preloader.preloadedFiles.forEach(function (file) {
+ me.rtenv['copyToFS'](file.path, file.buffer);
+ });
+ preloader.preloadedFiles.length = 0; // Clear memory
+ me.rtenv['callMain'](me.config.args);
+ initPromise = null;
+ resolve();
+ });
+ });
});
- preloader.preloadedFiles.length = 0; // Clear memory
- me.rtenv['callMain'](args);
- initPromise = null;
- resolve();
- });
- });
- };
+ },
- Engine.prototype.startGame = function (execName, mainPack, extraArgs) {
- // Start and init with execName as loadPath if not inited.
- this.executableName = execName;
- const me = this;
- return Promise.all([
- this.init(execName),
- this.preloadFile(mainPack, mainPack),
- ]).then(function () {
- let args = ['--main-pack', mainPack];
- if (extraArgs) {
- args = args.concat(extraArgs);
- }
- return me.start.apply(me, args);
- });
- };
-
- Engine.prototype.setWebAssemblyFilenameExtension = function (override) {
- if (String(override).length === 0) {
- throw new Error('Invalid WebAssembly filename extension override');
- }
- wasmExt = String(override);
- };
-
- Engine.prototype.setUnloadAfterInit = function (enabled) {
- unloadAfterInit = enabled;
- };
-
- Engine.prototype.setCanvas = function (canvasElem) {
- this.canvas = canvasElem;
- };
-
- Engine.prototype.setCanvasResizedOnStart = function (enabled) {
- this.resizeCanvasOnStart = enabled;
- };
-
- Engine.prototype.setLocale = function (locale) {
- this.customLocale = locale;
- };
-
- Engine.prototype.setExecutableName = function (newName) {
- this.executableName = newName;
- };
-
- Engine.prototype.setProgressFunc = function (func) {
- progressFunc = func;
- };
+ /**
+ * Start the game instance using the given configuration override (if any).
+ *
+ * This will initialize the instance if it is not initialized. For manual initialization, see :js:meth:`init <Engine.prototype.init>`.
+ *
+ * This will load the engine if it is not loaded, and preload the main pck.
+ *
+ * This method expects the initial config (or the override) to have both the :js:attr:`executable` and :js:attr:`mainPack`
+ * properties set (normally done by the editor during export).
+ *
+ * @param {EngineConfig} override An optional configuration override.
+ * @return {Promise} Promise that resolves once the game started.
+ */
+ startGame: function (override) {
+ this.config.update(override);
+ // Add main-pack argument.
+ const exe = this.config.executable;
+ const pack = this.config.mainPack || `${exe}.pck`;
+ this.config.args = ['--main-pack', pack].concat(this.config.args);
+ // Start and init with execName as loadPath if not inited.
+ const me = this;
+ return Promise.all([
+ this.init(exe),
+ this.preloadFile(pack, pack),
+ ]).then(function () {
+ return me.start.apply(me);
+ });
+ },
- Engine.prototype.setStdoutFunc = function (func) {
- const print = function (text) {
- let msg = text;
- if (arguments.length > 1) {
- msg = Array.prototype.slice.call(arguments).join(' ');
- }
- func(msg);
- };
- if (this.rtenv) {
- this.rtenv.print = print;
- }
- stdout = print;
- };
+ /**
+ * Create a file at the specified ``path`` with the passed as ``buffer`` in the instance's file system.
+ *
+ * @param {string} path The location where the file will be created.
+ * @param {ArrayBuffer} buffer The content of the file.
+ */
+ copyToFS: function (path, buffer) {
+ if (this.rtenv == null) {
+ throw new Error('Engine must be inited before copying files');
+ }
+ this.rtenv['copyToFS'](path, buffer);
+ },
- Engine.prototype.setStderrFunc = function (func) {
- const printErr = function (text) {
- let msg = text;
- if (arguments.length > 1) {
- msg = Array.prototype.slice.call(arguments).join(' ');
- }
- func(msg);
+ /**
+ * Request that the current instance quit.
+ *
+ * This is akin the user pressing the close button in the window manager, and will
+ * have no effect if the engine has crashed, or is stuck in a loop.
+ *
+ */
+ requestQuit: function () {
+ if (this.rtenv) {
+ this.rtenv['request_quit']();
+ }
+ },
};
- if (this.rtenv) {
- this.rtenv.printErr = printErr;
- }
- stderr = printErr;
- };
-
- Engine.prototype.setOnExecute = function (onExecute) {
- this.onExecute = onExecute;
- };
-
- Engine.prototype.setOnExit = function (onExit) {
- this.onExit = onExit;
- };
-
- Engine.prototype.copyToFS = function (path, buffer) {
- if (this.rtenv == null) {
- throw new Error('Engine must be inited before copying files');
- }
- this.rtenv['copyToFS'](path, buffer);
- };
-
- Engine.prototype.setPersistentPaths = function (persistentPaths) {
- this.persistentPaths = persistentPaths;
- };
- Engine.prototype.setGDNativeLibraries = function (gdnativeLibs) {
- this.gdnativeLibs = gdnativeLibs;
- };
+ Engine.prototype = proto;
+ // Closure compiler exported instance methods.
+ Engine.prototype['init'] = Engine.prototype.init;
+ Engine.prototype['preloadFile'] = Engine.prototype.preloadFile;
+ Engine.prototype['start'] = Engine.prototype.start;
+ Engine.prototype['startGame'] = Engine.prototype.startGame;
+ Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
+ Engine.prototype['requestQuit'] = Engine.prototype.requestQuit;
+ // Also expose static methods as instance methods
+ Engine.prototype['load'] = Engine.load;
+ Engine.prototype['unload'] = Engine.unload;
+ Engine.prototype['isWebGLAvailable'] = Engine.isWebGLAvailable;
+ return new Engine(initConfig);
+ }
- Engine.prototype.requestQuit = function () {
- if (this.rtenv) {
- this.rtenv['request_quit']();
- }
- };
+ // Closure compiler exported static methods.
+ SafeEngine['load'] = Engine.load;
+ SafeEngine['unload'] = Engine.unload;
+ SafeEngine['isWebGLAvailable'] = Engine.isWebGLAvailable;
- // Closure compiler exported engine methods.
- /** @export */
- Engine['isWebGLAvailable'] = Utils.isWebGLAvailable;
- Engine['load'] = load;
- Engine['unload'] = unload;
- Engine.prototype['init'] = Engine.prototype.init;
- Engine.prototype['preloadFile'] = Engine.prototype.preloadFile;
- Engine.prototype['start'] = Engine.prototype.start;
- Engine.prototype['startGame'] = Engine.prototype.startGame;
- Engine.prototype['setWebAssemblyFilenameExtension'] = Engine.prototype.setWebAssemblyFilenameExtension;
- Engine.prototype['setUnloadAfterInit'] = Engine.prototype.setUnloadAfterInit;
- Engine.prototype['setCanvas'] = Engine.prototype.setCanvas;
- Engine.prototype['setCanvasResizedOnStart'] = Engine.prototype.setCanvasResizedOnStart;
- Engine.prototype['setLocale'] = Engine.prototype.setLocale;
- Engine.prototype['setExecutableName'] = Engine.prototype.setExecutableName;
- Engine.prototype['setProgressFunc'] = Engine.prototype.setProgressFunc;
- Engine.prototype['setStdoutFunc'] = Engine.prototype.setStdoutFunc;
- Engine.prototype['setStderrFunc'] = Engine.prototype.setStderrFunc;
- Engine.prototype['setOnExecute'] = Engine.prototype.setOnExecute;
- Engine.prototype['setOnExit'] = Engine.prototype.setOnExit;
- Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
- Engine.prototype['setPersistentPaths'] = Engine.prototype.setPersistentPaths;
- Engine.prototype['setGDNativeLibraries'] = Engine.prototype.setGDNativeLibraries;
- Engine.prototype['requestQuit'] = Engine.prototype.requestQuit;
- return Engine;
+ return SafeEngine;
}());
if (typeof window !== 'undefined') {
window['Engine'] = Engine;
diff --git a/platform/javascript/js/engine/preloader.js b/platform/javascript/js/engine/preloader.js
index ec34fb93f2..564c68d264 100644
--- a/platform/javascript/js/engine/preloader.js
+++ b/platform/javascript/js/engine/preloader.js
@@ -1,54 +1,62 @@
const Preloader = /** @constructor */ function () { // eslint-disable-line no-unused-vars
- const loadXHR = function (resolve, reject, file, tracker, attempts) {
- const xhr = new XMLHttpRequest();
+ function getTrackedResponse(response, load_status) {
+ function onloadprogress(reader, controller) {
+ return reader.read().then(function (result) {
+ if (load_status.done) {
+ return Promise.resolve();
+ }
+ if (result.value) {
+ controller.enqueue(result.value);
+ load_status.loaded += result.value.length;
+ }
+ if (!result.done) {
+ return onloadprogress(reader, controller);
+ }
+ load_status.done = true;
+ return Promise.resolve();
+ });
+ }
+ const reader = response.body.getReader();
+ return new Response(new ReadableStream({
+ start: function (controller) {
+ onloadprogress(reader, controller).then(function () {
+ controller.close();
+ });
+ },
+ }), { headers: response.headers });
+ }
+
+ function loadFetch(file, tracker, fileSize, raw) {
tracker[file] = {
- total: 0,
+ total: fileSize || 0,
loaded: 0,
- final: false,
+ done: false,
};
- xhr.onerror = function () {
+ return fetch(file).then(function (response) {
+ if (!response.ok) {
+ return Promise.reject(new Error(`Failed loading file '${file}'`));
+ }
+ const tr = getTrackedResponse(response, tracker[file]);
+ if (raw) {
+ return Promise.resolve(tr);
+ }
+ return tr.arrayBuffer();
+ });
+ }
+
+ function retry(func, attempts = 1) {
+ function onerror(err) {
if (attempts <= 1) {
- reject(new Error(`Failed loading file '${file}'`));
- } else {
+ return Promise.reject(err);
+ }
+ return new Promise(function (resolve, reject) {
setTimeout(function () {
- loadXHR(resolve, reject, file, tracker, attempts - 1);
+ retry(func, attempts - 1).then(resolve).catch(reject);
}, 1000);
- }
- };
- xhr.onabort = function () {
- tracker[file].final = true;
- reject(new Error(`Loading file '${file}' was aborted.`));
- };
- xhr.onloadstart = function (ev) {
- tracker[file].total = ev.total;
- tracker[file].loaded = ev.loaded;
- };
- xhr.onprogress = function (ev) {
- tracker[file].loaded = ev.loaded;
- tracker[file].total = ev.total;
- };
- xhr.onload = function () {
- if (xhr.status >= 400) {
- if (xhr.status < 500 || attempts <= 1) {
- reject(new Error(`Failed loading file '${file}': ${xhr.statusText}`));
- xhr.abort();
- } else {
- setTimeout(function () {
- loadXHR(resolve, reject, file, tracker, attempts - 1);
- }, 1000);
- }
- } else {
- tracker[file].final = true;
- resolve(xhr);
- }
- };
- // Make request.
- xhr.open('GET', file);
- if (!file.endsWith('.js')) {
- xhr.responseType = 'arraybuffer';
+ });
}
- xhr.send();
- };
+ return func().catch(onerror);
+ }
const DOWNLOAD_ATTEMPTS_MAX = 4;
const loadingFiles = {};
@@ -63,7 +71,7 @@ const Preloader = /** @constructor */ function () { // eslint-disable-line no-un
Object.keys(loadingFiles).forEach(function (file) {
const stat = loadingFiles[file];
- if (!stat.final) {
+ if (!stat.done) {
progressIsFinal = false;
}
if (!totalIsValid || stat.total === 0) {
@@ -92,21 +100,19 @@ const Preloader = /** @constructor */ function () { // eslint-disable-line no-un
progressFunc = callback;
};
- this.loadPromise = function (file) {
- return new Promise(function (resolve, reject) {
- loadXHR(resolve, reject, file, loadingFiles, DOWNLOAD_ATTEMPTS_MAX);
- });
+ this.loadPromise = function (file, fileSize, raw = false) {
+ return retry(loadFetch.bind(null, file, loadingFiles, fileSize, raw), DOWNLOAD_ATTEMPTS_MAX);
};
this.preloadedFiles = [];
- this.preload = function (pathOrBuffer, destPath) {
+ this.preload = function (pathOrBuffer, destPath, fileSize) {
let buffer = null;
if (typeof pathOrBuffer === 'string') {
const me = this;
- return this.loadPromise(pathOrBuffer).then(function (xhr) {
+ return this.loadPromise(pathOrBuffer, fileSize).then(function (buf) {
me.preloadedFiles.push({
path: destPath || pathOrBuffer,
- buffer: xhr.response,
+ buffer: buf,
});
return Promise.resolve();
});
diff --git a/platform/javascript/js/engine/utils.js b/platform/javascript/js/engine/utils.js
deleted file mode 100644
index 9273bbad42..0000000000
--- a/platform/javascript/js/engine/utils.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const Utils = { // eslint-disable-line no-unused-vars
-
- createLocateRewrite: function (execName) {
- function rw(path) {
- if (path.endsWith('.worker.js')) {
- return `${execName}.worker.js`;
- } else if (path.endsWith('.audio.worklet.js')) {
- return `${execName}.audio.worklet.js`;
- } else if (path.endsWith('.js')) {
- return `${execName}.js`;
- } else if (path.endsWith('.side.wasm')) {
- return `${execName}.side.wasm`;
- } else if (path.endsWith('.wasm')) {
- return `${execName}.wasm`;
- }
- return path;
- }
- return rw;
- },
-
- createInstantiatePromise: function (wasmLoader) {
- let loader = wasmLoader;
- function instantiateWasm(imports, onSuccess) {
- loader.then(function (xhr) {
- WebAssembly.instantiate(xhr.response, imports).then(function (result) {
- onSuccess(result['instance'], result['module']);
- });
- });
- loader = null;
- return {};
- }
-
- return instantiateWasm;
- },
-
- findCanvas: function () {
- const nodes = document.getElementsByTagName('canvas');
- if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
- return nodes[0];
- }
- return null;
- },
-
- isWebGLAvailable: function (majorVersion = 1) {
- let testContext = false;
- try {
- const testCanvas = document.createElement('canvas');
- if (majorVersion === 1) {
- testContext = testCanvas.getContext('webgl') || testCanvas.getContext('experimental-webgl');
- } else if (majorVersion === 2) {
- testContext = testCanvas.getContext('webgl2') || testCanvas.getContext('experimental-webgl2');
- }
- } catch (e) {
- // Not available
- }
- return !!testContext;
- },
-};
diff --git a/platform/javascript/js/jsdoc2rst/publish.js b/platform/javascript/js/jsdoc2rst/publish.js
new file mode 100644
index 0000000000..ad9c0fbaaa
--- /dev/null
+++ b/platform/javascript/js/jsdoc2rst/publish.js
@@ -0,0 +1,354 @@
+/* eslint-disable strict */
+
+'use strict';
+
+const fs = require('fs');
+
+class JSDoclet {
+ constructor(doc) {
+ this.doc = doc;
+ this.description = doc['description'] || '';
+ this.name = doc['name'] || 'unknown';
+ this.longname = doc['longname'] || '';
+ this.types = [];
+ if (doc['type'] && doc['type']['names']) {
+ this.types = doc['type']['names'].slice();
+ }
+ this.type = this.types.length > 0 ? this.types.join('\\|') : '*';
+ this.variable = doc['variable'] || false;
+ this.kind = doc['kind'] || '';
+ this.memberof = doc['memberof'] || null;
+ this.scope = doc['scope'] || '';
+ this.members = [];
+ this.optional = doc['optional'] || false;
+ this.defaultvalue = doc['defaultvalue'];
+ this.summary = doc['summary'] || null;
+ this.classdesc = doc['classdesc'] || null;
+
+ // Parameters (functions)
+ this.params = [];
+ this.returns = doc['returns'] ? doc['returns'][0]['type']['names'][0] : 'void';
+ this.returns_desc = doc['returns'] ? doc['returns'][0]['description'] : null;
+
+ this.params = (doc['params'] || []).slice().map((p) => new JSDoclet(p));
+
+ // Custom tags
+ this.tags = doc['tags'] || [];
+ this.header = this.tags.filter((t) => t['title'] === 'header').map((t) => t['text']).pop() || null;
+ }
+
+ add_member(obj) {
+ this.members.push(obj);
+ }
+
+ is_static() {
+ return this.scope === 'static';
+ }
+
+ is_instance() {
+ return this.scope === 'instance';
+ }
+
+ is_object() {
+ return this.kind === 'Object' || (this.kind === 'typedef' && this.type === 'Object');
+ }
+
+ is_class() {
+ return this.kind === 'class';
+ }
+
+ is_function() {
+ return this.kind === 'function' || (this.kind === 'typedef' && this.type === 'function');
+ }
+
+ is_module() {
+ return this.kind === 'module';
+ }
+}
+
+function format_table(f, data, depth = 0) {
+ if (!data.length) {
+ return;
+ }
+
+ const column_sizes = new Array(data[0].length).fill(0);
+
+ data.forEach((row) => {
+ row.forEach((e, idx) => {
+ column_sizes[idx] = Math.max(e.length, column_sizes[idx]);
+ });
+ });
+
+ const indent = ' '.repeat(depth);
+ let sep = indent;
+ column_sizes.forEach((size) => {
+ sep += '+';
+ sep += '-'.repeat(size + 2);
+ });
+ sep += '+\n';
+ f.write(sep);
+
+ data.forEach((row) => {
+ let row_text = `${indent}|`;
+ row.forEach((entry, idx) => {
+ row_text += ` ${entry.padEnd(column_sizes[idx])} |`;
+ });
+ row_text += '\n';
+ f.write(row_text);
+ f.write(sep);
+ });
+
+ f.write('\n');
+}
+
+function make_header(header, sep) {
+ return `${header}\n${sep.repeat(header.length)}\n\n`;
+}
+
+function indent_multiline(text, depth) {
+ const indent = ' '.repeat(depth);
+ return text.split('\n').map((l) => (l === '' ? l : indent + l)).join('\n');
+}
+
+function make_rst_signature(obj, types = false, style = false) {
+ let out = '';
+ const fmt = style ? '*' : '';
+ obj.params.forEach((arg, idx) => {
+ if (idx > 0) {
+ if (arg.optional) {
+ out += ` ${fmt}[`;
+ }
+ out += ', ';
+ } else {
+ out += ' ';
+ if (arg.optional) {
+ out += `${fmt}[ `;
+ }
+ }
+ if (types) {
+ out += `${arg.type} `;
+ }
+ const variable = arg.variable ? '...' : '';
+ const defval = arg.defaultvalue !== undefined ? `=${arg.defaultvalue}` : '';
+ out += `${variable}${arg.name}${defval}`;
+ if (arg.optional) {
+ out += ` ]${fmt}`;
+ }
+ });
+ out += ' ';
+ return out;
+}
+
+function make_rst_param(f, obj, depth = 0) {
+ const indent = ' '.repeat(depth * 3);
+ f.write(indent);
+ f.write(`:param ${obj.type} ${obj.name}:\n`);
+ f.write(indent_multiline(obj.description, (depth + 1) * 3));
+ f.write('\n\n');
+}
+
+function make_rst_attribute(f, obj, depth = 0, brief = false) {
+ const indent = ' '.repeat(depth * 3);
+ f.write(indent);
+ f.write(`.. js:attribute:: ${obj.name}\n\n`);
+
+ if (brief) {
+ if (obj.summary) {
+ f.write(indent_multiline(obj.summary, (depth + 1) * 3));
+ }
+ f.write('\n\n');
+ return;
+ }
+
+ f.write(indent_multiline(obj.description, (depth + 1) * 3));
+ f.write('\n\n');
+
+ f.write(indent);
+ f.write(` :type: ${obj.type}\n\n`);
+
+ if (obj.defaultvalue !== undefined) {
+ let defval = obj.defaultvalue;
+ if (defval === '') {
+ defval = '""';
+ }
+ f.write(indent);
+ f.write(` :value: \`\`${defval}\`\`\n\n`);
+ }
+}
+
+function make_rst_function(f, obj, depth = 0) {
+ let prefix = '';
+ if (obj.is_instance()) {
+ prefix = 'prototype.';
+ }
+
+ const indent = ' '.repeat(depth * 3);
+ const sig = make_rst_signature(obj);
+ f.write(indent);
+ f.write(`.. js:function:: ${prefix}${obj.name}(${sig})\n`);
+ f.write('\n');
+
+ f.write(indent_multiline(obj.description, (depth + 1) * 3));
+ f.write('\n\n');
+
+ obj.params.forEach((param) => {
+ make_rst_param(f, param, depth + 1);
+ });
+
+ if (obj.returns !== 'void') {
+ f.write(indent);
+ f.write(' :return:\n');
+ f.write(indent_multiline(obj.returns_desc, (depth + 2) * 3));
+ f.write('\n\n');
+ f.write(indent);
+ f.write(` :rtype: ${obj.returns}\n\n`);
+ }
+}
+
+function make_rst_object(f, obj) {
+ let brief = false;
+ // Our custom header flag.
+ if (obj.header !== null) {
+ f.write(make_header(obj.header, '-'));
+ f.write(`${obj.description}\n\n`);
+ brief = true;
+ }
+
+ // Format members table and descriptions
+ const data = [['type', 'name']].concat(obj.members.map((m) => [m.type, `:js:attr:\`${m.name}\``]));
+
+ f.write(make_header('Properties', '^'));
+ format_table(f, data, 0);
+
+ make_rst_attribute(f, obj, 0, brief);
+
+ if (!obj.members.length) {
+ return;
+ }
+
+ f.write(' **Property Descriptions**\n\n');
+
+ // Properties first
+ obj.members.filter((m) => !m.is_function()).forEach((m) => {
+ make_rst_attribute(f, m, 1);
+ });
+
+ // Callbacks last
+ obj.members.filter((m) => m.is_function()).forEach((m) => {
+ make_rst_function(f, m, 1);
+ });
+}
+
+function make_rst_class(f, obj) {
+ const header = obj.header ? obj.header : obj.name;
+ f.write(make_header(header, '-'));
+
+ if (obj.classdesc) {
+ f.write(`${obj.classdesc}\n\n`);
+ }
+
+ const funcs = obj.members.filter((m) => m.is_function());
+ function make_data(m) {
+ const base = m.is_static() ? obj.name : `${obj.name}.prototype`;
+ const params = make_rst_signature(m, true, true);
+ const sig = `:js:attr:\`${m.name} <${base}.${m.name}>\` **(**${params}**)**`;
+ return [m.returns, sig];
+ }
+ const sfuncs = funcs.filter((m) => m.is_static());
+ const ifuncs = funcs.filter((m) => !m.is_static());
+
+ f.write(make_header('Static Methods', '^'));
+ format_table(f, sfuncs.map((m) => make_data(m)));
+
+ f.write(make_header('Instance Methods', '^'));
+ format_table(f, ifuncs.map((m) => make_data(m)));
+
+ const sig = make_rst_signature(obj);
+ f.write(`.. js:class:: ${obj.name}(${sig})\n\n`);
+ f.write(indent_multiline(obj.description, 3));
+ f.write('\n\n');
+
+ obj.params.forEach((p) => {
+ make_rst_param(f, p, 1);
+ });
+
+ f.write(' **Static Methods**\n\n');
+ sfuncs.forEach((m) => {
+ make_rst_function(f, m, 1);
+ });
+
+ f.write(' **Instance Methods**\n\n');
+ ifuncs.forEach((m) => {
+ make_rst_function(f, m, 1);
+ });
+}
+
+function make_rst_module(f, obj) {
+ const header = obj.header !== null ? obj.header : obj.name;
+ f.write(make_header(header, '='));
+ f.write(obj.description);
+ f.write('\n\n');
+}
+
+function write_base_object(f, obj) {
+ if (obj.is_object()) {
+ make_rst_object(f, obj);
+ } else if (obj.is_function()) {
+ make_rst_function(f, obj);
+ } else if (obj.is_class()) {
+ make_rst_class(f, obj);
+ } else if (obj.is_module()) {
+ make_rst_module(f, obj);
+ }
+}
+
+function generate(f, docs) {
+ const globs = [];
+ const SYMBOLS = {};
+ docs.filter((d) => !d.ignore && d.kind !== 'package').forEach((d) => {
+ SYMBOLS[d.name] = d;
+ if (d.memberof) {
+ const up = SYMBOLS[d.memberof];
+ if (up === undefined) {
+ console.log(d); // eslint-disable-line no-console
+ console.log(`Undefined symbol! ${d.memberof}`); // eslint-disable-line no-console
+ throw new Error('Undefined symbol!');
+ }
+ SYMBOLS[d.memberof].add_member(d);
+ } else {
+ globs.push(d);
+ }
+ });
+
+ f.write('.. _doc_html5_shell_classref:\n\n');
+ globs.forEach((obj) => write_base_object(f, obj));
+}
+
+/**
+ * Generate documentation output.
+ *
+ * @param {TAFFY} data - A TaffyDB collection representing
+ * all the symbols documented in your code.
+ * @param {object} opts - An object with options information.
+ */
+exports.publish = function (data, opts) {
+ const docs = data().get().filter((doc) => !doc.undocumented && !doc.ignore).map((doc) => new JSDoclet(doc));
+ const dest = opts.destination;
+ if (dest === 'dry-run') {
+ process.stdout.write('Dry run... ');
+ generate({
+ write: function () { /* noop */ },
+ }, docs);
+ process.stdout.write('Okay!\n');
+ return;
+ }
+ if (dest !== '' && !dest.endsWith('.rst')) {
+ throw new Error('Destination file must be either a ".rst" file, or an empty string (for printing to stdout)');
+ }
+ if (dest !== '') {
+ const f = fs.createWriteStream(dest);
+ generate(f, docs);
+ } else {
+ generate(process.stdout, docs);
+ }
+};
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js
index 8e385e9176..ac4055516c 100644
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ b/platform/javascript/js/libs/library_godot_audio.js
@@ -238,6 +238,9 @@ const GodotAudioWorklet = {
close: function () {
return new Promise(function (resolve, reject) {
+ if (GodotAudioWorklet.promise === null) {
+ return;
+ }
GodotAudioWorklet.promise.then(function () {
GodotAudioWorklet.worklet.port.postMessage({
'cmd': 'stop',
@@ -247,7 +250,7 @@ const GodotAudioWorklet = {
GodotAudioWorklet.worklet = null;
GodotAudioWorklet.promise = null;
resolve();
- });
+ }).catch(function (err) { /* aborted? */ });
});
},
},
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 2977b7c122..91cab5eacc 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -192,33 +192,45 @@ const GodotDisplayDragDrop = {
GodotDisplayDragDrop.promises = [];
GodotDisplayDragDrop.pending_files = [];
callback(drops);
- const dirs = [DROP.substr(0, DROP.length - 1)];
- // Remove temporary files
- files.forEach(function (file) {
- FS.unlink(file);
- let dir = file.replace(DROP, '');
- let idx = dir.lastIndexOf('/');
- while (idx > 0) {
- dir = dir.substr(0, idx);
- if (dirs.indexOf(DROP + dir) === -1) {
- dirs.push(DROP + dir);
- }
- idx = dir.lastIndexOf('/');
- }
- });
- // Remove dirs.
- dirs.sort(function (a, b) {
- const al = (a.match(/\//g) || []).length;
- const bl = (b.match(/\//g) || []).length;
- if (al > bl) {
- return -1;
- } else if (al < bl) {
- return 1;
+ if (GodotConfig.persistent_drops) {
+ // Delay removal at exit.
+ GodotOS.atexit(function (resolve, reject) {
+ GodotDisplayDragDrop.remove_drop(files, DROP);
+ resolve();
+ });
+ } else {
+ GodotDisplayDragDrop.remove_drop(files, DROP);
+ }
+ });
+ },
+
+ remove_drop: function (files, drop_path) {
+ const dirs = [drop_path.substr(0, drop_path.length - 1)];
+ // Remove temporary files
+ files.forEach(function (file) {
+ FS.unlink(file);
+ let dir = file.replace(drop_path, '');
+ let idx = dir.lastIndexOf('/');
+ while (idx > 0) {
+ dir = dir.substr(0, idx);
+ if (dirs.indexOf(drop_path + dir) === -1) {
+ dirs.push(drop_path + dir);
}
- return 0;
- }).forEach(function (dir) {
- FS.rmdir(dir);
- });
+ idx = dir.lastIndexOf('/');
+ }
+ });
+ // Remove dirs.
+ dirs.sort(function (a, b) {
+ const al = (a.match(/\//g) || []).length;
+ const bl = (b.match(/\//g) || []).length;
+ if (al > bl) {
+ return -1;
+ } else if (al < bl) {
+ return 1;
+ }
+ return 0;
+ }).forEach(function (dir) {
+ FS.rmdir(dir);
});
},
@@ -231,6 +243,105 @@ const GodotDisplayDragDrop = {
};
mergeInto(LibraryManager.library, GodotDisplayDragDrop);
+const GodotDisplayVK = {
+
+ $GodotDisplayVK__deps: ['$GodotRuntime', '$GodotConfig', '$GodotDisplayListeners'],
+ $GodotDisplayVK__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayVK.clear(); resolve(); });',
+ $GodotDisplayVK: {
+ textinput: null,
+ textarea: null,
+
+ available: function () {
+ return GodotConfig.virtual_keyboard && 'ontouchstart' in window;
+ },
+
+ init: function (input_cb) {
+ function create(what) {
+ const elem = document.createElement(what);
+ elem.style.display = 'none';
+ elem.style.position = 'absolute';
+ elem.style.zIndex = '-1';
+ elem.style.background = 'transparent';
+ elem.style.padding = '0px';
+ elem.style.margin = '0px';
+ elem.style.overflow = 'hidden';
+ elem.style.width = '0px';
+ elem.style.height = '0px';
+ elem.style.border = '0px';
+ elem.style.outline = 'none';
+ elem.readonly = true;
+ elem.disabled = true;
+ GodotDisplayListeners.add(elem, 'input', function (evt) {
+ const c_str = GodotRuntime.allocString(elem.value);
+ input_cb(c_str, elem.selectionEnd);
+ GodotRuntime.free(c_str);
+ }, false);
+ GodotDisplayListeners.add(elem, 'blur', function (evt) {
+ elem.style.display = 'none';
+ elem.readonly = true;
+ elem.disabled = true;
+ }, false);
+ GodotConfig.canvas.insertAdjacentElement('beforebegin', elem);
+ return elem;
+ }
+ GodotDisplayVK.textinput = create('input');
+ GodotDisplayVK.textarea = create('textarea');
+ GodotDisplayVK.updateSize();
+ },
+ show: function (text, multiline, start, end) {
+ if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {
+ return;
+ }
+ if (GodotDisplayVK.textinput.style.display !== '' || GodotDisplayVK.textarea.style.display !== '') {
+ GodotDisplayVK.hide();
+ }
+ GodotDisplayVK.updateSize();
+ const elem = multiline ? GodotDisplayVK.textarea : GodotDisplayVK.textinput;
+ elem.readonly = false;
+ elem.disabled = false;
+ elem.value = text;
+ elem.style.display = 'block';
+ elem.focus();
+ elem.setSelectionRange(start, end);
+ },
+ hide: function () {
+ if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {
+ return;
+ }
+ [GodotDisplayVK.textinput, GodotDisplayVK.textarea].forEach(function (elem) {
+ elem.blur();
+ elem.style.display = 'none';
+ elem.value = '';
+ });
+ },
+ updateSize: function () {
+ if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {
+ return;
+ }
+ const rect = GodotConfig.canvas.getBoundingClientRect();
+ function update(elem) {
+ elem.style.left = `${rect.left}px`;
+ elem.style.top = `${rect.top}px`;
+ elem.style.width = `${rect.width}px`;
+ elem.style.height = `${rect.height}px`;
+ }
+ update(GodotDisplayVK.textinput);
+ update(GodotDisplayVK.textarea);
+ },
+ clear: function () {
+ if (GodotDisplayVK.textinput) {
+ GodotDisplayVK.textinput.remove();
+ GodotDisplayVK.textinput = null;
+ }
+ if (GodotDisplayVK.textarea) {
+ GodotDisplayVK.textarea.remove();
+ GodotDisplayVK.textarea = null;
+ }
+ },
+ },
+};
+mergeInto(LibraryManager.library, GodotDisplayVK);
+
/*
* Display server cursor helper.
* Keeps track of cursor status and custom shapes.
@@ -396,15 +507,145 @@ const GodotDisplayGamepads = {
};
mergeInto(LibraryManager.library, GodotDisplayGamepads);
+const GodotDisplayScreen = {
+ $GodotDisplayScreen__deps: ['$GodotConfig', '$GodotOS', '$GL', 'emscripten_webgl_get_current_context'],
+ $GodotDisplayScreen: {
+ desired_size: [0, 0],
+ hidpi: true,
+ getPixelRatio: function () {
+ return GodotDisplayScreen.hidpi ? window.devicePixelRatio || 1 : 1;
+ },
+ isFullscreen: function () {
+ const elem = document.fullscreenElement || document.mozFullscreenElement
+ || document.webkitFullscreenElement || document.msFullscreenElement;
+ if (elem) {
+ return elem === GodotConfig.canvas;
+ }
+ // But maybe knowing the element is not supported.
+ return document.fullscreen || document.mozFullScreen
+ || document.webkitIsFullscreen;
+ },
+ hasFullscreen: function () {
+ return document.fullscreenEnabled || document.mozFullScreenEnabled
+ || document.webkitFullscreenEnabled;
+ },
+ requestFullscreen: function () {
+ if (!GodotDisplayScreen.hasFullscreen()) {
+ return 1;
+ }
+ const canvas = GodotConfig.canvas;
+ try {
+ const promise = (canvas.requestFullscreen || canvas.msRequestFullscreen
+ || canvas.mozRequestFullScreen || canvas.mozRequestFullscreen
+ || canvas.webkitRequestFullscreen
+ ).call(canvas);
+ // Some browsers (Safari) return undefined.
+ // For the standard ones, we need to catch it.
+ if (promise) {
+ promise.catch(function () {
+ // nothing to do.
+ });
+ }
+ } catch (e) {
+ return 1;
+ }
+ return 0;
+ },
+ exitFullscreen: function () {
+ if (!GodotDisplayScreen.isFullscreen()) {
+ return 0;
+ }
+ try {
+ const promise = document.exitFullscreen();
+ if (promise) {
+ promise.catch(function () {
+ // nothing to do.
+ });
+ }
+ } catch (e) {
+ return 1;
+ }
+ return 0;
+ },
+ _updateGL: function () {
+ const gl_context_handle = _emscripten_webgl_get_current_context(); // eslint-disable-line no-undef
+ const gl = GL.getContext(gl_context_handle);
+ if (gl) {
+ GL.resizeOffscreenFramebuffer(gl);
+ }
+ },
+ updateSize: function () {
+ const isFullscreen = GodotDisplayScreen.isFullscreen();
+ const wantsFullWindow = GodotConfig.canvas_resize_policy === 2;
+ const noResize = GodotConfig.canvas_resize_policy === 0;
+ const wwidth = GodotDisplayScreen.desired_size[0];
+ const wheight = GodotDisplayScreen.desired_size[1];
+ const canvas = GodotConfig.canvas;
+ let width = wwidth;
+ let height = wheight;
+ if (noResize) {
+ // Don't resize canvas, just update GL if needed.
+ if (canvas.width !== width || canvas.height !== height) {
+ GodotDisplayScreen.desired_size = [canvas.width, canvas.height];
+ GodotDisplayScreen._updateGL();
+ return 1;
+ }
+ return 0;
+ }
+ const scale = GodotDisplayScreen.getPixelRatio();
+ if (isFullscreen || wantsFullWindow) {
+ // We need to match screen size.
+ width = window.innerWidth * scale;
+ height = window.innerHeight * scale;
+ }
+ const csw = `${width / scale}px`;
+ const csh = `${height / scale}px`;
+ if (canvas.style.width !== csw || canvas.style.height !== csh || canvas.width !== width || canvas.height !== height) {
+ // Size doesn't match.
+ // Resize canvas, set correct CSS pixel size, update GL.
+ canvas.width = width;
+ canvas.height = height;
+ canvas.style.width = csw;
+ canvas.style.height = csh;
+ GodotDisplayScreen._updateGL();
+ return 1;
+ }
+ return 0;
+ },
+ },
+};
+mergeInto(LibraryManager.library, GodotDisplayScreen);
+
/**
* Display server interface.
*
* Exposes all the functions needed by DisplayServer implementation.
*/
const GodotDisplay = {
- $GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotDisplayListeners', '$GodotDisplayDragDrop', '$GodotDisplayGamepads'],
+ $GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotDisplayListeners', '$GodotDisplayDragDrop', '$GodotDisplayGamepads', '$GodotDisplayScreen', '$GodotDisplayVK'],
$GodotDisplay: {
window_icon: '',
+ findDPI: function () {
+ function testDPI(dpi) {
+ return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches;
+ }
+ function bisect(low, high, func) {
+ const mid = parseInt(((high - low) / 2) + low, 10);
+ if (high - low <= 1) {
+ return func(high) ? high : low;
+ }
+ if (func(mid)) {
+ return bisect(low, mid, func);
+ }
+ return bisect(mid, high, func);
+ }
+ try {
+ const dpi = bisect(0, 800, testDPI);
+ return dpi >= 96 ? dpi : 96;
+ } catch (e) {
+ return 96;
+ }
+ },
},
godot_js_display_is_swap_ok_cancel__sig: 'i',
@@ -422,9 +663,71 @@ const GodotDisplay = {
window.alert(GodotRuntime.parseString(p_text)); // eslint-disable-line no-alert
},
+ godot_js_display_screen_dpi_get__sig: 'i',
+ godot_js_display_screen_dpi_get: function () {
+ return GodotDisplay.findDPI();
+ },
+
godot_js_display_pixel_ratio_get__sig: 'f',
godot_js_display_pixel_ratio_get: function () {
- return window.devicePixelRatio || 1;
+ return GodotDisplayScreen.getPixelRatio();
+ },
+
+ godot_js_display_fullscreen_request__sig: 'i',
+ godot_js_display_fullscreen_request: function () {
+ return GodotDisplayScreen.requestFullscreen();
+ },
+
+ godot_js_display_fullscreen_exit__sig: 'i',
+ godot_js_display_fullscreen_exit: function () {
+ return GodotDisplayScreen.exitFullscreen();
+ },
+
+ godot_js_display_desired_size_set__sig: 'v',
+ godot_js_display_desired_size_set: function (width, height) {
+ GodotDisplayScreen.desired_size = [width, height];
+ GodotDisplayScreen.updateSize();
+ },
+
+ godot_js_display_size_update__sig: 'i',
+ godot_js_display_size_update: function () {
+ const updated = GodotDisplayScreen.updateSize();
+ if (updated) {
+ GodotDisplayVK.updateSize();
+ }
+ return updated;
+ },
+
+ godot_js_display_screen_size_get__sig: 'vii',
+ godot_js_display_screen_size_get: function (width, height) {
+ const scale = GodotDisplayScreen.getPixelRatio();
+ GodotRuntime.setHeapValue(width, window.screen.width * scale, 'i32');
+ GodotRuntime.setHeapValue(height, window.screen.height * scale, 'i32');
+ },
+
+ godot_js_display_window_size_get: function (p_width, p_height) {
+ GodotRuntime.setHeapValue(p_width, GodotConfig.canvas.width, 'i32');
+ GodotRuntime.setHeapValue(p_height, GodotConfig.canvas.height, 'i32');
+ },
+
+ godot_js_display_compute_position: function (x, y, r_x, r_y) {
+ const canvas = GodotConfig.canvas;
+ const rect = canvas.getBoundingClientRect();
+ const rw = canvas.width / rect.width;
+ const rh = canvas.height / rect.height;
+ GodotRuntime.setHeapValue(r_x, (x - rect.x) * rw, 'i32');
+ GodotRuntime.setHeapValue(r_y, (y - rect.y) * rh, 'i32');
+ },
+
+ godot_js_display_has_webgl__sig: 'ii',
+ godot_js_display_has_webgl: function (p_version) {
+ if (p_version !== 1 && p_version !== 2) {
+ return false;
+ }
+ try {
+ return !!document.createElement('canvas').getContext(p_version === 2 ? 'webgl2' : 'webgl');
+ } catch (e) { /* Not available */ }
+ return false;
},
/*
@@ -440,13 +743,6 @@ const GodotDisplay = {
return document.activeElement === GodotConfig.canvas;
},
- godot_js_display_canvas_bounding_rect_position_get__sig: 'vii',
- godot_js_display_canvas_bounding_rect_position_get: function (r_x, r_y) {
- const brect = GodotConfig.canvas.getBoundingClientRect();
- GodotRuntime.setHeapValue(r_x, brect.x, 'i32');
- GodotRuntime.setHeapValue(r_y, brect.y, 'i32');
- },
-
/*
* Touchscreen
*/
@@ -490,15 +786,6 @@ const GodotDisplay = {
/*
* Window
*/
- godot_js_display_window_request_fullscreen__sig: 'v',
- godot_js_display_window_request_fullscreen: function () {
- const canvas = GodotConfig.canvas;
- (canvas.requestFullscreen || canvas.msRequestFullscreen
- || canvas.mozRequestFullScreen || canvas.mozRequestFullscreen
- || canvas.webkitRequestFullscreen
- ).call(canvas);
- },
-
godot_js_display_window_title_set__sig: 'vi',
godot_js_display_window_title_set: function (p_data) {
document.title = GodotRuntime.parseString(p_data);
@@ -514,7 +801,7 @@ const GodotDisplay = {
document.head.appendChild(link);
}
const old_icon = GodotDisplay.window_icon;
- const png = new Blob([GodotRuntime.heapCopy(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
+ 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 (old_icon) {
@@ -554,7 +841,7 @@ const GodotDisplay = {
const shape = GodotRuntime.parseString(p_shape);
const old_shape = GodotDisplayCursor.cursors[shape];
if (p_len > 0) {
- const png = new Blob([GodotRuntime.heapCopy(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
+ const png = new Blob([GodotRuntime.heapSlice(HEAPU8, p_ptr, p_len)], { type: 'image/png' });
const url = URL.createObjectURL(png);
GodotDisplayCursor.cursors[shape] = {
url: url,
@@ -582,7 +869,7 @@ const GodotDisplay = {
const notif = [p_enter, p_exit, p_in, p_out];
['mouseover', 'mouseleave', 'focus', 'blur'].forEach(function (evt_name, idx) {
GodotDisplayListeners.add(canvas, evt_name, function () {
- func.bind(null, notif[idx]);
+ func(notif[idx]);
}, true);
});
},
@@ -619,6 +906,66 @@ const GodotDisplay = {
GodotDisplayListeners.add(canvas, 'drop', GodotDisplayDragDrop.handler(dropFiles));
},
+ godot_js_display_setup_canvas__sig: 'viiii',
+ godot_js_display_setup_canvas: function (p_width, p_height, p_fullscreen, p_hidpi) {
+ const canvas = GodotConfig.canvas;
+ GodotDisplayListeners.add(canvas, 'contextmenu', function (ev) {
+ ev.preventDefault();
+ }, false);
+ GodotDisplayListeners.add(canvas, 'webglcontextlost', function (ev) {
+ alert('WebGL context lost, please reload the page'); // eslint-disable-line no-alert
+ ev.preventDefault();
+ }, false);
+ GodotDisplayScreen.hidpi = !!p_hidpi;
+ switch (GodotConfig.canvas_resize_policy) {
+ case 0: // None
+ GodotDisplayScreen.desired_size = [canvas.width, canvas.height];
+ break;
+ case 1: // Project
+ GodotDisplayScreen.desired_size = [p_width, p_height];
+ break;
+ default: // Full window
+ // Ensure we display in the right place, the size will be handled by updateSize
+ canvas.style.position = 'absolute';
+ canvas.style.top = 0;
+ canvas.style.left = 0;
+ break;
+ }
+ GodotDisplayScreen.updateSize();
+ if (p_fullscreen) {
+ GodotDisplayScreen.requestFullscreen();
+ }
+ },
+
+ /*
+ * Virtual Keyboard
+ */
+ godot_js_display_vk_show__sig: 'viiii',
+ godot_js_display_vk_show: function (p_text, p_multiline, p_start, p_end) {
+ const text = GodotRuntime.parseString(p_text);
+ const start = p_start > 0 ? p_start : 0;
+ const end = p_end > 0 ? p_end : start;
+ GodotDisplayVK.show(text, p_multiline, start, end);
+ },
+
+ godot_js_display_vk_hide__sig: 'v',
+ godot_js_display_vk_hide: function () {
+ GodotDisplayVK.hide();
+ },
+
+ godot_js_display_vk_available__sig: 'i',
+ godot_js_display_vk_available: function () {
+ return GodotDisplayVK.available();
+ },
+
+ godot_js_display_vk_cb__sig: 'vi',
+ godot_js_display_vk_cb: function (p_input_cb) {
+ const input_cb = GodotRuntime.get_func(p_input_cb);
+ if (GodotDisplayVK.available()) {
+ GodotDisplayVK.init(input_cb);
+ }
+ },
+
/*
* Gamepads
*/
diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/javascript/js/libs/library_godot_fetch.js
new file mode 100644
index 0000000000..de5ae2b1ae
--- /dev/null
+++ b/platform/javascript/js/libs/library_godot_fetch.js
@@ -0,0 +1,247 @@
+/*************************************************************************/
+/* library_godot_fetch.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+const GodotFetch = {
+ $GodotFetch__deps: ['$GodotRuntime'],
+ $GodotFetch: {
+
+ onread: function (id, result) {
+ const obj = IDHandler.get(id);
+ if (!obj) {
+ return;
+ }
+ if (result.value) {
+ obj.chunks.push(result.value);
+ }
+ obj.reading = false;
+ obj.done = result.done;
+ },
+
+ onresponse: function (id, response) {
+ const obj = IDHandler.get(id);
+ if (!obj) {
+ return;
+ }
+ let chunked = false;
+ response.headers.forEach(function (value, header) {
+ const v = value.toLowerCase().trim();
+ const h = header.toLowerCase().trim();
+ if (h === 'transfer-encoding' && v === 'chunked') {
+ chunked = true;
+ }
+ });
+ obj.status = response.status;
+ obj.response = response;
+ obj.reader = response.body.getReader();
+ obj.chunked = chunked;
+ },
+
+ onerror: function (id, err) {
+ GodotRuntime.error(err);
+ const obj = IDHandler.get(id);
+ if (!obj) {
+ return;
+ }
+ obj.error = err;
+ },
+
+ create: function (method, url, headers, body) {
+ const obj = {
+ request: null,
+ response: null,
+ reader: null,
+ error: null,
+ done: false,
+ reading: false,
+ status: 0,
+ chunks: [],
+ bodySize: -1,
+ };
+ const id = IDHandler.add(obj);
+ const init = {
+ method: method,
+ headers: headers,
+ body: body,
+ };
+ obj.request = fetch(url, init);
+ obj.request.then(GodotFetch.onresponse.bind(null, id)).catch(GodotFetch.onerror.bind(null, id));
+ return id;
+ },
+
+ free: function (id) {
+ const obj = IDHandler.get(id);
+ if (!obj) {
+ return;
+ }
+ IDHandler.remove(id);
+ if (!obj.request) {
+ return;
+ }
+ // Try to abort
+ obj.request.then(function (response) {
+ response.abort();
+ }).catch(function (e) { /* nothing to do */ });
+ },
+
+ read: function (id) {
+ const obj = IDHandler.get(id);
+ if (!obj) {
+ return;
+ }
+ if (obj.reader && !obj.reading) {
+ if (obj.done) {
+ obj.reader = null;
+ return;
+ }
+ obj.reading = true;
+ obj.reader.read().then(GodotFetch.onread.bind(null, id)).catch(GodotFetch.onerror.bind(null, id));
+ }
+ },
+ },
+
+ godot_js_fetch_create__sig: 'iii',
+ godot_js_fetch_create: function (p_method, p_url, p_headers, p_headers_size, p_body, p_body_size) {
+ const method = GodotRuntime.parseString(p_method);
+ const url = GodotRuntime.parseString(p_url);
+ const headers = GodotRuntime.parseStringArray(p_headers, p_headers_size);
+ const body = p_body_size ? GodotRuntime.heapSlice(HEAP8, p_body, p_body_size) : null;
+ return GodotFetch.create(method, url, headers.map(function (hv) {
+ const idx = hv.indexOf(':');
+ if (idx <= 0) {
+ return [];
+ }
+ return [
+ hv.slice(0, idx).trim(),
+ hv.slice(idx + 1).trim(),
+ ];
+ }).filter(function (v) {
+ return v.length === 2;
+ }), body);
+ },
+
+ godot_js_fetch_state_get__sig: 'ii',
+ godot_js_fetch_state_get: function (p_id) {
+ const obj = IDHandler.get(p_id);
+ if (!obj) {
+ return -1;
+ }
+ if (obj.error) {
+ return -1;
+ }
+ if (!obj.response) {
+ return 0;
+ }
+ if (obj.reader) {
+ return 1;
+ }
+ if (obj.done) {
+ return 2;
+ }
+ return -1;
+ },
+
+ godot_js_fetch_http_status_get__sig: 'ii',
+ godot_js_fetch_http_status_get: function (p_id) {
+ const obj = IDHandler.get(p_id);
+ if (!obj || !obj.response) {
+ return 0;
+ }
+ return obj.status;
+ },
+
+ godot_js_fetch_read_headers__sig: 'iii',
+ godot_js_fetch_read_headers: function (p_id, p_parse_cb, p_ref) {
+ const obj = IDHandler.get(p_id);
+ if (!obj || !obj.response) {
+ return 1;
+ }
+ const cb = GodotRuntime.get_func(p_parse_cb);
+ const arr = [];
+ obj.response.headers.forEach(function (v, h) {
+ arr.push(`${h}:${v}`);
+ });
+ const c_ptr = GodotRuntime.allocStringArray(arr);
+ cb(arr.length, c_ptr, p_ref);
+ GodotRuntime.freeStringArray(c_ptr, arr.length);
+ return 0;
+ },
+
+ godot_js_fetch_read_chunk__sig: 'ii',
+ godot_js_fetch_read_chunk: function (p_id, p_buf, p_buf_size) {
+ const obj = IDHandler.get(p_id);
+ if (!obj || !obj.response) {
+ return 0;
+ }
+ let to_read = p_buf_size;
+ const chunks = obj.chunks;
+ while (to_read && chunks.length) {
+ const chunk = obj.chunks[0];
+ if (chunk.length > to_read) {
+ GodotRuntime.heapCopy(HEAP8, chunk.slice(0, to_read), p_buf);
+ chunks[0] = chunk.slice(to_read);
+ to_read = 0;
+ } else {
+ GodotRuntime.heapCopy(HEAP8, chunk, p_buf);
+ to_read -= chunk.length;
+ chunks.pop();
+ }
+ }
+ if (!chunks.length) {
+ GodotFetch.read(p_id);
+ }
+ 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);
+ if (!obj || !obj.response) {
+ return -1;
+ }
+ return obj.chunked ? 1 : 0;
+ },
+
+ godot_js_fetch_free__sig: 'vi',
+ godot_js_fetch_free: function (id) {
+ GodotFetch.free(id);
+ },
+};
+
+autoAddDeps(GodotFetch, '$GodotFetch');
+mergeInto(LibraryManager.library, GodotFetch);
diff --git a/platform/javascript/js/libs/library_godot_http_request.js b/platform/javascript/js/libs/library_godot_http_request.js
deleted file mode 100644
index 930d3209f8..0000000000
--- a/platform/javascript/js/libs/library_godot_http_request.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/*************************************************************************/
-/* http_request.js */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-const GodotHTTPRequest = {
- $GodotHTTPRequest__deps: ['$GodotRuntime'],
- $GodotHTTPRequest: {
- requests: [],
-
- getUnusedRequestId: function () {
- const idMax = GodotHTTPRequest.requests.length;
- for (let potentialId = 0; potentialId < idMax; ++potentialId) {
- if (GodotHTTPRequest.requests[potentialId] instanceof XMLHttpRequest) {
- continue;
- }
- return potentialId;
- }
- GodotHTTPRequest.requests.push(null);
- return idMax;
- },
-
- setupRequest: function (xhr) {
- xhr.responseType = 'arraybuffer';
- },
- },
-
- godot_xhr_new__sig: 'i',
- godot_xhr_new: function () {
- const newId = GodotHTTPRequest.getUnusedRequestId();
- GodotHTTPRequest.requests[newId] = new XMLHttpRequest();
- GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[newId]);
- return newId;
- },
-
- godot_xhr_reset__sig: 'vi',
- godot_xhr_reset: function (xhrId) {
- GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest();
- GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]);
- },
-
- godot_xhr_free__sig: 'vi',
- godot_xhr_free: function (xhrId) {
- GodotHTTPRequest.requests[xhrId].abort();
- GodotHTTPRequest.requests[xhrId] = null;
- },
-
- godot_xhr_open__sig: 'viiiii',
- godot_xhr_open: function (xhrId, method, url, p_user, p_password) {
- const user = p_user > 0 ? GodotRuntime.parseString(p_user) : null;
- const password = p_password > 0 ? GodotRuntime.parseString(p_password) : null;
- GodotHTTPRequest.requests[xhrId].open(GodotRuntime.parseString(method), GodotRuntime.parseString(url), true, user, password);
- },
-
- godot_xhr_set_request_header__sig: 'viii',
- godot_xhr_set_request_header: function (xhrId, header, value) {
- GodotHTTPRequest.requests[xhrId].setRequestHeader(GodotRuntime.parseString(header), GodotRuntime.parseString(value));
- },
-
- godot_xhr_send_null__sig: 'vi',
- godot_xhr_send_null: function (xhrId) {
- GodotHTTPRequest.requests[xhrId].send();
- },
-
- godot_xhr_send_string__sig: 'vii',
- godot_xhr_send_string: function (xhrId, strPtr) {
- if (!strPtr) {
- GodotRuntime.error('Failed to send string per XHR: null pointer');
- return;
- }
- GodotHTTPRequest.requests[xhrId].send(GodotRuntime.parseString(strPtr));
- },
-
- godot_xhr_send_data__sig: 'viii',
- godot_xhr_send_data: function (xhrId, ptr, len) {
- if (!ptr) {
- GodotRuntime.error('Failed to send data per XHR: null pointer');
- return;
- }
- if (len < 0) {
- GodotRuntime.error('Failed to send data per XHR: buffer length less than 0');
- return;
- }
- GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len));
- },
-
- godot_xhr_abort__sig: 'vi',
- godot_xhr_abort: function (xhrId) {
- GodotHTTPRequest.requests[xhrId].abort();
- },
-
- godot_xhr_get_status__sig: 'ii',
- godot_xhr_get_status: function (xhrId) {
- return GodotHTTPRequest.requests[xhrId].status;
- },
-
- godot_xhr_get_ready_state__sig: 'ii',
- godot_xhr_get_ready_state: function (xhrId) {
- return GodotHTTPRequest.requests[xhrId].readyState;
- },
-
- godot_xhr_get_response_headers_length__sig: 'ii',
- godot_xhr_get_response_headers_length: function (xhrId) {
- const headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
- return headers === null ? 0 : GodotRuntime.strlen(headers);
- },
-
- godot_xhr_get_response_headers__sig: 'viii',
- godot_xhr_get_response_headers: function (xhrId, dst, len) {
- const str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
- if (str === null) {
- return;
- }
- GodotRuntime.stringToHeap(str, dst, len);
- },
-
- godot_xhr_get_response_length__sig: 'ii',
- godot_xhr_get_response_length: function (xhrId) {
- const body = GodotHTTPRequest.requests[xhrId].response;
- return body === null ? 0 : body.byteLength;
- },
-
- godot_xhr_get_response__sig: 'viii',
- godot_xhr_get_response: function (xhrId, dst, len) {
- let buf = GodotHTTPRequest.requests[xhrId].response;
- if (buf === null) {
- return;
- }
- buf = new Uint8Array(buf).subarray(0, len);
- HEAPU8.set(buf, dst);
- },
-};
-
-autoAddDeps(GodotHTTPRequest, '$GodotHTTPRequest');
-mergeInto(LibraryManager.library, GodotHTTPRequest);
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 9fde4a84e1..1d9f889bce 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -58,21 +58,34 @@ const GodotConfig = {
$GodotConfig: {
canvas: null,
locale: 'en',
- resize_on_start: false,
+ canvas_resize_policy: 2, // Adaptive
+ virtual_keyboard: false,
+ persistent_drops: false,
on_execute: null,
+ on_exit: null,
init_config: function (p_opts) {
- GodotConfig.resize_on_start = !!p_opts['resizeCanvasOnStart'];
+ GodotConfig.canvas_resize_policy = p_opts['canvasResizePolicy'];
GodotConfig.canvas = p_opts['canvas'];
GodotConfig.locale = p_opts['locale'] || GodotConfig.locale;
+ GodotConfig.virtual_keyboard = p_opts['virtualKeyboard'];
+ GodotConfig.persistent_drops = !!p_opts['persistentDrops'];
GodotConfig.on_execute = p_opts['onExecute'];
- // This is called by emscripten, even if undocumented.
- Module['onExit'] = p_opts['onExit']; // eslint-disable-line no-undef
+ GodotConfig.on_exit = p_opts['onExit'];
},
locate_file: function (file) {
return Module['locateFile'](file); // eslint-disable-line no-undef
},
+ clear: function () {
+ GodotConfig.canvas = null;
+ GodotConfig.locale = 'en';
+ GodotConfig.canvas_resize_policy = 2;
+ GodotConfig.virtual_keyboard = false;
+ GodotConfig.persistent_drops = false;
+ GodotConfig.on_execute = null;
+ GodotConfig.on_exit = null;
+ },
},
godot_js_config_canvas_id_get__sig: 'vii',
@@ -84,11 +97,6 @@ const GodotConfig = {
godot_js_config_locale_get: function (p_ptr, p_ptr_max) {
GodotRuntime.stringToHeap(GodotConfig.locale, p_ptr, p_ptr_max);
},
-
- godot_js_config_is_resize_on_start__sig: 'i',
- godot_js_config_is_resize_on_start: function () {
- return GodotConfig.resize_on_start ? 1 : 0;
- },
};
autoAddDeps(GodotConfig, '$GodotConfig');
@@ -98,7 +106,6 @@ const GodotFS = {
$GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'],
$GodotFS__postset: [
'Module["initFS"] = GodotFS.init;',
- 'Module["deinitFS"] = GodotFS.deinit;',
'Module["copyToFS"] = GodotFS.copy_to_fs;',
].join(''),
$GodotFS: {
@@ -210,9 +217,10 @@ const GodotFS = {
mergeInto(LibraryManager.library, GodotFS);
const GodotOS = {
- $GodotOS__deps: ['$GodotFS', '$GodotRuntime'],
+ $GodotOS__deps: ['$GodotRuntime', '$GodotConfig', '$GodotFS'],
$GodotOS__postset: [
'Module["request_quit"] = function() { GodotOS.request_quit() };',
+ 'Module["onExit"] = GodotOS.cleanup;',
'GodotOS._fs_sync_promise = Promise.resolve();',
].join(''),
$GodotOS: {
@@ -224,6 +232,15 @@ const GodotOS = {
GodotOS._async_cbs.push(p_promise_cb);
},
+ cleanup: function (exit_code) {
+ const cb = GodotConfig.on_exit;
+ GodotFS.deinit();
+ GodotConfig.clear();
+ if (cb) {
+ cb(exit_code);
+ }
+ },
+
finish_async: function (callback) {
GodotOS._fs_sync_promise.then(function (err) {
const promises = [];
@@ -282,6 +299,11 @@ const GodotOS = {
godot_js_os_shell_open: function (p_uri) {
window.open(GodotRuntime.parseString(p_uri), '_blank');
},
+
+ godot_js_os_hw_concurrency_get__sig: 'i',
+ godot_js_os_hw_concurrency_get: function () {
+ return navigator.hardwareConcurrency || 1;
+ },
};
autoAddDeps(GodotOS, '$GodotOS');
diff --git a/platform/javascript/js/libs/library_godot_runtime.js b/platform/javascript/js/libs/library_godot_runtime.js
index 7e36ff8ab5..3da1ed8f06 100644
--- a/platform/javascript/js/libs/library_godot_runtime.js
+++ b/platform/javascript/js/libs/library_godot_runtime.js
@@ -72,11 +72,16 @@ const GodotRuntime = {
return p_heap.subarray(p_ptr / bytes, p_ptr / bytes + p_len);
},
- heapCopy: function (p_heap, p_ptr, p_len) {
+ heapSlice: function (p_heap, p_ptr, p_len) {
const bytes = p_heap.BYTES_PER_ELEMENT;
return p_heap.slice(p_ptr / bytes, p_ptr / bytes + p_len);
},
+ heapCopy: function (p_dst, p_src, p_ptr) {
+ const bytes = p_src.BYTES_PER_ELEMENT;
+ return p_dst.set(p_src, p_ptr / bytes);
+ },
+
/*
* Strings
*/
@@ -84,6 +89,15 @@ const GodotRuntime = {
return UTF8ToString(p_ptr); // eslint-disable-line no-undef
},
+ parseStringArray: function (p_ptr, p_size) {
+ const strings = [];
+ const ptrs = GodotRuntime.heapSub(HEAP32, p_ptr, p_size); // TODO wasm64
+ ptrs.forEach(function (ptr) {
+ strings.push(GodotRuntime.parseString(ptr));
+ });
+ return strings;
+ },
+
strlen: function (p_str) {
return lengthBytesUTF8(p_str); // eslint-disable-line no-undef
},
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index b922b2ba91..0b1650076c 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -129,6 +129,10 @@ int OS_JavaScript::get_process_id() const {
ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the HTML5 platform.");
}
+int OS_JavaScript::get_processor_count() const {
+ return godot_js_os_hw_concurrency_get();
+}
+
bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
if (p_feature == "HTML5" || p_feature == "web") {
return true;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 8db62d9d1c..81bb9c5f3d 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -74,6 +74,7 @@ public:
Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
Error kill(const ProcessID &p_pid) override;
int get_process_id() const override;
+ int get_processor_count() const override;
String get_executable_path() const override;
Error shell_open(String p_uri) override;
diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json
index 8e298a495e..b8c434b3dd 100644
--- a/platform/javascript/package-lock.json
+++ b/platform/javascript/package-lock.json
@@ -43,6 +43,12 @@
}
}
},
+ "@babel/parser": {
+ "version": "7.13.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.4.tgz",
+ "integrity": "sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==",
+ "dev": true
+ },
"@eslint/eslintrc": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
@@ -202,6 +208,12 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -218,6 +230,15 @@
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true
},
+ "catharsis": {
+ "version": "0.8.11",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
+ "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
@@ -362,6 +383,12 @@
"ansi-colors": "^4.1.1"
}
},
+ "entities": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+ "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
+ "dev": true
+ },
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -925,6 +952,51 @@
"esprima": "^4.0.0"
}
},
+ "js2xmlparser": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz",
+ "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==",
+ "dev": true,
+ "requires": {
+ "xmlcreate": "^2.0.3"
+ }
+ },
+ "jsdoc": {
+ "version": "3.6.6",
+ "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.6.tgz",
+ "integrity": "sha512-znR99e1BHeyEkSvgDDpX0sTiTu+8aQyDl9DawrkOGZTTW8hv0deIFXx87114zJ7gRaDZKVQD/4tr1ifmJp9xhQ==",
+ "dev": true,
+ "requires": {
+ "@babel/parser": "^7.9.4",
+ "bluebird": "^3.7.2",
+ "catharsis": "^0.8.11",
+ "escape-string-regexp": "^2.0.0",
+ "js2xmlparser": "^4.0.1",
+ "klaw": "^3.0.0",
+ "markdown-it": "^10.0.0",
+ "markdown-it-anchor": "^5.2.7",
+ "marked": "^0.8.2",
+ "mkdirp": "^1.0.4",
+ "requizzle": "^0.2.3",
+ "strip-json-comments": "^3.1.0",
+ "taffydb": "2.6.2",
+ "underscore": "~1.10.2"
+ },
+ "dependencies": {
+ "escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ }
+ }
+ },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -946,6 +1018,15 @@
"minimist": "^1.2.0"
}
},
+ "klaw": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
+ "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.9"
+ }
+ },
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -956,6 +1037,15 @@
"type-check": "~0.4.0"
}
},
+ "linkify-it": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
+ "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+ "dev": true,
+ "requires": {
+ "uc.micro": "^1.0.1"
+ }
+ },
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -984,6 +1074,37 @@
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true
},
+ "markdown-it": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
+ "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "entities": "~2.0.0",
+ "linkify-it": "^2.0.0",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ }
+ },
+ "markdown-it-anchor": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz",
+ "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==",
+ "dev": true
+ },
+ "marked": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
+ "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
+ "dev": true
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
+ "dev": true
+ },
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1287,6 +1408,15 @@
"integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
"dev": true
},
+ "requizzle": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
+ "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
@@ -1513,6 +1643,12 @@
"string-width": "^3.0.0"
}
},
+ "taffydb": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
+ "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
+ "dev": true
+ },
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -1546,6 +1682,18 @@
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
},
+ "uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+ "dev": true
+ },
+ "underscore": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
+ "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==",
+ "dev": true
+ },
"uri-js": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
@@ -1600,6 +1748,12 @@
"requires": {
"mkdirp": "^0.5.1"
}
+ },
+ "xmlcreate": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz",
+ "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
+ "dev": true
}
}
}
diff --git a/platform/javascript/package.json b/platform/javascript/package.json
index 630b584f5b..d9d272923e 100644
--- a/platform/javascript/package.json
+++ b/platform/javascript/package.json
@@ -5,20 +5,24 @@
"description": "Linting setup for Godot's HTML5 platform code",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules",
+ "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''",
+ "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools",
"lint:engine": "eslint \"js/engine/*.js\" --no-eslintrc -c .eslintrc.engine.js",
"lint:libs": "eslint \"js/libs/*.js\" --no-eslintrc -c .eslintrc.libs.js",
"lint:modules": "eslint \"../../modules/**/*.js\" --no-eslintrc -c .eslintrc.libs.js",
- "format": "npm run format:engine && npm run format:libs && npm run format:modules",
+ "lint:tools": "eslint \"js/jsdoc2rst/**/*.js\" --no-eslintrc -c .eslintrc.engine.js",
+ "format": "npm run format:engine && npm run format:libs && npm run format:modules && npm run format:tools",
"format:engine": "npm run lint:engine -- --fix",
"format:libs": "npm run lint:libs -- --fix",
- "format:modules": "npm run lint:modules -- --fix"
+ "format:modules": "npm run lint:modules -- --fix",
+ "format:tools": "npm run lint:tools -- --fix"
},
"author": "Godot Engine contributors",
"license": "MIT",
"devDependencies": {
"eslint": "^7.9.0",
"eslint-config-airbnb-base": "^14.2.0",
- "eslint-plugin-import": "^2.22.0"
+ "eslint-plugin-import": "^2.22.0",
+ "jsdoc": "^3.6.6"
}
}
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index ddc698a55b..46714e9502 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -16,6 +16,9 @@ common_x11 = [
"key_mapping_x11.cpp",
]
+if "udev" in env and env["udev"]:
+ common_x11.append("libudev-so_wrap.c")
+
prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_x11)
if env["debug_symbols"] and env["separate_debug_symbols"]:
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 13d1fe3237..adbbcaac31 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -67,9 +67,10 @@ def get_opts():
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_coverage", "Test Godot coverage", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
+ BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
@@ -89,7 +90,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"]:
@@ -98,7 +99,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
@@ -142,15 +143,27 @@ def configure(env):
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
- if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"]:
+ if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]:
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ if env["use_llvm"]:
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change"
+ ]
+ )
+ else:
+ env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
if env["use_lsan"]:
@@ -161,6 +174,12 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
+ if env["use_msan"] and env["use_llvm"]:
+ env.Append(CCFLAGS=["-fsanitize=memory"])
+ env.Append(CCFLAGS=["-fsanitize-memory-track-origins"])
+ env.Append(CCFLAGS=["-fsanitize-recover=memory"])
+ env.Append(LINKFLAGS=["-fsanitize=memory"])
+
if env["use_lto"]:
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
env.Append(CCFLAGS=["-flto"])
@@ -310,9 +329,8 @@ def configure(env):
if os.system("pkg-config --exists alsa") == 0: # 0 means found
print("Enabling ALSA")
+ env["alsa"] = True
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
- # Don't parse --cflags, we don't need to add /usr/include/alsa to include path
- env.ParseConfig("pkg-config alsa --libs")
else:
print("ALSA libraries not found, disabling driver")
@@ -320,20 +338,20 @@ def configure(env):
if os.system("pkg-config --exists libpulse") == 0: # 0 means found
print("Enabling PulseAudio")
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
- env.ParseConfig("pkg-config --cflags --libs libpulse")
+ env.ParseConfig("pkg-config --cflags libpulse")
else:
print("PulseAudio development libraries not found, disabling driver")
if platform.system() == "Linux":
env.Append(CPPDEFINES=["JOYDEV_ENABLED"])
-
if env["udev"]:
if os.system("pkg-config --exists libudev") == 0: # 0 means found
print("Enabling udev support")
env.Append(CPPDEFINES=["UDEV_ENABLED"])
- env.ParseConfig("pkg-config libudev --cflags --libs")
else:
print("libudev development libraries not found, disabling udev support")
+ else:
+ env["udev"] = False # Linux specific
# Linkflags below this line should typically stay the last ones
if not env["builtin_zlib"]:
@@ -390,7 +408,10 @@ def configure(env):
# Link those statically for portability
if env["use_static_cpp"]:
- # Workaround for GH-31743, Ubuntu 18.04 i386 crashes when it's used.
- # That doesn't make any sense but it's likely a Ubuntu bug?
- if is64 or env["bits"] == "64":
- env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
+ env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
+ if env["use_llvm"]:
+ env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a"
+
+ else:
+ if env["use_llvm"]:
+ env.Append(LIBS=["atomic"])
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
index 0f8d108dff..da1c95a593 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -61,6 +61,7 @@ struct vendor {
vendor vendormap[] = {
{ "Advanced Micro Devices, Inc.", 30 },
+ { "AMD", 30 },
{ "NVIDIA Corporation", 30 },
{ "X.Org", 30 },
{ "Intel Open Source Technology Center", 20 },
@@ -128,7 +129,7 @@ void create_context() {
int detect_prime() {
pid_t p;
- int priorities[2];
+ int priorities[2] = {};
String vendors[2];
String renderers[2];
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 53baf17858..8dc1b41702 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -727,9 +727,9 @@ Point2i DisplayServerX11::screen_get_position(int p_screen) const {
int count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- if (p_screen >= count) {
- return Point2i(0, 0);
- }
+
+ // Check if screen is valid
+ ERR_FAIL_INDEX_V(p_screen, count, Point2i(0, 0));
Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
@@ -758,9 +758,9 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
int count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- if (p_screen >= count) {
- return Rect2i(0, 0, 0, 0);
- }
+
+ // Check if screen is valid
+ ERR_FAIL_INDEX_V(p_screen, count, Rect2i(0, 0, 0, 0));
Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height);
XFree(xsi);
@@ -1041,11 +1041,13 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- int count = get_screen_count();
- if (p_screen >= count) {
- return;
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
}
+ // Check if screen is valid
+ ERR_FAIL_INDEX(p_screen, get_screen_count());
+
if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {
Point2i position = screen_get_position(p_screen);
Size2i size = screen_get_size(p_screen);
@@ -1915,7 +1917,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
Rect2i atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -1938,7 +1940,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -2010,7 +2012,7 @@ int DisplayServerX11::keyboard_get_layout_count() const {
XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2044,7 +2046,7 @@ String DisplayServerX11::keyboard_get_layout_language(int p_index) const {
int _group_count = 0;
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2083,7 +2085,7 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
int _group_count = 0;
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2682,7 +2684,7 @@ bool DisplayServerX11::_wait_for_events() const {
tv.tv_sec = 1;
// Wait for next event or timeout.
- int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+ int num_ready_fds = select(x11_fd + 1, &in_fds, nullptr, nullptr, &tv);
if (num_ready_fds > 0) {
// Event received.
@@ -2697,7 +2699,7 @@ bool DisplayServerX11::_wait_for_events() const {
}
void DisplayServerX11::_poll_events() {
- while (!events_thread_done) {
+ while (!events_thread_done.is_set()) {
_wait_for_events();
// Process events from the queue.
@@ -3296,7 +3298,7 @@ void DisplayServerX11::process_events() {
if (xi.pressure_supported) {
mm->set_pressure(xi.pressure);
} else {
- mm->set_pressure((mouse_get_button_state() & (1 << (BUTTON_LEFT - 1))) ? 1.0f : 0.0f);
+ mm->set_pressure((mouse_get_button_state() & (1 << (MOUSE_BUTTON_LEFT - 1))) ? 1.0f : 0.0f);
}
mm->set_tilt(xi.tilt);
@@ -4028,7 +4030,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
use_prime = 0;
}
- if (getenv("LD_LIBRARY_PATH")) {
+ // Some tools use fake libGL libraries and have them override the real one using
+ // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its
+ // runtime and includes system `/lib` and `/lib64`... so ignore Steam.
+ if (use_prime == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) {
String ld_library_path(getenv("LD_LIBRARY_PATH"));
Vector<String> libraries = ld_library_path.split(":");
@@ -4279,7 +4284,7 @@ DisplayServerX11::~DisplayServerX11() {
_clipboard_transfer_ownership(XA_PRIMARY, x11_main_window);
_clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window);
- events_thread_done = true;
+ events_thread_done.set();
events_thread.wait_to_finish();
//destroy all windows
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 906710f933..10686d8424 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -253,7 +253,7 @@ class DisplayServerX11 : public DisplayServer {
mutable Mutex events_mutex;
Thread events_thread;
- bool events_thread_done = false;
+ SafeFlag events_thread_done;
LocalVector<XEvent> polled_events;
static void _poll_events_thread(void *ud);
bool _wait_for_events() const;
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 4e96e6d687..e8f4352dff 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -39,7 +39,7 @@
#include <unistd.h>
#ifdef UDEV_ENABLED
-#include <libudev.h>
+#include "libudev-so_wrap.h"
#endif
#define LONG_BITS (sizeof(long) * 8)
@@ -62,7 +62,7 @@ void JoypadLinux::Joypad::reset() {
dpad = 0;
fd = -1;
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = -1;
jx.value = 0.0f;
for (int i = 0; i < MAX_ABS; i++) {
@@ -72,13 +72,27 @@ void JoypadLinux::Joypad::reset() {
}
JoypadLinux::JoypadLinux(Input *in) {
- exit_udev = false;
+#ifdef UDEV_ENABLED
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+ use_udev = initialize_libudev(dylibloader_verbose) == 0;
+ if (use_udev) {
+ print_verbose("JoypadLinux: udev enabled and loaded successfully.");
+ } else {
+ print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads.");
+ }
+#else
+ print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads.");
+#endif
input = in;
joy_thread.start(joy_thread_func, this);
}
JoypadLinux::~JoypadLinux() {
- exit_udev = true;
+ exit_monitor.set();
joy_thread.wait_to_finish();
close_joypad();
}
@@ -92,11 +106,20 @@ void JoypadLinux::joy_thread_func(void *p_user) {
void JoypadLinux::run_joypad_thread() {
#ifdef UDEV_ENABLED
- udev *_udev = udev_new();
- ERR_FAIL_COND(!_udev);
- enumerate_joypads(_udev);
- monitor_joypads(_udev);
- udev_unref(_udev);
+ if (use_udev) {
+ udev *_udev = udev_new();
+ if (!_udev) {
+ use_udev = false;
+ ERR_PRINT("Failed getting an udev context, falling back to parsing /dev/input.");
+ monitor_joypads();
+ } else {
+ enumerate_joypads(_udev);
+ monitor_joypads(_udev);
+ udev_unref(_udev);
+ }
+ } else {
+ monitor_joypads();
+ }
#else
monitor_joypads();
#endif
@@ -137,7 +160,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
udev_monitor_enable_receiving(mon);
int fd = udev_monitor_get_fd(mon);
- while (!exit_udev) {
+ while (!exit_monitor.is_set()) {
fd_set fds;
struct timeval tv;
int ret;
@@ -155,17 +178,18 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
select() ensured that this will not block. */
dev = udev_monitor_receive_device(mon);
- if (dev && udev_device_get_devnode(dev) != 0) {
+ if (dev && udev_device_get_devnode(dev) != nullptr) {
MutexLock lock(joy_mutex);
String action = udev_device_get_action(dev);
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
if (devnode_str.find(ignore_str) == -1) {
- if (action == "add")
+ if (action == "add") {
open_joypad(devnode);
- else if (String(action) == "remove")
+ } else if (String(action) == "remove") {
close_joypad(get_joy_from_path(devnode));
+ }
}
}
@@ -179,7 +203,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
#endif
void JoypadLinux::monitor_joypads() {
- while (!exit_udev) {
+ while (!exit_monitor.is_set()) {
{
MutexLock lock(joy_mutex);
@@ -189,7 +213,7 @@ void JoypadLinux::monitor_joypads() {
struct dirent *current;
char fname[64];
- while ((current = readdir(input_directory)) != NULL) {
+ while ((current = readdir(input_directory)) != nullptr) {
if (strncmp(current->d_name, "event", 5) != 0) {
continue;
}
@@ -405,10 +429,10 @@ void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
joy.ff_effect_timestamp = p_timestamp;
}
-Input::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+Input::JoyAxisValue JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
int min = p_abs->minimum;
int max = p_abs->maximum;
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
if (min < 0) {
jx.min = -1;
@@ -490,7 +514,7 @@ void JoypadLinux::process_joypads() {
return;
}
if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
- Input::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
+ Input::JoyAxisValue value = axis_correct(joy->abs_info[ev.code], ev.value);
joy->curr_axis[joy->abs_map[ev.code]] = value;
}
break;
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
index bf343b7ceb..177d7a51ce 100644
--- a/platform/linuxbsd/joypad_linux.h
+++ b/platform/linuxbsd/joypad_linux.h
@@ -53,7 +53,7 @@ private:
};
struct Joypad {
- Input::JoyAxis curr_axis[MAX_ABS];
+ Input::JoyAxisValue curr_axis[MAX_ABS];
int key_map[MAX_KEY];
int abs_map[MAX_ABS];
int dpad = 0;
@@ -70,10 +70,13 @@ private:
void reset();
};
- bool exit_udev;
+#ifdef UDEV_ENABLED
+ bool use_udev = false;
+#endif
+ SafeFlag exit_monitor;
Mutex joy_mutex;
Thread joy_thread;
- Input *input;
+ Input *input = nullptr;
Joypad joypads[JOYPADS_MAX];
Vector<String> attached_devices;
@@ -94,7 +97,7 @@ private:
void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop(int p_id, uint64_t p_timestamp);
- Input::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
+ Input::JoyAxisValue axis_correct(const input_absinfo *p_abs, int p_value) const;
};
#endif
diff --git a/platform/linuxbsd/libudev-so_wrap.c b/platform/linuxbsd/libudev-so_wrap.c
new file mode 100644
index 0000000000..a9fa4a494a
--- /dev/null
+++ b/platform/linuxbsd/libudev-so_wrap.c
@@ -0,0 +1,1013 @@
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:59
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/libudev.h --sys-include <libudev.h> --soname libudev.so.1 --init-name libudev --omit-prefix gnu_ --output-header libudev-so_wrap.h --output-implementation libudev-so_wrap.c
+//
+#include <stdint.h>
+
+#define udev_ref udev_ref_dylibloader_orig_libudev
+#define udev_unref udev_unref_dylibloader_orig_libudev
+#define udev_new udev_new_dylibloader_orig_libudev
+#define udev_set_log_fn udev_set_log_fn_dylibloader_orig_libudev
+#define udev_get_log_priority udev_get_log_priority_dylibloader_orig_libudev
+#define udev_set_log_priority udev_set_log_priority_dylibloader_orig_libudev
+#define udev_get_userdata udev_get_userdata_dylibloader_orig_libudev
+#define udev_set_userdata udev_set_userdata_dylibloader_orig_libudev
+#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_orig_libudev
+#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_orig_libudev
+#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_orig_libudev
+#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_orig_libudev
+#define udev_device_ref udev_device_ref_dylibloader_orig_libudev
+#define udev_device_unref udev_device_unref_dylibloader_orig_libudev
+#define udev_device_get_udev udev_device_get_udev_dylibloader_orig_libudev
+#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_orig_libudev
+#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_orig_libudev
+#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_orig_libudev
+#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_orig_libudev
+#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_orig_libudev
+#define udev_device_get_parent udev_device_get_parent_dylibloader_orig_libudev
+#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_orig_libudev
+#define udev_device_get_devpath udev_device_get_devpath_dylibloader_orig_libudev
+#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_orig_libudev
+#define udev_device_get_devtype udev_device_get_devtype_dylibloader_orig_libudev
+#define udev_device_get_syspath udev_device_get_syspath_dylibloader_orig_libudev
+#define udev_device_get_sysname udev_device_get_sysname_dylibloader_orig_libudev
+#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_orig_libudev
+#define udev_device_get_devnode udev_device_get_devnode_dylibloader_orig_libudev
+#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_orig_libudev
+#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_orig_libudev
+#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_orig_libudev
+#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_orig_libudev
+#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_orig_libudev
+#define udev_device_get_property_value udev_device_get_property_value_dylibloader_orig_libudev
+#define udev_device_get_driver udev_device_get_driver_dylibloader_orig_libudev
+#define udev_device_get_devnum udev_device_get_devnum_dylibloader_orig_libudev
+#define udev_device_get_action udev_device_get_action_dylibloader_orig_libudev
+#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_orig_libudev
+#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_orig_libudev
+#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_orig_libudev
+#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_orig_libudev
+#define udev_device_has_tag udev_device_has_tag_dylibloader_orig_libudev
+#define udev_monitor_ref udev_monitor_ref_dylibloader_orig_libudev
+#define udev_monitor_unref udev_monitor_unref_dylibloader_orig_libudev
+#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_orig_libudev
+#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_orig_libudev
+#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_orig_libudev
+#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_orig_libudev
+#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_orig_libudev
+#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_orig_libudev
+#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_orig_libudev
+#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_orig_libudev
+#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_orig_libudev
+#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_orig_libudev
+#define udev_enumerate_ref udev_enumerate_ref_dylibloader_orig_libudev
+#define udev_enumerate_unref udev_enumerate_unref_dylibloader_orig_libudev
+#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_orig_libudev
+#define udev_enumerate_new udev_enumerate_new_dylibloader_orig_libudev
+#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_orig_libudev
+#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_orig_libudev
+#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_orig_libudev
+#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_orig_libudev
+#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_orig_libudev
+#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_orig_libudev
+#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_orig_libudev
+#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_orig_libudev
+#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_orig_libudev
+#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_orig_libudev
+#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_orig_libudev
+#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_orig_libudev
+#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_orig_libudev
+#define udev_queue_ref udev_queue_ref_dylibloader_orig_libudev
+#define udev_queue_unref udev_queue_unref_dylibloader_orig_libudev
+#define udev_queue_get_udev udev_queue_get_udev_dylibloader_orig_libudev
+#define udev_queue_new udev_queue_new_dylibloader_orig_libudev
+#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_orig_libudev
+#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_orig_libudev
+#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_orig_libudev
+#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_orig_libudev
+#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_orig_libudev
+#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_orig_libudev
+#define udev_queue_get_fd udev_queue_get_fd_dylibloader_orig_libudev
+#define udev_queue_flush udev_queue_flush_dylibloader_orig_libudev
+#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_orig_libudev
+#define udev_hwdb_new udev_hwdb_new_dylibloader_orig_libudev
+#define udev_hwdb_ref udev_hwdb_ref_dylibloader_orig_libudev
+#define udev_hwdb_unref udev_hwdb_unref_dylibloader_orig_libudev
+#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_orig_libudev
+#define udev_util_encode_string udev_util_encode_string_dylibloader_orig_libudev
+#include <libudev.h>
+#undef udev_ref
+#undef udev_unref
+#undef udev_new
+#undef udev_set_log_fn
+#undef udev_get_log_priority
+#undef udev_set_log_priority
+#undef udev_get_userdata
+#undef udev_set_userdata
+#undef udev_list_entry_get_next
+#undef udev_list_entry_get_by_name
+#undef udev_list_entry_get_name
+#undef udev_list_entry_get_value
+#undef udev_device_ref
+#undef udev_device_unref
+#undef udev_device_get_udev
+#undef udev_device_new_from_syspath
+#undef udev_device_new_from_devnum
+#undef udev_device_new_from_subsystem_sysname
+#undef udev_device_new_from_device_id
+#undef udev_device_new_from_environment
+#undef udev_device_get_parent
+#undef udev_device_get_parent_with_subsystem_devtype
+#undef udev_device_get_devpath
+#undef udev_device_get_subsystem
+#undef udev_device_get_devtype
+#undef udev_device_get_syspath
+#undef udev_device_get_sysname
+#undef udev_device_get_sysnum
+#undef udev_device_get_devnode
+#undef udev_device_get_is_initialized
+#undef udev_device_get_devlinks_list_entry
+#undef udev_device_get_properties_list_entry
+#undef udev_device_get_tags_list_entry
+#undef udev_device_get_sysattr_list_entry
+#undef udev_device_get_property_value
+#undef udev_device_get_driver
+#undef udev_device_get_devnum
+#undef udev_device_get_action
+#undef udev_device_get_seqnum
+#undef udev_device_get_usec_since_initialized
+#undef udev_device_get_sysattr_value
+#undef udev_device_set_sysattr_value
+#undef udev_device_has_tag
+#undef udev_monitor_ref
+#undef udev_monitor_unref
+#undef udev_monitor_get_udev
+#undef udev_monitor_new_from_netlink
+#undef udev_monitor_enable_receiving
+#undef udev_monitor_set_receive_buffer_size
+#undef udev_monitor_get_fd
+#undef udev_monitor_receive_device
+#undef udev_monitor_filter_add_match_subsystem_devtype
+#undef udev_monitor_filter_add_match_tag
+#undef udev_monitor_filter_update
+#undef udev_monitor_filter_remove
+#undef udev_enumerate_ref
+#undef udev_enumerate_unref
+#undef udev_enumerate_get_udev
+#undef udev_enumerate_new
+#undef udev_enumerate_add_match_subsystem
+#undef udev_enumerate_add_nomatch_subsystem
+#undef udev_enumerate_add_match_sysattr
+#undef udev_enumerate_add_nomatch_sysattr
+#undef udev_enumerate_add_match_property
+#undef udev_enumerate_add_match_sysname
+#undef udev_enumerate_add_match_tag
+#undef udev_enumerate_add_match_parent
+#undef udev_enumerate_add_match_is_initialized
+#undef udev_enumerate_add_syspath
+#undef udev_enumerate_scan_devices
+#undef udev_enumerate_scan_subsystems
+#undef udev_enumerate_get_list_entry
+#undef udev_queue_ref
+#undef udev_queue_unref
+#undef udev_queue_get_udev
+#undef udev_queue_new
+#undef udev_queue_get_kernel_seqnum
+#undef udev_queue_get_udev_seqnum
+#undef udev_queue_get_udev_is_active
+#undef udev_queue_get_queue_is_empty
+#undef udev_queue_get_seqnum_is_finished
+#undef udev_queue_get_seqnum_sequence_is_finished
+#undef udev_queue_get_fd
+#undef udev_queue_flush
+#undef udev_queue_get_queued_list_entry
+#undef udev_hwdb_new
+#undef udev_hwdb_ref
+#undef udev_hwdb_unref
+#undef udev_hwdb_get_properties_list_entry
+#undef udev_util_encode_string
+#include <dlfcn.h>
+#include <stdio.h>
+struct udev* (*udev_ref_dylibloader_wrapper_libudev)(struct udev*);
+struct udev* (*udev_unref_dylibloader_wrapper_libudev)(struct udev*);
+struct udev* (*udev_new_dylibloader_wrapper_libudev)( void);
+void (*udev_set_log_fn_dylibloader_wrapper_libudev)(struct udev*, void*);
+int (*udev_get_log_priority_dylibloader_wrapper_libudev)(struct udev*);
+void (*udev_set_log_priority_dylibloader_wrapper_libudev)(struct udev*, int);
+void* (*udev_get_userdata_dylibloader_wrapper_libudev)(struct udev*);
+void (*udev_set_userdata_dylibloader_wrapper_libudev)(struct udev*, void*);
+struct udev_list_entry* (*udev_list_entry_get_next_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+struct udev_list_entry* (*udev_list_entry_get_by_name_dylibloader_wrapper_libudev)(struct udev_list_entry*,const char*);
+const char* (*udev_list_entry_get_name_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+const char* (*udev_list_entry_get_value_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+struct udev_device* (*udev_device_ref_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_device* (*udev_device_unref_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev* (*udev_device_get_udev_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_device* (*udev_device_new_from_syspath_dylibloader_wrapper_libudev)(struct udev*,const char*);
+struct udev_device* (*udev_device_new_from_devnum_dylibloader_wrapper_libudev)(struct udev*, char, dev_t);
+struct udev_device* (*udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev)(struct udev*,const char*,const char*);
+struct udev_device* (*udev_device_new_from_device_id_dylibloader_wrapper_libudev)(struct udev*,const char*);
+struct udev_device* (*udev_device_new_from_environment_dylibloader_wrapper_libudev)(struct udev*);
+struct udev_device* (*udev_device_get_parent_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_device* (*udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*);
+const char* (*udev_device_get_devpath_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_subsystem_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_devtype_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_syspath_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_sysname_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_sysnum_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_devnode_dylibloader_wrapper_libudev)(struct udev_device*);
+int (*udev_device_get_is_initialized_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_list_entry* (*udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_list_entry* (*udev_device_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_list_entry* (*udev_device_get_tags_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+struct udev_list_entry* (*udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_property_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+const char* (*udev_device_get_driver_dylibloader_wrapper_libudev)(struct udev_device*);
+dev_t (*udev_device_get_devnum_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_action_dylibloader_wrapper_libudev)(struct udev_device*);
+unsigned long long int (*udev_device_get_seqnum_dylibloader_wrapper_libudev)(struct udev_device*);
+unsigned long long int (*udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev)(struct udev_device*);
+const char* (*udev_device_get_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+int (*udev_device_set_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*);
+int (*udev_device_has_tag_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+struct udev_monitor* (*udev_monitor_ref_dylibloader_wrapper_libudev)(struct udev_monitor*);
+struct udev_monitor* (*udev_monitor_unref_dylibloader_wrapper_libudev)(struct udev_monitor*);
+struct udev* (*udev_monitor_get_udev_dylibloader_wrapper_libudev)(struct udev_monitor*);
+struct udev_monitor* (*udev_monitor_new_from_netlink_dylibloader_wrapper_libudev)(struct udev*,const char*);
+int (*udev_monitor_enable_receiving_dylibloader_wrapper_libudev)(struct udev_monitor*);
+int (*udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev)(struct udev_monitor*, int);
+int (*udev_monitor_get_fd_dylibloader_wrapper_libudev)(struct udev_monitor*);
+struct udev_device* (*udev_monitor_receive_device_dylibloader_wrapper_libudev)(struct udev_monitor*);
+int (*udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*,const char*);
+int (*udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*);
+int (*udev_monitor_filter_update_dylibloader_wrapper_libudev)(struct udev_monitor*);
+int (*udev_monitor_filter_remove_dylibloader_wrapper_libudev)(struct udev_monitor*);
+struct udev_enumerate* (*udev_enumerate_ref_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+struct udev_enumerate* (*udev_enumerate_unref_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+struct udev* (*udev_enumerate_get_udev_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+struct udev_enumerate* (*udev_enumerate_new_dylibloader_wrapper_libudev)(struct udev*);
+int (*udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+int (*udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+int (*udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+int (*udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+int (*udev_enumerate_add_match_property_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+int (*udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+int (*udev_enumerate_add_match_tag_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+int (*udev_enumerate_add_match_parent_dylibloader_wrapper_libudev)(struct udev_enumerate*,struct udev_device*);
+int (*udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+int (*udev_enumerate_add_syspath_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+int (*udev_enumerate_scan_devices_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+int (*udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+struct udev_list_entry* (*udev_enumerate_get_list_entry_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+struct udev_queue* (*udev_queue_ref_dylibloader_wrapper_libudev)(struct udev_queue*);
+struct udev_queue* (*udev_queue_unref_dylibloader_wrapper_libudev)(struct udev_queue*);
+struct udev* (*udev_queue_get_udev_dylibloader_wrapper_libudev)(struct udev_queue*);
+struct udev_queue* (*udev_queue_new_dylibloader_wrapper_libudev)(struct udev*);
+unsigned long long int (*udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*);
+unsigned long long int (*udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*);
+int (*udev_queue_get_udev_is_active_dylibloader_wrapper_libudev)(struct udev_queue*);
+int (*udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev)(struct udev_queue*);
+int (*udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int);
+int (*udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int, unsigned long long int);
+int (*udev_queue_get_fd_dylibloader_wrapper_libudev)(struct udev_queue*);
+int (*udev_queue_flush_dylibloader_wrapper_libudev)(struct udev_queue*);
+struct udev_list_entry* (*udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev)(struct udev_queue*);
+struct udev_hwdb* (*udev_hwdb_new_dylibloader_wrapper_libudev)(struct udev*);
+struct udev_hwdb* (*udev_hwdb_ref_dylibloader_wrapper_libudev)(struct udev_hwdb*);
+struct udev_hwdb* (*udev_hwdb_unref_dylibloader_wrapper_libudev)(struct udev_hwdb*);
+struct udev_list_entry* (*udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_hwdb*,const char*, unsigned);
+int (*udev_util_encode_string_dylibloader_wrapper_libudev)(const char*, char*, size_t);
+int initialize_libudev(int verbose) {
+ void *handle;
+ char *error;
+ handle = dlopen("libudev.so.1", RTLD_LAZY);
+ if (!handle) {
+ if (verbose) {
+ fprintf(stderr, "%s\n", dlerror());
+ }
+ return(1);
+ }
+ dlerror();
+// udev_ref
+ *(void **) (&udev_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_unref
+ *(void **) (&udev_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_new
+ *(void **) (&udev_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_set_log_fn
+ *(void **) (&udev_set_log_fn_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_log_fn");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_get_log_priority
+ *(void **) (&udev_get_log_priority_dylibloader_wrapper_libudev) = dlsym(handle, "udev_get_log_priority");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_set_log_priority
+ *(void **) (&udev_set_log_priority_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_log_priority");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_get_userdata
+ *(void **) (&udev_get_userdata_dylibloader_wrapper_libudev) = dlsym(handle, "udev_get_userdata");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_set_userdata
+ *(void **) (&udev_set_userdata_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_userdata");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_list_entry_get_next
+ *(void **) (&udev_list_entry_get_next_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_next");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_list_entry_get_by_name
+ *(void **) (&udev_list_entry_get_by_name_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_list_entry_get_name
+ *(void **) (&udev_list_entry_get_name_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_list_entry_get_value
+ *(void **) (&udev_list_entry_get_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_ref
+ *(void **) (&udev_device_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_unref
+ *(void **) (&udev_device_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_udev
+ *(void **) (&udev_device_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_udev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_new_from_syspath
+ *(void **) (&udev_device_new_from_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_syspath");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_new_from_devnum
+ *(void **) (&udev_device_new_from_devnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_devnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_new_from_subsystem_sysname
+ *(void **) (&udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_subsystem_sysname");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_new_from_device_id
+ *(void **) (&udev_device_new_from_device_id_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_device_id");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_new_from_environment
+ *(void **) (&udev_device_new_from_environment_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_environment");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_parent
+ *(void **) (&udev_device_get_parent_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_parent");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_parent_with_subsystem_devtype
+ *(void **) (&udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_parent_with_subsystem_devtype");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_devpath
+ *(void **) (&udev_device_get_devpath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devpath");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_subsystem
+ *(void **) (&udev_device_get_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_subsystem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_devtype
+ *(void **) (&udev_device_get_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devtype");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_syspath
+ *(void **) (&udev_device_get_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_syspath");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_sysname
+ *(void **) (&udev_device_get_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysname");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_sysnum
+ *(void **) (&udev_device_get_sysnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_devnode
+ *(void **) (&udev_device_get_devnode_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devnode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_is_initialized
+ *(void **) (&udev_device_get_is_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_is_initialized");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_devlinks_list_entry
+ *(void **) (&udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devlinks_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_properties_list_entry
+ *(void **) (&udev_device_get_properties_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_properties_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_tags_list_entry
+ *(void **) (&udev_device_get_tags_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_tags_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_sysattr_list_entry
+ *(void **) (&udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysattr_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_property_value
+ *(void **) (&udev_device_get_property_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_property_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_driver
+ *(void **) (&udev_device_get_driver_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_driver");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_devnum
+ *(void **) (&udev_device_get_devnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_action
+ *(void **) (&udev_device_get_action_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_action");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_seqnum
+ *(void **) (&udev_device_get_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_seqnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_usec_since_initialized
+ *(void **) (&udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_usec_since_initialized");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_get_sysattr_value
+ *(void **) (&udev_device_get_sysattr_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysattr_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_set_sysattr_value
+ *(void **) (&udev_device_set_sysattr_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_set_sysattr_value");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_device_has_tag
+ *(void **) (&udev_device_has_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_has_tag");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_ref
+ *(void **) (&udev_monitor_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_unref
+ *(void **) (&udev_monitor_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_get_udev
+ *(void **) (&udev_monitor_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_get_udev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_new_from_netlink
+ *(void **) (&udev_monitor_new_from_netlink_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_new_from_netlink");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_enable_receiving
+ *(void **) (&udev_monitor_enable_receiving_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_enable_receiving");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_set_receive_buffer_size
+ *(void **) (&udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_set_receive_buffer_size");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_get_fd
+ *(void **) (&udev_monitor_get_fd_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_get_fd");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_receive_device
+ *(void **) (&udev_monitor_receive_device_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_receive_device");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_filter_add_match_subsystem_devtype
+ *(void **) (&udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_add_match_subsystem_devtype");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_filter_add_match_tag
+ *(void **) (&udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_add_match_tag");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_filter_update
+ *(void **) (&udev_monitor_filter_update_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_update");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_monitor_filter_remove
+ *(void **) (&udev_monitor_filter_remove_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_remove");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_ref
+ *(void **) (&udev_enumerate_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_unref
+ *(void **) (&udev_enumerate_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_get_udev
+ *(void **) (&udev_enumerate_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_get_udev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_new
+ *(void **) (&udev_enumerate_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_subsystem
+ *(void **) (&udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_subsystem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_nomatch_subsystem
+ *(void **) (&udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_nomatch_subsystem");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_sysattr
+ *(void **) (&udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_sysattr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_nomatch_sysattr
+ *(void **) (&udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_nomatch_sysattr");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_property
+ *(void **) (&udev_enumerate_add_match_property_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_property");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_sysname
+ *(void **) (&udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_sysname");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_tag
+ *(void **) (&udev_enumerate_add_match_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_tag");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_parent
+ *(void **) (&udev_enumerate_add_match_parent_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_parent");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_match_is_initialized
+ *(void **) (&udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_is_initialized");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_add_syspath
+ *(void **) (&udev_enumerate_add_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_syspath");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_scan_devices
+ *(void **) (&udev_enumerate_scan_devices_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_scan_devices");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_scan_subsystems
+ *(void **) (&udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_scan_subsystems");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_enumerate_get_list_entry
+ *(void **) (&udev_enumerate_get_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_get_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_ref
+ *(void **) (&udev_queue_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_unref
+ *(void **) (&udev_queue_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_udev
+ *(void **) (&udev_queue_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_new
+ *(void **) (&udev_queue_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_kernel_seqnum
+ *(void **) (&udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_kernel_seqnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_udev_seqnum
+ *(void **) (&udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev_seqnum");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_udev_is_active
+ *(void **) (&udev_queue_get_udev_is_active_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_queue_is_empty
+ *(void **) (&udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_queue_is_empty");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_seqnum_is_finished
+ *(void **) (&udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_seqnum_is_finished");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_seqnum_sequence_is_finished
+ *(void **) (&udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_seqnum_sequence_is_finished");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_fd
+ *(void **) (&udev_queue_get_fd_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_fd");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_flush
+ *(void **) (&udev_queue_flush_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_flush");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_queue_get_queued_list_entry
+ *(void **) (&udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_queued_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_hwdb_new
+ *(void **) (&udev_hwdb_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_hwdb_ref
+ *(void **) (&udev_hwdb_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_hwdb_unref
+ *(void **) (&udev_hwdb_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_hwdb_get_properties_list_entry
+ *(void **) (&udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_get_properties_list_entry");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// udev_util_encode_string
+ *(void **) (&udev_util_encode_string_dylibloader_wrapper_libudev) = dlsym(handle, "udev_util_encode_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+return 0;
+}
diff --git a/platform/linuxbsd/libudev-so_wrap.h b/platform/linuxbsd/libudev-so_wrap.h
new file mode 100644
index 0000000000..dd43fd1191
--- /dev/null
+++ b/platform/linuxbsd/libudev-so_wrap.h
@@ -0,0 +1,378 @@
+#ifndef DYLIBLOAD_WRAPPER_LIBUDEV
+#define DYLIBLOAD_WRAPPER_LIBUDEV
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:59
+// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/libudev.h --sys-include <libudev.h> --soname libudev.so.1 --init-name libudev --omit-prefix gnu_ --output-header libudev-so_wrap.h --output-implementation libudev-so_wrap.c
+//
+#include <stdint.h>
+
+#define udev_ref udev_ref_dylibloader_orig_libudev
+#define udev_unref udev_unref_dylibloader_orig_libudev
+#define udev_new udev_new_dylibloader_orig_libudev
+#define udev_set_log_fn udev_set_log_fn_dylibloader_orig_libudev
+#define udev_get_log_priority udev_get_log_priority_dylibloader_orig_libudev
+#define udev_set_log_priority udev_set_log_priority_dylibloader_orig_libudev
+#define udev_get_userdata udev_get_userdata_dylibloader_orig_libudev
+#define udev_set_userdata udev_set_userdata_dylibloader_orig_libudev
+#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_orig_libudev
+#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_orig_libudev
+#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_orig_libudev
+#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_orig_libudev
+#define udev_device_ref udev_device_ref_dylibloader_orig_libudev
+#define udev_device_unref udev_device_unref_dylibloader_orig_libudev
+#define udev_device_get_udev udev_device_get_udev_dylibloader_orig_libudev
+#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_orig_libudev
+#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_orig_libudev
+#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_orig_libudev
+#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_orig_libudev
+#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_orig_libudev
+#define udev_device_get_parent udev_device_get_parent_dylibloader_orig_libudev
+#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_orig_libudev
+#define udev_device_get_devpath udev_device_get_devpath_dylibloader_orig_libudev
+#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_orig_libudev
+#define udev_device_get_devtype udev_device_get_devtype_dylibloader_orig_libudev
+#define udev_device_get_syspath udev_device_get_syspath_dylibloader_orig_libudev
+#define udev_device_get_sysname udev_device_get_sysname_dylibloader_orig_libudev
+#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_orig_libudev
+#define udev_device_get_devnode udev_device_get_devnode_dylibloader_orig_libudev
+#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_orig_libudev
+#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_orig_libudev
+#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_orig_libudev
+#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_orig_libudev
+#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_orig_libudev
+#define udev_device_get_property_value udev_device_get_property_value_dylibloader_orig_libudev
+#define udev_device_get_driver udev_device_get_driver_dylibloader_orig_libudev
+#define udev_device_get_devnum udev_device_get_devnum_dylibloader_orig_libudev
+#define udev_device_get_action udev_device_get_action_dylibloader_orig_libudev
+#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_orig_libudev
+#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_orig_libudev
+#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_orig_libudev
+#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_orig_libudev
+#define udev_device_has_tag udev_device_has_tag_dylibloader_orig_libudev
+#define udev_monitor_ref udev_monitor_ref_dylibloader_orig_libudev
+#define udev_monitor_unref udev_monitor_unref_dylibloader_orig_libudev
+#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_orig_libudev
+#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_orig_libudev
+#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_orig_libudev
+#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_orig_libudev
+#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_orig_libudev
+#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_orig_libudev
+#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_orig_libudev
+#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_orig_libudev
+#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_orig_libudev
+#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_orig_libudev
+#define udev_enumerate_ref udev_enumerate_ref_dylibloader_orig_libudev
+#define udev_enumerate_unref udev_enumerate_unref_dylibloader_orig_libudev
+#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_orig_libudev
+#define udev_enumerate_new udev_enumerate_new_dylibloader_orig_libudev
+#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_orig_libudev
+#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_orig_libudev
+#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_orig_libudev
+#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_orig_libudev
+#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_orig_libudev
+#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_orig_libudev
+#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_orig_libudev
+#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_orig_libudev
+#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_orig_libudev
+#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_orig_libudev
+#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_orig_libudev
+#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_orig_libudev
+#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_orig_libudev
+#define udev_queue_ref udev_queue_ref_dylibloader_orig_libudev
+#define udev_queue_unref udev_queue_unref_dylibloader_orig_libudev
+#define udev_queue_get_udev udev_queue_get_udev_dylibloader_orig_libudev
+#define udev_queue_new udev_queue_new_dylibloader_orig_libudev
+#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_orig_libudev
+#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_orig_libudev
+#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_orig_libudev
+#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_orig_libudev
+#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_orig_libudev
+#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_orig_libudev
+#define udev_queue_get_fd udev_queue_get_fd_dylibloader_orig_libudev
+#define udev_queue_flush udev_queue_flush_dylibloader_orig_libudev
+#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_orig_libudev
+#define udev_hwdb_new udev_hwdb_new_dylibloader_orig_libudev
+#define udev_hwdb_ref udev_hwdb_ref_dylibloader_orig_libudev
+#define udev_hwdb_unref udev_hwdb_unref_dylibloader_orig_libudev
+#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_orig_libudev
+#define udev_util_encode_string udev_util_encode_string_dylibloader_orig_libudev
+#include <libudev.h>
+#undef udev_ref
+#undef udev_unref
+#undef udev_new
+#undef udev_set_log_fn
+#undef udev_get_log_priority
+#undef udev_set_log_priority
+#undef udev_get_userdata
+#undef udev_set_userdata
+#undef udev_list_entry_get_next
+#undef udev_list_entry_get_by_name
+#undef udev_list_entry_get_name
+#undef udev_list_entry_get_value
+#undef udev_device_ref
+#undef udev_device_unref
+#undef udev_device_get_udev
+#undef udev_device_new_from_syspath
+#undef udev_device_new_from_devnum
+#undef udev_device_new_from_subsystem_sysname
+#undef udev_device_new_from_device_id
+#undef udev_device_new_from_environment
+#undef udev_device_get_parent
+#undef udev_device_get_parent_with_subsystem_devtype
+#undef udev_device_get_devpath
+#undef udev_device_get_subsystem
+#undef udev_device_get_devtype
+#undef udev_device_get_syspath
+#undef udev_device_get_sysname
+#undef udev_device_get_sysnum
+#undef udev_device_get_devnode
+#undef udev_device_get_is_initialized
+#undef udev_device_get_devlinks_list_entry
+#undef udev_device_get_properties_list_entry
+#undef udev_device_get_tags_list_entry
+#undef udev_device_get_sysattr_list_entry
+#undef udev_device_get_property_value
+#undef udev_device_get_driver
+#undef udev_device_get_devnum
+#undef udev_device_get_action
+#undef udev_device_get_seqnum
+#undef udev_device_get_usec_since_initialized
+#undef udev_device_get_sysattr_value
+#undef udev_device_set_sysattr_value
+#undef udev_device_has_tag
+#undef udev_monitor_ref
+#undef udev_monitor_unref
+#undef udev_monitor_get_udev
+#undef udev_monitor_new_from_netlink
+#undef udev_monitor_enable_receiving
+#undef udev_monitor_set_receive_buffer_size
+#undef udev_monitor_get_fd
+#undef udev_monitor_receive_device
+#undef udev_monitor_filter_add_match_subsystem_devtype
+#undef udev_monitor_filter_add_match_tag
+#undef udev_monitor_filter_update
+#undef udev_monitor_filter_remove
+#undef udev_enumerate_ref
+#undef udev_enumerate_unref
+#undef udev_enumerate_get_udev
+#undef udev_enumerate_new
+#undef udev_enumerate_add_match_subsystem
+#undef udev_enumerate_add_nomatch_subsystem
+#undef udev_enumerate_add_match_sysattr
+#undef udev_enumerate_add_nomatch_sysattr
+#undef udev_enumerate_add_match_property
+#undef udev_enumerate_add_match_sysname
+#undef udev_enumerate_add_match_tag
+#undef udev_enumerate_add_match_parent
+#undef udev_enumerate_add_match_is_initialized
+#undef udev_enumerate_add_syspath
+#undef udev_enumerate_scan_devices
+#undef udev_enumerate_scan_subsystems
+#undef udev_enumerate_get_list_entry
+#undef udev_queue_ref
+#undef udev_queue_unref
+#undef udev_queue_get_udev
+#undef udev_queue_new
+#undef udev_queue_get_kernel_seqnum
+#undef udev_queue_get_udev_seqnum
+#undef udev_queue_get_udev_is_active
+#undef udev_queue_get_queue_is_empty
+#undef udev_queue_get_seqnum_is_finished
+#undef udev_queue_get_seqnum_sequence_is_finished
+#undef udev_queue_get_fd
+#undef udev_queue_flush
+#undef udev_queue_get_queued_list_entry
+#undef udev_hwdb_new
+#undef udev_hwdb_ref
+#undef udev_hwdb_unref
+#undef udev_hwdb_get_properties_list_entry
+#undef udev_util_encode_string
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define udev_ref udev_ref_dylibloader_wrapper_libudev
+#define udev_unref udev_unref_dylibloader_wrapper_libudev
+#define udev_new udev_new_dylibloader_wrapper_libudev
+#define udev_set_log_fn udev_set_log_fn_dylibloader_wrapper_libudev
+#define udev_get_log_priority udev_get_log_priority_dylibloader_wrapper_libudev
+#define udev_set_log_priority udev_set_log_priority_dylibloader_wrapper_libudev
+#define udev_get_userdata udev_get_userdata_dylibloader_wrapper_libudev
+#define udev_set_userdata udev_set_userdata_dylibloader_wrapper_libudev
+#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_wrapper_libudev
+#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_wrapper_libudev
+#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_wrapper_libudev
+#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_wrapper_libudev
+#define udev_device_ref udev_device_ref_dylibloader_wrapper_libudev
+#define udev_device_unref udev_device_unref_dylibloader_wrapper_libudev
+#define udev_device_get_udev udev_device_get_udev_dylibloader_wrapper_libudev
+#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_wrapper_libudev
+#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_wrapper_libudev
+#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev
+#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_wrapper_libudev
+#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_wrapper_libudev
+#define udev_device_get_parent udev_device_get_parent_dylibloader_wrapper_libudev
+#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev
+#define udev_device_get_devpath udev_device_get_devpath_dylibloader_wrapper_libudev
+#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_wrapper_libudev
+#define udev_device_get_devtype udev_device_get_devtype_dylibloader_wrapper_libudev
+#define udev_device_get_syspath udev_device_get_syspath_dylibloader_wrapper_libudev
+#define udev_device_get_sysname udev_device_get_sysname_dylibloader_wrapper_libudev
+#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_wrapper_libudev
+#define udev_device_get_devnode udev_device_get_devnode_dylibloader_wrapper_libudev
+#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_wrapper_libudev
+#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev
+#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_wrapper_libudev
+#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_wrapper_libudev
+#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev
+#define udev_device_get_property_value udev_device_get_property_value_dylibloader_wrapper_libudev
+#define udev_device_get_driver udev_device_get_driver_dylibloader_wrapper_libudev
+#define udev_device_get_devnum udev_device_get_devnum_dylibloader_wrapper_libudev
+#define udev_device_get_action udev_device_get_action_dylibloader_wrapper_libudev
+#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_wrapper_libudev
+#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev
+#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_wrapper_libudev
+#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_wrapper_libudev
+#define udev_device_has_tag udev_device_has_tag_dylibloader_wrapper_libudev
+#define udev_monitor_ref udev_monitor_ref_dylibloader_wrapper_libudev
+#define udev_monitor_unref udev_monitor_unref_dylibloader_wrapper_libudev
+#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_wrapper_libudev
+#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_wrapper_libudev
+#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_wrapper_libudev
+#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev
+#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_wrapper_libudev
+#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_wrapper_libudev
+#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev
+#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev
+#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_wrapper_libudev
+#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_wrapper_libudev
+#define udev_enumerate_ref udev_enumerate_ref_dylibloader_wrapper_libudev
+#define udev_enumerate_unref udev_enumerate_unref_dylibloader_wrapper_libudev
+#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_wrapper_libudev
+#define udev_enumerate_new udev_enumerate_new_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev
+#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev
+#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_wrapper_libudev
+#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev
+#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_wrapper_libudev
+#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_wrapper_libudev
+#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev
+#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_wrapper_libudev
+#define udev_queue_ref udev_queue_ref_dylibloader_wrapper_libudev
+#define udev_queue_unref udev_queue_unref_dylibloader_wrapper_libudev
+#define udev_queue_get_udev udev_queue_get_udev_dylibloader_wrapper_libudev
+#define udev_queue_new udev_queue_new_dylibloader_wrapper_libudev
+#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev
+#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev
+#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_wrapper_libudev
+#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev
+#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev
+#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev
+#define udev_queue_get_fd udev_queue_get_fd_dylibloader_wrapper_libudev
+#define udev_queue_flush udev_queue_flush_dylibloader_wrapper_libudev
+#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev
+#define udev_hwdb_new udev_hwdb_new_dylibloader_wrapper_libudev
+#define udev_hwdb_ref udev_hwdb_ref_dylibloader_wrapper_libudev
+#define udev_hwdb_unref udev_hwdb_unref_dylibloader_wrapper_libudev
+#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev
+#define udev_util_encode_string udev_util_encode_string_dylibloader_wrapper_libudev
+extern struct udev* (*udev_ref_dylibloader_wrapper_libudev)(struct udev*);
+extern struct udev* (*udev_unref_dylibloader_wrapper_libudev)(struct udev*);
+extern struct udev* (*udev_new_dylibloader_wrapper_libudev)( void);
+extern void (*udev_set_log_fn_dylibloader_wrapper_libudev)(struct udev*, void*);
+extern int (*udev_get_log_priority_dylibloader_wrapper_libudev)(struct udev*);
+extern void (*udev_set_log_priority_dylibloader_wrapper_libudev)(struct udev*, int);
+extern void* (*udev_get_userdata_dylibloader_wrapper_libudev)(struct udev*);
+extern void (*udev_set_userdata_dylibloader_wrapper_libudev)(struct udev*, void*);
+extern struct udev_list_entry* (*udev_list_entry_get_next_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+extern struct udev_list_entry* (*udev_list_entry_get_by_name_dylibloader_wrapper_libudev)(struct udev_list_entry*,const char*);
+extern const char* (*udev_list_entry_get_name_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+extern const char* (*udev_list_entry_get_value_dylibloader_wrapper_libudev)(struct udev_list_entry*);
+extern struct udev_device* (*udev_device_ref_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_device* (*udev_device_unref_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev* (*udev_device_get_udev_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_device* (*udev_device_new_from_syspath_dylibloader_wrapper_libudev)(struct udev*,const char*);
+extern struct udev_device* (*udev_device_new_from_devnum_dylibloader_wrapper_libudev)(struct udev*, char, dev_t);
+extern struct udev_device* (*udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev)(struct udev*,const char*,const char*);
+extern struct udev_device* (*udev_device_new_from_device_id_dylibloader_wrapper_libudev)(struct udev*,const char*);
+extern struct udev_device* (*udev_device_new_from_environment_dylibloader_wrapper_libudev)(struct udev*);
+extern struct udev_device* (*udev_device_get_parent_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_device* (*udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*);
+extern const char* (*udev_device_get_devpath_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_subsystem_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_devtype_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_syspath_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_sysname_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_sysnum_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_devnode_dylibloader_wrapper_libudev)(struct udev_device*);
+extern int (*udev_device_get_is_initialized_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_list_entry* (*udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_list_entry* (*udev_device_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_list_entry* (*udev_device_get_tags_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+extern struct udev_list_entry* (*udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_property_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+extern const char* (*udev_device_get_driver_dylibloader_wrapper_libudev)(struct udev_device*);
+extern dev_t (*udev_device_get_devnum_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_action_dylibloader_wrapper_libudev)(struct udev_device*);
+extern unsigned long long int (*udev_device_get_seqnum_dylibloader_wrapper_libudev)(struct udev_device*);
+extern unsigned long long int (*udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev)(struct udev_device*);
+extern const char* (*udev_device_get_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+extern int (*udev_device_set_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*);
+extern int (*udev_device_has_tag_dylibloader_wrapper_libudev)(struct udev_device*,const char*);
+extern struct udev_monitor* (*udev_monitor_ref_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern struct udev_monitor* (*udev_monitor_unref_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern struct udev* (*udev_monitor_get_udev_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern struct udev_monitor* (*udev_monitor_new_from_netlink_dylibloader_wrapper_libudev)(struct udev*,const char*);
+extern int (*udev_monitor_enable_receiving_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern int (*udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev)(struct udev_monitor*, int);
+extern int (*udev_monitor_get_fd_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern struct udev_device* (*udev_monitor_receive_device_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern int (*udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*,const char*);
+extern int (*udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*);
+extern int (*udev_monitor_filter_update_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern int (*udev_monitor_filter_remove_dylibloader_wrapper_libudev)(struct udev_monitor*);
+extern struct udev_enumerate* (*udev_enumerate_ref_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern struct udev_enumerate* (*udev_enumerate_unref_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern struct udev* (*udev_enumerate_get_udev_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern struct udev_enumerate* (*udev_enumerate_new_dylibloader_wrapper_libudev)(struct udev*);
+extern int (*udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+extern int (*udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+extern int (*udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+extern int (*udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+extern int (*udev_enumerate_add_match_property_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*);
+extern int (*udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+extern int (*udev_enumerate_add_match_tag_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+extern int (*udev_enumerate_add_match_parent_dylibloader_wrapper_libudev)(struct udev_enumerate*,struct udev_device*);
+extern int (*udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern int (*udev_enumerate_add_syspath_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*);
+extern int (*udev_enumerate_scan_devices_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern int (*udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern struct udev_list_entry* (*udev_enumerate_get_list_entry_dylibloader_wrapper_libudev)(struct udev_enumerate*);
+extern struct udev_queue* (*udev_queue_ref_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern struct udev_queue* (*udev_queue_unref_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern struct udev* (*udev_queue_get_udev_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern struct udev_queue* (*udev_queue_new_dylibloader_wrapper_libudev)(struct udev*);
+extern unsigned long long int (*udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern unsigned long long int (*udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern int (*udev_queue_get_udev_is_active_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern int (*udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern int (*udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int);
+extern int (*udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int, unsigned long long int);
+extern int (*udev_queue_get_fd_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern int (*udev_queue_flush_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern struct udev_list_entry* (*udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev)(struct udev_queue*);
+extern struct udev_hwdb* (*udev_hwdb_new_dylibloader_wrapper_libudev)(struct udev*);
+extern struct udev_hwdb* (*udev_hwdb_ref_dylibloader_wrapper_libudev)(struct udev_hwdb*);
+extern struct udev_hwdb* (*udev_hwdb_unref_dylibloader_wrapper_libudev)(struct udev_hwdb*);
+extern struct udev_list_entry* (*udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_hwdb*,const char*, unsigned);
+extern int (*udev_util_encode_string_dylibloader_wrapper_libudev)(const char*, char*, size_t);
+int initialize_libudev(int verbose);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 147ce26779..0f128d504f 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -70,7 +70,7 @@ static uint64_t load_address() {
}
static void handle_crash(int sig) {
- if (OS::get_singleton() == NULL) {
+ if (OS::get_singleton() == nullptr) {
abort();
}
@@ -105,7 +105,7 @@ static void handle_crash(int sig) {
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
int status;
- char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
+ char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
@@ -167,9 +167,9 @@ void CrashHandler::disable() {
return;
#ifdef CRASH_HANDLER_ENABLED
- signal(SIGSEGV, NULL);
- signal(SIGFPE, NULL);
- signal(SIGILL, NULL);
+ signal(SIGSEGV, nullptr);
+ signal(SIGFPE, nullptr);
+ signal(SIGILL, nullptr);
#endif
disabled = true;
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index acea00c5ac..317e79d0ea 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -34,8 +34,8 @@ def get_opts():
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
]
@@ -49,7 +49,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize"])
if env["arch"] != "arm64":
env.Prepend(CCFLAGS=["-msse2"])
@@ -60,7 +60,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"]:
@@ -135,11 +135,16 @@ def configure(env):
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ env.Append(CCFLAGS=["-fsanitize=nullability-return,nullability-arg,function,nullability-assign"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
if env["use_tsan"]:
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 597ebce6ff..9fac99810b 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -93,6 +93,7 @@ public:
List<WarpEvent> warp_events;
NSTimeInterval last_warp = 0;
+ bool ignore_warp = false;
Vector<KeyEvent> key_event_buffer;
int key_event_pos;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 2d43454501..61bb26c2a8 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -829,7 +829,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
mb->set_position(pos);
mb->set_global_position(pos);
mb->set_button_mask(DS_OSX->last_button_state);
- if (index == BUTTON_LEFT && pressed) {
+ if (index == MOUSE_BUTTON_LEFT && pressed) {
mb->set_doubleclick([event clickCount] == 2);
}
@@ -842,10 +842,10 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
if (([event modifierFlags] & NSEventModifierFlagControl)) {
wd.mouse_down_control = true;
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
} else {
wd.mouse_down_control = false;
- _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, true);
}
}
@@ -858,9 +858,9 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
if (wd.mouse_down_control) {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
} else {
- _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, false);
}
}
@@ -871,6 +871,15 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
NSPoint delta = NSMakePoint([event deltaX], [event deltaY]);
NSPoint mpos = [event locationInWindow];
+ if (DS_OSX->ignore_warp) {
+ // Discard late events, before warp
+ if (([event timestamp]) < DS_OSX->last_warp) {
+ return;
+ }
+ DS_OSX->ignore_warp = false;
+ return;
+ }
+
if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED) {
// Discard late events
if (([event timestamp]) < DS_OSX->last_warp) {
@@ -937,7 +946,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
}
- (void)rightMouseDown:(NSEvent *)event {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
}
- (void)rightMouseDragged:(NSEvent *)event {
@@ -945,16 +954,16 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
}
- (void)rightMouseUp:(NSEvent *)event {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
}
- (void)otherMouseDown:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, true);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, true);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, true);
} else {
return;
}
@@ -966,11 +975,11 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
- (void)otherMouseUp:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, false);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, false);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, false);
} else {
return;
}
@@ -1549,10 +1558,10 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy
sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]);
} else {
if (fabs(deltaX)) {
- sendScrollEvent(window_id, 0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 > deltaX ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
}
if (fabs(deltaY)) {
- sendScrollEvent(window_id, 0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 < deltaY ? MOUSE_BUTTON_WHEEL_UP : MOUSE_BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
}
}
}
@@ -1631,7 +1640,7 @@ String DisplayServerOSX::get_name() const {
}
const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const {
- const NSMenu *menu = NULL;
+ const NSMenu *menu = nullptr;
if (p_menu_root == "") {
// Main menu.x
menu = [NSApp mainMenu];
@@ -1646,13 +1655,13 @@ const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const
}
if (menu == apple_menu) {
// Do not allow to change Apple menu.
- return NULL;
+ return nullptr;
}
return menu;
}
NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
- NSMenu *menu = NULL;
+ NSMenu *menu = nullptr;
if (p_menu_root == "") {
// Main menu.
menu = [NSApp mainMenu];
@@ -1669,7 +1678,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
}
if (menu == apple_menu) {
// Do not allow to change Apple menu.
- return NULL;
+ return nullptr;
}
return menu;
}
@@ -2098,6 +2107,8 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
CGAssociateMouseAndMouseCursorPosition(true);
}
+ last_warp = [[NSProcessInfo processInfo] systemUptime];
+ ignore_warp = true;
warp_events.clear();
mouse_mode = p_mode;
}
@@ -3018,7 +3029,7 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) {
return;
}
- if (cursors[p_shape] != NULL) {
+ if (cursors[p_shape] != nullptr) {
[cursors[p_shape] set];
} else {
switch (p_shape) {
@@ -3106,7 +3117,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -3129,7 +3140,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -3191,9 +3202,9 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
[nsimage release];
} else {
// Reset to default system cursor
- if (cursors[p_shape] != NULL) {
+ if (cursors[p_shape] != nullptr) {
[cursors[p_shape] release];
- cursors[p_shape] = NULL;
+ cursors[p_shape] = nullptr;
}
CursorShape c = cursor_shape;
@@ -3748,12 +3759,12 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
// Register to be notified on keyboard layout changes
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
- NULL, keyboard_layout_changed,
- kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+ nullptr, keyboard_layout_changed,
+ kTISNotifySelectedKeyboardInputSourceChanged, nullptr,
CFNotificationSuspensionBehaviorDeliverImmediately);
// Register to be notified on displays arrangement changes
- CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
+ CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, nullptr);
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
@@ -3843,7 +3854,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
context_vulkan = memnew(VulkanContextOSX);
if (context_vulkan->initialize() != OK) {
memdelete(context_vulkan);
- context_vulkan = NULL;
+ context_vulkan = nullptr;
r_error = ERR_CANT_CREATE;
ERR_FAIL_MSG("Could not initialize Vulkan");
}
@@ -3915,8 +3926,8 @@ DisplayServerOSX::~DisplayServerOSX() {
}
#endif
- CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
- CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), nullptr, kTISNotifySelectedKeyboardInputSourceChanged, nullptr);
+ CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, nullptr);
cursors_cache.clear();
}
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 337cfd6808..51204bc8f6 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -56,7 +56,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
@@ -114,7 +114,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("pc");
r_features->push_back("s3tc");
- r_features->push_back("OSX");
+ r_features->push_back("macOS");
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
@@ -155,11 +155,35 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
#ifdef OSX_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/location"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/address_book"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/calendars"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_bluetooth"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_downloads", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ 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::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
@@ -191,7 +215,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
if ((p_source.ptr()[(i + 1) * 4 + p_ch] == cur) && (p_source.ptr()[(i + 2) * 4 + p_ch] == cur)) {
if (buf_size > 0) {
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -217,7 +241,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
buf[buf_size++] = cur;
if (buf_size == 128) {
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -225,7 +249,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
} else {
buf[buf_size++] = cur;
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -235,7 +259,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
int ofs = p_dest.size();
p_dest.resize(p_dest.size() + res_size);
- copymem(&p_dest.write[ofs], result.ptr(), res_size);
+ memcpy(&p_dest.write[ofs], result.ptr(), res_size);
}
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
@@ -294,7 +318,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
memdelete(f);
len += 8;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
encode_uint32(len, &data.write[ofs + 4]);
// Clean up generated file.
@@ -314,7 +338,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
int len = data.size() - ofs;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
encode_uint32(len, &data.write[ofs + 4]);
}
@@ -329,7 +353,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
}
len += 8;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].mask_name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].mask_name, 4);
encode_uint32(len, &data.write[ofs + 4]);
}
}
@@ -437,7 +461,7 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset
return OK;
}
-Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path) {
#ifdef OSX_ENABLED
List<String> args;
@@ -449,9 +473,9 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
args.push_back("runtime");
}
- if ((p_preset->get("codesign/entitlements") != "") && (p_path.get_extension() != "dmg")) {
+ if (p_path.get_extension() != "dmg") {
args.push_back("--entitlements");
- args.push_back(p_preset->get("codesign/entitlements"));
+ args.push_back(p_ent_path);
}
PackedStringArray user_args = p_preset->get("codesign/custom_options");
@@ -463,10 +487,18 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
}
args.push_back("-s");
- args.push_back(p_preset->get("codesign/identity"));
+ if (p_preset->get("codesign/identity") == "") {
+ args.push_back("-");
+ } else {
+ args.push_back(p_preset->get("codesign/identity"));
+ }
args.push_back("-v"); /* provide some more feedback */
+ if (p_preset->get("codesign/replace_existing_signature")) {
+ args.push_back("-f");
+ }
+
args.push_back(p_path);
String str;
@@ -607,6 +639,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Now process our template.
bool found_binary = false;
int total_size = 0;
+ Vector<String> dylibs_found;
while (ret == UNZ_OK && err == OK) {
bool is_execute = false;
@@ -678,14 +711,18 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name + "/");
+ file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/");
}
if (file.find("/data.mono.osx.64.release/") != -1) {
if (p_debug) {
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name + "/");
+ file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/");
+ }
+
+ if (file.ends_with(".dylib")) {
+ dylibs_found.push_back(file);
}
print_line("ADDING: " + file + " size: " + itos(data.size()));
@@ -735,22 +772,149 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// See if we can code sign our new package.
bool sign_enabled = p_preset->get("codesign/enable");
+ String ent_path = p_preset->get("codesign/entitlements/custom_file");
+ if (sign_enabled && (ent_path == "")) {
+ ent_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
+
+ FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
+ if (ent_f) {
+ ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ ent_f->store_line("<plist version=\"1.0\">");
+ ent_f->store_line("<dict>");
+ if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) {
+ ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) {
+ ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/audio_input")) {
+ ent_f->store_line("<key>com.apple.security.device.audio-input</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/camera")) {
+ ent_f->store_line("<key>com.apple.security.device.camera</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/location")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.location</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/address_book")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.addressbook</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/calendars")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.calendars</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/photos_library")) {
+ ent_f->store_line("<key>com.apple.security.personal-information.photos-library</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/apple_events")) {
+ ent_f->store_line("<key>com.apple.security.automation.apple-events</key>");
+ ent_f->store_line("<true/>");
+ }
+
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) {
+ ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
+ ent_f->store_line("<true/>");
+
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_server")) {
+ ent_f->store_line("<key>com.apple.security.network.server</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/network_client")) {
+ ent_f->store_line("<key>com.apple.security.network.client</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_usb")) {
+ ent_f->store_line("<key>com.apple.security.device.usb</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((bool)p_preset->get("codesign/entitlements/app_sandbox/device_bluetooth")) {
+ ent_f->store_line("<key>com.apple.security.device.bluetooth</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.downloads.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_downloads") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.downloads.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.pictures.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_pictures") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.pictures.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.music.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_music") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.music.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 1) {
+ ent_f->store_line("<key>com.apple.security.files.movies.read-only</key>");
+ ent_f->store_line("<true/>");
+ }
+ if ((int)p_preset->get("codesign/entitlements/app_sandbox/files_movies") == 2) {
+ ent_f->store_line("<key>com.apple.security.files.movies.read-write</key>");
+ ent_f->store_line("<true/>");
+ }
+ }
+
+ ent_f->store_line("</dict>");
+ ent_f->store_line("</plist>");
+
+ ent_f->close();
+ memdelete(ent_f);
+ } else {
+ err = ERR_CANT_CREATE;
+ }
+ }
+
if (err == OK) {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file(), ent_path);
}
}
memdelete(da);
}
+ if (sign_enabled) {
+ for (int i = 0; i < dylibs_found.size(); i++) {
+ if (err == OK) {
+ err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path);
+ }
+ }
+ }
+
if (err == OK && sign_enabled) {
if (ep.step("Code signing bundle", 2)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name, ent_path);
}
if (export_format == "dmg") {
@@ -766,7 +930,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (ep.step("Code signing DMG", 3)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, p_path);
+ err = _code_sign(p_preset, p_path, ent_path);
}
} else {
// Create ZIP.
@@ -900,12 +1064,6 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset
}
bool sign_enabled = p_preset->get("codesign/enable");
- if (sign_enabled) {
- if (p_preset->get("codesign/identity") == "") {
- err += TTR("Codesign: identity not specified.") + "\n";
- valid = false;
- }
- }
bool noto_enabled = p_preset->get("notarization/enable");
if (noto_enabled) {
if (!sign_enabled) {
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index 0b6a0e20a6..b12526915f 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -433,8 +433,8 @@ void JoypadOSX::poll_joypads() const {
}
}
-static const Input::JoyAxis axis_correct(int p_value, int p_min, int p_max) {
- Input::JoyAxis jx;
+static const Input::JoyAxisValue axis_correct(int p_value, int p_min, int p_max) {
+ Input::JoyAxisValue jx;
if (p_min < 0) {
jx.min = -1;
if (p_value < 0) {
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 7b5daf5bfb..e6feda5a9b 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -101,7 +101,7 @@ String OS_OSX::get_unique_id() const {
if (serial_number.is_empty()) {
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
- CFStringRef serialNumberAsCFString = NULL;
+ CFStringRef serialNumberAsCFString = nullptr;
if (platformExpert) {
serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
IOObjectRelease(platformExpert);
@@ -158,7 +158,7 @@ void OS_OSX::delete_main_loop() {
if (!main_loop)
return;
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
}
String OS_OSX::get_name() const {
@@ -346,7 +346,7 @@ Error OS_OSX::move_to_trash(const String &p_path) {
}
OS_OSX::OS_OSX() {
- main_loop = NULL;
+ main_loop = nullptr;
force_quit = false;
Vector<Logger *> loggers;
diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm
index 75a4fc990f..6b87fbd489 100644
--- a/platform/osx/vulkan_context_osx.mm
+++ b/platform/osx/vulkan_context_osx.mm
@@ -38,12 +38,12 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const {
Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height) {
VkMacOSSurfaceCreateInfoMVK createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
- createInfo.pNext = NULL;
+ createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pView = p_window;
VkSurfaceKHR surface;
- VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface);
+ VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return _window_create(p_window_id, surface, p_width, p_height);
}
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 1c3fa990fe..478bcad212 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -35,9 +35,10 @@ def get_opts():
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_coverage", "Test Godot coverage", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
+ BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
@@ -55,7 +56,7 @@ def configure(env):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O3"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"]:
@@ -64,7 +65,7 @@ def configure(env):
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Prepend(CCFLAGS=["-O2"])
- else: # optimize for size
+ elif env["optimize"] == "size": # optimize for size
env.Prepend(CCFLAGS=["-Os"])
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
@@ -93,20 +94,33 @@ def configure(env):
env["CC"] = "clang"
env["CXX"] = "clang++"
env.extra_suffix = ".llvm" + env.extra_suffix
+ env.Append(LIBS=["atomic"])
if env["use_coverage"]:
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
- if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"]:
+ if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]:
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ if env["use_llvm"]:
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change"
+ ]
+ )
+ else:
+ env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
if env["use_lsan"]:
@@ -117,6 +131,12 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
+ if env["use_msan"] and env["use_llvm"]:
+ env.Append(CCFLAGS=["-fsanitize=memory"])
+ env.Append(CCFLAGS=["-fsanitize-memory-track-origins"])
+ env.Append(CCFLAGS=["-fsanitize-recover=memory"])
+ env.Append(LINKFLAGS=["-fsanitize=memory"])
+
if env["use_lto"]:
env.Append(CCFLAGS=["-flto"])
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp
index dc4238bdd4..b7e4361831 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app.cpp
@@ -149,28 +149,28 @@ static int _get_button(Windows::UI::Input::PointerPoint ^ pt) {
using namespace Windows::UI::Input;
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
- return BUTTON_LEFT;
+ return MOUSE_BUTTON_LEFT;
#else
switch (pt->Properties->PointerUpdateKind) {
case PointerUpdateKind::LeftButtonPressed:
case PointerUpdateKind::LeftButtonReleased:
- return BUTTON_LEFT;
+ return MOUSE_BUTTON_LEFT;
case PointerUpdateKind::RightButtonPressed:
case PointerUpdateKind::RightButtonReleased:
- return BUTTON_RIGHT;
+ return MOUSE_BUTTON_RIGHT;
case PointerUpdateKind::MiddleButtonPressed:
case PointerUpdateKind::MiddleButtonReleased:
- return BUTTON_MIDDLE;
+ return MOUSE_BUTTON_MIDDLE;
case PointerUpdateKind::XButton1Pressed:
case PointerUpdateKind::XButton1Released:
- return BUTTON_WHEEL_UP;
+ return MOUSE_BUTTON_WHEEL_UP;
case PointerUpdateKind::XButton2Pressed:
case PointerUpdateKind::XButton2Released:
- return BUTTON_WHEEL_DOWN;
+ return MOUSE_BUTTON_WHEEL_DOWN;
default:
break;
@@ -265,9 +265,9 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor
if (p_is_wheel) {
if (point->Properties->MouseWheelDelta > 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_UP);
} else if (point->Properties->MouseWheelDelta < 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_LEFT : MOUSE_BUTTON_WHEEL_DOWN);
}
}
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index fda8fdec66..28922a4f59 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -54,16 +54,19 @@ def configure(env):
## Build type
if env["target"] == "release":
- env.Append(CCFLAGS=["/O2", "/GL"])
env.Append(CCFLAGS=["/MD"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS", "/LTCG"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["/O2", "/GL"])
+ env.Append(LINKFLAGS=["/LTCG"])
elif env["target"] == "release_debug":
- env.Append(CCFLAGS=["/O2", "/Zi"])
env.Append(CCFLAGS=["/MD"])
- env.Append(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ if env["optimize"] != "none":
+ env.Append(CCFLAGS=["/O2", "/Zi"])
elif env["target"] == "debug":
env.Append(CCFLAGS=["/Zi"])
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 1aad2bfa1a..217c119978 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -855,33 +855,33 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
Vector<uint8_t> data;
- StreamTexture2D *image = nullptr;
+ StreamTexture2D *texture = nullptr;
if (p_path.find("StoreLogo") != -1) {
- image = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
+ texture = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
} else if (p_path.find("Square44x44Logo") != -1) {
- image = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
+ texture = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
} else if (p_path.find("Square71x71Logo") != -1) {
- image = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
+ texture = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
} else if (p_path.find("Square150x150Logo") != -1) {
- image = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
+ texture = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
} else if (p_path.find("Square310x310Logo") != -1) {
- image = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
+ texture = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
} else if (p_path.find("Wide310x150Logo") != -1) {
- image = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
+ texture = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
} else if (p_path.find("SplashScreen") != -1) {
- image = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
+ texture = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
} else {
ERR_PRINT("Unable to load logo");
}
- if (!image) {
+ if (!texture) {
return data;
}
String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
- Error err = image->get_data()->save_png(tmp_path);
+ Error err = texture->get_image()->save_png(tmp_path);
if (err != OK) {
String err_string = "Couldn't save temp logo file.";
@@ -1177,6 +1177,8 @@ public:
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
String src_appx;
EditorProgress ep("export", "Exporting for UWP", 7, true);
@@ -1334,7 +1336,7 @@ public:
int base = clf.size();
clf.resize(base + 4 + txt.length());
encode_uint32(txt.length(), &clf.write[base]);
- copymem(&clf.write[base + 4], txt.ptr(), txt.length());
+ memcpy(&clf.write[base + 4], txt.ptr(), txt.length());
print_line(itos(i) + " param: " + cl[i]);
}
diff --git a/platform/uwp/joypad_uwp.cpp b/platform/uwp/joypad_uwp.cpp
index 5da90db49d..b419fb4fae 100644
--- a/platform/uwp/joypad_uwp.cpp
+++ b/platform/uwp/joypad_uwp.cpp
@@ -134,8 +134,8 @@ void JoypadUWP::OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Inp
input->joy_connection_changed(idx, false, "Xbox Controller");
}
-InputDefault::JoyAxis JoypadUWP::axis_correct(double p_val, bool p_negate, bool p_trigger) const {
- InputDefault::JoyAxis jx;
+InputDefault::JoyAxisValue JoypadUWP::axis_correct(double p_val, bool p_negate, bool p_trigger) const {
+ InputDefault::JoyAxisValue jx;
jx.min = p_trigger ? 0 : -1;
jx.value = (float)(p_negate ? -p_val : p_val);
diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h
index 5df4a211ac..d760d9e2fe 100644
--- a/platform/uwp/joypad_uwp.h
+++ b/platform/uwp/joypad_uwp.h
@@ -73,7 +73,7 @@ private:
void OnGamepadAdded(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
void OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
- InputDefault::JoyAxis axis_correct(double p_val, bool p_negate = false, bool p_trigger = false) const;
+ InputDefault::JoyAxisValue axis_correct(double p_val, bool p_negate = false, bool p_trigger = false) const;
void joypad_vibration_start(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop(int p_device, uint64_t p_timestamp);
};
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 8b60e55d2d..33992069f9 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -44,7 +44,6 @@
#include "platform/windows/windows_terminal_logger.h"
#include "servers/audio_server.h"
#include "servers/rendering/rendering_server_default.h"
-#include "servers/rendering/rendering_server_wrap_mt.h"
#include <ppltasks.h>
#include <wrl.h>
@@ -63,6 +62,8 @@ using namespace Windows::Devices::Sensors;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace concurrency;
+static const float earth_gravity = 9.80665;
+
int OS_UWP::get_video_driver_count() const {
return 2;
}
@@ -373,9 +374,9 @@ void OS_UWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sende
AccelerometerReading ^ reading = args->Reading;
os->input->set_accelerometer(Vector3(
- reading->AccelerationX,
- reading->AccelerationY,
- reading->AccelerationZ));
+ reading->AccelerationX * earth_gravity,
+ reading->AccelerationY * earth_gravity,
+ reading->AccelerationZ * earth_gravity));
}
void OS_UWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, MagnetometerReadingChangedEventArgs ^ args) {
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index e24e466f88..e2d507eddd 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -36,7 +36,7 @@
#ifdef CRASH_HANDLER_EXCEPTION
-// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
+// Backtrace code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
#include <algorithm>
#include <iterator>
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index f26dea8d35..7772ba2dbe 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -72,6 +72,7 @@ def get_opts():
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
+ BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
]
@@ -190,18 +191,20 @@ def configure_msvc(env, manual_msvc_config):
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
- else: # optimize for size
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
- env.Append(LINKFLAGS=["/OPT:REF"])
elif env["target"] == "release_debug":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
- else: # optimize for size
+ env.Append(LINKFLAGS=["/OPT:REF"])
+ elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
- env.Append(LINKFLAGS=["/OPT:REF"])
elif env["target"] == "debug":
env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"])
@@ -306,6 +309,12 @@ def configure_msvc(env, manual_msvc_config):
env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
+ # Sanitizers
+ if env["use_asan"]:
+ env.extra_suffix += ".s"
+ env.Append(LINKFLAGS=["/INFERASANLIBS"])
+ env.Append(CCFLAGS=["/fsanitize=address"])
+
# Incremental linking fix
env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
env["BUILDERS"]["Program"] = methods.precious_program
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 21dfc4ae2c..8789e6dfb4 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -332,7 +332,7 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito
EnumRectData *data = (EnumRectData *)dwData;
if (data->count == data->screen) {
MONITORINFO minfo;
- zeromem(&minfo, sizeof(MONITORINFO));
+ memset(&minfo, 0, sizeof(MONITORINFO));
minfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfoA(hMonitor, &minfo);
@@ -535,7 +535,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
}
#endif
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[p_window].wtctx) {
+ if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window].wtctx) {
wintab_WTClose(windows[p_window].wtctx);
windows[p_window].wtctx = 0;
}
@@ -1253,12 +1253,12 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
- // Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap
+ // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be white pixels of the monochrome bitmap
SetBkColor(hMainDC, clrTransparent);
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
- // Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap
+ // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be black and rest the pixels same as corresponding
// pixels of the source bitmap
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
@@ -1299,7 +1299,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -1322,7 +1322,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -1419,13 +1419,13 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
}
int DisplayServerWindows::keyboard_get_layout_count() const {
- return GetKeyboardLayoutList(0, NULL);
+ return GetKeyboardLayoutList(0, nullptr);
}
int DisplayServerWindows::keyboard_get_current_layout() const {
HKL cur_layout = GetKeyboardLayout(0);
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
GetKeyboardLayoutList(layout_count, layouts);
@@ -1440,7 +1440,7 @@ int DisplayServerWindows::keyboard_get_current_layout() const {
}
void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX(p_index, layout_count);
@@ -1451,7 +1451,7 @@ void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
}
String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX_V(p_index, layout_count, "");
@@ -1481,7 +1481,7 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
DWORD buffer = 1024;
DWORD vtype = REG_SZ;
- if (RegQueryValueExW(hkey, L"Layout Text", NULL, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
+ if (RegQueryValueExW(hkey, L"Layout Text", nullptr, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
ret = String::utf16((const char16_t *)layout_text);
}
RegCloseKey(hkey);
@@ -1489,7 +1489,7 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
}
String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX_V(p_index, layout_count, "");
@@ -2021,7 +2021,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WT_CSRCHANGE:
case WT_PROXIMITY: {
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
+ if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
AXIS pressure;
if (wintab_WTInfo(WTI_DEVICES + windows[window_id].wtlc.lcDevice, DVC_NPRESSURE, &pressure)) {
windows[window_id].min_pressure = int(pressure.axMin);
@@ -2035,7 +2035,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
} break;
case WT_PACKET: {
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
+ if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
PACKET packet;
if (wintab_WTPacket(windows[window_id].wtctx, wParam, &packet)) {
float pressure = float(packet.pkNormalPressure - windows[window_id].min_pressure) / float(windows[window_id].max_pressure - windows[window_id].min_pressure);
@@ -2114,7 +2114,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
- if ((OS::get_singleton()->get_current_tablet_driver() != "winink") || !winink_available) {
+ if ((tablet_get_current_driver() != "winink") || !winink_available) {
break;
}
@@ -2140,7 +2140,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
- if ((OS::get_singleton()->get_current_tablet_driver() != "winink") || !winink_available) {
+ if ((tablet_get_current_driver() != "winink") || !winink_available) {
break;
}
@@ -2304,8 +2304,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_shift((wParam & MK_SHIFT) != 0);
mm->set_alt(alt_mem);
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
- // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not update recently.
+ if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
+ // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently.
if (windows[window_id].last_pressure_update < 10) {
windows[window_id].last_pressure_update++;
} else {
@@ -2431,9 +2431,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0;
if (motion > 0)
- mb->set_button_index(BUTTON_WHEEL_UP);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_UP);
else
- mb->set_button_index(BUTTON_WHEEL_DOWN);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
} break;
case WM_MOUSEHWHEEL: {
@@ -2443,33 +2443,33 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0;
if (motion < 0) {
- mb->set_button_index(BUTTON_WHEEL_LEFT);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
} else {
- mb->set_button_index(BUTTON_WHEEL_RIGHT);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
}
} break;
case WM_XBUTTONDOWN: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
} break;
case WM_XBUTTONUP: {
mb->set_pressed(false);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
} break;
case WM_XBUTTONDBLCLK: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
mb->set_doubleclick(true);
} break;
default: {
@@ -2566,6 +2566,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].preserve_window_size = false;
window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id);
}
+ } else {
+ windows[window_id].preserve_window_size = true;
}
if (!windows[window_id].rect_changed_callback.is_null()) {
@@ -2799,7 +2801,7 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM
alt_mem = false;
}
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) {
+ if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) {
wintab_WTEnable(windows[p_window_id].wtctx, GET_WM_ACTIVATE_STATE(wParam, lParam));
}
}
@@ -3037,7 +3039,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DragAcceptFiles(wd.hWnd, true);
- if ((OS::get_singleton()->get_current_tablet_driver() == "wintab") && wintab_available) {
+ if ((tablet_get_current_driver() == "wintab") && wintab_available) {
wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
wd.wtlc.lcOptions |= CXO_MESSAGES;
wd.wtlc.lcPktData = PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
@@ -3104,6 +3106,40 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2
} SHC_PROCESS_DPI_AWARENESS;
+int DisplayServerWindows::tablet_get_driver_count() const {
+ return tablet_drivers.size();
+}
+
+String DisplayServerWindows::tablet_get_driver_name(int p_driver) const {
+ if (p_driver < 0 || p_driver >= tablet_drivers.size()) {
+ return "";
+ } else {
+ return tablet_drivers[p_driver];
+ }
+}
+
+String DisplayServerWindows::tablet_get_current_driver() const {
+ return tablet_driver;
+}
+
+void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
+ if (tablet_get_driver_count() == 0) {
+ return;
+ }
+ bool found = false;
+ for (int i = 0; i < tablet_get_driver_count(); i++) {
+ if (p_driver == tablet_get_driver_name(i)) {
+ found = true;
+ }
+ }
+ if (found) {
+ _update_tablet_ctx(tablet_driver, p_driver);
+ tablet_driver = p_driver;
+ } else {
+ ERR_PRINT("Unknown tablet driver " + p_driver + ".");
+ }
+}
+
DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
drop_events = false;
key_event_pos = 0;
@@ -3122,6 +3158,35 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
outside = true;
+ //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
+ HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
+ if (wintab_lib) {
+ wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW");
+ wintab_WTClose = (WTClosePtr)GetProcAddress(wintab_lib, "WTClose");
+ wintab_WTInfo = (WTInfoPtr)GetProcAddress(wintab_lib, "WTInfoW");
+ wintab_WTPacket = (WTPacketPtr)GetProcAddress(wintab_lib, "WTPacket");
+ wintab_WTEnable = (WTEnablePtr)GetProcAddress(wintab_lib, "WTEnable");
+
+ wintab_available = wintab_WTOpen && wintab_WTClose && wintab_WTInfo && wintab_WTPacket && wintab_WTEnable;
+ }
+
+ if (wintab_available) {
+ tablet_drivers.push_back("wintab");
+ }
+
+ //Note: Windows Ink API for pen input, available on Windows 8+ only.
+ HMODULE user32_lib = LoadLibraryW(L"user32.dll");
+ if (user32_lib) {
+ win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
+ win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
+
+ winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo;
+ }
+
+ if (winink_available) {
+ tablet_drivers.push_back("winink");
+ }
+
if (OS::get_singleton()->is_hidpi_allowed()) {
HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index c8c6a75bf5..a734077e59 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -264,7 +264,6 @@ class DisplayServerWindows : public DisplayServer {
_THREAD_SAFE_CLASS_
-public:
// WinTab API
static bool wintab_available;
static WTOpenPtr wintab_WTOpen;
@@ -279,8 +278,9 @@ public:
static GetPointerPenInfoPtr win8p_GetPointerPenInfo;
void _update_tablet_ctx(const String &p_old_driver, const String &p_new_driver);
+ String tablet_driver;
+ Vector<String> tablet_drivers;
-private:
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
enum {
@@ -542,6 +542,11 @@ public:
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
+ virtual int tablet_get_driver_count() const;
+ virtual String tablet_get_driver_name(int p_driver) const;
+ virtual String tablet_get_current_driver() const;
+ virtual void tablet_set_current_driver(const String &p_driver);
+
virtual void process_events();
virtual void force_process_and_drop_events();
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index d85dfbc3d3..857c6a88f1 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -10,6 +10,16 @@
</Expand>
</Type>
+ <Type Name="LocalVector&lt;*&gt;">
+ <Expand>
+ <Item Name="[size]">count</Item>
+ <ArrayItems>
+ <Size>count</Size>
+ <ValuePointer>data</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
<Type Name="List&lt;*&gt;">
<Expand>
<Item Name="[size]">_data ? (_data->size_cache) : 0</Item>
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index f46a0dbe2e..da36dc1f2b 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -110,12 +110,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
return false;
}
- dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
- if (!dev_list)
- return false;
+ dev_list = (PRAWINPUTDEVICELIST)memalloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
+ ERR_FAIL_NULL_V_MSG(dev_list, false, "Out of memory.");
if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
- free(dev_list);
+ memfree(dev_list);
return false;
}
for (unsigned int i = 0; i < dev_list_count; i++) {
@@ -130,11 +129,11 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) &&
(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) &&
(strstr(dev_name, "IG_") != nullptr)) {
- free(dev_list);
+ memfree(dev_list);
return true;
}
}
- free(dev_list);
+ memfree(dev_list);
return false;
}
@@ -447,8 +446,8 @@ void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
input->joy_hat(p_device, dpad_val);
};
-Input::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
- Input::JoyAxis jx;
+Input::JoyAxisValue JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+ Input::JoyAxisValue jx;
if (Math::abs(p_val) < MIN_JOY_AXIS) {
jx.min = p_trigger ? 0 : -1;
jx.value = 0.0f;
diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h
index 4727b4a14c..757fb54fb3 100644
--- a/platform/windows/joypad_windows.h
+++ b/platform/windows/joypad_windows.h
@@ -132,7 +132,7 @@ private:
void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
- Input::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
+ Input::JoyAxisValue axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
XInputGetState_t xinput_get_state;
XInputSetState_t xinput_set_state;
};
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index fe007027da..1e9cdd241d 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -45,7 +45,6 @@
#include "platform/windows/display_server_windows.h"
#include "servers/audio_server.h"
#include "servers/rendering/rendering_server_default.h"
-#include "servers/rendering/rendering_server_wrap_mt.h"
#include "windows_terminal_logger.h"
#include <avrt.h>
@@ -335,7 +334,7 @@ OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
}
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
- // For example on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
+ // For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
ret.bias = -info.Bias;
return ret;
}
@@ -766,77 +765,12 @@ Error OS_Windows::move_to_trash(const String &p_path) {
return OK;
}
-int OS_Windows::get_tablet_driver_count() const {
- return tablet_drivers.size();
-}
-
-String OS_Windows::get_tablet_driver_name(int p_driver) const {
- if (p_driver < 0 || p_driver >= tablet_drivers.size()) {
- return "";
- } else {
- return tablet_drivers[p_driver];
- }
-}
-
-String OS_Windows::get_current_tablet_driver() const {
- return tablet_driver;
-}
-
-void OS_Windows::set_current_tablet_driver(const String &p_driver) {
- if (get_tablet_driver_count() == 0) {
- return;
- }
- bool found = false;
- for (int i = 0; i < get_tablet_driver_count(); i++) {
- if (p_driver == get_tablet_driver_name(i)) {
- found = true;
- }
- }
- if (found) {
- if (DisplayServerWindows::get_singleton()) {
- ((DisplayServerWindows *)DisplayServerWindows::get_singleton())->_update_tablet_ctx(tablet_driver, p_driver);
- }
- tablet_driver = p_driver;
- } else {
- ERR_PRINT("Unknown tablet driver " + p_driver + ".");
- }
-}
-
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
ticks_per_second = 0;
ticks_start = 0;
main_loop = nullptr;
process_map = nullptr;
- //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
- HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
- if (wintab_lib) {
- DisplayServerWindows::wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW");
- DisplayServerWindows::wintab_WTClose = (WTClosePtr)GetProcAddress(wintab_lib, "WTClose");
- DisplayServerWindows::wintab_WTInfo = (WTInfoPtr)GetProcAddress(wintab_lib, "WTInfoW");
- DisplayServerWindows::wintab_WTPacket = (WTPacketPtr)GetProcAddress(wintab_lib, "WTPacket");
- DisplayServerWindows::wintab_WTEnable = (WTEnablePtr)GetProcAddress(wintab_lib, "WTEnable");
-
- DisplayServerWindows::wintab_available = DisplayServerWindows::wintab_WTOpen && DisplayServerWindows::wintab_WTClose && DisplayServerWindows::wintab_WTInfo && DisplayServerWindows::wintab_WTPacket && DisplayServerWindows::wintab_WTEnable;
- }
-
- if (DisplayServerWindows::wintab_available) {
- tablet_drivers.push_back("wintab");
- }
-
- //Note: Windows Ink API for pen input, available on Windows 8+ only.
- HMODULE user32_lib = LoadLibraryW(L"user32.dll");
- if (user32_lib) {
- DisplayServerWindows::win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
- DisplayServerWindows::win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
-
- DisplayServerWindows::winink_available = DisplayServerWindows::win8p_GetPointerType && DisplayServerWindows::win8p_GetPointerPenInfo;
- }
-
- if (DisplayServerWindows::winink_available) {
- tablet_drivers.push_back("winink");
- }
-
force_quit = false;
hInstance = _hInstance;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 1a8791196b..8f9ef254f1 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -73,9 +73,6 @@ class OS_Windows : public OS {
HINSTANCE hInstance;
MainLoop *main_loop;
- String tablet_driver;
- Vector<String> tablet_drivers;
-
#ifdef WASAPI_ENABLED
AudioDriverWASAPI driver_wasapi;
#endif
@@ -119,11 +116,6 @@ public:
virtual String get_name() const override;
- virtual int get_tablet_driver_count() const override;
- virtual String get_tablet_driver_name(int p_driver) const override;
- virtual String get_current_tablet_driver() const override;
- virtual void set_current_tablet_driver(const String &p_driver) override;
-
virtual void initialize_joypads() override {}
virtual Date get_date(bool utc) const override;
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 56b620a6d9..c1f3827d15 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -53,7 +53,8 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
if (wlen < 0)
return;
- wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
+ wchar_t *wbuf = (wchar_t *)memalloc((len + 1) * sizeof(wchar_t));
+ ERR_FAIL_NULL_MSG(wbuf, "Out of memory.");
MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen);
wbuf[wlen] = 0;
@@ -62,7 +63,7 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
else
wprintf(L"%ls", wbuf);
- free(wbuf);
+ memfree(wbuf);
#ifdef DEBUG_ENABLED
fflush(stdout);
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 8a6bd5f6b6..9ee37670d1 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -105,214 +105,6 @@ Rect2 AnimatedSprite2D::_get_rect() const {
return Rect2(ofs, s);
}
-void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) {
- E->get().frames.insert(p_at_pos, p_frame);
- } else {
- E->get().frames.push_back(p_frame);
- }
-
- emit_changed();
-}
-
-int SpriteFrames::get_frame_count(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- return E->get().frames.size();
-}
-
-void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- E->get().frames.remove(p_idx);
- emit_changed();
-}
-
-void SpriteFrames::clear(const StringName &p_anim) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
- E->get().frames.clear();
- emit_changed();
-}
-
-void SpriteFrames::clear_all() {
- animations.clear();
- add_animation("default");
-}
-
-void SpriteFrames::add_animation(const StringName &p_anim) {
- ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
-
- animations[p_anim] = Anim();
-}
-
-bool SpriteFrames::has_animation(const StringName &p_anim) const {
- return animations.has(p_anim);
-}
-
-void SpriteFrames::remove_animation(const StringName &p_anim) {
- animations.erase(p_anim);
-}
-
-void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
- ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'.");
- ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists.");
-
- Anim anim = animations[p_prev];
- animations.erase(p_prev);
- animations[p_next] = anim;
-}
-
-Vector<String> SpriteFrames::_get_animation_list() const {
- Vector<String> ret;
- List<StringName> al;
- get_animation_list(&al);
- for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
- ret.push_back(E->get());
- }
-
- return ret;
-}
-
-void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
- for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- r_animations->push_back(E->key());
- }
-}
-
-Vector<String> SpriteFrames::get_animation_names() const {
- Vector<String> names;
- for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- names.push_back(E->key());
- }
- names.sort();
- return names;
-}
-
-void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
- ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().speed = p_fps;
-}
-
-float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().speed;
-}
-
-void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().loop = p_loop;
-}
-
-bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
- return E->get().loop;
-}
-
-void SpriteFrames::_set_frames(const Array &p_frames) {
- clear_all();
- Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
- ERR_FAIL_COND(!E);
-
- E->get().frames.resize(p_frames.size());
- for (int i = 0; i < E->get().frames.size(); i++) {
- E->get().frames.write[i] = p_frames[i];
- }
-}
-
-Array SpriteFrames::_get_frames() const {
- return Array();
-}
-
-Array SpriteFrames::_get_animations() const {
- Array anims;
- for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
- Dictionary d;
- d["name"] = E->key();
- d["speed"] = E->get().speed;
- d["loop"] = E->get().loop;
- Array frames;
- for (int i = 0; i < E->get().frames.size(); i++) {
- frames.push_back(E->get().frames[i]);
- }
- d["frames"] = frames;
- anims.push_back(d);
- }
-
- return anims;
-}
-
-void SpriteFrames::_set_animations(const Array &p_animations) {
- animations.clear();
- for (int i = 0; i < p_animations.size(); i++) {
- Dictionary d = p_animations[i];
-
- ERR_CONTINUE(!d.has("name"));
- ERR_CONTINUE(!d.has("speed"));
- ERR_CONTINUE(!d.has("loop"));
- ERR_CONTINUE(!d.has("frames"));
-
- Anim anim;
- anim.speed = d["speed"];
- anim.loop = d["loop"];
- Array frames = d["frames"];
- for (int j = 0; j < frames.size(); j++) {
- RES res = frames[j];
- anim.frames.push_back(res);
- }
-
- animations[d["name"]] = anim;
- }
-}
-
-void SpriteFrames::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
- ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
- ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
- ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
-
- ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
-
- ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
- ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
-
- ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
- ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
-
- ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
- ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
- ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
- ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
- ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
- ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
-
- ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
- ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
-
- ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
- ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
-}
-
-SpriteFrames::SpriteFrames() {
- add_animation(SceneStringNames::get_singleton()->_default);
-}
-
void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
if (!frames.is_valid()) {
return;
@@ -409,7 +201,7 @@ void AnimatedSprite2D::_notification(int p_what) {
}
update();
- _change_notify("frame");
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -477,10 +269,10 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
set_frame(frame);
}
- _change_notify();
+ notify_property_list_changed();
_reset_timeout();
update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
@@ -510,7 +302,7 @@ void AnimatedSprite2D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
update();
- _change_notify("frame");
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -546,7 +338,6 @@ void AnimatedSprite2D::set_offset(const Point2 &p_offset) {
offset = p_offset;
update();
item_rect_changed();
- _change_notify("offset");
}
Point2 AnimatedSprite2D::get_offset() const {
@@ -573,8 +364,7 @@ bool AnimatedSprite2D::is_flipped_v() const {
void AnimatedSprite2D::_res_changed() {
set_frame(frame);
- _change_notify("frame");
- _change_notify("animation");
+
update();
}
@@ -596,7 +386,7 @@ void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backward
if (p_animation) {
set_animation(p_animation);
- if (backwards && get_frame() == 0) {
+ if (frames.is_valid() && backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -642,7 +432,7 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) {
animation = p_animation;
_reset_timeout();
set_frame(0);
- _change_notify();
+ notify_property_list_changed();
update();
}
@@ -650,17 +440,14 @@ StringName AnimatedSprite2D::get_animation() const {
return animation;
}
-String AnimatedSprite2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
+ warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."));
}
- return warning;
+ return warnings;
}
void AnimatedSprite2D::_bind_methods() {
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 5e53a401e2..ef0027edf1 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -32,74 +32,9 @@
#define ANIMATED_SPRITE_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/resources/sprite_frames.h"
#include "scene/resources/texture.h"
-class SpriteFrames : public Resource {
- GDCLASS(SpriteFrames, Resource);
-
- struct Anim {
- float speed = 5.0;
- bool loop = true;
- Vector<Ref<Texture2D>> frames;
- };
-
- Map<StringName, Anim> animations;
-
- Array _get_frames() const;
- void _set_frames(const Array &p_frames);
-
- Array _get_animations() const;
- void _set_animations(const Array &p_animations);
-
- Vector<String> _get_animation_list() const;
-
-protected:
- static void _bind_methods();
-
-public:
- void add_animation(const StringName &p_anim);
- bool has_animation(const StringName &p_anim) const;
- void remove_animation(const StringName &p_anim);
- void rename_animation(const StringName &p_prev, const StringName &p_next);
-
- void get_animation_list(List<StringName> *r_animations) const;
- Vector<String> get_animation_names() const;
-
- void set_animation_speed(const StringName &p_anim, float p_fps);
- float get_animation_speed(const StringName &p_anim) const;
-
- void set_animation_loop(const StringName &p_anim, bool p_loop);
- bool get_animation_loop(const StringName &p_anim) const;
-
- void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
- int get_frame_count(const StringName &p_anim) const;
- _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
- ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
- if (p_idx >= E->get().frames.size()) {
- return Ref<Texture2D>();
- }
-
- return E->get().frames[p_idx];
- }
-
- void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
- Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- ERR_FAIL_COND(p_idx < 0);
- if (p_idx >= E->get().frames.size()) {
- return;
- }
- E->get().frames.write[p_idx] = p_frame;
- }
- void remove_frame(const StringName &p_anim, int p_idx);
- void clear(const StringName &p_anim);
- void clear_all();
-
- SpriteFrames();
-};
-
class AnimatedSprite2D : public Node2D {
GDCLASS(AnimatedSprite2D, Node2D);
@@ -174,7 +109,7 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite2D();
};
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 68d5b4b540..9dfdd7bd0e 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -450,52 +450,6 @@ bool Area2D::overlaps_body(Node *p_body) const {
return E->get().in_tree;
}
-void Area2D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area2D::get_collision_mask() const {
- return collision_mask;
-}
-
-void Area2D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area2D::get_collision_layer() const {
- return collision_layer;
-}
-
-void Area2D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool Area2D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area2D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t layer = get_collision_layer();
- if (p_value) {
- layer |= 1 << p_bit;
- } else {
- layer &= ~(1 << p_bit);
- }
- set_collision_layer(layer);
-}
-
-bool Area2D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
void Area2D::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
@@ -557,18 +511,6 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area2D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area2D::get_priority);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area2D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area2D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area2D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area2D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area2D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area2D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area2D::set_monitoring);
ClassDB::bind_method(D_METHOD("is_monitoring"), &Area2D::is_monitoring);
@@ -590,16 +532,21 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout);
ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
- ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D")));
+ ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D")));
ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+
+ ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
@@ -607,12 +554,6 @@ void Area2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index 39b022fd2c..d6fcb2c2a5 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -54,8 +54,6 @@ private:
real_t gravity_distance_scale = 0.0;
real_t linear_damp = 0.1;
real_t angular_damp = 1.0;
- uint32_t collision_mask = 1;
- uint32_t collision_layer = 1;
int priority = 0;
bool monitoring = false;
bool monitorable = false;
@@ -163,18 +161,6 @@ public:
void set_monitorable(bool p_enable);
bool is_monitorable() const;
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<Node2D> get_overlapping_bodies() const; //function for script
TypedArray<Area2D> get_overlapping_areas() const; //function for script
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index ae1c1e449a..6d8d6058eb 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -35,14 +35,14 @@
#include "scene/main/window.h"
void AudioStreamPlayer2D::_mix_audio() {
- if (!stream_playback.is_valid() || !active ||
+ if (!stream_playback.is_valid() || !active.is_set() ||
(stream_paused && !stream_paused_fade_out)) {
return;
}
- if (setseek >= 0.0) {
- stream_playback->start(setseek);
- setseek = -1.0; //reset seek
+ if (setseek.get() >= 0.0) {
+ stream_playback->start(setseek.get());
+ setseek.set(-1.0); //reset seek
}
//get data
@@ -57,7 +57,8 @@ void AudioStreamPlayer2D::_mix_audio() {
stream_playback->mix(buffer, pitch_scale, buffer_size);
//write all outputs
- for (int i = 0; i < output_count; i++) {
+ int oc = output_count.get();
+ for (int i = 0; i < oc; i++) {
Output current = outputs[i];
//see if current output exists, to keep volume ramp
@@ -130,14 +131,14 @@ void AudioStreamPlayer2D::_mix_audio() {
prev_outputs[i] = current;
}
- prev_output_count = output_count;
+ prev_output_count = oc;
//stream is no longer active, disable this.
if (!stream_playback->is_playing()) {
- active = false;
+ active.clear();
}
- output_ready = false;
+ output_ready.clear();
stream_paused_fade_in = false;
stream_paused_fade_out = false;
}
@@ -168,7 +169,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
- if (!output_ready) {
+ if (!output_ready.is_set()) {
List<Viewport *> viewports;
Ref<World2D> world_2d = get_world_2d();
ERR_FAIL_COND(world_2d.is_null());
@@ -240,24 +241,20 @@ void AudioStreamPlayer2D::_notification(int p_what) {
}
}
- output_count = new_output_count;
- output_ready = true;
+ output_count.set(new_output_count);
+ output_ready.set();
}
//start playing if requested
- if (setplay >= 0.0) {
- setseek = setplay;
- active = true;
- setplay = -1;
- //do not update, this makes it easier to animate (will shut off otherwise)
- //_change_notify("playing"); //update property in editor
+ if (setplay.get() >= 0.0) {
+ setseek.set(setplay.get());
+ active.set();
+ setplay.set(-1);
}
//stop playing if no longer active
- if (!active) {
+ if (!active.is_set()) {
set_physics_process_internal(false);
- //do not update, this makes it easier to animate (will shut off otherwise)
- //_change_notify("playing"); //update property in editor
emit_signal("finished");
}
}
@@ -271,8 +268,8 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
if (stream_playback.is_valid()) {
stream_playback.unref();
stream.unref();
- active = false;
- setseek = -1;
+ active.clear();
+ setseek.set(-1);
}
if (p_stream.is_valid()) {
@@ -315,30 +312,29 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
}
if (stream_playback.is_valid()) {
- active = true;
- setplay = p_from_pos;
- output_ready = false;
+ setplay.set(p_from_pos);
+ output_ready.clear();
set_physics_process_internal(true);
}
}
void AudioStreamPlayer2D::seek(float p_seconds) {
if (stream_playback.is_valid()) {
- setseek = p_seconds;
+ setseek.set(p_seconds);
}
}
void AudioStreamPlayer2D::stop() {
if (stream_playback.is_valid()) {
- active = false;
+ active.clear();
set_physics_process_internal(false);
- setplay = -1;
+ setplay.set(-1);
}
}
bool AudioStreamPlayer2D::is_playing() const {
if (stream_playback.is_valid()) {
- return active; // && stream_playback->is_playing();
+ return active.is_set() || setplay.get() >= 0;
}
return false;
@@ -346,6 +342,10 @@ bool AudioStreamPlayer2D::is_playing() const {
float AudioStreamPlayer2D::get_playback_position() {
if (stream_playback.is_valid()) {
+ float ss = setseek.get();
+ if (ss >= 0.0) {
+ return ss;
+ }
return stream_playback->get_playback_position();
}
@@ -385,7 +385,7 @@ void AudioStreamPlayer2D::_set_playing(bool p_enable) {
}
bool AudioStreamPlayer2D::_is_active() const {
- return active;
+ return active.is_set();
}
void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
@@ -404,7 +404,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
}
void AudioStreamPlayer2D::_bus_layout_changed() {
- _change_notify();
+ notify_property_list_changed();
}
void AudioStreamPlayer2D::set_max_distance(float p_pixels) {
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index 6fb8cc414c..21f524c703 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -31,6 +31,7 @@
#ifndef AUDIO_STREAM_PLAYER_2D_H
#define AUDIO_STREAM_PLAYER_2D_H
+#include "core/templates/safe_refcount.h"
#include "scene/2d/node_2d.h"
#include "servers/audio/audio_stream.h"
#include "servers/audio_server.h"
@@ -52,8 +53,8 @@ private:
};
Output outputs[MAX_OUTPUTS];
- volatile int output_count = 0;
- volatile bool output_ready = false;
+ SafeNumeric<int> output_count;
+ SafeFlag output_ready;
//these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
Output prev_outputs[MAX_OUTPUTS];
@@ -63,9 +64,9 @@ private:
Ref<AudioStream> stream;
Vector<AudioFrame> mix_buffer;
- volatile float setseek = -1.0;
- volatile bool active = false;
- volatile float setplay = -1.0;
+ SafeNumeric<float> setseek{ -1.0 };
+ SafeFlag active;
+ SafeNumeric<float> setplay{ -1.0 };
float volume_db = 0.0;
float pitch_scale = 1.0;
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 853e92780b..01045502d5 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -63,11 +63,11 @@ void Camera2D::_update_scroll() {
};
}
-void Camera2D::_update_process_mode() {
+void Camera2D::_update_process_callback() {
if (Engine::get_singleton()->is_editor_hint()) {
set_process_internal(false);
set_physics_process_internal(false);
- } else if (process_mode == CAMERA2D_PROCESS_IDLE) {
+ } else if (process_callback == CAMERA2D_PROCESS_IDLE) {
set_process_internal(true);
set_physics_process_internal(false);
} else {
@@ -157,7 +157,7 @@ Transform2D Camera2D::get_camera_transform() {
}
if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
- float c = smoothing * (process_mode == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
+ real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
//camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
@@ -172,7 +172,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
- float angle = get_global_transform().get_rotation();
+ real_t angle = get_global_transform().get_rotation();
if (rotating) {
screen_offset = screen_offset.rotated(angle);
}
@@ -247,7 +247,7 @@ void Camera2D::_notification(int p_what) {
add_to_group(group_name);
add_to_group(canvas_group_name);
- _update_process_mode();
+ _update_process_callback();
_update_scroll();
first = true;
@@ -263,6 +263,7 @@ void Camera2D::_notification(int p_what) {
viewport = nullptr;
} break;
+#ifdef TOOLS_ENABLED
case NOTIFICATION_DRAW: {
if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) {
break;
@@ -270,7 +271,7 @@ void Camera2D::_notification(int p_what) {
if (screen_drawing_enabled) {
Color area_axis_color(0.5, 0.42, 0.87, 0.63);
- float area_axis_width = 1;
+ real_t area_axis_width = 1;
if (is_current()) {
area_axis_width = 3;
area_axis_color.a = 0.83;
@@ -295,7 +296,7 @@ void Camera2D::_notification(int p_what) {
if (limit_drawing_enabled) {
Color limit_drawing_color(1, 1, 0, 0.63);
- float limit_drawing_width = 1;
+ real_t limit_drawing_width = 1;
if (is_current()) {
limit_drawing_color.a = 0.83;
limit_drawing_width = 3;
@@ -317,7 +318,7 @@ void Camera2D::_notification(int p_what) {
if (margin_drawing_enabled) {
Color margin_drawing_color(0, 1, 1, 0.63);
- float margin_drawing_width = 1;
+ real_t margin_drawing_width = 1;
if (is_current()) {
margin_drawing_width = 3;
margin_drawing_color.a = 0.83;
@@ -339,8 +340,8 @@ void Camera2D::_notification(int p_what) {
draw_line(inv_transform.xform(margin_endpoints[i]), inv_transform.xform(margin_endpoints[(i + 1) % 4]), margin_drawing_color, margin_drawing_width);
}
}
-
} break;
+#endif
}
}
@@ -375,17 +376,17 @@ bool Camera2D::is_rotating() const {
return rotating;
}
-void Camera2D::set_process_mode(Camera2DProcessMode p_mode) {
- if (process_mode == p_mode) {
+void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
+ if (process_callback == p_mode) {
return;
}
- process_mode = p_mode;
- _update_process_mode();
+ process_callback = p_mode;
+ _update_process_callback();
}
-Camera2D::Camera2DProcessMode Camera2D::get_process_mode() const {
- return process_mode;
+Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const {
+ return process_callback;
}
void Camera2D::_make_current(Object *p_which) {
@@ -445,13 +446,13 @@ bool Camera2D::is_limit_smoothing_enabled() const {
return limit_smoothing_enabled;
}
-void Camera2D::set_drag_margin(Side p_side, float p_drag_margin) {
+void Camera2D::set_drag_margin(Side p_side, real_t p_drag_margin) {
ERR_FAIL_INDEX((int)p_side, 4);
drag_margin[p_side] = p_drag_margin;
update();
}
-float Camera2D::get_drag_margin(Side p_side) const {
+real_t Camera2D::get_drag_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0);
return drag_margin[p_side];
}
@@ -493,7 +494,7 @@ void Camera2D::align() {
_update_scroll();
}
-void Camera2D::set_follow_smoothing(float p_speed) {
+void Camera2D::set_follow_smoothing(real_t p_speed) {
smoothing = p_speed;
if (smoothing > 0 && !(is_inside_tree() && Engine::get_singleton()->is_editor_hint())) {
set_process_internal(true);
@@ -502,7 +503,7 @@ void Camera2D::set_follow_smoothing(float p_speed) {
}
}
-float Camera2D::get_follow_smoothing() const {
+real_t Camera2D::get_follow_smoothing() const {
return smoothing;
}
@@ -534,7 +535,7 @@ bool Camera2D::is_drag_vertical_enabled() const {
return drag_vertical_enabled;
}
-void Camera2D::set_drag_vertical_offset(float p_offset) {
+void Camera2D::set_drag_vertical_offset(real_t p_offset) {
drag_vertical_offset = p_offset;
drag_vertical_offset_changed = true;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
@@ -542,11 +543,11 @@ void Camera2D::set_drag_vertical_offset(float p_offset) {
smoothed_camera_pos = old_smoothed_camera_pos;
}
-float Camera2D::get_drag_vertical_offset() const {
+real_t Camera2D::get_drag_vertical_offset() const {
return drag_vertical_offset;
}
-void Camera2D::set_drag_horizontal_offset(float p_offset) {
+void Camera2D::set_drag_horizontal_offset(real_t p_offset) {
drag_horizontal_offset = p_offset;
drag_horizontal_offset_changed = true;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
@@ -554,11 +555,11 @@ void Camera2D::set_drag_horizontal_offset(float p_offset) {
smoothed_camera_pos = old_smoothed_camera_pos;
}
-float Camera2D::get_drag_horizontal_offset() const {
+real_t Camera2D::get_drag_horizontal_offset() const {
return drag_horizontal_offset;
}
-void Camera2D::_set_old_smoothing(float p_enable) {
+void Camera2D::_set_old_smoothing(real_t p_enable) {
//compatibility
if (p_enable > 0) {
smoothing_enabled = true;
@@ -568,6 +569,7 @@ void Camera2D::_set_old_smoothing(float p_enable) {
void Camera2D::set_enable_follow_smoothing(bool p_enabled) {
smoothing_enabled = p_enabled;
+ notify_property_list_changed();
}
bool Camera2D::is_follow_smoothing_enabled() const {
@@ -610,7 +612,9 @@ Node *Camera2D::get_custom_viewport() const {
void Camera2D::set_screen_drawing_enabled(bool enable) {
screen_drawing_enabled = enable;
+#ifdef TOOLS_ENABLED
update();
+#endif
}
bool Camera2D::is_screen_drawing_enabled() const {
@@ -619,7 +623,9 @@ bool Camera2D::is_screen_drawing_enabled() const {
void Camera2D::set_limit_drawing_enabled(bool enable) {
limit_drawing_enabled = enable;
+#ifdef TOOLS_ENABLED
update();
+#endif
}
bool Camera2D::is_limit_drawing_enabled() const {
@@ -628,13 +634,21 @@ bool Camera2D::is_limit_drawing_enabled() const {
void Camera2D::set_margin_drawing_enabled(bool enable) {
margin_drawing_enabled = enable;
+#ifdef TOOLS_ENABLED
update();
+#endif
}
bool Camera2D::is_margin_drawing_enabled() const {
return margin_drawing_enabled;
}
+void Camera2D::_validate_property(PropertyInfo &property) const {
+ if (!smoothing_enabled && property.name == "smoothing_speed") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Camera2D::set_offset);
ClassDB::bind_method(D_METHOD("get_offset"), &Camera2D::get_offset);
@@ -651,8 +665,8 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_scroll"), &Camera2D::_update_scroll);
- ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Camera2D::set_process_mode);
- ClassDB::bind_method(D_METHOD("get_process_mode"), &Camera2D::get_process_mode);
+ ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &Camera2D::set_process_callback);
+ ClassDB::bind_method(D_METHOD("get_process_callback"), &Camera2D::get_process_callback);
ClassDB::bind_method(D_METHOD("_set_current", "current"), &Camera2D::_set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current);
@@ -714,7 +728,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
ADD_GROUP("Limit", "limit_");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", SIDE_LEFT);
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 3a7d01901d..7494e526cc 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -43,7 +43,7 @@ public:
ANCHOR_MODE_DRAG_CENTER
};
- enum Camera2DProcessMode {
+ enum Camera2DProcessCallback {
CAMERA2D_PROCESS_PHYSICS,
CAMERA2D_PROCESS_IDLE
};
@@ -65,40 +65,42 @@ protected:
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool rotating = false;
bool current = false;
- float smoothing = 5.0;
+ real_t smoothing = 5.0;
bool smoothing_enabled = false;
int limit[4];
bool limit_smoothing_enabled = false;
- float drag_margin[4];
+ real_t drag_margin[4];
bool drag_horizontal_enabled = false;
bool drag_vertical_enabled = false;
- float drag_horizontal_offset = 0.0;
- float drag_vertical_offset = 0.0;
+ real_t drag_horizontal_offset = 0.0;
+ real_t drag_vertical_offset = 0.0;
bool drag_horizontal_offset_changed = false;
bool drag_vertical_offset_changed = false;
Point2 camera_screen_center;
- void _update_process_mode();
+ void _update_process_callback();
void _update_scroll();
void _make_current(Object *p_which);
void _set_current(bool p_current);
- void _set_old_smoothing(float p_enable);
+ void _set_old_smoothing(real_t p_enable);
bool screen_drawing_enabled = true;
bool limit_drawing_enabled = false;
bool margin_drawing_enabled = false;
- Camera2DProcessMode process_mode = CAMERA2D_PROCESS_IDLE;
+ Camera2DProcessCallback process_callback = CAMERA2D_PROCESS_IDLE;
Size2 _get_camera_screen_size() const;
protected:
virtual Transform2D get_camera_transform();
+
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_offset(const Vector2 &p_offset);
@@ -122,23 +124,23 @@ public:
void set_drag_vertical_enabled(bool p_enabled);
bool is_drag_vertical_enabled() const;
- void set_drag_margin(Side p_side, float p_drag_margin);
- float get_drag_margin(Side p_side) const;
+ void set_drag_margin(Side p_side, real_t p_drag_margin);
+ real_t get_drag_margin(Side p_side) const;
- void set_drag_horizontal_offset(float p_offset);
- float get_drag_horizontal_offset() const;
+ void set_drag_horizontal_offset(real_t p_offset);
+ real_t get_drag_horizontal_offset() const;
- void set_drag_vertical_offset(float p_offset);
- float get_drag_vertical_offset() const;
+ void set_drag_vertical_offset(real_t p_offset);
+ real_t get_drag_vertical_offset() const;
void set_enable_follow_smoothing(bool p_enabled);
bool is_follow_smoothing_enabled() const;
- void set_follow_smoothing(float p_speed);
- float get_follow_smoothing() const;
+ void set_follow_smoothing(real_t p_speed);
+ real_t get_follow_smoothing() const;
- void set_process_mode(Camera2DProcessMode p_mode);
- Camera2DProcessMode get_process_mode() const;
+ void set_process_callback(Camera2DProcessCallback p_mode);
+ Camera2DProcessCallback get_process_callback() const;
void make_current();
void clear_current();
@@ -170,6 +172,6 @@ public:
};
VARIANT_ENUM_CAST(Camera2D::AnchorMode);
-VARIANT_ENUM_CAST(Camera2D::Camera2DProcessMode);
+VARIANT_ENUM_CAST(Camera2D::Camera2DProcessCallback);
#endif // CAMERA_2D_H
diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp
index 0f0e583ea7..ee025b6dfc 100644
--- a/scene/2d/canvas_group.cpp
+++ b/scene/2d/canvas_group.cpp
@@ -30,7 +30,7 @@
#include "canvas_group.h"
-void CanvasGroup::set_fit_margin(float p_fit_margin) {
+void CanvasGroup::set_fit_margin(real_t p_fit_margin) {
ERR_FAIL_COND(p_fit_margin < 0.0);
fit_margin = p_fit_margin;
@@ -39,11 +39,11 @@ void CanvasGroup::set_fit_margin(float p_fit_margin) {
update();
}
-float CanvasGroup::get_fit_margin() const {
+real_t CanvasGroup::get_fit_margin() const {
return fit_margin;
}
-void CanvasGroup::set_clear_margin(float p_clear_margin) {
+void CanvasGroup::set_clear_margin(real_t p_clear_margin) {
ERR_FAIL_COND(p_clear_margin < 0.0);
clear_margin = p_clear_margin;
@@ -52,7 +52,7 @@ void CanvasGroup::set_clear_margin(float p_clear_margin) {
update();
}
-float CanvasGroup::get_clear_margin() const {
+real_t CanvasGroup::get_clear_margin() const {
return clear_margin;
}
diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h
index cecf7c24f4..b487d7a098 100644
--- a/scene/2d/canvas_group.h
+++ b/scene/2d/canvas_group.h
@@ -35,19 +35,19 @@
class CanvasGroup : public Node2D {
GDCLASS(CanvasGroup, Node2D)
- float fit_margin = 10.0;
- float clear_margin = 10.0;
+ real_t fit_margin = 10.0;
+ real_t clear_margin = 10.0;
bool use_mipmaps = false;
protected:
static void _bind_methods();
public:
- void set_fit_margin(float p_fit_margin);
- float get_fit_margin() const;
+ void set_fit_margin(real_t p_fit_margin);
+ real_t get_fit_margin() const;
- void set_clear_margin(float p_clear_margin);
- float get_clear_margin() const;
+ void set_clear_margin(real_t p_clear_margin);
+ real_t get_clear_margin() const;
void set_use_mipmaps(bool p_use_mipmaps);
bool is_using_mipmaps() const;
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 5d5aaae505..52eabefbcb 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -51,7 +51,7 @@ void CanvasModulate::_notification(int p_what) {
remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
}
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -73,24 +73,19 @@ Color CanvasModulate::get_color() const {
return color;
}
-String CanvasModulate::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CanvasModulate::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- List<Node *> nodes;
- get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
+ if (is_visible_in_tree() && is_inside_tree()) {
+ List<Node *> nodes;
+ get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
- if (nodes.size() > 1) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (nodes.size() > 1) {
+ warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."));
}
- warning += TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.");
}
- return warning;
+ return warnings;
}
CanvasModulate::CanvasModulate() {
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
index 4d55a5d9cb..3d85a92a11 100644
--- a/scene/2d/canvas_modulate.h
+++ b/scene/2d/canvas_modulate.h
@@ -46,7 +46,7 @@ public:
void set_color(const Color &p_color);
Color get_color() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CanvasModulate();
~CanvasModulate();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index c83ed36917..de648d404c 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -100,6 +100,64 @@ void CollisionObject2D::_notification(int p_what) {
}
}
+void CollisionObject2D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
+ }
+}
+
+uint32_t CollisionObject2D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void CollisionObject2D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
+ }
+}
+
+uint32_t CollisionObject2D::get_collision_mask() const {
+ return collision_mask;
+}
+
+void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
+ if (p_value) {
+ collision_layer |= 1 << p_bit;
+ } else {
+ collision_layer &= ~(1 << p_bit);
+ }
+ set_collision_layer(collision_layer);
+}
+
+bool CollisionObject2D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << p_bit;
+ } else {
+ mask &= ~(1 << p_bit);
+ }
+ set_collision_mask(mask);
+}
+
+bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
+ return get_collision_mask() & (1 << p_bit);
+}
+
uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
ShapeData sd;
uint32_t id;
@@ -363,22 +421,26 @@ void CollisionObject2D::_update_pickable() {
}
}
-String CollisionObject2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CollisionObject2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.");
+ warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."));
}
- return warning;
+ return warnings;
}
void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid);
-
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject2D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject2D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject2D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject2D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject2D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable);
ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject2D::create_shape_owner);
@@ -407,9 +469,12 @@ void CollisionObject2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
- ADD_GROUP("Pickable", "input_");
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable");
- ADD_GROUP("", "");
}
CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index e82b61d441..bb1a9dfcf5 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -37,6 +37,9 @@
class CollisionObject2D : public Node2D {
GDCLASS(CollisionObject2D, Node2D);
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+
bool area = false;
RID rid;
bool pickable = false;
@@ -76,6 +79,18 @@ protected:
void set_only_update_transform_changes(bool p_enable);
public:
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
@@ -107,7 +122,7 @@ public:
void set_pickable(bool p_enabled);
bool is_pickable() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
_FORCE_INLINE_ RID get_rid() const { return rid; }
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 39d7705226..a69ef73a54 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -41,13 +41,13 @@
void CollisionPolygon2D::_build_polygon() {
parent->shape_owner_clear_shapes(owner_id);
- if (polygon.size() == 0) {
- return;
- }
-
bool solids = build_mode == BUILD_SOLIDS;
if (solids) {
+ if (polygon.size() < 3) {
+ return;
+ }
+
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
Vector<Vector<Vector2>> decomp = _decompose_in_convex();
@@ -58,6 +58,10 @@ void CollisionPolygon2D::_build_polygon() {
}
} else {
+ if (polygon.size() < 2) {
+ return;
+ }
+
Ref<ConcavePolygonShape2D> concave = memnew(ConcavePolygonShape2D);
Vector<Vector2> segments;
@@ -132,25 +136,28 @@ void CollisionPolygon2D::_notification(int p_what) {
break;
}
- for (int i = 0; i < polygon.size(); i++) {
+ int polygon_count = polygon.size();
+ for (int i = 0; i < polygon_count; i++) {
Vector2 p = polygon[i];
- Vector2 n = polygon[(i + 1) % polygon.size()];
+ Vector2 n = polygon[(i + 1) % polygon_count];
// draw line with width <= 1, so it does not scale with zoom and break pixel exact editing
draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 1);
}
+
+ if (polygon_count > 2) {
#define DEBUG_DECOMPOSE
#if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE)
+ Vector<Vector<Vector2>> decomp = _decompose_in_convex();
- Vector<Vector<Vector2>> decomp = _decompose_in_convex();
-
- Color c(0.4, 0.9, 0.1);
- for (int i = 0; i < decomp.size(); i++) {
- c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5);
- draw_colored_polygon(decomp[i], c);
- }
+ Color c(0.4, 0.9, 0.1);
+ for (int i = 0; i < decomp.size(); i++) {
+ c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5);
+ draw_colored_polygon(decomp[i], c);
+ }
#else
- draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color());
+ draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color());
#endif
+ }
if (one_way_collision) {
Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
@@ -197,7 +204,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
_update_in_shape_owner();
}
update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Vector<Point2> CollisionPolygon2D::get_polygon() const {
@@ -211,6 +218,8 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
_build_polygon();
_update_in_shape_owner();
}
+ update();
+ update_configuration_warnings();
}
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const {
@@ -231,24 +240,28 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
}
#endif
-String CollisionPolygon2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
- if (polygon.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ int polygon_count = polygon.size();
+ if (polygon_count == 0) {
+ warnings.push_back(TTR("An empty CollisionPolygon2D has no effect on collision."));
+ } else {
+ bool solids = build_mode == BUILD_SOLIDS;
+ if (solids) {
+ if (polygon_count < 3) {
+ warnings.push_back(TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."));
+ }
+ } else if (polygon_count < 2) {
+ warnings.push_back(TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."));
}
- warning += TTR("An empty CollisionPolygon2D has no effect on collision.");
}
- return warning;
+ return warnings;
}
void CollisionPolygon2D::set_disabled(bool p_disabled) {
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 9df9802629..95dd8c9e21 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -78,7 +78,7 @@ public:
void set_polygon(const Vector<Point2> &p_polygon);
Vector<Point2> get_polygon() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_disabled(bool p_disabled);
bool is_disabled() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 4d1d274542..d9009ef85c 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -110,6 +110,7 @@ void CollisionShape2D::_notification(int p_what) {
draw_col.r = g;
draw_col.g = g;
draw_col.b = g;
+ draw_col.a *= 0.5;
}
shape->draw(get_canvas_item(), draw_col);
@@ -161,7 +162,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Shape2D> CollisionShape2D::get_shape() const {
@@ -176,19 +177,23 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double
return shape->_edit_is_selected_on_click(p_point, p_tolerance);
}
-String CollisionShape2D::get_configuration_warning() const {
+TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
+ warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
}
+
Ref<ConvexPolygonShape2D> convex = shape;
Ref<ConcavePolygonShape2D> concave = shape;
if (convex.is_valid() || concave.is_valid()) {
- return TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.");
+ warnings.push_back(TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead."));
}
- return String();
+
+ return warnings;
}
void CollisionShape2D::set_disabled(bool p_disabled) {
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 695d0c6657..eaf72627c8 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -72,7 +72,7 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionShape2D();
};
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index b34a9a9ea4..1578643d14 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -60,7 +60,7 @@ void CPUParticles2D::set_amount(int p_amount) {
}
particle_data.resize((8 + 4 + 4) * p_amount);
- RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true);
+ RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true);
particle_order.resize(p_amount);
}
@@ -78,11 +78,11 @@ void CPUParticles2D::set_pre_process_time(float p_time) {
pre_process_time = p_time;
}
-void CPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+void CPUParticles2D::set_explosiveness_ratio(real_t p_ratio) {
explosiveness_ratio = p_ratio;
}
-void CPUParticles2D::set_randomness_ratio(float p_ratio) {
+void CPUParticles2D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
}
@@ -95,7 +95,7 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
set_notify_transform(!p_enable);
}
-void CPUParticles2D::set_speed_scale(float p_scale) {
+void CPUParticles2D::set_speed_scale(real_t p_scale) {
speed_scale = p_scale;
}
@@ -119,11 +119,11 @@ float CPUParticles2D::get_pre_process_time() const {
return pre_process_time;
}
-float CPUParticles2D::get_explosiveness_ratio() const {
+real_t CPUParticles2D::get_explosiveness_ratio() const {
return explosiveness_ratio;
}
-float CPUParticles2D::get_randomness_ratio() const {
+real_t CPUParticles2D::get_randomness_ratio() const {
return randomness_ratio;
}
@@ -135,7 +135,7 @@ bool CPUParticles2D::get_use_local_coordinates() const {
return local_coords;
}
-float CPUParticles2D::get_speed_scale() const {
+real_t CPUParticles2D::get_speed_scale() const {
return speed_scale;
}
@@ -244,18 +244,15 @@ bool CPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
-String CPUParticles2D::get_configuration_warning() const {
- String warnings = Node2D::get_configuration_warning();
+TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+ warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
}
@@ -289,39 +286,39 @@ Vector2 CPUParticles2D::get_direction() const {
return direction;
}
-void CPUParticles2D::set_spread(float p_spread) {
+void CPUParticles2D::set_spread(real_t p_spread) {
spread = p_spread;
}
-float CPUParticles2D::get_spread() const {
+real_t CPUParticles2D::get_spread() const {
return spread;
}
-void CPUParticles2D::set_param(Parameter p_param, float p_value) {
+void CPUParticles2D::set_param(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
parameters[p_param] = p_value;
}
-float CPUParticles2D::get_param(Parameter p_param) const {
+real_t CPUParticles2D::get_param(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return parameters[p_param];
}
-void CPUParticles2D::set_param_randomness(Parameter p_param, float p_value) {
+void CPUParticles2D::set_param_randomness(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
randomness[p_param] = p_value;
}
-float CPUParticles2D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles2D::get_param_randomness(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return randomness[p_param];
}
-static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) {
+static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
Ref<Curve> curve = p_curve;
if (!curve.is_valid()) {
return;
@@ -410,10 +407,10 @@ bool CPUParticles2D::get_particle_flag(ParticleFlags p_particle_flag) const {
void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
emission_shape = p_shape;
- _change_notify();
+ notify_property_list_changed();
}
-void CPUParticles2D::set_emission_sphere_radius(float p_radius) {
+void CPUParticles2D::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
}
@@ -433,7 +430,7 @@ void CPUParticles2D::set_emission_colors(const Vector<Color> &p_colors) {
emission_colors = p_colors;
}
-float CPUParticles2D::get_emission_sphere_radius() const {
+real_t CPUParticles2D::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
@@ -502,7 +499,7 @@ static uint32_t idhash(uint32_t x) {
return x;
}
-static float rand_from_seed(uint32_t &seed) {
+static real_t rand_from_seed(uint32_t &seed) {
int k;
int s = int(seed);
if (s == 0) {
@@ -514,7 +511,7 @@ static float rand_from_seed(uint32_t &seed) {
s += 2147483647;
}
seed = uint32_t(s);
- return float(seed % uint32_t(65536)) / 65535.0;
+ return (seed % uint32_t(65536)) / 65535.0;
}
void CPUParticles2D::_update_internal() {
@@ -599,7 +596,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
cycle++;
if (one_shot && cycle > 0) {
set_emitting(false);
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -625,7 +622,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
// The phase is a ratio between 0 (birth) and 1 (end of life) for each particle.
// While we use time in tests later on, for randomness we use the phase as done in the
// original shader code, and we later multiply by lifetime to get the time.
- float restart_phase = float(i) / float(pcount);
+ real_t restart_phase = real_t(i) / real_t(pcount);
if (randomness_ratio > 0.0) {
uint32_t seed = cycle;
@@ -634,8 +631,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
seed *= uint32_t(pcount);
seed += uint32_t(i);
- float random = float(idhash(seed) % uint32_t(65536)) / 65536.0;
- restart_phase += randomness_ratio * random * 1.0 / float(pcount);
+ real_t random = (idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_phase += randomness_ratio * random * 1.0 / pcount;
}
restart_phase *= (1.0 - explosiveness_ratio);
@@ -680,17 +677,17 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
p.active = true;
- /*float tex_linear_velocity = 0;
+ /*real_t tex_linear_velocity = 0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
}*/
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
@@ -702,16 +699,16 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
- float angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
p.rotation = Math::deg2rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
@@ -723,8 +720,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
//do none
} break;
case EMISSION_SHAPE_SPHERE: {
- float s = Math::randf(), t = Math_TAU * Math::randf();
- float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
+ real_t s = Math::randf(), t = Math_TAU * Math::randf();
+ real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius;
} break;
case EMISSION_SHAPE_RECTANGLE: {
@@ -775,51 +772,51 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.custom[1] = p.time / lifetime;
tv = p.time / p.lifetime;
- float tex_linear_velocity = 0.0;
+ real_t tex_linear_velocity = 0.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
}
- float tex_orbit_velocity = 0.0;
+ real_t tex_orbit_velocity = 0.0;
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
}
- float tex_angular_velocity = 0.0;
+ real_t tex_angular_velocity = 0.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
}
- float tex_linear_accel = 0.0;
+ real_t tex_linear_accel = 0.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
}
- float tex_tangential_accel = 0.0;
+ real_t tex_tangential_accel = 0.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
}
- float tex_radial_accel = 0.0;
+ real_t tex_radial_accel = 0.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
}
- float tex_damping = 0.0;
+ real_t tex_damping = 0.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
}
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_speed = 0.0;
+ real_t tex_anim_speed = 0.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
}
@@ -828,20 +825,20 @@ void CPUParticles2D::_particles_process(float p_delta) {
Vector2 pos = p.transform[2];
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
//apply radial acceleration
Vector2 org = emission_xform[2];
Vector2 diff = pos - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
+ force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
//apply tangential acceleration;
Vector2 yx = Vector2(diff.y, diff.x);
- force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
+ force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
if (orbit_amount != 0.0) {
- float ang = orbit_amount * local_delta * Math_TAU;
+ real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
// but we use -ang here to reproduce its behavior.
Transform2D rot = Transform2D(-ang, Vector2());
@@ -853,8 +850,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
- float v = p.velocity.length();
- float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ real_t v = p.velocity.length();
+ real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector2();
@@ -862,28 +859,28 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
+ base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
p.rotation = Math::deg2rad(base_angle); //angle
- float animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
+ real_t animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
p.custom[2] = animation_phase;
}
//apply color
//apply hue rotation
- float tex_scale = 1.0;
+ real_t tex_scale = 1.0;
if (curve_parameters[PARAM_SCALE].is_valid()) {
tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
}
- float tex_hue_variation = 0.0;
+ real_t tex_hue_variation = 0.0;
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
- float hue_rot_c = Math::cos(hue_rot_angle);
- float hue_rot_s = Math::sin(hue_rot_angle);
+ real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ real_t hue_rot_c = Math::cos(hue_rot_angle);
+ real_t hue_rot_s = Math::sin(hue_rot_angle);
Basis hue_rot_mat;
{
@@ -921,7 +918,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
//scale by scale
- float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]);
if (base_scale < 0.000001) {
base_scale = 0.000001;
}
@@ -979,7 +976,7 @@ void CPUParticles2D::_update_particle_data_buffer() {
ptr[7] = t.elements[2][1];
} else {
- zeromem(ptr, sizeof(float) * 8);
+ memset(ptr, 0, sizeof(float) * 8);
}
Color c = r[idx].color;
@@ -1032,66 +1029,64 @@ void CPUParticles2D::_update_render_thread() {
}
void CPUParticles2D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- set_process_internal(emitting);
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- _set_redraw(false);
- }
-
- if (p_what == NOTIFICATION_DRAW) {
- // first update before rendering to avoid one frame delay after emitting starts
- if (emitting && (time == 0)) {
- _update_internal();
- }
-
- if (!redraw) {
- return; // don't add to render list
- }
-
- RID texrid;
- if (texture.is_valid()) {
- texrid = texture->get_rid();
- }
-
- RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid);
- }
-
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- _update_internal();
- }
-
- if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- inv_emission_transform = get_global_transform().affine_inverse();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ set_process_internal(emitting);
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ _set_redraw(false);
+ } break;
+ case NOTIFICATION_DRAW: {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0)) {
+ _update_internal();
+ }
- if (!local_coords) {
- int pc = particles.size();
+ if (!redraw) {
+ return; // don't add to render list
+ }
- float *w = particle_data.ptrw();
- const Particle *r = particles.ptr();
- float *ptr = w;
+ RID texrid;
+ if (texture.is_valid()) {
+ texrid = texture->get_rid();
+ }
- for (int i = 0; i < pc; i++) {
- Transform2D t = inv_emission_transform * r[i].transform;
+ RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid);
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ _update_internal();
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ inv_emission_transform = get_global_transform().affine_inverse();
- if (r[i].active) {
- ptr[0] = t.elements[0][0];
- ptr[1] = t.elements[1][0];
- ptr[2] = 0;
- ptr[3] = t.elements[2][0];
- ptr[4] = t.elements[0][1];
- ptr[5] = t.elements[1][1];
- ptr[6] = 0;
- ptr[7] = t.elements[2][1];
+ if (!local_coords) {
+ int pc = particles.size();
+
+ float *w = particle_data.ptrw();
+ const Particle *r = particles.ptr();
+ float *ptr = w;
+
+ for (int i = 0; i < pc; i++) {
+ Transform2D t = inv_emission_transform * r[i].transform;
+
+ if (r[i].active) {
+ ptr[0] = t.elements[0][0];
+ ptr[1] = t.elements[1][0];
+ ptr[2] = 0;
+ ptr[3] = t.elements[2][0];
+ ptr[4] = t.elements[0][1];
+ ptr[5] = t.elements[1][1];
+ ptr[6] = 0;
+ ptr[7] = t.elements[2][1];
+
+ } else {
+ memset(ptr, 0, sizeof(float) * 8);
+ }
- } else {
- zeromem(ptr, sizeof(float) * 8);
+ ptr += 16;
}
-
- ptr += 16;
}
- }
+ } break;
}
}
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 7ee165b3e1..ba34a0f45d 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -84,13 +84,13 @@ private:
Transform2D transform;
Color color;
float custom[4] = {};
- float rotation = 0.0;
+ real_t rotation = 0.0;
Vector2 velocity;
bool active = false;
- float angle_rand = 0.0;
- float scale_rand = 0.0;
- float hue_rot_rand = 0.0;
- float anim_offset_rand = 0.0;
+ real_t angle_rand = 0.0;
+ real_t scale_rand = 0.0;
+ real_t hue_rot_rand = 0.0;
+ real_t anim_offset_rand = 0.0;
float time = 0.0;
float lifetime = 0.0;
Color base_color;
@@ -133,10 +133,10 @@ private:
float lifetime = 1.0;
float pre_process_time = 0.0;
- float explosiveness_ratio = 0.0;
- float randomness_ratio = 0.0;
- float lifetime_randomness = 0.0;
- float speed_scale = 1.0;
+ real_t explosiveness_ratio = 0.0;
+ real_t randomness_ratio = 0.0;
+ real_t lifetime_randomness = 0.0;
+ real_t speed_scale = 1.0;
bool local_coords;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -150,10 +150,10 @@ private:
////////
Vector2 direction = Vector2(1, 0);
- float spread = 45.0;
+ real_t spread = 45.0;
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX];
+ real_t parameters[PARAM_MAX];
+ real_t randomness[PARAM_MAX];
Ref<Curve> curve_parameters[PARAM_MAX];
Color color;
@@ -162,7 +162,7 @@ private:
bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape = EMISSION_SHAPE_POINT;
- float emission_sphere_radius = 1.0;
+ real_t emission_sphere_radius = 1.0;
Vector2 emission_rect_extents = Vector2(1, 1);
Vector<Vector2> emission_points;
Vector<Vector2> emission_normals;
@@ -196,24 +196,24 @@ public:
void set_lifetime(float p_lifetime);
void set_one_shot(bool p_one_shot);
void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
+ void set_explosiveness_ratio(real_t p_ratio);
+ void set_randomness_ratio(real_t p_ratio);
void set_lifetime_randomness(float p_random);
void set_visibility_aabb(const Rect2 &p_aabb);
void set_use_local_coordinates(bool p_enable);
- void set_speed_scale(float p_scale);
+ void set_speed_scale(real_t p_scale);
bool is_emitting() const;
int get_amount() const;
float get_lifetime() const;
bool get_one_shot() const;
float get_pre_process_time() const;
- float get_explosiveness_ratio() const;
- float get_randomness_ratio() const;
+ real_t get_explosiveness_ratio() const;
+ real_t get_randomness_ratio() const;
float get_lifetime_randomness() const;
Rect2 get_visibility_aabb() const;
bool get_use_local_coordinates() const;
- float get_speed_scale() const;
+ real_t get_speed_scale() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -235,14 +235,14 @@ public:
void set_direction(Vector2 p_direction);
Vector2 get_direction() const;
- void set_spread(float p_spread);
- float get_spread() const;
+ void set_spread(real_t p_spread);
+ real_t get_spread() const;
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
+ void set_param(Parameter p_param, real_t p_value);
+ real_t get_param(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, float p_value);
- float get_param_randomness(Parameter p_param) const;
+ void set_param_randomness(Parameter p_param, real_t p_value);
+ real_t get_param_randomness(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -257,7 +257,7 @@ public:
bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
- void set_emission_sphere_radius(float p_radius);
+ void set_emission_sphere_radius(real_t p_radius);
void set_emission_rect_extents(Vector2 p_extents);
void set_emission_points(const Vector<Vector2> &p_points);
void set_emission_normals(const Vector<Vector2> &p_normals);
@@ -265,7 +265,7 @@ public:
void set_emission_point_count(int p_count);
EmissionShape get_emission_shape() const;
- float get_emission_sphere_radius() const;
+ real_t get_emission_sphere_radius() const;
Vector2 get_emission_rect_extents() const;
Vector<Vector2> get_emission_points() const;
Vector<Vector2> get_emission_normals() const;
@@ -275,7 +275,7 @@ public:
void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 2e477a88a9..8a0631a614 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -101,7 +101,6 @@ void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
RS::get_singleton()->particles_set_custom_aabb(particles, aabb);
- _change_notify("visibility_rect");
update();
}
@@ -138,7 +137,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
}
RS::get_singleton()->particles_set_process_material(particles, material_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
void GPUParticles2D::set_speed_scale(float p_scale) {
@@ -217,18 +216,15 @@ bool GPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
-String GPUParticles2D::get_configuration_warning() const {
+TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose.");
+ warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."));
}
- String warnings = Node2D::get_configuration_warning();
-
if (process_material.is_null()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+ warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
@@ -237,10 +233,7 @@ String GPUParticles2D::get_configuration_warning() const {
if (process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+ warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
}
}
@@ -305,7 +298,7 @@ void GPUParticles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
if (one_shot && !is_emitting()) {
- _change_notify();
+ notify_property_list_changed();
set_process_internal(false);
}
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 774cef9cc9..20f9f768ed 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -110,7 +110,7 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
Rect2 capture_rect() const;
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index 80445e7e5d..8a4ccc2f96 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -49,35 +49,24 @@ void Joint2D::_disconnect_signals() {
}
}
-void Joint2D::_body_exit_tree(const ObjectID &p_body_id) {
+void Joint2D::_body_exit_tree() {
_disconnect_signals();
- Object *object = ObjectDB::get_instance(p_body_id);
- PhysicsBody2D *body = Object::cast_to<PhysicsBody2D>(object);
- ERR_FAIL_NULL(body);
- RID body_rid = body->get_rid();
- if (ba == body_rid) {
- a = NodePath();
- }
- if (bb == body_rid) {
- b = NodePath();
- }
- _update_joint();
+ _update_joint(true);
}
void Joint2D::_update_joint(bool p_only_free) {
- if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid() && exclude_from_collision) {
- PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
- }
-
- PhysicsServer2D::get_singleton()->free(joint);
- joint = RID();
- ba = RID();
- bb = RID();
+ if (ba.is_valid() && bb.is_valid() && exclude_from_collision) {
+ PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
}
+ ba = RID();
+ bb = RID();
+ configured = false;
+
if (p_only_free || !is_inside_tree()) {
+ PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = String();
+ update_configuration_warnings();
return;
}
@@ -89,37 +78,25 @@ void Joint2D::_update_joint(bool p_only_free) {
if (node_a && !body_a && node_b && !body_b) {
warning = TTR("Node A and Node B must be PhysicsBody2Ds");
- update_configuration_warning();
- return;
- }
-
- if (node_a && !body_a) {
+ } else if (node_a && !body_a) {
warning = TTR("Node A must be a PhysicsBody2D");
- update_configuration_warning();
- return;
- }
-
- if (node_b && !body_b) {
+ } else if (node_b && !body_b) {
warning = TTR("Node B must be a PhysicsBody2D");
- update_configuration_warning();
- return;
- }
-
- if (!body_a || !body_b) {
+ } else if (!body_a || !body_b) {
warning = TTR("Joint is not connected to two PhysicsBody2Ds");
- update_configuration_warning();
- return;
+ } else if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody2Ds");
+ } else {
+ warning = String();
}
- if (body_a == body_b) {
- warning = TTR("Node A and Node B must be different PhysicsBody2Ds");
- update_configuration_warning();
+ update_configuration_warnings();
+
+ if (!warning.is_empty()) {
+ PhysicsServer2D::get_singleton()->joint_clear(joint);
return;
}
- warning = String();
- update_configuration_warning();
-
if (body_a) {
body_a->force_update_transform();
}
@@ -128,7 +105,9 @@ void Joint2D::_update_joint(bool p_only_free) {
body_b->force_update_transform();
}
- joint = _configure_joint(body_a, body_b);
+ configured = true;
+
+ _configure_joint(joint, body_a, body_b);
ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint.");
@@ -137,8 +116,8 @@ void Joint2D::_update_joint(bool p_only_free) {
ba = body_a->get_rid();
bb = body_b->get_rid();
- body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree), make_binds(body_a->get_instance_id()));
- body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree), make_binds(body_b->get_instance_id()));
+ body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree));
+ body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree));
PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
}
@@ -216,17 +195,14 @@ bool Joint2D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-String Joint2D::get_configuration_warning() const {
- String node_warning = Node2D::get_configuration_warning();
+TypedArray<String> Joint2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node2D::get_configuration_warnings();
if (!warning.is_empty()) {
- if (!node_warning.is_empty()) {
- node_warning += "\n\n";
- }
- node_warning += warning;
+ warnings.push_back(warning);
}
- return node_warning;
+ return warnings;
}
void Joint2D::_bind_methods() {
@@ -249,6 +225,11 @@ void Joint2D::_bind_methods() {
}
Joint2D::Joint2D() {
+ joint = PhysicsServer2D::get_singleton()->joint_create();
+}
+
+Joint2D::~Joint2D() {
+ PhysicsServer2D::get_singleton()->free(joint);
}
///////////////////////////////////////////////////////////////////////////////
@@ -272,16 +253,15 @@ void PinJoint2D::_notification(int p_what) {
}
}
-RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
- RID pj = PhysicsServer2D::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
- PhysicsServer2D::get_singleton()->pin_joint_set_param(pj, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness);
- return pj;
+void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
+ PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
+ PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness);
}
void PinJoint2D::set_softness(real_t p_softness) {
softness = p_softness;
update();
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness);
}
}
@@ -323,13 +303,13 @@ void GrooveJoint2D::_notification(int p_what) {
}
}
-RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
+void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
Transform2D gt = get_global_transform();
Vector2 groove_A1 = gt.get_origin();
Vector2 groove_A2 = gt.xform(Vector2(0, length));
Vector2 anchor_B = gt.xform(Vector2(0, initial_offset));
- return PhysicsServer2D::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
+ PhysicsServer2D::get_singleton()->joint_make_groove(p_joint, groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
}
void GrooveJoint2D::set_length(real_t p_length) {
@@ -385,19 +365,17 @@ void DampedSpringJoint2D::_notification(int p_what) {
}
}
-RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
+void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
Transform2D gt = get_global_transform();
Vector2 anchor_A = gt.get_origin();
Vector2 anchor_B = gt.xform(Vector2(0, length));
- RID dsj = PhysicsServer2D::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
+ PhysicsServer2D::get_singleton()->joint_make_damped_spring(p_joint, anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
if (rest_length) {
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length);
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length);
}
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness);
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping);
-
- return dsj;
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness);
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping);
}
void DampedSpringJoint2D::set_length(real_t p_length) {
@@ -412,7 +390,7 @@ real_t DampedSpringJoint2D::get_length() const {
void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
rest_length = p_rest_length;
update();
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
}
}
@@ -424,7 +402,7 @@ real_t DampedSpringJoint2D::get_rest_length() const {
void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
stiffness = p_stiffness;
update();
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness);
}
}
@@ -436,7 +414,7 @@ real_t DampedSpringJoint2D::get_stiffness() const {
void DampedSpringJoint2D::set_damping(real_t p_damping) {
damping = p_damping;
update();
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping);
}
}
diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h
index 887155c6ea..dc5a08f815 100644
--- a/scene/2d/joints_2d.h
+++ b/scene/2d/joints_2d.h
@@ -46,20 +46,23 @@ class Joint2D : public Node2D {
real_t bias = 0.0;
bool exclude_from_collision = true;
+ bool configured = false;
String warning;
protected:
void _disconnect_signals();
- void _body_exit_tree(const ObjectID &p_body_id);
+ void _body_exit_tree();
void _update_joint(bool p_only_free = false);
void _notification(int p_what);
- virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0;
+ virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0;
static void _bind_methods();
+ _FORCE_INLINE_ bool is_configured() const { return configured; }
+
public:
- virtual String get_configuration_warning() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
@@ -75,6 +78,7 @@ public:
RID get_joint() const { return joint; }
Joint2D();
+ ~Joint2D();
};
class PinJoint2D : public Joint2D {
@@ -84,7 +88,7 @@ class PinJoint2D : public Joint2D {
protected:
void _notification(int p_what);
- virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
static void _bind_methods();
public:
@@ -102,7 +106,7 @@ class GrooveJoint2D : public Joint2D {
protected:
void _notification(int p_what);
- virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
static void _bind_methods();
public:
@@ -125,7 +129,7 @@ class DampedSpringJoint2D : public Joint2D {
protected:
void _notification(int p_what);
- virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override;
static void _bind_methods();
public:
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index c000c8ea19..8fb765f16b 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -84,21 +84,21 @@ Color Light2D::get_color() const {
return color;
}
-void Light2D::set_height(float p_height) {
+void Light2D::set_height(real_t p_height) {
height = p_height;
RS::get_singleton()->canvas_light_set_height(canvas_light, height);
}
-float Light2D::get_height() const {
+real_t Light2D::get_height() const {
return height;
}
-void Light2D::set_energy(float p_energy) {
+void Light2D::set_energy(real_t p_energy) {
energy = p_energy;
RS::get_singleton()->canvas_light_set_energy(canvas_light, energy);
}
-float Light2D::get_energy() const {
+real_t Light2D::get_energy() const {
return energy;
}
@@ -159,6 +159,7 @@ int Light2D::get_item_shadow_cull_mask() const {
void Light2D::set_shadow_enabled(bool p_enabled) {
shadow = p_enabled;
RS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow);
+ notify_property_list_changed();
}
bool Light2D::is_shadow_enabled() const {
@@ -212,15 +213,21 @@ void Light2D::_notification(int p_what) {
}
}
-void Light2D::set_shadow_smooth(float p_amount) {
+void Light2D::set_shadow_smooth(real_t p_amount) {
shadow_smooth = p_amount;
RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth);
}
-float Light2D::get_shadow_smooth() const {
+real_t Light2D::get_shadow_smooth() const {
return shadow_smooth;
}
+void Light2D::_validate_property(PropertyInfo &property) const {
+ if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void Light2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Light2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &Light2D::is_enabled);
@@ -366,7 +373,7 @@ void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) {
RS::get_singleton()->canvas_light_set_texture(_get_light(), RID());
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Texture2D> PointLight2D::get_texture() const {
@@ -377,27 +384,23 @@ void PointLight2D::set_texture_offset(const Vector2 &p_offset) {
texture_offset = p_offset;
RS::get_singleton()->canvas_light_set_texture_offset(_get_light(), texture_offset);
item_rect_changed();
- _change_notify("offset");
}
Vector2 PointLight2D::get_texture_offset() const {
return texture_offset;
}
-String PointLight2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> PointLight2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!texture.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
+ warnings.push_back(TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
}
- return warning;
+ return warnings;
}
-void PointLight2D::set_texture_scale(float p_scale) {
+void PointLight2D::set_texture_scale(real_t p_scale) {
_scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if (_scale == 0) {
@@ -407,7 +410,7 @@ void PointLight2D::set_texture_scale(float p_scale) {
item_rect_changed();
}
-float PointLight2D::get_texture_scale() const {
+real_t PointLight2D::get_texture_scale() const {
return _scale;
}
@@ -433,12 +436,12 @@ PointLight2D::PointLight2D() {
//////////
-void DirectionalLight2D::set_max_distance(float p_distance) {
+void DirectionalLight2D::set_max_distance(real_t p_distance) {
max_distance = p_distance;
RS::get_singleton()->canvas_light_set_directional_distance(_get_light(), max_distance);
}
-float DirectionalLight2D::get_max_distance() const {
+real_t DirectionalLight2D::get_max_distance() const {
return max_distance;
}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index 4279baf15b..d9ecd81f1c 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -57,15 +57,15 @@ private:
bool shadow = false;
Color color = Color(1, 1, 1);
Color shadow_color = Color(0, 0, 0, 0);
- float height = 0.0;
- float energy = 1.0;
+ real_t height = 0.0;
+ real_t energy = 1.0;
int z_min = -1024;
int z_max = 1024;
int layer_min = 0;
int layer_max = 0;
int item_mask = 1;
int item_shadow_mask = 1;
- float shadow_smooth = 0.0;
+ real_t shadow_smooth = 0.0;
Ref<Texture2D> texture;
Vector2 texture_offset;
ShadowFilter shadow_filter = SHADOW_FILTER_NONE;
@@ -77,6 +77,7 @@ protected:
_FORCE_INLINE_ RID _get_light() const { return canvas_light; }
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_enabled(bool p_enabled);
@@ -88,11 +89,11 @@ public:
void set_color(const Color &p_color);
Color get_color() const;
- void set_height(float p_height);
- float get_height() const;
+ void set_height(real_t p_height);
+ real_t get_height() const;
- void set_energy(float p_energy);
- float get_energy() const;
+ void set_energy(real_t p_energy);
+ real_t get_energy() const;
void set_z_range_min(int p_min_z);
int get_z_range_min() const;
@@ -121,8 +122,8 @@ public:
void set_shadow_color(const Color &p_shadow_color);
Color get_shadow_color() const;
- void set_shadow_smooth(float p_amount);
- float get_shadow_smooth() const;
+ void set_shadow_smooth(real_t p_amount);
+ real_t get_shadow_smooth() const;
void set_blend_mode(BlendMode p_mode);
BlendMode get_blend_mode() const;
@@ -138,7 +139,7 @@ class PointLight2D : public Light2D {
GDCLASS(PointLight2D, Light2D);
private:
- float _scale = 1.0;
+ real_t _scale = 1.0;
Ref<Texture2D> texture;
Vector2 texture_offset;
@@ -165,10 +166,10 @@ public:
void set_texture_offset(const Vector2 &p_offset);
Vector2 get_texture_offset() const;
- void set_texture_scale(float p_scale);
- float get_texture_scale() const;
+ void set_texture_scale(real_t p_scale);
+ real_t get_texture_scale() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PointLight2D();
};
@@ -176,14 +177,14 @@ public:
class DirectionalLight2D : public Light2D {
GDCLASS(DirectionalLight2D, Light2D);
- float max_distance = 10000.0;
+ real_t max_distance = 10000.0;
protected:
static void _bind_methods();
public:
- void set_max_distance(float p_distance);
- float get_max_distance() const;
+ void set_max_distance(real_t p_distance);
+ real_t get_max_distance() const;
DirectionalLight2D();
};
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 9589702e2e..fdc28f81c2 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -242,24 +242,18 @@ int LightOccluder2D::get_occluder_light_mask() const {
return mask;
}
-String LightOccluder2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> LightOccluder2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!occluder_polygon.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
+ warnings.push_back(TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));
}
if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
+ warnings.push_back(TTR("The occluder polygon for this occluder is empty. Please draw a polygon."));
}
- return warning;
+ return warnings;
}
void LightOccluder2D::set_as_sdf_collision(bool p_enable) {
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index f567c6d965..b4a48d1062 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -106,7 +106,7 @@ public:
void set_as_sdf_collision(bool p_enable);
bool is_set_as_sdf_collision() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
LightOccluder2D();
~LightOccluder2D();
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 2959ea1a36..37eb45c21d 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -116,6 +116,7 @@ Vector<Vector2> Line2D::get_points() const {
}
void Line2D::set_point_position(int i, Vector2 p_pos) {
+ ERR_FAIL_INDEX(i, _points.size());
_points.set(i, p_pos);
update();
}
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 892ccadfda..c478f03356 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -375,7 +375,7 @@ void LineBuilder::build() {
}
if (intersection_result != SEGMENT_INTERSECT) {
- // In this case the joint is too corrputed to be re-used,
+ // In this case the joint is too corrupted to be re-used,
// start again the strip with fallback points
strip_begin(pos_up0, pos_down0, color1, uvx1);
}
@@ -485,7 +485,7 @@ void LineBuilder::strip_add_tri(Vector2 up, Orientation orientation) {
if (texture_mode != Line2D::LINE_TEXTURE_NONE) {
// UVs are just one slice of the texture all along
- // (otherwise we can't share the bottom vertice)
+ // (otherwise we can't share the bottom vertex)
uvs.push_back(uvs[_last_index[opposite_orientation]]);
}
@@ -520,7 +520,7 @@ void LineBuilder::strip_add_arc(Vector2 center, float angle_delta, Orientation o
strip_add_tri(rpos, orientation);
}
- // Last arc vertice
+ // Last arc vertex
rpos = center + Vector2(Math::cos(end_angle), Math::sin(end_angle)) * radius;
strip_add_tri(rpos, orientation);
}
@@ -569,7 +569,7 @@ void LineBuilder::new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Col
}
}
- // Last arc vertice
+ // Last arc vertex
Vector2 sc = Vector2(Math::cos(end_angle), Math::sin(end_angle));
rpos = center + sc * radius;
vertices.push_back(rpos);
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index 430e655fc6..b7a0028199 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -71,7 +71,6 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
update();
emit_signal("texture_changed");
- _change_notify("texture");
}
void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) {
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
index 5164e5c7e9..72a899370e 100644
--- a/scene/2d/multimesh_instance_2d.cpp
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -71,7 +71,6 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
update();
emit_signal("texture_changed");
- _change_notify("texture");
}
Ref<Texture2D> MultiMeshInstance2D::get_texture() const {
diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp
deleted file mode 100644
index bec5ee7984..0000000000
--- a/scene/2d/navigation_2d.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*************************************************************************/
-/* navigation_2d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "navigation_2d.h"
-#include "servers/navigation_server_2d.h"
-
-void Navigation2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_rid"), &Navigation2D::get_rid);
-
- ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation2D::get_simple_path, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation2D::get_closest_point);
- ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation2D::get_closest_point_owner);
-
- ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation2D::set_cell_size);
- ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation2D::get_cell_size);
-
- ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation2D::set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation2D::get_edge_connection_margin);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_connection_margin"), "set_edge_connection_margin", "get_edge_connection_margin");
-}
-
-void Navigation2D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- NavigationServer2D::get_singleton()->map_set_active(map, true);
- } break;
- case NOTIFICATION_EXIT_TREE: {
- NavigationServer2D::get_singleton()->map_set_active(map, false);
- } break;
- }
-}
-
-void Navigation2D::set_cell_size(float p_cell_size) {
- cell_size = p_cell_size;
- NavigationServer2D::get_singleton()->map_set_cell_size(map, cell_size);
-}
-
-void Navigation2D::set_edge_connection_margin(float p_edge_connection_margin) {
- edge_connection_margin = p_edge_connection_margin;
- NavigationServer2D::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin);
-}
-
-Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize) const {
- return NavigationServer2D::get_singleton()->map_get_path(map, p_start, p_end, p_optimize);
-}
-
-Vector2 Navigation2D::get_closest_point(const Vector2 &p_point) const {
- return NavigationServer2D::get_singleton()->map_get_closest_point(map, p_point);
-}
-
-RID Navigation2D::get_closest_point_owner(const Vector2 &p_point) const {
- return NavigationServer2D::get_singleton()->map_get_closest_point_owner(map, p_point);
-}
-
-Navigation2D::Navigation2D() {
- map = NavigationServer2D::get_singleton()->map_create();
- set_cell_size(10); // Ten pixels
- set_edge_connection_margin(100);
-}
-
-Navigation2D::~Navigation2D() {
- NavigationServer2D::get_singleton()->free(map);
-}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 534e31b1f2..f9cbdbf377 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -32,19 +32,17 @@
#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
-#include "scene/2d/navigation_2d.h"
#include "servers/navigation_server_2d.h"
void NavigationAgent2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent2D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent2D::get_radius);
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent2D::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent2D::get_navigation_node);
-
ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent2D::set_neighbor_dist);
ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent2D::get_neighbor_dist);
@@ -92,41 +90,21 @@ void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node2D>(get_parent());
-
- NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
-
- // Search the navigation node and set it
- {
- Navigation2D *nav = nullptr;
- Node *p = get_parent();
- while (p != nullptr) {
- nav = Object::cast_to<Navigation2D>(p);
- if (nav != nullptr) {
- p = nullptr;
- } else {
- p = p->get_parent();
- }
- }
-
- set_navigation(nav);
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
}
-
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
agent_parent = nullptr;
- set_navigation(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().get_origin());
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -146,23 +124,13 @@ NavigationAgent2D::~NavigationAgent2D() {
agent = RID(); // Pointless
}
-void NavigationAgent2D::set_navigation(Navigation2D *p_nav) {
- if (navigation == p_nav) {
- return; // Pointless
- }
-
- navigation = p_nav;
- NavigationServer2D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid());
-}
-
-void NavigationAgent2D::set_navigation_node(Node *p_nav) {
- Navigation2D *nav = Object::cast_to<Navigation2D>(p_nav);
- ERR_FAIL_COND(nav == nullptr);
- set_navigation(nav);
+void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) {
+ navigable_layers = p_layers;
+ update_navigation();
}
-Node *NavigationAgent2D::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
+uint32_t NavigationAgent2D::get_navigable_layers() const {
+ return navigable_layers;
}
void NavigationAgent2D::set_target_desired_distance(real_t p_dd) {
@@ -270,24 +238,21 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", velocity);
}
-String NavigationAgent2D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationAgent2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationAgent2D can be used only under a Node2D node");
+ warnings.push_back(TTR("The NavigationAgent2D can be used only under a Node2D node"));
}
- return warning;
+ return warnings;
}
void NavigationAgent2D::update_navigation() {
if (agent_parent == nullptr) {
return;
}
- if (navigation == nullptr) {
+ if (!agent_parent->is_inside_tree()) {
return;
}
if (update_frame_id == Engine::get_singleton()->get_physics_frames()) {
@@ -319,7 +284,7 @@ void NavigationAgent2D::update_navigation() {
}
if (reload_path) {
- navigation_path = NavigationServer2D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
+ navigation_path = NavigationServer2D::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigable_layers);
navigation_finished = false;
nav_path_index = 0;
emit_signal("path_changed");
@@ -335,6 +300,7 @@ void NavigationAgent2D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index]) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -343,3 +309,12 @@ void NavigationAgent2D::update_navigation() {
}
}
}
+
+void NavigationAgent2D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 6b7da4a5f2..234cad333f 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -35,16 +35,16 @@
#include "scene/main/node.h"
class Node2D;
-class Navigation2D;
class NavigationAgent2D : public Node {
GDCLASS(NavigationAgent2D, Node);
Node2D *agent_parent = nullptr;
- Navigation2D *navigation = nullptr;
RID agent;
+ uint32_t navigable_layers = 1;
+
real_t target_desired_distance = 1.0;
real_t radius;
real_t neighbor_dist;
@@ -74,18 +74,13 @@ public:
NavigationAgent2D();
virtual ~NavigationAgent2D();
- void set_navigation(Navigation2D *p_nav);
- const Navigation2D *get_navigation() const {
- return navigation;
- }
-
- void set_navigation_node(Node *p_nav);
- Node *get_navigation_node() const;
-
RID get_rid() const {
return agent;
}
+ void set_navigable_layers(uint32_t p_layers);
+ uint32_t get_navigable_layers() const;
+
void set_target_desired_distance(real_t p_dd);
real_t get_target_desired_distance() const {
return target_desired_distance;
@@ -141,10 +136,11 @@ public:
void set_velocity(Vector2 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 7e1aefe5e2..a06f7a9fd0 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -31,48 +31,31 @@
#include "navigation_obstacle_2d.h"
#include "scene/2d/collision_shape_2d.h"
-#include "scene/2d/navigation_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "servers/navigation_server_2d.h"
void NavigationObstacle2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle2D::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle2D::get_navigation_node);
}
void NavigationObstacle2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- update_agent_shape();
-
- // Search the navigation node and set it
- {
- Navigation2D *nav = nullptr;
- Node *p = get_parent();
- while (p != nullptr) {
- nav = Object::cast_to<Navigation2D>(p);
- if (nav != nullptr) {
- p = nullptr;
- } else {
- p = p->get_parent();
- }
- }
-
- set_navigation(nav);
- }
-
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- set_navigation(nullptr);
set_physics_process_internal(false);
} break;
+ case NOTIFICATION_PARENTED: {
+ parent_node2d = Object::cast_to<Node2D>(get_parent());
+ update_agent_shape();
+ } break;
+ case NOTIFICATION_UNPARENTED: {
+ parent_node2d = nullptr;
+ } break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- Node2D *node = Object::cast_to<Node2D>(get_parent());
- if (node) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, node->get_global_transform().get_origin());
+ if (parent_node2d) {
+ NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_transform().get_origin());
}
-
} break;
}
}
@@ -86,73 +69,48 @@ NavigationObstacle2D::~NavigationObstacle2D() {
agent = RID(); // Pointless
}
-void NavigationObstacle2D::set_navigation(Navigation2D *p_nav) {
- if (navigation == p_nav) {
- return; // Pointless
- }
-
- navigation = p_nav;
- NavigationServer2D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid());
-}
-
-void NavigationObstacle2D::set_navigation_node(Node *p_nav) {
- Navigation2D *nav = Object::cast_to<Navigation2D>(p_nav);
- ERR_FAIL_COND(nav == nullptr);
- set_navigation(nav);
-}
-
-Node *NavigationObstacle2D::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
-}
-
-String NavigationObstacle2D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
+ warnings.push_back(TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));
}
- return warning;
+ return warnings;
}
void NavigationObstacle2D::update_agent_shape() {
- Node *node = get_parent();
-
- // Estimate the radius of this physics body
- real_t radius = 0.0;
- for (int i(0); i < node->get_child_count(); i++) {
- // For each collision shape
- CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(node->get_child(i));
- if (cs) {
- // Take the distance between the Body center to the shape center
- real_t r = cs->get_transform().get_origin().length();
- if (cs->get_shape().is_valid()) {
- // and add the enclosing shape radius
- r += cs->get_shape()->get_enclosing_radius();
+ if (parent_node2d) {
+ // Estimate the radius of this physics body
+ real_t radius = 0.0;
+ for (int i(0); i < parent_node2d->get_child_count(); i++) {
+ // For each collision shape
+ CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(parent_node2d->get_child(i));
+ if (cs) {
+ // Take the distance between the Body center to the shape center
+ real_t r = cs->get_transform().get_origin().length();
+ if (cs->get_shape().is_valid()) {
+ // and add the enclosing shape radius
+ r += cs->get_shape()->get_enclosing_radius();
+ }
+ Size2 s = cs->get_global_transform().get_scale();
+ r *= MAX(s.x, s.y);
+ // Takes the biggest radius
+ radius = MAX(radius, r);
}
- Size2 s = cs->get_global_transform().get_scale();
- r *= MAX(s.x, s.y);
- // Takes the biggest radius
- radius = MAX(radius, r);
}
- }
- Node2D *node_2d = Object::cast_to<Node2D>(node);
- if (node_2d) {
- Vector2 s = node_2d->get_global_transform().get_scale();
+ Vector2 s = parent_node2d->get_global_transform().get_scale();
radius *= MAX(s.x, s.y);
- }
- if (radius == 0.0) {
- radius = 1.0; // Never a 0 radius
- }
+ if (radius == 0.0) {
+ radius = 1.0; // Never a 0 radius
+ }
- // Initialize the Agent as an object
- NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
- NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0);
- NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0);
- NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
- NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0);
+ // Initialize the Agent as an object
+ NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
+ NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0);
+ NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0);
+ NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
+ NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0);
+ }
}
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 421f8ca7cd..9cffc2c0c3 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -31,15 +31,13 @@
#ifndef NAVIGATION_OBSTACLE_2D_H
#define NAVIGATION_OBSTACLE_2D_H
+#include "scene/2d/node_2d.h"
#include "scene/main/node.h"
-class Navigation2D;
-
class NavigationObstacle2D : public Node {
GDCLASS(NavigationObstacle2D, Node);
- Navigation2D *navigation = nullptr;
-
+ Node2D *parent_node2d = nullptr;
RID agent;
protected:
@@ -50,19 +48,11 @@ public:
NavigationObstacle2D();
virtual ~NavigationObstacle2D();
- void set_navigation(Navigation2D *p_nav);
- const Navigation2D *get_navigation() const {
- return navigation;
- }
-
- void set_navigation_node(Node *p_nav);
- Node *get_navigation_node() const;
-
RID get_rid() const {
return agent;
}
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_agent_shape();
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 7360fce330..d2caf5bea8 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -34,7 +34,6 @@
#include "core/core_string_names.h"
#include "core/math/geometry_2d.h"
#include "core/os/mutex.h"
-#include "navigation_2d.h"
#include "servers/navigation_server_2d.h"
#include "thirdparty/misc/polypartition.h"
@@ -365,10 +364,10 @@ void NavigationRegion2D::set_enabled(bool p_enabled) {
if (!enabled) {
NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
} else {
- if (navigation) {
- NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid());
- }
+ NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) {
@@ -380,6 +379,14 @@ bool NavigationRegion2D::is_enabled() const {
return enabled;
}
+void NavigationRegion2D::set_layers(uint32_t p_layers) {
+ NavigationServer2D::get_singleton()->region_set_layers(region, p_layers);
+}
+
+uint32_t NavigationRegion2D::get_layers() const {
+ return NavigationServer2D::get_singleton()->region_get_layers(region);
+}
+
/////////////////////////////
#ifdef TOOLS_ENABLED
Rect2 NavigationRegion2D::_edit_get_rect() const {
@@ -394,35 +401,24 @@ 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: {
- Node2D *c = this;
- while (c) {
- navigation = Object::cast_to<Navigation2D>(c);
- if (navigation) {
- if (enabled) {
- NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- break;
- }
-
- c = Object::cast_to<Node2D>(c->get_parent());
+ if (enabled) {
+ NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
-
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
NavigationServer2D::get_singleton()->region_set_transform(region, get_global_transform());
-
} break;
case NOTIFICATION_EXIT_TREE: {
- if (navigation) {
- NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ if (enabled) {
+ NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed));
}
- navigation = nullptr;
} break;
case NOTIFICATION_DRAW: {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) {
Vector<Vector2> verts = navpoly->get_vertices();
- int vsize = verts.size();
- if (vsize < 3) {
+ if (verts.size() < 3) {
return;
}
@@ -432,33 +428,47 @@ void NavigationRegion2D::_notification(int p_what) {
} else {
color = get_tree()->get_debug_navigation_disabled_color();
}
- Vector<Color> colors;
- Vector<Vector2> vertices;
- vertices.resize(vsize);
- colors.resize(vsize);
- {
- const Vector2 *vr = verts.ptr();
- for (int i = 0; i < vsize; i++) {
- vertices.write[i] = vr[i];
- colors.write[i] = color;
- }
- }
+ Color doors_color = color.lightened(0.2);
- Vector<int> indices;
+ RandomPCG rand;
for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
Vector<int> polygon = navpoly->get_polygon(i);
-
- for (int j = 2; j < polygon.size(); j++) {
- int kofs[3] = { 0, j - 1, j };
- for (int k = 0; k < 3; k++) {
- int idx = polygon[kofs[k]];
- ERR_FAIL_INDEX(idx, vsize);
- indices.push_back(idx);
- }
+ Vector<Vector2> vertices;
+ vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], verts.size());
+ vertices.write[j] = verts[polygon[j]];
}
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color;
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.a = color.a;
+ Vector<Color> colors;
+ colors.push_back(random_variation_color);
+
+ RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), vertices, colors);
+ }
+
+ // Draw the region
+ Transform2D xform = get_global_transform();
+ const NavigationServer2D *ns = NavigationServer2D::get_singleton();
+ float radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
+ for (int i = 0; i < ns->region_get_connections_count(region); i++) {
+ // Two main points
+ Vector2 a = ns->region_get_connection_pathway_start(region, i);
+ a = xform.affine_inverse().xform(a);
+ Vector2 b = ns->region_get_connection_pathway_end(region, i);
+ b = xform.affine_inverse().xform(b);
+ draw_line(a, b, doors_color);
+
+ // Draw a circle to illustrate the margins.
+ float angle = (b - a).angle();
+ draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color);
+ draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color);
}
- RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
}
} break;
}
@@ -481,8 +491,7 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
}
_navpoly_changed();
- _change_notify("navpoly");
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
@@ -494,32 +503,22 @@ void NavigationRegion2D::_navpoly_changed() {
update();
}
}
-
-String NavigationRegion2D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
+void NavigationRegion2D::_map_changed(RID p_map) {
+ if (enabled && get_world_2d()->get_navigation_map() == p_map) {
+ update();
}
+}
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> NavigationRegion2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node2D::get_configuration_warnings();
- if (!navpoly.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!navpoly.is_valid()) {
+ warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon."));
}
- warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
}
- const Node2D *c = this;
- while (c) {
- if (Object::cast_to<Navigation2D>(c)) {
- return warning;
- }
- c = Object::cast_to<Node2D>(c->get_parent());
- }
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- return warning + TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+ return warnings;
}
void NavigationRegion2D::_bind_methods() {
@@ -529,10 +528,14 @@ 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_layers", "layers"), &NavigationRegion2D::set_layers);
+ ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion2D::get_layers);
+
ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers");
}
NavigationRegion2D::NavigationRegion2D() {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 0b9a258a25..2db8d70791 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -91,17 +91,15 @@ public:
~NavigationPolygon() {}
};
-class Navigation2D;
-
class NavigationRegion2D : public Node2D {
GDCLASS(NavigationRegion2D, Node2D);
bool enabled = true;
RID region;
- Navigation2D *navigation = nullptr;
Ref<NavigationPolygon> navpoly;
void _navpoly_changed();
+ void _map_changed(RID p_RID);
protected:
void _notification(int p_what);
@@ -116,10 +114,13 @@ public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
+ void set_layers(uint32_t p_layers);
+ uint32_t get_layers() const;
+
void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
Ref<NavigationPolygon> get_navigation_polygon() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
NavigationRegion2D();
~NavigationRegion2D();
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 70a4e3f0fb..8afc43ddc9 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -53,12 +53,6 @@ void Node2D::_edit_set_state(const Dictionary &p_state) {
skew = p_state["skew"];
_update_transform();
- _change_notify("rotation");
- _change_notify("rotation_degrees");
- _change_notify("scale");
- _change_notify("skew");
- _change_notify("skew_degrees");
- _change_notify("position");
}
void Node2D::_edit_set_position(const Point2 &p_position) {
@@ -77,14 +71,12 @@ Size2 Node2D::_edit_get_scale() const {
return _scale;
}
-void Node2D::_edit_set_rotation(float p_rotation) {
+void Node2D::_edit_set_rotation(real_t p_rotation) {
angle = p_rotation;
_update_transform();
- _change_notify("rotation");
- _change_notify("rotation_degrees");
}
-float Node2D::_edit_get_rotation() const {
+real_t Node2D::_edit_get_rotation() const {
return angle;
}
@@ -124,8 +116,6 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
_scale *= new_scale;
_update_transform();
- _change_notify("scale");
- _change_notify("position");
}
#endif
@@ -156,34 +146,29 @@ void Node2D::set_position(const Point2 &p_pos) {
}
pos = p_pos;
_update_transform();
- _change_notify("position");
}
-void Node2D::set_rotation(float p_radians) {
+void Node2D::set_rotation(real_t p_radians) {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
angle = p_radians;
_update_transform();
- _change_notify("rotation");
- _change_notify("rotation_degrees");
}
-void Node2D::set_skew(float p_radians) {
+void Node2D::set_skew(real_t p_radians) {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
skew = p_radians;
_update_transform();
- _change_notify("skew");
- _change_notify("skew_degrees");
}
-void Node2D::set_rotation_degrees(float p_degrees) {
+void Node2D::set_rotation_degrees(real_t p_degrees) {
set_rotation(Math::deg2rad(p_degrees));
}
-void Node2D::set_skew_degrees(float p_degrees) {
+void Node2D::set_skew_degrees(real_t p_degrees) {
set_skew(Math::deg2rad(p_degrees));
}
@@ -200,7 +185,6 @@ void Node2D::set_scale(const Size2 &p_scale) {
_scale.y = CMP_EPSILON;
}
_update_transform();
- _change_notify("scale");
}
Point2 Node2D::get_position() const {
@@ -210,7 +194,7 @@ Point2 Node2D::get_position() const {
return pos;
}
-float Node2D::get_rotation() const {
+real_t Node2D::get_rotation() const {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -218,7 +202,7 @@ float Node2D::get_rotation() const {
return angle;
}
-float Node2D::get_skew() const {
+real_t Node2D::get_skew() const {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -226,11 +210,11 @@ float Node2D::get_skew() const {
return skew;
}
-float Node2D::get_rotation_degrees() const {
+real_t Node2D::get_rotation_degrees() const {
return Math::rad2deg(get_rotation());
}
-float Node2D::get_skew_degrees() const {
+real_t Node2D::get_skew_degrees() const {
return Math::rad2deg(get_skew());
}
@@ -246,7 +230,7 @@ Transform2D Node2D::get_transform() const {
return _mat;
}
-void Node2D::rotate(float p_radians) {
+void Node2D::rotate(real_t p_radians) {
set_rotation(get_rotation() + p_radians);
}
@@ -262,7 +246,7 @@ void Node2D::apply_scale(const Size2 &p_amount) {
set_scale(get_scale() * p_amount);
}
-void Node2D::move_x(float p_delta, bool p_scaled) {
+void Node2D::move_x(real_t p_delta, bool p_scaled) {
Transform2D t = get_transform();
Vector2 m = t[0];
if (!p_scaled) {
@@ -271,7 +255,7 @@ void Node2D::move_x(float p_delta, bool p_scaled) {
set_position(t[2] + m * p_delta);
}
-void Node2D::move_y(float p_delta, bool p_scaled) {
+void Node2D::move_y(real_t p_delta, bool p_scaled) {
Transform2D t = get_transform();
Vector2 m = t[1];
if (!p_scaled) {
@@ -295,25 +279,25 @@ void Node2D::set_global_position(const Point2 &p_pos) {
}
}
-float Node2D::get_global_rotation() const {
+real_t Node2D::get_global_rotation() const {
return get_global_transform().get_rotation();
}
-void Node2D::set_global_rotation(float p_radians) {
+void Node2D::set_global_rotation(real_t p_radians) {
CanvasItem *pi = get_parent_item();
if (pi) {
- const float parent_global_rot = pi->get_global_transform().get_rotation();
+ const real_t parent_global_rot = pi->get_global_transform().get_rotation();
set_rotation(p_radians - parent_global_rot);
} else {
set_rotation(p_radians);
}
}
-float Node2D::get_global_rotation_degrees() const {
+real_t Node2D::get_global_rotation_degrees() const {
return Math::rad2deg(get_global_rotation());
}
-void Node2D::set_global_rotation_degrees(float p_degrees) {
+void Node2D::set_global_rotation_degrees(real_t p_degrees) {
set_global_rotation(Math::deg2rad(p_degrees));
}
@@ -358,7 +342,6 @@ void Node2D::set_z_index(int p_z) {
ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
z_index = p_z;
RS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index);
- _change_notify("z_index");
}
void Node2D::set_z_as_relative(bool p_enabled) {
@@ -396,7 +379,7 @@ void Node2D::look_at(const Vector2 &p_pos) {
rotate(get_angle_to(p_pos));
}
-float Node2D::get_angle_to(const Vector2 &p_pos) const {
+real_t Node2D::get_angle_to(const Vector2 &p_pos) const {
return (to_local(p_pos) * get_scale()).angle();
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index c27d740b8a..358b7e6520 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -37,9 +37,9 @@ class Node2D : public CanvasItem {
GDCLASS(Node2D, CanvasItem);
Point2 pos;
- float angle = 0.0;
+ real_t angle = 0.0;
Size2 _scale = Vector2(1, 1);
- float skew = 0.0;
+ real_t skew = 0.0;
int z_index = 0;
bool z_relative = true;
@@ -65,51 +65,51 @@ public:
virtual void _edit_set_scale(const Size2 &p_scale) override;
virtual Size2 _edit_get_scale() const override;
- virtual void _edit_set_rotation(float p_rotation) override;
- virtual float _edit_get_rotation() const override;
+ virtual void _edit_set_rotation(real_t p_rotation) override;
+ virtual real_t _edit_get_rotation() const override;
virtual bool _edit_use_rotation() const override;
virtual void _edit_set_rect(const Rect2 &p_edit_rect) override;
#endif
void set_position(const Point2 &p_pos);
- void set_rotation(float p_radians);
- void set_rotation_degrees(float p_degrees);
- void set_skew(float p_radians);
- void set_skew_degrees(float p_radians);
+ void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
+ void set_skew(real_t p_radians);
+ void set_skew_degrees(real_t p_radians);
void set_scale(const Size2 &p_scale);
- void rotate(float p_radians);
- void move_x(float p_delta, bool p_scaled = false);
- void move_y(float p_delta, bool p_scaled = false);
+ void rotate(real_t p_radians);
+ void move_x(real_t p_delta, bool p_scaled = false);
+ void move_y(real_t p_delta, bool p_scaled = false);
void translate(const Vector2 &p_amount);
void global_translate(const Vector2 &p_amount);
void apply_scale(const Size2 &p_amount);
Point2 get_position() const;
- float get_rotation() const;
- float get_skew() const;
- float get_rotation_degrees() const;
- float get_skew_degrees() const;
+ real_t get_rotation() const;
+ real_t get_skew() const;
+ real_t get_rotation_degrees() const;
+ real_t get_skew_degrees() const;
Size2 get_scale() const;
Point2 get_global_position() const;
- float get_global_rotation() const;
- float get_global_rotation_degrees() const;
+ real_t get_global_rotation() const;
+ real_t get_global_rotation_degrees() const;
Size2 get_global_scale() const;
void set_transform(const Transform2D &p_transform);
void set_global_transform(const Transform2D &p_transform);
void set_global_position(const Point2 &p_pos);
- void set_global_rotation(float p_radians);
- void set_global_rotation_degrees(float p_degrees);
+ void set_global_rotation(real_t p_radians);
+ void set_global_rotation_degrees(real_t p_degrees);
void set_global_scale(const Size2 &p_scale);
void set_z_index(int p_z);
int get_z_index() const;
void look_at(const Vector2 &p_pos);
- float get_angle_to(const Vector2 &p_pos) const;
+ real_t get_angle_to(const Vector2 &p_pos) const;
Point2 to_local(Point2 p_global) const;
Point2 to_global(Point2 p_local) const;
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index c93915d1bc..4870ae614b 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -51,11 +51,11 @@ void ParallaxBackground::_camera_moved(const Transform2D &p_transform, const Poi
set_scroll_offset(p_transform.get_origin());
}
-void ParallaxBackground::set_scroll_scale(float p_scale) {
+void ParallaxBackground::set_scroll_scale(real_t p_scale) {
scale = p_scale;
}
-float ParallaxBackground::get_scroll_scale() const {
+real_t ParallaxBackground::get_scroll_scale() const {
return scale;
}
diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h
index c9991efc9d..27134dab29 100644
--- a/scene/2d/parallax_background.h
+++ b/scene/2d/parallax_background.h
@@ -39,7 +39,7 @@ class ParallaxBackground : public CanvasLayer {
GDCLASS(ParallaxBackground, CanvasLayer);
Point2 offset;
- float scale = 1.0;
+ real_t scale = 1.0;
Point2 base_offset;
Point2 base_scale = Vector2(1, 1);
Point2 screen_offset;
@@ -61,8 +61,8 @@ public:
void set_scroll_offset(const Point2 &p_ofs);
Point2 get_scroll_offset() const;
- void set_scroll_scale(float p_scale);
- float get_scroll_scale() const;
+ void set_scroll_scale(real_t p_scale);
+ real_t get_scroll_scale() const;
void set_scroll_base_offset(const Point2 &p_ofs);
Point2 get_scroll_base_offset() const;
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index a38338e1e3..228020d383 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -39,7 +39,7 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
- float scale = pb->get_scroll_scale();
+ real_t scale = pb->get_scroll_scale();
set_base_offset_and_scale(ofs, scale, screen_offset);
}
}
@@ -54,7 +54,7 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
- float scale = pb->get_scroll_scale();
+ real_t scale = pb->get_scroll_scale();
set_base_offset_and_scale(ofs, scale, screen_offset);
}
}
@@ -107,7 +107,7 @@ void ParallaxLayer::_notification(int p_what) {
}
}
-void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset) {
+void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset) {
screen_offset = p_screen_offset;
if (!is_inside_tree()) {
@@ -135,17 +135,14 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
_update_mirroring();
}
-String ParallaxLayer::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> ParallaxLayer::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<ParallaxBackground>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
+ warnings.push_back(TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));
}
- return warning;
+ return warnings;
}
void ParallaxLayer::_bind_methods() {
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index 86694c7724..cc2d2e096e 100644
--- a/scene/2d/parallax_layer.h
+++ b/scene/2d/parallax_layer.h
@@ -59,9 +59,9 @@ public:
void set_mirroring(const Size2 &p_mirroring);
Size2 get_mirroring() const;
- void set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset);
+ void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ParallaxLayer();
};
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 8c103a1239..9912612c4f 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -96,9 +96,9 @@ void Path2D::_notification(int p_what) {
}
#ifdef TOOLS_ENABLED
- const float line_width = 2 * EDSCALE;
+ const real_t line_width = 2 * EDSCALE;
#else
- const float line_width = 2;
+ const real_t line_width = 2;
#endif
const Color color = Color(0.5, 0.6, 1.0, 0.7);
@@ -164,14 +164,14 @@ void PathFollow2D::_update_transform() {
return;
}
- float path_length = c->get_baked_length();
+ real_t path_length = c->get_baked_length();
if (path_length == 0) {
return;
}
Vector2 pos = c->interpolate_baked(offset, cubic);
if (rotates) {
- float ahead = offset + lookahead;
+ real_t ahead = offset + lookahead;
if (loop && ahead >= path_length) {
// If our lookahead will loop, we need to check if the path is closed.
@@ -240,7 +240,7 @@ bool PathFollow2D::get_cubic_interpolation() const {
void PathFollow2D::_validate_property(PropertyInfo &property) const {
if (property.name == "offset") {
- float max = 10000.0;
+ real_t max = 10000.0;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
@@ -249,21 +249,16 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const {
}
}
-String PathFollow2D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> PathFollow2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!Object::cast_to<Path2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!Object::cast_to<Path2D>(get_parent())) {
+ warnings.push_back(TTR("PathFollow2D only works when set as a child of a Path2D node."));
}
- warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");
}
- return warning;
+ return warnings;
}
void PathFollow2D::_bind_methods() {
@@ -301,11 +296,11 @@ void PathFollow2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
}
-void PathFollow2D::set_offset(float p_offset) {
+void PathFollow2D::set_offset(real_t p_offset) {
offset = p_offset;
if (path) {
if (path->get_curve().is_valid()) {
- float path_length = path->get_curve()->get_baked_length();
+ real_t path_length = path->get_curve()->get_baked_length();
if (loop) {
offset = Math::fposmod(offset, path_length);
@@ -319,43 +314,41 @@ void PathFollow2D::set_offset(float p_offset) {
_update_transform();
}
- _change_notify("offset");
- _change_notify("unit_offset");
}
-void PathFollow2D::set_h_offset(float p_h_offset) {
+void PathFollow2D::set_h_offset(real_t p_h_offset) {
h_offset = p_h_offset;
if (path) {
_update_transform();
}
}
-float PathFollow2D::get_h_offset() const {
+real_t PathFollow2D::get_h_offset() const {
return h_offset;
}
-void PathFollow2D::set_v_offset(float p_v_offset) {
+void PathFollow2D::set_v_offset(real_t p_v_offset) {
v_offset = p_v_offset;
if (path) {
_update_transform();
}
}
-float PathFollow2D::get_v_offset() const {
+real_t PathFollow2D::get_v_offset() const {
return v_offset;
}
-float PathFollow2D::get_offset() const {
+real_t PathFollow2D::get_offset() const {
return offset;
}
-void PathFollow2D::set_unit_offset(float p_unit_offset) {
+void PathFollow2D::set_unit_offset(real_t p_unit_offset) {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
set_offset(p_unit_offset * path->get_curve()->get_baked_length());
}
}
-float PathFollow2D::get_unit_offset() const {
+real_t PathFollow2D::get_unit_offset() const {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
return get_offset() / path->get_curve()->get_baked_length();
} else {
@@ -363,11 +356,11 @@ float PathFollow2D::get_unit_offset() const {
}
}
-void PathFollow2D::set_lookahead(float p_lookahead) {
+void PathFollow2D::set_lookahead(real_t p_lookahead) {
lookahead = p_lookahead;
}
-float PathFollow2D::get_lookahead() const {
+real_t PathFollow2D::get_lookahead() const {
return lookahead;
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index a748817555..3b12f025fc 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -81,20 +81,20 @@ protected:
static void _bind_methods();
public:
- void set_offset(float p_offset);
- float get_offset() const;
+ void set_offset(real_t p_offset);
+ real_t get_offset() const;
- void set_h_offset(float p_h_offset);
- float get_h_offset() const;
+ void set_h_offset(real_t p_h_offset);
+ real_t get_h_offset() const;
- void set_v_offset(float p_v_offset);
- float get_v_offset() const;
+ void set_v_offset(real_t p_v_offset);
+ real_t get_v_offset() const;
- void set_unit_offset(float p_unit_offset);
- float get_unit_offset() const;
+ void set_unit_offset(real_t p_unit_offset);
+ real_t get_unit_offset() const;
- void set_lookahead(float p_lookahead);
- float get_lookahead() const;
+ void set_lookahead(real_t p_lookahead);
+ real_t get_lookahead() const;
void set_loop(bool p_loop);
bool has_loop() const;
@@ -105,7 +105,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PathFollow2D() {}
};
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 96d8fb609b..3f2f6d6b1c 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -42,70 +42,9 @@ void PhysicsBody2D::_notification(int p_what) {
}
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody2D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody2D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody2D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody2D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody2D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody2D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with);
-
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
-}
-
-void PhysicsBody2D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody2D::get_collision_layer() const {
- return collision_layer;
-}
-
-void PhysicsBody2D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t PhysicsBody2D::get_collision_mask() const {
- return collision_mask;
-}
-
-void PhysicsBody2D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool PhysicsBody2D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void PhysicsBody2D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t collision_layer = get_collision_layer();
- if (p_value) {
- collision_layer |= 1 << p_bit;
- } else {
- collision_layer &= ~(1 << p_bit);
- }
- set_collision_layer(collision_layer);
-}
-
-bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
}
PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
@@ -332,6 +271,7 @@ bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia,
void RigidBody2D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
#else
state = (PhysicsDirectBodyState2D *)p_state; //trust it
#endif
@@ -411,13 +351,13 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
}
}
- //process remotions
+ //process removals
for (int i = 0; i < toremove_count; i++) {
_body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
- //process aditions
+ //process additions
for (int i = 0; i < toadd_count; i++) {
_body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
@@ -708,26 +648,23 @@ void RigidBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
#endif
}
-String RigidBody2D::get_configuration_warning() const {
+TypedArray<String> RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
- String warning = CollisionObject2D::get_configuration_warning();
+ TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void RigidBody2D::_bind_methods() {
@@ -793,8 +730,6 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody2D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
@@ -838,7 +773,7 @@ void RigidBody2D::_bind_methods() {
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed));
}
RigidBody2D::~RigidBody2D() {
@@ -1144,11 +1079,11 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) {
}
if (p_enable) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody2D::_direct_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
@@ -1164,6 +1099,7 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
}
PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
last_valid_transform = state->get_transform();
set_notify_local_transform(false);
@@ -1217,8 +1153,6 @@ void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled);
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody2D::_direct_state_changed);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 2dc853b23b..e0fc0766bc 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -41,9 +41,6 @@ class KinematicCollision2D;
class PhysicsBody2D : public CollisionObject2D {
GDCLASS(PhysicsBody2D, CollisionObject2D);
- uint32_t collision_layer = 1;
- uint32_t collision_mask = 1;
-
protected:
void _notification(int p_what);
PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);
@@ -51,18 +48,6 @@ protected:
static void _bind_methods();
public:
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
@@ -246,7 +231,7 @@ public:
TypedArray<Node2D> get_colliding_bodies() const; //function for script
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RigidBody2D();
~RigidBody2D();
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index ecb354ad15..1a7038bb80 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -90,6 +90,12 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler
}
#endif
+void Polygon2D::_validate_property(PropertyInfo &property) const {
+ if (!invert && property.name == "invert_border") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void Polygon2D::_skeleton_bone_setup_changed() {
update();
}
@@ -154,8 +160,8 @@ void Polygon2D::_notification(int p_what) {
if (invert) {
Rect2 bounds;
int highest_idx = -1;
- float highest_y = -1e20;
- float sum = 0.0;
+ real_t highest_y = -1e20;
+ real_t sum = 0.0;
for (int i = 0; i < len; i++) {
if (i == 0) {
@@ -273,7 +279,7 @@ void Polygon2D::_notification(int p_what) {
//normalize the weights
for (int i = 0; i < vc; i++) {
- float tw = 0.0;
+ real_t tw = 0.0;
for (int j = 0; j < 4; j++) {
tw += weightsw[i * 4 + j];
}
@@ -426,20 +432,20 @@ Vector2 Polygon2D::get_texture_offset() const {
return tex_ofs;
}
-void Polygon2D::set_texture_rotation(float p_rot) {
+void Polygon2D::set_texture_rotation(real_t p_rot) {
tex_rot = p_rot;
update();
}
-float Polygon2D::get_texture_rotation() const {
+real_t Polygon2D::get_texture_rotation() const {
return tex_rot;
}
-void Polygon2D::set_texture_rotation_degrees(float p_rot) {
+void Polygon2D::set_texture_rotation_degrees(real_t p_rot) {
set_texture_rotation(Math::deg2rad(p_rot));
}
-float Polygon2D::get_texture_rotation_degrees() const {
+real_t Polygon2D::get_texture_rotation_degrees() const {
return Math::rad2deg(get_texture_rotation());
}
@@ -455,6 +461,7 @@ Size2 Polygon2D::get_texture_scale() const {
void Polygon2D::set_invert(bool p_invert) {
invert = p_invert;
update();
+ notify_property_list_changed();
}
bool Polygon2D::get_invert() const {
@@ -470,12 +477,12 @@ bool Polygon2D::get_antialiased() const {
return antialiased;
}
-void Polygon2D::set_invert_border(float p_invert_border) {
+void Polygon2D::set_invert_border(real_t p_invert_border) {
invert_border = p_invert_border;
update();
}
-float Polygon2D::get_invert_border() const {
+real_t Polygon2D::get_invert_border() const {
return invert_border;
}
@@ -483,7 +490,6 @@ void Polygon2D::set_offset(const Vector2 &p_offset) {
offset = p_offset;
rect_cache_dirty = true;
update();
- _change_notify("offset");
}
Vector2 Polygon2D::get_offset() const {
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index ab01a4ffd0..c207024a53 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -55,9 +55,9 @@ class Polygon2D : public Node2D {
Size2 tex_scale = Vector2(1, 1);
Vector2 tex_ofs;
bool tex_tile = true;
- float tex_rot = 0.0;
+ real_t tex_rot = 0.0;
bool invert = false;
- float invert_border = 100.0;
+ real_t invert_border = 100.0;
bool antialiased = false;
Vector2 offset;
@@ -75,6 +75,7 @@ class Polygon2D : public Node2D {
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
#ifdef TOOLS_ENABLED
@@ -114,11 +115,11 @@ public:
void set_texture_offset(const Vector2 &p_offset);
Vector2 get_texture_offset() const;
- void set_texture_rotation(float p_rot);
- float get_texture_rotation() const;
+ void set_texture_rotation(real_t p_rot);
+ real_t get_texture_rotation() const;
- void set_texture_rotation_degrees(float p_rot);
- float get_texture_rotation_degrees() const;
+ void set_texture_rotation_degrees(real_t p_rot);
+ real_t get_texture_rotation_degrees() const;
void set_texture_scale(const Size2 &p_scale);
Size2 get_texture_scale() const;
@@ -129,8 +130,8 @@ public:
void set_antialiased(bool p_antialiased);
bool get_antialiased() const;
- void set_invert_border(float p_invert_border);
- float get_invert_border() const;
+ void set_invert_border(real_t p_invert_border);
+ real_t get_invert_border() const;
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index ff7a0dbac3..5c7d65e3e0 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -33,10 +33,10 @@
#include "core/config/engine.h"
#include "scene/resources/texture.h"
-const float DEFAULT_GIZMO_EXTENTS = 10.0;
+const real_t DEFAULT_GIZMO_EXTENTS = 10.0;
void Position2D::_draw_cross() {
- float extents = get_gizmo_extents();
+ real_t extents = get_gizmo_extents();
// Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`)
draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32));
draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01));
@@ -44,7 +44,7 @@ void Position2D::_draw_cross() {
#ifdef TOOLS_ENABLED
Rect2 Position2D::_edit_get_rect() const {
- float extents = get_gizmo_extents();
+ real_t extents = get_gizmo_extents();
return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2));
}
@@ -70,7 +70,7 @@ void Position2D::_notification(int p_what) {
}
}
-void Position2D::set_gizmo_extents(float p_extents) {
+void Position2D::set_gizmo_extents(real_t p_extents) {
if (p_extents == DEFAULT_GIZMO_EXTENTS) {
set_meta("_gizmo_extents_", Variant());
} else {
@@ -80,7 +80,7 @@ void Position2D::set_gizmo_extents(float p_extents) {
update();
}
-float Position2D::get_gizmo_extents() const {
+real_t Position2D::get_gizmo_extents() const {
if (has_meta("_gizmo_extents_")) {
return get_meta("_gizmo_extents_");
} else {
diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h
index fcaef0e6a3..9ed622c8f6 100644
--- a/scene/2d/position_2d.h
+++ b/scene/2d/position_2d.h
@@ -48,8 +48,8 @@ public:
virtual bool _edit_use_rect() const override;
#endif
- void set_gizmo_extents(float p_extents);
- float get_gizmo_extents() const;
+ void set_gizmo_extents(real_t p_extents);
+ real_t get_gizmo_extents() const;
Position2D();
};
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 2cc3a74270..f6740040c1 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -55,6 +55,7 @@ uint32_t RayCast2D::get_collision_mask() const {
}
void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -65,6 +66,7 @@ void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool RayCast2D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -159,30 +161,7 @@ void RayCast2D::_notification(int p_what) {
if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
break;
}
- Transform2D xf;
- xf.rotate(target_position.angle());
- xf.translate(Vector2(target_position.length(), 0));
-
- // Draw an arrow indicating where the RayCast is pointing to
- Color draw_col = get_tree()->get_debug_collisions_color();
- if (!enabled) {
- float g = draw_col.get_v();
- draw_col.r = g;
- draw_col.g = g;
- draw_col.b = g;
- }
- draw_line(Vector2(), target_position, draw_col, 2);
- Vector<Vector2> pts;
- float tsize = 8.0;
- pts.push_back(xf.xform(Vector2(tsize, 0)));
- pts.push_back(xf.xform(Vector2(0, Math_SQRT12 * tsize)));
- pts.push_back(xf.xform(Vector2(0, -Math_SQRT12 * tsize)));
- Vector<Color> cols;
- for (int i = 0; i < 3; i++) {
- cols.push_back(draw_col);
- }
-
- draw_primitive(pts, cols, Vector<Vector2>());
+ _draw_debug_shape();
} break;
@@ -212,7 +191,7 @@ void RayCast2D::_update_raycast_state() {
}
PhysicsDirectSpaceState2D::RayResult rr;
-
+ bool prev_collision_state = collided;
if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
@@ -224,6 +203,48 @@ void RayCast2D::_update_raycast_state() {
against = ObjectID();
against_shape = 0;
}
+
+ if (prev_collision_state != collided) {
+ update();
+ }
+}
+
+void RayCast2D::_draw_debug_shape() {
+ Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color();
+ if (!enabled) {
+ float g = draw_col.get_v();
+ draw_col.r = g;
+ draw_col.g = g;
+ draw_col.b = g;
+ }
+
+ // Draw an arrow indicating where the RayCast is pointing to
+ const float max_arrow_size = 6;
+ const float line_width = 1.4;
+ bool no_line = target_position.length() < line_width;
+ float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
+
+ if (no_line) {
+ arrow_size = target_position.length();
+ } else {
+ draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width);
+ }
+
+ Transform2D xf;
+ xf.rotate(target_position.angle());
+ xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
+
+ Vector<Vector2> pts;
+ pts.push_back(xf.xform(Vector2(arrow_size, 0)));
+ pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size)));
+ pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size)));
+
+ Vector<Color> cols;
+ for (int i = 0; i < 3; i++) {
+ cols.push_back(draw_col);
+ }
+
+ draw_primitive(pts, cols, Vector<Vector2>());
}
void RayCast2D::force_raycast_update() {
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index dab3302e25..984c6bda49 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -51,6 +51,8 @@ class RayCast2D : public Node2D {
bool collide_with_areas = false;
bool collide_with_bodies = true;
+ void _draw_debug_shape();
+
protected:
void _notification(int p_what);
void _update_raycast_state();
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index f10714e28a..a7613dc009 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -138,7 +138,7 @@ void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {
_update_remote();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath RemoteTransform2D::get_remote_node() const {
@@ -185,17 +185,14 @@ void RemoteTransform2D::force_update_cache() {
_update_cache();
}
-String RemoteTransform2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> RemoteTransform2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path property must point to a valid Node2D node to work.");
+ warnings.push_back(TTR("Path property must point to a valid Node2D node to work."));
}
- return warning;
+ return warnings;
}
void RemoteTransform2D::_bind_methods() {
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index 4a26d7b339..36fddb58c7 100644
--- a/scene/2d/remote_transform_2d.h
+++ b/scene/2d/remote_transform_2d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RemoteTransform2D();
};
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 48e44e01a1..22180797f0 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -100,7 +100,7 @@ void Bone2D::set_rest(const Transform2D &p_rest) {
skeleton->_make_bone_setup_dirty();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Transform2D Bone2D::get_rest() const {
@@ -119,11 +119,11 @@ void Bone2D::apply_rest() {
set_transform(rest);
}
-void Bone2D::set_default_length(float p_length) {
+void Bone2D::set_default_length(real_t p_length) {
default_length = p_length;
}
-float Bone2D::get_default_length() const {
+real_t Bone2D::get_default_length() const {
return default_length;
}
@@ -133,27 +133,21 @@ int Bone2D::get_index_in_skeleton() const {
return skeleton_index;
}
-String Bone2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> Bone2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!skeleton) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
if (parent_bone) {
- warning += TTR("This Bone2D chain should end at a Skeleton2D node.");
+ warnings.push_back(TTR("This Bone2D chain should end at a Skeleton2D node."));
} else {
- warning += TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.");
+ warnings.push_back(TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."));
}
}
if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
+ warnings.push_back(TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."));
}
- return warning;
+ return warnings;
}
Bone2D::Bone2D() {
@@ -182,9 +176,9 @@ void Skeleton2D::_update_bone_setup() {
}
bone_setup_dirty = false;
- RS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);
+ RS::get_singleton()->skeleton_allocate_data(skeleton, bones.size(), true);
- bones.sort(); //sorty so they are always in the same order/index
+ bones.sort(); //sorting so that they are always in the same order/index
for (int i = 0; i < bones.size(); i++) {
bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index 80ca8c80ac..fd62b87bde 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -46,7 +46,7 @@ class Bone2D : public Node2D {
Bone2D *parent_bone = nullptr;
Skeleton2D *skeleton = nullptr;
Transform2D rest;
- float default_length = 16.0;
+ real_t default_length = 16.0;
int skeleton_index = -1;
@@ -60,10 +60,10 @@ public:
void apply_rest();
Transform2D get_skeleton_rest() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
- void set_default_length(float p_length);
- float get_default_length() const;
+ void set_default_length(real_t p_length);
+ real_t get_default_length() const;
int get_index_in_skeleton() const;
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index d1a3c01266..7c93edbff9 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -77,14 +77,14 @@ Rect2 Sprite2D::get_anchorable_rect() const {
return get_rect();
}
-void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
+void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const {
Rect2 base_rect;
- if (region) {
- r_filter_clip = region_filter_clip;
+ if (region_enabled) {
+ r_filter_clip_enabled = region_filter_clip_enabled;
base_rect = region_rect;
} else {
- r_filter_clip = false;
+ r_filter_clip_enabled = false;
base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
}
@@ -129,10 +129,10 @@ void Sprite2D::_notification(int p_what) {
*/
Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
+ bool filter_clip_enabled;
+ _get_rects(src_rect, dst_rect, filter_clip_enabled);
- texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip);
+ texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip_enabled);
} break;
}
}
@@ -155,7 +155,6 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {
update();
emit_signal("texture_changed");
item_rect_changed();
- _change_notify("texture");
}
Ref<Texture2D> Sprite2D::get_texture() const {
@@ -176,7 +175,6 @@ void Sprite2D::set_offset(const Point2 &p_offset) {
offset = p_offset;
update();
item_rect_changed();
- _change_notify("offset");
}
Point2 Sprite2D::get_offset() const {
@@ -201,17 +199,18 @@ bool Sprite2D::is_flipped_v() const {
return vflip;
}
-void Sprite2D::set_region(bool p_region) {
- if (p_region == region) {
+void Sprite2D::set_region_enabled(bool p_region_enabled) {
+ if (p_region_enabled == region_enabled) {
return;
}
- region = p_region;
+ region_enabled = p_region_enabled;
update();
+ notify_property_list_changed();
}
-bool Sprite2D::is_region() const {
- return region;
+bool Sprite2D::is_region_enabled() const {
+ return region_enabled;
}
void Sprite2D::set_region_rect(const Rect2 &p_region_rect) {
@@ -221,24 +220,22 @@ void Sprite2D::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
- if (region) {
+ if (region_enabled) {
item_rect_changed();
}
-
- _change_notify("region_rect");
}
Rect2 Sprite2D::get_region_rect() const {
return region_rect;
}
-void Sprite2D::set_region_filter_clip(bool p_enable) {
- region_filter_clip = p_enable;
+void Sprite2D::set_region_filter_clip_enabled(bool p_region_filter_clip_enabled) {
+ region_filter_clip_enabled = p_region_filter_clip_enabled;
update();
}
bool Sprite2D::is_region_filter_clip_enabled() const {
- return region_filter_clip;
+ return region_filter_clip_enabled;
}
void Sprite2D::set_frame(int p_frame) {
@@ -250,8 +247,6 @@ void Sprite2D::set_frame(int p_frame) {
frame = p_frame;
- _change_notify("frame");
- _change_notify("frame_coords");
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -275,7 +270,7 @@ void Sprite2D::set_vframes(int p_amount) {
vframes = p_amount;
update();
item_rect_changed();
- _change_notify();
+ notify_property_list_changed();
}
int Sprite2D::get_vframes() const {
@@ -287,7 +282,7 @@ void Sprite2D::set_hframes(int p_amount) {
hframes = p_amount;
update();
item_rect_changed();
- _change_notify();
+ notify_property_list_changed();
}
int Sprite2D::get_hframes() const {
@@ -304,8 +299,8 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const {
}
Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
+ bool filter_clip_enabled;
+ _get_rects(src_rect, dst_rect, filter_clip_enabled);
dst_rect.size = dst_rect.size.abs();
if (!dst_rect.has_point(p_point)) {
@@ -355,7 +350,7 @@ Rect2 Sprite2D::get_rect() const {
Size2i s;
- if (region) {
+ if (region_enabled) {
s = region_rect.size;
} else {
s = texture->get_size();
@@ -389,6 +384,10 @@ void Sprite2D::_validate_property(PropertyInfo &property) const {
if (property.name == "frame_coords") {
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
}
void Sprite2D::_texture_changed() {
@@ -415,15 +414,15 @@ void Sprite2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite2D::set_flip_v);
ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite2D::is_flipped_v);
- ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite2D::set_region);
- ClassDB::bind_method(D_METHOD("is_region"), &Sprite2D::is_region);
+ ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite2D::set_region_enabled);
+ ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite2D::is_region_enabled);
ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite2D::is_pixel_opaque);
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite2D::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite2D::get_region_rect);
- ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite2D::set_region_filter_clip);
+ ClassDB::bind_method(D_METHOD("set_region_filter_clip_enabled", "enabled"), &Sprite2D::set_region_filter_clip_enabled);
ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite2D::is_region_filter_clip_enabled);
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite2D::set_frame);
@@ -456,9 +455,9 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip_enabled"), "set_region_filter_clip_enabled", "is_region_filter_clip_enabled");
}
Sprite2D::Sprite2D() {
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
index fa765f457d..9db74cfe26 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -39,23 +39,23 @@ class Sprite2D : public Node2D {
Ref<Texture2D> texture;
Color specular_color;
- float shininess = 0.0;
+ real_t shininess = 0.0;
bool centered = true;
Point2 offset;
bool hflip = false;
bool vflip = false;
- bool region = false;
+ bool region_enabled = false;
Rect2 region_rect;
- bool region_filter_clip = false;
+ bool region_filter_clip_enabled = false;
int frame = 0;
int vframes = 1;
int hframes = 1;
- void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const;
void _texture_changed();
@@ -97,10 +97,10 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_enabled);
+ bool is_region_enabled() const;
- void set_region_filter_clip(bool p_enable);
+ void set_region_filter_clip_enabled(bool p_enabled);
bool is_region_filter_clip_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 33c238d455..4565543ec3 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -48,16 +48,6 @@ int TileMap::_get_quadrant_size() const {
void TileMap::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- Node2D *c = this;
- while (c) {
- navigation = Object::cast_to<Navigation2D>(c);
- if (navigation) {
- break;
- }
-
- c = Object::cast_to<Node2D>(c->get_parent());
- }
-
if (use_parent) {
_clear_quadrants();
collision_parent = Object::cast_to<CollisionObject2D>(get_parent());
@@ -69,7 +59,7 @@ void TileMap::_notification(int p_what) {
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
_update_quadrant_space(space);
- update_configuration_warning();
+ update_configuration_warnings();
} break;
@@ -77,12 +67,10 @@ void TileMap::_notification(int p_what) {
_update_quadrant_space(RID());
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- if (navigation) {
- for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID());
- }
- q.navpoly_ids.clear();
+ for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
+ NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID());
}
+ q.navpoly_ids.clear();
if (collision_parent) {
collision_parent->remove_shape_owner(q.shape_owner_id);
@@ -96,8 +84,6 @@ void TileMap::_notification(int p_what) {
}
collision_parent = nullptr;
- navigation = nullptr;
-
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -135,11 +121,6 @@ void TileMap::_update_quadrant_transform() {
local_transform = get_transform();
}
- Transform2D nav_rel;
- if (navigation) {
- nav_rel = get_relative_transform_to_parent(navigation);
- }
-
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
Transform2D xform;
@@ -150,9 +131,9 @@ void TileMap::_update_quadrant_transform() {
PhysicsServer2D::get_singleton()->body_set_state(q.body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
- if (navigation) {
+ if (bake_navigation) {
for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- NavigationServer2D::get_singleton()->region_set_transform(F->get().region, nav_rel * F->get().xform);
+ NavigationServer2D::get_singleton()->region_set_transform(F->get().region, F->get().xform);
}
}
@@ -165,7 +146,6 @@ void TileMap::_update_quadrant_transform() {
void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
if (tile_set.is_valid()) {
tile_set->disconnect("changed", callable_mp(this, &TileMap::_recreate_quadrants));
- tile_set->remove_change_receptor(this);
}
_clear_quadrants();
@@ -173,7 +153,6 @@ void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
if (tile_set.is_valid()) {
tile_set->connect("changed", callable_mp(this, &TileMap::_recreate_quadrants));
- tile_set->add_change_receptor(this);
} else {
clear();
}
@@ -317,11 +296,6 @@ void TileMap::update_dirty_quadrants() {
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
Vector2 tofs = get_cell_draw_offset();
- Transform2D nav_rel;
- if (navigation) {
- nav_rel = get_relative_transform_to_parent(navigation);
- }
-
Vector2 qofs;
SceneTree *st = SceneTree::get_singleton();
@@ -354,12 +328,10 @@ void TileMap::update_dirty_quadrants() {
}
int shape_idx = 0;
- if (navigation) {
- for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
- }
- q.navpoly_ids.clear();
+ for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
+ NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
}
+ q.navpoly_ids.clear();
for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
RS::get_singleton()->free(E->get().id);
@@ -581,7 +553,7 @@ void TileMap::update_dirty_quadrants() {
vs->canvas_item_add_set_transform(debug_canvas_item, Transform2D());
}
- if (navigation) {
+ if (bake_navigation) {
Ref<NavigationPolygon> navpoly;
Vector2 npoly_ofs;
if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
@@ -598,8 +570,8 @@ void TileMap::update_dirty_quadrants() {
_fix_cell_transform(xform, c, npoly_ofs, s);
RID region = NavigationServer2D::get_singleton()->region_create();
- NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid());
- NavigationServer2D::get_singleton()->region_set_transform(region, nav_rel * xform);
+ NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->region_set_transform(region, xform);
NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
Quadrant::NavPoly np;
@@ -789,12 +761,10 @@ void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) {
dirty_quadrant_list.remove(&q.dirty_list);
}
- if (navigation) {
- for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
- }
- q.navpoly_ids.clear();
+ for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
+ NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
}
+ q.navpoly_ids.clear();
for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
RS::get_singleton()->free(E->get().id);
@@ -1280,6 +1250,7 @@ void TileMap::set_collision_mask(uint32_t p_mask) {
}
void TileMap::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t layer = get_collision_layer();
if (p_value) {
layer |= 1 << p_bit;
@@ -1290,6 +1261,7 @@ void TileMap::set_collision_layer_bit(int p_bit, bool p_value) {
}
void TileMap::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -1330,8 +1302,8 @@ void TileMap::set_collision_use_parent(bool p_use_parent) {
}
_recreate_quadrants();
- _change_notify();
- update_configuration_warning();
+ notify_property_list_changed();
+ update_configuration_warnings();
}
void TileMap::set_collision_friction(float p_friction) {
@@ -1362,6 +1334,17 @@ float TileMap::get_collision_bounce() const {
return bounce;
}
+void TileMap::set_bake_navigation(bool p_bake_navigation) {
+ bake_navigation = p_bake_navigation;
+ for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
+ _make_quadrant_dirty(F);
+ }
+}
+
+bool TileMap::is_baking_navigation() {
+ return bake_navigation;
+}
+
uint32_t TileMap::get_collision_layer() const {
return collision_layer;
}
@@ -1371,10 +1354,12 @@ uint32_t TileMap::get_collision_mask() const {
}
bool TileMap::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
bool TileMap::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -1712,17 +1697,14 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
}
}
-String TileMap::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> TileMap::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (use_parent && !collision_parent) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
- return warning;
+ return warnings;
}
void TileMap::_bind_methods() {
@@ -1786,6 +1768,9 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_bounce", "value"), &TileMap::set_collision_bounce);
ClassDB::bind_method(D_METHOD("get_collision_bounce"), &TileMap::get_collision_bounce);
+ ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &TileMap::set_bake_navigation);
+ ClassDB::bind_method(D_METHOD("is_baking_navigation"), &TileMap::is_baking_navigation);
+
ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &TileMap::set_occluder_light_mask);
ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &TileMap::get_occluder_light_mask);
@@ -1844,6 +1829,9 @@ void TileMap::_bind_methods() {
ADD_GROUP("Occluder", "occluder_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
+ ADD_GROUP("Navigation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
+
ADD_PROPERTY_DEFAULT("format", FORMAT_1);
ADD_SIGNAL(MethodInfo("settings_changed"));
@@ -1865,21 +1853,11 @@ void TileMap::_bind_methods() {
BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT);
}
-void TileMap::_changed_callback(Object *p_changed, const char *p_prop) {
- if (tile_set.is_valid() && tile_set.ptr() == p_changed) {
- emit_signal("settings_changed");
- }
-}
-
TileMap::TileMap() {
set_notify_transform(true);
set_notify_local_transform(false);
}
TileMap::~TileMap() {
- if (tile_set.is_valid()) {
- tile_set->remove_change_receptor(this);
- }
-
clear();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index cfed4c0743..9d27053fee 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -33,7 +33,6 @@
#include "core/templates/self_list.h"
#include "core/templates/vset.h"
-#include "scene/2d/navigation_2d.h"
#include "scene/2d/node_2d.h"
#include "scene/resources/tile_set.h"
@@ -78,7 +77,7 @@ private:
bool use_parent = false;
CollisionObject2D *collision_parent = nullptr;
bool use_kinematic = false;
- Navigation2D *navigation = nullptr;
+ bool bake_navigation = false;
union PosKey {
struct {
@@ -232,7 +231,6 @@ protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
- virtual void _changed_callback(Object *p_changed, const char *p_prop) override;
public:
enum {
@@ -296,6 +294,9 @@ public:
void set_collision_bounce(float p_bounce);
float get_collision_bounce() const;
+ void set_bake_navigation(bool p_bake_navigation);
+ bool is_baking_navigation();
+
void set_mode(Mode p_mode);
Mode get_mode() const;
@@ -339,7 +340,7 @@ public:
void set_clip_uv(bool p_enable);
bool get_clip_uv() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index fccf126dad..4e58984b37 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -129,8 +129,11 @@ void TouchScreenButton::_notification(int p_what) {
if (shape.is_valid()) {
Color draw_col = get_tree()->get_debug_collisions_color();
- Vector2 size = texture.is_null() ? shape->get_rect().size : texture->get_size();
- Vector2 pos = shape_centered ? size * 0.5f : Vector2();
+ Vector2 pos;
+ if (shape_centered && texture.is_valid()) {
+ pos = texture->get_size() * 0.5;
+ }
+
draw_set_transform_matrix(get_canvas_transform().translated(pos));
shape->draw(get_canvas_item(), draw_col);
}
@@ -186,6 +189,8 @@ String TouchScreenButton::get_action() const {
}
void TouchScreenButton::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!get_tree()) {
return;
}
@@ -251,9 +256,12 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) {
if (shape.is_valid()) {
check_rect = false;
- Vector2 size = texture.is_null() ? shape->get_rect().size : texture->get_size();
- Transform2D xform = shape_centered ? Transform2D().translated(size * 0.5f) : Transform2D();
- touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5)));
+ Vector2 pos;
+ if (shape_centered && texture.is_valid()) {
+ pos = texture->get_size() * 0.5;
+ }
+
+ touched = shape->collide(Transform2D().translated(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5)));
}
if (bitmask.is_valid()) {
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 21a2561dd0..8feb47f1cc 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -89,8 +89,6 @@ void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) {
item_rect_changed();
}
}
-
- _change_notify("rect");
}
Rect2 VisibilityNotifier2D::get_rect() const {
@@ -312,18 +310,15 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {
nodes.erase(p_node);
}
-String VisibilityEnabler2D::get_configuration_warning() const {
- String warning = VisibilityNotifier2D::get_configuration_warning();
+TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
#ifdef TOOLS_ENABLED
if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
+ warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));
}
#endif
- return warning;
+ return warnings;
}
void VisibilityEnabler2D::_bind_methods() {
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index 3d1701a1e5..7f4a5bc193 100644
--- a/scene/2d/visibility_notifier_2d.h
+++ b/scene/2d/visibility_notifier_2d.h
@@ -102,7 +102,7 @@ public:
void set_enabler(Enabler p_enabler, bool p_enable);
bool is_enabler_enabled(Enabler p_enabler) const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
VisibilityEnabler2D();
};
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 99c5276636..e187e06308 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -211,7 +211,7 @@ void Area3D::_clear_monitoring() {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
- if (!node) { //node may have been deleted in previous frame or at other legiminate point
+ if (!node) { //node may have been deleted in previous frame or at other legitimate point
continue;
}
//ERR_CONTINUE(!node);
@@ -240,7 +240,7 @@ void Area3D::_clear_monitoring() {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = Object::cast_to<Node>(obj);
- if (!node) { //node may have been deleted in previous frame or at other legiminate point
+ if (!node) { //node may have been deleted in previous frame or at other legitimate point
continue;
}
//ERR_CONTINUE(!node);
@@ -451,52 +451,6 @@ bool Area3D::overlaps_body(Node *p_body) const {
return E->get().in_tree;
}
-void Area3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void Area3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area3D::get_collision_layer() const {
- return collision_layer;
-}
-
-void Area3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool Area3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t layer = get_collision_layer();
- if (p_value) {
- layer |= 1 << p_bit;
- } else {
- layer &= ~(1 << p_bit);
- }
- set_collision_layer(layer);
-}
-
-bool Area3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
void Area3D::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
@@ -595,18 +549,6 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area3D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area3D::get_priority);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area3D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area3D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
@@ -640,16 +582,21 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity);
ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
- ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
+ ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+
+ ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
@@ -657,15 +604,11 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
+
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 6d976115f7..9605a937af 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -54,8 +54,6 @@ private:
real_t gravity_distance_scale = 0.0;
real_t angular_damp = 0.1;
real_t linear_damp = 0.1;
- uint32_t collision_mask = 1;
- uint32_t collision_layer = 1;
int priority = 0;
bool monitoring = false;
bool monitorable = false;
@@ -169,18 +167,6 @@ public:
void set_monitorable(bool p_enable);
bool is_monitorable() const;
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<Node3D> get_overlapping_bodies() const;
TypedArray<Area3D> get_overlapping_areas() const; //function for script
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index fa8408ba5b..72392be5bd 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -138,15 +138,15 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig
}
void AudioStreamPlayer3D::_mix_audio() {
- if (!stream_playback.is_valid() || !active ||
+ if (!stream_playback.is_valid() || !active.is_set() ||
(stream_paused && !stream_paused_fade_out)) {
return;
}
bool started = false;
- if (setseek >= 0.0) {
- stream_playback->start(setseek);
- setseek = -1.0; //reset seek
+ if (setseek.get() >= 0.0) {
+ stream_playback->start(setseek.get());
+ setseek.set(-1.0); //reset seek
started = true;
}
@@ -160,14 +160,14 @@ void AudioStreamPlayer3D::_mix_audio() {
}
// Mix if we're not paused or we're fading out
- if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
+ if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
float output_pitch_scale = 0.0;
- if (output_count) {
+ if (output_count.get()) {
//used for doppler, not realistic but good enough
- for (int i = 0; i < output_count; i++) {
+ for (int i = 0; i < output_count.get(); i++) {
output_pitch_scale += outputs[i].pitch_scale;
}
- output_pitch_scale /= float(output_count);
+ output_pitch_scale /= float(output_count.get());
} else {
output_pitch_scale = 1.0;
}
@@ -176,7 +176,7 @@ void AudioStreamPlayer3D::_mix_audio() {
}
//write all outputs
- for (int i = 0; i < output_count; i++) {
+ for (int i = 0; i < output_count.get(); i++) {
Output current = outputs[i];
//see if current output exists, to keep volume ramp
@@ -285,14 +285,14 @@ void AudioStreamPlayer3D::_mix_audio() {
prev_outputs[i] = current;
}
- prev_output_count = output_count;
+ prev_output_count = output_count.get();
//stream is no longer active, disable this.
if (!stream_playback->is_playing()) {
- active = false;
+ active.clear();
}
- output_ready = false;
+ output_ready.clear();
stream_paused_fade_in = false;
stream_paused_fade_out = false;
}
@@ -360,7 +360,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
- if (!output_ready) {
+ if (!output_ready.is_set()) {
Vector3 linear_velocity;
//compute linear velocity for doppler
@@ -596,24 +596,20 @@ void AudioStreamPlayer3D::_notification(int p_what) {
}
}
- output_count = new_output_count;
- output_ready = true;
+ output_count.set(new_output_count);
+ output_ready.set();
}
//start playing if requested
- if (setplay >= 0.0) {
- setseek = setplay;
- active = true;
- setplay = -1;
- //do not update, this makes it easier to animate (will shut off otherwise)
- ///_change_notify("playing"); //update property in editor
+ if (setplay.get() >= 0.0) {
+ setseek.set(setplay.get());
+ active.set();
+ setplay.set(-1);
}
//stop playing if no longer active
- if (!active) {
+ if (!active.is_set()) {
set_physics_process_internal(false);
- //do not update, this makes it easier to animate (will shut off otherwise)
- //_change_notify("playing"); //update property in editor
emit_signal("finished");
}
}
@@ -627,8 +623,8 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
if (stream_playback.is_valid()) {
stream_playback.unref();
stream.unref();
- active = false;
- setseek = -1;
+ active.clear();
+ setseek.set(-1);
}
if (p_stream.is_valid()) {
@@ -687,30 +683,29 @@ void AudioStreamPlayer3D::play(float p_from_pos) {
}
if (stream_playback.is_valid()) {
- active = true;
- setplay = p_from_pos;
- output_ready = false;
+ setplay.set(p_from_pos);
+ output_ready.clear();
set_physics_process_internal(true);
}
}
void AudioStreamPlayer3D::seek(float p_seconds) {
if (stream_playback.is_valid()) {
- setseek = p_seconds;
+ setseek.set(p_seconds);
}
}
void AudioStreamPlayer3D::stop() {
if (stream_playback.is_valid()) {
- active = false;
+ active.clear();
set_physics_process_internal(false);
- setplay = -1;
+ setplay.set(-1);
}
}
bool AudioStreamPlayer3D::is_playing() const {
if (stream_playback.is_valid()) {
- return active; // && stream_playback->is_playing();
+ return active.is_set() || setplay.get() >= 0;
}
return false;
@@ -718,6 +713,10 @@ bool AudioStreamPlayer3D::is_playing() const {
float AudioStreamPlayer3D::get_playback_position() {
if (stream_playback.is_valid()) {
+ float ss = setseek.get();
+ if (ss >= 0.0) {
+ return ss;
+ }
return stream_playback->get_playback_position();
}
@@ -757,7 +756,7 @@ void AudioStreamPlayer3D::_set_playing(bool p_enable) {
}
bool AudioStreamPlayer3D::_is_active() const {
- return active;
+ return active.is_set();
}
void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
@@ -776,7 +775,7 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
}
void AudioStreamPlayer3D::_bus_layout_changed() {
- _change_notify();
+ notify_property_list_changed();
}
void AudioStreamPlayer3D::set_max_distance(float p_metres) {
@@ -809,7 +808,6 @@ void AudioStreamPlayer3D::set_emission_angle(float p_angle) {
ERR_FAIL_COND(p_angle < 0 || p_angle > 90);
emission_angle = p_angle;
update_gizmo();
- _change_notify("emission_angle");
}
float AudioStreamPlayer3D::get_emission_angle() const {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 33ed758749..70c535bd89 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -31,6 +31,7 @@
#ifndef AUDIO_STREAM_PLAYER_3D_H
#define AUDIO_STREAM_PLAYER_3D_H
+#include "core/templates/safe_refcount.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/velocity_tracker_3d.h"
#include "servers/audio/audio_filter_sw.h"
@@ -80,8 +81,8 @@ private:
};
Output outputs[MAX_OUTPUTS];
- volatile int output_count = 0;
- volatile bool output_ready = false;
+ SafeNumeric<int> output_count;
+ SafeFlag output_ready;
//these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
Output prev_outputs[MAX_OUTPUTS];
@@ -91,9 +92,9 @@ private:
Ref<AudioStream> stream;
Vector<AudioFrame> mix_buffer;
- volatile float setseek = -1.0;
- volatile bool active = false;
- volatile float setplay = -1.0;
+ SafeNumeric<float> setseek{ -1.0 };
+ SafeFlag active;
+ SafeNumeric<float> setplay{ -1.0 };
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
float unit_db = 0.0;
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 7c05878710..ef648a126e 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -78,6 +78,7 @@ void BakedLightmapData::clear_users() {
}
void BakedLightmapData::_set_user_data(const Array &p_data) {
+ ERR_FAIL_COND(p_data.size() <= 0);
ERR_FAIL_COND((p_data.size() % 4) != 0);
for (int i = 0; i < p_data.size(); i += 4) {
@@ -195,7 +196,7 @@ void BakedLightmapData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &BakedLightmapData::set_uses_spherical_harmonics);
ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &BakedLightmapData::is_using_spherical_harmonics);
- ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "offset"), &BakedLightmapData::add_user);
+ ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &BakedLightmapData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users);
@@ -258,7 +259,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
if (all_override.is_valid()) {
mf.overrides.push_back(all_override);
} else {
- mf.overrides.push_back(mi->get_surface_material(i));
+ mf.overrides.push_back(mi->get_surface_override_material(i));
}
}
@@ -448,7 +449,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
ERR_FAIL_COND_V(p_simplex_indices.size() <= 1, 0); //should not happen, this is a bug
// Failed to separate the tetrahedrons using planes
- // this means Delaunay borked at some point.
+ // this means Delaunay broke at some point.
// Luckily, because we are using tetrahedrons, we can resort to
// less precise but still working ways to generate the separating plane
// this will most likely look bad when interpolating, but at least it will not crash.
@@ -510,7 +511,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
node.plane = best_plane;
if (indices_under.size() == 0) {
- //noting to do here
+ //nothing to do here
node.under = BSPNode::EMPTY_LEAF;
} else if (indices_under.size() == 1) {
node.under = -(indices_under[0] + 1);
@@ -519,7 +520,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
}
if (indices_over.size() == 0) {
- //noting to do here
+ //nothing to do here
node.over = BSPNode::EMPTY_LEAF;
} else if (indices_over.size() == 1) {
node.over = -(indices_over[0] + 1);
@@ -618,10 +619,6 @@ void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell
}
BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
- if (p_image_data_path == "" && (get_light_data().is_null() || !get_light_data()->get_path().is_resource_file())) {
- return BAKE_ERROR_NO_SAVE_PATH;
- }
-
if (p_image_data_path == "") {
if (get_light_data().is_null()) {
return BAKE_ERROR_NO_SAVE_PATH;
@@ -659,7 +656,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
}
// create mesh data for insert
- //get the base material textures, help compute altlas size and bounds
+ //get the base material textures, help compute atlas size and bounds
for (int m_i = 0; m_i < meshes_found.size(); m_i++) {
if (p_bake_step) {
float p = (float)(m_i) / meshes_found.size();
@@ -973,7 +970,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) {
images.push_back(lightmapper->get_bake_texture(i));
}
- //we assume they are all the same, so lets create a large one for saving
+ //we assume they are all the same, so let's create a large one for saving
Ref<Image> large_image;
large_image.instance();
@@ -1302,7 +1299,7 @@ bool BakedLightmap::is_interior() const {
void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) {
environment_mode = p_mode;
- _change_notify();
+ notify_property_list_changed();
}
BakedLightmap::EnvironmentMode BakedLightmap::get_environment_mode() const {
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index fa9da6898c..041da4f6ff 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -102,7 +102,7 @@ void Camera3D::_update_camera() {
void Camera3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
- // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD
+ // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD
// and Spatial will handle it first, including clearing its reference to the Viewport,
// therefore making it impossible to subclasses to access it
viewport = get_viewport();
@@ -209,7 +209,7 @@ void Camera3D::set_projection(Camera3D::Projection p_mode) {
if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
mode = p_mode;
_update_camera_mode();
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -432,7 +432,7 @@ void Camera3D::set_keep_aspect_mode(KeepAspect p_aspect) {
keep_aspect = p_aspect;
RenderingServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH);
_update_camera_mode();
- _change_notify();
+ notify_property_list_changed();
}
Camera3D::KeepAspect Camera3D::get_keep_aspect_mode() const {
@@ -562,14 +562,12 @@ void Camera3D::set_fov(float p_fov) {
ERR_FAIL_COND(p_fov < 1 || p_fov > 179);
fov = p_fov;
_update_camera_mode();
- _change_notify("fov");
}
void Camera3D::set_size(float p_size) {
ERR_FAIL_COND(p_size < 0.1 || p_size > 16384);
size = p_size;
_update_camera_mode();
- _change_notify("size");
}
void Camera3D::set_near(float p_near) {
@@ -675,17 +673,17 @@ float ClippedCamera3D::get_margin() const {
return margin;
}
-void ClippedCamera3D::set_process_mode(ProcessMode p_mode) {
- if (process_mode == p_mode) {
+void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) {
+ if (process_callback == p_mode) {
return;
}
- process_mode = p_mode;
- set_process_internal(process_mode == CLIP_PROCESS_IDLE);
- set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
+ process_callback = p_mode;
+ set_process_internal(process_callback == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS);
}
-ClippedCamera3D::ProcessMode ClippedCamera3D::get_process_mode() const {
- return process_mode;
+ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const {
+ return process_callback;
}
Transform ClippedCamera3D::get_camera_transform() const {
@@ -717,7 +715,7 @@ void ClippedCamera3D::_notification(int p_what) {
Vector3 ray_from = parent_plane.project(cam_pos);
- clip_offset = 0; //reset by defau;t
+ clip_offset = 0; //reset by default
{ //check if points changed
Vector<Vector3> local_points = get_near_plane_points();
@@ -763,6 +761,7 @@ uint32_t ClippedCamera3D::get_collision_mask() const {
}
void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -773,6 +772,7 @@ void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -830,8 +830,8 @@ void ClippedCamera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin);
- ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera3D::set_process_mode);
- ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera3D::get_process_mode);
+ ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback);
+ ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
@@ -856,7 +856,7 @@ void ClippedCamera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Clip To", "clip_to");
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index 06bb55e23c..cea61e4db8 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -186,13 +186,13 @@ class ClippedCamera3D : public Camera3D {
GDCLASS(ClippedCamera3D, Camera3D);
public:
- enum ProcessMode {
+ enum ClipProcessCallback {
CLIP_PROCESS_PHYSICS,
CLIP_PROCESS_IDLE,
};
private:
- ProcessMode process_mode = CLIP_PROCESS_PHYSICS;
+ ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS;
RID pyramid_shape;
float margin = 0.0;
float clip_offset = 0.0;
@@ -219,8 +219,8 @@ public:
void set_margin(float p_margin);
float get_margin() const;
- void set_process_mode(ProcessMode p_mode);
- ProcessMode get_process_mode() const;
+ void set_process_callback(ClipProcessCallback p_mode);
+ ClipProcessCallback get_process_callback() const;
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
@@ -240,5 +240,5 @@ public:
~ClippedCamera3D();
};
-VARIANT_ENUM_CAST(ClippedCamera3D::ProcessMode);
+VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback);
#endif
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index b7da4822e2..688509a979 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -30,6 +30,8 @@
#include "collision_object_3d.h"
+#include "core/config/engine.h"
+#include "mesh_instance_3d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_server_3d.h"
@@ -73,9 +75,72 @@ void CollisionObject3D::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_PREDELETE: {
+ if (debug_shape_count > 0) {
+ _clear_debug_shapes();
+ }
+ } break;
+ }
+}
+
+void CollisionObject3D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
+ }
+}
+
+uint32_t CollisionObject3D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void CollisionObject3D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
}
}
+uint32_t CollisionObject3D::get_collision_mask() const {
+ return collision_mask;
+}
+
+void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
+ if (p_value) {
+ collision_layer |= 1 << p_bit;
+ } else {
+ collision_layer &= ~(1 << p_bit);
+ }
+ set_collision_layer(collision_layer);
+}
+
+bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << p_bit;
+ } else {
+ mask &= ~(1 << p_bit);
+ }
+ set_collision_mask(mask);
+}
+
+bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
+ return get_collision_mask() & (1 << p_bit);
+}
+
void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
@@ -110,6 +175,62 @@ void CollisionObject3D::_update_pickable() {
}
}
+void CollisionObject3D::_update_debug_shapes() {
+ for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
+ if (shapes.has(shapedata_idx->get())) {
+ ShapeData &shapedata = shapes[shapedata_idx->get()];
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.debug_shape) {
+ s.debug_shape->queue_delete();
+ s.debug_shape = nullptr;
+ --debug_shape_count;
+ }
+ if (s.shape.is_null() || shapedata.disabled) {
+ continue;
+ }
+
+ Ref<Mesh> mesh = s.shape->get_debug_mesh();
+ MeshInstance3D *mi = memnew(MeshInstance3D);
+ mi->set_transform(shapedata.xform);
+ mi->set_mesh(mesh);
+ add_child(mi);
+ mi->force_update_transform();
+ s.debug_shape = mi;
+ ++debug_shape_count;
+ }
+ }
+ }
+ debug_shapes_to_update.clear();
+}
+
+void CollisionObject3D::_clear_debug_shapes() {
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ ShapeData &shapedata = E->get();
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.debug_shape) {
+ s.debug_shape->queue_delete();
+ s.debug_shape = nullptr;
+ --debug_shape_count;
+ }
+ }
+ }
+
+ debug_shape_count = 0;
+}
+
+void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) {
+ if (debug_shapes_to_update.is_empty()) {
+ call_deferred("_update_debug_shapes");
+ }
+ debug_shapes_to_update.insert(p_owner);
+ }
+}
+
void CollisionObject3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
@@ -120,6 +241,14 @@ bool CollisionObject3D::is_ray_pickable() const {
}
void CollisionObject3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject3D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject3D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject3D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject3D::is_ray_pickable);
ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag);
@@ -141,12 +270,19 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
+ ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject3D::_update_debug_shapes);
+
BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag");
}
@@ -188,6 +324,7 @@ void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl
PhysicsServer3D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
}
}
+ _update_shape_data(p_owner);
}
bool CollisionObject3D::is_shape_owner_disabled(uint32_t p_owner) const {
@@ -223,6 +360,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf
PhysicsServer3D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
}
}
+
+ _update_shape_data(p_owner);
}
Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
@@ -245,6 +384,7 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3
ShapeData::ShapeBase s;
s.index = total_subshapes;
s.shape = p_shape;
+
if (area) {
PhysicsServer3D::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
@@ -253,6 +393,8 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3
sd.shapes.push_back(s);
total_subshapes++;
+
+ _update_shape_data(p_owner);
}
int CollisionObject3D::shape_owner_get_shape_count(uint32_t p_owner) const {
@@ -279,13 +421,19 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
ERR_FAIL_COND(!shapes.has(p_owner));
ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
- int index_to_remove = shapes[p_owner].shapes[p_shape].index;
+ const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape];
+ int index_to_remove = s.index;
+
if (area) {
PhysicsServer3D::get_singleton()->area_remove_shape(rid, index_to_remove);
} else {
PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove);
}
+ if (s.debug_shape) {
+ s.debug_shape->queue_delete();
+ }
+
shapes[p_owner].shapes.remove(p_shape);
for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
@@ -343,17 +491,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
-String CollisionObject3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionObject3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.");
+ warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
}
- return warning;
+ return warnings;
}
CollisionObject3D::CollisionObject3D() {
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index b7473ca12a..e3901979d3 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -37,6 +37,9 @@
class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, Node3D);
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+
bool area = false;
RID rid;
@@ -45,6 +48,7 @@ class CollisionObject3D : public Node3D {
Object *owner = nullptr;
Transform xform;
struct ShapeBase {
+ Node *debug_shape = nullptr;
Ref<Shape3D> shape;
int index = 0;
};
@@ -60,8 +64,13 @@ class CollisionObject3D : public Node3D {
bool capture_input_on_drag = false;
bool ray_pickable = true;
+ Set<uint32_t> debug_shapes_to_update;
+ int debug_shape_count = 0;
+
void _update_pickable();
+ void _update_shape_data(uint32_t p_owner);
+
protected:
CollisionObject3D(RID p_rid, bool p_area);
@@ -72,7 +81,22 @@ protected:
virtual void _mouse_enter();
virtual void _mouse_exit();
+ void _update_debug_shapes();
+ void _clear_debug_shapes();
+
public:
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
@@ -103,7 +127,7 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; }
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionObject3D();
~CollisionObject3D();
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 4d117f02d3..ac715b22b2 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -70,6 +70,7 @@ void CollisionPolygon3D::_build_polygon() {
}
convex->set_points(cp);
+ convex->set_margin(margin);
parent->shape_owner_add_shape(owner_id, convex);
parent->shape_owner_set_disabled(owner_id, disabled);
}
@@ -120,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
if (parent) {
_build_polygon();
}
- update_configuration_warning();
+ update_configuration_warnings();
update_gizmo();
}
@@ -155,24 +156,29 @@ bool CollisionPolygon3D::is_disabled() const {
return disabled;
}
-String CollisionPolygon3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+real_t CollisionPolygon3D::get_margin() const {
+ return margin;
+}
+
+void CollisionPolygon3D::set_margin(real_t p_margin) {
+ margin = p_margin;
+ if (parent) {
+ _build_polygon();
+ }
+}
+
+TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
+ warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision."));
}
- return warning;
+ return warnings;
}
bool CollisionPolygon3D::_is_editable_3d_polygon() const {
@@ -189,11 +195,15 @@ void CollisionPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon3D::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon3D::is_disabled);
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon3D::get_margin);
+
ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon3D::_is_editable_3d_polygon);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
CollisionPolygon3D::CollisionPolygon3D() {
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index cb0aba67b1..73b8a8e0e3 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -37,6 +37,7 @@
class CollisionObject3D;
class CollisionPolygon3D : public Node3D {
GDCLASS(CollisionPolygon3D, Node3D);
+ real_t margin = 0.04;
protected:
real_t depth = 1.0;
@@ -70,7 +71,10 @@ public:
virtual AABB get_item_rect() const;
- String get_configuration_warning() const override;
+ real_t get_margin() const;
+ void set_margin(real_t p_margin);
+
+ TypedArray<String> get_configuration_warnings() const override;
CollisionPolygon3D();
};
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 914c8eab7a..bec87914c0 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -100,9 +100,6 @@ void CollisionShape3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner();
}
- if (get_tree()->is_debugging_collisions_hint()) {
- _update_debug_shape();
- }
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
@@ -123,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) {
update_gizmo();
}
-String CollisionShape3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+ warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));
}
if (shape.is_valid() &&
Object::cast_to<RigidBody3D>(get_parent()) &&
Object::cast_to<ConcavePolygonShape3D>(*shape) &&
Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
+ warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
}
- return warning;
+ return warnings;
}
void CollisionShape3D::_bind_methods() {
@@ -163,8 +151,6 @@ void CollisionShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_convex_from_siblings"), &CollisionShape3D::make_convex_from_siblings);
ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_siblings", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
- ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape3D::_update_debug_shape);
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
}
@@ -193,7 +179,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
if (is_inside_tree()) {
_shape_changed();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Shape3D> CollisionShape3D::get_shape() const {
@@ -224,34 +210,9 @@ CollisionShape3D::~CollisionShape3D() {
//RenderingServer::get_singleton()->free(indicator);
}
-void CollisionShape3D::_update_debug_shape() {
- debug_shape_dirty = false;
-
- if (debug_shape) {
- debug_shape->queue_delete();
- debug_shape = nullptr;
- }
-
- Ref<Shape3D> s = get_shape();
- if (s.is_null()) {
- return;
- }
-
- Ref<Mesh> mesh = s->get_debug_mesh();
- MeshInstance3D *mi = memnew(MeshInstance3D);
- mi->set_mesh(mesh);
- add_child(mi);
- debug_shape = mi;
-}
-
void CollisionShape3D::_shape_changed() {
// If this is a heightfield shape our center may have changed
if (parent) {
_update_in_shape_owner(true);
}
-
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) {
- debug_shape_dirty = true;
- call_deferred("_update_debug_shape");
- }
}
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index f55c09ffaa..56a4ae3039 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -43,14 +43,10 @@ class CollisionShape3D : public Node3D {
uint32_t owner_id = 0;
CollisionObject3D *parent = nullptr;
- Node *debug_shape = nullptr;
- bool debug_shape_dirty;
-
void resource_changed(RES res);
bool disabled = false;
protected:
- void _update_debug_shape();
void _shape_changed();
void _update_in_shape_owner(bool p_xform_only = false);
@@ -68,7 +64,7 @@ public:
void set_disabled(bool p_disabled);
bool is_disabled() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionShape3D();
~CollisionShape3D();
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 48fdeb051d..aa29728c73 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -73,7 +73,7 @@ void CPUParticles3D::set_amount(int p_amount) {
}
particle_data.resize((12 + 4 + 4) * p_amount);
- RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true);
+ RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true);
particle_order.resize(p_amount);
}
@@ -152,6 +152,7 @@ float CPUParticles3D::get_speed_scale() const {
}
void CPUParticles3D::set_draw_order(DrawOrder p_order) {
+ ERR_FAIL_INDEX(p_order, DRAW_ORDER_MAX);
draw_order = p_order;
}
@@ -188,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String CPUParticles3D::get_configuration_warning() const {
- String warnings = GeometryInstance3D::get_configuration_warning();
+TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
bool mesh_found = false;
bool anim_material_found = false;
@@ -208,18 +209,12 @@ String CPUParticles3D::get_configuration_warning() const {
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!mesh_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because no mesh has been assigned.");
+ warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));
}
if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
return warnings;
@@ -372,7 +367,7 @@ void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_ena
ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
particle_flags[p_particle_flag] = p_enable;
if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -575,7 +570,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
cycle++;
if (one_shot && cycle > 0) {
set_emitting(false);
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -1011,6 +1006,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
sorter.compare.particles = r;
sorter.sort(order, pc);
} else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
+ ERR_FAIL_NULL(get_viewport());
Camera3D *c = get_viewport()->get_camera();
if (c) {
Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
@@ -1054,7 +1050,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
Color c = r[idx].color;
@@ -1072,7 +1068,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr += 20;
}
- can_update = true;
+ can_update.set();
}
void CPUParticles3D::_set_redraw(bool p_redraw) {
@@ -1101,9 +1097,9 @@ void CPUParticles3D::_set_redraw(bool p_redraw) {
void CPUParticles3D::_update_render_thread() {
MutexLock lock(update_mutex);
- if (can_update) {
+ if (can_update.is_set()) {
RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
- can_update = false; //wait for next time
+ can_update.clear(); //wait for next time
}
}
@@ -1159,13 +1155,13 @@ void CPUParticles3D::_notification(int p_what) {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
ptr += 20;
}
- can_update = true;
+ can_update.set();
}
}
}
@@ -1466,6 +1462,21 @@ CPUParticles3D::CPUParticles3D() {
set_param(PARAM_HUE_VARIATION, 0);
set_param(PARAM_ANIM_SPEED, 0);
set_param(PARAM_ANIM_OFFSET, 0);
+ set_emission_shape(EMISSION_SHAPE_POINT);
+ set_emission_sphere_radius(1);
+ set_emission_box_extents(Vector3(1, 1, 1));
+
+ set_gravity(Vector3(0, -9.8, 0));
+
+ for (int i = 0; i < PARAM_MAX; i++) {
+ set_param_randomness(Parameter(i), 0);
+ }
+
+ for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
+ particle_flags[i] = false;
+ }
+
+ set_color(Color(1, 1, 1, 1));
}
CPUParticles3D::~CPUParticles3D() {
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index d650bf95ac..c073c93c47 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -32,6 +32,7 @@
#define CPU_PARTICLES_H
#include "core/templates/rid.h"
+#include "core/templates/safe_refcount.h"
#include "scene/3d/visual_instance_3d.h"
class CPUParticles3D : public GeometryInstance3D {
@@ -43,6 +44,7 @@ public:
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
DRAW_ORDER_VIEW_DEPTH,
+ DRAW_ORDER_MAX
};
enum Parameter {
@@ -141,7 +143,7 @@ private:
Transform inv_emission_transform;
- volatile bool can_update = false;
+ SafeFlag can_update;
DrawOrder draw_order = DRAW_ORDER_INDEX;
@@ -278,7 +280,7 @@ public:
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 1cdea37dad..7d6abe458a 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -34,7 +34,6 @@ void Decal::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->decal_set_extents(decal, p_extents);
update_gizmo();
- _change_notify("extents");
}
Vector3 Decal::get_extents() const {
@@ -110,6 +109,7 @@ Color Decal::get_modulate() const {
void Decal::set_enable_distance_fade(bool p_enable) {
distance_fade_enabled = p_enable;
RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length);
+ notify_property_list_changed();
}
bool Decal::is_distance_fade_enabled() const {
@@ -154,6 +154,12 @@ Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
+void Decal::_validate_property(PropertyInfo &property) const {
+ if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void Decal::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents);
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 095579d775..ce19e76de1 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -64,6 +64,7 @@ private:
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_extents(const Vector3 &p_extents);
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 1f00eab092..4d7fc29f15 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -91,7 +91,7 @@ Dictionary GIProbeData::_get_data() const {
}
void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
- RS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
+ RS::get_singleton()->gi_probe_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
bounds = p_aabb;
to_cell_xform = p_to_cell_xform;
octree_size = p_octree_size;
@@ -221,7 +221,7 @@ RID GIProbeData::get_rid() const {
void GIProbeData::_validate_property(PropertyInfo &property) const {
if (property.name == "anisotropy_strength") {
- bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/quality/gi_probes/anisotropic");
+ bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/gi_probes/anisotropic");
if (!anisotropy_enabled) {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
@@ -323,7 +323,6 @@ GIProbe::Subdiv GIProbe::get_subdiv() const {
void GIProbe::set_extents(const Vector3 &p_extents) {
extents = p_extents;
update_gizmo();
- _change_notify("extents");
}
Vector3 GIProbe::get_extents() const {
@@ -344,7 +343,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
pm.local_xform = xf;
pm.mesh = mesh;
for (int i = 0; i < mesh->get_surface_count(); i++) {
- pm.instance_materials.push_back(mi->get_surface_material(i));
+ pm.instance_materials.push_back(mi->get_surface_override_material(i));
}
pm.override_material = mi->get_material_override();
plot_meshes.push_back(pm);
@@ -416,13 +415,16 @@ Vector3i GIProbe::get_estimated_cell_size() const {
void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
+ p_from_node = p_from_node ? p_from_node : get_parent();
+ ERR_FAIL_NULL(p_from_node);
+
Voxelizer baker;
baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0));
List<PlotMesh> mesh_list;
- _find_meshes(p_from_node ? p_from_node : get_parent(), mesh_list);
+ _find_meshes(p_from_node, mesh_list);
if (bake_begin_function) {
bake_begin_function(mesh_list.size() + 1);
@@ -486,7 +488,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
bake_end_function();
}
- _change_notify(); //bake property may have changed
+ notify_property_list_changed(); //bake property may have changed
}
void GIProbe::_debug_bake() {
@@ -501,19 +503,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-String GIProbe::get_configuration_warning() const {
- String warning = VisualInstance3D::get_configuration_warning();
+TypedArray<String> GIProbe::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+ warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."));
} else if (probe_data.is_null()) {
- warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI.");
+ warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."));
}
-
- return warning;
+ return warnings;
}
void GIProbe::_bind_methods() {
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 534b425557..dac7dd3e17 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/gi_probe.h
@@ -165,7 +165,7 @@ public:
virtual AABB get_aabb() const override;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
GIProbe();
~GIProbe();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 7d77578b01..5339b8a8da 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -100,7 +100,6 @@ void GPUParticles3D::set_visibility_aabb(const AABB &p_aabb) {
visibility_aabb = p_aabb;
RS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb);
update_gizmo();
- _change_notify("visibility_aabb");
}
void GPUParticles3D::set_use_local_coordinates(bool p_enable) {
@@ -116,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
}
RS::get_singleton()->particles_set_process_material(particles, material_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
void GPUParticles3D::set_speed_scale(float p_scale) {
@@ -182,15 +181,36 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
}
+void GPUParticles3D::set_enable_trail(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+}
+void GPUParticles3D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+}
+
+bool GPUParticles3D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles3D::get_trail_length() const {
+ return trail_length;
+}
+
GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
return draw_order;
}
void GPUParticles3D::set_draw_passes(int p_count) {
ERR_FAIL_COND(p_count < 1);
+ for (int i = p_count; i < draw_passes.size(); i++) {
+ set_draw_pass_mesh(i, Ref<Mesh>());
+ }
draw_passes.resize(p_count);
RS::get_singleton()->particles_set_draw_passes(particles, p_count);
- _change_notify();
+ notify_property_list_changed();
}
int GPUParticles3D::get_draw_passes() const {
@@ -200,8 +220,16 @@ int GPUParticles3D::get_draw_passes() const {
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] = 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), varray(), CONNECT_DEFERRED);
+ }
+
RID mesh_rid;
if (p_mesh.is_valid()) {
mesh_rid = p_mesh->get_rid();
@@ -209,7 +237,8 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
- update_configuration_warning();
+ _skinning_changed();
+ update_configuration_warnings();
}
Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const {
@@ -236,13 +265,22 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String GPUParticles3D::get_configuration_warning() const {
+void GPUParticles3D::set_interpolate(bool p_enable) {
+ interpolate = p_enable;
+ RS::get_singleton()->particles_set_interpolate(particles, p_enable);
+}
+
+bool GPUParticles3D::get_interpolate() const {
+ return interpolate;
+}
+
+TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.");
+ warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));
}
- String warnings = GeometryInstance3D::get_configuration_warning();
-
bool meshes_found = false;
bool anim_material_found = false;
@@ -251,7 +289,7 @@ String GPUParticles3D::get_configuration_warning() const {
meshes_found = true;
for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
}
if (anim_material_found) {
@@ -261,30 +299,73 @@ String GPUParticles3D::get_configuration_warning() const {
}
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == BaseMaterial3D::BILLBOARD_PARTICLES);
+ }
if (!meshes_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
+ warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
}
if (process_material.is_null()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+ warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (!anim_material_found && process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
+ warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ }
+ }
+
+ if (trail_enabled) {
+ int dp_count = 0;
+ bool missing_trails = false;
+ bool no_materials = false;
+
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ dp_count++;
+ }
+
+ if (draw_pass.is_valid()) {
+ int mats_found = 0;
+ for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ if (spat) {
+ mats_found++;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+ }
+
+ if (mats_found != draw_passes[i]->get_surface_count()) {
+ no_materials = true;
+ }
}
- warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ }
+
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ if (spat) {
+ no_materials = false;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+
+ if (dp_count && skin.is_valid()) {
+ warnings.push_back(TTR("Using Trail meshes with a skin causes Skin to override Trail poses. Suggest removing the Skin."));
+ } else if (dp_count == 0 && skin.is_null()) {
+ warnings.push_back(TTR("Trails active, but neither Trail meshes or a Skin were found."));
+ } else if (dp_count > 1) {
+ warnings.push_back(TTR("Only one Trail mesh is supported. If you want to use more than a single mesh, a Skin is needed (see documentation)."));
+ }
+
+ if ((dp_count || !skin.is_null()) && (missing_trails || no_materials)) {
+ warnings.push_back(TTR("Trails enabled, but one or more mesh materials are either missing or not set for trails rendering."));
}
}
@@ -349,11 +430,11 @@ void GPUParticles3D::_notification(int p_what) {
}
}
- // Use internal process when emitting and one_shot are on so that when
+ // Use internal process when emitting and one_shot is on so that when
// the shot ends the editor can properly update
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
if (one_shot && !is_emitting()) {
- _change_notify();
+ notify_property_list_changed();
set_process_internal(false);
}
}
@@ -376,6 +457,47 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+void GPUParticles3D::_skinning_changed() {
+ Vector<Transform> xforms;
+ if (skin.is_valid()) {
+ xforms.resize(skin->get_bind_count());
+ for (int i = 0; i < skin->get_bind_count(); i++) {
+ xforms.write[i] = skin->get_bind_pose(i);
+ }
+ } else {
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ xforms.resize(draw_pass->get_builtin_bind_pose_count());
+ for (int j = 0; j < draw_pass->get_builtin_bind_pose_count(); j++) {
+ xforms.write[i] = draw_pass->get_builtin_bind_pose(j);
+ }
+ break;
+ }
+ }
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+ update_configuration_warnings();
+}
+
+void GPUParticles3D::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+ _skinning_changed();
+}
+Ref<Skin> GPUParticles3D::get_skin() const {
+ return skin;
+}
+
+void GPUParticles3D::set_transform_align(TransformAlign p_align) {
+ ERR_FAIL_INDEX(uint32_t(p_align), 4);
+ transform_align = p_align;
+ RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align));
+}
+GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const {
+ return transform_align;
+}
+
void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount);
@@ -388,6 +510,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles3D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles3D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_interpolate", "enable"), &GPUParticles3D::set_interpolate);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size);
@@ -403,6 +526,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles3D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles3D::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_interpolate"), &GPUParticles3D::get_interpolate);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size);
@@ -417,6 +541,9 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_passes"), &GPUParticles3D::get_draw_passes);
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &GPUParticles3D::get_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &GPUParticles3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &GPUParticles3D::get_skin);
+
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
@@ -425,6 +552,15 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+ ClassDB::bind_method(D_METHOD("set_enable_trail", "enabled"), &GPUParticles3D::set_enable_trail);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length);
+
+ 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_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
@@ -436,6 +572,7 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
@@ -443,6 +580,10 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_enable_trail", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,4,0.01"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -450,6 +591,7 @@ void GPUParticles3D::_bind_methods() {
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
}
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "draw_skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
@@ -462,6 +604,11 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
BIND_CONSTANT(MAX_DRAW_PASSES);
+
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_DISABLED);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY);
}
GPUParticles3D::GPUParticles3D() {
@@ -472,17 +619,20 @@ GPUParticles3D::GPUParticles3D() {
set_one_shot(false);
set_amount(8);
set_lifetime(1);
- set_fixed_fps(0);
+ set_fixed_fps(30);
set_fractional_delta(true);
+ set_interpolate(true);
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
+ set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_use_local_coordinates(true);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
set_collision_base_size(0.01);
+ set_transform_align(TRANSFORM_ALIGN_DISABLED);
}
GPUParticles3D::~GPUParticles3D() {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 0c1a1a510c..1f9cea79b6 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -34,6 +34,7 @@
#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/material.h"
+#include "scene/resources/skin.h"
class GPUParticles3D : public GeometryInstance3D {
private:
@@ -46,6 +47,13 @@ public:
DRAW_ORDER_VIEW_DEPTH,
};
+ enum TransformAlign {
+ TRANSFORM_ALIGN_DISABLED,
+ TRANSFORM_ALIGN_Z_BILLBOARD,
+ TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY
+ };
+
enum {
MAX_DRAW_PASSES = 4
};
@@ -64,17 +72,26 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ bool interpolate = true;
NodePath sub_emitter;
float collision_base_size;
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+
+ TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
+
Ref<Material> process_material;
DrawOrder draw_order;
Vector<Ref<Mesh>> draw_passes;
+ Ref<Skin> skin;
void _attach_sub_emitter();
+ void _skinning_changed();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -96,6 +113,8 @@ public:
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
void set_collision_base_size(float p_ratio);
+ void set_enable_trail(bool p_enabled);
+ void set_trail_length(float p_seconds);
bool is_emitting() const;
int get_amount() const;
@@ -109,6 +128,8 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -116,6 +137,9 @@ public:
void set_fractional_delta(bool p_enable);
bool get_fractional_delta() const;
+ void set_interpolate(bool p_enable);
+ bool get_interpolate() const;
+
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
@@ -125,11 +149,17 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_transform_align(TransformAlign p_align);
+ TransformAlign get_transform_align() const;
+
void restart();
enum EmitFlags {
@@ -148,6 +178,7 @@ public:
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(GPUParticles3D::TransformAlign)
VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
#endif // PARTICLES_H
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 97241be60f..628b823f89 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -346,7 +346,7 @@ void GPUParticlesCollisionSDF::_compute_sdf(ComputeSDFParams *params) {
ThreadWorkPool work_pool;
work_pool.init();
work_pool.begin_work(params->size.z, this, &GPUParticlesCollisionSDF::_compute_sdf_z, params);
- while (work_pool.get_work_index() < (uint32_t)params->size.z) {
+ while (!work_pool.is_done_dispatching()) {
OS::get_singleton()->delay_usec(10000);
bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF");
}
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index e6e23b927a..d45749d36b 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -48,11 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) {
update_gizmo();
if (p_param == PARAM_SPOT_ANGLE) {
- _change_notify("spot_angle");
- update_configuration_warning();
- } else if (p_param == PARAM_RANGE) {
- _change_notify("omni_range");
- _change_notify("spot_range");
+ update_configuration_warnings();
}
}
}
@@ -67,8 +63,10 @@ void Light3D::set_shadow(bool p_enable) {
RS::get_singleton()->light_set_shadow(light, p_enable);
if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
- update_configuration_warning();
+ update_configuration_warnings();
}
+
+ notify_property_list_changed();
}
bool Light3D::has_shadow() const {
@@ -155,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) {
projector = p_texture;
RID tex_id = projector.is_valid() ? projector->get_rid() : RID();
RS::get_singleton()->light_set_projector(light, tex_id);
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Texture2D> Light3D::get_projector() const {
@@ -184,8 +182,6 @@ void Light3D::_update_visibility() {
#endif
RS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree() && editor_ok);
-
- _change_notify("geometry/visible");
}
void Light3D::_notification(int p_what) {
@@ -208,6 +204,10 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &property) const {
+ if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur")) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+
if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") {
property.usage = 0;
}
@@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
return shadow_mode;
}
-String OmniLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> OmniLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void OmniLight3D::_bind_methods() {
@@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);
}
-String SpotLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> SpotLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
+ warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
}
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void SpotLight3D::_bind_methods() {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 311db54bce..e145b08b74 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -202,7 +202,7 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
OmniLight3D();
};
@@ -216,7 +216,7 @@ protected:
static void _bind_methods();
public:
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
SpotLight3D() :
Light3D(RenderingServer::LIGHT_SPOT) {}
diff --git a/scene/3d/lightmapper.cpp b/scene/3d/lightmapper.cpp
index c17ac52aa2..9e5078ba95 100644
--- a/scene/3d/lightmapper.cpp
+++ b/scene/3d/lightmapper.cpp
@@ -39,6 +39,15 @@ Ref<LightmapDenoiser> LightmapDenoiser::create() {
return Ref<LightmapDenoiser>();
}
+LightmapRaycaster *(*LightmapRaycaster::create_function)() = nullptr;
+
+Ref<LightmapRaycaster> LightmapRaycaster::create() {
+ if (create_function) {
+ return Ref<LightmapRaycaster>(create_function());
+ }
+ return Ref<LightmapRaycaster>();
+}
+
Lightmapper::CreateFunc Lightmapper::create_custom = nullptr;
Lightmapper::CreateFunc Lightmapper::create_gpu = nullptr;
Lightmapper::CreateFunc Lightmapper::create_cpu = nullptr;
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index a07a964c01..f63515f666 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -34,6 +34,16 @@
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
+#if !defined(__aligned)
+
+#if defined(_WIN32) && defined(_MSC_VER)
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#else
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#endif
+
class LightmapDenoiser : public Reference {
GDCLASS(LightmapDenoiser, Reference)
protected:
@@ -44,6 +54,73 @@ public:
static Ref<LightmapDenoiser> create();
};
+class LightmapRaycaster : public Reference {
+ GDCLASS(LightmapRaycaster, Reference)
+protected:
+ static LightmapRaycaster *(*create_function)();
+
+public:
+ // compatible with embree3 rays
+ struct __aligned(16) Ray {
+ const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
+
+ /*! Default construction does nothing. */
+ _FORCE_INLINE_ Ray() :
+ geomID(INVALID_GEOMETRY_ID) {}
+
+ /*! Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far. */
+ _FORCE_INLINE_ Ray(const Vector3 &org,
+ const Vector3 &dir,
+ float tnear = 0.0f,
+ float tfar = INFINITY) :
+ org(org),
+ tnear(tnear),
+ dir(dir),
+ time(0.0f),
+ tfar(tfar),
+ mask(-1),
+ u(0.0),
+ v(0.0),
+ primID(INVALID_GEOMETRY_ID),
+ geomID(INVALID_GEOMETRY_ID),
+ instID(INVALID_GEOMETRY_ID) {}
+
+ /*! Tests if we hit something. */
+ _FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; }
+
+ public:
+ Vector3 org; //!< Ray origin + tnear
+ float tnear; //!< Start of ray segment
+ Vector3 dir; //!< Ray direction + tfar
+ float time; //!< Time of this ray for motion blur.
+ float tfar; //!< End of ray segment
+ unsigned int mask; //!< used to mask out objects during traversal
+ unsigned int id; //!< ray ID
+ unsigned int flags; //!< ray flags
+
+ Vector3 normal; //!< Not normalized geometry normal
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+ unsigned int primID; //!< primitive ID
+ unsigned int geomID; //!< geometry ID
+ unsigned int instID; //!< instance ID
+ };
+
+ virtual bool intersect(Ray &p_ray) = 0;
+
+ virtual void intersect(Vector<Ray> &r_rays) = 0;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) = 0;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) = 0;
+ virtual void commit() = 0;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) = 0;
+ virtual void clear_mesh_filter() = 0;
+
+ static Ref<LightmapRaycaster> create();
+};
+
class Lightmapper : public Reference {
GDCLASS(Lightmapper, Reference)
public:
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 9029b5b028..27d5487a1a 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -51,13 +51,13 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- set_surface_material(idx, p_value);
+ set_surface_override_material(idx, p_value);
return true;
}
@@ -75,12 +75,12 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- r_ret = materials[idx];
+ r_ret = surface_override_materials[idx];
return true;
}
return false;
@@ -95,12 +95,12 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
ls.sort();
for (List<String>::Element *E = ls.front(); E; E = E->next()) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "-1,1,0.00001"));
}
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
}
}
}
@@ -126,7 +126,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
}
mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
- materials.resize(mesh->get_surface_count());
+ surface_override_materials.resize(mesh->get_surface_count());
set_base(mesh->get_rid());
} else {
@@ -135,7 +135,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
update_gizmo();
- _change_notify();
+ notify_property_list_changed();
}
Ref<Mesh> MeshInstance3D::get_mesh() const {
@@ -152,7 +152,7 @@ void MeshInstance3D::_resolve_skeleton_path() {
if (skin_internal.is_null()) {
//a skin was created for us
skin_internal = new_skin_reference->get_skin();
- _change_notify();
+ notify_property_list_changed();
}
}
}
@@ -271,32 +271,67 @@ void MeshInstance3D::create_convex_collision() {
}
}
+Node *MeshInstance3D::create_multiple_convex_collisions_node() {
+ if (mesh.is_null()) {
+ return nullptr;
+ }
+
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ if (!shapes.size()) {
+ return nullptr;
+ }
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ for (int i = 0; i < shapes.size(); i++) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shapes[i]);
+ static_body->add_child(cshape);
+ }
+ return static_body;
+}
+
+void MeshInstance3D::create_multiple_convex_collisions() {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_multiple_convex_collisions_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ static_body->set_owner(get_owner());
+ int count = static_body->get_child_count();
+ for (int i = 0; i < count; i++) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(i));
+ cshape->set_owner(get_owner());
+ }
+ }
+}
+
void MeshInstance3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
}
}
-int MeshInstance3D::get_surface_material_count() const {
- return materials.size();
+int MeshInstance3D::get_surface_override_material_count() const {
+ return surface_override_materials.size();
}
-void MeshInstance3D::set_surface_material(int p_surface, const Ref<Material> &p_material) {
- ERR_FAIL_INDEX(p_surface, materials.size());
+void MeshInstance3D::set_surface_override_material(int p_surface, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_surface, surface_override_materials.size());
- materials.write[p_surface] = p_material;
+ surface_override_materials.write[p_surface] = p_material;
- if (materials[p_surface].is_valid()) {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
+ if (surface_override_materials[p_surface].is_valid()) {
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, surface_override_materials[p_surface]->get_rid());
} else {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID());
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, RID());
}
}
-Ref<Material> MeshInstance3D::get_surface_material(int p_surface) const {
- ERR_FAIL_INDEX_V(p_surface, materials.size(), Ref<Material>());
+Ref<Material> MeshInstance3D::get_surface_override_material(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surface_override_materials.size(), Ref<Material>());
- return materials[p_surface];
+ return surface_override_materials[p_surface];
}
Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
@@ -305,7 +340,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
return material_override;
}
- Ref<Material> surface_material = get_surface_material(p_surface);
+ Ref<Material> surface_material = get_surface_override_material(p_surface);
if (surface_material.is_valid()) {
return surface_material;
}
@@ -319,7 +354,9 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
}
void MeshInstance3D::_mesh_changed() {
- materials.resize(mesh->get_surface_count());
+ ERR_FAIL_COND(mesh.is_null());
+ surface_override_materials.resize(mesh->get_surface_count());
+ update_gizmo();
}
void MeshInstance3D::create_debug_tangents() {
@@ -407,15 +444,17 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance3D::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance3D::get_skin);
- ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance3D::get_surface_material_count);
- ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance3D::set_surface_material);
- ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance3D::get_surface_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MeshInstance3D::get_surface_override_material_count);
+ ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MeshInstance3D::set_surface_override_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material", "surface"), &MeshInstance3D::get_surface_override_material);
ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MeshInstance3D::get_active_material);
ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance3D::create_trimesh_collision);
ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance3D::create_convex_collision);
ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT);
+ ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions);
+ ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance3D::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index eb300784b1..9dea5804e0 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -52,7 +52,7 @@ protected:
};
Map<StringName, BlendShapeTrack> blend_shape_tracks;
- Vector<Ref<Material>> materials;
+ Vector<Ref<Material>> surface_override_materials;
void _mesh_changed();
void _resolve_skeleton_path();
@@ -75,9 +75,9 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
- int get_surface_material_count() const;
- void set_surface_material(int p_surface, const Ref<Material> &p_material);
- Ref<Material> get_surface_material(int p_surface) const;
+ int get_surface_override_material_count() const;
+ void set_surface_override_material(int p_surface, const Ref<Material> &p_material);
+ Ref<Material> get_surface_override_material(int p_surface) const;
Ref<Material> get_active_material(int p_surface) const;
Node *create_trimesh_collision_node();
@@ -86,6 +86,9 @@ public:
Node *create_convex_collision_node();
void create_convex_collision();
+ Node *create_multiple_convex_collisions_node();
+ void create_multiple_convex_collisions();
+
void create_debug_tangents();
virtual AABB get_aabb() const override;
diff --git a/scene/3d/navigation_3d.cpp b/scene/3d/navigation_3d.cpp
deleted file mode 100644
index eaddec7601..0000000000
--- a/scene/3d/navigation_3d.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*************************************************************************/
-/* navigation_3d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "navigation_3d.h"
-
-#include "servers/navigation_server_3d.h"
-
-Vector<Vector3> Navigation3D::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) const {
- return NavigationServer3D::get_singleton()->map_get_path(map, p_start, p_end, p_optimize);
-}
-
-Vector3 Navigation3D::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {
- return NavigationServer3D::get_singleton()->map_get_closest_point_to_segment(map, p_from, p_to, p_use_collision);
-}
-
-Vector3 Navigation3D::get_closest_point(const Vector3 &p_point) const {
- return NavigationServer3D::get_singleton()->map_get_closest_point(map, p_point);
-}
-
-Vector3 Navigation3D::get_closest_point_normal(const Vector3 &p_point) const {
- return NavigationServer3D::get_singleton()->map_get_closest_point_normal(map, p_point);
-}
-
-RID Navigation3D::get_closest_point_owner(const Vector3 &p_point) const {
- return NavigationServer3D::get_singleton()->map_get_closest_point_owner(map, p_point);
-}
-
-void Navigation3D::set_up_vector(const Vector3 &p_up) {
- up = p_up;
- NavigationServer3D::get_singleton()->map_set_up(map, up);
-}
-
-Vector3 Navigation3D::get_up_vector() const {
- return up;
-}
-
-void Navigation3D::set_cell_size(float p_cell_size) {
- cell_size = p_cell_size;
- NavigationServer3D::get_singleton()->map_set_cell_size(map, cell_size);
-}
-
-void Navigation3D::set_edge_connection_margin(float p_edge_connection_margin) {
- edge_connection_margin = p_edge_connection_margin;
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin);
-}
-
-void Navigation3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_rid"), &Navigation3D::get_rid);
-
- ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation3D::get_simple_path, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "start", "end", "use_collision"), &Navigation3D::get_closest_point_to_segment, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation3D::get_closest_point);
- ClassDB::bind_method(D_METHOD("get_closest_point_normal", "to_point"), &Navigation3D::get_closest_point_normal);
- ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation3D::get_closest_point_owner);
-
- ClassDB::bind_method(D_METHOD("set_up_vector", "up"), &Navigation3D::set_up_vector);
- ClassDB::bind_method(D_METHOD("get_up_vector"), &Navigation3D::get_up_vector);
-
- ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation3D::set_cell_size);
- ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation3D::get_cell_size);
-
- ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation3D::set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation3D::get_edge_connection_margin);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_vector"), "set_up_vector", "get_up_vector");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size"), "set_cell_size", "get_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_connection_margin"), "set_edge_connection_margin", "get_edge_connection_margin");
-}
-
-void Navigation3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- NavigationServer3D::get_singleton()->map_set_active(map, true);
- } break;
- case NOTIFICATION_EXIT_TREE: {
- NavigationServer3D::get_singleton()->map_set_active(map, false);
- } break;
- }
-}
-
-Navigation3D::Navigation3D() {
- map = NavigationServer3D::get_singleton()->map_create();
-
- set_cell_size(0.3);
- set_edge_connection_margin(5.0); // Five meters, depends a lot on the agent's radius
-}
-
-Navigation3D::~Navigation3D() {
- NavigationServer3D::get_singleton()->free(map);
-}
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 8917cc4664..64cfe4dca7 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -31,10 +31,11 @@
#include "navigation_agent_3d.h"
#include "core/config/engine.h"
-#include "scene/3d/navigation_3d.h"
#include "servers/navigation_server_3d.h"
void NavigationAgent3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance);
@@ -47,9 +48,6 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent3D::set_ignore_y);
ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent3D::get_ignore_y);
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent3D::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent3D::get_navigation_node);
-
ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent3D::set_neighbor_dist);
ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent3D::get_neighbor_dist);
@@ -99,41 +97,21 @@ void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node3D>(get_parent());
-
- NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
-
- // Search the navigation node and set it
- {
- Navigation3D *nav = nullptr;
- Node *p = get_parent();
- while (p != nullptr) {
- nav = Object::cast_to<Navigation3D>(p);
- if (nav != nullptr) {
- p = nullptr;
- } else {
- p = p->get_parent();
- }
- }
-
- set_navigation(nav);
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
}
-
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
agent_parent = nullptr;
- set_navigation(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -154,25 +132,6 @@ NavigationAgent3D::~NavigationAgent3D() {
agent = RID(); // Pointless
}
-void NavigationAgent3D::set_navigation(Navigation3D *p_nav) {
- if (navigation == p_nav) {
- return; // Pointless
- }
-
- navigation = p_nav;
- NavigationServer3D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid());
-}
-
-void NavigationAgent3D::set_navigation_node(Node *p_nav) {
- Navigation3D *nav = Object::cast_to<Navigation3D>(p_nav);
- ERR_FAIL_COND(nav == nullptr);
- set_navigation(nav);
-}
-
-Node *NavigationAgent3D::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
-}
-
void NavigationAgent3D::set_target_desired_distance(real_t p_dd) {
target_desired_distance = p_dd;
}
@@ -286,24 +245,21 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", p_new_velocity);
}
-String NavigationAgent3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
+ warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node."));
}
- return warning;
+ return warnings;
}
void NavigationAgent3D::update_navigation() {
if (agent_parent == nullptr) {
return;
}
- if (navigation == nullptr) {
+ if (!agent_parent->is_inside_tree()) {
return;
}
if (update_frame_id == Engine::get_singleton()->get_physics_frames()) {
@@ -337,7 +293,7 @@ void NavigationAgent3D::update_navigation() {
}
if (reload_path) {
- navigation_path = NavigationServer3D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
+ navigation_path = NavigationServer3D::get_singleton()->map_get_path(agent_parent->get_world_3d()->get_navigation_map(), o, target_location, true);
navigation_finished = false;
nav_path_index = 0;
emit_signal("path_changed");
@@ -353,6 +309,7 @@ void NavigationAgent3D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -361,3 +318,12 @@ void NavigationAgent3D::update_navigation() {
}
}
}
+
+void NavigationAgent3D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index bd890a051b..56da2d1acf 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -35,13 +35,11 @@
#include "scene/main/node.h"
class Node3D;
-class Navigation3D;
class NavigationAgent3D : public Node {
GDCLASS(NavigationAgent3D, Node);
Node3D *agent_parent = nullptr;
- Navigation3D *navigation = nullptr;
RID agent;
@@ -76,14 +74,6 @@ public:
NavigationAgent3D();
virtual ~NavigationAgent3D();
- void set_navigation(Navigation3D *p_nav);
- const Navigation3D *get_navigation() const {
- return navigation;
- }
-
- void set_navigation_node(Node *p_nav);
- Node *get_navigation_node() const;
-
RID get_rid() const {
return agent;
}
@@ -153,10 +143,11 @@ public:
void set_velocity(Vector3 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 01bf7de913..20ffc3b00e 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -31,55 +31,38 @@
#include "navigation_obstacle_3d.h"
#include "scene/3d/collision_shape_3d.h"
-#include "scene/3d/navigation_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "servers/navigation_server_3d.h"
void NavigationObstacle3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle3D::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle3D::get_navigation_node);
}
void NavigationObstacle3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- update_agent_shape();
-
- // Search the navigation node and set it
- {
- Navigation3D *nav = nullptr;
- Node *p = get_parent();
- while (p != nullptr) {
- nav = Object::cast_to<Navigation3D>(p);
- if (nav != nullptr) {
- p = nullptr;
- } else {
- p = p->get_parent();
- }
- }
-
- set_navigation(nav);
- }
-
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- set_navigation(nullptr);
set_physics_process_internal(false);
} break;
+ case NOTIFICATION_PARENTED: {
+ parent_node3d = Object::cast_to<Node3D>(get_parent());
+ update_agent_shape();
+ } break;
+ case NOTIFICATION_UNPARENTED: {
+ parent_node3d = nullptr;
+ } break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- Node3D *spatial = Object::cast_to<Node3D>(get_parent());
- if (spatial) {
- NavigationServer3D::get_singleton()->agent_set_position(agent, spatial->get_global_transform().origin);
- }
-
- PhysicsBody3D *rigid = Object::cast_to<PhysicsBody3D>(get_parent());
- if (rigid) {
- Vector3 v = rigid->get_linear_velocity();
- NavigationServer3D::get_singleton()->agent_set_velocity(agent, v);
- NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, v);
+ if (parent_node3d) {
+ NavigationServer3D::get_singleton()->agent_set_position(agent, parent_node3d->get_global_transform().origin);
+
+ PhysicsBody3D *rigid = Object::cast_to<PhysicsBody3D>(get_parent());
+ if (rigid) {
+ Vector3 v = rigid->get_linear_velocity();
+ NavigationServer3D::get_singleton()->agent_set_velocity(agent, v);
+ NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, v);
+ }
}
-
} break;
}
}
@@ -93,73 +76,49 @@ NavigationObstacle3D::~NavigationObstacle3D() {
agent = RID(); // Pointless
}
-void NavigationObstacle3D::set_navigation(Navigation3D *p_nav) {
- if (navigation == p_nav) {
- return; // Pointless
- }
-
- navigation = p_nav;
- NavigationServer3D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid());
-}
-
-void NavigationObstacle3D::set_navigation_node(Node *p_nav) {
- Navigation3D *nav = Object::cast_to<Navigation3D>(p_nav);
- ERR_FAIL_COND(nav == nullptr);
- set_navigation(nav);
-}
-
-Node *NavigationObstacle3D::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
-}
-
-String NavigationObstacle3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+ warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."));
}
- return warning;
+ return warnings;
}
void NavigationObstacle3D::update_agent_shape() {
- Node *node = get_parent();
-
- // Estimate the radius of this physics body
- real_t radius = 0.0;
- for (int i(0); i < node->get_child_count(); i++) {
- // For each collision shape
- CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(node->get_child(i));
- if (cs) {
- // Take the distance between the Body center to the shape center
- real_t r = cs->get_transform().origin.length();
- if (cs->get_shape().is_valid()) {
- // and add the enclosing shape radius
- r += cs->get_shape()->get_enclosing_radius();
+ if (parent_node3d) {
+ // Estimate the radius of this physics body
+ real_t radius = 0.0;
+ for (int i(0); i < parent_node3d->get_child_count(); i++) {
+ // For each collision shape
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(parent_node3d->get_child(i));
+ if (cs) {
+ // Take the distance between the Body center to the shape center
+ real_t r = cs->get_transform().origin.length();
+ if (cs->get_shape().is_valid()) {
+ // and add the enclosing shape radius
+ r += cs->get_shape()->get_enclosing_radius();
+ }
+ Vector3 s = cs->get_global_transform().basis.get_scale();
+ r *= MAX(s.x, MAX(s.y, s.z));
+ // Takes the biggest radius
+ radius = MAX(radius, r);
}
- Vector3 s = cs->get_global_transform().basis.get_scale();
- r *= MAX(s.x, MAX(s.y, s.z));
- // Takes the biggest radius
- radius = MAX(radius, r);
}
- }
- Node3D *spa = Object::cast_to<Node3D>(node);
- if (spa) {
- Vector3 s = spa->get_global_transform().basis.get_scale();
+
+ Vector3 s = parent_node3d->get_global_transform().basis.get_scale();
radius *= MAX(s.x, MAX(s.y, s.z));
- }
- if (radius == 0.0) {
- radius = 1.0; // Never a 0 radius
- }
+ if (radius == 0.0) {
+ radius = 1.0; // Never a 0 radius
+ }
- // Initialize the Agent as an object
- NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
- NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0);
- NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0);
- NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
- NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0);
+ // Initialize the Agent as an object
+ NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
+ NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0);
+ NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0);
+ NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
+ NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0);
+ }
}
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index b8d05b8a87..2f78f624a4 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -31,15 +31,13 @@
#ifndef NAVIGATION_OBSTACLE_H
#define NAVIGATION_OBSTACLE_H
+#include "scene/3d/node_3d.h"
#include "scene/main/node.h"
-class Navigation3D;
-
class NavigationObstacle3D : public Node {
GDCLASS(NavigationObstacle3D, Node);
- Navigation3D *navigation = nullptr;
-
+ Node3D *parent_node3d = nullptr;
RID agent;
protected:
@@ -50,19 +48,11 @@ public:
NavigationObstacle3D();
virtual ~NavigationObstacle3D();
- void set_navigation(Navigation3D *p_nav);
- const Navigation3D *get_navigation() const {
- return navigation;
- }
-
- void set_navigation_node(Node *p_nav);
- Node *get_navigation_node() const;
-
RID get_rid() const {
return agent;
}
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_agent_shape();
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index a9acaefc65..0afad62404 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -32,7 +32,6 @@
#include "core/os/thread.h"
#include "mesh_instance_3d.h"
-#include "navigation_3d.h"
#include "servers/navigation_server_3d.h"
void NavigationRegion3D::set_enabled(bool p_enabled) {
@@ -48,9 +47,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) {
if (!enabled) {
NavigationServer3D::get_singleton()->region_set_map(region, RID());
} else {
- if (navigation) {
- NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid());
- }
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
}
if (debug_view) {
@@ -69,22 +66,21 @@ bool NavigationRegion3D::is_enabled() const {
return enabled;
}
+void NavigationRegion3D::set_layers(uint32_t p_layers) {
+ NavigationServer3D::get_singleton()->region_set_layers(region, p_layers);
+}
+
+uint32_t NavigationRegion3D::get_layers() const {
+ return NavigationServer3D::get_singleton()->region_get_layers(region);
+}
+
/////////////////////////////
void NavigationRegion3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- Node3D *c = this;
- while (c) {
- navigation = Object::cast_to<Navigation3D>(c);
- if (navigation) {
- if (enabled) {
- NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- break;
- }
-
- c = c->get_parent_spatial();
+ if (enabled) {
+ NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
}
if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
@@ -105,15 +101,12 @@ void NavigationRegion3D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- if (navigation) {
- NavigationServer3D::get_singleton()->region_set_map(region, RID());
- }
+ NavigationServer3D::get_singleton()->region_set_map(region, RID());
if (debug_view) {
debug_view->queue_delete();
debug_view = nullptr;
}
- navigation = nullptr;
} break;
}
}
@@ -124,13 +117,13 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
}
if (navmesh.is_valid()) {
- navmesh->remove_change_receptor(this);
+ navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
navmesh = p_navmesh;
if (navmesh.is_valid()) {
- navmesh->add_change_receptor(this);
+ navmesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
@@ -142,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
emit_signal("navigation_mesh_changed");
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
@@ -184,33 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
emit_signal("bake_finished");
}
-String NavigationRegion3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
-
- if (!navmesh.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
- }
+TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- const Node3D *c = this;
- while (c) {
- if (Object::cast_to<Navigation3D>(c)) {
- return warning;
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!navmesh.is_valid()) {
+ warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work."));
}
-
- c = Object::cast_to<Node3D>(c->get_parent());
}
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- return warning + TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
+ return warnings;
}
void NavigationRegion3D::_bind_methods() {
@@ -220,19 +196,23 @@ 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_layers", "layers"), &NavigationRegion3D::set_layers);
+ ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion3D::get_layers);
+
ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion3D::bake_navigation_mesh);
ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_layers", "get_layers");
ADD_SIGNAL(MethodInfo("navigation_mesh_changed"));
ADD_SIGNAL(MethodInfo("bake_finished"));
}
-void NavigationRegion3D::_changed_callback(Object *p_changed, const char *p_prop) {
+void NavigationRegion3D::_navigation_changed() {
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
NavigationRegion3D::NavigationRegion3D() {
@@ -242,7 +222,7 @@ NavigationRegion3D::NavigationRegion3D() {
NavigationRegion3D::~NavigationRegion3D() {
if (navmesh.is_valid()) {
- navmesh->remove_change_receptor(this);
+ navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed));
}
NavigationServer3D::get_singleton()->free(region);
}
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index e966523b64..c2045215b1 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -35,8 +35,6 @@
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
-class Navigation3D;
-
class NavigationRegion3D : public Node3D {
GDCLASS(NavigationRegion3D, Node3D);
@@ -44,19 +42,22 @@ class NavigationRegion3D : public Node3D {
RID region;
Ref<NavigationMesh> navmesh;
- Navigation3D *navigation = nullptr;
Node *debug_view = nullptr;
Thread bake_thread;
+ void _navigation_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
- void _changed_callback(Object *p_changed, const char *p_prop) override;
public:
void set_enabled(bool p_enabled);
bool is_enabled() const;
+ void set_layers(uint32_t p_layers);
+ uint32_t get_layers() const;
+
void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
Ref<NavigationMesh> get_navigation_mesh() const;
@@ -65,7 +66,7 @@ public:
void bake_navigation_mesh();
void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
NavigationRegion3D();
~NavigationRegion3D();
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 57bead022b..ba0f8cc870 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -48,7 +48,7 @@
a) If above is invalid, don't keep invalidating upwards
2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below)
- drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow
+ drawback: setting/reading globals is useful and used very often, and using affine inverses is slow
---
@@ -226,10 +226,6 @@ void Node3D::_notification(int p_what) {
void Node3D::set_transform(const Transform &p_transform) {
data.local_transform = p_transform;
data.dirty |= DIRTY_VECTORS;
- _change_notify("translation");
- _change_notify("rotation");
- _change_notify("rotation_degrees");
- _change_notify("scale");
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -307,7 +303,6 @@ Transform Node3D::get_relative_transform(const Node *p_parent) const {
void Node3D::set_translation(const Vector3 &p_translation) {
data.local_transform.origin = p_translation;
- _change_notify("transform");
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -322,7 +317,6 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) {
data.rotation = p_euler_rad;
data.dirty |= DIRTY_LOCAL;
- _change_notify("transform");
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -341,7 +335,6 @@ void Node3D::set_scale(const Vector3 &p_scale) {
data.scale = p_scale;
data.dirty |= DIRTY_LOCAL;
- _change_notify("transform");
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -495,7 +488,6 @@ Ref<World3D> Node3D::get_world_3d() const {
void Node3D::_propagate_visibility_changed() {
notification(NOTIFICATION_VISIBILITY_CHANGED);
emit_signal(SceneStringNames::get_singleton()->visibility_changed);
- _change_notify("visible");
#ifdef TOOLS_ENABLED
if (data.gizmo.is_valid()) {
_update_gizmo();
@@ -755,8 +747,8 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("orthonormalize"), &Node3D::orthonormalize);
ClassDB::bind_method(D_METHOD("set_identity"), &Node3D::set_identity);
- ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at);
- ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position);
+ ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at, DEFVAL(Vector3(0, 1, 0)));
+ ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position, DEFVAL(Vector3(0, 1, 0)));
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global);
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 8610e2c0bd..a62c7b31a8 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -173,8 +173,8 @@ public:
void global_scale(const Vector3 &p_scale);
void global_translate(const Vector3 &p_offset);
- void look_at(const Vector3 &p_target, const Vector3 &p_up);
- void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up);
+ void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
+ void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Vector3 to_local(Vector3 p_global) const;
Vector3 to_global(Vector3 p_local) const;
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
new file mode 100644
index 0000000000..d3a256db34
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* occluder_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "occluder_instance_3d.h"
+#include "core/core_string_names.h"
+#include "scene/3d/mesh_instance_3d.h"
+
+RID Occluder3D::get_rid() const {
+ if (!occluder.is_valid()) {
+ occluder = RS::get_singleton()->occluder_create();
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ return occluder;
+}
+
+void Occluder3D::set_vertices(PackedVector3Array p_vertices) {
+ vertices = p_vertices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedVector3Array Occluder3D::get_vertices() const {
+ return vertices;
+}
+
+void Occluder3D::set_indices(PackedInt32Array p_indices) {
+ indices = p_indices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedInt32Array Occluder3D::get_indices() const {
+ return indices;
+}
+
+void Occluder3D::_update_changes() {
+ aabb = AABB();
+
+ const Vector3 *ptr = vertices.ptr();
+ for (int i = 0; i < vertices.size(); i++) {
+ aabb.expand_to(ptr[i]);
+ }
+
+ debug_lines.clear();
+ debug_mesh.unref();
+
+ emit_changed();
+}
+
+Vector<Vector3> Occluder3D::get_debug_lines() const {
+ if (!debug_lines.is_empty()) {
+ return debug_lines;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return Vector<Vector3>();
+ }
+
+ for (int i = 0; i < indices.size() / 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ int a = indices[i * 3 + j];
+ int b = indices[i * 3 + (j + 1) % 3];
+ ERR_FAIL_INDEX_V_MSG(a, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ ERR_FAIL_INDEX_V_MSG(b, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ debug_lines.push_back(vertices[a]);
+ debug_lines.push_back(vertices[b]);
+ }
+ }
+ return debug_lines;
+}
+
+Ref<ArrayMesh> Occluder3D::get_debug_mesh() const {
+ if (debug_mesh.is_valid()) {
+ return debug_mesh;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return debug_mesh;
+ }
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+ arrays[Mesh::ARRAY_VERTEX] = vertices;
+ arrays[Mesh::ARRAY_INDEX] = indices;
+
+ debug_mesh.instance();
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ return debug_mesh;
+}
+
+AABB Occluder3D::get_aabb() const {
+ return aabb;
+}
+
+void Occluder3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &Occluder3D::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &Occluder3D::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &Occluder3D::set_indices);
+ ClassDB::bind_method(D_METHOD("get_indices"), &Occluder3D::get_indices);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_indices", "get_indices");
+}
+
+Occluder3D::Occluder3D() {
+}
+
+Occluder3D::~Occluder3D() {
+ if (occluder.is_valid()) {
+ RS::get_singleton()->free(occluder);
+ }
+}
+/////////////////////////////////////////////////
+
+AABB OccluderInstance3D::get_aabb() const {
+ if (occluder.is_valid()) {
+ return occluder->get_aabb();
+ }
+ return AABB();
+}
+
+Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
+void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
+ if (occluder == p_occluder) {
+ return;
+ }
+
+ if (occluder.is_valid()) {
+ occluder->disconnect(CoreStringNames::get_singleton()->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));
+ } else {
+ set_base(RID());
+ }
+
+ update_gizmo();
+}
+
+void OccluderInstance3D::_occluder_changed() {
+ update_gizmo();
+}
+
+Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
+ return occluder;
+}
+
+void OccluderInstance3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+}
+
+uint32_t OccluderInstance3D::get_bake_mask() const {
+ return bake_mask;
+}
+
+void OccluderInstance3D::set_bake_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_bake_mask(bake_mask | (1 << p_layer));
+ } else {
+ set_bake_mask(bake_mask & (~(1 << p_layer)));
+ }
+}
+
+bool OccluderInstance3D::get_bake_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (bake_mask & (1 << p_layer));
+}
+
+bool OccluderInstance3D::_bake_material_check(Ref<Material> p_material) {
+ StandardMaterial3D *standard_mat = Object::cast_to<StandardMaterial3D>(p_material.ptr());
+ if (standard_mat && standard_mat->get_transparency() != StandardMaterial3D::TRANSPARENCY_DISABLED) {
+ return false;
+ }
+ return true;
+}
+
+void OccluderInstance3D::_bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (mi && mi->is_visible_in_tree()) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ bool valid = true;
+
+ if (mesh.is_null()) {
+ valid = false;
+ }
+
+ if (valid && !_bake_material_check(mi->get_material_override())) {
+ valid = false;
+ }
+
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ valid = false;
+ }
+
+ if (valid) {
+ Transform global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (mi->get_surface_override_material(i).is_valid()) {
+ if (!_bake_material_check(mi->get_surface_override_material(i))) {
+ continue;
+ }
+ } else {
+ if (!_bake_material_check(mesh->surface_get_material(i))) {
+ continue;
+ }
+ }
+
+ Array arrays = mesh->surface_get_arrays(i);
+
+ int vertex_offset = r_vertices.size();
+ PackedVector3Array vertices = arrays[Mesh::ARRAY_VERTEX];
+ r_vertices.resize(r_vertices.size() + vertices.size());
+
+ Vector3 *vtx_ptr = r_vertices.ptrw();
+ for (int j = 0; j < vertices.size(); j++) {
+ vtx_ptr[vertex_offset + j] = global_to_local.xform(vertices[j]);
+ }
+
+ int index_offset = r_indices.size();
+ PackedInt32Array indices = arrays[Mesh::ARRAY_INDEX];
+ r_indices.resize(r_indices.size() + indices.size());
+
+ int *idx_ptr = r_indices.ptrw();
+ for (int j = 0; j < indices.size(); j++) {
+ idx_ptr[index_offset + j] = vertex_offset + indices[j];
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ if (!child->get_owner()) {
+ continue; //maybe a helper
+ }
+
+ _bake_node(child, r_vertices, r_indices);
+ }
+}
+
+OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String p_occluder_path) {
+ if (p_occluder_path == "") {
+ if (get_occluder().is_null()) {
+ return BAKE_ERROR_NO_SAVE_PATH;
+ }
+ }
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ _bake_node(p_from_node, vertices, indices);
+
+ if (vertices.is_empty() || indices.is_empty()) {
+ return BAKE_ERROR_NO_MESHES;
+ }
+
+ Ref<Occluder3D> occ;
+ if (get_occluder().is_valid()) {
+ occ = get_occluder();
+ } else {
+ occ.instance();
+ occ->set_path(p_occluder_path);
+ }
+
+ occ->set_vertices(vertices);
+ occ->set_indices(indices);
+ set_occluder(occ);
+
+ return BAKE_ERROR_OK;
+}
+
+void OccluderInstance3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask);
+ ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_bit", "layer", "enabled"), &OccluderInstance3D::set_bake_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_bit", "layer"), &OccluderInstance3D::get_bake_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_occluder", "occluder"), &OccluderInstance3D::set_occluder);
+ ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "Occluder3D"), "set_occluder", "get_occluder");
+ ADD_GROUP("Bake", "bake_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
+}
+
+OccluderInstance3D::OccluderInstance3D() {
+}
+
+OccluderInstance3D::~OccluderInstance3D() {
+}
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
new file mode 100644
index 0000000000..4bb468274d
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* occluder_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUDER_INSTANCE_3D_H
+#define OCCLUDER_INSTANCE_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+
+class Occluder3D : public Resource {
+ GDCLASS(Occluder3D, Resource);
+ RES_BASE_EXTENSION("occ");
+
+ mutable RID occluder;
+ mutable Ref<ArrayMesh> debug_mesh;
+ mutable Vector<Vector3> debug_lines;
+ AABB aabb;
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ void _update_changes();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_vertices(PackedVector3Array p_vertices);
+ PackedVector3Array get_vertices() const;
+
+ void set_indices(PackedInt32Array p_indices);
+ PackedInt32Array get_indices() const;
+
+ Vector<Vector3> get_debug_lines() const;
+ Ref<ArrayMesh> get_debug_mesh() const;
+ AABB get_aabb() const;
+
+ virtual RID get_rid() const override;
+ Occluder3D();
+ ~Occluder3D();
+};
+
+class OccluderInstance3D : public VisualInstance3D {
+ GDCLASS(OccluderInstance3D, Node3D);
+
+private:
+ Ref<Occluder3D> occluder;
+ uint32_t bake_mask = 0xFFFFFFFF;
+
+ void _occluder_changed();
+
+ bool _bake_material_check(Ref<Material> p_material);
+ void _bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum BakeError {
+ BAKE_ERROR_OK,
+ BAKE_ERROR_NO_SAVE_PATH,
+ BAKE_ERROR_NO_MESHES,
+ };
+
+ void set_occluder(const Ref<Occluder3D> &p_occluder);
+ Ref<Occluder3D> get_occluder() const;
+
+ virtual AABB get_aabb() const override;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
+ void set_bake_mask(uint32_t p_mask);
+ uint32_t get_bake_mask() const;
+
+ void set_bake_mask_bit(int p_layer, bool p_enable);
+ bool get_bake_mask_bit(int p_layer) const;
+ BakeError bake(Node *p_from_node, String p_occluder_path = "");
+
+ OccluderInstance3D();
+ ~OccluderInstance3D();
+};
+
+#endif
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 3f048beb71..4ec4ee6207 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -50,7 +50,7 @@ void Path3D::_curve_changed() {
for (int i = 0; i < get_child_count(); i++) {
PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));
if (child) {
- child->update_configuration_warning();
+ child->update_configuration_warnings();
}
}
}
@@ -241,29 +241,21 @@ void PathFollow3D::_validate_property(PropertyInfo &property) const {
}
}
-String PathFollow3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> PathFollow3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!Object::cast_to<Path3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("PathFollow3D only works when set as a child of a Path3D node.");
- } else {
- Path3D *path = Object::cast_to<Path3D>(get_parent());
- if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!Object::cast_to<Path3D>(get_parent())) {
+ warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node."));
+ } else {
+ Path3D *path = Object::cast_to<Path3D>(get_parent());
+ if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
+ warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));
}
- warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
}
}
- return warning;
+ return warnings;
}
void PathFollow3D::_bind_methods() {
@@ -323,8 +315,6 @@ void PathFollow3D::set_offset(float p_offset) {
_update_transform();
}
- _change_notify("offset");
- _change_notify("unit_offset");
}
void PathFollow3D::set_h_offset(float p_h_offset) {
@@ -370,7 +360,7 @@ float PathFollow3D::get_unit_offset() const {
void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {
rotation_mode = p_rotation_mode;
- update_configuration_warning();
+ update_configuration_warnings();
_update_transform();
}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 17ee47593e..8545370a4a 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -104,7 +104,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PathFollow3D() {}
};
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 367dd7ec91..93d3e946fd 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -55,52 +55,6 @@ real_t PhysicsBody3D::get_inverse_mass() const {
return 0;
}
-void PhysicsBody3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody3D::get_collision_layer() const {
- return collision_layer;
-}
-
-void PhysicsBody3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t PhysicsBody3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void PhysicsBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool PhysicsBody3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void PhysicsBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_layer(mask);
-}
-
-bool PhysicsBody3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
@@ -129,28 +83,11 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody3D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody3D::get_collision_layer_bit);
-
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-}
+void PhysicsBody3D::_bind_methods() {}
PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
- CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(p_mode), false) {
- collision_layer = 1;
- collision_mask = 1;
+ CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
}
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
@@ -337,6 +274,7 @@ struct _RigidBodyInOut {
void RigidBody3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -415,13 +353,13 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
}
}
- //process remotions
+ //process removals
for (int i = 0; i < toremove_count; i++) {
_body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
- //process aditions
+ //process additions
for (int i = 0; i < toadd_count; i++) {
_body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
@@ -443,7 +381,7 @@ void RigidBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -468,7 +406,7 @@ void RigidBody3D::set_mode(Mode p_mode) {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
} break;
}
- update_configuration_warning();
+ update_configuration_warnings();
}
RigidBody3D::Mode RigidBody3D::get_mode() const {
@@ -708,19 +646,16 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret;
}
-String RigidBody3D::get_configuration_warning() const {
+TypedArray<String> RigidBody3D::get_configuration_warnings() const {
Transform t = get_transform();
- String warning = CollisionObject3D::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void RigidBody3D::_bind_methods() {
@@ -778,8 +713,6 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock);
@@ -825,7 +758,7 @@ void RigidBody3D::_bind_methods() {
RigidBody3D::RigidBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -1159,8 +1092,6 @@ void KinematicBody3D::_notification(int p_what) {
}
void KinematicBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
@@ -1193,6 +1124,7 @@ void KinematicBody3D::_bind_methods() {
void KinematicBody3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -1204,7 +1136,7 @@ void KinematicBody3D::_direct_state_changed(Object *p_state) {
KinematicBody3D::KinematicBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
set_safe_margin(0.001);
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody3D::_direct_state_changed));
}
KinematicBody3D::~KinematicBody3D() {
@@ -2011,7 +1943,7 @@ void PhysicalBone3D::_notification(int p_what) {
update_bone_id();
reset_to_rest_position();
reset_physics_simulation_state();
- if (!joint.is_valid() && joint_data) {
+ if (joint_data) {
_reload_joint();
}
break;
@@ -2022,10 +1954,7 @@ void PhysicalBone3D::_notification(int p_what) {
}
}
parent_skeleton = nullptr;
- if (joint.is_valid()) {
- PhysicsServer3D::get_singleton()->free(joint);
- joint = RID();
- }
+ PhysicsServer3D::get_singleton()->joint_clear(joint);
break;
case NOTIFICATION_TRANSFORM_CHANGED:
if (Engine::get_singleton()->is_editor_hint()) {
@@ -2046,6 +1975,7 @@ void PhysicalBone3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -2068,8 +1998,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type);
ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type);
@@ -2175,17 +2103,14 @@ void PhysicalBone3D::_fix_joint_offset() {
}
void PhysicalBone3D::_reload_joint() {
- if (joint.is_valid()) {
- PhysicsServer3D::get_singleton()->free(joint);
- joint = RID();
- }
-
if (!parent_skeleton) {
+ PhysicsServer3D::get_singleton()->joint_clear(joint);
return;
}
PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id);
if (!body_a) {
+ PhysicsServer3D::get_singleton()->joint_clear(joint);
return;
}
@@ -2195,7 +2120,7 @@ void PhysicalBone3D::_reload_joint() {
switch (get_joint_type()) {
case JOINT_TYPE_PIN: {
- joint = PhysicsServer3D::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin);
+ PhysicsServer3D::get_singleton()->joint_make_pin(joint, body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin);
const PinJointData *pjd(static_cast<const PinJointData *>(joint_data));
PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_BIAS, pjd->bias);
PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_DAMPING, pjd->damping);
@@ -2203,7 +2128,7 @@ void PhysicalBone3D::_reload_joint() {
} break;
case JOINT_TYPE_CONE: {
- joint = PhysicsServer3D::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ PhysicsServer3D::get_singleton()->joint_make_cone_twist(joint, body_a->get_rid(), local_a, get_rid(), joint_offset);
const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data));
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span);
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span);
@@ -2213,7 +2138,7 @@ void PhysicalBone3D::_reload_joint() {
} break;
case JOINT_TYPE_HINGE: {
- joint = PhysicsServer3D::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ PhysicsServer3D::get_singleton()->joint_make_hinge(joint, body_a->get_rid(), local_a, get_rid(), joint_offset);
const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data));
PhysicsServer3D::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled);
PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper);
@@ -2224,7 +2149,7 @@ void PhysicalBone3D::_reload_joint() {
} break;
case JOINT_TYPE_SLIDER: {
- joint = PhysicsServer3D::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ PhysicsServer3D::get_singleton()->joint_make_slider(joint, body_a->get_rid(), local_a, get_rid(), joint_offset);
const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data));
PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper);
PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower);
@@ -2239,7 +2164,7 @@ void PhysicalBone3D::_reload_joint() {
} break;
case JOINT_TYPE_6DOF: {
- joint = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ PhysicsServer3D::get_singleton()->joint_make_generic_6dof(joint, body_a->get_rid(), local_a, get_rid(), joint_offset);
const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data));
for (int axis = 0; axis < 3; ++axis) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled);
@@ -2332,7 +2257,7 @@ void PhysicalBone3D::set_joint_type(JointType p_joint_type) {
_reload_joint();
#ifdef TOOLS_ENABLED
- _change_notify();
+ notify_property_list_changed();
if (get_gizmo().is_valid()) {
get_gizmo()->redraw();
}
@@ -2347,7 +2272,6 @@ void PhysicalBone3D::set_joint_offset(const Transform &p_offset) {
joint_offset = p_offset;
_update_joint_offset();
- _change_notify("joint_rotation_degrees");
}
const Transform &PhysicalBone3D::get_joint_offset() const {
@@ -2358,7 +2282,6 @@ void PhysicalBone3D::set_joint_rotation(const Vector3 &p_euler_rad) {
joint_offset.basis.set_euler_scale(p_euler_rad, joint_offset.basis.get_scale());
_update_joint_offset();
- _change_notify("joint_offset");
}
Vector3 PhysicalBone3D::get_joint_rotation() const {
@@ -2493,6 +2416,7 @@ bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
PhysicalBone3D::PhysicalBone3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) {
+ joint = PhysicsServer3D::get_singleton()->joint_create();
reset_physics_simulation_state();
}
@@ -2500,6 +2424,7 @@ PhysicalBone3D::~PhysicalBone3D() {
if (joint_data) {
memdelete(joint_data);
}
+ PhysicsServer3D::get_singleton()->free(joint);
}
void PhysicalBone3D::update_bone_id() {
@@ -2551,7 +2476,7 @@ void PhysicalBone3D::_start_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2570,7 +2495,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 1450fce6a6..21afe66861 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -40,9 +40,6 @@
class PhysicsBody3D : public CollisionObject3D {
GDCLASS(PhysicsBody3D, CollisionObject3D);
- uint32_t collision_layer;
- uint32_t collision_mask;
-
protected:
static void _bind_methods();
PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
@@ -52,18 +49,6 @@ public:
virtual Vector3 get_angular_velocity() const;
virtual real_t get_inverse_mass() const;
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
TypedArray<PhysicsBody3D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
@@ -238,7 +223,7 @@ public:
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RigidBody3D();
~RigidBody3D();
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index 624587cce4..3d58d1c10e 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -46,35 +46,26 @@ void Joint3D::_disconnect_signals() {
}
}
-void Joint3D::_body_exit_tree(const ObjectID &p_body_id) {
+void Joint3D::_body_exit_tree() {
_disconnect_signals();
- Object *object = ObjectDB::get_instance(p_body_id);
- PhysicsBody3D *body = Object::cast_to<PhysicsBody3D>(object);
- ERR_FAIL_NULL(body);
- RID body_rid = body->get_rid();
- if (ba == body_rid) {
- a = NodePath();
- }
- if (bb == body_rid) {
- b = NodePath();
- }
- _update_joint();
+ _update_joint(true);
}
void Joint3D::_update_joint(bool p_only_free) {
- if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid()) {
- PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb);
- }
-
- PhysicsServer3D::get_singleton()->free(joint);
- joint = RID();
- ba = RID();
- bb = RID();
+ if (ba.is_valid() && bb.is_valid()) {
+ PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb);
+ PhysicsServer3D::get_singleton()->body_remove_collision_exception(bb, ba);
}
+ ba = RID();
+ bb = RID();
+
+ configured = false;
+
if (p_only_free || !is_inside_tree()) {
+ PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = String();
+ update_configuration_warnings();
return;
}
@@ -86,55 +77,43 @@ void Joint3D::_update_joint(bool p_only_free) {
if (node_a && !body_a && node_b && !body_b) {
warning = TTR("Node A and Node B must be PhysicsBody3Ds");
- update_configuration_warning();
- return;
- }
-
- if (node_a && !body_a) {
+ } else if (node_a && !body_a) {
warning = TTR("Node A must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (node_b && !body_b) {
+ } else if (node_b && !body_b) {
warning = TTR("Node B must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (!body_a && !body_b) {
+ } else if (!body_a && !body_b) {
warning = TTR("Joint is not connected to any PhysicsBody3Ds");
- update_configuration_warning();
- return;
+ } else if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
+ } else {
+ warning = String();
}
- if (body_a == body_b) {
- warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
- update_configuration_warning();
+ update_configuration_warnings();
+
+ if (!warning.is_empty()) {
+ PhysicsServer3D::get_singleton()->joint_clear(joint);
return;
}
- warning = String();
- update_configuration_warning();
+ configured = true;
if (body_a) {
- joint = _configure_joint(body_a, body_b);
+ _configure_joint(joint, body_a, body_b);
} else if (body_b) {
- joint = _configure_joint(body_b, nullptr);
+ _configure_joint(joint, body_b, nullptr);
}
- ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint.");
-
PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority);
if (body_a) {
ba = body_a->get_rid();
- body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree), make_binds(body_a->get_instance_id()));
+ body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree));
}
if (body_b) {
bb = body_b->get_rid();
- body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree), make_binds(body_b->get_instance_id()));
+ body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree));
}
PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
@@ -211,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-String Joint3D::get_configuration_warning() const {
- String node_warning = Node3D::get_configuration_warning();
+TypedArray<String> Joint3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node3D::get_configuration_warnings();
if (!warning.is_empty()) {
- if (!node_warning.is_empty()) {
- node_warning += "\n\n";
- }
- node_warning += warning;
+ warnings.push_back(warning);
}
- return node_warning;
+ return warnings;
}
void Joint3D::_bind_methods() {
@@ -246,6 +222,11 @@ void Joint3D::_bind_methods() {
Joint3D::Joint3D() {
set_notify_transform(true);
+ joint = PhysicsServer3D::get_singleton()->joint_create();
+}
+
+Joint3D::~Joint3D() {
+ PhysicsServer3D::get_singleton()->free(joint);
}
///////////////////////////////////
@@ -266,7 +247,7 @@ void PinJoint3D::_bind_methods() {
void PinJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, 3);
params[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer3D::PinJointParam(p_param), p_value);
}
}
@@ -276,7 +257,7 @@ real_t PinJoint3D::get_param(Param p_param) const {
return params[p_param];
}
-RID PinJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+void PinJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Vector3 pinpos = get_global_transform().origin;
Vector3 local_a = body_a->get_global_transform().affine_inverse().xform(pinpos);
Vector3 local_b;
@@ -287,11 +268,10 @@ RID PinJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
local_b = pinpos;
}
- RID j = PhysicsServer3D::get_singleton()->joint_create_pin(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
+ PhysicsServer3D::get_singleton()->joint_make_pin(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
for (int i = 0; i < 3; i++) {
- PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PinJointParam(i), params[i]);
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer3D::PinJointParam(i), params[i]);
}
- return j;
}
PinJoint3D::PinJoint3D() {
@@ -364,7 +344,7 @@ void HingeJoint3D::_bind_methods() {
void HingeJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer3D::HingeJointParam(p_param), p_value);
}
@@ -379,7 +359,7 @@ real_t HingeJoint3D::get_param(Param p_param) const {
void HingeJoint3D::set_flag(Flag p_flag, bool p_value) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags[p_flag] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer3D::HingeJointFlag(p_flag), p_value);
}
@@ -391,7 +371,7 @@ bool HingeJoint3D::get_flag(Flag p_flag) const {
return flags[p_flag];
}
-RID HingeJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
Transform ainv = body_a->get_global_transform().affine_inverse();
@@ -406,15 +386,14 @@ RID HingeJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b)
local_b.orthonormalize();
- RID j = PhysicsServer3D::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
+ PhysicsServer3D::get_singleton()->joint_make_hinge(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HingeJointParam(i), params[i]);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(p_joint, PhysicsServer3D::HingeJointParam(i), params[i]);
}
for (int i = 0; i < FLAG_MAX; i++) {
set_flag(Flag(i), flags[i]);
- PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HingeJointFlag(i), flags[i]);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_flag(p_joint, PhysicsServer3D::HingeJointFlag(i), flags[i]);
}
- return j;
}
HingeJoint3D::HingeJoint3D() {
@@ -515,7 +494,7 @@ void SliderJoint3D::_bind_methods() {
void SliderJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer3D::SliderJointParam(p_param), p_value);
}
update_gizmo();
@@ -526,7 +505,7 @@ real_t SliderJoint3D::get_param(Param p_param) const {
return params[p_param];
}
-RID SliderJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
Transform ainv = body_a->get_global_transform().affine_inverse();
@@ -541,12 +520,10 @@ RID SliderJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b
local_b.orthonormalize();
- RID j = PhysicsServer3D::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
+ PhysicsServer3D::get_singleton()->joint_make_slider(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SliderJointParam(i), params[i]);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(p_joint, PhysicsServer3D::SliderJointParam(i), params[i]);
}
-
- return j;
}
SliderJoint3D::SliderJoint3D() {
@@ -621,7 +598,7 @@ void ConeTwistJoint3D::_bind_methods() {
void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value);
}
@@ -633,7 +610,7 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const {
return params[p_param];
}
-RID ConeTwistJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
//Vector3 cone_twistdir = gt.basis.get_axis(2);
@@ -651,12 +628,10 @@ RID ConeTwistJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *bod
local_b.orthonormalize();
- RID j = PhysicsServer3D::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
+ PhysicsServer3D::get_singleton()->joint_make_cone_twist(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::ConeTwistJointParam(i), params[i]);
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(p_joint, PhysicsServer3D::ConeTwistJointParam(i), params[i]);
}
-
- return j;
}
ConeTwistJoint3D::ConeTwistJoint3D() {
@@ -878,7 +853,7 @@ void Generic6DOFJoint3D::_bind_methods() {
void Generic6DOFJoint3D::set_param_x(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_x[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
@@ -893,7 +868,7 @@ real_t Generic6DOFJoint3D::get_param_x(Param p_param) const {
void Generic6DOFJoint3D::set_param_y(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_y[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
update_gizmo();
@@ -907,7 +882,7 @@ real_t Generic6DOFJoint3D::get_param_y(Param p_param) const {
void Generic6DOFJoint3D::set_param_z(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_z[p_param] = p_value;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
update_gizmo();
@@ -921,7 +896,7 @@ real_t Generic6DOFJoint3D::get_param_z(Param p_param) const {
void Generic6DOFJoint3D::set_flag_x(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_x[p_flag] = p_enabled;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmo();
@@ -935,7 +910,7 @@ bool Generic6DOFJoint3D::get_flag_x(Flag p_flag) const {
void Generic6DOFJoint3D::set_flag_y(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_y[p_flag] = p_enabled;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmo();
@@ -949,7 +924,7 @@ bool Generic6DOFJoint3D::get_flag_y(Flag p_flag) const {
void Generic6DOFJoint3D::set_flag_z(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_z[p_flag] = p_enabled;
- if (get_joint().is_valid()) {
+ if (is_configured()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmo();
@@ -960,7 +935,7 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
return flags_z[p_flag];
}
-RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform gt = get_global_transform();
//Vector3 cone_twistpos = gt.origin;
//Vector3 cone_twistdir = gt.basis.get_axis(2);
@@ -978,19 +953,17 @@ RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *b
local_b.orthonormalize();
- RID j = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
+ PhysicsServer3D::get_singleton()->joint_make_generic_6dof(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(i), params_x[i]);
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(i), params_y[i]);
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(i), params_z[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(i), params_x[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(i), params_y[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(i), params_z[i]);
}
for (int i = 0; i < FLAG_MAX; i++) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_x[i]);
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_y[i]);
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_z[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_x[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_y[i]);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_z[i]);
}
-
- return j;
}
Generic6DOFJoint3D::Generic6DOFJoint3D() {
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index 914ac3c392..3e0ea38a5c 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -47,20 +47,23 @@ class Joint3D : public Node3D {
int solver_priority = 1;
bool exclude_from_collision = true;
String warning;
+ bool configured = false;
protected:
void _disconnect_signals();
- void _body_exit_tree(const ObjectID &p_body_id);
+ void _body_exit_tree();
void _update_joint(bool p_only_free = false);
void _notification(int p_what);
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0;
static void _bind_methods();
+ _FORCE_INLINE_ bool is_configured() const { return configured; }
+
public:
- virtual String get_configuration_warning() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
@@ -76,6 +79,7 @@ public:
RID get_joint() const { return joint; }
Joint3D();
+ ~Joint3D();
};
///////////////////////////////////////////
@@ -92,7 +96,7 @@ public:
protected:
real_t params[3];
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
public:
@@ -129,7 +133,7 @@ public:
protected:
real_t params[PARAM_MAX];
bool flags[FLAG_MAX];
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
void _set_upper_limit(real_t p_limit);
@@ -191,7 +195,7 @@ protected:
real_t _get_lower_limit_angular() const;
real_t params[PARAM_MAX];
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
public:
@@ -224,7 +228,7 @@ protected:
real_t _get_twist_span() const;
real_t params[PARAM_MAX];
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
public:
@@ -302,7 +306,7 @@ protected:
real_t params_z[PARAM_MAX];
bool flags_z[FLAG_MAX];
- virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
+ virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
public:
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index bfe79f15f5..95638ce514 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -37,10 +37,13 @@
void RayCast3D::set_target_position(const Vector3 &p_point) {
target_position = p_point;
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) {
- update_gizmo();
- }
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
+ update_gizmo();
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (is_inside_tree()) {
+ _update_debug_shape_vertices();
+ }
+ } else if (debug_shape) {
_update_debug_shape();
}
}
@@ -58,6 +61,7 @@ uint32_t RayCast3D::get_collision_mask() const {
}
void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -68,6 +72,7 @@ void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool RayCast3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -146,6 +151,9 @@ bool RayCast3D::get_exclude_parent_body() const {
void RayCast3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ _update_debug_shape_vertices();
+ }
if (enabled && !Engine::get_singleton()->is_editor_hint()) {
set_physics_process_internal(true);
} else {
@@ -183,10 +191,7 @@ void RayCast3D::_notification(int p_what) {
bool prev_collision_state = collided;
_update_raycast_state();
if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) {
- if (debug_material.is_valid()) {
- Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D>>(debug_material);
- line_material->set_albedo(collided ? Color(1.0, 0, 0) : Color(1.0, 0.8, 0.6));
- }
+ _update_debug_shape_material(true);
}
} break;
@@ -310,6 +315,12 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast3D::set_collide_with_bodies);
ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast3D::is_collide_with_bodies_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);
+
+ ClassDB::bind_method(D_METHOD("set_debug_shape_thickness", "debug_shape_thickness"), &RayCast3D::set_debug_shape_thickness);
+ ClassDB::bind_method(D_METHOD("get_debug_shape_thickness"), &RayCast3D::get_debug_shape_thickness);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
@@ -318,16 +329,80 @@ void RayCast3D::_bind_methods() {
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");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
+
+ ADD_GROUP("Debug Shape", "debug_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_shape_thickness", PROPERTY_HINT_RANGE, "1,5"), "set_debug_shape_thickness", "get_debug_shape_thickness");
}
-void RayCast3D::_create_debug_shape() {
- if (!debug_material.is_valid()) {
- debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+float RayCast3D::get_debug_shape_thickness() const {
+ return debug_shape_thickness;
+}
+
+void RayCast3D::_update_debug_shape_vertices() {
+ debug_shape_vertices.clear();
+ debug_line_vertices.clear();
+
+ if (target_position == Vector3()) {
+ return;
+ }
+
+ debug_line_vertices.push_back(Vector3());
+ debug_line_vertices.push_back(target_position);
+
+ if (debug_shape_thickness > 1) {
+ float scale_factor = 100.0;
+ Vector3 dir = Vector3(target_position).normalized();
+ // Draw truncated pyramid
+ Vector3 normal = (fabs(dir.x) + fabs(dir.y) > CMP_EPSILON) ? Vector3(-dir.y, dir.x, 0).normalized() : Vector3(0, -dir.z, dir.y).normalized();
+ normal *= debug_shape_thickness / scale_factor;
+ int vertices_strip_order[14] = { 4, 5, 0, 1, 2, 5, 6, 4, 7, 0, 3, 2, 7, 6 };
+ for (int v = 0; v < 14; v++) {
+ Vector3 vertex = vertices_strip_order[v] < 4 ? normal : normal / 3.0 + target_position;
+ debug_shape_vertices.push_back(vertex.rotated(dir, Math_PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25)));
+ }
+ }
+}
+
+void RayCast3D::set_debug_shape_thickness(const float p_debug_shape_thickness) {
+ debug_shape_thickness = p_debug_shape_thickness;
+ update_gizmo();
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (is_inside_tree()) {
+ _update_debug_shape_vertices();
+ }
+ } else if (debug_shape) {
+ _update_debug_shape();
+ }
+}
+
+const Vector<Vector3> &RayCast3D::get_debug_shape_vertices() const {
+ return debug_shape_vertices;
+}
- Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D>>(debug_material);
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_albedo(Color(1.0, 0.8, 0.6));
+const Vector<Vector3> &RayCast3D::get_debug_line_vertices() const {
+ return debug_line_vertices;
+}
+
+void RayCast3D::set_debug_shape_custom_color(const Color &p_color) {
+ debug_shape_custom_color = p_color;
+ if (debug_material.is_valid()) {
+ _update_debug_shape_material();
}
+}
+
+Ref<StandardMaterial3D> RayCast3D::get_debug_material() {
+ _update_debug_shape_material();
+ return debug_material;
+}
+
+const Color &RayCast3D::get_debug_shape_custom_color() const {
+ return debug_shape_custom_color;
+}
+
+void RayCast3D::_create_debug_shape() {
+ _update_debug_shape_material();
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
@@ -338,6 +413,35 @@ void RayCast3D::_create_debug_shape() {
debug_shape = mi;
}
+void RayCast3D::_update_debug_shape_material(bool p_check_collision) {
+ if (!debug_material.is_valid()) {
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ debug_material = material;
+
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
+ }
+
+ Color color = debug_shape_custom_color;
+ if (color == Color(0.0, 0.0, 0.0)) {
+ // Use the default debug shape color defined in the Project Settings.
+ color = get_tree()->get_debug_collisions_color();
+ }
+
+ if (p_check_collision) {
+ if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
+ // If base color is already quite reddish, highlight collision with green color
+ color = Color(0.0, 1.0, 0.0, color.a);
+ } else {
+ // Else, highlight collision with red color
+ color = Color(1.0, 0, 0, color.a);
+ }
+ }
+
+ Ref<StandardMaterial3D> material = static_cast<Ref<StandardMaterial3D>>(debug_material);
+ material->set_albedo(color);
+}
+
void RayCast3D::_update_debug_shape() {
if (!enabled) {
return;
@@ -353,26 +457,28 @@ void RayCast3D::_update_debug_shape() {
return;
}
- Vector<Vector3> verts;
- verts.push_back(Vector3());
- verts.push_back(target_position);
+ _update_debug_shape_vertices();
- if (mesh->get_surface_count() == 0) {
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = verts;
+ mesh->clear_surfaces();
- uint32_t flags = Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ uint32_t flags = 0;
+ int surface_count = 0;
+
+ if (!debug_line_vertices.is_empty()) {
+ a[Mesh::ARRAY_VERTEX] = debug_line_vertices;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags);
- mesh->surface_set_material(0, debug_material);
- } else {
- Vector<uint8_t> byte_array;
- int array_size = sizeof(Vector3) * verts.size();
- byte_array.resize(array_size);
- copymem(byte_array.ptrw(), verts.ptr(), array_size);
+ mesh->surface_set_material(surface_count, debug_material);
+ ++surface_count;
+ }
- RS::get_singleton()->mesh_surface_update_region(mesh->get_rid(), 0, 0, byte_array);
+ if (!debug_shape_vertices.is_empty()) {
+ a[Mesh::ARRAY_VERTEX] = debug_shape_vertices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, a, Array(), Dictionary(), flags);
+ mesh->surface_set_material(surface_count, debug_material);
+ ++surface_count;
}
}
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index ae92189527..968cede9f2 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -51,9 +51,15 @@ class RayCast3D : public Node3D {
Node *debug_shape = nullptr;
Ref<Material> debug_material;
+ Color debug_shape_custom_color = Color(0.0, 0.0, 0.0);
+ int debug_shape_thickness = 2;
+ Vector<Vector3> debug_shape_vertices;
+ Vector<Vector3> debug_line_vertices;
void _create_debug_shape();
void _update_debug_shape();
+ void _update_debug_shape_material(bool p_check_collision = false);
+ void _update_debug_shape_vertices();
void _clear_debug_shape();
bool collide_with_areas = false;
@@ -86,6 +92,17 @@ public:
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
+ const Color &get_debug_shape_custom_color() const;
+ void set_debug_shape_custom_color(const Color &p_color);
+
+ const Vector<Vector3> &get_debug_shape_vertices() const;
+ const Vector<Vector3> &get_debug_line_vertices() const;
+
+ Ref<StandardMaterial3D> get_debug_material();
+
+ float get_debug_shape_thickness() const;
+ void set_debug_shape_thickness(const float p_debug_thickness);
+
void force_raycast_update();
bool is_colliding() const;
Object *get_collider() const;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 74f7fe2b52..ad24f39bce 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -42,7 +42,7 @@ float ReflectionProbe::get_intensity() const {
void ReflectionProbe::set_ambient_mode(AmbientMode p_mode) {
ambient_mode = p_mode;
RS::get_singleton()->reflection_probe_set_ambient_mode(probe, RS::ReflectionProbeAmbientMode(p_mode));
- _change_notify();
+ notify_property_list_changed();
}
ReflectionProbe::AmbientMode ReflectionProbe::get_ambient_mode() const {
@@ -95,13 +95,12 @@ void ReflectionProbe::set_extents(const Vector3 &p_extents) {
if (extents[i] - 0.01 < ABS(origin_offset[i])) {
origin_offset[i] = SGN(origin_offset[i]) * (extents[i] - 0.01);
- _change_notify("origin_offset");
}
}
RS::get_singleton()->reflection_probe_set_extents(probe, extents);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
- _change_notify("extents");
+
update_gizmo();
}
@@ -120,7 +119,6 @@ void ReflectionProbe::set_origin_offset(const Vector3 &p_extents) {
RS::get_singleton()->reflection_probe_set_extents(probe, extents);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
- _change_notify("origin_offset");
update_gizmo();
}
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 83ac813c53..29a407905b 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {
_update_remote();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath RemoteTransform3D::get_remote_node() const {
@@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() {
_update_cache();
}
-String RemoteTransform3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> RemoteTransform3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+ warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
}
- return warning;
+ return warnings;
}
void RemoteTransform3D::_bind_methods() {
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
index 21005d92d1..321bd3b51e 100644
--- a/scene/3d/remote_transform_3d.h
+++ b/scene/3d/remote_transform_3d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RemoteTransform3D();
};
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index ac2e9bf871..ebbb8985c9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -304,7 +304,7 @@ void Skeleton3D::_notification(int p_what) {
uint32_t bind_count = skin->get_bind_count();
if (E->get()->bind_count != bind_count) {
- RS::get_singleton()->skeleton_allocate(skeleton, bind_count);
+ RS::get_singleton()->skeleton_allocate_data(skeleton, bind_count);
E->get()->bind_count = bind_count;
E->get()->skin_bone_indices.resize(bind_count);
E->get()->skin_bone_indices_ptrs = E->get()->skin_bone_indices.ptrw();
@@ -387,6 +387,7 @@ void Skeleton3D::_notification(int p_what) {
void Skeleton3D::clear_bones_global_pose_override() {
for (int i = 0; i < bones.size(); i += 1) {
bones.write[i].global_pose_override_amount = 0;
+ bones.write[i].global_pose_override_reset = true;
}
_make_dirty();
}
@@ -439,6 +440,17 @@ String Skeleton3D::get_bone_name(int p_bone) const {
return bones[p_bone].name;
}
+void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ for (int i = 0; i < bones.size(); i++) {
+ if (i != p_bone) {
+ ERR_FAIL_COND(bones[i].name == p_name);
+ }
+ }
+
+ bones.write[p_bone].name = p_name;
+}
bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
int parent_of_bone = get_bone_parent(p_bone);
@@ -869,6 +881,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone);
ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone);
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton3D::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "name"), &Skeleton3D::set_bone_name);
ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &Skeleton3D::get_bone_parent);
ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent);
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 9772bfcc95..2941ac2c45 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -143,6 +143,7 @@ public:
void add_bone(const String &p_name);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
+ void set_bone_name(int p_bone, const String &p_name);
bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index cb486a12ae..898f94ccc1 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -63,7 +63,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
chain.chain_root.bone = p_task->root_bone;
chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(chain.chain_root.bone);
chain.chain_root.current_pos = chain.chain_root.initial_transform.origin;
- chain.chain_root.pb = p_task->skeleton->get_physical_bone(chain.chain_root.bone);
chain.middle_chain_item = nullptr;
// Holds all IDs that are composing a single chain in reverse order
@@ -96,8 +95,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
if (!child_ci) {
child_ci = sub_chain->add_child(chain_ids[i]);
- child_ci->pb = p_task->skeleton->get_physical_bone(child_ci->bone);
-
child_ci->initial_transform = p_task->skeleton->get_bone_global_pose(child_ci->bone);
child_ci->current_pos = child_ci->initial_transform.origin;
@@ -123,7 +120,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
if (p_force_simple_chain) {
// NOTE:
- // This is an "hack" that force to create only one tip per chain since the solver of multi tip (end effector)
+ // This is a "hack" that force to create only one tip per chain since the solver of multi tip (end effector)
// is not yet created.
// Remove this code when this is done
break;
@@ -132,20 +129,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
return true;
}
-void FabrikInverseKinematic::update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item) {
- if (!p_chain_item) {
- return;
- }
-
- p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
- p_chain_item->current_pos = p_chain_item->initial_transform.origin;
-
- ChainItem *items = p_chain_item->children.ptrw();
- for (int i = 0; i < p_chain_item->children.size(); i += 1) {
- update_chain(p_sk, items + i);
- }
-}
-
void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
real_t distance_to_goal(1e4);
real_t previous_distance_to_goal(0);
@@ -263,7 +246,7 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_
p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform;
} else {
// End effector in local transform
- const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors.write[0].tip_bone));
+ const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors[0].tip_bone));
// Update the end_effector (local transform) by blending with current pose
p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta);
@@ -272,6 +255,18 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_
void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) {
if (blending_delta <= 0.01f) {
+ // Before skipping, make sure we undo the global pose overrides
+ ChainItem *ci(&p_task->chain.chain_root);
+ while (ci) {
+ p_task->skeleton->set_bone_global_pose_override(ci->bone, ci->initial_transform, 0.0, false);
+
+ if (!ci->children.is_empty()) {
+ ci = &ci->children.write[0];
+ } else {
+ ci = nullptr;
+ }
+ }
+
return; // Skip solving
}
@@ -285,9 +280,11 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
p_task->skeleton->set_bone_global_pose_override(p_task->chain.tips[i].chain_item->bone, Transform(), 0.0, true);
}
- make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse().scaled(p_task->skeleton->get_global_transform().get_basis().get_scale()), blending_delta);
+ // Update the transforms to their global poses
+ // (Needed to sync IK with animation)
+ _update_chain(p_task->skeleton, &p_task->chain.chain_root);
- update_chain(p_task->skeleton, &p_task->chain.chain_root);
+ make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta);
if (p_use_magnet && p_task->chain.middle_chain_item) {
p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta);
@@ -301,24 +298,55 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
Transform new_bone_pose(ci->initial_transform);
new_bone_pose.origin = ci->current_pos;
- if (!ci->children.is_empty()) {
- /// Rotate basis
- const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
- const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
-
- if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
- const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
- new_bone_pose.basis.rotate(rot_axis, rot_angle);
+ // The root bone needs to be rotated differently so it isn't frozen in place.
+ if (ci == &p_task->chain.chain_root && !ci->children.is_empty()) {
+ new_bone_pose = new_bone_pose.looking_at(ci->children[0].current_pos);
+ const Vector3 bone_rest_dir = p_task->skeleton->get_bone_rest(ci->children[0].bone).origin.normalized().abs();
+ const Vector3 bone_rest_dir_abs = bone_rest_dir.abs();
+ if (bone_rest_dir_abs.x > bone_rest_dir_abs.y && bone_rest_dir_abs.x > bone_rest_dir_abs.z) {
+ if (bone_rest_dir.x < 0) {
+ new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), -Math_PI / 2.0f);
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), Math_PI / 2.0f);
+ }
+ } else if (bone_rest_dir_abs.y > bone_rest_dir_abs.x && bone_rest_dir_abs.y > bone_rest_dir_abs.z) {
+ if (bone_rest_dir.y < 0) {
+ new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), Math_PI / 2.0f);
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), -Math_PI / 2.0f);
+ }
+ } else {
+ if (bone_rest_dir.z < 0) {
+ // Do nothing!
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(0, 0, 1), Math_PI);
+ }
}
} else {
- // Set target orientation to tip
- if (override_tip_basis) {
- new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
+ if (!ci->children.is_empty()) {
+ /// Rotate basis
+ const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
+ const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
+
+ if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
+ const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
+ new_bone_pose.basis.rotate(rot_axis, rot_angle);
+ }
+
} else {
- new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
+ // Set target orientation to tip
+ if (override_tip_basis) {
+ new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
+ } else {
+ new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
+ }
}
}
+ // IK should not affect scale, so undo any scaling
+ new_bone_pose.basis.orthonormalize();
+ new_bone_pose.basis.scale(p_task->skeleton->get_bone_global_pose(ci->bone).basis.get_scale());
+
p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true);
if (!ci->children.is_empty()) {
@@ -329,6 +357,20 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
}
}
+void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item) {
+ if (!p_chain_item) {
+ return;
+ }
+
+ p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
+ p_chain_item->current_pos = p_chain_item->initial_transform.origin;
+
+ ChainItem *items = p_chain_item->children.ptrw();
+ for (int i = 0; i < p_chain_item->children.size(); i += 1) {
+ _update_chain(p_sk, items + i);
+ }
+}
+
void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
if (property.name == "root_bone" || property.name == "tip_bone") {
if (skeleton) {
@@ -524,6 +566,9 @@ void SkeletonIK3D::start(bool p_one_time) {
void SkeletonIK3D::stop() {
set_process_internal(false);
+ if (skeleton) {
+ skeleton->clear_bones_global_pose_override();
+ }
}
Transform SkeletonIK3D::_get_target_transform() {
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index eefecf68bb..9255e18b72 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -52,7 +52,6 @@ class FabrikInverseKinematic {
// Bone info
BoneId bone = -1;
- PhysicalBone3D *pb = nullptr;
real_t length = 0.0;
/// Positions relative to root bone
@@ -107,8 +106,6 @@ private:
/// Init a chain that starts from the root to tip
static bool build_chain(Task *p_task, bool p_force_simple_chain = true);
- static void update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item);
-
static void solve_simple(Task *p_task, bool p_solve_magnet);
/// Special solvers that solve only chains with one end effector
static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet);
@@ -121,6 +118,8 @@ public:
static void set_goal(Task *p_task, const Transform &p_goal);
static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta);
static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position);
+
+ static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item);
};
class SkeletonIK3D : public Node {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 785465f28e..dc4deb0570 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -37,7 +37,6 @@
#include "scene/3d/collision_object_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/skeleton_3d.h"
-#include "servers/physics_server_3d.h"
SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
@@ -48,27 +47,28 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
mesh = p_mesh;
surface = p_surface;
-#ifndef _MSC_VER
-#warning Softbody is not working, needs to be redone considering that these functions no longer exist
-#endif
-#if 0
- const uint32_t surface_format = RS::get_singleton()->mesh_surface_get_format(mesh, surface);
- const int surface_vertex_len = RS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
- const int surface_index_len = RS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
+
+ RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh, surface);
+
uint32_t surface_offsets[RS::ARRAY_MAX];
+ uint32_t vertex_stride;
+ uint32_t attrib_stride;
+ uint32_t skin_stride;
+ RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, attrib_stride, skin_stride);
- buffer = RS::get_singleton()->mesh_surface_get_array(mesh, surface);
- stride = RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets);
+ buffer = surface_data.vertex_data;
+ stride = vertex_stride;
offset_vertices = surface_offsets[RS::ARRAY_VERTEX];
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
-#endif
}
void SoftBodyRenderingServerHandler::clear() {
- if (mesh.is_valid()) {
- buffer.resize(0);
- }
+ buffer.resize(0);
+ stride = 0;
+ offset_vertices = 0;
+ offset_normal = 0;
+ surface = 0;
mesh = RID();
}
@@ -77,7 +77,7 @@ void SoftBodyRenderingServerHandler::open() {
}
void SoftBodyRenderingServerHandler::close() {
- //write_buffer.release();
+ write_buffer = nullptr;
}
void SoftBodyRenderingServerHandler::commit_changes() {
@@ -85,11 +85,11 @@ void SoftBodyRenderingServerHandler::commit_changes() {
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
@@ -245,13 +245,11 @@ bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, V
return true;
}
-void SoftBody3D::_changed_callback(Object *p_changed, const char *p_prop) {
+void SoftBody3D::_softbody_changed() {
prepare_physics_server();
_reset_points_offsets();
#ifdef TOOLS_ENABLED
- if (p_changed == this) {
- update_configuration_warning();
- }
+ update_configuration_warnings();
#endif
}
@@ -259,7 +257,9 @@ void SoftBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
- add_change_receptor(this);
+ // I have no idea what this is supposed to do, it's really weird
+ // leaving for upcoming PK work on physics
+ //add_change_receptor(this);
}
RID space = get_world_3d()->get_space();
@@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -309,6 +309,8 @@ void SoftBody3D::_notification(int p_what) {
}
void SoftBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
+
ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
@@ -337,18 +339,9 @@ void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
- ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody3D::set_areaAngular_stiffness);
- ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody3D::get_areaAngular_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody3D::set_volume_stiffness);
- ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody3D::get_volume_stiffness);
-
ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody3D::set_pose_matching_coefficient);
- ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody3D::get_pose_matching_coefficient);
-
ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
@@ -366,37 +359,26 @@ void SoftBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
-String SoftBody3D::get_configuration_warning() const {
- String warning = MeshInstance3D::get_configuration_warning();
+TypedArray<String> SoftBody3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += TTR("This body will be ignored until you set a mesh.");
+ warnings.push_back(TTR("This body will be ignored until you set a mesh."));
}
Transform t = get_transform();
if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void SoftBody3D::_update_physics_server() {
@@ -470,7 +452,7 @@ void SoftBody3D::become_mesh_owner() {
mesh_owner = true;
Vector<Ref<Material>> copy_materials;
- copy_materials.append_array(materials);
+ copy_materials.append_array(surface_override_materials);
ERR_FAIL_COND(!mesh->get_surface_count());
@@ -490,7 +472,7 @@ void SoftBody3D::become_mesh_owner() {
set_mesh(soft_mesh);
for (int i = copy_materials.size() - 1; 0 <= i; --i) {
- set_surface_material(i, copy_materials[i]);
+ set_surface_override_material(i, copy_materials[i]);
}
}
}
@@ -514,6 +496,7 @@ uint32_t SoftBody3D::get_collision_layer() const {
}
void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -524,10 +507,12 @@ void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t layer = get_collision_layer();
if (p_value) {
layer |= 1 << p_bit;
@@ -538,6 +523,7 @@ void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
@@ -612,34 +598,10 @@ real_t SoftBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
-void SoftBody3D::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) {
- PhysicsServer3D::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness);
-}
-
-real_t SoftBody3D::get_areaAngular_stiffness() {
- return PhysicsServer3D::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid);
-}
-
-void SoftBody3D::set_volume_stiffness(real_t p_volume_stiffness) {
- PhysicsServer3D::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
-}
-
-real_t SoftBody3D::get_volume_stiffness() {
- return PhysicsServer3D::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
-}
-
real_t SoftBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
-void SoftBody3D::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
- PhysicsServer3D::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
-}
-
-real_t SoftBody3D::get_pose_matching_coefficient() {
- return PhysicsServer3D::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
-}
-
void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
@@ -768,7 +730,9 @@ void SoftBody3D::_reset_points_offsets() {
PinnedPoint *w = pinned_points.ptrw();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!r[i].spatial_attachment) {
- w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path));
+ if (!r[i].spatial_attachment_path.is_empty() && has_node(r[i].spatial_attachment_path)) {
+ w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path));
+ }
}
if (!r[i].spatial_attachment) {
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 288deb0673..0d0d39d48f 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -32,10 +32,11 @@
#define SOFT_PHYSICS_BODY_H
#include "scene/3d/mesh_instance_3d.h"
+#include "servers/physics_server_3d.h"
class SoftBody3D;
-class SoftBodyRenderingServerHandler {
+class SoftBodyRenderingServerHandler : public RenderingServerHandler {
friend class SoftBody3D;
RID mesh;
@@ -57,9 +58,9 @@ private:
void commit_changes();
public:
- void set_vertex(int p_vertex_id, const void *p_vector3);
- void set_normal(int p_vertex_id, const void *p_vector3);
- void set_aabb(const AABB &p_aabb);
+ void set_vertex(int p_vertex_id, const void *p_vector3) override;
+ void set_normal(int p_vertex_id, const void *p_vector3) override;
+ void set_aabb(const AABB &p_aabb) override;
};
class SoftBody3D : public MeshInstance3D {
@@ -98,6 +99,8 @@ private:
void _update_pickable();
+ void _softbody_changed();
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -107,12 +110,10 @@ protected:
bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value);
bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const;
- virtual void _changed_callback(Object *p_changed, const char *p_prop) override;
-
void _notification(int p_what);
static void _bind_methods();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
protected:
void _update_physics_server();
@@ -122,6 +123,8 @@ public:
void prepare_physics_server();
void become_mesh_owner();
+ RID get_physics_rid() const { return physics_rid; }
+
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
@@ -149,18 +152,9 @@ public:
void set_linear_stiffness(real_t p_linear_stiffness);
real_t get_linear_stiffness();
- void set_areaAngular_stiffness(real_t p_areaAngular_stiffness);
- real_t get_areaAngular_stiffness();
-
- void set_volume_stiffness(real_t p_volume_stiffness);
- real_t get_volume_stiffness();
-
void set_pressure_coefficient(real_t p_pressure_coefficient);
real_t get_pressure_coefficient();
- void set_pose_matching_coefficient(real_t p_pose_matching_coefficient);
- real_t get_pose_matching_coefficient();
-
void set_damping_coefficient(real_t p_damping_coefficient);
real_t get_damping_coefficient();
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index f178daad42..33b8b488c6 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -366,7 +366,7 @@ void Sprite3D::_draw() {
}
Rect2 base_rect;
- if (region) {
+ if (region_enabled) {
base_rect = region_rect;
} else {
base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
@@ -511,23 +511,24 @@ Ref<Texture2D> Sprite3D::get_texture() const {
return texture;
}
-void Sprite3D::set_region(bool p_region) {
- if (p_region == region) {
+void Sprite3D::set_region_enabled(bool p_region_enabled) {
+ if (p_region_enabled == region_enabled) {
return;
}
- region = p_region;
+ region_enabled = p_region_enabled;
_queue_update();
+ notify_property_list_changed();
}
-bool Sprite3D::is_region() const {
- return region;
+bool Sprite3D::is_region_enabled() const {
+ return region_enabled;
}
void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
bool changed = region_rect != p_region_rect;
region_rect = p_region_rect;
- if (region && changed) {
+ if (region_enabled && changed) {
_queue_update();
}
}
@@ -543,8 +544,6 @@ void Sprite3D::set_frame(int p_frame) {
_queue_update();
- _change_notify("frame");
- _change_notify("frame_coords");
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -567,7 +566,7 @@ void Sprite3D::set_vframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
vframes = p_amount;
_queue_update();
- _change_notify();
+ notify_property_list_changed();
}
int Sprite3D::get_vframes() const {
@@ -578,7 +577,7 @@ void Sprite3D::set_hframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
hframes = p_amount;
_queue_update();
- _change_notify();
+ notify_property_list_changed();
}
int Sprite3D::get_hframes() const {
@@ -596,7 +595,7 @@ Rect2 Sprite3D::get_item_rect() const {
Size2i s;
- if (region) {
+ if (region_enabled) {
s = region_rect.size;
} else {
s = texture->get_size();
@@ -625,14 +624,18 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
if (property.name == "frame_coords") {
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (!region_enabled && property.name == "region_rect") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
}
void Sprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite3D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &Sprite3D::get_texture);
- ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite3D::set_region);
- ClassDB::bind_method(D_METHOD("is_region"), &Sprite3D::is_region);
+ ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite3D::set_region_enabled);
+ ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite3D::is_region_enabled);
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite3D::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite3D::get_region_rect);
@@ -656,14 +659,14 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_SIGNAL(MethodInfo("frame_changed"));
}
Sprite3D::Sprite3D() {
- region = false;
+ region_enabled = false;
frame = 0;
vframes = 1;
hframes = 1;
@@ -689,7 +692,7 @@ void AnimatedSprite3D::_draw() {
Ref<Texture2D> texture = frames->get_frame(animation, frame);
if (!texture.is_valid()) {
- return; //no texuture no life
+ return; //no texture no life
}
Vector2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0) {
@@ -890,12 +893,13 @@ void AnimatedSprite3D::_notification(int p_what) {
} else {
frame = fc - 1;
}
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
} else {
frame++;
}
_queue_update();
- _change_notify("frame");
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
float to_process = MIN(timeout, remaining);
@@ -921,10 +925,10 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
set_frame(frame);
}
- _change_notify();
+ notify_property_list_changed();
_reset_timeout();
_queue_update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
@@ -954,7 +958,7 @@ void AnimatedSprite3D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
_queue_update();
- _change_notify("frame");
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -990,8 +994,6 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
void AnimatedSprite3D::_res_changed() {
set_frame(frame);
- _change_notify("frame");
- _change_notify("animation");
_queue_update();
}
@@ -1048,7 +1050,7 @@ void AnimatedSprite3D::set_animation(const StringName &p_animation) {
animation = p_animation;
_reset_timeout();
set_frame(0);
- _change_notify();
+ notify_property_list_changed();
_queue_update();
}
@@ -1056,17 +1058,14 @@ StringName AnimatedSprite3D::get_animation() const {
return animation;
}
-String AnimatedSprite3D::get_configuration_warning() const {
- String warning = SpriteBase3D::get_configuration_warning();
+TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+ warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
- return warning;
+ return warnings;
}
void AnimatedSprite3D::_bind_methods() {
@@ -1087,6 +1086,7 @@ void AnimatedSprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
ADD_SIGNAL(MethodInfo("frame_changed"));
+ ADD_SIGNAL(MethodInfo("animation_finished"));
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index a9ce2d8eee..5e47e66bcb 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -31,8 +31,8 @@
#ifndef SPRITE_3D_H
#define SPRITE_3D_H
-#include "scene/2d/animated_sprite_2d.h"
#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/sprite_frames.h"
class SpriteBase3D : public GeometryInstance3D {
GDCLASS(SpriteBase3D, GeometryInstance3D);
@@ -107,8 +107,8 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_region_enabled);
+ bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
@@ -147,7 +147,7 @@ class Sprite3D : public SpriteBase3D {
GDCLASS(Sprite3D, SpriteBase3D);
Ref<Texture2D> texture;
- bool region;
+ bool region_enabled;
Rect2 region_rect;
int frame;
@@ -167,8 +167,8 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- void set_region(bool p_region);
- bool is_region() const;
+ void set_region_enabled(bool p_region_enabled);
+ bool is_region_enabled() const;
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
@@ -203,8 +203,8 @@ class AnimatedSprite3D : public SpriteBase3D {
float timeout = 0.0;
- bool hflip = 1;
- bool vflip = 1;
+ bool hflip = true;
+ bool vflip = true;
Color modulate;
@@ -236,7 +236,7 @@ public:
virtual Rect2 get_item_rect() const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite3D();
};
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 0d25e2f21f..9493f686c4 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -102,17 +102,14 @@ void VehicleWheel3D::_notification(int p_what) {
}
}
-String VehicleWheel3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> VehicleWheel3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+ warnings.push_back(TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));
}
- return warning;
+ return warnings;
}
void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
@@ -407,7 +404,7 @@ real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) {
PhysicsDirectSpaceState3D *ss = s->get_space_state();
- bool col = ss->intersect_ray(source, target, rr, exclude);
+ bool col = ss->intersect_ray(source, target, rr, exclude, get_collision_mask());
wheel.m_raycastInfo.m_groundObject = nullptr;
@@ -563,7 +560,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const
b2invmass);
// FIXME: rel_vel assignment here is overwritten by the following assignment.
- // What seems to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel);
+ // What seems to be intended in the next assignment is: rel_vel = normal.dot(rel_vel);
// Investigate why.
real_t rel_vel = jac.getRelativeVelocity(
s->get_linear_velocity(),
@@ -806,6 +803,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
RigidBody3D::_direct_state_changed(p_state);
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
real_t step = state->get_step();
@@ -925,7 +923,7 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &VehicleBody3D::_direct_state_changed));
set_mass(40);
}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 3c35c0ce97..646071a363 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -87,7 +87,7 @@ class VehicleWheel3D : public Node3D {
Vector3 m_wheelDirectionWS; //direction in worldspace
Vector3 m_wheelAxleWS; // axle in worldspace
bool m_isInContact = false;
- PhysicsBody3D *m_groundObject; //could be general void* ptr
+ PhysicsBody3D *m_groundObject = nullptr; //could be general void* ptr
} m_raycastInfo;
void _update(PhysicsDirectBodyState3D *s);
@@ -145,7 +145,7 @@ public:
void set_steering(real_t p_steering);
real_t get_steering() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
VehicleWheel3D();
};
diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp
index 68a275684b..471838b9d1 100644
--- a/scene/3d/visibility_notifier_3d.cpp
+++ b/scene/3d/visibility_notifier_3d.cpp
@@ -69,7 +69,6 @@ void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb));
}
- _change_notify("aabb");
update_gizmo();
}
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 61591cfd10..d81b09b86c 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -43,7 +43,6 @@ void VisualInstance3D::_update_visibility() {
return;
}
- _change_notify("visible");
RS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree());
}
@@ -339,6 +338,15 @@ GeometryInstance3D::GIMode GeometryInstance3D::get_gi_mode() const {
return gi_mode;
}
+void GeometryInstance3D::set_ignore_occlusion_culling(bool p_enabled) {
+ ignore_occlusion_culling = p_enabled;
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, ignore_occlusion_culling);
+}
+
+bool GeometryInstance3D::is_ignoring_occlusion_culling() {
+ return ignore_occlusion_culling;
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
@@ -346,21 +354,24 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance3D::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance3D::get_cast_shadows_setting);
+ ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
+ ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+
ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance3D::set_lod_max_hysteresis);
ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance3D::get_lod_max_hysteresis);
ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance3D::set_lod_max_distance);
ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance3D::get_lod_max_distance);
- ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
-
ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance3D::set_lod_min_hysteresis);
ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance3D::get_lod_min_hysteresis);
ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance);
ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance);
+ ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
@@ -370,8 +381,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
- ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
- ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+ ClassDB::bind_method(D_METHOD("set_ignore_occlusion_culling", "ignore_culling"), &GeometryInstance3D::set_ignore_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_ignoring_occlusion_culling"), &GeometryInstance3D::is_ignoring_occlusion_culling);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
@@ -382,6 +393,7 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 7fed8095ef..68d29ef81e 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -120,6 +120,7 @@ private:
float extra_cull_margin = 0.0;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
GIMode gi_mode = GI_MODE_DISABLED;
+ bool ignore_occlusion_culling = false;
const StringName *_instance_uniform_get_remap(const StringName p_name) const;
@@ -167,6 +168,9 @@ public:
void set_custom_aabb(AABB aabb);
+ void set_ignore_occlusion_culling(bool p_enabled);
+ bool is_ignoring_occlusion_culling();
+
GeometryInstance3D();
};
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 17c8596e8f..1b9ce0201f 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -151,7 +151,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
Vector2 uv;
Vector3 lnormal;
get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
- if (lnormal == Vector3()) { //just in case normal as nor provided
+ if (lnormal == Vector3()) { //just in case normal is not provided
lnormal = normal;
}
@@ -183,7 +183,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
Vector3 lnormal;
Vector2 uv;
get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
- if (lnormal == Vector3()) { //just in case normal as nor provided
+ if (lnormal == Vector3()) { //just in case normal is not provided
lnormal = normal;
}
@@ -344,7 +344,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
Ref<Image> img_albedo;
if (albedo_tex.is_valid()) {
- img_albedo = albedo_tex->get_data();
+ img_albedo = albedo_tex->get_image();
mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative
} else {
mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
@@ -358,7 +358,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
Ref<Image> img_emission;
if (emission_tex.is_valid()) {
- img_emission = emission_tex->get_data();
+ img_emission = emission_tex->get_image();
}
if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index cf1c319acc..829ecc5ec2 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -35,51 +35,69 @@
void WorldEnvironment::_notification(int p_what) {
if (p_what == Node3D::NOTIFICATION_ENTER_WORLD || p_what == Node3D::NOTIFICATION_ENTER_TREE) {
if (environment.is_valid()) {
- if (get_viewport()->find_world_3d()->get_environment().is_valid()) {
- WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding.");
- }
- get_viewport()->find_world_3d()->set_environment(environment);
add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_environment();
}
if (camera_effects.is_valid()) {
- if (get_viewport()->find_world_3d()->get_camera_effects().is_valid()) {
- WARN_PRINT("World already has a camera effects (Another WorldEnvironment?), overriding.");
- }
- get_viewport()->find_world_3d()->set_camera_effects(camera_effects);
add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_camera_effects();
}
} else if (p_what == Node3D::NOTIFICATION_EXIT_WORLD || p_what == Node3D::NOTIFICATION_EXIT_TREE) {
- if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() == environment) {
- get_viewport()->find_world_3d()->set_environment(Ref<Environment>());
+ if (environment.is_valid()) {
remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_environment();
}
- if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) {
- get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
+ if (camera_effects.is_valid()) {
remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
+ _update_current_camera_effects();
}
}
}
-void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
- if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world_3d()->get_environment() == environment) {
+void WorldEnvironment::_update_current_environment() {
+ WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())));
+
+ if (first) {
+ get_viewport()->find_world_3d()->set_environment(first->environment);
+ } else {
get_viewport()->find_world_3d()->set_environment(Ref<Environment>());
+ }
+ get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
+}
+
+void WorldEnvironment::_update_current_camera_effects() {
+ WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())));
+ if (first) {
+ get_viewport()->find_world_3d()->set_camera_effects(first->camera_effects);
+ } else {
+ get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
+ }
+
+ get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
+}
+
+void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
+ if (environment == p_environment) {
+ return;
+ }
+ if (is_inside_tree() && environment.is_valid()) {
remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
- //clean up
}
environment = p_environment;
+
if (is_inside_tree() && environment.is_valid()) {
- if (get_viewport()->find_world_3d()->get_environment().is_valid()) {
- WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding.");
- }
- get_viewport()->find_world_3d()->set_environment(environment);
add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
}
- update_configuration_warning();
+ if (is_inside_tree()) {
+ _update_current_environment();
+ } else {
+ update_configuration_warnings();
+ }
}
Ref<Environment> WorldEnvironment::get_environment() const {
@@ -87,53 +105,50 @@ Ref<Environment> WorldEnvironment::get_environment() const {
}
void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
+ if (camera_effects == p_camera_effects) {
+ return;
+ }
+
if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) {
- get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
- //clean up
}
camera_effects = p_camera_effects;
if (is_inside_tree() && camera_effects.is_valid()) {
- if (get_viewport()->find_world_3d()->get_camera_effects().is_valid()) {
- WARN_PRINT("World already has an camera_effects (Another WorldEnvironment?), overriding.");
- }
- get_viewport()->find_world_3d()->set_camera_effects(camera_effects);
add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()));
}
- update_configuration_warning();
+ if (is_inside_tree()) {
+ _update_current_camera_effects();
+ } else {
+ update_configuration_warnings();
+ }
}
Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
return camera_effects;
}
-String WorldEnvironment::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!environment.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+ warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."));
}
if (!is_inside_tree()) {
- return warning;
+ return warnings;
}
- List<Node *> nodes;
- get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), &nodes);
+ if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) {
+ warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));
+ }
- if (nodes.size() > 1) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
+ if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
+ warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));
}
- return warning;
+ return warnings;
}
void WorldEnvironment::_bind_methods() {
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 3dfba20bf0..9e85982381 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -41,6 +41,9 @@ class WorldEnvironment : public Node {
Ref<Environment> environment;
Ref<CameraEffects> camera_effects;
+ void _update_current_environment();
+ void _update_current_camera_effects();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -52,7 +55,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
WorldEnvironment();
};
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 7fed34c7c6..b5037f9be7 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) {
};
};
-String XRCamera3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
+TypedArray<String> XRCamera3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRCamera3D must have an XROrigin3D node as its parent."));
+ };
}
- String warning = Camera3D::get_configuration_warning();
-
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
- };
-
- return warning;
+ return warnings;
};
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
@@ -190,8 +185,8 @@ void XRController3D::_notification(int p_what) {
ERR_FAIL_NULL(xr_server);
// find the tracker for our controller
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
// this controller is currently turned off
is_active = false;
button_states = 0;
@@ -265,7 +260,7 @@ void XRController3D::set_controller_id(int p_controller_id) {
// We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRController3D::get_controller_id() const {
@@ -277,8 +272,8 @@ String XRController3D::get_controller_name() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, String());
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return String("Not connected");
};
@@ -290,8 +285,8 @@ int XRController3D::get_joystick_id() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
// No tracker? no joystick id... (0 is our first joystick)
return -1;
};
@@ -322,8 +317,8 @@ real_t XRController3D::get_rumble() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return 0.0;
};
@@ -335,8 +330,8 @@ void XRController3D::set_rumble(real_t p_rumble) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (tracker.is_valid()) {
tracker->set_rumble(p_rumble);
};
};
@@ -354,38 +349,30 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, XRPositionalTracker::TRACKER_HAND_UNKNOWN);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
};
return tracker->get_tracker_hand();
};
-String XRController3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XRController3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- // must be child node of XROrigin!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
- };
- if (controller_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (controller_id == 0) {
+ warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));
}
- warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
- };
+ }
- return warning;
+ return warnings;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -404,8 +391,8 @@ void XRAnchor3D::_notification(int p_what) {
ERR_FAIL_NULL(xr_server);
// find the tracker for our anchor
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
+ if (!tracker.is_valid()) {
// this anchor is currently not available
is_active = false;
} else {
@@ -459,7 +446,7 @@ void XRAnchor3D::set_anchor_id(int p_anchor_id) {
// We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRAnchor3D::get_anchor_id() const {
@@ -475,8 +462,8 @@ String XRAnchor3D::get_anchor_name() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, String());
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
+ if (!tracker.is_valid()) {
return String("Not connected");
};
@@ -487,30 +474,22 @@ bool XRAnchor3D::get_is_active() const {
return is_active;
};
-String XRAnchor3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
- };
- if (anchor_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (anchor_id == 0) {
+ warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));
}
- warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
- };
+ }
- return warning;
+ return warnings;
};
Plane XRAnchor3D::get_plane() const {
@@ -528,21 +507,16 @@ Ref<Mesh> XRAnchor3D::get_mesh() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
-String XROrigin3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XROrigin3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (tracked_camera == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ if (tracked_camera == nullptr) {
+ warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node."));
}
- warning += TTR("XROrigin3D requires an XRCamera3D child node.");
}
- return warning;
+ return warnings;
};
void XROrigin3D::_bind_methods() {
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 7cd6e2ac57..90079f5fe9 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -50,7 +50,7 @@ protected:
void _notification(int p_what);
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override;
@@ -97,7 +97,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRController3D() {}
~XRController3D() {}
@@ -133,7 +133,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRAnchor3D() {}
~XRAnchor3D() {}
@@ -158,7 +158,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera);
void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index b80ae30f1a..9c4bc107dd 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -437,7 +437,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
Vector2 blend_pos = get_parameter(blend_position);
int closest = get_parameter(this->closest);
float length_internal = get_parameter(this->length_internal);
- float mind = 0; //time of min distance point
+ float mind = 0.0; //time of min distance point
if (blend_mode == BLEND_MODE_INTERPOLATED) {
if (triangles.size() == 0) {
@@ -529,7 +529,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
}
if (new_closest != closest && new_closest != -1) {
- float from = 0;
+ float from = 0.0;
if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) {
//see how much animation remains
from = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, true, 0.0, FILTER_IGNORE, false) - length_internal;
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 4a0e9e99be..79a1dc1ac0 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -34,7 +34,6 @@
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
animation = p_name;
- _change_notify("animation");
}
StringName AnimationNodeAnimation::get_animation() const {
@@ -583,7 +582,6 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
} else if (seek_pos >= 0) {
float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false);
set_parameter(this->seek_pos, -1.0); //reset
- _change_notify("seek_pos");
return ret;
} else {
return blend_input(0, p_time, false, 1.0, FILTER_IGNORE, false);
@@ -702,7 +700,7 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
return 0;
}
- float rem = 0;
+ float rem = 0.0;
if (prev < 0) { // process current animation, check for transition
@@ -1123,6 +1121,13 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeBlendTree::reset_state() {
+ graph_offset = Vector2();
+ nodes.clear();
+ emit_changed();
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendTree::_tree_changed() {
emit_signal("tree_changed");
}
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 4732f43af2..d82658c8c2 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -351,6 +351,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
enum ConnectionError {
CONNECTION_OK,
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 552e6b6f5d..246fff6d57 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -281,7 +281,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
at = cost_map[at].prev;
}
- path.invert();
+ path.reverse();
return true;
}
@@ -317,7 +317,7 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_st
// stopped, invalid state
String node_name = start_request;
start_request = StringName(); //clear start request
- ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing.");
+ ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
}
} else {
if (!_travel(p_state_machine, start_request)) {
@@ -393,7 +393,7 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_st
//find next
StringName next;
- float next_xfade = 0;
+ float next_xfade = 0.0;
AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE;
if (path.size()) {
@@ -914,6 +914,18 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeStateMachine::reset_state() {
+ states.clear();
+ transitions.clear();
+ playback = "playback";
+ start_node = StringName();
+ end_node = StringName();
+ graph_offset = Vector2();
+
+ emit_changed();
+ emit_signal("tree_changed");
+}
+
void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) {
ERR_FAIL_COND(!states.has(p_name));
states[p_name].position = p_position;
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 7abc6388a1..9c1bca63c3 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -171,6 +171,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index c6554462f7..0c1798a876 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -206,7 +206,7 @@ void AnimationPlayer::_notification(int p_what) {
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- if (animation_process_mode == ANIMATION_PROCESS_PHYSICS) {
+ if (process_callback == ANIMATION_PROCESS_PHYSICS) {
break;
}
@@ -215,7 +215,7 @@ void AnimationPlayer::_notification(int p_what) {
}
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (animation_process_mode == ANIMATION_PROCESS_IDLE) {
+ if (process_callback == ANIMATION_PROCESS_IDLE) {
break;
}
@@ -229,13 +229,13 @@ void AnimationPlayer::_notification(int p_what) {
}
}
-void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
+void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_override) {
// Already cached?
if (p_anim->node_cache.size() == p_anim->animation->get_track_count()) {
return;
}
- Node *parent = get_node(root);
+ Node *parent = p_root_override ? p_root_override : get_node(root);
ERR_FAIL_COND(!parent);
@@ -605,7 +605,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
}
if (p_seeked) {
- //find whathever should be playing
+ //find whatever should be playing
int idx = a->track_find_key(i, p_time);
if (idx < 0) {
continue;
@@ -634,7 +634,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->audio_playing = true;
playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
nc->audio_len = len - start_ofs - end_ofs;
} else {
nc->audio_len = 0;
@@ -665,7 +665,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->audio_playing = true;
playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
nc->audio_len = len - start_ofs - end_ofs;
} else {
nc->audio_len = 0;
@@ -969,7 +969,7 @@ Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animati
}
_ref_anim(p_animation);
- _change_notify();
+ notify_property_list_changed();
return OK;
}
@@ -981,7 +981,7 @@ void AnimationPlayer::remove_animation(const StringName &p_name) {
animation_set.erase(p_name);
clear_caches();
- _change_notify();
+ notify_property_list_changed();
}
void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) {
@@ -1039,7 +1039,7 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam
}
clear_caches();
- _change_notify();
+ notify_property_list_changed();
}
bool AnimationPlayer::has_animation(const StringName &p_name) const {
@@ -1132,7 +1132,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float
Playback &c = playback;
if (c.current.from) {
- float blend_time = 0;
+ float blend_time = 0.0;
// find if it can blend
BlendKey bk;
bk.from = c.current.from->name;
@@ -1343,7 +1343,7 @@ void AnimationPlayer::_stop_playing_caches() {
}
void AnimationPlayer::_node_removed(Node *p_node) {
- clear_caches(); // nodes contained here ar being removed, clear the caches
+ clear_caches(); // nodes contained here are being removed, clear the caches
}
void AnimationPlayer::clear_caches() {
@@ -1403,8 +1403,8 @@ bool AnimationPlayer::is_reset_on_save_enabled() const {
return reset_on_save;
}
-void AnimationPlayer::set_animation_process_mode(AnimationProcessMode p_mode) {
- if (animation_process_mode == p_mode) {
+void AnimationPlayer::set_process_callback(AnimationProcessCallback p_mode) {
+ if (process_callback == p_mode) {
return;
}
@@ -1412,14 +1412,14 @@ void AnimationPlayer::set_animation_process_mode(AnimationProcessMode p_mode) {
if (pr) {
_set_process(false);
}
- animation_process_mode = p_mode;
+ process_callback = p_mode;
if (pr) {
_set_process(true);
}
}
-AnimationPlayer::AnimationProcessMode AnimationPlayer::get_animation_process_mode() const {
- return animation_process_mode;
+AnimationPlayer::AnimationProcessCallback AnimationPlayer::get_process_callback() const {
+ return process_callback;
}
void AnimationPlayer::set_method_call_mode(AnimationMethodCallMode p_mode) {
@@ -1435,7 +1435,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
return;
}
- switch (animation_process_mode) {
+ switch (process_callback) {
case ANIMATION_PROCESS_PHYSICS:
set_physics_process_internal(p_process && active);
break;
@@ -1497,13 +1497,13 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i
}
#ifdef TOOLS_ENABLED
-Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values() {
+Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_override) {
Ref<AnimatedValuesBackup> backup;
if (!playback.current.from) {
return backup;
}
- _ensure_node_caches(playback.current.from);
+ _ensure_node_caches(playback.current.from, p_root_override);
backup.instance();
for (int i = 0; i < playback.current.from->node_cache.size(); i++) {
@@ -1560,10 +1560,11 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
AnimationPlayer *aux_player = memnew(AnimationPlayer);
EditorNode::get_singleton()->add_child(aux_player);
- aux_player->set_root(aux_player->get_path_to(root_node));
aux_player->add_animation("RESET", reset_anim);
aux_player->set_assigned_animation("RESET");
- Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values();
+ // Forcing the use of the original root because the scene where original player belongs may be not the active one
+ Node *root = get_node(get_root());
+ Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(root);
aux_player->seek(0.0f, true);
aux_player->queue_delete();
@@ -1636,8 +1637,8 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches);
- ClassDB::bind_method(D_METHOD("set_animation_process_mode", "mode"), &AnimationPlayer::set_animation_process_mode);
- ClassDB::bind_method(D_METHOD("get_animation_process_mode"), &AnimationPlayer::get_animation_process_mode);
+ ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &AnimationPlayer::set_process_callback);
+ ClassDB::bind_method(D_METHOD("get_process_callback"), &AnimationPlayer::get_process_callback);
ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
@@ -1657,7 +1658,7 @@ void AnimationPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position");
ADD_GROUP("Playback Options", "playback_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_animation_process_mode", "get_animation_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index c04eeeca68..2a1821c215 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -64,7 +64,7 @@ class AnimationPlayer : public Node {
OBJ_CATEGORY("Animation Nodes");
public:
- enum AnimationProcessMode {
+ enum AnimationProcessCallback {
ANIMATION_PROCESS_PHYSICS,
ANIMATION_PROCESS_IDLE,
ANIMATION_PROCESS_MANUAL,
@@ -206,7 +206,7 @@ private:
String autoplay;
bool reset_on_save = true;
- AnimationProcessMode animation_process_mode = ANIMATION_PROCESS_IDLE;
+ AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE;
AnimationMethodCallMode method_call_mode = ANIMATION_METHOD_CALL_DEFERRED;
bool processing = false;
bool active = true;
@@ -215,7 +215,7 @@ private:
void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false);
- void _ensure_node_caches(AnimationData *p_anim);
+ void _ensure_node_caches(AnimationData *p_anim, Node *p_root_override = nullptr);
void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started);
void _animation_process2(float p_delta, bool p_started);
void _animation_update_transforms();
@@ -298,8 +298,8 @@ public:
void set_reset_on_save_enabled(bool p_enabled);
bool is_reset_on_save_enabled() const;
- void set_animation_process_mode(AnimationProcessMode p_mode);
- AnimationProcessMode get_animation_process_mode() const;
+ void set_process_callback(AnimationProcessCallback p_mode);
+ AnimationProcessCallback get_process_callback() const;
void set_method_call_mode(AnimationMethodCallMode p_mode);
AnimationMethodCallMode get_method_call_mode() const;
@@ -319,7 +319,7 @@ public:
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
#ifdef TOOLS_ENABLED
- Ref<AnimatedValuesBackup> backup_animated_values();
+ Ref<AnimatedValuesBackup> backup_animated_values(Node *p_root_override = nullptr);
Ref<AnimatedValuesBackup> apply_reset(bool p_user_initiated = false);
bool can_apply_reset() const;
#endif
@@ -328,7 +328,7 @@ public:
~AnimationPlayer();
};
-VARIANT_ENUM_CAST(AnimationPlayer::AnimationProcessMode);
+VARIANT_ENUM_CAST(AnimationPlayer::AnimationProcessCallback);
VARIANT_ENUM_CAST(AnimationPlayer::AnimationMethodCallMode);
#endif
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 0f0cdc67f4..44f2d38a84 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -158,7 +158,7 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p
Ref<AnimationNode> node = blend_tree->get_node(node_name);
//inputs.write[p_input].last_pass = state->last_pass;
- float activity = 0;
+ float activity = 0.0;
float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
@@ -458,7 +458,7 @@ void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
properties_dirty = true;
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<AnimationNode> AnimationTree::get_tree_root() const {
@@ -473,7 +473,7 @@ void AnimationTree::set_active(bool p_active) {
active = p_active;
started = active;
- if (process_mode == ANIMATION_PROCESS_IDLE) {
+ if (process_callback == ANIMATION_PROCESS_IDLE) {
set_process_internal(active);
} else {
set_physics_process_internal(active);
@@ -494,8 +494,8 @@ bool AnimationTree::is_active() const {
return active;
}
-void AnimationTree::set_process_mode(AnimationProcessMode p_mode) {
- if (process_mode == p_mode) {
+void AnimationTree::set_process_callback(AnimationProcessCallback p_mode) {
+ if (process_callback == p_mode) {
return;
}
@@ -504,15 +504,15 @@ void AnimationTree::set_process_mode(AnimationProcessMode p_mode) {
set_active(false);
}
- process_mode = p_mode;
+ process_callback = p_mode;
if (was_active) {
set_active(true);
}
}
-AnimationTree::AnimationProcessMode AnimationTree::get_process_mode() const {
- return process_mode;
+AnimationTree::AnimationProcessCallback AnimationTree::get_process_callback() const {
+ return process_callback;
}
void AnimationTree::_node_removed(Node *p_node) {
@@ -1009,7 +1009,7 @@ void AnimationTree::_process_graph(float p_delta) {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
if (seeked) {
- //find whathever should be playing
+ //find whatever should be playing
int idx = a->track_find_key(i, time);
if (idx < 0) {
continue;
@@ -1038,7 +1038,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->playing = true;
playing_caches.insert(t);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
t->len = len - start_ofs - end_ofs;
} else {
t->len = 0;
@@ -1069,7 +1069,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->playing = true;
playing_caches.insert(t);
- if (len && end_ofs > 0) { //force a end at a time
+ if (len && end_ofs > 0) { //force an end at a time
t->len = len - start_ofs - end_ofs;
} else {
t->len = 0;
@@ -1234,11 +1234,11 @@ void AnimationTree::advance(float p_time) {
}
void AnimationTree::_notification(int p_what) {
- if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) {
+ if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_callback == ANIMATION_PROCESS_PHYSICS) {
_process_graph(get_physics_process_delta_time());
}
- if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_mode == ANIMATION_PROCESS_IDLE) {
+ if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_callback == ANIMATION_PROCESS_IDLE) {
_process_graph(get_process_delta_time());
}
@@ -1262,7 +1262,7 @@ void AnimationTree::_notification(int p_what) {
void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player;
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath AnimationTree::get_animation_player() const {
@@ -1281,38 +1281,26 @@ uint64_t AnimationTree::get_last_process_pass() const {
return process_pass;
}
-String AnimationTree::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> AnimationTree::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!root.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("No root AnimationNode for the graph is set.");
+ warnings.push_back(TTR("No root AnimationNode for the graph is set."));
}
if (!has_node(animation_player)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path to an AnimationPlayer node containing animations is not set.");
+ warnings.push_back(TTR("Path to an AnimationPlayer node containing animations is not set."));
} else {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
if (!player) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node.");
+ warnings.push_back(TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."));
} else if (!player->has_node(player->get_root())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The AnimationPlayer root node is not a valid node.");
+ warnings.push_back(TTR("The AnimationPlayer root node is not a valid node."));
}
}
- return warning;
+ return warnings;
}
void AnimationTree::set_root_motion_track(const NodePath &p_track) {
@@ -1337,6 +1325,7 @@ void AnimationTree::_tree_changed() {
}
void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) {
+ ERR_FAIL_COND(node.is_null());
if (!property_parent_map.has(p_base_path)) {
property_parent_map[p_base_path] = HashMap<StringName, StringName>();
}
@@ -1394,7 +1383,7 @@ void AnimationTree::_update_properties() {
properties_dirty = false;
- _change_notify();
+ notify_property_list_changed();
}
bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
@@ -1404,9 +1393,6 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
if (property_map.has(p_name)) {
property_map[p_name] = p_value;
-#ifdef TOOLS_ENABLED
- _change_notify(p_name.operator String().utf8().get_data());
-#endif
return true;
}
@@ -1474,8 +1460,8 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tree_root", "root"), &AnimationTree::set_tree_root);
ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_tree_root);
- ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationTree::set_process_mode);
- ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationTree::get_process_mode);
+ ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &AnimationTree::set_process_callback);
+ ClassDB::bind_method(D_METHOD("get_process_callback"), &AnimationTree::get_process_callback);
ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationTree::set_animation_player);
ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player);
@@ -1494,7 +1480,7 @@ void AnimationTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback");
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 0f78b1f0e2..700ff1cb5b 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -163,7 +163,7 @@ class AnimationTree : public Node {
GDCLASS(AnimationTree, Node);
public:
- enum AnimationProcessMode {
+ enum AnimationProcessCallback {
ANIMATION_PROCESS_PHYSICS,
ANIMATION_PROCESS_IDLE,
ANIMATION_PROCESS_MANUAL,
@@ -238,7 +238,7 @@ private:
Ref<AnimationNode> root;
- AnimationProcessMode process_mode = ANIMATION_PROCESS_IDLE;
+ AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE;
bool active = false;
NodePath animation_player;
@@ -294,13 +294,13 @@ public:
void set_active(bool p_active);
bool is_active() const;
- void set_process_mode(AnimationProcessMode p_mode);
- AnimationProcessMode get_process_mode() const;
+ void set_process_callback(AnimationProcessCallback p_mode);
+ AnimationProcessCallback get_process_callback() const;
void set_animation_player(const NodePath &p_player);
NodePath get_animation_player() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
bool is_state_invalid() const;
String get_invalid_state_reason() const;
@@ -320,6 +320,6 @@ public:
~AnimationTree();
};
-VARIANT_ENUM_CAST(AnimationTree::AnimationProcessMode)
+VARIANT_ENUM_CAST(AnimationTree::AnimationProcessCallback)
#endif // ANIMATION_GRAPH_PLAYER_H
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index a4a1b02a4c..9ee1f32581 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -89,12 +89,12 @@ void RootMotionView::_notification(int p_what) {
AnimationTree *tree = Object::cast_to<AnimationTree>(node);
if (tree && tree->is_active() && tree->get_root_motion_track() != NodePath()) {
- if (is_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_PHYSICS) {
+ if (is_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_PHYSICS) {
set_process_internal(false);
set_physics_process_internal(true);
}
- if (is_physics_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_IDLE) {
+ if (is_physics_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_IDLE) {
set_process_internal(true);
set_physics_process_internal(false);
}
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 354f7e5aae..2030808724 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -869,8 +869,21 @@ void Tween::start() {
return;
}
+ pending_update++;
+ for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
+ InterpolateData &data = E->get();
+ data.active = true;
+ }
+ pending_update--;
+
// We want to be activated
set_active(true);
+
+ // Don't resume from current position if stop_all() function has been used
+ if (was_stopped) {
+ seek(0);
+ }
+ was_stopped = false;
}
void Tween::reset(Object *p_object, StringName p_key) {
@@ -939,7 +952,7 @@ void Tween::stop(Object *p_object, StringName p_key) {
void Tween::stop_all() {
// We no longer need to be active since all tweens have been stopped
set_active(false);
-
+ was_stopped = true;
// For each interpolation...
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -1098,11 +1111,11 @@ void Tween::seek(real_t p_time) {
real_t Tween::tell() const {
// We want to grab the position of the furthest along tween
pending_update++;
- real_t pos = 0;
+ real_t pos = 0.0;
// For each interpolation...
for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
- // Get the data and figure out if it's position is further along than the previous ones
+ // Get the data and figure out if its position is further along than the previous ones
const InterpolateData &data = E->get();
if (data.elapsed > pos) {
// Save it if so
@@ -1122,7 +1135,7 @@ real_t Tween::get_runtime() const {
pending_update++;
// For each interpolation...
- real_t runtime = 0;
+ real_t runtime = 0.0;
for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
// Get the tween data and see if it's runtime is greater than the previous tweens
const InterpolateData &data = E->get();
@@ -1350,6 +1363,9 @@ void Tween::interpolate_property(Object *p_object, NodePath p_property, Variant
return;
}
+ // Check that the target object is valid
+ ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name()));
+
// Get the property from the node path
p_property = p_property.get_as_property_path();
@@ -1378,6 +1394,9 @@ void Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_
return;
}
+ // Check that the target object is valid
+ ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name()));
+
// Convert any integers into REALs as they are better for interpolation
if (p_initial_val.get_type() == Variant::INT) {
p_initial_val = p_initial_val.operator real_t();
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 88c02be0bc..142c0c65e0 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -107,6 +107,7 @@ private:
float speed_scale = 1.0;
mutable int pending_update = 0;
int uid = 0;
+ bool was_stopped = false;
List<InterpolateData> interpolates;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 70d00734f4..1478cbf69e 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -99,37 +99,37 @@ void AudioStreamPlayer::_mix_audio() {
use_fadeout = false;
}
- if (!stream_playback.is_valid() || !active ||
+ if (!stream_playback.is_valid() || !active.is_set() ||
(stream_paused && !stream_paused_fade)) {
return;
}
if (stream_paused) {
- if (stream_paused_fade) {
+ if (stream_paused_fade && stream_playback->is_playing()) {
_mix_internal(true);
stream_paused_fade = false;
}
return;
}
- if (setstop) {
+ if (setstop.is_set()) {
_mix_internal(true);
stream_playback->stop();
- setstop = false;
+ setstop.clear();
}
- if (setseek >= 0.0 && !stop_has_priority) {
+ if (setseek.get() >= 0.0 && !stop_has_priority.is_set()) {
if (stream_playback->is_playing()) {
//fade out to avoid pops
_mix_internal(true);
}
- stream_playback->start(setseek);
- setseek = -1.0; //reset seek
+ stream_playback->start(setseek.get());
+ setseek.set(-1.0); //reset seek
mix_volume_db = volume_db; //reset ramp
}
- stop_has_priority = false;
+ stop_has_priority.clear();
_mix_internal(false);
}
@@ -143,8 +143,8 @@ void AudioStreamPlayer::_notification(int p_what) {
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (!active || (setseek < 0 && !stream_playback->is_playing())) {
- active = false;
+ if (!active.is_set() || (setseek.get() < 0 && !stream_playback->is_playing())) {
+ active.clear();
set_process_internal(false);
emit_signal("finished");
}
@@ -169,9 +169,9 @@ void AudioStreamPlayer::_notification(int p_what) {
void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
AudioServer::get_singleton()->lock();
- if (active && stream_playback.is_valid() && !stream_paused) {
+ if (active.is_set() && stream_playback.is_valid() && !stream_paused) {
//changing streams out of the blue is not a great idea, but at least
- //lets try to somehow avoid a click
+ //let's try to somehow avoid a click
AudioFrame *buffer = fadeout_buffer.ptrw();
int buffer_size = fadeout_buffer.size();
@@ -196,9 +196,9 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
if (stream_playback.is_valid()) {
stream_playback.unref();
stream.unref();
- active = false;
- setseek = -1;
- setstop = false;
+ active.clear();
+ setseek.set(-1);
+ setstop.clear();
}
if (p_stream.is_valid()) {
@@ -237,29 +237,29 @@ float AudioStreamPlayer::get_pitch_scale() const {
void AudioStreamPlayer::play(float p_from_pos) {
if (stream_playback.is_valid()) {
//mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
- setseek = p_from_pos;
- stop_has_priority = false;
- active = true;
+ setseek.set(p_from_pos);
+ stop_has_priority.clear();
+ active.set();
set_process_internal(true);
}
}
void AudioStreamPlayer::seek(float p_seconds) {
if (stream_playback.is_valid()) {
- setseek = p_seconds;
+ setseek.set(p_seconds);
}
}
void AudioStreamPlayer::stop() {
- if (stream_playback.is_valid() && active) {
- setstop = true;
- stop_has_priority = true;
+ if (stream_playback.is_valid() && active.is_set()) {
+ setstop.set();
+ stop_has_priority.set();
}
}
bool AudioStreamPlayer::is_playing() const {
if (stream_playback.is_valid()) {
- return active && !setstop; //&& stream_playback->is_playing();
+ return active.is_set() && !setstop.is_set(); //&& stream_playback->is_playing();
}
return false;
@@ -267,6 +267,10 @@ bool AudioStreamPlayer::is_playing() const {
float AudioStreamPlayer::get_playback_position() {
if (stream_playback.is_valid()) {
+ float ss = setseek.get();
+ if (ss >= 0.0) {
+ return ss;
+ }
return stream_playback->get_playback_position();
}
@@ -314,7 +318,7 @@ void AudioStreamPlayer::_set_playing(bool p_enable) {
}
bool AudioStreamPlayer::_is_active() const {
- return active;
+ return active.is_set();
}
void AudioStreamPlayer::set_stream_paused(bool p_pause) {
@@ -344,7 +348,7 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
}
void AudioStreamPlayer::_bus_layout_changed() {
- _change_notify();
+ notify_property_list_changed();
}
Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index ab98d41302..aa8d088be5 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -31,6 +31,7 @@
#ifndef AUDIO_STREAM_PLAYER_H
#define AUDIO_STREAM_PLAYER_H
+#include "core/templates/safe_refcount.h"
#include "scene/main/node.h"
#include "servers/audio/audio_stream.h"
@@ -51,10 +52,10 @@ private:
Vector<AudioFrame> fadeout_buffer;
bool use_fadeout = false;
- volatile float setseek = -1.0;
- volatile bool active = false;
- volatile bool setstop = false;
- volatile bool stop_has_priority = false;
+ SafeNumeric<float> setseek{ -1.0 };
+ SafeFlag active;
+ SafeFlag setstop;
+ SafeFlag stop_has_priority;
float mix_volume_db = 0.0;
float pitch_scale = 1.0;
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 4dbe3cc1c4..a1d4adcd41 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -487,7 +487,7 @@ void LiveEditor::_send_tree() {
}
Array arr;
- // Encoded as a flat list depth fist.
+ // Encoded as a flat list depth first.
SceneDebuggerTree tree(scene_tree->root);
tree.serialize(arr);
EngineDebugger::get_singleton()->send_message("scene:scene_tree", arr);
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 27e33be9d7..826fd0189b 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -53,6 +53,8 @@ void BaseButton::_unpress_group() {
}
void BaseButton::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (status.disabled) { // no interaction with disabled button
return;
}
@@ -199,7 +201,6 @@ void BaseButton::set_disabled(bool p_disabled) {
status.pressing_inside = false;
}
update();
- _change_notify("disabled");
}
bool BaseButton::is_disabled() const {
@@ -213,7 +214,6 @@ void BaseButton::set_pressed(bool p_pressed) {
if (status.pressed == p_pressed) {
return;
}
- _change_notify("pressed");
status.pressed = p_pressed;
if (p_pressed) {
@@ -325,6 +325,8 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
}
void BaseButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!_is_focus_owner_in_shorcut_context()) {
return;
}
@@ -448,18 +450,7 @@ void BaseButton::_bind_methods() {
}
BaseButton::BaseButton() {
- toggle_mode = false;
- shortcut_in_tooltip = true;
- keep_pressed_outside = false;
- status.pressed = false;
- status.press_attempt = false;
- status.hovering = false;
- status.pressing_inside = false;
- status.disabled = false;
set_focus_mode(FOCUS_ALL);
- action_mode = ACTION_MODE_BUTTON_RELEASE;
- button_mask = BUTTON_MASK_LEFT;
- shortcut_context = ObjectID();
}
BaseButton::~BaseButton() {
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index b349b75761..6c7a8f3433 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -45,21 +45,21 @@ public:
};
private:
- int button_mask;
- bool toggle_mode;
- bool shortcut_in_tooltip;
- bool keep_pressed_outside;
+ int button_mask = MOUSE_BUTTON_MASK_LEFT;
+ bool toggle_mode = false;
+ bool shortcut_in_tooltip = true;
+ bool keep_pressed_outside = false;
Ref<Shortcut> shortcut;
ObjectID shortcut_context;
- ActionMode action_mode;
+ ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE;
struct Status {
- bool pressed;
- bool hovering;
- bool press_attempt;
- bool pressing_inside;
+ bool pressed = false;
+ bool hovering = false;
+ bool press_attempt = false;
+ bool pressing_inside = false;
- bool disabled;
+ bool disabled = false;
} status;
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index a00d755c9c..7407ad5b8f 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -33,9 +33,9 @@
#include "margin_container.h"
struct _MinSizeCache {
- int min_size;
- bool will_stretch;
- int final_size;
+ int min_size = 0;
+ bool will_stretch = false;
+ int final_size = 0;
};
void BoxContainer::_resort() {
@@ -50,7 +50,7 @@ void BoxContainer::_resort() {
int children_count = 0;
int stretch_min = 0;
int stretch_avail = 0;
- float stretch_ratio_total = 0;
+ float stretch_ratio_total = 0.0;
Map<Control *, _MinSizeCache> min_size_cache;
for (int i = 0; i < get_child_count(); i++) {
@@ -105,7 +105,7 @@ void BoxContainer::_resort() {
has_stretched = true;
bool refit_successful = true; //assume refit-test will go well
- float error = 0; // Keep track of accumulated error in pixels
+ float error = 0.0; // Keep track of accumulated error in pixels
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -313,7 +313,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const {
return align;
}
-void BoxContainer::add_spacer(bool p_begin) {
+Control *BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew(Control);
c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events
@@ -327,11 +327,12 @@ void BoxContainer::add_spacer(bool p_begin) {
if (p_begin) {
move_child(c, 0);
}
+
+ return c;
}
BoxContainer::BoxContainer(bool p_vertical) {
vertical = p_vertical;
- align = ALIGN_BEGIN;
}
void BoxContainer::_bind_methods() {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index 8285c2b9a2..23feea565c 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -44,8 +44,8 @@ public:
};
private:
- bool vertical;
- AlignMode align;
+ bool vertical = false;
+ AlignMode align = ALIGN_BEGIN;
void _resort();
@@ -55,7 +55,7 @@ protected:
static void _bind_methods();
public:
- void add_spacer(bool p_begin = false);
+ Control *add_spacer(bool p_begin = false);
void set_alignment(AlignMode p_align);
AlignMode get_alignment() const;
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 8b3daf79a8..b0bcde8865 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -56,6 +56,11 @@ Size2 Button::get_minimum_size() const {
}
}
+ Ref<Font> font = get_theme_font("font");
+ float font_height = font->get_height(get_theme_font_size("font_size"));
+
+ minsize.height = MAX(font_height, minsize.height);
+
return get_theme_stylebox("normal")->get_minimum_size() + minsize;
}
@@ -203,7 +208,7 @@ void Button::_notification(int p_what) {
color_icon.a = 0.4;
}
- float icon_ofs_region = 0;
+ float icon_ofs_region = 0.0;
if (rtl) {
if (_internal_margin[SIDE_RIGHT] > 0) {
icon_ofs_region = _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation");
@@ -338,7 +343,6 @@ void Button::set_text(const String &p_text) {
_shape();
update();
- _change_notify("text");
minimum_size_changed();
}
}
@@ -399,7 +403,6 @@ void Button::set_icon(const Ref<Texture2D> &p_icon) {
if (icon != p_icon) {
icon = p_icon;
update();
- _change_notify("icon");
minimum_size_changed();
}
}
@@ -424,7 +427,6 @@ void Button::set_flat(bool p_flat) {
if (flat != p_flat) {
flat = p_flat;
update();
- _change_notify("flat");
}
}
@@ -474,7 +476,7 @@ bool Button::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -544,16 +546,8 @@ Button::Button(const String &p_text) {
text_buf.instance();
text_buf->set_flags(TextServer::BREAK_MANDATORY);
- flat = false;
- clip_text = false;
- expand_icon = false;
set_mouse_filter(MOUSE_FILTER_STOP);
set_text(p_text);
- align = ALIGN_CENTER;
-
- for (int i = 0; i < 4; i++) {
- _internal_margin[i] = 0;
- }
}
Button::~Button() {
diff --git a/scene/gui/button.h b/scene/gui/button.h
index d633fddc8a..d968f63f51 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -45,7 +45,7 @@ public:
};
private:
- bool flat;
+ bool flat = false;
String text;
String xl_text;
Ref<TextParagraph> text_buf;
@@ -55,10 +55,10 @@ private:
TextDirection text_direction = TEXT_DIRECTION_AUTO;
Ref<Texture2D> icon;
- bool expand_icon;
- bool clip_text;
- TextAlign align;
- float _internal_margin[4];
+ bool expand_icon = false;
+ bool clip_text = false;
+ TextAlign align = ALIGN_CENTER;
+ float _internal_margin[4] = {};
void _shape();
diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp
index f2d1dee0fc..909516e7ef 100644
--- a/scene/gui/center_container.cpp
+++ b/scene/gui/center_container.cpp
@@ -95,6 +95,4 @@ void CenterContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_top_left"), "set_use_top_left", "is_using_top_left");
}
-CenterContainer::CenterContainer() {
- use_top_left = false;
-}
+CenterContainer::CenterContainer() {}
diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h
index ee8b2e0e48..0944f200fc 100644
--- a/scene/gui/center_container.h
+++ b/scene/gui/center_container.h
@@ -36,7 +36,7 @@
class CenterContainer : public Container {
GDCLASS(CenterContainer, Container);
- bool use_top_left;
+ bool use_top_left = false;
protected:
void _notification(int p_what);
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 9df328dd11..c0650a8f3f 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -34,7 +34,9 @@
Size2 CheckBox::get_icon_size() const {
Ref<Texture2D> checked = Control::get_theme_icon("checked");
+ Ref<Texture2D> checked_disabled = Control::get_theme_icon("checked_disabled");
Ref<Texture2D> unchecked = Control::get_theme_icon("unchecked");
+ Ref<Texture2D> unchecked_disabled = Control::get_theme_icon("unchecked_disabled");
Ref<Texture2D> radio_checked = Control::get_theme_icon("radio_checked");
Ref<Texture2D> radio_unchecked = Control::get_theme_icon("radio_unchecked");
@@ -79,8 +81,8 @@ void CheckBox::_notification(int p_what) {
} else if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- Ref<Texture2D> on = Control::get_theme_icon(is_radio() ? "radio_checked" : "checked");
- Ref<Texture2D> off = Control::get_theme_icon(is_radio() ? "radio_unchecked" : "unchecked");
+ Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : ""));
+ Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : ""));
Ref<StyleBox> sb = get_theme_stylebox("normal");
Vector2 ofs;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 6c36db0c92..b78f9cad24 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -113,6 +113,27 @@ void ColorPicker::_update_controls() {
btn_hsv->set_disabled(false);
}
+ if (raw_mode_enabled) {
+ for (int i = 0; i < 3; i++) {
+ scroll[i]->remove_theme_icon_override("grabber");
+ scroll[i]->remove_theme_icon_override("grabber_highlight");
+ scroll[i]->remove_theme_style_override("slider");
+ scroll[i]->remove_theme_style_override("grabber_area");
+ scroll[i]->remove_theme_style_override("grabber_area_highlight");
+ }
+ } else {
+ Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
+ Ref<Texture2D> bar_arrow = get_theme_icon("bar_arrow");
+
+ for (int i = 0; i < 4; i++) {
+ scroll[i]->add_theme_icon_override("grabber", bar_arrow);
+ scroll[i]->add_theme_icon_override("grabber_highlight", bar_arrow);
+ scroll[i]->add_theme_style_override("slider", style_box_empty);
+ scroll[i]->add_theme_style_override("grabber_area", style_box_empty);
+ scroll[i]->add_theme_style_override("grabber_area_highlight", style_box_empty);
+ }
+ }
+
if (edit_alpha) {
values[3]->show();
scroll[3]->show();
@@ -122,6 +143,30 @@ void ColorPicker::_update_controls() {
scroll[3]->hide();
labels[3]->hide();
}
+
+ switch (picker_type) {
+ case SHAPE_HSV_RECTANGLE:
+ wheel_edit->hide();
+ w_edit->show();
+ uv_edit->show();
+ break;
+ case SHAPE_HSV_WHEEL:
+ wheel_edit->show();
+ w_edit->hide();
+ uv_edit->hide();
+
+ wheel->set_material(wheel_mat);
+ break;
+ case SHAPE_VHS_CIRCLE:
+ wheel_edit->show();
+ w_edit->show();
+ uv_edit->hide();
+
+ wheel->set_material(circle_mat);
+ break;
+ default: {
+ }
+ }
}
void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
@@ -166,10 +211,13 @@ void ColorPicker::_value_changed(double) {
}
if (hsv_mode_enabled) {
- color.set_hsv(scroll[0]->get_value() / 360.0,
- scroll[1]->get_value() / 100.0,
- scroll[2]->get_value() / 100.0,
- scroll[3]->get_value() / 255.0);
+ h = scroll[0]->get_value() / 360.0;
+ s = scroll[1]->get_value() / 100.0;
+ v = scroll[2]->get_value() / 100.0;
+ color.set_hsv(h, s, v, scroll[3]->get_value() / 255.0);
+
+ last_hsv = color;
+
} else {
for (int i = 0; i < 4; i++) {
color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0);
@@ -240,6 +288,11 @@ void ColorPicker::_update_color(bool p_update_sliders) {
sample->update();
uv_edit->update();
w_edit->update();
+ for (int i = 0; i < 4; i++) {
+ scroll[i]->update();
+ }
+ wheel->update();
+ wheel_uv->update();
updating = false;
}
@@ -282,6 +335,18 @@ Color ColorPicker::get_pick_color() const {
return color;
}
+void ColorPicker::set_picker_shape(PickerShapeType p_picker_type) {
+ ERR_FAIL_INDEX(p_picker_type, SHAPE_MAX);
+ picker_type = p_picker_type;
+
+ _update_controls();
+ _update_color();
+}
+
+ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const {
+ return picker_type;
+}
+
void ColorPicker::add_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.move_to_back(presets.find(p_color));
@@ -394,7 +459,7 @@ void ColorPicker::_update_text_value() {
}
void ColorPicker::_sample_draw() {
- const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
+ const Rect2 r = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
if (color.a < 1.0) {
sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true);
@@ -414,55 +479,242 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
}
if (p_which == 0) {
Vector<Point2> points;
- points.push_back(Vector2());
- points.push_back(Vector2(c->get_size().x, 0));
- points.push_back(c->get_size());
- points.push_back(Vector2(0, c->get_size().y));
Vector<Color> colors;
- colors.push_back(Color(1, 1, 1, 1));
- colors.push_back(Color(1, 1, 1, 1));
- colors.push_back(Color(0, 0, 0, 1));
- colors.push_back(Color(0, 0, 0, 1));
- c->draw_polygon(points, colors);
Vector<Color> colors2;
Color col = color;
+ Vector2 center = c->get_size() / 2.0;
+
+ switch (picker_type) {
+ case SHAPE_HSV_WHEEL: {
+ points.resize(4);
+ colors.resize(4);
+ colors2.resize(4);
+ real_t ring_radius_x = Math_SQRT12 * c->get_size().width * 0.42;
+ real_t ring_radius_y = Math_SQRT12 * c->get_size().height * 0.42;
+
+ points.set(0, center - Vector2(ring_radius_x, ring_radius_y));
+ points.set(1, center + Vector2(ring_radius_x, -ring_radius_y));
+ points.set(2, center + Vector2(ring_radius_x, ring_radius_y));
+ points.set(3, center + Vector2(-ring_radius_x, ring_radius_y));
+ colors.set(0, Color(1, 1, 1, 1));
+ colors.set(1, Color(1, 1, 1, 1));
+ colors.set(2, Color(0, 0, 0, 1));
+ colors.set(3, Color(0, 0, 0, 1));
+ c->draw_polygon(points, colors);
+
+ col.set_hsv(h, 1, 1);
+ col.a = 0;
+ colors2.set(0, col);
+ col.a = 1;
+ colors2.set(1, col);
+ col.set_hsv(h, 1, 0);
+ colors2.set(2, col);
+ col.a = 0;
+ colors2.set(3, col);
+ c->draw_polygon(points, colors2);
+ break;
+ }
+ case SHAPE_HSV_RECTANGLE: {
+ points.resize(4);
+ colors.resize(4);
+ colors2.resize(4);
+ points.set(0, Vector2());
+ points.set(1, Vector2(c->get_size().x, 0));
+ points.set(2, c->get_size());
+ points.set(3, Vector2(0, c->get_size().y));
+ colors.set(0, Color(1, 1, 1, 1));
+ colors.set(1, Color(1, 1, 1, 1));
+ colors.set(2, Color(0, 0, 0, 1));
+ colors.set(3, Color(0, 0, 0, 1));
+ c->draw_polygon(points, colors);
+ col = color;
+ col.set_hsv(h, 1, 1);
+ col.a = 0;
+ colors2.set(0, col);
+ col.a = 1;
+ colors2.set(1, col);
+ col.set_hsv(h, 1, 0);
+ colors2.set(2, col);
+ col.a = 0;
+ colors2.set(3, col);
+ c->draw_polygon(points, colors2);
+ break;
+ }
+ default: {
+ }
+ }
+ Ref<Texture2D> cursor = get_theme_icon("picker_cursor", "ColorPicker");
+ int x;
+ int y;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (cursor->get_width() / 2);
+ y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2);
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+ x = CLAMP(real_size.x * s, 0, real_size.x) + corner_x - (cursor->get_width() / 2);
+ y = CLAMP(real_size.y - real_size.y * v, 0, real_size.y) + corner_y - (cursor->get_height() / 2);
+ }
+ c->draw_texture(cursor, Point2(x, y));
+
col.set_hsv(h, 1, 1);
- col.a = 0;
- colors2.push_back(col);
- col.a = 1;
- colors2.push_back(col);
- col.set_hsv(h, 1, 0);
- colors2.push_back(col);
- col.a = 0;
- colors2.push_back(col);
- c->draw_polygon(points, colors2);
- int x = CLAMP(c->get_size().x * s, 0, c->get_size().x);
- int y = CLAMP(c->get_size().y - c->get_size().y * v, 0, c->get_size().y);
- col = color;
- col.a = 1;
- c->draw_line(Point2(x, 0), Point2(x, c->get_size().y), col.inverted());
- c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
- c->draw_line(Point2(x, y), Point2(x, y), Color(1, 1, 1), 2);
+ if (picker_type == SHAPE_HSV_WHEEL) {
+ points.resize(4);
+ double h1 = h - (0.5 / 360);
+ double h2 = h + (0.5 / 360);
+ points.set(0, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU)), center.y + (center.y * Math::sin(h1 * Math_TAU))));
+ points.set(1, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h1 * Math_TAU) * 0.84)));
+ points.set(2, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU)), center.y + (center.y * Math::sin(h2 * Math_TAU))));
+ points.set(3, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h2 * Math_TAU) * 0.84)));
+ c->draw_multiline(points, col.inverted());
+ }
+
} else if (p_which == 1) {
- Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker");
- c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
- int y = c->get_size().y - c->get_size().y * (1.0 - h);
- Color col = Color();
- col.set_hsv(h, 1, 1);
- c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ if (picker_type == SHAPE_HSV_RECTANGLE) {
+ Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker");
+ c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
+ int y = c->get_size().y - c->get_size().y * (1.0 - h);
+ Color col;
+ col.set_hsv(h, 1, 1);
+ c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ } else if (picker_type == SHAPE_VHS_CIRCLE) {
+ Vector<Point2> points;
+ Vector<Color> colors;
+ Color col;
+ col.set_hsv(h, s, 1);
+ points.resize(4);
+ colors.resize(4);
+ points.set(0, Vector2());
+ points.set(1, Vector2(c->get_size().x, 0));
+ points.set(2, c->get_size());
+ points.set(3, Vector2(0, c->get_size().y));
+ colors.set(0, col);
+ colors.set(1, col);
+ colors.set(2, Color(0, 0, 0));
+ colors.set(3, Color(0, 0, 0));
+ c->draw_polygon(points, colors);
+ int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
+ col.set_hsv(h, 1, v);
+ c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ }
+ } else if (p_which == 2) {
+ c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1));
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ circle_mat->set_shader_param("v", v);
+ }
}
}
-void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
+void ColorPicker::_slider_draw(int p_which) {
+ Vector<Vector2> pos;
+ pos.resize(4);
+ Vector<Color> col;
+ col.resize(4);
+ Size2 size = scroll[p_which]->get_size();
+ Color left_color;
+ Color right_color;
+#ifdef TOOLS_ENABLED
+ const real_t margin = 4 * EDSCALE;
+#else
+ const real_t margin = 4;
+#endif
+
+ if (p_which == 3) {
+ scroll[p_which]->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+
+ left_color = color;
+ left_color.a = 0;
+ right_color = color;
+ right_color.a = 1;
+ } else {
+ if (raw_mode_enabled) {
+ return;
+ }
+ if (hsv_mode_enabled) {
+ if (p_which == 0) {
+ Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker");
+ scroll[p_which]->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
+ scroll[p_which]->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(scroll[p_which]->get_size().x, margin)), false, Color(1, 1, 1), true);
+ return;
+ }
+ Color s_col;
+ Color v_col;
+ s_col.set_hsv(h, 0, v);
+ left_color = (p_which == 1) ? s_col : Color(0, 0, 0);
+ s_col.set_hsv(h, 1, v);
+ v_col.set_hsv(h, s, 1);
+ right_color = (p_which == 1) ? s_col : v_col;
+ } else {
+ left_color = Color(
+ p_which == 0 ? 0 : color.r,
+ p_which == 1 ? 0 : color.g,
+ p_which == 2 ? 0 : color.b);
+ right_color = Color(
+ p_which == 0 ? 1 : color.r,
+ p_which == 1 ? 1 : color.g,
+ p_which == 2 ? 1 : color.b);
+ }
+ }
+
+ col.set(0, left_color);
+ col.set(1, right_color);
+ col.set(2, right_color);
+ col.set(3, left_color);
+ pos.set(0, Vector2(0, margin));
+ pos.set(1, Vector2(size.x, margin));
+ pos.set(2, Vector2(size.x, margin * 2));
+ pos.set(3, Vector2(0, margin * 2));
+
+ scroll[p_which]->draw_polygon(pos, col);
+}
+
+void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
+ Vector2 center = c->get_size() / 2.0;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ real_t dist = center.distance_to(bev->get_position());
+
+ if (dist <= center.x) {
+ real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ s = CLAMP(dist / center.x, 0, 1);
+ } else {
+ return;
+ }
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+
+ if (bev->get_position().x < corner_x || bev->get_position().x > c->get_size().x - corner_x ||
+ bev->get_position().y < corner_y || bev->get_position().y > c->get_size().y - corner_y) {
+ {
+ real_t dist = center.distance_to(bev->get_position());
+
+ if (dist >= center.x * 0.84 && dist <= center.x) {
+ real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ spinning = true;
+ } else {
+ return;
+ }
+ }
+ }
+
+ if (!spinning) {
+ real_t x = CLAMP(bev->get_position().x, corner_x, c->get_size().x - corner_x);
+ real_t y = CLAMP(bev->get_position().y, corner_x, c->get_size().y - corner_y);
+
+ s = (x - c->get_position().x - corner_x) / real_size.x;
+ v = 1.0 - (y - c->get_position().y - corner_y) / real_size.y;
+ }
+ }
changing_color = true;
- float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width);
- float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height);
- s = x / uv_edit->get_size().width;
- v = 1.0 - y / uv_edit->get_size().height;
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -470,11 +722,13 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
if (!deferred_mode_enabled) {
emit_signal("color_changed", color);
}
- } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
emit_signal("color_changed", color);
changing_color = false;
+ spinning = false;
} else {
changing_color = false;
+ spinning = false;
}
}
@@ -484,10 +738,30 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
if (!changing_color) {
return;
}
- float x = CLAMP((float)mev->get_position().x, 0, uv_edit->get_size().width);
- float y = CLAMP((float)mev->get_position().y, 0, uv_edit->get_size().height);
- s = x / uv_edit->get_size().width;
- v = 1.0 - y / uv_edit->get_size().height;
+
+ Vector2 center = c->get_size() / 2.0;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ real_t dist = center.distance_to(mev->get_position());
+ real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ s = CLAMP(dist / center.x, 0, 1);
+ } else {
+ if (spinning) {
+ real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+
+ real_t x = CLAMP(mev->get_position().x, corner_x, c->get_size().x - corner_x);
+ real_t y = CLAMP(mev->get_position().y, corner_x, c->get_size().y - corner_y);
+
+ s = (x - corner_x) / real_size.x;
+ v = 1.0 - (y - corner_y) / real_size.y;
+ }
+ }
+
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -502,10 +776,14 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
changing_color = true;
float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height);
- h = y / w_edit->get_size().height;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ v = 1.0 - (y / w_edit->get_size().height);
+ } else {
+ h = y / w_edit->get_size().height;
+ }
} else {
changing_color = false;
}
@@ -515,7 +793,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
_update_color();
if (!deferred_mode_enabled) {
emit_signal("color_changed", color);
- } else if (!bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ } else if (!bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
emit_signal("color_changed", color);
}
}
@@ -527,7 +805,11 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
return;
}
float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height);
- h = y / w_edit->get_size().height;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ v = 1.0 - (y / w_edit->get_size().height);
+ } else {
+ h = y / w_edit->get_size().height;
+ }
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -543,7 +825,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
if (bev.is_valid()) {
int index = 0;
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
for (int i = 0; i < presets.size(); i++) {
int x = (i % presets_per_row) * bt_add_preset->get_size().x;
int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
@@ -554,7 +836,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
set_pick_color(presets[index]);
_update_color();
emit_signal("color_changed", color);
- } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
+ } else if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_RIGHT && presets_enabled) {
index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
@@ -578,8 +860,12 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
}
void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
+ if (!is_inside_tree()) {
+ return;
+ }
+
Ref<InputEventMouseButton> bev = p_event;
- if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) {
+ if (bev.is_valid() && bev->get_button_index() == MOUSE_BUTTON_LEFT && !bev->is_pressed()) {
emit_signal("color_changed", color);
screen->hide();
}
@@ -591,7 +877,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
return;
}
- Ref<Image> img = r->get_texture()->get_data();
+ Ref<Image> img = r->get_texture()->get_image();
if (img.is_valid() && !img->is_empty()) {
Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
Color c = img->get_pixel(ofs.x, r->get_visible_rect().size.height - ofs.y);
@@ -607,6 +893,10 @@ void ColorPicker::_add_preset_pressed() {
}
void ColorPicker::_screen_pick_pressed() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
Viewport *r = get_tree()->get_root();
if (!screen) {
screen = memnew(Control);
@@ -703,67 +993,52 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
+ ClassDB::bind_method(D_METHOD("set_picker_shape", "picker"), &ColorPicker::set_picker_shape);
+ ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle"), "set_picker_shape", "get_picker_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_removed", PropertyInfo(Variant::COLOR, "color")));
+
+ BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE);
+ BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL);
+ BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE);
}
ColorPicker::ColorPicker() :
BoxContainer(true) {
- updating = true;
- edit_alpha = true;
- text_is_constructor = false;
- hsv_mode_enabled = false;
- raw_mode_enabled = false;
- deferred_mode_enabled = false;
- changing_color = false;
- presets_enabled = true;
- presets_visible = true;
- screen = nullptr;
-
HBoxContainer *hb_edit = memnew(HBoxContainer);
add_child(hb_edit);
hb_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- uv_edit = memnew(Control);
hb_edit->add_child(uv_edit);
- uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input));
+ uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(uv_edit));
uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
uv_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height")));
uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
- w_edit = memnew(Control);
- hb_edit->add_child(w_edit);
- w_edit->set_custom_minimum_size(Size2(get_theme_constant("h_width"), 0));
- w_edit->set_h_size_flags(SIZE_FILL);
- w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
- w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit));
-
HBoxContainer *hb_smpl = memnew(HBoxContainer);
add_child(hb_smpl);
- sample = memnew(TextureRect);
hb_smpl->add_child(sample);
sample->set_h_size_flags(SIZE_EXPAND_FILL);
sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw));
- btn_pick = memnew(Button);
btn_pick->set_flat(true);
hb_smpl->add_child(btn_pick);
btn_pick->set_toggle_mode(true);
- btn_pick->set_tooltip(TTR("Pick a color from the editor window."));
+ btn_pick->set_tooltip(RTR("Pick a color from the editor window."));
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
VBoxContainer *vbl = memnew(VBoxContainer);
@@ -799,25 +1074,24 @@ ColorPicker::ColorPicker() :
scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL);
scroll[i]->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed));
+ scroll[i]->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(i));
vbr->add_child(hbc);
}
+
labels[3]->set_text("A");
HBoxContainer *hhb = memnew(HBoxContainer);
vbr->add_child(hhb);
- btn_hsv = memnew(CheckButton);
hhb->add_child(btn_hsv);
- btn_hsv->set_text(TTR("HSV"));
+ btn_hsv->set_text(RTR("HSV"));
btn_hsv->connect("toggled", callable_mp(this, &ColorPicker::set_hsv_mode));
- btn_raw = memnew(CheckButton);
hhb->add_child(btn_raw);
- btn_raw->set_text(TTR("Raw"));
+ btn_raw->set_text(RTR("Raw"));
btn_raw->connect("toggled", callable_mp(this, &ColorPicker::set_raw_mode));
- text_type = memnew(Button);
hhb->add_child(text_type);
text_type->set_text("#");
text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
@@ -831,36 +1105,70 @@ ColorPicker::ColorPicker() :
text_type->set_mouse_filter(MOUSE_FILTER_IGNORE);
}
- c_text = memnew(LineEdit);
hhb->add_child(c_text);
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
c_text->connect("text_entered", callable_mp(this, &ColorPicker::_html_entered));
c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter));
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
+ wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ wheel_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height")));
+ hb_edit->add_child(wheel_edit);
+
+ wheel_mat.instance();
+ circle_mat.instance();
+
+ Ref<Shader> wheel_shader(memnew(Shader));
+ wheel_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);COLOR=vec4(clamp((abs(fract(((a-TAU)/TAU)+vec3(3.0,2.0,1.0)/3.0)*6.0-3.0)-1.0),0.0,1.0),(b+b2+b3+b4)/4.00);}");
+ wheel_mat->set_shader(wheel_shader);
+
+ Ref<Shader> circle_shader(memnew(Shader));
+ circle_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;uniform float v=1.0;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5);COLOR=vec4(mix(vec3(1.0),clamp(abs(fract(vec3((a-TAU)/TAU)+vec3(1.0,2.0/3.0,1.0/3.0))*6.0-vec3(3.0))-vec3(1.0),0.0,1.0),((float(sqrt(x*x+y*y))*2.0))/1.0)*vec3(v),(b+b2+b3+b4)/4.00);}");
+ circle_mat->set_shader(circle_shader);
+
+ MarginContainer *wheel_margin(memnew(MarginContainer));
+#ifdef TOOLS_ENABLED
+ wheel_margin->add_theme_constant_override("margin_bottom", 8 * EDSCALE);
+#else
+ wheel_margin->add_theme_constant_override("margin_bottom", 8);
+#endif
+ wheel_edit->add_child(wheel_margin);
+
+ wheel_margin->add_child(wheel);
+ wheel->set_mouse_filter(MOUSE_FILTER_PASS);
+ wheel->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(2, wheel));
+
+ wheel_margin->add_child(wheel_uv);
+ wheel_uv->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(wheel_uv));
+ wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv));
+
+ hb_edit->add_child(w_edit);
+ w_edit->set_custom_minimum_size(Size2(get_theme_constant("h_width"), 0));
+ w_edit->set_h_size_flags(SIZE_FILL);
+ w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
+ w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit));
+
+ picker_type = SHAPE_HSV_RECTANGLE;
_update_controls();
updating = false;
set_pick_color(Color(1, 1, 1));
- preset_separator = memnew(HSeparator);
add_child(preset_separator);
- preset_container = memnew(HBoxContainer);
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container);
- preset = memnew(TextureRect);
preset_container->add_child(preset);
preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input));
preset->connect("draw", callable_mp(this, &ColorPicker::_update_presets));
- preset_container2 = memnew(HBoxContainer);
preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container2);
- bt_add_preset = memnew(Button);
preset_container2->add_child(bt_add_preset);
- bt_add_preset->set_tooltip(TTR("Add current color as a preset."));
+ bt_add_preset->set_tooltip(RTR("Add current color as a preset."));
bt_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
}
@@ -1002,12 +1310,5 @@ void ColorPickerButton::_bind_methods() {
}
ColorPickerButton::ColorPickerButton() {
- // Initialization is now done deferred,
- // this improves performance in the inspector as the color picker
- // can be expensive to initialize.
- picker = nullptr;
- popup = nullptr;
- edit_alpha = true;
-
set_toggle_mode(true);
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 3695820a79..a0d2aa95ca 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -31,6 +31,7 @@
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
+#include "scene/gui/aspect_ratio_container.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
@@ -45,39 +46,57 @@
class ColorPicker : public BoxContainer {
GDCLASS(ColorPicker, BoxContainer);
+public:
+ enum PickerShapeType {
+ SHAPE_HSV_RECTANGLE,
+ SHAPE_HSV_WHEEL,
+ SHAPE_VHS_CIRCLE,
+
+ SHAPE_MAX
+ };
+
private:
- Control *screen;
- Control *uv_edit;
- Control *w_edit;
- TextureRect *sample;
- TextureRect *preset;
- HBoxContainer *preset_container;
- HBoxContainer *preset_container2;
- HSeparator *preset_separator;
- Button *bt_add_preset;
+ Control *screen = nullptr;
+ Control *uv_edit = memnew(Control);
+ Control *w_edit = memnew(Control);
+ AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer);
+ Ref<ShaderMaterial> wheel_mat;
+ Ref<ShaderMaterial> circle_mat;
+ Control *wheel = memnew(Control);
+ Control *wheel_uv = memnew(Control);
+ TextureRect *sample = memnew(TextureRect);
+ TextureRect *preset = memnew(TextureRect);
+ HBoxContainer *preset_container = memnew(HBoxContainer);
+ HBoxContainer *preset_container2 = memnew(HBoxContainer);
+ HSeparator *preset_separator = memnew(HSeparator);
+ Button *bt_add_preset = memnew(Button);
List<Color> presets;
- Button *btn_pick;
- CheckButton *btn_hsv;
- CheckButton *btn_raw;
+ Button *btn_pick = memnew(Button);
+ CheckButton *btn_hsv = memnew(CheckButton);
+ CheckButton *btn_raw = memnew(CheckButton);
HSlider *scroll[4];
SpinBox *values[4];
Label *labels[4];
- Button *text_type;
- LineEdit *c_text;
- bool edit_alpha;
+ Button *text_type = memnew(Button);
+ LineEdit *c_text = memnew(LineEdit);
+ bool edit_alpha = true;
Size2i ms;
- bool text_is_constructor;
- int presets_per_row;
+ bool text_is_constructor = false;
+ int presets_per_row = 0;
+ PickerShapeType picker_type = SHAPE_HSV_WHEEL;
Color color;
- bool raw_mode_enabled;
- bool hsv_mode_enabled;
- bool deferred_mode_enabled;
- bool updating;
- bool changing_color;
- bool presets_enabled;
- bool presets_visible;
- float h, s, v;
+ bool raw_mode_enabled = false;
+ bool hsv_mode_enabled = false;
+ bool deferred_mode_enabled = false;
+ bool updating = true;
+ bool changing_color = false;
+ bool spinning = false;
+ bool presets_enabled = true;
+ bool presets_visible = true;
+ float h = 0.0;
+ float s = 0.0;
+ float v = 0.0;
Color last_hsv;
void _html_entered(const String &p_html);
@@ -89,8 +108,9 @@ private:
void _text_type_toggled();
void _sample_draw();
void _hsv_draw(int p_which, Control *c);
+ void _slider_draw(int p_which);
- void _uv_input(const Ref<InputEvent> &p_event);
+ void _uv_input(const Ref<InputEvent> &p_event, Control *c);
void _w_input(const Ref<InputEvent> &p_event);
void _preset_input(const Ref<InputEvent> &p_event);
void _screen_input(const Ref<InputEvent> &p_event);
@@ -112,6 +132,9 @@ public:
void set_pick_color(const Color &p_color);
Color get_pick_color() const;
+ void set_picker_shape(PickerShapeType p_picker_type);
+ PickerShapeType get_picker_shape() const;
+
void add_preset(const Color &p_color);
void erase_preset(const Color &p_color);
PackedColorArray get_presets() const;
@@ -139,10 +162,14 @@ public:
class ColorPickerButton : public Button {
GDCLASS(ColorPickerButton, Button);
- PopupPanel *popup;
- ColorPicker *picker;
+ // Initialization is now done deferred,
+ // this improves performance in the inspector as the color picker
+ // can be expensive to initialize.
+
+ PopupPanel *popup = nullptr;
+ ColorPicker *picker = nullptr;
Color color;
- bool edit_alpha;
+ bool edit_alpha = true;
void _color_changed(const Color &p_color);
void _modal_closed();
@@ -168,4 +195,5 @@ public:
ColorPickerButton();
};
+VARIANT_ENUM_CAST(ColorPicker::PickerShapeType);
#endif // COLOR_PICKER_H
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 03bade6702..dea69aae6b 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -159,16 +159,14 @@ void Container::_notification(int p_what) {
}
}
-String Container::get_configuration_warning() const {
- String warning = Control::get_configuration_warning();
+TypedArray<String> Container::get_configuration_warnings() const {
+ TypedArray<String> warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead.");
+ warnings.push_back(TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
}
- return warning;
+
+ return warnings;
}
void Container::_bind_methods() {
@@ -180,7 +178,6 @@ void Container::_bind_methods() {
}
Container::Container() {
- pending_sort = false;
// All containers should let mouse events pass by default.
set_mouse_filter(MOUSE_FILTER_PASS);
}
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 5e60ca04dc..bce3085f0c 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -36,7 +36,7 @@
class Container : public Control {
GDCLASS(Container, Control);
- bool pending_sort;
+ bool pending_sort = false;
void _sort_children();
void _child_minsize_changed();
@@ -56,7 +56,7 @@ public:
void fit_child_in_rect(Control *p_child, const Rect2 &p_rect);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Container();
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 6b5d8cb658..191f94b2b8 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -73,6 +73,9 @@ Dictionary Control::_edit_get_state() const {
}
void Control::_edit_set_state(const Dictionary &p_state) {
+ ERR_FAIL_COND((p_state.size() <= 0) ||
+ !p_state.has("rotation") || !p_state.has("scale") ||
+ !p_state.has("pivot") || !p_state.has("anchors") || !p_state.has("offsets"));
Dictionary state = p_state;
set_rotation(state["rotation"]);
@@ -93,7 +96,8 @@ void Control::_edit_set_state(const Dictionary &p_state) {
void Control::_edit_set_position(const Point2 &p_position) {
#ifdef TOOLS_ENABLED
- set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled());
+ ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins.");
+ set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled() && Object::cast_to<Control>(data.parent));
#else
// Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED
set_position(p_position);
@@ -114,6 +118,7 @@ Size2 Control::_edit_get_scale() const {
void Control::_edit_set_rect(const Rect2 &p_edit_rect) {
#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins.");
set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled());
set_size(p_edit_rect.size.snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled());
#else
@@ -131,11 +136,11 @@ bool Control::_edit_use_rect() const {
return true;
}
-void Control::_edit_set_rotation(float p_rotation) {
+void Control::_edit_set_rotation(real_t p_rotation) {
set_rotation(p_rotation);
}
-float Control::_edit_get_rotation() const {
+real_t Control::_edit_get_rotation() const {
return get_rotation();
}
@@ -285,15 +290,11 @@ void Control::_update_minimum_size() {
}
Size2 minsize = get_combined_minimum_size();
- if (minsize.x > data.size_cache.x ||
- minsize.y > data.size_cache.y) {
- _size_changed();
- }
-
data.updating_last_minimum_size = false;
if (minsize != data.last_minimum_size) {
data.last_minimum_size = minsize;
+ _size_changed();
emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
}
}
@@ -322,7 +323,6 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = data.color_override.has(name) ? Variant(data.color_override[name]) : Variant();
} else if (sname.begins_with("custom_constants/")) {
String name = sname.get_slicec('/', 1);
-
r_ret = data.constant_override.has(name) ? Variant(data.constant_override[name]) : Variant();
} else {
return false;
@@ -439,14 +439,14 @@ bool Control::is_layout_rtl() const {
} else if (parent_window) {
return parent_window->is_layout_rtl();
} else {
- if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) {
+ if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) {
return true;
}
String locale = TranslationServer::get_singleton()->get_tool_locale();
return TS->is_locale_right_to_left(locale);
}
} else if (data.layout_dir == LAYOUT_DIRECTION_LOCALE) {
- if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) {
+ if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) {
return true;
}
String locale = TranslationServer::get_singleton()->get_tool_locale();
@@ -456,6 +456,10 @@ bool Control::is_layout_rtl() const {
}
}
+void Control::_clear_size_warning() {
+ data.size_warning = false;
+}
+
//moved theme configuration here, so controls can set up even if still not inside active scene
void Control::add_child_notify(Node *p_child) {
@@ -503,7 +507,9 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_EXIT_TREE: {
get_viewport()->_gui_remove_control(this);
-
+ } break;
+ case NOTIFICATION_READY: {
+ connect("ready", callable_mp(this, &Control::_clear_size_warning), varray(), CONNECT_DEFERRED | CONNECT_ONESHOT);
} break;
case NOTIFICATION_ENTER_CANVAS: {
@@ -575,7 +581,7 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
- // some parents need to know the order of the childrens to draw (like TabContainer)
+ // some parents need to know the order of the children to draw (like TabContainer)
// update if necessary
if (data.parent) {
data.parent->update();
@@ -1227,10 +1233,10 @@ Size2 Control::get_parent_area_size() const {
void Control::_size_changed() {
Rect2 parent_rect = get_parent_anchorable_rect();
- float edge_pos[4];
+ real_t edge_pos[4];
for (int i = 0; i < 4; i++) {
- float area = parent_rect.size[i & 1];
+ real_t area = parent_rect.size[i & 1];
edge_pos[i] = data.offset[i] + (data.anchor[i] * area);
}
@@ -1275,7 +1281,6 @@ void Control::_size_changed() {
}
if (pos_changed || size_changed) {
item_rect_changed(size_changed);
- _change_notify_offsets();
_notify_transform();
}
@@ -1285,13 +1290,13 @@ void Control::_size_changed() {
}
}
-void Control::set_anchor(Side p_side, float p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) {
+void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) {
ERR_FAIL_INDEX((int)p_side, 4);
Rect2 parent_rect = get_parent_anchorable_rect();
- float parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
- float previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range;
- float previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range;
+ real_t parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
+ real_t previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range;
+ real_t previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range;
data.anchor[p_side] = p_anchor;
@@ -1315,17 +1320,13 @@ void Control::set_anchor(Side p_side, float p_anchor, bool p_keep_offset, bool p
}
update();
- _change_notify("anchor_left");
- _change_notify("anchor_right");
- _change_notify("anchor_top");
- _change_notify("anchor_bottom");
}
-void Control::_set_anchor(Side p_side, float p_anchor) {
+void Control::_set_anchor(Side p_side, real_t p_anchor) {
set_anchor(p_side, p_anchor);
}
-void Control::set_anchor_and_offset(Side p_side, float p_anchor, float p_pos, bool p_push_opposite_anchor) {
+void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor) {
set_anchor(p_side, p_anchor, false, p_push_opposite_anchor);
set_offset(p_side, p_pos);
}
@@ -1462,7 +1463,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
Rect2 parent_rect = get_parent_anchorable_rect();
- float x = parent_rect.size.x;
+ real_t x = parent_rect.size.x;
if (is_layout_rtl()) {
x = parent_rect.size.x - x - new_size.x;
}
@@ -1586,23 +1587,13 @@ void Control::set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPreset
set_offsets_preset(p_preset, p_resize_mode, p_margin);
}
-float Control::get_anchor(Side p_side) const {
+real_t Control::get_anchor(Side p_side) const {
ERR_FAIL_INDEX_V(int(p_side), 4, 0.0);
return data.anchor[p_side];
}
-void Control::_change_notify_offsets() {
- // this avoids sending the whole object data again on a change
- _change_notify("offset_left");
- _change_notify("offset_top");
- _change_notify("offset_right");
- _change_notify("offset_bottom");
- _change_notify("rect_position");
- _change_notify("rect_size");
-}
-
-void Control::set_offset(Side p_side, float p_value) {
+void Control::set_offset(Side p_side, real_t p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
data.offset[p_side] = p_value;
@@ -1621,7 +1612,7 @@ void Control::set_end(const Size2 &p_point) {
_size_changed();
}
-float Control::get_offset(Side p_side) const {
+real_t Control::get_offset(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0);
return data.offset[p_side];
@@ -1664,12 +1655,12 @@ void Control::set_global_position(const Point2 &p_point, bool p_keep_offsets) {
set_position(inv.xform(p_point), p_keep_offsets);
}
-void Control::_compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r_anchors)[4]) {
+void Control::_compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]) {
Size2 parent_rect_size = get_parent_anchorable_rect().size;
ERR_FAIL_COND(parent_rect_size.x == 0.0);
ERR_FAIL_COND(parent_rect_size.y == 0.0);
- float x = p_rect.position.x;
+ real_t x = p_rect.position.x;
if (is_layout_rtl()) {
x = parent_rect_size.x - x - p_rect.size.x;
}
@@ -1679,10 +1670,10 @@ void Control::_compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r
r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_offsets[3]) / parent_rect_size.y;
}
-void Control::_compute_offsets(Rect2 p_rect, const float p_anchors[4], float (&r_offsets)[4]) {
+void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]) {
Size2 parent_rect_size = get_parent_anchorable_rect().size;
- float x = p_rect.position.x;
+ real_t x = p_rect.position.x;
if (is_layout_rtl()) {
x = parent_rect_size.x - x - p_rect.size.x;
}
@@ -1699,10 +1690,6 @@ void Control::_set_position(const Size2 &p_point) {
void Control::set_position(const Size2 &p_point, bool p_keep_offsets) {
if (p_keep_offsets) {
_compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor);
- _change_notify("anchor_left");
- _change_notify("anchor_right");
- _change_notify("anchor_top");
- _change_notify("anchor_bottom");
} else {
_compute_offsets(Rect2(p_point, data.size_cache), data.anchor, data.offset);
}
@@ -1721,6 +1708,11 @@ void Control::set_rect(const Rect2 &p_rect) {
}
void Control::_set_size(const Size2 &p_size) {
+#ifdef DEBUG_ENABLED
+ if (data.size_warning) {
+ WARN_PRINT("Adjusting the size of Control nodes before they are fully initialized is unreliable. Consider deferring it with set_deferred().");
+ }
+#endif
set_size(p_size);
}
@@ -1736,10 +1728,6 @@ void Control::set_size(const Size2 &p_size, bool p_keep_offsets) {
if (p_keep_offsets) {
_compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor);
- _change_notify("anchor_left");
- _change_notify("anchor_right");
- _change_notify("anchor_top");
- _change_notify("anchor_bottom");
} else {
_compute_offsets(Rect2(data.pos_cache, new_size), data.anchor, data.offset);
}
@@ -1787,53 +1775,38 @@ Rect2 Control::get_anchorable_rect() const {
}
void Control::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
+ ERR_FAIL_COND(!p_icon.is_valid());
+
if (data.icon_override.has(p_name)) {
data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a icon
- if (p_icon.is_null()) {
- data.icon_override.erase(p_name);
- } else {
- data.icon_override[p_name] = p_icon;
- if (data.icon_override[p_name].is_valid()) {
- data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.icon_override[p_name] = p_icon;
+ data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
+ ERR_FAIL_COND(!p_style.is_valid());
+
if (data.style_override.has(p_name)) {
data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a style
- if (p_style.is_null()) {
- data.style_override.erase(p_name);
- } else {
- data.style_override[p_name] = p_style;
- if (data.style_override[p_name].is_valid()) {
- data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.style_override[p_name] = p_style;
+ data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
+ ERR_FAIL_COND(!p_font.is_valid());
+
if (data.font_override.has(p_name)) {
data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a font
- if (p_font.is_null()) {
- data.font_override.erase(p_name);
- } else {
- data.font_override[p_name] = p_font;
- if (data.font_override[p_name].is_valid()) {
- data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.font_override[p_name] = p_font;
+ data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
@@ -1852,6 +1825,48 @@ void Control::add_theme_constant_override(const StringName &p_name, int p_consta
notification(NOTIFICATION_THEME_CHANGED);
}
+void Control::remove_theme_icon_override(const StringName &p_name) {
+ if (data.icon_override.has(p_name)) {
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.icon_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_style_override(const StringName &p_name) {
+ if (data.style_override.has(p_name)) {
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.style_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_font_override(const StringName &p_name) {
+ if (data.font_override.has(p_name)) {
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.font_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_font_size_override(const StringName &p_name) {
+ data.font_size_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_color_override(const StringName &p_name) {
+ data.color_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_constant_override(const StringName &p_name) {
+ data.constant_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
void Control::set_focus_mode(FocusMode p_focus_mode) {
ERR_FAIL_INDEX((int)p_focus_mode, 3);
@@ -2168,7 +2183,7 @@ Ref<Theme> Control::get_theme() const {
void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip;
- update_configuration_warning();
+ update_configuration_warnings();
}
String Control::get_tooltip(const Point2 &p_pos) const {
@@ -2264,7 +2279,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
return c;
}
- float dist = 1e7;
+ real_t dist = 1e7;
Control *result = nullptr;
Point2 points[4];
@@ -2285,10 +2300,10 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
Vector2 vdir = dir[p_side];
- float maxd = -1e7;
+ real_t maxd = -1e7;
for (int i = 0; i < 4; i++) {
- float d = vdir.dot(points[i]);
+ real_t d = vdir.dot(points[i]);
if (d > maxd) {
maxd = d;
}
@@ -2315,7 +2330,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
return result;
}
-void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
+void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest) {
if (Object::cast_to<Viewport>(p_at)) {
return; //bye
}
@@ -2332,10 +2347,10 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
points[2] = xform.xform(c->get_size());
points[3] = xform.xform(Point2(0, c->get_size().y));
- float min = 1e7;
+ real_t min = 1e7;
for (int i = 0; i < 4; i++) {
- float d = p_dir.dot(points[i]);
+ real_t d = p_dir.dot(points[i]);
if (d < min) {
min = d;
}
@@ -2351,8 +2366,8 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
Vector2 fb = points[(j + 1) % 4];
Vector2 pa, pb;
- float d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb);
- //float d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
+ real_t d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb);
+ //real_t d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
if (d < r_closest_dist) {
r_closest_dist = d;
*r_closest = c;
@@ -2392,7 +2407,7 @@ void Control::set_v_size_flags(int p_flags) {
emit_signal(SceneStringNames::get_singleton()->size_flags_changed);
}
-void Control::set_stretch_ratio(float p_ratio) {
+void Control::set_stretch_ratio(real_t p_ratio) {
if (data.expand == p_ratio) {
return;
}
@@ -2401,7 +2416,7 @@ void Control::set_stretch_ratio(float p_ratio) {
emit_signal(SceneStringNames::get_singleton()->size_flags_changed);
}
-float Control::get_stretch_ratio() const {
+real_t Control::get_stretch_ratio() const {
return data.expand;
}
@@ -2453,7 +2468,7 @@ int Control::get_v_size_flags() const {
void Control::set_mouse_filter(MouseFilter p_filter) {
ERR_FAIL_INDEX(p_filter, 3);
data.mouse_filter = p_filter;
- update_configuration_warning();
+ update_configuration_warnings();
}
Control::MouseFilter Control::get_mouse_filter() const {
@@ -2573,22 +2588,21 @@ Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_node_typ
return ret;
}
-void Control::set_rotation(float p_radians) {
+void Control::set_rotation(real_t p_radians) {
data.rotation = p_radians;
update();
_notify_transform();
- _change_notify("rect_rotation");
}
-float Control::get_rotation() const {
+real_t Control::get_rotation() const {
return data.rotation;
}
-void Control::set_rotation_degrees(float p_degrees) {
+void Control::set_rotation_degrees(real_t p_degrees) {
set_rotation(Math::deg2rad(p_degrees));
}
-float Control::get_rotation_degrees() const {
+real_t Control::get_rotation_degrees() const {
return Math::rad2deg(get_rotation());
}
@@ -2602,7 +2616,6 @@ void Control::set_pivot_offset(const Vector2 &p_pivot) {
data.pivot_offset = p_pivot;
update();
_notify_transform();
- _change_notify("rect_pivot_offset");
}
Vector2 Control::get_pivot_offset() const {
@@ -2675,15 +2688,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
if (p_idx == 0) {
List<StringName> sn;
String pf = p_function;
- if (pf == "add_color_override" || pf == "has_color" || pf == "has_color_override" || pf == "get_color") {
+ if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
Theme::get_default()->get_color_list(get_class(), &sn);
- } else if (pf == "add_style_override" || pf == "has_style" || pf == "has_style_override" || pf == "get_style") {
+ } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
Theme::get_default()->get_stylebox_list(get_class(), &sn);
- } else if (pf == "add_font_override" || pf == "has_font" || pf == "has_font_override" || pf == "get_font") {
+ } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
Theme::get_default()->get_font_list(get_class(), &sn);
- } else if (pf == "add_font_size_override" || pf == "has_font_size" || pf == "has_font_size_override" || pf == "get_font_size") {
+ } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
Theme::get_default()->get_font_size_list(get_class(), &sn);
- } else if (pf == "add_constant_override" || pf == "has_constant" || pf == "has_constant_override" || pf == "get_constant") {
+ } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
Theme::get_default()->get_constant_list(get_class(), &sn);
}
@@ -2694,17 +2707,14 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
}
}
-String Control::get_configuration_warning() const {
- String warning = CanvasItem::get_configuration_warning();
+TypedArray<String> Control::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".");
+ warnings.push_back(TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
}
- return warning;
+ return warnings;
}
void Control::set_clip_contents(bool p_clip) {
@@ -2808,6 +2818,13 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_theme_color_override", "name", "color"), &Control::add_theme_color_override);
ClassDB::bind_method(D_METHOD("add_theme_constant_override", "name", "constant"), &Control::add_theme_constant_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_icon_override", "name"), &Control::remove_theme_icon_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_stylebox_override", "name"), &Control::remove_theme_style_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_font_override", "name"), &Control::remove_theme_font_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_font_size_override", "name"), &Control::remove_theme_font_size_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_color_override", "name"), &Control::remove_theme_color_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_constant_override", "name"), &Control::remove_theme_constant_override);
+
ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "node_type"), &Control::get_theme_icon, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "node_type"), &Control::get_theme_stylebox, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_theme_font", "name", "node_type"), &Control::get_theme_font, DEFVAL(""));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index ac2a1b35de..1f397df589 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -171,21 +171,22 @@ private:
Size2 last_minimum_size;
bool updating_last_minimum_size = false;
- float offset[4] = { 0.0, 0.0, 0.0, 0.0 };
- float anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
+ real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
+ real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
FocusMode focus_mode = FOCUS_NONE;
GrowDirection h_grow = GROW_DIRECTION_END;
GrowDirection v_grow = GROW_DIRECTION_END;
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
- float rotation = 0;
+ real_t rotation = 0.0;
Vector2 scale = Vector2(1, 1);
Vector2 pivot_offset;
+ bool size_warning = true;
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
- float expand = 1;
+ real_t expand = 1.0;
Point2 custom_minimum_size;
MouseFilter mouse_filter = MOUSE_FILTER_STOP;
@@ -223,23 +224,23 @@ private:
// used internally
Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform);
- void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
+ void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest);
Control *_get_focus_neighbor(Side p_side, int p_count = 0);
- void _set_anchor(Side p_side, float p_anchor);
+ void _set_anchor(Side p_side, real_t p_anchor);
void _set_position(const Point2 &p_point);
void _set_global_position(const Point2 &p_point);
void _set_size(const Size2 &p_size);
void _theme_changed();
- void _change_notify_offsets();
void _update_minimum_size();
+ void _clear_size_warning();
void _update_scroll();
- void _compute_offsets(Rect2 p_rect, const float p_anchors[4], float (&r_offsets)[4]);
- void _compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r_anchors)[4]);
+ void _compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]);
+ void _compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]);
void _size_changed();
String _get_tooltip() const;
@@ -324,8 +325,8 @@ public:
virtual Rect2 _edit_get_rect() const override;
virtual bool _edit_use_rect() const override;
- virtual void _edit_set_rotation(float p_rotation) override;
- virtual float _edit_get_rotation() const override;
+ virtual void _edit_set_rotation(real_t p_rotation) override;
+ virtual real_t _edit_get_rotation() const override;
virtual bool _edit_use_rotation() const override;
virtual void _edit_set_pivot(const Point2 &p_pivot) override;
@@ -363,13 +364,13 @@ public:
void set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
void set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
- void set_anchor(Side p_side, float p_anchor, bool p_keep_offset = true, bool p_push_opposite_anchor = true);
- float get_anchor(Side p_side) const;
+ void set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset = true, bool p_push_opposite_anchor = true);
+ real_t get_anchor(Side p_side) const;
- void set_offset(Side p_side, float p_value);
- float get_offset(Side p_side) const;
+ void set_offset(Side p_side, real_t p_value);
+ real_t get_offset(Side p_side) const;
- void set_anchor_and_offset(Side p_side, float p_anchor, float p_pos, bool p_push_opposite_anchor = true);
+ void set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor = true);
void set_begin(const Point2 &p_point); // helper
void set_end(const Point2 &p_point); // helper
@@ -394,10 +395,10 @@ public:
void set_rect(const Rect2 &p_rect); // Reset anchors to begin and set rect, for faster container children sorting.
- void set_rotation(float p_radians);
- void set_rotation_degrees(float p_degrees);
- float get_rotation() const;
- float get_rotation_degrees() const;
+ void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
+ real_t get_rotation() const;
+ real_t get_rotation_degrees() const;
void set_h_grow_direction(GrowDirection p_direction);
GrowDirection get_h_grow_direction() const;
@@ -420,8 +421,8 @@ public:
void set_v_size_flags(int p_flags);
int get_v_size_flags() const;
- void set_stretch_ratio(float p_ratio);
- float get_stretch_ratio() const;
+ void set_stretch_ratio(real_t p_ratio);
+ real_t get_stretch_ratio() const;
void minimum_size_changed();
@@ -458,6 +459,13 @@ public:
void add_theme_color_override(const StringName &p_name, const Color &p_color);
void add_theme_constant_override(const StringName &p_name, int p_constant);
+ void remove_theme_icon_override(const StringName &p_name);
+ void remove_theme_style_override(const StringName &p_name);
+ void remove_theme_font_override(const StringName &p_name);
+ void remove_theme_font_size_override(const StringName &p_name);
+ void remove_theme_color_override(const StringName &p_name);
+ void remove_theme_constant_override(const StringName &p_name);
+
Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
@@ -516,7 +524,7 @@ public:
bool is_visibility_clip_disabled() const;
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Control() {}
};
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 773c609a70..b6884bd37d 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -256,7 +256,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
if (p_cancel == "") {
- c = RTR("Cancel");
+ c = TTRC("Cancel");
}
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
@@ -292,8 +292,6 @@ void AcceptDialog::set_swap_cancel_ok(bool p_swap) {
}
AcceptDialog::AcceptDialog() {
- parent_visible = nullptr;
-
set_wrap_controls(true);
set_visible(false);
set_transient(true);
@@ -319,14 +317,13 @@ AcceptDialog::AcceptDialog() {
hbc->add_spacer();
ok = memnew(Button);
- ok->set_text(RTR("OK"));
+ ok->set_text(TTRC("OK"));
hbc->add_child(ok);
hbc->add_spacer();
ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
- hide_on_ok = true;
- set_title(RTR("Alert!"));
+ set_title(TTRC("Alert!"));
connect("window_input", callable_mp(this, &AcceptDialog::_input_from_window));
}
@@ -345,7 +342,7 @@ Button *ConfirmationDialog::get_cancel_button() {
}
ConfirmationDialog::ConfirmationDialog() {
- set_title(RTR("Please Confirm..."));
+ set_title(TTRC("Please Confirm..."));
#ifdef TOOLS_ENABLED
set_min_size(Size2(200, 70) * EDSCALE);
#endif
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index e450a3c30a..b072055d49 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -44,12 +44,12 @@ class LineEdit;
class AcceptDialog : public Window {
GDCLASS(AcceptDialog, Window);
- Window *parent_visible;
+ Window *parent_visible = nullptr;
Panel *bg;
HBoxContainer *hbc;
Label *label;
Button *ok;
- bool hide_on_ok;
+ bool hide_on_ok = true;
void _custom_action(const String &p_action);
void _update_child_rects();
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 3a0350b9fb..5409b44b9e 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -57,6 +57,14 @@ void FileDialog::_theme_changed() {
dir_up->add_theme_color_override("icon_hover_color", font_hover_color);
dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color);
+ dir_prev->add_theme_color_override("icon_color_normal", font_color);
+ dir_prev->add_theme_color_override("icon_color_hover", font_hover_color);
+ dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
+ dir_next->add_theme_color_override("icon_color_normal", font_color);
+ dir_next->add_theme_color_override("icon_color_hover", font_hover_color);
+ dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
refresh->add_theme_color_override("icon_normal_color", font_color);
refresh->add_theme_color_override("icon_hover_color", font_hover_color);
refresh->add_theme_color_override("icon_pressed_color", font_pressed_color);
@@ -74,6 +82,13 @@ void FileDialog::_notification(int p_what) {
}
if (p_what == NOTIFICATION_ENTER_TREE) {
dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog"));
+ if (vbox->is_layout_rtl()) {
+ dir_prev->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+ dir_next->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+ } else {
+ dir_prev->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+ dir_next->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+ }
refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog"));
show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog"));
_theme_changed();
@@ -81,6 +96,8 @@ void FileDialog::_notification(int p_what) {
}
void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && has_focus()) {
if (k->is_pressed()) {
@@ -144,6 +161,7 @@ void FileDialog::_dir_entered(String p_dir) {
file->set_text("");
invalidate();
update_dir();
+ _push_history();
}
void FileDialog::_file_entered(const String &p_file) {
@@ -177,6 +195,21 @@ void FileDialog::_post_popup() {
} else {
file_box->set_visible(true);
}
+
+ local_history.clear();
+ local_history_pos = -1;
+ _push_history();
+}
+
+void FileDialog::_push_history() {
+ local_history.resize(local_history_pos + 1);
+ String new_path = dir_access->get_current_dir();
+ if (local_history.size() == 0 || new_path != local_history[local_history_pos]) {
+ local_history.push_back(new_path);
+ local_history_pos++;
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(true);
+ }
}
void FileDialog::_action_pressed() {
@@ -272,7 +305,7 @@ void FileDialog::_action_pressed() {
}
if (dir_access->file_exists(f)) {
- confirm_save->set_text(RTR("File exists, overwrite?"));
+ confirm_save->set_text(TTRC("File exists, overwrite?"));
confirm_save->popup_centered(Size2(200, 80));
} else {
emit_signal("file_selected", f);
@@ -316,6 +349,35 @@ void FileDialog::_go_up() {
dir_access->change_dir("..");
update_file_list();
update_dir();
+ _push_history();
+}
+
+void FileDialog::_go_back() {
+ if (local_history_pos <= 0) {
+ return;
+ }
+
+ local_history_pos--;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(local_history_pos == local_history.size() - 1);
+}
+
+void FileDialog::_go_forward() {
+ if (local_history_pos == local_history.size() - 1) {
+ return;
+ }
+
+ local_history_pos++;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(local_history_pos == local_history.size() - 1);
}
void FileDialog::deselect_all() {
@@ -329,10 +391,10 @@ void FileDialog::deselect_all() {
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(TTRC("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -356,7 +418,7 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok_button()->set_text(RTR("Select This Folder"));
+ get_ok_button()->set_text(TTRC("Select This Folder"));
}
get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -377,6 +439,7 @@ void FileDialog::_tree_item_activated() {
}
call_deferred("_update_file_list");
call_deferred("_update_dir");
+ _push_history();
} else {
_action_pressed();
}
@@ -415,6 +478,13 @@ void FileDialog::update_file_list() {
bool is_hidden;
String item;
+ if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) {
+ message->hide();
+ } else {
+ message->set_text(TTRC("You don't have permission to access contents of this folder."));
+ message->show();
+ }
+
while ((item = dir_access->get_next()) != "") {
if (item == "." || item == "..") {
continue;
@@ -549,7 +619,7 @@ void FileDialog::update_filters() {
all_filters += ", ...";
}
- filter->add_item(RTR("All Recognized") + " (" + all_filters + ")");
+ filter->add_item(String(TTRC("All Recognized")) + " (" + all_filters + ")");
}
for (int i = 0; i < filters.size(); i++) {
String flt = filters[i].get_slice(";", 0).strip_edges();
@@ -561,7 +631,7 @@ void FileDialog::update_filters() {
}
}
- filter->add_item(RTR("All Files (*)"));
+ filter->add_item(TTRC("All Files (*)"));
}
void FileDialog::clear_filters() {
@@ -602,6 +672,7 @@ void FileDialog::set_current_dir(const String &p_dir) {
dir_access->change_dir(p_dir);
update_dir();
invalidate();
+ _push_history();
}
void FileDialog::set_current_file(const String &p_file) {
@@ -646,37 +717,37 @@ void FileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open a File"));
+ set_title(TTRC("Open a File"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open File(s)"));
+ set_title(TTRC("Open File(s)"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(TTRC("Select Current Folder"));
if (mode_overrides_title) {
- set_title(RTR("Open a Directory"));
+ set_title(TTRC("Open a Directory"));
}
makedir->show();
break;
case FILE_MODE_OPEN_ANY:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open a File or Directory"));
+ set_title(TTRC("Open a File or Directory"));
}
makedir->show();
break;
case FILE_MODE_SAVE_FILE:
- get_ok_button()->set_text(RTR("Save"));
+ get_ok_button()->set_text(TTRC("Save"));
if (mode_overrides_title) {
- set_title(RTR("Save a File"));
+ set_title(TTRC("Save a File"));
}
makedir->show();
break;
@@ -731,12 +802,13 @@ FileDialog::Access FileDialog::get_access() const {
}
void FileDialog::_make_dir_confirm() {
- Error err = dir_access->make_dir(makedirname->get_text());
+ Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
if (err == OK) {
- dir_access->change_dir(makedirname->get_text());
+ dir_access->change_dir(makedirname->get_text().strip_edges());
invalidate();
update_filters();
update_dir();
+ _push_history();
} else {
mkdirerr->popup_centered(Size2(250, 50));
}
@@ -754,6 +826,7 @@ void FileDialog::_select_drive(int p_idx) {
file->set_text("");
invalidate();
update_dir();
+ _push_history();
}
void FileDialog::_update_drives() {
@@ -852,24 +925,32 @@ void FileDialog::set_default_show_hidden_files(bool p_show) {
FileDialog::FileDialog() {
show_hidden_files = default_show_hidden_files;
- mode_overrides_title = true;
-
vbox = memnew(VBoxContainer);
add_child(vbox);
vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
mode = FILE_MODE_SAVE_FILE;
- set_title(RTR("Save a File"));
+ set_title(TTRC("Save a File"));
HBoxContainer *hbc = memnew(HBoxContainer);
+ dir_prev = memnew(Button);
+ dir_prev->set_flat(true);
+ dir_prev->set_tooltip(TTRC("Go to previous folder."));
+ dir_next = memnew(Button);
+ dir_next->set_flat(true);
+ dir_next->set_tooltip(TTRC("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(RTR("Go to parent folder."));
+ dir_up->set_tooltip(TTRC("Go to parent folder."));
+ hbc->add_child(dir_prev);
+ hbc->add_child(dir_next);
hbc->add_child(dir_up);
+ dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back));
+ dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward));
dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up));
- hbc->add_child(memnew(Label(RTR("Path:"))));
+ hbc->add_child(memnew(Label(TTRC("Path:"))));
drives_container = memnew(HBoxContainer);
hbc->add_child(drives_container);
@@ -885,7 +966,7 @@ FileDialog::FileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(RTR("Refresh files."));
+ refresh->set_tooltip(TTRC("Refresh files."));
refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list));
hbc->add_child(refresh);
@@ -893,7 +974,7 @@ FileDialog::FileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip(TTRC("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files));
hbc->add_child(show_hidden);
@@ -901,17 +982,24 @@ FileDialog::FileDialog() {
hbc->add_child(shortcuts_container);
makedir = memnew(Button);
- makedir->set_text(RTR("Create Folder"));
+ makedir->set_text(TTRC("Create Folder"));
makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir));
hbc->add_child(makedir);
vbox->add_child(hbc);
tree = memnew(Tree);
tree->set_hide_root(true);
- vbox->add_margin_child(RTR("Directories & Files:"), tree, true);
+ vbox->add_margin_child(TTRC("Directories & Files:"), tree, true);
+
+ message = memnew(Label);
+ message->hide();
+ message->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ message->set_align(Label::ALIGN_CENTER);
+ message->set_valign(Label::VALIGN_CENTER);
+ tree->add_child(message);
file_box = memnew(HBoxContainer);
- file_box->add_child(memnew(Label(RTR("File:"))));
+ file_box->add_child(memnew(Label(TTRC("File:"))));
file = memnew(LineEdit);
file->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
file->set_stretch_ratio(4);
@@ -925,7 +1013,6 @@ FileDialog::FileDialog() {
vbox->add_child(file_box);
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- access = ACCESS_RESOURCES;
_update_drives();
connect("confirmed", callable_mp(this, &FileDialog::_action_pressed));
@@ -944,22 +1031,22 @@ FileDialog::FileDialog() {
confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed));
makedialog = memnew(ConfirmationDialog);
- makedialog->set_title(RTR("Create Folder"));
+ makedialog->set_title(TTRC("Create Folder"));
VBoxContainer *makevb = memnew(VBoxContainer);
makedialog->add_child(makevb);
makedirname = memnew(LineEdit);
makedirname->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
- makevb->add_margin_child(RTR("Name:"), makedirname);
+ makevb->add_margin_child(TTRC("Name:"), makedirname);
add_child(makedialog);
makedialog->register_text_enter(makedirname);
makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm));
mkdirerr = memnew(AcceptDialog);
- mkdirerr->set_text(RTR("Could not create folder."));
+ mkdirerr->set_text(TTRC("Could not create folder."));
add_child(mkdirerr);
exterr = memnew(AcceptDialog);
- exterr->set_text(RTR("Must use a valid extension."));
+ exterr->set_text(TTRC("Must use a valid extension."));
add_child(exterr);
update_filters();
@@ -967,7 +1054,6 @@ FileDialog::FileDialog() {
set_hide_on_ok(false);
- invalidated = true;
if (register_func) {
register_func(this);
}
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 626bb78d42..4996f00cb3 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -69,7 +69,7 @@ private:
LineEdit *makedirname;
Button *makedir;
- Access access;
+ Access access = ACCESS_RESOURCES;
//Button *action;
VBoxContainer *vbox;
FileMode mode;
@@ -86,6 +86,10 @@ private:
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
+ Label *message;
+
+ Button *dir_prev;
+ Button *dir_next;
Button *dir_up;
Button *refresh;
@@ -93,12 +97,16 @@ private:
Vector<String> filters;
- bool mode_overrides_title;
+ Vector<String> local_history;
+ int local_history_pos = 0;
+ void _push_history();
+
+ bool mode_overrides_title = true;
static bool default_show_hidden_files;
- bool show_hidden_files;
+ bool show_hidden_files = false;
- bool invalidated;
+ bool invalidated = true;
void update_dir();
void update_file_name();
@@ -119,6 +127,8 @@ private:
void _make_dir();
void _make_dir_confirm();
void _go_up();
+ void _go_back();
+ void _go_forward();
void _update_drives();
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index d18fff887d..e72709e847 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -42,8 +42,6 @@
#endif
GradientEdit::GradientEdit() {
- grabbed = -1;
- grabbing = false;
set_focus_mode(FOCUS_ALL);
popup = memnew(PopupPanel);
@@ -94,6 +92,8 @@ GradientEdit::~GradientEdit() {
}
void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && grabbed != -1) {
diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h
index 189b33f563..eb7367d598 100644
--- a/scene/gui/gradient_edit.h
+++ b/scene/gui/gradient_edit.h
@@ -44,8 +44,8 @@ class GradientEdit : public Control {
Ref<ImageTexture> checker;
- bool grabbing;
- int grabbed;
+ bool grabbing = false;
+ int grabbed = -1;
Vector<Gradient::Point> points;
void _draw_checker(int x, int y, int w, int h);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index d7602bd7cf..06c9cf1b63 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -154,6 +154,8 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position)
}
void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
if (!ge->is_minimap_enabled()) {
return;
}
@@ -161,7 +163,7 @@ void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
Ref<InputEventMouseMotion> mm = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
is_pressing = true;
@@ -180,7 +182,12 @@ void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
accept_event();
} else if (mm.is_valid() && is_pressing) {
if (is_resizing) {
- ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative());
+ // Prevent setting minimap wider than GraphEdit
+ Vector2 new_minimap_size;
+ new_minimap_size.x = MIN(get_size().x - mm->get_relative().x, ge->get_size().x - 2.0 * minimap_padding.x);
+ new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y);
+ ge->set_minimap_size(new_minimap_size);
+
update();
} else {
Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
@@ -385,6 +392,15 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
connections_layer->update();
}
+void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) {
+ GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
+ ERR_FAIL_COND(!gn);
+ top_layer->update();
+ minimap->update();
+ update();
+ connections_layer->update();
+}
+
void GraphEdit::add_child_notify(Node *p_child) {
Control::add_child_notify(p_child);
@@ -394,6 +410,7 @@ void GraphEdit::add_child_notify(Node *p_child) {
if (gn) {
gn->set_scale(Vector2(zoom, zoom));
gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved), varray(gn));
+ gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated), varray(gn));
gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised), varray(gn));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update));
gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update));
@@ -419,6 +436,7 @@ void GraphEdit::remove_child_notify(Node *p_child) {
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
if (gn) {
gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
+ gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated));
gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised));
// In case of the whole GraphEdit being destroyed these references can already be freed.
@@ -519,14 +537,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (is_in_hot_zone(pos, p_point)) {
+ if (is_in_hot_zone(pos / zoom, p_point / zoom)) {
return true;
}
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (is_in_hot_zone(pos, p_point)) {
+ if (is_in_hot_zone(pos / zoom, p_point / zoom)) {
return true;
}
}
@@ -537,10 +555,10 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
connecting_valid = false;
Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
- click_pos = mb->get_position();
+ 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) {
@@ -549,7 +567,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (is_in_hot_zone(pos, click_pos)) {
+ if (is_in_hot_zone(pos / zoom, click_pos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
@@ -591,7 +609,7 @@ 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();
- if (is_in_hot_zone(pos, click_pos)) {
+ if (is_in_hot_zone(pos / zoom, click_pos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
@@ -640,11 +658,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_target = false;
top_layer->update();
minimap->update();
- connecting_valid = just_disconnected || click_pos.distance_to(connecting_to) > 20.0 * zoom;
+ connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0 * zoom;
if (connecting_valid) {
Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
- Vector2 mpos = mm->get_position();
+ Vector2 mpos = mm->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn) {
@@ -655,7 +673,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -667,7 +685,7 @@ 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();
int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -680,7 +698,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (connecting_valid) {
if (connecting && connecting_target) {
String from = connecting_from;
@@ -749,6 +767,11 @@ bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) {
continue;
}
Rect2 rect = child->get_rect();
+
+ // To prevent intersections with other nodes.
+ rect.position *= zoom;
+ rect.size *= zoom;
+
if (rect.has_point(p_mouse_pos)) {
//check sub-controls
Vector2 subpos = p_mouse_pos - rect.position;
@@ -1045,8 +1068,10 @@ void GraphEdit::set_selected(Node *p_child) {
}
void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
+ if (mm.is_valid() && (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
}
@@ -1102,7 +1127,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
gn->set_selected(box_selection_mode_additive);
} else {
- bool select = (previus_selected.find(gn) != nullptr);
+ bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal("node_deselected", gn);
} else if (!gn->is_selected() && select) {
@@ -1118,7 +1143,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> b = p_ev;
if (b.is_valid()) {
- if (b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
if (box_selecting) {
box_selecting = false;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1127,7 +1152,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previus_selected.find(gn) != nullptr);
+ bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal("node_deselected", gn);
} else if (!gn->is_selected() && select) {
@@ -1148,7 +1173,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
}
- if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && dragging) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && dragging) {
if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
//deselect current node
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1187,7 +1212,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
connections_layer->update();
}
- if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
GraphNode *gn = nullptr;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1198,7 +1223,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- if (gn_selected->has_point(b->get_position() - gn_selected->get_position())) {
+ if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
gn = gn_selected;
break;
}
@@ -1252,29 +1277,29 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
box_selecting_from = b->get_position();
if (b->get_control()) {
box_selection_mode_additive = true;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previus_selected.push_back(gn2);
+ previous_selected.push_back(gn2);
}
} else if (b->get_shift()) {
box_selection_mode_additive = false;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previus_selected.push_back(gn2);
+ previous_selected.push_back(gn2);
}
} else {
box_selection_mode_additive = true;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2) {
@@ -1289,55 +1314,40 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
}
- if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && box_selecting) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && box_selecting) {
box_selecting = false;
- previus_selected.clear();
+ box_selecting_rect = Rect2();
+ previous_selected.clear();
top_layer->update();
minimap->update();
}
- if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
- //too difficult to get right
- //set_zoom(zoom*ZOOM_SCALE);
- }
-
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) {
- //too difficult to get right
- //set_zoom(zoom/ZOOM_SCALE);
- }
- if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom_custom(zoom * ZOOM_SCALE, b->get_position());
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom_custom(zoom / ZOOM_SCALE, b->get_position());
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8);
- }
- if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8);
}
}
- Ref<InputEventKey> k = p_ev;
-
- if (k.is_valid()) {
- if (k->get_keycode() == KEY_D && k->is_pressed() && k->get_command()) {
+ if (p_ev->is_pressed()) {
+ if (p_ev->is_action("ui_graph_duplicate")) {
emit_signal("duplicate_nodes_request");
accept_event();
- }
-
- if (k->get_keycode() == KEY_C && k->is_pressed() && k->get_command()) {
+ } else if (p_ev->is_action("ui_copy")) {
emit_signal("copy_nodes_request");
accept_event();
- }
-
- if (k->get_keycode() == KEY_V && k->is_pressed() && k->get_command()) {
+ } else if (p_ev->is_action("ui_paste")) {
emit_signal("paste_nodes_request");
accept_event();
- }
-
- if (k->get_keycode() == KEY_DELETE && k->is_pressed()) {
+ } else if (p_ev->is_action("ui_graph_delete")) {
emit_signal("delete_nodes_request");
accept_event();
}
@@ -1550,7 +1560,12 @@ bool GraphEdit::is_minimap_enabled() const {
}
void GraphEdit::_minimap_toggled() {
- minimap->update();
+ if (is_minimap_enabled()) {
+ minimap->set_visible(true);
+ minimap->update();
+ } else {
+ minimap->set_visible(false);
+ }
}
void GraphEdit::set_connection_lines_thickness(float p_thickness) {
@@ -1657,8 +1672,6 @@ void GraphEdit::_bind_methods() {
GraphEdit::GraphEdit() {
set_focus_mode(FOCUS_ALL);
- awaiting_scroll_offset_update = false;
- top_layer = nullptr;
top_layer = memnew(GraphEditFilter(this));
add_child(top_layer);
top_layer->set_mouse_filter(MOUSE_FILTER_PASS);
@@ -1681,13 +1694,6 @@ GraphEdit::GraphEdit() {
v_scroll->set_name("_v_scroll");
top_layer->add_child(v_scroll);
- updating = false;
- connecting = false;
- right_disconnects = false;
-
- box_selecting = false;
- dragging = false;
-
//set large minmax so it can scroll even if not resized yet
h_scroll->set_min(-10000);
h_scroll->set_max(10000);
@@ -1698,8 +1704,6 @@ GraphEdit::GraphEdit() {
h_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
v_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved));
- zoom = 1;
-
zoom_hb = memnew(HBoxContainer);
top_layer->add_child(zoom_hb);
zoom_hb->set_position(Vector2(10, 10));
@@ -1768,7 +1772,5 @@ GraphEdit::GraphEdit() {
minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET);
minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw));
- setting_scroll_ofs = false;
- just_disconnected = false;
set_clip_contents(true);
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 4525152bd5..fa3b113705 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -99,9 +99,9 @@ public:
struct Connection {
StringName from;
StringName to;
- int from_port;
- int to_port;
- float activity;
+ int from_port = 0;
+ int to_port = 0;
+ float activity = 0.0;
};
private:
@@ -121,41 +121,41 @@ private:
HScrollBar *h_scroll;
VScrollBar *v_scroll;
- float port_grab_distance_horizontal;
+ float port_grab_distance_horizontal = 0.0;
float port_grab_distance_vertical;
- bool connecting;
+ bool connecting = false;
String connecting_from;
- bool connecting_out;
- int connecting_index;
- int connecting_type;
+ bool connecting_out = false;
+ int connecting_index = 0;
+ int connecting_type = 0;
Color connecting_color;
- bool connecting_target;
+ bool connecting_target = false;
Vector2 connecting_to;
String connecting_target_to;
int connecting_target_index;
- bool just_disconnected;
- bool connecting_valid;
+ bool just_disconnected = false;
+ bool connecting_valid = false;
Vector2 click_pos;
- bool dragging;
- bool just_selected;
- bool moving_selection;
+ bool dragging = false;
+ bool just_selected = false;
+ bool moving_selection = false;
Vector2 drag_accum;
- float zoom;
+ float zoom = 1.0;
- bool box_selecting;
- bool box_selection_mode_additive;
+ bool box_selecting = false;
+ bool box_selection_mode_additive = false;
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
- List<GraphNode *> previus_selected;
+ List<GraphNode *> previous_selected;
- bool setting_scroll_ofs;
- bool right_disconnects;
- bool updating;
- bool awaiting_scroll_offset_update;
+ bool setting_scroll_ofs = false;
+ bool right_disconnects = false;
+ bool updating = false;
+ bool awaiting_scroll_offset_update = false;
List<Connection> connections;
float lines_thickness = 2.0f;
@@ -167,6 +167,7 @@ private:
void _graph_node_raised(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 _scroll_moved(double);
@@ -194,7 +195,7 @@ private:
uint32_t type_a;
uint32_t type_b;
};
- uint64_t key;
+ uint64_t key = 0;
};
bool operator<(const ConnType &p_type) const {
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 6a83042b00..7d5c53effe 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -32,6 +32,12 @@
#include "core/string/translation.h"
+struct _MinSizeCache {
+ int min_size;
+ bool will_stretch;
+ int final_size;
+};
+
bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
String str = p_name;
if (str.begins_with("opentype_features/")) {
@@ -51,7 +57,7 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -171,15 +177,23 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
}
void GraphNode::_resort() {
- int sep = get_theme_constant("separation");
+ /** First pass, determine minimum size AND amount of stretchable elements */
+
+ Size2i new_size = get_size();
Ref<StyleBox> sb = get_theme_stylebox("frame");
- bool first = true;
- Size2 minsize;
+ int sep = get_theme_constant("separation");
+
+ bool first = true;
+ int children_count = 0;
+ int stretch_min = 0;
+ int stretch_avail = 0;
+ float stretch_ratio_total = 0;
+ Map<Control *, _MinSizeCache> min_size_cache;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c) {
+ if (!c || !c->is_visible_in_tree()) {
continue;
}
if (c->is_set_as_top_level()) {
@@ -187,38 +201,120 @@ void GraphNode::_resort() {
}
Size2i size = c->get_combined_minimum_size();
+ _MinSizeCache msc;
- minsize.y += size.y;
- minsize.x = MAX(minsize.x, size.x);
+ stretch_min += size.height;
+ msc.min_size = size.height;
+ msc.will_stretch = c->get_v_size_flags() & SIZE_EXPAND;
- if (first) {
- first = false;
- } else {
- minsize.y += sep;
+ if (msc.will_stretch) {
+ stretch_avail += msc.min_size;
+ stretch_ratio_total += c->get_stretch_ratio();
}
+ msc.final_size = msc.min_size;
+ min_size_cache[c] = msc;
+ children_count++;
}
- int vofs = 0;
- int w = get_size().x - sb->get_minimum_size().x;
+ if (children_count == 0) {
+ return;
+ }
+
+ int stretch_max = new_size.height - (children_count - 1) * sep;
+ int stretch_diff = stretch_max - stretch_min;
+ if (stretch_diff < 0) {
+ //avoid negative stretch space
+ stretch_diff = 0;
+ }
+
+ stretch_avail += stretch_diff - sb->get_margin(SIDE_BOTTOM) - sb->get_margin(SIDE_TOP); //available stretch space.
+ /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable
+ elements exist */
+
+ while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist
+ bool refit_successful = true; //assume refit-test will go well
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (!c || !c->is_visible_in_tree()) {
+ continue;
+ }
+ if (c->is_set_as_top_level()) {
+ continue;
+ }
+
+ ERR_FAIL_COND(!min_size_cache.has(c));
+ _MinSizeCache &msc = min_size_cache[c];
+
+ if (msc.will_stretch) { //wants to stretch
+ //let's see if it can really stretch
+
+ int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
+ if (final_pixel_size < msc.min_size) {
+ //if available stretching area is too small for widget,
+ //then remove it from stretching area
+ msc.will_stretch = false;
+ stretch_ratio_total -= c->get_stretch_ratio();
+ refit_successful = false;
+ stretch_avail -= msc.min_size;
+ msc.final_size = msc.min_size;
+ break;
+ } else {
+ msc.final_size = final_pixel_size;
+ }
+ }
+ }
+
+ if (refit_successful) { //uf refit went well, break
+ break;
+ }
+ }
+
+ /** Final pass, draw and stretch elements **/
+ int ofs = sb->get_margin(SIDE_TOP);
+
+ first = true;
+ int idx = 0;
cache_y.clear();
+ int w = new_size.width - sb->get_minimum_size().x;
+
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c) {
+ if (!c || !c->is_visible_in_tree()) {
continue;
}
if (c->is_set_as_top_level()) {
continue;
}
- Size2i size = c->get_combined_minimum_size();
+ _MinSizeCache &msc = min_size_cache[c];
+
+ if (first) {
+ first = false;
+ } else {
+ ofs += sep;
+ }
- Rect2 r(sb->get_margin(SIDE_LEFT), sb->get_margin(SIDE_TOP) + vofs, w, size.y);
+ int from = ofs;
+ int to = ofs + msc.final_size;
+
+ if (msc.will_stretch && idx == children_count - 1) {
+ //adjust so the last one always fits perfect
+ //compensating for numerical imprecision
+
+ to = new_size.height - sb->get_margin(SIDE_BOTTOM);
+ }
- fit_child_in_rect(c, r);
- cache_y.push_back(vofs + size.y * 0.5);
+ int size = to - from;
- vofs += size.y + sep;
+ Rect2 rect(sb->get_margin(SIDE_LEFT), from, w, size);
+
+ fit_child_in_rect(c, rect);
+ cache_y.push_back(from - sb->get_margin(SIDE_TOP) + size * 0.5);
+
+ ofs = to;
+ idx++;
}
update();
@@ -384,6 +480,8 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C
slot_info[p_idx] = s;
update();
connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
}
void GraphNode::clear_slot(int p_idx) {
@@ -484,7 +582,6 @@ void GraphNode::set_title(const String &p_title) {
_shape();
update();
- _change_notify("title");
minimum_size_changed();
}
@@ -707,11 +804,13 @@ Color GraphNode::get_connection_output_color(int p_idx) {
}
void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node.");
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y);
if (close_rect.size != Size2() && close_rect.has_point(mpos)) {
//send focus to parent
@@ -734,7 +833,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
emit_signal("raise_request");
}
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
resizing = false;
}
}
@@ -838,6 +937,7 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
+ ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
ADD_SIGNAL(MethodInfo("raise_request"));
ADD_SIGNAL(MethodInfo("close_request"));
@@ -850,12 +950,5 @@ void GraphNode::_bind_methods() {
GraphNode::GraphNode() {
title_buf.instance();
- overlay = OVERLAY_DISABLED;
- show_close = false;
- connpos_dirty = true;
set_mouse_filter(MOUSE_FILTER_STOP);
- comment = false;
- resizable = false;
- resizing = false;
- selected = false;
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index cf66586e6b..1bc54dddb7 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -46,23 +46,14 @@ public:
private:
struct Slot {
- bool enable_left;
- int type_left;
- Color color_left;
- bool enable_right;
- int type_right;
- Color color_right;
+ bool enable_left = false;
+ int type_left = 0;
+ Color color_left = Color(1, 1, 1, 1);
+ bool enable_right = false;
+ int type_right = 0;
+ Color color_right = Color(1, 1, 1, 1);
Ref<Texture2D> custom_slot_left;
Ref<Texture2D> custom_slot_right;
-
- Slot() {
- enable_left = false;
- type_left = 0;
- color_left = Color(1, 1, 1, 1);
- enable_right = false;
- type_right = 0;
- color_right = Color(1, 1, 1, 1);
- }
};
String title;
@@ -72,12 +63,12 @@ private:
String language;
TextDirection text_direction = TEXT_DIRECTION_AUTO;
- bool show_close;
+ bool show_close = false;
Vector2 position_offset;
- bool comment;
- bool resizable;
+ bool comment = false;
+ bool resizable = false;
- bool resizing;
+ bool resizing = false;
Vector2 resizing_from;
Vector2 resizing_from_size;
@@ -87,7 +78,7 @@ private:
struct ConnCache {
Vector2 pos;
- int type;
+ int type = 0;
Color color;
};
@@ -96,16 +87,16 @@ private:
Map<int, Slot> slot_info;
- bool connpos_dirty;
+ bool connpos_dirty = true;
void _connpos_update();
void _resort();
void _shape();
Vector2 drag_from;
- bool selected;
+ bool selected = false;
- Overlay overlay;
+ Overlay overlay = OVERLAY_DISABLED;
protected:
void _gui_input(const Ref<InputEvent> &p_ev);
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 11335db54a..541925a802 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -261,6 +261,4 @@ Size2 GridContainer::get_minimum_size() const {
return ms;
}
-GridContainer::GridContainer() {
- columns = 1;
-}
+GridContainer::GridContainer() {}
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index 8045c94b9a..9b43a5bc7e 100644
--- a/scene/gui/grid_container.h
+++ b/scene/gui/grid_container.h
@@ -36,7 +36,7 @@
class GridContainer : public Container {
GDCLASS(GridContainer, Container);
- int columns;
+ int columns = 1;
protected:
void _notification(int p_what);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index bd57817bd3..86d070f9b1 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -530,6 +530,8 @@ Size2 ItemList::Item::get_icon_size() const {
}
void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
double prev_scroll = scroll_bar->get_value();
Ref<InputEventMouseMotion> mm = p_event;
@@ -540,7 +542,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
select(defer_select_single, true);
emit_signal("multi_selected", defer_select_single, true);
@@ -548,7 +550,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) {
+ if (mb.is_valid() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == MOUSE_BUTTON_RIGHT)) && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
Ref<StyleBox> bg = get_theme_stylebox("bg");
@@ -594,16 +596,16 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
}
} else {
- if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
defer_select_single = i;
return;
}
- if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) {
+ if (items[i].selected && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
} else {
bool selected = items[i].selected;
@@ -618,7 +620,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
} else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
emit_signal("item_activated", i);
@@ -628,7 +630,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("rmb_clicked", mb->get_position());
return;
@@ -637,10 +639,10 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
// Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting.
emit_signal("nothing_selected");
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
scroll_bar->set_value(scroll_bar->get_value() - scroll_bar->get_page() * mb->get_factor() / 8);
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * mb->get_factor() / 8);
}
@@ -768,7 +770,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
} else if (p_event->is_action("ui_accept")) {
- search_string = ""; //any mousepress cance
+ search_string = ""; //any mousepress cancels
if (current >= 0 && current < items.size()) {
emit_signal("item_activated", current);
@@ -883,6 +885,8 @@ void ItemList::_notification(int p_what) {
int vseparation = get_theme_constant("vseparation");
int icon_margin = get_theme_constant("icon_margin");
int line_separation = get_theme_constant("line_separation");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox("selected_focus") : get_theme_stylebox("selected");
Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox("cursor") : get_theme_stylebox("cursor_unfocused");
@@ -899,7 +903,7 @@ void ItemList::_notification(int p_what) {
}
if (shape_changed) {
- float max_column_width = 0;
+ float max_column_width = 0.0;
//1- compute item minimum sizes
for (int i = 0; i < items.size(); i++) {
@@ -1204,6 +1208,10 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_width(max_len);
items.write[i].text_buf->set_align(HALIGN_CENTER);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ }
+
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
} else {
if (fixed_column_width > 0) {
@@ -1230,6 +1238,11 @@ void ItemList::_notification(int p_what) {
} else {
items.write[i].text_buf->set_align(HALIGN_LEFT);
}
+
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
+ }
+
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
}
}
@@ -1615,34 +1628,12 @@ void ItemList::_bind_methods() {
}
ItemList::ItemList() {
- current = -1;
-
- select_mode = SELECT_SINGLE;
- icon_mode = ICON_MODE_LEFT;
-
- fixed_column_width = 0;
- same_column_width = false;
- max_text_lines = 1;
- max_columns = 1;
- auto_height = false;
- auto_height_value = 0.0f;
-
scroll_bar = memnew(VScrollBar);
add_child(scroll_bar);
- shape_changed = true;
scroll_bar->connect("value_changed", callable_mp(this, &ItemList::_scroll_changed));
set_focus_mode(FOCUS_ALL);
- current_columns = 1;
- search_time_msec = 0;
- ensure_selected_visible = false;
- defer_select_single = -1;
- allow_rmb_select = false;
- allow_reselect = false;
- do_autoscroll_to_bottom = false;
-
- icon_scale = 1.0f;
set_clip_contents(true);
}
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 4982a68071..86a0174a20 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -52,7 +52,7 @@ public:
private:
struct Item {
Ref<Texture2D> icon;
- bool icon_transposed;
+ bool icon_transposed = false;
Rect2i icon_region;
Color icon_modulate;
Ref<Texture2D> tag_icon;
@@ -62,10 +62,10 @@ private:
String language;
TextDirection text_direction = TEXT_DIRECTION_AUTO;
- bool selectable;
- bool selected;
- bool disabled;
- bool tooltip_enabled;
+ bool selectable = false;
+ bool selected = false;
+ bool disabled = false;
+ bool tooltip_enabled = false;
Variant metadata;
String tooltip;
Color custom_fg;
@@ -79,44 +79,44 @@ private:
bool operator<(const Item &p_another) const { return text < p_another.text; }
};
- int current;
+ int current = -1;
- bool shape_changed;
+ bool shape_changed = true;
- bool ensure_selected_visible;
- bool same_column_width;
+ bool ensure_selected_visible = false;
+ bool same_column_width = false;
- bool auto_height;
- float auto_height_value;
+ bool auto_height = false;
+ float auto_height_value = 0.0;
Vector<Item> items;
Vector<int> separators;
- SelectMode select_mode;
- IconMode icon_mode;
+ SelectMode select_mode = SELECT_SINGLE;
+ IconMode icon_mode = ICON_MODE_LEFT;
VScrollBar *scroll_bar;
- uint64_t search_time_msec;
+ uint64_t search_time_msec = 0;
String search_string;
- int current_columns;
- int fixed_column_width;
- int max_text_lines;
- int max_columns;
+ int current_columns = 1;
+ int fixed_column_width = 0;
+ int max_text_lines = 1;
+ int max_columns = 1;
Size2 fixed_icon_size;
Size2 max_item_size_cache;
- int defer_select_single;
+ int defer_select_single = -1;
- bool allow_rmb_select;
+ bool allow_rmb_select = false;
- bool allow_reselect;
+ bool allow_reselect = false;
- real_t icon_scale;
+ real_t icon_scale = 1.0;
- bool do_autoscroll_to_bottom;
+ bool do_autoscroll_to_bottom = false;
Array _get_items() const;
void _set_items(const Array &p_items);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 8fc40955f0..be73fd8f51 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -194,7 +194,7 @@ void Label::_notification(int p_what) {
style->draw(ci, Rect2(Point2(0, 0), get_size()));
- float total_h = 0;
+ float total_h = 0.0;
int lines_visible = 0;
// Get number of lines to fit to the height.
@@ -260,7 +260,8 @@ void Label::_notification(int p_what) {
}
}
}
- visible_glyphs = total_glyphs * percent_visible;
+
+ visible_glyphs = MIN(total_glyphs, visible_chars);
}
Vector2 ofs;
@@ -357,21 +358,25 @@ void Label::_notification(int p_what) {
}
Size2 Label::get_minimum_size() const {
- Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
-
// don't want to mutable everything
if (dirty || lines_dirty) {
const_cast<Label *>(this)->_shape();
}
+ Size2 min_size = minsize;
+
+ Ref<Font> font = get_theme_font("font");
+ min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size("font_size")) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM));
+
+ Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
if (autowrap) {
- return Size2(1, clip ? 1 : minsize.height) + min_style;
+ return Size2(1, clip ? 1 : min_size.height) + min_style;
} else {
- Size2 ms = minsize;
if (clip) {
- ms.width = 1;
+ min_size.width = 1;
}
- return ms + min_style;
+
+ return min_size + min_style;
}
}
@@ -391,7 +396,7 @@ int Label::get_visible_line_count() const {
Ref<StyleBox> style = get_theme_stylebox("normal");
int line_spacing = get_theme_constant("line_spacing");
int lines_visible = 0;
- float total_h = 0;
+ float total_h = 0.0;
for (int64_t i = lines_skipped; i < lines_rid.size(); i++) {
total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) {
@@ -537,8 +542,9 @@ void Label::set_visible_characters(int p_amount) {
visible_chars = p_amount;
if (get_total_character_count() > 0) {
percent_visible = (float)p_amount / (float)get_total_character_count();
+ } else {
+ percent_visible = 1.0;
}
- _change_notify("percent_visible");
update();
}
@@ -555,7 +561,6 @@ void Label::set_percent_visible(float p_percent) {
visible_chars = get_total_character_count() * p_percent;
percent_visible = p_percent;
}
- _change_notify("visible_chars");
update();
}
@@ -564,6 +569,7 @@ float Label::get_percent_visible() const {
}
void Label::set_lines_skipped(int p_lines) {
+ ERR_FAIL_COND(p_lines < 0);
lines_skipped = p_lines;
_update_visible();
update();
@@ -610,7 +616,7 @@ bool Label::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 219c6af39e..032b4112e1 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -72,7 +72,7 @@ private:
Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
Array st_args;
- float percent_visible = 1;
+ float percent_visible = 1.0;
int visible_chars = -1;
int lines_skipped = 0;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 51f780462f..1aff5d5390 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -30,6 +30,7 @@
#include "line_edit.h"
+#include "core/input/input_map.h"
#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -44,7 +45,180 @@
#endif
#include "scene/main/window.h"
+void LineEdit::_swap_current_input_direction() {
+ if (input_direction == TEXT_DIRECTION_LTR) {
+ input_direction = TEXT_DIRECTION_RTL;
+ } else {
+ input_direction = TEXT_DIRECTION_LTR;
+ }
+ set_caret_column(get_caret_column());
+ update();
+}
+
+void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
+ if (selection.enabled && !p_select) {
+ set_caret_column(selection.begin);
+ deselect();
+ return;
+ }
+
+ shift_selection_check_pre(p_select);
+
+ if (p_move_by_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < cc) {
+ cc = words[i].x;
+ break;
+ }
+ }
+
+ set_caret_column(cc);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() - 1);
+ } else {
+ set_caret_column(TS->shaped_text_prev_grapheme_pos(text_rid, get_caret_column()));
+ }
+ }
+
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
+ if (selection.enabled && !p_select) {
+ set_caret_column(selection.end);
+ deselect();
+ return;
+ }
+
+ shift_selection_check_pre(p_select);
+
+ if (p_move_by_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > cc) {
+ cc = words[i].y;
+ break;
+ }
+ }
+
+ set_caret_column(cc);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() + 1);
+ } else {
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, get_caret_column()));
+ }
+ }
+
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_start(bool p_select) {
+ shift_selection_check_pre(p_select);
+ set_caret_column(0);
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_end(bool p_select) {
+ shift_selection_check_pre(p_select);
+ set_caret_column(text.length());
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
+ if (!editable) {
+ return;
+ }
+
+ if (p_all_to_left) {
+ deselect();
+ text = text.substr(0, caret_column);
+ _text_changed();
+ return;
+ }
+
+ if (selection.enabled) {
+ selection_delete();
+ return;
+ }
+
+ if (p_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < cc) {
+ cc = words[i].x;
+ break;
+ }
+ }
+
+ delete_text(cc, caret_column);
+
+ set_caret_column(cc);
+ } else {
+ delete_char();
+ }
+}
+
+void LineEdit::_delete(bool p_word, bool p_all_to_right) {
+ if (!editable) {
+ return;
+ }
+
+ if (p_all_to_right) {
+ deselect();
+ text = text.substr(caret_column, text.length() - caret_column);
+ _shape();
+ set_caret_column(0);
+ _text_changed();
+ return;
+ }
+
+ if (selection.enabled) {
+ selection_delete();
+ return;
+ }
+
+ int text_len = text.length();
+
+ if (caret_column == text_len) {
+ return; // Nothing to do.
+ }
+
+ if (p_word) {
+ int cc = caret_column;
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > cc) {
+ cc = words[i].y;
+ break;
+ }
+ }
+
+ delete_text(caret_column, cc);
+ set_caret_column(caret_column);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(caret_column + 1);
+ delete_char();
+ } else {
+ int cc = caret_column;
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, caret_column));
+ delete_text(cc, caret_column);
+ }
+ }
+}
+
void LineEdit::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -52,17 +226,17 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
// Ignore mouse clicks in IME input mode.
return;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
menu->set_position(get_screen_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
- //menu->set_scale(get_global_transform().get_scale());
+ _generate_context_menu();
menu->popup();
grab_focus();
accept_event();
return;
}
- if (b->get_button_index() != BUTTON_LEFT) {
+ if (b->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
@@ -78,25 +252,44 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
shift_selection_check_pre(b->get_shift());
- set_cursor_at_pixel_pos(b->get_position().x);
+ set_caret_at_pixel_pos(b->get_position().x);
if (b->get_shift()) {
- selection_fill_at_cursor();
+ selection_fill_at_caret();
selection.creating = true;
} else {
- if (b->is_doubleclick() && selecting_enabled) {
- selection.enabled = true;
- selection.begin = 0;
- selection.end = text.length();
- selection.doubleclick = true;
+ if (selecting_enabled) {
+ if (!b->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ // Triple-click select all.
+ selection.enabled = true;
+ selection.begin = 0;
+ selection.end = text.length();
+ selection.doubleclick = true;
+ selection.last_dblclk = 0;
+ caret_column = selection.begin;
+ } else if (b->is_doubleclick()) {
+ // Double-click select word.
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x < caret_column && words[i].y > caret_column) {
+ selection.enabled = true;
+ selection.begin = words[i].x;
+ selection.end = words[i].y;
+ selection.doubleclick = true;
+ selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
+ caret_column = selection.end;
+ break;
+ }
+ }
+ }
}
selection.drag_attempt = false;
- if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) {
+ if ((caret_column < selection.begin) || (caret_column > selection.end) || !selection.enabled) {
deselect();
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
selection.creating = true;
} else if (selection.enabled) {
selection.drag_attempt = true;
@@ -138,10 +331,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (m->get_button_mask() & BUTTON_LEFT) {
+ if (m->get_button_mask() & MOUSE_BUTTON_LEFT) {
if (selection.creating) {
- set_cursor_at_pixel_pos(m->get_position().x);
- selection_fill_at_cursor();
+ set_caret_at_pixel_pos(m->get_position().x);
+ selection_fill_at_caret();
}
}
}
@@ -153,453 +346,163 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
return;
}
-#ifdef APPLE_STYLE_KEYS
- if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) {
- uint32_t remap_key = KEY_UNKNOWN;
- switch (k->get_keycode()) {
- case KEY_F: {
- remap_key = KEY_RIGHT;
- } break;
- case KEY_B: {
- remap_key = KEY_LEFT;
- } break;
- case KEY_P: {
- remap_key = KEY_UP;
- } break;
- case KEY_N: {
- remap_key = KEY_DOWN;
- } break;
- case KEY_D: {
- remap_key = KEY_DELETE;
- } break;
- case KEY_H: {
- remap_key = KEY_BACKSPACE;
- } break;
- case KEY_A: {
- remap_key = KEY_HOME;
- } break;
- case KEY_E: {
- remap_key = KEY_END;
- } break;
+ if (context_menu_enabled) {
+ if (k->is_action("ui_menu", true)) {
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
+ menu->set_position(get_global_transform().xform(pos));
+ menu->set_size(Vector2(1, 1));
+ _generate_context_menu();
+ menu->popup();
+ menu->grab_focus();
}
+ }
- if (remap_key != KEY_UNKNOWN) {
- k->set_keycode(remap_key);
- k->set_control(false);
+ // Default is ENTER, KP_ENTER. Cannot use ui_accept as default includes SPACE
+ if (k->is_action("ui_text_newline", true)) {
+ emit_signal("text_entered", text);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
+ DisplayServer::get_singleton()->virtual_keyboard_hide();
}
}
-#endif
-
- unsigned int code = k->get_keycode();
-
- if (k->get_command() && is_shortcut_keys_enabled()) {
- bool handled = true;
-
- switch (code) {
- case (KEY_QUOTELEFT): { // Swap current input direction (primary cursor)
-
- if (input_direction == TEXT_DIRECTION_LTR) {
- input_direction = TEXT_DIRECTION_RTL;
- } else {
- input_direction = TEXT_DIRECTION_LTR;
- }
- set_cursor_position(get_cursor_position());
- update();
-
- } break;
-
- case (KEY_X): { // CUT.
-
- if (editable) {
- cut_text();
- }
- } break;
-
- case (KEY_C): { // COPY.
-
- copy_text();
-
- } break;
-
- case (KEY_Y): // PASTE (Yank for unix users).
- case (KEY_V): { // PASTE.
-
- if (editable) {
- paste_text();
- }
-
- } break;
-
- case (KEY_Z): { // Undo/redo.
- if (editable) {
- if (k->get_shift()) {
- redo();
- } else {
- undo();
- }
- }
- } break;
-
- case (KEY_U): { // Delete from start to cursor.
-
- if (editable) {
- deselect();
- text = text.substr(cursor_pos, text.length() - cursor_pos);
- _shape();
- set_cursor_position(0);
- _text_changed();
- }
-
- } break;
-
- case (KEY_K): { // Delete from cursor_pos to end.
-
- if (editable) {
- deselect();
- text = text.substr(0, cursor_pos);
- _text_changed();
- }
+ if (is_shortcut_keys_enabled()) {
+ if (k->is_action("ui_copy", true)) {
+ copy_text();
+ accept_event();
+ return;
+ }
- } break;
- case (KEY_A): { // Select all.
- select();
+ if (k->is_action("ui_text_select_all", true)) {
+ select();
+ accept_event();
+ return;
+ }
- } break;
-#ifdef APPLE_STYLE_KEYS
- case (KEY_LEFT): { // Go to start of text - like HOME key.
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(0);
- shift_selection_check_post(k->get_shift());
- } break;
- case (KEY_RIGHT): { // Go to end of text - like END key.
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(text.length());
- shift_selection_check_post(k->get_shift());
- } break;
- case (KEY_BACKSPACE): {
- if (!editable)
- break;
+ // Cut / Paste
+ if (k->is_action("ui_cut", true)) {
+ cut_text();
+ accept_event();
+ return;
+ }
- // If selected, delete the selection
- if (selection.enabled) {
- selection_delete();
- break;
- }
+ if (k->is_action("ui_paste", true)) {
+ paste_text();
+ accept_event();
+ return;
+ }
- // Otherwise delete from cursor to beginning of text edit
- int current_pos = get_cursor_position();
- if (current_pos != 0) {
- delete_text(0, current_pos);
- }
- } break;
-#endif
- default: {
- handled = false;
- }
+ // Undo / Redo
+ if (k->is_action("ui_undo", true)) {
+ undo();
+ accept_event();
+ return;
}
- if (handled) {
+ if (k->is_action("ui_redo", true)) {
+ redo();
accept_event();
return;
}
}
- _reset_caret_blink_timer();
- if (!k->get_metakey()) {
- bool handled = true;
- switch (code) {
- case KEY_KP_ENTER:
- case KEY_ENTER: {
- emit_signal("text_entered", text);
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
- DisplayServer::get_singleton()->virtual_keyboard_hide();
- }
-
- } break;
-
- case KEY_BACKSPACE: {
- if (!editable) {
- break;
- }
-
- if (selection.enabled) {
- selection_delete();
- break;
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < cc) {
- cc = words[i].x;
- break;
- }
- }
-
- delete_text(cc, cursor_pos);
-
- set_cursor_position(cc);
-
- } else {
- delete_char();
- }
-
- } break;
- case KEY_KP_4: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_LEFT: {
-#ifndef APPLE_STYLE_KEYS
- if (!k->get_alt()) {
-#endif
- if (selection.enabled && !k->get_shift()) {
- set_cursor_position(selection.begin);
- deselect();
- handled = true;
- break;
- }
-
- shift_selection_check_pre(k->get_shift());
-#ifndef APPLE_STYLE_KEYS
- }
-#endif
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- set_cursor_position(0);
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < cc) {
- cc = words[i].x;
- break;
- }
- }
-
- set_cursor_position(cc);
-
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() - 1);
- } else {
- set_cursor_position(TS->shaped_text_prev_grapheme_pos(text_rid, get_cursor_position()));
- }
- }
-
- shift_selection_check_post(k->get_shift());
-
- } break;
- case KEY_KP_6: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_RIGHT: {
-#ifndef APPLE_STYLE_KEYS
- if (!k->get_alt()) {
-#endif
- if (selection.enabled && !k->get_shift()) {
- set_cursor_position(selection.end);
- deselect();
- handled = true;
- break;
- }
-
- shift_selection_check_pre(k->get_shift());
-#ifndef APPLE_STYLE_KEYS
- }
-#endif
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- set_cursor_position(text.length());
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > cc) {
- cc = words[i].y;
- break;
- }
- }
-
- set_cursor_position(cc);
-
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() + 1);
- } else {
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, get_cursor_position()));
- }
- }
-
- shift_selection_check_post(k->get_shift());
-
- } break;
- case KEY_UP: {
- shift_selection_check_pre(k->get_shift());
- if (get_cursor_position() == 0) {
- handled = false;
- }
- set_cursor_position(0);
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_DOWN: {
- shift_selection_check_pre(k->get_shift());
- if (get_cursor_position() == text.length()) {
- handled = false;
- }
- set_cursor_position(text.length());
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_DELETE: {
- if (!editable) {
- break;
- }
-
- if (k->get_shift() && !k->get_command() && !k->get_alt()) {
- cut_text();
- break;
- }
-
- if (selection.enabled) {
- selection_delete();
- break;
- }
-
- int text_len = text.length();
+ // BACKSPACE
+ if (k->is_action("ui_text_backspace_all_to_left", true)) {
+ _backspace(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace_word", true)) {
+ _backspace(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace", true)) {
+ _backspace();
+ accept_event();
+ return;
+ }
- if (cursor_pos == text_len) {
- break; // Nothing to do.
- }
+ // DELETE
+ if (k->is_action("ui_text_delete_all_to_right", true)) {
+ _delete(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete_word", true)) {
+ _delete(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete", true)) {
+ _delete();
+ accept_event();
+ return;
+ }
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
+ // Cursor Movement
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > cc) {
- cc = words[i].y;
- break;
- }
- }
+ k = k->duplicate();
+ bool shift_pressed = k->get_shift();
+ // Remove shift or else actions will not match. Use above variable for selection.
+ k->set_shift(false);
- delete_text(cursor_pos, cc);
+ if (k->is_action("ui_text_caret_word_left", true)) {
+ _move_caret_left(shift_pressed, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_left", true)) {
+ _move_caret_left(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_word_right", true)) {
+ _move_caret_right(shift_pressed, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_right", true)) {
+ _move_caret_right(shift_pressed, false);
+ accept_event();
+ return;
+ }
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(cursor_pos + 1);
- delete_char();
- } else {
- int cc = cursor_pos;
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, cursor_pos));
- delete_text(cc, cursor_pos);
- }
- }
+ // Up = Home, Down = End
+ if (k->is_action("ui_text_caret_up", true) || k->is_action("ui_text_caret_line_start", true) || k->is_action("ui_text_caret_page_up", true)) {
+ _move_caret_start(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_down", true) || k->is_action("ui_text_caret_line_end", true) || k->is_action("ui_text_caret_page_down", true)) {
+ _move_caret_end(shift_pressed);
+ accept_event();
+ return;
+ }
- } break;
- case KEY_KP_7: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_HOME: {
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(0);
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_KP_1: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_END: {
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(text.length());
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_MENU: {
- if (context_menu_enabled) {
- Point2 pos = Point2(get_cursor_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
- menu->set_position(get_global_transform().xform(pos));
- menu->set_size(Vector2(1, 1));
- //menu->set_scale(get_global_transform().get_scale());
- menu->popup();
- menu->grab_focus();
- }
- } break;
+ // Misc
+ if (k->is_action("ui_swap_input_direction", true)) {
+ _swap_current_input_direction();
+ accept_event();
+ return;
+ }
- default: {
- handled = false;
- } break;
- }
+ _reset_caret_blink_timer();
- if (handled) {
- accept_event();
- } else if (!k->get_command()) {
- if (k->get_unicode() >= 32 && k->get_keycode() != KEY_DELETE) {
- if (editable) {
- selection_delete();
- char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
- int prev_len = text.length();
- append_at_cursor(ucodestr);
- if (text.length() != prev_len) {
- _text_changed();
- }
- accept_event();
- }
+ // Allow unicode handling if:
+ // * No Modifiers are pressed (except shift)
+ bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey());
- } else {
- return;
- }
+ if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
+ // Handle Unicode (if no modifiers active)
+ selection_delete();
+ char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
+ int prev_len = text.length();
+ insert_text_at_caret(ucodestr);
+ if (text.length() != prev_len) {
+ _text_changed();
}
-
- update();
+ accept_event();
}
-
- return;
}
}
@@ -641,15 +544,15 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
Control::drop_data(p_point, p_data);
if (p_data.get_type() == Variant::STRING) {
- set_cursor_at_pixel_pos(p_point.x);
+ set_caret_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
text.erase(selection.begin, selected);
_shape();
- append_at_cursor(p_data);
- selection.begin = cursor_pos - selected;
- selection.end = cursor_pos;
+ insert_text_at_caret(p_data);
+ selection.begin = caret_column - selected;
+ selection.end = caret_column;
}
}
@@ -674,8 +577,8 @@ void LineEdit::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -686,7 +589,7 @@ void LineEdit::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
_fit_to_width();
scroll_offset = 0;
- set_cursor_position(get_cursor_position());
+ set_caret_column(get_caret_column());
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
@@ -773,7 +676,7 @@ void LineEdit::_notification(int p_what) {
Color selection_color = get_theme_color("selection_color");
Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_uneditable_color");
Color font_selected_color = get_theme_color("font_selected_color");
- Color cursor_color = get_theme_color("cursor_color");
+ Color caret_color = get_theme_color("caret_color");
// Draw placeholder color.
if (using_placeholder) {
@@ -835,6 +738,24 @@ void LineEdit::_notification(int p_what) {
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ Vector2 oofs = ofs;
+ for (int i = 0; i < gl_size; i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) {
+ if (glyphs[i].font_rid != RID()) {
+ TS->font_draw_glyph_outline(glyphs[i].font_rid, ci, glyphs[i].font_size, outline_size, oofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color);
+ }
+ }
+ oofs.x += glyphs[i].advance;
+ }
+ if (oofs.x >= ofs_max) {
+ break;
+ }
+ }
+ }
for (int i = 0; i < gl_size; i++) {
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -859,7 +780,7 @@ void LineEdit::_notification(int p_what) {
// Normal caret.
Rect2 l_caret, t_caret;
TextServer::Direction l_dir, t_dir;
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
if (l_caret == Rect2() && t_caret == Rect2()) {
// No carets, add one at the start.
@@ -872,28 +793,28 @@ void LineEdit::_notification(int p_what) {
l_dir = TextServer::DIRECTION_LTR;
l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
}
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
} else {
if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
// Draw extra marker on top of mid caret.
Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
trect.position += ofs;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
}
l_caret.position += ofs;
l_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
t_caret.position += ofs;
t_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, caret_color);
}
} else {
{
- // IME intermidiet text range.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos, cursor_pos + ime_text.length());
+ // IME intermediate text range.
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column, caret_column + ime_text.length());
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -906,12 +827,12 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
{
// IME caret.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos + ime_selection.x, cursor_pos + ime_selection.x + ime_selection.y);
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y);
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -924,14 +845,14 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width * 3;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
}
}
if (has_focus()) {
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + TS->shaped_text_get_size(text_rid).y), get_viewport()->get_window_id());
}
@@ -948,10 +869,10 @@ void LineEdit::_notification(int p_what) {
}
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height;
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
+ Point2 caret_column = Point2(get_caret_column(), 1) * get_minimum_size().height;
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + caret_column, get_viewport()->get_window_id());
}
show_virtual_keyboard();
@@ -961,14 +882,14 @@ void LineEdit::_notification(int p_what) {
caret_blink_timer->stop();
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id());
}
ime_text = "";
ime_selection = Point2();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
@@ -980,7 +901,7 @@ void LineEdit::_notification(int p_what) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
update();
}
@@ -995,13 +916,17 @@ void LineEdit::copy_text() {
}
void LineEdit::cut_text() {
- if (selection.enabled && !pass) {
+ if (editable && selection.enabled && !pass) {
DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin));
selection_delete();
}
}
void LineEdit::paste_text() {
+ if (!editable) {
+ return;
+ }
+
// Strip escape characters like \n and \t as they can't be displayed on LineEdit.
String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes();
@@ -1010,7 +935,7 @@ void LineEdit::paste_text() {
if (selection.enabled) {
selection_delete();
}
- append_at_cursor(paste_buffer);
+ insert_text_at_caret(paste_buffer);
if (!text_changed_dirty) {
if (is_inside_tree() && text.length() != prev_len) {
@@ -1022,6 +947,10 @@ void LineEdit::paste_text() {
}
void LineEdit::undo() {
+ if (!editable) {
+ return;
+ }
+
if (undo_stack_pos == nullptr) {
if (undo_stack.size() <= 1) {
return;
@@ -1034,13 +963,17 @@ void LineEdit::undo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
}
void LineEdit::redo() {
+ if (!editable) {
+ return;
+ }
+
if (undo_stack_pos == nullptr) {
return;
}
@@ -1051,7 +984,7 @@ void LineEdit::redo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
@@ -1059,7 +992,7 @@ void LineEdit::redo() {
void LineEdit::shift_selection_check_pre(bool p_shift) {
if (!selection.enabled && p_shift) {
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
}
if (!p_shift) {
deselect();
@@ -1068,11 +1001,11 @@ void LineEdit::shift_selection_check_pre(bool p_shift) {
void LineEdit::shift_selection_check_post(bool p_shift) {
if (p_shift) {
- selection_fill_at_cursor();
+ selection_fill_at_caret();
}
}
-void LineEdit::set_cursor_at_pixel_pos(int p_x) {
+void LineEdit::set_caret_at_pixel_pos(int p_x) {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1117,10 +1050,10 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
}
int ofs = TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset);
- set_cursor_position(ofs);
+ set_caret_column(ofs);
}
-Vector2i LineEdit::get_cursor_pixel_pos() {
+Vector2i LineEdit::get_caret_pixel_pos() {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1169,9 +1102,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
TextServer::Direction l_dir, t_dir;
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
@@ -1183,9 +1116,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
ret.y = x_ofs + l_caret.position.x + scroll_offset;
@@ -1199,19 +1132,19 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
return ret;
}
-void LineEdit::set_mid_grapheme_caret_enabled(const bool p_enabled) {
- mid_grapheme_caret_enabled = p_enabled;
+void LineEdit::set_caret_mid_grapheme_enabled(const bool p_enabled) {
+ caret_mid_grapheme_enabled = p_enabled;
}
-bool LineEdit::get_mid_grapheme_caret_enabled() const {
- return mid_grapheme_caret_enabled;
+bool LineEdit::is_caret_mid_grapheme_enabled() const {
+ return caret_mid_grapheme_enabled;
}
-bool LineEdit::cursor_get_blink_enabled() const {
+bool LineEdit::is_caret_blink_enabled() const {
return caret_blink_enabled;
}
-void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
+void LineEdit::set_caret_blink_enabled(const bool p_enabled) {
caret_blink_enabled = p_enabled;
if (has_focus() || caret_force_displayed) {
@@ -1225,23 +1158,25 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
}
draw_caret = true;
+
+ notify_property_list_changed();
}
-bool LineEdit::cursor_get_force_displayed() const {
+bool LineEdit::is_caret_force_displayed() const {
return caret_force_displayed;
}
-void LineEdit::cursor_set_force_displayed(const bool p_enabled) {
+void LineEdit::set_caret_force_displayed(const bool p_enabled) {
caret_force_displayed = p_enabled;
- cursor_set_blink_enabled(caret_blink_enabled);
+ set_caret_blink_enabled(caret_blink_enabled);
update();
}
-float LineEdit::cursor_get_blink_speed() const {
+float LineEdit::get_caret_blink_speed() const {
return caret_blink_timer->get_wait_time();
}
-void LineEdit::cursor_set_blink_speed(const float p_speed) {
+void LineEdit::set_caret_blink_speed(const float p_speed) {
ERR_FAIL_COND(p_speed <= 0);
caret_blink_timer->set_wait_time(p_speed);
}
@@ -1265,14 +1200,14 @@ void LineEdit::_toggle_draw_caret() {
}
void LineEdit::delete_char() {
- if ((text.length() <= 0) || (cursor_pos == 0)) {
+ if ((text.length() <= 0) || (caret_column == 0)) {
return;
}
- text.erase(cursor_pos - 1, 1);
+ text.erase(caret_column - 1, 1);
_shape();
- set_cursor_position(get_cursor_position() - 1);
+ set_caret_column(get_caret_column() - 1);
_text_changed();
}
@@ -1284,10 +1219,10 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
text.erase(p_from_column, p_to_column - p_from_column);
_shape();
- cursor_pos -= CLAMP(cursor_pos - p_from_column, 0, p_to_column - p_from_column);
+ caret_column -= CLAMP(caret_column - p_from_column, 0, p_to_column - p_from_column);
- if (cursor_pos >= text.length()) {
- cursor_pos = text.length();
+ if (caret_column >= text.length()) {
+ caret_column = text.length();
}
if (!text_changed_dirty) {
@@ -1300,10 +1235,11 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
void LineEdit::set_text(String p_text) {
clear_internal();
- append_at_cursor(p_text);
+ insert_text_at_caret(p_text);
+ _create_undo_state();
update();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
}
@@ -1413,7 +1349,7 @@ void LineEdit::show_virtual_keyboard() {
if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
} else {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, caret_column);
}
}
}
@@ -1442,16 +1378,16 @@ float LineEdit::get_placeholder_alpha() const {
return placeholder_alpha;
}
-void LineEdit::set_cursor_position(int p_pos) {
- if (p_pos > (int)text.length()) {
- p_pos = text.length();
+void LineEdit::set_caret_column(int p_column) {
+ if (p_column > (int)text.length()) {
+ p_column = text.length();
}
- if (p_pos < 0) {
- p_pos = 0;
+ if (p_column < 0) {
+ p_column = 0;
}
- cursor_pos = p_pos;
+ caret_column = p_column;
// Fit to window.
@@ -1505,8 +1441,8 @@ void LineEdit::set_cursor_position(int p_pos) {
ofs_max -= r_icon->get_width();
}
- // Note: Use too coordinates to fit IME input range.
- Vector2i primary_catret_offset = get_cursor_pixel_pos();
+ // Note: Use two coordinates to fit IME input range.
+ Vector2i primary_catret_offset = get_caret_pixel_pos();
if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) {
scroll_offset += (x_ofs - MIN(primary_catret_offset.x, primary_catret_offset.y));
@@ -1518,8 +1454,8 @@ void LineEdit::set_cursor_position(int p_pos) {
update();
}
-int LineEdit::get_cursor_position() const {
- return cursor_pos;
+int LineEdit::get_caret_column() const {
+ return caret_column;
}
void LineEdit::set_scroll_offset(int p_pos) {
@@ -1533,17 +1469,17 @@ int LineEdit::get_scroll_offset() const {
return scroll_offset;
}
-void LineEdit::append_at_cursor(String p_text) {
+void LineEdit::insert_text_at_caret(String p_text) {
if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) {
- String pre = text.substr(0, cursor_pos);
- String post = text.substr(cursor_pos, text.length() - cursor_pos);
+ String pre = text.substr(0, caret_column);
+ String post = text.substr(caret_column, text.length() - caret_column);
text = pre + p_text + post;
_shape();
- TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, cursor_pos, cursor_pos + p_text.length());
+ TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length());
if (dir != TextServer::DIRECTION_AUTO) {
input_direction = (TextDirection)dir;
}
- set_cursor_position(cursor_pos + p_text.length());
+ set_caret_column(caret_column + p_text.length());
} else {
emit_signal("text_change_rejected");
}
@@ -1552,7 +1488,7 @@ void LineEdit::append_at_cursor(String p_text) {
void LineEdit::clear_internal() {
deselect();
_clear_undo_stack();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
undo_text = "";
text = "";
@@ -1568,12 +1504,12 @@ Size2 LineEdit::get_minimum_size() const {
Size2 min_size;
// Minimum size of text.
- int space_size = font->get_char_size('m', 0, font_size).x;
- min_size.width = get_theme_constant("minimum_spaces") * space_size;
+ int em_space_size = font->get_char_size('M', 0, font_size).x;
+ min_size.width = get_theme_constant("minimum_character_width") * em_space_size;
if (expand_to_text_length) {
- // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end.
- min_size.width = MAX(min_size.width, full_width + space_size);
+ // Add a space because some fonts are too exact, and because caret needs a bit more when at the end.
+ min_size.width = MAX(min_size.width, full_width + em_space_size);
}
min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size));
@@ -1593,7 +1529,7 @@ Size2 LineEdit::get_minimum_size() const {
void LineEdit::deselect() {
selection.begin = 0;
selection.end = 0;
- selection.cursor_start = 0;
+ selection.start_column = 0;
selection.enabled = false;
selection.creating = false;
selection.doubleclick = false;
@@ -1618,13 +1554,13 @@ int LineEdit::get_max_length() const {
return max_length;
}
-void LineEdit::selection_fill_at_cursor() {
+void LineEdit::selection_fill_at_caret() {
if (!selecting_enabled) {
return;
}
- selection.begin = cursor_pos;
- selection.end = selection.cursor_start;
+ selection.begin = caret_column;
+ selection.end = selection.start_column;
if (selection.end < selection.begin) {
int aux = selection.end;
@@ -1781,82 +1717,82 @@ void LineEdit::menu_option(int p_option) {
} break;
case MENU_INSERT_LRM: {
if (editable) {
- append_at_cursor(String::chr(0x200E));
+ insert_text_at_caret(String::chr(0x200E));
}
} break;
case MENU_INSERT_RLM: {
if (editable) {
- append_at_cursor(String::chr(0x200F));
+ insert_text_at_caret(String::chr(0x200F));
}
} break;
case MENU_INSERT_LRE: {
if (editable) {
- append_at_cursor(String::chr(0x202A));
+ insert_text_at_caret(String::chr(0x202A));
}
} break;
case MENU_INSERT_RLE: {
if (editable) {
- append_at_cursor(String::chr(0x202B));
+ insert_text_at_caret(String::chr(0x202B));
}
} break;
case MENU_INSERT_LRO: {
if (editable) {
- append_at_cursor(String::chr(0x202D));
+ insert_text_at_caret(String::chr(0x202D));
}
} break;
case MENU_INSERT_RLO: {
if (editable) {
- append_at_cursor(String::chr(0x202E));
+ insert_text_at_caret(String::chr(0x202E));
}
} break;
case MENU_INSERT_PDF: {
if (editable) {
- append_at_cursor(String::chr(0x202C));
+ insert_text_at_caret(String::chr(0x202C));
}
} break;
case MENU_INSERT_ALM: {
if (editable) {
- append_at_cursor(String::chr(0x061C));
+ insert_text_at_caret(String::chr(0x061C));
}
} break;
case MENU_INSERT_LRI: {
if (editable) {
- append_at_cursor(String::chr(0x2066));
+ insert_text_at_caret(String::chr(0x2066));
}
} break;
case MENU_INSERT_RLI: {
if (editable) {
- append_at_cursor(String::chr(0x2067));
+ insert_text_at_caret(String::chr(0x2067));
}
} break;
case MENU_INSERT_FSI: {
if (editable) {
- append_at_cursor(String::chr(0x2068));
+ insert_text_at_caret(String::chr(0x2068));
}
} break;
case MENU_INSERT_PDI: {
if (editable) {
- append_at_cursor(String::chr(0x2069));
+ insert_text_at_caret(String::chr(0x2069));
}
} break;
case MENU_INSERT_ZWJ: {
if (editable) {
- append_at_cursor(String::chr(0x200D));
+ insert_text_at_caret(String::chr(0x200D));
}
} break;
case MENU_INSERT_ZWNJ: {
if (editable) {
- append_at_cursor(String::chr(0x200C));
+ insert_text_at_caret(String::chr(0x200C));
}
} break;
case MENU_INSERT_WJ: {
if (editable) {
- append_at_cursor(String::chr(0x2060));
+ insert_text_at_caret(String::chr(0x2060));
}
} break;
case MENU_INSERT_SHY: {
if (editable) {
- append_at_cursor(String::chr(0x00AD));
+ insert_text_at_caret(String::chr(0x00AD));
}
}
}
@@ -1876,18 +1812,18 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
#endif
}
-void LineEdit::set_expand_to_text_length(bool p_enabled) {
+void LineEdit::set_expand_to_text_length_enabled(bool p_enabled) {
expand_to_text_length = p_enabled;
minimum_size_changed();
- set_cursor_position(cursor_pos);
+ set_caret_column(caret_column);
}
-bool LineEdit::get_expand_to_text_length() const {
+bool LineEdit::is_expand_to_text_length_enabled() const {
return expand_to_text_length;
}
@@ -1958,7 +1894,6 @@ void LineEdit::_text_changed() {
void LineEdit::_emit_text_change() {
emit_signal("text_changed", text);
- _change_notify("text");
text_changed_dirty = false;
}
@@ -1973,7 +1908,7 @@ void LineEdit::_shape() {
t = secret_character.repeat(text.length() + ime_text.length());
} else {
if (ime_text.length() > 0) {
- t = text.substr(0, cursor_pos) + ime_text + text.substr(cursor_pos, text.length());
+ t = text.substr(0, caret_column) + ime_text + text.substr(caret_column, text.length());
} else {
t = text;
}
@@ -2038,30 +1973,55 @@ void LineEdit::_clear_undo_stack() {
void LineEdit::_create_undo_state() {
TextOperation op;
op.text = text;
- op.cursor_pos = cursor_pos;
+ op.caret_column = caret_column;
op.scroll_offset = scroll_offset;
undo_stack.push_back(op);
}
+int LineEdit::_get_menu_action_accelerator(const String &p_action) {
+ const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action);
+ if (!events) {
+ return 0;
+ }
+
+ // Use first event in the list for the accelerator.
+ const List<Ref<InputEvent>>::Element *first_event = events->front();
+ if (!first_event) {
+ return 0;
+ }
+
+ const Ref<InputEventKey> event = first_event->get();
+ if (event.is_null()) {
+ return 0;
+ }
+
+ // Use physical keycode if non-zero
+ if (event->get_physical_keycode() != 0) {
+ return event->get_physical_keycode_with_modifiers();
+ } else {
+ return event->get_keycode_with_modifiers();
+ }
+}
+
void LineEdit::_generate_context_menu() {
// Reorganize context menu.
menu->clear();
if (editable) {
- menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0);
+ menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0);
}
- menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0);
+ menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : 0);
if (editable) {
- menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0);
+ menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : 0);
}
menu->add_separator();
if (is_selecting_enabled()) {
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : 0);
}
if (editable) {
menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0);
- menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0);
+ menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_undo") : 0);
+ menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_redo") : 0);
}
menu->add_separator();
menu->add_submenu_item(RTR("Text writing direction"), "DirMenu");
@@ -2091,7 +2051,7 @@ bool LineEdit::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -2122,6 +2082,12 @@ void LineEdit::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
}
+void LineEdit::_validate_property(PropertyInfo &property) const {
+ if (!caret_blink_enabled && property.name == "caret_blink_speed") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed);
@@ -2152,23 +2118,23 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_placeholder"), &LineEdit::get_placeholder);
ClassDB::bind_method(D_METHOD("set_placeholder_alpha", "alpha"), &LineEdit::set_placeholder_alpha);
ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha);
- ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position);
- ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position);
+ ClassDB::bind_method(D_METHOD("set_caret_column", "position"), &LineEdit::set_caret_column);
+ ClassDB::bind_method(D_METHOD("get_caret_column"), &LineEdit::get_caret_column);
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset);
- ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length);
- ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length);
- ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled);
- ClassDB::bind_method(D_METHOD("cursor_get_blink_enabled"), &LineEdit::cursor_get_blink_enabled);
- ClassDB::bind_method(D_METHOD("set_mid_grapheme_caret_enabled", "enabled"), &LineEdit::set_mid_grapheme_caret_enabled);
- ClassDB::bind_method(D_METHOD("get_mid_grapheme_caret_enabled"), &LineEdit::get_mid_grapheme_caret_enabled);
- ClassDB::bind_method(D_METHOD("cursor_set_force_displayed", "enabled"), &LineEdit::cursor_set_force_displayed);
- ClassDB::bind_method(D_METHOD("cursor_get_force_displayed"), &LineEdit::cursor_get_force_displayed);
- ClassDB::bind_method(D_METHOD("cursor_set_blink_speed", "blink_speed"), &LineEdit::cursor_set_blink_speed);
- ClassDB::bind_method(D_METHOD("cursor_get_blink_speed"), &LineEdit::cursor_get_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_expand_to_text_length_enabled", "enabled"), &LineEdit::set_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("is_expand_to_text_length_enabled"), &LineEdit::is_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enabled"), &LineEdit::set_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &LineEdit::is_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_mid_grapheme_enabled", "enabled"), &LineEdit::set_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_blink_speed);
ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length);
ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length);
- ClassDB::bind_method(D_METHOD("append_at_cursor", "text"), &LineEdit::append_at_cursor);
- ClassDB::bind_method(D_METHOD("delete_char_at_cursor"), &LineEdit::delete_char);
+ ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret);
+ ClassDB::bind_method(D_METHOD("delete_char_at_caret"), &LineEdit::delete_char);
ClassDB::bind_method(D_METHOD("delete_text", "from_column", "to_column"), &LineEdit::delete_text);
ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &LineEdit::set_editable);
ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable);
@@ -2236,7 +2202,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");
@@ -2253,20 +2219,17 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
ADD_GROUP("Caret", "caret_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "cursor_set_force_displayed", "cursor_get_force_displayed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_mid_grapheme_caret_enabled", "get_mid_grapheme_caret_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column"), "set_caret_column", "get_caret_column");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
}
LineEdit::LineEdit() {
text_rid = TS->create_shaped_text();
_create_undo_state();
- clear_button_status.press_attempt = false;
- clear_button_status.pressing_inside = false;
-
deselect();
set_focus_mode(FOCUS_ALL);
set_default_cursor_shape(CURSOR_IBEAM);
@@ -2276,7 +2239,7 @@ LineEdit::LineEdit() {
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
- cursor_set_blink_enabled(false);
+ set_caret_blink_enabled(false);
menu = memnew(PopupMenu);
add_child(menu);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 6db7a78f61..f4f0ff0629 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -94,7 +94,7 @@ private:
Point2 ime_selection;
RID text_rid;
- float full_width = 0;
+ float full_width = 0.0;
bool selecting_enabled = true;
@@ -103,9 +103,9 @@ private:
PopupMenu *menu_dir = nullptr;
PopupMenu *menu_ctl = nullptr;
- bool mid_grapheme_caret_enabled = false;
+ bool caret_mid_grapheme_enabled = false;
- int cursor_pos = 0;
+ int caret_column = 0;
int scroll_offset = 0;
int max_length = 0; // 0 for no maximum.
@@ -129,19 +129,20 @@ private:
Ref<Texture2D> right_icon;
struct Selection {
- int begin;
- int end;
- int cursor_start;
- bool enabled;
- bool creating;
- bool doubleclick;
- bool drag_attempt;
+ int begin = 0;
+ int end = 0;
+ int start_column = 0;
+ bool enabled = false;
+ bool creating = false;
+ bool doubleclick = false;
+ bool drag_attempt = false;
+ uint64_t last_dblclk = 0;
} selection;
struct TextOperation {
- int cursor_pos;
- int scroll_offset;
- int cached_width;
+ int caret_column = 0;
+ int scroll_offset = 0;
+ int cached_width = 0;
String text;
};
List<TextOperation> undo_stack;
@@ -163,6 +164,7 @@ private:
void _clear_redo();
void _create_undo_state();
+ int _get_menu_action_accelerator(const String &p_action);
void _generate_context_menu();
void _shape();
@@ -173,12 +175,12 @@ private:
void shift_selection_check_pre(bool);
void shift_selection_check_post(bool);
- void selection_fill_at_cursor();
+ void selection_fill_at_caret();
void set_scroll_offset(int p_pos);
int get_scroll_offset() const;
- void set_cursor_at_pixel_pos(int p_x);
- Vector2i get_cursor_pixel_pos();
+ void set_caret_at_pixel_pos(int p_x);
+ Vector2i get_caret_pixel_pos();
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -188,15 +190,23 @@ private:
void _editor_settings_changed();
- void _gui_input(Ref<InputEvent> p_event);
- void _notification(int p_what);
+ void _swap_current_input_direction();
+ void _move_caret_left(bool p_select, bool p_move_by_word = false);
+ void _move_caret_right(bool p_select, bool p_move_by_word = false);
+ void _move_caret_start(bool p_select);
+ void _move_caret_end(bool p_select);
+ void _backspace(bool p_word = false, bool p_all_to_left = false);
+ void _delete(bool p_word = false, bool p_all_to_right = false);
protected:
+ void _notification(int p_what);
static void _bind_methods();
+ void _gui_input(Ref<InputEvent> p_event);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_align(Align p_align);
@@ -249,26 +259,26 @@ public:
void set_placeholder_alpha(float p_alpha);
float get_placeholder_alpha() const;
- void set_cursor_position(int p_pos);
- int get_cursor_position() const;
+ void set_caret_column(int p_column);
+ int get_caret_column() const;
void set_max_length(int p_max_length);
int get_max_length() const;
- void append_at_cursor(String p_text);
+ void insert_text_at_caret(String p_text);
void clear();
- void set_mid_grapheme_caret_enabled(const bool p_enabled);
- bool get_mid_grapheme_caret_enabled() const;
+ void set_caret_mid_grapheme_enabled(const bool p_enabled);
+ bool is_caret_mid_grapheme_enabled() const;
- bool cursor_get_blink_enabled() const;
- void cursor_set_blink_enabled(const bool p_enabled);
+ bool is_caret_blink_enabled() const;
+ void set_caret_blink_enabled(const bool p_enabled);
- float cursor_get_blink_speed() const;
- void cursor_set_blink_speed(const float p_speed);
+ float get_caret_blink_speed() const;
+ void set_caret_blink_speed(const float p_speed);
- bool cursor_get_force_displayed() const;
- void cursor_set_force_displayed(const bool p_enabled);
+ void set_caret_force_displayed(const bool p_enabled);
+ bool is_caret_force_displayed() const;
void copy_text();
void cut_text();
@@ -287,8 +297,8 @@ public:
virtual Size2 get_minimum_size() const override;
- void set_expand_to_text_length(bool p_enabled);
- bool get_expand_to_text_length() const;
+ void set_expand_to_text_length_enabled(bool p_enabled);
+ bool is_expand_to_text_length_enabled() const;
void set_clear_button_enabled(bool p_enabled);
bool is_clear_button_enabled() const;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 8e972438a5..1f7b61e3d1 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -191,9 +191,17 @@ void LinkButton::_notification(int p_what) {
int width = text_buf->get_line_width();
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
if (is_layout_rtl()) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color);
+ }
text_buf->draw(get_canvas_item(), Vector2(size.width - width, 0), color);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf->draw_outline(get_canvas_item(), Vector2(0, 0), outline_size, font_outline_color);
+ }
text_buf->draw(get_canvas_item(), Vector2(0, 0), color);
}
@@ -231,7 +239,7 @@ bool LinkButton::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -294,7 +302,6 @@ void LinkButton::_bind_methods() {
LinkButton::LinkButton() {
text_buf.instance();
- underline_mode = UNDERLINE_MODE_ALWAYS;
set_focus_mode(FOCUS_NONE);
set_default_cursor_shape(CURSOR_POINTING_HAND);
}
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index 5ab6aba122..7eaa9f88b6 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -48,7 +48,7 @@ public:
private:
String text;
Ref<TextLine> text_buf;
- UnderlineMode underline_mode;
+ UnderlineMode underline_mode = UNDERLINE_MODE_ALWAYS;
Dictionary opentype_features;
String language;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 94cb5ef0f4..1e9baa77fc 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -34,6 +34,8 @@
#include "scene/main/window.h"
void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!_is_focus_owner_in_shorcut_context()) {
return;
}
@@ -118,7 +120,6 @@ void MenuButton::set_disable_shortcuts(bool p_disabled) {
}
MenuButton::MenuButton() {
- switch_on_hover = false;
set_flat(true);
set_toggle_mode(true);
set_disable_shortcuts(false);
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index cd4ed5bcb2..fd9ae6021e 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -37,9 +37,9 @@
class MenuButton : public Button {
GDCLASS(MenuButton, Button);
- bool clicked;
- bool switch_on_hover;
- bool disable_shortcuts;
+ bool clicked = false;
+ bool switch_on_hover = false;
+ bool disable_shortcuts = false;
PopupMenu *popup;
Array _get_items() const;
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index c274eb5c10..29a38ad5e3 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -98,7 +98,6 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) {
*/
minimum_size_changed();
emit_signal("texture_changed");
- _change_notify("texture");
}
Ref<Texture2D> NinePatchRect::get_texture() const {
@@ -110,20 +109,6 @@ void NinePatchRect::set_patch_margin(Side p_side, int p_size) {
margin[p_side] = p_size;
update();
minimum_size_changed();
- switch (p_side) {
- case SIDE_LEFT:
- _change_notify("patch_margin_left");
- break;
- case SIDE_TOP:
- _change_notify("patch_margin_top");
- break;
- case SIDE_RIGHT:
- _change_notify("patch_margin_right");
- break;
- case SIDE_BOTTOM:
- _change_notify("patch_margin_bottom");
- break;
- }
}
int NinePatchRect::get_patch_margin(Side p_side) const {
@@ -139,7 +124,6 @@ void NinePatchRect::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
item_rect_changed();
- _change_notify("region_rect");
}
Rect2 NinePatchRect::get_region_rect() const {
@@ -174,16 +158,7 @@ NinePatchRect::AxisStretchMode NinePatchRect::get_v_axis_stretch_mode() const {
}
NinePatchRect::NinePatchRect() {
- margin[SIDE_LEFT] = 0;
- margin[SIDE_RIGHT] = 0;
- margin[SIDE_BOTTOM] = 0;
- margin[SIDE_TOP] = 0;
-
set_mouse_filter(MOUSE_FILTER_IGNORE);
- draw_center = true;
-
- axis_h = AXIS_STRETCH_MODE_STRETCH;
- axis_v = AXIS_STRETCH_MODE_STRETCH;
}
NinePatchRect::~NinePatchRect() {
diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h
index fcf25018aa..f9a3f31fe5 100644
--- a/scene/gui/nine_patch_rect.h
+++ b/scene/gui/nine_patch_rect.h
@@ -43,12 +43,13 @@ public:
AXIS_STRETCH_MODE_TILE_FIT,
};
- bool draw_center;
- int margin[4];
+ bool draw_center = true;
+ int margin[4] = {};
Rect2 region_rect;
Ref<Texture2D> texture;
- AxisStretchMode axis_h, axis_v;
+ AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH;
+ AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH;
protected:
void _notification(int p_what);
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index e4c1f94b31..e52b6917be 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -336,7 +336,6 @@ void OptionButton::_bind_methods() {
}
OptionButton::OptionButton() {
- current = -1;
set_toggle_mode(true);
set_text_align(ALIGN_LEFT);
if (is_layout_rtl()) {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 9cb296baa9..d846e395ad 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -38,7 +38,7 @@ class OptionButton : public Button {
GDCLASS(OptionButton, Button);
PopupMenu *popup;
- int current;
+ int current = -1;
void _focused(int p_which);
void _selected(int p_which);
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index b2ebb91500..44df8eafdc 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -52,8 +52,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); // Accounts for margin in the margin container
minsize.x += scroll_container->get_v_scrollbar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content
- float max_w = 0;
- float icon_w = 0;
+ float max_w = 0.0;
+ float icon_w = 0.0;
int check_w = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
int accel_max_w = 0;
bool has_check = false;
@@ -62,7 +62,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
Size2 size;
Size2 icon_size = items[i].get_icon_size();
- size.height = MAX(icon_size.height, items[i].text_buf->get_size().y);
+ size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
size.width += items[i].h_ofs;
@@ -89,7 +89,9 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.height += size.height;
}
- minsize.width += max_w + icon_w + accel_max_w;
+ int item_side_padding = get_theme_constant("item_start_padding") + get_theme_constant("item_end_padding");
+ minsize.width += max_w + icon_w + accel_max_w + item_side_padding;
+
if (has_check) {
minsize.width += check_w;
}
@@ -104,13 +106,35 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
return minsize;
}
+int PopupMenu::_get_item_height(int p_item) const {
+ ERR_FAIL_INDEX_V(p_item, items.size(), 0);
+ ERR_FAIL_COND_V(p_item < 0, 0);
+
+ int icon_height = items[p_item].get_icon_size().height;
+ if (items[p_item].checkable_type) {
+ icon_height = MAX(icon_height, MAX(get_theme_icon("checked")->get_height(), get_theme_icon("radio_checked")->get_height()));
+ }
+
+ int text_height = items[p_item].text_buf->get_size().height;
+ if (text_height == 0 && !items[p_item].separator) {
+ text_height = get_theme_font("font")->get_height(get_theme_font_size("font_size"));
+ }
+
+ int separator_height = 0;
+ if (items[p_item].separator) {
+ separator_height = MAX(get_theme_stylebox("separator")->get_minimum_size().height, MAX(get_theme_stylebox("labeled_separator_left")->get_minimum_size().height, get_theme_stylebox("labeled_separator_right")->get_minimum_size().height));
+ }
+
+ return MAX(separator_height, MAX(text_height, icon_height));
+}
+
int PopupMenu::_get_items_total_height() const {
int vsep = get_theme_constant("vseparation");
// Get total height of all items by taking max of icon height and font height
int items_total_height = 0;
for (int i = 0; i < items.size(); i++) {
- items_total_height += MAX(items[i].get_icon_size().height, items[i].text_buf->get_size().y) + vsep;
+ items_total_height += _get_item_height(i) + vsep;
}
// Subtract a separator which is not needed for the last item.
@@ -152,7 +176,7 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
for (int i = 0; i < items.size(); i++) {
ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
- ofs.y += MAX(items[i].get_icon_size().height, items[i].text_buf->get_size().y);
+ ofs.y += _get_item_height(i);
if (p_over.y - control->get_position().y < ofs.y) {
return i;
@@ -198,7 +222,7 @@ void PopupMenu::_activate_submenu(int p_over) {
submenu_popup->set_close_on_parent_focus(false);
submenu_popup->set_position(submenu_pos);
- submenu_popup->set_as_minsize(); // Shrink the popup size to it's contents.
+ submenu_popup->set_as_minsize(); // Shrink the popup size to its contents.
submenu_popup->popup();
// Set autohide areas
@@ -228,6 +252,8 @@ void PopupMenu::_submenu_timeout() {
}
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_action("ui_down") && p_event->is_pressed()) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
@@ -335,7 +361,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed() || (!b->is_pressed() && during_grabbed_click)) {
// Allow activating item by releasing the LMB or any that was down when the popup appeared.
// However, if button was not held when opening menu, do not allow release to activate item.
- if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
+ if (button_idx == MOUSE_BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
bool was_during_grabbed_click = during_grabbed_click;
during_grabbed_click = false;
initial_button_mask = 0;
@@ -451,6 +477,10 @@ void PopupMenu::_draw_items() {
margin_size.width = margin_container->get_theme_constant("margin_right") + margin_container->get_theme_constant("margin_left");
margin_size.height = margin_container->get_theme_constant("margin_top") + margin_container->get_theme_constant("margin_bottom");
+ // Space between the item content and the sides of popup menu.
+ int item_start_padding = get_theme_constant("item_start_padding");
+ int item_end_padding = get_theme_constant("item_end_padding");
+
bool rtl = control->is_layout_rtl();
Ref<StyleBox> style = get_theme_stylebox("panel");
Ref<StyleBox> hover = get_theme_stylebox("hover");
@@ -509,7 +539,7 @@ void PopupMenu::_draw_items() {
Point2 item_ofs = ofs;
Size2 icon_size = items[i].get_icon_size();
- float h = MAX(icon_size.height, items[i].text_buf->get_size().y);
+ float h = _get_item_height(i);
if (i == mouse_over) {
if (rtl) {
@@ -525,24 +555,28 @@ void PopupMenu::_draw_items() {
item_ofs.x += items[i].h_ofs;
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
+ int sep_ofs = Math::floor((h - sep_h) / 2.0);
if (text != String()) {
int text_size = items[i].text_buf->get_size().width;
int text_center = display_width / 2;
int text_left = text_center - text_size / 2;
int text_right = text_center + text_size / 2;
if (text_left > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
}
if (text_right < display_width) {
- labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, display_width - text_right), sep_h)));
+ labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - text_right), sep_h)));
}
} else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(display_width, sep_h)));
+ separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ // For non-separator items, add some padding for the content.
+ item_ofs.x += item_start_padding;
+
// Checkboxes
if (items[i].checkable_type) {
Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
@@ -565,35 +599,53 @@ void PopupMenu::_draw_items() {
// Submenu arrow on right hand side
if (items[i].submenu != "") {
if (rtl) {
- submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
- submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
}
// Text
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
if (items[i].separator) {
if (text != String()) {
int center = (display_width - items[i].text_buf->get_size().width) / 2;
- items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_separator_color);
+ Vector2 text_pos = Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, font_separator_color);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
if (rtl) {
- items[i].text_buf->draw(ci, Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
} else {
- items[i].text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
+ Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
}
}
// Accelerator / Shortcut
if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
if (rtl) {
- item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT);
+ item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding;
} else {
- item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x;
+ item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding;
+ }
+ Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
}
- items[i].accel_text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), i == mouse_over ? font_hover_color : font_accelerator_color);
+ items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color);
}
// Cache the item vertical offset from the first item and the height
@@ -672,6 +724,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = 0; i < items.size(); i++) {
items.write[i].xl_text = tr(items[i].text);
items.write[i].dirty = true;
+ _shape_item(i);
}
child_controls_changed();
@@ -1656,19 +1709,6 @@ PopupMenu::PopupMenu() {
connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
- mouse_over = -1;
- submenu_over = -1;
- initial_button_mask = 0;
- during_grabbed_click = false;
-
- allow_search = true;
- search_time_msec = 0;
- search_string = "";
-
- set_hide_on_item_selection(true);
- set_hide_on_checkable_item_selection(true);
- set_hide_on_multistate_item_selection(false);
-
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);
submenu_timer->set_one_shot(true);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index c050e61d50..e4cbe984c9 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -51,28 +51,28 @@ class PopupMenu : public Popup {
String language;
Control::TextDirection text_direction = Control::TEXT_DIRECTION_AUTO;
- bool checked;
+ bool checked = false;
enum {
CHECKABLE_TYPE_NONE,
CHECKABLE_TYPE_CHECK_BOX,
CHECKABLE_TYPE_RADIO_BUTTON,
} checkable_type;
- int max_states;
- int state;
- bool separator;
- bool disabled;
- bool dirty;
- int id;
+ int max_states = 0;
+ int state = 0;
+ bool separator = false;
+ bool disabled = false;
+ bool dirty = true;
+ int id = 0;
Variant metadata;
String submenu;
String tooltip;
- uint32_t accel;
- int _ofs_cache;
- int _height_cache;
- int h_ofs;
+ uint32_t accel = 0;
+ int _ofs_cache = 0;
+ int _height_cache = 0;
+ int h_ofs = 0;
Ref<Shortcut> shortcut;
- bool shortcut_is_global;
- bool shortcut_is_disabled;
+ bool shortcut_is_global = false;
+ bool shortcut_is_disabled = false;
// Returns (0,0) if icon is null.
Size2 get_icon_size() const {
@@ -82,19 +82,7 @@ class PopupMenu : public Popup {
Item() {
text_buf.instance();
accel_text_buf.instance();
- dirty = true;
- checked = false;
checkable_type = CHECKABLE_TYPE_NONE;
- separator = false;
- max_states = 0;
- state = 0;
- accel = 0;
- disabled = false;
- _ofs_cache = 0;
- _height_cache = 0;
- h_ofs = 0;
- shortcut_is_global = false;
- shortcut_is_disabled = false;
}
};
@@ -104,15 +92,16 @@ class PopupMenu : public Popup {
Timer *submenu_timer;
List<Rect2> autohide_areas;
Vector<Item> items;
- int initial_button_mask;
- bool during_grabbed_click;
- int mouse_over;
- int submenu_over;
+ int initial_button_mask = 0;
+ bool during_grabbed_click = false;
+ int mouse_over = -1;
+ int submenu_over = -1;
Rect2 parent_rect;
String _get_accel_text(const Item &p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 _get_contents_minimum_size() const override;
+ int _get_item_height(int p_item) const;
int _get_items_total_height() const;
void _scroll_to_item(int p_item);
@@ -123,9 +112,9 @@ class PopupMenu : public Popup {
void _submenu_timeout();
uint64_t popup_time_msec = 0;
- bool hide_on_item_selection;
- bool hide_on_checkable_item_selection;
- bool hide_on_multistate_item_selection;
+ bool hide_on_item_selection = true;
+ bool hide_on_checkable_item_selection = true;
+ bool hide_on_multistate_item_selection = false;
Vector2 moved;
Array _get_items() const;
@@ -136,9 +125,9 @@ class PopupMenu : public Popup {
void _ref_shortcut(Ref<Shortcut> p_sc);
void _unref_shortcut(Ref<Shortcut> p_sc);
- bool allow_search;
- uint64_t search_time_msec;
- String search_string;
+ bool allow_search = true;
+ uint64_t search_time_msec = 0;
+ String search_string = "";
MarginContainer *margin_container;
ScrollContainer *scroll_container;
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 1b33cc6ffb..6e8dfd5994 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -74,7 +74,13 @@ void ProgressBar::_notification(int p_what) {
if (percent_visible) {
String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign();
TextLine tl = TextLine(txt, font, font_size);
- tl.draw(get_canvas_item(), (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(), font_color);
+ Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color);
+ }
+ tl.draw(get_canvas_item(), text_pos, font_color);
}
}
}
@@ -98,5 +104,4 @@ void ProgressBar::_bind_methods() {
ProgressBar::ProgressBar() {
set_v_size_flags(0);
set_step(0.01);
- percent_visible = true;
}
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index 3317846108..fb6060d932 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -36,7 +36,7 @@
class ProgressBar : public Range {
GDCLASS(ProgressBar, Range);
- bool percent_visible;
+ bool percent_visible = true;
protected:
void _notification(int p_what);
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 1e33ab0758..adc1ed67ca 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -30,24 +30,20 @@
#include "range.h"
-String Range::get_configuration_warning() const {
- String warning = Control::get_configuration_warning();
+TypedArray<String> Range::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0.");
+ warnings.push_back(TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
}
- return warning;
+ return warnings;
}
void Range::_value_changed_notify() {
_value_changed(shared->val);
emit_signal("value_changed", shared->val);
update();
- _change_notify("value");
}
void Range::Shared::emit_value_changed() {
@@ -63,7 +59,6 @@ void Range::Shared::emit_value_changed() {
void Range::_changed_notify(const char *p_what) {
emit_signal("changed");
update();
- _change_notify(p_what);
}
void Range::Shared::emit_changed(const char *p_what) {
@@ -108,7 +103,7 @@ void Range::set_min(double p_min) {
shared->emit_changed("min");
- update_configuration_warning();
+ update_configuration_warnings();
}
void Range::set_max(double p_max) {
@@ -183,7 +178,6 @@ double Range::get_as_ratio() const {
double v = Math::log(value) / Math::log((double)2);
return CLAMP((v - exp_min) / (exp_max - exp_min), 0, 1);
-
} else {
float value = CLAMP(get_value(), shared->min, shared->max);
return CLAMP((value - get_min()) / (get_max() - get_min()), 0, 1);
@@ -289,7 +283,7 @@ bool Range::is_using_rounded_values() const {
void Range::set_exp_ratio(bool p_enable) {
shared->exp_ratio = p_enable;
- update_configuration_warning();
+ update_configuration_warnings();
}
bool Range::is_ratio_exp() const {
@@ -314,17 +308,7 @@ bool Range::is_lesser_allowed() const {
Range::Range() {
shared = memnew(Shared);
- shared->min = 0;
- shared->max = 100;
- shared->val = 0;
- shared->step = 1;
- shared->page = 0;
shared->owners.insert(this);
- shared->exp_ratio = false;
- shared->allow_greater = false;
- shared->allow_lesser = false;
-
- _rounded_values = false;
}
Range::~Range() {
diff --git a/scene/gui/range.h b/scene/gui/range.h
index 68ff46bd74..7a129e88d6 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -37,11 +37,14 @@ class Range : public Control {
GDCLASS(Range, Control);
struct Shared {
- double val, min, max;
- double step, page;
- bool exp_ratio;
- bool allow_greater;
- bool allow_lesser;
+ double val = 0.0;
+ double min = 0.0;
+ double max = 100.0;
+ double step = 1.0;
+ double page = 0.0;
+ bool exp_ratio = false;
+ bool allow_greater = false;
+ bool allow_lesser = false;
Set<Range *> owners;
void emit_value_changed();
void emit_changed(const char *p_what = "");
@@ -62,7 +65,7 @@ protected:
static void _bind_methods();
- bool _rounded_values;
+ bool _rounded_values = false;
public:
void set_value(double p_val);
@@ -94,7 +97,7 @@ public:
void share(Range *p_range);
void unshare();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Range();
~Range();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 6d5905aedc..c763ae6bd6 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -45,7 +45,7 @@
#include "editor/editor_scale.h"
#endif
-RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
+RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const {
if (p_free) {
if (p_item->subitems.size()) {
return p_item->subitems.front()->get();
@@ -90,7 +90,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
return nullptr;
}
-RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
+RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) const {
if (p_free) {
if (p_item->subitems.size()) {
return p_item->subitems.back()->get();
@@ -220,7 +220,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (tab_size > 0) { // Align inline tabs.
Vector<float> tabs;
- tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width);
l.text_buf->tab_align(tabs);
}
@@ -314,7 +314,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font>
table->rows.clear();
Vector2 offset;
- float row_height = 0;
+ float row_height = 0.0;
for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
@@ -392,7 +392,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
if (tab_size > 0) { // Align inline tabs.
Vector<float> tabs;
- tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width);
+ tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width);
l.text_buf->tab_align(tabs);
}
@@ -454,6 +454,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
ItemImage *img = (ItemImage *)it;
l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
text += String::chr(0xfffc);
+ l.char_count += 1;
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
@@ -553,7 +554,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
table->rows.clear();
Vector2 offset;
- float row_height = 0;
+ float row_height = 0.0;
for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
@@ -587,7 +588,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
offset.x += table->columns[column].width + hseparation + frame->padding.size.x;
row_height = MAX(yofs, row_height);
- if (column == col_count - 1) {
+ // Add row height after last column of the row or last cell of the table.
+ if (column == col_count - 1 || E->next() == nullptr) {
offset.x = 0;
row_height += vseparation;
table->total_height += row_height;
@@ -758,7 +760,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
//draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS
- off.y += TS->shaped_text_get_ascent(rid);
+ off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top();
// Draw inlined objects.
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
@@ -776,6 +778,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Color odd_row_bg = get_theme_color("table_odd_row_bg");
Color even_row_bg = get_theme_color("table_even_row_bg");
Color border = get_theme_color("table_border");
+ int hseparation = get_theme_constant("table_hseparation");
int col_count = table->columns.size();
int row_count = table->rows.size();
@@ -792,11 +795,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
coff.x = rect.size.width - table->columns[col].width - coff.x;
}
if (row % 2 == 0) {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true);
} else {
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true);
}
- draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
+ draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false);
}
for (int j = 0; j < frame->lines.size(); j++) {
@@ -819,8 +822,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
// Draw oulines and shadow.
for (int i = 0; i < gl_size; i++) {
Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
- int size = _find_outline_size(it);
- Color font_color = _find_outline_color(it, Color(0, 0, 0, 0));
+ int size = _find_outline_size(it, p_outline_size);
+ Color font_color = _find_outline_color(it, p_outline_color);
if (size <= 0) {
gloff.x += glyphs[i].advance;
continue;
@@ -1076,7 +1079,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
off.x += glyphs[i].advance;
}
}
- off.y += TS->shaped_text_get_descent(rid);
+ off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom();
}
return line_count;
@@ -1115,7 +1118,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
while (ofs.y < size.height && from_line < main->lines.size()) {
- ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ ofs.y += main->lines[from_line].text_buf->get_size().y;
if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
if (r_outside != nullptr) {
*r_outside = false;
@@ -1170,7 +1174,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
} break;
}
- off.y += TS->shaped_text_get_ascent(rid);
+ off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top();
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
@@ -1234,7 +1238,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (rect.has_point(p_click) && !table_hit) {
char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
}
- off.y += TS->shaped_text_get_descent(rid);
+ off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom();
}
if (char_pos >= 0) {
@@ -1242,8 +1246,19 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (r_click_item != nullptr) {
Item *it = p_frame->lines[p_line].from;
Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
- it = _get_item_at_pos(it, it_to, char_pos);
- *r_click_item = it;
+ if (char_pos == p_frame->lines[p_line].char_count) {
+ // Selection after the end of line, select last item.
+ if (it_to != nullptr) {
+ *r_click_item = _get_prev_item(it_to);
+ } else {
+ for (Item *i = it; i && i != it_to; i = _get_next_item(i)) {
+ *r_click_item = i;
+ }
+ }
+ } else {
+ // Selection in the line.
+ *r_click_item = _get_item_at_pos(it, it_to, char_pos);
+ }
}
if (r_click_frame != nullptr) {
@@ -1398,7 +1413,7 @@ void RichTextLabel::_notification(int p_what) {
}
Ref<Font> base_font = get_theme_font("normal_font");
Color base_color = get_theme_color("default_color");
- Color outline_color = get_theme_color("outline_color");
+ Color outline_color = get_theme_color("font_outline_color");
int outline_size = get_theme_constant("outline_size");
Color font_shadow_color = get_theme_color("font_shadow_color");
bool use_outline = get_theme_constant("shadow_as_outline");
@@ -1454,6 +1469,8 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
}
void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -1464,7 +1481,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
return;
}
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (b->is_pressed() && !b->is_doubleclick()) {
scroll_updated = false;
ItemFrame *c_frame = nullptr;
@@ -1549,12 +1566,12 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (b->get_button_index() == BUTTON_WHEEL_UP) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
if (scroll_active) {
vscroll->set_value(vscroll->get_value() - vscroll->get_page() * b->get_factor() * 0.5 / 8);
}
}
- if (b->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (scroll_active) {
vscroll->set_value(vscroll->get_value() + vscroll->get_page() * b->get_factor() * 0.5 / 8);
}
@@ -1573,53 +1590,36 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
- if (k->is_pressed() && !k->get_alt() && !k->get_shift()) {
+ if (k->is_pressed()) {
bool handled = false;
- switch (k->get_keycode()) {
- case KEY_PAGEUP: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - vscroll->get_page());
- handled = true;
- }
- } break;
- case KEY_PAGEDOWN: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + vscroll->get_page());
- handled = true;
- }
- } break;
- case KEY_UP: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
- handled = true;
- }
- } break;
- case KEY_DOWN: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
- handled = true;
- }
- } break;
- case KEY_HOME: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(0);
- handled = true;
- }
- } break;
- case KEY_END: {
- if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_max());
- handled = true;
- }
- } break;
- case KEY_INSERT:
- case KEY_C: {
- if (k->get_command()) {
- selection_copy();
- handled = true;
- }
- } break;
+ if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(vscroll->get_value() - vscroll->get_page());
+ handled = true;
+ }
+ if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(vscroll->get_value() + vscroll->get_page());
+ handled = true;
+ }
+ if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
+ handled = true;
+ }
+ if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size")));
+ handled = true;
+ }
+ if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(0);
+ handled = true;
+ }
+ if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) {
+ vscroll->set_value(vscroll->get_max());
+ handled = true;
+ }
+ if (k->is_action("ui_copy")) {
+ selection_copy();
+ handled = true;
}
if (handled) {
@@ -1753,7 +1753,7 @@ int RichTextLabel::_find_font_size(Item *p_item) {
return -1;
}
-int RichTextLabel::_find_outline_size(Item *p_item) {
+int RichTextLabel::_find_outline_size(Item *p_item, int p_default) {
Item *sizeitem = p_item;
while (sizeitem) {
@@ -1765,7 +1765,7 @@ int RichTextLabel::_find_outline_size(Item *p_item) {
sizeitem = sizeitem->parent;
}
- return 0;
+ return p_default;
}
Dictionary RichTextLabel::_find_font_features(Item *p_item) {
@@ -1847,7 +1847,7 @@ int RichTextLabel::_find_list(Item *p_item, Vector<int> &r_index, Vector<ItemLis
int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size) {
Item *item = p_item;
- float margin = 0;
+ float margin = 0.0;
while (item) {
if (item->type == ITEM_INDENT) {
@@ -1859,7 +1859,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int
if (font_size == -1) {
font_size = p_base_font_size;
}
- margin += tab_size * font->get_char_size('m', 0, font_size).width;
+ margin += tab_size * font->get_char_size(' ', 0, font_size).width;
} else if (item->type == ITEM_LIST) {
Ref<Font> font = _find_font(item);
@@ -1870,7 +1870,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int
if (font_size == -1) {
font_size = p_base_font_size;
}
- margin += tab_size * font->get_char_size('m', 0, font_size).width;
+ margin += tab_size * font->get_char_size(' ', 0, font_size).width;
}
item = item->parent;
@@ -2252,6 +2252,8 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
}
ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(p_image->get_width() == 0);
+ ERR_FAIL_COND(p_image->get_height() == 0);
ItemImage *item = memnew(ItemImage);
item->image = p_image;
@@ -3520,7 +3522,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
return false;
}
-String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) {
+String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
String text;
ERR_FAIL_COND_V(p_frame == nullptr, text);
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text);
@@ -3587,7 +3589,7 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
return text;
}
-String RichTextLabel::get_selected_text() {
+String RichTextLabel::get_selected_text() const {
if (!selection.active || !selection.enabled) {
return "";
}
@@ -3611,6 +3613,22 @@ bool RichTextLabel::is_selection_enabled() const {
return selection.enabled;
}
+int RichTextLabel::get_selection_from() const {
+ if (!selection.active || !selection.enabled) {
+ return -1;
+ }
+
+ return selection.from_frame->lines[selection.from_line].char_offset + selection.from_char;
+}
+
+int RichTextLabel::get_selection_to() const {
+ if (!selection.active || !selection.enabled) {
+ return -1;
+ }
+
+ return selection.to_frame->lines[selection.to_line].char_offset + selection.to_char - 1;
+}
+
void RichTextLabel::set_bbcode(const String &p_bbcode) {
bbcode = p_bbcode;
if (is_inside_tree() && use_bbcode) {
@@ -3631,6 +3649,7 @@ void RichTextLabel::set_use_bbcode(bool p_enable) {
}
use_bbcode = p_enable;
set_bbcode(bbcode);
+ notify_property_list_changed();
}
bool RichTextLabel::is_using_bbcode() const {
@@ -3646,6 +3665,8 @@ String RichTextLabel::get_text() {
text += t->text;
} else if (it->type == ITEM_NEWLINE) {
text += "\n";
+ } else if (it->type == ITEM_IMAGE) {
+ text += " ";
} else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) {
text += "\t";
}
@@ -3722,7 +3743,6 @@ void RichTextLabel::set_percent_visible(float p_percent) {
}
main->first_invalid_line = 0; //invalidate ALL
_validate_line_caches(main);
- _change_notify("visible_characters");
update();
}
}
@@ -3738,7 +3758,9 @@ void RichTextLabel::set_effects(const Vector<Variant> &effects) {
custom_effects.push_back(effect);
}
- parse_bbcode(bbcode);
+ if ((bbcode != "") && use_bbcode) {
+ parse_bbcode(bbcode);
+ }
}
Vector<Variant> RichTextLabel::get_effects() {
@@ -3755,7 +3777,9 @@ void RichTextLabel::install_effect(const Variant effect) {
if (rteffect.is_valid()) {
custom_effects.push_back(effect);
- parse_bbcode(bbcode);
+ if ((bbcode != "") && use_bbcode) {
+ parse_bbcode(bbcode);
+ }
}
}
@@ -3767,6 +3791,12 @@ int RichTextLabel::get_content_height() const {
return total_height;
}
+void RichTextLabel::_validate_property(PropertyInfo &property) const {
+ if (!use_bbcode && property.name == "bbcode_text") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &RichTextLabel::_gui_input);
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
@@ -3839,6 +3869,11 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selection_enabled", "enabled"), &RichTextLabel::set_selection_enabled);
ClassDB::bind_method(D_METHOD("is_selection_enabled"), &RichTextLabel::is_selection_enabled);
+ ClassDB::bind_method(D_METHOD("get_selection_from"), &RichTextLabel::get_selection_from);
+ ClassDB::bind_method(D_METHOD("get_selection_to"), &RichTextLabel::get_selection_to);
+
+ ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text);
+
ClassDB::bind_method(D_METHOD("parse_bbcode", "bbcode"), &RichTextLabel::parse_bbcode);
ClassDB::bind_method(D_METHOD("append_bbcode", "bbcode"), &RichTextLabel::append_bbcode);
@@ -3948,7 +3983,6 @@ void RichTextLabel::set_visible_characters(int p_visible) {
percent_visible = (float)p_visible / (float)total_char_count;
}
}
- _change_notify("percent_visible");
update();
}
@@ -3971,14 +4005,16 @@ void RichTextLabel::set_fixed_size_to_width(int p_width) {
}
Size2 RichTextLabel::get_minimum_size() const {
- Size2 size(0, 0);
+ Ref<StyleBox> style = get_theme_stylebox("normal");
+ Size2 size = style->get_minimum_size();
+
if (fixed_width != -1) {
- size.x = fixed_width;
+ size.x += fixed_width;
}
if (fixed_width != -1 || fit_content_height) {
const_cast<RichTextLabel *>(this)->_validate_line_caches(main);
- size.y = get_content_height();
+ size.y += get_content_height();
}
return size;
@@ -4066,19 +4102,6 @@ RichTextLabel::RichTextLabel() {
main->first_invalid_line = 0;
main->first_resized_line = 0;
current_frame = main;
- tab_size = 4;
- default_align = ALIGN_LEFT;
- underline_meta = true;
- meta_hovering = nullptr;
- override_selected_font_color = false;
-
- scroll_visible = false;
- scroll_follow = false;
- scroll_following = false;
- updating_scroll = false;
- scroll_active = true;
- scroll_w = 0;
- scroll_updated = false;
vscroll = memnew(VScrollBar);
add_child(vscroll);
@@ -4090,19 +4113,6 @@ RichTextLabel::RichTextLabel() {
vscroll->connect("value_changed", callable_mp(this, &RichTextLabel::_scroll_changed));
vscroll->set_step(1);
vscroll->hide();
- use_bbcode = false;
-
- selection.click_frame = nullptr;
- selection.click_item = nullptr;
- selection.active = false;
- selection.enabled = false;
-
- visible_characters = -1;
- percent_visible = 1;
- visible_line_count = 0;
-
- fixed_width = -1;
- fit_content_height = false;
set_clip_contents(true);
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 037839dac7..e3e457d1f2 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -81,7 +81,9 @@ public:
};
protected:
+ void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
private:
struct Item;
@@ -147,9 +149,9 @@ private:
struct ItemDropcap : public Item {
String text;
Ref<Font> font;
- int font_size;
+ int font_size = 0;
Color color;
- int ol_size;
+ int ol_size = 0;
Color ol_color;
Rect2 dropcap_margins;
ItemDropcap() { type = ITEM_DROPCAP; }
@@ -232,11 +234,11 @@ private:
struct ItemTable : public Item {
struct Column {
- bool expand;
- int expand_ratio;
- int min_width;
- int max_width;
- int width;
+ bool expand = false;
+ int expand_ratio = 0;
+ int min_width = 0;
+ int max_width = 0;
+ int width = 0;
};
Vector<Column> columns;
@@ -322,31 +324,31 @@ private:
}
};
- ItemFrame *main;
- Item *current;
- ItemFrame *current_frame;
+ ItemFrame *main = nullptr;
+ Item *current = nullptr;
+ ItemFrame *current_frame = nullptr;
- VScrollBar *vscroll;
+ VScrollBar *vscroll = nullptr;
- bool scroll_visible;
- bool scroll_follow;
- bool scroll_following;
- bool scroll_active;
- int scroll_w;
- bool scroll_updated;
- bool updating_scroll;
+ bool scroll_visible = false;
+ bool scroll_follow = false;
+ bool scroll_following = false;
+ bool scroll_active = true;
+ int scroll_w = 0;
+ bool scroll_updated = false;
+ bool updating_scroll = false;
int current_idx = 1;
int current_char_ofs = 0;
- int visible_paragraph_count;
- int visible_line_count;
+ int visible_paragraph_count = 0;
+ int visible_line_count = 0;
- int tab_size;
- bool underline_meta;
- bool override_selected_font_color;
+ int tab_size = 4;
+ bool underline_meta = true;
+ bool override_selected_font_color = false;
- Align default_align;
+ Align default_align = ALIGN_LEFT;
- ItemMeta *meta_hovering;
+ ItemMeta *meta_hovering = nullptr;
Variant current_meta;
Vector<Ref<RichTextEffect>> custom_effects;
@@ -363,33 +365,33 @@ private:
Array st_args;
struct Selection {
- ItemFrame *click_frame;
- int click_line;
- Item *click_item;
- int click_char;
-
- ItemFrame *from_frame;
- int from_line;
- Item *from_item;
- int from_char;
-
- ItemFrame *to_frame;
- int to_line;
- Item *to_item;
- int to_char;
-
- bool active; // anything selected? i.e. from, to, etc. valid?
- bool enabled; // allow selections?
+ ItemFrame *click_frame = nullptr;
+ int click_line = 0;
+ Item *click_item = nullptr;
+ int click_char = 0;
+
+ ItemFrame *from_frame = nullptr;
+ int from_line = 0;
+ Item *from_item = nullptr;
+ int from_char = 0;
+
+ ItemFrame *to_frame = nullptr;
+ int to_line = 0;
+ Item *to_item = nullptr;
+ int to_char = 0;
+
+ bool active = false; // anything selected? i.e. from, to, etc. valid?
+ bool enabled = false; // allow selections?
};
Selection selection;
- int visible_characters;
- float percent_visible;
+ int visible_characters = -1;
+ float percent_visible = 1.0;
void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
- String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel);
+ String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
@@ -405,7 +407,7 @@ private:
Ref<Font> _find_font(Item *p_item);
int _find_font_size(Item *p_item);
Dictionary _find_font_features(Item *p_item);
- int _find_outline_size(Item *p_item);
+ int _find_outline_size(Item *p_item, int p_default);
ItemList *_find_list_item(Item *p_item);
ItemDropcap *_find_dc_item(Item *p_item);
int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list);
@@ -427,22 +429,19 @@ private:
void _scroll_changed(double);
void _gui_input(Ref<InputEvent> p_event);
- Item *_get_next_item(Item *p_item, bool p_free = false);
- Item *_get_prev_item(Item *p_item, bool p_free = false);
+ Item *_get_next_item(Item *p_item, bool p_free = false) const;
+ Item *_get_prev_item(Item *p_item, bool p_free = false) const;
Rect2 _get_text_rect();
Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier);
virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions);
- bool use_bbcode;
+ bool use_bbcode = false;
String bbcode;
- int fixed_width;
-
- bool fit_content_height;
+ int fixed_width = -1;
-protected:
- void _notification(int p_what);
+ bool fit_content_height = false;
public:
String get_text();
@@ -524,7 +523,9 @@ public:
void set_selection_enabled(bool p_enabled);
bool is_selection_enabled() const;
- String get_selected_text();
+ int get_selection_from() const;
+ int get_selection_to() const;
+ String get_selected_text() const;
void selection_copy();
Error parse_bbcode(const String &p_bbcode);
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 79a0de35fc..62276e3af0 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -42,6 +42,8 @@ void ScrollBar::set_can_focus_by_default(bool p_can_focus) {
}
void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> m = p_event;
if (!m.is_valid() || drag.active) {
emit_signal("scrolling");
@@ -52,17 +54,17 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (b.is_valid()) {
accept_event();
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && b->is_pressed()) {
set_value(get_value() + get_page() / 4.0);
accept_event();
}
- if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && b->is_pressed()) {
set_value(get_value() - get_page() / 4.0);
accept_event();
}
- if (b->get_button_index() != BUTTON_LEFT) {
+ if (b->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
@@ -434,7 +436,7 @@ double ScrollBar::get_area_size() const {
}
double ScrollBar::get_area_offset() const {
- double ofs = 0;
+ double ofs = 0.0;
if (orientation == VERTICAL) {
ofs += get_theme_stylebox("hscroll")->get_margin(SIDE_TOP);
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 7dd71cc269..24b3b33e82 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -47,14 +47,14 @@ class ScrollBar : public Range {
Orientation orientation;
Size2 size;
- float custom_step = -1;
+ float custom_step = -1.0;
HighlightStatus highlight = HIGHLIGHT_NONE;
struct Drag {
bool active = false;
- float pos_at_click = 0;
- float value_at_click = 0;
+ float pos_at_click = 0.0;
+ float value_at_click = 0.0;
} drag;
double get_grabber_size() const;
@@ -73,14 +73,14 @@ class ScrollBar : public Range {
Vector2 drag_node_accum;
Vector2 drag_node_from;
Vector2 last_drag_node_accum;
- float last_drag_node_time;
- float time_since_motion;
+ float last_drag_node_time = 0.0;
+ float time_since_motion = 0.0;
bool drag_node_touching = false;
bool drag_node_touching_deaccel = false;
- bool click_handled;
+ bool click_handled = false;
bool scrolling = false;
- double target_scroll = 0;
+ double target_scroll = 0.0;
bool smooth_scroll_enabled = false;
void _drag_node_exit();
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 52feb2ab23..73c6371658 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -88,13 +88,15 @@ void ScrollContainer::_cancel_drag() {
}
void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
+ ERR_FAIL_COND(p_gui_input.is_null());
+
double prev_v_scroll = v_scroll->get_value();
double prev_h_scroll = h_scroll->get_value();
Ref<InputEventMouseButton> mb = p_gui_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor());
@@ -103,7 +105,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor());
@@ -112,13 +114,13 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT && mb->is_pressed()) {
if (h_scroll->is_visible_in_tree()) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb->get_factor() / 8);
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT && mb->is_pressed()) {
if (h_scroll->is_visible_in_tree()) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * mb->get_factor() / 8);
}
@@ -132,7 +134,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (mb->get_button_index() != BUTTON_LEFT) {
+ if (mb->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
@@ -244,11 +246,11 @@ void ScrollContainer::_ensure_focused_visible(Control *p_control) {
if (is_a_parent_of(p_control)) {
Rect2 global_rect = get_global_rect();
Rect2 other_rect = p_control->get_global_rect();
- float right_margin = 0;
+ float right_margin = 0.0;
if (v_scroll->is_visible()) {
right_margin += v_scroll->get_size().x;
}
- float bottom_margin = 0;
+ float bottom_margin = 0.0;
if (h_scroll->is_visible()) {
bottom_margin += h_scroll->get_size().y;
}
@@ -542,8 +544,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
follow_focus = p_follow;
}
-String ScrollContainer::get_configuration_warning() const {
- String warning = Container::get_configuration_warning();
+TypedArray<String> ScrollContainer::get_configuration_warnings() const {
+ TypedArray<String> warnings = Container::get_configuration_warnings();
int found = 0;
@@ -563,12 +565,10 @@ String ScrollContainer::get_configuration_warning() const {
}
if (found != 1) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually.");
+ warnings.push_back(TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."));
}
- return warning;
+
+ return warnings;
}
HScrollBar *ScrollContainer::get_h_scrollbar() {
@@ -624,15 +624,7 @@ ScrollContainer::ScrollContainer() {
add_child(v_scroll);
v_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved));
- drag_speed = Vector2();
- drag_touching = false;
- drag_touching_deaccel = false;
- beyond_deadzone = false;
- scroll_h = true;
- scroll_v = true;
-
deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
- follow_focus = false;
set_clip_contents(true);
};
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 7e32cbed1c..e7d73bab0a 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -50,18 +50,18 @@ class ScrollContainer : public Container {
Vector2 drag_accum;
Vector2 drag_from;
Vector2 last_drag_accum;
- float last_drag_time;
- float time_since_motion;
- bool drag_touching;
- bool drag_touching_deaccel;
- bool click_handled;
- bool beyond_deadzone;
+ float last_drag_time = 0.0;
+ float time_since_motion = 0.0;
+ bool drag_touching = false;
+ bool drag_touching_deaccel = false;
+ bool click_handled = false;
+ bool beyond_deadzone = false;
- bool scroll_h;
- bool scroll_v;
+ bool scroll_h = true;
+ bool scroll_v = true;
- int deadzone;
- bool follow_focus;
+ int deadzone = 0;
+ bool follow_focus = false;
void _cancel_drag();
@@ -103,7 +103,7 @@ public:
virtual bool clips_input() const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ScrollContainer();
};
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index 1ac0f2c503..77162c68fa 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -36,7 +36,7 @@ class Separator : public Control {
GDCLASS(Separator, Control);
protected:
- Orientation orientation;
+ Orientation orientation = Orientation::HORIZONTAL;
void _notification(int p_what);
public:
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 0edf1856de..a407ef21cb 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -46,6 +46,8 @@ Size2 Slider::get_minimum_size() const {
}
void Slider::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!editable) {
return;
}
@@ -53,7 +55,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber");
grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x;
@@ -72,9 +74,11 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
grab.active = false;
}
} else if (scrollable) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ grab_focus();
set_value(get_value() + get_step());
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ grab_focus();
set_value(get_value() - get_step());
}
}
@@ -269,12 +273,5 @@ void Slider::_bind_methods() {
Slider::Slider(Orientation p_orientation) {
orientation = p_orientation;
- mouse_inside = false;
- grab.active = false;
- ticks = 0;
- ticks_on_borders = false;
- custom_step = -1;
- editable = true;
- scrollable = true;
set_focus_mode(FOCUS_ALL);
}
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 292931b7b5..65a4036cd1 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -37,23 +37,23 @@ class Slider : public Range {
GDCLASS(Slider, Range);
struct Grab {
- int pos;
- float uvalue;
- bool active;
+ int pos = 0;
+ float uvalue = 0.0;
+ bool active = false;
} grab;
- int ticks;
- bool mouse_inside;
+ int ticks = 0;
+ bool mouse_inside = false;
Orientation orientation;
- float custom_step;
- bool editable;
- bool scrollable;
+ float custom_step = -1.0;
+ bool editable = true;
+ bool scrollable = true;
protected:
void _gui_input(Ref<InputEvent> p_event);
void _notification(int p_what);
static void _bind_methods();
- bool ticks_on_borders;
+ bool ticks_on_borders = false;
public:
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 32c878205e..9dc2afdb2d 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -76,7 +76,7 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) {
}
void SpinBox::_range_click_timeout() {
- if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
bool up = get_local_mouse_position().y < (get_size().height / 2);
set_value(get_value() + (up ? get_step() : -get_step()));
@@ -91,7 +91,17 @@ void SpinBox::_range_click_timeout() {
}
}
+void SpinBox::_release_mouse() {
+ if (drag.enabled) {
+ drag.enabled = false;
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ warp_mouse(drag.capture_pos);
+ }
+}
+
void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_editable()) {
return;
}
@@ -102,7 +112,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
bool up = mb->get_position().y < (get_size().height / 2);
switch (mb->get_button_index()) {
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_LEFT: {
line_edit->grab_focus();
set_value(get_value() + (up ? get_step() : -get_step()));
@@ -114,17 +124,17 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
drag.allowed = true;
drag.capture_pos = mb->get_position();
} break;
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
line_edit->grab_focus();
set_value((up ? get_max() : get_min()));
} break;
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
if (line_edit->has_focus()) {
set_value(get_value() + get_step() * mb->get_factor());
accept_event();
}
} break;
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
if (line_edit->has_focus()) {
set_value(get_value() - get_step() * mb->get_factor());
accept_event();
@@ -133,21 +143,16 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
//set_default_cursor_shape(CURSOR_ARROW);
range_click_timer->stop();
-
- if (drag.enabled) {
- drag.enabled = false;
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
- warp_mouse(drag.capture_pos);
- }
+ _release_mouse();
drag.allowed = false;
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
if (drag.enabled) {
drag.diff_y += mm->get_relative().y;
float diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8f) * SGN(drag.diff_y);
@@ -199,6 +204,8 @@ void SpinBox::_notification(int p_what) {
} else if (p_what == NOTIFICATION_ENTER_TREE) {
_adjust_width_for_icon(get_theme_icon("updown"));
_value_changed(0);
+ } else if (p_what == NOTIFICATION_EXIT_TREE) {
+ _release_mouse();
} else if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
_value_changed(0);
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
@@ -268,7 +275,6 @@ void SpinBox::_bind_methods() {
}
SpinBox::SpinBox() {
- last_w = 0;
line_edit = memnew(LineEdit);
add_child(line_edit);
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index a4e3d644e2..e116adb64c 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -39,10 +39,11 @@ class SpinBox : public Range {
GDCLASS(SpinBox, Range);
LineEdit *line_edit;
- int last_w;
+ int last_w = 0;
Timer *range_click_timer;
void _range_click_timeout();
+ void _release_mouse();
void _text_entered(const String &p_string);
virtual void _value_changed(double) override;
@@ -52,11 +53,11 @@ class SpinBox : public Range {
void _line_edit_input(const Ref<InputEvent> &p_event);
struct Drag {
- float base_val = 0;
+ float base_val = 0.0;
bool allowed = false;
bool enabled = false;
Vector2 capture_pos;
- float diff_y = 0;
+ float diff_y = 0.0;
} drag;
void _line_edit_focus_exit();
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d6f2df1d8c..13ff2c5b86 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -102,7 +102,7 @@ void SplitContainer::_resort() {
middle_sep += clamped_split_offset;
if (should_clamp_split_offset) {
split_offset = clamped_split_offset;
- _change_notify("split_offset");
+
should_clamp_split_offset = false;
}
}
@@ -207,6 +207,8 @@ void SplitContainer::_notification(int p_what) {
}
void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) {
return;
}
@@ -214,7 +216,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
int sep = get_theme_constant("separation");
@@ -359,12 +361,5 @@ void SplitContainer::_bind_methods() {
}
SplitContainer::SplitContainer(bool p_vertical) {
- mouse_inside = false;
- split_offset = 0;
- should_clamp_split_offset = false;
- middle_sep = 0;
vertical = p_vertical;
- dragging = false;
- collapsed = false;
- dragger_visibility = DRAGGER_VISIBLE;
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 46a6792206..6cb94d6ecf 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -44,16 +44,16 @@ public:
};
private:
- bool should_clamp_split_offset;
- int split_offset;
- int middle_sep;
- bool vertical;
- bool dragging;
- int drag_from;
- int drag_ofs;
- bool collapsed;
- DraggerVisibility dragger_visibility;
- bool mouse_inside;
+ bool should_clamp_split_offset = false;
+ int split_offset = 0;
+ int middle_sep = 0;
+ bool vertical = false;
+ bool dragging = false;
+ int drag_from = 0;
+ int drag_ofs = 0;
+ bool collapsed = false;
+ DraggerVisibility dragger_visibility = DRAGGER_VISIBLE;
+ bool mouse_inside = false;
Control *_getch(int p_idx) const;
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 68eef0f96b..bfc7e29f9c 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -140,6 +140,8 @@ void SubViewportContainer::_notification(int p_what) {
}
void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -165,6 +167,8 @@ void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
}
void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -203,8 +207,6 @@ void SubViewportContainer::_bind_methods() {
}
SubViewportContainer::SubViewportContainer() {
- stretch = false;
- shrink = 1;
set_process_input(true);
set_process_unhandled_input(true);
}
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 91fc29d377..77cf4c16b3 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -36,8 +36,8 @@
class SubViewportContainer : public Container {
GDCLASS(SubViewportContainer, Container);
- bool stretch;
- int shrink;
+ bool stretch = false;
+ int shrink = 1;
protected:
void _notification(int p_what);
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 5acc789fbb..ff9dafa0f9 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -72,11 +72,13 @@ int TabContainer::_get_top_margin() const {
}
void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
Popup *popup = get_popup();
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos(mb->get_position().x, mb->get_position().y);
Size2 size = get_size();
@@ -535,6 +537,8 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in
Vector<Control *> tabs = _get_tabs();
RID canvas = get_canvas_item();
Ref<Font> font = get_theme_font("font");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
int icon_text_distance = get_theme_constant("icon_separation");
int tab_width = _get_tab_width(p_index);
int header_height = _get_top_margin();
@@ -565,6 +569,9 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in
// Draw the tab text.
Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color);
+ }
text_buf[p_index]->draw(canvas, text_pos, p_font_color);
}
@@ -640,7 +647,7 @@ int TabContainer::_get_tab_width(int p_index) const {
// Get the width of the text displayed on the tab.
Ref<Font> font = get_theme_font("font");
int font_size = get_theme_font_size("font_size");
- String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(control->get_name());
+ String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name()));
int width = font->get_string_size(text, font_size).width;
// Add space for a tab icon.
@@ -747,8 +754,6 @@ void TabContainer::set_current_tab(int p_current) {
_repaint();
- _change_notify("current_tab");
-
if (pending_previous == current) {
emit_signal("tab_selected", current);
} else {
@@ -967,8 +972,6 @@ void TabContainer::set_tab_align(TabAlign p_align) {
ERR_FAIL_INDEX(p_align, 3);
align = p_align;
update();
-
- _change_notify("tab_align");
}
TabContainer::TabAlign TabContainer::get_tab_align() const {
@@ -1022,6 +1025,7 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = _get_tab(p_tab);
ERR_FAIL_COND(!child);
child->set_meta("_tab_name", p_title);
+ _refresh_texts();
update();
}
@@ -1243,20 +1247,5 @@ void TabContainer::_bind_methods() {
}
TabContainer::TabContainer() {
- first_tab_cache = 0;
- last_tab_cache = 0;
- buttons_visible_cache = false;
- menu_hovered = false;
- highlight_arrow = -1;
- tabs_ofs_cache = 0;
- current = 0;
- previous = 0;
- align = ALIGN_CENTER;
- tabs_visible = true;
- all_tabs_in_front = false;
- drag_to_rearrange_enabled = false;
- tabs_rearrange_group = -1;
- use_hidden_tabs_for_min_size = false;
-
connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited));
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 58742c5be8..4ed5255729 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -46,23 +46,23 @@ public:
};
private:
- int first_tab_cache;
- int tabs_ofs_cache;
- int last_tab_cache;
- int current;
- int previous;
- bool tabs_visible;
- bool all_tabs_in_front;
- bool buttons_visible_cache;
- bool menu_hovered;
- int highlight_arrow;
- TabAlign align;
+ int first_tab_cache = 0;
+ int tabs_ofs_cache = 0;
+ int last_tab_cache = 0;
+ int current = 0;
+ int previous = 0;
+ bool tabs_visible = true;
+ bool all_tabs_in_front = false;
+ bool buttons_visible_cache = false;
+ bool menu_hovered = false;
+ int highlight_arrow = -1;
+ TabAlign align = ALIGN_CENTER;
Control *_get_tab(int p_idx) const;
int _get_top_margin() const;
mutable ObjectID popup_obj_id;
- bool drag_to_rearrange_enabled;
- bool use_hidden_tabs_for_min_size;
- int tabs_rearrange_group;
+ bool drag_to_rearrange_enabled = false;
+ bool use_hidden_tabs_for_min_size = false;
+ int tabs_rearrange_group = -1;
Vector<Ref<TextLine>> text_buf;
Vector<Control *> _get_tabs() const;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index c156b1e6f8..6cbc5890ce 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -83,11 +83,16 @@ Size2 Tabs::get_minimum_size() const {
}
}
- ms.width = 0; //TODO: should make this optional
+ if (clip_tabs) {
+ ms.width = 0;
+ }
+
return ms;
}
void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -105,10 +110,10 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
highlight_arrow = 0;
}
} else {
- int limit = get_size().width - incr->get_width() - decr->get_width();
- if (pos.x > limit + decr->get_width()) {
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+ if (pos.x > limit_minus_buttons + decr->get_width()) {
highlight_arrow = 1;
- } else if (pos.x > limit) {
+ } else if (pos.x > limit_minus_buttons) {
highlight_arrow = 0;
}
}
@@ -122,7 +127,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
if (scrolling_enabled && buttons_visible) {
if (offset > 0) {
offset--;
@@ -131,7 +136,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
if (scrolling_enabled && buttons_visible) {
if (missing_right) {
offset++;
@@ -140,7 +145,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (rb_hover != -1) {
//pressed
emit_signal("right_button_pressed", rb_hover);
@@ -150,7 +155,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (cb_hover != -1) {
//pressed
emit_signal("tab_closed", cb_hover);
@@ -160,7 +165,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb->is_pressed() && (mb->get_button_index() == BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == BUTTON_RIGHT))) {
+ if (mb->is_pressed() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == MOUSE_BUTTON_RIGHT))) {
// clicks
Point2 pos(mb->get_position().x, mb->get_position().y);
@@ -275,6 +280,9 @@ void Tabs::_notification(int p_what) {
Color font_unselected_color = get_theme_color("font_unselected_color");
Color font_disabled_color = get_theme_color("font_disabled_color");
Ref<Texture2D> close = get_theme_icon("close");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+
Vector2 size = get_size();
bool rtl = is_layout_rtl();
@@ -302,7 +310,8 @@ void Tabs::_notification(int p_what) {
Ref<Texture2D> incr_hl = get_theme_icon("increment_highlight");
Ref<Texture2D> decr_hl = get_theme_icon("decrement_highlight");
- int limit = get_size().width - incr->get_size().width - decr->get_size().width;
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
missing_right = false;
@@ -325,7 +334,8 @@ void Tabs::_notification(int p_what) {
col = font_unselected_color;
}
- if (w + lsize > limit) {
+ int new_width = w + lsize;
+ if (new_width > limit || (i < tabs.size() - 1 && new_width > limit_minus_buttons)) { // For the last tab, we accept if the tab covers the buttons.
max_drawn_tab = i - 1;
missing_right = true;
break;
@@ -357,9 +367,17 @@ void Tabs::_notification(int p_what) {
}
if (rtl) {
- tabs[i].text_buf->draw(ci, Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col);
+ Vector2 text_pos = Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ tabs[i].text_buf->draw(ci, text_pos, col);
} else {
- tabs[i].text_buf->draw(ci, Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col);
+ Vector2 text_pos = Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ tabs[i].text_buf->draw(ci, text_pos, col);
}
w += tabs[i].size_text;
@@ -448,15 +466,15 @@ void Tabs::_notification(int p_what) {
}
} else {
if (offset > 0) {
- draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit, vofs));
+ draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs));
} else {
- draw_texture(decr, Point2(limit, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
}
if (missing_right) {
- draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit + decr->get_size().width, vofs));
+ draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs));
} else {
- draw_texture(incr, Point2(limit + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
}
@@ -481,7 +499,6 @@ void Tabs::set_current_tab(int p_current) {
previous = current;
current = p_current;
- _change_notify("current_tab");
_update_cache();
update();
@@ -656,7 +673,7 @@ void Tabs::_update_cache() {
Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected");
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
int w = 0;
int mw = 0;
@@ -676,7 +693,7 @@ void Tabs::_update_cache() {
}
int m_width = min_width;
if (count_resize > 0) {
- m_width = MAX((limit - size_fixed) / count_resize, min_width);
+ m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width);
}
for (int i = offset; i < tabs.size(); i++) {
Ref<StyleBox> sb;
@@ -689,7 +706,7 @@ void Tabs::_update_cache() {
}
int lsize = tabs[i].size_cache;
int slen = tabs[i].size_text;
- if (min_width > 0 && mw > limit && i != current) {
+ if (min_width > 0 && mw > limit_minus_buttons && i != current) {
if (lsize > m_width) {
slen = m_width - (sb->get_margin(SIDE_LEFT) + sb->get_margin(SIDE_RIGHT));
if (tabs[i].icon.is_valid()) {
@@ -899,6 +916,19 @@ Tabs::TabAlign Tabs::get_tab_align() const {
return tab_align;
}
+void Tabs::set_clip_tabs(bool p_clip_tabs) {
+ if (clip_tabs == p_clip_tabs) {
+ return;
+ }
+ clip_tabs = p_clip_tabs;
+ update();
+ minimum_size_changed();
+}
+
+bool Tabs::get_clip_tabs() const {
+ return clip_tabs;
+}
+
void Tabs::move_tab(int from, int to) {
if (from == to) {
return;
@@ -965,7 +995,8 @@ void Tabs::_ensure_no_over_offset() {
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
while (offset > 0) {
int total_w = 0;
@@ -973,7 +1004,7 @@ void Tabs::_ensure_no_over_offset() {
total_w += tabs[i].size_cache;
}
- if (total_w < limit) {
+ if ((buttons_visible && total_w < limit_minus_buttons) || total_w < limit) { // For the last tab, we accept if the tab covers the buttons.
offset--;
update();
} else {
@@ -1004,9 +1035,12 @@ void Tabs::ensure_tab_visible(int p_idx) {
int prev_offset = offset;
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+
for (int i = offset; i <= p_idx; i++) {
- if (tabs[i].ofs_cache + tabs[i].size_cache > limit) {
+ int total_w = tabs[i].ofs_cache + tabs[i].size_cache;
+ if (total_w > limit || (buttons_visible && total_w > limit_minus_buttons)) {
offset++;
}
}
@@ -1095,6 +1129,8 @@ void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &Tabs::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align);
ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align);
+ ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &Tabs::set_clip_tabs);
+ ClassDB::bind_method(D_METHOD("get_clip_tabs"), &Tabs::get_clip_tabs);
ClassDB::bind_method(D_METHOD("get_tab_offset"), &Tabs::get_tab_offset);
ClassDB::bind_method(D_METHOD("get_offset_buttons_visible"), &Tabs::get_offset_buttons_visible);
ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible);
@@ -1121,6 +1157,7 @@ void Tabs::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
@@ -1137,27 +1174,5 @@ void Tabs::_bind_methods() {
}
Tabs::Tabs() {
- current = 0;
- previous = 0;
- tab_align = ALIGN_CENTER;
- rb_hover = -1;
- rb_pressing = false;
- highlight_arrow = -1;
-
- cb_hover = -1;
- cb_pressing = false;
- cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER;
- offset = 0;
- max_drawn_tab = 0;
-
- select_with_rmb = false;
-
- min_width = 0;
- scrolling_enabled = true;
- buttons_visible = false;
- hover = -1;
- drag_to_rearrange_enabled = false;
- tabs_rearrange_group = -1;
-
connect("mouse_exited", callable_mp(this, &Tabs::_on_mouse_exited));
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 4396981004..61c9a5d96a 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -63,42 +63,43 @@ private:
Ref<TextLine> text_buf;
Ref<Texture2D> icon;
- int ofs_cache;
- bool disabled;
- int size_cache;
- int size_text;
- int x_cache;
- int x_size_cache;
+ int ofs_cache = 0;
+ bool disabled = false;
+ int size_cache = 0;
+ int size_text = 0;
+ int x_cache = 0;
+ int x_size_cache = 0;
Ref<Texture2D> right_button;
Rect2 rb_rect;
Rect2 cb_rect;
};
- int offset;
- int max_drawn_tab;
- int highlight_arrow;
- bool buttons_visible;
- bool missing_right;
+ int offset = 0;
+ int max_drawn_tab = 0;
+ int highlight_arrow = -1;
+ bool buttons_visible = false;
+ bool missing_right = false;
Vector<Tab> tabs;
- int current;
- int previous;
+ int current = 0;
+ int previous = 0;
int _get_top_margin() const;
- TabAlign tab_align;
- int rb_hover;
- bool rb_pressing;
+ TabAlign tab_align = ALIGN_CENTER;
+ bool clip_tabs = true;
+ int rb_hover = -1;
+ bool rb_pressing = false;
- bool select_with_rmb;
+ bool select_with_rmb = false;
- int cb_hover;
- bool cb_pressing;
- CloseButtonDisplayPolicy cb_displaypolicy;
+ int cb_hover = -1;
+ bool cb_pressing = false;
+ CloseButtonDisplayPolicy cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER;
- int hover; // Hovered tab.
- int min_width;
- bool scrolling_enabled;
- bool drag_to_rearrange_enabled;
- int tabs_rearrange_group;
+ int hover = -1; // Hovered tab.
+ int min_width = 0;
+ bool scrolling_enabled = true;
+ bool drag_to_rearrange_enabled = false;
+ int tabs_rearrange_group = -1;
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
@@ -148,6 +149,9 @@ public:
void set_tab_align(TabAlign p_align);
TabAlign get_tab_align() const;
+ void set_clip_tabs(bool p_clip_tabs);
+ bool get_clip_tabs() const;
+
void move_tab(int from, int to);
void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 9285314abe..4f508423b3 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
+#include "core/input/input_map.h"
#include "core/object/message_queue.h"
#include "core/object/script_language.h"
#include "core/os/keyboard.h"
@@ -202,7 +203,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
// Apply tab align.
if (indent_size > 0) {
Vector<float> tabs;
- tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size);
+ tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
text.write[p_line].data_buf->tab_align(tabs);
}
}
@@ -212,7 +213,7 @@ void TextEdit::Text::invalidate_all_lines() {
text.write[i].data_buf->set_width(width);
if (indent_size > 0) {
Vector<float> tabs;
- tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size);
+ tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
text.write[i].data_buf->tab_align(tabs);
}
}
@@ -356,10 +357,10 @@ void TextEdit::_update_scrollbars() {
}
void TextEdit::_click_selection_held() {
- // Warning: is_mouse_button_pressed(BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
+ // Warning: is_mouse_button_pressed(MOUSE_BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
// and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
// I'm unsure if there's an actual fix that doesn't have a ton of side effects.
- if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
switch (selection.selecting_mode) {
case SelectionMode::SELECTION_MODE_POINTER: {
_update_selection_mode_pointer();
@@ -411,25 +412,16 @@ void TextEdit::_update_selection_mode_word() {
_get_mouse_pos(Point2i(mp.x, mp.y), row, col);
String line = text[row];
- int beg = CLAMP(col, 0, line.length());
- // If its the first selection and on whitespace make sure we grab the word instead.
- if (!selection.active) {
- while (beg > 0 && line[beg] <= 32) {
- beg--;
- }
- }
+ int cursor_pos = CLAMP(col, 0, line.length());
+ int beg = cursor_pos;
int end = beg;
- bool symbol = beg < line.length() && _is_symbol(line[beg]);
-
- // Get the word end and begin points.
- while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) {
- beg--;
- }
- while (end < line.length() && line[end + 1] > 32 && (symbol == _is_symbol(line[end + 1]))) {
- end++;
- }
- if (end < line.length()) {
- end += 1;
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(row)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x < cursor_pos && words[i].y > cursor_pos) {
+ beg = words[i].x;
+ end = words[i].y;
+ break;
+ }
}
// Initial selection.
@@ -500,7 +492,7 @@ void TextEdit::_update_minimap_click() {
int row;
_get_minimap_mouse_row(Point2i(mp.x, mp.y), row);
- if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) {
+ if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
minimap_scroll_ratio = v_scroll->get_as_ratio();
minimap_scroll_click_pos = mp.y;
can_drag_minimap = true;
@@ -816,7 +808,7 @@ void TextEdit::_notification(int p_what) {
// Get the highlighted words.
String highlighted_text = get_selection_text();
- // Check if highlighted words contains only whitespaces (tabs or spaces).
+ // Check if highlighted words contain only whitespaces (tabs or spaces).
bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
int cursor_wrap_index = get_cursor_wrap_index();
@@ -977,6 +969,16 @@ void TextEdit::_notification(int p_what) {
}
}
+ int top_limit_y = 0;
+ int bottom_limit_y = get_size().height;
+ if (readonly) {
+ top_limit_y += cache.style_readonly->get_margin(SIDE_TOP);
+ bottom_limit_y -= cache.style_readonly->get_margin(SIDE_BOTTOM);
+ } else {
+ top_limit_y += cache.style_normal->get_margin(SIDE_TOP);
+ bottom_limit_y -= cache.style_normal->get_margin(SIDE_BOTTOM);
+ }
+
// draw main text
int row_height = get_row_height();
int line = first_visible_line;
@@ -1019,17 +1021,33 @@ void TextEdit::_notification(int p_what) {
const String &str = wrap_rows[line_wrap_index];
int char_margin = xmargin_beg - cursor.x_ofs;
- int ofs_readonly = 0;
int ofs_x = 0;
+ int ofs_y = 0;
if (readonly) {
- ofs_readonly = cache.style_readonly->get_offset().y / 2;
ofs_x = cache.style_readonly->get_offset().x / 2;
+ ofs_x -= cache.style_normal->get_offset().x / 2;
+ ofs_y = cache.style_readonly->get_offset().y / 2;
+ } else {
+ ofs_y = cache.style_normal->get_offset().y / 2;
}
- int ofs_y = (i * row_height + cache.line_spacing / 2) + ofs_readonly;
+ ofs_y += i * row_height + cache.line_spacing / 2;
ofs_y -= cursor.wrap_ofs * row_height;
ofs_y -= get_v_scroll_offset() * row_height;
+ bool clipped = false;
+ if (ofs_y + row_height < top_limit_y) {
+ // Line is outside the top margin, clip current line.
+ // Still need to go through the process to prepare color changes for next lines.
+ clipped = true;
+ }
+
+ if (ofs_y > bottom_limit_y) {
+ // Line is outside the bottom margin, clip any remaining text.
+ i = draw_amount;
+ break;
+ }
+
if (text.is_marked(line)) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), cache.mark_color);
@@ -1039,7 +1057,7 @@ void TextEdit::_notification(int p_what) {
}
if (str.length() == 0) {
- // Draw line background if empty as we won't loop at at all.
+ // Draw line background if empty as we won't loop at all.
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), cache.current_line_color);
@@ -1050,7 +1068,7 @@ void TextEdit::_notification(int p_what) {
// Give visual indication of empty selected line.
if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) {
- int char_w = cache.font->get_char_size('m', 0, cache.font_size).width;
+ int char_w = cache.font->get_char_size(' ', 0, cache.font_size).width;
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), cache.selection_color);
} else {
@@ -1091,6 +1109,9 @@ void TextEdit::_notification(int p_what) {
tl->add_string(text, cache.font, cache.font_size);
int yofs = ofs_y + (row_height - tl->get_size().y) / 2;
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ tl->draw_outline(ci, Point2(gutter_offset + ofs_x, yofs), cache.outline_size, cache.outline_color);
+ }
tl->draw(ci, Point2(gutter_offset + ofs_x, yofs), get_line_gutter_item_color(line, g));
} break;
case GUTTER_TPYE_ICON: {
@@ -1147,7 +1168,7 @@ void TextEdit::_notification(int p_what) {
char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x;
}
- if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
+ if (!clipped && selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection
int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column;
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to);
@@ -1167,7 +1188,7 @@ void TextEdit::_notification(int p_what) {
}
int start = TS->shaped_text_get_range(rid).x;
- if (!search_text.is_empty()) { // Search highhlight
+ if (!clipped && !search_text.is_empty()) { // Search highhlight
int search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
while (search_text_col != -1) {
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, search_text_col + start, search_text_col + search_text.length() + start);
@@ -1190,7 +1211,7 @@ void TextEdit::_notification(int p_what) {
}
}
- if (highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.is_empty()) { // Highlight
+ if (!clipped && highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.is_empty()) { // Highlight
int highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
while (highlighted_text_col != -1) {
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, highlighted_text_col + start, highlighted_text_col + highlighted_text.length() + start);
@@ -1212,7 +1233,7 @@ void TextEdit::_notification(int p_what) {
}
}
- if (select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word
+ if (!clipped && select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word
if (_is_char(highlighted_word[0]) || highlighted_word[0] == '.') {
int highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
while (highlighted_word_col != -1) {
@@ -1247,6 +1268,22 @@ void TextEdit::_notification(int p_what) {
ofs_y += ldata->get_line_ascent(line_wrap_index);
int char_ofs = 0;
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ for (int j = 0; j < gl_size; j++) {
+ for (int k = 0; k < glyphs[j].repeat; k++) {
+ if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
+ if (glyphs[j].font_rid != RID()) {
+ TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, cache.outline_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, cache.outline_color);
+ }
+ }
+ char_ofs += glyphs[j].advance;
+ }
+ if ((char_ofs + char_margin) >= xmargin_end) {
+ break;
+ }
+ }
+ char_ofs = 0;
+ }
for (int j = 0; j < gl_size; j++) {
if (color_map.has(glyphs[j].start)) {
current_color = color_map[glyphs[j].start].get("color");
@@ -1297,7 +1334,7 @@ void TextEdit::_notification(int p_what) {
}
for (int k = 0; k < glyphs[j].repeat; k++) {
- if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
+ if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
@@ -1327,7 +1364,7 @@ void TextEdit::_notification(int p_what) {
#else
int caret_width = 1;
#endif
- if (cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) {
+ if (!clipped && cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) {
is_cursor_line_visible = true;
cursor_pos.y = line_top_offset_y;
@@ -1380,7 +1417,7 @@ void TextEdit::_notification(int p_what) {
l_caret.size.y = h;
}
l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- l_caret.size.x = cache.font->get_char_size('m', 0, cache.font_size).x;
+ l_caret.size.x = cache.font->get_char_size('M', 0, cache.font_size).x;
draw_rect(l_caret, cache.caret_color, false);
}
@@ -1405,7 +1442,7 @@ void TextEdit::_notification(int p_what) {
}
} else {
{
- // IME intermidiet text range.
+ // IME Intermediate text range.
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, cursor.column, cursor.column + ime_text.length());
for (int j = 0; j < sel.size(); j++) {
Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
@@ -1444,7 +1481,6 @@ void TextEdit::_notification(int p_what) {
}
}
}
- ofs_y += ldata->get_line_descent(line_wrap_index);
}
}
@@ -1521,7 +1557,7 @@ void TextEdit::_notification(int p_what) {
completion_rect.position.x = rect_left_border_x;
}
- if (cursor_pos.y + row_height + total_height > get_size().height) {
+ if (cursor_pos.y + row_height + total_height > get_size().height && cursor_pos.y > total_height) {
// Completion panel above the cursor line
completion_rect.position.y = cursor_pos.y - total_height;
} else {
@@ -1576,6 +1612,9 @@ void TextEdit::_notification(int p_what) {
}
tl->set_align(HALIGN_LEFT);
}
+ if (cache.outline_size > 0 && cache.outline_color.a > 0) {
+ tl->draw_outline(ci, title_pos, cache.outline_size, cache.outline_color);
+ }
tl->draw(ci, title_pos, completion_options[l].font_color);
}
@@ -1663,7 +1702,7 @@ void TextEdit::_notification(int p_what) {
}
if (has_focus()) {
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
}
@@ -1676,7 +1715,7 @@ void TextEdit::_notification(int p_what) {
draw_caret = true;
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(false), get_viewport()->get_window_id());
}
@@ -1705,7 +1744,7 @@ void TextEdit::_notification(int p_what) {
caret_blink_timer->stop();
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id());
}
@@ -1934,11 +1973,11 @@ void TextEdit::backspace_at_cursor() {
}
}
- cursor_set_line(prev_line, true, true);
+ cursor_set_line(prev_line, false, true);
cursor_set_column(prev_column);
}
-void TextEdit::indent_right() {
+void TextEdit::indent_selected_lines_right() {
int start_line;
int end_line;
@@ -1970,7 +2009,7 @@ void TextEdit::indent_right() {
// We don't really care where selection is - we just need to know indentation level at the beginning of the line.
int left = _find_first_non_whitespace_column_of_line(line_text);
int spaces_to_add = _calculate_spaces_till_next_right_indent(left);
- // Since we will add this much spaces we want move whole selection and cursor by this much.
+ // Since we will add these many spaces, we want to move the whole selection and cursor by this much.
selection_offset = spaces_to_add;
for (int j = 0; j < spaces_to_add; j++) {
line_text = ' ' + line_text;
@@ -1990,12 +2029,12 @@ void TextEdit::indent_right() {
update();
}
-void TextEdit::indent_left() {
+void TextEdit::indent_selected_lines_left() {
int start_line;
int end_line;
// Moving cursor and selection after unindenting can get tricky because
- // changing content of line can move cursor and selection on it's own (if new line ends before previous position of either),
+ // changing content of line can move cursor and selection on its own (if new line ends before previous position of either),
// therefore we just remember initial values and at the end of the operation offset them by number of removed characters.
int removed_characters = 0;
int initial_selection_end_column = selection.to_column;
@@ -2061,6 +2100,623 @@ int TextEdit::_calculate_spaces_till_next_right_indent(int column) {
return indent_size - column % indent_size;
}
+void TextEdit::_swap_current_input_direction() {
+ if (input_direction == TEXT_DIRECTION_LTR) {
+ input_direction = TEXT_DIRECTION_RTL;
+ } else {
+ input_direction = TEXT_DIRECTION_LTR;
+ }
+ cursor_set_column(cursor.column);
+ update();
+}
+
+void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
+ if (readonly) {
+ return;
+ }
+
+ String ins = "\n";
+
+ // Keep indentation.
+ int space_count = 0;
+ for (int i = 0; i < cursor.column; i++) {
+ if (text[cursor.line][i] == '\t') {
+ if (indent_using_spaces) {
+ ins += space_indent;
+ } else {
+ ins += "\t";
+ }
+ space_count = 0;
+ } else if (text[cursor.line][i] == ' ') {
+ space_count++;
+
+ if (space_count == indent_size) {
+ if (indent_using_spaces) {
+ ins += space_indent;
+ } else {
+ ins += "\t";
+ }
+ space_count = 0;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (is_folded(cursor.line)) {
+ unfold_line(cursor.line);
+ }
+
+ bool brace_indent = false;
+
+ // No need to indent if we are going upwards.
+ if (auto_indent && !p_above) {
+ // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment
+ // (i.e. colon/brace precedes current cursor position).
+ if (cursor.column > 0) {
+ bool indent_char_found = false;
+ bool should_indent = false;
+ char indent_char = ':';
+ char c = text[cursor.line][cursor.column];
+
+ for (int i = 0; i < cursor.column; i++) {
+ c = text[cursor.line][i];
+ switch (c) {
+ case ':':
+ case '{':
+ case '[':
+ case '(':
+ indent_char_found = true;
+ should_indent = true;
+ indent_char = c;
+ continue;
+ }
+
+ if (indent_char_found && is_line_comment(cursor.line)) {
+ should_indent = true;
+ break;
+ } else if (indent_char_found && !_is_whitespace(c)) {
+ should_indent = false;
+ indent_char_found = false;
+ }
+ }
+
+ if (!is_line_comment(cursor.line) && should_indent) {
+ if (indent_using_spaces) {
+ ins += space_indent;
+ } else {
+ ins += "\t";
+ }
+
+ // No need to move the brace below if we are not taking the text with us.
+ char32_t closing_char = _get_right_pair_symbol(indent_char);
+ if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column])) {
+ if (p_split_current_line) {
+ brace_indent = true;
+ ins += "\n" + ins.substr(1, ins.length() - 2);
+ } else {
+ brace_indent = false;
+ ins = "\n" + ins.substr(1, ins.length() - 2);
+ }
+ }
+ }
+ }
+ }
+ begin_complex_operation();
+ bool first_line = false;
+ if (!p_split_current_line) {
+ if (p_above) {
+ if (cursor.line > 0) {
+ cursor_set_line(cursor.line - 1, false);
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ cursor_set_column(0);
+ first_line = true;
+ }
+ } else {
+ cursor_set_column(text[cursor.line].length());
+ }
+ }
+
+ insert_text_at_cursor(ins);
+
+ if (first_line) {
+ cursor_set_line(0);
+ } else if (brace_indent) {
+ cursor_set_line(cursor.line - 1, false);
+ cursor_set_column(text[cursor.line].length());
+ }
+ end_complex_operation();
+}
+
+void TextEdit::_indent_right() {
+ if (readonly) {
+ return;
+ }
+
+ if (is_selection_active()) {
+ indent_selected_lines_right();
+ } else {
+ // Simple indent.
+ if (indent_using_spaces) {
+ // Insert only as much spaces as needed till next indentation level.
+ int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column);
+ String indent_to_insert = String();
+ for (int i = 0; i < spaces_to_add; i++) {
+ indent_to_insert = ' ' + indent_to_insert;
+ }
+ _insert_text_at_cursor(indent_to_insert);
+ } else {
+ _insert_text_at_cursor("\t");
+ }
+ }
+}
+
+void TextEdit::_indent_left() {
+ if (readonly) {
+ return;
+ }
+
+ if (is_selection_active()) {
+ indent_selected_lines_left();
+ } else {
+ // Simple unindent.
+ int cc = cursor.column;
+ const String &line = text[cursor.line];
+
+ int left = _find_first_non_whitespace_column_of_line(line);
+ cc = MIN(cc, left);
+
+ while (cc < indent_size && cc < left && line[cc] == ' ') {
+ cc++;
+ }
+
+ if (cc > 0 && cc <= text[cursor.line].length()) {
+ if (text[cursor.line][cc - 1] == '\t') {
+ // Tabs unindentation.
+ _remove_text(cursor.line, cc - 1, cursor.line, cc);
+ if (cursor.column >= left) {
+ cursor_set_column(MAX(0, cursor.column - 1));
+ }
+ update();
+ } else {
+ // Spaces unindentation.
+ int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
+ if (spaces_to_remove > 0) {
+ _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc);
+ if (cursor.column > left - spaces_to_remove) { // Inside text?
+ cursor_set_column(MAX(0, cursor.column - spaces_to_remove));
+ }
+ update();
+ }
+ }
+ } else if (cc == 0 && line.length() > 0 && line[0] == '\t') {
+ _remove_text(cursor.line, 0, cursor.line, 1);
+ update();
+ }
+ }
+}
+
+void TextEdit::_move_cursor_left(bool p_select, bool p_move_by_word) {
+ // Handle selection
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ if (p_move_by_word) {
+ int cc = cursor.column;
+
+ if (cc == 0 && cursor.line > 0) {
+ cursor_set_line(cursor.line - 1);
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid());
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < cc) {
+ cc = words[i].x;
+ break;
+ }
+ }
+ cursor_set_column(cc);
+ }
+ } else {
+ // If the cursor is at the start of the line, and not on the first line, move it up to the end of the previous line.
+ if (cursor.column == 0) {
+ if (cursor.line > 0) {
+ cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1));
+ cursor_set_column(text[cursor.line].length());
+ }
+ } else {
+ if (mid_grapheme_caret_enabled) {
+ cursor_set_column(cursor_get_column() - 1);
+ } else {
+ cursor_set_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column()));
+ }
+ }
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+}
+
+void TextEdit::_move_cursor_right(bool p_select, bool p_move_by_word) {
+ // Handle selection
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ if (p_move_by_word) {
+ int cc = cursor.column;
+
+ if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) {
+ cursor_set_line(cursor.line + 1);
+ cursor_set_column(0);
+ } else {
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > cc) {
+ cc = words[i].y;
+ break;
+ }
+ }
+ cursor_set_column(cc);
+ }
+ } else {
+ // If we are at the end of the line, move the caret to the next line down.
+ if (cursor.column == text[cursor.line].length()) {
+ if (cursor.line < text.size() - 1) {
+ cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
+ cursor_set_column(0);
+ }
+ } else {
+ if (mid_grapheme_caret_enabled) {
+ cursor_set_column(cursor_get_column() + 1);
+ } else {
+ cursor_set_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column()));
+ }
+ }
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+}
+
+void TextEdit::_move_cursor_up(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index > 0) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index - 1);
+ } else if (cursor.line == 0) {
+ cursor_set_column(0);
+ } else {
+ int new_line = cursor.line - num_lines_from(cursor.line - 1, -1);
+ if (line_wraps(new_line)) {
+ cursor_set_line(new_line, true, false, times_line_wraps(new_line));
+ } else {
+ cursor_set_line(new_line, true, false);
+ }
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+
+ _cancel_code_hint();
+}
+
+void TextEdit::_move_cursor_down(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index < times_line_wraps(cursor.line)) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index + 1);
+ } else if (cursor.line == get_last_unhidden_line()) {
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1);
+ cursor_set_line(new_line, true, false, 0);
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+
+ _cancel_code_hint();
+}
+
+void TextEdit::_move_cursor_to_line_start(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ // Move cursor column to start of wrapped row and then to start of text.
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_start_col = 0;
+ for (int i = 0; i < wi; i++) {
+ row_start_col += rows[i].length();
+ }
+ if (cursor.column == row_start_col || wi == 0) {
+ // Compute whitespace symbols sequence length.
+ int current_line_whitespace_len = 0;
+ while (current_line_whitespace_len < text[cursor.line].length()) {
+ char32_t c = text[cursor.line][current_line_whitespace_len];
+ if (c != '\t' && c != ' ') {
+ break;
+ }
+ current_line_whitespace_len++;
+ }
+
+ if (cursor_get_column() == current_line_whitespace_len) {
+ cursor_set_column(0);
+ } else {
+ cursor_set_column(current_line_whitespace_len);
+ }
+ } else {
+ cursor_set_column(row_start_col);
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+
+ _cancel_completion();
+ completion_hint = "";
+}
+
+void TextEdit::_move_cursor_to_line_end(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ // Move cursor column to end of wrapped row and then to end of text.
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_end_col = -1;
+ for (int i = 0; i < wi + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (wi == rows.size() - 1 || cursor.column == row_end_col) {
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ cursor_set_column(row_end_col);
+ }
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+ _cancel_completion();
+ completion_hint = "";
+}
+
+void TextEdit::_move_cursor_page_up(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ int wi;
+ int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1;
+ cursor_set_line(n_line, true, false, wi);
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+
+ _cancel_completion();
+ completion_hint = "";
+}
+
+void TextEdit::_move_cursor_page_down(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ int wi;
+ int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1;
+ cursor_set_line(n_line, true, false, wi);
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+
+ _cancel_completion();
+ completion_hint = "";
+}
+
+void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
+ if (readonly) {
+ return;
+ }
+
+ if (is_selection_active()) {
+ _delete_selection();
+ return;
+ }
+ if (p_all_to_left) {
+ int cursor_current_column = cursor.column;
+ cursor.column = 0;
+ _remove_text(cursor.line, 0, cursor.line, cursor_current_column);
+ } else if (p_word) {
+ int line = cursor.line;
+ int column = cursor.column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < column) {
+ column = words[i].x;
+ break;
+ }
+ }
+
+ _remove_text(line, column, cursor.line, cursor.column);
+
+ cursor_set_line(line, false);
+ cursor_set_column(column);
+ } else {
+ // One character.
+ if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) {
+ unfold_line(cursor.line - 1);
+ }
+ backspace_at_cursor();
+ }
+}
+
+void TextEdit::_delete(bool p_word, bool p_all_to_right) {
+ if (readonly) {
+ return;
+ }
+
+ if (is_selection_active()) {
+ _delete_selection();
+ return;
+ }
+ int curline_len = text[cursor.line].length();
+
+ if (cursor.line == text.size() - 1 && cursor.column == curline_len) {
+ return; // Last line, last column: Nothing to do.
+ }
+
+ int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1;
+ int next_column;
+
+ if (p_all_to_right) {
+ // Delete everything to right of cursor
+ next_column = curline_len;
+ next_line = cursor.line;
+ } else if (p_word && cursor.column < curline_len - 1) {
+ // Delete next word to right of cursor
+ int line = cursor.line;
+ int column = cursor.column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > column) {
+ column = words[i].y;
+ break;
+ }
+ }
+
+ next_line = line;
+ next_column = column;
+ } else {
+ // Delete one character
+ next_column = cursor.column < curline_len ? (cursor.column + 1) : 0;
+ if (mid_grapheme_caret_enabled) {
+ next_column = cursor.column < curline_len ? (cursor.column + 1) : 0;
+ } else {
+ next_column = cursor.column < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), (cursor.column)) : 0;
+ }
+ }
+
+ _remove_text(cursor.line, cursor.column, next_line, next_column);
+ update();
+}
+
+void TextEdit::_delete_selection() {
+ if (is_selection_active()) {
+ selection.active = false;
+ update();
+ _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ cursor_set_line(selection.from_line, false, false);
+ cursor_set_column(selection.from_column);
+ update();
+ }
+}
+
+void TextEdit::_move_cursor_document_start(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ cursor_set_line(0);
+ cursor_set_column(0);
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+}
+
+void TextEdit::_move_cursor_document_end(bool p_select) {
+ if (p_select) {
+ _pre_shift_selection();
+ } else {
+ deselect();
+ }
+
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
+ cursor_set_column(text[cursor.line].length());
+
+ if (p_select) {
+ _post_shift_selection();
+ }
+}
+
+void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete) {
+ if (p_update_auto_complete) {
+ _reset_caret_blink_timer();
+ }
+
+ if (p_had_selection) {
+ _delete_selection();
+ }
+
+ // Remove the old character if in insert mode and no selection.
+ if (insert_mode && !p_had_selection) {
+ begin_complex_operation();
+
+ // Make sure we don't try and remove empty space.
+ if (cursor.column < get_line(cursor.line).length()) {
+ _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
+ }
+ }
+
+ const char32_t chr[2] = { (char32_t)unicode, 0 };
+
+ // Clear completion hint when function closed
+ if (completion_hint != "" && unicode == ')') {
+ completion_hint = "";
+ }
+
+ if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
+ _consume_pair_symbol(chr[0]);
+ } else {
+ _insert_text_at_cursor(chr);
+ }
+
+ if ((insert_mode && !p_had_selection) || (selection.active != p_had_selection)) {
+ end_complex_operation();
+ }
+
+ if (p_update_auto_complete) {
+ _update_completion_candidates();
+ }
+}
+
void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const {
float rows = p_mouse.y;
rows -= cache.style_normal->get_margin(SIDE_TOP);
@@ -2091,6 +2747,18 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
} else {
int colx = p_mouse.x - (cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding);
colx += cursor.x_ofs;
+ col = get_char_pos_for_line(colx, row, wrap_index);
+ if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) {
+ // Move back one if we are at the end of the row.
+ Vector<String> rows2 = get_wrap_rows_text(row);
+ int row_end_col = 0;
+ for (int i = 0; i < wrap_index + 1; i++) {
+ row_end_col += rows2[i].length();
+ }
+ if (col >= row_end_col) {
+ col -= 1;
+ }
+ }
RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index);
if (is_layout_rtl()) {
@@ -2186,6 +2854,8 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
}
void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
+ ERR_FAIL_COND(p_gui_input.is_null());
+
double prev_v_scroll = v_scroll->get_value();
double prev_h_scroll = h_scroll->get_value();
@@ -2205,14 +2875,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
if (completion_index > 0) {
completion_index--;
completion_current = completion_options[completion_index];
update();
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (completion_index < completion_options.size() - 1) {
completion_index++;
completion_current = completion_options[completion_index];
@@ -2220,7 +2890,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
completion_index = CLAMP(completion_line_ofs + (mpos.y - completion_rect.position.y) / get_row_height(), 0, completion_options.size() - 1);
completion_current = completion_options[completion_index];
@@ -2236,27 +2906,27 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (mb->is_pressed()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
if (mb->get_shift()) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
} else if (v_scroll->is_visible()) {
_scroll_up(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
if (mb->get_shift()) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
} else if (v_scroll->is_visible()) {
_scroll_down(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
}
- if (mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_reset_caret_blink_timer();
int row, col;
@@ -2321,8 +2991,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
if (cursor.line < selection.selecting_line || (cursor.line == selection.selecting_line && cursor.column < selection.selecting_column)) {
if (selection.shiftclick_left) {
- SWAP(selection.from_column, selection.to_column);
- SWAP(selection.from_line, selection.to_line);
selection.shiftclick_left = !selection.shiftclick_left;
}
selection.from_column = cursor.column;
@@ -2343,7 +3011,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
update();
}
-
} else {
selection.active = false;
selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
@@ -2366,7 +3033,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
update();
}
- if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
_reset_caret_blink_timer();
int row, col;
@@ -2392,12 +3059,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
menu->set_position(get_screen_transform().xform(mpos));
menu->set_size(Vector2(1, 1));
- // menu->set_scale(get_global_transform().get_scale());
+ _generate_context_menu();
menu->popup();
grab_focus();
}
} else {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->get_command() && highlighted_word != String()) {
int row, col;
_get_mouse_pos(Point2i(mpos.x, mpos.y), row, col);
@@ -2453,7 +3120,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging.
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging.
_reset_caret_blink_timer();
if (draw_minimap && !dragging_selection) {
@@ -2486,13 +3153,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventKey> k = p_gui_input;
if (k.is_valid()) {
- k = k->duplicate(); // It will be modified later on.
-
+ // Ctrl + Hover symbols
#ifdef OSX_ENABLED
if (k->get_keycode() == KEY_META) {
#else
if (k->get_keycode() == KEY_CONTROL) {
-
#endif
if (select_identifiers_enabled) {
if (k->is_pressed() && !dragging_minimap && !dragging_selection) {
@@ -2502,1191 +3167,347 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
set_highlighted_word(String());
}
}
+ return;
}
if (!k->is_pressed()) {
return;
}
- if (completion_active) {
- if (readonly) {
- return;
- }
-
- bool valid = true;
- if (k->get_command() || k->get_metakey()) {
- valid = false;
- }
-
- if (valid) {
- if (!k->get_alt()) {
- if (k->get_keycode() == KEY_UP) {
- if (completion_index > 0) {
- completion_index--;
- } else {
- completion_index = completion_options.size() - 1;
- }
- completion_current = completion_options[completion_index];
- update();
-
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_DOWN) {
- if (completion_index < completion_options.size() - 1) {
- completion_index++;
- } else {
- completion_index = 0;
- }
- completion_current = completion_options[completion_index];
- update();
-
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_PAGEUP) {
- completion_index -= get_theme_constant("completion_lines");
- if (completion_index < 0) {
- completion_index = 0;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_PAGEDOWN) {
- completion_index += get_theme_constant("completion_lines");
- if (completion_index >= completion_options.size()) {
- completion_index = completion_options.size() - 1;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_HOME && completion_index > 0) {
- completion_index = 0;
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_END && completion_index < completion_options.size() - 1) {
- completion_index = completion_options.size() - 1;
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_KP_ENTER || k->get_keycode() == KEY_ENTER || k->get_keycode() == KEY_TAB) {
- _confirm_completion();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_BACKSPACE) {
- _reset_caret_blink_timer();
-
- backspace_at_cursor();
- _update_completion_candidates();
- accept_event();
- return;
- }
-
- if (k->get_keycode() == KEY_SHIFT) {
- accept_event();
- return;
- }
- }
-
- if (k->get_unicode() > 32) {
- _reset_caret_blink_timer();
-
- const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 };
- if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
- _consume_pair_symbol(chr[0]);
- } else {
- // Remove the old character if in insert mode.
- if (insert_mode) {
- begin_complex_operation();
-
- // Make sure we don't try and remove empty space.
- if (cursor.column < get_line(cursor.line).length()) {
- _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
- }
- }
-
- _insert_text_at_cursor(chr);
-
- if (insert_mode) {
- end_complex_operation();
- }
- }
- _update_completion_candidates();
- accept_event();
-
- return;
- }
- }
-
- _cancel_completion();
- }
-
- /* TEST CONTROL FIRST! */
-
- // Some remaps for duplicate functions.
- if (k->get_command() && !k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_keycode() == KEY_INSERT) {
- k->set_keycode(KEY_C);
- }
- if (!k->get_command() && k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_keycode() == KEY_INSERT) {
- k->set_keycode(KEY_V);
- k->set_command(true);
- k->set_shift(false);
- }
-#ifdef APPLE_STYLE_KEYS
- if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) {
- uint32_t remap_key = KEY_UNKNOWN;
- switch (k->get_keycode()) {
- case KEY_F: {
- remap_key = KEY_RIGHT;
- } break;
- case KEY_B: {
- remap_key = KEY_LEFT;
- } break;
- case KEY_P: {
- remap_key = KEY_UP;
- } break;
- case KEY_N: {
- remap_key = KEY_DOWN;
- } break;
- case KEY_D: {
- remap_key = KEY_DELETE;
- } break;
- case KEY_H: {
- remap_key = KEY_BACKSPACE;
- } break;
- }
-
- if (remap_key != KEY_UNKNOWN) {
- k->set_keycode(remap_key);
- k->set_control(false);
- }
+ // If a modifier has been pressed, and nothing else, return.
+ if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT || k->get_keycode() == KEY_META) {
+ return;
}
-#endif
_reset_caret_blink_timer();
+ // Allow unicode handling if:
+ // * No Modifiers are pressed (except shift)
+ bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey());
+
// Save here for insert mode, just in case it is cleared in the following section.
bool had_selection = selection.active;
- // Stuff to do when selection is active.
- if (!readonly && selection.active) {
- bool clear = false;
- bool unselect = false;
- bool dobreak = false;
-
- switch (k->get_keycode()) {
- case KEY_TAB: {
- if (k->get_shift()) {
- indent_left();
- } else {
- indent_right();
- }
- dobreak = true;
- accept_event();
- } break;
- case KEY_X:
- case KEY_C:
- // Special keys often used with control, wait.
- clear = (!k->get_command() || k->get_shift() || k->get_alt());
- break;
- case KEY_DELETE:
- if (!k->get_shift()) {
- accept_event();
- clear = true;
- dobreak = true;
- } else if (k->get_command() || k->get_alt()) {
- dobreak = true;
- }
- break;
- case KEY_BACKSPACE:
- accept_event();
- clear = true;
- dobreak = true;
- break;
- case KEY_LEFT:
- case KEY_RIGHT:
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGEUP:
- case KEY_PAGEDOWN:
- case KEY_HOME:
- case KEY_END:
- // Ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys).
- if (k->get_command() || k->get_shift() || k->get_alt()) {
- break;
- }
- unselect = true;
- break;
-
- default:
- if (k->get_unicode() >= 32 && !k->get_command() && !k->get_alt() && !k->get_metakey()) {
- clear = true;
- }
- if (auto_brace_completion_enabled && _is_pair_left_symbol(k->get_unicode())) {
- clear = false;
- }
- }
-
- if (unselect) {
- selection.active = false;
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- update();
- }
- if (clear) {
- if (!dobreak) {
- begin_complex_operation();
- }
- selection.active = false;
- update();
- _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line, true, false);
- cursor_set_column(selection.from_column);
- update();
- }
- if (dobreak) {
- return;
- }
- }
-
selection.selecting_text = false;
- bool keycode_handled = true;
-
- // Special keycode test.
-
- switch (k->get_keycode()) {
- case KEY_KP_ENTER:
- case KEY_ENTER: {
- if (readonly) {
- break;
- }
-
- String ins = "\n";
-
- // Keep indentation.
- int space_count = 0;
- for (int i = 0; i < cursor.column; i++) {
- if (text[cursor.line][i] == '\t') {
- if (indent_using_spaces) {
- ins += space_indent;
- } else {
- ins += "\t";
- }
- space_count = 0;
- } else if (text[cursor.line][i] == ' ') {
- space_count++;
-
- if (space_count == indent_size) {
- if (indent_using_spaces) {
- ins += space_indent;
- } else {
- ins += "\t";
- }
- space_count = 0;
- }
- } else {
- break;
- }
- }
-
- if (is_folded(cursor.line)) {
- unfold_line(cursor.line);
- }
-
- bool brace_indent = false;
-
- // No need to indent if we are going upwards.
- if (auto_indent && !(k->get_command() && k->get_shift())) {
- // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment
- // (i.e. colon/brace precedes current cursor position).
- if (cursor.column > 0) {
- bool indent_char_found = false;
- bool should_indent = false;
- char indent_char = ':';
- char c = text[cursor.line][cursor.column];
-
- for (int i = 0; i < cursor.column; i++) {
- c = text[cursor.line][i];
- switch (c) {
- case ':':
- case '{':
- case '[':
- case '(':
- indent_char_found = true;
- should_indent = true;
- indent_char = c;
- continue;
- }
-
- if (indent_char_found && is_line_comment(cursor.line)) {
- should_indent = true;
- break;
- } else if (indent_char_found && !_is_whitespace(c)) {
- should_indent = false;
- indent_char_found = false;
- }
- }
-
- if (!is_line_comment(cursor.line) && should_indent) {
- if (indent_using_spaces) {
- ins += space_indent;
- } else {
- ins += "\t";
- }
-
- // No need to move the brace below if we are not taking the text with us.
- char32_t closing_char = _get_right_pair_symbol(indent_char);
- if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column]) && !k->get_command()) {
- brace_indent = true;
- ins += "\n" + ins.substr(1, ins.length() - 2);
- }
- }
- }
- }
- begin_complex_operation();
- bool first_line = false;
- if (k->get_command()) {
- if (k->get_shift()) {
- if (cursor.line > 0) {
- cursor_set_line(cursor.line - 1);
- cursor_set_column(text[cursor.line].length());
- } else {
- cursor_set_column(0);
- first_line = true;
- }
- } else {
- cursor_set_column(text[cursor.line].length());
- }
- }
+ // Check and handle all built in shortcuts.
- insert_text_at_cursor(ins);
+ // AUTO-COMPLETE
- if (first_line) {
- cursor_set_line(0);
- } else if (brace_indent) {
- cursor_set_line(cursor.line - 1);
- cursor_set_column(text[cursor.line].length());
- }
- end_complex_operation();
- } break;
- case KEY_ESCAPE: {
- if (completion_hint != "") {
- completion_hint = "";
- update();
- } else {
- keycode_handled = false;
- }
- } break;
- case KEY_TAB: {
- if (k->get_command()) {
- break; // Avoid tab when command.
- }
-
- if (readonly) {
- break;
- }
-
- if (is_selection_active()) {
- if (k->get_shift()) {
- indent_left();
- } else {
- indent_right();
- }
- } else {
- if (k->get_shift()) {
- // Simple unindent.
- int cc = cursor.column;
- const String &line = text[cursor.line];
-
- int left = _find_first_non_whitespace_column_of_line(line);
- cc = MIN(cc, left);
-
- while (cc < indent_size && cc < left && line[cc] == ' ') {
- cc++;
- }
-
- if (cc > 0 && cc <= text[cursor.line].length()) {
- if (text[cursor.line][cc - 1] == '\t') {
- // Tabs unindentation.
- _remove_text(cursor.line, cc - 1, cursor.line, cc);
- if (cursor.column >= left) {
- cursor_set_column(MAX(0, cursor.column - 1));
- }
- update();
- } else {
- // Spaces unindentation.
- int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
- if (spaces_to_remove > 0) {
- _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc);
- if (cursor.column > left - spaces_to_remove) { // Inside text?
- cursor_set_column(MAX(0, cursor.column - spaces_to_remove));
- }
- update();
- }
- }
- } else if (cc == 0 && line.length() > 0 && line[0] == '\t') {
- _remove_text(cursor.line, 0, cursor.line, 1);
- update();
- }
- } else {
- // Simple indent.
- if (indent_using_spaces) {
- // Insert only as much spaces as needed till next indentation level.
- int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column);
- String indent_to_insert = String();
- for (int i = 0; i < spaces_to_add; i++) {
- indent_to_insert = ' ' + indent_to_insert;
- }
- _insert_text_at_cursor(indent_to_insert);
- } else {
- _insert_text_at_cursor("\t");
- }
- }
- }
-
- } break;
- case KEY_BACKSPACE: {
- if (readonly) {
- break;
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt() && cursor.column > 1) {
-#else
- if (k->get_alt()) {
- keycode_handled = false;
- break;
- } else if (k->get_command() && cursor.column > 1) {
-#endif
- int line = cursor.line;
- int column = cursor.column;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < column) {
- column = words[i].x;
- break;
- }
- }
-
- _remove_text(line, column, cursor.line, cursor.column);
-
- cursor_set_line(line);
- cursor_set_column(column);
-
-#ifdef APPLE_STYLE_KEYS
- } else if (k->get_command()) {
- int cursor_current_column = cursor.column;
- cursor.column = 0;
- _remove_text(cursor.line, 0, cursor.line, cursor_current_column);
-#endif
- } else {
- if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) {
- unfold_line(cursor.line - 1);
- }
- backspace_at_cursor();
- }
-
- } break;
- case KEY_KP_4: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_LEFT: {
- if (k->get_shift()) {
- _pre_shift_selection();
-#ifdef APPLE_STYLE_KEYS
- } else {
-#else
- } else if (!k->get_alt()) {
-#endif
- deselect();
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- // Start at first column (it's slightly faster that way) and look for the first non-whitespace character.
- int new_cursor_pos = 0;
- for (int i = 0; i < text[cursor.line].length(); ++i) {
- if (!_is_whitespace(text[cursor.line][i])) {
- new_cursor_pos = i;
- break;
- }
- }
- if (new_cursor_pos == cursor.column) {
- // We're already at the first text character, so move to the very beginning of the line.
- cursor_set_column(0);
- } else {
- // We're somewhere to the right of the first text character; move to the first one.
- cursor_set_column(new_cursor_pos);
- }
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- keycode_handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor.column;
-
- if (cc == 0 && cursor.line > 0) {
- cursor_set_line(cursor.line - 1);
- cursor_set_column(text[cursor.line].length());
- } else {
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid());
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < cc) {
- cc = words[i].x;
- break;
- }
- }
- cursor_set_column(cc);
- }
+ if (k->is_action("ui_text_completion_query", true)) {
+ query_code_comple();
+ accept_event();
+ return;
+ }
- } else if (cursor.column == 0) {
- if (cursor.line > 0) {
- cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1));
- cursor_set_column(text[cursor.line].length());
- }
+ if (completion_active) {
+ if (k->is_action("ui_up", true)) {
+ if (completion_index > 0) {
+ completion_index--;
} else {
- if (mid_grapheme_caret_enabled) {
- cursor_set_column(cursor_get_column() - 1);
- } else {
- cursor_set_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column()));
- }
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
+ completion_index = completion_options.size() - 1;
}
-
- } break;
- case KEY_KP_6: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
- }
- [[fallthrough]];
+ completion_current = completion_options[completion_index];
+ update();
+ accept_event();
+ return;
}
- case KEY_RIGHT: {
- if (k->get_shift()) {
- _pre_shift_selection();
-#ifdef APPLE_STYLE_KEYS
- } else {
-#else
- } else if (!k->get_alt()) {
-#endif
- deselect();
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- cursor_set_column(text[cursor.line].length());
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- keycode_handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor.column;
-
- if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) {
- cursor_set_line(cursor.line + 1);
- cursor_set_column(0);
- } else {
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid());
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > cc) {
- cc = words[i].y;
- break;
- }
- }
- cursor_set_column(cc);
- }
-
- } else if (cursor.column == text[cursor.line].length()) {
- if (cursor.line < text.size() - 1) {
- cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
- cursor_set_column(0);
- }
+ if (k->is_action("ui_down", true)) {
+ if (completion_index < completion_options.size() - 1) {
+ completion_index++;
} else {
- if (mid_grapheme_caret_enabled) {
- cursor_set_column(cursor_get_column() + 1);
- } else {
- cursor_set_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column()));
- }
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
- }
-
- } break;
- case KEY_KP_8: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
+ completion_index = 0;
}
- [[fallthrough]];
+ completion_current = completion_options[completion_index];
+ update();
+ accept_event();
+ return;
}
- case KEY_UP: {
- if (k->get_alt()) {
- keycode_handled = false;
- break;
+ if (k->is_action("ui_page_up", true)) {
+ completion_index -= get_theme_constant("completion_lines");
+ if (completion_index < 0) {
+ completion_index = 0;
}
-#ifndef APPLE_STYLE_KEYS
- if (k->get_command()) {
-#else
- if (k->get_command() && k->get_alt()) {
-#endif
- _scroll_lines_up();
- break;
- }
-
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- cursor_set_line(0);
- } else
-#endif
- {
- int cur_wrap_index = get_cursor_wrap_index();
- if (cur_wrap_index > 0) {
- cursor_set_line(cursor.line, true, false, cur_wrap_index - 1);
- } else if (cursor.line == 0) {
- cursor_set_column(0);
- } else {
- int new_line = cursor.line - num_lines_from(cursor.line - 1, -1);
- if (line_wraps(new_line)) {
- cursor_set_line(new_line, true, false, times_line_wraps(new_line));
- } else {
- cursor_set_line(new_line, true, false);
- }
- }
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
- }
- _cancel_code_hint();
-
- } break;
- case KEY_KP_2: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
- }
- [[fallthrough]];
+ completion_current = completion_options[completion_index];
+ update();
+ accept_event();
+ return;
}
- case KEY_DOWN: {
- if (k->get_alt()) {
- keycode_handled = false;
- break;
- }
-#ifndef APPLE_STYLE_KEYS
- if (k->get_command()) {
-#else
- if (k->get_command() && k->get_alt()) {
-#endif
- _scroll_lines_down();
- break;
- }
-
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- cursor_set_line(get_last_unhidden_line(), true, false, 9999);
- } else
-#endif
- {
- int cur_wrap_index = get_cursor_wrap_index();
- if (cur_wrap_index < times_line_wraps(cursor.line)) {
- cursor_set_line(cursor.line, true, false, cur_wrap_index + 1);
- } else if (cursor.line == get_last_unhidden_line()) {
- cursor_set_column(text[cursor.line].length());
- } else {
- int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1);
- cursor_set_line(new_line, true, false, 0);
- }
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
- }
- _cancel_code_hint();
-
- } break;
- case KEY_DELETE: {
- if (readonly) {
- break;
- }
-
- if (k->get_shift() && !k->get_command() && !k->get_alt() && is_shortcut_keys_enabled()) {
- cut();
- break;
- }
-
- int curline_len = text[cursor.line].length();
-
- if (cursor.line == text.size() - 1 && cursor.column == curline_len) {
- break; // Nothing to do.
+ if (k->is_action("ui_page_down", true)) {
+ completion_index += get_theme_constant("completion_lines");
+ if (completion_index >= completion_options.size()) {
+ completion_index = completion_options.size() - 1;
}
-
- int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1;
- int next_column;
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt() && cursor.column < curline_len - 1) {
-#else
- if (k->get_alt()) {
- keycode_handled = false;
- break;
- } else if (k->get_command() && cursor.column < curline_len - 1) {
-#endif
-
- int line = cursor.line;
- int column = cursor.column;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > column) {
- column = words[i].y;
- break;
- }
- }
-
- next_line = line;
- next_column = column;
-#ifdef APPLE_STYLE_KEYS
- } else if (k->get_command()) {
- next_column = curline_len;
- next_line = cursor.line;
-#endif
- } else {
- if (mid_grapheme_caret_enabled) {
- next_column = cursor.column < curline_len ? (cursor.column + 1) : 0;
- } else {
- next_column = cursor.column < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), (cursor.column)) : 0;
- }
- }
-
- _remove_text(cursor.line, cursor.column, next_line, next_column);
+ completion_current = completion_options[completion_index];
update();
-
- } break;
- case KEY_KP_7: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
- }
- [[fallthrough]];
+ accept_event();
+ return;
}
- case KEY_HOME: {
-#ifdef APPLE_STYLE_KEYS
- if (k->get_shift())
- _pre_shift_selection();
-
- cursor_set_line(0);
-
- if (k->get_shift())
- _post_shift_selection();
- else if (k->get_command() || k->get_control())
- deselect();
-#else
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
- if (k->get_command()) {
- cursor_set_line(0);
- cursor_set_column(0);
- } else {
- // Move cursor column to start of wrapped row and then to start of text.
- Vector<String> rows = get_wrap_rows_text(cursor.line);
- int wi = get_cursor_wrap_index();
- int row_start_col = 0;
- for (int i = 0; i < wi; i++) {
- row_start_col += rows[i].length();
- }
- if (cursor.column == row_start_col || wi == 0) {
- // Compute whitespace symbols seq length.
- int current_line_whitespace_len = 0;
- while (current_line_whitespace_len < text[cursor.line].length()) {
- char32_t c = text[cursor.line][current_line_whitespace_len];
- if (c != '\t' && c != ' ') {
- break;
- }
- current_line_whitespace_len++;
- }
-
- if (cursor_get_column() == current_line_whitespace_len) {
- cursor_set_column(0);
- } else {
- cursor_set_column(current_line_whitespace_len);
- }
- } else {
- cursor_set_column(row_start_col);
- }
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
- } else if (k->get_command() || k->get_control()) {
- deselect();
- }
- _cancel_completion();
- completion_hint = "";
-#endif
- } break;
- case KEY_KP_1: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
+ if (k->is_action("ui_home", true)) {
+ if (completion_index > 0) {
+ completion_index = 0;
+ completion_current = completion_options[completion_index];
+ update();
}
- [[fallthrough]];
+ accept_event();
+ return;
}
- case KEY_END: {
-#ifdef APPLE_STYLE_KEYS
- if (k->get_shift())
- _pre_shift_selection();
-
- cursor_set_line(get_last_unhidden_line(), true, false, 9999);
-
- if (k->get_shift())
- _post_shift_selection();
- else if (k->get_command() || k->get_control())
- deselect();
-#else
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
- if (k->get_command()) {
- cursor_set_line(get_last_unhidden_line(), true, false, 9999);
- }
-
- // Move cursor column to end of wrapped row and then to end of text.
- Vector<String> rows = get_wrap_rows_text(cursor.line);
- int wi = get_cursor_wrap_index();
- int row_end_col = -1;
- for (int i = 0; i < wi + 1; i++) {
- row_end_col += rows[i].length();
- }
- if (wi == rows.size() - 1 || cursor.column == row_end_col) {
- cursor_set_column(text[cursor.line].length());
- } else {
- cursor_set_column(row_end_col);
- }
-
- if (k->get_shift()) {
- _post_shift_selection();
- } else if (k->get_command() || k->get_control()) {
- deselect();
- }
-
- _cancel_completion();
- completion_hint = "";
-#endif
- } break;
- case KEY_KP_9: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
+ if (k->is_action("ui_end", true)) {
+ if (completion_index < completion_options.size() - 1) {
+ completion_index = completion_options.size() - 1;
+ completion_current = completion_options[completion_index];
+ update();
}
- [[fallthrough]];
+ accept_event();
+ return;
}
- case KEY_PAGEUP: {
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
- int wi;
- int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1;
- cursor_set_line(n_line, true, false, wi);
-
- if (k->get_shift()) {
- _post_shift_selection();
- }
-
+ if (k->is_action("ui_text_completion_accept", true)) {
+ _confirm_completion();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_cancel", true)) {
_cancel_completion();
- completion_hint = "";
+ accept_event();
+ return;
+ }
- } break;
- case KEY_KP_3: {
- if (k->get_unicode() != 0) {
- keycode_handled = false;
- break;
+ // Handle Unicode here (if no modifiers active) and update autocomplete.
+ if (k->get_unicode() >= 32) {
+ if (allow_unicode_handling && !readonly) {
+ _handle_unicode_character(k->get_unicode(), had_selection, true);
+ accept_event();
+ return;
}
- [[fallthrough]];
}
- case KEY_PAGEDOWN: {
- if (k->get_shift()) {
- _pre_shift_selection();
- }
-
- int wi;
- int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1;
- cursor_set_line(n_line, true, false, wi);
+ }
- if (k->get_shift()) {
- _post_shift_selection();
- }
+ // NEWLINES.
+ if (k->is_action("ui_text_newline_above", true)) {
+ _new_line(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_newline_blank", true)) {
+ _new_line(false);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_newline", true)) {
+ _new_line();
+ accept_event();
+ return;
+ }
- _cancel_completion();
- completion_hint = "";
+ // INDENTATION.
+ if (k->is_action("ui_text_dedent", true)) {
+ _indent_left();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_indent", true)) {
+ _indent_right();
+ accept_event();
+ return;
+ }
- } break;
- case KEY_A: {
-#ifndef APPLE_STYLE_KEYS
- if (!k->get_control() || k->get_shift() || k->get_alt()) {
- keycode_handled = false;
- break;
- }
- if (is_shortcut_keys_enabled()) {
- select_all();
- }
-#else
- if ((!k->get_command() && !k->get_control())) {
- keycode_handled = false;
- break;
- }
- if (!k->get_shift() && k->get_command() && is_shortcut_keys_enabled())
- select_all();
- else if (k->get_control()) {
- if (k->get_shift())
- _pre_shift_selection();
-
- int current_line_whitespace_len = 0;
- while (current_line_whitespace_len < text[cursor.line].length()) {
- char32_t c = text[cursor.line][current_line_whitespace_len];
- if (c != '\t' && c != ' ')
- break;
- current_line_whitespace_len++;
- }
+ // BACKSPACE AND DELETE.
+ if (k->is_action("ui_text_backspace_all_to_left", true)) {
+ _backspace(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace_word", true)) {
+ _backspace(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace", true)) {
+ _backspace();
+ if (completion_active) {
+ _update_completion_candidates();
+ }
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete_all_to_right", true)) {
+ _delete(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete_word", true)) {
+ _delete(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete", true)) {
+ _delete();
+ accept_event();
+ return;
+ }
- if (cursor_get_column() == current_line_whitespace_len)
- cursor_set_column(0);
- else
- cursor_set_column(current_line_whitespace_len);
+ // SCROLLING.
+ if (k->is_action("ui_text_scroll_up", true)) {
+ _scroll_lines_up();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_scroll_down", true)) {
+ _scroll_lines_down();
+ accept_event();
+ return;
+ }
- if (k->get_shift())
- _post_shift_selection();
- else if (k->get_command() || k->get_control())
- deselect();
- }
- } break;
- case KEY_E: {
- if (!k->get_control() || k->get_command() || k->get_alt()) {
- keycode_handled = false;
- break;
- }
+ // SELECT ALL, CUT, COPY, PASTE.
- if (k->get_shift())
- _pre_shift_selection();
+ if (k->is_action("ui_text_select_all", true)) {
+ select_all();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_cut", true)) {
+ cut();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_copy", true)) {
+ copy();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_paste", true)) {
+ paste();
+ accept_event();
+ return;
+ }
- if (k->get_command())
- cursor_set_line(text.size() - 1, true, false);
- cursor_set_column(text[cursor.line].length());
+ // UNDO/REDO.
+ if (k->is_action("ui_undo", true)) {
+ undo();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_redo", true)) {
+ redo();
+ accept_event();
+ return;
+ }
- if (k->get_shift())
- _post_shift_selection();
- else if (k->get_command() || k->get_control())
- deselect();
+ // MISC.
- _cancel_completion();
+ if (k->is_action("ui_menu", true)) {
+ if (context_menu_enabled) {
+ menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos()));
+ menu->set_size(Vector2(1, 1));
+ _generate_context_menu();
+ menu->popup();
+ menu->grab_focus();
+ }
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_toggle_insert_mode", true)) {
+ set_insert_mode(!insert_mode);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_cancel", true)) {
+ if (completion_hint != "") {
completion_hint = "";
-#endif
- } break;
- case (KEY_QUOTELEFT): { // Swap current input direction (primary cursor)
- if (!k->get_command()) {
- keycode_handled = false;
- break;
- }
-
- if (input_direction == TEXT_DIRECTION_LTR) {
- input_direction = TEXT_DIRECTION_RTL;
- } else {
- input_direction = TEXT_DIRECTION_LTR;
- }
- cursor_set_column(cursor.column);
update();
- } break;
- case KEY_X: {
- if (readonly) {
- break;
- }
- if (!k->get_command() || k->get_shift() || k->get_alt()) {
- keycode_handled = false;
- break;
- }
- if (is_shortcut_keys_enabled()) {
- cut();
- }
-
- } break;
- case KEY_C: {
- if (!k->get_command() || k->get_shift() || k->get_alt()) {
- keycode_handled = false;
- break;
- }
-
- if (is_shortcut_keys_enabled()) {
- copy();
- }
-
- } break;
- case KEY_Z: {
- if (readonly) {
- break;
- }
-
- if (!k->get_command()) {
- keycode_handled = false;
- break;
- }
-
- if (is_shortcut_keys_enabled()) {
- if (k->get_shift()) {
- redo();
- } else {
- undo();
- }
- }
- } break;
- case KEY_Y: {
- if (readonly) {
- break;
- }
-
- if (!k->get_command()) {
- keycode_handled = false;
- break;
- }
-
- if (is_shortcut_keys_enabled()) {
- redo();
- }
- } break;
- case KEY_V: {
- if (readonly) {
- break;
- }
- if (!k->get_command() || k->get_shift() || k->get_alt()) {
- keycode_handled = false;
- break;
- }
-
- if (is_shortcut_keys_enabled()) {
- paste();
- }
-
- } break;
- case KEY_SPACE: {
-#ifdef OSX_ENABLED
- if (completion_enabled && k->get_metakey()) { // cmd-space is spotlight shortcut in OSX
-#else
- if (completion_enabled && k->get_command()) {
-#endif
-
- query_code_comple();
- keycode_handled = true;
- } else {
- keycode_handled = false;
- }
+ }
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_swap_input_direction", true)) {
+ _swap_current_input_direction();
+ accept_event();
+ return;
+ }
- } break;
+ // CURSOR MOVEMENT
- case KEY_MENU: {
- if (context_menu_enabled) {
- menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos()));
- menu->set_size(Vector2(1, 1));
- menu->popup();
- menu->grab_focus();
- }
- } break;
+ k = k->duplicate();
+ bool shift_pressed = k->get_shift();
+ // Remove shift or else actions will not match. Use above variable for selection.
+ k->set_shift(false);
- default: {
- keycode_handled = false;
- } break;
+ // CURSOR MOVEMENT - LEFT, RIGHT.
+ if (k->is_action("ui_text_caret_word_left", true)) {
+ _move_cursor_left(shift_pressed, true);
+ accept_event();
+ return;
}
-
- if (keycode_handled) {
+ if (k->is_action("ui_text_caret_left", true)) {
+ _move_cursor_left(shift_pressed, false);
accept_event();
+ return;
}
-
- if (k->get_keycode() == KEY_INSERT) {
- set_insert_mode(!insert_mode);
+ if (k->is_action("ui_text_caret_word_right", true)) {
+ _move_cursor_right(shift_pressed, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_right", true)) {
+ _move_cursor_right(shift_pressed, false);
accept_event();
return;
}
- if (!keycode_handled && !k->get_command()) { // For German keyboards.
-
- if (k->get_unicode() >= 32) {
- if (readonly) {
- return;
- }
-
- // Remove the old character if in insert mode and no selection.
- if (insert_mode && !had_selection) {
- begin_complex_operation();
-
- // Make sure we don't try and remove empty space.
- if (cursor.column < get_line(cursor.line).length()) {
- _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
- }
- }
-
- const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 };
+ // CURSOR MOVEMENT - UP, DOWN.
+ if (k->is_action("ui_text_caret_up", true)) {
+ _move_cursor_up(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_down", true)) {
+ _move_cursor_down(shift_pressed);
+ accept_event();
+ return;
+ }
- if (completion_hint != "" && k->get_unicode() == ')') {
- completion_hint = "";
- }
- if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
- _consume_pair_symbol(chr[0]);
- } else {
- _insert_text_at_cursor(chr);
- }
+ // CURSOR MOVEMENT - DOCUMENT START/END.
+ if (k->is_action("ui_text_caret_document_start", true)) { // && shift_pressed) {
+ _move_cursor_document_start(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_document_end", true)) { // && shift_pressed) {
+ _move_cursor_document_end(shift_pressed);
+ accept_event();
+ return;
+ }
- if (insert_mode && !had_selection) {
- end_complex_operation();
- }
+ // CURSOR MOVEMENT - LINE START/END.
+ if (k->is_action("ui_text_caret_line_start", true)) {
+ _move_cursor_to_line_start(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_line_end", true)) {
+ _move_cursor_to_line_end(shift_pressed);
+ accept_event();
+ return;
+ }
- if (selection.active != had_selection) {
- end_complex_operation();
- }
- accept_event();
- }
+ // CURSOR MOVEMENT - PAGE UP/DOWN.
+ if (k->is_action("ui_text_caret_page_up", true)) {
+ _move_cursor_page_up(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_page_down", true)) {
+ _move_cursor_page_down(shift_pressed);
+ accept_event();
+ return;
}
- return;
+ if (allow_unicode_handling && !readonly && k->get_unicode() >= 32) {
+ // Handle Unicode (if no modifiers active).
+ _handle_unicode_character(k->get_unicode(), had_selection, false);
+ accept_event();
+ return;
+ }
}
}
@@ -3775,8 +3596,8 @@ void TextEdit::_scroll_lines_up() {
if (!selection.active) {
int cur_line = cursor.line;
int cur_wrap = get_cursor_wrap_index();
- int last_vis_line = get_last_visible_line();
- int last_vis_wrap = get_last_visible_line_wrap_index();
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
cursor_set_line(last_vis_line, false, false, last_vis_wrap);
@@ -4030,7 +3851,7 @@ void TextEdit::_insert_text_at_cursor(const String &p_text) {
int new_column, new_line;
_insert_text(cursor.line, cursor.column, p_text, &new_line, &new_column);
_update_scrollbars();
- cursor_set_line(new_line);
+ cursor_set_line(new_line, false);
cursor_set_column(new_column);
update();
@@ -4062,25 +3883,50 @@ int TextEdit::_get_control_height() const {
return control_height;
}
+int TextEdit::_get_menu_action_accelerator(const String &p_action) {
+ const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action);
+ if (!events) {
+ return 0;
+ }
+
+ // Use first event in the list for the accelerator.
+ const List<Ref<InputEvent>>::Element *first_event = events->front();
+ if (!first_event) {
+ return 0;
+ }
+
+ const Ref<InputEventKey> event = first_event->get();
+ if (event.is_null()) {
+ return 0;
+ }
+
+ // Use physical keycode if non-zero
+ if (event->get_physical_keycode() != 0) {
+ return event->get_physical_keycode_with_modifiers();
+ } else {
+ return event->get_keycode_with_modifiers();
+ }
+}
+
void TextEdit::_generate_context_menu() {
// Reorganize context menu.
menu->clear();
if (!readonly) {
- menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0);
+ menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0);
}
- menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0);
+ menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : 0);
if (!readonly) {
- menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0);
+ menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : 0);
}
menu->add_separator();
if (is_selecting_enabled()) {
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : 0);
}
if (!readonly) {
menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0);
- menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0);
+ menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_undo") : 0);
+ menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_redo") : 0);
}
menu->add_separator();
menu->add_submenu_item(RTR("Text writing direction"), "DirMenu");
@@ -4149,8 +3995,8 @@ void TextEdit::adjust_viewport_to_cursor() {
int first_vis_line = get_first_visible_line();
int first_vis_wrap = cursor.wrap_ofs;
- int last_vis_line = get_last_visible_line();
- int last_vis_wrap = get_last_visible_line_wrap_index();
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
// Cursor is above screen.
@@ -4579,7 +4425,7 @@ int TextEdit::get_column_x_offset_for_line(int p_char, int p_line) const {
void TextEdit::insert_text_at_cursor(const String &p_text) {
if (selection.active) {
- cursor_set_line(selection.from_line);
+ cursor_set_line(selection.from_line, false);
cursor_set_column(selection.from_column);
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
@@ -4919,6 +4765,8 @@ void TextEdit::_update_caches() {
cache.completion_font_color = get_theme_color("completion_font_color");
cache.font = get_theme_font("font");
cache.font_size = get_theme_font_size("font_size");
+ cache.outline_color = get_theme_color("font_outline_color");
+ cache.outline_size = get_theme_constant("outline_size");
cache.caret_color = get_theme_color("caret_color");
cache.caret_background_color = get_theme_color("caret_background_color");
cache.font_color = get_theme_color("font_color");
@@ -5168,6 +5016,10 @@ void TextEdit::set_auto_indent(bool p_auto_indent) {
}
void TextEdit::cut() {
+ if (readonly) {
+ return;
+ }
+
if (!selection.active) {
String clipboard = text[cursor.line];
DisplayServer::get_singleton()->clipboard_set(clipboard);
@@ -5190,7 +5042,7 @@ void TextEdit::cut() {
DisplayServer::get_singleton()->clipboard_set(clipboard);
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line); // Set afterwards else it causes the view to be offset.
+ cursor_set_line(selection.from_line, false); // Set afterwards else it causes the view to be offset.
cursor_set_column(selection.from_column);
selection.active = false;
@@ -5215,6 +5067,10 @@ void TextEdit::copy() {
}
void TextEdit::paste() {
+ if (readonly) {
+ return;
+ }
+
String clipboard = DisplayServer::get_singleton()->clipboard_get();
begin_complex_operation();
@@ -5222,7 +5078,7 @@ void TextEdit::paste() {
selection.active = false;
selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line);
+ cursor_set_line(selection.from_line, false);
cursor_set_column(selection.from_column);
} else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) {
@@ -5918,6 +5774,10 @@ void TextEdit::_clear_redo() {
}
void TextEdit::undo() {
+ if (readonly) {
+ return;
+ }
+
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -5957,17 +5817,20 @@ void TextEdit::undo() {
_update_scrollbars();
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
- cursor_set_line(undo_stack_pos->get().to_line);
+ cursor_set_line(undo_stack_pos->get().to_line, false);
cursor_set_column(undo_stack_pos->get().to_column);
_cancel_code_hint();
} else {
- cursor_set_line(undo_stack_pos->get().from_line);
+ cursor_set_line(undo_stack_pos->get().from_line, false);
cursor_set_column(undo_stack_pos->get().from_column);
}
update();
}
void TextEdit::redo() {
+ if (readonly) {
+ return;
+ }
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -5993,7 +5856,7 @@ void TextEdit::redo() {
}
_update_scrollbars();
- cursor_set_line(undo_stack_pos->get().to_line);
+ cursor_set_line(undo_stack_pos->get().to_line, false);
cursor_set_column(undo_stack_pos->get().to_column);
undo_stack_pos = undo_stack_pos->next();
update();
@@ -6128,7 +5991,7 @@ double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
}
// Count the number of visible lines up to this line.
- double new_line_scroll_pos = 0;
+ double new_line_scroll_pos = 0.0;
int to = CLAMP(p_line, 0, text.size() - 1);
for (int i = 0; i < to; i++) {
if (!text.is_hidden(i)) {
@@ -6163,19 +6026,19 @@ int TextEdit::get_first_visible_line() const {
return CLAMP(cursor.line_ofs, 0, text.size() - 1);
}
-int TextEdit::get_last_visible_line() const {
+int TextEdit::get_last_full_visible_line() const {
int first_vis_line = get_first_visible_line();
int last_vis_line = 0;
int wi;
- last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1;
+ last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi) - 1;
last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
return last_vis_line;
}
-int TextEdit::get_last_visible_line_wrap_index() const {
+int TextEdit::get_last_full_visible_line_wrap_index() const {
int first_vis_line = get_first_visible_line();
int wi;
- num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi);
+ num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi);
return wi;
}
@@ -6906,7 +6769,7 @@ bool TextEdit::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -7205,23 +7068,11 @@ void TextEdit::_bind_methods() {
}
TextEdit::TextEdit() {
- setting_row = false;
- draw_tabs = false;
- draw_spaces = false;
- override_selected_font_color = false;
- draw_caret = true;
- max_chars = 0;
clear();
- wrap_enabled = false;
- wrap_at = 0;
- wrap_right_offset = 10;
set_focus_mode(FOCUS_ALL);
_update_caches();
- cache.line_spacing = 1;
- cache.font_size = 16;
set_default_cursor_shape(CURSOR_IBEAM);
- indent_size = 4;
text.set_indent_size(indent_size);
text.clear();
@@ -7231,31 +7082,16 @@ TextEdit::TextEdit() {
add_child(h_scroll);
add_child(v_scroll);
- updating_scrolls = false;
- selection.active = false;
-
h_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved));
v_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved));
v_scroll->connect("scrolling", callable_mp(this, &TextEdit::_v_scroll_input));
- cursor_changed_dirty = false;
- text_changed_dirty = false;
-
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- selection.selecting_line = 0;
- selection.selecting_column = 0;
- selection.selecting_text = false;
- selection.active = false;
-
- block_caret = false;
- caret_blink_enabled = false;
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &TextEdit::_toggle_draw_caret));
cursor_set_blink_enabled(false);
- right_click_moves_caret = true;
idle_detect = memnew(Timer);
add_child(idle_detect);
@@ -7268,54 +7104,8 @@ TextEdit::TextEdit() {
click_select_held->set_wait_time(0.05);
click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held));
- current_op.type = TextOperation::TYPE_NONE;
- undo_enabled = true;
undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size");
- undo_stack_pos = nullptr;
- setting_text = false;
- last_dblclk = 0;
- current_op.version = 0;
- version = 0;
- saved_version = 0;
- completion_enabled = false;
- completion_active = false;
- completion_line_ofs = 0;
- tooltip_obj = nullptr;
- line_length_guidelines = false;
- line_length_guideline_soft_col = 80;
- line_length_guideline_hard_col = 100;
- hiding_enabled = false;
- next_operation_is_complex = false;
- scroll_past_end_of_file_enabled = false;
- auto_brace_completion_enabled = false;
- brace_matching_enabled = false;
- highlight_all_occurrences = false;
- highlight_current_line = false;
- indent_using_spaces = false;
- space_indent = " ";
- auto_indent = false;
- insert_mode = false;
- window_has_focus = true;
- select_identifiers_enabled = false;
- smooth_scroll_enabled = false;
- scrolling = false;
- minimap_clicked = false;
- dragging_minimap = false;
- can_drag_minimap = false;
- minimap_scroll_ratio = 0;
- minimap_scroll_click_pos = 0;
- dragging_selection = false;
- target_v_scroll = 0;
- v_scroll_speed = 80;
- draw_minimap = false;
- minimap_width = 80;
- minimap_char_size = Point2(1, 2);
- minimap_line_spacing = 1;
-
- selecting_enabled = true;
- context_menu_enabled = true;
- shortcut_keys_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
@@ -7350,12 +7140,10 @@ TextEdit::TextEdit() {
menu_ctl->add_item(RTR("Soft hyphen (SHY)"), MENU_INSERT_SHY);
menu->add_child(menu_ctl);
- readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly.
set_readonly(false);
menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
menu_ctl->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
- first_draw = true;
}
TextEdit::~TextEdit() {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index dc811059c8..b0c7314c65 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -92,14 +92,11 @@ private:
Vector<Vector2i> bidi_override;
Ref<TextParagraph> data_buf;
- bool marked;
- bool hidden;
+ bool marked = false;
+ bool hidden = false;
Line() {
data_buf.instance();
-
- marked = false;
- hidden = false;
}
};
@@ -173,46 +170,31 @@ private:
};
struct Cursor {
- int last_fit_x;
- int line, column; ///< cursor
- int x_ofs, line_ofs, wrap_ofs;
- Cursor() {
- last_fit_x = 0;
- line = 0;
- column = 0; ///< cursor
- x_ofs = 0;
- line_ofs = 0;
- wrap_ofs = 0;
- }
+ int last_fit_x = 0;
+ int line = 0;
+ int column = 0; ///< cursor
+ int x_ofs = 0;
+ int line_ofs = 0;
+ int wrap_ofs = 0;
} cursor;
struct Selection {
- SelectionMode selecting_mode;
- int selecting_line, selecting_column;
- int selected_word_beg, selected_word_end, selected_word_origin;
- bool selecting_text;
-
- bool active;
-
- int from_line, from_column;
- int to_line, to_column;
-
- bool shiftclick_left;
- Selection() {
- selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- selecting_line = 0;
- selecting_column = 0;
- selected_word_beg = 0;
- selected_word_end = 0;
- selected_word_origin = 0;
- selecting_text = false;
- active = false;
- from_line = 0;
- from_column = 0;
- to_line = 0;
- to_column = 0;
- shiftclick_left = false;
- }
+ SelectionMode selecting_mode = SelectionMode::SELECTION_MODE_NONE;
+ int selecting_line = 0;
+ int selecting_column = 0;
+ int selected_word_beg = 0;
+ int selected_word_end = 0;
+ int selected_word_origin = 0;
+ bool selecting_text = false;
+
+ bool active = false;
+
+ int from_line = 0;
+ int from_column = 0;
+ int to_line = 0;
+ int to_column = 0;
+
+ bool shiftclick_left = false;
} selection;
Map<int, Dictionary> syntax_highlighting_cache;
@@ -224,25 +206,16 @@ private:
TYPE_REMOVE
};
- Type type;
- int from_line, from_column;
- int to_line, to_column;
+ Type type = TYPE_NONE;
+ int from_line = 0;
+ int from_column = 0;
+ int to_line = 0;
+ int to_column = 0;
String text;
- uint32_t prev_version;
- uint32_t version;
- bool chain_forward;
- bool chain_backward;
- TextOperation() {
- type = TYPE_NONE;
- from_line = 0;
- from_column = 0;
- to_line = 0;
- to_column = 0;
- prev_version = 0;
- version = 0;
- chain_forward = false;
- chain_backward = false;
- }
+ uint32_t prev_version = 0;
+ uint32_t version = 0;
+ bool chain_forward = false;
+ bool chain_backward = false;
};
String ime_text;
@@ -251,7 +224,7 @@ private:
TextOperation current_op;
List<TextOperation> undo_stack;
- List<TextOperation>::Element *undo_stack_pos;
+ List<TextOperation>::Element *undo_stack_pos = nullptr;
int undo_stack_max_size;
void _clear_redo();
@@ -264,20 +237,20 @@ private:
Dictionary _get_line_syntax_highlighting(int p_line);
Set<String> completion_prefixes;
- bool completion_enabled;
+ bool completion_enabled = false;
List<ScriptCodeCompletionOption> completion_sources;
Vector<ScriptCodeCompletionOption> completion_options;
- bool completion_active;
- bool completion_forced;
+ bool completion_active = false;
+ bool completion_forced = false;
ScriptCodeCompletionOption completion_current;
String completion_base;
- int completion_index;
+ int completion_index = 0;
Rect2i completion_rect;
- int completion_line_ofs;
+ int completion_line_ofs = 0;
String completion_hint;
- int completion_hint_offset;
+ int completion_hint_offset = 0;
- bool setting_text;
+ bool setting_text = false;
// data
Text text;
@@ -290,93 +263,93 @@ private:
Array st_args;
bool draw_control_chars = false;
- uint32_t version;
- uint32_t saved_version;
+ uint32_t version = 0;
+ uint32_t saved_version = 0;
- int max_chars;
- bool readonly;
- bool indent_using_spaces;
- int indent_size;
- String space_indent;
+ int max_chars = 0;
+ bool readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly.
+ bool indent_using_spaces = false;
+ int indent_size = 4;
+ String space_indent = " ";
Timer *caret_blink_timer;
- bool caret_blink_enabled;
- bool draw_caret;
- bool window_has_focus;
- bool block_caret;
- bool right_click_moves_caret;
+ bool caret_blink_enabled = false;
+ bool draw_caret = true;
+ bool window_has_focus = true;
+ bool block_caret = false;
+ bool right_click_moves_caret = true;
bool mid_grapheme_caret_enabled = false;
- bool wrap_enabled;
- int wrap_at;
- int wrap_right_offset;
-
- bool first_draw;
- bool setting_row;
- bool draw_tabs;
- bool draw_spaces;
- bool override_selected_font_color;
- bool cursor_changed_dirty;
- bool text_changed_dirty;
- bool undo_enabled;
- bool line_length_guidelines;
- int line_length_guideline_soft_col;
- int line_length_guideline_hard_col;
- bool hiding_enabled;
- bool draw_minimap;
- int minimap_width;
- Point2 minimap_char_size;
- int minimap_line_spacing;
-
- bool highlight_all_occurrences;
- bool scroll_past_end_of_file_enabled;
- bool auto_brace_completion_enabled;
- bool brace_matching_enabled;
- bool highlight_current_line;
- bool auto_indent;
+ bool wrap_enabled = false;
+ int wrap_at = 0;
+ int wrap_right_offset = 10;
+
+ bool first_draw = true;
+ bool setting_row = false;
+ bool draw_tabs = false;
+ bool draw_spaces = false;
+ bool override_selected_font_color = false;
+ bool cursor_changed_dirty = false;
+ bool text_changed_dirty = false;
+ bool undo_enabled = true;
+ bool line_length_guidelines = false;
+ int line_length_guideline_soft_col = 80;
+ int line_length_guideline_hard_col = 100;
+ bool hiding_enabled = false;
+ bool draw_minimap = false;
+ int minimap_width = 80;
+ Point2 minimap_char_size = Point2(1, 2);
+ int minimap_line_spacing = 1;
+
+ bool highlight_all_occurrences = false;
+ bool scroll_past_end_of_file_enabled = false;
+ bool auto_brace_completion_enabled = false;
+ bool brace_matching_enabled = false;
+ bool highlight_current_line = false;
+ bool auto_indent = false;
String cut_copy_line;
- bool insert_mode;
- bool select_identifiers_enabled;
-
- bool smooth_scroll_enabled;
- bool scrolling;
- bool dragging_selection;
- bool dragging_minimap;
- bool can_drag_minimap;
- bool minimap_clicked;
- double minimap_scroll_ratio;
- double minimap_scroll_click_pos;
- float target_v_scroll;
- float v_scroll_speed;
+ bool insert_mode = false;
+ bool select_identifiers_enabled = false;
+
+ bool smooth_scroll_enabled = false;
+ bool scrolling = false;
+ bool dragging_selection = false;
+ bool dragging_minimap = false;
+ bool can_drag_minimap = false;
+ bool minimap_clicked = false;
+ double minimap_scroll_ratio = 0.0;
+ double minimap_scroll_click_pos = 0.0;
+ float target_v_scroll = 0.0;
+ float v_scroll_speed = 80.0;
String highlighted_word;
- uint64_t last_dblclk;
+ uint64_t last_dblclk = 0;
Timer *idle_detect;
Timer *click_select_held;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
- bool updating_scrolls;
+ bool updating_scrolls = false;
- Object *tooltip_obj;
+ Object *tooltip_obj = nullptr;
StringName tooltip_func;
Variant tooltip_ud;
- bool next_operation_is_complex;
+ bool next_operation_is_complex = false;
- bool callhint_below;
+ bool callhint_below = false;
Vector2 callhint_offset;
String search_text;
- uint32_t search_flags;
- int search_result_line;
- int search_result_col;
+ uint32_t search_flags = 0;
+ int search_result_line = 0;
+ int search_result_col = 0;
- bool selecting_enabled;
+ bool selecting_enabled = true;
- bool context_menu_enabled;
- bool shortcut_keys_enabled;
+ bool context_menu_enabled = true;
+ bool shortcut_keys_enabled = true;
bool virtual_keyboard_enabled = true;
void _generate_context_menu();
@@ -400,8 +373,8 @@ private:
void set_line_as_center_visible(int p_line, int p_wrap_index = 0);
void set_line_as_last_visible(int p_line, int p_wrap_index = 0);
int get_first_visible_line() const;
- int get_last_visible_line() const;
- int get_last_visible_line_wrap_index() const;
+ int get_last_full_visible_line() const;
+ int get_last_full_visible_line_wrap_index() const;
double get_visible_rows_offset() const;
double get_v_scroll_offset() const;
@@ -435,6 +408,7 @@ private:
int _get_control_height() const;
Point2 _get_local_mouse_pos() const;
+ int _get_menu_action_accelerator(const String &p_action);
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -468,6 +442,26 @@ private:
int _calculate_spaces_till_next_left_indent(int column);
int _calculate_spaces_till_next_right_indent(int column);
+ // Methods used in shortcuts
+ void _swap_current_input_direction();
+ void _new_line(bool p_split_current = true, bool p_above = false);
+ void _indent_right();
+ void _indent_left();
+ void _move_cursor_left(bool p_select, bool p_move_by_word = false);
+ void _move_cursor_right(bool p_select, bool p_move_by_word = false);
+ void _move_cursor_up(bool p_select);
+ void _move_cursor_down(bool p_select);
+ void _move_cursor_to_line_start(bool p_select);
+ void _move_cursor_to_line_end(bool p_select);
+ void _move_cursor_page_up(bool p_select);
+ void _move_cursor_page_down(bool p_select);
+ void _backspace(bool p_word = false, bool p_all_to_left = false);
+ void _delete(bool p_word = false, bool p_all_to_right = false);
+ void _delete_selection();
+ void _move_cursor_document_start(bool p_select);
+ void _move_cursor_document_end(bool p_select);
+ void _handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete);
+
protected:
struct Cache {
Ref<Texture2D> tab_icon;
@@ -477,7 +471,9 @@ protected:
Ref<StyleBox> style_focus;
Ref<StyleBox> style_readonly;
Ref<Font> font;
- int font_size;
+ int font_size = 16;
+ int outline_size = 0;
+ Color outline_color;
Color completion_background_color;
Color completion_selected_color;
Color completion_existing_color;
@@ -498,12 +494,8 @@ protected:
Color search_result_border_color;
Color background_color;
- int line_spacing;
- int minimap_width;
- Cache() {
- line_spacing = 0;
- minimap_width = 0;
- }
+ int line_spacing = 1;
+ int minimap_width = 0;
} cache;
virtual String get_tooltip(const Point2 &p_pos) const override;
@@ -668,8 +660,8 @@ public:
int get_row_height() const;
void backspace_at_cursor();
- void indent_left();
- void indent_right();
+ void indent_selected_lines_left();
+ void indent_selected_lines_right();
int get_indent_level(int p_line) const;
bool is_line_comment(int p_line) const;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index bd670555ea..f43e3d1a9d 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -377,13 +377,4 @@ bool TextureButton::is_flipped_v() const {
return vflip;
}
-TextureButton::TextureButton() {
- expand = false;
- stretch_mode = STRETCH_SCALE;
- hflip = false;
- vflip = false;
-
- _texture_region = Rect2();
- _position_rect = Rect2();
- _tile = false;
-}
+TextureButton::TextureButton() {}
diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h
index 4b750c3fb1..8361f3c341 100644
--- a/scene/gui/texture_button.h
+++ b/scene/gui/texture_button.h
@@ -54,15 +54,15 @@ private:
Ref<Texture2D> disabled;
Ref<Texture2D> focused;
Ref<BitMap> click_mask;
- bool expand;
- StretchMode stretch_mode;
+ bool expand = false;
+ StretchMode stretch_mode = STRETCH_SCALE;
Rect2 _texture_region;
Rect2 _position_rect;
- bool _tile;
+ bool _tile = false;
- bool hflip;
- bool vflip;
+ bool hflip = false;
+ bool vflip = false;
protected:
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 76564e2b17..46ce9d5ca9 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -145,9 +145,9 @@ Point2 TextureProgressBar::unit_val_to_uv(float val) {
float angle = (val * Math_TAU) - Math_PI * 0.5;
Point2 dir = Vector2(Math::cos(angle), Math::sin(angle));
float t1 = 1.0;
- float cp = 0;
- float cq = 0;
- float cr = 0;
+ float cp = 0.0;
+ float cq = 0.0;
+ float cr = 0.0;
float edgeLeft = 0.0;
float edgeRight = 1.0;
float edgeBottom = 0.0;
@@ -540,17 +540,5 @@ void TextureProgressBar::_bind_methods() {
}
TextureProgressBar::TextureProgressBar() {
- mode = FILL_LEFT_TO_RIGHT;
- rad_init_angle = 0;
- rad_center_off = Point2();
- rad_max_degrees = 360;
set_mouse_filter(MOUSE_FILTER_PASS);
-
- nine_patch_stretch = false;
- stretch_margin[SIDE_LEFT] = 0;
- stretch_margin[SIDE_RIGHT] = 0;
- stretch_margin[SIDE_BOTTOM] = 0;
- stretch_margin[SIDE_TOP] = 0;
-
- tint_under = tint_progress = tint_over = Color(1, 1, 1);
}
diff --git a/scene/gui/texture_progress_bar.h b/scene/gui/texture_progress_bar.h
index ee33a915f7..a3883a7017 100644
--- a/scene/gui/texture_progress_bar.h
+++ b/scene/gui/texture_progress_bar.h
@@ -98,13 +98,15 @@ public:
TextureProgressBar();
private:
- FillMode mode;
- float rad_init_angle;
- float rad_max_degrees;
+ FillMode mode = FILL_LEFT_TO_RIGHT;
+ float rad_init_angle = 0.0;
+ float rad_max_degrees = 360.0;
Point2 rad_center_off;
- bool nine_patch_stretch;
- int stretch_margin[4];
- Color tint_under, tint_progress, tint_over;
+ bool nine_patch_stretch = false;
+ int stretch_margin[4] = {};
+ Color tint_under = Color(1, 1, 1);
+ Color tint_progress = Color(1, 1, 1);
+ Color tint_over = Color(1, 1, 1);
Point2 unit_val_to_uv(float val);
Point2 get_relative_center();
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index beb06b7739..1cba88e06f 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -217,11 +217,7 @@ bool TextureRect::is_flipped_v() const {
}
TextureRect::TextureRect() {
- expand = false;
- hflip = false;
- vflip = false;
set_mouse_filter(MOUSE_FILTER_PASS);
- stretch_mode = STRETCH_SCALE_ON_EXPAND;
}
TextureRect::~TextureRect() {
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 0f3172f5bd..0f93d5732f 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -49,11 +49,11 @@ public:
};
private:
- bool expand;
- bool hflip;
- bool vflip;
+ bool expand = false;
+ bool hflip = false;
+ bool vflip = false;
Ref<Texture2D> texture;
- StretchMode stretch_mode;
+ StretchMode stretch_mode = STRETCH_SCALE_ON_EXPAND;
void _texture_changed();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index c21497a995..73fd9dbcd7 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -410,6 +410,14 @@ bool TreeItem::is_collapsed() {
return collapsed;
}
+void TreeItem::uncollapse_tree() {
+ TreeItem *t = this;
+ while (t) {
+ t->set_collapsed(false);
+ t = t->parent;
+ }
+}
+
void TreeItem::set_custom_minimum_height(int p_height) {
custom_min_height = p_height;
_changed_notify();
@@ -842,6 +850,8 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
+ ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree);
+
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
@@ -1118,7 +1128,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
return height;
}
-void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color) {
+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(cache.font.is_null());
Rect2i rect = p_rect;
@@ -1160,6 +1170,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
Point2 draw_pos = rect.position;
draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0);
p_cell.text_buf->set_width(MAX(0, rect.size.width));
+ if (p_ol_size > 0 && p_ol_color.a > 0) {
+ p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color);
+ }
p_cell.text_buf->draw(ci, draw_pos, p_color);
rect.position.x += ts.width + cache.hseparation;
rect.size.x -= ts.width + cache.hseparation;
@@ -1182,6 +1195,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
Point2 draw_pos = rect.position;
draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0);
p_cell.text_buf->set_width(MAX(0, rect.size.width));
+ if (p_ol_size > 0 && p_ol_color.a > 0) {
+ p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color);
+ }
p_cell.text_buf->draw(ci, draw_pos, p_color);
}
}
@@ -1434,6 +1450,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Color icon_col = p_item->cells[i].icon_color;
if (p_item->cells[i].dirty) {
@@ -1450,7 +1468,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
switch (p_item->cells[i].mode) {
case TreeItem::CELL_MODE_STRING: {
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
} break;
case TreeItem::CELL_MODE_CHECK: {
Ref<Texture2D> checked = cache.checked;
@@ -1471,7 +1489,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
item_rect.size.x -= check_w;
item_rect.position.x += check_w;
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
} break;
case TreeItem::CELL_MODE_RANGE: {
@@ -1485,8 +1503,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
p_item->cells.write[i].text_buf->set_width(cell_width);
if (rtl) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos, col);
}
@@ -1501,8 +1525,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int cell_width = item_rect.size.x - updown->get_width();
if (rtl) {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col);
} else {
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
p_item->cells[i].text_buf->draw(ci, text_pos, col);
}
@@ -1543,7 +1573,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if (!p_item->cells[i].editable) {
- draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color);
break;
}
@@ -1558,7 +1588,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].custom_button) {
if (cache.hover_item == p_item && cache.hover_cell == i) {
- if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
draw_style_box(cache.custom_button_pressed, ir);
} else {
draw_style_box(cache.custom_button_hover, ir);
@@ -1571,7 +1601,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
ir.position += cache.custom_button->get_offset();
}
- draw_item_rect(p_item->cells.write[i], ir, col, icon_col);
+ draw_item_rect(p_item->cells.write[i], ir, col, icon_col, outline_size, font_outline_color);
downarrow->draw(ci, arrow_pos);
@@ -1795,7 +1825,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) {
}
void Tree::_range_click_timeout() {
- if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
Point2 pos = get_local_mouse_position() - cache.bg->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -1813,7 +1843,7 @@ void Tree::_range_click_timeout() {
propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, false, root, BUTTON_LEFT, mb);
+ propagate_mouse_event(pos + cache.offset, 0, 0, false, root, MOUSE_BUTTON_LEFT, mb);
blocked--;
if (range_click_timer->is_one_shot()) {
@@ -1930,7 +1960,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
col_width -= w + cache.button_margin;
}
- if (p_button == BUTTON_LEFT || (p_button == BUTTON_RIGHT && allow_rmb_select)) {
+ if (p_button == MOUSE_BUTTON_LEFT || (p_button == MOUSE_BUTTON_RIGHT && allow_rmb_select)) {
/* process selection */
if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
@@ -1942,10 +1972,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
}
if (select_mode == SELECT_MULTI && p_mod->get_command() && c.selectable) {
- if (!c.selected || p_button == BUTTON_RIGHT) {
+ if (!c.selected || p_button == MOUSE_BUTTON_RIGHT) {
p_item->select(col);
emit_signal("multi_selected", p_item, col, true);
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
@@ -1962,21 +1992,21 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
bool inrange = false;
select_single_item(p_item, root, col, selected_item, &inrange);
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
} else {
int icount = _count_selected_items(root);
- if (select_mode == SELECT_MULTI && icount > 1 && p_button != BUTTON_RIGHT) {
+ if (select_mode == SELECT_MULTI && icount > 1 && p_button != MOUSE_BUTTON_RIGHT) {
single_select_defer = p_item;
single_select_defer_column = col;
} else {
- if (p_button != BUTTON_RIGHT || !c.selected) {
+ if (p_button != MOUSE_BUTTON_RIGHT || !c.selected) {
select_single_item(p_item, root, col);
}
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
}
@@ -2046,7 +2076,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
/* touching the combo */
bool up = p_pos.y < (item_h / 2);
- if (p_button == BUTTON_LEFT) {
+ if (p_button == MOUSE_BUTTON_LEFT) {
if (range_click_timer->get_time_left() == 0) {
range_item_last = p_item;
range_up_last = up;
@@ -2063,13 +2093,13 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
item_edited(col, p_item);
- } else if (p_button == BUTTON_RIGHT) {
+ } else if (p_button == MOUSE_BUTTON_RIGHT) {
p_item->set_range(col, (up ? c.max : c.min));
item_edited(col, p_item);
- } else if (p_button == BUTTON_WHEEL_UP) {
+ } else if (p_button == MOUSE_BUTTON_WHEEL_UP) {
p_item->set_range(col, c.val + c.step);
item_edited(col, p_item);
- } else if (p_button == BUTTON_WHEEL_DOWN) {
+ } else if (p_button == MOUSE_BUTTON_WHEEL_DOWN) {
p_item->set_range(col, c.val - c.step);
item_edited(col, p_item);
}
@@ -2102,14 +2132,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
}
if (!p_item->cells[col].custom_button || !on_arrow) {
- item_edited(col, p_item, p_button == BUTTON_LEFT);
+ item_edited(col, p_item, p_button == MOUSE_BUTTON_LEFT);
}
click_handled = true;
return -1;
} break;
};
- if (!bring_up_editor || p_button != BUTTON_LEFT) {
+ if (!bring_up_editor || p_button != MOUSE_BUTTON_LEFT) {
return -1;
}
@@ -2149,7 +2179,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
item_h += child_h;
}
}
- if (p_item == root && p_button == BUTTON_RIGHT) {
+ if (p_item == root && p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("empty_rmb", get_local_mouse_position());
}
}
@@ -2372,6 +2402,8 @@ void Tree::_go_down() {
}
void Tree::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
bool is_command = k.is_valid() && k->get_command();
@@ -2690,7 +2722,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
bool rtl = is_layout_rtl();
if (!b->is_pressed()) {
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos = b->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
@@ -2771,8 +2803,8 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
switch (b->get_button_index()) {
- case BUTTON_RIGHT:
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_LEFT: {
Ref<StyleBox> bg = cache.bg;
Point2 pos = b->get_position();
@@ -2785,7 +2817,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
pos.x += cache.offset.x;
int len = 0;
for (int i = 0; i < columns.size(); i++) {
@@ -2803,7 +2835,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
}
if (!root || (!root->get_children() && hide_root)) {
- if (b->get_button_index() == BUTTON_RIGHT && allow_rmb_select) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) {
emit_signal("empty_tree_rmb_selected", get_local_mouse_position());
}
break;
@@ -2824,7 +2856,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (b->get_button_index() == BUTTON_RIGHT) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT) {
break;
}
@@ -2847,7 +2879,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
set_physics_process_internal(true);
}
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (get_item_at_position(b->get_position()) == nullptr && !b->get_shift() && !b->get_control() && !b->get_command()) {
emit_signal("nothing_selected");
}
@@ -2860,7 +2892,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
@@ -2868,7 +2900,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
@@ -3143,6 +3175,8 @@ void Tree::_notification(int p_what) {
Ref<StyleBox> bg = cache.bg;
Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus");
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3179,7 +3213,12 @@ void Tree::_notification(int p_what) {
//text
int clip_w = tbrect.size.width - sb->get_minimum_size().width;
columns.write[i].text_buf->set_width(clip_w);
- columns[i].text_buf->draw(ci, tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2), cache.title_button_color);
+
+ Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2);
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
+ }
+ columns[i].text_buf->draw(ci, text_pos, cache.title_button_color);
}
}
}
@@ -3315,6 +3354,9 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
selected_col = p_column;
+ if (!selected_item) {
+ selected_item = p_item;
+ }
} else {
select_single_item(p_item, root, p_column);
}
@@ -3324,10 +3366,10 @@ 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) {
selected_item = nullptr;
- }
- if (selected_col == p_column) {
- selected_col = -1;
+ if (selected_col == p_column) {
+ selected_col = -1;
+ }
}
if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) {
@@ -3476,9 +3518,13 @@ int Tree::get_column_width(int p_column) const {
return columns[p_column].min_width;
}
+ int expand_area = get_size().width;
+
Ref<StyleBox> bg = cache.bg;
- int expand_area = get_size().width - (bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT));
+ if (bg.is_valid()) {
+ expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT);
+ }
if (v_scroll->is_visible_in_tree()) {
expand_area -= v_scroll->get_combined_minimum_size().width;
@@ -4157,6 +4203,7 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_edited"), &Tree::get_edited);
ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column);
+ ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected);
ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect);
ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::_get_item_rect, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position);
@@ -4232,19 +4279,8 @@ void Tree::_bind_methods() {
}
Tree::Tree() {
- selected_col = 0;
columns.resize(1);
- selected_item = nullptr;
- edited_item = nullptr;
- selected_col = -1;
- edited_col = -1;
- hide_root = false;
- select_mode = SELECT_SINGLE;
- root = nullptr;
- popup_menu = nullptr;
- popup_edited_item = nullptr;
- text_editor = nullptr;
set_focus_mode(FOCUS_ALL);
popup_menu = memnew(PopupMenu);
@@ -4288,50 +4324,9 @@ Tree::Tree() {
set_notify_transform(true);
- updating_value_editor = false;
- pressed_button = -1;
- show_column_titles = false;
-
- cache.click_type = Cache::CLICK_NONE;
- cache.hover_type = Cache::CLICK_NONE;
- cache.hover_index = -1;
- cache.click_index = -1;
- cache.click_id = -1;
- cache.click_item = nullptr;
- cache.click_column = 0;
- cache.hover_cell = -1;
- last_keypress = 0;
- focus_in_id = 0;
-
- blocked = 0;
-
- cursor_can_exit_tree = true;
set_mouse_filter(MOUSE_FILTER_STOP);
- drag_speed = 0;
- drag_touching = false;
- drag_touching_deaccel = false;
- pressing_for_editor = false;
- range_drag_enabled = false;
-
- hide_folding = false;
-
- drop_mode_flags = 0;
- drop_mode_over = nullptr;
- drop_mode_section = 0;
- single_select_defer = nullptr;
-
- scrolling = false;
- allow_rmb_select = false;
- force_edit_checkbox_only_on_checkbox = false;
-
set_clip_contents(true);
-
- cache.hover_item = nullptr;
- cache.hover_cell = -1;
-
- allow_reselect = false;
- propagate_mouse_activated = false;
}
Tree::~Tree() {
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 854b82ebd7..d1407e24d4 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -62,7 +62,7 @@ private:
friend class Tree;
struct Cell {
- TreeCellMode mode;
+ TreeCellMode mode = TreeItem::CELL_MODE_STRING;
Ref<Texture2D> icon;
Rect2i icon_region;
@@ -74,24 +74,27 @@ private:
Control::StructuredTextParser st_parser = Control::STRUCTURED_TEXT_DEFAULT;
Array st_args;
Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED;
- bool dirty;
- double min, max, step, val;
- int icon_max_w;
- bool expr;
- bool checked;
- bool editable;
- bool selected;
- bool selectable;
- bool custom_color;
+ bool dirty = true;
+ double min = 0.0;
+ double max = 100.0;
+ double step = 1.0;
+ double val = 0.0;
+ int icon_max_w = 0;
+ bool expr = false;
+ bool checked = false;
+ bool editable = false;
+ bool selected = false;
+ bool selectable = true;
+ bool custom_color = false;
Color color;
- bool custom_bg_color;
- bool custom_bg_outline;
+ bool custom_bg_color = false;
+ bool custom_bg_outline = false;
Color bg_color;
- bool custom_button;
- bool expand_right;
- Color icon_color;
+ bool custom_button = false;
+ bool expand_right = false;
+ Color icon_color = Color(1, 1, 1);
- TextAlign text_align;
+ TextAlign text_align = ALIGN_LEFT;
Variant meta;
String tooltip;
@@ -100,42 +103,17 @@ private:
StringName custom_draw_callback;
struct Button {
- int id;
- bool disabled;
+ int id = 0;
+ bool disabled = false;
Ref<Texture2D> texture;
- Color color;
+ Color color = Color(1, 1, 1, 1);
String tooltip;
- Button() {
- id = 0;
- disabled = false;
- color = Color(1, 1, 1, 1);
- tooltip = "";
- }
};
Vector<Button> buttons;
Cell() {
text_buf.instance();
- dirty = true;
- custom_draw_obj = ObjectID();
- custom_button = false;
- mode = TreeItem::CELL_MODE_STRING;
- min = 0;
- max = 100;
- step = 1;
- val = 0;
- checked = false;
- editable = false;
- selected = false;
- selectable = true;
- custom_color = false;
- custom_bg_color = false;
- expr = false;
- icon_max_w = 0;
- text_align = ALIGN_LEFT;
- expand_right = false;
- icon_color = Color(1, 1, 1);
}
Size2 get_icon_size() const;
@@ -251,6 +229,8 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed();
+ void uncollapse_tree();
+
void set_custom_minimum_height(int p_height);
int get_custom_minimum_height() const;
@@ -332,46 +312,46 @@ public:
private:
friend class TreeItem;
- TreeItem *root;
- TreeItem *popup_edited_item;
- TreeItem *selected_item;
- TreeItem *edited_item;
+ TreeItem *root = nullptr;
+ TreeItem *popup_edited_item = nullptr;
+ TreeItem *selected_item = nullptr;
+ TreeItem *edited_item = nullptr;
- TreeItem *drop_mode_over;
- int drop_mode_section;
+ TreeItem *drop_mode_over = nullptr;
+ int drop_mode_section = 0;
- TreeItem *single_select_defer;
- int single_select_defer_column;
+ TreeItem *single_select_defer = nullptr;
+ int single_select_defer_column = 0;
- int pressed_button;
- bool pressing_for_editor;
+ int pressed_button = -1;
+ bool pressing_for_editor = false;
String pressing_for_editor_text;
Vector2 pressing_pos;
Rect2 pressing_item_rect;
- float range_drag_base;
- bool range_drag_enabled;
+ float range_drag_base = 0.0;
+ bool range_drag_enabled = false;
Vector2 range_drag_capture_pos;
- bool propagate_mouse_activated;
+ bool propagate_mouse_activated = false;
//TreeItem *cursor_item;
//int cursor_column;
Rect2 custom_popup_rect;
- int edited_col;
- int selected_col;
- int popup_edited_item_col;
- bool hide_root;
- SelectMode select_mode;
+ int edited_col = -1;
+ int selected_col = -1;
+ int popup_edited_item_col = -1;
+ bool hide_root = false;
+ SelectMode select_mode = SELECT_SINGLE;
- int blocked;
+ int blocked = 0;
- int drop_mode_flags;
+ int drop_mode_flags = 0;
struct ColumnInfo {
- int min_width;
- bool expand;
+ int min_width = 1;
+ bool expand = true;
String title;
Ref<TextLine> text_buf;
Dictionary opentype_features;
@@ -379,27 +359,25 @@ private:
Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED;
ColumnInfo() {
text_buf.instance();
- min_width = 1;
- expand = true;
}
};
- bool show_column_titles;
+ bool show_column_titles = false;
VBoxContainer *popup_editor_vb;
Popup *popup_editor;
- LineEdit *text_editor;
+ LineEdit *text_editor = nullptr;
HSlider *value_editor;
- bool updating_value_editor;
- uint64_t focus_in_id;
- PopupMenu *popup_menu;
+ bool updating_value_editor = false;
+ uint64_t focus_in_id = 0;
+ PopupMenu *popup_menu = nullptr;
Vector<ColumnInfo> columns;
Timer *range_click_timer;
- TreeItem *range_item_last;
- bool range_up_last;
+ TreeItem *range_item_last = nullptr;
+ bool range_up_last = false;
void _range_click_timeout();
int compute_item_height(TreeItem *p_item) const;
@@ -409,7 +387,7 @@ private:
void update_item_cell(TreeItem *p_item, int p_col);
void update_item_cache(TreeItem *p_item);
//void draw_item_text(String p_text,const Ref<Texture2D>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color);
- void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color);
+ void 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);
int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item);
void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false);
int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
@@ -434,8 +412,8 @@ private:
struct Cache {
Ref<Font> font;
Ref<Font> tb_font;
- int font_size;
- int tb_font_size;
+ int font_size = 0;
+ int tb_font_size = 0;
Ref<StyleBox> bg;
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
@@ -465,15 +443,15 @@ private:
Color relationship_line_color;
Color custom_button_font_highlight;
- int hseparation;
- int vseparation;
- int item_margin;
- int button_margin;
+ int hseparation = 0;
+ int vseparation = 0;
+ int item_margin = 0;
+ int button_margin = 0;
Point2 offset;
- int draw_relationship_lines;
- int draw_guides;
- int scroll_border;
- int scroll_speed;
+ int draw_relationship_lines = 0;
+ int draw_guides = 0;
+ int scroll_border = 0;
+ int scroll_speed = 0;
enum ClickType {
CLICK_NONE,
@@ -482,17 +460,17 @@ private:
};
- ClickType click_type;
- ClickType hover_type;
- int click_index;
- int click_id;
- TreeItem *click_item;
- int click_column;
- int hover_index;
+ ClickType click_type = Cache::CLICK_NONE;
+ ClickType hover_type = Cache::CLICK_NONE;
+ int click_index = -1;
+ int click_id = -1;
+ TreeItem *click_item = nullptr;
+ int click_column = 0;
+ int hover_index = -1;
Point2 click_pos;
- TreeItem *hover_item;
- int hover_cell;
+ TreeItem *hover_item = nullptr;
+ int hover_cell = -1;
Point2i text_editor_position;
@@ -510,9 +488,9 @@ private:
Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item);
//Rect2 get_item_rect(TreeItem *p_item);
- uint64_t last_keypress;
+ uint64_t last_keypress = 0;
String incr_search;
- bool cursor_can_exit_tree;
+ bool cursor_can_exit_tree = true;
void _do_incr_search(const String &p_add);
TreeItem *_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards = false);
@@ -526,21 +504,21 @@ private:
float last_drag_time;
float time_since_motion;*/
- float drag_speed;
- float drag_from;
- float drag_accum;
+ float drag_speed = 0.0;
+ float drag_from = 0.0;
+ float drag_accum = 0.0;
Vector2 last_speed;
- bool drag_touching;
- bool drag_touching_deaccel;
- bool click_handled;
- bool allow_rmb_select;
- bool scrolling;
+ bool drag_touching = false;
+ bool drag_touching_deaccel = false;
+ bool click_handled = false;
+ bool allow_rmb_select = false;
+ bool scrolling = false;
- bool allow_reselect;
+ bool allow_reselect = false;
- bool force_edit_checkbox_only_on_checkbox;
+ bool force_edit_checkbox_only_on_checkbox = false;
- bool hide_folding;
+ bool hide_folding = false;
int _count_selected_items(TreeItem *p_from) const;
void _go_left();
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 84d689369b..0590ae2415 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -462,25 +462,7 @@ void VideoPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
}
-VideoPlayer::VideoPlayer() {
- volume = 1;
- loops = false;
- paused = false;
- autoplay = false;
- expand = true;
-
- audio_track = 0;
- bus_index = 0;
-
- buffering_ms = 500;
-
- // internal_stream.player=this;
- // stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
- last_audio_time = 0;
-
- wait_resampler = 0;
- wait_resampler_limit = 2;
-};
+VideoPlayer::VideoPlayer() {}
VideoPlayer::~VideoPlayer() {
// if (stream_rid.is_valid())
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 089337eed5..0edad296a1 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -41,8 +41,8 @@ class VideoPlayer : public Control {
struct Output {
AudioFrame vol;
- int bus_index;
- Viewport *viewport; //pointer only used for reference to previous mix
+ int bus_index = 0;
+ Viewport *viewport = nullptr; //pointer only used for reference to previous mix
};
Ref<VideoStreamPlayback> playback;
Ref<VideoStream> stream;
@@ -56,17 +56,18 @@ class VideoPlayer : public Control {
AudioRBResampler resampler;
Vector<AudioFrame> mix_buffer;
- int wait_resampler, wait_resampler_limit;
-
- bool paused;
- bool autoplay;
- float volume;
- double last_audio_time;
- bool expand;
- bool loops;
- int buffering_ms;
- int audio_track;
- int bus_index;
+ int wait_resampler = 0;
+ int wait_resampler_limit = 2;
+
+ bool paused = false;
+ bool autoplay = false;
+ float volume = 1.0;
+ double last_audio_time = 0.0;
+ bool expand = true;
+ bool loops = false;
+ int buffering_ms = 500;
+ int audio_track = 0;
+ int bus_index = 0;
StringName bus;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index efef49fbf0..55529517f1 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -203,7 +203,7 @@ CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
particles_animation = p_particles_anim;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
bool CanvasItemMaterial::get_particles_animation() const {
@@ -387,7 +387,6 @@ void CanvasItem::show() {
}
_propagate_visibility_changed(true);
- _change_notify("visible");
}
void CanvasItem::hide() {
@@ -403,7 +402,6 @@ void CanvasItem::hide() {
}
_propagate_visibility_changed(false);
- _change_notify("visible");
}
CanvasItem *CanvasItem::current_item_drawn = nullptr;
@@ -731,13 +729,13 @@ void CanvasItem::item_rect_changed(bool p_size_changed) {
emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
}
-void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
}
-void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -745,25 +743,25 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
}
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
-void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
Vector<Point2> points;
points.resize(p_point_count);
- const float delta_angle = p_end_angle - p_start_angle;
+ const real_t delta_angle = p_end_angle - p_start_angle;
for (int i = 0; i < p_point_count; i++) {
- float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
}
draw_polyline(points, p_color, p_width, p_antialiased);
}
-void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -771,13 +769,13 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
}
-void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
}
-void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) {
+void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
if (p_filled) {
@@ -789,7 +787,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
} else {
// Thick lines are offset depending on their width to avoid partial overlapping.
// Thin lines don't require an offset, so don't apply one in this case
- float offset;
+ real_t offset;
if (p_width >= 2) {
offset = p_width / 2.0;
} else {
@@ -823,7 +821,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
}
}
-void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
+void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
@@ -858,14 +856,14 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
p_style_box->draw(canvas_item, p_rect);
}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width) {
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width);
}
-void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
+void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Transform2D xform(p_rot, p_offset);
@@ -909,19 +907,19 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
}
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_string(canvas_item, p_pos, p_text, p_align, p_width, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_align, p_width, p_max_lines, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
+real_t CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
ERR_FAIL_COND_V_MSG(!drawing, 0.f, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND_V(p_font.is_null(), 0.f);
ERR_FAIL_COND_V(p_char.length() != 1, 0.f);
@@ -1035,7 +1033,7 @@ void CanvasItem::set_material(const Ref<Material> &p_material) {
rid = material->get_rid();
}
RS::get_singleton()->canvas_item_set_material(canvas_item, rid);
- _change_notify(); //properties for material exposed
+ notify_property_list_changed(); //properties for material exposed
}
void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
@@ -1341,7 +1339,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
}
texture_filter = p_texture_filter;
_update_texture_filter_changed(true);
- _change_notify();
+ notify_property_list_changed();
}
CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
@@ -1381,7 +1379,7 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
}
texture_repeat = p_texture_repeat;
_update_texture_repeat_changed(true);
- _change_notify();
+ notify_property_list_changed();
}
void CanvasItem::set_clip_children(bool p_enabled) {
@@ -1443,6 +1441,7 @@ void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid);
}
+
Ref<Texture2D> CanvasTexture::get_specular_texture() const {
return specular_texture;
}
@@ -1451,15 +1450,17 @@ void CanvasTexture::set_specular_color(const Color &p_color) {
specular = p_color;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
+
Color CanvasTexture::get_specular_color() const {
return specular;
}
-void CanvasTexture::set_specular_shininess(float p_shininess) {
+void CanvasTexture::set_specular_shininess(real_t p_shininess) {
shininess = p_shininess;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
-float CanvasTexture::get_specular_shininess() const {
+
+real_t CanvasTexture::get_specular_shininess() const {
return shininess;
}
@@ -1510,9 +1511,9 @@ bool CanvasTexture::has_alpha() const {
}
}
-Ref<Image> CanvasTexture::get_data() const {
+Ref<Image> CanvasTexture::get_image() const {
if (diffuse_texture.is_valid()) {
- return diffuse_texture->get_data();
+ return diffuse_texture->get_image();
} else {
return Ref<Image>();
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 64eb3f4e0a..1c64cafab8 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -90,7 +90,7 @@ private:
struct ShaderData {
RID shader;
- int users;
+ int users = 0;
};
static Map<MaterialKey, ShaderData> shader_map;
@@ -290,8 +290,8 @@ public:
// Used to rotate the node
virtual bool _edit_use_rotation() const { return false; };
- virtual void _edit_set_rotation(float p_rotation) {}
- virtual float _edit_get_rotation() const { return 0.0; };
+ virtual void _edit_set_rotation(real_t p_rotation) {}
+ virtual real_t _edit_get_rotation() const { return 0.0; };
// Used to resize/move the node
virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
@@ -331,30 +331,30 @@ public:
/* DRAWING API */
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
- void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
- void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
- void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
- void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0);
+ void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0);
+ void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0);
+ void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color);
void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
- void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1);
+ void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1);
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture);
- void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
+ void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ real_t draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
- void draw_set_transform(const Point2 &p_offset, float p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
+ void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
void draw_set_transform_matrix(const Transform2D &p_matrix);
static CanvasItem *get_current_item_drawn();
@@ -437,7 +437,7 @@ class CanvasTexture : public Texture2D {
Ref<Texture2D> normal_texture;
Ref<Texture2D> specular_texture;
Color specular = Color(1, 1, 1, 1);
- float shininess = 1.0;
+ real_t shininess = 1.0;
RID canvas_texture;
@@ -460,8 +460,8 @@ public:
void set_specular_color(const Color &p_color);
Color get_specular_color() const;
- void set_specular_shininess(float p_shininess);
- float get_specular_shininess() const;
+ void set_specular_shininess(real_t p_shininess);
+ real_t get_specular_shininess() const;
void set_texture_filter(CanvasItem::TextureFilter p_filter);
CanvasItem::TextureFilter get_texture_filter() const;
@@ -475,7 +475,7 @@ public:
virtual bool is_pixel_opaque(int p_x, int p_y) const override;
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
virtual RID get_rid() const override;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 9826d9d4db..85d7edd64b 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -231,6 +231,7 @@ void CanvasLayer::set_follow_viewport(bool p_enable) {
follow_viewport = p_enable;
_update_follow_viewport();
+ notify_property_list_changed();
}
bool CanvasLayer::is_following_viewport() const {
@@ -257,6 +258,12 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
}
}
+void CanvasLayer::_validate_property(PropertyInfo &property) const {
+ if (!follow_viewport && property.name == "follow_viewport_scale") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);
ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer);
@@ -303,17 +310,7 @@ void CanvasLayer::_bind_methods() {
}
CanvasLayer::CanvasLayer() {
- vp = nullptr;
- scale = Vector2(1, 1);
- rot = 0;
- locrotscale_dirty = false;
- layer = 1;
canvas = RS::get_singleton()->canvas_create();
- custom_viewport = nullptr;
-
- sort_index = 0;
- follow_viewport = false;
- follow_viewport_scale = 1.0;
}
CanvasLayer::~CanvasLayer() {
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index cb10c6299b..899039340a 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -38,24 +38,24 @@ class Viewport;
class CanvasLayer : public Node {
GDCLASS(CanvasLayer, Node);
- bool locrotscale_dirty;
+ bool locrotscale_dirty = false;
Vector2 ofs;
- Size2 scale;
- real_t rot;
- int layer;
+ Size2 scale = Vector2(1, 1);
+ real_t rot = 0.0;
+ int layer = 1;
Transform2D transform;
RID canvas;
ObjectID custom_viewport_id; // to check validity
- Viewport *custom_viewport;
+ Viewport *custom_viewport = nullptr;
RID viewport;
- Viewport *vp;
+ Viewport *vp = nullptr;
- int sort_index;
+ int sort_index = 0;
- bool follow_viewport;
- float follow_viewport_scale;
+ bool follow_viewport = false;
+ float follow_viewport_scale = 1.0;
void _update_xform();
void _update_locrotscale();
@@ -64,6 +64,7 @@ class CanvasLayer : public Node {
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
void set_layer(int p_xform);
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 4c6b85d78b..884696d58d 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -40,47 +40,30 @@ Error HTTPRequest::_request() {
}
Error HTTPRequest::_parse_url(const String &p_url) {
- url = p_url;
use_ssl = false;
-
request_string = "";
port = 80;
request_sent = false;
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ downloaded.set(0);
redirections = 0;
- String url_lower = url.to_lower();
- if (url_lower.begins_with("http://")) {
- url = url.substr(7, url.length() - 7);
- } else if (url_lower.begins_with("https://")) {
- url = url.substr(8, url.length() - 8);
+ String scheme;
+ Error err = p_url.parse_url(scheme, url, port, request_string);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
+ if (scheme == "https://") {
use_ssl = true;
- port = 443;
- } else {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + ".");
+ } else if (scheme != "http://") {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
-
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
-
- int slash_pos = url.find("/");
-
- if (slash_pos != -1) {
- request_string = url.substr(slash_pos, url.length());
- url = url.substr(0, slash_pos);
- } else {
- request_string = "/";
+ if (port == 0) {
+ port = use_ssl ? 443 : 80;
}
-
- int colon_pos = url.find(":");
- if (colon_pos != -1) {
- port = url.substr(colon_pos + 1, url.length()).to_int();
- url = url.substr(0, colon_pos);
- ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER);
+ if (request_string.is_empty()) {
+ request_string = "/";
}
-
return OK;
}
@@ -123,7 +106,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
size_t len = charstr.length();
raw_data.resize(len);
uint8_t *w = raw_data.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
}
@@ -159,9 +142,9 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
requesting = true;
- if (use_threads) {
- thread_done = false;
- thread_request_quit = false;
+ if (use_threads.is_set()) {
+ thread_done.clear();
+ thread_request_quit.clear();
client->set_blocking_mode(true);
thread.start(_thread_func, this);
} else {
@@ -186,7 +169,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
if (err != OK) {
hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
} else {
- while (!hr->thread_request_quit) {
+ while (!hr->thread_request_quit.is_set()) {
bool exit = hr->_update_connection();
if (exit) {
break;
@@ -195,7 +178,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
}
}
- hr->thread_done = true;
+ hr->thread_done.set();
}
void HTTPRequest::cancel_request() {
@@ -205,10 +188,10 @@ void HTTPRequest::cancel_request() {
return;
}
- if (!use_threads) {
+ if (!use_threads.is_set()) {
set_process_internal(false);
} else {
- thread_request_quit = true;
+ thread_request_quit.set();
thread.wait_to_finish();
}
@@ -236,7 +219,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
- downloaded = 0;
+ downloaded.set(0);
for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
response_headers.push_back(E->get());
}
@@ -276,7 +259,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ downloaded.set(0);
redirections = new_redirs;
*ret_value = false;
return true;
@@ -335,7 +318,7 @@ bool HTTPRequest::_update_connection() {
call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
return true;
- // Request migh have been done
+ // Request might have been done
} else {
// Did not request yet, do request
@@ -387,9 +370,12 @@ bool HTTPRequest::_update_connection() {
}
client->poll();
+ if (client->get_status() != HTTPClient::STATUS_BODY) {
+ return false;
+ }
PackedByteArray chunk = client->read_response_body_chunk();
- downloaded += chunk.size();
+ downloaded.add(chunk.size());
if (file) {
const uint8_t *r = chunk.ptr();
@@ -402,19 +388,20 @@ bool HTTPRequest::_update_connection() {
body.append_array(chunk);
}
- if (body_size_limit >= 0 && downloaded > body_size_limit) {
+ if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len >= 0) {
- if (downloaded == body_len) {
+ if (downloaded.get() == body_len) {
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
} else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) {
// We read till EOF, with no errors. Request is done.
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
+ return true;
}
return false;
@@ -450,7 +437,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
is_compressed = false;
}
- const PackedByteArray *data = NULL;
+ const PackedByteArray *data = nullptr;
if (accept_gzip && is_compressed && p_data.size() > 0) {
// Decompress request body
@@ -478,7 +465,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
void HTTPRequest::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (use_threads) {
+ if (use_threads.is_set()) {
return;
}
bool done = _update_connection();
@@ -497,11 +484,11 @@ void HTTPRequest::_notification(int p_what) {
void HTTPRequest::set_use_threads(bool p_use) {
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
- use_threads = p_use;
+ use_threads.set_to(p_use);
}
bool HTTPRequest::is_using_threads() const {
- return use_threads;
+ return use_threads.is_set();
}
void HTTPRequest::set_accept_gzip(bool p_gzip) {
@@ -555,7 +542,7 @@ int HTTPRequest::get_max_redirects() const {
}
int HTTPRequest::get_downloaded_bytes() const {
- return downloaded;
+ return downloaded.get();
}
int HTTPRequest::get_body_size() const {
@@ -638,29 +625,11 @@ void HTTPRequest::_bind_methods() {
}
HTTPRequest::HTTPRequest() {
- port = 80;
- redirections = 0;
- max_redirects = 8;
- body_len = -1;
- got_response = false;
- validate_ssl = false;
- use_ssl = false;
- accept_gzip = true;
- response_code = 0;
- request_sent = false;
- requesting = false;
client.instance();
- use_threads = false;
- thread_done = false;
- downloaded = 0;
- body_size_limit = -1;
- file = nullptr;
-
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
add_child(timer);
- timeout = 0;
}
HTTPRequest::~HTTPRequest() {
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 9dbf561cd4..92b0ff28e9 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -34,6 +34,7 @@
#include "core/io/http_client.h"
#include "core/os/file_access.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "node.h"
#include "scene/main/timer.h"
@@ -60,42 +61,42 @@ public:
};
private:
- bool requesting;
+ bool requesting = false;
String request_string;
String url;
- int port;
+ int port = 80;
Vector<String> headers;
- bool validate_ssl;
- bool use_ssl;
+ bool validate_ssl = false;
+ bool use_ssl = false;
HTTPClient::Method method;
Vector<uint8_t> request_data;
- bool request_sent;
+ bool request_sent = false;
Ref<HTTPClient> client;
PackedByteArray body;
- volatile bool use_threads;
- bool accept_gzip;
+ SafeFlag use_threads;
+ bool accept_gzip = true;
- bool got_response;
- int response_code;
+ bool got_response = false;
+ int response_code = 0;
Vector<String> response_headers;
String download_to_file;
- FileAccess *file;
+ FileAccess *file = nullptr;
- int body_len;
- volatile int downloaded;
- int body_size_limit;
+ int body_len = -1;
+ SafeNumeric<int> downloaded;
+ int body_size_limit = -1;
- int redirections;
+ int redirections = 0;
bool _update_connection();
- int max_redirects;
+ int max_redirects = 8;
- int timeout;
+ int timeout = 0;
void _redirect_request(const String &p_new_url);
@@ -107,8 +108,8 @@ private:
bool has_header(const PackedStringArray &p_headers, const String &p_header_name);
String get_header_value(const PackedStringArray &p_headers, const String &header_name);
- volatile bool thread_done;
- volatile bool thread_request_quit;
+ SafeFlag thread_done;
+ SafeFlag thread_request_quit;
Thread thread;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 0c01516032..b7313749d6 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -46,7 +46,7 @@
#include <stdint.h>
-VARIANT_ENUM_CAST(Node::PauseMode);
+VARIANT_ENUM_CAST(Node::ProcessMode);
int Node::orphan_node_count = 0;
@@ -69,14 +69,14 @@ void Node::_notification(int p_notification) {
ERR_FAIL_COND(!get_viewport());
ERR_FAIL_COND(!get_tree());
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
if (data.parent) {
- data.pause_owner = data.parent->data.pause_owner;
+ data.process_owner = data.parent->data.process_owner;
} else {
- data.pause_owner = nullptr;
+ data.process_owner = nullptr;
}
} else {
- data.pause_owner = this;
+ data.process_owner = this;
}
if (data.input) {
@@ -110,7 +110,7 @@ void Node::_notification(int p_notification) {
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
}
- data.pause_owner = nullptr;
+ data.process_owner = nullptr;
if (data.path_cache) {
memdelete(data.path_cache);
data.path_cache = nullptr;
@@ -367,8 +367,6 @@ void Node::set_physics_process(bool p_process) {
} else {
remove_from_group("physics_process");
}
-
- _change_notify("physics_process");
}
bool Node::is_physics_processing() const {
@@ -387,52 +385,87 @@ void Node::set_physics_process_internal(bool p_process_internal) {
} else {
remove_from_group("physics_process_internal");
}
-
- _change_notify("physics_process_internal");
}
bool Node::is_physics_processing_internal() const {
return data.physics_process_internal;
}
-void Node::set_pause_mode(PauseMode p_mode) {
- if (data.pause_mode == p_mode) {
+void Node::set_process_mode(ProcessMode p_mode) {
+ if (data.process_mode == p_mode) {
return;
}
- bool prev_inherits = data.pause_mode == PAUSE_MODE_INHERIT;
- data.pause_mode = p_mode;
if (!is_inside_tree()) {
- return; //pointless
- }
- if ((data.pause_mode == PAUSE_MODE_INHERIT) == prev_inherits) {
- return; ///nothing changed
+ data.process_mode = p_mode;
+ return;
}
- Node *owner = nullptr;
+ bool prev_can_process = can_process();
+
+ data.process_mode = p_mode;
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
if (data.parent) {
- owner = data.parent->data.pause_owner;
+ data.process_owner = data.parent->data.owner;
+ } else {
+ data.process_owner = nullptr;
}
} else {
- owner = this;
+ data.process_owner = this;
+ }
+
+ bool next_can_process = can_process();
+
+ int pause_notification = 0;
+
+ if (prev_can_process && !next_can_process) {
+ pause_notification = NOTIFICATION_PAUSED;
+ } else if (!prev_can_process && next_can_process) {
+ pause_notification = NOTIFICATION_UNPAUSED;
+ }
+
+ _propagate_process_owner(data.process_owner, pause_notification);
+#ifdef TOOLS_ENABLED
+ // This is required for the editor to update the visibility of disabled nodes
+ // It's very expensive during runtime to change, so editor-only
+ if (Engine::get_singleton()->is_editor_hint()) {
+ get_tree()->emit_signal("tree_process_mode_changed");
+ }
+#endif
+}
+
+void Node::_propagate_pause_notification(bool p_enable) {
+ bool prev_can_process = _can_process(!p_enable);
+ bool next_can_process = _can_process(p_enable);
+
+ if (prev_can_process && !next_can_process) {
+ notification(NOTIFICATION_PAUSED);
+ } else if (!prev_can_process && next_can_process) {
+ notification(NOTIFICATION_UNPAUSED);
}
- _propagate_pause_owner(owner);
+ for (int i = 0; i < data.children.size(); i++) {
+ data.children[i]->_propagate_pause_notification(p_enable);
+ }
}
-Node::PauseMode Node::get_pause_mode() const {
- return data.pause_mode;
+Node::ProcessMode Node::get_process_mode() const {
+ return data.process_mode;
}
-void Node::_propagate_pause_owner(Node *p_owner) {
- if (this != p_owner && data.pause_mode != PAUSE_MODE_INHERIT) {
- return;
+void Node::_propagate_process_owner(Node *p_owner, int p_notification) {
+ data.process_owner = p_owner;
+
+ if (p_notification != 0) {
+ notification(p_notification);
}
- data.pause_owner = p_owner;
+
for (int i = 0; i < data.children.size(); i++) {
- data.children[i]->_propagate_pause_owner(p_owner);
+ Node *c = data.children[i];
+ if (c->data.process_mode == PROCESS_MODE_INHERIT) {
+ c->_propagate_process_owner(p_owner, p_notification);
+ }
}
}
@@ -466,7 +499,7 @@ uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_
nd.name = p_method;
nd.mode = p_mode;
data.rpc_methods.push_back(nd);
- return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
+ return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
} else {
int c_mid = (~(1 << 15)) & mid;
data.rpc_methods.write[c_mid].mode = p_mode;
@@ -555,7 +588,7 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr
return Variant();
}
- if (p_args[0]->get_type() != Variant::STRING) {
+ if (p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING;
@@ -584,7 +617,7 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal
return Variant();
}
- if (p_args[1]->get_type() != Variant::STRING) {
+ if (p_args[1]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::STRING;
@@ -607,7 +640,7 @@ Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Calla
return Variant();
}
- if (p_args[0]->get_type() != Variant::STRING) {
+ if (p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING;
@@ -636,7 +669,7 @@ Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Ca
return Variant();
}
- if (p_args[1]->get_type() != Variant::STRING) {
+ if (p_args[1]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
r_error.expected = Variant::STRING;
@@ -809,30 +842,33 @@ bool Node::can_process_notification(int p_what) const {
bool Node::can_process() const {
ERR_FAIL_COND_V(!is_inside_tree(), false);
+ return _can_process(get_tree()->is_paused());
+}
- if (get_tree()->is_paused()) {
- if (data.pause_mode == PAUSE_MODE_STOP) {
- return false;
- }
- if (data.pause_mode == PAUSE_MODE_PROCESS) {
- return true;
- }
- if (data.pause_mode == PAUSE_MODE_INHERIT) {
- if (!data.pause_owner) {
- return false; //clearly no pause owner by default
- }
-
- if (data.pause_owner->data.pause_mode == PAUSE_MODE_PROCESS) {
- return true;
- }
+bool Node::_can_process(bool p_paused) const {
+ ProcessMode process_mode;
- if (data.pause_owner->data.pause_mode == PAUSE_MODE_STOP) {
- return false;
- }
+ if (data.process_mode == PROCESS_MODE_INHERIT) {
+ if (!data.process_owner) {
+ process_mode = PROCESS_MODE_PAUSABLE;
+ } else {
+ process_mode = data.process_owner->data.process_mode;
}
+ } else {
+ process_mode = data.process_mode;
}
- return true;
+ if (process_mode == PROCESS_MODE_DISABLED) {
+ return false;
+ } else if (process_mode == PROCESS_MODE_ALWAYS) {
+ return true;
+ }
+
+ if (p_paused) {
+ return process_mode == PROCESS_MODE_WHEN_PAUSED;
+ } else {
+ return process_mode == PROCESS_MODE_PAUSABLE;
+ }
}
float Node::get_physics_process_delta_time() const {
@@ -863,8 +899,6 @@ void Node::set_process(bool p_process) {
} else {
remove_from_group("process");
}
-
- _change_notify("process");
}
bool Node::is_processing() const {
@@ -883,8 +917,6 @@ void Node::set_process_internal(bool p_process_internal) {
} else {
remove_from_group("process_internal");
}
-
- _change_notify("process_internal");
}
bool Node::is_processing_internal() const {
@@ -989,22 +1021,8 @@ void Node::_set_name_nocheck(const StringName &p_name) {
data.name = p_name;
}
-String Node::invalid_character = ". : @ / \"";
-
-bool Node::_validate_node_name(String &p_name) {
- String name = p_name;
- Vector<String> chars = Node::invalid_character.split(" ");
- for (int i = 0; i < chars.size(); i++) {
- name = name.replace(chars[i], "");
- }
- bool is_valid = name == p_name;
- p_name = name;
- return is_valid;
-}
-
void Node::set_name(const String &p_name) {
- String name = p_name;
- _validate_node_name(name);
+ String name = p_name.validate_node_name();
ERR_FAIL_COND(name == "");
data.name = name;
@@ -1112,11 +1130,11 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new nade is needed, create one.
+ //no name and a new name is needed, create one.
name = p_child->get_class();
// Adjust casing according to project setting. The current type name is expected to be in PascalCase.
- switch (ProjectSettings::get_singleton()->get("node/name_casing").operator int()) {
+ switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
case NAME_CASING_PASCAL_CASE:
break;
case NAME_CASING_CAMEL_CASE: {
@@ -1138,7 +1156,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
bool exists = false;
for (int i = 0; i < cc; i++) {
- if (children_ptr[i] == p_child) { //exclude self in renaming if its already a child
+ if (children_ptr[i] == p_child) { //exclude self in renaming if it's already a child
continue;
}
if (children_ptr[i]->data.name == name) {
@@ -1410,7 +1428,15 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
- ERR_FAIL_COND_V_MSG(!node, nullptr, "Node not found: " + p_path + ".");
+
+ if (p_path.is_absolute()) {
+ ERR_FAIL_COND_V_MSG(!node, nullptr,
+ vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path()));
+ } else {
+ ERR_FAIL_COND_V_MSG(!node, nullptr,
+ vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path()));
+ }
+
return node;
}
@@ -1664,7 +1690,7 @@ NodePath Node::get_path_to(const Node *p_node) const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
return NodePath(path, false);
}
@@ -1685,7 +1711,7 @@ NodePath Node::get_path() const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
data.path_cache = memnew(NodePath(path, true));
@@ -1906,15 +1932,11 @@ String Node::get_filename() const {
}
void Node::set_editor_description(const String &p_editor_description) {
- set_meta("_editor_description_", p_editor_description);
+ data.editor_description = p_editor_description;
}
String Node::get_editor_description() const {
- if (has_meta("_editor_description_")) {
- return get_meta("_editor_description_");
- } else {
- return "";
- }
+ return data.editor_description;
}
void Node::set_editable_instance(Node *p_node, bool p_editable) {
@@ -1923,7 +1945,7 @@ void Node::set_editable_instance(Node *p_node, bool p_editable) {
if (!p_editable) {
p_node->data.editable_instance = false;
// Avoid this flag being needlessly saved;
- // also give more visual feedback if editable children is re-enabled
+ // also give more visual feedback if editable children are re-enabled
set_display_folded(false);
} else {
p_node->data.editable_instance = true;
@@ -1938,6 +1960,24 @@ bool Node::is_editable_instance(const Node *p_node) const {
return p_node->data.editable_instance;
}
+Node *Node::get_deepest_editable_node(Node *p_start_node) const {
+ ERR_FAIL_NULL_V(p_start_node, nullptr);
+ ERR_FAIL_COND_V(!is_a_parent_of(p_start_node), p_start_node);
+
+ Node const *iterated_item = p_start_node;
+ Node *node = p_start_node;
+
+ while (iterated_item->get_owner() && iterated_item->get_owner() != this) {
+ if (!is_editable_instance(iterated_item->get_owner())) {
+ node = iterated_item->get_owner();
+ }
+
+ iterated_item = iterated_item->get_owner();
+ }
+
+ return node;
+}
+
void Node::set_scene_instance_state(const Ref<SceneState> &p_state) {
data.instance_state = p_state;
}
@@ -1999,6 +2039,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (get_filename() != "") { //an instance
node->set_filename(get_filename());
+ node->data.editable_instance = data.editable_instance;
}
StringName script_property_name = CoreStringNames::get_singleton()->_script;
@@ -2011,19 +2052,26 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
// Since nodes in the instanced hierarchy won't be duplicated explicitly, we need to make an inventory
// of all the nodes in the tree of the instanced scene in order to transfer the values of the properties
+ Vector<const Node *> instance_roots;
+ instance_roots.push_back(this);
+
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
for (int i = 0; i < N->get()->get_child_count(); ++i) {
Node *descendant = N->get()->get_child(i);
// Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
// but remember non-instanced nodes that are hidden below instanced ones
- if (descendant->data.owner != this) {
- if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this && descendant->data.owner != descendant->get_parent()) {
+ if (!instance_roots.has(descendant->get_owner())) {
+ if (descendant->get_parent() && descendant->get_parent() != this && descendant->data.owner != descendant->get_parent()) {
hidden_roots.push_back(descendant);
}
continue;
}
node_tree.push_back(descendant);
+
+ if (descendant->get_filename() != "" && instance_roots.has(descendant->get_owner())) {
+ instance_roots.push_back(descendant);
+ }
}
}
}
@@ -2146,8 +2194,17 @@ Node *Node::duplicate(int p_flags) const {
#ifdef TOOLS_ENABLED
Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
+ return duplicate_from_editor(r_duplimap, Map<RES, RES>());
+}
+
+Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const {
Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap);
+ // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
+ if (!p_resource_remap.is_empty()) {
+ remap_node_resources(dupe, p_resource_remap);
+ }
+
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
@@ -2155,75 +2212,55 @@ Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const {
return dupe;
}
-#endif
-
-void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const {
- if (get_owner() != get_parent()->get_owner()) {
- return;
- }
-
- Node *node = nullptr;
-
- if (get_filename() != "") {
- Ref<PackedScene> res = ResourceLoader::load(get_filename());
- ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename());
- node = res->instance();
- ERR_FAIL_COND(!node);
- } else {
- Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_MSG(!obj, "Node: Could not duplicate: " + String(get_class()) + ".");
- node = Object::cast_to<Node>(obj);
- if (!node) {
- memdelete(obj);
- ERR_FAIL_MSG("Node: Could not duplicate: " + String(get_class()) + ".");
- }
- }
- List<PropertyInfo> plist;
+void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_node->get_property_list(&props);
- get_property_list(&plist);
-
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
}
- String name = E->get().name;
-
- Variant value = get(name).duplicate(true);
- node->set(name, value);
+ Variant v = p_node->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_node->set(E->get().name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
+ }
+ }
}
- List<GroupInfo> groups;
- get_groups(&groups);
-
- for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) {
- node->add_to_group(E->get().name, E->get().persistent);
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ remap_node_resources(p_node->get_child(i), p_resource_remap);
}
+}
- node->set_name(get_name());
- p_new_parent->add_child(node);
-
- Node *owner = get_owner();
+void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const {
+ List<PropertyInfo> props;
+ p_resource->get_property_list(&props);
- if (p_reown_map.has(owner)) {
- owner = p_reown_map[owner];
- }
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
- if (owner) {
- NodePath p = get_path_to(owner);
- if (owner != this) {
- Node *new_owner = node->get_node(p);
- if (new_owner) {
- node->set_owner(new_owner);
+ Variant v = p_resource->get(E->get().name);
+ if (v.is_ref()) {
+ RES res = v;
+ if (res.is_valid()) {
+ if (p_resource_remap.has(res)) {
+ p_resource->set(E->get().name, p_resource_remap[res]);
+ remap_nested_resources(res, p_resource_remap);
+ }
}
}
}
-
- for (int i = 0; i < get_child_count(); i++) {
- get_child(i)->_duplicate_and_reown(node, p_reown_map);
- }
}
+#endif
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
@@ -2279,49 +2316,6 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
}
}
-Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const {
- ERR_FAIL_COND_V(get_filename() != "", nullptr);
-
- Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V_MSG(!obj, nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
-
- Node *node = Object::cast_to<Node>(obj);
- if (!node) {
- memdelete(obj);
- ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
- }
- node->set_name(get_name());
-
- List<PropertyInfo> plist;
-
- get_property_list(&plist);
-
- for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
- String name = E->get().name;
- node->set(name, get(name));
- }
-
- List<GroupInfo> groups;
- get_groups(&groups);
-
- for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) {
- node->add_to_group(E->get().name, E->get().persistent);
- }
-
- for (int i = 0; i < get_child_count(); i++) {
- get_child(i)->_duplicate_and_reown(node, p_reown_map);
- }
-
- // Duplication of signals must happen after all the node descendants have been copied,
- // because re-targeting of connections from some descendant to another is not possible
- // if the emitter node comes later in tree order than the receiver
- _duplicate_signals(this, node);
- return node;
-}
-
static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) {
if (p_node->get_owner() == p_by) {
p_owned->push_back(p_node);
@@ -2640,15 +2634,27 @@ void Node::clear_internal_tree_resource_paths() {
}
}
-String Node::get_configuration_warning() const {
+TypedArray<String> Node::get_configuration_warnings() const {
if (get_script_instance() && get_script_instance()->get_script().is_valid() &&
- get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warning")) {
- return get_script_instance()->call("_get_configuration_warning");
+ get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) {
+ return get_script_instance()->call("_get_configuration_warnings");
}
- return String();
+ return Array();
}
-void Node::update_configuration_warning() {
+String Node::get_configuration_warnings_as_string() const {
+ TypedArray<String> warnings = get_configuration_warnings();
+ String all_warnings = String();
+ for (int i = 0; i < warnings.size(); i++) {
+ if (i > 0) {
+ all_warnings += "\n\n";
+ }
+ all_warnings += String(warnings[i]);
+ }
+ return all_warnings;
+}
+
+void Node::update_configuration_warnings() {
#ifdef TOOLS_ENABLED
if (!is_inside_tree()) {
return;
@@ -2676,10 +2682,10 @@ void Node::request_ready() {
}
void Node::_bind_methods() {
- GLOBAL_DEF("node/name_num_separator", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("node/name_num_separator", PropertyInfo(Variant::INT, "node/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"));
- GLOBAL_DEF("node/name_casing", NAME_CASING_PASCAL_CASE);
- ProjectSettings::get_singleton()->set_custom_property_info("node/name_casing", PropertyInfo(Variant::INT, "node/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
+ GLOBAL_DEF("editor/node_naming/name_num_separator", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_num_separator", PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"));
+ GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE);
+ ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case"));
ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false));
@@ -2734,8 +2740,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_processing_unhandled_input"), &Node::is_processing_unhandled_input);
ClassDB::bind_method(D_METHOD("set_process_unhandled_key_input", "enable"), &Node::set_process_unhandled_key_input);
ClassDB::bind_method(D_METHOD("is_processing_unhandled_key_input"), &Node::is_processing_unhandled_key_input);
- ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Node::set_pause_mode);
- ClassDB::bind_method(D_METHOD("get_pause_mode"), &Node::get_pause_mode);
+ ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Node::set_process_mode);
+ ClassDB::bind_method(D_METHOD("get_process_mode"), &Node::get_process_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
@@ -2773,12 +2779,12 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config);
ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
- ClassDB::bind_method(D_METHOD("_set_editor_description", "editor_description"), &Node::set_editor_description);
- ClassDB::bind_method(D_METHOD("_get_editor_description"), &Node::get_editor_description);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_editor_description", "_get_editor_description");
+ ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description);
+ ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description);
ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path);
ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path);
+
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
{
@@ -2804,7 +2810,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
- ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning);
+ ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_TREE);
@@ -2842,9 +2848,11 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT);
BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED);
- BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT);
- BIND_ENUM_CONSTANT(PAUSE_MODE_STOP);
- BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_PAUSABLE);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_WHEN_PAUSED);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(PROCESS_MODE_DISABLED);
BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS);
BIND_ENUM_CONSTANT(DUPLICATE_GROUPS);
@@ -2857,15 +2865,19 @@ void Node::_bind_methods() {
ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
-
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
+
+ ADD_GROUP("Process", "process_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,WhenPaused,Always,Disabled"), "set_process_mode", "get_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority");
+ ADD_GROUP("Editor Description", "editor_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "set_editor_description", "get_editor_description");
+
BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "delta")));
BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::FLOAT, "delta")));
BIND_VMETHOD(MethodInfo("_enter_tree"));
@@ -2874,11 +2886,11 @@ void Node::_bind_methods() {
BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning"));
+ BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings"));
}
String Node::_get_name_num_separator() {
- switch (ProjectSettings::get_singleton()->get("node/name_num_separator").operator int()) {
+ switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_num_separator").operator int()) {
case 0:
return "";
case 1:
diff --git a/scene/main/node.h b/scene/main/node.h
index a0dca75791..6ca2317d9e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -46,10 +46,12 @@ class Node : public Object {
OBJ_CATEGORY("Nodes");
public:
- enum PauseMode {
- PAUSE_MODE_INHERIT,
- PAUSE_MODE_STOP,
- PAUSE_MODE_PROCESS
+ enum ProcessMode {
+ PROCESS_MODE_INHERIT, // same as parent node
+ PROCESS_MODE_PAUSABLE, // process only if not paused
+ PROCESS_MODE_WHEN_PAUSED, // process only if paused
+ PROCESS_MODE_ALWAYS, // process always
+ PROCESS_MODE_DISABLED, // never process
};
enum DuplicateFlags {
@@ -80,7 +82,7 @@ private:
struct NetData {
StringName name;
- MultiplayerAPI::RPCMode mode;
+ MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED;
};
struct Data {
@@ -102,6 +104,7 @@ private:
#ifdef TOOLS_ENABLED
NodePath import_path; // Path used when imported, used by scene editors to keep tracking.
#endif
+ String editor_description;
Viewport *viewport = nullptr;
@@ -109,8 +112,8 @@ private:
List<Node *>::Element *OW = nullptr; // Owned element.
List<Node *> owned;
- PauseMode pause_mode = PAUSE_MODE_INHERIT;
- Node *pause_owner = nullptr;
+ ProcessMode process_mode = PROCESS_MODE_INHERIT;
+ Node *process_owner = nullptr;
int network_master = 1; // Server by default.
Vector<NetData> rpc_methods;
@@ -166,11 +169,10 @@ private:
void _propagate_after_exit_tree();
void _propagate_validate_owner();
void _print_stray_nodes();
- void _propagate_pause_owner(Node *p_owner);
+ void _propagate_process_owner(Node *p_owner, int p_notification);
Array _get_node_and_resource(const NodePath &p_path);
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
- void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;
TypedArray<Node> _get_children() const;
@@ -184,12 +186,9 @@ private:
friend class SceneTree;
void _set_tree(SceneTree *p_tree);
+ void _propagate_pause_notification(bool p_enable);
-#ifdef TOOLS_ENABLED
- friend class SceneTreeEditor;
-#endif
- static String invalid_character;
- static bool _validate_node_name(String &p_name);
+ _FORCE_INLINE_ bool _can_process(bool p_paused) const;
protected:
void _block() { data.blocked++; }
@@ -297,7 +296,7 @@ public:
struct GroupInfo {
StringName name;
- bool persistent;
+ bool persistent = false;
};
void get_groups(List<GroupInfo> *p_groups) const;
@@ -324,6 +323,7 @@ public:
void set_editable_instance(Node *p_node, bool p_editable);
bool is_editable_instance(const Node *p_node) const;
+ Node *get_deepest_editable_node(Node *p_start_node) const;
/* NOTIFICATIONS */
@@ -359,9 +359,11 @@ public:
bool is_processing_unhandled_key_input() const;
Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const;
- Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const;
#ifdef TOOLS_ENABLED
Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const;
+ Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const;
+ void remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const;
+ void remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const;
#endif
// used by editors, to save what has changed only
@@ -378,8 +380,8 @@ public:
void replace_by(Node *p_node, bool p_keep_data = false);
- void set_pause_mode(PauseMode p_mode);
- PauseMode get_pause_mode() const;
+ void set_process_mode(ProcessMode p_mode);
+ ProcessMode get_process_mode() const;
bool can_process() const;
bool can_process_notification(int p_what) const;
@@ -410,9 +412,10 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
- virtual String get_configuration_warning() const;
+ virtual TypedArray<String> get_configuration_warnings() const;
+ String get_configuration_warnings_as_string() const;
- void update_configuration_warning();
+ void update_configuration_warnings();
void set_display_folded(bool p_folded);
bool is_displayed_folded() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 4f1143b201..387af3703b 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -54,6 +54,7 @@
#include "window.h"
#include <stdio.h>
+#include <stdlib.h>
void SceneTreeTimer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
@@ -72,12 +73,12 @@ float SceneTreeTimer::get_time_left() const {
return time_left;
}
-void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) {
- process_pause = p_pause_mode_process;
+void SceneTreeTimer::set_process_always(bool p_process_always) {
+ process_always = p_process_always;
}
-bool SceneTreeTimer::is_pause_mode_process() {
- return process_pause;
+bool SceneTreeTimer::is_process_always() {
+ return process_always;
}
void SceneTreeTimer::release_connections() {
@@ -90,10 +91,7 @@ void SceneTreeTimer::release_connections() {
}
}
-SceneTreeTimer::SceneTreeTimer() {
- time_left = 0;
- process_pause = true;
-}
+SceneTreeTimer::SceneTreeTimer() {}
void SceneTree::tree_changed() {
tree_version++;
@@ -391,6 +389,7 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
}
void SceneTree::initialize() {
+ ERR_FAIL_COND(!root);
initialized = true;
root->_set_tree(this);
MainLoop::initialize();
@@ -458,7 +457,7 @@ bool SceneTree::process(float p_time) {
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
List<Ref<SceneTreeTimer>>::Element *N = E->next();
- if (pause && !E->get()->is_pause_mode_process()) {
+ if (paused && !E->get()->is_process_always()) {
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
}
@@ -487,7 +486,7 @@ bool SceneTree::process(float p_time) {
if (Engine::get_singleton()->is_editor_hint()) {
//simple hack to reload fallback environment if it changed from editor
- String env_path = ProjectSettings::get_singleton()->get("rendering/environment/default_environment");
+ String env_path = ProjectSettings::get_singleton()->get("rendering/environment/defaults/default_environment");
env_path = env_path.strip_edges(); //user may have added a space or two
String cpath;
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
@@ -499,7 +498,7 @@ bool SceneTree::process(float p_time) {
fallback = ResourceLoader::load(env_path);
if (fallback.is_null()) {
//could not load fallback, set as empty
- ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
+ ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
} else {
fallback.unref();
@@ -537,12 +536,7 @@ void SceneTree::finalize() {
}
void SceneTree::quit(int p_exit_code) {
- if (p_exit_code >= 0) {
- // Override the exit code if a positive argument is given (the default is `-1`).
- // This is a shorthand for calling `set_exit_code()` on the OS singleton then quitting.
- OS::get_singleton()->set_exit_code(p_exit_code);
- }
-
+ OS::get_singleton()->set_exit_code(p_exit_code);
_quit = true;
}
@@ -762,20 +756,20 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
}
void SceneTree::set_pause(bool p_enabled) {
- if (p_enabled == pause) {
+ if (p_enabled == paused) {
return;
}
- pause = p_enabled;
+ paused = p_enabled;
NavigationServer3D::get_singleton()->set_active(!p_enabled);
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
PhysicsServer2D::get_singleton()->set_active(!p_enabled);
if (get_root()) {
- get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED);
+ get_root()->_propagate_pause_notification(p_enabled);
}
}
bool SceneTree::is_paused() const {
- return pause;
+ return paused;
}
void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
@@ -959,6 +953,21 @@ bool SceneTree::has_group(const StringName &p_identifier) const {
return group_map.has(p_identifier);
}
+Node *SceneTree::get_first_node_in_group(const StringName &p_group) {
+ Map<StringName, Group>::Element *E = group_map.find(p_group);
+ if (!E) {
+ return nullptr; //no group
+ }
+
+ _update_group_order(E->get()); //update order just in case
+
+ if (E->get().nodes.size() == 0) {
+ return nullptr;
+ }
+
+ return E->get().nodes[0];
+}
+
void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_list) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E) {
@@ -1073,10 +1082,10 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
+Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_always) {
Ref<SceneTreeTimer> stt;
stt.instance();
- stt->set_pause_mode_process(p_process_pause);
+ stt->set_process_always(p_process_always);
stt->set_time_left(p_delay_sec);
timers.push_back(stt);
return stt;
@@ -1189,11 +1198,11 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
- ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count);
ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame);
- ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(EXIT_SUCCESS));
ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete);
@@ -1219,6 +1228,7 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_group", "group", "property", "value"), &SceneTree::set_group);
ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group);
+ ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group);
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
@@ -1257,6 +1267,7 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled");
ADD_SIGNAL(MethodInfo("tree_changed"));
+ ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it cant be removed in run-time
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
@@ -1329,13 +1340,17 @@ SceneTree::SceneTree() {
if (singleton == nullptr) {
singleton = this;
}
- debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.5));
+ debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42));
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
+ GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+
+ Math::randomize();
+
// Create with mainloop.
root = memnew(Window);
@@ -1352,39 +1367,42 @@ SceneTree::SceneTree() {
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
- const int msaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"));
+ const int msaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/msaa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"));
root->set_msaa(Viewport::MSAA(msaa_mode));
- const int ssaa_mode = GLOBAL_DEF("rendering/quality/screen_filters/screen_space_aa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_aa", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
+ const int ssaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/screen_space_aa", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
- const bool use_debanding = GLOBAL_DEF("rendering/quality/screen_filters/use_debanding", false);
+ const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false);
root->set_use_debanding(use_debanding);
- float lod_threshold = GLOBAL_DEF("rendering/quality/mesh_lod/threshold_pixels", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/mesh_lod/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/quality/mesh_lod/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
+ const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false);
+ root->set_use_occlusion_culling(use_occlusion_culling);
+
+ float lod_threshold = GLOBAL_DEF("rendering/mesh_lod/lod_change/threshold_pixels", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/mesh_lod/lod_change/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/mesh_lod/lod_change/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
root->set_lod_threshold(lod_threshold);
- bool snap_2d_transforms = GLOBAL_DEF("rendering/quality/2d/snap_2d_transforms_to_pixel", false);
+ bool snap_2d_transforms = GLOBAL_DEF("rendering/2d/snap/snap_2d_transforms_to_pixel", false);
root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
- bool snap_2d_vertices = GLOBAL_DEF("rendering/quality/2d/snap_2d_vertices_to_pixel", false);
+ bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false);
root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
- int shadowmap_size = GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384"));
- GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048);
- bool shadowmap_16_bits = GLOBAL_DEF("rendering/quality/shadow_atlas/16_bits", true);
- int atlas_q0 = GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_0_subdiv", 2);
- int atlas_q1 = GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2);
- int atlas_q2 = GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3);
- int atlas_q3 = GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_3_subdiv", 4);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ int shadowmap_size = GLOBAL_DEF("rendering/shadows/shadow_atlas/size", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384"));
+ GLOBAL_DEF("rendering/shadows/shadow_atlas/size.mobile", 2048);
+ bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/shadow_atlas/16_bits", true);
+ int atlas_q0 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_0_subdiv", 2);
+ int atlas_q1 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_1_subdiv", 2);
+ int atlas_q2 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_2_subdiv", 3);
+ int atlas_q3 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_3_subdiv", 4);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
root->set_shadow_atlas_size(shadowmap_size);
root->set_shadow_atlas_16_bits(shadowmap_16_bits);
@@ -1393,13 +1411,13 @@ SceneTree::SceneTree() {
root->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
root->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
- Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/quality/2d_sdf/oversize", 1)));
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/2d/sdf/oversize", 1)));
root->set_sdf_oversize(sdf_oversize);
- Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/quality/2d_sdf/scale", 1)));
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/2d/sdf/scale", 1)));
root->set_sdf_scale(sdf_scale);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/oversize", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/scale", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/oversize", PropertyInfo(Variant::INT, "rendering/2d/sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/scale", PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"));
{ // Load default fallback environment.
// Get possible extensions.
@@ -1413,9 +1431,9 @@ SceneTree::SceneTree() {
ext_hint += "*." + E->get();
}
// Get path.
- String env_path = GLOBAL_DEF("rendering/environment/default_environment", "");
+ String env_path = GLOBAL_DEF("rendering/environment/defaults/default_environment", "");
// Setup property.
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/defaults/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint));
env_path = env_path.strip_edges();
if (env_path != String()) {
Ref<Environment> env = ResourceLoader::load(env_path);
@@ -1424,7 +1442,7 @@ SceneTree::SceneTree() {
} else {
if (Engine::get_singleton()->is_editor_hint()) {
// File was erased, clear the field.
- ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
+ ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
} else {
// File was erased, notify user.
ERR_PRINT(RTR("Default Environment as specified in Project Settings (Rendering -> Environment -> Default Environment) could not be loaded."));
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 748908c8a6..a2f2adb8f8 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -51,8 +51,8 @@ class SceneDebugger;
class SceneTreeTimer : public Reference {
GDCLASS(SceneTreeTimer, Reference);
- float time_left;
- bool process_pause;
+ float time_left = 0.0;
+ bool process_always = true;
protected:
static void _bind_methods();
@@ -61,8 +61,8 @@ public:
void set_time_left(float p_time);
float get_time_left() const;
- void set_pause_mode_process(bool p_pause_mode_process);
- bool is_pause_mode_process();
+ void set_process_always(bool p_process_always);
+ bool is_process_always();
void release_connections();
@@ -80,8 +80,7 @@ public:
private:
struct Group {
Vector<Node *> nodes;
- bool changed;
- Group() { changed = false; };
+ bool changed = false;
};
Window *root = nullptr;
@@ -96,7 +95,7 @@ private:
bool debug_collisions_hint = false;
bool debug_navigation_hint = false;
#endif
- bool pause = false;
+ bool paused = false;
int root_lock = 0;
Map<StringName, Group> group_map;
@@ -246,7 +245,7 @@ public:
void set_auto_accept_quit(bool p_enable);
void set_quit_on_go_back(bool p_enable);
- void quit(int p_exit_code = -1);
+ void quit(int p_exit_code = EXIT_SUCCESS);
_FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; }
_FORCE_INLINE_ float get_process_time() const { return process_time; }
@@ -303,6 +302,7 @@ public:
void queue_delete(Object *p_object);
void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list);
+ Node *get_first_node_in_group(const StringName &p_group);
bool has_group(const StringName &p_identifier) const;
//void change_scene(const String& p_path);
@@ -317,7 +317,7 @@ public:
Error change_scene_to(const Ref<PackedScene> &p_scene);
Error reload_current_scene();
- Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_pause = true);
+ Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_always = true);
//used by Main::start, don't use otherwise
void add_current_scene(Node *p_current);
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 4485cffff5..cb3b2cb392 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -232,7 +232,7 @@ void ShaderGlobalsOverride::_activate() {
}
}
- update_configuration_warning(); //may have activated
+ update_configuration_warnings(); //may have activated
}
}
@@ -260,23 +260,18 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-String ShaderGlobalsOverride::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!active) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
+ warnings.push_back(TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
}
- return warning;
+ return warnings;
}
void ShaderGlobalsOverride::_bind_methods() {
ClassDB::bind_method(D_METHOD("_activate"), &ShaderGlobalsOverride::_activate);
}
-ShaderGlobalsOverride::ShaderGlobalsOverride() {
- active = false;
-}
+ShaderGlobalsOverride::ShaderGlobalsOverride() {}
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index 9e666a0ec5..2d9c3c76bd 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -43,7 +43,7 @@ class ShaderGlobalsOverride : public Node {
StringName *_remap(const StringName &p_name) const;
- bool active;
+ bool active = false;
mutable HashMap<StringName, Override> overrides;
mutable HashMap<StringName, StringName> param_remaps;
@@ -58,7 +58,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index d7b2292ff5..4bc159f6aa 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -46,7 +46,7 @@ void Timer::_notification(int p_what) {
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- if (!processing || timer_process_mode == TIMER_PROCESS_PHYSICS || !is_processing_internal()) {
+ if (!processing || timer_process_callback == TIMER_PROCESS_PHYSICS || !is_processing_internal()) {
return;
}
time_left -= get_process_delta_time();
@@ -63,7 +63,7 @@ void Timer::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (!processing || timer_process_mode == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) {
+ if (!processing || timer_process_callback == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) {
return;
}
time_left -= get_physics_process_delta_time();
@@ -143,12 +143,12 @@ float Timer::get_time_left() const {
return time_left > 0 ? time_left : 0;
}
-void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
- if (timer_process_mode == p_mode) {
+void Timer::set_timer_process_callback(TimerProcessCallback p_callback) {
+ if (timer_process_callback == p_callback) {
return;
}
- switch (timer_process_mode) {
+ switch (timer_process_callback) {
case TIMER_PROCESS_PHYSICS:
if (is_physics_processing_internal()) {
set_physics_process_internal(false);
@@ -162,15 +162,15 @@ void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
}
break;
}
- timer_process_mode = p_mode;
+ timer_process_callback = p_callback;
}
-Timer::TimerProcessMode Timer::get_timer_process_mode() const {
- return timer_process_mode;
+Timer::TimerProcessCallback Timer::get_timer_process_callback() const {
+ return timer_process_callback;
}
void Timer::_set_process(bool p_process, bool p_force) {
- switch (timer_process_mode) {
+ switch (timer_process_callback) {
case TIMER_PROCESS_PHYSICS:
set_physics_process_internal(p_process && !paused);
break;
@@ -201,12 +201,12 @@ void Timer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left);
- ClassDB::bind_method(D_METHOD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
- ClassDB::bind_method(D_METHOD("get_timer_process_mode"), &Timer::get_timer_process_mode);
+ ClassDB::bind_method(D_METHOD("set_timer_process_callback", "callback"), &Timer::set_timer_process_callback);
+ ClassDB::bind_method(D_METHOD("get_timer_process_callback"), &Timer::get_timer_process_callback);
ADD_SIGNAL(MethodInfo("timeout"));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_mode", "get_timer_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
@@ -217,12 +217,4 @@ void Timer::_bind_methods() {
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
}
-Timer::Timer() {
- timer_process_mode = TIMER_PROCESS_IDLE;
- autostart = false;
- wait_time = 1;
- one_shot = false;
- time_left = -1;
- processing = false;
- paused = false;
-}
+Timer::Timer() {}
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 0604a2d990..3d9e21d7fc 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -36,20 +36,20 @@
class Timer : public Node {
GDCLASS(Timer, Node);
- float wait_time;
- bool one_shot;
- bool autostart;
- bool processing;
- bool paused;
+ float wait_time = 1.0;
+ bool one_shot = false;
+ bool autostart = false;
+ bool processing = false;
+ bool paused = false;
- double time_left;
+ double time_left = -1.0;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- enum TimerProcessMode {
+ enum TimerProcessCallback {
TIMER_PROCESS_PHYSICS,
TIMER_PROCESS_IDLE,
};
@@ -73,15 +73,15 @@ public:
float get_time_left() const;
- void set_timer_process_mode(TimerProcessMode p_mode);
- TimerProcessMode get_timer_process_mode() const;
+ void set_timer_process_callback(TimerProcessCallback p_callback);
+ TimerProcessCallback get_timer_process_callback() const;
Timer();
private:
- TimerProcessMode timer_process_mode;
+ TimerProcessCallback timer_process_callback = TIMER_PROCESS_IDLE;
void _set_process(bool p_process, bool p_force = false);
};
-VARIANT_ENUM_CAST(Timer::TimerProcessMode);
+VARIANT_ENUM_CAST(Timer::TimerProcessCallback);
#endif // TIMER_H
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 0ba8264f2a..90f556cf1b 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -131,7 +131,7 @@ bool ViewportTexture::has_alpha() const {
return false;
}
-Ref<Image> ViewportTexture::get_data() const {
+Ref<Image> ViewportTexture::get_image() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
@@ -144,7 +144,6 @@ void ViewportTexture::_bind_methods() {
}
ViewportTexture::ViewportTexture() {
- vp = nullptr;
set_local_to_scene(true);
}
@@ -184,26 +183,6 @@ public:
/////////////////////////////////////
-Viewport::GUI::GUI() {
- embed_subwindows_hint = false;
- embedding_subwindows = false;
-
- dragging = false;
- mouse_focus = nullptr;
- forced_mouse_focus = false;
- mouse_click_grabber = nullptr;
- mouse_focus_mask = 0;
- key_focus = nullptr;
- mouse_over = nullptr;
- drag_mouse_over = nullptr;
-
- tooltip_control = nullptr;
- tooltip_popup = nullptr;
- tooltip_label = nullptr;
-}
-
-/////////////////////////////////////
-
void Viewport::update_worlds() {
if (!is_inside_tree()) {
return;
@@ -299,6 +278,11 @@ void Viewport::_sub_window_update(Window *p_window) {
int x = (r.size.width - title_text.get_size().x) / 2;
int y = (-title_height - title_text.get_size().y) / 2;
+ Color font_outline_color = p_window->get_theme_color("title_outline_modulate");
+ int outline_size = p_window->get_theme_constant("title_outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color);
+ }
title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color);
bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
@@ -468,7 +452,7 @@ void Viewport::_notification(int p_what) {
//3D
PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count());
contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create();
- RenderingServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
+ RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true);
RenderingServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
RenderingServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
contact_3d_debug_instance = RenderingServer::get_singleton()->instance_create();
@@ -567,6 +551,12 @@ void Viewport::_notification(int p_what) {
int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space());
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
+
+ for (int i = 0; i < point_count; i++) {
+ Transform point_transform;
+ point_transform.origin = points[i];
+ RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
+ }
}
} break;
case NOTIFICATION_WM_MOUSE_EXIT: {
@@ -1173,7 +1163,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (p_world_2d.is_valid()) {
world_2d = p_world_2d;
} else {
- WARN_PRINT("Invalid world_3d");
+ WARN_PRINT("Invalid world_2d");
world_2d = Ref<World2D>(memnew(World2D));
}
@@ -1422,6 +1412,16 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
}
+void Viewport::set_use_xr(bool p_use_xr) {
+ use_xr = p_use_xr;
+
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+}
+
+bool Viewport::is_using_xr() {
+ return use_xr;
+}
+
Ref<ViewportTexture> Viewport::get_texture() const {
return default_texture;
}
@@ -1631,10 +1631,10 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Ref<InputEventMouseButton> mb = p_input;
bool cant_stop_me_now = (mb.is_valid() &&
- (mb->get_button_index() == BUTTON_WHEEL_DOWN ||
- mb->get_button_index() == BUTTON_WHEEL_UP ||
- mb->get_button_index() == BUTTON_WHEEL_LEFT ||
- mb->get_button_index() == BUTTON_WHEEL_RIGHT));
+ (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT));
Ref<InputEventPanGesture> pn = p_input;
cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
@@ -1780,19 +1780,22 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
}
}
- if (!c) {
+ if (!c || c->data.mouse_filter == Control::MOUSE_FILTER_IGNORE) {
return nullptr;
}
matrix.affine_invert();
+ if (!c->has_point(matrix.xform(p_global))) {
+ return nullptr;
+ }
- //conditions for considering this as a valid control for return
- if (c->data.mouse_filter != Control::MOUSE_FILTER_IGNORE && c->has_point(matrix.xform(p_global)) && (!gui.drag_preview || (c != gui.drag_preview && !gui.drag_preview->is_a_parent_of(c)))) {
+ Control *drag_preview = _gui_get_drag_preview();
+ if (!drag_preview || (c != drag_preview && !drag_preview->is_a_parent_of(c))) {
r_inv_xform = matrix;
return c;
- } else {
- return nullptr;
}
+
+ return nullptr;
}
bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
@@ -1867,7 +1870,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
gui.drag_accum = Vector2();
gui.drag_attempted = false;
}
@@ -1890,7 +1893,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
#endif
- if (mb->get_button_index() == BUTTON_LEFT) { //assign focus
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { //assign focus
CanvasItem *ci = gui.mouse_focus;
while (ci) {
Control *control = Object::cast_to<Control>(ci);
@@ -1921,7 +1924,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
set_input_as_handled();
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
//alternate drop use (when using force_drag(), as proposed by #5342
if (gui.mouse_focus) {
_gui_drop(gui.mouse_focus, pos, false);
@@ -1930,9 +1933,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data = Variant();
gui.dragging = false;
- if (gui.drag_preview) {
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
@@ -1940,14 +1944,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_cancel_tooltip();
} else {
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (gui.drag_mouse_over) {
_gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);
}
- if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) {
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
gui.drag_data = Variant();
@@ -1983,7 +1988,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_call_input(mouse_focus, mb);
}
- /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) {
+ /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==MOUSE_BUTTON_LEFT) {
_propagate_viewport_notification(this,NOTIFICATION_DRAG_END);
gui.drag_data=Variant(); //always clear
}*/
@@ -2027,7 +2032,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
// D&D
- if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
gui.drag_accum += mm->get_relative();
float len = gui.drag_accum.length();
if (len > 10) {
@@ -2044,10 +2049,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask = 0;
break;
} else {
- if (gui.drag_preview != nullptr) {
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored.");
- memdelete(gui.drag_preview);
- gui.drag_preview = nullptr;
+ memdelete(drag_preview);
+ gui.drag_preview_id = ObjectID();
}
gui.dragging = false;
}
@@ -2187,8 +2193,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() != Variant::NIL) {
//handle dragandrop
- if (gui.drag_preview) {
- gui.drag_preview->set_position(mpos);
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ drag_preview->set_position(mpos);
}
gui.drag_mouse_over = over;
@@ -2204,7 +2211,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
embedder = this;
viewport_pos = mpos;
} else {
- //not an embeder, but may be a subwindow of an embedder
+ //not an embedder, but may be a subwindow of an embedder
Window *w = Object::cast_to<Window>(this);
if (w) {
if (w->is_embedded()) {
@@ -2269,7 +2276,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse();
gui.drag_mouse_over_pos = localizer.xform(viewport_pos);
- if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
if (!can_drop) {
@@ -2396,35 +2403,33 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//keyboard focus
//if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
Ref<InputEventKey> k = p_event;
- //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/righ/etc> is handled here when it shouldn't be.
+ //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be.
bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
if (from && p_event->is_pressed()) {
Control *next = nullptr;
- Input *input = Input::get_singleton();
-
- if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
+ if (p_event->is_action_pressed("ui_focus_next", true)) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
+ if (p_event->is_action_pressed("ui_focus_prev", true)) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
+ if (!mods && p_event->is_action_pressed("ui_up", true)) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
- if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
+ if (!mods && p_event->is_action_pressed("ui_left", true)) {
next = from->_get_focus_neighbor(SIDE_LEFT);
}
- if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
+ if (!mods && p_event->is_action_pressed("ui_right", true)) {
next = from->_get_focus_neighbor(SIDE_RIGHT);
}
- if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
+ if (!mods && p_event->is_action_pressed("ui_down", true)) {
next = from->_get_focus_neighbor(SIDE_BOTTOM);
}
@@ -2463,15 +2468,29 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
ERR_FAIL_COND(p_control->is_inside_tree());
ERR_FAIL_COND(p_control->get_parent() != nullptr);
- if (gui.drag_preview) {
- memdelete(gui.drag_preview);
+ Control *drag_preview = _gui_get_drag_preview();
+ if (drag_preview) {
+ memdelete(drag_preview);
}
p_control->set_as_top_level(true);
p_control->set_position(gui.last_mouse_pos);
p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport
p_control->raise();
- gui.drag_preview = p_control;
+ gui.drag_preview_id = p_control->get_instance_id();
+}
+
+Control *Viewport::_gui_get_drag_preview() {
+ if (gui.drag_preview_id.is_null()) {
+ return nullptr;
+ } else {
+ Control *drag_preview = Object::cast_to<Control>(ObjectDB::get_instance(gui.drag_preview_id));
+ if (!drag_preview) {
+ ERR_PRINT("Don't free the control set as drag preview.");
+ gui.drag_preview_id = ObjectID();
+ }
+ return drag_preview;
+ }
}
void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
@@ -2661,7 +2680,7 @@ void Viewport::_post_gui_grab_click_focus() {
Ref<InputEventMouseButton> mb;
mb.instance();
- //send unclic
+ //send unclick
mb->set_position(click);
mb->set_button_index(i + 1);
@@ -2679,7 +2698,7 @@ void Viewport::_post_gui_grab_click_focus() {
Ref<InputEventMouseButton> mb;
mb.instance();
- //send clic
+ //send click
mb->set_position(click);
mb->set_button_index(i + 1);
@@ -2772,7 +2791,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) {
//close window
@@ -2897,7 +2916,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
//if the event is a mouse button, we need to check whether another window was clicked
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool click_on_window = false;
for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
SubWindow &sw = gui.sub_windows.write[i];
@@ -3056,6 +3075,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
}
void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+ ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
if (disable_input || !_can_consume_input_events()) {
@@ -3165,20 +3185,17 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-String Viewport::get_configuration_warning() const {
+TypedArray<String> Viewport::get_configuration_warnings() const {
/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");
}*/
- String warning = Node::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (size.x == 0 || size.y == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Viewport size must be greater than 0 to render anything.");
+ warnings.push_back(TTR("Viewport size must be greater than 0 to render anything."));
}
- return warning;
+ return warnings;
}
void Viewport::gui_reset_canvas_sort_index() {
@@ -3216,8 +3233,9 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
}
void Viewport::set_use_debanding(bool p_use_debanding) {
- if (use_debanding == p_use_debanding)
+ if (use_debanding == p_use_debanding) {
return;
+ }
use_debanding = p_use_debanding;
RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding);
}
@@ -3234,6 +3252,21 @@ float Viewport::get_lod_threshold() const {
return lod_threshold;
}
+void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
+ if (use_occlusion_culling == p_use_occlusion_culling) {
+ return;
+ }
+
+ use_occlusion_culling = p_use_occlusion_culling;
+ RS::get_singleton()->viewport_set_use_occlusion_culling(viewport, p_use_occlusion_culling);
+
+ notify_property_list_changed();
+}
+
+bool Viewport::is_using_occlusion_culling() const {
+ return use_occlusion_culling;
+}
+
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
@@ -3323,9 +3356,6 @@ bool Viewport::is_handling_input_locally() const {
return handle_input_locally;
}
-void Viewport::_validate_property(PropertyInfo &property) const {
-}
-
void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
@@ -3470,11 +3500,17 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding);
ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding);
+ ClassDB::bind_method(D_METHOD("set_use_occlusion_culling", "enable"), &Viewport::set_use_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_using_occlusion_culling"), &Viewport::is_using_occlusion_culling);
+
ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
ClassDB::bind_method(D_METHOD("get_render_info", "info"), &Viewport::get_render_info);
+ ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
+ ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
+
ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture);
ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
@@ -3555,6 +3591,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3566,6 +3603,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
@@ -3647,6 +3685,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_SPOT_LIGHTS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_DECALS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_REFLECTION_PROBES);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_OCCLUDERS)
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
@@ -3682,26 +3721,10 @@ Viewport::Viewport() {
viewport_textures.insert(default_texture.ptr());
default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid);
- audio_listener = false;
//internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
- audio_listener_2d = false;
- transparent_bg = false;
- parent = nullptr;
- listener = nullptr;
- camera = nullptr;
- override_canvas_transform = false;
canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport)
- gen_mipmaps = false;
-
//clear=true;
-
- physics_object_picking = false;
- physics_has_last_mousepos = false;
- physics_last_mousepos = Vector2(Math_INF, Math_INF);
-
- shadow_atlas_16_bits = true;
- shadow_atlas_size = 2048;
set_shadow_atlas_size(shadow_atlas_size);
for (int i = 0; i < 4; i++) {
@@ -3720,50 +3743,11 @@ Viewport::Viewport() {
unhandled_input_group = "_vp_unhandled_input" + id;
unhandled_key_input_group = "_vp_unhandled_key_input" + id;
- disable_input = false;
-
// Window tooltip.
- gui.tooltip_timer = -1;
-
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
- gui.tooltip_control = nullptr;
- gui.tooltip_label = nullptr;
- gui.drag_preview = nullptr;
- gui.drag_attempted = false;
- gui.canvas_sort_index = 0;
- gui.roots_order_dirty = false;
- gui.mouse_focus = nullptr;
- gui.forced_mouse_focus = false;
- gui.last_mouse_focus = nullptr;
- gui.subwindow_focused = nullptr;
- gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
-
- msaa = MSAA_DISABLED;
- screen_space_aa = SCREEN_SPACE_AA_DISABLED;
- debug_draw = DEBUG_DRAW_DISABLED;
-
- snap_controls_to_pixels = true;
- snap_2d_transforms_to_pixel = false;
- snap_2d_vertices_to_pixel = false;
-
- physics_last_mouse_state.alt = false;
- physics_last_mouse_state.control = false;
- physics_last_mouse_state.shift = false;
- physics_last_mouse_state.meta = false;
- physics_last_mouse_state.mouse_mask = 0;
- local_input_handled = false;
- handle_input_locally = true;
-
- size_allocated = false;
-
- default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
-
- sdf_oversize = SDF_OVERSIZE_120_PERCENT;
- sdf_scale = SDF_SCALE_50_PERCENT;
- set_sdf_oversize(SDF_OVERSIZE_120_PERCENT); //set to server
+ set_sdf_oversize(sdf_oversize); //set to server
}
Viewport::~Viewport() {
@@ -3776,16 +3760,6 @@ Viewport::~Viewport() {
/////////////////////////////////
-void SubViewport::set_use_xr(bool p_use_xr) {
- xr = p_use_xr;
-
- RS::get_singleton()->viewport_set_use_xr(get_viewport_rid(), xr);
-}
-
-bool SubViewport::is_using_xr() {
- return xr;
-}
-
void SubViewport::set_size(const Size2i &p_size) {
_set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
}
@@ -3858,9 +3832,6 @@ void SubViewport::_notification(int p_what) {
}
void SubViewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &SubViewport::set_use_xr);
- ClassDB::bind_method(D_METHOD("is_using_xr"), &SubViewport::is_using_xr);
-
ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size);
@@ -3876,7 +3847,6 @@ void SubViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &SubViewport::set_clear_mode);
ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_2d_override"), "set_size_2d_override", "get_size_2d_override");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_2d_override_stretch"), "set_size_2d_override_stretch", "is_size_2d_override_stretch_enabled");
@@ -3895,12 +3865,6 @@ void SubViewport::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
}
-SubViewport::SubViewport() {
- xr = false;
- size_2d_override_stretch = false;
- update_mode = UPDATE_WHEN_VISIBLE;
- clear_mode = CLEAR_MODE_ALWAYS;
-}
+SubViewport::SubViewport() {}
-SubViewport::~SubViewport() {
-}
+SubViewport::~SubViewport() {}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index bddc45206d..2e88e1251d 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -56,7 +56,7 @@ class ViewportTexture : public Texture2D {
NodePath path;
friend class Viewport;
- Viewport *vp;
+ Viewport *vp = nullptr;
mutable RID proxy_ph;
mutable RID proxy;
@@ -77,7 +77,7 @@ public:
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
ViewportTexture();
~ViewportTexture();
@@ -147,6 +147,7 @@ public:
DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
DEBUG_DRAW_CLUSTER_DECALS,
DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ DEBUG_DRAW_OCCLUDERS,
};
enum DefaultCanvasItemTextureFilter {
@@ -186,9 +187,9 @@ public:
private:
friend class ViewportTexture;
- Viewport *parent;
+ Viewport *parent = nullptr;
- Listener3D *listener;
+ Listener3D *listener = nullptr;
Set<Listener3D *> listeners;
struct CameraOverrideData {
@@ -197,11 +198,11 @@ private:
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL
};
- Projection projection;
- float fov;
- float size;
- float z_near;
- float z_far;
+ Projection projection = Projection::PROJECTION_PERSPECTIVE;
+ float fov = 0.0;
+ float size = 0.0;
+ float z_near = 0.0;
+ float z_far = 0.0;
RID rid;
operator bool() const {
@@ -209,7 +210,7 @@ private:
}
} camera_override;
- Camera3D *camera;
+ Camera3D *camera = nullptr;
Set<Camera3D *> cameras;
Set<CanvasLayer *> canvas_layers;
@@ -217,13 +218,13 @@ private:
RID current_canvas;
RID subwindow_canvas;
- bool audio_listener;
+ bool audio_listener = false;
RID internal_listener;
- bool audio_listener_2d;
+ bool audio_listener_2d = false;
RID internal_listener_2d;
- bool override_canvas_transform;
+ bool override_canvas_transform = false;
Transform2D canvas_transform_override;
Transform2D canvas_transform;
@@ -232,7 +233,8 @@ private:
Size2i size;
Size2i size_2d_override;
- bool size_allocated;
+ bool size_allocated = false;
+ bool use_xr = false;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
@@ -240,36 +242,36 @@ private:
Rect2 last_vp_rect;
- bool transparent_bg;
+ bool transparent_bg = false;
bool filter;
- bool gen_mipmaps;
+ bool gen_mipmaps = false;
- bool snap_controls_to_pixels;
- bool snap_2d_transforms_to_pixel;
- bool snap_2d_vertices_to_pixel;
+ bool snap_controls_to_pixels = true;
+ bool snap_2d_transforms_to_pixel = false;
+ bool snap_2d_vertices_to_pixel = false;
- bool physics_object_picking;
+ bool physics_object_picking = false;
List<Ref<InputEvent>> physics_picking_events;
ObjectID physics_object_capture;
ObjectID physics_object_over;
Transform physics_last_object_transform;
Transform physics_last_camera_transform;
ObjectID physics_last_id;
- bool physics_has_last_mousepos;
- Vector2 physics_last_mousepos;
+ bool physics_has_last_mousepos = false;
+ Vector2 physics_last_mousepos = Vector2(Math_INF, Math_INF);
struct {
- bool alt;
- bool control;
- bool shift;
- bool meta;
- int mouse_mask;
+ bool alt = false;
+ bool control = false;
+ bool shift = false;
+ bool meta = false;
+ int mouse_mask = 0;
} physics_last_mouse_state;
void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
- bool handle_input_locally;
- bool local_input_handled;
+ bool handle_input_locally = true;
+ bool local_input_handled = false;
Map<ObjectID, uint64_t> physics_2d_mouseover;
@@ -294,22 +296,23 @@ private:
RID texture_rid;
- DebugDraw debug_draw;
+ DebugDraw debug_draw = DEBUG_DRAW_DISABLED;
- int shadow_atlas_size;
+ int shadow_atlas_size = 2048;
bool shadow_atlas_16_bits = true;
ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
- MSAA msaa;
- ScreenSpaceAA screen_space_aa;
+ MSAA msaa = MSAA_DISABLED;
+ ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
float lod_threshold = 1.0;
+ bool use_occlusion_culling = false;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
- SDFOversize sdf_oversize;
- SDFScale sdf_scale;
+ SDFOversize sdf_oversize = SDF_OVERSIZE_120_PERCENT;
+ SDFScale sdf_scale = SDF_SCALE_50_PERCENT;
enum SubWindowDrag {
SUB_WINDOW_DRAG_DISABLED,
@@ -332,60 +335,58 @@ private:
};
struct SubWindow {
- Window *window;
+ Window *window = nullptr;
RID canvas_item;
};
struct GUI {
// info used when this is a window
- bool forced_mouse_focus; //used for menu buttons
- bool key_event_accepted;
- Control *mouse_focus;
- Control *last_mouse_focus;
- Control *mouse_click_grabber;
- int mouse_focus_mask;
- Control *key_focus;
- Control *mouse_over;
- Control *drag_mouse_over;
+ bool forced_mouse_focus = false; //used for menu buttons
+ bool key_event_accepted = false;
+ Control *mouse_focus = nullptr;
+ Control *last_mouse_focus = nullptr;
+ Control *mouse_click_grabber = nullptr;
+ int mouse_focus_mask = 0;
+ Control *key_focus = nullptr;
+ Control *mouse_over = nullptr;
+ Control *drag_mouse_over = nullptr;
Vector2 drag_mouse_over_pos;
- Control *tooltip_control;
- Window *tooltip_popup;
- Label *tooltip_label;
+ Control *tooltip_control = nullptr;
+ Window *tooltip_popup = nullptr;
+ Label *tooltip_label = nullptr;
Point2 tooltip_pos;
Point2 last_mouse_pos;
Point2 drag_accum;
- bool drag_attempted;
+ bool drag_attempted = false;
Variant drag_data;
- Control *drag_preview;
- float tooltip_timer;
- float tooltip_delay;
+ ObjectID drag_preview_id;
+ float tooltip_timer = -1.0;
+ float tooltip_delay = 0.0;
Transform2D focus_inv_xform;
- bool roots_order_dirty;
+ bool roots_order_dirty = false;
List<Control *> roots;
- int canvas_sort_index; //for sorting items with canvas as root
- bool dragging;
- bool embed_subwindows_hint;
- bool embedding_subwindows;
+ int canvas_sort_index = 0; //for sorting items with canvas as root
+ bool dragging = false;
+ bool embed_subwindows_hint = false;
+ bool embedding_subwindows = false;
- Window *subwindow_focused;
- SubWindowDrag subwindow_drag;
+ Window *subwindow_focused = nullptr;
+ SubWindowDrag subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
Vector2 subwindow_drag_from;
Vector2 subwindow_drag_pos;
Rect2i subwindow_drag_close_rect;
- bool subwindow_drag_close_inside;
+ bool subwindow_drag_close_inside = false;
SubWindowResize subwindow_resize_mode;
Rect2i subwindow_resize_from_rect;
Vector<SubWindow> sub_windows;
-
- GUI();
} gui;
- DefaultCanvasItemTextureFilter default_canvas_item_texture_filter;
- DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat;
+ DefaultCanvasItemTextureFilter default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
- bool disable_input;
+ bool disable_input = false;
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
void _gui_call_notification(Control *p_control, int p_what);
@@ -417,6 +418,7 @@ private:
void _gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control);
void _gui_set_drag_preview(Control *p_base, Control *p_control);
+ Control *_gui_get_drag_preview();
void _gui_remove_focus_for_window(Node *p_window);
void _gui_remove_focus();
@@ -481,7 +483,6 @@ protected:
void _notification(int p_what);
void _process_picking();
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
public:
uint64_t get_processed_events_count() const { return event_count; }
@@ -534,6 +535,9 @@ public:
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
+ void set_use_xr(bool p_use_xr);
+ bool is_using_xr();
+
Ref<ViewportTexture> get_texture() const;
void set_shadow_atlas_size(int p_size);
@@ -557,6 +561,9 @@ public:
void set_lod_threshold(float p_pixels);
float get_lod_threshold() const;
+ void set_use_occlusion_culling(bool p_us_occlusion_culling);
+ bool is_using_occlusion_culling() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -581,7 +588,7 @@ public:
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const;
@@ -651,10 +658,9 @@ public:
};
private:
- UpdateMode update_mode;
- ClearMode clear_mode;
- bool xr;
- bool size_2d_override_stretch;
+ UpdateMode update_mode = UPDATE_WHEN_VISIBLE;
+ ClearMode clear_mode = CLEAR_MODE_ALWAYS;
+ bool size_2d_override_stretch = false;
protected:
static void _bind_methods();
@@ -669,9 +675,6 @@ public:
void set_size_2d_override(const Size2i &p_size);
Size2i get_size_2d_override() const;
- void set_use_xr(bool p_use_xr);
- bool is_using_xr();
-
void set_size_2d_override_stretch(bool p_enable);
bool is_size_2d_override_stretch_enabled() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 0a541a2d07..bacb0030bb 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -232,7 +232,7 @@ void Window::_make_window() {
DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
- DisplayServer::get_singleton()->window_set_title(title, window_id);
+ DisplayServer::get_singleton()->window_set_title(tr(title), window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
_update_window_size();
@@ -759,6 +759,10 @@ void Window::_notification(int p_what) {
}
}
+ if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+ child_controls_changed();
+ }
+
if (p_what == NOTIFICATION_EXIT_TREE) {
if (transient) {
_clear_transient();
@@ -826,6 +830,9 @@ bool Window::is_using_font_oversampling() const {
}
DisplayServer::WindowID Window::get_window_id() const {
+ if (embedder) {
+ return parent->get_window_id();
+ }
return window_id;
}
@@ -881,10 +888,6 @@ bool Window::_can_consume_input_events() const {
}
void Window::_window_input(const Ref<InputEvent> &p_ev) {
- if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_ev.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_ev))) {
- return; //avoid joy input on editor
- }
-
if (EngineDebugger::is_active()) {
//quit from game window using F8
Ref<InputEventKey> k = p_ev;
@@ -894,12 +897,13 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
}
if (exclusive_child != nullptr) {
+ /*
Window *focus_target = exclusive_child;
focus_target->grab_focus();
while (focus_target->exclusive_child != nullptr) {
focus_target = focus_target->exclusive_child;
focus_target->grab_focus();
- }
+ }*/
if (!is_embedding_subwindows()) { //not embedding, no need for event
return;
@@ -1039,6 +1043,9 @@ void Window::popup_centered_ratio(float p_ratio) {
void Window::popup(const Rect2i &p_screen_rect) {
emit_signal("about_to_popup");
+ // Update window size to calculate the actual window size based on contents minimum size and minimum size.
+ _update_window_size();
+
if (p_screen_rect != Rect2i()) {
set_position(p_screen_rect.position);
set_size(p_screen_rect.size);
@@ -1283,14 +1290,14 @@ bool Window::is_layout_rtl() const {
if (parent) {
return parent->is_layout_rtl();
} else {
- if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) {
+ if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) {
return true;
}
String locale = TranslationServer::get_singleton()->get_tool_locale();
return TS->is_locale_right_to_left(locale);
}
} else if (layout_dir == LAYOUT_DIRECTION_LOCALE) {
- if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) {
+ if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) {
return true;
}
String locale = TranslationServer::get_singleton()->get_tool_locale();
@@ -1349,8 +1356,8 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus);
ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus);
- ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active);
- ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position);
+ ClassDB::bind_method(D_METHOD("set_ime_active", "active"), &Window::set_ime_active);
+ ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &Window::set_ime_position);
ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded);
@@ -1466,11 +1473,6 @@ void Window::_bind_methods() {
}
Window::Window() {
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
- }
- content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
- content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 2ffeff03ff..38846ed00e 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -90,7 +90,7 @@ private:
mutable Size2i min_size;
mutable Size2i max_size;
mutable Mode mode = MODE_WINDOWED;
- mutable bool flags[FLAG_MAX];
+ mutable bool flags[FLAG_MAX] = {};
bool visible = true;
bool focused = false;
@@ -106,8 +106,8 @@ private:
void _update_child_controls();
Size2i content_scale_size;
- ContentScaleMode content_scale_mode;
- ContentScaleAspect content_scale_aspect;
+ ContentScaleMode content_scale_mode = CONTENT_SCALE_MODE_DISABLED;
+ ContentScaleAspect content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE;
void _make_window();
void _clear_window();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index b14c44689e..b16532676f 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -50,7 +50,6 @@
#include "scene/2d/line_2d.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/multimesh_instance_2d.h"
-#include "scene/2d/navigation_2d.h"
#include "scene/2d/navigation_agent_2d.h"
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/2d/parallax_background.h"
@@ -206,10 +205,10 @@
#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
-#include "scene/3d/navigation_3d.h"
#include "scene/3d/navigation_agent_3d.h"
#include "scene/3d/navigation_obstacle_3d.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/path_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/physics_joint_3d.h"
@@ -444,6 +443,8 @@ void register_scene_types() {
ClassDB::register_class<XRAnchor3D>();
ClassDB::register_class<XROrigin3D>();
ClassDB::register_class<MeshInstance3D>();
+ ClassDB::register_class<OccluderInstance3D>();
+ ClassDB::register_class<Occluder3D>();
ClassDB::register_class<ImmediateGeometry3D>();
ClassDB::register_virtual_class<SpriteBase3D>();
ClassDB::register_class<Sprite3D>();
@@ -516,7 +517,6 @@ void register_scene_types() {
ClassDB::register_class<ConeTwistJoint3D>();
ClassDB::register_class<Generic6DOFJoint3D>();
- ClassDB::register_class<Navigation3D>();
ClassDB::register_class<NavigationRegion3D>();
ClassDB::register_class<NavigationAgent3D>();
ClassDB::register_class<NavigationObstacle3D>();
@@ -535,6 +535,7 @@ void register_scene_types() {
ClassDB::register_virtual_class<VisualShaderNodeResizableBase>();
ClassDB::register_virtual_class<VisualShaderNodeGroupBase>();
ClassDB::register_virtual_class<VisualShaderNodeConstant>();
+ ClassDB::register_class<VisualShaderNodeComment>();
ClassDB::register_class<VisualShaderNodeFloatConstant>();
ClassDB::register_class<VisualShaderNodeIntConstant>();
ClassDB::register_class<VisualShaderNodeBooleanConstant>();
@@ -688,6 +689,8 @@ void register_scene_types() {
ClassDB::register_class<PrismMesh>();
ClassDB::register_class<QuadMesh>();
ClassDB::register_class<SphereMesh>();
+ ClassDB::register_class<TubeTrailMesh>();
+ ClassDB::register_class<RibbonTrailMesh>();
ClassDB::register_class<PointMesh>();
ClassDB::register_virtual_class<Material>();
ClassDB::register_virtual_class<BaseMaterial3D>();
@@ -728,7 +731,6 @@ void register_scene_types() {
ClassDB::register_class<ImageTexture>();
ClassDB::register_class<AtlasTexture>();
ClassDB::register_class<MeshTexture>();
- ClassDB::register_class<LargeTexture>();
ClassDB::register_class<CurveTexture>();
ClassDB::register_class<GradientTexture>();
ClassDB::register_class<ProxyTexture>();
@@ -793,7 +795,6 @@ void register_scene_types() {
ClassDB::register_class<PathFollow2D>();
ClassDB::register_class<NavigationMesh>();
- ClassDB::register_class<Navigation2D>();
ClassDB::register_class<NavigationPolygon>();
ClassDB::register_class<NavigationRegion2D>();
ClassDB::register_class<NavigationAgent2D>();
@@ -814,6 +815,8 @@ void register_scene_types() {
ClassDB::add_compatibility_class("DynamicFont", "Font");
ClassDB::add_compatibility_class("DynamicFontData", "FontData");
ClassDB::add_compatibility_class("ToolButton", "Button");
+ ClassDB::add_compatibility_class("Navigation3D", "Node3D");
+ ClassDB::add_compatibility_class("Navigation2D", "Node2D");
// Renamed in 4.0.
// Keep alphabetical ordering to easily locate classes and avoid duplicates.
@@ -865,7 +868,6 @@ void register_scene_types() {
ClassDB::add_compatibility_class("Listener", "Listener3D");
ClassDB::add_compatibility_class("MeshInstance", "MeshInstance3D");
ClassDB::add_compatibility_class("MultiMeshInstance", "MultiMeshInstance3D");
- ClassDB::add_compatibility_class("Navigation", "Navigation3D");
ClassDB::add_compatibility_class("NavigationAgent", "NavigationAgent3D");
ClassDB::add_compatibility_class("NavigationMeshInstance", "NavigationRegion3D");
ClassDB::add_compatibility_class("NavigationObstacle", "NavigationObstacle3D");
@@ -948,17 +950,19 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
for (int i = 0; i < 20; i++) {
- GLOBAL_DEF(vformat("layer_names/2d_render/layer_%d", i), "");
- GLOBAL_DEF(vformat("layer_names/2d_physics/layer_%d", i), "");
- GLOBAL_DEF(vformat("layer_names/3d_render/layer_%d", i), "");
- GLOBAL_DEF(vformat("layer_names/3d_physics/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_render/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_physics/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/2d_navigation/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_render/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_physics/layer_%d", i), "");
+ GLOBAL_DEF_BASIC(vformat("layer_names/3d_navigation/layer_%d", i), "");
}
bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false);
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String theme_path = GLOBAL_DEF("gui/theme/custom", "");
+ String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String font_path = GLOBAL_DEF("gui/theme/custom_font", "");
+ String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
Ref<Font> font;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 796fe1d106..6f64ac6d04 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -580,6 +580,10 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Animation::reset_state() {
+ clear();
+}
+
int Animation::add_track(TrackType p_type, int p_at_pos) {
if (p_at_pos < 0 || p_at_pos >= tracks.size()) {
p_at_pos = tracks.size();
@@ -1604,7 +1608,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola
bool result = true;
int next = 0;
- float c = 0;
+ float c = 0.0;
// prepare for all cases of interpolation
if (loop && p_loop_wrap) {
@@ -2278,8 +2282,8 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const {
int iterations = 10;
float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes
- float low = 0; // 0% of the current animation segment
- float high = 1; // 100% of the current animation segment
+ float low = 0.0; // 0% of the current animation segment
+ float high = 1.0; // 100% of the current animation segment
float middle;
Vector2 start(0, bt->values[idx].value.value);
@@ -2734,7 +2738,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
if (d > pd.length() * p_alowed_linear_err) {
- return false; //beyond allowed error for colinearity
+ return false; //beyond allowed error for collinearity
}
if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_alowed_angular_err) {
@@ -2824,7 +2828,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
if (d > pd.length() * p_alowed_linear_err) {
- return false; //beyond allowed error for colinearity
+ return false; //beyond allowed error for collinearity
}
t[2] = (d1 - d0) / (d2 - d0);
@@ -2836,7 +2840,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
erase = true;
} else {
erase = true;
- real_t lt = -1;
+ real_t lt = -1.0;
for (int j = 0; j < 3; j++) {
//search for t on first, one must be it
if (t[j] != -1) {
@@ -2919,11 +2923,7 @@ void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err
}
}
-Animation::Animation() {
- step = 0.1;
- loop = false;
- length = 1;
-}
+Animation::Animation() {}
Animation::~Animation() {
for (int i = 0; i < tracks.size(); i++) {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index fa374e6ad2..66bc71c834 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -65,28 +65,19 @@ public:
private:
struct Track {
- TrackType type;
- InterpolationType interpolation;
- bool loop_wrap;
+ TrackType type = TrackType::TYPE_ANIMATION;
+ InterpolationType interpolation = INTERPOLATION_LINEAR;
+ bool loop_wrap = true;
NodePath path; // path to something
- bool imported;
- bool enabled;
- Track() {
- interpolation = INTERPOLATION_LINEAR;
- imported = false;
- loop_wrap = true;
- enabled = true;
- }
+ bool imported = false;
+ bool enabled = true;
+ Track() {}
virtual ~Track() {}
};
struct Key {
- float transition;
- float time; // time in secs
- Key() {
- transition = 1;
- time = 0;
- }
+ float transition = 1.0;
+ float time = 0.0; // time in secs
};
// transform key holds either Vector3 or Quaternion
@@ -112,13 +103,12 @@ private:
/* PROPERTY VALUE TRACK */
struct ValueTrack : public Track {
- UpdateMode update_mode;
- bool update_on_seek;
+ UpdateMode update_mode = UPDATE_CONTINUOUS;
+ bool update_on_seek = false;
Vector<TKey<Variant>> values;
ValueTrack() {
type = TYPE_VALUE;
- update_mode = UPDATE_CONTINUOUS;
}
};
@@ -139,7 +129,7 @@ private:
struct BezierKey {
Vector2 in_handle; //relative (x always <0)
Vector2 out_handle; //relative (x always >0)
- float value;
+ float value = 0.0;
};
struct BezierTrack : public Track {
@@ -154,11 +144,9 @@ private:
struct AudioKey {
RES stream;
- float start_offset; //offset from start
- float end_offset; //offset from end, if 0 then full length or infinite
+ float start_offset = 0.0; //offset from start
+ float end_offset = 0.0; //offset from end, if 0 then full length or infinite
AudioKey() {
- start_offset = 0;
- end_offset = 0;
}
};
@@ -217,9 +205,9 @@ private:
_FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const;
_FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const;
- float length;
- float step;
- bool loop;
+ float length = 1.0;
+ float step = 0.1;
+ bool loop = false;
// bind helpers
private:
@@ -264,6 +252,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
static void _bind_methods();
public:
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index 8fdb004e65..9a9f019dda 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -403,11 +403,7 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
}
}
-AudioStreamPlaybackSample::AudioStreamPlaybackSample() {
- active = false;
- offset = 0;
- sign = 1;
-}
+AudioStreamPlaybackSample::AudioStreamPlaybackSample() {}
/////////////////////
@@ -494,9 +490,9 @@ void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) {
const uint8_t *r = p_data.ptr();
int alloc_len = datalen + DATA_PAD * 2;
data = memalloc(alloc_len); //alloc with some padding for interpolation
- zeromem(data, alloc_len);
+ memset(data, 0, alloc_len);
uint8_t *dataptr = (uint8_t *)data;
- copymem(dataptr + DATA_PAD, r, datalen);
+ memcpy(dataptr + DATA_PAD, r, datalen);
data_bytes = datalen;
}
@@ -511,7 +507,7 @@ Vector<uint8_t> AudioStreamSample::get_data() const {
{
uint8_t *w = pv.ptrw();
uint8_t *dataptr = (uint8_t *)data;
- copymem(w, dataptr + DATA_PAD, data_bytes);
+ memcpy(w, dataptr + DATA_PAD, data_bytes);
}
}
@@ -651,16 +647,7 @@ void AudioStreamSample::_bind_methods() {
BIND_ENUM_CONSTANT(LOOP_BACKWARD);
}
-AudioStreamSample::AudioStreamSample() {
- format = FORMAT_8_BITS;
- loop_mode = LOOP_DISABLED;
- stereo = false;
- loop_begin = 0;
- loop_end = 0;
- mix_rate = 44100;
- data = nullptr;
- data_bytes = 0;
-}
+AudioStreamSample::AudioStreamSample() {}
AudioStreamSample::~AudioStreamSample() {
if (data) {
diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h
index ba475c0888..70b8ba79ad 100644
--- a/scene/resources/audio_stream_sample.h
+++ b/scene/resources/audio_stream_sample.h
@@ -44,19 +44,19 @@ class AudioStreamPlaybackSample : public AudioStreamPlayback {
};
struct IMA_ADPCM_State {
- int16_t step_index;
- int32_t predictor;
+ int16_t step_index = 0;
+ int32_t predictor = 0;
/* values at loop point */
- int16_t loop_step_index;
- int32_t loop_predictor;
- int32_t last_nibble;
- int32_t loop_pos;
- int32_t window_ofs;
+ int16_t loop_step_index = 0;
+ int32_t loop_predictor = 0;
+ int32_t last_nibble = 0;
+ int32_t loop_pos = 0;
+ int32_t window_ofs = 0;
} ima_adpcm[2];
- int64_t offset;
- int sign;
- bool active;
+ int64_t offset = 0;
+ int sign = 1;
+ bool active = false;
friend class AudioStreamSample;
Ref<AudioStreamSample> base;
@@ -103,14 +103,14 @@ private:
DATA_PAD = 16 //padding for interpolation
};
- Format format;
- LoopMode loop_mode;
- bool stereo;
- int loop_begin;
- int loop_end;
- int mix_rate;
- void *data;
- uint32_t data_bytes;
+ Format format = FORMAT_8_BITS;
+ LoopMode loop_mode = LOOP_DISABLED;
+ bool stereo = false;
+ int loop_begin = 0;
+ int loop_end = 0;
+ int mix_rate = 44100;
+ void *data = nullptr;
+ uint32_t data_bytes = 0;
protected:
static void _bind_methods();
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index dfb7a1fdfb..e9bfac3653 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -39,7 +39,7 @@ void BitMap::create(const Size2 &p_size) {
width = p_size.width;
height = p_size.height;
bitmask.resize(((width * height) / 8) + 1);
- zeromem(bitmask.ptrw(), bitmask.size());
+ memset(bitmask.ptrw(), 0, bitmask.size());
}
void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) {
@@ -285,7 +285,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
| 4 | |
+---+---+
- this normally go RIGHT, but if its coming from RIGHT, it should go LEFT
+ this normally go RIGHT, but if it's coming from RIGHT, it should go LEFT
*/
if (case6s.has(Point2i(curx, cury))) {
//found, so we go left, and delete from case6s;
@@ -346,7 +346,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
}
int index = -1;
- float dist = 0;
+ float dist = 0.0;
//not looping first and last point
for (size_t i = 1, size = v.size(); i < size - 1; ++i) {
float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]);
@@ -406,8 +406,8 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect,
struct FillBitsStackEntry {
Point2i pos;
- int i;
- int j;
+ int i = 0;
+ int j = 0;
};
static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
@@ -677,9 +677,6 @@ void BitMap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
-BitMap::BitMap() {
- width = 0;
- height = 0;
-}
+BitMap::BitMap() {}
//////////////////////////////////////
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index 7414265cee..68fd0b999a 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -40,8 +40,8 @@ class BitMap : public Resource {
OBJ_SAVE_TYPE(BitMap);
Vector<uint8_t> bitmask;
- int width;
- int height;
+ int width = 0;
+ int height = 0;
Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp
index fadbf21e43..6e7adc0bd7 100644
--- a/scene/resources/box_shape_3d.cpp
+++ b/scene/resources/box_shape_3d.cpp
@@ -60,7 +60,6 @@ void BoxShape3D::set_size(const Vector3 &p_size) {
size = p_size;
_update_shape();
notify_change_to_owners();
- _change_notify("size");
}
Vector3 BoxShape3D::get_size() const {
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
index 695b14939f..34c6bc05bc 100644
--- a/scene/resources/camera_effects.cpp
+++ b/scene/resources/camera_effects.cpp
@@ -41,7 +41,7 @@ RID CameraEffects::get_rid() const {
void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) {
dof_blur_far_enabled = p_enabled;
_update_dof_blur();
- _change_notify();
+ notify_property_list_changed();
}
bool CameraEffects::is_dof_blur_far_enabled() const {
@@ -69,7 +69,7 @@ float CameraEffects::get_dof_blur_far_transition() const {
void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) {
dof_blur_near_enabled = p_enabled;
_update_dof_blur();
- _change_notify();
+ notify_property_list_changed();
}
bool CameraEffects::is_dof_blur_near_enabled() const {
@@ -120,6 +120,7 @@ void CameraEffects::_update_dof_blur() {
void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
override_exposure_enabled = p_enabled;
_update_override_exposure();
+ notify_property_list_changed();
}
bool CameraEffects::is_override_exposure_enabled() const {
@@ -144,6 +145,14 @@ void CameraEffects::_update_override_exposure() {
// Private methods, constructor and destructor
+void CameraEffects::_validate_property(PropertyInfo &property) const {
+ if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) ||
+ (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) ||
+ (!override_exposure_enabled && property.name == "override_exposure")) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void CameraEffects::_bind_methods() {
// DOF blur
diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h
index cf12b6d3c0..b9338f4806 100644
--- a/scene/resources/camera_effects.h
+++ b/scene/resources/camera_effects.h
@@ -42,12 +42,12 @@ private:
// DOF blur
bool dof_blur_far_enabled = false;
- float dof_blur_far_distance = 10;
- float dof_blur_far_transition = 5;
+ float dof_blur_far_distance = 10.0;
+ float dof_blur_far_transition = 5.0;
bool dof_blur_near_enabled = false;
- float dof_blur_near_distance = 2;
- float dof_blur_near_transition = 1;
+ float dof_blur_near_distance = 2.0;
+ float dof_blur_near_transition = 1.0;
float dof_blur_amount = 0.1;
void _update_dof_blur();
@@ -59,6 +59,7 @@ private:
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
virtual RID get_rid() const override;
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 63d90a8364..e5edba8a67 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -85,6 +85,11 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Color> col;
col.push_back(p_color);
RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ if (is_collision_outline_enabled()) {
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
+ // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color);
+ }
}
Rect2 CapsuleShape2D::get_rect() const {
@@ -112,7 +117,5 @@ void CapsuleShape2D::_bind_methods() {
CapsuleShape2D::CapsuleShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->capsule_shape_create()) {
- radius = 10;
- height = 20;
_update_shape();
}
diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h
index 8c8c1b259b..439b67e8c3 100644
--- a/scene/resources/capsule_shape_2d.h
+++ b/scene/resources/capsule_shape_2d.h
@@ -36,8 +36,8 @@
class CapsuleShape2D : public Shape2D {
GDCLASS(CapsuleShape2D, Shape2D);
- real_t height;
- real_t radius;
+ real_t height = 20.0;
+ real_t radius = 10.0;
void _update_shape();
Vector<Vector2> _get_points() const;
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index a0b454a00f..226fe1ecd2 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -82,7 +82,6 @@ void CapsuleShape3D::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
- _change_notify("radius");
}
float CapsuleShape3D::get_radius() const {
@@ -93,7 +92,6 @@ void CapsuleShape3D::set_height(float p_height) {
height = p_height;
_update_shape();
notify_change_to_owners();
- _change_notify("height");
}
float CapsuleShape3D::get_height() const {
@@ -112,7 +110,5 @@ void CapsuleShape3D::_bind_methods() {
CapsuleShape3D::CapsuleShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CAPSULE)) {
- radius = 1.0;
- height = 1.0;
_update_shape();
}
diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h
index b5b8912445..25645ecf9d 100644
--- a/scene/resources/capsule_shape_3d.h
+++ b/scene/resources/capsule_shape_3d.h
@@ -35,8 +35,8 @@
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
- float radius;
- float height;
+ float radius = 1.0;
+ float height = 1.0;
protected:
static void _bind_methods();
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index a44c1b68bf..f06bc4248d 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -79,10 +79,14 @@ void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Color> col;
col.push_back(p_color);
RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ if (is_collision_outline_enabled()) {
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
+ // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color);
+ }
}
CircleShape2D::CircleShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->circle_shape_create()) {
- radius = 10;
_update_shape();
}
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index a066b773ef..333f299236 100644
--- a/scene/resources/circle_shape_2d.h
+++ b/scene/resources/circle_shape_2d.h
@@ -36,7 +36,7 @@
class CircleShape2D : public Shape2D {
GDCLASS(CircleShape2D, Shape2D);
- real_t radius;
+ real_t radius = 10.0;
void _update_shape();
protected:
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index 3d6df3bb9c..0c767c8a52 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -98,7 +98,7 @@ Rect2 ConcavePolygonShape2D::get_rect() const {
real_t ConcavePolygonShape2D::get_enclosing_radius() const {
Vector<Vector2> data = get_segments();
const Vector2 *read = data.ptr();
- real_t r = 0;
+ real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
index 358c99ad09..3fed700383 100644
--- a/scene/resources/concave_polygon_shape_3d.cpp
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -35,13 +35,12 @@
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
Set<DrawEdge> edges;
- Vector<Vector3> data = get_faces();
- int datalen = data.size();
- ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
+ int index_count = faces.size();
+ ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
- const Vector3 *r = data.ptr();
+ const Vector3 *r = faces.ptr();
- for (int i = 0; i < datalen; i += 3) {
+ for (int i = 0; i < index_count; i += 3) {
for (int j = 0; j < 3; j++) {
DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
edges.insert(de);
@@ -63,7 +62,7 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
real_t ConcavePolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_faces();
const Vector3 *read = data.ptr();
- real_t r = 0;
+ real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
@@ -71,22 +70,46 @@ real_t ConcavePolygonShape3D::get_enclosing_radius() const {
}
void ConcavePolygonShape3D::_update_shape() {
+ Dictionary d;
+ d["faces"] = faces;
+ d["backface_collision"] = backface_collision;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+
Shape3D::_update_shape();
}
void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
- PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), p_faces);
+ faces = p_faces;
+ _update_shape();
notify_change_to_owners();
}
Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
- return PhysicsServer3D::get_singleton()->shape_get_data(get_shape());
+ return faces;
+}
+
+void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
+ backface_collision = p_enabled;
+
+ if (!faces.is_empty()) {
+ _update_shape();
+ notify_change_to_owners();
+ }
+}
+
+bool ConcavePolygonShape3D::is_backface_collision_enabled() const {
+ return backface_collision;
}
void ConcavePolygonShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces);
+
+ ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled);
+ ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled");
}
ConcavePolygonShape3D::ConcavePolygonShape3D() :
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
index 391459a3d7..bb28359dcc 100644
--- a/scene/resources/concave_polygon_shape_3d.h
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -36,6 +36,9 @@
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
+ Vector<Vector3> faces;
+ bool backface_collision = false;
+
struct DrawEdge {
Vector3 a;
Vector3 b;
@@ -65,6 +68,9 @@ public:
void set_faces(const Vector<Vector3> &p_faces);
Vector<Vector3> get_faces() const;
+ void set_backface_collision_enabled(bool p_enabled);
+ bool is_backface_collision_enabled() const;
+
virtual Vector<Vector3> get_debug_mesh_lines() const override;
virtual real_t get_enclosing_radius() const override;
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 656e064356..ac31315858 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -41,7 +41,7 @@ bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, dou
void ConvexPolygonShape2D::_update_shape() {
Vector<Vector2> final_points = points;
if (Geometry2D::is_polygon_clockwise(final_points)) { //needs to be counter clockwise
- final_points.invert();
+ final_points.reverse();
}
PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), final_points);
emit_changed();
@@ -72,9 +72,18 @@ void ConvexPolygonShape2D::_bind_methods() {
}
void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
+ if (points.size() < 3) {
+ return;
+ }
+
Vector<Color> col;
col.push_back(p_color);
RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ if (is_collision_outline_enabled()) {
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
+ // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color);
+ }
}
Rect2 ConvexPolygonShape2D::get_rect() const {
@@ -91,7 +100,7 @@ Rect2 ConvexPolygonShape2D::get_rect() const {
}
real_t ConvexPolygonShape2D::get_enclosing_radius() const {
- real_t r = 0;
+ real_t r = 0.0;
for (int i(0); i < get_points().size(); i++) {
r = MAX(get_points()[i].length_squared(), r);
}
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index 770d547231..9e030bc077 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -56,7 +56,7 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
real_t ConvexPolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_points();
const Vector3 *read = data.ptr();
- real_t r = 0;
+ real_t r = 0.0;
for (int i(0); i < data.size(); i++) {
r = MAX(read[i].length_squared(), r);
}
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 123c77a036..846da39221 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -47,11 +47,6 @@ static _FORCE_INLINE_ T _bezier_interp(real_t t, T start, T control_1, T control
const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
Curve::Curve() {
- _bake_resolution = 100;
- _baked_cache_dirty = false;
- _min_value = 0;
- _max_value = 1;
- _minmax_set_once = 0b00;
}
int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent, TangentMode left_mode, TangentMode right_mode) {
@@ -450,10 +445,10 @@ void Curve::set_bake_resolution(int p_resolution) {
_baked_cache_dirty = true;
}
-real_t Curve::interpolate_baked(real_t offset) {
+real_t Curve::interpolate_baked(real_t offset) const {
if (_baked_cache_dirty) {
// Last-second bake if not done already
- bake();
+ const_cast<Curve *>(this)->bake();
}
// Special cases if the cache is too small
@@ -683,7 +678,7 @@ void Curve2D::_bake() const {
for (int i = 0; i < points.size() - 1; i++) {
float step = 0.1; // at least 10 substeps ought to be enough?
- float p = 0;
+ float p = 0.0;
while (p < 1.0) {
float np = p + step;
@@ -993,12 +988,9 @@ void Curve2D::_bind_methods() {
}
Curve2D::Curve2D() {
- baked_cache_dirty = false;
- baked_max_ofs = 0;
/* add_point(Vector2(-1,0,0));
add_point(Vector2(0,2,0));
add_point(Vector2(0,3,5));*/
- bake_interval = 5;
}
/***********************************************************************************/
@@ -1178,7 +1170,7 @@ void Curve3D::_bake() const {
for (int i = 0; i < points.size() - 1; i++) {
float step = 0.1; // at least 10 substeps ought to be enough?
- float p = 0;
+ float p = 0.0;
while (p < 1.0) {
float np = p + step;
@@ -1669,11 +1661,7 @@ void Curve3D::_bind_methods() {
}
Curve3D::Curve3D() {
- baked_cache_dirty = false;
- baked_max_ofs = 0;
/* add_point(Vector3(-1,0,0));
add_point(Vector3(0,2,0));
add_point(Vector3(0,3,5));*/
- bake_interval = 0.2;
- up_vector_enabled = true;
}
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index f33f3c5abe..746c6fa597 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -51,21 +51,17 @@ public:
struct Point {
Vector2 pos;
- real_t left_tangent;
- real_t right_tangent;
- TangentMode left_mode;
- TangentMode right_mode;
+ real_t left_tangent = 0.0;
+ real_t right_tangent = 0.0;
+ TangentMode left_mode = TANGENT_FREE;
+ TangentMode right_mode = TANGENT_FREE;
Point() {
- left_tangent = 0;
- right_tangent = 0;
- left_mode = TANGENT_FREE;
- right_mode = TANGENT_FREE;
}
Point(Vector2 p_pos,
- real_t p_left = 0,
- real_t p_right = 0,
+ real_t p_left = 0.0,
+ real_t p_right = 0.0,
TangentMode p_left_mode = TANGENT_FREE,
TangentMode p_right_mode = TANGENT_FREE) {
pos = p_pos;
@@ -126,7 +122,7 @@ public:
void bake();
int get_bake_resolution() const { return _bake_resolution; }
void set_bake_resolution(int p_resolution);
- real_t interpolate_baked(real_t offset);
+ real_t interpolate_baked(real_t offset) const;
void ensure_default_setup(float p_min, float p_max);
@@ -137,12 +133,12 @@ private:
void mark_dirty();
Vector<Point> _points;
- bool _baked_cache_dirty;
+ bool _baked_cache_dirty = false;
Vector<real_t> _baked_cache;
- int _bake_resolution;
- float _min_value;
- float _max_value;
- int _minmax_set_once; // Encodes whether min and max have been set a first time, first bit for min and second for max.
+ int _bake_resolution = 100;
+ float _min_value = 0.0;
+ float _max_value = 1.0;
+ int _minmax_set_once = 0b00; // Encodes whether min and max have been set a first time, first bit for min and second for max.
};
VARIANT_ENUM_CAST(Curve::TangentMode)
@@ -159,17 +155,17 @@ class Curve2D : public Resource {
Vector<Point> points;
struct BakedPoint {
- float ofs;
+ float ofs = 0.0;
Vector2 point;
};
- mutable bool baked_cache_dirty;
+ mutable bool baked_cache_dirty = false;
mutable PackedVector2Array baked_point_cache;
- mutable float baked_max_ofs;
+ mutable float baked_max_ofs = 0.0;
void _bake() const;
- float bake_interval;
+ float bake_interval = 5.0;
void _bake_segment2d(Map<float, Vector2> &r_bake, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, float p_tol) const;
Dictionary _get_data() const;
@@ -214,28 +210,26 @@ class Curve3D : public Resource {
Vector3 in;
Vector3 out;
Vector3 pos;
- float tilt;
-
- Point() { tilt = 0; }
+ float tilt = 0.0;
};
Vector<Point> points;
struct BakedPoint {
- float ofs;
+ float ofs = 0.0;
Vector3 point;
};
- mutable bool baked_cache_dirty;
+ mutable bool baked_cache_dirty = false;
mutable PackedVector3Array baked_point_cache;
mutable PackedFloat32Array baked_tilt_cache;
mutable PackedVector3Array baked_up_vector_cache;
- mutable float baked_max_ofs;
+ mutable float baked_max_ofs = 0.0;
void _bake() const;
- float bake_interval;
- bool up_vector_enabled;
+ float bake_interval = 0.2;
+ bool up_vector_enabled = true;
void _bake_segment3d(Map<float, Vector3> &r_bake, float p_begin, float p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, float p_tol) const;
Dictionary _get_data() const;
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index 3e9cdca872..63bdc8d26d 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -75,7 +75,6 @@ void CylinderShape3D::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
- _change_notify("radius");
}
float CylinderShape3D::get_radius() const {
@@ -86,7 +85,6 @@ void CylinderShape3D::set_height(float p_height) {
height = p_height;
_update_shape();
notify_change_to_owners();
- _change_notify("height");
}
float CylinderShape3D::get_height() const {
@@ -105,7 +103,5 @@ void CylinderShape3D::_bind_methods() {
CylinderShape3D::CylinderShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CYLINDER)) {
- radius = 1.0;
- height = 2.0;
_update_shape();
}
diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h
index 93e8345727..d1b8364672 100644
--- a/scene/resources/cylinder_shape_3d.h
+++ b/scene/resources/cylinder_shape_3d.h
@@ -35,8 +35,8 @@
class CylinderShape3D : public Shape3D {
GDCLASS(CylinderShape3D, Shape3D);
- float radius;
- float height;
+ float radius = 1.0;
+ float height = 2.0;
protected:
static void _bind_methods();
diff --git a/scene/resources/default_theme/bar_arrow.png b/scene/resources/default_theme/bar_arrow.png
new file mode 100644
index 0000000000..7cf146b8da
--- /dev/null
+++ b/scene/resources/default_theme/bar_arrow.png
Binary files differ
diff --git a/scene/resources/default_theme/checked_disabled.png b/scene/resources/default_theme/checked_disabled.png
new file mode 100644
index 0000000000..70549e2edc
--- /dev/null
+++ b/scene/resources/default_theme/checked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index a0b65e9799..7c00c6d146 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -43,7 +43,7 @@
typedef Map<const void *, Ref<ImageTexture>> TexCacheMap;
static TexCacheMap *tex_cache;
-static float scale = 1;
+static float scale = 1.0;
template <class T>
static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
@@ -114,7 +114,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
}
Ref<ImageTexture> texture(memnew(ImageTexture));
- Ref<Image> img = p_texture->get_data();
+ Ref<Image> img = p_texture->get_image();
img = img->duplicate();
if (p_flip_y) {
@@ -128,6 +128,38 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
return texture;
}
+static Ref<FontData> make_font(int p_height, int p_ascent, int p_charcount, const int *p_char_rects, int p_kerning_count, const int *p_kernings, int p_w, int p_h, const unsigned char *p_img) {
+ Ref<FontData> font(memnew(FontData));
+ font->new_bitmap(p_height, p_ascent, p_height);
+
+ Ref<Image> image = memnew(Image(p_img));
+ Ref<ImageTexture> tex = memnew(ImageTexture);
+ tex->create_from_image(image);
+
+ font->bitmap_add_texture(tex);
+
+ for (int i = 0; i < p_charcount; i++) {
+ const int *c = &p_char_rects[i * 8];
+
+ int chr = c[0];
+ Rect2 frect;
+ frect.position.x = c[1];
+ frect.position.y = c[2];
+ frect.size.x = c[3];
+ frect.size.y = c[4];
+ Point2 align(c[6], c[5]);
+ int advance = c[7];
+
+ font->bitmap_add_char(chr, 0, frect, align, advance);
+ }
+
+ for (int i = 0; i < p_kerning_count; i++) {
+ font->bitmap_add_kerning_pair(p_kernings[i * 3 + 0], p_kernings[i * 3 + 1], p_kernings[i * 3 + 2]);
+ }
+
+ return font;
+}
+
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));
@@ -210,7 +242,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "LinkButton", control_font_color);
theme->set_color("font_pressed_color", "LinkButton", control_font_pressed_color);
theme->set_color("font_hover_color", "LinkButton", control_font_hover_color);
+ 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);
// ColorPickerButton
@@ -228,8 +262,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1));
theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1));
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("hseparation", "ColorPickerButton", 2 * scale);
+ theme->set_constant("outline_size", "ColorPickerButton", 0);
// OptionButton
@@ -265,9 +301,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_hover_color", "OptionButton", control_font_hover_color);
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("hseparation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 2 * scale);
+ theme->set_constant("outline_size", "OptionButton", 0);
// MenuButton
@@ -284,8 +322,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_pressed_color", "MenuButton", control_font_pressed_color);
theme->set_color("font_hover_color", "MenuButton", control_font_hover_color);
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("hseparation", "MenuButton", 3 * scale);
+ theme->set_constant("outline_size", "MenuButton", 0);
// CheckBox
@@ -308,9 +348,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("focus", "CheckBox", cbx_focus);
theme->set_icon("checked", "CheckBox", make_icon(checked_png));
+ theme->set_icon("checked_disabled", "CheckBox", make_icon(checked_disabled_png));
theme->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
+ theme->set_icon("unchecked_disabled", "CheckBox", make_icon(unchecked_disabled_png));
theme->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
+ theme->set_icon("radio_checked_disabled", "CheckBox", make_icon(radio_checked_disabled_png));
theme->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
+ theme->set_icon("radio_unchecked_disabled", "CheckBox", make_icon(radio_unchecked_disabled_png));
theme->set_font("font", "CheckBox", Ref<Font>());
theme->set_font_size("font_size", "CheckBox", -1);
@@ -320,9 +364,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_hover_color", "CheckBox", control_font_hover_color);
theme->set_color("font_hover_pressed_color", "CheckBox", control_font_pressed_color);
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("hseparation", "CheckBox", 4 * scale);
theme->set_constant("check_vadjust", "CheckBox", 0 * scale);
+ theme->set_constant("outline_size", "CheckBox", 0);
// CheckButton
@@ -357,9 +403,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_hover_color", "CheckButton", control_font_hover_color);
theme->set_color("font_hover_pressed_color", "CheckButton", control_font_pressed_color);
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("hseparation", "CheckButton", 4 * scale);
theme->set_constant("check_vadjust", "CheckButton", 0 * scale);
+ theme->set_constant("outline_size", "CheckButton", 0);
// Label
@@ -373,7 +421,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("shadow_offset_x", "Label", 1 * scale);
theme->set_constant("shadow_offset_y", "Label", 1 * scale);
- theme->set_constant("outline_size", "Label", 0 * 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);
@@ -389,12 +437,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "LineEdit", control_font_color);
theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0));
theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
- theme->set_color("cursor_color", "LineEdit", control_font_hover_color);
+ theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1));
+ theme->set_color("caret_color", "LineEdit", control_font_hover_color);
theme->set_color("selection_color", "LineEdit", control_selection_color);
theme->set_color("clear_button_color", "LineEdit", control_font_color);
theme->set_color("clear_button_color_pressed", "LineEdit", control_font_pressed_color);
- theme->set_constant("minimum_spaces", "LineEdit", 12 * scale);
+ theme->set_constant("minimum_character_width", "LineEdit", 4);
+ theme->set_constant("outline_size", "LineEdit", 0);
theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png));
@@ -408,6 +458,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ProgressBar", control_font_hover_color);
theme->set_color("font_shadow_color", "ProgressBar", Color(0, 0, 0));
+ theme->set_color("font_outline_color", "ProgressBar", Color(1, 1, 1));
+
+ theme->set_constant("outline_size", "ProgressBar", 0);
// TextEdit
@@ -431,6 +484,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "TextEdit", control_font_color);
theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
theme->set_color("selection_color", "TextEdit", control_selection_color);
theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
@@ -444,8 +498,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_max_width", "TextEdit", 50);
theme->set_constant("completion_scroll_width", "TextEdit", 3);
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
+ theme->set_constant("outline_size", "TextEdit", 0);
// CodeEdit
+
theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_stylebox("focus", "CodeEdit", focus);
theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
@@ -471,6 +527,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "CodeEdit", control_font_color);
theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
+ theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
theme->set_color("selection_color", "CodeEdit", control_selection_color);
theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8));
@@ -489,6 +546,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("completion_max_width", "CodeEdit", 50);
theme->set_constant("completion_scroll_width", "CodeEdit", 3);
theme->set_constant("line_spacing", "CodeEdit", 4 * scale);
+ theme->set_constant("outline_size", "CodeEdit", 0);
Ref<Texture2D> empty_icon = memnew(ImageTexture);
@@ -544,7 +602,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png));
- //scroll container
+ // ScrollContainer
+
Ref<StyleBoxEmpty> empty;
empty.instance();
theme->set_stylebox("bg", "ScrollContainer", empty);
@@ -556,7 +615,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("scaleborder_size", "Window", 4 * scale);
theme->set_font("title_font", "Window", large_font);
+ theme->set_font_size("title_font_size", "Window", -1);
+
theme->set_color("title_color", "Window", Color(0, 0, 0));
+ 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", 20 * scale);
theme->set_constant("resize_margin", "Window", 4 * scale);
@@ -568,6 +632,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// File Dialog
theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png));
+ theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png));
+ theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png));
theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png));
theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png));
@@ -611,9 +677,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_disabled_color", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8));
theme->set_color("font_hover_color", "PopupMenu", control_font_color);
theme->set_color("font_separator_color", "PopupMenu", control_font_color);
+ theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_constant("hseparation", "PopupMenu", 4 * scale);
theme->set_constant("vseparation", "PopupMenu", 4 * scale);
+ theme->set_constant("outline_size", "PopupMenu", 0);
+ theme->set_constant("item_start_padding", "PopupMenu", 2 * scale);
+ theme->set_constant("item_end_padding", "PopupMenu", 2 * scale);
// GraphNode
@@ -682,6 +752,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("title_button_color", "Tree", control_font_color);
theme->set_color("font_color", "Tree", control_font_low_color);
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
+ theme->set_color("font_outline_color", "Tree", Color(1, 1, 1));
theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1));
theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
@@ -695,8 +766,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("draw_guides", "Tree", 1);
theme->set_constant("scroll_border", "Tree", 4);
theme->set_constant("scroll_speed", "Tree", 12);
+ theme->set_constant("outline_size", "Tree", 0);
// ItemList
+
Ref<StyleBoxTexture> item_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 2, 8, 2);
Ref<StyleBoxTexture> item_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 2, 8, 2);
@@ -712,12 +785,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ItemList", control_font_lower_color);
theme->set_color("font_selected_color", "ItemList", control_font_pressed_color);
+ theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1));
theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1));
theme->set_stylebox("selected", "ItemList", item_selected_oof);
theme->set_stylebox("selected_focus", "ItemList", item_selected);
theme->set_stylebox("cursor", "ItemList", focus);
theme->set_stylebox("cursor_unfocused", "ItemList", focus);
+ theme->set_constant("outline_size", "ItemList", 0);
+
// TabContainer
Ref<StyleBoxTexture> tc_sb = sb_expand(make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 4, 4, 4, 4), 3, 3, 3, 3);
@@ -743,16 +819,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "TabContainer", control_font_hover_color);
theme->set_color("font_unselected_color", "TabContainer", control_font_low_color);
theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color);
+ theme->set_color("font_outline_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("outline_size", "TabContainer", 0);
// Tabs
theme->set_stylebox("tab_selected", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2));
theme->set_stylebox("tab_unselected", "Tabs", sb_expand(make_stylebox(tab_behind_png, 5, 4, 5, 1, 16, 5, 16, 2), 3, 3, 3, 3));
theme->set_stylebox("tab_disabled", "Tabs", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3));
- theme->set_stylebox("panel", "Tabs", tc_sb);
theme->set_stylebox("button_pressed", "Tabs", make_stylebox(button_pressed_png, 4, 4, 4, 4));
theme->set_stylebox("button", "Tabs", make_stylebox(button_normal_png, 4, 4, 4, 4));
@@ -768,8 +845,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "Tabs", control_font_hover_color);
theme->set_color("font_unselected_color", "Tabs", control_font_low_color);
theme->set_color("font_disabled_color", "Tabs", control_font_disabled_color);
+ theme->set_color("font_outline_color", "Tabs", Color(1, 1, 1));
theme->set_constant("hseparation", "Tabs", 4 * scale);
+ theme->set_constant("outline_size", "Tabs", 0);
// Separators
@@ -810,6 +889,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("color_sample", "ColorPicker", make_icon(color_picker_sample_png));
theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png));
theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png));
+ theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png));
+ theme->set_icon("picker_cursor", "ColorPicker", make_icon(picker_cursor_png));
theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png));
@@ -827,9 +908,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "TooltipLabel", Color(0, 0, 0));
theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0.1));
+ theme->set_color("font_outline_color", "TooltipLabel", Color(1, 1, 1));
theme->set_constant("shadow_offset_x", "TooltipLabel", 1);
theme->set_constant("shadow_offset_y", "TooltipLabel", 1);
+ theme->set_constant("outline_size", "TooltipLabel", 0);
// RichTextLabel
@@ -854,6 +937,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
+ 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_as_outline", "RichTextLabel", 0 * scale);
@@ -862,9 +947,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
+ theme->set_constant("outline_size", "RichTextLabel", 0);
+
theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
+
// Containers
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));
@@ -904,6 +992,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale);
// Visual Node Ports
+
theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
@@ -935,45 +1024,15 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
Ref<StyleBox> default_style;
Ref<Texture2D> default_icon;
Ref<Font> default_font;
- int default_font_size = 16;
+ int default_font_size = 14;
if (p_font.is_valid()) {
default_font = p_font;
} else if (p_hidpi) {
- TextServer::BitmapFontData data;
- data.height = _hidpi_font_height;
- data.ascent = _hidpi_font_ascent;
- data.charcount = _hidpi_font_charcount;
- data.char_rects = &_hidpi_font_charrects[0][0];
- data.kerning_count = _hidpi_font_kerning_pair_count;
- data.kernings = &_hidpi_font_kerning_pairs[0][0];
- data.w = _hidpi_font_img_width;
- data.h = _hidpi_font_img_height;
- data.img = _hidpi_font_img_data;
-
- Ref<FontData> font_data;
- font_data.instance();
- font_data->load_memory((const uint8_t *)&data, sizeof(data), "fnt");
- default_font_size = font_data->get_base_size();
-
+ Ref<FontData> font_data = make_font(_hidpi_font_height, _hidpi_font_ascent, _hidpi_font_charcount, &_hidpi_font_charrects[0][0], _hidpi_font_kerning_pair_count, &_hidpi_font_kerning_pairs[0][0], _hidpi_font_img_width, _hidpi_font_img_height, _hidpi_font_img_data);
default_font.instance();
default_font->add_data(font_data);
} else {
- TextServer::BitmapFontData data;
- data.height = _lodpi_font_height;
- data.ascent = _lodpi_font_ascent;
- data.charcount = _lodpi_font_charcount;
- data.char_rects = &_lodpi_font_charrects[0][0];
- data.kerning_count = _lodpi_font_kerning_pair_count;
- data.kernings = &_lodpi_font_kerning_pairs[0][0];
- data.w = _lodpi_font_img_width;
- data.h = _lodpi_font_img_height;
- data.img = _lodpi_font_img_data;
-
- Ref<FontData> font_data;
- font_data.instance();
- font_data->load_memory((const uint8_t *)&data, sizeof(data), "fnt");
- default_font_size = font_data->get_base_size();
-
+ Ref<FontData> font_data = make_font(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data);
default_font.instance();
default_font->add_data(font_data);
}
diff --git a/scene/resources/default_theme/picker_cursor.png b/scene/resources/default_theme/picker_cursor.png
new file mode 100644
index 0000000000..2f403492d2
--- /dev/null
+++ b/scene/resources/default_theme/picker_cursor.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_checked_disabled.png b/scene/resources/default_theme/radio_checked_disabled.png
new file mode 100644
index 0000000000..72f08ecb96
--- /dev/null
+++ b/scene/resources/default_theme/radio_checked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_unchecked_disabled.png b/scene/resources/default_theme/radio_unchecked_disabled.png
new file mode 100644
index 0000000000..a8f4c1b555
--- /dev/null
+++ b/scene/resources/default_theme/radio_unchecked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index b905c9db69..190f2a03d9 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -14,6 +14,10 @@ static const unsigned char arrow_right_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char bar_arrow_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x14, 0x8, 0x4, 0x0, 0x0, 0x0, 0x2e, 0x6b, 0x75, 0xfc, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0xe, 0xc0, 0x1, 0x6a, 0xd6, 0x89, 0x9, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0xfc, 0xcf, 0x80, 0x1f, 0x30, 0x8e, 0x20, 0x5, 0x8c, 0x38, 0x24, 0xff, 0x53, 0x5f, 0xc1, 0xb, 0xee, 0x9f, 0x53, 0x18, 0x18, 0xd8, 0x73, 0x24, 0xbe, 0x62, 0x55, 0x70, 0x5f, 0x83, 0x61, 0x15, 0xa3, 0x2e, 0x3, 0x3, 0xc3, 0xd, 0xe6, 0x30, 0xd9, 0xcb, 0x18, 0xa, 0x1e, 0xc6, 0xfd, 0x9f, 0xc6, 0xc0, 0xd, 0x35, 0xea, 0x3b, 0x63, 0x81, 0xfc, 0x2c, 0x14, 0x5, 0xf, 0x2a, 0x18, 0xda, 0xd1, 0x1c, 0x50, 0xa9, 0xd0, 0x1, 0x57, 0xf0, 0x10, 0x53, 0x9a, 0x81, 0x81, 0x81, 0xa1, 0x52, 0xbe, 0x83, 0x81, 0x81, 0xf1, 0x3f, 0x2e, 0x69, 0xa8, 0x12, 0x3a, 0x4, 0x14, 0x0, 0x7b, 0xda, 0x34, 0x1, 0xbb, 0xb5, 0x3e, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char bookmark_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x93, 0x31, 0xa, 0xc0, 0x30, 0xc, 0x3, 0xa5, 0xd0, 0xff, 0x7f, 0x59, 0x1d, 0x8a, 0x42, 0x8, 0x9, 0x95, 0xc9, 0xd2, 0xa1, 0x9a, 0x8c, 0xf1, 0xdd, 0x62, 0x1b, 0x38, 0xc, 0x87, 0x5a, 0x5, 0xae, 0x79, 0xde, 0x2, 0x1, 0x80, 0x94, 0x39, 0x48, 0x76, 0x49, 0x17, 0xa4, 0xf0, 0x24, 0x61, 0x2b, 0x51, 0x8b, 0xfc, 0x82, 0xcf, 0xb, 0x48, 0x7a, 0xdf, 0x75, 0x81, 0xf, 0xe5, 0x29, 0xf7, 0x92, 0x6b, 0x3, 0x1a, 0x1e, 0xda, 0x7c, 0x3d, 0x77, 0x21, 0x7b, 0xa8, 0x74, 0x2e, 0xcb, 0xd, 0xc8, 0x75, 0x13, 0x28, 0x9, 0xed, 0xc2, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -42,6 +46,10 @@ static const unsigned char checked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char checked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x73, 0x72, 0x7b, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x82, 0x80, 0x8a, 0x90, 0x90, 0x93, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x93, 0x93, 0x95, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x7d, 0x7d, 0x7f, 0x58, 0x58, 0x5b, 0xa4, 0xa4, 0xa4, 0x9e, 0x9e, 0xa0, 0x9e, 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x93, 0x93, 0x94, 0x8f, 0x8f, 0x8f, 0x86, 0x86, 0x88, 0x85, 0x85, 0x86, 0x82, 0x82, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x7c, 0x7e, 0x7a, 0x7a, 0x7d, 0x78, 0x78, 0x7b, 0x71, 0x71, 0x74, 0x68, 0x68, 0x6c, 0x66, 0x66, 0x6a, 0x65, 0x65, 0x68, 0x63, 0x63, 0x66, 0x5f, 0x5f, 0x63, 0x5c, 0x5c, 0x60, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x59, 0x59, 0x5c, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x10, 0x13, 0xbb, 0xf, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xb4, 0xdd, 0xfa, 0xfa, 0xfb, 0xfb, 0x5b, 0xd1, 0xf1, 0xe6, 0x0, 0x0, 0x0, 0x96, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x5d, 0x8f, 0xc9, 0x12, 0x82, 0x30, 0x14, 0x4, 0x87, 0x18, 0x50, 0x51, 0x44, 0x25, 0x42, 0x4, 0x77, 0xc4, 0x8d, 0x97, 0x0, 0xf9, 0xff, 0x8f, 0xb3, 0x88, 0xa4, 0x4a, 0xed, 0x63, 0x5f, 0xa6, 0x7, 0xf8, 0x7, 0x1e, 0xe3, 0x7e, 0x60, 0x19, 0x4f, 0x46, 0x1e, 0x0, 0x36, 0x8d, 0x4c, 0x67, 0x59, 0x65, 0x33, 0x6, 0x80, 0x47, 0xad, 0x56, 0x3d, 0xb7, 0x3c, 0x5d, 0x70, 0x0, 0xbe, 0xd1, 0x44, 0x65, 0x4d, 0x94, 0xc8, 0xc2, 0xf8, 0x0, 0x82, 0x4e, 0x91, 0x94, 0x15, 0x5d, 0xd2, 0xec, 0xde, 0x5, 0x83, 0x38, 0xc8, 0xe3, 0x63, 0x23, 0xce, 0xca, 0x9, 0x7a, 0x6e, 0xf3, 0x93, 0x48, 0x1a, 0x27, 0x14, 0x35, 0x3b, 0xb9, 0x5e, 0x56, 0xe4, 0x84, 0x22, 0xba, 0xa, 0x51, 0xd0, 0xb7, 0xa8, 0xcb, 0xfd, 0xcb, 0x9, 0x3b, 0xfb, 0x41, 0xdb, 0x59, 0x17, 0xa6, 0x94, 0x6e, 0xe3, 0x3e, 0x8c, 0x85, 0xf1, 0x90, 0x6e, 0xe6, 0x21, 0xfb, 0x39, 0xe7, 0x73, 0xe6, 0xfd, 0x5f, 0x7, 0xde, 0xc3, 0xb5, 0x16, 0x87, 0xb0, 0x9e, 0x42, 0x46, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char checker_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -258,6 +266,10 @@ static const unsigned char panel_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char picker_cursor_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xb9, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0x8f, 0x3d, 0x8a, 0xc2, 0x50, 0x18, 0x45, 0xcf, 0x6b, 0x92, 0x2a, 0x19, 0xd4, 0xa4, 0x72, 0x47, 0x3, 0x42, 0xc0, 0x9f, 0x55, 0x44, 0x17, 0x24, 0x88, 0xee, 0x24, 0x53, 0x4d, 0x7e, 0xa, 0xbf, 0x94, 0xd6, 0x71, 0x5, 0xf2, 0x5e, 0x7f, 0x2d, 0xa2, 0xa2, 0xe0, 0x29, 0xef, 0xb9, 0xcd, 0x1, 0x40, 0xb1, 0x76, 0x6a, 0x14, 0x14, 0xd4, 0x68, 0xab, 0x98, 0x11, 0xcd, 0xd5, 0xef, 0x9b, 0xac, 0x27, 0x10, 0x32, 0x3b, 0xb4, 0x32, 0xcd, 0xc7, 0x77, 0xff, 0xfb, 0xc7, 0xc0, 0x92, 0x84, 0x84, 0x82, 0xcb, 0xa2, 0x92, 0x29, 0x46, 0xbb, 0x7d, 0xc3, 0xc0, 0x94, 0x27, 0x13, 0x86, 0x63, 0xa7, 0x12, 0xb5, 0x59, 0xcf, 0x8a, 0x77, 0xd6, 0xb9, 0xa9, 0x46, 0xde, 0x5, 0x92, 0xf, 0x91, 0x3a, 0x2f, 0xff, 0x4d, 0xfc, 0x38, 0xaf, 0x1b, 0x6a, 0x33, 0xa3, 0xf8, 0x10, 0x9b, 0xfc, 0xac, 0x1a, 0x6d, 0xf, 0x2d, 0x17, 0x26, 0xaf, 0x79, 0xc6, 0xf5, 0xd4, 0xa9, 0x44, 0xb1, 0x6c, 0x51, 0x31, 0xb0, 0x26, 0x25, 0x65, 0xc3, 0xb5, 0xa8, 0x64, 0x8a, 0xc6, 0x40, 0x3b, 0x76, 0xb9, 0xb9, 0xe0, 0x42, 0x7e, 0x3e, 0x75, 0x8f, 0x40, 0x0, 0x45, 0x2a, 0x55, 0xcb, 0xcb, 0xeb, 0x5f, 0xa5, 0x22, 0x80, 0x3b, 0xa0, 0x2c, 0x6c, 0xa1, 0x40, 0x2f, 0xda, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char popup_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa2, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x36, 0xc6, 0xc8, 0x93, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8f, 0x35, 0x82, 0xc3, 0x0, 0xc, 0x4, 0x77, 0x24, 0x85, 0xba, 0xe3, 0xff, 0xff, 0xee, 0xca, 0x74, 0x41, 0xdb, 0x32, 0xf3, 0x94, 0x82, 0x85, 0x10, 0x1d, 0x92, 0xb2, 0x3, 0x8e, 0x95, 0x77, 0x93, 0x6c, 0x28, 0xed, 0x15, 0x54, 0x67, 0xa6, 0x41, 0x3e, 0x8, 0x9c, 0xc3, 0xf4, 0xf2, 0xf6, 0x2a, 0x80, 0xf8, 0x44, 0x2d, 0x79, 0x2d, 0x20, 0xe0, 0x2, 0xa8, 0xc3, 0x2e, 0x6f, 0xc, 0x9e, 0x4c, 0x3c, 0x21, 0x4, 0xd8, 0xf0, 0x2, 0x28, 0x24, 0xcd, 0x3, 0xa9, 0x19, 0x64, 0xce, 0x83, 0x4c, 0x45, 0xe6, 0x69, 0x1a, 0xd8, 0xe9, 0x99, 0x96, 0x7f, 0x77, 0x37, 0x59, 0x83, 0xcc, 0xef, 0x7f, 0x89, 0x1f, 0x8e, 0xbf, 0x95, 0xd3, 0x1d, 0xf0, 0xff, 0x7a, 0x63, 0x7e, 0x86, 0xcb, 0x73, 0x8c, 0x5e, 0xee, 0xca, 0xb1, 0xad, 0x5f, 0x3, 0xaf, 0xdb, 0x49, 0x94, 0x4b, 0x90, 0x40, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -282,10 +294,18 @@ static const unsigned char radio_checked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char radio_checked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x83, 0xac, 0xe9, 0xaf, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x20, 0xe, 0xf0, 0x8, 0x2, 0x1, 0xf, 0x9c, 0x2b, 0x2c, 0x8, 0x5, 0xc2, 0x50, 0x1, 0xb0, 0x34, 0x58, 0x11, 0x5c, 0xbd, 0x10, 0x3f, 0x10, 0x8, 0xc1, 0x74, 0x1, 0x65, 0xf8, 0xc1, 0x0, 0xa6, 0x4, 0x28, 0x1, 0x11, 0xe0, 0xc1, 0x2d, 0x80, 0xa6, 0x5, 0xc3, 0x50, 0xc, 0x6b, 0x31, 0x1d, 0x86, 0xe1, 0x74, 0xfc, 0x0, 0x0, 0x1b, 0xc, 0x7, 0xb9, 0xa, 0x5e, 0x2e, 0x12, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char radio_unchecked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char radio_unchecked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x54, 0x54, 0x54, 0xad, 0xad, 0xad, 0x80, 0x80, 0x81, 0x64, 0x64, 0x64, 0xf4, 0x17, 0x36, 0x28, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1b, 0xfc, 0xf6, 0x4, 0xd4, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x7d, 0x8d, 0xb1, 0x11, 0x80, 0x40, 0xc, 0xc3, 0x94, 0xd, 0x12, 0x60, 0x1, 0xc4, 0x4, 0xb0, 0x1, 0xfb, 0x2f, 0x45, 0xe5, 0x3b, 0xaa, 0x57, 0xe5, 0xc2, 0xb6, 0x20, 0xc0, 0xcc, 0xc, 0x40, 0xed, 0x7a, 0x37, 0x70, 0xa8, 0xbe, 0x50, 0x9b, 0xea, 0xd9, 0xd4, 0xa3, 0x7a, 0x35, 0xa5, 0xaa, 0xeb, 0x90, 0x72, 0xe6, 0x39, 0xfc, 0x2b, 0x22, 0xd, 0x1f, 0xe7, 0x64, 0xa, 0x5d, 0x6c, 0xfe, 0xc1, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char scroll_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -430,6 +450,10 @@ static const unsigned char unchecked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char unchecked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x58, 0x58, 0x5b, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x27, 0xa1, 0xa6, 0x53, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xb4, 0xfa, 0xfa, 0xfb, 0xc7, 0x8b, 0xf6, 0x7e, 0x0, 0x0, 0x0, 0x52, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xb5, 0xcf, 0x31, 0x12, 0xc0, 0x20, 0x8, 0x44, 0xd1, 0x15, 0x50, 0x83, 0x11, 0xe5, 0xfe, 0xa7, 0xcd, 0xe8, 0xc4, 0x22, 0xf4, 0x79, 0xe5, 0x36, 0x7c, 0x80, 0x8, 0x89, 0x58, 0xf2, 0x26, 0x4c, 0x9, 0x0, 0x15, 0xf5, 0xb9, 0xb9, 0x16, 0x2, 0xc0, 0x3a, 0xac, 0x6f, 0x36, 0x94, 0x1, 0x88, 0xdb, 0xfd, 0x32, 0x17, 0x0, 0x79, 0xf6, 0x33, 0xf4, 0x99, 0xff, 0x1a, 0xe2, 0xd9, 0x4f, 0x58, 0x5b, 0x61, 0x54, 0xdb, 0x49, 0xbf, 0xea, 0x4a, 0x8f, 0xcf, 0x45, 0xf, 0x4, 0x40, 0x7, 0x90, 0xb0, 0x7b, 0x47, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char updown_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/default_theme/unchecked_disabled.png b/scene/resources/default_theme/unchecked_disabled.png
new file mode 100644
index 0000000000..bef9316f58
--- /dev/null
+++ b/scene/resources/default_theme/unchecked_disabled.png
Binary files differ
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 8827da1fc4..c04b271d81 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -44,7 +44,7 @@ RID Environment::get_rid() const {
void Environment::set_background(BGMode p_bg) {
bg_mode = p_bg;
RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg));
- _change_notify();
+ notify_property_list_changed();
if (bg_mode != BG_SKY) {
set_fog_aerial_perspective(0.0);
}
@@ -138,7 +138,7 @@ Color Environment::get_ambient_light_color() const {
void Environment::set_ambient_source(AmbientSource p_source) {
ambient_source = p_source;
_update_ambient_light();
- _change_notify();
+ notify_property_list_changed();
}
Environment::AmbientSource Environment::get_ambient_source() const {
@@ -166,7 +166,7 @@ float Environment::get_ambient_light_sky_contribution() const {
void Environment::set_reflection_source(ReflectionSource p_source) {
reflection_source = p_source;
_update_ambient_light();
- _change_notify();
+ notify_property_list_changed();
}
Environment::ReflectionSource Environment::get_reflection_source() const {
@@ -224,7 +224,7 @@ float Environment::get_tonemap_white() const {
void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) {
tonemap_auto_exposure_enabled = p_enabled;
_update_tonemap();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_tonemap_auto_exposure_enabled() const {
@@ -285,7 +285,7 @@ void Environment::_update_tonemap() {
void Environment::set_ssr_enabled(bool p_enabled) {
ssr_enabled = p_enabled;
_update_ssr();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_ssr_enabled() const {
@@ -343,7 +343,7 @@ void Environment::_update_ssr() {
void Environment::set_ssao_enabled(bool p_enabled) {
ssao_enabled = p_enabled;
_update_ssao();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_ssao_enabled() const {
@@ -441,6 +441,7 @@ void Environment::_update_ssao() {
void Environment::set_sdfgi_enabled(bool p_enabled) {
sdfgi_enabled = p_enabled;
_update_sdfgi();
+ notify_property_list_changed();
}
bool Environment::is_sdfgi_enabled() const {
@@ -458,8 +459,6 @@ Environment::SDFGICascades Environment::get_sdfgi_cascades() const {
void Environment::set_sdfgi_min_cell_size(float p_size) {
sdfgi_min_cell_size = p_size;
- _change_notify("sdfgi_max_distance");
- _change_notify("sdfgi_cascade0_distance");
_update_sdfgi();
}
@@ -475,8 +474,6 @@ void Environment::set_sdfgi_max_distance(float p_distance) {
p_distance *= 0.5; //halve for each cascade
}
sdfgi_min_cell_size = p_distance;
- _change_notify("sdfgi_min_cell_size");
- _change_notify("sdfgi_cascade0_distance");
_update_sdfgi();
}
@@ -493,8 +490,6 @@ float Environment::get_sdfgi_max_distance() const {
void Environment::set_sdfgi_cascade0_distance(float p_distance) {
sdfgi_min_cell_size = p_distance / 64.0;
- _change_notify("sdfgi_min_cell_size");
- _change_notify("sdfgi_max_distance");
_update_sdfgi();
}
@@ -520,13 +515,12 @@ bool Environment::is_sdfgi_using_occlusion() const {
return sdfgi_use_occlusion;
}
-void Environment::set_sdfgi_use_multi_bounce(bool p_enabled) {
- sdfgi_use_multibounce = p_enabled;
+void Environment::set_sdfgi_bounce_feedback(float p_amount) {
+ sdfgi_bounce_feedback = p_amount;
_update_sdfgi();
}
-
-bool Environment::is_sdfgi_using_multi_bounce() const {
- return sdfgi_use_multibounce;
+float Environment::get_sdfgi_bounce_feedback() const {
+ return sdfgi_bounce_feedback;
}
void Environment::set_sdfgi_read_sky_light(bool p_enabled) {
@@ -573,7 +567,7 @@ void Environment::_update_sdfgi() {
sdfgi_min_cell_size,
RS::EnvironmentSDFGIYScale(sdfgi_y_scale),
sdfgi_use_occlusion,
- sdfgi_use_multibounce,
+ sdfgi_bounce_feedback,
sdfgi_read_sky_light,
sdfgi_energy,
sdfgi_normal_bias,
@@ -585,7 +579,7 @@ void Environment::_update_sdfgi() {
void Environment::set_glow_enabled(bool p_enabled) {
glow_enabled = p_enabled;
_update_glow();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_glow_enabled() const {
@@ -655,7 +649,7 @@ float Environment::get_glow_bloom() const {
void Environment::set_glow_blend_mode(GlowBlendMode p_mode) {
glow_blend_mode = p_mode;
_update_glow();
- _change_notify();
+ notify_property_list_changed();
}
Environment::GlowBlendMode Environment::get_glow_blend_mode() const {
@@ -723,7 +717,7 @@ void Environment::_update_glow() {
void Environment::set_fog_enabled(bool p_enabled) {
fog_enabled = p_enabled;
_update_fog();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_fog_enabled() const {
@@ -803,7 +797,7 @@ void Environment::_update_volumetric_fog() {
void Environment::set_volumetric_fog_enabled(bool p_enable) {
volumetric_fog_enabled = p_enable;
_update_volumetric_fog();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_volumetric_fog_enabled() const {
@@ -875,7 +869,7 @@ float Environment::get_volumetric_fog_temporal_reprojection_amount() const {
void Environment::set_adjustment_enabled(bool p_enabled) {
adjustment_enabled = p_enabled;
_update_adjustment();
- _change_notify();
+ notify_property_list_changed();
}
bool Environment::is_adjustment_enabled() const {
@@ -990,6 +984,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
"auto_exposure_",
"ss_reflections_",
"ssao_",
+ "sdfgi_",
"glow_",
"adjustment_",
nullptr
@@ -1207,8 +1202,8 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_sdfgi_y_scale"), &Environment::get_sdfgi_y_scale);
ClassDB::bind_method(D_METHOD("set_sdfgi_use_occlusion", "enable"), &Environment::set_sdfgi_use_occlusion);
ClassDB::bind_method(D_METHOD("is_sdfgi_using_occlusion"), &Environment::is_sdfgi_using_occlusion);
- ClassDB::bind_method(D_METHOD("set_sdfgi_use_multi_bounce", "enable"), &Environment::set_sdfgi_use_multi_bounce);
- ClassDB::bind_method(D_METHOD("is_sdfgi_using_multi_bounce"), &Environment::is_sdfgi_using_multi_bounce);
+ ClassDB::bind_method(D_METHOD("set_sdfgi_bounce_feedback", "amount"), &Environment::set_sdfgi_bounce_feedback);
+ ClassDB::bind_method(D_METHOD("get_sdfgi_bounce_feedback"), &Environment::get_sdfgi_bounce_feedback);
ClassDB::bind_method(D_METHOD("set_sdfgi_read_sky_light", "enable"), &Environment::set_sdfgi_read_sky_light);
ClassDB::bind_method(D_METHOD("is_sdfgi_reading_sky_light"), &Environment::is_sdfgi_reading_sky_light);
ClassDB::bind_method(D_METHOD("set_sdfgi_energy", "amount"), &Environment::set_sdfgi_energy);
@@ -1220,9 +1215,9 @@ void Environment::_bind_methods() {
ADD_GROUP("SDFGI", "sdfgi_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_enabled"), "set_sdfgi_enabled", "is_sdfgi_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_multi_bounce"), "set_sdfgi_use_multi_bounce", "is_sdfgi_using_multi_bounce");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_occlusion"), "set_sdfgi_use_occlusion", "is_sdfgi_using_occlusion");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_read_sky_light"), "set_sdfgi_read_sky_light", "is_sdfgi_reading_sky_light");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_ENUM, "4 Cascades,6 Cascades,8 Cascades"), "set_sdfgi_cascades", "get_sdfgi_cascades");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance");
@@ -1428,7 +1423,7 @@ Environment::Environment() {
_update_fog();
_update_adjustment();
_update_volumetric_fog();
- _change_notify();
+ notify_property_list_changed();
}
Environment::~Environment() {
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index 6eb0e0607e..0df2c3cc27 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -103,7 +103,7 @@ private:
// Background
BGMode bg_mode = BG_CLEAR_COLOR;
Ref<Sky> bg_sky;
- float bg_sky_custom_fov = 0;
+ float bg_sky_custom_fov = 0.0;
Vector3 bg_sky_rotation;
Color bg_color;
float bg_energy = 1.0;
@@ -125,7 +125,7 @@ private:
float tonemap_white = 1.0;
bool tonemap_auto_exposure_enabled = false;
float tonemap_auto_exposure_min = 0.05;
- float tonemap_auto_exposure_max = 8;
+ float tonemap_auto_exposure_max = 8.0;
float tonemap_auto_exposure_speed = 0.5;
float tonemap_auto_exposure_grey = 0.4;
void _update_tonemap();
@@ -156,7 +156,7 @@ private:
float sdfgi_min_cell_size = 0.2;
SDFGIYScale sdfgi_y_scale = SDFGI_Y_SCALE_DISABLED;
bool sdfgi_use_occlusion = false;
- bool sdfgi_use_multibounce = false;
+ float sdfgi_bounce_feedback = 0.0;
bool sdfgi_read_sky_light = false;
float sdfgi_energy = 1.0;
float sdfgi_normal_bias = 1.1;
@@ -318,8 +318,8 @@ public:
SDFGIYScale get_sdfgi_y_scale() const;
void set_sdfgi_use_occlusion(bool p_enabled);
bool is_sdfgi_using_occlusion() const;
- void set_sdfgi_use_multi_bounce(bool p_enabled);
- bool is_sdfgi_using_multi_bounce() const;
+ void set_sdfgi_bounce_feedback(float p_amount);
+ float get_sdfgi_bounce_feedback() const;
void set_sdfgi_read_sky_light(bool p_enabled);
bool is_sdfgi_reading_sky_light() const;
void set_sdfgi_energy(float p_energy);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 1c06d7b519..6f87c524d8 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -39,6 +39,11 @@
void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_resource", "filename", "base_size"), &FontData::load_resource, DEFVAL(16));
ClassDB::bind_method(D_METHOD("load_memory", "data", "type", "base_size"), &FontData::_load_memory, DEFVAL(16));
+ ClassDB::bind_method(D_METHOD("new_bitmap", "height", "ascent", "base_size"), &FontData::new_bitmap);
+
+ ClassDB::bind_method(D_METHOD("bitmap_add_texture", "texture"), &FontData::bitmap_add_texture);
+ ClassDB::bind_method(D_METHOD("bitmap_add_char", "char", "texture_idx", "rect", "align", "advance"), &FontData::bitmap_add_char);
+ ClassDB::bind_method(D_METHOD("bitmap_add_kerning_pair", "A", "B", "kerning"), &FontData::bitmap_add_kerning_pair);
ClassDB::bind_method(D_METHOD("set_data_path", "path"), &FontData::set_data_path);
ClassDB::bind_method(D_METHOD("get_data_path"), &FontData::get_data_path);
@@ -50,6 +55,9 @@ void FontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &FontData::get_underline_position);
ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &FontData::get_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_spacing", "type"), &FontData::get_spacing);
+ ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &FontData::set_spacing);
+
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased);
@@ -100,6 +108,13 @@ void FontData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_field_hint"), "set_distance_field_hint", "get_distance_field_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
+
+ ADD_GROUP("Extra Spacing", "extra_spacing");
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_glyph"), "set_spacing", "get_spacing", SPACING_GLYPH);
+ ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE);
+
+ BIND_ENUM_CONSTANT(SPACING_GLYPH);
+ BIND_ENUM_CONSTANT(SPACING_SPACE);
}
bool FontData::_set(const StringName &p_name, const Variant &p_value) {
@@ -177,6 +192,14 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void FontData::reset_state() {
+ if (rid != RID()) {
+ TS->free(rid);
+ }
+ base_size = 16;
+ path = String();
+}
+
RID FontData::get_rid() const {
return rid;
}
@@ -211,6 +234,34 @@ void FontData::load_memory(const uint8_t *p_data, size_t p_size, const String &p
emit_changed();
}
+void FontData::new_bitmap(float p_height, float p_ascent, int p_base_size) {
+ if (rid != RID()) {
+ TS->free(rid);
+ }
+ rid = TS->create_font_bitmap(p_height, p_ascent, p_base_size);
+ path = TTR("(Bitmap: " + String::num_int64(rid.get_id(), 16, true) + ")");
+ base_size = TS->font_get_base_size(rid);
+ emit_changed();
+}
+
+void FontData::bitmap_add_texture(const Ref<Texture> &p_texture) {
+ if (rid != RID()) {
+ TS->font_bitmap_add_texture(rid, p_texture);
+ }
+}
+
+void FontData::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+ if (rid != RID()) {
+ TS->font_bitmap_add_char(rid, p_char, p_texture_idx, p_rect, p_align, p_advance);
+ }
+}
+
+void FontData::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) {
+ if (rid != RID()) {
+ TS->font_bitmap_add_kerning_pair(rid, p_A, p_B, p_kerning);
+ }
+}
+
void FontData::set_data_path(const String &p_path) {
load_resource(p_path, base_size);
}
@@ -281,6 +332,27 @@ double FontData::get_variation(const String &p_name) const {
return TS->font_get_variation(rid, p_name);
}
+int FontData::get_spacing(int p_type) const {
+ if (rid == RID()) {
+ return 0;
+ }
+ if (p_type == SPACING_GLYPH) {
+ return TS->font_get_spacing_glyph(rid);
+ } else {
+ return TS->font_get_spacing_space(rid);
+ }
+}
+
+void FontData::set_spacing(int p_type, int p_value) {
+ ERR_FAIL_COND(rid == RID());
+ if (p_type == SPACING_GLYPH) {
+ TS->font_set_spacing_glyph(rid, p_value);
+ } else {
+ TS->font_set_spacing_space(rid, p_value);
+ }
+ emit_changed();
+}
+
void FontData::set_antialiased(bool p_antialiased) {
ERR_FAIL_COND(rid == RID());
TS->font_set_antialiased(rid, p_antialiased);
@@ -509,7 +581,7 @@ void Font::_data_changed() {
cache_wrap.clear();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
bool Font::_set(const StringName &p_name, const Variant &p_value) {
@@ -588,6 +660,14 @@ void Font::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData"));
}
+void Font::reset_state() {
+ spacing_top = 0;
+ spacing_bottom = 0;
+ cache.clear();
+ cache_wrap.clear();
+ data.clear();
+}
+
void Font::add_data(const Ref<FontData> &p_data) {
ERR_FAIL_COND(p_data.is_null());
data.push_back(p_data);
@@ -600,7 +680,7 @@ void Font::add_data(const Ref<FontData> &p_data) {
cache_wrap.clear();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
@@ -621,7 +701,7 @@ void Font::set_data(int p_idx, const Ref<FontData> &p_data) {
cache_wrap.clear();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
int Font::get_data_count() const {
@@ -646,7 +726,7 @@ void Font::remove_data(int p_idx) {
cache_wrap.clear();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
Dictionary Font::get_feature_list() const {
@@ -718,7 +798,7 @@ void Font::set_spacing(int p_type, int p_value) {
}
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
// Drawing string and string sizes, cached.
@@ -781,6 +861,8 @@ Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p
}
void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+ ERR_FAIL_COND(data.is_empty());
+
uint64_t hash = p_text.hash64();
hash = hash_djb2_one_64(p_size, hash);
@@ -811,6 +893,8 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
}
void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+ ERR_FAIL_COND(data.is_empty());
+
uint64_t hash = p_text.hash64();
hash = hash_djb2_one_64(p_size, hash);
@@ -951,7 +1035,7 @@ Font::~Font() {
/*************************************************************************/
-RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -1006,7 +1090,7 @@ String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const {
#ifndef DISABLE_DEPRECATED
-RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 086226c082..200373aa8c 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -42,6 +42,13 @@
class FontData : public Resource {
GDCLASS(FontData, Resource);
+public:
+ enum SpacingType {
+ SPACING_GLYPH,
+ SPACING_SPACE,
+ };
+
+private:
RID rid;
int base_size = 16;
String path;
@@ -53,6 +60,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public:
virtual RID get_rid() const override;
@@ -60,6 +69,12 @@ public:
void load_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16);
void _load_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16);
+ void new_bitmap(float p_height, float p_ascent, int p_base_size = 16);
+
+ void bitmap_add_texture(const Ref<Texture> &p_texture);
+ void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance);
+ void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning);
+
void set_data_path(const String &p_path);
String get_data_path() const;
@@ -76,6 +91,9 @@ public:
float get_underline_position(int p_size) const;
float get_underline_thickness(int p_size) const;
+ int get_spacing(int p_type) const;
+ void set_spacing(int p_type, int p_value);
+
void set_antialiased(bool p_antialiased);
bool get_antialiased() const;
@@ -132,7 +150,7 @@ class Font : public Resource {
public:
enum SpacingType {
SPACING_TOP,
- SPACING_BOTTOM
+ SPACING_BOTTOM,
};
private:
@@ -151,6 +169,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
void _data_changed();
public:
@@ -195,13 +215,14 @@ public:
~Font();
};
+VARIANT_ENUM_CAST(FontData::SpacingType);
VARIANT_ENUM_CAST(Font::SpacingType);
/*************************************************************************/
class ResourceFormatLoaderFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
@@ -212,7 +233,7 @@ public:
class ResourceFormatLoaderCompatFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index b87235518f..7b9b942142 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -39,7 +39,6 @@ Gradient::Gradient() {
points.write[0].offset = 0;
points.write[1].color = Color(1, 1, 1, 1);
points.write[1].offset = 1;
- is_sorted = true;
}
Gradient::~Gradient() {
diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h
index 344a3fd283..cf5b179c45 100644
--- a/scene/resources/gradient.h
+++ b/scene/resources/gradient.h
@@ -39,7 +39,7 @@ class Gradient : public Resource {
public:
struct Point {
- float offset;
+ float offset = 0.0;
Color color;
bool operator<(const Point &p_ponit) const {
return offset < p_ponit.offset;
@@ -48,7 +48,7 @@ public:
private:
Vector<Point> points;
- bool is_sorted;
+ bool is_sorted = true;
_FORCE_INLINE_ void _update_sorting() {
if (!is_sorted) {
points.sort();
diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp
index a32cc1c4df..de5da944bc 100644
--- a/scene/resources/height_map_shape_3d.cpp
+++ b/scene/resources/height_map_shape_3d.cpp
@@ -41,10 +41,10 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
Vector2 size(map_width - 1, map_depth - 1);
Vector2 start = size * -0.5;
- const real_t *r = map_data.ptr();
+ const float *r = map_data.ptr();
// reserve some memory for our points..
- points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
+ points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2));
// now set our points
int r_offset = 0;
@@ -65,6 +65,11 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
+ if ((w != map_width - 1) && (d != map_depth - 1)) {
+ points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
+ points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
+ }
+
height.x += 1.0;
}
@@ -100,15 +105,13 @@ void HeightMapShape3D::set_map_width(int p_new) {
int new_size = map_width * map_depth;
map_data.resize(map_width * map_depth);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
notify_change_to_owners();
- _change_notify("map_width");
- _change_notify("map_data");
}
}
@@ -126,15 +129,13 @@ void HeightMapShape3D::set_map_depth(int p_new) {
int new_size = map_width * map_depth;
map_data.resize(new_size);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
_update_shape();
notify_change_to_owners();
- _change_notify("map_depth");
- _change_notify("map_data");
}
}
@@ -150,8 +151,8 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) {
}
// copy
- real_t *w = map_data.ptrw();
- const real_t *r = p_new.ptr();
+ float *w = map_data.ptrw();
+ const float *r = p_new.ptr();
for (int i = 0; i < size; i++) {
float val = r[i];
w[i] = val;
@@ -171,7 +172,6 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) {
_update_shape();
notify_change_to_owners();
- _change_notify("map_data");
}
PackedFloat32Array HeightMapShape3D::get_map_data() const {
@@ -193,16 +193,12 @@ void HeightMapShape3D::_bind_methods() {
HeightMapShape3D::HeightMapShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {
- map_width = 2;
- map_depth = 2;
map_data.resize(map_width * map_depth);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
w[0] = 0.0;
w[1] = 0.0;
w[2] = 0.0;
w[3] = 0.0;
- min_height = 0.0;
- max_height = 0.0;
_update_shape();
}
diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h
index eda405fc06..1219791c56 100644
--- a/scene/resources/height_map_shape_3d.h
+++ b/scene/resources/height_map_shape_3d.h
@@ -36,11 +36,11 @@
class HeightMapShape3D : public Shape3D {
GDCLASS(HeightMapShape3D, Shape3D);
- int map_width;
- int map_depth;
+ int map_width = 2;
+ int map_depth = 2;
PackedFloat32Array map_data;
- float min_height;
- float max_height;
+ real_t min_height = 0.0;
+ real_t max_height = 0.0;
protected:
static void _bind_methods();
diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp
index 2b08c21c34..d206f12287 100644
--- a/scene/resources/line_shape_2d.cpp
+++ b/scene/resources/line_shape_2d.cpp
@@ -113,7 +113,5 @@ void LineShape2D::_bind_methods() {
LineShape2D::LineShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->line_shape_create()) {
- normal = Vector2(0, 1);
- distance = 0;
_update_shape();
}
diff --git a/scene/resources/line_shape_2d.h b/scene/resources/line_shape_2d.h
index 043be1eebe..9f0405ad29 100644
--- a/scene/resources/line_shape_2d.h
+++ b/scene/resources/line_shape_2d.h
@@ -36,8 +36,8 @@
class LineShape2D : public Shape2D {
GDCLASS(LineShape2D, Shape2D);
- Vector2 normal;
- real_t distance;
+ Vector2 normal = Vector2(0, 1);
+ real_t distance = 0.0;
void _update_shape();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 92d2fb1c6d..e8157c7165 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -192,7 +192,7 @@ Variant ShaderMaterial::property_get_revert(const String &p_name) {
void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
// Only connect/disconnect the signal when running in the editor.
- // This can be a slow operation, and `_change_notify()` (which is called by `_shader_changed()`)
+ // 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));
@@ -210,7 +210,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
}
RS::get_singleton()->material_set_shader(_get_material(), rid);
- _change_notify(); //properties for shader exposed
+ notify_property_list_changed(); //properties for shader exposed
emit_changed();
}
@@ -227,7 +227,7 @@ Variant ShaderMaterial::get_shader_param(const StringName &p_param) const {
}
void ShaderMaterial::_shader_changed() {
- _change_notify(); //update all properties
+ notify_property_list_changed(); //update all properties
}
void ShaderMaterial::_bind_methods() {
@@ -543,6 +543,9 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_DISABLE_DEPTH_TEST]) {
code += ",depth_test_disabled";
}
+ if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
+ code += ",particle_trails";
+ }
if (shading_mode == SHADING_MODE_PER_VERTEX) {
code += ",vertex_lighting";
}
@@ -672,7 +675,7 @@ void BaseMaterial3D::_update_shader() {
code += "uniform sampler2D texture_flowmap : hint_aniso," + texfilter_str + ";\n";
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
- code += "uniform sampler2D texture_ambient_occlusion : hint_white;\n";
+ code += "uniform sampler2D texture_ambient_occlusion : hint_white, " + texfilter_str + ";\n";
code += "uniform vec4 ao_texture_channel;\n";
code += "uniform float ao_light_affect;\n";
}
@@ -829,16 +832,26 @@ void BaseMaterial3D::_update_shader() {
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tuv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n";
+ if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
+ code += "\tuv1_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL),vec3(uv1_blend_sharpness));\n";
+ code += "\tuv1_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n";
+ } else {
+ code += "\tuv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n";
+ code += "\tuv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n";
+ }
code += "\tuv1_power_normal/=dot(uv1_power_normal,vec3(1.0));\n";
- code += "\tuv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n";
code += "\tuv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
}
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += "\tuv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n";
+ if (flags[FLAG_UV2_USE_WORLD_TRIPLANAR]) {
+ code += "\tuv2_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));\n";
+ code += "\tuv2_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv2_scale + uv2_offset;\n";
+ } else {
+ code += "\tuv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n";
+ code += "\tuv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n";
+ }
code += "\tuv2_power_normal/=dot(uv2_power_normal,vec3(1.0));\n";
- code += "\tuv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n";
code += "\tuv2_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
}
@@ -1489,7 +1502,7 @@ void BaseMaterial3D::set_transparency(Transparency p_transparency) {
transparency = p_transparency;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
BaseMaterial3D::Transparency BaseMaterial3D::get_transparency() const {
@@ -1503,7 +1516,7 @@ void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) {
alpha_antialiasing_mode = p_alpha_aa;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
BaseMaterial3D::AlphaAntiAliasing BaseMaterial3D::get_alpha_antialiasing() const {
@@ -1517,7 +1530,7 @@ void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) {
shading_mode = p_shading_mode;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
BaseMaterial3D::ShadingMode BaseMaterial3D::get_shading_mode() const {
@@ -1584,8 +1597,11 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
}
flags[p_flag] = p_enabled;
- if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN) {
- _change_notify();
+ if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) {
+ notify_property_list_changed();
+ }
+ if (p_flag == FLAG_PARTICLE_TRAILS_MODE) {
+ update_configuration_warning();
}
_queue_shader_change();
}
@@ -1602,7 +1618,7 @@ void BaseMaterial3D::set_feature(Feature p_feature, bool p_enabled) {
}
features[p_feature] = p_enabled;
- _change_notify();
+ notify_property_list_changed();
_queue_shader_change();
}
@@ -1620,7 +1636,7 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t
RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size,
Vector2i(p_texture->get_width(), p_texture->get_height()));
}
- _change_notify();
+ notify_property_list_changed();
_queue_shader_change();
}
@@ -1650,7 +1666,7 @@ BaseMaterial3D::TextureFilter BaseMaterial3D::get_texture_filter() const {
void BaseMaterial3D::_validate_feature(const String &text, Feature feature, PropertyInfo &property) const {
if (property.name.begins_with(text) && property.name != text + "_enabled" && !features[feature]) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
@@ -1683,19 +1699,27 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if (property.name == "params_grow_amount" && !grow_enabled) {
- property.usage = 0;
+ if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+
+ if (property.name == "grow_amount" && !grow_enabled) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+
+ if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
}
if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NOEDITOR;
}
if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NOEDITOR;
}
- // you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash
+ // you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
const bool can_select_aa = (transparency == TRANSPARENCY_ALPHA_SCISSOR || transparency == TRANSPARENCY_ALPHA_HASH);
// alpha anti aliasiasing is only enabled when you can select aa
const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa;
@@ -1714,7 +1738,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- // we cant choose an antialiasing mode if alpha isnt possible
+ // we can't choose an antialiasing mode if alpha isn't possible
if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
property.usage = 0;
}
@@ -1860,7 +1884,7 @@ float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_billboard_mode(BillboardMode p_mode) {
billboard_mode = p_mode;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const {
@@ -1897,7 +1921,7 @@ bool BaseMaterial3D::get_particles_anim_loop() const {
void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) {
deep_parallax = p_enable;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const {
@@ -1943,7 +1967,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
void BaseMaterial3D::set_grow_enabled(bool p_enable) {
grow_enabled = p_enable;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
bool BaseMaterial3D::is_grow_enabled() const {
@@ -2093,7 +2117,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
void BaseMaterial3D::set_proximity_fade(bool p_enable) {
proximity_fade_enabled = p_enable;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
bool BaseMaterial3D::is_proximity_fade_enabled() const {
@@ -2112,7 +2136,7 @@ float BaseMaterial3D::get_proximity_fade_distance() const {
void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) {
distance_fade = p_mode;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const {
@@ -2159,6 +2183,8 @@ Shader::Mode BaseMaterial3D::get_shader_mode() const {
}
void BaseMaterial3D::_bind_methods() {
+ static_assert(sizeof(MaterialKey) == 16, "MaterialKey should be 16 bytes");
+
ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &BaseMaterial3D::set_albedo);
ClassDB::bind_method(D_METHOD("get_albedo"), &BaseMaterial3D::get_albedo);
@@ -2516,6 +2542,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_proximity_fade_distance", "get_proximity_fade_distance");
@@ -2617,6 +2644,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT);
BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP);
BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN);
+ BIND_ENUM_CONSTANT(FLAG_PARTICLE_TRAILS_MODE);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
@@ -2655,9 +2683,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
element(this) {
orm = p_orm;
// Initialize to the same values as the shader
- shading_mode = SHADING_MODE_PER_PIXEL;
- transparency = TRANSPARENCY_DISABLED;
- alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
set_albedo(Color(1.0, 1.0, 1.0, 1.0));
set_specular(0.5);
set_roughness(1.0);
@@ -2689,7 +2714,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_particles_anim_h_frames(1);
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);
- emission_op = EMISSION_OP_ADD;
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
@@ -2697,8 +2721,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_alpha_hash_scale(1.0);
set_alpha_antialiasing_edge(0.3);
- proximity_fade_enabled = false;
- distance_fade = DISTANCE_FADE_DISABLED;
set_proximity_fade_distance(1);
set_distance_fade_min_distance(0);
set_distance_fade_max_distance(10);
@@ -2710,35 +2732,14 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_ao_texture_channel(TEXTURE_CHANNEL_RED);
set_refraction_texture_channel(TEXTURE_CHANNEL_RED);
- grow_enabled = false;
set_grow(0.0);
- deep_parallax = false;
- heightmap_parallax_flip_tangent = false;
- heightmap_parallax_flip_binormal = false;
set_heightmap_deep_parallax_min_layers(8);
set_heightmap_deep_parallax_max_layers(32);
set_heightmap_deep_parallax_flip_tangent(false); //also sets binormal
- detail_uv = DETAIL_UV_1;
- blend_mode = BLEND_MODE_MIX;
- detail_blend_mode = BLEND_MODE_MIX;
- depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY;
- cull_mode = CULL_BACK;
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
- }
flags[FLAG_USE_TEXTURE_REPEAT] = true;
- diffuse_mode = DIFFUSE_BURLEY;
- specular_mode = SPECULAR_SCHLICK_GGX;
-
- for (int i = 0; i < FEATURE_MAX; i++) {
- features[i] = false;
- }
-
- texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
-
_queue_shader_change();
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 0048b43c8b..ad1b7b3e33 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -235,6 +235,7 @@ public:
FLAG_USE_TEXTURE_REPEAT,
FLAG_INVERT_HEIGHTMAP,
FLAG_SUBSURFACE_MODE_SKIN,
+ FLAG_PARTICLE_TRAILS_MODE,
FLAG_MAX
};
@@ -305,16 +306,15 @@ private:
uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1);
uint64_t emission_op : get_num_bits(EMISSION_OP_MAX - 1);
uint64_t distance_fade : get_num_bits(DISTANCE_FADE_MAX - 1);
-
- // flag bitfield
- uint64_t feature_mask : FEATURE_MAX - 1;
- uint64_t flags : FLAG_MAX - 1;
-
// booleans
uint64_t deep_parallax : 1;
uint64_t grow : 1;
uint64_t proximity_fade : 1;
+ // flag bitfield
+ uint32_t feature_mask;
+ uint32_t flags;
+
MaterialKey() {
memset(this, 0, sizeof(MaterialKey));
}
@@ -330,7 +330,7 @@ private:
struct ShaderData {
RID shader;
- int users;
+ int users = 0;
};
static Map<MaterialKey, ShaderData> shader_map;
@@ -468,16 +468,16 @@ private:
float alpha_scissor_threshold;
float alpha_hash_scale;
float alpha_antialiasing_edge;
- bool grow_enabled;
+ bool grow_enabled = false;
float ao_light_affect;
float grow;
int particles_anim_h_frames;
int particles_anim_v_frames;
bool particles_anim_loop;
- Transparency transparency;
- ShadingMode shading_mode;
+ Transparency transparency = TRANSPARENCY_DISABLED;
+ ShadingMode shading_mode = SHADING_MODE_PER_PIXEL;
- TextureFilter texture_filter;
+ TextureFilter texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
Vector3 uv1_scale;
Vector3 uv1_offset;
@@ -487,39 +487,39 @@ private:
Vector3 uv2_offset;
float uv2_triplanar_sharpness;
- DetailUV detail_uv;
+ DetailUV detail_uv = DETAIL_UV_1;
- bool deep_parallax;
+ bool deep_parallax = false;
int deep_parallax_min_layers;
int deep_parallax_max_layers;
- bool heightmap_parallax_flip_tangent;
- bool heightmap_parallax_flip_binormal;
+ bool heightmap_parallax_flip_tangent = false;
+ bool heightmap_parallax_flip_binormal = false;
- bool proximity_fade_enabled;
+ bool proximity_fade_enabled = false;
float proximity_fade_distance;
- DistanceFadeMode distance_fade;
+ DistanceFadeMode distance_fade = DISTANCE_FADE_DISABLED;
float distance_fade_max_distance;
float distance_fade_min_distance;
- BlendMode blend_mode;
- BlendMode detail_blend_mode;
- DepthDrawMode depth_draw_mode;
- CullMode cull_mode;
- bool flags[FLAG_MAX];
- SpecularMode specular_mode;
- DiffuseMode diffuse_mode;
+ BlendMode blend_mode = BLEND_MODE_MIX;
+ BlendMode detail_blend_mode = BLEND_MODE_MIX;
+ DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY;
+ CullMode cull_mode = CULL_BACK;
+ bool flags[FLAG_MAX] = {};
+ SpecularMode specular_mode = SPECULAR_SCHLICK_GGX;
+ DiffuseMode diffuse_mode = DIFFUSE_BURLEY;
BillboardMode billboard_mode;
- EmissionOperator emission_op;
+ EmissionOperator emission_op = EMISSION_OP_ADD;
TextureChannel metallic_texture_channel;
TextureChannel roughness_texture_channel;
TextureChannel ao_texture_channel;
TextureChannel refraction_texture_channel;
- AlphaAntiAliasing alpha_antialiasing_mode;
+ AlphaAntiAliasing alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
- bool features[FEATURE_MAX];
+ bool features[FEATURE_MAX] = {};
Ref<Texture2D> textures[TEXTURE_MAX];
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index e812ad3a01..d31dbc877b 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -579,6 +579,13 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const {
return ret;
}
+int Mesh::get_builtin_bind_pose_count() const {
+ return 0;
+}
+Transform Mesh::get_builtin_bind_pose(int p_index) const {
+ return Transform();
+}
+
Mesh::Mesh() {
}
@@ -1095,6 +1102,15 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
+void ArrayMesh::reset_state() {
+ clear_surfaces();
+ clear_blend_shapes();
+
+ aabb = AABB();
+ blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE;
+ custom_aabb = AABB();
+}
+
void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
if (_is_generated()) {
return;
@@ -1156,7 +1172,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
RenderingServer::get_singleton()->mesh_add_surface(mesh, sd);
clear_cache();
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -1229,6 +1245,22 @@ StringName ArrayMesh::get_blend_shape_name(int p_index) const {
return blend_shapes[p_index];
}
+void ArrayMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
+ ERR_FAIL_INDEX(p_index, blend_shapes.size());
+
+ StringName name = p_name;
+ int found = blend_shapes.find(name);
+ if (found != -1 && found != p_index) {
+ int count = 2;
+ do {
+ name = String(p_name) + " " + itos(count);
+ count++;
+ } while (blend_shapes.find(name) != -1);
+ }
+
+ blend_shapes.write[p_index] = name;
+}
+
void ArrayMesh::clear_blend_shapes() {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't set shape key count if surfaces are already created.");
@@ -1278,7 +1310,6 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material)
surfaces.write[p_idx].material = p_material;
RenderingServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid());
- _change_notify("material");
emit_changed();
}
@@ -1375,8 +1406,8 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v
struct ArrayMeshLightmapSurface {
Ref<Material> material;
LocalVector<SurfaceTool::Vertex> vertices;
- Mesh::PrimitiveType primitive;
- uint32_t format;
+ Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX;
+ uint32_t format = 0;
};
Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) {
@@ -1582,6 +1613,7 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape);
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count);
ClassDB::bind_method(D_METHOD("get_blend_shape_name", "index"), &ArrayMesh::get_blend_shape_name);
+ ClassDB::bind_method(D_METHOD("set_blend_shape_name", "index", "name"), &ArrayMesh::set_blend_shape_name);
ClassDB::bind_method(D_METHOD("clear_blend_shapes"), &ArrayMesh::clear_blend_shapes);
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
@@ -1633,13 +1665,12 @@ void ArrayMesh::reload_from_file() {
Resource::reload_from_file();
- _change_notify();
+ notify_property_list_changed();
}
ArrayMesh::ArrayMesh() {
//mesh is now created on demand
//mesh = RenderingServer::get_singleton()->mesh_create();
- blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE;
}
ArrayMesh::~ArrayMesh() {
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 1fd45c880a..13019c691d 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -141,6 +141,7 @@ public:
virtual Ref<Material> surface_get_material(int p_idx) const = 0;
virtual int get_blend_shape_count() const = 0;
virtual StringName get_blend_shape_name(int p_index) const = 0;
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0;
Vector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
@@ -164,6 +165,9 @@ public:
Vector<Ref<Shape3D>> convex_decompose() const;
+ virtual int get_builtin_bind_pose_count() const;
+ virtual Transform get_builtin_bind_pose(int p_index) const;
+
Mesh();
};
@@ -180,20 +184,20 @@ class ArrayMesh : public Mesh {
private:
struct Surface {
- uint32_t format;
- int array_length;
- int index_array_length;
- PrimitiveType primitive;
+ uint32_t format = 0;
+ int array_length = 0;
+ int index_array_length = 0;
+ PrimitiveType primitive = PrimitiveType::PRIMITIVE_MAX;
String name;
AABB aabb;
Ref<Material> material;
- bool is_2d;
+ bool is_2d = false;
};
Vector<Surface> surfaces;
mutable RID mesh;
AABB aabb;
- BlendShapeMode blend_shape_mode;
+ BlendShapeMode blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE;
Vector<StringName> blend_shapes;
AABB custom_aabb;
@@ -207,6 +211,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
static void _bind_methods();
public:
@@ -221,6 +227,7 @@ public:
void add_blend_shape(const StringName &p_name);
int get_blend_shape_count() const override;
StringName get_blend_shape_name(int p_index) const override;
+ void set_blend_shape_name(int p_index, const StringName &p_name) override;
void clear_blend_shapes();
void set_blend_shape_mode(BlendShapeMode p_mode);
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 1b82aca386..3fb4f8f211 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -50,6 +50,28 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
int vcount = varray.size();
ERR_FAIL_COND_V(vcount == 0, ERR_INVALID_PARAMETER);
+ Vector<int> indices;
+
+ if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) {
+ indices = arrays[Mesh::ARRAY_INDEX];
+ } else {
+ //make code simpler
+ indices.resize(vcount);
+ int *iw = indices.ptrw();
+ for (int i = 0; i < vcount; i++) {
+ iw[i] = i;
+ }
+ }
+
+ int icount = indices.size();
+ const int *r = indices.ptr();
+
+ ERR_FAIL_COND_V(icount == 0, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(icount % 3, ERR_INVALID_PARAMETER);
+ for (int i = 0; i < icount; i++) {
+ ERR_FAIL_INDEX_V(r[i], vcount, ERR_INVALID_PARAMETER);
+ }
+
clear();
format = p_mesh->surface_get_format(p_surface);
material = p_mesh->surface_get_material(p_surface);
@@ -128,22 +150,6 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
vertices.write[i] = v;
}
- Vector<int> indices;
-
- if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) {
- indices = arrays[Mesh::ARRAY_INDEX];
- } else {
- //make code simpler
- indices.resize(vcount);
- int *iw = indices.ptrw();
- for (int i = 0; i < vcount; i++) {
- iw[i] = i;
- }
- }
-
- int icount = indices.size();
- const int *r = indices.ptr();
-
Map<Point2i, int> edge_indices;
for (int i = 0; i < icount; i += 3) {
diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h
index d8b8d85900..f5c8f11437 100644
--- a/scene/resources/mesh_data_tool.h
+++ b/scene/resources/mesh_data_tool.h
@@ -36,7 +36,7 @@
class MeshDataTool : public Reference {
GDCLASS(MeshDataTool, Reference);
- int format;
+ int format = 0;
struct Vertex {
Vector3 vertex;
Color color;
@@ -54,7 +54,7 @@ class MeshDataTool : public Reference {
Vector<Vertex> vertices;
struct Edge {
- int vertex[2];
+ int vertex[2] = {};
Vector<int> faces;
Variant meta;
};
@@ -62,8 +62,8 @@ class MeshDataTool : public Reference {
Vector<Edge> edges;
struct Face {
- int v[3];
- int edges[3];
+ int v[3] = {};
+ int edges[3] = {};
Variant meta;
};
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 96d3a5750e..ad90481fbd 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -109,14 +109,14 @@ void MeshLibrary::create_item(int p_item) {
ERR_FAIL_COND(p_item < 0);
ERR_FAIL_COND(item_map.has(p_item));
item_map[p_item] = Item();
- _change_notify();
+ notify_property_list_changed();
}
void MeshLibrary::set_item_name(int p_item, const String &p_name) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].name = p_name;
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
@@ -124,25 +124,25 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
item_map[p_item].mesh = p_mesh;
notify_change_to_owners();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
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;
- _change_notify();
+ notify_property_list_changed();
notify_change_to_owners();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navmesh = p_navmesh;
- _change_notify();
+ notify_property_list_changed();
notify_change_to_owners();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) {
@@ -150,14 +150,14 @@ void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_tran
item_map[p_item].navmesh_transform = p_transform;
notify_change_to_owners();
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].preview = p_preview;
emit_changed();
- _change_notify();
+ notify_property_list_changed();
}
String MeshLibrary::get_item_name(int p_item) const {
@@ -198,14 +198,14 @@ 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();
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
void MeshLibrary::clear() {
item_map.clear();
notify_change_to_owners();
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -264,6 +264,9 @@ Array MeshLibrary::_get_item_shapes(int p_item) const {
return ret;
}
+void MeshLibrary::reset_state() {
+ clear();
+}
void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item);
ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name);
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 5c302fcf08..1da624c275 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -65,6 +65,7 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
static void _bind_methods();
public:
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index 050e398ca4..4991887eb3 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -217,7 +217,7 @@ Ref<Mesh> MultiMesh::get_mesh() const {
void MultiMesh::set_instance_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
- RenderingServer::get_singleton()->multimesh_allocate(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data);
+ RenderingServer::get_singleton()->multimesh_allocate_data(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data);
instance_count = p_count;
}
@@ -361,11 +361,6 @@ void MultiMesh::_bind_methods() {
MultiMesh::MultiMesh() {
multimesh = RenderingServer::get_singleton()->multimesh_create();
- use_colors = false;
- use_custom_data = false;
- transform_format = TRANSFORM_2D;
- visible_instance_count = -1;
- instance_count = 0;
}
MultiMesh::~MultiMesh() {
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index 633d754b8e..ca5c42d47a 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -47,11 +47,11 @@ public:
private:
Ref<Mesh> mesh;
RID multimesh;
- TransformFormat transform_format;
- bool use_colors;
- bool use_custom_data;
- int instance_count;
- int visible_instance_count;
+ TransformFormat transform_format = TRANSFORM_2D;
+ bool use_colors = false;
+ bool use_custom_data = false;
+ int instance_count = 0;
+ int visible_instance_count = -1;
protected:
static void _bind_methods();
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 43c3ef4edc..0a25bb2ed1 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -31,6 +31,8 @@
#include "navigation_mesh.h"
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
+ ERR_FAIL_COND(p_mesh.is_null());
+
vertices = Vector<Vector3>();
clear_polygons();
@@ -74,7 +76,7 @@ int NavigationMesh::get_sample_partition_type() const {
void NavigationMesh::set_parsed_geometry_type(int p_value) {
ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX);
parsed_geometry_type = static_cast<ParsedGeometryType>(p_value);
- _change_notify();
+ notify_property_list_changed();
}
int NavigationMesh::get_parsed_geometry_type() const {
@@ -90,6 +92,7 @@ uint32_t NavigationMesh::get_collision_mask() const {
}
void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -100,13 +103,14 @@ void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) {
ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode);
- _change_notify();
+ notify_property_list_changed();
}
int NavigationMesh::get_source_geometry_mode() const {
@@ -251,7 +255,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
- _change_notify();
+ notify_property_list_changed();
}
Vector<Vector3> NavigationMesh::get_vertices() const {
@@ -263,7 +267,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
polygons.write[i].indices = p_array[i];
}
- _change_notify();
+ notify_property_list_changed();
}
Array NavigationMesh::_get_polygons() const {
@@ -280,7 +284,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) {
Polygon polygon;
polygon.indices = p_polygon;
polygons.push_back(polygon);
- _change_notify();
+ notify_property_list_changed();
}
int NavigationMesh::get_polygon_count() const {
@@ -510,27 +514,4 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
}
}
-NavigationMesh::NavigationMesh() {
- cell_size = 0.3f;
- cell_height = 0.2f;
- agent_height = 2.0f;
- agent_radius = 0.6f;
- agent_max_climb = 0.9f;
- agent_max_slope = 45.0f;
- region_min_size = 8.0f;
- region_merge_size = 20.0f;
- edge_max_length = 12.0f;
- edge_max_error = 1.3f;
- verts_per_poly = 6.0f;
- detail_sample_distance = 6.0f;
- detail_sample_max_error = 1.0f;
-
- partition_type = SAMPLE_PARTITION_WATERSHED;
- parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
- collision_mask = 0xFFFFFFFF;
- source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
- source_group_name = "navmesh";
- filter_low_hanging_obstacles = false;
- filter_ledge_spans = false;
- filter_walkable_low_height_spans = false;
-}
+NavigationMesh::NavigationMesh() {}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 693c4184bc..966221c7c6 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -82,30 +82,30 @@ public:
};
protected:
- float cell_size;
- float cell_height;
- float agent_height;
- float agent_radius;
- float agent_max_climb;
- float agent_max_slope;
- float region_min_size;
- float region_merge_size;
- float edge_max_length;
- float edge_max_error;
- float verts_per_poly;
- float detail_sample_distance;
- float detail_sample_max_error;
-
- SamplePartitionType partition_type;
- ParsedGeometryType parsed_geometry_type;
- uint32_t collision_mask;
-
- SourceGeometryMode source_geometry_mode;
- StringName source_group_name;
-
- bool filter_low_hanging_obstacles;
- bool filter_ledge_spans;
- bool filter_walkable_low_height_spans;
+ float cell_size = 0.3f;
+ float cell_height = 0.2f;
+ float agent_height = 2.0f;
+ float agent_radius = 0.6f;
+ float agent_max_climb = 0.9f;
+ float agent_max_slope = 45.0f;
+ float region_min_size = 8.0f;
+ float region_merge_size = 20.0f;
+ float edge_max_length = 12.0f;
+ float edge_max_error = 1.3f;
+ float verts_per_poly = 6.0f;
+ float detail_sample_distance = 6.0f;
+ float detail_sample_max_error = 1.0f;
+
+ SamplePartitionType partition_type = SAMPLE_PARTITION_WATERSHED;
+ ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
+ uint32_t collision_mask = 0xFFFFFFFF;
+
+ SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
+ StringName source_group_name = "navmesh";
+
+ bool filter_low_hanging_obstacles = false;
+ bool filter_ledge_spans = false;
+ bool filter_walkable_low_height_spans = false;
public:
// Recast settings
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 794b281100..ab8a4b7934 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -147,15 +147,20 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
#endif
}
- } else if (ClassDB::is_class_enabled(snames[n.type])) {
- //node belongs to this scene and must be created
- Object *obj = ClassDB::instance(snames[n.type]);
+ } else {
+ Object *obj = nullptr;
+
+ if (ClassDB::is_class_enabled(snames[n.type])) {
+ //node belongs to this scene and must be created
+ obj = ClassDB::instance(snames[n.type]);
+ }
+
if (!Object::cast_to<Node>(obj)) {
if (obj) {
memdelete(obj);
obj = nullptr;
}
- WARN_PRINT(String("Warning node of type " + snames[n.type].operator String() + " does not exist.").ascii().get_data());
+ WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data());
if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) {
if (Object::cast_to<Node3D>(ret_nodes[n.parent])) {
obj = memnew(Node3D);
@@ -172,10 +177,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
node = Object::cast_to<Node>(obj);
-
- } else {
- //print_line("Class is disabled for: " + itos(n.type));
- //print_line("name: " + String(snames[n.type]));
}
if (node) {
@@ -469,6 +470,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
p_node->get_property_list(&plist);
StringName type = p_node->get_class();
+ Ref<Script> script = p_node->get_script();
+ if (script.is_valid()) {
+ script->update_exports();
+ }
+
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
@@ -484,7 +490,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
}
- Ref<Script> script = p_node->get_script();
if (!isdefault && script.is_valid() && script->get_property_default_value(name, default_value)) {
isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
}
@@ -1589,8 +1594,6 @@ void SceneState::_bind_methods() {
}
SceneState::SceneState() {
- base_scene_idx = -1;
- last_modified_time = 0;
}
////////////////
@@ -1663,6 +1666,9 @@ void PackedScene::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
}
+void PackedScene::reset_state() {
+ clear();
+}
void PackedScene::_bind_methods() {
ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack);
ClassDB::bind_method(D_METHOD("instance", "edit_state"), &PackedScene::instance, DEFVAL(GEN_EDIT_STATE_DISABLED));
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index a31dcd8d39..78a0aeaa9a 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -44,7 +44,7 @@ class SceneState : public Reference {
mutable HashMap<NodePath, int> node_path_cache;
mutable Map<int, int> base_scene_node_remap;
- int base_scene_idx;
+ int base_scene_idx = -1;
enum {
NO_PARENT_SAVED = 0x7FFFFFFF,
@@ -53,16 +53,16 @@ class SceneState : public Reference {
};
struct NodeData {
- int parent;
- int owner;
- int type;
- int name;
- int instance;
- int index;
+ int parent = 0;
+ int owner = 0;
+ int type = 0;
+ int name = 0;
+ int instance = 0;
+ int index = 0;
struct Property {
- int name;
- int value;
+ int name = 0;
+ int value = 0;
};
Vector<Property> properties;
@@ -71,18 +71,17 @@ class SceneState : public Reference {
struct PackState {
Ref<SceneState> state;
- int node;
- PackState() { node = -1; }
+ int node = -1;
};
Vector<NodeData> nodes;
struct ConnectionData {
- int from;
- int to;
- int signal;
- int method;
- int flags;
+ int from = 0;
+ int to = 0;
+ int signal = 0;
+ int method = 0;
+ int flags = 0;
Vector<int> binds;
};
@@ -93,7 +92,7 @@ class SceneState : public Reference {
String path;
- uint64_t last_modified_time;
+ uint64_t last_modified_time = 0;
_FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
@@ -201,6 +200,7 @@ class PackedScene : public Resource {
protected:
virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better
static void _bind_methods();
+ virtual void reset_state() override;
public:
enum GenEditState {
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index c5a295e13f..59e699326d 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -289,7 +289,7 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
- code += "void compute() {\n";
+ code += "void start() {\n";
code += " uint base_number = NUMBER;\n";
code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
code += " float angle_rand = rand_from_seed(alt_seed);\n";
@@ -305,90 +305,94 @@ void ParticlesMaterial::_update_shader() {
code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
}
- code += " float tv = 0.0;\n";
- code += " if (RESTART) {\n";
-
if (tex_parameters[PARAM_ANGLE].is_valid()) {
- code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angle = 0.0;\n";
+ code += " float tex_angle = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 0.0;\n";
}
- code += " float spread_rad = spread * degree_to_rad;\n";
+ code += " float spread_rad = spread * degree_to_rad;\n";
- code += " if (RESTART_VELOCITY) {\n";
+ code += " if (RESTART_VELOCITY) {\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 0.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
- code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
- code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
+ code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
+ code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
} else {
//initiate velocity spread in 3D
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
- code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n";
- code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n";
- code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
- code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
- code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
- code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
- code += " vec_direction = normalize(vec_direction);\n";
- code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
+ code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
+ code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
+ code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
+ code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
+ code += " vec3 direction_nrm = normalize(direction);\n";
+ code += " // rotate spread to direction\n";
+ code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n";
+ code += " if (length(binormal) < 0.0001) {\n";
+ code += " // direction is parallel to Y. Choose Z as the binormal.\n";
+ code += " binormal = vec3(0.0, 0.0, 1.0);\n";
+ code += " }\n";
+ code += " binormal = normalize(binormal);\n";
+ code += " vec3 normal = cross(binormal, direction_nrm);\n";
+ code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n";
+ code += " VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
}
- code += " }\n";
+ code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
- code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
- code += " CUSTOM.y = 0.0;\n"; // phase
- code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
+ code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
+ code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
+ code += " CUSTOM.y = 0.0;\n"; // phase
+ code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
+ code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
- code += " if (RESTART_POSITION) {\n";
+ code += " if (RESTART_POSITION) {\n";
switch (emission_shape) {
case EMISSION_SHAPE_POINT: {
//do none, identity (will later be multiplied by emission transform)
- code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
+ code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
} break;
case EMISSION_SHAPE_SPHERE: {
- code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
- code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
- code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
- code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
+ code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
+ code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
+ code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
+ code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
} break;
case EMISSION_SHAPE_BOX: {
- code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
+ code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
} break;
case EMISSION_SHAPE_POINTS:
case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
+ code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " mat2 rotm;";
- code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
- code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
- code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n";
+ code += " mat2 rotm;";
+ code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
+ code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
+ code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n";
} else {
- code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
- code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
- code += " vec3 tangent = normalize(cross(v0, normal));\n";
- code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
- code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
+ code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
+ code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
+ code += " vec3 tangent = normalize(cross(v0, normal));\n";
+ code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
+ code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
}
}
} break;
@@ -397,134 +401,144 @@ void ParticlesMaterial::_update_shader() {
}
}
- code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
- code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+ code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
+ code += " VELOCITY.z = 0.0;\n";
+ code += " TRANSFORM[3].z = 0.0;\n";
}
- code += " }\n";
+ code += " }\n";
+ code += "}\n\n";
- code += " } else {\n";
+ code += "void process() {\n";
+ code += " uint base_number = NUMBER;\n";
+ code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
+ code += " float angle_rand = rand_from_seed(alt_seed);\n";
+ code += " float scale_rand = rand_from_seed(alt_seed);\n";
+ code += " float hue_rot_rand = rand_from_seed(alt_seed);\n";
+ code += " float anim_offset_rand = rand_from_seed(alt_seed);\n";
+ code += " float pi = 3.14159;\n";
+ code += " float degree_to_rad = pi / 180.0;\n";
+ code += "\n";
- code += " CUSTOM.y += DELTA / LIFETIME;\n";
- code += " tv = CUSTOM.y / CUSTOM.w;\n";
+ code += " CUSTOM.y += DELTA / LIFETIME;\n";
+ code += " float tv = CUSTOM.y / CUSTOM.w;\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 0.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_orbit_velocity = 0.0;\n";
+ code += " float tex_orbit_velocity = 0.0;\n";
}
}
if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angular_velocity = 0.0;\n";
+ code += " float tex_angular_velocity = 0.0;\n";
}
if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_accel = 0.0;\n";
+ code += " float tex_linear_accel = 0.0;\n";
}
if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_radial_accel = 0.0;\n";
+ code += " float tex_radial_accel = 0.0;\n";
}
if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_tangent_accel = 0.0;\n";
+ code += " float tex_tangent_accel = 0.0;\n";
}
if (tex_parameters[PARAM_DAMPING].is_valid()) {
- code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_damping = 0.0;\n";
+ code += " float tex_damping = 0.0;\n";
}
if (tex_parameters[PARAM_ANGLE].is_valid()) {
- code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angle = 0.0;\n";
+ code += " float tex_angle = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) {
- code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_speed = 0.0;\n";
+ code += " float tex_anim_speed = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 0.0;\n";
}
- code += " vec3 force = gravity;\n";
- code += " vec3 pos = TRANSFORM[3].xyz;\n";
+ code += " vec3 force = gravity;\n";
+ code += " vec3 pos = TRANSFORM[3].xyz;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " pos.z = 0.0;\n";
- }
- code += " // apply linear acceleration\n";
- code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
- code += " // apply radial acceleration\n";
- code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
- code += " vec3 diff = pos - org;\n";
- code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
- code += " // apply tangential acceleration;\n";
+ code += " pos.z = 0.0;\n";
+ }
+ code += " // apply linear acceleration\n";
+ code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
+ code += " // apply radial acceleration\n";
+ code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
+ code += " vec3 diff = pos - org;\n";
+ code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
+ code += " // apply tangential acceleration;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
} else {
- code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
- code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
+ code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
}
if (attractor_interaction_enabled) {
- code += " force += ATTRACTOR_FORCE;\n\n";
+ code += " force += ATTRACTOR_FORCE;\n\n";
}
- code += " // apply attractor forces\n";
- code += " VELOCITY += force * DELTA;\n";
- code += " // orbit velocity\n";
+ code += " // apply attractor forces\n";
+ code += " VELOCITY += force * DELTA;\n";
+ code += " // orbit velocity\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
- code += " if (orbit_amount != 0.0) {\n";
- code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
- code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n";
- code += " TRANSFORM[3].xy -= diff.xy;\n";
- code += " TRANSFORM[3].xy += rot * diff.xy;\n";
- code += " }\n";
+ code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
+ code += " if (orbit_amount != 0.0) {\n";
+ code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
+ code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n";
+ code += " TRANSFORM[3].xy -= diff.xy;\n";
+ code += " TRANSFORM[3].xy += rot * diff.xy;\n";
+ code += " }\n";
}
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
- }
- code += " if (damping + tex_damping > 0.0) {\n";
- code += " float v = length(VELOCITY);\n";
- code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
- code += " v -= damp * DELTA;\n";
- code += " if (v < 0.0) {\n";
- code += " VELOCITY = vec3(0.0);\n";
- code += " } else {\n";
- code += " VELOCITY = normalize(VELOCITY) * v;\n";
- code += " }\n";
+ code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
+ }
+ code += " if (damping + tex_damping > 0.0) {\n";
+ code += " float v = length(VELOCITY);\n";
+ code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
+ code += " v -= damp * DELTA;\n";
+ code += " if (v < 0.0) {\n";
+ code += " VELOCITY = vec3(0.0);\n";
+ code += " } else {\n";
+ code += " VELOCITY = normalize(VELOCITY) * v;\n";
code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
- code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
- code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
code += " }\n";
+ code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
+ code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
+ code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
+ code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
+
// apply color
// apply hue rotation
if (tex_parameters[PARAM_SCALE].is_valid()) {
@@ -601,7 +615,7 @@ void ParticlesMaterial::_update_shader() {
}
// turn particle by rotation in Y
if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
- code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
}
//scale by scale
@@ -652,7 +666,7 @@ void ParticlesMaterial::_update_shader() {
code += " }";
}
- code += " if (CUSTOM.y > CUSTOM.w) {";
+ code += " if (CUSTOM.y > CUSTOM.w) {\n";
code += " ACTIVE = false;\n";
code += " }\n";
code += "}\n";
@@ -911,7 +925,7 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
color_ramp = p_texture;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
Ref<Texture2D> ParticlesMaterial::get_color_ramp() const {
@@ -923,7 +937,7 @@ void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_
particle_flags[p_particle_flag] = p_enable;
_queue_shader_change();
if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) {
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -935,7 +949,7 @@ bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
emission_shape = p_shape;
- _change_notify();
+ notify_property_list_changed();
_queue_shader_change();
}
@@ -1066,7 +1080,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
sub_emitter_mode = p_sub_emitter_mode;
_queue_shader_change();
- _change_notify();
+ notify_property_list_changed();
}
ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const {
@@ -1075,7 +1089,7 @@ ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() cons
void ParticlesMaterial::set_sub_emitter_frequency(float p_frequency) {
sub_emitter_frequency = p_frequency;
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pas delta instead of frequency, since its easier to compute
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute
}
float ParticlesMaterial::get_sub_emitter_frequency() const {
return sub_emitter_frequency;
@@ -1370,7 +1384,6 @@ ParticlesMaterial::ParticlesMaterial() :
set_emission_box_extents(Vector3(1, 1, 1));
set_gravity(Vector3(0, -9.8, 0));
set_lifetime_randomness(0);
- emission_point_count = 1;
set_sub_emitter_mode(SUB_EMITTER_DISABLED);
set_sub_emitter_frequency(4);
@@ -1393,7 +1406,6 @@ ParticlesMaterial::ParticlesMaterial() :
set_color(Color(1, 1, 1, 1));
- current_key.key = 0;
current_key.invalid_key = 1;
_queue_shader_change();
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 49b48a01b7..3f874bd68c 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -100,7 +100,7 @@ private:
uint32_t collision_scale : 1;
};
- uint32_t key;
+ uint32_t key = 0;
bool operator<(const MaterialKey &p_key) const {
return key < p_key.key;
@@ -109,7 +109,7 @@ private:
struct ShaderData {
RID shader;
- int users;
+ int users = 0;
};
static Map<MaterialKey, ShaderData> shader_map;
@@ -235,7 +235,7 @@ private:
Ref<Texture2D> emission_point_texture;
Ref<Texture2D> emission_normal_texture;
Ref<Texture2D> emission_color_texture;
- int emission_point_count;
+ int emission_point_count = 1;
bool anim_loop;
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
index dfb2d1480b..d302800823 100644
--- a/scene/resources/physics_material.h
+++ b/scene/resources/physics_material.h
@@ -39,9 +39,9 @@ class PhysicsMaterial : public Resource {
OBJ_SAVE_TYPE(PhysicsMaterial);
RES_BASE_EXTENSION("phymat");
- real_t friction = 1;
+ real_t friction = 1.0;
bool rough = false;
- real_t bounce = 0;
+ real_t bounce = 0.0;
bool absorbent = false;
protected:
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index f292140d6b..a08684a506 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -77,7 +77,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
outside_point.x += 20.451 + Math::randf() * 10.2039;
outside_point.y += 21.193 + Math::randf() * 12.5412;
- //insert edges (which are also connetions)
+ //insert edges (which are also connections)
for (int i = 0; i < p_connections.size(); i += 2) {
Edge e(p_connections[i], p_connections[i + 1]);
@@ -335,7 +335,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
//oh this was visited already, can we win the cost?
if (p.distance > distance) {
- p.prev = least_cost_point; //reasign previous
+ p.prev = least_cost_point; //reassign previous
p.distance = distance;
}
} else {
@@ -368,7 +368,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
path.push_back(points[at].pos);
} while (at != aidx);
- path.invert();
+ path.reverse();
}
for (int i = 0; i < points.size() - 2; i++) {
diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h
index 410e1dba52..2f3cb634fb 100644
--- a/scene/resources/polygon_path_finder.h
+++ b/scene/resources/polygon_path_finder.h
@@ -39,13 +39,13 @@ class PolygonPathFinder : public Resource {
struct Point {
Vector2 pos;
Set<int> connections;
- float distance;
- float penalty;
- int prev;
+ float distance = 0.0;
+ float penalty = 0.0;
+ int prev = 0;
};
struct Edge {
- int points[2];
+ int points[2] = {};
_FORCE_INLINE_ bool operator<(const Edge &p_edge) const {
if (points[0] == p_edge.points[0]) {
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 398bce0602..c3d84aeda2 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -175,6 +175,9 @@ StringName PrimitiveMesh::get_blend_shape_name(int p_index) const {
return StringName();
}
+void PrimitiveMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
+}
+
AABB PrimitiveMesh::get_aabb() const {
if (pending_request) {
_update();
@@ -214,7 +217,7 @@ void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
RenderingServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
- _change_notify();
+ notify_property_list_changed();
emit_changed();
};
}
@@ -247,18 +250,7 @@ bool PrimitiveMesh::get_flip_faces() const {
}
PrimitiveMesh::PrimitiveMesh() {
- flip_faces = false;
- // defaults
mesh = RenderingServer::get_singleton()->mesh_create();
-
- // assume primitive triangles as the type, correct for all but one and it will change this :)
- primitive_type = Mesh::PRIMITIVE_TRIANGLES;
-
- // make sure we do an update after we've finished constructing our object
- pending_request = true;
-
- array_len = 0;
- index_array_len = 0;
}
PrimitiveMesh::~PrimitiveMesh() {
@@ -468,13 +460,7 @@ int CapsuleMesh::get_rings() const {
return rings;
}
-CapsuleMesh::CapsuleMesh() {
- // defaults
- radius = 1.0;
- mid_height = 1.0;
- radial_segments = 64;
- rings = 8;
-}
+CapsuleMesh::CapsuleMesh() {}
/**
BoxMesh
@@ -725,13 +711,7 @@ int BoxMesh::get_subdivide_depth() const {
return subdivide_d;
}
-BoxMesh::BoxMesh() {
- // defaults
- size = Vector3(2.0, 2.0, 2.0);
- subdivide_w = 0;
- subdivide_h = 0;
- subdivide_d = 0;
-}
+BoxMesh::BoxMesh() {}
/**
CylinderMesh
@@ -938,14 +918,7 @@ int CylinderMesh::get_rings() const {
return rings;
}
-CylinderMesh::CylinderMesh() {
- // defaults
- top_radius = 1.0;
- bottom_radius = 1.0;
- height = 2.0;
- radial_segments = 64;
- rings = 4;
-}
+CylinderMesh::CylinderMesh() {}
/**
PlaneMesh
@@ -1053,12 +1026,7 @@ int PlaneMesh::get_subdivide_depth() const {
return subdivide_d;
}
-PlaneMesh::PlaneMesh() {
- // defaults
- size = Size2(2.0, 2.0);
- subdivide_w = 0;
- subdivide_d = 0;
-}
+PlaneMesh::PlaneMesh() {}
/**
PrismMesh
@@ -1338,14 +1306,7 @@ int PrismMesh::get_subdivide_depth() const {
return subdivide_d;
}
-PrismMesh::PrismMesh() {
- // defaults
- left_to_right = 0.5;
- size = Vector3(2.0, 2.0, 2.0);
- subdivide_w = 0;
- subdivide_h = 0;
- subdivide_d = 0;
-}
+PrismMesh::PrismMesh() {}
/**
QuadMesh
@@ -1409,7 +1370,6 @@ void QuadMesh::_bind_methods() {
QuadMesh::QuadMesh() {
primitive_type = PRIMITIVE_TRIANGLES;
- size = Size2(1.0, 1.0);
}
void QuadMesh::set_size(const Size2 &p_size) {
@@ -1561,14 +1521,7 @@ bool SphereMesh::get_is_hemisphere() const {
return is_hemisphere;
}
-SphereMesh::SphereMesh() {
- // defaults
- radius = 1.0;
- height = 2.0;
- radial_segments = 64;
- rings = 32;
- is_hemisphere = false;
-}
+SphereMesh::SphereMesh() {}
/**
PointMesh
@@ -1585,3 +1538,552 @@ void PointMesh::_create_mesh_array(Array &p_arr) const {
PointMesh::PointMesh() {
primitive_type = PRIMITIVE_POINTS;
}
+// TUBE TRAIL
+
+void TubeTrailMesh::set_radius(const float p_radius) {
+ radius = p_radius;
+ _request_update();
+}
+float TubeTrailMesh::get_radius() const {
+ return radius;
+}
+
+void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
+ ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
+ radial_steps = p_radial_steps;
+ _request_update();
+}
+int TubeTrailMesh::get_radial_steps() const {
+ return radial_steps;
+}
+
+void TubeTrailMesh::set_sections(const int p_sections) {
+ ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
+ sections = p_sections;
+ _request_update();
+}
+int TubeTrailMesh::get_sections() const {
+ return sections;
+}
+
+void TubeTrailMesh::set_section_length(float p_section_length) {
+ section_length = p_section_length;
+ _request_update();
+}
+float TubeTrailMesh::get_section_length() const {
+ return section_length;
+}
+
+void TubeTrailMesh::set_section_rings(const int p_section_rings) {
+ ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
+ section_rings = p_section_rings;
+ _request_update();
+}
+int TubeTrailMesh::get_section_rings() const {
+ return section_rings;
+}
+
+void TubeTrailMesh::set_curve(const Ref<Curve> &p_curve) {
+ if (curve == p_curve) {
+ return;
+ }
+ if (curve.is_valid()) {
+ 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));
+ }
+ _request_update();
+}
+Ref<Curve> TubeTrailMesh::get_curve() const {
+ return curve;
+}
+
+void TubeTrailMesh::_curve_changed() {
+ _request_update();
+}
+int TubeTrailMesh::get_builtin_bind_pose_count() const {
+ return sections + 1;
+}
+
+Transform TubeTrailMesh::get_builtin_bind_pose(int p_index) const {
+ float depth = section_length * sections;
+
+ Transform xform;
+ xform.origin.y = depth / 2.0 - section_length * float(p_index);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y
+
+ return xform;
+}
+
+void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
+ PackedVector3Array points;
+ PackedVector3Array normals;
+ PackedFloat32Array tangents;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+ int point = 0;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ int thisrow = 0;
+ int prevrow = 0;
+
+ int total_rings = section_rings * sections;
+ float depth = section_length * sections;
+
+ for (int j = 0; j <= total_rings; j++) {
+ float v = j;
+ v /= total_rings;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / section_rings;
+ float blend = 1.0 - float(j % section_rings) / float(section_rings);
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float u = i;
+ u /= radial_steps;
+
+ float r = radius;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ r *= curve->interpolate_baked(v);
+ }
+ float x = sin(u * Math_TAU);
+ float z = cos(u * Math_TAU);
+
+ Vector3 p = Vector3(x * r, y, z * r);
+ points.push_back(p);
+ normals.push_back(Vector3(x, 0, z));
+ ADD_TANGENT(z, 0.0, -x, 1.0)
+ uvs.push_back(Vector2(u, v * 0.5));
+ point++;
+ {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (i > 0 && j > 0) {
+ indices.push_back(prevrow + i - 1);
+ indices.push_back(prevrow + i);
+ indices.push_back(thisrow + i - 1);
+
+ indices.push_back(prevrow + i);
+ indices.push_back(thisrow + i);
+ indices.push_back(thisrow + i - 1);
+ }
+ }
+
+ prevrow = thisrow;
+ thisrow = point;
+ }
+
+ // add top
+ float scale_pos = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_pos = curve->interpolate_baked(0);
+ }
+
+ if (scale_pos > CMP_EPSILON) {
+ float y = depth * 0.5;
+
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0));
+ normals.push_back(Vector3(0.0, 1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(0.25, 0.75));
+ point++;
+
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ float rm = radius * scale_pos;
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
+
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
+
+ float u = ((x + 1.0) * 0.25);
+ float v = 0.5 + ((z + 1.0) * 0.25);
+
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, 1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
+
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 1);
+ indices.push_back(point - 2);
+ };
+ };
+ };
+
+ float scale_neg = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_neg = curve->interpolate_baked(1.0);
+ }
+
+ // add bottom
+ if (scale_neg > CMP_EPSILON) {
+ float y = depth * -0.5;
+
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0.0));
+ normals.push_back(Vector3(0.0, -1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(0.75, 0.75));
+ point++;
+
+ bone_indices.push_back(sections);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ float rm = radius * scale_neg;
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
+
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
+
+ float u = 0.5 + ((x + 1.0) * 0.25);
+ float v = 1.0 - ((z + 1.0) * 0.25);
+
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, -1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
+
+ bone_indices.push_back(sections);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 2);
+ indices.push_back(point - 1);
+ };
+ };
+ };
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_BONES] = bone_indices;
+ p_arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void TubeTrailMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &TubeTrailMesh::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &TubeTrailMesh::get_radius);
+
+ ClassDB::bind_method(D_METHOD("set_radial_steps", "radial_steps"), &TubeTrailMesh::set_radial_steps);
+ ClassDB::bind_method(D_METHOD("get_radial_steps"), &TubeTrailMesh::get_radial_steps);
+
+ ClassDB::bind_method(D_METHOD("set_sections", "sections"), &TubeTrailMesh::set_sections);
+ ClassDB::bind_method(D_METHOD("get_sections"), &TubeTrailMesh::get_sections);
+
+ ClassDB::bind_method(D_METHOD("set_section_length", "section_length"), &TubeTrailMesh::set_section_length);
+ ClassDB::bind_method(D_METHOD("get_section_length"), &TubeTrailMesh::get_section_length);
+
+ ClassDB::bind_method(D_METHOD("set_section_rings", "section_rings"), &TubeTrailMesh::set_section_rings);
+ ClassDB::bind_method(D_METHOD("get_section_rings"), &TubeTrailMesh::get_section_rings);
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_steps", PROPERTY_HINT_RANGE, "3,128,1"), "set_radial_steps", "get_radial_steps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings");
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+}
+
+TubeTrailMesh::TubeTrailMesh() {
+}
+
+// TUBE TRAIL
+
+void RibbonTrailMesh::set_shape(Shape p_shape) {
+ shape = p_shape;
+ _request_update();
+}
+RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
+ return shape;
+}
+
+void RibbonTrailMesh::set_size(const float p_size) {
+ size = p_size;
+ _request_update();
+}
+float RibbonTrailMesh::get_size() const {
+ return size;
+}
+
+void RibbonTrailMesh::set_sections(const int p_sections) {
+ ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
+ sections = p_sections;
+ _request_update();
+}
+int RibbonTrailMesh::get_sections() const {
+ return sections;
+}
+
+void RibbonTrailMesh::set_section_length(float p_section_length) {
+ section_length = p_section_length;
+ _request_update();
+}
+float RibbonTrailMesh::get_section_length() const {
+ return section_length;
+}
+
+void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
+ ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
+ section_segments = p_section_segments;
+ _request_update();
+}
+int RibbonTrailMesh::get_section_segments() const {
+ return section_segments;
+}
+
+void RibbonTrailMesh::set_curve(const Ref<Curve> &p_curve) {
+ if (curve == p_curve) {
+ return;
+ }
+ if (curve.is_valid()) {
+ 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));
+ }
+ _request_update();
+}
+Ref<Curve> RibbonTrailMesh::get_curve() const {
+ return curve;
+}
+
+void RibbonTrailMesh::_curve_changed() {
+ _request_update();
+}
+int RibbonTrailMesh::get_builtin_bind_pose_count() const {
+ return sections + 1;
+}
+
+Transform RibbonTrailMesh::get_builtin_bind_pose(int p_index) const {
+ float depth = section_length * sections;
+
+ Transform xform;
+ xform.origin.y = depth / 2.0 - section_length * float(p_index);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y
+
+ return xform;
+}
+
+void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
+ PackedVector3Array points;
+ PackedVector3Array normals;
+ PackedFloat32Array tangents;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ int total_segments = section_segments * sections;
+ float depth = section_length * sections;
+
+ for (int j = 0; j <= total_segments; j++) {
+ float v = j;
+ v /= total_segments;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / section_segments;
+ float blend = 1.0 - float(j % section_segments) / float(section_segments);
+
+ float s = size;
+
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ s *= curve->interpolate_baked(v);
+ }
+
+ points.push_back(Vector3(-s * 0.5, y, 0));
+ points.push_back(Vector3(+s * 0.5, y, 0));
+ if (shape == SHAPE_CROSS) {
+ points.push_back(Vector3(0, y, -s * 0.5));
+ points.push_back(Vector3(0, y, +s * 0.5));
+ }
+
+ normals.push_back(Vector3(0, 0, 1));
+ normals.push_back(Vector3(0, 0, 1));
+ if (shape == SHAPE_CROSS) {
+ normals.push_back(Vector3(1, 0, 0));
+ normals.push_back(Vector3(1, 0, 0));
+ }
+
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+ if (shape == SHAPE_CROSS) {
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+ }
+
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ if (shape == SHAPE_CROSS) {
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ }
+
+ for (int i = 0; i < (shape == SHAPE_CROSS ? 4 : 2); i++) {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (j > 0) {
+ if (shape == SHAPE_CROSS) {
+ int base = j * 4 - 4;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 4);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 5);
+ indices.push_back(base + 4);
+
+ indices.push_back(base + 2);
+ indices.push_back(base + 3);
+ indices.push_back(base + 6);
+
+ indices.push_back(base + 3);
+ indices.push_back(base + 7);
+ indices.push_back(base + 6);
+ } else {
+ int base = j * 2 - 2;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 2);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 3);
+ indices.push_back(base + 2);
+ }
+ }
+ }
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_BONES] = bone_indices;
+ p_arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void RibbonTrailMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &RibbonTrailMesh::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &RibbonTrailMesh::get_size);
+
+ ClassDB::bind_method(D_METHOD("set_sections", "sections"), &RibbonTrailMesh::set_sections);
+ ClassDB::bind_method(D_METHOD("get_sections"), &RibbonTrailMesh::get_sections);
+
+ ClassDB::bind_method(D_METHOD("set_section_length", "section_length"), &RibbonTrailMesh::set_section_length);
+ ClassDB::bind_method(D_METHOD("get_section_length"), &RibbonTrailMesh::get_section_length);
+
+ ClassDB::bind_method(D_METHOD("set_section_segments", "section_segments"), &RibbonTrailMesh::set_section_segments);
+ ClassDB::bind_method(D_METHOD("get_section_segments"), &RibbonTrailMesh::get_section_segments);
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &RibbonTrailMesh::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &RibbonTrailMesh::get_curve);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &RibbonTrailMesh::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &RibbonTrailMesh::get_shape);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Flat,Cross"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "section_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_segments", "get_section_segments");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+
+ BIND_ENUM_CONSTANT(SHAPE_FLAT)
+ BIND_ENUM_CONSTANT(SHAPE_CROSS)
+}
+
+RibbonTrailMesh::RibbonTrailMesh() {
+}
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index d0ca4b10e7..ec5806489e 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -49,17 +49,19 @@ private:
mutable AABB aabb;
AABB custom_aabb;
- mutable int array_len;
- mutable int index_array_len;
+ mutable int array_len = 0;
+ mutable int index_array_len = 0;
Ref<Material> material;
- bool flip_faces;
+ bool flip_faces = false;
- mutable bool pending_request;
+ // make sure we do an update after we've finished constructing our object
+ mutable bool pending_request = true;
void _update() const;
protected:
- Mesh::PrimitiveType primitive_type;
+ // assume primitive triangles as the type, correct for all but one and it will change this :)
+ Mesh::PrimitiveType primitive_type = Mesh::PRIMITIVE_TRIANGLES;
static void _bind_methods();
@@ -79,6 +81,7 @@ public:
virtual Ref<Material> surface_get_material(int p_idx) const override;
virtual int get_blend_shape_count() const override;
virtual StringName get_blend_shape_name(int p_index) const override;
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name) override;
virtual AABB get_aabb() const override;
virtual RID get_rid() const override;
@@ -104,10 +107,10 @@ class CapsuleMesh : public PrimitiveMesh {
GDCLASS(CapsuleMesh, PrimitiveMesh);
private:
- float radius;
- float mid_height;
- int radial_segments;
- int rings;
+ float radius = 1.0;
+ float mid_height = 1.0;
+ int radial_segments = 64;
+ int rings = 8;
protected:
static void _bind_methods();
@@ -136,10 +139,10 @@ class BoxMesh : public PrimitiveMesh {
GDCLASS(BoxMesh, PrimitiveMesh);
private:
- Vector3 size;
- int subdivide_w;
- int subdivide_h;
- int subdivide_d;
+ Vector3 size = Vector3(2.0, 2.0, 2.0);
+ int subdivide_w = 0;
+ int subdivide_h = 0;
+ int subdivide_d = 0;
protected:
static void _bind_methods();
@@ -169,11 +172,11 @@ class CylinderMesh : public PrimitiveMesh {
GDCLASS(CylinderMesh, PrimitiveMesh);
private:
- float top_radius;
- float bottom_radius;
- float height;
- int radial_segments;
- int rings;
+ float top_radius = 1.0;
+ float bottom_radius = 1.0;
+ float height = 2.0;
+ int radial_segments = 64;
+ int rings = 4;
protected:
static void _bind_methods();
@@ -205,9 +208,9 @@ class PlaneMesh : public PrimitiveMesh {
GDCLASS(PlaneMesh, PrimitiveMesh);
private:
- Size2 size;
- int subdivide_w;
- int subdivide_d;
+ Size2 size = Size2(2.0, 2.0);
+ int subdivide_w = 0;
+ int subdivide_d = 0;
protected:
static void _bind_methods();
@@ -233,11 +236,11 @@ class PrismMesh : public PrimitiveMesh {
GDCLASS(PrismMesh, PrimitiveMesh);
private:
- float left_to_right;
- Vector3 size;
- int subdivide_w;
- int subdivide_h;
- int subdivide_d;
+ float left_to_right = 0.5;
+ Vector3 size = Vector3(2.0, 2.0, 2.0);
+ int subdivide_w = 0;
+ int subdivide_h = 0;
+ int subdivide_d = 0;
protected:
static void _bind_methods();
@@ -270,7 +273,7 @@ class QuadMesh : public PrimitiveMesh {
GDCLASS(QuadMesh, PrimitiveMesh);
private:
- Size2 size;
+ Size2 size = Size2(1.0, 1.0);
protected:
static void _bind_methods();
@@ -290,11 +293,11 @@ class SphereMesh : public PrimitiveMesh {
GDCLASS(SphereMesh, PrimitiveMesh);
private:
- float radius;
- float height;
- int radial_segments;
- int rings;
- bool is_hemisphere;
+ float radius = 1.0;
+ float height = 2.0;
+ int radial_segments = 64;
+ int rings = 32;
+ bool is_hemisphere = false;
protected:
static void _bind_methods();
@@ -333,4 +336,98 @@ public:
PointMesh();
};
+class TubeTrailMesh : public PrimitiveMesh {
+ GDCLASS(TubeTrailMesh, PrimitiveMesh);
+
+private:
+ float radius = 1.0;
+ int radial_steps = 8;
+ int sections = 5;
+ float section_length = 0.2;
+ int section_rings = 3;
+
+ Ref<Curve> curve;
+
+ void _curve_changed();
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_radius(const float p_radius);
+ float get_radius() const;
+
+ void set_radial_steps(const int p_radial_steps);
+ int get_radial_steps() const;
+
+ void set_sections(const int p_sections);
+ int get_sections() const;
+
+ void set_section_length(float p_sectionlength);
+ float get_section_length() const;
+
+ void set_section_rings(const int p_section_rings);
+ int get_section_rings() const;
+
+ void set_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_curve() const;
+
+ virtual int get_builtin_bind_pose_count() const override;
+ virtual Transform get_builtin_bind_pose(int p_index) const override;
+
+ TubeTrailMesh();
+};
+
+class RibbonTrailMesh : public PrimitiveMesh {
+ GDCLASS(RibbonTrailMesh, PrimitiveMesh);
+
+public:
+ enum Shape {
+ SHAPE_FLAT,
+ SHAPE_CROSS
+ };
+
+private:
+ float size = 1.0;
+ int sections = 5;
+ float section_length = 0.2;
+ int section_segments = 3;
+
+ Shape shape = SHAPE_CROSS;
+
+ Ref<Curve> curve;
+
+ void _curve_changed();
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_shape(Shape p_shape);
+ Shape get_shape() const;
+
+ void set_size(const float p_size);
+ float get_size() const;
+
+ void set_sections(const int p_sections);
+ int get_sections() const;
+
+ void set_section_length(float p_sectionlength);
+ float get_section_length() const;
+
+ void set_section_segments(const int p_section_segments);
+ int get_section_segments() const;
+
+ void set_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_curve() const;
+
+ virtual int get_builtin_bind_pose_count() const override;
+ virtual Transform get_builtin_bind_pose(int p_index) const override;
+
+ RibbonTrailMesh();
+};
+
+VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
#endif
diff --git a/scene/resources/ray_shape_2d.cpp b/scene/resources/ray_shape_2d.cpp
index 98fd160810..fb8f4b9985 100644
--- a/scene/resources/ray_shape_2d.cpp
+++ b/scene/resources/ray_shape_2d.cpp
@@ -42,17 +42,33 @@ void RayShape2D::_update_shape() {
}
void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- Vector2 tip = Vector2(0, get_length());
- RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3);
+ const Vector2 target_position = Vector2(0, get_length());
+
+ const float max_arrow_size = 6;
+ const float line_width = 1.4;
+ bool no_line = target_position.length() < line_width;
+ float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
+
+ if (no_line) {
+ arrow_size = target_position.length();
+ } else {
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), target_position - target_position.normalized() * arrow_size, p_color, line_width);
+ }
+
+ Transform2D xf;
+ xf.rotate(target_position.angle());
+ xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
+
Vector<Vector2> pts;
- float tsize = 4;
- pts.push_back(tip + Vector2(0, tsize));
- pts.push_back(tip + Vector2(Math_SQRT12 * tsize, 0));
- pts.push_back(tip + Vector2(-Math_SQRT12 * tsize, 0));
+ pts.push_back(xf.xform(Vector2(arrow_size, 0)));
+ pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size)));
+ pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size)));
+
Vector<Color> cols;
for (int i = 0; i < 3; i++) {
cols.push_back(p_color);
}
+
RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID());
}
@@ -99,7 +115,5 @@ bool RayShape2D::get_slips_on_slope() const {
RayShape2D::RayShape2D() :
Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) {
- length = 20;
- slips_on_slope = false;
_update_shape();
}
diff --git a/scene/resources/ray_shape_2d.h b/scene/resources/ray_shape_2d.h
index 3570b7be52..56ecfa2722 100644
--- a/scene/resources/ray_shape_2d.h
+++ b/scene/resources/ray_shape_2d.h
@@ -36,8 +36,8 @@
class RayShape2D : public Shape2D {
GDCLASS(RayShape2D, Shape2D);
- real_t length;
- bool slips_on_slope;
+ real_t length = 20.0;
+ bool slips_on_slope = false;
void _update_shape();
diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp
index a332bb575f..5446b4daab 100644
--- a/scene/resources/ray_shape_3d.cpp
+++ b/scene/resources/ray_shape_3d.cpp
@@ -56,7 +56,6 @@ void RayShape3D::set_length(float p_length) {
length = p_length;
_update_shape();
notify_change_to_owners();
- _change_notify("length");
}
float RayShape3D::get_length() const {
@@ -67,7 +66,6 @@ void RayShape3D::set_slips_on_slope(bool p_active) {
slips_on_slope = p_active;
_update_shape();
notify_change_to_owners();
- _change_notify("slips_on_slope");
}
bool RayShape3D::get_slips_on_slope() const {
@@ -87,12 +85,7 @@ void RayShape3D::_bind_methods() {
RayShape3D::RayShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_RAY)) {
- length = 1.0;
- slips_on_slope = false;
-
/* Code copied from setters to prevent the use of uninitialized variables */
_update_shape();
notify_change_to_owners();
- _change_notify("length");
- _change_notify("slips_on_slope");
}
diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h
index 2c27d56c63..2da6311321 100644
--- a/scene/resources/ray_shape_3d.h
+++ b/scene/resources/ray_shape_3d.h
@@ -34,8 +34,8 @@
class RayShape3D : public Shape3D {
GDCLASS(RayShape3D, Shape3D);
- float length;
- bool slips_on_slope;
+ float length = 1.0;
+ bool slips_on_slope = false;
protected:
static void _bind_methods();
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index a5b909c9a7..dc4c6dc2d7 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -33,7 +33,7 @@
#include "servers/physics_server_2d.h"
#include "servers/rendering_server.h"
void RectangleShape2D::_update_shape() {
- PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), size / 2);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), size * 0.5);
emit_changed();
}
@@ -47,11 +47,29 @@ Vector2 RectangleShape2D::get_size() const {
}
void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-size / 2, size), p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-size * 0.5, size), p_color);
+ if (is_collision_outline_enabled()) {
+ // Draw an outlined rectangle to make individual shapes easier to distinguish.
+ Vector<Vector2> stroke_points;
+ stroke_points.resize(5);
+ stroke_points.write[0] = -size * 0.5;
+ stroke_points.write[1] = Vector2(size.x, -size.y) * 0.5;
+ stroke_points.write[2] = size * 0.5;
+ stroke_points.write[3] = Vector2(-size.x, size.y) * 0.5;
+ stroke_points.write[4] = -size * 0.5;
+
+ Vector<Color> stroke_colors;
+ stroke_colors.resize(5);
+ for (int i = 0; i < 5; i++) {
+ stroke_colors.write[i] = (p_color);
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors);
+ }
}
Rect2 RectangleShape2D::get_rect() const {
- return Rect2(-size / 2, size);
+ return Rect2(-size * 0.5, size);
}
real_t RectangleShape2D::get_enclosing_radius() const {
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 433e3392e3..f2751b7604 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -114,23 +114,8 @@ Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, R
}
int index = token.value;
-
- if (use_nocache) {
- r_res = int_resources[index];
- } else {
- String path = local_path + "::" + itos(index);
-
- if (!ignore_resource_parsing) {
- if (!ResourceCache::has(path)) {
- r_err_str = "Can't load cached sub-resource: " + path;
- return ERR_PARSE_ERROR;
- }
-
- r_res = RES(ResourceCache::get(path));
- } else {
- r_res = RES();
- }
- }
+ ERR_FAIL_COND_V(!int_resources.has(index), ERR_INVALID_PARAMETER);
+ r_res = int_resources[index];
VariantParser::get_token(p_stream, token, line, r_err_str);
if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
@@ -440,7 +425,7 @@ Error ResourceLoaderText::load() {
er.type = type;
if (use_sub_threads) {
- Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, local_path);
+ Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
if (err != OK) {
if (ResourceLoader::get_abort_on_missing_resources()) {
@@ -517,29 +502,44 @@ Error ResourceLoaderText::load() {
//bool exists=ResourceCache::has(path);
Ref<Resource> res;
+ bool do_assign = false;
- if (use_nocache || !ResourceCache::has(path)) { //only if it doesn't exist
-
- Object *obj = ClassDB::instance(type);
- if (!obj) {
- error_text += "Can't create sub resource of type: " + type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //reuse existing
+ Resource *r = ResourceCache::get(path);
+ if (r && r->get_class() == type) {
+ res = Ref<Resource>(r);
+ res->reset_state();
+ do_assign = true;
}
+ }
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- error_text += "Can't create sub resource of type, because not a resource: " + type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
+ if (res.is_null()) { //not reuse
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ //cached, do not assign
+ Resource *r = ResourceCache::get(path);
+ res = Ref<Resource>(r);
+ } else {
+ //create
- res = Ref<Resource>(r);
- int_resources[id] = res;
- if (!use_nocache) {
- res->set_path(path);
+ Object *obj = ClassDB::instance(type);
+ if (!obj) {
+ error_text += "Can't create sub resource of type: " + type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ error_text += "Can't create sub resource of type, because not a resource: " + type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ res = Ref<Resource>(r);
+ do_assign = true;
}
}
@@ -557,7 +557,7 @@ Error ResourceLoaderText::load() {
}
if (assign != String()) {
- if (res.is_valid()) {
+ if (do_assign) {
res->set(assign, value);
}
//it's assignment
@@ -572,6 +572,11 @@ Error ResourceLoaderText::load() {
}
}
+ int_resources[id] = res; //always assign int resources
+ if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
+ }
+
if (progress && resources_total > 0) {
*progress = resource_current / float(resources_total);
}
@@ -589,23 +594,33 @@ Error ResourceLoaderText::load() {
return error;
}
- Object *obj = ClassDB::instance(res_type);
- if (!obj) {
- error_text += "Can't create sub resource of type: " + res_type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
+ Resource *r = ResourceCache::get(local_path);
+ if (r->get_class() == res_type) {
+ r->reset_state();
+ resource = Ref<Resource>(r);
+ }
}
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- error_text += "Can't create sub resource of type, because not a resource: " + res_type;
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
+ if (!resource.is_valid()) {
+ Object *obj = ClassDB::instance(res_type);
+ if (!obj) {
+ error_text += "Can't create sub resource of type: " + res_type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ error_text += "Can't create sub resource of type, because not a resource: " + res_type;
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
- resource = Ref<Resource>(r);
+ resource = Ref<Resource>(r);
+ }
resource_current++;
@@ -620,7 +635,7 @@ Error ResourceLoaderText::load() {
_printerr();
} else {
error = OK;
- if (!use_nocache) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
if (!ResourceCache::has(res_path)) {
resource->set_path(res_path);
}
@@ -668,7 +683,7 @@ Error ResourceLoaderText::load() {
error = OK;
//get it here
resource = packed_scene;
- if (!use_nocache && !ResourceCache::has(res_path)) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
packed_scene->set_path(res_path);
}
@@ -699,18 +714,7 @@ void ResourceLoaderText::set_translation_remapped(bool p_remapped) {
translation_remapped = p_remapped;
}
-ResourceLoaderText::ResourceLoaderText() {
- use_nocache = false;
-
- resources_total = 0;
- resource_current = 0;
-
- progress = nullptr;
- lines = false;
- translation_remapped = false;
- use_sub_threads = false;
- error = OK;
-}
+ResourceLoaderText::ResourceLoaderText() {}
ResourceLoaderText::~ResourceLoaderText() {
memdelete(f);
@@ -1252,7 +1256,7 @@ String ResourceLoaderText::recognize(FileAccess *p_f) {
/////////////////////
-RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -1265,7 +1269,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina
ResourceLoaderText loader;
String path = p_original_path != "" ? p_original_path : p_path;
- loader.use_nocache = p_no_cache;
+ loader.cache_mode = p_cache_mode;
loader.use_sub_threads = p_use_sub_threads;
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
loader.progress = r_progress;
@@ -1317,7 +1321,7 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
- return ""; //could not rwead
+ return ""; //could not read
}
ResourceLoaderText loader;
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index e67a13d41a..2dc683415d 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -38,12 +38,12 @@
#include "scene/resources/packed_scene.h"
class ResourceLoaderText {
- bool translation_remapped;
+ bool translation_remapped = false;
String local_path;
String res_path;
String error_text;
- FileAccess *f;
+ FileAccess *f = nullptr;
VariantParser::StreamFile stream;
@@ -53,28 +53,28 @@ class ResourceLoaderText {
String type;
};
- bool is_scene;
+ bool is_scene = false;
String res_type;
- bool ignore_resource_parsing;
+ bool ignore_resource_parsing = false;
//Map<String,String> remaps;
Map<int, ExtResource> ext_resources;
Map<int, RES> int_resources;
- int resources_total;
- int resource_current;
+ int resources_total = 0;
+ int resource_current = 0;
String resource_type;
VariantParser::Tag next_tag;
- bool use_nocache;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
- bool use_sub_threads;
- float *progress;
+ bool use_sub_threads = false;
+ float *progress = nullptr;
- mutable int lines;
+ mutable int lines = 0;
Map<String, String> remaps;
//void _printerr();
@@ -107,7 +107,7 @@ class ResourceLoaderText {
friend class ResourceFormatLoaderText;
- Error error;
+ Error error = OK;
RES resource;
@@ -134,7 +134,7 @@ public:
class ResourceFormatLoaderText : public ResourceFormatLoader {
public:
static ResourceFormatLoaderText *singleton;
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
@@ -152,11 +152,11 @@ class ResourceFormatSaverTextInstance {
Ref<PackedScene> packed_scene;
- bool takeover_paths;
- bool relative_paths;
- bool bundle_resources;
- bool skip_editor;
- FileAccess *f;
+ bool takeover_paths = false;
+ bool relative_paths = false;
+ bool bundle_resources = false;
+ bool skip_editor = false;
+ FileAccess *f = nullptr;
struct NonPersistentKey { //for resource properties generated on the fly
RES base;
@@ -173,7 +173,7 @@ class ResourceFormatSaverTextInstance {
struct ResourceSort {
RES resource;
- int index;
+ int index = 0;
bool operator<(const ResourceSort &p_right) const {
return index < p_right.index;
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 53f3dd1a4b..77c6199794 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -152,9 +152,7 @@ void Shader::_bind_methods() {
}
Shader::Shader() {
- mode = MODE_SPATIAL;
shader = RenderingServer::get_singleton()->shader_create();
- params_cache_dirty = true;
}
Shader::~Shader() {
@@ -163,7 +161,7 @@ Shader::~Shader() {
////////////
-RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index a3f9330055..6563181ca2 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -51,12 +51,12 @@ public:
private:
RID shader;
- Mode mode;
+ Mode mode = MODE_SPATIAL;
// hack the name of performance
// shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make
// conversion fast and save memory.
- mutable bool params_cache_dirty;
+ mutable bool params_cache_dirty = true;
mutable Map<StringName, StringName> params_cache; //map a shader param to a material param..
Map<StringName, Ref<Texture2D>> default_textures;
@@ -102,7 +102,7 @@ VARIANT_ENUM_CAST(Shader::Mode);
class ResourceFormatLoaderShader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 6f3897b0cd..013b1ef1a9 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -29,7 +29,11 @@
/*************************************************************************/
#include "shape_2d.h"
+
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
#include "servers/physics_server_2d.h"
+
RID Shape2D::get_rid() const {
return shape;
}
@@ -105,9 +109,17 @@ void Shape2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
}
+bool Shape2D::is_collision_outline_enabled() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return true;
+ }
+#endif
+ return GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+}
+
Shape2D::Shape2D(const RID &p_rid) {
shape = p_rid;
- custom_bias = 0;
}
Shape2D::~Shape2D() {
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index f5814c42f8..14bdd60e4b 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -38,7 +38,7 @@ class Shape2D : public Resource {
OBJ_SAVE_TYPE(Shape2D);
RID shape;
- real_t custom_bias;
+ real_t custom_bias = 0.0;
protected:
static void _bind_methods();
@@ -61,6 +61,9 @@ public:
/// Returns the radius of a circle that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
virtual RID get_rid() const override;
+
+ static bool is_collision_outline_enabled();
+
Shape2D();
~Shape2D();
};
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index e2df965138..fee8fdbde2 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -58,7 +58,7 @@ void Skin::set_bind_name(int p_index, const StringName &p_name) {
binds_ptr[p_index].name = p_name;
emit_changed();
if (notify_change) {
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -81,6 +81,10 @@ void Skin::clear_binds() {
emit_changed();
}
+void Skin::reset_state() {
+ clear_binds();
+}
+
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
if (name == "bind_count") {
@@ -153,6 +157,4 @@ void Skin::_bind_methods() {
}
Skin::Skin() {
- bind_count = 0;
- binds_ptr = nullptr;
}
diff --git a/scene/resources/skin.h b/scene/resources/skin.h
index 64fe24bbe4..f5d64f96aa 100644
--- a/scene/resources/skin.h
+++ b/scene/resources/skin.h
@@ -44,14 +44,15 @@ class Skin : public Resource {
Vector<Bind> binds;
- Bind *binds_ptr;
- int bind_count;
+ Bind *binds_ptr = nullptr;
+ int bind_count = 0;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
static void _bind_methods();
public:
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 8fcd92bb89..71424ba8ac 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -102,8 +102,6 @@ void Sky::_bind_methods() {
}
Sky::Sky() {
- mode = PROCESS_MODE_AUTOMATIC;
- radiance_size = RADIANCE_SIZE_256;
sky = RS::get_singleton()->sky_create();
}
diff --git a/scene/resources/sky.h b/scene/resources/sky.h
index 46f645a53d..f0226d321d 100644
--- a/scene/resources/sky.h
+++ b/scene/resources/sky.h
@@ -59,8 +59,8 @@ public:
private:
RID sky;
- ProcessMode mode;
- RadianceSize radiance_size;
+ ProcessMode mode = PROCESS_MODE_AUTOMATIC;
+ RadianceSize radiance_size = RADIANCE_SIZE_256;
Ref<Material> sky_material;
protected:
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index b2efecb1cb..f50ee9c4c8 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -194,7 +194,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
code += "uniform float sun_angle_max = 1.74;\n";
code += "uniform float sun_curve : hint_range(0, 1) = 0.05;\n\n";
code += "const float PI = 3.1415926535897932384626433833;\n\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tfloat v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));\n";
code += "\tfloat c = (1.0 - v_angle / (PI * 0.5));\n";
code += "\tvec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0));\n";
@@ -301,7 +301,7 @@ PanoramaSkyMaterial::PanoramaSkyMaterial() {
String code = "shader_type sky;\n\n";
code += "uniform sampler2D source_panorama : filter_linear;\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tCOLOR = texture(source_panorama, SKY_COORDS).rgb;\n";
code += "}";
@@ -521,7 +521,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
code += "\treturn fract(p.x * p.y * p.z * (p.x + p.y + p.z));\n";
code += "}\n\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tif (LIGHT0_ENABLED) {\n";
code += "\t\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n";
code += "\t\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n";
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index 008cb3e1d6..e4b4398063 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -66,7 +66,6 @@ void SphereShape3D::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
- _change_notify("radius");
}
float SphereShape3D::get_radius() const {
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
new file mode 100644
index 0000000000..90c702081b
--- /dev/null
+++ b/scene/resources/sprite_frames.cpp
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* sprite_frames.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "sprite_frames.h"
+
+#include "scene/scene_string_names.h"
+
+void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) {
+ E->get().frames.insert(p_at_pos, p_frame);
+ } else {
+ E->get().frames.push_back(p_frame);
+ }
+
+ emit_changed();
+}
+
+int SpriteFrames::get_frame_count(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ return E->get().frames.size();
+}
+
+void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ E->get().frames.remove(p_idx);
+ emit_changed();
+}
+
+void SpriteFrames::clear(const StringName &p_anim) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+ E->get().frames.clear();
+ emit_changed();
+}
+
+void SpriteFrames::clear_all() {
+ animations.clear();
+ add_animation("default");
+}
+
+void SpriteFrames::add_animation(const StringName &p_anim) {
+ ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
+
+ animations[p_anim] = Anim();
+}
+
+bool SpriteFrames::has_animation(const StringName &p_anim) const {
+ return animations.has(p_anim);
+}
+
+void SpriteFrames::remove_animation(const StringName &p_anim) {
+ animations.erase(p_anim);
+}
+
+void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
+ ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'.");
+ ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists.");
+
+ Anim anim = animations[p_prev];
+ animations.erase(p_prev);
+ animations[p_next] = anim;
+}
+
+Vector<String> SpriteFrames::_get_animation_list() const {
+ Vector<String> ret;
+ List<StringName> al;
+ get_animation_list(&al);
+ for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
+ ret.push_back(E->get());
+ }
+
+ return ret;
+}
+
+void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
+ for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ r_animations->push_back(E->key());
+ }
+}
+
+Vector<String> SpriteFrames::get_animation_names() const {
+ Vector<String> names;
+ for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ names.push_back(E->key());
+ }
+ names.sort();
+ return names;
+}
+
+void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
+ ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ E->get().speed = p_fps;
+}
+
+float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+ return E->get().speed;
+}
+
+void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ E->get().loop = p_loop;
+}
+
+bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
+ return E->get().loop;
+}
+
+void SpriteFrames::_set_frames(const Array &p_frames) {
+ clear_all();
+ Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
+ ERR_FAIL_COND(!E);
+
+ E->get().frames.resize(p_frames.size());
+ for (int i = 0; i < E->get().frames.size(); i++) {
+ E->get().frames.write[i] = p_frames[i];
+ }
+}
+
+Array SpriteFrames::_get_frames() const {
+ return Array();
+}
+
+Array SpriteFrames::_get_animations() const {
+ Array anims;
+ for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ Dictionary d;
+ d["name"] = E->key();
+ d["speed"] = E->get().speed;
+ d["loop"] = E->get().loop;
+ Array frames;
+ for (int i = 0; i < E->get().frames.size(); i++) {
+ frames.push_back(E->get().frames[i]);
+ }
+ d["frames"] = frames;
+ anims.push_back(d);
+ }
+
+ return anims;
+}
+
+void SpriteFrames::_set_animations(const Array &p_animations) {
+ animations.clear();
+ for (int i = 0; i < p_animations.size(); i++) {
+ Dictionary d = p_animations[i];
+
+ ERR_CONTINUE(!d.has("name"));
+ ERR_CONTINUE(!d.has("speed"));
+ ERR_CONTINUE(!d.has("loop"));
+ ERR_CONTINUE(!d.has("frames"));
+
+ Anim anim;
+ anim.speed = d["speed"];
+ anim.loop = d["loop"];
+ Array frames = d["frames"];
+ for (int j = 0; j < frames.size(); j++) {
+ RES res = frames[j];
+ anim.frames.push_back(res);
+ }
+
+ animations[d["name"]] = anim;
+ }
+}
+
+void SpriteFrames::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
+ ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
+ ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
+ ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
+
+ ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
+
+ ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
+ ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
+
+ ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
+ ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
+
+ ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
+ ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
+ ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
+ ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
+ ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
+ ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
+
+ ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
+ ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
+
+ ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
+ ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+}
+
+SpriteFrames::SpriteFrames() {
+ add_animation(SceneStringNames::get_singleton()->_default);
+}
diff --git a/editor/input_map_editor.h b/scene/resources/sprite_frames.h
index cc6ac1660d..282c5f20ab 100644
--- a/editor/input_map_editor.h
+++ b/scene/resources/sprite_frames.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* input_map_editor.h */
+/* sprite_frames.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,82 +28,75 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef INPUT_MAP_EDITOR_H
-#define INPUT_MAP_EDITOR_H
+#ifndef SPRITE_FRAMES_H
+#define SPRITE_FRAMES_H
-#include "core/object/undo_redo.h"
-#include "editor/editor_data.h"
+#include "scene/resources/texture.h"
-class InputMapEditor : public Control {
- GDCLASS(InputMapEditor, Control);
+class SpriteFrames : public Resource {
+ GDCLASS(SpriteFrames, Resource);
- enum InputType {
- INPUT_KEY,
- INPUT_KEY_PHYSICAL,
- INPUT_JOY_BUTTON,
- INPUT_JOY_MOTION,
- INPUT_MOUSE_BUTTON
+ struct Anim {
+ float speed = 5.0;
+ bool loop = true;
+ Vector<Ref<Texture2D>> frames;
};
- Tree *input_editor;
- LineEdit *action_name;
- Button *action_add;
- Label *action_add_error;
-
- InputType add_type;
- String add_at;
- int edit_idx;
-
- PopupMenu *popup_add;
- ConfirmationDialog *press_a_key;
- bool press_a_key_physical;
- Label *press_a_key_label;
- ConfirmationDialog *device_input;
- OptionButton *device_id;
- OptionButton *device_index;
- Label *device_index_label;
- MenuButton *popup_copy_to_feature;
-
- Ref<InputEventKey> last_wait_for_key;
-
- AcceptDialog *message;
- UndoRedo *undo_redo;
- String inputmap_changed;
- bool setting = false;
-
- void _update_actions();
- void _add_item(int p_item, Ref<InputEvent> p_exiting_event = Ref<InputEvent>());
- void _edit_item(Ref<InputEvent> p_exiting_event);
-
- void _action_check(String p_action);
- void _action_adds(String);
- void _action_add();
- void _device_input_add();
-
- void _action_selected();
- void _action_edited();
- void _action_activated();
- void _action_button_pressed(Object *p_obj, int p_column, int p_id);
- void _wait_for_key(const Ref<InputEvent> &p_event);
- void _press_a_key_confirm();
- void _show_last_added(const Ref<InputEvent> &p_event, const String &p_name);
-
- String _get_joypad_motion_event_text(const Ref<InputEventJoypadMotion> &p_event);
-
- Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ Map<StringName, Anim> animations;
-protected:
- int _get_current_device();
- void _set_current_device(int i_device);
- String _get_device_string(int i_device);
+ Array _get_frames() const;
+ void _set_frames(const Array &p_frames);
+
+ Array _get_animations() const;
+ void _set_animations(const Array &p_animations);
- void _notification(int p_what);
+ Vector<String> _get_animation_list() const;
+
+protected:
static void _bind_methods();
public:
- InputMapEditor();
+ void add_animation(const StringName &p_anim);
+ bool has_animation(const StringName &p_anim) const;
+ void remove_animation(const StringName &p_anim);
+ void rename_animation(const StringName &p_prev, const StringName &p_next);
+
+ void get_animation_list(List<StringName> *r_animations) const;
+ Vector<String> get_animation_names() const;
+
+ void set_animation_speed(const StringName &p_anim, float p_fps);
+ float get_animation_speed(const StringName &p_anim) const;
+
+ void set_animation_loop(const StringName &p_anim, bool p_loop);
+ bool get_animation_loop(const StringName &p_anim) const;
+
+ void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
+ int get_frame_count(const StringName &p_anim) const;
+ _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+ if (p_idx >= E->get().frames.size()) {
+ return Ref<Texture2D>();
+ }
+
+ return E->get().frames[p_idx];
+ }
+
+ void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
+ Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND(p_idx < 0);
+ if (p_idx >= E->get().frames.size()) {
+ return;
+ }
+ E->get().frames.write[p_idx] = p_frame;
+ }
+ void remove_frame(const StringName &p_anim, int p_idx);
+ void clear(const StringName &p_anim);
+ void clear_all();
+
+ SpriteFrames();
};
-#endif // INPUT_MAP_EDITOR_H
+#endif // SPRITE_FRAMES_H
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 7504a05a49..2159f1bc97 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -123,7 +123,6 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) {
}
emit_signal("texture_changed");
emit_changed();
- _change_notify("texture");
}
Ref<Texture2D> StyleBoxTexture::get_texture() const {
@@ -135,13 +134,6 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) {
margin[p_side] = p_size;
emit_changed();
- static const char *margin_prop[4] = {
- "content_margin_left",
- "content_margin_top",
- "content_margin_right",
- "content_margin_bottom",
- };
- _change_notify(margin_prop[p_side]);
}
float StyleBoxTexture::get_margin_size(Side p_side) const {
@@ -228,7 +220,6 @@ void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
emit_changed();
- _change_notify("region");
}
Rect2 StyleBoxTexture::get_region_rect() const {
@@ -320,20 +311,9 @@ void StyleBoxTexture::_bind_methods() {
BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT);
}
-StyleBoxTexture::StyleBoxTexture() {
- for (int i = 0; i < 4; i++) {
- margin[i] = 0;
- expand_margin[i] = 0;
- }
- draw_center = true;
- modulate = Color(1, 1, 1, 1);
-
- axis_h = AXIS_STRETCH_MODE_STRETCH;
- axis_v = AXIS_STRETCH_MODE_STRETCH;
-}
+StyleBoxTexture::StyleBoxTexture() {}
-StyleBoxTexture::~StyleBoxTexture() {
-}
+StyleBoxTexture::~StyleBoxTexture() {}
////////////////
@@ -480,6 +460,7 @@ Point2 StyleBoxFlat::get_shadow_offset() const {
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 {
@@ -801,6 +782,12 @@ float StyleBoxFlat::get_style_margin(Side p_side) const {
return border_width[p_side];
}
+void StyleBoxFlat::_validate_property(PropertyInfo &property) const {
+ if (!anti_aliased && property.name == "anti_aliasing_size") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
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);
@@ -888,38 +875,9 @@ void StyleBoxFlat::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "1,5,1"), "set_aa_size", "get_aa_size");
}
-StyleBoxFlat::StyleBoxFlat() {
- bg_color = Color(0.6, 0.6, 0.6);
- shadow_color = Color(0, 0, 0, 0.6);
- border_color = Color(0.8, 0.8, 0.8);
-
- blend_border = false;
- draw_center = true;
- anti_aliased = true;
+StyleBoxFlat::StyleBoxFlat() {}
- shadow_size = 0;
- shadow_offset = Point2(0, 0);
- corner_detail = 8;
- aa_size = 1;
-
- border_width[0] = 0;
- border_width[1] = 0;
- border_width[2] = 0;
- border_width[3] = 0;
-
- expand_margin[0] = 0;
- expand_margin[1] = 0;
- expand_margin[2] = 0;
- expand_margin[3] = 0;
-
- corner_radius[0] = 0;
- corner_radius[1] = 0;
- corner_radius[2] = 0;
- corner_radius[3] = 0;
-}
-
-StyleBoxFlat::~StyleBoxFlat() {
-}
+StyleBoxFlat::~StyleBoxFlat() {}
void StyleBoxLine::set_color(const Color &p_color) {
color = p_color;
@@ -986,8 +944,17 @@ void StyleBoxLine::_bind_methods() {
}
float StyleBoxLine::get_style_margin(Side p_side) const {
- ERR_FAIL_INDEX_V((int)p_side, 4, thickness);
- return thickness;
+ 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;
}
Size2 StyleBoxLine::get_center_size() const {
@@ -1011,12 +978,6 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
vs->canvas_item_add_rect(p_canvas_item, r, color);
}
-StyleBoxLine::StyleBoxLine() {
- grow_begin = 1.0;
- grow_end = 1.0;
- thickness = 1;
- color = Color(0.0, 0.0, 0.0);
- vertical = false;
-}
+StyleBoxLine::StyleBoxLine() {}
StyleBoxLine::~StyleBoxLine() {}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index c133f0c825..dd5c873a00 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -86,14 +86,14 @@ public:
};
private:
- float expand_margin[4];
- float margin[4];
+ float expand_margin[4] = {};
+ float margin[4] = {};
Rect2 region_rect;
Ref<Texture2D> texture;
- bool draw_center;
- Color modulate;
- AxisStretchMode axis_h;
- AxisStretchMode axis_v;
+ 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;
@@ -139,26 +139,27 @@ VARIANT_ENUM_CAST(StyleBoxTexture::AxisStretchMode)
class StyleBoxFlat : public StyleBox {
GDCLASS(StyleBoxFlat, StyleBox);
- Color bg_color;
- Color shadow_color;
- Color border_color;
+ 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);
- int border_width[4];
- int expand_margin[4];
- int corner_radius[4];
+ int border_width[4] = {};
+ int expand_margin[4] = {};
+ int corner_radius[4] = {};
- bool draw_center;
- bool blend_border;
- bool anti_aliased;
+ bool draw_center = true;
+ bool blend_border = false;
+ bool anti_aliased = true;
- int corner_detail;
- int shadow_size;
+ int corner_detail = 8;
+ int shadow_size = 0;
Point2 shadow_offset;
- int aa_size;
+ int aa_size = 1;
protected:
virtual float get_style_margin(Side p_side) const override;
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const override;
public:
//Color
@@ -231,10 +232,10 @@ public:
class StyleBoxLine : public StyleBox {
GDCLASS(StyleBoxLine, StyleBox);
Color color;
- int thickness;
- bool vertical;
- float grow_begin;
- float grow_end;
+ 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;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index dbf5268762..c30bd7927d 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -160,7 +160,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
//cap
weights.resize(expected_vertices);
//renormalize
- float total = 0;
+ float total = 0.0;
for (int i = 0; i < expected_vertices; i++) {
total += weights[i].weight;
}
@@ -299,6 +299,7 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect
void SurfaceTool::add_index(int p_index) {
ERR_FAIL_COND(!begun);
+ ERR_FAIL_COND(p_index < 0);
format |= Mesh::ARRAY_FORMAT_INDEX;
index_array.push_back(p_index);
@@ -1058,6 +1059,10 @@ void SurfaceTool::set_material(const Ref<Material> &p_material) {
material = p_material;
}
+Ref<Material> SurfaceTool::get_material() const {
+ return material;
+}
+
void SurfaceTool::clear() {
begun = false;
primitive = Mesh::PRIMITIVE_LINES;
@@ -1087,6 +1092,10 @@ void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) {
ERR_FAIL_COND(begun);
last_custom_format[p_index] = p_format;
}
+
+Mesh::PrimitiveType SurfaceTool::get_primitive() const {
+ return primitive;
+}
SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const {
ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX);
return last_custom_format[p_index];
@@ -1096,7 +1105,7 @@ void SurfaceTool::optimize_indices_for_cache() {
ERR_FAIL_COND(index_array.size() == 0);
LocalVector old_index_array = index_array;
- zeromem(index_array.ptr(), index_array.size() * sizeof(int));
+ memset(index_array.ptr(), 0, index_array.size() * sizeof(int));
optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
}
@@ -1173,6 +1182,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3));
ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material);
+ ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive);
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
@@ -1196,12 +1206,7 @@ void SurfaceTool::_bind_methods() {
}
SurfaceTool::SurfaceTool() {
- first = false;
- begun = false;
for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) {
last_custom_format[i] = CUSTOM_MAX;
}
- primitive = Mesh::PRIMITIVE_LINES;
- skin_weights = SKIN_4_WEIGHTS;
- format = 0;
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index ea6069e7c1..28addf2245 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -89,17 +89,17 @@ private:
};
struct WeightSort {
- int index;
- float weight;
+ int index = 0;
+ float weight = 0.0;
bool operator<(const WeightSort &p_right) const {
return weight < p_right.weight;
}
};
- bool begun;
- bool first;
- Mesh::PrimitiveType primitive;
- uint32_t format;
+ bool begun = false;
+ bool first = false;
+ Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_LINES;
+ uint32_t format = 0;
Ref<Material> material;
//arrays
LocalVector<Vertex> vertex_array;
@@ -115,7 +115,7 @@ private:
Plane last_tangent;
uint32_t last_smooth_group = 0;
- SkinWeightCount skin_weights;
+ SkinWeightCount skin_weights = SKIN_4_WEIGHTS;
Color last_custom[RS::ARRAY_CUSTOM_COUNT];
@@ -143,6 +143,8 @@ public:
void set_custom_format(int p_index, CustomFormat p_format);
CustomFormat get_custom_format(int p_index) const;
+ Mesh::PrimitiveType get_primitive() const;
+
void begin(Mesh::PrimitiveType p_primitive);
void set_color(Color p_color);
@@ -171,6 +173,7 @@ public:
Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3);
void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
void clear();
diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h
index c9db8e31a2..f3964b0c8f 100644
--- a/scene/resources/syntax_highlighter.h
+++ b/scene/resources/syntax_highlighter.h
@@ -75,7 +75,7 @@ private:
Color color;
String start_key;
String end_key;
- bool line_only;
+ bool line_only = false;
};
Vector<ColorRegion> color_regions;
Map<int, int> color_region_cache;
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index ed69c093cf..925867a1f2 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -167,6 +167,7 @@ void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) {
}
bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index 3e0a74a84b..74d4f2c32c 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -45,7 +45,7 @@ class TextLine : public Reference {
bool dirty = true;
- float width = -1;
+ float width = -1.0;
uint8_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HAlign align = HALIGN_LEFT;
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 94957df510..341f5abd80 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -98,6 +98,9 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position);
ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_spacing_top"), &TextParagraph::get_spacing_top);
+ ClassDB::bind_method(D_METHOD("get_spacing_bottom"), &TextParagraph::get_spacing_bottom);
+
ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size);
ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines);
@@ -243,6 +246,7 @@ TextServer::Orientation TextParagraph::get_orientation() const {
}
bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
@@ -257,6 +261,7 @@ void TextParagraph::clear_dropcap() {
}
bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
+ ERR_FAIL_COND_V(p_fonts.is_null(), false);
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
@@ -264,6 +269,14 @@ bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, i
return res;
}
+int TextParagraph::get_spacing_top() const {
+ return spacing_top;
+}
+
+int TextParagraph::get_spacing_bottom() const {
+ return spacing_bottom;
+}
+
void TextParagraph::_set_bidi_override(const Array &p_override) {
Vector<Vector2i> overrides;
for (int i = 0; i < p_override.size(); i++) {
@@ -607,11 +620,13 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- if (ofs.y < 0)
+ if (ofs.y < 0) {
return 0;
+ }
} else {
- if (ofs.x < 0)
+ if (ofs.x < 0) {
return 0;
+ }
}
for (int i = 0; i < lines.size(); i++) {
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index e58c157b01..4396b07130 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -50,7 +50,7 @@ class TextParagraph : public Reference {
bool dirty_lines = true;
- float width = -1;
+ float width = -1.0;
uint8_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HAlign align = HALIGN_LEFT;
@@ -116,6 +116,9 @@ public:
float get_line_underline_position(int p_line) const;
float get_line_underline_thickness(int p_line) const;
+ int get_spacing_top() const;
+ int get_spacing_bottom() const;
+
Size2 get_dropcap_size() const;
int get_dropcap_lines() const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 9a987ae8b1..624eae0411 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -71,7 +71,7 @@ void Texture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_data"), &Texture2D::get_data);
+ ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image);
ADD_GROUP("", "");
}
@@ -94,7 +94,7 @@ void ImageTexture::reload_from_file() {
create_from_image(img);
} else {
Resource::reload_from_file();
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -116,7 +116,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "image") {
- r_ret = get_data();
+ r_ret = get_image();
} else if (p_name == "size") {
r_ret = Size2(w, h);
} else {
@@ -146,12 +146,12 @@ void ImageTexture::_reload_hook(const RID &p_hook) {
RID new_texture = RenderingServer::get_singleton()->texture_2d_create(img);
RenderingServer::get_singleton()->texture_replace(texture, new_texture);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
void ImageTexture::create_from_image(const Ref<Image> &p_image) {
- ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid 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();
@@ -163,7 +163,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image) {
RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
RenderingServer::get_singleton()->texture_replace(texture, new_texture);
}
- _change_notify();
+ notify_property_list_changed();
emit_changed();
image_stored = true;
@@ -189,7 +189,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) {
RenderingServer::get_singleton()->texture_2d_update(texture, p_image);
}
- _change_notify();
+ notify_property_list_changed();
emit_changed();
alpha_cache.unref();
@@ -200,7 +200,7 @@ void ImageTexture::_resource_path_changed() {
String path = get_path();
}
-Ref<Image> ImageTexture::get_data() const {
+Ref<Image> ImageTexture::get_image() const {
if (image_stored) {
return RenderingServer::get_singleton()->texture_2d_get(texture);
} else {
@@ -251,7 +251,7 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_data();
+ Ref<Image> img = get_image();
if (img.is_valid()) {
if (img->is_compressed()) { //must decompress, if compressed
Ref<Image> decom = img->duplicate();
@@ -310,12 +310,7 @@ void ImageTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook);
}
-ImageTexture::ImageTexture() {
- w = h = 0;
- image_stored = false;
- mipmaps = false;
- format = Image::FORMAT_L8;
-}
+ImageTexture::ImageTexture() {}
ImageTexture::~ImageTexture() {
if (texture.is_valid()) {
@@ -415,7 +410,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
Vector<uint8_t> id = mipmap_images[i]->get_data();
int len = id.size();
const uint8_t *r = id.ptr();
- copymem(&wr[ofs], r, len);
+ memcpy(&wr[ofs], r, len);
ofs += len;
}
}
@@ -617,7 +612,7 @@ Error StreamTexture2D::load(const String &p_path) {
}
#endif
- _change_notify();
+ notify_property_list_changed();
emit_changed();
return OK;
}
@@ -666,7 +661,7 @@ bool StreamTexture2D::has_alpha() const {
return false;
}
-Ref<Image> StreamTexture2D::get_data() const {
+Ref<Image> StreamTexture2D::get_image() const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_2d_get(texture);
} else {
@@ -676,7 +671,7 @@ Ref<Image> StreamTexture2D::get_data() const {
bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const {
if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_data();
+ Ref<Image> img = get_image();
if (img.is_valid()) {
if (img->is_compressed()) { //must decompress, if compressed
Ref<Image> decom = img->duplicate();
@@ -733,11 +728,7 @@ void StreamTexture2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
}
-StreamTexture2D::StreamTexture2D() {
- format = Image::FORMAT_MAX;
- w = 0;
- h = 0;
-}
+StreamTexture2D::StreamTexture2D() {}
StreamTexture2D::~StreamTexture2D() {
if (texture.is_valid()) {
@@ -745,7 +736,7 @@ StreamTexture2D::~StreamTexture2D() {
}
}
-RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTexture2D::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<StreamTexture2D> st;
st.instance();
Error err = st->load(p_path);
@@ -968,7 +959,7 @@ Error StreamTexture3D::load(const String &p_path) {
RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
- _change_notify();
+ notify_property_list_changed();
emit_changed();
return OK;
}
@@ -1033,13 +1024,7 @@ void StreamTexture3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path");
}
-StreamTexture3D::StreamTexture3D() {
- format = Image::FORMAT_MAX;
- w = 0;
- h = 0;
- d = 0;
- mipmaps = false;
-}
+StreamTexture3D::StreamTexture3D() {}
StreamTexture3D::~StreamTexture3D() {
if (texture.is_valid()) {
@@ -1049,7 +1034,7 @@ StreamTexture3D::~StreamTexture3D() {
/////////////////////////////
-RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTexture3D::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<StreamTexture3D> st;
st.instance();
Error err = st->load(p_path);
@@ -1125,7 +1110,6 @@ void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) {
}
atlas = p_atlas;
emit_changed();
- _change_notify("atlas");
}
Ref<Texture2D> AtlasTexture::get_atlas() const {
@@ -1138,7 +1122,6 @@ void AtlasTexture::set_region(const Rect2 &p_region) {
}
region = p_region;
emit_changed();
- _change_notify("region");
}
Rect2 AtlasTexture::get_region() const {
@@ -1151,7 +1134,6 @@ void AtlasTexture::set_margin(const Rect2 &p_margin) {
}
margin = p_margin;
emit_changed();
- _change_notify("margin");
}
Rect2 AtlasTexture::get_margin() const {
@@ -1161,7 +1143,6 @@ Rect2 AtlasTexture::get_margin() const {
void AtlasTexture::set_filter_clip(const bool p_enable) {
filter_clip = p_enable;
emit_changed();
- _change_notify("filter_clip");
}
bool AtlasTexture::has_filter_clip() const {
@@ -1295,9 +1276,7 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
return atlas->is_pixel_opaque(x, y);
}
-AtlasTexture::AtlasTexture() {
- filter_clip = false;
-}
+AtlasTexture::AtlasTexture() {}
/////////////////////////////////////////
@@ -1426,185 +1405,6 @@ MeshTexture::MeshTexture() {
//////////////////////////////////////////
-int LargeTexture::get_width() const {
- return size.width;
-}
-
-int LargeTexture::get_height() const {
- return size.height;
-}
-
-RID LargeTexture::get_rid() const {
- return RID();
-}
-
-bool LargeTexture::has_alpha() const {
- for (int i = 0; i < pieces.size(); i++) {
- if (pieces[i].texture->has_alpha()) {
- return true;
- }
- }
-
- return false;
-}
-
-int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND_V(p_texture.is_null(), -1);
- Piece p;
- p.offset = p_offset;
- p.texture = p_texture;
- pieces.push_back(p);
-
- return pieces.size() - 1;
-}
-
-void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) {
- ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces.write[p_idx].offset = p_offset;
-};
-
-void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND(p_texture == this);
- ERR_FAIL_COND(p_texture.is_null());
- ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces.write[p_idx].texture = p_texture;
-};
-
-void LargeTexture::set_size(const Size2 &p_size) {
- size = p_size;
-}
-
-void LargeTexture::clear() {
- pieces.clear();
- size = Size2i();
-}
-
-Array LargeTexture::_get_data() const {
- Array arr;
- for (int i = 0; i < pieces.size(); i++) {
- arr.push_back(pieces[i].offset);
- arr.push_back(pieces[i].texture);
- }
- arr.push_back(Size2(size));
- return arr;
-}
-
-void LargeTexture::_set_data(const Array &p_array) {
- ERR_FAIL_COND(p_array.size() < 1);
- ERR_FAIL_COND(!(p_array.size() & 1));
- clear();
- for (int i = 0; i < p_array.size() - 1; i += 2) {
- add_piece(p_array[i], p_array[i + 1]);
- }
- size = Size2(p_array[p_array.size() - 1]);
-}
-
-int LargeTexture::get_piece_count() const {
- return pieces.size();
-}
-
-Vector2 LargeTexture::get_piece_offset(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, pieces.size(), Vector2());
- return pieces[p_idx].offset;
-}
-
-Ref<Texture2D> LargeTexture::get_piece_texture(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref<Texture2D>());
- return pieces[p_idx].texture;
-}
-
-Ref<Image> LargeTexture::to_image() const {
- Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8));
- for (int i = 0; i < pieces.size(); i++) {
- Ref<Image> src_img = pieces[i].texture->get_data();
- img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset);
- }
-
- return img;
-}
-
-void LargeTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_piece", "ofs", "texture"), &LargeTexture::add_piece);
- ClassDB::bind_method(D_METHOD("set_piece_offset", "idx", "ofs"), &LargeTexture::set_piece_offset);
- ClassDB::bind_method(D_METHOD("set_piece_texture", "idx", "texture"), &LargeTexture::set_piece_texture);
- ClassDB::bind_method(D_METHOD("set_size", "size"), &LargeTexture::set_size);
- ClassDB::bind_method(D_METHOD("clear"), &LargeTexture::clear);
-
- ClassDB::bind_method(D_METHOD("get_piece_count"), &LargeTexture::get_piece_count);
- ClassDB::bind_method(D_METHOD("get_piece_offset", "idx"), &LargeTexture::get_piece_offset);
- ClassDB::bind_method(D_METHOD("get_piece_texture", "idx"), &LargeTexture::get_piece_texture);
-
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &LargeTexture::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &LargeTexture::_get_data);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
-}
-
-void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose);
- }
-}
-
-void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- //tiling not supported for this
- if (size.x == 0 || size.y == 0) {
- return;
- }
-
- Size2 scale = p_rect.size / size;
-
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose);
- }
-}
-
-void LargeTexture::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 {
- //tiling not supported for this
- if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) {
- return;
- }
-
- Size2 scale = p_rect.size / p_src_rect.size;
-
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
- if (!p_src_rect.intersects(rect)) {
- continue;
- }
- Rect2 local = p_src_rect.intersection(rect);
- Rect2 target = local;
- target.size *= scale;
- target.position = p_rect.position + (p_src_rect.position + rect.position) * scale;
- local.position -= rect.position;
- pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, false);
- }
-}
-
-bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const {
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- if (!pieces[i].texture.is_valid()) {
- continue;
- }
-
- Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
- if (rect.has_point(Point2(p_x, p_y))) {
- return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y);
- }
- }
-
- return true;
-}
-
-LargeTexture::LargeTexture() {
-}
-
-///////////////////
-
void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
@@ -1698,9 +1498,7 @@ RID CurveTexture::get_rid() const {
return _texture;
}
-CurveTexture::CurveTexture() {
- _width = 2048;
-}
+CurveTexture::CurveTexture() {}
CurveTexture::~CurveTexture() {
if (_texture.is_valid()) {
@@ -1711,9 +1509,6 @@ CurveTexture::~CurveTexture() {
//////////////////
GradientTexture::GradientTexture() {
- update_pending = false;
- width = 2048;
-
_queue_update();
}
@@ -1808,7 +1603,7 @@ int GradientTexture::get_width() const {
return width;
}
-Ref<Image> GradientTexture::get_data() const {
+Ref<Image> GradientTexture::get_image() const {
if (!texture.is_valid()) {
return Ref<Image>();
}
@@ -1926,7 +1721,7 @@ void AnimatedTexture::_update_proxy() {
}
}
time -= frame_limit;
- _change_notify("current_frame");
+
} else {
break;
}
@@ -2057,14 +1852,14 @@ bool AnimatedTexture::has_alpha() const {
return frames[current_frame].texture->has_alpha();
}
-Ref<Image> AnimatedTexture::get_data() const {
+Ref<Image> AnimatedTexture::get_image() const {
RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return Ref<Image>();
}
- return frames[current_frame].texture->get_data();
+ return frames[current_frame].texture->get_image();
}
bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
@@ -2128,13 +1923,6 @@ AnimatedTexture::AnimatedTexture() {
proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
- time = 0;
- frame_count = 1;
- fps = 4;
- prev_ticks = 0;
- current_frame = 0;
- pause = false;
- oneshot = false;
RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy));
}
@@ -2288,11 +2076,6 @@ void ImageTextureLayered::_bind_methods() {
ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) {
layered_type = p_layered_type;
- format = Image::FORMAT_MAX;
-
- width = 0;
- height = 0;
- layers = 0;
}
ImageTextureLayered::~ImageTextureLayered() {
@@ -2389,7 +2172,7 @@ Error StreamTextureLayered::load(const String &p_path) {
RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
- _change_notify();
+ notify_property_list_changed();
emit_changed();
return OK;
}
@@ -2460,11 +2243,6 @@ void StreamTextureLayered::_bind_methods() {
StreamTextureLayered::StreamTextureLayered(LayeredType p_type) {
layered_type = p_type;
- format = Image::FORMAT_MAX;
- w = 0;
- h = 0;
- layers = 0;
- mipmaps = false;
}
StreamTextureLayered::~StreamTextureLayered() {
@@ -2475,7 +2253,7 @@ StreamTextureLayered::~StreamTextureLayered() {
/////////////////////////////////////////////////
-RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderStreamTextureLayered::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<StreamTextureLayered> st;
if (p_path.get_extension().to_lower() == "stexarray") {
Ref<StreamTexture2DArray> s;
@@ -2586,14 +2364,14 @@ uint32_t CameraTexture::get_flags() const {
return 0;
}
-Ref<Image> CameraTexture::get_data() const {
+Ref<Image> CameraTexture::get_image() const {
// not (yet) supported
return Ref<Image>();
}
void CameraTexture::set_camera_feed_id(int p_new_id) {
camera_feed_id = p_new_id;
- _change_notify();
+ notify_property_list_changed();
}
int CameraTexture::get_camera_feed_id() const {
@@ -2602,7 +2380,7 @@ int CameraTexture::get_camera_feed_id() const {
void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) {
which_feed = p_which;
- _change_notify();
+ notify_property_list_changed();
}
CameraServer::FeedImage CameraTexture::get_which_feed() const {
@@ -2613,7 +2391,7 @@ 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);
- _change_notify();
+ notify_property_list_changed();
}
}
@@ -2626,10 +2404,7 @@ bool CameraTexture::get_camera_active() const {
}
}
-CameraTexture::CameraTexture() {
- camera_feed_id = 0;
- which_feed = CameraServer::FEED_RGBA_IMAGE;
-}
+CameraTexture::CameraTexture() {}
CameraTexture::~CameraTexture() {
// nothing to do here yet
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 83ef0c44ae..264d85d187 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -71,7 +71,7 @@ public:
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const;
virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
- virtual Ref<Image> get_data() const { return Ref<Image>(); }
+ virtual Ref<Image> get_image() const { return Ref<Image>(); }
Texture2D();
};
@@ -83,12 +83,13 @@ class ImageTexture : public Texture2D {
RES_BASE_EXTENSION("tex");
mutable RID texture;
- Image::Format format;
- bool mipmaps;
- int w, h;
+ 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;
+ bool image_stored = false;
protected:
virtual void reload_from_file() override;
@@ -107,7 +108,7 @@ public:
Image::Format get_format() const;
void update(const Ref<Image> &p_image, bool p_immediate = false);
- Ref<Image> get_data() const override;
+ Ref<Image> get_image() const override;
int get_width() const override;
int get_height() const override;
@@ -160,8 +161,9 @@ private:
Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, 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;
- int w, h;
+ Image::Format format = Image::FORMAT_MAX;
+ int w = 0;
+ int h = 0;
mutable Ref<BitMap> alpha_cache;
virtual void reload_from_file() override;
@@ -201,7 +203,7 @@ public:
virtual bool has_alpha() const override;
bool is_pixel_opaque(int p_x, int p_y) const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
StreamTexture2D();
~StreamTexture2D();
@@ -209,7 +211,7 @@ public:
class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -223,7 +225,7 @@ protected:
Ref<Texture2D> atlas;
Rect2 region;
Rect2 margin;
- bool filter_clip;
+ bool filter_clip = false;
static void _bind_methods();
@@ -295,51 +297,6 @@ public:
MeshTexture();
};
-class LargeTexture : public Texture2D {
- GDCLASS(LargeTexture, Texture2D);
- RES_BASE_EXTENSION("largetex");
-
-protected:
- struct Piece {
- Point2 offset;
- Ref<Texture2D> texture;
- };
-
- Vector<Piece> pieces;
- Size2i size;
-
- Array _get_data() const;
- void _set_data(const Array &p_array);
- 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;
-
- int add_piece(const Point2 &p_offset, const Ref<Texture2D> &p_texture);
- void set_piece_offset(int p_idx, const Point2 &p_offset);
- void set_piece_texture(int p_idx, const Ref<Texture2D> &p_texture);
-
- void set_size(const Size2 &p_size);
- void clear();
-
- int get_piece_count() const;
- Vector2 get_piece_offset(int p_idx) const;
- Ref<Texture2D> get_piece_texture(int p_idx) const;
- Ref<Image> to_image() 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;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- LargeTexture();
-};
-
class TextureLayered : public Texture {
GDCLASS(TextureLayered, Texture);
@@ -370,12 +327,12 @@ class ImageTextureLayered : public TextureLayered {
LayeredType layered_type;
mutable RID texture;
- Image::Format format;
+ Image::Format format = Image::FORMAT_MAX;
- int width;
- int height;
- int layers;
- bool mipmaps;
+ int width = 0;
+ int height = 0;
+ int layers = 0;
+ bool mipmaps = false;
Error _create_from_images(const Array &p_images);
@@ -453,10 +410,12 @@ 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;
- int w, h, layers;
- bool mipmaps;
- LayeredType layered_type;
+ Image::Format format = Image::FORMAT_MAX;
+ 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;
@@ -509,7 +468,7 @@ public:
class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -594,9 +553,11 @@ 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;
- int w, h, d;
- bool mipmaps;
+ Image::Format format = Image::FORMAT_MAX;
+ int w = 0;
+ int h = 0;
+ int d = 0;
+ bool mipmaps = false;
virtual void reload_from_file() override;
@@ -625,7 +586,7 @@ public:
class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -638,7 +599,7 @@ class CurveTexture : public Texture2D {
private:
mutable RID _texture;
Ref<Curve> _curve;
- int _width;
+ int _width = 2048;
void _update();
@@ -680,7 +641,7 @@ class GradientTexture : public Texture2D {
public:
struct Point {
- float offset;
+ float offset = 0.0;
Color color;
bool operator<(const Point &p_ponit) const {
return offset < p_ponit.offset;
@@ -689,9 +650,9 @@ public:
private:
Ref<Gradient> gradient;
- bool update_pending;
+ bool update_pending = false;
RID texture;
- int width;
+ int width = 2048;
void _queue_update();
void _update();
@@ -710,7 +671,7 @@ public:
virtual int get_height() const override { return 1; }
virtual bool has_alpha() const override { return true; }
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
GradientTexture();
virtual ~GradientTexture();
@@ -758,23 +719,19 @@ private:
struct Frame {
Ref<Texture2D> texture;
- float delay_sec;
-
- Frame() {
- delay_sec = 0;
- }
+ float delay_sec = 0.0;
};
Frame frames[MAX_FRAMES];
- int frame_count;
- int current_frame;
- bool pause;
- bool oneshot;
- float fps;
+ int frame_count = 1.0;
+ int current_frame = 0;
+ bool pause = false;
+ bool oneshot = false;
+ float fps = 4.0;
- float time;
+ float time = 0.0;
- uint64_t prev_ticks;
+ uint64_t prev_ticks = 0;
void _update_proxy();
@@ -810,7 +767,7 @@ public:
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
bool is_pixel_opaque(int p_x, int p_y) const override;
@@ -822,8 +779,8 @@ class CameraTexture : public Texture2D {
GDCLASS(CameraTexture, Texture2D);
private:
- int camera_feed_id;
- CameraServer::FeedImage which_feed;
+ int camera_feed_id = 0;
+ CameraServer::FeedImage which_feed = CameraServer::FEED_RGBA_IMAGE;
protected:
static void _bind_methods();
@@ -837,7 +794,7 @@ public:
virtual void set_flags(uint32_t p_flags);
virtual uint32_t get_flags() const;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
void set_camera_feed_id(int p_new_id);
int get_camera_feed_id() const;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 5279f59d77..e8b203417e 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -141,6 +141,21 @@ Vector<String> Theme::_get_font_size_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_font_size_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_size_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_color_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -201,6 +216,48 @@ Vector<String> Theme::_get_constant_type_list() const {
return ilret;
}
+Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_list(p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_list(p_node_type);
+ case DATA_TYPE_FONT:
+ return _get_font_list(p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_list(p_node_type);
+ case DATA_TYPE_ICON:
+ return _get_icon_list(p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_list(p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
+Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_type_list();
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_type_list();
+ case DATA_TYPE_FONT:
+ return _get_font_type_list();
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_type_list();
+ case DATA_TYPE_ICON:
+ return _get_icon_type_list();
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_type_list();
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
Vector<String> Theme::_get_type_list() const {
Vector<String> ilret;
List<StringName> il;
@@ -358,7 +415,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) {
default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -373,7 +430,7 @@ void Theme::set_default_theme_font_size(int p_font_size) {
default_theme_font_size = p_font_size;
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -421,8 +478,6 @@ void Theme::set_default_font_size(int p_font_size) {
}
void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) {
- //ERR_FAIL_COND(p_icon.is_null());
-
bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name);
if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) {
@@ -436,7 +491,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, co
}
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -453,9 +508,25 @@ bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) co
return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid());
}
+bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(icon_map[p_node_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist.");
+
+ icon_map[p_node_type][p_name] = icon_map[p_node_type][p_old_name];
+ icon_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!icon_map.has(p_node_type));
- ERR_FAIL_COND(!icon_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist.");
if (icon_map[p_node_type][p_name].is_valid()) {
icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
@@ -463,7 +534,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type)
icon_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -481,6 +552,10 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::add_icon_type(const StringName &p_node_type) {
+ icon_map[p_node_type] = HashMap<StringName, Ref<Texture2D>>();
+}
+
void Theme::get_icon_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -491,8 +566,6 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const {
}
void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) {
- //ERR_FAIL_COND(p_style.is_null());
-
bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name);
if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) {
@@ -506,7 +579,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type
}
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
}
emit_changed();
}
@@ -523,9 +596,25 @@ bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type
return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid());
}
+bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(style_map[p_node_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist.");
+
+ style_map[p_node_type][p_name] = style_map[p_node_type][p_old_name];
+ style_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!style_map.has(p_node_type));
- ERR_FAIL_COND(!style_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist.");
if (style_map[p_node_type][p_name].is_valid()) {
style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
@@ -533,7 +622,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_ty
style_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -551,6 +640,10 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_stylebox_type(const StringName &p_node_type) {
+ style_map[p_node_type] = HashMap<StringName, Ref<StyleBox>>();
+}
+
void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -561,8 +654,6 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
}
void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) {
- //ERR_FAIL_COND(p_font.is_null());
-
bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name);
if (font_map[p_node_type][p_name].is_valid()) {
@@ -576,7 +667,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_node_type, co
}
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -595,16 +686,32 @@ bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) co
return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid());
}
+bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (font_map.has(p_node_type) && font_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_map[p_node_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist.");
+
+ font_map[p_node_type][p_name] = font_map[p_node_type][p_old_name];
+ font_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!font_map.has(p_node_type));
- ERR_FAIL_COND(!font_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist.");
if (font_map[p_node_type][p_name].is_valid()) {
font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
font_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -622,6 +729,10 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::add_font_type(const StringName &p_node_type) {
+ font_map[p_node_type] = HashMap<StringName, Ref<Font>>();
+}
+
void Theme::get_font_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -637,7 +748,7 @@ void Theme::set_font_size(const StringName &p_name, const StringName &p_node_typ
font_size_map[p_node_type][p_name] = p_font_size;
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -656,12 +767,28 @@ bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_typ
return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0));
}
+bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_size_map[p_node_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist.");
+
+ font_size_map[p_node_type][p_name] = font_size_map[p_node_type][p_old_name];
+ font_size_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!font_size_map.has(p_node_type));
- ERR_FAIL_COND(!font_size_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist.");
font_size_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -679,13 +806,26 @@ void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_font_size_type(const StringName &p_node_type) {
+ font_size_map[p_node_type] = HashMap<StringName, int>();
+}
+
+void Theme::get_font_size_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = font_size_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) {
bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name);
color_map[p_node_type][p_name] = p_color;
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -702,12 +842,28 @@ bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) c
return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name));
}
+bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(color_map[p_node_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist.");
+
+ color_map[p_node_type][p_name] = color_map[p_node_type][p_old_name];
+ color_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!color_map.has(p_node_type));
- ERR_FAIL_COND(!color_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist.");
color_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -725,6 +881,10 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con
}
}
+void Theme::add_color_type(const StringName &p_node_type) {
+ color_map[p_node_type] = HashMap<StringName, Color>();
+}
+
void Theme::get_color_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -739,7 +899,7 @@ void Theme::set_constant(const StringName &p_name, const StringName &p_node_type
constant_map[p_node_type][p_name] = p_constant;
if (new_value) {
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
}
@@ -756,12 +916,28 @@ bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type
return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name));
}
+bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(constant_map[p_node_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist.");
+
+ constant_map[p_node_type][p_name] = constant_map[p_node_type][p_old_name];
+ constant_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!constant_map.has(p_node_type));
- ERR_FAIL_COND(!constant_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist.");
constant_map[p_node_type].erase(p_name);
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -779,6 +955,10 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_constant_type(const StringName &p_node_type) {
+ constant_map[p_node_type] = HashMap<StringName, int>();
+}
+
void Theme::get_constant_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -788,6 +968,237 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const {
}
}
+void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Color color_value = p_value;
+ set_color(p_name, p_node_type, color_value);
+ } break;
+ case DATA_TYPE_CONSTANT: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ int constant_value = p_value;
+ set_constant(p_name, p_node_type, constant_value);
+ } break;
+ case DATA_TYPE_FONT: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<Font> font_value = Object::cast_to<Font>(p_value.get_validated_object());
+ set_font(p_name, p_node_type, font_value);
+ } break;
+ case DATA_TYPE_FONT_SIZE: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ int font_size_value = p_value;
+ set_font_size(p_name, p_node_type, font_size_value);
+ } break;
+ case DATA_TYPE_ICON: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<Texture2D> icon_value = Object::cast_to<Texture2D>(p_value.get_validated_object());
+ set_icon(p_name, p_node_type, icon_value);
+ } break;
+ case DATA_TYPE_STYLEBOX: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<StyleBox> stylebox_value = Object::cast_to<StyleBox>(p_value.get_validated_object());
+ set_stylebox(p_name, p_node_type, stylebox_value);
+ } break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return get_color(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return get_constant(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return get_font(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return get_font_size(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return get_icon(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return get_stylebox(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Variant();
+}
+
+bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return has_color(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return has_constant(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return has_font(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return has_font_size(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return has_icon(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return has_stylebox(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return false;
+}
+
+bool Theme::has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return has_color_nocheck(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return has_constant_nocheck(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return has_font_nocheck(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return has_font_size_nocheck(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return has_icon_nocheck(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return has_stylebox_nocheck(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return false;
+}
+
+void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ rename_color(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ rename_constant(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ rename_font(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ rename_font_size(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ rename_icon(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ rename_stylebox(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ clear_color(p_name, p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ clear_constant(p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ clear_font(p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ clear_font_size(p_name, p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ clear_icon(p_name, p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ clear_stylebox(p_name, p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ get_color_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_CONSTANT:
+ get_constant_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_FONT:
+ get_font_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ get_font_size_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_ICON:
+ get_icon_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ get_stylebox_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ add_color_type(p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ add_constant_type(p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ add_font_type(p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ add_font_size_type(p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ add_icon_type(p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ add_stylebox_type(p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ get_color_type_list(p_list);
+ break;
+ case DATA_TYPE_CONSTANT:
+ get_constant_type_list(p_list);
+ break;
+ case DATA_TYPE_FONT:
+ get_font_type_list(p_list);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ get_font_size_type_list(p_list);
+ break;
+ case DATA_TYPE_ICON:
+ get_icon_type_list(p_list);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ get_stylebox_type_list(p_list);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
void Theme::clear() {
//these need disconnecting
{
@@ -835,7 +1246,7 @@ void Theme::clear() {
color_map.clear();
constant_map.clear();
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -847,11 +1258,10 @@ void Theme::copy_default_theme() {
void Theme::copy_theme(const Ref<Theme> &p_other) {
if (p_other.is_null()) {
clear();
-
return;
}
- //these need reconnecting, so add normally
+ // These items need reconnecting, so add them normally.
{
const StringName *K = nullptr;
while ((K = p_other->icon_map.next(K))) {
@@ -882,12 +1292,12 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
}
}
- //these are ok to just copy
-
+ // These items can be simply copied.
+ font_size_map = p_other->font_size_map;
color_map = p_other->color_map;
constant_map = p_other->constant_map;
- _change_notify();
+ notify_property_list_changed();
emit_changed();
}
@@ -930,10 +1340,14 @@ void Theme::get_type_list(List<StringName> *p_list) const {
}
}
+void Theme::reset_state() {
+ clear();
+}
void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon);
ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon);
ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon);
+ ClassDB::bind_method(D_METHOD("rename_icon", "old_name", "name", "node_type"), &Theme::rename_icon);
ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon);
ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list);
ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list);
@@ -941,6 +1355,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox);
ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox);
+ ClassDB::bind_method(D_METHOD("rename_stylebox", "old_name", "name", "node_type"), &Theme::rename_stylebox);
ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list);
ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list);
@@ -948,6 +1363,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font);
ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font);
ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font);
+ ClassDB::bind_method(D_METHOD("rename_font", "old_name", "name", "node_type"), &Theme::rename_font);
ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font);
ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list);
ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list);
@@ -955,12 +1371,15 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size);
ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size);
ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size);
+ ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "node_type"), &Theme::rename_font_size);
ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size);
ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list);
+ ClassDB::bind_method(D_METHOD("get_font_size_type_list"), &Theme::_get_font_size_type_list);
ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color);
ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color);
ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color);
+ ClassDB::bind_method(D_METHOD("rename_color", "old_name", "name", "node_type"), &Theme::rename_color);
ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color);
ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list);
ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list);
@@ -968,6 +1387,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant);
ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant);
ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant);
+ ClassDB::bind_method(D_METHOD("rename_constant", "old_name", "name", "node_type"), &Theme::rename_constant);
ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant);
ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list);
ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
@@ -980,6 +1400,14 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size);
ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size);
+ ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "node_type", "value"), &Theme::set_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "node_type"), &Theme::get_theme_item);
+ ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "node_type"), &Theme::has_theme_item);
+ ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "node_type"), &Theme::rename_theme_item);
+ ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "node_type"), &Theme::clear_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "node_type"), &Theme::_get_theme_item_list);
+ ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list);
+
ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme);
@@ -987,6 +1415,14 @@ void Theme::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font");
ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size");
+
+ BIND_ENUM_CONSTANT(DATA_TYPE_COLOR);
+ BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT);
+ BIND_ENUM_CONSTANT(DATA_TYPE_FONT);
+ BIND_ENUM_CONSTANT(DATA_TYPE_FONT_SIZE);
+ BIND_ENUM_CONSTANT(DATA_TYPE_ICON);
+ BIND_ENUM_CONSTANT(DATA_TYPE_STYLEBOX);
+ BIND_ENUM_CONSTANT(DATA_TYPE_MAX);
}
Theme::Theme() {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index c802ba2536..7e887b6343 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -41,6 +41,18 @@ class Theme : public Resource {
GDCLASS(Theme, Resource);
RES_BASE_EXTENSION("theme");
+public:
+ enum DataType {
+ DATA_TYPE_COLOR,
+ DATA_TYPE_CONSTANT,
+ DATA_TYPE_FONT,
+ DATA_TYPE_FONT_SIZE,
+ DATA_TYPE_ICON,
+ DATA_TYPE_STYLEBOX,
+ DATA_TYPE_MAX
+ };
+
+private:
void _emit_theme_changed();
HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
@@ -57,10 +69,14 @@ class Theme : public Resource {
Vector<String> _get_font_list(const String &p_node_type) const;
Vector<String> _get_font_type_list() const;
Vector<String> _get_font_size_list(const String &p_node_type) const;
+ Vector<String> _get_font_size_type_list() const;
Vector<String> _get_color_list(const String &p_node_type) const;
Vector<String> _get_color_type_list() const;
Vector<String> _get_constant_list(const String &p_node_type) const;
Vector<String> _get_constant_type_list() const;
+
+ Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const;
+ Vector<String> _get_theme_item_type_list(DataType p_data_type) const;
Vector<String> _get_type_list() const;
protected:
@@ -80,6 +96,8 @@ protected:
static void _bind_methods();
+ virtual void reset_state() override;
+
public:
static Ref<Theme> get_default();
static void set_default(const Ref<Theme> &p_default);
@@ -101,44 +119,73 @@ public:
void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const;
bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_icon_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_icon(const StringName &p_name, const StringName &p_node_type);
void get_icon_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_icon_type(const StringName &p_node_type);
void get_icon_type_list(List<StringName> *p_list) const;
void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style);
Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_stylebox(const StringName &p_name, const StringName &p_node_type);
void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_stylebox_type(const StringName &p_node_type);
void get_stylebox_type_list(List<StringName> *p_list) const;
void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font);
Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const;
bool has_font(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_font_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_font(const StringName &p_name, const StringName &p_node_type);
void get_font_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_font_type(const StringName &p_node_type);
void get_font_type_list(List<StringName> *p_list) const;
void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size);
int get_font_size(const StringName &p_name, const StringName &p_node_type) const;
bool has_font_size(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_font_size_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_font_size(const StringName &p_name, const StringName &p_node_type);
void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_font_size_type(const StringName &p_node_type);
+ void get_font_size_type_list(List<StringName> *p_list) const;
void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color);
Color get_color(const StringName &p_name, const StringName &p_node_type) const;
bool has_color(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_color_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_color(const StringName &p_name, const StringName &p_node_type);
void get_color_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_color_type(const StringName &p_node_type);
void get_color_type_list(List<StringName> *p_list) const;
void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant);
int get_constant(const StringName &p_name, const StringName &p_node_type) const;
bool has_constant(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_constant_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_constant(const StringName &p_name, const StringName &p_node_type);
void get_constant_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_constant_type(const StringName &p_node_type);
void get_constant_type_list(List<StringName> *p_list) const;
+ void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value);
+ Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
+ void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type);
+ void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const;
+ void add_theme_item_type(DataType p_data_type, const StringName &p_node_type);
+ void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const;
+
void get_type_list(List<StringName> *p_list) const;
void copy_default_theme();
@@ -149,4 +196,6 @@ public:
~Theme();
};
+VARIANT_ENUM_CAST(Theme::DataType);
+
#endif
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index ae536a2928..84be69d0d6 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -369,14 +369,14 @@ void TileSet::create_tile(int p_id) {
ERR_FAIL_COND(tile_map.has(p_id));
tile_map[p_id] = TileData();
tile_map[p_id].autotile_data = AutotileData();
- _change_notify("");
+ notify_property_list_changed();
emit_changed();
}
void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].autotile_data.bitmask_mode = p_mode;
- _change_notify("");
+ notify_property_list_changed();
emit_changed();
}
@@ -389,7 +389,6 @@ void TileSet::tile_set_texture(int p_id, const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].texture = p_texture;
emit_changed();
- _change_notify("texture");
}
Ref<Texture2D> TileSet::tile_get_texture(int p_id) const {
@@ -412,7 +411,6 @@ void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].modulate = p_modulate;
emit_changed();
- _change_notify("modulate");
}
Color TileSet::tile_get_modulate(int p_id) const {
@@ -435,7 +433,6 @@ void TileSet::tile_set_region(int p_id, const Rect2 &p_region) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].region = p_region;
emit_changed();
- _change_notify("region");
}
Rect2 TileSet::tile_get_region(int p_id) const {
@@ -447,7 +444,6 @@ void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].tile_mode = p_tile_mode;
emit_changed();
- _change_notify("tile_mode");
}
TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const {
@@ -669,7 +665,6 @@ void TileSet::tile_set_name(int p_id, const String &p_name) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].name = p_name;
emit_changed();
- _change_notify("name");
}
String TileSet::tile_get_name(int p_id) const {
@@ -1060,7 +1055,7 @@ bool TileSet::is_tile_bound(int p_drawn_id, int p_neighbor_id) {
void TileSet::remove_tile(int p_id) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map.erase(p_id);
- _change_notify("");
+ notify_property_list_changed();
emit_changed();
}
@@ -1081,9 +1076,13 @@ int TileSet::find_tile_by_name(const String &p_name) const {
return -1;
}
+void TileSet::reset_state() {
+ clear();
+}
+
void TileSet::clear() {
tile_map.clear();
- _change_notify("");
+ notify_property_list_changed();
emit_changed();
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 210520350f..0a8721f35b 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -136,6 +136,8 @@ protected:
static void _bind_methods();
+ virtual void reset_state() override;
+
public:
void create_tile(int p_id);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 72724d5ee1..b810f9562e 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -300,6 +300,30 @@ String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, Vis
return "";
}
+void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value) {
+ if (!is_initialized) {
+ VisualShaderNode::set_input_port_default_value(p_port, p_value);
+ }
+}
+
+void VisualShaderNodeCustom::set_default_input_values(const Array &p_values) {
+ if (!is_initialized) {
+ VisualShaderNode::set_default_input_values(p_values);
+ }
+}
+
+void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Variant &p_value) {
+ VisualShaderNode::set_input_port_default_value(p_port, p_value);
+}
+
+bool VisualShaderNodeCustom::_is_initialized() {
+ return is_initialized;
+}
+
+void VisualShaderNodeCustom::_set_initialized(bool p_enabled) {
+ is_initialized = p_enabled;
+}
+
void VisualShaderNodeCustom::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description"));
@@ -314,6 +338,12 @@ void VisualShaderNodeCustom::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_highend"));
+
+ ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized);
+ ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized);
+ ClassDB::bind_method(D_METHOD("_set_input_port_default_value", "port", "value"), &VisualShaderNodeCustom::_set_input_port_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_initialized", "_is_initialized");
}
VisualShaderNodeCustom::VisualShaderNodeCustom() {
@@ -585,6 +615,12 @@ bool VisualShader::is_port_types_compatible(int p_a, int p_b) const {
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
ERR_FAIL_INDEX(p_type, TYPE_MAX);
Graph *g = &graph[p_type];
+
+ ERR_FAIL_COND(!g->nodes.has(p_from_node));
+ ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count());
+ ERR_FAIL_COND(!g->nodes.has(p_to_node));
+ ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count());
+
Connection c;
c.from_node = p_from_node;
c.from_port = p_from_port;
@@ -675,6 +711,8 @@ void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connect
}
void VisualShader::set_mode(Mode p_mode) {
+ ERR_FAIL_INDEX_MSG(p_mode, Mode::MODE_MAX, vformat("Invalid shader mode: %d.", p_mode));
+
if (shader_mode == p_mode) {
return;
}
@@ -730,7 +768,7 @@ void VisualShader::set_mode(Mode p_mode) {
}
_queue_update();
- _change_notify();
+ notify_property_list_changed();
}
void VisualShader::set_graph_offset(const Vector2 &p_offset) {
@@ -953,7 +991,8 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
"light",
"emit",
"process",
- "end"
+ "end",
+ "sky",
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
@@ -1095,6 +1134,12 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
+void VisualShader::reset_state() {
+#ifndef _MSC_VER
+#warning everything needs to be cleared here
+#endif
+ emit_changed();
+}
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky"));
@@ -1392,11 +1437,11 @@ bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const Strin
}
void VisualShader::_update_shader() const {
- if (!dirty) {
+ if (!dirty.is_set()) {
return;
}
- dirty = false;
+ dirty.clear();
StringBuilder global_code;
StringBuilder global_code_per_node;
@@ -1462,7 +1507,7 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
- static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end" };
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end", "sky" };
String global_expressions;
Set<String> used_uniform_names;
@@ -1582,15 +1627,16 @@ void VisualShader::_update_shader() const {
}
void VisualShader::_queue_update() {
- if (dirty) {
+ if (dirty.is_set()) {
return;
}
- dirty = true;
+ dirty.set();
call_deferred("_update_shader");
}
void VisualShader::_input_type_changed(Type p_type, int p_id) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
//erase connections using this input, as type changed
Graph *g = &graph[p_type];
@@ -1605,7 +1651,7 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) {
}
void VisualShader::rebuild() {
- dirty = true;
+ dirty.set();
_update_shader();
}
@@ -1652,6 +1698,7 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_EMIT);
BIND_ENUM_CONSTANT(TYPE_PROCESS);
BIND_ENUM_CONSTANT(TYPE_END);
+ BIND_ENUM_CONSTANT(TYPE_SKY);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_CONSTANT(NODE_ID_INVALID);
@@ -1659,6 +1706,7 @@ void VisualShader::_bind_methods() {
}
VisualShader::VisualShader() {
+ dirty.set();
for (int i = 0; i < TYPE_MAX; i++) {
Ref<VisualShaderNodeOutput> output;
output.instance();
@@ -1682,7 +1730,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "modelview", "MODELVIEW_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1705,10 +1752,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD, 0.0)" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "float(FRONT_FACING ? 1.0 : 0.0)" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1734,7 +1779,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1743,6 +1787,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
+
// Canvas Item, Vertex
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1750,12 +1795,12 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" },
-
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "canvas", "CANVAS_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen", "SCREEN_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
+
// Canvas Item, Fragment
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1773,6 +1818,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
+
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1840,36 +1886,36 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- // Sky, Fragment
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "eyedir", "EYEDIR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "half_res_color", "HALF_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light0_color", "LIGHT0_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light0_direction", "LIGHT0_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light1_color", "LIGHT1_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light1_direction", "LIGHT1_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light2_color", "LIGHT2_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light2_direction", "LIGHT2_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light3_color", "LIGHT3_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light3_direction", "LIGHT3_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "position", "POSITION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "quarter_res_color", "QUARTER_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Sky, Sky
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "eyedir", "EYEDIR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "half_res_color", "HALF_RES_COLOR.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_color", "LIGHT0_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_direction", "LIGHT0_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_color", "LIGHT1_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_direction", "LIGHT1_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_color", "LIGHT2_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_direction", "LIGHT2_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_color", "LIGHT3_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_direction", "LIGHT3_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "position", "POSITION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "quarter_res_color", "QUARTER_RES_COLOR.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@@ -2433,9 +2479,9 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- // Sky, Fragment
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
+ // Sky, Sky
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@@ -2651,6 +2697,70 @@ VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() {
set_allow_v_resize(true);
}
+////////////// Comment
+
+String VisualShaderNodeComment::get_caption() const {
+ return title;
+}
+
+int VisualShaderNodeComment::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeComment::PortType VisualShaderNodeComment::get_input_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeComment::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeComment::get_output_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeComment::PortType VisualShaderNodeComment::get_output_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeComment::get_output_port_name(int p_port) const {
+ return String();
+}
+
+void VisualShaderNodeComment::set_title(const String &p_title) {
+ title = p_title;
+}
+
+String VisualShaderNodeComment::get_title() const {
+ return title;
+}
+
+void VisualShaderNodeComment::set_description(const String &p_description) {
+ description = p_description;
+}
+
+String VisualShaderNodeComment::get_description() const {
+ return description;
+}
+
+String VisualShaderNodeComment::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return String();
+}
+
+void VisualShaderNodeComment::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualShaderNodeComment::set_title);
+ ClassDB::bind_method(D_METHOD("get_title"), &VisualShaderNodeComment::get_title);
+
+ ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualShaderNodeComment::set_description);
+ ClassDB::bind_method(D_METHOD("get_description"), &VisualShaderNodeComment::get_description);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_description", "get_description");
+}
+
+VisualShaderNodeComment::VisualShaderNodeComment() {
+}
+
////////////// GroupBase
void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 9396a53e8b..8af0fc9e44 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -32,6 +32,7 @@
#define VISUAL_SHADER_H
#include "core/string/string_builder.h"
+#include "core/templates/safe_refcount.h"
#include "scene/gui/control.h"
#include "scene/resources/shader.h"
@@ -53,14 +54,15 @@ public:
TYPE_EMIT,
TYPE_PROCESS,
TYPE_END,
+ TYPE_SKY,
TYPE_MAX
};
struct Connection {
- int from_node;
- int from_port;
- int to_node;
- int to_port;
+ int from_node = 0;
+ int from_port = 0;
+ int to_node = 0;
+ int to_port = 0;
};
struct DefaultTextureParam {
@@ -90,7 +92,7 @@ private:
Vector2 graph_offset;
struct RenderModeEnums {
- Shader::Mode mode;
+ Shader::Mode mode = Shader::Mode::MODE_MAX;
const char *string;
};
@@ -99,7 +101,7 @@ private:
static RenderModeEnums render_mode_enums[];
- volatile mutable bool dirty = true;
+ mutable SafeFlag dirty;
void _queue_update();
union ConnectionKey {
@@ -107,7 +109,7 @@ private:
uint64_t node : 32;
uint64_t port : 32;
};
- uint64_t key;
+ uint64_t key = 0;
bool operator<(const ConnectionKey &p_key) const {
return key < p_key.key;
}
@@ -126,6 +128,8 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void reset_state() override;
+
public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;
@@ -219,10 +223,10 @@ public:
virtual PortType get_input_port_type(int p_port) const = 0;
virtual String get_input_port_name(int p_port) const = 0;
- void set_input_port_default_value(int p_port, const Variant &p_value);
+ virtual void set_input_port_default_value(int p_port, const Variant &p_value);
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)
Array get_default_input_values() const;
- void set_default_input_values(const Array &p_values);
+ virtual void set_default_input_values(const Array &p_values);
virtual int get_output_port_count() const = 0;
virtual PortType get_output_port_type(int p_port) const = 0;
@@ -265,9 +269,10 @@ class VisualShaderNodeCustom : public VisualShaderNode {
struct Port {
String name;
- int type;
+ int type = 0;
};
+ bool is_initialized = false;
List<Port> input_ports;
List<Port> output_ports;
@@ -284,7 +289,12 @@ protected:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual void set_input_port_default_value(int p_port, const Variant &p_value) override;
+ virtual void set_default_input_values(const Array &p_values) override;
+
protected:
+ void _set_input_port_default_value(int p_port, const Variant &p_value);
+
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;
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
@@ -293,6 +303,9 @@ protected:
public:
VisualShaderNodeCustom();
void update_ports();
+
+ bool _is_initialized();
+ void _set_initialized(bool p_enabled);
};
/////
@@ -305,9 +318,9 @@ class VisualShaderNodeInput : public VisualShaderNode {
Shader::Mode shader_mode = Shader::MODE_MAX;
struct Port {
- Shader::Mode mode;
- VisualShader::Type shader_type;
- PortType type;
+ Shader::Mode mode = Shader::Mode::MODE_MAX;
+ VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX;
+ PortType type = PortType::PORT_TYPE_MAX;
const char *name;
const char *string;
};
@@ -356,13 +369,13 @@ class VisualShaderNodeOutput : public VisualShaderNode {
public:
friend class VisualShader;
- VisualShader::Type shader_type;
- Shader::Mode shader_mode;
+ VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX;
+ Shader::Mode shader_mode = Shader::Mode::MODE_MAX;
struct Port {
- Shader::Mode mode;
- VisualShader::Type shader_type;
- PortType type;
+ Shader::Mode mode = Shader::Mode::MODE_MAX;
+ VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX;
+ PortType type = PortType::PORT_TYPE_MAX;
const char *name;
const char *string;
};
@@ -418,6 +431,7 @@ public:
bool is_global_code_generated() const;
virtual bool is_qualifier_supported(Qualifier p_qual) const = 0;
+ virtual bool is_convertible_to_constant() const = 0;
virtual Vector<StringName> get_editable_properties() const override;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
@@ -507,6 +521,38 @@ public:
VisualShaderNodeResizableBase();
};
+class VisualShaderNodeComment : public VisualShaderNodeResizableBase {
+ GDCLASS(VisualShaderNodeComment, VisualShaderNodeResizableBase);
+
+protected:
+ String title = "Comment";
+ String description = "";
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_title(const String &p_title);
+ String get_title() const;
+
+ void set_description(const String &p_description);
+ String get_description() const;
+
+ VisualShaderNodeComment();
+};
+
class VisualShaderNodeGroupBase : public VisualShaderNodeResizableBase {
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNodeResizableBase);
@@ -519,7 +565,7 @@ protected:
bool editable = false;
struct Port {
- PortType type;
+ PortType type = PortType::PORT_TYPE_MAX;
String name;
};
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index d6200059f6..7943b95177 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -2742,8 +2742,6 @@ int VisualShaderNodeClamp::get_input_port_count() const {
VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_FLOAT:
- return PORT_TYPE_SCALAR;
case OP_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
case OP_TYPE_VECTOR:
@@ -2771,8 +2769,6 @@ int VisualShaderNodeClamp::get_output_port_count() const {
VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_FLOAT:
- return PORT_TYPE_SCALAR;
case OP_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
case OP_TYPE_VECTOR:
@@ -2954,18 +2950,11 @@ int VisualShaderNodeStep::get_input_port_count() const {
VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
- switch (p_port) {
- case 0:
- return PORT_TYPE_SCALAR;
- case 1:
- return PORT_TYPE_VECTOR;
- default:
- break;
+ if (p_port == 1) {
+ return PORT_TYPE_VECTOR;
}
break;
default:
@@ -2989,8 +2978,6 @@ int VisualShaderNodeStep::get_output_port_count() const {
VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
@@ -3032,7 +3019,7 @@ void VisualShaderNodeStep::set_op_type(OpType p_op_type) {
set_input_port_default_value(0, 0.0); // edge
}
if (op_type == OP_TYPE_SCALAR) {
- set_input_port_default_value(1, 0.0); // x
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x
}
break;
default:
@@ -3085,20 +3072,11 @@ int VisualShaderNodeSmoothStep::get_input_port_count() const {
VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
- switch (p_port) {
- case 0:
- return PORT_TYPE_SCALAR; // edge0
- case 1:
- return PORT_TYPE_SCALAR; // edge1
- case 2:
- return PORT_TYPE_VECTOR; // x
- default:
- break;
+ if (p_port == 2) {
+ return PORT_TYPE_VECTOR; // x
}
break;
default:
@@ -3124,8 +3102,6 @@ int VisualShaderNodeSmoothStep::get_output_port_count() const {
VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
@@ -3319,16 +3295,11 @@ int VisualShaderNodeMix::get_input_port_count() const {
VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
- if (p_port == 2) {
- return PORT_TYPE_VECTOR;
- }
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
if (p_port == 2) {
- return PORT_TYPE_SCALAR;
+ break;
}
return PORT_TYPE_VECTOR;
default:
@@ -3353,8 +3324,6 @@ int VisualShaderNodeMix::get_output_port_count() const {
VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_SCALAR:
- return PORT_TYPE_SCALAR;
case OP_TYPE_VECTOR:
return PORT_TYPE_VECTOR;
case OP_TYPE_VECTOR_SCALAR:
@@ -3775,6 +3744,10 @@ bool VisualShaderNodeFloatUniform::is_qualifier_supported(Qualifier p_qual) cons
return true; // all qualifiers are supported
}
+bool VisualShaderNodeFloatUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("hint");
@@ -3942,6 +3915,10 @@ bool VisualShaderNodeIntUniform::is_qualifier_supported(Qualifier p_qual) const
return true; // all qualifiers are supported
}
+bool VisualShaderNodeIntUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("hint");
@@ -4050,6 +4027,10 @@ bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) co
return true; // all qualifiers are supported
}
+bool VisualShaderNodeBooleanUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4144,6 +4125,10 @@ bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) cons
return true; // all qualifiers are supported
}
+bool VisualShaderNodeColorUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4240,6 +4225,10 @@ bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const
return true; // all qualifiers are supported
}
+bool VisualShaderNodeVec3Uniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4340,6 +4329,10 @@ bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual)
return true; // all qualifiers are supported
}
+bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4525,6 +4518,10 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co
return false;
}
+bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const {
+ return false; // conversion is not allowed
+}
+
VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
simple_decl = false;
}
@@ -4540,9 +4537,7 @@ int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {
}
VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
- if (p_port == 0) {
- return PORT_TYPE_VECTOR;
- } else if (p_port == 1) {
+ if (p_port == 0 || p_port == 1) {
return PORT_TYPE_VECTOR;
}
return PORT_TYPE_SCALAR;
@@ -4665,16 +4660,18 @@ String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mod
switch (texture_type) {
case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black;\n";
- else
+ } else {
code += ";\n";
+ }
break;
case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black_albedo;\n";
- else
+ } else {
code += " : hint_albedo;\n";
+ }
break;
case TYPE_NORMAL_MAP:
code += " : hint_normal;\n";
@@ -4733,16 +4730,18 @@ String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, Vi
switch (texture_type) {
case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black;\n";
- else
+ } else {
code += ";\n";
+ }
break;
case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black_albedo;\n";
- else
+ } else {
code += " : hint_albedo;\n";
+ }
break;
case TYPE_NORMAL_MAP:
code += " : hint_normal;\n";
@@ -4923,8 +4922,6 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int
}
if (p_port == 1 || p_port == 2) {
switch (op_type) {
- case OP_TYPE_FLOAT:
- return PORT_TYPE_SCALAR;
case OP_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
case OP_TYPE_VECTOR:
@@ -4959,8 +4956,6 @@ int VisualShaderNodeSwitch::get_output_port_count() const {
VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const {
switch (op_type) {
- case OP_TYPE_FLOAT:
- return PORT_TYPE_SCALAR;
case OP_TYPE_INT:
return PORT_TYPE_SCALAR_INT;
case OP_TYPE_VECTOR:
@@ -5238,9 +5233,6 @@ int VisualShaderNodeCompare::get_input_port_count() const {
}
VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(int p_port) const {
- if (p_port == 2) {
- return PORT_TYPE_SCALAR;
- }
switch (ctype) {
case CTYPE_SCALAR:
return PORT_TYPE_SCALAR;
@@ -5252,8 +5244,9 @@ VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(i
return PORT_TYPE_BOOLEAN;
case CTYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
+ default:
+ return PORT_TYPE_SCALAR;
}
- return PORT_TYPE_VECTOR;
}
String VisualShaderNodeCompare::get_input_port_name(int p_port) const {
@@ -5472,10 +5465,10 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const {
}
VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const {
- if (op_type == OP_TYPE_SCALAR) {
- return PORT_TYPE_SCALAR;
+ if (op_type == OP_TYPE_VECTOR) {
+ return PORT_TYPE_VECTOR;
}
- return PORT_TYPE_VECTOR;
+ return PORT_TYPE_SCALAR;
}
String VisualShaderNodeMultiplyAdd::get_input_port_name(int p_port) const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index a5d0fe4649..594a494cf1 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1574,6 +1574,7 @@ public:
float get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1639,6 +1640,7 @@ public:
int get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1683,6 +1685,7 @@ public:
bool get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1724,6 +1727,7 @@ public:
Color get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1766,6 +1770,7 @@ public:
Vector3 get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1808,6 +1813,7 @@ public:
Transform get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1865,6 +1871,7 @@ public:
ColorDefault get_color_default() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
VisualShaderNodeTextureUniform();
};
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index cadbd93fed..ccdc5bebd0 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -34,12 +34,13 @@
#include "scene/2d/camera_2d.h"
#include "scene/2d/visibility_notifier_2d.h"
#include "scene/main/window.h"
+#include "servers/navigation_server_2d.h"
#include "servers/physics_server_2d.h"
#include "servers/rendering_server.h"
struct SpatialIndexer2D {
struct CellRef {
- int ref;
+ int ref = 0;
_FORCE_INLINE_ int inc() {
ref++;
@@ -49,10 +50,6 @@ struct SpatialIndexer2D {
ref--;
return ref;
}
-
- _FORCE_INLINE_ CellRef() {
- ref = 0;
- }
};
struct CellKey {
@@ -61,7 +58,7 @@ struct SpatialIndexer2D {
int32_t x;
int32_t y;
};
- uint64_t key;
+ uint64_t key = 0;
};
bool operator==(const CellKey &p_key) const { return key == p_key.key; }
@@ -86,9 +83,9 @@ struct SpatialIndexer2D {
Map<Viewport *, ViewportData> viewports;
- bool changed;
+ bool changed = false;
- uint64_t pass;
+ uint64_t pass = 0;
void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) {
Point2i begin = p_rect.position;
@@ -287,8 +284,6 @@ struct SpatialIndexer2D {
}
SpatialIndexer2D() {
- pass = 0;
- changed = false;
cell_size = GLOBAL_DEF("world/2d/cell_size", 100);
}
};
@@ -321,14 +316,18 @@ void World2D::_update() {
indexer->_update();
}
-RID World2D::get_canvas() {
+RID World2D::get_canvas() const {
return canvas;
}
-RID World2D::get_space() {
+RID World2D::get_space() const {
return space;
}
+RID World2D::get_navigation_map() const {
+ return navigation_map;
+}
+
void World2D::get_viewport_list(List<Viewport *> *r_viewports) {
for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) {
r_viewports->push_back(E->key());
@@ -338,11 +337,13 @@ void World2D::get_viewport_list(List<Viewport *> *r_viewports) {
void World2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas);
ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &World2D::get_navigation_map);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World2D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state");
}
@@ -352,9 +353,9 @@ PhysicsDirectSpaceState2D *World2D::get_direct_space_state() {
World2D::World2D() {
canvas = RenderingServer::get_singleton()->canvas_create();
- space = PhysicsServer2D::get_singleton()->space_create();
- //set space2D to be more friendly with pixels than meters, by adjusting some constants
+ // Create and configure space2D to be more friendly with pixels than meters
+ space = PhysicsServer2D::get_singleton()->space_create();
PhysicsServer2D::get_singleton()->space_set_active(space, true);
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 98));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1)));
@@ -362,11 +363,19 @@ World2D::World2D() {
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_angular_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
+
+ // Create and configure the navigation_map to be more friendly with pixels than meters.
+ navigation_map = NavigationServer2D::get_singleton()->map_create();
+ NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
+ NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10));
+ NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5));
+
indexer = memnew(SpatialIndexer2D);
}
World2D::~World2D() {
RenderingServer::get_singleton()->free(canvas);
PhysicsServer2D::get_singleton()->free(space);
+ NavigationServer2D::get_singleton()->free(navigation_map);
memdelete(indexer);
}
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index ae13367421..38abf3d7ad 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -44,6 +44,7 @@ class World2D : public Resource {
RID canvas;
RID space;
+ RID navigation_map;
SpatialIndexer2D *indexer;
@@ -63,8 +64,9 @@ protected:
void _update();
public:
- RID get_canvas();
- RID get_space();
+ RID get_canvas() const;
+ RID get_space() const;
+ RID get_navigation_map() const;
PhysicsDirectSpaceState2D *get_direct_space_state();
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 9c0317454b..e811cbf57a 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -35,6 +35,7 @@
#include "scene/3d/camera_3d.h"
#include "scene/3d/visibility_notifier_3d.h"
#include "scene/scene_string_names.h"
+#include "servers/navigation_server_3d.h"
struct SpatialIndexer {
Octree<VisibilityNotifier3D> octree;
@@ -243,6 +244,10 @@ RID World3D::get_space() const {
return space;
}
+RID World3D::get_navigation_map() const {
+ return navigation_map;
+}
+
RID World3D::get_scenario() const {
return scenario;
}
@@ -310,18 +315,20 @@ void World3D::get_camera_list(List<Camera3D *> *r_cameras) {
void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space);
+ ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map);
ClassDB::bind_method(D_METHOD("get_scenario"), &World3D::get_scenario);
ClassDB::bind_method(D_METHOD("set_environment", "env"), &World3D::set_environment);
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
- ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &World3D::set_camera_effects);
+ ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects);
ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects");
ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space");
+ ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map");
ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", 0), "", "get_direct_space_state");
}
@@ -338,6 +345,11 @@ World3D::World3D() {
PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_angular_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
+ navigation_map = NavigationServer3D::get_singleton()->map_create();
+ NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
+ NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
+
#ifdef _3D_DISABLED
indexer = nullptr;
#else
@@ -348,6 +360,7 @@ World3D::World3D() {
World3D::~World3D() {
PhysicsServer3D::get_singleton()->free(space);
RenderingServer::get_singleton()->free(scenario);
+ NavigationServer3D::get_singleton()->free(navigation_map);
#ifndef _3D_DISABLED
memdelete(indexer);
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index 3d6c33997e..4e2717a2bb 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -46,6 +46,7 @@ class World3D : public Resource {
private:
RID space;
+ RID navigation_map;
RID scenario;
SpatialIndexer *indexer;
Ref<Environment> environment;
@@ -70,6 +71,7 @@ protected:
public:
RID get_space() const;
+ RID get_navigation_map() const;
RID get_scenario() const;
void set_environment(const Ref<Environment> &p_environment);
diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp
index 79cbb3bbe0..28d50e1921 100644
--- a/scene/resources/world_margin_shape_3d.cpp
+++ b/scene/resources/world_margin_shape_3d.cpp
@@ -69,7 +69,6 @@ void WorldMarginShape3D::set_plane(Plane p_plane) {
plane = p_plane;
_update_shape();
notify_change_to_owners();
- _change_notify("plane");
}
Plane WorldMarginShape3D::get_plane() const {
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 892802c103..7575ccd5c3 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -190,10 +190,6 @@ SceneStringNames::SceneStringNames() {
_default = StaticCString::create("default");
- for (int i = 0; i < MAX_MATERIALS; i++) {
- mesh_materials[i] = "material/" + itos(i);
- }
-
_window_group = StaticCString::create("_window_group");
_window_input = StaticCString::create("_window_input");
window_input = StaticCString::create("window_input");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 655e49c6f9..a5b489eddc 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -216,10 +216,6 @@ public:
StringName use_in_baked_light;
StringName use_dynamic_gi;
#endif
- enum {
- MAX_MATERIALS = 32
- };
- StringName mesh_materials[MAX_MATERIALS];
};
#endif // SCENE_STRING_NAMES_H
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp
index faddced155..a28dcb1015 100644
--- a/servers/audio/audio_driver_dummy.cpp
+++ b/servers/audio/audio_driver_dummy.cpp
@@ -39,11 +39,11 @@ Error AudioDriverDummy::init() {
exit_thread = false;
samples_in = nullptr;
- mix_rate = GLOBAL_GET("audio/mix_rate");
+ mix_rate = GLOBAL_GET("audio/driver/mix_rate");
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_GET("audio/output_latency");
+ int latency = GLOBAL_GET("audio/driver/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_frames * channels);
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
index efdcb916ed..3c8a1469cd 100644
--- a/servers/audio/audio_rb_resampler.cpp
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -131,7 +131,7 @@ bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) {
src_read = read_space;
}
- rb_read_pos = (rb_read_pos + src_read) & rb_mask;
+ rb_read_pos.set((rb_read_pos.get() + src_read) & rb_mask);
// Create fadeout effect for the end of stream (note that it can be because of slow writer)
if (p_frames - target_todo > 0) {
@@ -183,8 +183,8 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m
src_mix_rate = p_src_mix_rate;
target_mix_rate = p_target_mix_rate;
offset = 0;
- rb_read_pos = 0;
- rb_write_pos = 0;
+ rb_read_pos.set(0);
+ rb_write_pos.set(0);
//avoid maybe strange noises upon load
for (unsigned int i = 0; i < (rb_len * channels); i++) {
@@ -205,8 +205,8 @@ void AudioRBResampler::clear() {
memdelete_arr(read_buf);
rb = nullptr;
offset = 0;
- rb_read_pos = 0;
- rb_write_pos = 0;
+ rb_read_pos.set(0);
+ rb_write_pos.set(0);
read_buf = nullptr;
}
@@ -214,8 +214,8 @@ AudioRBResampler::AudioRBResampler() {
rb = nullptr;
offset = 0;
read_buf = nullptr;
- rb_read_pos = 0;
- rb_write_pos = 0;
+ rb_read_pos.set(0);
+ rb_write_pos.set(0);
rb_bits = 0;
rb_len = 0;
diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h
index 7b74e3a2a1..c0f981704b 100644
--- a/servers/audio/audio_rb_resampler.h
+++ b/servers/audio/audio_rb_resampler.h
@@ -32,6 +32,7 @@
#define AUDIO_RB_RESAMPLER_H
#include "core/os/memory.h"
+#include "core/templates/safe_refcount.h"
#include "core/typedefs.h"
#include "servers/audio_server.h"
@@ -44,8 +45,8 @@ struct AudioRBResampler {
uint32_t src_mix_rate;
uint32_t target_mix_rate;
- volatile int rb_read_pos;
- volatile int rb_write_pos;
+ SafeNumeric<int> rb_read_pos;
+ SafeNumeric<int> rb_write_pos;
int32_t offset; //contains the fractional remainder of the resampler
enum {
@@ -62,8 +63,8 @@ struct AudioRBResampler {
public:
_FORCE_INLINE_ void flush() {
- rb_read_pos = 0;
- rb_write_pos = 0;
+ rb_read_pos.set(0);
+ rb_write_pos.set(0);
offset = 0;
}
@@ -78,8 +79,8 @@ public:
_FORCE_INLINE_ int get_writer_space() const {
int space, r, w;
- r = rb_read_pos;
- w = rb_write_pos;
+ r = rb_read_pos.get();
+ w = rb_write_pos.get();
if (r == w) {
space = rb_len - 1;
@@ -95,8 +96,8 @@ public:
_FORCE_INLINE_ int get_reader_space() const {
int space, r, w;
- r = rb_read_pos;
- w = rb_write_pos;
+ r = rb_read_pos.get();
+ w = rb_write_pos.get();
if (r == w) {
space = 0;
@@ -110,48 +111,52 @@ public:
}
_FORCE_INLINE_ bool has_data() const {
- return rb && rb_read_pos != rb_write_pos;
+ return rb && rb_read_pos.get() != rb_write_pos.get();
}
_FORCE_INLINE_ float *get_write_buffer() { return read_buf; }
_FORCE_INLINE_ void write(uint32_t p_frames) {
ERR_FAIL_COND(p_frames >= rb_len);
+ int wp = rb_write_pos.get();
+
switch (channels) {
case 1: {
for (uint32_t i = 0; i < p_frames; i++) {
- rb[rb_write_pos] = read_buf[i];
- rb_write_pos = (rb_write_pos + 1) & rb_mask;
+ rb[wp] = read_buf[i];
+ wp = (wp + 1) & rb_mask;
}
} break;
case 2: {
for (uint32_t i = 0; i < p_frames; i++) {
- rb[(rb_write_pos << 1) + 0] = read_buf[(i << 1) + 0];
- rb[(rb_write_pos << 1) + 1] = read_buf[(i << 1) + 1];
- rb_write_pos = (rb_write_pos + 1) & rb_mask;
+ rb[(wp << 1) + 0] = read_buf[(i << 1) + 0];
+ rb[(wp << 1) + 1] = read_buf[(i << 1) + 1];
+ wp = (wp + 1) & rb_mask;
}
} break;
case 4: {
for (uint32_t i = 0; i < p_frames; i++) {
- rb[(rb_write_pos << 2) + 0] = read_buf[(i << 2) + 0];
- rb[(rb_write_pos << 2) + 1] = read_buf[(i << 2) + 1];
- rb[(rb_write_pos << 2) + 2] = read_buf[(i << 2) + 2];
- rb[(rb_write_pos << 2) + 3] = read_buf[(i << 2) + 3];
- rb_write_pos = (rb_write_pos + 1) & rb_mask;
+ rb[(wp << 2) + 0] = read_buf[(i << 2) + 0];
+ rb[(wp << 2) + 1] = read_buf[(i << 2) + 1];
+ rb[(wp << 2) + 2] = read_buf[(i << 2) + 2];
+ rb[(wp << 2) + 3] = read_buf[(i << 2) + 3];
+ wp = (wp + 1) & rb_mask;
}
} break;
case 6: {
for (uint32_t i = 0; i < p_frames; i++) {
- rb[(rb_write_pos * 6) + 0] = read_buf[(i * 6) + 0];
- rb[(rb_write_pos * 6) + 1] = read_buf[(i * 6) + 1];
- rb[(rb_write_pos * 6) + 2] = read_buf[(i * 6) + 2];
- rb[(rb_write_pos * 6) + 3] = read_buf[(i * 6) + 3];
- rb[(rb_write_pos * 6) + 4] = read_buf[(i * 6) + 4];
- rb[(rb_write_pos * 6) + 5] = read_buf[(i * 6) + 5];
- rb_write_pos = (rb_write_pos + 1) & rb_mask;
+ rb[(wp * 6) + 0] = read_buf[(i * 6) + 0];
+ rb[(wp * 6) + 1] = read_buf[(i * 6) + 1];
+ rb[(wp * 6) + 2] = read_buf[(i * 6) + 2];
+ rb[(wp * 6) + 3] = read_buf[(i * 6) + 3];
+ rb[(wp * 6) + 4] = read_buf[(i * 6) + 4];
+ rb[(wp * 6) + 5] = read_buf[(i * 6) + 5];
+ wp = (wp + 1) & rb_mask;
}
} break;
}
+
+ rb_write_pos.set(wp);
}
int get_channel_count() const;
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 91fce5d34e..ae07f999ed 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -54,21 +54,21 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale,
for (int i = 0; i < p_frames; i++) {
uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS);
- //standard cubic interpolation (great quality/performance ratio)
- //this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory.
+ // 4 point, 4th order optimal resampling algorithm from: http://yehar.com/blog/wp-content/uploads/2009/08/deip.pdf
float mu = (mix_offset & FP_MASK) / float(FP_LEN);
AudioFrame y0 = internal_buffer[idx - 3];
AudioFrame y1 = internal_buffer[idx - 2];
AudioFrame y2 = internal_buffer[idx - 1];
AudioFrame y3 = internal_buffer[idx - 0];
- float mu2 = mu * mu;
- AudioFrame a0 = y3 - y2 - y0 + y1;
- AudioFrame a1 = y0 - y1 - a0;
- AudioFrame a2 = y2 - y0;
- AudioFrame a3 = y1;
-
- p_buffer[i] = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3);
+ AudioFrame even1 = y2 + y1, odd1 = y2 - y1;
+ AudioFrame even2 = y3 + y0, odd2 = y3 - y0;
+ AudioFrame c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309;
+ AudioFrame c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288;
+ AudioFrame c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131;
+ AudioFrame c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800;
+ AudioFrame c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478;
+ p_buffer[i] = (((c4 * mu + c3) * mu + c2) * mu + c1) * mu + c0;
mix_offset += mix_increment;
@@ -184,7 +184,7 @@ void AudioStreamPlaybackMicrophone::start(float p_from_pos) {
return;
}
- if (!GLOBAL_GET("audio/enable_audio_input")) {
+ if (!GLOBAL_GET("audio/driver/enable_input")) {
WARN_PRINT("Need to enable Project settings > Audio > Enable Audio Input option to use capturing.");
return;
}
diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp
index f37938eec8..78837c7531 100644
--- a/servers/audio/effects/audio_effect_capture.cpp
+++ b/servers/audio/effects/audio_effect_capture.cpp
@@ -91,8 +91,6 @@ Ref<AudioEffectInstance> AudioEffectCapture::instance() {
}
void AudioEffectCapture::set_buffer_length(float p_buffer_length_seconds) {
- ERR_FAIL_COND(buffer_initialized);
-
buffer_length_seconds = p_buffer_length_seconds;
}
@@ -106,7 +104,7 @@ int AudioEffectCapture::get_frames_available() const {
}
int64_t AudioEffectCapture::get_discarded_frames() const {
- return discarded_frames;
+ return discarded_frames.get();
}
int AudioEffectCapture::get_buffer_length_frames() const {
@@ -115,7 +113,7 @@ int AudioEffectCapture::get_buffer_length_frames() const {
}
int64_t AudioEffectCapture::get_pushed_frames() const {
- return pushed_frames;
+ return pushed_frames.get();
}
void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
@@ -129,9 +127,9 @@ void AudioEffectCaptureInstance::process(const AudioFrame *p_src_frames, AudioFr
// Add incoming audio frames to the IO ring buffer
int32_t ret = buffer.write(p_src_frames, p_frame_count);
ERR_FAIL_COND_MSG(ret != p_frame_count, "Failed to add data to effect capture ring buffer despite sufficient space.");
- atomic_add(&base->pushed_frames, p_frame_count);
+ base->pushed_frames.add(p_frame_count);
} else {
- atomic_add(&base->discarded_frames, p_frame_count);
+ base->discarded_frames.add(p_frame_count);
}
}
diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h
index b154be85de..81d4ed6b0f 100644
--- a/servers/audio/effects/audio_effect_capture.h
+++ b/servers/audio/effects/audio_effect_capture.h
@@ -55,8 +55,8 @@ class AudioEffectCapture : public AudioEffect {
friend class AudioEffectCaptureInstance;
RingBuffer<AudioFrame> buffer;
- uint64_t discarded_frames = 0;
- uint64_t pushed_frames = 0;
+ SafeNumeric<uint64_t> discarded_frames;
+ SafeNumeric<uint64_t> pushed_frames;
float buffer_length_seconds = 0.1f;
bool buffer_initialized = false;
diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp
index 76a995eb37..eb2268aa2e 100644
--- a/servers/audio/effects/audio_effect_chorus.cpp
+++ b/servers/audio/effects/audio_effect_chorus.cpp
@@ -309,7 +309,7 @@ void AudioEffectChorus::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_dry", "amount"), &AudioEffectChorus::set_dry);
ClassDB::bind_method(D_METHOD("get_dry"), &AudioEffectChorus::get_dry);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "voice_count", PROPERTY_HINT_RANGE, "1,4,1"), "set_voice_count", "get_voice_count");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "voice_count", PROPERTY_HINT_RANGE, "1,4,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_voice_count", "get_voice_count");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dry", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dry", "get_dry");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wet", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_wet", "get_wet");
diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp
index b79434e7c2..06d51776a3 100644
--- a/servers/audio/effects/audio_effect_distortion.cpp
+++ b/servers/audio/effects/audio_effect_distortion.cpp
@@ -58,7 +58,8 @@ void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames, Audi
switch (base->mode) {
case AudioEffectDistortion::MODE_CLIP: {
- a = powf(a, 1.0001 - drive_f);
+ float a_sign = a < 0 ? -1.0f : 1.0f;
+ a = powf(abs(a), 1.0001 - drive_f) * a_sign;
if (a > 1.0) {
a = 1.0;
} else if (a < (-1.0)) {
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 16c6a26595..08c482553b 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -188,10 +188,10 @@ int AudioDriverManager::get_driver_count() {
}
void AudioDriverManager::initialize(int p_driver) {
- GLOBAL_DEF_RST("audio/enable_audio_input", false);
- GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
- GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
- GLOBAL_DEF_RST("audio/output_latency.web", 50); // Safer default output_latency for web.
+ GLOBAL_DEF_RST("audio/driver/enable_input", false);
+ GLOBAL_DEF_RST("audio/driver/mix_rate", DEFAULT_MIX_RATE);
+ GLOBAL_DEF_RST("audio/driver/output_latency", DEFAULT_OUTPUT_LATENCY);
+ GLOBAL_DEF_RST("audio/driver/output_latency.web", 50); // Safer default output_latency for web.
int failed_driver = -1;
@@ -246,6 +246,7 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
init_channels_and_buffers();
}
+ ERR_FAIL_COND_MSG(buses.is_empty() && todo, "AudioServer bus count is less than 1.");
while (todo) {
if (to_mix == 0) {
_mix_step();
@@ -939,9 +940,9 @@ void AudioServer::init_channels_and_buffers() {
}
void AudioServer::init() {
- channel_disable_threshold_db = GLOBAL_DEF_RST("audio/channel_disable_threshold_db", -60.0);
- channel_disable_frames = float(GLOBAL_DEF_RST("audio/channel_disable_time", 2.0)) * get_mix_rate();
- ProjectSettings::get_singleton()->set_custom_property_info("audio/channel_disable_time", PropertyInfo(Variant::FLOAT, "audio/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
+ channel_disable_threshold_db = GLOBAL_DEF_RST("audio/buses/channel_disable_threshold_db", -60.0);
+ channel_disable_frames = float(GLOBAL_DEF_RST("audio/buses/channel_disable_time", 2.0)) * get_mix_rate();
+ ProjectSettings::get_singleton()->set_custom_property_info("audio/buses/channel_disable_time", PropertyInfo(Variant::FLOAT, "audio/buses/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
buffer_size = 1024; //hardcoded for now
init_channels_and_buffers();
@@ -958,7 +959,7 @@ void AudioServer::init() {
set_edited(false); //avoid editors from thinking this was edited
#endif
- GLOBAL_DEF_RST("audio/video_delay_compensation_ms", 0);
+ GLOBAL_DEF_RST("audio/video/video_delay_compensation_ms", 0);
}
void AudioServer::update() {
@@ -1035,7 +1036,7 @@ void AudioServer::update() {
}
void AudioServer::load_default_bus_layout() {
- String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
if (ResourceLoader::exists(layout_path)) {
Ref<AudioBusLayout> default_layout = ResourceLoader::load(layout_path);
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index be812cf62d..eab4c61591 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -184,9 +184,10 @@ CameraFeed::~CameraFeed() {
#endif
}
-void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
+void CameraFeed::set_RGB_img(const Ref<Image> &p_rgb_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_rgb_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -207,9 +208,10 @@ void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
#endif
}
-void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
+void CameraFeed::set_YCbCr_img(const Ref<Image> &p_ycbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_ycbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
@@ -230,9 +232,11 @@ void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
#endif
}
-void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
+void CameraFeed::set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
+ ERR_FAIL_COND(p_y_img.is_null());
+ ERR_FAIL_COND(p_cbcr_img.is_null());
if (active) {
RenderingServer *vs = RenderingServer::get_singleton();
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index fc02af4249..eb4ef155bc 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -100,9 +100,9 @@ public:
virtual ~CameraFeed();
FeedDataType get_datatype() const;
- void set_RGB_img(Ref<Image> p_rgb_img);
- void set_YCbCr_img(Ref<Image> p_ycbcr_img);
- void set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img);
+ void set_RGB_img(const Ref<Image> &p_rgb_img);
+ void set_YCbCr_img(const Ref<Image> &p_ycbcr_img);
+ void set_YCbCr_imgs(const Ref<Image> &p_y_img, const Ref<Image> &p_cbcr_img);
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
void allocate_texture(int p_width, int p_height, Image::Format p_format, RenderingServer::TextureType p_texture_type, FeedDataType p_data_type);
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index b06f32417c..ee4a2e148b 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -99,6 +99,8 @@ Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) {
};
void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) {
+ ERR_FAIL_COND(p_feed.is_null());
+
// add our feed
feeds.push_back(p_feed);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 29c1c9fc60..2fa333cc05 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -477,7 +477,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus);
- ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track"), &DisplayServer::native_video_play);
+ ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track", "screen"), &DisplayServer::native_video_play);
ClassDB::bind_method(D_METHOD("native_video_is_playing"), &DisplayServer::native_video_is_playing);
ClassDB::bind_method(D_METHOD("native_video_stop"), &DisplayServer::native_video_stop);
ClassDB::bind_method(D_METHOD("native_video_pause"), &DisplayServer::native_video_pause);
@@ -504,6 +504,11 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon);
ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon);
+ ClassDB::bind_method(D_METHOD("tablet_get_driver_count"), &DisplayServer::tablet_get_driver_count);
+ ClassDB::bind_method(D_METHOD("tablet_get_driver_name", "idx"), &DisplayServer::tablet_get_driver_name);
+ ClassDB::bind_method(D_METHOD("tablet_get_current_driver"), &DisplayServer::tablet_get_current_driver);
+ ClassDB::bind_method(D_METHOD("tablet_set_current_driver", "name"), &DisplayServer::tablet_set_current_driver);
+
BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU);
BIND_ENUM_CONSTANT(FEATURE_SUBWINDOWS);
BIND_ENUM_CONSTANT(FEATURE_TOUCHSCREEN);
diff --git a/servers/display_server.h b/servers/display_server.h
index fc34a2a228..3aab572120 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -83,7 +83,7 @@ protected:
static DisplayServerCreate server_create_functions[MAX_SERVERS];
static int server_create_count;
- friend class RenderingServerDefault;
+ friend class RendererViewport;
virtual void _set_use_vsync(bool p_enable);
public:
@@ -340,6 +340,11 @@ public:
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
+ virtual int tablet_get_driver_count() const { return 1; };
+ virtual String tablet_get_driver_name(int p_driver) const { return "default"; };
+ virtual String tablet_get_current_driver() const { return "default"; };
+ virtual void tablet_set_current_driver(const String &p_driver){};
+
virtual void process_events() = 0;
virtual void force_process_and_drop_events();
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index df348d2add..9e32bc209b 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -80,6 +80,18 @@ NavigationServer2D *NavigationServer2D::singleton = nullptr;
return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \
}
+#define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \
+ }
+
+#define FORWARD_5_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4)); \
+ }
+
static RID rid_to_rid(const RID d) {
return d;
}
@@ -92,6 +104,10 @@ static int int_to_int(const int d) {
return d;
}
+static uint32_t uint32_to_uint32(const uint32_t d) {
+ return d;
+}
+
static real_t real_to_real(const real_t d) {
return d;
}
@@ -116,7 +132,8 @@ static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
static Transform trf2_to_trf3(const Transform2D &d) {
Vector3 o(v2_to_v3(d.get_origin()));
Basis b;
- b.rotate(Vector3(0, 1, 0), d.get_rotation());
+ b.rotate(Vector3(0, -1, 0), d.get_rotation());
+ b.scale(v2_to_v3(d.get_scale()));
return Transform(b, o);
}
@@ -140,6 +157,10 @@ static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
}
}
+void NavigationServer2D::_emit_map_changed(RID p_map) {
+ emit_signal("map_changed", p_map);
+}
+
void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
@@ -148,14 +169,19 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &NavigationServer2D::map_get_path);
+ ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map);
+ ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer2D::region_set_layers);
+ ClassDB::bind_method(D_METHOD("region_get_layers", "region"), &NavigationServer2D::region_get_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &NavigationServer2D::region_set_navpoly);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
@@ -171,10 +197,14 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer2D::agent_set_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("free", "object"), &NavigationServer2D::free);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
NavigationServer2D::NavigationServer2D() {
singleton = this;
+ ERR_FAIL_COND_MSG(!NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one.");
+ NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed));
}
NavigationServer2D::~NavigationServer2D() {
@@ -193,20 +223,25 @@ real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
void FORWARD_2_C(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
-Vector<Vector2> FORWARD_4_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool);
+Vector<Vector2> FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_0_C(region_create);
void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
-
+void FORWARD_2_C(region_set_layers, RID, p_region, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
+uint32_t FORWARD_1_C(region_get_layers, RID, p_region, rid_to_rid);
void FORWARD_2_C(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
void NavigationServer2D::region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const {
NavigationServer3D::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh));
}
+int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+
RID NavigationServer2D::agent_create() const {
RID agent = NavigationServer3D::get_singleton()->agent_create();
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 7be5a74cb3..d56c719839 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -45,12 +45,14 @@ class NavigationServer2D : public Object {
static NavigationServer2D *singleton;
+ void _emit_map_changed(RID p_map);
+
protected:
static void _bind_methods();
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer2D *get_singleton() { return singleton; }
+ static NavigationServer2D *get_singleton() { return singleton; }
/// MUST be used in single thread!
static NavigationServer2D *get_singleton_mut() { return singleton; }
@@ -77,7 +79,7 @@ public:
virtual real_t map_get_edge_connection_margin(RID p_map) const;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize) const;
+ virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
@@ -88,12 +90,21 @@ public:
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
+ /// Set the region's layers
+ virtual void region_set_layers(RID p_region, uint32_t p_layers) const;
+ virtual uint32_t region_get_layers(RID p_region) const;
+
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform2D p_transform) const;
/// Set the navigation poly of this region.
virtual void region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const;
+ virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
+ virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+
/// Creates the agent.
virtual RID agent_create() const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 0e5ae82b0d..b0047a250a 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -46,7 +46,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer3D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer3D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer3D::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &NavigationServer3D::map_get_path);
+ ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "layers"), &NavigationServer3D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point_to_segment", "map", "start", "end", "use_collision"), &NavigationServer3D::map_get_closest_point_to_segment, DEFVAL(false));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer3D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer3D::map_get_closest_point_normal);
@@ -54,9 +54,14 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map);
+ ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer3D::region_set_layers);
+ ClassDB::bind_method(D_METHOD("region_get_layers", "region"), &NavigationServer3D::region_get_layers);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer3D::region_set_navmesh);
ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer3D::region_bake_navmesh);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
@@ -75,9 +80,11 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer3D::set_active);
ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
}
-const NavigationServer3D *NavigationServer3D::get_singleton() {
+NavigationServer3D *NavigationServer3D::get_singleton() {
return singleton;
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 3761c3871a..420f9c9c18 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -55,7 +55,7 @@ protected:
public:
/// Thread safe, can be used across many threads.
- static const NavigationServer3D *get_singleton();
+ static NavigationServer3D *get_singleton();
/// MUST be used in single thread!
static NavigationServer3D *get_singleton_mut();
@@ -88,7 +88,7 @@ public:
virtual real_t map_get_edge_connection_margin(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize) const = 0;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigable_layers = 1) const = 0;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const = 0;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const = 0;
@@ -101,15 +101,24 @@ public:
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
+ /// Set the region's layers
+ virtual void region_set_layers(RID p_region, uint32_t p_layers) const = 0;
+ virtual uint32_t region_get_layers(RID p_region) const = 0;
+
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform p_transform) const = 0;
/// Set the navigation mesh of this region.
virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0;
- /// Bake the navigation mesh
+ /// Bake the navigation mesh.
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
+ /// Get a list of a region's connection to other regions.
+ virtual int region_get_connections_count(RID p_region) const = 0;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
+
/// Creates the agent.
virtual RID agent_create() const = 0;
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 6485c8d1e9..532cb259b3 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -215,7 +215,9 @@ void Area2DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_bodies.erase(E);
+ E = next;
continue;
}
@@ -250,7 +252,9 @@ void Area2DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_areas.erase(E);
+ E = next;
continue;
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index d0636047b7..9306fea70c 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -591,16 +591,17 @@ void Body2DSW::call_queries() {
Variant v = dbs;
const Variant *vp[2] = { &v, &fi_callback->callback_udata };
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
Callable::CallError ce;
+ Variant rv;
if (fi_callback->callback_udata.get_type() != Variant::NIL) {
- obj->call(fi_callback->method, vp, 2, ce);
+ fi_callback->callable.call(vp, 2, rv, ce);
} else {
- obj->call(fi_callback->method, vp, 1, ce);
+ fi_callback->callable.call(vp, 1, rv, ce);
}
}
}
@@ -625,16 +626,15 @@ bool Body2DSW::sleep_test(real_t p_step) {
}
}
-void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->callback_udata = p_udata;
}
}
@@ -658,8 +658,6 @@ Body2DSW::Body2DSW() :
omit_force_integration = false;
applied_torque = 0;
island_step = 0;
- island_next = nullptr;
- island_list_next = nullptr;
_set_static(false);
first_time_kinematic = false;
linear_damp = -1;
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 60d55ab8bd..b4a95651cb 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -117,23 +117,20 @@ class Body2DSW : public CollisionObject2DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant callback_udata;
};
ForceIntegrationCallback *fi_callback;
uint64_t island_step;
- Body2DSW *island_next;
- Body2DSW *island_list_next;
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
_FORCE_INLINE_ void add_area(Area2DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
@@ -175,12 +172,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Body2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Body2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); }
_FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); }
const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; }
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index feced36a2b..da70ac7d4b 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -221,11 +221,21 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) {
bool BodyPair2DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
+ bool report_contacts_only = false;
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -350,51 +360,44 @@ bool BodyPair2DSW::setup(real_t p_step) {
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
+ c.active = false;
+
Vector2 global_A = xform_Au.xform(c.local_A);
Vector2 global_B = xform_Bu.xform(c.local_B);
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0 || !c.reused) {
- c.active = false;
continue;
}
- c.active = true;
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
#endif
- int gather_A = A->can_report_contacts();
- int gather_B = B->can_report_contacts();
c.rA = global_A;
c.rB = global_B - offset_B;
- if (gather_A | gather_B) {
- //Vector2 crB( -B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x );
-
- global_A += offset_A;
- global_B += offset_A;
+ if (A->can_report_contacts()) {
+ Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
+ A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
+ }
- if (gather_A) {
- Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x);
- A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity());
- }
- if (gather_B) {
- Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
- B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
- }
+ if (B->can_report_contacts()) {
+ Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
+ B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity());
}
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
- c.active = false;
+ if (report_contacts_only) {
collided = false;
continue;
}
+ c.active = true;
+
// Precompute normal mass, tangent mass, and bias.
real_t rnA = c.rA.dot(c.normal);
real_t rnB = c.rB.dot(c.normal);
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 6cfe6908d1..35447c5389 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -35,6 +35,12 @@
#define LARGE_ELEMENT_FI 1.01239812
void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
+ if (p_elem->owner == p_with->owner) {
+ return;
+ }
+ if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
+ return;
+ }
Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
ERR_FAIL_COND(p_elem->_static && p_with->_static);
@@ -49,6 +55,12 @@ void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
}
void BroadPhase2DHashGrid::_unpair_attempt(Element *p_elem, Element *p_with) {
+ if (p_elem->owner == p_with->owner) {
+ return;
+ }
+ if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
+ return;
+ }
Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
ERR_FAIL_COND(!E); //this should really be paired..
@@ -74,24 +86,22 @@ void BroadPhase2DHashGrid::_check_motion(Element *p_elem) {
bool physical_collision = p_elem->aabb.intersects(E->key()->aabb);
bool logical_collision = p_elem->owner->test_collision_mask(E->key()->owner);
- if (physical_collision) {
- if (!E->get()->colliding || (logical_collision && !E->get()->ud && pair_callback)) {
+ if (physical_collision && logical_collision) {
+ if (!E->get()->colliding && pair_callback) {
E->get()->ud = pair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, pair_userdata);
- } else if (E->get()->colliding && !logical_collision && E->get()->ud && unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
- E->get()->ud = nullptr;
}
E->get()->colliding = true;
- } else { // No physcial_collision
+ } else { // No collision
if (E->get()->colliding && unpair_callback) {
unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
+ E->get()->ud = nullptr;
}
E->get()->colliding = false;
}
}
}
-void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
+void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter) {
Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); //use magic number to avoid floating point issues
if (sz.width * sz.height > large_object_min_surface) {
//large object, do not use grid, must check against all elements
@@ -99,9 +109,6 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (E->key() == p_elem->self) {
continue; // do not pair against itself
}
- if (E->get().owner == p_elem->owner) {
- continue;
- }
if (E->get()._static && p_static) {
continue;
}
@@ -133,7 +140,7 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
pb = pb->next;
}
- bool entered = false;
+ bool entered = p_force_enter;
if (!pb) {
//does not exist, create!
@@ -155,17 +162,11 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (entered) {
for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_pair_attempt(p_elem, E->key());
}
if (!p_static) {
for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_pair_attempt(p_elem, E->key());
}
}
@@ -179,18 +180,14 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (E->key() == p_elem) {
continue; // do not pair against itself
}
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
if (E->key()->_static && p_static) {
continue;
}
-
_pair_attempt(E->key(), p_elem);
}
}
-void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
+void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit) {
Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI);
if (sz.width * sz.height > large_object_min_surface) {
//unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static
@@ -229,7 +226,7 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
ERR_CONTINUE(!pb); //should exist!!
- bool exited = false;
+ bool exited = p_force_exit;
if (p_static) {
if (pb->static_object_set[p_elem].dec() == 0) {
@@ -245,17 +242,11 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
if (exited) {
for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_unpair_attempt(p_elem, E->key());
}
if (!p_static) {
for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_unpair_attempt(p_elem, E->key());
}
}
@@ -288,9 +279,6 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
if (E->key() == p_elem) {
continue; // do not pair against itself
}
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
if (E->key()->_static && p_static) {
continue;
}
@@ -306,6 +294,8 @@ BroadPhase2DHashGrid::ID BroadPhase2DHashGrid::create(CollisionObject2DSW *p_obj
Element e;
e.owner = p_object;
e._static = false;
+ e.collision_mask = p_object->get_collision_mask();
+ e.collision_layer = p_object->get_collision_layer();
e.subindex = p_subindex;
e.self = current;
e.pass = 0;
@@ -319,13 +309,26 @@ void BroadPhase2DHashGrid::move(ID p_id, const Rect2 &p_aabb) {
ERR_FAIL_COND(!E);
Element &e = E->get();
+ bool layer_changed = e.collision_mask != e.owner->get_collision_mask() || e.collision_layer != e.owner->get_collision_layer();
- if (p_aabb != e.aabb) {
+ if (p_aabb != e.aabb || layer_changed) {
+ uint32_t old_mask = e.collision_mask;
+ uint32_t old_layer = e.collision_layer;
if (p_aabb != Rect2()) {
- _enter_grid(&e, p_aabb, e._static);
+ e.collision_mask = e.owner->get_collision_mask();
+ e.collision_layer = e.owner->get_collision_layer();
+
+ _enter_grid(&e, p_aabb, e._static, layer_changed);
}
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ // Need _exit_grid to remove from cells based on the old layer values.
+ e.collision_mask = old_mask;
+ e.collision_layer = old_layer;
+
+ _exit_grid(&e, e.aabb, e._static, layer_changed);
+
+ e.collision_mask = e.owner->get_collision_mask();
+ e.collision_layer = e.owner->get_collision_layer();
}
e.aabb = p_aabb;
}
@@ -344,13 +347,13 @@ void BroadPhase2DHashGrid::set_static(ID p_id, bool p_static) {
}
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ _exit_grid(&e, e.aabb, e._static, false);
}
e._static = p_static;
if (e.aabb != Rect2()) {
- _enter_grid(&e, e.aabb, e._static);
+ _enter_grid(&e, e.aabb, e._static, false);
_check_motion(&e);
}
}
@@ -362,7 +365,7 @@ void BroadPhase2DHashGrid::remove(ID p_id) {
Element &e = E->get();
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ _exit_grid(&e, e.aabb, e._static, false);
}
element_map.erase(p_id);
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
index eb7c8879ac..bb7c03b989 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.h
@@ -51,6 +51,9 @@ class BroadPhase2DHashGrid : public BroadPhase2DSW {
CollisionObject2DSW *owner;
bool _static;
Rect2 aabb;
+ // Owner's collision_mask/layer, used to detect changes in layers.
+ uint32_t collision_mask;
+ uint32_t collision_layer;
int subindex;
uint64_t pass;
Map<Element *, PairData *> paired;
@@ -115,8 +118,12 @@ class BroadPhase2DHashGrid : public BroadPhase2DSW {
UnpairCallback unpair_callback;
void *unpair_userdata;
- void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
- void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
+ static _FORCE_INLINE_ bool _test_collision_mask(uint32_t p_mask1, uint32_t p_layer1, uint32_t p_mask2, uint32_t p_layer2) {
+ return p_mask1 & p_layer2 || p_mask2 & p_layer1;
+ }
+
+ void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter);
+ void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit);
template <bool use_aabb, bool use_segment>
_FORCE_INLINE_ void _cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index);
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index 49ae4dd848..b724deb48e 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -37,8 +37,6 @@ class Constraint2DSW {
Body2DSW **_body_ptr;
int _body_count;
uint64_t island_step;
- Constraint2DSW *island_next;
- Constraint2DSW *island_list_next;
bool disabled_collisions_between_bodies;
RID self;
@@ -58,12 +56,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Constraint2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Constraint2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Constraint2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Constraint2DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 3558848dac..20d4b9aa1a 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -55,6 +55,14 @@
* SOFTWARE.
*/
+void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) {
+ set_self(p_joint->get_self());
+ set_max_force(p_joint->get_max_force());
+ set_bias(p_joint->get_bias());
+ set_max_bias(p_joint->get_max_bias());
+ disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies());
+}
+
static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) {
real_t value = 0;
@@ -89,8 +97,13 @@ normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vecto
}
bool PinJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
Space2DSW *space = A->get_space();
ERR_FAIL_COND_V(!space, false);
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B ? B->get_transform().basis_xform(anchor_B) : anchor_B;
@@ -197,15 +210,6 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p
}
}
-PinJoint2DSW::~PinJoint2DSW() {
- if (A) {
- A->remove_constraint(this, 0);
- }
- if (B) {
- B->remove_constraint(this, 1);
- }
-}
-
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
@@ -258,6 +262,10 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) {
}
bool GrooveJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
// calculate endpoints in worldspace
Vector2 ta = A->get_transform().xform(A_groove_1);
Vector2 tb = A->get_transform().xform(A_groove_2);
@@ -338,16 +346,15 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
B->add_constraint(this, 1);
}
-GrooveJoint2DSW::~GrooveJoint2DSW() {
- A->remove_constraint(this, 0);
- B->remove_constraint(this, 1);
-}
-
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
bool DampedSpringJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B->get_transform().basis_xform(anchor_B);
@@ -434,8 +441,3 @@ DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Ve
A->add_constraint(this, 0);
B->add_constraint(this, 1);
}
-
-DampedSpringJoint2DSW::~DampedSpringJoint2DSW() {
- A->remove_constraint(this, 0);
- B->remove_constraint(this, 1);
-}
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 53e436b539..628de972ae 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -49,12 +49,26 @@ public:
_FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias = p_bias; }
_FORCE_INLINE_ real_t get_max_bias() const { return max_bias; }
- virtual PhysicsServer2D::JointType get_type() const = 0;
+ virtual bool setup(real_t p_step) { return false; }
+ virtual void solve(real_t p_step) {}
+
+ void copy_settings_from(Joint2DSW *p_joint);
+
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_MAX; }
Joint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) :
Constraint2DSW(p_body_ptr, p_body_count) {
bias = 0;
max_force = max_bias = 3.40282e+38;
};
+
+ virtual ~Joint2DSW() {
+ for (int i = 0; i < get_body_count(); i++) {
+ Body2DSW *body = get_body_ptr()[i];
+ if (body) {
+ body->remove_constraint(this, i);
+ }
+ }
+ };
};
class PinJoint2DSW : public Joint2DSW {
@@ -76,7 +90,7 @@ class PinJoint2DSW : public Joint2DSW {
real_t softness;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_PIN; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
@@ -85,7 +99,6 @@ public:
real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr);
- ~PinJoint2DSW();
};
class GrooveJoint2DSW : public Joint2DSW {
@@ -113,13 +126,12 @@ class GrooveJoint2DSW : public Joint2DSW {
bool correct;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_GROOVE; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b);
- ~GrooveJoint2DSW();
};
class DampedSpringJoint2DSW : public Joint2DSW {
@@ -146,7 +158,7 @@ class DampedSpringJoint2DSW : public Joint2DSW {
real_t v_coef;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_DAMPED_SPRING; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
@@ -155,7 +167,6 @@ public:
real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;
DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b);
- ~DampedSpringJoint2DSW();
};
#endif // JOINTS_2D_SW_H
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 14fcf1520a..6d64f4126c 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -927,10 +927,10 @@ int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
@@ -985,6 +985,24 @@ PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) {
/* JOINT API */
+RID PhysicsServer2DSW::joint_create() {
+ Joint2DSW *joint = memnew(Joint2DSW);
+ RID joint_rid = joint_owner.make_rid(joint);
+ joint->set_self(joint_rid);
+ return joint_rid;
+}
+
+void PhysicsServer2DSW::joint_clear(RID p_joint) {
+ Joint2DSW *joint = joint_owner.getornull(p_joint);
+ if (joint->get_type() != JOINT_TYPE_MAX) {
+ Joint2DSW *empty_joint = memnew(Joint2DSW);
+ empty_joint->copy_settings_from(joint);
+
+ joint_owner.replace(p_joint, empty_joint);
+ memdelete(joint);
+ }
+}
+
void PhysicsServer2DSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) {
Joint2DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
@@ -1048,52 +1066,63 @@ bool PhysicsServer2DSW::joint_is_disabled_collisions_between_bodies(RID p_joint)
return joint->is_disabled_collisions_between_bodies();
}
-RID PhysicsServer2DSW::pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b) {
+void PhysicsServer2DSW::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) {
Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND_V(!A, RID());
+ ERR_FAIL_COND(!A);
Body2DSW *B = nullptr;
if (body_owner.owns(p_body_b)) {
B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
+ ERR_FAIL_COND(!B);
}
+ Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
+
Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B));
- RID self = joint_owner.make_rid(joint);
- joint->set_self(self);
- return self;
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
}
-RID PhysicsServer2DSW::groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) {
+void PhysicsServer2DSW::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) {
Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND_V(!A, RID());
+ ERR_FAIL_COND(!A);
Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
+ ERR_FAIL_COND(!B);
+
+ Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint2DSW *joint = memnew(GrooveJoint2DSW(p_a_groove1, p_a_groove2, p_b_anchor, A, B));
- RID self = joint_owner.make_rid(joint);
- joint->set_self(self);
- return self;
+
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
}
-RID PhysicsServer2DSW::damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) {
+void PhysicsServer2DSW::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) {
Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND_V(!A, RID());
+ ERR_FAIL_COND(!A);
Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
+ ERR_FAIL_COND(!B);
+
+ Joint2DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint2DSW *joint = memnew(DampedSpringJoint2DSW(p_anchor_a, p_anchor_b, A, B));
- RID self = joint_owner.make_rid(joint);
- joint->set_self(self);
- return self;
+
+ joint_owner.replace(p_joint, joint);
+ joint->copy_settings_from(prev_joint);
+ memdelete(prev_joint);
}
void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
Joint2DSW *j = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!j);
- ERR_FAIL_COND(j->get_type() != JOINT_PIN);
+ ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN);
PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
pin_joint->set_param(p_param, p_value);
@@ -1102,7 +1131,7 @@ void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param,
real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
Joint2DSW *j = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!j, 0);
- ERR_FAIL_COND_V(j->get_type() != JOINT_PIN, 0);
+ ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0);
PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
return pin_joint->get_param(p_param);
@@ -1111,7 +1140,7 @@ real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param
void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) {
Joint2DSW *j = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!j);
- ERR_FAIL_COND(j->get_type() != JOINT_DAMPED_SPRING);
+ ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING);
DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
dsj->set_param(p_param, p_value);
@@ -1120,7 +1149,7 @@ void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringP
real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const {
Joint2DSW *j = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!j, 0);
- ERR_FAIL_COND_V(j->get_type() != JOINT_DAMPED_SPRING, 0);
+ ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0);
DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
return dsj->get_param(p_param);
@@ -1128,7 +1157,7 @@ real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSprin
PhysicsServer2D::JointType PhysicsServer2DSW::joint_get_type(RID p_joint) const {
Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, JOINT_PIN);
+ ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN);
return joint->get_type();
}
@@ -1325,7 +1354,7 @@ int PhysicsServer2DSW::get_process_info(ProcessInfo p_info) {
PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr;
-PhysicsServer2DSW::PhysicsServer2DSW() {
+PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) {
singletonsw = this;
BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create;
//BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
@@ -1334,10 +1363,6 @@ PhysicsServer2DSW::PhysicsServer2DSW() {
island_count = 0;
active_objects = 0;
collision_pairs = 0;
-#ifdef NO_THREADS
- using_threads = false;
-#else
- using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2;
-#endif
+ using_threads = p_using_threads;
flushing_queries = false;
};
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index 62ea30b3f6..efa0784245 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -61,11 +61,11 @@ class PhysicsServer2DSW : public PhysicsServer2D {
PhysicsDirectBodyState2DSW *direct_state;
- mutable RID_PtrOwner<Shape2DSW> shape_owner;
- mutable RID_PtrOwner<Space2DSW> space_owner;
- mutable RID_PtrOwner<Area2DSW> area_owner;
- mutable RID_PtrOwner<Body2DSW> body_owner;
- mutable RID_PtrOwner<Joint2DSW> joint_owner;
+ mutable RID_PtrOwner<Shape2DSW, true> shape_owner;
+ mutable RID_PtrOwner<Space2DSW, true> space_owner;
+ mutable RID_PtrOwner<Area2DSW, true> area_owner;
+ mutable RID_PtrOwner<Body2DSW, true> body_owner;
+ mutable RID_PtrOwner<Joint2DSW, true> joint_owner;
static PhysicsServer2DSW *singletonsw;
@@ -242,7 +242,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
@@ -255,15 +255,20 @@ public:
/* JOINT API */
+ virtual RID joint_create() override;
+
+ virtual void joint_clear(RID p_joint) override;
+
virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value) override;
virtual real_t joint_get_param(RID p_joint, JointParam p_param) const override;
virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disabled) override;
virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const override;
- virtual RID pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b = RID()) override;
- virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) override;
- virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) override;
+ virtual void joint_make_pin(RID p_joint, const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) override;
+ virtual void joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) override;
+ virtual void joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) override;
+
virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override;
virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override;
virtual void damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) override;
@@ -287,7 +292,7 @@ public:
int get_process_info(ProcessInfo p_info) override;
- PhysicsServer2DSW();
+ PhysicsServer2DSW(bool p_using_threads = false);
~PhysicsServer2DSW() {}
};
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
index 897724fe6f..790c87cc44 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
void PhysicsServer2DWrapMT::thread_exit() {
- exit = true;
+ exit.set();
}
void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
@@ -52,9 +52,9 @@ void PhysicsServer2DWrapMT::thread_loop() {
physics_2d_server->init();
- exit = false;
- step_thread_up = true;
- while (!exit) {
+ exit.clear();
+ step_thread_up.set();
+ while (!exit.is_set()) {
// flush commands one by one, until exit is requested
command_queue.wait_and_flush_one();
}
@@ -98,7 +98,7 @@ void PhysicsServer2DWrapMT::init() {
if (create_thread) {
//OS::get_singleton()->release_rendering_thread();
thread.start(_thread_callback, this);
- while (!step_thread_up) {
+ while (!step_thread_up.is_set()) {
OS::get_singleton()->delay_usec(1000);
}
} else {
@@ -113,19 +113,6 @@ void PhysicsServer2DWrapMT::finish() {
} else {
physics_2d_server->finish();
}
-
- line_shape_free_cached_ids();
- ray_shape_free_cached_ids();
- segment_shape_free_cached_ids();
- circle_shape_free_cached_ids();
- rectangle_shape_free_cached_ids();
- capsule_shape_free_cached_ids();
- convex_polygon_shape_free_cached_ids();
- concave_polygon_shape_free_cached_ids();
-
- space_free_cached_ids();
- area_free_cached_ids();
- body_free_cached_ids();
}
PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) :
@@ -133,7 +120,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool
physics_2d_server = p_contained;
create_thread = p_create_thread;
step_pending = 0;
- step_thread_up = false;
pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc");
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index fbc5b1eaa1..88ac742e40 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/os/thread.h"
#include "core/templates/command_queue_mt.h"
+#include "core/templates/safe_refcount.h"
#include "servers/physics_server_2d.h"
#ifdef DEBUG_SYNC
@@ -52,9 +53,9 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D {
Thread::ID server_thread;
Thread::ID main_thread;
- volatile bool exit;
+ SafeFlag exit;
Thread thread;
- volatile bool step_thread_up;
+ SafeFlag step_thread_up;
bool create_thread;
Semaphore step_sem;
@@ -73,6 +74,8 @@ public:
#define ServerName PhysicsServer2D
#define ServerNameWrapMT PhysicsServer2DWrapMT
#define server_name physics_2d_server
+#define WRITE_ACTION
+
#include "servers/server_wrap_mt_common.h"
//FUNC1RID(shape,ShapeType); todo fix
@@ -93,7 +96,7 @@ public:
FUNC1RC(real_t, shape_get_custom_solver_bias, RID);
//these work well, but should be used from the main thread only
- bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) {
+ bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_2d_server->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count);
}
@@ -108,18 +111,18 @@ public:
FUNC2RC(real_t, space_get_param, RID, SpaceParameter);
// this function only works on physics process, errors and returns null otherwise
- PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) {
+ PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
return physics_2d_server->space_get_direct_state(p_space);
}
FUNC2(space_set_debug_contacts, RID, int);
- virtual Vector<Vector2> space_get_contacts(RID p_space) const {
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector2>());
return physics_2d_server->space_get_contacts(p_space);
}
- virtual int space_get_contact_count(RID p_space) const {
+ virtual int space_get_contact_count(RID p_space) const override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0);
return physics_2d_server->space_get_contact_count(p_space);
}
@@ -242,32 +245,36 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
- bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
+ bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
}
FUNC2(body_set_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) {
+ bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
}
- int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) {
+ int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_2d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
}
// this function only works on physics process, errors and returns null otherwise
- PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) {
+ PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
return physics_2d_server->body_get_direct_state(p_body);
}
/* JOINT API */
+ FUNCRID(joint)
+
+ FUNC1(joint_clear, RID)
+
FUNC3(joint_set_param, RID, JointParam, real_t);
FUNC2RC(real_t, joint_get_param, RID, JointParam);
@@ -280,9 +287,9 @@ public:
//TODO need to convert this to FUNCRID, but it's a hassle..
- FUNC3R(RID, pin_joint_create, const Vector2 &, RID, RID);
- FUNC5R(RID, groove_joint_create, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID);
- FUNC4R(RID, damped_spring_joint_create, const Vector2 &, const Vector2 &, RID, RID);
+ FUNC4(joint_make_pin, RID, const Vector2 &, RID, RID);
+ FUNC6(joint_make_groove, RID, const Vector2 &, const Vector2 &, const Vector2 &, RID, RID);
+ FUNC5(joint_make_damped_spring, RID, const Vector2 &, const Vector2 &, RID, RID);
FUNC3(pin_joint_set_param, RID, PinJointParam, real_t);
FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam);
@@ -297,43 +304,28 @@ public:
FUNC1(free, RID);
FUNC1(set_active, bool);
- virtual void init();
- virtual void step(real_t p_step);
- virtual void sync();
- virtual void end_sync();
- virtual void flush_queries();
- virtual void finish();
+ virtual void init() override;
+ virtual void step(real_t p_step) override;
+ virtual void sync() override;
+ virtual void end_sync() override;
+ virtual void flush_queries() override;
+ virtual void finish() override;
- virtual bool is_flushing_queries() const {
+ virtual bool is_flushing_queries() const override {
return physics_2d_server->is_flushing_queries();
}
- int get_process_info(ProcessInfo p_info) {
+ int get_process_info(ProcessInfo p_info) override {
return physics_2d_server->get_process_info(p_info);
}
PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread);
~PhysicsServer2DWrapMT();
- template <class T>
- static PhysicsServer2D *init_server() {
-#ifdef NO_THREADS
- return memnew(T); // Always single unsafe when no threads are available.
-#else
- int tm = GLOBAL_DEF("physics/2d/thread_model", 1);
- if (tm == 0) { // single unsafe
- return memnew(T);
- } else if (tm == 1) { // single safe
- return memnew(PhysicsServer2DWrapMT(memnew(T), false));
- } else { // multi threaded
- return memnew(PhysicsServer2DWrapMT(memnew(T), true));
- }
-#endif
- }
-
#undef ServerNameWrapMT
#undef ServerName
#undef server_name
+#undef WRITE_ACTION
};
#ifdef DEBUG_SYNC
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 6e7e802a8b..6cc086b9b7 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -502,6 +502,7 @@ Variant CapsuleShape2DSW::get_data() const {
void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
int support_idx = -1;
real_t d = -1e10;
+ r_amount = 0;
for (int i = 0; i < point_count; i++) {
//test point
@@ -520,7 +521,7 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su
}
}
- ERR_FAIL_COND(support_idx == -1);
+ ERR_FAIL_COND_MSG(support_idx == -1, "Convex polygon shape support not found.");
r_amount = 1;
r_supports[0] = points[support_idx].pos;
@@ -580,6 +581,7 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vec
}
real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+ ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points.");
Rect2 aabb;
aabb.position = points[0].pos * p_scale;
for (int i = 0; i < point_count; i++) {
@@ -691,6 +693,10 @@ bool ConcavePolygonShape2DSW::contains_point(const Vector2 &p_point) const {
}
bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+ if (segments.size() == 0 || points.size() == 0) {
+ return false;
+ }
+
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);
enum {
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 05136e2501..4f12248c3e 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -84,6 +84,10 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Shape2DSW *shape = col_obj->get_shape(shape_idx);
Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point);
@@ -229,6 +233,10 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_margin)) {
continue;
}
@@ -272,6 +280,10 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
//test initial overlap, does it collide if going all the way?
if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
@@ -346,12 +358,17 @@ bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D &
}
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
cbk.valid_dir = Vector2();
cbk.valid_depth = 0;
@@ -376,6 +393,7 @@ struct _RestCallbackData2D {
Vector2 best_normal;
real_t best_len;
Vector2 valid_dir;
+ real_t valid_depth;
real_t min_allowed_depth;
};
@@ -385,22 +403,24 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B,
Vector2 contact_rel = p_point_B - p_point_A;
real_t len = contact_rel.length();
- if (len == 0) {
+ if (len < rd->min_allowed_depth) {
return;
}
- Vector2 normal = contact_rel / len;
-
- if (rd->valid_dir != Vector2() && rd->valid_dir.dot(normal) > -CMP_EPSILON) {
+ if (len <= rd->best_len) {
return;
}
- if (len < rd->min_allowed_depth) {
- return;
- }
+ Vector2 normal = contact_rel / len;
- if (len <= rd->best_len) {
- return;
+ if (rd->valid_dir != Vector2()) {
+ if (len > rd->valid_depth) {
+ return;
+ }
+
+ if (rd->valid_dir.dot(normal) > -CMP_EPSILON) {
+ return;
+ }
}
rd->best_len = len;
@@ -433,12 +453,17 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh
}
const CollisionObject2DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
rcd.valid_dir = Vector2();
rcd.object = col_obj;
rcd.shape = shape_idx;
@@ -739,10 +764,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
int excluded_shape_pair_count = 0;
- real_t separation_margin = MIN(p_margin, MAX(0.0, p_motion.length() - CMP_EPSILON)); //don't separate by more than the intended motion
+ real_t motion_length = p_motion.length();
+ Vector2 motion_normal = p_motion / motion_length;
Transform2D body_transform = p_from;
+ bool recovered = false;
+
{
//STEP 1, FREE BODY IF STUCK
@@ -819,7 +847,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
bool did_collide = false;
Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, separation_margin)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
}
@@ -845,11 +873,20 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
Vector2 recover_motion;
-
for (int i = 0; i < cbk.amount; i++) {
Vector2 a = sr[i * 2 + 0];
Vector2 b = sr[i * 2 + 1];
- recover_motion += (b - a) / cbk.amount;
+
+ // Compute plane on b towards a.
+ Vector2 n = (a - b).normalized();
+ real_t d = n.dot(b);
+
+ // Compute depth on recovered motion.
+ real_t depth = n.dot(a + recover_motion) - d;
+ if (depth > 0.0) {
+ // Only recover if there is penetration.
+ recover_motion -= n * depth * 0.4;
+ }
}
if (recover_motion == Vector2()) {
@@ -857,6 +894,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
break;
}
+ recovered = true;
+
body_transform.elements[2] += recover_motion;
body_aabb.position += recover_motion;
@@ -929,7 +968,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//test initial overlap
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
- continue;
+ Vector2 direction = col_obj_shape_xform.get_axis(1).normalized();
+ if (motion_normal.dot(direction) < 0) {
+ continue;
+ }
}
stuck = true;
@@ -939,13 +981,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//just do kinematic solving
real_t low = 0;
real_t hi = 1;
- Vector2 mnormal = p_motion.normalized();
for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t ofs = (low + hi) * 0.5;
- Vector2 sep = mnormal; //important optimization for this to work fast enough
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0);
if (collided) {
@@ -966,7 +1007,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.valid_depth = 10e20;
- Vector2 sep = mnormal; //important optimization for this to work fast enough
+ Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) {
continue;
@@ -997,11 +1038,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
bool collided = false;
- if (safe >= 1) {
- best_shape = -1; //no best shape with cast, reset to -1
- }
- if (safe < 1) {
+ if (recovered || (safe < 1)) {
+ if (safe >= 1) {
+ best_shape = -1; //no best shape with cast, reset to -1
+ }
+
//it collided, let's get the rest info in unsafe advance
Transform2D ugt = body_transform;
ugt.elements[2] += p_motion * unsafe;
@@ -1010,9 +1052,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
- rcd.min_allowed_depth = test_motion_min_contact_depth;
- //optimization
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
+
int from_shape = best_shape != -1 ? best_shape : 0;
int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
@@ -1060,8 +1103,25 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
+
+ real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
+ rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work
+
+ if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
+ const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
+ //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
+ Vector2 lv = b->get_linear_velocity();
+ //compute displacement from linear velocity
+ Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
+ real_t motion_len = motion.length();
+ motion.normalize();
+ rcd.valid_depth += motion_len * MAX(motion.dot(-rcd.valid_dir), 0.0);
+ }
+ }
} else {
rcd.valid_dir = Vector2();
+ rcd.valid_depth = 0;
}
rcd.object = col_obj;
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 6613d19729..406d750776 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -31,19 +31,23 @@
#include "step_2d_sw.h"
#include "core/os/os.h"
-void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island) {
+#define BODY_ISLAND_COUNT_RESERVE 128
+#define BODY_ISLAND_SIZE_RESERVE 512
+#define ISLAND_COUNT_RESERVE 128
+#define ISLAND_SIZE_RESERVE 512
+
+void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
+ p_body_island.push_back(p_body);
- for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
+ // Faster with reversed iterations.
+ for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().back(); E; E = E->prev()) {
Constraint2DSW *c = (Constraint2DSW *)E->get().first;
if (c->get_island_step() == _step) {
continue; //already processed
}
c->set_island_step(_step);
- c->set_island_next(*p_constraint_island);
- *p_constraint_island = c;
+ p_constraint_island.push_back(c);
for (int i = 0; i < c->get_body_count(); i++) {
if (i == E->get().second) {
@@ -53,78 +57,62 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
continue; //no go
}
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
+ _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
}
}
}
-bool Step2DSW::_setup_island(Constraint2DSW *p_island, real_t p_delta) {
- Constraint2DSW *ci = p_island;
- Constraint2DSW *prev_ci = nullptr;
- bool removed_root = false;
- while (ci) {
- bool process = ci->setup(p_delta);
-
- if (!process) {
- //remove from island if process fails
- if (prev_ci) {
- prev_ci->set_island_next(ci->get_island_next());
- } else {
- removed_root = true;
- prev_ci = ci;
- }
- } else {
- prev_ci = ci;
+void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta) {
+ uint32_t constraint_count = p_constraint_island.size();
+ uint32_t valid_constraint_count = 0;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint2DSW *constraint = p_constraint_island[constraint_index];
+ if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ // Keep this constraint for solving.
+ p_constraint_island[valid_constraint_count++] = constraint;
}
- ci = ci->get_island_next();
}
-
- return removed_root;
+ p_constraint_island.resize(valid_constraint_count);
}
-void Step2DSW::_solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta) {
+void Step2DSW::_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
for (int i = 0; i < p_iterations; i++) {
- Constraint2DSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
+ uint32_t constraint_count = p_constraint_island.size();
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ p_constraint_island[constraint_index]->solve(p_delta);
}
}
}
-void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) {
+void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta) {
bool can_sleep = true;
- Body2DSW *b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ uint32_t body_count = p_body_island.size();
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body2DSW *body = p_body_island[body_index];
+
+ if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- if (!b->sleep_test(p_delta)) {
+ if (!body->sleep_test(p_delta)) {
can_sleep = false;
}
-
- b = b->get_island_next();
}
- //put all to sleep or wake up everyoen
+ // Put all to sleep or wake up everyone.
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body2DSW *body = p_body_island[body_index];
- b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- bool active = b->is_active();
+ bool active = body->is_active();
if (active == can_sleep) {
- b->set_active(!can_sleep);
+ body->set_active(!can_sleep);
}
-
- b = b->get_island_next();
}
}
@@ -159,33 +147,43 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* GENERATE CONSTRAINT ISLANDS */
- Body2DSW *island_list = nullptr;
- Constraint2DSW *constraint_island_list = nullptr;
b = body_list->first();
- int island_count = 0;
+ uint32_t body_island_count = 0;
+ uint32_t island_count = 0;
while (b) {
Body2DSW *body = b->self();
if (body->get_island_step() != _step) {
- Body2DSW *island = nullptr;
- Constraint2DSW *constraint_island = nullptr;
- _populate_island(body, &island, &constraint_island);
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
+ }
+ LocalVector<Body2DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
- island->set_island_list_next(island_list);
- island_list = island;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
+ _populate_island(body, body_island, constraint_island);
+
+ body_islands.push_back(body_island);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
}
b = b->next();
}
- p_space->set_island_count(island_count);
+ p_space->set_island_count((int)island_count);
const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
@@ -196,9 +194,13 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
continue;
}
c->set_island_step(_step);
- c->set_island_next(nullptr);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(c);
}
p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
}
@@ -211,39 +213,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SETUP CONSTRAINT ISLANDS */
- {
- Constraint2DSW *ci = constraint_island_list;
- Constraint2DSW *prev_ci = nullptr;
- while (ci) {
- if (_setup_island(ci, p_delta)) {
- //removed the root from the island graph because it is not to be processed
-
- Constraint2DSW *next = ci->get_island_next();
-
- if (next) {
- //root from list being deleted no longer exists, replace by next
- next->set_island_list_next(ci->get_island_list_next());
- if (prev_ci) {
- prev_ci->set_island_list_next(next);
- } else {
- constraint_island_list = next;
- }
- prev_ci = next;
- } else {
- //list is empty, just skip
- if (prev_ci) {
- prev_ci->set_island_list_next(ci->get_island_list_next());
-
- } else {
- constraint_island_list = ci->get_island_list_next();
- }
- }
- } else {
- prev_ci = ci;
- }
-
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _setup_island(constraint_islands[island_index], p_delta);
}
{ //profile
@@ -254,13 +225,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SOLVE CONSTRAINT ISLANDS */
- {
- Constraint2DSW *ci = constraint_island_list;
- while (ci) {
- //iterating each island separatedly improves cache efficiency
- _solve_island(ci, p_iterations, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _solve_island(constraint_islands[island_index], p_iterations, p_delta);
}
{ //profile
@@ -280,12 +246,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
- {
- Body2DSW *bi = island_list;
- while (bi) {
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
+ _check_suspend(body_islands[island_index], p_delta);
}
{ //profile
@@ -301,4 +263,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
Step2DSW::Step2DSW() {
_step = 1;
+
+ body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
+ constraint_islands.reserve(ISLAND_COUNT_RESERVE);
}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index 83b9130608..5af4a36f52 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/step_2d_sw.h
@@ -33,13 +33,18 @@
#include "space_2d_sw.h"
+#include "core/templates/local_vector.h"
+
class Step2DSW {
uint64_t _step;
- void _populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island);
- bool _setup_island(Constraint2DSW *p_island, real_t p_delta);
- void _solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(Body2DSW *p_island, real_t p_delta);
+ LocalVector<LocalVector<Body2DSW *>> body_islands;
+ LocalVector<LocalVector<Constraint2DSW *>> constraint_islands;
+
+ void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island);
+ void _setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta);
+ void _solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
+ void _check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta);
public:
void step(Space2DSW *p_space, real_t p_delta, int p_iterations);
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
index b6c5b3003c..bb4e0ed752 100644
--- a/servers/physics_3d/area_3d_sw.cpp
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -215,7 +215,9 @@ void Area3DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_bodies.erase(E);
+ E = next;
continue;
}
@@ -250,7 +252,9 @@ void Area3DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_areas.erase(E);
+ E = next;
continue;
}
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 82356e77ef..d54345821d 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -51,18 +51,18 @@ void Body3DSW::_update_transform_dependant() {
}
void Body3DSW::update_inertias() {
- //update shapes and motions
+ // Update shapes and motions.
switch (mode) {
case PhysicsServer3D::BODY_MODE_RIGID: {
- //update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
+ // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
for (int i = 0; i < get_shape_count(); i++) {
total_area += get_shape_area(i);
}
- // We have to recompute the center of mass
+ // We have to recompute the center of mass.
center_of_mass_local.zero();
for (int i = 0; i < get_shape_count(); i++) {
@@ -70,21 +70,24 @@ void Body3DSW::update_inertias() {
real_t mass = area * this->mass / total_area;
- // NOTE: we assume that the shape origin is also its center of mass
+ // NOTE: we assume that the shape origin is also its center of mass.
center_of_mass_local += mass * get_shape_transform(i).origin;
}
center_of_mass_local /= mass;
- // Recompute the inertia tensor
+ // Recompute the inertia tensor.
Basis inertia_tensor;
inertia_tensor.set_zero();
+ bool inertia_set = false;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
continue;
}
+ inertia_set = true;
+
const Shape3DSW *shape = get_shape(i);
real_t area = get_shape_area(i);
@@ -102,7 +105,12 @@ void Body3DSW::update_inertias() {
inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
}
- // Compute the principal axes of inertia
+ // Set the inertia to a valid value when there are no valid shapes.
+ if (!inertia_set) {
+ inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0));
+ }
+
+ // Compute the principal axes of inertia.
principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
_inv_inertia = inertia_tensor.get_main_diagonal().inverse();
@@ -493,20 +501,18 @@ void Body3DSW::integrate_forces(real_t p_step) {
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
- linear_velocity = (new_transform.origin - get_transform().origin) / p_step;
+ motion = new_transform.origin - get_transform().origin;
+ do_motion = true;
+ linear_velocity = motion / p_step;
//compute a FAKE angular velocity, not so easy
- Basis rot = new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
+ Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
Vector3 axis;
real_t angle;
rot.get_axis_angle(axis, angle);
axis.normalize();
- angular_velocity = axis.normalized() * (angle / p_step);
-
- motion = new_transform.origin - get_transform().origin;
- do_motion = true;
-
+ angular_velocity = axis * (angle / p_step);
} else {
if (!omit_force_integration && !first_integration) {
//overridden by direct state query
@@ -687,15 +693,16 @@ void Body3DSW::call_queries() {
Variant v = dbs;
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &v, &fi_callback->udata };
Callable::CallError ce;
int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(fi_callback->method, vp, argc, ce);
+ Variant rv;
+ fi_callback->callable.call(vp, argc, rv, ce);
}
}
}
@@ -719,16 +726,15 @@ bool Body3DSW::sleep_test(real_t p_step) {
}
}
-void Body3DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->udata = p_udata;
}
}
@@ -755,8 +761,6 @@ Body3DSW::Body3DSW() :
omit_force_integration = false;
//applied_torque=0;
island_step = 0;
- island_next = nullptr;
- island_list_next = nullptr;
first_time_kinematic = false;
first_integration = false;
_set_static(false);
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 8e21003a5f..9afb8cd56f 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -127,16 +127,13 @@ class Body3DSW : public CollisionObject3DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
ForceIntegrationCallback *fi_callback;
uint64_t island_step;
- Body3DSW *island_next;
- Body3DSW *island_list_next;
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area3DSW *p_area);
@@ -145,7 +142,7 @@ class Body3DSW : public CollisionObject3DSW {
friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
void set_kinematic_margin(real_t p_margin);
_FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
@@ -189,12 +186,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Body3DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Body3DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Body3DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Body3DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
_FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraint_map.erase(p_constraint); }
const Map<Constraint3DSW *, int> &get_constraint_map() const { return constraint_map; }
@@ -290,10 +281,10 @@ public:
void update_inertias();
_FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; }
- _FORCE_INLINE_ Vector3 get_inv_inertia() const { return _inv_inertia; }
- _FORCE_INLINE_ Basis get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
+ _FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; }
+ _FORCE_INLINE_ const Basis &get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
- _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
+ _FORCE_INLINE_ const Vector3 &get_gravity() const { return gravity; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock);
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 6012ff1522..28c854466f 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -49,12 +49,12 @@
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
-void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
BodyPair3DSW *pair = (BodyPair3DSW *)p_userdata;
- pair->contact_added_callback(p_point_A, p_point_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
}
-void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
// check if we already have the contact
//Vector3 local_A = A->get_inv_transform().xform(p_point_A);
@@ -73,6 +73,8 @@ void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector
contact.acc_bias_impulse = 0;
contact.acc_bias_impulse_center_of_mass = 0;
contact.acc_tangent_impulse = Vector3();
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
contact.local_A = local_A;
contact.local_B = local_B;
contact.normal = (p_point_A - p_point_B).normalized();
@@ -211,11 +213,21 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) {
bool BodyPair3DSW::setup(real_t p_step) {
//cannot collide
- if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self()) || (A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
+ if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
+ bool report_contacts_only = false;
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
+ report_contacts_only = true;
+ } else {
+ collided = false;
+ return false;
+ }
+ }
+
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
@@ -269,6 +281,8 @@ bool BodyPair3DSW::setup(real_t p_step) {
real_t inv_dt = 1.0 / p_step;
+ bool do_process = false;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
c.active = false;
@@ -279,12 +293,9 @@ bool BodyPair3DSW::setup(real_t p_step) {
real_t depth = c.normal.dot(global_A - global_B);
if (depth <= 0) {
- c.active = false;
continue;
}
- c.active = true;
-
#ifdef DEBUG_ENABLED
if (space->is_debugging_contacts()) {
@@ -308,7 +319,13 @@ bool BodyPair3DSW::setup(real_t p_step) {
B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
}
+ if (report_contacts_only) {
+ collided = false;
+ continue;
+ }
+
c.active = true;
+ do_process = true;
// Precompute normal mass, tangent mass, and bias.
Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
@@ -336,7 +353,7 @@ bool BodyPair3DSW::setup(real_t p_step) {
}
}
- return true;
+ return do_process;
}
void BodyPair3DSW::solve(real_t p_step) {
@@ -456,7 +473,7 @@ void BodyPair3DSW::solve(real_t p_step) {
}
BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B) :
- Constraint3DSW(_arr, 2) {
+ BodyContact3DSW(_arr, 2) {
A = p_A;
B = p_B;
shape_A = p_shape_A;
@@ -472,3 +489,308 @@ BodyPair3DSW::~BodyPair3DSW() {
A->remove_constraint(this);
B->remove_constraint(this);
}
+
+void BodySoftBodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ BodySoftBodyPair3DSW *pair = (BodySoftBodyPair3DSW *)p_userdata;
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+}
+
+void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+ Vector3 local_A = body->get_inv_transform().xform(p_point_A);
+ Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B);
+
+ Contact contact;
+ contact.index_A = p_index_A;
+ contact.index_B = p_index_B;
+ contact.acc_normal_impulse = 0;
+ contact.acc_bias_impulse = 0;
+ contact.acc_bias_impulse_center_of_mass = 0;
+ contact.acc_tangent_impulse = Vector3();
+ contact.local_A = local_A;
+ contact.local_B = local_B;
+ contact.normal = (p_point_A - p_point_B).normalized();
+ contact.mass_normal = 0;
+
+ // Attempt to determine if the contact will be reused.
+ real_t contact_recycle_radius = space->get_contact_recycle_radius();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (c.index_B == p_index_B) {
+ if (c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
+ c.local_B.distance_squared_to(local_B) < (contact_recycle_radius * contact_recycle_radius)) {
+ contact.acc_normal_impulse = c.acc_normal_impulse;
+ contact.acc_bias_impulse = c.acc_bias_impulse;
+ contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
+ contact.acc_tangent_impulse = c.acc_tangent_impulse;
+ }
+ c = contact;
+ return;
+ }
+ }
+
+ contacts.push_back(contact);
+}
+
+void BodySoftBodyPair3DSW::validate_contacts() {
+ // Make sure to erase contacts that are no longer valid.
+ const Transform &transform_A = body->get_transform();
+
+ real_t contact_max_separation = space->get_contact_max_separation();
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+
+ Vector3 global_A = transform_A.xform(c.local_A);
+ Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
+
+ if (depth < -contact_max_separation || (global_B + c.normal * depth - global_A).length() > contact_max_separation) {
+ // Contact no longer needed, remove.
+ if ((contact_index + 1) < contact_count) {
+ // Swap with the last one.
+ SWAP(c, contacts[contact_count - 1]);
+ }
+
+ contact_index--;
+ contact_count--;
+ }
+ }
+
+ contacts.resize(contact_count);
+}
+
+bool BodySoftBodyPair3DSW::setup(real_t p_step) {
+ if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
+ collided = false;
+ return false;
+ }
+
+ if (body->is_shape_set_as_disabled(body_shape)) {
+ collided = false;
+ return false;
+ }
+
+ const Transform &xform_Au = body->get_transform();
+ Transform xform_A = xform_Au * body->get_shape_transform(body_shape);
+
+ Transform xform_Bu = soft_body->get_transform();
+ Transform xform_B = xform_Bu * soft_body->get_shape_transform(0);
+
+ validate_contacts();
+
+ Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
+ Shape3DSW *shape_B_ptr = soft_body->get_shape(0);
+
+ bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
+ this->collided = collided;
+
+ real_t max_penetration = space->get_contact_max_allowed_penetration();
+
+ real_t bias = (real_t)0.3;
+ if (shape_A_ptr->get_custom_bias()) {
+ bias = shape_A_ptr->get_custom_bias();
+ }
+
+ real_t inv_dt = 1.0 / p_step;
+
+ bool do_process = false;
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ c.active = false;
+
+ real_t node_inv_mass = soft_body->get_node_inv_mass(c.index_B);
+ if (node_inv_mass == 0.0) {
+ continue;
+ }
+
+ Vector3 global_A = xform_Au.xform(c.local_A);
+ Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
+
+ real_t depth = c.normal.dot(global_A - global_B);
+
+ if (depth <= 0) {
+ continue;
+ }
+
+ c.active = true;
+ do_process = true;
+
+#ifdef DEBUG_ENABLED
+
+ if (space->is_debugging_contacts()) {
+ space->add_debug_contact(global_A);
+ space->add_debug_contact(global_B);
+ }
+#endif
+
+ c.rA = global_A - xform_Au.origin - body->get_center_of_mass();
+ c.rB = global_B;
+
+ if (body->can_report_contacts()) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA) + body->get_linear_velocity();
+ body->add_contact(global_A, -c.normal, depth, body_shape, global_B, 0, soft_body->get_instance_id(), soft_body->get_self(), crA);
+ }
+
+ if (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ body->set_active(true);
+ }
+
+ // Precompute normal mass, tangent mass, and bias.
+ Vector3 inertia_A = body->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
+ real_t kNormal = body->get_inv_mass() + node_inv_mass;
+ kNormal += c.normal.dot(inertia_A.cross(c.rA));
+ c.mass_normal = 1.0f / kNormal;
+
+ c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);
+ c.depth = depth;
+
+ Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
+ body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass());
+ soft_body->apply_node_impulse(c.index_B, j_vec);
+ c.acc_bias_impulse = 0;
+ c.acc_bias_impulse_center_of_mass = 0;
+
+ c.bounce = body->get_bounce();
+
+ if (c.bounce) {
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ c.bounce = c.bounce * dv.dot(c.normal);
+ }
+ }
+
+ return do_process;
+}
+
+void BodySoftBodyPair3DSW::solve(real_t p_step) {
+ if (!collided) {
+ return;
+ }
+
+ uint32_t contact_count = contacts.size();
+ for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
+ Contact &c = contacts[contact_index];
+ if (!c.active) {
+ continue;
+ }
+
+ c.active = false;
+
+ // Bias impulse.
+ Vector3 crbA = body->get_biased_angular_velocity().cross(c.rA);
+ Vector3 dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ real_t vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn = (-vbn + c.bias) * c.mass_normal;
+ real_t jbnOld = c.acc_bias_impulse;
+ c.acc_bias_impulse = MAX(jbnOld + jbn, 0.0f);
+
+ Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
+
+ body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
+ soft_body->apply_node_bias_impulse(c.index_B, jb);
+
+ crbA = body->get_biased_angular_velocity().cross(c.rA);
+ dbv = soft_body->get_node_biased_velocity(c.index_B) - body->get_biased_linear_velocity() - crbA;
+
+ vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+ real_t jbn_com = (-vbn + c.bias) / (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B));
+ real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
+ c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
+
+ Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
+
+ body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f);
+ soft_body->apply_node_bias_impulse(c.index_B, jb_com);
+ }
+
+ c.active = true;
+ }
+
+ Vector3 crA = body->get_angular_velocity().cross(c.rA);
+ Vector3 dv = soft_body->get_node_velocity(c.index_B) - body->get_linear_velocity() - crA;
+
+ // Normal impulse.
+ real_t vn = dv.dot(c.normal);
+
+ if (Math::abs(vn) > MIN_VELOCITY) {
+ real_t jn = -(c.bounce + vn) * c.mass_normal;
+ real_t jnOld = c.acc_normal_impulse;
+ c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
+
+ Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
+
+ body->apply_impulse(-j, c.rA + body->get_center_of_mass());
+ soft_body->apply_node_impulse(c.index_B, j);
+
+ c.active = true;
+ }
+
+ // Friction impulse.
+ real_t friction = body->get_friction();
+
+ Vector3 lvA = body->get_linear_velocity() + body->get_angular_velocity().cross(c.rA);
+ Vector3 lvB = soft_body->get_node_velocity(c.index_B);
+ Vector3 dtv = lvB - lvA;
+
+ real_t tn = c.normal.dot(dtv);
+
+ // Tangential velocity.
+ Vector3 tv = dtv - c.normal * tn;
+ real_t tvl = tv.length();
+
+ if (tvl > MIN_VELOCITY) {
+ tv /= tvl;
+
+ Vector3 temp1 = body->get_inv_inertia_tensor().xform(c.rA.cross(tv));
+
+ real_t t = -tvl /
+ (body->get_inv_mass() + soft_body->get_node_inv_mass(c.index_B) + tv.dot(temp1.cross(c.rA)));
+
+ Vector3 jt = t * tv;
+
+ Vector3 jtOld = c.acc_tangent_impulse;
+ c.acc_tangent_impulse += jt;
+
+ real_t fi_len = c.acc_tangent_impulse.length();
+ real_t jtMax = c.acc_normal_impulse * friction;
+
+ if (fi_len > CMP_EPSILON && fi_len > jtMax) {
+ c.acc_tangent_impulse *= jtMax / fi_len;
+ }
+
+ jt = c.acc_tangent_impulse - jtOld;
+
+ body->apply_impulse(-jt, c.rA + body->get_center_of_mass());
+ soft_body->apply_node_impulse(c.index_B, jt);
+
+ c.active = true;
+ }
+ }
+}
+
+BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) {
+ body = p_A;
+ soft_body = p_B;
+ body_shape = p_shape_A;
+ space = p_A->get_space();
+ body->add_constraint(this, 0);
+ soft_body->add_constraint(this);
+}
+
+BodySoftBodyPair3DSW::~BodySoftBodyPair3DSW() {
+ body->remove_constraint(this);
+ soft_body->remove_constraint(this);
+}
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
index 4d049eafdc..74dddfa6aa 100644
--- a/servers/physics_3d/body_pair_3d_sw.h
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -28,32 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BODY_PAIR_SW_H
-#define BODY_PAIR_SW_H
+#ifndef BODY_PAIR_3D_SW_H
+#define BODY_PAIR_3D_SW_H
#include "body_3d_sw.h"
#include "constraint_3d_sw.h"
+#include "core/templates/local_vector.h"
+#include "soft_body_3d_sw.h"
-class BodyPair3DSW : public Constraint3DSW {
- enum {
- MAX_CONTACTS = 4
- };
-
- union {
- struct {
- Body3DSW *A;
- Body3DSW *B;
- };
-
- Body3DSW *_arr[2];
- };
-
- int shape_A;
- int shape_B;
-
+class BodyContact3DSW : public Constraint3DSW {
+protected:
struct Contact {
Vector3 position;
Vector3 normal;
+ int index_A, index_B;
Vector3 local_A, local_B;
real_t acc_normal_impulse; // accumulated normal impulse (Pn)
Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
@@ -68,22 +56,45 @@ class BodyPair3DSW : public Constraint3DSW {
Vector3 rA, rB; // Offset in world orientation with respect to center of mass
};
+ Vector3 sep_axis;
+ bool collided;
+
+ Space3DSW *space;
+
+ BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
+ Constraint3DSW(p_body_ptr, p_body_count) {
+ }
+};
+
+class BodyPair3DSW : public BodyContact3DSW {
+ enum {
+ MAX_CONTACTS = 4
+ };
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ int shape_A;
+ int shape_B;
+
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
- Vector3 sep_axis;
Contact contacts[MAX_CONTACTS];
int contact_count;
- bool collided;
- static void _contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
- void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B);
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
void validate_contacts();
bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B);
- Space3DSW *space;
-
public:
bool setup(real_t p_step);
void solve(real_t p_step);
@@ -92,4 +103,26 @@ public:
~BodyPair3DSW();
};
-#endif // BODY_PAIR__SW_H
+class BodySoftBodyPair3DSW : public BodyContact3DSW {
+ Body3DSW *body;
+ SoftBody3DSW *soft_body;
+
+ int body_shape;
+
+ LocalVector<Contact> contacts;
+
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+
+ void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
+
+ void validate_contacts();
+
+public:
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B);
+ ~BodySoftBodyPair3DSW();
+};
+
+#endif // BODY_PAIR_3D_SW_H
diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp
index b06ade5ed3..293a7e6606 100644
--- a/servers/physics_3d/collision_object_3d_sw.cpp
+++ b/servers/physics_3d/collision_object_3d_sw.cpp
@@ -43,7 +43,7 @@ void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform &p_trans
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes();
//_shapes_changed();
@@ -56,7 +56,7 @@ void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) {
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes();
//_shapes_changed();
@@ -68,7 +68,7 @@ void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_tr
shapes.write[p_index].xform = p_transform;
shapes.write[p_index].xform_inv = p_transform.affine_inverse();
if (!pending_shape_update_list.in_list()) {
- PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes();
//_shapes_changed();
@@ -77,7 +77,7 @@ void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_tr
void CollisionObject3DSW::set_shape_as_disabled(int p_idx, bool p_enable) {
shapes.write[p_idx].disabled = p_enable;
if (!pending_shape_update_list.in_list()) {
- PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
}
@@ -106,7 +106,7 @@ void CollisionObject3DSW::remove_shape(int p_index) {
shapes.remove(p_index);
if (!pending_shape_update_list.in_list()) {
- PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes();
//_shapes_changed();
diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h
index 3847b81381..85221b7746 100644
--- a/servers/physics_3d/collision_object_3d_sw.h
+++ b/servers/physics_3d/collision_object_3d_sw.h
@@ -48,7 +48,8 @@ class CollisionObject3DSW : public ShapeOwner3DSW {
public:
enum Type {
TYPE_AREA,
- TYPE_BODY
+ TYPE_BODY,
+ TYPE_SOFT_BODY,
};
private:
@@ -129,8 +130,8 @@ public:
_FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; }
_FORCE_INLINE_ real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; }
- _FORCE_INLINE_ Transform get_transform() const { return transform; }
- _FORCE_INLINE_ Transform get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space3DSW *get_space() const { return space; }
_FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index b8e056f1f4..9d5448dbfa 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -31,7 +31,38 @@
#include "collision_solver_3d_sat.h"
#include "core/math/geometry_3d.h"
-#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.02
+#include "gjk_epa.h"
+
+#define fallback_collision_solver gjk_epa_calculate_penetration
+
+// Cylinder SAT analytic methods and face-circle contact points for cylinder-trimesh and cylinder-box collision are based on ODE colliders.
+
+/*
+ * Cylinder-trimesh and Cylinder-box colliders by Alen Ladavac
+ * Ported to ODE by Nguyen Binh
+ */
+
+/*************************************************************************
+ * *
+ * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
+ * All rights reserved. Email: russ@q12.org Web: www.q12.org *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of EITHER: *
+ * (1) The GNU Lesser General Public License as published by the Free *
+ * Software Foundation; either version 2.1 of the License, or (at *
+ * your option) any later version. The text of the GNU Lesser *
+ * General Public License is included with this library in the *
+ * file LICENSE.TXT. *
+ * (2) The BSD-style license that is included with this library in *
+ * the file LICENSE-BSD.TXT. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
+ * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
+ * *
+ *************************************************************************/
struct _CollectorCallback {
CollisionSolver3DSW::CallbackResult callback;
@@ -43,9 +74,9 @@ struct _CollectorCallback {
_FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
if (swap) {
- callback(p_point_B, p_point_A, userdata);
+ callback(p_point_B, 0, p_point_A, 0, userdata);
} else {
- callback(p_point_A, p_point_B, userdata);
+ callback(p_point_A, 0, p_point_B, 0, userdata);
}
}
};
@@ -82,6 +113,17 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point
p_callback->call(*p_points_A, closest_B);
}
+static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(p_point_count_A != 1);
+ ERR_FAIL_COND(p_point_count_B != 3);
+#endif
+
+ Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A);
+
+ p_callback->call(*p_points_A, closest_B);
+}
+
static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(p_point_count_A != 2);
@@ -128,6 +170,104 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
p_callback->call(closest_A, closest_B);
}
+static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(p_point_count_A != 2);
+ ERR_FAIL_COND(p_point_count_B != 3);
+#endif
+
+ const Vector3 &circle_B_pos = p_points_B[0];
+ Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos;
+ Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos;
+
+ real_t circle_B_radius = circle_B_line_1.length();
+ Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized();
+
+ Plane circle_plane(circle_B_pos, circle_B_normal);
+
+ static const int max_clip = 2;
+ Vector3 contact_points[max_clip];
+ int num_points = 0;
+
+ // Project edge point in circle plane.
+ const Vector3 &edge_A_1 = p_points_A[0];
+ Vector3 proj_point_1 = circle_plane.project(edge_A_1);
+
+ Vector3 dist_vec = proj_point_1 - circle_B_pos;
+ real_t dist_sq = dist_vec.length_squared();
+
+ // Point 1 is inside disk, add as contact point.
+ if (dist_sq <= circle_B_radius * circle_B_radius) {
+ contact_points[num_points] = edge_A_1;
+ ++num_points;
+ }
+
+ const Vector3 &edge_A_2 = p_points_A[1];
+ Vector3 proj_point_2 = circle_plane.project(edge_A_2);
+
+ Vector3 dist_vec_2 = proj_point_2 - circle_B_pos;
+ real_t dist_sq_2 = dist_vec_2.length_squared();
+
+ // Point 2 is inside disk, add as contact point.
+ if (dist_sq_2 <= circle_B_radius * circle_B_radius) {
+ contact_points[num_points] = edge_A_2;
+ ++num_points;
+ }
+
+ if (num_points < 2) {
+ Vector3 line_vec = proj_point_2 - proj_point_1;
+ real_t line_length_sq = line_vec.length_squared();
+
+ // Create a quadratic formula of the form ax^2 + bx + c = 0
+ real_t a, b, c;
+
+ a = line_length_sq;
+ b = 2.0 * dist_vec.dot(line_vec);
+ c = dist_sq - circle_B_radius * circle_B_radius;
+
+ // Solve for t.
+ real_t sqrtterm = b * b - 4.0 * a * c;
+
+ // If the term we intend to square root is less than 0 then the answer won't be real,
+ // so the line doesn't intersect.
+ if (sqrtterm >= 0) {
+ sqrtterm = Math::sqrt(sqrtterm);
+
+ Vector3 edge_dir = edge_A_2 - edge_A_1;
+
+ real_t fraction_1 = (-b - sqrtterm) / (2.0 * a);
+ if ((fraction_1 > 0.0) && (fraction_1 < 1.0)) {
+ Vector3 face_point_1 = edge_A_1 + fraction_1 * edge_dir;
+ ERR_FAIL_COND(num_points >= max_clip);
+ contact_points[num_points] = face_point_1;
+ ++num_points;
+ }
+
+ real_t fraction_2 = (-b + sqrtterm) / (2.0 * a);
+ if ((fraction_2 > 0.0) && (fraction_2 < 1.0) && !Math::is_equal_approx(fraction_1, fraction_2)) {
+ Vector3 face_point_2 = edge_A_1 + fraction_2 * edge_dir;
+ ERR_FAIL_COND(num_points >= max_clip);
+ contact_points[num_points] = face_point_2;
+ ++num_points;
+ }
+ }
+ }
+
+ // Generate contact points.
+ for (int i = 0; i < num_points; i++) {
+ const Vector3 &contact_point_A = contact_points[i];
+
+ real_t d = circle_plane.distance_to(contact_point_A);
+ Vector3 closest_B = contact_point_A - circle_plane.normal * d;
+
+ if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) {
+ continue;
+ }
+
+ p_callback->call(contact_point_A, closest_B);
+ }
+}
+
static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(p_point_count_A < 2);
@@ -217,36 +357,229 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_
}
}
-static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(p_point_count_A < 3);
+ ERR_FAIL_COND(p_point_count_B != 3);
+#endif
+
+ const Vector3 &circle_B_pos = p_points_B[0];
+ Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos;
+ Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos;
+
+ // Clip face with circle segments.
+ static const int circle_segments = 8;
+ Vector3 circle_points[circle_segments];
+
+ real_t angle_delta = 2.0 * Math_PI / circle_segments;
+
+ for (int i = 0; i < circle_segments; ++i) {
+ Vector3 point_pos = circle_B_pos;
+ point_pos += circle_B_line_1 * Math::cos(i * angle_delta);
+ point_pos += circle_B_line_2 * Math::sin(i * angle_delta);
+ circle_points[i] = point_pos;
+ }
+
+ _generate_contacts_face_face(p_points_A, p_point_count_A, circle_points, circle_segments, p_callback);
+
+ // Clip face with circle plane.
+ Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized();
+
+ Plane circle_plane(circle_B_pos, circle_B_normal);
+
+ static const int max_clip = 32;
+ Vector3 contact_points[max_clip];
+ int num_points = 0;
+
+ for (int i = 0; i < p_point_count_A; i++) {
+ int i_n = (i + 1) % p_point_count_A;
+
+ const Vector3 &edge0_A = p_points_A[i];
+ const Vector3 &edge1_A = p_points_A[i_n];
+
+ real_t dist0 = circle_plane.distance_to(edge0_A);
+ real_t dist1 = circle_plane.distance_to(edge1_A);
+
+ // First point in front of plane, generate contact point.
+ if (dist0 * circle_plane.d >= 0) {
+ ERR_FAIL_COND(num_points >= max_clip);
+ contact_points[num_points] = edge0_A;
+ ++num_points;
+ }
+
+ // Points on different sides, generate contact point.
+ if (dist0 * dist1 < 0) {
+ // calculate intersection
+ Vector3 rel = edge1_A - edge0_A;
+ real_t den = circle_plane.normal.dot(rel);
+ real_t dist = -(circle_plane.normal.dot(edge0_A) - circle_plane.d) / den;
+ Vector3 inters = edge0_A + rel * dist;
+
+ ERR_FAIL_COND(num_points >= max_clip);
+ contact_points[num_points] = inters;
+ ++num_points;
+ }
+ }
+
+ // Generate contact points.
+ for (int i = 0; i < num_points; i++) {
+ const Vector3 &contact_point_A = contact_points[i];
+
+ real_t d = circle_plane.distance_to(contact_point_A);
+ Vector3 closest_B = contact_point_A - circle_plane.normal * d;
+
+ if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) {
+ continue;
+ }
+
+ p_callback->call(contact_point_A, closest_B);
+ }
+}
+
+static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(p_point_count_A != 3);
+ ERR_FAIL_COND(p_point_count_B != 3);
+#endif
+
+ const Vector3 &circle_A_pos = p_points_A[0];
+ Vector3 circle_A_line_1 = p_points_A[1] - circle_A_pos;
+ Vector3 circle_A_line_2 = p_points_A[2] - circle_A_pos;
+
+ real_t circle_A_radius = circle_A_line_1.length();
+ Vector3 circle_A_normal = circle_A_line_1.cross(circle_A_line_2).normalized();
+
+ const Vector3 &circle_B_pos = p_points_B[0];
+ Vector3 circle_B_line_1 = p_points_B[1] - circle_B_pos;
+ Vector3 circle_B_line_2 = p_points_B[2] - circle_B_pos;
+
+ real_t circle_B_radius = circle_B_line_1.length();
+ Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized();
+
+ static const int max_clip = 4;
+ Vector3 contact_points[max_clip];
+ int num_points = 0;
+
+ Vector3 centers_diff = circle_B_pos - circle_A_pos;
+ Vector3 norm_proj = circle_A_normal.dot(centers_diff) * circle_A_normal;
+ Vector3 comp_proj = centers_diff - norm_proj;
+ real_t proj_dist = comp_proj.length();
+ if (!Math::is_zero_approx(proj_dist)) {
+ comp_proj /= proj_dist;
+ if ((proj_dist > circle_A_radius - circle_B_radius) && (proj_dist > circle_B_radius - circle_A_radius)) {
+ // Circles are overlapping, use the 2 points of intersection as contacts.
+ real_t radius_a_sqr = circle_A_radius * circle_A_radius;
+ real_t radius_b_sqr = circle_B_radius * circle_B_radius;
+ real_t d_sqr = proj_dist * proj_dist;
+ real_t s = (1.0 + (radius_a_sqr - radius_b_sqr) / d_sqr) * 0.5;
+ real_t h = Math::sqrt(MAX(radius_a_sqr - d_sqr * s * s, 0.0));
+ Vector3 midpoint = circle_A_pos + s * comp_proj * proj_dist;
+ Vector3 h_vec = h * circle_A_normal.cross(comp_proj);
+
+ Vector3 point_A = midpoint + h_vec;
+ contact_points[num_points] = point_A;
+ ++num_points;
+
+ point_A = midpoint - h_vec;
+ contact_points[num_points] = point_A;
+ ++num_points;
+
+ // Add 2 points from circle A and B along the line between the centers.
+ point_A = circle_A_pos + comp_proj * circle_A_radius;
+ contact_points[num_points] = point_A;
+ ++num_points;
+
+ point_A = circle_B_pos - comp_proj * circle_B_radius - norm_proj;
+ contact_points[num_points] = point_A;
+ ++num_points;
+ } // Otherwise one circle is inside the other one, use 3 arbitrary equidistant points.
+ } // Otherwise circles are concentric, use 3 arbitrary equidistant points.
+
+ if (num_points == 0) {
+ // Generate equidistant points.
+ if (circle_A_radius < circle_B_radius) {
+ // Circle A inside circle B.
+ for (int i = 0; i < 3; ++i) {
+ Vector3 circle_A_point = circle_A_pos;
+ circle_A_point += circle_A_line_1 * Math::cos(2.0 * Math_PI * i / 3.0);
+ circle_A_point += circle_A_line_2 * Math::sin(2.0 * Math_PI * i / 3.0);
+
+ contact_points[num_points] = circle_A_point;
+ ++num_points;
+ }
+ } else {
+ // Circle B inside circle A.
+ for (int i = 0; i < 3; ++i) {
+ Vector3 circle_B_point = circle_B_pos;
+ circle_B_point += circle_B_line_1 * Math::cos(2.0 * Math_PI * i / 3.0);
+ circle_B_point += circle_B_line_2 * Math::sin(2.0 * Math_PI * i / 3.0);
+
+ Vector3 circle_A_point = circle_B_point - norm_proj;
+
+ contact_points[num_points] = circle_A_point;
+ ++num_points;
+ }
+ }
+ }
+
+ Plane circle_B_plane(circle_B_pos, circle_B_normal);
+
+ // Generate contact points.
+ for (int i = 0; i < num_points; i++) {
+ const Vector3 &contact_point_A = contact_points[i];
+
+ real_t d = circle_B_plane.distance_to(contact_point_A);
+ Vector3 closest_B = contact_point_A - circle_B_plane.normal * d;
+
+ if (p_callback->normal.dot(contact_point_A) >= p_callback->normal.dot(closest_B)) {
+ continue;
+ }
+
+ p_callback->call(contact_point_A, closest_B);
+ }
+}
+
+static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, Shape3DSW::FeatureType p_feature_type_A, const Vector3 *p_points_B, int p_point_count_B, Shape3DSW::FeatureType p_feature_type_B, _CollectorCallback *p_callback) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(p_point_count_A < 1);
ERR_FAIL_COND(p_point_count_B < 1);
#endif
- static const GenerateContactsFunc generate_contacts_func_table[3][3] = {
+ static const GenerateContactsFunc generate_contacts_func_table[4][4] = {
{
_generate_contacts_point_point,
_generate_contacts_point_edge,
_generate_contacts_point_face,
+ _generate_contacts_point_circle,
},
{
nullptr,
_generate_contacts_edge_edge,
_generate_contacts_face_face,
+ _generate_contacts_edge_circle,
},
{
nullptr,
nullptr,
_generate_contacts_face_face,
- }
+ _generate_contacts_face_circle,
+ },
+ {
+ nullptr,
+ nullptr,
+ nullptr,
+ _generate_contacts_circle_circle,
+ },
};
int pointcount_B;
int pointcount_A;
const Vector3 *points_A;
const Vector3 *points_B;
+ int version_A;
+ int version_B;
- if (p_point_count_A > p_point_count_B) {
+ if (p_feature_type_A > p_feature_type_B) {
//swap
p_callback->swap = !p_callback->swap;
p_callback->normal = -p_callback->normal;
@@ -255,16 +588,17 @@ static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_po
pointcount_A = p_point_count_B;
points_A = p_points_B;
points_B = p_points_A;
+ version_A = p_feature_type_B;
+ version_B = p_feature_type_A;
} else {
pointcount_B = p_point_count_B;
pointcount_A = p_point_count_A;
points_A = p_points_A;
points_B = p_points_B;
+ version_A = p_feature_type_A;
+ version_B = p_feature_type_B;
}
- int version_A = (pointcount_A > 3 ? 3 : pointcount_A) - 1;
- int version_B = (pointcount_B > 3 ? 3 : pointcount_B) - 1;
-
GenerateContactsFunc contacts_func = generate_contacts_func_table[version_A][version_B];
ERR_FAIL_COND(!contacts_func);
contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_callback);
@@ -292,7 +626,7 @@ public:
}
}
- _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
+ _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) {
Vector3 axis = p_axis;
if (Math::abs(axis.x) < CMP_EPSILON &&
@@ -328,7 +662,12 @@ public:
//use the smallest depth
if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0
- min_B = -min_B;
+ if (p_directional) {
+ min_B = max_B;
+ axis = -axis;
+ } else {
+ min_B = -min_B;
+ }
}
if (max_B < min_B) {
@@ -346,6 +685,17 @@ public:
return true;
}
+ static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata;
+ Vector3 axis = (p_point_B - p_point_A);
+ real_t depth = axis.length();
+
+ // Filter out bogus directions with a treshold and re-testing axis.
+ if (separator->best_depth - depth > 0.001) {
+ separator->test_axis(axis / depth);
+ }
+ }
+
_FORCE_INLINE_ void generate_contacts() {
// nothing to do, don't generate
if (best_axis == Vector3(0.0, 0.0, 0.0)) {
@@ -365,7 +715,8 @@ public:
Vector3 supports_A[max_supports];
int support_count_A;
- shape_A->get_supports(transform_A->basis.xform_inv(-best_axis).normalized(), max_supports, supports_A, support_count_A);
+ Shape3DSW::FeatureType support_type_A;
+ shape_A->get_supports(transform_A->basis.xform_inv(-best_axis).normalized(), max_supports, supports_A, support_count_A, support_type_A);
for (int i = 0; i < support_count_A; i++) {
supports_A[i] = transform_A->xform(supports_A[i]);
}
@@ -378,7 +729,8 @@ public:
Vector3 supports_B[max_supports];
int support_count_B;
- shape_B->get_supports(transform_B->basis.xform_inv(best_axis).normalized(), max_supports, supports_B, support_count_B);
+ Shape3DSW::FeatureType support_type_B;
+ shape_B->get_supports(transform_B->basis.xform_inv(best_axis).normalized(), max_supports, supports_B, support_count_B, support_type_B);
for (int i = 0; i < support_count_B; i++) {
supports_B[i] = transform_B->xform(supports_B[i]);
}
@@ -393,7 +745,7 @@ public:
if (callback->prev_axis) {
*callback->prev_axis = best_axis;
}
- _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback);
+ _generate_contacts_from_supports(supports_A, support_count_A, support_type_A, supports_B, support_count_B, support_type_B, callback);
callback->collided = true;
}
@@ -498,7 +850,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t
//capsule sphere 1, sphere
- Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis;
@@ -529,6 +881,61 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t
template <bool withMargin>
static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a);
+ const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, CylinderShape3DSW, withMargin> separator(sphere_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Cylinder B end caps.
+ Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1).normalized();
+ if (!separator.test_axis(cylinder_B_axis)) {
+ return;
+ }
+
+ Vector3 cylinder_diff = p_transform_b.origin - p_transform_a.origin;
+
+ // Cylinder B lateral surface.
+ if (!separator.test_axis(cylinder_B_axis.cross(cylinder_diff).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ // Closest point to cylinder caps.
+ const Vector3 &sphere_center = p_transform_a.origin;
+ Vector3 cyl_axis = p_transform_b.basis.get_axis(1);
+ Vector3 cap_axis = p_transform_b.basis.get_axis(0);
+ real_t height_scale = cyl_axis.length();
+ real_t cap_dist = cylinder_B->get_height() * 0.5 * height_scale;
+ cyl_axis /= height_scale;
+ real_t radius_scale = cap_axis.length();
+ real_t cap_radius = cylinder_B->get_radius() * radius_scale;
+
+ for (int i = 0; i < 2; i++) {
+ Vector3 cap_dir = ((i == 0) ? cyl_axis : -cyl_axis);
+ Vector3 cap_pos = p_transform_b.origin + cap_dir * cap_dist;
+
+ Vector3 closest_point;
+
+ Vector3 diff = sphere_center - cap_pos;
+ Vector3 proj = diff - cap_dir.dot(diff) * cap_dir;
+
+ real_t proj_len = proj.length();
+ if (Math::is_zero_approx(proj_len)) {
+ // Point is equidistant to all circle points.
+ continue;
+ }
+
+ closest_point = cap_pos + (cap_radius / proj_len) * proj;
+
+ if (!separator.test_axis((closest_point - sphere_center).normalized())) {
+ return;
+ }
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
@@ -604,23 +1011,31 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// edges and points of B
for (int i = 0; i < 3; i++) {
Vector3 n1 = vertex[i] - p_transform_a.origin;
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
Vector3 axis = n1.cross(n2).cross(n2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -739,14 +1154,14 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
// faces of A
for (int i = 0; i < 3; i++) {
- Vector3 axis = p_transform_a.basis.get_axis(i);
+ Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
if (!separator.test_axis(axis)) {
return;
}
}
- Vector3 cyl_axis = p_transform_b.basis.get_axis(2).normalized();
+ Vector3 cyl_axis = p_transform_b.basis.get_axis(1).normalized();
// edges of A, capsule cylinder
@@ -791,7 +1206,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
// capsule balls, edges of A
for (int i = 0; i < 2; i++) {
- Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis);
@@ -826,6 +1241,115 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
template <bool withMargin>
static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a);
+ const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
+
+ SeparatorAxisTest<BoxShape3DSW, CylinderShape3DSW, withMargin> separator(box_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Faces of A.
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
+
+ if (!separator.test_axis(axis)) {
+ return;
+ }
+ }
+
+ Vector3 cyl_axis = p_transform_b.basis.get_axis(1).normalized();
+
+ // Cylinder end caps.
+ {
+ if (!separator.test_axis(cyl_axis)) {
+ return;
+ }
+ }
+
+ // Edges of A, cylinder lateral surface.
+ for (int i = 0; i < 3; i++) {
+ Vector3 box_axis = p_transform_a.basis.get_axis(i);
+ Vector3 axis = box_axis.cross(cyl_axis);
+ if (Math::is_zero_approx(axis.length_squared())) {
+ continue;
+ }
+
+ if (!separator.test_axis(axis.normalized())) {
+ return;
+ }
+ }
+
+ // Gather points of A.
+ Vector3 vertices_A[8];
+ Vector3 box_extent = box_A->get_half_extents();
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ Vector3 extent = box_extent;
+ extent.x *= (i * 2 - 1);
+ extent.y *= (j * 2 - 1);
+ extent.z *= (k * 2 - 1);
+ Vector3 &point = vertices_A[i * 2 * 2 + j * 2 + k];
+ point = p_transform_a.origin;
+ for (int l = 0; l < 3; l++) {
+ point += p_transform_a.basis.get_axis(l) * extent[l];
+ }
+ }
+ }
+ }
+
+ // Points of A, cylinder lateral surface.
+ for (int i = 0; i < 8; i++) {
+ const Vector3 &point = vertices_A[i];
+ Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+
+ if (!separator.test_axis(axis)) {
+ return;
+ }
+ }
+
+ // Edges of A, cylinder end caps rim.
+ int edges_start_A[12] = { 0, 2, 4, 6, 0, 1, 4, 5, 0, 1, 2, 3 };
+ int edges_end_A[12] = { 1, 3, 5, 7, 2, 3, 6, 7, 4, 5, 6, 7 };
+
+ Vector3 cap_axis = cyl_axis * (cylinder_B->get_height() * 0.5);
+
+ for (int i = 0; i < 2; i++) {
+ Vector3 cap_pos = p_transform_b.origin + ((i == 0) ? cap_axis : -cap_axis);
+
+ for (int e = 0; e < 12; e++) {
+ const Vector3 &edge_start = vertices_A[edges_start_A[e]];
+ const Vector3 &edge_end = vertices_A[edges_end_A[e]];
+
+ Vector3 edge_dir = (edge_end - edge_start);
+ edge_dir.normalize();
+
+ real_t edge_dot = edge_dir.dot(cyl_axis);
+ if (Math::is_zero_approx(edge_dot)) {
+ // Edge is perpendicular to cylinder axis.
+ continue;
+ }
+
+ // Calculate intersection between edge and circle plane.
+ Vector3 edge_diff = cap_pos - edge_start;
+ real_t diff_dot = edge_diff.dot(cyl_axis);
+ Vector3 intersection = edge_start + edge_dir * diff_dot / edge_dot;
+
+ // Calculate tangent that touches intersection.
+ Vector3 tangent = (cap_pos - intersection).cross(cyl_axis);
+
+ // Axis is orthogonal both to tangent and edge direction.
+ Vector3 axis = tangent.cross(edge_dir);
+
+ if (!separator.test_axis(axis.normalized())) {
+ return;
+ }
+ }
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
@@ -956,15 +1480,20 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// faces of A
for (int i = 0; i < 3; i++) {
Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -975,9 +1504,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 e = vertex[i] - vertex[(i + 1) % 3];
for (int j = 0; j < 3; j++) {
- Vector3 axis = p_transform_a.basis.get_axis(j);
+ Vector3 axis = e.cross(p_transform_a.basis.get_axis(j)).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(e.cross(axis).normalized())) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -997,8 +1529,11 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
(cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
Vector3 axis_ab = support_a - vertex[v];
+ if (axis_ab.dot(normal) < 0.0) {
+ axis_ab *= -1.0;
+ }
- if (!separator.test_axis(axis_ab.normalized())) {
+ if (!separator.test_axis(axis_ab.normalized(), !face_B->backface_collision)) {
return;
}
@@ -1008,7 +1543,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
//a ->b
Vector3 axis_a = p_transform_a.basis.get_axis(i);
- if (!separator.test_axis(axis_ab.cross(axis_a).cross(axis_a).normalized())) {
+ Vector3 axis = axis_ab.cross(axis_a).cross(axis_a).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1033,7 +1573,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
Vector3 n = (p2 - p1);
- if (!separator.test_axis((point - p2).cross(n).cross(n).normalized())) {
+ Vector3 axis = (point - p2).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1058,8 +1603,8 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_
// some values
- Vector3 capsule_A_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
- Vector3 capsule_B_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+ Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_B_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis;
Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis;
@@ -1111,6 +1656,64 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_
template <bool withMargin>
static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a);
+ const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Cylinder B end caps.
+ Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1).normalized();
+ if (!separator.test_axis(cylinder_B_axis)) {
+ return;
+ }
+
+ // Cylinder edge against capsule balls.
+
+ Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1);
+
+ Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5);
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_1).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_2).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ // Cylinder edge against capsule edge.
+
+ Vector3 center_diff = p_transform_b.origin - p_transform_a.origin;
+
+ if (!separator.test_axis(capsule_A_axis.cross(center_diff).cross(capsule_A_axis).normalized())) {
+ return;
+ }
+
+ if (!separator.test_axis(cylinder_B_axis.cross(center_diff).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ real_t proj = capsule_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(capsule_A_axis);
+ if (Math::is_zero_approx(proj)) {
+ // Parallel capsule and cylinder axes, handle with specific axes only.
+ // Note: GJKEPA with no margin can lead to degenerate cases in this situation.
+ separator.generate_contacts();
+ return;
+ }
+
+ CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
+
+ // Fallback to generic algorithm to find the best separating axis.
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
+ return;
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
@@ -1146,7 +1749,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
for (int i = 0; i < edge_count; i++) {
// cylinder
Vector3 edge_axis = p_transform_b.basis.xform(vertices[edges[i].a]) - p_transform_b.basis.xform(vertices[edges[i].b]);
- Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(2)).normalized();
+ Vector3 axis = edge_axis.cross(p_transform_a.basis.get_axis(1)).normalized();
if (!separator.test_axis(axis)) {
return;
@@ -1158,7 +1761,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
for (int i = 0; i < 2; i++) {
// edges of B, capsule cylinder
- Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
Vector3 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);
@@ -1190,24 +1793,35 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
// edges of B, capsule cylinder
- Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (capsule_A->get_height() * 0.5);
+ Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
for (int i = 0; i < 3; i++) {
// edge-cylinder
Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3];
+
Vector3 axis = edge_axis.cross(capsule_axis).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
- if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized())) {
+ Vector3 dir_axis = (p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized();
+ if (dir_axis.dot(normal) < 0.0) {
+ dir_axis *= -1.0;
+ }
+
+ if (!separator.test_axis(dir_axis, !face_B->backface_collision)) {
return;
}
@@ -1216,16 +1830,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
Vector3 n1 = sphere_pos - vertex[i];
+ if (n1.dot(normal) < 0.0) {
+ n1 *= -1.0;
+ }
- if (!separator.test_axis(n1.normalized())) {
+ if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
return;
}
Vector3 n2 = edge_axis;
axis = n1.cross(n2).cross(n2);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis.normalized())) {
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
return;
}
}
@@ -1236,14 +1856,178 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
template <bool withMargin>
static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
+ const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin> separator(cylinder_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ Vector3 cylinder_A_axis = p_transform_a.basis.get_axis(1);
+ Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1);
+
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ // Cylinder A end caps.
+ if (!separator.test_axis(cylinder_A_axis.normalized())) {
+ return;
+ }
+
+ // Cylinder B end caps.
+ if (!separator.test_axis(cylinder_A_axis.normalized())) {
+ return;
+ }
+
+ Vector3 cylinder_diff = p_transform_b.origin - p_transform_a.origin;
+
+ // Cylinder A lateral surface.
+ if (!separator.test_axis(cylinder_A_axis.cross(cylinder_diff).cross(cylinder_A_axis).normalized())) {
+ return;
+ }
+
+ // Cylinder B lateral surface.
+ if (!separator.test_axis(cylinder_B_axis.cross(cylinder_diff).cross(cylinder_B_axis).normalized())) {
+ return;
+ }
+
+ real_t proj = cylinder_A_axis.cross(cylinder_B_axis).cross(cylinder_B_axis).dot(cylinder_A_axis);
+ if (Math::is_zero_approx(proj)) {
+ // Parallel cylinders, handle with specific axes only.
+ // Note: GJKEPA with no margin can lead to degenerate cases in this situation.
+ separator.generate_contacts();
+ return;
+ }
+
+ CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points;
+
+ // Fallback to generic algorithm to find the best separating axis.
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
+ return;
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
+ const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(cylinder_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin>::test_contact_points;
+
+ // Fallback to generic algorithm to find the best separating axis.
+ if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) {
+ return;
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+ const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
+ const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CylinderShape3DSW, FaceShape3DSW, withMargin> separator(cylinder_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis()) {
+ return;
+ }
+
+ Vector3 vertex[3] = {
+ p_transform_b.xform(face_B->vertex[0]),
+ p_transform_b.xform(face_B->vertex[1]),
+ p_transform_b.xform(face_B->vertex[2]),
+ };
+
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ // Face B normal.
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
+ return;
+ }
+
+ Vector3 cyl_axis = p_transform_a.basis.get_axis(1).normalized();
+ if (cyl_axis.dot(normal) < 0.0) {
+ cyl_axis *= -1.0;
+ }
+
+ // Cylinder end caps.
+ if (!separator.test_axis(cyl_axis, !face_B->backface_collision)) {
+ return;
+ }
+
+ // Edges of B, cylinder lateral surface.
+ for (int i = 0; i < 3; i++) {
+ Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3];
+ Vector3 axis = edge_axis.cross(cyl_axis);
+ if (Math::is_zero_approx(axis.length_squared())) {
+ continue;
+ }
+
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
+ return;
+ }
+ }
+
+ // Points of B, cylinder lateral surface.
+ for (int i = 0; i < 3; i++) {
+ const Vector3 &point = vertex[i];
+ Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
+ return;
+ }
+ }
+
+ // Edges of B, cylinder end caps rim.
+ Vector3 cap_axis = cyl_axis * (cylinder_A->get_height() * 0.5);
+
+ for (int i = 0; i < 2; i++) {
+ Vector3 cap_pos = p_transform_a.origin + ((i == 0) ? cap_axis : -cap_axis);
+
+ for (int j = 0; j < 3; j++) {
+ const Vector3 &edge_start = vertex[j];
+ const Vector3 &edge_end = vertex[(j + 1) % 3];
+ Vector3 edge_dir = edge_end - edge_start;
+ edge_dir.normalize();
+
+ real_t edge_dot = edge_dir.dot(cyl_axis);
+ if (Math::is_zero_approx(edge_dot)) {
+ // Edge is perpendicular to cylinder axis.
+ continue;
+ }
+
+ // Calculate intersection between edge and circle plane.
+ Vector3 edge_diff = cap_pos - edge_start;
+ real_t diff_dot = edge_diff.dot(cyl_axis);
+ Vector3 intersection = edge_start + edge_dir * diff_dot / edge_dot;
+
+ // Calculate tangent that touches intersection.
+ Vector3 tangent = (cap_pos - intersection).cross(cyl_axis);
+
+ // Axis is orthogonal both to tangent and edge direction.
+ Vector3 axis = tangent.cross(edge_dir);
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
+ return;
+ }
+ }
+ }
+
+ separator.generate_contacts();
}
template <bool withMargin>
@@ -1377,7 +2161,9 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
p_transform_b.xform(face_B->vertex[2]),
};
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+ if (!separator.test_axis(normal, !face_B->backface_collision)) {
return;
}
@@ -1385,8 +2171,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int i = 0; i < face_count; i++) {
//Vector3 axis = p_transform_a.xform( faces[i].plane ).normal;
Vector3 axis = p_transform_a.basis.xform(faces[i].plane.normal).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1399,8 +2188,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
Vector3 axis = e1.cross(e2).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
- if (!separator.test_axis(axis)) {
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1412,7 +2204,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
Vector3 va = p_transform_a.xform(vertices[i]);
for (int j = 0; j < 3; j++) {
- if (!separator.test_axis((va - vertex[j]).normalized())) {
+ Vector3 axis = (va - vertex[j]).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1427,7 +2224,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < 3; j++) {
Vector3 e3 = vertex[j];
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
@@ -1441,7 +2243,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
for (int j = 0; j < vertex_count; j++) {
Vector3 e3 = p_transform_a.xform(vertices[j]);
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+ Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+ if (axis.dot(normal) < 0.0) {
+ axis *= -1.0;
+ }
+
+ if (!separator.test_axis(axis, !face_B->backface_collision)) {
return;
}
}
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index 1150696b84..f655c4626c 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -30,6 +30,7 @@
#include "collision_solver_3d_sw.h"
#include "collision_solver_3d_sat.h"
+#include "soft_body_3d_sw.h"
#include "gjk_epa.h"
@@ -46,8 +47,24 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
static const int max_supports = 16;
Vector3 supports[max_supports];
int support_count;
-
- p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count);
+ Shape3DSW::FeatureType support_type;
+ p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
+
+ if (support_type == Shape3DSW::FEATURE_CIRCLE) {
+ ERR_FAIL_COND_V(support_count != 3, false);
+
+ Vector3 circle_pos = supports[0];
+ Vector3 circle_axis_1 = supports[1] - circle_pos;
+ Vector3 circle_axis_2 = supports[2] - circle_pos;
+
+ // Use 3 equidistant points on the circle.
+ for (int i = 0; i < 3; ++i) {
+ Vector3 vertex_pos = circle_pos;
+ vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0);
+ vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0);
+ supports[i] = vertex_pos;
+ }
+ }
bool found = false;
@@ -62,9 +79,9 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(supports[i], support_A, p_userdata);
+ p_result_callback(supports[i], 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, supports[i], p_userdata);
+ p_result_callback(support_A, 0, supports[i], 0, p_userdata);
}
}
}
@@ -97,14 +114,148 @@ bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(support_B, support_A, p_userdata);
+ p_result_callback(support_B, 0, support_A, 0, p_userdata);
} else {
- p_result_callback(support_A, support_B, p_userdata);
+ p_result_callback(support_A, 0, support_B, 0, p_userdata);
}
}
return true;
}
+struct _SoftBodyContactCollisionInfo {
+ int node_index = 0;
+ CollisionSolver3DSW::CallbackResult result_callback = nullptr;
+ void *userdata = nullptr;
+ bool swap_result = false;
+ int contact_count = 0;
+};
+
+void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+ _SoftBodyContactCollisionInfo &cinfo = *(_SoftBodyContactCollisionInfo *)(p_userdata);
+
+ ++cinfo.contact_count;
+
+ if (cinfo.swap_result) {
+ cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
+ } else {
+ cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata);
+ }
+}
+
+struct _SoftBodyQueryInfo {
+ SoftBody3DSW *soft_body = nullptr;
+ const Shape3DSW *shape_A = nullptr;
+ const Shape3DSW *shape_B = nullptr;
+ Transform transform_A;
+ Transform node_transform;
+ _SoftBodyContactCollisionInfo contact_info;
+#ifdef DEBUG_ENABLED
+ int node_query_count = 0;
+ int convex_query_count = 0;
+#endif
+};
+
+bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *p_userdata) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index);
+
+ Transform transform_B;
+ transform_B.origin = query_cinfo.node_transform.xform(node_position);
+
+ query_cinfo.contact_info.node_index = p_node_index;
+ solve_static(query_cinfo.shape_A, query_cinfo.transform_A, query_cinfo.shape_B, transform_B, soft_body_contact_callback, &query_cinfo.contact_info);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.node_query_count;
+#endif
+
+ // Continue with the query.
+ return false;
+}
+
+void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+ _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata);
+
+ query_cinfo.shape_A = p_convex;
+
+ // Calculate AABB for internal soft body query (in world space).
+ AABB shape_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis;
+ axis[i] = 1.0;
+
+ real_t smin, smax;
+ p_convex->project_range(axis, query_cinfo.transform_A, smin, smax);
+
+ shape_aabb.position[i] = smin;
+ shape_aabb.size[i] = smax - smin;
+ }
+
+ shape_aabb.grow_by(query_cinfo.soft_body->get_collision_margin());
+
+ query_cinfo.soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+
+#ifdef DEBUG_ENABLED
+ ++query_cinfo.convex_query_count;
+#endif
+}
+
+bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+ const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B);
+
+ SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body();
+ const Transform &world_to_local = soft_body->get_inv_transform();
+
+ const real_t collision_margin = soft_body->get_collision_margin();
+
+ SphereShape3DSW sphere_shape;
+ sphere_shape.set_data(collision_margin);
+
+ _SoftBodyQueryInfo query_cinfo;
+ query_cinfo.contact_info.result_callback = p_result_callback;
+ query_cinfo.contact_info.userdata = p_userdata;
+ query_cinfo.contact_info.swap_result = p_swap_result;
+ query_cinfo.soft_body = soft_body;
+ query_cinfo.node_transform = p_transform_B * world_to_local;
+ query_cinfo.shape_A = p_shape_A;
+ query_cinfo.transform_A = p_transform_A;
+ query_cinfo.shape_B = &sphere_shape;
+
+ if (p_shape_A->is_concave()) {
+ // In case of concave shape, query convex shapes first.
+ const ConcaveShape3DSW *concave_shape_A = static_cast<const ConcaveShape3DSW *>(p_shape_A);
+
+ AABB soft_body_aabb = soft_body->get_bounds();
+ soft_body_aabb.grow_by(collision_margin);
+
+ // Calculate AABB for internal concave shape query (in local space).
+ AABB local_aabb;
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis(p_transform_A.basis.get_axis(i));
+ real_t axis_scale = 1.0 / axis.length();
+
+ real_t smin = soft_body_aabb.position[i];
+ real_t smax = smin + soft_body_aabb.size[i];
+
+ smin *= axis_scale;
+ smax *= axis_scale;
+
+ local_aabb.position[i] = smin;
+ local_aabb.size[i] = smax - smin;
+ }
+
+ concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo);
+ } else {
+ AABB shape_aabb = p_transform_A.xform(p_shape_A->get_aabb());
+ shape_aabb.grow_by(collision_margin);
+
+ soft_body->query_aabb(shape_aabb, soft_body_query_callback, &query_cinfo);
+ }
+
+ return (query_cinfo.contact_info.contact_count > 0);
+}
+
struct _ConcaveCollisionInfo {
const Transform *transform_A;
const Shape3DSW *shape_A;
@@ -199,6 +350,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
if (type_B == PhysicsServer3D::SHAPE_RAY) {
return false;
}
+ if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ return false;
+ }
if (swap) {
return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
@@ -217,6 +371,18 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
return solve_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
+ } else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
+ // Soft Body / Soft Body not supported.
+ return false;
+ }
+
+ if (swap) {
+ return solve_soft_body(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ } else {
+ return solve_soft_body(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ }
+
} else if (concave_B) {
if (concave_A) {
return false;
@@ -265,8 +431,25 @@ bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const
static const int max_supports = 16;
Vector3 supports[max_supports];
int support_count;
+ Shape3DSW::FeatureType support_type;
+
+ p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
- p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count);
+ if (support_type == Shape3DSW::FEATURE_CIRCLE) {
+ ERR_FAIL_COND_V(support_count != 3, false);
+
+ Vector3 circle_pos = supports[0];
+ Vector3 circle_axis_1 = supports[1] - circle_pos;
+ Vector3 circle_axis_2 = supports[2] - circle_pos;
+
+ // Use 3 equidistant points on the circle.
+ for (int i = 0; i < 3; ++i) {
+ Vector3 vertex_pos = circle_pos;
+ vertex_pos += circle_axis_1 * Math::cos(2.0 * Math_PI * i / 3.0);
+ vertex_pos += circle_axis_2 * Math::sin(2.0 * Math_PI * i / 3.0);
+ supports[i] = vertex_pos;
+ }
+ }
bool collided = false;
Vector3 closest;
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
index 81d87e9773..34ac2c6d3f 100644
--- a/servers/physics_3d/collision_solver_3d_sw.h
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -35,12 +35,16 @@
class CollisionSolver3DSW {
public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
private:
+ static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata);
+ static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+ static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
static void concave_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
static void concave_distance_callback(void *p_userdata, Shape3DSW *p_convex);
static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h
index 2571335c43..16a31e167d 100644
--- a/servers/physics_3d/constraint_3d_sw.h
+++ b/servers/physics_3d/constraint_3d_sw.h
@@ -37,8 +37,6 @@ class Constraint3DSW {
Body3DSW **_body_ptr;
int _body_count;
uint64_t island_step;
- Constraint3DSW *island_next;
- Constraint3DSW *island_list_next;
int priority;
bool disabled_collisions_between_bodies;
@@ -60,12 +58,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Constraint3DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Constraint3DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Constraint3DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Constraint3DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index dafd2feb8b..1a8c7f704f 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -64,7 +64,7 @@ GJK-EPA collision solver by Nathanael Presson, 2008
/* GJK */
#define GJK_MAX_ITERATIONS 128
-#define GJK_ACCURARY ((real_t)0.0001)
+#define GJK_ACCURACY ((real_t)0.0001)
#define GJK_MIN_DISTANCE ((real_t)0.0001)
#define GJK_DUPLICATED_EPS ((real_t)0.0001)
#define GJK_SIMPLEX2_EPS ((real_t)0.0)
@@ -72,10 +72,13 @@ GJK-EPA collision solver by Nathanael Presson, 2008
#define GJK_SIMPLEX4_EPS ((real_t)0.0)
/* EPA */
-#define EPA_MAX_VERTICES 64
+#define EPA_MAX_VERTICES 128
#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
#define EPA_MAX_ITERATIONS 255
-#define EPA_ACCURACY ((real_t)0.0001)
+// -- GODOT start --
+//#define EPA_ACCURACY ((real_t)0.0001)
+#define EPA_ACCURACY ((real_t)0.00001)
+// -- GODOT end --
#define EPA_FALLBACK (10*EPA_ACCURACY)
#define EPA_PLANE_EPS ((real_t)0.00001)
#define EPA_INSIDE_EPS ((real_t)0.01)
@@ -107,26 +110,60 @@ struct MinkowskiDiff {
Transform transform_A;
Transform transform_B;
+ real_t margin_A = 0.0;
+ real_t margin_B = 0.0;
+
+ Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t);
+
+ void Initialize(const Shape3DSW* shape0, const Transform& wtrs0, const real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, const real_t margin1) {
+ m_shapes[0] = shape0;
+ m_shapes[1] = shape1;
+ transform_A = wtrs0;
+ transform_B = wtrs1;
+ margin_A = margin0;
+ margin_B = margin1;
+
+ if ((margin0 > 0.0) || (margin1 > 0.0)) {
+ get_support = get_support_with_margin;
+ } else {
+ get_support = get_support_without_margin;
+ }
+ }
+
+ static Vector3 get_support_without_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ return p_shape->get_support(p_dir.normalized());
+ }
+
+ static Vector3 get_support_with_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) {
+ Vector3 local_dir_norm = p_dir;
+ if (local_dir_norm.length_squared() < CMP_EPSILON2) {
+ local_dir_norm = Vector3(-1.0, -1.0, -1.0);
+ }
+ local_dir_norm.normalize();
+
+ return p_shape->get_support(local_dir_norm) + p_margin * local_dir_norm;
+ }
+
// i wonder how this could be sped up... if it can
- _FORCE_INLINE_ Vector3 Support0 ( const Vector3& d ) const {
- return transform_A.xform( m_shapes[0]->get_support( transform_A.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support0(const Vector3& d) const {
+ return transform_A.xform(get_support(m_shapes[0], transform_A.basis.xform_inv(d), margin_A));
}
- _FORCE_INLINE_ Vector3 Support1 ( const Vector3& d ) const {
- return transform_B.xform( m_shapes[1]->get_support( transform_B.basis.xform_inv(d).normalized() ) );
+ _FORCE_INLINE_ Vector3 Support1(const Vector3& d) const {
+ return transform_B.xform(get_support(m_shapes[1], transform_B.basis.xform_inv(d), margin_B));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d ) const {
- return ( Support0 ( d )-Support1 ( -d ) );
+ _FORCE_INLINE_ Vector3 Support (const Vector3& d) const {
+ return (Support0(d) - Support1(-d));
}
- _FORCE_INLINE_ Vector3 Support ( const Vector3& d,U index ) const
- {
- if ( index ) {
- return ( Support1 ( d ) );
+ _FORCE_INLINE_ Vector3 Support(const Vector3& d, U index) const {
+ if (index) {
+ return Support1(d);
} else {
- return ( Support0 ( d ) );
-}
+ return Support0(d);
+ }
}
};
@@ -237,7 +274,7 @@ struct GJK
/* Check for termination */
const real_t omega=vec3_dot(m_ray,w)/rl;
alpha=MAX(omega,alpha);
- if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
+ if(((rl-alpha)-(GJK_ACCURACY*rl))<=0)
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
@@ -466,7 +503,7 @@ struct GJK
if(ng&&(Math::abs(vl)>GJK_SIMPLEX4_EPS))
{
real_t mindist=-1;
- real_t subw[3];
+ real_t subw[3] = {0.f, 0.f, 0.f};
U subm=0;
for(U i=0;i<3;++i)
{
@@ -512,7 +549,6 @@ struct GJK
{
Vector3 n;
real_t d;
- real_t p;
sSV* c[3];
sFace* f[3];
sFace* l[2];
@@ -661,8 +697,7 @@ struct GJK
remove(m_hull,best);
append(m_stock,best);
best=findbest();
- if(best->p>=outer.p) { outer=*best;
-}
+ outer=*best;
} else { m_status=eStatus::InvalidHull;break; }
} else { m_status=eStatus::AccuraryReached;break; }
} else { m_status=eStatus::OutOfVertices;break; }
@@ -688,24 +723,54 @@ struct GJK
}
}
/* Fallback */
- m_status = eStatus::FallBack;
- m_normal = -guess;
- const real_t nl=m_normal.length();
- if(nl>0) {
- m_normal = m_normal/nl;
+ m_status = eStatus::FallBack;
+ m_normal = -guess;
+ const real_t nl = m_normal.length();
+ if (nl > 0) {
+ m_normal = m_normal/nl;
} else {
- m_normal = Vector3(1,0,0);
-}
+ m_normal = Vector3(1,0,0);
+ }
m_depth = 0;
m_result.rank=1;
m_result.c[0]=simplex.c[0];
m_result.p[0]=1;
return(m_status);
}
+
+ bool getedgedist(sFace* face, sSV* a, sSV* b, real_t& dist)
+ {
+ const Vector3 ba = b->w - a->w;
+ const Vector3 n_ab = vec3_cross(ba, face->n); // Outward facing edge normal direction, on triangle plane
+ const real_t a_dot_nab = vec3_dot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required
+
+ if (a_dot_nab < 0) {
+ // Outside of edge a->b
+ const real_t ba_l2 = ba.length_squared();
+ const real_t a_dot_ba = vec3_dot(a->w, ba);
+ const real_t b_dot_ba = vec3_dot(b->w, ba);
+
+ if (a_dot_ba > 0) {
+ // Pick distance vertex a
+ dist = a->w.length();
+ } else if (b_dot_ba < 0) {
+ // Pick distance vertex b
+ dist = b->w.length();
+ } else {
+ // Pick distance to edge a->b
+ const real_t a_dot_b = vec3_dot(a->w, b->w);
+ dist = Math::sqrt(MAX((a->w.length_squared() * b->w.length_squared() - a_dot_b * a_dot_b) / ba_l2, 0.0));
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)
{
- if(m_stock.root)
- {
+ if (m_stock.root) {
sFace* face=m_stock.root;
remove(m_stock,face);
append(m_hull,face);
@@ -716,23 +781,23 @@ struct GJK
face->n = vec3_cross(b->w-a->w,c->w-a->w);
const real_t l=face->n.length();
const bool v=l>EPA_ACCURACY;
- face->p = MIN(MIN(
- vec3_dot(a->w,vec3_cross(face->n,a->w-b->w)),
- vec3_dot(b->w,vec3_cross(face->n,b->w-c->w))),
- vec3_dot(c->w,vec3_cross(face->n,c->w-a->w))) /
- (v?l:1);
- face->p = face->p>=-EPA_INSIDE_EPS?0:face->p;
- if(v)
- {
- face->d = vec3_dot(a->w,face->n)/l;
+ if (v) {
+ if (!(getedgedist(face, a, b, face->d) ||
+ getedgedist(face, b, c, face->d) ||
+ getedgedist(face, c, a, face->d))) {
+ // Origin projects to the interior of the triangle
+ // Use distance to triangle plane
+ face->d = vec3_dot(a->w, face->n) / l;
+ }
face->n /= l;
- if(forced||(face->d>=-EPA_PLANE_EPS))
- {
+ if (forced||(face->d>=-EPA_PLANE_EPS)) {
return(face);
- } else { m_status=eStatus::NonConvex;
-}
- } else { m_status=eStatus::Degenerated;
-}
+ } else {
+ m_status=eStatus::NonConvex;
+ }
+ } else {
+ m_status=eStatus::Degenerated;
+ }
remove(m_hull,face);
append(m_stock,face);
return(nullptr);
@@ -747,15 +812,13 @@ struct GJK
{
sFace* minf=m_hull.root;
real_t mind=minf->d*minf->d;
- real_t maxp=minf->p;
for(sFace* f=minf->l[1];f;f=f->l[1])
{
const real_t sqd=f->d*f->d;
- if((f->p>=maxp)&&(sqd<mind))
+ if(sqd<mind)
{
minf=f;
mind=sqd;
- maxp=f->p;
}
}
return(minf);
@@ -799,22 +862,17 @@ struct GJK
};
//
- static void Initialize( const Shape3DSW* shape0,const Transform& wtrs0,
- const Shape3DSW* shape1,const Transform& wtrs1,
+ static void Initialize( const Shape3DSW* shape0, const Transform& wtrs0, real_t margin0,
+ const Shape3DSW* shape1, const Transform& wtrs1, real_t margin1,
sResults& results,
- tShape& shape,
- bool withmargins)
+ tShape& shape)
{
/* Results */
- results.witnesses[0] =
- results.witnesses[1] = Vector3(0,0,0);
+ results.witnesses[0] = Vector3(0,0,0);
+ results.witnesses[1] = Vector3(0,0,0);
results.status = sResults::Separated;
/* Shape */
- shape.m_shapes[0] = shape0;
- shape.m_shapes[1] = shape1;
- shape.transform_A = wtrs0;
- shape.transform_B = wtrs1;
-
+ shape.Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1);
}
@@ -828,13 +886,15 @@ struct GJK
//
bool Distance( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
+ real_t margin1,
const Vector3& guess,
sResults& results)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
if(gjk_status==GJK::eStatus::Valid)
@@ -867,14 +927,16 @@ bool Distance( const Shape3DSW* shape0,
//
bool Penetration( const Shape3DSW* shape0,
const Transform& wtrs0,
- const Shape3DSW* shape1,
+ real_t margin0,
+ const Shape3DSW* shape1,
const Transform& wtrs1,
- const Vector3& guess,
+ real_t margin1,
+ const Vector3& guess,
sResults& results
)
{
tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ Initialize(shape0, wtrs0, margin0, shape1, wtrs1, margin1, results, shape);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
switch(gjk_status)
@@ -934,7 +996,7 @@ bool Penetration( const Shape3DSW* shape0,
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) {
r_result_A = res.witnesses[0];
r_result_B = res.witnesses[1];
return true;
@@ -943,15 +1005,15 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_t
return false;
}
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap) {
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {
GjkEpa2::sResults res;
- if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_transform_B.origin - p_transform_A.origin, res)) {
+ if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {
if (p_result_callback) {
if (p_swap) {
- p_result_callback(res.witnesses[1], res.witnesses[0], p_userdata);
+ p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata);
} else {
- p_result_callback(res.witnesses[0], res.witnesses[1], p_userdata);
+ p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata);
}
}
return true;
diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h
index be3ba4e664..a7e2e1719e 100644
--- a/servers/physics_3d/gjk_epa.h
+++ b/servers/physics_3d/gjk_epa.h
@@ -34,7 +34,7 @@
#include "collision_solver_3d_sw.h"
#include "shape_3d_sw.h"
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false);
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
#endif
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
index 9c4493f4a2..167f797bfe 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
@@ -109,6 +109,10 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans
}
bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
//set bias, sign, clear accumulator
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
index c38edc5737..4e4d4e7f0c 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
@@ -102,7 +102,7 @@ public:
bool m_solveSwingLimit;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
virtual bool setup(real_t p_timestep);
virtual void solve(real_t p_timestep);
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index 13b389251f..a86e8b4e76 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -303,6 +303,10 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) {
}
bool Generic6DOFJoint3DSW::setup(real_t p_timestep) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
// Clear accumulated impulses for the next simulation step
m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
int i;
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
index 2ae6fe85fa..d61a033231 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -234,7 +234,7 @@ protected:
public:
Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_6DOF; }
virtual bool setup(real_t p_timestep);
virtual void solve(real_t p_timestep);
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
index 2b9f0038b4..90b82f4680 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -155,6 +155,10 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo
}
bool HingeJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
if (!m_angularOnly) {
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h
index 028a8b8c72..b6117aa0bc 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.h
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h
@@ -96,7 +96,7 @@ class HingeJoint3DSW : public Joint3DSW {
real_t m_appliedImpulse;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_HINGE; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
index 9f708ce151..75d87992d1 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -50,6 +50,10 @@ subject to the following restrictions:
#include "pin_joint_3d_sw.h"
bool PinJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
Vector3 normal(0, 0, 0);
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h
index e28fbec6cd..1875983527 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.h
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.h
@@ -74,7 +74,7 @@ class PinJoint3DSW : public Joint3DSW {
Vector3 m_pivotInB;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_PIN; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_PIN; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
index 0adc471797..2e1ee8e770 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -127,6 +127,10 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &
//-----------------------------------------------------------------------------
bool SliderJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
//calculate transforms
m_calculatedTransformA = A->get_transform() * m_frameInA;
m_calculatedTransformB = B->get_transform() * m_frameInB;
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h
index 196e60d19d..f52f6ace27 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.h
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.h
@@ -243,7 +243,7 @@ public:
bool setup(real_t p_step);
void solve(real_t p_step);
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
};
#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h
index cad05b6702..225a71aca9 100644
--- a/servers/physics_3d/joints_3d_sw.h
+++ b/servers/physics_3d/joints_3d_sw.h
@@ -36,10 +36,28 @@
class Joint3DSW : public Constraint3DSW {
public:
- virtual PhysicsServer3D::JointType get_type() const = 0;
+ virtual bool setup(real_t p_step) { return false; }
+ virtual void solve(real_t p_step) {}
+
+ void copy_settings_from(Joint3DSW *p_joint) {
+ set_self(p_joint->get_self());
+ set_priority(p_joint->get_priority());
+ disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies());
+ }
+
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_MAX; }
_FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
Constraint3DSW(p_body_ptr, p_body_count) {
}
+
+ virtual ~Joint3DSW() {
+ for (int i = 0; i < get_body_count(); i++) {
+ Body3DSW *body = get_body_ptr()[i];
+ if (body) {
+ body->remove_constraint(this);
+ }
+ }
+ }
};
#endif // JOINTS_SW_H
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index b554a23bf2..c08e2b5794 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -43,47 +43,63 @@
#define FLUSH_QUERY_CHECK(m_object) \
ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.");
-RID PhysicsServer3DSW::shape_create(ShapeType p_shape) {
- Shape3DSW *shape = nullptr;
- switch (p_shape) {
- case SHAPE_PLANE: {
- shape = memnew(PlaneShape3DSW);
- } break;
- case SHAPE_RAY: {
- shape = memnew(RayShape3DSW);
- } break;
- case SHAPE_SPHERE: {
- shape = memnew(SphereShape3DSW);
- } break;
- case SHAPE_BOX: {
- shape = memnew(BoxShape3DSW);
- } break;
- case SHAPE_CAPSULE: {
- shape = memnew(CapsuleShape3DSW);
- } break;
- case SHAPE_CYLINDER: {
- ERR_FAIL_V_MSG(RID(), "CylinderShape3D is not supported in GodotPhysics3D. Please switch to Bullet in the Project Settings.");
- } break;
- case SHAPE_CONVEX_POLYGON: {
- shape = memnew(ConvexPolygonShape3DSW);
- } break;
- case SHAPE_CONCAVE_POLYGON: {
- shape = memnew(ConcavePolygonShape3DSW);
- } break;
- case SHAPE_HEIGHTMAP: {
- shape = memnew(HeightMapShape3DSW);
- } break;
- case SHAPE_CUSTOM: {
- ERR_FAIL_V(RID());
-
- } break;
- }
-
- RID id = shape_owner.make_rid(shape);
- shape->set_self(id);
-
- return id;
-};
+RID PhysicsServer3DSW::plane_shape_create() {
+ Shape3DSW *shape = memnew(PlaneShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::ray_shape_create() {
+ Shape3DSW *shape = memnew(RayShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::sphere_shape_create() {
+ Shape3DSW *shape = memnew(SphereShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::box_shape_create() {
+ Shape3DSW *shape = memnew(BoxShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::capsule_shape_create() {
+ Shape3DSW *shape = memnew(CapsuleShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::cylinder_shape_create() {
+ Shape3DSW *shape = memnew(CylinderShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::convex_polygon_shape_create() {
+ Shape3DSW *shape = memnew(ConvexPolygonShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::concave_polygon_shape_create() {
+ Shape3DSW *shape = memnew(ConcavePolygonShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::heightmap_shape_create() {
+ Shape3DSW *shape = memnew(HeightMapShape3DSW);
+ RID rid = shape_owner.make_rid(shape);
+ shape->set_self(rid);
+ return rid;
+}
+RID PhysicsServer3DSW::custom_shape_create() {
+ ERR_FAIL_V(RID());
+}
void PhysicsServer3DSW::shape_set_data(RID p_shape, const Variant &p_data) {
Shape3DSW *shape = shape_owner.getornull(p_shape);
@@ -174,7 +190,7 @@ real_t PhysicsServer3DSW::space_get_param(RID p_space, SpaceParameter p_param) c
PhysicsDirectSpaceState3D *PhysicsServer3DSW::space_get_direct_state(RID p_space) {
Space3DSW *space = space_owner.getornull(p_space);
ERR_FAIL_COND_V(!space, nullptr);
- ERR_FAIL_COND_V_MSG(space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification.");
+ ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification.");
return space->get_direct_state();
}
@@ -413,13 +429,6 @@ void PhysicsServer3DSW::area_set_ray_pickable(RID p_area, bool p_enable) {
area->set_ray_pickable(p_enable);
}
-bool PhysicsServer3DSW::area_is_ray_pickable(RID p_area) const {
- Area3DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, false);
-
- return area->is_ray_pickable();
-}
-
void PhysicsServer3DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
Area3DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -429,14 +438,8 @@ void PhysicsServer3DSW::area_set_area_monitor_callback(RID p_area, Object *p_rec
/* BODY API */
-RID PhysicsServer3DSW::body_create(BodyMode p_mode, bool p_init_sleeping) {
+RID PhysicsServer3DSW::body_create() {
Body3DSW *body = memnew(Body3DSW);
- if (p_mode != BODY_MODE_RIGID) {
- body->set_mode(p_mode);
- }
- if (p_init_sleeping) {
- body->set_state(BODY_STATE_SLEEPING, p_init_sleeping);
- }
RID rid = body_owner.make_rid(body);
body->set_self(rid);
return rid;
@@ -608,9 +611,18 @@ uint32_t PhysicsServer3DSW::body_get_collision_mask(RID p_body) const {
void PhysicsServer3DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
+ if (body) {
+ body->set_instance_id(p_id);
+ return;
+ }
- body->set_instance_id(p_id);
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ if (soft_body) {
+ soft_body->set_instance_id(p_id);
+ return;
+ }
+
+ ERR_FAIL_MSG("Invalid ID.");
};
ObjectID PhysicsServer3DSW::body_get_object_instance_id(RID p_body) const {
@@ -845,10 +857,10 @@ int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -857,12 +869,6 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-bool PhysicsServer3DSW::body_is_ray_pickable(RID p_body) const {
- Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
@@ -886,6 +892,8 @@ int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_t
}
PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
+ ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
+
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, nullptr);
ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
@@ -894,32 +902,314 @@ PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
return direct_state;
}
+/* SOFT BODY */
+
+RID PhysicsServer3DSW::soft_body_create() {
+ SoftBody3DSW *soft_body = memnew(SoftBody3DSW);
+ RID rid = soft_body_owner.make_rid(soft_body);
+ soft_body->set_self(rid);
+ return rid;
+}
+
+void PhysicsServer3DSW::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->update_rendering_server(p_rendering_server_handler);
+}
+
+void PhysicsServer3DSW::soft_body_set_space(RID p_body, RID p_space) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ Space3DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (soft_body->get_space() == space) {
+ return;
+ }
+
+ soft_body->set_space(space);
+}
+
+RID PhysicsServer3DSW::soft_body_get_space(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, RID());
+
+ Space3DSW *space = soft_body->get_space();
+ if (!space) {
+ return RID();
+ }
+ return space->get_self();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_layer(p_layer);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_layer(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_layer();
+}
+
+void PhysicsServer3DSW::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsServer3DSW::soft_body_get_collision_mask(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0);
+
+ return soft_body->get_collision_mask();
+}
+
+void PhysicsServer3DSW::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->add_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->remove_exception(p_body_b);
+}
+
+void PhysicsServer3DSW::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ for (int i = 0; i < soft_body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(soft_body->get_exceptions()[i]);
+ }
+}
+
+void PhysicsServer3DSW::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(p_state, p_variant);
+}
+
+Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Variant());
+
+ return soft_body->get_state(p_state);
+}
+
+void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_state(BODY_STATE_TRANSFORM, p_transform);
+}
+
+void PhysicsServer3DSW::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_ray_pickable(p_enable);
+}
+
+void PhysicsServer3DSW::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_iteration_count(p_simulation_precision);
+}
+
+int PhysicsServer3DSW::soft_body_get_simulation_precision(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_iteration_count();
+}
+
+void PhysicsServer3DSW::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_total_mass(p_total_mass);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_total_mass(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_total_mass();
+}
+
+void PhysicsServer3DSW::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_linear_stiffness(p_stiffness);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_linear_stiffness(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_linear_stiffness();
+}
+
+void PhysicsServer3DSW::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_pressure_coefficient(p_pressure_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_pressure_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_pressure_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_damping_coefficient(p_damping_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_damping_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_damping_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_drag_coefficient(p_drag_coefficient);
+}
+
+real_t PhysicsServer3DSW::soft_body_get_drag_coefficient(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, 0.f);
+
+ return soft_body->get_drag_coefficient();
+}
+
+void PhysicsServer3DSW::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_mesh(p_mesh);
+}
+
+AABB PhysicsServer3DSW::soft_body_get_bounds(RID p_body) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, AABB());
+
+ return soft_body->get_bounds();
+}
+
+void PhysicsServer3DSW::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->set_vertex_position(p_point_index, p_global_position);
+}
+
+Vector3 PhysicsServer3DSW::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, Vector3());
+
+ return soft_body->get_vertex_position(p_point_index);
+}
+
+void PhysicsServer3DSW::soft_body_remove_all_pinned_points(RID p_body) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ soft_body->unpin_all_vertices();
+}
+
+void PhysicsServer3DSW::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND(!soft_body);
+
+ if (p_pin) {
+ soft_body->pin_vertex(p_point_index);
+ } else {
+ soft_body->unpin_vertex(p_point_index);
+ }
+}
+
+bool PhysicsServer3DSW::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!soft_body, false);
+
+ return soft_body->is_vertex_pinned(p_point_index);
+}
+
/* JOINT API */
-RID PhysicsServer3DSW::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
+RID PhysicsServer3DSW::joint_create() {
+ Joint3DSW *joint = memnew(Joint3DSW);
+ RID rid = joint_owner.make_rid(joint);
+ joint->set_self(rid);
+ return rid;
+}
+
+void PhysicsServer3DSW::joint_clear(RID p_joint) {
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ if (joint->get_type() != JOINT_TYPE_MAX) {
+ Joint3DSW *empty_joint = memnew(Joint3DSW);
+ empty_joint->copy_settings_from(joint);
+
+ joint_owner.replace(p_joint, empty_joint);
+ memdelete(joint);
+ }
+}
+
+void PhysicsServer3DSW::joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
+
+ ERR_FAIL_COND(body_A == body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(PinJoint3DSW(body_A, p_local_A, body_B, p_local_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
void PhysicsServer3DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN);
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
pin_joint->set_param(p_param, p_value);
}
@@ -927,7 +1217,7 @@ void PhysicsServer3DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param,
real_t PhysicsServer3DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, 0);
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
return pin_joint->get_param(p_param);
}
@@ -935,7 +1225,7 @@ real_t PhysicsServer3DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param
void PhysicsServer3DSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN);
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
pin_joint->set_pos_a(p_A);
}
@@ -943,7 +1233,7 @@ void PhysicsServer3DSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
Vector3 PhysicsServer3DSW::pin_joint_get_local_a(RID p_joint) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3());
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
return pin_joint->get_position_a();
}
@@ -951,7 +1241,7 @@ Vector3 PhysicsServer3DSW::pin_joint_get_local_a(RID p_joint) const {
void PhysicsServer3DSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN);
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
pin_joint->set_pos_b(p_B);
}
@@ -959,55 +1249,63 @@ void PhysicsServer3DSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
Vector3 PhysicsServer3DSW::pin_joint_get_local_b(RID p_joint) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3());
PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
return pin_joint->get_position_b();
}
-RID PhysicsServer3DSW::joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) {
+void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
+
+ ERR_FAIL_COND(body_A == body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_frame_A, p_frame_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
-RID PhysicsServer3DSW::joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) {
+void PhysicsServer3DSW::joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ ERR_FAIL_COND(body_A == body_B);
+
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
void PhysicsServer3DSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE);
HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
hinge_joint->set_param(p_param, p_value);
}
@@ -1015,7 +1313,7 @@ void PhysicsServer3DSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_par
real_t PhysicsServer3DSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, 0);
HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
return hinge_joint->get_param(p_param);
}
@@ -1023,7 +1321,7 @@ real_t PhysicsServer3DSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_p
void PhysicsServer3DSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE);
HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
hinge_joint->set_flag(p_flag, p_value);
}
@@ -1031,7 +1329,7 @@ void PhysicsServer3DSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag,
bool PhysicsServer3DSW::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, false);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, false);
HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
return hinge_joint->get_flag(p_flag);
}
@@ -1077,34 +1375,38 @@ bool PhysicsServer3DSW::joint_is_disabled_collisions_between_bodies(RID p_joint)
PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, JOINT_PIN);
+ ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN);
return joint->get_type();
}
-RID PhysicsServer3DSW::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
+
+ ERR_FAIL_COND(body_A == body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(SliderJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
void PhysicsServer3DSW::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_SLIDER);
SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint);
slider_joint->set_param(p_param, p_value);
}
@@ -1112,35 +1414,39 @@ void PhysicsServer3DSW::slider_joint_set_param(RID p_joint, SliderJointParam p_p
real_t PhysicsServer3DSW::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0);
SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint);
return slider_joint->get_param(p_param);
}
-RID PhysicsServer3DSW::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
+
+ ERR_FAIL_COND(body_A == body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(ConeTwistJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
void PhysicsServer3DSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_CONE_TWIST);
ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint);
cone_twist_joint->set_param(p_param, p_value);
}
@@ -1148,43 +1454,47 @@ void PhysicsServer3DSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointPa
real_t PhysicsServer3DSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0);
ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint);
return cone_twist_joint->get_param(p_param);
}
-RID PhysicsServer3DSW::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
+ ERR_FAIL_COND(!body_A);
if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ ERR_FAIL_COND(!body_A->get_space());
p_body_B = body_A->get_space()->get_static_global_body();
}
Body3DSW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
+ ERR_FAIL_COND(!body_B);
+
+ ERR_FAIL_COND(body_A == body_B);
- ERR_FAIL_COND_V(body_A == body_B, RID());
+ Joint3DSW *prev_joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(prev_joint == nullptr);
Joint3DSW *joint = memnew(Generic6DOFJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B, true));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
+
+ joint->copy_settings_from(prev_joint);
+ joint_owner.replace(p_joint, joint);
+ memdelete(prev_joint);
}
void PhysicsServer3DSW::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF);
Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
generic_6dof_joint->set_param(p_axis, p_param, p_value);
}
-real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
+real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, 0);
Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
return generic_6dof_joint->get_param(p_axis, p_param);
}
@@ -1192,15 +1502,15 @@ real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axi
void PhysicsServer3DSW::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
+ ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF);
Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
generic_6dof_joint->set_flag(p_axis, p_flag, p_enable);
}
-bool PhysicsServer3DSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
+bool PhysicsServer3DSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) const {
Joint3DSW *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, false);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, false);
Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
@@ -1237,7 +1547,13 @@ void PhysicsServer3DSW::free(RID p_rid) {
body_owner.free(p_rid);
memdelete(body);
+ } else if (soft_body_owner.owns(p_rid)) {
+ SoftBody3DSW *soft_body = soft_body_owner.getornull(p_rid);
+
+ soft_body->set_space(nullptr);
+ soft_body_owner.free(p_rid);
+ memdelete(soft_body);
} else if (area_owner.owns(p_rid)) {
Area3DSW *area = area_owner.getornull(p_rid);
@@ -1271,9 +1587,6 @@ void PhysicsServer3DSW::free(RID p_rid) {
} else if (joint_owner.owns(p_rid)) {
Joint3DSW *joint = joint_owner.getornull(p_rid);
- for (int i = 0; i < joint->get_body_count(); i++) {
- joint->get_body_ptr()[i]->remove_constraint(joint);
- }
joint_owner.free(p_rid);
memdelete(joint);
@@ -1317,6 +1630,10 @@ void PhysicsServer3DSW::step(real_t p_step) {
#endif
}
+void PhysicsServer3DSW::sync() {
+ doing_sync = true;
+};
+
void PhysicsServer3DSW::flush_queries() {
#ifndef _3D_DISABLED
@@ -1370,6 +1687,10 @@ void PhysicsServer3DSW::flush_queries() {
#endif
};
+void PhysicsServer3DSW::end_sync() {
+ doing_sync = false;
+};
+
void PhysicsServer3DSW::finish() {
memdelete(stepper);
memdelete(direct_state);
@@ -1398,7 +1719,7 @@ void PhysicsServer3DSW::_update_shapes() {
}
}
-void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
CollCbkData *cbk = (CollCbkData *)p_userdata;
if (cbk->max == 0) {
@@ -1431,14 +1752,15 @@ void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &
}
}
-PhysicsServer3DSW *PhysicsServer3DSW::singleton = nullptr;
-PhysicsServer3DSW::PhysicsServer3DSW() {
- singleton = this;
+PhysicsServer3DSW *PhysicsServer3DSW::singletonsw = nullptr;
+PhysicsServer3DSW::PhysicsServer3DSW(bool p_using_threads) {
+ singletonsw = this;
BroadPhase3DSW::create_func = BroadPhaseOctree::_create;
island_count = 0;
active_objects = 0;
collision_pairs = 0;
-
+ using_threads = p_using_threads;
active = true;
flushing_queries = false;
+ doing_sync = false;
};
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index c48db81d97..0b42f1d605 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -50,6 +50,8 @@ class PhysicsServer3DSW : public PhysicsServer3D {
int active_objects;
int collision_pairs;
+ bool using_threads;
+ bool doing_sync;
bool flushing_queries;
Step3DSW *stepper;
@@ -57,29 +59,40 @@ class PhysicsServer3DSW : public PhysicsServer3D {
PhysicsDirectBodyState3DSW *direct_state;
- mutable RID_PtrOwner<Shape3DSW> shape_owner;
- mutable RID_PtrOwner<Space3DSW> space_owner;
- mutable RID_PtrOwner<Area3DSW> area_owner;
- mutable RID_PtrOwner<Body3DSW> body_owner;
- mutable RID_PtrOwner<Joint3DSW> joint_owner;
+ mutable RID_PtrOwner<Shape3DSW, true> shape_owner;
+ mutable RID_PtrOwner<Space3DSW, true> space_owner;
+ mutable RID_PtrOwner<Area3DSW, true> area_owner;
+ mutable RID_PtrOwner<Body3DSW, true> body_owner;
+ mutable RID_PtrOwner<SoftBody3DSW, true> soft_body_owner;
+ mutable RID_PtrOwner<Joint3DSW, true> joint_owner;
//void _clear_query(QuerySW *p_query);
friend class CollisionObject3DSW;
SelfList<CollisionObject3DSW>::List pending_shape_update_list;
void _update_shapes();
-public:
- static PhysicsServer3DSW *singleton;
+ static PhysicsServer3DSW *singletonsw;
+public:
struct CollCbkData {
int max;
int amount;
Vector3 *ptr;
};
- static void _shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+ static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
+
+ virtual RID plane_shape_create() override;
+ virtual RID ray_shape_create() override;
+ virtual RID sphere_shape_create() override;
+ virtual RID box_shape_create() override;
+ virtual RID capsule_shape_create() override;
+ virtual RID cylinder_shape_create() override;
+ virtual RID convex_polygon_shape_create() override;
+ virtual RID concave_polygon_shape_create() override;
+ virtual RID heightmap_shape_create() override;
+ virtual RID custom_shape_create() override;
- virtual RID shape_create(ShapeType p_shape) override;
virtual void shape_set_data(RID p_shape, const Variant &p_data) override;
virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) override;
@@ -140,7 +153,6 @@ public:
virtual Transform area_get_transform(RID p_area) const override;
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
- virtual bool area_is_ray_pickable(RID p_area) const override;
virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
@@ -153,7 +165,7 @@ public:
/* BODY API */
// create a body of a given type
- virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) override;
+ virtual RID body_create() override;
virtual void body_set_space(RID p_body, RID p_space) override;
virtual RID body_get_space(RID p_body) const override;
@@ -229,10 +241,9 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_is_ray_pickable(RID p_body) const override;
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
@@ -242,73 +253,66 @@ public:
/* SOFT BODY */
- virtual RID soft_body_create(bool p_init_sleeping = false) override { return RID(); }
+ virtual RID soft_body_create() override;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) override {}
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) override;
- virtual void soft_body_set_space(RID p_body, RID p_space) override {}
- virtual RID soft_body_get_space(RID p_body) const override { return RID(); }
+ virtual void soft_body_set_space(RID p_body, RID p_space) override;
+ virtual RID soft_body_get_space(RID p_body) const override;
- virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override {}
- virtual uint32_t soft_body_get_collision_layer(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) override;
+ virtual uint32_t soft_body_get_collision_layer(RID p_body) const override;
- virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override {}
- virtual uint32_t soft_body_get_collision_mask(RID p_body) const override { return 0; }
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) override;
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const override;
- virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override {}
- virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override {}
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) override;
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) override;
- virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override {}
- virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override { return Variant(); }
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
+ virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override;
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override {}
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const override { return Vector3(); }
+ virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
- virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override {}
- virtual bool soft_body_is_ray_pickable(RID p_body) const override { return false; }
+ virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override {}
- virtual int soft_body_get_simulation_precision(RID p_body) override { return 0; }
+ virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) override;
+ virtual int soft_body_get_simulation_precision(RID p_body) const override;
- virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override {}
- virtual real_t soft_body_get_total_mass(RID p_body) override { return 0.; }
+ virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) override;
+ virtual real_t soft_body_get_total_mass(RID p_body) const override;
- virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_linear_stiffness(RID p_body) override { return 0.; }
+ virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) override;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const override;
- virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) override { return 0.; }
+ virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const override;
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) override {}
- virtual real_t soft_body_get_volume_stiffness(RID p_body) override { return 0.; }
+ virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const override;
- virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) override {}
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) override { return 0.; }
+ virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const override;
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) override {}
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) override { return 0.; }
+ virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
- virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) override {}
- virtual real_t soft_body_get_damping_coefficient(RID p_body) override { return 0.; }
+ virtual AABB soft_body_get_bounds(RID p_body) const override;
- virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override {}
- virtual real_t soft_body_get_drag_coefficient(RID p_body) override { return 0.; }
+ virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const override;
- virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override {}
+ virtual void soft_body_remove_all_pinned_points(RID p_body) override;
+ virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override;
- virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) override {}
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) override { return Vector3(); }
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const override { return Vector3(); }
+ /* JOINT API */
- virtual void soft_body_remove_all_pinned_points(RID p_body) override {}
- virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {}
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) override { return false; }
+ virtual RID joint_create() override;
- /* JOINT API */
+ virtual void joint_clear(RID p_joint) override; //resets type
- virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override;
+ virtual void joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override;
virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override;
virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override;
@@ -319,8 +323,8 @@ public:
virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override;
virtual Vector3 pin_joint_get_local_b(RID p_joint) const override;
- virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override;
- virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override;
+ virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override;
+ virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override;
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override;
virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override;
@@ -328,23 +332,23 @@ public:
virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override;
virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override;
- virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override;
virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override;
- virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override;
virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override;
- virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) override;
- virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) override;
+ virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const override;
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) override;
- virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) override;
+ virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const override;
virtual JointType joint_get_type(RID p_joint) const override;
@@ -361,14 +365,16 @@ public:
virtual void set_active(bool p_active) override;
virtual void init() override;
virtual void step(real_t p_step) override;
+ virtual void sync() override;
virtual void flush_queries() override;
+ virtual void end_sync() override;
virtual void finish() override;
virtual bool is_flushing_queries() const override { return flushing_queries; }
int get_process_info(ProcessInfo p_info) override;
- PhysicsServer3DSW();
+ PhysicsServer3DSW(bool p_using_threads = false);
~PhysicsServer3DSW() {}
};
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.cpp b/servers/physics_3d/physics_server_3d_wrap_mt.cpp
new file mode 100644
index 0000000000..f73f67a756
--- /dev/null
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.cpp
@@ -0,0 +1,140 @@
+/*************************************************************************/
+/* physics_server_3d_wrap_mt.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "physics_server_3d_wrap_mt.h"
+
+#include "core/os/os.h"
+
+void PhysicsServer3DWrapMT::thread_exit() {
+ exit = true;
+}
+
+void PhysicsServer3DWrapMT::thread_step(real_t p_delta) {
+ physics_3d_server->step(p_delta);
+ step_sem.post();
+}
+
+void PhysicsServer3DWrapMT::_thread_callback(void *_instance) {
+ PhysicsServer3DWrapMT *vsmt = reinterpret_cast<PhysicsServer3DWrapMT *>(_instance);
+
+ vsmt->thread_loop();
+}
+
+void PhysicsServer3DWrapMT::thread_loop() {
+ server_thread = Thread::get_caller_id();
+
+ physics_3d_server->init();
+
+ exit = false;
+ step_thread_up = true;
+ while (!exit) {
+ // flush commands one by one, until exit is requested
+ command_queue.wait_and_flush_one();
+ }
+
+ command_queue.flush_all(); // flush all
+
+ physics_3d_server->finish();
+}
+
+/* EVENT QUEUING */
+
+void PhysicsServer3DWrapMT::step(real_t p_step) {
+ if (create_thread) {
+ command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step);
+ } else {
+ command_queue.flush_all(); //flush all pending from other threads
+ physics_3d_server->step(p_step);
+ }
+}
+
+void PhysicsServer3DWrapMT::sync() {
+ if (create_thread) {
+ if (first_frame) {
+ first_frame = false;
+ } else {
+ step_sem.wait(); //must not wait if a step was not issued
+ }
+ }
+ physics_3d_server->sync();
+}
+
+void PhysicsServer3DWrapMT::flush_queries() {
+ physics_3d_server->flush_queries();
+}
+
+void PhysicsServer3DWrapMT::end_sync() {
+ physics_3d_server->end_sync();
+}
+
+void PhysicsServer3DWrapMT::init() {
+ if (create_thread) {
+ //OS::get_singleton()->release_rendering_thread();
+ thread.start(_thread_callback, this);
+ while (!step_thread_up) {
+ OS::get_singleton()->delay_usec(1000);
+ }
+ } else {
+ physics_3d_server->init();
+ }
+}
+
+void PhysicsServer3DWrapMT::finish() {
+ if (thread.is_started()) {
+ command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit);
+ thread.wait_to_finish();
+ } else {
+ physics_3d_server->finish();
+ }
+}
+
+PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) :
+ command_queue(p_create_thread) {
+ physics_3d_server = p_contained;
+ create_thread = p_create_thread;
+ step_pending = 0;
+ step_thread_up = false;
+
+ pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc");
+
+ if (!p_create_thread) {
+ server_thread = Thread::get_caller_id();
+ } else {
+ server_thread = 0;
+ }
+
+ main_thread = Thread::get_caller_id();
+ first_frame = true;
+}
+
+PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() {
+ memdelete(physics_3d_server);
+ //finish();
+}
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
new file mode 100644
index 0000000000..69d0fcf3ed
--- /dev/null
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -0,0 +1,413 @@
+/*************************************************************************/
+/* physics_server_3d_wrap_mt.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PHYSICS3DSERVERWRAPMT_H
+#define PHYSICS3DSERVERWRAPMT_H
+
+#include "core/config/project_settings.h"
+#include "core/os/thread.h"
+#include "core/templates/command_queue_mt.h"
+#include "servers/physics_server_3d.h"
+
+#ifdef DEBUG_SYNC
+#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
+#else
+#define SYNC_DEBUG
+#endif
+
+class PhysicsServer3DWrapMT : public PhysicsServer3D {
+ mutable PhysicsServer3D *physics_3d_server;
+
+ mutable CommandQueueMT command_queue;
+
+ static void _thread_callback(void *_instance);
+ void thread_loop();
+
+ Thread::ID server_thread;
+ Thread::ID main_thread;
+ volatile bool exit = false;
+ Thread thread;
+ volatile bool step_thread_up = false;
+ bool create_thread = false;
+
+ Semaphore step_sem;
+ int step_pending;
+ void thread_step(real_t p_delta);
+ void thread_flush();
+
+ void thread_exit();
+
+ bool first_frame = true;
+
+ Mutex alloc_mutex;
+ int pool_max_size = 0;
+
+public:
+#define ServerName PhysicsServer3D
+#define ServerNameWrapMT PhysicsServer3DWrapMT
+#define server_name physics_3d_server
+#define WRITE_ACTION
+
+#include "servers/server_wrap_mt_common.h"
+
+ //FUNC1RID(shape,ShapeType); todo fix
+ FUNCRID(plane_shape)
+ FUNCRID(ray_shape)
+ FUNCRID(sphere_shape)
+ FUNCRID(box_shape)
+ FUNCRID(capsule_shape)
+ FUNCRID(cylinder_shape)
+ FUNCRID(convex_polygon_shape)
+ FUNCRID(concave_polygon_shape)
+ FUNCRID(heightmap_shape)
+ FUNCRID(custom_shape)
+
+ FUNC2(shape_set_data, RID, const Variant &);
+ FUNC2(shape_set_custom_solver_bias, RID, real_t);
+
+ FUNC2(shape_set_margin, RID, real_t)
+ FUNC1RC(real_t, shape_get_margin, RID)
+
+ FUNC1RC(ShapeType, shape_get_type, RID);
+ FUNC1RC(Variant, shape_get_data, RID);
+ FUNC1RC(real_t, shape_get_custom_solver_bias, RID);
+#if 0
+ //these work well, but should be used from the main thread only
+ bool shape_collide(RID p_shape_A, const Transform &p_xform_A, const Vector3 &p_motion_A, RID p_shape_B, const Transform &p_xform_B, const Vector3 &p_motion_B, Vector3 *r_results, int p_result_max, int &r_result_count) {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
+ return physics_3d_server->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count);
+ }
+#endif
+ /* SPACE API */
+
+ FUNCRID(space);
+ FUNC2(space_set_active, RID, bool);
+ FUNC1RC(bool, space_is_active, RID);
+
+ FUNC3(space_set_param, RID, SpaceParameter, real_t);
+ FUNC2RC(real_t, space_get_param, RID, SpaceParameter);
+
+ // this function only works on physics process, errors and returns null otherwise
+ PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
+ return physics_3d_server->space_get_direct_state(p_space);
+ }
+
+ FUNC2(space_set_debug_contacts, RID, int);
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector3>());
+ return physics_3d_server->space_get_contacts(p_space);
+ }
+
+ virtual int space_get_contact_count(RID p_space) const override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0);
+ return physics_3d_server->space_get_contact_count(p_space);
+ }
+
+ /* AREA API */
+
+ //FUNC0RID(area);
+ FUNCRID(area);
+
+ FUNC2(area_set_space, RID, RID);
+ FUNC1RC(RID, area_get_space, RID);
+
+ FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode);
+ FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID);
+
+ FUNC4(area_add_shape, RID, RID, const Transform &, bool);
+ FUNC3(area_set_shape, RID, int, RID);
+ FUNC3(area_set_shape_transform, RID, int, const Transform &);
+ FUNC3(area_set_shape_disabled, RID, int, bool);
+
+ FUNC1RC(int, area_get_shape_count, RID);
+ FUNC2RC(RID, area_get_shape, RID, int);
+ FUNC2RC(Transform, area_get_shape_transform, RID, int);
+ FUNC2(area_remove_shape, RID, int);
+ FUNC1(area_clear_shapes, RID);
+
+ FUNC2(area_attach_object_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, area_get_object_instance_id, RID);
+
+ FUNC3(area_set_param, RID, AreaParameter, const Variant &);
+ FUNC2(area_set_transform, RID, const Transform &);
+
+ FUNC2RC(Variant, area_get_param, RID, AreaParameter);
+ FUNC1RC(Transform, area_get_transform, RID);
+
+ FUNC2(area_set_collision_mask, RID, uint32_t);
+ FUNC2(area_set_collision_layer, RID, uint32_t);
+
+ FUNC2(area_set_monitorable, RID, bool);
+ FUNC2(area_set_ray_pickable, RID, bool);
+
+ FUNC3(area_set_monitor_callback, RID, Object *, const StringName &);
+ FUNC3(area_set_area_monitor_callback, RID, Object *, const StringName &);
+
+ /* BODY API */
+
+ //FUNC2RID(body,BodyMode,bool);
+ FUNCRID(body)
+
+ FUNC2(body_set_space, RID, RID);
+ FUNC1RC(RID, body_get_space, RID);
+
+ FUNC2(body_set_mode, RID, BodyMode);
+ FUNC1RC(BodyMode, body_get_mode, RID);
+
+ FUNC4(body_add_shape, RID, RID, const Transform &, bool);
+ FUNC3(body_set_shape, RID, int, RID);
+ FUNC3(body_set_shape_transform, RID, int, const Transform &);
+
+ FUNC1RC(int, body_get_shape_count, RID);
+ FUNC2RC(Transform, body_get_shape_transform, RID, int);
+ FUNC2RC(RID, body_get_shape, RID, int);
+
+ FUNC3(body_set_shape_disabled, RID, int, bool);
+
+ FUNC2(body_remove_shape, RID, int);
+ FUNC1(body_clear_shapes, RID);
+
+ FUNC2(body_attach_object_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, body_get_object_instance_id, RID);
+
+ FUNC2(body_set_enable_continuous_collision_detection, RID, bool);
+ FUNC1RC(bool, body_is_continuous_collision_detection_enabled, RID);
+
+ FUNC2(body_set_collision_layer, RID, uint32_t);
+ FUNC1RC(uint32_t, body_get_collision_layer, RID);
+
+ FUNC2(body_set_collision_mask, RID, uint32_t);
+ FUNC1RC(uint32_t, body_get_collision_mask, RID);
+
+ FUNC2(body_set_user_flags, RID, uint32_t);
+ FUNC1RC(uint32_t, body_get_user_flags, RID);
+
+ FUNC3(body_set_param, RID, BodyParameter, real_t);
+ FUNC2RC(real_t, body_get_param, RID, BodyParameter);
+
+ FUNC2(body_set_kinematic_safe_margin, RID, real_t);
+ FUNC1RC(real_t, body_get_kinematic_safe_margin, RID);
+
+ FUNC3(body_set_state, RID, BodyState, const Variant &);
+ FUNC2RC(Variant, body_get_state, RID, BodyState);
+
+ FUNC2(body_set_applied_force, RID, const Vector3 &);
+ FUNC1RC(Vector3, body_get_applied_force, RID);
+
+ FUNC2(body_set_applied_torque, RID, const Vector3 &);
+ FUNC1RC(Vector3, body_get_applied_torque, RID);
+
+ FUNC2(body_add_central_force, RID, const Vector3 &);
+ FUNC3(body_add_force, RID, const Vector3 &, const Vector3 &);
+ FUNC2(body_add_torque, RID, const Vector3 &);
+ FUNC2(body_apply_torque_impulse, RID, const Vector3 &);
+ FUNC2(body_apply_central_impulse, RID, const Vector3 &);
+ FUNC3(body_apply_impulse, RID, const Vector3 &, const Vector3 &);
+ FUNC2(body_set_axis_velocity, RID, const Vector3 &);
+
+ FUNC3(body_set_axis_lock, RID, BodyAxis, bool);
+ FUNC2RC(bool, body_is_axis_locked, RID, BodyAxis);
+
+ FUNC2(body_add_collision_exception, RID, RID);
+ FUNC2(body_remove_collision_exception, RID, RID);
+ FUNC2S(body_get_collision_exceptions, RID, List<RID> *);
+
+ FUNC2(body_set_max_contacts_reported, RID, int);
+ FUNC1RC(int, body_get_max_contacts_reported, RID);
+
+ FUNC2(body_set_contacts_reported_depth_threshold, RID, real_t);
+ FUNC1RC(real_t, body_get_contacts_reported_depth_threshold, RID);
+
+ FUNC2(body_set_omit_force_integration, RID, bool);
+ FUNC1RC(bool, body_is_omitting_force_integration, RID);
+
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
+
+ FUNC2(body_set_ray_pickable, RID, bool);
+
+ bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
+ return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
+ }
+
+ int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
+ return physics_3d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+ }
+
+ // this function only works on physics process, errors and returns null otherwise
+ PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override {
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
+ return physics_3d_server->body_get_direct_state(p_body);
+ }
+
+ /* SOFT BODY API */
+
+ FUNCRID(soft_body)
+
+ FUNC2(soft_body_update_rendering_server, RID, class RenderingServerHandler *)
+
+ FUNC2(soft_body_set_space, RID, RID)
+ FUNC1RC(RID, soft_body_get_space, RID)
+
+ FUNC2(soft_body_set_ray_pickable, RID, bool);
+
+ FUNC2(soft_body_set_collision_layer, RID, uint32_t)
+ FUNC1RC(uint32_t, soft_body_get_collision_layer, RID)
+
+ FUNC2(soft_body_set_collision_mask, RID, uint32_t)
+ FUNC1RC(uint32_t, soft_body_get_collision_mask, RID)
+
+ FUNC2(soft_body_add_collision_exception, RID, RID)
+ FUNC2(soft_body_remove_collision_exception, RID, RID)
+ FUNC2S(soft_body_get_collision_exceptions, RID, List<RID> *)
+
+ FUNC3(soft_body_set_state, RID, BodyState, const Variant &);
+ FUNC2RC(Variant, soft_body_get_state, RID, BodyState);
+
+ FUNC2(soft_body_set_transform, RID, const Transform &);
+
+ FUNC2(soft_body_set_simulation_precision, RID, int);
+ FUNC1RC(int, soft_body_get_simulation_precision, RID);
+
+ FUNC2(soft_body_set_total_mass, RID, real_t);
+ FUNC1RC(real_t, soft_body_get_total_mass, RID);
+
+ FUNC2(soft_body_set_linear_stiffness, RID, real_t);
+ FUNC1RC(real_t, soft_body_get_linear_stiffness, RID);
+
+ FUNC2(soft_body_set_pressure_coefficient, RID, real_t);
+ FUNC1RC(real_t, soft_body_get_pressure_coefficient, RID);
+
+ FUNC2(soft_body_set_damping_coefficient, RID, real_t);
+ FUNC1RC(real_t, soft_body_get_damping_coefficient, RID);
+
+ FUNC2(soft_body_set_drag_coefficient, RID, real_t);
+ FUNC1RC(real_t, soft_body_get_drag_coefficient, RID);
+
+ FUNC2(soft_body_set_mesh, RID, const REF &);
+
+ FUNC1RC(AABB, soft_body_get_bounds, RID);
+
+ FUNC3(soft_body_move_point, RID, int, const Vector3 &);
+ FUNC2RC(Vector3, soft_body_get_point_global_position, RID, int);
+
+ FUNC1(soft_body_remove_all_pinned_points, RID);
+ FUNC3(soft_body_pin_point, RID, int, bool);
+ FUNC2RC(bool, soft_body_is_point_pinned, RID, int);
+
+ /* JOINT API */
+
+ FUNCRID(joint)
+
+ FUNC1(joint_clear, RID)
+
+ FUNC5(joint_make_pin, RID, RID, const Vector3 &, RID, const Vector3 &)
+
+ FUNC3(pin_joint_set_param, RID, PinJointParam, real_t)
+ FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam)
+
+ FUNC2(pin_joint_set_local_a, RID, const Vector3 &)
+ FUNC1RC(Vector3, pin_joint_get_local_a, RID)
+
+ FUNC2(pin_joint_set_local_b, RID, const Vector3 &)
+ FUNC1RC(Vector3, pin_joint_get_local_b, RID)
+
+ FUNC5(joint_make_hinge, RID, RID, const Transform &, RID, const Transform &)
+ FUNC7(joint_make_hinge_simple, RID, RID, const Vector3 &, const Vector3 &, RID, const Vector3 &, const Vector3 &)
+
+ FUNC3(hinge_joint_set_param, RID, HingeJointParam, real_t)
+ FUNC2RC(real_t, hinge_joint_get_param, RID, HingeJointParam)
+
+ FUNC3(hinge_joint_set_flag, RID, HingeJointFlag, bool)
+ FUNC2RC(bool, hinge_joint_get_flag, RID, HingeJointFlag)
+
+ FUNC5(joint_make_slider, RID, RID, const Transform &, RID, const Transform &)
+
+ FUNC3(slider_joint_set_param, RID, SliderJointParam, real_t)
+ FUNC2RC(real_t, slider_joint_get_param, RID, SliderJointParam)
+
+ FUNC5(joint_make_cone_twist, RID, RID, const Transform &, RID, const Transform &)
+
+ FUNC3(cone_twist_joint_set_param, RID, ConeTwistJointParam, real_t)
+ FUNC2RC(real_t, cone_twist_joint_get_param, RID, ConeTwistJointParam)
+
+ FUNC5(joint_make_generic_6dof, RID, RID, const Transform &, RID, const Transform &)
+
+ FUNC4(generic_6dof_joint_set_param, RID, Vector3::Axis, G6DOFJointAxisParam, real_t)
+ FUNC3RC(real_t, generic_6dof_joint_get_param, RID, Vector3::Axis, G6DOFJointAxisParam)
+
+ FUNC4(generic_6dof_joint_set_flag, RID, Vector3::Axis, G6DOFJointAxisFlag, bool)
+ FUNC3RC(bool, generic_6dof_joint_get_flag, RID, Vector3::Axis, G6DOFJointAxisFlag)
+
+ FUNC1RC(JointType, joint_get_type, RID);
+
+ FUNC2(joint_set_solver_priority, RID, int);
+ FUNC1RC(int, joint_get_solver_priority, RID);
+
+ FUNC2(joint_disable_collisions_between_bodies, RID, const bool);
+ FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID);
+
+ /* MISC */
+
+ FUNC1(free, RID);
+ FUNC1(set_active, bool);
+
+ virtual void init() override;
+ virtual void step(real_t p_step) override;
+ virtual void sync() override;
+ virtual void end_sync() override;
+ virtual void flush_queries() override;
+ virtual void finish() override;
+
+ virtual bool is_flushing_queries() const override {
+ return physics_3d_server->is_flushing_queries();
+ }
+
+ int get_process_info(ProcessInfo p_info) override {
+ return physics_3d_server->get_process_info(p_info);
+ }
+
+ PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread);
+ ~PhysicsServer3DWrapMT();
+
+#undef ServerNameWrapMT
+#undef ServerName
+#undef server_name
+#undef WRITE_ACTION
+};
+
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
+
+#endif // PHYSICS3DSERVERWRAPMT_H
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index 9c37060bea..ccd37ca742 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -30,14 +30,34 @@
#include "shape_3d_sw.h"
+#include "core/io/image.h"
#include "core/math/geometry_3d.h"
#include "core/math/quick_hull.h"
#include "core/templates/sort_array.h"
-#define _POINT_SNAP 0.001953125
+// HeightMapShape3DSW is based on Bullet btHeightfieldTerrainShape.
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002
#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998
+#define _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD 0.002
+#define _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD 0.999
+
void Shape3DSW::configure(const AABB &p_aabb) {
aabb = p_aabb;
configured = true;
@@ -50,7 +70,8 @@ void Shape3DSW::configure(const AABB &p_aabb) {
Vector3 Shape3DSW::get_support(const Vector3 &p_normal) const {
Vector3 res;
int amnt;
- get_supports(p_normal, 1, &res, amnt);
+ FeatureType type;
+ get_supports(p_normal, 1, &res, amnt, type);
return res;
}
@@ -167,16 +188,19 @@ Vector3 RayShape3DSW::get_support(const Vector3 &p_normal) const {
}
}
-void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 2;
+ r_type = FEATURE_EDGE;
r_supports[0] = Vector3(0, 0, 0);
r_supports[1] = Vector3(0, 0, length);
} else if (p_normal.z > 0) {
r_amount = 1;
+ r_type = FEATURE_POINT;
*r_supports = Vector3(0, 0, length);
} else {
r_amount = 1;
+ r_type = FEATURE_POINT;
*r_supports = Vector3(0, 0, 0);
}
}
@@ -246,9 +270,10 @@ Vector3 SphereShape3DSW::get_support(const Vector3 &p_normal) const {
return p_normal * radius;
}
-void SphereShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void SphereShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
*r_supports = p_normal * radius;
r_amount = 1;
+ r_type = FEATURE_POINT;
}
bool SphereShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
@@ -312,7 +337,7 @@ Vector3 BoxShape3DSW::get_support(const Vector3 &p_normal) const {
return point;
}
-void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
static const int next[3] = { 1, 2, 0 };
static const int next2[3] = { 2, 0, 1 };
@@ -325,6 +350,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s
bool neg = dot < 0;
r_amount = 4;
+ r_type = FEATURE_FACE;
Vector3 point;
point[i] = half_extents[i];
@@ -362,6 +388,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s
if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 2;
+ r_type = FEATURE_EDGE;
int i_n = next[i];
int i_n2 = next2[i];
@@ -389,6 +416,7 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s
(p_normal.z < 0) ? -half_extents.z : half_extents.z);
r_amount = 1;
+ r_type = FEATURE_POINT;
r_supports[0] = point;
}
@@ -481,10 +509,10 @@ BoxShape3DSW::BoxShape3DSW() {
void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
- real_t h = (n.z > 0) ? height : -height;
+ real_t h = (n.y > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
r_max = p_normal.dot(p_transform.xform(n));
r_min = p_normal.dot(p_transform.xform(-n));
@@ -493,36 +521,38 @@ void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p
Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const {
Vector3 n = p_normal;
- real_t h = (n.z > 0) ? height : -height;
+ real_t h = (n.y > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
return n;
}
-void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
Vector3 n = p_normal;
- real_t d = n.z;
+ real_t d = n.y;
if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
// make it flat
- n.z = 0.0;
+ n.y = 0.0;
n.normalize();
n *= radius;
r_amount = 2;
+ r_type = FEATURE_EDGE;
r_supports[0] = n;
- r_supports[0].z += height * 0.5;
+ r_supports[0].y += height * 0.5;
r_supports[1] = n;
- r_supports[1].z -= height * 0.5;
+ r_supports[1].y -= height * 0.5;
} else {
real_t h = (d > 0) ? height : -height;
n *= radius;
- n.z += h * 0.5;
+ n.y += h * 0.5;
r_amount = 1;
+ r_type = FEATURE_POINT;
*r_supports = n;
}
}
@@ -539,7 +569,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
// test against cylinder and spheres :-|
- collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn, 1);
if (collided) {
real_t d = norm.dot(auxres);
@@ -551,7 +581,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}
- collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * 0.5), radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5, 0), radius, &auxres, &auxn);
if (collided) {
real_t d = norm.dot(auxres);
@@ -563,7 +593,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}
- collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * -0.5), radius, &auxres, &auxn);
+ collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5, 0), radius, &auxres, &auxn);
if (collided) {
real_t d = norm.dot(auxres);
@@ -584,19 +614,19 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const {
- if (Math::abs(p_point.z) < height * 0.5) {
- return Vector3(p_point.x, p_point.y, 0).length() < radius;
+ if (Math::abs(p_point.y) < height * 0.5) {
+ return Vector3(p_point.x, 0, p_point.z).length() < radius;
} else {
Vector3 p = p_point;
- p.z = Math::abs(p.z) - height * 0.5;
+ p.y = Math::abs(p.y) - height * 0.5;
return p.length() < radius;
}
}
Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
Vector3 s[2] = {
- Vector3(0, 0, -height * 0.5),
- Vector3(0, 0, height * 0.5),
+ Vector3(0, -height * 0.5, 0),
+ Vector3(0, height * 0.5, 0),
};
Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s);
@@ -615,13 +645,13 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) {
height = p_height;
radius = p_radius;
- configure(AABB(Vector3(-radius, -radius, -height * 0.5 - radius), Vector3(radius * 2, radius * 2, height + radius * 2.0)));
+ configure(AABB(Vector3(-radius, -height * 0.5 - radius, -radius), Vector3(radius * 2, height + radius * 2.0, radius * 2)));
}
void CapsuleShape3DSW::set_data(const Variant &p_data) {
@@ -642,6 +672,186 @@ CapsuleShape3DSW::CapsuleShape3DSW() {
height = radius = 0;
}
+/********** CYLINDER *************/
+
+void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+ Vector3 cylinder_axis = p_transform.basis.get_axis(1).normalized();
+ real_t axis_dot = cylinder_axis.dot(p_normal);
+
+ Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
+ real_t scale = local_normal.length();
+ real_t scaled_radius = radius * scale;
+ real_t scaled_height = height * scale;
+
+ real_t length;
+ if (Math::abs(axis_dot) > 1.0) {
+ length = scaled_height * 0.5;
+ } else {
+ length = Math::abs(axis_dot * scaled_height * 0.5) + scaled_radius * Math::sqrt(1.0 - axis_dot * axis_dot);
+ }
+
+ real_t distance = p_normal.dot(p_transform.origin);
+
+ r_min = distance - length;
+ r_max = distance + length;
+}
+
+Vector3 CylinderShape3DSW::get_support(const Vector3 &p_normal) const {
+ Vector3 n = p_normal;
+ real_t h = (n.y > 0) ? height : -height;
+ real_t s = Math::sqrt(n.x * n.x + n.z * n.z);
+ if (Math::is_zero_approx(s)) {
+ n.x = radius;
+ n.y = h * 0.5;
+ n.z = 0.0;
+ } else {
+ real_t d = radius / s;
+ n.x = n.x * d;
+ n.y = h * 0.5;
+ n.z = n.z * d;
+ }
+
+ return n;
+}
+
+void CylinderShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
+ real_t d = p_normal.y;
+ if (Math::abs(d) > _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD) {
+ real_t h = (d > 0) ? height : -height;
+
+ Vector3 n = p_normal;
+ n.x = 0.0;
+ n.z = 0.0;
+ n.y = h * 0.5;
+
+ r_amount = 3;
+ r_type = FEATURE_CIRCLE;
+ r_supports[0] = n;
+ r_supports[1] = n;
+ r_supports[1].x += radius;
+ r_supports[2] = n;
+ r_supports[2].z += radius;
+ } else if (Math::abs(d) < _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+ // make it flat
+ Vector3 n = p_normal;
+ n.y = 0.0;
+ n.normalize();
+ n *= radius;
+
+ r_amount = 2;
+ r_type = FEATURE_EDGE;
+ r_supports[0] = n;
+ r_supports[0].y += height * 0.5;
+ r_supports[1] = n;
+ r_supports[1].y -= height * 0.5;
+ } else {
+ r_amount = 1;
+ r_type = FEATURE_POINT;
+ r_supports[0] = get_support(p_normal);
+ return;
+
+ Vector3 n = p_normal;
+ real_t h = n.y * Math::sqrt(0.25 * height * height + radius * radius);
+ if (Math::abs(h) > 1.0) {
+ // Top or bottom surface.
+ n.y = (n.y > 0.0) ? height * 0.5 : -height * 0.5;
+ } else {
+ // Lateral surface.
+ n.y = height * 0.5 * h;
+ }
+
+ real_t s = Math::sqrt(n.x * n.x + n.z * n.z);
+ if (Math::is_zero_approx(s)) {
+ n.x = 0.0;
+ n.z = 0.0;
+ } else {
+ real_t scaled_radius = radius / s;
+ n.x = n.x * scaled_radius;
+ n.z = n.z * scaled_radius;
+ }
+
+ r_supports[0] = n;
+ }
+}
+
+bool CylinderShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+ return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1);
+}
+
+bool CylinderShape3DSW::intersect_point(const Vector3 &p_point) const {
+ if (Math::abs(p_point.y) < height * 0.5) {
+ return Vector3(p_point.x, 0, p_point.z).length() < radius;
+ }
+ return false;
+}
+
+Vector3 CylinderShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+ if (Math::absf(p_point.y) > height * 0.5) {
+ // Project point to top disk.
+ real_t dir = p_point.y > 0.0 ? 1.0 : -1.0;
+ Vector3 circle_pos(0.0, dir * height * 0.5, 0.0);
+ Plane circle_plane(circle_pos, Vector3(0.0, dir, 0.0));
+ Vector3 proj_point = circle_plane.project(p_point);
+
+ // Clip position.
+ Vector3 delta_point_1 = proj_point - circle_pos;
+ real_t dist_point_1 = delta_point_1.length_squared();
+ if (!Math::is_zero_approx(dist_point_1)) {
+ dist_point_1 = Math::sqrt(dist_point_1);
+ proj_point = circle_pos + delta_point_1 * MIN(dist_point_1, radius) / dist_point_1;
+ }
+
+ return proj_point;
+ } else {
+ Vector3 s[2] = {
+ Vector3(0, -height * 0.5, 0),
+ Vector3(0, height * 0.5, 0),
+ };
+
+ Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s);
+
+ if (p.distance_to(p_point) < radius) {
+ return p_point;
+ }
+
+ return p + (p_point - p).normalized() * radius;
+ }
+}
+
+Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+ // use bad AABB approximation
+ Vector3 extents = get_aabb().size * 0.5;
+
+ return Vector3(
+ (p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
+ (p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
+}
+
+void CylinderShape3DSW::_setup(real_t p_height, real_t p_radius) {
+ height = p_height;
+ radius = p_radius;
+ configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0)));
+}
+
+void CylinderShape3DSW::set_data(const Variant &p_data) {
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("radius"));
+ ERR_FAIL_COND(!d.has("height"));
+ _setup(d["height"], d["radius"]);
+}
+
+Variant CylinderShape3DSW::get_data() const {
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ return d;
+}
+
+CylinderShape3DSW::CylinderShape3DSW() {
+ height = radius = 0;
+}
+
/********** CONVEX POLYGON *************/
void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
@@ -689,7 +899,7 @@ Vector3 ConvexPolygonShape3DSW::get_support(const Vector3 &p_normal) const {
return vrts[vert_support_idx];
}
-void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
int fc = mesh.faces.size();
@@ -699,6 +909,9 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve
const Vector3 *vertices = mesh.vertices.ptr();
int vc = mesh.vertices.size();
+ r_amount = 0;
+ ERR_FAIL_COND_MSG(vc == 0, "Convex polygon shape has no vertices.");
+
//find vertex first
real_t max = 0;
int vtx = 0;
@@ -734,6 +947,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve
r_supports[j] = vertices[ind[j]];
}
r_amount = m;
+ r_type = FEATURE_FACE;
return;
}
}
@@ -743,6 +957,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve
dot = ABS(dot);
if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) {
r_amount = 2;
+ r_type = FEATURE_EDGE;
r_supports[0] = vertices[edges[i].a];
r_supports[1] = vertices[edges[i].b];
return;
@@ -751,6 +966,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve
r_supports[0] = vertices[vtx];
r_amount = 1;
+ r_type = FEATURE_POINT;
}
bool ConvexPolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
@@ -869,7 +1085,7 @@ Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) {
@@ -935,12 +1151,13 @@ Vector3 FaceShape3DSW::get_support(const Vector3 &p_normal) const {
return vertex[vert_support_idx];
}
-void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
Vector3 n = p_normal;
/** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+ if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 3;
+ r_type = FEATURE_FACE;
for (int i = 0; i < 3; i++) {
r_supports[i] = vertex[i];
}
@@ -974,6 +1191,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_
dot = ABS(dot);
if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
r_amount = 2;
+ r_type = FEATURE_EDGE;
r_supports[0] = vertex[i];
r_supports[1] = vertex[nx];
return;
@@ -981,6 +1199,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_
}
r_amount = 1;
+ r_type = FEATURE_POINT;
r_supports[0] = vertex[vert_support_idx];
}
@@ -989,7 +1208,11 @@ bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_e
if (c) {
r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
if (r_normal.dot(p_end - p_begin) > 0) {
- r_normal = -r_normal;
+ if (backface_collision) {
+ r_normal = -r_normal;
+ } else {
+ c = false;
+ }
}
}
@@ -1087,30 +1310,24 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par
}
if (bvh->face_index >= 0) {
- Vector3 res;
- Vector3 vertices[3] = {
- p_params->vertices[p_params->faces[bvh->face_index].indices[0]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[1]],
- p_params->vertices[p_params->faces[bvh->face_index].indices[2]]
- };
+ const Face *f = &p_params->faces[bvh->face_index];
+ FaceShape3DSW *face = p_params->face;
+ face->normal = f->normal;
+ face->vertex[0] = p_params->vertices[f->indices[0]];
+ face->vertex[1] = p_params->vertices[f->indices[1]];
+ face->vertex[2] = p_params->vertices[f->indices[2]];
- if (Geometry3D::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
+ Vector3 res;
+ Vector3 normal;
+ if (face->intersect_segment(p_params->from, p_params->to, res, normal)) {
real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
- //TODO, seems segmen/triangle intersection is broken :(
- if (d > 0 && d < p_params->min_d) {
+ if ((d > 0) && (d < p_params->min_d)) {
p_params->min_d = d;
p_params->result = res;
- p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
+ p_params->normal = normal;
p_params->collisions++;
}
}
-
} else {
if (bvh->left >= 0) {
_cull_segment(bvh->left, p_params);
@@ -1131,17 +1348,20 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve
const Vector3 *vr = vertices.ptr();
const BVH *br = bvh.ptr();
+ FaceShape3DSW face;
+ face.backface_collision = backface_collision;
+
_SegmentCullParams params;
params.from = p_begin;
params.to = p_end;
- params.collisions = 0;
params.dir = (p_end - p_begin).normalized();
params.faces = fr;
params.vertices = vr;
params.bvh = br;
- params.min_d = 1e20;
+ params.face = &face;
+
// cull
_cull_segment(0, &params);
@@ -1203,6 +1423,7 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback
const BVH *br = bvh.ptr();
FaceShape3DSW face; // use this to send in the callback
+ face.backface_collision = backface_collision;
_CullParams params;
params.aabb = local_aabb;
@@ -1224,7 +1445,7 @@ Vector3 ConcavePolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
struct _VolumeSW_BVH_Element {
@@ -1334,7 +1555,7 @@ void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_ar
memdelete(p_bvh_tree);
}
-void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
+void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) {
int src_face_count = p_faces.size();
if (src_face_count == 0) {
configure(AABB());
@@ -1389,15 +1610,24 @@ void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
int idx = 0;
_fill_bvh(bvh_tree, bvh_arrayw2, idx);
+ backface_collision = p_backface_collision;
+
configure(_aabb); // this type of shape has no margin
}
void ConcavePolygonShape3DSW::set_data(const Variant &p_data) {
- _setup(p_data);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("faces"));
+
+ _setup(d["faces"], d["backface_collision"]);
}
Variant ConcavePolygonShape3DSW::get_data() const {
- return get_faces();
+ Dictionary d;
+ d["faces"] = get_faces();
+ d["backface_collision"] = backface_collision;
+
+ return d;
}
ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
@@ -1405,7 +1635,7 @@ ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
/* HEIGHT MAP SHAPE */
-Vector<real_t> HeightMapShape3DSW::get_heights() const {
+Vector<float> HeightMapShape3DSW::get_heights() const {
return heights;
}
@@ -1417,10 +1647,6 @@ int HeightMapShape3DSW::get_depth() const {
return depth;
}
-real_t HeightMapShape3DSW::get_cell_size() const {
- return cell_size;
-}
-
void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
//not very useful, but not very used either
p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal, 0), r_min, r_max);
@@ -1431,7 +1657,198 @@ Vector3 HeightMapShape3DSW::get_support(const Vector3 &p_normal) const {
return get_aabb().get_support(p_normal);
}
+struct _HeightmapSegmentCullParams {
+ Vector3 from;
+ Vector3 to;
+ Vector3 dir;
+
+ Vector3 result;
+ Vector3 normal;
+
+ const HeightMapShape3DSW *heightmap = nullptr;
+ FaceShape3DSW *face = nullptr;
+};
+
+_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
+ Vector3 res;
+ Vector3 normal;
+ if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal)) {
+ p_params.result = res;
+ p_params.normal = normal;
+ return true;
+ }
+
+ return false;
+}
+
+_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) {
+ // First triangle.
+ p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]);
+ p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]);
+ p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]);
+ p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
+ if (_heightmap_face_cull_segment(p_params)) {
+ return true;
+ }
+
+ // Second triangle.
+ p_params.face->vertex[0] = p_params.face->vertex[1];
+ p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]);
+ p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
+ if (_heightmap_face_cull_segment(p_params)) {
+ return true;
+ }
+
+ return false;
+}
+
bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
+ if (heights.is_empty()) {
+ return false;
+ }
+
+ Vector3 local_begin = p_begin + local_origin;
+ Vector3 local_end = p_end + local_origin;
+
+ FaceShape3DSW face;
+ face.backface_collision = false;
+
+ _HeightmapSegmentCullParams params;
+ params.from = p_begin;
+ params.to = p_end;
+ params.dir = (p_end - p_begin).normalized();
+ params.heightmap = this;
+ params.face = &face;
+
+ // Quantize the ray begin/end.
+ int begin_x = floor(local_begin.x);
+ int begin_z = floor(local_begin.z);
+ int end_x = floor(local_end.x);
+ int end_z = floor(local_end.z);
+
+ if ((begin_x == end_x) && (begin_z == end_z)) {
+ // Simple case for rays that don't traverse the grid horizontally.
+ // Just perform a test on the given cell.
+ int x = CLAMP(begin_x, 0, width - 2);
+ int z = CLAMP(begin_z, 0, depth - 2);
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+ } else {
+ // Perform grid query from projected ray.
+ Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z);
+ real_t ray_dist_proj = ray_dir_proj.length();
+
+ if (ray_dist_proj < CMP_EPSILON) {
+ ray_dir_proj = Vector2();
+ } else {
+ ray_dir_proj /= ray_dist_proj;
+ }
+
+ const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0);
+ const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0);
+
+ const real_t infinite = 1e20;
+ const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite;
+ const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite;
+
+ real_t cross_x; // At which value of `param` we will cross a x-axis lane?
+ real_t cross_z; // At which value of `param` we will cross a z-axis lane?
+
+ // X initialization.
+ if (x_step != 0) {
+ if (x_step == 1) {
+ cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x;
+ } else {
+ cross_x = (local_begin.x - floor(local_begin.x)) * delta_x;
+ }
+ } else {
+ cross_x = infinite; // Will never cross on X.
+ }
+
+ // Z initialization.
+ if (z_step != 0) {
+ if (z_step == 1) {
+ cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z;
+ } else {
+ cross_z = (local_begin.z - floor(local_begin.z)) * delta_z;
+ }
+ } else {
+ cross_z = infinite; // Will never cross on Z.
+ }
+
+ int x = floor(local_begin.x);
+ int z = floor(local_begin.z);
+
+ // Workaround cases where the ray starts at an integer position.
+ if (Math::abs(cross_x) < CMP_EPSILON) {
+ cross_x += delta_x;
+ // If going backwards, we should ignore the position we would get by the above flooring,
+ // because the ray is not heading in that direction.
+ if (x_step == -1) {
+ x -= 1;
+ }
+ }
+
+ if (Math::abs(cross_z) < CMP_EPSILON) {
+ cross_z += delta_z;
+ if (z_step == -1) {
+ z -= 1;
+ }
+ }
+
+ // Start inside the grid.
+ int x_start = CLAMP(x, 0, width - 2);
+ int z_start = CLAMP(z, 0, depth - 2);
+
+ // Adjust initial cross values.
+ cross_x += delta_x * x_step * (x_start - x);
+ cross_z += delta_z * z_step * (z_start - z);
+
+ x = x_start;
+ z = z_start;
+
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+
+ real_t dist = 0.0;
+ while (true) {
+ if (cross_x < cross_z) {
+ // X lane.
+ x += x_step;
+ // Assign before advancing the param,
+ // to be in sync with the initialization step.
+ dist = cross_x;
+ cross_x += delta_x;
+ } else {
+ // Z lane.
+ z += z_step;
+ dist = cross_z;
+ cross_z += delta_z;
+ }
+
+ // Stop when outside the grid.
+ if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) {
+ break;
+ }
+
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+
+ if (dist > ray_dist_proj) {
+ break;
+ }
+ }
+ }
+
return false;
}
@@ -1443,7 +1860,66 @@ Vector3 HeightMapShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
return Vector3();
}
+void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const {
+ const AABB &aabb = get_aabb();
+
+ Vector3 pos_local = aabb.position + local_origin;
+
+ Vector3 clamped_point(p_point);
+ clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + aabb.size.x);
+ clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + aabb.size.y);
+ clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.x + aabb.size.z);
+
+ r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5);
+ r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5);
+ r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5);
+}
+
void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+ if (heights.is_empty()) {
+ return;
+ }
+
+ AABB local_aabb = p_local_aabb;
+ local_aabb.position += local_origin;
+
+ // Quantize the aabb, and adjust the start/end ranges.
+ int aabb_min[3];
+ int aabb_max[3];
+ _get_cell(local_aabb.position, aabb_min[0], aabb_min[1], aabb_min[2]);
+ _get_cell(local_aabb.position + local_aabb.size, aabb_max[0], aabb_max[1], aabb_max[2]);
+
+ // Expand the min/max quantized values.
+ // This is to catch the case where the input aabb falls between grid points.
+ for (int i = 0; i < 3; ++i) {
+ aabb_min[i]--;
+ aabb_max[i]++;
+ }
+
+ int start_x = MAX(0, aabb_min[0]);
+ int end_x = MIN(width - 1, aabb_max[0]);
+ int start_z = MAX(0, aabb_min[2]);
+ int end_z = MIN(depth - 1, aabb_max[2]);
+
+ FaceShape3DSW face;
+ face.backface_collision = true;
+
+ for (int z = start_z; z < end_z; z++) {
+ for (int x = start_x; x < end_x; x++) {
+ // First triangle.
+ _get_point(x, z, face.vertex[0]);
+ _get_point(x + 1, z, face.vertex[1]);
+ _get_point(x, z + 1, face.vertex[2]);
+ face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ p_callback(p_userdata, &face);
+
+ // Second triangle.
+ face.vertex[0] = face.vertex[1];
+ _get_point(x + 1, z + 1, face.vertex[1]);
+ face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ p_callback(p_userdata, &face);
+ }
+ }
}
Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
@@ -1453,61 +1929,105 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
-void HeightMapShape3DSW::_setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size) {
+void HeightMapShape3DSW::_setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
heights = p_heights;
width = p_width;
depth = p_depth;
- cell_size = p_cell_size;
-
- const real_t *r = heights.ptr();
+ // Initialize aabb.
AABB aabb;
+ aabb.position = Vector3(0.0, p_min_height, 0.0);
+ aabb.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1);
- for (int i = 0; i < depth; i++) {
- for (int j = 0; j < width; j++) {
- real_t h = r[i * width + j];
+ // Initialize origin as the aabb center.
+ local_origin = aabb.position + 0.5 * aabb.size;
+ local_origin.y = 0.0;
- Vector3 pos(j * cell_size, h, i * cell_size);
- if (i == 0 || j == 0) {
- aabb.position = pos;
- } else {
- aabb.expand_to(pos);
- }
- }
- }
+ aabb.position -= local_origin;
configure(aabb);
}
void HeightMapShape3DSW::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY);
+
Dictionary d = p_data;
ERR_FAIL_COND(!d.has("width"));
ERR_FAIL_COND(!d.has("depth"));
- ERR_FAIL_COND(!d.has("cell_size"));
ERR_FAIL_COND(!d.has("heights"));
int width = d["width"];
int depth = d["depth"];
- real_t cell_size = d["cell_size"];
- Vector<real_t> heights = d["heights"];
- ERR_FAIL_COND(width <= 0);
- ERR_FAIL_COND(depth <= 0);
- ERR_FAIL_COND(cell_size <= CMP_EPSILON);
- ERR_FAIL_COND(heights.size() != (width * depth));
- _setup(heights, width, depth, cell_size);
+ ERR_FAIL_COND(width <= 0.0);
+ ERR_FAIL_COND(depth <= 0.0);
+
+ Variant heights_variant = d["heights"];
+ Vector<float> heights_buffer;
+ if (heights_variant.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+ // Ready-to-use heights can be passed.
+ heights_buffer = heights_variant;
+ } else if (heights_variant.get_type() == Variant::OBJECT) {
+ // If an image is passed, we have to convert it.
+ // This would be expensive to do with a script, so it's nice to have it here.
+ Ref<Image> image = heights_variant;
+ ERR_FAIL_COND(image.is_null());
+ ERR_FAIL_COND(image->get_format() != Image::FORMAT_RF);
+
+ PackedByteArray im_data = image->get_data();
+ heights_buffer.resize(image->get_width() * image->get_height());
+
+ float *w = heights_buffer.ptrw();
+ float *rp = (float *)im_data.ptr();
+ for (int i = 0; i < heights_buffer.size(); ++i) {
+ w[i] = rp[i];
+ }
+ } else {
+ ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
+ }
+
+ // Compute min and max heights or use precomputed values.
+ real_t min_height = 0.0;
+ real_t max_height = 0.0;
+ if (d.has("min_height") && d.has("max_height")) {
+ min_height = d["min_height"];
+ max_height = d["max_height"];
+ } else {
+ int heights_size = heights.size();
+ for (int i = 0; i < heights_size; ++i) {
+ float h = heights[i];
+ if (h < min_height) {
+ min_height = h;
+ } else if (h > max_height) {
+ max_height = h;
+ }
+ }
+ }
+
+ ERR_FAIL_COND(min_height > max_height);
+
+ ERR_FAIL_COND(heights_buffer.size() != (width * depth));
+
+ // If specified, min and max height will be used as precomputed values.
+ _setup(heights_buffer, width, depth, min_height, max_height);
}
Variant HeightMapShape3DSW::get_data() const {
- ERR_FAIL_V(Variant());
+ Dictionary d;
+ d["width"] = width;
+ d["depth"] = depth;
+
+ const AABB &aabb = get_aabb();
+ d["min_height"] = aabb.position.y;
+ d["max_height"] = aabb.position.y + aabb.size.y;
+
+ d["heights"] = heights;
+
+ return d;
}
HeightMapShape3DSW::HeightMapShape3DSW() {
- width = 0;
- depth = 0;
- cell_size = 0;
}
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index 851c0d9443..4d2b6ffbed 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -67,8 +67,11 @@ protected:
void configure(const AABB &p_aabb);
public:
- enum {
- MAX_SUPPORTS = 8
+ enum FeatureType {
+ FEATURE_POINT,
+ FEATURE_EDGE,
+ FEATURE_FACE,
+ FEATURE_CIRCLE,
};
virtual real_t get_area() const { return aabb.get_area(); }
@@ -78,14 +81,14 @@ public:
virtual PhysicsServer3D::ShapeType get_type() const = 0;
- _FORCE_INLINE_ AABB get_aabb() const { return aabb; }
+ _FORCE_INLINE_ const AABB &get_aabb() const { return aabb; }
_FORCE_INLINE_ bool is_configured() const { return configured; }
virtual bool is_concave() const { return false; }
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const = 0;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const = 0;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const = 0;
virtual bool intersect_point(const Vector3 &p_point) const = 0;
@@ -110,7 +113,7 @@ class ConcaveShape3DSW : public Shape3DSW {
public:
virtual bool is_concave() const { return true; }
typedef void (*Callback)(void *p_userdata, Shape3DSW *p_convex);
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
virtual void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
@@ -129,7 +132,7 @@ public:
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_PLANE; }
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
@@ -156,7 +159,7 @@ public:
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_RAY; }
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
@@ -184,7 +187,7 @@ public:
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
@@ -209,7 +212,7 @@ public:
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
@@ -238,7 +241,7 @@ public:
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
@@ -251,6 +254,35 @@ public:
CapsuleShape3DSW();
};
+class CylinderShape3DSW : public Shape3DSW {
+ real_t height;
+ real_t radius;
+
+ void _setup(real_t p_height, real_t p_radius);
+
+public:
+ _FORCE_INLINE_ real_t get_height() const { return height; }
+ _FORCE_INLINE_ real_t get_radius() const { return radius; }
+
+ virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CYLINDER; }
+
+ virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
+ virtual Vector3 get_support(const Vector3 &p_normal) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
+ virtual bool intersect_point(const Vector3 &p_point) const;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
+
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
+
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+
+ CylinderShape3DSW();
+};
+
struct ConvexPolygonShape3DSW : public Shape3DSW {
Geometry3D::MeshData mesh;
@@ -263,7 +295,7 @@ public:
virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
@@ -302,34 +334,37 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
struct _CullParams {
AABB aabb;
- Callback callback;
- void *userdata;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- FaceShape3DSW *face;
+ Callback callback = nullptr;
+ void *userdata = nullptr;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
};
struct _SegmentCullParams {
Vector3 from;
Vector3 to;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
Vector3 dir;
+ const Face *faces = nullptr;
+ const Vector3 *vertices = nullptr;
+ const BVH *bvh = nullptr;
+ FaceShape3DSW *face = nullptr;
Vector3 result;
Vector3 normal;
- real_t min_d;
- int collisions;
+ real_t min_d = 1e20;
+ int collisions = 0;
};
+ bool backface_collision = false;
+
void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;
void _cull(int p_idx, _CullParams *p_params) const;
void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);
- void _setup(Vector<Vector3> p_faces);
+ void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision);
public:
Vector<Vector3> get_faces() const;
@@ -354,21 +389,29 @@ public:
};
struct HeightMapShape3DSW : public ConcaveShape3DSW {
- Vector<real_t> heights;
- int width;
- int depth;
- real_t cell_size;
+ Vector<float> heights;
+ int width = 0;
+ int depth = 0;
+ Vector3 local_origin;
+
+ _FORCE_INLINE_ float _get_height(int p_x, int p_z) const {
+ return heights[(p_z * width) + p_x];
+ }
+
+ _FORCE_INLINE_ void _get_point(int p_x, int p_z, Vector3 &r_point) const {
+ r_point.x = p_x - 0.5 * (width - 1.0);
+ r_point.y = _get_height(p_x, p_z);
+ r_point.z = p_z - 0.5 * (depth - 1.0);
+ }
- //void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
- //void _cull(int p_idx,_CullParams *p_params) const;
+ void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const;
- void _setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size);
+ void _setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
public:
- Vector<real_t> get_heights() const;
+ Vector<float> get_heights() const;
int get_width() const;
int get_depth() const;
- real_t get_cell_size() const;
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; }
@@ -392,6 +435,7 @@ public:
struct FaceShape3DSW : public Shape3DSW {
Vector3 normal; //cache
Vector3 vertex[3];
+ bool backface_collision = false;
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
@@ -399,7 +443,7 @@ struct FaceShape3DSW : public Shape3DSW {
void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const;
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
virtual bool intersect_point(const Vector3 &p_point) const;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
@@ -437,7 +481,7 @@ struct MotionShape3DSW : public Shape3DSW {
}
return support;
}
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const { r_amount = 0; }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { return false; }
virtual bool intersect_point(const Vector3 &p_point) const { return false; }
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const { return p_point; }
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
new file mode 100644
index 0000000000..f63a470cbe
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -0,0 +1,1221 @@
+/*************************************************************************/
+/* soft_body_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "soft_body_3d_sw.h"
+#include "space_3d_sw.h"
+
+#include "core/math/geometry_3d.h"
+#include "core/templates/map.h"
+
+// Based on Bullet soft body.
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+///btSoftBody implementation by Nathanael Presson
+
+SoftBody3DSW::SoftBody3DSW() :
+ CollisionObject3DSW(TYPE_SOFT_BODY),
+ active_list(this) {
+ _set_static(false);
+}
+
+void SoftBody3DSW::_shapes_changed() {
+}
+
+void SoftBody3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().inverse());
+
+ apply_nodes_transform(get_transform());
+
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ // Not supported.
+ ERR_FAIL_MSG("Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_MSG("Angular velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+}
+
+Variant SoftBody3DSW::get_state(PhysicsServer3D::BodyState p_state) const {
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+ return get_transform();
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Linear velocity is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ ERR_FAIL_V_MSG(Vector3(), "Angular velocity is not supported for Soft bodies.");
+ return Vector3();
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
+ } break;
+ }
+
+ return Variant();
+}
+
+void SoftBody3DSW::set_space(Space3DSW *p_space) {
+ if (get_space()) {
+ get_space()->soft_body_remove_from_active_list(&active_list);
+
+ deinitialize_shape();
+ }
+
+ _set_space(p_space);
+
+ if (get_space()) {
+ get_space()->soft_body_add_to_active_list(&active_list);
+
+ if (bounds != AABB()) {
+ initialize_shape(true);
+ }
+ }
+}
+
+void SoftBody3DSW::set_mesh(const Ref<Mesh> &p_mesh) {
+ destroy();
+
+ soft_mesh = p_mesh;
+
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ Array arrays = soft_mesh->surface_get_arrays(0);
+ ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX));
+
+ bool success = create_from_trimesh(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
+ if (!success) {
+ destroy();
+ soft_mesh = Ref<Mesh>();
+ }
+}
+
+void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ const uint32_t vertex_count = map_visual_to_physics.size();
+ for (uint32_t i = 0; i < vertex_count; ++i) {
+ const uint32_t node_index = map_visual_to_physics[i];
+ const Node &node = nodes[node_index];
+ const Vector3 &vertex_position = node.x;
+ const Vector3 &vertex_normal = node.n;
+
+ p_rendering_server_handler->set_vertex(i, &vertex_position);
+ p_rendering_server_handler->set_normal(i, &vertex_normal);
+ }
+
+ p_rendering_server_handler->set_aabb(bounds);
+}
+
+void SoftBody3DSW::update_normals() {
+ uint32_t i, ni;
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].n = Vector3();
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+ const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x);
+ face.n[0]->n += n;
+ face.n[1]->n += n;
+ face.n[2]->n += n;
+ face.normal = n;
+ face.normal.normalize();
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ real_t len = node.n.length();
+ if (len > CMP_EPSILON) {
+ node.n /= len;
+ }
+ }
+}
+
+void SoftBody3DSW::update_bounds() {
+ AABB prev_bounds = bounds;
+ prev_bounds.grow_by(collision_margin);
+
+ bounds = AABB();
+
+ const uint32_t nodes_count = nodes.size();
+ if (nodes_count == 0) {
+ deinitialize_shape();
+ return;
+ }
+
+ bool first = true;
+ bool moved = false;
+ for (uint32_t node_index = 0; node_index < nodes_count; ++node_index) {
+ const Node &node = nodes[node_index];
+ if (!prev_bounds.has_point(node.x)) {
+ moved = true;
+ }
+ if (first) {
+ bounds.position = node.x;
+ first = false;
+ } else {
+ bounds.expand_to(node.x);
+ }
+ }
+
+ if (get_space()) {
+ initialize_shape(moved);
+ }
+}
+
+void SoftBody3DSW::update_constants() {
+ reset_link_rest_lengths();
+ update_link_constants();
+ update_area();
+}
+
+void SoftBody3DSW::update_area() {
+ int i, ni;
+
+ // Face area.
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ Face &face = faces[i];
+
+ const Vector3 &x0 = face.n[0]->x;
+ const Vector3 &x1 = face.n[1]->x;
+ const Vector3 &x2 = face.n[2]->x;
+
+ const Vector3 a = x1 - x0;
+ const Vector3 b = x2 - x0;
+ const Vector3 cr = vec3_cross(a, b);
+ face.ra = cr.length();
+ }
+
+ // Node area.
+ LocalVector<int> counts;
+ counts.resize(nodes.size());
+ memset(counts.ptr(), 0, counts.size() * sizeof(int));
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ nodes[i].area = 0.0;
+ }
+
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ for (int j = 0; j < 3; ++j) {
+ const int index = (int)(face.n[j] - &nodes[0]);
+ counts[index]++;
+ face.n[j]->area += Math::abs(face.ra);
+ }
+ }
+
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ if (counts[i] > 0) {
+ nodes[i].area /= (real_t)counts[i];
+ } else {
+ nodes[i].area = 0.0;
+ }
+ }
+}
+
+void SoftBody3DSW::reset_link_rest_lengths() {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.rl = (link.n[0]->x - link.n[1]->x).length();
+ link.c1 = link.rl * link.rl;
+ }
+}
+
+void SoftBody3DSW::update_link_constants() {
+ real_t inv_linear_stiffness = 1.0 / linear_stiffness;
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness;
+ }
+}
+
+void SoftBody3DSW::apply_nodes_transform(const Transform &p_transform) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ uint32_t node_count = nodes.size();
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+
+ node.x = p_transform.xform(node.x);
+ node.q = node.x;
+ node.v = Vector3();
+ node.bv = Vector3();
+
+ AABB node_aabb(node.x, leaf_size);
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ face_tree.clear();
+
+ update_normals();
+ update_bounds();
+ update_constants();
+}
+
+Vector3 SoftBody3DSW::get_vertex_position(int p_index) const {
+ if (soft_mesh.is_null()) {
+ return Vector3();
+ }
+
+ ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());
+ return nodes[node_index].x;
+}
+
+void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) {
+ if (soft_mesh.is_null()) {
+ return;
+ }
+
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.q = node.x;
+ node.x = p_position;
+}
+
+void SoftBody3DSW::pin_vertex(int p_index) {
+ if (is_vertex_pinned(p_index)) {
+ return;
+ }
+
+ pinned_vertices.push_back(p_index);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+}
+
+void SoftBody3DSW::unpin_vertex(int p_index) {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ pinned_vertices.remove(i);
+
+ if (!soft_mesh.is_null()) {
+ ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[p_index];
+
+ ERR_FAIL_COND(node_index >= nodes.size());
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+
+ return;
+ }
+ }
+}
+
+void SoftBody3DSW::unpin_all_vertices() {
+ if (!soft_mesh.is_null()) {
+ real_t inv_node_mass = nodes.size() * inv_total_mass;
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ uint32_t vertex_index = pinned_vertices[i];
+
+ ERR_CONTINUE(vertex_index >= map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[vertex_index];
+
+ ERR_CONTINUE(node_index >= nodes.size());
+ Node &node = nodes[node_index];
+ node.im = inv_node_mass;
+ }
+ }
+
+ pinned_vertices.clear();
+}
+
+bool SoftBody3DSW::is_vertex_pinned(int p_index) const {
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ if (p_index == pinned_vertices[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint32_t SoftBody3DSW::get_node_count() const {
+ return nodes.size();
+}
+
+real_t SoftBody3DSW::get_node_inv_mass(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), 0.0);
+ return nodes[p_node_index].im;
+}
+
+Vector3 SoftBody3DSW::get_node_position(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].x;
+}
+
+Vector3 SoftBody3DSW::get_node_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].v;
+}
+
+Vector3 SoftBody3DSW::get_node_biased_velocity(uint32_t p_node_index) const {
+ ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3());
+ return nodes[p_node_index].bv;
+}
+
+void SoftBody3DSW::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.v += p_impulse * node.im;
+}
+
+void SoftBody3DSW::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND(p_node_index >= nodes.size());
+ Node &node = nodes[p_node_index];
+ node.bv += p_impulse * node.im;
+}
+
+uint32_t SoftBody3DSW::get_face_count() const {
+ return faces.size();
+}
+
+void SoftBody3DSW::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const {
+ ERR_FAIL_COND(p_face_index >= faces.size());
+ const Face &face = faces[p_face_index];
+ r_point_1 = face.n[0]->x;
+ r_point_2 = face.n[1]->x;
+ r_point_3 = face.n[2]->x;
+}
+
+Vector3 SoftBody3DSW::get_face_normal(uint32_t p_face_index) const {
+ ERR_FAIL_COND_V(p_face_index >= faces.size(), Vector3());
+ return faces[p_face_index].normal;
+}
+
+bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) {
+ uint32_t node_count = 0;
+ LocalVector<Vector3> vertices;
+ const int visual_vertex_count(p_vertices.size());
+
+ LocalVector<int> triangles;
+ const uint32_t triangle_count(p_indices.size() / 3);
+ triangles.resize(triangle_count * 3);
+
+ // Merge all overlapping vertices and create a map of physical vertices to visual vertices.
+ {
+ // Process vertices.
+ {
+ uint32_t vertex_count = 0;
+ Map<Vector3, uint32_t> unique_vertices;
+
+ vertices.resize(visual_vertex_count);
+ map_visual_to_physics.resize(visual_vertex_count);
+
+ for (int visual_vertex_index = 0; visual_vertex_index < visual_vertex_count; ++visual_vertex_index) {
+ const Vector3 &vertex = p_vertices[visual_vertex_index];
+
+ Map<Vector3, uint32_t>::Element *e = unique_vertices.find(vertex);
+ uint32_t vertex_id;
+ if (e) {
+ // Already existing.
+ vertex_id = e->value();
+ } else {
+ // Create new one.
+ vertex_id = vertex_count++;
+ unique_vertices[vertex] = vertex_id;
+ vertices[vertex_id] = vertex;
+ }
+
+ map_visual_to_physics[visual_vertex_index] = vertex_id;
+ }
+
+ vertices.resize(vertex_count);
+ }
+
+ // Process triangles.
+ {
+ for (uint32_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) {
+ for (int i = 0; i < 3; ++i) {
+ int visual_index = 3 * triangle_index + i;
+ int physics_index = map_visual_to_physics[p_indices[visual_index]];
+ triangles[visual_index] = physics_index;
+ node_count = MAX((int)node_count, physics_index);
+ }
+ }
+ }
+ }
+
+ ++node_count;
+
+ // Create nodes from vertices.
+ nodes.resize(node_count);
+ real_t inv_node_mass = node_count * inv_total_mass;
+ Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
+ for (uint32_t i = 0; i < node_count; ++i) {
+ Node &node = nodes[i];
+ node.s = vertices[i];
+ node.x = node.s;
+ node.q = node.s;
+ node.im = inv_node_mass;
+
+ AABB node_aabb(node.x, leaf_size);
+ node.leaf = node_tree.insert(node_aabb, &node);
+
+ node.index = i;
+ }
+
+ // Create links and faces from triangles.
+ LocalVector<bool> chks;
+ chks.resize(node_count * node_count);
+ memset(chks.ptr(), 0, chks.size() * sizeof(bool));
+
+ for (uint32_t i = 0; i < triangle_count * 3; i += 3) {
+ const int idx[] = { triangles[i], triangles[i + 1], triangles[i + 2] };
+
+ for (int j = 2, k = 0; k < 3; j = k++) {
+ int chk = idx[k] * node_count + idx[j];
+ if (!chks[chk]) {
+ chks[chk] = true;
+ int inv_chk = idx[j] * node_count + idx[k];
+ chks[inv_chk] = true;
+
+ append_link(idx[j], idx[k]);
+ }
+ }
+
+ append_face(idx[0], idx[1], idx[2]);
+ }
+
+ // Set pinned nodes.
+ uint32_t pinned_count = pinned_vertices.size();
+ for (uint32_t i = 0; i < pinned_count; ++i) {
+ int pinned_vertex = pinned_vertices[i];
+
+ ERR_CONTINUE(pinned_vertex >= visual_vertex_count);
+ uint32_t node_index = map_visual_to_physics[pinned_vertex];
+
+ ERR_CONTINUE(node_index >= node_count);
+ Node &node = nodes[node_index];
+ node.im = 0.0;
+ }
+
+ generate_bending_constraints(2);
+ reoptimize_link_order();
+
+ update_constants();
+ update_normals();
+ update_bounds();
+
+ return true;
+}
+
+void SoftBody3DSW::generate_bending_constraints(int p_distance) {
+ uint32_t i, j;
+
+ if (p_distance > 1) {
+ // Build graph.
+ const uint32_t n = nodes.size();
+ const unsigned inf = (~(unsigned)0) >> 1;
+ const uint32_t adj_size = n * n;
+ unsigned *adj = memnew_arr(unsigned, adj_size);
+
+#define IDX(_x_, _y_) ((_y_)*n + (_x_))
+ for (j = 0; j < n; ++j) {
+ for (i = 0; i < n; ++i) {
+ int idx_ij = j * n + i;
+ int idx_ji = i * n + j;
+ if (i != j) {
+ adj[idx_ij] = adj[idx_ji] = inf;
+ } else {
+ adj[idx_ij] = adj[idx_ji] = 0;
+ }
+ }
+ }
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ int idx = ib * n + ia;
+ int idx_inv = ia * n + ib;
+ adj[idx] = 1;
+ adj[idx_inv] = 1;
+ }
+
+ // Special optimized case for distance == 2.
+ if (p_distance == 2) {
+ LocalVector<LocalVector<int>> node_links;
+
+ // Build node links.
+ node_links.resize(nodes.size());
+
+ for (i = 0; i < links.size(); ++i) {
+ const int ia = (int)(links[i].n[0] - &nodes[0]);
+ const int ib = (int)(links[i].n[1] - &nodes[0]);
+ if (node_links[ia].find(ib) == -1) {
+ node_links[ia].push_back(ib);
+ }
+
+ if (node_links[ib].find(ia) == -1) {
+ node_links[ib].push_back(ia);
+ }
+ }
+ for (uint32_t ii = 0; ii < node_links.size(); ii++) {
+ for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) {
+ int k = node_links[ii][jj];
+ for (uint32_t kk = 0; kk < node_links[k].size(); kk++) {
+ int l = node_links[k][kk];
+ if ((int)ii != l) {
+ int idx_ik = k * n + ii;
+ int idx_kj = l * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ ERR_FAIL_COND(sum != 2);
+ int idx_ij = l * n + ii;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = l * n + ii;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // Generic Floyd's algorithm.
+ for (uint32_t k = 0; k < n; ++k) {
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ik = k * n + i;
+ int idx_kj = j * n + k;
+ const unsigned sum = adj[idx_ik] + adj[idx_kj];
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] > sum) {
+ int idx_ji = j * n + i;
+ adj[idx_ij] = adj[idx_ji] = sum;
+ }
+ }
+ }
+ }
+ }
+
+ // Build links.
+ for (j = 0; j < n; ++j) {
+ for (i = j + 1; i < n; ++i) {
+ int idx_ij = j * n + i;
+ if (adj[idx_ij] == (unsigned)p_distance) {
+ append_link(i, j);
+ }
+ }
+ }
+ memdelete_arr(adj);
+ }
+}
+
+//===================================================================
+//
+//
+// This function takes in a list of interdependent Links and tries
+// to maximize the distance between calculation
+// of dependent links. This increases the amount of parallelism that can
+// be exploited by out-of-order instruction processors with large but
+// (inevitably) finite instruction windows.
+//
+//===================================================================
+
+// A small structure to track lists of dependent link calculations.
+class LinkDeps {
+public:
+ int value; // A link calculation that is dependent on this one
+ // Positive values = "input A" while negative values = "input B"
+ LinkDeps *next; // Next dependence in the list
+};
+typedef LinkDeps *LinkDepsPtr;
+
+void SoftBody3DSW::reoptimize_link_order() {
+ const int reop_not_dependent = -1;
+ const int reop_node_complete = -2;
+
+ uint32_t i, link_count = links.size(), node_count = nodes.size();
+ Link *lr;
+ int ar, br;
+ Node *node0 = &(nodes[0]);
+ Node *node1 = &(nodes[1]);
+ LinkDepsPtr link_dep;
+ int ready_list_head, ready_list_tail, link_num, link_dep_frees, dep_link;
+
+ // Allocate temporary buffers.
+ int *node_written_at = memnew_arr(int, node_count + 1); // What link calculation produced this node's current values?
+ int *link_dep_A = memnew_arr(int, link_count); // Link calculation input is dependent upon prior calculation #N
+ int *link_dep_B = memnew_arr(int, link_count);
+ int *ready_list = memnew_arr(int, link_count); // List of ready-to-process link calculations (# of links, maximum)
+ LinkDeps *link_dep_free_list = memnew_arr(LinkDeps, 2 * link_count); // Dependent-on-me list elements (2x# of links, maximum)
+ LinkDepsPtr *link_dep_list_starts = memnew_arr(LinkDepsPtr, link_count); // Start nodes of dependent-on-me lists, one for each link
+
+ // Copy the original, unsorted links to a side buffer.
+ Link *link_buffer = memnew_arr(Link, link_count);
+ memcpy(link_buffer, &(links[0]), sizeof(Link) * link_count);
+
+ // Clear out the node setup and ready list.
+ for (i = 0; i < node_count + 1; i++) {
+ node_written_at[i] = reop_not_dependent;
+ }
+ for (i = 0; i < link_count; i++) {
+ link_dep_list_starts[i] = nullptr;
+ }
+ ready_list_head = ready_list_tail = link_dep_frees = 0;
+
+ // Initial link analysis to set up data structures.
+ for (i = 0; i < link_count; i++) {
+ // Note which prior link calculations we are dependent upon & build up dependence lists.
+ lr = &(links[i]);
+ ar = (lr->n[0] - node0) / (node1 - node0);
+ br = (lr->n[1] - node0) / (node1 - node0);
+ if (node_written_at[ar] > reop_not_dependent) {
+ link_dep_A[i] = node_written_at[ar];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = i;
+ link_dep->next = link_dep_list_starts[node_written_at[ar]];
+ link_dep_list_starts[node_written_at[ar]] = link_dep;
+ } else {
+ link_dep_A[i] = reop_not_dependent;
+ }
+ if (node_written_at[br] > reop_not_dependent) {
+ link_dep_B[i] = node_written_at[br];
+ link_dep = &link_dep_free_list[link_dep_frees++];
+ link_dep->value = -(int)(i + 1);
+ link_dep->next = link_dep_list_starts[node_written_at[br]];
+ link_dep_list_starts[node_written_at[br]] = link_dep;
+ } else {
+ link_dep_B[i] = reop_not_dependent;
+ }
+
+ // Add this link to the initial ready list, if it is not dependent on any other links.
+ if ((link_dep_A[i] == reop_not_dependent) && (link_dep_B[i] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = i;
+ link_dep_A[i] = link_dep_B[i] = reop_node_complete; // Probably not needed now.
+ }
+
+ // Update the nodes to mark which ones are calculated by this link.
+ node_written_at[ar] = node_written_at[br] = i;
+ }
+
+ // Process the ready list and create the sorted list of links:
+ // -- By treating the ready list as a queue, we maximize the distance between any
+ // inter-dependent node calculations.
+ // -- All other (non-related) nodes in the ready list will automatically be inserted
+ // in between each set of inter-dependent link calculations by this loop.
+ i = 0;
+ while (ready_list_head != ready_list_tail) {
+ // Use ready list to select the next link to process.
+ link_num = ready_list[ready_list_head++];
+ // Copy the next-to-calculate link back into the original link array.
+ links[i++] = link_buffer[link_num];
+
+ // Free up any link inputs that are dependent on this one.
+ link_dep = link_dep_list_starts[link_num];
+ while (link_dep) {
+ dep_link = link_dep->value;
+ if (dep_link >= 0) {
+ link_dep_A[dep_link] = reop_not_dependent;
+ } else {
+ dep_link = -dep_link - 1;
+ link_dep_B[dep_link] = reop_not_dependent;
+ }
+ // Add this dependent link calculation to the ready list if *both* inputs are clear.
+ if ((link_dep_A[dep_link] == reop_not_dependent) && (link_dep_B[dep_link] == reop_not_dependent)) {
+ ready_list[ready_list_tail++] = dep_link;
+ link_dep_A[dep_link] = link_dep_B[dep_link] = reop_node_complete; // Probably not needed now.
+ }
+ link_dep = link_dep->next;
+ }
+ }
+
+ // Delete the temporary buffers.
+ memdelete_arr(node_written_at);
+ memdelete_arr(link_dep_A);
+ memdelete_arr(link_dep_B);
+ memdelete_arr(ready_list);
+ memdelete_arr(link_dep_free_list);
+ memdelete_arr(link_dep_list_starts);
+ memdelete_arr(link_buffer);
+}
+
+void SoftBody3DSW::append_link(uint32_t p_node1, uint32_t p_node2) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+
+ Link link;
+ link.n[0] = node1;
+ link.n[1] = node2;
+ link.rl = (node1->x - node2->x).length();
+
+ links.push_back(link);
+}
+
+void SoftBody3DSW::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) {
+ if (p_node1 == p_node2) {
+ return;
+ }
+ if (p_node1 == p_node3) {
+ return;
+ }
+ if (p_node2 == p_node3) {
+ return;
+ }
+
+ Node *node1 = &nodes[p_node1];
+ Node *node2 = &nodes[p_node2];
+ Node *node3 = &nodes[p_node3];
+
+ Face face;
+ face.n[0] = node1;
+ face.n[1] = node2;
+ face.n[2] = node3;
+
+ face.index = faces.size();
+
+ faces.push_back(face);
+}
+
+void SoftBody3DSW::set_iteration_count(int p_val) {
+ iteration_count = p_val;
+}
+
+void SoftBody3DSW::set_total_mass(real_t p_val) {
+ ERR_FAIL_COND(p_val < 0.0);
+
+ inv_total_mass = 1.0 / p_val;
+ real_t mass_factor = total_mass * inv_total_mass;
+ total_mass = p_val;
+
+ uint32_t node_count = nodes.size();
+ for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
+ Node &node = nodes[node_index];
+ node.im *= mass_factor;
+ }
+
+ update_constants();
+}
+
+void SoftBody3DSW::set_collision_margin(real_t p_val) {
+ collision_margin = p_val;
+}
+
+void SoftBody3DSW::set_linear_stiffness(real_t p_val) {
+ linear_stiffness = p_val;
+}
+
+void SoftBody3DSW::set_pressure_coefficient(real_t p_val) {
+ pressure_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_damping_coefficient(real_t p_val) {
+ damping_coefficient = p_val;
+}
+
+void SoftBody3DSW::set_drag_coefficient(real_t p_val) {
+ drag_coefficient = p_val;
+}
+
+void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) {
+ for (uint32_t i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.v += p_velocity;
+ }
+ }
+}
+
+void SoftBody3DSW::apply_forces() {
+ if (pressure_coefficient < CMP_EPSILON) {
+ return;
+ }
+
+ if (nodes.is_empty()) {
+ return;
+ }
+
+ uint32_t i, ni;
+
+ // Calculate volume.
+ real_t volume = 0.0;
+ const Vector3 &org = nodes[0].x;
+ for (i = 0, ni = faces.size(); i < ni; ++i) {
+ const Face &face = faces[i];
+ volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));
+ }
+ volume /= 6.0;
+
+ // Apply per node forces.
+ real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ if (node.im > 0) {
+ node.f += node.n * (node.area * ivolumetp);
+ }
+ }
+}
+
+void SoftBody3DSW::predict_motion(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ ERR_FAIL_COND(!get_space());
+
+ Area3DSW *def_area = get_space()->get_default_area();
+ ERR_FAIL_COND(!def_area);
+
+ // Apply forces.
+ Vector3 gravity = def_area->get_gravity_vector() * def_area->get_gravity();
+ add_velocity(gravity * p_delta);
+ apply_forces();
+
+ // Avoid soft body from 'exploding' so use some upper threshold of maximum motion
+ // that a node can travel per frame.
+ const real_t max_displacement = 1000.0;
+ real_t clamp_delta_v = max_displacement * inv_delta;
+
+ // Integrate.
+ uint32_t i, ni;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.q = node.x;
+ Vector3 delta_v = node.f * node.im * p_delta;
+ for (int c = 0; c < 3; c++) {
+ delta_v[c] = CLAMP(delta_v[c], -clamp_delta_v, clamp_delta_v);
+ }
+ node.v += delta_v;
+ node.x += node.v * p_delta;
+ node.f = Vector3();
+ }
+
+ // Bounds and tree update.
+ update_bounds();
+
+ // Node tree update.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ const Node &node = nodes[i];
+
+ AABB node_aabb(node.x, Vector3());
+ node_aabb.expand_to(node.x + node.v * p_delta);
+ node_aabb.grow_by(collision_margin);
+
+ node_tree.update(node.leaf, node_aabb);
+ }
+
+ // Face tree update.
+ if (!face_tree.is_empty()) {
+ update_face_tree(p_delta);
+ }
+
+ // Optimize node tree.
+ node_tree.optimize_incremental(1);
+ face_tree.optimize_incremental(1);
+}
+
+void SoftBody3DSW::solve_constraints(real_t p_delta) {
+ const real_t inv_delta = 1.0 / p_delta;
+
+ uint32_t i, ni;
+
+ for (i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ link.c3 = link.n[1]->q - link.n[0]->q;
+ link.c2 = 1 / (link.c3.length_squared() * link.c0);
+ }
+
+ // Solve velocities.
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+ node.x = node.q + node.v * p_delta;
+ }
+
+ // Solve positions.
+ for (int isolve = 0; isolve < iteration_count; ++isolve) {
+ const real_t ti = isolve / (real_t)iteration_count;
+ solve_links(1.0, ti);
+ }
+ const real_t vc = (1.0 - damping_coefficient) * inv_delta;
+ for (i = 0, ni = nodes.size(); i < ni; ++i) {
+ Node &node = nodes[i];
+
+ node.x += node.bv * p_delta;
+ node.bv = Vector3();
+
+ node.v = (node.x - node.q) * vc;
+
+ node.q = node.x;
+ }
+
+ update_normals();
+}
+
+void SoftBody3DSW::solve_links(real_t kst, real_t ti) {
+ for (uint32_t i = 0, ni = links.size(); i < ni; ++i) {
+ Link &link = links[i];
+ if (link.c0 > 0) {
+ Node &node_a = *link.n[0];
+ Node &node_b = *link.n[1];
+ const Vector3 del = node_b.x - node_a.x;
+ const real_t len = del.length_squared();
+ if (link.c1 + len > CMP_EPSILON) {
+ const real_t k = ((link.c1 - len) / (link.c0 * (link.c1 + len))) * kst;
+ node_a.x -= del * (k * node_a.im);
+ node_b.x += del * (k * node_b.im);
+ }
+ }
+ }
+}
+
+struct AABBQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_node_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_aabb(const AABB &p_aabb, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ AABBQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ node_tree.aabb_query(p_aabb, query_result);
+}
+
+struct RayQueryResult {
+ const SoftBody3DSW *soft_body = nullptr;
+ void *userdata = nullptr;
+ SoftBody3DSW::QueryResultCallback result_callback = nullptr;
+
+ _FORCE_INLINE_ bool operator()(void *p_data) {
+ return result_callback(soft_body->get_face_index(p_data), userdata);
+ };
+};
+
+void SoftBody3DSW::query_ray(const Vector3 &p_from, const Vector3 &p_to, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) {
+ if (face_tree.is_empty()) {
+ initialize_face_tree();
+ }
+
+ RayQueryResult query_result;
+ query_result.soft_body = this;
+ query_result.result_callback = p_result_callback;
+ query_result.userdata = p_userdata;
+
+ face_tree.ray_query(p_from, p_to, query_result);
+}
+
+void SoftBody3DSW::initialize_face_tree() {
+ face_tree.clear();
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ Face &face = faces[i];
+
+ AABB face_aabb;
+
+ face_aabb.position = face.n[0]->x;
+ face_aabb.expand_to(face.n[1]->x);
+ face_aabb.expand_to(face.n[2]->x);
+
+ face_aabb.grow_by(collision_margin);
+
+ face.leaf = face_tree.insert(face_aabb, &face);
+ }
+}
+
+void SoftBody3DSW::update_face_tree(real_t p_delta) {
+ for (uint32_t i = 0; i < faces.size(); ++i) {
+ const Face &face = faces[i];
+
+ AABB face_aabb;
+
+ const Node *node0 = face.n[0];
+ face_aabb.position = node0->x;
+ face_aabb.expand_to(node0->x + node0->v * p_delta);
+
+ const Node *node1 = face.n[1];
+ face_aabb.expand_to(node1->x);
+ face_aabb.expand_to(node1->x + node1->v * p_delta);
+
+ const Node *node2 = face.n[2];
+ face_aabb.expand_to(node2->x);
+ face_aabb.expand_to(node2->x + node2->v * p_delta);
+
+ face_aabb.grow_by(collision_margin);
+
+ face_tree.update(face.leaf, face_aabb);
+ }
+}
+
+void SoftBody3DSW::initialize_shape(bool p_force_move) {
+ if (get_shape_count() == 0) {
+ SoftBodyShape3DSW *soft_body_shape = memnew(SoftBodyShape3DSW(this));
+ add_shape(soft_body_shape);
+ } else if (p_force_move) {
+ SoftBodyShape3DSW *soft_body_shape = static_cast<SoftBodyShape3DSW *>(get_shape(0));
+ soft_body_shape->update_bounds();
+ }
+}
+
+void SoftBody3DSW::deinitialize_shape() {
+ if (get_shape_count() > 0) {
+ Shape3DSW *shape = get_shape(0);
+ remove_shape(shape);
+ memdelete(shape);
+ }
+}
+
+void SoftBody3DSW::destroy() {
+ map_visual_to_physics.clear();
+
+ node_tree.clear();
+ face_tree.clear();
+
+ nodes.clear();
+ links.clear();
+ faces.clear();
+
+ bounds = AABB();
+ deinitialize_shape();
+}
+
+void SoftBodyShape3DSW::update_bounds() {
+ ERR_FAIL_COND(!soft_body);
+
+ AABB collision_aabb = soft_body->get_bounds();
+ collision_aabb.grow_by(soft_body->get_collision_margin());
+ configure(collision_aabb);
+}
+
+SoftBodyShape3DSW::SoftBodyShape3DSW(SoftBody3DSW *p_soft_body) {
+ soft_body = p_soft_body;
+ update_bounds();
+}
+
+struct _SoftBodyIntersectSegmentInfo {
+ const SoftBody3DSW *soft_body = nullptr;
+ Vector3 from;
+ Vector3 dir;
+ Vector3 hit_position;
+ uint32_t hit_face_index = -1;
+ real_t hit_dist_sq = Math_INF;
+
+ static bool process_hit(uint32_t p_face_index, void *p_userdata) {
+ _SoftBodyIntersectSegmentInfo &query_info = *(_SoftBodyIntersectSegmentInfo *)(p_userdata);
+
+ Vector3 points[3];
+ query_info.soft_body->get_face_points(p_face_index, points[0], points[1], points[2]);
+
+ Vector3 result;
+ if (Geometry3D::ray_intersects_triangle(query_info.from, query_info.dir, points[0], points[1], points[2], &result)) {
+ real_t dist_sq = query_info.from.distance_squared_to(result);
+ if (dist_sq < query_info.hit_dist_sq) {
+ query_info.hit_dist_sq = dist_sq;
+ query_info.hit_position = result;
+ query_info.hit_face_index = p_face_index;
+ }
+ }
+
+ // Continue with the query.
+ return false;
+ }
+};
+
+bool SoftBodyShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+ _SoftBodyIntersectSegmentInfo query_info;
+ query_info.soft_body = soft_body;
+ query_info.from = p_begin;
+ query_info.dir = (p_end - p_begin).normalized();
+
+ soft_body->query_ray(p_begin, p_end, _SoftBodyIntersectSegmentInfo::process_hit, &query_info);
+
+ if (query_info.hit_dist_sq != Math_INF) {
+ r_result = query_info.hit_position;
+ r_normal = soft_body->get_face_normal(query_info.hit_face_index);
+ return true;
+ }
+
+ return false;
+}
+
+bool SoftBodyShape3DSW::intersect_point(const Vector3 &p_point) const {
+ return false;
+}
+
+Vector3 SoftBodyShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+ ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies.");
+}
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
new file mode 100644
index 0000000000..6c0451ff45
--- /dev/null
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -0,0 +1,247 @@
+/*************************************************************************/
+/* soft_body_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SOFT_BODY_3D_SW_H
+#define SOFT_BODY_3D_SW_H
+
+#include "collision_object_3d_sw.h"
+
+#include "core/math/aabb.h"
+#include "core/math/dynamic_bvh.h"
+#include "core/math/vector3.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/set.h"
+#include "core/templates/vset.h"
+#include "scene/resources/mesh.h"
+
+class Constraint3DSW;
+
+class SoftBody3DSW : public CollisionObject3DSW {
+ Ref<Mesh> soft_mesh;
+
+ struct Node {
+ Vector3 s; // Source position
+ Vector3 x; // Position
+ Vector3 q; // Previous step position/Test position
+ Vector3 f; // Force accumulator
+ Vector3 v; // Velocity
+ Vector3 bv; // Biased Velocity
+ Vector3 n; // Normal
+ real_t area = 0.0; // Area
+ real_t im = 0.0; // 1/mass
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ struct Link {
+ Vector3 c3; // gradient
+ Node *n[2] = { nullptr, nullptr }; // Node pointers
+ real_t rl = 0.0; // Rest length
+ real_t c0 = 0.0; // (ima+imb)*kLST
+ real_t c1 = 0.0; // rl^2
+ real_t c2 = 0.0; // |gradient|^2/c0
+ };
+
+ struct Face {
+ Node *n[3] = { nullptr, nullptr, nullptr }; // Node pointers
+ Vector3 normal; // Normal
+ real_t ra = 0.0; // Rest area
+ DynamicBVH::ID leaf; // Leaf data
+ uint32_t index = 0;
+ };
+
+ LocalVector<Node> nodes;
+ LocalVector<Link> links;
+ LocalVector<Face> faces;
+
+ DynamicBVH node_tree;
+ DynamicBVH face_tree;
+
+ LocalVector<uint32_t> map_visual_to_physics;
+
+ AABB bounds;
+
+ real_t collision_margin = 0.05;
+
+ real_t total_mass = 1.0;
+ real_t inv_total_mass = 1.0;
+
+ int iteration_count = 5;
+ real_t linear_stiffness = 0.5; // [0,1]
+ real_t pressure_coefficient = 0.0; // [-inf,+inf]
+ real_t damping_coefficient = 0.01; // [0,1]
+ real_t drag_coefficient = 0.0; // [0,1]
+ LocalVector<int> pinned_vertices;
+
+ SelfList<SoftBody3DSW> active_list;
+
+ Set<Constraint3DSW *> constraints;
+
+ VSet<RID> exceptions;
+
+public:
+ SoftBody3DSW();
+
+ const AABB &get_bounds() const { return bounds; }
+
+ void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer3D::BodyState p_state) const;
+
+ _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint) { constraints.insert(p_constraint); }
+ _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraints.erase(p_constraint); }
+ _FORCE_INLINE_ const Set<Constraint3DSW *> &get_constraints() const { return constraints; }
+ _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
+
+ _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); }
+ _FORCE_INLINE_ void remove_exception(const RID &p_exception) { exceptions.erase(p_exception); }
+ _FORCE_INLINE_ bool has_exception(const RID &p_exception) const { return exceptions.has(p_exception); }
+ _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; }
+
+ virtual void set_space(Space3DSW *p_space);
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+
+ void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
+
+ Vector3 get_vertex_position(int p_index) const;
+ void set_vertex_position(int p_index, const Vector3 &p_position);
+
+ void pin_vertex(int p_index);
+ void unpin_vertex(int p_index);
+ void unpin_all_vertices();
+ bool is_vertex_pinned(int p_index) const;
+
+ uint32_t get_node_count() const;
+ real_t get_node_inv_mass(uint32_t p_node_index) const;
+ Vector3 get_node_position(uint32_t p_node_index) const;
+ Vector3 get_node_velocity(uint32_t p_node_index) const;
+ Vector3 get_node_biased_velocity(uint32_t p_node_index) const;
+ void apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+ void apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+
+ uint32_t get_face_count() const;
+ void get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const;
+ Vector3 get_face_normal(uint32_t p_face_index) const;
+
+ void set_iteration_count(int p_val);
+ _FORCE_INLINE_ real_t get_iteration_count() const { return iteration_count; }
+
+ void set_total_mass(real_t p_val);
+ _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; }
+ _FORCE_INLINE_ real_t get_total_inv_mass() const { return inv_total_mass; }
+
+ void set_collision_margin(real_t p_val);
+ _FORCE_INLINE_ real_t get_collision_margin() const { return collision_margin; }
+
+ void set_linear_stiffness(real_t p_val);
+ _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
+
+ void set_pressure_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
+
+ void set_damping_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
+
+ void set_drag_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
+
+ void predict_motion(real_t p_delta);
+ void solve_constraints(real_t p_delta);
+
+ _FORCE_INLINE_ uint32_t get_node_index(void *p_node) const { return ((Node *)p_node)->index; }
+ _FORCE_INLINE_ uint32_t get_face_index(void *p_face) const { return ((Face *)p_face)->index; }
+
+ // Return true to stop the query.
+ // p_index is the node index for AABB query, face index for Ray query.
+ typedef bool (*QueryResultCallback)(uint32_t p_index, void *p_userdata);
+
+ void query_aabb(const AABB &p_aabb, QueryResultCallback p_result_callback, void *p_userdata);
+ void query_ray(const Vector3 &p_from, const Vector3 &p_to, QueryResultCallback p_result_callback, void *p_userdata);
+
+protected:
+ virtual void _shapes_changed();
+
+private:
+ void update_normals();
+ void update_bounds();
+ void update_constants();
+ void update_area();
+ void reset_link_rest_lengths();
+ void update_link_constants();
+
+ void apply_nodes_transform(const Transform &p_transform);
+
+ void add_velocity(const Vector3 &p_velocity);
+
+ void apply_forces();
+
+ bool create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices);
+ void generate_bending_constraints(int p_distance);
+ void reoptimize_link_order();
+ void append_link(uint32_t p_node1, uint32_t p_node2);
+ void append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3);
+
+ void solve_links(real_t kst, real_t ti);
+
+ void initialize_face_tree();
+ void update_face_tree(real_t p_delta);
+
+ void initialize_shape(bool p_force_move = true);
+ void deinitialize_shape();
+
+ void destroy();
+};
+
+class SoftBodyShape3DSW : public Shape3DSW {
+ SoftBody3DSW *soft_body = nullptr;
+
+public:
+ SoftBody3DSW *get_soft_body() const { return soft_body; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; }
+ virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
+ virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
+
+ virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
+ virtual bool intersect_point(const Vector3 &p_point) const;
+ virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); }
+
+ virtual void set_data(const Variant &p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ void update_bounds();
+
+ SoftBodyShape3DSW(SoftBody3DSW *p_soft_body);
+ ~SoftBodyShape3DSW() {}
+};
+
+#endif // SOFT_BODY_3D_SW_H
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 43cc032120..2df824b320 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -47,6 +47,10 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint
return false;
}
+ if (p_object->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY && !p_collide_with_bodies) {
+ return false;
+ }
+
return true;
}
@@ -181,7 +185,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
return 0;
}
- Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
AABB aabb = p_xform.xform(shape->get_aabb());
@@ -210,6 +214,10 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (!CollisionSolver3DSW::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_margin, 0)) {
continue;
}
@@ -232,7 +240,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
}
bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) {
- Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, false);
AABB aabb = p_xform.xform(shape->get_aabb());
@@ -265,6 +273,10 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
int shape_idx = space->intersection_query_subindex_results[i];
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
Vector3 point_A, point_B;
Vector3 sep_axis = p_motion.normalized();
@@ -324,7 +336,8 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
best_first = false;
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(col_obj);
- r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
+ Vector3 rel_vec = closest_B - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -340,7 +353,7 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_
return false;
}
- Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
AABB aabb = p_shape_xform.xform(shape->get_aabb());
@@ -365,12 +378,17 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_
}
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
if (CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
collided = true;
}
@@ -384,6 +402,8 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_
struct _RestCallbackData {
const CollisionObject3DSW *object;
const CollisionObject3DSW *best_object;
+ int local_shape;
+ int best_local_shape;
int shape;
int best_shape;
Vector3 best_contact;
@@ -392,7 +412,7 @@ struct _RestCallbackData {
real_t min_allowed_depth;
};
-static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
_RestCallbackData *rd = (_RestCallbackData *)p_userdata;
Vector3 contact_rel = p_point_B - p_point_A;
@@ -409,10 +429,11 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B,
rd->best_normal = contact_rel / len;
rd->best_object = rd->object;
rd->best_shape = rd->shape;
+ rd->best_local_shape = rd->local_shape;
}
bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
AABB aabb = p_shape_xform.xform(shape->get_aabb());
@@ -432,12 +453,17 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
}
const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ if (col_obj->is_shape_set_as_disabled(shape_idx)) {
+ continue;
+ }
+
rcd.object = col_obj;
rcd.shape = shape_idx;
bool sc = CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
@@ -457,8 +483,8 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
r_info->rid = rcd.best_object->get_self();
if (rcd.best_object->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- r_info->linear_velocity = body->get_linear_velocity() +
- (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
} else {
r_info->linear_velocity = Vector3();
@@ -468,9 +494,9 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap
}
Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const {
- CollisionObject3DSW *obj = PhysicsServer3DSW::singleton->area_owner.getornull(p_object);
+ CollisionObject3DSW *obj = PhysicsServer3DSW::singletonsw->area_owner.getornull(p_object);
if (!obj) {
- obj = PhysicsServer3DSW::singleton->body_owner.getornull(p_object);
+ obj = PhysicsServer3DSW::singletonsw->body_owner.getornull(p_object);
}
ERR_FAIL_COND_V(!obj, Vector3());
@@ -523,6 +549,8 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
keep = false;
} else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_AREA) {
keep = false;
+ } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ keep = false;
} else if ((static_cast<Body3DSW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0) {
keep = false;
} else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) {
@@ -663,10 +691,8 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
//result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
Body3DSW *body = (Body3DSW *)col_obj;
-
- Vector3 rel_vec = b - body->get_transform().get_origin();
- //result.collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rel_vec); // * mPos);
+ Vector3 rel_vec = b - (body->get_transform().origin + body->get_center_of_mass());
+ result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
}
}
@@ -739,8 +765,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin);
+ real_t motion_length = p_motion.length();
+ Vector3 motion_normal = p_motion / motion_length;
+
Transform body_transform = p_from;
+ bool recovered = false;
+
{
//STEP 1, FREE BODY IF STUCK
@@ -791,7 +822,17 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
for (int i = 0; i < cbk.amount; i++) {
Vector3 a = sr[i * 2 + 0];
Vector3 b = sr[i * 2 + 1];
- recover_motion += (b - a) / cbk.amount;
+
+ // Compute plane on b towards a.
+ Vector3 n = (a - b).normalized();
+ real_t d = n.dot(b);
+
+ // Compute depth on recovered motion.
+ real_t depth = n.dot(a + recover_motion) - d;
+ if (depth > 0.0) {
+ // Only recover if there is penetration.
+ recover_motion -= n * depth * 0.4;
+ }
}
if (recover_motion == Vector3()) {
@@ -799,6 +840,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
break;
}
+ recovered = true;
+
body_transform.origin += recover_motion;
body_aabb.position += recover_motion;
@@ -848,14 +891,14 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//test initial overlap, does it collide if going all the way?
Vector3 point_A, point_B;
- Vector3 sep_axis = p_motion.normalized();
+ Vector3 sep_axis = motion_normal;
Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
//test initial overlap, does it collide if going all the way?
if (CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) {
continue;
}
- sep_axis = p_motion.normalized();
+ sep_axis = motion_normal;
if (!CollisionSolver3DSW::solve_distance(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) {
stuck = true;
@@ -865,13 +908,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
//just do kinematic solving
real_t low = 0;
real_t hi = 1;
- Vector3 mnormal = p_motion.normalized();
for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t ofs = (low + hi) * 0.5;
- Vector3 sep = mnormal; //important optimization for this to work fast enough
+ Vector3 sep = motion_normal; //important optimization for this to work fast enough
mshape.motion = body_shape_xform_inv.basis.xform(p_motion * ofs);
@@ -912,16 +954,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
}
bool collided = false;
- if (safe >= 1) {
- //not collided
- collided = false;
- if (r_result) {
- r_result->motion = p_motion;
- r_result->remainder = Vector3();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ if (recovered || (safe < 1)) {
+ if (safe >= 1) {
+ best_shape = -1; //no best shape with cast, reset to -1
}
- } else {
//it collided, let's get the rest info in unsafe advance
Transform ugt = body_transform;
ugt.origin += p_motion * unsafe;
@@ -930,25 +967,40 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
- rcd.min_allowed_depth = test_motion_min_contact_depth;
- Transform body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
- Shape3DSW *body_shape = p_body->get_shape(best_shape);
+ // Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
+ rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
- body_aabb.position += p_motion * unsafe;
+ int from_shape = best_shape != -1 ? best_shape : 0;
+ int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count();
- int amount = _cull_aabb_for_body(p_body, body_aabb);
+ for (int j = from_shape; j < to_shape; j++) {
+ if (p_body->is_shape_set_as_disabled(j)) {
+ continue;
+ }
- for (int i = 0; i < amount; i++) {
- const CollisionObject3DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
+ Transform body_shape_xform = ugt * p_body->get_shape_transform(j);
+ Shape3DSW *body_shape = p_body->get_shape(j);
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
- if (!sc) {
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
continue;
}
+
+ body_aabb.position += p_motion * unsafe;
+
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ for (int i = 0; i < amount; i++) {
+ const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ int shape_idx = intersection_query_subindex_results[i];
+
+ rcd.object = col_obj;
+ rcd.shape = shape_idx;
+ bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
+ if (!sc) {
+ continue;
+ }
+ }
}
if (rcd.best_len != 0) {
@@ -956,15 +1008,15 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
r_result->collider = rcd.best_object->get_self();
r_result->collider_id = rcd.best_object->get_instance_id();
r_result->collider_shape = rcd.best_shape;
- r_result->collision_local_shape = best_shape;
+ r_result->collision_local_shape = rcd.best_local_shape;
r_result->collision_normal = rcd.best_normal;
r_result->collision_point = rcd.best_contact;
//r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
- //Vector3 rel_vec = r_result->collision_point - body->get_transform().get_origin();
- // r_result->collider_velocity = Vector3(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
+
+ Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
+ r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
r_result->motion = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
@@ -972,17 +1024,15 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
}
collided = true;
- } else {
- if (r_result) {
- r_result->motion = p_motion;
- r_result->remainder = Vector3();
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
- }
-
- collided = false;
}
}
+ if (!collided && r_result) {
+ r_result->motion = p_motion;
+ r_result->remainder = Vector3();
+ r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ }
+
return collided;
}
@@ -1009,14 +1059,23 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll
Area3DSW *area_b = static_cast<Area3DSW *>(B);
Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A));
return area2_pair;
+ } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ // Area/Soft Body, not supported.
} else {
Body3DSW *body = static_cast<Body3DSW *>(B);
AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A));
return area_pair;
}
+ } else if (type_A == CollisionObject3DSW::TYPE_BODY) {
+ if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) {
+ BodySoftBodyPair3DSW *soft_pair = memnew(BodySoftBodyPair3DSW((Body3DSW *)A, p_subindex_A, (SoftBody3DSW *)B));
+ return soft_pair;
+ } else {
+ BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
+ return b;
+ }
} else {
- BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
- return b;
+ // Soft Body/Soft Body, not supported.
}
return nullptr;
@@ -1099,6 +1158,18 @@ const SelfList<Area3DSW>::List &Space3DSW::get_moved_area_list() const {
return area_moved_list;
}
+const SelfList<SoftBody3DSW>::List &Space3DSW::get_active_soft_body_list() const {
+ return active_soft_body_list;
+}
+
+void Space3DSW::soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.add(p_soft_body);
+}
+
+void Space3DSW::soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body) {
+ active_soft_body_list.remove(p_soft_body);
+}
+
void Space3DSW::call_queries() {
while (state_query_list.first()) {
Body3DSW *b = state_query_list.first()->self();
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index eed3d86a72..3a8f452e54 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -40,6 +40,7 @@
#include "core/config/project_settings.h"
#include "core/templates/hash_map.h"
#include "core/typedefs.h"
+#include "soft_body_3d_sw.h"
class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D {
GDCLASS(PhysicsDirectSpaceState3DSW, PhysicsDirectSpaceState3D);
@@ -82,6 +83,7 @@ private:
SelfList<Body3DSW>::List state_query_list;
SelfList<Area3DSW>::List monitor_query_list;
SelfList<Area3DSW>::List area_moved_list;
+ SelfList<SoftBody3DSW>::List active_soft_body_list;
static void *_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self);
static void _broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self);
@@ -145,6 +147,10 @@ public:
void area_remove_from_moved_list(SelfList<Area3DSW> *p_area);
const SelfList<Area3DSW>::List &get_moved_area_list() const;
+ const SelfList<SoftBody3DSW>::List &get_active_soft_body_list() const;
+ void soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+ void soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body);
+
BroadPhase3DSW *get_broadphase();
void add_object(CollisionObject3DSW *p_object);
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index d9370de6a3..06f3227eab 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -33,19 +33,23 @@
#include "core/os/os.h"
-void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island) {
+#define BODY_ISLAND_COUNT_RESERVE 128
+#define BODY_ISLAND_SIZE_RESERVE 512
+#define ISLAND_COUNT_RESERVE 128
+#define ISLAND_SIZE_RESERVE 512
+
+void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
+ p_body_island.push_back(p_body);
- for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
+ // Faster with reversed iterations.
+ for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().back(); E; E = E->prev()) {
Constraint3DSW *c = (Constraint3DSW *)E->key();
if (c->get_island_step() == _step) {
continue; //already processed
}
c->set_island_step(_step);
- c->set_island_next(*p_constraint_island);
- *p_constraint_island = c;
+ p_constraint_island.push_back(c);
for (int i = 0; i < c->get_body_count(); i++) {
if (i == E->get()) {
@@ -55,87 +59,79 @@ void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constrain
if (b->get_island_step() == _step || b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
continue; //no go
}
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
+ _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
}
}
}
-void Step3DSW::_setup_island(Constraint3DSW *p_island, real_t p_delta) {
- Constraint3DSW *ci = p_island;
- while (ci) {
- ci->setup(p_delta);
- //todo remove from island if process fails
- ci = ci->get_island_next();
+void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta) {
+ uint32_t constraint_count = p_constraint_island.size();
+ uint32_t valid_constraint_count = 0;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ // Keep this constraint for solving.
+ p_constraint_island[valid_constraint_count++] = constraint;
+ }
}
+ p_constraint_island.resize(valid_constraint_count);
}
-void Step3DSW::_solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta) {
- int at_priority = 1;
+void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
+ int current_priority = 1;
- while (p_island) {
+ uint32_t constraint_count = p_constraint_island.size();
+ while (constraint_count > 0) {
for (int i = 0; i < p_iterations; i++) {
- Constraint3DSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
+ // Go through all iterations.
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ p_constraint_island[constraint_index]->solve(p_delta);
}
}
- at_priority++;
-
- {
- Constraint3DSW *ci = p_island;
- Constraint3DSW *prev = nullptr;
- while (ci) {
- if (ci->get_priority() < at_priority) {
- if (prev) {
- prev->set_island_next(ci->get_island_next()); //remove
- } else {
- p_island = ci->get_island_next();
- }
- } else {
- prev = ci;
- }
-
- ci = ci->get_island_next();
+ // Check priority to keep only higher priority constraints.
+ uint32_t priority_constraint_count = 0;
+ ++current_priority;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ if (constraint->get_priority() >= current_priority) {
+ // Keep this constraint for the next iteration.
+ p_constraint_island[priority_constraint_count++] = constraint;
}
}
+ constraint_count = priority_constraint_count;
}
}
-void Step3DSW::_check_suspend(Body3DSW *p_island, real_t p_delta) {
+void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta) {
bool can_sleep = true;
- Body3DSW *b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ uint32_t body_count = p_body_island.size();
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body3DSW *body = p_body_island[body_index];
+
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- if (!b->sleep_test(p_delta)) {
+ if (!body->sleep_test(p_delta)) {
can_sleep = false;
}
-
- b = b->get_island_next();
}
- //put all to sleep or wake up everyoen
+ // Put all to sleep or wake up everyone.
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body3DSW *body = p_body_island[body_index];
- b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- bool active = b->is_active();
+ bool active = body->is_active();
if (active == can_sleep) {
- b->set_active(!can_sleep);
+ body->set_active(!can_sleep);
}
-
- b = b->get_island_next();
}
}
@@ -146,6 +142,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list();
+ const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list();
+
/* INTEGRATE FORCES */
uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
@@ -160,6 +158,15 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
active_count++;
}
+ /* UPDATE SOFT BODY MOTION */
+
+ const SelfList<SoftBody3DSW> *sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->predict_motion(p_delta);
+ sb = sb->next();
+ active_count++;
+ }
+
p_space->set_active_objects(active_count);
{ //profile
@@ -170,33 +177,43 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* GENERATE CONSTRAINT ISLANDS */
- Body3DSW *island_list = nullptr;
- Constraint3DSW *constraint_island_list = nullptr;
b = body_list->first();
- int island_count = 0;
+ uint32_t body_island_count = 0;
+ uint32_t island_count = 0;
while (b) {
Body3DSW *body = b->self();
if (body->get_island_step() != _step) {
- Body3DSW *island = nullptr;
- Constraint3DSW *constraint_island = nullptr;
- _populate_island(body, &island, &constraint_island);
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
+ }
+ LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
- island->set_island_list_next(island_list);
- island_list = island;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
+
+ _populate_island(body, body_island, constraint_island);
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
+ body_islands.push_back(body_island);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
}
b = b->next();
}
- p_space->set_island_count(island_count);
+ p_space->set_island_count((int)island_count);
const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
@@ -207,13 +224,36 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
continue;
}
c->set_island_step(_step);
- c->set_island_next(nullptr);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(c);
}
p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
}
+ sb = soft_body_list->first();
+ while (sb) {
+ for (const Set<Constraint3DSW *>::Element *E = sb->self()->get_constraints().front(); E; E = E->next()) {
+ Constraint3DSW *c = E->get();
+ if (c->get_island_step() == _step) {
+ continue;
+ }
+ c->set_island_step(_step);
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(c);
+ }
+ sb = sb->next();
+ }
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
@@ -222,12 +262,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SETUP CONSTRAINT ISLANDS */
- {
- Constraint3DSW *ci = constraint_island_list;
- while (ci) {
- _setup_island(ci, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _setup_island(constraint_islands[island_index], p_delta);
}
{ //profile
@@ -238,13 +274,10 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SOLVE CONSTRAINT ISLANDS */
- {
- Constraint3DSW *ci = constraint_island_list;
- while (ci) {
- //iterating each island separatedly improves cache efficiency
- _solve_island(ci, p_iterations, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ _solve_island(constraint_islands[island_index], p_iterations, p_delta);
}
{ //profile
@@ -264,12 +297,16 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
- {
- Body3DSW *bi = island_list;
- while (bi) {
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
+ _check_suspend(body_islands[island_index], p_delta);
+ }
+
+ /* UPDATE SOFT BODY CONSTRAINTS */
+
+ sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->solve_constraints(p_delta);
+ sb = sb->next();
}
{ //profile
@@ -285,4 +322,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
Step3DSW::Step3DSW() {
_step = 1;
+
+ body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
+ constraint_islands.reserve(ISLAND_COUNT_RESERVE);
}
diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h
index 55c48ec0eb..f406c35c3a 100644
--- a/servers/physics_3d/step_3d_sw.h
+++ b/servers/physics_3d/step_3d_sw.h
@@ -33,13 +33,18 @@
#include "space_3d_sw.h"
+#include "core/templates/local_vector.h"
+
class Step3DSW {
uint64_t _step;
- void _populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island);
- void _setup_island(Constraint3DSW *p_island, real_t p_delta);
- void _solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(Body3DSW *p_island, real_t p_delta);
+ LocalVector<LocalVector<Body3DSW *>> body_islands;
+ LocalVector<LocalVector<Constraint3DSW *>> constraint_islands;
+
+ void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
+ void _setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta);
+ void _solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
+ void _check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta);
public:
void step(Space3DSW *p_space, real_t p_delta, int p_iterations);
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 7c36229e9f..384179f2c3 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -176,11 +176,11 @@ real_t PhysicsShapeQueryParameters2D::get_margin() const {
return margin;
}
-void PhysicsShapeQueryParameters2D::set_collision_mask(int p_collision_mask) {
+void PhysicsShapeQueryParameters2D::set_collision_mask(uint32_t p_collision_mask) {
collision_mask = p_collision_mask;
}
-int PhysicsShapeQueryParameters2D::get_collision_mask() const {
+uint32_t PhysicsShapeQueryParameters2D::get_collision_mask() const {
return collision_mask;
}
@@ -647,7 +647,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer2D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer2D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
@@ -655,12 +655,16 @@ void PhysicsServer2D::_bind_methods() {
/* JOINT API */
+ ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer2D::joint_create);
+
+ ClassDB::bind_method(D_METHOD("joint_clear", "joint"), &PhysicsServer2D::joint_clear);
+
ClassDB::bind_method(D_METHOD("joint_set_param", "joint", "param", "value"), &PhysicsServer2D::joint_set_param);
ClassDB::bind_method(D_METHOD("joint_get_param", "joint", "param"), &PhysicsServer2D::joint_get_param);
- ClassDB::bind_method(D_METHOD("pin_joint_create", "anchor", "body_a", "body_b"), &PhysicsServer2D::pin_joint_create, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("groove_joint_create", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::groove_joint_create, DEFVAL(RID()), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("damped_spring_joint_create", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::damped_spring_joint_create, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "anchor", "body_a", "body_b"), &PhysicsServer2D::joint_make_pin, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("joint_make_groove", "joint", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_groove, DEFVAL(RID()), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("joint_make_damped_spring", "joint", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_damped_spring, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("damped_spring_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::damped_spring_joint_set_param);
ClassDB::bind_method(D_METHOD("damped_spring_joint_get_param", "joint", "param"), &PhysicsServer2D::damped_spring_joint_get_param);
@@ -727,9 +731,10 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_STATE_SLEEPING);
BIND_ENUM_CONSTANT(BODY_STATE_CAN_SLEEP);
- BIND_ENUM_CONSTANT(JOINT_PIN);
- BIND_ENUM_CONSTANT(JOINT_GROOVE);
- BIND_ENUM_CONSTANT(JOINT_DAMPED_SPRING);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_GROOVE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_DAMPED_SPRING);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_MAX);
BIND_ENUM_CONSTANT(JOINT_PARAM_BIAS);
BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 710eecfdec..a5cf3f3a46 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -128,8 +128,8 @@ public:
void set_margin(real_t p_margin);
real_t get_margin() const;
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
void set_collide_with_bodies(bool p_enable);
bool is_collide_with_bodies_enabled() const;
@@ -477,7 +477,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
@@ -524,10 +524,15 @@ public:
/* JOINT API */
+ virtual RID joint_create() = 0;
+
+ virtual void joint_clear(RID p_joint) = 0;
+
enum JointType {
- JOINT_PIN,
- JOINT_GROOVE,
- JOINT_DAMPED_SPRING
+ JOINT_TYPE_PIN,
+ JOINT_TYPE_GROOVE,
+ JOINT_TYPE_DAMPED_SPRING,
+ JOINT_TYPE_MAX
};
enum JointParam {
@@ -542,9 +547,9 @@ public:
virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0;
virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0;
- virtual RID pin_joint_create(const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) = 0;
- virtual RID groove_joint_create(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) = 0;
- virtual RID damped_spring_joint_create(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) = 0;
+ virtual void joint_make_pin(RID p_joint, const Vector2 &p_anchor, RID p_body_a, RID p_body_b = RID()) = 0;
+ virtual void joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) = 0;
+ virtual void joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b = RID()) = 0;
enum PinJointParam {
PIN_JOINT_SOFTNESS
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index a4dc80b0a6..80a9bd4c0b 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -172,11 +172,11 @@ real_t PhysicsShapeQueryParameters3D::get_margin() const {
return margin;
}
-void PhysicsShapeQueryParameters3D::set_collision_mask(int p_collision_mask) {
+void PhysicsShapeQueryParameters3D::set_collision_mask(uint32_t p_collision_mask) {
collision_mask = p_collision_mask;
}
-int PhysicsShapeQueryParameters3D::get_collision_mask() const {
+uint32_t PhysicsShapeQueryParameters3D::get_collision_mask() const {
return collision_mask;
}
@@ -398,10 +398,47 @@ void PhysicsShapeQueryResult3D::_bind_methods() {
///////////////////////////////////////
+RID PhysicsServer3D::shape_create(ShapeType p_shape) {
+ switch (p_shape) {
+ case SHAPE_PLANE:
+ return plane_shape_create();
+ case SHAPE_RAY:
+ return ray_shape_create();
+ case SHAPE_SPHERE:
+ return sphere_shape_create();
+ case SHAPE_BOX:
+ return box_shape_create();
+ case SHAPE_CAPSULE:
+ return capsule_shape_create();
+ case SHAPE_CYLINDER:
+ return cylinder_shape_create();
+ case SHAPE_CONVEX_POLYGON:
+ return convex_polygon_shape_create();
+ case SHAPE_CONCAVE_POLYGON:
+ return concave_polygon_shape_create();
+ case SHAPE_HEIGHTMAP:
+ return heightmap_shape_create();
+ case SHAPE_CUSTOM:
+ return custom_shape_create();
+ default:
+ return RID();
+ }
+}
+
void PhysicsServer3D::_bind_methods() {
#ifndef _3D_DISABLED
- ClassDB::bind_method(D_METHOD("shape_create", "type"), &PhysicsServer3D::shape_create);
+ ClassDB::bind_method(D_METHOD("plane_shape_create"), &PhysicsServer3D::plane_shape_create);
+ ClassDB::bind_method(D_METHOD("ray_shape_create"), &PhysicsServer3D::ray_shape_create);
+ ClassDB::bind_method(D_METHOD("sphere_shape_create"), &PhysicsServer3D::sphere_shape_create);
+ ClassDB::bind_method(D_METHOD("box_shape_create"), &PhysicsServer3D::box_shape_create);
+ ClassDB::bind_method(D_METHOD("capsule_shape_create"), &PhysicsServer3D::capsule_shape_create);
+ ClassDB::bind_method(D_METHOD("cylinder_shape_create"), &PhysicsServer3D::cylinder_shape_create);
+ ClassDB::bind_method(D_METHOD("convex_polygon_shape_create"), &PhysicsServer3D::convex_polygon_shape_create);
+ ClassDB::bind_method(D_METHOD("concave_polygon_shape_create"), &PhysicsServer3D::concave_polygon_shape_create);
+ ClassDB::bind_method(D_METHOD("heightmap_shape_create"), &PhysicsServer3D::heightmap_shape_create);
+ ClassDB::bind_method(D_METHOD("custom_shape_create"), &PhysicsServer3D::custom_shape_create);
+
ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer3D::shape_set_data);
ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &PhysicsServer3D::shape_get_type);
@@ -450,9 +487,8 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer3D::area_set_monitorable);
ClassDB::bind_method(D_METHOD("area_set_ray_pickable", "area", "enable"), &PhysicsServer3D::area_set_ray_pickable);
- ClassDB::bind_method(D_METHOD("area_is_ray_pickable", "area"), &PhysicsServer3D::area_is_ray_pickable);
- ClassDB::bind_method(D_METHOD("body_create", "mode", "init_sleeping"), &PhysicsServer3D::body_create, DEFVAL(BODY_MODE_RIGID), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("body_create"), &PhysicsServer3D::body_create);
ClassDB::bind_method(D_METHOD("body_set_space", "body", "space"), &PhysicsServer3D::body_set_space);
ClassDB::bind_method(D_METHOD("body_get_space", "body"), &PhysicsServer3D::body_get_space);
@@ -514,22 +550,29 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer3D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer3D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
- ClassDB::bind_method(D_METHOD("body_is_ray_pickable", "body"), &PhysicsServer3D::body_is_ray_pickable);
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
+ /* SOFT BODY API */
+
+ ClassDB::bind_method(D_METHOD("soft_body_get_bounds", "body"), &PhysicsServer3D::soft_body_get_bounds);
+
/* JOINT API */
- BIND_ENUM_CONSTANT(JOINT_PIN);
- BIND_ENUM_CONSTANT(JOINT_HINGE);
- BIND_ENUM_CONSTANT(JOINT_SLIDER);
- BIND_ENUM_CONSTANT(JOINT_CONE_TWIST);
- BIND_ENUM_CONSTANT(JOINT_6DOF);
+ ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer3D::joint_create);
+ ClassDB::bind_method(D_METHOD("joint_clear", "joint"), &PhysicsServer3D::joint_clear);
+
+ BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_CONE_TWIST);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_MAX);
- ClassDB::bind_method(D_METHOD("joint_create_pin", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer3D::joint_create_pin);
+ ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer3D::joint_make_pin);
ClassDB::bind_method(D_METHOD("pin_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::pin_joint_set_param);
ClassDB::bind_method(D_METHOD("pin_joint_get_param", "joint", "param"), &PhysicsServer3D::pin_joint_get_param);
@@ -555,7 +598,7 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(HINGE_JOINT_FLAG_USE_LIMIT);
BIND_ENUM_CONSTANT(HINGE_JOINT_FLAG_ENABLE_MOTOR);
- ClassDB::bind_method(D_METHOD("joint_create_hinge", "body_A", "hinge_A", "body_B", "hinge_B"), &PhysicsServer3D::joint_create_hinge);
+ ClassDB::bind_method(D_METHOD("joint_make_hinge", "joint", "body_A", "hinge_A", "body_B", "hinge_B"), &PhysicsServer3D::joint_make_hinge);
ClassDB::bind_method(D_METHOD("hinge_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::hinge_joint_set_param);
ClassDB::bind_method(D_METHOD("hinge_joint_get_param", "joint", "param"), &PhysicsServer3D::hinge_joint_get_param);
@@ -563,7 +606,7 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("hinge_joint_set_flag", "joint", "flag", "enabled"), &PhysicsServer3D::hinge_joint_set_flag);
ClassDB::bind_method(D_METHOD("hinge_joint_get_flag", "joint", "flag"), &PhysicsServer3D::hinge_joint_get_flag);
- ClassDB::bind_method(D_METHOD("joint_create_slider", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_slider);
+ ClassDB::bind_method(D_METHOD("joint_make_slider", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_slider);
ClassDB::bind_method(D_METHOD("slider_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::slider_joint_set_param);
ClassDB::bind_method(D_METHOD("slider_joint_get_param", "joint", "param"), &PhysicsServer3D::slider_joint_get_param);
@@ -593,7 +636,7 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING);
BIND_ENUM_CONSTANT(SLIDER_JOINT_MAX);
- ClassDB::bind_method(D_METHOD("joint_create_cone_twist", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_cone_twist);
+ ClassDB::bind_method(D_METHOD("joint_make_cone_twist", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_cone_twist);
ClassDB::bind_method(D_METHOD("cone_twist_joint_set_param", "joint", "param", "value"), &PhysicsServer3D::cone_twist_joint_set_param);
ClassDB::bind_method(D_METHOD("cone_twist_joint_get_param", "joint", "param"), &PhysicsServer3D::cone_twist_joint_get_param);
@@ -631,7 +674,7 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("joint_set_solver_priority", "joint", "priority"), &PhysicsServer3D::joint_set_solver_priority);
ClassDB::bind_method(D_METHOD("joint_get_solver_priority", "joint"), &PhysicsServer3D::joint_get_solver_priority);
- ClassDB::bind_method(D_METHOD("joint_create_generic_6dof", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_create_generic_6dof);
+ ClassDB::bind_method(D_METHOD("joint_make_generic_6dof", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_generic_6dof);
ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_param", "joint", "axis", "param", "value"), &PhysicsServer3D::generic_6dof_joint_set_param);
ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_param", "joint", "axis", "param"), &PhysicsServer3D::generic_6dof_joint_get_param);
@@ -654,6 +697,7 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);
+ BIND_ENUM_CONSTANT(SHAPE_SOFT_BODY);
BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
@@ -718,7 +762,6 @@ void PhysicsServer3D::_bind_methods() {
}
PhysicsServer3D::PhysicsServer3D() {
- ERR_FAIL_COND(singleton != nullptr);
singleton = this;
}
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 1349e0e033..c434109865 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -125,8 +125,8 @@ public:
void set_margin(real_t p_margin);
real_t get_margin() const;
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
+ void set_collision_mask(uint32_t p_collision_mask);
+ uint32_t get_collision_mask() const;
void set_exclude(const Vector<RID> &p_exclude);
Vector<RID> get_exclude() const;
@@ -216,6 +216,15 @@ public:
PhysicsShapeQueryResult3D();
};
+class RenderingServerHandler {
+public:
+ virtual void set_vertex(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_normal(int p_vertex_id, const void *p_vector3) = 0;
+ virtual void set_aabb(const AABB &p_aabb) = 0;
+
+ virtual ~RenderingServerHandler() {}
+};
+
class PhysicsServer3D : public Object {
GDCLASS(PhysicsServer3D, Object);
@@ -237,10 +246,23 @@ public:
SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
SHAPE_CONCAVE_POLYGON, ///< vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
SHAPE_HEIGHTMAP, ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
+ SHAPE_SOFT_BODY, ///< Used internally, can't be created from the physics server.
SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
};
- virtual RID shape_create(ShapeType p_shape) = 0;
+ RID shape_create(ShapeType p_shape);
+
+ virtual RID plane_shape_create() = 0;
+ virtual RID ray_shape_create() = 0;
+ virtual RID sphere_shape_create() = 0;
+ virtual RID box_shape_create() = 0;
+ virtual RID capsule_shape_create() = 0;
+ virtual RID cylinder_shape_create() = 0;
+ virtual RID convex_polygon_shape_create() = 0;
+ virtual RID concave_polygon_shape_create() = 0;
+ virtual RID heightmap_shape_create() = 0;
+ virtual RID custom_shape_create() = 0;
+
virtual void shape_set_data(RID p_shape, const Variant &p_data) = 0;
virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias) = 0;
@@ -344,7 +366,6 @@ public:
virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
virtual void area_set_ray_pickable(RID p_area, bool p_enable) = 0;
- virtual bool area_is_ray_pickable(RID p_area) const = 0;
/* BODY API */
@@ -357,7 +378,7 @@ public:
BODY_MODE_CHARACTER
};
- virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) = 0;
+ virtual RID body_create() = 0;
virtual void body_set_space(RID p_body, RID p_space) = 0;
virtual RID body_get_space(RID p_body) const = 0;
@@ -465,10 +486,9 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
- virtual bool body_is_ray_pickable(RID p_body) const = 0;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0;
@@ -510,15 +530,17 @@ public:
/* SOFT BODY */
- virtual RID soft_body_create(bool p_init_sleeping = false) = 0;
+ virtual RID soft_body_create() = 0;
- virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) = 0;
+ virtual void soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) = 0;
virtual void soft_body_set_space(RID p_body, RID p_space) = 0;
virtual RID soft_body_get_space(RID p_body) const = 0;
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0;
+ virtual AABB soft_body_get_bounds(RID p_body) const = 0;
+
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
virtual uint32_t soft_body_get_collision_layer(RID p_body) const = 0;
@@ -533,58 +555,50 @@ public:
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0;
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0;
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0;
- virtual bool soft_body_is_ray_pickable(RID p_body) const = 0;
virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) = 0;
- virtual int soft_body_get_simulation_precision(RID p_body) = 0;
+ virtual int soft_body_get_simulation_precision(RID p_body) const = 0;
virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) = 0;
- virtual real_t soft_body_get_total_mass(RID p_body) = 0;
+ virtual real_t soft_body_get_total_mass(RID p_body) const = 0;
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_linear_stiffness(RID p_body) = 0;
-
- virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) = 0;
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0;
- virtual real_t soft_body_get_volume_stiffness(RID p_body) = 0;
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) const = 0;
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0;
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) = 0;
-
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0;
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) = 0;
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) const = 0;
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0;
- virtual real_t soft_body_get_damping_coefficient(RID p_body) = 0;
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) const = 0;
virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) = 0;
- virtual real_t soft_body_get_drag_coefficient(RID p_body) = 0;
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) const = 0;
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0;
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) = 0;
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0;
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const = 0;
virtual void soft_body_remove_all_pinned_points(RID p_body) = 0;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0;
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) = 0;
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const = 0;
/* JOINT API */
enum JointType {
- JOINT_PIN,
- JOINT_HINGE,
- JOINT_SLIDER,
- JOINT_CONE_TWIST,
- JOINT_6DOF
+ JOINT_TYPE_PIN,
+ JOINT_TYPE_HINGE,
+ JOINT_TYPE_SLIDER,
+ JOINT_TYPE_CONE_TWIST,
+ JOINT_TYPE_6DOF,
+ JOINT_TYPE_MAX,
};
+ virtual RID joint_create() = 0;
+
+ virtual void joint_clear(RID p_joint) = 0;
+
virtual JointType joint_get_type(RID p_joint) const = 0;
virtual void joint_set_solver_priority(RID p_joint, int p_priority) = 0;
@@ -593,7 +607,7 @@ public:
virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) = 0;
virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const = 0;
- virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) = 0;
+ virtual void joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) = 0;
enum PinJointParam {
PIN_JOINT_BIAS,
@@ -628,8 +642,8 @@ public:
HINGE_JOINT_FLAG_MAX
};
- virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0;
- virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0;
+ virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0;
+ virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0;
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) = 0;
virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const = 0;
@@ -665,7 +679,7 @@ public:
};
- virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) = 0;
virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0;
@@ -679,7 +693,7 @@ public:
CONE_TWIST_MAX
};
- virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) = 0;
virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0;
@@ -720,13 +734,13 @@ public:
G6DOF_JOINT_FLAG_MAX
};
- virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) = 0;
- virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) = 0;
+ virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const = 0;
virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable) = 0;
- virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) = 0;
+ virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag) const = 0;
/* QUERY API */
@@ -742,7 +756,9 @@ public:
virtual void set_active(bool p_active) = 0;
virtual void init() = 0;
virtual void step(real_t p_step) = 0;
+ virtual void sync() = 0;
virtual void flush_queries() = 0;
+ virtual void end_sync() = 0;
virtual void finish() = 0;
virtual bool is_flushing_queries() const = 0;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 50efd7c554..deb230c4fb 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -61,6 +61,7 @@
#include "physics_2d/physics_server_2d_sw.h"
#include "physics_2d/physics_server_2d_wrap_mt.h"
#include "physics_3d/physics_server_3d_sw.h"
+#include "physics_3d/physics_server_3d_wrap_mt.h"
#include "physics_server_2d.h"
#include "physics_server_3d.h"
#include "rendering/renderer_compositor.h"
@@ -76,11 +77,19 @@
ShaderTypes *shader_types = nullptr;
PhysicsServer3D *_createGodotPhysics3DCallback() {
- return memnew(PhysicsServer3DSW);
+ bool using_threads = GLOBAL_GET("physics/3d/run_on_thread");
+
+ PhysicsServer3D *physics_server = memnew(PhysicsServer3DSW(using_threads));
+
+ return memnew(PhysicsServer3DWrapMT(physics_server, using_threads));
}
PhysicsServer2D *_createGodotPhysics2DCallback() {
- return PhysicsServer2DWrapMT::init_server<PhysicsServer2DSW>();
+ bool using_threads = GLOBAL_GET("physics/2d/run_on_thread");
+
+ PhysicsServer2D *physics_server = memnew(PhysicsServer2DSW(using_threads));
+
+ return memnew(PhysicsServer2DWrapMT(physics_server, using_threads));
}
static bool has_server_feature_callback(const String &p_feature) {
@@ -95,6 +104,16 @@ static bool has_server_feature_callback(const String &p_feature) {
void preregister_server_types() {
shader_types = memnew(ShaderTypes);
+
+ GLOBAL_DEF("internationalization/rendering/text_driver", "");
+ String text_driver_options;
+ for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
+ if (i > 0) {
+ text_driver_options += ",";
+ }
+ text_driver_options += TextServerManager::get_interface_name(i);
+ }
+ ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
}
void register_server_types() {
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index e1ce52661c..7f3fc2f8f4 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -97,7 +97,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
}
}
-void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item> &canvas_item_owner) {
+void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item, true> &canvas_item_owner) {
do {
ysort_owner->ysort_children_count = -1;
ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr;
@@ -148,6 +148,8 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
} else {
ci->final_clip_rect = global_rect;
}
+ ci->final_clip_rect.position = ci->final_clip_rect.position.round();
+ ci->final_clip_rect.size = ci->final_clip_rect.size.round();
ci->final_clip_owner = ci;
} else {
@@ -356,12 +358,12 @@ bool RendererCanvasCull::was_sdf_used() {
return sdf_used;
}
-RID RendererCanvasCull::canvas_create() {
+RID RendererCanvasCull::canvas_allocate() {
+ return canvas_owner.allocate_rid();
+}
+void RendererCanvasCull::canvas_initialize(RID p_rid) {
Canvas *canvas = memnew(Canvas);
- ERR_FAIL_COND_V(!canvas, RID());
- RID rid = canvas_owner.make_rid(canvas);
-
- return rid;
+ canvas_owner.initialize_rid(p_rid, canvas);
}
void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
@@ -393,11 +395,12 @@ void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_s
canvas->parent_scale = p_scale;
}
-RID RendererCanvasCull::canvas_item_create() {
+RID RendererCanvasCull::canvas_item_allocate() {
+ return canvas_item_owner.allocate_rid();
+}
+void RendererCanvasCull::canvas_item_initialize(RID p_rid) {
Item *canvas_item = memnew(Item);
- ERR_FAIL_COND_V(!canvas_item, RID());
-
- return canvas_item_owner.make_rid(canvas_item);
+ canvas_item_owner.initialize_rid(p_rid, canvas_item);
}
void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
@@ -524,11 +527,11 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
ERR_FAIL_COND(!line);
if (p_width > 1.001) {
- Vector2 t = (p_from - p_to).orthogonal().normalized();
- line->points[0] = p_from + t * p_width;
- line->points[1] = p_from - t * p_width;
- line->points[2] = p_to - t * p_width;
- line->points[3] = p_to + t * p_width;
+ Vector2 t = (p_from - p_to).orthogonal().normalized() * p_width * 0.5;
+ line->points[0] = p_from + t;
+ line->points[1] = p_from - t;
+ line->points[2] = p_to - t;
+ line->points[3] = p_to + t;
line->point_count = 4;
} else {
line->point_count = 2;
@@ -1075,10 +1078,13 @@ void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::Canva
}
}
-RID RendererCanvasCull::canvas_light_create() {
+RID RendererCanvasCull::canvas_light_allocate() {
+ return canvas_light_owner.allocate_rid();
+}
+void RendererCanvasCull::canvas_light_initialize(RID p_rid) {
RendererCanvasRender::Light *clight = memnew(RendererCanvasRender::Light);
clight->light_internal = RSG::canvas_render->light_create();
- return canvas_light_owner.make_rid(clight);
+ return canvas_light_owner.initialize_rid(p_rid, clight);
}
void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
@@ -1268,10 +1274,13 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo
clight->shadow_smooth = p_smooth;
}
-RID RendererCanvasCull::canvas_light_occluder_create() {
+RID RendererCanvasCull::canvas_light_occluder_allocate() {
+ return canvas_light_occluder_owner.allocate_rid();
+}
+void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) {
RendererCanvasRender::LightOccluderInstance *occluder = memnew(RendererCanvasRender::LightOccluderInstance);
- return canvas_light_occluder_owner.make_rid(occluder);
+ return canvas_light_occluder_owner.initialize_rid(p_rid, occluder);
}
void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
@@ -1349,10 +1358,13 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in
occluder->light_mask = p_mask;
}
-RID RendererCanvasCull::canvas_occluder_polygon_create() {
+RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
+ return canvas_light_occluder_polygon_owner.allocate_rid();
+}
+void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) {
LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon);
occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create();
- return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
+ return canvas_light_occluder_polygon_owner.initialize_rid(p_rid, occluder_poly);
}
void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
@@ -1393,8 +1405,11 @@ void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) {
RSG::canvas_render->set_shadow_texture_size(p_size);
}
-RID RendererCanvasCull::canvas_texture_create() {
- return RSG::storage->canvas_texture_create();
+RID RendererCanvasCull::canvas_texture_allocate() {
+ return RSG::storage->canvas_texture_allocate();
+}
+void RendererCanvasCull::canvas_texture_initialize(RID p_rid) {
+ RSG::storage->canvas_texture_initialize(p_rid);
}
void RendererCanvasCull::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 7496a413ee..b71f8e5a9a 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -101,9 +101,9 @@ public:
}
};
- RID_PtrOwner<LightOccluderPolygon> canvas_light_occluder_polygon_owner;
+ RID_PtrOwner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner;
- RID_PtrOwner<RendererCanvasRender::LightOccluderInstance> canvas_light_occluder_owner;
+ RID_PtrOwner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner;
struct Canvas : public RendererViewport::CanvasBase {
Set<RID> viewports;
@@ -148,9 +148,9 @@ public:
}
};
- mutable RID_PtrOwner<Canvas> canvas_owner;
- RID_PtrOwner<Item> canvas_item_owner;
- RID_PtrOwner<RendererCanvasRender::Light> canvas_light_owner;
+ mutable RID_PtrOwner<Canvas, true> canvas_owner;
+ RID_PtrOwner<Item, true> canvas_item_owner;
+ RID_PtrOwner<RendererCanvasRender::Light, true> canvas_light_owner;
bool disable_scale;
bool sdf_used = false;
@@ -168,13 +168,17 @@ public:
bool was_sdf_used();
- RID canvas_create();
+ RID canvas_allocate();
+ void canvas_initialize(RID p_rid);
+
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);
void canvas_set_modulate(RID p_canvas, const Color &p_color);
void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale);
void canvas_set_disable_scale(bool p_disable);
- RID canvas_item_create();
+ RID canvas_item_allocate();
+ void canvas_item_initialize(RID p_rid);
+
void canvas_item_set_parent(RID p_item, RID p_parent);
void canvas_item_set_visible(RID p_item, bool p_visible);
@@ -222,7 +226,9 @@ public:
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
- RID canvas_light_create();
+ RID canvas_light_allocate();
+ void canvas_light_initialize(RID p_rid);
+
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
void canvas_light_set_enabled(RID p_light, bool p_enabled);
@@ -246,7 +252,9 @@ public:
void canvas_light_set_shadow_color(RID p_light, const Color &p_color);
void canvas_light_set_shadow_smooth(RID p_light, float p_smooth);
- RID canvas_light_occluder_create();
+ RID canvas_light_occluder_allocate();
+ void canvas_light_occluder_initialize(RID p_rid);
+
void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas);
void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled);
void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon);
@@ -254,14 +262,18 @@ public:
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
- RID canvas_occluder_polygon_create();
+ RID canvas_occluder_polygon_allocate();
+ void canvas_occluder_polygon_initialize(RID p_rid);
+
void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed);
void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode);
void canvas_set_shadow_texture_size(int p_size);
- RID canvas_texture_create();
+ RID canvas_texture_allocate();
+ void canvas_texture_initialize(RID p_rid);
+
void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture);
void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess);
diff --git a/servers/rendering/renderer_rd/SCsub b/servers/rendering/renderer_rd/SCsub
index 6a2e682c67..64e613ab91 100644
--- a/servers/rendering/renderer_rd/SCsub
+++ b/servers/rendering/renderer_rd/SCsub
@@ -4,4 +4,6 @@ Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
+SConscript("forward_clustered/SCsub")
+SConscript("forward_mobile/SCsub")
SConscript("shaders/SCsub")
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index 0fdd864d47..2669a73014 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -86,13 +86,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3);
- copymem(vertex_data.ptrw(), icosphere_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), icosphere_vertices, vertex_data.size());
sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3);
- copymem(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
@@ -130,13 +130,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * cone_vertex_count * 3);
- copymem(vertex_data.ptrw(), cone_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), cone_vertices, vertex_data.size());
cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3);
- copymem(index_data.ptrw(), cone_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), cone_triangle_indices, index_data.size());
cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
@@ -184,13 +184,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * box_vertex_count * 3);
- copymem(vertex_data.ptrw(), box_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), box_vertices, vertex_data.size());
box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * box_triangle_count * 3);
- copymem(index_data.ptrw(), box_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), box_triangle_indices, index_data.size());
box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index a9cadb40df..563e08fdcb 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -226,7 +226,7 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te
}
void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
- zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
copy_to_fb.push_constant.use_section = true;
copy_to_fb.push_constant.section[0] = p_uv_rect.position.x;
@@ -247,7 +247,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer
}
void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) {
- zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
if (p_flip_y) {
copy_to_fb.push_constant.flip_y = true;
@@ -275,7 +275,7 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer,
}
void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -309,7 +309,7 @@ void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const
}
void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -329,7 +329,7 @@ void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama,
}
void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -353,7 +353,7 @@ void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_
}
void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -375,7 +375,7 @@ void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture,
}
void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -397,7 +397,7 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i
}
void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
uint32_t base_flags = 0;
copy.push_constant.section[0] = p_region.position.x;
@@ -430,7 +430,7 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back
}
void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;
uint32_t base_flags = 0;
@@ -657,7 +657,7 @@ void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_bas
}
void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -694,7 +694,7 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe
}
void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
- zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant));
+ memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
tonemap.push_constant.use_bcs = p_settings.use_bcs;
tonemap.push_constant.bcs[0] = p_settings.brightness;
@@ -1294,7 +1294,7 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
}
void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
- zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
roughness.push_constant.roughness = p_roughness;
@@ -1368,7 +1368,7 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
SkyPushConstant sky_push_constant;
- zeromem(&sky_push_constant, sizeof(SkyPushConstant));
+ memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
sky_push_constant.proj[0] = p_camera.matrix[2][0];
sky_push_constant.proj[1] = p_camera.matrix[0][0];
@@ -1510,7 +1510,7 @@ EffectsRD::EffectsRD() {
copy_modes.push_back("\n#define MODE_CUBEMAP_ARRAY_TO_PANORAMA\n");
copy.shader.initialize(copy_modes);
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.shader_version = copy.shader.version_create();
for (int i = 0; i < COPY_MODE_MAX; i++) {
@@ -1781,7 +1781,7 @@ EffectsRD::EffectsRD() {
{
// Initialize cubemap filter
- filter.use_high_quality = GLOBAL_GET("rendering/quality/reflections/fast_filter_high_quality");
+ filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality");
Vector<String> cubemap_filter_modes;
cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
diff --git a/servers/rendering/renderer_rd/forward_clustered/SCsub b/servers/rendering/renderer_rd/forward_clustered/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 509495680a..ff57aa94ce 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward.cpp */
+/* render_forward_clustered.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,508 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "renderer_scene_render_forward.h"
+#include "render_forward_clustered.h"
#include "core/config/project_settings.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_server_default.h"
-/* SCENE SHADER */
-void RendererSceneRenderForward::ShaderData::set_code(const String &p_code) {
- //compile
+using namespace RendererSceneRenderImplementation;
- code = p_code;
- valid = false;
- ubo_size = 0;
- uniforms.clear();
- uses_screen_texture = false;
-
- if (code == String()) {
- return; //just invalid, but no error
- }
-
- ShaderCompilerRD::GeneratedCode gen_code;
-
- int blend_mode = BLEND_MODE_MIX;
- int depth_testi = DEPTH_TEST_ENABLED;
- int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
- int cull = CULL_BACK;
-
- uses_point_size = false;
- uses_alpha = false;
- uses_blend_alpha = false;
- uses_depth_pre_pass = false;
- uses_discard = false;
- uses_roughness = false;
- uses_normal = false;
- bool wireframe = false;
-
- unshaded = false;
- uses_vertex = false;
- uses_sss = false;
- uses_transmittance = false;
- uses_screen_texture = false;
- uses_depth_texture = false;
- uses_normal_texture = false;
- uses_time = false;
- writes_modelview_or_projection = false;
- uses_world_coordinates = false;
-
- int depth_drawi = DEPTH_DRAW_OPAQUE;
-
- ShaderCompilerRD::IdentifierActions actions;
-
- actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
- actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
- actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
- actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
-
- actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
- actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
-
- actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
- actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
- actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
-
- actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
-
- actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
- actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
- actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
-
- actions.render_mode_flags["unshaded"] = &unshaded;
- actions.render_mode_flags["wireframe"] = &wireframe;
-
- actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
- actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
-
- actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
- actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
-
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
- actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
- actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
- actions.usage_flag_pointers["DISCARD"] = &uses_discard;
- actions.usage_flag_pointers["TIME"] = &uses_time;
- actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
- actions.usage_flag_pointers["NORMAL"] = &uses_normal;
- actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
-
- actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
- actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
-
- actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
- actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
- actions.write_flag_pointers["VERTEX"] = &uses_vertex;
-
- actions.uniforms = &uniforms;
-
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
-
- Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
-
- if (version.is_null()) {
- version = scene_singleton->shader.scene_shader.version_create();
- }
-
- depth_draw = DepthDraw(depth_drawi);
- depth_test = DepthTest(depth_testi);
-
-#if 0
- print_line("**compiling shader:");
- print_line("**defines:\n");
- for (int i = 0; i < gen_code.defines.size(); i++) {
- print_line(gen_code.defines[i]);
- }
- print_line("\n**uniforms:\n" + gen_code.uniforms);
- print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
-#endif
- scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
- ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version));
-
- ubo_size = gen_code.uniform_total_size;
- ubo_offsets = gen_code.uniform_offsets;
- texture_uniforms = gen_code.texture_uniforms;
-
- //blend modes
-
- // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
- if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
- blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
- }
-
- RD::PipelineColorBlendState::Attachment blend_attachment;
-
- switch (blend_mode) {
- case BLEND_MODE_MIX: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
-
- } break;
- case BLEND_MODE_ADD: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- uses_blend_alpha = true; //force alpha used because of blend
-
- } break;
- case BLEND_MODE_SUB: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
- blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- uses_blend_alpha = true; //force alpha used because of blend
-
- } break;
- case BLEND_MODE_MUL: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
- uses_blend_alpha = true; //force alpha used because of blend
- } break;
- case BLEND_MODE_ALPHA_TO_COVERAGE: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
- }
- }
-
- RD::PipelineColorBlendState blend_state_blend;
- blend_state_blend.attachments.push_back(blend_attachment);
- RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
- RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
- RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
- RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
-
- //update pipelines
-
- RD::PipelineDepthStencilState depth_stencil_state;
-
- if (depth_test != DEPTH_TEST_DISABLED) {
- depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
- }
-
- for (int i = 0; i < CULL_VARIANT_MAX; i++) {
- RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
- };
-
- RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
-
- for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
- RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
- RD::RENDER_PRIMITIVE_POINTS,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_LINESTRIPS,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
- };
-
- RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
-
- for (int k = 0; k < SHADER_VERSION_MAX; k++) {
- if (!static_cast<RendererSceneRenderForward *>(singleton)->shader.scene_shader.is_variant_enabled(k)) {
- continue;
- }
- RD::PipelineRasterizationState raster_state;
- raster_state.cull_mode = cull_mode_rd;
- raster_state.wireframe = wireframe;
-
- RD::PipelineColorBlendState blend_state;
- RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
- RD::PipelineMultisampleState multisample_state;
-
- if (uses_alpha || uses_blend_alpha) {
- // only allow these flags to go through if we have some form of msaa
- if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
- multisample_state.enable_alpha_to_coverage = true;
- } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
- multisample_state.enable_alpha_to_coverage = true;
- multisample_state.enable_alpha_to_one = true;
- }
-
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_blend;
- if (depth_draw == DEPTH_DRAW_OPAQUE) {
- depth_stencil.enable_depth_write = false; //alpha does not draw depth
- }
- } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
- if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, blend state contains nothing
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else {
- blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
- }
- } else {
- pipelines[i][j][k].clear();
- continue; // do not use this version (will error if using it is attempted)
- }
- } else {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_opaque;
- } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, leave empty
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
- blend_state = blend_state_depth_normal_roughness;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
- blend_state = blend_state_depth_normal_roughness_giprobe;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
- blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
- } else {
- //specular write
- blend_state = blend_state_opaque_specular;
- depth_stencil.enable_depth_test = false;
- depth_stencil.enable_depth_write = false;
- }
- }
-
- RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
- }
- }
- }
-
- valid = true;
-}
-
-void RendererSceneRenderForward::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
- if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
- } else {
- default_texture_params[p_name] = p_texture;
- }
-}
-
-void RendererSceneRenderForward::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
- Map<int, StringName> order;
-
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
- continue;
- }
-
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
- } else {
- order[E->get().order] = E->key();
- }
- }
-
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
- p_param_list->push_back(pi);
- }
-}
-
-void RendererSceneRenderForward::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
- p_param_list->push_back(p);
- }
-}
-
-bool RendererSceneRenderForward::ShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RendererSceneRenderForward::ShaderData::is_animated() const {
- return false;
-}
-
-bool RendererSceneRenderForward::ShaderData::casts_shadows() const {
- return false;
-}
-
-Variant RendererSceneRenderForward::ShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
- }
- return Variant();
-}
-
-RS::ShaderNativeSourceCode RendererSceneRenderForward::ShaderData::get_native_source_code() const {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
-
- return scene_singleton->shader.scene_shader.version_get_native_source_code(version);
-}
-
-RendererSceneRenderForward::ShaderData::ShaderData() {
- valid = false;
- uses_screen_texture = false;
-}
-
-RendererSceneRenderForward::ShaderData::~ShaderData() {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
- ERR_FAIL_COND(!scene_singleton);
- //pipeline variants will clear themselves if shader is gone
- if (version.is_valid()) {
- scene_singleton->shader.scene_shader.version_free(version);
- }
-}
-
-RendererStorageRD::ShaderData *RendererSceneRenderForward::_create_shader_func() {
- ShaderData *shader_data = memnew(ShaderData);
- return shader_data;
-}
-
-void RendererSceneRenderForward::MaterialData::set_render_priority(int p_priority) {
- priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
-}
-
-void RendererSceneRenderForward::MaterialData::set_next_pass(RID p_pass) {
- next_pass = p_pass;
-}
-
-void RendererSceneRenderForward::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- RendererSceneRenderForward *scene_singleton = (RendererSceneRenderForward *)RendererSceneRenderForward::singleton;
-
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
-}
-
-RendererSceneRenderForward::MaterialData::~MaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
-}
-
-RendererStorageRD::MaterialData *RendererSceneRenderForward::_create_material_func(ShaderData *p_shader) {
- MaterialData *material_data = memnew(MaterialData);
- material_data->shader_data = p_shader;
- material_data->last_frame = false;
- //update will happen later anyway so do nothing.
- return material_data;
-}
-
-RendererSceneRenderForward::RenderBufferDataForward::~RenderBufferDataForward() {
+RenderForwardClustered::RenderBufferDataForwardClustered::~RenderBufferDataForwardClustered() {
clear();
}
-void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular() {
if (!specular.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@@ -583,7 +93,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::ensure_specular() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() {
if (!giprobe_buffer.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8_UINT;
@@ -619,7 +129,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::ensure_giprobe() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::clear() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
if (giprobe_buffer != RID()) {
RD::get_singleton()->free(giprobe_buffer);
giprobe_buffer = RID();
@@ -673,7 +183,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::clear() {
}
}
-void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
clear();
msaa = p_msaa;
@@ -740,7 +250,7 @@ void RendererSceneRenderForward::RenderBufferDataForward::configure(RID p_color_
}
}
-void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) {
+void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb) {
if (rb->normal_roughness_buffer.is_valid()) {
return;
}
@@ -774,15 +284,13 @@ void RendererSceneRenderForward::_allocate_normal_roughness_texture(RenderBuffer
fb.push_back(rb->normal_roughness_buffer_msaa);
rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb);
}
-
- _render_buffers_clear_uniform_set(rb);
}
-RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForward::_create_render_buffer_data() {
- return memnew(RenderBufferDataForward);
+RendererSceneRenderRD::RenderBufferData *RenderForwardClustered::_create_render_buffer_data() {
+ return memnew(RenderBufferDataForwardClustered);
}
-bool RendererSceneRenderForward::free(RID p_rid) {
+bool RenderForwardClustered::free(RID p_rid) {
if (RendererSceneRenderRD::free(p_rid)) {
return true;
}
@@ -791,15 +299,15 @@ bool RendererSceneRenderForward::free(RID p_rid) {
/// RENDERING ///
-template <RendererSceneRenderForward::PassMode p_pass_mode>
-void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+template <RenderForwardClustered::PassMode p_pass_mode>
+void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RD::DrawListID draw_list = p_draw_list;
RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
//global scope bindings
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
RID prev_material_uniform_set;
@@ -826,7 +334,7 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
push_constant.base_index = i + p_params->element_offset;
RID material_uniform_set;
- ShaderData *shader;
+ SceneShaderForwardClustered::ShaderData *shader;
void *mesh_surface;
if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
@@ -845,59 +353,59 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
}
//find cull variant
- ShaderData::CullVariant cull_variant;
+ SceneShaderForwardClustered::ShaderData::CullVariant cull_variant;
if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
- cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED;
+ cull_variant = SceneShaderForwardClustered::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
} else {
bool mirror = surf->owner->mirror;
if (p_params->reverse_cull) {
mirror = !mirror;
}
- cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL;
+ cull_variant = mirror ? SceneShaderForwardClustered::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardClustered::ShaderData::CULL_VARIANT_NORMAL;
}
RS::PrimitiveType primitive = surf->primitive;
RID xforms_uniform_set = surf->owner->transforms_uniform_set;
- ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+ SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
switch (p_params->pass_mode) {
case PASS_MODE_COLOR:
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
} else if (element_info.uses_forward_gi) {
- shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
} else {
- shader_version = SHADER_VERSION_COLOR_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS;
}
} break;
case PASS_MODE_COLOR_SPECULAR: {
if (element_info.uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
} else {
- shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
}
} break;
case PASS_MODE_SHADOW:
case PASS_MODE_DEPTH: {
- shader_version = SHADER_VERSION_DEPTH_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS;
} break;
case PASS_MODE_SHADOW_DP: {
- shader_version = SHADER_VERSION_DEPTH_PASS_DP;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_DP;
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
} break;
case PASS_MODE_SDF: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_SDF;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_SDF;
} break;
}
@@ -956,12 +464,16 @@ void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawList
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
+ instance_count /= surf->owner->trail_steps;
+ }
+
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
i += element_info.repeat - 1; //skip equal elements
}
}
-void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
//use template for faster performance (pass mode comparisons are inlined)
switch (p_params->pass_mode) {
@@ -998,7 +510,7 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw
}
}
-void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
+void RenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
uint32_t render_total = p_params->element_count;
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
uint32_t render_from = p_thread * render_total / total_threads;
@@ -1006,7 +518,7 @@ void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread,
_render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
}
-void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
p_params->framebuffer_format = fb_format;
@@ -1014,7 +526,7 @@ void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters
//multi threaded
thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForward::_render_list_thread_function, p_params);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardClustered::_render_list_thread_function, p_params);
RD::get_singleton()->draw_list_end(p_params->barrier);
} else {
//single threaded
@@ -1024,7 +536,7 @@ void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters
}
}
-void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
//CameraMatrix projection = p_cam_projection;
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
CameraMatrix correction;
@@ -1083,7 +595,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren
scene_state.ubo.fog_enabled = false;
if (p_render_buffers.is_valid()) {
- RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ RenderBufferDataForwardClustered *render_buffers = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
scene_state.ubo.gi_upscale_for_msaa = true;
}
@@ -1130,7 +642,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren
//vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) );
//vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx;
- uint32_t oct_size = sdfgi_get_lightprobe_octahedron_size();
+ uint32_t oct_size = gi.sdfgi_get_lightprobe_octahedron_size();
scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size * scene_state.ubo.sdfgi_probe_axis_size);
scene_state.ubo.sdfgi_lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * scene_state.ubo.sdfgi_probe_axis_size);
@@ -1274,7 +786,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
-void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_render_list) {
+void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
if (scene_state.instance_data[p_render_list].size() > 0) {
if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) {
if (scene_state.instance_buffer[p_render_list] != RID()) {
@@ -1287,7 +799,7 @@ void RendererSceneRenderForward::_update_instance_data_buffer(RenderListType p_r
RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
}
}
-void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
@@ -1298,7 +810,7 @@ void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_lis
GeometryInstanceSurfaceDataCache *prev_surface = nullptr;
for (uint32_t i = 0; i < element_total; i++) {
GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
- GeometryInstanceForward *inst = surface->owner;
+ GeometryInstanceForwardClustered *inst = surface->owner;
SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset];
@@ -1355,7 +867,7 @@ void RendererSceneRenderForward::_fill_instance_data(RenderListType p_render_lis
}
}
-void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
scene_state.used_screen_texture = false;
@@ -1381,7 +893,7 @@ void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list,
//fill list
for (int i = 0; i < (int)p_instances.size(); i++) {
- GeometryInstanceForward *inst = static_cast<GeometryInstanceForward *>(p_instances[i]);
+ GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>(p_instances[i]);
Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
inst->depth = near_plane.distance_to(support_min);
@@ -1431,7 +943,7 @@ void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list,
uses_lightmap = true;
}
- } else if (!low_end) {
+ } else {
if (p_using_opaque_gi) {
flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS;
}
@@ -1549,14 +1061,14 @@ void RendererSceneRenderForward::_fill_render_list(RenderListType p_render_list,
}
}
-void RendererSceneRenderForward::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
+void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES));
for (uint32_t i = 0; i < scene_state.giprobes_used; i++) {
scene_state.giprobe_ids[i] = p_giprobes[i];
}
}
-void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
@@ -1578,11 +1090,12 @@ void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<RID> &p_light
}
}
-void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
- RenderBufferDataForward *render_buffer = nullptr;
+void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
+ RenderBufferDataForwardClustered *render_buffer = nullptr;
if (p_render_buffer.is_valid()) {
- render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer);
+ render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffer);
}
+ RendererSceneEnvironmentRD *env = get_environment(p_environment);
//first of all, make a new render pass
//fill up ubo
@@ -1615,6 +1128,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
bool using_ssr = false;
bool using_sdfgi = false;
bool using_giprobe = false;
+ bool reverse_cull = false;
if (render_buffer) {
screen_size.x = render_buffer->width;
@@ -1622,7 +1136,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
opaque_framebuffer = render_buffer->color_fb;
- if (!low_end && p_gi_probes.size() > 0) {
+ if (p_gi_probes.size() > 0) {
using_giprobe = true;
}
@@ -1681,6 +1195,8 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
p_environment = RID(); //no environment on interiors
}
+
+ reverse_cull = true; // for some reason our views are inverted
} else {
ERR_FAIL(); //bug?
}
@@ -1701,7 +1217,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RD::get_singleton()->draw_command_end_label();
- bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
+ bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
if (using_sss) {
using_separate_specular = true;
@@ -1729,7 +1245,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
draw_sky_fog_only = true;
- storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
} break;
case RS::ENV_BG_COLOR: {
@@ -1739,7 +1255,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
draw_sky_fog_only = true;
- storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
} break;
case RS::ENV_BG_SKY: {
@@ -1767,12 +1283,12 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
projection = correction * p_cam_projection;
}
- _setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size);
+ sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this);
- RID sky = environment_get_sky(p_environment);
- if (sky.is_valid()) {
- _update_sky(p_environment, projection, p_cam_transform);
- radiance_texture = sky_get_radiance_texture_rd(sky);
+ RID sky_rid = env->sky;
+ if (sky_rid.is_valid()) {
+ sky.update(env, projection, p_cam_transform, time);
+ radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
draw_sky = false;
@@ -1785,7 +1301,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
- bool depth_pre_pass = !low_end && depth_framebuffer.is_valid();
+ bool depth_pre_pass = depth_framebuffer.is_valid();
bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment);
bool continue_depth = false;
@@ -1810,7 +1326,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
bool finish_depth = using_ssao || using_sdfgi || using_giprobe;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1868,7 +1384,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
}
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
_render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1890,7 +1406,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
RD::get_singleton()->draw_command_begin_label("Debug GIProbes");
for (int i = 0; i < (int)p_gi_probes.size(); i++) {
- _debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);
+ gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_list_end();
@@ -1921,7 +1437,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
projection = correction * p_cam_projection;
}
RD::get_singleton()->draw_command_begin_label("Draw Sky");
- _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform);
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time);
RD::get_singleton()->draw_command_end_label();
}
@@ -1980,7 +1496,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_shadow_begin() {
+void RenderForwardClustered::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
_update_render_base_uniform_set();
@@ -1988,7 +1504,7 @@ void RendererSceneRenderForward::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RendererSceneRenderForward::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
@@ -2035,7 +1551,7 @@ void RendererSceneRenderForward::_render_shadow_append(RID p_framebuffer, const
}
}
-void RendererSceneRenderForward::_render_shadow_process() {
+void RenderForwardClustered::_render_shadow_process() {
_update_instance_data_buffer(RENDER_LIST_SECONDARY);
//render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time)
@@ -2047,7 +1563,7 @@ void RendererSceneRenderForward::_render_shadow_process() {
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) {
+void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_begin_label("Shadow Render");
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
@@ -2062,7 +1578,7 @@ void RendererSceneRenderForward::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
RENDER_TIMESTAMP("Setup Render Collider Heightfield");
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
@@ -2090,7 +1606,7 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb,
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
@@ -2128,7 +1644,7 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering UV2");
RD::get_singleton()->draw_command_begin_label("Render UV2");
@@ -2190,14 +1706,14 @@ void RendererSceneRenderForward::_render_uv2(const PagedArray<GeometryInstance *
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
RENDER_TIMESTAMP("Render SDFGI");
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
_update_render_base_uniform_set();
- RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ RenderBufferDataForwardClustered *render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
ERR_FAIL_COND(!render_buffer);
PassMode pass_mode = PASS_MODE_SDF;
@@ -2271,14 +1787,14 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForward::_base_uniforms_changed() {
+void RenderForwardClustered::_base_uniforms_changed() {
if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
render_base_uniform_set = RID();
}
-void RendererSceneRenderForward::_update_render_base_uniform_set() {
+void RenderForwardClustered::_update_render_base_uniform_set() {
if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
@@ -2313,7 +1829,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(shadow_sampler);
+ u.ids.push_back(scene_shader.shadow_sampler);
uniforms.push_back(u);
}
@@ -2392,7 +1908,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- if (!low_end) {
+ {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 13;
@@ -2400,17 +1916,17 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
}
-RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
+RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
- RenderBufferDataForward *rb = nullptr;
+ RenderBufferDataForwardClustered *rb = nullptr;
if (p_render_buffers.is_valid()) {
- rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
}
//default render buffer and scene state uniform set
@@ -2430,7 +1946,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[p_render_list];
if (instance_buffer == RID()) {
- instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // any buffer will do since its not used
}
u.ids.push_back(instance_buffer);
uniforms.push_back(u);
@@ -2514,7 +2030,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_GI_PROBES; i++) {
if (i < (int)p_gi_probes.size()) {
- RID tex = gi_probe_instance_get_texture(p_gi_probes[i]);
+ RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]);
if (!tex.is_valid()) {
tex = default_tex;
}
@@ -2531,7 +2047,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
+ RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : scene_shader.default_vec4_xform_buffer;
u.ids.push_back(cb);
uniforms.push_back(u);
}
@@ -2554,7 +2070,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
uniforms.push_back(u);
}
- if (!low_end) {
+ {
{
RD::Uniform u;
u.binding = 11;
@@ -2650,11 +2166,11 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RenderListType p_
RD::get_singleton()->free(render_pass_uniform_sets[p_index]);
}
- render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET);
+ render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET);
return render_pass_uniform_sets[p_index];
}
-RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) {
+RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) {
if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) {
RD::get_singleton()->free(sdfgi_pass_uniform_set);
}
@@ -2747,7 +2263,7 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = default_vec4_xform_buffer;
+ RID cb = scene_shader.default_vec4_xform_buffer;
u.ids.push_back(cb);
uniforms.push_back(u);
}
@@ -2783,34 +2299,20 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed
uniforms.push_back(u);
}
- sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET);
+ sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET);
return sdfgi_pass_uniform_set;
}
-void RendererSceneRenderForward::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) {
-}
-
-void RendererSceneRenderForward::_render_buffers_uniform_set_changed(RID p_render_buffers) {
- RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
-
- _render_buffers_clear_uniform_set(rb);
-}
-
-RID RendererSceneRenderForward::_render_buffers_get_normal_texture(RID p_render_buffers) {
- RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+RID RenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
+ RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
return rb->normal_roughness_buffer;
}
-RendererSceneRenderForward *RendererSceneRenderForward::singleton = nullptr;
-
-void RendererSceneRenderForward::set_time(double p_time, double p_step) {
- time = p_time;
- RendererSceneRenderRD::set_time(p_time, p_step);
-}
+RenderForwardClustered *RenderForwardClustered::singleton = nullptr;
-void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->dirty_list_element.in_list()) {
return;
}
@@ -2829,7 +2331,7 @@ void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance
geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
}
-void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+void RenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha);
bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
@@ -2853,14 +2355,14 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
}
- if (ginstance->data->cast_double_sided_shaodows) {
+ if (ginstance->data->cast_double_sided_shadows) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
}
- if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) {
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED) {
//material is only meant for alpha pass
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
- if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) {
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
@@ -2870,11 +2372,15 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
- MaterialData *material_shadow = nullptr;
+ if (p_material->shader_data->uses_particle_trails) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
+ }
+
+ SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
- material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
@@ -2925,15 +2431,15 @@ void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(Ge
sdcache->sort.priority = p_material->priority;
}
-void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
RID m_src;
m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
- MaterialData *material = nullptr;
+ SceneShaderForwardClustered::MaterialData *material = nullptr;
if (m_src.is_valid()) {
- material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -2944,8 +2450,8 @@ void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstance
storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
}
} else {
- material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
- m_src = default_material;
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+ m_src = scene_shader.default_material;
}
ERR_FAIL_COND(!material);
@@ -2954,7 +2460,7 @@ void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstance
while (material->next_pass.is_valid()) {
RID next_pass = material->next_pass;
- material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
if (!material || !material->shader_data->valid) {
break;
}
@@ -2965,8 +2471,8 @@ void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstance
}
}
-void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->data->dirty_dependencies) {
ginstance->data->dependency_tracker.update_begin();
@@ -3026,8 +2532,9 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
for (int j = 0; j < draw_passes; j++) {
RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
- if (!mesh.is_valid())
+ if (!mesh.is_valid()) {
continue;
+ }
const RID *materials = nullptr;
uint32_t surface_count;
@@ -3040,7 +2547,7 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
}
}
- ginstance->instance_count = storage->particles_get_amount(ginstance->data->base);
+ ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps);
} break;
@@ -3054,52 +2561,35 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
- uint32_t stride;
if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
- stride = 2;
- } else {
- stride = 3;
}
if (storage->multimesh_uses_colors(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
- stride += 1;
}
if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
- stride += 1;
}
- ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
- ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
- uint32_t stride;
- if (false) { // 2D particles
- ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
- stride = 2;
- } else {
- stride = 3;
- }
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
- stride += 1;
-
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
- stride += 1;
- ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
+ //for particles, stride is the trail size
+ ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT);
if (!storage->particles_is_using_local_coords(ginstance->data->base)) {
store_transform = false;
}
- ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
- ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON;
- ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
if (ginstance->data->dirty_dependencies) {
storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
}
@@ -3109,7 +2599,7 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
ginstance->store_transform_cache = store_transform;
ginstance->can_sdfgi = false;
- if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) {
+ if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
@@ -3123,24 +2613,25 @@ void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_g
ginstance->dirty_list_element.remove_from_list();
}
-void RendererSceneRenderForward::_update_dirty_geometry_instances() {
+void RenderForwardClustered::_update_dirty_geometry_instances() {
while (geometry_instance_dirty_list.first()) {
_geometry_instance_update(geometry_instance_dirty_list.first()->self());
}
}
-void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+void RenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
switch (p_notification) {
case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
- static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
} break;
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_tracker->userdata);
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata);
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
- ginstance->instance_count = static_cast<RendererSceneRenderForward *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ ginstance->instance_count = static_cast<RenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
}
} break;
default: {
@@ -3148,16 +2639,16 @@ void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererS
} break;
}
}
-void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
- static_cast<RendererSceneRenderForward *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+void RenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
+ static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
}
-RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) {
+RendererSceneRender::GeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_base) {
RS::InstanceType type = storage->get_base_type(p_base);
ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
- GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc();
- ginstance->data = memnew(GeometryInstanceForward::Data);
+ GeometryInstanceForwardClustered *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceForwardClustered::Data);
ginstance->data->base = p_base;
ginstance->data->base_type = type;
@@ -3169,35 +2660,35 @@ RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_inst
return ginstance;
}
-void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->skeleton = p_skeleton;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->material_override = p_override;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->surface_materials = p_materials;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->mesh_instance = p_mesh_instance;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->transform = p_transform;
ginstance->mirror = p_transform.basis.determinant() < 0;
@@ -3213,40 +2704,40 @@ void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstanc
ginstance->lod_model_scale = max_scale;
}
-void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->lod_bias = p_lod_bias;
}
-void RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->use_baked_light = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->use_dynamic_gi = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->lightmap_instance = p_lightmap_instance;
ginstance->lightmap_uv_scale = p_lightmap_uv_scale;
ginstance->lightmap_slice_index = p_lightmap_slice_index;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (p_sh9) {
if (ginstance->lightmap_sh == nullptr) {
ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc();
}
- copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
+ memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
} else {
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
@@ -3255,28 +2746,28 @@ void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(Geometry
}
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->shader_parameters_offset = p_offset;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
- ginstance->data->cast_double_sided_shaodows = p_enable;
+ ginstance->data->cast_double_sided_shadows = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->layer_mask = p_layer_mask;
}
-void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
@@ -3291,29 +2782,29 @@ void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geom
geometry_instance_alloc.free(ginstance);
}
-uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() {
+uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() {
return (1 << RS::INSTANCE_GI_PROBE);
}
-void RendererSceneRenderForward::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
}
-void RendererSceneRenderForward::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
}
-void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
}
-Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance);
+Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, Transform());
return ginstance->transform;
}
-AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_instance);
+AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, AABB());
return ginstance->data->aabb;
}
-void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
- GeometryInstanceForward *ginstance = static_cast<GeometryInstanceForward *>(p_geometry_instance);
+void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+ GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (p_gi_probe_instance_count > 0) {
ginstance->gi_probes[0] = p_gi_probe_instances[0];
@@ -3328,30 +2819,24 @@ void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(Geome
}
}
-RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) :
+RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
- low_end = is_low_end();
- storage = p_storage;
/* SCENE SHADER */
{
String defines;
- if (low_end) {
- defines += "\n#define LOW_END_MODE \n";
- }
-
defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
if (is_using_radiance_cubemap_array()) {
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
}
- defines += "\n#define SDFGI_OCT_SIZE " + itos(sdfgi_get_lightprobe_octahedron_size()) + "\n";
+ defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
{
//lightmaps
- scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS;
+ scene_state.max_lightmaps = MAX_LIGHTMAPS;
defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n";
defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n";
@@ -3367,261 +2852,13 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
}
- Vector<String> shader_versions;
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
- shader_versions.push_back("");
- shader_versions.push_back("\n#define USE_FORWARD_GI\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
- shader_versions.push_back("\n#define USE_LIGHTMAP\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
- shader.scene_shader.initialize(shader_versions, defines);
-
- if (is_low_end()) {
- //disable the high end versions
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- }
- }
-
- storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
- storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
-
- {
- //shader compiler
- ShaderCompilerRD::DefaultIdentifierActions actions;
-
- actions.renames["WORLD_MATRIX"] = "world_matrix";
- actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
- actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
- actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
- actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
- actions.renames["MODELVIEW_MATRIX"] = "modelview";
- actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
-
- actions.renames["VERTEX"] = "vertex";
- actions.renames["NORMAL"] = "normal";
- actions.renames["TANGENT"] = "tangent";
- actions.renames["BINORMAL"] = "binormal";
- actions.renames["POSITION"] = "position";
- actions.renames["UV"] = "uv_interp";
- actions.renames["UV2"] = "uv2_interp";
- actions.renames["COLOR"] = "color_interp";
- actions.renames["POINT_SIZE"] = "gl_PointSize";
- actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
-
- actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
- actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
- actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
- actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
-
- //builtins
-
- actions.renames["TIME"] = "scene_data.time";
- actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
-
- actions.renames["FRAGCOORD"] = "gl_FragCoord";
- actions.renames["FRONT_FACING"] = "gl_FrontFacing";
- actions.renames["NORMAL_MAP"] = "normal_map";
- actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
- actions.renames["ALBEDO"] = "albedo";
- actions.renames["ALPHA"] = "alpha";
- actions.renames["METALLIC"] = "metallic";
- actions.renames["SPECULAR"] = "specular";
- actions.renames["ROUGHNESS"] = "roughness";
- actions.renames["RIM"] = "rim";
- actions.renames["RIM_TINT"] = "rim_tint";
- actions.renames["CLEARCOAT"] = "clearcoat";
- actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
- actions.renames["ANISOTROPY"] = "anisotropy";
- actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- actions.renames["SSS_STRENGTH"] = "sss_strength";
- actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
- actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
- actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
- actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
- actions.renames["BACKLIGHT"] = "backlight";
- actions.renames["AO"] = "ao";
- actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
- actions.renames["EMISSION"] = "emission";
- actions.renames["POINT_COORD"] = "gl_PointCoord";
- actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
- actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "color_buffer";
- actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
- actions.renames["DEPTH"] = "gl_FragDepth";
- actions.renames["OUTPUT_IS_SRGB"] = "true";
- actions.renames["FOG"] = "custom_fog";
- actions.renames["RADIANCE"] = "custom_radiance";
- actions.renames["IRRADIANCE"] = "custom_irradiance";
- actions.renames["BONE_INDICES"] = "bone_attrib";
- actions.renames["BONE_WEIGHTS"] = "weight_attrib";
- actions.renames["CUSTOM0"] = "custom0_attrib";
- actions.renames["CUSTOM1"] = "custom1_attrib";
- actions.renames["CUSTOM2"] = "custom2_attrib";
- actions.renames["CUSTOM3"] = "custom3_attrib";
-
- //for light
- actions.renames["VIEW"] = "view";
- actions.renames["LIGHT_COLOR"] = "light_color";
- actions.renames["LIGHT"] = "light";
- actions.renames["ATTENUATION"] = "attenuation";
- actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
- actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
- actions.renames["SPECULAR_LIGHT"] = "specular_light";
-
- actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
- actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
- actions.usage_defines["BINORMAL"] = "@TANGENT";
- actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
- actions.usage_defines["RIM_TINT"] = "@RIM";
- actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
- actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
- actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
- actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
- actions.usage_defines["AO"] = "#define AO_USED\n";
- actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
- actions.usage_defines["UV"] = "#define UV_USED\n";
- actions.usage_defines["UV2"] = "#define UV2_USED\n";
- actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
- actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
- actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
- actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
- actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
- actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
-
- actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
- actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
- actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
- actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
-
- actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
- actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
- actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
-
- actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
- actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
- actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
- actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
-
- actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
- actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
- actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
- actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
- actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
-
- bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley");
-
- if (!force_lambert) {
- actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
- }
-
- actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
- actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
- actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
-
- actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
-
- bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
-
- if (!force_blinn) {
- actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
- } else {
- actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
- }
-
- actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
- actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
- actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
- actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
- actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
- actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
- actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
- actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
-
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = MATERIAL_UNIFORM_SET;
- actions.base_uniform_string = "material.";
- actions.base_varying_index = 10;
-
- actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
- actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
-
- shader.compiler.initialize(actions);
- }
-
- {
- //default material and shader
- default_shader = storage->shader_create();
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
- default_material = storage->material_create();
- storage->material_set_shader(default_material, default_shader);
-
- MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
- default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
- if (!low_end) {
- default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
- }
- }
-
- {
- overdraw_material_shader = storage->shader_create();
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
- overdraw_material = storage->material_create();
- storage->material_set_shader(overdraw_material, overdraw_material_shader);
-
- wireframe_material_shader = storage->shader_create();
- storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
- wireframe_material = storage->material_create();
- storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ scene_shader.init(p_storage, defines);
}
- {
- default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(default_vec4_xform_buffer);
- u.binding = 0;
- uniforms.push_back(u);
-
- default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, TRANSFORMS_UNIFORM_SET);
- }
- {
- RD::SamplerState sampler;
- sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
- shadow_sampler = RD::get_singleton()->sampler_create(sampler);
- }
-
- render_list_thread_threshold = GLOBAL_GET("rendering/forward_renderer/threaded_render_minimum_instances");
+ render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
}
-RendererSceneRenderForward::~RendererSceneRenderForward() {
+RenderForwardClustered::~RenderForwardClustered() {
directional_shadow_atlas_set_size(0);
//clear base uniform set if still valid
@@ -3635,17 +2872,6 @@ RendererSceneRenderForward::~RendererSceneRenderForward() {
RD::get_singleton()->free(sdfgi_pass_uniform_set);
}
- RD::get_singleton()->free(default_vec4_xform_buffer);
- RD::get_singleton()->free(shadow_sampler);
-
- storage->free(wireframe_material_shader);
- storage->free(overdraw_material_shader);
- storage->free(default_shader);
-
- storage->free(wireframe_material);
- storage->free(overdraw_material);
- storage->free(default_material);
-
{
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
RD::get_singleton()->free(scene_state.uniform_buffers[i]);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index af78c50fda..4b998a9e76 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward.h */
+/* render_forward_clustered.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H
-#define RENDERING_SERVER_SCENE_RENDER_FORWARD_H
+#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
+#define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class RenderForwardClustered : public RendererSceneRenderRD {
+ friend SceneShaderForwardClustered;
-class RendererSceneRenderForward : public RendererSceneRenderRD {
enum {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
@@ -63,157 +68,11 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
/* Scene Shader */
- enum ShaderVersion {
- SHADER_VERSION_DEPTH_PASS,
- SHADER_VERSION_DEPTH_PASS_DP,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
- SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
- SHADER_VERSION_DEPTH_PASS_WITH_SDF,
- SHADER_VERSION_COLOR_PASS,
- SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
- SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_MAX
- };
-
- struct {
- SceneForwardShaderRD scene_shader;
- ShaderCompilerRD compiler;
- } shader;
-
- RendererStorageRD *storage;
-
- /* Material */
-
- struct ShaderData : public RendererStorageRD::ShaderData {
- enum BlendMode { //used internally
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- BLEND_MODE_ALPHA_TO_COVERAGE
- };
-
- enum DepthDraw {
- DEPTH_DRAW_DISABLED,
- DEPTH_DRAW_OPAQUE,
- DEPTH_DRAW_ALWAYS
- };
-
- enum DepthTest {
- DEPTH_TEST_DISABLED,
- DEPTH_TEST_ENABLED
- };
-
- enum Cull {
- CULL_DISABLED,
- CULL_FRONT,
- CULL_BACK
- };
-
- enum CullVariant {
- CULL_VARIANT_NORMAL,
- CULL_VARIANT_REVERSED,
- CULL_VARIANT_DOUBLE_SIDED,
- CULL_VARIANT_MAX
-
- };
-
- enum AlphaAntiAliasing {
- ALPHA_ANTIALIASING_OFF,
- ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
- ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
- };
-
- bool valid;
- RID version;
- uint32_t vertex_input_mask;
- PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
-
- String path;
-
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
- Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
- Vector<uint32_t> ubo_offsets;
- uint32_t ubo_size;
-
- String code;
- Map<StringName, RID> default_texture_params;
-
- DepthDraw depth_draw;
- DepthTest depth_test;
-
- bool uses_point_size;
- bool uses_alpha;
- bool uses_blend_alpha;
- bool uses_alpha_clip;
- bool uses_depth_pre_pass;
- bool uses_discard;
- bool uses_roughness;
- bool uses_normal;
-
- bool unshaded;
- bool uses_vertex;
- bool uses_sss;
- bool uses_transmittance;
- bool uses_screen_texture;
- bool uses_depth_texture;
- bool uses_normal_texture;
- bool uses_time;
- bool writes_modelview_or_projection;
- bool uses_world_coordinates;
-
- uint64_t last_pass = 0;
- uint32_t index = 0;
-
- virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
- void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_param_texture(const StringName &p_param) const;
- virtual bool is_animated() const;
- virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
- virtual RS::ShaderNativeSourceCode get_native_source_code() const;
-
- ShaderData();
- virtual ~ShaderData();
- };
-
- RendererStorageRD::ShaderData *_create_shader_func();
- static RendererStorageRD::ShaderData *_create_shader_funcs() {
- return static_cast<RendererSceneRenderForward *>(singleton)->_create_shader_func();
- }
-
- struct MaterialData : public RendererStorageRD::MaterialData {
- uint64_t last_frame;
- ShaderData *shader_data;
- RID uniform_buffer;
- RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
- uint64_t last_pass = 0;
- uint32_t index = 0;
- RID next_pass;
- uint8_t priority;
- virtual void set_render_priority(int p_priority);
- virtual void set_next_pass(RID p_pass);
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
- virtual ~MaterialData();
- };
-
- RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
- return static_cast<RendererSceneRenderForward *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
- }
+ SceneShaderForwardClustered scene_shader;
/* Framebuffer */
- struct RenderBufferDataForward : public RenderBufferData {
+ struct RenderBufferDataForwardClustered : public RenderBufferData {
//for rendering, may be MSAAd
RID color;
@@ -246,13 +105,12 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
- ~RenderBufferDataForward();
+ ~RenderBufferDataForwardClustered();
};
virtual RenderBufferData *_create_render_buffer_data();
- void _allocate_normal_roughness_texture(RenderBufferDataForward *rb);
+ void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb);
- RID shadow_sampler;
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
RID sdfgi_pass_uniform_set;
@@ -260,8 +118,6 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
virtual void _base_uniforms_changed();
- void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb);
- virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
void _update_render_base_uniform_set();
@@ -338,12 +194,13 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
- INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16,
- INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7,
- INSTANCE_DATA_FLAG_SKELETON = 1 << 19,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
};
struct SceneState {
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
struct UBO {
float projection_matrix[16];
float inv_projection_matrix[16];
@@ -490,20 +347,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
} scene_state;
- static RendererSceneRenderForward *singleton;
-
- double time;
- RID default_shader;
- RID default_material;
- RID overdraw_material_shader;
- RID overdraw_material;
- RID wireframe_material_shader;
- RID wireframe_material;
- RID default_shader_rd;
- RID default_shader_sdfgi_rd;
-
- RID default_vec4_xform_buffer;
- RID default_vec4_xform_uniform_set;
+ static RenderForwardClustered *singleton;
void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_giprobes(const PagedArray<RID> &p_giprobes);
@@ -534,7 +378,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
Map<Size2i, RID> sdfgi_framebuffer_size_cache;
struct GeometryInstanceData;
- struct GeometryInstanceForward;
+ struct GeometryInstanceForwardClustered;
struct GeometryInstanceLightmapSH {
Color sh[9];
@@ -553,6 +397,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
FLAG_USES_DEPTH_TEXTURE = 8192,
FLAG_USES_NORMAL_TEXTURE = 16384,
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
+ FLAG_USES_PARTICLE_TRAILS = 65536,
};
union {
@@ -581,17 +426,17 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
void *surface = nullptr;
RID material_uniform_set;
- ShaderData *shader = nullptr;
+ SceneShaderForwardClustered::ShaderData *shader = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
- ShaderData *shader_shadow = nullptr;
+ SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr;
GeometryInstanceSurfaceDataCache *next = nullptr;
- GeometryInstanceForward *owner = nullptr;
+ GeometryInstanceForwardClustered *owner = nullptr;
};
- struct GeometryInstanceForward : public GeometryInstance {
+ struct GeometryInstanceForwardClustered : public GeometryInstance {
//used during rendering
bool mirror = false;
bool non_uniform_scale = false;
@@ -608,6 +453,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
uint32_t layer_mask = 1;
RID transforms_uniform_set;
uint32_t instance_count = 0;
+ uint32_t trail_steps = 1;
RID mesh_instance;
bool can_sdfgi = false;
//used during setup
@@ -617,7 +463,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
RID lightmap_instance;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
- SelfList<GeometryInstanceForward> dirty_list_element;
+ SelfList<GeometryInstanceForwardClustered> dirty_list_element;
struct Data {
//data used less often goes into regular heap
@@ -631,7 +477,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
bool use_dynamic_gi = false;
bool use_baked_light = false;
- bool cast_double_sided_shaodows = false;
+ bool cast_double_sided_shadows = false;
bool mirror = false;
bool dirty_dependencies = false;
@@ -640,27 +486,25 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {
Data *data = nullptr;
- GeometryInstanceForward() :
+ GeometryInstanceForwardClustered() :
dirty_list_element(this) {}
};
static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
- SelfList<GeometryInstanceForward>::List geometry_instance_dirty_list;
+ SelfList<GeometryInstanceForwardClustered>::List geometry_instance_dirty_list;
- PagedAllocator<GeometryInstanceForward> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceForwardClustered> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
- void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
- void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
void _geometry_instance_update(GeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
- bool low_end = false;
-
/* Render List */
struct RenderList {
@@ -761,11 +605,10 @@ public:
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count);
- virtual void set_time(double p_time, double p_step);
-
virtual bool free(RID p_rid);
- RendererSceneRenderForward(RendererStorageRD *p_storage);
- ~RendererSceneRenderForward();
+ RenderForwardClustered(RendererStorageRD *p_storage);
+ ~RenderForwardClustered();
};
-#endif // RASTERIZER_SCENE_HIGHEND_RD_H
+} // namespace RendererSceneRenderImplementation
+#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
new file mode 100644
index 0000000000..f7ed0205af
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -0,0 +1,806 @@
+/*************************************************************************/
+/* scene_shader_forward_clustered.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "scene_shader_forward_clustered.h"
+#include "core/config/project_settings.h"
+#include "render_forward_clustered.h"
+
+using namespace RendererSceneRenderImplementation;
+
+void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+
+ int blend_mode = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
+ int cull = CULL_BACK;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ bool wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+ uses_particle_trails = false;
+
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+
+ actions.uniforms = &uniforms;
+
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+ Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = shader_singleton->shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+
+ Map<String, String>::Element * el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]);
+#endif
+ shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
+ ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //blend modes
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ RD::PipelineColorBlendState::Attachment blend_attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_SUB: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_MUL: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ uses_blend_alpha = true; //force alpha used because of blend
+ } break;
+ case BLEND_MODE_ALPHA_TO_COVERAGE: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ }
+ }
+
+ RD::PipelineColorBlendState blend_state_blend;
+ blend_state_blend.attachments.push_back(blend_attachment);
+ RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
+
+ //update pipelines
+
+ RD::PipelineDepthStencilState depth_stencil_state;
+
+ if (depth_test != DEPTH_TEST_DISABLED) {
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+ }
+
+ for (int i = 0; i < CULL_VARIANT_MAX; i++) {
+ RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
+ };
+
+ RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
+
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ };
+
+ RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
+
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) {
+ continue;
+ }
+ RD::PipelineRasterizationState raster_state;
+ raster_state.cull_mode = cull_mode_rd;
+ raster_state.wireframe = wireframe;
+
+ RD::PipelineColorBlendState blend_state;
+ RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ RD::PipelineMultisampleState multisample_state;
+
+ if (uses_alpha || uses_blend_alpha) {
+ // only allow these flags to go through if we have some form of msaa
+ if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ multisample_state.enable_alpha_to_one = true;
+ }
+
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_blend;
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
+ }
+ } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
+ if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+ }
+ } else {
+ pipelines[i][j][k].clear();
+ continue; // do not use this version (will error if using it is attempted)
+ }
+ } else {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_opaque;
+ } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, leave empty
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
+ blend_state = blend_state_depth_normal_roughness;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
+ blend_state = blend_state_depth_normal_roughness_giprobe;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
+ blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
+ } else {
+ //specular write
+ blend_state = blend_state_opaque_specular;
+ depth_stencil.enable_depth_test = false;
+ depth_stencil.enable_depth_write = false;
+ }
+ }
+
+ RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ }
+ }
+ }
+
+ valid = true;
+}
+
+void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+ return shader_singleton->shader.version_get_native_source_code(version);
+}
+
+SceneShaderForwardClustered::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderForwardClustered::ShaderData::~ShaderData() {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+ ERR_FAIL_COND(!shader_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ shader_singleton->shader.version_free(version);
+ }
+}
+
+RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+
+void SceneShaderForwardClustered::MaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET);
+}
+
+SceneShaderForwardClustered::MaterialData::~MaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
+ MaterialData *material_data = memnew(MaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr;
+
+SceneShaderForwardClustered::SceneShaderForwardClustered() {
+ // there should be only one of these, contained within our RenderFM singleton.
+ singleton = this;
+}
+
+SceneShaderForwardClustered::~SceneShaderForwardClustered() {
+ RD::get_singleton()->free(default_vec4_xform_buffer);
+ RD::get_singleton()->free(shadow_sampler);
+
+ storage->free(wireframe_material_shader);
+ storage->free(overdraw_material_shader);
+ storage->free(default_shader);
+
+ storage->free(wireframe_material);
+ storage->free(overdraw_material);
+ storage->free(default_material);
+}
+
+void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const String p_defines) {
+ storage = p_storage;
+
+ {
+ Vector<String> shader_versions;
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
+ shader_versions.push_back("");
+ shader_versions.push_back("\n#define USE_FORWARD_GI\n");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
+ shader.initialize(shader_versions, p_defines);
+ }
+
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
+
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
+ actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
+ actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
+ actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
+ actions.renames["MODELVIEW_MATRIX"] = "modelview";
+ actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["TANGENT"] = "tangent";
+ actions.renames["BINORMAL"] = "binormal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["UV"] = "uv_interp";
+ actions.renames["UV2"] = "uv2_interp";
+ actions.renames["COLOR"] = "color_interp";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+ //builtins
+
+ actions.renames["TIME"] = "scene_data.time";
+ actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["METALLIC"] = "metallic";
+ actions.renames["SPECULAR"] = "specular";
+ actions.renames["ROUGHNESS"] = "roughness";
+ actions.renames["RIM"] = "rim";
+ actions.renames["RIM_TINT"] = "rim_tint";
+ actions.renames["CLEARCOAT"] = "clearcoat";
+ actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions.renames["ANISOTROPY"] = "anisotropy";
+ actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions.renames["SSS_STRENGTH"] = "sss_strength";
+ actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+ actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+ actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
+ actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+ actions.renames["BACKLIGHT"] = "backlight";
+ actions.renames["AO"] = "ao";
+ actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+ actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["RADIANCE"] = "custom_radiance";
+ actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+ actions.usage_defines["BINORMAL"] = "@TANGENT";
+ actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+ actions.usage_defines["RIM_TINT"] = "@RIM";
+ actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+ actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+ actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions.usage_defines["AO"] = "#define AO_USED\n";
+ actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+ actions.usage_defines["UV"] = "#define UV_USED\n";
+ actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+ actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+ actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+ actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+ actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+
+ if (!force_lambert) {
+ actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+ bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
+
+ if (!force_blinn) {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+ actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+
+ compiler.initialize(actions);
+ }
+
+ {
+ //default material and shader
+ default_shader = storage->shader_allocate();
+ storage->shader_initialize(default_shader);
+ storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ default_material = storage->material_allocate();
+ storage->material_initialize(default_material);
+ storage->material_set_shader(default_material, default_shader);
+
+ MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+ default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
+ }
+
+ {
+ overdraw_material_shader = storage->shader_allocate();
+ storage->shader_initialize(overdraw_material_shader);
+ storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ overdraw_material = storage->material_allocate();
+ storage->material_initialize(overdraw_material);
+ storage->material_set_shader(overdraw_material, overdraw_material_shader);
+
+ wireframe_material_shader = storage->shader_allocate();
+ storage->shader_initialize(wireframe_material_shader);
+ storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
+ wireframe_material = storage->material_allocate();
+ storage->material_initialize(wireframe_material);
+ storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ }
+
+ {
+ default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(default_vec4_xform_buffer);
+ u.binding = 0;
+ uniforms.push_back(u);
+
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardClustered::TRANSFORMS_UNIFORM_SET);
+ }
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
new file mode 100644
index 0000000000..7c8879686b
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -0,0 +1,211 @@
+/*************************************************************************/
+/* scene_shader_forward_clustered.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RSSR_SCENE_SHADER_FC_H
+#define RSSR_SCENE_SHADER_FC_H
+
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class SceneShaderForwardClustered {
+private:
+ static SceneShaderForwardClustered *singleton;
+
+public:
+ RendererStorageRD *storage;
+
+ enum ShaderVersion {
+ SHADER_VERSION_DEPTH_PASS,
+ SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ SHADER_VERSION_DEPTH_PASS_WITH_SDF,
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
+ SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_MAX
+ };
+
+ struct ShaderData : public RendererStorageRD::ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum CullVariant {
+ CULL_VARIANT_NORMAL,
+ CULL_VARIANT_REVERSED,
+ CULL_VARIANT_DOUBLE_SIDED,
+ CULL_VARIANT_MAX
+
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+ uint32_t vertex_input_mask;
+ PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+ bool uses_particle_trails;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RendererStorageRD::ShaderData *_create_shader_func();
+ static RendererStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~MaterialData();
+ };
+
+ RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ SceneForwardClusteredShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID overdraw_material_shader;
+ RID overdraw_material;
+ RID wireframe_material_shader;
+ RID wireframe_material;
+ RID default_shader_rd;
+ RID default_shader_sdfgi_rd;
+
+ RID default_vec4_xform_buffer;
+ RID default_vec4_xform_uniform_set;
+
+ RID shadow_sampler;
+
+ SceneShaderForwardClustered();
+ ~SceneShaderForwardClustered();
+
+ void init(RendererStorageRD *p_storage, const String p_defines);
+};
+
+} // namespace RendererSceneRenderImplementation
+#endif // !RSSR_SCENE_SHADER_FM_H
diff --git a/servers/rendering/renderer_rd/forward_mobile/SCsub b/servers/rendering/renderer_rd/forward_mobile/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
new file mode 100644
index 0000000000..b2aaa50421
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -0,0 +1,2163 @@
+/*************************************************************************/
+/* render_forward_mobile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "render_forward_mobile.h"
+#include "core/config/project_settings.h"
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_server_default.h"
+
+using namespace RendererSceneRenderImplementation;
+
+/* Render buffer */
+
+void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
+ if (color_msaa.is_valid()) {
+ RD::get_singleton()->free(color_msaa);
+ color_msaa = RID();
+ }
+
+ if (depth_msaa.is_valid()) {
+ RD::get_singleton()->free(depth_msaa);
+ depth_msaa = RID();
+ }
+
+ color = RID();
+ depth = RID();
+ color_fb = RID();
+}
+
+void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+ clear();
+
+ msaa = p_msaa;
+
+ width = p_width;
+ height = p_height;
+
+ color = p_color_buffer;
+ depth = p_depth_buffer;
+
+ // re-introduce setting up msaa? For now we ignore this...
+
+ if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
+ Vector<RID> fb;
+ fb.push_back(p_color_buffer);
+ fb.push_back(depth);
+
+ color_fb = RD::get_singleton()->framebuffer_create(fb);
+ } else {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = p_width;
+ tf.height = p_height;
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ RD::TEXTURE_SAMPLES_16
+ };
+
+ texture_samples = ts[p_msaa];
+ tf.samples = texture_samples;
+
+ color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.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::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ {
+ Vector<RID> fb;
+ fb.push_back(color_msaa);
+ fb.push_back(depth_msaa);
+
+ color_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+}
+
+RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
+ clear();
+}
+
+RendererSceneRenderRD::RenderBufferData *RenderForwardMobile::_create_render_buffer_data() {
+ return memnew(RenderBufferDataForwardMobile);
+}
+
+bool RenderForwardMobile::free(RID p_rid) {
+ if (RendererSceneRenderRD::free(p_rid)) {
+ return true;
+ }
+ return false;
+}
+
+/* Render functions */
+
+RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
+ //there should always be enough uniform buffers for render passes, otherwise bugs
+ ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
+
+ RenderBufferDataForwardMobile *rb = nullptr;
+ if (p_render_buffers.is_valid()) {
+ rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers);
+ }
+
+ // default render buffer and scene state uniform set
+ // loaded into set 1
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.uniform_buffers[p_index]);
+ uniforms.push_back(u);
+ }
+
+ {
+ RID radiance_texture;
+ if (p_radiance_texture.is_valid()) {
+ radiance_texture = p_radiance_texture;
+ } else {
+ radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ }
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(radiance_texture);
+ uniforms.push_back(u);
+ }
+
+ {
+ RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ if (ref_texture.is_valid()) {
+ u.ids.push_back(ref_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture;
+ if (p_shadow_atlas.is_valid()) {
+ texture = shadow_atlas_get_texture(p_shadow_atlas);
+ }
+ if (!texture.is_valid()) {
+ texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
+ u.ids.push_back(directional_shadow_get_texture());
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+
+ /* we have limited ability to keep textures like this so we're moving this to a set we change before drawing geometry and just pushing the needed texture in */
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.resize(scene_state.max_lightmaps);
+ RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
+ if (i < p_lightmaps.size()) {
+ RID base = lightmap_instance_get_lightmap(p_lightmaps[i]);
+ RID texture = storage->lightmap_get_texture(base);
+ RID rd_texture = storage->texture_get_rd_texture(texture);
+ u.ids.write[i] = rd_texture;
+ } else {
+ u.ids.write[i] = default_tex;
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ /*
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.resize(MAX_GI_PROBES);
+ RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ for (int i = 0; i < MAX_GI_PROBES; i++) {
+ if (i < (int)p_gi_probes.size()) {
+ RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]);
+ if (!tex.is_valid()) {
+ tex = default_tex;
+ }
+ u.ids.write[i] = tex;
+ } else {
+ u.ids.write[i] = default_tex;
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
+ u.ids.push_back(cb);
+ uniforms.push_back(u);
+ }
+ */
+
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID();
+ RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ if (p_index >= (int)render_pass_uniform_sets.size()) {
+ render_pass_uniform_sets.resize(p_index + 1);
+ }
+
+ if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) {
+ RD::get_singleton()->free(render_pass_uniform_sets[p_index]);
+ }
+
+ render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET);
+ return render_pass_uniform_sets[p_index];
+}
+
+void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+ // This probably needs to change...
+ scene_state.lightmaps_used = 0;
+ for (int i = 0; i < (int)p_lightmaps.size(); i++) {
+ if (i >= (int)scene_state.max_lightmaps) {
+ break;
+ }
+
+ RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+
+ Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+ to_lm = to_lm.inverse().transposed(); //will transform normals
+ RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+ scene_state.lightmap_ids[i] = p_lightmaps[i];
+ scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap);
+
+ scene_state.lightmaps_used++;
+ }
+ if (scene_state.lightmaps_used > 0) {
+ RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER);
+ }
+}
+
+void RenderForwardMobile::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
+ // These are UNUSED here and will not have data parsed from RendererSceneRenderRD:
+ // - p_gi_probes
+ // - p_cluster_buffer
+ // - p_cluster_size
+ // - p_cluster_max_elements
+
+ RenderBufferDataForwardMobile *render_buffer = nullptr;
+ if (p_render_buffer.is_valid()) {
+ render_buffer = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffer);
+ }
+ RendererSceneEnvironmentRD *env = get_environment(p_environment);
+
+ RENDER_TIMESTAMP("Setup 3D Scene");
+
+ float lod_distance_multiplier = p_cam_projection.get_lod_multiplier();
+ Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ p_screen_lod_threshold = 0.0;
+ }
+
+ Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
+ scene_state.ubo.viewport_size[0] = vp_he.x;
+ scene_state.ubo.viewport_size[1] = vp_he.y;
+ scene_state.ubo.directional_light_count = 0;
+
+ Size2i screen_size;
+ RID opaque_framebuffer;
+ RID alpha_framebuffer;
+ bool reverse_cull = false;
+
+ // I don't think we support either of these in our mobile renderer so probably should phase them out
+ bool using_ssr = false;
+ bool using_sss = false;
+
+ if (render_buffer) {
+ // setup rendering to render buffer
+ screen_size.x = render_buffer->width;
+ screen_size.y = render_buffer->height;
+
+ opaque_framebuffer = render_buffer->color_fb;
+ alpha_framebuffer = opaque_framebuffer;
+ } else if (p_reflection_probe.is_valid()) {
+ uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe);
+ screen_size.x = resolution;
+ screen_size.y = resolution;
+
+ opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
+ alpha_framebuffer = opaque_framebuffer;
+
+ if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+ p_environment = RID(); //no environment on interiors
+ }
+
+ reverse_cull = true;
+ } else {
+ ERR_FAIL(); //bug?
+ }
+
+ RD::get_singleton()->draw_command_begin_label("Render Setup");
+
+ _setup_lightmaps(p_lightmaps, p_cam_transform);
+ _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false);
+
+ _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
+
+ _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_depth();
+
+ // we no longer use this...
+ _fill_instance_data(RENDER_LIST_OPAQUE);
+ _fill_instance_data(RENDER_LIST_ALPHA);
+
+ RD::get_singleton()->draw_command_end_label();
+
+ // note, no depth prepass here!
+
+ // setup environment
+ RID radiance_texture;
+ bool draw_sky = false;
+ bool draw_sky_fog_only = false;
+
+ Color clear_color = p_default_bg_color;
+ bool keep_color = false;
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
+ } else if (is_environment(p_environment)) {
+ RS::EnvironmentBG bg_mode = environment_get_background(p_environment);
+ float bg_energy = environment_get_bg_energy(p_environment);
+ switch (bg_mode) {
+ case RS::ENV_BG_CLEAR_COLOR: {
+ clear_color = p_default_bg_color;
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ /*
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
+ */
+ } break;
+ case RS::ENV_BG_COLOR: {
+ clear_color = environment_get_bg_color(p_environment);
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ /*
+ if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
+ */
+ } break;
+ case RS::ENV_BG_SKY: {
+ draw_sky = true;
+ } break;
+ case RS::ENV_BG_CANVAS: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_KEEP: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_CAMERA_FEED: {
+ } break;
+ default: {
+ }
+ }
+ // setup sky if used for ambient, reflections, or background
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ RD::get_singleton()->draw_command_begin_label("Setup Sky");
+ CameraMatrix projection = p_cam_projection;
+ if (p_reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_cam_projection;
+ }
+
+ sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this);
+
+ RID sky_rid = env->sky;
+ if (sky_rid.is_valid()) {
+ sky.update(env, projection, p_cam_transform, time);
+ radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
+ } else {
+ // do not try to draw sky if invalid
+ draw_sky = false;
+ }
+ RD::get_singleton()->draw_command_end_label();
+ }
+ } else {
+ clear_color = p_default_bg_color;
+ }
+
+ // opaque pass
+
+ // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here
+ // does trigger shadow map rendering so kinda important
+ _pre_opaque_render(false, false, RID(), RID());
+
+ RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
+
+ scene_state.ubo.directional_light_count = _get_render_state_directional_light_count();
+
+ _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid());
+
+ RENDER_TIMESTAMP("Render Opaque Pass");
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_lightmaps, true);
+
+ bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
+ bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
+
+ {
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
+
+ // regular forward for now
+ Vector<Color> c;
+ c.push_back(clear_color.to_linear());
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ if (draw_sky || draw_sky_fog_only) {
+ RENDER_TIMESTAMP("Render Sky");
+
+ CameraMatrix projection = p_cam_projection;
+ if (p_reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_cam_projection;
+ }
+ RD::get_singleton()->draw_command_begin_label("Draw Sky");
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time);
+ RD::get_singleton()->draw_command_end_label();
+ }
+
+ if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ /*
+ if (using_separate_specular) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
+ }
+ */
+ }
+
+ if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
+ }
+
+ // transparent pass
+ RENDER_TIMESTAMP("Render Transparent Pass");
+
+ RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
+
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_lightmaps, true);
+
+ _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false);
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ RD::get_singleton()->draw_command_begin_label("Resolve");
+
+ if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
+
+void RenderForwardMobile::_render_shadow_begin() {
+ scene_state.shadow_passes.clear();
+ RD::get_singleton()->draw_command_begin_label("Shadow Setup");
+ _update_render_base_uniform_set();
+
+ render_list[RENDER_LIST_SECONDARY].clear();
+}
+
+void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+ uint32_t shadow_pass_index = scene_state.shadow_passes.size();
+
+ SceneState::ShadowPass shadow_pass;
+
+ scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+
+ _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index);
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ p_screen_lod_threshold = 0.0;
+ }
+
+ PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
+
+ uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
+ _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true);
+ uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
+ render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
+ _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
+
+ {
+ //regular forward for now
+ bool flip_cull = p_use_dp_flip;
+ if (p_flip_y) {
+ flip_cull = !flip_cull;
+ }
+
+ shadow_pass.element_from = render_list_from;
+ shadow_pass.element_count = render_list_size;
+ shadow_pass.flip_cull = flip_cull;
+ shadow_pass.pass_mode = pass_mode;
+
+ shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
+ shadow_pass.camera_plane = p_camera_plane;
+ shadow_pass.screen_lod_threshold = p_screen_lod_threshold;
+ shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier;
+
+ shadow_pass.framebuffer = p_framebuffer;
+ shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
+ shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE;
+ shadow_pass.rect = p_rect;
+
+ scene_state.shadow_passes.push_back(shadow_pass);
+ }
+}
+
+void RenderForwardMobile::_render_shadow_process() {
+ //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time)
+
+ for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
+ //render passes need to be configured after instance buffer is done, since they need the latest version
+ SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
+ shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), PagedArray<RID>(), false, i);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
+ RD::get_singleton()->draw_command_begin_label("Shadow Render");
+
+ for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
+ SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ }
+
+ if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier);
+ }
+ RD::get_singleton()->draw_command_end_label();
+}
+
+/* */
+
+void RenderForwardMobile::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering Material");
+
+ RD::get_singleton()->draw_command_begin_label("Render Material");
+
+ _update_render_base_uniform_set();
+
+ scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.material_uv2_mode = false;
+
+ _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0);
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), PagedArray<RID>());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set);
+ //regular forward for now
+ Vector<Color> clear;
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering UV2");
+
+ RD::get_singleton()->draw_command_begin_label("Render UV2");
+
+ _update_render_base_uniform_set();
+
+ scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.material_uv2_mode = true;
+
+ _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0);
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform());
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), PagedArray<RID>());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true);
+ //regular forward for now
+ Vector<Color> clear;
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+
+ const int uv_offset_count = 9;
+ static const Vector2 uv_offsets[uv_offset_count] = {
+ Vector2(-1, 1),
+ Vector2(1, 1),
+ Vector2(1, -1),
+ Vector2(-1, -1),
+ Vector2(-1, 0),
+ Vector2(1, 0),
+ Vector2(0, -1),
+ Vector2(0, 1),
+ Vector2(0, 0),
+
+ };
+
+ for (int i = 0; i < uv_offset_count; i++) {
+ Vector2 ofs = uv_offsets[i];
+ ofs.x /= p_region.size.width;
+ ofs.y /= p_region.size.height;
+ render_list_params.uv_offset = ofs;
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
+ }
+ render_list_params.uv_offset = Vector2();
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
+
+ RD::get_singleton()->draw_list_end();
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+ // we don't do GI in low end..
+}
+
+void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+ RENDER_TIMESTAMP("Setup Render Collider Heightfield");
+
+ RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
+
+ _update_render_base_uniform_set();
+ scene_state.ubo.dual_paraboloid_side = 0;
+
+ _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false);
+
+ PassMode pass_mode = PASS_MODE_SHADOW;
+
+ _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), PagedArray<RID>());
+
+ RENDER_TIMESTAMP("Render Collider Heightfield");
+
+ {
+ //regular forward for now
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set);
+ _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
+ }
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_base_uniforms_changed() {
+ if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+ render_base_uniform_set = RID();
+}
+
+void RenderForwardMobile::_update_render_base_uniform_set() {
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+
+ // This is all loaded into set 0
+
+ lightmap_texture_array_version = storage->lightmap_array_get_version();
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(scene_shader.shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_omni_light_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_spot_light_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_reflection_probe_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(get_directional_light_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.lightmap_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.lightmap_capture_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID decal_atlas = storage->decal_atlas_get_texture();
+ u.ids.push_back(decal_atlas);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID decal_atlas = storage->decal_atlas_get_texture_srgb();
+ u.ids.push_back(decal_atlas);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_decal_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 12;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
+ }
+}
+
+RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers) {
+ // RenderBufferDataForwardMobile *rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers);
+
+ // We don't have this. This is for debugging
+ // return rb->normal_roughness_buffer;
+ return RID();
+}
+
+void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ scene_state.used_sss = false;
+ scene_state.used_screen_texture = false;
+ scene_state.used_normal_texture = false;
+ scene_state.used_depth_texture = false;
+ }
+ uint32_t lightmap_captures_used = 0;
+
+ Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ near_plane.d += p_cam_projection.get_z_near();
+ float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near();
+
+ RenderList *rl = &render_list[p_render_list];
+
+ // Parse any updates on our geometry, updates surface caches and such
+ _update_dirty_geometry_instances();
+
+ if (!p_append) {
+ rl->clear();
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
+ }
+ }
+
+ //fill list
+
+ for (int i = 0; i < (int)p_instances.size(); i++) {
+ GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>(p_instances[i]);
+
+ Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
+ inst->depth = near_plane.distance_to(support_min);
+ uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
+
+ uint32_t flags = inst->base_flags; //fill flags if appropriate
+
+ bool uses_lightmap = false;
+ // bool uses_gi = false;
+
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ if (inst->lightmap_instance.is_valid()) {
+ int32_t lightmap_cull_index = -1;
+ for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) {
+ if (scene_state.lightmap_ids[j] == inst->lightmap_instance) {
+ lightmap_cull_index = j;
+ break;
+ }
+ }
+ if (lightmap_cull_index >= 0) {
+ inst->gi_offset_cache = inst->lightmap_slice_index << 16;
+ inst->gi_offset_cache |= lightmap_cull_index;
+ flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP;
+ if (scene_state.lightmap_has_sh[lightmap_cull_index]) {
+ flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP;
+ }
+ uses_lightmap = true;
+ } else {
+ inst->gi_offset_cache = 0xFFFFFFFF;
+ }
+
+ } else if (inst->lightmap_sh) {
+ if (lightmap_captures_used < scene_state.max_lightmap_captures) {
+ const Color *src_capture = inst->lightmap_sh->sh;
+ LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used];
+ for (int j = 0; j < 9; j++) {
+ lcd.sh[j * 4 + 0] = src_capture[j].r;
+ lcd.sh[j * 4 + 1] = src_capture[j].g;
+ lcd.sh[j * 4 + 2] = src_capture[j].b;
+ lcd.sh[j * 4 + 3] = src_capture[j].a;
+ }
+ flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE;
+ inst->gi_offset_cache = lightmap_captures_used;
+ lightmap_captures_used++;
+ uses_lightmap = true;
+ }
+ }
+ }
+ inst->flags_cache = flags;
+
+ GeometryInstanceSurfaceDataCache *surf = inst->surface_caches;
+
+ while (surf) {
+ surf->sort.uses_lightmap = 0;
+
+ // LOD
+
+ if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
+ //lod
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal);
+
+ float distance_min = p_lod_plane.distance_to(lod_support_min);
+ float distance_max = p_lod_plane.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;
+ }
+
+ surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold);
+ } else {
+ surf->lod_index = 0;
+ }
+
+ // ADD Element
+ if (p_pass_mode == PASS_MODE_COLOR) {
+ if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) {
+ render_list[RENDER_LIST_ALPHA].add_element(surf);
+ // if (uses_gi) {
+ // surf->sort.uses_forward_gi = 1;
+ // }
+ }
+
+ if (uses_lightmap) {
+ surf->sort.uses_lightmap = 1; // This needs to become our lightmap index but we'll do that in a separate PR.
+ }
+
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) {
+ scene_state.used_sss = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) {
+ scene_state.used_screen_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) {
+ scene_state.used_normal_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
+ scene_state.used_depth_texture = true;
+ }
+
+ } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
+ rl->add_element(surf);
+ }
+ } else {
+ if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ }
+
+ surf->sort.depth_layer = depth_layer;
+
+ surf = surf->next;
+ }
+ }
+}
+
+void RenderForwardMobile::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+ //!BAS! need to go through this and find out what we don't need anymore
+
+ // This populates our UBO with main scene data that is pushed into set 1
+
+ //CameraMatrix projection = p_cam_projection;
+ //projection.flip_y(); // Vulkan and modern APIs use Y-Down
+ CameraMatrix correction;
+ correction.set_depth_correction(p_flip_y);
+ CameraMatrix projection = correction * p_cam_projection;
+
+ //store camera into ubo
+ RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix);
+ RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
+ RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
+
+ scene_state.ubo.z_far = p_zfar;
+ scene_state.ubo.z_near = p_znear;
+
+ scene_state.ubo.pancake_shadows = p_pancake_shadows;
+
+ RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
+
+ scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
+ scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
+ scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get();
+ scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get();
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ /*
+ scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size);
+ scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32;
+ {
+ uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1;
+ uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1;
+ scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32);
+ scene_state.ubo.cluster_width = cluster_screen_width;
+ }
+ */
+
+ if (p_shadow_atlas.is_valid()) {
+ Vector2 sas = shadow_atlas_get_size(p_shadow_atlas);
+ scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
+ scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
+ }
+ {
+ Vector2 dss = directional_shadow_get_size();
+ scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
+ scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
+ }
+
+ //time global variables
+ scene_state.ubo.time = time;
+
+ /*
+ scene_state.ubo.gi_upscale_for_msaa = false;
+ scene_state.ubo.volumetric_fog_enabled = false;
+ scene_state.ubo.fog_enabled = false;
+
+ if (p_render_buffers.is_valid()) {
+ RenderBufferDataForwardMobile *render_buffers = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers);
+ if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ scene_state.ubo.gi_upscale_for_msaa = true;
+ }
+
+ if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+ scene_state.ubo.volumetric_fog_enabled = true;
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
+ }
+ }
+
+ */
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.ambient_light_color_energy[0] = 1;
+ scene_state.ubo.ambient_light_color_energy[1] = 1;
+ scene_state.ubo.ambient_light_color_energy[2] = 1;
+ scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+ scene_state.ubo.use_ambient_cubemap = false;
+ scene_state.ubo.use_reflection_cubemap = false;
+ scene_state.ubo.ssao_enabled = false;
+
+ } else if (is_environment(p_environment)) {
+ RS::EnvironmentBG env_bg = environment_get_background(p_environment);
+ RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment);
+
+ float bg_energy = environment_get_bg_energy(p_environment);
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+
+ scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_environment);
+
+ //ambient
+ if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
+ Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_environment);
+ color = color.to_linear();
+
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.use_ambient_cubemap = false;
+ } else {
+ float energy = environment_get_ambient_light_energy(p_environment);
+ Color color = environment_get_ambient_light_color(p_environment);
+ color = color.to_linear();
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
+
+ Basis sky_transform = environment_get_sky_orientation(p_environment);
+ sky_transform = sky_transform.inverse() * p_cam_transform.basis;
+ RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+
+ scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment);
+ if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
+ scene_state.ubo.use_reflection_cubemap = true;
+ } else {
+ scene_state.ubo.use_reflection_cubemap = false;
+ }
+
+ scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_environment);
+ scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_environment);
+ scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_environment);
+
+ Color ao_color = environment_get_ao_color(p_environment).to_linear();
+ scene_state.ubo.ao_color[0] = ao_color.r;
+ scene_state.ubo.ao_color[1] = ao_color.g;
+ scene_state.ubo.ao_color[2] = ao_color.b;
+ scene_state.ubo.ao_color[3] = ao_color.a;
+
+ scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
+ scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
+ scene_state.ubo.fog_height = environment_get_fog_height(p_environment);
+ scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment);
+ if (scene_state.ubo.fog_height_density >= 0.0001) {
+ scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
+ }
+ scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment);
+
+ Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_environment);
+
+ scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+
+ } else {
+ if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+ scene_state.ubo.use_ambient_light = false;
+ } else {
+ scene_state.ubo.use_ambient_light = true;
+ Color clear_color = p_default_bg_color;
+ clear_color = clear_color.to_linear();
+ scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
+ scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
+ scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
+ scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+ }
+
+ scene_state.ubo.use_ambient_cubemap = false;
+ scene_state.ubo.use_reflection_cubemap = false;
+ scene_state.ubo.ssao_enabled = false;
+ }
+
+ scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
+ scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
+ scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
+
+ if (p_index >= (int)scene_state.uniform_buffers.size()) {
+ uint32_t from = scene_state.uniform_buffers.size();
+ scene_state.uniform_buffers.resize(p_index + 1);
+ render_pass_uniform_sets.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
+ scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
+ }
+ }
+ RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
+}
+
+void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+ // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer?
+
+ RenderList *rl = &render_list[p_render_list];
+ uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
+
+ rl->element_info.resize(p_offset + element_total);
+
+ uint32_t repeats = 0;
+ GeometryInstanceSurfaceDataCache *prev_surface = nullptr;
+ for (uint32_t i = 0; i < element_total; i++) {
+ GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
+ GeometryInstanceForwardMobile *inst = surface->owner;
+
+ bool cant_repeat = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
+
+ if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) {
+ //this element is the same as the previous one, count repeats to draw it using instancing
+ repeats++;
+ } else {
+ if (repeats > 0) {
+ for (uint32_t j = 1; j <= repeats; j++) {
+ rl->element_info[p_offset + i - j].repeat = j;
+ }
+ }
+ repeats = 1;
+ }
+
+ RenderElementInfo &element_info = rl->element_info[p_offset + i];
+
+ element_info.lod_index = surface->lod_index;
+ element_info.uses_lightmap = surface->sort.uses_lightmap;
+
+ if (cant_repeat) {
+ prev_surface = nullptr;
+ } else {
+ prev_surface = surface;
+ }
+ }
+
+ if (repeats > 0) {
+ for (uint32_t j = 1; j <= repeats; j++) {
+ rl->element_info[p_offset + element_total - j].repeat = j;
+ }
+ }
+}
+
+/// RENDERING ///
+
+void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+ //use template for faster performance (pass mode comparisons are inlined)
+
+ switch (p_params->pass_mode) {
+ case PASS_MODE_COLOR: {
+ _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_SHADOW: {
+ _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_SHADOW_DP: {
+ _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ }
+}
+
+void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
+ uint32_t render_total = p_params->element_count;
+ uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+ uint32_t render_from = p_thread * render_total / total_threads;
+ uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads);
+ _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
+}
+
+void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
+ p_params->framebuffer_format = fb_format;
+
+ if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, p_params);
+ RD::get_singleton()->draw_list_end(p_params->barrier);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
+ _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
+ RD::get_singleton()->draw_list_end(p_params->barrier);
+ }
+}
+
+template <RenderForwardMobile::PassMode p_pass_mode>
+void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+ RD::DrawListID draw_list = p_draw_list;
+ RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
+
+ //global scope bindings
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
+
+ RID prev_material_uniform_set;
+
+ RID prev_vertex_array_rd;
+ RID prev_index_array_rd;
+ RID prev_pipeline_rd;
+ RID prev_xforms_uniform_set;
+
+ bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
+
+ for (uint32_t i = p_from_element; i < p_to_element; i++) {
+ const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i];
+ const RenderElementInfo &element_info = p_params->element_info[i];
+ const GeometryInstanceForwardMobile *inst = surf->owner;
+
+ // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
+ GeometryInstanceForwardMobile::PushConstant push_constant;
+
+ if (inst->store_transform_cache) {
+ RendererStorageRD::store_transform(inst->transform, push_constant.transform);
+ } else {
+ RendererStorageRD::store_transform(Transform(), push_constant.transform);
+ }
+
+ push_constant.flags = inst->flags_cache;
+ push_constant.gi_offset = inst->gi_offset_cache;
+ push_constant.layer_mask = inst->layer_mask;
+ push_constant.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset);
+
+ if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ // abuse lightmap_uv_scale[0] here, should not be needed here
+ push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x;
+ push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y;
+ } else {
+ push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
+ push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
+ push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
+ push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+ };
+
+ _fill_instance_indices(inst->omni_lights, inst->omni_light_count, push_constant.omni_lights, inst->spot_lights, inst->spot_light_count, push_constant.spot_lights, inst->reflection_probes, inst->reflection_probe_count, push_constant.reflection_probes, inst->decals, inst->decals_count, push_constant.decals, push_constant.layer_mask);
+
+ RID material_uniform_set;
+ SceneShaderForwardMobile::ShaderData *shader;
+ void *mesh_surface;
+
+ if (shadow_pass) {
+ material_uniform_set = surf->material_uniform_set_shadow;
+ shader = surf->shader_shadow;
+ mesh_surface = surf->surface_shadow;
+
+ } else {
+ material_uniform_set = surf->material_uniform_set;
+ shader = surf->shader;
+ mesh_surface = surf->surface;
+ }
+
+ if (!mesh_surface) {
+ continue;
+ }
+
+ //find cull variant
+ SceneShaderForwardMobile::ShaderData::CullVariant cull_variant;
+
+ if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ cull_variant = SceneShaderForwardMobile::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
+ } else {
+ bool mirror = surf->owner->mirror;
+ if (p_params->reverse_cull) {
+ mirror = !mirror;
+ }
+ cull_variant = mirror ? SceneShaderForwardMobile::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardMobile::ShaderData::CULL_VARIANT_NORMAL;
+ }
+
+ RS::PrimitiveType primitive = surf->primitive;
+ RID xforms_uniform_set = surf->owner->transforms_uniform_set;
+
+ SceneShaderForwardMobile::ShaderVersion shader_version = SceneShaderForwardMobile::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+
+ switch (p_params->pass_mode) {
+ case PASS_MODE_COLOR:
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ if (element_info.uses_lightmap) {
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ } else {
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
+ }
+ } break;
+ case PASS_MODE_SHADOW: {
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
+ } break;
+ case PASS_MODE_SHADOW_DP: {
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_DP;
+ } break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ } break;
+ }
+
+ PipelineCacheRD *pipeline = nullptr;
+
+ pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
+
+ RD::VertexFormatID vertex_format = -1;
+ RID vertex_array_rd;
+ RID index_array_rd;
+
+ //skeleton and blend shape
+ if (surf->owner->mesh_instance.is_valid()) {
+ storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ } else {
+ storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ }
+
+ index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
+
+ if (prev_vertex_array_rd != vertex_array_rd) {
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
+ prev_vertex_array_rd = vertex_array_rd;
+ }
+
+ if (prev_index_array_rd != index_array_rd) {
+ if (index_array_rd.is_valid()) {
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd);
+ }
+ prev_index_array_rd = index_array_rd;
+ }
+
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+
+ if (pipeline_rd != prev_pipeline_rd) {
+ // checking with prev shader does not make so much sense, as
+ // the pipeline may still be different.
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
+ prev_pipeline_rd = pipeline_rd;
+ }
+
+ if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET);
+ prev_xforms_uniform_set = xforms_uniform_set;
+ }
+
+ if (material_uniform_set != prev_material_uniform_set) {
+ //update uniform set
+ if (material_uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
+ }
+
+ prev_material_uniform_set = material_uniform_set;
+ }
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
+
+ uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
+ instance_count /= surf->owner->trail_steps;
+ }
+
+ RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
+ i += element_info.repeat - 1; //skip equal elements
+ }
+}
+
+/* Geometry instance */
+
+RendererSceneRender::GeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base) {
+ RS::InstanceType type = storage->get_base_type(p_base);
+ ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
+
+ GeometryInstanceForwardMobile *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceForwardMobile::Data);
+
+ ginstance->data->base = p_base;
+ ginstance->data->base_type = type;
+
+ _geometry_instance_mark_dirty(ginstance);
+
+ return ginstance;
+}
+
+void RenderForwardMobile::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->skeleton = p_skeleton;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->material_override = p_override;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->surface_materials = p_materials;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->mesh_instance = p_mesh_instance;
+
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->transform = p_transform;
+ ginstance->mirror = p_transform.basis.determinant() < 0;
+ ginstance->data->aabb = p_aabb;
+ ginstance->transformed_aabb = p_transformed_aabb;
+
+ Vector3 model_scale_vec = p_transform.basis.get_scale_abs();
+ // handle non uniform scale here
+
+ float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z));
+ float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z));
+ ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9;
+
+ ginstance->lod_model_scale = max_scale;
+}
+
+void RenderForwardMobile::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->layer_mask = p_layer_mask;
+}
+
+void RenderForwardMobile::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->lod_bias = p_lod_bias;
+}
+
+void RenderForwardMobile::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->use_baked_light = p_enable;
+
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
+ // !BAS! do we support this in mobile?
+ // GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ // ERR_FAIL_COND(!ginstance);
+ // ginstance->data->use_dynamic_gi = p_enable;
+ // _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->lightmap_instance = p_lightmap_instance;
+ ginstance->lightmap_uv_scale = p_lightmap_uv_scale;
+ ginstance->lightmap_slice_index = p_lightmap_slice_index;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ if (p_sh9) {
+ if (ginstance->lightmap_sh == nullptr) {
+ ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc();
+ }
+
+ memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
+ } else {
+ if (ginstance->lightmap_sh != nullptr) {
+ geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
+ ginstance->lightmap_sh = nullptr;
+ }
+ }
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->shader_parameters_offset = p_offset;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->data->cast_double_sided_shadows = p_enable;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+Transform RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance);
+ ERR_FAIL_COND_V(!ginstance, Transform());
+ return ginstance->transform;
+}
+
+AABB RenderForwardMobile::geometry_instance_get_aabb(GeometryInstance *p_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance);
+ ERR_FAIL_COND_V(!ginstance, AABB());
+ return ginstance->data->aabb;
+}
+
+void RenderForwardMobile::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ if (ginstance->lightmap_sh != nullptr) {
+ geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
+ }
+ GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches;
+ while (surf) {
+ GeometryInstanceSurfaceDataCache *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+ memdelete(ginstance->data);
+ geometry_instance_alloc.free(ginstance);
+}
+
+uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() {
+ return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL));
+}
+
+void RenderForwardMobile::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->omni_light_count = 0;
+ ginstance->spot_light_count = 0;
+
+ for (uint32_t i = 0; i < p_light_instance_count; i++) {
+ RS::LightType type = light_instance_get_type(p_light_instances[i]);
+ switch (type) {
+ case RS::LIGHT_OMNI: {
+ if (ginstance->omni_light_count < (uint32_t)MAX_RDL_CULL) {
+ ginstance->omni_lights[ginstance->omni_light_count] = p_light_instances[i];
+ ginstance->omni_light_count++;
+ }
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (ginstance->spot_light_count < (uint32_t)MAX_RDL_CULL) {
+ ginstance->spot_lights[ginstance->spot_light_count] = p_light_instances[i];
+ ginstance->spot_light_count++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
+ for (uint32_t i = 0; i < ginstance->reflection_probe_count; i++) {
+ ginstance->reflection_probes[i] = p_reflection_probe_instances[i];
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
+ for (uint32_t i = 0; i < ginstance->decals_count; i++) {
+ ginstance->decals[i] = p_decal_instances[i];
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+ // We do not have this here!
+}
+
+void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ if (ginstance->dirty_list_element.in_list()) {
+ return;
+ }
+
+ //clear surface caches
+ GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches;
+
+ while (surf) {
+ GeometryInstanceSurfaceDataCache *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+
+ ginstance->surface_caches = nullptr;
+
+ geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
+}
+
+void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+ bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
+ bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha);
+ bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
+ bool has_alpha = has_base_alpha || has_blend_alpha;
+
+ uint32_t flags = 0;
+
+ if (p_material->shader_data->uses_sss) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING;
+ }
+
+ if (p_material->shader_data->uses_screen_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_depth_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_normal_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
+ }
+
+ if (ginstance->data->cast_double_sided_shadows) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
+ }
+
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) {
+ //material is only meant for alpha pass
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
+ }
+ } else {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
+ }
+
+ if (p_material->shader_data->uses_particle_trails) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
+ }
+
+ SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
+ void *surface_shadow = nullptr;
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
+ material_shadow = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+
+ RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
+
+ if (shadow_mesh.is_valid()) {
+ surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface);
+ }
+
+ } else {
+ material_shadow = p_material;
+ }
+
+ GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc();
+
+ sdcache->flags = flags;
+
+ sdcache->shader = p_material->shader_data;
+ sdcache->material_uniform_set = p_material->uniform_set;
+ sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface);
+ sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface);
+ sdcache->surface_index = p_surface;
+
+ if (ginstance->data->dirty_dependencies) {
+ storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker);
+ }
+
+ //shadow
+ sdcache->shader_shadow = material_shadow->shader_data;
+ sdcache->material_uniform_set_shadow = material_shadow->uniform_set;
+
+ sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
+
+ sdcache->owner = ginstance;
+
+ sdcache->next = ginstance->surface_caches;
+ ginstance->surface_caches = sdcache;
+
+ //sortkey
+
+ sdcache->sort.sort_key1 = 0;
+ sdcache->sort.sort_key2 = 0;
+
+ sdcache->sort.surface_index = p_surface;
+ sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
+ sdcache->sort.shader_id = p_shader_id;
+ sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway
+ // sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
+ sdcache->sort.priority = p_material->priority;
+}
+
+void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+ RID m_src;
+
+ m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
+
+ SceneShaderForwardMobile::MaterialData *material = nullptr;
+
+ if (m_src.is_valid()) {
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (material) {
+ if (ginstance->data->dirty_dependencies) {
+ storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+ } else {
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+ m_src = scene_shader.default_material;
+ }
+
+ ERR_FAIL_COND(!material);
+
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh);
+
+ while (material->next_pass.is_valid()) {
+ RID next_pass = material->next_pass;
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid) {
+ break;
+ }
+ if (ginstance->data->dirty_dependencies) {
+ storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker);
+ }
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh);
+ }
+}
+
+void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_begin();
+ }
+
+ //add geometry for drawing
+ switch (ginstance->data->base_type) {
+ case RS::INSTANCE_MESH: {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+ RID mesh = ginstance->data->base;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ //if no materials, no surfaces.
+ const RID *inst_materials = ginstance->data->surface_materials.ptr();
+ uint32_t surf_mat_count = ginstance->data->surface_materials.size();
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+ RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j];
+ _geometry_instance_add_surface(ginstance, j, material, mesh);
+ }
+ }
+
+ ginstance->instance_count = 1;
+
+ } break;
+
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = storage->multimesh_get_mesh(ginstance->data->base);
+ if (mesh.is_valid()) {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t j = 0; j < surface_count; j++) {
+ _geometry_instance_add_surface(ginstance, j, materials[j], mesh);
+ }
+ }
+
+ ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+
+ } break;
+#if 0
+ case RS::INSTANCE_IMMEDIATE: {
+ RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base);
+ ERR_CONTINUE(!immediate);
+
+ _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
+
+ } break;
+#endif
+ case RS::INSTANCE_PARTICLES: {
+ int draw_passes = storage->particles_get_draw_passes(ginstance->data->base);
+
+ for (int j = 0; j < draw_passes; j++) {
+ RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
+ if (!mesh.is_valid()) {
+ continue;
+ }
+
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t k = 0; k < surface_count; k++) {
+ _geometry_instance_add_surface(ginstance, k, materials[k], mesh);
+ }
+ }
+ }
+
+ ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps);
+
+ } break;
+
+ default: {
+ }
+ }
+
+ //Fill push constant
+
+ bool store_transform = true;
+
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+ if (storage->multimesh_uses_colors(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ }
+ if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ }
+
+ ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (false) { // 2D particles
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+
+ //for particles, stride is the trail size
+ ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT);
+
+ if (!storage->particles_is_using_local_coords(ginstance->data->base)) {
+ store_transform = false;
+ }
+ ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
+ if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
+ ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ if (ginstance->data->dirty_dependencies) {
+ storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
+ }
+ }
+ }
+
+ ginstance->store_transform_cache = store_transform;
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_end();
+ ginstance->data->dirty_dependencies = false;
+ }
+
+ ginstance->dirty_list_element.remove_from_list();
+}
+
+void RenderForwardMobile::_update_dirty_geometry_instances() {
+ while (geometry_instance_dirty_list.first()) {
+ _geometry_instance_update(geometry_instance_dirty_list.first()->self());
+ }
+}
+
+void RenderForwardMobile::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+ switch (p_notification) {
+ case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
+ case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
+ case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
+ static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ } break;
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata);
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->instance_count = static_cast<RenderForwardMobile *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+ } break;
+ default: {
+ //rest of notifications of no interest
+ } break;
+ }
+}
+void RenderForwardMobile::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
+ static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+}
+
+/* misc */
+
+bool RenderForwardMobile::is_dynamic_gi_supported() const {
+ return false;
+}
+
+bool RenderForwardMobile::is_clustered_enabled() const {
+ return false;
+}
+
+bool RenderForwardMobile::is_volumetric_supported() const {
+ return false;
+}
+
+uint32_t RenderForwardMobile::get_max_elements() const {
+ return 256;
+}
+
+RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
+
+RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
+ RendererSceneRenderRD(p_storage) {
+ singleton = this;
+
+ String defines;
+
+ defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
+ if (is_using_radiance_cubemap_array()) {
+ defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
+ }
+ // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+
+ {
+ //lightmaps
+ scene_state.max_lightmaps = 2;
+ defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n";
+ defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n";
+
+ scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps);
+ }
+ {
+ //captures
+ scene_state.max_lightmap_captures = 2048;
+ scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures);
+ scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures);
+ }
+ {
+ defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
+ }
+
+ scene_shader.init(p_storage, defines);
+
+ // !BAS! maybe we need a mobile version of this setting?
+ render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+}
+
+RenderForwardMobile::~RenderForwardMobile() {
+ directional_shadow_atlas_set_size(0);
+
+ //clear base uniform set if still valid
+ for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) {
+ if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) {
+ RD::get_singleton()->free(render_pass_uniform_sets[i]);
+ }
+ }
+
+ {
+ for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
+ RD::get_singleton()->free(scene_state.uniform_buffers[i]);
+ }
+ RD::get_singleton()->free(scene_state.lightmap_buffer);
+ RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
+ memdelete_arr(scene_state.lightmap_captures);
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
new file mode 100644
index 0000000000..d356d88335
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -0,0 +1,604 @@
+/*************************************************************************/
+/* render_forward_mobile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
+#define RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
+
+#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h"
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+
+namespace RendererSceneRenderImplementation {
+
+class RenderForwardMobile : public RendererSceneRenderRD {
+ friend SceneShaderForwardMobile;
+
+protected:
+ /* Scene Shader */
+
+ enum {
+ SCENE_UNIFORM_SET = 0,
+ RENDER_PASS_UNIFORM_SET = 1,
+ TRANSFORMS_UNIFORM_SET = 2,
+ MATERIAL_UNIFORM_SET = 3
+ };
+
+ enum {
+ MAX_LIGHTMAPS = 8,
+ MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance
+ INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
+ };
+
+ enum RenderListType {
+ RENDER_LIST_OPAQUE, //used for opaque objects
+ RENDER_LIST_ALPHA, //used for transparent objects
+ RENDER_LIST_SECONDARY, //used for shadows and other objects
+ RENDER_LIST_MAX
+ };
+
+ /* Scene Shader */
+
+ SceneShaderForwardMobile scene_shader;
+
+ /* Render Buffer */
+
+ struct RenderBufferDataForwardMobile : public RenderBufferData {
+ RID color;
+ RID depth;
+ // RID normal_roughness_buffer;
+
+ RS::ViewportMSAA msaa;
+ RD::TextureSamples texture_samples;
+
+ RID color_msaa;
+ RID depth_msaa;
+ // RID normal_roughness_buffer_msaa;
+
+ RID color_fb;
+ int width, height;
+
+ void clear();
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
+
+ ~RenderBufferDataForwardMobile();
+ };
+
+ virtual RenderBufferData *_create_render_buffer_data();
+
+ /* Rendering */
+
+ enum PassMode {
+ PASS_MODE_COLOR,
+ // PASS_MODE_COLOR_SPECULAR,
+ PASS_MODE_COLOR_TRANSPARENT,
+ PASS_MODE_SHADOW,
+ PASS_MODE_SHADOW_DP,
+ // PASS_MODE_DEPTH,
+ // PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
+ // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE,
+ PASS_MODE_DEPTH_MATERIAL,
+ // PASS_MODE_SDF,
+ };
+
+ struct GeometryInstanceForwardMobile;
+ struct GeometryInstanceSurfaceDataCache;
+ struct RenderElementInfo;
+
+ struct RenderListParameters {
+ GeometryInstanceSurfaceDataCache **elements = nullptr;
+ RenderElementInfo *element_info = nullptr;
+ int element_count = 0;
+ bool reverse_cull = false;
+ PassMode pass_mode = PASS_MODE_COLOR;
+ // bool no_gi = false;
+ RID render_pass_uniform_set;
+ bool force_wireframe = false;
+ Vector2 uv_offset;
+ Plane lod_plane;
+ float lod_distance_multiplier = 0.0;
+ float screen_lod_threshold = 0.0;
+ RD::FramebufferFormatID framebuffer_format = 0;
+ uint32_t element_offset = 0;
+ uint32_t barrier = RD::BARRIER_MASK_ALL;
+
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ elements = p_elements;
+ element_info = p_element_info;
+ element_count = p_element_count;
+ reverse_cull = p_reverse_cull;
+ pass_mode = p_pass_mode;
+ // no_gi = p_no_gi;
+ render_pass_uniform_set = p_render_pass_uniform_set;
+ force_wireframe = p_force_wireframe;
+ uv_offset = p_uv_offset;
+ lod_plane = p_lod_plane;
+ lod_distance_multiplier = p_lod_distance_multiplier;
+ screen_lod_threshold = p_screen_lod_threshold;
+ element_offset = p_element_offset;
+ barrier = p_barrier;
+ }
+ };
+
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold);
+
+ virtual void _render_shadow_begin();
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
+ virtual void _render_shadow_process();
+ virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+
+ virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
+
+ uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
+
+ virtual void _base_uniforms_changed();
+ void _update_render_base_uniform_set();
+ virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
+
+ void _fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false);
+ void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
+ // void _update_instance_data_buffer(RenderListType p_render_list);
+
+ static RenderForwardMobile *singleton;
+
+ void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform);
+
+ RID render_base_uniform_set;
+ LocalVector<RID> render_pass_uniform_sets;
+
+ /* Light map */
+
+ struct LightmapData {
+ float normal_xform[12];
+ };
+
+ struct LightmapCaptureData {
+ float sh[9 * 4];
+ };
+
+ /* Scene state */
+
+ struct SceneState {
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+
+ float camera_matrix[16];
+ float inv_camera_matrix[16];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float directional_penumbra_shadow_kernel[128]; //32 vec4s
+ float directional_soft_shadow_kernel[128];
+ float penumbra_shadow_kernel[128];
+ float soft_shadow_kernel[128];
+
+ uint32_t directional_penumbra_shadow_samples;
+ uint32_t directional_soft_shadow_samples;
+ uint32_t penumbra_shadow_samples;
+ uint32_t soft_shadow_samples;
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t use_ambient_light;
+ uint32_t use_ambient_cubemap;
+ uint32_t use_reflection_cubemap;
+
+ float radiance_inverse_xform[12];
+
+ float shadow_atlas_pixel_size[2];
+ float directional_shadow_pixel_size[2];
+
+ uint32_t directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ uint32_t ssao_enabled;
+ float ssao_light_affect;
+ float ssao_ao_affect;
+ uint32_t roughness_limiter_enabled;
+
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ uint32_t roughness_limiter_pad[2];
+
+ float ao_color[4];
+
+ // Fog
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ uint32_t material_uv2_mode;
+
+ float time;
+ float reflection_multiplier;
+
+ uint32_t pancake_shadows;
+ uint32_t pad1;
+ uint32_t pad2;
+ uint32_t pad3;
+ };
+
+ UBO ubo;
+
+ LocalVector<RID> uniform_buffers;
+
+ // !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
+ LightmapData lightmaps[MAX_LIGHTMAPS];
+ RID lightmap_ids[MAX_LIGHTMAPS];
+ bool lightmap_has_sh[MAX_LIGHTMAPS];
+ uint32_t lightmaps_used = 0;
+ uint32_t max_lightmaps;
+ RID lightmap_buffer;
+
+ LightmapCaptureData *lightmap_captures;
+ uint32_t max_lightmap_captures;
+ RID lightmap_capture_buffer;
+
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+ bool used_sss = false;
+
+ struct ShadowPass {
+ uint32_t element_from;
+ uint32_t element_count;
+ bool flip_cull;
+ PassMode pass_mode;
+
+ RID rp_uniform_set;
+ Plane camera_plane;
+ float lod_distance_multiplier;
+ float screen_lod_threshold;
+
+ RID framebuffer;
+ RD::InitialAction initial_depth_action;
+ RD::FinalAction final_depth_action;
+ Rect2i rect;
+ };
+
+ LocalVector<ShadowPass> shadow_passes;
+ } scene_state;
+
+ /* Render List */
+
+ // !BAS! Render list can probably be reused between clustered and mobile?
+ struct RenderList {
+ LocalVector<GeometryInstanceSurfaceDataCache *> elements;
+ LocalVector<RenderElementInfo> element_info;
+
+ void clear() {
+ elements.clear();
+ element_info.clear();
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
+ }
+ };
+
+ void sort_by_key() {
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
+ sorter.sort(elements.ptr() + p_from, p_size);
+ }
+
+ struct SortByDepth {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->owner->depth < B->owner->depth);
+ }
+ };
+
+ void sort_by_depth() { //used for shadows
+
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ struct SortByReverseDepthAndPriority {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) {
+ elements.push_back(p_element);
+ }
+ };
+
+ struct RenderElementInfo {
+ uint32_t repeat : 22;
+ uint32_t uses_lightmap : 1;
+ uint32_t lod_index : 8;
+ uint32_t reserved : 1; // was uses_forward_gi but we don't use that here
+ };
+
+ template <PassMode p_pass_mode>
+ _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
+
+ void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
+
+ LocalVector<RD::DrawListID> thread_draw_lists;
+ void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params);
+ void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
+
+ uint32_t render_list_thread_threshold = 500;
+
+ RenderList render_list[RENDER_LIST_MAX];
+
+ /* Geometry instance */
+
+ // check which ones of these apply, probably all except GI and SDFGI
+ enum {
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
+ INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11,
+ INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
+ INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
+ };
+
+ struct GeometryInstanceLightmapSH {
+ Color sh[9];
+ };
+
+ // Cached data for drawing surfaces
+ struct GeometryInstanceSurfaceDataCache {
+ enum {
+ FLAG_PASS_DEPTH = 1,
+ FLAG_PASS_OPAQUE = 2,
+ FLAG_PASS_ALPHA = 4,
+ FLAG_PASS_SHADOW = 8,
+ FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
+ FLAG_USES_SUBSURFACE_SCATTERING = 2048,
+ FLAG_USES_SCREEN_TEXTURE = 4096,
+ FLAG_USES_DEPTH_TEXTURE = 8192,
+ FLAG_USES_NORMAL_TEXTURE = 16384,
+ FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
+ FLAG_USES_PARTICLE_TRAILS = 65536,
+ };
+
+ union {
+ struct {
+ // !BAS! CHECK BITS!!!
+
+ uint64_t surface_index : 10;
+ uint64_t geometry_id : 32;
+ uint64_t material_id_low : 16;
+
+ uint64_t material_id_hi : 16;
+ uint64_t shader_id : 32;
+ uint64_t uses_lightmap : 4; // sort by lightmap id here, not whether its yes/no (is 4 bits enough?)
+ uint64_t depth_layer : 4;
+ uint64_t priority : 8;
+
+ // uint64_t lod_index : 8; // no need to sort on LOD
+ // uint64_t uses_forward_gi : 1; // no GI here, remove
+ };
+ struct {
+ uint64_t sort_key1;
+ uint64_t sort_key2;
+ };
+ } sort;
+
+ RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
+ uint32_t flags = 0;
+ uint32_t surface_index = 0;
+ uint32_t lod_index = 0;
+
+ void *surface = nullptr;
+ RID material_uniform_set;
+ SceneShaderForwardMobile::ShaderData *shader = nullptr;
+
+ void *surface_shadow = nullptr;
+ RID material_uniform_set_shadow;
+ SceneShaderForwardMobile::ShaderData *shader_shadow = nullptr;
+
+ GeometryInstanceSurfaceDataCache *next = nullptr;
+ GeometryInstanceForwardMobile *owner = nullptr;
+ };
+
+ // !BAS! GeometryInstanceForwardClustered and GeometryInstanceForwardMobile will likely have a lot of overlap
+ // may need to think about making this its own class like GeometryInstanceRD?
+
+ struct GeometryInstanceForwardMobile : public GeometryInstance {
+ // setup
+ uint32_t base_flags = 0;
+ uint32_t flags_cache = 0;
+
+ // this structure maps to our push constant in our shader and is populated right before our draw call
+ struct PushConstant {
+ float transform[16];
+ uint32_t flags;
+ uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables
+ uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
+ uint32_t layer_mask = 1;
+ float lightmap_uv_scale[4]; // doubles as uv_offset when needed
+ uint32_t reflection_probes[2]; // packed reflection probes
+ uint32_t omni_lights[2]; // packed omni lights
+ uint32_t spot_lights[2]; // packed spot lights
+ uint32_t decals[2]; // packed spot lights
+ };
+
+ // PushConstant push_constant; // we populate this from our instance data
+
+ //used during rendering
+ uint32_t layer_mask = 1;
+ RID transforms_uniform_set;
+ float depth = 0;
+ bool mirror = false;
+ Transform transform;
+ bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
+ bool non_uniform_scale = false;
+ AABB transformed_aabb; //needed for LOD
+ float lod_bias = 0.0;
+ float lod_model_scale = 1.0;
+ int32_t shader_parameters_offset = -1;
+ uint32_t instance_count = 0;
+ uint32_t trail_steps = 1;
+ RID mesh_instance;
+
+ // lightmap
+ uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap
+ uint32_t lightmap_slice_index;
+ Rect2 lightmap_uv_scale;
+ RID lightmap_instance;
+ GeometryInstanceLightmapSH *lightmap_sh = nullptr;
+
+ // culled light info
+ uint32_t reflection_probe_count;
+ RID reflection_probes[MAX_RDL_CULL];
+ uint32_t omni_light_count;
+ RID omni_lights[MAX_RDL_CULL];
+ uint32_t spot_light_count;
+ RID spot_lights[MAX_RDL_CULL];
+ uint32_t decals_count;
+ RID decals[MAX_RDL_CULL];
+
+ GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
+
+ // do we use this?
+ SelfList<GeometryInstanceForwardMobile> dirty_list_element;
+
+ struct Data {
+ //data used less often goes into regular heap
+ RID base;
+ RS::InstanceType base_type;
+
+ RID skeleton;
+ Vector<RID> surface_materials;
+ RID material_override;
+ AABB aabb;
+
+ bool use_baked_light = false;
+ bool cast_double_sided_shadows = false;
+ // bool mirror = false; // !BAS! Does not seem used, we already have this in the main struct
+
+ bool dirty_dependencies = false;
+
+ RendererStorage::DependencyTracker dependency_tracker;
+ };
+
+ Data *data = nullptr;
+
+ GeometryInstanceForwardMobile() :
+ dirty_list_element(this) {}
+ };
+
+public:
+ static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
+ static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
+
+ SelfList<GeometryInstanceForwardMobile>::List geometry_instance_dirty_list;
+
+ PagedAllocator<GeometryInstanceForwardMobile> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
+ PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
+
+ void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
+ void _geometry_instance_update(GeometryInstance *p_geometry_instance);
+ void _update_dirty_geometry_instances();
+
+ virtual GeometryInstance *geometry_instance_create(RID p_base);
+ virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton);
+ virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override);
+ virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials);
+ virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance);
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
+ virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask);
+ virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias);
+ virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable);
+ virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable);
+ virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index);
+ virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9);
+ virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset);
+ virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable);
+
+ virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance);
+ virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance);
+
+ virtual void geometry_instance_free(GeometryInstance *p_geometry_instance);
+
+ virtual uint32_t geometry_instance_get_pair_mask();
+ virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count);
+ virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count);
+ virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
+ virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count);
+
+ virtual bool free(RID p_rid);
+
+ virtual bool is_dynamic_gi_supported() const;
+ virtual bool is_clustered_enabled() const;
+ virtual bool is_volumetric_supported() const;
+ virtual uint32_t get_max_elements() const;
+
+ RenderForwardMobile(RendererStorageRD *p_storage);
+ ~RenderForwardMobile();
+};
+} // namespace RendererSceneRenderImplementation
+#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
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
new file mode 100644
index 0000000000..b9220cc514
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -0,0 +1,833 @@
+/*************************************************************************/
+/* scene_shader_forward_mobile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "scene_shader_forward_mobile.h"
+#include "core/config/project_settings.h"
+#include "render_forward_mobile.h"
+
+using namespace RendererSceneRenderImplementation;
+
+/* ShaderData */
+
+void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+
+ int blend_mode = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
+ int cull = CULL_BACK;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ bool wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+ uses_particle_trails = false;
+
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ // actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+
+ actions.uniforms = &uniforms;
+
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = shader_singleton->shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+
+ Map<String, String>::Element * el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]);
+#endif
+
+ shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
+ ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //blend modes
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ RD::PipelineColorBlendState::Attachment blend_attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_SUB: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_MUL: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ uses_blend_alpha = true; //force alpha used because of blend
+ } break;
+ case BLEND_MODE_ALPHA_TO_COVERAGE: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ }
+ }
+
+ RD::PipelineColorBlendState blend_state_blend;
+ blend_state_blend.attachments.push_back(blend_attachment);
+ RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
+
+ //update pipelines
+
+ RD::PipelineDepthStencilState depth_stencil_state;
+
+ if (depth_test != DEPTH_TEST_DISABLED) {
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+ }
+
+ for (int i = 0; i < CULL_VARIANT_MAX; i++) {
+ RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
+ };
+
+ RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
+
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ };
+
+ RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
+
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ if (!static_cast<SceneShaderForwardMobile *>(singleton)->shader.is_variant_enabled(k)) {
+ continue;
+ }
+ RD::PipelineRasterizationState raster_state;
+ raster_state.cull_mode = cull_mode_rd;
+ raster_state.wireframe = wireframe;
+
+ RD::PipelineColorBlendState blend_state;
+ RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ RD::PipelineMultisampleState multisample_state;
+
+ if (uses_alpha || uses_blend_alpha) {
+ // only allow these flags to go through if we have some form of msaa
+ if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ multisample_state.enable_alpha_to_one = true;
+ }
+
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_blend;
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
+ }
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ pipelines[i][j][k].clear();
+ continue; // do not use this version (will error if using it is attempted)
+ }
+
+ /*
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_blend;
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
+ }
+ } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
+ if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+ }
+ } else {
+ pipelines[i][j][k].clear();
+ continue; // do not use this version (will error if using it is attempted)
+ }
+ */
+ } else {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_opaque;
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, leave empty
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ // ???
+ }
+
+ /*
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_opaque;
+ } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, leave empty
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
+ blend_state = blend_state_depth_normal_roughness;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
+ blend_state = blend_state_depth_normal_roughness_giprobe;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
+ blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
+ } else {
+ //specular write
+ blend_state = blend_state_opaque_specular;
+ depth_stencil.enable_depth_test = false;
+ depth_stencil.enable_depth_write = false;
+ }
+ */
+ }
+
+ RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ }
+ }
+ }
+
+ valid = true;
+}
+
+void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderForwardMobile::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderForwardMobile::ShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ return shader_singleton->shader.version_get_native_source_code(version);
+}
+
+SceneShaderForwardMobile::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderForwardMobile::ShaderData::~ShaderData() {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+ ERR_FAIL_COND(!shader_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ shader_singleton->shader.version_free(version);
+ }
+}
+
+RendererStorageRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+
+void SceneShaderForwardMobile::MaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET);
+}
+
+SceneShaderForwardMobile::MaterialData::~MaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
+ MaterialData *material_data = memnew(MaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+/* Scene Shader */
+
+SceneShaderForwardMobile *SceneShaderForwardMobile::singleton = nullptr;
+
+SceneShaderForwardMobile::SceneShaderForwardMobile() {
+ // there should be only one of these, contained within our RenderForwardMobile singleton.
+ singleton = this;
+}
+
+void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p_defines) {
+ storage = p_storage;
+
+ /* SCENE SHADER */
+
+ {
+ Vector<String> shader_versions;
+ shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // !BAS! SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP (maybe rename to SHADER_VERSION_SHADOW_PASS_DP?)
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
+ shader.initialize(shader_versions, p_defines);
+ }
+
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
+
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
+ actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
+ actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
+ actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
+ actions.renames["MODELVIEW_MATRIX"] = "modelview";
+ actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["TANGENT"] = "tangent";
+ actions.renames["BINORMAL"] = "binormal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["UV"] = "uv_interp";
+ actions.renames["UV2"] = "uv2_interp";
+ actions.renames["COLOR"] = "color_interp";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+ //builtins
+
+ actions.renames["TIME"] = "scene_data.time";
+ actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["METALLIC"] = "metallic";
+ actions.renames["SPECULAR"] = "specular";
+ actions.renames["ROUGHNESS"] = "roughness";
+ actions.renames["RIM"] = "rim";
+ actions.renames["RIM_TINT"] = "rim_tint";
+ actions.renames["CLEARCOAT"] = "clearcoat";
+ actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions.renames["ANISOTROPY"] = "anisotropy";
+ actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions.renames["SSS_STRENGTH"] = "sss_strength";
+ actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+ actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+ actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
+ actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+ actions.renames["BACKLIGHT"] = "backlight";
+ actions.renames["AO"] = "ao";
+ actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+ actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["RADIANCE"] = "custom_radiance";
+ actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+ actions.usage_defines["BINORMAL"] = "@TANGENT";
+ actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+ actions.usage_defines["RIM_TINT"] = "@RIM";
+ actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+ actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+ actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions.usage_defines["AO"] = "#define AO_USED\n";
+ actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+ actions.usage_defines["UV"] = "#define UV_USED\n";
+ actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+ actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+ actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+ actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+ actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+ if (!force_lambert) {
+ actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+ bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
+ if (!force_blinn) {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+ actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+
+ compiler.initialize(actions);
+ }
+
+ {
+ //default material and shader
+ default_shader = storage->shader_allocate();
+ storage->shader_initialize(default_shader);
+ storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ default_material = storage->material_allocate();
+ storage->material_initialize(default_material);
+ storage->material_set_shader(default_material, default_shader);
+
+ MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+ }
+
+ {
+ overdraw_material_shader = storage->shader_allocate();
+ storage->shader_initialize(overdraw_material_shader);
+ storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ overdraw_material = storage->material_allocate();
+ storage->material_initialize(overdraw_material);
+ storage->material_set_shader(overdraw_material, overdraw_material_shader);
+
+ wireframe_material_shader = storage->shader_allocate();
+ storage->shader_initialize(wireframe_material_shader);
+ storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
+ wireframe_material = storage->material_allocate();
+ storage->material_initialize(wireframe_material);
+ storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ }
+
+ {
+ default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(default_vec4_xform_buffer);
+ u.binding = 0;
+ uniforms.push_back(u);
+
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardMobile::TRANSFORMS_UNIFORM_SET);
+ }
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+}
+
+SceneShaderForwardMobile::~SceneShaderForwardMobile() {
+ RD::get_singleton()->free(default_vec4_xform_buffer);
+ RD::get_singleton()->free(shadow_sampler);
+
+ storage->free(wireframe_material_shader);
+ storage->free(overdraw_material_shader);
+ storage->free(default_shader);
+
+ storage->free(wireframe_material);
+ storage->free(overdraw_material);
+ storage->free(default_material);
+}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
new file mode 100644
index 0000000000..1517197d25
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* scene_shader_forward_mobile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RSSR_SCENE_SHADER_FM_H
+#define RSSR_SCENE_SHADER_FM_H
+
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class SceneShaderForwardMobile {
+private:
+ static SceneShaderForwardMobile *singleton;
+ RendererStorageRD *storage;
+
+public:
+ enum ShaderVersion {
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_SHADOW_PASS,
+ SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ SHADER_VERSION_MAX
+ };
+
+ struct ShaderData : public RendererStorageRD::ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum CullVariant {
+ CULL_VARIANT_NORMAL,
+ CULL_VARIANT_REVERSED,
+ CULL_VARIANT_DOUBLE_SIDED,
+ CULL_VARIANT_MAX
+
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+ uint32_t vertex_input_mask;
+ PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+ bool uses_particle_trails;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RendererStorageRD::ShaderData *_create_shader_func();
+ static RendererStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<SceneShaderForwardMobile *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~MaterialData();
+ };
+
+ RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ SceneForwardMobileShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID overdraw_material_shader;
+ RID overdraw_material;
+ RID wireframe_material_shader;
+ RID wireframe_material;
+ RID default_shader_rd;
+
+ RID default_vec4_xform_buffer;
+ RID default_vec4_xform_uniform_set;
+
+ RID shadow_sampler;
+
+ SceneShaderForwardMobile();
+ ~SceneShaderForwardMobile();
+
+ void init(RendererStorageRD *p_storage, const String p_defines);
+};
+
+} // namespace RendererSceneRenderImplementation
+#endif // !RSSR_SCENE_SHADER_FM_H
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 2a1a4efe48..377b0fd72d 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -304,7 +304,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
index_buffer.resize(p_indices.size() * sizeof(int32_t));
{
uint8_t *w = index_buffer.ptrw();
- copymem(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size());
+ memcpy(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size());
}
pb.index_buffer = RD::get_singleton()->index_buffer_create(p_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, index_buffer);
pb.indices = RD::get_singleton()->index_array_create(pb.index_buffer, 0, p_indices.size());
@@ -2012,6 +2012,9 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
uses_screen_texture = false;
ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
@@ -2048,7 +2051,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
print_line("\n**fragment_code:\n" + gen_code.fragment);
print_line("\n**light_code:\n" + gen_code.light);
#endif
- canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+ canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
@@ -2695,9 +2698,10 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
state.default_transforms_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
}
- default_canvas_texture = storage->canvas_texture_create();
+ default_canvas_texture = storage->canvas_texture_allocate();
+ storage->canvas_texture_initialize(default_canvas_texture);
- state.shadow_texture_size = GLOBAL_GET("rendering/quality/2d_shadow_atlas/size");
+ state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size");
//create functions for shader and material
storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_2D, _create_shader_funcs);
@@ -2706,9 +2710,14 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
state.time = 0;
{
- default_canvas_group_shader = storage->shader_create();
+ default_canvas_group_shader = storage->shader_allocate();
+ storage->shader_initialize(default_canvas_group_shader);
+
storage->shader_set_code(default_canvas_group_shader, "shader_type canvas_item; \nvoid fragment() {\n\tvec4 c = textureLod(SCREEN_TEXTURE,SCREEN_UV,0.0); if (c.a > 0.0001) c.rgb/=c.a; COLOR *= c; \n}\n");
- default_canvas_group_material = storage->material_create();
+
+ default_canvas_group_material = storage->material_allocate();
+ storage->material_initialize(default_canvas_group_material);
+
storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index be2552bd32..cb3e67e990 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -175,5 +175,14 @@ RendererCompositorRD::RendererCompositorRD() {
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- scene = memnew(RendererSceneRenderForward(storage));
+
+ uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end");
+ uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
+ if (back_end == 1 || textures_per_stage < 48) {
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage));
+ } else { // back_end == 0
+ // default to our high end renderer
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
+ }
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index cb85fc79e0..b3865de2bf 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -34,15 +34,16 @@
#include "core/os/os.h"
#include "core/templates/thread_work_pool.h"
#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
+#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
-#include "servers/rendering/renderer_rd/renderer_scene_render_forward.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
class RendererCompositorRD : public RendererCompositor {
protected:
RendererCanvasRenderRD *canvas;
RendererStorageRD *storage;
- RendererSceneRenderForward *scene;
+ RendererSceneRenderRD *scene;
RID copy_viewports_rd_shader;
RID copy_viewports_rd_pipeline;
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
new file mode 100644
index 0000000000..d631cb4bac
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* renderer_scene_environment_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+
+uint64_t RendererSceneEnvironmentRD::auto_exposure_counter = 2;
+
+void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
+ ambient_light = p_color;
+ ambient_source = p_ambient;
+ ambient_light_energy = p_energy;
+ ambient_sky_contribution = p_sky_contribution;
+ reflection_source = p_reflection_source;
+ ao_color = p_ao_color;
+}
+
+void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
+ exposure = p_exposure;
+ tone_mapper = p_tone_mapper;
+ if (!auto_exposure && p_auto_exposure) {
+ auto_exposure_version = ++auto_exposure_counter;
+ }
+ auto_exposure = p_auto_exposure;
+ white = p_white;
+ min_luminance = p_min_luminance;
+ max_luminance = p_max_luminance;
+ auto_exp_speed = p_auto_exp_speed;
+ auto_exp_scale = p_auto_exp_scale;
+}
+
+void RendererSceneEnvironmentRD::set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
+ ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");
+ glow_enabled = p_enable;
+ glow_levels = p_levels;
+ glow_intensity = p_intensity;
+ glow_strength = p_strength;
+ glow_mix = p_mix;
+ glow_bloom = p_bloom_threshold;
+ glow_blend_mode = p_blend_mode;
+ glow_hdr_bleed_threshold = p_hdr_bleed_threshold;
+ glow_hdr_bleed_scale = p_hdr_bleed_scale;
+ glow_hdr_luminance_cap = p_hdr_luminance_cap;
+}
+
+void RendererSceneEnvironmentRD::set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
+ sdfgi_enabled = p_enable;
+ sdfgi_cascades = p_cascades;
+ sdfgi_min_cell_size = p_min_cell_size;
+ sdfgi_use_occlusion = p_use_occlusion;
+ sdfgi_bounce_feedback = p_bounce_feedback;
+ sdfgi_read_sky_light = p_read_sky;
+ sdfgi_energy = p_energy;
+ sdfgi_normal_bias = p_normal_bias;
+ sdfgi_probe_bias = p_probe_bias;
+ sdfgi_y_scale = p_y_scale;
+}
+
+void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
+ fog_enabled = p_enable;
+ fog_light_color = p_light_color;
+ fog_light_energy = p_light_energy;
+ fog_sun_scatter = p_sun_scatter;
+ fog_density = p_density;
+ fog_height = p_height;
+ fog_height_density = p_height_density;
+ fog_aerial_perspective = p_fog_aerial_perspective;
+}
+
+void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
+ volumetric_fog_enabled = p_enable;
+ volumetric_fog_density = p_density;
+ volumetric_fog_light = p_light;
+ volumetric_fog_light_energy = p_light_energy;
+ volumetric_fog_length = p_length;
+ volumetric_fog_detail_spread = p_detail_spread;
+ volumetric_fog_gi_inject = p_gi_inject;
+ volumetric_fog_temporal_reprojection = p_temporal_reprojection;
+ volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
+}
+
+void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
+ ssr_enabled = p_enable;
+ ssr_max_steps = p_max_steps;
+ ssr_fade_in = p_fade_int;
+ ssr_fade_out = p_fade_out;
+ ssr_depth_tolerance = p_depth_tolerance;
+}
+
+void RendererSceneEnvironmentRD::set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
+ ssao_enabled = p_enable;
+ ssao_radius = p_radius;
+ ssao_intensity = p_intensity;
+ ssao_power = p_power;
+ ssao_detail = p_detail;
+ ssao_horizon = p_horizon;
+ ssao_sharpness = p_sharpness;
+ ssao_direct_light_affect = p_light_affect;
+ ssao_ao_channel_affect = p_ao_channel_affect;
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
new file mode 100644
index 0000000000..992c4bf471
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h
@@ -0,0 +1,155 @@
+/*************************************************************************/
+/* renderer_scene_environment_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H
+#define RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H
+
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+class RendererSceneEnvironmentRD {
+private:
+ static uint64_t auto_exposure_counter;
+
+public:
+ // BG
+ RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR;
+ RID sky;
+ float sky_custom_fov = 0.0;
+ Basis sky_orientation;
+ Color bg_color;
+ float bg_energy = 1.0;
+ int canvas_max_layer = 0;
+ RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG;
+ Color ambient_light;
+ float ambient_light_energy = 1.0;
+ float ambient_sky_contribution = 1.0;
+ RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
+ Color ao_color;
+
+ /// Tonemap
+
+ RS::EnvironmentToneMapper tone_mapper;
+ float exposure = 1.0;
+ float white = 1.0;
+ bool auto_exposure = false;
+ float min_luminance = 0.2;
+ float max_luminance = 8.0;
+ float auto_exp_speed = 0.2;
+ float auto_exp_scale = 0.5;
+ uint64_t auto_exposure_version = 0;
+
+ // Fog
+ bool fog_enabled = false;
+ Color fog_light_color = Color(0.5, 0.6, 0.7);
+ float fog_light_energy = 1.0;
+ float fog_sun_scatter = 0.0;
+ float fog_density = 0.001;
+ float fog_height = 0.0;
+ float fog_height_density = 0.0; //can be negative to invert effect
+ float fog_aerial_perspective = 0.0;
+
+ /// Volumetric Fog
+ ///
+ bool volumetric_fog_enabled = false;
+ float volumetric_fog_density = 0.01;
+ Color volumetric_fog_light = Color(0, 0, 0);
+ float volumetric_fog_light_energy = 0.0;
+ float volumetric_fog_length = 64.0;
+ float volumetric_fog_detail_spread = 2.0;
+ float volumetric_fog_gi_inject = 0.0;
+ bool volumetric_fog_temporal_reprojection = true;
+ float volumetric_fog_temporal_reprojection_amount = 0.9;
+
+ /// Glow
+
+ bool glow_enabled = false;
+ Vector<float> glow_levels;
+ float glow_intensity = 0.8;
+ float glow_strength = 1.0;
+ float glow_bloom = 0.0;
+ float glow_mix = 0.01;
+ RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT;
+ float glow_hdr_bleed_threshold = 1.0;
+ float glow_hdr_luminance_cap = 12.0;
+ float glow_hdr_bleed_scale = 2.0;
+
+ /// SSAO
+
+ bool ssao_enabled = false;
+ float ssao_radius = 1.0;
+ float ssao_intensity = 2.0;
+ float ssao_power = 1.5;
+ float ssao_detail = 0.5;
+ float ssao_horizon = 0.06;
+ float ssao_sharpness = 0.98;
+ float ssao_direct_light_affect = 0.0;
+ float ssao_ao_channel_affect = 0.0;
+
+ /// SSR
+ ///
+ bool ssr_enabled = false;
+ int ssr_max_steps = 64;
+ float ssr_fade_in = 0.15;
+ float ssr_fade_out = 2.0;
+ float ssr_depth_tolerance = 0.2;
+
+ /// SDFGI
+ bool sdfgi_enabled = false;
+ RS::EnvironmentSDFGICascades sdfgi_cascades;
+ float sdfgi_min_cell_size = 0.2;
+ bool sdfgi_use_occlusion = false;
+ float sdfgi_bounce_feedback = 0.0;
+ bool sdfgi_read_sky_light = false;
+ float sdfgi_energy = 1.0;
+ float sdfgi_normal_bias = 1.1;
+ float sdfgi_probe_bias = 1.1;
+ RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED;
+
+ /// Adjustments
+
+ bool adjustments_enabled = false;
+ float adjustments_brightness = 1.0f;
+ float adjustments_contrast = 1.0f;
+ float adjustments_saturation = 1.0f;
+ bool use_1d_color_correction = false;
+ RID color_correction = RID();
+
+ void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color);
+ void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
+ void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
+ void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
+ void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective);
+ void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount);
+ void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance);
+ void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect);
+};
+
+#endif /* !RENDERING_SERVER_SCENE_ENVIRONMENT_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
new file mode 100644
index 0000000000..bc92e0b1ad
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -0,0 +1,3402 @@
+/*************************************************************************/
+/* renderer_scene_gi_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "renderer_scene_gi_rd.h"
+
+#include "core/config/project_settings.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/rendering_server_default.h"
+
+const Vector3i RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
+
+////////////////////////////////////////////////////////////////////////////////
+// SDFGI
+
+void RendererSceneGIRD::SDFGI::create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi) {
+ storage = p_gi->storage;
+ gi = p_gi;
+ cascade_mode = p_env->sdfgi_cascades;
+ min_cell_size = p_env->sdfgi_min_cell_size;
+ uses_occlusion = p_env->sdfgi_use_occlusion;
+ y_scale_mode = p_env->sdfgi_y_scale;
+ static const float y_scale[3] = { 1.0, 1.5, 2.0 };
+ y_mult = y_scale[y_scale_mode];
+ static const int cascasde_size[3] = { 4, 6, 8 };
+ cascades.resize(cascasde_size[cascade_mode]);
+ probe_axis_count = SDFGI::PROBE_DIVISOR + 1;
+ solid_cell_ratio = gi->sdfgi_solid_cell_ratio;
+ solid_cell_count = uint32_t(float(cascade_size * cascade_size * cascade_size) * solid_cell_ratio);
+
+ float base_cell_size = min_cell_size;
+
+ RD::TextureFormat tf_sdf;
+ tf_sdf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf_sdf.width = cascade_size; // Always 64x64
+ tf_sdf.height = cascade_size;
+ tf_sdf.depth = cascade_size;
+ tf_sdf.texture_type = RD::TEXTURE_TYPE_3D;
+ tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+
+ {
+ RD::TextureFormat tf_render = tf_sdf;
+ tf_render.format = RD::DATA_FORMAT_R16_UINT;
+ render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ tf_render.format = RD::DATA_FORMAT_R32_UINT;
+ render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize
+
+ for (int i = 0; i < 8; i++) {
+ render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ }
+
+ tf_render.format = RD::DATA_FORMAT_R32_UINT;
+ render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT;
+ render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+
+ tf_render.width /= 2;
+ tf_render.height /= 2;
+ tf_render.depth /= 2;
+
+ render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
+ }
+
+ RD::TextureFormat tf_occlusion = tf_sdf;
+ tf_occlusion.format = RD::DATA_FORMAT_R16_UINT;
+ tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
+ tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
+ tf_occlusion.depth *= cascades.size(); //use depth for occlusion slices
+ tf_occlusion.width *= 2; //use width for the other half
+
+ RD::TextureFormat tf_light = tf_sdf;
+ tf_light.format = RD::DATA_FORMAT_R32_UINT;
+ tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
+ tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
+
+ RD::TextureFormat tf_aniso0 = tf_sdf;
+ tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ RD::TextureFormat tf_aniso1 = tf_sdf;
+ tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM;
+
+ int passes = nearest_shift(cascade_size) - 1;
+
+ //store lightprobe SH
+ RD::TextureFormat tf_probes;
+ tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf_probes.width = probe_axis_count * probe_axis_count;
+ tf_probes.height = probe_axis_count * SDFGI::SH_SIZE;
+ tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+
+ history_size = p_requested_history_size;
+
+ RD::TextureFormat tf_probe_history = tf_probes;
+ tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed
+ tf_probe_history.array_layers = history_size;
+
+ RD::TextureFormat tf_probe_average = tf_probes;
+ tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed
+ tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D;
+
+ lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
+ lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
+
+ {
+ //octahedral lightprobes
+ RD::TextureFormat tf_octprobes = tf_probes;
+ tf_octprobes.array_layers = cascades.size() * 2;
+ tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE
+ tf_octprobes.width = probe_axis_count * probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
+ tf_octprobes.height = probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
+ tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
+ tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
+ //lightprobe texture is an octahedral texture
+
+ lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView());
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, lightprobe_data);
+
+ //texture handling ambient data, to integrate with volumetric foc
+ RD::TextureFormat tf_ambient = tf_probes;
+ tf_ambient.array_layers = cascades.size();
+ tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
+ tf_ambient.width = probe_axis_count * probe_axis_count;
+ tf_ambient.height = probe_axis_count;
+ tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ //lightprobe texture is an octahedral texture
+ ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
+ }
+
+ cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
+
+ occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView());
+ {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
+ occlusion_texture = RD::get_singleton()->texture_create_shared(tv, occlusion_data);
+ }
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ /* 3D Textures */
+
+ cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView());
+
+ cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView());
+
+ cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView());
+ cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView());
+
+ {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+ cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data);
+
+ RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ }
+
+ cascade.cell_size = base_cell_size;
+ Vector3 world_position = p_world_position;
+ world_position.y *= y_mult;
+ int32_t probe_cells = cascade_size / SDFGI::PROBE_DIVISOR;
+ Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells;
+ Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor());
+ cascade.position = probe_pos * probe_cells;
+
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+
+ base_cell_size *= 2.0;
+
+ /* Probe History */
+
+ cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
+ RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work
+
+ cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
+ RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work
+
+ /* Buffers */
+
+ cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * solid_cell_count);
+ cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
+ cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS));
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ for (int j = 0; j < 8; j++) {
+ u.ids.push_back(render_occlusion[j]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 4;
+ u.ids.push_back(render_emission);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(render_emission_aniso);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(cascade.sdf_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(occlusion_data);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 10;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 11;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+
+ cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_STORE), 0);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_emission);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 4;
+ u.ids.push_back(render_emission_aniso);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 5;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 6;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+
+ cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_SCROLL), 0);
+ }
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ for (int j = 0; j < 8; j++) {
+ u.ids.push_back(render_occlusion[j]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(occlusion_data);
+ uniforms.push_back(u);
+ }
+
+ cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0);
+ }
+ }
+
+ //direct light
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.solid_cell_dispatch_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.solid_cell_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_data);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_aniso_0_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(cascade.light_aniso_1_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cascade.lights_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+
+ cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.direct_light.version_get_shader(gi->sdfgi_shader.direct_light_shader, 0), 0);
+ }
+
+ //preprocess initialize uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf[0]);
+ uniforms.push_back(u);
+ }
+
+ sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[0]);
+ uniforms.push_back(u);
+ }
+
+ sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0);
+ }
+
+ //jump flood uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf[1]);
+ uniforms.push_back(u);
+ }
+
+ jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
+ jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ }
+ //jump flood half uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_sdf_half[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[1]);
+ uniforms.push_back(u);
+ }
+
+ jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
+ jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
+ }
+
+ //upscale half size sdf
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ u.ids.push_back(render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass
+ uniforms.push_back(u);
+ }
+
+ upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1;
+ sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0);
+ }
+
+ //occlusion uniform set
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(render_albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 2;
+ for (int i = 0; i < 8; i++) {
+ u.ids.push_back(render_occlusion[i]);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(render_geom_facing);
+ uniforms.push_back(u);
+ }
+
+ occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.preprocess.version_get_shader(gi->sdfgi_shader.preprocess_shader, SDFGIShader::PRE_PROCESS_OCCLUSION), 0);
+ }
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ //integrate uniform
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (j < cascades.size()) {
+ u.ids.push_back(cascades[j].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 7;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(lightprobe_data);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(cascades[i].lightprobe_history_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 10;
+ u.ids.push_back(cascades[i].lightprobe_average_tex);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(lightprobe_history_scroll);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(lightprobe_average_scroll);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 13;
+ RID parent_average;
+ if (i < cascades.size() - 1) {
+ parent_average = cascades[i + 1].lightprobe_average_tex;
+ } else {
+ parent_average = cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used
+ }
+ u.ids.push_back(parent_average);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 14;
+ u.ids.push_back(ambient_texture);
+ uniforms.push_back(u);
+ }
+
+ cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 0);
+ }
+
+ bounce_feedback = p_env->sdfgi_bounce_feedback;
+ energy = p_env->sdfgi_energy;
+ normal_bias = p_env->sdfgi_normal_bias;
+ probe_bias = p_env->sdfgi_probe_bias;
+ reads_sky = p_env->sdfgi_read_sky_light;
+}
+
+void RendererSceneGIRD::SDFGI::erase() {
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ const SDFGI::Cascade &c = cascades[i];
+ RD::get_singleton()->free(c.light_data);
+ RD::get_singleton()->free(c.light_aniso_0_tex);
+ RD::get_singleton()->free(c.light_aniso_1_tex);
+ RD::get_singleton()->free(c.sdf_tex);
+ RD::get_singleton()->free(c.solid_cell_dispatch_buffer);
+ RD::get_singleton()->free(c.solid_cell_buffer);
+ RD::get_singleton()->free(c.lightprobe_history_tex);
+ RD::get_singleton()->free(c.lightprobe_average_tex);
+ RD::get_singleton()->free(c.lights_buffer);
+ }
+
+ RD::get_singleton()->free(render_albedo);
+ RD::get_singleton()->free(render_emission);
+ RD::get_singleton()->free(render_emission_aniso);
+
+ RD::get_singleton()->free(render_sdf[0]);
+ RD::get_singleton()->free(render_sdf[1]);
+
+ RD::get_singleton()->free(render_sdf_half[0]);
+ RD::get_singleton()->free(render_sdf_half[1]);
+
+ for (int i = 0; i < 8; i++) {
+ RD::get_singleton()->free(render_occlusion[i]);
+ }
+
+ RD::get_singleton()->free(render_geom_facing);
+
+ RD::get_singleton()->free(lightprobe_data);
+ RD::get_singleton()->free(lightprobe_history_scroll);
+ RD::get_singleton()->free(occlusion_data);
+ RD::get_singleton()->free(ambient_texture);
+
+ RD::get_singleton()->free(cascades_ubo);
+}
+
+void RendererSceneGIRD::SDFGI::update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position) {
+ bounce_feedback = p_env->sdfgi_bounce_feedback;
+ energy = p_env->sdfgi_energy;
+ normal_bias = p_env->sdfgi_normal_bias;
+ probe_bias = p_env->sdfgi_probe_bias;
+ reads_sky = p_env->sdfgi_read_sky_light;
+
+ int32_t drag_margin = (cascade_size / SDFGI::PROBE_DIVISOR) / 2;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+ cascade.dirty_regions = Vector3i();
+
+ Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(cascade_size / SDFGI::PROBE_DIVISOR) * 0.5;
+ probe_half_size = Vector3(0, 0, 0);
+
+ Vector3 world_position = p_world_position;
+ world_position.y *= y_mult;
+ Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size);
+
+ for (int j = 0; j < 3; j++) {
+ if (pos_in_cascade[j] < cascade.position[j]) {
+ while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) {
+ cascade.position[j] -= drag_margin * 2;
+ cascade.dirty_regions[j] += drag_margin * 2;
+ }
+ } else if (pos_in_cascade[j] > cascade.position[j]) {
+ while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) {
+ cascade.position[j] += drag_margin * 2;
+ cascade.dirty_regions[j] -= drag_margin * 2;
+ }
+ }
+
+ if (cascade.dirty_regions[j] == 0) {
+ continue; // not dirty
+ } else if (uint32_t(ABS(cascade.dirty_regions[j])) >= cascade_size) {
+ //moved too much, just redraw everything (make all dirty)
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+ break;
+ }
+ }
+
+ if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ //see how much the total dirty volume represents from the total volume
+ uint32_t total_volume = cascade_size * cascade_size * cascade_size;
+ uint32_t safe_volume = 1;
+ for (int j = 0; j < 3; j++) {
+ safe_volume *= cascade_size - ABS(cascade.dirty_regions[j]);
+ }
+ uint32_t dirty_volume = total_volume - safe_volume;
+ if (dirty_volume > (safe_volume / 2)) {
+ //more than half the volume is dirty, make all dirty so its only rendered once
+ cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
+ }
+ }
+ }
+}
+
+void RendererSceneGIRD::SDFGI::update_light() {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light");
+
+ /* Update dynamic light */
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_DYNAMIC]);
+
+ SDFGIShader::DirectLightPushConstant push_constant;
+
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.bounce_feedback = bounce_feedback;
+ push_constant.y_mult = y_mult;
+ push_constant.use_occlusion = uses_occlusion;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+ push_constant.light_count = cascade_dynamic_light_count[i];
+ push_constant.cascade = i;
+
+ if (cascades[i].all_dynamic_lights_dirty || gi->sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) {
+ push_constant.process_offset = 0;
+ push_constant.process_increment = 1;
+ } else {
+ static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = {
+ 1, 2, 4, 8, 16
+ };
+
+ uint32_t frames_to_update = frames_to_update_table[gi->sdfgi_frames_to_update_light];
+
+ push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update;
+ push_constant.process_increment = frames_to_update;
+ }
+ cascades[i].all_dynamic_lights_dirty = false;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0);
+ }
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky) {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes");
+
+ SDFGIShader::IntegratePushConstant push_constant;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.history_index = render_pass % history_size;
+ push_constant.history_size = history_size;
+ static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
+ push_constant.ray_count = ray_count[gi->sdfgi_ray_count];
+ push_constant.ray_bias = probe_bias;
+ push_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ push_constant.image_size[1] = probe_axis_count;
+ push_constant.store_ambient_texture = p_env->volumetric_fog_enabled;
+
+ RID sky_uniform_set = gi->sdfgi_shader.integrate_default_sky_uniform_set;
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
+ push_constant.y_mult = y_mult;
+
+ if (reads_sky && p_env) {
+ push_constant.sky_energy = p_env->bg_energy;
+
+ if (p_env->background == RS::ENV_BG_CLEAR_COLOR) {
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
+ Color c = storage->get_default_clear_color().to_linear();
+ push_constant.sky_color[0] = c.r;
+ push_constant.sky_color[1] = c.g;
+ push_constant.sky_color[2] = c.b;
+ } else if (p_env->background == RS::ENV_BG_COLOR) {
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
+ Color c = p_env->bg_color;
+ push_constant.sky_color[0] = c.r;
+ push_constant.sky_color[1] = c.g;
+ push_constant.sky_color[2] = c.b;
+
+ } else if (p_env->background == RS::ENV_BG_SKY) {
+ if (p_sky && p_sky->radiance.is_valid()) {
+ if (integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(integrate_sky_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(p_sky->radiance);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.integrate.version_get_shader(gi->sdfgi_shader.integrate_shader, 0), 1);
+ }
+ sky_uniform_set = integrate_sky_uniform_set;
+ push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_SKY;
+ }
+ }
+ }
+
+ render_pass++;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS]);
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ push_constant.cascade = i;
+ push_constant.world_offset[0] = cascades[i].position.x / probe_divisor;
+ push_constant.world_offset[1] = cascades[i].position.y / probe_divisor;
+ push_constant.world_offset[2] = cascades[i].position.z / probe_divisor;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+ }
+
+ //end later after raster to avoid barriering on layout changes
+ //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::SDFGI::store_probes() {
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes");
+
+ SDFGIShader::IntegratePushConstant push_constant;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.history_index = render_pass % history_size;
+ push_constant.history_size = history_size;
+ static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
+ push_constant.ray_count = ray_count[gi->sdfgi_ray_count];
+ push_constant.ray_bias = probe_bias;
+ push_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ push_constant.image_size[1] = probe_axis_count;
+ push_constant.store_ambient_texture = false;
+
+ push_constant.sky_mode = 0;
+ push_constant.y_mult = y_mult;
+
+ // Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces
+ RENDER_TIMESTAMP("Average Probes");
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
+
+ //convert to octahedral to store
+ push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+ push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ push_constant.cascade = i;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[i].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
+ }
+
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+int RendererSceneGIRD::SDFGI::get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const {
+ int dirty_count = 0;
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ const SDFGI::Cascade &c = cascades[i];
+
+ if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
+ if (dirty_count == p_region) {
+ r_local_offset = Vector3i();
+ r_local_size = Vector3i(1, 1, 1) * cascade_size;
+
+ r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ return i;
+ }
+ dirty_count++;
+ } else {
+ for (int j = 0; j < 3; j++) {
+ if (c.dirty_regions[j] != 0) {
+ if (dirty_count == p_region) {
+ Vector3i from = Vector3i(0, 0, 0);
+ Vector3i to = Vector3i(1, 1, 1) * cascade_size;
+
+ if (c.dirty_regions[j] > 0) {
+ //fill from the beginning
+ to[j] = c.dirty_regions[j];
+ } else {
+ //fill from the end
+ from[j] = to[j] + c.dirty_regions[j];
+ }
+
+ for (int k = 0; k < j; k++) {
+ // "chip" away previous regions to avoid re-voxelizing the same thing
+ if (c.dirty_regions[k] > 0) {
+ from[k] += c.dirty_regions[k];
+ } else if (c.dirty_regions[k] < 0) {
+ to[k] += c.dirty_regions[k];
+ }
+ }
+
+ r_local_offset = from;
+ r_local_size = to - from;
+
+ r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+ r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / y_mult, 1);
+
+ return i;
+ }
+
+ dirty_count++;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+void RendererSceneGIRD::SDFGI::update_cascades() {
+ //update cascades
+ SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES];
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size;
+
+ cascade_data[i].offset[0] = pos.x;
+ cascade_data[i].offset[1] = pos.y;
+ cascade_data[i].offset[2] = pos.z;
+ cascade_data[i].to_cell = 1.0 / cascades[i].cell_size;
+ cascade_data[i].probe_offset[0] = cascades[i].position.x / probe_divisor;
+ cascade_data[i].probe_offset[1] = cascades[i].position.y / probe_divisor;
+ cascade_data[i].probe_offset[2] = cascades[i].position.z / probe_divisor;
+ cascade_data[i].pad = 0;
+ }
+
+ RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
+}
+
+void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
+ if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
+ if (i < cascades.size()) {
+ u.ids.push_back(cascades[i].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_shader_version, 0);
+ }
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.debug_pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set, 0);
+
+ SDFGIShader::DebugPushConstant push_constant;
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.max_cascades = cascades.size();
+ push_constant.screen_size[0] = p_width;
+ push_constant.screen_size[1] = p_height;
+ push_constant.probe_axis_size = probe_axis_count;
+ push_constant.use_occlusion = uses_occlusion;
+ push_constant.y_mult = y_mult;
+
+ Vector2 vp_half = p_projection.get_viewport_half_extents();
+ push_constant.cam_extent[0] = vp_half.x;
+ push_constant.cam_extent[1] = vp_half.y;
+ push_constant.cam_extent[2] = -p_projection.get_z_near();
+
+ push_constant.cam_transform[0] = p_transform.basis.elements[0][0];
+ push_constant.cam_transform[1] = p_transform.basis.elements[1][0];
+ push_constant.cam_transform[2] = p_transform.basis.elements[2][0];
+ push_constant.cam_transform[3] = 0;
+ push_constant.cam_transform[4] = p_transform.basis.elements[0][1];
+ push_constant.cam_transform[5] = p_transform.basis.elements[1][1];
+ push_constant.cam_transform[6] = p_transform.basis.elements[2][1];
+ push_constant.cam_transform[7] = 0;
+ push_constant.cam_transform[8] = p_transform.basis.elements[0][2];
+ push_constant.cam_transform[9] = p_transform.basis.elements[1][2];
+ push_constant.cam_transform[10] = p_transform.basis.elements[2][2];
+ push_constant.cam_transform[11] = 0;
+ push_constant.cam_transform[12] = p_transform.origin.x;
+ push_constant.cam_transform[13] = p_transform.origin.y;
+ push_constant.cam_transform[14] = p_transform.origin.z;
+ push_constant.cam_transform[15] = 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::DebugPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_width, p_height, 1);
+ RD::get_singleton()->compute_list_end();
+
+ Size2 rtsize = storage->render_target_get_size(p_render_target);
+ storage->get_effects()->copy_to_fb_rect(p_texture, storage->render_target_get_rd_framebuffer(p_render_target), Rect2(Vector2(), rtsize), true);
+}
+
+void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
+ SDFGIShader::DebugProbesPushConstant push_constant;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j];
+ }
+ }
+
+ //gen spheres from strips
+ uint32_t band_points = 16;
+ push_constant.band_power = 4;
+ push_constant.sections_in_band = ((band_points / 2) - 1);
+ push_constant.band_mask = band_points - 2;
+ push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band);
+ push_constant.y_mult = y_mult;
+
+ uint32_t total_points = push_constant.sections_in_band * band_points;
+ uint32_t total_probes = probe_axis_count * probe_axis_count * probe_axis_count;
+
+ push_constant.grid_size[0] = cascade_size;
+ push_constant.grid_size[1] = cascade_size;
+ push_constant.grid_size[2] = cascade_size;
+ push_constant.cascade = 0;
+
+ push_constant.probe_axis_size = probe_axis_count;
+
+ if (!debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_probes_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(cascades_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(lightprobe_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(occlusion_texture);
+ uniforms.push_back(u);
+ }
+
+ debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->sdfgi_shader.debug_probes.version_get_shader(gi->sdfgi_shader.debug_probes_shader, 0), 0);
+ }
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDFGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDFGIShader::DebugProbesPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points);
+
+ if (gi->sdfgi_debug_probe_dir != Vector3()) {
+ print_line("CLICK DEBUG ME?");
+ uint32_t cascade = 0;
+ Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[cascade].position)) * cascades[cascade].cell_size * Vector3(1.0, 1.0 / y_mult, 1.0);
+ Vector3 probe_size = cascades[cascade].cell_size * (cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / y_mult, 1.0);
+ Vector3 ray_from = gi->sdfgi_debug_probe_pos;
+ Vector3 ray_to = gi->sdfgi_debug_probe_pos + gi->sdfgi_debug_probe_dir * cascades[cascade].cell_size * Math::sqrt(3.0) * cascade_size;
+ float sphere_radius = 0.2;
+ float closest_dist = 1e20;
+ gi->sdfgi_debug_probe_enabled = false;
+
+ Vector3i probe_from = cascades[cascade].position / (cascade_size / SDFGI::PROBE_DIVISOR);
+ for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) {
+ for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) {
+ for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) {
+ Vector3 pos = offset + probe_size * Vector3(i, j, k);
+ Vector3 res;
+ if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) {
+ float d = ray_from.distance_to(res);
+ if (d < closest_dist) {
+ closest_dist = d;
+ gi->sdfgi_debug_probe_enabled = true;
+ gi->sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k);
+ }
+ }
+ }
+ }
+ }
+
+ if (gi->sdfgi_debug_probe_enabled) {
+ print_line("found: " + gi->sdfgi_debug_probe_index);
+ } else {
+ print_line("no found");
+ }
+ gi->sdfgi_debug_probe_dir = Vector3();
+ }
+
+ if (gi->sdfgi_debug_probe_enabled) {
+ uint32_t cascade = 0;
+ uint32_t probe_cells = (cascade_size / SDFGI::PROBE_DIVISOR);
+ Vector3i probe_from = cascades[cascade].position / probe_cells;
+ Vector3i ofs = gi->sdfgi_debug_probe_index - probe_from;
+ if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) {
+ return;
+ }
+ if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) {
+ return;
+ }
+
+ uint32_t mult = (SDFGI::PROBE_DIVISOR + 1);
+ uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x;
+
+ push_constant.probe_debug_index = index;
+
+ uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2;
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, gi->sdfgi_shader.debug_probes_pipeline[SDFGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, debug_probes_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDFGIShader::DebugProbesPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points);
+ }
+}
+
+void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render) {
+ /* Update general SDFGI Buffer */
+
+ SDFGIData sdfgi_data;
+
+ sdfgi_data.grid_size[0] = cascade_size;
+ sdfgi_data.grid_size[1] = cascade_size;
+ sdfgi_data.grid_size[2] = cascade_size;
+
+ sdfgi_data.max_cascades = cascades.size();
+ sdfgi_data.probe_axis_size = probe_axis_count;
+ sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance
+ sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1;
+ sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1;
+
+ float csize = cascade_size;
+ sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]);
+ sdfgi_data.use_occlusion = uses_occlusion;
+ //sdfgi_data.energy = energy;
+
+ sdfgi_data.y_mult = y_mult;
+
+ float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]);
+ float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size;
+ sdfgi_data.occlusion_clamp[0] = occlusion_clamp;
+ sdfgi_data.occlusion_clamp[1] = occlusion_clamp;
+ sdfgi_data.occlusion_clamp[2] = occlusion_clamp;
+ sdfgi_data.normal_bias = (normal_bias / csize) * sdfgi_data.cascade_probe_size[0];
+
+ //vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) );
+ //vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx;
+
+ uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size);
+ sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size);
+ sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0;
+
+ sdfgi_data.energy = energy;
+
+ sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0];
+ sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1];
+ sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0];
+
+ sdfgi_data.occlusion_renormalize[0] = 0.5;
+ sdfgi_data.occlusion_renormalize[1] = 1.0;
+ sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades);
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+
+ for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) {
+ SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i];
+ Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[i].position)) * cascades[i].cell_size;
+ Vector3 cam_origin = p_transform.origin;
+ cam_origin.y *= y_mult;
+ pos -= cam_origin; //make pos local to camera, to reduce numerical error
+ c.position[0] = pos.x;
+ c.position[1] = pos.y;
+ c.position[2] = pos.z;
+ c.to_probe = 1.0 / (float(cascade_size) * cascades[i].cell_size / float(probe_axis_count - 1));
+
+ Vector3i probe_ofs = cascades[i].position / probe_divisor;
+ c.probe_world_offset[0] = probe_ofs.x;
+ c.probe_world_offset[1] = probe_ofs.y;
+ c.probe_world_offset[2] = probe_ofs.z;
+
+ c.to_cell = 1.0 / cascades[i].cell_size;
+ }
+
+ RD::get_singleton()->buffer_update(gi->sdfgi_ubo, 0, sizeof(SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
+
+ /* Update dynamic lights in SDFGI cascades */
+
+ for (uint32_t i = 0; i < cascades.size(); i++) {
+ SDFGI::Cascade &cascade = cascades[i];
+
+ SDFGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
+ uint32_t idx = 0;
+ for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) {
+ if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
+ ERR_CONTINUE(!li);
+
+ if (storage->light_directional_is_sky_only(li->light)) {
+ continue;
+ }
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ dir.y *= y_mult;
+ dir.normalize();
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].type = RS::LIGHT_DIRECTIONAL;
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+
+ idx++;
+ }
+
+ AABB cascade_aabb;
+ cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size;
+ cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size;
+
+ for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) {
+ if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
+ ERR_CONTINUE(!li);
+
+ uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
+ if (i > max_sdfgi_cascade) {
+ continue;
+ }
+
+ if (!cascade_aabb.intersects(li->aabb)) {
+ continue;
+ }
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ //faster to not do this here
+ //dir.y *= y_mult;
+ //dir.normalize();
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Vector3 pos = li->transform.origin;
+ pos.y *= y_mult;
+ lights[idx].position[0] = pos.x;
+ lights[idx].position[1] = pos.y;
+ lights[idx].position[2] = pos.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].type = storage->light_get_type(li->light);
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+ lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE);
+ }
+
+ cascade_dynamic_light_count[i] = idx;
+ }
+}
+
+void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) {
+ //print_line("rendering region " + itos(p_region));
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+ AABB bounds;
+ Vector3i from;
+ Vector3i size;
+
+ int cascade_prev = get_pending_region_data(p_region - 1, from, size, bounds);
+ int cascade_next = get_pending_region_data(p_region + 1, from, size, bounds);
+ int cascade = get_pending_region_data(p_region, from, size, bounds);
+ ERR_FAIL_COND(cascade < 0);
+
+ if (cascade_prev != cascade) {
+ //initialize render
+ RD::get_singleton()->texture_clear(render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ }
+
+ //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size));
+ p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing);
+
+ if (cascade_next != cascade) {
+ RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
+
+ RENDER_TIMESTAMP(">SDFGI Update SDF");
+ //done rendering! must update SDF
+ //clear dispatch indirect data
+
+ SDFGIShader::PreprocessPushConstant push_constant;
+ memset(&push_constant, 0, sizeof(SDFGIShader::PreprocessPushConstant));
+
+ RENDER_TIMESTAMP("Scroll SDF");
+
+ //scroll
+ if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ //for scroll
+ Vector3i dirty = cascades[cascade].dirty_regions;
+ push_constant.scroll[0] = dirty.x;
+ push_constant.scroll[1] = dirty.y;
+ push_constant.scroll[2] = dirty.z;
+ } else {
+ //for no scroll
+ push_constant.scroll[0] = 0;
+ push_constant.scroll[1] = 0;
+ push_constant.scroll[2] = 0;
+ }
+
+ cascades[cascade].all_dynamic_lights_dirty = true;
+
+ push_constant.grid_size = cascade_size;
+ push_constant.cascade = cascade;
+
+ if (cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ //must pre scroll existing data because not all is dirty
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer, 0);
+ // no barrier do all together
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_occlusion_uniform_set, 0);
+
+ Vector3i dirty = cascades[cascade].dirty_regions;
+ Vector3i groups;
+ groups.x = cascade_size - ABS(dirty.x);
+ groups.y = cascade_size - ABS(dirty.y);
+ groups.z = cascade_size - ABS(dirty.z);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z);
+
+ //no barrier, continue together
+
+ {
+ //scroll probes and their history also
+
+ SDFGIShader::IntegratePushConstant ipush_constant;
+ ipush_constant.grid_size[1] = cascade_size;
+ ipush_constant.grid_size[2] = cascade_size;
+ ipush_constant.grid_size[0] = cascade_size;
+ ipush_constant.max_cascades = cascades.size();
+ ipush_constant.probe_axis_size = probe_axis_count;
+ ipush_constant.history_index = 0;
+ ipush_constant.history_size = history_size;
+ ipush_constant.ray_count = 0;
+ ipush_constant.ray_bias = 0;
+ ipush_constant.sky_mode = 0;
+ ipush_constant.sky_energy = 0;
+ ipush_constant.sky_color[0] = 0;
+ ipush_constant.sky_color[1] = 0;
+ ipush_constant.sky_color[2] = 0;
+ ipush_constant.y_mult = y_mult;
+ ipush_constant.store_ambient_texture = false;
+
+ ipush_constant.image_size[0] = probe_axis_count * probe_axis_count;
+ ipush_constant.image_size[1] = probe_axis_count;
+
+ int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
+ ipush_constant.cascade = cascade;
+ ipush_constant.world_offset[0] = cascades[cascade].position.x / probe_divisor;
+ ipush_constant.world_offset[1] = cascades[cascade].position.y / probe_divisor;
+ ipush_constant.world_offset[2] = cascades[cascade].position.z / probe_divisor;
+
+ ipush_constant.scroll[0] = dirty.x / probe_divisor;
+ ipush_constant.scroll[1] = dirty.y / probe_divisor;
+ ipush_constant.scroll[2] = dirty.z / probe_divisor;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL_STORE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count, probe_axis_count, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (bounce_feedback > 0.0) {
+ //multibounce requires this to be stored so direct light can read from it
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
+
+ //convert to octahedral to store
+ ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+ ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, probe_axis_count * probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
+ }
+ }
+
+ //ok finally barrier
+ RD::get_singleton()->compute_list_end();
+ }
+
+ //clear dispatch indirect data
+ uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
+ RD::get_singleton()->buffer_update(cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ bool half_size = true; //much faster, very little difference
+ static const int optimized_jf_group_size = 8;
+
+ if (half_size) {
+ push_constant.grid_size >>= 1;
+
+ uint32_t cascade_half_size = cascade_size >> 1;
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_half_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //must start with regular jumpflood
+
+ push_constant.half_size = true;
+ {
+ RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)");
+
+ uint32_t s = cascade_half_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
+
+ int jf_us = 0;
+ //start with regular jump flood for very coarse reads, as this is impossible to optimize
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+
+ if (cascade_half_size / (s / 2) >= optimized_jf_group_size) {
+ break;
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)");
+
+ //continue with optimized jump flood for smaller reads
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_half_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+ }
+ }
+
+ // restore grid size for last passes
+ push_constant.grid_size = cascade_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_upscale_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //run one pass of fullsize jumpflood to fix up half size arctifacts
+
+ push_constant.half_size = false;
+ push_constant.step_size = 1;
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[upscale_jfa_uniform_set_index], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ } else {
+ //full size jumpflood
+ RENDER_TIMESTAMP("SDFGI Jump Flood");
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ push_constant.half_size = false;
+ {
+ uint32_t s = cascade_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
+
+ int jf_us = 0;
+ //start with regular jump flood for very coarse reads, as this is impossible to optimize
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+
+ if (cascade_size / (s / 2) >= optimized_jf_group_size) {
+ break;
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Jump Flood Optimized");
+
+ //continue with optimized jump flood for smaller reads
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
+ while (s > 1) {
+ s /= 2;
+ push_constant.step_size = s;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[jf_us], 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ jf_us = jf_us == 0 ? 1 : 0;
+ }
+ }
+ }
+
+ RENDER_TIMESTAMP("SDFGI Occlusion");
+
+ // occlusion
+ {
+ uint32_t probe_size = cascade_size / SDFGI::PROBE_DIVISOR;
+ Vector3i probe_global_pos = cascades[cascade].position / probe_size;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_OCCLUSION]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, occlusion_uniform_set, 0);
+ for (int i = 0; i < 8; i++) {
+ //dispatch all at once for performance
+ Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1);
+
+ if ((probe_global_pos.x & 1) != 0) {
+ offset.x = (offset.x + 1) & 1;
+ }
+ if ((probe_global_pos.y & 1) != 0) {
+ offset.y = (offset.y + 1) & 1;
+ }
+ if ((probe_global_pos.z & 1) != 0) {
+ offset.z = (offset.z + 1) & 1;
+ }
+ push_constant.probe_offset[0] = offset.x;
+ push_constant.probe_offset[1] = offset.y;
+ push_constant.probe_offset[2] = offset.z;
+ push_constant.occlusion_index = i;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+
+ Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute
+ RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z);
+ }
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ RENDER_TIMESTAMP("SDFGI Store");
+
+ // store
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_STORE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].sdf_store_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
+
+ RD::get_singleton()->compute_list_end();
+
+ //clear these textures, as they will have previous garbage on next draw
+ RD::get_singleton()->texture_clear(cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+ RD::get_singleton()->texture_clear(cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
+
+#if 0
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(cascades[cascade].sdf, 0);
+ Ref<Image> img;
+ img.instance();
+ for (uint32_t i = 0; i < cascade_size; i++) {
+ Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1);
+ img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr);
+ img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png");
+ }
+
+ //finalize render and update sdf
+#endif
+
+#if 0
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(render_albedo, 0);
+ Ref<Image> img;
+ img.instance();
+ for (uint32_t i = 0; i < cascade_size; i++) {
+ Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1);
+ img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr);
+ img->convert(Image::FORMAT_RGBA8);
+ img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png");
+ }
+
+ //finalize render and update sdf
+#endif
+
+ RENDER_TIMESTAMP("<SDFGI Update SDF");
+ RD::get_singleton()->draw_command_end_label();
+ }
+}
+
+void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but...
+
+ RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs");
+
+ update_cascades();
+ ; //need cascades updated for this
+
+ SDFGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS];
+ uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS];
+
+ for (uint32_t i = 0; i < p_cascade_count; i++) {
+ ERR_CONTINUE(p_cascade_indices[i] >= cascades.size());
+
+ SDFGI::Cascade &cc = cascades[p_cascade_indices[i]];
+
+ { //fill light buffer
+
+ AABB cascade_aabb;
+ cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cc.position)) * cc.cell_size;
+ cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cc.cell_size;
+
+ int idx = 0;
+
+ for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) {
+ if (idx == SDFGI::MAX_STATIC_LIGHTS) {
+ break;
+ }
+
+ RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_positional_light_cull_result[i][j]);
+ ERR_CONTINUE(!li);
+
+ uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
+ if (p_cascade_indices[i] > max_sdfgi_cascade) {
+ continue;
+ }
+
+ if (!cascade_aabb.intersects(li->aabb)) {
+ continue;
+ }
+
+ lights[idx].type = storage->light_get_type(li->light);
+
+ Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
+ if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
+ dir.y *= y_mult; //only makes sense for directional
+ dir.normalize();
+ }
+ lights[idx].direction[0] = dir.x;
+ lights[idx].direction[1] = dir.y;
+ lights[idx].direction[2] = dir.z;
+ Vector3 pos = li->transform.origin;
+ pos.y *= y_mult;
+ lights[idx].position[0] = pos.x;
+ lights[idx].position[1] = pos.y;
+ lights[idx].position[2] = pos.z;
+ Color color = storage->light_get_color(li->light);
+ color = color.to_linear();
+ lights[idx].color[0] = color.r;
+ lights[idx].color[1] = color.g;
+ lights[idx].color[2] = color.b;
+ lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
+ lights[idx].has_shadow = storage->light_has_shadow(li->light);
+ lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDFGIShader::Light), lights);
+ }
+
+ light_count[i] = idx;
+ }
+ }
+
+ /* Static Lights */
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_STATIC]);
+
+ SDFGIShader::DirectLightPushConstant dl_push_constant;
+
+ dl_push_constant.grid_size[0] = cascade_size;
+ dl_push_constant.grid_size[1] = cascade_size;
+ dl_push_constant.grid_size[2] = cascade_size;
+ dl_push_constant.max_cascades = cascades.size();
+ dl_push_constant.probe_axis_size = probe_axis_count;
+ dl_push_constant.bounce_feedback = 0.0; // this is static light, do not multibounce yet
+ dl_push_constant.y_mult = y_mult;
+ dl_push_constant.use_occlusion = uses_occlusion;
+
+ //all must be processed
+ dl_push_constant.process_offset = 0;
+ dl_push_constant.process_increment = 1;
+
+ for (uint32_t i = 0; i < p_cascade_count; i++) {
+ ERR_CONTINUE(p_cascade_indices[i] >= cascades.size());
+
+ SDFGI::Cascade &cc = cascades[p_cascade_indices[i]];
+
+ dl_push_constant.light_count = light_count[i];
+ dl_push_constant.cascade = p_cascade_indices[i];
+
+ if (dl_push_constant.light_count > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDFGIShader::DirectLightPushConstant));
+ RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0);
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GIProbeInstance
+
+void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ uint32_t data_version = storage->gi_probe_get_data_version(probe);
+
+ // (RE)CREATE IF NEEDED
+
+ if (last_probe_data_version != data_version) {
+ //need to re-create everything
+ if (texture.is_valid()) {
+ RD::get_singleton()->free(texture);
+ RD::get_singleton()->free(write_buffer);
+ mipmaps.clear();
+ }
+
+ for (int i = 0; i < dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(dynamic_maps[i].texture);
+ RD::get_singleton()->free(dynamic_maps[i].depth);
+ }
+
+ dynamic_maps.clear();
+
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+
+ if (octree_size != Vector3i()) {
+ //can create a 3D texture
+ Vector<int> levels = storage->gi_probe_get_level_counts(probe);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tf.width = octree_size.x;
+ tf.height = octree_size.y;
+ tf.depth = octree_size.z;
+ tf.texture_type = RD::TEXTURE_TYPE_3D;
+ tf.mipmaps = levels.size();
+
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+
+ texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1);
+
+ {
+ int total_elements = 0;
+ for (int i = 0; i < levels.size(); i++) {
+ total_elements += levels[i];
+ }
+
+ write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
+ }
+
+ for (int i = 0; i < levels.size(); i++) {
+ GIProbeInstance::Mipmap mipmap;
+ mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D);
+ mipmap.level = levels.size() - i - 1;
+ mipmap.cell_offset = 0;
+ for (uint32_t j = 0; j < mipmap.level; j++) {
+ mipmap.cell_offset += levels[j];
+ }
+ mipmap.cell_count = levels[mipmap.level];
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_octree_buffer(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 4;
+ u.ids.push_back(write_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ Vector<RD::Uniform> copy_uniforms = uniforms;
+ if (i == 0) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi->gi_probe_lights_uniform);
+ copy_uniforms.push_back(u);
+ }
+
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+
+ copy_uniforms = uniforms; //restore
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(texture);
+ copy_uniforms.push_back(u);
+ }
+ mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+ } else {
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(mipmap.texture);
+ uniforms.push_back(u);
+ }
+
+ mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+
+ mipmaps.push_back(mipmap);
+ }
+
+ {
+ uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+ uint32_t oversample = nearest_power_of_2_templated(4);
+ int mipmap_index = 0;
+
+ while (mipmap_index < mipmaps.size()) {
+ GIProbeInstance::DynamicMap dmap;
+
+ if (oversample > 0) {
+ dmap.size = dynamic_map_size * (1 << oversample);
+ dmap.mipmap = -1;
+ oversample--;
+ } else {
+ dmap.size = dynamic_map_size >> mipmap_index;
+ dmap.mipmap = mipmap_index;
+ mipmap_index++;
+ }
+
+ RD::TextureFormat dtf;
+ dtf.width = dmap.size;
+ dtf.height = dmap.size;
+ dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ if (dynamic_maps.size() == 0) {
+ dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (dynamic_maps.size() == 0) {
+ //render depth for first one
+ dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+ dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ }
+
+ //just use depth as-is
+ dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ if (dynamic_maps.size() == 0) {
+ dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+ dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
+
+ Vector<RID> fb;
+ fb.push_back(dmap.albedo);
+ fb.push_back(dmap.normal);
+ fb.push_back(dmap.orm);
+ fb.push_back(dmap.texture); //emission
+ fb.push_back(dmap.depth);
+ fb.push_back(dmap.fb_depth);
+
+ dmap.fb = RD::get_singleton()->framebuffer_create(fb);
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(gi->gi_probe_lights_uniform);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dmap.albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dmap.normal);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.orm);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(dmap.fb_depth);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+ }
+ } else {
+ bool plot = dmap.mipmap >= 0;
+ bool write = dmap.mipmap < (mipmaps.size() - 1);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dynamic_maps[dynamic_maps.size() - 1].depth);
+ uniforms.push_back(u);
+ }
+
+ if (write) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 9;
+ u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 10;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ if (plot) {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(mipmaps[dmap.mipmap].texture);
+ uniforms.push_back(u);
+ }
+ }
+
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(
+ uniforms,
+ gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
+ 0);
+ }
+
+ dynamic_maps.push_back(dmap);
+ }
+ }
+ }
+
+ last_probe_data_version = data_version;
+ p_update_light_instances = true; //just in case
+
+ p_scene_render->_base_uniforms_changed();
+ }
+
+ // UDPDATE TIME
+
+ if (has_dynamic_object_data) {
+ //if it has dynamic object data, it needs to be cleared
+ RD::get_singleton()->texture_clear(texture, Color(0, 0, 0, 0), 0, mipmaps.size(), 0, 1);
+ }
+
+ uint32_t light_count = 0;
+
+ if (p_update_light_instances || p_dynamic_objects.size() > 0) {
+ light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size());
+
+ {
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(probe);
+ Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ //update lights
+
+ for (uint32_t i = 0; i < light_count; i++) {
+ GIProbeLight &l = gi->gi_probe_lights[i];
+ RID light_instance = p_light_instances[i];
+ RID light = p_scene_render->light_instance_get_base_light(light_instance);
+
+ l.type = storage->light_get_type(light);
+ if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
+ light_count--;
+ continue;
+ }
+
+ l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+ l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
+ Color color = storage->light_get_color(light).to_linear();
+ l.color[0] = color.r;
+ l.color[1] = color.g;
+ l.color[2] = color.b;
+
+ l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ Transform xform = p_scene_render->light_instance_get_base_transform(light_instance);
+
+ Vector3 pos = to_probe_xform.xform(xform.origin);
+ Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
+
+ l.position[0] = pos.x;
+ l.position[1] = pos.y;
+ l.position[2] = pos.z;
+
+ l.direction[0] = dir.x;
+ l.direction[1] = dir.y;
+ l.direction[2] = dir.z;
+
+ l.has_shadow = storage->light_has_shadow(light);
+ }
+
+ RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights);
+ }
+ }
+
+ if (has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) {
+ // PROCESS MIPMAPS
+ if (mipmaps.size()) {
+ //can update mipmaps
+
+ Vector3i probe_size = storage->gi_probe_get_octree_size(probe);
+
+ GIProbePushConstant push_constant;
+
+ push_constant.limits[0] = probe_size.x;
+ push_constant.limits[1] = probe_size.y;
+ push_constant.limits[2] = probe_size.z;
+ push_constant.stack_size = mipmaps.size();
+ push_constant.emission_scale = 1.0;
+ push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.light_count = light_count;
+ push_constant.aniso_strength = 0;
+
+ /* print_line("probe update to version " + itos(last_probe_version));
+ print_line("propagation " + rtos(push_constant.propagation));
+ print_line("dynrange " + rtos(push_constant.dynamic_range));
+ */
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ int passes;
+ if (p_update_light_instances) {
+ passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1;
+ } else {
+ passes = 1; //only re-blitting is necessary
+ }
+ int wg_size = 64;
+ int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
+
+ for (int pass = 0; pass < passes; pass++) {
+ if (p_update_light_instances) {
+ for (int i = 0; i < mipmaps.size(); i++) {
+ if (i == 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+ } else if (i == 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+ }
+
+ if (pass == 1 || i > 0) {
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ }
+ if (pass == 0 || i > 0) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].uniform_set, 0);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].second_bounce_uniform_set, 0);
+ }
+
+ push_constant.cell_offset = mipmaps[i].cell_offset;
+ push_constant.cell_count = mipmaps[i].cell_count;
+
+ int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
+ }
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
+ }
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+
+ for (int i = 0; i < mipmaps.size(); i++) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0);
+
+ push_constant.cell_offset = mipmaps[i].cell_offset;
+ push_constant.cell_count = mipmaps[i].cell_count;
+
+ int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
+ while (wg_todo) {
+ int wg_count = MIN(wg_todo, wg_limit_x);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
+ wg_todo -= wg_count;
+ push_constant.cell_offset += wg_count * wg_size;
+ }
+ }
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ has_dynamic_object_data = false; //clear until dynamic object data is used again
+
+ if (p_dynamic_objects.size() && dynamic_maps.size()) {
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
+
+ Transform oversample_scale;
+ oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
+
+ Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe);
+ Transform to_world_xform = transform * to_cell.affine_inverse();
+ Transform to_probe_xform = to_world_xform.affine_inverse();
+
+ AABB probe_aabb(Vector3(), octree_size);
+
+ //this could probably be better parallelized in compute..
+ for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
+ RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i];
+
+ //transform aabb to giprobe
+ AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance));
+
+ //this needs to wrap to grid resolution to avoid jitter
+ //also extend margin a bit just in case
+ Vector3i begin = aabb.position - Vector3i(1, 1, 1);
+ Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
+
+ for (int j = 0; j < 3; j++) {
+ if ((end[j] - begin[j]) & 1) {
+ end[j]++; //for half extents split, it needs to be even
+ }
+ begin[j] = MAX(begin[j], 0);
+ end[j] = MIN(end[j], octree_size[j] * multiplier);
+ }
+
+ //aabb = aabb.intersection(probe_aabb); //intersect
+ aabb.position = begin;
+ aabb.size = end - begin;
+
+ //print_line("aabb: " + aabb);
+
+ for (int j = 0; j < 6; j++) {
+ //if (j != 0 && j != 3) {
+ // continue;
+ //}
+ static const Vector3 render_z[6] = {
+ Vector3(1, 0, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(-1, 0, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, -1),
+ };
+ static const Vector3 render_up[6] = {
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ };
+
+ Vector3 render_dir = render_z[j];
+ Vector3 up_dir = render_up[j];
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ Transform xform;
+ xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
+
+ Vector3 x_dir = xform.basis.get_axis(0).abs();
+ int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
+ Vector3 y_dir = xform.basis.get_axis(1).abs();
+ int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
+ Vector3 z_dir = -xform.basis.get_axis(2);
+ int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
+
+ Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
+ bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
+ bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
+ bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
+
+ CameraMatrix cm;
+ cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
+
+ if (p_scene_render->cull_argument.size() == 0) {
+ p_scene_render->cull_argument.push_back(nullptr);
+ }
+ p_scene_render->cull_argument[0] = instance;
+
+ p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
+
+ GIProbeDynamicPushConstant push_constant;
+ memset(&push_constant, 0, sizeof(GIProbeDynamicPushConstant));
+ push_constant.limits[0] = octree_size.x;
+ push_constant.limits[1] = octree_size.y;
+ push_constant.limits[2] = octree_size.z;
+ push_constant.light_count = p_light_instances.size();
+ push_constant.x_dir[0] = x_dir[0];
+ push_constant.x_dir[1] = x_dir[1];
+ push_constant.x_dir[2] = x_dir[2];
+ push_constant.y_dir[0] = y_dir[0];
+ push_constant.y_dir[1] = y_dir[1];
+ push_constant.y_dir[2] = y_dir[2];
+ push_constant.z_dir[0] = z_dir[0];
+ push_constant.z_dir[1] = z_dir[1];
+ push_constant.z_dir[2] = z_dir[2];
+ push_constant.z_base = xform.origin[z_axis];
+ push_constant.z_sign = (z_flip ? -1.0 : 1.0);
+ push_constant.pos_multiplier = float(1.0) / multiplier;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.flip_x = x_flip;
+ push_constant.flip_y = y_flip;
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.prev_rect_ofs[0] = 0;
+ push_constant.prev_rect_ofs[1] = 0;
+ push_constant.prev_rect_size[0] = 0;
+ push_constant.prev_rect_size[1] = 0;
+ push_constant.on_mipmap = false;
+ push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.pad[0] = 0;
+ push_constant.pad[1] = 0;
+ push_constant.pad[2] = 0;
+
+ //process lighting
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+ //print_line("rect: " + itos(i) + ": " + rect);
+
+ for (int k = 1; k < dynamic_maps.size(); k++) {
+ // enlarge the rect if needed so all pixels fit when downscaled,
+ // this ensures downsampling is smooth and optimal because no pixels are left behind
+
+ //x
+ if (rect.position.x & 1) {
+ rect.size.x++;
+ push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
+ } else {
+ push_constant.prev_rect_ofs[0] = 0;
+ }
+ if (rect.size.x & 1) {
+ rect.size.x++;
+ }
+
+ rect.position.x >>= 1;
+ rect.size.x = MAX(1, rect.size.x >> 1);
+
+ //y
+ if (rect.position.y & 1) {
+ rect.size.y++;
+ push_constant.prev_rect_ofs[1] = 1;
+ } else {
+ push_constant.prev_rect_ofs[1] = 0;
+ }
+ if (rect.size.y & 1) {
+ rect.size.y++;
+ }
+
+ rect.position.y >>= 1;
+ rect.size.y = MAX(1, rect.size.y >> 1);
+
+ //shrink limits to ensure plot does not go outside map
+ if (dynamic_maps[k].mipmap > 0) {
+ for (int l = 0; l < 3; l++) {
+ push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
+ }
+ }
+
+ //print_line("rect: " + itos(i) + ": " + rect);
+ push_constant.rect_pos[0] = rect.position[0];
+ push_constant.rect_pos[1] = rect.position[1];
+ push_constant.prev_rect_size[0] = push_constant.rect_size[0];
+ push_constant.prev_rect_size[1] = push_constant.rect_size[1];
+ push_constant.rect_size[0] = rect.size[0];
+ push_constant.rect_size[1] = rect.size[1];
+ push_constant.on_mipmap = dynamic_maps[k].mipmap > 0;
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (dynamic_maps[k].mipmap < 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+ } else if (k < dynamic_maps.size() - 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+ } else {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+ }
+ }
+
+ has_dynamic_object_data = true; //clear until dynamic object data is used again
+ }
+
+ last_probe_version = storage->gi_probe_get_version(probe);
+}
+
+void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ if (mipmaps.size() == 0) {
+ return;
+ }
+
+ CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse());
+
+ int level = 0;
+ Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+
+ GIProbeDebugPushConstant push_constant;
+ push_constant.alpha = p_alpha;
+ push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.cell_offset = mipmaps[level].cell_offset;
+ push_constant.level = level;
+
+ push_constant.bounds[0] = octree_size.x >> level;
+ push_constant.bounds[1] = octree_size.y >> level;
+ push_constant.bounds[2] = octree_size.z >> level;
+ push_constant.pad = 0;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ push_constant.projection[i * 4 + j] = cam_transform.matrix[i][j];
+ }
+ }
+
+ if (gi->giprobe_debug_uniform_set.is_valid()) {
+ RD::get_singleton()->free(gi->giprobe_debug_uniform_set);
+ }
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 3;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ int cell_count;
+ if (!p_emission && p_lighting && has_dynamic_object_data) {
+ cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
+ } else {
+ cell_count = mipmaps[level].cell_count;
+ }
+
+ gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0);
+
+ int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
+ if (p_emission) {
+ giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
+ } else if (p_lighting) {
+ giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
+ }
+ RD::get_singleton()->draw_list_bind_render_pipeline(
+ p_draw_list,
+ gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// GIRD
+
+RendererSceneGIRD::RendererSceneGIRD() {
+ sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1)));
+ sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1)));
+ sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1)));
+}
+
+RendererSceneGIRD::~RendererSceneGIRD() {
+}
+
+void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p_sky) {
+ storage = p_storage;
+
+ /* GI */
+
+ {
+ //kinda complicated to compute the amount of slots, we try to use as many as we can
+
+ gi_probe_max_lights = 32;
+
+ gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
+ gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
+ gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1));
+
+ String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
+ versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
+ versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
+ versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
+ versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+
+ giprobe_shader.initialize(versions, defines);
+ giprobe_lighting_shader_version = giprobe_shader.version_create();
+ for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
+ giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
+ giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
+ }
+ }
+
+ {
+ String defines;
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_DEBUG_COLOR\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
+ versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
+ versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
+
+ giprobe_debug_shader.initialize(versions, defines);
+ giprobe_debug_shader_version = giprobe_debug_shader.version_create();
+ for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
+ giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = RD::POLYGON_CULL_FRONT;
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_test = true;
+ ds.enable_depth_write = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+ giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ /* SDGFI */
+
+ {
+ Vector<String> preprocess_modes;
+ preprocess_modes.push_back("\n#define MODE_SCROLL\n");
+ preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n");
+ preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n");
+ preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n");
+ preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n");
+ preprocess_modes.push_back("\n#define MODE_OCCLUSION\n");
+ preprocess_modes.push_back("\n#define MODE_STORE\n");
+ String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n";
+ sdfgi_shader.preprocess.initialize(preprocess_modes, defines);
+ sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create();
+ for (int i = 0; i < SDFGIShader::PRE_PROCESS_MAX; i++) {
+ sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
+ }
+ }
+
+ {
+ //calculate tables
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+
+ Vector<String> direct_light_modes;
+ direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n");
+ direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n");
+ sdfgi_shader.direct_light.initialize(direct_light_modes, defines);
+ sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create();
+ for (int i = 0; i < SDFGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
+ sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
+ }
+ }
+
+ {
+ //calculate tables
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n";
+ if (p_sky->sky_use_cubemap_array) {
+ defines += "\n#define USE_CUBEMAP_ARRAY\n";
+ }
+
+ Vector<String> integrate_modes;
+ integrate_modes.push_back("\n#define MODE_PROCESS\n");
+ integrate_modes.push_back("\n#define MODE_STORE\n");
+ integrate_modes.push_back("\n#define MODE_SCROLL\n");
+ integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n");
+ sdfgi_shader.integrate.initialize(integrate_modes, defines);
+ sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create();
+
+ for (int i = 0; i < SDFGIShader::INTEGRATE_MODE_MAX; i++) {
+ sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
+ }
+ }
+
+ //GK
+ {
+ //calculate tables
+ String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ Vector<String> gi_modes;
+ gi_modes.push_back("\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+
+ shader.initialize(gi_modes, defines);
+ shader_version = shader.version_create();
+ for (int i = 0; i < MODE_MAX; i++) {
+ pipelines[i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, i));
+ }
+
+ sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGIData));
+ }
+ {
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+ Vector<String> debug_modes;
+ debug_modes.push_back("");
+ sdfgi_shader.debug.initialize(debug_modes, defines);
+ sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create();
+ sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0);
+ sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version);
+ }
+ {
+ String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
+
+ Vector<String> versions;
+ versions.push_back("\n#define MODE_PROBES\n");
+ versions.push_back("\n#define MODE_VISIBILITY\n");
+
+ sdfgi_shader.debug_probes.initialize(versions, defines);
+ sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create();
+
+ {
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = RD::POLYGON_CULL_DISABLED;
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_test = true;
+ ds.enable_depth_write = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) {
+ RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i);
+ sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+ }
+ default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+ half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
+}
+
+void RendererSceneGIRD::free() {
+ RD::get_singleton()->free(default_giprobe_buffer);
+ RD::get_singleton()->free(gi_probe_lights_uniform);
+ RD::get_singleton()->free(sdfgi_ubo);
+
+ giprobe_debug_shader.version_free(giprobe_debug_shader_version);
+ giprobe_shader.version_free(giprobe_lighting_shader_version);
+ shader.version_free(shader_version);
+ sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
+ sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
+ sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader);
+ sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
+ sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+
+ memdelete_arr(gi_probe_lights);
+}
+
+RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
+ SDFGI *sdfgi = memnew(SDFGI);
+
+ sdfgi->create(p_env, p_world_position, p_requested_history_size, this);
+
+ return sdfgi;
+}
+
+void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) {
+ r_gi_probes_used = 0;
+
+ // feels a little dirty to use our container this way but....
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+
+ RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers);
+
+ RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
+
+ GIProbeData gi_probe_data[MAX_GIPROBES];
+
+ bool giprobes_changed = false;
+
+ Transform to_camera;
+ to_camera.origin = p_transform.origin; //only translation, make local
+
+ for (int i = 0; i < MAX_GIPROBES; i++) {
+ RID texture;
+ if (i < (int)p_gi_probes.size()) {
+ GIProbeInstance *gipi = get_probe_instance(p_gi_probes[i]);
+
+ if (gipi) {
+ texture = gipi->texture;
+ GIProbeData &gipd = gi_probe_data[i];
+
+ RID base_probe = gipi->probe;
+
+ Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
+
+ gipd.xform[0] = to_cell.basis.elements[0][0];
+ gipd.xform[1] = to_cell.basis.elements[1][0];
+ gipd.xform[2] = to_cell.basis.elements[2][0];
+ gipd.xform[3] = 0;
+ gipd.xform[4] = to_cell.basis.elements[0][1];
+ gipd.xform[5] = to_cell.basis.elements[1][1];
+ gipd.xform[6] = to_cell.basis.elements[2][1];
+ gipd.xform[7] = 0;
+ gipd.xform[8] = to_cell.basis.elements[0][2];
+ gipd.xform[9] = to_cell.basis.elements[1][2];
+ gipd.xform[10] = to_cell.basis.elements[2][2];
+ gipd.xform[11] = 0;
+ gipd.xform[12] = to_cell.origin.x;
+ gipd.xform[13] = to_cell.origin.y;
+ gipd.xform[14] = to_cell.origin.z;
+ gipd.xform[15] = 1;
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gipd.bounds[0] = bounds.x;
+ gipd.bounds[1] = bounds.y;
+ gipd.bounds[2] = bounds.z;
+
+ gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gipd.bias = storage->gi_probe_get_bias(base_probe);
+ gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gipd.anisotropy_strength = 0;
+ gipd.ao = storage->gi_probe_get_ao(base_probe);
+ gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+ gipd.mipmaps = gipi->mipmaps.size();
+ }
+
+ r_gi_probes_used++;
+ }
+
+ if (texture == RID()) {
+ texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ }
+
+ if (texture != rb->gi.giprobe_textures[i]) {
+ giprobes_changed = true;
+ rb->gi.giprobe_textures[i] = texture;
+ }
+ }
+
+ if (giprobes_changed) {
+ if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
+ RD::get_singleton()->free(rb->gi.uniform_set);
+ }
+ rb->gi.uniform_set = RID();
+ if (rb->volumetric_fog) {
+ if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+ RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+ }
+ rb->volumetric_fog->uniform_set = RID();
+ rb->volumetric_fog->uniform_set2 = RID();
+ }
+ }
+
+ if (p_gi_probes.size() > 0) {
+ RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) {
+ RD::get_singleton()->draw_command_begin_label("GI Render");
+
+ RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+ RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment);
+
+ if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) {
+ if (rb->ambient_buffer.is_valid()) {
+ RD::get_singleton()->free(rb->ambient_buffer);
+ RD::get_singleton()->free(rb->reflection_buffer);
+ }
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ if (half_resolution) {
+ tf.width >>= 1;
+ tf.height >>= 1;
+ }
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->gi.using_half_size_gi = half_resolution;
+ }
+
+ PushConstant push_constant;
+
+ push_constant.screen_size[0] = rb->width;
+ push_constant.screen_size[1] = rb->height;
+ push_constant.z_near = p_projection.get_z_near();
+ push_constant.z_far = p_projection.get_z_far();
+ push_constant.orthogonal = p_projection.is_orthogonal();
+ push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
+ push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
+ push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
+ push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
+ push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size());
+ push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
+
+ bool use_sdfgi = rb->sdfgi != nullptr;
+ bool use_giprobes = push_constant.max_giprobes > 0;
+
+ if (env) {
+ push_constant.ao_color[0] = env->ao_color.r;
+ push_constant.ao_color[1] = env->ao_color.g;
+ push_constant.ao_color[2] = env->ao_color.b;
+ } else {
+ push_constant.ao_color[0] = 0;
+ push_constant.ao_color[1] = 0;
+ push_constant.ao_color[2] = 0;
+ }
+
+ push_constant.cam_rotation[0] = p_transform.basis[0][0];
+ push_constant.cam_rotation[1] = p_transform.basis[1][0];
+ push_constant.cam_rotation[2] = p_transform.basis[2][0];
+ push_constant.cam_rotation[3] = 0;
+ push_constant.cam_rotation[4] = p_transform.basis[0][1];
+ push_constant.cam_rotation[5] = p_transform.basis[1][1];
+ push_constant.cam_rotation[6] = p_transform.basis[2][1];
+ push_constant.cam_rotation[7] = 0;
+ push_constant.cam_rotation[8] = p_transform.basis[0][2];
+ push_constant.cam_rotation[9] = p_transform.basis[1][2];
+ push_constant.cam_rotation[10] = p_transform.basis[2][2];
+ push_constant.cam_rotation[11] = 0;
+
+ if (rb->gi.uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
+ if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
+ u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ if (rb->sdfgi) {
+ u.ids.push_back(rb->sdfgi->occlusion_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 7;
+ u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 9;
+ u.ids.push_back(rb->ambient_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 10;
+ u.ids.push_back(rb->reflection_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 11;
+ if (rb->sdfgi) {
+ u.ids.push_back(rb->sdfgi->lightprobe_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 12;
+ u.ids.push_back(rb->depth_texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 13;
+ u.ids.push_back(p_normal_roughness_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 14;
+ RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 15;
+ u.ids.push_back(sdfgi_ubo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 16;
+ u.ids.push_back(rb->gi.giprobe_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 17;
+ for (int i = 0; i < MAX_GIPROBES; i++) {
+ u.ids.push_back(rb->gi.giprobe_textures[i]);
+ }
+ uniforms.push_back(u);
+ }
+
+ rb->gi.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
+ }
+
+ Mode mode;
+
+ if (rb->gi.using_half_size_gi) {
+ mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
+ } else {
+ mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
+ }
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
+
+ if (rb->gi.using_half_size_gi) {
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
+ } else {
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
+ }
+ //do barrier later to allow oeverlap
+ //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
+ RD::get_singleton()->draw_command_end_label();
+}
+
+RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) {
+ GIProbeInstance gi_probe;
+ gi_probe.gi = this;
+ gi_probe.storage = storage;
+ gi_probe.probe = p_base;
+ RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+ return rid;
+}
+
+void RendererSceneGIRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->transform = p_xform;
+}
+
+bool RendererSceneGIRD::gi_probe_needs_update(RID p_probe) const {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!gi_probe, false);
+
+ return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+}
+
+void RendererSceneGIRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+}
+
+void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
new file mode 100644
index 0000000000..df20011b23
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -0,0 +1,671 @@
+/*************************************************************************/
+/* renderer_scene_gi_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERING_SERVER_SCENE_GI_RD_H
+#define RENDERING_SERVER_SCENE_GI_RD_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
+class RendererSceneRenderRD;
+
+class RendererSceneGIRD {
+private:
+ RendererStorageRD *storage;
+
+ /* GIPROBE INSTANCE */
+
+ struct GIProbeLight {
+ uint32_t type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ float color[3];
+ float cos_spot_angle;
+
+ float position[3];
+ float inv_spot_attenuation;
+
+ float direction[3];
+ uint32_t has_shadow;
+ };
+
+ struct GIProbePushConstant {
+ int32_t limits[3];
+ uint32_t stack_size;
+
+ float emission_scale;
+ float propagation;
+ float dynamic_range;
+ uint32_t light_count;
+
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ float aniso_strength;
+ uint32_t pad;
+ };
+
+ struct GIProbeDynamicPushConstant {
+ int32_t limits[3];
+ uint32_t light_count;
+ int32_t x_dir[3];
+ float z_base;
+ int32_t y_dir[3];
+ float z_sign;
+ int32_t z_dir[3];
+ float pos_multiplier;
+ uint32_t rect_pos[2];
+ uint32_t rect_size[2];
+ uint32_t prev_rect_ofs[2];
+ uint32_t prev_rect_size[2];
+ uint32_t flip_x;
+ uint32_t flip_y;
+ float dynamic_range;
+ uint32_t on_mipmap;
+ float propagation;
+ float pad[3];
+ };
+
+ GIProbeLight *gi_probe_lights;
+ uint32_t gi_probe_max_lights;
+ RID gi_probe_lights_uniform;
+
+ enum {
+ GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
+ GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+ GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
+ GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+ GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
+ GI_PROBE_SHADER_VERSION_MAX
+ };
+
+ GiprobeShaderRD giprobe_shader;
+ RID giprobe_lighting_shader_version;
+ RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
+ RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
+
+ enum {
+ GI_PROBE_DEBUG_COLOR,
+ GI_PROBE_DEBUG_LIGHT,
+ GI_PROBE_DEBUG_EMISSION,
+ GI_PROBE_DEBUG_LIGHT_FULL,
+ GI_PROBE_DEBUG_MAX
+ };
+
+ struct GIProbeDebugPushConstant {
+ float projection[16];
+ uint32_t cell_offset;
+ float dynamic_range;
+ float alpha;
+ uint32_t level;
+ int32_t bounds[3];
+ uint32_t pad;
+ };
+
+ GiprobeDebugShaderRD giprobe_debug_shader;
+ RID giprobe_debug_shader_version;
+ RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
+ PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
+ RID giprobe_debug_uniform_set;
+
+ /* SDFGI */
+
+ struct SDFGIShader {
+ enum SDFGIPreprocessShaderVersion {
+ PRE_PROCESS_SCROLL,
+ PRE_PROCESS_SCROLL_OCCLUSION,
+ PRE_PROCESS_JUMP_FLOOD_INITIALIZE,
+ PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF,
+ PRE_PROCESS_JUMP_FLOOD,
+ PRE_PROCESS_JUMP_FLOOD_OPTIMIZED,
+ PRE_PROCESS_JUMP_FLOOD_UPSCALE,
+ PRE_PROCESS_OCCLUSION,
+ PRE_PROCESS_STORE,
+ PRE_PROCESS_MAX
+ };
+
+ struct PreprocessPushConstant {
+ int32_t scroll[3];
+ int32_t grid_size;
+
+ int32_t probe_offset[3];
+ int32_t step_size;
+
+ int32_t half_size;
+ uint32_t occlusion_index;
+ int32_t cascade;
+ uint32_t pad;
+ };
+
+ SdfgiPreprocessShaderRD preprocess;
+ RID preprocess_shader;
+ RID preprocess_pipeline[PRE_PROCESS_MAX];
+
+ struct DebugPushConstant {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ int32_t screen_size[2];
+ uint32_t use_occlusion;
+ float y_mult;
+
+ float cam_extent[3];
+ uint32_t probe_axis_size;
+
+ float cam_transform[16];
+ };
+
+ SdfgiDebugShaderRD debug;
+ RID debug_shader;
+ RID debug_shader_version;
+ RID debug_pipeline;
+
+ enum ProbeDebugMode {
+ PROBE_DEBUG_PROBES,
+ PROBE_DEBUG_VISIBILITY,
+ PROBE_DEBUG_MAX
+ };
+
+ struct DebugProbesPushConstant {
+ float projection[16];
+
+ uint32_t band_power;
+ uint32_t sections_in_band;
+ uint32_t band_mask;
+ float section_arc;
+
+ float grid_size[3];
+ uint32_t cascade;
+
+ uint32_t pad;
+ float y_mult;
+ int32_t probe_debug_index;
+ int32_t probe_axis_size;
+ };
+
+ SdfgiDebugProbesShaderRD debug_probes;
+ RID debug_probes_shader;
+ RID debug_probes_shader_version;
+
+ PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX];
+
+ struct Light {
+ float color[3];
+ float energy;
+
+ float direction[3];
+ uint32_t has_shadow;
+
+ float position[3];
+ float attenuation;
+
+ uint32_t type;
+ float cos_spot_angle;
+ float inv_spot_attenuation;
+ float radius;
+
+ float shadow_color[4];
+ };
+
+ struct DirectLightPushConstant {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t cascade;
+ uint32_t light_count;
+ uint32_t process_offset;
+ uint32_t process_increment;
+
+ int32_t probe_axis_size;
+ float bounce_feedback;
+ float y_mult;
+ uint32_t use_occlusion;
+ };
+
+ enum {
+ DIRECT_LIGHT_MODE_STATIC,
+ DIRECT_LIGHT_MODE_DYNAMIC,
+ DIRECT_LIGHT_MODE_MAX
+ };
+ SdfgiDirectLightShaderRD direct_light;
+ RID direct_light_shader;
+ RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
+
+ enum {
+ INTEGRATE_MODE_PROCESS,
+ INTEGRATE_MODE_STORE,
+ INTEGRATE_MODE_SCROLL,
+ INTEGRATE_MODE_SCROLL_STORE,
+ INTEGRATE_MODE_MAX
+ };
+ struct IntegratePushConstant {
+ enum {
+ SKY_MODE_DISABLED,
+ SKY_MODE_COLOR,
+ SKY_MODE_SKY,
+ };
+
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t probe_axis_size;
+ uint32_t cascade;
+ uint32_t history_index;
+ uint32_t history_size;
+
+ uint32_t ray_count;
+ float ray_bias;
+ int32_t image_size[2];
+
+ int32_t world_offset[3];
+ uint32_t sky_mode;
+
+ int32_t scroll[3];
+ float sky_energy;
+
+ float sky_color[3];
+ float y_mult;
+
+ uint32_t store_ambient_texture;
+ uint32_t pad[3];
+ };
+
+ SdfgiIntegrateShaderRD integrate;
+ RID integrate_shader;
+ RID integrate_pipeline[INTEGRATE_MODE_MAX];
+
+ RID integrate_default_sky_uniform_set;
+
+ } sdfgi_shader;
+
+public:
+ /* GIPROBE INSTANCE */
+
+ //@TODO GIProbeInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
+
+ struct GIProbeInstance {
+ // access to our containers
+ RendererStorageRD *storage;
+ RendererSceneGIRD *gi;
+
+ RID probe;
+ RID texture;
+ RID write_buffer;
+
+ struct Mipmap {
+ RID texture;
+ RID uniform_set;
+ RID second_bounce_uniform_set;
+ RID write_uniform_set;
+ uint32_t level;
+ uint32_t cell_offset;
+ uint32_t cell_count;
+ };
+ Vector<Mipmap> mipmaps;
+
+ struct DynamicMap {
+ RID texture; //color normally, or emission on first pass
+ RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
+ RID depth; //actual depth buffer for the first pass, float depth for later passes
+ RID normal; //normal buffer for the first pass
+ RID albedo; //emission buffer for the first pass
+ RID orm; //orm buffer for the first pass
+ RID fb; //used for rendering, only valid on first map
+ RID uniform_set;
+ uint32_t size;
+ int mipmap; // mipmap to write to, -1 if no mipmap assigned
+ };
+
+ Vector<DynamicMap> dynamic_maps;
+
+ int slot = -1;
+ uint32_t last_probe_version = 0;
+ uint32_t last_probe_data_version = 0;
+
+ //uint64_t last_pass = 0;
+ uint32_t render_index = 0;
+
+ bool has_dynamic_object_data = false;
+
+ Transform transform;
+
+ void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+ };
+
+ mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+ _FORCE_INLINE_ GIProbeInstance *get_probe_instance(RID p_probe) const {
+ return gi_probe_instance_owner.getornull(p_probe);
+ };
+
+ _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
+ GIProbeInstance *gi_probe = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->texture;
+ };
+
+ RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
+
+ /* SDFGI */
+
+ struct SDFGI {
+ enum {
+ MAX_CASCADES = 8,
+ CASCADE_SIZE = 128,
+ PROBE_DIVISOR = 16,
+ ANISOTROPY_SIZE = 6,
+ MAX_DYNAMIC_LIGHTS = 128,
+ MAX_STATIC_LIGHTS = 1024,
+ LIGHTPROBE_OCT_SIZE = 6,
+ SH_SIZE = 16
+ };
+
+ struct Cascade {
+ struct UBO {
+ float offset[3];
+ float to_cell;
+ int32_t probe_offset[3];
+ uint32_t pad;
+ };
+
+ //cascade blocks are full-size for volume (128^3), half size for albedo/emission
+ RID sdf_tex;
+ RID light_tex;
+ RID light_aniso_0_tex;
+ RID light_aniso_1_tex;
+
+ RID light_data;
+ RID light_aniso_0_data;
+ RID light_aniso_1_data;
+
+ struct SolidCell { // this struct is unused, but remains as reference for size
+ uint32_t position;
+ uint32_t albedo;
+ uint32_t static_light;
+ uint32_t static_light_aniso;
+ };
+
+ RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch
+ RID solid_cell_buffer;
+
+ RID lightprobe_history_tex;
+ RID lightprobe_average_tex;
+
+ float cell_size;
+ Vector3i position;
+
+ static const Vector3i DIRTY_ALL;
+ Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all.
+
+ RID sdf_store_uniform_set;
+ RID sdf_direct_light_uniform_set;
+ RID scroll_uniform_set;
+ RID scroll_occlusion_uniform_set;
+ RID integrate_uniform_set;
+ RID lights_buffer;
+
+ bool all_dynamic_lights_dirty = true;
+ };
+
+ // access to our containers
+ RendererStorageRD *storage;
+ RendererSceneGIRD *gi;
+
+ // used for rendering (voxelization)
+ RID render_albedo;
+ RID render_emission;
+ RID render_emission_aniso;
+ RID render_occlusion[8];
+ RID render_geom_facing;
+
+ RID render_sdf[2];
+ RID render_sdf_half[2];
+
+ // used for ping pong processing in cascades
+ RID sdf_initialize_uniform_set;
+ RID sdf_initialize_half_uniform_set;
+ RID jump_flood_uniform_set[2];
+ RID jump_flood_half_uniform_set[2];
+ RID sdf_upscale_uniform_set;
+ int upscale_jfa_uniform_set_index;
+ RID occlusion_uniform_set;
+
+ uint32_t cascade_size = 128;
+
+ LocalVector<Cascade> cascades;
+
+ RID lightprobe_texture;
+ RID lightprobe_data;
+ RID occlusion_texture;
+ RID occlusion_data;
+ RID ambient_texture; //integrates with volumetric fog
+
+ RID lightprobe_history_scroll; //used for scrolling lightprobes
+ RID lightprobe_average_scroll; //used for scrolling lightprobes
+
+ uint32_t history_size = 0;
+ float solid_cell_ratio = 0;
+ uint32_t solid_cell_count = 0;
+
+ RS::EnvironmentSDFGICascades cascade_mode;
+ float min_cell_size = 0;
+ uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints
+
+ RID debug_uniform_set;
+ RID debug_probes_uniform_set;
+ RID cascades_ubo;
+
+ bool uses_occlusion = false;
+ float bounce_feedback = 0.0;
+ bool reads_sky = false;
+ float energy = 1.0;
+ float normal_bias = 1.1;
+ float probe_bias = 1.1;
+ RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED;
+
+ float y_mult = 1.0;
+
+ uint32_t render_pass = 0;
+
+ int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
+ RID integrate_sky_uniform_set;
+
+ void create(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size, RendererSceneGIRD *p_gi);
+ void erase();
+ void update(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position);
+ void update_light();
+ void update_probes(RendererSceneEnvironmentRD *p_env, RendererSceneSkyRD::Sky *p_sky);
+ void store_probes();
+ int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
+ void update_cascades();
+
+ void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture);
+ void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
+
+ void pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render);
+ void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render);
+ void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
+ };
+
+ RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
+ RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES;
+ RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES;
+
+ float sdfgi_solid_cell_ratio = 0.25;
+ Vector3 sdfgi_debug_probe_pos;
+ Vector3 sdfgi_debug_probe_dir;
+ bool sdfgi_debug_probe_enabled = false;
+ Vector3i sdfgi_debug_probe_index;
+
+ /* SDFGI UPDATE */
+
+ int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
+
+ /* GI */
+ enum {
+ MAX_GIPROBES = 8
+ };
+
+ // Struct for use in render buffer
+ struct RenderBuffersGI {
+ RID giprobe_textures[MAX_GIPROBES];
+ RID giprobe_buffer;
+
+ RID full_buffer;
+ RID full_dispatch;
+ RID full_mask;
+
+ RID uniform_set;
+ bool using_half_size_gi = false;
+ };
+
+ struct SDFGIData {
+ float grid_size[3];
+ uint32_t max_cascades;
+
+ uint32_t use_occlusion;
+ int32_t probe_axis_size;
+ float probe_to_uvw;
+ float normal_bias;
+
+ float lightprobe_tex_pixel_size[3];
+ float energy;
+
+ float lightprobe_uv_offset[3];
+ float y_mult;
+
+ float occlusion_clamp[3];
+ uint32_t pad3;
+
+ float occlusion_renormalize[3];
+ uint32_t pad4;
+
+ float cascade_probe_size[3];
+ uint32_t pad5;
+
+ struct ProbeCascadeData {
+ float position[3]; //offset of (0,0,0) in world coordinates
+ float to_probe; // 1/bounds * grid_size
+ int32_t probe_world_offset[3];
+ float to_cell; // 1/bounds * grid_size
+ };
+
+ ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
+ };
+
+ struct GIProbeData {
+ float xform[16];
+ float bounds[3];
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ uint32_t blend_ambient;
+ uint32_t texture_slot;
+
+ float anisotropy_strength;
+ float ao;
+ float ao_size;
+ uint32_t mipmaps;
+ };
+
+ struct PushConstant {
+ int32_t screen_size[2];
+ float z_near;
+ float z_far;
+
+ float proj_info[4];
+ float ao_color[3];
+ uint32_t max_giprobes;
+
+ uint32_t high_quality_vct;
+ uint32_t orthogonal;
+ uint32_t pad[2];
+
+ float cam_rotation[12];
+ };
+
+ RID sdfgi_ubo;
+ enum Mode {
+ MODE_GIPROBE,
+ MODE_SDFGI,
+ MODE_COMBINED,
+ MODE_HALF_RES_GIPROBE,
+ MODE_HALF_RES_SDFGI,
+ MODE_HALF_RES_COMBINED,
+ MODE_MAX
+ };
+
+ RID default_giprobe_buffer;
+
+ bool half_resolution = false;
+ GiShaderRD shader;
+ RID shader_version;
+ RID pipelines[MODE_MAX];
+
+ RendererSceneGIRD();
+ ~RendererSceneGIRD();
+
+ void init(RendererStorageRD *p_storage, RendererSceneSkyRD *p_sky);
+ void free();
+
+ SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
+
+ void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render);
+ void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render);
+
+ RID gi_probe_instance_create(RID p_base);
+ void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
+ bool gi_probe_needs_update(RID p_probe) const;
+ void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+};
+
+#endif /* !RENDERING_SERVER_SCENE_GI_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 09d2c032a8..2d4cd11f37 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -35,8 +35,6 @@
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_server_default.h"
-uint64_t RendererSceneRenderRD::auto_exposure_counter = 2;
-
void get_vogel_disk(float *r_kernel, int p_sample_count) {
const float golden_angle = 2.4;
@@ -49,973 +47,38 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) {
}
}
-void RendererSceneRenderRD::_clear_reflection_data(ReflectionData &rd) {
- rd.layers.clear();
- rd.radiance_base_cubemap = RID();
- if (rd.downsampled_radiance_cubemap.is_valid()) {
- RD::get_singleton()->free(rd.downsampled_radiance_cubemap);
- }
- rd.downsampled_radiance_cubemap = RID();
- rd.downsampled_layer.mipmaps.clear();
- rd.coefficient_buffer = RID();
-}
-
-void RendererSceneRenderRD::_update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality) {
- //recreate radiance and all data
-
- int mipmaps = p_mipmaps;
- uint32_t w = p_size, h = p_size;
-
- if (p_use_array) {
- int layers = p_low_quality ? 8 : roughness_layers;
-
- for (int i = 0; i < layers; i++) {
- ReflectionData::Layer layer;
- uint32_t mmw = w;
- uint32_t mmh = h;
- layer.mipmaps.resize(mipmaps);
- layer.views.resize(mipmaps);
- for (int j = 0; j < mipmaps; j++) {
- ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- for (int k = 0; k < 6; k++) {
- mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j);
- Vector<RID> fbtex;
- fbtex.push_back(mm.views[k]);
- mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
-
- rd.layers.push_back(layer);
- }
-
- } else {
- mipmaps = p_low_quality ? 8 : mipmaps;
- //regular cubemap, lower quality (aliasing, less memory)
- ReflectionData::Layer layer;
- uint32_t mmw = w;
- uint32_t mmh = h;
- layer.mipmaps.resize(mipmaps);
- layer.views.resize(mipmaps);
- for (int j = 0; j < mipmaps; j++) {
- ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- for (int k = 0; k < 6; k++) {
- mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j);
- Vector<RID> fbtex;
- fbtex.push_back(mm.views[k]);
- mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
-
- rd.layers.push_back(layer);
- }
-
- rd.radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = 64; // Always 64x64
- tf.height = 64;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE;
- tf.array_layers = 6;
- tf.mipmaps = 7;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- rd.downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
- {
- uint32_t mmw = 64;
- uint32_t mmh = 64;
- rd.downsampled_layer.mipmaps.resize(7);
- for (int j = 0; j < rd.downsampled_layer.mipmaps.size(); j++) {
- ReflectionData::DownsampleLayer::Mipmap &mm = rd.downsampled_layer.mipmaps.write[j];
- mm.size.width = mmw;
- mm.size.height = mmh;
- mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rd.downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
-
- mmw = MAX(1, mmw >> 1);
- mmh = MAX(1, mmh >> 1);
- }
- }
-}
-
-void RendererSceneRenderRD::_create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays) {
- storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
-
- for (int i = 1; i < rd.downsampled_layer.mipmaps.size(); i++) {
- storage->get_effects()->cubemap_downsample(rd.downsampled_layer.mipmaps[i - 1].view, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
-
- Vector<RID> views;
- if (p_use_arrays) {
- for (int i = 1; i < rd.layers.size(); i++) {
- views.push_back(rd.layers[i].views[0]);
- }
- } else {
- for (int i = 1; i < rd.layers[0].views.size(); i++) {
- views.push_back(rd.layers[0].views[i]);
- }
- }
-
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, p_use_arrays);
-}
-
-void RendererSceneRenderRD::_create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer) {
- if (p_use_arrays) {
- //render directly to the layers
- storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x);
- } else {
- storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x);
- }
-}
-
-void RendererSceneRenderRD::_update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end) {
- for (int i = p_start; i < p_end; i++) {
- for (int j = 0; j < rd.layers[i].views.size() - 1; j++) {
- RID view = rd.layers[i].views[j];
- RID texture = rd.layers[i].views[j + 1];
- Size2i size = rd.layers[i].mipmaps[j + 1].size;
- storage->get_effects()->cubemap_downsample(view, texture, size);
- }
- }
-}
-
-void RendererSceneRenderRD::_sdfgi_erase(RenderBuffers *rb) {
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
- RD::get_singleton()->free(c.light_data);
- RD::get_singleton()->free(c.light_aniso_0_tex);
- RD::get_singleton()->free(c.light_aniso_1_tex);
- RD::get_singleton()->free(c.sdf_tex);
- RD::get_singleton()->free(c.solid_cell_dispatch_buffer);
- RD::get_singleton()->free(c.solid_cell_buffer);
- RD::get_singleton()->free(c.lightprobe_history_tex);
- RD::get_singleton()->free(c.lightprobe_average_tex);
- RD::get_singleton()->free(c.lights_buffer);
- }
-
- RD::get_singleton()->free(rb->sdfgi->render_albedo);
- RD::get_singleton()->free(rb->sdfgi->render_emission);
- RD::get_singleton()->free(rb->sdfgi->render_emission_aniso);
-
- RD::get_singleton()->free(rb->sdfgi->render_sdf[0]);
- RD::get_singleton()->free(rb->sdfgi->render_sdf[1]);
-
- RD::get_singleton()->free(rb->sdfgi->render_sdf_half[0]);
- RD::get_singleton()->free(rb->sdfgi->render_sdf_half[1]);
-
- for (int i = 0; i < 8; i++) {
- RD::get_singleton()->free(rb->sdfgi->render_occlusion[i]);
- }
-
- RD::get_singleton()->free(rb->sdfgi->render_geom_facing);
-
- RD::get_singleton()->free(rb->sdfgi->lightprobe_data);
- RD::get_singleton()->free(rb->sdfgi->lightprobe_history_scroll);
- RD::get_singleton()->free(rb->sdfgi->occlusion_data);
- RD::get_singleton()->free(rb->sdfgi->ambient_texture);
-
- RD::get_singleton()->free(rb->sdfgi->cascades_ubo);
-
- memdelete(rb->sdfgi);
-
- rb->sdfgi = nullptr;
-}
-
-const Vector3i RendererSceneRenderRD::SDFGI::Cascade::DIRTY_ALL = Vector3i(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
-
void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) {
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
bool needs_sdfgi = env && env->sdfgi_enabled;
if (!needs_sdfgi) {
if (rb->sdfgi != nullptr) {
//erase it
- _sdfgi_erase(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
}
return;
}
static const uint32_t history_frames_to_converge[RS::ENV_SDFGI_CONVERGE_MAX] = { 5, 10, 15, 20, 25, 30 };
- uint32_t requested_history_size = history_frames_to_converge[sdfgi_frames_to_converge];
+ uint32_t requested_history_size = history_frames_to_converge[gi.sdfgi_frames_to_converge];
if (rb->sdfgi && (rb->sdfgi->cascade_mode != env->sdfgi_cascades || rb->sdfgi->min_cell_size != env->sdfgi_min_cell_size || requested_history_size != rb->sdfgi->history_size || rb->sdfgi->uses_occlusion != env->sdfgi_use_occlusion || rb->sdfgi->y_scale_mode != env->sdfgi_y_scale)) {
//configuration changed, erase
- _sdfgi_erase(rb);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
}
- SDFGI *sdfgi = rb->sdfgi;
+ RendererSceneGIRD::SDFGI *sdfgi = rb->sdfgi;
if (sdfgi == nullptr) {
- //re-create
- rb->sdfgi = memnew(SDFGI);
- sdfgi = rb->sdfgi;
- sdfgi->cascade_mode = env->sdfgi_cascades;
- sdfgi->min_cell_size = env->sdfgi_min_cell_size;
- sdfgi->uses_occlusion = env->sdfgi_use_occlusion;
- sdfgi->y_scale_mode = env->sdfgi_y_scale;
- static const float y_scale[3] = { 1.0, 1.5, 2.0 };
- sdfgi->y_mult = y_scale[sdfgi->y_scale_mode];
- static const int cascasde_size[3] = { 4, 6, 8 };
- sdfgi->cascades.resize(cascasde_size[sdfgi->cascade_mode]);
- sdfgi->probe_axis_count = SDFGI::PROBE_DIVISOR + 1;
- sdfgi->solid_cell_ratio = sdfgi_solid_cell_ratio;
- sdfgi->solid_cell_count = uint32_t(float(sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size) * sdfgi->solid_cell_ratio);
-
- float base_cell_size = sdfgi->min_cell_size;
-
- RD::TextureFormat tf_sdf;
- tf_sdf.format = RD::DATA_FORMAT_R8_UNORM;
- tf_sdf.width = sdfgi->cascade_size; // Always 64x64
- tf_sdf.height = sdfgi->cascade_size;
- tf_sdf.depth = sdfgi->cascade_size;
- tf_sdf.texture_type = RD::TEXTURE_TYPE_3D;
- tf_sdf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
-
- {
- RD::TextureFormat tf_render = tf_sdf;
- tf_render.format = RD::DATA_FORMAT_R16_UINT;
- sdfgi->render_albedo = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- tf_render.format = RD::DATA_FORMAT_R32_UINT;
- sdfgi->render_emission = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_emission_aniso = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.format = RD::DATA_FORMAT_R8_UNORM; //at least its easy to visualize
-
- for (int i = 0; i < 8; i++) {
- sdfgi->render_occlusion[i] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- }
-
- tf_render.format = RD::DATA_FORMAT_R32_UINT;
- sdfgi->render_geom_facing = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.format = RD::DATA_FORMAT_R8G8B8A8_UINT;
- sdfgi->render_sdf[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_sdf[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
-
- tf_render.width /= 2;
- tf_render.height /= 2;
- tf_render.depth /= 2;
-
- sdfgi->render_sdf_half[0] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- sdfgi->render_sdf_half[1] = RD::get_singleton()->texture_create(tf_render, RD::TextureView());
- }
-
- RD::TextureFormat tf_occlusion = tf_sdf;
- tf_occlusion.format = RD::DATA_FORMAT_R16_UINT;
- tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
- tf_occlusion.shareable_formats.push_back(RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16);
- tf_occlusion.depth *= sdfgi->cascades.size(); //use depth for occlusion slices
- tf_occlusion.width *= 2; //use width for the other half
-
- RD::TextureFormat tf_light = tf_sdf;
- tf_light.format = RD::DATA_FORMAT_R32_UINT;
- tf_light.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
- tf_light.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
-
- RD::TextureFormat tf_aniso0 = tf_sdf;
- tf_aniso0.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- RD::TextureFormat tf_aniso1 = tf_sdf;
- tf_aniso1.format = RD::DATA_FORMAT_R8G8_UNORM;
-
- int passes = nearest_shift(sdfgi->cascade_size) - 1;
-
- //store lightprobe SH
- RD::TextureFormat tf_probes;
- tf_probes.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf_probes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
- tf_probes.height = sdfgi->probe_axis_count * SDFGI::SH_SIZE;
- tf_probes.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- tf_probes.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-
- sdfgi->history_size = requested_history_size;
-
- RD::TextureFormat tf_probe_history = tf_probes;
- tf_probe_history.format = RD::DATA_FORMAT_R16G16B16A16_SINT; //signed integer because SH are signed
- tf_probe_history.array_layers = sdfgi->history_size;
-
- RD::TextureFormat tf_probe_average = tf_probes;
- tf_probe_average.format = RD::DATA_FORMAT_R32G32B32A32_SINT; //signed integer because SH are signed
- tf_probe_average.texture_type = RD::TEXTURE_TYPE_2D;
-
- sdfgi->lightprobe_history_scroll = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
- sdfgi->lightprobe_average_scroll = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
-
- {
- //octahedral lightprobes
- RD::TextureFormat tf_octprobes = tf_probes;
- tf_octprobes.array_layers = sdfgi->cascades.size() * 2;
- tf_octprobes.format = RD::DATA_FORMAT_R32_UINT; //pack well with RGBE
- tf_octprobes.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
- tf_octprobes.height = sdfgi->probe_axis_count * (SDFGI::LIGHTPROBE_OCT_SIZE + 2);
- tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_R32_UINT);
- tf_octprobes.shareable_formats.push_back(RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32);
- //lightprobe texture is an octahedral texture
-
- sdfgi->lightprobe_data = RD::get_singleton()->texture_create(tf_octprobes, RD::TextureView());
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
- sdfgi->lightprobe_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->lightprobe_data);
-
- //texture handling ambient data, to integrate with volumetric foc
- RD::TextureFormat tf_ambient = tf_probes;
- tf_ambient.array_layers = sdfgi->cascades.size();
- tf_ambient.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; //pack well with RGBE
- tf_ambient.width = sdfgi->probe_axis_count * sdfgi->probe_axis_count;
- tf_ambient.height = sdfgi->probe_axis_count;
- tf_ambient.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- //lightprobe texture is an octahedral texture
- sdfgi->ambient_texture = RD::get_singleton()->texture_create(tf_ambient, RD::TextureView());
- }
-
- sdfgi->cascades_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES);
-
- sdfgi->occlusion_data = RD::get_singleton()->texture_create(tf_occlusion, RD::TextureView());
- {
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_R4G4B4A4_UNORM_PACK16;
- sdfgi->occlusion_texture = RD::get_singleton()->texture_create_shared(tv, sdfgi->occlusion_data);
- }
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
-
- /* 3D Textures */
-
- cascade.sdf_tex = RD::get_singleton()->texture_create(tf_sdf, RD::TextureView());
-
- cascade.light_data = RD::get_singleton()->texture_create(tf_light, RD::TextureView());
-
- cascade.light_aniso_0_tex = RD::get_singleton()->texture_create(tf_aniso0, RD::TextureView());
- cascade.light_aniso_1_tex = RD::get_singleton()->texture_create(tf_aniso1, RD::TextureView());
-
- {
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
- cascade.light_tex = RD::get_singleton()->texture_create_shared(tv, cascade.light_data);
-
- RD::get_singleton()->texture_clear(cascade.light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(cascade.light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- }
-
- cascade.cell_size = base_cell_size;
- Vector3 world_position = p_world_position;
- world_position.y *= sdfgi->y_mult;
- int32_t probe_cells = sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- Vector3 probe_size = Vector3(1, 1, 1) * cascade.cell_size * probe_cells;
- Vector3i probe_pos = Vector3i((world_position / probe_size + Vector3(0.5, 0.5, 0.5)).floor());
- cascade.position = probe_pos * probe_cells;
-
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
-
- base_cell_size *= 2.0;
-
- /* Probe History */
-
- cascade.lightprobe_history_tex = RD::get_singleton()->texture_create(tf_probe_history, RD::TextureView());
- RD::get_singleton()->texture_clear(cascade.lightprobe_history_tex, Color(0, 0, 0, 0), 0, 1, 0, tf_probe_history.array_layers); //needs to be cleared for average to work
-
- cascade.lightprobe_average_tex = RD::get_singleton()->texture_create(tf_probe_average, RD::TextureView());
- RD::get_singleton()->texture_clear(cascade.lightprobe_average_tex, Color(0, 0, 0, 0), 0, 1, 0, 1); //needs to be cleared for average to work
-
- /* Buffers */
-
- cascade.solid_cell_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDFGI::Cascade::SolidCell) * sdfgi->solid_cell_count);
- cascade.solid_cell_dispatch_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4, Vector<uint8_t>(), RD::STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT);
- cascade.lights_buffer = RD::get_singleton()->storage_buffer_create(sizeof(SDGIShader::Light) * MAX(SDFGI::MAX_STATIC_LIGHTS, SDFGI::MAX_DYNAMIC_LIGHTS));
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 1 : 0]); //if passes are even, we read from buffer 0, else we read from buffer 1
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- for (int j = 0; j < 8; j++) {
- u.ids.push_back(sdfgi->render_occlusion[j]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 4;
- u.ids.push_back(sdfgi->render_emission);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(sdfgi->render_emission_aniso);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(cascade.sdf_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(sdfgi->occlusion_data);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 10;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 11;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
-
- cascade.sdf_store_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_STORE), 0);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_emission);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 4;
- u.ids.push_back(sdfgi->render_emission_aniso);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 5;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 6;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
-
- cascade.scroll_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL), 0);
- }
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- for (int j = 0; j < 8; j++) {
- u.ids.push_back(sdfgi->render_occlusion[j]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->occlusion_data);
- uniforms.push_back(u);
- }
-
- cascade.scroll_occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION), 0);
- }
- }
-
- //direct light
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.solid_cell_dispatch_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.solid_cell_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 5;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_data);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 6;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_aniso_0_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 7;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(cascade.light_aniso_1_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cascade.lights_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 10;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
-
- cascade.sdf_direct_light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, 0), 0);
- }
-
- //preprocess initialize uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf[0]);
- uniforms.push_back(u);
- }
-
- sdfgi->sdf_initialize_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE), 0);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[0]);
- uniforms.push_back(u);
- }
-
- sdfgi->sdf_initialize_half_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF), 0);
- }
-
- //jump flood uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf[1]);
- uniforms.push_back(u);
- }
-
- sdfgi->jump_flood_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
- sdfgi->jump_flood_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- }
- //jump flood half uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_sdf_half[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[1]);
- uniforms.push_back(u);
- }
-
- sdfgi->jump_flood_half_uniform_set[0] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- SWAP(uniforms.write[0].ids.write[0], uniforms.write[1].ids.write[0]);
- sdfgi->jump_flood_half_uniform_set[1] = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD), 0);
- }
-
- //upscale half size sdf
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- u.ids.push_back(sdfgi->render_sdf_half[(passes & 1) ? 0 : 1]); //reverse pass order because half size
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_sdf[(passes & 1) ? 0 : 1]); //reverse pass order because it needs an extra JFA pass
- uniforms.push_back(u);
- }
-
- sdfgi->upscale_jfa_uniform_set_index = (passes & 1) ? 0 : 1;
- sdfgi->sdf_upscale_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE), 0);
- }
-
- //occlusion uniform set
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 1;
- u.ids.push_back(sdfgi->render_albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 2;
- for (int i = 0; i < 8; i++) {
- u.ids.push_back(sdfgi->render_occlusion[i]);
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(sdfgi->render_geom_facing);
- uniforms.push_back(u);
- }
-
- sdfgi->occlusion_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, SDGIShader::PRE_PROCESS_OCCLUSION), 0);
- }
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- //integrate uniform
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (j < sdfgi->cascades.size()) {
- u.ids.push_back(sdfgi->cascades[j].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 7;
- u.ids.push_back(sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(sdfgi->lightprobe_data);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
- u.ids.push_back(sdfgi->cascades[i].lightprobe_history_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
- u.ids.push_back(sdfgi->cascades[i].lightprobe_average_tex);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(sdfgi->lightprobe_history_scroll);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
- u.ids.push_back(sdfgi->lightprobe_average_scroll);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 13;
- RID parent_average;
- if (i < sdfgi->cascades.size() - 1) {
- parent_average = sdfgi->cascades[i + 1].lightprobe_average_tex;
- } else {
- parent_average = sdfgi->cascades[i - 1].lightprobe_average_tex; //to use something, but it won't be used
- }
- u.ids.push_back(parent_average);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 14;
- u.ids.push_back(sdfgi->ambient_texture);
- uniforms.push_back(u);
- }
-
- sdfgi->cascades[i].integrate_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 0);
- }
-
- sdfgi->uses_multibounce = env->sdfgi_use_multibounce;
- sdfgi->energy = env->sdfgi_energy;
- sdfgi->normal_bias = env->sdfgi_normal_bias;
- sdfgi->probe_bias = env->sdfgi_probe_bias;
- sdfgi->reads_sky = env->sdfgi_read_sky_light;
-
- _render_buffers_uniform_set_changed(p_render_buffers);
-
- return; //done. all levels will need to be rendered which its going to take a bit
- }
-
- //check for updates
-
- sdfgi->uses_multibounce = env->sdfgi_use_multibounce;
- sdfgi->energy = env->sdfgi_energy;
- sdfgi->normal_bias = env->sdfgi_normal_bias;
- sdfgi->probe_bias = env->sdfgi_probe_bias;
- sdfgi->reads_sky = env->sdfgi_read_sky_light;
-
- int32_t drag_margin = (sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) / 2;
-
- for (uint32_t i = 0; i < sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = sdfgi->cascades[i];
- cascade.dirty_regions = Vector3i();
-
- Vector3 probe_half_size = Vector3(1, 1, 1) * cascade.cell_size * float(sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * 0.5;
- probe_half_size = Vector3(0, 0, 0);
-
- Vector3 world_position = p_world_position;
- world_position.y *= sdfgi->y_mult;
- Vector3i pos_in_cascade = Vector3i((world_position + probe_half_size) / cascade.cell_size);
-
- for (int j = 0; j < 3; j++) {
- if (pos_in_cascade[j] < cascade.position[j]) {
- while (pos_in_cascade[j] < (cascade.position[j] - drag_margin)) {
- cascade.position[j] -= drag_margin * 2;
- cascade.dirty_regions[j] += drag_margin * 2;
- }
- } else if (pos_in_cascade[j] > cascade.position[j]) {
- while (pos_in_cascade[j] > (cascade.position[j] + drag_margin)) {
- cascade.position[j] += drag_margin * 2;
- cascade.dirty_regions[j] -= drag_margin * 2;
- }
- }
-
- if (cascade.dirty_regions[j] == 0) {
- continue; // not dirty
- } else if (uint32_t(ABS(cascade.dirty_regions[j])) >= sdfgi->cascade_size) {
- //moved too much, just redraw everything (make all dirty)
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
- break;
- }
- }
-
- if (cascade.dirty_regions != Vector3i() && cascade.dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- //see how much the total dirty volume represents from the total volume
- uint32_t total_volume = sdfgi->cascade_size * sdfgi->cascade_size * sdfgi->cascade_size;
- uint32_t safe_volume = 1;
- for (int j = 0; j < 3; j++) {
- safe_volume *= sdfgi->cascade_size - ABS(cascade.dirty_regions[j]);
- }
- uint32_t dirty_volume = total_volume - safe_volume;
- if (dirty_volume > (safe_volume / 2)) {
- //more than half the volume is dirty, make all dirty so its only rendered once
- cascade.dirty_regions = SDFGI::Cascade::DIRTY_ALL;
- }
- }
+ // re-create
+ rb->sdfgi = gi.create_sdfgi(env, p_world_position, requested_history_size);
+ } else {
+ //check for updates
+ rb->sdfgi->update(env, p_world_position);
}
}
@@ -1030,9 +93,9 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)
int dirty_count = 0;
for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
+ const RendererSceneGIRD::SDFGI::Cascade &c = rb->sdfgi->cascades[i];
- if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
+ if (c.dirty_regions == RendererSceneGIRD::SDFGI::Cascade::DIRTY_ALL) {
dirty_count++;
} else {
for (int j = 0; j < 3; j++) {
@@ -1046,72 +109,15 @@ int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers)
return dirty_count;
}
-int RendererSceneRenderRD::_sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND_V(rb == nullptr, -1);
- ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
-
- int dirty_count = 0;
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- const SDFGI::Cascade &c = rb->sdfgi->cascades[i];
-
- if (c.dirty_regions == SDFGI::Cascade::DIRTY_ALL) {
- if (dirty_count == p_region) {
- r_local_offset = Vector3i();
- r_local_size = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size;
-
- r_bounds.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position)) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- return i;
- }
- dirty_count++;
- } else {
- for (int j = 0; j < 3; j++) {
- if (c.dirty_regions[j] != 0) {
- if (dirty_count == p_region) {
- Vector3i from = Vector3i(0, 0, 0);
- Vector3i to = Vector3i(1, 1, 1) * rb->sdfgi->cascade_size;
-
- if (c.dirty_regions[j] > 0) {
- //fill from the beginning
- to[j] = c.dirty_regions[j];
- } else {
- //fill from the end
- from[j] = to[j] + c.dirty_regions[j];
- }
-
- for (int k = 0; k < j; k++) {
- // "chip" away previous regions to avoid re-voxelizing the same thing
- if (c.dirty_regions[k] > 0) {
- from[k] += c.dirty_regions[k];
- } else if (c.dirty_regions[k] < 0) {
- to[k] += c.dirty_regions[k];
- }
- }
-
- r_local_offset = from;
- r_local_size = to - from;
-
- r_bounds.position = Vector3(from + Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + c.position) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
- r_bounds.size = Vector3(r_local_size) * c.cell_size * Vector3(1, 1.0 / rb->sdfgi->y_mult, 1);
-
- return i;
- }
-
- dirty_count++;
- }
- }
- }
- }
- return -1;
-}
-
AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const {
AABB bounds;
Vector3i from;
Vector3i size;
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(rb == nullptr, AABB());
+ ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB());
- int c = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
+ int c = rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
ERR_FAIL_COND_V(c == -1, AABB());
return bounds;
}
@@ -1120,1949 +126,179 @@ uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_bu
AABB bounds;
Vector3i from;
Vector3i size;
-
- return _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
-}
-
-void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- //update cascades
- SDFGI::Cascade::UBO cascade_data[SDFGI::MAX_CASCADES];
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size;
-
- cascade_data[i].offset[0] = pos.x;
- cascade_data[i].offset[1] = pos.y;
- cascade_data[i].offset[2] = pos.z;
- cascade_data[i].to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size;
- cascade_data[i].probe_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor;
- cascade_data[i].probe_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor;
- cascade_data[i].probe_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor;
- cascade_data[i].pad = 0;
- }
-
- RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
-}
-
-void RendererSceneRenderRD::_sdfgi_update_light(RID p_render_buffers, RID p_environment) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Update dynamic Light");
-
- /* Update dynamic light */
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_DYNAMIC]);
-
- SDGIShader::DirectLightPushConstant push_constant;
-
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.multibounce = rb->sdfgi->uses_multibounce;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = rb->sdfgi->cascades[i];
- push_constant.light_count = rb->sdfgi->cascade_dynamic_light_count[i];
- push_constant.cascade = i;
-
- if (rb->sdfgi->cascades[i].all_dynamic_lights_dirty || sdfgi_frames_to_update_light == RS::ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME) {
- push_constant.process_offset = 0;
- push_constant.process_increment = 1;
- } else {
- static uint32_t frames_to_update_table[RS::ENV_SDFGI_UPDATE_LIGHT_MAX] = {
- 1, 2, 4, 8, 16
- };
-
- uint32_t frames_to_update = frames_to_update_table[sdfgi_frames_to_update_light];
-
- push_constant.process_offset = RSG::rasterizer->get_frame_number() % frames_to_update;
- push_constant.process_increment = frames_to_update;
- }
- rb->sdfgi->cascades[i].all_dynamic_lights_dirty = false;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascade.sdf_direct_light_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascade.solid_cell_dispatch_buffer, 0);
- }
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_sdfgi_update_probes(RID p_render_buffers, RID p_environment) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Update Probes");
-
- Environment *env = environment_owner.getornull(p_environment);
-
- SDGIShader::IntegratePushConstant push_constant;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size;
- push_constant.history_size = rb->sdfgi->history_size;
- static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
- push_constant.ray_count = ray_count[sdfgi_ray_count];
- push_constant.ray_bias = rb->sdfgi->probe_bias;
- push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
- push_constant.store_ambient_texture = env->volumetric_fog_enabled;
-
- RID sky_uniform_set = sdfgi_shader.integrate_default_sky_uniform_set;
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_DISABLED;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- if (rb->sdfgi->reads_sky && env) {
- push_constant.sky_energy = env->bg_energy;
-
- if (env->background == RS::ENV_BG_CLEAR_COLOR) {
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR;
- Color c = storage->get_default_clear_color().to_linear();
- push_constant.sky_color[0] = c.r;
- push_constant.sky_color[1] = c.g;
- push_constant.sky_color[2] = c.b;
- } else if (env->background == RS::ENV_BG_COLOR) {
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_COLOR;
- Color c = env->bg_color;
- push_constant.sky_color[0] = c.r;
- push_constant.sky_color[1] = c.g;
- push_constant.sky_color[2] = c.b;
-
- } else if (env->background == RS::ENV_BG_SKY) {
- Sky *sky = sky_owner.getornull(env->sky);
- if (sky && sky->radiance.is_valid()) {
- if (sky->sdfgi_integrate_sky_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->sdfgi_integrate_sky_uniform_set)) {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(sky->radiance);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 1;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- sky->sdfgi_integrate_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
- }
- sky_uniform_set = sky->sdfgi_integrate_sky_uniform_set;
- push_constant.sky_mode = SDGIShader::IntegratePushConstant::SKY_MODE_SKY;
- }
- }
- }
-
- rb->sdfgi->render_pass++;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_PROCESS]);
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- push_constant.cascade = i;
- push_constant.world_offset[0] = rb->sdfgi->cascades[i].position.x / probe_divisor;
- push_constant.world_offset[1] = rb->sdfgi->cascades[i].position.y / probe_divisor;
- push_constant.world_offset[2] = rb->sdfgi->cascades[i].position.z / probe_divisor;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sky_uniform_set, 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
- }
-
- //end later after raster to avoid barriering on layout changes
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
-
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_sdfgi_store_probes(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
- }
-
- RD::get_singleton()->barrier(RD::BARRIER_MASK_COMPUTE, RD::BARRIER_MASK_COMPUTE);
- RD::get_singleton()->draw_command_begin_label("SDFGI Store Probes");
-
- SDGIShader::IntegratePushConstant push_constant;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.history_index = rb->sdfgi->render_pass % rb->sdfgi->history_size;
- push_constant.history_size = rb->sdfgi->history_size;
- static const uint32_t ray_count[RS::ENV_SDFGI_RAY_COUNT_MAX] = { 4, 8, 16, 32, 64, 96, 128 };
- push_constant.ray_count = ray_count[sdfgi_ray_count];
- push_constant.ray_bias = rb->sdfgi->probe_bias;
- push_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- push_constant.image_size[1] = rb->sdfgi->probe_axis_count;
- push_constant.store_ambient_texture = false;
-
- push_constant.sky_mode = 0;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- // Then store values into the lightprobe texture. Separating these steps has a small performance hit, but it allows for multiple bounces
- RENDER_TIMESTAMP("Average Probes");
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]);
-
- //convert to octahedral to store
- push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
- push_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- push_constant.cascade = i;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[i].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
- }
-
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
-
- RD::get_singleton()->draw_command_end_label();
-}
-void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) {
- r_gi_probes_used = 0;
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
-
- RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
-
- RID gi_probe_buffer = render_buffers_get_gi_probe_buffer(p_render_buffers);
- GI::GIProbeData gi_probe_data[RenderBuffers::MAX_GIPROBES];
-
- bool giprobes_changed = false;
-
- Transform to_camera;
- to_camera.origin = p_transform.origin; //only translation, make local
-
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- RID texture;
- if (i < (int)p_gi_probes.size()) {
- GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]);
-
- if (gipi) {
- texture = gipi->texture;
- GI::GIProbeData &gipd = gi_probe_data[i];
-
- RID base_probe = gipi->probe;
-
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
-
- gipd.xform[0] = to_cell.basis.elements[0][0];
- gipd.xform[1] = to_cell.basis.elements[1][0];
- gipd.xform[2] = to_cell.basis.elements[2][0];
- gipd.xform[3] = 0;
- gipd.xform[4] = to_cell.basis.elements[0][1];
- gipd.xform[5] = to_cell.basis.elements[1][1];
- gipd.xform[6] = to_cell.basis.elements[2][1];
- gipd.xform[7] = 0;
- gipd.xform[8] = to_cell.basis.elements[0][2];
- gipd.xform[9] = to_cell.basis.elements[1][2];
- gipd.xform[10] = to_cell.basis.elements[2][2];
- gipd.xform[11] = 0;
- gipd.xform[12] = to_cell.origin.x;
- gipd.xform[13] = to_cell.origin.y;
- gipd.xform[14] = to_cell.origin.z;
- gipd.xform[15] = 1;
-
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
-
- gipd.bounds[0] = bounds.x;
- gipd.bounds[1] = bounds.y;
- gipd.bounds[2] = bounds.z;
-
- gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gipd.bias = storage->gi_probe_get_bias(base_probe);
- gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
- gipd.anisotropy_strength = 0;
- gipd.ao = storage->gi_probe_get_ao(base_probe);
- gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
- gipd.mipmaps = gipi->mipmaps.size();
- }
-
- r_gi_probes_used++;
- }
-
- if (texture == RID()) {
- texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
-
- if (texture != rb->giprobe_textures[i]) {
- giprobes_changed = true;
- rb->giprobe_textures[i] = texture;
- }
- }
-
- if (giprobes_changed) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
- RD::get_singleton()->free(rb->gi_uniform_set);
- }
- rb->gi_uniform_set = RID();
- if (rb->volumetric_fog) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
- RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
- }
- rb->volumetric_fog->uniform_set = RID();
- rb->volumetric_fog->uniform_set2 = RID();
- }
- }
-
- if (p_gi_probes.size() > 0) {
- RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
- }
-
- RD::get_singleton()->draw_command_end_label();
-}
-
-void RendererSceneRenderRD::_pre_process_gi(RID p_render_buffers, const Transform &p_transform) {
- // Do the required buffer transfers and setup before the depth-pre pass, this way GI can
- // run in parallel during depth-pre pass and shadow rendering.
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
-
- /* Update Cascades UBO */
-
- if (rb->sdfgi) {
- /* Update general SDFGI Buffer */
-
- _sdfgi_update_cascades(p_render_buffers);
-
- GI::SDFGIData sdfgi_data;
-
- sdfgi_data.grid_size[0] = rb->sdfgi->cascade_size;
- sdfgi_data.grid_size[1] = rb->sdfgi->cascade_size;
- sdfgi_data.grid_size[2] = rb->sdfgi->cascade_size;
-
- sdfgi_data.max_cascades = rb->sdfgi->cascades.size();
- sdfgi_data.probe_axis_size = rb->sdfgi->probe_axis_count;
- sdfgi_data.cascade_probe_size[0] = sdfgi_data.probe_axis_size - 1; //float version for performance
- sdfgi_data.cascade_probe_size[1] = sdfgi_data.probe_axis_size - 1;
- sdfgi_data.cascade_probe_size[2] = sdfgi_data.probe_axis_size - 1;
-
- float csize = rb->sdfgi->cascade_size;
- sdfgi_data.probe_to_uvw = 1.0 / float(sdfgi_data.cascade_probe_size[0]);
- sdfgi_data.use_occlusion = rb->sdfgi->uses_occlusion;
- //sdfgi_data.energy = rb->sdfgi->energy;
-
- sdfgi_data.y_mult = rb->sdfgi->y_mult;
-
- float cascade_voxel_size = (csize / sdfgi_data.cascade_probe_size[0]);
- float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size;
- sdfgi_data.occlusion_clamp[0] = occlusion_clamp;
- sdfgi_data.occlusion_clamp[1] = occlusion_clamp;
- sdfgi_data.occlusion_clamp[2] = occlusion_clamp;
- sdfgi_data.normal_bias = (rb->sdfgi->normal_bias / csize) * sdfgi_data.cascade_probe_size[0];
-
- //vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) );
- //vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx;
-
- uint32_t oct_size = SDFGI::LIGHTPROBE_OCT_SIZE;
-
- sdfgi_data.lightprobe_tex_pixel_size[0] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size * sdfgi_data.probe_axis_size);
- sdfgi_data.lightprobe_tex_pixel_size[1] = 1.0 / ((oct_size + 2) * sdfgi_data.probe_axis_size);
- sdfgi_data.lightprobe_tex_pixel_size[2] = 1.0;
-
- sdfgi_data.energy = rb->sdfgi->energy;
-
- sdfgi_data.lightprobe_uv_offset[0] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[0];
- sdfgi_data.lightprobe_uv_offset[1] = float(oct_size + 2) * sdfgi_data.lightprobe_tex_pixel_size[1];
- sdfgi_data.lightprobe_uv_offset[2] = float((oct_size + 2) * sdfgi_data.probe_axis_size) * sdfgi_data.lightprobe_tex_pixel_size[0];
-
- sdfgi_data.occlusion_renormalize[0] = 0.5;
- sdfgi_data.occlusion_renormalize[1] = 1.0;
- sdfgi_data.occlusion_renormalize[2] = 1.0 / float(sdfgi_data.max_cascades);
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
-
- for (uint32_t i = 0; i < sdfgi_data.max_cascades; i++) {
- GI::SDFGIData::ProbeCascadeData &c = sdfgi_data.cascades[i];
- Vector3 pos = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[i].position)) * rb->sdfgi->cascades[i].cell_size;
- Vector3 cam_origin = p_transform.origin;
- cam_origin.y *= rb->sdfgi->y_mult;
- pos -= cam_origin; //make pos local to camera, to reduce numerical error
- c.position[0] = pos.x;
- c.position[1] = pos.y;
- c.position[2] = pos.z;
- c.to_probe = 1.0 / (float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[i].cell_size / float(rb->sdfgi->probe_axis_count - 1));
-
- Vector3i probe_ofs = rb->sdfgi->cascades[i].position / probe_divisor;
- c.probe_world_offset[0] = probe_ofs.x;
- c.probe_world_offset[1] = probe_ofs.y;
- c.probe_world_offset[2] = probe_ofs.z;
-
- c.to_cell = 1.0 / rb->sdfgi->cascades[i].cell_size;
- }
-
- RD::get_singleton()->buffer_update(gi.sdfgi_ubo, 0, sizeof(GI::SDFGIData), &sdfgi_data, RD::BARRIER_MASK_COMPUTE);
-
- /* Update dynamic lights in SDFGI cascades */
-
- for (uint32_t i = 0; i < rb->sdfgi->cascades.size(); i++) {
- SDFGI::Cascade &cascade = rb->sdfgi->cascades[i];
-
- SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
- uint32_t idx = 0;
- for (uint32_t j = 0; j < (uint32_t)render_state.sdfgi_update_data->directional_lights->size(); j++) {
- if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->directional_lights->get(j));
- ERR_CONTINUE(!li);
-
- if (storage->light_directional_is_sky_only(li->light)) {
- continue;
- }
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- dir.y *= rb->sdfgi->y_mult;
- dir.normalize();
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].type = RS::LIGHT_DIRECTIONAL;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
-
- idx++;
- }
-
- AABB cascade_aabb;
- cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cascade.position)) * cascade.cell_size;
- cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cascade.cell_size;
-
- for (uint32_t j = 0; j < render_state.sdfgi_update_data->positional_light_count; j++) {
- if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(render_state.sdfgi_update_data->positional_light_instances[j]);
- ERR_CONTINUE(!li);
-
- uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
- if (i > max_sdfgi_cascade) {
- continue;
- }
-
- if (!cascade_aabb.intersects(li->aabb)) {
- continue;
- }
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- //faster to not do this here
- //dir.y *= rb->sdfgi->y_mult;
- //dir.normalize();
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
- pos.y *= rb->sdfgi->y_mult;
- lights[idx].position[0] = pos.x;
- lights[idx].position[1] = pos.y;
- lights[idx].position[2] = pos.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].type = storage->light_get_type(li->light);
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
- lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
-
- if (idx > 0) {
- RD::get_singleton()->buffer_update(cascade.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights, RD::BARRIER_MASK_COMPUTE);
- }
-
- rb->sdfgi->cascade_dynamic_light_count[i] = idx;
- }
- }
-}
-
-void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) {
- RD::get_singleton()->draw_command_begin_label("GI Render");
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(rb == nullptr);
- Environment *env = environment_owner.getornull(p_environment);
-
- if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != gi.half_resolution) {
- if (rb->ambient_buffer.is_valid()) {
- RD::get_singleton()->free(rb->ambient_buffer);
- RD::get_singleton()->free(rb->reflection_buffer);
- }
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
- if (gi.half_resolution) {
- tf.width >>= 1;
- tf.height >>= 1;
- }
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->using_half_size_gi = gi.half_resolution;
-
- _render_buffers_uniform_set_changed(p_render_buffers);
- }
-
- GI::PushConstant push_constant;
-
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
- push_constant.z_near = p_projection.get_z_near();
- push_constant.z_far = p_projection.get_z_far();
- push_constant.orthogonal = p_projection.is_orthogonal();
- push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
- push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
- push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
- push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size());
- push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
-
- bool use_sdfgi = rb->sdfgi != nullptr;
- bool use_giprobes = push_constant.max_giprobes > 0;
-
- if (env) {
- push_constant.ao_color[0] = env->ao_color.r;
- push_constant.ao_color[1] = env->ao_color.g;
- push_constant.ao_color[2] = env->ao_color.b;
- } else {
- push_constant.ao_color[0] = 0;
- push_constant.ao_color[1] = 0;
- push_constant.ao_color[2] = 0;
- }
-
- push_constant.cam_rotation[0] = p_transform.basis[0][0];
- push_constant.cam_rotation[1] = p_transform.basis[1][0];
- push_constant.cam_rotation[2] = p_transform.basis[2][0];
- push_constant.cam_rotation[3] = 0;
- push_constant.cam_rotation[4] = p_transform.basis[0][1];
- push_constant.cam_rotation[5] = p_transform.basis[1][1];
- push_constant.cam_rotation[6] = p_transform.basis[2][1];
- push_constant.cam_rotation[7] = 0;
- push_constant.cam_rotation[8] = p_transform.basis[0][2];
- push_constant.cam_rotation[9] = p_transform.basis[1][2];
- push_constant.cam_rotation[10] = p_transform.basis[2][2];
- push_constant.cam_rotation[11] = 0;
-
- if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t j = 0; j < SDFGI::MAX_CASCADES; j++) {
- if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[j].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- if (rb->sdfgi) {
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 7;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
- u.ids.push_back(rb->ambient_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
- u.ids.push_back(rb->reflection_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 11;
- if (rb->sdfgi) {
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 12;
- u.ids.push_back(rb->depth_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 13;
- u.ids.push_back(p_normal_roughness_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 14;
- RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- u.ids.push_back(buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 15;
- u.ids.push_back(gi.sdfgi_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 16;
- u.ids.push_back(rb->giprobe_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 17;
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->giprobe_textures[i]);
- }
- uniforms.push_back(u);
- }
-
- rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi.shader.version_get_shader(gi.shader_version, 0), 0);
- }
-
- GI::Mode mode;
-
- if (rb->using_half_size_gi) {
- mode = (use_sdfgi && use_giprobes) ? GI::MODE_HALF_RES_COMBINED : (use_sdfgi ? GI::MODE_HALF_RES_SDFGI : GI::MODE_HALF_RES_GIPROBE);
- } else {
- mode = (use_sdfgi && use_giprobes) ? GI::MODE_COMBINED : (use_sdfgi ? GI::MODE_SDFGI : GI::MODE_GIPROBE);
- }
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi.pipelines[mode]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GI::PushConstant));
+ ERR_FAIL_COND_V(rb == nullptr, -1);
+ ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1);
- if (rb->using_half_size_gi) {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
- } else {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
- }
- //do barrier later to allow oeverlap
- //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
- RD::get_singleton()->draw_command_end_label();
+ return rb->sdfgi->get_pending_region_data(p_region, from, size, bounds);
}
-RID RendererSceneRenderRD::sky_create() {
- return sky_owner.make_rid(Sky());
+RID RendererSceneRenderRD::sky_allocate() {
+ return sky.allocate_sky_rid();
}
-
-void RendererSceneRenderRD::_sky_invalidate(Sky *p_sky) {
- if (!p_sky->dirty) {
- p_sky->dirty = true;
- p_sky->dirty_list = dirty_sky_list;
- dirty_sky_list = p_sky;
- }
+void RendererSceneRenderRD::sky_initialize(RID p_rid) {
+ sky.initialize_sky_rid(p_rid);
}
void RendererSceneRenderRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
- ERR_FAIL_COND(p_radiance_size < 32 || p_radiance_size > 2048);
- if (sky->radiance_size == p_radiance_size) {
- return;
- }
- sky->radiance_size = p_radiance_size;
-
- if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
- sky->radiance_size = 256;
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
+ sky.sky_set_radiance_size(p_sky, p_radiance_size);
}
void RendererSceneRenderRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
-
- if (sky->mode == p_mode) {
- return;
- }
-
- sky->mode = p_mode;
-
- if (sky->mode == RS::SKY_MODE_REALTIME && sky->radiance_size != 256) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
- sky_set_radiance_size(p_sky, 256);
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
+ sky.sky_set_mode(p_sky, p_mode);
}
void RendererSceneRenderRD::sky_set_material(RID p_sky, RID p_material) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
- sky->material = p_material;
- _sky_invalidate(sky);
+ sky.sky_set_material(p_sky, p_material);
}
Ref<Image> RendererSceneRenderRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, Ref<Image>());
-
- _update_dirty_skys();
-
- if (sky->radiance.is_valid()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- tf.width = p_size.width;
- tf.height = p_size.height;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
-
- RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView());
- storage->get_effects()->copy_cubemap_to_panorama(sky->radiance, rad_tex, p_size, p_bake_irradiance ? roughness_layers : 0, sky->reflection.layers.size() > 1);
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0);
- RD::get_singleton()->free(rad_tex);
-
- Ref<Image> img;
- img.instance();
- img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
- for (int i = 0; i < p_size.width; i++) {
- for (int j = 0; j < p_size.height; j++) {
- Color c = img->get_pixel(i, j);
- c.r *= p_energy;
- c.g *= p_energy;
- c.b *= p_energy;
- img->set_pixel(i, j, c);
- }
- }
- return img;
- }
-
- return Ref<Image>();
-}
-
-void RendererSceneRenderRD::_update_dirty_skys() {
- Sky *sky = dirty_sky_list;
-
- while (sky) {
- bool texture_set_dirty = false;
- //update sky configuration if texture is missing
-
- if (sky->radiance.is_null()) {
- int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
-
- uint32_t w = sky->radiance_size, h = sky->radiance_size;
- int layers = roughness_layers;
- if (sky->mode == RS::SKY_MODE_REALTIME) {
- layers = 8;
- if (roughness_layers != 8) {
- WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections");
- }
- }
-
- if (sky_use_cubemap_array) {
- //array (higher quality, 6 times more memory)
- RD::TextureFormat tf;
- tf.array_layers = layers * 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
- tf.mipmaps = mipmaps;
- tf.width = w;
- tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- _update_reflection_data(sky->reflection, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME);
-
- } else {
- //regular cubemap, lower quality (aliasing, less memory)
- RD::TextureFormat tf;
- tf.array_layers = 6;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE;
- tf.mipmaps = MIN(mipmaps, layers);
- tf.width = w;
- tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- _update_reflection_data(sky->reflection, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME);
- }
- texture_set_dirty = true;
- }
-
- // Create subpass buffers if they haven't been created already
- if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tformat.width = sky->screen_size.x / 2;
- tformat.height = sky->screen_size.y / 2;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->half_res_pass);
- sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tformat.width = sky->screen_size.x / 4;
- tformat.height = sky->screen_size.y / 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
- sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- Vector<RID> texs;
- texs.push_back(sky->quarter_res_pass);
- sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
- texture_set_dirty = true;
- }
-
- if (texture_set_dirty) {
- for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
- if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
- RD::get_singleton()->free(sky->texture_uniform_sets[i]);
- sky->texture_uniform_sets[i] = RID();
- }
- }
- }
-
- sky->reflection.dirty = true;
- sky->processing_layer = 0;
-
- Sky *next = sky->dirty_list;
- sky->dirty_list = nullptr;
- sky->dirty = false;
- sky = next;
- }
-
- dirty_sky_list = nullptr;
-}
-
-RID RendererSceneRenderRD::sky_get_radiance_texture_rd(RID p_sky) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- return sky->radiance;
-}
-
-RID RendererSceneRenderRD::sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- if (sky->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(sky->uniform_set)) {
- sky->uniform_set = RID();
- if (sky->radiance.is_valid()) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(sky->radiance);
- uniforms.push_back(u);
- }
-
- sky->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
- }
- }
-
- return sky->uniform_set;
-}
-
-RID RendererSceneRenderRD::_get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version) {
- if (p_sky->texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(p_sky->texture_uniform_sets[p_version])) {
- return p_sky->texture_uniform_sets[p_version];
- }
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- if (p_sky->radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) {
- u.ids.push_back(p_sky->radiance);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1; // half res
- if (p_sky->half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(p_sky->reflection.layers[0].views[1]);
- } else {
- u.ids.push_back(p_sky->half_res_pass);
- }
- } else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2; // quarter res
- if (p_sky->quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
- if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(p_sky->reflection.layers[0].views[2]);
- } else {
- u.ids.push_back(p_sky->quarter_res_pass);
- }
- } else {
- if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- }
- }
- uniforms.push_back(u);
- }
-
- p_sky->texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
- return p_sky->texture_uniform_sets[p_version];
+ return sky.sky_bake_panorama(p_sky, p_energy, p_bake_irradiance, p_size);
}
-RID RendererSceneRenderRD::sky_get_material(RID p_sky) const {
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
-
- return sky->material;
+RID RendererSceneRenderRD::environment_allocate() {
+ return environment_owner.allocate_rid();
}
-
-void RendererSceneRenderRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-
- RID sky_material;
-
- RS::EnvironmentBG background = environment_get_background(p_environment);
-
- if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
- sky_material = sky_get_material(environment_get_sky(p_environment));
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
- }
-
- if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
- sky_material = sky_scene_state.fog_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- SkyShaderData *shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
-
- Basis sky_transform = environment_get_sky_orientation(p_environment);
- sky_transform.invert();
-
- float multiplier = environment_get_bg_energy(p_environment);
- float custom_fov = environment_get_sky_custom_fov(p_environment);
- // Camera
- CameraMatrix camera;
-
- if (custom_fov) {
- float near_plane = p_projection.get_z_near();
- float far_plane = p_projection.get_z_far();
- float aspect = p_projection.get_aspect();
-
- camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
- } else {
- camera = p_projection;
- }
-
- sky_transform = p_transform.basis * sky_transform;
-
- if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
-
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_QUARTER_RES);
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
-
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_HALF_RES);
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
-
- RID texture_uniform_set;
- if (sky) {
- texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
- } else {
- texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
- }
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
-}
-
-void RendererSceneRenderRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-
- RID sky_material;
-
- SkyShaderData *shader_data = nullptr;
-
- RS::EnvironmentBG background = environment_get_background(p_environment);
-
- if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
- ERR_FAIL_COND(!sky);
- sky_material = sky_get_material(environment_get_sky(p_environment));
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
- }
-
- if (sky) {
- // Invalidate supbass buffers if screen size changes
- if (sky->screen_size != p_screen_size) {
- sky->screen_size = p_screen_size;
- sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
- sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
- if (shader_data->uses_half_res) {
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
- }
- _sky_invalidate(sky);
- }
- if (shader_data->uses_quarter_res) {
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
- }
- _sky_invalidate(sky);
- }
- }
-
- // Create new subpass buffers if necessary
- if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
- (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
- sky->radiance.is_null()) {
- _sky_invalidate(sky);
- _update_dirty_skys();
- }
-
- if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
- sky->prev_time = time;
- sky->reflection.dirty = true;
- RenderingServerDefault::redraw_request();
- }
-
- if (material != sky->prev_material) {
- sky->prev_material = material;
- sky->reflection.dirty = true;
- }
-
- if (material->uniform_set_updated) {
- material->uniform_set_updated = false;
- sky->reflection.dirty = true;
- }
-
- if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_transform.origin;
- sky->reflection.dirty = true;
- }
-
- if (shader_data->uses_light) {
- // Check whether the directional_light_buffer changes
- bool light_data_dirty = false;
-
- 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;
- }
- }
- 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);
-
- RendererSceneRenderRD::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;
- sky->reflection.dirty = true;
- }
- }
- }
-
- //setup fog variables
- sky_scene_state.ubo.volumetric_fog_enabled = false;
- if (p_render_buffers.is_valid()) {
- if (render_buffers_has_volumetric_fog(p_render_buffers)) {
- sky_scene_state.ubo.volumetric_fog_enabled = true;
-
- float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
- if (fog_end > 0.0) {
- sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
- } else {
- sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
- }
-
- float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
- if (fog_detail_spread > 0.0) {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
- } else {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
- }
- }
-
- RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
-
- if (fog_uniform_set != RID()) {
- sky_scene_state.fog_uniform_set = fog_uniform_set;
- } else {
- sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
- }
- }
-
- sky_scene_state.ubo.z_far = p_projection.get_z_far();
- sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
- sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
- sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment);
- Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
- float fog_energy = environment_get_fog_light_energy(p_environment);
- sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
- sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
-
- RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
-}
-
-void RendererSceneRenderRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
- ERR_FAIL_COND(!is_environment(p_environment));
-
- Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
- ERR_FAIL_COND(!sky);
-
- RID sky_material = sky_get_material(environment_get_sky(p_environment));
-
- SkyMaterialData *material = nullptr;
-
- if (sky_material.is_valid()) {
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- if (!material || !material->shader_data->valid) {
- material = nullptr;
- }
- }
-
- if (!material) {
- sky_material = sky_shader.default_material;
- material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
- }
-
- ERR_FAIL_COND(!material);
-
- SkyShaderData *shader_data = material->shader_data;
-
- ERR_FAIL_COND(!shader_data);
-
- float multiplier = environment_get_bg_energy(p_environment);
-
- bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
- RS::SkyMode sky_mode = sky->mode;
-
- if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
- if (shader_data->uses_time || shader_data->uses_position) {
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_REALTIME;
- } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
- update_single_frame = false;
- sky_mode = RS::SKY_MODE_INCREMENTAL;
- } else {
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_QUALITY;
- }
- }
-
- if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
- // On the first frame after creating sky, rebuild in single frame
- update_single_frame = true;
- sky_mode = RS::SKY_MODE_QUALITY;
- }
-
- int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size();
-
- // Update radiance cubemap
- if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
- static const Vector3 view_normals[6] = {
- Vector3(+1, 0, 0),
- Vector3(-1, 0, 0),
- Vector3(0, +1, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, +1),
- Vector3(0, 0, -1)
- };
- static const Vector3 view_up[6] = {
- Vector3(0, -1, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, +1),
- Vector3(0, 0, -1),
- Vector3(0, -1, 0),
- Vector3(0, -1, 0)
- };
-
- CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, 10.0);
- CameraMatrix correction;
- correction.set_depth_correction(true);
- cm = correction * cm;
-
- if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID cubemap_draw_list;
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
-
- Vector<Color> clear_colors;
- clear_colors.push_back(Color(0.0, 0.0, 0.0));
- RD::DrawListID cubemap_draw_list;
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- RD::DrawListID cubemap_draw_list;
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
-
- for (int i = 0; i < 6; i++) {
- Transform local_view;
- local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
- RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);
-
- cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
- RD::get_singleton()->draw_list_end();
- }
-
- if (sky_mode == RS::SKY_MODE_REALTIME) {
- _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
- }
- } else {
- if (update_single_frame) {
- for (int i = 1; i < max_processing_layer; i++) {
- _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
- }
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, 0, sky->reflection.layers.size());
- }
- } else {
- if (sky_use_cubemap_array) {
- // Multi-Frame so just update the first array level
- _update_reflection_mipmaps(sky->reflection, 0, 1);
- }
- }
- sky->processing_layer = 1;
- }
-
- sky->reflection.dirty = false;
-
- } else {
- if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
- _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, sky->processing_layer);
-
- if (sky_use_cubemap_array) {
- _update_reflection_mipmaps(sky->reflection, sky->processing_layer, sky->processing_layer + 1);
- }
-
- sky->processing_layer++;
- }
- }
-}
-
-/* SKY SHADER */
-
-void RendererSceneRenderRD::SkyShaderData::set_code(const String &p_code) {
- //compile
-
- code = p_code;
- valid = false;
- ubo_size = 0;
- uniforms.clear();
-
- if (code == String()) {
- return; //just invalid, but no error
- }
-
- ShaderCompilerRD::GeneratedCode gen_code;
- ShaderCompilerRD::IdentifierActions actions;
-
- uses_time = false;
- uses_half_res = false;
- uses_quarter_res = false;
- uses_position = false;
- uses_light = false;
-
- actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
- actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
-
- actions.usage_flag_pointers["TIME"] = &uses_time;
- actions.usage_flag_pointers["POSITION"] = &uses_position;
- actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
- actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
-
- actions.uniforms = &uniforms;
-
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- Error err = scene_singleton->sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
-
- if (version.is_null()) {
- version = scene_singleton->sky_shader.shader.version_create();
- }
-
-#if 0
- print_line("**compiling shader:");
- print_line("**defines:\n");
- for (int i = 0; i < gen_code.defines.size(); i++) {
- print_line(gen_code.defines[i]);
- }
- print_line("\n**uniforms:\n" + gen_code.uniforms);
- // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- // print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
-#endif
-
- scene_singleton->sky_shader.shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
- ERR_FAIL_COND(!scene_singleton->sky_shader.shader.version_is_valid(version));
-
- ubo_size = gen_code.uniform_total_size;
- ubo_offsets = gen_code.uniform_offsets;
- texture_uniforms = gen_code.texture_uniforms;
-
- //update pipelines
-
- for (int i = 0; i < SKY_VERSION_MAX; i++) {
- RD::PipelineDepthStencilState depth_stencil_state;
- depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
-
- RID shader_variant = scene_singleton->sky_shader.shader.version_get_shader(version, i);
- pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
- }
-
- valid = true;
-}
-
-void RendererSceneRenderRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
- if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
- } else {
- default_texture_params[p_name] = p_texture;
- }
-}
-
-void RendererSceneRenderRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
- Map<int, StringName> order;
-
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
- } else {
- order[E->get().order] = E->key();
- }
- }
-
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
- p_param_list->push_back(pi);
- }
-}
-
-void RendererSceneRenderRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
- p_param_list->push_back(p);
- }
-}
-
-bool RendererSceneRenderRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RendererSceneRenderRD::SkyShaderData::is_animated() const {
- return false;
-}
-
-bool RendererSceneRenderRD::SkyShaderData::casts_shadows() const {
- return false;
-}
-
-Variant RendererSceneRenderRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
- }
- return Variant();
-}
-
-RS::ShaderNativeSourceCode RendererSceneRenderRD::SkyShaderData::get_native_source_code() const {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- return scene_singleton->sky_shader.shader.version_get_native_source_code(version);
-}
-
-RendererSceneRenderRD::SkyShaderData::SkyShaderData() {
- valid = false;
-}
-
-RendererSceneRenderRD::SkyShaderData::~SkyShaderData() {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
- ERR_FAIL_COND(!scene_singleton);
- //pipeline variants will clear themselves if shader is gone
- if (version.is_valid()) {
- scene_singleton->sky_shader.shader.version_free(version);
- }
-}
-
-RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_sky_shader_func() {
- SkyShaderData *shader_data = memnew(SkyShaderData);
- return shader_data;
-}
-
-void RendererSceneRenderRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
-
- uniform_set_updated = true;
-
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
-}
-
-RendererSceneRenderRD::SkyMaterialData::~SkyMaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
-}
-
-RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_sky_material_func(SkyShaderData *p_shader) {
- SkyMaterialData *material_data = memnew(SkyMaterialData);
- material_data->shader_data = p_shader;
- material_data->last_frame = false;
- //update will happen later anyway so do nothing.
- return material_data;
-}
-
-RID RendererSceneRenderRD::environment_create() {
- return environment_owner.make_rid(Environment());
+void RendererSceneRenderRD::environment_initialize(RID p_rid) {
+ environment_owner.initialize_rid(p_rid, RendererSceneEnvironmentRD());
}
void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->background = p_bg;
}
void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky = p_sky;
}
void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_custom_fov = p_scale;
}
void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->sky_orientation = p_orientation;
}
void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_color = p_color;
}
void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->bg_energy = p_energy;
}
void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->canvas_max_layer = p_max_layer;
}
void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->ambient_light = p_color;
- env->ambient_source = p_ambient;
- env->ambient_light_energy = p_energy;
- env->ambient_sky_contribution = p_sky_contribution;
- env->reflection_source = p_reflection_source;
- env->ao_color = p_ao_color;
+ env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source, p_ao_color);
}
RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
return env->background;
}
RID RendererSceneRenderRD::environment_get_sky(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RID());
return env->sky;
}
float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->sky_custom_fov;
}
Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Basis());
return env->sky_orientation;
}
Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->bg_color;
}
float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->bg_energy;
}
int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->canvas_max_layer;
}
Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ambient_light;
}
RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
return env->ambient_source;
}
float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_light_energy;
}
float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->ambient_sky_contribution;
}
RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);
return env->reflection_source;
}
Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->ao_color;
}
void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->exposure = p_exposure;
- env->tone_mapper = p_tone_mapper;
- if (!env->auto_exposure && p_auto_exposure) {
- env->auto_exposure_version = ++auto_exposure_counter;
- }
- env->auto_exposure = p_auto_exposure;
- env->white = p_white;
- env->min_luminance = p_min_luminance;
- env->max_luminance = p_max_luminance;
- env->auto_exp_speed = p_auto_exp_speed;
- env->auto_exp_scale = p_auto_exp_scale;
+ env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale);
}
void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- ERR_FAIL_COND_MSG(p_levels.size() != 7, "Size of array of glow levels must be 7");
- env->glow_enabled = p_enable;
- env->glow_levels = p_levels;
- env->glow_intensity = p_intensity;
- env->glow_strength = p_strength;
- env->glow_mix = p_mix;
- env->glow_bloom = p_bloom_threshold;
- env->glow_blend_mode = p_blend_mode;
- env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold;
- env->glow_hdr_bleed_scale = p_hdr_bleed_scale;
- env->glow_hdr_luminance_cap = p_hdr_luminance_cap;
+ env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap);
}
void RendererSceneRenderRD::environment_glow_set_use_bicubic_upscale(bool p_enable) {
@@ -3073,101 +309,77 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable)
glow_high_quality = p_enable;
}
-void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
- Environment *env = environment_owner.getornull(p_env);
+void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return;
}
- env->sdfgi_enabled = p_enable;
- env->sdfgi_cascades = p_cascades;
- env->sdfgi_min_cell_size = p_min_cell_size;
- env->sdfgi_use_occlusion = p_use_occlusion;
- env->sdfgi_use_multibounce = p_use_multibounce;
- env->sdfgi_read_sky_light = p_read_sky;
- env->sdfgi_energy = p_energy;
- env->sdfgi_normal_bias = p_normal_bias;
- env->sdfgi_probe_bias = p_probe_bias;
- env->sdfgi_y_scale = p_y_scale;
+ env->set_sdfgi(p_enable, p_cascades, p_min_cell_size, p_y_scale, p_use_occlusion, p_bounce_feedback, p_read_sky, p_energy, p_normal_bias, p_probe_bias);
}
void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- env->fog_enabled = p_enable;
- env->fog_light_color = p_light_color;
- env->fog_light_energy = p_light_energy;
- env->fog_sun_scatter = p_sun_scatter;
- env->fog_density = p_density;
- env->fog_height = p_height;
- env->fog_height_density = p_height_density;
- env->fog_aerial_perspective = p_fog_aerial_perspective;
+ env->set_fog(p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_fog_aerial_perspective);
}
bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->fog_enabled;
}
Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Color());
return env->fog_light_color;
}
float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_light_energy;
}
float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_sun_scatter;
}
float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_density;
}
float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height;
}
float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_height_density;
}
float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const {
- const Environment *env = environment_owner.getornull(p_env);
+ const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0);
return env->fog_aerial_perspective;
}
void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
+ if (!is_volumetric_supported()) {
return;
}
- env->volumetric_fog_enabled = p_enable;
- env->volumetric_fog_density = p_density;
- env->volumetric_fog_light = p_light;
- env->volumetric_fog_light_energy = p_light_energy;
- env->volumetric_fog_length = p_length;
- env->volumetric_fog_detail_spread = p_detail_spread;
- env->volumetric_fog_gi_inject = p_gi_inject;
- env->volumetric_fog_temporal_reprojection = p_temporal_reprojection;
- env->volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount;
+ env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount);
}
void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) {
@@ -3180,29 +392,21 @@ void RendererSceneRenderRD::environment_set_volumetric_fog_filter_active(bool p_
}
void RendererSceneRenderRD::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) {
- sdfgi_ray_count = p_ray_count;
+ gi.sdfgi_ray_count = p_ray_count;
}
void RendererSceneRenderRD::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) {
- sdfgi_frames_to_converge = p_frames;
+ gi.sdfgi_frames_to_converge = p_frames;
}
void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) {
- sdfgi_frames_to_update_light = p_update;
+ gi.sdfgi_frames_to_update_light = p_update;
}
void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
- return;
- }
-
- env->ssr_enabled = p_enable;
- env->ssr_max_steps = p_max_steps;
- env->ssr_fade_in = p_fade_int;
- env->ssr_fade_out = p_fade_out;
- env->ssr_depth_tolerance = p_depth_tolerance;
+ env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance);
}
void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
@@ -3214,22 +418,10 @@ RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_ro
}
void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
- return;
- }
-
- env->ssao_enabled = p_enable;
- env->ssao_radius = p_radius;
- env->ssao_intensity = p_intensity;
- env->ssao_power = p_power;
- env->ssao_detail = p_detail;
- env->ssao_horizon = p_horizon;
- env->ssao_sharpness = p_sharpness;
- env->ssao_direct_light_affect = p_light_affect;
- env->ssao_ao_channel_affect = p_ao_channel_affect;
+ env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect);
}
void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
@@ -3242,30 +434,30 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual
}
bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssao_enabled;
}
float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_ao_channel_affect;
}
float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, 0.0);
return env->ssao_direct_light_affect;
}
bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->ssr_enabled;
}
bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, false);
return env->sdfgi_enabled;
}
@@ -3275,7 +467,7 @@ bool RendererSceneRenderRD::is_environment(RID p_env) const {
}
Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND_V(!env, Ref<Image>());
if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) {
@@ -3315,12 +507,16 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
RID RendererSceneRenderRD::reflection_atlas_create() {
ReflectionAtlas ra;
- ra.count = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_count");
- ra.size = GLOBAL_GET("rendering/quality/reflection_atlas/reflection_size");
+ ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
+ ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
- ra.cluster_builder = memnew(ClusterBuilderRD);
- ra.cluster_builder->set_shared(&cluster_builder_shared);
- ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+ if (is_clustered_enabled()) {
+ ra.cluster_builder = memnew(ClusterBuilderRD);
+ ra.cluster_builder->set_shared(&cluster_builder_shared);
+ ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+ } else {
+ ra.cluster_builder = nullptr;
+ }
return reflection_atlas_owner.make_rid(ra);
}
@@ -3333,7 +529,10 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
return; //no changes
}
- ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+ if (ra->cluster_builder) {
+ // only if we're using our cluster
+ ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+ }
ra->size = p_reflection_size;
ra->count = p_reflection_count;
@@ -3345,7 +544,7 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
RD::get_singleton()->free(ra->depth_buffer);
ra->depth_buffer = RID();
for (int i = 0; i < ra->reflections.size(); i++) {
- _clear_reflection_data(ra->reflections.write[i].data);
+ ra->reflections.write[i].data.clear_reflection_data();
if (ra->reflections[i].owner.is_null()) {
continue;
}
@@ -3449,7 +648,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
if (atlas->reflection.is_null()) {
- int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
+ int mipmaps = MIN(sky.roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering
{
//reflection atlas was unused, create:
@@ -3474,7 +673,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
}
atlas->reflections.resize(atlas->count);
for (int i = 0; i < atlas->count; i++) {
- _update_reflection_data(atlas->reflections.write[i].data, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS);
+ atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);
for (int j = 0; j < 6; j++) {
Vector<RID> fb;
fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
@@ -3534,7 +733,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
// Using real time reflections, all roughness is done in one step
- _create_reflection_fast_filter(atlas->reflections.write[rpi->atlas_index].data, false);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(storage, false);
rpi->rendering = false;
rpi->processing_side = 0;
rpi->processing_layer = 1;
@@ -3542,7 +741,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
}
if (rpi->processing_layer > 1) {
- _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, 10, rpi->processing_layer);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, 10, rpi->processing_layer, sky.sky_ggx_samples_quality);
rpi->processing_layer++;
if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
rpi->rendering = false;
@@ -3553,7 +752,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins
return false;
} else {
- _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, rpi->processing_side, rpi->processing_layer);
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(storage, false, rpi->processing_side, rpi->processing_layer, sky.sky_ggx_samples_quality);
}
rpi->processing_side++;
@@ -3983,8 +1182,11 @@ int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance
//////////////////////////////////////////////////
-RID RendererSceneRenderRD::camera_effects_create() {
- return camera_effects_owner.make_rid(CameraEffects());
+RID RendererSceneRenderRD::camera_effects_allocate() {
+ return camera_effects_owner.allocate_rid();
+}
+void RendererSceneRenderRD::camera_effects_initialize(RID p_rid) {
+ camera_effects_owner.initialize_rid(p_rid, CameraEffects());
}
void RendererSceneRenderRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {
@@ -4125,817 +1327,27 @@ void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, cons
/////////////////////////////////
RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) {
- GIProbeInstance gi_probe;
- gi_probe.probe = p_base;
- RID rid = gi_probe_instance_owner.make_rid(gi_probe);
- return rid;
+ return gi.gi_probe_instance_create(p_base);
}
void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->transform = p_xform;
+ gi.gi_probe_instance_set_transform_to_data(p_probe, p_xform);
}
bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
-
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return false;
}
- //return true;
- return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+ return gi.gi_probe_needs_update(p_probe);
}
void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND(!gi_probe);
-
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return;
}
- uint32_t data_version = storage->gi_probe_get_data_version(gi_probe->probe);
-
- // (RE)CREATE IF NEEDED
-
- if (gi_probe->last_probe_data_version != data_version) {
- //need to re-create everything
- if (gi_probe->texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->texture);
- RD::get_singleton()->free(gi_probe->write_buffer);
- gi_probe->mipmaps.clear();
- }
-
- for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) {
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture);
- RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
- }
-
- gi_probe->dynamic_maps.clear();
-
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- if (octree_size != Vector3i()) {
- //can create a 3D texture
- Vector<int> levels = storage->gi_probe_get_level_counts(gi_probe->probe);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tf.width = octree_size.x;
- tf.height = octree_size.y;
- tf.depth = octree_size.z;
- tf.texture_type = RD::TEXTURE_TYPE_3D;
- tf.mipmaps = levels.size();
-
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
-
- gi_probe->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, levels.size(), 0, 1);
-
- {
- int total_elements = 0;
- for (int i = 0; i < levels.size(); i++) {
- total_elements += levels[i];
- }
-
- gi_probe->write_buffer = RD::get_singleton()->storage_buffer_create(total_elements * 16);
- }
-
- for (int i = 0; i < levels.size(); i++) {
- GIProbeInstance::Mipmap mipmap;
- mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), gi_probe->texture, 0, i, RD::TEXTURE_SLICE_3D);
- mipmap.level = levels.size() - i - 1;
- mipmap.cell_offset = 0;
- for (uint32_t j = 0; j < mipmap.level; j++) {
- mipmap.cell_offset += levels[j];
- }
- mipmap.cell_count = levels[mipmap.level];
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_octree_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 2;
- u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 4;
- u.ids.push_back(gi_probe->write_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- Vector<RD::Uniform> copy_uniforms = uniforms;
- if (i == 0) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 3;
- u.ids.push_back(gi_probe_lights_uniform);
- copy_uniforms.push_back(u);
- }
-
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
-
- copy_uniforms = uniforms; //restore
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- u.ids.push_back(gi_probe->texture);
- copy_uniforms.push_back(u);
- }
- mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
- } else {
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
- }
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(mipmap.texture);
- uniforms.push_back(u);
- }
-
- mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
-
- gi_probe->mipmaps.push_back(mipmap);
- }
-
- {
- uint32_t dynamic_map_size = MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
- uint32_t oversample = nearest_power_of_2_templated(4);
- int mipmap_index = 0;
-
- while (mipmap_index < gi_probe->mipmaps.size()) {
- GIProbeInstance::DynamicMap dmap;
-
- if (oversample > 0) {
- dmap.size = dynamic_map_size * (1 << oversample);
- dmap.mipmap = -1;
- oversample--;
- } else {
- dmap.size = dynamic_map_size >> mipmap_index;
- dmap.mipmap = mipmap_index;
- mipmap_index++;
- }
-
- RD::TextureFormat dtf;
- dtf.width = dmap.size;
- dtf.height = dmap.size;
- dtf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
-
- if (gi_probe->dynamic_maps.size() == 0) {
- dtf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- }
- dmap.texture = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- if (gi_probe->dynamic_maps.size() == 0) {
- //render depth for first one
- dtf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
- dtf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- dmap.fb_depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- }
-
- //just use depth as-is
- dtf.format = RD::DATA_FORMAT_R32_SFLOAT;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- dmap.depth = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- if (gi_probe->dynamic_maps.size() == 0) {
- dtf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- dtf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
- dmap.albedo = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- dmap.normal = RD::get_singleton()->texture_create(dtf, RD::TextureView());
- dmap.orm = RD::get_singleton()->texture_create(dtf, RD::TextureView());
-
- Vector<RID> fb;
- fb.push_back(dmap.albedo);
- fb.push_back(dmap.normal);
- fb.push_back(dmap.orm);
- fb.push_back(dmap.texture); //emission
- fb.push_back(dmap.depth);
- fb.push_back(dmap.fb_depth);
-
- dmap.fb = RD::get_singleton()->framebuffer_create(fb);
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 3;
- u.ids.push_back(gi_probe_lights_uniform);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(dmap.albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(dmap.normal);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.orm);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 8;
- u.ids.push_back(dmap.fb_depth);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
- u.ids.push_back(dmap.depth);
- uniforms.push_back(u);
- }
-
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
- }
- } else {
- bool plot = dmap.mipmap >= 0;
- bool write = dmap.mipmap < (gi_probe->mipmaps.size() - 1);
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(gi_probe->dynamic_maps[gi_probe->dynamic_maps.size() - 1].depth);
- uniforms.push_back(u);
- }
-
- if (write) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(dmap.depth);
- uniforms.push_back(u);
- }
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- if (plot) {
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
- uniforms.push_back(u);
- }
- }
-
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(
- uniforms,
- giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
- 0);
- }
-
- gi_probe->dynamic_maps.push_back(dmap);
- }
- }
- }
-
- gi_probe->last_probe_data_version = data_version;
- p_update_light_instances = true; //just in case
-
- _base_uniforms_changed();
- }
-
- // UDPDATE TIME
-
- if (gi_probe->has_dynamic_object_data) {
- //if it has dynamic object data, it needs to be cleared
- RD::get_singleton()->texture_clear(gi_probe->texture, Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1);
- }
-
- uint32_t light_count = 0;
-
- if (p_update_light_instances || p_dynamic_objects.size() > 0) {
- light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());
-
- {
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gi_probe->probe);
- Transform to_probe_xform = (gi_probe->transform * to_cell.affine_inverse()).affine_inverse();
- //update lights
-
- for (uint32_t i = 0; i < light_count; i++) {
- GIProbeLight &l = gi_probe_lights[i];
- RID light_instance = p_light_instances[i];
- RID light = light_instance_get_base_light(light_instance);
-
- l.type = storage->light_get_type(light);
- if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
- light_count--;
- continue;
- }
-
- l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
- l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
- Color color = storage->light_get_color(light).to_linear();
- l.color[0] = color.r;
- l.color[1] = color.g;
- l.color[2] = color.b;
-
- l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- Transform xform = light_instance_get_base_transform(light_instance);
-
- Vector3 pos = to_probe_xform.xform(xform.origin);
- Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
-
- l.position[0] = pos.x;
- l.position[1] = pos.y;
- l.position[2] = pos.z;
-
- l.direction[0] = dir.x;
- l.direction[1] = dir.y;
- l.direction[2] = dir.z;
-
- l.has_shadow = storage->light_has_shadow(light);
- }
-
- RD::get_singleton()->buffer_update(gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi_probe_lights);
- }
- }
-
- if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) {
- // PROCESS MIPMAPS
- if (gi_probe->mipmaps.size()) {
- //can update mipmaps
-
- Vector3i probe_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- GIProbePushConstant push_constant;
-
- push_constant.limits[0] = probe_size.x;
- push_constant.limits[1] = probe_size.y;
- push_constant.limits[2] = probe_size.z;
- push_constant.stack_size = gi_probe->mipmaps.size();
- push_constant.emission_scale = 1.0;
- push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.light_count = light_count;
- push_constant.aniso_strength = 0;
-
- /* print_line("probe update to version " + itos(gi_probe->last_probe_version));
- print_line("propagation " + rtos(push_constant.propagation));
- print_line("dynrange " + rtos(push_constant.dynamic_range));
- */
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- int passes;
- if (p_update_light_instances) {
- passes = storage->gi_probe_is_using_two_bounces(gi_probe->probe) ? 2 : 1;
- } else {
- passes = 1; //only re-blitting is necessary
- }
- int wg_size = 64;
- int wg_limit_x = RD::get_singleton()->limit_get(RD::LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X);
-
- for (int pass = 0; pass < passes; pass++) {
- if (p_update_light_instances) {
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
- if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
- } else if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
- }
-
- if (pass == 1 || i > 0) {
- RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
- }
- if (pass == 0 || i > 0) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].uniform_set, 0);
- } else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].second_bounce_uniform_set, 0);
- }
-
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
-
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
- }
- }
-
- RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
- }
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
-
- for (int i = 0; i < gi_probe->mipmaps.size(); i++) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->mipmaps[i].write_uniform_set, 0);
-
- push_constant.cell_offset = gi_probe->mipmaps[i].cell_offset;
- push_constant.cell_count = gi_probe->mipmaps[i].cell_count;
-
- int wg_todo = (gi_probe->mipmaps[i].cell_count - 1) / wg_size + 1;
- while (wg_todo) {
- int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
- wg_todo -= wg_count;
- push_constant.cell_offset += wg_count * wg_size;
- }
- }
- }
-
- RD::get_singleton()->compute_list_end();
- }
- }
-
- gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again
-
- if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) {
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
- int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
-
- Transform oversample_scale;
- oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
-
- Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(gi_probe->probe);
- Transform to_world_xform = gi_probe->transform * to_cell.affine_inverse();
- Transform to_probe_xform = to_world_xform.affine_inverse();
-
- AABB probe_aabb(Vector3(), octree_size);
-
- //this could probably be better parallelized in compute..
- for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
- GeometryInstance *instance = p_dynamic_objects[i];
-
- //transform aabb to giprobe
- AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance));
-
- //this needs to wrap to grid resolution to avoid jitter
- //also extend margin a bit just in case
- Vector3i begin = aabb.position - Vector3i(1, 1, 1);
- Vector3i end = aabb.position + aabb.size + Vector3i(1, 1, 1);
-
- for (int j = 0; j < 3; j++) {
- if ((end[j] - begin[j]) & 1) {
- end[j]++; //for half extents split, it needs to be even
- }
- begin[j] = MAX(begin[j], 0);
- end[j] = MIN(end[j], octree_size[j] * multiplier);
- }
-
- //aabb = aabb.intersection(probe_aabb); //intersect
- aabb.position = begin;
- aabb.size = end - begin;
-
- //print_line("aabb: " + aabb);
-
- for (int j = 0; j < 6; j++) {
- //if (j != 0 && j != 3) {
- // continue;
- //}
- static const Vector3 render_z[6] = {
- Vector3(1, 0, 0),
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(-1, 0, 0),
- Vector3(0, -1, 0),
- Vector3(0, 0, -1),
- };
- static const Vector3 render_up[6] = {
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(0, 1, 0),
- Vector3(0, 1, 0),
- Vector3(0, 0, 1),
- Vector3(0, 1, 0),
- };
-
- Vector3 render_dir = render_z[j];
- Vector3 up_dir = render_up[j];
-
- Vector3 center = aabb.position + aabb.size * 0.5;
- Transform xform;
- xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
-
- Vector3 x_dir = xform.basis.get_axis(0).abs();
- int x_axis = int(Vector3(0, 1, 2).dot(x_dir));
- Vector3 y_dir = xform.basis.get_axis(1).abs();
- int y_axis = int(Vector3(0, 1, 2).dot(y_dir));
- Vector3 z_dir = -xform.basis.get_axis(2);
- int z_axis = int(Vector3(0, 1, 2).dot(z_dir.abs()));
-
- Rect2i rect(aabb.position[x_axis], aabb.position[y_axis], aabb.size[x_axis], aabb.size[y_axis]);
- bool x_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(0)) < 0);
- bool y_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(1)) < 0);
- bool z_flip = bool(Vector3(1, 1, 1).dot(xform.basis.get_axis(2)) > 0);
-
- CameraMatrix cm;
- cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
-
- if (cull_argument.size() == 0) {
- cull_argument.push_back(nullptr);
- }
- cull_argument[0] = instance;
-
- _render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
-
- GIProbeDynamicPushConstant push_constant;
- zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
- push_constant.limits[0] = octree_size.x;
- push_constant.limits[1] = octree_size.y;
- push_constant.limits[2] = octree_size.z;
- push_constant.light_count = p_light_instances.size();
- push_constant.x_dir[0] = x_dir[0];
- push_constant.x_dir[1] = x_dir[1];
- push_constant.x_dir[2] = x_dir[2];
- push_constant.y_dir[0] = y_dir[0];
- push_constant.y_dir[1] = y_dir[1];
- push_constant.y_dir[2] = y_dir[2];
- push_constant.z_dir[0] = z_dir[0];
- push_constant.z_dir[1] = z_dir[1];
- push_constant.z_dir[2] = z_dir[2];
- push_constant.z_base = xform.origin[z_axis];
- push_constant.z_sign = (z_flip ? -1.0 : 1.0);
- push_constant.pos_multiplier = float(1.0) / multiplier;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.flip_x = x_flip;
- push_constant.flip_y = y_flip;
- push_constant.rect_pos[0] = rect.position[0];
- push_constant.rect_pos[1] = rect.position[1];
- push_constant.rect_size[0] = rect.size[0];
- push_constant.rect_size[1] = rect.size[1];
- push_constant.prev_rect_ofs[0] = 0;
- push_constant.prev_rect_ofs[1] = 0;
- push_constant.prev_rect_size[0] = 0;
- push_constant.prev_rect_size[1] = 0;
- push_constant.on_mipmap = false;
- push_constant.propagation = storage->gi_probe_get_propagation(gi_probe->probe);
- push_constant.pad[0] = 0;
- push_constant.pad[1] = 0;
- push_constant.pad[2] = 0;
-
- //process lighting
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[0].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
- //print_line("rect: " + itos(i) + ": " + rect);
-
- for (int k = 1; k < gi_probe->dynamic_maps.size(); k++) {
- // enlarge the rect if needed so all pixels fit when downscaled,
- // this ensures downsampling is smooth and optimal because no pixels are left behind
-
- //x
- if (rect.position.x & 1) {
- rect.size.x++;
- push_constant.prev_rect_ofs[0] = 1; //this is used to ensure reading is also optimal
- } else {
- push_constant.prev_rect_ofs[0] = 0;
- }
- if (rect.size.x & 1) {
- rect.size.x++;
- }
-
- rect.position.x >>= 1;
- rect.size.x = MAX(1, rect.size.x >> 1);
-
- //y
- if (rect.position.y & 1) {
- rect.size.y++;
- push_constant.prev_rect_ofs[1] = 1;
- } else {
- push_constant.prev_rect_ofs[1] = 0;
- }
- if (rect.size.y & 1) {
- rect.size.y++;
- }
-
- rect.position.y >>= 1;
- rect.size.y = MAX(1, rect.size.y >> 1);
-
- //shrink limits to ensure plot does not go outside map
- if (gi_probe->dynamic_maps[k].mipmap > 0) {
- for (int l = 0; l < 3; l++) {
- push_constant.limits[l] = MAX(1, push_constant.limits[l] >> 1);
- }
- }
-
- //print_line("rect: " + itos(i) + ": " + rect);
- push_constant.rect_pos[0] = rect.position[0];
- push_constant.rect_pos[1] = rect.position[1];
- push_constant.prev_rect_size[0] = push_constant.rect_size[0];
- push_constant.prev_rect_size[1] = push_constant.rect_size[1];
- push_constant.rect_size[0] = rect.size[0];
- push_constant.rect_size[1] = rect.size[1];
- push_constant.on_mipmap = gi_probe->dynamic_maps[k].mipmap > 0;
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (gi_probe->dynamic_maps[k].mipmap < 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
- } else if (k < gi_probe->dynamic_maps.size() - 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
- } else {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
- }
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi_probe->dynamic_maps[k].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
- RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
- }
-
- RD::get_singleton()->compute_list_end();
- }
- }
-
- gi_probe->has_dynamic_object_data = true; //clear until dynamic object data is used again
- }
-
- gi_probe->last_probe_version = storage->gi_probe_get_version(gi_probe->probe);
-}
-
-void RendererSceneRenderRD::_debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- if (gi_probe->mipmaps.size() == 0) {
- return;
- }
-
- CameraMatrix transform = (p_camera_with_transform * CameraMatrix(gi_probe->transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(gi_probe->probe).affine_inverse());
-
- int level = 0;
- Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);
-
- GIProbeDebugPushConstant push_constant;
- push_constant.alpha = p_alpha;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(gi_probe->probe);
- push_constant.cell_offset = gi_probe->mipmaps[level].cell_offset;
- push_constant.level = level;
-
- push_constant.bounds[0] = octree_size.x >> level;
- push_constant.bounds[1] = octree_size.y >> level;
- push_constant.bounds[2] = octree_size.z >> level;
- push_constant.pad = 0;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.projection[i * 4 + j] = transform.matrix[i][j];
- }
- }
-
- if (giprobe_debug_uniform_set.is_valid()) {
- RD::get_singleton()->free(giprobe_debug_uniform_set);
- }
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_data_buffer(gi_probe->probe));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- u.ids.push_back(gi_probe->texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 3;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- int cell_count;
- if (!p_emission && p_lighting && gi_probe->has_dynamic_object_data) {
- cell_count = push_constant.bounds[0] * push_constant.bounds[1] * push_constant.bounds[2];
- } else {
- cell_count = gi_probe->mipmaps[level].cell_count;
- }
-
- giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_debug_shader_version_shaders[0], 0);
-
- int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
- if (p_emission) {
- giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
- } else if (p_lighting) {
- giprobe_debug_pipeline = gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
- }
- RD::get_singleton()->draw_list_bind_render_pipeline(
- p_draw_list,
- giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, giprobe_debug_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
+ gi.gi_probe_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
}
void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
@@ -4946,132 +1358,7 @@ void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawLi
return; //nothing to debug
}
- SDGIShader::DebugProbesPushConstant push_constant;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.projection[i * 4 + j] = p_camera_with_transform.matrix[i][j];
- }
- }
-
- //gen spheres from strips
- uint32_t band_points = 16;
- push_constant.band_power = 4;
- push_constant.sections_in_band = ((band_points / 2) - 1);
- push_constant.band_mask = band_points - 2;
- push_constant.section_arc = Math_TAU / float(push_constant.sections_in_band);
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- uint32_t total_points = push_constant.sections_in_band * band_points;
- uint32_t total_probes = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
-
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.cascade = 0;
-
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
-
- if (!rb->sdfgi->debug_probes_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_probes_uniform_set)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- uniforms.push_back(u);
- }
-
- rb->sdfgi->debug_probes_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, 0), 0);
- }
-
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_PROBES].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points);
-
- if (sdfgi_debug_probe_dir != Vector3()) {
- print_line("CLICK DEBUG ME?");
- uint32_t cascade = 0;
- Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + rb->sdfgi->cascades[cascade].position)) * rb->sdfgi->cascades[cascade].cell_size * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0);
- Vector3 probe_size = rb->sdfgi->cascades[cascade].cell_size * (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / rb->sdfgi->y_mult, 1.0);
- Vector3 ray_from = sdfgi_debug_probe_pos;
- Vector3 ray_to = sdfgi_debug_probe_pos + sdfgi_debug_probe_dir * rb->sdfgi->cascades[cascade].cell_size * Math::sqrt(3.0) * rb->sdfgi->cascade_size;
- float sphere_radius = 0.2;
- float closest_dist = 1e20;
- sdfgi_debug_probe_enabled = false;
-
- Vector3i probe_from = rb->sdfgi->cascades[cascade].position / (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR);
- for (int i = 0; i < (SDFGI::PROBE_DIVISOR + 1); i++) {
- for (int j = 0; j < (SDFGI::PROBE_DIVISOR + 1); j++) {
- for (int k = 0; k < (SDFGI::PROBE_DIVISOR + 1); k++) {
- Vector3 pos = offset + probe_size * Vector3(i, j, k);
- Vector3 res;
- if (Geometry3D::segment_intersects_sphere(ray_from, ray_to, pos, sphere_radius, &res)) {
- float d = ray_from.distance_to(res);
- if (d < closest_dist) {
- closest_dist = d;
- sdfgi_debug_probe_enabled = true;
- sdfgi_debug_probe_index = probe_from + Vector3i(i, j, k);
- }
- }
- }
- }
- }
-
- if (sdfgi_debug_probe_enabled) {
- print_line("found: " + sdfgi_debug_probe_index);
- } else {
- print_line("no found");
- }
- sdfgi_debug_probe_dir = Vector3();
- }
-
- if (sdfgi_debug_probe_enabled) {
- uint32_t cascade = 0;
- uint32_t probe_cells = (rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR);
- Vector3i probe_from = rb->sdfgi->cascades[cascade].position / probe_cells;
- Vector3i ofs = sdfgi_debug_probe_index - probe_from;
- if (ofs.x < 0 || ofs.y < 0 || ofs.z < 0) {
- return;
- }
- if (ofs.x > SDFGI::PROBE_DIVISOR || ofs.y > SDFGI::PROBE_DIVISOR || ofs.z > SDFGI::PROBE_DIVISOR) {
- return;
- }
-
- uint32_t mult = (SDFGI::PROBE_DIVISOR + 1);
- uint32_t index = ofs.z * mult * mult + ofs.y * mult + ofs.x;
-
- push_constant.probe_debug_index = index;
-
- uint32_t cell_count = probe_cells * 2 * probe_cells * 2 * probe_cells * 2;
-
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, sdfgi_shader.debug_probes_pipeline[SDGIShader::PROBE_DEBUG_VISIBILITY].get_render_pipeline(RD::INVALID_FORMAT_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, rb->sdfgi->debug_probes_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(SDGIShader::DebugProbesPushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, total_points);
- }
+ rb->sdfgi->debug_probes(p_draw_list, p_framebuffer, p_camera_with_transform);
}
////////////////////////////////
@@ -5242,7 +1529,6 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality);
@@ -5260,7 +1546,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
return;
}
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
ERR_FAIL_COND(!env->ssr_enabled);
@@ -5294,7 +1580,6 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
@@ -5305,7 +1590,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
ERR_FAIL_COND(!env);
RENDER_TIMESTAMP("Process SSAO");
@@ -5420,7 +1705,6 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final");
- _render_buffers_uniform_set_changed(p_render_buffers);
}
ssao_using_half_size = ssao_half_size;
uniform_sets_are_invalid = true;
@@ -5451,7 +1735,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
//glow (if enabled)
CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
@@ -5460,7 +1744,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
if (can_use_effects && camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0) {
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
float bokeh_size = camfx->dof_blur_amount * 64.0;
@@ -5470,7 +1753,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
if (can_use_effects && env && env->auto_exposure) {
if (rb->luminance.current.is_null()) {
_allocate_luminance_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
bool set_immediate = env->auto_exposure_version != rb->auto_exposure_version;
@@ -5491,7 +1773,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
if (rb->blur[1].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) {
@@ -5582,7 +1863,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
storage->render_target_disable_clear_request(rb->render_target);
}
-void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) {
+void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
EffectsRD *effects = storage->get_effects();
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
@@ -5641,10 +1922,17 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
RID reflection_texture = rb->reflection_buffer;
effects->copy_to_fb_rect(ambient_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture);
}
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
+ if (p_occlusion_buffer.is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+ effects->copy_to_fb_rect(storage->texture_get_rd_texture(p_occlusion_buffer), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize), true, false);
+ }
+ }
}
void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) {
- Environment *env = environment_owner.getornull(p_env);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
env->adjustments_enabled = p_enable;
@@ -5655,152 +1943,6 @@ void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable,
env->color_correction = p_color_correction;
}
-void RendererSceneRenderRD::_sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- if (!rb->sdfgi) {
- return; //eh
- }
-
- if (!rb->sdfgi->debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(rb->sdfgi->debug_uniform_set)) {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 1;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].sdf_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_0_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- for (uint32_t i = 0; i < SDFGI::MAX_CASCADES; i++) {
- if (i < rb->sdfgi->cascades.size()) {
- u.ids.push_back(rb->sdfgi->cascades[i].light_aniso_1_tex);
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
- }
- }
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 5;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->occlusion_texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 8;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb->sdfgi->cascades_ubo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 10;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.ids.push_back(rb->texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 11;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(rb->sdfgi->lightprobe_texture);
- uniforms.push_back(u);
- }
- rb->sdfgi->debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.debug_shader_version, 0);
- }
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.debug_pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->debug_uniform_set, 0);
-
- SDGIShader::DebugPushConstant push_constant;
- push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- push_constant.max_cascades = rb->sdfgi->cascades.size();
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
- push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- push_constant.use_occlusion = rb->sdfgi->uses_occlusion;
- push_constant.y_mult = rb->sdfgi->y_mult;
-
- Vector2 vp_half = p_projection.get_viewport_half_extents();
- push_constant.cam_extent[0] = vp_half.x;
- push_constant.cam_extent[1] = vp_half.y;
- push_constant.cam_extent[2] = -p_projection.get_z_near();
-
- push_constant.cam_transform[0] = p_transform.basis.elements[0][0];
- push_constant.cam_transform[1] = p_transform.basis.elements[1][0];
- push_constant.cam_transform[2] = p_transform.basis.elements[2][0];
- push_constant.cam_transform[3] = 0;
- push_constant.cam_transform[4] = p_transform.basis.elements[0][1];
- push_constant.cam_transform[5] = p_transform.basis.elements[1][1];
- push_constant.cam_transform[6] = p_transform.basis.elements[2][1];
- push_constant.cam_transform[7] = 0;
- push_constant.cam_transform[8] = p_transform.basis.elements[0][2];
- push_constant.cam_transform[9] = p_transform.basis.elements[1][2];
- push_constant.cam_transform[10] = p_transform.basis.elements[2][2];
- push_constant.cam_transform[11] = 0;
- push_constant.cam_transform[12] = p_transform.origin.x;
- push_constant.cam_transform[13] = p_transform.origin.y;
- push_constant.cam_transform[14] = p_transform.origin.z;
- push_constant.cam_transform[15] = 1;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::DebugPushConstant));
-
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
- RD::get_singleton()->compute_list_end();
-
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
- storage->get_effects()->copy_to_fb_rect(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), true);
-}
-
RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
@@ -5820,14 +1962,14 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
- if (rb->giprobe_buffer.is_null()) {
- rb->giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
+ if (rb->gi.giprobe_buffer.is_null()) {
+ rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES);
}
- return rb->giprobe_buffer;
+ return rb->gi.giprobe_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() {
- return default_giprobe_buffer;
+ return gi.default_giprobe_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) {
@@ -5876,7 +2018,7 @@ Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RI
ERR_FAIL_COND_V(!rb, Vector3i());
ERR_FAIL_COND_V(!rb->sdfgi, Vector3i());
ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i());
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
+ int32_t probe_divisor = rb->sdfgi->cascade_size / RendererSceneGIRD::SDFGI::PROBE_DIVISOR;
return rb->sdfgi->cascades[p_cascade].position / probe_divisor;
}
@@ -5978,10 +2120,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
rb->use_debanding = p_use_debanding;
- if (rb->cluster_builder == nullptr) {
- rb->cluster_builder = memnew(ClusterBuilderRD);
+
+ if (is_clustered_enabled()) {
+ if (rb->cluster_builder == nullptr) {
+ rb->cluster_builder = memnew(ClusterBuilderRD);
+ }
+ rb->cluster_builder->set_shared(&cluster_builder_shared);
}
- rb->cluster_builder->set_shared(&cluster_builder_shared);
_free_render_buffer_data(rb);
@@ -6022,9 +2167,10 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
}
rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
- _render_buffers_uniform_set_changed(p_render_buffers);
- rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ if (is_clustered_enabled()) {
+ rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ }
}
void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
@@ -6125,11 +2271,11 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q
}
int RendererSceneRenderRD::get_roughness_layers() const {
- return roughness_layers;
+ return sky.roughness_layers;
}
bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
- return sky_use_cubemap_array;
+ return sky.sky_use_cubemap_array;
}
RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) {
@@ -6172,6 +2318,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
Vector3 extents = storage->reflection_probe_get_extents(base_probe);
+ rpi->cull_mask = storage->reflection_probe_get_cull_mask(base_probe);
+
reflection_ubo.box_extents[0] = extents.x;
reflection_ubo.box_extents[1] = extents.y;
reflection_ubo.box_extents[2] = extents.z;
@@ -6200,13 +2348,15 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
Transform proj = (p_camera_inverse_transform * transform).inverse();
RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix);
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents);
+ }
rpi->last_pass = RSG::rasterizer->get_frame_number();
}
if (cluster.reflection_count) {
- RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(Cluster::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
}
}
@@ -6215,7 +2365,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
r_directional_light_count = 0;
r_positional_light_count = 0;
- sky_scene_state.ubo.directional_light_count = 0;
+ sky.sky_scene_state.ubo.directional_light_count = 0;
Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized());
@@ -6235,8 +2385,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
switch (type) {
case RS::LIGHT_DIRECTIONAL: {
// Copy to SkyDirectionalLightData
- if (r_directional_light_count < sky_scene_state.max_directional_lights) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
+ if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) {
+ RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count];
Transform light_transform = li->transform;
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
@@ -6264,7 +2414,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
angular_diameter = 0.0;
}
sky_light_data.size = angular_diameter;
- sky_scene_state.ubo.directional_light_count++;
+ sky.sky_scene_state.ubo.directional_light_count++;
}
if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) {
@@ -6590,8 +2740,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
li->light_index = index;
+ li->cull_mask = storage->light_get_cull_mask(base);
- current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+ }
r_positional_light_count++;
}
@@ -6659,6 +2812,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
DecalInstance *di = cluster.decal_sort[i].instance;
RID decal = di->decal;
+ di->render_index = i;
+ di->cull_mask = storage->decal_get_cull_mask(decal);
+
Transform xform = di->transform;
float fade = 1.0;
@@ -6763,7 +2919,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
dd.upper_fade = storage->decal_get_upper_fade(decal);
dd.lower_fade = storage->decal_get_lower_fade(decal);
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents);
+ }
}
if (cluster.decal_count > 0) {
@@ -6771,6 +2929,116 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
}
+void RendererSceneRenderRD::_fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words) {
+ // first zero out our indices
+ for (uint32_t i = 0; i < p_max_dst_words; i++) {
+ p_omni_light_indices[i] = 0;
+ p_spot_light_indices[i] = 0;
+ p_reflection_probe_indices[i] = 0;
+ p_decal_instance_indices[i] = 0;
+ }
+
+ {
+ // process omni lights
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_omni_light_instance_count && dword < p_max_dst_words; i++) {
+ LightInstance *li = light_instance_owner.getornull(p_omni_light_instances[i]);
+
+ if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
+ p_omni_light_indices[dword] += li->light_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_omni_light_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process spot lights
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_spot_light_instance_count && dword < p_max_dst_words; i++) {
+ LightInstance *li = light_instance_owner.getornull(p_spot_light_instances[i]);
+
+ if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
+ p_spot_light_indices[dword] += li->light_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_spot_light_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process reflection probes
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_reflection_probe_instance_count && dword < p_max_dst_words; i++) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_instances[i]);
+
+ if ((rpi->cull_mask & p_layer_mask) && (rpi->render_index < 255)) {
+ p_reflection_probe_indices[dword] += rpi->render_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_reflection_probe_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process decals
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_decal_instance_count && dword < p_max_dst_words; i++) {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal_instances[i]);
+
+ if ((decal->cull_mask & p_layer_mask) && (decal->render_index < 255)) {
+ p_decal_instance_indices[dword] += decal->render_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_decal_instance_indices[dword] += 0xFF << shift;
+ }
+ }
+}
+
void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->volumetric_fog);
@@ -6797,9 +3065,10 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
}
void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+ ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
- Environment *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
float ratio = float(rb->width) / float((rb->width + rb->height) / 2);
uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
@@ -6809,7 +3078,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
//validate
if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) {
_volumetric_fog_erase(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
}
@@ -6845,7 +3113,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
- _render_buffers_uniform_set_changed(p_render_buffers);
Vector<RD::Uniform> uniforms;
{
@@ -6856,7 +3123,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
uniforms.push_back(u);
}
- rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG);
}
//update volumetric fog
@@ -6967,8 +3234,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 12;
- for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->giprobe_textures[i]);
+ for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) {
+ u.ids.push_back(rb->gi.giprobe_textures[i]);
}
uniforms.push_back(u);
}
@@ -7207,7 +3474,14 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) {
void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) {
if (render_state.render_buffers.is_valid()) {
if (p_use_gi) {
- _sdfgi_update_probes(render_state.render_buffers, render_state.environment);
+ RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+ if (rb->sdfgi == nullptr) {
+ return;
+ }
+
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(render_state.environment);
+ rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky));
}
}
}
@@ -7224,7 +3498,13 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
if (render_state.render_buffers.is_valid() && p_use_gi) {
- _sdfgi_store_probes(render_state.render_buffers);
+ RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ ERR_FAIL_COND(rb == nullptr);
+ if (rb->sdfgi == nullptr) {
+ return;
+ }
+
+ rb->sdfgi->store_probes();
}
render_state.cube_shadows.clear();
@@ -7291,7 +3571,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
//start GI
if (render_gi) {
- _process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes);
+ gi.process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes, this);
}
//Do shadow rendering (in parallel with GI)
@@ -7346,11 +3626,20 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
break;
}
}
- _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ if (is_volumetric_supported()) {
+ _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ }
}
}
-void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) {
+void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) {
+ // getting this here now so we can direct call a bunch of things more easily
+ RenderBuffers *rb = nullptr;
+ if (p_render_buffers.is_valid()) {
+ rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+ }
+
//assign render data
{
render_state.render_buffers = p_render_buffers;
@@ -7387,34 +3676,34 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
}
//sdfgi first
- if (p_render_buffers.is_valid()) {
+ if (rb != nullptr && rb->sdfgi != nullptr) {
for (int i = 0; i < render_state.render_sdfgi_region_count; i++) {
- _render_sdfgi_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances);
+ rb->sdfgi->render_region(p_render_buffers, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this);
}
if (render_state.sdfgi_update_data->update_static) {
- _render_sdfgi_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights);
+ rb->sdfgi->render_static_lights(p_render_buffers, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);
}
}
Color clear_color;
if (p_render_buffers.is_valid()) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
clear_color = storage->render_target_get_clear_request_color(rb->render_target);
} else {
clear_color = storage->get_default_clear_color();
}
//assign render indices to giprobes
- for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) {
- GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[i]);
- if (giprobe_inst) {
- giprobe_inst->render_index = i;
+ if (is_dynamic_gi_supported()) {
+ for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) {
+ RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]);
+ if (giprobe_inst) {
+ giprobe_inst->render_index = i;
+ }
}
}
if (render_buffers_owner.owns(render_state.render_buffers)) {
- RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ // render_state.render_buffers == p_render_buffers so we can use our already retrieved rb
current_cluster_builder = rb->cluster_builder;
} else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);
@@ -7426,23 +3715,30 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
current_cluster_builder = ra->cluster_builder;
}
} else {
- ERR_PRINT("No cluster builder, bug"); //should never happen, will crash
+ ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
current_cluster_builder = nullptr;
}
- if (p_render_buffers.is_valid()) {
- _pre_process_gi(p_render_buffers, p_cam_transform);
+ if (rb != nullptr && rb->sdfgi != nullptr) {
+ rb->sdfgi->update_cascades();
+
+ rb->sdfgi->pre_process_gi(p_cam_transform, this);
}
render_state.gi_probe_count = 0;
- if (render_state.render_buffers.is_valid()) {
- _setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count);
- _sdfgi_update_light(render_state.render_buffers, render_state.environment);
+ if (rb != nullptr && rb->sdfgi != nullptr) {
+ gi.setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count, this);
+
+ rb->sdfgi->update_light();
}
render_state.depth_prepass_used = false;
//calls _pre_opaque_render between depth pre-pass and opaque pass
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);
+ if (current_cluster_builder != nullptr) {
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);
+ } else {
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, RID(), 0, 0, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);
+ }
if (p_render_buffers.is_valid()) {
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
@@ -7463,15 +3759,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
default: {
}
}
- current_cluster_builder->debug(elem_type);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->debug(elem_type);
+ }
}
RENDER_TIMESTAMP("Tonemap");
_render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection);
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas);
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI) {
- _sdfgi_debug_draw(p_render_buffers, p_cam_projection, p_cam_transform);
+ _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
+ rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
}
}
}
@@ -7651,366 +3949,6 @@ void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, co
_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);
}
-void RendererSceneRenderRD::_render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances) {
- //print_line("rendering region " + itos(p_region));
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
- ERR_FAIL_COND(!rb->sdfgi);
- AABB bounds;
- Vector3i from;
- Vector3i size;
-
- int cascade_prev = _sdfgi_get_pending_region_data(p_render_buffers, p_region - 1, from, size, bounds);
- int cascade_next = _sdfgi_get_pending_region_data(p_render_buffers, p_region + 1, from, size, bounds);
- int cascade = _sdfgi_get_pending_region_data(p_render_buffers, p_region, from, size, bounds);
- ERR_FAIL_COND(cascade < 0);
-
- if (cascade_prev != cascade) {
- //initialize render
- RD::get_singleton()->texture_clear(rb->sdfgi->render_albedo, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_emission, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_emission_aniso, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->render_geom_facing, Color(0, 0, 0, 0), 0, 1, 0, 1);
- }
-
- //print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size));
- _render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing);
-
- if (cascade_next != cascade) {
- RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
-
- RENDER_TIMESTAMP(">SDFGI Update SDF");
- //done rendering! must update SDF
- //clear dispatch indirect data
-
- SDGIShader::PreprocessPushConstant push_constant;
- zeromem(&push_constant, sizeof(SDGIShader::PreprocessPushConstant));
-
- RENDER_TIMESTAMP("Scroll SDF");
-
- //scroll
- if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- //for scroll
- Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions;
- push_constant.scroll[0] = dirty.x;
- push_constant.scroll[1] = dirty.y;
- push_constant.scroll[2] = dirty.z;
- } else {
- //for no scroll
- push_constant.scroll[0] = 0;
- push_constant.scroll[1] = 0;
- push_constant.scroll[2] = 0;
- }
-
- rb->sdfgi->cascades[cascade].all_dynamic_lights_dirty = true;
-
- push_constant.grid_size = rb->sdfgi->cascade_size;
- push_constant.cascade = cascade;
-
- if (rb->sdfgi->cascades[cascade].dirty_regions != SDFGI::Cascade::DIRTY_ALL) {
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- //must pre scroll existing data because not all is dirty
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_uniform_set, 0);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0);
- // no barrier do all together
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].scroll_occlusion_uniform_set, 0);
-
- Vector3i dirty = rb->sdfgi->cascades[cascade].dirty_regions;
- Vector3i groups;
- groups.x = rb->sdfgi->cascade_size - ABS(dirty.x);
- groups.y = rb->sdfgi->cascade_size - ABS(dirty.y);
- groups.z = rb->sdfgi->cascade_size - ABS(dirty.z);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, groups.x, groups.y, groups.z);
-
- //no barrier, continue together
-
- {
- //scroll probes and their history also
-
- SDGIShader::IntegratePushConstant ipush_constant;
- ipush_constant.grid_size[1] = rb->sdfgi->cascade_size;
- ipush_constant.grid_size[2] = rb->sdfgi->cascade_size;
- ipush_constant.grid_size[0] = rb->sdfgi->cascade_size;
- ipush_constant.max_cascades = rb->sdfgi->cascades.size();
- ipush_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- ipush_constant.history_index = 0;
- ipush_constant.history_size = rb->sdfgi->history_size;
- ipush_constant.ray_count = 0;
- ipush_constant.ray_bias = 0;
- ipush_constant.sky_mode = 0;
- ipush_constant.sky_energy = 0;
- ipush_constant.sky_color[0] = 0;
- ipush_constant.sky_color[1] = 0;
- ipush_constant.sky_color[2] = 0;
- ipush_constant.y_mult = rb->sdfgi->y_mult;
- ipush_constant.store_ambient_texture = false;
-
- ipush_constant.image_size[0] = rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count;
- ipush_constant.image_size[1] = rb->sdfgi->probe_axis_count;
-
- int32_t probe_divisor = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- ipush_constant.cascade = cascade;
- ipush_constant.world_offset[0] = rb->sdfgi->cascades[cascade].position.x / probe_divisor;
- ipush_constant.world_offset[1] = rb->sdfgi->cascades[cascade].position.y / probe_divisor;
- ipush_constant.world_offset[2] = rb->sdfgi->cascades[cascade].position.z / probe_divisor;
-
- ipush_constant.scroll[0] = dirty.x / probe_divisor;
- ipush_constant.scroll[1] = dirty.y / probe_divisor;
- ipush_constant.scroll[2] = dirty.z / probe_divisor;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_SCROLL_STORE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count, rb->sdfgi->probe_axis_count, 1);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (rb->sdfgi->uses_multibounce) {
- //multibounce requires this to be stored so direct light can read from it
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.integrate_pipeline[SDGIShader::INTEGRATE_MODE_STORE]);
-
- //convert to octahedral to store
- ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
- ipush_constant.image_size[1] *= SDFGI::LIGHTPROBE_OCT_SIZE;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].integrate_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdfgi_shader.integrate_default_sky_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDGIShader::IntegratePushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->probe_axis_count * rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, rb->sdfgi->probe_axis_count * SDFGI::LIGHTPROBE_OCT_SIZE, 1);
- }
- }
-
- //ok finally barrier
- RD::get_singleton()->compute_list_end();
- }
-
- //clear dispatch indirect data
- uint32_t dispatch_indirct_data[4] = { 0, 0, 0, 0 };
- RD::get_singleton()->buffer_update(rb->sdfgi->cascades[cascade].solid_cell_dispatch_buffer, 0, sizeof(uint32_t) * 4, dispatch_indirct_data);
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- bool half_size = true; //much faster, very little difference
- static const int optimized_jf_group_size = 8;
-
- if (half_size) {
- push_constant.grid_size >>= 1;
-
- uint32_t cascade_half_size = rb->sdfgi->cascade_size >> 1;
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_half_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //must start with regular jumpflood
-
- push_constant.half_size = true;
- {
- RENDER_TIMESTAMP("SDFGI Jump Flood (Half Size)");
-
- uint32_t s = cascade_half_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]);
-
- int jf_us = 0;
- //start with regular jump flood for very coarse reads, as this is impossible to optimize
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
-
- if (cascade_half_size / (s / 2) >= optimized_jf_group_size) {
- break;
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half Size)");
-
- //continue with optimized jump flood for smaller reads
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_half_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
- }
- }
-
- // restore grid size for last passes
- push_constant.grid_size = rb->sdfgi->cascade_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_upscale_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //run one pass of fullsize jumpflood to fix up half size arctifacts
-
- push_constant.half_size = false;
- push_constant.step_size = 1;
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[rb->sdfgi->upscale_jfa_uniform_set_index], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- } else {
- //full size jumpflood
- RENDER_TIMESTAMP("SDFGI Jump Flood");
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->sdf_initialize_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- push_constant.half_size = false;
- {
- uint32_t s = rb->sdfgi->cascade_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD]);
-
- int jf_us = 0;
- //start with regular jump flood for very coarse reads, as this is impossible to optimize
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
-
- if (rb->sdfgi->cascade_size / (s / 2) >= optimized_jf_group_size) {
- break;
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Jump Flood Optimized");
-
- //continue with optimized jump flood for smaller reads
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
- while (s > 1) {
- s /= 2;
- push_constant.step_size = s;
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->jump_flood_uniform_set[jf_us], 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- jf_us = jf_us == 0 ? 1 : 0;
- }
- }
- }
-
- RENDER_TIMESTAMP("SDFGI Occlusion");
-
- // occlusion
- {
- uint32_t probe_size = rb->sdfgi->cascade_size / SDFGI::PROBE_DIVISOR;
- Vector3i probe_global_pos = rb->sdfgi->cascades[cascade].position / probe_size;
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_OCCLUSION]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->occlusion_uniform_set, 0);
- for (int i = 0; i < 8; i++) {
- //dispatch all at once for performance
- Vector3i offset(i & 1, (i >> 1) & 1, (i >> 2) & 1);
-
- if ((probe_global_pos.x & 1) != 0) {
- offset.x = (offset.x + 1) & 1;
- }
- if ((probe_global_pos.y & 1) != 0) {
- offset.y = (offset.y + 1) & 1;
- }
- if ((probe_global_pos.z & 1) != 0) {
- offset.z = (offset.z + 1) & 1;
- }
- push_constant.probe_offset[0] = offset.x;
- push_constant.probe_offset[1] = offset.y;
- push_constant.probe_offset[2] = offset.z;
- push_constant.occlusion_index = i;
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
-
- Vector3i groups = Vector3i(probe_size + 1, probe_size + 1, probe_size + 1) - offset; //if offset, it's one less probe per axis to compute
- RD::get_singleton()->compute_list_dispatch(compute_list, groups.x, groups.y, groups.z);
- }
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- }
-
- RENDER_TIMESTAMP("SDFGI Store");
-
- // store
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.preprocess_pipeline[SDGIShader::PRE_PROCESS_STORE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->sdfgi->cascades[cascade].sdf_store_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDGIShader::PreprocessPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, rb->sdfgi->cascade_size);
-
- RD::get_singleton()->compute_list_end();
-
- //clear these textures, as they will have previous garbage on next draw
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_0_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
- RD::get_singleton()->texture_clear(rb->sdfgi->cascades[cascade].light_aniso_1_tex, Color(0, 0, 0, 0), 0, 1, 0, 1);
-
-#if 0
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->cascades[cascade].sdf, 0);
- Ref<Image> img;
- img.instance();
- for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) {
- Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1);
- img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_L8, subarr);
- img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png");
- }
-
- //finalize render and update sdf
-#endif
-
-#if 0
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rb->sdfgi->render_albedo, 0);
- Ref<Image> img;
- img.instance();
- for (uint32_t i = 0; i < rb->sdfgi->cascade_size; i++) {
- Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1);
- img->create(rb->sdfgi->cascade_size, rb->sdfgi->cascade_size, false, Image::FORMAT_RGB565, subarr);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png");
- }
-
- //finalize render and update sdf
-#endif
-
- RENDER_TIMESTAMP("<SDFGI Update SDF");
- RD::get_singleton()->draw_command_end_label();
- }
-}
-
void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));
Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
@@ -8028,132 +3966,15 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
_render_particle_collider_heightfield(fb, cam_xform, cm, p_instances);
}
-void RendererSceneRenderRD::_render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
- ERR_FAIL_COND(!rb->sdfgi);
-
- RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs");
-
- _sdfgi_update_cascades(p_render_buffers); //need cascades updated for this
-
- SDGIShader::Light lights[SDFGI::MAX_STATIC_LIGHTS];
- uint32_t light_count[SDFGI::MAX_STATIC_LIGHTS];
-
- for (uint32_t i = 0; i < p_cascade_count; i++) {
- ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size());
-
- SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]];
-
- { //fill light buffer
-
- AABB cascade_aabb;
- cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(rb->sdfgi->cascade_size >> 1) + cc.position)) * cc.cell_size;
- cascade_aabb.size = Vector3(1, 1, 1) * rb->sdfgi->cascade_size * cc.cell_size;
-
- int idx = 0;
-
- for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) {
- if (idx == SDFGI::MAX_STATIC_LIGHTS) {
- break;
- }
-
- LightInstance *li = light_instance_owner.getornull(p_positional_light_cull_result[i][j]);
- ERR_CONTINUE(!li);
-
- uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light);
- if (p_cascade_indices[i] > max_sdfgi_cascade) {
- continue;
- }
-
- if (!cascade_aabb.intersects(li->aabb)) {
- continue;
- }
-
- lights[idx].type = storage->light_get_type(li->light);
-
- Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
- if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
- dir.y *= rb->sdfgi->y_mult; //only makes sense for directional
- dir.normalize();
- }
- lights[idx].direction[0] = dir.x;
- lights[idx].direction[1] = dir.y;
- lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
- pos.y *= rb->sdfgi->y_mult;
- lights[idx].position[0] = pos.x;
- lights[idx].position[1] = pos.y;
- lights[idx].position[2] = pos.z;
- Color color = storage->light_get_color(li->light);
- color = color.to_linear();
- lights[idx].color[0] = color.r;
- lights[idx].color[1] = color.g;
- lights[idx].color[2] = color.b;
- lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY);
- lights[idx].has_shadow = storage->light_has_shadow(li->light);
- lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
-
- if (idx > 0) {
- RD::get_singleton()->buffer_update(cc.lights_buffer, 0, idx * sizeof(SDGIShader::Light), lights);
- }
-
- light_count[i] = idx;
- }
- }
-
- /* Static Lights */
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sdfgi_shader.direct_light_pipeline[SDGIShader::DIRECT_LIGHT_MODE_STATIC]);
-
- SDGIShader::DirectLightPushConstant dl_push_constant;
-
- dl_push_constant.grid_size[0] = rb->sdfgi->cascade_size;
- dl_push_constant.grid_size[1] = rb->sdfgi->cascade_size;
- dl_push_constant.grid_size[2] = rb->sdfgi->cascade_size;
- dl_push_constant.max_cascades = rb->sdfgi->cascades.size();
- dl_push_constant.probe_axis_size = rb->sdfgi->probe_axis_count;
- dl_push_constant.multibounce = false; // this is static light, do not multibounce yet
- dl_push_constant.y_mult = rb->sdfgi->y_mult;
-
- //all must be processed
- dl_push_constant.process_offset = 0;
- dl_push_constant.process_increment = 1;
-
- for (uint32_t i = 0; i < p_cascade_count; i++) {
- ERR_CONTINUE(p_cascade_indices[i] >= rb->sdfgi->cascades.size());
-
- SDFGI::Cascade &cc = rb->sdfgi->cascades[p_cascade_indices[i]];
-
- dl_push_constant.light_count = light_count[i];
- dl_push_constant.cascade = p_cascade_indices[i];
-
- if (dl_push_constant.light_count > 0) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cc.sdf_direct_light_uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &dl_push_constant, sizeof(SDGIShader::DirectLightPushConstant));
- RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cc.solid_cell_dispatch_buffer, 0);
- }
- }
-
- RD::get_singleton()->compute_list_end();
-
- RD::get_singleton()->draw_command_end_label();
-}
-
bool RendererSceneRenderRD::free(RID p_rid) {
if (render_buffers_owner.owns(p_rid)) {
RenderBuffers *rb = render_buffers_owner.getornull(p_rid);
_free_render_buffer_data(rb);
memdelete(rb->data);
if (rb->sdfgi) {
- _sdfgi_erase(rb);
+ rb->sdfgi->erase();
+ memdelete(rb->sdfgi);
+ rb->sdfgi = nullptr;
}
if (rb->volumetric_fog) {
_volumetric_fog_erase(rb);
@@ -8184,8 +4005,8 @@ bool RendererSceneRenderRD::free(RID p_rid) {
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
- } else if (gi_probe_instance_owner.owns(p_rid)) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid);
+ } else if (gi.gi_probe_instance_owner.owns(p_rid)) {
+ RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid);
if (gi_probe->texture.is_valid()) {
RD::get_singleton()->free(gi_probe->texture);
RD::get_singleton()->free(gi_probe->write_buffer);
@@ -8196,37 +4017,10 @@ bool RendererSceneRenderRD::free(RID p_rid) {
RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth);
}
- gi_probe_instance_owner.free(p_rid);
- } else if (sky_owner.owns(p_rid)) {
- _update_dirty_skys();
- Sky *sky = sky_owner.getornull(p_rid);
-
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
-
- if (sky->uniform_buffer.is_valid()) {
- RD::get_singleton()->free(sky->uniform_buffer);
- sky->uniform_buffer = RID();
- }
-
- if (sky->half_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->half_res_pass);
- sky->half_res_pass = RID();
- }
-
- if (sky->quarter_res_pass.is_valid()) {
- RD::get_singleton()->free(sky->quarter_res_pass);
- sky->quarter_res_pass = RID();
- }
-
- if (sky->material.is_valid()) {
- storage->free(sky->material);
- }
-
- sky_owner.free(p_rid);
+ gi.gi_probe_instance_owner.free(p_rid);
+ } else if (sky.sky_owner.owns(p_rid)) {
+ sky.update_dirty_skys();
+ sky.free_sky(p_rid);
} else if (light_instance_owner.owns(p_rid)) {
LightInstance *light_instance = light_instance_owner.getornull(p_rid);
@@ -8260,7 +4054,7 @@ void RendererSceneRenderRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_dr
}
void RendererSceneRenderRD::update() {
- _update_dirty_skys();
+ sky.update_dirty_skys();
}
void RendererSceneRenderRD::set_time(double p_time, double p_step) {
@@ -8386,8 +4180,8 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto
}
void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) {
- sdfgi_debug_probe_pos = p_position;
- sdfgi_debug_probe_dir = p_dir;
+ gi.sdfgi_debug_probe_pos = p_position;
+ gi.sdfgi_debug_probe_dir = p_dir;
}
RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr;
@@ -8413,409 +4207,42 @@ int RendererSceneRenderRD::get_max_directional_lights() const {
return cluster.max_directional_lights;
}
-bool RendererSceneRenderRD::is_low_end() const {
- return low_end;
+bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
+ // usable by default (unless low end = true)
+ return true;
}
-RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
- max_cluster_elements = GLOBAL_GET("rendering/cluster_builder/max_clustered_elements");
-
- storage = p_storage;
- singleton = this;
-
- roughness_layers = GLOBAL_GET("rendering/quality/reflections/roughness_layers");
- sky_ggx_samples_quality = GLOBAL_GET("rendering/quality/reflections/ggx_samples");
- sky_use_cubemap_array = GLOBAL_GET("rendering/quality/reflections/texture_array_reflections");
-
- sdfgi_ray_count = RS::EnvironmentSDFGIRayCount(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/probe_ray_count")), 0, int32_t(RS::ENV_SDFGI_RAY_COUNT_MAX - 1)));
- sdfgi_frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_converge")), 0, int32_t(RS::ENV_SDFGI_CONVERGE_MAX - 1)));
- sdfgi_frames_to_update_light = RS::EnvironmentSDFGIFramesToUpdateLight(CLAMP(int32_t(GLOBAL_GET("rendering/sdfgi/frames_to_update_lights")), 0, int32_t(RS::ENV_SDFGI_UPDATE_LIGHT_MAX - 1)));
-
- directional_shadow.size = GLOBAL_GET("rendering/quality/directional_shadow/size");
- directional_shadow.use_16_bits = GLOBAL_GET("rendering/quality/directional_shadow/16_bits");
-
- uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
-
- low_end = GLOBAL_GET("rendering/quality/rd_renderer/use_low_end_renderer");
-
- if (textures_per_stage < 48) {
- low_end = true;
- }
-
- if (!low_end) {
- //kinda complicated to compute the amount of slots, we try to use as many as we can
-
- gi_probe_max_lights = 32;
-
- gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
- gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
- gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/quality/gi_probes/quality")), 0, 1));
-
- String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
-
- Vector<String> versions;
- versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
- versions.push_back("\n#define MODE_SECOND_BOUNCE\n");
- versions.push_back("\n#define MODE_UPDATE_MIPMAPS\n");
- versions.push_back("\n#define MODE_WRITE_TEXTURE\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_LIGHTING\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n");
- versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n");
+bool RendererSceneRenderRD::is_clustered_enabled() const {
+ // used by default.
+ return true;
+}
- giprobe_shader.initialize(versions, defines);
- giprobe_lighting_shader_version = giprobe_shader.version_create();
- for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) {
- giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i);
- giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]);
- }
- }
+bool RendererSceneRenderRD::is_volumetric_supported() const {
+ // usable by default (unless low end = true)
+ return true;
+}
- if (!low_end) {
- String defines;
- Vector<String> versions;
- versions.push_back("\n#define MODE_DEBUG_COLOR\n");
- versions.push_back("\n#define MODE_DEBUG_LIGHT\n");
- versions.push_back("\n#define MODE_DEBUG_EMISSION\n");
- versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n");
+uint32_t RendererSceneRenderRD::get_max_elements() const {
+ return GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements");
+}
- giprobe_debug_shader.initialize(versions, defines);
- giprobe_debug_shader_version = giprobe_debug_shader.version_create();
- for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) {
- giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i);
+RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
+ max_cluster_elements = get_max_elements();
- RD::PipelineRasterizationState rs;
- rs.cull_mode = RD::POLYGON_CULL_FRONT;
- RD::PipelineDepthStencilState ds;
- ds.enable_depth_test = true;
- ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ storage = p_storage;
+ singleton = this;
- giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
+ directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
+ directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
/* SKY SHADER */
- {
- // Start with the directional lights for the sky
- sky_scene_state.max_directional_lights = 4;
- uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData);
- sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
- sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
- sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1;
- 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";
-
- // Initialize sky
- Vector<String> sky_modes;
- sky_modes.push_back(""); // Full size
- sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res
- sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap
- sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap
- sky_shader.shader.initialize(sky_modes, defines);
- }
-
- // register our shader funds
- storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
- storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs);
-
- {
- ShaderCompilerRD::DefaultIdentifierActions actions;
-
- actions.renames["COLOR"] = "color";
- actions.renames["ALPHA"] = "alpha";
- actions.renames["EYEDIR"] = "cube_normal";
- actions.renames["POSITION"] = "params.position_multiplier.xyz";
- actions.renames["SKY_COORDS"] = "panorama_coords";
- actions.renames["SCREEN_UV"] = "uv";
- actions.renames["TIME"] = "params.time";
- actions.renames["HALF_RES_COLOR"] = "half_res_color";
- actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
- actions.renames["RADIANCE"] = "radiance";
- actions.renames["FOG"] = "custom_fog";
- actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
- actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
- actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
- actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
- actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
- actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
- actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
- actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
- actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
- actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
- actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
- actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
- actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
- actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
- actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
- actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
- actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
- actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
- actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
- actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
- 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.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.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = 1;
- actions.base_uniform_string = "material.";
- actions.base_varying_index = 10;
-
- actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
- actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.global_buffer_array_variable = "global_variables.data";
-
- sky_shader.compiler.initialize(actions);
- }
-
- {
- // default material and shader for sky shader
- sky_shader.default_shader = storage->shader_create();
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n");
- sky_shader.default_material = storage->material_create();
- storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
-
- SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
- sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
-
- sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 0;
- u.ids.resize(12);
- RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(storage->global_variables_get_storage_buffer());
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 2;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.uniform_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 3;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(sky_scene_state.directional_light_buffer);
- uniforms.push_back(u);
- }
-
- sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
- }
-
- {
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 0;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- u.ids.push_back(vfog);
- uniforms.push_back(u);
- }
-
- sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
- }
-
- {
- // Need defaults for using fog with clear color
- sky_scene_state.fog_shader = storage->shader_create();
- storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n");
- sky_scene_state.fog_material = storage->material_create();
- storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- uniforms.push_back(u);
- }
-
- sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
- }
-
- if (!low_end) {
- //SDFGI
- {
- Vector<String> preprocess_modes;
- preprocess_modes.push_back("\n#define MODE_SCROLL\n");
- preprocess_modes.push_back("\n#define MODE_SCROLL_OCCLUSION\n");
- preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD\n");
- preprocess_modes.push_back("\n#define MODE_INITIALIZE_JUMP_FLOOD_HALF\n");
- preprocess_modes.push_back("\n#define MODE_JUMPFLOOD\n");
- preprocess_modes.push_back("\n#define MODE_JUMPFLOOD_OPTIMIZED\n");
- preprocess_modes.push_back("\n#define MODE_UPSCALE_JUMP_FLOOD\n");
- preprocess_modes.push_back("\n#define MODE_OCCLUSION\n");
- preprocess_modes.push_back("\n#define MODE_STORE\n");
- String defines = "\n#define OCCLUSION_SIZE " + itos(SDFGI::CASCADE_SIZE / SDFGI::PROBE_DIVISOR) + "\n";
- sdfgi_shader.preprocess.initialize(preprocess_modes, defines);
- sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create();
- for (int i = 0; i < SDGIShader::PRE_PROCESS_MAX; i++) {
- sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
- }
- }
-
- {
- //calculate tables
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
-
- Vector<String> direct_light_modes;
- direct_light_modes.push_back("\n#define MODE_PROCESS_STATIC\n");
- direct_light_modes.push_back("\n#define MODE_PROCESS_DYNAMIC\n");
- sdfgi_shader.direct_light.initialize(direct_light_modes, defines);
- sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create();
- for (int i = 0; i < SDGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
- sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
- }
- }
-
- {
- //calculate tables
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- defines += "\n#define SH_SIZE " + itos(SDFGI::SH_SIZE) + "\n";
- if (sky_use_cubemap_array) {
- defines += "\n#define USE_CUBEMAP_ARRAY\n";
- }
-
- Vector<String> integrate_modes;
- integrate_modes.push_back("\n#define MODE_PROCESS\n");
- integrate_modes.push_back("\n#define MODE_STORE\n");
- integrate_modes.push_back("\n#define MODE_SCROLL\n");
- integrate_modes.push_back("\n#define MODE_SCROLL_STORE\n");
- sdfgi_shader.integrate.initialize(integrate_modes, defines);
- sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create();
-
- for (int i = 0; i < SDGIShader::INTEGRATE_MODE_MAX; i++) {
- sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
- }
-
- {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 1;
- u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- sdfgi_shader.integrate_default_sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, 0), 1);
- }
- }
- //GK
- {
- //calculate tables
- String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- Vector<String> gi_modes;
- gi_modes.push_back("\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
-
- gi.shader.initialize(gi_modes, defines);
- gi.shader_version = gi.shader.version_create();
- for (int i = 0; i < GI::MODE_MAX; i++) {
- gi.pipelines[i] = RD::get_singleton()->compute_pipeline_create(gi.shader.version_get_shader(gi.shader_version, i));
- }
-
- gi.sdfgi_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(GI::SDFGIData));
- }
- {
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
- Vector<String> debug_modes;
- debug_modes.push_back("");
- sdfgi_shader.debug.initialize(debug_modes, defines);
- sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create();
- sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0);
- sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version);
- }
- {
- String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
-
- Vector<String> versions;
- versions.push_back("\n#define MODE_PROBES\n");
- versions.push_back("\n#define MODE_VISIBILITY\n");
+ sky.init(storage);
- sdfgi_shader.debug_probes.initialize(versions, defines);
- sdfgi_shader.debug_probes_shader = sdfgi_shader.debug_probes.version_create();
+ /* GI */
- {
- RD::PipelineRasterizationState rs;
- rs.cull_mode = RD::POLYGON_CULL_DISABLED;
- RD::PipelineDepthStencilState ds;
- ds.enable_depth_test = true;
- ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- for (int i = 0; i < SDGIShader::PROBE_DEBUG_MAX; i++) {
- RID debug_probes_shader_version = sdfgi_shader.debug_probes.version_get_shader(sdfgi_shader.debug_probes_shader, i);
- sdfgi_shader.debug_probes_pipeline[i].setup(debug_probes_shader_version, RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
- }
- default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GI::GIProbeData) * RenderBuffers::MAX_GIPROBES);
+ if (is_dynamic_gi_supported()) {
+ gi.init(storage, &sky);
}
{ //decals
@@ -8852,7 +4279,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
}
- if (!low_end) {
+ if (is_volumetric_supported()) {
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
@@ -8876,31 +4303,29 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
- camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape"))));
- camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter"));
- environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"), GLOBAL_GET("rendering/quality/ssao/adaptive_target"), GLOBAL_GET("rendering/quality/ssao/blur_passes"), GLOBAL_GET("rendering/quality/ssao/fadeout_from"), GLOBAL_GET("rendering/quality/ssao/fadeout_to"));
- screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled");
- screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount");
- screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit");
- glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
- glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality");
- ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
- sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
- sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
- sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale");
+ camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape"))));
+ camera_effects_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"));
+ environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
+ screen_space_roughness_limiter = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled");
+ screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount");
+ screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit");
+ glow_bicubic_upscale = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
+ glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality");
+ ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
+ sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
+ sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+ sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
directional_penumbra_shadow_kernel = memnew_arr(float, 128);
directional_soft_shadow_kernel = memnew_arr(float, 128);
penumbra_shadow_kernel = memnew_arr(float, 128);
soft_shadow_kernel = memnew_arr(float, 128);
- shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality"))));
- directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality"))));
+ shadows_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/shadows/soft_shadow_quality"))));
+ directional_shadow_quality_set(RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_quality"))));
- environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/volumetric_fog/volume_size"), GLOBAL_GET("rendering/volumetric_fog/volume_depth"));
- environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter"));
+ environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
+ environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
cull_argument.set_page_pool(&cull_argument_pool);
-
- gi.half_resolution = GLOBAL_GET("rendering/quality/gi/use_half_resolution");
}
RendererSceneRenderRD::~RendererSceneRenderRD() {
@@ -8908,40 +4333,27 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
RD::get_singleton()->free(E->get().cubemap);
}
- if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
- RD::get_singleton()->free(sky_scene_state.uniform_set);
+ if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) {
+ RD::get_singleton()->free(sky.sky_scene_state.uniform_set);
}
- if (!low_end) {
- RD::get_singleton()->free(default_giprobe_buffer);
- RD::get_singleton()->free(gi_probe_lights_uniform);
- RD::get_singleton()->free(gi.sdfgi_ubo);
-
- giprobe_debug_shader.version_free(giprobe_debug_shader_version);
- giprobe_shader.version_free(giprobe_lighting_shader_version);
- gi.shader.version_free(gi.shader_version);
- sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
- sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
- sdfgi_shader.direct_light.version_free(sdfgi_shader.direct_light_shader);
- sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
- sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
+ if (is_dynamic_gi_supported()) {
+ gi.free();
volumetric_fog.shader.version_free(volumetric_fog.shader_version);
RD::get_singleton()->free(volumetric_fog.params_ubo);
-
- memdelete_arr(gi_probe_lights);
}
- SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
- sky_shader.shader.version_free(md->shader_data->version);
- RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
- RD::get_singleton()->free(sky_scene_state.uniform_buffer);
- memdelete_arr(sky_scene_state.directional_lights);
- memdelete_arr(sky_scene_state.last_frame_directional_lights);
- storage->free(sky_shader.default_shader);
- storage->free(sky_shader.default_material);
- storage->free(sky_scene_state.fog_shader);
- storage->free(sky_scene_state.fog_material);
+ RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
+ sky.sky_shader.shader.version_free(md->shader_data->version);
+ RD::get_singleton()->free(sky.sky_scene_state.directional_light_buffer);
+ RD::get_singleton()->free(sky.sky_scene_state.uniform_buffer);
+ memdelete_arr(sky.sky_scene_state.directional_lights);
+ memdelete_arr(sky.sky_scene_state.last_frame_directional_lights);
+ storage->free(sky.sky_shader.default_shader);
+ storage->free(sky.sky_shader.default_material);
+ storage->free(sky.sky_scene_state.fog_shader);
+ storage->free(sky.sky_scene_state.fog_material);
memdelete_arr(directional_penumbra_shadow_kernel);
memdelete_arr(directional_soft_shadow_kernel);
memdelete_arr(penumbra_shadow_kernel);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index cdcdb73132..b289eda58f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -35,68 +35,22 @@
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_gi_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
-#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
class RendererSceneRenderRD : public RendererSceneRender {
+ friend RendererSceneSkyRD;
+ friend RendererSceneGIRD;
+
protected:
+ RendererStorageRD *storage;
double time;
-
- // Skys need less info from Directional Lights than the normal shaders
- struct SkyDirectionalLightData {
- float direction[3];
- float energy;
- float color[3];
- float size;
- uint32_t enabled;
- uint32_t pad[3];
- };
-
- struct SkySceneState {
- struct UBO {
- uint32_t volumetric_fog_enabled;
- float volumetric_fog_inv_length;
- float volumetric_fog_detail_spread;
-
- float fog_aerial_perspective;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- uint32_t fog_enabled;
- float fog_density;
-
- float z_far;
- uint32_t directional_light_count;
- };
-
- UBO ubo;
-
- SkyDirectionalLightData *directional_lights;
- SkyDirectionalLightData *last_frame_directional_lights;
- uint32_t max_directional_lights;
- uint32_t last_frame_directional_light_count;
- RID directional_light_buffer;
- RID uniform_set;
- RID uniform_buffer;
- RID fog_uniform_set;
- RID default_fog_uniform_set;
-
- RID fog_shader;
- RID fog_material;
- RID fog_only_texture_uniform_set;
- } sky_scene_state;
+ double time_step = 0;
struct RenderBufferData {
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
@@ -107,7 +61,6 @@ protected:
void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform);
void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment);
- void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used);
virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0;
@@ -121,25 +74,17 @@ protected:
virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
- virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
virtual void _base_uniforms_changed() = 0;
- virtual void _render_buffers_uniform_set_changed(RID p_render_buffers) = 0;
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0;
void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection);
void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
- void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);
- void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
- void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
- void _pre_process_gi(RID p_render_buffers, const Transform &p_transform);
- void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes);
-
bool _needs_post_prepass_render(bool p_use_gi);
void _post_prepass_render(bool p_use_gi);
void _pre_resolve_render(bool p_use_gi);
@@ -150,190 +95,21 @@ protected:
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
PagedArray<GeometryInstance *> cull_argument; //need this to exist
-private:
- RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
- double time_step = 0;
- static RendererSceneRenderRD *singleton;
-
- int roughness_layers;
-
- RendererStorageRD *storage;
-
- struct ReflectionData {
- struct Layer {
- struct Mipmap {
- RID framebuffers[6];
- RID views[6];
- Size2i size;
- };
- Vector<Mipmap> mipmaps; //per-face view
- Vector<RID> views; // per-cubemap view
- };
-
- struct DownsampleLayer {
- struct Mipmap {
- RID view;
- Size2i size;
- };
- Vector<Mipmap> mipmaps;
- };
-
- RID radiance_base_cubemap; //cubemap for first layer, first cubemap
- RID downsampled_radiance_cubemap;
- DownsampleLayer downsampled_layer;
- RID coefficient_buffer;
-
- bool dirty = true;
-
- Vector<Layer> layers;
- };
-
- void _clear_reflection_data(ReflectionData &rd);
- void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality);
- void _create_reflection_fast_filter(ReflectionData &rd, bool p_use_arrays);
- void _create_reflection_importance_sample(ReflectionData &rd, bool p_use_arrays, int p_cube_side, int p_base_layer);
- void _update_reflection_mipmaps(ReflectionData &rd, int p_start, int p_end);
-
- /* Sky shader */
-
- enum SkyVersion {
- SKY_VERSION_BACKGROUND,
- SKY_VERSION_HALF_RES,
- SKY_VERSION_QUARTER_RES,
- SKY_VERSION_CUBEMAP,
- SKY_VERSION_CUBEMAP_HALF_RES,
- SKY_VERSION_CUBEMAP_QUARTER_RES,
- SKY_VERSION_MAX
- };
-
- struct SkyShader {
- SkyShaderRD shader;
- ShaderCompilerRD compiler;
-
- RID default_shader;
- RID default_material;
- RID default_shader_rd;
- } sky_shader;
-
- struct SkyShaderData : public RendererStorageRD::ShaderData {
- bool valid;
- RID version;
-
- PipelineCacheRD pipelines[SKY_VERSION_MAX];
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
- Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
- Vector<uint32_t> ubo_offsets;
- uint32_t ubo_size;
-
- String path;
- String code;
- Map<StringName, RID> default_texture_params;
-
- bool uses_time;
- bool uses_position;
- bool uses_half_res;
- bool uses_quarter_res;
- bool uses_light;
-
- virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
- virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
- virtual bool is_param_texture(const StringName &p_param) const;
- virtual bool is_animated() const;
- virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
- virtual RS::ShaderNativeSourceCode get_native_source_code() const;
- SkyShaderData();
- virtual ~SkyShaderData();
- };
-
- RendererStorageRD::ShaderData *_create_sky_shader_func();
- static RendererStorageRD::ShaderData *_create_sky_shader_funcs() {
- return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_shader_func();
- };
-
- struct SkyMaterialData : public RendererStorageRD::MaterialData {
- uint64_t last_frame;
- SkyShaderData *shader_data;
- RID uniform_buffer;
- RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
- bool uniform_set_updated;
-
- virtual void set_render_priority(int p_priority) {}
- virtual void set_next_pass(RID p_pass) {}
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
- virtual ~SkyMaterialData();
- };
-
- RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
- static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) {
- return static_cast<RendererSceneRenderRD *>(singleton)->_create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
- };
-
- enum SkyTextureSetVersion {
- SKY_TEXTURE_SET_BACKGROUND,
- SKY_TEXTURE_SET_HALF_RES,
- SKY_TEXTURE_SET_QUARTER_RES,
- SKY_TEXTURE_SET_CUBEMAP,
- SKY_TEXTURE_SET_CUBEMAP_HALF_RES,
- SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES,
- SKY_TEXTURE_SET_MAX
- };
-
- enum SkySet {
- SKY_SET_UNIFORMS,
- SKY_SET_MATERIAL,
- SKY_SET_TEXTURES,
- SKY_SET_FOG,
- SKY_SET_MAX
- };
-
- /* SKY */
- struct Sky {
- RID radiance;
- RID half_res_pass;
- RID half_res_framebuffer;
- RID quarter_res_pass;
- RID quarter_res_framebuffer;
- Size2i screen_size;
-
- RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
- RID uniform_set;
-
- RID material;
- RID uniform_buffer;
-
- int radiance_size = 256;
-
- RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
-
- ReflectionData reflection;
- bool dirty = false;
- int processing_layer = 0;
- Sky *dirty_list = nullptr;
-
- //State to track when radiance cubemap needs updating
- SkyMaterialData *prev_material;
- Vector3 prev_position;
- float prev_time;
-
- RID sdfgi_integrate_sky_uniform_set;
- };
-
- Sky *dirty_sky_list = nullptr;
- void _sky_invalidate(Sky *p_sky);
- void _update_dirty_skys();
- RID _get_sky_textures(Sky *p_sky, SkyTextureSetVersion p_version);
+ RendererSceneGIRD gi;
+ RendererSceneSkyRD sky;
- uint32_t sky_ggx_samples_quality;
- bool sky_use_cubemap_array;
+ RendererSceneEnvironmentRD *get_environment(RID p_environment) {
+ if (p_environment.is_valid()) {
+ return environment_owner.getornull(p_environment);
+ } else {
+ return nullptr;
+ }
+ }
- mutable RID_Owner<Sky> sky_owner;
+private:
+ RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
+ static RendererSceneRenderRD *singleton;
/* REFLECTION ATLAS */
@@ -347,7 +123,7 @@ private:
struct Reflection {
RID owner;
- ReflectionData data;
+ RendererSceneSkyRD::ReflectionData data;
RID fbs[6];
};
@@ -373,6 +149,7 @@ private:
uint32_t render_step = 0;
uint64_t last_pass = 0;
uint32_t render_index = 0;
+ uint32_t cull_mask = 0;
Transform transform;
};
@@ -384,6 +161,8 @@ private:
struct DecalInstance {
RID decal;
Transform transform;
+ uint32_t render_index;
+ uint32_t cull_mask;
};
mutable RID_Owner<DecalInstance> decal_instance_owner;
@@ -397,151 +176,6 @@ private:
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
- /* GIPROBE INSTANCE */
-
- struct GIProbeLight {
- uint32_t type;
- float energy;
- float radius;
- float attenuation;
-
- float color[3];
- float cos_spot_angle;
-
- float position[3];
- float inv_spot_attenuation;
-
- float direction[3];
- uint32_t has_shadow;
- };
-
- struct GIProbePushConstant {
- int32_t limits[3];
- uint32_t stack_size;
-
- float emission_scale;
- float propagation;
- float dynamic_range;
- uint32_t light_count;
-
- uint32_t cell_offset;
- uint32_t cell_count;
- float aniso_strength;
- uint32_t pad;
- };
-
- struct GIProbeDynamicPushConstant {
- int32_t limits[3];
- uint32_t light_count;
- int32_t x_dir[3];
- float z_base;
- int32_t y_dir[3];
- float z_sign;
- int32_t z_dir[3];
- float pos_multiplier;
- uint32_t rect_pos[2];
- uint32_t rect_size[2];
- uint32_t prev_rect_ofs[2];
- uint32_t prev_rect_size[2];
- uint32_t flip_x;
- uint32_t flip_y;
- float dynamic_range;
- uint32_t on_mipmap;
- float propagation;
- float pad[3];
- };
-
- struct GIProbeInstance {
- RID probe;
- RID texture;
- RID write_buffer;
-
- struct Mipmap {
- RID texture;
- RID uniform_set;
- RID second_bounce_uniform_set;
- RID write_uniform_set;
- uint32_t level;
- uint32_t cell_offset;
- uint32_t cell_count;
- };
- Vector<Mipmap> mipmaps;
-
- struct DynamicMap {
- RID texture; //color normally, or emission on first pass
- RID fb_depth; //actual depth buffer for the first pass, float depth for later passes
- RID depth; //actual depth buffer for the first pass, float depth for later passes
- RID normal; //normal buffer for the first pass
- RID albedo; //emission buffer for the first pass
- RID orm; //orm buffer for the first pass
- RID fb; //used for rendering, only valid on first map
- RID uniform_set;
- uint32_t size;
- int mipmap; // mipmap to write to, -1 if no mipmap assigned
- };
-
- Vector<DynamicMap> dynamic_maps;
-
- int slot = -1;
- uint32_t last_probe_version = 0;
- uint32_t last_probe_data_version = 0;
-
- //uint64_t last_pass = 0;
- uint32_t render_index = 0;
-
- bool has_dynamic_object_data = false;
-
- Transform transform;
- };
-
- GIProbeLight *gi_probe_lights;
- uint32_t gi_probe_max_lights;
- RID gi_probe_lights_uniform;
-
- enum {
- GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
- GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
- GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
- GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
- GI_PROBE_SHADER_VERSION_MAX
- };
- GiprobeShaderRD giprobe_shader;
- RID giprobe_lighting_shader_version;
- RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX];
- RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX];
-
- mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
-
- RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
-
- enum {
- GI_PROBE_DEBUG_COLOR,
- GI_PROBE_DEBUG_LIGHT,
- GI_PROBE_DEBUG_EMISSION,
- GI_PROBE_DEBUG_LIGHT_FULL,
- GI_PROBE_DEBUG_MAX
- };
-
- struct GIProbeDebugPushConstant {
- float projection[16];
- uint32_t cell_offset;
- float dynamic_range;
- float alpha;
- uint32_t level;
- int32_t bounds[3];
- uint32_t pad;
- };
-
- GiprobeDebugShaderRD giprobe_debug_shader;
- RID giprobe_debug_shader_version;
- RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
- PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
- RID giprobe_debug_uniform_set;
-
/* SHADOW ATLAS */
struct ShadowShrinkStage {
@@ -673,6 +307,7 @@ private:
uint64_t last_scene_shadow_pass = 0;
uint64_t last_pass = 0;
uint32_t light_index = 0;
+ uint32_t cull_mask = 0;
uint32_t light_directional_index = 0;
uint32_t current_shadow_atlas_key = 0;
@@ -690,111 +325,6 @@ private:
/* ENVIRONMENT */
- struct Environment {
- // BG
- RS::EnvironmentBG background = RS::ENV_BG_CLEAR_COLOR;
- RID sky;
- float sky_custom_fov = 0.0;
- Basis sky_orientation;
- Color bg_color;
- float bg_energy = 1.0;
- int canvas_max_layer = 0;
- RS::EnvironmentAmbientSource ambient_source = RS::ENV_AMBIENT_SOURCE_BG;
- Color ambient_light;
- float ambient_light_energy = 1.0;
- float ambient_sky_contribution = 1.0;
- RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG;
- Color ao_color;
-
- /// Tonemap
-
- RS::EnvironmentToneMapper tone_mapper;
- float exposure = 1.0;
- float white = 1.0;
- bool auto_exposure = false;
- float min_luminance = 0.2;
- float max_luminance = 8.0;
- float auto_exp_speed = 0.2;
- float auto_exp_scale = 0.5;
- uint64_t auto_exposure_version = 0;
-
- // Fog
- bool fog_enabled = false;
- Color fog_light_color = Color(0.5, 0.6, 0.7);
- float fog_light_energy = 1.0;
- float fog_sun_scatter = 0.0;
- float fog_density = 0.001;
- float fog_height = 0.0;
- float fog_height_density = 0.0; //can be negative to invert effect
- float fog_aerial_perspective = 0.0;
-
- /// Volumetric Fog
- ///
- bool volumetric_fog_enabled = false;
- float volumetric_fog_density = 0.01;
- Color volumetric_fog_light = Color(0, 0, 0);
- float volumetric_fog_light_energy = 0.0;
- float volumetric_fog_length = 64.0;
- float volumetric_fog_detail_spread = 2.0;
- float volumetric_fog_gi_inject = 0.0;
- bool volumetric_fog_temporal_reprojection = true;
- float volumetric_fog_temporal_reprojection_amount = 0.9;
-
- /// Glow
-
- bool glow_enabled = false;
- Vector<float> glow_levels;
- float glow_intensity = 0.8;
- float glow_strength = 1.0;
- float glow_bloom = 0.0;
- float glow_mix = 0.01;
- RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT;
- float glow_hdr_bleed_threshold = 1.0;
- float glow_hdr_luminance_cap = 12.0;
- float glow_hdr_bleed_scale = 2.0;
-
- /// SSAO
-
- bool ssao_enabled = false;
- float ssao_radius = 1.0;
- float ssao_intensity = 2.0;
- float ssao_power = 1.5;
- float ssao_detail = 0.5;
- float ssao_horizon = 0.06;
- float ssao_sharpness = 0.98;
- float ssao_direct_light_affect = 0.0;
- float ssao_ao_channel_affect = 0.0;
-
- /// SSR
- ///
- bool ssr_enabled = false;
- int ssr_max_steps = 64;
- float ssr_fade_in = 0.15;
- float ssr_fade_out = 2.0;
- float ssr_depth_tolerance = 0.2;
-
- /// SDFGI
- bool sdfgi_enabled = false;
- RS::EnvironmentSDFGICascades sdfgi_cascades;
- float sdfgi_min_cell_size = 0.2;
- bool sdfgi_use_occlusion = false;
- bool sdfgi_use_multibounce = false;
- bool sdfgi_read_sky_light = false;
- float sdfgi_energy = 1.0;
- float sdfgi_normal_bias = 1.1;
- float sdfgi_probe_bias = 1.1;
- RS::EnvironmentSDFGIYScale sdfgi_y_scale = RS::ENV_SDFGI_Y_SCALE_DISABLED;
-
- /// Adjustments
-
- bool adjustments_enabled = false;
- float adjustments_brightness = 1.0f;
- float adjustments_contrast = 1.0f;
- float adjustments_saturation = 1.0f;
- bool use_1d_color_correction = false;
- RID color_correction = RID();
- };
-
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
bool ssao_half_size = false;
bool ssao_using_half_size = false;
@@ -807,9 +337,7 @@ private:
bool glow_high_quality = false;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;
- static uint64_t auto_exposure_counter;
-
- mutable RID_Owner<Environment> environment_owner;
+ mutable RID_Owner<RendererSceneEnvironmentRD, true> environment_owner;
/* CAMERA EFFECTS */
@@ -835,21 +363,16 @@ private:
float sss_scale = 0.05;
float sss_depth_scale = 0.01;
- mutable RID_Owner<CameraEffects> camera_effects_owner;
+ mutable RID_Owner<CameraEffects, true> camera_effects_owner;
/* RENDER BUFFERS */
ClusterBuilderSharedDataRD cluster_builder_shared;
ClusterBuilderRD *current_cluster_builder = nullptr;
- struct SDFGI;
struct VolumetricFog;
struct RenderBuffers {
- enum {
- MAX_GIPROBES = 8
- };
-
RenderBufferData *data = nullptr;
int width = 0, height = 0;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
@@ -863,9 +386,9 @@ private:
RID texture; //main texture for rendering to, must be filled after done rendering
RID depth_texture; //main depth texture
- RID gi_uniform_set;
- SDFGI *sdfgi = nullptr;
+ RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
+ RendererSceneGIRD::RenderBuffersGI gi;
ClusterBuilderRD *cluster_builder = nullptr;
@@ -906,414 +429,11 @@ private:
RID blur_radius[2];
} ssr;
- RID giprobe_textures[MAX_GIPROBES];
- RID giprobe_buffer;
-
RID ambient_buffer;
RID reflection_buffer;
- bool using_half_size_gi = false;
-
- struct GI {
- RID full_buffer;
- RID full_dispatch;
- RID full_mask;
- } gi;
};
- RID default_giprobe_buffer;
-
- /* SDFGI */
-
- struct SDFGI {
- enum {
- MAX_CASCADES = 8,
- CASCADE_SIZE = 128,
- PROBE_DIVISOR = 16,
- ANISOTROPY_SIZE = 6,
- MAX_DYNAMIC_LIGHTS = 128,
- MAX_STATIC_LIGHTS = 1024,
- LIGHTPROBE_OCT_SIZE = 6,
- SH_SIZE = 16
- };
-
- struct Cascade {
- struct UBO {
- float offset[3];
- float to_cell;
- int32_t probe_offset[3];
- uint32_t pad;
- };
-
- //cascade blocks are full-size for volume (128^3), half size for albedo/emission
- RID sdf_tex;
- RID light_tex;
- RID light_aniso_0_tex;
- RID light_aniso_1_tex;
-
- RID light_data;
- RID light_aniso_0_data;
- RID light_aniso_1_data;
-
- struct SolidCell { // this struct is unused, but remains as reference for size
- uint32_t position;
- uint32_t albedo;
- uint32_t static_light;
- uint32_t static_light_aniso;
- };
-
- RID solid_cell_dispatch_buffer; //buffer for indirect compute dispatch
- RID solid_cell_buffer;
-
- RID lightprobe_history_tex;
- RID lightprobe_average_tex;
-
- float cell_size;
- Vector3i position;
-
- static const Vector3i DIRTY_ALL;
- Vector3i dirty_regions; //(0,0,0 is not dirty, negative is refresh from the end, DIRTY_ALL is refresh all.
-
- RID sdf_store_uniform_set;
- RID sdf_direct_light_uniform_set;
- RID scroll_uniform_set;
- RID scroll_occlusion_uniform_set;
- RID integrate_uniform_set;
- RID lights_buffer;
-
- bool all_dynamic_lights_dirty = true;
- };
-
- //used for rendering (voxelization)
- RID render_albedo;
- RID render_emission;
- RID render_emission_aniso;
- RID render_occlusion[8];
- RID render_geom_facing;
-
- RID render_sdf[2];
- RID render_sdf_half[2];
-
- //used for ping pong processing in cascades
- RID sdf_initialize_uniform_set;
- RID sdf_initialize_half_uniform_set;
- RID jump_flood_uniform_set[2];
- RID jump_flood_half_uniform_set[2];
- RID sdf_upscale_uniform_set;
- int upscale_jfa_uniform_set_index;
- RID occlusion_uniform_set;
-
- uint32_t cascade_size = 128;
-
- LocalVector<Cascade> cascades;
-
- RID lightprobe_texture;
- RID lightprobe_data;
- RID occlusion_texture;
- RID occlusion_data;
- RID ambient_texture; //integrates with volumetric fog
-
- RID lightprobe_history_scroll; //used for scrolling lightprobes
- RID lightprobe_average_scroll; //used for scrolling lightprobes
-
- uint32_t history_size = 0;
- float solid_cell_ratio = 0;
- uint32_t solid_cell_count = 0;
-
- RS::EnvironmentSDFGICascades cascade_mode;
- float min_cell_size = 0;
- uint32_t probe_axis_count = 0; //amount of probes per axis, this is an odd number because it encloses endpoints
-
- RID debug_uniform_set;
- RID debug_probes_uniform_set;
- RID cascades_ubo;
-
- bool uses_occlusion = false;
- bool uses_multibounce = false;
- bool reads_sky = false;
- float energy = 1.0;
- float normal_bias = 1.1;
- float probe_bias = 1.1;
- RS::EnvironmentSDFGIYScale y_scale_mode = RS::ENV_SDFGI_Y_SCALE_DISABLED;
-
- float y_mult = 1.0;
-
- uint32_t render_pass = 0;
-
- int32_t cascade_dynamic_light_count[SDFGI::MAX_CASCADES]; //used dynamically
- };
-
- void _sdfgi_update_light(RID p_render_buffers, RID p_environment);
- void _sdfgi_update_probes(RID p_render_buffers, RID p_environment);
- void _sdfgi_store_probes(RID p_render_buffers);
-
- RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
- RS::EnvironmentSDFGIFramesToConverge sdfgi_frames_to_converge = RS::ENV_SDFGI_CONVERGE_IN_10_FRAMES;
- RS::EnvironmentSDFGIFramesToUpdateLight sdfgi_frames_to_update_light = RS::ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES;
-
- float sdfgi_solid_cell_ratio = 0.25;
- Vector3 sdfgi_debug_probe_pos;
- Vector3 sdfgi_debug_probe_dir;
- bool sdfgi_debug_probe_enabled = false;
- Vector3i sdfgi_debug_probe_index;
-
- struct SDGIShader {
- enum SDFGIPreprocessShaderVersion {
- PRE_PROCESS_SCROLL,
- PRE_PROCESS_SCROLL_OCCLUSION,
- PRE_PROCESS_JUMP_FLOOD_INITIALIZE,
- PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF,
- PRE_PROCESS_JUMP_FLOOD,
- PRE_PROCESS_JUMP_FLOOD_OPTIMIZED,
- PRE_PROCESS_JUMP_FLOOD_UPSCALE,
- PRE_PROCESS_OCCLUSION,
- PRE_PROCESS_STORE,
- PRE_PROCESS_MAX
- };
-
- struct PreprocessPushConstant {
- int32_t scroll[3];
- int32_t grid_size;
-
- int32_t probe_offset[3];
- int32_t step_size;
-
- int32_t half_size;
- uint32_t occlusion_index;
- int32_t cascade;
- uint32_t pad;
- };
-
- SdfgiPreprocessShaderRD preprocess;
- RID preprocess_shader;
- RID preprocess_pipeline[PRE_PROCESS_MAX];
-
- struct DebugPushConstant {
- float grid_size[3];
- uint32_t max_cascades;
-
- int32_t screen_size[2];
- uint32_t use_occlusion;
- float y_mult;
-
- float cam_extent[3];
- uint32_t probe_axis_size;
-
- float cam_transform[16];
- };
-
- SdfgiDebugShaderRD debug;
- RID debug_shader;
- RID debug_shader_version;
- RID debug_pipeline;
-
- enum ProbeDebugMode {
- PROBE_DEBUG_PROBES,
- PROBE_DEBUG_VISIBILITY,
- PROBE_DEBUG_MAX
- };
-
- struct DebugProbesPushConstant {
- float projection[16];
-
- uint32_t band_power;
- uint32_t sections_in_band;
- uint32_t band_mask;
- float section_arc;
-
- float grid_size[3];
- uint32_t cascade;
-
- uint32_t pad;
- float y_mult;
- int32_t probe_debug_index;
- int32_t probe_axis_size;
- };
-
- SdfgiDebugProbesShaderRD debug_probes;
- RID debug_probes_shader;
- RID debug_probes_shader_version;
-
- PipelineCacheRD debug_probes_pipeline[PROBE_DEBUG_MAX];
-
- struct Light {
- float color[3];
- float energy;
-
- float direction[3];
- uint32_t has_shadow;
-
- float position[3];
- float attenuation;
-
- uint32_t type;
- float cos_spot_angle;
- float inv_spot_attenuation;
- float radius;
-
- float shadow_color[4];
- };
-
- struct DirectLightPushConstant {
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t cascade;
- uint32_t light_count;
- uint32_t process_offset;
- uint32_t process_increment;
-
- int32_t probe_axis_size;
- uint32_t multibounce;
- float y_mult;
- uint32_t pad;
- };
-
- enum {
- DIRECT_LIGHT_MODE_STATIC,
- DIRECT_LIGHT_MODE_DYNAMIC,
- DIRECT_LIGHT_MODE_MAX
- };
- SdfgiDirectLightShaderRD direct_light;
- RID direct_light_shader;
- RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
-
- enum {
- INTEGRATE_MODE_PROCESS,
- INTEGRATE_MODE_STORE,
- INTEGRATE_MODE_SCROLL,
- INTEGRATE_MODE_SCROLL_STORE,
- INTEGRATE_MODE_MAX
- };
- struct IntegratePushConstant {
- enum {
- SKY_MODE_DISABLED,
- SKY_MODE_COLOR,
- SKY_MODE_SKY,
- };
-
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t probe_axis_size;
- uint32_t cascade;
- uint32_t history_index;
- uint32_t history_size;
-
- uint32_t ray_count;
- float ray_bias;
- int32_t image_size[2];
-
- int32_t world_offset[3];
- uint32_t sky_mode;
-
- int32_t scroll[3];
- float sky_energy;
-
- float sky_color[3];
- float y_mult;
-
- uint32_t store_ambient_texture;
- uint32_t pad[3];
- };
-
- SdfgiIntegrateShaderRD integrate;
- RID integrate_shader;
- RID integrate_pipeline[INTEGRATE_MODE_MAX];
-
- RID integrate_default_sky_uniform_set;
-
- } sdfgi_shader;
-
- void _sdfgi_erase(RenderBuffers *rb);
- int _sdfgi_get_pending_region_data(RID p_render_buffers, int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
- void _sdfgi_update_cascades(RID p_render_buffers);
-
/* GI */
-
- struct GI {
- struct SDFGIData {
- float grid_size[3];
- uint32_t max_cascades;
-
- uint32_t use_occlusion;
- int32_t probe_axis_size;
- float probe_to_uvw;
- float normal_bias;
-
- float lightprobe_tex_pixel_size[3];
- float energy;
-
- float lightprobe_uv_offset[3];
- float y_mult;
-
- float occlusion_clamp[3];
- uint32_t pad3;
-
- float occlusion_renormalize[3];
- uint32_t pad4;
-
- float cascade_probe_size[3];
- uint32_t pad5;
-
- struct ProbeCascadeData {
- float position[3]; //offset of (0,0,0) in world coordinates
- float to_probe; // 1/bounds * grid_size
- int32_t probe_world_offset[3];
- float to_cell; // 1/bounds * grid_size
- };
-
- ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
- };
-
- struct GIProbeData {
- float xform[16];
- float bounds[3];
- float dynamic_range;
-
- float bias;
- float normal_bias;
- uint32_t blend_ambient;
- uint32_t texture_slot;
-
- float anisotropy_strength;
- float ao;
- float ao_size;
- uint32_t mipmaps;
- };
-
- struct PushConstant {
- int32_t screen_size[2];
- float z_near;
- float z_far;
-
- float proj_info[4];
- float ao_color[3];
- uint32_t max_giprobes;
-
- uint32_t high_quality_vct;
- uint32_t orthogonal;
- uint32_t pad[2];
-
- float cam_rotation[12];
- };
-
- RID sdfgi_ubo;
- enum Mode {
- MODE_GIPROBE,
- MODE_SDFGI,
- MODE_COMBINED,
- MODE_HALF_RES_GIPROBE,
- MODE_HALF_RES_SDFGI,
- MODE_HALF_RES_COMBINED,
- MODE_MAX
- };
-
- bool half_resolution = false;
- GiShaderRD shader;
- RID shader_version;
- RID pipelines[MODE_MAX];
- } gi;
-
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
@@ -1324,15 +444,16 @@ private:
void _allocate_blur_textures(RenderBuffers *rb);
void _allocate_luminance_textures(RenderBuffers *rb);
- void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas);
+ void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
void _render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection);
- void _sdfgi_debug_draw(RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform);
/* Cluster */
struct Cluster {
/* Scene State UBO */
+ // !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate
+
enum {
REFLECTION_AMBIENT_DISABLED = 0,
REFLECTION_AMBIENT_ENVIRONMENT = 1,
@@ -1346,8 +467,8 @@ private:
uint32_t mask;
float ambient[3]; // ambient color,
float intensity;
- bool exterior;
- bool box_project;
+ uint32_t exterior;
+ uint32_t box_project;
uint32_t ambient_mode;
uint32_t pad;
float local_matrix[16]; // up to here for spot and omni, rest is for directional
@@ -1592,17 +713,16 @@ private:
uint64_t scene_pass = 0;
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+ /* !BAS! is this used anywhere?
struct SDFGICosineNeighbour {
uint32_t neighbour;
float weight;
};
+ */
uint32_t max_cluster_elements = 512;
- bool low_end = false;
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
- void _render_sdfgi_region(RID p_render_buffers, int p_region, const PagedArray<GeometryInstance *> &p_instances);
- void _render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result);
public:
virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
@@ -1646,27 +766,26 @@ public:
/* SDFGI UPDATE */
- int sdfgi_get_lightprobe_octahedron_size() const { return SDFGI::LIGHTPROBE_OCT_SIZE; }
virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position);
virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const;
virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const;
virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const;
RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }
+
/* SKY API */
- RID sky_create();
+ virtual RID sky_allocate();
+ virtual void sky_initialize(RID p_rid);
+
void sky_set_radiance_size(RID p_sky, int p_radiance_size);
void sky_set_mode(RID p_sky, RS::SkyMode p_mode);
void sky_set_material(RID p_sky, RID p_material);
Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
- RID sky_get_radiance_texture_rd(RID p_sky) const;
- RID sky_get_radiance_uniform_set_rd(RID p_sky, RID p_shader, int p_set) const;
- RID sky_get_material(RID p_sky) const;
-
/* ENVIRONMENT API */
- RID environment_create();
+ virtual RID environment_allocate();
+ virtual void environment_initialize(RID p_rid);
void environment_set_background(RID p_env, RS::EnvironmentBG p_bg);
void environment_set_sky(RID p_env, RID p_sky);
@@ -1721,7 +840,7 @@ public:
bool environment_is_ssr_enabled(RID p_env) const;
bool environment_is_sdfgi_enabled(RID p_env) const;
- virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
+ virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias);
virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count);
virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames);
virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update);
@@ -1734,7 +853,8 @@ public:
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size);
- virtual RID camera_effects_create();
+ virtual RID camera_effects_allocate();
+ virtual void camera_effects_initialize(RID p_rid);
virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter);
virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape);
@@ -1970,57 +1090,18 @@ public:
return li->transform;
}
+ void _fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words = 2);
+
+ /* gi light probes */
+
RID gi_probe_instance_create(RID p_base);
void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
bool gi_probe_needs_update(RID p_probe) const;
void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects);
+ void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; }
- void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; }
-
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_slot(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->slot;
- }
- _FORCE_INLINE_ RID gi_probe_instance_get_base_probe(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->probe;
- }
- _FORCE_INLINE_ Transform gi_probe_instance_get_transform_to_cell(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return storage->gi_probe_get_to_cell_xform(gi_probe->probe) * gi_probe->transform.affine_inverse();
- }
-
- _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->texture;
- }
-
- _FORCE_INLINE_ void gi_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!gi_probe);
- gi_probe->render_index = p_render_index;
- }
-
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_index(RID p_instance) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!gi_probe, 0);
-
- return gi_probe->render_index;
- }
- /*
- _FORCE_INLINE_ void gi_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
- GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!g_probe);
- g_probe->last_pass = p_render_pass;
- }
+ /* render buffers */
- _FORCE_INLINE_ uint32_t gi_probe_instance_get_render_pass(RID p_instance) {
- GIProbeInstance *g_probe = gi_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!g_probe, 0);
-
- return g_probe->last_pass;
- }
-*/
RID render_buffers_create();
void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);
void gi_set_use_half_resolution(bool p_enable);
@@ -2051,7 +1132,7 @@ public:
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr);
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr);
void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
@@ -2104,7 +1185,7 @@ public:
return debug_draw;
}
- virtual void set_time(double p_time, double p_step);
+ void set_time(double p_time, double p_step);
RID get_reflection_probe_buffer();
RID get_omni_light_buffer();
@@ -2115,7 +1196,10 @@ public:
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
- bool is_low_end() const;
+ virtual bool is_dynamic_gi_supported() const;
+ virtual bool is_clustered_enabled() const;
+ virtual bool is_volumetric_supported() const;
+ virtual uint32_t get_max_elements() const;
RendererSceneRenderRD(RendererStorageRD *p_storage);
~RendererSceneRenderRD();
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
new file mode 100644
index 0000000000..54c6e81110
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -0,0 +1,1492 @@
+/*************************************************************************/
+/* renderer_scene_sky_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "renderer_scene_sky_rd.h"
+#include "core/config/project_settings.h"
+#include "renderer_scene_render_rd.h"
+#include "servers/rendering/rendering_server_default.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// SKY SHADER
+
+void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["sky"] = ShaderCompilerRD::STAGE_FRAGMENT;
+
+ uses_time = false;
+ uses_half_res = false;
+ uses_quarter_res = false;
+ uses_position = false;
+ uses_light = false;
+
+ actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+ actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["POSITION"] = &uses_position;
+ actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
+
+ actions.uniforms = &uniforms;
+
+ // !BAS! Contemplate making `SkyShader sky` accessible from this struct or even part of this struct.
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ Error err = scene_singleton->sky.sky_shader.compiler.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = scene_singleton->sky.sky_shader.shader.version_create();
+ }
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ // print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+
+ scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
+ ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //update pipelines
+
+ for (int i = 0; i < SKY_VERSION_MAX; i++) {
+ RD::PipelineDepthStencilState depth_stencil_state;
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+
+ RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
+ pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+
+ valid = true;
+}
+
+void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void RendererSceneSkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool RendererSceneSkyRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RendererSceneSkyRD::SkyShaderData::is_animated() const {
+ return false;
+}
+
+bool RendererSceneSkyRD::SkyShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode RendererSceneSkyRD::SkyShaderData::get_native_source_code() const {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ return scene_singleton->sky.sky_shader.shader.version_get_native_source_code(version);
+}
+
+RendererSceneSkyRD::SkyShaderData::SkyShaderData() {
+ valid = false;
+}
+
+RendererSceneSkyRD::SkyShaderData::~SkyShaderData() {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+ ERR_FAIL_COND(!scene_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ scene_singleton->sky.sky_shader.shader.version_free(version);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sky material
+
+void RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton;
+
+ uniform_set_updated = true;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
+}
+
+RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ReflectionData
+
+void RendererSceneSkyRD::ReflectionData::clear_reflection_data() {
+ layers.clear();
+ radiance_base_cubemap = RID();
+ if (downsampled_radiance_cubemap.is_valid()) {
+ RD::get_singleton()->free(downsampled_radiance_cubemap);
+ }
+ downsampled_radiance_cubemap = RID();
+ downsampled_layer.mipmaps.clear();
+ coefficient_buffer = RID();
+}
+
+void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) {
+ //recreate radiance and all data
+
+ int mipmaps = p_mipmaps;
+ uint32_t w = p_size, h = p_size;
+
+ if (p_use_array) {
+ int num_layers = p_low_quality ? 8 : p_roughness_layers;
+
+ for (int i = 0; i < num_layers; i++) {
+ ReflectionData::Layer layer;
+ uint32_t mmw = w;
+ uint32_t mmh = h;
+ layer.mipmaps.resize(mipmaps);
+ layer.views.resize(mipmaps);
+ for (int j = 0; j < mipmaps; j++) {
+ ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6 + k, j);
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+
+ layers.push_back(layer);
+ }
+
+ } else {
+ mipmaps = p_low_quality ? 8 : mipmaps;
+ //regular cubemap, lower quality (aliasing, less memory)
+ ReflectionData::Layer layer;
+ uint32_t mmw = w;
+ uint32_t mmh = h;
+ layer.mipmaps.resize(mipmaps);
+ layer.views.resize(mipmaps);
+ for (int j = 0; j < mipmaps; j++) {
+ ReflectionData::Layer::Mipmap &mm = layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ for (int k = 0; k < 6; k++) {
+ mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + k, j);
+ Vector<RID> fbtex;
+ fbtex.push_back(mm.views[k]);
+ mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+
+ layers.push_back(layer);
+ }
+
+ radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = 64; // Always 64x64
+ tf.height = 64;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE;
+ tf.array_layers = 6;
+ tf.mipmaps = 7;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ {
+ uint32_t mmw = 64;
+ uint32_t mmh = 64;
+ downsampled_layer.mipmaps.resize(7);
+ for (int j = 0; j < downsampled_layer.mipmaps.size(); j++) {
+ ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j];
+ mm.size.width = mmw;
+ mm.size.height = mmh;
+ mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
+
+ mmw = MAX(1, mmw >> 1);
+ mmh = MAX(1, mmh >> 1);
+ }
+ }
+}
+
+void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
+ p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+
+ for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+ p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+ }
+
+ Vector<RID> views;
+ if (p_use_arrays) {
+ for (int i = 1; i < layers.size(); i++) {
+ views.push_back(layers[i].views[0]);
+ }
+ } else {
+ for (int i = 1; i < layers[0].views.size(); i++) {
+ views.push_back(layers[0].views[i]);
+ }
+ }
+
+ p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+}
+
+void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
+ if (p_use_arrays) {
+ //render directly to the layers
+ p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ } else {
+ p_storage->get_effects()->cubemap_roughness(
+ layers[0].views[p_base_layer - 1],
+ layers[0].views[p_base_layer],
+ p_cube_side,
+ p_sky_ggx_samples_quality,
+ float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+ layers[0].mipmaps[p_base_layer].size.x);
+ }
+}
+
+void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
+ for (int i = p_start; i < p_end; i++) {
+ for (int j = 0; j < layers[i].views.size() - 1; j++) {
+ RID view = layers[i].views[j];
+ RID texture = layers[i].views[j + 1];
+ Size2i size = layers[i].mipmaps[j + 1].size;
+ p_storage->get_effects()->cubemap_downsample(view, texture, size);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RendererSceneSkyRD::Sky
+
+void RendererSceneSkyRD::Sky::free(RendererStorageRD *p_storage) {
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ if (half_res_pass.is_valid()) {
+ RD::get_singleton()->free(half_res_pass);
+ half_res_pass = RID();
+ }
+
+ if (quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(quarter_res_pass);
+ quarter_res_pass = RID();
+ }
+
+ if (material.is_valid()) {
+ p_storage->free(material);
+ }
+}
+
+RID RendererSceneSkyRD::Sky::get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd) {
+ if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) {
+ return texture_uniform_sets[p_version];
+ }
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) {
+ u.ids.push_back(radiance);
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1; // half res
+ if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(reflection.layers[0].views[1]);
+ } else {
+ u.ids.push_back(half_res_pass);
+ }
+ } else {
+ if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2; // quarter res
+ if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
+ if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(reflection.layers[0].views[2]);
+ } else {
+ u.ids.push_back(quarter_res_pass);
+ }
+ } else {
+ if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(p_storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ }
+ uniforms.push_back(u);
+ }
+
+ texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES);
+ return texture_uniform_sets[p_version];
+}
+
+bool RendererSceneSkyRD::Sky::set_radiance_size(int p_radiance_size) {
+ ERR_FAIL_COND_V(p_radiance_size < 32 || p_radiance_size > 2048, false);
+ if (radiance_size == p_radiance_size) {
+ return false;
+ }
+ radiance_size = p_radiance_size;
+
+ if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) {
+ WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
+ radiance_size = 256;
+ }
+
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ return true;
+}
+
+bool RendererSceneSkyRD::Sky::set_mode(RS::SkyMode p_mode) {
+ if (mode == p_mode) {
+ return false;
+ }
+
+ mode = p_mode;
+
+ if (mode == RS::SKY_MODE_REALTIME && radiance_size != 256) {
+ WARN_PRINT("Realtime Skies can only use a radiance size of 256. Radiance size will be set to 256 internally.");
+ set_radiance_size(256);
+ }
+
+ if (radiance.is_valid()) {
+ RD::get_singleton()->free(radiance);
+ radiance = RID();
+ }
+ reflection.clear_reflection_data();
+
+ return true;
+}
+
+bool RendererSceneSkyRD::Sky::set_material(RID p_material) {
+ if (material == p_material) {
+ return false;
+ }
+
+ material = p_material;
+ return true;
+}
+
+Ref<Image> RendererSceneSkyRD::Sky::bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size) {
+ if (radiance.is_valid()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ tf.width = p_size.width;
+ tf.height = p_size.height;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+
+ RID rad_tex = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ p_storage->get_effects()->copy_cubemap_to_panorama(radiance, rad_tex, p_size, p_roughness_layers, reflection.layers.size() > 1);
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0);
+ RD::get_singleton()->free(rad_tex);
+
+ Ref<Image> img;
+ img.instance();
+ img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
+ for (int i = 0; i < p_size.width; i++) {
+ for (int j = 0; j < p_size.height; j++) {
+ Color c = img->get_pixel(i, j);
+ c.r *= p_energy;
+ c.g *= p_energy;
+ c.b *= p_energy;
+ img->set_pixel(i, j, c);
+ }
+ }
+ return img;
+ }
+
+ return Ref<Image>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RendererSceneSkyRD
+
+RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_func() {
+ SkyShaderData *shader_data = memnew(SkyShaderData);
+ return shader_data;
+}
+
+RendererStorageRD::ShaderData *RendererSceneSkyRD::_create_sky_shader_funcs() {
+ // !BAS! Why isn't _create_sky_shader_func not just static too?
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func();
+};
+
+RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_func(SkyShaderData *p_shader) {
+ SkyMaterialData *material_data = memnew(SkyMaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+RendererStorageRD::MaterialData *RendererSceneSkyRD::_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ // !BAS! same here, we could just make _create_sky_material_func static?
+ return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
+};
+
+RendererSceneSkyRD::RendererSceneSkyRD() {
+ roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
+ sky_ggx_samples_quality = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
+ sky_use_cubemap_array = GLOBAL_GET("rendering/reflections/sky_reflections/texture_array_reflections");
+}
+
+void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
+ storage = p_storage;
+
+ {
+ // Start with the directional lights for the sky
+ sky_scene_state.max_directional_lights = 4;
+ uint32_t directional_light_buffer_size = sky_scene_state.max_directional_lights * sizeof(SkyDirectionalLightData);
+ sky_scene_state.directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
+ sky_scene_state.last_frame_directional_lights = memnew_arr(SkyDirectionalLightData, sky_scene_state.max_directional_lights);
+ sky_scene_state.last_frame_directional_light_count = sky_scene_state.max_directional_lights + 1;
+ 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";
+
+ // Initialize sky
+ Vector<String> sky_modes;
+ sky_modes.push_back(""); // Full size
+ sky_modes.push_back("\n#define USE_HALF_RES_PASS\n"); // Half Res
+ sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n"); // Quarter res
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap
+ sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap
+ sky_shader.shader.initialize(sky_modes, defines);
+ }
+
+ // register our shader funds
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_SKY, _create_sky_material_funcs);
+
+ {
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["EYEDIR"] = "cube_normal";
+ actions.renames["POSITION"] = "params.position_multiplier.xyz";
+ actions.renames["SKY_COORDS"] = "panorama_coords";
+ actions.renames["SCREEN_UV"] = "uv";
+ actions.renames["TIME"] = "params.time";
+ actions.renames["HALF_RES_COLOR"] = "half_res_color";
+ actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
+ actions.renames["RADIANCE"] = "radiance";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
+ actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction_energy.xyz";
+ actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].direction_energy.w";
+ actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color_size.xyz";
+ actions.renames["LIGHT0_SIZE"] = "directional_lights.data[0].color_size.w";
+ actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
+ actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction_energy.xyz";
+ actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].direction_energy.w";
+ actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color_size.xyz";
+ actions.renames["LIGHT1_SIZE"] = "directional_lights.data[1].color_size.w";
+ actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
+ actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction_energy.xyz";
+ actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].direction_energy.w";
+ actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color_size.xyz";
+ actions.renames["LIGHT2_SIZE"] = "directional_lights.data[2].color_size.w";
+ actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
+ actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction_energy.xyz";
+ actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].direction_energy.w";
+ actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color_size.xyz";
+ actions.renames["LIGHT3_SIZE"] = "directional_lights.data[3].color_size.w";
+ 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.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.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = 1;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+
+ sky_shader.compiler.initialize(actions);
+ }
+
+ {
+ // default material and shader for sky shader
+ sky_shader.default_shader = storage->shader_allocate();
+ storage->shader_initialize(sky_shader.default_shader);
+
+ storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void sky() { COLOR = vec3(0.0); } \n");
+
+ sky_shader.default_material = storage->material_allocate();
+ storage->material_initialize(sky_shader.default_material);
+
+ storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
+
+ SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY);
+ sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
+
+ sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 0;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.push_back(vfog);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+ }
+
+ {
+ // Need defaults for using fog with clear color
+ sky_scene_state.fog_shader = storage->shader_allocate();
+ storage->shader_initialize(sky_scene_state.fog_shader);
+
+ storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void sky() { COLOR = clear_color.rgb; } \n");
+ sky_scene_state.fog_material = storage->material_allocate();
+ storage->material_initialize(sky_scene_state.fog_material);
+
+ storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
+ }
+}
+
+void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+ ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky...
+
+ SkyMaterialData *material = nullptr;
+ Sky *sky = get_sky(p_env->sky);
+
+ RID sky_material;
+
+ SkyShaderData *shader_data = nullptr;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ // !BAS! Possibly silently fail here, we now get error spam when you select sky as the background but haven't setup the sky yet.
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+ }
+
+ if (sky) {
+ // Invalidate supbass buffers if screen size changes
+ if (sky->screen_size != p_screen_size) {
+ sky->screen_size = p_screen_size;
+ sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
+ sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
+ if (shader_data->uses_half_res) {
+ if (sky->half_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->half_res_pass);
+ sky->half_res_pass = RID();
+ }
+ invalidate_sky(sky);
+ }
+ if (shader_data->uses_quarter_res) {
+ if (sky->quarter_res_pass.is_valid()) {
+ RD::get_singleton()->free(sky->quarter_res_pass);
+ sky->quarter_res_pass = RID();
+ }
+ invalidate_sky(sky);
+ }
+ }
+
+ // Create new subpass buffers if necessary
+ if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
+ (shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
+ sky->radiance.is_null()) {
+ invalidate_sky(sky);
+ update_dirty_skys();
+ }
+
+ if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) {
+ sky->prev_time = p_scene_render->time;
+ sky->reflection.dirty = true;
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (material != sky->prev_material) {
+ sky->prev_material = material;
+ sky->reflection.dirty = true;
+ }
+
+ if (material->uniform_set_updated) {
+ material->uniform_set_updated = false;
+ sky->reflection.dirty = true;
+ }
+
+ if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_transform.origin;
+ sky->reflection.dirty = true;
+ }
+
+ if (shader_data->uses_light) {
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ 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;
+ }
+ }
+ 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);
+
+ 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;
+ sky->reflection.dirty = true;
+ }
+ }
+ }
+
+ //setup fog variables
+ sky_scene_state.ubo.volumetric_fog_enabled = false;
+ if (p_render_buffers.is_valid()) {
+ if (p_scene_render->render_buffers_has_volumetric_fog(p_render_buffers)) {
+ sky_scene_state.ubo.volumetric_fog_enabled = true;
+
+ float fog_end = p_scene_render->render_buffers_get_volumetric_fog_end(p_render_buffers);
+ if (fog_end > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = p_scene_render->render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
+ }
+
+ RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
+
+ if (fog_uniform_set != RID()) {
+ sky_scene_state.fog_uniform_set = fog_uniform_set;
+ } else {
+ sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
+ }
+ }
+
+ sky_scene_state.ubo.z_far = p_projection.get_z_far();
+ sky_scene_state.ubo.fog_enabled = p_env->fog_enabled;
+ sky_scene_state.ubo.fog_density = p_env->fog_density;
+ sky_scene_state.ubo.fog_aerial_perspective = p_env->fog_aerial_perspective;
+ Color fog_color = p_env->fog_light_color.to_linear();
+ float fog_energy = p_env->fog_light_energy;
+ sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+ sky_scene_state.ubo.fog_sun_scatter = p_env->fog_sun_scatter;
+
+ RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
+}
+
+void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ RID sky_material = sky_get_material(p_env->sky);
+
+ SkyMaterialData *material = nullptr;
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ float multiplier = p_env->bg_energy;
+
+ bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
+ RS::SkyMode sky_mode = sky->mode;
+
+ if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
+ if (shader_data->uses_time || shader_data->uses_position) {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_REALTIME;
+ } else if (shader_data->uses_light || shader_data->ubo_size > 0) {
+ update_single_frame = false;
+ sky_mode = RS::SKY_MODE_INCREMENTAL;
+ } else {
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+ }
+
+ if (sky->processing_layer == 0 && sky_mode == RS::SKY_MODE_INCREMENTAL) {
+ // On the first frame after creating sky, rebuild in single frame
+ update_single_frame = true;
+ sky_mode = RS::SKY_MODE_QUALITY;
+ }
+
+ int max_processing_layer = sky_use_cubemap_array ? sky->reflection.layers.size() : sky->reflection.layers[0].mipmaps.size();
+
+ // Update radiance cubemap
+ if (sky->reflection.dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
+ static const Vector3 view_normals[6] = {
+ Vector3(+1, 0, 0),
+ Vector3(-1, 0, 0),
+ Vector3(0, +1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1)
+ };
+ static const Vector3 view_up[6] = {
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0),
+ Vector3(0, 0, +1),
+ Vector3(0, 0, -1),
+ Vector3(0, -1, 0),
+ Vector3(0, -1, 0)
+ };
+
+ CameraMatrix cm;
+ cm.set_perspective(90, 1, 0.01, 10.0);
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ cm = correction * cm;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+ RD::DrawListID cubemap_draw_list;
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+ RD::DrawListID cubemap_draw_list;
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ RD::DrawListID cubemap_draw_list;
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
+
+ for (int i = 0; i < 6; i++) {
+ Transform local_view;
+ local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
+
+ cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (sky_mode == RS::SKY_MODE_REALTIME) {
+ sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size());
+ }
+ } else {
+ if (update_single_frame) {
+ for (int i = 1; i < max_processing_layer; i++) {
+ sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, i, sky_ggx_samples_quality);
+ }
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, 0, sky->reflection.layers.size());
+ }
+ } else {
+ if (sky_use_cubemap_array) {
+ // Multi-Frame so just update the first array level
+ sky->reflection.update_reflection_mipmaps(storage, 0, 1);
+ }
+ }
+ sky->processing_layer = 1;
+ }
+
+ sky->reflection.dirty = false;
+
+ } else {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
+ sky->reflection.create_reflection_importance_sample(storage, sky_use_cubemap_array, 10, sky->processing_layer, sky_ggx_samples_quality);
+
+ if (sky_use_cubemap_array) {
+ sky->reflection.update_reflection_mipmaps(storage, sky->processing_layer, sky->processing_layer + 1);
+ }
+
+ sky->processing_layer++;
+ }
+ }
+}
+
+void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+ ERR_FAIL_COND(!p_env);
+
+ Sky *sky = get_sky(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ SkyMaterialData *material = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky_get_material(p_env->sky);
+
+ if (sky_material.is_valid()) {
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ sky_material = sky_shader.default_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+ }
+
+ if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_scene_state.fog_material;
+ material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+
+ float multiplier = p_env->bg_energy;
+ float custom_fov = p_env->sky_custom_fov;
+ // Camera
+ CameraMatrix camera;
+
+ if (custom_fov) {
+ float near_plane = p_projection.get_z_near();
+ float far_plane = p_projection.get_z_far();
+ float aspect = p_projection.get_aspect();
+
+ camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+
+ } else {
+ camera = p_projection;
+ }
+
+ sky_transform = p_transform.basis * sky_transform;
+
+ if (shader_data->uses_quarter_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (shader_data->uses_half_res) {
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
+
+ RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+
+ Vector<Color> clear_colors;
+ clear_colors.push_back(Color(0.0, 0.0, 0.0));
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
+
+ RID texture_uniform_set;
+ if (sky) {
+ texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+ } else {
+ texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+ }
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
+ storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) {
+ if (!p_sky->dirty) {
+ p_sky->dirty = true;
+ p_sky->dirty_list = dirty_sky_list;
+ dirty_sky_list = p_sky;
+ }
+}
+
+void RendererSceneSkyRD::update_dirty_skys() {
+ Sky *sky = dirty_sky_list;
+
+ while (sky) {
+ bool texture_set_dirty = false;
+ //update sky configuration if texture is missing
+
+ if (sky->radiance.is_null()) {
+ int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
+
+ uint32_t w = sky->radiance_size, h = sky->radiance_size;
+ int layers = roughness_layers;
+ if (sky->mode == RS::SKY_MODE_REALTIME) {
+ layers = 8;
+ if (roughness_layers != 8) {
+ WARN_PRINT("When using REALTIME skies, roughness_layers should be set to 8 in the project settings for best quality reflections");
+ }
+ }
+
+ if (sky_use_cubemap_array) {
+ //array (higher quality, 6 times more memory)
+ RD::TextureFormat tf;
+ tf.array_layers = layers * 6;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+ tf.mipmaps = mipmaps;
+ tf.width = w;
+ tf.height = h;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+
+ } else {
+ //regular cubemap, lower quality (aliasing, less memory)
+ RD::TextureFormat tf;
+ tf.array_layers = 6;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE;
+ tf.mipmaps = MIN(mipmaps, layers);
+ tf.width = w;
+ tf.height = h;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+ }
+ texture_set_dirty = true;
+ }
+
+ // Create subpass buffers if they haven't been created already
+ if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.width = sky->screen_size.x / 2;
+ tformat.height = sky->screen_size.y / 2;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D;
+
+ sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+ Vector<RID> texs;
+ texs.push_back(sky->half_res_pass);
+ sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
+ texture_set_dirty = true;
+ }
+
+ if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tformat.width = sky->screen_size.x / 4;
+ tformat.height = sky->screen_size.y / 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D;
+
+ sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+ Vector<RID> texs;
+ texs.push_back(sky->quarter_res_pass);
+ sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
+ texture_set_dirty = true;
+ }
+
+ if (texture_set_dirty) {
+ for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
+ if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
+ RD::get_singleton()->free(sky->texture_uniform_sets[i]);
+ sky->texture_uniform_sets[i] = RID();
+ }
+ }
+ }
+
+ sky->reflection.dirty = true;
+ sky->processing_layer = 0;
+
+ Sky *next = sky->dirty_list;
+ sky->dirty_list = nullptr;
+ sky->dirty = false;
+ sky = next;
+ }
+
+ dirty_sky_list = nullptr;
+}
+
+RID RendererSceneSkyRD::sky_get_material(RID p_sky) const {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, RID());
+
+ return sky->material;
+}
+
+RID RendererSceneSkyRD::allocate_sky_rid() {
+ return sky_owner.allocate_rid();
+}
+
+void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) {
+ sky_owner.initialize_rid(p_rid, Sky());
+}
+
+RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const {
+ return sky_owner.getornull(p_sky);
+}
+
+void RendererSceneSkyRD::free_sky(RID p_sky) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ sky->free(storage);
+ sky_owner.free(p_sky);
+}
+
+void RendererSceneSkyRD::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_radiance_size(p_radiance_size)) {
+ invalidate_sky(sky);
+ }
+}
+
+void RendererSceneSkyRD::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_mode(p_mode)) {
+ invalidate_sky(sky);
+ }
+}
+
+void RendererSceneSkyRD::sky_set_material(RID p_sky, RID p_material) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->set_material(p_material)) {
+ invalidate_sky(sky);
+ }
+}
+
+Ref<Image> RendererSceneSkyRD::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, Ref<Image>());
+
+ update_dirty_skys();
+
+ return sky->bake_panorama(storage, p_energy, p_bake_irradiance ? roughness_layers : 0, p_size);
+}
+
+RID RendererSceneSkyRD::sky_get_radiance_texture_rd(RID p_sky) const {
+ Sky *sky = get_sky(p_sky);
+ ERR_FAIL_COND_V(!sky, RID());
+
+ return sky->radiance;
+}
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
new file mode 100644
index 0000000000..73390a586b
--- /dev/null
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
@@ -0,0 +1,292 @@
+/*************************************************************************/
+/* renderer_scene_sky_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERING_SERVER_SCENE_SKY_RD_H
+#define RENDERING_SERVER_SCENE_SKY_RD_H
+
+#include "core/templates/rid_owner.h"
+#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/renderer_scene_environment_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/sky.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
+class RendererSceneRenderRD;
+
+class RendererSceneSkyRD {
+private:
+ RendererStorageRD *storage;
+
+public:
+ enum SkySet {
+ SKY_SET_UNIFORMS,
+ SKY_SET_MATERIAL,
+ SKY_SET_TEXTURES,
+ SKY_SET_FOG,
+ SKY_SET_MAX
+ };
+
+ enum SkyTextureSetVersion {
+ SKY_TEXTURE_SET_BACKGROUND,
+ SKY_TEXTURE_SET_HALF_RES,
+ SKY_TEXTURE_SET_QUARTER_RES,
+ SKY_TEXTURE_SET_CUBEMAP,
+ SKY_TEXTURE_SET_CUBEMAP_HALF_RES,
+ SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES,
+ SKY_TEXTURE_SET_MAX
+ };
+
+ enum SkyVersion {
+ SKY_VERSION_BACKGROUND,
+ SKY_VERSION_HALF_RES,
+ SKY_VERSION_QUARTER_RES,
+ SKY_VERSION_CUBEMAP,
+ SKY_VERSION_CUBEMAP_HALF_RES,
+ SKY_VERSION_CUBEMAP_QUARTER_RES,
+ SKY_VERSION_MAX
+ };
+
+ // Skys need less info from Directional Lights than the normal shaders
+ struct SkyDirectionalLightData {
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ uint32_t enabled;
+ uint32_t pad[3];
+ };
+
+ struct SkySceneState {
+ struct UBO {
+ uint32_t volumetric_fog_enabled;
+ float volumetric_fog_inv_length;
+ float volumetric_fog_detail_spread;
+
+ float fog_aerial_perspective;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ uint32_t fog_enabled;
+ float fog_density;
+
+ float z_far;
+ uint32_t directional_light_count;
+ };
+
+ UBO ubo;
+
+ SkyDirectionalLightData *directional_lights;
+ SkyDirectionalLightData *last_frame_directional_lights;
+ uint32_t max_directional_lights;
+ uint32_t last_frame_directional_light_count;
+ RID directional_light_buffer;
+ RID uniform_set;
+ RID uniform_buffer;
+ RID fog_uniform_set;
+ RID default_fog_uniform_set;
+
+ RID fog_shader;
+ RID fog_material;
+ RID fog_only_texture_uniform_set;
+ } sky_scene_state;
+
+ struct ReflectionData {
+ struct Layer {
+ struct Mipmap {
+ RID framebuffers[6];
+ RID views[6];
+ Size2i size;
+ };
+ Vector<Mipmap> mipmaps; //per-face view
+ Vector<RID> views; // per-cubemap view
+ };
+
+ struct DownsampleLayer {
+ struct Mipmap {
+ RID view;
+ Size2i size;
+ };
+ Vector<Mipmap> mipmaps;
+ };
+
+ RID radiance_base_cubemap; //cubemap for first layer, first cubemap
+ RID downsampled_radiance_cubemap;
+ DownsampleLayer downsampled_layer;
+ RID coefficient_buffer;
+
+ bool dirty = true;
+
+ Vector<Layer> layers;
+
+ void clear_reflection_data();
+ void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers);
+ void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
+ void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
+ void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
+ };
+
+ struct SkyShaderData : public RendererStorageRD::ShaderData {
+ bool valid;
+ RID version;
+
+ PipelineCacheRD pipelines[SKY_VERSION_MAX];
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ bool uses_time;
+ bool uses_position;
+ bool uses_half_res;
+ bool uses_quarter_res;
+ bool uses_light;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+ };
+
+ /* Sky shader */
+
+ struct SkyShader {
+ SkyShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID default_shader_rd;
+ } sky_shader;
+
+ struct SkyMaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ SkyShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ bool uniform_set_updated;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~SkyMaterialData();
+ };
+
+ struct Sky {
+ RID radiance;
+ RID half_res_pass;
+ RID half_res_framebuffer;
+ RID quarter_res_pass;
+ RID quarter_res_framebuffer;
+ Size2i screen_size;
+
+ RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
+ RID uniform_set;
+
+ RID material;
+ RID uniform_buffer;
+
+ int radiance_size = 256;
+
+ RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC;
+
+ ReflectionData reflection;
+ bool dirty = false;
+ int processing_layer = 0;
+ Sky *dirty_list = nullptr;
+
+ //State to track when radiance cubemap needs updating
+ SkyMaterialData *prev_material;
+ Vector3 prev_position;
+ float prev_time;
+
+ void free(RendererStorageRD *p_storage);
+
+ RID get_textures(RendererStorageRD *p_storage, SkyTextureSetVersion p_version, RID p_default_shader_rd);
+ bool set_radiance_size(int p_radiance_size);
+ bool set_mode(RS::SkyMode p_mode);
+ bool set_material(RID p_material);
+ Ref<Image> bake_panorama(RendererStorageRD *p_storage, float p_energy, int p_roughness_layers, const Size2i &p_size);
+ };
+
+ uint32_t sky_ggx_samples_quality;
+ bool sky_use_cubemap_array;
+ Sky *dirty_sky_list = nullptr;
+ mutable RID_Owner<Sky, true> sky_owner;
+ int roughness_layers;
+
+ RendererStorageRD::ShaderData *_create_sky_shader_func();
+ static RendererStorageRD::ShaderData *_create_sky_shader_funcs();
+
+ RendererStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader);
+
+ RendererSceneSkyRD();
+
+ void init(RendererStorageRD *p_storage);
+
+ void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+ void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+
+ void invalidate_sky(Sky *p_sky);
+ void update_dirty_skys();
+
+ RID sky_get_material(RID p_sky) const;
+
+ RID allocate_sky_rid();
+ void initialize_sky_rid(RID p_rid);
+ Sky *get_sky(RID p_sky) const;
+ void free_sky(RID p_sky);
+ void sky_set_radiance_size(RID p_sky, int p_radiance_size);
+ void sky_set_mode(RID p_sky, RS::SkyMode p_mode);
+ void sky_set_material(RID p_sky, RID p_material);
+ Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size);
+
+ RID sky_get_radiance_texture_rd(RID p_sky) const;
+};
+
+#endif /* RENDERING_SERVER_SCENE_SKY_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index a1358f94fa..47b9e33ca6 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -36,6 +36,10 @@
#include "renderer_compositor_rd.h"
#include "servers/rendering/shader_language.h"
+bool RendererStorageRD::can_create_resources_async() const {
+ return true;
+}
+
Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
Ref<Image> image = p_image->duplicate();
@@ -535,9 +539,13 @@ Ref<Image> RendererStorageRD::_validate_texture_format(const Ref<Image> &p_image
return image;
}
-RID RendererStorageRD::texture_2d_create(const Ref<Image> &p_image) {
- ERR_FAIL_COND_V(p_image.is_null(), RID());
- ERR_FAIL_COND_V(p_image->is_empty(), RID());
+RID RendererStorageRD::texture_allocate() {
+ return texture_owner.allocate_rid();
+}
+
+void RendererStorageRD::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) {
+ ERR_FAIL_COND(p_image.is_null());
+ ERR_FAIL_COND(p_image->is_empty());
TextureToRDFormat ret_format;
Ref<Image> image = _validate_texture_format(p_image, ret_format);
@@ -585,13 +593,13 @@ RID RendererStorageRD::texture_2d_create(const Ref<Image> &p_image) {
Vector<Vector<uint8_t>> data_slices;
data_slices.push_back(data);
texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices);
- ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture.is_null());
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_view.format_override = texture.rd_format_srgb;
texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture);
if (texture.rd_texture_srgb.is_null()) {
RD::get_singleton()->free(texture.rd_texture);
- ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture_srgb.is_null());
}
}
@@ -602,14 +610,14 @@ RID RendererStorageRD::texture_2d_create(const Ref<Image> &p_image) {
texture.rd_view = rd_view;
texture.is_proxy = false;
- return texture_owner.make_rid(texture);
+ texture_owner.initialize_rid(p_texture, texture);
}
-RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
- ERR_FAIL_COND_V(p_layers.size() == 0, RID());
+void RendererStorageRD::texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
+ ERR_FAIL_COND(p_layers.size() == 0);
- ERR_FAIL_COND_V(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6, RID());
- ERR_FAIL_COND_V(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY && (p_layers.size() < 6 || (p_layers.size() % 6) != 0), RID());
+ ERR_FAIL_COND(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP && p_layers.size() != 6);
+ ERR_FAIL_COND(p_layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY && (p_layers.size() < 6 || (p_layers.size() % 6) != 0));
TextureToRDFormat ret_format;
Vector<Ref<Image>> images;
@@ -620,7 +628,7 @@ RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_lay
Image::Format valid_format = Image::FORMAT_MAX;
for (int i = 0; i < p_layers.size(); i++) {
- ERR_FAIL_COND_V(p_layers[i]->is_empty(), RID());
+ ERR_FAIL_COND(p_layers[i]->is_empty());
if (i == 0) {
valid_width = p_layers[i]->get_width();
@@ -628,10 +636,10 @@ RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_lay
valid_format = p_layers[i]->get_format();
valid_mipmaps = p_layers[i]->has_mipmaps();
} else {
- ERR_FAIL_COND_V(p_layers[i]->get_width() != valid_width, RID());
- ERR_FAIL_COND_V(p_layers[i]->get_height() != valid_height, RID());
- ERR_FAIL_COND_V(p_layers[i]->get_format() != valid_format, RID());
- ERR_FAIL_COND_V(p_layers[i]->has_mipmaps() != valid_mipmaps, RID());
+ ERR_FAIL_COND(p_layers[i]->get_width() != valid_width);
+ ERR_FAIL_COND(p_layers[i]->get_height() != valid_height);
+ ERR_FAIL_COND(p_layers[i]->get_format() != valid_format);
+ ERR_FAIL_COND(p_layers[i]->has_mipmaps() != valid_mipmaps);
}
images.push_back(_validate_texture_format(p_layers[i], ret_format));
@@ -695,13 +703,13 @@ RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_lay
data_slices.push_back(data);
}
texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices);
- ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture.is_null());
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_view.format_override = texture.rd_format_srgb;
texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture);
if (texture.rd_texture_srgb.is_null()) {
RD::get_singleton()->free(texture.rd_texture);
- ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture_srgb.is_null());
}
}
@@ -712,14 +720,14 @@ RID RendererStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_lay
texture.rd_view = rd_view;
texture.is_proxy = false;
- return texture_owner.make_rid(texture);
+ texture_owner.initialize_rid(p_texture, texture);
}
-RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
- ERR_FAIL_COND_V(p_data.size() == 0, RID());
+void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) {
+ ERR_FAIL_COND(p_data.size() == 0);
Image::Image3DValidateError verr = Image::validate_3d_image(p_format, p_width, p_height, p_depth, p_mipmaps, p_data);
if (verr != Image::VALIDATE_3D_OK) {
- ERR_FAIL_V_MSG(RID(), Image::get_3d_image_validation_error_text(verr));
+ ERR_FAIL_MSG(Image::get_3d_image_validation_error_text(verr));
}
TextureToRDFormat ret_format;
@@ -748,7 +756,7 @@ RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, in
for (int i = 0; i < p_data.size(); i++) {
uint32_t s = images[i]->get_data().size();
- copymem(&all_data.write[offset], images[i]->get_data().ptr(), s);
+ memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s);
{
Texture::BufferSlice3D slice;
slice.size.width = images[i]->get_width();
@@ -811,13 +819,13 @@ RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, in
data_slices.push_back(all_data); //one slice
texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices);
- ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture.is_null());
if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
rd_view.format_override = texture.rd_format_srgb;
texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture);
if (texture.rd_texture_srgb.is_null()) {
RD::get_singleton()->free(texture.rd_texture);
- ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID());
+ ERR_FAIL_COND(texture.rd_texture_srgb.is_null());
}
}
@@ -828,12 +836,12 @@ RID RendererStorageRD::texture_3d_create(Image::Format p_format, int p_width, in
texture.rd_view = rd_view;
texture.is_proxy = false;
- return texture_owner.make_rid(texture);
+ texture_owner.initialize_rid(p_texture, texture);
}
-RID RendererStorageRD::texture_proxy_create(RID p_base) {
+void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) {
Texture *tex = texture_owner.getornull(p_base);
- ERR_FAIL_COND_V(!tex, RID());
+ ERR_FAIL_COND(!tex);
Texture proxy_tex = *tex;
proxy_tex.rd_view.format_override = tex->rd_format;
@@ -847,11 +855,9 @@ RID RendererStorageRD::texture_proxy_create(RID p_base) {
proxy_tex.is_proxy = true;
proxy_tex.proxies.clear();
- RID rid = texture_owner.make_rid(proxy_tex);
-
- tex->proxies.push_back(rid);
+ texture_owner.initialize_rid(p_texture, proxy_tex);
- return rid;
+ tex->proxies.push_back(p_texture);
}
void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) {
@@ -913,7 +919,7 @@ void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>
for (int i = 0; i < p_data.size(); i++) {
uint32_t s = images[i]->get_data().size();
- copymem(&all_data.write[offset], images[i]->get_data().ptr(), s);
+ memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s);
offset += s;
}
}
@@ -961,7 +967,7 @@ void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
}
//these two APIs can be used together or in combination with the others.
-RID RendererStorageRD::texture_2d_placeholder_create() {
+void RendererStorageRD::texture_2d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
@@ -974,10 +980,10 @@ RID RendererStorageRD::texture_2d_placeholder_create() {
}
}
- return texture_2d_create(image);
+ texture_2d_initialize(p_texture, image);
}
-RID RendererStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayeredType p_layered_type) {
+void RendererStorageRD::texture_2d_layered_placeholder_initialize(RID p_texture, RS::TextureLayeredType p_layered_type) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
@@ -1000,10 +1006,10 @@ RID RendererStorageRD::texture_2d_layered_placeholder_create(RS::TextureLayeredT
}
}
- return texture_2d_layered_create(images, p_layered_type);
+ texture_2d_layered_initialize(p_texture, images, p_layered_type);
}
-RID RendererStorageRD::texture_3d_placeholder_create() {
+void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
Ref<Image> image;
@@ -1022,7 +1028,7 @@ RID RendererStorageRD::texture_3d_placeholder_create() {
images.push_back(image);
}
- return texture_3d_create(Image::FORMAT_RGBA8, 4, 4, 4, false, images);
+ texture_3d_initialize(p_texture, Image::FORMAT_RGBA8, 4, 4, 4, false, images);
}
Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const {
@@ -1223,8 +1229,11 @@ RendererStorageRD::CanvasTexture::~CanvasTexture() {
clear_sets();
}
-RID RendererStorageRD::canvas_texture_create() {
- return canvas_texture_owner.make_rid(memnew(CanvasTexture));
+RID RendererStorageRD::canvas_texture_allocate() {
+ return canvas_texture_owner.allocate_rid();
+}
+void RendererStorageRD::canvas_texture_initialize(RID p_rid) {
+ canvas_texture_owner.initialize_rid(p_rid, memnew(CanvasTexture));
}
void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
@@ -1365,12 +1374,15 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas
/* SHADER API */
-RID RendererStorageRD::shader_create() {
+RID RendererStorageRD::shader_allocate() {
+ return shader_owner.allocate_rid();
+}
+void RendererStorageRD::shader_initialize(RID p_rid) {
Shader shader;
shader.data = nullptr;
shader.type = SHADER_TYPE_MAX;
- return shader_owner.make_rid(shader);
+ shader_owner.initialize_rid(p_rid, shader);
}
void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
@@ -1510,7 +1522,10 @@ RS::ShaderNativeSourceCode RendererStorageRD::shader_get_native_source_code(RID
/* COMMON MATERIAL API */
-RID RendererStorageRD::material_create() {
+RID RendererStorageRD::material_allocate() {
+ return material_owner.allocate_rid();
+}
+void RendererStorageRD::material_initialize(RID p_rid) {
Material material;
material.data = nullptr;
material.shader = nullptr;
@@ -1520,12 +1535,8 @@ RID RendererStorageRD::material_create() {
material.uniform_dirty = false;
material.texture_dirty = false;
material.priority = 0;
- RID id = material_owner.make_rid(material);
- {
- Material *material_ptr = material_owner.getornull(id);
- material_ptr->self = id;
- }
- return id;
+ material.self = p_rid;
+ material_owner.initialize_rid(p_rid, material);
}
void RendererStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
@@ -2097,13 +2108,13 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_INT:
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_FLOAT: {
- zeromem(data, 4);
+ memset(data, 0, 4);
} break;
case ShaderLanguage::TYPE_BVEC2:
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_UVEC2:
case ShaderLanguage::TYPE_VEC2: {
- zeromem(data, 8);
+ memset(data, 0, 8);
} break;
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
@@ -2113,16 +2124,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
case ShaderLanguage::TYPE_VEC4: {
- zeromem(data, 16);
+ memset(data, 0, 16);
} break;
case ShaderLanguage::TYPE_MAT2: {
- zeromem(data, 32);
+ memset(data, 0, 32);
} break;
case ShaderLanguage::TYPE_MAT3: {
- zeromem(data, 48);
+ memset(data, 0, 48);
} break;
case ShaderLanguage::TYPE_MAT4: {
- zeromem(data, 64);
+ memset(data, 0, 64);
} break;
default: {
@@ -2399,8 +2410,11 @@ void RendererStorageRD::_update_queued_materials() {
/* MESH API */
-RID RendererStorageRD::mesh_create() {
- return mesh_owner.make_rid(Mesh());
+RID RendererStorageRD::mesh_allocate() {
+ return mesh_owner.allocate_rid();
+}
+void RendererStorageRD::mesh_initialize(RID p_rid) {
+ mesh_owner.initialize_rid(p_rid, Mesh());
}
void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) {
@@ -3298,11 +3312,14 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf
////////////////// MULTIMESH
-RID RendererStorageRD::multimesh_create() {
- return multimesh_owner.make_rid(MultiMesh());
+RID RendererStorageRD::multimesh_allocate() {
+ return multimesh_owner.allocate_rid();
+}
+void RendererStorageRD::multimesh_initialize(RID p_rid) {
+ multimesh_owner.initialize_rid(p_rid, MultiMesh());
}
-void RendererStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
+void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
@@ -3395,10 +3412,10 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const {
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
{
const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
+ memcpy(w, r, buffer.size());
}
} else {
- zeromem(w, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float));
}
}
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
@@ -3754,7 +3771,7 @@ Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const {
{
float *w = ret.ptrw();
const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
+ memcpy(w, r, buffer.size());
}
return ret;
@@ -3849,8 +3866,11 @@ void RendererStorageRD::_update_dirty_multimeshes() {
/* PARTICLES */
-RID RendererStorageRD::particles_create() {
- return particles_owner.make_rid(Particles());
+RID RendererStorageRD::particles_allocate() {
+ return particles_owner.allocate_rid();
+}
+void RendererStorageRD::particles_initialize(RID p_rid) {
+ particles_owner.initialize_rid(p_rid, Particles());
}
void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) {
@@ -3868,22 +3888,37 @@ bool RendererStorageRD::particles_get_emitting(RID p_particles) {
}
void RendererStorageRD::_particles_free_data(Particles *particles) {
- if (!particles->particle_buffer.is_valid()) {
- return;
+ if (particles->particle_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->particle_buffer);
+ particles->particle_buffer = RID();
+ RD::get_singleton()->free(particles->particle_instance_buffer);
+ particles->particle_instance_buffer = RID();
+ }
+
+ if (particles->frame_params_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ particles->frame_params_buffer = RID();
}
- RD::get_singleton()->free(particles->particle_buffer);
- RD::get_singleton()->free(particles->frame_params_buffer);
- RD::get_singleton()->free(particles->particle_instance_buffer);
particles->particles_transforms_buffer_uniform_set = RID();
- particles->particle_buffer = RID();
+ if (RD::get_singleton()->uniform_set_is_valid(particles->trail_bind_pose_uniform_set)) {
+ RD::get_singleton()->free(particles->trail_bind_pose_uniform_set);
+ }
+ particles->trail_bind_pose_uniform_set = RID();
+
+ if (particles->trail_bind_pose_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->trail_bind_pose_buffer);
+ particles->trail_bind_pose_buffer = RID();
+ }
if (RD::get_singleton()->uniform_set_is_valid(particles->collision_textures_uniform_set)) {
RD::get_singleton()->free(particles->collision_textures_uniform_set);
}
+ particles->collision_textures_uniform_set = RID();
if (particles->particles_sort_buffer.is_valid()) {
RD::get_singleton()->free(particles->particles_sort_buffer);
particles->particles_sort_buffer = RID();
+ particles->particles_sort_uniform_set = RID();
}
if (particles->emission_buffer != nullptr) {
@@ -3892,6 +3927,12 @@ void RendererStorageRD::_particles_free_data(Particles *particles) {
RD::get_singleton()->free(particles->emission_storage_buffer);
particles->emission_storage_buffer = RID();
}
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ //will need to be re-created
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ }
+ particles->particles_material_uniform_set = RID();
}
void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
@@ -3906,38 +3947,12 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
particles->amount = p_amount;
- if (particles->amount > 0) {
- particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount);
- particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * 1);
- particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * p_amount);
- //needs to clear it
-
- {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(particles->particle_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 2;
- u.ids.push_back(particles->particle_instance_buffer);
- uniforms.push_back(u);
- }
-
- particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
- }
- }
-
particles->prev_ticks = 0;
particles->phase = 0;
particles->prev_phase = 0;
particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) {
@@ -3993,6 +4008,22 @@ void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) {
ERR_FAIL_COND(!particles);
particles->fixed_fps = p_fps;
+
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
+void RendererStorageRD::particles_set_interpolate(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->interpolate = p_enable;
}
void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) {
@@ -4002,6 +4033,42 @@ void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_e
particles->fractional_delta = p_enable;
}
+void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, float p_length) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(p_length < 0.1);
+ p_length = MIN(10.0, p_length);
+
+ particles->trails_enabled = p_enable;
+ particles->trail_length = p_length;
+
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
+void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) {
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ }
+ particles->trail_bind_poses = p_bind_poses;
+ particles->trail_bind_poses_dirty = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4009,6 +4076,13 @@ void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float
particles->collision_base_size = p_size;
}
+void RendererStorageRD::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->transform_align = p_transform_align;
+}
+
void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4048,7 +4122,7 @@ void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles
ERR_FAIL_COND(particles->emission_buffer != nullptr);
particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4);
- zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size());
+ memset(particles->emission_buffer_data.ptrw(), 0, particles->emission_buffer_data.size());
particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw();
particles->emission_buffer->particle_max = particles->amount;
@@ -4132,8 +4206,13 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
const Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, AABB());
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
Vector<ParticleData> data;
- data.resize(particles->amount);
+ data.resize(total_amount);
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer);
@@ -4142,8 +4221,9 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
AABB aabb;
if (buffer.size()) {
bool first = true;
+
const ParticleData *particle_data = (const ParticleData *)data.ptr();
- for (int i = 0; i < particles->amount; i++) {
+ for (int i = 0; i < total_amount; i++) {
if (particle_data[i].active) {
Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]);
if (!particles->use_local_coords) {
@@ -4204,14 +4284,12 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass)
void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
-
particles->collisions.insert(p_particles_collision_instance);
}
void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
-
particles->collisions.erase(p_particles_collision_instance);
}
@@ -4266,7 +4344,12 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
- ParticlesFrameParams &frame_params = p_particles->frame_params;
+ //move back history (if there is any)
+ for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) {
+ p_particles->frame_history[i] = p_particles->frame_history[i - 1];
+ }
+ //update current frame
+ ParticlesFrameParams &frame_params = p_particles->frame_history[0];
if (p_particles->clear) {
p_particles->cycle_number = 0;
@@ -4297,6 +4380,10 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
}
frame_params.cycle = p_particles->cycle_number;
+ frame_params.frame = p_particles->frame_counter++;
+ frame_params.pad0 = 0;
+ frame_params.pad1 = 0;
+ frame_params.pad2 = 0;
{ //collision and attractors
@@ -4495,12 +4582,18 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
ParticlesShader::PushConstant push_constant;
+ int process_amount = p_particles->amount;
+
+ if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) {
+ process_amount *= p_particles->trail_bind_poses.size();
+ }
push_constant.clear = p_particles->clear;
push_constant.total_particles = p_particles->amount;
push_constant.lifetime = p_particles->lifetime;
- push_constant.trail_size = 1;
+ push_constant.trail_size = p_particles->trail_params.size();
push_constant.use_fractional_delta = p_particles->fractional_delta;
push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit);
+ push_constant.trail_pass = false;
p_particles->force_sub_emit = false; //reset
@@ -4533,7 +4626,17 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
p_particles->clear = false;
- RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params);
+ if (p_particles->trail_params.size() > 1) {
+ //fill the trail params
+ for (uint32_t i = 0; i < p_particles->trail_params.size(); i++) {
+ uint32_t src_idx = i * p_particles->frame_history.size() / p_particles->trail_params.size();
+ p_particles->trail_params[i] = p_particles->frame_history[src_idx];
+ }
+ } else {
+ p_particles->trail_params[0] = p_particles->frame_history[0];
+ }
+
+ RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr());
ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES);
if (!m) {
@@ -4555,27 +4658,45 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1);
+ if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) {
+ //trails requires two passes in order to catch particle starts
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount / p_particles->trail_bind_poses.size(), 1, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ push_constant.trail_pass = true;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount - p_particles->amount, 1, 1);
+ } else {
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount, 1, 1);
+ }
RD::get_singleton()->compute_list_end();
}
-void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) {
+void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
- if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
- return; //uninteresting for other modes
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ return;
}
+ if (particles->particle_buffer.is_null()) {
+ return; //particles have not processed yet
+ }
+
+ bool do_sort = particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH;
+
//copy to sort buffer
- if (particles->particles_sort_buffer == RID()) {
+ if (do_sort && particles->particles_sort_buffer == RID()) {
uint32_t size = particles->amount;
if (size & 1) {
size++; //make multiple of 16
}
size *= sizeof(float) * 2;
particles->particles_sort_buffer = RD::get_singleton()->storage_buffer_create(size);
+
{
Vector<RD::Uniform> uniforms;
@@ -4591,41 +4712,105 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
}
}
+ ParticlesShader::CopyPushConstant copy_push_constant;
+
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ int fixed_fps = 60.0;
+ if (particles->fixed_fps > 0) {
+ fixed_fps = particles->fixed_fps;
+ }
+
+ copy_push_constant.trail_size = particles->trail_bind_poses.size();
+ copy_push_constant.trail_total = particles->frame_history.size();
+ copy_push_constant.frame_delta = 1.0 / fixed_fps;
+ } else {
+ copy_push_constant.trail_size = 1;
+ copy_push_constant.trail_total = 1;
+ copy_push_constant.frame_delta = 0.0;
+ }
+ copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
+ copy_push_constant.total_particles = particles->amount;
+
Vector3 axis = -p_axis; // cameras look to z negative
if (particles->use_local_coords) {
axis = particles->emission_transform.basis.xform_inv(axis).normalized();
}
- ParticlesShader::CopyPushConstant copy_push_constant;
- copy_push_constant.total_particles = particles->amount;
copy_push_constant.sort_direction[0] = axis.x;
copy_push_constant.sort_direction[1] = axis.y;
copy_push_constant.sort_direction[2] = axis.z;
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+ copy_push_constant.align_up[0] = p_up_axis.x;
+ copy_push_constant.align_up[1] = p_up_axis.y;
+ copy_push_constant.align_up[2] = p_up_axis.z;
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ copy_push_constant.align_mode = particles->transform_align;
- RD::get_singleton()->compute_list_end();
+ if (do_sort) {
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+ effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ }
- effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ copy_push_constant.total_particles *= copy_push_constant.total_particles;
- compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER]);
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ if (do_sort) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
+
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, copy_push_constant.total_particles, 1, 1);
RD::get_singleton()->compute_list_end();
}
+void RendererStorageRD::_particles_update_buffers(Particles *particles) {
+ if (particles->amount > 0 && particles->particle_buffer.is_null()) {
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+ particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * total_amount);
+ particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * total_amount);
+ //needs to clear it
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(particles->particle_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(particles->particle_instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
+ }
+ }
+}
void RendererStorageRD::update_particles() {
while (particle_update_list) {
//use transform feedback to process particles
@@ -4637,6 +4822,8 @@ void RendererStorageRD::update_particles() {
particles->update_list = nullptr;
particles->dirty = false;
+ _particles_update_buffers(particles);
+
if (particles->restart_request) {
particles->prev_ticks = 0;
particles->phase = 0;
@@ -4668,14 +4855,84 @@ void RendererStorageRD::update_particles() {
}
}
+#ifndef _MSC_VER
+#warning Should use display refresh rate for all this
+#endif
+
+ float screen_hz = 60;
+
+ int fixed_fps = 0;
+ if (particles->fixed_fps > 0) {
+ fixed_fps = particles->fixed_fps;
+ } else if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ fixed_fps = screen_hz;
+ }
+ {
+ //update trails
+ int history_size = 1;
+ int trail_steps = 1;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ history_size = MAX(1, int(particles->trail_length * fixed_fps));
+ trail_steps = particles->trail_bind_poses.size();
+ }
+
+ if (uint32_t(history_size) != particles->frame_history.size()) {
+ particles->frame_history.resize(history_size);
+ memset(particles->frame_history.ptr(), 0, sizeof(ParticlesFrameParams) * history_size);
+ }
+
+ if (uint32_t(trail_steps) != particles->trail_params.size() || particles->frame_params_buffer.is_null()) {
+ particles->trail_params.resize(trail_steps);
+ if (particles->frame_params_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ }
+ particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * trail_steps);
+ }
+
+ if (particles->trail_bind_poses.size() > 1 && particles->trail_bind_pose_buffer.is_null()) {
+ particles->trail_bind_pose_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 16 * particles->trail_bind_poses.size());
+ particles->trail_bind_poses_dirty = true;
+ }
+
+ if (particles->trail_bind_pose_uniform_set.is_null()) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ if (particles->trail_bind_pose_buffer.is_valid()) {
+ u.ids.push_back(particles->trail_bind_pose_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+
+ particles->trail_bind_pose_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 2);
+ }
+
+ if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses_dirty) {
+ if (particles_shader.pose_update_buffer.size() < uint32_t(particles->trail_bind_poses.size()) * 16) {
+ particles_shader.pose_update_buffer.resize(particles->trail_bind_poses.size() * 16);
+ }
+
+ for (int i = 0; i < particles->trail_bind_poses.size(); i++) {
+ store_transform(particles->trail_bind_poses[i], &particles_shader.pose_update_buffer[i * 16]);
+ }
+
+ RD::get_singleton()->buffer_update(particles->trail_bind_pose_buffer, 0, particles->trail_bind_poses.size() * 16 * sizeof(float), particles_shader.pose_update_buffer.ptr());
+ }
+ }
+
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
if (particles->clear && particles->pre_process_time > 0.0) {
float frame_time;
- if (particles->fixed_fps > 0)
- frame_time = 1.0 / particles->fixed_fps;
- else
+ if (fixed_fps > 0) {
+ frame_time = 1.0 / fixed_fps;
+ } else {
frame_time = 1.0 / 30.0;
+ }
float todo = particles->pre_process_time;
@@ -4685,14 +4942,14 @@ void RendererStorageRD::update_particles() {
}
}
- if (particles->fixed_fps > 0) {
+ if (fixed_fps > 0) {
float frame_time;
float decr;
if (zero_time_scale) {
frame_time = 0.0;
- decr = 1.0 / particles->fixed_fps;
+ decr = 1.0 / fixed_fps;
} else {
- frame_time = 1.0 / particles->fixed_fps;
+ frame_time = 1.0 / fixed_fps;
decr = frame_time;
}
float delta = RendererCompositorRD::singleton->get_frame_delta_time();
@@ -4711,24 +4968,48 @@ void RendererStorageRD::update_particles() {
particles->frame_remainder = todo;
} else {
- if (zero_time_scale)
+ if (zero_time_scale) {
_particles_process(particles, 0.0);
- else
+ } else {
_particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
+ }
}
//copy particles to instance buffer
- if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ //does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
- copy_push_constant.total_particles = particles->amount;
+
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
+ copy_push_constant.total_particles = total_amount;
+ copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
+ copy_push_constant.align_mode = particles->transform_align;
+ copy_push_constant.align_up[0] = 0;
+ copy_push_constant.align_up[1] = 0;
+ copy_push_constant.align_up[2] = 0;
+
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ copy_push_constant.trail_size = particles->trail_bind_poses.size();
+ copy_push_constant.trail_total = particles->frame_history.size();
+ copy_push_constant.frame_delta = 1.0 / fixed_fps;
+ } else {
+ copy_push_constant.trail_size = 1;
+ copy_push_constant.trail_total = 1;
+ copy_push_constant.frame_delta = 0.0;
+ }
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, total_amount, 1, 1);
RD::get_singleton()->compute_list_end();
}
@@ -4759,6 +5040,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
ShaderCompilerRD::GeneratedCode gen_code;
ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["start"] = ShaderCompilerRD::STAGE_COMPUTE;
+ actions.entry_point_stages["process"] = ShaderCompilerRD::STAGE_COMPUTE;
/*
uses_time = false;
@@ -4779,7 +5062,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
version = base_singleton->particles_shader.shader.version_create();
}
- base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.uniforms, gen_code.compute_global, gen_code.compute, gen_code.defines);
+ base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines);
ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
@@ -4984,8 +5267,11 @@ RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_f
/* PARTICLES COLLISION API */
-RID RendererStorageRD::particles_collision_create() {
- return particles_collision_owner.make_rid(ParticlesCollision());
+RID RendererStorageRD::particles_collision_allocate() {
+ return particles_collision_owner.allocate_rid();
+}
+void RendererStorageRD::particles_collision_initialize(RID p_rid) {
+ particles_collision_owner.initialize_rid(p_rid, ParticlesCollision());
}
RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
@@ -5098,6 +5384,7 @@ void RendererStorageRD::particles_collision_height_field_update(RID p_particles_
void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision);
ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
if (particles_collision->heightfield_resolution == p_resolution) {
return;
@@ -5164,8 +5451,11 @@ void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_
/* SKELETON API */
-RID RendererStorageRD::skeleton_create() {
- return skeleton_owner.make_rid(Skeleton());
+RID RendererStorageRD::skeleton_allocate() {
+ return skeleton_owner.allocate_rid();
+}
+void RendererStorageRD::skeleton_initialize(RID p_rid) {
+ skeleton_owner.initialize_rid(p_rid, Skeleton());
}
void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) {
@@ -5176,7 +5466,7 @@ void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) {
}
}
-void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(!skeleton);
ERR_FAIL_COND(p_bones < 0);
@@ -5199,7 +5489,7 @@ void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d
if (skeleton->size) {
skeleton->data.resize(skeleton->size * (skeleton->use_2d ? 8 : 12));
skeleton->buffer = RD::get_singleton()->storage_buffer_create(skeleton->data.size() * sizeof(float));
- zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float));
+ memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
_skeleton_make_dirty(skeleton);
@@ -5350,7 +5640,7 @@ void RendererStorageRD::_update_dirty_skeletons() {
/* LIGHT */
-RID RendererStorageRD::light_create(RS::LightType p_type) {
+void RendererStorageRD::_light_initialize(RID p_light, RS::LightType p_type) {
Light light;
light.type = p_type;
@@ -5374,7 +5664,28 @@ RID RendererStorageRD::light_create(RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1;
light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
- return light_owner.make_rid(light);
+ light_owner.initialize_rid(p_light, light);
+}
+
+RID RendererStorageRD::directional_light_allocate() {
+ return light_owner.allocate_rid();
+}
+void RendererStorageRD::directional_light_initialize(RID p_light) {
+ _light_initialize(p_light, RS::LIGHT_DIRECTIONAL);
+}
+
+RID RendererStorageRD::omni_light_allocate() {
+ return light_owner.allocate_rid();
+}
+void RendererStorageRD::omni_light_initialize(RID p_light) {
+ _light_initialize(p_light, RS::LIGHT_OMNI);
+}
+
+RID RendererStorageRD::spot_light_allocate() {
+ return light_owner.allocate_rid();
+}
+void RendererStorageRD::spot_light_initialize(RID p_light) {
+ _light_initialize(p_light, RS::LIGHT_SPOT);
}
void RendererStorageRD::light_set_color(RID p_light, const Color &p_color) {
@@ -5612,8 +5923,11 @@ AABB RendererStorageRD::light_get_aabb(RID p_light) const {
/* REFLECTION PROBE */
-RID RendererStorageRD::reflection_probe_create() {
- return reflection_probe_owner.make_rid(ReflectionProbe());
+RID RendererStorageRD::reflection_probe_allocate() {
+ return reflection_probe_owner.allocate_rid();
+}
+void RendererStorageRD::reflection_probe_initialize(RID p_reflection_probe) {
+ reflection_probe_owner.initialize_rid(p_reflection_probe, ReflectionProbe());
}
void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
@@ -5835,8 +6149,11 @@ float RendererStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe)
return reflection_probe->ambient_color_energy;
}
-RID RendererStorageRD::decal_create() {
- return decal_owner.make_rid(Decal());
+RID RendererStorageRD::decal_allocate() {
+ return decal_owner.allocate_rid();
+}
+void RendererStorageRD::decal_initialize(RID p_decal) {
+ decal_owner.initialize_rid(p_decal, Decal());
}
void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
@@ -5923,11 +6240,14 @@ AABB RendererStorageRD::decal_get_aabb(RID p_decal) const {
return AABB(-decal->extents, decal->extents * 2.0);
}
-RID RendererStorageRD::gi_probe_create() {
- return gi_probe_owner.make_rid(GIProbe());
+RID RendererStorageRD::gi_probe_allocate() {
+ return gi_probe_owner.allocate_rid();
+}
+void RendererStorageRD::gi_probe_initialize(RID p_gi_probe) {
+ gi_probe_owner.initialize_rid(p_gi_probe, GIProbe());
}
-void RendererStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
+void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
ERR_FAIL_COND(!gi_probe);
@@ -6276,8 +6596,12 @@ RID RendererStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
/* LIGHTMAP API */
-RID RendererStorageRD::lightmap_create() {
- return lightmap_owner.make_rid(Lightmap());
+RID RendererStorageRD::lightmap_allocate() {
+ return lightmap_owner.allocate_rid();
+}
+
+void RendererStorageRD::lightmap_initialize(RID p_lightmap) {
+ lightmap_owner.initialize_rid(p_lightmap, Lightmap());
}
void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
@@ -6480,7 +6804,8 @@ void RendererStorageRD::_clear_render_target(RenderTarget *rt) {
void RendererStorageRD::_update_render_target(RenderTarget *rt) {
if (rt->texture.is_null()) {
//create a placeholder until updated
- rt->texture = texture_2d_placeholder_create();
+ rt->texture = texture_allocate();
+ texture_2d_placeholder_initialize(rt->texture);
Texture *tex = texture_owner.getornull(rt->texture);
tex->is_render_target = true;
}
@@ -6806,7 +7131,7 @@ RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) {
Vector<uint8_t> pv;
pv.resize(16 * 4);
- zeromem(pv.ptrw(), 16 * 4);
+ memset(pv.ptrw(), 0, 16 * 4);
Vector<Vector<uint8_t>> vpv;
rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
@@ -7293,7 +7618,7 @@ void RendererStorageRD::_update_decal_atlas() {
v_offsetsv.resize(base_size);
int *v_offsets = v_offsetsv.ptrw();
- zeromem(v_offsets, sizeof(int) * base_size);
+ memset(v_offsets, 0, sizeof(int) * base_size);
int max_height = 0;
@@ -7857,7 +8182,6 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
} else {
//texture
- //texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material);
@@ -8050,7 +8374,7 @@ void RendererStorageRD::_update_global_variables() {
if (total_regions / global_variables.buffer_dirty_region_count <= 4) {
// 25% of regions dirty, just update all buffer
RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values);
- zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions);
+ memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * total_regions);
} else {
uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
@@ -8217,13 +8541,13 @@ bool RendererStorageRD::free(RID p_rid) {
} else if (multimesh_owner.owns(p_rid)) {
_update_dirty_multimeshes();
- multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
+ multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
MultiMesh *multimesh = multimesh_owner.getornull(p_rid);
multimesh->dependency.deleted_notify(p_rid);
multimesh_owner.free(p_rid);
} else if (skeleton_owner.owns(p_rid)) {
_update_dirty_skeletons();
- skeleton_allocate(p_rid, 0);
+ skeleton_allocate_data(p_rid, 0);
Skeleton *skeleton = skeleton_owner.getornull(p_rid);
skeleton->dependency.deleted_notify(p_rid);
skeleton_owner.free(p_rid);
@@ -8241,7 +8565,7 @@ bool RendererStorageRD::free(RID p_rid) {
decal->dependency.deleted_notify(p_rid);
decal_owner.free(p_rid);
} else if (gi_probe_owner.owns(p_rid)) {
- gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
+ gi_probe_allocate_data(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
gi_probe->dependency.deleted_notify(p_rid);
gi_probe_owner.free(p_rid);
@@ -8259,9 +8583,10 @@ bool RendererStorageRD::free(RID p_rid) {
light_owner.free(p_rid);
} else if (particles_owner.owns(p_rid)) {
+ update_particles();
Particles *particles = particles_owner.getornull(p_rid);
- _particles_free_data(particles);
particles->dependency.deleted_notify(p_rid);
+ _particles_free_data(particles);
particles_owner.free(p_rid);
} else if (particles_collision_owner.owns(p_rid)) {
ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid);
@@ -8335,13 +8660,13 @@ RendererStorageRD::RendererStorageRD() {
static_assert(sizeof(GlobalVariables::Value) == 16);
- global_variables.buffer_size = GLOBAL_GET("rendering/high_end/global_shader_variables_buffer_size");
+ global_variables.buffer_size = GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size");
global_variables.buffer_size = MAX(4096, global_variables.buffer_size);
global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size);
- zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
+ memset(global_variables.buffer_values, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size);
global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
- zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
+ memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size);
material_update_list = nullptr;
@@ -8603,14 +8928,14 @@ RendererStorageRD::RendererStorageRD() {
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level"));
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
} break;
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.use_anisotropy = true;
- sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/quality/texture_filters/anisotropic_filtering_level"));
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
} break;
default: {
@@ -8760,7 +9085,6 @@ RendererStorageRD::RendererStorageRD() {
sdf_versions.push_back(""); //one only
giprobe_sdf_shader.initialize(sdf_versions);
giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
- giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>());
giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
}
@@ -8780,7 +9104,7 @@ RendererStorageRD::RendererStorageRD() {
}
}
- lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed");
+ lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
/* Particles */
@@ -8799,14 +9123,14 @@ RendererStorageRD::RendererStorageRD() {
actions.renames["COLOR"] = "PARTICLE.color";
actions.renames["VELOCITY"] = "PARTICLE.velocity";
//actions.renames["MASS"] = "mass"; ?
- actions.renames["ACTIVE"] = "PARTICLE.is_active";
+ actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
actions.renames["TRANSFORM"] = "PARTICLE.xform";
actions.renames["TIME"] = "FRAME.time";
actions.renames["LIFETIME"] = "params.lifetime";
actions.renames["DELTA"] = "local_delta";
- actions.renames["NUMBER"] = "particle";
+ actions.renames["NUMBER"] = "particle_number";
actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
@@ -8847,9 +9171,11 @@ RendererStorageRD::RendererStorageRD() {
{
// default material and shader for particles shader
- particles_shader.default_shader = shader_create();
- shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n");
- particles_shader.default_material = material_create();
+ particles_shader.default_shader = shader_allocate();
+ shader_initialize(particles_shader.default_shader);
+ shader_set_code(particles_shader.default_shader, "shader_type particles; void process() { COLOR = vec4(1.0); } \n");
+ particles_shader.default_material = material_allocate();
+ material_initialize(particles_shader.default_material);
material_set_shader(particles_shader.default_material, particles_shader.default_shader);
ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RendererStorageRD::SHADER_TYPE_PARTICLES);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 48d43568c4..961bdfb178 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -221,7 +221,7 @@ private:
~CanvasTexture();
};
- RID_PtrOwner<CanvasTexture> canvas_texture_owner;
+ RID_PtrOwner<CanvasTexture, true> canvas_texture_owner;
/* TEXTURE API */
struct Texture {
@@ -367,7 +367,7 @@ private:
};
ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
- mutable RID_Owner<Shader> shader_owner;
+ mutable RID_Owner<Shader, true> shader_owner;
/* Material */
@@ -389,7 +389,7 @@ private:
};
MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
- mutable RID_Owner<Material> material_owner;
+ mutable RID_Owner<Material, true> material_owner;
Material *material_update_list;
void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
@@ -484,7 +484,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<Mesh> mesh_owner;
+ mutable RID_Owner<Mesh, true> mesh_owner;
struct MeshInstance {
Mesh *mesh;
@@ -587,7 +587,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<MultiMesh> multimesh_owner;
+ mutable RID_Owner<MultiMesh, true> multimesh_owner;
MultiMesh *multimesh_dirty_list = nullptr;
@@ -660,6 +660,11 @@ private:
float time;
float delta;
+ uint32_t frame;
+ uint32_t pad0;
+ uint32_t pad1;
+ uint32_t pad2;
+
uint32_t random_seed;
uint32_t attractor_count;
uint32_t collider_count;
@@ -691,23 +696,29 @@ private:
};
struct Particles {
- bool inactive;
- float inactive_time;
- bool emitting;
- bool one_shot;
- int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness;
- float randomness;
- bool restart_request;
- AABB custom_aabb;
- bool use_local_coords;
+ bool inactive = true;
+ float inactive_time = 0.0;
+ bool emitting = false;
+ bool one_shot = false;
+ int amount = 0;
+ float lifetime = 1.0;
+ float pre_process_time = 0.0;
+ float explosiveness = 0.0;
+ float randomness = 0.0;
+ bool restart_request = false;
+ AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
+ bool use_local_coords = true;
RID process_material;
+ uint32_t frame_counter = 0;
+ RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
- RS::ParticlesDrawOrder draw_order;
+ RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
Vector<RID> draw_passes;
+ Vector<Transform> trail_bind_poses;
+ bool trail_bind_poses_dirty = false;
+ RID trail_bind_pose_buffer;
+ RID trail_bind_pose_uniform_set;
RID particle_buffer;
RID particle_instance_buffer;
@@ -730,21 +741,22 @@ private:
RID sub_emitter;
- float phase;
- float prev_phase;
- uint64_t prev_ticks;
- uint32_t random_seed;
+ float phase = 0.0;
+ float prev_phase = 0.0;
+ uint64_t prev_ticks = 0;
+ uint32_t random_seed = 0;
- uint32_t cycle_number;
+ uint32_t cycle_number = 0;
- float speed_scale;
+ float speed_scale = 1.0;
- int fixed_fps;
- bool fractional_delta;
- float frame_remainder;
- float collision_base_size;
+ int fixed_fps = 30;
+ bool interpolate = true;
+ bool fractional_delta = false;
+ float frame_remainder = 0;
+ float collision_base_size = 0.01;
- bool clear;
+ bool clear = true;
bool force_sub_emit = false;
@@ -757,39 +769,21 @@ private:
Set<RID> collisions;
- Particles() :
- inactive(true),
- inactive_time(0.0),
- emitting(false),
- one_shot(false),
- amount(0),
- lifetime(1.0),
- pre_process_time(0.0),
- explosiveness(0.0),
- randomness(0.0),
- restart_request(false),
- custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))),
- use_local_coords(true),
- draw_order(RS::PARTICLES_DRAW_ORDER_INDEX),
- prev_ticks(0),
- random_seed(0),
- cycle_number(0),
- speed_scale(1.0),
- fixed_fps(0),
- fractional_delta(false),
- frame_remainder(0),
- collision_base_size(0.01),
- clear(true) {
- }
-
Dependency dependency;
- ParticlesFrameParams frame_params;
+ float trail_length = 1.0;
+ bool trails_enabled = false;
+ LocalVector<ParticlesFrameParams> frame_history;
+ LocalVector<ParticlesFrameParams> trail_params;
+
+ Particles() {
+ }
};
void _particles_process(Particles *p_particles, float p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
+ void _particles_update_buffers(Particles *particles);
struct ParticlesShader {
struct PushConstant {
@@ -801,7 +795,7 @@ private:
uint32_t use_fractional_delta;
uint32_t sub_emitter_mode;
uint32_t can_emit;
- uint32_t pad;
+ uint32_t trail_pass;
};
ParticlesShaderRD shader;
@@ -816,6 +810,14 @@ private:
struct CopyPushConstant {
float sort_direction[3];
uint32_t total_particles;
+
+ uint32_t trail_size;
+ uint32_t trail_total;
+ float frame_delta;
+ float frame_remainder;
+
+ float align_up[3];
+ uint32_t align_mode;
};
enum {
@@ -829,6 +831,8 @@ private:
RID copy_shader_version;
RID copy_pipelines[COPY_MODE_MAX];
+ LocalVector<float> pose_update_buffer;
+
} particles_shader;
Particles *particle_update_list = nullptr;
@@ -893,7 +897,7 @@ private:
void update_particles();
- mutable RID_Owner<Particles> particles_owner;
+ mutable RID_Owner<Particles, true> particles_owner;
/* Particles Collision */
@@ -915,7 +919,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<ParticlesCollision> particles_collision_owner;
+ mutable RID_Owner<ParticlesCollision, true> particles_collision_owner;
struct ParticlesCollisionInstance {
RID collision;
@@ -945,7 +949,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<Skeleton> skeleton_owner;
+ mutable RID_Owner<Skeleton, true> skeleton_owner;
_FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
@@ -977,7 +981,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<Light> light_owner;
+ mutable RID_Owner<Light, true> light_owner;
/* REFLECTION PROBE */
@@ -1000,7 +1004,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
+ mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
/* DECAL */
@@ -1021,7 +1025,7 @@ private:
Dependency dependency;
};
- mutable RID_Owner<Decal> decal_owner;
+ mutable RID_Owner<Decal, true> decal_owner;
/* GI PROBE */
@@ -1064,7 +1068,7 @@ private:
RID giprobe_sdf_shader_version_shader;
RID giprobe_sdf_shader_pipeline;
- mutable RID_Owner<GIProbe> gi_probe_owner;
+ mutable RID_Owner<GIProbe, true> gi_probe_owner;
/* REFLECTION PROBE */
@@ -1095,7 +1099,7 @@ private:
uint64_t lightmap_array_version = 0;
- mutable RID_Owner<Lightmap> lightmap_owner;
+ mutable RID_Owner<Lightmap, true> lightmap_owner;
float lightmap_probe_capture_update_speed = 4;
@@ -1249,12 +1253,16 @@ private:
EffectsRD effects;
public:
+ virtual bool can_create_resources_async() const;
+
/* TEXTURE API */
- virtual RID texture_2d_create(const Ref<Image> &p_image);
- virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type);
- virtual RID texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); //all slices, then all the mipmaps, must be coherent
- virtual RID texture_proxy_create(RID p_base);
+ virtual RID texture_allocate();
+
+ virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image);
+ virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type);
+ virtual void texture_3d_initialize(RID p_texture, Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data); //all slices, then all the mipmaps, must be coherent
+ virtual void texture_proxy_initialize(RID p_texture, RID p_base);
virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);
@@ -1264,9 +1272,9 @@ public:
virtual void texture_proxy_update(RID p_texture, RID p_proxy_to);
//these two APIs can be used together or in combination with the others.
- virtual RID texture_2d_placeholder_create();
- virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type);
- virtual RID texture_3d_placeholder_create();
+ virtual void texture_2d_placeholder_initialize(RID p_texture);
+ virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type);
+ virtual void texture_3d_placeholder_initialize(RID p_texture);
virtual Ref<Image> texture_2d_get(RID p_texture) const;
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const;
@@ -1338,7 +1346,8 @@ public:
/* CANVAS TEXTURE API */
- virtual RID canvas_texture_create();
+ RID canvas_texture_allocate();
+ void canvas_texture_initialize(RID p_canvas_texture);
virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture);
virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess);
@@ -1350,7 +1359,8 @@ public:
/* SHADER API */
- RID shader_create();
+ RID shader_allocate();
+ void shader_initialize(RID p_shader);
void shader_set_code(RID p_shader, const String &p_code);
String shader_get_code(RID p_shader) const;
@@ -1365,7 +1375,8 @@ public:
/* COMMON MATERIAL API */
- RID material_create();
+ RID material_allocate();
+ void material_initialize(RID p_material);
void material_set_shader(RID p_material, RID p_shader);
@@ -1401,7 +1412,8 @@ public:
/* MESH API */
- virtual RID mesh_create();
+ RID mesh_allocate();
+ void mesh_initialize(RID p_mesh);
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count);
@@ -1622,9 +1634,10 @@ public:
/* MULTIMESH API */
- RID multimesh_create();
+ RID multimesh_allocate();
+ void multimesh_initialize(RID p_multimesh);
- void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false);
+ void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false);
int multimesh_get_instance_count(RID p_multimesh) const;
void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
@@ -1688,24 +1701,28 @@ public:
/* IMMEDIATE API */
- RID immediate_create() { return RID(); }
- void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {}
- void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {}
- void immediate_normal(RID p_immediate, const Vector3 &p_normal) {}
- void immediate_tangent(RID p_immediate, const Plane &p_tangent) {}
- void immediate_color(RID p_immediate, const Color &p_color) {}
- void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {}
- void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {}
- void immediate_end(RID p_immediate) {}
- void immediate_clear(RID p_immediate) {}
- void immediate_set_material(RID p_immediate, RID p_material) {}
- RID immediate_get_material(RID p_immediate) const { return RID(); }
- AABB immediate_get_aabb(RID p_immediate) const { return AABB(); }
+ RID immediate_allocate() { return RID(); }
+ void immediate_initialize(RID p_immediate) {}
+
+ virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {}
+ virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {}
+ virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) {}
+ virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) {}
+ virtual void immediate_color(RID p_immediate, const Color &p_color) {}
+ virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {}
+ virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {}
+ virtual void immediate_end(RID p_immediate) {}
+ virtual void immediate_clear(RID p_immediate) {}
+ virtual void immediate_set_material(RID p_immediate, RID p_material) {}
+ virtual RID immediate_get_material(RID p_immediate) const { return RID(); }
+ virtual AABB immediate_get_aabb(RID p_immediate) const { return AABB(); }
/* SKELETON API */
- RID skeleton_create();
- void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
+ RID skeleton_allocate();
+ void skeleton_initialize(RID p_skeleton);
+
+ void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform);
int skeleton_get_bone_count(RID p_skeleton) const;
@@ -1739,11 +1756,16 @@ public:
}
/* Light API */
- RID light_create(RS::LightType p_type);
+ void _light_initialize(RID p_rid, RS::LightType p_type);
- RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); }
- RID omni_light_create() { return light_create(RS::LIGHT_OMNI); }
- RID spot_light_create() { return light_create(RS::LIGHT_SPOT); }
+ RID directional_light_allocate();
+ void directional_light_initialize(RID p_light);
+
+ RID omni_light_allocate();
+ void omni_light_initialize(RID p_light);
+
+ RID spot_light_allocate();
+ void spot_light_initialize(RID p_light);
void light_set_color(RID p_light, const Color &p_color);
void light_set_param(RID p_light, RS::LightParam p_param, float p_value);
@@ -1846,7 +1868,8 @@ public:
/* PROBE API */
- RID reflection_probe_create();
+ RID reflection_probe_allocate();
+ void reflection_probe_initialize(RID p_reflection_probe);
void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode);
void reflection_probe_set_intensity(RID p_probe, float p_intensity);
@@ -1886,7 +1909,9 @@ public:
/* DECAL API */
- virtual RID decal_create();
+ RID decal_allocate();
+ void decal_initialize(RID p_decal);
+
virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents);
virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture);
virtual void decal_set_emission_energy(RID p_decal, float p_energy);
@@ -1961,9 +1986,10 @@ public:
/* GI PROBE API */
- RID gi_probe_create();
+ RID gi_probe_allocate();
+ void gi_probe_initialize(RID p_gi_probe);
- void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
+ void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
AABB gi_probe_get_bounds(RID p_gi_probe) const;
Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
@@ -2014,7 +2040,8 @@ public:
/* LIGHTMAP CAPTURE */
- virtual RID lightmap_create();
+ RID lightmap_allocate();
+ void lightmap_initialize(RID p_lightmap);
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics);
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds);
@@ -2063,7 +2090,8 @@ public:
/* PARTICLES */
- RID particles_create();
+ RID particles_allocate();
+ void particles_initialize(RID p_particles_collision);
void particles_set_emitting(RID p_particles, bool p_emitting);
void particles_set_amount(RID p_particles, int p_amount);
@@ -2077,10 +2105,17 @@ public:
void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
void particles_set_process_material(RID p_particles, RID p_material);
void particles_set_fixed_fps(RID p_particles, int p_fps);
+ void particles_set_interpolate(RID p_particles, bool p_enable);
void particles_set_fractional_delta(RID p_particles, bool p_enable);
void particles_set_collision_base_size(RID p_particles, float p_size);
+ void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align);
+
+ void particles_set_trails(RID p_particles, bool p_enable, float p_length);
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses);
+
void particles_restart(RID p_particles);
void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+
void particles_set_subemitter(RID p_particles, RID p_subemitter_particles);
void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
@@ -2098,15 +2133,21 @@ public:
int particles_get_draw_passes(RID p_particles) const;
RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const;
- void particles_set_view_axis(RID p_particles, const Vector3 &p_axis);
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
virtual bool particles_is_inactive(RID p_particles) const;
- _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
+ _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, 0);
- return particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ r_trail_divisor = particles->trail_bind_poses.size();
+ } else {
+ r_trail_divisor = 1;
+ }
+
+ return particles->amount * r_trail_divisor;
}
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
@@ -2120,6 +2161,8 @@ public:
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, RID());
if (particles->particles_transforms_buffer_uniform_set.is_null()) {
+ _particles_update_buffers(particles);
+
Vector<RD::Uniform> uniforms;
{
@@ -2141,7 +2184,9 @@ public:
/* PARTICLES COLLISION */
- virtual RID particles_collision_create();
+ RID particles_collision_allocate();
+ void particles_collision_initialize(RID p_particles_collision);
+
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type);
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask);
virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius); //for spheres
@@ -2237,7 +2282,7 @@ public:
void render_info_end_capture() {}
int get_captured_render_info(RS::RenderInfo p_info) { return 0; }
- int get_render_info(RS::RenderInfo p_info) { return 0; }
+ uint64_t get_render_info(RS::RenderInfo p_info) { return 0; }
String get_video_adapter_name() const { return String(); }
String get_video_adapter_vendor() const { return String(); }
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index e77141b26c..24ac85bb35 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -535,9 +535,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
struct_code += "}";
struct_code += ";\n";
- r_gen_code.vertex_global += struct_code;
- r_gen_code.fragment_global += struct_code;
- r_gen_code.compute_global += struct_code;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += struct_code;
+ }
}
int max_texture_uniforms = 0;
@@ -590,9 +590,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
ucode += " " + _mkid(E->key());
ucode += ";\n";
if (SL::is_sampler_type(E->get().type)) {
- r_gen_code.vertex_global += ucode;
- r_gen_code.fragment_global += ucode;
- r_gen_code.compute_global += ucode;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += ucode;
+ }
GeneratedCode::Texture texture;
texture.name = E->key();
@@ -608,7 +608,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
} else {
if (!uses_uniforms) {
- r_gen_code.defines.push_back(String("#define USE_MATERIAL_UNIFORMS\n"));
uses_uniforms = true;
}
uniform_defines.write[E->get().order] = ucode;
@@ -687,7 +686,15 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uint32_t index = p_default_actions.base_varying_index;
+ List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light;
+
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
+ if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
+ var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get()));
+ fragment_varyings.insert(E->key());
+ continue;
+ }
+
String vcode;
String interp_mode = _interpstr(E->get().interpolation);
vcode += _prestr(E->get().precision);
@@ -699,12 +706,28 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
vcode += "]";
}
vcode += ";\n";
- r_gen_code.vertex_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
- r_gen_code.fragment_global += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
- r_gen_code.compute_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
+
+ r_gen_code.stage_globals[STAGE_VERTEX] += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
+
index++;
}
+ if (var_frag_to_light.size() > 0) {
+ String gcode = "\n\nstruct {\n";
+ for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) {
+ gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first);
+ if (E->get().second.array_size > 0) {
+ gcode += "[";
+ gcode += itos(E->get().second.array_size);
+ gcode += "]";
+ }
+ gcode += ";\n";
+ }
+ gcode += "} frag_to_light;\n";
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += gcode;
+ }
+
for (int i = 0; i < pnode->vconstants.size(); i++) {
const SL::ShaderNode::Constant &cnode = pnode->vconstants[i];
String gcode;
@@ -724,9 +747,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
gcode += "=";
gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
gcode += ";\n";
- r_gen_code.vertex_global += gcode;
- r_gen_code.fragment_global += gcode;
- r_gen_code.compute_global += gcode;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += gcode;
+ }
}
Map<StringName, String> function_code;
@@ -742,9 +765,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
//place functions in actual code
- Set<StringName> added_vtx;
- Set<StringName> added_fragment; //share for light
- Set<StringName> added_compute; //share for light
+ Set<StringName> added_funcs_per_stage[STAGE_MAX];
for (int i = 0; i < pnode->functions.size(); i++) {
SL::FunctionNode *fnode = pnode->functions[i].function;
@@ -753,24 +774,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
current_func_name = fnode->name;
- if (fnode->name == vertex_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx);
- r_gen_code.vertex = function_code[vertex_name];
- }
-
- if (fnode->name == fragment_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
- r_gen_code.fragment = function_code[fragment_name];
- }
-
- if (fnode->name == light_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
- r_gen_code.light = function_code[light_name];
- }
-
- if (fnode->name == compute_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.compute_global, added_compute);
- r_gen_code.compute = function_code[compute_name];
+ if (p_actions.entry_point_stages.has(fnode->name)) {
+ Stage stage = p_actions.entry_point_stages[fnode->name];
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.stage_globals[stage], added_funcs_per_stage[stage]);
+ r_gen_code.code[fnode->name] = function_code[fnode->name];
}
function = nullptr;
@@ -833,6 +840,19 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} break;
case SL::Node::TYPE_VARIABLE: {
SL::VariableNode *vnode = (SL::VariableNode *)p_node;
+ bool use_fragment_varying = false;
+
+ if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
+ if (p_assigning) {
+ if (shader->varyings.has(vnode->name)) {
+ use_fragment_varying = true;
+ }
+ } else {
+ if (fragment_varyings.has(vnode->name)) {
+ use_fragment_varying = true;
+ }
+ }
+ }
if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) {
*p_actions.write_flag_pointers[vnode->name] = true;
@@ -877,15 +897,18 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
} else {
- code = _mkid(vnode->name); //its something else (local var most likely) use as is
+ if (use_fragment_varying) {
+ code = "frag_to_light.";
+ }
+ code += _mkid(vnode->name); //its something else (local var most likely) use as is
}
}
if (vnode->name == time_name) {
- if (current_func_name == vertex_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) {
r_gen_code.uses_vertex_time = true;
}
- if (current_func_name == fragment_name || current_func_name == light_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) {
r_gen_code.uses_fragment_time = true;
}
}
@@ -962,6 +985,23 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} break;
case SL::Node::TYPE_ARRAY: {
SL::ArrayNode *anode = (SL::ArrayNode *)p_node;
+ bool use_fragment_varying = false;
+
+ if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
+ if (anode->assign_expression != nullptr) {
+ use_fragment_varying = true;
+ } else {
+ if (p_assigning) {
+ if (shader->varyings.has(anode->name)) {
+ use_fragment_varying = true;
+ }
+ } else {
+ if (fragment_varyings.has(anode->name)) {
+ use_fragment_varying = true;
+ }
+ }
+ }
+ }
if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) {
*p_actions.write_flag_pointers[anode->name] = true;
@@ -984,7 +1024,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (p_default_actions.renames.has(anode->name)) {
code = p_default_actions.renames[anode->name];
} else {
- code = _mkid(anode->name);
+ if (use_fragment_varying) {
+ code = "frag_to_light.";
+ }
+ code += _mkid(anode->name);
}
if (anode->call_expression != nullptr) {
@@ -1000,10 +1043,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
if (anode->name == time_name) {
- if (current_func_name == vertex_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) {
r_gen_code.uses_vertex_time = true;
}
- if (current_func_name == fragment_name || current_func_name == light_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) {
r_gen_code.uses_fragment_time = true;
}
}
@@ -1250,7 +1293,7 @@ ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &
}
Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
- Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
+ Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
if (err != OK) {
Vector<String> shader = p_code.split("\n");
@@ -1263,13 +1306,10 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
}
r_gen_code.defines.clear();
- r_gen_code.vertex = String();
- r_gen_code.vertex_global = String();
- r_gen_code.fragment = String();
- r_gen_code.fragment_global = String();
- r_gen_code.compute = String();
- r_gen_code.compute_global = String();
- r_gen_code.light = String();
+ r_gen_code.code.clear();
+ for (int i = 0; i < STAGE_MAX; i++) {
+ r_gen_code.stage_globals[i] = String();
+ }
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
@@ -1277,6 +1317,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
used_name_defines.clear();
used_rmode_defines.clear();
used_flag_pointers.clear();
+ fragment_varyings.clear();
shader = parser.get_shader();
function = nullptr;
@@ -1288,10 +1329,6 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
actions = p_actions;
- vertex_name = "vertex";
- fragment_name = "fragment";
- compute_name = "compute";
- light_name = "light";
time_name = "TIME";
List<String> func_list;
@@ -1408,7 +1445,7 @@ ShaderCompilerRD::ShaderCompilerRD() {
actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
- bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley");
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
if (!force_lambert) {
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
@@ -1418,7 +1455,7 @@ ShaderCompilerRD::ShaderCompilerRD() {
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
- bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
+ bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
if (!force_blinn) {
actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h
index d127d8e01c..2da127ffa3 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.h
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.h
@@ -38,7 +38,16 @@
class ShaderCompilerRD {
public:
+ enum Stage {
+ STAGE_VERTEX,
+ STAGE_FRAGMENT,
+ STAGE_COMPUTE,
+ STAGE_MAX
+ };
+
struct IdentifierActions {
+ Map<StringName, Stage> entry_point_stages;
+
Map<StringName, Pair<int *, int>> render_mode_values;
Map<StringName, bool *> render_mode_flags;
Map<StringName, bool *> usage_flag_pointers;
@@ -63,13 +72,9 @@ public:
Vector<uint32_t> uniform_offsets;
uint32_t uniform_total_size;
String uniforms;
- String vertex_global;
- String vertex;
- String fragment_global;
- String fragment;
- String light;
- String compute_global;
- String compute;
+ String stage_globals[STAGE_MAX];
+
+ Map<String, String> code;
bool uses_global_textures;
bool uses_fragment_time;
@@ -103,10 +108,6 @@ private:
const ShaderLanguage::ShaderNode *shader;
const ShaderLanguage::FunctionNode *function;
StringName current_func_name;
- StringName vertex_name;
- StringName fragment_name;
- StringName light_name;
- StringName compute_name;
StringName time_name;
Set<StringName> texture_functions;
@@ -114,6 +115,7 @@ private:
Set<StringName> used_flag_pointers;
Set<StringName> used_rmode_defines;
Set<StringName> internal_functions;
+ Set<StringName> fragment_varyings;
DefaultIdentifierActions actions;
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index e4a39ff813..f7242a2b17 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -30,146 +30,83 @@
#include "shader_rd.h"
-#include "core/string/string_builder.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_device.h"
-void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
- name = p_name;
- //split vertex and shader code (thank you, shader compiler programmers from you know what company).
- if (p_vertex_code) {
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nVERTEX_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nVERTEX_SHADER_CODE";
- String code = p_vertex_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- vertex_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
- }
-
- cpos = code.find(material_tag);
-
- if (cpos == -1) {
- vertex_code0 = code.ascii();
- } else {
- vertex_code0 = code.substr(0, cpos).ascii();
- code = code.substr(cpos + material_tag.length(), code.length());
-
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- vertex_code1 = code.ascii();
- } else {
- vertex_code1 = code.substr(0, cpos).ascii();
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
-
- cpos = code2.find(code_tag);
- if (cpos == -1) {
- vertex_code2 = code2.ascii();
- } else {
- vertex_code2 = code2.substr(0, cpos).ascii();
- vertex_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
+void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
+ Vector<String> lines = String(p_code).split("\n");
+
+ String text;
+
+ for (int i = 0; i < lines.size(); i++) {
+ String l = lines[i];
+ bool push_chunk = false;
+
+ StageTemplate::Chunk chunk;
+
+ if (l.begins_with("#VERSION_DEFINES")) {
+ chunk.type = StageTemplate::Chunk::TYPE_VERSION_DEFINES;
+ push_chunk = true;
+ } else if (l.begins_with("#GLOBALS")) {
+ switch (p_stage_type) {
+ case STAGE_TYPE_VERTEX:
+ chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
+ break;
+ case STAGE_TYPE_FRAGMENT:
+ chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS;
+ break;
+ case STAGE_TYPE_COMPUTE:
+ chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS;
+ break;
+ default: {
}
}
- }
- }
- if (p_fragment_code) {
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nFRAGMENT_SHADER_CODE";
- String light_code_tag = "\nLIGHT_SHADER_CODE";
- String code = p_fragment_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- fragment_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
+ push_chunk = true;
+ } else if (l.begins_with("#MATERIAL_UNIFORMS")) {
+ chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS;
+ push_chunk = true;
+ } else if (l.begins_with("#CODE")) {
+ chunk.type = StageTemplate::Chunk::TYPE_CODE;
+ push_chunk = true;
+ chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper();
+ } else {
+ text += l + "\n";
}
- cpos = code.find(material_tag);
- if (cpos == -1) {
- fragment_code0 = code.ascii();
- } else {
- fragment_code0 = code.substr(0, cpos).ascii();
- //print_line("CODE0:\n"+String(fragment_code0.get_data()));
- code = code.substr(cpos + material_tag.length(), code.length());
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- fragment_code1 = code.ascii();
- } else {
- fragment_code1 = code.substr(0, cpos).ascii();
- //print_line("CODE1:\n"+String(fragment_code1.get_data()));
-
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
- cpos = code2.find(light_code_tag);
-
- if (cpos == -1) {
- fragment_code2 = code2.ascii();
- } else {
- fragment_code2 = code2.substr(0, cpos).ascii();
- //print_line("CODE2:\n"+String(fragment_code2.get_data()));
-
- String code3 = code2.substr(cpos + light_code_tag.length(), code2.length());
-
- cpos = code3.find(code_tag);
- if (cpos == -1) {
- fragment_code3 = code3.ascii();
- } else {
- fragment_code3 = code3.substr(0, cpos).ascii();
- //print_line("CODE3:\n"+String(fragment_code3.get_data()));
- fragment_code4 = code3.substr(cpos + code_tag.length(), code3.length()).ascii();
- //print_line("CODE4:\n"+String(fragment_code4.get_data()));
- }
- }
+ if (push_chunk) {
+ if (text != String()) {
+ StageTemplate::Chunk text_chunk;
+ text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+ text_chunk.text = text.utf8();
+ stage_templates[p_stage_type].chunks.push_back(text_chunk);
+ text = String();
}
+ stage_templates[p_stage_type].chunks.push_back(chunk);
}
}
+ if (text != String()) {
+ StageTemplate::Chunk text_chunk;
+ text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+ text_chunk.text = text.utf8();
+ stage_templates[p_stage_type].chunks.push_back(text_chunk);
+ text = String();
+ }
+}
+
+void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
+ name = p_name;
if (p_compute_code) {
+ _add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
is_compute = true;
-
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nCOMPUTE_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nCOMPUTE_SHADER_CODE";
- String code = p_compute_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- compute_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
+ } else {
+ is_compute = false;
+ if (p_vertex_code) {
+ _add_stage(p_vertex_code, STAGE_TYPE_VERTEX);
}
-
- cpos = code.find(material_tag);
-
- if (cpos == -1) {
- compute_code0 = code.ascii();
- } else {
- compute_code0 = code.substr(0, cpos).ascii();
- code = code.substr(cpos + material_tag.length(), code.length());
-
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- compute_code1 = code.ascii();
- } else {
- compute_code1 = code.substr(0, cpos).ascii();
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
-
- cpos = code2.find(code_tag);
- if (cpos == -1) {
- compute_code2 = code2.ascii();
- } else {
- compute_code2 = code2.substr(0, cpos).ascii();
- compute_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
- }
- }
+ if (p_fragment_code) {
+ _add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
}
}
}
@@ -198,6 +135,49 @@ void ShaderRD::_clear_version(Version *p_version) {
}
}
+void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) {
+ for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
+ const StageTemplate::Chunk &chunk = p_template.chunks[i];
+ switch (chunk.type) {
+ case StageTemplate::Chunk::TYPE_VERSION_DEFINES: {
+ builder.append("\n"); //make sure defines begin at newline
+ builder.append(general_defines.get_data());
+ builder.append(variant_defines[p_variant].get_data());
+ for (int j = 0; j < p_version->custom_defines.size(); j++) {
+ builder.append(p_version->custom_defines[j].get_data());
+ }
+ builder.append("\n"); //make sure defines begin at newline
+ if (p_version->uniforms.size()) {
+ builder.append("#define MATERIAL_UNIFORMS_USED\n");
+ }
+ for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) {
+ builder.append(String("#define ") + String(E->key()) + "_CODE_USED\n");
+ }
+ } break;
+ case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
+ builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
+ } break;
+ case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
+ builder.append(p_version->vertex_globals.get_data()); // vertex globals
+ } break;
+ case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
+ builder.append(p_version->fragment_globals.get_data()); // fragment globals
+ } break;
+ case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: {
+ builder.append(p_version->compute_globals.get_data()); // compute globals
+ } break;
+ case StageTemplate::Chunk::TYPE_CODE: {
+ if (p_version->code_sections.has(chunk.code)) {
+ builder.append(p_version->code_sections[chunk.code].get_data());
+ }
+ } break;
+ case StageTemplate::Chunk::TYPE_TEXT: {
+ builder.append(chunk.text.get_data());
+ } break;
+ }
+ }
+}
+
void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
if (!variants_enabled[p_variant]) {
return; //variant is disabled, return
@@ -214,29 +194,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
//vertex stage
StringBuilder builder;
-
- builder.append(vertex_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
-
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(vertex_code0.get_data()); //first part of vertex
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
-
- builder.append(vertex_code1.get_data()); //second part of vertex
-
- builder.append(p_version->vertex_globals.get_data()); // vertex globals
-
- builder.append(vertex_code2.get_data()); //third part of vertex
-
- builder.append(p_version->vertex_code.get_data()); // code
-
- builder.append(vertex_code3.get_data()); //fourth of vertex
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
RD::ShaderStageData stage;
@@ -254,33 +212,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_stage = RD::SHADER_STAGE_FRAGMENT;
StringBuilder builder;
-
- builder.append(fragment_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
-
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(fragment_code0.get_data()); //first part of fragment
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for fragment and fragment)
-
- builder.append(fragment_code1.get_data()); //first part of fragment
-
- builder.append(p_version->fragment_globals.get_data()); // fragment globals
-
- builder.append(fragment_code2.get_data()); //third part of fragment
-
- builder.append(p_version->fragment_light.get_data()); // fragment light
-
- builder.append(fragment_code3.get_data()); //fourth part of fragment
-
- builder.append(p_version->fragment_code.get_data()); // fragment code
-
- builder.append(fragment_code4.get_data()); //fourth part of fragment
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
RD::ShaderStageData stage;
@@ -298,32 +230,10 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_stage = RD::SHADER_STAGE_COMPUTE;
StringBuilder builder;
-
- builder.append(compute_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(base_compute_defines.get_data());
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
-
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(compute_code0.get_data()); //first part of compute
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for compute and fragment)
-
- builder.append(compute_code1.get_data()); //second part of compute
-
- builder.append(p_version->compute_globals.get_data()); // compute globals
-
- builder.append(compute_code2.get_data()); //third part of compute
-
- builder.append(p_version->compute_code.get_data()); // code
-
- builder.append(compute_code3.get_data()); //fourth of compute
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_COMPUTE]);
current_source = builder.as_string();
+
RD::ShaderStageData stage;
stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
@@ -364,29 +274,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//vertex stage
StringBuilder builder;
-
- builder.append(vertex_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
-
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(vertex_code0.get_data()); //first part of vertex
-
- builder.append(version->uniforms.get_data()); //uniforms (same for vertex and fragment)
-
- builder.append(vertex_code1.get_data()); //second part of vertex
-
- builder.append(version->vertex_globals.get_data()); // vertex globals
-
- builder.append(vertex_code2.get_data()); //third part of vertex
-
- builder.append(version->vertex_code.get_data()); // code
-
- builder.append(vertex_code3.get_data()); //fourth of vertex
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
@@ -399,32 +287,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//fragment stage
StringBuilder builder;
-
- builder.append(fragment_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(fragment_code0.get_data()); //first part of fragment
-
- builder.append(version->uniforms.get_data()); //uniforms (same for fragment and fragment)
-
- builder.append(fragment_code1.get_data()); //first part of fragment
-
- builder.append(version->fragment_globals.get_data()); // fragment globals
-
- builder.append(fragment_code2.get_data()); //third part of fragment
-
- builder.append(version->fragment_light.get_data()); // fragment light
-
- builder.append(fragment_code3.get_data()); //fourth part of fragment
-
- builder.append(version->fragment_code.get_data()); // fragment code
-
- builder.append(fragment_code4.get_data()); //fourth part of fragment
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
@@ -437,30 +300,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//compute stage
StringBuilder builder;
-
- builder.append(compute_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(base_compute_defines.get_data());
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
-
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(compute_code0.get_data()); //first part of compute
-
- builder.append(version->uniforms.get_data()); //uniforms (same for compute and fragment)
-
- builder.append(compute_code1.get_data()); //second part of compute
-
- builder.append(version->compute_globals.get_data()); // compute globals
-
- builder.append(compute_code2.get_data()); //third part of compute
-
- builder.append(version->compute_code.get_data()); // code
-
- builder.append(compute_code3.get_data()); //fourth of compute
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_COMPUTE]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "compute";
@@ -518,17 +358,18 @@ void ShaderRD::_compile_version(Version *p_version) {
p_version->valid = true;
}
-void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) {
+void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(is_compute);
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND(!version);
version->vertex_globals = p_vertex_globals.utf8();
- version->vertex_code = p_vertex_code.utf8();
- version->fragment_light = p_fragment_light.utf8();
version->fragment_globals = p_fragment_globals.utf8();
- version->fragment_code = p_fragment_code.utf8();
version->uniforms = p_uniforms.utf8();
+ version->code_sections.clear();
+ for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
+ version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ }
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
@@ -542,15 +383,20 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S
}
}
-void ShaderRD::version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines) {
+void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(!is_compute);
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND(!version);
+
version->compute_globals = p_compute_globals.utf8();
- version->compute_code = p_compute_code.utf8();
version->uniforms = p_uniforms.utf8();
+ version->code_sections.clear();
+ for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
+ version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ }
+
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
version->custom_defines.push_back(p_custom_defines[i].utf8());
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index e0f4dcf2d0..f20d539621 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -32,7 +32,9 @@
#define SHADER_RD_H
#include "core/os/mutex.h"
+#include "core/string/string_builder.h"
#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
#include "core/templates/map.h"
#include "core/templates/rid_owner.h"
#include "core/variant/variant.h"
@@ -52,12 +54,9 @@ class ShaderRD {
struct Version {
CharString uniforms;
CharString vertex_globals;
- CharString vertex_code;
CharString compute_globals;
- CharString compute_code;
- CharString fragment_light;
CharString fragment_globals;
- CharString fragment_code;
+ Map<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
RID *variants; //same size as version defines
@@ -76,31 +75,44 @@ class ShaderRD {
RID_Owner<Version> version_owner;
- CharString fragment_codev; //for version and extensions
- CharString fragment_code0;
- CharString fragment_code1;
- CharString fragment_code2;
- CharString fragment_code3;
- CharString fragment_code4;
-
- CharString vertex_codev; //for version and extensions
- CharString vertex_code0;
- CharString vertex_code1;
- CharString vertex_code2;
- CharString vertex_code3;
+ struct StageTemplate {
+ struct Chunk {
+ enum Type {
+ TYPE_VERSION_DEFINES,
+ TYPE_MATERIAL_UNIFORMS,
+ TYPE_VERTEX_GLOBALS,
+ TYPE_FRAGMENT_GLOBALS,
+ TYPE_COMPUTE_GLOBALS,
+ TYPE_CODE,
+ TYPE_TEXT
+ };
+
+ Type type;
+ StringName code;
+ CharString text;
+ };
+ LocalVector<Chunk> chunks;
+ };
bool is_compute = false;
- CharString compute_codev; //for version and extensions
- CharString compute_code0;
- CharString compute_code1;
- CharString compute_code2;
- CharString compute_code3;
-
const char *name;
CharString base_compute_defines;
+ enum StageType {
+ STAGE_TYPE_VERTEX,
+ STAGE_TYPE_FRAGMENT,
+ STAGE_TYPE_COMPUTE,
+ STAGE_TYPE_MAX,
+ };
+
+ StageTemplate stage_templates[STAGE_TYPE_MAX];
+
+ void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template);
+
+ void _add_stage(const char *p_code, StageType p_stage_type);
+
protected:
ShaderRD();
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
@@ -108,8 +120,8 @@ protected:
public:
RID version_create();
- void version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines);
- void version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines);
+ void version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines);
+ void version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines);
_FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) {
ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID());
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index c192574ff2..fc513d3fb9 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -3,46 +3,15 @@
Import("env")
if "RD_GLSL" in env["BUILDERS"]:
- env.RD_GLSL("canvas.glsl")
- env.RD_GLSL("canvas_occlusion.glsl")
- env.RD_GLSL("canvas_sdf.glsl")
- env.RD_GLSL("copy.glsl")
- env.RD_GLSL("copy_to_fb.glsl")
- env.RD_GLSL("cubemap_roughness.glsl")
- env.RD_GLSL("cubemap_downsampler.glsl")
- env.RD_GLSL("cubemap_filter.glsl")
- env.RD_GLSL("scene_forward.glsl")
- env.RD_GLSL("sky.glsl")
- env.RD_GLSL("tonemap.glsl")
- env.RD_GLSL("cube_to_dp.glsl")
- env.RD_GLSL("giprobe.glsl")
- env.RD_GLSL("giprobe_debug.glsl")
- env.RD_GLSL("giprobe_sdf.glsl")
- env.RD_GLSL("luminance_reduce.glsl")
- env.RD_GLSL("bokeh_dof.glsl")
- env.RD_GLSL("ssao.glsl")
- env.RD_GLSL("ssao_downsample.glsl")
- env.RD_GLSL("ssao_importance_map.glsl")
- env.RD_GLSL("ssao_blur.glsl")
- env.RD_GLSL("ssao_interleave.glsl")
- env.RD_GLSL("roughness_limiter.glsl")
- env.RD_GLSL("screen_space_reflection.glsl")
- env.RD_GLSL("screen_space_reflection_filter.glsl")
- env.RD_GLSL("screen_space_reflection_scale.glsl")
- env.RD_GLSL("subsurface_scattering.glsl")
- env.RD_GLSL("specular_merge.glsl")
- env.RD_GLSL("gi.glsl")
- env.RD_GLSL("resolve.glsl")
- env.RD_GLSL("sdfgi_preprocess.glsl")
- env.RD_GLSL("sdfgi_integrate.glsl")
- env.RD_GLSL("sdfgi_direct_light.glsl")
- env.RD_GLSL("sdfgi_debug.glsl")
- env.RD_GLSL("sdfgi_debug_probes.glsl")
- env.RD_GLSL("volumetric_fog.glsl")
- env.RD_GLSL("particles.glsl")
- env.RD_GLSL("particles_copy.glsl")
- env.RD_GLSL("sort.glsl")
- env.RD_GLSL("skeleton.glsl")
- env.RD_GLSL("cluster_render.glsl")
- env.RD_GLSL("cluster_store.glsl")
- env.RD_GLSL("cluster_debug.glsl")
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files)
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
index 63f086a83d..b70e0b6bd5 100644
--- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 3b39edc70e..8b97ec119f 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef USE_ATTRIBUTES
layout(location = 0) in vec2 vertex_attrib;
@@ -26,17 +26,15 @@ layout(location = 3) out vec2 pixel_size_interp;
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
-/* clang-format off */
-VERTEX_SHADER_GLOBALS
-/* clang-format on */
+#GLOBALS
void main() {
vec4 instance_custom = vec4(0.0);
@@ -132,9 +130,7 @@ void main() {
float point_size = 1.0;
#endif
{
- /* clang-format off */
-VERTEX_SHADER_CODE
- /* clang-format on */
+#CODE : VERTEX
}
#ifdef USE_NINEPATCH
@@ -212,7 +208,7 @@ VERTEX_SHADER_CODE
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "canvas_uniforms_inc.glsl"
@@ -228,11 +224,11 @@ layout(location = 3) in vec2 pixel_size_interp;
layout(location = 0) out vec4 frag_color;
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
@@ -260,11 +256,9 @@ vec2 sdf_to_screen_uv(vec2 p_sdf) {
return p_sdf * canvas_data.sdf_to_screen;
}
-/* clang-format off */
-FRAGMENT_SHADER_GLOBALS
-/* clang-format on */
+#GLOBALS
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 light_compute(
vec3 light_vertex,
@@ -278,9 +272,9 @@ vec4 light_compute(
vec2 uv,
vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
- /* clang-format off */
-LIGHT_SHADER_CODE
- /* clang-format on */
+
+#CODE : LIGHT
+
return light;
}
@@ -356,7 +350,7 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig
//float distance = length(shadow_pos);
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
vec3 shadow_modulate
#endif
@@ -395,7 +389,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
}
vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
shadow_color.rgb *= shadow_modulate;
#endif
@@ -504,11 +498,7 @@ void main() {
normal_used = true;
#endif
- /* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
- /* clang-format on */
+#CODE : FRAGMENT
#if defined(NORMAL_MAP_USED)
normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth);
@@ -543,7 +533,7 @@ FRAGMENT_SHADER_CODE
vec2 direction = light_array.data[light_base].position;
vec4 light_color = light_array.data[light_base].color;
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
@@ -561,7 +551,7 @@ FRAGMENT_SHADER_CODE
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
@@ -599,7 +589,7 @@ FRAGMENT_SHADER_CODE
vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
vec4 light_base_color = light_array.data[light_base].color;
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
@@ -657,7 +647,7 @@ FRAGMENT_SHADER_CODE
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
index 5c25235c58..9f89f4b3b7 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in highp vec3 vertex;
@@ -32,7 +32,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 0, std430) uniform Constants {
mat4 projection;
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 302ad03b41..65a554e839 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
index 3a4bf4da07..8e616ebe1f 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
@@ -1,105 +1,3 @@
-
#define CLUSTER_COUNTER_SHIFT 20
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
#define CLUSTER_COUNTER_MASK 0xfff
-
-struct LightData { //this structure needs to be as packed as possible
- vec3 position;
- float inv_radius;
-
- vec3 direction;
- float size;
-
- vec3 color;
- float attenuation;
-
- float cone_attenuation;
- float cone_angle;
- float specular_amount;
- bool shadow_enabled;
-
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
- uint mask;
- float shadow_volumetric_fog_fade;
- uint pad;
- vec4 projector_rect; //projector rect in srgb decal atlas
-};
-
-#define REFLECTION_AMBIENT_DISABLED 0
-#define REFLECTION_AMBIENT_ENVIRONMENT 1
-#define REFLECTION_AMBIENT_COLOR 2
-
-struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
- uint mask;
- vec3 ambient; // ambient color
- float intensity;
- bool exterior;
- bool box_project;
- uint ambient_mode;
- uint pad;
- //0-8 is intensity,8-9 is ambient, mode
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
- // notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
- uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
- bool blend_splits;
- bool shadow_enabled;
- float fade_from;
- float fade_to;
- uvec3 pad;
- float shadow_volumetric_fog_fade;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
- vec4 shadow_z_range;
- vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
-};
-
-struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
- uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
-};
diff --git a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
index 70a875192c..40da2c6e5c 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index 8723ea78e4..da7d189281 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec3 vertex_attrib;
@@ -63,9 +63,9 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) && defined(GL_KHR_shader_subgroup_vote)
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) && defined(has_GL_KHR_shader_subgroup_vote)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
index 5be0893c4f..b0606efa94 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_store.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl
index cdd35dfb3f..4110a95ddb 100644
--- a/servers/rendering/renderer_rd/shaders/copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/copy.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
index 9751e13b4e..8c68e2dc2f 100644
--- a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
+++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -37,7 +37,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 1, std430) uniform Params {
vec4 section;
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
index c3ac0bee57..dfbce29119 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
@@ -26,7 +26,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
index 7f269b7af3..9fa84657d1 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
@@ -22,7 +22,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
index 987545fb76..2a774b0eb4 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
@@ -22,7 +22,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define GROUP_SIZE 64
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
index 5cbb00baa4..ce7c03c1d4 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define GROUP_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
new file mode 100644
index 0000000000..ccaad13311
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -0,0 +1,18 @@
+
+struct DecalData {
+ mat4 xform; //to decal transform
+ vec3 inv_extents;
+ float albedo_mix;
+ vec4 albedo_rect;
+ vec4 normal_rect;
+ vec4 orm_rect;
+ vec4 emission_rect;
+ vec4 modulate;
+ float emission_energy;
+ uint mask;
+ float upper_fade;
+ float lower_fade;
+ mat3x4 normal_xform;
+ vec3 normal;
+ float normal_fade;
+};
diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl
index 92a5682572..bfd5c4c88d 100644
--- a/servers/rendering/renderer_rd/shaders/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/gi.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl
index b931461b31..49a493cdc7 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef MODE_DYNAMIC
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
index 515cc35507..7d4d72967a 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
struct CellData {
uint position; // xyz 10 bits
@@ -172,7 +172,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec4 color_interp;
layout(location = 0) out vec4 frag_color;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
index 5b3dec0ee7..e20b3f680d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
index 56b3b7ccb4..5dc2d08a3b 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
new file mode 100644
index 0000000000..46b571a5f5
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -0,0 +1,83 @@
+
+struct LightData { //this structure needs to be as packed as possible
+ vec3 position;
+ float inv_radius;
+
+ vec3 direction;
+ float size;
+
+ vec3 color;
+ float attenuation;
+
+ float cone_attenuation;
+ float cone_angle;
+ float specular_amount;
+ bool shadow_enabled;
+
+ vec4 atlas_rect; // rect in the shadow atlas
+ mat4 shadow_matrix;
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ uint mask;
+ float shadow_volumetric_fog_fade;
+ uint pad;
+ vec4 projector_rect; //projector rect in srgb decal atlas
+};
+
+#define REFLECTION_AMBIENT_DISABLED 0
+#define REFLECTION_AMBIENT_ENVIRONMENT 1
+#define REFLECTION_AMBIENT_COLOR 2
+
+struct ReflectionData {
+ vec3 box_extents;
+ float index;
+ vec3 box_offset;
+ uint mask;
+ vec3 ambient; // ambient color
+ float intensity;
+ bool exterior;
+ bool box_project;
+ uint ambient_mode;
+ uint pad;
+ //0-8 is intensity,8-9 is ambient, mode
+ mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ // notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+struct DirectionalLightData {
+ vec3 direction;
+ float energy;
+ vec3 color;
+ float size;
+ float specular;
+ uint mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ bool blend_splits;
+ bool shadow_enabled;
+ float fade_from;
+ float fade_to;
+ uvec3 pad;
+ float shadow_volumetric_fog_fade;
+ vec4 shadow_bias;
+ vec4 shadow_normal_bias;
+ vec4 shadow_transmittance_bias;
+ vec4 shadow_z_range;
+ vec4 shadow_range_begin;
+ vec4 shadow_split_offsets;
+ mat4 shadow_matrix1;
+ mat4 shadow_matrix2;
+ mat4 shadow_matrix3;
+ mat4 shadow_matrix4;
+ vec4 shadow_color1;
+ vec4 shadow_color2;
+ vec4 shadow_color3;
+ vec4 shadow_color4;
+ vec2 uv_scale1;
+ vec2 uv_scale2;
+ vec2 uv_scale3;
+ vec2 uv_scale4;
+};
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
index 8a11c35b78..466442b67a 100644
--- a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index cb6d8dc7f6..beaff10793 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
@@ -76,6 +76,11 @@ struct FrameParams {
float time;
float delta;
+ uint frame;
+ uint pad0;
+ uint pad1;
+ uint pad2;
+
uint random_seed;
uint attractor_count;
uint collider_count;
@@ -92,10 +97,16 @@ layout(set = 1, binding = 0, std430) restrict buffer FrameHistory {
}
frame_history;
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+#define PARTICLE_FRAME_MASK uint(0xFFFF)
+#define PARTICLE_FRAME_SHIFT uint(16)
+
struct ParticleData {
mat4 xform;
vec3 velocity;
- bool is_active;
+ uint flags;
vec4 color;
vec4 custom;
};
@@ -146,11 +157,11 @@ layout(set = 2, binding = 1) uniform texture2D height_field_texture;
/* SET 3: MATERIAL */
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 3, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
@@ -162,7 +173,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
bool use_fractional_delta;
bool sub_emitter_mode;
bool can_emit;
- uint pad;
+ bool trail_pass;
}
params;
@@ -196,15 +207,19 @@ bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom
return true;
}
-/* clang-format off */
-
-COMPUTE_SHADER_GLOBALS
-
-/* clang-format on */
+#GLOBALS
void main() {
uint particle = gl_GlobalInvocationID.x;
+ if (params.trail_size > 1) {
+ if (params.trail_pass) {
+ particle += (particle / (params.trail_size - 1)) + 1;
+ } else {
+ particle *= params.trail_size;
+ }
+ }
+
if (particle >= params.total_particles * params.trail_size) {
return; //discard
}
@@ -233,7 +248,7 @@ void main() {
PARTICLE.color = vec4(1.0);
PARTICLE.custom = vec4(0.0);
PARTICLE.velocity = vec3(0.0);
- PARTICLE.is_active = false;
+ PARTICLE.flags = 0;
PARTICLE.xform = mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
@@ -241,6 +256,29 @@ void main() {
vec4(0.0, 0.0, 0.0, 1.0));
}
+ //clear started flag if set
+
+ if (params.trail_pass) {
+ //trail started
+ uint src_idx = index * params.trail_size;
+ if (bool(particles.data[src_idx].flags & PARTICLE_FLAG_STARTED)) {
+ //save start conditions for trails
+ PARTICLE.color = particles.data[src_idx].color;
+ PARTICLE.custom = particles.data[src_idx].custom;
+ PARTICLE.velocity = particles.data[src_idx].velocity;
+ PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start
+ PARTICLE.xform = particles.data[src_idx].xform;
+ }
+
+ if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now
+ // we just assume that this is the first frame of the particle, the rest is deterministic
+ PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT));
+ return; //- this appears like it should be correct, but it seems not to be.. wonder why.
+ }
+ } else {
+ PARTICLE.flags &= ~PARTICLE_FLAG_STARTED;
+ }
+
bool collided = false;
vec3 collision_normal = vec3(0.0);
float collision_depth = 0.0;
@@ -249,14 +287,121 @@ void main() {
#if !defined(DISABLE_VELOCITY)
- if (PARTICLE.is_active) {
+ if (bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta;
}
#endif
- /* Process physics if active */
+ if (!params.trail_pass && params.sub_emitter_mode) {
+ if (!bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
+ int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
+
+ if (src_index >= 0) {
+ PARTICLE.flags = (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT));
+ restart = true;
+
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
+ PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
+ } else {
+ PARTICLE.xform[3] = vec4(0, 0, 0, 1);
+ restart_position = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
+ PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
+ PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
+ PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
+ } else {
+ PARTICLE.xform[0] = vec4(1, 0, 0, 0);
+ PARTICLE.xform[1] = vec4(0, 1, 0, 0);
+ PARTICLE.xform[2] = vec4(0, 0, 1, 0);
+ restart_rotation_scale = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
+ PARTICLE.velocity = src_particles.data[src_index].velocity;
+ } else {
+ PARTICLE.velocity = vec3(0);
+ restart_velocity = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
+ PARTICLE.color = src_particles.data[src_index].color;
+ } else {
+ PARTICLE.color = vec4(1);
+ restart_color = true;
+ }
- if (PARTICLE.is_active) {
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
+ PARTICLE.custom = src_particles.data[src_index].custom;
+ } else {
+ PARTICLE.custom = vec4(0);
+ restart_custom = true;
+ }
+ }
+ }
+
+ } else if (FRAME.emitting) {
+ float restart_phase = float(index) / float(params.total_particles);
+
+ if (FRAME.randomness > 0.0) {
+ uint seed = FRAME.cycle;
+ if (restart_phase >= FRAME.system_phase) {
+ seed -= uint(1);
+ }
+ seed *= uint(params.total_particles);
+ seed += uint(index);
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
+ }
+
+ restart_phase *= (1.0 - FRAME.explosiveness);
+
+ if (FRAME.system_phase > FRAME.prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+
+ if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+
+ } else if (FRAME.delta > 0.0) {
+ if (restart_phase >= FRAME.prev_system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
+ }
+
+ } else if (restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+ }
+
+ if (params.trail_pass) {
+ restart = false;
+ }
+
+ if (restart) {
+ PARTICLE.flags = FRAME.emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT)) : 0;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
+ }
+ }
+
+ bool particle_active = bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE);
+
+ uint particle_number = (PARTICLE.flags >> PARTICLE_FRAME_SHIFT) * uint(params.total_particles) + index;
+
+ if (restart && particle_active) {
+#CODE : START
+ }
+
+ if (particle_active) {
for (uint i = 0; i < FRAME.attractor_count; i++) {
vec3 dir;
float amount;
@@ -434,116 +579,12 @@ void main() {
}
}
- if (params.sub_emitter_mode) {
- if (!PARTICLE.is_active) {
- int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
-
- if (src_index >= 0) {
- PARTICLE.is_active = true;
- restart = true;
-
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
- PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
- } else {
- PARTICLE.xform[3] = vec4(0, 0, 0, 1);
- restart_position = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
- PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
- PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
- PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
- } else {
- PARTICLE.xform[0] = vec4(1, 0, 0, 0);
- PARTICLE.xform[1] = vec4(0, 1, 0, 0);
- PARTICLE.xform[2] = vec4(0, 0, 1, 0);
- restart_rotation_scale = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
- PARTICLE.velocity = src_particles.data[src_index].velocity;
- } else {
- PARTICLE.velocity = vec3(0);
- restart_velocity = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
- PARTICLE.color = src_particles.data[src_index].color;
- } else {
- PARTICLE.color = vec4(1);
- restart_color = true;
- }
-
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
- PARTICLE.custom = src_particles.data[src_index].custom;
- } else {
- PARTICLE.custom = vec4(0);
- restart_custom = true;
- }
- }
- }
-
- } else if (FRAME.emitting) {
- float restart_phase = float(index) / float(params.total_particles);
-
- if (FRAME.randomness > 0.0) {
- uint seed = FRAME.cycle;
- if (restart_phase >= FRAME.system_phase) {
- seed -= uint(1);
- }
- seed *= uint(params.total_particles);
- seed += uint(index);
- float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
- }
-
- restart_phase *= (1.0 - FRAME.explosiveness);
-
- if (FRAME.system_phase > FRAME.prev_system_phase) {
- // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
-
- if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
-
- } else if (FRAME.delta > 0.0) {
- if (restart_phase >= FRAME.prev_system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
- }
-
- } else if (restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
- }
-
- uint current_cycle = FRAME.cycle;
-
- if (FRAME.system_phase < restart_phase) {
- current_cycle -= uint(1);
- }
-
- uint particle_number = current_cycle * uint(params.total_particles) + particle;
-
- if (restart) {
- PARTICLE.is_active = FRAME.emitting;
- restart_position = true;
- restart_rotation_scale = true;
- restart_velocity = true;
- restart_color = true;
- restart_custom = true;
- }
+ if (particle_active) {
+#CODE : PROCESS
}
- if (PARTICLE.is_active) {
- /* clang-format off */
-
-COMPUTE_SHADER_CODE
-
- /* clang-format on */
+ PARTICLE.flags &= ~PARTICLE_FLAG_ACTIVE;
+ if (particle_active) {
+ PARTICLE.flags |= PARTICLE_FLAG_ACTIVE;
}
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index 6c782b6045..7804d66d1c 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -2,14 +2,18 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+
struct ParticleData {
mat4 xform;
vec3 velocity;
- bool is_active;
+ uint flags;
vec4 color;
vec4 custom;
};
@@ -33,12 +37,30 @@ sort_buffer;
#endif // USE_SORT_BUFFER
+layout(set = 2, binding = 0, std430) restrict readonly buffer TrailBindPoses {
+ mat4 data[];
+}
+trail_bind_poses;
+
layout(push_constant, binding = 0, std430) uniform Params {
vec3 sort_direction;
uint total_particles;
+
+ uint trail_size;
+ uint trail_total;
+ float frame_delta;
+ float frame_remainder;
+
+ vec3 align_up;
+ uint align_mode;
}
params;
+#define TRANSFORM_ALIGN_DISABLED 0
+#define TRANSFORM_ALIGN_Z_BILLBOARD 1
+#define TRANSFORM_ALIGN_Y_TO_VELOCITY 2
+#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY 3
+
void main() {
#ifdef MODE_FILL_SORT_BUFFER
@@ -47,7 +69,11 @@ void main() {
return; //discard
}
- sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[particle].xform[3].xyz);
+ uint src_particle = particle;
+ if (params.trail_size > 1) {
+ src_particle = src_particle * params.trail_size + params.trail_size / 2; //use trail center for sorting
+ }
+ sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[src_particle].xform[3].xyz);
sort_buffer.data[particle].y = float(particle);
#endif
@@ -61,13 +87,78 @@ void main() {
}
#ifdef USE_SORT_BUFFER
- particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
+
+ if (params.trail_size > 1) {
+ particle = uint(sort_buffer.data[particle / params.trail_size].y) + (particle % params.trail_size);
+ } else {
+ particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
+ }
#endif
mat4 txform;
- if (particles.data[particle].is_active) {
- txform = transpose(particles.data[particle].xform);
+ if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) {
+ txform = particles.data[particle].xform;
+ if (params.trail_size > 1) {
+ // since the steps dont fit precisely in the history frames, must do a tiny bit of
+ // interpolation to get them close to their intended location.
+ uint part_ofs = particle % params.trail_size;
+ float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta;
+
+ txform[3].xyz -= particles.data[particle].velocity * natural_ofs;
+ }
+
+ switch (params.align_mode) {
+ case TRANSFORM_ALIGN_DISABLED: {
+ } break; //nothing
+ case TRANSFORM_ALIGN_Z_BILLBOARD: {
+ mat3 local = mat3(normalize(cross(params.align_up, params.sort_direction)), params.align_up, params.sort_direction);
+ local = local * mat3(txform);
+ txform[0].xyz = local[0];
+ txform[1].xyz = local[1];
+ txform[2].xyz = local[2];
+
+ } break;
+ case TRANSFORM_ALIGN_Y_TO_VELOCITY: {
+ vec3 v = particles.data[particle].velocity;
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+ if (length(v) > 0.0) {
+ txform[1].xyz = normalize(v);
+ } else {
+ txform[1].xyz = normalize(txform[1].xyz);
+ }
+
+ txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz));
+ txform[2].xyz = vec3(0.0, 0.0, 1.0) * s;
+ txform[0].xyz *= s;
+ txform[1].xyz *= s;
+ } break;
+ case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
+ vec3 v = particles.data[particle].velocity;
+ vec3 sv = v - params.sort_direction * dot(params.sort_direction, v); //screen velocity
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+
+ if (length(sv) == 0) {
+ sv = params.align_up;
+ }
+
+ sv = normalize(sv);
+
+ txform[0].xyz = normalize(cross(sv, params.sort_direction)) * s;
+ txform[1].xyz = sv * s;
+ txform[2].xyz = params.sort_direction * s;
+
+ } break;
+ }
+
+ txform[3].xyz += particles.data[particle].velocity * params.frame_remainder;
+
+ if (params.trail_size > 1) {
+ uint part_ofs = particle % params.trail_size;
+ txform = txform * trail_bind_poses.data[part_ofs];
+ }
+
+ txform = transpose(txform);
} else {
txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible
}
diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl
index e83c4ca93b..2286a26485 100644
--- a/servers/rendering/renderer_rd/shaders/resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/resolve.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
index 464895928a..7b964675ca 100644
--- a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
+++ b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
new file mode 100644
index 0000000000..99714b4504
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
@@ -0,0 +1,58 @@
+#ifdef ALPHA_HASH_USED
+
+float hash_2d(vec2 p) {
+ return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
+}
+
+float hash_3d(vec3 p) {
+ return hash_2d(vec2(hash_2d(p.xy), p.z));
+}
+
+float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
+ vec3 dx = dFdx(pos);
+ vec3 dy = dFdx(pos);
+ float delta_max_sqr = max(length(dx), length(dy));
+ float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
+
+ vec2 pix_scales =
+ vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
+
+ vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
+ hash_3d(floor(pix_scales.y * pos.xyz)));
+
+ float lerp_factor = fract(log2(pix_scale));
+
+ float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
+
+ float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
+
+ vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
+ (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
+ (2.0 * min_lerp * (1.0 - min_lerp))));
+
+ float alpha_hash_threshold =
+ (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
+
+ return clamp(alpha_hash_threshold, 0.0, 1.0);
+}
+
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+
+float calc_mip_level(vec2 texture_coord) {
+ vec2 dx = dFdx(texture_coord);
+ vec2 dy = dFdy(texture_coord);
+ float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
+ return max(0.0, 0.5 * log2(delta_max_sqr));
+}
+
+float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
+ input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
+ input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
+ return clamp(input_alpha, 0.0, 1.0);
+}
+
+#endif // ALPHA_ANTIALIASING_USED
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index adccf1e712..0bb16a8b29 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -2,9 +2,9 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
-#include "scene_forward_inc.glsl"
+#include "scene_forward_clustered_inc.glsl"
/* INPUT ATTRIBS */
@@ -48,11 +48,11 @@ layout(location = 8) in vec4 custom2_attrib;
layout(location = 9) in vec4 custom3_attrib;
#endif
-#if defined(BONES_USED)
+#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS)
layout(location = 10) in uvec4 bone_attrib;
#endif
-#if defined(WEIGHTS_USED)
+#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS)
layout(location = 11) in vec4 weight_attrib;
#endif
@@ -81,16 +81,14 @@ layout(location = 5) out vec3 tangent_interp;
layout(location = 6) out vec3 binormal_interp;
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
-invariant gl_Position;
-
#ifdef MODE_DUAL_PARABOLOID
layout(location = 8) out float dp_clip;
@@ -99,11 +97,9 @@ layout(location = 8) out float dp_clip;
layout(location = 9) out flat uint instance_index;
-/* clang-format off */
-
-VERTEX_SHADER_GLOBALS
+invariant gl_Position;
-/* clang-format on */
+#GLOBALS
void main() {
vec4 instance_custom = vec4(0.0);
@@ -129,10 +125,72 @@ void main() {
if (is_multimesh) {
//multimesh, instances are for it
- uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK;
- offset *= gl_InstanceIndex;
mat4 matrix;
+
+#ifdef USE_PARTICLE_TRAILS
+ uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint stride = 3 + 1 + 1; //particles always uses this format
+
+ uint offset = trail_size * stride * gl_InstanceIndex;
+
+#ifdef COLOR_USED
+ vec4 pcolor;
+#endif
+ {
+ uint boffset = offset + bone_attrib.x * stride;
+ matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
+#ifdef COLOR_USED
+ pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+#endif
+ }
+ if (weight_attrib.y > 0.001) {
+ uint boffset = offset + bone_attrib.y * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+#endif
+ }
+ if (weight_attrib.z > 0.001) {
+ uint boffset = offset + bone_attrib.z * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+#endif
+ }
+ if (weight_attrib.w > 0.001) {
+ uint boffset = offset + bone_attrib.w * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+#endif
+ }
+
+ instance_custom = transforms.data[offset + 4];
+
+#ifdef COLOR_USED
+ color_interp *= pcolor;
+#endif
+
+#else
+ uint stride = 0;
+ {
+ //TODO implement a small lookup table for the stride
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ stride += 2;
+ } else {
+ stride += 3;
+ }
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ stride += 1;
+ }
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
@@ -152,6 +210,7 @@ void main() {
instance_custom = transforms.data[offset];
}
+#endif
//transpose
matrix = transpose(matrix);
world_matrix = world_matrix * matrix;
@@ -169,32 +228,6 @@ void main() {
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
-#if 0
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) {
- //multimesh, instances are for it
-
- uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3;
- uvec2 bones_23 = uvec2(bone_attrib.y & 0xFFFF, bone_attrib.y >> 16) * 3;
- vec2 weights_01 = unpackUnorm2x16(bone_attrib.z);
- vec2 weights_23 = unpackUnorm2x16(bone_attrib.w);
-
- mat4 m = mat4(transforms.data[bones_01.x], transforms.data[bones_01.x + 1], transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x;
- m += mat4(transforms.data[bones_01.y], transforms.data[bones_01.y + 1], transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y;
- m += mat4(transforms.data[bones_23.x], transforms.data[bones_23.x + 1], transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x;
- m += mat4(transforms.data[bones_23.y], transforms.data[bones_23.y + 1], transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y;
-
- //reverse order because its transposed
- vertex = (vec4(vertex, 1.0) * m).xyz;
- normal = (vec4(normal, 0.0) * m).xyz;
-
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-
- tangent = (vec4(tangent, 0.0) * m).xyz;
- binormal = (vec4(binormal, 0.0) * m).xyz;
-#endif
- }
-#endif
-
#ifdef UV_USED
uv_interp = uv_attrib;
#endif
@@ -230,11 +263,7 @@ void main() {
mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix;
{
- /* clang-format off */
-
-VERTEX_SHADER_CODE
-
- /* clang-format on */
+#CODE : VERTEX
}
// using local coordinates (default)
@@ -325,9 +354,9 @@ VERTEX_SHADER_CODE
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
-#include "scene_forward_inc.glsl"
+#include "scene_forward_clustered_inc.glsl"
/* Varyings */
@@ -372,19 +401,15 @@ layout(location = 9) in flat uint instance_index;
#define LIGHT_TRANSMITTANCE_USED
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
-} material;
-#endif
-/* clang-format off */
+#MATERIAL_UNIFORMS
-FRAGMENT_SHADER_GLOBALS
+} material;
+#endif
-/* clang-format on */
+#GLOBALS
#ifdef MODE_RENDER_DEPTH
@@ -396,7 +421,7 @@ layout(location = 2) out vec4 orm_output_buffer;
layout(location = 3) out vec4 emission_output_buffer;
layout(location = 4) out float depth_output_buffer;
-#endif
+#endif // MODE_RENDER_MATERIAL
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
layout(location = 0) out vec4 normal_roughness_output_buffer;
@@ -415,1321 +440,19 @@ layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface sc
#else
layout(location = 0) out vec4 frag_color;
-#endif
+#endif // MODE_MULTIPLE_RENDER_TARGETS
#endif // RENDER DEPTH
-#ifdef ALPHA_HASH_USED
-
-float hash_2d(vec2 p) {
- return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
- (0.1 + abs(sin(13.0 * p.y + p.x))));
-}
-
-float hash_3d(vec3 p) {
- return hash_2d(vec2(hash_2d(p.xy), p.z));
-}
-
-float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
- vec3 dx = dFdx(pos);
- vec3 dy = dFdx(pos);
- float delta_max_sqr = max(length(dx), length(dy));
- float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
-
- vec2 pix_scales =
- vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
-
- vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
- hash_3d(floor(pix_scales.y * pos.xyz)));
-
- float lerp_factor = fract(log2(pix_scale));
-
- float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
-
- float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
-
- vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
- (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
- 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
- (2.0 * min_lerp * (1.0 - min_lerp))));
-
- float alpha_hash_threshold =
- (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
-
- return clamp(alpha_hash_threshold, 0.0, 1.0);
-}
-
-#endif // ALPHA_HASH_USED
-
-#ifdef ALPHA_ANTIALIASING_EDGE_USED
-
-float calc_mip_level(vec2 texture_coord) {
- vec2 dx = dFdx(texture_coord);
- vec2 dy = dFdy(texture_coord);
- float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
- return max(0.0, 0.5 * log2(delta_max_sqr));
-}
-
-float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
- input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
- input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
- return clamp(input_alpha, 0.0, 1.0);
-}
-
-#endif // ALPHA_ANTIALIASING_USED
-
-// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
-// We're dividing this factor off because the overall term we'll end up looks like
-// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
-//
-// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V)
-//
-// We're basically regouping this as
-//
-// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)]
-//
-// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V.
-//
-// The contents of the D and G (G1) functions (GGX) are taken from
-// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
-// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
+#include "scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-float G_GGX_2cos(float cos_theta_m, float alpha) {
- // Schlick's approximation
- // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
- // Eq. (19), although see Heitz (2014) the about the problems with his derivation.
- // It nevertheless approximates GGX well with k = alpha/2.
- float k = 0.5 * alpha;
- return 0.5 / (cos_theta_m * (1.0 - k) + k);
-
- // float cos2 = cos_theta_m * cos_theta_m;
- // float sin2 = (1.0 - cos2);
- // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
-}
-
-float D_GGX(float cos_theta_m, float alpha) {
- float alpha2 = alpha * alpha;
- float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
- return alpha2 / (M_PI * d * d);
-}
-
-float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0 - cos2);
- float s_x = alpha_x * cos_phi;
- float s_y = alpha_y * sin_phi;
- return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001);
-}
-
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0 - cos2);
- float r_x = cos_phi / alpha_x;
- float r_y = sin_phi / alpha_y;
- float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
- return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
-}
-
-float SchlickFresnel(float u) {
- float m = 1.0 - u;
- float m2 = m * m;
- return m2 * m2 * m; // pow(m,5)
-}
-
-float GTR1(float NdotH, float a) {
- if (a >= 1.0)
- return 1.0 / M_PI;
- float a2 = a * a;
- float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
- return (a2 - 1.0) / (M_PI * log(a2) * t);
-}
-
-vec3 F0(float metallic, float specular, vec3 albedo) {
- float dielectric = 0.16 * specular * specular;
- // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
- // see https://google.github.io/filament/Filament.md.html
- return mix(vec3(dielectric), albedo, vec3(metallic));
-}
-
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
- float transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 B, vec3 T, float anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOWS
- float A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light, inout vec3 specular_light) {
-
-#if defined(USE_LIGHT_SHADER_CODE)
- // light is written by the light shader
-
- vec3 normal = N;
- vec3 light = L;
- vec3 view = V;
-
- /* clang-format off */
-
-LIGHT_SHADER_CODE
-
- /* clang-format on */
-
-#else
-
-#ifdef USE_SOFT_SHADOWS
- float NdotL = min(A + dot(N, L), 1.0);
-#else
- float NdotL = dot(N, L);
-#endif
- float cNdotL = max(NdotL, 0.0); // clamped NdotL
- float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
- vec3 H = normalize(V + L);
-#endif
-
-#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
- float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
-#else
- float cNdotH = clamp(dot(N, H), 0.0, 1.0);
-#endif
-#endif
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
- float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
-#else
- float cLdotH = clamp(dot(L, H), 0.0, 1.0);
-#endif
-#endif
-
- float metallic = unpackUnorm4x8(orms).z;
- if (metallic < 1.0) {
- float roughness = unpackUnorm4x8(orms).y;
-
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
- float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
-
-#if defined(DIFFUSE_LAMBERT_WRAP)
- // energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
-#elif defined(DIFFUSE_TOON)
-
- diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
-
-#elif defined(DIFFUSE_BURLEY)
-
- {
- float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
- float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
- float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
- diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
- /*
- float energyBias = mix(roughness, 0.0, 0.5);
- float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
- float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
- float f0 = 1.0;
- float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
- float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
-
- diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
- */
- }
-#else
- // lambert
- diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
-#endif
-
- diffuse_light += light_color * diffuse_brdf_NL * attenuation;
-
-#if defined(LIGHT_BACKLIGHT_USED)
- diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
-#endif
-
-#if defined(LIGHT_RIM_USED)
- float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
-#endif
-
-#ifdef LIGHT_TRANSMITTANCE_USED
-
-#ifdef SSS_MODE_SKIN
-
- {
- float scale = 8.25 / transmittance_depth;
- float d = scale * abs(transmittance_z);
- float dd = -d * d;
- vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
-
- diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
- }
-#else
-
- if (transmittance_depth > 0.0) {
- float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
-
- fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
- fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
-
- diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
- }
-
-#endif //SSS_MODE_SKIN
-
-#endif //LIGHT_TRANSMITTANCE_USED
- }
-
- float roughness = unpackUnorm4x8(orms).y;
- if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-
- // D
-
-#if defined(SPECULAR_BLINN)
-
- //normalized blinn
- float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess) * cNdotL;
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = blinn;
-
- specular_light += light_color * intensity * attenuation * specular_amount;
-
-#elif defined(SPECULAR_PHONG)
-
- vec3 R = normalize(-reflect(L, N));
- float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
- float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float phong = pow(cRdotV, shininess);
- phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
-
- specular_light += light_color * intensity * attenuation * specular_amount;
-
-#elif defined(SPECULAR_TOON)
-
- vec3 R = normalize(-reflect(L, N));
- float RdotV = dot(R, V);
- float mid = 1.0 - roughness;
- mid *= mid;
- float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
- diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
-
-#elif defined(SPECULAR_DISABLED)
- // none..
-
-#elif defined(SPECULAR_SCHLICK_GGX)
- // shlick+ggx as default
-
-#if defined(LIGHT_ANISOTROPY_USED)
-
- float alpha_ggx = roughness * roughness;
- float aspect = sqrt(1.0 - anisotropy * 0.9);
- float ax = alpha_ggx / aspect;
- float ay = alpha_ggx * aspect;
- float XdotH = dot(T, H);
- float YdotH = dot(B, H);
- float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
- float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
-
-#else
- float alpha_ggx = roughness * roughness;
- float D = D_GGX(cNdotH, alpha_ggx);
- float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx);
-#endif
- // F
- float cLdotH5 = SchlickFresnel(cLdotH);
- vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
-
- vec3 specular_brdf_NL = cNdotL * D * F * G;
-
- specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
-#endif
-
-#if defined(LIGHT_CLEARCOAT_USED)
-
-#if !defined(SPECULAR_SCHLICK_GGX)
- float cLdotH5 = SchlickFresnel(cLdotH);
-#endif
- float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
- float Fr = mix(.04, 1.0, cLdotH5);
- float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
-
- float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
-
- specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
-#endif
- }
-
-#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
-#endif
-
-#endif //defined(USE_LIGHT_SHADER_CODE)
-}
-
-#ifndef USE_NO_SHADOWS
-
-// Produces cheap white noise, optimized for window-space
-// Comes from: https://www.shadertoy.com/view/4djSRW
-// Copyright: Dave Hoskins, MIT License
-float quick_hash(vec2 pos) {
- vec3 p3 = fract(vec3(pos.xyx) * .1031);
- p3 += dot(p3, p3.yzx + 33.33);
- return fract((p3.x + p3.y) * p3.z);
-}
-
-float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
- vec2 pos = coord.xy;
- float depth = coord.z;
-
- //if only one sample is taken, take it from the center
- if (scene_data.directional_soft_shadow_samples == 1) {
- return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
- }
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float avg = 0.0;
-
- for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
- }
-
- return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
-}
-
-float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
- vec2 pos = coord.xy;
- float depth = coord.z;
-
- //if only one sample is taken, take it from the center
- if (scene_data.soft_shadow_samples == 1) {
- return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
- }
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float avg = 0.0;
-
- for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
- }
-
- return avg * (1.0 / float(scene_data.soft_shadow_samples));
-}
-
-float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
- //find blocker
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
- vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < pssm_coord.z) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (pssm_coord.z - blocker_average) / blocker_average;
- tex_scale *= penumbra;
-
- float s = 0.0;
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
- vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
- }
-
- return s / float(scene_data.directional_penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- return 1.0;
- }
-}
-
-#endif //USE_NO_SHADOWS
-
-float get_omni_attenuation(float distance, float inv_range, float decay) {
- float nd = distance * inv_range;
- nd *= nd;
- nd *= nd; // nd^4
- nd = max(1.0 - nd, 0.0);
- nd *= nd; // nd^2
- return nd * pow(max(distance, 0.0001), -decay);
-}
-
-float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
- if (omni_lights.data[idx].shadow_enabled) {
- // there is a shadowmap
-
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
-
- vec4 v = vec4(vertex, 1.0);
-
- vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
-
- {
- vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
- nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
- v.xyz += nofs;
- splane = (omni_lights.data[idx].shadow_matrix * v);
- }
-
- float shadow;
-
-#ifdef USE_SOFT_SHADOWS
- if (omni_lights.data[idx].soft_shadow_size > 0.0) {
- //soft shadow
-
- //find blocker
-
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- vec3 normal = normalize(splane.xyz);
- vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
- vec3 tangent = normalize(cross(v0, normal));
- vec3 bitangent = normalize(cross(tangent, normal));
- float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
-
- tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
- bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
-
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
-
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
-
- pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
-
- if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
- }
-
- pos.xy /= pos.z;
-
- 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;
- if (d < z_norm) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (z_norm - blocker_average) / blocker_average;
- tangent *= penumbra;
- bitangent *= penumbra;
-
- z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
-
- shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
-
- pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
-
- if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
- }
-
- pos.xy /= pos.z;
-
- pos.xy = pos.xy * 0.5 + 0.5;
- pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
- }
-
- shadow /= float(scene_data.penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- shadow = 1.0;
- }
- } else {
-#endif
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
-
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
- }
-
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
- shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
-#ifdef USE_SOFT_SHADOWS
- }
-#endif
-
- return shadow;
- }
-#endif
-
- return 1.0;
-}
-
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light, inout vec3 specular_light) {
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
- float light_attenuation = omni_attenuation;
- vec3 color = omni_lights.data[idx].color;
-
-#ifdef USE_SOFT_SHADOWS
- float size_A = 0.0;
-
- if (omni_lights.data[idx].size > 0.0) {
- float t = omni_lights.data[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
- }
-#endif
-
-#ifdef LIGHT_TRANSMITTANCE_USED
- float transmittance_z = transmittance_depth; //no transmittance by default
- transmittance_color.a *= light_attenuation;
- {
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- //redo shadowmapping, but shrink the model a bit to avoid arctifacts
- vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
-
- shadow_len = length(splane.xyz);
- splane = normalize(splane.xyz);
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
-
- } else {
- splane.z = 1.0 - splane.z;
- }
-
- splane.xy /= splane.z;
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = shadow_len * omni_lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- 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;
- transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
- }
-#endif
-
-#if 0
-
- if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
- vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
- local_v = normalize(local_v);
-
- vec4 atlas_rect = omni_lights.data[idx].projector_rect;
-
- if (local_v.z >= 0.0) {
- local_v.z += 1.0;
- atlas_rect.y += atlas_rect.w;
-
- } else {
- local_v.z = 1.0 - local_v.z;
- }
-
- local_v.xy /= local_v.z;
- local_v.xy = local_v.xy * 0.5 + 0.5;
- vec2 proj_uv = local_v.xy * atlas_rect.zw;
-
- vec2 proj_uv_ddx;
- vec2 proj_uv_ddy;
- {
- vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
- local_v_ddx = normalize(local_v_ddx);
-
- if (local_v_ddx.z >= 0.0) {
- local_v_ddx.z += 1.0;
- } else {
- local_v_ddx.z = 1.0 - local_v_ddx.z;
- }
-
- local_v_ddx.xy /= local_v_ddx.z;
- local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
-
- proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
-
- vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
- local_v_ddy = normalize(local_v_ddy);
-
- if (local_v_ddy.z >= 0.0) {
- local_v_ddy.z += 1.0;
- } else {
- local_v_ddy.z = 1.0 - local_v_ddy.z;
- }
-
- local_v_ddy.xy /= local_v_ddy.z;
- local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
-
- proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
- }
-
- vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
- no_shadow = mix(no_shadow, proj.rgb, proj.a);
- }
-#endif
-
- light_attenuation *= shadow;
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * omni_attenuation, rim_tint, rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOWS
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
-}
-
-float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
- if (spot_lights.data[idx].shadow_enabled) {
- vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- vec3 spot_dir = spot_lights.data[idx].direction;
- //there is a shadowmap
- vec4 v = vec4(vertex, 1.0);
-
- v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
-
- float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
-
- float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
- normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
- v.xyz += normal_bias;
-
- //adjust with bias
- z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
-
- float shadow;
-
- vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
- splane /= splane.w;
-
-#ifdef USE_SOFT_SHADOWS
- if (spot_lights.data[idx].soft_shadow_size > 0.0) {
- //soft shadow
-
- //find blocker
-
- vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
-
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
- vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = shadow_uv + (disk_rotation * scene_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;
- if (d < z_norm) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (z_norm - blocker_average) / blocker_average;
- uv_size *= penumbra;
-
- shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
- suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
- }
-
- shadow /= float(scene_data.penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- shadow = 1.0;
- }
-
- } else {
-#endif
- //hard shadow
- vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
-
- shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
-#ifdef USE_SOFT_SHADOWS
- }
-#endif
-
- return shadow;
- }
-
-#endif //USE_NO_SHADOWS
-
- return 1.0;
-}
-
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light,
- inout vec3 specular_light) {
- vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
- vec3 spot_dir = spot_lights.data[idx].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle));
- spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
- float light_attenuation = spot_attenuation;
- vec3 color = spot_lights.data[idx].color;
- float specular_amount = spot_lights.data[idx].specular_amount;
-
-#ifdef USE_SOFT_SHADOWS
- float size_A = 0.0;
-
- if (spot_lights.data[idx].size > 0.0) {
- float t = spot_lights.data[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
- }
-#endif
-
- /*
- if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
-
-#ifdef LIGHT_TRANSMITTANCE_USED
- float transmittance_z = transmittance_depth;
- transmittance_color.a *= light_attenuation;
- {
- splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
- 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;
- //reconstruct depth
- shadow_z /= spot_lights.data[idx].inv_radius;
- //distance to light plane
- float z = dot(spot_dir, -light_rel_vec);
- transmittance_z = z - shadow_z;
- }
-#endif //LIGHT_TRANSMITTANCE_USED
-
- light_attenuation *= shadow;
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * spot_attenuation, rim_tint, rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOW
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
-}
-
-void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
- vec3 box_extents = reflections.data[ref_index].box_extents;
- vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
-
- if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
- return;
- }
-
- vec3 ref_vec = normalize(reflect(vertex, normal));
-
- vec3 inner_pos = abs(local_pos / box_extents);
- float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
- //make blend more rounded
- blend = mix(length(inner_pos), blend, blend);
- blend *= blend;
- blend = max(0.0, 1.0 - blend);
-
- if (reflections.data[ref_index].intensity > 0.0) { // compute reflection
-
- vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
-
- if (reflections.data[ref_index].box_project) { //box project
-
- vec3 nrdir = normalize(local_ref_vec);
- vec3 rbmax = (box_extents - local_pos) / nrdir;
- vec3 rbmin = (-box_extents - local_pos) / nrdir;
-
- vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
-
- float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
- vec3 posonbox = local_pos + nrdir * fa;
- local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
- }
-
- 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;
-
- if (reflections.data[ref_index].exterior) {
- reflection.rgb = mix(specular_light, reflection.rgb, blend);
- }
-
- reflection.rgb *= reflections.data[ref_index].intensity; //intensity
- reflection.a = blend;
- reflection.rgb *= reflection.a;
-
- reflection_accum += reflection;
- }
-
- switch (reflections.data[ref_index].ambient_mode) {
- case REFLECTION_AMBIENT_DISABLED: {
- //do nothing
- } break;
- case REFLECTION_AMBIENT_ENVIRONMENT: {
- //do nothing
- vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
-
- 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.a = blend;
- if (reflections.data[ref_index].exterior) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
-
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- } break;
- case REFLECTION_AMBIENT_COLOR: {
- vec4 ambient_out;
- ambient_out.a = blend;
- ambient_out.rgb = reflections.data[ref_index].ambient;
- if (reflections.data[ref_index].exterior) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- } break;
- }
-}
+#include "scene_forward_lights_inc.glsl"
#ifdef USE_FORWARD_GI
-//standard voxel cone trace
-vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
- float dist = p_bias;
- vec4 color = vec4(0.0);
-
- while (dist < max_distance && color.a < 0.95) {
- float diameter = max(1.0, 2.0 * tan_half_angle * dist);
- vec3 uvw_pos = (pos + dist * direction) * cell_size;
- float half_diameter = diameter * 0.5;
- //check if outside, then break
- 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));
- float a = (1.0 - color.a);
- color += a * scolor;
- dist += half_diameter;
- }
-
- return color;
-}
-
-vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
- float dist = p_bias;
- vec4 color = vec4(0.0);
- float radius = max(0.5, tan_half_angle * dist);
- float lod_level = log2(radius * 2.0);
-
- while (dist < max_distance && color.a < 0.95) {
- vec3 uvw_pos = (pos + dist * direction) * cell_size;
-
- //check if outside, then break
- 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);
- lod_level += 1.0;
-
- float a = (1.0 - color.a);
- scolor *= a;
- color += scolor;
- dist += radius;
- radius = max(0.5, tan_half_angle * dist);
- }
-
- return color;
-}
-
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
-
- position += normal * gi_probes.data[index].normal_bias;
-
- //this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
- return;
- }
-
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
- float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
- //float blend=1.0;
-
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
-
- //radiance
-
-#define MAX_CONE_DIRS 4
-
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
- vec3(0.707107, 0.0, 0.707107),
- vec3(0.0, 0.707107, 0.707107),
- vec3(-0.707107, 0.0, 0.707107),
- vec3(0.0, -0.707107, 0.707107));
-
- float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
- float cone_angle_tan = 0.98269;
-
- vec3 light = vec3(0.0);
-
- for (int i = 0; i < MAX_CONE_DIRS; i++) {
- vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
-
- vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-
- if (gi_probes.data[index].blend_ambient) {
- cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
- }
-
- light += cone_weights[i] * cone_light.rgb;
- }
-
- light *= gi_probes.data[index].dynamic_range;
- out_diff += vec4(light * blend, blend);
-
- //irradiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
- irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
- }
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
- //irr_light=vec3(0.0);
-
- out_spec += vec4(irr_light.rgb * blend, blend);
-}
-
-vec2 octahedron_wrap(vec2 v) {
- vec2 signVal;
- signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
- signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
- return (1.0 - abs(v.yx)) * signVal;
-}
-
-vec2 octahedron_encode(vec3 n) {
- // https://twitter.com/Stubbesaurus/status/937994790553227264
- n /= (abs(n.x) + abs(n.y) + abs(n.z));
- n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy);
- n.xy = n.xy * 0.5 + 0.5;
- return n.xy;
-}
-
-void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) {
- cascade_pos += cam_normal * sdfgi.normal_bias;
-
- vec3 base_pos = floor(cascade_pos);
- //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal;
- ivec3 probe_base_pos = ivec3(base_pos);
-
- vec4 diffuse_accum = vec4(0.0);
- vec3 specular_accum;
-
- ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade));
- tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
- tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1);
-
- vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
-
- vec3 specular_posf;
-
- if (use_specular) {
- specular_accum = vec3(0.0);
- specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
- }
-
- vec4 light_accum = vec4(0.0);
- float weight_accum = 0.0;
-
- for (uint j = 0; j < 8; j++) {
- ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
- ivec3 probe_posi = probe_base_pos;
- probe_posi += offset;
-
- // Compute weight
-
- vec3 probe_pos = vec3(probe_posi);
- vec3 probe_to_pos = cascade_pos - probe_pos;
- vec3 probe_dir = normalize(-probe_to_pos);
-
- vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
- float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir));
-
- // Compute lightprobe occlusion
-
- if (sdfgi.use_occlusion) {
- ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
- vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
-
- vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
- occ_pos.z += float(cascade);
- if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
- occ_pos.x += 1.0;
- }
-
- occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask);
-
- weight *= max(occlusion, 0.01);
- }
-
- // Compute lightprobe texture position
-
- vec3 diffuse;
- 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_accum += vec4(diffuse * weight, weight);
-
- if (use_specular) {
- vec3 specular = vec3(0.0);
- vec3 pos_uvw = specular_posf;
- 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;
- }
- 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_accum += specular * weight;
- }
- }
-
- if (diffuse_accum.a > 0.0) {
- diffuse_accum.rgb /= diffuse_accum.a;
- }
-
- diffuse_light = diffuse_accum.rgb;
-
- if (use_specular) {
- if (diffuse_accum.a > 0.0) {
- specular_accum /= diffuse_accum.a;
- }
-
- specular_light = specular_accum;
- }
-
- {
- //process blend
- float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5;
- float blend_to = blend_from + 2.0;
-
- vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe;
-
- float len = length(inner_pos);
-
- inner_pos = abs(normalize(inner_pos));
- len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z));
-
- if (len >= blend_from) {
- blend = smoothstep(blend_from, blend_to, len);
- } else {
- blend = 0.0;
- }
- }
-}
+#include "scene_forward_gi_inc.glsl"
#endif //USE_FORWARD_GI
@@ -1737,8 +460,6 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
#ifndef MODE_RENDER_DEPTH
-#ifndef LOW_END_MODE
-
vec4 volumetric_fog_process(vec2 screen_uv, float z) {
vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length);
if (fog_pos.z < 0.0) {
@@ -1749,7 +470,6 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) {
return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
}
-#endif
vec4 fog_process(vec3 vertex) {
vec3 fog_color = scene_data.fog_light_color;
@@ -1813,26 +533,6 @@ uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
}
-float blur_shadow(float shadow) {
- return shadow;
-#if 0
- //disabling for now, will investigate later
- float interp_shadow = shadow;
- if (gl_HelperInvocation) {
- interp_shadow = -4.0; // technically anything below -4 will do but just to make sure
- }
-
- uvec2 fc2 = uvec2(gl_FragCoord.xy);
- interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5);
- interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5);
-
- if (interp_shadow >= 0.0) {
- shadow = interp_shadow;
- }
- return shadow;
-#endif
-}
-
#endif //!MODE_RENDER DEPTH
void main() {
@@ -1930,11 +630,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
{
- /* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
- /* clang-format on */
+#CODE : FRAGMENT
}
#ifdef LIGHT_TRANSMITTANCE_USED
@@ -2021,7 +717,6 @@ FRAGMENT_SHADER_CODE
fog = fog_process(vertex);
}
-#ifndef LOW_END_MODE
if (scene_data.volumetric_fog_enabled) {
vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z);
if (scene_data.fog_enabled) {
@@ -2039,7 +734,6 @@ FRAGMENT_SHADER_CODE
fog = volumetric_fog;
}
}
-#endif //!LOW_END_MODE
#endif //!CUSTOM_FOG_USED
uint fog_rg = packHalf2x16(fog.rg);
@@ -2379,7 +1073,7 @@ FRAGMENT_SHADER_CODE
specular_light = spec_accum.rgb;
ambient_light = amb_accum.rgb;
}
-#elif !defined(LOW_END_MODE)
+#else
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
@@ -2414,13 +1108,11 @@ FRAGMENT_SHADER_CODE
}
#endif
-#ifndef LOW_END_MODE
if (scene_data.ssao_enabled) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
ao = min(ao, ssao);
ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
}
-#endif //LOW_END_MODE
{ // process reflections
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index d78890fa9e..ca75d6300e 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -3,7 +3,7 @@
#define MAX_GI_PROBES 8
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic)
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
@@ -13,6 +13,7 @@
#endif
#include "cluster_data_inc.glsl"
+#include "decal_data_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
#ifndef NORMAL_USED
@@ -28,7 +29,11 @@ layout(push_constant, binding = 0, std430) uniform DrawCall {
}
draw_call;
-/* Set 0 Scene data that never changes, ever */
+#define SDFGI_MAX_CASCADES 8
+
+/* Set 0: Base Pass (never changes) */
+
+#include "light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -43,10 +48,6 @@ draw_call;
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-#define SDFGI_MAX_CASCADES 8
-
-/* Set 1: Base Pass (never changes) */
-
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
@@ -61,12 +62,11 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
-#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
//3 bits of stride
-#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_SKELETON (1 << 19)
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20)
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
@@ -78,7 +78,7 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
}
spot_lights;
-layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData {
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
@@ -122,8 +122,6 @@ layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableDat
}
global_variables;
-#ifndef LOW_END_MODE
-
struct SDFGIProbeCascadeData {
vec3 position;
float to_probe;
@@ -159,9 +157,7 @@ layout(set = 0, binding = 13, std140) uniform SDFGI {
}
sdfgi;
-#endif //LOW_END_MODE
-
-/* Set 2: Render Pass (changes per render pass) */
+/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
mat4 projection_matrix;
@@ -245,7 +241,6 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
bool pancake_shadows;
}
-
scene_data;
struct InstanceData {
@@ -280,9 +275,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-#ifndef LOW_END_MOD
layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
-#endif
layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
uint data[];
@@ -306,8 +299,6 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
layout(set = 1, binding = 9) uniform texture2D depth_buffer;
layout(set = 1, binding = 10) uniform texture2D color_buffer;
-#ifndef LOW_END_MODE
-
layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer;
layout(set = 1, binding = 12) uniform texture2D ao_buffer;
layout(set = 1, binding = 13) uniform texture2D ambient_buffer;
@@ -338,8 +329,6 @@ gi_probes;
layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
-#endif // LOW_END_MODE
-
#endif
/* Set 2 Skeleton & Instancing (can change per item) */
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
new file mode 100644
index 0000000000..b41f16cbe7
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -0,0 +1,242 @@
+// Functions related to gi/sdfgi for our forward renderer
+
+//standard voxel cone trace
+vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ 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));
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += half_diameter;
+ }
+
+ return color;
+}
+
+vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+ float radius = max(0.5, tan_half_angle * dist);
+ float lod_level = log2(radius * 2.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+
+ //check if outside, then break
+ 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);
+ lod_level += 1.0;
+
+ float a = (1.0 - color.a);
+ scolor *= a;
+ color += scolor;
+ dist += radius;
+ radius = max(0.5, tan_half_angle * dist);
+ }
+
+ return color;
+}
+
+void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
+ position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
+
+ position += normal * gi_probes.data[index].normal_bias;
+
+ //this causes corrupted pixels, i have no idea why..
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
+ return;
+ }
+
+ vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
+ //float blend=1.0;
+
+ float max_distance = length(gi_probes.data[index].bounds);
+ vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
+
+ //radiance
+
+#define MAX_CONE_DIRS 4
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.707107, 0.0, 0.707107),
+ vec3(0.0, 0.707107, 0.707107),
+ vec3(-0.707107, 0.0, 0.707107),
+ vec3(0.0, -0.707107, 0.707107));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
+ float cone_angle_tan = 0.98269;
+
+ vec3 light = vec3(0.0);
+
+ for (int i = 0; i < MAX_CONE_DIRS; i++) {
+ vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+
+ vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+
+ if (gi_probes.data[index].blend_ambient) {
+ cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
+ }
+
+ light += cone_weights[i] * cone_light.rgb;
+ }
+
+ light *= gi_probes.data[index].dynamic_range;
+ out_diff += vec4(light * blend, blend);
+
+ //irradiance
+ vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
+ if (gi_probes.data[index].blend_ambient) {
+ irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
+ }
+ irr_light.rgb *= gi_probes.data[index].dynamic_range;
+ //irr_light=vec3(0.0);
+
+ out_spec += vec4(irr_light.rgb * blend, blend);
+}
+
+vec2 octahedron_wrap(vec2 v) {
+ vec2 signVal;
+ signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
+ signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
+ return (1.0 - abs(v.yx)) * signVal;
+}
+
+vec2 octahedron_encode(vec3 n) {
+ // https://twitter.com/Stubbesaurus/status/937994790553227264
+ n /= (abs(n.x) + abs(n.y) + abs(n.z));
+ n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy);
+ n.xy = n.xy * 0.5 + 0.5;
+ return n.xy;
+}
+
+void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) {
+ cascade_pos += cam_normal * sdfgi.normal_bias;
+
+ vec3 base_pos = floor(cascade_pos);
+ //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal;
+ ivec3 probe_base_pos = ivec3(base_pos);
+
+ vec4 diffuse_accum = vec4(0.0);
+ vec3 specular_accum;
+
+ ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade));
+ tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
+ tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1);
+
+ vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
+
+ vec3 specular_posf;
+
+ if (use_specular) {
+ specular_accum = vec3(0.0);
+ specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
+ }
+
+ vec4 light_accum = vec4(0.0);
+ float weight_accum = 0.0;
+
+ for (uint j = 0; j < 8; j++) {
+ ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
+ ivec3 probe_posi = probe_base_pos;
+ probe_posi += offset;
+
+ // Compute weight
+
+ vec3 probe_pos = vec3(probe_posi);
+ vec3 probe_to_pos = cascade_pos - probe_pos;
+ vec3 probe_dir = normalize(-probe_to_pos);
+
+ vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
+ float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir));
+
+ // Compute lightprobe occlusion
+
+ if (sdfgi.use_occlusion) {
+ ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
+ occ_pos.z += float(cascade);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+
+ occ_pos *= sdfgi.occlusion_renormalize;
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask);
+
+ weight *= max(occlusion, 0.01);
+ }
+
+ // Compute lightprobe texture position
+
+ vec3 diffuse;
+ 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_accum += vec4(diffuse * weight, weight);
+
+ if (use_specular) {
+ vec3 specular = vec3(0.0);
+ vec3 pos_uvw = specular_posf;
+ 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;
+ }
+ 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_accum += specular * weight;
+ }
+ }
+
+ if (diffuse_accum.a > 0.0) {
+ diffuse_accum.rgb /= diffuse_accum.a;
+ }
+
+ diffuse_light = diffuse_accum.rgb;
+
+ if (use_specular) {
+ if (diffuse_accum.a > 0.0) {
+ specular_accum /= diffuse_accum.a;
+ }
+
+ specular_light = specular_accum;
+ }
+
+ {
+ //process blend
+ float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5;
+ float blend_to = blend_from + 2.0;
+
+ vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe;
+
+ float len = length(inner_pos);
+
+ inner_pos = abs(normalize(inner_pos));
+ len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+
+ if (len >= blend_from) {
+ blend = smoothstep(blend_from, blend_to, len);
+ } else {
+ blend = 0.0;
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
new file mode 100644
index 0000000000..32a86cb166
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -0,0 +1,1023 @@
+// Functions related to lighting
+
+// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
+// We're dividing this factor off because the overall term we'll end up looks like
+// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
+//
+// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V)
+//
+// We're basically regouping this as
+//
+// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)]
+//
+// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V.
+//
+// The contents of the D and G (G1) functions (GGX) are taken from
+// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
+// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
+
+float G_GGX_2cos(float cos_theta_m, float alpha) {
+ // Schlick's approximation
+ // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
+ // Eq. (19), although see Heitz (2014) the about the problems with his derivation.
+ // It nevertheless approximates GGX well with k = alpha/2.
+ float k = 0.5 * alpha;
+ return 0.5 / (cos_theta_m * (1.0 - k) + k);
+
+ // float cos2 = cos_theta_m * cos_theta_m;
+ // float sin2 = (1.0 - cos2);
+ // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
+}
+
+float D_GGX(float cos_theta_m, float alpha) {
+ float alpha2 = alpha * alpha;
+ float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
+ return alpha2 / (M_PI * d * d);
+}
+
+float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
+ float cos2 = cos_theta_m * cos_theta_m;
+ float sin2 = (1.0 - cos2);
+ float s_x = alpha_x * cos_phi;
+ float s_y = alpha_y * sin_phi;
+ return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001);
+}
+
+float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
+ float cos2 = cos_theta_m * cos_theta_m;
+ float sin2 = (1.0 - cos2);
+ float r_x = cos_phi / alpha_x;
+ float r_y = sin_phi / alpha_y;
+ float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
+ return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
+}
+
+float SchlickFresnel(float u) {
+ float m = 1.0 - u;
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a) {
+ if (a >= 1.0)
+ return 1.0 / M_PI;
+ float a2 = a * a;
+ float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
+}
+
+vec3 F0(float metallic, float specular, vec3 albedo) {
+ float dielectric = 0.16 * specular * specular;
+ // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
+ // see https://google.github.io/filament/Filament.md.html
+ return mix(vec3(dielectric), albedo, vec3(metallic));
+}
+
+void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+ float transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 B, vec3 T, float anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOWS
+ float A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+
+#if defined(LIGHT_CODE_USED)
+ // light is written by the light shader
+
+ vec3 normal = N;
+ vec3 light = L;
+ vec3 view = V;
+
+#CODE : LIGHT
+
+#else
+
+#ifdef USE_SOFT_SHADOWS
+ float NdotL = min(A + dot(N, L), 1.0);
+#else
+ float NdotL = dot(N, L);
+#endif
+ float cNdotL = max(NdotL, 0.0); // clamped NdotL
+ float NdotV = dot(N, V);
+ float cNdotV = max(NdotV, 0.0);
+
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+ vec3 H = normalize(V + L);
+#endif
+
+#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+#ifdef USE_SOFT_SHADOWS
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
+#else
+ float cNdotH = clamp(dot(N, H), 0.0, 1.0);
+#endif
+#endif
+
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+#ifdef USE_SOFT_SHADOWS
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
+#else
+ float cLdotH = clamp(dot(L, H), 0.0, 1.0);
+#endif
+#endif
+
+ float metallic = unpackUnorm4x8(orms).z;
+ if (metallic < 1.0) {
+ float roughness = unpackUnorm4x8(orms).y;
+
+#if defined(DIFFUSE_OREN_NAYAR)
+ vec3 diffuse_brdf_NL;
+#else
+ float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
+#endif
+
+#if defined(DIFFUSE_LAMBERT_WRAP)
+ // energy conserving lambert wrap shader
+ diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+#elif defined(DIFFUSE_TOON)
+
+ diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
+
+#elif defined(DIFFUSE_BURLEY)
+
+ {
+ float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
+ float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
+ float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
+ diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
+ /*
+ float energyBias = mix(roughness, 0.0, 0.5);
+ float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
+ float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
+ float f0 = 1.0;
+ float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
+ float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
+
+ diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
+ */
+ }
+#else
+ // lambert
+ diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
+#endif
+
+ diffuse_light += light_color * diffuse_brdf_NL * attenuation;
+
+#if defined(LIGHT_BACKLIGHT_USED)
+ diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
+#endif
+
+#if defined(LIGHT_RIM_USED)
+ float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+ diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
+#endif
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+
+#ifdef SSS_MODE_SKIN
+
+ {
+ float scale = 8.25 / transmittance_depth;
+ float d = scale * abs(transmittance_z);
+ float dd = -d * d;
+ vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+
+ diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
+ }
+#else
+
+ if (transmittance_depth > 0.0) {
+ float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
+
+ fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
+ fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
+
+ diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
+ }
+
+#endif //SSS_MODE_SKIN
+
+#endif //LIGHT_TRANSMITTANCE_USED
+ }
+
+ float roughness = unpackUnorm4x8(orms).y;
+ if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
+
+ // D
+
+#if defined(SPECULAR_BLINN)
+
+ //normalized blinn
+ float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
+ float blinn = pow(cNdotH, shininess) * cNdotL;
+ blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float intensity = blinn;
+
+ specular_light += light_color * intensity * attenuation * specular_amount;
+
+#elif defined(SPECULAR_PHONG)
+
+ vec3 R = normalize(-reflect(L, N));
+ float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
+ float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
+ float phong = pow(cRdotV, shininess);
+ phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
+
+ specular_light += light_color * intensity * attenuation * specular_amount;
+
+#elif defined(SPECULAR_TOON)
+
+ vec3 R = normalize(-reflect(L, N));
+ float RdotV = dot(R, V);
+ float mid = 1.0 - roughness;
+ mid *= mid;
+ float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
+ diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
+
+#elif defined(SPECULAR_DISABLED)
+ // none..
+
+#elif defined(SPECULAR_SCHLICK_GGX)
+ // shlick+ggx as default
+
+#if defined(LIGHT_ANISOTROPY_USED)
+
+ float alpha_ggx = roughness * roughness;
+ float aspect = sqrt(1.0 - anisotropy * 0.9);
+ float ax = alpha_ggx / aspect;
+ float ay = alpha_ggx * aspect;
+ float XdotH = dot(T, H);
+ float YdotH = dot(B, H);
+ float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
+ float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
+
+#else
+ float alpha_ggx = roughness * roughness;
+ float D = D_GGX(cNdotH, alpha_ggx);
+ float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx);
+#endif
+ // F
+ float cLdotH5 = SchlickFresnel(cLdotH);
+ vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
+
+ vec3 specular_brdf_NL = cNdotL * D * F * G;
+
+ specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
+#endif
+
+#if defined(LIGHT_CLEARCOAT_USED)
+
+#if !defined(SPECULAR_SCHLICK_GGX)
+ float cLdotH5 = SchlickFresnel(cLdotH);
+#endif
+ float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
+ float Fr = mix(.04, 1.0, cLdotH5);
+ float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
+
+ float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
+
+ specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
+#endif
+ }
+
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
+#endif
+
+#endif //defined(LIGHT_CODE_USED)
+}
+
+#ifndef USE_NO_SHADOWS
+
+// Interleaved Gradient Noise
+// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+float quick_hash(vec2 pos) {
+ const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+ return fract(magic.z * fract(dot(pos, magic.xy)));
+}
+
+float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+ vec2 pos = coord.xy;
+ float depth = coord.z;
+
+ //if only one sample is taken, take it from the center
+ if (scene_data.directional_soft_shadow_samples == 1) {
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+
+ for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
+ }
+
+ return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
+}
+
+float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+ vec2 pos = coord.xy;
+ float depth = coord.z;
+
+ //if only one sample is taken, take it from the center
+ if (scene_data.soft_shadow_samples == 1) {
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+
+ for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
+ }
+
+ return avg * (1.0 / float(scene_data.soft_shadow_samples));
+}
+
+float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
+ //find blocker
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
+ float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ if (d < pssm_coord.z) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (pssm_coord.z - blocker_average) / blocker_average;
+ tex_scale *= penumbra;
+
+ float s = 0.0;
+ for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
+ s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
+ }
+
+ return s / float(scene_data.directional_penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ return 1.0;
+ }
+}
+
+#endif //USE_NO_SHADOWS
+
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+
+float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
+#ifndef USE_NO_SHADOWS
+ if (omni_lights.data[idx].shadow_enabled) {
+ // there is a shadowmap
+
+ vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+
+ vec4 v = vec4(vertex, 1.0);
+
+ vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
+ float shadow_len = length(splane.xyz); //need to remember shadow len from here
+
+ {
+ vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
+ nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
+ v.xyz += nofs;
+ splane = (omni_lights.data[idx].shadow_matrix * v);
+ }
+
+ float shadow;
+
+#ifdef USE_SOFT_SHADOWS
+ if (omni_lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ vec3 normal = normalize(splane.xyz);
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
+
+ tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
+ bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
+
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
+
+ vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+
+ pos = normalize(pos);
+ vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ if (pos.z >= 0.0) {
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ 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;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ tangent *= penumbra;
+ bitangent *= penumbra;
+
+ z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
+ vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+
+ pos = normalize(pos);
+ vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ if (pos.z >= 0.0) {
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
+ } else {
+#endif
+ splane.xyz = normalize(splane.xyz);
+ vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
+
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+
+ clamp_rect.y += clamp_rect.w;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
+
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ splane.w = 1.0; //needed? i think it should be 1 already
+ shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
+#ifdef USE_SOFT_SHADOWS
+ }
+#endif
+
+ return shadow;
+ }
+#endif
+
+ return 1.0;
+}
+
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
+ float light_attenuation = omni_attenuation;
+ vec3 color = omni_lights.data[idx].color;
+
+#ifdef USE_SOFT_SHADOWS
+ float size_A = 0.0;
+
+ if (omni_lights.data[idx].size > 0.0) {
+ float t = omni_lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+#endif
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth; //no transmittance by default
+ transmittance_color.a *= light_attenuation;
+ {
+ vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
+
+ //redo shadowmapping, but shrink the model a bit to avoid arctifacts
+ vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
+
+ shadow_len = length(splane.xyz);
+ splane = normalize(splane.xyz);
+
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len * omni_lights.data[idx].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ 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;
+ transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
+ }
+#endif
+
+#if 0
+
+ if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
+ vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ local_v = normalize(local_v);
+
+ vec4 atlas_rect = omni_lights.data[idx].projector_rect;
+
+ if (local_v.z >= 0.0) {
+ local_v.z += 1.0;
+ atlas_rect.y += atlas_rect.w;
+
+ } else {
+ local_v.z = 1.0 - local_v.z;
+ }
+
+ local_v.xy /= local_v.z;
+ local_v.xy = local_v.xy * 0.5 + 0.5;
+ vec2 proj_uv = local_v.xy * atlas_rect.zw;
+
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
+
+ if (local_v_ddx.z >= 0.0) {
+ local_v_ddx.z += 1.0;
+ } else {
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
+
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+
+ vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
+
+ if (local_v_ddy.z >= 0.0) {
+ local_v_ddy.z += 1.0;
+ } else {
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
+
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ }
+#endif
+
+ light_attenuation *= shadow;
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * omni_attenuation, rim_tint, rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOWS
+ size_A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+}
+
+float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
+#ifndef USE_NO_SHADOWS
+ if (spot_lights.data[idx].shadow_enabled) {
+ vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ vec3 spot_dir = spot_lights.data[idx].direction;
+ //there is a shadowmap
+ vec4 v = vec4(vertex, 1.0);
+
+ v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
+
+ float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
+
+ float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
+ vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
+ normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
+ v.xyz += normal_bias;
+
+ //adjust with bias
+ z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
+
+ float shadow;
+
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
+ splane /= splane.w;
+
+#ifdef USE_SOFT_SHADOWS
+ if (spot_lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
+ vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 suv = shadow_uv + (disk_rotation * scene_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;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ uv_size *= penumbra;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
+ suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
+
+ } else {
+#endif
+ //hard shadow
+ vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
+
+ shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
+#ifdef USE_SOFT_SHADOWS
+ }
+#endif
+
+ return shadow;
+ }
+
+#endif //USE_NO_SHADOWS
+
+ return 1.0;
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
+ vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
+ vec3 spot_dir = spot_lights.data[idx].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
+ float light_attenuation = spot_attenuation;
+ vec3 color = spot_lights.data[idx].color;
+ float specular_amount = spot_lights.data[idx].specular_amount;
+
+#ifdef USE_SOFT_SHADOWS
+ float size_A = 0.0;
+
+ if (spot_lights.data[idx].size > 0.0) {
+ float t = spot_lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+#endif
+
+ /*
+ if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
+ //use projector texture
+ }
+ */
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth;
+ transmittance_color.a *= light_attenuation;
+ {
+ splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
+ 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;
+ //reconstruct depth
+ shadow_z /= spot_lights.data[idx].inv_radius;
+ //distance to light plane
+ float z = dot(spot_dir, -light_rel_vec);
+ transmittance_z = z - shadow_z;
+ }
+#endif //LIGHT_TRANSMITTANCE_USED
+
+ light_attenuation *= shadow;
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * spot_attenuation, rim_tint, rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOW
+ size_A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+}
+
+void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
+ vec3 box_extents = reflections.data[ref_index].box_extents;
+ vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
+
+ if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
+ return;
+ }
+
+ vec3 ref_vec = normalize(reflect(vertex, normal));
+
+ vec3 inner_pos = abs(local_pos / box_extents);
+ float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+ //make blend more rounded
+ blend = mix(length(inner_pos), blend, blend);
+ blend *= blend;
+ blend = max(0.0, 1.0 - blend);
+
+ if (reflections.data[ref_index].intensity > 0.0) { // compute reflection
+
+ vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
+
+ if (reflections.data[ref_index].box_project) { //box project
+
+ vec3 nrdir = normalize(local_ref_vec);
+ vec3 rbmax = (box_extents - local_pos) / nrdir;
+ vec3 rbmin = (-box_extents - local_pos) / nrdir;
+
+ vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
+
+ float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
+ vec3 posonbox = local_pos + nrdir * fa;
+ local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
+ }
+
+ 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;
+
+ if (reflections.data[ref_index].exterior) {
+ reflection.rgb = mix(specular_light, reflection.rgb, blend);
+ }
+
+ reflection.rgb *= reflections.data[ref_index].intensity; //intensity
+ reflection.a = blend;
+ reflection.rgb *= reflection.a;
+
+ reflection_accum += reflection;
+ }
+
+ switch (reflections.data[ref_index].ambient_mode) {
+ case REFLECTION_AMBIENT_DISABLED: {
+ //do nothing
+ } break;
+ case REFLECTION_AMBIENT_ENVIRONMENT: {
+ //do nothing
+ vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
+
+ 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.a = blend;
+ if (reflections.data[ref_index].exterior) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ } break;
+ case REFLECTION_AMBIENT_COLOR: {
+ vec4 ambient_out;
+ ambient_out.a = blend;
+ ambient_out.rgb = reflections.data[ref_index].ambient;
+ if (reflections.data[ref_index].exterior) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ } break;
+ }
+}
+
+float blur_shadow(float shadow) {
+ return shadow;
+#if 0
+ //disabling for now, will investigate later
+ float interp_shadow = shadow;
+ if (gl_HelperInvocation) {
+ interp_shadow = -4.0; // technically anything below -4 will do but just to make sure
+ }
+
+ uvec2 fc2 = uvec2(gl_FragCoord.xy);
+ interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5);
+ interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5);
+
+ if (interp_shadow >= 0.0) {
+ shadow = interp_shadow;
+ }
+ return shadow;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
new file mode 100644
index 0000000000..b38b8d803d
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -0,0 +1,1476 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Include our forward mobile UBOs definitions etc. */
+#include "scene_forward_mobile_inc.glsl"
+
+/* INPUT ATTRIBS */
+
+layout(location = 0) in vec3 vertex_attrib;
+
+//only for pure render depth when normal is not used
+
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_attrib;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 2) in vec4 tangent_attrib;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 3) in vec4 color_attrib;
+#endif
+
+#ifdef UV_USED
+layout(location = 4) in vec2 uv_attrib;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL)
+layout(location = 5) in vec2 uv2_attrib;
+#endif // MODE_RENDER_MATERIAL
+
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
+#endif
+
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
+#endif
+
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
+#endif
+
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
+#endif
+
+#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS)
+layout(location = 10) in uvec4 bone_attrib;
+#endif
+
+#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS)
+layout(location = 11) in vec4 weight_attrib;
+#endif
+
+/* Varyings */
+
+layout(location = 0) out vec3 vertex_interp;
+
+#ifdef NORMAL_USED
+layout(location = 1) out vec3 normal_interp;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 2) out vec4 color_interp;
+#endif
+
+#ifdef UV_USED
+layout(location = 3) out vec2 uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) out vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) out vec3 tangent_interp;
+layout(location = 6) out vec3 binormal_interp;
+#endif
+
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
+
+#MATERIAL_UNIFORMS
+
+} material;
+#endif
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) out float dp_clip;
+
+#endif
+
+invariant gl_Position;
+
+#GLOBALS
+
+void main() {
+ vec4 instance_custom = vec4(0.0);
+#if defined(COLOR_USED)
+ color_interp = color_attrib;
+#endif
+
+ bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH);
+
+ mat4 world_matrix = draw_call.transform;
+
+ mat3 world_normal_matrix;
+ if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ world_normal_matrix = inverse(mat3(world_matrix));
+ } else {
+ world_normal_matrix = mat3(world_matrix);
+ }
+
+ if (is_multimesh) {
+ //multimesh, instances are for it
+
+ mat4 matrix;
+
+#ifdef USE_PARTICLE_TRAILS
+ uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint stride = 3 + 1 + 1; //particles always uses this format
+
+ uint offset = trail_size * stride * gl_InstanceIndex;
+
+#ifdef COLOR_USED
+ vec4 pcolor;
+#endif
+ {
+ uint boffset = offset + bone_attrib.x * stride;
+ matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
+#ifdef COLOR_USED
+ pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+#endif
+ }
+ if (weight_attrib.y > 0.001) {
+ uint boffset = offset + bone_attrib.y * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+#endif
+ }
+ if (weight_attrib.z > 0.001) {
+ uint boffset = offset + bone_attrib.z * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+#endif
+ }
+ if (weight_attrib.w > 0.001) {
+ uint boffset = offset + bone_attrib.w * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+#endif
+ }
+
+ instance_custom = transforms.data[offset + 4];
+
+#ifdef COLOR_USED
+ color_interp *= pcolor;
+#endif
+
+#else
+ uint stride = 0;
+ {
+ //TODO implement a small lookup table for the stride
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ stride += 2;
+ } else {
+ stride += 3;
+ }
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ stride += 1;
+ }
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 2;
+ } else {
+ matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], transforms.data[offset + 2], vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 3;
+ }
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+#ifdef COLOR_USED
+ color_interp *= transforms.data[offset];
+#endif
+ offset += 1;
+ }
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ instance_custom = transforms.data[offset];
+ }
+
+#endif
+ //transpose
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
+ world_normal_matrix = world_normal_matrix * mat3(matrix);
+ }
+
+ vec3 vertex = vertex_attrib;
+#ifdef NORMAL_USED
+ vec3 normal = normal_attrib * 2.0 - 1.0;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+ float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#endif
+
+#ifdef UV_USED
+ uv_interp = uv_attrib;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = uv2_attrib;
+#endif
+
+#ifdef OVERRIDE_POSITION
+ vec4 position;
+#endif
+
+ mat4 projection_matrix = scene_data.projection_matrix;
+
+//using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (world_matrix * vec4(vertex, 1.0)).xyz;
+
+ normal = world_normal_matrix * normal;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ tangent = world_normal_matrix * tangent;
+ binormal = world_normal_matrix * binormal;
+
+#endif
+#endif
+
+ float roughness = 1.0;
+
+ mat4 modelview = scene_data.inv_camera_matrix * world_matrix;
+ mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix;
+
+ {
+#CODE : VERTEX
+ }
+
+ /* output */
+
+// using local coordinates (default)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = modelview_normal * normal;
+#endif
+
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ binormal = modelview_normal * binormal;
+ tangent = modelview_normal * tangent;
+#endif
+
+//using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz;
+ normal = mat3(scene_data.inverse_normal_matrix) * normal;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal;
+ tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent;
+#endif
+#endif
+
+ vertex_interp = vertex;
+#ifdef NORMAL_USED
+ normal_interp = normal;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ tangent_interp = tangent;
+ binormal_interp = binormal;
+#endif
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_DUAL_PARABOLOID
+
+ vertex_interp.z *= scene_data.dual_paraboloid_side;
+
+ dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+
+ //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
+
+ vec3 vtx = vertex_interp;
+ float distance = length(vtx);
+ vtx = normalize(vtx);
+ vtx.xy /= 1.0 - vtx.z;
+ vtx.z = (distance / scene_data.z_far);
+ vtx.z = vtx.z * 2.0 - 1.0;
+ vertex_interp = vtx;
+
+#endif
+
+#endif //MODE_RENDER_DEPTH
+
+#ifdef OVERRIDE_POSITION
+ gl_Position = position;
+#else
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
+#endif // OVERRIDE_POSITION
+
+#ifdef MODE_RENDER_DEPTH
+ if (scene_data.pancake_shadows) {
+ if (gl_Position.z <= 0.00001) {
+ gl_Position.z = 0.00001;
+ }
+ }
+#endif // MODE_RENDER_DEPTH
+#ifdef MODE_RENDER_MATERIAL
+ if (scene_data.material_uv2_mode) {
+ vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass...
+ gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0;
+ gl_Position.z = 0.00001;
+ gl_Position.w = 1.0;
+ }
+#endif // MODE_RENDER_MATERIAL
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Include our forward mobile UBOs definitions etc. */
+#include "scene_forward_mobile_inc.glsl"
+
+/* Varyings */
+
+layout(location = 0) in vec3 vertex_interp;
+
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_interp;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 2) in vec4 color_interp;
+#endif
+
+#ifdef UV_USED
+layout(location = 3) in vec2 uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) in vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) in vec3 tangent_interp;
+layout(location = 6) in vec3 binormal_interp;
+#endif
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) in float dp_clip;
+
+#endif
+
+//defines to keep compatibility with vertex
+
+#define world_matrix draw_call.transform
+#define projection_matrix scene_data.projection_matrix
+
+#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE)
+//both required for transmittance to be enabled
+#define LIGHT_TRANSMITTANCE_USED
+#endif
+
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
+
+#MATERIAL_UNIFORMS
+
+} material;
+#endif
+
+#GLOBALS
+
+/* clang-format on */
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+layout(location = 0) out vec4 albedo_output_buffer;
+layout(location = 1) out vec4 normal_output_buffer;
+layout(location = 2) out vec4 orm_output_buffer;
+layout(location = 3) out vec4 emission_output_buffer;
+layout(location = 4) out float depth_output_buffer;
+
+#endif // MODE_RENDER_MATERIAL
+
+#else // RENDER DEPTH
+
+#ifdef MODE_MULTIPLE_RENDER_TARGETS
+
+layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
+layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
+#else
+
+layout(location = 0) out vec4 frag_color;
+#endif // MODE_MULTIPLE_RENDER_TARGETS
+
+#endif // RENDER DEPTH
+
+#include "scene_forward_aa_inc.glsl"
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#include "scene_forward_lights_inc.glsl"
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifndef MODE_RENDER_DEPTH
+
+/*
+ Only supporting normal fog here.
+*/
+
+vec4 fog_process(vec3 vertex) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+ if (scene_data.fog_aerial_perspective > 0.0) {
+ vec3 sky_fog_color = vec3(0.0);
+ vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
+ // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
+ float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
+#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);
+#else
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[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.fog_aerial_perspective);
+ }
+
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ vec3 view = normalize(vertex);
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy;
+ float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+
+ float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+
+ if (abs(scene_data.fog_height_density) > 0.001) {
+ float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
+
+ float y_dist = scene_data.fog_height - y;
+
+ float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+
+ fog_amount = max(vfog_amount, fog_amount);
+ }
+
+ return vec4(fog_color, fog_amount);
+}
+
+#endif //!MODE_RENDER DEPTH
+
+void main() {
+#ifdef MODE_DUAL_PARABOLOID
+
+ if (dp_clip > 0.0)
+ discard;
+#endif
+
+ //lay out everything, whathever is unused is optimized away anyway
+ vec3 vertex = vertex_interp;
+ vec3 view = -normalize(vertex_interp);
+ vec3 albedo = vec3(1.0);
+ vec3 backlight = vec3(0.0);
+ vec4 transmittance_color = vec4(0.0);
+ float transmittance_depth = 0.0;
+ float transmittance_curve = 1.0;
+ float transmittance_boost = 0.0;
+ float metallic = 0.0;
+ float specular = 0.5;
+ vec3 emission = vec3(0.0);
+ float roughness = 1.0;
+ float rim = 0.0;
+ float rim_tint = 0.0;
+ float clearcoat = 0.0;
+ float clearcoat_gloss = 0.0;
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
+ vec4 fog = vec4(0.0);
+#if defined(CUSTOM_RADIANCE_USED)
+ vec4 custom_radiance = vec4(0.0);
+#endif
+#if defined(CUSTOM_IRRADIANCE_USED)
+ vec4 custom_irradiance = vec4(0.0);
+#endif
+
+ float ao = 1.0;
+ float ao_light_affect = 0.0;
+
+ float alpha = 1.0;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 binormal = normalize(binormal_interp);
+ vec3 tangent = normalize(tangent_interp);
+#else
+ vec3 binormal = vec3(0.0);
+ vec3 tangent = vec3(0.0);
+#endif
+
+#ifdef NORMAL_USED
+ vec3 normal = normalize(normal_interp);
+
+#if defined(DO_SIDE_CHECK)
+ if (!gl_FrontFacing) {
+ normal = -normal;
+ }
+#endif
+
+#endif //NORMAL_USED
+
+#ifdef UV_USED
+ vec2 uv = uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(COLOR_USED)
+ vec4 color = color_interp;
+#endif
+
+#if defined(NORMAL_MAP_USED)
+
+ vec3 normal_map = vec3(0.5);
+#endif
+
+ float normal_map_depth = 1.0;
+
+ vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center
+
+ float sss_strength = 0.0;
+
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
+ {
+#CODE : FRAGMENT
+ }
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+#ifdef SSS_MODE_SKIN
+ transmittance_color.a = sss_strength;
+#else
+ transmittance_color.a *= sss_strength;
+#endif
+#endif
+
+#ifndef USE_SHADOW_TO_OPACITY
+
+#ifdef ALPHA_SCISSOR_USED
+ if (alpha < alpha_scissor_threshold) {
+ discard;
+ }
+#endif // ALPHA_SCISSOR_USED
+
+// alpha hash can be used in unison with alpha antialiasing
+#ifdef ALPHA_HASH_USED
+ if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) {
+ discard;
+ }
+#endif // ALPHA_HASH_USED
+
+// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
+#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
+ alpha = 1.0;
+#endif
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+#ifdef ALPHA_SCISSOR_USED
+ alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
+#endif
+ alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
+#ifdef USE_OPAQUE_PREPASS
+ if (alpha < opaque_prepass_threshold) {
+ discard;
+ }
+#endif // USE_OPAQUE_PREPASS
+
+#endif // !USE_SHADOW_TO_OPACITY
+
+#ifdef NORMAL_MAP_USED
+
+ normal_map.xy = normal_map.xy * 2.0 - 1.0;
+ normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+
+ normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth));
+
+#endif
+
+#ifdef LIGHT_ANISOTROPY_USED
+
+ if (anisotropy > 0.01) {
+ //rotation matrix
+ mat3 rot = mat3(tangent, binormal, normal);
+ //make local to space
+ tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0));
+ }
+
+#endif
+
+#ifdef ENABLE_CLIP_ALPHA
+ if (albedo.a < 0.99) {
+ //used for doublepass and shadowmapping
+ discard;
+ }
+#endif
+
+ /////////////////////// FOG //////////////////////
+#ifndef MODE_RENDER_DEPTH
+
+#ifndef CUSTOM_FOG_USED
+ // fog must be processed as early as possible and then packed.
+ // to maximize VGPR usage
+ // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
+
+ if (scene_data.fog_enabled) {
+ fog = fog_process(vertex);
+ }
+
+#endif //!CUSTOM_FOG_USED
+
+ uint fog_rg = packHalf2x16(fog.rg);
+ uint fog_ba = packHalf2x16(fog.ba);
+
+#endif //!MODE_RENDER_DEPTH
+
+ /////////////////////// DECALS ////////////////////////////////
+
+#ifndef MODE_RENDER_DEPTH
+
+ vec3 vertex_ddx = dFdx(vertex);
+ vec3 vertex_ddy = dFdy(vertex);
+
+ { //Decals
+ // must implement
+
+ uint decal_indices = draw_call.decals.x;
+ for (uint i = 0; i < 8; i++) {
+ uint decal_index = decal_indices & 0xFF;
+ if (i == 4) {
+ decal_indices = draw_call.decals.y;
+ } else {
+ decal_indices = decal_indices >> 8;
+ }
+
+ if (decal_index == 0xFF) {
+ break;
+ }
+
+ vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz;
+ if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) {
+ continue; //out of decal
+ }
+
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
+ float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
+
+ if (decals.data[decal_index].normal_fade > 0.0) {
+ fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
+ }
+
+ if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
+ //has albedo
+ vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ decal_albedo *= decals.data[decal_index].modulate;
+ decal_albedo.a *= fade;
+ albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
+
+ if (decals.data[decal_index].normal_rect != vec4(0.0)) {
+ vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
+ decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
+ //convert to view space, use xzy because y is up
+ decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz;
+
+ normal = normalize(mix(normal, decal_normal, decal_albedo.a));
+ }
+
+ if (decals.data[decal_index].orm_rect != vec4(0.0)) {
+ vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ ao = mix(ao, decal_orm.r, decal_albedo.a);
+ roughness = mix(roughness, decal_orm.g, decal_albedo.a);
+ metallic = mix(metallic, decal_orm.b, decal_albedo.a);
+ }
+ }
+
+ if (decals.data[decal_index].emission_rect != vec4(0.0)) {
+ //emission is additive, so its independent from albedo
+ emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ }
+ }
+ } //Decals
+#endif //!MODE_RENDER_DEPTH
+
+ /////////////////////// LIGHTING //////////////////////////////
+
+#ifdef NORMAL_USED
+ if (scene_data.roughness_limiter_enabled) {
+ //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ float roughness2 = roughness * roughness;
+ vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
+ float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
+ float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
+ roughness = sqrt(filteredRoughness2);
+ }
+#endif // NORMAL_USED
+ //apply energy conservation
+
+ vec3 specular_light = vec3(0.0, 0.0, 0.0);
+ vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
+ vec3 ambient_light = vec3(0.0, 0.0, 0.0);
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ if (scene_data.use_reflection_cubemap) {
+ vec3 ref_vec = reflect(-view, normal);
+ ref_vec = scene_data.radiance_inverse_xform * ref_vec;
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+
+ float lod, blend;
+ blend = modf(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);
+
+#else // USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
+
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= scene_data.ambient_light_color_energy.a;
+ }
+
+#if defined(CUSTOM_RADIANCE_USED)
+ specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a);
+#endif // CUSTOM_RADIANCE_USED
+
+#ifndef USE_LIGHTMAP
+ //lightmap overrides everything
+ if (scene_data.use_ambient_light) {
+ ambient_light = scene_data.ambient_light_color_energy.rgb;
+
+ 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;
+#else
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+
+ ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
+ }
+ }
+#endif // !USE_LIGHTMAP
+
+#if defined(CUSTOM_IRRADIANCE_USED)
+ ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);
+#endif // CUSTOM_IRRADIANCE_USED
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ //radiance
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifdef USE_LIGHTMAP
+
+ //lightmap
+ if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
+ uint index = draw_call.gi_offset;
+
+ vec3 wnormal = mat3(scene_data.camera_matrix) * normal;
+ const float c1 = 0.429043;
+ const float c2 = 0.511664;
+ const float c3 = 0.743125;
+ const float c4 = 0.886227;
+ const float c5 = 0.247708;
+ ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+
+ } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
+ bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
+ uint ofs = draw_call.gi_offset & 0xFFFF;
+ vec3 uvw;
+ uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
+ uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF);
+
+ 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;
+
+ uint idx = draw_call.gi_offset >> 20;
+ vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
+
+ ambient_light += lm_light_l0 * 0.282095f;
+ ambient_light += lm_light_l1n1 * 0.32573 * n.y;
+ ambient_light += lm_light_l1_0 * 0.32573 * n.z;
+ ambient_light += lm_light_l1p1 * 0.32573 * n.x;
+ if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
+ vec3 r = reflect(normalize(-vertex), normal);
+ specular_light += lm_light_l1n1 * 0.32573 * r.y;
+ specular_light += lm_light_l1_0 * 0.32573 * r.z;
+ specular_light += lm_light_l1p1 * 0.32573 * r.x;
+ }
+
+ } else {
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
+ }
+ }
+
+ // No GI nor non low end mode...
+
+#endif // USE_LIGHTMAP
+
+ // skipping ssao, do we remove ssao totally?
+
+ { //Reflection probes
+ vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ uint reflection_indices = draw_call.reflection_probes.x;
+ for (uint i = 0; i < 8; i++) {
+ uint reflection_index = reflection_indices & 0xFF;
+ if (i == 4) {
+ reflection_indices = draw_call.reflection_probes.y;
+ } else {
+ reflection_indices = reflection_indices >> 8;
+ }
+
+ if (reflection_index == 0xFF) {
+ break;
+ }
+
+ reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
+ }
+
+ if (reflection_accum.a > 0.0) {
+ specular_light = reflection_accum.rgb / reflection_accum.a;
+ }
+ } //Reflection probes
+
+ // finalize ambient light here
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+
+ // convert ao to direct light ao
+ ao = mix(1.0, ao, ao_light_affect);
+
+ //this saves some VGPRs
+ vec3 f0 = F0(metallic, specular, albedo);
+
+ {
+#if defined(DIFFUSE_TOON)
+ //simplify for toon, as
+ specular_light *= specular * metallic * albedo * 2.0;
+#else
+
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment, GI, and reflection probes are added
+ // Environment brdf approximation (Lazarov 2013)
+ // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, view), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ specular_light *= env.x * f0 + env.y;
+#endif
+ }
+
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#if !defined(MODE_RENDER_DEPTH)
+ //this saves some VGPRs
+ uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular));
+#endif
+
+// LIGHTING
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ { //directional light
+
+ // Do shadow and lighting in two passes to reduce register pressure
+ uint shadow0 = 0;
+ uint shadow1 = 0;
+
+ for (uint i = 0; i < 8; i++) {
+ if (i >= scene_data.directional_light_count) {
+ break;
+ }
+
+ if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ continue; //not masked
+ }
+
+ float shadow = 1.0;
+
+ // Directional light shadow code is basically the same as forward clustered at this point in time minus `LIGHT_TRANSMITTANCE_USED` support.
+ // Not sure if there is a reason to change this seeing directional lights are part of our global data
+ // Should think about whether we may want to move this code into an include file or function??
+
+#ifdef USE_SOFT_SHADOWS
+ //version with soft shadows, more expensive
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -vertex.z;
+
+ vec4 pssm_coord;
+ vec3 shadow_color = vec3(0.0);
+ vec3 light_dir = directional_lights.data[i].direction;
+
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
+ m_var.xyz += normal_bias;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 0)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.x;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color1.rgb;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 1)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color2.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 2)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color3.rgb;
+
+ } else {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 3)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color4.rgb;
+ }
+
+ if (directional_lights.data[i].blend_splits) {
+ vec3 shadow_color_blend = vec3(0.0);
+ float pssm_blend;
+ float shadow2;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ shadow_color_blend = directional_lights.data[i].shadow_color2.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+
+ shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ shadow_color_blend = directional_lights.data[i].shadow_color4.rgb;
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
+
+ pssm_blend = sqrt(pssm_blend);
+
+ shadow = mix(shadow, shadow2, pssm_blend);
+ shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
+ }
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+
+#undef BIAS_FUNC
+ }
+#else
+ // Soft shadow disabled version
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -vertex.z;
+
+ vec4 pssm_coord;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
+
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
+ m_var.xyz += normal_bias;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 0)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 1)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 2)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+
+ } else {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 3)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ }
+
+ pssm_coord /= pssm_coord.w;
+
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+ float pssm_blend;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
+
+ pssm_coord /= pssm_coord.w;
+
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = mix(shadow, shadow2, pssm_blend);
+ }
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+
+#undef BIAS_FUNC
+ }
+#endif
+
+ if (i < 4) {
+ shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
+ } else {
+ shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
+ }
+ }
+
+ for (uint i = 0; i < 8; i++) {
+ if (i >= scene_data.directional_light_count) {
+ break;
+ }
+
+ if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ continue; //not masked
+ }
+
+ // We're not doing light transmittence
+
+ float shadow = 1.0;
+
+ if (i < 4) {
+ shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
+ } else {
+ shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
+ }
+
+ blur_shadow(shadow);
+
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/* not supported here
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim, rim_tint, albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOW
+ directional_lights.data[i].size,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+ }
+ } //directional light
+
+ { //omni lights
+ uint light_indices = draw_call.omni_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 4) {
+ light_indices = draw_call.omni_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ float shadow = light_process_omni_shadow(light_index, vertex, view);
+
+ shadow = blur_shadow(shadow);
+
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/*
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
+ albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent, binormal, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+ }
+ } //omni lights
+
+ { //spot lights
+
+ uint light_indices = draw_call.spot_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 4) {
+ light_indices = draw_call.spot_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ float shadow = light_process_spot_shadow(light_index, vertex, view);
+
+ shadow = blur_shadow(shadow);
+
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/*
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
+ albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent, binormal, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+ }
+ } //spot lights
+
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
+
+#if defined(ALPHA_SCISSOR_USED)
+ if (alpha < alpha_scissor) {
+ discard;
+ }
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef USE_OPAQUE_PREPASS
+
+ if (alpha < opaque_prepass_threshold) {
+ discard;
+ }
+
+#endif // USE_OPAQUE_PREPASS
+
+#endif // USE_SHADOW_TO_OPACITY
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
+
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+ depth_output_buffer.r = -vertex.z;
+
+ orm_output_buffer.r = ao;
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = sss_strength;
+
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
+#endif // MODE_RENDER_MATERIAL
+
+#else // MODE_RENDER_DEPTH
+
+ // multiply by albedo
+ diffuse_light *= albedo; // ambient must be multiplied by albedo at the end
+
+ // apply direct light AO
+ ao = unpackUnorm4x8(orms).x;
+ specular_light *= ao;
+ diffuse_light *= ao;
+
+ // apply metallic
+ metallic = unpackUnorm4x8(orms).z;
+ diffuse_light *= 1.0 - metallic;
+ ambient_light *= 1.0 - metallic;
+
+ //restore fog
+ fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+
+#ifdef MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ diffuse_buffer = vec4(albedo.rgb, 0.0);
+ specular_buffer = vec4(0.0);
+
+#else // MODE_UNSHADED
+
+#ifdef SSS_MODE_SKIN
+ sss_strength = -sss_strength;
+#endif // SSS_MODE_SKIN
+ diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength);
+ specular_buffer = vec4(specular_light, metallic);
+#endif // MODE_UNSHADED
+
+ diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
+ specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+
+#else //MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ frag_color = vec4(albedo, alpha);
+#else // MODE_UNSHADED
+ frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
+ //frag_color = vec4(1.0);
+#endif // MODE_UNSHADED
+
+ // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+
+#endif //MODE_MULTIPLE_RENDER_TARGETS
+
+#endif //MODE_RENDER_DEPTH
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
new file mode 100644
index 0000000000..0156b58574
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -0,0 +1,220 @@
+#define M_PI 3.14159265359
+
+#include "decal_data_inc.glsl"
+
+#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
+#endif
+#endif
+
+/* don't exceed 128 bytes!! */
+/* put instance data into our push content, not a array */
+layout(push_constant, binding = 0, std430) uniform DrawCall {
+ mat4 transform; // 64 - 64
+ uint flags; // 04 - 68
+ uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
+ uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
+ uint layer_mask; // 04 - 80
+ vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
+
+ uvec2 reflection_probes; // 08 - 104
+ uvec2 omni_lights; // 08 - 112
+ uvec2 spot_lights; // 08 - 120
+ uvec2 decals; // 08 - 128
+}
+draw_call;
+
+/* Set 0: Base Pass (never changes) */
+
+#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];
+
+layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+
+#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
+#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
+#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
+#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
+#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
+#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
+#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
+#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
+#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
+//3 bits of stride
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
+
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+ LightData data[];
+}
+omni_lights;
+
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+ LightData data[];
+}
+spot_lights;
+
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+ ReflectionData data[];
+}
+reflections;
+
+layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+#define LIGHTMAP_FLAG_USE_DIRECTION 1
+#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
+
+struct Lightmap {
+ mat3 normal_xform;
+};
+
+layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+ Lightmap data[];
+}
+lightmaps;
+
+struct LightmapCapture {
+ vec4 sh[9];
+};
+
+layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+ LightmapCapture data[];
+}
+lightmap_captures;
+
+layout(set = 0, binding = 9) uniform texture2D decal_atlas;
+layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+
+layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+ DecalData data[];
+}
+decals;
+
+layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
+
+/* Set 1: Render Pass (changes per render pass) */
+
+layout(set = 1, binding = 0, std140) uniform SceneData {
+ mat4 projection_matrix;
+ mat4 inv_projection_matrix;
+
+ mat4 camera_matrix;
+ mat4 inv_camera_matrix;
+
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
+
+ //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ vec4 directional_penumbra_shadow_kernel[32];
+ vec4 directional_soft_shadow_kernel[32];
+ vec4 penumbra_shadow_kernel[32];
+ vec4 soft_shadow_kernel[32];
+
+ uint directional_penumbra_shadow_samples;
+ uint directional_soft_shadow_samples;
+ uint penumbra_shadow_samples;
+ uint soft_shadow_samples;
+
+ vec4 ambient_light_color_energy;
+
+ float ambient_color_sky_mix;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ mat3 radiance_inverse_xform;
+
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
+ uint directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ bool ssao_enabled;
+ float ssao_light_affect;
+ float ssao_ao_affect;
+ bool roughness_limiter_enabled;
+
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ uvec2 roughness_limiter_pad;
+
+ vec4 ao_color;
+
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ bool material_uv2_mode;
+
+ float time;
+ float reflection_multiplier; // one normally, zero when rendering reflections
+
+ bool pancake_shadows;
+ uint pad1;
+ uint pad2;
+ uint pad3;
+}
+scene_data;
+
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+
+layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+
+#else
+
+layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+
+#endif
+
+layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+
+layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+
+layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+
+// this needs to change to providing just the lightmap we're using..
+layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
+
+layout(set = 1, binding = 9) uniform texture2D depth_buffer;
+layout(set = 1, binding = 10) uniform texture2D color_buffer;
+
+/* Set 2 Skeleton & Instancing (can change per item) */
+
+layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
+ vec4 data[];
+}
+transforms;
+
+/* Set 3 User Material */
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
index 06dc4b13de..78e0a85341 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
index a5afe74cb2..62d1cffb0a 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
index 218605a962..7e06516d90 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
index e4c3f3a84b..8b58796962 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
index 08da283dad..0eacbc5363 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define MAX_CASCADES 8
@@ -153,7 +153,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec4 frag_color;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
index 5e8934adb4..99db35bb34 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
@@ -80,6 +80,7 @@ layout(set = 0, binding = 9, std140) buffer restrict readonly Lights {
lights;
layout(set = 0, binding = 10) uniform texture2DArray lightprobe_texture;
+layout(set = 0, binding = 11) uniform texture3D occlusion_texture;
layout(push_constant, binding = 0, std430) uniform Params {
vec3 grid_size;
@@ -91,9 +92,9 @@ layout(push_constant, binding = 0, std430) uniform Params {
uint process_increment;
int probe_axis_size;
- bool multibounce;
+ float bounce_feedback;
float y_mult;
- uint pad;
+ bool use_occlusion;
}
params;
@@ -159,7 +160,8 @@ void main() {
// Add indirect light first, in order to save computation resources
#ifdef MODE_PROCESS_DYNAMIC
- if (params.multibounce) {
+ if (params.bounce_feedback > 0.001) {
+ vec3 feedback = (params.bounce_feedback < 1.0) ? (albedo * params.bounce_feedback) : mix(albedo, vec3(1.0), params.bounce_feedback - 1.0);
vec3 pos = (vec3(positioni) + vec3(0.5)) * float(params.probe_axis_size - 1) / params.grid_size;
ivec3 probe_base_pos = ivec3(pos);
@@ -172,7 +174,7 @@ void main() {
vec3 base_tex_posf = vec3(tex_pos);
vec2 tex_pixel_size = 1.0 / vec2(ivec2((OCT_SIZE + 2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE + 2) * params.probe_axis_size));
- vec3 probe_uv_offset = (ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx;
+ vec3 probe_uv_offset = vec3(ivec3(OCT_SIZE + 2, OCT_SIZE + 2, (OCT_SIZE + 2) * params.probe_axis_size)) * tex_pixel_size.xyx;
for (uint j = 0; j < 8; j++) {
ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
@@ -192,18 +194,35 @@ void main() {
for (uint k = 0; k < 6; k++) {
if (bool(valid_aniso & (1 << k))) {
vec3 n = aniso_dir[k];
- float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(n, probe_dir));
-
- vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0);
- tex_posf.xy *= tex_pixel_size;
-
- vec3 pos_uvw = tex_posf;
- pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy;
- pos_uvw.x += float(offset.z) * probe_uv_offset.z;
- vec3 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb;
-
- light_accum[k] += indirect_light * weight;
- weight_accum[k] += weight;
+ float weight = trilinear.x * trilinear.y * trilinear.z * max(0, dot(n, probe_dir));
+
+ if (weight > 0.0 && params.use_occlusion) {
+ ivec3 occ_indexv = abs((cascades.data[params.cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = (vec3(positioni) + aniso_dir[k] + vec3(0.5)) / params.grid_size;
+ occ_pos.z += float(params.cascade);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+ occ_pos *= vec3(0.5, 1.0, 1.0 / float(params.max_cascades)); //renormalize
+ float occlusion = dot(textureLod(sampler3D(occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask);
+
+ weight *= occlusion;
+ }
+
+ if (weight > 0.0) {
+ vec3 tex_posf = base_tex_posf + vec3(octahedron_encode(n) * float(OCT_SIZE), 0.0);
+ tex_posf.xy *= tex_pixel_size;
+
+ vec3 pos_uvw = tex_posf;
+ pos_uvw.xy += vec2(offset.xy) * probe_uv_offset.xy;
+ pos_uvw.x += float(offset.z) * probe_uv_offset.z;
+ vec3 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), pos_uvw, 0.0).rgb;
+
+ light_accum[k] += indirect_light * weight;
+ weight_accum[k] += weight;
+ }
}
}
}
@@ -211,7 +230,7 @@ void main() {
for (uint k = 0; k < 6; k++) {
if (weight_accum[k] > 0.0) {
light_accum[k] /= weight_accum[k];
- light_accum[k] *= albedo;
+ light_accum[k] *= feedback;
}
}
}
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
deleted file mode 100644
index 69d8824d8a..0000000000
--- a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
+++ /dev/null
@@ -1,182 +0,0 @@
-/* clang-format off */
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in;
-
-/* clang-format on */
-
-#define MAX_CASCADES 8
-
-layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture;
-layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture;
-
-layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture;
-layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture;
-
-struct CascadeData {
- vec3 offset; //offset of (0,0,0) in world coordinates
- float to_cell; // 1/bounds * grid_size
-};
-
-layout(set = 0, binding = 5, std140) uniform Cascades {
- CascadeData data[MAX_CASCADES];
-}
-cascades;
-
-#define DEPTH_HISTORY_BITS 24
-#define IRRADIANCE_HISTORY_BITS 16
-
-layout(push_constant, binding = 0, std430) uniform Params {
- vec3 grid_size;
- uint max_cascades;
-
- uint probe_axis_size;
- uint cascade;
- uint history_size;
- uint pad0;
-
- ivec3 scroll; //scroll in probes
- uint pad1;
-}
-params;
-
-void main() {
- ivec2 local = ivec2(gl_LocalInvocationID.xy);
- ivec2 probe = ivec2(gl_WorkGroupID.xy);
-
- ivec3 probe_cell;
- probe_cell.x = probe.x % int(params.probe_axis_size);
- probe_cell.y = probe.y;
- probe_cell.z = probe.x / int(params.probe_axis_size);
-
-#ifdef MODE_SCROLL_BEGIN
-
- ivec3 read_cell = probe_cell - params.scroll;
-
- uint src_layer = (params.history_size + 1) * params.cascade;
- uint dst_layer = (params.history_size + 1) * params.max_cascades;
-
- for (uint i = 0; i <= params.history_size; i++) {
- ivec3 write_pos = ivec3(probe * OCT_RES + local, int(i));
-
- if (any(lessThan(read_pos, ivec3(0))) || any(greaterThanEqual(read_pos, ivec3(params.probe_axis_size)))) {
- // nowhere to read from for scrolling, try finding the value from upper probes
-
-#ifdef MODE_IRRADIANCE
- imageStore(irradiance_history_texture, write_pos, uvec4(0));
-#endif
-#ifdef MODE_DEPTH
- imageStore(depth_history_texture, write_pos, uvec4(0));
-#endif
- } else {
- ivec3 read_pos;
- read_pos.xy = read_cell.xy;
- read_pos.x += read_cell.z * params.probe_axis_size;
- read_pos.xy = read_pos.xy * OCT_RES + local;
- read_pos.z = int(i);
-
-#ifdef MODE_IRRADIANCE
- uvec4 value = imageLoad(irradiance_history_texture, read_pos);
- imageStore(irradiance_history_texture, write_pos, value);
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- imageStore(depth_history_texture, write_pos, value);
-#endif
- }
- }
-
-#endif // MODE_SCROLL_BEGIN
-
-#ifdef MODE_SCROLL_END
-
- uint src_layer = (params.history_size + 1) * params.max_cascades;
- uint dst_layer = (params.history_size + 1) * params.cascade;
-
- for (uint i = 0; i <= params.history_size; i++) {
- ivec3 pos = ivec3(probe * OCT_RES + local, int(i));
-
-#ifdef MODE_IRRADIANCE
- uvec4 value = imageLoad(irradiance_history_texture, read_pos);
- imageStore(irradiance_history_texture, write_pos, value);
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- imageStore(depth_history_texture, write_pos, value);
-#endif
- }
-
-#endif //MODE_SCROLL_END
-
-#ifdef MODE_STORE
-
- uint src_layer = (params.history_size + 1) * params.cascade + params.history_size;
- ivec3 read_pos = ivec3(probe * OCT_RES + local, int(src_layer));
-
- ivec3 write_pos = ivec3(probe * (OCT_RES + 2) + ivec2(1), int(params.cascade));
-
- ivec3 copy_to[4] = ivec3[](write_pos, ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2));
-
-#ifdef MODE_IRRADIANCE
- uvec4 average = imageLoad(irradiance_history_texture, read_pos);
- vec4 light_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS);
-
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- vec2 depth_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS);
-
- float probe_cell_size = float(params.grid_size / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell;
- float max_depth = length(params.grid_size / cascades.data[params.max_cascades - 1].to_cell);
- max_depth /= probe_cell_size;
-
- depth_value = (vec2(average / params.history_size) / float(1 << DEPTH_HISTORY_BITS)) * vec2(max_depth, max_depth * max_depth);
-
-#endif
-
- /* Fill the border if required */
-
- if (local == ivec2(0, 0)) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - 1, -1, 0);
- copy_to[2] = texture_pos + ivec3(-1, OCT_RES - 1, 0);
- copy_to[3] = texture_pos + ivec3(OCT_RES, OCT_RES, 0);
- } else if (local == ivec2(OCT_RES - 1, 0)) {
- copy_to[1] = texture_pos + ivec3(0, -1, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES, OCT_RES - 1, 0);
- copy_to[3] = texture_pos + ivec3(-1, OCT_RES, 0);
- } else if (local == ivec2(0, OCT_RES - 1)) {
- copy_to[1] = texture_pos + ivec3(-1, 0, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES - 1, OCT_RES, 0);
- copy_to[3] = texture_pos + ivec3(OCT_RES, -1, 0);
- } else if (local == ivec2(OCT_RES - 1, OCT_RES - 1)) {
- copy_to[1] = texture_pos + ivec3(0, OCT_RES, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES, 0, 0);
- copy_to[3] = texture_pos + ivec3(-1, -1, 0);
- } else if (local.y == 0) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y - 1, 0);
- } else if (local.x == 0) {
- copy_to[1] = texture_pos + ivec3(local.x - 1, OCT_RES - local.y - 1, 0);
- } else if (local.y == OCT_RES - 1) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y + 1, 0);
- } else if (local.x == OCT_RES - 1) {
- copy_to[1] = texture_pos + ivec3(local.x + 1, OCT_RES - local.y - 1, 0);
- }
-
- for (int i = 0; i < 4; i++) {
- if (copy_to[i] == ivec3(-2, -2, -2)) {
- continue;
- }
-#ifdef MODE_IRRADIANCE
- imageStore(irradiance_texture, copy_to[i], light_accum);
-#endif
-#ifdef MODE_DEPTH
- imageStore(depth_texture, copy_to[i], vec4(depth_value, 0.0, 0.0));
-#endif
- }
-
-#endif // MODE_STORE
-}
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
index 007e4c113a..bc376e9522 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
index 916c60ac89..aa4ded146f 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef MODE_JUMPFLOOD_OPTIMIZED
#define GROUP_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index b19f5a9ad3..669ffc961d 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
@@ -100,7 +100,7 @@ void main() {
for (uint i = 0; i < params.blend_shape_count; i++) {
float w = blend_shape_weights.data[i];
- if (w > 0.0001) {
+ if (abs(w) > 0.0001) {
uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w;
diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl
index 6c985e1f5c..9924da37d5 100644
--- a/servers/rendering/renderer_rd/shaders/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/sky.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -24,7 +24,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define M_PI 3.14159265359
@@ -88,13 +88,9 @@ layout(set = 0, binding = 3, std140) uniform DirectionalLights {
directional_lights;
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-
-MATERIAL_UNIFORMS
-
- /* clang-format on */
+#MATERIAL_UNIFORMS
} material;
#endif
@@ -127,11 +123,7 @@ layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
#define AT_QUARTER_RES_PASS false
#endif
-/* clang-format off */
-
-FRAGMENT_SHADER_GLOBALS
-
-/* clang-format on */
+#GLOBALS
layout(location = 0) out vec4 frag_color;
@@ -202,22 +194,10 @@ void main() {
#endif
#endif
-// unused, just here to make our compiler happy, make sure we don't execute any light code the user adds in..
-#ifndef REALLYINCLUDETHIS
- {
- /* clang-format off */
-
-LIGHT_SHADER_CODE
-
- /* clang-format on */
- }
-#endif
{
- /* clang-format off */
-FRAGMENT_SHADER_CODE
+#CODE : SKY
- /* clang-format on */
}
frag_color.rgb = color * params.position_multiplier.w;
diff --git a/servers/rendering/renderer_rd/shaders/sort.glsl b/servers/rendering/renderer_rd/shaders/sort.glsl
index e5ebb9c64b..307e60dc21 100644
--- a/servers/rendering/renderer_rd/shaders/sort.glsl
+++ b/servers/rendering/renderer_rd/shaders/sort.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
// Original version here:
// https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11/blob/master/gpuparticles11/src/Shaders
diff --git a/servers/rendering/renderer_rd/shaders/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/specular_merge.glsl
index 0b8f406213..3579c35cce 100644
--- a/servers/rendering/renderer_rd/shaders/specular_merge.glsl
+++ b/servers/rendering/renderer_rd/shaders/specular_merge.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -17,7 +17,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl
index 231f8f91ec..6e945edfcd 100644
--- a/servers/rendering/renderer_rd/shaders/ssao.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5
diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
index 510a777048..d9cd2b4e85 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
index cb2d31f70d..ee0db6a6f0 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
index 6aa7624261..687fe1e6e2 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
index 4fdf334aa5..0907423d5d 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
@@ -20,7 +20,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
index 88a953562f..9367b641c2 100644
--- a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
+++ b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 7de91fd541..86b4da6b08 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -16,7 +16,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index e7ba8feb80..c793b6ebe1 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -2,13 +2,13 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
/* Do not use subgroups here, seems there is not much advantage and causes glitches
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot: enable
#extension GL_KHR_shader_subgroup_arithmetic: enable
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic)
#define USE_SUBGROUPS
#endif
*/
@@ -26,6 +26,7 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
#endif
#include "cluster_data_inc.glsl"
+#include "light_data_inc.glsl"
#define M_PI 3.14159265359
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index e8966414ab..db1e3d1377 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -36,7 +36,8 @@
class RendererScene {
public:
- virtual RID camera_create() = 0;
+ virtual RID camera_allocate() = 0;
+ virtual void camera_initialize(RID p_rid) = 0;
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0;
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0;
@@ -48,7 +49,12 @@ public:
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
virtual bool is_camera(RID p_camera) const = 0;
- virtual RID scenario_create() = 0;
+ virtual RID occluder_allocate() = 0;
+ virtual void occluder_initialize(RID p_occluder) = 0;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0;
+
+ virtual RID scenario_allocate() = 0;
+ virtual void scenario_initialize(RID p_rid) = 0;
virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) = 0;
virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
@@ -58,7 +64,8 @@ public:
virtual bool is_scenario(RID p_scenario) const = 0;
virtual RID scenario_get_environment(RID p_scenario) = 0;
- virtual RID instance_create() = 0;
+ virtual RID instance_allocate() = 0;
+ virtual void instance_initialize(RID p_rid) = 0;
virtual void instance_set_base(RID p_instance, RID p_base) = 0;
virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0;
@@ -66,7 +73,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0;
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0;
@@ -99,7 +106,9 @@ public:
/* SKY API */
- virtual RID sky_create() = 0;
+ virtual RID sky_allocate() = 0;
+ virtual void sky_initialize(RID p_rid) = 0;
+
virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0;
virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0;
virtual void sky_set_material(RID p_sky, RID p_material) = 0;
@@ -107,7 +116,8 @@ public:
/* ENVIRONMENT API */
- virtual RID environment_create() = 0;
+ virtual RID environment_allocate() = 0;
+ virtual void environment_initialize(RID p_rid) = 0;
virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0;
virtual void environment_set_sky(RID p_env, RID p_sky) = 0;
@@ -134,7 +144,7 @@ public:
virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0;
- virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
+ virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0;
virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0;
@@ -159,7 +169,8 @@ public:
/* Camera Effects */
- virtual RID camera_effects_create() = 0;
+ virtual RID camera_effects_allocate() = 0;
+ virtual void camera_effects_initialize(RID p_rid) = 0;
virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0;
virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0;
@@ -177,6 +188,7 @@ public:
/* Render Buffers */
virtual RID render_buffers_create() = 0;
+
virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
@@ -189,8 +201,8 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
+ virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
+ virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
virtual void update() = 0;
virtual void render_probes() = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 8067f9574c..aee4d8712a 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -39,9 +39,11 @@
/* CAMERA API */
-RID RendererSceneCull::camera_create() {
- Camera *camera = memnew(Camera);
- return camera_owner.make_rid(camera);
+RID RendererSceneCull::camera_allocate() {
+ return camera_owner.allocate_rid();
+}
+void RendererSceneCull::camera_initialize(RID p_rid) {
+ camera_owner.initialize_rid(p_rid, memnew(Camera));
}
void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -107,6 +109,20 @@ bool RendererSceneCull::is_camera(RID p_camera) const {
return camera_owner.owns(p_camera);
}
+/* OCCLUDER API */
+
+RID RendererSceneCull::occluder_allocate() {
+ return RendererSceneOcclusionCull::get_singleton()->occluder_allocate();
+}
+
+void RendererSceneCull::occluder_initialize(RID p_rid) {
+ RendererSceneOcclusionCull::get_singleton()->occluder_initialize(p_rid);
+}
+
+void RendererSceneCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+ RendererSceneOcclusionCull::get_singleton()->occluder_set_mesh(p_occluder, p_vertices, p_indices);
+}
+
/* SCENARIO API */
void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
@@ -290,11 +306,12 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
}
}
-RID RendererSceneCull::scenario_create() {
+RID RendererSceneCull::scenario_allocate() {
+ return scenario_owner.allocate_rid();
+}
+void RendererSceneCull::scenario_initialize(RID p_rid) {
Scenario *scenario = memnew(Scenario);
- ERR_FAIL_COND_V(!scenario, RID());
- RID scenario_rid = scenario_owner.make_rid(scenario);
- scenario->self = scenario_rid;
+ scenario->self = p_rid;
scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create();
scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
@@ -307,7 +324,9 @@ RID RendererSceneCull::scenario_create() {
scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
scenario->instance_data.set_page_pool(&instance_data_page_pool);
- return scenario_rid;
+ RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid);
+
+ scenario_owner.initialize_rid(p_rid, scenario);
}
void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) {
@@ -367,14 +386,14 @@ void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_upda
_instance_update_list.add(&p_instance->update_item);
}
-RID RendererSceneCull::instance_create() {
+RID RendererSceneCull::instance_allocate() {
+ return instance_owner.allocate_rid();
+}
+void RendererSceneCull::instance_initialize(RID p_rid) {
Instance *instance = memnew(Instance);
- ERR_FAIL_COND_V(!instance, RID());
-
- RID instance_rid = instance_owner.make_rid(instance);
- instance->self = instance_rid;
+ instance->self = p_rid;
- return instance_rid;
+ instance_owner.initialize_rid(p_rid, instance);
}
void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
@@ -494,6 +513,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
scene_render->free(gi_probe->probe_instance);
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (scenario && instance->visible) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance);
+ }
+ } break;
default: {
}
}
@@ -511,6 +535,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
if (p_base.is_valid()) {
instance->base_type = RSG::storage->get_base_type(p_base);
+
+ if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) {
+ instance->base_type = RS::INSTANCE_OCCLUDER;
+ }
+
ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
switch (instance->base_type) {
@@ -585,6 +614,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base);
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, p_base, instance->transform, instance->visible);
+ }
+ } break;
default: {
}
}
@@ -652,6 +686,11 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
gi_probe_update_list.remove(&gi_probe->update_element);
}
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (instance->visible) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance);
+ }
+ } break;
default: {
}
}
@@ -681,6 +720,9 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
gi_probe_update_list.add(&gi_probe->update_element);
}
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, instance->base, instance->transform, instance->visible);
+ } break;
default: {
}
}
@@ -749,7 +791,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
}
}
-void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) {
+void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
@@ -798,6 +840,12 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible);
}
+
+ if (instance->base_type == RS::INSTANCE_OCCLUDER) {
+ if (instance->scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible);
+ }
+ }
}
inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
@@ -995,6 +1043,18 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
}
} break;
+ case RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING: {
+ instance->ignore_occlusion_culling = p_enabled;
+
+ if (instance->scenario && instance->array_index >= 0) {
+ InstanceData &idata = instance->scenario->instance_data[instance->array_index];
+ if (instance->ignore_occlusion_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
+ } else {
+ idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_OCCLUSION_CULLING);
+ }
+ }
+ } break;
default: {
}
}
@@ -1207,6 +1267,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
heightfield_particle_colliders_update_list.insert(p_instance);
}
RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform);
+ } else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) {
+ if (p_instance->scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible);
+ }
}
if (p_instance->aabb.has_no_surface()) {
@@ -1334,6 +1398,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (p_instance->mesh_instance.is_valid()) {
idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE;
}
+ if (p_instance->ignore_occlusion_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
+ }
p_instance->scenario->instance_data.push_back(idata);
p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb));
@@ -1360,6 +1427,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.pair_mask |= 1 << RS::INSTANCE_LIGHT;
pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE;
pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP;
+ if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
+ pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION;
+ }
pair.pair_mask |= geometry_instance_pair_mask;
@@ -2116,7 +2186,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
+void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
// render to mono camera
#ifndef _3D_DISABLED
@@ -2161,11 +2231,14 @@ void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_
RID environment = _render_get_environment(p_camera, p_scenario);
- _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
+ RENDER_TIMESTAMP("Update occlusion buffer")
+ RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera->transform, camera_matrix, ortho, RendererThreadPool::singleton->thread_work_pool);
+
+ _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
#endif
}
-void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
+void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
// render for AR/VR interface
#if 0
Camera *camera = camera_owner.getornull(p_camera);
@@ -2250,7 +2323,7 @@ void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_
#endif
};
-void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) {
+void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, CullData *cull_data) {
uint32_t cull_total = cull_data->scenario->instance_data.size();
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
uint32_t cull_from = p_thread * cull_total / total_threads;
@@ -2259,7 +2332,7 @@ void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullDat
_frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to);
}
-void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
+void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
uint64_t frame_number = RSG::rasterizer->get_frame_number();
float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time();
@@ -2268,10 +2341,14 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
+ Transform inv_cam_transform = cull_data.cam_transform.inverse();
+ float z_near = cull_data.camera_matrix->get_z_near();
+
for (uint64_t i = p_from; i < p_to; i++) {
bool mesh_visible = false;
- if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) {
+ if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum) && (cull_data.occlusion_buffer == nullptr || cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING ||
+ !cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))) {
InstanceData &idata = cull_data.scenario->instance_data[i];
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
@@ -2336,7 +2413,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
cull_data.cull->lock.lock();
RSG::storage->particles_request_process(idata.base_rid);
cull_data.cull->lock.unlock();
- RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized());
+ RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
//particles visible? request redraw
RenderingServerDefault::redraw_request();
}
@@ -2376,18 +2453,19 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
}
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
- //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- //todo for GLES3
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
- /*for (Set<Instance *>::Element *E = geom->dec.front(); E; E = E->next()) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- instance_pair_buffer[idx++] = reflection_probe->instance;
- if (idx==MAX_INSTANCE_PAIRS) {
- break;
+ for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
+
+ instance_pair_buffer[idx++] = decal->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
- }*/
- //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx);
+ scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
}
if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) {
@@ -2466,7 +2544,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
}
}
-void RendererSceneCull::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) {
+void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) {
// Note, in stereo rendering:
// - p_cam_transform will be a transform in the middle of our two eyes
// - p_cam_projection is a wider frustrum that encompasses both eyes
@@ -2563,7 +2641,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
uint64_t cull_from = 0;
uint64_t cull_to = scenario->instance_data.size();
- FrustumCullData cull_data;
+ CullData cull_data;
//prepare for eventual thread usage
cull_data.cull = &cull;
@@ -2572,6 +2650,8 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
cull_data.cam_transform = p_cam_transform;
cull_data.visible_layers = p_visible_layers;
cull_data.render_reflection_probe = render_reflection_probe;
+ cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport);
+ cull_data.camera_matrix = &p_cam_projection;
//#define DEBUG_CULL_TIME
#ifdef DEBUG_CULL_TIME
uint64_t time_from = OS::get_singleton()->get_ticks_usec();
@@ -2778,8 +2858,13 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
}
/* PROCESS GEOMETRY AND DRAW SCENE */
+ RID occluders_tex;
+ if (p_viewport.is_valid()) {
+ occluders_tex = RSG::viewport->viewport_get_occluder_debug_texture(p_viewport);
+ }
+
RENDER_TIMESTAMP("Render Scene ");
- scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
+ scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
for (uint32_t i = 0; i < max_shadows_used; i++) {
render_shadow_data[i].instances.clear();
@@ -2826,7 +2911,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,
environment = scenario->fallback_environment;
}
RENDER_TIMESTAMP("Render Empty Scene ");
- scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
+ scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
}
@@ -2888,8 +2973,15 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
shadow_atlas = scenario->reflection_probe_shadow_atlas;
}
+ RID environment;
+ if (scenario->environment.is_valid()) {
+ environment = scenario->environment;
+ } else {
+ environment = scenario->fallback_environment;
+ }
+
RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _render_scene(xform, cm, false, false, RID(), RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
+ _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
} else {
//do roughness postprocess step until it believes it's done
@@ -3463,8 +3555,11 @@ bool RendererSceneCull::free(RID p_rid) {
scene_render->free(scenario->reflection_probe_shadow_atlas);
scene_render->free(scenario->reflection_atlas);
scenario_owner.free(p_rid);
+ RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
memdelete(scenario);
+ } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
+ RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid);
} else if (instance_owner.owns(p_rid)) {
// delete the instance
@@ -3530,9 +3625,11 @@ RendererSceneCull::RendererSceneCull() {
frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
}
- indexer_update_iterations = GLOBAL_GET("rendering/spatial_indexer/update_iterations_per_frame");
- thread_cull_threshold = GLOBAL_GET("rendering/spatial_indexer/threaded_cull_minimum_instances");
+ indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame");
+ thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances");
thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU
+
+ dummy_occlusion_culling = memnew(RendererSceneOcclusionCull);
}
RendererSceneCull::~RendererSceneCull() {
@@ -3551,4 +3648,8 @@ RendererSceneCull::~RendererSceneCull() {
frustum_cull_result_threads[i].reset();
}
frustum_cull_result_threads.clear();
+
+ if (dummy_occlusion_culling) {
+ memdelete(dummy_occlusion_culling);
+ }
}
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index d6d730af15..a61b04afc8 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -45,8 +45,10 @@
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/renderer_scene_occlusion_cull.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/xr/xr_interface.h"
+
class RendererSceneCull : public RendererScene {
public:
RendererSceneRender *scene_render;
@@ -94,9 +96,11 @@ public:
}
};
- mutable RID_PtrOwner<Camera> camera_owner;
+ mutable RID_PtrOwner<Camera, true> camera_owner;
+
+ virtual RID camera_allocate();
+ virtual void camera_initialize(RID p_rid);
- virtual RID camera_create();
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far);
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
@@ -107,6 +111,14 @@ public:
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
virtual bool is_camera(RID p_camera) const;
+ /* OCCLUDER API */
+
+ virtual RID occluder_allocate();
+ virtual void occluder_initialize(RID p_occluder);
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
+
+ RendererSceneOcclusionCull *dummy_occlusion_culling;
+
/* SCENARIO API */
struct Instance;
@@ -246,6 +258,7 @@ public:
FLAG_USES_BAKED_LIGHT = (1 << 16),
FLAG_USES_MESH_INSTANCE = (1 << 17),
FLAG_REFLECTION_PROBE_DIRTY = (1 << 18),
+ FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19),
};
uint32_t flags = 0;
@@ -296,14 +309,15 @@ public:
int indexer_update_iterations = 0;
- mutable RID_PtrOwner<Scenario> scenario_owner;
+ mutable RID_PtrOwner<Scenario, true> scenario_owner;
static void _instance_pair(Instance *p_A, Instance *p_B);
static void _instance_unpair(Instance *p_A, Instance *p_B);
void _instance_update_mesh_instance(Instance *p_instance);
- virtual RID scenario_create();
+ virtual RID scenario_allocate();
+ virtual void scenario_initialize(RID p_rid);
virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode);
virtual void scenario_set_environment(RID p_scenario, RID p_environment);
@@ -343,6 +357,8 @@ public:
float lod_bias;
+ bool ignore_occlusion_culling;
+
Vector<RID> materials;
RS::ShadowCastingSetting cast_shadows;
@@ -427,6 +443,7 @@ public:
singleton->_instance_queue_update(instance, false, true);
} break;
case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_DECAL:
case RendererStorage::DEPENDENCY_CHANGED_LIGHT:
@@ -467,6 +484,7 @@ public:
lightmap = nullptr;
lightmap_cull_index = 0;
lod_bias = 1.0;
+ ignore_occlusion_culling = false;
scenario = nullptr;
@@ -644,6 +662,7 @@ public:
_FORCE_INLINE_ bool operator()(void *p_data) {
Instance *p_instance = (Instance *)p_data;
+
if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) {
//test is more coarse in indexer
p_instance->pair_check = pair_pass;
@@ -824,11 +843,12 @@ public:
uint32_t thread_cull_threshold = 200;
- RID_PtrOwner<Instance> instance_owner;
+ RID_PtrOwner<Instance, true> instance_owner;
uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered
- virtual RID instance_create();
+ virtual RID instance_allocate();
+ virtual void instance_initialize(RID p_rid);
virtual void instance_set_base(RID p_instance, RID p_base);
virtual void instance_set_scenario(RID p_instance, RID p_scenario);
@@ -836,7 +856,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform);
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material);
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material);
virtual void instance_set_visible(RID p_instance, bool p_visible);
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
@@ -917,24 +937,26 @@ public:
Frustum frustum;
} cull;
- struct FrustumCullData {
+ struct CullData {
Cull *cull;
Scenario *scenario;
RID shadow_atlas;
Transform cam_transform;
uint32_t visible_layers;
Instance *render_reflection_probe;
+ const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer;
+ const CameraMatrix *camera_matrix;
};
- void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data);
- void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to);
+ void _frustum_cull_threaded(uint32_t p_thread, CullData *cull_data);
+ void _frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
+ void _render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
+ void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
+ void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
void update_dirty_instances();
void render_particle_colliders();
@@ -957,13 +979,16 @@ public:
/* SKY API */
- PASS0R(RID, sky_create)
+ PASS0R(RID, sky_allocate)
+ PASS1(sky_initialize, RID)
+
PASS2(sky_set_radiance_size, RID, int)
PASS2(sky_set_mode, RID, RS::SkyMode)
PASS2(sky_set_material, RID, RID)
PASS4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &)
- PASS0R(RID, environment_create)
+ PASS0R(RID, environment_allocate)
+ PASS1(environment_initialize, RID)
PASS1RC(bool, is_environment, RID)
@@ -996,7 +1021,7 @@ public:
PASS2(environment_set_volumetric_fog_volume_size, int, int)
PASS1(environment_set_volumetric_fog_filter_active, bool)
- PASS11(environment_set_sdfgi, RID, bool, RS::EnvironmentSDFGICascades, float, RS::EnvironmentSDFGIYScale, bool, bool, bool, float, float, float)
+ PASS11(environment_set_sdfgi, RID, bool, RS::EnvironmentSDFGICascades, float, RS::EnvironmentSDFGIYScale, bool, float, bool, float, float, float)
PASS1(environment_set_sdfgi_ray_count, RS::EnvironmentSDFGIRayCount)
PASS1(environment_set_sdfgi_frames_to_converge, RS::EnvironmentSDFGIFramesToConverge)
PASS1(environment_set_sdfgi_frames_to_update_light, RS::EnvironmentSDFGIFramesToUpdateLight)
@@ -1012,7 +1037,8 @@ public:
/* CAMERA EFFECTS */
- PASS0R(RID, camera_effects_create)
+ PASS0R(RID, camera_effects_allocate)
+ PASS1(camera_effects_initialize, RID)
PASS2(camera_effects_set_dof_blur_quality, RS::DOFBlurQuality, bool)
PASS1(camera_effects_set_dof_blur_bokeh_shape, RS::DOFBokehShape)
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
new file mode 100644
index 0000000000..c491ccbe7a
--- /dev/null
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -0,0 +1,192 @@
+/*************************************************************************/
+/* renderer_scene_occlusion_cull.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "renderer_scene_occlusion_cull.h"
+
+RendererSceneOcclusionCull *RendererSceneOcclusionCull::singleton = nullptr;
+
+const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = {
+ Vector3(0, 0, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ Vector3(0, 1, 1),
+ Vector3(1, 0, 0),
+ Vector3(1, 0, 1),
+ Vector3(1, 1, 0),
+ Vector3(1, 1, 1)
+};
+
+bool RendererSceneOcclusionCull::HZBuffer::is_empty() const {
+ return sizes.is_empty();
+}
+
+void RendererSceneOcclusionCull::HZBuffer::clear() {
+ if (sizes.is_empty()) {
+ return; // Already cleared
+ }
+
+ data.clear();
+ sizes.clear();
+ mips.clear();
+
+ debug_data.clear();
+ if (debug_image.is_valid()) {
+ debug_image.unref();
+ }
+ RS::get_singleton()->free(debug_texture);
+}
+
+void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) {
+ if (p_size == Size2i()) {
+ clear();
+ return;
+ }
+
+ if (!sizes.is_empty() && p_size == sizes[0]) {
+ return; // Size didn't change
+ }
+
+ int mip_count = 0;
+ int data_size = 0;
+ int w = p_size.x;
+ int h = p_size.y;
+
+ while (true) {
+ data_size += h * w;
+
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+
+ mip_count++;
+
+ if (w == 1U && h == 1U) {
+ data_size += 1U;
+ mip_count++;
+ break;
+ }
+ }
+
+ data.resize(data_size);
+ mips.resize(mip_count);
+ sizes.resize(mip_count);
+
+ w = p_size.x;
+ h = p_size.y;
+ float *ptr = data.ptr();
+
+ for (int i = 0; i < mip_count; i++) {
+ sizes[i] = Size2i(w, h);
+ mips[i] = ptr;
+
+ ptr = &ptr[w * h];
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+ }
+
+ for (int i = 0; i < data_size; i++) {
+ data[i] = FLT_MAX;
+ }
+
+ debug_data.resize(sizes[0].x * sizes[0].y);
+ if (debug_texture.is_valid()) {
+ RS::get_singleton()->free(debug_texture);
+ debug_texture = RID();
+ }
+}
+
+void RendererSceneOcclusionCull::HZBuffer::update_mips() {
+ if (sizes.is_empty()) {
+ return;
+ }
+
+ for (uint32_t mip = 1; mip < mips.size(); mip++) {
+ for (int y = 0; y < sizes[mip].y; y++) {
+ for (int x = 0; x < sizes[mip].x; x++) {
+ int prev_x = x * 2;
+ int prev_y = y * 2;
+
+ int prev_w = sizes[mip - 1].width;
+ int prev_h = sizes[mip - 1].height;
+
+ bool odd_w = (prev_w % 2) != 0;
+ bool odd_h = (prev_h % 2) != 0;
+
+#define CHECK_OFFSET(xx, yy) max_depth = MAX(max_depth, mips[mip - 1][MIN(prev_h - 1, prev_y + (yy)) * prev_w + MIN(prev_w - 1, prev_x + (xx))])
+
+ float max_depth = mips[mip - 1][prev_y * sizes[mip - 1].x + prev_x];
+ CHECK_OFFSET(0, 1);
+ CHECK_OFFSET(1, 0);
+ CHECK_OFFSET(1, 1);
+
+ if (odd_w) {
+ CHECK_OFFSET(2, 0);
+ CHECK_OFFSET(2, 1);
+ }
+
+ if (odd_h) {
+ CHECK_OFFSET(0, 2);
+ CHECK_OFFSET(1, 2);
+ }
+
+ if (odd_w && odd_h) {
+ CHECK_OFFSET(2, 2);
+ }
+
+ mips[mip][y * sizes[mip].x + x] = max_depth;
+#undef CHECK_OFFSET
+ }
+ }
+ }
+}
+
+RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() {
+ if (sizes.is_empty() || sizes[0] == Size2i()) {
+ return RID();
+ }
+
+ if (debug_image.is_null()) {
+ debug_image.instance();
+ }
+
+ unsigned char *ptrw = debug_data.ptrw();
+ for (int i = 0; i < debug_data.size(); i++) {
+ ptrw[i] = MIN(mips[0][i] / debug_tex_range, 1.0) * 255;
+ }
+
+ debug_image->create(sizes[0].x, sizes[0].y, false, Image::FORMAT_L8, debug_data);
+
+ if (debug_texture.is_null()) {
+ debug_texture = RS::get_singleton()->texture_2d_create(debug_image);
+ } else {
+ RenderingServer::get_singleton()->texture_2d_update_immediate(debug_texture, debug_image);
+ }
+
+ return debug_texture;
+}
diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h
new file mode 100644
index 0000000000..390bbaa64b
--- /dev/null
+++ b/servers/rendering/renderer_scene_occlusion_cull.h
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* renderer_scene_occlusion_cull.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERER_SCENE_OCCLUSION_CULL_H
+#define RENDERER_SCENE_OCCLUSION_CULL_H
+
+#include "core/math/camera_matrix.h"
+#include "core/templates/local_vector.h"
+#include "servers/rendering_server.h"
+
+class RendererSceneOcclusionCull {
+protected:
+ static RendererSceneOcclusionCull *singleton;
+
+public:
+ class HZBuffer {
+ protected:
+ static const Vector3 corners[8];
+
+ LocalVector<float> data;
+ LocalVector<Size2i> sizes;
+ LocalVector<float *> mips;
+
+ RID debug_texture;
+ Ref<Image> debug_image;
+ PackedByteArray debug_data;
+ float debug_tex_range = 0.0f;
+
+ public:
+ bool is_empty() const;
+ virtual void clear();
+ virtual void resize(const Size2i &p_size);
+
+ void update_mips();
+
+ _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const {
+ if (is_empty()) {
+ return false;
+ }
+
+ Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5]));
+
+ if (closest_point == p_cam_position) {
+ return false;
+ }
+
+ Vector3 closest_point_view = p_cam_inv_transform.xform(closest_point);
+ if (closest_point_view.z > -p_near) {
+ return false;
+ }
+
+ float min_depth;
+ if (p_cam_projection.is_orthogonal()) {
+ min_depth = (-closest_point_view.z) - p_near;
+ } else {
+ float r = -p_near / closest_point_view.z;
+ Vector3 closest_point_proj = Vector3(closest_point_view.x * r, closest_point_view.y * r, -p_near);
+ min_depth = closest_point_proj.distance_to(closest_point_view);
+ }
+
+ Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX);
+ Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
+
+ for (int j = 0; j < 8; j++) {
+ Vector3 c = RendererSceneOcclusionCull::HZBuffer::corners[j];
+ Vector3 nc = Vector3(1, 1, 1) - c;
+ Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z);
+ Vector3 view = p_cam_inv_transform.xform(corner);
+
+ Vector3 projected = p_cam_projection.xform(view);
+ Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f);
+ rect_min = rect_min.min(normalized);
+ rect_max = rect_max.max(normalized);
+ }
+
+ rect_max = rect_max.min(Vector2(1, 1));
+ rect_min = rect_min.max(Vector2(0, 0));
+
+ int mip_count = mips.size();
+
+ Vector2 screen_diagonal = (rect_max - rect_min) * sizes[0];
+ float size = MAX(screen_diagonal.x, screen_diagonal.y);
+ float l = Math::ceil(Math::log2(size));
+ int lod = CLAMP(l, 0, mip_count - 1);
+
+ const int max_samples = 512;
+ int sample_count = 0;
+ bool visible = true;
+
+ for (; lod >= 0; lod--) {
+ int w = sizes[lod].x;
+ int h = sizes[lod].y;
+
+ int minx = CLAMP(rect_min.x * w - 1, 0, w - 1);
+ int maxx = CLAMP(rect_max.x * w + 1, 0, w - 1);
+
+ int miny = CLAMP(rect_min.y * h - 1, 0, h - 1);
+ int maxy = CLAMP(rect_max.y * h + 1, 0, h - 1);
+
+ sample_count += (maxx - minx + 1) * (maxy - miny + 1);
+
+ if (sample_count > max_samples) {
+ return false;
+ }
+
+ visible = false;
+ for (int y = miny; y <= maxy; y++) {
+ for (int x = minx; x <= maxx; x++) {
+ float depth = mips[lod][y * w + x];
+ if (depth > min_depth) {
+ visible = true;
+ break;
+ }
+ }
+ if (visible) {
+ break;
+ }
+ }
+
+ if (!visible) {
+ return true;
+ }
+ }
+
+ return !visible;
+ }
+
+ RID get_debug_texture();
+
+ virtual ~HZBuffer(){};
+ };
+
+ static RendererSceneOcclusionCull *get_singleton() { return singleton; }
+
+ void _print_warining() {
+ WARN_PRINT_ONCE("Occlusion culling is disabled at build time.");
+ }
+
+ virtual bool is_occluder(RID p_rid) { return false; }
+ virtual RID occluder_allocate() { return RID(); }
+ virtual void occluder_initialize(RID p_occluder) {}
+ virtual void free_occluder(RID p_occluder) { _print_warining(); }
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { _print_warining(); }
+
+ virtual void add_scenario(RID p_scenario) {}
+ virtual void remove_scenario(RID p_scenario) {}
+ virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) { _print_warining(); }
+ virtual void scenario_remove_instance(RID p_scenario, RID p_instance) { _print_warining(); }
+
+ virtual void add_buffer(RID p_buffer) { _print_warining(); }
+ virtual void remove_buffer(RID p_buffer) { _print_warining(); }
+ virtual HZBuffer *buffer_get_ptr(RID p_buffer) {
+ return nullptr;
+ }
+ virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) { _print_warining(); }
+ virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) { _print_warining(); }
+ virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {}
+ virtual RID buffer_get_debug_texture(RID p_buffer) {
+ _print_warining();
+ return RID();
+ }
+
+ virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {}
+
+ RendererSceneOcclusionCull() {
+ singleton = this;
+ };
+
+ virtual ~RendererSceneOcclusionCull() {
+ singleton = nullptr;
+ };
+};
+
+#endif //RENDERER_SCENE_OCCLUSION_CULL_H
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 72fcdd3758..3f28fac549 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -71,8 +71,7 @@ public:
/* SHADOW ATLAS API */
- virtual RID
- shadow_atlas_create() = 0;
+ virtual RID shadow_atlas_create() = 0;
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) = 0;
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0;
@@ -90,7 +89,9 @@ public:
/* SKY API */
- virtual RID sky_create() = 0;
+ virtual RID sky_allocate() = 0;
+ virtual void sky_initialize(RID p_rid) = 0;
+
virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0;
virtual void sky_set_mode(RID p_sky, RS::SkyMode p_samples) = 0;
virtual void sky_set_material(RID p_sky, RID p_material) = 0;
@@ -98,7 +99,8 @@ public:
/* ENVIRONMENT API */
- virtual RID environment_create() = 0;
+ virtual RID environment_allocate() = 0;
+ virtual void environment_initialize(RID p_rid) = 0;
virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) = 0;
virtual void environment_set_sky(RID p_env, RID p_sky) = 0;
@@ -128,7 +130,7 @@ public:
virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0;
- virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
+ virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) = 0;
virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) = 0;
@@ -146,7 +148,8 @@ public:
virtual RS::EnvironmentBG environment_get_background(RID p_env) const = 0;
virtual int environment_get_canvas_max_layer(RID p_env) const = 0;
- virtual RID camera_effects_create() = 0;
+ virtual RID camera_effects_allocate() = 0;
+ virtual void camera_effects_initialize(RID p_rid) = 0;
virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) = 0;
virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) = 0;
@@ -213,7 +216,7 @@ public:
uint32_t positional_light_count;
};
- virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0;
+ virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0;
virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0;
@@ -238,8 +241,6 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
- virtual bool is_low_end() const = 0;
-
virtual void update() = 0;
virtual ~RendererSceneRender() {}
};
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index f015b50eee..15d99c038e 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -43,6 +43,7 @@ public:
DEPENDENCY_CHANGED_MESH,
DEPENDENCY_CHANGED_MULTIMESH,
DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES,
+ DEPENDENCY_CHANGED_PARTICLES,
DEPENDENCY_CHANGED_DECAL,
DEPENDENCY_CHANGED_SKELETON_DATA,
DEPENDENCY_CHANGED_SKELETON_BONES,
@@ -119,12 +120,15 @@ public:
Set<Dependency *> dependencies;
};
+ virtual bool can_create_resources_async() const = 0;
/* TEXTURE API */
- virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
- virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0;
- virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0;
- virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_allocate() = 0;
+
+ virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) = 0;
+ virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) = 0;
+ virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0;
+ virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0;
@@ -132,9 +136,9 @@ public:
virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0;
//these two APIs can be used together or in combination with the others.
- virtual RID texture_2d_placeholder_create() = 0;
- virtual RID texture_2d_layered_placeholder_create(RenderingServer::TextureLayeredType p_layered_type) = 0;
- virtual RID texture_3d_placeholder_create() = 0;
+ virtual void texture_2d_placeholder_initialize(RID p_texture) = 0;
+ virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) = 0;
+ virtual void texture_3d_placeholder_initialize(RID p_texture) = 0;
virtual Ref<Image> texture_2d_get(RID p_texture) const = 0;
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const = 0;
@@ -161,7 +165,9 @@ public:
/* CANVAS TEXTURE API */
- virtual RID canvas_texture_create() = 0;
+ virtual RID canvas_texture_allocate() = 0;
+ virtual void canvas_texture_initialize(RID p_rid) = 0;
+
virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) = 0;
virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) = 0;
@@ -170,7 +176,8 @@ public:
/* SHADER API */
- virtual RID shader_create() = 0;
+ virtual RID shader_allocate() = 0;
+ virtual void shader_initialize(RID p_rid) = 0;
virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
virtual String shader_get_code(RID p_shader) const = 0;
@@ -184,7 +191,8 @@ public:
/* COMMON MATERIAL API */
- virtual RID material_create() = 0;
+ virtual RID material_allocate() = 0;
+ virtual void material_initialize(RID p_rid) = 0;
virtual void material_set_render_priority(RID p_material, int priority) = 0;
virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
@@ -209,7 +217,8 @@ public:
/* MESH API */
- virtual RID mesh_create() = 0;
+ virtual RID mesh_allocate() = 0;
+ virtual void mesh_initialize(RID p_rid) = 0;
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) = 0;
@@ -251,9 +260,10 @@ public:
/* MULTIMESH API */
- virtual RID multimesh_create() = 0;
+ virtual RID multimesh_allocate() = 0;
+ virtual void multimesh_initialize(RID p_rid) = 0;
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
+ virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
@@ -280,7 +290,9 @@ public:
/* IMMEDIATE API */
- virtual RID immediate_create() = 0;
+ virtual RID immediate_allocate() = 0;
+ virtual void immediate_initialize(RID p_rid) = 0;
+
virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0;
virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0;
virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0;
@@ -296,8 +308,10 @@ public:
/* SKELETON API */
- virtual RID skeleton_create() = 0;
- virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
+ virtual RID skeleton_allocate() = 0;
+ virtual void skeleton_initialize(RID p_rid) = 0;
+
+ virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0;
virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
@@ -307,11 +321,14 @@ public:
/* Light API */
- virtual RID light_create(RS::LightType p_type) = 0;
+ virtual RID directional_light_allocate() = 0;
+ virtual void directional_light_initialize(RID p_rid) = 0;
+
+ virtual RID omni_light_allocate() = 0;
+ virtual void omni_light_initialize(RID p_rid) = 0;
- RID directional_light_create() { return light_create(RS::LIGHT_DIRECTIONAL); }
- RID omni_light_create() { return light_create(RS::LIGHT_OMNI); }
- RID spot_light_create() { return light_create(RS::LIGHT_SPOT); }
+ virtual RID spot_light_allocate() = 0;
+ virtual void spot_light_initialize(RID p_rid) = 0;
virtual void light_set_color(RID p_light, const Color &p_color) = 0;
virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) = 0;
@@ -349,7 +366,8 @@ public:
/* PROBE API */
- virtual RID reflection_probe_create() = 0;
+ virtual RID reflection_probe_allocate() = 0;
+ virtual void reflection_probe_initialize(RID p_rid) = 0;
virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) = 0;
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
@@ -380,7 +398,9 @@ public:
/* DECAL API */
- virtual RID decal_create() = 0;
+ virtual RID decal_allocate() = 0;
+ virtual void decal_initialize(RID p_rid) = 0;
+
virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0;
virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) = 0;
virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0;
@@ -395,9 +415,10 @@ public:
/* GI PROBE API */
- virtual RID gi_probe_create() = 0;
+ virtual RID gi_probe_allocate() = 0;
+ virtual void gi_probe_initialize(RID p_rid) = 0;
- virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
+ virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
@@ -440,9 +461,10 @@ public:
virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
- /* LIGHTMAP CAPTURE */
+ /* LIGHTMAP */
- virtual RID lightmap_create() = 0;
+ virtual RID lightmap_allocate() = 0;
+ virtual void lightmap_initialize(RID p_rid) = 0;
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) = 0;
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) = 0;
@@ -460,7 +482,8 @@ public:
/* PARTICLES */
- virtual RID particles_create() = 0;
+ virtual RID particles_allocate() = 0;
+ virtual void particles_initialize(RID p_rid) = 0;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
virtual bool particles_get_emitting(RID p_particles) = 0;
@@ -476,8 +499,15 @@ public:
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+ virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0;
+
+ virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0;
+
+ virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length) = 0;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0;
+
virtual void particles_restart(RID p_particles) = 0;
virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
@@ -498,7 +528,7 @@ public:
virtual int particles_get_draw_passes(RID p_particles) const = 0;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;
- virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0;
+ virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) = 0;
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0;
@@ -507,7 +537,9 @@ public:
/* PARTICLES COLLISION */
- virtual RID particles_collision_create() = 0;
+ virtual RID particles_collision_allocate() = 0;
+ virtual void particles_collision_initialize(RID p_rid) = 0;
+
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) = 0;
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) = 0;
virtual void particles_collision_set_sphere_radius(RID p_particles_collision, float p_radius) = 0; //for spheres
@@ -584,7 +616,7 @@ public:
virtual void render_info_end_capture() = 0;
virtual int get_captured_render_info(RS::RenderInfo p_info) = 0;
- virtual int get_render_info(RS::RenderInfo p_info) = 0;
+ virtual uint64_t get_render_info(RS::RenderInfo p_info) = 0;
virtual String get_video_adapter_name() const = 0;
virtual String get_video_adapter_vendor() const = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index d52da5b331..f7be6c6c60 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -79,11 +79,26 @@ void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
xr_interface = XRServer::get_singleton()->get_primary_interface();
}
+ if (p_viewport->use_occlusion_culling) {
+ if (p_viewport->occlusion_buffer_dirty) {
+ float aspect = p_viewport->size.aspect();
+ int max_size = occlusion_rays_per_thread * RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+
+ int viewport_size = p_viewport->size.width * p_viewport->size.height;
+ max_size = CLAMP(max_size, viewport_size / (32 * 32), viewport_size / (2 * 2)); // At least one depth pixel for every 16x16 region. At most one depth pixel for every 2x2 region.
+
+ float height = Math::sqrt(max_size / aspect);
+ Size2i new_size = Size2i(height * aspect, height);
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_size(p_viewport->self, new_size);
+ p_viewport->occlusion_buffer_dirty = false;
+ }
+ }
+
float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width);
if (p_viewport->use_xr && xr_interface.is_valid()) {
- RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
+ RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
} else {
- RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
}
RENDER_TIMESTAMP("<End Rendering 3D Scene");
}
@@ -457,7 +472,7 @@ void RendererViewport::draw_viewports() {
}
if (Engine::get_singleton()->is_editor_hint()) {
- set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color"));
+ set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
//sort viewports
@@ -608,19 +623,20 @@ void RendererViewport::draw_viewports() {
}
}
-RID RendererViewport::viewport_create() {
- Viewport *viewport = memnew(Viewport);
-
- RID rid = viewport_owner.make_rid(viewport);
+RID RendererViewport::viewport_allocate() {
+ return viewport_owner.allocate_rid();
+}
- viewport->self = rid;
+void RendererViewport::viewport_initialize(RID p_rid) {
+ Viewport *viewport = memnew(Viewport);
+ viewport->self = p_rid;
viewport->hide_scenario = false;
viewport->hide_canvas = false;
viewport->render_target = RSG::storage->render_target_create();
viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
viewport->viewport_render_direct_to_screen = false;
- return rid;
+ viewport_owner.initialize_rid(p_rid, viewport);
}
void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
@@ -646,6 +662,8 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig
RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding);
}
}
+
+ viewport->occlusion_buffer_dirty = true;
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -654,6 +672,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
if (p_active) {
ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active
+ viewport->occlusion_buffer_dirty = true;
active_viewports.push_back(viewport);
} else {
active_viewports.erase(viewport);
@@ -738,6 +757,16 @@ RID RendererViewport::viewport_get_texture(RID p_viewport) const {
return RSG::storage->render_target_get_texture(viewport->render_target);
}
+RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const {
+ const Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, RID());
+
+ if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
+ return RendererSceneOcclusionCull::get_singleton()->buffer_get_debug_texture(p_viewport);
+ }
+ return RID();
+}
+
void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
@@ -771,6 +800,9 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
ERR_FAIL_COND(!viewport);
viewport->scenario = p_scenario;
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario);
+ }
}
void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
@@ -887,6 +919,41 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
}
}
+void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->use_occlusion_culling == p_use_occlusion_culling) {
+ return;
+ }
+ viewport->use_occlusion_culling = p_use_occlusion_culling;
+
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->add_buffer(p_viewport);
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, viewport->scenario);
+ } else {
+ RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_viewport);
+ }
+
+ viewport->occlusion_buffer_dirty = true;
+}
+
+void RendererViewport::viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) {
+ if (occlusion_rays_per_thread == p_rays_per_thread) {
+ return;
+ }
+
+ occlusion_rays_per_thread = p_rays_per_thread;
+
+ for (int i = 0; i < active_viewports.size(); i++) {
+ active_viewports[i]->occlusion_buffer_dirty = true;
+ }
+}
+
+void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {
+ RendererSceneOcclusionCull::get_singleton()->set_build_quality(p_quality);
+}
+
void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
@@ -984,6 +1051,10 @@ bool RendererViewport::free(RID p_rid) {
viewport_set_scenario(p_rid, RID());
active_viewports.erase(viewport);
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);
+ }
+
viewport_owner.free(p_rid);
memdelete(viewport);
@@ -1019,5 +1090,11 @@ void RendererViewport::set_default_clear_color(const Color &p_color) {
RSG::storage->set_default_clear_color(p_color);
}
+//workaround for setting this on thread
+void RendererViewport::call_set_use_vsync(bool p_enable) {
+ DisplayServer::get_singleton()->_set_use_vsync(p_enable);
+}
+
RendererViewport::RendererViewport() {
+ occlusion_rays_per_thread = GLOBAL_GET("rendering/occlusion_culling/occlusion_rays_per_thread");
}
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 979cbb095b..5c372e8c9a 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -31,9 +31,9 @@
#ifndef VISUALSERVERVIEWPORT_H
#define VISUALSERVERVIEWPORT_H
+#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
-#include "renderer_compositor.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
@@ -61,6 +61,9 @@ public:
RS::ViewportScreenSpaceAA screen_space_aa;
bool use_debanding;
+ bool use_occlusion_culling;
+ bool occlusion_buffer_dirty;
+
DisplayServer::WindowID viewport_to_screen;
Rect2 viewport_to_screen_rect;
bool viewport_render_direct_to_screen;
@@ -143,6 +146,8 @@ public:
msaa = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
use_debanding = false;
+ use_occlusion_culling = false;
+ occlusion_buffer_dirty = true;
snap_2d_transforms_to_pixel = false;
snap_2d_vertices_to_pixel = false;
@@ -165,7 +170,7 @@ public:
uint64_t draw_viewports_pass = 0;
- mutable RID_PtrOwner<Viewport> viewport_owner;
+ mutable RID_PtrOwner<Viewport, true> viewport_owner;
struct ViewportSort {
_FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
@@ -185,8 +190,13 @@ private:
void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye);
void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO);
+ int occlusion_rays_per_thread = 512;
+
+ void _resize_occlusion_culling_buffer(const Size2i &p_size);
+
public:
- RID viewport_create();
+ RID viewport_allocate();
+ void viewport_initialize(RID p_rid);
void viewport_set_use_xr(RID p_viewport, bool p_use_xr);
@@ -203,6 +213,7 @@ public:
void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode);
RID viewport_get_texture(RID p_viewport) const;
+ RID viewport_get_occluder_debug_texture(RID p_viewport) const;
void viewport_set_hide_scenario(RID p_viewport, bool p_hide);
void viewport_set_hide_canvas(RID p_viewport, bool p_hide);
@@ -224,7 +235,9 @@ public:
void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa);
void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding);
-
+ void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling);
+ void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread);
+ void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality);
void viewport_set_lod_threshold(RID p_viewport, float p_pixels);
virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
@@ -249,6 +262,9 @@ public:
bool free(RID p_rid);
+ //workaround for setting this on thread
+ void call_set_use_vsync(bool p_enable);
+
RendererViewport();
virtual ~RendererViewport() {}
};
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 4b0eafe369..e6ad001807 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -59,7 +59,7 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage,
ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>());
- return compile_function(p_stage, p_source_code, p_language, r_error);
+ return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
}
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
@@ -269,7 +269,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);
- ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("index_buffer_create", "size_indices", "format", "data", "use_restart_indices"), &RenderingDevice::index_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("index_array_create", "index_buffer", "index_offset", "index_count"), &RenderingDevice::index_array_create);
ClassDB::bind_method(D_METHOD("shader_compile_from_source", "shader_source", "allow_cache"), &RenderingDevice::_shader_compile_from_source, DEFVAL(true));
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 9fbf58d131..2de0549e8d 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -51,6 +51,13 @@ class RDPipelineColorBlendState;
class RenderingDevice : public Object {
GDCLASS(RenderingDevice, Object)
public:
+ enum DeviceFamily {
+ DEVICE_UNKNOWN,
+ DEVICE_OPENGL,
+ DEVICE_VULKAN,
+ DEVICE_DIRECTX
+ };
+
enum ShaderStage {
SHADER_STAGE_VERTEX,
SHADER_STAGE_FRAGMENT,
@@ -70,7 +77,29 @@ public:
SHADER_LANGUAGE_HLSL
};
- typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error);
+ enum SubgroupOperations {
+ SUBGROUP_BASIC_BIT = 1,
+ SUBGROUP_VOTE_BIT = 2,
+ SUBGROUP_ARITHMETIC_BIT = 4,
+ SUBGROUP_BALLOT_BIT = 8,
+ SUBGROUP_SHUFFLE_BIT = 16,
+ SUBGROUP_SHUFFLE_RELATIVE_BIT = 32,
+ SUBGROUP_CLUSTERED_BIT = 64,
+ SUBGROUP_QUAD_BIT = 128,
+ };
+
+ struct Capabilities {
+ // main device info
+ DeviceFamily device_family = DEVICE_UNKNOWN;
+ uint32_t version_major = 1.0;
+ uint32_t version_minor = 0.0;
+ // subgroup capabilities
+ uint32_t subgroup_size = 0;
+ uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
+ uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations
+ };
+
+ typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
private:
@@ -82,6 +111,8 @@ private:
protected:
static void _bind_methods();
+ Capabilities device_capabilities;
+
public:
//base numeric ID for all types
enum {
@@ -597,6 +628,8 @@ public:
/**** SHADER ****/
/****************/
+ const Capabilities *get_device_capabilities() const { return &device_capabilities; };
+
virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
static void shader_set_compile_function(ShaderCompileFunction p_function);
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 360b333454..c6fe6a07e0 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -64,7 +64,7 @@ void RenderingServerDefault::_draw_margins() {
/* FREE */
-void RenderingServerDefault::free(RID p_rid) {
+void RenderingServerDefault::_free(RID p_rid) {
if (RSG::storage->free(p_rid)) {
return;
}
@@ -91,7 +91,7 @@ void RenderingServerDefault::request_frame_drawn_callback(Object *p_where, const
frame_drawn_callbacks.push_back(fdc);
}
-void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
+void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
//needs to be done before changes is reset to 0, to not force the editor to redraw
RS::get_singleton()->emit_signal("frame_pre_draw");
@@ -213,18 +213,15 @@ float RenderingServerDefault::get_frame_setup_time_cpu() const {
return frame_setup_time;
}
-void RenderingServerDefault::sync() {
-}
-
bool RenderingServerDefault::has_changed() const {
return changes > 0;
}
-void RenderingServerDefault::init() {
+void RenderingServerDefault::_init() {
RSG::rasterizer->initialize();
}
-void RenderingServerDefault::finish() {
+void RenderingServerDefault::_finish() {
if (test_cube.is_valid()) {
free(test_cube);
}
@@ -232,9 +229,35 @@ void RenderingServerDefault::finish() {
RSG::rasterizer->finalize();
}
+void RenderingServerDefault::init() {
+ if (create_thread) {
+ print_verbose("RenderingServerWrapMT: Creating render thread");
+ DisplayServer::get_singleton()->release_rendering_thread();
+ if (create_thread) {
+ thread.start(_thread_callback, this);
+ print_verbose("RenderingServerWrapMT: Starting render thread");
+ }
+ while (!draw_thread_up.is_set()) {
+ OS::get_singleton()->delay_usec(1000);
+ }
+ print_verbose("RenderingServerWrapMT: Finished render thread");
+ } else {
+ _init();
+ }
+}
+
+void RenderingServerDefault::finish() {
+ if (create_thread) {
+ command_queue.push(this, &RenderingServerDefault::_thread_exit);
+ thread.wait_to_finish();
+ } else {
+ _finish();
+ }
+}
+
/* STATUS INFORMATION */
-int RenderingServerDefault::get_render_info(RenderInfo p_info) {
+uint64_t RenderingServerDefault::get_render_info(RenderInfo p_info) {
return RSG::storage->get_render_info(p_info);
}
@@ -297,10 +320,6 @@ void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) {
RSG::storage->set_debug_generate_wireframes(p_generate);
}
-void RenderingServerDefault::call_set_use_vsync(bool p_enable) {
- DisplayServer::get_singleton()->_set_use_vsync(p_enable);
-}
-
bool RenderingServerDefault::is_low_end() const {
// FIXME: Commented out when rebasing vulkan branch on master,
// causes a crash, it seems rasterizer is not initialized yet the
@@ -309,7 +328,74 @@ bool RenderingServerDefault::is_low_end() const {
return false;
}
-RenderingServerDefault::RenderingServerDefault() {
+void RenderingServerDefault::_thread_exit() {
+ exit.set();
+}
+
+void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) {
+ if (!draw_pending.decrement()) {
+ _draw(p_swap_buffers, frame_step);
+ }
+}
+
+void RenderingServerDefault::_thread_flush() {
+ draw_pending.decrement();
+}
+
+void RenderingServerDefault::_thread_callback(void *_instance) {
+ RenderingServerDefault *vsmt = reinterpret_cast<RenderingServerDefault *>(_instance);
+
+ vsmt->_thread_loop();
+}
+
+void RenderingServerDefault::_thread_loop() {
+ server_thread = Thread::get_caller_id();
+
+ DisplayServer::get_singleton()->make_rendering_thread();
+
+ _init();
+
+ draw_thread_up.set();
+ while (!exit.is_set()) {
+ // flush commands one by one, until exit is requested
+ command_queue.wait_and_flush_one();
+ }
+
+ command_queue.flush_all(); // flush all
+
+ _finish();
+}
+
+/* EVENT QUEUING */
+
+void RenderingServerDefault::sync() {
+ if (create_thread) {
+ draw_pending.increment();
+ command_queue.push_and_sync(this, &RenderingServerDefault::_thread_flush);
+ } else {
+ command_queue.flush_all(); //flush all pending from other threads
+ }
+}
+
+void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
+ if (create_thread) {
+ draw_pending.increment();
+ command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step);
+ } else {
+ _draw(p_swap_buffers, frame_step);
+ }
+}
+
+RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
+ command_queue(p_create_thread) {
+ create_thread = p_create_thread;
+
+ if (!p_create_thread) {
+ server_thread = Thread::get_caller_id();
+ } else {
+ server_thread = 0;
+ }
+
RSG::canvas = memnew(RendererCanvasCull);
RSG::viewport = memnew(RendererViewport);
RendererSceneCull *sr = memnew(RendererSceneCull);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 823d28c669..c76ae1bb34 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -32,6 +32,7 @@
#define RENDERING_SERVER_DEFAULT_H
#include "core/math/octree.h"
+#include "core/templates/command_queue_mt.h"
#include "core/templates/ordered_hash_map.h"
#include "renderer_canvas_cull.h"
#include "renderer_scene_cull.h"
@@ -39,6 +40,7 @@
#include "rendering_server_globals.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
+#include "servers/server_wrap_mt_common.h"
class RenderingServerDefault : public RenderingServer {
enum {
@@ -81,6 +83,31 @@ class RenderingServerDefault : public RenderingServer {
uint64_t print_frame_profile_ticks_from = 0;
uint32_t print_frame_profile_frame_count = 0;
+ mutable CommandQueueMT command_queue;
+
+ static void _thread_callback(void *_instance);
+ void _thread_loop();
+
+ Thread::ID server_thread;
+ SafeFlag exit;
+ Thread thread;
+ SafeFlag draw_thread_up;
+ bool create_thread;
+
+ SafeNumeric<uint64_t> draw_pending;
+ void _thread_draw(bool p_swap_buffers, double frame_step);
+ void _thread_flush();
+
+ void _thread_exit();
+
+ Mutex alloc_mutex;
+
+ void _draw(bool p_swap_buffers, double frame_step);
+ void _init();
+ void _finish();
+
+ void _free(RID p_rid);
+
public:
//if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed()
//#define DEBUG_CHANGES
@@ -97,807 +124,826 @@ public:
#else
_FORCE_INLINE_ static void redraw_request() { changes++; }
+#endif
-#define DISPLAY_CHANGED \
- changes++;
+#define WRITE_ACTION redraw_request();
+
+#ifdef DEBUG_SYNC
+#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
+#else
+#define SYNC_DEBUG
#endif
-#define BIND0R(m_r, m_name) \
- m_r m_name() { return BINDBASE->m_name(); }
-#define BIND0RC(m_r, m_name) \
- m_r m_name() const { return BINDBASE->m_name(); }
-#define BIND1R(m_r, m_name, m_type1) \
- m_r m_name(m_type1 arg1) { return BINDBASE->m_name(arg1); }
-#define BIND1RC(m_r, m_name, m_type1) \
- m_r m_name(m_type1 arg1) const { return BINDBASE->m_name(arg1); }
-#define BIND2R(m_r, m_name, m_type1, m_type2) \
- m_r m_name(m_type1 arg1, m_type2 arg2) { return BINDBASE->m_name(arg1, arg2); }
-#define BIND2RC(m_r, m_name, m_type1, m_type2) \
- m_r m_name(m_type1 arg1, m_type2 arg2) const { return BINDBASE->m_name(arg1, arg2); }
-#define BIND3R(m_r, m_name, m_type1, m_type2, m_type3) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { return BINDBASE->m_name(arg1, arg2, arg3); }
-#define BIND3RC(m_r, m_name, m_type1, m_type2, m_type3) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) const { return BINDBASE->m_name(arg1, arg2, arg3); }
-#define BIND4R(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { return BINDBASE->m_name(arg1, arg2, arg3, arg4); }
-#define BIND4RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4); }
-#define BIND5R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); }
-#define BIND5RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); }
-#define BIND6R(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); }
-#define BIND6RC(m_r, m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
- m_r m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) const { return BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); }
-
-#define BIND0(m_name) \
- void m_name() { DISPLAY_CHANGED BINDBASE->m_name(); }
-#define BIND1(m_name, m_type1) \
- void m_name(m_type1 arg1) { DISPLAY_CHANGED BINDBASE->m_name(arg1); }
-#define BIND1C(m_name, m_type1) \
- void m_name(m_type1 arg1) const { DISPLAY_CHANGED BINDBASE->m_name(arg1); }
-#define BIND2(m_name, m_type1, m_type2) \
- void m_name(m_type1 arg1, m_type2 arg2) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2); }
-#define BIND2C(m_name, m_type1, m_type2) \
- void m_name(m_type1 arg1, m_type2 arg2) const { BINDBASE->m_name(arg1, arg2); }
-#define BIND3(m_name, m_type1, m_type2, m_type3) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3); }
-#define BIND4(m_name, m_type1, m_type2, m_type3, m_type4) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4); }
-#define BIND5(m_name, m_type1, m_type2, m_type3, m_type4, m_type5) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5); }
-#define BIND6(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6); }
-#define BIND7(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7); }
-#define BIND8(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); }
-#define BIND9(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); }
-#define BIND10(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); }
-#define BIND11(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); }
-#define BIND12(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); }
-#define BIND13(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); }
-#define BIND14(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); }
-#define BIND15(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14, m_type15) \
- void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14, m_type15 arg15) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); }
+#include "servers/server_wrap_mt_common.h"
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::storage
+#define ServerName RendererStorage
+#define server_name RSG::storage
/* TEXTURE API */
+#define FUNCRIDTEX0(m_type) \
+ virtual RID m_type##_create() override { \
+ RID ret = RSG::storage->texture_allocate(); \
+ if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \
+ RSG::storage->m_type##_initialize(ret); \
+ } else { \
+ command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret); \
+ } \
+ return ret; \
+ }
+
+#define FUNCRIDTEX1(m_type, m_type1) \
+ virtual RID m_type##_create(m_type1 p1) override { \
+ RID ret = RSG::storage->texture_allocate(); \
+ if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \
+ RSG::storage->m_type##_initialize(ret, p1); \
+ } else { \
+ command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1); \
+ } \
+ return ret; \
+ }
+
+#define FUNCRIDTEX2(m_type, m_type1, m_type2) \
+ virtual RID m_type##_create(m_type1 p1, m_type2 p2) override { \
+ RID ret = RSG::storage->texture_allocate(); \
+ if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \
+ RSG::storage->m_type##_initialize(ret, p1, p2); \
+ } else { \
+ command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1, p2); \
+ } \
+ return ret; \
+ }
+
+#define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
+ virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \
+ RID ret = RSG::storage->texture_allocate(); \
+ if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) { \
+ RSG::storage->m_type##_initialize(ret, p1, p2, p3, p4, p5, p6); \
+ } else { \
+ command_queue.push(RSG::storage, &RendererStorage::m_type##_initialize, ret, p1, p2, p3, p4, p5, p6); \
+ } \
+ return ret; \
+ }
+
//these go pass-through, as they can be called from any thread
- BIND1R(RID, texture_2d_create, const Ref<Image> &)
- BIND2R(RID, texture_2d_layered_create, const Vector<Ref<Image>> &, TextureLayeredType)
- BIND6R(RID, texture_3d_create, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &)
- BIND1R(RID, texture_proxy_create, RID)
+ FUNCRIDTEX1(texture_2d, const Ref<Image> &)
+ FUNCRIDTEX2(texture_2d_layered, const Vector<Ref<Image>> &, TextureLayeredType)
+ FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &)
+ FUNCRIDTEX1(texture_proxy, RID)
//goes pass-through
- BIND3(texture_2d_update_immediate, RID, const Ref<Image> &, int)
+ FUNC3(texture_2d_update_immediate, RID, const Ref<Image> &, int)
//these go through command queue if they are in another thread
- BIND3(texture_2d_update, RID, const Ref<Image> &, int)
- BIND2(texture_3d_update, RID, const Vector<Ref<Image>> &)
- BIND2(texture_proxy_update, RID, RID)
+ FUNC3(texture_2d_update, RID, const Ref<Image> &, int)
+ FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &)
+ FUNC2(texture_proxy_update, RID, RID)
//these also go pass-through
- BIND0R(RID, texture_2d_placeholder_create)
- BIND1R(RID, texture_2d_layered_placeholder_create, TextureLayeredType)
- BIND0R(RID, texture_3d_placeholder_create)
+ FUNCRIDTEX0(texture_2d_placeholder)
+ FUNCRIDTEX1(texture_2d_layered_placeholder, TextureLayeredType)
+ FUNCRIDTEX0(texture_3d_placeholder)
- BIND1RC(Ref<Image>, texture_2d_get, RID)
- BIND2RC(Ref<Image>, texture_2d_layer_get, RID, int)
- BIND1RC(Vector<Ref<Image>>, texture_3d_get, RID)
+ FUNC1RC(Ref<Image>, texture_2d_get, RID)
+ FUNC2RC(Ref<Image>, texture_2d_layer_get, RID, int)
+ FUNC1RC(Vector<Ref<Image>>, texture_3d_get, RID)
- BIND2(texture_replace, RID, RID)
+ FUNC2(texture_replace, RID, RID)
- BIND3(texture_set_size_override, RID, int, int)
+ FUNC3(texture_set_size_override, RID, int, int)
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
- BIND2(texture_bind, RID, uint32_t)
+ FUNC2(texture_bind, RID, uint32_t)
#endif
- BIND3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *)
- BIND3(texture_set_detect_normal_callback, RID, TextureDetectCallback, void *)
- BIND3(texture_set_detect_roughness_callback, RID, TextureDetectRoughnessCallback, void *)
+ FUNC3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *)
+ FUNC3(texture_set_detect_normal_callback, RID, TextureDetectCallback, void *)
+ FUNC3(texture_set_detect_roughness_callback, RID, TextureDetectRoughnessCallback, void *)
- BIND2(texture_set_path, RID, const String &)
- BIND1RC(String, texture_get_path, RID)
- BIND1(texture_debug_usage, List<TextureInfo> *)
+ FUNC2(texture_set_path, RID, const String &)
+ FUNC1RC(String, texture_get_path, RID)
+ FUNC1(texture_debug_usage, List<TextureInfo> *)
- BIND2(texture_set_force_redraw_if_visible, RID, bool)
+ FUNC2(texture_set_force_redraw_if_visible, RID, bool)
/* SHADER API */
- BIND0R(RID, shader_create)
+ FUNCRIDSPLIT(shader)
- BIND2(shader_set_code, RID, const String &)
- BIND1RC(String, shader_get_code, RID)
+ FUNC2(shader_set_code, RID, const String &)
+ FUNC1RC(String, shader_get_code, RID)
- BIND2C(shader_get_param_list, RID, List<PropertyInfo> *)
+ FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
- BIND3(shader_set_default_texture_param, RID, const StringName &, RID)
- BIND2RC(RID, shader_get_default_texture_param, RID, const StringName &)
- BIND2RC(Variant, shader_get_param_default, RID, const StringName &)
+ FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
+ FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
+ FUNC2RC(Variant, shader_get_param_default, RID, const StringName &)
- BIND1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID)
+ FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID)
/* COMMON MATERIAL API */
- BIND0R(RID, material_create)
+ FUNCRIDSPLIT(material)
- BIND2(material_set_shader, RID, RID)
+ FUNC2(material_set_shader, RID, RID)
- BIND3(material_set_param, RID, const StringName &, const Variant &)
- BIND2RC(Variant, material_get_param, RID, const StringName &)
+ FUNC3(material_set_param, RID, const StringName &, const Variant &)
+ FUNC2RC(Variant, material_get_param, RID, const StringName &)
- BIND2(material_set_render_priority, RID, int)
- BIND2(material_set_next_pass, RID, RID)
+ FUNC2(material_set_render_priority, RID, int)
+ FUNC2(material_set_next_pass, RID, RID)
/* MESH API */
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) {
- RID mesh = mesh_create();
- mesh_set_blend_shape_count(mesh, p_blend_shape_count);
- for (int i = 0; i < p_surfaces.size(); i++) {
- mesh_add_surface(mesh, p_surfaces[i]);
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override {
+ RID mesh = RSG::storage->mesh_allocate();
+
+ if (Thread::get_caller_id() == server_thread || RSG::storage->can_create_resources_async()) {
+ if (Thread::get_caller_id() == server_thread) {
+ command_queue.flush_if_pending();
+ }
+ RSG::storage->mesh_initialize(mesh);
+ RSG::storage->mesh_set_blend_shape_count(mesh, p_blend_shape_count);
+ for (int i = 0; i < p_surfaces.size(); i++) {
+ RSG::storage->mesh_add_surface(mesh, p_surfaces[i]);
+ }
+ } else {
+ command_queue.push(RSG::storage, &RendererStorage::mesh_initialize, mesh);
+ command_queue.push(RSG::storage, &RendererStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count);
+ for (int i = 0; i < p_surfaces.size(); i++) {
+ RSG::storage->mesh_add_surface(mesh, p_surfaces[i]);
+ command_queue.push(RSG::storage, &RendererStorage::mesh_add_surface, mesh, p_surfaces[i]);
+ }
}
+
return mesh;
}
- BIND2(mesh_set_blend_shape_count, RID, int)
+ FUNC2(mesh_set_blend_shape_count, RID, int)
- BIND0R(RID, mesh_create)
+ FUNCRIDSPLIT(mesh)
- BIND2(mesh_add_surface, RID, const SurfaceData &)
+ FUNC2(mesh_add_surface, RID, const SurfaceData &)
- BIND1RC(int, mesh_get_blend_shape_count, RID)
+ FUNC1RC(int, mesh_get_blend_shape_count, RID)
- BIND2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
- BIND1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
+ FUNC2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
+ FUNC1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
- BIND4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &)
+ FUNC4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &)
- BIND3(mesh_surface_set_material, RID, int, RID)
- BIND2RC(RID, mesh_surface_get_material, RID, int)
+ FUNC3(mesh_surface_set_material, RID, int, RID)
+ FUNC2RC(RID, mesh_surface_get_material, RID, int)
- BIND2RC(SurfaceData, mesh_get_surface, RID, int)
+ FUNC2RC(SurfaceData, mesh_get_surface, RID, int)
- BIND1RC(int, mesh_get_surface_count, RID)
+ FUNC1RC(int, mesh_get_surface_count, RID)
- BIND2(mesh_set_custom_aabb, RID, const AABB &)
- BIND1RC(AABB, mesh_get_custom_aabb, RID)
+ FUNC2(mesh_set_custom_aabb, RID, const AABB &)
+ FUNC1RC(AABB, mesh_get_custom_aabb, RID)
- BIND2(mesh_set_shadow_mesh, RID, RID)
+ FUNC2(mesh_set_shadow_mesh, RID, RID)
- BIND1(mesh_clear, RID)
+ FUNC1(mesh_clear, RID)
/* MULTIMESH API */
- BIND0R(RID, multimesh_create)
+ FUNCRIDSPLIT(multimesh)
- BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool)
- BIND1RC(int, multimesh_get_instance_count, RID)
+ FUNC5(multimesh_allocate_data, RID, int, MultimeshTransformFormat, bool, bool)
+ FUNC1RC(int, multimesh_get_instance_count, RID)
- BIND2(multimesh_set_mesh, RID, RID)
- BIND3(multimesh_instance_set_transform, RID, int, const Transform &)
- BIND3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &)
- BIND3(multimesh_instance_set_color, RID, int, const Color &)
- BIND3(multimesh_instance_set_custom_data, RID, int, const Color &)
+ FUNC2(multimesh_set_mesh, RID, RID)
+ FUNC3(multimesh_instance_set_transform, RID, int, const Transform &)
+ FUNC3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &)
+ FUNC3(multimesh_instance_set_color, RID, int, const Color &)
+ FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &)
- BIND1RC(RID, multimesh_get_mesh, RID)
- BIND1RC(AABB, multimesh_get_aabb, RID)
+ FUNC1RC(RID, multimesh_get_mesh, RID)
+ FUNC1RC(AABB, multimesh_get_aabb, RID)
- BIND2RC(Transform, multimesh_instance_get_transform, RID, int)
- BIND2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int)
- BIND2RC(Color, multimesh_instance_get_color, RID, int)
- BIND2RC(Color, multimesh_instance_get_custom_data, RID, int)
+ FUNC2RC(Transform, multimesh_instance_get_transform, RID, int)
+ FUNC2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int)
+ FUNC2RC(Color, multimesh_instance_get_color, RID, int)
+ FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)
- BIND2(multimesh_set_buffer, RID, const Vector<float> &)
- BIND1RC(Vector<float>, multimesh_get_buffer, RID)
+ FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
+ FUNC1RC(Vector<float>, multimesh_get_buffer, RID)
- BIND2(multimesh_set_visible_instances, RID, int)
- BIND1RC(int, multimesh_get_visible_instances, RID)
+ FUNC2(multimesh_set_visible_instances, RID, int)
+ FUNC1RC(int, multimesh_get_visible_instances, RID)
/* IMMEDIATE API */
- BIND0R(RID, immediate_create)
- BIND3(immediate_begin, RID, PrimitiveType, RID)
- BIND2(immediate_vertex, RID, const Vector3 &)
- BIND2(immediate_normal, RID, const Vector3 &)
- BIND2(immediate_tangent, RID, const Plane &)
- BIND2(immediate_color, RID, const Color &)
- BIND2(immediate_uv, RID, const Vector2 &)
- BIND2(immediate_uv2, RID, const Vector2 &)
- BIND1(immediate_end, RID)
- BIND1(immediate_clear, RID)
- BIND2(immediate_set_material, RID, RID)
- BIND1RC(RID, immediate_get_material, RID)
+ FUNCRIDSPLIT(immediate)
+ FUNC3(immediate_begin, RID, PrimitiveType, RID)
+ FUNC2(immediate_vertex, RID, const Vector3 &)
+ FUNC2(immediate_normal, RID, const Vector3 &)
+ FUNC2(immediate_tangent, RID, const Plane &)
+ FUNC2(immediate_color, RID, const Color &)
+ FUNC2(immediate_uv, RID, const Vector2 &)
+ FUNC2(immediate_uv2, RID, const Vector2 &)
+ FUNC1(immediate_end, RID)
+ FUNC1(immediate_clear, RID)
+ FUNC2(immediate_set_material, RID, RID)
+ FUNC1RC(RID, immediate_get_material, RID)
/* SKELETON API */
- BIND0R(RID, skeleton_create)
- BIND3(skeleton_allocate, RID, int, bool)
- BIND1RC(int, skeleton_get_bone_count, RID)
- BIND3(skeleton_bone_set_transform, RID, int, const Transform &)
- BIND2RC(Transform, skeleton_bone_get_transform, RID, int)
- BIND3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
- BIND2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
- BIND2(skeleton_set_base_transform_2d, RID, const Transform2D &)
+ FUNCRIDSPLIT(skeleton)
+ FUNC3(skeleton_allocate_data, RID, int, bool)
+ FUNC1RC(int, skeleton_get_bone_count, RID)
+ FUNC3(skeleton_bone_set_transform, RID, int, const Transform &)
+ FUNC2RC(Transform, skeleton_bone_get_transform, RID, int)
+ FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
+ FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
+ FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
/* Light API */
- BIND0R(RID, directional_light_create)
- BIND0R(RID, omni_light_create)
- BIND0R(RID, spot_light_create)
+ FUNCRIDSPLIT(directional_light)
+ FUNCRIDSPLIT(omni_light)
+ FUNCRIDSPLIT(spot_light)
- BIND2(light_set_color, RID, const Color &)
- BIND3(light_set_param, RID, LightParam, float)
- BIND2(light_set_shadow, RID, bool)
- BIND2(light_set_shadow_color, RID, const Color &)
- BIND2(light_set_projector, RID, RID)
- BIND2(light_set_negative, RID, bool)
- BIND2(light_set_cull_mask, RID, uint32_t)
- BIND2(light_set_reverse_cull_face_mode, RID, bool)
- BIND2(light_set_bake_mode, RID, LightBakeMode)
- BIND2(light_set_max_sdfgi_cascade, RID, uint32_t)
+ FUNC2(light_set_color, RID, const Color &)
+ FUNC3(light_set_param, RID, LightParam, float)
+ FUNC2(light_set_shadow, RID, bool)
+ FUNC2(light_set_shadow_color, RID, const Color &)
+ FUNC2(light_set_projector, RID, RID)
+ FUNC2(light_set_negative, RID, bool)
+ FUNC2(light_set_cull_mask, RID, uint32_t)
+ FUNC2(light_set_reverse_cull_face_mode, RID, bool)
+ FUNC2(light_set_bake_mode, RID, LightBakeMode)
+ FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t)
- BIND2(light_omni_set_shadow_mode, RID, LightOmniShadowMode)
+ FUNC2(light_omni_set_shadow_mode, RID, LightOmniShadowMode)
- BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
- BIND2(light_directional_set_blend_splits, RID, bool)
- BIND2(light_directional_set_sky_only, RID, bool)
- BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
+ FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
+ FUNC2(light_directional_set_blend_splits, RID, bool)
+ FUNC2(light_directional_set_sky_only, RID, bool)
+ FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
- BIND0R(RID, reflection_probe_create)
-
- BIND2(reflection_probe_set_update_mode, RID, ReflectionProbeUpdateMode)
- BIND2(reflection_probe_set_intensity, RID, float)
- BIND2(reflection_probe_set_ambient_color, RID, const Color &)
- BIND2(reflection_probe_set_ambient_energy, RID, float)
- BIND2(reflection_probe_set_ambient_mode, RID, ReflectionProbeAmbientMode)
- BIND2(reflection_probe_set_max_distance, RID, float)
- BIND2(reflection_probe_set_extents, RID, const Vector3 &)
- BIND2(reflection_probe_set_origin_offset, RID, const Vector3 &)
- BIND2(reflection_probe_set_as_interior, RID, bool)
- BIND2(reflection_probe_set_enable_box_projection, RID, bool)
- BIND2(reflection_probe_set_enable_shadows, RID, bool)
- BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
- BIND2(reflection_probe_set_resolution, RID, int)
- BIND2(reflection_probe_set_lod_threshold, RID, float)
+ FUNCRIDSPLIT(reflection_probe)
+
+ FUNC2(reflection_probe_set_update_mode, RID, ReflectionProbeUpdateMode)
+ FUNC2(reflection_probe_set_intensity, RID, float)
+ FUNC2(reflection_probe_set_ambient_color, RID, const Color &)
+ FUNC2(reflection_probe_set_ambient_energy, RID, float)
+ FUNC2(reflection_probe_set_ambient_mode, RID, ReflectionProbeAmbientMode)
+ FUNC2(reflection_probe_set_max_distance, RID, float)
+ FUNC2(reflection_probe_set_extents, RID, const Vector3 &)
+ FUNC2(reflection_probe_set_origin_offset, RID, const Vector3 &)
+ FUNC2(reflection_probe_set_as_interior, RID, bool)
+ FUNC2(reflection_probe_set_enable_box_projection, RID, bool)
+ FUNC2(reflection_probe_set_enable_shadows, RID, bool)
+ FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
+ FUNC2(reflection_probe_set_resolution, RID, int)
+ FUNC2(reflection_probe_set_lod_threshold, RID, float)
/* DECAL API */
- BIND0R(RID, decal_create)
+ FUNCRIDSPLIT(decal)
- BIND2(decal_set_extents, RID, const Vector3 &)
- BIND3(decal_set_texture, RID, DecalTexture, RID)
- BIND2(decal_set_emission_energy, RID, float)
- BIND2(decal_set_albedo_mix, RID, float)
- BIND2(decal_set_modulate, RID, const Color &)
- BIND2(decal_set_cull_mask, RID, uint32_t)
- BIND4(decal_set_distance_fade, RID, bool, float, float)
- BIND3(decal_set_fade, RID, float, float)
- BIND2(decal_set_normal_fade, RID, float)
+ FUNC2(decal_set_extents, RID, const Vector3 &)
+ FUNC3(decal_set_texture, RID, DecalTexture, RID)
+ FUNC2(decal_set_emission_energy, RID, float)
+ FUNC2(decal_set_albedo_mix, RID, float)
+ FUNC2(decal_set_modulate, RID, const Color &)
+ FUNC2(decal_set_cull_mask, RID, uint32_t)
+ FUNC4(decal_set_distance_fade, RID, bool, float, float)
+ FUNC3(decal_set_fade, RID, float, float)
+ FUNC2(decal_set_normal_fade, RID, float)
/* BAKED LIGHT API */
- BIND0R(RID, gi_probe_create)
+ FUNCRIDSPLIT(gi_probe)
- BIND8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
+ FUNC8(gi_probe_allocate_data, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
- BIND1RC(AABB, gi_probe_get_bounds, RID)
- BIND1RC(Vector3i, gi_probe_get_octree_size, RID)
- BIND1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID)
- BIND1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID)
- BIND1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID)
- BIND1RC(Vector<int>, gi_probe_get_level_counts, RID)
- BIND1RC(Transform, gi_probe_get_to_cell_xform, RID)
+ FUNC1RC(AABB, gi_probe_get_bounds, RID)
+ FUNC1RC(Vector3i, gi_probe_get_octree_size, RID)
+ FUNC1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID)
+ FUNC1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID)
+ FUNC1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID)
+ FUNC1RC(Vector<int>, gi_probe_get_level_counts, RID)
+ FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID)
- BIND2(gi_probe_set_dynamic_range, RID, float)
- BIND1RC(float, gi_probe_get_dynamic_range, RID)
+ FUNC2(gi_probe_set_dynamic_range, RID, float)
+ FUNC1RC(float, gi_probe_get_dynamic_range, RID)
- BIND2(gi_probe_set_propagation, RID, float)
- BIND1RC(float, gi_probe_get_propagation, RID)
+ FUNC2(gi_probe_set_propagation, RID, float)
+ FUNC1RC(float, gi_probe_get_propagation, RID)
- BIND2(gi_probe_set_energy, RID, float)
- BIND1RC(float, gi_probe_get_energy, RID)
+ FUNC2(gi_probe_set_energy, RID, float)
+ FUNC1RC(float, gi_probe_get_energy, RID)
- BIND2(gi_probe_set_ao, RID, float)
- BIND1RC(float, gi_probe_get_ao, RID)
+ FUNC2(gi_probe_set_ao, RID, float)
+ FUNC1RC(float, gi_probe_get_ao, RID)
- BIND2(gi_probe_set_ao_size, RID, float)
- BIND1RC(float, gi_probe_get_ao_size, RID)
+ FUNC2(gi_probe_set_ao_size, RID, float)
+ FUNC1RC(float, gi_probe_get_ao_size, RID)
- BIND2(gi_probe_set_bias, RID, float)
- BIND1RC(float, gi_probe_get_bias, RID)
+ FUNC2(gi_probe_set_bias, RID, float)
+ FUNC1RC(float, gi_probe_get_bias, RID)
- BIND2(gi_probe_set_normal_bias, RID, float)
- BIND1RC(float, gi_probe_get_normal_bias, RID)
+ FUNC2(gi_probe_set_normal_bias, RID, float)
+ FUNC1RC(float, gi_probe_get_normal_bias, RID)
- BIND2(gi_probe_set_interior, RID, bool)
- BIND1RC(bool, gi_probe_is_interior, RID)
+ FUNC2(gi_probe_set_interior, RID, bool)
+ FUNC1RC(bool, gi_probe_is_interior, RID)
- BIND2(gi_probe_set_use_two_bounces, RID, bool)
- BIND1RC(bool, gi_probe_is_using_two_bounces, RID)
+ FUNC2(gi_probe_set_use_two_bounces, RID, bool)
+ FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
- BIND2(gi_probe_set_anisotropy_strength, RID, float)
- BIND1RC(float, gi_probe_get_anisotropy_strength, RID)
+ FUNC2(gi_probe_set_anisotropy_strength, RID, float)
+ FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
/* LIGHTMAP */
- BIND0R(RID, lightmap_create)
+ FUNCRIDSPLIT(lightmap)
- BIND3(lightmap_set_textures, RID, RID, bool)
- BIND2(lightmap_set_probe_bounds, RID, const AABB &)
- BIND2(lightmap_set_probe_interior, RID, bool)
- BIND5(lightmap_set_probe_capture_data, RID, const PackedVector3Array &, const PackedColorArray &, const PackedInt32Array &, const PackedInt32Array &)
- BIND1RC(PackedVector3Array, lightmap_get_probe_capture_points, RID)
- BIND1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID)
- BIND1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID)
- BIND1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
- BIND1(lightmap_set_probe_capture_update_speed, float)
+ FUNC3(lightmap_set_textures, RID, RID, bool)
+ FUNC2(lightmap_set_probe_bounds, RID, const AABB &)
+ FUNC2(lightmap_set_probe_interior, RID, bool)
+ FUNC5(lightmap_set_probe_capture_data, RID, const PackedVector3Array &, const PackedColorArray &, const PackedInt32Array &, const PackedInt32Array &)
+ FUNC1RC(PackedVector3Array, lightmap_get_probe_capture_points, RID)
+ FUNC1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID)
+ FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID)
+ FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
+ FUNC1(lightmap_set_probe_capture_update_speed, float)
/* PARTICLES */
- BIND0R(RID, particles_create)
-
- BIND2(particles_set_emitting, RID, bool)
- BIND1R(bool, particles_get_emitting, RID)
- BIND2(particles_set_amount, RID, int)
- BIND2(particles_set_lifetime, RID, float)
- BIND2(particles_set_one_shot, RID, bool)
- BIND2(particles_set_pre_process_time, RID, float)
- BIND2(particles_set_explosiveness_ratio, RID, float)
- BIND2(particles_set_randomness_ratio, RID, float)
- BIND2(particles_set_custom_aabb, RID, const AABB &)
- BIND2(particles_set_speed_scale, RID, float)
- BIND2(particles_set_use_local_coordinates, RID, bool)
- BIND2(particles_set_process_material, RID, RID)
- BIND2(particles_set_fixed_fps, RID, int)
- BIND2(particles_set_fractional_delta, RID, bool)
- BIND1R(bool, particles_is_inactive, RID)
- BIND1(particles_request_process, RID)
- BIND1(particles_restart, RID)
- BIND6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
- BIND2(particles_set_subemitter, RID, RID)
- BIND2(particles_set_collision_base_size, RID, float)
-
- BIND2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
-
- BIND2(particles_set_draw_passes, RID, int)
- BIND3(particles_set_draw_pass_mesh, RID, int, RID)
-
- BIND1R(AABB, particles_get_current_aabb, RID)
- BIND2(particles_set_emission_transform, RID, const Transform &)
+ FUNCRIDSPLIT(particles)
+
+ FUNC2(particles_set_emitting, RID, bool)
+ FUNC1R(bool, particles_get_emitting, RID)
+ FUNC2(particles_set_amount, RID, int)
+ FUNC2(particles_set_lifetime, RID, float)
+ FUNC2(particles_set_one_shot, RID, bool)
+ FUNC2(particles_set_pre_process_time, RID, float)
+ FUNC2(particles_set_explosiveness_ratio, RID, float)
+ FUNC2(particles_set_randomness_ratio, RID, float)
+ FUNC2(particles_set_custom_aabb, RID, const AABB &)
+ FUNC2(particles_set_speed_scale, RID, float)
+ FUNC2(particles_set_use_local_coordinates, RID, bool)
+ FUNC2(particles_set_process_material, RID, RID)
+ FUNC2(particles_set_fixed_fps, RID, int)
+ FUNC2(particles_set_interpolate, RID, bool)
+ FUNC2(particles_set_fractional_delta, RID, bool)
+ FUNC1R(bool, particles_is_inactive, RID)
+ FUNC3(particles_set_trails, RID, bool, float)
+ FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform> &)
+
+ FUNC1(particles_request_process, RID)
+ FUNC1(particles_restart, RID)
+ FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+ FUNC2(particles_set_subemitter, RID, RID)
+ FUNC2(particles_set_collision_base_size, RID, float)
+
+ FUNC2(particles_set_transform_align, RID, RS::ParticlesTransformAlign)
+
+ FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
+
+ FUNC2(particles_set_draw_passes, RID, int)
+ FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
+
+ FUNC1R(AABB, particles_get_current_aabb, RID)
+ FUNC2(particles_set_emission_transform, RID, const Transform &)
/* PARTICLES COLLISION */
- BIND0R(RID, particles_collision_create)
-
- BIND2(particles_collision_set_collision_type, RID, ParticlesCollisionType)
- BIND2(particles_collision_set_cull_mask, RID, uint32_t)
- BIND2(particles_collision_set_sphere_radius, RID, float)
- BIND2(particles_collision_set_box_extents, RID, const Vector3 &)
- BIND2(particles_collision_set_attractor_strength, RID, float)
- BIND2(particles_collision_set_attractor_directionality, RID, float)
- BIND2(particles_collision_set_attractor_attenuation, RID, float)
- BIND2(particles_collision_set_field_texture, RID, RID)
- BIND1(particles_collision_height_field_update, RID)
- BIND2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
-
-#undef BINDBASE
+ FUNCRIDSPLIT(particles_collision)
+
+ FUNC2(particles_collision_set_collision_type, RID, ParticlesCollisionType)
+ FUNC2(particles_collision_set_cull_mask, RID, uint32_t)
+ FUNC2(particles_collision_set_sphere_radius, RID, float)
+ FUNC2(particles_collision_set_box_extents, RID, const Vector3 &)
+ FUNC2(particles_collision_set_attractor_strength, RID, float)
+ FUNC2(particles_collision_set_attractor_directionality, RID, float)
+ FUNC2(particles_collision_set_attractor_attenuation, RID, float)
+ FUNC2(particles_collision_set_field_texture, RID, RID)
+ FUNC1(particles_collision_height_field_update, RID)
+ FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
+
+#undef server_name
+#undef ServerName
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::scene
+#define ServerName RendererScene
+#define server_name RSG::scene
/* CAMERA API */
- BIND0R(RID, camera_create)
- BIND4(camera_set_perspective, RID, float, float, float)
- BIND4(camera_set_orthogonal, RID, float, float, float)
- BIND5(camera_set_frustum, RID, float, Vector2, float, float)
- BIND2(camera_set_transform, RID, const Transform &)
- BIND2(camera_set_cull_mask, RID, uint32_t)
- BIND2(camera_set_environment, RID, RID)
- BIND2(camera_set_camera_effects, RID, RID)
- BIND2(camera_set_use_vertical_aspect, RID, bool)
-
-#undef BINDBASE
+ FUNCRIDSPLIT(camera)
+ FUNC4(camera_set_perspective, RID, float, float, float)
+ FUNC4(camera_set_orthogonal, RID, float, float, float)
+ FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
+ FUNC2(camera_set_transform, RID, const Transform &)
+ FUNC2(camera_set_cull_mask, RID, uint32_t)
+ FUNC2(camera_set_environment, RID, RID)
+ FUNC2(camera_set_camera_effects, RID, RID)
+ FUNC2(camera_set_use_vertical_aspect, RID, bool)
+
+ /* OCCLUDER */
+ FUNCRIDSPLIT(occluder)
+ FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &);
+
+#undef server_name
+#undef ServerName
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::viewport
+#define ServerName RendererViewport
+#define server_name RSG::viewport
/* VIEWPORT TARGET API */
- BIND0R(RID, viewport_create)
+ FUNCRIDSPLIT(viewport)
- BIND2(viewport_set_use_xr, RID, bool)
- BIND3(viewport_set_size, RID, int, int)
+ FUNC2(viewport_set_use_xr, RID, bool)
+ FUNC3(viewport_set_size, RID, int, int)
- BIND2(viewport_set_active, RID, bool)
- BIND2(viewport_set_parent_viewport, RID, RID)
+ FUNC2(viewport_set_active, RID, bool)
+ FUNC2(viewport_set_parent_viewport, RID, RID)
- BIND2(viewport_set_clear_mode, RID, ViewportClearMode)
+ FUNC2(viewport_set_clear_mode, RID, ViewportClearMode)
- BIND3(viewport_attach_to_screen, RID, const Rect2 &, int)
- BIND2(viewport_set_render_direct_to_screen, RID, bool)
+ FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int)
+ FUNC2(viewport_set_render_direct_to_screen, RID, bool)
- BIND2(viewport_set_update_mode, RID, ViewportUpdateMode)
- BIND2(viewport_set_vflip, RID, bool)
+ FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode)
- BIND1RC(RID, viewport_get_texture, RID)
+ FUNC1RC(RID, viewport_get_texture, RID)
- BIND2(viewport_set_hide_scenario, RID, bool)
- BIND2(viewport_set_hide_canvas, RID, bool)
- BIND2(viewport_set_disable_environment, RID, bool)
+ FUNC2(viewport_set_hide_scenario, RID, bool)
+ FUNC2(viewport_set_hide_canvas, RID, bool)
+ FUNC2(viewport_set_disable_environment, RID, bool)
- BIND2(viewport_attach_camera, RID, RID)
- BIND2(viewport_set_scenario, RID, RID)
- BIND2(viewport_attach_canvas, RID, RID)
+ FUNC2(viewport_attach_camera, RID, RID)
+ FUNC2(viewport_set_scenario, RID, RID)
+ FUNC2(viewport_attach_canvas, RID, RID)
- BIND2(viewport_remove_canvas, RID, RID)
- BIND3(viewport_set_canvas_transform, RID, RID, const Transform2D &)
- BIND2(viewport_set_transparent_background, RID, bool)
- BIND2(viewport_set_snap_2d_transforms_to_pixel, RID, bool)
- BIND2(viewport_set_snap_2d_vertices_to_pixel, RID, bool)
+ FUNC2(viewport_remove_canvas, RID, RID)
+ FUNC3(viewport_set_canvas_transform, RID, RID, const Transform2D &)
+ FUNC2(viewport_set_transparent_background, RID, bool)
+ FUNC2(viewport_set_snap_2d_transforms_to_pixel, RID, bool)
+ FUNC2(viewport_set_snap_2d_vertices_to_pixel, RID, bool)
- BIND2(viewport_set_default_canvas_item_texture_filter, RID, CanvasItemTextureFilter)
- BIND2(viewport_set_default_canvas_item_texture_repeat, RID, CanvasItemTextureRepeat)
+ FUNC2(viewport_set_default_canvas_item_texture_filter, RID, CanvasItemTextureFilter)
+ FUNC2(viewport_set_default_canvas_item_texture_repeat, RID, CanvasItemTextureRepeat)
- BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &)
- BIND4(viewport_set_canvas_stacking, RID, RID, int, int)
- BIND3(viewport_set_shadow_atlas_size, RID, int, bool)
- BIND3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
- BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
- BIND2(viewport_set_msaa, RID, ViewportMSAA)
- BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
- BIND2(viewport_set_use_debanding, RID, bool)
- BIND2(viewport_set_lod_threshold, RID, float)
+ FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &)
+ FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
+ FUNC3(viewport_set_shadow_atlas_size, RID, int, bool)
+ FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
+ FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
+ FUNC2(viewport_set_msaa, RID, ViewportMSAA)
+ FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
+ FUNC2(viewport_set_use_debanding, RID, bool)
+ FUNC2(viewport_set_use_occlusion_culling, RID, bool)
+ FUNC1(viewport_set_occlusion_rays_per_thread, int)
+ FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality)
+ FUNC2(viewport_set_lod_threshold, RID, float)
- BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
- BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw)
+ FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
+ FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw)
- BIND2(viewport_set_measure_render_time, RID, bool)
- BIND1RC(float, viewport_get_measured_render_time_cpu, RID)
- BIND1RC(float, viewport_get_measured_render_time_gpu, RID)
+ FUNC2(viewport_set_measure_render_time, RID, bool)
+ FUNC1RC(float, viewport_get_measured_render_time_cpu, RID)
+ FUNC1RC(float, viewport_get_measured_render_time_gpu, RID)
+
+ FUNC1(call_set_use_vsync, bool)
/* ENVIRONMENT API */
-#undef BINDBASE
+#undef server_name
+#undef ServerName
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::scene
+#define ServerName RendererScene
+#define server_name RSG::scene
- BIND2(directional_shadow_atlas_set_size, int, bool)
- BIND1(gi_probe_set_quality, GIProbeQuality)
+ FUNC2(directional_shadow_atlas_set_size, int, bool)
+ FUNC1(gi_probe_set_quality, GIProbeQuality)
/* SKY API */
- BIND0R(RID, sky_create)
- BIND2(sky_set_radiance_size, RID, int)
- BIND2(sky_set_mode, RID, SkyMode)
- BIND2(sky_set_material, RID, RID)
- BIND4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &)
+ FUNCRIDSPLIT(sky)
+ FUNC2(sky_set_radiance_size, RID, int)
+ FUNC2(sky_set_mode, RID, SkyMode)
+ FUNC2(sky_set_material, RID, RID)
+ FUNC4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &)
- BIND0R(RID, environment_create)
+ FUNCRIDSPLIT(environment)
- BIND2(environment_set_background, RID, EnvironmentBG)
- BIND2(environment_set_sky, RID, RID)
- BIND2(environment_set_sky_custom_fov, RID, float)
- BIND2(environment_set_sky_orientation, RID, const Basis &)
- BIND2(environment_set_bg_color, RID, const Color &)
- BIND2(environment_set_bg_energy, RID, float)
- BIND2(environment_set_canvas_max_layer, RID, int)
- BIND7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &)
+ FUNC2(environment_set_background, RID, EnvironmentBG)
+ FUNC2(environment_set_sky, RID, RID)
+ FUNC2(environment_set_sky_custom_fov, RID, float)
+ FUNC2(environment_set_sky_orientation, RID, const Basis &)
+ FUNC2(environment_set_bg_color, RID, const Color &)
+ FUNC2(environment_set_bg_energy, RID, float)
+ FUNC2(environment_set_canvas_max_layer, RID, int)
+ FUNC7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &)
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
- BIND2(environment_set_camera_feed_id, RID, int)
+ FUNC2(environment_set_camera_feed_id, RID, int)
#endif
- BIND6(environment_set_ssr, RID, bool, int, float, float, float)
- BIND1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality)
+ FUNC6(environment_set_ssr, RID, bool, int, float, float, float)
+ FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality)
- BIND10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float)
- BIND6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float)
+ FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float)
+ FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float)
- BIND11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
- BIND1(environment_glow_set_use_bicubic_upscale, bool)
- BIND1(environment_glow_set_use_high_quality, bool)
+ FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
+ FUNC1(environment_glow_set_use_bicubic_upscale, bool)
+ FUNC1(environment_glow_set_use_high_quality, bool)
- BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
+ FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
- BIND7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
+ FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
- BIND9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
- BIND10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
+ FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
+ FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
- BIND2(environment_set_volumetric_fog_volume_size, int, int)
- BIND1(environment_set_volumetric_fog_filter_active, bool)
+ FUNC2(environment_set_volumetric_fog_volume_size, int, int)
+ FUNC1(environment_set_volumetric_fog_filter_active, bool)
- BIND11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float)
- BIND1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount)
- BIND1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge)
- BIND1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight)
+ FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, float, bool, float, float, float)
+ FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount)
+ FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge)
+ FUNC1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight)
- BIND3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &)
+ FUNC3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &)
- BIND3(screen_space_roughness_limiter_set_active, bool, float, float)
- BIND1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
- BIND2(sub_surface_scattering_set_scale, float, float)
+ FUNC3(screen_space_roughness_limiter_set_active, bool, float, float)
+ FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
+ FUNC2(sub_surface_scattering_set_scale, float, float)
/* CAMERA EFFECTS */
- BIND0R(RID, camera_effects_create)
+ FUNCRIDSPLIT(camera_effects)
- BIND2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
- BIND1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape)
+ FUNC2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
+ FUNC1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape)
- BIND8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float)
- BIND3(camera_effects_set_custom_exposure, RID, bool, float)
+ FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float)
+ FUNC3(camera_effects_set_custom_exposure, RID, bool, float)
- BIND1(shadows_quality_set, ShadowQuality);
- BIND1(directional_shadow_quality_set, ShadowQuality);
+ FUNC1(shadows_quality_set, ShadowQuality);
+ FUNC1(directional_shadow_quality_set, ShadowQuality);
/* SCENARIO API */
-#undef BINDBASE
-#define BINDBASE RSG::scene
+#undef server_name
+#undef ServerName
+
+#define ServerName RendererScene
+#define server_name RSG::scene
- BIND0R(RID, scenario_create)
+ FUNCRIDSPLIT(scenario)
- BIND2(scenario_set_debug, RID, ScenarioDebugMode)
- BIND2(scenario_set_environment, RID, RID)
- BIND2(scenario_set_camera_effects, RID, RID)
- BIND2(scenario_set_fallback_environment, RID, RID)
+ FUNC2(scenario_set_debug, RID, ScenarioDebugMode)
+ FUNC2(scenario_set_environment, RID, RID)
+ FUNC2(scenario_set_camera_effects, RID, RID)
+ FUNC2(scenario_set_fallback_environment, RID, RID)
/* INSTANCING API */
- BIND0R(RID, instance_create)
+ FUNCRIDSPLIT(instance)
- BIND2(instance_set_base, RID, RID)
- BIND2(instance_set_scenario, RID, RID)
- BIND2(instance_set_layer_mask, RID, uint32_t)
- BIND2(instance_set_transform, RID, const Transform &)
- BIND2(instance_attach_object_instance_id, RID, ObjectID)
- BIND3(instance_set_blend_shape_weight, RID, int, float)
- BIND3(instance_set_surface_material, RID, int, RID)
- BIND2(instance_set_visible, RID, bool)
+ FUNC2(instance_set_base, RID, RID)
+ FUNC2(instance_set_scenario, RID, RID)
+ FUNC2(instance_set_layer_mask, RID, uint32_t)
+ FUNC2(instance_set_transform, RID, const Transform &)
+ FUNC2(instance_attach_object_instance_id, RID, ObjectID)
+ FUNC3(instance_set_blend_shape_weight, RID, int, float)
+ FUNC3(instance_set_surface_override_material, RID, int, RID)
+ FUNC2(instance_set_visible, RID, bool)
- BIND2(instance_set_custom_aabb, RID, AABB)
+ FUNC2(instance_set_custom_aabb, RID, AABB)
- BIND2(instance_attach_skeleton, RID, RID)
- BIND2(instance_set_exterior, RID, bool)
+ FUNC2(instance_attach_skeleton, RID, RID)
+ FUNC2(instance_set_exterior, RID, bool)
- BIND2(instance_set_extra_visibility_margin, RID, real_t)
+ FUNC2(instance_set_extra_visibility_margin, RID, real_t)
// don't use these in a game!
- BIND2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
- BIND3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID)
- BIND2RC(Vector<ObjectID>, instances_cull_convex, const Vector<Plane> &, RID)
+ FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
+ FUNC3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID)
+ FUNC2RC(Vector<ObjectID>, instances_cull_convex, const Vector<Plane> &, RID)
- BIND3(instance_geometry_set_flag, RID, InstanceFlags, bool)
- BIND2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting)
- BIND2(instance_geometry_set_material_override, RID, RID)
+ FUNC3(instance_geometry_set_flag, RID, InstanceFlags, bool)
+ FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting)
+ FUNC2(instance_geometry_set_material_override, RID, RID)
- BIND5(instance_geometry_set_draw_range, RID, float, float, float, float)
- BIND2(instance_geometry_set_as_instance_lod, RID, RID)
- BIND4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
- BIND2(instance_geometry_set_lod_bias, RID, float)
+ FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
+ FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
+ FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
+ FUNC2(instance_geometry_set_lod_bias, RID, float)
- BIND3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
- BIND2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
- BIND2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &)
- BIND2C(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *)
+ FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
+ FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
+ FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &)
+ FUNC2C(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *)
- BIND3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &)
+ FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &)
- BIND1(gi_set_use_half_resolution, bool)
+ FUNC1(gi_set_use_half_resolution, bool)
-#undef BINDBASE
+#undef server_name
+#undef ServerName
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::canvas
+#define ServerName RendererCanvasCull
+#define server_name RSG::canvas
/* CANVAS (2D) */
- BIND0R(RID, canvas_create)
- BIND3(canvas_set_item_mirroring, RID, RID, const Point2 &)
- BIND2(canvas_set_modulate, RID, const Color &)
- BIND3(canvas_set_parent, RID, RID, float)
- BIND1(canvas_set_disable_scale, bool)
-
- BIND0R(RID, canvas_texture_create)
- BIND3(canvas_texture_set_channel, RID, CanvasTextureChannel, RID)
- BIND3(canvas_texture_set_shading_parameters, RID, const Color &, float)
-
- BIND2(canvas_texture_set_texture_filter, RID, CanvasItemTextureFilter)
- BIND2(canvas_texture_set_texture_repeat, RID, CanvasItemTextureRepeat)
-
- BIND0R(RID, canvas_item_create)
- BIND2(canvas_item_set_parent, RID, RID)
-
- BIND2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
- BIND2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
-
- BIND2(canvas_item_set_visible, RID, bool)
- BIND2(canvas_item_set_light_mask, RID, int)
-
- BIND2(canvas_item_set_update_when_visible, RID, bool)
-
- BIND2(canvas_item_set_transform, RID, const Transform2D &)
- BIND2(canvas_item_set_clip, RID, bool)
- BIND2(canvas_item_set_distance_field_mode, RID, bool)
- BIND3(canvas_item_set_custom_rect, RID, bool, const Rect2 &)
- BIND2(canvas_item_set_modulate, RID, const Color &)
- BIND2(canvas_item_set_self_modulate, RID, const Color &)
-
- BIND2(canvas_item_set_draw_behind_parent, RID, bool)
-
- BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
- BIND4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
- BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
- BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
- BIND6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
- BIND7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
- BIND10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
- BIND6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
- BIND5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
- BIND9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int)
- BIND5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID)
- BIND3(canvas_item_add_multimesh, RID, RID, RID)
- BIND3(canvas_item_add_particles, RID, RID, RID)
- BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
- BIND2(canvas_item_add_clip_ignore, RID, bool)
- BIND2(canvas_item_set_sort_children_by_y, RID, bool)
- BIND2(canvas_item_set_z_index, RID, int)
- BIND2(canvas_item_set_z_as_relative_to_parent, RID, bool)
- BIND3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &)
- BIND2(canvas_item_attach_skeleton, RID, RID)
-
- BIND1(canvas_item_clear, RID)
- BIND2(canvas_item_set_draw_index, RID, int)
-
- BIND2(canvas_item_set_material, RID, RID)
-
- BIND2(canvas_item_set_use_parent_material, RID, bool)
-
- BIND6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
-
- BIND0R(RID, canvas_light_create)
-
- BIND2(canvas_light_set_mode, RID, CanvasLightMode)
-
- BIND2(canvas_light_attach_to_canvas, RID, RID)
- BIND2(canvas_light_set_enabled, RID, bool)
- BIND2(canvas_light_set_texture_scale, RID, float)
- BIND2(canvas_light_set_transform, RID, const Transform2D &)
- BIND2(canvas_light_set_texture, RID, RID)
- BIND2(canvas_light_set_texture_offset, RID, const Vector2 &)
- BIND2(canvas_light_set_color, RID, const Color &)
- BIND2(canvas_light_set_height, RID, float)
- BIND2(canvas_light_set_energy, RID, float)
- BIND3(canvas_light_set_z_range, RID, int, int)
- BIND3(canvas_light_set_layer_range, RID, int, int)
- BIND2(canvas_light_set_item_cull_mask, RID, int)
- BIND2(canvas_light_set_item_shadow_cull_mask, RID, int)
- BIND2(canvas_light_set_directional_distance, RID, float)
-
- BIND2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode)
-
- BIND2(canvas_light_set_shadow_enabled, RID, bool)
- BIND2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter)
- BIND2(canvas_light_set_shadow_color, RID, const Color &)
- BIND2(canvas_light_set_shadow_smooth, RID, float)
-
- BIND0R(RID, canvas_light_occluder_create)
- BIND2(canvas_light_occluder_attach_to_canvas, RID, RID)
- BIND2(canvas_light_occluder_set_enabled, RID, bool)
- BIND2(canvas_light_occluder_set_polygon, RID, RID)
- BIND2(canvas_light_occluder_set_as_sdf_collision, RID, bool)
- BIND2(canvas_light_occluder_set_transform, RID, const Transform2D &)
- BIND2(canvas_light_occluder_set_light_mask, RID, int)
-
- BIND0R(RID, canvas_occluder_polygon_create)
- BIND3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
-
- BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
-
- BIND1(canvas_set_shadow_texture_size, int)
+ FUNCRIDSPLIT(canvas)
+ FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &)
+ FUNC2(canvas_set_modulate, RID, const Color &)
+ FUNC3(canvas_set_parent, RID, RID, float)
+ FUNC1(canvas_set_disable_scale, bool)
+
+ FUNCRIDSPLIT(canvas_texture)
+ FUNC3(canvas_texture_set_channel, RID, CanvasTextureChannel, RID)
+ FUNC3(canvas_texture_set_shading_parameters, RID, const Color &, float)
+
+ FUNC2(canvas_texture_set_texture_filter, RID, CanvasItemTextureFilter)
+ FUNC2(canvas_texture_set_texture_repeat, RID, CanvasItemTextureRepeat)
+
+ FUNCRIDSPLIT(canvas_item)
+ FUNC2(canvas_item_set_parent, RID, RID)
+
+ FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
+ FUNC2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
+
+ FUNC2(canvas_item_set_visible, RID, bool)
+ FUNC2(canvas_item_set_light_mask, RID, int)
+
+ FUNC2(canvas_item_set_update_when_visible, RID, bool)
+
+ FUNC2(canvas_item_set_transform, RID, const Transform2D &)
+ FUNC2(canvas_item_set_clip, RID, bool)
+ FUNC2(canvas_item_set_distance_field_mode, RID, bool)
+ FUNC3(canvas_item_set_custom_rect, RID, bool, const Rect2 &)
+ FUNC2(canvas_item_set_modulate, RID, const Color &)
+ FUNC2(canvas_item_set_self_modulate, RID, const Color &)
+
+ FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
+
+ FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
+ FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
+ FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+ FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
+ FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
+ FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
+ FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
+ FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
+ FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
+ FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
+ FUNC9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int)
+ FUNC5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID)
+ FUNC3(canvas_item_add_multimesh, RID, RID, RID)
+ FUNC3(canvas_item_add_particles, RID, RID, RID)
+ FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
+ FUNC2(canvas_item_add_clip_ignore, RID, bool)
+ FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
+ FUNC2(canvas_item_set_z_index, RID, int)
+ FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool)
+ FUNC3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &)
+ FUNC2(canvas_item_attach_skeleton, RID, RID)
+
+ FUNC1(canvas_item_clear, RID)
+ FUNC2(canvas_item_set_draw_index, RID, int)
+
+ FUNC2(canvas_item_set_material, RID, RID)
+
+ FUNC2(canvas_item_set_use_parent_material, RID, bool)
+
+ FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
+
+ FUNCRIDSPLIT(canvas_light)
+
+ FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
+
+ FUNC2(canvas_light_attach_to_canvas, RID, RID)
+ FUNC2(canvas_light_set_enabled, RID, bool)
+ FUNC2(canvas_light_set_texture_scale, RID, float)
+ FUNC2(canvas_light_set_transform, RID, const Transform2D &)
+ FUNC2(canvas_light_set_texture, RID, RID)
+ FUNC2(canvas_light_set_texture_offset, RID, const Vector2 &)
+ FUNC2(canvas_light_set_color, RID, const Color &)
+ FUNC2(canvas_light_set_height, RID, float)
+ FUNC2(canvas_light_set_energy, RID, float)
+ FUNC3(canvas_light_set_z_range, RID, int, int)
+ FUNC3(canvas_light_set_layer_range, RID, int, int)
+ FUNC2(canvas_light_set_item_cull_mask, RID, int)
+ FUNC2(canvas_light_set_item_shadow_cull_mask, RID, int)
+ FUNC2(canvas_light_set_directional_distance, RID, float)
+
+ FUNC2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode)
+
+ FUNC2(canvas_light_set_shadow_enabled, RID, bool)
+ FUNC2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter)
+ FUNC2(canvas_light_set_shadow_color, RID, const Color &)
+ FUNC2(canvas_light_set_shadow_smooth, RID, float)
+
+ FUNCRIDSPLIT(canvas_light_occluder)
+ FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
+ FUNC2(canvas_light_occluder_set_enabled, RID, bool)
+ FUNC2(canvas_light_occluder_set_polygon, RID, RID)
+ FUNC2(canvas_light_occluder_set_as_sdf_collision, RID, bool)
+ FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
+ FUNC2(canvas_light_occluder_set_light_mask, RID, int)
+
+ FUNCRIDSPLIT(canvas_occluder_polygon)
+ FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
+
+ FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
+
+ FUNC1(canvas_set_shadow_texture_size, int)
/* GLOBAL VARIABLES */
-#undef BINDBASE
+#undef server_name
+#undef ServerName
//from now on, calls forwarded to this singleton
-#define BINDBASE RSG::storage
+#define ServerName RendererStorage
+#define server_name RSG::storage
- BIND3(global_variable_add, const StringName &, GlobalVariableType, const Variant &)
- BIND1(global_variable_remove, const StringName &)
- BIND0RC(Vector<StringName>, global_variable_get_list)
- BIND2(global_variable_set, const StringName &, const Variant &)
- BIND2(global_variable_set_override, const StringName &, const Variant &)
- BIND1RC(GlobalVariableType, global_variable_get_type, const StringName &)
- BIND1RC(Variant, global_variable_get, const StringName &)
+ FUNC3(global_variable_add, const StringName &, GlobalVariableType, const Variant &)
+ FUNC1(global_variable_remove, const StringName &)
+ FUNC0RC(Vector<StringName>, global_variable_get_list)
+ FUNC2(global_variable_set, const StringName &, const Variant &)
+ FUNC2(global_variable_set_override, const StringName &, const Variant &)
+ FUNC1RC(GlobalVariableType, global_variable_get_type, const StringName &)
+ FUNC1RC(Variant, global_variable_get, const StringName &)
- BIND1(global_variables_load_settings, bool)
- BIND0(global_variables_clear)
+ FUNC1(global_variables_load_settings, bool)
+ FUNC0(global_variables_clear)
+
+#undef server_name
+#undef ServerName
+#undef WRITE_ACTION
+#undef SYNC_DEBUG
/* BLACK BARS */
- virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom);
- virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom);
+ virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) override;
+ virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) override;
/* FREE */
- virtual void free(RID p_rid); ///< free RIDs associated with the visual server
+ virtual void free(RID p_rid) override {
+ if (Thread::get_caller_id() == server_thread) {
+ command_queue.flush_if_pending();
+ _free(p_rid);
+ } else {
+ command_queue.push(this, &RenderingServerDefault::_free, p_rid);
+ }
+ }
/* EVENT QUEUING */
- virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata);
+ virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) override;
- virtual void draw(bool p_swap_buffers, double frame_step);
- virtual void sync();
- virtual bool has_changed() const;
- virtual void init();
- virtual void finish();
+ virtual void draw(bool p_swap_buffers, double frame_step) override;
+ virtual void sync() override;
+ virtual bool has_changed() const override;
+ virtual void init() override;
+ virtual void finish() override;
/* STATUS INFORMATION */
- virtual int get_render_info(RenderInfo p_info);
- virtual String get_video_adapter_name() const;
- virtual String get_video_adapter_vendor() const;
+ virtual uint64_t get_render_info(RenderInfo p_info) override;
+ virtual String get_video_adapter_name() const override;
+ virtual String get_video_adapter_vendor() const override;
- virtual void set_frame_profiling_enabled(bool p_enable);
- virtual Vector<FrameProfileArea> get_frame_profile();
- virtual uint64_t get_frame_profile_frame();
+ 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();
+ virtual RID get_test_cube() override;
/* TESTING */
- virtual float get_frame_setup_time_cpu() const;
-
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true);
- virtual void set_default_clear_color(const Color &p_color);
+ virtual float get_frame_setup_time_cpu() const override;
- virtual bool has_feature(Features p_feature) const;
+ virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override;
+ virtual void set_default_clear_color(const Color &p_color) override;
- virtual bool has_os_feature(const String &p_feature) const;
- virtual void set_debug_generate_wireframes(bool p_generate);
+ virtual bool has_feature(Features p_feature) const override;
- virtual void call_set_use_vsync(bool p_enable);
+ virtual bool has_os_feature(const String &p_feature) const override;
+ virtual void set_debug_generate_wireframes(bool p_generate) override;
- virtual bool is_low_end() const;
+ virtual bool is_low_end() const override;
- virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
+ virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
- virtual void set_print_gpu_profile(bool p_enable);
+ virtual void set_print_gpu_profile(bool p_enable) override;
- RenderingServerDefault();
+ RenderingServerDefault(bool p_create_thread = false);
~RenderingServerDefault();
-
-#undef DISPLAY_CHANGED
-
-#undef BIND0R
-#undef BIND1RC
-#undef BIND2RC
-#undef BIND3RC
-#undef BIND4RC
-
-#undef BIND1
-#undef BIND2
-#undef BIND3
-#undef BIND4
-#undef BIND5
-#undef BIND6
-#undef BIND7
-#undef BIND8
-#undef BIND9
-#undef BIND10
};
#endif
diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp
deleted file mode 100644
index 9b8d35e5b3..0000000000
--- a/servers/rendering/rendering_server_wrap_mt.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*************************************************************************/
-/* rendering_server_wrap_mt.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "rendering_server_wrap_mt.h"
-#include "core/config/project_settings.h"
-#include "core/os/os.h"
-#include "servers/display_server.h"
-
-void RenderingServerWrapMT::thread_exit() {
- exit = true;
-}
-
-void RenderingServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) {
- if (!atomic_decrement(&draw_pending)) {
- rendering_server->draw(p_swap_buffers, frame_step);
- }
-}
-
-void RenderingServerWrapMT::thread_flush() {
- atomic_decrement(&draw_pending);
-}
-
-void RenderingServerWrapMT::_thread_callback(void *_instance) {
- RenderingServerWrapMT *vsmt = reinterpret_cast<RenderingServerWrapMT *>(_instance);
-
- vsmt->thread_loop();
-}
-
-void RenderingServerWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- DisplayServer::get_singleton()->make_rendering_thread();
-
- rendering_server->init();
-
- exit = false;
- draw_thread_up = true;
- while (!exit) {
- // flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
- }
-
- command_queue.flush_all(); // flush all
-
- rendering_server->finish();
-}
-
-/* EVENT QUEUING */
-
-void RenderingServerWrapMT::sync() {
- if (create_thread) {
- atomic_increment(&draw_pending);
- command_queue.push_and_sync(this, &RenderingServerWrapMT::thread_flush);
- } else {
- command_queue.flush_all(); //flush all pending from other threads
- }
-}
-
-void RenderingServerWrapMT::draw(bool p_swap_buffers, double frame_step) {
- if (create_thread) {
- atomic_increment(&draw_pending);
- command_queue.push(this, &RenderingServerWrapMT::thread_draw, p_swap_buffers, frame_step);
- } else {
- rendering_server->draw(p_swap_buffers, frame_step);
- }
-}
-
-void RenderingServerWrapMT::init() {
- if (create_thread) {
- print_verbose("RenderingServerWrapMT: Creating render thread");
- DisplayServer::get_singleton()->release_rendering_thread();
- if (create_thread) {
- thread.start(_thread_callback, this);
- print_verbose("RenderingServerWrapMT: Starting render thread");
- }
- while (!draw_thread_up) {
- OS::get_singleton()->delay_usec(1000);
- }
- print_verbose("RenderingServerWrapMT: Finished render thread");
- } else {
- rendering_server->init();
- }
-}
-
-void RenderingServerWrapMT::finish() {
- sky_free_cached_ids();
- shader_free_cached_ids();
- material_free_cached_ids();
- mesh_free_cached_ids();
- multimesh_free_cached_ids();
- immediate_free_cached_ids();
- skeleton_free_cached_ids();
- directional_light_free_cached_ids();
- omni_light_free_cached_ids();
- spot_light_free_cached_ids();
- reflection_probe_free_cached_ids();
- gi_probe_free_cached_ids();
- lightmap_free_cached_ids();
- particles_free_cached_ids();
- particles_collision_free_cached_ids();
- camera_free_cached_ids();
- viewport_free_cached_ids();
- environment_free_cached_ids();
- camera_effects_free_cached_ids();
- scenario_free_cached_ids();
- instance_free_cached_ids();
- canvas_free_cached_ids();
- canvas_item_free_cached_ids();
- canvas_light_occluder_free_cached_ids();
- canvas_occluder_polygon_free_cached_ids();
-
- if (create_thread) {
- command_queue.push(this, &RenderingServerWrapMT::thread_exit);
- thread.wait_to_finish();
- } else {
- rendering_server->finish();
- }
-}
-
-void RenderingServerWrapMT::set_use_vsync_callback(bool p_enable) {
- singleton_mt->call_set_use_vsync(p_enable);
-}
-
-RenderingServerWrapMT *RenderingServerWrapMT::singleton_mt = nullptr;
-
-RenderingServerWrapMT::RenderingServerWrapMT(RenderingServer *p_contained, bool p_create_thread) :
- command_queue(p_create_thread) {
- singleton_mt = this;
- DisplayServer::switch_vsync_function = set_use_vsync_callback; //as this goes to another thread, make sure it goes properly
-
- rendering_server = p_contained;
- create_thread = p_create_thread;
- draw_pending = 0;
- draw_thread_up = false;
- pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc");
-
- if (!p_create_thread) {
- server_thread = Thread::get_caller_id();
- } else {
- server_thread = 0;
- }
-}
-
-RenderingServerWrapMT::~RenderingServerWrapMT() {
- memdelete(rendering_server);
- //finish();
-}
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
deleted file mode 100644
index 81e202780e..0000000000
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ /dev/null
@@ -1,808 +0,0 @@
-/*************************************************************************/
-/* rendering_server_wrap_mt.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef RENDERING_SERVER_WRAP_MT_H
-#define RENDERING_SERVER_WRAP_MT_H
-
-#include "core/os/thread.h"
-#include "core/templates/command_queue_mt.h"
-#include "servers/rendering_server.h"
-
-class RenderingServerWrapMT : public RenderingServer {
- // the real visual server
- mutable RenderingServer *rendering_server;
-
- mutable CommandQueueMT command_queue;
-
- static void _thread_callback(void *_instance);
- void thread_loop();
-
- Thread::ID server_thread;
- volatile bool exit;
- Thread thread;
- volatile bool draw_thread_up;
- bool create_thread;
-
- uint64_t draw_pending;
- void thread_draw(bool p_swap_buffers, double frame_step);
- void thread_flush();
-
- void thread_exit();
-
- Mutex alloc_mutex;
-
- int pool_max_size;
-
- //#define DEBUG_SYNC
-
- static RenderingServerWrapMT *singleton_mt;
-
-#ifdef DEBUG_SYNC
-#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
-#else
-#define SYNC_DEBUG
-#endif
-
-public:
-#define ServerName RenderingServer
-#define ServerNameWrapMT RenderingServerWrapMT
-#define server_name rendering_server
-#include "servers/server_wrap_mt_common.h"
-
- //these go pass-through, as they can be called from any thread
- virtual RID texture_2d_create(const Ref<Image> &p_image) { return rendering_server->texture_2d_create(p_image); }
- virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, TextureLayeredType p_layered_type) { return rendering_server->texture_2d_layered_create(p_layers, p_layered_type); }
- virtual RID texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) { return rendering_server->texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, p_data); }
- virtual RID texture_proxy_create(RID p_base) { return rendering_server->texture_proxy_create(p_base); }
-
- //goes pass-through
- virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) { rendering_server->texture_2d_update_immediate(p_texture, p_image, p_layer); }
- //these go through command queue if they are in another thread
- FUNC3(texture_2d_update, RID, const Ref<Image> &, int)
- FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &)
- FUNC2(texture_proxy_update, RID, RID)
-
- //these also go pass-through
- virtual RID texture_2d_placeholder_create() { return rendering_server->texture_2d_placeholder_create(); }
- virtual RID texture_2d_layered_placeholder_create(TextureLayeredType p_type) { return rendering_server->texture_2d_layered_placeholder_create(p_type); }
- virtual RID texture_3d_placeholder_create() { return rendering_server->texture_3d_placeholder_create(); }
-
- FUNC1RC(Ref<Image>, texture_2d_get, RID)
- FUNC2RC(Ref<Image>, texture_2d_layer_get, RID, int)
- FUNC1RC(Vector<Ref<Image>>, texture_3d_get, RID)
-
- FUNC2(texture_replace, RID, RID)
-
- FUNC3(texture_set_size_override, RID, int, int)
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- FUNC2(texture_bind, RID, uint32_t)
-#endif
-
- FUNC3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *)
- FUNC3(texture_set_detect_normal_callback, RID, TextureDetectCallback, void *)
- FUNC3(texture_set_detect_roughness_callback, RID, TextureDetectRoughnessCallback, void *)
-
- FUNC2(texture_set_path, RID, const String &)
- FUNC1RC(String, texture_get_path, RID)
- FUNC1S(texture_debug_usage, List<TextureInfo> *)
-
- FUNC2(texture_set_force_redraw_if_visible, RID, bool)
-
- /* SHADER API */
-
- FUNCRID(shader)
-
- FUNC2(shader_set_code, RID, const String &)
- FUNC1RC(String, shader_get_code, RID)
-
- FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
-
- FUNC3(shader_set_default_texture_param, RID, const StringName &, RID)
- FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &)
- FUNC2RC(Variant, shader_get_param_default, RID, const StringName &)
-
- FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID)
-
- /* COMMON MATERIAL API */
-
- FUNCRID(material)
-
- FUNC2(material_set_shader, RID, RID)
-
- FUNC3(material_set_param, RID, const StringName &, const Variant &)
- FUNC2RC(Variant, material_get_param, RID, const StringName &)
-
- FUNC2(material_set_render_priority, RID, int)
- FUNC2(material_set_next_pass, RID, RID)
-
- /* MESH API */
-
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) {
- return rendering_server->mesh_create_from_surfaces(p_surfaces, p_blend_shape_count);
- }
-
- FUNC2(mesh_set_blend_shape_count, RID, int)
-
- FUNCRID(mesh)
-
- FUNC2(mesh_add_surface, RID, const SurfaceData &)
-
- FUNC1RC(int, mesh_get_blend_shape_count, RID)
-
- FUNC2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
- FUNC1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
-
- FUNC4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &)
-
- FUNC3(mesh_surface_set_material, RID, int, RID)
- FUNC2RC(RID, mesh_surface_get_material, RID, int)
-
- FUNC2RC(SurfaceData, mesh_get_surface, RID, int)
-
- FUNC1RC(int, mesh_get_surface_count, RID)
-
- FUNC2(mesh_set_custom_aabb, RID, const AABB &)
- FUNC1RC(AABB, mesh_get_custom_aabb, RID)
-
- FUNC2(mesh_set_shadow_mesh, RID, RID)
- FUNC1(mesh_clear, RID)
-
- /* MULTIMESH API */
-
- FUNCRID(multimesh)
-
- FUNC5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool)
- FUNC1RC(int, multimesh_get_instance_count, RID)
-
- FUNC2(multimesh_set_mesh, RID, RID)
- FUNC3(multimesh_instance_set_transform, RID, int, const Transform &)
- FUNC3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &)
- FUNC3(multimesh_instance_set_color, RID, int, const Color &)
- FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &)
-
- FUNC1RC(RID, multimesh_get_mesh, RID)
- FUNC1RC(AABB, multimesh_get_aabb, RID)
-
- FUNC2RC(Transform, multimesh_instance_get_transform, RID, int)
- FUNC2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int)
- FUNC2RC(Color, multimesh_instance_get_color, RID, int)
- FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)
-
- FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
- FUNC1RC(Vector<float>, multimesh_get_buffer, RID)
-
- FUNC2(multimesh_set_visible_instances, RID, int)
- FUNC1RC(int, multimesh_get_visible_instances, RID)
-
- /* IMMEDIATE API */
-
- FUNCRID(immediate)
- FUNC3(immediate_begin, RID, PrimitiveType, RID)
- FUNC2(immediate_vertex, RID, const Vector3 &)
- FUNC2(immediate_normal, RID, const Vector3 &)
- FUNC2(immediate_tangent, RID, const Plane &)
- FUNC2(immediate_color, RID, const Color &)
- FUNC2(immediate_uv, RID, const Vector2 &)
- FUNC2(immediate_uv2, RID, const Vector2 &)
- FUNC1(immediate_end, RID)
- FUNC1(immediate_clear, RID)
- FUNC2(immediate_set_material, RID, RID)
- FUNC1RC(RID, immediate_get_material, RID)
-
- /* SKELETON API */
-
- FUNCRID(skeleton)
- FUNC3(skeleton_allocate, RID, int, bool)
- FUNC1RC(int, skeleton_get_bone_count, RID)
- FUNC3(skeleton_bone_set_transform, RID, int, const Transform &)
- FUNC2RC(Transform, skeleton_bone_get_transform, RID, int)
- FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &)
- FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int)
- FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &)
-
- /* Light API */
-
- FUNCRID(directional_light)
- FUNCRID(omni_light)
- FUNCRID(spot_light)
-
- FUNC2(light_set_color, RID, const Color &)
- FUNC3(light_set_param, RID, LightParam, float)
- FUNC2(light_set_shadow, RID, bool)
- FUNC2(light_set_shadow_color, RID, const Color &)
- FUNC2(light_set_projector, RID, RID)
- FUNC2(light_set_negative, RID, bool)
- FUNC2(light_set_cull_mask, RID, uint32_t)
- FUNC2(light_set_reverse_cull_face_mode, RID, bool)
- FUNC2(light_set_bake_mode, RID, LightBakeMode)
- FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t)
-
- FUNC2(light_omni_set_shadow_mode, RID, LightOmniShadowMode)
-
- FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
- FUNC2(light_directional_set_blend_splits, RID, bool)
- FUNC2(light_directional_set_sky_only, RID, bool)
- FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
-
- /* PROBE API */
-
- FUNCRID(reflection_probe)
-
- FUNC2(reflection_probe_set_update_mode, RID, ReflectionProbeUpdateMode)
- FUNC2(reflection_probe_set_intensity, RID, float)
- FUNC2(reflection_probe_set_ambient_color, RID, const Color &)
- FUNC2(reflection_probe_set_ambient_energy, RID, float)
- FUNC2(reflection_probe_set_ambient_mode, RID, ReflectionProbeAmbientMode)
- FUNC2(reflection_probe_set_max_distance, RID, float)
- FUNC2(reflection_probe_set_extents, RID, const Vector3 &)
- FUNC2(reflection_probe_set_origin_offset, RID, const Vector3 &)
- FUNC2(reflection_probe_set_as_interior, RID, bool)
- FUNC2(reflection_probe_set_enable_box_projection, RID, bool)
- FUNC2(reflection_probe_set_enable_shadows, RID, bool)
- FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
- FUNC2(reflection_probe_set_resolution, RID, int)
- FUNC2(reflection_probe_set_lod_threshold, RID, float)
-
- /* DECAL API */
-
- FUNCRID(decal)
-
- FUNC2(decal_set_extents, RID, const Vector3 &)
- FUNC3(decal_set_texture, RID, DecalTexture, RID)
- FUNC2(decal_set_emission_energy, RID, float)
- FUNC2(decal_set_albedo_mix, RID, float)
- FUNC2(decal_set_modulate, RID, const Color &)
- FUNC2(decal_set_cull_mask, RID, uint32_t)
- FUNC4(decal_set_distance_fade, RID, bool, float, float)
- FUNC3(decal_set_fade, RID, float, float)
- FUNC2(decal_set_normal_fade, RID, float)
-
- /* BAKED LIGHT API */
-
- FUNCRID(gi_probe)
-
- FUNC8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
-
- FUNC1RC(AABB, gi_probe_get_bounds, RID)
- FUNC1RC(Vector3i, gi_probe_get_octree_size, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID)
- FUNC1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID)
- FUNC1RC(Vector<int>, gi_probe_get_level_counts, RID)
- FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID)
-
- FUNC2(gi_probe_set_dynamic_range, RID, float)
- FUNC1RC(float, gi_probe_get_dynamic_range, RID)
-
- FUNC2(gi_probe_set_propagation, RID, float)
- FUNC1RC(float, gi_probe_get_propagation, RID)
-
- FUNC2(gi_probe_set_energy, RID, float)
- FUNC1RC(float, gi_probe_get_energy, RID)
-
- FUNC2(gi_probe_set_ao, RID, float)
- FUNC1RC(float, gi_probe_get_ao, RID)
-
- FUNC2(gi_probe_set_ao_size, RID, float)
- FUNC1RC(float, gi_probe_get_ao_size, RID)
-
- FUNC2(gi_probe_set_bias, RID, float)
- FUNC1RC(float, gi_probe_get_bias, RID)
-
- FUNC2(gi_probe_set_normal_bias, RID, float)
- FUNC1RC(float, gi_probe_get_normal_bias, RID)
-
- FUNC2(gi_probe_set_interior, RID, bool)
- FUNC1RC(bool, gi_probe_is_interior, RID)
-
- FUNC2(gi_probe_set_use_two_bounces, RID, bool)
- FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
-
- FUNC2(gi_probe_set_anisotropy_strength, RID, float)
- FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
-
- FUNC1(gi_probe_set_quality, GIProbeQuality)
-
- /* LIGHTMAP CAPTURE */
-
- FUNCRID(lightmap)
- FUNC3(lightmap_set_textures, RID, RID, bool)
- FUNC2(lightmap_set_probe_bounds, RID, const AABB &)
- FUNC2(lightmap_set_probe_interior, RID, bool)
- FUNC5(lightmap_set_probe_capture_data, RID, const PackedVector3Array &, const PackedColorArray &, const PackedInt32Array &, const PackedInt32Array &)
- FUNC1RC(PackedVector3Array, lightmap_get_probe_capture_points, RID)
- FUNC1RC(PackedColorArray, lightmap_get_probe_capture_sh, RID)
- FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_tetrahedra, RID)
- FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
-
- FUNC1(lightmap_set_probe_capture_update_speed, float)
-
- /* PARTICLES */
-
- FUNCRID(particles)
-
- FUNC2(particles_set_emitting, RID, bool)
- FUNC1R(bool, particles_get_emitting, RID)
- FUNC2(particles_set_amount, RID, int)
- FUNC2(particles_set_lifetime, RID, float)
- FUNC2(particles_set_one_shot, RID, bool)
- FUNC2(particles_set_pre_process_time, RID, float)
- FUNC2(particles_set_explosiveness_ratio, RID, float)
- FUNC2(particles_set_randomness_ratio, RID, float)
- FUNC2(particles_set_custom_aabb, RID, const AABB &)
- FUNC2(particles_set_speed_scale, RID, float)
- FUNC2(particles_set_use_local_coordinates, RID, bool)
- FUNC2(particles_set_process_material, RID, RID)
- FUNC2(particles_set_fixed_fps, RID, int)
- FUNC2(particles_set_fractional_delta, RID, bool)
- FUNC2(particles_set_collision_base_size, RID, float)
-
- FUNC1R(bool, particles_is_inactive, RID)
- FUNC1(particles_request_process, RID)
- FUNC1(particles_restart, RID)
-
- FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
-
- FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
-
- FUNC2(particles_set_draw_passes, RID, int)
- FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
- FUNC2(particles_set_emission_transform, RID, const Transform &)
- FUNC2(particles_set_subemitter, RID, RID)
-
- FUNC1R(AABB, particles_get_current_aabb, RID)
-
- /* PARTICLES COLLISION */
-
- FUNCRID(particles_collision)
-
- FUNC2(particles_collision_set_collision_type, RID, ParticlesCollisionType)
- FUNC2(particles_collision_set_cull_mask, RID, uint32_t)
- FUNC2(particles_collision_set_sphere_radius, RID, float)
- FUNC2(particles_collision_set_box_extents, RID, const Vector3 &)
- FUNC2(particles_collision_set_attractor_strength, RID, float)
- FUNC2(particles_collision_set_attractor_directionality, RID, float)
- FUNC2(particles_collision_set_attractor_attenuation, RID, float)
- FUNC2(particles_collision_set_field_texture, RID, RID)
- FUNC1(particles_collision_height_field_update, RID)
- FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
-
- /* CAMERA API */
-
- FUNCRID(camera)
- FUNC4(camera_set_perspective, RID, float, float, float)
- FUNC4(camera_set_orthogonal, RID, float, float, float)
- FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
- FUNC2(camera_set_transform, RID, const Transform &)
- FUNC2(camera_set_cull_mask, RID, uint32_t)
- FUNC2(camera_set_environment, RID, RID)
- FUNC2(camera_set_camera_effects, RID, RID)
- FUNC2(camera_set_use_vertical_aspect, RID, bool)
-
- /* VIEWPORT TARGET API */
-
- FUNCRID(viewport)
-
- FUNC2(viewport_set_use_xr, RID, bool)
-
- FUNC3(viewport_set_size, RID, int, int)
-
- FUNC2(viewport_set_active, RID, bool)
- FUNC2(viewport_set_parent_viewport, RID, RID)
-
- FUNC2(viewport_set_clear_mode, RID, ViewportClearMode)
-
- FUNC3(viewport_attach_to_screen, RID, const Rect2 &, DisplayServer::WindowID)
- FUNC2(viewport_set_render_direct_to_screen, RID, bool)
-
- FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode)
-
- FUNC1RC(RID, viewport_get_texture, RID)
-
- FUNC2(viewport_set_hide_scenario, RID, bool)
- FUNC2(viewport_set_hide_canvas, RID, bool)
- FUNC2(viewport_set_disable_environment, RID, bool)
-
- FUNC2(viewport_attach_camera, RID, RID)
- FUNC2(viewport_set_scenario, RID, RID)
- FUNC2(viewport_attach_canvas, RID, RID)
-
- FUNC2(viewport_remove_canvas, RID, RID)
- FUNC3(viewport_set_canvas_transform, RID, RID, const Transform2D &)
- FUNC2(viewport_set_transparent_background, RID, bool)
- FUNC2(viewport_set_snap_2d_transforms_to_pixel, RID, bool)
- FUNC2(viewport_set_snap_2d_vertices_to_pixel, RID, bool)
-
- FUNC2(viewport_set_default_canvas_item_texture_filter, RID, CanvasItemTextureFilter)
- FUNC2(viewport_set_default_canvas_item_texture_repeat, RID, CanvasItemTextureRepeat)
-
- FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &)
- FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
- FUNC3(viewport_set_shadow_atlas_size, RID, int, bool)
- FUNC3(viewport_set_sdf_oversize_and_scale, RID, ViewportSDFOversize, ViewportSDFScale)
-
- FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
- FUNC2(viewport_set_msaa, RID, ViewportMSAA)
- FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
- FUNC2(viewport_set_use_debanding, RID, bool)
-
- FUNC2(viewport_set_lod_threshold, RID, float)
-
- //this passes directly to avoid stalling, but it's pretty dangerous, so don't call after freeing a viewport
- virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) {
- return rendering_server->viewport_get_render_info(p_viewport, p_info);
- }
-
- FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw)
-
- FUNC2(viewport_set_measure_render_time, RID, bool)
- virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const {
- return rendering_server->viewport_get_measured_render_time_cpu(p_viewport);
- }
- virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const {
- return rendering_server->viewport_get_measured_render_time_gpu(p_viewport);
- }
-
- FUNC2(directional_shadow_atlas_set_size, int, bool)
-
- /* SKY API */
-
- FUNCRID(sky)
- FUNC2(sky_set_radiance_size, RID, int)
- FUNC2(sky_set_mode, RID, SkyMode)
- FUNC2(sky_set_material, RID, RID)
- FUNC4R(Ref<Image>, sky_bake_panorama, RID, float, bool, const Size2i &)
-
- /* ENVIRONMENT API */
-
- FUNCRID(environment)
-
- FUNC2(environment_set_background, RID, EnvironmentBG)
- FUNC2(environment_set_sky, RID, RID)
- FUNC2(environment_set_sky_custom_fov, RID, float)
- FUNC2(environment_set_sky_orientation, RID, const Basis &)
- FUNC2(environment_set_bg_color, RID, const Color &)
- FUNC2(environment_set_bg_energy, RID, float)
- FUNC2(environment_set_canvas_max_layer, RID, int)
- FUNC7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &)
-
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- FUNC2(environment_set_camera_feed_id, RID, int)
-#endif
- FUNC6(environment_set_ssr, RID, bool, int, float, float, float)
- FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality)
-
- FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float)
-
- FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float)
-
- FUNC11(environment_set_sdfgi, RID, bool, EnvironmentSDFGICascades, float, EnvironmentSDFGIYScale, bool, bool, bool, float, float, float)
- FUNC1(environment_set_sdfgi_ray_count, EnvironmentSDFGIRayCount)
- FUNC1(environment_set_sdfgi_frames_to_converge, EnvironmentSDFGIFramesToConverge)
- FUNC1(environment_set_sdfgi_frames_to_update_light, EnvironmentSDFGIFramesToUpdateLight)
-
- FUNC11(environment_set_glow, RID, bool, Vector<float>, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
- FUNC1(environment_glow_set_use_bicubic_upscale, bool)
- FUNC1(environment_glow_set_use_high_quality, bool)
-
- FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
-
- FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID)
-
- FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
-
- FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float)
-
- FUNC2(environment_set_volumetric_fog_volume_size, int, int)
- FUNC1(environment_set_volumetric_fog_filter_active, bool)
-
- FUNC3R(Ref<Image>, environment_bake_panorama, RID, bool, const Size2i &)
-
- FUNC3(screen_space_roughness_limiter_set_active, bool, float, float)
- FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
- FUNC2(sub_surface_scattering_set_scale, float, float)
-
- FUNCRID(camera_effects)
-
- FUNC2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
- FUNC1(camera_effects_set_dof_blur_bokeh_shape, DOFBokehShape)
-
- FUNC8(camera_effects_set_dof_blur, RID, bool, float, float, bool, float, float, float)
- FUNC3(camera_effects_set_custom_exposure, RID, bool, float)
-
- FUNC1(shadows_quality_set, ShadowQuality);
- FUNC1(directional_shadow_quality_set, ShadowQuality);
-
- FUNCRID(scenario)
-
- FUNC2(scenario_set_debug, RID, ScenarioDebugMode)
- FUNC2(scenario_set_environment, RID, RID)
- FUNC2(scenario_set_camera_effects, RID, RID)
- FUNC2(scenario_set_fallback_environment, RID, RID)
-
- /* INSTANCING API */
- FUNCRID(instance)
-
- FUNC2(instance_set_base, RID, RID)
- FUNC2(instance_set_scenario, RID, RID)
- FUNC2(instance_set_layer_mask, RID, uint32_t)
- FUNC2(instance_set_transform, RID, const Transform &)
- FUNC2(instance_attach_object_instance_id, RID, ObjectID)
- FUNC3(instance_set_blend_shape_weight, RID, int, float)
- FUNC3(instance_set_surface_material, RID, int, RID)
- FUNC2(instance_set_visible, RID, bool)
-
- FUNC2(instance_set_custom_aabb, RID, AABB)
-
- FUNC2(instance_attach_skeleton, RID, RID)
- FUNC2(instance_set_exterior, RID, bool)
-
- FUNC2(instance_set_extra_visibility_margin, RID, real_t)
-
- // don't use these in a game!
- FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
- FUNC3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID)
- FUNC2RC(Vector<ObjectID>, instances_cull_convex, const Vector<Plane> &, RID)
-
- FUNC3(instance_geometry_set_flag, RID, InstanceFlags, bool)
- FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting)
- FUNC2(instance_geometry_set_material_override, RID, RID)
-
- FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
- FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
- FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
- FUNC2(instance_geometry_set_lod_bias, RID, float)
-
- FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
- FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
- FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &)
- FUNC2SC(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *)
-
- /* BAKE */
-
- FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &)
-
- /* CANVAS (2D) */
-
- FUNCRID(canvas)
- FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &)
- FUNC2(canvas_set_modulate, RID, const Color &)
- FUNC3(canvas_set_parent, RID, RID, float)
- FUNC1(canvas_set_disable_scale, bool)
-
- FUNCRID(canvas_texture)
- FUNC3(canvas_texture_set_channel, RID, CanvasTextureChannel, RID)
- FUNC3(canvas_texture_set_shading_parameters, RID, const Color &, float)
-
- FUNC2(canvas_texture_set_texture_filter, RID, CanvasItemTextureFilter)
- FUNC2(canvas_texture_set_texture_repeat, RID, CanvasItemTextureRepeat)
-
- FUNCRID(canvas_item)
- FUNC2(canvas_item_set_parent, RID, RID)
-
- FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
- FUNC2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
-
- FUNC2(canvas_item_set_visible, RID, bool)
- FUNC2(canvas_item_set_light_mask, RID, int)
-
- FUNC2(canvas_item_set_update_when_visible, RID, bool)
-
- FUNC2(canvas_item_set_transform, RID, const Transform2D &)
- FUNC2(canvas_item_set_clip, RID, bool)
- FUNC2(canvas_item_set_distance_field_mode, RID, bool)
- FUNC3(canvas_item_set_custom_rect, RID, bool, const Rect2 &)
- FUNC2(canvas_item_set_modulate, RID, const Color &)
- FUNC2(canvas_item_set_self_modulate, RID, const Color &)
-
- FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
-
- FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
- FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
- FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
- FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)
- FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
- FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
- FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
- FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
- FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
- FUNC9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int)
- FUNC5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID)
- FUNC3(canvas_item_add_multimesh, RID, RID, RID)
- FUNC3(canvas_item_add_particles, RID, RID, RID)
- FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
- FUNC2(canvas_item_add_clip_ignore, RID, bool)
- FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
- FUNC2(canvas_item_set_z_index, RID, int)
- FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool)
- FUNC3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &)
- FUNC2(canvas_item_attach_skeleton, RID, RID)
-
- FUNC1(canvas_item_clear, RID)
- FUNC2(canvas_item_set_draw_index, RID, int)
-
- FUNC2(canvas_item_set_material, RID, RID)
-
- FUNC2(canvas_item_set_use_parent_material, RID, bool)
-
- FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
-
- FUNC0R(RID, canvas_light_create)
-
- FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
-
- FUNC2(canvas_light_attach_to_canvas, RID, RID)
- FUNC2(canvas_light_set_enabled, RID, bool)
- FUNC2(canvas_light_set_texture_scale, RID, float)
- FUNC2(canvas_light_set_transform, RID, const Transform2D &)
- FUNC2(canvas_light_set_texture, RID, RID)
- FUNC2(canvas_light_set_texture_offset, RID, const Vector2 &)
- FUNC2(canvas_light_set_color, RID, const Color &)
- FUNC2(canvas_light_set_height, RID, float)
- FUNC2(canvas_light_set_energy, RID, float)
- FUNC3(canvas_light_set_z_range, RID, int, int)
- FUNC3(canvas_light_set_layer_range, RID, int, int)
- FUNC2(canvas_light_set_item_cull_mask, RID, int)
- FUNC2(canvas_light_set_item_shadow_cull_mask, RID, int)
- FUNC2(canvas_light_set_directional_distance, RID, float)
-
- FUNC2(canvas_light_set_blend_mode, RID, CanvasLightBlendMode)
-
- FUNC2(canvas_light_set_shadow_enabled, RID, bool)
- FUNC2(canvas_light_set_shadow_filter, RID, CanvasLightShadowFilter)
- FUNC2(canvas_light_set_shadow_color, RID, const Color &)
- FUNC2(canvas_light_set_shadow_smooth, RID, float)
-
- FUNCRID(canvas_light_occluder)
- FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
- FUNC2(canvas_light_occluder_set_enabled, RID, bool)
- FUNC2(canvas_light_occluder_set_polygon, RID, RID)
- FUNC2(canvas_light_occluder_set_as_sdf_collision, RID, bool)
- FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
- FUNC2(canvas_light_occluder_set_light_mask, RID, int)
-
- FUNCRID(canvas_occluder_polygon)
- FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
-
- FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
-
- FUNC1(canvas_set_shadow_texture_size, int)
-
- /* GLOBAL VARIABLES */
-
- FUNC3(global_variable_add, const StringName &, GlobalVariableType, const Variant &)
- FUNC1(global_variable_remove, const StringName &)
- FUNC0RC(Vector<StringName>, global_variable_get_list)
- FUNC2(global_variable_set, const StringName &, const Variant &)
- FUNC2(global_variable_set_override, const StringName &, const Variant &)
- FUNC1RC(GlobalVariableType, global_variable_get_type, const StringName &)
- FUNC1RC(Variant, global_variable_get, const StringName &)
- FUNC1(global_variables_load_settings, bool)
- FUNC0(global_variables_clear)
-
- /* BLACK BARS */
-
- FUNC4(black_bars_set_margins, int, int, int, int)
- FUNC4(black_bars_set_images, RID, RID, RID, RID)
-
- /* FREE */
-
- FUNC1(free, RID)
-
- /* EVENT QUEUING */
-
- FUNC3(request_frame_drawn_callback, Object *, const StringName &, const Variant &)
-
- virtual void init();
- virtual void finish();
- virtual void draw(bool p_swap_buffers, double frame_step);
- virtual void sync();
- FUNC0RC(bool, has_changed)
-
- /* RENDER INFO */
-
- //this passes directly to avoid stalling
- virtual int get_render_info(RenderInfo p_info) {
- return rendering_server->get_render_info(p_info);
- }
-
- virtual String get_video_adapter_name() const {
- return rendering_server->get_video_adapter_name();
- }
-
- virtual String get_video_adapter_vendor() const {
- return rendering_server->get_video_adapter_vendor();
- }
-
- FUNC1(gi_set_use_half_resolution, bool)
-
- FUNC4(set_boot_image, const Ref<Image> &, const Color &, bool, bool)
- FUNC1(set_default_clear_color, const Color &)
-
- FUNC0R(RID, get_test_cube)
-
- FUNC1(set_debug_generate_wireframes, bool)
-
- virtual bool has_feature(Features p_feature) const {
- return rendering_server->has_feature(p_feature);
- }
- virtual bool has_os_feature(const String &p_feature) const {
- return rendering_server->has_os_feature(p_feature);
- }
-
- FUNC1(call_set_use_vsync, bool)
-
- static void set_use_vsync_callback(bool p_enable);
-
- virtual bool is_low_end() const {
- return rendering_server->is_low_end();
- }
-
- virtual uint64_t get_frame_profile_frame() {
- return rendering_server->get_frame_profile_frame();
- }
-
- virtual void set_frame_profiling_enabled(bool p_enabled) {
- rendering_server->set_frame_profiling_enabled(p_enabled);
- }
-
- virtual Vector<FrameProfileArea> get_frame_profile() {
- return rendering_server->get_frame_profile();
- }
-
- virtual float get_frame_setup_time_cpu() const {
- return rendering_server->get_frame_setup_time_cpu();
- }
-
- virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) {
- rendering_server->sdfgi_set_debug_probe_select(p_position, p_dir);
- }
-
- virtual void set_print_gpu_profile(bool p_enable) {
- rendering_server->set_print_gpu_profile(p_enable);
- }
-
- RenderingServerWrapMT(RenderingServer *p_contained, bool p_create_thread);
- ~RenderingServerWrapMT();
-
-#undef ServerName
-#undef ServerNameWrapMT
-#undef server_name
-};
-
-#ifdef DEBUG_SYNC
-#undef DEBUG_SYNC
-#endif
-#undef SYNC_DEBUG
-
-#endif
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e6415c0258..0d6d3f5e13 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -558,13 +558,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
hexa_found = true;
- } else if (GETCHAR(i) == 'e') {
- if (hexa_found || exponent_found || float_suffix_found) {
+ } else if (GETCHAR(i) == 'e' && !hexa_found) {
+ if (exponent_found || float_suffix_found) {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
exponent_found = true;
- } else if (GETCHAR(i) == 'f') {
- if (hexa_found || exponent_found) {
+ } else if (GETCHAR(i) == 'f' && !hexa_found) {
+ if (exponent_found) {
return _make_token(TK_ERROR, "Invalid numeric constant");
}
float_suffix_found = true;
@@ -3102,6 +3102,102 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
return false;
}
+bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) {
+ if (current_function == String("light")) {
+ *r_message = RTR("Varying may not be assigned in the 'light' function.");
+ return false;
+ }
+ switch (p_varying.stage) {
+ case ShaderNode::Varying::STAGE_UNKNOWN: // first assign
+ if (current_function == varying_function_names.vertex) {
+ p_varying.stage = ShaderNode::Varying::STAGE_VERTEX;
+ } else if (current_function == varying_function_names.fragment) {
+ p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_VERTEX:
+ if (current_function == varying_function_names.fragment) {
+ *r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'.");
+ return false;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_FRAGMENT:
+ if (current_function == varying_function_names.vertex) {
+ *r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'.");
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) {
+ switch (p_varying.stage) {
+ case ShaderNode::Varying::STAGE_UNKNOWN:
+ *r_message = RTR("Varying must be assigned before using!");
+ return false;
+ case ShaderNode::Varying::STAGE_VERTEX:
+ if (current_function == varying_function_names.fragment) {
+ p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT;
+ } else if (current_function == varying_function_names.light) {
+ p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_FRAGMENT:
+ if (current_function == varying_function_names.light) {
+ p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT:
+ if (current_function == varying_function_names.light) {
+ *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
+ return false;
+ }
+ break;
+ case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT:
+ if (current_function == varying_function_names.fragment) {
+ *r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
+ switch (p_node->type) {
+ case Node::TYPE_OPERATOR: {
+ OperatorNode *op_node = (OperatorNode *)p_node;
+ for (int i = (1 ? op_node->op == OP_CALL : 0); i < op_node->arguments.size(); i++) {
+ if (!_check_node_constness(op_node->arguments[i])) {
+ return false;
+ }
+ }
+ } break;
+ case Node::TYPE_CONSTANT:
+ break;
+ case Node::TYPE_VARIABLE: {
+ VariableNode *varn = (VariableNode *)p_node;
+ if (!varn->is_const) {
+ return false;
+ }
+ } break;
+ case Node::TYPE_ARRAY: {
+ ArrayNode *arrn = (ArrayNode *)p_node;
+ if (!arrn->is_const) {
+ return false;
+ }
+ } break;
+ default:
+ return false;
+ }
+ return true;
+}
+
bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
@@ -3142,13 +3238,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi
return false;
}
- if (shader->varyings.has(var->name) && current_function != String("vertex")) {
- if (r_message) {
- *r_message = RTR("Varyings can only be assigned in vertex function.");
- }
- return false;
- }
-
if (shader->constants.has(var->name) || var->is_const) {
if (r_message) {
*r_message = RTR("Constants cannot be modified.");
@@ -3169,13 +3258,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_functi
return false;
}
- if (shader->varyings.has(arr->name) && current_function != String("vertex")) {
- if (r_message) {
- *r_message = RTR("Varyings can only be assigned in vertex function.");
- }
- return false;
- }
-
return true;
}
@@ -3761,6 +3843,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Unknown identifier in expression: " + String(identifier));
return nullptr;
}
+ if (ident_type == IDENTIFIER_VARYING) {
+ TkPos prev_pos = _get_tkpos();
+ Token next_token = _get_token();
+ _set_tkpos(prev_pos);
+ String error;
+ if (next_token.type == TK_OP_ASSIGN) {
+ if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
+ _set_error(error);
+ return nullptr;
+ }
+ } else {
+ if (!_validate_varying_using(shader->varyings[identifier], &error)) {
+ _set_error(error);
+ return nullptr;
+ }
+ }
+ }
last_const = is_const;
if (ident_type == IDENTIFIER_FUNCTION) {
@@ -3786,10 +3885,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Constants cannot be modified.");
return nullptr;
}
- if (shader->varyings.has(identifier) && current_function != String("vertex")) {
- _set_error("Varyings can only be assigned in vertex function.");
- return nullptr;
- }
assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size);
if (!assign_expression) {
return nullptr;
@@ -3891,8 +3986,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_COND_V(!expr, nullptr);
/* OK now see what's NEXT to the operator.. */
- /* OK now see what's NEXT to the operator.. */
- /* OK now see what's NEXT to the operator.. */
while (true) {
TkPos pos2 = _get_tkpos();
@@ -4670,7 +4763,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_COND_V(next_op == -1, nullptr);
// OK! create operator..
- // OK! create operator..
if (is_unary) {
int expr_pos = next_op;
while (expression[expr_pos].is_op) {
@@ -5322,8 +5414,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression after '='");
- return ERR_PARSE_ERROR;
+ OperatorNode *op = ((OperatorNode *)n);
+ for (int i = 1; i < op->arguments.size(); i++) {
+ if (!_check_node_constness(op->arguments[i])) {
+ _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ return ERR_PARSE_ERROR;
+ }
+ }
}
decl.initializer = n;
@@ -5782,7 +5879,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
//check return type
BlockNode *b = p_block;
- if (b && b->parent_function && (b->parent_function->name == "vertex" || b->parent_function->name == "fragment" || b->parent_function->name == "light")) {
+ if (b && b->parent_function && p_function_info.main_function) {
_set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
return ERR_PARSE_ERROR;
}
@@ -5796,6 +5893,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_BUG;
}
+ String return_struct_name = String(b->parent_function->return_struct_name);
+
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
flow->flow_op = FLOW_OP_RETURN;
@@ -5804,7 +5903,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
} else {
@@ -5814,8 +5913,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- if (b->parent_function->return_type != expr->get_datatype()) {
- _set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) {
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
@@ -5859,15 +5958,15 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- //all is good
_set_error("Expected ';' after discard");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
} else if (tk.type == TK_CF_BREAK) {
if (!p_can_break) {
- //all is good
- _set_error("Breaking is not allowed here");
+ _set_error("'break' is not allowed outside of a loop or 'switch' statement");
+ return ERR_PARSE_ERROR;
}
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@@ -5876,8 +5975,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
- //all is good
_set_error("Expected ';' after break");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
@@ -5892,8 +5991,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
} else if (tk.type == TK_CF_CONTINUE) {
if (!p_can_continue) {
- //all is good
- _set_error("Continuing is not allowed here");
+ _set_error("'continue' is not allowed outside of a loop");
+ return ERR_PARSE_ERROR;
}
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@@ -5904,6 +6003,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type != TK_SEMICOLON) {
//all is good
_set_error("Expected ';' after continue");
+ return ERR_PARSE_ERROR;
}
p_block->statements.push_back(flow);
@@ -6068,6 +6168,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
st.name = tk.text;
+ if (shader->structs.has(st.name)) {
+ _set_error("Redefinition of '" + String(st.name) + "'");
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
_set_error("Expected '{'");
@@ -6260,6 +6364,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
+ TkPos name_pos = _get_tkpos();
name = tk.text;
if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
@@ -6541,11 +6646,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
- } else {
+ } else { // varying
ShaderNode::Varying varying;
varying.type = type;
varying.precision = precision;
varying.interpolation = interpolation;
+ varying.tkpos = name_pos;
tk = _get_token();
if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
@@ -6751,7 +6857,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
+ Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -6832,7 +6938,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
+ Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -6858,10 +6964,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
decl.initializer.push_back(n);
break;
} else {
- if (curly)
+ if (curly) {
_set_error("Expected '}' or ','");
- else
+ } else {
_set_error("Expected ')' or ','");
+ }
return ERR_PARSE_ERROR;
}
}
@@ -6887,12 +6994,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
} else {
//variable created with assignment! must parse an expression
- Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo());
- if (!expr)
+ Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
+ if (!expr) {
return ERR_PARSE_ERROR;
+ }
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
- _set_error("Expected constant expression after '='");
- return ERR_PARSE_ERROR;
+ OperatorNode *op = ((OperatorNode *)expr);
+ for (int i = 1; i < op->arguments.size(); i++) {
+ if (!_check_node_constness(op->arguments[i])) {
+ _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ return ERR_PARSE_ERROR;
+ }
+ }
}
constant.initializer = static_cast<ConstantNode *>(expr);
@@ -7158,30 +7271,24 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
}
+ for (Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) {
+ if (E->get().stage == ShaderNode::Varying::STAGE_VERTEX || E->get().stage == ShaderNode::Varying::STAGE_FRAGMENT) {
+ _set_tkpos(E->get().tkpos);
+ _set_error(RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"));
+ return ERR_PARSE_ERROR;
+ }
+ }
+
return OK;
}
bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) {
- if (p_functions.has("vertex")) {
- if (p_functions["vertex"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("fragment")) {
- if (p_functions["fragment"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("light")) {
- if (p_functions["light"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("compute")) {
- if (p_functions["compute"].built_ins.has(p_name)) {
+ for (Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
+ if (E->get().built_ins.has(p_name)) {
return true;
}
}
+
return false;
}
@@ -7315,11 +7422,12 @@ String ShaderLanguage::get_shader_type(const String &p_code) {
return String();
}
-Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
+Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
clear();
code = p_code;
global_var_get_type_func = p_global_variable_type_func;
+ varying_function_names = p_varying_function_names;
nodes = nullptr;
@@ -7332,10 +7440,11 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi
return OK;
}
-Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
+Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
clear();
code = p_code;
+ varying_function_names = p_varying_function_names;
nodes = nullptr;
global_var_get_type_func = p_global_variable_type_func;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 27767378f9..470f3d38d5 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -41,6 +41,11 @@
class ShaderLanguage {
public:
+ struct TkPos {
+ int char_idx;
+ int tk_line;
+ };
+
enum TokenType {
TK_EMPTY,
TK_IDENTIFIER,
@@ -326,6 +331,17 @@ public:
MAX_INSTANCE_UNIFORM_INDICES = 16
};
+ struct VaryingFunctionNames {
+ StringName fragment;
+ StringName vertex;
+ StringName light;
+ VaryingFunctionNames() {
+ fragment = "fragment";
+ vertex = "vertex";
+ light = "light";
+ }
+ };
+
struct Node {
Node *next = nullptr;
@@ -598,10 +614,21 @@ public:
};
struct Varying {
+ enum Stage {
+ STAGE_UNKNOWN,
+ STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT or STAGE_VERTEX_TO_LIGHT, emits error if they are not used
+ STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits error if it's not used
+ STAGE_VERTEX_TO_FRAGMENT,
+ STAGE_VERTEX_TO_LIGHT,
+ STAGE_FRAGMENT_TO_LIGHT,
+ };
+
+ Stage stage = STAGE_UNKNOWN;
DataType type = TYPE_VOID;
DataInterpolation interpolation = INTERPOLATION_FLAT;
DataPrecision precision = PRECISION_DEFAULT;
int array_size = 0;
+ TkPos tkpos;
Varying() {}
};
@@ -753,7 +780,8 @@ public:
Map<StringName, BuiltInInfo> built_ins;
Map<StringName, StageFunctionInfo> stage_functions;
- bool can_discard;
+ bool can_discard = false;
+ bool main_function = false;
};
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
@@ -780,10 +808,7 @@ private:
StringName current_function;
bool last_const = false;
- struct TkPos {
- int char_idx;
- int tk_line;
- };
+ VaryingFunctionNames varying_function_names;
TkPos _get_tkpos() {
TkPos tkp;
@@ -864,6 +889,9 @@ private:
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
+ bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
+ bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message);
+ bool _check_node_constness(const Node *p_node) const;
Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size);
@@ -885,8 +913,8 @@ public:
void clear();
static String get_shader_type(const String &p_code);
- Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func);
- Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
+ Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func);
+ Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
String get_error_text();
int get_error_line();
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index e99b8504bb..0bf68b9e0f 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -74,6 +74,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].main_function = true;
//builtins
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
@@ -139,6 +140,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RADIANCE"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["IRRADIANCE"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].main_function = true;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR_THRESHOLD"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_HASH_SCALE"] = ShaderLanguage::TYPE_FLOAT;
@@ -171,6 +173,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true;
//order used puts first enum mode (default) first
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix");
@@ -216,6 +219,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("particle_trails");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one");
@@ -236,6 +240,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].main_function = true;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
@@ -257,6 +262,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true;
{
ShaderLanguage::StageFunctionInfo func;
@@ -294,6 +300,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].main_function = true;
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
@@ -310,34 +317,50 @@ ShaderTypes::ShaderTypes() {
/************ PARTICLES **************************/
shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].can_discard = false;
+
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true;
+
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true;
{
ShaderLanguage::StageFunctionInfo emit_vertex_func;
@@ -347,7 +370,7 @@ ShaderTypes::ShaderTypes() {
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_subparticle"] = emit_vertex_func;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func;
}
shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale");
@@ -384,14 +407,15 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_SIZE"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SKY].functions["sky"].main_function = true;
shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 41c88aa3be..3605dec1be 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -349,7 +349,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[2] = { src[i].x, src[i].y };
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2);
if (i == 0) {
aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size
@@ -374,7 +374,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[3] = { src[i].x, src[i].y, src[i].z };
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
if (i == 0) {
aabb = AABB(src[i], SMALL_VEC3);
@@ -403,7 +403,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -422,9 +422,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30;
+ value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 1023.0), 0, 1023) << 30;
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -442,7 +442,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
color16[1] = Math::make_half_float(src[i].g);
color16[2] = Math::make_half_float(src[i].b);
color16[3] = Math::make_half_float(src[i].a);
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8);
}
} break;
case RS::ARRAY_TEX_UV: {
@@ -457,7 +457,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float uv[2] = { src[i].x, src[i].y };
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
}
} break;
@@ -473,7 +473,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2);
}
} break;
case RS::ARRAY_CUSTOM0:
@@ -495,7 +495,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const uint8_t *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4);
}
} break;
@@ -510,7 +510,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const uint8_t *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8);
}
} break;
case ARRAY_CUSTOM_R_FLOAT:
@@ -528,7 +528,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const float *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
}
} break;
default: {
@@ -554,7 +554,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535);
}
- copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
+ memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
}
@@ -578,7 +578,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
max_bone = MAX(data[j], max_bone);
}
- copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
+ memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
} break;
@@ -600,11 +600,11 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
if (p_vertex_array_len < (1 << 16)) {
uint16_t v = src[i];
- copymem(&iw[i * 2], &v, 2);
+ memcpy(&iw[i * 2], &v, 2);
} else {
uint32_t v = src[i];
- copymem(&iw[i * 4], &v, 4);
+ memcpy(&iw[i * 4], &v, 4);
}
}
} break;
@@ -1172,7 +1172,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]];
- copymem(&w[j * s], v, s);
+ memcpy(&w[j * s], v, s);
}
ret[i] = arr;
@@ -1189,7 +1189,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]];
- copymem(&w[j * s], v, s * sizeof(float));
+ memcpy(&w[j * s], v, s * sizeof(float));
}
ret[i] = arr;
@@ -1489,7 +1489,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &RenderingServer::mesh_clear);
ClassDB::bind_method(D_METHOD("multimesh_create"), &RenderingServer::multimesh_create);
- ClassDB::bind_method(D_METHOD("multimesh_allocate", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("multimesh_allocate_data", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate_data, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &RenderingServer::multimesh_get_instance_count);
ClassDB::bind_method(D_METHOD("multimesh_set_mesh", "multimesh", "mesh"), &RenderingServer::multimesh_set_mesh);
ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform);
@@ -1523,7 +1523,7 @@ void RenderingServer::_bind_methods() {
#endif
ClassDB::bind_method(D_METHOD("skeleton_create"), &RenderingServer::skeleton_create);
- ClassDB::bind_method(D_METHOD("skeleton_allocate", "skeleton", "bones", "is_2d_skeleton"), &RenderingServer::skeleton_allocate, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("skeleton_allocate_data", "skeleton", "bones", "is_2d_skeleton"), &RenderingServer::skeleton_allocate_data, DEFVAL(false));
ClassDB::bind_method(D_METHOD("skeleton_get_bone_count", "skeleton"), &RenderingServer::skeleton_get_bone_count);
ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform", "skeleton", "bone", "transform"), &RenderingServer::skeleton_bone_set_transform);
ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform", "skeleton", "bone"), &RenderingServer::skeleton_bone_get_transform);
@@ -1594,7 +1594,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("gi_probe_set_compress", "probe", "enable"), &RenderingServer::gi_probe_set_compress);
ClassDB::bind_method(D_METHOD("gi_probe_is_compressed", "probe"), &RenderingServer::gi_probe_is_compressed);
#endif
-/*
+ /*
ClassDB::bind_method(D_METHOD("lightmap_create()"), &RenderingServer::lightmap_capture_create);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &RenderingServer::lightmap_capture_set_bounds);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &RenderingServer::lightmap_capture_get_bounds);
@@ -1607,6 +1607,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &RenderingServer::lightmap_capture_set_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &RenderingServer::lightmap_capture_get_energy);
*/
+
+ ClassDB::bind_method(D_METHOD("occluder_create"), &RenderingServer::occluder_create);
+ ClassDB::bind_method(D_METHOD("occluder_set_mesh"), &RenderingServer::occluder_set_mesh);
+
#endif
ClassDB::bind_method(D_METHOD("particles_create"), &RenderingServer::particles_create);
ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting);
@@ -1667,6 +1671,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision);
ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa);
ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding);
+ ClassDB::bind_method(D_METHOD("viewport_set_use_occlusion_culling", "viewport", "enable"), &RenderingServer::viewport_set_use_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("viewport_set_occlusion_rays_per_thread", "rays_per_thread"), &RenderingServer::viewport_set_occlusion_rays_per_thread);
+ ClassDB::bind_method(D_METHOD("viewport_set_occlusion_culling_build_quality", "quality"), &RenderingServer::viewport_set_occlusion_culling_build_quality);
ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info);
ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw);
@@ -1694,6 +1701,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create);
ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &RenderingServer::scenario_set_debug);
ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment);
+ ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects);
ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment);
#ifndef _3D_DISABLED
@@ -1706,7 +1714,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform);
ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight);
- ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_material);
+ ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material);
ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible);
// ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap"), &RenderingServer::instance_set_use_lightmap);
ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb);
@@ -2024,6 +2032,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI);
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI_PROBES);
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_BUFFER);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS);
BIND_ENUM_CONSTANT(SKY_MODE_QUALITY);
BIND_ENUM_CONSTANT(SKY_MODE_REALTIME);
@@ -2093,6 +2102,10 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW);
BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH);
+
BIND_ENUM_CONSTANT(INSTANCE_NONE);
BIND_ENUM_CONSTANT(INSTANCE_MESH);
BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
@@ -2104,12 +2117,14 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(INSTANCE_DECAL);
BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE);
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP);
+ BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER);
BIND_ENUM_CONSTANT(INSTANCE_MAX);
BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_DYNAMIC_GI);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
+ BIND_ENUM_CONSTANT(INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
@@ -2259,130 +2274,138 @@ RenderingServer::RenderingServer() {
thread_pool = memnew(RendererThreadPool);
singleton = this;
- GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false);
- GLOBAL_DEF_RST("rendering/vram_compression/import_s3tc", true);
- GLOBAL_DEF_RST("rendering/vram_compression/import_etc", false);
- GLOBAL_DEF_RST("rendering/vram_compression/import_etc2", true);
- GLOBAL_DEF_RST("rendering/vram_compression/import_pvrtc", false);
+ GLOBAL_DEF_RST("rendering/textures/vram_compression/import_bptc", false);
+ GLOBAL_DEF_RST("rendering/textures/vram_compression/import_s3tc", true);
+ GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc", false);
+ GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc2", true);
+ GLOBAL_DEF_RST("rendering/textures/vram_compression/import_pvrtc", false);
GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::FLOAT, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"));
- GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096);
- GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
- GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality", 2);
- GLOBAL_DEF("rendering/quality/directional_shadow/soft_shadow_quality.mobile", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
- GLOBAL_DEF("rendering/quality/directional_shadow/16_bits", true);
-
- GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality", 2);
- GLOBAL_DEF("rendering/quality/shadows/soft_shadow_quality.mobile", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/quality/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
-
- GLOBAL_DEF("rendering/quality/2d_shadow_atlas/size", 2048);
-
- GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer", false);
- GLOBAL_DEF("rendering/quality/rd_renderer/use_low_end_renderer.mobile", true);
-
- GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 8);
- GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections", true);
- GLOBAL_DEF("rendering/quality/reflections/texture_array_reflections.mobile", false);
- GLOBAL_DEF("rendering/quality/reflections/ggx_samples", 1024);
- GLOBAL_DEF("rendering/quality/reflections/ggx_samples.mobile", 128);
- GLOBAL_DEF("rendering/quality/reflections/fast_filter_high_quality", false);
- GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size", 256);
- GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128);
- GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64);
-
- GLOBAL_DEF("rendering/quality/gi/use_half_resolution", false);
-
- GLOBAL_DEF("rendering/quality/gi_probes/anisotropic", false);
- GLOBAL_DEF("rendering/quality/gi_probes/quality", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/quality/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"));
-
- GLOBAL_DEF("rendering/quality/shading/force_vertex_shading", false);
- GLOBAL_DEF("rendering/quality/shading/force_vertex_shading.mobile", true);
- GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley", false);
- GLOBAL_DEF("rendering/quality/shading/force_lambert_over_burley.mobile", true);
- GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx", false);
- GLOBAL_DEF("rendering/quality/shading/force_blinn_over_ggx.mobile", true);
-
- GLOBAL_DEF("rendering/quality/depth_prepass/enable", true);
- GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");
-
- GLOBAL_DEF("rendering/quality/texture_filters/use_nearest_mipmap_filter", false);
- GLOBAL_DEF("rendering/quality/texture_filters/anisotropic_filtering_level", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/texture_filters/anisotropic_filtering_level", PropertyInfo(Variant::INT, "rendering/quality/texture_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Faster),4x (Fast),8x (Average),16x (Slow)"));
-
- GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)"));
- GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)"));
- GLOBAL_DEF("rendering/quality/depth_of_field/depth_of_field_use_jitter", false);
-
- GLOBAL_DEF("rendering/quality/ssao/quality", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low (Fast),Medium (Average),High (Slow),Ultra (Custom)"));
- GLOBAL_DEF("rendering/quality/ssao/half_size", false);
- GLOBAL_DEF("rendering/quality/ssao/half_size.mobile", true);
- GLOBAL_DEF("rendering/quality/ssao/adaptive_target", 0.5);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/adaptive_target", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/adaptive_target", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
- GLOBAL_DEF("rendering/quality/ssao/blur_passes", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/blur_passes", PropertyInfo(Variant::INT, "rendering/quality/ssao/blur_passes", PROPERTY_HINT_RANGE, "0,6"));
- GLOBAL_DEF("rendering/quality/ssao/fadeout_from", 50.0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/fadeout_from", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/fadeout_from", PROPERTY_HINT_RANGE, "0.0,512,0.1,or_greater"));
- GLOBAL_DEF("rendering/quality/ssao/fadeout_to", 300.0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/fadeout_to", PropertyInfo(Variant::FLOAT, "rendering/quality/ssao/fadeout_to", PROPERTY_HINT_RANGE, "64,65536,0.1,or_greater"));
-
- GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled", true);
- GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_amount", 0.25);
- GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_limit", 0.18);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_amount", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"));
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_limit", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"));
-
- GLOBAL_DEF("rendering/quality/glow/upscale_mode", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/quality/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"));
- GLOBAL_DEF("rendering/quality/glow/upscale_mode.mobile", 0);
- GLOBAL_DEF("rendering/quality/glow/use_high_quality", false);
-
- GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"));
-
- GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_quality", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"));
- GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_scale", 0.05);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
- GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", 0.01);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
-
- GLOBAL_DEF("rendering/high_end/global_shader_variables_buffer_size", 65536);
-
- GLOBAL_DEF("rendering/lightmapper/probe_capture_update_speed", 15);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/lightmapper/probe_capture_update_speed", PropertyInfo(Variant::FLOAT, "rendering/lightmapper/probe_capture_update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"));
-
- GLOBAL_DEF("rendering/sdfgi/probe_ray_count", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)"));
- GLOBAL_DEF("rendering/sdfgi/frames_to_converge", 4);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)"));
- GLOBAL_DEF("rendering/sdfgi/frames_to_update_lights", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/sdfgi/frames_to_update_lights", PropertyInfo(Variant::INT, "rendering/sdfgi/frames_to_update_lights", PROPERTY_HINT_ENUM, "1 (Slower),2,4,8,16 (Faster)"));
-
- GLOBAL_DEF("rendering/volumetric_fog/volume_size", 64);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1"));
- GLOBAL_DEF("rendering/volumetric_fog/volume_depth", 128);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"));
- GLOBAL_DEF("rendering/volumetric_fog/use_filter", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"));
-
- GLOBAL_DEF("rendering/spatial_indexer/update_iterations_per_frame", 10);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/update_iterations_per_frame", PropertyInfo(Variant::INT, "rendering/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"));
- GLOBAL_DEF("rendering/spatial_indexer/threaded_cull_minimum_instances", 1000);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/threaded_cull_minimum_instances", PropertyInfo(Variant::INT, "rendering/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"));
- GLOBAL_DEF("rendering/forward_renderer/threaded_render_minimum_instances", 500);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/forward_renderer/threaded_render_minimum_instances", PropertyInfo(Variant::INT, "rendering/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"));
-
- GLOBAL_DEF("rendering/cluster_builder/max_clustered_elements", 512);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"));
+ GLOBAL_DEF("rendering/shadows/directional_shadow/size", 4096);
+ GLOBAL_DEF("rendering/shadows/directional_shadow/size.mobile", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
+ GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 2);
+ GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality.mobile", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
+ GLOBAL_DEF("rendering/shadows/directional_shadow/16_bits", true);
+
+ GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 2);
+ GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality.mobile", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"));
+
+ GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
+
+ GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end", 0);
+ GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end.mobile", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/vulkan/rendering/back_end",
+ PropertyInfo(Variant::INT,
+ "rendering/vulkan/rendering/back_end",
+ PROPERTY_HINT_ENUM, "ForwardClustered,ForwardMobile"));
+
+ GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
+ GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true);
+ GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false);
+ GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024);
+ GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128);
+ GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false);
+ GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size", 256);
+ GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_size.mobile", 128);
+ GLOBAL_DEF("rendering/reflections/reflection_atlas/reflection_count", 64);
+
+ GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);
+
+ GLOBAL_DEF("rendering/global_illumination/gi_probes/anisotropic", false);
+ GLOBAL_DEF("rendering/global_illumination/gi_probes/quality", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"));
+
+ GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false);
+ GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true);
+ GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley", false);
+ GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true);
+ GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx", false);
+ GLOBAL_DEF("rendering/shading/overrides/force_blinn_over_ggx.mobile", true);
+
+ GLOBAL_DEF("rendering/driver/depth_prepass/enable", true);
+ GLOBAL_DEF("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");
+
+ GLOBAL_DEF("rendering/textures/default_filters/use_nearest_mipmap_filter", false);
+ GLOBAL_DEF("rendering/textures/default_filters/anisotropic_filtering_level", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/default_filters/anisotropic_filtering_level", PropertyInfo(Variant::INT, "rendering/textures/default_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Faster),4x (Fast),8x (Average),16x (Slow)"));
+
+ GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_bokeh_shape", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/camera/depth_of_field/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/camera/depth_of_field/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fast),Hexagon (Average),Circle (Slow)"));
+ GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_bokeh_quality", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/camera/depth_of_field/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/camera/depth_of_field/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fastest),Low (Fast),Medium (Average),High (Slow)"));
+ GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_use_jitter", false);
+
+ GLOBAL_DEF("rendering/environment/ssao/quality", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/quality", PropertyInfo(Variant::INT, "rendering/environment/ssao/quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low (Fast),Medium (Average),High (Slow),Ultra (Custom)"));
+ GLOBAL_DEF("rendering/environment/ssao/half_size", false);
+ GLOBAL_DEF("rendering/environment/ssao/half_size.mobile", true);
+ GLOBAL_DEF("rendering/environment/ssao/adaptive_target", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/adaptive_target", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/adaptive_target", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
+ GLOBAL_DEF("rendering/environment/ssao/blur_passes", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/blur_passes", PropertyInfo(Variant::INT, "rendering/environment/ssao/blur_passes", PROPERTY_HINT_RANGE, "0,6"));
+ GLOBAL_DEF("rendering/environment/ssao/fadeout_from", 50.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/fadeout_from", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/fadeout_from", PROPERTY_HINT_RANGE, "0.0,512,0.1,or_greater"));
+ GLOBAL_DEF("rendering/environment/ssao/fadeout_to", 300.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/ssao/fadeout_to", PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/fadeout_to", PROPERTY_HINT_RANGE, "64,65536,0.1,or_greater"));
+
+ GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/enabled", true);
+ GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/amount", 0.25);
+ GLOBAL_DEF("rendering/anti_aliasing/screen_space_roughness_limiter/limit", 0.18);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"));
+
+ GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512);
+ GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/occlusion_culling/bvh_build_quality", PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"));
+
+ GLOBAL_DEF("rendering/environment/glow/upscale_mode", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"));
+ GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0);
+ GLOBAL_DEF("rendering/environment/glow/use_high_quality", false);
+
+ GLOBAL_DEF("rendering/environment/screen_space_reflection/roughness_quality", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/environment/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"));
+
+ GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_quality", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/environment/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"));
+ GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_scale", 0.05);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
+ GLOBAL_DEF("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", 0.01);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"));
+
+ GLOBAL_DEF("rendering/limits/global_shader_variables/buffer_size", 65536);
+
+ GLOBAL_DEF("rendering/lightmapping/probe_capture/update_speed", 15);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/lightmapping/probe_capture/update_speed", PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"));
+
+ GLOBAL_DEF("rendering/global_illumination/sdfgi/probe_ray_count", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/probe_ray_count", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)"));
+ GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_converge", 4);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_converge", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)"));
+ GLOBAL_DEF("rendering/global_illumination/sdfgi/frames_to_update_lights", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/sdfgi/frames_to_update_lights", PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_update_lights", PROPERTY_HINT_ENUM, "1 (Slower),2,4,8,16 (Faster)"));
+
+ GLOBAL_DEF("rendering/environment/volumetric_fog/volume_size", 64);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1"));
+ GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"));
+ GLOBAL_DEF("rendering/environment/volumetric_fog/use_filter", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"));
+
+ GLOBAL_DEF("rendering/limits/spatial_indexer/update_iterations_per_frame", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/spatial_indexer/update_iterations_per_frame", PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"));
+ GLOBAL_DEF("rendering/limits/spatial_indexer/threaded_cull_minimum_instances", 1000);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"));
+ GLOBAL_DEF("rendering/limits/forward_renderer/threaded_render_minimum_instances", 500);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/forward_renderer/threaded_render_minimum_instances", PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"));
+
+ GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"));
}
RenderingServer::~RenderingServer() {
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 5defa1f667..ad965e9690 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -367,7 +367,7 @@ public:
MULTIMESH_TRANSFORM_3D,
};
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
+ virtual void multimesh_allocate_data(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0;
virtual int multimesh_get_instance_count(RID p_multimesh) const = 0;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
@@ -409,7 +409,7 @@ public:
/* SKELETON API */
virtual RID skeleton_create() = 0;
- virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
+ virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0;
virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
@@ -552,7 +552,7 @@ public:
virtual RID gi_probe_create() = 0;
- virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
+ virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
@@ -631,8 +631,22 @@ public:
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+ virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0;
+
+ enum ParticlesTransformAlign {
+ PARTICLES_TRANSFORM_ALIGN_DISABLED,
+ PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD,
+ PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY,
+ };
+
+ virtual void particles_set_transform_align(RID p_particles, ParticlesTransformAlign p_transform_align) = 0;
+
+ virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length_sec) = 0;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0;
+
virtual bool particles_is_inactive(RID p_particles) = 0;
virtual void particles_request_process(RID p_particles) = 0;
virtual void particles_restart(RID p_particles) = 0;
@@ -713,6 +727,11 @@ public:
virtual void camera_set_camera_effects(RID p_camera, RID p_camera_effects) = 0;
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
+ /* OCCLUDER API */
+
+ virtual RID occluder_create() = 0;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0;
+
/* VIEWPORT TARGET API */
enum CanvasItemTextureFilter {
@@ -826,6 +845,17 @@ public:
virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0;
+ virtual void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_debanding) = 0;
+ virtual void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) = 0;
+
+ enum ViewportOcclusionCullingBuildQuality {
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW = 0,
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM = 1,
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH = 2,
+ };
+
+ virtual void viewport_set_occlusion_culling_build_quality(ViewportOcclusionCullingBuildQuality p_quality) = 0;
+
enum ViewportRenderInfo {
VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,
@@ -862,6 +892,7 @@ public:
VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS,
VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ VIEWPORT_DEBUG_DRAW_OCCLUDERS,
};
virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0;
@@ -985,7 +1016,7 @@ public:
ENV_SDFGI_Y_SCALE_50_PERCENT
};
- virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
+ virtual void environment_set_sdfgi(RID p_env, bool p_enable, EnvironmentSDFGICascades p_cascades, float p_min_cell_size, EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) = 0;
enum EnvironmentSDFGIRayCount {
ENV_SDFGI_RAY_COUNT_4,
@@ -1109,6 +1140,7 @@ public:
INSTANCE_DECAL,
INSTANCE_GI_PROBE,
INSTANCE_LIGHTMAP,
+ INSTANCE_OCCLUDER,
INSTANCE_MAX,
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
@@ -1124,7 +1156,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0;
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0;
@@ -1147,6 +1179,7 @@ public:
INSTANCE_FLAG_USE_BAKED_LIGHT,
INSTANCE_FLAG_USE_DYNAMIC_GI,
INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
+ INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING,
INSTANCE_FLAG_MAX
};
@@ -1419,7 +1452,7 @@ public:
INFO_VERTEX_MEM_USED,
};
- virtual int get_render_info(RenderInfo p_info) = 0;
+ virtual uint64_t get_render_info(RenderInfo p_info) = 0;
virtual String get_video_adapter_name() const = 0;
virtual String get_video_adapter_vendor() const = 0;
@@ -1505,6 +1538,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA);
VARIANT_ENUM_CAST(RenderingServer::ViewportScreenSpaceAA);
VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfo);
VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw);
+VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality);
VARIANT_ENUM_CAST(RenderingServer::SkyMode);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource);
diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h
index 5e18dc1e6d..95d2e2254e 100644
--- a/servers/server_wrap_mt_common.h
+++ b/servers/server_wrap_mt_common.h
@@ -29,245 +29,89 @@
/*************************************************************************/
#define FUNC0R(m_r, m_type) \
- virtual m_r m_type() { \
+ virtual m_r m_type() override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(); \
} \
}
-#define FUNCRID(m_type) \
- List<RID> m_type##_id_pool; \
- int m_type##allocn() { \
- for (int i = 0; i < pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- server_name->free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create() { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(); \
- } \
- }
-
-#define FUNC1RID(m_type, m_arg1) \
- int m_type##allocn() { \
- for (int i = 0; i < m_type##_pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create(m_arg1 p1) { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(p1); \
- } \
- }
-
-#define FUNC2RID(m_type, m_arg1, m_arg2) \
- int m_type##allocn() { \
- for (int i = 0; i < m_type##_pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create(m_arg1 p1, m_arg2 p2) { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(p1, p2); \
- } \
- }
-
-#define FUNC3RID(m_type, m_arg1, m_arg2, m_arg3) \
- int m_type##allocn() { \
- for (int i = 0; i < m_type##_pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(p1, p2, p3); \
- } \
- }
-
-#define FUNC4RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- int m_type##allocn() { \
- for (int i = 0; i < m_type##_pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create()); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, p4, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(p1, p2, p3, p4); \
- } \
+#define FUNCRIDSPLIT(m_type) \
+ virtual RID m_type##_create() override { \
+ RID ret = server_name->m_type##_allocate(); \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type##_initialize, ret); \
+ } else { \
+ server_name->m_type##_initialize(ret); \
+ } \
+ return ret; \
}
-#define FUNC5RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- List<RID> m_type##_id_pool; \
- int m_type##allocn(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- for (int i = 0; i < pool_max_size; i++) { \
- m_type##_id_pool.push_back(server_name->m_type##_create(p1, p2, p3, p4, p5)); \
- } \
- return 0; \
- } \
- void m_type##_free_cached_ids() { \
- while (m_type##_id_pool.size()) { \
- free(m_type##_id_pool.front()->get()); \
- m_type##_id_pool.pop_front(); \
- } \
- } \
- virtual RID m_type##_create(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_id() != server_thread) { \
- RID rid; \
- MutexLock lock(alloc_mutex); \
- if (m_type##_id_pool.size() == 0) { \
- int ret; \
- command_queue.push_and_ret(this, &ServerNameWrapMT::m_type##allocn, p1, p2, p3, p4, p5, &ret); \
- SYNC_DEBUG \
- } \
- rid = m_type##_id_pool.front()->get(); \
- m_type##_id_pool.pop_front(); \
- return rid; \
- } else { \
- return server_name->m_type##_create(p1, p2, p3, p4, p5); \
- } \
+//RID now returns directly, ensure thread safety yourself
+#define FUNCRID(m_type) \
+ virtual RID m_type##_create() override { \
+ return server_name->m_type##_create(); \
}
#define FUNC0RC(m_r, m_type) \
- virtual m_r m_type() const { \
+ virtual m_r m_type() const override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(); \
} \
}
#define FUNC0(m_type) \
- virtual void m_type() { \
+ virtual void m_type() override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(); \
} \
}
#define FUNC0C(m_type) \
- virtual void m_type() const { \
+ virtual void m_type() const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(); \
} \
}
#define FUNC0S(m_type) \
- virtual void m_type() { \
+ virtual void m_type() override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(); \
} \
}
#define FUNC0SC(m_type) \
- virtual void m_type() const { \
+ virtual void m_type() const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(); \
} \
}
@@ -275,560 +119,646 @@
///////////////////////////////////////////////
#define FUNC1R(m_r, m_type, m_arg1) \
- virtual m_r m_type(m_arg1 p1) { \
+ virtual m_r m_type(m_arg1 p1) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1); \
} \
}
#define FUNC1RC(m_r, m_type, m_arg1) \
- virtual m_r m_type(m_arg1 p1) const { \
+ virtual m_r m_type(m_arg1 p1) const override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1); \
} \
}
#define FUNC1S(m_type, m_arg1) \
- virtual void m_type(m_arg1 p1) { \
+ virtual void m_type(m_arg1 p1) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1); \
} \
}
#define FUNC1SC(m_type, m_arg1) \
- virtual void m_type(m_arg1 p1) const { \
+ virtual void m_type(m_arg1 p1) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1); \
} \
}
#define FUNC1(m_type, m_arg1) \
- virtual void m_type(m_arg1 p1) { \
+ virtual void m_type(m_arg1 p1) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1); \
} \
}
#define FUNC1C(m_type, m_arg1) \
- virtual void m_type(m_arg1 p1) const { \
+ virtual void m_type(m_arg1 p1) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1); \
} \
}
#define FUNC2R(m_r, m_type, m_arg1, m_arg2) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2); \
} \
}
#define FUNC2RC(m_r, m_type, m_arg1, m_arg2) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2) const override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2); \
} \
}
#define FUNC2S(m_type, m_arg1, m_arg2) \
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2); \
} \
}
#define FUNC2SC(m_type, m_arg1, m_arg2) \
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2); \
} \
}
#define FUNC2(m_type, m_arg1, m_arg2) \
- virtual void m_type(m_arg1 p1, m_arg2 p2) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1, p2); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2); \
} \
}
#define FUNC2C(m_type, m_arg1, m_arg2) \
- virtual void m_type(m_arg1 p1, m_arg2 p2) const { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1, p2); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2); \
} \
}
#define FUNC3R(m_r, m_type, m_arg1, m_arg2, m_arg3) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC3RC(m_r, m_type, m_arg1, m_arg2, m_arg3) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC3S(m_type, m_arg1, m_arg2, m_arg3) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC3SC(m_type, m_arg1, m_arg2, m_arg3) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC3(m_type, m_arg1, m_arg2, m_arg3) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1, p2, p3); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC3C(m_type, m_arg1, m_arg2, m_arg3) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1, p2, p3); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3); \
} \
}
#define FUNC4R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3, p4); \
} \
}
#define FUNC4RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3, p4); \
} \
}
#define FUNC4S(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3, p4); \
} \
}
#define FUNC4SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3, p4); \
} \
}
#define FUNC4(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3, p4); \
} \
}
-#define FUNC4C(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \
- } else { \
- server_name->m_type(p1, p2, p3, p4); \
- } \
+#define FUNC4C(m_type, m_arg1, m_arg2, m_arg3, m_arg4) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4); \
+ } \
}
#define FUNC5R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3, p4, p5); \
} \
}
#define FUNC5RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3, p4, p5); \
} \
}
#define FUNC5S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) override { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
SYNC_DEBUG \
} else { \
+ command_queue.flush_if_pending(); \
server_name->m_type(p1, p2, p3, p4, p5); \
} \
}
-#define FUNC5SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5); \
- } \
+#define FUNC5SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5); \
+ } \
}
-#define FUNC5(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5); \
- } \
+#define FUNC5(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5); \
+ } \
}
-#define FUNC5C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5); \
- } \
+#define FUNC5C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5); \
+ } \
}
#define FUNC6R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
+ WRITE_ACTION \
if (Thread::get_caller_id() != server_thread) { \
m_r ret; \
command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \
SYNC_DEBUG \
return ret; \
} else { \
+ command_queue.flush_if_pending(); \
return server_name->m_type(p1, p2, p3, p4, p5, p6); \
} \
}
-#define FUNC6RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_id() != server_thread) { \
- m_r ret; \
- command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \
- SYNC_DEBUG \
- return ret; \
- } else { \
- return server_name->m_type(p1, p2, p3, p4, p5, p6); \
- } \
+#define FUNC6RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ m_r ret; \
+ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \
+ SYNC_DEBUG \
+ return ret; \
+ } else { \
+ command_queue.flush_if_pending(); \
+ return server_name->m_type(p1, p2, p3, p4, p5, p6); \
+ } \
+ }
+
+#define FUNC6S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6); \
+ } \
+ }
+
+#define FUNC6SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6); \
+ } \
}
-#define FUNC6S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6); \
- } \
+#define FUNC6(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6); \
+ } \
}
-#define FUNC6SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6); \
- } \
+#define FUNC6C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6); \
+ } \
}
-#define FUNC6(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6); \
- } \
+#define FUNC7R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ m_r ret; \
+ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \
+ SYNC_DEBUG \
+ return ret; \
+ } else { \
+ command_queue.flush_if_pending(); \
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
}
-#define FUNC6C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6); \
- } \
- }
-
-#define FUNC7R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_id() != server_thread) { \
- m_r ret; \
- command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \
- SYNC_DEBUG \
- return ret; \
- } else { \
- return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC7RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_id() != server_thread) { \
- m_r ret; \
- command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \
- SYNC_DEBUG \
- return ret; \
- } else { \
- return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC7S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC7SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC7(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC7C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
- } \
- }
-
-#define FUNC8R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \
- if (Thread::get_caller_id() != server_thread) { \
- m_r ret; \
- command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \
- SYNC_DEBUG \
- return ret; \
- } else { \
- return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC8RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \
- if (Thread::get_caller_id() != server_thread) { \
- m_r ret; \
- command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \
- SYNC_DEBUG \
- return ret; \
- } else { \
- return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC8S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC8SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
- SYNC_DEBUG \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC8(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC8C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
- } \
- }
-
-#define FUNC9(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
- } \
- }
-
-#define FUNC10(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
- } \
- }
-
-#define FUNC11(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
- } \
- }
-
-#define FUNC12(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
- } \
- }
-
-#define FUNC13(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
- } \
- }
-
-#define FUNC14(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
- } \
- }
-
-#define FUNC15(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14, m_arg15) \
- virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14, m_arg15 p15) { \
- if (Thread::get_caller_id() != server_thread) { \
- command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
- } else { \
- server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
- } \
+#define FUNC7RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ m_r ret; \
+ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \
+ SYNC_DEBUG \
+ return ret; \
+ } else { \
+ command_queue.flush_if_pending(); \
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
+ }
+
+#define FUNC7S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
+ }
+
+#define FUNC7SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
+ }
+
+#define FUNC7(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
+ }
+
+#define FUNC7C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \
+ } \
+ }
+
+#define FUNC8R(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ m_r ret; \
+ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \
+ SYNC_DEBUG \
+ return ret; \
+ } else { \
+ command_queue.flush_if_pending(); \
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC8RC(m_r, m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ m_r ret; \
+ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \
+ SYNC_DEBUG \
+ return ret; \
+ } else { \
+ command_queue.flush_if_pending(); \
+ return server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC8S(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC8SC(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
+ SYNC_DEBUG \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC8(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC8C(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8) const override { \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \
+ } \
+ }
+
+#define FUNC9(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9); \
+ } \
+ }
+
+#define FUNC10(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
+ } \
+ }
+
+#define FUNC11(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
+ } \
+ }
+
+#define FUNC12(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
+ } \
+ }
+
+#define FUNC13(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
+ } \
+ }
+
+#define FUNC14(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \
+ } \
+ }
+
+#define FUNC15(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14, m_arg15) \
+ virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14, m_arg15 p15) override { \
+ WRITE_ACTION \
+ if (Thread::get_caller_id() != server_thread) { \
+ command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
+ } else { \
+ command_queue.flush_if_pending(); \
+ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \
+ } \
}
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index da68ceb128..8b03565291 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -219,6 +219,11 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_font_system", "name", "base_size"), &TextServer::create_font_system, DEFVAL(16));
ClassDB::bind_method(D_METHOD("create_font_resource", "filename", "base_size"), &TextServer::create_font_resource, DEFVAL(16));
ClassDB::bind_method(D_METHOD("create_font_memory", "data", "type", "base_size"), &TextServer::_create_font_memory, DEFVAL(16));
+ ClassDB::bind_method(D_METHOD("create_font_bitmap", "height", "ascent", "base_size"), &TextServer::create_font_bitmap);
+
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_texture", "font", "texture"), &TextServer::font_bitmap_add_texture);
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_char", "font", "char", "texture_idx", "rect", "align", "advance"), &TextServer::font_bitmap_add_char);
+ ClassDB::bind_method(D_METHOD("font_bitmap_add_kerning_pair", "font", "A", "B", "kerning"), &TextServer::font_bitmap_add_kerning_pair);
ClassDB::bind_method(D_METHOD("font_get_height", "font", "size"), &TextServer::font_get_height);
ClassDB::bind_method(D_METHOD("font_get_ascent", "font", "size"), &TextServer::font_get_ascent);
@@ -227,6 +232,12 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("font_get_underline_position", "font", "size"), &TextServer::font_get_underline_position);
ClassDB::bind_method(D_METHOD("font_get_underline_thickness", "font", "size"), &TextServer::font_get_underline_thickness);
+ ClassDB::bind_method(D_METHOD("font_get_spacing_space", "font"), &TextServer::font_get_spacing_space);
+ ClassDB::bind_method(D_METHOD("font_set_spacing_space", "font", "value"), &TextServer::font_set_spacing_space);
+
+ ClassDB::bind_method(D_METHOD("font_get_spacing_glyph", "font"), &TextServer::font_get_spacing_glyph);
+ ClassDB::bind_method(D_METHOD("font_set_spacing_glyph", "font", "value"), &TextServer::font_set_spacing_glyph);
+
ClassDB::bind_method(D_METHOD("font_set_antialiased", "font", "antialiased"), &TextServer::font_set_antialiased);
ClassDB::bind_method(D_METHOD("font_get_antialiased", "font"), &TextServer::font_get_antialiased);
@@ -280,11 +291,13 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size);
ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box);
+ ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::_font_get_glyph_contours);
+
/* Shaped text buffer interface */
ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL));
- ClassDB::bind_method(D_METHOD("shaped_text_clear"), &TextServer::shaped_text_clear);
+ ClassDB::bind_method(D_METHOD("shaped_text_clear", "rid"), &TextServer::shaped_text_clear);
ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO));
ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction);
@@ -392,6 +405,11 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM);
BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
+
+ /* FT Contour Point Types */
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON);
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CONIC);
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CUBIC);
}
Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) };
@@ -1201,6 +1219,21 @@ RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String
return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size);
}
+Dictionary TextServer::_font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const {
+ Vector<Vector3> points;
+ Vector<int32_t> contours;
+ bool orientation;
+ bool ok = font_get_glyph_contours(p_font, p_size, p_index, points, contours, orientation);
+ Dictionary out;
+
+ if (ok) {
+ out["points"] = points;
+ out["contours"] = contours;
+ out["orientation"] = orientation;
+ }
+ return out;
+}
+
void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
Vector<Vector2i> overrides;
for (int i = 0; i < p_override.size(); i++) {
diff --git a/servers/text_server.h b/servers/text_server.h
index 23367de4c8..7fcfb91151 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -99,6 +99,12 @@ public:
FEATURE_USE_SUPPORT_DATA = 1 << 7
};
+ enum ContourPointTag {
+ CONTOUR_CURVE_TAG_ON = 0x01,
+ CONTOUR_CURVE_TAG_OFF_CONIC = 0x00,
+ CONTOUR_CURVE_TAG_OFF_CUBIC = 0x02
+ };
+
struct Glyph {
int start = -1; // Start offset in the source string.
int end = -1; // End offset in the source string.
@@ -192,18 +198,6 @@ public:
Vector<TextServer::Glyph> glyphs_logical;
};
- struct BitmapFontData {
- int height = 0;
- int ascent = 0;
- int charcount = 0;
- const int *char_rects = nullptr;
- int kerning_count = 0;
- const int *kernings = nullptr;
- int w = 0;
- int h = 0;
- const unsigned char *img = nullptr;
- };
-
protected:
static void _bind_methods();
@@ -236,11 +230,22 @@ public:
virtual RID create_font_system(const String &p_name, int p_base_size = 16) = 0;
virtual RID create_font_resource(const String &p_filename, int p_base_size = 16) = 0;
virtual RID create_font_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16) = 0;
+ virtual RID create_font_bitmap(float p_height, float p_ascent, int p_base_size = 16) = 0;
+
+ virtual void font_bitmap_add_texture(RID p_font, const Ref<Texture> &p_texture) = 0;
+ virtual void font_bitmap_add_char(RID p_font, char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) = 0;
+ virtual void font_bitmap_add_kerning_pair(RID p_font, char32_t p_A, char32_t p_B, int p_kerning) = 0;
virtual float font_get_height(RID p_font, int p_size) const = 0;
virtual float font_get_ascent(RID p_font, int p_size) const = 0;
virtual float font_get_descent(RID p_font, int p_size) const = 0;
+ virtual int font_get_spacing_space(RID p_font) const = 0;
+ virtual void font_set_spacing_space(RID p_font, int p_value) = 0;
+
+ virtual int font_get_spacing_glyph(RID p_font) const = 0;
+ virtual void font_set_spacing_glyph(RID p_font, int p_value) = 0;
+
virtual float font_get_underline_position(RID p_font, int p_size) const = 0;
virtual float font_get_underline_thickness(RID p_font, int p_size) const = 0;
@@ -287,6 +292,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const = 0;
+
virtual float font_get_oversampling() const = 0;
virtual void font_set_oversampling(float p_oversampling) = 0;
@@ -373,6 +380,8 @@ public:
/* GDScript wrappers */
RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16);
+ Dictionary _font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const;
+
Array _shaped_text_get_glyphs(RID p_shaped) const;
Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const;
@@ -455,5 +464,6 @@ VARIANT_ENUM_CAST(TextServer::LineBreakFlag);
VARIANT_ENUM_CAST(TextServer::GraphemeFlag);
VARIANT_ENUM_CAST(TextServer::Hinting);
VARIANT_ENUM_CAST(TextServer::Feature);
+VARIANT_ENUM_CAST(TextServer::ContourPointTag);
#endif // TEXT_SERVER_H
diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h
index 420d818342..a5c6459471 100644
--- a/servers/xr/xr_positional_tracker.h
+++ b/servers/xr/xr_positional_tracker.h
@@ -43,8 +43,8 @@
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
*/
-class XRPositionalTracker : public Object {
- GDCLASS(XRPositionalTracker, Object);
+class XRPositionalTracker : public Reference {
+ GDCLASS(XRPositionalTracker, Reference);
_THREAD_SAFE_CLASS_
public:
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index 2acc2e398c..5678071857 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -48,12 +48,17 @@ void XRServer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
+ ClassDB::bind_method(D_METHOD("add_interface", "interface"), &XRServer::add_interface);
+ ClassDB::bind_method(D_METHOD("clear_primary_interface_if", "interface"), &XRServer::clear_primary_interface_if);
ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count);
+ ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &XRServer::remove_interface);
ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface);
ClassDB::bind_method(D_METHOD("get_interfaces"), &XRServer::get_interfaces);
ClassDB::bind_method(D_METHOD("find_interface", "name"), &XRServer::find_interface);
ClassDB::bind_method(D_METHOD("get_tracker_count"), &XRServer::get_tracker_count);
ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &XRServer::get_tracker);
+ ClassDB::bind_method(D_METHOD("add_tracker", "tracker"), &XRServer::add_tracker);
+ ClassDB::bind_method(D_METHOD("remove_tracker", "tracker"), &XRServer::remove_tracker);
ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface);
ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface);
@@ -260,15 +265,15 @@ int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) {
return tracker_id;
};
-void XRServer::add_tracker(XRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
+void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) {
+ ERR_FAIL_COND(p_tracker.is_null());
trackers.push_back(p_tracker);
emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id());
};
-void XRServer::remove_tracker(XRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
+void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) {
+ ERR_FAIL_COND(p_tracker.is_null());
int idx = -1;
for (int i = 0; i < trackers.size(); i++) {
@@ -288,14 +293,14 @@ int XRServer::get_tracker_count() const {
return trackers.size();
};
-XRPositionalTracker *XRServer::get_tracker(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, trackers.size(), nullptr);
+Ref<XRPositionalTracker> XRServer::get_tracker(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, trackers.size(), Ref<XRPositionalTracker>());
return trackers[p_index];
};
-XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const {
- ERR_FAIL_COND_V(p_tracker_id == 0, nullptr);
+Ref<XRPositionalTracker> XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const {
+ ERR_FAIL_COND_V(p_tracker_id == 0, Ref<XRPositionalTracker>());
for (int i = 0; i < trackers.size(); i++) {
if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
@@ -303,7 +308,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i
};
};
- return nullptr;
+ return Ref<XRPositionalTracker>();
};
Ref<XRInterface> XRServer::get_primary_interface() const {
@@ -311,6 +316,7 @@ Ref<XRInterface> XRServer::get_primary_interface() const {
};
void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) {
+ ERR_FAIL_COND(p_primary_interface.is_null());
primary_interface = p_primary_interface;
print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
diff --git a/servers/xr_server.h b/servers/xr_server.h
index d3972be838..46243d7fd0 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -77,7 +77,7 @@ public:
private:
Vector<Ref<XRInterface>> interfaces;
- Vector<XRPositionalTracker *> trackers;
+ Vector<Ref<XRPositionalTracker>> trackers;
Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */
@@ -167,11 +167,11 @@ public:
*/
bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const;
int get_free_tracker_id_for_type(TrackerType p_tracker_type);
- void add_tracker(XRPositionalTracker *p_tracker);
- void remove_tracker(XRPositionalTracker *p_tracker);
+ void add_tracker(Ref<XRPositionalTracker> p_tracker);
+ void remove_tracker(Ref<XRPositionalTracker> p_tracker);
int get_tracker_count() const;
- XRPositionalTracker *get_tracker(int p_index) const;
- XRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const;
+ Ref<XRPositionalTracker> get_tracker(int p_index) const;
+ Ref<XRPositionalTracker> find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const;
uint64_t get_last_process_usec();
uint64_t get_last_commit_usec();
diff --git a/tests/test_array.h b/tests/test_array.h
new file mode 100644
index 0000000000..52da256860
--- /dev/null
+++ b/tests/test_array.h
@@ -0,0 +1,186 @@
+/*************************************************************************/
+/* test_array.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_ARRAY_H
+#define TEST_ARRAY_H
+
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/vector.h"
+#include "core/variant/array.h"
+#include "core/variant/container_type_validate.h"
+#include "core/variant/variant.h"
+#include "tests/test_macros.h"
+
+namespace TestArray {
+
+TEST_CASE("[Array] size(), clear(), and is_empty()") {
+ Array arr;
+ CHECK(arr.size() == 0);
+ CHECK(arr.is_empty());
+ arr.push_back(1);
+ CHECK(arr.size() == 1);
+ arr.clear();
+ CHECK(arr.is_empty());
+ CHECK(arr.size() == 0);
+}
+
+TEST_CASE("[Array] Assignment and comparison operators") {
+ Array arr1;
+ Array arr2;
+ arr1.push_back(1);
+ CHECK(arr1 != arr2);
+ CHECK(arr1 > arr2);
+ CHECK(arr1 >= arr2);
+ arr2.push_back(2);
+ CHECK(arr1 != arr2);
+ CHECK(arr1 < arr2);
+ CHECK(arr1 <= arr2);
+ CHECK(arr2 > arr1);
+ CHECK(arr2 >= arr1);
+ Array arr3 = arr2;
+ CHECK(arr3 == arr2);
+}
+
+TEST_CASE("[Array] append_array()") {
+ Array arr1;
+ Array arr2;
+ arr1.push_back(1);
+ arr1.append_array(arr2);
+ CHECK(arr1.size() == 1);
+ arr2.push_back(2);
+ arr1.append_array(arr2);
+ CHECK(arr1.size() == 2);
+ CHECK(int(arr1[0]) == 1);
+ CHECK(int(arr1[1]) == 2);
+}
+
+TEST_CASE("[Array] resize(), insert(), and erase()") {
+ Array arr;
+ arr.resize(2);
+ CHECK(arr.size() == 2);
+ arr.insert(0, 1);
+ CHECK(int(arr[0]) == 1);
+ arr.insert(0, 2);
+ CHECK(int(arr[0]) == 2);
+ arr.erase(2);
+ CHECK(int(arr[0]) == 1);
+}
+
+TEST_CASE("[Array] front() and back()") {
+ Array arr;
+ arr.push_back(1);
+ CHECK(int(arr.front()) == 1);
+ CHECK(int(arr.back()) == 1);
+ arr.push_back(3);
+ CHECK(int(arr.front()) == 1);
+ CHECK(int(arr.back()) == 3);
+}
+
+TEST_CASE("[Array] has() and count()") {
+ Array arr;
+ arr.push_back(1);
+ arr.push_back(1);
+ CHECK(arr.has(1));
+ CHECK(!arr.has(2));
+ CHECK(arr.count(1) == 2);
+ CHECK(arr.count(2) == 0);
+}
+
+TEST_CASE("[Array] remove()") {
+ Array arr;
+ arr.push_back(1);
+ arr.push_back(2);
+ arr.remove(0);
+ CHECK(arr.size() == 1);
+ CHECK(int(arr[0]) == 2);
+ arr.remove(0);
+ CHECK(arr.size() == 0);
+
+ // The array is now empty; try to use `remove()` again.
+ // Normally, this prints an error message so we silence it.
+ ERR_PRINT_OFF;
+ arr.remove(0);
+ ERR_PRINT_ON;
+
+ CHECK(arr.size() == 0);
+}
+
+TEST_CASE("[Array] get()") {
+ Array arr;
+ arr.push_back(1);
+ CHECK(int(arr.get(0)) == 1);
+}
+
+TEST_CASE("[Array] sort()") {
+ Array arr;
+
+ arr.push_back(3);
+ arr.push_back(4);
+ arr.push_back(2);
+ arr.push_back(1);
+ arr.sort();
+ int val = 1;
+ for (int i = 0; i < arr.size(); i++) {
+ CHECK(int(arr[i]) == val);
+ val++;
+ }
+}
+
+TEST_CASE("[Array] push_front(), pop_front(), pop_back()") {
+ Array arr;
+ arr.push_front(1);
+ arr.push_front(2);
+ CHECK(int(arr[0]) == 2);
+ arr.pop_front();
+ CHECK(int(arr[0]) == 1);
+ CHECK(arr.size() == 1);
+ arr.push_front(2);
+ arr.push_front(3);
+ arr.pop_back();
+ CHECK(int(arr[1]) == 2);
+ CHECK(arr.size() == 2);
+}
+
+TEST_CASE("[Array] max() and min()") {
+ Array arr;
+ arr.push_back(3);
+ arr.push_front(4);
+ arr.push_back(5);
+ arr.push_back(2);
+ int max = int(arr.max());
+ int min = int(arr.min());
+ CHECK(max == 5);
+ CHECK(min == 2);
+}
+} // namespace TestArray
+
+#endif // TEST_ARRAY_H
diff --git a/tests/test_class_db.h b/tests/test_class_db.h
index b1440b83ef..9ef4569c14 100644
--- a/tests/test_class_db.h
+++ b/tests/test_class_db.h
@@ -340,7 +340,14 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
if (prop_class) {
TEST_COND(prop_class->is_singleton,
"Property type is a singleton: '", p_class.name, ".", String(p_prop.name), "'.");
+
+ if (p_class.api_type == ClassDB::API_CORE) {
+ TEST_COND(prop_class->api_type == ClassDB::API_EDITOR,
+ "Property '", p_class.name, ".", p_prop.name, "' has type '", prop_class->name,
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
} else {
+ // Look for types that don't inherit Object
TEST_FAIL_COND(!p_context.has_type(prop_type_ref),
"Property type '", prop_type_ref.name, "' not found: '", p_class.name, ".", String(p_prop.name), "'.");
}
@@ -370,10 +377,22 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
}
void validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) {
- const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type);
- if (return_class) {
- TEST_COND(return_class->is_singleton,
- "Method return type is a singleton: '", p_class.name, ".", p_method.name, "'.");
+ if (p_method.return_type.name != StringName()) {
+ const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type);
+ if (return_class) {
+ TEST_COND(return_class->is_singleton,
+ "Method return type is a singleton: '", p_class.name, ".", p_method.name, "'.");
+
+ if (p_class.api_type == ClassDB::API_CORE) {
+ TEST_COND(return_class->api_type == ClassDB::API_EDITOR,
+ "Method '", p_class.name, ".", p_method.name, "' has return type '", return_class->name,
+ "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
+ } else {
+ // Look for types that don't inherit Object
+ TEST_FAIL_COND(!p_context.has_type(p_method.return_type),
+ "Method return type '", p_method.return_type.name, "' not found: '", p_class.name, ".", p_method.name, "'.");
+ }
}
for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) {
@@ -383,7 +402,14 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons
if (arg_class) {
TEST_COND(arg_class->is_singleton,
"Argument type is a singleton: '", arg.name, "' of method '", p_class.name, ".", p_method.name, "'.");
+
+ if (p_class.api_type == ClassDB::API_CORE) {
+ TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
+ "Argument '", arg.name, "' of method '", p_class.name, ".", p_method.name, "' has type '",
+ arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
} else {
+ // Look for types that don't inherit Object
TEST_FAIL_COND(!p_context.has_type(arg.type),
"Argument type '", arg.type.name, "' not found: '", arg.name, "' of method", p_class.name, ".", p_method.name, "'.");
}
@@ -407,8 +433,15 @@ void validate_signal(const Context &p_context, const ExposedClass &p_class, cons
const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
if (arg_class) {
TEST_COND(arg_class->is_singleton,
- "Argument class is a singleton: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'.");
+ "Argument class is a singleton: '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "'.");
+
+ if (p_class.api_type == ClassDB::API_CORE) {
+ TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
+ "Argument '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "' has type '",
+ arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
+ }
} else {
+ // Look for types that don't inherit Object
TEST_FAIL_COND(!p_context.has_type(arg.type),
"Argument type '", arg.type.name, "' not found: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'.");
}
diff --git a/tests/test_command_queue.h b/tests/test_command_queue.h
index b4fa63ad2b..2f0f62f5c8 100644
--- a/tests/test_command_queue.h
+++ b/tests/test_command_queue.h
@@ -31,14 +31,14 @@
#ifndef TEST_COMMAND_QUEUE_H
#define TEST_COMMAND_QUEUE_H
-#include "test_command_queue.h"
-
#include "core/config/project_settings.h"
+#include "core/math/random_number_generator.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/command_queue_mt.h"
+#include "test_macros.h"
#if !defined(NO_THREADS)
diff --git a/tests/test_dictionary.h b/tests/test_dictionary.h
new file mode 100644
index 0000000000..b94cf36109
--- /dev/null
+++ b/tests/test_dictionary.h
@@ -0,0 +1,159 @@
+/*************************************************************************/
+/* test_dictionary.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_DICTIONARY_H
+#define TEST_DICTIONARY_H
+
+#include "core/templates/ordered_hash_map.h"
+#include "core/templates/safe_refcount.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "tests/test_macros.h"
+
+namespace TestDictionary {
+
+TEST_CASE("[Dictionary] Assignment using bracket notation ([])") {
+ Dictionary map;
+ map["Hello"] = 0;
+ CHECK(int(map["Hello"]) == 0);
+ map["Hello"] = 3;
+ CHECK(int(map["Hello"]) == 3);
+ map["World!"] = 4;
+ CHECK(int(map["World!"]) == 4);
+
+ // Test non-string keys, since keys can be of any Variant type.
+ map[12345] = -5;
+ CHECK(int(map[12345]) == -5);
+ map[false] = 128;
+ CHECK(int(map[false]) == 128);
+ map[Vector2(10, 20)] = 30;
+ CHECK(int(map[Vector2(10, 20)]) == 30);
+ map[0] = 400;
+ CHECK(int(map[0]) == 400);
+ // Check that assigning 0 doesn't overwrite the value for `false`.
+ CHECK(int(map[false]) == 128);
+}
+
+TEST_CASE("[Dictionary] == and != operators") {
+ Dictionary map1;
+ Dictionary map2;
+ CHECK(map1 != map2);
+ map1[1] = 3;
+ map2 = map1;
+ CHECK(map1 == map2);
+}
+
+TEST_CASE("[Dictionary] get_key_lists()") {
+ Dictionary map;
+ List<Variant> keys;
+ List<Variant> *ptr = &keys;
+ map.get_key_list(ptr);
+ CHECK(keys.is_empty());
+ map[1] = 3;
+ map.get_key_list(ptr);
+ CHECK(keys.size() == 1);
+ CHECK(int(keys[0]) == 1);
+ map[2] = 4;
+ map.get_key_list(ptr);
+ CHECK(keys.size() == 3);
+}
+
+TEST_CASE("[Dictionary] get_key_at_index()") {
+ Dictionary map;
+ map[4] = 3;
+ Variant val = map.get_key_at_index(0);
+ CHECK(int(val) == 4);
+ map[3] = 1;
+ val = map.get_key_at_index(0);
+ CHECK(int(val) == 4);
+ val = map.get_key_at_index(1);
+ CHECK(int(val) == 3);
+}
+
+TEST_CASE("[Dictionary] getptr()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant *key = map.getptr(1);
+ CHECK(int(*key) == 3);
+ key = map.getptr(2);
+ CHECK(key == nullptr);
+}
+
+TEST_CASE("[Dictionary] get_valid()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant val = map.get_valid(1);
+ CHECK(int(val) == 3);
+}
+TEST_CASE("[Dictionary] get()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant val = map.get(1, -1);
+ CHECK(int(val) == 3);
+}
+
+TEST_CASE("[Dictionary] size(), empty() and clear()") {
+ Dictionary map;
+ CHECK(map.size() == 0);
+ CHECK(map.is_empty());
+ map[1] = 3;
+ CHECK(map.size() == 1);
+ CHECK(!map.is_empty());
+ map.clear();
+ CHECK(map.size() == 0);
+ CHECK(map.is_empty());
+}
+
+TEST_CASE("[Dictionary] has() and has_all()") {
+ Dictionary map;
+ CHECK(map.has(1) == false);
+ map[1] = 3;
+ CHECK(map.has(1));
+ Array keys;
+ keys.push_back(1);
+ CHECK(map.has_all(keys));
+ keys.push_back(2);
+ CHECK(map.has_all(keys) == false);
+}
+
+TEST_CASE("[Dictionary] keys() and values()") {
+ Dictionary map;
+ Array keys = map.keys();
+ Array values = map.values();
+ CHECK(keys.is_empty());
+ CHECK(values.is_empty());
+ map[1] = 3;
+ keys = map.keys();
+ values = map.values();
+ CHECK(int(keys[0]) == 1);
+ CHECK(int(values[0]) == 3);
+}
+} // namespace TestDictionary
+#endif // TEST_DICTIONARY_H
diff --git a/tests/test_geometry_2d.h b/tests/test_geometry_2d.h
index ea02d1114f..c9313f3625 100644
--- a/tests/test_geometry_2d.h
+++ b/tests/test_geometry_2d.h
@@ -113,7 +113,7 @@ TEST_CASE("[Geometry2D] Polygon clockwise") {
p.push_back(Vector2(1, 5));
CHECK(Geometry2D::is_polygon_clockwise(p));
- p.invert();
+ p.reverse();
CHECK_FALSE(Geometry2D::is_polygon_clockwise(p));
}
diff --git a/tests/test_geometry_3d.h b/tests/test_geometry_3d.h
new file mode 100644
index 0000000000..2b2a424b2b
--- /dev/null
+++ b/tests/test_geometry_3d.h
@@ -0,0 +1,417 @@
+/*************************************************************************/
+/* test_geometry_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_3D_GEOMETRY_H
+#define TEST_3D_GEOMETRY_H
+
+#include "core/math/geometry_3d.h"
+#include "core/math/plane.h"
+#include "core/math/random_number_generator.h"
+#include "core/math/vector3.h"
+#include "tests/test_macros.h"
+#include "vector"
+
+namespace Test3DGeometry {
+TEST_CASE("[Geometry3D] Closest Points Between Segments") {
+ struct Case {
+ Vector3 p_1, p_2, p_3, p_4;
+ Vector3 got_1, got_2;
+ Vector3 want_1, want_2;
+ Case(){};
+ Case(Vector3 p_p_1, Vector3 p_p_2, Vector3 p_p_3, Vector3 p_p_4, Vector3 p_want_1, Vector3 p_want_2) :
+ p_1(p_p_1), p_2(p_p_2), p_3(p_p_3), p_4(p_p_4), want_1(p_want_1), want_2(p_want_2){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(1, -1, 1), Vector3(1, 1, -1), Vector3(-1, -2, -1), Vector3(-1, 1, 1), Vector3(1, -0.2, 0.2), Vector3(-1, -0.2, 0.2)));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Geometry3D::get_closest_points_between_segments(current_case.p_1, current_case.p_2, current_case.p_3, current_case.p_4, current_case.got_1, current_case.got_2);
+ CHECK(current_case.got_1.is_equal_approx(current_case.want_1));
+ CHECK(current_case.got_2.is_equal_approx(current_case.want_2));
+ }
+}
+TEST_CASE("[Geometry3D] Closest Distance Between Segments") {
+ struct Case {
+ Vector3 p_1, p_2, p_3, p_4;
+ float want;
+ Case(){};
+ Case(Vector3 p_p_1, Vector3 p_p_2, Vector3 p_p_3, Vector3 p_p_4, float p_want) :
+ p_1(p_p_1), p_2(p_p_2), p_3(p_p_3), p_4(p_p_4), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(1, -2, 0), Vector3(1, 2, 0), Vector3(-1, 2, 0), Vector3(-1, -2, 0), 0.0f));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ float out = Geometry3D::get_closest_distance_between_segments(current_case.p_1, current_case.p_2, current_case.p_3, current_case.p_4);
+ CHECK(out == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Build Box Planes") {
+ const Vector3 extents = Vector3(5, 5, 20);
+ Vector<Plane> box = Geometry3D::build_box_planes(extents);
+ CHECK(box.size() == 6);
+ CHECK(extents.x == box[0].d);
+ CHECK(box[0].normal == Vector3(1, 0, 0));
+ CHECK(extents.x == box[1].d);
+ CHECK(box[1].normal == Vector3(-1, 0, 0));
+ CHECK(extents.y == box[2].d);
+ CHECK(box[2].normal == Vector3(0, 1, 0));
+ CHECK(extents.y == box[3].d);
+ CHECK(box[3].normal == Vector3(0, -1, 0));
+ CHECK(extents.z == box[4].d);
+ CHECK(box[4].normal == Vector3(0, 0, 1));
+ CHECK(extents.z == box[5].d);
+ CHECK(box[5].normal == Vector3(0, 0, -1));
+}
+TEST_CASE("[Geometry3D] Build Capsule Planes") {
+ struct Case {
+ real_t radius, height;
+ int sides, lats;
+ Vector3::Axis axis;
+ int want_size;
+ Case(){};
+ Case(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis, int p_want) :
+ radius(p_radius), height(p_height), sides(p_sides), lats(p_lats), axis(p_axis), want_size(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(10, 20, 6, 10, Vector3::Axis(), 126));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector<Plane> capsule = Geometry3D::build_capsule_planes(current_case.radius, current_case.height, current_case.sides, current_case.lats, current_case.axis);
+ // Should equal (p_sides * p_lats) * 2 + p_sides
+ CHECK(capsule.size() == current_case.want_size);
+ }
+}
+TEST_CASE("[Geometry3D] Build Cylinder Planes") {
+ struct Case {
+ real_t radius, height;
+ int sides;
+ Vector3::Axis axis;
+ int want_size;
+ Case(){};
+ Case(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis, int p_want) :
+ radius(p_radius), height(p_height), sides(p_sides), axis(p_axis), want_size(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(3.0f, 10.0f, 10, Vector3::Axis(), 12));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector<Plane> planes = Geometry3D::build_cylinder_planes(current_case.radius, current_case.height, current_case.sides, current_case.axis);
+ CHECK(planes.size() == current_case.want_size);
+ }
+}
+TEST_CASE("[Geometry3D] Build Sphere Planes") {
+ struct Case {
+ real_t radius;
+ int lats, lons;
+ Vector3::Axis axis;
+ int want_size;
+ Case(){};
+ Case(real_t p_radius, int p_lat, int p_lons, Vector3::Axis p_axis, int p_want) :
+ radius(p_radius), lats(p_lat), lons(p_lons), axis(p_axis), want_size(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(10.0f, 10, 3, Vector3::Axis(), 63));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector<Plane> planes = Geometry3D::build_sphere_planes(current_case.radius, current_case.lats, current_case.lons, current_case.axis);
+ CHECK(planes.size() == 63);
+ }
+}
+TEST_CASE("[Geometry3D] Build Convex Mesh") {
+ struct Case {
+ Vector<Plane> object;
+ int want_faces, want_edges, want_vertices;
+ Case(){};
+ Case(Vector<Plane> p_object, int p_want_faces, int p_want_edges, int p_want_vertices) :
+ object(p_object), want_faces(p_want_faces), want_edges(p_want_edges), want_vertices(p_want_vertices){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Geometry3D::build_box_planes(Vector3(5, 10, 5)), 6, 12, 8));
+ tt.push_back(Case(Geometry3D::build_capsule_planes(5, 5, 20, 20, Vector3::Axis()), 820, 7603, 6243));
+ tt.push_back(Case(Geometry3D::build_cylinder_planes(5, 5, 20, Vector3::Axis()), 22, 100, 80));
+ tt.push_back(Case(Geometry3D::build_sphere_planes(5, 5, 20), 220, 1011, 522));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Geometry3D::MeshData mesh = Geometry3D::build_convex_mesh(current_case.object);
+ CHECK(mesh.faces.size() == current_case.want_faces);
+ CHECK(mesh.edges.size() == current_case.want_edges);
+ CHECK(mesh.vertices.size() == current_case.want_vertices);
+ }
+}
+TEST_CASE("[Geometry3D] Clip Polygon") {
+ struct Case {
+ Plane clipping_plane;
+ Vector<Vector3> polygon;
+ bool want;
+ Case(){};
+ Case(Plane p_clipping_plane, Vector<Vector3> p_polygon, bool p_want) :
+ clipping_plane(p_clipping_plane), polygon(p_polygon), want(p_want){};
+ };
+ Vector<Case> tt;
+ Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 10, 5));
+ Vector<Vector3> box = Geometry3D::compute_convex_mesh_points(&box_planes[0], box_planes.size());
+ tt.push_back(Case(Plane(), box, true));
+ tt.push_back(Case(Plane(Vector3(0, 3, 0), Vector3(0, 1, 0)), box, false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector<Vector3> output = Geometry3D::clip_polygon(current_case.polygon, current_case.clipping_plane);
+ if (current_case.want) {
+ CHECK(output == current_case.polygon);
+ } else {
+ CHECK(output != current_case.polygon);
+ }
+ }
+}
+TEST_CASE("[Geometry3D] Compute Convex Mesh Points") {
+ struct Case {
+ Vector<Plane> mesh;
+ Vector<Vector3> want;
+ Case(){};
+ Case(Vector<Plane> p_mesh, Vector<Vector3> p_want) :
+ mesh(p_mesh), want(p_want){};
+ };
+ Vector<Case> tt;
+ Vector<Vector3> cube;
+ cube.push_back(Vector3(-5, -5, -5));
+ cube.push_back(Vector3(5, -5, -5));
+ cube.push_back(Vector3(-5, 5, -5));
+ cube.push_back(Vector3(5, 5, -5));
+ cube.push_back(Vector3(-5, -5, 5));
+ cube.push_back(Vector3(5, -5, 5));
+ cube.push_back(Vector3(-5, 5, 5));
+ cube.push_back(Vector3(5, 5, 5));
+ tt.push_back(Case(Geometry3D::build_box_planes(Vector3(5, 5, 5)), cube));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector<Vector3> vectors = Geometry3D::compute_convex_mesh_points(&current_case.mesh[0], current_case.mesh.size());
+ CHECK(vectors == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Get Closest Point To Segment") {
+ struct Case {
+ Vector3 point;
+ Vector<Vector3> segment;
+ Vector3 want;
+ Case(){};
+ Case(Vector3 p_point, Vector<Vector3> p_segment, Vector3 p_want) :
+ point(p_point), segment(p_segment), want(p_want){};
+ };
+ Vector<Case> tt;
+ Vector<Vector3> test_segment;
+ test_segment.push_back(Vector3(1, 1, 1));
+ test_segment.push_back(Vector3(5, 5, 5));
+ tt.push_back(Case(Vector3(2, 1, 4), test_segment, Vector3(2.33333, 2.33333, 2.33333)));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ Vector3 output = Geometry3D::get_closest_point_to_segment(current_case.point, &current_case.segment[0]);
+ CHECK(output.is_equal_approx(current_case.want));
+ }
+}
+TEST_CASE("[Geometry3D] Plane and Box Overlap") {
+ struct Case {
+ Vector3 normal, max_box;
+ float d;
+ bool want;
+ Case(){};
+ Case(Vector3 p_normal, float p_d, Vector3 p_max_box, bool p_want) :
+ normal(p_normal), max_box(p_max_box), d(p_d), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(3, 4, 2), 5, Vector3(5, 5, 5), true));
+ tt.push_back(Case(Vector3(0, 1, 0), -10, Vector3(5, 5, 5), false));
+ tt.push_back(Case(Vector3(1, 0, 0), -6, Vector3(5, 5, 5), false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool overlap = Geometry3D::planeBoxOverlap(current_case.normal, current_case.d, current_case.max_box);
+ CHECK(overlap == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Is Point in Projected Triangle") {
+ struct Case {
+ Vector3 point, v_1, v_2, v_3;
+ bool want;
+ Case(){};
+ Case(Vector3 p_point, Vector3 p_v_1, Vector3 p_v_2, Vector3 p_v_3, bool p_want) :
+ point(p_point), v_1(p_v_1), v_2(p_v_2), v_3(p_v_3), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(1, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0), true));
+ tt.push_back(Case(Vector3(5, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0), false));
+ tt.push_back(Case(Vector3(3, 0, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0), true));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::point_in_projected_triangle(current_case.point, current_case.v_1, current_case.v_2, current_case.v_3);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Does Ray Intersect Triangle") {
+ struct Case {
+ Vector3 from, direction, v_1, v_2, v_3;
+ Vector3 *result;
+ bool want;
+ Case(){};
+ Case(Vector3 p_from, Vector3 p_direction, Vector3 p_v_1, Vector3 p_v_2, Vector3 p_v_3, bool p_want) :
+ from(p_from), direction(p_direction), v_1(p_v_1), v_2(p_v_2), v_3(p_v_3), result(nullptr), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(0, 1, 1), Vector3(0, 0, -10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), true));
+ tt.push_back(Case(Vector3(5, 10, 1), Vector3(0, 0, -10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), false));
+ tt.push_back(Case(Vector3(0, 1, 1), Vector3(0, 0, 10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::ray_intersects_triangle(current_case.from, current_case.direction, current_case.v_1, current_case.v_2, current_case.v_3, current_case.result);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Does Segment Intersect Convex") {
+ struct Case {
+ Vector3 from, to;
+ Vector<Plane> planes;
+ Vector3 *result, *normal;
+ bool want;
+ Case(){};
+ Case(Vector3 p_from, Vector3 p_to, Vector<Plane> p_planes, bool p_want) :
+ from(p_from), to(p_to), planes(p_planes), result(nullptr), normal(nullptr), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(0, 0, 0), Geometry3D::build_box_planes(Vector3(5, 5, 5)), true));
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(5, 5, 5), Geometry3D::build_box_planes(Vector3(5, 5, 5)), true));
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(6, 5, 5), Geometry3D::build_box_planes(Vector3(5, 5, 5)), false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::segment_intersects_convex(current_case.from, current_case.to, &current_case.planes[0], current_case.planes.size(), current_case.result, current_case.normal);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
+ struct Case {
+ Vector3 from, to;
+ real_t height, radius;
+ Vector3 *result, *normal;
+ bool want;
+ Case(){};
+ Case(Vector3 p_from, Vector3 p_to, real_t p_height, real_t p_radius, bool p_want) :
+ from(p_from), to(p_to), height(p_height), radius(p_radius), result(nullptr), normal(nullptr), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(0, 0, 0), 5, 5, true));
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(6, 6, 6), 5, 5, false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::segment_intersects_cylinder(current_case.from, current_case.to, current_case.height, current_case.radius, current_case.result, current_case.normal);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
+ struct Case {
+ Vector3 from, to, sphere_pos;
+ real_t radius;
+ Vector3 *result, *normal;
+ bool want;
+ Case(){};
+ Case(Vector3 p_from, Vector3 p_to, Vector3 p_sphere_pos, real_t p_radius, bool p_want) :
+ from(p_from), to(p_to), sphere_pos(p_sphere_pos), radius(p_radius), result(nullptr), normal(nullptr), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(0, 0, 0), Vector3(0, 0, 0), 5, true));
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(0, 0, 2.5), Vector3(0, 0, 0), 5, true));
+ tt.push_back(Case(Vector3(10, 10, 10), Vector3(5, 5, 5), Vector3(0, 0, 0), 5, false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::segment_intersects_sphere(current_case.from, current_case.to, current_case.sphere_pos, current_case.radius, current_case.result, current_case.normal);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Segment Intersects Triangle") {
+ struct Case {
+ Vector3 from, to, v_1, v_2, v_3, *result;
+ bool want;
+ Case(){};
+ Case(Vector3 p_from, Vector3 p_to, Vector3 p_v_1, Vector3 p_v_2, Vector3 p_v_3, bool p_want) :
+ from(p_from), to(p_to), v_1(p_v_1), v_2(p_v_2), v_3(p_v_3), result(nullptr), want(p_want){};
+ };
+ Vector<Case> tt;
+ tt.push_back(Case(Vector3(1, 1, 1), Vector3(-1, -1, -1), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), true));
+ tt.push_back(Case(Vector3(1, 1, 1), Vector3(3, 0, 0), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), true));
+ tt.push_back(Case(Vector3(1, 1, 1), Vector3(10, -1, -1), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::segment_intersects_triangle(current_case.from, current_case.to, current_case.v_1, current_case.v_2, current_case.v_3, current_case.result);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
+ struct Case {
+ Vector3 box_centre;
+ Vector3 box_half_size;
+ Vector3 *tri_verts;
+ bool want;
+ Case(){};
+ Case(Vector3 p_centre, Vector3 p_half_size, Vector3 *p_verts, bool p_want) :
+ box_centre(p_centre), box_half_size(p_half_size), tri_verts(p_verts), want(p_want){};
+ };
+ Vector<Case> tt;
+ Vector3 GoodTriangle[3] = { Vector3(3, 2, 3), Vector3(2, 2, 1), Vector3(2, 1, 1) };
+ tt.push_back(Case(Vector3(0, 0, 0), Vector3(5, 5, 5), GoodTriangle, true));
+ Vector3 BadTriangle[3] = { Vector3(100, 100, 100), Vector3(-100, -100, -100), Vector3(10, 10, 10) };
+ tt.push_back(Case(Vector3(1000, 1000, 1000), Vector3(1, 1, 1), BadTriangle, false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::triangle_box_overlap(current_case.box_centre, current_case.box_half_size, current_case.tri_verts);
+ CHECK(output == current_case.want);
+ }
+}
+TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") {
+ struct Case {
+ Vector<Vector3> triangle;
+ Vector3 normal, sphere_pos, triangle_contact, sphere_contact;
+ real_t sphere_radius;
+ bool want;
+ Case(){};
+ Case(Vector<Vector3> p_triangle, Vector3 p_normal, Vector3 p_sphere_pos, real_t p_sphere_radius, bool p_want) :
+ triangle(p_triangle), normal(p_normal), sphere_pos(p_sphere_pos), triangle_contact(Vector3()), sphere_contact(Vector3()), sphere_radius(p_sphere_radius), want(p_want){};
+ };
+ Vector<Case> tt;
+ Vector<Vector3> triangle;
+ triangle.push_back(Vector3(3, 0, 0));
+ triangle.push_back(Vector3(-3, 0, 0));
+ triangle.push_back(Vector3(0, 3, 0));
+ tt.push_back(Case(triangle, Vector3(0, -1, 0), Vector3(0, 0, 0), 5, true));
+ tt.push_back(Case(triangle, Vector3(0, 1, 0), Vector3(0, 0, 0), 5, true));
+ tt.push_back(Case(triangle, Vector3(0, 1, 0), Vector3(20, 0, 0), 5, false));
+ for (int i = 0; i < tt.size(); ++i) {
+ Case current_case = tt[i];
+ bool output = Geometry3D::triangle_sphere_intersection_test(&current_case.triangle[0], current_case.normal, current_case.sphere_pos, current_case.sphere_radius, current_case.triangle_contact, current_case.sphere_contact);
+ CHECK(output == current_case.want);
+ }
+}
+} // namespace Test3DGeometry
+#endif
diff --git a/tests/test_hashing_context.h b/tests/test_hashing_context.h
new file mode 100644
index 0000000000..728a5f2cfa
--- /dev/null
+++ b/tests/test_hashing_context.h
@@ -0,0 +1,165 @@
+/*************************************************************************/
+/* test_hashing_context.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_HASHING_CONTEXT_H
+#define TEST_HASHING_CONTEXT_H
+
+#include "core/crypto/hashing_context.h"
+
+#include "tests/test_macros.h"
+
+namespace TestHashingContext {
+
+TEST_CASE("[HashingContext] Default - MD5/SHA1/SHA256") {
+ HashingContext ctx;
+
+ static const uint8_t md5_expected[] = {
+ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
+ };
+ static const uint8_t sha1_expected[] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
+ 0xaf, 0xd8, 0x07, 0x09
+ };
+ static const uint8_t sha256_expected[] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
+ };
+
+ CHECK(ctx.start(HashingContext::HASH_MD5) == OK);
+ PackedByteArray result = ctx.finish();
+ REQUIRE(result.size() == 16);
+ CHECK(memcmp(result.ptr(), md5_expected, 16) == 0);
+
+ CHECK(ctx.start(HashingContext::HASH_SHA1) == OK);
+ result = ctx.finish();
+ REQUIRE(result.size() == 20);
+ CHECK(memcmp(result.ptr(), sha1_expected, 20) == 0);
+
+ CHECK(ctx.start(HashingContext::HASH_SHA256) == OK);
+ result = ctx.finish();
+ REQUIRE(result.size() == 32);
+ CHECK(memcmp(result.ptr(), sha256_expected, 32) == 0);
+}
+
+TEST_CASE("[HashingContext] Multiple updates - MD5/SHA1/SHA256") {
+ HashingContext ctx;
+ const String s = "xyz";
+
+ const PackedByteArray s_byte_parts[] = {
+ String("x").to_ascii_buffer(),
+ String("y").to_ascii_buffer(),
+ String("z").to_ascii_buffer()
+ };
+
+ static const uint8_t md5_expected[] = {
+ 0xd1, 0x6f, 0xb3, 0x6f, 0x09, 0x11, 0xf8, 0x78, 0x99, 0x8c, 0x13, 0x61, 0x91, 0xaf, 0x70, 0x5e
+ };
+ static const uint8_t sha1_expected[] = {
+ 0x66, 0xb2, 0x74, 0x17, 0xd3, 0x7e, 0x02, 0x4c, 0x46, 0x52, 0x6c, 0x2f, 0x6d, 0x35, 0x8a, 0x75,
+ 0x4f, 0xc5, 0x52, 0xf3
+ };
+ static const uint8_t sha256_expected[] = {
+ 0x36, 0x08, 0xbc, 0xa1, 0xe4, 0x4e, 0xa6, 0xc4, 0xd2, 0x68, 0xeb, 0x6d, 0xb0, 0x22, 0x60, 0x26,
+ 0x98, 0x92, 0xc0, 0xb4, 0x2b, 0x86, 0xbb, 0xf1, 0xe7, 0x7a, 0x6f, 0xa1, 0x6c, 0x3c, 0x92, 0x82
+ };
+
+ CHECK(ctx.start(HashingContext::HASH_MD5) == OK);
+ CHECK(ctx.update(s_byte_parts[0]) == OK);
+ CHECK(ctx.update(s_byte_parts[1]) == OK);
+ CHECK(ctx.update(s_byte_parts[2]) == OK);
+ PackedByteArray result = ctx.finish();
+ REQUIRE(result.size() == 16);
+ CHECK(memcmp(result.ptr(), md5_expected, 16) == 0);
+
+ CHECK(ctx.start(HashingContext::HASH_SHA1) == OK);
+ CHECK(ctx.update(s_byte_parts[0]) == OK);
+ CHECK(ctx.update(s_byte_parts[1]) == OK);
+ CHECK(ctx.update(s_byte_parts[2]) == OK);
+ result = ctx.finish();
+ REQUIRE(result.size() == 20);
+ CHECK(memcmp(result.ptr(), sha1_expected, 20) == 0);
+
+ CHECK(ctx.start(HashingContext::HASH_SHA256) == OK);
+ CHECK(ctx.update(s_byte_parts[0]) == OK);
+ CHECK(ctx.update(s_byte_parts[1]) == OK);
+ CHECK(ctx.update(s_byte_parts[2]) == OK);
+ result = ctx.finish();
+ REQUIRE(result.size() == 32);
+ CHECK(memcmp(result.ptr(), sha256_expected, 32) == 0);
+}
+
+TEST_CASE("[HashingContext] Invalid use of start") {
+ HashingContext ctx;
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ ctx.start(static_cast<HashingContext::HashType>(-1)) == ERR_UNAVAILABLE,
+ "Using invalid hash types should fail.");
+ ERR_PRINT_ON;
+
+ REQUIRE(ctx.start(HashingContext::HASH_MD5) == OK);
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ ctx.start(HashingContext::HASH_MD5) == ERR_ALREADY_IN_USE,
+ "Calling 'start' twice before 'finish' should fail.");
+ ERR_PRINT_ON;
+}
+
+TEST_CASE("[HashingContext] Invalid use of update") {
+ HashingContext ctx;
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ ctx.update(PackedByteArray()) == ERR_UNCONFIGURED,
+ "Calling 'update' before 'start' should fail.");
+ ERR_PRINT_ON;
+
+ REQUIRE(ctx.start(HashingContext::HASH_MD5) == OK);
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ ctx.update(PackedByteArray()) == FAILED,
+ "Calling 'update' with an empty byte array should fail.");
+ ERR_PRINT_ON;
+}
+
+TEST_CASE("[HashingContext] Invalid use of finish") {
+ HashingContext ctx;
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ ctx.finish() == PackedByteArray(),
+ "Calling 'finish' before 'start' should return an empty byte array.");
+ ERR_PRINT_ON;
+}
+} // namespace TestHashingContext
+
+#endif // TEST_HASHING_CONTEXT_H
diff --git a/tests/test_list.h b/tests/test_list.h
index 1c70b6e961..52d5edff70 100644
--- a/tests/test_list.h
+++ b/tests/test_list.h
@@ -260,7 +260,7 @@ TEST_CASE("[List] Invert") {
List<int>::Element *n[4];
populate_integers(list, n, 4);
- list.invert();
+ list.reverse();
CHECK(list.front()->get() == 3);
CHECK(list.front()->next()->get() == 2);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 2697eb6399..d06d604532 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -33,6 +33,7 @@
#include "core/templates/list.h"
#include "test_aabb.h"
+#include "test_array.h"
#include "test_astar.h"
#include "test_basis.h"
#include "test_class_db.h"
@@ -41,11 +42,14 @@
#include "test_config_file.h"
#include "test_crypto.h"
#include "test_curve.h"
+#include "test_dictionary.h"
#include "test_expression.h"
#include "test_file_access.h"
#include "test_geometry_2d.h"
+#include "test_geometry_3d.h"
#include "test_gradient.h"
#include "test_gui.h"
+#include "test_hashing_context.h"
#include "test_image.h"
#include "test_json.h"
#include "test_list.h"
@@ -59,17 +63,20 @@
#include "test_object.h"
#include "test_ordered_hash_map.h"
#include "test_paged_array.h"
+#include "test_path_3d.h"
#include "test_pck_packer.h"
#include "test_physics_2d.h"
#include "test_physics_3d.h"
#include "test_random_number_generator.h"
#include "test_rect2.h"
#include "test_render.h"
+#include "test_resource.h"
#include "test_shader_lang.h"
#include "test_string.h"
#include "test_text_server.h"
#include "test_validate_testing.h"
#include "test_variant.h"
+#include "test_xml_parser.h"
#include "modules/modules_tests.gen.h"
diff --git a/editor/import/resource_importer_csv.cpp b/tests/test_path_3d.h
index f621ce7855..9961ae6e97 100644
--- a/editor/import/resource_importer_csv.cpp
+++ b/tests/test_path_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* resource_importer_csv.cpp */
+/* test_path_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,49 +28,58 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "resource_importer_csv.h"
+#ifndef TEST_PATH_3D_H
+#define TEST_PATH_3D_H
-#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
+#include "scene/3d/path_3d.h"
+#include "scene/resources/curve.h"
-String ResourceImporterCSV::get_importer_name() const {
- return "csv";
-}
+#include "tests/test_macros.h"
-String ResourceImporterCSV::get_visible_name() const {
- return "CSV";
-}
+namespace TestPath3D {
-void ResourceImporterCSV::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("csv");
+TEST_CASE("[Path3D] Initialization") {
+ SUBCASE("Path should be empty right after initialization") {
+ Path3D *test_path = memnew(Path3D);
+ CHECK(test_path->get_curve() == nullptr);
+ memdelete(test_path);
+ }
}
-String ResourceImporterCSV::get_save_extension() const {
- return ""; //does not save a single resource
-}
+TEST_CASE("[Path3D] Curve setter and getter") {
+ SUBCASE("Curve passed to the class should remain the same") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve = memnew(Curve3D);
-String ResourceImporterCSV::get_resource_type() const {
- return "TextFile";
-}
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ memdelete(test_path);
+ }
+ SUBCASE("Curve passed many times to the class should remain the same") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve = memnew(Curve3D);
-bool ResourceImporterCSV::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
- return true;
-}
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ memdelete(test_path);
+ }
+ SUBCASE("Curve rewrite testing") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve1 = memnew(Curve3D);
+ const Ref<Curve3D> &curve2 = memnew(Curve3D);
-int ResourceImporterCSV::get_preset_count() const {
- return 0;
+ test_path->set_curve(curve1);
+ test_path->set_curve(curve2);
+ CHECK_MESSAGE(test_path->get_curve() != curve1,
+ "After rewrite, second curve should be in class");
+ CHECK_MESSAGE(test_path->get_curve() == curve2,
+ "After rewrite, second curve should be in class");
+ memdelete(test_path);
+ }
}
-String ResourceImporterCSV::get_preset_name(int p_idx) const {
- return "";
-}
+} // namespace TestPath3D
-void ResourceImporterCSV::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-}
-
-Error ResourceImporterCSV::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
- return OK;
-}
-
-ResourceImporterCSV::ResourceImporterCSV() {
-}
+#endif // TEST_PATH_3D
diff --git a/tests/test_path_follow_2d.h b/tests/test_path_follow_2d.h
new file mode 100644
index 0000000000..388b690060
--- /dev/null
+++ b/tests/test_path_follow_2d.h
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* test_path_follow_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_PATH_FOLLOW_2D_H
+#define TEST_PATH_FOLLOW_2D_H
+
+#include "scene/2d/path_2d.h"
+#include "scene/resources/curve.h"
+
+#include "tests/test_macros.h"
+
+namespace TestPathFollow2D {
+
+TEST_CASE("[PathFollow2D] Sampling with unit offset") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ curve->add_point(Vector2(100, 100));
+ curve->add_point(Vector2(0, 100));
+ curve->add_point(Vector2(0, 0));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_unit_offset(0);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
+
+ path_follow_2d->set_unit_offset(0.125);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
+
+ path_follow_2d->set_unit_offset(0.25);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
+
+ path_follow_2d->set_unit_offset(0.375);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50)));
+
+ path_follow_2d->set_unit_offset(0.5);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100)));
+
+ path_follow_2d->set_unit_offset(0.625);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100)));
+
+ path_follow_2d->set_unit_offset(0.75);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100)));
+
+ path_follow_2d->set_unit_offset(0.875);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50)));
+
+ path_follow_2d->set_unit_offset(1);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow2D] Sampling with offset") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ curve->add_point(Vector2(100, 100));
+ curve->add_point(Vector2(0, 100));
+ curve->add_point(Vector2(0, 0));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_offset(0);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
+
+ path_follow_2d->set_offset(50);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
+
+ path_follow_2d->set_offset(100);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
+
+ path_follow_2d->set_offset(150);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50)));
+
+ path_follow_2d->set_offset(200);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100)));
+
+ path_follow_2d->set_offset(250);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100)));
+
+ path_follow_2d->set_offset(300);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100)));
+
+ path_follow_2d->set_offset(350);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50)));
+
+ path_follow_2d->set_offset(400);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow2D] Removal of a point in curve") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ curve->add_point(Vector2(100, 100));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_unit_offset(0.5);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
+
+ curve->remove_point(1);
+
+ CHECK_MESSAGE(
+ path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 50)),
+ "Path follow's position should be updated after removing a point from the curve");
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow2D] Setting h_offset and v_offset") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_unit_offset(0.5);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
+
+ path_follow_2d->set_h_offset(25);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(75, 0)));
+
+ path_follow_2d->set_v_offset(25);
+ CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(75, 25)));
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow2D] Unit offset out of range") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_loop(true);
+
+ path_follow_2d->set_unit_offset(-0.3);
+ CHECK_MESSAGE(
+ path_follow_2d->get_unit_offset() == 0.7,
+ "Unit Offset should loop back from the end in the opposite direction");
+
+ path_follow_2d->set_unit_offset(1.3);
+ CHECK_MESSAGE(
+ path_follow_2d->get_unit_offset() == 0.3,
+ "Unit Offset should loop back from the end in the opposite direction");
+
+ path_follow_2d->set_loop(false);
+
+ path_follow_2d->set_unit_offset(-0.3);
+ CHECK_MESSAGE(
+ path_follow_2d->get_unit_offset() == 0,
+ "Unit Offset should be clamped at 0");
+
+ path_follow_2d->set_unit_offset(1.3);
+ CHECK_MESSAGE(
+ path_follow_2d->get_unit_offset() == 1,
+ "Unit Offset should be clamped at 1");
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow2D] Offset out of range") {
+ const Ref<Curve2D> &curve = memnew(Curve2D());
+ curve->add_point(Vector2(0, 0));
+ curve->add_point(Vector2(100, 0));
+ const Path2D *path = memnew(Path2D);
+ path->set_curve(curve);
+ const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
+ path->add_child(path_follow_2d);
+
+ path_follow_2d->set_loop(true);
+
+ path_follow_2d->set_offset(-50);
+ CHECK_MESSAGE(
+ path_follow_2d->get_offset() == 50,
+ "Offset should loop back from the end in the opposite direction");
+
+ path_follow_2d->set_offset(150);
+ CHECK_MESSAGE(
+ path_follow_2d->get_offset() == 50,
+ "Offset should loop back from the end in the opposite direction");
+
+ path_follow_2d->set_loop(false);
+
+ path_follow_2d->set_offset(-50);
+ CHECK_MESSAGE(
+ path_follow_2d->get_offset() == 0,
+ "Offset should be clamped at 0");
+
+ path_follow_2d->set_offset(150);
+ CHECK_MESSAGE(
+ path_follow_2d->get_offset() == 100,
+ "Offset should be clamped at 1");
+
+ memdelete(path);
+}
+} // namespace TestPathFollow2D
+
+#endif // TEST_PATH_FOLLOW_2D_H
diff --git a/tests/test_path_follow_3d.h b/tests/test_path_follow_3d.h
new file mode 100644
index 0000000000..b6b4c88222
--- /dev/null
+++ b/tests/test_path_follow_3d.h
@@ -0,0 +1,220 @@
+/*************************************************************************/
+/* test_path_follow_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_PATH_FOLLOW_3D_H
+#define TEST_PATH_FOLLOW_3D_H
+
+#include "scene/3d/path_3d.h"
+#include "scene/resources/curve.h"
+
+#include "tests/test_macros.h"
+
+namespace TestPathFollow3D {
+
+TEST_CASE("[PathFollow3D] Sampling with unit offset") {
+ const Ref<Curve3D> &curve = memnew(Curve3D());
+ curve->add_point(Vector3(0, 0, 0));
+ curve->add_point(Vector3(100, 0, 0));
+ curve->add_point(Vector3(100, 100, 0));
+ curve->add_point(Vector3(100, 100, 100));
+ curve->add_point(Vector3(100, 0, 100));
+ const Path3D *path = memnew(Path3D);
+ path->set_curve(curve);
+ const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
+ path->add_child(path_follow_3d);
+
+ path_follow_3d->set_unit_offset(0);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0));
+
+ path_follow_3d->set_unit_offset(0.125);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0));
+
+ path_follow_3d->set_unit_offset(0.25);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0);
+
+ path_follow_3d->set_unit_offset(0.375);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0)));
+
+ path_follow_3d->set_unit_offset(0.5);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0)));
+
+ path_follow_3d->set_unit_offset(0.625);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50)));
+
+ path_follow_3d->set_unit_offset(0.75);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100)));
+
+ path_follow_3d->set_unit_offset(0.875);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100)));
+
+ path_follow_3d->set_unit_offset(1);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100)));
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow3D] Sampling with offset") {
+ const Ref<Curve3D> &curve = memnew(Curve3D());
+ curve->add_point(Vector3(0, 0, 0));
+ curve->add_point(Vector3(100, 0, 0));
+ curve->add_point(Vector3(100, 100, 0));
+ curve->add_point(Vector3(100, 100, 100));
+ curve->add_point(Vector3(100, 0, 100));
+ const Path3D *path = memnew(Path3D);
+ path->set_curve(curve);
+ const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
+ path->add_child(path_follow_3d);
+
+ path_follow_3d->set_offset(0);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0));
+
+ path_follow_3d->set_offset(50);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0));
+
+ path_follow_3d->set_offset(100);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0);
+
+ path_follow_3d->set_offset(150);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0)));
+
+ path_follow_3d->set_offset(200);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0)));
+
+ path_follow_3d->set_offset(250);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50)));
+
+ path_follow_3d->set_offset(300);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100)));
+
+ path_follow_3d->set_offset(350);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100)));
+
+ path_follow_3d->set_offset(400);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100)));
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow3D] Removal of a point in curve") {
+ const Ref<Curve3D> &curve = memnew(Curve3D());
+ curve->add_point(Vector3(0, 0, 0));
+ curve->add_point(Vector3(100, 0, 0));
+ curve->add_point(Vector3(100, 100, 0));
+ const Path3D *path = memnew(Path3D);
+ path->set_curve(curve);
+ const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
+ path->add_child(path_follow_3d);
+
+ path_follow_3d->set_unit_offset(0.5);
+ CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(100, 0, 0)));
+
+ curve->remove_point(1);
+
+ CHECK_MESSAGE(
+ path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(50, 50, 0)),
+ "Path follow's position should be updated after removing a point from the curve");
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow3D] Unit offset out of range") {
+ const Ref<Curve3D> &curve = memnew(Curve3D());
+ curve->add_point(Vector3(0, 0, 0));
+ curve->add_point(Vector3(100, 0, 0));
+ const Path3D *path = memnew(Path3D);
+ path->set_curve(curve);
+ const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
+ path->add_child(path_follow_3d);
+
+ path_follow_3d->set_loop(true);
+
+ path_follow_3d->set_unit_offset(-0.3);
+ CHECK_MESSAGE(
+ path_follow_3d->get_unit_offset() == 0.7,
+ "Unit Offset should loop back from the end in the opposite direction");
+
+ path_follow_3d->set_unit_offset(1.3);
+ CHECK_MESSAGE(
+ path_follow_3d->get_unit_offset() == 0.3,
+ "Unit Offset should loop back from the end in the opposite direction");
+
+ path_follow_3d->set_loop(false);
+
+ path_follow_3d->set_unit_offset(-0.3);
+ CHECK_MESSAGE(
+ path_follow_3d->get_unit_offset() == 0,
+ "Unit Offset should be clamped at 0");
+
+ path_follow_3d->set_unit_offset(1.3);
+ CHECK_MESSAGE(
+ path_follow_3d->get_unit_offset() == 1,
+ "Unit Offset should be clamped at 1");
+
+ memdelete(path);
+}
+
+TEST_CASE("[PathFollow3D] Offset out of range") {
+ const Ref<Curve3D> &curve = memnew(Curve3D());
+ curve->add_point(Vector3(0, 0, 0));
+ curve->add_point(Vector3(100, 0, 0));
+ const Path3D *path = memnew(Path3D);
+ path->set_curve(curve);
+ const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
+ path->add_child(path_follow_3d);
+
+ path_follow_3d->set_loop(true);
+
+ path_follow_3d->set_offset(-50);
+ CHECK_MESSAGE(
+ path_follow_3d->get_offset() == 50,
+ "Offset should loop back from the end in the opposite direction");
+
+ path_follow_3d->set_offset(150);
+ CHECK_MESSAGE(
+ path_follow_3d->get_offset() == 50,
+ "Offset should loop back from the end in the opposite direction");
+
+ path_follow_3d->set_loop(false);
+
+ path_follow_3d->set_offset(-50);
+ CHECK_MESSAGE(
+ path_follow_3d->get_offset() == 0,
+ "Offset should be clamped at 0");
+
+ path_follow_3d->set_offset(150);
+ CHECK_MESSAGE(
+ path_follow_3d->get_offset() == 100,
+ "Offset should be clamped at max value of curve");
+
+ memdelete(path);
+}
+} // namespace TestPathFollow3D
+
+#endif // TEST_PATH_FOLLOW_3D_H
diff --git a/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp
index 570e1897d6..25b2871890 100644
--- a/tests/test_physics_2d.cpp
+++ b/tests/test_physics_2d.cpp
@@ -216,10 +216,10 @@ protected:
if (mm.is_valid()) {
Point2 p = mm->get_position();
- if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
ray_to = p;
_do_ray_query();
- } else if (mm->get_button_mask() & BUTTON_MASK_RIGHT) {
+ } else if (mm->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) {
ray_from = p;
_do_ray_query();
}
@@ -243,9 +243,7 @@ protected:
Size2 imgsize(5, 5); //vs->texture_get_width(body_shape_data[p_shape].image), vs->texture_get_height(body_shape_data[p_shape].image));
vs->canvas_item_add_texture_rect(sprite, Rect2(-imgsize / 2.0, imgsize), body_shape_data[p_shape].image);
- ps->body_set_force_integration_callback(body, this, "_body_moved", sprite);
- //RID q = ps->query_create(this,"_body_moved",sprite);
- //ps->query_body_state(q,body);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics2DMainLoop::_body_moved), sprite);
return body;
}
@@ -310,7 +308,6 @@ protected:
}
static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved);
ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback);
}
diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp
index f991fd7c86..ac8078a0a8 100644
--- a/tests/test_physics_3d.cpp
+++ b/tests/test_physics_3d.cpp
@@ -77,21 +77,19 @@ class TestPhysics3DMainLoop : public MainLoop {
bool quit;
protected:
- static void _bind_methods() {
- ClassDB::bind_method("body_changed_transform", &TestPhysics3DMainLoop::body_changed_transform);
- }
-
RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) {
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape], scenario);
- RID body = ps->body_create(p_body, !p_active_default);
+ RID body = ps->body_create();
+ ps->body_set_mode(body, p_body);
+ ps->body_set_state(body, PhysicsServer3D::BODY_STATE_SLEEPING, !p_active_default);
ps->body_set_space(body, space);
ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0);
//todo set space
ps->body_add_shape(body, type_shape_map[p_shape]);
- ps->body_set_force_integration_callback(body, this, "body_changed_transform", mesh_instance);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location);
bodies.push_back(body);
@@ -108,7 +106,9 @@ protected:
RID world_margin_shape = ps->shape_create(PhysicsServer3D::SHAPE_PLANE);
ps->shape_set_data(world_margin_shape, p_plane);
- RID b = ps->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ RID b = ps->body_create();
+ ps->body_set_mode(b, PhysicsServer3D::BODY_MODE_STATIC);
+
ps->body_set_space(b, space);
//todo set space
ps->body_add_shape(b, world_margin_shape);
@@ -183,8 +183,10 @@ protected:
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON);
- ps->shape_set_data(trimesh_shape, p_faces);
- p_faces = ps->shape_get_data(trimesh_shape); // optimized one
+ Dictionary trimesh_params;
+ trimesh_params["faces"] = p_faces;
+ trimesh_params["backface_collision"] = false;
+ ps->shape_set_data(trimesh_shape, trimesh_params);
Vector<Vector3> normals; // for drawing
for (int i = 0; i < p_faces.size() / 3; i++) {
Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]);
@@ -202,7 +204,8 @@ protected:
RID triins = vs->instance_create2(trimesh_mesh, scenario);
- RID tribody = ps->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ RID tribody = ps->body_create();
+ ps->body_set_mode(tribody, PhysicsServer3D::BODY_MODE_STATIC);
ps->body_set_space(tribody, space);
//todo set space
ps->body_add_shape(tribody, trimesh_shape);
@@ -358,12 +361,12 @@ public:
ps->shape_set_data(capsule_shape, capsule_params);
RID mesh_instance = vs->instance_create2(capsule_mesh, scenario);
- character = ps->body_create(PhysicsServer3D::BODY_MODE_CHARACTER);
+ character = ps->body_create();
+ ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_CHARACTER);
ps->body_set_space(character, space);
//todo add space
ps->body_add_shape(character, capsule_shape);
-
- ps->body_set_force_integration_callback(character, this, "body_changed_transform", mesh_instance);
+ ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2)));
bodies.push_back(character);
diff --git a/tests/test_render.cpp b/tests/test_render.cpp
index 2a4ae8bd73..72b2840098 100644
--- a/tests/test_render.cpp
+++ b/tests/test_render.cpp
@@ -183,8 +183,8 @@ public:
//vs->light_set_shadow( lightaux, true );
light = vs->instance_create2(lightaux, scenario);
Transform lla;
- //lla.set_look_at(Vector3(),Vector3(1,-1,1),Vector3(0,1,0));
- lla.set_look_at(Vector3(), Vector3(-0.000000, -0.836026, -0.548690), Vector3(0, 1, 0));
+ //lla.set_look_at(Vector3(),Vector3(1, -1, 1));
+ lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690));
vs->instance_set_transform(light, lla);
diff --git a/tests/test_resource.h b/tests/test_resource.h
new file mode 100644
index 0000000000..cee3281995
--- /dev/null
+++ b/tests/test_resource.h
@@ -0,0 +1,114 @@
+/*************************************************************************/
+/* test_resource.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_RESOURCE
+#define TEST_RESOURCE
+
+#include "core/io/resource.h"
+#include "core/io/resource_loader.h"
+#include "core/io/resource_saver.h"
+#include "core/os/os.h"
+
+#include "thirdparty/doctest/doctest.h"
+
+namespace TestResource {
+
+TEST_CASE("[Resource] Duplication") {
+ Ref<Resource> resource = memnew(Resource);
+ resource->set_name("Hello world");
+ Ref<Resource> child_resource = memnew(Resource);
+ child_resource->set_name("I'm a child resource");
+ resource->set_meta("other_resource", child_resource);
+
+ Ref<Resource> resource_dupe = resource->duplicate();
+ const Ref<Resource> &resource_dupe_reference = resource_dupe;
+ resource_dupe->set_name("Changed name");
+ child_resource->set_name("My name was changed too");
+
+ CHECK_MESSAGE(
+ resource_dupe->get_name() == "Changed name",
+ "Duplicated resource should have the new name.");
+ CHECK_MESSAGE(
+ resource_dupe_reference->get_name() == "Changed name",
+ "Reference to the duplicated resource should have the new name.");
+ CHECK_MESSAGE(
+ resource->get_name() == "Hello world",
+ "Original resource name should not be affected after editing the duplicate's name.");
+ CHECK_MESSAGE(
+ Ref<Resource>(resource_dupe->get_meta("other_resource"))->get_name() == "My name was changed too",
+ "Duplicated resource should share its child resource with the original.");
+}
+
+TEST_CASE("[Resource] Saving and loading") {
+ Ref<Resource> resource = memnew(Resource);
+ resource->set_name("Hello world");
+ resource->set_meta(" ExampleMetadata ", Vector2i(40, 80));
+ resource->set_meta("string", "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks");
+ Ref<Resource> child_resource = memnew(Resource);
+ child_resource->set_name("I'm a child resource");
+ resource->set_meta("other_resource", child_resource);
+ const String save_path_binary = OS::get_singleton()->get_cache_path().plus_file("resource.res");
+ const String save_path_text = OS::get_singleton()->get_cache_path().plus_file("resource.tres");
+ ResourceSaver::save(save_path_binary, resource);
+ ResourceSaver::save(save_path_text, resource);
+
+ const Ref<Resource> &loaded_resource_binary = ResourceLoader::load(save_path_binary);
+ CHECK_MESSAGE(
+ loaded_resource_binary->get_name() == "Hello world",
+ "The loaded resource name should be equal to the expected value.");
+ CHECK_MESSAGE(
+ loaded_resource_binary->get_meta(" ExampleMetadata ") == Vector2i(40, 80),
+ "The loaded resource metadata should be equal to the expected value.");
+ CHECK_MESSAGE(
+ loaded_resource_binary->get_meta("string") == "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks",
+ "The loaded resource metadata should be equal to the expected value.");
+ const Ref<Resource> &loaded_child_resource_binary = loaded_resource_binary->get_meta("other_resource");
+ CHECK_MESSAGE(
+ loaded_child_resource_binary->get_name() == "I'm a child resource",
+ "The loaded child resource name should be equal to the expected value.");
+
+ const Ref<Resource> &loaded_resource_text = ResourceLoader::load(save_path_text);
+ CHECK_MESSAGE(
+ loaded_resource_text->get_name() == "Hello world",
+ "The loaded resource name should be equal to the expected value.");
+ CHECK_MESSAGE(
+ loaded_resource_text->get_meta(" ExampleMetadata ") == Vector2i(40, 80),
+ "The loaded resource metadata should be equal to the expected value.");
+ CHECK_MESSAGE(
+ loaded_resource_text->get_meta("string") == "The\nstring\nwith\nunnecessary\nline\n\t\\\nbreaks",
+ "The loaded resource metadata should be equal to the expected value.");
+ const Ref<Resource> &loaded_child_resource_text = loaded_resource_text->get_meta("other_resource");
+ CHECK_MESSAGE(
+ loaded_child_resource_text->get_name() == "I'm a child resource",
+ "The loaded child resource name should be equal to the expected value.");
+}
+} // namespace TestResource
+
+#endif // TEST_RESOURCE
diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp
index a023f35506..2169350c02 100644
--- a/tests/test_shader_lang.cpp
+++ b/tests/test_shader_lang.cpp
@@ -344,7 +344,7 @@ MainLoop *test() {
Set<String> types;
types.insert("spatial");
- Error err = sl.compile(code, dt, rm, types, nullptr);
+ Error err = sl.compile(code, dt, rm, ShaderLanguage::VaryingFunctionNames(), types, nullptr);
if (err) {
print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text());
diff --git a/tests/test_string.h b/tests/test_string.h
index cc3152203e..94d14517ae 100644
--- a/tests/test_string.h
+++ b/tests/test_string.h
@@ -1045,7 +1045,7 @@ TEST_CASE("[String] lstrip and rstrip") {
TEST_CASE("[String] ensuring empty string into parse_utf8 passes empty string") {
String empty;
- CHECK(empty.parse_utf8(NULL, -1));
+ CHECK(empty.parse_utf8(nullptr, -1));
}
TEST_CASE("[String] Cyrillic to_lower()") {
@@ -1156,6 +1156,17 @@ TEST_CASE("[String] uri_encode/unescape") {
String s = "Godot Engine:'docs'";
String t = "Godot%20Engine%3A%27docs%27";
+ String x1 = "T%C4%93%C5%A1t";
+ static const uint8_t u8str[] = { 0x54, 0xC4, 0x93, 0xC5, 0xA1, 0x74, 0x00 };
+ String x2 = String::utf8((const char *)u8str);
+ String x3 = U"Tēšt";
+
+ CHECK(x1.uri_decode() == x2);
+ CHECK(x1.uri_decode() == x3);
+ CHECK((x1 + x3).uri_decode() == (x2 + x3)); // Mixed unicode and URL encoded string, e.g. GTK+ bookmark.
+ CHECK(x2.uri_encode() == x1);
+ CHECK(x3.uri_encode() == x1);
+
CHECK(s.uri_encode() == t);
CHECK(t.uri_decode() == s);
}
@@ -1166,6 +1177,52 @@ TEST_CASE("[String] xml_escape/unescape") {
CHECK(s.xml_escape(false).xml_unescape() == s);
}
+TEST_CASE("[String] xml_unescape") {
+ // Named entities
+ String input = "&quot;&amp;&apos;&lt;&gt;";
+ CHECK(input.xml_unescape() == "\"&\'<>");
+
+ // Numeric entities
+ input = "&#x41;&#66;";
+ CHECK(input.xml_unescape() == "AB");
+
+ input = "&#0;&x#0;More text";
+ String result = input.xml_unescape();
+ // Didn't put in a leading NUL and terminate the string
+ CHECK(input.length() > 0);
+ CHECK(input[0] != '\0');
+ // Entity should be left as-is if invalid
+ CHECK(input.xml_unescape() == input);
+
+ // Check near char32_t range
+ input = "&#xFFFFFFFF;";
+ result = input.xml_unescape();
+ CHECK(result.length() == 1);
+ CHECK(result[0] == 0xFFFFFFFF);
+ input = "&#4294967295;";
+ result = input.xml_unescape();
+ CHECK(result.length() == 1);
+ CHECK(result[0] == 0xFFFFFFFF);
+
+ // Check out of range of char32_t
+ input = "&#xFFFFFFFFF;";
+ CHECK(input.xml_unescape() == input);
+ input = "&#4294967296;";
+ CHECK(input.xml_unescape() == input);
+
+ // Shouldn't consume without ending in a ';'
+ input = "&#66";
+ CHECK(input.xml_unescape() == input);
+ input = "&#x41";
+ CHECK(input.xml_unescape() == input);
+
+ // Invalid characters should make the entity ignored
+ input = "&#x41SomeIrrelevantText;";
+ CHECK(input.xml_unescape() == input);
+ input = "&#66SomeIrrelevantText;";
+ CHECK(input.xml_unescape() == input);
+}
+
TEST_CASE("[String] Strip escapes") {
String s = "\t\tTest Test\r\n Test";
CHECK(s.strip_escapes() == "Test Test Test");
@@ -1272,6 +1329,20 @@ TEST_CASE("[String] humanize_size") {
CHECK(String::humanize_size(100523550) == "95.86 MiB");
CHECK(String::humanize_size(5345555000) == "4.97 GiB");
}
+
+TEST_CASE("[String] validate_node_name") {
+ String numeric_only = "12345";
+ CHECK(numeric_only.validate_node_name() == "12345");
+
+ String name_with_spaces = "Name with spaces";
+ CHECK(name_with_spaces.validate_node_name() == "Name with spaces");
+
+ String name_with_kana = "Name with kana ゴドツ";
+ CHECK(name_with_kana.validate_node_name() == "Name with kana ゴドツ");
+
+ String name_with_invalid_chars = "Name with invalid characters :.@removed!";
+ CHECK(name_with_invalid_chars.validate_node_name() == "Name with invalid characters removed!");
+}
} // namespace TestString
#endif // TEST_STRING_H
diff --git a/tests/test_text_server.h b/tests/test_text_server.h
index b0b40447fe..3d700f8ec4 100644
--- a/tests/test_text_server.h
+++ b/tests/test_text_server.h
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef TOOLS_ENABLED
+
#ifndef TEST_TEXT_SERVER_H
#define TEST_TEXT_SERVER_H
@@ -247,3 +249,4 @@ TEST_SUITE("[[TextServer]") {
}; // namespace TestTextServer
#endif // TEST_TEXT_SERVER_H
+#endif // TOOLS_ENABLED
diff --git a/tests/test_variant.h b/tests/test_variant.h
index f8fa852bf4..dfc72b512c 100644
--- a/tests/test_variant.h
+++ b/tests/test_variant.h
@@ -105,6 +105,600 @@ TEST_CASE("[Variant] Writer and parser float") {
CHECK_MESSAGE(b64_float_parsed == 340282001837565597733306976381245063168.0, "Should not overflow.");
}
+
+TEST_CASE("[Variant] Assignment To Bool from Int,Float,String,Vec2,Vec2i,Vec3,Vec3i and Color") {
+ Variant int_v = 0;
+ Variant bool_v = true;
+ int_v = bool_v; // int_v is now a bool
+ CHECK(int_v == Variant(true));
+ bool_v = false;
+ int_v = bool_v;
+ CHECK(int_v.get_type() == Variant::BOOL);
+
+ Variant float_v = 0.0f;
+ bool_v = true;
+ float_v = bool_v;
+ CHECK(float_v == Variant(true));
+ bool_v = false;
+ float_v = bool_v;
+ CHECK(float_v.get_type() == Variant::BOOL);
+
+ Variant string_v = "";
+ bool_v = true;
+ string_v = bool_v;
+ CHECK(string_v == Variant(true));
+ bool_v = false;
+ string_v = bool_v;
+ CHECK(string_v.get_type() == Variant::BOOL);
+
+ Variant vec2_v = Vector2(0, 0);
+ bool_v = true;
+ vec2_v = bool_v;
+ CHECK(vec2_v == Variant(true));
+ bool_v = false;
+ vec2_v = bool_v;
+ CHECK(vec2_v.get_type() == Variant::BOOL);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ bool_v = true;
+ vec2i_v = bool_v;
+ CHECK(vec2i_v == Variant(true));
+ bool_v = false;
+ vec2i_v = bool_v;
+ CHECK(vec2i_v.get_type() == Variant::BOOL);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ bool_v = true;
+ vec3_v = bool_v;
+ CHECK(vec3_v == Variant(true));
+ bool_v = false;
+ vec3_v = bool_v;
+ CHECK(vec3_v.get_type() == Variant::BOOL);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ bool_v = true;
+ vec3i_v = bool_v;
+ CHECK(vec3i_v == Variant(true));
+ bool_v = false;
+ vec3i_v = bool_v;
+ CHECK(vec3i_v.get_type() == Variant::BOOL);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ bool_v = true;
+ col_v = bool_v;
+ CHECK(col_v == Variant(true));
+ bool_v = false;
+ col_v = bool_v;
+ CHECK(col_v.get_type() == Variant::BOOL);
+}
+
+TEST_CASE("[Variant] Assignment To Int from Bool,Float,String,Vec2,Vec2i,Vec3,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant int_v = 2;
+ bool_v = int_v; // Now bool_v is int
+ CHECK(bool_v == Variant(2));
+ int_v = -3;
+ bool_v = int_v;
+ CHECK(bool_v.get_type() == Variant::INT);
+
+ Variant float_v = 0.0f;
+ int_v = 2;
+ float_v = int_v;
+ CHECK(float_v == Variant(2));
+ int_v = -3;
+ float_v = int_v;
+ CHECK(float_v.get_type() == Variant::INT);
+
+ Variant string_v = "";
+ int_v = 2;
+ string_v = int_v;
+ CHECK(string_v == Variant(2));
+ int_v = -3;
+ string_v = int_v;
+ CHECK(string_v.get_type() == Variant::INT);
+
+ Variant vec2_v = Vector2(0, 0);
+ int_v = 2;
+ vec2_v = int_v;
+ CHECK(vec2_v == Variant(2));
+ int_v = -3;
+ vec2_v = int_v;
+ CHECK(vec2_v.get_type() == Variant::INT);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ int_v = 2;
+ vec2i_v = int_v;
+ CHECK(vec2i_v == Variant(2));
+ int_v = -3;
+ vec2i_v = int_v;
+ CHECK(vec2i_v.get_type() == Variant::INT);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ int_v = 2;
+ vec3_v = int_v;
+ CHECK(vec3_v == Variant(2));
+ int_v = -3;
+ vec3_v = int_v;
+ CHECK(vec3_v.get_type() == Variant::INT);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ int_v = 2;
+ vec3i_v = int_v;
+ CHECK(vec3i_v == Variant(2));
+ int_v = -3;
+ vec3i_v = int_v;
+ CHECK(vec3i_v.get_type() == Variant::INT);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ int_v = 2;
+ col_v = int_v;
+ CHECK(col_v == Variant(2));
+ int_v = -3;
+ col_v = int_v;
+ CHECK(col_v.get_type() == Variant::INT);
+}
+
+TEST_CASE("[Variant] Assignment To Float from Bool,Int,String,Vec2,Vec2i,Vec3,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant float_v = 1.5f;
+ bool_v = float_v; // Now bool_v is float
+ CHECK(bool_v == Variant(1.5f));
+ float_v = -4.6f;
+ bool_v = float_v;
+ CHECK(bool_v.get_type() == Variant::FLOAT);
+
+ Variant int_v = 1;
+ float_v = 1.5f;
+ int_v = float_v;
+ CHECK(int_v == Variant(1.5f));
+ float_v = -4.6f;
+ int_v = float_v;
+ CHECK(int_v.get_type() == Variant::FLOAT);
+
+ Variant string_v = "";
+ float_v = 1.5f;
+ string_v = float_v;
+ CHECK(string_v == Variant(1.5f));
+ float_v = -4.6f;
+ string_v = float_v;
+ CHECK(string_v.get_type() == Variant::FLOAT);
+
+ Variant vec2_v = Vector2(0, 0);
+ float_v = 1.5f;
+ vec2_v = float_v;
+ CHECK(vec2_v == Variant(1.5f));
+ float_v = -4.6f;
+ vec2_v = float_v;
+ CHECK(vec2_v.get_type() == Variant::FLOAT);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ float_v = 1.5f;
+ vec2i_v = float_v;
+ CHECK(vec2i_v == Variant(1.5f));
+ float_v = -4.6f;
+ vec2i_v = float_v;
+ CHECK(vec2i_v.get_type() == Variant::FLOAT);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ float_v = 1.5f;
+ vec3_v = float_v;
+ CHECK(vec3_v == Variant(1.5f));
+ float_v = -4.6f;
+ vec3_v = float_v;
+ CHECK(vec3_v.get_type() == Variant::FLOAT);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ float_v = 1.5f;
+ vec3i_v = float_v;
+ CHECK(vec3i_v == Variant(1.5f));
+ float_v = -4.6f;
+ vec3i_v = float_v;
+ CHECK(vec3i_v.get_type() == Variant::FLOAT);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ float_v = 1.5f;
+ col_v = float_v;
+ CHECK(col_v == Variant(1.5f));
+ float_v = -4.6f;
+ col_v = float_v;
+ CHECK(col_v.get_type() == Variant::FLOAT);
+}
+
+TEST_CASE("[Variant] Assignment To String from Bool,Int,Float,Vec2,Vec2i,Vec3,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant string_v = "Hello";
+ bool_v = string_v; // Now bool_v is string
+ CHECK(bool_v == Variant("Hello"));
+ string_v = "Hello there";
+ bool_v = string_v;
+ CHECK(bool_v.get_type() == Variant::STRING);
+
+ Variant int_v = 0;
+ string_v = "Hello";
+ int_v = string_v;
+ CHECK(int_v == Variant("Hello"));
+ string_v = "Hello there";
+ int_v = string_v;
+ CHECK(int_v.get_type() == Variant::STRING);
+
+ Variant float_v = 0.0f;
+ string_v = "Hello";
+ float_v = string_v;
+ CHECK(float_v == Variant("Hello"));
+ string_v = "Hello there";
+ float_v = string_v;
+ CHECK(float_v.get_type() == Variant::STRING);
+
+ Variant vec2_v = Vector2(0, 0);
+ string_v = "Hello";
+ vec2_v = string_v;
+ CHECK(vec2_v == Variant("Hello"));
+ string_v = "Hello there";
+ vec2_v = string_v;
+ CHECK(vec2_v.get_type() == Variant::STRING);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ string_v = "Hello";
+ vec2i_v = string_v;
+ CHECK(vec2i_v == Variant("Hello"));
+ string_v = "Hello there";
+ vec2i_v = string_v;
+ CHECK(vec2i_v.get_type() == Variant::STRING);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ string_v = "Hello";
+ vec3_v = string_v;
+ CHECK(vec3_v == Variant("Hello"));
+ string_v = "Hello there";
+ vec3_v = string_v;
+ CHECK(vec3_v.get_type() == Variant::STRING);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ string_v = "Hello";
+ vec3i_v = string_v;
+ CHECK(vec3i_v == Variant("Hello"));
+ string_v = "Hello there";
+ vec3i_v = string_v;
+ CHECK(vec3i_v.get_type() == Variant::STRING);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ string_v = "Hello";
+ col_v = string_v;
+ CHECK(col_v == Variant("Hello"));
+ string_v = "Hello there";
+ col_v = string_v;
+ CHECK(col_v.get_type() == Variant::STRING);
+}
+
+TEST_CASE("[Variant] Assignment To Vec2 from Bool,Int,Float,String,Vec2i,Vec3,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant vec2_v = Vector2(2.2f, 3.5f);
+ bool_v = vec2_v; // Now bool_v is Vector2
+ CHECK(bool_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ bool_v = vec2_v;
+ CHECK(bool_v.get_type() == Variant::VECTOR2);
+
+ Variant int_v = 0;
+ vec2_v = Vector2(2.2f, 3.5f);
+ int_v = vec2_v;
+ CHECK(int_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ int_v = vec2_v;
+ CHECK(int_v.get_type() == Variant::VECTOR2);
+
+ Variant float_v = 0.0f;
+ vec2_v = Vector2(2.2f, 3.5f);
+ float_v = vec2_v;
+ CHECK(float_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ float_v = vec2_v;
+ CHECK(float_v.get_type() == Variant::VECTOR2);
+
+ Variant string_v = "";
+ vec2_v = Vector2(2.2f, 3.5f);
+ string_v = vec2_v;
+ CHECK(string_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ string_v = vec2_v;
+ CHECK(string_v.get_type() == Variant::VECTOR2);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ vec2_v = Vector2(2.2f, 3.5f);
+ vec2i_v = vec2_v;
+ CHECK(vec2i_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ vec2i_v = vec2_v;
+ CHECK(vec2i_v.get_type() == Variant::VECTOR2);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ vec2_v = Vector2(2.2f, 3.5f);
+ vec3_v = vec2_v;
+ CHECK(vec3_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ vec3_v = vec2_v;
+ CHECK(vec3_v.get_type() == Variant::VECTOR2);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ vec2_v = Vector2(2.2f, 3.5f);
+ vec3i_v = vec2_v;
+ CHECK(vec3i_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ vec3i_v = vec2_v;
+ CHECK(vec3i_v.get_type() == Variant::VECTOR2);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ vec2_v = Vector2(2.2f, 3.5f);
+ col_v = vec2_v;
+ CHECK(col_v == Variant(Vector2(2.2f, 3.5f)));
+ vec2_v = Vector2(-5.4f, -7.9f);
+ col_v = vec2_v;
+ CHECK(col_v.get_type() == Variant::VECTOR2);
+}
+
+TEST_CASE("[Variant] Assignment To Vec2i from Bool,Int,Float,String,Vec2,Vec3,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant vec2i_v = Vector2i(2, 3);
+ bool_v = vec2i_v; // Now bool_v is Vector2i
+ CHECK(bool_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ bool_v = vec2i_v;
+ CHECK(bool_v.get_type() == Variant::VECTOR2I);
+
+ Variant int_v = 0;
+ vec2i_v = Vector2i(2, 3);
+ int_v = vec2i_v;
+ CHECK(int_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ int_v = vec2i_v;
+ CHECK(int_v.get_type() == Variant::VECTOR2I);
+
+ Variant float_v = 0.0f;
+ vec2i_v = Vector2i(2, 3);
+ float_v = vec2i_v;
+ CHECK(float_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ float_v = vec2i_v;
+ CHECK(float_v.get_type() == Variant::VECTOR2I);
+
+ Variant string_v = "";
+ vec2i_v = Vector2i(2, 3);
+ string_v = vec2i_v;
+ CHECK(string_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ string_v = vec2i_v;
+ CHECK(string_v.get_type() == Variant::VECTOR2I);
+
+ Variant vec2_v = Vector2(0, 0);
+ vec2i_v = Vector2i(2, 3);
+ vec2_v = vec2i_v;
+ CHECK(vec2_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ vec2_v = vec2i_v;
+ CHECK(vec2i_v.get_type() == Variant::VECTOR2I);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ vec2i_v = Vector2i(2, 3);
+ vec3_v = vec2i_v;
+ CHECK(vec3_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ vec3_v = vec2i_v;
+ CHECK(vec3_v.get_type() == Variant::VECTOR2I);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ vec2i_v = Vector2i(2, 3);
+ vec3i_v = vec2i_v;
+ CHECK(vec3i_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ vec3i_v = vec2i_v;
+ CHECK(vec3i_v.get_type() == Variant::VECTOR2I);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ vec2i_v = Vector2i(2, 3);
+ col_v = vec2i_v;
+ CHECK(col_v == Variant(Vector2i(2, 3)));
+ vec2i_v = Vector2i(-5, -7);
+ col_v = vec2i_v;
+ CHECK(col_v.get_type() == Variant::VECTOR2I);
+}
+
+TEST_CASE("[Variant] Assignment To Vec3 from Bool,Int,Float,String,Vec2,Vec2i,Vec3i and Color") {
+ Variant bool_v = false;
+ Variant vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ bool_v = vec3_v; // Now bool_v is Vector3
+ CHECK(bool_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ bool_v = vec3_v;
+ CHECK(bool_v.get_type() == Variant::VECTOR3);
+
+ Variant int_v = 0;
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ int_v = vec3_v;
+ CHECK(int_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ int_v = vec3_v;
+ CHECK(int_v.get_type() == Variant::VECTOR3);
+
+ Variant float_v = 0.0f;
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ float_v = vec3_v;
+ CHECK(float_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ float_v = vec3_v;
+ CHECK(float_v.get_type() == Variant::VECTOR3);
+
+ Variant string_v = "";
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ string_v = vec3_v;
+ CHECK(string_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ string_v = vec3_v;
+ CHECK(string_v.get_type() == Variant::VECTOR3);
+
+ Variant vec2_v = Vector2(0, 0);
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ vec2_v = vec3_v;
+ CHECK(vec2_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ vec2_v = vec3_v;
+ CHECK(vec2_v.get_type() == Variant::VECTOR3);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ vec2i_v = vec3_v;
+ CHECK(vec2i_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ vec2i_v = vec3_v;
+ CHECK(vec2i_v.get_type() == Variant::VECTOR3);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ vec3i_v = vec3_v;
+ CHECK(vec3i_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ vec3i_v = vec3_v;
+ CHECK(vec3i_v.get_type() == Variant::VECTOR3);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ vec3_v = Vector3(2.2f, 3.5f, 5.3f);
+ col_v = vec3_v;
+ CHECK(col_v == Variant(Vector3(2.2f, 3.5f, 5.3f)));
+ vec3_v = Vector3(-5.4f, -7.9f, -2.1f);
+ col_v = vec3_v;
+ CHECK(col_v.get_type() == Variant::VECTOR3);
+}
+
+TEST_CASE("[Variant] Assignment To Vec3i from Bool,Int,Float,String,Vec2,Vec2i,Vec3 and Color") {
+ Variant bool_v = false;
+ Variant vec3i_v = Vector3i(2, 3, 5);
+ bool_v = vec3i_v; // Now bool_v is Vector3i
+ CHECK(bool_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ bool_v = vec3i_v;
+ CHECK(bool_v.get_type() == Variant::VECTOR3I);
+
+ Variant int_v = 0;
+ vec3i_v = Vector3i(2, 3, 5);
+ int_v = vec3i_v;
+ CHECK(int_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ int_v = vec3i_v;
+ CHECK(int_v.get_type() == Variant::VECTOR3I);
+
+ Variant float_v = 0.0f;
+ vec3i_v = Vector3i(2, 3, 5);
+ float_v = vec3i_v;
+ CHECK(float_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ float_v = vec3i_v;
+ CHECK(float_v.get_type() == Variant::VECTOR3I);
+
+ Variant string_v = "";
+ vec3i_v = Vector3i(2, 3, 5);
+ string_v = vec3i_v;
+ CHECK(string_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ string_v = vec3i_v;
+ CHECK(string_v.get_type() == Variant::VECTOR3I);
+
+ Variant vec2_v = Vector2(0, 0);
+ vec3i_v = Vector3i(2, 3, 5);
+ vec2_v = vec3i_v;
+ CHECK(vec2_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ vec2_v = vec3i_v;
+ CHECK(vec2_v.get_type() == Variant::VECTOR3I);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ vec3i_v = Vector3i(2, 3, 5);
+ vec2i_v = vec3i_v;
+ CHECK(vec2i_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ vec2i_v = vec3i_v;
+ CHECK(vec2i_v.get_type() == Variant::VECTOR3I);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ vec3i_v = Vector3i(2, 3, 5);
+ vec3_v = vec3i_v;
+ CHECK(vec3_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ vec3_v = vec3i_v;
+ CHECK(vec3_v.get_type() == Variant::VECTOR3I);
+
+ Variant col_v = Color(0.5f, 0.2f, 0.75f);
+ vec3i_v = Vector3i(2, 3, 5);
+ col_v = vec3i_v;
+ CHECK(col_v == Variant(Vector3i(2, 3, 5)));
+ vec3i_v = Vector3i(-5, -7, -2);
+ col_v = vec3i_v;
+ CHECK(col_v.get_type() == Variant::VECTOR3I);
+}
+
+TEST_CASE("[Variant] Assignment To Color from Bool,Int,Float,String,Vec2,Vec2i,Vec3 and Vec3i") {
+ Variant bool_v = false;
+ Variant col_v = Color(0.25f, 0.4f, 0.78f);
+ bool_v = col_v; // Now bool_v is Color
+ CHECK(bool_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ bool_v = col_v;
+ CHECK(bool_v.get_type() == Variant::COLOR);
+
+ Variant int_v = 0;
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ int_v = col_v;
+ CHECK(int_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ int_v = col_v;
+ CHECK(int_v.get_type() == Variant::COLOR);
+
+ Variant float_v = 0.0f;
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ float_v = col_v;
+ CHECK(float_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ float_v = col_v;
+ CHECK(float_v.get_type() == Variant::COLOR);
+
+ Variant string_v = "";
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ string_v = col_v;
+ CHECK(string_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ string_v = col_v;
+ CHECK(string_v.get_type() == Variant::COLOR);
+
+ Variant vec2_v = Vector2(0, 0);
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ vec2_v = col_v;
+ CHECK(vec2_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ vec2_v = col_v;
+ CHECK(vec2_v.get_type() == Variant::COLOR);
+
+ Variant vec2i_v = Vector2i(0, 0);
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ vec2i_v = col_v;
+ CHECK(vec2i_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ vec2i_v = col_v;
+ CHECK(vec2i_v.get_type() == Variant::COLOR);
+
+ Variant vec3_v = Vector3(0, 0, 0);
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ vec3_v = col_v;
+ CHECK(vec3_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ vec3_v = col_v;
+ CHECK(vec3_v.get_type() == Variant::COLOR);
+
+ Variant vec3i_v = Vector3i(0, 0, 0);
+ col_v = Color(0.25f, 0.4f, 0.78f);
+ vec3i_v = col_v;
+ CHECK(vec3i_v == Variant(Color(0.25f, 0.4f, 0.78f)));
+ col_v = Color(0.33f, 0.75f, 0.21f);
+ vec3i_v = col_v;
+ CHECK(vec3i_v.get_type() == Variant::COLOR);
+}
} // namespace TestVariant
#endif // TEST_VARIANT_H
diff --git a/scene/3d/navigation_3d.h b/tests/test_xml_parser.h
index b89725a3f5..55de048d6a 100644
--- a/scene/3d/navigation_3d.h
+++ b/tests/test_xml_parser.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* navigation_3d.h */
+/* test_xml_parser.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,51 +28,47 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NAVIGATION_3D_H
-#define NAVIGATION_3D_H
+#ifndef TEST_XML_PARSER_H
+#define TEST_XML_PARSER_H
-#include "scene/3d/navigation_region_3d.h"
-#include "scene/3d/node_3d.h"
+#include <inttypes.h>
-class Navigation3D : public Node3D {
- GDCLASS(Navigation3D, Node3D);
+#include "core/io/xml_parser.h"
+#include "core/string/ustring.h"
- RID map;
+#include "tests/test_macros.h"
- Vector3 up = Vector3(0, 1, 0);
- real_t cell_size;
- real_t edge_connection_margin;
+namespace TestXMLParser {
+TEST_CASE("[XMLParser] End-to-end") {
+ String source = "<?xml version = \"1.0\" encoding=\"UTF-8\" ?>\
+<top attr=\"attr value\">\
+ Text&lt;&#65;&#x42;&gt;\
+</top>";
+ Vector<uint8_t> buff = source.to_utf8_buffer();
-protected:
- static void _bind_methods();
- void _notification(int p_what);
+ XMLParser parser;
+ parser.open_buffer(buff);
-public:
- RID get_rid() const {
- return map;
- }
+ // <?xml ...?> gets parsed as NODE_UNKNOWN
+ CHECK(parser.read() == OK);
+ CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_UNKNOWN);
- void set_up_vector(const Vector3 &p_up);
- Vector3 get_up_vector() const;
+ CHECK(parser.read() == OK);
+ CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT);
+ CHECK(parser.get_node_name() == "top");
+ CHECK(parser.has_attribute("attr"));
+ CHECK(parser.get_attribute_value("attr") == "attr value");
- void set_cell_size(float p_cell_size);
- float get_cell_size() const {
- return cell_size;
- }
+ CHECK(parser.read() == OK);
+ CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_TEXT);
+ CHECK(parser.get_node_data().lstrip(" \t") == "Text<AB>");
- void set_edge_connection_margin(float p_edge_connection_margin);
- float get_edge_connection_margin() const {
- return edge_connection_margin;
- }
+ CHECK(parser.read() == OK);
+ CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT_END);
+ CHECK(parser.get_node_name() == "top");
- Vector<Vector3> get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize = true) const;
- Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const;
- Vector3 get_closest_point(const Vector3 &p_point) const;
- Vector3 get_closest_point_normal(const Vector3 &p_point) const;
- RID get_closest_point_owner(const Vector3 &p_point) const;
+ parser.close();
+}
+} // namespace TestXMLParser
- Navigation3D();
- ~Navigation3D();
-};
-
-#endif // NAVIGATION_H
+#endif // TEST_XML_PARSER_H
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 3803e87fea..605b298ac1 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -62,6 +62,26 @@ Files extracted from upstream source:
Extracted from .zip provided. Extracted license and header only.
+## embree-aarch64
+
+- Upstream: https://github.com/lighttransport/embree-aarch64
+- Version: 3.12.1 (6ef362f99af80c9dfe8dd2bfc582d9067897edc6, 2020)
+- License: Apache 2.0
+
+Files extracted from upstream:
+
+- All cpp files listed in `modules/raycast/godot_update_embree.py`
+- All header files in the directories listed in `modules/raycast/godot_update_embree.py`
+
+The `modules/raycast/godot_update_embree.py`script can be used to pull the
+relevant files from the latest Embree-aarch64 release and apply some automatic changes.
+
+Some changes have been made in order to remove exceptions and fix minor build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+comments. Apply the patches in the `patches/` folder when syncing on newer upstream
+commits.
+
+
## enet
- Upstream: http://enet.bespin.org
@@ -86,20 +106,20 @@ It is still possible to build against a system wide ENet but doing so
will limit its functionality to IPv4 only.
-## etc2comp
+## etcpak
-- Upstream: https://github.com/google/etc2comp
-- Version: git (9cd0f9cae0f32338943699bb418107db61bb66f2, 2017)
-- License: Apache 2.0
+- Upstream: https://github.com/wolfpld/etcpak
+- Version: git (f27daea656ff77671580f838a889e33049430ebd, 2021)
+- License: BSD-3-Clause
Files extracted from upstream source:
-- all .cpp and .h files in EtcLib/
-- README.md, LICENSE, AUTHORS
-
-Important: Some files have Godot-made changes.
-They are marked with `// -- GODOT start --` and `// -- GODOT end --`
-comments.
+- Only the files relevant for compression (i.e. `Process*.cpp` and their deps):
+ ```
+ Dither.{cpp,hpp} ForceInline.hpp Math.hpp ProcessCommon.hpp ProcessRGB.{cpp,hpp}
+ ProcessDxtc.{cpp,hpp} Tables.{cpp,hpp} Vector.hpp
+ ```
+- `AUTHORS.txt` and `LICENSE.txt`
## fonts
@@ -174,7 +194,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 2.7.4 (7236c7e29cef1c2d76c7a284c5081ff4d3aa1127, 2020)
+- Version: 2.8.0 (03538e872a0610a65fad692b33d3646f387cf578, 2021)
- License: MIT
Files extracted from upstream source:
@@ -186,17 +206,17 @@ Files extracted from upstream source:
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 68.2 (84e1f26ea77152936e70d53178a816dbfbf69989, 2020)
+- Version: 69.1 (0e7b4428866f3133b4abba2d932ee3faa708db1d, 2021)
- License: Unicode
Files extracted from upstream source:
- the `common` folder
-- `APIChangeReport.md`, `LICENSE`
+- `LICENSE`
Files generated from upstream source:
-- the `icudt68l.dat` built with the provided `godot_data.json` config file (see
+- the `icudt69l.dat` built with the provided `godot_data.json` config file (see
https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md
for instructions)
@@ -324,7 +344,7 @@ changes are marked with `// -- GODOT --` comments.
## mbedtls
- Upstream: https://tls.mbed.org/
-- Version: 2.16.9 (3fac0bae4a50113989b3d015cd2d948f51a6d9ac, 2020)
+- Version: 2.16.10 (d61fa61bef06b64132e3490543c81b8ee40fbee3, 2021)
- License: Apache 2.0
File extracted from upstream release tarball:
@@ -344,7 +364,7 @@ File extracted from upstream release tarball:
## meshoptimizer
- Upstream: https://github.com/zeux/meshoptimizer
-- Version: git (e3f53f66e7a35b9b8764bee478589d79e34fa698, 2021)
+- Version: 0.16 (95893c0566646434dd675b708d293fcb2d526d08, 2021)
- License: MIT
Files extracted from upstream repository:
@@ -355,18 +375,23 @@ Files extracted from upstream repository:
## miniupnpc
-- Upstream: https://github.com/miniupnp/miniupnp/tree/master/miniupnpc
-- Version: git (44366328661826603982d1e0d7ebb4062c5f2bfc, 2020)
+- Upstream: https://github.com/miniupnp/miniupnp
+- Version: 2.2.2 (81029a860baf1f727903e5b85307903b3f40cbc8, 2021)
- License: BSD-3-Clause
Files extracted from upstream source:
- All `*.c` and `*.h` files from `miniupnpc` to `thirdparty/miniupnpc/miniupnpc`
-- Remove `test*`, `minihttptestserver.c` and `wingenminiupnpcstrings.c`
+- Remove the following test or sample files:
+ `listdevices.c minihttptestserver.c miniupnpcmodule.c upnpc.c upnperrors.* test* wingenminiupnpcstrings.c`
+- `LICENSE`
+
+The only modified file is `miniupnpcstrings.h`, which was created for Godot
+(it is usually autogenerated by cmake). Bump the version number for miniupnpc in that
+file when upgrading.
-The patch `windows_fix.diff` is applied to `minissdpc.c` to fix an upstream issue.
-The only modified file is miniupnpcstrings.h, which was created for Godot
-(it is usually autogenerated by cmake).
+Note: The following upstream patch has been applied, remove this notice on next update.
+https://github.com/miniupnp/miniupnp/commit/3a08dd4b89af2e9effa22a136bac86f2f306fd79
## minizip
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
index 6873a95d90..c79623bd57 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
@@ -80,7 +80,6 @@ struct ClipVertex
btVector3 v;
int id;
//b2ContactID id;
- //b2ContactID id;
};
#define b2Dot(a, b) (a).dot(b)
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
index fec9b03213..4372489fa1 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
@@ -43,7 +43,6 @@ void btMultiBodyJointMotor::finalizeMultiDof()
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
- // row 0: the lower bound
jacobianA(0)[offset] = 1;
m_numDofsFinalized = m_jacSizeBoth;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
index 25ddd539bf..5c20d2a0d4 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
@@ -45,7 +45,6 @@ void btMultiBodySphericalJointMotor::finalizeMultiDof()
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
- // row 0: the lower bound
jacobianA(0)[offset] = 1;
m_numDofsFinalized = m_jacSizeBoth;
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_any_of.h b/thirdparty/embree-aarch64/common/algorithms/parallel_any_of.h
new file mode 100644
index 0000000000..01f1f80f6c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_any_of.h
@@ -0,0 +1,55 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <functional>
+#include "parallel_reduce.h"
+
+namespace embree
+{
+
+ template<typename Index, class UnaryPredicate>
+ __forceinline bool parallel_any_of (Index first, Index last, UnaryPredicate pred)
+ {
+ bool ret = false;
+
+#if defined(TASKING_TBB)
+#if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(tbb::blocked_range<size_t>{first, last}, [&ret,pred,&context](const tbb::blocked_range<size_t>& r) {
+ if (context.is_group_execution_cancelled()) return;
+ for (size_t i = r.begin(); i != r.end(); ++i) {
+ if (pred(i)) {
+ ret = true;
+ context.cancel_group_execution();
+ }
+ }
+ });
+#else
+ tbb::parallel_for(tbb::blocked_range<size_t>{first, last}, [&ret,pred](const tbb::blocked_range<size_t>& r) {
+ if (tbb::task::self().is_cancelled()) return;
+ for (size_t i = r.begin(); i != r.end(); ++i) {
+ if (pred(i)) {
+ ret = true;
+ tbb::task::self().cancel_group_execution();
+ }
+ }
+ });
+#endif
+#else
+ ret = parallel_reduce (first, last, false, [pred](const range<size_t>& r)->bool {
+ bool localret = false;
+ for (auto i=r.begin(); i<r.end(); ++i) {
+ localret |= pred(i);
+ }
+ return localret;
+ },
+ std::bit_or<bool>()
+ );
+#endif
+
+ return ret;
+ }
+
+} // end namespace
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp
new file mode 100644
index 0000000000..acddc0ff81
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_filter.cpp
@@ -0,0 +1,56 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_filter.h"
+#include "../sys/regression.h"
+#include <map>
+
+namespace embree
+{
+ struct parallel_filter_regression_test : public RegressionTest
+ {
+ parallel_filter_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+ auto pred = [&]( uint32_t v ) { return (v & 0x3) == 0; };
+
+ for (size_t N=10; N<1000000; N=size_t(2.1*N))
+ {
+ size_t N0 = rand() % N;
+
+ /* initialize array with random numbers */
+ std::vector<uint32_t> src(N);
+ std::map<uint32_t,int> m;
+ for (size_t i=0; i<N; i++) src[i] = rand();
+
+ /* count elements up */
+ for (size_t i=N0; i<N; i++)
+ if (pred(src[i]))
+ m[src[i]] = 0;
+ for (size_t i=N0; i<N; i++)
+ if (pred(src[i]))
+ m[src[i]]++;
+
+ /* filter array */
+ //size_t M = sequential_filter(src.data(),N0,N,pred);
+ size_t M = parallel_filter(src.data(),N0,N,size_t(1024),pred);
+
+ /* check if filtered data is correct */
+ for (size_t i=N0; i<M; i++) {
+ passed &= pred(src[i]);
+ m[src[i]]--;
+ }
+ for (size_t i=N0; i<M; i++)
+ passed &= (m[src[i]] == 0);
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_filter_regression_test parallel_filter_regression("parallel_filter_regression");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_filter.h b/thirdparty/embree-aarch64/common/algorithms/parallel_filter.h
new file mode 100644
index 0000000000..5823fc631f
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_filter.h
@@ -0,0 +1,93 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Ty, typename Index, typename Predicate>
+ inline Index sequential_filter( Ty* data, const Index first, const Index last, const Predicate& predicate)
+ {
+ Index j = first;
+ for (Index i=first; i<last; i++)
+ if (predicate(data[i]))
+ data[j++] = data[i];
+
+ return j;
+ }
+
+ template<typename Ty, typename Index, typename Predicate>
+ inline Index parallel_filter( Ty* data, const Index begin, const Index end, const Index minStepSize, const Predicate& predicate)
+ {
+ /* sequential fallback */
+ if (end-begin <= minStepSize)
+ return sequential_filter(data,begin,end,predicate);
+
+ /* calculate number of tasks to use */
+ enum { MAX_TASKS = 64 };
+ const Index numThreads = TaskScheduler::threadCount();
+ const Index numBlocks = (end-begin+minStepSize-1)/minStepSize;
+ const Index taskCount = min(numThreads,numBlocks,(Index)MAX_TASKS);
+
+ /* filter blocks */
+ Index nused[MAX_TASKS];
+ Index nfree[MAX_TASKS];
+ parallel_for(taskCount, [&](const Index taskIndex)
+ {
+ const Index i0 = begin+(taskIndex+0)*(end-begin)/taskCount;
+ const Index i1 = begin+(taskIndex+1)*(end-begin)/taskCount;
+ const Index i2 = sequential_filter(data,i0,i1,predicate);
+ nused[taskIndex] = i2-i0;
+ nfree[taskIndex] = i1-i2;
+ });
+
+ /* calculate offsets */
+ Index sused=0;
+ Index sfree=0;
+ Index pfree[MAX_TASKS];
+ for (Index i=0; i<taskCount; i++)
+ {
+ sused+=nused[i];
+ Index cfree = nfree[i]; pfree[i] = sfree; sfree+=cfree;
+ }
+
+ /* return if we did not filter out any element */
+ assert(sfree <= end-begin);
+ assert(sused <= end-begin);
+ if (sused == end-begin)
+ return end;
+
+ /* otherwise we have to copy misplaced elements around */
+ parallel_for(taskCount, [&](const Index taskIndex)
+ {
+ /* destination to write elements to */
+ Index dst = begin+(taskIndex+0)*(end-begin)/taskCount+nused[taskIndex];
+ Index dst_end = min(dst+nfree[taskIndex],begin+sused);
+ if (dst_end <= dst) return;
+
+ /* range of misplaced elements to copy to destination */
+ Index r0 = pfree[taskIndex];
+ Index r1 = r0+dst_end-dst;
+
+ /* find range in misplaced elements in back to front order */
+ Index k0=0;
+ for (Index i=taskCount-1; i>0; i--)
+ {
+ if (k0 > r1) break;
+ Index k1 = k0+nused[i];
+ Index src = begin+(i+0)*(end-begin)/taskCount+nused[i];
+ for (Index i=max(r0,k0); i<min(r1,k1); i++) {
+ Index isrc = src-i+k0-1;
+ assert(dst >= begin && dst < end);
+ assert(isrc >= begin && isrc < end);
+ data[dst++] = data[isrc];
+ }
+ k0 = k1;
+ }
+ });
+
+ return begin+sused;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp
new file mode 100644
index 0000000000..ef070ebc4d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for.cpp
@@ -0,0 +1,48 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_for.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_for_regression_test : public RegressionTest
+ {
+ parallel_for_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ const size_t M = 10;
+ for (size_t N=10; N<10000000; N=size_t(2.1*N))
+ {
+ /* sequentially calculate sum of squares */
+ size_t sum0 = 0;
+ for (size_t i=0; i<N; i++) {
+ sum0 += i*i;
+ }
+
+ /* parallel calculation of sum of squares */
+ for (size_t m=0; m<M; m++)
+ {
+ std::atomic<size_t> sum1(0);
+ parallel_for( size_t(0), size_t(N), size_t(1024), [&](const range<size_t>& r)
+ {
+ size_t s = 0;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ s += i*i;
+ sum1 += s;
+ });
+ passed = sum0 == sum1;
+ }
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_for_regression_test parallel_for_regression("parallel_for_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for.h b/thirdparty/embree-aarch64/common/algorithms/parallel_for.h
new file mode 100644
index 0000000000..51d296fb16
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for.h
@@ -0,0 +1,229 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../tasking/taskscheduler.h"
+#include "../sys/array.h"
+#include "../math/math.h"
+#include "../math/range.h"
+
+#if defined(TASKING_GCD) && defined(BUILD_IOS)
+#include <dispatch/dispatch.h>
+#include <algorithm>
+#include <type_traits>
+#endif
+
+namespace embree
+{
+ /* parallel_for without range */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index N, const Func& func)
+ {
+#if defined(TASKING_INTERNAL)
+ if (N) {
+ TaskScheduler::spawn(Index(0),N,Index(1),[&] (const range<Index>& r) {
+ assert(r.size() == 1);
+ func(r.begin());
+ });
+ if (!TaskScheduler::wait())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ }
+#elif defined(TASKING_GCD) && defined(BUILD_IOS)
+
+ const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? TaskScheduler::threadCount() : 1;
+ const size_t length = N;
+ const size_t blockSize = (length + baselineNumBlocks-1) / baselineNumBlocks;
+ const size_t numBlocks = (length + blockSize-1) / blockSize;
+
+ dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
+
+ const size_t start = (currentBlock * blockSize);
+ const size_t blockLength = std::min(length - start, blockSize);
+ const size_t end = start + blockLength;
+
+ for(size_t i=start; i < end; i++)
+ {
+ func(i);
+ }
+ });
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+
+#elif defined(TASKING_PPL)
+ concurrency::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+#else
+# error "no tasking system enabled"
+#endif
+ }
+
+ /* parallel for with range and granulatity */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index first, const Index last, const Index minStepSize, const Func& func)
+ {
+ assert(first <= last);
+#if defined(TASKING_INTERNAL)
+ TaskScheduler::spawn(first,last,minStepSize,func);
+ if (!TaskScheduler::wait())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+
+#elif defined(TASKING_GCD) && defined(BUILD_IOS)
+
+ const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? 4*TaskScheduler::threadCount() : 1;
+ const size_t length = last - first;
+ const size_t blockSizeByThreads = (length + baselineNumBlocks-1) / baselineNumBlocks;
+ size_t blockSize = std::max<size_t>(minStepSize,blockSizeByThreads);
+ blockSize += blockSize % 4;
+
+ const size_t numBlocks = (length + blockSize-1) / blockSize;
+
+ dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
+
+ const size_t start = first + (currentBlock * blockSize);
+ const size_t end = std::min<size_t>(last, start + blockSize);
+
+ func( embree::range<Index>(start,end) );
+ });
+
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ },context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ });
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+
+#elif defined(TASKING_PPL)
+ concurrency::parallel_for(first, last, Index(1) /*minStepSize*/, [&](Index i) {
+ func(range<Index>(i,i+1));
+ });
+
+#else
+# error "no tasking system enabled"
+#endif
+ }
+
+ /* parallel for with range */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index first, const Index last, const Func& func)
+ {
+ assert(first <= last);
+ parallel_for(first,last,(Index)1,func);
+ }
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION > 4001)
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_static( const Index N, const Func& func)
+ {
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner(),context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner());
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+ }
+
+ typedef tbb::affinity_partitioner affinity_partitioner;
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_affinity( const Index N, const Func& func, tbb::affinity_partitioner& ap)
+ {
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap,context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap);
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+ }
+
+#else
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_static( const Index N, const Func& func)
+ {
+ parallel_for(N,func);
+ }
+
+ struct affinity_partitioner {
+ };
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_affinity( const Index N, const Func& func, affinity_partitioner& ap)
+ {
+ parallel_for(N,func);
+ }
+
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp
new file mode 100644
index 0000000000..0337611b35
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.cpp
@@ -0,0 +1,63 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_for_for.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_for_for_regression_test : public RegressionTest
+ {
+ parallel_for_for_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ /* create vector with random numbers */
+ size_t sum0 = 0;
+ size_t K = 0;
+ const size_t M = 1000;
+ std::vector<std::vector<size_t>* > array2(M);
+ for (size_t i=0; i<M; i++) {
+ const size_t N = rand() % 1024;
+ K+=N;
+ array2[i] = new std::vector<size_t>(N);
+ for (size_t j=0; j<N; j++)
+ sum0 += (*array2[i])[j] = rand();
+ }
+
+ /* array to test global index */
+ std::vector<atomic<size_t>> verify_k(K);
+ for (size_t i=0; i<K; i++) verify_k[i].store(0);
+
+ /* add all numbers using parallel_for_for */
+ std::atomic<size_t> sum1(0);
+ parallel_for_for( array2, size_t(1), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k) -> size_t
+ {
+ size_t s = 0;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ s += (*v)[i];
+ verify_k[k++]++;
+ }
+ sum1 += s;
+ return sum1;
+ });
+ passed &= (sum0 == sum1);
+
+ /* check global index */
+ for (size_t i=0; i<K; i++)
+ passed &= (verify_k[i] == 1);
+
+ /* delete vectors again */
+ for (size_t i=0; i<array2.size(); i++)
+ delete array2[i];
+
+ return passed;
+ }
+ };
+
+ parallel_for_for_regression_test parallel_for_for_regression("parallel_for_for_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.h b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.h
new file mode 100644
index 0000000000..852b8a0900
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for.h
@@ -0,0 +1,149 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename ArrayArray, typename Func>
+ __forceinline void sequential_for_for( ArrayArray& array2, const size_t minStepSize, const Func& func )
+ {
+ size_t k=0;
+ for (size_t i=0; i!=array2.size(); ++i) {
+ const size_t N = array2[i]->size();
+ if (N) func(array2[i],range<size_t>(0,N),k);
+ k+=N;
+ }
+ }
+
+ class ParallelForForState
+ {
+ public:
+
+ enum { MAX_TASKS = 64 };
+
+ __forceinline ParallelForForState ()
+ : taskCount(0) {}
+
+ template<typename ArrayArray>
+ __forceinline ParallelForForState (ArrayArray& array2, const size_t minStepSize) {
+ init(array2,minStepSize);
+ }
+
+ template<typename ArrayArray>
+ __forceinline void init ( ArrayArray& array2, const size_t minStepSize )
+ {
+ /* first calculate total number of elements */
+ size_t N = 0;
+ for (size_t i=0; i<array2.size(); i++) {
+ N += array2[i] ? array2[i]->size() : 0;
+ }
+ this->N = N;
+
+ /* calculate number of tasks to use */
+ const size_t numThreads = TaskScheduler::threadCount();
+ const size_t numBlocks = (N+minStepSize-1)/minStepSize;
+ taskCount = max(size_t(1),min(numThreads,numBlocks,size_t(ParallelForForState::MAX_TASKS)));
+
+ /* calculate start (i,j) for each task */
+ size_t taskIndex = 0;
+ i0[taskIndex] = 0;
+ j0[taskIndex] = 0;
+ size_t k0 = (++taskIndex)*N/taskCount;
+ for (size_t i=0, k=0; taskIndex < taskCount; i++)
+ {
+ assert(i<array2.size());
+ size_t j=0, M = array2[i] ? array2[i]->size() : 0;
+ while (j<M && k+M-j >= k0 && taskIndex < taskCount) {
+ assert(taskIndex<taskCount);
+ i0[taskIndex] = i;
+ j0[taskIndex] = j += k0-k;
+ k=k0;
+ k0 = (++taskIndex)*N/taskCount;
+ }
+ k+=M-j;
+ }
+ }
+
+ __forceinline size_t size() const {
+ return N;
+ }
+
+ public:
+ size_t i0[MAX_TASKS];
+ size_t j0[MAX_TASKS];
+ size_t taskCount;
+ size_t N;
+ };
+
+ template<typename ArrayArray, typename Func>
+ __forceinline void parallel_for_for( ArrayArray& array2, const size_t minStepSize, const Func& func )
+ {
+ ParallelForForState state(array2,minStepSize);
+
+ parallel_for(state.taskCount, [&](const size_t taskIndex)
+ {
+ /* calculate range */
+ const size_t k0 = (taskIndex+0)*state.size()/state.taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/state.taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t N = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(N,r0+k1-k);
+ if (r1 > r0) func(array2[i],range<size_t>(r0,r1),k);
+ k+=r1-r0; j0 = 0;
+ }
+ });
+ }
+
+ template<typename ArrayArray, typename Func>
+ __forceinline void parallel_for_for( ArrayArray& array2, const Func& func )
+ {
+ parallel_for_for(array2,1,func);
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_reduce( ArrayArray& array2, const size_t minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ ParallelForForState state(array2,minStepSize);
+ Value temp[ParallelForForState::MAX_TASKS];
+
+ for (size_t i=0; i<state.taskCount; i++)
+ temp[i] = identity;
+
+ parallel_for(state.taskCount, [&](const size_t taskIndex)
+ {
+ /* calculate range */
+ const size_t k0 = (taskIndex+0)*state.size()/state.taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/state.taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t N = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(N,r0+k1-k);
+ if (r1 > r0) temp[taskIndex] = reduction(temp[taskIndex],func(array2[i],range<size_t>(r0,r1),k));
+ k+=r1-r0; j0 = 0;
+ }
+ });
+
+ Value ret = identity;
+ for (size_t i=0; i<state.taskCount; i++)
+ ret = reduction(ret,temp[i]);
+ return ret;
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_reduce( ArrayArray& array2, const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_reduce(array2,1,identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp
new file mode 100644
index 0000000000..0169d8e481
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.cpp
@@ -0,0 +1,85 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_for_for_prefix_sum.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_for_for_prefix_sum_regression_test : public RegressionTest
+ {
+ parallel_for_for_prefix_sum_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ /* create vector with random numbers */
+ const size_t M = 10;
+ std::vector<atomic<size_t>> flattened;
+ typedef std::vector<std::vector<size_t>* > ArrayArray;
+ ArrayArray array2(M);
+ size_t K = 0;
+ for (size_t i=0; i<M; i++) {
+ const size_t N = rand() % 10;
+ K += N;
+ array2[i] = new std::vector<size_t>(N);
+ for (size_t j=0; j<N; j++)
+ (*array2[i])[j] = rand() % 10;
+ }
+
+ /* array to test global index */
+ std::vector<atomic<size_t>> verify_k(K);
+ for (size_t i=0; i<K; i++) verify_k[i].store(0);
+
+ ParallelForForPrefixSumState<size_t> state(array2,size_t(1));
+
+ /* dry run only counts */
+ size_t S = parallel_for_for_prefix_sum0( state, array2, size_t(0), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k, size_t i) -> size_t
+ {
+ size_t s = 0;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ s += (*v)[i];
+ verify_k[k++]++;
+ }
+ return s;
+ }, [](size_t v0, size_t v1) { return v0+v1; });
+
+ /* create properly sized output array */
+ flattened.resize(S);
+ for (auto& a : flattened) a.store(0);
+
+ /* now we actually fill the flattened array */
+ parallel_for_for_prefix_sum1( state, array2, size_t(0), [&](std::vector<size_t>* v, const range<size_t>& r, size_t k, size_t i, const size_t base) -> size_t
+ {
+ size_t s = 0;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ for (size_t j=0; j<(*v)[i]; j++) {
+ flattened[base+s+j]++;
+ }
+ s += (*v)[i];
+ verify_k[k++]++;
+ }
+ return s;
+ }, [](size_t v0, size_t v1) { return v0+v1; });
+
+ /* check global index */
+ for (size_t i=0; i<K; i++)
+ passed &= (verify_k[i] == 2);
+
+ /* check if each element was assigned exactly once */
+ for (size_t i=0; i<flattened.size(); i++)
+ passed &= (flattened[i] == 1);
+
+ /* delete arrays again */
+ for (size_t i=0; i<array2.size(); i++)
+ delete array2[i];
+
+ return passed;
+ }
+ };
+
+ parallel_for_for_prefix_sum_regression_test parallel_for_for_prefix_sum_regression("parallel_for_for_prefix_sum_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.h b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.h
new file mode 100644
index 0000000000..d2671d8a6a
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for_for_prefix_sum.h
@@ -0,0 +1,112 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for_for.h"
+#include "parallel_prefix_sum.h"
+
+namespace embree
+{
+ template<typename Value>
+ struct ParallelForForPrefixSumState : public ParallelForForState
+ {
+ __forceinline ParallelForForPrefixSumState () {}
+
+ template<typename ArrayArray>
+ __forceinline ParallelForForPrefixSumState (ArrayArray& array2, const size_t minStepSize)
+ : ParallelForForState(array2,minStepSize) {}
+
+ ParallelPrefixSumState<Value> prefix_state;
+ };
+
+ template<typename ArrayArray, typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum0( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2, Index minStepSize,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t taskCount = state.taskCount;
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t k0 = (taskIndex+0)*state.size()/taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ Value N=identity;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t size = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(size,r0+k1-k);
+ if (r1 > r0) N = reduction(N, func(array2[i],range<Index>((Index)r0,(Index)r1),(Index)k,(Index)i));
+ k+=r1-r0; j0 = 0;
+ }
+ state.prefix_state.counts[taskIndex] = N;
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.prefix_state.counts[i];
+ state.prefix_state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ template<typename ArrayArray, typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum1( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2, Index minStepSize,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t taskCount = state.taskCount;
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t k0 = (taskIndex+0)*state.size()/taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ Value N=identity;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t size = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(size,r0+k1-k);
+ if (r1 > r0) N = reduction(N, func(array2[i],range<Index>((Index)r0,(Index)r1),(Index)k,(Index)i,reduction(state.prefix_state.sums[taskIndex],N)));
+ k+=r1-r0; j0 = 0;
+ }
+ state.prefix_state.counts[taskIndex] = N;
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.prefix_state.counts[i];
+ state.prefix_state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum0( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_prefix_sum0(state,array2,size_t(1),identity,func,reduction);
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum1( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_prefix_sum1(state,array2,size_t(1),identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp
new file mode 100644
index 0000000000..09dc303f81
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_map.cpp
@@ -0,0 +1,47 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_map.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_map_regression_test : public RegressionTest
+ {
+ parallel_map_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ /* create key/value vectors with random numbers */
+ const size_t N = 10000;
+ std::vector<uint32_t> keys(N);
+ std::vector<uint32_t> vals(N);
+ for (size_t i=0; i<N; i++) keys[i] = 2*unsigned(i)*647382649;
+ for (size_t i=0; i<N; i++) std::swap(keys[i],keys[rand()%N]);
+ for (size_t i=0; i<N; i++) vals[i] = 2*rand();
+
+ /* create map */
+ parallel_map<uint32_t,uint32_t> map;
+ map.init(keys,vals);
+
+ /* check that all keys are properly mapped */
+ for (size_t i=0; i<N; i++) {
+ const uint32_t* val = map.lookup(keys[i]);
+ passed &= val && (*val == vals[i]);
+ }
+
+ /* check that these keys are not in the map */
+ for (size_t i=0; i<N; i++) {
+ passed &= !map.lookup(keys[i]+1);
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_map_regression_test parallel_map_regression("parallel_map_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_map.h b/thirdparty/embree-aarch64/common/algorithms/parallel_map.h
new file mode 100644
index 0000000000..02e1a8f8d0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_map.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_sort.h"
+
+namespace embree
+{
+ /*! implementation of a key/value map with parallel construction */
+ template<typename Key, typename Val>
+ class parallel_map
+ {
+ /* key/value pair to build the map */
+ struct KeyValue
+ {
+ __forceinline KeyValue () {}
+
+ __forceinline KeyValue (const Key key, const Val val)
+ : key(key), val(val) {}
+
+ __forceinline operator Key() const {
+ return key;
+ }
+
+ public:
+ Key key;
+ Val val;
+ };
+
+ public:
+
+ /*! parallel map constructors */
+ parallel_map () {}
+
+ /*! construction from pair of vectors */
+ template<typename KeyVector, typename ValVector>
+ parallel_map (const KeyVector& keys, const ValVector& values) { init(keys,values); }
+
+ /*! initialized the parallel map from a vector with keys and values */
+ template<typename KeyVector, typename ValVector>
+ void init(const KeyVector& keys, const ValVector& values)
+ {
+ /* reserve sufficient space for all data */
+ assert(keys.size() == values.size());
+ vec.resize(keys.size());
+
+ /* generate key/value pairs */
+ parallel_for( size_t(0), keys.size(), size_t(4*4096), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ vec[i] = KeyValue((Key)keys[i],values[i]);
+ });
+
+ /* perform parallel radix sort of the key/value pairs */
+ std::vector<KeyValue> temp(keys.size());
+ radix_sort<KeyValue,Key>(vec.data(),temp.data(),keys.size());
+ }
+
+ /*! Returns a pointer to the value associated with the specified key. The pointer will be nullptr of the key is not contained in the map. */
+ __forceinline const Val* lookup(const Key& key) const
+ {
+ typename std::vector<KeyValue>::const_iterator i = std::lower_bound(vec.begin(), vec.end(), key);
+ if (i == vec.end()) return nullptr;
+ if (i->key != key) return nullptr;
+ return &i->val;
+ }
+
+ /*! If the key is in the map, the function returns the value associated with the key, otherwise it returns the default value. */
+ __forceinline Val lookup(const Key& key, const Val& def) const
+ {
+ typename std::vector<KeyValue>::const_iterator i = std::lower_bound(vec.begin(), vec.end(), key);
+ if (i == vec.end()) return def;
+ if (i->key != key) return def;
+ return i->val;
+ }
+
+ /*! clears all state */
+ void clear() {
+ vec.clear();
+ }
+
+ private:
+ std::vector<KeyValue> vec; //!< vector containing sorted elements
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp
new file mode 100644
index 0000000000..eb20c4465d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_partition.cpp
@@ -0,0 +1,53 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_partition.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_partition_regression_test : public RegressionTest
+ {
+ parallel_partition_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ for (size_t i=0; i<100; i++)
+ {
+ /* create random permutation */
+ size_t N = std::rand() % 1000000;
+ std::vector<unsigned> array(N);
+ for (unsigned i=0; i<N; i++) array[i] = i;
+ for (auto& v : array) std::swap(v,array[std::rand()%array.size()]);
+ size_t split = std::rand() % (N+1);
+
+ /* perform parallel partitioning */
+ size_t left_sum = 0, right_sum = 0;
+ size_t mid = parallel_partitioning(array.data(),0,array.size(),0,left_sum,right_sum,
+ [&] ( size_t i ) { return i < split; },
+ [] ( size_t& sum, unsigned v) { sum += v; },
+ [] ( size_t& sum, size_t v) { sum += v; },
+ 128);
+
+ /*serial_partitioning(array.data(),0,array.size(),left_sum,right_sum,
+ [&] ( size_t i ) { return i < split; },
+ [] ( size_t& left_sum, int v) { left_sum += v; });*/
+
+ /* verify result */
+ passed &= mid == split;
+ passed &= left_sum == split*(split-1)/2;
+ passed &= right_sum == N*(N-1)/2-left_sum;
+ for (size_t i=0; i<split; i++) passed &= array[i] < split;
+ for (size_t i=split; i<N; i++) passed &= array[i] >= split;
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_partition_regression_test parallel_partition_regression("parallel_partition_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_partition.h b/thirdparty/embree-aarch64/common/algorithms/parallel_partition.h
new file mode 100644
index 0000000000..3b3ad7c854
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_partition.h
@@ -0,0 +1,283 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+#include "../math/range.h"
+
+namespace embree
+{
+ /* serial partitioning */
+ template<typename T, typename V, typename IsLeft, typename Reduction_T>
+ __forceinline size_t serial_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ V& leftReduction,
+ V& rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t)
+ {
+ T* l = array + begin;
+ T* r = array + end - 1;
+
+ while(1)
+ {
+ /* *l < pivot */
+ while (likely(l <= r && is_left(*l) ))
+ {
+ //prefetchw(l+4); // FIXME: enable?
+ reduction_t(leftReduction,*l);
+ ++l;
+ }
+ /* *r >= pivot) */
+ while (likely(l <= r && !is_left(*r)))
+ {
+ //prefetchw(r-4); FIXME: enable?
+ reduction_t(rightReduction,*r);
+ --r;
+ }
+ if (r<l) break;
+
+ reduction_t(leftReduction ,*r);
+ reduction_t(rightReduction,*l);
+ xchg(*l,*r);
+ l++; r--;
+ }
+
+ return l - array;
+ }
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ class __aligned(64) parallel_partition_task
+ {
+ ALIGNED_CLASS_(64);
+ private:
+
+ static const size_t MAX_TASKS = 64;
+
+ T* array;
+ size_t N;
+ const IsLeft& is_left;
+ const Reduction_T& reduction_t;
+ const Reduction_V& reduction_v;
+ const Vi& identity;
+
+ size_t numTasks;
+ __aligned(64) size_t counter_start[MAX_TASKS+1];
+ __aligned(64) size_t counter_left[MAX_TASKS+1];
+ __aligned(64) range<ssize_t> leftMisplacedRanges[MAX_TASKS];
+ __aligned(64) range<ssize_t> rightMisplacedRanges[MAX_TASKS];
+ __aligned(64) V leftReductions[MAX_TASKS];
+ __aligned(64) V rightReductions[MAX_TASKS];
+
+ public:
+
+ __forceinline parallel_partition_task(T* array,
+ const size_t N,
+ const Vi& identity,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ const size_t BLOCK_SIZE)
+
+ : array(array), N(N), is_left(is_left), reduction_t(reduction_t), reduction_v(reduction_v), identity(identity),
+ numTasks(min((N+BLOCK_SIZE-1)/BLOCK_SIZE,min(TaskScheduler::threadCount(),MAX_TASKS))) {}
+
+ __forceinline const range<ssize_t>* findStartRange(size_t& index, const range<ssize_t>* const r, const size_t numRanges)
+ {
+ size_t i = 0;
+ while(index >= (size_t)r[i].size())
+ {
+ assert(i < numRanges);
+ index -= (size_t)r[i].size();
+ i++;
+ }
+ return &r[i];
+ }
+
+ __forceinline void swapItemsInMisplacedRanges(const size_t numLeftMisplacedRanges,
+ const size_t numRightMisplacedRanges,
+ const size_t startID,
+ const size_t endID)
+ {
+ size_t leftLocalIndex = startID;
+ size_t rightLocalIndex = startID;
+ const range<ssize_t>* l_range = findStartRange(leftLocalIndex,leftMisplacedRanges,numLeftMisplacedRanges);
+ const range<ssize_t>* r_range = findStartRange(rightLocalIndex,rightMisplacedRanges,numRightMisplacedRanges);
+
+ size_t l_left = l_range->size() - leftLocalIndex;
+ size_t r_left = r_range->size() - rightLocalIndex;
+ T *__restrict__ l = &array[l_range->begin() + leftLocalIndex];
+ T *__restrict__ r = &array[r_range->begin() + rightLocalIndex];
+ size_t size = endID - startID;
+ size_t items = min(size,min(l_left,r_left));
+
+ while (size)
+ {
+ if (unlikely(l_left == 0))
+ {
+ l_range++;
+ l_left = l_range->size();
+ l = &array[l_range->begin()];
+ items = min(size,min(l_left,r_left));
+ }
+
+ if (unlikely(r_left == 0))
+ {
+ r_range++;
+ r_left = r_range->size();
+ r = &array[r_range->begin()];
+ items = min(size,min(l_left,r_left));
+ }
+
+ size -= items;
+ l_left -= items;
+ r_left -= items;
+
+ while(items) {
+ items--;
+ xchg(*l++,*r++);
+ }
+ }
+ }
+
+ __forceinline size_t partition(V& leftReduction, V& rightReduction)
+ {
+ /* partition the individual ranges for each task */
+ parallel_for(numTasks,[&] (const size_t taskID) {
+ const size_t startID = (taskID+0)*N/numTasks;
+ const size_t endID = (taskID+1)*N/numTasks;
+ V local_left(identity);
+ V local_right(identity);
+ const size_t mid = serial_partitioning(array,startID,endID,local_left,local_right,is_left,reduction_t);
+ counter_start[taskID] = startID;
+ counter_left [taskID] = mid-startID;
+ leftReductions[taskID] = local_left;
+ rightReductions[taskID] = local_right;
+ });
+ counter_start[numTasks] = N;
+ counter_left[numTasks] = 0;
+
+ /* finalize the reductions */
+ for (size_t i=0; i<numTasks; i++) {
+ reduction_v(leftReduction,leftReductions[i]);
+ reduction_v(rightReduction,rightReductions[i]);
+ }
+
+ /* calculate mid point for partitioning */
+ size_t mid = counter_left[0];
+ for (size_t i=1; i<numTasks; i++)
+ mid += counter_left[i];
+ const range<ssize_t> globalLeft (0,mid);
+ const range<ssize_t> globalRight(mid,N);
+
+ /* calculate all left and right ranges that are on the wrong global side */
+ size_t numMisplacedRangesLeft = 0;
+ size_t numMisplacedRangesRight = 0;
+ size_t numMisplacedItemsLeft = 0;
+ size_t numMisplacedItemsRight = 0;
+
+ for (size_t i=0; i<numTasks; i++)
+ {
+ const range<ssize_t> left_range (counter_start[i], counter_start[i] + counter_left[i]);
+ const range<ssize_t> right_range(counter_start[i] + counter_left[i], counter_start[i+1]);
+ const range<ssize_t> left_misplaced = globalLeft. intersect(right_range);
+ const range<ssize_t> right_misplaced = globalRight.intersect(left_range);
+
+ if (!left_misplaced.empty())
+ {
+ numMisplacedItemsLeft += left_misplaced.size();
+ leftMisplacedRanges[numMisplacedRangesLeft++] = left_misplaced;
+ }
+
+ if (!right_misplaced.empty())
+ {
+ numMisplacedItemsRight += right_misplaced.size();
+ rightMisplacedRanges[numMisplacedRangesRight++] = right_misplaced;
+ }
+ }
+ assert( numMisplacedItemsLeft == numMisplacedItemsRight );
+
+ /* if no items are misplaced we are done */
+ if (numMisplacedItemsLeft == 0)
+ return mid;
+
+ /* otherwise we copy the items to the right place in parallel */
+ parallel_for(numTasks,[&] (const size_t taskID) {
+ const size_t startID = (taskID+0)*numMisplacedItemsLeft/numTasks;
+ const size_t endID = (taskID+1)*numMisplacedItemsLeft/numTasks;
+ swapItemsInMisplacedRanges(numMisplacedRangesLeft,numMisplacedRangesRight,startID,endID);
+ });
+
+ return mid;
+ }
+ };
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ __noinline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const Vi &identity,
+ V &leftReduction,
+ V &rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ size_t BLOCK_SIZE = 128)
+ {
+ /* fall back to single threaded partitioning for small N */
+ if (unlikely(end-begin < BLOCK_SIZE))
+ return serial_partitioning(array,begin,end,leftReduction,rightReduction,is_left,reduction_t);
+
+ /* otherwise use parallel code */
+ else {
+ typedef parallel_partition_task<T,V,Vi,IsLeft,Reduction_T,Reduction_V> partition_task;
+ std::unique_ptr<partition_task> p(new partition_task(&array[begin],end-begin,identity,is_left,reduction_t,reduction_v,BLOCK_SIZE));
+ return begin+p->partition(leftReduction,rightReduction);
+ }
+ }
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ __noinline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const Vi &identity,
+ V &leftReduction,
+ V &rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ size_t BLOCK_SIZE,
+ size_t PARALLEL_THRESHOLD)
+ {
+ /* fall back to single threaded partitioning for small N */
+ if (unlikely(end-begin < PARALLEL_THRESHOLD))
+ return serial_partitioning(array,begin,end,leftReduction,rightReduction,is_left,reduction_t);
+
+ /* otherwise use parallel code */
+ else {
+ typedef parallel_partition_task<T,V,Vi,IsLeft,Reduction_T,Reduction_V> partition_task;
+ std::unique_ptr<partition_task> p(new partition_task(&array[begin],end-begin,identity,is_left,reduction_t,reduction_v,BLOCK_SIZE));
+ return begin+p->partition(leftReduction,rightReduction);
+ }
+ }
+
+
+ template<typename T, typename IsLeft>
+ inline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const IsLeft& is_left,
+ size_t BLOCK_SIZE = 128)
+ {
+ size_t leftReduction = 0;
+ size_t rightReduction = 0;
+ return parallel_partitioning(
+ array,begin,end,0,leftReduction,rightReduction,is_left,
+ [] (size_t& t,const T& ref) { },
+ [] (size_t& t0,size_t& t1) { },
+ BLOCK_SIZE);
+ }
+
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp
new file mode 100644
index 0000000000..685952c3dc
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.cpp
@@ -0,0 +1,48 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_prefix_sum.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_prefix_sum_regression_test : public RegressionTest
+ {
+ parallel_prefix_sum_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+ const size_t M = 10;
+
+ for (size_t N=10; N<10000000; N=size_t(2.1*N))
+ {
+ /* initialize array with random numbers */
+ uint32_t sum0 = 0;
+ std::vector<uint32_t> src(N);
+ for (size_t i=0; i<N; i++) {
+ sum0 += src[i] = rand();
+ }
+
+ /* calculate parallel prefix sum */
+ std::vector<uint32_t> dst(N);
+ for (auto& v : dst) v = 0;
+
+ for (size_t i=0; i<M; i++) {
+ uint32_t sum1 = parallel_prefix_sum(src,dst,N,0,std::plus<uint32_t>());
+ passed &= (sum0 == sum1);
+ }
+
+ /* check if prefix sum is correct */
+ for (size_t i=0, sum=0; i<N; sum+=src[i++])
+ passed &= ((uint32_t)sum == dst[i]);
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_prefix_sum_regression_test parallel_prefix_sum_regression("parallel_prefix_sum_regression");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.h b/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.h
new file mode 100644
index 0000000000..117c7a79b0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_prefix_sum.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Value>
+ struct ParallelPrefixSumState
+ {
+ enum { MAX_TASKS = 64 };
+ Value counts[MAX_TASKS];
+ Value sums [MAX_TASKS];
+ };
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_prefix_sum( ParallelPrefixSumState<Value>& state, Index first, Index last, Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t numThreads = TaskScheduler::threadCount();
+ const size_t numBlocks = (last-first+minStepSize-1)/minStepSize;
+ const size_t taskCount = min(numThreads,numBlocks,size_t(ParallelPrefixSumState<Value>::MAX_TASKS));
+
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t i0 = first+(taskIndex+0)*(last-first)/taskCount;
+ const size_t i1 = first+(taskIndex+1)*(last-first)/taskCount;
+ state.counts[taskIndex] = func(range<size_t>(i0,i1),state.sums[taskIndex]);
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.counts[i];
+ state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ /*! parallel calculation of prefix sums */
+ template<typename SrcArray, typename DstArray, typename Value, typename Add>
+ __forceinline Value parallel_prefix_sum(const SrcArray& src, DstArray& dst, size_t N, const Value& identity, const Add& add, const size_t SINGLE_THREAD_THRESHOLD = 4096)
+ {
+ /* perform single threaded prefix operation for small N */
+ if (N < SINGLE_THREAD_THRESHOLD)
+ {
+ Value sum=identity;
+ for (size_t i=0; i<N; sum=add(sum,src[i++])) dst[i] = sum;
+ return sum;
+ }
+
+ /* perform parallel prefix operation for large N */
+ else
+ {
+ ParallelPrefixSumState<Value> state;
+
+ /* initial run just sets up start values for subtasks */
+ parallel_prefix_sum( state, size_t(0), size_t(N), size_t(1024), identity, [&](const range<size_t>& r, const Value& sum) -> Value {
+
+ Value s = identity;
+ for (size_t i=r.begin(); i<r.end(); i++) s = add(s,src[i]);
+ return s;
+
+ }, add);
+
+ /* final run calculates prefix sum */
+ return parallel_prefix_sum( state, size_t(0), size_t(N), size_t(1024), identity, [&](const range<size_t>& r, const Value& sum) -> Value {
+
+ Value s = identity;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ dst[i] = add(sum,s);
+ s = add(s,src[i]);
+ }
+ return s;
+
+ }, add);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp
new file mode 100644
index 0000000000..331fe4288e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.cpp
@@ -0,0 +1,49 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_reduce.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_reduce_regression_test : public RegressionTest
+ {
+ parallel_reduce_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ const size_t M = 10;
+ for (size_t N=10; N<10000000; N=size_t(2.1*N))
+ {
+ /* sequentially calculate sum of squares */
+ size_t sum0 = 0;
+ for (size_t i=0; i<N; i++) {
+ sum0 += i*i;
+ }
+
+ /* parallel calculation of sum of squares */
+ for (size_t m=0; m<M; m++)
+ {
+ size_t sum1 = parallel_reduce( size_t(0), size_t(N), size_t(1024), size_t(0), [&](const range<size_t>& r) -> size_t
+ {
+ size_t s = 0;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ s += i*i;
+ return s;
+ },
+ [](const size_t v0, const size_t v1) {
+ return v0+v1;
+ });
+ passed = sum0 == sum1;
+ }
+ }
+ return passed;
+ }
+ };
+
+ parallel_reduce_regression_test parallel_reduce_regression("parallel_reduce_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h
new file mode 100644
index 0000000000..0daf94e50e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h
@@ -0,0 +1,150 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value sequential_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return func(range<Index>(first,last));
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value sequential_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return func(range<Index>(first,last));
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __noinline Value parallel_reduce_internal( Index taskCount, const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ const Index maxTasks = 512;
+ const Index threadCount = (Index) TaskScheduler::threadCount();
+ taskCount = min(taskCount,threadCount,maxTasks);
+
+ /* parallel invokation of all tasks */
+ dynamic_large_stack_array(Value,values,taskCount,8192); // consumes at most 8192 bytes on the stack
+ parallel_for(taskCount, [&](const Index taskIndex) {
+ const Index k0 = first+(taskIndex+0)*(last-first)/taskCount;
+ const Index k1 = first+(taskIndex+1)*(last-first)/taskCount;
+ values[taskIndex] = func(range<Index>(k0,k1));
+ });
+
+ /* perform reduction over all tasks */
+ Value v = identity;
+ for (Index i=0; i<taskCount; i++) v = reduction(v,values[i]);
+ return v;
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+#if defined(TASKING_INTERNAL) || (defined(TASKING_GCD) && defined(BUILD_IOS))
+
+ /* fast path for small number of iterations */
+ Index taskCount = (last-first+minStepSize-1)/minStepSize;
+ if (likely(taskCount == 1)) {
+ return func(range<Index>(first,last));
+ }
+ return parallel_reduce_internal(taskCount,first,last,minStepSize,identity,func,reduction);
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction,context);
+ // -- GODOT start --
+ // if (context.is_group_execution_cancelled())
+ // throw std::runtime_error("task cancelled");
+ // -- GODOT end --
+ return v;
+ #else
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction);
+ // -- GODOT start --
+ // if (tbb::task::self().is_cancelled())
+ // throw std::runtime_error("task cancelled");
+ // -- GODOT end --
+ return v;
+ #endif
+#else // TASKING_PPL
+ struct AlignedValue
+ {
+ char storage[__alignof(Value)+sizeof(Value)];
+ static uintptr_t alignUp(uintptr_t p, size_t a) { return p + (~(p - 1) % a); };
+ Value* getValuePtr() { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
+ const Value* getValuePtr() const { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
+ AlignedValue(const Value& v) { new(getValuePtr()) Value(v); }
+ AlignedValue(const AlignedValue& v) { new(getValuePtr()) Value(*v.getValuePtr()); }
+ AlignedValue(const AlignedValue&& v) { new(getValuePtr()) Value(*v.getValuePtr()); };
+ AlignedValue& operator = (const AlignedValue& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
+ AlignedValue& operator = (const AlignedValue&& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
+ operator Value() const { return *getValuePtr(); }
+ };
+
+ struct Iterator_Index
+ {
+ Index v;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef AlignedValue value_type;
+ typedef Index difference_type;
+ typedef Index distance_type;
+ typedef AlignedValue* pointer;
+ typedef AlignedValue& reference;
+ __forceinline Iterator_Index() {}
+ __forceinline Iterator_Index(Index v) : v(v) {}
+ __forceinline bool operator== (Iterator_Index other) { return v == other.v; }
+ __forceinline bool operator!= (Iterator_Index other) { return v != other.v; }
+ __forceinline Iterator_Index operator++() { return Iterator_Index(++v); }
+ __forceinline Iterator_Index operator++(int) { return Iterator_Index(v++); }
+ };
+
+ auto range_reduction = [&](Iterator_Index begin, Iterator_Index end, const AlignedValue& start) {
+ assert(begin.v < end.v);
+ return reduction(start, func(range<Index>(begin.v, end.v)));
+ };
+ const Value v = concurrency::parallel_reduce(Iterator_Index(first), Iterator_Index(last), AlignedValue(identity), range_reduction, reduction);
+ return v;
+#endif
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ if (likely(last-first < parallel_threshold)) {
+ return func(range<Index>(first,last));
+ } else {
+ return parallel_reduce(first,last,minStepSize,identity,func,reduction);
+ }
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const range<Index> range, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return parallel_reduce(range.begin(),range.end(),minStepSize,parallel_threshold,identity,func,reduction);
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ auto funcr = [&] ( const range<Index> r ) {
+ Value v = identity;
+ for (Index i=r.begin(); i<r.end(); i++)
+ v = reduction(v,func(i));
+ return v;
+ };
+ return parallel_reduce(first,last,Index(1),identity,funcr,reduction);
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const range<Index> range, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return parallel_reduce(range.begin(),range.end(),Index(1),identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp
new file mode 100644
index 0000000000..20b639c1c9
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_set.cpp
@@ -0,0 +1,43 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_set.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ struct parallel_set_regression_test : public RegressionTest
+ {
+ parallel_set_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+
+ /* create vector with random numbers */
+ const size_t N = 10000;
+ std::vector<uint32_t> unsorted(N);
+ for (size_t i=0; i<N; i++) unsorted[i] = 2*rand();
+
+ /* created set from numbers */
+ parallel_set<uint32_t> sorted;
+ sorted.init(unsorted);
+
+ /* check that all elements are in the set */
+ for (size_t i=0; i<N; i++) {
+ passed &= sorted.lookup(unsorted[i]);
+ }
+
+ /* check that these elements are not in the set */
+ for (size_t i=0; i<N; i++) {
+ passed &= !sorted.lookup(unsorted[i]+1);
+ }
+
+ return passed;
+ }
+ };
+
+ parallel_set_regression_test parallel_set_regression("parallel_set_regression_test");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_set.h b/thirdparty/embree-aarch64/common/algorithms/parallel_set.h
new file mode 100644
index 0000000000..640beba7ec
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_set.h
@@ -0,0 +1,52 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_sort.h"
+
+namespace embree
+{
+ /* implementation of a set of values with parallel construction */
+ template<typename T>
+ class parallel_set
+ {
+ public:
+
+ /*! default constructor for the parallel set */
+ parallel_set () {}
+
+ /*! construction from vector */
+ template<typename Vector>
+ parallel_set (const Vector& in) { init(in); }
+
+ /*! initialized the parallel set from a vector */
+ template<typename Vector>
+ void init(const Vector& in)
+ {
+ /* copy data to internal vector */
+ vec.resize(in.size());
+ parallel_for( size_t(0), in.size(), size_t(4*4096), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ vec[i] = in[i];
+ });
+
+ /* sort the data */
+ std::vector<T> temp(in.size());
+ radix_sort<T>(vec.data(),temp.data(),vec.size());
+ }
+
+ /*! tests if some element is in the set */
+ __forceinline bool lookup(const T& elt) const {
+ return std::binary_search(vec.begin(), vec.end(), elt);
+ }
+
+ /*! clears all state */
+ void clear() {
+ vec.clear();
+ }
+
+ private:
+ std::vector<T> vec; //!< vector containing sorted elements
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp b/thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp
new file mode 100644
index 0000000000..5e7ec79ac1
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_sort.cpp
@@ -0,0 +1,50 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "parallel_sort.h"
+#include "../sys/regression.h"
+
+namespace embree
+{
+ template<typename Key>
+ struct RadixSortRegressionTest : public RegressionTest
+ {
+ RadixSortRegressionTest(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+ const size_t M = 10;
+
+ for (size_t N=10; N<1000000; N=size_t(2.1*N))
+ {
+ std::vector<Key> src(N); memset(src.data(),0,N*sizeof(Key));
+ std::vector<Key> tmp(N); memset(tmp.data(),0,N*sizeof(Key));
+ for (size_t i=0; i<N; i++) src[i] = uint64_t(rand())*uint64_t(rand());
+
+ /* calculate checksum */
+ Key sum0 = 0; for (size_t i=0; i<N; i++) sum0 += src[i];
+
+ /* sort numbers */
+ for (size_t i=0; i<M; i++) {
+ radix_sort<Key>(src.data(),tmp.data(),N);
+ }
+
+ /* calculate checksum */
+ Key sum1 = 0; for (size_t i=0; i<N; i++) sum1 += src[i];
+ if (sum0 != sum1) passed = false;
+
+ /* check if numbers are sorted */
+ for (size_t i=1; i<N; i++)
+ passed &= src[i-1] <= src[i];
+ }
+
+ return passed;
+ }
+ };
+
+ RadixSortRegressionTest<uint32_t> test_u32("RadixSortRegressionTestU32");
+ RadixSortRegressionTest<uint64_t> test_u64("RadixSortRegressionTestU64");
+}
diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_sort.h b/thirdparty/embree-aarch64/common/algorithms/parallel_sort.h
new file mode 100644
index 0000000000..a758227c1b
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/algorithms/parallel_sort.h
@@ -0,0 +1,457 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../simd/simd.h"
+#include "parallel_for.h"
+#if defined(TASKING_GCD) && defined(BUILD_IOS)
+#include "../sys/alloc.h"
+#endif
+#include <algorithm>
+
+namespace embree
+{
+ template<class T>
+ __forceinline void insertionsort_ascending(T *__restrict__ array, const size_t length)
+ {
+ for(size_t i = 1;i<length;++i)
+ {
+ T v = array[i];
+ size_t j = i;
+ while(j > 0 && v < array[j-1])
+ {
+ array[j] = array[j-1];
+ --j;
+ }
+ array[j] = v;
+ }
+ }
+
+ template<class T>
+ __forceinline void insertionsort_decending(T *__restrict__ array, const size_t length)
+ {
+ for(size_t i = 1;i<length;++i)
+ {
+ T v = array[i];
+ size_t j = i;
+ while(j > 0 && v > array[j-1])
+ {
+ array[j] = array[j-1];
+ --j;
+ }
+ array[j] = v;
+ }
+ }
+
+ template<class T>
+ void quicksort_ascending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] > pivotvalue);
+ while (t[++left] < pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const int pivot = right;
+ quicksort_ascending(t, begin, pivot);
+ quicksort_ascending(t, pivot + 1, end);
+ }
+ }
+
+ template<class T>
+ void quicksort_decending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] < pivotvalue);
+ while (t[++left] > pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const int pivot = right;
+ quicksort_decending(t, begin, pivot);
+ quicksort_decending(t, pivot + 1, end);
+ }
+ }
+
+
+ template<class T, ssize_t THRESHOLD>
+ void quicksort_insertionsort_ascending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const ssize_t size = end-begin+1;
+ if (likely(size <= THRESHOLD))
+ {
+ insertionsort_ascending<T>(&t[begin],size);
+ }
+ else
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] > pivotvalue);
+ while (t[++left] < pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const ssize_t pivot = right;
+ quicksort_insertionsort_ascending<T,THRESHOLD>(t, begin, pivot);
+ quicksort_insertionsort_ascending<T,THRESHOLD>(t, pivot + 1, end);
+ }
+ }
+ }
+
+
+ template<class T, ssize_t THRESHOLD>
+ void quicksort_insertionsort_decending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const ssize_t size = end-begin+1;
+ if (likely(size <= THRESHOLD))
+ {
+ insertionsort_decending<T>(&t[begin],size);
+ }
+ else
+ {
+
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] < pivotvalue);
+ while (t[++left] > pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const ssize_t pivot = right;
+ quicksort_insertionsort_decending<T,THRESHOLD>(t, begin, pivot);
+ quicksort_insertionsort_decending<T,THRESHOLD>(t, pivot + 1, end);
+ }
+ }
+ }
+
+ template<typename T>
+ static void radixsort32(T* const morton, const size_t num, const unsigned int shift = 3*8)
+ {
+ static const unsigned int BITS = 8;
+ static const unsigned int BUCKETS = (1 << BITS);
+ static const unsigned int CMP_SORT_THRESHOLD = 16;
+
+ __aligned(64) unsigned int count[BUCKETS];
+
+ /* clear buckets */
+ for (size_t i=0;i<BUCKETS;i++) count[i] = 0;
+
+ /* count buckets */
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=0;i<num;i++)
+ count[(unsigned(morton[i]) >> shift) & (BUCKETS-1)]++;
+
+ /* prefix sums */
+ __aligned(64) unsigned int head[BUCKETS];
+ __aligned(64) unsigned int tail[BUCKETS];
+
+ head[0] = 0;
+ for (size_t i=1; i<BUCKETS; i++)
+ head[i] = head[i-1] + count[i-1];
+
+ for (size_t i=0; i<BUCKETS-1; i++)
+ tail[i] = head[i+1];
+
+ tail[BUCKETS-1] = head[BUCKETS-1] + count[BUCKETS-1];
+
+ assert(tail[BUCKETS-1] == head[BUCKETS-1] + count[BUCKETS-1]);
+ assert(tail[BUCKETS-1] == num);
+
+ /* in-place swap */
+ for (size_t i=0;i<BUCKETS;i++)
+ {
+ /* process bucket */
+ while(head[i] < tail[i])
+ {
+ T v = morton[head[i]];
+ while(1)
+ {
+ const size_t b = (unsigned(v) >> shift) & (BUCKETS-1);
+ if (b == i) break;
+ std::swap(v,morton[head[b]++]);
+ }
+ assert((unsigned(v) >> shift & (BUCKETS-1)) == i);
+ morton[head[i]++] = v;
+ }
+ }
+ if (shift == 0) return;
+
+ size_t offset = 0;
+ for (size_t i=0;i<BUCKETS;i++)
+ if (count[i])
+ {
+
+ for (size_t j=offset;j<offset+count[i]-1;j++)
+ assert(((unsigned(morton[j]) >> shift) & (BUCKETS-1)) == i);
+
+ if (unlikely(count[i] < CMP_SORT_THRESHOLD))
+ insertionsort_ascending(morton + offset, count[i]);
+ else
+ radixsort32(morton + offset, count[i], shift-BITS);
+
+ for (size_t j=offset;j<offset+count[i]-1;j++)
+ assert(morton[j] <= morton[j+1]);
+
+ offset += count[i];
+ }
+ }
+
+ template<typename Ty, typename Key>
+ class ParallelRadixSort
+ {
+ static const size_t MAX_TASKS = 64;
+ static const size_t BITS = 8;
+ static const size_t BUCKETS = (1 << BITS);
+ typedef unsigned int TyRadixCount[BUCKETS];
+
+ template<typename T>
+ static bool compare(const T& v0, const T& v1) {
+ return (Key)v0 < (Key)v1;
+ }
+
+ private:
+ ParallelRadixSort (const ParallelRadixSort& other) DELETED; // do not implement
+ ParallelRadixSort& operator= (const ParallelRadixSort& other) DELETED; // do not implement
+
+
+ public:
+ ParallelRadixSort (Ty* const src, Ty* const tmp, const size_t N)
+ : radixCount(nullptr), src(src), tmp(tmp), N(N) {}
+
+ void sort(const size_t blockSize)
+ {
+ assert(blockSize > 0);
+
+ /* perform single threaded sort for small N */
+ if (N<=blockSize) // handles also special case of 0!
+ {
+ /* do inplace sort inside destination array */
+ std::sort(src,src+N,compare<Ty>);
+ }
+
+ /* perform parallel sort for large N */
+ else
+ {
+ const size_t numThreads = min((N+blockSize-1)/blockSize,TaskScheduler::threadCount(),size_t(MAX_TASKS));
+ tbbRadixSort(numThreads);
+ }
+ }
+
+ ~ParallelRadixSort()
+ {
+ alignedFree(radixCount);
+ radixCount = nullptr;
+ }
+
+ private:
+
+ void tbbRadixIteration0(const Key shift,
+ const Ty* __restrict const src,
+ Ty* __restrict const dst,
+ const size_t threadIndex, const size_t threadCount)
+ {
+ const size_t startID = (threadIndex+0)*N/threadCount;
+ const size_t endID = (threadIndex+1)*N/threadCount;
+
+ /* mask to extract some number of bits */
+ const Key mask = BUCKETS-1;
+
+ /* count how many items go into the buckets */
+ for (size_t i=0; i<BUCKETS; i++)
+ radixCount[threadIndex][i] = 0;
+
+ /* iterate over src array and count buckets */
+ unsigned int * __restrict const count = radixCount[threadIndex];
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=startID; i<endID; i++) {
+#if defined(__X86_64__) || defined(__aarch64__)
+ const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
+#else
+ const Key index = ((Key)src[i] >> shift) & mask;
+#endif
+ count[index]++;
+ }
+ }
+
+ void tbbRadixIteration1(const Key shift,
+ const Ty* __restrict const src,
+ Ty* __restrict const dst,
+ const size_t threadIndex, const size_t threadCount)
+ {
+ const size_t startID = (threadIndex+0)*N/threadCount;
+ const size_t endID = (threadIndex+1)*N/threadCount;
+
+ /* mask to extract some number of bits */
+ const Key mask = BUCKETS-1;
+
+ /* calculate total number of items for each bucket */
+ __aligned(64) unsigned int total[BUCKETS];
+ /*
+ for (size_t i=0; i<BUCKETS; i++)
+ total[i] = 0;
+ */
+ for (size_t i=0; i<BUCKETS; i+=VSIZEX)
+ vintx::store(&total[i], zero);
+
+ for (size_t i=0; i<threadCount; i++)
+ {
+ /*
+ for (size_t j=0; j<BUCKETS; j++)
+ total[j] += radixCount[i][j];
+ */
+ for (size_t j=0; j<BUCKETS; j+=VSIZEX)
+ vintx::store(&total[j], vintx::load(&total[j]) + vintx::load(&radixCount[i][j]));
+ }
+
+ /* calculate start offset of each bucket */
+ __aligned(64) unsigned int offset[BUCKETS];
+ offset[0] = 0;
+ for (size_t i=1; i<BUCKETS; i++)
+ offset[i] = offset[i-1] + total[i-1];
+
+ /* calculate start offset of each bucket for this thread */
+ for (size_t i=0; i<threadIndex; i++)
+ {
+ /*
+ for (size_t j=0; j<BUCKETS; j++)
+ offset[j] += radixCount[i][j];
+ */
+ for (size_t j=0; j<BUCKETS; j+=VSIZEX)
+ vintx::store(&offset[j], vintx::load(&offset[j]) + vintx::load(&radixCount[i][j]));
+ }
+
+ /* copy items into their buckets */
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=startID; i<endID; i++) {
+ const Ty elt = src[i];
+#if defined(__X86_64__) || defined(__aarch64__)
+ const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
+#else
+ const size_t index = ((Key)src[i] >> shift) & mask;
+#endif
+ dst[offset[index]++] = elt;
+ }
+ }
+
+ void tbbRadixIteration(const Key shift, const bool last,
+ const Ty* __restrict src, Ty* __restrict dst,
+ const size_t numTasks)
+ {
+ affinity_partitioner ap;
+ parallel_for_affinity(numTasks,[&] (size_t taskIndex) { tbbRadixIteration0(shift,src,dst,taskIndex,numTasks); },ap);
+ parallel_for_affinity(numTasks,[&] (size_t taskIndex) { tbbRadixIteration1(shift,src,dst,taskIndex,numTasks); },ap);
+ }
+
+ void tbbRadixSort(const size_t numTasks)
+ {
+ radixCount = (TyRadixCount*) alignedMalloc(MAX_TASKS*sizeof(TyRadixCount),64);
+
+ if (sizeof(Key) == sizeof(uint32_t)) {
+ tbbRadixIteration(0*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(1*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(2*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(3*BITS,1,tmp,src,numTasks);
+ }
+ else if (sizeof(Key) == sizeof(uint64_t))
+ {
+ tbbRadixIteration(0*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(1*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(2*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(3*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(4*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(5*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(6*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(7*BITS,1,tmp,src,numTasks);
+ }
+ }
+
+ private:
+ TyRadixCount* radixCount;
+ Ty* const src;
+ Ty* const tmp;
+ const size_t N;
+ };
+
+ template<typename Ty>
+ void radix_sort(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192)
+ {
+ ParallelRadixSort<Ty,Ty>(src,tmp,N).sort(blockSize);
+ }
+
+ template<typename Ty, typename Key>
+ void radix_sort(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192)
+ {
+ ParallelRadixSort<Ty,Key>(src,tmp,N).sort(blockSize);
+ }
+
+ template<typename Ty>
+ void radix_sort_u32(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192) {
+ radix_sort<Ty,uint32_t>(src,tmp,N,blockSize);
+ }
+
+ template<typename Ty>
+ void radix_sort_u64(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192) {
+ radix_sort<Ty,uint64_t>(src,tmp,N,blockSize);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/parsestream.h b/thirdparty/embree-aarch64/common/lexers/parsestream.h
new file mode 100644
index 0000000000..db46dc114f
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/parsestream.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stringstream.h"
+#include "../sys/filename.h"
+#include "../math/vec2.h"
+#include "../math/vec3.h"
+#include "../math/col3.h"
+#include "../math/color.h"
+
+namespace embree
+{
+ /*! helper class for simple command line parsing */
+ class ParseStream : public Stream<std::string>
+ {
+ public:
+ ParseStream (const Ref<Stream<std::string> >& cin) : cin(cin) {}
+
+ ParseStream (const Ref<Stream<int> >& cin, const std::string& seps = "\n\t\r ",
+ const std::string& endl = "", bool multiLine = false)
+ : cin(new StringStream(cin,seps,endl,multiLine)) {}
+
+ public:
+ ParseLocation location() { return cin->loc(); }
+ std::string next() { return cin->get(); }
+
+ void force(const std::string& next) {
+ std::string token = getString();
+ if (token != next)
+ THROW_RUNTIME_ERROR("token \""+next+"\" expected but token \""+token+"\" found");
+ }
+
+ std::string getString() {
+ return get();
+ }
+
+ FileName getFileName() {
+ return FileName(get());
+ }
+
+ int getInt () {
+ return atoi(get().c_str());
+ }
+
+ Vec2i getVec2i() {
+ int x = atoi(get().c_str());
+ int y = atoi(get().c_str());
+ return Vec2i(x,y);
+ }
+
+ Vec3ia getVec3ia() {
+ int x = atoi(get().c_str());
+ int y = atoi(get().c_str());
+ int z = atoi(get().c_str());
+ return Vec3ia(x,y,z);
+ }
+
+ float getFloat() {
+ return (float)atof(get().c_str());
+ }
+
+ Vec2f getVec2f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ return Vec2f(x,y);
+ }
+
+ Vec3f getVec3f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Vec3f(x,y,z);
+ }
+
+ Vec3fa getVec3fa() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Vec3fa(x,y,z);
+ }
+
+ Col3f getCol3f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Col3f(x,y,z);
+ }
+
+ Color getColor() {
+ float r = (float)atof(get().c_str());
+ float g = (float)atof(get().c_str());
+ float b = (float)atof(get().c_str());
+ return Color(r,g,b);
+ }
+
+ private:
+ Ref<Stream<std::string> > cin;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/stream.h b/thirdparty/embree-aarch64/common/lexers/stream.h
new file mode 100644
index 0000000000..3f75677e68
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/stream.h
@@ -0,0 +1,215 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/ref.h"
+#include "../sys/filename.h"
+#include "../sys/string.h"
+
+#include <vector>
+#include <iostream>
+#include <cstdio>
+#include <string.h>
+
+namespace embree
+{
+ /*! stores the location of a stream element in the source */
+ class ParseLocation
+ {
+ public:
+ ParseLocation () : lineNumber(-1), colNumber(-1) {}
+ ParseLocation (std::shared_ptr<std::string> fileName, ssize_t lineNumber, ssize_t colNumber, ssize_t /*charNumber*/)
+ : fileName(fileName), lineNumber(lineNumber), colNumber(colNumber) {}
+
+ std::string str() const
+ {
+ std::string str = "unknown";
+ if (fileName) str = *fileName;
+ if (lineNumber >= 0) str += " line " + toString(lineNumber);
+ if (lineNumber >= 0 && colNumber >= 0) str += " character " + toString(colNumber);
+ return str;
+ }
+
+ private:
+ std::shared_ptr<std::string> fileName; /// name of the file (or stream) the token is from
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ };
+
+ /*! a stream class templated over the stream elements */
+ template<typename T> class Stream : public RefCount
+ {
+ enum { BUF_SIZE = 1024 };
+
+ private:
+ virtual T next() = 0;
+ virtual ParseLocation location() = 0;
+ __forceinline std::pair<T,ParseLocation> nextHelper() {
+ ParseLocation l = location();
+ T v = next();
+ return std::pair<T,ParseLocation>(v,l);
+ }
+ __forceinline void push_back(const std::pair<T,ParseLocation>& v) {
+ if (past+future == BUF_SIZE) pop_front();
+ size_t end = (start+past+future++)%BUF_SIZE;
+ buffer[end] = v;
+ }
+ __forceinline void pop_front() {
+ if (past == 0) THROW_RUNTIME_ERROR("stream buffer empty");
+ start = (start+1)%BUF_SIZE; past--;
+ }
+ public:
+ Stream () : start(0), past(0), future(0), buffer(BUF_SIZE) {}
+ virtual ~Stream() {}
+
+ public:
+
+ const ParseLocation& loc() {
+ if (future == 0) push_back(nextHelper());
+ return buffer[(start+past)%BUF_SIZE].second;
+ }
+ T get() {
+ if (future == 0) push_back(nextHelper());
+ T t = buffer[(start+past)%BUF_SIZE].first;
+ past++; future--;
+ return t;
+ }
+ const T& peek() {
+ if (future == 0) push_back(nextHelper());
+ return buffer[(start+past)%BUF_SIZE].first;
+ }
+ const T& unget(size_t n = 1) {
+ if (past < n) THROW_RUNTIME_ERROR ("cannot unget that many items");
+ past -= n; future += n;
+ return peek();
+ }
+ void drop() {
+ if (future == 0) push_back(nextHelper());
+ past++; future--;
+ }
+ private:
+ size_t start,past,future;
+ std::vector<std::pair<T,ParseLocation> > buffer;
+ };
+
+ /*! warps an iostream stream */
+ class StdStream : public Stream<int>
+ {
+ public:
+ StdStream (std::istream& cin, const std::string& name = "std::stream")
+ : cin(cin), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
+ ~StdStream() {}
+ ParseLocation location() {
+ return ParseLocation(name,lineNumber,colNumber,charNumber);
+ }
+ int next() {
+ int c = cin.get();
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+ private:
+ std::istream& cin;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+
+ /*! creates a stream from a file */
+ class FileStream : public Stream<int>
+ {
+ public:
+
+ FileStream (FILE* file, const std::string& name = "file")
+ : file(file), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
+
+ FileStream (const FileName& fileName)
+ : lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str())))
+ {
+ file = fopen(fileName.c_str(),"r");
+ if (file == nullptr) THROW_RUNTIME_ERROR("cannot open file " + fileName.str());
+ }
+ ~FileStream() { if (file) fclose(file); }
+
+ public:
+ ParseLocation location() {
+ return ParseLocation(name,lineNumber,colNumber,charNumber);
+ }
+
+ int next() {
+ int c = fgetc(file);
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+
+ private:
+ FILE* file;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+
+ /*! creates a stream from a string */
+ class StrStream : public Stream<int>
+ {
+ public:
+
+ StrStream (const char* str)
+ : str(str), lineNumber(1), colNumber(0), charNumber(0) {}
+
+ public:
+ ParseLocation location() {
+ return ParseLocation(std::shared_ptr<std::string>(),lineNumber,colNumber,charNumber);
+ }
+
+ int next() {
+ int c = str[charNumber];
+ if (c == 0) return EOF;
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+
+ private:
+ const char* str;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ };
+
+ /*! creates a character stream from a command line */
+ class CommandLineStream : public Stream<int>
+ {
+ public:
+ CommandLineStream (int argc, char** argv, const std::string& name = "command line")
+ : i(0), j(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name)))
+ {
+ if (argc > 0) {
+ for (size_t i=0; argv[0][i] && i<1024; i++) charNumber++;
+ charNumber++;
+ }
+ for (ssize_t k=1; k<argc; k++) args.push_back(argv[k]);
+ }
+ ~CommandLineStream() {}
+ public:
+ ParseLocation location() {
+ return ParseLocation(name,0,charNumber,charNumber);
+ }
+ int next() {
+ if (i == args.size()) return EOF;
+ if (j == args[i].size()) { i++; j=0; charNumber++; return ' '; }
+ charNumber++;
+ return args[i][j++];
+ }
+ private:
+ size_t i,j;
+ std::vector<std::string> args;
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/streamfilters.h b/thirdparty/embree-aarch64/common/lexers/streamfilters.h
new file mode 100644
index 0000000000..25580a77b8
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/streamfilters.h
@@ -0,0 +1,39 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+
+namespace embree
+{
+ /* removes all line comments from a stream */
+ class LineCommentFilter : public Stream<int>
+ {
+ public:
+ LineCommentFilter (const FileName& fileName, const std::string& lineComment)
+ : cin(new FileStream(fileName)), lineComment(lineComment) {}
+ LineCommentFilter (Ref<Stream<int> > cin, const std::string& lineComment)
+ : cin(cin), lineComment(lineComment) {}
+
+ ParseLocation location() { return cin->loc(); }
+
+ int next()
+ {
+ /* look if the line comment starts here */
+ for (size_t j=0; j<lineComment.size(); j++) {
+ if (cin->peek() != lineComment[j]) { cin->unget(j); goto not_found; }
+ cin->get();
+ }
+ /* eat all characters until the end of the line (or file) */
+ while (cin->peek() != '\n' && cin->peek() != EOF) cin->get();
+
+ not_found:
+ return cin->get();
+ }
+
+ private:
+ Ref<Stream<int> > cin;
+ std::string lineComment;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/stringstream.cpp b/thirdparty/embree-aarch64/common/lexers/stringstream.cpp
new file mode 100644
index 0000000000..98dc80ad59
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/stringstream.cpp
@@ -0,0 +1,51 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "stringstream.h"
+
+namespace embree
+{
+ static const std::string stringChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _.,+-=:/*\\";
+
+ /* creates map for fast categorization of characters */
+ static void createCharMap(bool map[256], const std::string& chrs) {
+ for (size_t i=0; i<256; i++) map[i] = false;
+ for (size_t i=0; i<chrs.size(); i++) map[uint8_t(chrs[i])] = true;
+ }
+
+ /* simple tokenizer */
+ StringStream::StringStream(const Ref<Stream<int> >& cin, const std::string& seps, const std::string& endl, bool multiLine)
+ : cin(cin), endl(endl), multiLine(multiLine)
+ {
+ createCharMap(isSepMap,seps);
+ createCharMap(isValidCharMap,stringChars);
+ }
+
+ std::string StringStream::next()
+ {
+ /* skip separators */
+ while (cin->peek() != EOF) {
+ if (endl != "" && cin->peek() == '\n') { cin->drop(); return endl; }
+ if (multiLine && cin->peek() == '\\') {
+ cin->drop();
+ if (cin->peek() == '\n') { cin->drop(); continue; }
+ cin->unget();
+ }
+ if (!isSeparator(cin->peek())) break;
+ cin->drop();
+ }
+
+ /* parse everything until the next separator */
+ std::vector<char> str; str.reserve(64);
+ while (cin->peek() != EOF && !isSeparator(cin->peek())) {
+ int c = cin->get();
+ // -- GODOT start --
+ // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
+ if (!isValidChar(c)) abort();
+ // -- GODOT end --
+ str.push_back((char)c);
+ }
+ str.push_back(0);
+ return std::string(str.data());
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/stringstream.h b/thirdparty/embree-aarch64/common/lexers/stringstream.h
new file mode 100644
index 0000000000..e6dbd4aecc
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/stringstream.h
@@ -0,0 +1,29 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+
+namespace embree
+{
+ /*! simple tokenizer that produces a string stream */
+ class StringStream : public Stream<std::string>
+ {
+ public:
+ StringStream(const Ref<Stream<int> >& cin, const std::string& seps = "\n\t\r ",
+ const std::string& endl = "", bool multiLine = false);
+ public:
+ ParseLocation location() { return cin->loc(); }
+ std::string next();
+ private:
+ __forceinline bool isSeparator(unsigned int c) const { return c<256 && isSepMap[c]; }
+ __forceinline bool isValidChar(unsigned int c) const { return c<256 && isValidCharMap[c]; }
+ private:
+ Ref<Stream<int> > cin; /*! source character stream */
+ bool isSepMap[256]; /*! map for fast classification of separators */
+ bool isValidCharMap[256]; /*! map for valid characters */
+ std::string endl; /*! the token of the end of line */
+ bool multiLine; /*! whether to parse lines wrapped with \ */
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/tokenstream.cpp b/thirdparty/embree-aarch64/common/lexers/tokenstream.cpp
new file mode 100644
index 0000000000..d05be65862
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/tokenstream.cpp
@@ -0,0 +1,181 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "tokenstream.h"
+#include "../math/math.h"
+
+namespace embree
+{
+ /* shorthands for common sets of characters */
+ const std::string TokenStream::alpha = "abcdefghijklmnopqrstuvwxyz";
+ const std::string TokenStream::ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const std::string TokenStream::numbers = "0123456789";
+ const std::string TokenStream::separators = "\n\t\r ";
+ const std::string TokenStream::stringChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _.,+-=:/*\\";
+
+ /* creates map for fast categorization of characters */
+ static void createCharMap(bool map[256], const std::string& chrs) {
+ for (size_t i=0; i<256; i++) map[i] = false;
+ for (size_t i=0; i<chrs.size(); i++) map[uint8_t(chrs[i])] = true;
+ }
+
+ /* build full tokenizer that takes list of valid characters and keywords */
+ TokenStream::TokenStream(const Ref<Stream<int> >& cin, //< stream to read from
+ const std::string& alpha, //< valid characters for identifiers
+ const std::string& seps, //< characters that act as separators
+ const std::vector<std::string>& symbols) //< symbols
+ : cin(cin), symbols(symbols)
+ {
+ createCharMap(isAlphaMap,alpha);
+ createCharMap(isSepMap,seps);
+ createCharMap(isStringCharMap,stringChars);
+ }
+
+ bool TokenStream::decDigits(std::string& str_o)
+ {
+ bool ok = false;
+ std::string str;
+ if (cin->peek() == '+' || cin->peek() == '-') str += (char)cin->get();
+ while (isDigit(cin->peek())) { ok = true; str += (char)cin->get(); }
+ if (ok) str_o += str;
+ else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::decDigits1(std::string& str_o)
+ {
+ bool ok = false;
+ std::string str;
+ while (isDigit(cin->peek())) { ok = true; str += (char)cin->get(); }
+ if (ok) str_o += str; else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::trySymbol(const std::string& symbol)
+ {
+ size_t pos = 0;
+ while (pos < symbol.size()) {
+ if (symbol[pos] != cin->peek()) { cin->unget(pos); return false; }
+ cin->drop(); pos++;
+ }
+ return true;
+ }
+
+ bool TokenStream::trySymbols(Token& token, const ParseLocation& loc)
+ {
+ for (size_t i=0; i<symbols.size(); i++) {
+ if (!trySymbol(symbols[i])) continue;
+ token = Token(symbols[i],Token::TY_SYMBOL,loc);
+ return true;
+ }
+ return false;
+ }
+
+ bool TokenStream::tryFloat(Token& token, const ParseLocation& loc)
+ {
+ bool ok = false;
+ std::string str;
+ if (trySymbol("nan")) {
+ token = Token(float(nan));
+ return true;
+ }
+ if (trySymbol("+inf")) {
+ token = Token(float(pos_inf));
+ return true;
+ }
+ if (trySymbol("-inf")) {
+ token = Token(float(neg_inf));
+ return true;
+ }
+
+ if (decDigits(str))
+ {
+ if (cin->peek() == '.') {
+ str += (char)cin->get();
+ decDigits(str);
+ if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // 1.[2]E2
+ }
+ else ok = true; // 1.[2]
+ }
+ else if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // 1E2
+ }
+ }
+ else
+ {
+ if (cin->peek() == '.') {
+ str += (char)cin->get();
+ if (decDigits(str)) {
+ if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // .3E2
+ }
+ else ok = true; // .3
+ }
+ }
+ }
+ if (ok) {
+ token = Token((float)atof(str.c_str()),loc);
+ }
+ else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::tryInt(Token& token, const ParseLocation& loc) {
+ std::string str;
+ if (decDigits(str)) {
+ token = Token(atoi(str.c_str()),loc);
+ return true;
+ }
+ return false;
+ }
+
+ bool TokenStream::tryString(Token& token, const ParseLocation& loc)
+ {
+ std::string str;
+ if (cin->peek() != '\"') return false;
+ cin->drop();
+ while (cin->peek() != '\"') {
+ const int c = cin->get();
+ if (!isStringChar(c)) THROW_RUNTIME_ERROR("invalid string character "+std::string(1,c)+" at "+loc.str());
+ str += (char)c;
+ }
+ cin->drop();
+ token = Token(str,Token::TY_STRING,loc);
+ return true;
+ }
+
+ bool TokenStream::tryIdentifier(Token& token, const ParseLocation& loc)
+ {
+ std::string str;
+ if (!isAlpha(cin->peek())) return false;
+ str += (char)cin->get();
+ while (isAlphaNum(cin->peek())) str += (char)cin->get();
+ token = Token(str,Token::TY_IDENTIFIER,loc);
+ return true;
+ }
+
+ void TokenStream::skipSeparators()
+ {
+ /* skip separators */
+ while (cin->peek() != EOF && isSeparator(cin->peek()))
+ cin->drop();
+ }
+
+ Token TokenStream::next()
+ {
+ Token token;
+ skipSeparators();
+ ParseLocation loc = cin->loc();
+ if (trySymbols (token,loc)) return token; /**< try to parse a symbol */
+ if (tryFloat (token,loc)) return token; /**< try to parse float */
+ if (tryInt (token,loc)) return token; /**< try to parse integer */
+ if (tryString (token,loc)) return token; /**< try to parse string */
+ if (tryIdentifier(token,loc)) return token; /**< try to parse identifier */
+ if (cin->peek() == EOF ) return Token(loc); /**< return EOF token */
+ return Token((char)cin->get(),loc); /**< return invalid character token */
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/lexers/tokenstream.h b/thirdparty/embree-aarch64/common/lexers/tokenstream.h
new file mode 100644
index 0000000000..72a7b4f2f3
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/lexers/tokenstream.h
@@ -0,0 +1,164 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+#include <string>
+#include <vector>
+
+namespace embree
+{
+ /*! token class */
+ class Token
+ {
+ public:
+
+ enum Type { TY_EOF, TY_CHAR, TY_INT, TY_FLOAT, TY_IDENTIFIER, TY_STRING, TY_SYMBOL };
+
+ Token ( const ParseLocation& loc = ParseLocation()) : ty(TY_EOF ), loc(loc) {}
+ Token (char c, const ParseLocation& loc = ParseLocation()) : ty(TY_CHAR ), c(c), loc(loc) {}
+ Token (int i, const ParseLocation& loc = ParseLocation()) : ty(TY_INT ), i(i), loc(loc) {}
+ Token (float f,const ParseLocation& loc = ParseLocation()) : ty(TY_FLOAT), f(f), loc(loc) {}
+ Token (std::string str, Type ty, const ParseLocation& loc = ParseLocation()) : ty(ty), str(str), loc(loc) {}
+
+ static Token Eof() { return Token(); }
+ static Token Sym(std::string str) { return Token(str,TY_SYMBOL); }
+ static Token Str(std::string str) { return Token(str,TY_STRING); }
+ static Token Id (std::string str) { return Token(str,TY_IDENTIFIER); }
+
+ char Char() const {
+ if (ty == TY_CHAR) return c;
+ THROW_RUNTIME_ERROR(loc.str()+": character expected");
+ }
+
+ int Int() const {
+ if (ty == TY_INT) return i;
+ THROW_RUNTIME_ERROR(loc.str()+": integer expected");
+ }
+
+ float Float(bool cast = true) const {
+ if (ty == TY_FLOAT) return f;
+ if (ty == TY_INT && cast) return (float)i;
+ THROW_RUNTIME_ERROR(loc.str()+": float expected");
+ }
+
+ std::string Identifier() const {
+ if (ty == TY_IDENTIFIER) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": identifier expected");
+ }
+
+ std::string String() const {
+ if (ty == TY_STRING) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": string expected");
+ }
+
+ std::string Symbol() const {
+ if (ty == TY_SYMBOL) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": symbol expected");
+ }
+
+ const ParseLocation& Location() const { return loc; }
+
+ friend bool operator==(const Token& a, const Token& b)
+ {
+ if (a.ty != b.ty) return false;
+ if (a.ty == TY_CHAR) return a.c == b.c;
+ if (a.ty == TY_INT) return a.i == b.i;
+ if (a.ty == TY_FLOAT) return a.f == b.f;
+ if (a.ty == TY_IDENTIFIER) return a.str == b.str;
+ if (a.ty == TY_STRING) return a.str == b.str;
+ if (a.ty == TY_SYMBOL) return a.str == b.str;
+ return true;
+ }
+
+ friend bool operator!=(const Token& a, const Token& b) {
+ return !(a == b);
+ }
+
+ friend bool operator <( const Token& a, const Token& b ) {
+ if (a.ty != b.ty) return (int)a.ty < (int)b.ty;
+ if (a.ty == TY_CHAR) return a.c < b.c;
+ if (a.ty == TY_INT) return a.i < b.i;
+ if (a.ty == TY_FLOAT) return a.f < b.f;
+ if (a.ty == TY_IDENTIFIER) return a.str < b.str;
+ if (a.ty == TY_STRING) return a.str < b.str;
+ if (a.ty == TY_SYMBOL) return a.str < b.str;
+ return false;
+ }
+
+ friend std::ostream& operator<<(std::ostream& cout, const Token& t)
+ {
+ if (t.ty == TY_EOF) return cout << "eof";
+ if (t.ty == TY_CHAR) return cout << "Char(" << t.c << ")";
+ if (t.ty == TY_INT) return cout << "Int(" << t.i << ")";
+ if (t.ty == TY_FLOAT) return cout << "Float(" << t.f << ")";
+ if (t.ty == TY_IDENTIFIER) return cout << "Id(" << t.str << ")";
+ if (t.ty == TY_STRING) return cout << "String(" << t.str << ")";
+ if (t.ty == TY_SYMBOL) return cout << "Symbol(" << t.str << ")";
+ return cout << "unknown";
+ }
+
+ private:
+ Type ty; //< the type of the token
+ union {
+ char c; //< data for char tokens
+ int i; //< data for int tokens
+ float f; //< data for float tokens
+ };
+ std::string str; //< data for string and identifier tokens
+ ParseLocation loc; //< the location the token is from
+ };
+
+ /*! build full tokenizer that takes list of valid characters and keywords */
+ class TokenStream : public Stream<Token>
+ {
+ public:
+
+ /*! shorthands for common sets of characters */
+ static const std::string alpha;
+ static const std::string ALPHA;
+ static const std::string numbers;
+ static const std::string separators;
+ static const std::string stringChars;
+
+ public:
+ TokenStream(const Ref<Stream<int> >& cin,
+ const std::string& alpha, //< valid characters for identifiers
+ const std::string& seps, //< characters that act as separators
+ const std::vector<std::string>& symbols = std::vector<std::string>()); //< symbols
+ public:
+ ParseLocation location() { return cin->loc(); }
+ Token next();
+ bool trySymbol(const std::string& symbol);
+
+ private:
+ void skipSeparators();
+ bool decDigits(std::string& str);
+ bool decDigits1(std::string& str);
+ bool trySymbols(Token& token, const ParseLocation& loc);
+ bool tryFloat(Token& token, const ParseLocation& loc);
+ bool tryInt(Token& token, const ParseLocation& loc);
+ bool tryString(Token& token, const ParseLocation& loc);
+ bool tryIdentifier(Token& token, const ParseLocation& loc);
+
+ Ref<Stream<int> > cin;
+ bool isSepMap[256];
+ bool isAlphaMap[256];
+ bool isStringCharMap[256];
+ std::vector<std::string> symbols;
+
+ /*! checks if a character is a separator */
+ __forceinline bool isSeparator(unsigned int c) const { return c<256 && isSepMap[c]; }
+
+ /*! checks if a character is a number */
+ __forceinline bool isDigit(unsigned int c) const { return c >= '0' && c <= '9'; }
+
+ /*! checks if a character is valid inside a string */
+ __forceinline bool isStringChar(unsigned int c) const { return c<256 && isStringCharMap[c]; }
+
+ /*! checks if a character is legal for an identifier */
+ __forceinline bool isAlpha(unsigned int c) const { return c<256 && isAlphaMap[c]; }
+ __forceinline bool isAlphaNum(unsigned int c) const { return isAlpha(c) || isDigit(c); }
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/math/AVX2NEON.h b/thirdparty/embree-aarch64/common/math/AVX2NEON.h
new file mode 100644
index 0000000000..e8698ac56d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/AVX2NEON.h
@@ -0,0 +1,986 @@
+#pragma once
+
+#include "SSE2NEON.h"
+
+
+#define AVX2NEON_ABI static inline __attribute__((always_inline))
+
+
+struct __m256d;
+
+struct __m256 {
+ __m128 lo,hi;
+ __m256() {}
+};
+
+
+
+
+struct __m256i {
+ __m128i lo,hi;
+ explicit __m256i(const __m256 a) : lo(__m128i(a.lo)),hi(__m128i(a.hi)) {}
+ operator __m256() const {__m256 res; res.lo = __m128(lo);res.hi = __m128(hi); return res;}
+ __m256i() {}
+};
+
+
+
+
+struct __m256d {
+ float64x2_t lo,hi;
+ __m256d() {}
+ __m256d(const __m256& a) : lo(float64x2_t(a.lo)),hi(float64x2_t(a.hi)) {}
+ __m256d(const __m256i& a) : lo(float64x2_t(a.lo)),hi(float64x2_t(a.hi)) {}
+};
+
+#define UNARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a) {type res;res.lo=basic_func(a.lo);res.hi=basic_func(a.hi);return res;}
+
+
+#define BINARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a,const type& b) {type res;res.lo=basic_func(a.lo,b.lo);res.hi=basic_func(a.hi,b.hi);return res;}
+#define BINARY_AVX_OP_CAST(type,func,basic_func,bdst,bsrc) AVX2NEON_ABI type func(const type& a,const type& b) {type res;res.lo=bdst(basic_func(bsrc(a.lo),bsrc(b.lo)));res.hi=bdst(basic_func(bsrc(a.hi),bsrc(b.hi)));return res;}
+
+#define TERNARY_AVX_OP(type,func,basic_func) AVX2NEON_ABI type func(const type& a,const type& b,const type& c) {type res;res.lo=basic_func(a.lo,b.lo,c.lo);res.hi=basic_func(a.hi,b.hi,c.hi);return res;}
+
+
+#define CAST_SIMD_TYPE(to,name,from,basic_dst) AVX2NEON_ABI to name(const from& a) { to res; res.lo = basic_dst(a.lo); res.hi=basic_dst(a.hi); return res;}
+
+
+
+#define _mm_stream_load_si128 _mm_load_si128
+#define _mm256_stream_load_si256 _mm256_load_si256
+
+
+AVX2NEON_ABI
+__m128 _mm_blend_ps (__m128 a, __m128 b, const int imm8)
+{
+ __m128 res;
+ for (int i=0;i<4;i++)
+ {
+ if (imm8 & (1<<i))
+ {
+ res[i] = b[i];
+ }
+ else{
+ res[i] = a[i];
+ }
+ }
+
+ return res;
+}
+
+AVX2NEON_ABI
+__m128i _mm_blend_epi32 (__m128i a, __m128i b, const int imm8)
+{
+ __m128i res;
+ for (int i=0;i<4;i++)
+ {
+ if (imm8 & (1<<i))
+ {
+ res[i] = b[i];
+ }
+ else{
+ res[i] = a[i];
+ }
+ }
+ return res;
+}
+
+AVX2NEON_ABI
+__m128 _mm_cmpngt_ps (__m128 a, __m128 b)
+{
+ return __m128(vmvnq_s32(__m128i(_mm_cmpgt_ps(a,b))));
+}
+
+
+AVX2NEON_ABI
+__m128i _mm_loadl_epi64 (__m128i const* mem_addr)
+{
+ int64x2_t y;
+ y[0] = *(int64_t *)mem_addr;
+ y[1] = 0;
+ return __m128i(y);
+}
+
+AVX2NEON_ABI
+int _mm_movemask_popcnt(__m128 a)
+{
+ return __builtin_popcount(_mm_movemask_ps(a));
+}
+
+AVX2NEON_ABI
+__m128 _mm_maskload_ps (float const * mem_addr, __m128i mask)
+{
+ __m128 res;
+ for (int i=0;i<4;i++) {
+ if (mask[i] & 0x80000000) res[i] = mem_addr[i]; else res[i] = 0;
+ }
+ return res;
+}
+
+AVX2NEON_ABI
+void _mm_maskstore_ps (float * mem_addr, __m128i mask, __m128 a)
+{
+ for (int i=0;i<4;i++) {
+ if (mask[i] & 0x80000000) mem_addr[i] = a[i];
+ }
+}
+
+AVX2NEON_ABI
+void _mm_maskstore_epi32 (int * mem_addr, __m128i mask, __m128i a)
+{
+ for (int i=0;i<4;i++) {
+ if (mask[i] & 0x80000000) mem_addr[i] = a[i];
+ }
+}
+
+AVX2NEON_ABI
+__m128 _mm_fnmsub_ps (__m128 a, __m128 b, __m128 c)
+{
+ return vnegq_f32(vfmaq_f32(c,a,b));
+}
+
+#define _mm_fnmsub_ss _mm_fnmsub_ps
+
+AVX2NEON_ABI
+__m128 _mm_fnmadd_ps (__m128 a, __m128 b, __m128 c)
+{
+ return vfmsq_f32(c,a,b);
+}
+
+#define _mm_fnmadd_ss _mm_fnmadd_ps
+
+
+AVX2NEON_ABI
+__m128 _mm_broadcast_ss (float const * mem_addr)
+{
+ return vdupq_n_f32(*mem_addr);
+}
+
+
+AVX2NEON_ABI
+__m128 _mm_fmsub_ps (__m128 a, __m128 b, __m128 c)
+{
+ return vfmaq_f32(vnegq_f32(c),a,b);
+}
+
+#define _mm_fmsub_ss _mm_fmsub_ps
+#define _mm_fmadd_ps _mm_madd_ps
+#define _mm_fmadd_ss _mm_madd_ps
+
+
+
+template<int code>
+AVX2NEON_ABI float32x4_t dpps_neon(const float32x4_t& a,const float32x4_t& b)
+{
+ float v;
+ v = 0;
+ v += (code & 0x10) ? a[0]*b[0] : 0;
+ v += (code & 0x20) ? a[1]*b[1] : 0;
+ v += (code & 0x40) ? a[2]*b[2] : 0;
+ v += (code & 0x80) ? a[3]*b[3] : 0;
+ float32x4_t res;
+ res[0] = (code & 0x1) ? v : 0;
+ res[1] = (code & 0x2) ? v : 0;
+ res[2] = (code & 0x4) ? v : 0;
+ res[3] = (code & 0x8) ? v : 0;
+ return res;
+}
+
+template<>
+inline float32x4_t dpps_neon<0x7f>(const float32x4_t& a,const float32x4_t& b)
+{
+ float v;
+ float32x4_t m = _mm_mul_ps(a,b);
+ m[3] = 0;
+ v = vaddvq_f32(m);
+ return _mm_set1_ps(v);
+}
+
+template<>
+inline float32x4_t dpps_neon<0xff>(const float32x4_t& a,const float32x4_t& b)
+{
+ float v;
+ float32x4_t m = _mm_mul_ps(a,b);
+ v = vaddvq_f32(m);
+ return _mm_set1_ps(v);
+}
+
+#define _mm_dp_ps(a,b,c) dpps_neon<c>((a),(b))
+
+
+
+AVX2NEON_ABI
+__m128 _mm_cmpnge_ps (__m128 a, __m128 b)
+{
+ return __m128(vmvnq_s32(__m128i(_mm_cmpge_ps(a,b))));
+}
+
+
+AVX2NEON_ABI
+__m128 _mm_permutevar_ps (__m128 a, __m128i b)
+{
+ __m128 x;
+ for (int i=0;i<4;i++)
+ {
+ x[i] = a[b[i&3]];
+ }
+ return x;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_setzero_si256()
+{
+ __m256i res;
+ res.lo = res.hi = vdupq_n_s32(0);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_setzero_ps()
+{
+ __m256 res;
+ res.lo = res.hi = vdupq_n_f32(0.0f);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_undefined_si256()
+{
+ return _mm256_setzero_si256();
+}
+
+AVX2NEON_ABI
+__m256 _mm256_undefined_ps()
+{
+ return _mm256_setzero_ps();
+}
+
+CAST_SIMD_TYPE(__m256d,_mm256_castps_pd,__m256,float64x2_t)
+CAST_SIMD_TYPE(__m256i,_mm256_castps_si256,__m256,__m128i)
+CAST_SIMD_TYPE(__m256, _mm256_castsi256_ps, __m256i,__m128)
+CAST_SIMD_TYPE(__m256, _mm256_castpd_ps ,__m256d,__m128)
+CAST_SIMD_TYPE(__m256d, _mm256_castsi256_pd, __m256i,float64x2_t)
+CAST_SIMD_TYPE(__m256i, _mm256_castpd_si256, __m256d,__m128i)
+
+
+
+
+AVX2NEON_ABI
+__m128 _mm256_castps256_ps128 (__m256 a)
+{
+ return a.lo;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_castsi128_si256 (__m128i a)
+{
+ __m256i res;
+ res.lo = a ;
+ res.hi = vdupq_n_s32(0);
+ return res;
+}
+
+AVX2NEON_ABI
+__m128i _mm256_castsi256_si128 (__m256i a)
+{
+ return a.lo;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_castps128_ps256 (__m128 a)
+{
+ __m256 res;
+ res.lo = a;
+ res.hi = vdupq_n_f32(0);
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256 _mm256_broadcast_ss (float const * mem_addr)
+{
+ __m256 res;
+ res.lo = res.hi = vdupq_n_f32(*mem_addr);
+ return res;
+}
+
+
+
+AVX2NEON_ABI
+__m256i _mm256_set_epi32 (int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0)
+{
+ __m128i lo = {e0,e1,e2,e3}, hi = {e4,e5,e6,e7};
+ __m256i res;
+ res.lo = lo; res.hi = hi;
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256i _mm256_set1_epi32 (int a)
+{
+ __m256i res;
+ res.lo = res.hi = vdupq_n_s32(a);
+ return res;
+}
+
+
+
+
+AVX2NEON_ABI
+int _mm256_movemask_ps(const __m256& v)
+{
+ return (_mm_movemask_ps(v.hi) << 4) | _mm_movemask_ps(v.lo);
+}
+
+template<int imm8>
+AVX2NEON_ABI
+__m256 __mm256_permute_ps (const __m256& a)
+{
+ __m256 res;
+ res.lo = _mm_shuffle_ps(a.lo,a.lo,imm8);
+ res.hi = _mm_shuffle_ps(a.hi,a.hi,imm8);
+ return res;
+
+}
+
+#define _mm256_permute_ps(a,c) __mm256_permute_ps<c>(a)
+
+
+template<int imm8>
+AVX2NEON_ABI
+__m256 __mm256_shuffle_ps (const __m256 a,const __m256& b)
+{
+ __m256 res;
+ res.lo = _mm_shuffle_ps(a.lo,b.lo,imm8);
+ res.hi = _mm_shuffle_ps(a.hi,b.hi,imm8);
+ return res;
+
+}
+
+#define _mm256_shuffle_ps(a,b,c) __mm256_shuffle_ps<c>(a,b)
+
+AVX2NEON_ABI
+__m256i _mm256_set1_epi64x (long long a)
+{
+ __m256i res;
+ int64x2_t t = vdupq_n_s64(a);
+ res.lo = res.hi = __m128i(t);
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256 _mm256_permute2f128_ps (__m256 a, __m256 b, int imm8)
+{
+ __m256 res;
+ __m128 tmp;
+ switch (imm8 & 0x7)
+ {
+ case 0: tmp = a.lo; break;
+ case 1: tmp = a.hi; break;
+ case 2: tmp = b.lo; break;
+ case 3: tmp = b.hi; break;
+ }
+ if (imm8 & 0x8)
+ tmp = _mm_setzero_ps();
+
+
+
+ res.lo = tmp;
+ imm8 >>= 4;
+
+ switch (imm8 & 0x7)
+ {
+ case 0: tmp = a.lo; break;
+ case 1: tmp = a.hi; break;
+ case 2: tmp = b.lo; break;
+ case 3: tmp = b.hi; break;
+ }
+ if (imm8 & 0x8)
+ tmp = _mm_setzero_ps();
+
+ res.hi = tmp;
+
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_moveldup_ps (__m256 a)
+{
+ __m256 res;
+ res.lo[0] = res.lo[1] = a.lo[0];
+ res.lo[2] = res.lo[3] = a.lo[2];
+ res.hi[0] = res.hi[1] = a.hi[0];
+ res.hi[2] = res.hi[3] = a.hi[2];
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256 _mm256_movehdup_ps (__m256 a)
+{
+ __m256 res;
+ res.lo[0] = res.lo[1] = a.lo[1];
+ res.lo[2] = res.lo[3] = a.lo[3];
+ res.hi[0] = res.hi[1] = a.hi[1];
+ res.hi[2] = res.hi[3] = a.hi[3];
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_insertf128_ps (__m256 a, __m128 b, int imm8)
+{
+ __m256 res = a;
+ if (imm8 & 1) res.hi = b;
+ else res.lo = b;
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m128 _mm256_extractf128_ps (__m256 a, const int imm8)
+{
+ if (imm8 & 1) return a.hi;
+ return a.lo;
+}
+
+
+AVX2NEON_ABI
+__m256d _mm256_movedup_pd (__m256d a)
+{
+ __m256d res;
+ res.hi = a.hi;
+ res.lo[0] = res.lo[1] = a.lo[0];
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_abs_epi32(__m256i a)
+{
+ __m256i res;
+ res.lo = vabsq_s32(a.lo);
+ res.hi = vabsq_s32(a.hi);
+ return res;
+}
+
+UNARY_AVX_OP(__m256,_mm256_sqrt_ps,_mm_sqrt_ps)
+UNARY_AVX_OP(__m256,_mm256_rsqrt_ps,_mm_rsqrt_ps)
+UNARY_AVX_OP(__m256,_mm256_rcp_ps,_mm_rcp_ps)
+UNARY_AVX_OP(__m256,_mm256_floor_ps,vrndmq_f32)
+UNARY_AVX_OP(__m256,_mm256_ceil_ps,vrndpq_f32)
+
+
+BINARY_AVX_OP(__m256i,_mm256_add_epi32,_mm_add_epi32)
+BINARY_AVX_OP(__m256i,_mm256_sub_epi32,_mm_sub_epi32)
+BINARY_AVX_OP(__m256i,_mm256_mullo_epi32,_mm_mullo_epi32)
+
+BINARY_AVX_OP(__m256i,_mm256_min_epi32,_mm_min_epi32)
+BINARY_AVX_OP(__m256i,_mm256_max_epi32,_mm_max_epi32)
+BINARY_AVX_OP_CAST(__m256i,_mm256_min_epu32,vminq_u32,__m128i,uint32x4_t)
+BINARY_AVX_OP_CAST(__m256i,_mm256_max_epu32,vmaxq_u32,__m128i,uint32x4_t)
+
+BINARY_AVX_OP(__m256,_mm256_min_ps,_mm_min_ps)
+BINARY_AVX_OP(__m256,_mm256_max_ps,_mm_max_ps)
+
+BINARY_AVX_OP(__m256,_mm256_add_ps,_mm_add_ps)
+BINARY_AVX_OP(__m256,_mm256_mul_ps,_mm_mul_ps)
+BINARY_AVX_OP(__m256,_mm256_sub_ps,_mm_sub_ps)
+BINARY_AVX_OP(__m256,_mm256_div_ps,_mm_div_ps)
+
+BINARY_AVX_OP(__m256,_mm256_and_ps,_mm_and_ps)
+BINARY_AVX_OP(__m256,_mm256_andnot_ps,_mm_andnot_ps)
+BINARY_AVX_OP(__m256,_mm256_or_ps,_mm_or_ps)
+BINARY_AVX_OP(__m256,_mm256_xor_ps,_mm_xor_ps)
+
+BINARY_AVX_OP_CAST(__m256d,_mm256_and_pd,vandq_s64,float64x2_t,int64x2_t)
+BINARY_AVX_OP_CAST(__m256d,_mm256_or_pd,vorrq_s64,float64x2_t,int64x2_t)
+BINARY_AVX_OP_CAST(__m256d,_mm256_xor_pd,veorq_s64,float64x2_t,int64x2_t)
+
+
+
+BINARY_AVX_OP(__m256i,_mm256_and_si256,_mm_and_si128)
+BINARY_AVX_OP(__m256i,_mm256_or_si256,_mm_or_si128)
+BINARY_AVX_OP(__m256i,_mm256_xor_si256,_mm_xor_si128)
+
+
+BINARY_AVX_OP(__m256,_mm256_unpackhi_ps,_mm_unpackhi_ps)
+BINARY_AVX_OP(__m256,_mm256_unpacklo_ps,_mm_unpacklo_ps)
+TERNARY_AVX_OP(__m256,_mm256_blendv_ps,_mm_blendv_ps)
+
+
+TERNARY_AVX_OP(__m256,_mm256_fmadd_ps,_mm_fmadd_ps)
+TERNARY_AVX_OP(__m256,_mm256_fnmadd_ps,_mm_fnmadd_ps)
+TERNARY_AVX_OP(__m256,_mm256_fmsub_ps,_mm_fmsub_ps)
+TERNARY_AVX_OP(__m256,_mm256_fnmsub_ps,_mm_fnmsub_ps)
+
+
+BINARY_AVX_OP(__m256i,_mm256_unpackhi_epi32,_mm_unpackhi_epi32)
+BINARY_AVX_OP(__m256i,_mm256_unpacklo_epi32,_mm_unpacklo_epi32)
+
+
+BINARY_AVX_OP(__m256i,_mm256_cmpeq_epi32,_mm_cmpeq_epi32)
+BINARY_AVX_OP(__m256i,_mm256_cmpgt_epi32,_mm_cmpgt_epi32)
+BINARY_AVX_OP(__m256,_mm256_cmpeq_ps,_mm_cmpeq_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpneq_ps,_mm_cmpneq_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpnlt_ps,_mm_cmpnlt_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpngt_ps,_mm_cmpngt_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpge_ps,_mm_cmpge_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpnge_ps,_mm_cmpnge_ps)
+BINARY_AVX_OP(__m256,_mm256_cmplt_ps,_mm_cmplt_ps)
+BINARY_AVX_OP(__m256,_mm256_cmple_ps,_mm_cmple_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpgt_ps,_mm_cmpgt_ps)
+BINARY_AVX_OP(__m256,_mm256_cmpnle_ps,_mm_cmpnle_ps)
+
+
+AVX2NEON_ABI
+__m256i _mm256_cvtps_epi32 (__m256 a)
+{
+ __m256i res;
+ res.lo = _mm_cvtps_epi32(a.lo);
+ res.hi = _mm_cvtps_epi32(a.hi);
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256i _mm256_cvttps_epi32 (__m256 a)
+{
+ __m256i res;
+ res.lo = _mm_cvttps_epi32(a.lo);
+ res.hi = _mm_cvttps_epi32(a.hi);
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256 _mm256_loadu_ps (float const * mem_addr)
+{
+ __m256 res;
+ res.lo = *(__m128 *)(mem_addr + 0);
+ res.hi = *(__m128 *)(mem_addr + 4);
+ return res;
+}
+#define _mm256_load_ps _mm256_loadu_ps
+
+
+AVX2NEON_ABI
+int _mm256_testz_ps (const __m256& a, const __m256& b)
+{
+ __m256 t = a;
+ if (&a != &b)
+ t = _mm256_and_ps(a,b);
+
+ __m128i l = vshrq_n_s32(__m128i(t.lo),31);
+ __m128i h = vshrq_n_s32(__m128i(t.hi),31);
+ return vaddvq_s32(vaddq_s32(l,h)) == 0;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_set_epi64x (int64_t e3, int64_t e2, int64_t e1, int64_t e0)
+{
+ __m256i res;
+ int64x2_t t0 = {e0,e1};
+ int64x2_t t1 = {e2,e3};
+ res.lo = __m128i(t0);
+ res.hi = __m128i(t1);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256d _mm256_setzero_pd ()
+{
+ __m256d res;
+ res.lo = res.hi = vdupq_n_f64(0);
+ return res;
+}
+
+AVX2NEON_ABI
+int _mm256_movemask_pd (__m256d a)
+{
+ int res = 0;
+ uint64x2_t x;
+ x = uint64x2_t(a.lo);
+ res |= (x[0] >> 63) ? 1 : 0;
+ res |= (x[0] >> 63) ? 2 : 0;
+ x = uint64x2_t(a.hi);
+ res |= (x[0] >> 63) ? 4 : 0;
+ res |= (x[0] >> 63) ? 8 : 0;
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_cmpeq_epi64 (__m256i a, __m256i b)
+{
+ __m256i res;
+ res.lo = __m128i(vceqq_s64(int64x2_t(a.lo),int64x2_t(b.lo)));
+ res.hi = __m128i(vceqq_s64(int64x2_t(a.hi),int64x2_t(b.hi)));
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_cmpeq_pd (__m256d a, __m256d b)
+{
+ __m256i res;
+ res.lo = __m128i(vceqq_f64(a.lo,b.lo));
+ res.hi = __m128i(vceqq_f64(a.hi,b.hi));
+ return res;
+}
+
+
+AVX2NEON_ABI
+int _mm256_testz_pd (const __m256d& a, const __m256d& b)
+{
+ __m256d t = a;
+
+ if (&a != &b)
+ t = _mm256_and_pd(a,b);
+
+ return _mm256_movemask_pd(t) == 0;
+}
+
+AVX2NEON_ABI
+__m256d _mm256_blendv_pd (__m256d a, __m256d b, __m256d mask)
+{
+ __m256d res;
+ uint64x2_t t = uint64x2_t(mask.lo);
+ res.lo[0] = (t[0] >> 63) ? b.lo[0] : a.lo[0];
+ res.lo[1] = (t[1] >> 63) ? b.lo[1] : a.lo[1];
+ t = uint64x2_t(mask.hi);
+ res.hi[0] = (t[0] >> 63) ? b.hi[0] : a.hi[0];
+ res.hi[1] = (t[1] >> 63) ? b.hi[1] : a.hi[1];
+ return res;
+}
+
+template<int imm8>
+__m256 __mm256_dp_ps (__m256 a, __m256 b)
+{
+ __m256 res;
+ res.lo = _mm_dp_ps(a.lo,b.lo,imm8);
+ res.hi = _mm_dp_ps(a.hi,b.hi,imm8);
+ return res;
+}
+
+#define _mm256_dp_ps(a,b,c) __mm256_dp_ps<c>(a,b)
+
+AVX2NEON_ABI
+double _mm256_permute4x64_pd_select(__m256d a, const int imm8)
+{
+ switch (imm8 & 3) {
+ case 0:
+ return a.lo[0];
+ case 1:
+ return a.lo[1];
+ case 2:
+ return a.hi[0];
+ case 3:
+ return a.hi[1];
+ }
+ __builtin_unreachable();
+ return 0;
+}
+
+AVX2NEON_ABI
+__m256d _mm256_permute4x64_pd (__m256d a, const int imm8)
+{
+ __m256d res;
+ res.lo[0] = _mm256_permute4x64_pd_select(a,imm8 >> 0);
+ res.lo[1] = _mm256_permute4x64_pd_select(a,imm8 >> 2);
+ res.hi[0] = _mm256_permute4x64_pd_select(a,imm8 >> 4);
+ res.hi[1] = _mm256_permute4x64_pd_select(a,imm8 >> 6);
+
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_insertf128_si256 (__m256i a, __m128i b, int imm8)
+{
+ return __m256i(_mm256_insertf128_ps((__m256)a,(__m128)b,imm8));
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_loadu_si256 (__m256i const * mem_addr)
+{
+ __m256i res;
+ res.lo = *(__m128i *)((int32_t *)mem_addr + 0);
+ res.hi = *(__m128i *)((int32_t *)mem_addr + 4);
+ return res;
+}
+
+#define _mm256_load_si256 _mm256_loadu_si256
+
+AVX2NEON_ABI
+void _mm256_storeu_ps (float * mem_addr, __m256 a)
+{
+ *(__m128 *)(mem_addr + 0) = a.lo;
+ *(__m128 *)(mem_addr + 4) = a.hi;
+
+}
+
+#define _mm256_store_ps _mm256_storeu_ps
+#define _mm256_stream_ps _mm256_storeu_ps
+
+
+AVX2NEON_ABI
+void _mm256_storeu_si256 (__m256i * mem_addr, __m256i a)
+{
+ *(__m128i *)((int *)mem_addr + 0) = a.lo;
+ *(__m128i *)((int *)mem_addr + 4) = a.hi;
+
+}
+
+#define _mm256_store_si256 _mm256_storeu_si256
+
+
+
+AVX2NEON_ABI
+__m256 _mm256_maskload_ps (float const * mem_addr, __m256i mask)
+{
+ __m256 res;
+ res.lo = _mm_maskload_ps(mem_addr,mask.lo);
+ res.hi = _mm_maskload_ps(mem_addr + 4,mask.hi);
+ return res;
+
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_cvtepu8_epi32 (__m128i a)
+{
+ __m256i res;
+ uint8x16_t x = uint8x16_t(a);
+ for (int i=0;i<4;i++)
+ {
+ res.lo[i] = x[i];
+ res.hi[i] = x[i+4];
+ }
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_cvtepi8_epi32 (__m128i a)
+{
+ __m256i res;
+ int8x16_t x = int8x16_t(a);
+ for (int i=0;i<4;i++)
+ {
+ res.lo[i] = x[i];
+ res.hi[i] = x[i+4];
+ }
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_cvtepu16_epi32 (__m128i a)
+{
+ __m256i res;
+ uint16x8_t x = uint16x8_t(a);
+ for (int i=0;i<4;i++)
+ {
+ res.lo[i] = x[i];
+ res.hi[i] = x[i+4];
+ }
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_cvtepi16_epi32 (__m128i a)
+{
+ __m256i res;
+ int16x8_t x = int16x8_t(a);
+ for (int i=0;i<4;i++)
+ {
+ res.lo[i] = x[i];
+ res.hi[i] = x[i+4];
+ }
+ return res;
+}
+
+
+
+AVX2NEON_ABI
+void _mm256_maskstore_epi32 (int* mem_addr, __m256i mask, __m256i a)
+{
+ _mm_maskstore_epi32(mem_addr,mask.lo,a.lo);
+ _mm_maskstore_epi32(mem_addr + 4,mask.hi,a.hi);
+}
+
+AVX2NEON_ABI
+__m256i _mm256_slli_epi32 (__m256i a, int imm8)
+{
+ __m256i res;
+ res.lo = _mm_slli_epi32(a.lo,imm8);
+ res.hi = _mm_slli_epi32(a.hi,imm8);
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_srli_epi32 (__m256i a, int imm8)
+{
+ __m256i res;
+ res.lo = _mm_srli_epi32(a.lo,imm8);
+ res.hi = _mm_srli_epi32(a.hi,imm8);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256i _mm256_srai_epi32 (__m256i a, int imm8)
+{
+ __m256i res;
+ res.lo = _mm_srai_epi32(a.lo,imm8);
+ res.hi = _mm_srai_epi32(a.hi,imm8);
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_sllv_epi32 (__m256i a, __m256i count)
+{
+ __m256i res;
+ res.lo = vshlq_s32(a.lo,count.lo);
+ res.hi = vshlq_s32(a.hi,count.hi);
+ return res;
+
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_srav_epi32 (__m256i a, __m256i count)
+{
+ __m256i res;
+ res.lo = vshlq_s32(a.lo,vnegq_s32(count.lo));
+ res.hi = vshlq_s32(a.hi,vnegq_s32(count.hi));
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256i _mm256_srlv_epi32 (__m256i a, __m256i count)
+{
+ __m256i res;
+ res.lo = __m128i(vshlq_u32(uint32x4_t(a.lo),vnegq_s32(count.lo)));
+ res.hi = __m128i(vshlq_u32(uint32x4_t(a.hi),vnegq_s32(count.hi)));
+ return res;
+
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_permute2f128_si256 (__m256i a, __m256i b, int imm8)
+{
+ return __m256i(_mm256_permute2f128_ps(__m256(a),__m256(b),imm8));
+}
+
+
+AVX2NEON_ABI
+__m128i _mm256_extractf128_si256 (__m256i a, const int imm8)
+{
+ if (imm8 & 1) return a.hi;
+ return a.lo;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_set1_ps(float x)
+{
+ __m256 res;
+ res.lo = res.hi = vdupq_n_f32(x);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_set_ps (float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0)
+{
+ __m256 res;
+ res.lo = _mm_set_ps(e3,e2,e1,e0);
+ res.hi = _mm_set_ps(e7,e6,e5,e4);
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_broadcast_ps (__m128 const * mem_addr)
+{
+ __m256 res;
+ res.lo = res.hi = *mem_addr;
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_cvtepi32_ps (__m256i a)
+{
+ __m256 res;
+ res.lo = _mm_cvtepi32_ps(a.lo);
+ res.hi = _mm_cvtepi32_ps(a.hi);
+ return res;
+}
+AVX2NEON_ABI
+void _mm256_maskstore_ps (float * mem_addr, __m256i mask, __m256 a)
+{
+ for (int i=0;i<4;i++) {
+ if (mask.lo[i] & 0x80000000) mem_addr[i] = a.lo[i];
+ if (mask.hi[i] & 0x80000000) mem_addr[i+4] = a.hi[i];
+ }
+}
+
+AVX2NEON_ABI
+__m256d _mm256_andnot_pd (__m256d a, __m256d b)
+{
+ __m256d res;
+ res.lo = float64x2_t(_mm_andnot_ps(__m128(a.lo),__m128(b.lo)));
+ res.hi = float64x2_t(_mm_andnot_ps(__m128(a.hi),__m128(b.hi)));
+ return res;
+}
+
+AVX2NEON_ABI
+__m256 _mm256_blend_ps (__m256 a, __m256 b, const int imm8)
+{
+ __m256 res;
+ res.lo = _mm_blend_ps(a.lo,b.lo,imm8 & 0xf);
+ res.hi = _mm_blend_ps(a.hi,b.hi,imm8 >> 4);
+ return res;
+
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_blend_epi32 (__m256i a, __m256i b, const int imm8)
+{
+ __m256i res;
+ res.lo = _mm_blend_epi32(a.lo,b.lo,imm8 & 0xf);
+ res.hi = _mm_blend_epi32(a.hi,b.hi,imm8 >> 4);
+ return res;
+
+}
+
+AVX2NEON_ABI
+__m256i _mm256_i32gather_epi32 (int const* base_addr, __m256i vindex, const int scale)
+{
+ __m256i res;
+ for (int i=0;i<4;i++)
+ {
+ res.lo[i] = *(int *)((char *) base_addr + (vindex.lo[i]*scale));
+ res.hi[i] = *(int *)((char *) base_addr + (vindex.hi[i]*scale));
+ }
+ return res;
+}
+
+
+AVX2NEON_ABI
+__m256i _mm256_mask_i32gather_epi32 (__m256i src, int const* base_addr, __m256i vindex, __m256i mask, const int scale)
+{
+ __m256i res = _mm256_setzero_si256();
+ for (int i=0;i<4;i++)
+ {
+ if (mask.lo[i] >> 31) res.lo[i] = *(int *)((char *) base_addr + (vindex.lo[i]*scale));
+ if (mask.hi[i] >> 31) res.hi[i] = *(int *)((char *) base_addr + (vindex.hi[i]*scale));
+ }
+
+ return res;
+
+}
+
+
diff --git a/thirdparty/embree-aarch64/common/math/SSE2NEON.h b/thirdparty/embree-aarch64/common/math/SSE2NEON.h
new file mode 100644
index 0000000000..2013151d31
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/SSE2NEON.h
@@ -0,0 +1,1753 @@
+#ifndef SSE2NEON_H
+#define SSE2NEON_H
+
+// This header file provides a simple API translation layer
+// between SSE intrinsics to their corresponding ARM NEON versions
+//
+// This header file does not (yet) translate *all* of the SSE intrinsics.
+// Since this is in support of a specific porting effort, I have only
+// included the intrinsics I needed to get my port to work.
+//
+// Questions/Comments/Feedback send to: jratcliffscarab@gmail.com
+//
+// If you want to improve or add to this project, send me an
+// email and I will probably approve your access to the depot.
+//
+// Project is located here:
+//
+// https://github.com/jratcliff63367/sse2neon
+//
+// Show your appreciation for open source by sending me a bitcoin tip to the following
+// address.
+//
+// TipJar: 1PzgWDSyq4pmdAXRH8SPUtta4SWGrt4B1p :
+// https://blockchain.info/address/1PzgWDSyq4pmdAXRH8SPUtta4SWGrt4B1p
+//
+//
+// Contributors to this project are:
+//
+// John W. Ratcliff : jratcliffscarab@gmail.com
+// Brandon Rowlett : browlett@nvidia.com
+// Ken Fast : kfast@gdeb.com
+// Eric van Beurden : evanbeurden@nvidia.com
+//
+//
+// *********************************************************************************************************************
+// Release notes for January 20, 2017 version:
+//
+// The unit tests have been refactored. They no longer assert on an error, instead they return a pass/fail condition
+// The unit-tests now test 10,000 random float and int values against each intrinsic.
+//
+// SSE2NEON now supports 95 SSE intrinsics. 39 of them have formal unit tests which have been implemented and
+// fully tested on NEON/ARM. The remaining 56 still need unit tests implemented.
+//
+// A struct is now defined in this header file called 'SIMDVec' which can be used by applications which
+// attempt to access the contents of an _m128 struct directly. It is important to note that accessing the __m128
+// struct directly is bad coding practice by Microsoft: @see: https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx
+//
+// However, some legacy source code may try to access the contents of an __m128 struct directly so the developer
+// can use the SIMDVec as an alias for it. Any casting must be done manually by the developer, as you cannot
+// cast or otherwise alias the base NEON data type for intrinsic operations.
+//
+// A bug was found with the _mm_shuffle_ps intrinsic. If the shuffle permutation was not one of the ones with
+// a custom/unique implementation causing it to fall through to the default shuffle implementation it was failing
+// to return the correct value. This is now fixed.
+//
+// A bug was found with the _mm_cvtps_epi32 intrinsic. This converts floating point values to integers.
+// It was not honoring the correct rounding mode. In SSE the default rounding mode when converting from float to int
+// is to use 'round to even' otherwise known as 'bankers rounding'. ARMv7 did not support this feature but ARMv8 does.
+// As it stands today, this header file assumes ARMv8. If you are trying to target really old ARM devices, you may get
+// a build error.
+//
+// Support for a number of new intrinsics was added, however, none of them yet have unit-tests to 100% confirm they are
+// producing the correct results on NEON. These unit tests will be added as soon as possible.
+//
+// Here is the list of new instrinsics which have been added:
+//
+// _mm_cvtss_f32 : extracts the lower order floating point value from the parameter
+// _mm_add_ss : adds the scalar single - precision floating point values of a and b
+// _mm_div_ps : Divides the four single - precision, floating - point values of a and b.
+// _mm_div_ss : Divides the scalar single - precision floating point value of a by b.
+// _mm_sqrt_ss : Computes the approximation of the square root of the scalar single - precision floating point value of in.
+// _mm_rsqrt_ps : Computes the approximations of the reciprocal square roots of the four single - precision floating point values of in.
+// _mm_comilt_ss : Compares the lower single - precision floating point scalar values of a and b using a less than operation
+// _mm_comigt_ss : Compares the lower single - precision floating point scalar values of a and b using a greater than operation.
+// _mm_comile_ss : Compares the lower single - precision floating point scalar values of a and b using a less than or equal operation.
+// _mm_comige_ss : Compares the lower single - precision floating point scalar values of a and b using a greater than or equal operation.
+// _mm_comieq_ss : Compares the lower single - precision floating point scalar values of a and b using an equality operation.
+// _mm_comineq_s : Compares the lower single - precision floating point scalar values of a and b using an inequality operation
+// _mm_unpackhi_epi8 : Interleaves the upper 8 signed or unsigned 8 - bit integers in a with the upper 8 signed or unsigned 8 - bit integers in b.
+// _mm_unpackhi_epi16: Interleaves the upper 4 signed or unsigned 16 - bit integers in a with the upper 4 signed or unsigned 16 - bit integers in b.
+//
+// *********************************************************************************************************************
+/*
+** The MIT license:
+**
+** 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.
+*/
+
+#pragma once
+
+#define GCC 1
+#define ENABLE_CPP_VERSION 0
+
+// enable precise emulation of _mm_min_ps and _mm_max_ps?
+// This would slow down the computation a bit, but gives consistent result with x86 SSE2.
+// (e.g. would solve a hole or NaN pixel in the rendering result)
+#define USE_PRECISE_MINMAX_IMPLEMENTATION (1)
+
+#if GCC
+#define FORCE_INLINE inline __attribute__((always_inline))
+#define ALIGN_STRUCT(x) __attribute__((aligned(x)))
+#else
+#define FORCE_INLINE inline
+#define ALIGN_STRUCT(x) __declspec(align(x))
+#endif
+
+#include <stdint.h>
+#include "arm_neon.h"
+#if defined(__aarch64__)
+#include "constants.h"
+#endif
+
+
+#if !defined(__has_builtin)
+#define __has_builtin(x) (0)
+#endif
+
+/*******************************************************/
+/* MACRO for shuffle parameter for _mm_shuffle_ps(). */
+/* Argument fp3 is a digit[0123] that represents the fp*/
+/* from argument "b" of mm_shuffle_ps that will be */
+/* placed in fp3 of result. fp2 is the same for fp2 in */
+/* result. fp1 is a digit[0123] that represents the fp */
+/* from argument "a" of mm_shuffle_ps that will be */
+/* places in fp1 of result. fp0 is the same for fp0 of */
+/* result */
+/*******************************************************/
+#if defined(__aarch64__)
+#define _MN_SHUFFLE(fp3,fp2,fp1,fp0) ( (uint8x16_t){ (((fp3)*4)+0), (((fp3)*4)+1), (((fp3)*4)+2), (((fp3)*4)+3), (((fp2)*4)+0), (((fp2)*4)+1), (((fp2)*4)+2), (((fp2)*4)+3), (((fp1)*4)+0), (((fp1)*4)+1), (((fp1)*4)+2), (((fp1)*4)+3), (((fp0)*4)+0), (((fp0)*4)+1), (((fp0)*4)+2), (((fp0)*4)+3) } )
+#define _MF_SHUFFLE(fp3,fp2,fp1,fp0) ( (uint8x16_t){ (((fp3)*4)+0), (((fp3)*4)+1), (((fp3)*4)+2), (((fp3)*4)+3), (((fp2)*4)+0), (((fp2)*4)+1), (((fp2)*4)+2), (((fp2)*4)+3), (((fp1)*4)+16+0), (((fp1)*4)+16+1), (((fp1)*4)+16+2), (((fp1)*4)+16+3), (((fp0)*4)+16+0), (((fp0)*4)+16+1), (((fp0)*4)+16+2), (((fp0)*4)+16+3) } )
+#endif
+
+#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) (((fp3) << 6) | ((fp2) << 4) | \
+ ((fp1) << 2) | ((fp0)))
+
+typedef float32x4_t __m128;
+typedef int32x4_t __m128i;
+
+// union intended to allow direct access to an __m128 variable using the names that the MSVC
+// compiler provides. This union should really only be used when trying to access the members
+// of the vector as integer values. GCC/clang allow native access to the float members through
+// a simple array access operator (in C since 4.6, in C++ since 4.8).
+//
+// Ideally direct accesses to SIMD vectors should not be used since it can cause a performance
+// hit. If it really is needed however, the original __m128 variable can be aliased with a
+// pointer to this union and used to access individual components. The use of this union should
+// be hidden behind a macro that is used throughout the codebase to access the members instead
+// of always declaring this type of variable.
+typedef union ALIGN_STRUCT(16) SIMDVec
+{
+ float m128_f32[4]; // as floats - do not to use this. Added for convenience.
+ int8_t m128_i8[16]; // as signed 8-bit integers.
+ int16_t m128_i16[8]; // as signed 16-bit integers.
+ int32_t m128_i32[4]; // as signed 32-bit integers.
+ int64_t m128_i64[2]; // as signed 64-bit integers.
+ uint8_t m128_u8[16]; // as unsigned 8-bit integers.
+ uint16_t m128_u16[8]; // as unsigned 16-bit integers.
+ uint32_t m128_u32[4]; // as unsigned 32-bit integers.
+ uint64_t m128_u64[2]; // as unsigned 64-bit integers.
+ double m128_f64[2]; // as signed double
+} SIMDVec;
+
+// ******************************************
+// CPU stuff
+// ******************************************
+
+typedef SIMDVec __m128d;
+
+#include <stdlib.h>
+
+#ifndef _MM_MASK_MASK
+#define _MM_MASK_MASK 0x1f80
+#define _MM_MASK_DIV_ZERO 0x200
+#define _MM_FLUSH_ZERO_ON 0x8000
+#define _MM_DENORMALS_ZERO_ON 0x40
+#define _MM_MASK_DENORM 0x100
+#endif
+#define _MM_SET_EXCEPTION_MASK(x)
+#define _MM_SET_FLUSH_ZERO_MODE(x)
+#define _MM_SET_DENORMALS_ZERO_MODE(x)
+
+FORCE_INLINE void _mm_pause()
+{
+}
+
+FORCE_INLINE void _mm_mfence()
+{
+ __sync_synchronize();
+}
+
+#define _MM_HINT_T0 3
+#define _MM_HINT_T1 2
+#define _MM_HINT_T2 1
+#define _MM_HINT_NTA 0
+
+FORCE_INLINE void _mm_prefetch(const void* ptr, unsigned int level)
+{
+ __builtin_prefetch(ptr);
+
+}
+
+FORCE_INLINE void* _mm_malloc(int size, int align)
+{
+ void *ptr;
+ // align must be multiple of sizeof(void *) for posix_memalign.
+ if (align < sizeof(void *)) {
+ align = sizeof(void *);
+ }
+
+ if ((align % sizeof(void *)) != 0) {
+ // fallback to malloc
+ ptr = malloc(size);
+ } else {
+ if (posix_memalign(&ptr, align, size)) {
+ return 0;
+ }
+ }
+
+ return ptr;
+}
+
+FORCE_INLINE void _mm_free(void* ptr)
+{
+ free(ptr);
+}
+
+FORCE_INLINE int _mm_getcsr()
+{
+ return 0;
+}
+
+FORCE_INLINE void _mm_setcsr(int val)
+{
+ return;
+}
+
+// ******************************************
+// Set/get methods
+// ******************************************
+
+// extracts the lower order floating point value from the parameter : https://msdn.microsoft.com/en-us/library/bb514059%28v=vs.120%29.aspx?f=255&MSPPError=-2147217396
+#if defined(__aarch64__)
+FORCE_INLINE float _mm_cvtss_f32(const __m128& x)
+{
+ return x[0];
+}
+#else
+FORCE_INLINE float _mm_cvtss_f32(__m128 a)
+{
+ return vgetq_lane_f32(a, 0);
+}
+#endif
+
+// Sets the 128-bit value to zero https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_setzero_si128()
+{
+ return vdupq_n_s32(0);
+}
+
+// Clears the four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setzero_ps(void)
+{
+ return vdupq_n_f32(0);
+}
+
+// Sets the four single-precision, floating-point values to w. https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set1_ps(float _w)
+{
+ return vdupq_n_f32(_w);
+}
+
+// Sets the four single-precision, floating-point values to w. https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps1(float _w)
+{
+ return vdupq_n_f32(_w);
+}
+
+// Sets the four single-precision, floating-point values to the four inputs. https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx
+#if defined(__aarch64__)
+FORCE_INLINE __m128 _mm_set_ps(const float w, const float z, const float y, const float x)
+{
+ float32x4_t t = { x, y, z, w };
+ return t;
+}
+
+// Sets the four single-precision, floating-point values to the four inputs in reverse order. https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setr_ps(const float w, const float z , const float y , const float x )
+{
+ float32x4_t t = { w, z, y, x };
+ return t;
+}
+#else
+FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)
+{
+ float __attribute__((aligned(16))) data[4] = { x, y, z, w };
+ return vld1q_f32(data);
+}
+
+// Sets the four single-precision, floating-point values to the four inputs in reverse order. https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setr_ps(float w, float z , float y , float x )
+{
+ float __attribute__ ((aligned (16))) data[4] = { w, z, y, x };
+ return vld1q_f32(data);
+}
+#endif
+
+// Sets the 4 signed 32-bit integer values to i. https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi32(int _i)
+{
+ return vdupq_n_s32(_i);
+}
+
+//Set the first lane to of 4 signed single-position, floating-point number to w
+#if defined(__aarch64__)
+FORCE_INLINE __m128 _mm_set_ss(float _w)
+{
+ float32x4_t res = {_w, 0, 0, 0};
+ return res;
+}
+
+// Sets the 4 signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+ int32x4_t t = {i0,i1,i2,i3};
+ return t;
+}
+#else
+FORCE_INLINE __m128 _mm_set_ss(float _w)
+{
+ __m128 val = _mm_setzero_ps();
+ return vsetq_lane_f32(_w, val, 0);
+}
+
+// Sets the 4 signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+ int32_t __attribute__((aligned(16))) data[4] = { i0, i1, i2, i3 };
+ return vld1q_s32(data);
+}
+#endif
+
+// Stores four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, a);
+}
+
+// Stores four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, a);
+}
+
+FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t*) p,a);
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p. https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a )
+{
+ vst1q_s32((int32_t*) p,a);
+}
+
+// Stores the lower single - precision, floating - point value. https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ss(float *p, __m128 a)
+{
+ vst1q_lane_f32(p, a, 0);
+}
+
+// Reads the lower 64 bits of b and stores them into the lower 64 bits of a. https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_storel_epi64(__m128i* a, __m128i b)
+{
+ *a = (__m128i)vsetq_lane_s64((int64_t)vget_low_s32(b), *(int64x2_t*)a, 0);
+}
+
+// Loads a single single-precision, floating-point value, copying it into all four words https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load1_ps(const float * p)
+{
+ return vld1q_dup_f32(p);
+}
+
+// Loads four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load_ps(const float * p)
+{
+ return vld1q_f32(p);
+}
+
+// Loads four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_loadu_ps(const float * p)
+{
+ // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are equivalent for neon
+ return vld1q_f32(p);
+}
+
+// Loads an single - precision, floating - point value into the low word and clears the upper three words. https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_load_ss(const float * p)
+{
+ __m128 result = vdupq_n_f32(0);
+ return vsetq_lane_f32(*p, result, 0);
+}
+
+FORCE_INLINE __m128i _mm_loadu_si128(__m128i *p)
+{
+ return (__m128i)vld1q_s32((const int32_t*) p);
+}
+
+
+// ******************************************
+// Logic/Binary operations
+// ******************************************
+
+// Compares for inequality. https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)
+{
+ return (__m128)vmvnq_s32((__m128i)vceqq_f32(a, b));
+}
+
+// Computes the bitwise AND-NOT of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)
+{
+ return (__m128)vbicq_s32((__m128i)b, (__m128i)a); // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the 128-bit value in a. https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)
+{
+ return (__m128i)vbicq_s32(b, a); // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in b. https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)
+{
+ return (__m128i)vandq_s32(a, b);
+}
+
+// Computes the bitwise AND of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)
+{
+ return (__m128)vandq_s32((__m128i)a, (__m128i)b);
+}
+
+// Computes the bitwise OR of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
+{
+ return (__m128)vorrq_s32((__m128i)a, (__m128i)b);
+}
+
+// Computes bitwise EXOR (exclusive-or) of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)
+{
+ return (__m128)veorq_s32((__m128i)a, (__m128i)b);
+}
+
+// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)
+{
+ return (__m128i)vorrq_s32(a, b);
+}
+
+// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)
+{
+ return veorq_s32(a, b);
+}
+
+// NEON does not provide this method
+// Creates a 4-bit mask from the most significant bits of the four single-precision, floating-point values. https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_ps(__m128 a)
+{
+#if ENABLE_CPP_VERSION // I am not yet convinced that the NEON version is faster than the C version of this
+ uint32x4_t &ia = *(uint32x4_t *)&a;
+ return (ia[0] >> 31) | ((ia[1] >> 30) & 2) | ((ia[2] >> 29) & 4) | ((ia[3] >> 28) & 8);
+#else
+
+#if defined(__aarch64__)
+ uint32x4_t t2 = vandq_u32(vreinterpretq_u32_f32(a), embree::movemask_mask);
+ return vaddvq_u32(t2);
+#else
+ static const uint32x4_t movemask = { 1, 2, 4, 8 };
+ static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+ uint32x4_t t0 = vreinterpretq_u32_f32(a);
+ uint32x4_t t1 = vtstq_u32(t0, highbit);
+ uint32x4_t t2 = vandq_u32(t1, movemask);
+ uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));
+ return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);
+#endif
+
+#endif
+}
+
+#if defined(__aarch64__)
+FORCE_INLINE int _mm_movemask_popcnt_ps(__m128 a)
+{
+ uint32x4_t t2 = vandq_u32(vreinterpretq_u32_f32(a), embree::movemask_mask);
+ t2 = vreinterpretq_u32_u8(vcntq_u8(vreinterpretq_u8_u32(t2)));
+ return vaddvq_u32(t2);
+
+}
+#endif
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of b and places it into the high end of the result.
+FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)
+{
+ return vcombine_f32(vget_high_f32(a), vget_low_f32(b));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in high end of result
+// takes the higher two 32 bit values from b and swaps them and places in low end of result.
+FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)
+{
+ return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(b)));
+}
+
+// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the high
+FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)
+{
+ return vcombine_f32(vget_low_f32(a), vget_high_f32(b));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)
+{
+ return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 1)), vdup_n_f32(vgetq_lane_f32(b, 0)));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)
+{
+ return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 2)), vdup_n_f32(vgetq_lane_f32(b, 0)));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)
+{
+ return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 0)), vdup_n_f32(vgetq_lane_f32(b, 2)));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)
+{
+ float32_t a0 = vgetq_lane_f32(a, 0);
+ float32_t a2 = vgetq_lane_f32(a, 2);
+ float32x2_t aVal = vdup_n_f32(a2);
+ aVal = vset_lane_f32(a0, aVal, 1);
+ return vcombine_f32(aVal, vget_high_f32(b));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)
+{
+ return vcombine_f32(vdup_n_f32(vgetq_lane_f32(a, 3)), vdup_n_f32(vgetq_lane_f32(b, 1)));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)
+{
+ float32_t b0 = vgetq_lane_f32(b, 0);
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t bVal = vdup_n_f32(b0);
+ bVal = vset_lane_f32(b2, bVal, 1);
+ return vcombine_f32(vget_low_f32(a), bVal);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)
+{
+ float32_t b0 = vgetq_lane_f32(b, 0);
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t bVal = vdup_n_f32(b0);
+ bVal = vset_lane_f32(b2, bVal, 1);
+ return vcombine_f32(vrev64_f32(vget_low_f32(a)), bVal);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)
+{
+ float32_t b0 = vgetq_lane_f32(b, 0);
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t bVal = vdup_n_f32(b0);
+ bVal = vset_lane_f32(b2, bVal, 1);
+ return vcombine_f32(vget_high_f32(a), bVal);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)
+{
+ float32x2_t a21 = vget_high_f32(vextq_f32(a, a, 3));
+ float32x2_t b03 = vget_low_f32(vextq_f32(b, b, 3));
+ return vcombine_f32(a21, b03);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)
+{
+ float32x2_t a03 = vget_low_f32(vextq_f32(a, a, 3));
+ float32x2_t b21 = vget_high_f32(vextq_f32(b, b, 3));
+ return vcombine_f32(a03, b21);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(a);
+ float32x2_t b10 = vget_low_f32(b);
+ return vcombine_f32(a10, b10);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(a));
+ float32x2_t b10 = vget_low_f32(b);
+ return vcombine_f32(a01, b10);
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(a));
+ float32x2_t b01 = vrev64_f32(vget_low_f32(b));
+ return vcombine_f32(a01, b01);
+}
+
+// NEON does not support a general purpose permute intrinsic
+// Currently I am not sure whether the C implementation is faster or slower than the NEON version.
+// Note, this has to be expanded as a template because the shuffle value must be an immediate value.
+// The same is true on SSE as well.
+// Selects four specific single-precision, floating-point values from a and b, based on the mask i. https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx
+template <int i>
+FORCE_INLINE __m128 _mm_shuffle_ps_default(const __m128& a, const __m128& b)
+{
+#if ENABLE_CPP_VERSION // I am not convinced that the NEON version is faster than the C version yet.
+ __m128 ret;
+ ret[0] = a[i & 0x3];
+ ret[1] = a[(i >> 2) & 0x3];
+ ret[2] = b[(i >> 4) & 0x03];
+ ret[3] = b[(i >> 6) & 0x03];
+ return ret;
+#else
+# if __has_builtin(__builtin_shufflevector)
+ return __builtin_shufflevector( \
+ a, b, (i) & (0x3), ((i) >> 2) & 0x3,
+ (((i) >> 4) & 0x3) + 4, (((i) >> 6) & 0x3) + 4);
+# else
+ const int i0 = (i >> 0)&0x3;
+ const int i1 = (i >> 2)&0x3;
+ const int i2 = (i >> 4)&0x3;
+ const int i3 = (i >> 6)&0x3;
+
+ if (&a == &b)
+ {
+ if (i0 == i1 && i0 == i2 && i0 == i3)
+ {
+ return (float32x4_t)vdupq_laneq_f32(a,i0);
+ }
+ static const uint8_t tbl[16] = {
+ (i0*4) + 0,(i0*4) + 1,(i0*4) + 2,(i0*4) + 3,
+ (i1*4) + 0,(i1*4) + 1,(i1*4) + 2,(i1*4) + 3,
+ (i2*4) + 0,(i2*4) + 1,(i2*4) + 2,(i2*4) + 3,
+ (i3*4) + 0,(i3*4) + 1,(i3*4) + 2,(i3*4) + 3
+ };
+
+ return (float32x4_t)vqtbl1q_s8(int8x16_t(b),*(uint8x16_t *)tbl);
+
+ }
+ else
+ {
+
+ static const uint8_t tbl[16] = {
+ (i0*4) + 0,(i0*4) + 1,(i0*4) + 2,(i0*4) + 3,
+ (i1*4) + 0,(i1*4) + 1,(i1*4) + 2,(i1*4) + 3,
+ (i2*4) + 0 + 16,(i2*4) + 1 + 16,(i2*4) + 2 + 16,(i2*4) + 3 + 16,
+ (i3*4) + 0 + 16,(i3*4) + 1 + 16,(i3*4) + 2 + 16,(i3*4) + 3 + 16
+ };
+
+ return float32x4_t(vqtbl2q_s8((int8x16x2_t){int8x16_t(a),int8x16_t(b)},*(uint8x16_t *)tbl));
+ }
+# endif //builtin(shufflevector)
+#endif
+}
+
+template <int i >
+FORCE_INLINE __m128 _mm_shuffle_ps_function(const __m128& a, const __m128& b)
+{
+ switch (i)
+ {
+ case _MM_SHUFFLE(1, 0, 3, 2):
+ return _mm_shuffle_ps_1032(a, b);
+ break;
+ case _MM_SHUFFLE(2, 3, 0, 1):
+ return _mm_shuffle_ps_2301(a, b);
+ break;
+ case _MM_SHUFFLE(3, 2, 1, 0):
+ return _mm_shuffle_ps_3210(a, b);
+ break;
+ case _MM_SHUFFLE(0, 0, 1, 1):
+ return _mm_shuffle_ps_0011(a, b);
+ break;
+ case _MM_SHUFFLE(0, 0, 2, 2):
+ return _mm_shuffle_ps_0022(a, b);
+ break;
+ case _MM_SHUFFLE(2, 2, 0, 0):
+ return _mm_shuffle_ps_2200(a, b);
+ break;
+ case _MM_SHUFFLE(3, 2, 0, 2):
+ return _mm_shuffle_ps_3202(a, b);
+ break;
+ case _MM_SHUFFLE(1, 1, 3, 3):
+ return _mm_shuffle_ps_1133(a, b);
+ break;
+ case _MM_SHUFFLE(2, 0, 1, 0):
+ return _mm_shuffle_ps_2010(a, b);
+ break;
+ case _MM_SHUFFLE(2, 0, 0, 1):
+ return _mm_shuffle_ps_2001(a, b);
+ break;
+ case _MM_SHUFFLE(2, 0, 3, 2):
+ return _mm_shuffle_ps_2032(a, b);
+ break;
+ case _MM_SHUFFLE(0, 3, 2, 1):
+ return _mm_shuffle_ps_0321(a, b);
+ break;
+ case _MM_SHUFFLE(2, 1, 0, 3):
+ return _mm_shuffle_ps_2103(a, b);
+ break;
+ case _MM_SHUFFLE(1, 0, 1, 0):
+ return _mm_shuffle_ps_1010(a, b);
+ break;
+ case _MM_SHUFFLE(1, 0, 0, 1):
+ return _mm_shuffle_ps_1001(a, b);
+ break;
+ case _MM_SHUFFLE(0, 1, 0, 1):
+ return _mm_shuffle_ps_0101(a, b);
+ break;
+ }
+ return _mm_shuffle_ps_default<i>(a, b);
+}
+
+# if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_ps(a,b,i) _mm_shuffle_ps_default<i>(a,b)
+# else
+#define _mm_shuffle_ps(a,b,i) _mm_shuffle_ps_function<i>(a,b)
+#endif
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of b and places it into the high end of the result.
+FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a, __m128i b)
+{
+ return vcombine_s32(vget_high_s32(a), vget_low_s32(b));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in low end of result
+// takes the higher two 32 bit values from b and swaps them and places in high end of result.
+FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a, __m128i b)
+{
+ return vcombine_s32(vrev64_s32(vget_low_s32(a)), vrev64_s32(vget_high_s32(b)));
+}
+
+// shift a right by 32 bits, and put the lower 32 bits of a into the upper 32 bits of b
+// when a and b are the same, rotates the least significant 32 bits into the most signficant 32 bits, and shifts the rest down
+FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a, __m128i b)
+{
+ return vextq_s32(a, b, 1);
+}
+
+// shift a left by 32 bits, and put the upper 32 bits of b into the lower 32 bits of a
+// when a and b are the same, rotates the most significant 32 bits into the least signficant 32 bits, and shifts the rest up
+FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a, __m128i b)
+{
+ return vextq_s32(a, b, 3);
+}
+
+// gets the lower 64 bits of a, and places it in the upper 64 bits
+// gets the lower 64 bits of b and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a, __m128i b)
+{
+ return vcombine_s32(vget_low_s32(a), vget_low_s32(a));
+}
+
+// gets the lower 64 bits of a, and places it in the upper 64 bits
+// gets the lower 64 bits of b, swaps the 0 and 1 elements, and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a, __m128i b)
+{
+ return vcombine_s32(vrev64_s32(vget_low_s32(a)), vget_low_s32(b));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the upper 64 bits
+// gets the lower 64 bits of b, swaps the 0 and 1 elements, and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a, __m128i b)
+{
+ return vcombine_s32(vrev64_s32(vget_low_s32(a)), vrev64_s32(vget_low_s32(b)));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a, __m128i b)
+{
+ return vcombine_s32(vdup_n_s32(vgetq_lane_s32(a, 1)), vdup_n_s32(vgetq_lane_s32(b, 2)));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a, __m128i b)
+{
+ return vcombine_s32(vdup_n_s32(vgetq_lane_s32(a, 2)), vrev64_s32(vget_low_s32(b)));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a, __m128i b)
+{
+ return vcombine_s32(vget_high_s32(a), vdup_n_s32(vgetq_lane_s32(b, 3)));
+}
+
+template <int i >
+FORCE_INLINE __m128i _mm_shuffle_epi32_default(__m128i a, __m128i b)
+{
+#if ENABLE_CPP_VERSION
+ __m128i ret;
+ ret[0] = a[i & 0x3];
+ ret[1] = a[(i >> 2) & 0x3];
+ ret[2] = b[(i >> 4) & 0x03];
+ ret[3] = b[(i >> 6) & 0x03];
+ return ret;
+#else
+ __m128i ret = vmovq_n_s32(vgetq_lane_s32(a, i & 0x3));
+ ret = vsetq_lane_s32(vgetq_lane_s32(a, (i >> 2) & 0x3), ret, 1);
+ ret = vsetq_lane_s32(vgetq_lane_s32(b, (i >> 4) & 0x3), ret, 2);
+ ret = vsetq_lane_s32(vgetq_lane_s32(b, (i >> 6) & 0x3), ret, 3);
+ return ret;
+#endif
+}
+
+template <int i >
+FORCE_INLINE __m128i _mm_shuffle_epi32_function(__m128i a, __m128i b)
+{
+ switch (i)
+ {
+ case _MM_SHUFFLE(1, 0, 3, 2): return _mm_shuffle_epi_1032(a, b); break;
+ case _MM_SHUFFLE(2, 3, 0, 1): return _mm_shuffle_epi_2301(a, b); break;
+ case _MM_SHUFFLE(0, 3, 2, 1): return _mm_shuffle_epi_0321(a, b); break;
+ case _MM_SHUFFLE(2, 1, 0, 3): return _mm_shuffle_epi_2103(a, b); break;
+ case _MM_SHUFFLE(1, 0, 1, 0): return _mm_shuffle_epi_1010(a, b); break;
+ case _MM_SHUFFLE(1, 0, 0, 1): return _mm_shuffle_epi_1001(a, b); break;
+ case _MM_SHUFFLE(0, 1, 0, 1): return _mm_shuffle_epi_0101(a, b); break;
+ case _MM_SHUFFLE(2, 2, 1, 1): return _mm_shuffle_epi_2211(a, b); break;
+ case _MM_SHUFFLE(0, 1, 2, 2): return _mm_shuffle_epi_0122(a, b); break;
+ case _MM_SHUFFLE(3, 3, 3, 2): return _mm_shuffle_epi_3332(a, b); break;
+ default: return _mm_shuffle_epi32_default<i>(a, b);
+ }
+}
+
+template <int i >
+FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a)
+{
+ return vdupq_n_s32(vgetq_lane_s32(a, i));
+}
+
+template <int i>
+FORCE_INLINE __m128i _mm_shuffle_epi32_single(__m128i a)
+{
+ switch (i)
+ {
+ case _MM_SHUFFLE(0, 0, 0, 0): return _mm_shuffle_epi32_splat<0>(a); break;
+ case _MM_SHUFFLE(1, 1, 1, 1): return _mm_shuffle_epi32_splat<1>(a); break;
+ case _MM_SHUFFLE(2, 2, 2, 2): return _mm_shuffle_epi32_splat<2>(a); break;
+ case _MM_SHUFFLE(3, 3, 3, 3): return _mm_shuffle_epi32_splat<3>(a); break;
+ default: return _mm_shuffle_epi32_function<i>(a, a);
+ }
+}
+
+// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm. https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx
+#define _mm_shuffle_epi32(a,i) _mm_shuffle_epi32_single<i>(a)
+
+template <int i>
+FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a)
+{
+ int16x8_t ret = (int16x8_t)a;
+ int16x4_t highBits = vget_high_s16(ret);
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, i & 0x3), ret, 4);
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 2) & 0x3), ret, 5);
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 4) & 0x3), ret, 6);
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, (i >> 6) & 0x3), ret, 7);
+ return (__m128i)ret;
+}
+
+// Shuffles the upper 4 signed or unsigned 16 - bit integers in a as specified by imm. https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
+#define _mm_shufflehi_epi16(a,i) _mm_shufflehi_epi16_function<i>(a)
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while shifting in zeros. : https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx
+//#define _mm_slli_epi32(a, imm) (__m128i)vshlq_n_s32(a,imm)
+
+// Based on SIMDe
+FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, const int imm8)
+{
+#if defined(__aarch64__)
+ const int32x4_t s = vdupq_n_s32(imm8);
+ return vshlq_s32(a, s);
+#else
+ int32_t __attribute__((aligned(16))) data[4];
+ vst1q_s32(data, a);
+ const int s = (imm8 > 31) ? 0 : imm8;
+ data[0] = data[0] << s;
+ data[1] = data[1] << s;
+ data[2] = data[2] << s;
+ data[3] = data[3] << s;
+
+ return vld1q_s32(data);
+#endif
+}
+
+
+//Shifts the 4 signed or unsigned 32-bit integers in a right by count bits while shifting in zeros. https://msdn.microsoft.com/en-us/library/w486zcfa(v=vs.100).aspx
+//#define _mm_srli_epi32( a, imm ) (__m128i)vshrq_n_u32((uint32x4_t)a, imm)
+
+// Based on SIMDe
+FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, const int imm8)
+{
+#if defined(__aarch64__)
+ const int shift = (imm8 > 31) ? 0 : imm8; // Unfortunately, we need to check for this case for embree.
+ const int32x4_t s = vdupq_n_s32(-shift);
+ return vreinterpretq_s32_u32(vshlq_u32(vreinterpretq_u32_s32(a), s));
+#else
+ int32_t __attribute__((aligned(16))) data[4];
+ vst1q_s32(data, a);
+
+ const int s = (imm8 > 31) ? 0 : imm8;
+
+ data[0] = data[0] >> s;
+ data[1] = data[1] >> s;
+ data[2] = data[2] >> s;
+ data[3] = data[3] >> s;
+
+ return vld1q_s32(data);
+#endif
+}
+
+
+// Shifts the 4 signed 32 - bit integers in a right by count bits while shifting in the sign bit. https://msdn.microsoft.com/en-us/library/z1939387(v=vs.100).aspx
+//#define _mm_srai_epi32( a, imm ) vshrq_n_s32(a, imm)
+
+// Based on SIMDe
+FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, const int imm8)
+{
+#if defined(__aarch64__)
+ const int32x4_t s = vdupq_n_s32(-imm8);
+ return vshlq_s32(a, s);
+#else
+ int32_t __attribute__((aligned(16))) data[4];
+ vst1q_s32(data, a);
+ const uint32_t m = (uint32_t) ((~0U) << (32 - imm8));
+
+ for (int i = 0; i < 4; i++) {
+ uint32_t is_neg = ((uint32_t) (((data[i]) >> 31)));
+ data[i] = (data[i] >> imm8) | (m * is_neg);
+ }
+
+ return vld1q_s32(data);
+#endif
+}
+
+// Shifts the 128 - bit value in a right by imm bytes while shifting in zeros.imm must be an immediate. https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx
+//#define _mm_srli_si128( a, imm ) (__m128i)vmaxq_s8((int8x16_t)a, vextq_s8((int8x16_t)a, vdupq_n_s8(0), imm))
+#define _mm_srli_si128( a, imm ) (__m128i)vextq_s8((int8x16_t)a, vdupq_n_s8(0), (imm))
+
+// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm must be an immediate. https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx
+#define _mm_slli_si128( a, imm ) (__m128i)vextq_s8(vdupq_n_s8(0), (int8x16_t)a, 16 - (imm))
+
+// NEON does not provide a version of this function, here is an article about some ways to repro the results.
+// http://stackoverflow.com/questions/11870910/sse-mm-movemask-epi8-equivalent-method-for-arm-neon
+// Creates a 16-bit mask from the most significant bits of the 16 signed or unsigned 8-bit integers in a and zero extends the upper bits. https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_epi8(__m128i _a)
+{
+ uint8x16_t input = (uint8x16_t)_a;
+ const int8_t __attribute__((aligned(16))) xr[8] = { -7, -6, -5, -4, -3, -2, -1, 0 };
+ uint8x8_t mask_and = vdup_n_u8(0x80);
+ int8x8_t mask_shift = vld1_s8(xr);
+
+ uint8x8_t lo = vget_low_u8(input);
+ uint8x8_t hi = vget_high_u8(input);
+
+ lo = vand_u8(lo, mask_and);
+ lo = vshl_u8(lo, mask_shift);
+
+ hi = vand_u8(hi, mask_and);
+ hi = vshl_u8(hi, mask_shift);
+
+ lo = vpadd_u8(lo, lo);
+ lo = vpadd_u8(lo, lo);
+ lo = vpadd_u8(lo, lo);
+
+ hi = vpadd_u8(hi, hi);
+ hi = vpadd_u8(hi, hi);
+ hi = vpadd_u8(hi, hi);
+
+ return ((hi[0] << 8) | (lo[0] & 0xFF));
+}
+
+
+// ******************************************
+// Math operations
+// ******************************************
+
+// Subtracts the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)
+{
+ return vsubq_f32(a, b);
+}
+
+FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b)
+{
+ return vsubq_f32(a, b);
+}
+
+// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or unsigned 32-bit integers of a. https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)
+{
+ return vsubq_s32(a, b);
+}
+
+// Adds the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)
+{
+ return vaddq_f32(a, b);
+}
+
+// adds the scalar single-precision floating point values of a and b. https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)
+{
+ const float32_t b0 = vgetq_lane_f32(b, 0);
+ float32x4_t value = vdupq_n_f32(0);
+
+ //the upper values in the result must be the remnants of <a>.
+ value = vsetq_lane_f32(b0, value, 0);
+ return vaddq_f32(a, value);
+}
+
+// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or unsigned 32-bit integers in b. https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)
+{
+ return vaddq_s32(a, b);
+}
+
+// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or unsigned 16-bit integers in b. https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)vaddq_s16((int16x8_t)a, (int16x8_t)b);
+}
+
+// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or unsigned 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)vmulq_s16((int16x8_t)a, (int16x8_t)b);
+}
+
+// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or unsigned 32-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi32 (__m128i a, __m128i b)
+{
+ return (__m128i)vmulq_s32((int32x4_t)a,(int32x4_t)b);
+}
+
+// Multiplies the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)
+{
+ return vmulq_f32(a, b);
+}
+
+FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b)
+{
+ return vmulq_f32(a, b);
+}
+
+// Computes the approximations of reciprocals of the four single-precision, floating-point values of a. https://msdn.microsoft.com/en-us/library/vstudio/796k1tty(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rcp_ps(__m128 in)
+{
+#if defined(BUILD_IOS)
+ return vdivq_f32(vdupq_n_f32(1.0f),in);
+
+#endif
+ // Get an initial estimate of 1/in.
+ float32x4_t reciprocal = vrecpeq_f32(in);
+
+ // We only return estimated 1/in.
+ // Newton-Raphon iteration shold be done in the outside of _mm_rcp_ps().
+
+ // TODO(LTE): We could delete these ifdef?
+ reciprocal = vmulq_f32(vrecpsq_f32(in, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(in, reciprocal), reciprocal);
+ return reciprocal;
+
+}
+
+FORCE_INLINE __m128 _mm_rcp_ss(__m128 in)
+{
+ float32x4_t value;
+ float32x4_t result = in;
+
+ value = _mm_rcp_ps(in);
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+// Divides the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)
+{
+#if defined(BUILD_IOS)
+ return vdivq_f32(a,b);
+#else
+ float32x4_t reciprocal = _mm_rcp_ps(b);
+
+ reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
+
+ // Add one more round of newton-raphson since NEON's reciprocal estimation has less accuracy compared to SSE2's rcp.
+ reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
+
+ // Another round for safety
+ reciprocal = vmulq_f32(vrecpsq_f32(b, reciprocal), reciprocal);
+
+
+ return vmulq_f32(a, reciprocal);
+#endif
+}
+
+// Divides the scalar single-precision floating point value of a by b. https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)
+{
+ float32x4_t value;
+ float32x4_t result = a;
+ value = _mm_div_ps(a, b);
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+// Computes the approximations of the reciprocal square roots of the four single-precision floating point values of in. https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)
+{
+
+ float32x4_t value = vrsqrteq_f32(in);
+
+ // TODO: We must debug and ensure that rsqrt(0) and rsqrt(-0) yield proper values.
+ // Related code snippets can be found here: https://cpp.hotexamples.com/examples/-/-/vrsqrteq_f32/cpp-vrsqrteq_f32-function-examples.html
+ // If we adapt this function, we might be able to avoid special zero treatment in _mm_sqrt_ps
+
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
+
+ // one more round to get better precision
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
+
+ // another round for safety
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(in, value), value));
+
+ return value;
+}
+
+FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in)
+{
+ float32x4_t result = in;
+
+ __m128 value = _mm_rsqrt_ps(in);
+
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+
+// Computes the approximations of square roots of the four single-precision, floating-point values of a. First computes reciprocal square roots and then reciprocals of the four values. https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)
+{
+#if defined(BUILD_IOS)
+ return vsqrtq_f32(in);
+#else
+ __m128 reciprocal = _mm_rsqrt_ps(in);
+
+ // We must treat sqrt(in == 0) in a special way. At this point reciprocal contains gargabe due to vrsqrteq_f32(0) returning +inf.
+ // We assign 0 to reciprocal wherever required.
+ const float32x4_t vzero = vdupq_n_f32(0.0f);
+ const uint32x4_t mask = vceqq_f32(in, vzero);
+ reciprocal = vbslq_f32(mask, vzero, reciprocal);
+
+ // sqrt(x) = x * (1 / sqrt(x))
+ return vmulq_f32(in, reciprocal);
+#endif
+}
+
+// Computes the approximation of the square root of the scalar single-precision floating point value of in. https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)
+{
+ float32x4_t value;
+ float32x4_t result = in;
+
+ value = _mm_sqrt_ps(in);
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+
+// Computes the maximums of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)
+{
+#if USE_PRECISE_MINMAX_IMPLEMENTATION
+ return vbslq_f32(vcltq_f32(b,a),a,b);
+#else
+ // Faster, but would give inconsitent rendering(e.g. holes, NaN pixels)
+ return vmaxq_f32(a, b);
+#endif
+}
+
+// Computes the minima of the four single-precision, floating-point values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)
+{
+#if USE_PRECISE_MINMAX_IMPLEMENTATION
+ return vbslq_f32(vcltq_f32(a,b),a,b);
+#else
+ // Faster, but would give inconsitent rendering(e.g. holes, NaN pixels)
+ return vminq_f32(a, b);
+#endif
+}
+
+// Computes the maximum of the two lower scalar single-precision floating point values of a and b. https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)
+{
+ float32x4_t value;
+ float32x4_t result = a;
+
+ value = _mm_max_ps(a, b);
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+// Computes the minimum of the two lower scalar single-precision floating point values of a and b. https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)
+{
+ float32x4_t value;
+ float32x4_t result = a;
+
+
+ value = _mm_min_ps(a, b);
+ return vsetq_lane_f32(vgetq_lane_f32(value, 0), result, 0);
+}
+
+// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 signed 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)vminq_s16((int16x8_t)a, (int16x8_t)b);
+}
+
+// epi versions of min/max
+// Computes the pariwise maximums of the four signed 32-bit integer values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b )
+{
+ return vmaxq_s32(a,b);
+}
+
+// Computes the pariwise minima of the four signed 32-bit integer values of a and b. https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b )
+{
+ return vminq_s32(a,b);
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit integers from b. https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)
+{
+ int16x8_t ret = vqdmulhq_s16((int16x8_t)a, (int16x8_t)b);
+ ret = vshrq_n_s16(ret, 1);
+ return (__m128i)ret;
+}
+
+// Computes pairwise add of each argument as single-precision, floating-point values a and b.
+//https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx
+FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b )
+{
+#if defined(__aarch64__)
+ return vpaddq_f32(a,b);
+#else
+// This does not work, no vpaddq...
+// return (__m128) vpaddq_f32(a,b);
+ //
+ // get two f32x2_t values from a
+ // do vpadd
+ // put result in low half of f32x4 result
+ //
+ // get two f32x2_t values from b
+ // do vpadd
+ // put result in high half of f32x4 result
+ //
+ // combine
+ return vcombine_f32( vpadd_f32( vget_low_f32(a), vget_high_f32(a) ), vpadd_f32( vget_low_f32(b), vget_high_f32(b) ) );
+#endif
+}
+
+// ******************************************
+// Compare operations
+// ******************************************
+
+// Compares for less than https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)
+{
+ return (__m128)vcltq_f32(a, b);
+}
+
+FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b)
+{
+ return (__m128) vmvnq_s32((__m128i)_mm_cmplt_ps(a,b));
+}
+
+// Compares for greater than. https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)
+{
+ return (__m128)vcgtq_f32(a, b);
+}
+
+FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b)
+{
+ return (__m128) _mm_cmpgt_ps(a,b);
+}
+
+
+// Compares for greater than or equal. https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)
+{
+ return (__m128)vcgeq_f32(a, b);
+}
+
+// Compares for less than or equal. https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)
+{
+ return (__m128)vcleq_f32(a, b);
+}
+
+// Compares for equality. https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)
+{
+ return (__m128)vceqq_f32(a, b);
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers in b for less than. https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)vcltq_s32(a, b);
+}
+
+FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
+{
+ return (__m128i) vceqq_s32(a,b);
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers in b for greater than. https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)vcgtq_s32(a, b);
+}
+
+// Compares the four 32-bit floats in a and b to check if any values are NaN. Ordered compare between each value returns true for "orderable" and false for "not orderable" (NaN). https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx
+// see also:
+// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean
+// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics
+FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b )
+{
+ // Note: NEON does not have ordered compare builtin
+ // Need to compare a eq a and b eq b to check for NaN
+ // Do AND of results to get final
+ return (__m128) vreinterpretq_f32_u32( vandq_u32( vceqq_f32(a,a), vceqq_f32(b,b) ) );
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using a less than operation. : https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx
+FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vcltq_f32(a, b);
+ return vgetq_lane_u32(value, 0);
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using a greater than operation. : https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx
+FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vcgtq_f32(a, b);
+ return vgetq_lane_u32(value, 0);
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using a less than or equal operation. : https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx
+FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vcleq_f32(a, b);
+ return vgetq_lane_u32(value, 0);
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using a greater than or equal operation. : https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx
+FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vcgeq_f32(a, b);
+ return vgetq_lane_u32(value, 0);
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using an equality operation. : https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx
+FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vceqq_f32(a, b);
+ return vgetq_lane_u32(value, 0);
+}
+
+// Compares the lower single-precision floating point scalar values of a and b using an inequality operation. : https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx
+FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)
+{
+ uint32x4_t value;
+
+ value = vceqq_f32(a, b);
+ return !vgetq_lane_u32(value, 0);
+}
+
+// according to the documentation, these intrinsics behave the same as the non-'u' versions. We'll just alias them here.
+#define _mm_ucomilt_ss _mm_comilt_ss
+#define _mm_ucomile_ss _mm_comile_ss
+#define _mm_ucomigt_ss _mm_comigt_ss
+#define _mm_ucomige_ss _mm_comige_ss
+#define _mm_ucomieq_ss _mm_comieq_ss
+#define _mm_ucomineq_ss _mm_comineq_ss
+
+// ******************************************
+// Conversions
+// ******************************************
+
+// Converts the four single-precision, floating-point values of a to signed 32-bit integer values using truncate. https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)
+{
+ return vcvtq_s32_f32(a);
+}
+
+// Converts the four signed 32-bit integer values of a to single-precision, floating-point values https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)
+{
+ return vcvtq_f32_s32(a);
+}
+
+// Converts the four single-precision, floating-point values of a to signed 32-bit integer values. https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx
+// *NOTE*. The default rounding mode on SSE is 'round to even', which ArmV7 does not support!
+// It is supported on ARMv8 however.
+FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)
+{
+#if 1
+ return vcvtnq_s32_f32(a);
+#else
+ __m128 half = vdupq_n_f32(0.5f);
+ const __m128 sign = vcvtq_f32_u32((vshrq_n_u32(vreinterpretq_u32_f32(a), 31)));
+ const __m128 aPlusHalf = vaddq_f32(a, half);
+ const __m128 aRound = vsubq_f32(aPlusHalf, sign);
+ return vcvtq_s32_f32(aRound);
+#endif
+}
+
+// Moves the least significant 32 bits of a to a 32-bit integer. https://msdn.microsoft.com/en-us/library/5z7a9642%28v=vs.90%29.aspx
+FORCE_INLINE int _mm_cvtsi128_si32(__m128i a)
+{
+ return vgetq_lane_s32(a, 0);
+}
+
+// Moves 32-bit integer a to the least significant 32 bits of an __m128 object, zero extending the upper bits. https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_cvtsi32_si128(int a)
+{
+ __m128i result = vdupq_n_s32(0);
+ return vsetq_lane_s32(a, result, 0);
+}
+
+
+// Applies a type cast to reinterpret four 32-bit floating point values passed in as a 128-bit parameter as packed 32-bit integers. https://msdn.microsoft.com/en-us/library/bb514099.aspx
+FORCE_INLINE __m128i _mm_castps_si128(__m128 a)
+{
+#if defined(__aarch64__)
+ return (__m128i)a;
+#else
+ return *(const __m128i *)&a;
+#endif
+}
+
+// Applies a type cast to reinterpret four 32-bit integers passed in as a 128-bit parameter as packed 32-bit floating point values. https://msdn.microsoft.com/en-us/library/bb514029.aspx
+FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)
+{
+#if defined(__aarch64__)
+ return (__m128)a;
+#else
+ return *(const __m128 *)&a;
+#endif
+}
+
+// Loads 128-bit value. : https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx
+FORCE_INLINE __m128i _mm_load_si128(const __m128i *p)
+{
+ return vld1q_s32((int32_t *)p);
+}
+
+FORCE_INLINE __m128d _mm_castps_pd(const __m128 a)
+{
+ return *(const __m128d *)&a;
+}
+
+FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a)
+{
+ return *(const __m128d *)&a;
+}
+// ******************************************
+// Miscellaneous Operations
+// ******************************************
+
+// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and saturates. https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)
+{
+ return (__m128i)vcombine_s8(vqmovn_s16((int16x8_t)a), vqmovn_s16((int16x8_t)b));
+}
+
+// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned integers and saturates. https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
+{
+ return (__m128i)vcombine_u8(vqmovun_s16((int16x8_t)a), vqmovun_s16((int16x8_t)b));
+}
+
+// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers and saturates. https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)vcombine_s16(vqmovn_s32(a), vqmovn_s32(b));
+}
+
+// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower 8 signed or unsigned 8-bit integers in b. https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)
+{
+ int8x8_t a1 = (int8x8_t)vget_low_s16((int16x8_t)a);
+ int8x8_t b1 = (int8x8_t)vget_low_s16((int16x8_t)b);
+
+ int8x8x2_t result = vzip_s8(a1, b1);
+
+ return (__m128i)vcombine_s8(result.val[0], result.val[1]);
+}
+
+// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the lower 4 signed or unsigned 16-bit integers in b. https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)
+{
+ int16x4_t a1 = vget_low_s16((int16x8_t)a);
+ int16x4_t b1 = vget_low_s16((int16x8_t)b);
+
+ int16x4x2_t result = vzip_s16(a1, b1);
+
+ return (__m128i)vcombine_s16(result.val[0], result.val[1]);
+}
+
+// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the lower 2 signed or unsigned 32 - bit integers in b. https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)
+{
+ int32x2_t a1 = vget_low_s32(a);
+ int32x2_t b1 = vget_low_s32(b);
+
+ int32x2x2_t result = vzip_s32(a1, b1);
+
+ return vcombine_s32(result.val[0], result.val[1]);
+}
+
+// Selects and interleaves the lower two single-precision, floating-point values from a and b. https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)
+{
+ float32x2x2_t result = vzip_f32(vget_low_f32(a), vget_low_f32(b));
+ return vcombine_f32(result.val[0], result.val[1]);
+}
+
+// Selects and interleaves the upper two single-precision, floating-point values from a and b. https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)
+{
+ float32x2x2_t result = vzip_f32(vget_high_f32(a), vget_high_f32(b));
+ return vcombine_f32(result.val[0], result.val[1]);
+}
+
+// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper 8 signed or unsigned 8-bit integers in b. https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)
+{
+ int8x8_t a1 = (int8x8_t)vget_high_s16((int16x8_t)a);
+ int8x8_t b1 = (int8x8_t)vget_high_s16((int16x8_t)b);
+
+ int8x8x2_t result = vzip_s8(a1, b1);
+
+ return (__m128i)vcombine_s8(result.val[0], result.val[1]);
+}
+
+// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the upper 4 signed or unsigned 16-bit integers in b. https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)
+{
+ int16x4_t a1 = vget_high_s16((int16x8_t)a);
+ int16x4_t b1 = vget_high_s16((int16x8_t)b);
+
+ int16x4x2_t result = vzip_s16(a1, b1);
+
+ return (__m128i)vcombine_s16(result.val[0], result.val[1]);
+}
+
+// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the upper 2 signed or unsigned 32-bit integers in b. https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)
+{
+ int32x2_t a1 = vget_high_s32(a);
+ int32x2_t b1 = vget_high_s32(b);
+
+ int32x2x2_t result = vzip_s32(a1, b1);
+
+ return vcombine_s32(result.val[0], result.val[1]);
+}
+
+// Extracts the selected signed or unsigned 16-bit integer from a and zero extends. https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx
+#define _mm_extract_epi16( a, imm ) vgetq_lane_s16((int16x8_t)a, imm)
+
+// ******************************************
+// Streaming Extensions
+// ******************************************
+
+// Guarantees that every preceding store is globally visible before any subsequent store. https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_sfence(void)
+{
+ __sync_synchronize();
+}
+
+// Stores the data in a to the address p without polluting the caches. If the cache line containing address p is already in the cache, the cache will be updated.Address p must be 16 - byte aligned. https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)
+{
+ *p = a;
+}
+
+// Cache line containing p is flushed and invalidated from all caches in the coherency domain. : https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx
+FORCE_INLINE void _mm_clflush(void const*p)
+{
+ // no corollary for Neon?
+}
+
+FORCE_INLINE __m128i _mm_set_epi64x(int64_t a, int64_t b)
+{
+ // Stick to the flipped behavior of x86.
+ int64_t __attribute__((aligned(16))) data[2] = { b, a };
+ return (__m128i)vld1q_s64(data);
+}
+
+FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i)
+{
+ return (__m128i)vmovq_n_s64(_i);
+}
+
+#if defined(__aarch64__)
+FORCE_INLINE __m128 _mm_blendv_ps(__m128 a, __m128 b, __m128 c)
+{
+ int32x4_t mask = vshrq_n_s32(__m128i(c),31);
+ return vbslq_f32( uint32x4_t(mask), b, a);
+}
+
+FORCE_INLINE __m128i _mm_load4epu8_epi32(__m128i *ptr)
+{
+ uint8x8_t t0 = vld1_u8((uint8_t*)ptr);
+ uint16x8_t t1 = vmovl_u8(t0);
+ uint32x4_t t2 = vmovl_u16(vget_low_u16(t1));
+ return vreinterpretq_s32_u32(t2);
+}
+
+FORCE_INLINE __m128i _mm_load4epu16_epi32(__m128i *ptr)
+{
+ uint16x8_t t0 = vld1q_u16((uint16_t*)ptr);
+ uint32x4_t t1 = vmovl_u16(vget_low_u16(t0));
+ return vreinterpretq_s32_u32(t1);
+}
+
+FORCE_INLINE __m128i _mm_load4epi8_f32(__m128i *ptr)
+{
+ int8x8_t t0 = vld1_s8((int8_t*)ptr);
+ int16x8_t t1 = vmovl_s8(t0);
+ int32x4_t t2 = vmovl_s16(vget_low_s16(t1));
+ float32x4_t t3 = vcvtq_f32_s32(t2);
+ return vreinterpretq_s32_f32(t3);
+}
+
+FORCE_INLINE __m128i _mm_load4epu8_f32(__m128i *ptr)
+{
+ uint8x8_t t0 = vld1_u8((uint8_t*)ptr);
+ uint16x8_t t1 = vmovl_u8(t0);
+ uint32x4_t t2 = vmovl_u16(vget_low_u16(t1));
+ return vreinterpretq_s32_u32(t2);
+}
+
+FORCE_INLINE __m128i _mm_load4epi16_f32(__m128i *ptr)
+{
+ int16x8_t t0 = vld1q_s16((int16_t*)ptr);
+ int32x4_t t1 = vmovl_s16(vget_low_s16(t0));
+ float32x4_t t2 = vcvtq_f32_s32(t1);
+ return vreinterpretq_s32_f32(t2);
+}
+
+FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b)
+{
+ return (__m128i)vcombine_u8(vqmovun_s16((int16x8_t)a), vqmovun_s16((int16x8_t)b));
+}
+
+FORCE_INLINE __m128i _mm_stream_load_si128(__m128i* ptr)
+{
+ // No non-temporal load on a single register on ARM.
+ return vreinterpretq_s32_u8(vld1q_u8((uint8_t*)ptr));
+}
+
+FORCE_INLINE void _mm_stream_ps(float* ptr, __m128i a)
+{
+ // No non-temporal store on a single register on ARM.
+ vst1q_f32((float*)ptr, vreinterpretq_f32_s32(a));
+}
+
+FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b)
+{
+ return vreinterpretq_s32_u32(vminq_u32(vreinterpretq_u32_s32(a), vreinterpretq_u32_s32(b)));
+}
+
+FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b)
+{
+ return vreinterpretq_s32_u32(vmaxq_u32(vreinterpretq_u32_s32(a), vreinterpretq_u32_s32(b)));
+}
+
+FORCE_INLINE __m128 _mm_abs_ps(__m128 a)
+{
+ return vabsq_f32(a);
+}
+
+FORCE_INLINE __m128 _mm_madd_ps(__m128 a, __m128 b, __m128 c)
+{
+ return vmlaq_f32(c, a, b);
+}
+
+FORCE_INLINE __m128 _mm_msub_ps(__m128 a, __m128 b, __m128 c)
+{
+ return vmlsq_f32(c, a, b);
+}
+
+FORCE_INLINE __m128i _mm_abs_epi32(__m128i a)
+{
+ return vabsq_s32(a);
+}
+#endif //defined(__aarch64__)
+
+// Count the number of bits set to 1 in unsigned 32-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32
+FORCE_INLINE int _mm_popcnt_u32(unsigned int a)
+{
+ return (int)vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t)a)));
+}
+
+// Count the number of bits set to 1 in unsigned 64-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64
+FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a)
+{
+ return (int64_t)vaddlv_u8(vcnt_u8(vcreate_u8(a)));
+}
+
+#endif
diff --git a/thirdparty/embree-aarch64/common/math/affinespace.h b/thirdparty/embree-aarch64/common/math/affinespace.h
new file mode 100644
index 0000000000..32452fbe72
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/affinespace.h
@@ -0,0 +1,361 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "linearspace2.h"
+#include "linearspace3.h"
+#include "quaternion.h"
+#include "bbox.h"
+#include "vec4.h"
+
+namespace embree
+{
+ #define VectorT typename L::Vector
+ #define ScalarT typename L::Vector::Scalar
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Affine Space
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L>
+ struct AffineSpaceT
+ {
+ L l; /*< linear part of affine space */
+ VectorT p; /*< affine part of affine space */
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Constructors, Assignment, Cast, Copy Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline AffineSpaceT ( ) { }
+ __forceinline AffineSpaceT ( const AffineSpaceT& other ) { l = other.l; p = other.p; }
+ __forceinline AffineSpaceT ( const L & other ) { l = other ; p = VectorT(zero); }
+ __forceinline AffineSpaceT& operator=( const AffineSpaceT& other ) { l = other.l; p = other.p; return *this; }
+
+ __forceinline AffineSpaceT( const VectorT& vx, const VectorT& vy, const VectorT& vz, const VectorT& p ) : l(vx,vy,vz), p(p) {}
+ __forceinline AffineSpaceT( const L& l, const VectorT& p ) : l(l), p(p) {}
+
+ template<typename L1> __forceinline AffineSpaceT( const AffineSpaceT<L1>& s ) : l(s.l), p(s.p) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline AffineSpaceT( ZeroTy ) : l(zero), p(zero) {}
+ __forceinline AffineSpaceT( OneTy ) : l(one), p(zero) {}
+
+ /*! return matrix for scaling */
+ static __forceinline AffineSpaceT scale(const VectorT& s) { return L::scale(s); }
+
+ /*! return matrix for translation */
+ static __forceinline AffineSpaceT translate(const VectorT& p) { return AffineSpaceT(one,p); }
+
+ /*! return matrix for rotation, only in 2D */
+ static __forceinline AffineSpaceT rotate(const ScalarT& r) { return L::rotate(r); }
+
+ /*! return matrix for rotation around arbitrary point (2D) or axis (3D) */
+ static __forceinline AffineSpaceT rotate(const VectorT& u, const ScalarT& r) { return L::rotate(u,r); }
+
+ /*! return matrix for rotation around arbitrary axis and point, only in 3D */
+ static __forceinline AffineSpaceT rotate(const VectorT& p, const VectorT& u, const ScalarT& r) { return translate(+p) * rotate(u,r) * translate(-p); }
+
+ /*! return matrix for looking at given point, only in 3D */
+ static __forceinline AffineSpaceT lookat(const VectorT& eye, const VectorT& point, const VectorT& up) {
+ VectorT Z = normalize(point-eye);
+ VectorT U = normalize(cross(up,Z));
+ VectorT V = normalize(cross(Z,U));
+ return AffineSpaceT(L(U,V,Z),eye);
+ }
+
+ };
+
+ // template specialization to get correct identity matrix for type AffineSpace3fa
+ template<>
+ __forceinline AffineSpaceT<LinearSpace3ff>::AffineSpaceT( OneTy ) : l(one), p(0.f, 0.f, 0.f, 1.f) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline AffineSpaceT<L> operator -( const AffineSpaceT<L>& a ) { return AffineSpaceT<L>(-a.l,-a.p); }
+ template<typename L> __forceinline AffineSpaceT<L> operator +( const AffineSpaceT<L>& a ) { return AffineSpaceT<L>(+a.l,+a.p); }
+ template<typename L> __forceinline AffineSpaceT<L> rcp( const AffineSpaceT<L>& a ) { L il = rcp(a.l); return AffineSpaceT<L>(il,-(il*a.p)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline const AffineSpaceT<L> operator +( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l+b.l,a.p+b.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator -( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l-b.l,a.p-b.p); }
+
+ template<typename L> __forceinline const AffineSpaceT<L> operator *( const ScalarT & a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a*b.l,a*b.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator *( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l*b.l,a.l*b.p+a.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator /( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a * rcp(b); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator /( const AffineSpaceT<L>& a, const ScalarT & b ) { return a * rcp(b); }
+
+ template<typename L> __forceinline AffineSpaceT<L>& operator *=( AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a = a * b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator *=( AffineSpaceT<L>& a, const ScalarT & b ) { return a = a * b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator /=( AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a = a / b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator /=( AffineSpaceT<L>& a, const ScalarT & b ) { return a = a / b; }
+
+ template<typename L> __forceinline VectorT xfmPoint (const AffineSpaceT<L>& m, const VectorT& p) { return madd(VectorT(p.x),m.l.vx,madd(VectorT(p.y),m.l.vy,madd(VectorT(p.z),m.l.vz,m.p))); }
+ template<typename L> __forceinline VectorT xfmVector(const AffineSpaceT<L>& m, const VectorT& v) { return xfmVector(m.l,v); }
+ template<typename L> __forceinline VectorT xfmNormal(const AffineSpaceT<L>& m, const VectorT& n) { return xfmNormal(m.l,n); }
+
+ __forceinline const BBox<Vec3fa> xfmBounds(const AffineSpaceT<LinearSpace3<Vec3fa> >& m, const BBox<Vec3fa>& b)
+ {
+ BBox3fa dst = empty;
+ const Vec3fa p0(b.lower.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p0));
+ const Vec3fa p1(b.lower.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p1));
+ const Vec3fa p2(b.lower.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p2));
+ const Vec3fa p3(b.lower.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p3));
+ const Vec3fa p4(b.upper.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p4));
+ const Vec3fa p5(b.upper.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p5));
+ const Vec3fa p6(b.upper.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p6));
+ const Vec3fa p7(b.upper.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p7));
+ return dst;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline bool operator ==( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a.l == b.l && a.p == b.p; }
+ template<typename L> __forceinline bool operator !=( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a.l != b.l || a.p != b.p; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline AffineSpaceT<L> select ( const typename L::Vector::Scalar::Bool& s, const AffineSpaceT<L>& t, const AffineSpaceT<L>& f ) {
+ return AffineSpaceT<L>(select(s,t.l,f.l),select(s,t.p,f.p));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> static embree_ostream operator<<(embree_ostream cout, const AffineSpaceT<L>& m) {
+ return cout << "{ l = " << m.l << ", p = " << m.p << " }";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Template Instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef AffineSpaceT<LinearSpace2f> AffineSpace2f;
+ typedef AffineSpaceT<LinearSpace3f> AffineSpace3f;
+ typedef AffineSpaceT<LinearSpace3fa> AffineSpace3fa;
+ typedef AffineSpaceT<LinearSpace3fx> AffineSpace3fx;
+ typedef AffineSpaceT<LinearSpace3ff> AffineSpace3ff;
+ typedef AffineSpaceT<Quaternion3f > OrthonormalSpace3f;
+
+ template<int N> using AffineSpace3vf = AffineSpaceT<LinearSpace3<Vec3<vfloat<N>>>>;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<4>>>> AffineSpace3vf4;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<8>>>> AffineSpace3vf8;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<16>>>> AffineSpace3vf16;
+
+ template<int N> using AffineSpace3vff = AffineSpaceT<LinearSpace3<Vec4<vfloat<N>>>>;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<4>>>> AffineSpace3vfa4;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<8>>>> AffineSpace3vfa8;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<16>>>> AffineSpace3vfa16;
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Interpolation
+ //////////////////////////////////////////////////////////////////////////////
+ template<typename T, typename R>
+ __forceinline AffineSpaceT<T> lerp(const AffineSpaceT<T>& M0,
+ const AffineSpaceT<T>& M1,
+ const R& t)
+ {
+ return AffineSpaceT<T>(lerp(M0.l,M1.l,t),lerp(M0.p,M1.p,t));
+ }
+
+ // slerp interprets the 16 floats of the matrix M = D * R * S as components of
+ // three matrizes (D, R, S) that are interpolated individually.
+ template<typename T> __forceinline AffineSpaceT<LinearSpace3<Vec3<T>>>
+ slerp(const AffineSpaceT<LinearSpace3<Vec4<T>>>& M0,
+ const AffineSpaceT<LinearSpace3<Vec4<T>>>& M1,
+ const T& t)
+ {
+ QuaternionT<T> q0(M0.p.w, M0.l.vx.w, M0.l.vy.w, M0.l.vz.w);
+ QuaternionT<T> q1(M1.p.w, M1.l.vx.w, M1.l.vy.w, M1.l.vz.w);
+ QuaternionT<T> q = slerp(q0, q1, t);
+
+ AffineSpaceT<LinearSpace3<Vec3<T>>> S = lerp(M0, M1, t);
+ AffineSpaceT<LinearSpace3<Vec3<T>>> D(one);
+ D.p.x = S.l.vx.y;
+ D.p.y = S.l.vx.z;
+ D.p.z = S.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+
+ AffineSpaceT<LinearSpace3<Vec3<T>>> R = LinearSpace3<Vec3<T>>(q);
+ return D * R * S;
+ }
+
+ // this is a specialized version for Vec3fa because that does
+ // not play along nicely with the other templated Vec3/Vec4 types
+ __forceinline AffineSpace3fa slerp(const AffineSpace3ff& M0,
+ const AffineSpace3ff& M1,
+ const float& t)
+ {
+ Quaternion3f q0(M0.p.w, M0.l.vx.w, M0.l.vy.w, M0.l.vz.w);
+ Quaternion3f q1(M1.p.w, M1.l.vx.w, M1.l.vy.w, M1.l.vz.w);
+ Quaternion3f q = slerp(q0, q1, t);
+
+ AffineSpace3fa S = lerp(M0, M1, t);
+ AffineSpace3fa D(one);
+ D.p.x = S.l.vx.y;
+ D.p.y = S.l.vx.z;
+ D.p.z = S.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+
+ AffineSpace3fa R = LinearSpace3fa(q);
+ return D * R * S;
+ }
+
+ __forceinline AffineSpace3fa quaternionDecompositionToAffineSpace(const AffineSpace3ff& qd)
+ {
+ // compute affine transform from quaternion decomposition
+ Quaternion3f q(qd.p.w, qd.l.vx.w, qd.l.vy.w, qd.l.vz.w);
+ AffineSpace3fa M = qd;
+ AffineSpace3fa D(one);
+ D.p.x = M.l.vx.y;
+ D.p.y = M.l.vx.z;
+ D.p.z = M.l.vy.z;
+ M.l.vx.y = 0;
+ M.l.vx.z = 0;
+ M.l.vy.z = 0;
+ AffineSpace3fa R = LinearSpace3fa(q);
+ return D * R * M;
+ }
+
+ __forceinline void quaternionDecomposition(const AffineSpace3ff& qd, Vec3fa& T, Quaternion3f& q, AffineSpace3fa& S)
+ {
+ q = Quaternion3f(qd.p.w, qd.l.vx.w, qd.l.vy.w, qd.l.vz.w);
+ S = qd;
+ T.x = qd.l.vx.y;
+ T.y = qd.l.vx.z;
+ T.z = qd.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+ }
+
+ __forceinline AffineSpace3fx quaternionDecomposition(Vec3fa const& T, Quaternion3f const& q, AffineSpace3fa const& S)
+ {
+ AffineSpace3ff M = S;
+ M.l.vx.w = q.i;
+ M.l.vy.w = q.j;
+ M.l.vz.w = q.k;
+ M.p.w = q.r;
+ M.l.vx.y = T.x;
+ M.l.vx.z = T.y;
+ M.l.vy.z = T.z;
+ return M;
+ }
+
+ struct __aligned(16) QuaternionDecomposition
+ {
+ float scale_x = 1.f;
+ float scale_y = 1.f;
+ float scale_z = 1.f;
+ float skew_xy = 0.f;
+ float skew_xz = 0.f;
+ float skew_yz = 0.f;
+ float shift_x = 0.f;
+ float shift_y = 0.f;
+ float shift_z = 0.f;
+ float quaternion_r = 1.f;
+ float quaternion_i = 0.f;
+ float quaternion_j = 0.f;
+ float quaternion_k = 0.f;
+ float translation_x = 0.f;
+ float translation_y = 0.f;
+ float translation_z = 0.f;
+ };
+
+ __forceinline QuaternionDecomposition quaternionDecomposition(AffineSpace3ff const& M)
+ {
+ QuaternionDecomposition qd;
+ qd.scale_x = M.l.vx.x;
+ qd.scale_y = M.l.vy.y;
+ qd.scale_z = M.l.vz.z;
+ qd.shift_x = M.p.x;
+ qd.shift_y = M.p.y;
+ qd.shift_z = M.p.z;
+ qd.translation_x = M.l.vx.y;
+ qd.translation_y = M.l.vx.z;
+ qd.translation_z = M.l.vy.z;
+ qd.skew_xy = M.l.vy.x;
+ qd.skew_xz = M.l.vz.x;
+ qd.skew_yz = M.l.vz.y;
+ qd.quaternion_r = M.p.w;
+ qd.quaternion_i = M.l.vx.w;
+ qd.quaternion_j = M.l.vy.w;
+ qd.quaternion_k = M.l.vz.w;
+ return qd;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /*
+ * ! Template Specialization for 2D: return matrix for rotation around point
+ * (rotation around arbitrarty vector is not meaningful in 2D)
+ */
+ template<> __forceinline
+ AffineSpace2f AffineSpace2f::rotate(const Vec2f& p, const float& r) {
+ return translate(+p)*AffineSpace2f(LinearSpace2f::rotate(r))*translate(-p);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Similarity Transform
+ //
+ // checks, if M is a similarity transformation, i.e if there exists a factor D
+ // such that for all x,y: distance(Mx, My) = D * distance(x, y)
+ ////////////////////////////////////////////////////////////////////////////////
+ __forceinline bool similarityTransform(const AffineSpace3fa& M, float* D)
+ {
+ if (D) *D = 0.f;
+ if (abs(dot(M.l.vx, M.l.vy)) > 1e-5f) return false;
+ if (abs(dot(M.l.vx, M.l.vz)) > 1e-5f) return false;
+ if (abs(dot(M.l.vy, M.l.vz)) > 1e-5f) return false;
+
+ const float D_x = dot(M.l.vx, M.l.vx);
+ const float D_y = dot(M.l.vy, M.l.vy);
+ const float D_z = dot(M.l.vz, M.l.vz);
+
+ if (abs(D_x - D_y) > 1e-5f ||
+ abs(D_x - D_z) > 1e-5f ||
+ abs(D_y - D_z) > 1e-5f)
+ return false;
+
+ if (D) *D = sqrtf(D_x);
+ return true;
+ }
+
+ __forceinline void AffineSpace3fa_store_unaligned(const AffineSpace3fa &source, AffineSpace3fa* ptr)
+ {
+ Vec3fa::storeu(&ptr->l.vx, source.l.vx);
+ Vec3fa::storeu(&ptr->l.vy, source.l.vy);
+ Vec3fa::storeu(&ptr->l.vz, source.l.vz);
+ Vec3fa::storeu(&ptr->p, source.p);
+ }
+
+ __forceinline AffineSpace3fa AffineSpace3fa_load_unaligned(AffineSpace3fa* ptr)
+ {
+ AffineSpace3fa space;
+ space.l.vx = Vec3fa::loadu(&ptr->l.vx);
+ space.l.vy = Vec3fa::loadu(&ptr->l.vy);
+ space.l.vz = Vec3fa::loadu(&ptr->l.vz);
+ space.p = Vec3fa::loadu(&ptr->p);
+ return space;
+ }
+
+ #undef VectorT
+ #undef ScalarT
+}
diff --git a/thirdparty/embree-aarch64/common/math/bbox.h b/thirdparty/embree-aarch64/common/math/bbox.h
new file mode 100644
index 0000000000..29bb13912b
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/bbox.h
@@ -0,0 +1,331 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+#include "vec3.h"
+
+namespace embree
+{
+ namespace internal {
+
+ template <typename T> __forceinline T divideByTwo(const T& v) { return v / T(2); }
+ template <> __forceinline float divideByTwo<float>(const float& v) { return v * 0.5f; }
+ template <> __forceinline double divideByTwo<double>(const double& v) { return v * 0.5; }
+
+ } // namespace internal
+ template<typename T>
+ struct BBox
+ {
+ T lower, upper;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline BBox ( ) { }
+ template<typename T1>
+ __forceinline BBox ( const BBox<T1>& other ) : lower(other.lower), upper(other.upper) {}
+ __forceinline BBox& operator=( const BBox& other ) { lower = other.lower; upper = other.upper; return *this; }
+
+ __forceinline BBox ( const T& v ) : lower(v), upper(v) {}
+ __forceinline BBox ( const T& lower, const T& upper ) : lower(lower), upper(upper) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Extending Bounds
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const BBox& extend(const BBox& other) { lower = min(lower,other.lower); upper = max(upper,other.upper); return *this; }
+ __forceinline const BBox& extend(const T & other) { lower = min(lower,other ); upper = max(upper,other ); return *this; }
+
+ /*! tests if box is empty */
+ __forceinline bool empty() const { for (int i=0; i<T::N; i++) if (lower[i] > upper[i]) return true; return false; }
+
+ /*! computes the size of the box */
+ __forceinline T size() const { return upper - lower; }
+
+ /*! computes the center of the box */
+ __forceinline T center() const { return internal::divideByTwo<T>(lower+upper); }
+
+ /*! computes twice the center of the box */
+ __forceinline T center2() const { return lower+upper; }
+
+ /*! merges two boxes */
+ __forceinline static const BBox merge (const BBox& a, const BBox& b) {
+ return BBox(min(a.lower, b.lower), max(a.upper, b.upper));
+ }
+
+ /*! enlarge box by some scaling factor */
+ __forceinline BBox enlarge_by(const float a) const {
+ return BBox(lower - T(a)*abs(lower), upper + T(a)*abs(upper));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline BBox( EmptyTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( FullTy ) : lower(neg_inf), upper(pos_inf) {}
+ __forceinline BBox( FalseTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( TrueTy ) : lower(neg_inf), upper(pos_inf) {}
+ __forceinline BBox( NegInfTy ): lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( PosInfTy ): lower(neg_inf), upper(pos_inf) {}
+ };
+
+ template<> __forceinline bool BBox<float>::empty() const {
+ return lower > upper;
+ }
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ template<> __forceinline bool BBox<Vec3fa>::empty() const {
+ return !all(le_mask(lower,upper));
+ }
+ template<> __forceinline bool BBox<Vec3fx>::empty() const {
+ return !all(le_mask(lower,upper));
+ }
+#endif
+
+ /*! tests if box is finite */
+ __forceinline bool isvalid( const BBox<Vec3fa>& v ) {
+ return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)));
+ }
+
+ /*! tests if box is finite and non-empty*/
+ __forceinline bool isvalid_non_empty( const BBox<Vec3fa>& v ) {
+ return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)) & le_mask(v.lower,v.upper));
+ }
+
+ /*! tests if box has finite entries */
+ __forceinline bool is_finite( const BBox<Vec3fa>& b) {
+ return is_finite(b.lower) && is_finite(b.upper);
+ }
+
+ /*! test if point contained in box */
+ __forceinline bool inside ( const BBox<Vec3fa>& b, const Vec3fa& p ) { return all(ge_mask(p,b.lower) & le_mask(p,b.upper)); }
+
+ /*! computes the center of the box */
+ template<typename T> __forceinline const T center2(const BBox<T>& box) { return box.lower + box.upper; }
+ template<typename T> __forceinline const T center (const BBox<T>& box) { return internal::divideByTwo<T>(center2(box)); }
+
+ /*! computes the volume of a bounding box */
+ __forceinline float volume ( const BBox<Vec3fa>& b ) { return reduce_mul(b.size()); }
+ __forceinline float safeVolume( const BBox<Vec3fa>& b ) { if (b.empty()) return 0.0f; else return volume(b); }
+
+ /*! computes the volume of a bounding box */
+ __forceinline float volume( const BBox<Vec3f>& b ) { return reduce_mul(b.size()); }
+
+ /*! computes the surface area of a bounding box */
+ template<typename T> __forceinline const T area( const BBox<Vec2<T> >& b ) { const Vec2<T> d = b.size(); return d.x*d.y; }
+
+ template<typename T> __forceinline const T halfArea( const BBox<Vec3<T> >& b ) { return halfArea(b.size()); }
+ template<typename T> __forceinline const T area( const BBox<Vec3<T> >& b ) { return T(2)*halfArea(b); }
+
+ __forceinline float halfArea( const BBox<Vec3fa>& b ) { return halfArea(b.size()); }
+ __forceinline float area( const BBox<Vec3fa>& b ) { return 2.0f*halfArea(b); }
+
+ __forceinline float halfArea( const BBox<Vec3fx>& b ) { return halfArea(b.size()); }
+ __forceinline float area( const BBox<Vec3fx>& b ) { return 2.0f*halfArea(b); }
+
+ template<typename Vec> __forceinline float safeArea( const BBox<Vec>& b ) { if (b.empty()) return 0.0f; else return area(b); }
+
+ template<typename T> __forceinline float expectedApproxHalfArea(const BBox<T>& box) {
+ return halfArea(box);
+ }
+
+ /*! merges bounding boxes and points */
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const T& b ) { return BBox<T>(min(a.lower, b ), max(a.upper, b )); }
+ template<typename T> __forceinline const BBox<T> merge( const T& a, const BBox<T>& b ) { return BBox<T>(min(a , b.lower), max(a , b.upper)); }
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(min(a.lower, b.lower), max(a.upper, b.upper)); }
+
+ /*! Merges three boxes. */
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return merge(a,merge(b,c)); }
+
+ /*! Merges four boxes. */
+ template<typename T> __forceinline BBox<T> merge(const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d) {
+ return merge(merge(a,b),merge(c,d));
+ }
+
+ /*! Comparison Operators */
+ template<typename T> __forceinline bool operator==( const BBox<T>& a, const BBox<T>& b ) { return a.lower == b.lower && a.upper == b.upper; }
+ template<typename T> __forceinline bool operator!=( const BBox<T>& a, const BBox<T>& b ) { return a.lower != b.lower || a.upper != b.upper; }
+
+ /*! scaling */
+ template<typename T> __forceinline BBox<T> operator *( const float& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
+ template<typename T> __forceinline BBox<T> operator *( const T& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
+
+ /*! translations */
+ template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower+b.lower,a.upper+b.upper); }
+ template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower-b.lower,a.upper-b.upper); }
+ template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower+b ,a.upper+b ); }
+ template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower-b ,a.upper-b ); }
+
+ /*! extension */
+ template<typename T> __forceinline BBox<T> enlarge(const BBox<T>& a, const T& b) { return BBox<T>(a.lower-b, a.upper+b); }
+
+ /*! intersect bounding boxes */
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(max(a.lower, b.lower), min(a.upper, b.upper)); }
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return intersect(a,intersect(b,c)); }
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d ) { return intersect(intersect(a,b),intersect(c,d)); }
+
+ /*! subtract bounds from each other */
+ template<typename T> __forceinline void subtract(const BBox<T>& a, const BBox<T>& b, BBox<T>& c, BBox<T>& d)
+ {
+ c.lower = a.lower;
+ c.upper = min(a.upper,b.lower);
+ d.lower = max(a.lower,b.upper);
+ d.upper = a.upper;
+ }
+
+ /*! tests if bounding boxes (and points) are disjoint (empty intersection) */
+ template<typename T> __inline bool disjoint( const BBox<T>& a, const BBox<T>& b ) { return intersect(a,b).empty(); }
+ template<typename T> __inline bool disjoint( const BBox<T>& a, const T& b ) { return disjoint(a,BBox<T>(b)); }
+ template<typename T> __inline bool disjoint( const T& a, const BBox<T>& b ) { return disjoint(BBox<T>(a),b); }
+
+ /*! tests if bounding boxes (and points) are conjoint (non-empty intersection) */
+ template<typename T> __inline bool conjoint( const BBox<T>& a, const BBox<T>& b ) { return !intersect(a,b).empty(); }
+ template<typename T> __inline bool conjoint( const BBox<T>& a, const T& b ) { return conjoint(a,BBox<T>(b)); }
+ template<typename T> __inline bool conjoint( const T& a, const BBox<T>& b ) { return conjoint(BBox<T>(a),b); }
+
+ /*! subset relation */
+ template<typename T> __inline bool subset( const BBox<T>& a, const BBox<T>& b )
+ {
+ for ( size_t i = 0; i < T::N; i++ ) if ( a.lower[i] < b.lower[i] ) return false;
+ for ( size_t i = 0; i < T::N; i++ ) if ( a.upper[i] > b.upper[i] ) return false;
+ return true;
+ }
+
+ template<> __inline bool subset( const BBox<Vec3fa>& a, const BBox<Vec3fa>& b ) {
+ return all(ge_mask(a.lower,b.lower)) & all(le_mask(a.upper,b.upper));
+ }
+
+ template<> __inline bool subset( const BBox<Vec3fx>& a, const BBox<Vec3fx>& b ) {
+ return all(ge_mask(a.lower,b.lower)) & all(le_mask(a.upper,b.upper));
+ }
+
+ /*! blending */
+ template<typename T>
+ __forceinline BBox<T> lerp(const BBox<T>& b0, const BBox<T>& b1, const float t) {
+ return BBox<T>(lerp(b0.lower,b1.lower,t),lerp(b0.upper,b1.upper,t));
+ }
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const BBox<T>& box) {
+ return cout << "[" << box.lower << "; " << box.upper << "]";
+ }
+
+ /*! default template instantiations */
+ typedef BBox<float> BBox1f;
+ typedef BBox<Vec2f> BBox2f;
+ typedef BBox<Vec2fa> BBox2fa;
+ typedef BBox<Vec3f> BBox3f;
+ typedef BBox<Vec3fa> BBox3fa;
+ typedef BBox<Vec3fx> BBox3fx;
+ typedef BBox<Vec3ff> BBox3ff;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__SSE__) || defined(__ARM_NEON)
+#include "../simd/sse.h"
+#endif
+
+#if defined (__AVX__)
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<int N>
+ __forceinline BBox<Vec3<vfloat<N>>> transpose(const BBox3fa* bounds);
+
+ template<>
+ __forceinline BBox<Vec3<vfloat4>> transpose<4>(const BBox3fa* bounds)
+ {
+ BBox<Vec3<vfloat4>> dest;
+
+ transpose((vfloat4&)bounds[0].lower,
+ (vfloat4&)bounds[1].lower,
+ (vfloat4&)bounds[2].lower,
+ (vfloat4&)bounds[3].lower,
+ dest.lower.x,
+ dest.lower.y,
+ dest.lower.z);
+
+ transpose((vfloat4&)bounds[0].upper,
+ (vfloat4&)bounds[1].upper,
+ (vfloat4&)bounds[2].upper,
+ (vfloat4&)bounds[3].upper,
+ dest.upper.x,
+ dest.upper.y,
+ dest.upper.z);
+
+ return dest;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline BBox<Vec3<vfloat8>> transpose<8>(const BBox3fa* bounds)
+ {
+ BBox<Vec3<vfloat8>> dest;
+
+ transpose((vfloat4&)bounds[0].lower,
+ (vfloat4&)bounds[1].lower,
+ (vfloat4&)bounds[2].lower,
+ (vfloat4&)bounds[3].lower,
+ (vfloat4&)bounds[4].lower,
+ (vfloat4&)bounds[5].lower,
+ (vfloat4&)bounds[6].lower,
+ (vfloat4&)bounds[7].lower,
+ dest.lower.x,
+ dest.lower.y,
+ dest.lower.z);
+
+ transpose((vfloat4&)bounds[0].upper,
+ (vfloat4&)bounds[1].upper,
+ (vfloat4&)bounds[2].upper,
+ (vfloat4&)bounds[3].upper,
+ (vfloat4&)bounds[4].upper,
+ (vfloat4&)bounds[5].upper,
+ (vfloat4&)bounds[6].upper,
+ (vfloat4&)bounds[7].upper,
+ dest.upper.x,
+ dest.upper.y,
+ dest.upper.z);
+
+ return dest;
+ }
+#endif
+
+ template<int N>
+ __forceinline BBox3fa merge(const BBox3fa* bounds);
+
+ template<>
+ __forceinline BBox3fa merge<4>(const BBox3fa* bounds)
+ {
+ const Vec3fa lower = min(min(bounds[0].lower,bounds[1].lower),
+ min(bounds[2].lower,bounds[3].lower));
+ const Vec3fa upper = max(max(bounds[0].upper,bounds[1].upper),
+ max(bounds[2].upper,bounds[3].upper));
+ return BBox3fa(lower,upper);
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline BBox3fa merge<8>(const BBox3fa* bounds)
+ {
+ const Vec3fa lower = min(min(min(bounds[0].lower,bounds[1].lower),min(bounds[2].lower,bounds[3].lower)),
+ min(min(bounds[4].lower,bounds[5].lower),min(bounds[6].lower,bounds[7].lower)));
+ const Vec3fa upper = max(max(max(bounds[0].upper,bounds[1].upper),max(bounds[2].upper,bounds[3].upper)),
+ max(max(bounds[4].upper,bounds[5].upper),max(bounds[6].upper,bounds[7].upper)));
+ return BBox3fa(lower,upper);
+ }
+#endif
+}
+
diff --git a/thirdparty/embree-aarch64/common/math/col3.h b/thirdparty/embree-aarch64/common/math/col3.h
new file mode 100644
index 0000000000..f52015fb88
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/col3.h
@@ -0,0 +1,47 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// RGB Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Col3
+ {
+ T r, g, b;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col3 ( ) { }
+ __forceinline Col3 ( const Col3& other ) { r = other.r; g = other.g; b = other.b; }
+ __forceinline Col3& operator=( const Col3& other ) { r = other.r; g = other.g; b = other.b; return *this; }
+
+ __forceinline explicit Col3 (const T& v) : r(v), g(v), b(v) {}
+ __forceinline Col3 (const T& r, const T& g, const T& b) : r(r), g(g), b(b) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col3 (ZeroTy) : r(zero) , g(zero) , b(zero) {}
+ __forceinline Col3 (OneTy) : r(one) , g(one) , b(one) {}
+ __forceinline Col3 (PosInfTy) : r(pos_inf), g(pos_inf), b(pos_inf) {}
+ __forceinline Col3 (NegInfTy) : r(neg_inf), g(neg_inf), b(neg_inf) {}
+ };
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Col3<T>& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")";
+ }
+
+ /*! default template instantiations */
+ typedef Col3<uint8_t > Col3uc;
+ typedef Col3<float > Col3f;
+}
diff --git a/thirdparty/embree-aarch64/common/math/col4.h b/thirdparty/embree-aarch64/common/math/col4.h
new file mode 100644
index 0000000000..90df293f8e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/col4.h
@@ -0,0 +1,47 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// RGBA Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Col4
+ {
+ T r, g, b, a;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col4 ( ) { }
+ __forceinline Col4 ( const Col4& other ) { r = other.r; g = other.g; b = other.b; a = other.a; }
+ __forceinline Col4& operator=( const Col4& other ) { r = other.r; g = other.g; b = other.b; a = other.a; return *this; }
+
+ __forceinline explicit Col4 (const T& v) : r(v), g(v), b(v), a(v) {}
+ __forceinline Col4 (const T& r, const T& g, const T& b, const T& a) : r(r), g(g), b(b), a(a) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col4 (ZeroTy) : r(zero) , g(zero) , b(zero) , a(zero) {}
+ __forceinline Col4 (OneTy) : r(one) , g(one) , b(one) , a(one) {}
+ __forceinline Col4 (PosInfTy) : r(pos_inf), g(pos_inf), b(pos_inf), a(pos_inf) {}
+ __forceinline Col4 (NegInfTy) : r(neg_inf), g(neg_inf), b(neg_inf), a(neg_inf) {}
+ };
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Col4<T>& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ", " << a.a << ")";
+ }
+
+ /*! default template instantiations */
+ typedef Col4<uint8_t > Col4uc;
+ typedef Col4<float > Col4f;
+}
diff --git a/thirdparty/embree-aarch64/common/math/color.h b/thirdparty/embree-aarch64/common/math/color.h
new file mode 100644
index 0000000000..c3083e4fc0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/color.h
@@ -0,0 +1,257 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "constants.h"
+#include "col3.h"
+#include "col4.h"
+
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE RGBA Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct Color4
+ {
+ union {
+ __m128 m128;
+ struct { float r,g,b,a; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color4 () {}
+ __forceinline Color4 ( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Color4 (const float v) : m128(_mm_set1_ps(v)) {}
+ __forceinline Color4 (const float r, const float g, const float b, const float a) : m128(_mm_set_ps(a,b,g,r)) {}
+
+ __forceinline explicit Color4 ( const Col3uc& other ) { m128 = _mm_mul_ps(_mm_set_ps(255.0f,other.b,other.g,other.r),_mm_set1_ps(one_over_255)); }
+ __forceinline explicit Color4 ( const Col3f& other ) { m128 = _mm_set_ps(1.0f,other.b,other.g,other.r); }
+ __forceinline explicit Color4 ( const Col4uc& other ) { m128 = _mm_mul_ps(_mm_set_ps(other.a,other.b,other.g,other.r),_mm_set1_ps(one_over_255)); }
+ __forceinline explicit Color4 ( const Col4f& other ) { m128 = _mm_set_ps(other.a,other.b,other.g,other.r); }
+
+ __forceinline Color4 ( const Color4& other ) : m128(other.m128) {}
+ __forceinline Color4& operator=( const Color4& other ) { m128 = other.m128; return *this; }
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Set
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; }
+ __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = a; }
+ __forceinline void set(Col3uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (uint8_t)(s[0]);
+ d.g = (uint8_t)(s[1]);
+ d.b = (uint8_t)(s[2]);
+ }
+ __forceinline void set(Col4uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (uint8_t)(s[0]);
+ d.g = (uint8_t)(s[1]);
+ d.b = (uint8_t)(s[2]);
+ d.a = (uint8_t)(s[3]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color4( ZeroTy ) : m128(_mm_set1_ps(0.0f)) {}
+ __forceinline Color4( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Color4( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Color4( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE RGB Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct Color
+ {
+ union {
+ __m128 m128;
+ struct { float r,g,b; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color () {}
+ __forceinline Color ( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Color (const float v) : m128(_mm_set1_ps(v)) {}
+ __forceinline Color (const float r, const float g, const float b) : m128(_mm_set_ps(0.0f,b,g,r)) {}
+
+ __forceinline Color ( const Color& other ) : m128(other.m128) {}
+ __forceinline Color& operator=( const Color& other ) { m128 = other.m128; return *this; }
+
+ __forceinline Color ( const Color4& other ) : m128(other.m128) {}
+ __forceinline Color& operator=( const Color4& other ) { m128 = other.m128; return *this; }
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Set
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; }
+ __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = 1.0f; }
+ __forceinline void set(Col3uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (uint8_t)(s[0]);
+ d.g = (uint8_t)(s[1]);
+ d.b = (uint8_t)(s[2]);
+ }
+ __forceinline void set(Col4uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (uint8_t)(s[0]);
+ d.g = (uint8_t)(s[1]);
+ d.b = (uint8_t)(s[2]);
+ d.a = 255;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color( ZeroTy ) : m128(_mm_set1_ps(0.0f)) {}
+ __forceinline Color( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Color( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Color( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator +( const Color& a ) { return a; }
+ __forceinline const Color operator -( const Color& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline const Color abs ( const Color& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline const Color rcp ( const Color& a )
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ __m128 reciprocal = _mm_rcp_ps(a.m128);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ return (const Color)reciprocal;
+#else
+#if defined(__AVX512VL__)
+ const Color r = _mm_rcp14_ps(a.m128);
+#else
+ const Color r = _mm_rcp_ps(a.m128);
+#endif
+ return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif //defined(__aarch64__) && defined(BUILD_IOS)
+ }
+ __forceinline const Color rsqrt( const Color& a )
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ __m128 r = _mm_rsqrt_ps(a.m128);
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ return r;
+#else
+
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+
+#endif //defined(__aarch64__) && defined(BUILD_IOS)
+ }
+ __forceinline const Color sqrt ( const Color& a ) { return _mm_sqrt_ps(a.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator +( const Color& a, const Color& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline const Color operator -( const Color& a, const Color& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline const Color operator *( const Color& a, const Color& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline const Color operator *( const Color& a, const float b ) { return a * Color(b); }
+ __forceinline const Color operator *( const float a, const Color& b ) { return Color(a) * b; }
+ __forceinline const Color operator /( const Color& a, const Color& b ) { return a * rcp(b); }
+ __forceinline const Color operator /( const Color& a, const float b ) { return a * rcp(b); }
+
+ __forceinline const Color min( const Color& a, const Color& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline const Color max( const Color& a, const Color& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator+=(Color& a, const Color& b) { return a = a + b; }
+ __forceinline const Color operator-=(Color& a, const Color& b) { return a = a - b; }
+ __forceinline const Color operator*=(Color& a, const Color& b) { return a = a * b; }
+ __forceinline const Color operator/=(Color& a, const Color& b) { return a = a / b; }
+ __forceinline const Color operator*=(Color& a, const float b ) { return a = a * b; }
+ __forceinline const Color operator/=(Color& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Color& v) { return v.r+v.g+v.b; }
+ __forceinline float reduce_mul(const Color& v) { return v.r*v.g*v.b; }
+ __forceinline float reduce_min(const Color& v) { return min(v.r,v.g,v.b); }
+ __forceinline float reduce_max(const Color& v) { return max(v.r,v.g,v.b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Color& a, const Color& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Color& a, const Color& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+ __forceinline bool operator < ( const Color& a, const Color& b ) {
+ if (a.r != b.r) return a.r < b.r;
+ if (a.g != b.g) return a.g < b.g;
+ if (a.b != b.b) return a.b < b.b;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color select( bool s, const Color& t, const Color& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Special Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /*! computes luminance of a color */
+ __forceinline float luminance (const Color& a) { return madd(0.212671f,a.r,madd(0.715160f,a.g,0.072169f*a.b)); }
+
+ /*! output operator */
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Color& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/math/constants.cpp b/thirdparty/embree-aarch64/common/math/constants.cpp
new file mode 100644
index 0000000000..eeff131664
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/constants.cpp
@@ -0,0 +1,61 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#if defined(__aarch64__)
+#include <arm_neon.h>
+#endif
+
+#include "constants.h"
+
+namespace embree
+{
+ TrueTy True;
+ FalseTy False;
+ ZeroTy zero;
+ OneTy one;
+ NegInfTy neg_inf;
+ PosInfTy inf;
+ PosInfTy pos_inf;
+ NaNTy nan;
+ UlpTy ulp;
+ PiTy pi;
+ OneOverPiTy one_over_pi;
+ TwoPiTy two_pi;
+ OneOverTwoPiTy one_over_two_pi;
+ FourPiTy four_pi;
+ OneOverFourPiTy one_over_four_pi;
+ StepTy step;
+ ReverseStepTy reverse_step;
+ EmptyTy empty;
+ UndefinedTy undefined;
+
+#if defined(__aarch64__)
+const uint32x4_t movemask_mask = { 1, 2, 4, 8 };
+const uint32x4_t vzero = { 0, 0, 0, 0 };
+const uint32x4_t v0x80000000 = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+const uint32x4_t v0x7fffffff = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff };
+const uint32x4_t v000F = { 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF };
+const uint32x4_t v00F0 = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000 };
+const uint32x4_t v00FF = { 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+const uint32x4_t v0F00 = { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+const uint32x4_t v0F0F = { 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
+const uint32x4_t v0FF0 = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+const uint32x4_t v0FFF = { 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+const uint32x4_t vF000 = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 };
+const uint32x4_t vF00F = { 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF };
+const uint32x4_t vF0F0 = { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000 };
+const uint32x4_t vF0FF = { 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF };
+const uint32x4_t vFF00 = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000 };
+const uint32x4_t vFF0F = { 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF };
+const uint32x4_t vFFF0 = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+const uint32x4_t vFFFF = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+const uint8x16_t v0022 = {0,1,2,3, 0,1,2,3, 8,9,10,11, 8,9,10,11};
+const uint8x16_t v1133 = {4,5,6,7, 4,5,6,7, 12,13,14,15, 12,13,14,15};
+const uint8x16_t v0101 = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7};
+const float32x4_t vOne = { 1.0f, 1.0f, 1.0f, 1.0f };
+const float32x4_t vmOne = { -1.0f, -1.0f, -1.0f, -1.0f };
+const float32x4_t vInf = { INFINITY, INFINITY, INFINITY, INFINITY };
+const float32x4_t vmInf = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
+#endif
+
+}
diff --git a/thirdparty/embree-aarch64/common/math/constants.h b/thirdparty/embree-aarch64/common/math/constants.h
new file mode 100644
index 0000000000..e80abec80f
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/constants.h
@@ -0,0 +1,239 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+
+#include <limits>
+
+#define _USE_MATH_DEFINES
+#include <math.h> // using cmath causes issues under Windows
+#include <cfloat>
+#include <climits>
+
+// Math constants may not be defined in libcxx + mingw + strict C++ standard
+#if defined(__MINGW32__)
+
+// TODO(LTE): use constexpr
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_1_PI
+#define M_1_PI 0.31830988618379067154
+#endif
+
+#endif // __MINGW32__
+
+namespace embree
+{
+ static MAYBE_UNUSED const float one_over_255 = 1.0f/255.0f;
+ static MAYBE_UNUSED const float min_rcp_input = 1E-18f; // for abs(x) >= min_rcp_input the newton raphson rcp calculation does not fail
+
+ /* we consider floating point numbers in that range as valid input numbers */
+ static MAYBE_UNUSED float FLT_LARGE = 1.844E18f;
+
+ struct TrueTy {
+ __forceinline operator bool( ) const { return true; }
+ };
+
+ extern MAYBE_UNUSED TrueTy True;
+
+ struct FalseTy {
+ __forceinline operator bool( ) const { return false; }
+ };
+
+ extern MAYBE_UNUSED FalseTy False;
+
+ struct ZeroTy
+ {
+ __forceinline operator double ( ) const { return 0; }
+ __forceinline operator float ( ) const { return 0; }
+ __forceinline operator long long( ) const { return 0; }
+ __forceinline operator unsigned long long( ) const { return 0; }
+ __forceinline operator long ( ) const { return 0; }
+ __forceinline operator unsigned long ( ) const { return 0; }
+ __forceinline operator int ( ) const { return 0; }
+ __forceinline operator unsigned int ( ) const { return 0; }
+ __forceinline operator short ( ) const { return 0; }
+ __forceinline operator unsigned short ( ) const { return 0; }
+ __forceinline operator int8_t ( ) const { return 0; }
+ __forceinline operator uint8_t ( ) const { return 0; }
+ };
+
+ extern MAYBE_UNUSED ZeroTy zero;
+
+ struct OneTy
+ {
+ __forceinline operator double ( ) const { return 1; }
+ __forceinline operator float ( ) const { return 1; }
+ __forceinline operator long long( ) const { return 1; }
+ __forceinline operator unsigned long long( ) const { return 1; }
+ __forceinline operator long ( ) const { return 1; }
+ __forceinline operator unsigned long ( ) const { return 1; }
+ __forceinline operator int ( ) const { return 1; }
+ __forceinline operator unsigned int ( ) const { return 1; }
+ __forceinline operator short ( ) const { return 1; }
+ __forceinline operator unsigned short ( ) const { return 1; }
+ __forceinline operator int8_t ( ) const { return 1; }
+ __forceinline operator uint8_t ( ) const { return 1; }
+ };
+
+ extern MAYBE_UNUSED OneTy one;
+
+ struct NegInfTy
+ {
+ __forceinline operator double ( ) const { return -std::numeric_limits<double>::infinity(); }
+ __forceinline operator float ( ) const { return -std::numeric_limits<float>::infinity(); }
+ __forceinline operator long long( ) const { return std::numeric_limits<long long>::min(); }
+ __forceinline operator unsigned long long( ) const { return std::numeric_limits<unsigned long long>::min(); }
+ __forceinline operator long ( ) const { return std::numeric_limits<long>::min(); }
+ __forceinline operator unsigned long ( ) const { return std::numeric_limits<unsigned long>::min(); }
+ __forceinline operator int ( ) const { return std::numeric_limits<int>::min(); }
+ __forceinline operator unsigned int ( ) const { return std::numeric_limits<unsigned int>::min(); }
+ __forceinline operator short ( ) const { return std::numeric_limits<short>::min(); }
+ __forceinline operator unsigned short ( ) const { return std::numeric_limits<unsigned short>::min(); }
+ __forceinline operator int8_t ( ) const { return std::numeric_limits<int8_t>::min(); }
+ __forceinline operator uint8_t ( ) const { return std::numeric_limits<uint8_t>::min(); }
+
+ };
+
+ extern MAYBE_UNUSED NegInfTy neg_inf;
+
+ struct PosInfTy
+ {
+ __forceinline operator double ( ) const { return std::numeric_limits<double>::infinity(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::infinity(); }
+ __forceinline operator long long( ) const { return std::numeric_limits<long long>::max(); }
+ __forceinline operator unsigned long long( ) const { return std::numeric_limits<unsigned long long>::max(); }
+ __forceinline operator long ( ) const { return std::numeric_limits<long>::max(); }
+ __forceinline operator unsigned long ( ) const { return std::numeric_limits<unsigned long>::max(); }
+ __forceinline operator int ( ) const { return std::numeric_limits<int>::max(); }
+ __forceinline operator unsigned int ( ) const { return std::numeric_limits<unsigned int>::max(); }
+ __forceinline operator short ( ) const { return std::numeric_limits<short>::max(); }
+ __forceinline operator unsigned short ( ) const { return std::numeric_limits<unsigned short>::max(); }
+ __forceinline operator int8_t ( ) const { return std::numeric_limits<int8_t>::max(); }
+ __forceinline operator uint8_t ( ) const { return std::numeric_limits<uint8_t>::max(); }
+ };
+
+ extern MAYBE_UNUSED PosInfTy inf;
+ extern MAYBE_UNUSED PosInfTy pos_inf;
+
+ struct NaNTy
+ {
+ __forceinline operator double( ) const { return std::numeric_limits<double>::quiet_NaN(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::quiet_NaN(); }
+ };
+
+ extern MAYBE_UNUSED NaNTy nan;
+
+ struct UlpTy
+ {
+ __forceinline operator double( ) const { return std::numeric_limits<double>::epsilon(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::epsilon(); }
+ };
+
+ extern MAYBE_UNUSED UlpTy ulp;
+
+ struct PiTy
+ {
+ __forceinline operator double( ) const { return double(M_PI); }
+ __forceinline operator float ( ) const { return float(M_PI); }
+ };
+
+ extern MAYBE_UNUSED PiTy pi;
+
+ struct OneOverPiTy
+ {
+ __forceinline operator double( ) const { return double(M_1_PI); }
+ __forceinline operator float ( ) const { return float(M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverPiTy one_over_pi;
+
+ struct TwoPiTy
+ {
+ __forceinline operator double( ) const { return double(2.0*M_PI); }
+ __forceinline operator float ( ) const { return float(2.0*M_PI); }
+ };
+
+ extern MAYBE_UNUSED TwoPiTy two_pi;
+
+ struct OneOverTwoPiTy
+ {
+ __forceinline operator double( ) const { return double(0.5*M_1_PI); }
+ __forceinline operator float ( ) const { return float(0.5*M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverTwoPiTy one_over_two_pi;
+
+ struct FourPiTy
+ {
+ __forceinline operator double( ) const { return double(4.0*M_PI); }
+ __forceinline operator float ( ) const { return float(4.0*M_PI); }
+ };
+
+ extern MAYBE_UNUSED FourPiTy four_pi;
+
+ struct OneOverFourPiTy
+ {
+ __forceinline operator double( ) const { return double(0.25*M_1_PI); }
+ __forceinline operator float ( ) const { return float(0.25*M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverFourPiTy one_over_four_pi;
+
+ struct StepTy {
+ };
+
+ extern MAYBE_UNUSED StepTy step;
+
+ struct ReverseStepTy {
+ };
+
+ extern MAYBE_UNUSED ReverseStepTy reverse_step;
+
+ struct EmptyTy {
+ };
+
+ extern MAYBE_UNUSED EmptyTy empty;
+
+ struct FullTy {
+ };
+
+ extern MAYBE_UNUSED FullTy full;
+
+ struct UndefinedTy {
+ };
+
+ extern MAYBE_UNUSED UndefinedTy undefined;
+
+#if defined(__aarch64__)
+ extern const uint32x4_t movemask_mask;
+ extern const uint32x4_t vzero;
+ extern const uint32x4_t v0x80000000;
+ extern const uint32x4_t v0x7fffffff;
+ extern const uint32x4_t v000F;
+ extern const uint32x4_t v00F0;
+ extern const uint32x4_t v00FF;
+ extern const uint32x4_t v0F00;
+ extern const uint32x4_t v0F0F;
+ extern const uint32x4_t v0FF0;
+ extern const uint32x4_t v0FFF;
+ extern const uint32x4_t vF000;
+ extern const uint32x4_t vF00F;
+ extern const uint32x4_t vF0F0;
+ extern const uint32x4_t vF0FF;
+ extern const uint32x4_t vFF00;
+ extern const uint32x4_t vFF0F;
+ extern const uint32x4_t vFFF0;
+ extern const uint32x4_t vFFFF;
+ extern const uint8x16_t v0022;
+ extern const uint8x16_t v1133;
+ extern const uint8x16_t v0101;
+ extern const float32x4_t vOne;
+ extern const float32x4_t vmOne;
+ extern const float32x4_t vInf;
+ extern const float32x4_t vmInf;
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/math/interval.h b/thirdparty/embree-aarch64/common/math/interval.h
new file mode 100644
index 0000000000..f06478e881
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/interval.h
@@ -0,0 +1,161 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+#include "vec3.h"
+#include "bbox.h"
+
+namespace embree
+{
+ template<typename V>
+ struct Interval
+ {
+ V lower, upper;
+
+ __forceinline Interval() {}
+ __forceinline Interval ( const Interval& other ) { lower = other.lower; upper = other.upper; }
+ __forceinline Interval& operator=( const Interval& other ) { lower = other.lower; upper = other.upper; return *this; }
+
+ __forceinline Interval(const V& a) : lower(a), upper(a) {}
+ __forceinline Interval(const V& lower, const V& upper) : lower(lower), upper(upper) {}
+ __forceinline Interval(const BBox<V>& a) : lower(a.lower), upper(a.upper) {}
+
+ /*! tests if box is empty */
+ //__forceinline bool empty() const { return lower > upper; }
+
+ /*! computes the size of the interval */
+ __forceinline V size() const { return upper - lower; }
+
+ __forceinline V center() const { return 0.5f*(lower+upper); }
+
+ __forceinline const Interval& extend(const Interval& other) { lower = min(lower,other.lower); upper = max(upper,other.upper); return *this; }
+ __forceinline const Interval& extend(const V & other) { lower = min(lower,other ); upper = max(upper,other ); return *this; }
+
+ __forceinline friend Interval operator +( const Interval& a, const Interval& b ) {
+ return Interval(a.lower+b.lower,a.upper+b.upper);
+ }
+
+ __forceinline friend Interval operator -( const Interval& a, const Interval& b ) {
+ return Interval(a.lower-b.upper,a.upper-b.lower);
+ }
+
+ __forceinline friend Interval operator -( const Interval& a, const V& b ) {
+ return Interval(a.lower-b,a.upper-b);
+ }
+
+ __forceinline friend Interval operator *( const Interval& a, const Interval& b )
+ {
+ const V ll = a.lower*b.lower;
+ const V lu = a.lower*b.upper;
+ const V ul = a.upper*b.lower;
+ const V uu = a.upper*b.upper;
+ return Interval(min(ll,lu,ul,uu),max(ll,lu,ul,uu));
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b) {
+ return Interval(min(a.lower,b.lower),max(a.upper,b.upper));
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b, const Interval& c) {
+ return merge(merge(a,b),c);
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b, const Interval& c, const Interval& d) {
+ return merge(merge(a,b),merge(c,d));
+ }
+
+ /*! intersect bounding boxes */
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b ) { return Interval(max(a.lower, b.lower), min(a.upper, b.upper)); }
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b, const Interval& c ) { return intersect(a,intersect(b,c)); }
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b, const Interval& c, const Interval& d ) { return intersect(intersect(a,b),intersect(c,d)); }
+
+ friend embree_ostream operator<<(embree_ostream cout, const Interval& a) {
+ return cout << "[" << a.lower << ", " << a.upper << "]";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Interval( EmptyTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline Interval( FullTy ) : lower(neg_inf), upper(pos_inf) {}
+ };
+
+ __forceinline bool isEmpty(const Interval<float>& v) {
+ return v.lower > v.upper;
+ }
+
+ __forceinline vboolx isEmpty(const Interval<vfloatx>& v) {
+ return v.lower > v.upper;
+ }
+
+ /*! subset relation */
+ template<typename T> __forceinline bool subset( const Interval<T>& a, const Interval<T>& b ) {
+ return (a.lower > b.lower) && (a.upper < b.upper);
+ }
+
+ template<typename T> __forceinline bool subset( const Vec2<Interval<T>>& a, const Vec2<Interval<T>>& b ) {
+ return subset(a.x,b.x) && subset(a.y,b.y);
+ }
+
+ template<typename T> __forceinline const Vec2<Interval<T>> intersect( const Vec2<Interval<T>>& a, const Vec2<Interval<T>>& b ) {
+ return Vec2<Interval<T>>(intersect(a.x,b.x),intersect(a.y,b.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Interval<T> select ( bool s, const Interval<T>& t, const Interval<T>& f ) {
+ return Interval<T>(select(s,t.lower,f.lower),select(s,t.upper,f.upper));
+ }
+
+ template<typename T> __forceinline Interval<T> select ( const typename T::Bool& s, const Interval<T>& t, const Interval<T>& f ) {
+ return Interval<T>(select(s,t.lower,f.lower),select(s,t.upper,f.upper));
+ }
+
+ __forceinline int numRoots(const Interval<float>& p0, const Interval<float>& p1)
+ {
+ float eps = 1E-4f;
+ bool neg0 = p0.lower < eps; bool pos0 = p0.upper > -eps;
+ bool neg1 = p1.lower < eps; bool pos1 = p1.upper > -eps;
+ return (neg0 && pos1) || (pos0 && neg1) || (neg0 && pos0) || (neg1 && pos1);
+ }
+
+ typedef Interval<float> Interval1f;
+ typedef Vec2<Interval<float>> Interval2f;
+ typedef Vec3<Interval<float>> Interval3f;
+
+inline void swap(float& a, float& b) { float tmp = a; a = b; b = tmp; }
+
+inline Interval1f shift(const Interval1f& v, float shift) { return Interval1f(v.lower + shift, v.upper + shift); }
+
+#define TWO_PI (2.0*M_PI)
+inline Interval1f sin(Interval1f interval)
+{
+ if (interval.upper-interval.lower >= M_PI) { return Interval1f(-1.0, 1.0); }
+ if (interval.upper > TWO_PI) { interval = shift(interval, -TWO_PI*floor(interval.upper/TWO_PI)); }
+ if (interval.lower < 0) { interval = shift(interval, -TWO_PI*floor(interval.lower/TWO_PI)); }
+ float sinLower = sin(interval.lower);
+ float sinUpper = sin(interval.upper);
+ if (sinLower > sinUpper) swap(sinLower, sinUpper);
+ if (interval.lower < M_PI / 2.0 && interval.upper > M_PI / 2.0) sinUpper = 1.0;
+ if (interval.lower < 3.0 * M_PI / 2.0 && interval.upper > 3.0 * M_PI / 2.0) sinLower = -1.0;
+ return Interval1f(sinLower, sinUpper);
+}
+
+inline Interval1f cos(Interval1f interval)
+{
+ if (interval.upper-interval.lower >= M_PI) { return Interval1f(-1.0, 1.0); }
+ if (interval.upper > TWO_PI) { interval = shift(interval, -TWO_PI*floor(interval.upper/TWO_PI)); }
+ if (interval.lower < 0) { interval = shift(interval, -TWO_PI*floor(interval.lower/TWO_PI)); }
+ float cosLower = cos(interval.lower);
+ float cosUpper = cos(interval.upper);
+ if (cosLower > cosUpper) swap(cosLower, cosUpper);
+ if (interval.lower < M_PI && interval.upper > M_PI) cosLower = -1.0;
+ return Interval1f(cosLower, cosUpper);
+}
+#undef TWO_PI
+}
diff --git a/thirdparty/embree-aarch64/common/math/lbbox.h b/thirdparty/embree-aarch64/common/math/lbbox.h
new file mode 100644
index 0000000000..95df4a918d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/lbbox.h
@@ -0,0 +1,289 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bbox.h"
+#include "range.h"
+
+namespace embree
+{
+ template<typename T>
+ __forceinline std::pair<T,T> globalLinear(const std::pair<T,T>& v, const BBox1f& dt)
+ {
+ const float rcp_dt_size = float(1.0f)/dt.size();
+ const T g0 = lerp(v.first,v.second,-dt.lower*rcp_dt_size);
+ const T g1 = lerp(v.first,v.second,(1.0f-dt.lower)*rcp_dt_size);
+ return std::make_pair(g0,g1);
+ }
+
+ template<typename T>
+ struct LBBox
+ {
+ public:
+ __forceinline LBBox () {}
+
+ template<typename T1>
+ __forceinline LBBox ( const LBBox<T1>& other )
+ : bounds0(other.bounds0), bounds1(other.bounds1) {}
+
+ __forceinline LBBox& operator= ( const LBBox& other ) {
+ bounds0 = other.bounds0; bounds1 = other.bounds1; return *this;
+ }
+
+ __forceinline LBBox (EmptyTy)
+ : bounds0(EmptyTy()), bounds1(EmptyTy()) {}
+
+ __forceinline explicit LBBox ( const BBox<T>& bounds)
+ : bounds0(bounds), bounds1(bounds) { }
+
+ __forceinline LBBox ( const BBox<T>& bounds0, const BBox<T>& bounds1)
+ : bounds0(bounds0), bounds1(bounds1) { }
+
+ LBBox ( const avector<BBox<T>>& bounds )
+ {
+ assert(bounds.size());
+ BBox<T> b0 = bounds.front();
+ BBox<T> b1 = bounds.back();
+ for (size_t i=1; i<bounds.size()-1; i++) {
+ const float f = float(i)/float(bounds.size()-1);
+ const BBox<T> bt = lerp(b0,b1,f);
+ const T dlower = min(bounds[i].lower-bt.lower,T(zero));
+ const T dupper = max(bounds[i].upper-bt.upper,T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range, float numTimeSegments)
+ {
+ const float lower = time_range.lower*numTimeSegments;
+ const float upper = time_range.upper*numTimeSegments;
+ const float ilowerf = floor(lower);
+ const float iupperf = ceil(upper);
+ const int ilower = (int)ilowerf;
+ const int iupper = (int)iupperf;
+
+ const BBox<T> blower0 = bounds(ilower);
+ const BBox<T> bupper1 = bounds(iupper);
+
+ if (iupper-ilower == 1) {
+ bounds0 = lerp(blower0, bupper1, lower-ilowerf);
+ bounds1 = lerp(bupper1, blower0, iupperf-upper);
+ return;
+ }
+
+ const BBox<T> blower1 = bounds(ilower+1);
+ const BBox<T> bupper0 = bounds(iupper-1);
+ BBox<T> b0 = lerp(blower0, blower1, lower-ilowerf);
+ BBox<T> b1 = lerp(bupper1, bupper0, iupperf-upper);
+
+ for (int i = ilower+1; i < iupper; i++)
+ {
+ const float f = (float(i)/numTimeSegments - time_range.lower) / time_range.size();
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range_in, const BBox1f& geom_time_range, float geom_time_segments)
+ {
+ /* normalize global time_range_in to local geom_time_range */
+ const BBox1f time_range((time_range_in.lower-geom_time_range.lower)/geom_time_range.size(),
+ (time_range_in.upper-geom_time_range.lower)/geom_time_range.size());
+
+ const float lower = time_range.lower*geom_time_segments;
+ const float upper = time_range.upper*geom_time_segments;
+ const float ilowerf = floor(lower);
+ const float iupperf = ceil(upper);
+ const float ilowerfc = max(0.0f,ilowerf);
+ const float iupperfc = min(iupperf,geom_time_segments);
+ const int ilowerc = (int)ilowerfc;
+ const int iupperc = (int)iupperfc;
+ assert(iupperc-ilowerc > 0);
+
+ /* this larger iteration range guarantees that we process borders of geom_time_range is (partially) inside time_range_in */
+ const int ilower_iter = max(-1,(int)ilowerf);
+ const int iupper_iter = min((int)iupperf,(int)geom_time_segments+1);
+
+ const BBox<T> blower0 = bounds(ilowerc);
+ const BBox<T> bupper1 = bounds(iupperc);
+ if (iupper_iter-ilower_iter == 1) {
+ bounds0 = lerp(blower0, bupper1, max(0.0f,lower-ilowerfc));
+ bounds1 = lerp(bupper1, blower0, max(0.0f,iupperfc-upper));
+ return;
+ }
+
+ const BBox<T> blower1 = bounds(ilowerc+1);
+ const BBox<T> bupper0 = bounds(iupperc-1);
+ BBox<T> b0 = lerp(blower0, blower1, max(0.0f,lower-ilowerfc));
+ BBox<T> b1 = lerp(bupper1, bupper0, max(0.0f,iupperfc-upper));
+
+ for (int i = ilower_iter+1; i < iupper_iter; i++)
+ {
+ const float f = (float(i)/geom_time_segments - time_range.lower) / time_range.size();
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const range<int>& time_range, int numTimeSegments)
+ {
+ const int ilower = time_range.begin();
+ const int iupper = time_range.end();
+
+ BBox<T> b0 = bounds(ilower);
+ BBox<T> b1 = bounds(iupper);
+
+ if (iupper-ilower == 1)
+ {
+ bounds0 = b0;
+ bounds1 = b1;
+ return;
+ }
+
+ for (int i = ilower+1; i<iupper; i++)
+ {
+ const float f = float(i - time_range.begin()) / float(time_range.size());
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ public:
+
+ __forceinline bool empty() const {
+ return bounds().empty();
+ }
+
+ __forceinline BBox<T> bounds () const {
+ return merge(bounds0,bounds1);
+ }
+
+ __forceinline BBox<T> interpolate( const float t ) const {
+ return lerp(bounds0,bounds1,t);
+ }
+
+ __forceinline LBBox<T> interpolate( const BBox1f& dt ) const {
+ return LBBox<T>(interpolate(dt.lower),interpolate(dt.upper));
+ }
+
+ __forceinline void extend( const LBBox& other ) {
+ bounds0.extend(other.bounds0);
+ bounds1.extend(other.bounds1);
+ }
+
+ __forceinline float expectedHalfArea() const;
+
+ __forceinline float expectedHalfArea(const BBox1f& dt) const {
+ return interpolate(dt).expectedHalfArea();
+ }
+
+ __forceinline float expectedApproxHalfArea() const {
+ return 0.5f*(halfArea(bounds0) + halfArea(bounds1));
+ }
+
+ /* calculates bounds for [0,1] time range from bounds in dt time range */
+ __forceinline LBBox global(const BBox1f& dt) const
+ {
+ const float rcp_dt_size = 1.0f/dt.size();
+ const BBox<T> b0 = interpolate(-dt.lower*rcp_dt_size);
+ const BBox<T> b1 = interpolate((1.0f-dt.lower)*rcp_dt_size);
+ return LBBox(b0,b1);
+ }
+
+ /*! Comparison Operators */
+ //template<typename TT> friend __forceinline bool operator==( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }
+ //template<typename TT> friend __forceinline bool operator!=( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }
+ friend __forceinline bool operator==( const LBBox& a, const LBBox& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }
+ friend __forceinline bool operator!=( const LBBox& a, const LBBox& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const LBBox& box) {
+ return cout << "LBBox { " << box.bounds0 << "; " << box.bounds1 << " }";
+ }
+
+ public:
+ BBox<T> bounds0, bounds1;
+ };
+
+ /*! tests if box is finite */
+ template<typename T>
+ __forceinline bool isvalid( const LBBox<T>& v ) {
+ return isvalid(v.bounds0) && isvalid(v.bounds1);
+ }
+
+ template<typename T>
+ __forceinline bool isvalid_non_empty( const LBBox<T>& v ) {
+ return isvalid_non_empty(v.bounds0) && isvalid_non_empty(v.bounds1);
+ }
+
+ template<typename T>
+ __forceinline T expectedArea(const T& a0, const T& a1, const T& b0, const T& b1)
+ {
+ const T da = a1-a0;
+ const T db = b1-b0;
+ return a0*b0+(a0*db+da*b0)*T(0.5f) + da*db*T(1.0f/3.0f);
+ }
+
+ template<> __forceinline float LBBox<Vec3fa>::expectedHalfArea() const
+ {
+ const Vec3fa d0 = bounds0.size();
+ const Vec3fa d1 = bounds1.size();
+ return reduce_add(expectedArea(Vec3fa(d0.x,d0.y,d0.z),
+ Vec3fa(d1.x,d1.y,d1.z),
+ Vec3fa(d0.y,d0.z,d0.x),
+ Vec3fa(d1.y,d1.z,d1.x)));
+ }
+
+ template<typename T>
+ __forceinline float expectedApproxHalfArea(const LBBox<T>& box) {
+ return box.expectedApproxHalfArea();
+ }
+
+ template<typename T>
+ __forceinline LBBox<T> merge(const LBBox<T>& a, const LBBox<T>& b) {
+ return LBBox<T>(merge(a.bounds0, b.bounds0), merge(a.bounds1, b.bounds1));
+ }
+
+ /*! subset relation */
+ template<typename T> __inline bool subset( const LBBox<T>& a, const LBBox<T>& b ) {
+ return subset(a.bounds0,b.bounds0) && subset(a.bounds1,b.bounds1);
+ }
+
+ /*! default template instantiations */
+ typedef LBBox<float> LBBox1f;
+ typedef LBBox<Vec2f> LBBox2f;
+ typedef LBBox<Vec3f> LBBox3f;
+ typedef LBBox<Vec3fa> LBBox3fa;
+ typedef LBBox<Vec3fx> LBBox3fx;
+}
diff --git a/thirdparty/embree-aarch64/common/math/linearspace2.h b/thirdparty/embree-aarch64/common/math/linearspace2.h
new file mode 100644
index 0000000000..b9a382962c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/linearspace2.h
@@ -0,0 +1,148 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// 2D Linear Transform (2x2 Matrix)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct LinearSpace2
+ {
+ typedef T Vector;
+ typedef typename T::Scalar Scalar;
+
+ /*! default matrix constructor */
+ __forceinline LinearSpace2 ( ) {}
+ __forceinline LinearSpace2 ( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; }
+ __forceinline LinearSpace2& operator=( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; return *this; }
+
+ template<typename L1> __forceinline LinearSpace2( const LinearSpace2<L1>& s ) : vx(s.vx), vy(s.vy) {}
+
+ /*! matrix construction from column vectors */
+ __forceinline LinearSpace2(const Vector& vx, const Vector& vy)
+ : vx(vx), vy(vy) {}
+
+ /*! matrix construction from row mayor data */
+ __forceinline LinearSpace2(const Scalar& m00, const Scalar& m01,
+ const Scalar& m10, const Scalar& m11)
+ : vx(m00,m10), vy(m01,m11) {}
+
+ /*! compute the determinant of the matrix */
+ __forceinline const Scalar det() const { return vx.x*vy.y - vx.y*vy.x; }
+
+ /*! compute adjoint matrix */
+ __forceinline const LinearSpace2 adjoint() const { return LinearSpace2(vy.y,-vy.x,-vx.y,vx.x); }
+
+ /*! compute inverse matrix */
+ __forceinline const LinearSpace2 inverse() const { return adjoint()/det(); }
+
+ /*! compute transposed matrix */
+ __forceinline const LinearSpace2 transposed() const { return LinearSpace2(vx.x,vx.y,vy.x,vy.y); }
+
+ /*! returns first row of matrix */
+ __forceinline Vector row0() const { return Vector(vx.x,vy.x); }
+
+ /*! returns second row of matrix */
+ __forceinline Vector row1() const { return Vector(vx.y,vy.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline LinearSpace2( ZeroTy ) : vx(zero), vy(zero) {}
+ __forceinline LinearSpace2( OneTy ) : vx(one, zero), vy(zero, one) {}
+
+ /*! return matrix for scaling */
+ static __forceinline LinearSpace2 scale(const Vector& s) {
+ return LinearSpace2(s.x, 0,
+ 0 , s.y);
+ }
+
+ /*! return matrix for rotation */
+ static __forceinline LinearSpace2 rotate(const Scalar& r) {
+ Scalar s = sin(r), c = cos(r);
+ return LinearSpace2(c, -s,
+ s, c);
+ }
+
+ /*! return closest orthogonal matrix (i.e. a general rotation including reflection) */
+ LinearSpace2 orthogonal() const
+ {
+ LinearSpace2 m = *this;
+
+ // mirrored?
+ Scalar mirror(one);
+ if (m.det() < Scalar(zero)) {
+ m.vx = -m.vx;
+ mirror = -mirror;
+ }
+
+ // rotation
+ for (int i = 0; i < 99; i++) {
+ const LinearSpace2 m_next = 0.5 * (m + m.transposed().inverse());
+ const LinearSpace2 d = m_next - m;
+ m = m_next;
+ // norm^2 of difference small enough?
+ if (max(dot(d.vx, d.vx), dot(d.vy, d.vy)) < 1e-8)
+ break;
+ }
+
+ // rotation * mirror_x
+ return LinearSpace2(mirror*m.vx, m.vy);
+ }
+
+ public:
+
+ /*! the column vectors of the matrix */
+ Vector vx,vy;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace2<T> operator -( const LinearSpace2<T>& a ) { return LinearSpace2<T>(-a.vx,-a.vy); }
+ template<typename T> __forceinline LinearSpace2<T> operator +( const LinearSpace2<T>& a ) { return LinearSpace2<T>(+a.vx,+a.vy); }
+ template<typename T> __forceinline LinearSpace2<T> rcp ( const LinearSpace2<T>& a ) { return a.inverse(); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace2<T> operator +( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return LinearSpace2<T>(a.vx+b.vx,a.vy+b.vy); }
+ template<typename T> __forceinline LinearSpace2<T> operator -( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return LinearSpace2<T>(a.vx-b.vx,a.vy-b.vy); }
+
+ template<typename T> __forceinline LinearSpace2<T> operator*(const typename T::Scalar & a, const LinearSpace2<T>& b) { return LinearSpace2<T>(a*b.vx, a*b.vy); }
+ template<typename T> __forceinline T operator*(const LinearSpace2<T>& a, const T & b) { return b.x*a.vx + b.y*a.vy; }
+ template<typename T> __forceinline LinearSpace2<T> operator*(const LinearSpace2<T>& a, const LinearSpace2<T>& b) { return LinearSpace2<T>(a*b.vx, a*b.vy); }
+
+ template<typename T> __forceinline LinearSpace2<T> operator/(const LinearSpace2<T>& a, const typename T::Scalar & b) { return LinearSpace2<T>(a.vx/b, a.vy/b); }
+ template<typename T> __forceinline LinearSpace2<T> operator/(const LinearSpace2<T>& a, const LinearSpace2<T>& b) { return a * rcp(b); }
+
+ template<typename T> __forceinline LinearSpace2<T>& operator *=( LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a = a * b; }
+ template<typename T> __forceinline LinearSpace2<T>& operator /=( LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a.vx == b.vx && a.vy == b.vy; }
+ template<typename T> __forceinline bool operator !=( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a.vx != b.vx || a.vy != b.vy; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const LinearSpace2<T>& m) {
+ return cout << "{ vx = " << m.vx << ", vy = " << m.vy << "}";
+ }
+
+ /*! Shortcuts for common linear spaces. */
+ typedef LinearSpace2<Vec2f> LinearSpace2f;
+ typedef LinearSpace2<Vec2fa> LinearSpace2fa;
+}
diff --git a/thirdparty/embree-aarch64/common/math/linearspace3.h b/thirdparty/embree-aarch64/common/math/linearspace3.h
new file mode 100644
index 0000000000..12b5bb776b
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/linearspace3.h
@@ -0,0 +1,213 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec3.h"
+#include "quaternion.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// 3D Linear Transform (3x3 Matrix)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct LinearSpace3
+ {
+ typedef T Vector;
+ typedef typename T::Scalar Scalar;
+
+ /*! default matrix constructor */
+ __forceinline LinearSpace3 ( ) {}
+ __forceinline LinearSpace3 ( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; }
+ __forceinline LinearSpace3& operator=( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; return *this; }
+
+ template<typename L1> __forceinline LinearSpace3( const LinearSpace3<L1>& s ) : vx(s.vx), vy(s.vy), vz(s.vz) {}
+
+ /*! matrix construction from column vectors */
+ __forceinline LinearSpace3(const Vector& vx, const Vector& vy, const Vector& vz)
+ : vx(vx), vy(vy), vz(vz) {}
+
+ /*! construction from quaternion */
+ __forceinline LinearSpace3( const QuaternionT<Scalar>& q )
+ : vx((q.r*q.r + q.i*q.i - q.j*q.j - q.k*q.k), 2.0f*(q.i*q.j + q.r*q.k), 2.0f*(q.i*q.k - q.r*q.j))
+ , vy(2.0f*(q.i*q.j - q.r*q.k), (q.r*q.r - q.i*q.i + q.j*q.j - q.k*q.k), 2.0f*(q.j*q.k + q.r*q.i))
+ , vz(2.0f*(q.i*q.k + q.r*q.j), 2.0f*(q.j*q.k - q.r*q.i), (q.r*q.r - q.i*q.i - q.j*q.j + q.k*q.k)) {}
+
+ /*! matrix construction from row mayor data */
+ __forceinline LinearSpace3(const Scalar& m00, const Scalar& m01, const Scalar& m02,
+ const Scalar& m10, const Scalar& m11, const Scalar& m12,
+ const Scalar& m20, const Scalar& m21, const Scalar& m22)
+ : vx(m00,m10,m20), vy(m01,m11,m21), vz(m02,m12,m22) {}
+
+ /*! compute the determinant of the matrix */
+ __forceinline const Scalar det() const { return dot(vx,cross(vy,vz)); }
+
+ /*! compute adjoint matrix */
+ __forceinline const LinearSpace3 adjoint() const { return LinearSpace3(cross(vy,vz),cross(vz,vx),cross(vx,vy)).transposed(); }
+
+ /*! compute inverse matrix */
+ __forceinline const LinearSpace3 inverse() const { return adjoint()/det(); }
+
+ /*! compute transposed matrix */
+ __forceinline const LinearSpace3 transposed() const { return LinearSpace3(vx.x,vx.y,vx.z,vy.x,vy.y,vy.z,vz.x,vz.y,vz.z); }
+
+ /*! returns first row of matrix */
+ __forceinline Vector row0() const { return Vector(vx.x,vy.x,vz.x); }
+
+ /*! returns second row of matrix */
+ __forceinline Vector row1() const { return Vector(vx.y,vy.y,vz.y); }
+
+ /*! returns third row of matrix */
+ __forceinline Vector row2() const { return Vector(vx.z,vy.z,vz.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline LinearSpace3( ZeroTy ) : vx(zero), vy(zero), vz(zero) {}
+ __forceinline LinearSpace3( OneTy ) : vx(one, zero, zero), vy(zero, one, zero), vz(zero, zero, one) {}
+
+ /*! return matrix for scaling */
+ static __forceinline LinearSpace3 scale(const Vector& s) {
+ return LinearSpace3(s.x, 0, 0,
+ 0 , s.y, 0,
+ 0 , 0, s.z);
+ }
+
+ /*! return matrix for rotation around arbitrary axis */
+ static __forceinline LinearSpace3 rotate(const Vector& _u, const Scalar& r) {
+ Vector u = normalize(_u);
+ Scalar s = sin(r), c = cos(r);
+ return LinearSpace3(u.x*u.x+(1-u.x*u.x)*c, u.x*u.y*(1-c)-u.z*s, u.x*u.z*(1-c)+u.y*s,
+ u.x*u.y*(1-c)+u.z*s, u.y*u.y+(1-u.y*u.y)*c, u.y*u.z*(1-c)-u.x*s,
+ u.x*u.z*(1-c)-u.y*s, u.y*u.z*(1-c)+u.x*s, u.z*u.z+(1-u.z*u.z)*c);
+ }
+
+ public:
+
+ /*! the column vectors of the matrix */
+ Vector vx,vy,vz;
+ };
+
+ /*! compute transposed matrix */
+ template<> __forceinline const LinearSpace3<Vec3fa> LinearSpace3<Vec3fa>::transposed() const {
+ vfloat4 rx,ry,rz; transpose((vfloat4&)vx,(vfloat4&)vy,(vfloat4&)vz,vfloat4(zero),rx,ry,rz);
+ return LinearSpace3<Vec3fa>(Vec3fa(rx),Vec3fa(ry),Vec3fa(rz));
+ }
+
+ template<typename T>
+ __forceinline const LinearSpace3<T> transposed(const LinearSpace3<T>& xfm) {
+ return xfm.transposed();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> operator -( const LinearSpace3<T>& a ) { return LinearSpace3<T>(-a.vx,-a.vy,-a.vz); }
+ template<typename T> __forceinline LinearSpace3<T> operator +( const LinearSpace3<T>& a ) { return LinearSpace3<T>(+a.vx,+a.vy,+a.vz); }
+ template<typename T> __forceinline LinearSpace3<T> rcp ( const LinearSpace3<T>& a ) { return a.inverse(); }
+
+ /* constructs a coordinate frame form a normalized normal */
+ template<typename T> __forceinline LinearSpace3<T> frame(const T& N)
+ {
+ const T dx0(0,N.z,-N.y);
+ const T dx1(-N.z,0,N.x);
+ const T dx = normalize(select(dot(dx0,dx0) > dot(dx1,dx1),dx0,dx1));
+ const T dy = normalize(cross(N,dx));
+ return LinearSpace3<T>(dx,dy,N);
+ }
+
+ /* constructs a coordinate frame from a normal and approximate x-direction */
+ template<typename T> __forceinline LinearSpace3<T> frame(const T& N, const T& dxi)
+ {
+ if (abs(dot(dxi,N)) > 0.99f) return frame(N); // fallback in case N and dxi are very parallel
+ const T dx = normalize(cross(dxi,N));
+ const T dy = normalize(cross(N,dx));
+ return LinearSpace3<T>(dx,dy,N);
+ }
+
+ /* clamps linear space to range -1 to +1 */
+ template<typename T> __forceinline LinearSpace3<T> clamp(const LinearSpace3<T>& space) {
+ return LinearSpace3<T>(clamp(space.vx,T(-1.0f),T(1.0f)),
+ clamp(space.vy,T(-1.0f),T(1.0f)),
+ clamp(space.vz,T(-1.0f),T(1.0f)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> operator +( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return LinearSpace3<T>(a.vx+b.vx,a.vy+b.vy,a.vz+b.vz); }
+ template<typename T> __forceinline LinearSpace3<T> operator -( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return LinearSpace3<T>(a.vx-b.vx,a.vy-b.vy,a.vz-b.vz); }
+
+ template<typename T> __forceinline LinearSpace3<T> operator*(const typename T::Scalar & a, const LinearSpace3<T>& b) { return LinearSpace3<T>(a*b.vx, a*b.vy, a*b.vz); }
+ template<typename T> __forceinline T operator*(const LinearSpace3<T>& a, const T & b) { return madd(T(b.x),a.vx,madd(T(b.y),a.vy,T(b.z)*a.vz)); }
+ template<typename T> __forceinline LinearSpace3<T> operator*(const LinearSpace3<T>& a, const LinearSpace3<T>& b) { return LinearSpace3<T>(a*b.vx, a*b.vy, a*b.vz); }
+
+ template<typename T> __forceinline LinearSpace3<T> operator/(const LinearSpace3<T>& a, const typename T::Scalar & b) { return LinearSpace3<T>(a.vx/b, a.vy/b, a.vz/b); }
+ template<typename T> __forceinline LinearSpace3<T> operator/(const LinearSpace3<T>& a, const LinearSpace3<T>& b) { return a * rcp(b); }
+
+ template<typename T> __forceinline LinearSpace3<T>& operator *=( LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a = a * b; }
+ template<typename T> __forceinline LinearSpace3<T>& operator /=( LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a = a / b; }
+
+ template<typename T> __forceinline T xfmPoint (const LinearSpace3<T>& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); }
+ template<typename T> __forceinline T xfmVector(const LinearSpace3<T>& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); }
+ template<typename T> __forceinline T xfmNormal(const LinearSpace3<T>& s, const T & a) { return xfmVector(s.inverse().transposed(),a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a.vx == b.vx && a.vy == b.vy && a.vz == b.vz; }
+ template<typename T> __forceinline bool operator !=( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a.vx != b.vx || a.vy != b.vy || a.vz != b.vz; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> select ( const typename T::Scalar::Bool& s, const LinearSpace3<T>& t, const LinearSpace3<T>& f ) {
+ return LinearSpace3<T>(select(s,t.vx,f.vx),select(s,t.vy,f.vy),select(s,t.vz,f.vz));
+ }
+
+ /*! blending */
+ template<typename T>
+ __forceinline LinearSpace3<T> lerp(const LinearSpace3<T>& l0, const LinearSpace3<T>& l1, const float t)
+ {
+ return LinearSpace3<T>(lerp(l0.vx,l1.vx,t),
+ lerp(l0.vy,l1.vy,t),
+ lerp(l0.vz,l1.vz,t));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const LinearSpace3<T>& m) {
+ return cout << "{ vx = " << m.vx << ", vy = " << m.vy << ", vz = " << m.vz << "}";
+ }
+
+ /*! Shortcuts for common linear spaces. */
+ typedef LinearSpace3<Vec3f> LinearSpace3f;
+ typedef LinearSpace3<Vec3fa> LinearSpace3fa;
+ typedef LinearSpace3<Vec3fx> LinearSpace3fx;
+ typedef LinearSpace3<Vec3ff> LinearSpace3ff;
+
+ template<int N> using LinearSpace3vf = LinearSpace3<Vec3<vfloat<N>>>;
+ typedef LinearSpace3<Vec3<vfloat<4>>> LinearSpace3vf4;
+ typedef LinearSpace3<Vec3<vfloat<8>>> LinearSpace3vf8;
+ typedef LinearSpace3<Vec3<vfloat<16>>> LinearSpace3vf16;
+
+ /*! blending */
+ template<typename T, typename S>
+ __forceinline LinearSpace3<T> lerp(const LinearSpace3<T>& l0,
+ const LinearSpace3<T>& l1,
+ const S& t)
+ {
+ return LinearSpace3<T>(lerp(l0.vx,l1.vx,t),
+ lerp(l0.vy,l1.vy,t),
+ lerp(l0.vz,l1.vz,t));
+ }
+
+}
diff --git a/thirdparty/embree-aarch64/common/math/math.h b/thirdparty/embree-aarch64/common/math/math.h
new file mode 100644
index 0000000000..6d54abd44d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/math.h
@@ -0,0 +1,451 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "constants.h"
+#include <cmath>
+
+#if defined(__ARM_NEON)
+#include "SSE2NEON.h"
+#if defined(NEON_AVX2_EMULATION)
+#include "AVX2NEON.h"
+#endif
+#else
+#include <emmintrin.h>
+#include <xmmintrin.h>
+#include <immintrin.h>
+#endif
+
+#if defined(__WIN32__) && !defined(__MINGW32__)
+#if (__MSV_VER <= 1700)
+namespace std
+{
+ __forceinline bool isinf ( const float x ) { return _finite(x) == 0; }
+ __forceinline bool isnan ( const float x ) { return _isnan(x) != 0; }
+ __forceinline bool isfinite (const float x) { return _finite(x) != 0; }
+}
+#endif
+#endif
+
+namespace embree
+{
+ __forceinline bool isvalid ( const float& v ) {
+ return (v > -FLT_LARGE) & (v < +FLT_LARGE);
+ }
+
+ __forceinline int cast_f2i(float f) {
+ union { float f; int i; } v; v.f = f; return v.i;
+ }
+
+ __forceinline float cast_i2f(int i) {
+ union { float f; int i; } v; v.i = i; return v.f;
+ }
+
+ __forceinline int toInt (const float& a) { return int(a); }
+ __forceinline float toFloat(const int& a) { return float(a); }
+
+#if defined(__WIN32__) && !defined(__MINGW32__)
+ __forceinline bool finite ( const float x ) { return _finite(x) != 0; }
+#endif
+
+ __forceinline float sign ( const float x ) { return x<0?-1.0f:1.0f; }
+ __forceinline float sqr ( const float x ) { return x*x; }
+
+ __forceinline float rcp ( const float x )
+ {
+#if defined(__aarch64__)
+ // Move scalar to vector register and do rcp.
+ __m128 a;
+ a[0] = x;
+ float32x4_t reciprocal = vrecpeq_f32(a);
+ reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
+ return reciprocal[0];
+#else
+
+ const __m128 a = _mm_set_ss(x);
+
+#if defined(__AVX512VL__)
+ const __m128 r = _mm_rcp14_ss(_mm_set_ss(0.0f),a);
+#else
+ const __m128 r = _mm_rcp_ss(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm_cvtss_f32(_mm_mul_ss(r,_mm_fnmadd_ss(r, a, _mm_set_ss(2.0f))));
+#else
+ return _mm_cvtss_f32(_mm_mul_ss(r,_mm_sub_ss(_mm_set_ss(2.0f), _mm_mul_ss(r, a))));
+#endif
+
+#endif //defined(__aarch64__)
+ }
+
+ __forceinline float signmsk ( const float x ) {
+#if defined(__aarch64__)
+ // FP and Neon shares same vector register in arm64
+ __m128 a;
+ __m128i b;
+ a[0] = x;
+ b[0] = 0x80000000;
+ a = _mm_and_ps(a, vreinterpretq_f32_s32(b));
+ return a[0];
+#else
+ return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
+#endif
+ }
+ __forceinline float xorf( const float x, const float y ) {
+#if defined(__aarch64__)
+ // FP and Neon shares same vector register in arm64
+ __m128 a;
+ __m128 b;
+ a[0] = x;
+ b[0] = y;
+ a = _mm_xor_ps(a, b);
+ return a[0];
+#else
+ return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y)));
+#endif
+ }
+ __forceinline float andf( const float x, const unsigned y ) {
+#if defined(__aarch64__)
+ // FP and Neon shares same vector register in arm64
+ __m128 a;
+ __m128i b;
+ a[0] = x;
+ b[0] = y;
+ a = _mm_and_ps(a, vreinterpretq_f32_s32(b));
+ return a[0];
+#else
+ return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y))));
+#endif
+ }
+ __forceinline float rsqrt( const float x )
+ {
+#if defined(__aarch64__)
+ // FP and Neon shares same vector register in arm64
+ __m128 a;
+ a[0] = x;
+ __m128 value = _mm_rsqrt_ps(a);
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(a, value), value));
+ value = vmulq_f32(value, vrsqrtsq_f32(vmulq_f32(a, value), value));
+ return value[0];
+#else
+
+ const __m128 a = _mm_set_ss(x);
+#if defined(__AVX512VL__)
+ const __m128 r = _mm_rsqrt14_ss(_mm_set_ss(0.0f),a);
+#else
+ const __m128 r = _mm_rsqrt_ss(a);
+#endif
+ const __m128 c = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r),
+ _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
+ return _mm_cvtss_f32(c);
+#endif
+ }
+
+#if defined(__WIN32__) && (__MSC_VER <= 1700) && !defined(__MINGW32__)
+ __forceinline float nextafter(float x, float y) { if ((x<y) == (x>0)) return x*(1.1f+float(ulp)); else return x*(0.9f-float(ulp)); }
+ __forceinline double nextafter(double x, double y) { return _nextafter(x, y); }
+ __forceinline int roundf(float f) { return (int)(f + 0.5f); }
+#else
+ __forceinline float nextafter(float x, float y) { return ::nextafterf(x, y); }
+ __forceinline double nextafter(double x, double y) { return ::nextafter(x, y); }
+#endif
+
+ __forceinline float abs ( const float x ) { return ::fabsf(x); }
+ __forceinline float acos ( const float x ) { return ::acosf (x); }
+ __forceinline float asin ( const float x ) { return ::asinf (x); }
+ __forceinline float atan ( const float x ) { return ::atanf (x); }
+ __forceinline float atan2( const float y, const float x ) { return ::atan2f(y, x); }
+ __forceinline float cos ( const float x ) { return ::cosf (x); }
+ __forceinline float cosh ( const float x ) { return ::coshf (x); }
+ __forceinline float exp ( const float x ) { return ::expf (x); }
+ __forceinline float fmod ( const float x, const float y ) { return ::fmodf (x, y); }
+ __forceinline float log ( const float x ) { return ::logf (x); }
+ __forceinline float log10( const float x ) { return ::log10f(x); }
+ __forceinline float pow ( const float x, const float y ) { return ::powf (x, y); }
+ __forceinline float sin ( const float x ) { return ::sinf (x); }
+ __forceinline float sinh ( const float x ) { return ::sinhf (x); }
+ __forceinline float sqrt ( const float x ) { return ::sqrtf (x); }
+ __forceinline float tan ( const float x ) { return ::tanf (x); }
+ __forceinline float tanh ( const float x ) { return ::tanhf (x); }
+ __forceinline float floor( const float x ) { return ::floorf (x); }
+ __forceinline float ceil ( const float x ) { return ::ceilf (x); }
+ __forceinline float frac ( const float x ) { return x-floor(x); }
+
+ __forceinline double abs ( const double x ) { return ::fabs(x); }
+ __forceinline double sign ( const double x ) { return x<0?-1.0:1.0; }
+ __forceinline double acos ( const double x ) { return ::acos (x); }
+ __forceinline double asin ( const double x ) { return ::asin (x); }
+ __forceinline double atan ( const double x ) { return ::atan (x); }
+ __forceinline double atan2( const double y, const double x ) { return ::atan2(y, x); }
+ __forceinline double cos ( const double x ) { return ::cos (x); }
+ __forceinline double cosh ( const double x ) { return ::cosh (x); }
+ __forceinline double exp ( const double x ) { return ::exp (x); }
+ __forceinline double fmod ( const double x, const double y ) { return ::fmod (x, y); }
+ __forceinline double log ( const double x ) { return ::log (x); }
+ __forceinline double log10( const double x ) { return ::log10(x); }
+ __forceinline double pow ( const double x, const double y ) { return ::pow (x, y); }
+ __forceinline double rcp ( const double x ) { return 1.0/x; }
+ __forceinline double rsqrt( const double x ) { return 1.0/::sqrt(x); }
+ __forceinline double sin ( const double x ) { return ::sin (x); }
+ __forceinline double sinh ( const double x ) { return ::sinh (x); }
+ __forceinline double sqr ( const double x ) { return x*x; }
+ __forceinline double sqrt ( const double x ) { return ::sqrt (x); }
+ __forceinline double tan ( const double x ) { return ::tan (x); }
+ __forceinline double tanh ( const double x ) { return ::tanh (x); }
+ __forceinline double floor( const double x ) { return ::floor (x); }
+ __forceinline double ceil ( const double x ) { return ::ceil (x); }
+
+#if defined(__aarch64__)
+ __forceinline float mini(float a, float b) {
+ // FP and Neon shares same vector register in arm64
+ __m128 x;
+ __m128 y;
+ x[0] = a;
+ y[0] = b;
+ x = _mm_min_ps(x, y);
+ return x[0];
+ }
+#elif defined(__SSE4_1__)
+ __forceinline float mini(float a, float b) {
+ const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
+ const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
+ const __m128i ci = _mm_min_epi32(ai,bi);
+ return _mm_cvtss_f32(_mm_castsi128_ps(ci));
+ }
+#endif
+
+#if defined(__aarch64__)
+ __forceinline float maxi(float a, float b) {
+ // FP and Neon shares same vector register in arm64
+ __m128 x;
+ __m128 y;
+ x[0] = a;
+ y[0] = b;
+ x = _mm_max_ps(x, y);
+ return x[0];
+ }
+#elif defined(__SSE4_1__)
+ __forceinline float maxi(float a, float b) {
+ const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
+ const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
+ const __m128i ci = _mm_max_epi32(ai,bi);
+ return _mm_cvtss_f32(_mm_castsi128_ps(ci));
+ }
+#endif
+
+ template<typename T>
+ __forceinline T twice(const T& a) { return a+a; }
+
+ __forceinline int min(int a, int b) { return a<b ? a:b; }
+ __forceinline unsigned min(unsigned a, unsigned b) { return a<b ? a:b; }
+ __forceinline int64_t min(int64_t a, int64_t b) { return a<b ? a:b; }
+ __forceinline float min(float a, float b) { return a<b ? a:b; }
+ __forceinline double min(double a, double b) { return a<b ? a:b; }
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline size_t min(size_t a, size_t b) { return a<b ? a:b; }
+#endif
+
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c) { return min(min(a,b),c); }
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d) { return min(min(a,b),min(c,d)); }
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d, const T& e) { return min(min(min(a,b),min(c,d)),e); }
+
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c) { return mini(mini(a,b),c); }
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d) { return mini(mini(a,b),mini(c,d)); }
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d, const T& e) { return mini(mini(mini(a,b),mini(c,d)),e); }
+
+ __forceinline int max(int a, int b) { return a<b ? b:a; }
+ __forceinline unsigned max(unsigned a, unsigned b) { return a<b ? b:a; }
+ __forceinline int64_t max(int64_t a, int64_t b) { return a<b ? b:a; }
+ __forceinline float max(float a, float b) { return a<b ? b:a; }
+ __forceinline double max(double a, double b) { return a<b ? b:a; }
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline size_t max(size_t a, size_t b) { return a<b ? b:a; }
+#endif
+
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c) { return max(max(a,b),c); }
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d) { return max(max(a,b),max(c,d)); }
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d, const T& e) { return max(max(max(a,b),max(c,d)),e); }
+
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c) { return maxi(maxi(a,b),c); }
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d) { return maxi(maxi(a,b),maxi(c,d)); }
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d, const T& e) { return maxi(maxi(maxi(a,b),maxi(c,d)),e); }
+
+#if defined(__MACOSX__)
+ __forceinline ssize_t min(ssize_t a, ssize_t b) { return a<b ? a:b; }
+ __forceinline ssize_t max(ssize_t a, ssize_t b) { return a<b ? b:a; }
+#endif
+
+#if defined(__MACOSX__) && !defined(__INTEL_COMPILER)
+ __forceinline void sincosf(float x, float *sin, float *cos) {
+ __sincosf(x,sin,cos);
+ }
+#endif
+
+#if defined(__WIN32__) || defined(__FreeBSD__)
+ __forceinline void sincosf(float x, float *s, float *c) {
+ *s = sinf(x); *c = cosf(x);
+ }
+#endif
+
+ template<typename T> __forceinline T clamp(const T& x, const T& lower = T(zero), const T& upper = T(one)) { return max(min(x,upper),lower); }
+ template<typename T> __forceinline T clampz(const T& x, const T& upper) { return max(T(zero), min(x,upper)); }
+
+ template<typename T> __forceinline T deg2rad ( const T& x ) { return x * T(1.74532925199432957692e-2f); }
+ template<typename T> __forceinline T rad2deg ( const T& x ) { return x * T(5.72957795130823208768e1f); }
+ template<typename T> __forceinline T sin2cos ( const T& x ) { return sqrt(max(T(zero),T(one)-x*x)); }
+ template<typename T> __forceinline T cos2sin ( const T& x ) { return sin2cos(x); }
+
+#if defined(__AVX2__)
+ __forceinline float madd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float msub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float nmadd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float nmsub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+#elif defined (__aarch64__) && defined(__clang__)
+#pragma clang fp contract(fast)
+
+
+__forceinline float madd ( const float a, const float b, const float c) { return a*b + c; }
+__forceinline float msub ( const float a, const float b, const float c) { return a*b - c; }
+__forceinline float nmadd ( const float a, const float b, const float c) { return c - a*b; }
+__forceinline float nmsub ( const float a, const float b, const float c) { return -(c + a*b); }
+
+#pragma clang fp contract(on)
+#else
+ __forceinline float madd ( const float a, const float b, const float c) { return a*b+c; }
+ __forceinline float msub ( const float a, const float b, const float c) { return a*b-c; }
+ __forceinline float nmadd ( const float a, const float b, const float c) { return -a*b+c;}
+ __forceinline float nmsub ( const float a, const float b, const float c) { return -a*b-c; }
+#endif
+
+ /*! random functions */
+ template<typename T> T random() { return T(0); }
+#if defined(_WIN32)
+ template<> __forceinline int random() { return int(rand()) ^ (int(rand()) << 8) ^ (int(rand()) << 16); }
+ template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 8) ^ (uint32_t(rand()) << 16); }
+#else
+ template<> __forceinline int random() { return int(rand()); }
+ template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 16); }
+#endif
+ template<> __forceinline float random() { return rand()/float(RAND_MAX); }
+ template<> __forceinline double random() { return rand()/double(RAND_MAX); }
+
+#if _WIN32
+ __forceinline double drand48() {
+ return double(rand())/double(RAND_MAX);
+ }
+
+ __forceinline void srand48(long seed) {
+ return srand(seed);
+ }
+#endif
+
+ /*! selects */
+ __forceinline bool select(bool s, bool t , bool f) { return s ? t : f; }
+ __forceinline int select(bool s, int t, int f) { return s ? t : f; }
+ __forceinline float select(bool s, float t, float f) { return s ? t : f; }
+
+ __forceinline bool all(bool s) { return s; }
+
+ __forceinline float lerp(const float v0, const float v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ template<typename T>
+ __forceinline T lerp2(const float x0, const float x1, const float x2, const float x3, const T& u, const T& v) {
+ return madd((1.0f-u),madd((1.0f-v),T(x0),v*T(x2)),u*madd((1.0f-v),T(x1),v*T(x3)));
+ }
+
+ /*! exchange */
+ template<typename T> __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; }
+
+
+ template<typename T> __forceinline T prod_diff(const T& a,const T& b,const T& c,const T& d) {
+#if 1//!defined(__aarch64__)
+ return msub(a,b,c*d);
+#else
+ return nmadd(c,d,a*b);
+#endif
+ }
+
+ /*! bit reverse operation */
+ template<class T>
+ __forceinline T bitReverse(const T& vin)
+ {
+ T v = vin;
+ v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
+ v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
+ v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
+ v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
+ v = ( v >> 16 ) | ( v << 16);
+ return v;
+ }
+
+ /*! bit interleave operation */
+ template<class T>
+ __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin)
+ {
+ T x = xin, y = yin, z = zin;
+ x = (x | (x << 16)) & 0x030000FF;
+ x = (x | (x << 8)) & 0x0300F00F;
+ x = (x | (x << 4)) & 0x030C30C3;
+ x = (x | (x << 2)) & 0x09249249;
+
+ y = (y | (y << 16)) & 0x030000FF;
+ y = (y | (y << 8)) & 0x0300F00F;
+ y = (y | (y << 4)) & 0x030C30C3;
+ y = (y | (y << 2)) & 0x09249249;
+
+ z = (z | (z << 16)) & 0x030000FF;
+ z = (z | (z << 8)) & 0x0300F00F;
+ z = (z | (z << 4)) & 0x030C30C3;
+ z = (z | (z << 2)) & 0x09249249;
+
+ return x | (y << 1) | (z << 2);
+ }
+
+#if defined(__AVX2__) && !defined(__aarch64__)
+
+ template<>
+ __forceinline unsigned int bitInterleave(const unsigned int &xi, const unsigned int& yi, const unsigned int& zi)
+ {
+ const unsigned int xx = pdep(xi,0x49249249 /* 0b01001001001001001001001001001001 */ );
+ const unsigned int yy = pdep(yi,0x92492492 /* 0b10010010010010010010010010010010 */);
+ const unsigned int zz = pdep(zi,0x24924924 /* 0b00100100100100100100100100100100 */);
+ return xx | yy | zz;
+ }
+
+#endif
+
+ /*! bit interleave operation for 64bit data types*/
+ template<class T>
+ __forceinline T bitInterleave64(const T& xin, const T& yin, const T& zin){
+ T x = xin & 0x1fffff;
+ T y = yin & 0x1fffff;
+ T z = zin & 0x1fffff;
+
+ x = (x | x << 32) & 0x1f00000000ffff;
+ x = (x | x << 16) & 0x1f0000ff0000ff;
+ x = (x | x << 8) & 0x100f00f00f00f00f;
+ x = (x | x << 4) & 0x10c30c30c30c30c3;
+ x = (x | x << 2) & 0x1249249249249249;
+
+ y = (y | y << 32) & 0x1f00000000ffff;
+ y = (y | y << 16) & 0x1f0000ff0000ff;
+ y = (y | y << 8) & 0x100f00f00f00f00f;
+ y = (y | y << 4) & 0x10c30c30c30c30c3;
+ y = (y | y << 2) & 0x1249249249249249;
+
+ z = (z | z << 32) & 0x1f00000000ffff;
+ z = (z | z << 16) & 0x1f0000ff0000ff;
+ z = (z | z << 8) & 0x100f00f00f00f00f;
+ z = (z | z << 4) & 0x10c30c30c30c30c3;
+ z = (z | z << 2) & 0x1249249249249249;
+
+ return x | (y << 1) | (z << 2);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/math/obbox.h b/thirdparty/embree-aarch64/common/math/obbox.h
new file mode 100644
index 0000000000..032b56904e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/obbox.h
@@ -0,0 +1,39 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bbox.h"
+#include "linearspace3.h"
+
+namespace embree
+{
+ /*! Oriented bounding box */
+ template<typename T>
+ struct OBBox
+ {
+ public:
+
+ __forceinline OBBox () {}
+
+ __forceinline OBBox (EmptyTy)
+ : space(one), bounds(empty) {}
+
+ __forceinline OBBox (const BBox<T>& bounds)
+ : space(one), bounds(bounds) {}
+
+ __forceinline OBBox (const LinearSpace3<T>& space, const BBox<T>& bounds)
+ : space(space), bounds(bounds) {}
+
+ friend embree_ostream operator<<(embree_ostream cout, const OBBox& p) {
+ return cout << "{ space = " << p.space << ", bounds = " << p.bounds << "}";
+ }
+
+ public:
+ LinearSpace3<T> space; //!< orthonormal transformation
+ BBox<T> bounds; //!< bounds in transformed space
+ };
+
+ typedef OBBox<Vec3f> OBBox3f;
+ typedef OBBox<Vec3fa> OBBox3fa;
+}
diff --git a/thirdparty/embree-aarch64/common/math/quaternion.h b/thirdparty/embree-aarch64/common/math/quaternion.h
new file mode 100644
index 0000000000..20c69bc62f
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/quaternion.h
@@ -0,0 +1,254 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec3.h"
+#include "vec4.h"
+
+#include "transcendental.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////
+ // Quaternion Struct
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T>
+ struct QuaternionT
+ {
+ typedef Vec3<T> Vector;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline QuaternionT () { }
+ __forceinline QuaternionT ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; }
+ __forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; }
+
+ __forceinline QuaternionT( const T& r ) : r(r), i(zero), j(zero), k(zero) {}
+ __forceinline explicit QuaternionT( const Vec3<T>& v ) : r(zero), i(v.x), j(v.y), k(v.z) {}
+ __forceinline explicit QuaternionT( const Vec4<T>& v ) : r(v.x), i(v.y), j(v.z), k(v.w) {}
+ __forceinline QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {}
+ __forceinline QuaternionT( const T& r, const Vec3<T>& v ) : r(r), i(v.x), j(v.y), k(v.z) {}
+
+ __inline QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz );
+ __inline QuaternionT( const T& yaw, const T& pitch, const T& roll );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {}
+ __forceinline QuaternionT( OneTy ) : r( one), i(zero), j(zero), k(zero) {}
+
+ /*! return quaternion for rotation around arbitrary axis */
+ static __forceinline QuaternionT rotate(const Vec3<T>& u, const T& r) {
+ return QuaternionT<T>(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u));
+ }
+
+ /*! returns the rotation axis of the quaternion as a vector */
+ __forceinline Vec3<T> v( ) const { return Vec3<T>(i, j, k); }
+
+ public:
+ T r, i, j, k;
+ };
+
+ template<typename T> __forceinline QuaternionT<T> operator *( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a * b.r, a * b.i, a * b.j, a * b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r * b, a.i * b, a.j * b, a.k * b); }
+
+ ////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a ) { return QuaternionT<T>(+a.r, +a.i, +a.j, +a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a ) { return QuaternionT<T>(-a.r, -a.i, -a.j, -a.k); }
+ template<typename T> __forceinline QuaternionT<T> conj ( const QuaternionT<T>& a ) { return QuaternionT<T>(a.r, -a.i, -a.j, -a.k); }
+ template<typename T> __forceinline T abs ( const QuaternionT<T>& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+ template<typename T> __forceinline QuaternionT<T> rcp ( const QuaternionT<T>& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+ template<typename T> __forceinline QuaternionT<T> normalize ( const QuaternionT<T>& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+
+ // evaluates a*q-r
+ template<typename T> __forceinline QuaternionT<T>
+ msub(const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(msub(a, q.r, p.r),
+ msub(a, q.i, p.i),
+ msub(a, q.j, p.j),
+ msub(a, q.k, p.k));
+ }
+ // evaluates a*q-r
+ template<typename T> __forceinline QuaternionT<T>
+ madd (const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(madd(a, q.r, p.r),
+ madd(a, q.i, p.i),
+ madd(a, q.j, p.j),
+ madd(a, q.k, p.k));
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline QuaternionT<T> operator +( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a + b.r, b.i, b.j, b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r + b, a.i, a.j, a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a - b.r, -b.i, -b.j, -b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r - b, a.i, a.j, a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); }
+
+ template<typename T> __forceinline Vec3<T> operator *( const QuaternionT<T>& a, const Vec3<T> & b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const QuaternionT<T>& b ) {
+ return QuaternionT<T>(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k,
+ a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j,
+ a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i,
+ a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r);
+ }
+ template<typename T> __forceinline QuaternionT<T> operator /( const T & a, const QuaternionT<T>& b ) { return a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const T & b ) { return a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a*rcp(b); }
+
+ template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const T & b ) { return a = a+b; }
+ template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a+b; }
+ template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const T & b ) { return a = a-b; }
+ template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a-b; }
+ template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const T & b ) { return a = a*b; }
+ template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*b; }
+ template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const T & b ) { return a = a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*rcp(b); }
+
+ template<typename T, typename M> __forceinline QuaternionT<T>
+ select(const M& m, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(select(m, q.r, p.r),
+ select(m, q.i, p.i),
+ select(m, q.j, p.j),
+ select(m, q.k, p.k));
+ }
+
+
+ template<typename T> __forceinline Vec3<T> xfmPoint ( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline Vec3<T> xfmVector( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline Vec3<T> xfmNormal( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+
+ template<typename T> __forceinline T dot(const QuaternionT<T>& a, const QuaternionT<T>& b) { return a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r == b.r && a.i == b.i && a.j == b.j && a.k == b.k; }
+ template<typename T> __forceinline bool operator !=( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r != b.r || a.i != b.i || a.j != b.j || a.k != b.k; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Orientation Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> QuaternionT<T>::QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz )
+ {
+ if ( vx.x + vy.y + vz.z >= T(zero) )
+ {
+ const T t = T(one) + (vx.x + vy.y + vz.z);
+ const T s = rsqrt(t)*T(0.5f);
+ r = t*s;
+ i = (vy.z - vz.y)*s;
+ j = (vz.x - vx.z)*s;
+ k = (vx.y - vy.x)*s;
+ }
+ else if ( vx.x >= max(vy.y, vz.z) )
+ {
+ const T t = (T(one) + vx.x) - (vy.y + vz.z);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vy.z - vz.y)*s;
+ i = t*s;
+ j = (vx.y + vy.x)*s;
+ k = (vz.x + vx.z)*s;
+ }
+ else if ( vy.y >= vz.z ) // if ( vy.y >= max(vz.z, vx.x) )
+ {
+ const T t = (T(one) + vy.y) - (vz.z + vx.x);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vz.x - vx.z)*s;
+ i = (vx.y + vy.x)*s;
+ j = t*s;
+ k = (vy.z + vz.y)*s;
+ }
+ else //if ( vz.z >= max(vy.y, vx.x) )
+ {
+ const T t = (T(one) + vz.z) - (vx.x + vy.y);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vx.y - vy.x)*s;
+ i = (vz.x + vx.z)*s;
+ j = (vy.z + vz.y)*s;
+ k = t*s;
+ }
+ }
+
+ template<typename T> QuaternionT<T>::QuaternionT( const T& yaw, const T& pitch, const T& roll )
+ {
+ const T cya = cos(yaw *T(0.5f));
+ const T cpi = cos(pitch*T(0.5f));
+ const T cro = cos(roll *T(0.5f));
+ const T sya = sin(yaw *T(0.5f));
+ const T spi = sin(pitch*T(0.5f));
+ const T sro = sin(roll *T(0.5f));
+ r = cro*cya*cpi + sro*sya*spi;
+ i = cro*cya*spi + sro*sya*cpi;
+ j = cro*sya*cpi - sro*cya*spi;
+ k = sro*cya*cpi - cro*sya*spi;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ //////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const QuaternionT<T>& q) {
+ return cout << "{ r = " << q.r << ", i = " << q.i << ", j = " << q.j << ", k = " << q.k << " }";
+ }
+
+ /*! default template instantiations */
+ typedef QuaternionT<float> Quaternion3f;
+ typedef QuaternionT<double> Quaternion3d;
+
+ template<int N> using Quaternion3vf = QuaternionT<vfloat<N>>;
+ typedef QuaternionT<vfloat<4>> Quaternion3vf4;
+ typedef QuaternionT<vfloat<8>> Quaternion3vf8;
+ typedef QuaternionT<vfloat<16>> Quaternion3vf16;
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Interpolation
+ //////////////////////////////////////////////////////////////////////////////
+ template<typename T>
+ __forceinline QuaternionT<T>lerp(const QuaternionT<T>& q0,
+ const QuaternionT<T>& q1,
+ const T& factor)
+ {
+ QuaternionT<T> q;
+ q.r = lerp(q0.r, q1.r, factor);
+ q.i = lerp(q0.i, q1.i, factor);
+ q.j = lerp(q0.j, q1.j, factor);
+ q.k = lerp(q0.k, q1.k, factor);
+ return q;
+ }
+
+ template<typename T>
+ __forceinline QuaternionT<T> slerp(const QuaternionT<T>& q0,
+ const QuaternionT<T>& q1_,
+ const T& t)
+ {
+ T cosTheta = dot(q0, q1_);
+ QuaternionT<T> q1 = select(cosTheta < 0.f, -q1_, q1_);
+ cosTheta = select(cosTheta < 0.f, -cosTheta, cosTheta);
+ if (unlikely(all(cosTheta > 0.9995f))) {
+ return normalize(lerp(q0, q1, t));
+ }
+ const T phi = t * fastapprox::acos(cosTheta);
+ T sinPhi, cosPhi;
+ fastapprox::sincos(phi, sinPhi, cosPhi);
+ QuaternionT<T> qperp = sinPhi * normalize(msub(cosTheta, q0, q1));
+ return msub(cosPhi, q0, qperp);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/math/range.h b/thirdparty/embree-aarch64/common/math/range.h
new file mode 100644
index 0000000000..762d9cd9ea
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/range.h
@@ -0,0 +1,137 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../math/math.h"
+
+namespace embree
+{
+ template<typename Ty>
+ struct range
+ {
+ __forceinline range() {}
+
+ __forceinline range(const Ty& begin)
+ : _begin(begin), _end(begin+1) {}
+
+ __forceinline range(const Ty& begin, const Ty& end)
+ : _begin(begin), _end(end) {}
+
+ __forceinline range(const range& other)
+ : _begin(other._begin), _end(other._end) {}
+
+ template<typename T1>
+ __forceinline range(const range<T1>& other)
+ : _begin(Ty(other._begin)), _end(Ty(other._end)) {}
+
+ template<typename T1>
+ __forceinline range& operator =(const range<T1>& other) {
+ _begin = other._begin;
+ _end = other._end;
+ return *this;
+ }
+
+ __forceinline Ty begin() const {
+ return _begin;
+ }
+
+ __forceinline Ty end() const {
+ return _end;
+ }
+
+ __forceinline range intersect(const range& r) const {
+ return range (max(_begin,r._begin),min(_end,r._end));
+ }
+
+ __forceinline Ty size() const {
+ return _end - _begin;
+ }
+
+ __forceinline bool empty() const {
+ return _end <= _begin;
+ }
+
+ __forceinline Ty center() const {
+ return (_begin + _end)/2;
+ }
+
+ __forceinline std::pair<range,range> split() const
+ {
+ const Ty _center = center();
+ return std::make_pair(range(_begin,_center),range(_center,_end));
+ }
+
+ __forceinline void split(range& left_o, range& right_o) const
+ {
+ const Ty _center = center();
+ left_o = range(_begin,_center);
+ right_o = range(_center,_end);
+ }
+
+ __forceinline friend bool operator< (const range& r0, const range& r1) {
+ return r0.size() < r1.size();
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const range& r) {
+ return cout << "range [" << r.begin() << ", " << r.end() << "]";
+ }
+
+ Ty _begin, _end;
+ };
+
+ template<typename Ty>
+ range<Ty> make_range(const Ty& begin, const Ty& end) {
+ return range<Ty>(begin,end);
+ }
+
+ template<typename Ty>
+ struct extended_range : public range<Ty>
+ {
+ __forceinline extended_range () {}
+
+ __forceinline extended_range (const Ty& begin)
+ : range<Ty>(begin), _ext_end(begin+1) {}
+
+ __forceinline extended_range (const Ty& begin, const Ty& end)
+ : range<Ty>(begin,end), _ext_end(end) {}
+
+ __forceinline extended_range (const Ty& begin, const Ty& end, const Ty& ext_end)
+ : range<Ty>(begin,end), _ext_end(ext_end) {}
+
+ __forceinline Ty ext_end() const {
+ return _ext_end;
+ }
+
+ __forceinline Ty ext_size() const {
+ return _ext_end - range<Ty>::_begin;
+ }
+
+ __forceinline Ty ext_range_size() const {
+ return _ext_end - range<Ty>::_end;
+ }
+
+ __forceinline bool has_ext_range() const {
+ assert(_ext_end >= range<Ty>::_end);
+ return (_ext_end - range<Ty>::_end) > 0;
+ }
+
+ __forceinline void set_ext_range(const size_t ext_end){
+ assert(ext_end >= range<Ty>::_end);
+ _ext_end = ext_end;
+ }
+
+ __forceinline void move_right(const size_t plus){
+ range<Ty>::_begin += plus;
+ range<Ty>::_end += plus;
+ _ext_end += plus;
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const extended_range& r) {
+ return cout << "extended_range [" << r.begin() << ", " << r.end() << " (" << r.ext_end() << ")]";
+ }
+
+ Ty _ext_end;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/math/transcendental.h b/thirdparty/embree-aarch64/common/math/transcendental.h
new file mode 100644
index 0000000000..6855d82b53
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/transcendental.h
@@ -0,0 +1,525 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+// Transcendental functions from "ispc": https://github.com/ispc/ispc/
+// Most of the transcendental implementations in ispc code come from
+// Solomon Boulos's "syrah": https://github.com/boulos/syrah/
+
+#include "../simd/simd.h"
+
+namespace embree
+{
+
+namespace fastapprox
+{
+
+template <typename T>
+__forceinline T sin(const T &v)
+{
+ static const float piOverTwoVec = 1.57079637050628662109375;
+ static const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+ auto kMod4 = k & 3;
+ auto sinUseCos = (kMod4 == 1 | kMod4 == 3);
+ auto flipSign = (kMod4 > 1);
+
+ // These coefficients are from sollya with fpminimax(sin(x)/x, [|0, 2,
+ // 4, 6, 8, 10|], [|single...|], [0;Pi/2]);
+ static const float sinC2 = -0.16666667163372039794921875;
+ static const float sinC4 = +8.333347737789154052734375e-3;
+ static const float sinC6 = -1.9842604524455964565277099609375e-4;
+ static const float sinC8 = +2.760012648650445044040679931640625e-6;
+ static const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ static const float cosC2 = -0.5;
+ static const float cosC4 = +4.166664183139801025390625e-2;
+ static const float cosC6 = -1.388833043165504932403564453125e-3;
+ static const float cosC8 = +2.47562347794882953166961669921875e-5;
+ static const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto outside = select(sinUseCos, 1., x);
+ auto c2 = select(sinUseCos, T(cosC2), T(sinC2));
+ auto c4 = select(sinUseCos, T(cosC4), T(sinC4));
+ auto c6 = select(sinUseCos, T(cosC6), T(sinC6));
+ auto c8 = select(sinUseCos, T(cosC8), T(sinC8));
+ auto c10 = select(sinUseCos, T(cosC10), T(sinC10));
+
+ auto x2 = x * x;
+ auto formula = x2 * c10 + c8;
+ formula = x2 * formula + c6;
+ formula = x2 * formula + c4;
+ formula = x2 * formula + c2;
+ formula = x2 * formula + 1.;
+ formula *= outside;
+
+ formula = select(flipSign, -formula, formula);
+ return formula;
+}
+
+template <typename T>
+__forceinline T cos(const T &v)
+{
+ static const float piOverTwoVec = 1.57079637050628662109375;
+ static const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+
+ auto kMod4 = k & 3;
+ auto cosUseCos = (kMod4 == 0 | kMod4 == 2);
+ auto flipSign = (kMod4 == 1 | kMod4 == 2);
+
+ const float sinC2 = -0.16666667163372039794921875;
+ const float sinC4 = +8.333347737789154052734375e-3;
+ const float sinC6 = -1.9842604524455964565277099609375e-4;
+ const float sinC8 = +2.760012648650445044040679931640625e-6;
+ const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ const float cosC2 = -0.5;
+ const float cosC4 = +4.166664183139801025390625e-2;
+ const float cosC6 = -1.388833043165504932403564453125e-3;
+ const float cosC8 = +2.47562347794882953166961669921875e-5;
+ const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto outside = select(cosUseCos, 1., x);
+ auto c2 = select(cosUseCos, T(cosC2), T(sinC2));
+ auto c4 = select(cosUseCos, T(cosC4), T(sinC4));
+ auto c6 = select(cosUseCos, T(cosC6), T(sinC6));
+ auto c8 = select(cosUseCos, T(cosC8), T(sinC8));
+ auto c10 = select(cosUseCos, T(cosC10), T(sinC10));
+
+ auto x2 = x * x;
+ auto formula = x2 * c10 + c8;
+ formula = x2 * formula + c6;
+ formula = x2 * formula + c4;
+ formula = x2 * formula + c2;
+ formula = x2 * formula + 1.;
+ formula *= outside;
+
+ formula = select(flipSign, -formula, formula);
+ return formula;
+}
+
+template <typename T>
+__forceinline void sincos(const T &v, T &sinResult, T &cosResult)
+{
+ const float piOverTwoVec = 1.57079637050628662109375;
+ const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+ auto kMod4 = k & 3;
+ auto cosUseCos = ((kMod4 == 0) | (kMod4 == 2));
+ auto sinUseCos = ((kMod4 == 1) | (kMod4 == 3));
+ auto sinFlipSign = (kMod4 > 1);
+ auto cosFlipSign = ((kMod4 == 1) | (kMod4 == 2));
+
+ const float oneVec = +1.;
+ const float sinC2 = -0.16666667163372039794921875;
+ const float sinC4 = +8.333347737789154052734375e-3;
+ const float sinC6 = -1.9842604524455964565277099609375e-4;
+ const float sinC8 = +2.760012648650445044040679931640625e-6;
+ const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ const float cosC2 = -0.5;
+ const float cosC4 = +4.166664183139801025390625e-2;
+ const float cosC6 = -1.388833043165504932403564453125e-3;
+ const float cosC8 = +2.47562347794882953166961669921875e-5;
+ const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto x2 = x * x;
+
+ auto sinFormula = x2 * sinC10 + sinC8;
+ auto cosFormula = x2 * cosC10 + cosC8;
+ sinFormula = x2 * sinFormula + sinC6;
+ cosFormula = x2 * cosFormula + cosC6;
+
+ sinFormula = x2 * sinFormula + sinC4;
+ cosFormula = x2 * cosFormula + cosC4;
+
+ sinFormula = x2 * sinFormula + sinC2;
+ cosFormula = x2 * cosFormula + cosC2;
+
+ sinFormula = x2 * sinFormula + oneVec;
+ cosFormula = x2 * cosFormula + oneVec;
+
+ sinFormula *= x;
+
+ sinResult = select(sinUseCos, cosFormula, sinFormula);
+ cosResult = select(cosUseCos, cosFormula, sinFormula);
+
+ sinResult = select(sinFlipSign, -sinResult, sinResult);
+ cosResult = select(cosFlipSign, -cosResult, cosResult);
+}
+
+template <typename T>
+__forceinline T tan(const T &v)
+{
+ const float piOverFourVec = 0.785398185253143310546875;
+ const float fourOverPiVec = 1.27323949337005615234375;
+
+ auto xLt0 = v < 0.;
+ auto y = select(xLt0, -v, v);
+ auto scaled = y * fourOverPiVec;
+
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ auto x = y - kReal * piOverFourVec;
+
+ // If k & 1, x -= Pi/4
+ auto needOffset = (k & 1) != 0;
+ x = select(needOffset, x - piOverFourVec, x);
+
+ // If k & 3 == (0 or 3) let z = tan_In...(y) otherwise z = -cot_In0To...
+ auto kMod4 = k & 3;
+ auto useCotan = (kMod4 == 1) | (kMod4 == 2);
+
+ const float oneVec = 1.0;
+
+ const float tanC2 = +0.33333075046539306640625;
+ const float tanC4 = +0.13339905440807342529296875;
+ const float tanC6 = +5.3348250687122344970703125e-2;
+ const float tanC8 = +2.46033705770969390869140625e-2;
+ const float tanC10 = +2.892402000725269317626953125e-3;
+ const float tanC12 = +9.500005282461643218994140625e-3;
+
+ const float cotC2 = -0.3333333432674407958984375;
+ const float cotC4 = -2.222204394638538360595703125e-2;
+ const float cotC6 = -2.11752182804048061370849609375e-3;
+ const float cotC8 = -2.0846328698098659515380859375e-4;
+ const float cotC10 = -2.548247357481159269809722900390625e-5;
+ const float cotC12 = -3.5257363606433500535786151885986328125e-7;
+
+ auto x2 = x * x;
+ T z;
+ if (any(useCotan))
+ {
+ auto cotVal = x2 * cotC12 + cotC10;
+ cotVal = x2 * cotVal + cotC8;
+ cotVal = x2 * cotVal + cotC6;
+ cotVal = x2 * cotVal + cotC4;
+ cotVal = x2 * cotVal + cotC2;
+ cotVal = x2 * cotVal + oneVec;
+ // The equation is for x * cot(x) but we need -x * cot(x) for the tan part.
+ cotVal /= -x;
+ z = cotVal;
+ }
+ auto useTan = !useCotan;
+ if (any(useTan))
+ {
+ auto tanVal = x2 * tanC12 + tanC10;
+ tanVal = x2 * tanVal + tanC8;
+ tanVal = x2 * tanVal + tanC6;
+ tanVal = x2 * tanVal + tanC4;
+ tanVal = x2 * tanVal + tanC2;
+ tanVal = x2 * tanVal + oneVec;
+ // Equation was for tan(x)/x
+ tanVal *= x;
+ z = select(useTan, tanVal, z);
+ }
+ return select(xLt0, -z, z);
+}
+
+template <typename T>
+__forceinline T asin(const T &x0)
+{
+ auto isneg = (x0 < 0.f);
+ auto x = abs(x0);
+ auto isnan = (x > 1.f);
+
+ // sollya
+ // fpminimax(((asin(x)-pi/2)/-sqrt(1-x)), [|0,1,2,3,4,5|],[|single...|],
+ // [1e-20;.9999999999999999]);
+ // avg error: 1.1105439e-06, max error 1.3187528e-06
+ auto v = 1.57079517841339111328125f +
+ x * (-0.21450997889041900634765625f +
+ x * (8.78556668758392333984375e-2f +
+ x * (-4.489909112453460693359375e-2f +
+ x * (1.928029954433441162109375e-2f +
+ x * (-4.3095736764371395111083984375e-3f)))));
+
+ v *= -sqrt(1.f - x);
+ v = v + 1.57079637050628662109375f;
+
+ v = select(v < 0.f, T(0.f), v);
+ v = select(isneg, -v, v);
+ v = select(isnan, T(cast_i2f(0x7fc00000)), v);
+
+ return v;
+}
+
+template <typename T>
+__forceinline T acos(const T &v)
+{
+ return 1.57079637050628662109375f - asin(v);
+}
+
+template <typename T>
+__forceinline T atan(const T &v)
+{
+ const float piOverTwoVec = 1.57079637050628662109375;
+ // atan(-x) = -atan(x) (so flip from negative to positive first)
+ // If x > 1 -> atan(x) = Pi/2 - atan(1/x)
+ auto xNeg = v < 0.f;
+ auto xFlipped = select(xNeg, -v, v);
+
+ auto xGt1 = xFlipped > 1.;
+ auto x = select(xGt1, rcpSafe(xFlipped), xFlipped);
+
+ // These coefficients approximate atan(x)/x
+ const float atanC0 = +0.99999988079071044921875;
+ const float atanC2 = -0.3333191573619842529296875;
+ const float atanC4 = +0.199689209461212158203125;
+ const float atanC6 = -0.14015688002109527587890625;
+ const float atanC8 = +9.905083477497100830078125e-2;
+ const float atanC10 = -5.93664981424808502197265625e-2;
+ const float atanC12 = +2.417283318936824798583984375e-2;
+ const float atanC14 = -4.6721356920897960662841796875e-3;
+
+ auto x2 = x * x;
+ auto result = x2 * atanC14 + atanC12;
+ result = x2 * result + atanC10;
+ result = x2 * result + atanC8;
+ result = x2 * result + atanC6;
+ result = x2 * result + atanC4;
+ result = x2 * result + atanC2;
+ result = x2 * result + atanC0;
+ result *= x;
+
+ result = select(xGt1, piOverTwoVec - result, result);
+ result = select(xNeg, -result, result);
+ return result;
+}
+
+template <typename T>
+__forceinline T atan2(const T &y, const T &x)
+{
+ const float piVec = 3.1415926536;
+ // atan2(y, x) =
+ //
+ // atan2(y > 0, x = +-0) -> Pi/2
+ // atan2(y < 0, x = +-0) -> -Pi/2
+ // atan2(y = +-0, x < +0) -> +-Pi
+ // atan2(y = +-0, x >= +0) -> +-0
+ //
+ // atan2(y >= 0, x < 0) -> Pi + atan(y/x)
+ // atan2(y < 0, x < 0) -> -Pi + atan(y/x)
+ // atan2(y, x > 0) -> atan(y/x)
+ //
+ // and then a bunch of code for dealing with infinities.
+ auto yOverX = y * rcpSafe(x);
+ auto atanArg = atan(yOverX);
+ auto xLt0 = x < 0.f;
+ auto yLt0 = y < 0.f;
+ auto offset = select(xLt0,
+ select(yLt0, T(-piVec), T(piVec)), 0.f);
+ return offset + atanArg;
+}
+
+template <typename T>
+__forceinline T exp(const T &v)
+{
+ const float ln2Part1 = 0.6931457519;
+ const float ln2Part2 = 1.4286067653e-6;
+ const float oneOverLn2 = 1.44269502162933349609375;
+
+ auto scaled = v * oneOverLn2;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * ln2Part1;
+ x -= kReal * ln2Part2;
+
+ // These coefficients are for e^x in [0, ln(2)]
+ const float one = 1.;
+ const float c2 = 0.4999999105930328369140625;
+ const float c3 = 0.166668415069580078125;
+ const float c4 = 4.16539050638675689697265625e-2;
+ const float c5 = 8.378830738365650177001953125e-3;
+ const float c6 = 1.304379315115511417388916015625e-3;
+ const float c7 = 2.7555381529964506626129150390625e-4;
+
+ auto result = x * c7 + c6;
+ result = x * result + c5;
+ result = x * result + c4;
+ result = x * result + c3;
+ result = x * result + c2;
+ result = x * result + one;
+ result = x * result + one;
+
+ // Compute 2^k (should differ for float and double, but I'll avoid
+ // it for now and just do floats)
+ const int fpbias = 127;
+ auto biasedN = k + fpbias;
+ auto overflow = kReal > fpbias;
+ // Minimum exponent is -126, so if k is <= -127 (k + 127 <= 0)
+ // we've got underflow. -127 * ln(2) -> -88.02. So the most
+ // negative float input that doesn't result in zero is like -88.
+ auto underflow = kReal <= -fpbias;
+ const int infBits = 0x7f800000;
+ biasedN <<= 23;
+ // Reinterpret this thing as float
+ auto twoToTheN = asFloat(biasedN);
+ // Handle both doubles and floats (hopefully eliding the copy for float)
+ auto elemtype2n = twoToTheN;
+ result *= elemtype2n;
+ result = select(overflow, cast_i2f(infBits), result);
+ result = select(underflow, 0., result);
+ return result;
+}
+
+// Range reduction for logarithms takes log(x) -> log(2^n * y) -> n
+// * log(2) + log(y) where y is the reduced range (usually in [1/2, 1)).
+template <typename T, typename R>
+__forceinline void __rangeReduceLog(const T &input,
+ T &reduced,
+ R &exponent)
+{
+ auto intVersion = asInt(input);
+ // single precision = SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
+ // exponent mask = 0111 1111 1000 0000 0000 0000 0000 0000
+ // 0x7 0xF 0x8 0x0 0x0 0x0 0x0 0x0
+ // non-exponent = 1000 0000 0111 1111 1111 1111 1111 1111
+ // = 0x8 0x0 0x7 0xF 0xF 0xF 0xF 0xF
+
+ //const int exponentMask(0x7F800000)
+ static const int nonexponentMask = 0x807FFFFF;
+
+ // We want the reduced version to have an exponent of -1 which is
+ // -1 + 127 after biasing or 126
+ static const int exponentNeg1 = (126l << 23);
+ // NOTE(boulos): We don't need to mask anything out since we know
+ // the sign bit has to be 0. If it's 1, we need to return infinity/nan
+ // anyway (log(x), x = +-0 -> infinity, x < 0 -> NaN).
+ auto biasedExponent = intVersion >> 23; // This number is [0, 255] but it means [-127, 128]
+
+ auto offsetExponent = biasedExponent + 1; // Treat the number as if it were 2^{e+1} * (1.m)/2
+ exponent = offsetExponent - 127; // get the real value
+
+ // Blend the offset_exponent with the original input (do this in
+ // int for now, until I decide if float can have & and &not)
+ auto blended = (intVersion & nonexponentMask) | (exponentNeg1);
+ reduced = asFloat(blended);
+}
+
+template <typename T> struct ExponentType { };
+template <int N> struct ExponentType<vfloat<N>> { typedef vint<N> Ty; };
+template <> struct ExponentType<float> { typedef int Ty; };
+
+template <typename T>
+__forceinline T log(const T &v)
+{
+ T reduced;
+ typename ExponentType<T>::Ty exponent;
+
+ const int nanBits = 0x7fc00000;
+ const int negInfBits = 0xFF800000;
+ const float nan = cast_i2f(nanBits);
+ const float negInf = cast_i2f(negInfBits);
+ auto useNan = v < 0.;
+ auto useInf = v == 0.;
+ auto exceptional = useNan | useInf;
+ const float one = 1.0;
+
+ auto patched = select(exceptional, one, v);
+ __rangeReduceLog(patched, reduced, exponent);
+
+ const float ln2 = 0.693147182464599609375;
+
+ auto x1 = one - reduced;
+ const float c1 = +0.50000095367431640625;
+ const float c2 = +0.33326041698455810546875;
+ const float c3 = +0.2519190013408660888671875;
+ const float c4 = +0.17541764676570892333984375;
+ const float c5 = +0.3424419462680816650390625;
+ const float c6 = -0.599632322788238525390625;
+ const float c7 = +1.98442304134368896484375;
+ const float c8 = -2.4899270534515380859375;
+ const float c9 = +1.7491014003753662109375;
+
+ auto result = x1 * c9 + c8;
+ result = x1 * result + c7;
+ result = x1 * result + c6;
+ result = x1 * result + c5;
+ result = x1 * result + c4;
+ result = x1 * result + c3;
+ result = x1 * result + c2;
+ result = x1 * result + c1;
+ result = x1 * result + one;
+
+ // Equation was for -(ln(red)/(1-red))
+ result *= -x1;
+ result += toFloat(exponent) * ln2;
+
+ return select(exceptional,
+ select(useNan, T(nan), T(negInf)),
+ result);
+}
+
+template <typename T>
+__forceinline T pow(const T &x, const T &y)
+{
+ auto x1 = abs(x);
+ auto z = exp(y * log(x1));
+
+ // Handle special cases
+ const float twoOver23 = 8388608.0f;
+ auto yInt = y == round(y);
+ auto yOddInt = select(yInt, asInt(abs(y) + twoOver23) << 31, 0); // set sign bit
+
+ // x == 0
+ z = select(x == 0.0f,
+ select(y < 0.0f, T(inf) | signmsk(x),
+ select(y == 0.0f, T(1.0f), asFloat(yOddInt) & x)), z);
+
+ // x < 0
+ auto xNegative = x < 0.0f;
+ if (any(xNegative))
+ {
+ auto z1 = z | asFloat(yOddInt);
+ z1 = select(yInt, z1, std::numeric_limits<float>::quiet_NaN());
+ z = select(xNegative, z1, z);
+ }
+
+ auto xFinite = isfinite(x);
+ auto yFinite = isfinite(y);
+ if (all(xFinite & yFinite))
+ return z;
+
+ // x finite and y infinite
+ z = select(andn(xFinite, yFinite),
+ select(x1 == 1.0f, 1.0f,
+ select((x1 > 1.0f) ^ (y < 0.0f), inf, T(0.0f))), z);
+
+ // x infinite
+ z = select(xFinite, z,
+ select(y == 0.0f, 1.0f,
+ select(y < 0.0f, T(0.0f), inf) | (asFloat(yOddInt) & x)));
+
+ return z;
+}
+
+template <typename T>
+__forceinline T pow(const T &x, float y)
+{
+ return pow(x, T(y));
+}
+
+} // namespace fastapprox
+
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/common/math/vec2.h b/thirdparty/embree-aarch64/common/math/vec2.h
new file mode 100644
index 0000000000..a619459e9c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec2.h
@@ -0,0 +1,235 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ struct Vec2fa;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 2D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec2
+ {
+ enum { N = 2 };
+ union {
+ struct { T x, y; };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2( ) {}
+ __forceinline explicit Vec2( const T& a ) : x(a), y(a) {}
+ __forceinline Vec2( const T& x, const T& y ) : x(x), y(y) {}
+
+ __forceinline Vec2( const Vec2& other ) { x = other.x; y = other.y; }
+ __forceinline Vec2( const Vec2fa& other );
+
+ template<typename T1> __forceinline Vec2( const Vec2<T1>& a ) : x(T(a.x)), y(T(a.y)) {}
+ template<typename T1> __forceinline Vec2& operator =( const Vec2<T1>& other ) { x = other.x; y = other.y; return *this; }
+
+ __forceinline Vec2& operator =( const Vec2& other ) { x = other.x; y = other.y; return *this; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2( ZeroTy ) : x(zero), y(zero) {}
+ __forceinline Vec2( OneTy ) : x(one), y(one) {}
+ __forceinline Vec2( PosInfTy ) : x(pos_inf), y(pos_inf) {}
+ __forceinline Vec2( NegInfTy ) : x(neg_inf), y(neg_inf) {}
+
+#if defined(__WIN32__) && _MSC_VER == 1800 // workaround for older VS 2013 compiler
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 2); return (&x)[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 2); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 2); return components[axis]; }
+ __forceinline T& operator [](const size_t axis ) { assert(axis < 2); return components[axis]; }
+#endif
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a ) { return Vec2<T>(+a.x, +a.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a ) { return Vec2<T>(-a.x, -a.y); }
+ template<typename T> __forceinline Vec2<T> abs ( const Vec2<T>& a ) { return Vec2<T>(abs (a.x), abs (a.y)); }
+ template<typename T> __forceinline Vec2<T> rcp ( const Vec2<T>& a ) { return Vec2<T>(rcp (a.x), rcp (a.y)); }
+ template<typename T> __forceinline Vec2<T> rsqrt ( const Vec2<T>& a ) { return Vec2<T>(rsqrt(a.x), rsqrt(a.y)); }
+ template<typename T> __forceinline Vec2<T> sqrt ( const Vec2<T>& a ) { return Vec2<T>(sqrt (a.x), sqrt (a.y)); }
+ template<typename T> __forceinline Vec2<T> frac ( const Vec2<T>& a ) { return Vec2<T>(frac (a.x), frac (a.y)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x + b.x, a.y + b.y); }
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x + b , a.y + b ); }
+ template<typename T> __forceinline Vec2<T> operator +( const T& a, const Vec2<T>& b ) { return Vec2<T>(a + b.x, a + b.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x - b.x, a.y - b.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x - b , a.y - b ); }
+ template<typename T> __forceinline Vec2<T> operator -( const T& a, const Vec2<T>& b ) { return Vec2<T>(a - b.x, a - b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x * b.x, a.y * b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const T& a, const Vec2<T>& b ) { return Vec2<T>(a * b.x, a * b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x * b , a.y * b ); }
+ template<typename T> __forceinline Vec2<T> operator /( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x / b.x, a.y / b.y); }
+ template<typename T> __forceinline Vec2<T> operator /( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x / b , a.y / b ); }
+ template<typename T> __forceinline Vec2<T> operator /( const T& a, const Vec2<T>& b ) { return Vec2<T>(a / b.x, a / b.y); }
+
+ template<typename T> __forceinline Vec2<T> min(const Vec2<T>& a, const Vec2<T>& b) { return Vec2<T>(min(a.x, b.x), min(a.y, b.y)); }
+ template<typename T> __forceinline Vec2<T> max(const Vec2<T>& a, const Vec2<T>& b) { return Vec2<T>(max(a.x, b.x), max(a.y, b.y)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> madd ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> msub ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmadd ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmsub ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y) ); }
+
+ template<typename T> __forceinline Vec2<T> madd ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( madd(a,b.x,c.x), madd(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> msub ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( msub(a,b.x,c.x), msub(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmadd ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmsub ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y) ); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T>& operator +=( Vec2<T>& a, const Vec2<T>& b ) { a.x += b.x; a.y += b.y; return a; }
+ template<typename T> __forceinline Vec2<T>& operator -=( Vec2<T>& a, const Vec2<T>& b ) { a.x -= b.x; a.y -= b.y; return a; }
+ template<typename T> __forceinline Vec2<T>& operator *=( Vec2<T>& a, const T& b ) { a.x *= b ; a.y *= b ; return a; }
+ template<typename T> __forceinline Vec2<T>& operator /=( Vec2<T>& a, const T& b ) { a.x /= b ; a.y /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec2<T>& a ) { return a.x + a.y; }
+ template<typename T> __forceinline T reduce_mul( const Vec2<T>& a ) { return a.x * a.y; }
+ template<typename T> __forceinline T reduce_min( const Vec2<T>& a ) { return min(a.x, a.y); }
+ template<typename T> __forceinline T reduce_max( const Vec2<T>& a ) { return max(a.x, a.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec2<T>& a, const Vec2<T>& b ) { return a.x == b.x && a.y == b.y; }
+ template<typename T> __forceinline bool operator !=( const Vec2<T>& a, const Vec2<T>& b ) { return a.x != b.x || a.y != b.y; }
+ template<typename T> __forceinline bool operator < ( const Vec2<T>& a, const Vec2<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> shift_right_1( const Vec2<T>& a ) {
+ return Vec2<T>(shift_right_1(a.x),shift_right_1(a.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T dot ( const Vec2<T>& a, const Vec2<T>& b ) { return madd(a.x,b.x,a.y*b.y); }
+ template<typename T> __forceinline Vec2<T> cross ( const Vec2<T>& a ) { return Vec2<T>(-a.y,a.x); }
+ template<typename T> __forceinline T length ( const Vec2<T>& a ) { return sqrt(dot(a,a)); }
+ template<typename T> __forceinline Vec2<T> normalize( const Vec2<T>& a ) { return a*rsqrt(dot(a,a)); }
+ template<typename T> __forceinline T distance ( const Vec2<T>& a, const Vec2<T>& b ) { return length(a-b); }
+ template<typename T> __forceinline T det ( const Vec2<T>& a, const Vec2<T>& b ) { return a.x*b.y - a.y*b.x; }
+
+ template<typename T> __forceinline Vec2<T> normalize_safe( const Vec2<T>& a ) {
+ const T d = dot(a,a); return select(d == T( zero ),a, a*rsqrt(d) );
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> select ( bool s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s,t.x,f.x),select(s,t.y,f.y));
+ }
+
+ template<typename T> __forceinline Vec2<T> select ( const Vec2<bool>& s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y));
+ }
+
+ template<typename T> __forceinline Vec2<T> select ( const typename T::Bool& s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s,t.x,f.x),select(s,t.y,f.y));
+ }
+
+ template<typename T>
+ __forceinline Vec2<T> lerp(const Vec2<T>& v0, const Vec2<T>& v1, const T& t) {
+ return madd(Vec2<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ template<typename T> __forceinline int maxDim ( const Vec2<T>& a )
+ {
+ const Vec2<T> b = abs(a);
+ if (b.x > b.y) return 0;
+ else return 1;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec2<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ")";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Default template instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef Vec2<bool > Vec2b;
+ typedef Vec2<int > Vec2i;
+ typedef Vec2<float> Vec2f;
+}
+
+#include "vec2fa.h"
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+#include "../simd/sse.h"
+#endif
+
+#if defined(__AVX__)
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<> __forceinline Vec2<float>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ template<> __forceinline Vec2<vfloat4>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+
+#if defined(__AVX__)
+ template<> __forceinline Vec2<vfloat8>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec2<vfloat16>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec2fa.h b/thirdparty/embree-aarch64/common/math/vec2fa.h
new file mode 100644
index 0000000000..451ecd556c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec2fa.h
@@ -0,0 +1,317 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec2fa Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec2fa
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 2 };
+ union {
+ __m128 m128;
+ struct { float x,y,az,aw; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa( ) {}
+ __forceinline Vec2fa( const __m128 a ) : m128(a) {}
+
+ __forceinline Vec2fa ( const Vec2<float>& other ) { x = other.x; y = other.y; }
+ __forceinline Vec2fa& operator =( const Vec2<float>& other ) { x = other.x; y = other.y; return *this; }
+
+ __forceinline Vec2fa ( const Vec2fa& other ) { m128 = other.m128; }
+ __forceinline Vec2fa& operator =( const Vec2fa& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec2fa( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec2fa( const float x, const float y) : m128(_mm_set_ps(y, y, y, x)) {}
+
+ __forceinline explicit Vec2fa( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec2fa load( const void* const a ) {
+ return Vec2fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1))));
+ }
+
+ static __forceinline Vec2fa loadu( const void* const a ) {
+ return Vec2fa(_mm_and_ps(_mm_loadu_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1))));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec2fa& v ) {
+ _mm_storeu_ps((float*)ptr,v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec2fa( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec2fa( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec2fa( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 2); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 2); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa operator +( const Vec2fa& a ) { return a; }
+ __forceinline Vec2fa operator -( const Vec2fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline Vec2fa abs ( const Vec2fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline Vec2fa sign ( const Vec2fa& a ) {
+ return blendv_ps(Vec2fa(one), -Vec2fa(one), _mm_cmplt_ps (a,Vec2fa(zero)));
+ }
+
+ __forceinline Vec2fa rcp ( const Vec2fa& a )
+ {
+#if defined(__aarch64__)
+ __m128 reciprocal = _mm_rcp_ps(a.m128);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ return (const Vec2fa)reciprocal;
+#else
+#if defined(__AVX512VL__)
+ const Vec2fa r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec2fa r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec2fa res = _mm_mul_ps(r,_mm_fnmadd_ps(r, a, vfloat4(2.0f)));
+#else
+ const Vec2fa res = _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+#endif //defined(__aarch64__)
+ }
+
+ __forceinline Vec2fa sqrt ( const Vec2fa& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec2fa sqr ( const Vec2fa& a ) { return _mm_mul_ps(a,a); }
+
+ __forceinline Vec2fa rsqrt( const Vec2fa& a )
+ {
+#if defined(__aarch64__)
+ __m128 r = _mm_rsqrt_ps(a.m128);
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ return r;
+#else
+
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+
+#endif
+ }
+
+ __forceinline Vec2fa zero_fix(const Vec2fa& a) {
+ return blendv_ps(a, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec2fa rcp_safe(const Vec2fa& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec2fa log ( const Vec2fa& a ) {
+ return Vec2fa(logf(a.x),logf(a.y));
+ }
+
+ __forceinline Vec2fa exp ( const Vec2fa& a ) {
+ return Vec2fa(expf(a.x),expf(a.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa operator +( const Vec2fa& a, const Vec2fa& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator -( const Vec2fa& a, const Vec2fa& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator *( const Vec2fa& a, const Vec2fa& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator *( const Vec2fa& a, const float b ) { return a * Vec2fa(b); }
+ __forceinline Vec2fa operator *( const float a, const Vec2fa& b ) { return Vec2fa(a) * b; }
+ __forceinline Vec2fa operator /( const Vec2fa& a, const Vec2fa& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec2fa operator /( const Vec2fa& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec2fa operator /( const float a, const Vec2fa& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec2fa min( const Vec2fa& a, const Vec2fa& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec2fa max( const Vec2fa& a, const Vec2fa& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec2fa mini(const Vec2fa& a, const Vec2fa& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec2fa maxi(const Vec2fa& a, const Vec2fa& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec2fa pow ( const Vec2fa& a, const float& b ) {
+ return Vec2fa(powf(a.x,b),powf(a.y,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec2fa madd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fmadd_ps(a,b,c); }
+ __forceinline Vec2fa msub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fmsub_ps(a,b,c); }
+ __forceinline Vec2fa nmadd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fnmadd_ps(a,b,c); }
+ __forceinline Vec2fa nmsub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fnmsub_ps(a,b,c); }
+#else
+ __forceinline Vec2fa madd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return a*b+c; }
+ __forceinline Vec2fa msub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return a*b-c; }
+ __forceinline Vec2fa nmadd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return -a*b+c;}
+ __forceinline Vec2fa nmsub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return -a*b-c; }
+#endif
+
+ __forceinline Vec2fa madd ( const float a, const Vec2fa& b, const Vec2fa& c) { return madd(Vec2fa(a),b,c); }
+ __forceinline Vec2fa msub ( const float a, const Vec2fa& b, const Vec2fa& c) { return msub(Vec2fa(a),b,c); }
+ __forceinline Vec2fa nmadd ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmadd(Vec2fa(a),b,c); }
+ __forceinline Vec2fa nmsub ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmsub(Vec2fa(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa& operator +=( Vec2fa& a, const Vec2fa& b ) { return a = a + b; }
+ __forceinline Vec2fa& operator -=( Vec2fa& a, const Vec2fa& b ) { return a = a - b; }
+ __forceinline Vec2fa& operator *=( Vec2fa& a, const Vec2fa& b ) { return a = a * b; }
+ __forceinline Vec2fa& operator *=( Vec2fa& a, const float b ) { return a = a * b; }
+ __forceinline Vec2fa& operator /=( Vec2fa& a, const Vec2fa& b ) { return a = a / b; }
+ __forceinline Vec2fa& operator /=( Vec2fa& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Vec2fa& v) { return v.x+v.y; }
+ __forceinline float reduce_mul(const Vec2fa& v) { return v.x*v.y; }
+ __forceinline float reduce_min(const Vec2fa& v) { return min(v.x,v.y); }
+ __forceinline float reduce_max(const Vec2fa& v) { return max(v.x,v.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec2fa& a, const Vec2fa& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 3) == 3; }
+ __forceinline bool operator !=( const Vec2fa& a, const Vec2fa& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 3) != 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec2fa& a, const Vec2fa& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a,b,0x3F));
+ }
+#else
+ __forceinline float dot ( const Vec2fa& a, const Vec2fa& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec2fa cross ( const Vec2fa& a ) {
+ return Vec2fa(-a.y,a.x);
+ }
+
+ __forceinline float sqr_length ( const Vec2fa& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec2fa& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec2fa& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec2fa& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec2fa normalize( const Vec2fa& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec2fa& a, const Vec2fa& b ) { return length(a-b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa select( bool s, const Vec2fa& t, const Vec2fa& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f, t, mask);
+ }
+
+ __forceinline Vec2fa lerp(const Vec2fa& v0, const Vec2fa& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec2fa& a )
+ {
+ const Vec2fa b = abs(a);
+ if (b.x > b.y) return 0;
+ else return 1;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+__forceinline Vec2fa floor(const Vec2fa& a) { return vrndmq_f32(a); }
+__forceinline Vec2fa ceil (const Vec2fa& a) { return vrndpq_f32(a); }
+//__forceinline Vec2fa trunc(const Vec2fa& a) { return vrndq_f32(a); }
+#elif defined (__SSE4_1__)
+ //__forceinline Vec2fa trunc( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec2fa floor( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec2fa ceil ( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+#else
+ //__forceinline Vec2fa trunc( const Vec2fa& a ) { return Vec2fa(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec2fa floor( const Vec2fa& a ) { return Vec2fa(floorf(a.x),floorf(a.y)); }
+ __forceinline Vec2fa ceil ( const Vec2fa& a ) { return Vec2fa(ceilf (a.x),ceilf (a.y)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec2fa& a) {
+ return cout << "(" << a.x << ", " << a.y << ")";
+ }
+
+ typedef Vec2fa Vec2fa_t;
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec3.h b/thirdparty/embree-aarch64/common/math/vec3.h
new file mode 100644
index 0000000000..1870321715
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec3.h
@@ -0,0 +1,349 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ struct Vec3fa;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 3D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec3
+ {
+ enum { N = 3 };
+
+ union {
+ struct {
+ T x, y, z;
+ };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3( ) {}
+ __forceinline explicit Vec3( const T& a ) : x(a), y(a), z(a) {}
+ __forceinline Vec3( const T& x, const T& y, const T& z ) : x(x), y(y), z(z) {}
+
+ __forceinline Vec3( const Vec3& other ) { x = other.x; y = other.y; z = other.z; }
+ __forceinline Vec3( const Vec3fa& other );
+
+ template<typename T1> __forceinline Vec3( const Vec3<T1>& a ) : x(T(a.x)), y(T(a.y)), z(T(a.z)) {}
+ template<typename T1> __forceinline Vec3& operator =(const Vec3<T1>& other) { x = other.x; y = other.y; z = other.z; return *this; }
+
+ __forceinline Vec3& operator =(const Vec3& other) { x = other.x; y = other.y; z = other.z; return *this; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3( ZeroTy ) : x(zero), y(zero), z(zero) {}
+ __forceinline Vec3( OneTy ) : x(one), y(one), z(one) {}
+ __forceinline Vec3( PosInfTy ) : x(pos_inf), y(pos_inf), z(pos_inf) {}
+ __forceinline Vec3( NegInfTy ) : x(neg_inf), y(neg_inf), z(neg_inf) {}
+
+#if defined(__WIN32__) && (_MSC_VER == 1800) // workaround for older VS 2013 compiler
+ __forceinline const T& operator []( const size_t axis ) const { assert(axis < 3); return (&x)[axis]; }
+ __forceinline T& operator []( const size_t axis ) { assert(axis < 3); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 3); return components[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 3); return components[axis]; }
+#endif
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> operator +( const Vec3<T>& a ) { return Vec3<T>(+a.x, +a.y, +a.z); }
+ template<typename T> __forceinline Vec3<T> operator -( const Vec3<T>& a ) { return Vec3<T>(-a.x, -a.y, -a.z); }
+ template<typename T> __forceinline Vec3<T> abs ( const Vec3<T>& a ) { return Vec3<T>(abs (a.x), abs (a.y), abs (a.z)); }
+ template<typename T> __forceinline Vec3<T> rcp ( const Vec3<T>& a ) { return Vec3<T>(rcp (a.x), rcp (a.y), rcp (a.z)); }
+ template<typename T> __forceinline Vec3<T> rsqrt ( const Vec3<T>& a ) { return Vec3<T>(rsqrt(a.x), rsqrt(a.y), rsqrt(a.z)); }
+ template<typename T> __forceinline Vec3<T> sqrt ( const Vec3<T>& a ) { return Vec3<T>(sqrt (a.x), sqrt (a.y), sqrt (a.z)); }
+
+ template<typename T> __forceinline Vec3<T> zero_fix( const Vec3<T>& a )
+ {
+ return Vec3<T>(select(abs(a.x)<min_rcp_input,T(min_rcp_input),a.x),
+ select(abs(a.y)<min_rcp_input,T(min_rcp_input),a.y),
+ select(abs(a.z)<min_rcp_input,T(min_rcp_input),a.z));
+ }
+ template<typename T> __forceinline Vec3<T> rcp_safe(const Vec3<T>& a) { return rcp(zero_fix(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> operator +( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x + b.x, a.y + b.y, a.z + b.z); }
+ template<typename T> __forceinline Vec3<T> operator -( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x - b.x, a.y - b.y, a.z - b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x * b.x, a.y * b.y, a.z * b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const T& a, const Vec3<T>& b ) { return Vec3<T>(a * b.x, a * b.y, a * b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const Vec3<T>& a, const T& b ) { return Vec3<T>(a.x * b , a.y * b , a.z * b ); }
+ template<typename T> __forceinline Vec3<T> operator /( const Vec3<T>& a, const T& b ) { return Vec3<T>(a.x / b , a.y / b , a.z / b ); }
+ template<typename T> __forceinline Vec3<T> operator /( const T& a, const Vec3<T>& b ) { return Vec3<T>(a / b.x, a / b.y, a / b.z); }
+ template<typename T> __forceinline Vec3<T> operator /( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x / b.x, a.y / b.y, a.z / b.z); }
+
+ template<typename T> __forceinline Vec3<T> min(const Vec3<T>& a, const Vec3<T>& b) { return Vec3<T>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); }
+ template<typename T> __forceinline Vec3<T> max(const Vec3<T>& a, const Vec3<T>& b) { return Vec3<T>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); }
+
+ template<typename T> __forceinline Vec3<T> operator >>( const Vec3<T>& a, const int b ) { return Vec3<T>(a.x >> b, a.y >> b, a.z >> b); }
+ template<typename T> __forceinline Vec3<T> operator <<( const Vec3<T>& a, const int b ) { return Vec3<T>(a.x << b, a.y << b, a.z << b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> madd ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> msub ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> nmadd ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y),nmadd(a.z,b.z,c.z));}
+ template<typename T> __forceinline Vec3<T> nmsub ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y),nmsub(a.z,b.z,c.z)); }
+
+ template<typename T> __forceinline Vec3<T> madd ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( madd(a,b.x,c.x), madd(a,b.y,c.y), madd(a,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> msub ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( msub(a,b.x,c.x), msub(a,b.y,c.y), msub(a,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> nmadd ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y),nmadd(a,b.z,c.z));}
+ template<typename T> __forceinline Vec3<T> nmsub ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y),nmsub(a,b.z,c.z)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T>& operator +=( Vec3<T>& a, const T b ) { a.x += b; a.y += b; a.z += b; return a; }
+ template<typename T> __forceinline Vec3<T>& operator +=( Vec3<T>& a, const Vec3<T>& b ) { a.x += b.x; a.y += b.y; a.z += b.z; return a; }
+ template<typename T> __forceinline Vec3<T>& operator -=( Vec3<T>& a, const Vec3<T>& b ) { a.x -= b.x; a.y -= b.y; a.z -= b.z; return a; }
+ template<typename T> __forceinline Vec3<T>& operator *=( Vec3<T>& a, const T& b ) { a.x *= b ; a.y *= b ; a.z *= b ; return a; }
+ template<typename T> __forceinline Vec3<T>& operator /=( Vec3<T>& a, const T& b ) { a.x /= b ; a.y /= b ; a.z /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec3<T>& a ) { return a.x + a.y + a.z; }
+ template<typename T> __forceinline T reduce_mul( const Vec3<T>& a ) { return a.x * a.y * a.z; }
+ template<typename T> __forceinline T reduce_min( const Vec3<T>& a ) { return min(a.x, a.y, a.z); }
+ template<typename T> __forceinline T reduce_max( const Vec3<T>& a ) { return max(a.x, a.y, a.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec3<T>& a, const Vec3<T>& b ) { return a.x == b.x && a.y == b.y && a.z == b.z; }
+ template<typename T> __forceinline bool operator !=( const Vec3<T>& a, const Vec3<T>& b ) { return a.x != b.x || a.y != b.y || a.z != b.z; }
+ template<typename T> __forceinline bool operator < ( const Vec3<T>& a, const Vec3<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> shift_right_1( const Vec3<T>& a ) {
+ return Vec3<T>(shift_right_1(a.x),shift_right_1(a.y),shift_right_1(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> select ( bool s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z));
+ }
+
+ template<typename T> __forceinline Vec3<T> select ( const Vec3<bool>& s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y),select(s.z,t.z,f.z));
+ }
+
+ template<typename T> __forceinline Vec3<T> select ( const typename T::Bool& s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z));
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> lerp(const Vec3<T>& v0, const Vec3<T>& v1, const T& t) {
+ return madd(Vec3<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ template<typename T> __forceinline int maxDim ( const Vec3<T>& a )
+ {
+ const Vec3<T> b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<bool> eq_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x==b.x,a.y==b.y,a.z==b.z); }
+ template<typename T> __forceinline Vec3<bool> neq_mask(const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x!=b.x,a.y!=b.y,a.z!=b.z); }
+ template<typename T> __forceinline Vec3<bool> lt_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x< b.x,a.y< b.y,a.z< b.z); }
+ template<typename T> __forceinline Vec3<bool> le_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x<=b.x,a.y<=b.y,a.z<=b.z); }
+ template<typename T> __forceinline Vec3<bool> gt_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x> b.x,a.y> b.y,a.z> b.z); }
+ template<typename T> __forceinline Vec3<bool> ge_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x>=b.x,a.y>=b.y,a.z>=b.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T sqr ( const Vec3<T>& a ) { return dot(a,a); }
+ template<typename T> __forceinline T dot ( const Vec3<T>& a, const Vec3<T>& b ) { return madd(a.x,b.x,madd(a.y,b.y,a.z*b.z)); }
+ template<typename T> __forceinline T length ( const Vec3<T>& a ) { return sqrt(sqr(a)); }
+ template<typename T> __forceinline T rcp_length( const Vec3<T>& a ) { return rsqrt(sqr(a)); }
+ template<typename T> __forceinline Vec3<T> normalize( const Vec3<T>& a ) { return a*rsqrt(sqr(a)); }
+ template<typename T> __forceinline T distance ( const Vec3<T>& a, const Vec3<T>& b ) { return length(a-b); }
+ template<typename T> __forceinline Vec3<T> cross ( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(prod_diff(a.y,b.z,a.z,b.y), prod_diff(a.z,b.x,a.x,b.z), prod_diff(a.x,b.y,a.y,b.x)); }
+ template<typename T> __forceinline Vec3<T> stable_triangle_normal( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c )
+ {
+ const T ab_x = a.z*b.y, ab_y = a.x*b.z, ab_z = a.y*b.x;
+ const T bc_x = b.z*c.y, bc_y = b.x*c.z, bc_z = b.y*c.x;
+ const Vec3<T> cross_ab(msub(a.y,b.z,ab_x), msub(a.z,b.x,ab_y), msub(a.x,b.y,ab_z));
+ const Vec3<T> cross_bc(msub(b.y,c.z,bc_x), msub(b.z,c.x,bc_y), msub(b.x,c.y,bc_z));
+ const auto sx = abs(ab_x) < abs(bc_x);
+ const auto sy = abs(ab_y) < abs(bc_y);
+ const auto sz = abs(ab_z) < abs(bc_z);
+ return Vec3<T>(select(sx,cross_ab.x,cross_bc.x),
+ select(sy,cross_ab.y,cross_bc.y),
+ select(sz,cross_ab.z,cross_bc.z));
+ }
+
+ template<typename T> __forceinline T sum ( const Vec3<T>& a ) { return a.x+a.y+a.z; }
+
+ template<typename T> __forceinline T halfArea ( const Vec3<T>& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ template<typename T> __forceinline T area ( const Vec3<T>& d ) { return 2.0f*halfArea(d); }
+
+ template<typename T> __forceinline Vec3<T> normalize_safe( const Vec3<T>& a ) {
+ const T d = dot(a,a); return select(d == T( zero ), a , a*rsqrt(d) );
+ }
+
+ template<typename T> __forceinline T sqr_point_to_line_distance(const Vec3<T>& P, const Vec3<T>& Q0, const Vec3<T>& Q1)
+ {
+ const Vec3<T> N = cross(P-Q0,Q1-Q0);
+ const Vec3<T> D = Q1-Q0;
+ return dot(N,N)*rcp(dot(D,D));
+ }
+
+ template<typename T> __forceinline T sqr_point_to_line_distance(const Vec3<T>& PmQ0, const Vec3<T>& Q1mQ0)
+ {
+ const Vec3<T> N = cross(PmQ0,Q1mQ0);
+ const Vec3<T> D = Q1mQ0;
+ return dot(N,N)*rcp(dot(D,D));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+ typedef Vec3<bool > Vec3b;
+ typedef Vec3<int > Vec3i;
+ typedef Vec3<float> Vec3f;
+}
+
+#include "vec3ba.h"
+#include "vec3ia.h"
+#include "vec3fa.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+#include "../simd/sse.h"
+#endif
+
+#if defined(__AVX__)
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<typename Out, typename In>
+ __forceinline Vec3<Out> broadcast(const Vec3<In>& a, const size_t k) {
+ return Vec3<Out>(Out(a.x[k]), Out(a.y[k]), Out(a.z[k]));
+ }
+
+ template<> __forceinline Vec3<float>::Vec3(const Vec3fa& a) { x = a.x; y = a.y; z = a.z; }
+
+#if defined(__AVX__)
+ template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
+ x = a.x; y = a.y; z = a.z;
+ }
+#elif defined(__SSE__) || defined(__ARM_NEON)
+ template<>
+ __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
+ const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v);
+ }
+#endif
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ __forceinline Vec3<vfloat4> broadcast4f(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
+ }
+
+ template<>
+ __forceinline Vec3<vfloat4> broadcast<vfloat4,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline Vec3<vfloat4> shuffle(const Vec3<vfloat4>& b) {
+ return Vec3<vfloat4>(shuffle<i0,i1,i2,i3>(b.x), shuffle<i0,i1,i2,i3>(b.y), shuffle<i0,i1,i2,i3>(b.z));
+ }
+#endif
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Vec3<vfloat8>::Vec3(const Vec3fa& a) {
+ x = a.x; y = a.y; z = a.z;
+ }
+ __forceinline Vec3<vfloat4> broadcast4f(const Vec3<vfloat8>& a, const size_t k) {
+ return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
+ }
+ __forceinline Vec3<vfloat8> broadcast8f(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+ __forceinline Vec3<vfloat8> broadcast8f(const Vec3<vfloat8>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+
+ template<>
+ __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+ template<>
+ __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat8>(const Vec3<vfloat8>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline Vec3<vfloat8> shuffle(const Vec3<vfloat8>& b) {
+ return Vec3<vfloat8>(shuffle<i0,i1,i2,i3>(b.x), shuffle<i0,i1,i2,i3>(b.y), shuffle<i0,i1,i2,i3>(b.z));
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec3<vfloat16>::Vec3(const Vec3fa& a) : x(a.x), y(a.y), z(a.z) {}
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec3ba.h b/thirdparty/embree-aarch64/common/math/vec3ba.h
new file mode 100644
index 0000000000..90f31739c2
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec3ba.h
@@ -0,0 +1,120 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3ba Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3ba
+ {
+ ALIGNED_STRUCT_(16);
+
+ union {
+ __m128 m128;
+ struct { int x,y,z; };
+ };
+
+ typedef int Scalar;
+ enum { N = 3 };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba( ) {}
+ __forceinline Vec3ba( const __m128 input ) : m128(input) {}
+ __forceinline Vec3ba( const Vec3ba& other ) : m128(other.m128) {}
+ __forceinline Vec3ba& operator =(const Vec3ba& other) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3ba( bool a )
+ : m128(mm_lookupmask_ps[(size_t(a) << 3) | (size_t(a) << 2) | (size_t(a) << 1) | size_t(a)]) {}
+ __forceinline Vec3ba( bool a, bool b, bool c)
+ : m128(mm_lookupmask_ps[(size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba( FalseTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3ba( TrueTy ) : m128(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()))) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba operator !( const Vec3ba& a ) { return _mm_xor_ps(a.m128, Vec3ba(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba operator &( const Vec3ba& a, const Vec3ba& b ) { return _mm_and_ps(a.m128, b.m128); }
+ __forceinline Vec3ba operator |( const Vec3ba& a, const Vec3ba& b ) { return _mm_or_ps (a.m128, b.m128); }
+ __forceinline Vec3ba operator ^( const Vec3ba& a, const Vec3ba& b ) { return _mm_xor_ps(a.m128, b.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba& operator &=( Vec3ba& a, const Vec3ba& b ) { return a = a & b; }
+ __forceinline Vec3ba& operator |=( Vec3ba& a, const Vec3ba& b ) { return a = a | b; }
+ __forceinline Vec3ba& operator ^=( Vec3ba& a, const Vec3ba& b ) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3ba& a, const Vec3ba& b ) {
+ return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_castps_si128(a.m128), _mm_castps_si128(b.m128)))) & 7) == 7;
+ }
+ __forceinline bool operator !=( const Vec3ba& a, const Vec3ba& b ) {
+ return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_castps_si128(a.m128), _mm_castps_si128(b.m128)))) & 7) != 7;
+ }
+ __forceinline bool operator < ( const Vec3ba& a, const Vec3ba& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and( const Vec3ba& a ) { return (_mm_movemask_ps(a) & 0x7) == 0x7; }
+ __forceinline bool reduce_or ( const Vec3ba& a ) { return (_mm_movemask_ps(a) & 0x7) != 0x0; }
+
+ __forceinline bool all ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) == 0x7; }
+ __forceinline bool any ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) != 0x0; }
+ __forceinline bool none ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) == 0x0; }
+
+ __forceinline size_t movemask(const Vec3ba& a) { return _mm_movemask_ps(a) & 0x7; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3ba& a) {
+ return cout << "(" << (a.x ? "1" : "0") << ", " << (a.y ? "1" : "0") << ", " << (a.z ? "1" : "0") << ")";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec3fa.h b/thirdparty/embree-aarch64/common/math/vec3fa.h
new file mode 100644
index 0000000000..6163cfb596
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec3fa.h
@@ -0,0 +1,810 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3fa Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3fa
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 3 };
+ union {
+ __m128 m128;
+ struct { float x,y,z; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa( ) {}
+ __forceinline Vec3fa( const __m128 a ) : m128(a) {}
+
+ __forceinline Vec3fa ( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); }
+ //__forceinline Vec3fa& operator =( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); return *this; }
+
+ __forceinline Vec3fa ( const Vec3fa& other ) { m128 = other.m128; }
+ __forceinline Vec3fa& operator =( const Vec3fa& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3fa( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec3fa( const float x, const float y, const float z) : m128(_mm_set_ps(0, z, y, x)) {}
+
+ __forceinline explicit Vec3fa( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline explicit operator const vfloat4() const { return vfloat4(m128); }
+ __forceinline explicit operator const vint4() const { return vint4(_mm_cvtps_epi32(m128)); }
+ __forceinline explicit operator const Vec2fa() const { return Vec2fa(m128); }
+ __forceinline explicit operator const Vec3ia() const { return Vec3ia(_mm_cvtps_epi32(m128)); }
+
+ //__forceinline operator const __m128&() const { return m128; }
+ //__forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec3fa load( const void* const a ) {
+#if defined(__aarch64__)
+ __m128 t = _mm_load_ps((float*)a);
+ t[3] = 0.0f;
+ return Vec3fa(t);
+#else
+ return Vec3fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
+#endif
+ }
+
+ static __forceinline Vec3fa loadu( const void* const a ) {
+ return Vec3fa(_mm_loadu_ps((float*)a));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec3fa& v ) {
+ _mm_storeu_ps((float*)ptr,v.m128);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3fa( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec3fa( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec3fa( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa operator +( const Vec3fa& a ) { return a; }
+ __forceinline Vec3fa operator -( const Vec3fa& a ) {
+#if defined(__aarch64__)
+ return vnegq_f32(a.m128);
+#else
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+
+ return _mm_xor_ps(a.m128, mask);
+#endif
+ }
+ __forceinline Vec3fa abs ( const Vec3fa& a ) {
+#if defined(__aarch64__)
+ return _mm_abs_ps(a.m128);
+#else
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+#endif
+ }
+ __forceinline Vec3fa sign ( const Vec3fa& a ) {
+#if defined(__aarch64__)
+ Vec3fa r = blendv_ps(vOne, vmOne, _mm_cmplt_ps (a.m128,vdupq_n_f32(0.0f)));
+ return r;
+#else
+ return blendv_ps(Vec3fa(one).m128, (-Vec3fa(one)).m128, _mm_cmplt_ps (a.m128,Vec3fa(zero).m128));
+#endif
+ }
+
+ __forceinline Vec3fa rcp ( const Vec3fa& a )
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ return vdivq_f32(vdupq_n_f32(1.0f),a.m128);
+#elif defined(__aarch64__)
+ __m128 reciprocal = _mm_rcp_ps(a.m128);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(a.m128, reciprocal), reciprocal);
+ return (const Vec3fa)reciprocal;
+#else
+
+#if defined(__AVX512VL__)
+ const Vec3fa r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec3fa r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec3fa res = _mm_mul_ps(r.m128,_mm_fnmadd_ps(r.m128, a.m128, vfloat4(2.0f)));
+#else
+ const Vec3fa res = _mm_mul_ps(r.m128,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r.m128, a.m128)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+#endif //defined(__aarch64__)
+ }
+
+ __forceinline Vec3fa sqrt ( const Vec3fa& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec3fa sqr ( const Vec3fa& a ) { return _mm_mul_ps(a.m128,a.m128); }
+
+ __forceinline Vec3fa rsqrt( const Vec3fa& a )
+ {
+#if defined(__aarch64__)
+ __m128 r = _mm_rsqrt_ps(a.m128);
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a.m128, r), r));
+ return r;
+#else
+
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#endif
+ }
+
+ __forceinline Vec3fa zero_fix(const Vec3fa& a) {
+ return blendv_ps(a.m128, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec3fa rcp_safe(const Vec3fa& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec3fa log ( const Vec3fa& a ) {
+ return Vec3fa(logf(a.x),logf(a.y),logf(a.z));
+ }
+
+ __forceinline Vec3fa exp ( const Vec3fa& a ) {
+ return Vec3fa(expf(a.x),expf(a.y),expf(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa operator +( const Vec3fa& a, const Vec3fa& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator -( const Vec3fa& a, const Vec3fa& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator *( const Vec3fa& a, const Vec3fa& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator *( const Vec3fa& a, const float b ) { return a * Vec3fa(b); }
+ __forceinline Vec3fa operator *( const float a, const Vec3fa& b ) { return Vec3fa(a) * b; }
+ __forceinline Vec3fa operator /( const Vec3fa& a, const Vec3fa& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec3fa operator /( const Vec3fa& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec3fa operator /( const float a, const Vec3fa& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec3fa min( const Vec3fa& a, const Vec3fa& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec3fa max( const Vec3fa& a, const Vec3fa& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec3fa mini(const Vec3fa& a, const Vec3fa& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec3fa maxi(const Vec3fa& a, const Vec3fa& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec3fa pow ( const Vec3fa& a, const float& b ) {
+ return Vec3fa(powf(a.x,b),powf(a.y,b),powf(a.z,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa msub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
+#else
+
+#if defined(__aarch64__)
+ __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
+ return _mm_madd_ps(a.m128, b.m128, c.m128); //a*b+c;
+ }
+ __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
+ return _mm_msub_ps(a.m128, b.m128, c.m128); //-a*b+c;
+ }
+ __forceinline Vec3fa nmsub( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
+ Vec3fa t = _mm_madd_ps(a.m128, b.m128, c.m128);
+ return -t;
+ }
+ __forceinline Vec3fa msub( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) {
+ return _mm_madd_ps(a.m128,b.m128,vnegq_f32(c.m128)); //a*b-c
+ }
+
+#else
+ __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b+c; }
+ __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b+c;}
+ __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b-c; }
+ __forceinline Vec3fa msub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b-c; }
+#endif
+
+#endif
+
+ __forceinline Vec3fa madd ( const float a, const Vec3fa& b, const Vec3fa& c) { return madd(Vec3fa(a),b,c); }
+ __forceinline Vec3fa msub ( const float a, const Vec3fa& b, const Vec3fa& c) { return msub(Vec3fa(a),b,c); }
+ __forceinline Vec3fa nmadd ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmadd(Vec3fa(a),b,c); }
+ __forceinline Vec3fa nmsub ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmsub(Vec3fa(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa& operator +=( Vec3fa& a, const Vec3fa& b ) { return a = a + b; }
+ __forceinline Vec3fa& operator -=( Vec3fa& a, const Vec3fa& b ) { return a = a - b; }
+ __forceinline Vec3fa& operator *=( Vec3fa& a, const Vec3fa& b ) { return a = a * b; }
+ __forceinline Vec3fa& operator *=( Vec3fa& a, const float b ) { return a = a * b; }
+ __forceinline Vec3fa& operator /=( Vec3fa& a, const Vec3fa& b ) { return a = a / b; }
+ __forceinline Vec3fa& operator /=( Vec3fa& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ __forceinline float reduce_add(const Vec3fa& v) {
+ float32x4_t t = v.m128;
+ t[3] = 0.0f;
+ return vaddvq_f32(t);
+ }
+
+ __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
+ __forceinline float reduce_min(const Vec3fa& v) {
+ float32x4_t t = v.m128;
+ t[3] = t[2];
+ return vminvq_f32(t);
+ }
+ __forceinline float reduce_max(const Vec3fa& v) {
+ float32x4_t t = v.m128;
+ t[3] = t[2];
+ return vmaxvq_f32(t);
+ }
+#else
+ __forceinline float reduce_add(const Vec3fa& v) {
+ const vfloat4 a(v.m128);
+ const vfloat4 b = shuffle<1>(a);
+ const vfloat4 c = shuffle<2>(a);
+ return _mm_cvtss_f32(a+b+c);
+ }
+
+ __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
+ __forceinline float reduce_min(const Vec3fa& v) { return min(v.x,v.y,v.z); }
+ __forceinline float reduce_max(const Vec3fa& v) { return max(v.x,v.y,v.z); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3fa& a, const Vec3fa& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3fa& a, const Vec3fa& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+
+ __forceinline Vec3ba eq_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpeq_ps (a.m128, b.m128); }
+ __forceinline Vec3ba neq_mask(const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
+ __forceinline Vec3ba lt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
+ __forceinline Vec3ba le_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmple_ps (a.m128, b.m128); }
+ #if defined(__aarch64__)
+ __forceinline Vec3ba gt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpgt_ps (a.m128, b.m128); }
+ __forceinline Vec3ba ge_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpge_ps (a.m128, b.m128); }
+#else
+ __forceinline Vec3ba gt_mask(const Vec3fa& a, const Vec3fa& b) { return _mm_cmpnle_ps(a.m128, b.m128); }
+ __forceinline Vec3ba ge_mask(const Vec3fa& a, const Vec3fa& b) { return _mm_cmpnlt_ps(a.m128, b.m128); }
+#endif
+
+ __forceinline bool isvalid ( const Vec3fa& v ) {
+ return all(gt_mask(v,Vec3fa(-FLT_LARGE)) & lt_mask(v,Vec3fa(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite ( const Vec3fa& a ) {
+ return all(ge_mask(a,Vec3fa(-FLT_MAX)) & le_mask(a,Vec3fa(+FLT_MAX)));
+ }
+
+ __forceinline bool isvalid4 ( const Vec3fa& v ) {
+ return all((vfloat4(v.m128) > vfloat4(-FLT_LARGE)) & (vfloat4(v.m128) < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite4 ( const Vec3fa& a ) {
+ return all((vfloat4(a.m128) >= vfloat4(-FLT_MAX)) & (vfloat4(a.m128) <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec3fa& a, const Vec3fa& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a.m128,b.m128,0x7F));
+ }
+#else
+ __forceinline float dot ( const Vec3fa& a, const Vec3fa& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec3fa cross ( const Vec3fa& a, const Vec3fa& b )
+ {
+ vfloat4 a0 = vfloat4(a.m128);
+ vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
+ vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
+ vfloat4 b1 = vfloat4(b.m128);
+ return Vec3fa(shuffle<1,2,0,3>(prod_diff(a0,b0,a1,b1)));
+ }
+
+ __forceinline float sqr_length ( const Vec3fa& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec3fa& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec3fa& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec3fa& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec3fa normalize( const Vec3fa& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec3fa& a, const Vec3fa& b ) { return length(a-b); }
+ __forceinline float halfArea ( const Vec3fa& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ __forceinline float area ( const Vec3fa& d ) { return 2.0f*halfArea(d); }
+
+ __forceinline Vec3fa normalize_safe( const Vec3fa& a ) {
+ const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ }
+
+ /*! differentiated normalization */
+ __forceinline Vec3fa dnormalize(const Vec3fa& p, const Vec3fa& dp)
+ {
+ const float pp = dot(p,p);
+ const float pdp = dot(p,dp);
+ return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa select( bool s, const Vec3fa& t, const Vec3fa& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f.m128, t.m128, mask);
+ }
+
+ __forceinline Vec3fa select( const Vec3ba& s, const Vec3fa& t, const Vec3fa& f ) {
+ return blendv_ps(f.m128, t.m128, s);
+ }
+
+ __forceinline Vec3fa lerp(const Vec3fa& v0, const Vec3fa& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec3fa& a )
+ {
+ const Vec3fa b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+ __forceinline Vec3fa floor(const Vec3fa& a) { return vrndmq_f32(a.m128); }
+ __forceinline Vec3fa ceil (const Vec3fa& a) { return vrndpq_f32(a.m128); }
+ __forceinline Vec3fa trunc(const Vec3fa& a) { return vrndq_f32(a.m128); }
+#elif defined (__SSE4_1__)
+ __forceinline Vec3fa trunc( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec3fa floor( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec3fa ceil ( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF ); }
+#else
+ __forceinline Vec3fa trunc( const Vec3fa& a ) { return Vec3fa(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec3fa floor( const Vec3fa& a ) { return Vec3fa(floorf(a.x),floorf(a.y),floorf(a.z)); }
+ __forceinline Vec3fa ceil ( const Vec3fa& a ) { return Vec3fa(ceilf (a.x),ceilf (a.y),ceilf (a.z)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3fa& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+ typedef Vec3fa Vec3fa_t;
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3fx Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3fx
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 3 };
+ union {
+ __m128 m128;
+ struct { float x,y,z; union { int a; unsigned u; float w; }; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx( ) {}
+ __forceinline Vec3fx( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Vec3fx(const Vec3fa& v) : m128(v.m128) {}
+ __forceinline operator Vec3fa () const { return Vec3fa(m128); }
+
+ __forceinline explicit Vec3fx ( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); }
+ //__forceinline Vec3fx& operator =( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); return *this; }
+
+ __forceinline Vec3fx ( const Vec3fx& other ) { m128 = other.m128; }
+
+ __forceinline Vec3fx& operator =( const Vec3fx& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3fx( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec3fx( const float x, const float y, const float z) : m128(_mm_set_ps(0, z, y, x)) {}
+
+ __forceinline Vec3fx( const Vec3fa& other, const int a1) { m128 = other.m128; a = a1; }
+ __forceinline Vec3fx( const Vec3fa& other, const unsigned a1) { m128 = other.m128; u = a1; }
+ __forceinline Vec3fx( const Vec3fa& other, const float w1) {
+#if defined (__aarch64__)
+ m128 = other.m128; m128[3] = w1;
+#elif defined (__SSE4_1__)
+ m128 = _mm_insert_ps(other.m128, _mm_set_ss(w1),3 << 4);
+#else
+ const vint4 mask(-1,-1,-1,0);
+ m128 = select(vboolf4(_mm_castsi128_ps(mask)),vfloat4(other.m128),vfloat4(w1));
+#endif
+ }
+ //__forceinline Vec3fx( const float x, const float y, const float z, const int a) : x(x), y(y), z(z), a(a) {} // not working properly!
+ //__forceinline Vec3fx( const float x, const float y, const float z, const unsigned a) : x(x), y(y), z(z), u(a) {} // not working properly!
+ __forceinline Vec3fx( const float x, const float y, const float z, const float w) : m128(_mm_set_ps(w, z, y, x)) {}
+
+ //__forceinline explicit Vec3fx( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline explicit operator const vfloat4() const { return vfloat4(m128); }
+ __forceinline explicit operator const vint4() const { return vint4(_mm_cvtps_epi32(m128)); }
+ __forceinline explicit operator const Vec2fa() const { return Vec2fa(m128); }
+ __forceinline explicit operator const Vec3ia() const { return Vec3ia(_mm_cvtps_epi32(m128)); }
+
+ //__forceinline operator const __m128&() const { return m128; }
+ //__forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec3fx load( const void* const a ) {
+ return Vec3fx(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
+ }
+
+ static __forceinline Vec3fx loadu( const void* const a ) {
+ return Vec3fx(_mm_loadu_ps((float*)a));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec3fx& v ) {
+ _mm_storeu_ps((float*)ptr,v.m128);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3fx( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec3fx( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec3fx( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx operator +( const Vec3fx& a ) { return a; }
+ __forceinline Vec3fx operator -( const Vec3fx& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline Vec3fx abs ( const Vec3fx& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline Vec3fx sign ( const Vec3fx& a ) {
+ return blendv_ps(Vec3fx(one).m128, (-Vec3fx(one)).m128, _mm_cmplt_ps (a.m128,Vec3fx(zero).m128));
+ }
+
+ __forceinline Vec3fx rcp ( const Vec3fx& a )
+ {
+#if defined(__AVX512VL__)
+ const Vec3fx r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec3fx r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec3fx res = _mm_mul_ps(r.m128,_mm_fnmadd_ps(r.m128, a.m128, vfloat4(2.0f)));
+#else
+ const Vec3fx res = _mm_mul_ps(r.m128,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r.m128, a.m128)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+ }
+
+ __forceinline Vec3fx sqrt ( const Vec3fx& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec3fx sqr ( const Vec3fx& a ) { return _mm_mul_ps(a.m128,a.m128); }
+
+ __forceinline Vec3fx rsqrt( const Vec3fx& a )
+ {
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ }
+
+ __forceinline Vec3fx zero_fix(const Vec3fx& a) {
+ return blendv_ps(a.m128, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec3fx rcp_safe(const Vec3fx& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec3fx log ( const Vec3fx& a ) {
+ return Vec3fx(logf(a.x),logf(a.y),logf(a.z));
+ }
+
+ __forceinline Vec3fx exp ( const Vec3fx& a ) {
+ return Vec3fx(expf(a.x),expf(a.y),expf(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx operator +( const Vec3fx& a, const Vec3fx& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator -( const Vec3fx& a, const Vec3fx& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator *( const Vec3fx& a, const Vec3fx& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator *( const Vec3fx& a, const float b ) { return a * Vec3fx(b); }
+ __forceinline Vec3fx operator *( const float a, const Vec3fx& b ) { return Vec3fx(a) * b; }
+ __forceinline Vec3fx operator /( const Vec3fx& a, const Vec3fx& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec3fx operator /( const Vec3fx& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec3fx operator /( const float a, const Vec3fx& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec3fx min( const Vec3fx& a, const Vec3fx& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec3fx max( const Vec3fx& a, const Vec3fx& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__SSE4_1__) || defined(__aarch64__)
+ __forceinline Vec3fx mini(const Vec3fx& a, const Vec3fx& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__SSE4_1__) || defined(__aarch64__)
+ __forceinline Vec3fx maxi(const Vec3fx& a, const Vec3fx& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec3fx pow ( const Vec3fx& a, const float& b ) {
+ return Vec3fx(powf(a.x,b),powf(a.y,b),powf(a.z,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec3fx madd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx msub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx nmadd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx nmsub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
+#else
+ __forceinline Vec3fx madd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return a*b+c; }
+ __forceinline Vec3fx msub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return a*b-c; }
+ __forceinline Vec3fx nmadd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return -a*b+c;}
+ __forceinline Vec3fx nmsub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return -a*b-c; }
+#endif
+
+ __forceinline Vec3fx madd ( const float a, const Vec3fx& b, const Vec3fx& c) { return madd(Vec3fx(a),b,c); }
+ __forceinline Vec3fx msub ( const float a, const Vec3fx& b, const Vec3fx& c) { return msub(Vec3fx(a),b,c); }
+ __forceinline Vec3fx nmadd ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmadd(Vec3fx(a),b,c); }
+ __forceinline Vec3fx nmsub ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmsub(Vec3fx(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx& operator +=( Vec3fx& a, const Vec3fx& b ) { return a = a + b; }
+ __forceinline Vec3fx& operator -=( Vec3fx& a, const Vec3fx& b ) { return a = a - b; }
+ __forceinline Vec3fx& operator *=( Vec3fx& a, const Vec3fx& b ) { return a = a * b; }
+ __forceinline Vec3fx& operator *=( Vec3fx& a, const float b ) { return a = a * b; }
+ __forceinline Vec3fx& operator /=( Vec3fx& a, const Vec3fx& b ) { return a = a / b; }
+ __forceinline Vec3fx& operator /=( Vec3fx& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Vec3fx& v) {
+ const vfloat4 a(v.m128);
+ const vfloat4 b = shuffle<1>(a);
+ const vfloat4 c = shuffle<2>(a);
+ return _mm_cvtss_f32(a+b+c);
+ }
+
+ __forceinline float reduce_mul(const Vec3fx& v) { return v.x*v.y*v.z; }
+ __forceinline float reduce_min(const Vec3fx& v) { return min(v.x,v.y,v.z); }
+ __forceinline float reduce_max(const Vec3fx& v) { return max(v.x,v.y,v.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3fx& a, const Vec3fx& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3fx& a, const Vec3fx& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+
+ __forceinline Vec3ba eq_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpeq_ps (a.m128, b.m128); }
+ __forceinline Vec3ba neq_mask(const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
+ __forceinline Vec3ba lt_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
+ __forceinline Vec3ba le_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmple_ps (a.m128, b.m128); }
+ __forceinline Vec3ba gt_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpnle_ps(a.m128, b.m128); }
+ __forceinline Vec3ba ge_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpnlt_ps(a.m128, b.m128); }
+
+ __forceinline bool isvalid ( const Vec3fx& v ) {
+ return all(gt_mask(v,Vec3fx(-FLT_LARGE)) & lt_mask(v,Vec3fx(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite ( const Vec3fx& a ) {
+ return all(ge_mask(a,Vec3fx(-FLT_MAX)) & le_mask(a,Vec3fx(+FLT_MAX)));
+ }
+
+ __forceinline bool isvalid4 ( const Vec3fx& v ) {
+ return all((vfloat4(v.m128) > vfloat4(-FLT_LARGE)) & (vfloat4(v.m128) < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite4 ( const Vec3fx& a ) {
+ return all((vfloat4(a.m128) >= vfloat4(-FLT_MAX)) & (vfloat4(a.m128) <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec3fx& a, const Vec3fx& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a.m128,b.m128,0x7F));
+ }
+#else
+ __forceinline float dot ( const Vec3fx& a, const Vec3fx& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec3fx cross ( const Vec3fx& a, const Vec3fx& b )
+ {
+ vfloat4 a0 = vfloat4(a.m128);
+ vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
+ vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
+ vfloat4 b1 = vfloat4(b.m128);
+ return Vec3fx(shuffle<1,2,0,3>(msub(a0,b0,a1*b1)));
+ }
+
+ __forceinline float sqr_length ( const Vec3fx& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec3fx& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec3fx& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec3fx& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec3fx normalize( const Vec3fx& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec3fx& a, const Vec3fx& b ) { return length(a-b); }
+ __forceinline float halfArea ( const Vec3fx& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ __forceinline float area ( const Vec3fx& d ) { return 2.0f*halfArea(d); }
+
+ __forceinline Vec3fx normalize_safe( const Vec3fx& a ) {
+ const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ }
+
+ /*! differentiated normalization */
+ __forceinline Vec3fx dnormalize(const Vec3fx& p, const Vec3fx& dp)
+ {
+ const float pp = dot(p,p);
+ const float pdp = dot(p,dp);
+ return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx select( bool s, const Vec3fx& t, const Vec3fx& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f.m128, t.m128, mask);
+ }
+
+ __forceinline Vec3fx select( const Vec3ba& s, const Vec3fx& t, const Vec3fx& f ) {
+ return blendv_ps(f.m128, t.m128, s);
+ }
+
+ __forceinline Vec3fx lerp(const Vec3fx& v0, const Vec3fx& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec3fx& a )
+ {
+ const Vec3fx b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__SSE4_1__) && !defined(__aarch64__)
+ __forceinline Vec3fx trunc( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec3fx floor( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec3fx ceil ( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF ); }
+#else
+ __forceinline Vec3fx trunc( const Vec3fx& a ) { return Vec3fx(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec3fx floor( const Vec3fx& a ) { return Vec3fx(floorf(a.x),floorf(a.y),floorf(a.z)); }
+ __forceinline Vec3fx ceil ( const Vec3fx& a ) { return Vec3fx(ceilf (a.x),ceilf (a.y),ceilf (a.z)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3fx& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+
+ typedef Vec3fx Vec3ff;
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec3ia.h b/thirdparty/embree-aarch64/common/math/vec3ia.h
new file mode 100644
index 0000000000..737f67fd72
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec3ia.h
@@ -0,0 +1,210 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3ia Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3ia
+ {
+ ALIGNED_STRUCT_(16);
+
+ union {
+ __m128i m128;
+ struct { int x,y,z; };
+ };
+
+ typedef int Scalar;
+ enum { N = 3 };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia( ) {}
+ __forceinline Vec3ia( const __m128i a ) : m128(a) {}
+ __forceinline Vec3ia( const Vec3ia& other ) : m128(other.m128) {}
+ __forceinline Vec3ia& operator =(const Vec3ia& other) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3ia( const int a ) : m128(_mm_set1_epi32(a)) {}
+ __forceinline Vec3ia( const int x, const int y, const int z) : m128(_mm_set_epi32(z, z, y, x)) {}
+ __forceinline explicit Vec3ia( const __m128 a ) : m128(_mm_cvtps_epi32(a)) {}
+
+ __forceinline operator const __m128i&() const { return m128; }
+ __forceinline operator __m128i&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia( ZeroTy ) : m128(_mm_setzero_si128()) {}
+ __forceinline Vec3ia( OneTy ) : m128(_mm_set1_epi32(1)) {}
+ __forceinline Vec3ia( PosInfTy ) : m128(_mm_set1_epi32(pos_inf)) {}
+ __forceinline Vec3ia( NegInfTy ) : m128(_mm_set1_epi32(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia operator +( const Vec3ia& a ) { return a; }
+ __forceinline Vec3ia operator -( const Vec3ia& a ) { return _mm_sub_epi32(_mm_setzero_si128(), a.m128); }
+#if (defined(__aarch64__))
+ __forceinline Vec3ia abs ( const Vec3ia& a ) { return vabsq_s32(a.m128); }
+#elif defined(__SSSE3__)
+ __forceinline Vec3ia abs ( const Vec3ia& a ) { return _mm_abs_epi32(a.m128); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia operator +( const Vec3ia& a, const Vec3ia& b ) { return _mm_add_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator +( const Vec3ia& a, const int b ) { return a+Vec3ia(b); }
+ __forceinline Vec3ia operator +( const int a, const Vec3ia& b ) { return Vec3ia(a)+b; }
+
+ __forceinline Vec3ia operator -( const Vec3ia& a, const Vec3ia& b ) { return _mm_sub_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator -( const Vec3ia& a, const int b ) { return a-Vec3ia(b); }
+ __forceinline Vec3ia operator -( const int a, const Vec3ia& b ) { return Vec3ia(a)-b; }
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec3ia operator *( const Vec3ia& a, const Vec3ia& b ) { return _mm_mullo_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator *( const Vec3ia& a, const int b ) { return a * Vec3ia(b); }
+ __forceinline Vec3ia operator *( const int a, const Vec3ia& b ) { return Vec3ia(a) * b; }
+#endif
+
+ __forceinline Vec3ia operator &( const Vec3ia& a, const Vec3ia& b ) { return _mm_and_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator &( const Vec3ia& a, const int b ) { return a & Vec3ia(b); }
+ __forceinline Vec3ia operator &( const int a, const Vec3ia& b ) { return Vec3ia(a) & b; }
+
+ __forceinline Vec3ia operator |( const Vec3ia& a, const Vec3ia& b ) { return _mm_or_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator |( const Vec3ia& a, const int b ) { return a | Vec3ia(b); }
+ __forceinline Vec3ia operator |( const int a, const Vec3ia& b ) { return Vec3ia(a) | b; }
+
+ __forceinline Vec3ia operator ^( const Vec3ia& a, const Vec3ia& b ) { return _mm_xor_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator ^( const Vec3ia& a, const int b ) { return a ^ Vec3ia(b); }
+ __forceinline Vec3ia operator ^( const int a, const Vec3ia& b ) { return Vec3ia(a) ^ b; }
+
+#if !defined(__ARM_NEON)
+ __forceinline Vec3ia operator <<( const Vec3ia& a, const int n ) { return _mm_slli_epi32(a.m128, n); }
+ __forceinline Vec3ia operator >>( const Vec3ia& a, const int n ) { return _mm_srai_epi32(a.m128, n); }
+
+ __forceinline Vec3ia sll ( const Vec3ia& a, const int b ) { return _mm_slli_epi32(a.m128, b); }
+ __forceinline Vec3ia sra ( const Vec3ia& a, const int b ) { return _mm_srai_epi32(a.m128, b); }
+ __forceinline Vec3ia srl ( const Vec3ia& a, const int b ) { return _mm_srli_epi32(a.m128, b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia& operator +=( Vec3ia& a, const Vec3ia& b ) { return a = a + b; }
+ __forceinline Vec3ia& operator +=( Vec3ia& a, const int& b ) { return a = a + b; }
+
+ __forceinline Vec3ia& operator -=( Vec3ia& a, const Vec3ia& b ) { return a = a - b; }
+ __forceinline Vec3ia& operator -=( Vec3ia& a, const int& b ) { return a = a - b; }
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec3ia& operator *=( Vec3ia& a, const Vec3ia& b ) { return a = a * b; }
+ __forceinline Vec3ia& operator *=( Vec3ia& a, const int& b ) { return a = a * b; }
+#endif
+
+ __forceinline Vec3ia& operator &=( Vec3ia& a, const Vec3ia& b ) { return a = a & b; }
+ __forceinline Vec3ia& operator &=( Vec3ia& a, const int& b ) { return a = a & b; }
+
+ __forceinline Vec3ia& operator |=( Vec3ia& a, const Vec3ia& b ) { return a = a | b; }
+ __forceinline Vec3ia& operator |=( Vec3ia& a, const int& b ) { return a = a | b; }
+
+#if !defined(__ARM_NEON)
+ __forceinline Vec3ia& operator <<=( Vec3ia& a, const int& b ) { return a = a << b; }
+ __forceinline Vec3ia& operator >>=( Vec3ia& a, const int& b ) { return a = a >> b; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+#if defined(__aarch64__)
+ __forceinline int reduce_add(const Vec3ia& v) {
+ int32x4_t t = v.m128;
+ t[3] = 0;
+ return vaddvq_s32(t);
+
+ }
+ __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
+ __forceinline int reduce_min(const Vec3ia& v) {
+ int32x4_t t = (__m128i)blendv_ps((__m128)v0x7fffffff, (__m128)v.m128, (__m128)vFFF0);
+ return vminvq_s32(t);
+
+ }
+ __forceinline int reduce_max(const Vec3ia& v) {
+ int32x4_t t = (__m128i)blendv_ps((__m128)v0x80000000, (__m128)v.m128, (__m128)vFFF0);
+ return vmaxvq_s32(t);
+
+ }
+#else
+ __forceinline int reduce_add(const Vec3ia& v) { return v.x+v.y+v.z; }
+ __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
+ __forceinline int reduce_min(const Vec3ia& v) { return min(v.x,v.y,v.z); }
+ __forceinline int reduce_max(const Vec3ia& v) { return max(v.x,v.y,v.z); }
+#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3ia& a, const Vec3ia& b ) { return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(a.m128, b.m128))) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3ia& a, const Vec3ia& b ) { return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(a.m128, b.m128))) & 7) != 7; }
+ __forceinline bool operator < ( const Vec3ia& a, const Vec3ia& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ __forceinline Vec3ba eq_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmpeq_epi32 (a.m128, b.m128)); }
+ __forceinline Vec3ba lt_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmplt_epi32 (a.m128, b.m128)); }
+ __forceinline Vec3ba gt_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmpgt_epi32 (a.m128, b.m128)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia select( const Vec3ba& m, const Vec3ia& t, const Vec3ia& f ) {
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(_mm_castps_si128(m), t), _mm_andnot_si128(_mm_castps_si128(m), f));
+#endif
+ }
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return _mm_min_epi32(a.m128,b.m128); }
+ __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return _mm_max_epi32(a.m128,b.m128); }
+#else
+ __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return select(lt_mask(a,b),a,b); }
+ __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return select(gt_mask(a,b),a,b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3ia& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/math/vec4.h b/thirdparty/embree-aarch64/common/math/vec4.h
new file mode 100644
index 0000000000..d16542f507
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/math/vec4.h
@@ -0,0 +1,258 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+#include "vec3.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 4D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec4
+ {
+ enum { N = 4 };
+ union {
+ struct { T x, y, z, w; };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec4( ) {}
+ __forceinline explicit Vec4( const T& a ) : x(a), y(a), z(a), w(a) {}
+ __forceinline Vec4( const T& x, const T& y, const T& z, const T& w ) : x(x), y(y), z(z), w(w) {}
+ __forceinline Vec4( const Vec3<T>& xyz, const T& w ) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
+
+ __forceinline Vec4( const Vec4& other ) { x = other.x; y = other.y; z = other.z; w = other.w; }
+ __forceinline Vec4( const Vec3fx& other );
+
+ template<typename T1> __forceinline Vec4( const Vec4<T1>& a ) : x(T(a.x)), y(T(a.y)), z(T(a.z)), w(T(a.w)) {}
+ template<typename T1> __forceinline Vec4& operator =(const Vec4<T1>& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
+
+ __forceinline Vec4& operator =(const Vec4& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
+
+ __forceinline operator Vec3<T> () const { return Vec3<T>(x,y,z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec4( ZeroTy ) : x(zero), y(zero), z(zero), w(zero) {}
+ __forceinline Vec4( OneTy ) : x(one), y(one), z(one), w(one) {}
+ __forceinline Vec4( PosInfTy ) : x(pos_inf), y(pos_inf), z(pos_inf), w(pos_inf) {}
+ __forceinline Vec4( NegInfTy ) : x(neg_inf), y(neg_inf), z(neg_inf), w(neg_inf) {}
+
+#if defined(__WIN32__) && (_MSC_VER == 1800) // workaround for older VS 2013 compiler
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 4); return (&x)[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 4); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis ) const { assert(axis < 4); return components[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 4); return components[axis]; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Swizzles
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3<T> xyz() const { return Vec3<T>(x, y, z); }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> operator +( const Vec4<T>& a ) { return Vec4<T>(+a.x, +a.y, +a.z, +a.w); }
+ template<typename T> __forceinline Vec4<T> operator -( const Vec4<T>& a ) { return Vec4<T>(-a.x, -a.y, -a.z, -a.w); }
+ template<typename T> __forceinline Vec4<T> abs ( const Vec4<T>& a ) { return Vec4<T>(abs (a.x), abs (a.y), abs (a.z), abs (a.w)); }
+ template<typename T> __forceinline Vec4<T> rcp ( const Vec4<T>& a ) { return Vec4<T>(rcp (a.x), rcp (a.y), rcp (a.z), rcp (a.w)); }
+ template<typename T> __forceinline Vec4<T> rsqrt ( const Vec4<T>& a ) { return Vec4<T>(rsqrt(a.x), rsqrt(a.y), rsqrt(a.z), rsqrt(a.w)); }
+ template<typename T> __forceinline Vec4<T> sqrt ( const Vec4<T>& a ) { return Vec4<T>(sqrt (a.x), sqrt (a.y), sqrt (a.z), sqrt (a.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> operator +( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); }
+ template<typename T> __forceinline Vec4<T> operator -( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const T& a, const Vec4<T>& b ) { return Vec4<T>(a * b.x, a * b.y, a * b.z, a * b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const Vec4<T>& a, const T& b ) { return Vec4<T>(a.x * b , a.y * b , a.z * b , a.w * b ); }
+ template<typename T> __forceinline Vec4<T> operator /( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); }
+ template<typename T> __forceinline Vec4<T> operator /( const Vec4<T>& a, const T& b ) { return Vec4<T>(a.x / b , a.y / b , a.z / b , a.w / b ); }
+ template<typename T> __forceinline Vec4<T> operator /( const T& a, const Vec4<T>& b ) { return Vec4<T>(a / b.x, a / b.y, a / b.z, a / b.w); }
+
+ template<typename T> __forceinline Vec4<T> min(const Vec4<T>& a, const Vec4<T>& b) { return Vec4<T>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); }
+ template<typename T> __forceinline Vec4<T> max(const Vec4<T>& a, const Vec4<T>& b) { return Vec4<T>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> madd ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z), madd(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> msub ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z), msub(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmadd ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y),nmadd(a.z,b.z,c.z),nmadd(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmsub ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y),nmsub(a.z,b.z,c.z),nmsub(a.w,b.w,c.w)); }
+
+ template<typename T> __forceinline Vec4<T> madd ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( madd(a,b.x,c.x), madd(a,b.y,c.y), madd(a,b.z,c.z), madd(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> msub ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( msub(a,b.x,c.x), msub(a,b.y,c.y), msub(a,b.z,c.z), msub(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmadd ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y),nmadd(a,b.z,c.z),nmadd(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmsub ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y),nmsub(a,b.z,c.z),nmsub(a,b.w,c.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T>& operator +=( Vec4<T>& a, const Vec4<T>& b ) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; return a; }
+ template<typename T> __forceinline Vec4<T>& operator -=( Vec4<T>& a, const Vec4<T>& b ) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; return a; }
+ template<typename T> __forceinline Vec4<T>& operator *=( Vec4<T>& a, const T& b ) { a.x *= b ; a.y *= b ; a.z *= b ; a.w *= b ; return a; }
+ template<typename T> __forceinline Vec4<T>& operator /=( Vec4<T>& a, const T& b ) { a.x /= b ; a.y /= b ; a.z /= b ; a.w /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec4<T>& a ) { return a.x + a.y + a.z + a.w; }
+ template<typename T> __forceinline T reduce_mul( const Vec4<T>& a ) { return a.x * a.y * a.z * a.w; }
+ template<typename T> __forceinline T reduce_min( const Vec4<T>& a ) { return min(a.x, a.y, a.z, a.w); }
+ template<typename T> __forceinline T reduce_max( const Vec4<T>& a ) { return max(a.x, a.y, a.z, a.w); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec4<T>& a, const Vec4<T>& b ) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; }
+ template<typename T> __forceinline bool operator !=( const Vec4<T>& a, const Vec4<T>& b ) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; }
+ template<typename T> __forceinline bool operator < ( const Vec4<T>& a, const Vec4<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ if (a.w != b.w) return a.w < b.w;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> shift_right_1( const Vec4<T>& a ) {
+ return Vec4<T>(shift_right_1(a.x),shift_right_1(a.y),shift_right_1(a.z),shift_right_1(a.w));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T dot ( const Vec4<T>& a, const Vec4<T>& b ) { return madd(a.x,b.x,madd(a.y,b.y,madd(a.z,b.z,a.w*b.w))); }
+
+ template<typename T> __forceinline T length ( const Vec4<T>& a ) { return sqrt(dot(a,a)); }
+ template<typename T> __forceinline Vec4<T> normalize( const Vec4<T>& a ) { return a*rsqrt(dot(a,a)); }
+ template<typename T> __forceinline T distance ( const Vec4<T>& a, const Vec4<T>& b ) { return length(a-b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> select ( bool s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z),select(s,t.w,f.w));
+ }
+
+ template<typename T> __forceinline Vec4<T> select ( const Vec4<bool>& s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y),select(s.z,t.z,f.z),select(s.w,t.w,f.w));
+ }
+
+ template<typename T> __forceinline Vec4<T> select ( const typename T::Bool& s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z),select(s,t.w,f.w));
+ }
+
+ template<typename T>
+ __forceinline Vec4<T> lerp(const Vec4<T>& v0, const Vec4<T>& v1, const T& t) {
+ return madd(Vec4<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec4<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ", " << a.w << ")";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Default template instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef Vec4<bool > Vec4b;
+ typedef Vec4<uint8_t > Vec4uc;
+ typedef Vec4<int > Vec4i;
+ typedef Vec4<float > Vec4f;
+}
+
+#include "vec3ba.h"
+#include "vec3ia.h"
+#include "vec3fa.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+#include "../simd/sse.h"
+#endif
+
+#if defined __AVX__
+#include "../simd/avx.h"
+#endif
+
+#if defined __AVX512F__
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<> __forceinline Vec4<float>::Vec4( const Vec3fx& a ) { x = a.x; y = a.y; z = a.z; w = a.w; }
+
+#if defined(__AVX__)
+ template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
+ x = a.x; y = a.y; z = a.z; w = a.w;
+ }
+#elif defined(__SSE__) || defined(__ARM_NEON)
+ template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
+ const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v); w = shuffle<3,3,3,3>(v);
+ }
+#endif
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ __forceinline Vec4<vfloat4> broadcast4f( const Vec4<vfloat4>& a, const size_t k ) {
+ return Vec4<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]), vfloat4::broadcast(&a.w[k]));
+ }
+#endif
+
+#if defined(__AVX__)
+ template<> __forceinline Vec4<vfloat8>::Vec4( const Vec3fx& a ) {
+ x = a.x; y = a.y; z = a.z; w = a.w;
+ }
+ __forceinline Vec4<vfloat4> broadcast4f( const Vec4<vfloat8>& a, const size_t k ) {
+ return Vec4<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]), vfloat4::broadcast(&a.w[k]));
+ }
+ __forceinline Vec4<vfloat8> broadcast8f( const Vec4<vfloat4>& a, const size_t k ) {
+ return Vec4<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]), vfloat8::broadcast(&a.w[k]));
+ }
+ __forceinline Vec4<vfloat8> broadcast8f( const Vec4<vfloat8>& a, const size_t k ) {
+ return Vec4<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]), vfloat8::broadcast(&a.w[k]));
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec4<vfloat16>::Vec4( const Vec3fx& a ) : x(a.x), y(a.y), z(a.z), w(a.w) {}
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/simd/avx.h b/thirdparty/embree-aarch64/common/simd/avx.h
new file mode 100644
index 0000000000..c840e41805
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/avx.h
@@ -0,0 +1,34 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "sse.h"
+
+#if defined(__AVX512VL__)
+#include "vboolf8_avx512.h"
+#include "vboold4_avx512.h"
+#else
+#include "vboolf8_avx.h"
+#include "vboold4_avx.h"
+#endif
+
+#if defined(__AVX2__)
+#include "vint8_avx2.h"
+#include "vuint8_avx2.h"
+#if defined(__X86_64__)
+#include "vllong4_avx2.h"
+#endif
+#else
+#include "vint8_avx.h"
+#include "vuint8_avx.h"
+#endif
+#include "vfloat8_avx.h"
+#if defined(__X86_64__)
+#include "vdouble4_avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "avx512.h"
+#endif
+
diff --git a/thirdparty/embree-aarch64/common/simd/avx512.h b/thirdparty/embree-aarch64/common/simd/avx512.h
new file mode 100644
index 0000000000..25414ab5b1
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/avx512.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "../math/constants.h"
+#include "../sys/alloc.h"
+#include "varying.h"
+
+#include "vboolf16_avx512.h"
+#include "vint16_avx512.h"
+#include "vuint16_avx512.h"
+#include "vfloat16_avx512.h"
+
+#include "vboold8_avx512.h"
+#include "vllong8_avx512.h"
+#include "vdouble8_avx512.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Prefetching
+ ////////////////////////////////////////////////////////////////////////////////
+
+#define PFHINT_L1 0
+#define PFHINT_L2 1
+#define PFHINT_NT 2
+
+ template<const unsigned int mode>
+ __forceinline void prefetch(const void * __restrict__ const m)
+ {
+ if (mode == PFHINT_L1)
+ _mm_prefetch((const char*)m,_MM_HINT_T0);
+ else if (mode == PFHINT_L2)
+ _mm_prefetch((const char*)m,_MM_HINT_T1);
+ else if (mode == PFHINT_NT)
+ _mm_prefetch((const char*)m,_MM_HINT_NTA);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/simd.h b/thirdparty/embree-aarch64/common/simd/simd.h
new file mode 100644
index 0000000000..647851110b
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/simd.h
@@ -0,0 +1,110 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+/* include SSE wrapper classes */
+#if defined(__SSE__) || defined(__ARM_NEON)
+# include "sse.h"
+#endif
+
+/* include AVX wrapper classes */
+#if defined(__AVX__)
+# include "avx.h"
+#endif
+
+/* include AVX512 wrapper classes */
+#if defined (__AVX512F__)
+# include "avx512.h"
+#endif
+
+namespace embree
+{
+ template <int N>
+ __forceinline vbool<N> isfinite(const vfloat<N>& v)
+ {
+ return (v >= vfloat<N>(-std::numeric_limits<float>::max()))
+ & (v <= vfloat<N>( std::numeric_limits<float>::max()));
+ }
+
+ /* foreach unique */
+ template<typename vbool, typename vint, typename Closure>
+ __forceinline void foreach_unique(const vbool& valid0, const vint& vi, const Closure& closure)
+ {
+ vbool valid1 = valid0;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int i = vi[j];
+ const vbool valid2 = valid1 & (i == vi);
+ valid1 = andn(valid1, valid2);
+ closure(valid2, i);
+ }
+ }
+
+ /* returns the next unique value i in vi and the corresponding valid_i mask */
+ template<typename vbool, typename vint>
+ __forceinline int next_unique(vbool& valid, const vint& vi, /*out*/ vbool& valid_i)
+ {
+ assert(any(valid));
+ const int j = int(bsf(movemask(valid)));
+ const int i = vi[j];
+ valid_i = valid & (i == vi);
+ valid = andn(valid, valid_i);
+ return i;
+ }
+
+ /* foreach unique index */
+ template<typename vbool, typename vint, typename Closure>
+ __forceinline void foreach_unique_index(const vbool& valid0, const vint& vi, const Closure& closure)
+ {
+ vbool valid1 = valid0;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int i = vi[j];
+ const vbool valid2 = valid1 & (i == vi);
+ valid1 = andn(valid1, valid2);
+ closure(valid2, i, j);
+ }
+ }
+
+ /* returns the index of the next unique value i in vi and the corresponding valid_i mask */
+ template<typename vbool, typename vint>
+ __forceinline int next_unique_index(vbool& valid, const vint& vi, /*out*/ vbool& valid_i)
+ {
+ assert(any(valid));
+ const int j = int(bsf(movemask(valid)));
+ const int i = vi[j];
+ valid_i = valid & (i == vi);
+ valid = andn(valid, valid_i);
+ return j;
+ }
+
+ template<typename Closure>
+ __forceinline void foreach2(int x0, int x1, int y0, int y1, const Closure& closure)
+ {
+ __aligned(64) int U[2*VSIZEX];
+ __aligned(64) int V[2*VSIZEX];
+ int index = 0;
+ for (int y=y0; y<y1; y++) {
+ const bool lasty = y+1>=y1;
+ const vintx vy = y;
+ for (int x=x0; x<x1; ) { //x+=VSIZEX) {
+ const bool lastx = x+VSIZEX >= x1;
+ vintx vx = x+vintx(step);
+ vintx::storeu(&U[index], vx);
+ vintx::storeu(&V[index], vy);
+ const int dx = min(x1-x,VSIZEX);
+ index += dx;
+ x += dx;
+ if (index >= VSIZEX || (lastx && lasty)) {
+ const vboolx valid = vintx(step) < vintx(index);
+ closure(valid, vintx::load(U), vintx::load(V));
+ x-= max(0, index-VSIZEX);
+ index = 0;
+ }
+ }
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/sse.cpp b/thirdparty/embree-aarch64/common/simd/sse.cpp
new file mode 100644
index 0000000000..1732cfa421
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/sse.cpp
@@ -0,0 +1,34 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sse.h"
+
+namespace embree
+{
+ const __m128 mm_lookupmask_ps[16] = {
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1,-1,-1))
+ };
+
+ const __m128d mm_lookupmask_pd[4] = {
+ _mm_castsi128_pd(_mm_set_epi32( 0, 0, 0, 0)),
+ _mm_castsi128_pd(_mm_set_epi32( 0, 0,-1,-1)),
+ _mm_castsi128_pd(_mm_set_epi32(-1,-1, 0, 0)),
+ _mm_castsi128_pd(_mm_set_epi32(-1,-1,-1,-1))
+ };
+
+}
diff --git a/thirdparty/embree-aarch64/common/simd/sse.h b/thirdparty/embree-aarch64/common/simd/sse.h
new file mode 100644
index 0000000000..6bc818b55b
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/sse.h
@@ -0,0 +1,35 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "../sys/alloc.h"
+#include "../math/constants.h"
+#include "varying.h"
+
+namespace embree
+{
+#if (defined(__aarch64__) && defined(BUILD_IOS)) || defined(__SSE4_1__)
+ __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) {
+ return _mm_blendv_ps(f,t,mask);
+ }
+#else
+ __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) {
+ return _mm_or_ps(_mm_and_ps(mask, t), _mm_andnot_ps(mask, f));
+ }
+#endif
+
+ extern const __m128 mm_lookupmask_ps[16];
+ extern const __m128d mm_lookupmask_pd[4];
+}
+
+#if defined(__AVX512VL__)
+#include "vboolf4_avx512.h"
+#else
+#include "vboolf4_sse2.h"
+#endif
+#include "vint4_sse2.h"
+#include "vuint4_sse2.h"
+#include "vfloat4_sse2.h"
diff --git a/thirdparty/embree-aarch64/common/simd/varying.h b/thirdparty/embree-aarch64/common/simd/varying.h
new file mode 100644
index 0000000000..9a46817da9
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/varying.h
@@ -0,0 +1,132 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+
+namespace embree
+{
+ /* Varying numeric types */
+ template<int N>
+ struct vfloat
+ {
+ union { float f[N]; int i[N]; };
+ __forceinline const float& operator [](size_t index) const { assert(index < N); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < N); return f[index]; }
+ };
+
+ template<int N>
+ struct vdouble
+ {
+ union { double f[N]; long long i[N]; };
+ __forceinline const double& operator [](size_t index) const { assert(index < N); return f[index]; }
+ __forceinline double& operator [](size_t index) { assert(index < N); return f[index]; }
+ };
+
+ template<int N>
+ struct vint
+ {
+ int i[N];
+ __forceinline const int& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ template<int N>
+ struct vuint
+ {
+ unsigned int i[N];
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ template<int N>
+ struct vllong
+ {
+ long long i[N];
+ __forceinline const long long& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline long long& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ /* Varying bool types */
+ template<int N> struct vboolf { int i[N]; }; // for float/int
+ template<int N> struct vboold { long long i[N]; }; // for double/long long
+
+ /* Aliases to default types */
+ template<int N> using vreal = vfloat<N>;
+ template<int N> using vbool = vboolf<N>;
+
+ /* Varying size constants */
+#if defined(__AVX512VL__) // SKX
+ const int VSIZEX = 8; // default size
+ const int VSIZEL = 16; // large size
+#elif defined(__AVX512F__) // KNL
+ const int VSIZEX = 16;
+ const int VSIZEL = 16;
+#elif defined(__AVX__)
+ const int VSIZEX = 8;
+ const int VSIZEL = 8;
+#else
+ const int VSIZEX = 4;
+ const int VSIZEL = 4;
+#endif
+
+ /* Extends varying size N to optimal or up to max(N, N2) */
+ template<int N, int N2 = VSIZEX>
+ struct vextend
+ {
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+ /* use 16-wide SIMD calculations on KNL even for 4 and 8 wide SIMD */
+ static const int size = (N2 == VSIZEX) ? VSIZEX : N;
+ #define SIMD_MODE(N) N, 16
+#else
+ /* calculate with same SIMD width otherwise */
+ static const int size = N;
+ #define SIMD_MODE(N) N, N
+#endif
+ };
+
+ /* 4-wide shortcuts */
+ typedef vfloat<4> vfloat4;
+ typedef vdouble<4> vdouble4;
+ typedef vreal<4> vreal4;
+ typedef vint<4> vint4;
+ typedef vuint<4> vuint4;
+ typedef vllong<4> vllong4;
+ typedef vbool<4> vbool4;
+ typedef vboolf<4> vboolf4;
+ typedef vboold<4> vboold4;
+
+ /* 8-wide shortcuts */
+ typedef vfloat<8> vfloat8;
+ typedef vdouble<8> vdouble8;
+ typedef vreal<8> vreal8;
+ typedef vint<8> vint8;
+ typedef vuint<8> vuint8;
+ typedef vllong<8> vllong8;
+ typedef vbool<8> vbool8;
+ typedef vboolf<8> vboolf8;
+ typedef vboold<8> vboold8;
+
+ /* 16-wide shortcuts */
+ typedef vfloat<16> vfloat16;
+ typedef vdouble<16> vdouble16;
+ typedef vreal<16> vreal16;
+ typedef vint<16> vint16;
+ typedef vuint<16> vuint16;
+ typedef vllong<16> vllong16;
+ typedef vbool<16> vbool16;
+ typedef vboolf<16> vboolf16;
+ typedef vboold<16> vboold16;
+
+ /* Default shortcuts */
+ typedef vfloat<VSIZEX> vfloatx;
+ typedef vdouble<VSIZEX> vdoublex;
+ typedef vreal<VSIZEX> vrealx;
+ typedef vint<VSIZEX> vintx;
+ typedef vuint<VSIZEX> vuintx;
+ typedef vllong<VSIZEX> vllongx;
+ typedef vbool<VSIZEX> vboolx;
+ typedef vboolf<VSIZEX> vboolfx;
+ typedef vboold<VSIZEX> vbooldx;
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboold4_avx.h b/thirdparty/embree-aarch64/common/simd/vboold4_avx.h
new file mode 100644
index 0000000000..6505ee56f3
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboold4_avx.h
@@ -0,0 +1,160 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide AVX bool type for 64bit data types*/
+ template<>
+ struct vboold<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256d v;
+ struct { __m128d vl,vh; };
+ long long i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold4& a) { v = a.v; }
+ __forceinline vboold4& operator =(const vboold4& a) { v = a.v; return *this; }
+
+ __forceinline vboold(__m256d a) : v(a) {}
+ __forceinline vboold(__m256i a) : v(_mm256_castsi256_pd(a)) {}
+
+ __forceinline operator const __m256() const { return _mm256_castpd_ps(v); }
+ __forceinline operator const __m256i() const { return _mm256_castpd_si256(v); }
+ __forceinline operator const __m256d() const { return v; }
+
+ __forceinline vboold(int a)
+ {
+ assert(a >= 0 && a <= 255);
+#if defined (__AVX2__)
+ const __m256i mask = _mm256_set_epi64x(0x8, 0x4, 0x2, 0x1);
+ const __m256i b = _mm256_set1_epi64x(a);
+ const __m256i c = _mm256_and_si256(b,mask);
+ v = _mm256_castsi256_pd(_mm256_cmpeq_epi64(c,mask));
+#else
+ vl = mm_lookupmask_pd[a & 0x3];
+ vh = mm_lookupmask_pd[a >> 2];
+#endif
+ }
+
+ __forceinline vboold(__m128d a, __m128d b) : vl(a), vh(b) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(_mm256_setzero_pd()) {}
+#if !defined(__aarch64__)
+ __forceinline vboold(TrueTy) : v(_mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_OQ)) {}
+#else
+ __forceinline vboold(TrueTy) : v(_mm256_cmpeq_pd(_mm256_setzero_pd(), _mm256_setzero_pd())) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm256_movemask_pd(v) >> index) & 1; }
+ __forceinline long long& operator [](size_t index) { assert(index < 4); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !(const vboold4& a) { return _mm256_xor_pd(a, vboold4(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator &(const vboold4& a, const vboold4& b) { return _mm256_and_pd(a, b); }
+ __forceinline vboold4 operator |(const vboold4& a, const vboold4& b) { return _mm256_or_pd (a, b); }
+ __forceinline vboold4 operator ^(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(a, b); }
+
+ __forceinline vboold4 andn(const vboold4& a, const vboold4& b) { return _mm256_andnot_pd(b, a); }
+
+ __forceinline vboold4& operator &=(vboold4& a, const vboold4& b) { return a = a & b; }
+ __forceinline vboold4& operator |=(vboold4& a, const vboold4& b) { return a = a | b; }
+ __forceinline vboold4& operator ^=(vboold4& a, const vboold4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !=(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(a, b); }
+ __forceinline vboold4 operator ==(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(_mm256_xor_pd(a,b),vboold4(embree::True)); }
+
+ __forceinline vboold4 select(const vboold4& mask, const vboold4& t, const vboold4& f) {
+ return _mm256_blendv_pd(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(__aarch64__)
+ __forceinline vboold4 unpacklo(const vboold4& a, const vboold4& b) { return _mm256_unpacklo_pd(a, b); }
+ __forceinline vboold4 unpackhi(const vboold4& a, const vboold4& b) { return _mm256_unpackhi_pd(a, b); }
+#endif
+
+#if defined(__AVX2__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboold4 shuffle(const vboold4& v) {
+ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i>
+ __forceinline vboold4 shuffle(const vboold4& v) {
+ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(i, i, i, i));
+ }
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboold4& a) { return _mm256_movemask_pd(a) == (unsigned int)0xf; }
+ __forceinline bool reduce_or (const vboold4& a) { return !_mm256_testz_pd(a,a); }
+
+ __forceinline bool all (const vboold4& a) { return _mm256_movemask_pd(a) == (unsigned int)0xf; }
+ __forceinline bool any (const vboold4& a) { return !_mm256_testz_pd(a,a); }
+ __forceinline bool none(const vboold4& a) { return _mm256_testz_pd(a,a) != 0; }
+
+ __forceinline bool all (const vboold4& valid, const vboold4& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboold4& valid, const vboold4& b) { return any(valid & b); }
+ __forceinline bool none(const vboold4& valid, const vboold4& b) { return none(valid & b); }
+
+ __forceinline unsigned int movemask(const vboold4& a) { return _mm256_movemask_pd(a); }
+ __forceinline size_t popcnt (const vboold4& a) { return popcnt((size_t)_mm256_movemask_pd(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold4& a, size_t index) { return a[index]; }
+ __forceinline void set (vboold4& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboold4& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", "
+ << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboold4_avx512.h b/thirdparty/embree-aarch64/common/simd/vboold4_avx512.h
new file mode 100644
index 0000000000..4fe730d713
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboold4_avx512.h
@@ -0,0 +1,140 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide AVX-512 bool type */
+ template<>
+ struct vboold<4>
+ {
+ typedef vboold4 Bool;
+ typedef vint4 Int;
+
+ enum { size = 4 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold4& t) { v = t.v; }
+ __forceinline vboold4& operator =(const vboold4& f) { v = f.v; return *this; }
+
+ __forceinline vboold(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboold(bool b) { v = b ? 0xf : 0x0; }
+ __forceinline vboold(int t) { v = (__mmask8)t; }
+ __forceinline vboold(unsigned int t) { v = (__mmask8)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m256i mask64() const {
+ return _mm256_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(0x0) {}
+ __forceinline vboold(TrueTy) : v(0xf) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 4); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !(const vboold4& a) { return _mm512_kandn(a, 0xf); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator &(const vboold4& a, const vboold4& b) { return _mm512_kand(a, b); }
+ __forceinline vboold4 operator |(const vboold4& a, const vboold4& b) { return _mm512_kor(a, b); }
+ __forceinline vboold4 operator ^(const vboold4& a, const vboold4& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboold4 andn(const vboold4& a, const vboold4& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4& operator &=(vboold4& a, const vboold4& b) { return a = a & b; }
+ __forceinline vboold4& operator |=(vboold4& a, const vboold4& b) { return a = a | b; }
+ __forceinline vboold4& operator ^=(vboold4& a, const vboold4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !=(const vboold4& a, const vboold4& b) { return _mm512_kxor(a, b); }
+ __forceinline vboold4 operator ==(const vboold4& a, const vboold4& b) { return _mm512_kand(_mm512_kxnor(a, b), 0xf); }
+
+ __forceinline vboold4 select(const vboold4& s, const vboold4& a, const vboold4& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboold4& a) { return a.v == 0xf; }
+ __forceinline int any (const vboold4& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboold4& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboold4& valid, const vboold4& b) { return all((!valid) | b); }
+ __forceinline int any (const vboold4& valid, const vboold4& b) { return any(valid & b); }
+ __forceinline int none(const vboold4& valid, const vboold4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboold4& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboold4& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboold4& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold4& a, size_t index) { assert(index < 4); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboold4& a, size_t index) { assert(index < 4); a |= 1 << index; }
+ __forceinline void clear(vboold4& a, size_t index) { assert(index < 4); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold4& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<4; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboold8_avx512.h b/thirdparty/embree-aarch64/common/simd/vboold8_avx512.h
new file mode 100644
index 0000000000..fdf3f00de5
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboold8_avx512.h
@@ -0,0 +1,148 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX-512 bool type */
+ template<>
+ struct vboold<8>
+ {
+ typedef vboold8 Bool;
+ typedef vint8 Int;
+
+ enum { size = 8 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold8& t) { v = t.v; }
+ __forceinline vboold8& operator =(const vboold8& f) { v = f.v; return *this; }
+
+ __forceinline vboold(const __mmask8& t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboold(bool b) { v = b ? 0xff : 0x00; }
+ __forceinline vboold(int t) { v = (__mmask8)t; }
+ __forceinline vboold(unsigned int t) { v = (__mmask8)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+#if defined(__AVX512BW__)
+ return _mm_movm_epi8(v);
+#else
+ const __m512i f = _mm512_set1_epi64(0);
+ const __m512i t = _mm512_set1_epi64(-1);
+ const __m512i m = _mm512_mask_or_epi64(f,v,t,t);
+ return _mm512_cvtepi64_epi8(m);
+#endif
+ }
+
+ /* return int64 mask */
+ __forceinline __m512i mask64() const {
+#if defined(__AVX512DQ__)
+ return _mm512_movm_epi64(v);
+#else
+ const __m512i f = _mm512_set1_epi64(0);
+ const __m512i t = _mm512_set1_epi64(-1);
+ return _mm512_mask_or_epi64(f,v,t,t);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(0x00) {}
+ __forceinline vboold(TrueTy) : v(0xff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 8); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator !(const vboold8& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator &(const vboold8& a, const vboold8& b) { return _mm512_kand(a, b); }
+ __forceinline vboold8 operator |(const vboold8& a, const vboold8& b) { return _mm512_kor(a, b); }
+ __forceinline vboold8 operator ^(const vboold8& a, const vboold8& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboold8 andn(const vboold8& a, const vboold8& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8& operator &=(vboold8& a, const vboold8& b) { return a = a & b; }
+ __forceinline vboold8& operator |=(vboold8& a, const vboold8& b) { return a = a | b; }
+ __forceinline vboold8& operator ^=(vboold8& a, const vboold8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator !=(const vboold8& a, const vboold8& b) { return _mm512_kxor(a, b); }
+ __forceinline vboold8 operator ==(const vboold8& a, const vboold8& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboold8 select(const vboold8& s, const vboold8& a, const vboold8& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboold8& a) { return a.v == 0xff; }
+ __forceinline int any (const vboold8& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboold8& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboold8& valid, const vboold8& b) { return all((!valid) | b); }
+ __forceinline int any (const vboold8& valid, const vboold8& b) { return any(valid & b); }
+ __forceinline int none(const vboold8& valid, const vboold8& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboold8& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboold8& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboold8& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold8& a, size_t index) { assert(index < 8); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboold8& a, size_t index) { assert(index < 8); a |= 1 << index; }
+ __forceinline void clear(vboold8& a, size_t index) { assert(index < 8); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold8& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<8; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboolf16_avx512.h b/thirdparty/embree-aarch64/common/simd/vboolf16_avx512.h
new file mode 100644
index 0000000000..238cdc8eb9
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboolf16_avx512.h
@@ -0,0 +1,150 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 16-wide AVX-512 bool type */
+ template<>
+ struct vboolf<16>
+ {
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ __mmask16 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf16& t) { v = t.v; }
+ __forceinline vboolf16& operator =(const vboolf16& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask16& t) { v = t; }
+ __forceinline operator __mmask16() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xFFFF : 0x0000; }
+ __forceinline vboolf(int t) { v = (__mmask16)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask16)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+#if defined(__AVX512BW__)
+ return _mm_movm_epi8(v);
+#else
+ const __m512i f = _mm512_set1_epi32(0);
+ const __m512i t = _mm512_set1_epi32(-1);
+ const __m512i m = _mm512_mask_or_epi32(f,v,t,t);
+ return _mm512_cvtepi32_epi8(m);
+#endif
+ }
+
+ /* return int32 mask */
+ __forceinline __m512i mask32() const {
+#if defined(__AVX512DQ__)
+ return _mm512_movm_epi32(v);
+#else
+ const __m512i f = _mm512_set1_epi32(0);
+ const __m512i t = _mm512_set1_epi32(-1);
+ return _mm512_mask_or_epi32(f,v,t,t);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x0000) {}
+ __forceinline vboolf(TrueTy) : v(0xffff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 16); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator !(const vboolf16& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator &(const vboolf16& a, const vboolf16& b) { return _mm512_kand(a,b); }
+ __forceinline vboolf16 operator |(const vboolf16& a, const vboolf16& b) { return _mm512_kor(a,b); }
+ __forceinline vboolf16 operator ^(const vboolf16& a, const vboolf16& b) { return _mm512_kxor(a,b); }
+
+ __forceinline vboolf16 andn(const vboolf16& a, const vboolf16& b) { return _mm512_kandn(b,a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16& operator &=(vboolf16& a, const vboolf16& b) { return a = a & b; }
+ __forceinline vboolf16& operator |=(vboolf16& a, const vboolf16& b) { return a = a | b; }
+ __forceinline vboolf16& operator ^=(vboolf16& a, const vboolf16& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator !=(const vboolf16& a, const vboolf16& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf16 operator ==(const vboolf16& a, const vboolf16& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboolf16 select(const vboolf16& s, const vboolf16& a, const vboolf16& b) {
+ return _mm512_kor(_mm512_kand(s,a),_mm512_kandn(s,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf16& a) { return _mm512_kortestc(a,a) != 0; }
+ __forceinline int any (const vboolf16& a) { return _mm512_kortestz(a,a) == 0; }
+ __forceinline int none(const vboolf16& a) { return _mm512_kortestz(a,a) != 0; }
+
+ __forceinline int all (const vboolf16& valid, const vboolf16& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf16& valid, const vboolf16& b) { return any(valid & b); }
+ __forceinline int none(const vboolf16& valid, const vboolf16& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf16& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf16& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Convertion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt (const vboolf16& a) { return mm512_mask2int(a); }
+ __forceinline vboolf16 toMask(const int& a) { return mm512_int2mask(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf16& a, size_t index) { assert(index < 16); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf16& a, size_t index) { assert(index < 16); a |= 1 << index; }
+ __forceinline void clear(vboolf16& a, size_t index) { assert(index < 16); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf16& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<16; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboolf4_avx512.h b/thirdparty/embree-aarch64/common/simd/vboolf4_avx512.h
new file mode 100644
index 0000000000..2ae4c4470e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboolf4_avx512.h
@@ -0,0 +1,143 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide AVX-512 bool type */
+ template<>
+ struct vboolf<4>
+ {
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+
+ enum { size = 4 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf4& t) { v = t.v; }
+ __forceinline vboolf4& operator =(const vboolf4& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xf : 0x0; }
+ __forceinline vboolf(int t) { v = (__mmask8)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask8)t; }
+
+ __forceinline vboolf(bool a, bool b, bool c, bool d)
+ : v((__mmask8)((int(d) << 3) | (int(c) << 2) | (int(b) << 1) | int(a))) {}
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m256i mask64() const {
+ return _mm256_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x0) {}
+ __forceinline vboolf(TrueTy) : v(0xf) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 4); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !(const vboolf4& a) { return _mm512_kandn(a, 0xf); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator &(const vboolf4& a, const vboolf4& b) { return _mm512_kand(a, b); }
+ __forceinline vboolf4 operator |(const vboolf4& a, const vboolf4& b) { return _mm512_kor(a, b); }
+ __forceinline vboolf4 operator ^(const vboolf4& a, const vboolf4& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboolf4 andn(const vboolf4& a, const vboolf4& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4& operator &=(vboolf4& a, const vboolf4& b) { return a = a & b; }
+ __forceinline vboolf4& operator |=(vboolf4& a, const vboolf4& b) { return a = a | b; }
+ __forceinline vboolf4& operator ^=(vboolf4& a, const vboolf4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !=(const vboolf4& a, const vboolf4& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm512_kand(_mm512_kxnor(a, b), 0xf); }
+
+ __forceinline vboolf4 select(const vboolf4& s, const vboolf4& a, const vboolf4& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf4& a) { return a.v == 0xf; }
+ __forceinline int any (const vboolf4& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboolf4& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboolf4& valid, const vboolf4& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf4& valid, const vboolf4& b) { return any(valid & b); }
+ __forceinline int none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf4& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf4& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboolf4& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf4& a, size_t index) { assert(index < 4); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf4& a, size_t index) { assert(index < 4); a |= 1 << index; }
+ __forceinline void clear(vboolf4& a, size_t index) { assert(index < 4); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf4& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<4; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboolf4_sse2.h b/thirdparty/embree-aarch64/common/simd/vboolf4_sse2.h
new file mode 100644
index 0000000000..ed53b3c783
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboolf4_sse2.h
@@ -0,0 +1,198 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide SSE bool type */
+ template<>
+ struct vboolf<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128 v; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf4& other) { v = other.v; }
+ __forceinline vboolf4& operator =(const vboolf4& other) { v = other.v; return *this; }
+
+ __forceinline vboolf(__m128 input) : v(input) {}
+ __forceinline operator const __m128&() const { return v; }
+ __forceinline operator const __m128i() const { return _mm_castps_si128(v); }
+ __forceinline operator const __m128d() const { return _mm_castps_pd(v); }
+
+ __forceinline vboolf(bool a)
+ : v(mm_lookupmask_ps[(size_t(a) << 3) | (size_t(a) << 2) | (size_t(a) << 1) | size_t(a)]) {}
+ __forceinline vboolf(bool a, bool b)
+ : v(mm_lookupmask_ps[(size_t(b) << 3) | (size_t(a) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d)
+ : v(mm_lookupmask_ps[(size_t(d) << 3) | (size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ __forceinline vboolf(int mask) { v = mm_lookupmask_ps[mask]; }
+ __forceinline vboolf(unsigned int mask) { v = mm_lookupmask_ps[mask]; }
+#else
+ __forceinline vboolf(int mask) { assert(mask >= 0 && mask < 16); v = mm_lookupmask_ps[mask]; }
+ __forceinline vboolf(unsigned int mask) { assert(mask < 16); v = mm_lookupmask_ps[mask]; }
+#endif
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_castps_si128(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(_mm_setzero_ps()) {}
+ __forceinline vboolf(TrueTy) : v(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()))) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ __forceinline bool operator [](size_t index) const { return (_mm_movemask_ps(v) >> index) & 1; }
+ __forceinline int& operator [](size_t index) { return i[index]; }
+#else
+ __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm_movemask_ps(v) >> index) & 1; }
+ __forceinline int& operator [](size_t index) { assert(index < 4); return i[index]; }
+#endif
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !(const vboolf4& a) { return _mm_xor_ps(a, vboolf4(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator &(const vboolf4& a, const vboolf4& b) { return _mm_and_ps(a, b); }
+ __forceinline vboolf4 operator |(const vboolf4& a, const vboolf4& b) { return _mm_or_ps (a, b); }
+ __forceinline vboolf4 operator ^(const vboolf4& a, const vboolf4& b) { return _mm_xor_ps(a, b); }
+
+ __forceinline vboolf4 andn(const vboolf4& a, const vboolf4& b) { return _mm_andnot_ps(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4& operator &=(vboolf4& a, const vboolf4& b) { return a = a & b; }
+ __forceinline vboolf4& operator |=(vboolf4& a, const vboolf4& b) { return a = a | b; }
+ __forceinline vboolf4& operator ^=(vboolf4& a, const vboolf4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !=(const vboolf4& a, const vboolf4& b) { return _mm_xor_ps(a, b); }
+ __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+
+ __forceinline vboolf4 select(const vboolf4& m, const vboolf4& t, const vboolf4& f) {
+#if (defined(__aarch64__) && defined(BUILD_IOS)) || defined(__SSE4_1__)
+ return _mm_blendv_ps(f, t, m);
+#else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 unpacklo(const vboolf4& a, const vboolf4& b) { return _mm_unpacklo_ps(a, b); }
+ __forceinline vboolf4 unpackhi(const vboolf4& a, const vboolf4& b) { return _mm_unpackhi_ps(a, b); }
+
+#if defined(__aarch64__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& v) {
+ return vreinterpretq_f32_u8(vqtbl1q_u8( vreinterpretq_u8_s32(v), _MN_SHUFFLE(i0, i1, i2, i3)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
+ return vreinterpretq_f32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
+ }
+#else
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& v) {
+ return _mm_castsi128_ps(_mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+#endif
+
+ template<int i0>
+ __forceinline vboolf4 shuffle(const vboolf4& v) {
+ return shuffle<i0,i0,i0,i0>(v);
+ }
+
+#if defined(__SSE3__)
+ template<> __forceinline vboolf4 shuffle<0, 0, 2, 2>(const vboolf4& v) { return _mm_moveldup_ps(v); }
+ template<> __forceinline vboolf4 shuffle<1, 1, 3, 3>(const vboolf4& v) { return _mm_movehdup_ps(v); }
+ template<> __forceinline vboolf4 shuffle<0, 1, 0, 1>(const vboolf4& v) { return _mm_castpd_ps(_mm_movedup_pd(v)); }
+#endif
+
+#if defined(__SSE4_1__) && !defined(__aarch64__)
+ template<int dst, int src, int clr> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
+ template<int dst, int src> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return insert<dst, src, 0>(a, b); }
+ template<int dst> __forceinline vboolf4 insert(const vboolf4& a, const bool b) { return insert<dst, 0>(a, vboolf4(b)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboolf4& a) { return _mm_movemask_ps(a) == 0xf; }
+ __forceinline bool reduce_or (const vboolf4& a) { return _mm_movemask_ps(a) != 0x0; }
+
+ __forceinline bool all (const vboolf4& b) { return _mm_movemask_ps(b) == 0xf; }
+ __forceinline bool any (const vboolf4& b) { return _mm_movemask_ps(b) != 0x0; }
+ __forceinline bool none(const vboolf4& b) { return _mm_movemask_ps(b) == 0x0; }
+
+ __forceinline bool all (const vboolf4& valid, const vboolf4& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboolf4& valid, const vboolf4& b) { return any(valid & b); }
+ __forceinline bool none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf4& a) { return _mm_movemask_ps(a); }
+#if defined(__aarch64__) && defined(BUILD_IOS)
+__forceinline size_t popcnt(const vboolf4& a) { return _mm_movemask_popcnt_ps(a); }
+#else
+#if defined(__SSE4_2__)
+ __forceinline size_t popcnt(const vboolf4& a) { return popcnt((size_t)_mm_movemask_ps(a)); }
+#else
+ __forceinline size_t popcnt(const vboolf4& a) { return bool(a[0])+bool(a[1])+bool(a[2])+bool(a[3]); }
+#endif
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf4& a, size_t index) { return a[index]; }
+ __forceinline void set(vboolf4& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboolf4& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboolf8_avx.h b/thirdparty/embree-aarch64/common/simd/vboolf8_avx.h
new file mode 100644
index 0000000000..4f64741b55
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboolf8_avx.h
@@ -0,0 +1,189 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX bool type */
+ template<>
+ struct vboolf<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256 v;
+ struct { __m128 vl,vh; };
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf8& a) { v = a.v; }
+ __forceinline vboolf8& operator =(const vboolf8& a) { v = a.v; return *this; }
+
+ __forceinline vboolf(__m256 a) : v(a) {}
+ __forceinline operator const __m256&() const { return v; }
+ __forceinline operator const __m256i() const { return _mm256_castps_si256(v); }
+ __forceinline operator const __m256d() const { return _mm256_castps_pd(v); }
+
+ __forceinline vboolf(int a)
+ {
+ assert(a >= 0 && a <= 255);
+#if defined (__AVX2__)
+ const __m256i mask = _mm256_set_epi32(0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1);
+ const __m256i b = _mm256_set1_epi32(a);
+ const __m256i c = _mm256_and_si256(b,mask);
+ v = _mm256_castsi256_ps(_mm256_cmpeq_epi32(c,mask));
+#else
+ vl = mm_lookupmask_ps[a & 0xF];
+ vh = mm_lookupmask_ps[a >> 4];
+#endif
+ }
+
+ __forceinline vboolf(const vboolf4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
+ __forceinline vboolf(const vboolf4& a, const vboolf4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
+ __forceinline vboolf(__m128 a, __m128 b) : vl(a), vh(b) {}
+
+ __forceinline vboolf(bool a) : v(vboolf8(vboolf4(a), vboolf4(a))) {}
+ __forceinline vboolf(bool a, bool b) : v(vboolf8(vboolf4(a), vboolf4(b))) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d) : v(vboolf8(vboolf4(a,b), vboolf4(c,d))) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h) : v(vboolf8(vboolf4(a,b,c,d), vboolf4(e,f,g,h))) {}
+
+ /* return int32 mask */
+ __forceinline __m256i mask32() const {
+ return _mm256_castps_si256(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(_mm256_setzero_ps()) {}
+#if !defined(__aarch64__)
+ __forceinline vboolf(TrueTy) : v(_mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_OQ)) {}
+#else
+ __forceinline vboolf(TrueTy) : v(_mm256_cmpeq_ps(_mm256_setzero_ps(), _mm256_setzero_ps())) {}
+#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const { assert(index < 8); return (_mm256_movemask_ps(v) >> index) & 1; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !(const vboolf8& a) { return _mm256_xor_ps(a, vboolf8(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator &(const vboolf8& a, const vboolf8& b) { return _mm256_and_ps(a, b); }
+ __forceinline vboolf8 operator |(const vboolf8& a, const vboolf8& b) { return _mm256_or_ps (a, b); }
+ __forceinline vboolf8 operator ^(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(a, b); }
+
+ __forceinline vboolf8 andn(const vboolf8& a, const vboolf8& b) { return _mm256_andnot_ps(b, a); }
+
+ __forceinline vboolf8& operator &=(vboolf8& a, const vboolf8& b) { return a = a & b; }
+ __forceinline vboolf8& operator |=(vboolf8& a, const vboolf8& b) { return a = a | b; }
+ __forceinline vboolf8& operator ^=(vboolf8& a, const vboolf8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !=(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(a, b); }
+ __forceinline vboolf8 operator ==(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(_mm256_xor_ps(a,b),vboolf8(embree::True)); }
+
+ __forceinline vboolf8 select(const vboolf8& mask, const vboolf8& t, const vboolf8& f) {
+ return _mm256_blendv_ps(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 unpacklo(const vboolf8& a, const vboolf8& b) { return _mm256_unpacklo_ps(a, b); }
+ __forceinline vboolf8 unpackhi(const vboolf8& a, const vboolf8& b) { return _mm256_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vboolf8 shuffle(const vboolf8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1>
+ __forceinline vboolf8 shuffle4(const vboolf8& v) {
+ return _mm256_permute2f128_ps(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vboolf8 shuffle4(const vboolf8& a, const vboolf8& b) {
+ return _mm256_permute2f128_ps(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf8 shuffle(const vboolf8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf8 shuffle(const vboolf8& a, const vboolf8& b) {
+ return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<> __forceinline vboolf8 shuffle<0, 0, 2, 2>(const vboolf8& v) { return _mm256_moveldup_ps(v); }
+ template<> __forceinline vboolf8 shuffle<1, 1, 3, 3>(const vboolf8& v) { return _mm256_movehdup_ps(v); }
+ template<> __forceinline vboolf8 shuffle<0, 1, 0, 1>(const vboolf8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
+
+ template<int i> __forceinline vboolf8 insert4(const vboolf8& a, const vboolf4& b) { return _mm256_insertf128_ps(a, b, i); }
+ template<int i> __forceinline vboolf4 extract4 (const vboolf8& a) { return _mm256_extractf128_ps(a, i); }
+ template<> __forceinline vboolf4 extract4<0>(const vboolf8& a) { return _mm256_castps256_ps128(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboolf8& a) { return _mm256_movemask_ps(a) == (unsigned int)0xff; }
+ __forceinline bool reduce_or (const vboolf8& a) { return !_mm256_testz_ps(a,a); }
+
+ __forceinline bool all (const vboolf8& a) { return _mm256_movemask_ps(a) == (unsigned int)0xff; }
+ __forceinline bool any (const vboolf8& a) { return !_mm256_testz_ps(a,a); }
+ __forceinline bool none(const vboolf8& a) { return _mm256_testz_ps(a,a) != 0; }
+
+ __forceinline bool all (const vboolf8& valid, const vboolf8& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboolf8& valid, const vboolf8& b) { return any(valid & b); }
+ __forceinline bool none(const vboolf8& valid, const vboolf8& b) { return none(valid & b); }
+
+ __forceinline unsigned int movemask(const vboolf8& a) { return _mm256_movemask_ps(a); }
+ __forceinline size_t popcnt (const vboolf8& a) { return popcnt((size_t)_mm256_movemask_ps(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf8& a, size_t index) { return a[index]; }
+ __forceinline void set(vboolf8& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboolf8& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", "
+ << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vboolf8_avx512.h b/thirdparty/embree-aarch64/common/simd/vboolf8_avx512.h
new file mode 100644
index 0000000000..2a52b554c7
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vboolf8_avx512.h
@@ -0,0 +1,143 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX-512 bool type */
+ template<>
+ struct vboolf<8>
+ {
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+
+ enum { size = 8 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf8& t) { v = t.v; }
+ __forceinline vboolf8& operator =(const vboolf8& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xff : 0x00; }
+ __forceinline vboolf(int t) { v = (__mmask8)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask8)t; }
+
+ __forceinline vboolf(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h)
+ : v((__mmask8)((int(h) << 7) | (int(g) << 6) | (int(f) << 5) | (int(e) << 4) | (int(d) << 3) | (int(c) << 2) | (int(b) << 1) | int(a))) {}
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m256i mask32() const {
+ return _mm256_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m512i mask64() const {
+ return _mm512_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x00) {}
+ __forceinline vboolf(TrueTy) : v(0xff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 8); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !(const vboolf8& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator &(const vboolf8& a, const vboolf8& b) { return _mm512_kand(a, b); }
+ __forceinline vboolf8 operator |(const vboolf8& a, const vboolf8& b) { return _mm512_kor(a, b); }
+ __forceinline vboolf8 operator ^(const vboolf8& a, const vboolf8& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboolf8 andn(const vboolf8& a, const vboolf8& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8& operator &=(vboolf8& a, const vboolf8& b) { return a = a & b; }
+ __forceinline vboolf8& operator |=(vboolf8& a, const vboolf8& b) { return a = a | b; }
+ __forceinline vboolf8& operator ^=(vboolf8& a, const vboolf8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !=(const vboolf8& a, const vboolf8& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf8 operator ==(const vboolf8& a, const vboolf8& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboolf8 select(const vboolf8& s, const vboolf8& a, const vboolf8& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf8& a) { return a.v == 0xff; }
+ __forceinline int any (const vboolf8& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboolf8& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboolf8& valid, const vboolf8& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf8& valid, const vboolf8& b) { return any(valid & b); }
+ __forceinline int none(const vboolf8& valid, const vboolf8& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf8& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf8& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboolf8& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf8& a, size_t index) { assert(index < 8); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf8& a, size_t index) { assert(index < 8); a |= 1 << index; }
+ __forceinline void clear(vboolf8& a, size_t index) { assert(index < 8); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf8& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<8; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vdouble4_avx.h b/thirdparty/embree-aarch64/common/simd/vdouble4_avx.h
new file mode 100644
index 0000000000..1f65b45d7e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vdouble4_avx.h
@@ -0,0 +1,324 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide AVX 64-bit double type */
+ template<>
+ struct vdouble<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256d v;
+ double i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble() {}
+ __forceinline vdouble(const vdouble4& t) { v = t.v; }
+ __forceinline vdouble4& operator =(const vdouble4& f) { v = f.v; return *this; }
+
+ __forceinline vdouble(const __m256d& t) { v = t; }
+ __forceinline operator __m256d() const { return v; }
+
+ __forceinline vdouble(double i) {
+ v = _mm256_set1_pd(i);
+ }
+
+ __forceinline vdouble(double a, double b, double c, double d) {
+ v = _mm256_set_pd(d,c,b,a);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble(ZeroTy) : v(_mm256_setzero_pd()) {}
+ __forceinline vdouble(OneTy) : v(_mm256_set1_pd(1)) {}
+ __forceinline vdouble(StepTy) : v(_mm256_set_pd(3.0,2.0,1.0,0.0)) {}
+ __forceinline vdouble(ReverseStepTy) : v(_mm256_setr_pd(3.0,2.0,1.0,0.0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(double *__restrict__ ptr, const vdouble4& a) {
+ _mm256_stream_pd(ptr, a);
+ }
+
+ static __forceinline vdouble4 loadu(const double* addr) {
+ return _mm256_loadu_pd(addr);
+ }
+
+ static __forceinline vdouble4 load(const vdouble4* addr) {
+ return _mm256_load_pd((double*)addr);
+ }
+
+ static __forceinline vdouble4 load(const double* addr) {
+ return _mm256_load_pd(addr);
+ }
+
+ static __forceinline void store(double* ptr, const vdouble4& v) {
+ _mm256_store_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(double* ptr, const vdouble4& v) {
+ _mm256_storeu_pd(ptr, v);
+ }
+
+ static __forceinline vdouble4 broadcast(const void* a) { return _mm256_set1_pd(*(double*)a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline double& operator [](size_t index) { assert(index < 4); return i[index]; }
+ __forceinline const double& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline vdouble4 asDouble(const vllong4& a) { return _mm256_castsi256_pd(a); }
+ __forceinline vllong4 asLLong (const vdouble4& a) { return _mm256_castpd_si256(a); }
+#endif
+
+ __forceinline vdouble4 operator +(const vdouble4& a) { return a; }
+ __forceinline vdouble4 operator -(const vdouble4& a) { return _mm256_sub_pd(_mm256_setzero_pd(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4 operator +(const vdouble4& a, const vdouble4& b) { return _mm256_add_pd(a, b); }
+ __forceinline vdouble4 operator +(const vdouble4& a, double b) { return a + vdouble4(b); }
+ __forceinline vdouble4 operator +(double a, const vdouble4& b) { return vdouble4(a) + b; }
+
+ __forceinline vdouble4 operator -(const vdouble4& a, const vdouble4& b) { return _mm256_sub_pd(a, b); }
+ __forceinline vdouble4 operator -(const vdouble4& a, double b) { return a - vdouble4(b); }
+ __forceinline vdouble4 operator -(double a, const vdouble4& b) { return vdouble4(a) - b; }
+
+ __forceinline vdouble4 operator *(const vdouble4& a, const vdouble4& b) { return _mm256_mul_pd(a, b); }
+ __forceinline vdouble4 operator *(const vdouble4& a, double b) { return a * vdouble4(b); }
+ __forceinline vdouble4 operator *(double a, const vdouble4& b) { return vdouble4(a) * b; }
+
+ __forceinline vdouble4 operator &(const vdouble4& a, const vdouble4& b) { return _mm256_and_pd(a, b); }
+ __forceinline vdouble4 operator &(const vdouble4& a, double b) { return a & vdouble4(b); }
+ __forceinline vdouble4 operator &(double a, const vdouble4& b) { return vdouble4(a) & b; }
+
+ __forceinline vdouble4 operator |(const vdouble4& a, const vdouble4& b) { return _mm256_or_pd(a, b); }
+ __forceinline vdouble4 operator |(const vdouble4& a, double b) { return a | vdouble4(b); }
+ __forceinline vdouble4 operator |(double a, const vdouble4& b) { return vdouble4(a) | b; }
+
+ __forceinline vdouble4 operator ^(const vdouble4& a, const vdouble4& b) { return _mm256_xor_pd(a, b); }
+ __forceinline vdouble4 operator ^(const vdouble4& a, double b) { return a ^ vdouble4(b); }
+ __forceinline vdouble4 operator ^(double a, const vdouble4& b) { return vdouble4(a) ^ b; }
+
+ __forceinline vdouble4 min(const vdouble4& a, const vdouble4& b) { return _mm256_min_pd(a, b); }
+ __forceinline vdouble4 min(const vdouble4& a, double b) { return min(a,vdouble4(b)); }
+ __forceinline vdouble4 min(double a, const vdouble4& b) { return min(vdouble4(a),b); }
+
+ __forceinline vdouble4 max(const vdouble4& a, const vdouble4& b) { return _mm256_max_pd(a, b); }
+ __forceinline vdouble4 max(const vdouble4& a, double b) { return max(a,vdouble4(b)); }
+ __forceinline vdouble4 max(double a, const vdouble4& b) { return max(vdouble4(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__FMA__)
+ __forceinline vdouble4 madd (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fmadd_pd(a,b,c); }
+ __forceinline vdouble4 msub (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fmsub_pd(a,b,c); }
+ __forceinline vdouble4 nmadd(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fnmadd_pd(a,b,c); }
+ __forceinline vdouble4 nmsub(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fnmsub_pd(a,b,c); }
+#else
+ __forceinline vdouble4 madd (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return a*b+c; }
+ __forceinline vdouble4 msub (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return a*b-c; }
+ __forceinline vdouble4 nmadd(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return -a*b+c;}
+ __forceinline vdouble4 nmsub(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return -a*b-c; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4& operator +=(vdouble4& a, const vdouble4& b) { return a = a + b; }
+ __forceinline vdouble4& operator +=(vdouble4& a, double b) { return a = a + b; }
+
+ __forceinline vdouble4& operator -=(vdouble4& a, const vdouble4& b) { return a = a - b; }
+ __forceinline vdouble4& operator -=(vdouble4& a, double b) { return a = a - b; }
+
+ __forceinline vdouble4& operator *=(vdouble4& a, const vdouble4& b) { return a = a * b; }
+ __forceinline vdouble4& operator *=(vdouble4& a, double b) { return a = a * b; }
+
+ __forceinline vdouble4& operator &=(vdouble4& a, const vdouble4& b) { return a = a & b; }
+ __forceinline vdouble4& operator &=(vdouble4& a, double b) { return a = a & b; }
+
+ __forceinline vdouble4& operator |=(vdouble4& a, const vdouble4& b) { return a = a | b; }
+ __forceinline vdouble4& operator |=(vdouble4& a, double b) { return a = a | b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LE); }
+#elif !defined(__aarch64__)
+ __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OQ); }
+ __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_UQ); }
+ __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); }
+ __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); }
+ __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); }
+ __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); }
+#else
+ __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmpeq_pd(a, b); }
+ __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmpneq_pd(a, b); }
+ __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmplt_pd(a, b); }
+ __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmpnlt_pd(a, b); }
+ __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmpnle_pd(a, b); }
+ __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmple_pd(a, b); }
+#endif
+
+ __forceinline vboold4 operator ==(const vdouble4& a, double b) { return a == vdouble4(b); }
+ __forceinline vboold4 operator ==(double a, const vdouble4& b) { return vdouble4(a) == b; }
+
+ __forceinline vboold4 operator !=(const vdouble4& a, double b) { return a != vdouble4(b); }
+ __forceinline vboold4 operator !=(double a, const vdouble4& b) { return vdouble4(a) != b; }
+
+ __forceinline vboold4 operator < (const vdouble4& a, double b) { return a < vdouble4(b); }
+ __forceinline vboold4 operator < (double a, const vdouble4& b) { return vdouble4(a) < b; }
+
+ __forceinline vboold4 operator >=(const vdouble4& a, double b) { return a >= vdouble4(b); }
+ __forceinline vboold4 operator >=(double a, const vdouble4& b) { return vdouble4(a) >= b; }
+
+ __forceinline vboold4 operator > (const vdouble4& a, double b) { return a > vdouble4(b); }
+ __forceinline vboold4 operator > (double a, const vdouble4& b) { return vdouble4(a) > b; }
+
+ __forceinline vboold4 operator <=(const vdouble4& a, double b) { return a <= vdouble4(b); }
+ __forceinline vboold4 operator <=(double a, const vdouble4& b) { return vdouble4(a) <= b; }
+
+ __forceinline vboold4 eq(const vdouble4& a, const vdouble4& b) { return a == b; }
+ __forceinline vboold4 ne(const vdouble4& a, const vdouble4& b) { return a != b; }
+ __forceinline vboold4 lt(const vdouble4& a, const vdouble4& b) { return a < b; }
+ __forceinline vboold4 ge(const vdouble4& a, const vdouble4& b) { return a >= b; }
+ __forceinline vboold4 gt(const vdouble4& a, const vdouble4& b) { return a > b; }
+ __forceinline vboold4 le(const vdouble4& a, const vdouble4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 eq(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 ne(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 lt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 ge(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 gt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 le(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 eq(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a == b); }
+ __forceinline vboold4 ne(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a != b); }
+ __forceinline vboold4 lt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a < b); }
+ __forceinline vboold4 ge(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a >= b); }
+ __forceinline vboold4 gt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a > b); }
+ __forceinline vboold4 le(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a <= b); }
+#endif
+
+ __forceinline vdouble4 select(const vboold4& m, const vdouble4& t, const vdouble4& f) {
+#if defined(__AVX512VL__)
+ return _mm256_mask_blend_pd(m, f, t);
+#else
+ return _mm256_blendv_pd(f, t, m);
+#endif
+ }
+
+ __forceinline void xchg(const vboold4& m, vdouble4& a, vdouble4& b) {
+ const vdouble4 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboold4 test(const vdouble4& a, const vdouble4& b) {
+#if defined(__AVX512VL__)
+ return _mm256_test_epi64_mask(_mm256_castpd_si256(a),_mm256_castpd_si256(b));
+#else
+ return _mm256_testz_si256(_mm256_castpd_si256(a),_mm256_castpd_si256(b));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vdouble4 shuffle(const vdouble4& v) {
+ return _mm256_permute_pd(v, (i1 << 3) | (i0 << 2) | (i1 << 1) | i0);
+ }
+
+ template<int i>
+ __forceinline vdouble4 shuffle(const vdouble4& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1>
+ __forceinline vdouble4 shuffle2(const vdouble4& v) {
+ return _mm256_permute2f128_pd(v, v, (i1 << 4) | i0);
+ }
+
+ __forceinline double toScalar(const vdouble4& v) {
+ return _mm_cvtsd_f64(_mm256_castpd256_pd128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4 vreduce_min2(const vdouble4& x) { return min(x, shuffle<1,0>(x)); }
+ __forceinline vdouble4 vreduce_min (const vdouble4& y) { const vdouble4 x = vreduce_min2(y); return min(x, shuffle2<1,0>(x)); }
+
+ __forceinline vdouble4 vreduce_max2(const vdouble4& x) { return max(x,shuffle<1,0>(x)); }
+ __forceinline vdouble4 vreduce_max (const vdouble4& y) { const vdouble4 x = vreduce_max2(y); return max(x, shuffle2<1,0>(x)); }
+
+ __forceinline vdouble4 vreduce_and2(const vdouble4& x) { return x & shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_and (const vdouble4& y) { const vdouble4 x = vreduce_and2(y); return x & shuffle2<1,0>(x); }
+
+ __forceinline vdouble4 vreduce_or2(const vdouble4& x) { return x | shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_or (const vdouble4& y) { const vdouble4 x = vreduce_or2(y); return x | shuffle2<1,0>(x); }
+
+ __forceinline vdouble4 vreduce_add2(const vdouble4& x) { return x + shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_add (const vdouble4& y) { const vdouble4 x = vreduce_add2(y); return x + shuffle2<1,0>(x); }
+
+ __forceinline double reduce_add(const vdouble4& a) { return toScalar(vreduce_add(a)); }
+ __forceinline double reduce_min(const vdouble4& a) { return toScalar(vreduce_min(a)); }
+ __forceinline double reduce_max(const vdouble4& a) { return toScalar(vreduce_max(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vdouble4& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<4; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vdouble8_avx512.h b/thirdparty/embree-aarch64/common/simd/vdouble8_avx512.h
new file mode 100644
index 0000000000..4eec7d2f6a
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vdouble8_avx512.h
@@ -0,0 +1,356 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX-512 64-bit double type */
+ template<>
+ struct vdouble<8>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboold8 Bool;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m512d v;
+ double i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble() {}
+ __forceinline vdouble(const vdouble8& t) { v = t.v; }
+ __forceinline vdouble8& operator =(const vdouble8& f) { v = f.v; return *this; }
+
+ __forceinline vdouble(const __m512d& t) { v = t; }
+ __forceinline operator __m512d() const { return v; }
+ __forceinline operator __m256d() const { return _mm512_castpd512_pd256(v); }
+
+ __forceinline vdouble(double i) {
+ v = _mm512_set1_pd(i);
+ }
+
+ __forceinline vdouble(double a, double b, double c, double d) {
+ v = _mm512_set4_pd(d,c,b,a);
+ }
+
+ __forceinline vdouble(double a0, double a1, double a2, double a3,
+ double a4, double a5, double a6, double a7)
+ {
+ v = _mm512_set_pd(a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble(ZeroTy) : v(_mm512_setzero_pd()) {}
+ __forceinline vdouble(OneTy) : v(_mm512_set1_pd(1)) {}
+ __forceinline vdouble(StepTy) : v(_mm512_set_pd(7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0)) {}
+ __forceinline vdouble(ReverseStepTy) : v(_mm512_setr_pd(7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void *__restrict__ ptr, const vdouble8& a) {
+ _mm512_stream_pd((double*)ptr, a);
+ }
+
+ static __forceinline vdouble8 loadu(const void* addr) {
+ return _mm512_loadu_pd((double*)addr);
+ }
+
+ static __forceinline vdouble8 load(const vdouble8* addr) {
+ return _mm512_load_pd((double*)addr);
+ }
+
+ static __forceinline vdouble8 load(const double* addr) {
+ return _mm512_load_pd(addr);
+ }
+
+ static __forceinline void store(void* ptr, const vdouble8& v) {
+ _mm512_store_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vdouble8& v) {
+ _mm512_storeu_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(const vboold8& mask, double* ptr, const vdouble8& f) {
+ _mm512_mask_storeu_pd(ptr, mask, f);
+ }
+
+ static __forceinline void store(const vboold8& mask, void* addr, const vdouble8& v2) {
+ _mm512_mask_store_pd(addr, mask, v2);
+ }
+
+ /* pass by value to avoid compiler generating inefficient code */
+ static __forceinline void storeu_compact(const vboold8 mask,void * addr, const vdouble8& reg) {
+ _mm512_mask_compressstoreu_pd(addr, mask, reg);
+ }
+
+ static __forceinline vdouble8 compact64bit(const vboold8& mask, vdouble8& v) {
+ return _mm512_mask_compress_pd(v, mask, v);
+ }
+
+ static __forceinline vdouble8 compact(const vboold8& mask, vdouble8& v) {
+ return _mm512_mask_compress_pd(v, mask, v);
+ }
+
+ static __forceinline vdouble8 compact(const vboold8& mask, const vdouble8& a, vdouble8& b) {
+ return _mm512_mask_compress_pd(a, mask, b);
+ }
+
+ static __forceinline vdouble8 broadcast(const void* a) { return _mm512_set1_pd(*(double*)a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline double& operator [](size_t index) { assert(index < 8); return i[index]; }
+ __forceinline const double& operator [](size_t index) const { assert(index < 8); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 asDouble(const vllong8& a) { return _mm512_castsi512_pd(a); }
+ __forceinline vllong8 asLLong (const vdouble8& a) { return _mm512_castpd_si512(a); }
+
+ __forceinline vdouble8 operator +(const vdouble8& a) { return a; }
+ __forceinline vdouble8 operator -(const vdouble8& a) { return _mm512_sub_pd(_mm512_setzero_pd(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 operator +(const vdouble8& a, const vdouble8& b) { return _mm512_add_pd(a, b); }
+ __forceinline vdouble8 operator +(const vdouble8& a, double b) { return a + vdouble8(b); }
+ __forceinline vdouble8 operator +(double a, const vdouble8& b) { return vdouble8(a) + b; }
+
+ __forceinline vdouble8 operator -(const vdouble8& a, const vdouble8& b) { return _mm512_sub_pd(a, b); }
+ __forceinline vdouble8 operator -(const vdouble8& a, double b) { return a - vdouble8(b); }
+ __forceinline vdouble8 operator -(double a, const vdouble8& b) { return vdouble8(a) - b; }
+
+ __forceinline vdouble8 operator *(const vdouble8& a, const vdouble8& b) { return _mm512_mul_pd(a, b); }
+ __forceinline vdouble8 operator *(const vdouble8& a, double b) { return a * vdouble8(b); }
+ __forceinline vdouble8 operator *(double a, const vdouble8& b) { return vdouble8(a) * b; }
+
+ __forceinline vdouble8 operator &(const vdouble8& a, const vdouble8& b) { return _mm512_and_pd(a, b); }
+ __forceinline vdouble8 operator &(const vdouble8& a, double b) { return a & vdouble8(b); }
+ __forceinline vdouble8 operator &(double a, const vdouble8& b) { return vdouble8(a) & b; }
+
+ __forceinline vdouble8 operator |(const vdouble8& a, const vdouble8& b) { return _mm512_or_pd(a, b); }
+ __forceinline vdouble8 operator |(const vdouble8& a, double b) { return a | vdouble8(b); }
+ __forceinline vdouble8 operator |(double a, const vdouble8& b) { return vdouble8(a) | b; }
+
+ __forceinline vdouble8 operator ^(const vdouble8& a, const vdouble8& b) { return _mm512_xor_pd(a, b); }
+ __forceinline vdouble8 operator ^(const vdouble8& a, double b) { return a ^ vdouble8(b); }
+ __forceinline vdouble8 operator ^(double a, const vdouble8& b) { return vdouble8(a) ^ b; }
+
+ __forceinline vdouble8 operator <<(const vdouble8& a, const unsigned int n) { return _mm512_castsi512_pd(_mm512_slli_epi64(_mm512_castpd_si512(a), n)); }
+ __forceinline vdouble8 operator >>(const vdouble8& a, const unsigned int n) { return _mm512_castsi512_pd(_mm512_srai_epi64(_mm512_castpd_si512(a), n)); }
+
+ __forceinline vdouble8 operator <<(const vdouble8& a, const vllong8& n) { return _mm512_castsi512_pd(_mm512_sllv_epi64(_mm512_castpd_si512(a), n)); }
+ __forceinline vdouble8 operator >>(const vdouble8& a, const vllong8& n) { return _mm512_castsi512_pd(_mm512_srav_epi64(_mm512_castpd_si512(a), n)); }
+
+ __forceinline vdouble8 sll (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_slli_epi64(_mm512_castpd_si512(a), b)); }
+ __forceinline vdouble8 sra (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_srai_epi64(_mm512_castpd_si512(a), b)); }
+ __forceinline vdouble8 srl (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_srli_epi64(_mm512_castpd_si512(a), b)); }
+
+ __forceinline vdouble8 min(const vdouble8& a, const vdouble8& b) { return _mm512_min_pd(a, b); }
+ __forceinline vdouble8 min(const vdouble8& a, double b) { return min(a,vdouble8(b)); }
+ __forceinline vdouble8 min(double a, const vdouble8& b) { return min(vdouble8(a),b); }
+
+ __forceinline vdouble8 max(const vdouble8& a, const vdouble8& b) { return _mm512_max_pd(a, b); }
+ __forceinline vdouble8 max(const vdouble8& a, double b) { return max(a,vdouble8(b)); }
+ __forceinline vdouble8 max(double a, const vdouble8& b) { return max(vdouble8(a),b); }
+
+ __forceinline vdouble8 mask_add(const vboold8& mask, vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_add_pd(c,mask,a,b); }
+ __forceinline vdouble8 mask_sub(const vboold8& mask, vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_sub_pd(c,mask,a,b); }
+
+ __forceinline vdouble8 mask_and(const vboold8& m,vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_and_pd(c,m,a,b); }
+ __forceinline vdouble8 mask_or (const vboold8& m,vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_or_pd(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 madd (const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fmadd_pd(a,b,c); }
+ __forceinline vdouble8 msub (const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fmsub_pd(a,b,c); }
+ __forceinline vdouble8 nmadd(const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fnmadd_pd(a,b,c); }
+ __forceinline vdouble8 nmsub(const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fnmsub_pd(a,b,c); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8& operator +=(vdouble8& a, const vdouble8& b) { return a = a + b; }
+ __forceinline vdouble8& operator +=(vdouble8& a, double b) { return a = a + b; }
+
+ __forceinline vdouble8& operator -=(vdouble8& a, const vdouble8& b) { return a = a - b; }
+ __forceinline vdouble8& operator -=(vdouble8& a, double b) { return a = a - b; }
+
+ __forceinline vdouble8& operator *=(vdouble8& a, const vdouble8& b) { return a = a * b; }
+ __forceinline vdouble8& operator *=(vdouble8& a, double b) { return a = a * b; }
+
+ __forceinline vdouble8& operator &=(vdouble8& a, const vdouble8& b) { return a = a & b; }
+ __forceinline vdouble8& operator &=(vdouble8& a, double b) { return a = a & b; }
+
+ __forceinline vdouble8& operator |=(vdouble8& a, const vdouble8& b) { return a = a | b; }
+ __forceinline vdouble8& operator |=(vdouble8& a, double b) { return a = a | b; }
+
+ __forceinline vdouble8& operator <<=(vdouble8& a, const double b) { return a = a << b; }
+ __forceinline vdouble8& operator >>=(vdouble8& a, const double b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator ==(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 operator ==(const vdouble8& a, double b) { return a == vdouble8(b); }
+ __forceinline vboold8 operator ==(double a, const vdouble8& b) { return vdouble8(a) == b; }
+
+ __forceinline vboold8 operator !=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 operator !=(const vdouble8& a, double b) { return a != vdouble8(b); }
+ __forceinline vboold8 operator !=(double a, const vdouble8& b) { return vdouble8(a) != b; }
+
+ __forceinline vboold8 operator < (const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 operator < (const vdouble8& a, double b) { return a < vdouble8(b); }
+ __forceinline vboold8 operator < (double a, const vdouble8& b) { return vdouble8(a) < b; }
+
+ __forceinline vboold8 operator >=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 operator >=(const vdouble8& a, double b) { return a >= vdouble8(b); }
+ __forceinline vboold8 operator >=(double a, const vdouble8& b) { return vdouble8(a) >= b; }
+
+ __forceinline vboold8 operator > (const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 operator > (const vdouble8& a, double b) { return a > vdouble8(b); }
+ __forceinline vboold8 operator > (double a, const vdouble8& b) { return vdouble8(a) > b; }
+
+ __forceinline vboold8 operator <=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboold8 operator <=(const vdouble8& a, double b) { return a <= vdouble8(b); }
+ __forceinline vboold8 operator <=(double a, const vdouble8& b) { return vdouble8(a) <= b; }
+
+ __forceinline vboold8 eq(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboold8 eq(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vdouble8 select(const vboold8& m, const vdouble8& t, const vdouble8& f) {
+ return _mm512_mask_or_pd(f,m,t,t);
+ }
+
+ __forceinline void xchg(const vboold8& m, vdouble8& a, vdouble8& b) {
+ const vdouble8 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboold8 test(const vboold8& m, const vdouble8& a, const vdouble8& b) {
+ return _mm512_mask_test_epi64_mask(m,_mm512_castpd_si512(a),_mm512_castpd_si512(b));
+ }
+
+ __forceinline vboold8 test(const vdouble8& a, const vdouble8& b) {
+ return _mm512_test_epi64_mask(_mm512_castpd_si512(a),_mm512_castpd_si512(b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return _mm512_permute_pd(v, (i1 << 7) | (i0 << 6) | (i1 << 5) | (i0 << 4) | (i1 << 3) | (i0 << 2) | (i1 << 1) | i0);
+ }
+
+ template<int i>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return _mm512_permutex_pd(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vdouble8 shuffle4(const vdouble8& v) {
+ return _mm512_shuffle_f64x2(v, v, _MM_SHUFFLE(i1*2+1, i1*2, i0*2+1, i0*2));
+ }
+
+ template<int i>
+ __forceinline vdouble8 shuffle4(const vdouble8& v) {
+ return shuffle4<i, i>(v);
+ }
+
+ template<int i>
+ __forceinline vdouble8 align_shift_right(const vdouble8& a, const vdouble8& b) {
+ return _mm512_castsi512_pd(_mm512_alignr_epi64(_mm512_castpd_si512(a), _mm512_castpd_si512(b), i));
+ }
+
+ __forceinline double toScalar(const vdouble8& v) {
+ return _mm_cvtsd_f64(_mm512_castpd512_pd128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 vreduce_add2(vdouble8 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vdouble8 vreduce_add4(vdouble8 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vdouble8 vreduce_add (vdouble8 x) { x = vreduce_add4(x); return x + shuffle4<1,0>(x); }
+
+ __forceinline vdouble8 vreduce_min2(vdouble8 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vdouble8 vreduce_min4(vdouble8 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vdouble8 vreduce_min (vdouble8 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0>(x)); }
+
+ __forceinline vdouble8 vreduce_max2(vdouble8 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vdouble8 vreduce_max4(vdouble8 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vdouble8 vreduce_max (vdouble8 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0>(x)); }
+
+ __forceinline double reduce_add(const vdouble8& v) { return toScalar(vreduce_add(v)); }
+ __forceinline double reduce_min(const vdouble8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline double reduce_max(const vdouble8& v) { return toScalar(vreduce_max(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 permute(const vdouble8& v, const vllong8& index) {
+ return _mm512_permutexvar_pd(index, v);
+ }
+
+ __forceinline vdouble8 reverse(const vdouble8& a) {
+ return permute(a, vllong8(reverse_step));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vdouble8& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<8; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vfloat16_avx512.h b/thirdparty/embree-aarch64/common/simd/vfloat16_avx512.h
new file mode 100644
index 0000000000..aed2419b77
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vfloat16_avx512.h
@@ -0,0 +1,771 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 16-wide AVX-512 float type */
+ template<>
+ struct vfloat<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512 v;
+ float f[16];
+ int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat16& t) { v = t; }
+ __forceinline vfloat16& operator =(const vfloat16& f) { v = f.v; return *this; }
+
+ __forceinline vfloat(const __m512& t) { v = t; }
+ __forceinline operator __m512() const { return v; }
+ __forceinline operator __m256() const { return _mm512_castps512_ps256(v); }
+ __forceinline operator __m128() const { return _mm512_castps512_ps128(v); }
+
+ __forceinline vfloat(float f) {
+ v = _mm512_set1_ps(f);
+ }
+
+ __forceinline vfloat(float a, float b, float c, float d) {
+ v = _mm512_set4_ps(a, b, c, d);
+ }
+
+ __forceinline vfloat(const vfloat4& i) {
+ v = _mm512_broadcast_f32x4(i);
+ }
+
+ __forceinline vfloat(const vfloat4& a, const vfloat4& b, const vfloat4& c, const vfloat4& d) {
+ v = _mm512_castps128_ps512(a);
+ v = _mm512_insertf32x4(v, b, 1);
+ v = _mm512_insertf32x4(v, c, 2);
+ v = _mm512_insertf32x4(v, d, 3);
+ }
+
+ __forceinline vfloat(const vboolf16& mask, const vfloat4& a, const vfloat4& b) {
+ v = _mm512_broadcast_f32x4(a);
+ v = _mm512_mask_broadcast_f32x4(v,mask,b);
+ }
+
+ __forceinline vfloat(const vfloat8& i) {
+ v = _mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castps_pd(i)));
+ }
+
+ __forceinline vfloat(const vfloat8& a, const vfloat8& b) {
+ v = _mm512_castps256_ps512(a);
+#if defined(__AVX512DQ__)
+ v = _mm512_insertf32x8(v, b, 1);
+#else
+ v = _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castps_pd(v), _mm256_castps_pd(b), 1));
+#endif
+ }
+
+ /* WARNING: due to f64x4 the mask is considered as an 8bit mask */
+ __forceinline vfloat(const vboolf16& mask, const vfloat8& a, const vfloat8& b) {
+ __m512d aa = _mm512_broadcast_f64x4(_mm256_castps_pd(a));
+ aa = _mm512_mask_broadcast_f64x4(aa,mask,_mm256_castps_pd(b));
+ v = _mm512_castpd_ps(aa);
+ }
+
+ __forceinline explicit vfloat(const vint16& a) {
+ v = _mm512_cvtepi32_ps(a);
+ }
+
+ __forceinline explicit vfloat(const vuint16& a) {
+ v = _mm512_cvtepu32_ps(a);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm512_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm512_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm512_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm512_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm512_set_ps(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vfloat(NaNTy) : v(_mm512_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm512_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat16 load (const void* ptr) { return _mm512_load_ps((float*)ptr); }
+ static __forceinline vfloat16 loadu(const void* ptr) { return _mm512_loadu_ps((float*)ptr); }
+
+ static __forceinline vfloat16 load (const vboolf16& mask, const void* ptr) { return _mm512_mask_load_ps (_mm512_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat16 loadu(const vboolf16& mask, const void* ptr) { return _mm512_mask_loadu_ps(_mm512_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (void* ptr, const vfloat16& v) { _mm512_store_ps ((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat16& v) { _mm512_storeu_ps((float*)ptr,v); }
+
+ static __forceinline void store (const vboolf16& mask, void* ptr, const vfloat16& v) { _mm512_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vfloat16& v) { _mm512_mask_storeu_ps((float*)ptr,mask,v); }
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vfloat16& a) {
+ _mm512_stream_ps((float*)ptr,a);
+ }
+
+ static __forceinline vfloat16 broadcast(const float* f) {
+ return _mm512_set1_ps(*f);
+ }
+
+ static __forceinline vfloat16 compact(const vboolf16& mask, vfloat16 &v) {
+ return _mm512_mask_compress_ps(v, mask, v);
+ }
+ static __forceinline vfloat16 compact(const vboolf16& mask, vfloat16 &a, const vfloat16& b) {
+ return _mm512_mask_compress_ps(a, mask, b);
+ }
+
+ static __forceinline vfloat16 expand(const vboolf16& mask, const vfloat16& a, vfloat16& b) {
+ return _mm512_mask_expand_ps(b, mask, a);
+ }
+
+ static __forceinline vfloat16 loadu_compact(const vboolf16& mask, const void* ptr) {
+ return _mm512_mask_expandloadu_ps(_mm512_setzero_ps(), mask, (float*)ptr);
+ }
+
+ static __forceinline void storeu_compact(const vboolf16& mask, float *addr, const vfloat16 reg) {
+ _mm512_mask_compressstoreu_ps(addr, mask, reg);
+ }
+
+ static __forceinline void storeu_compact_single(const vboolf16& mask, float * addr, const vfloat16& reg) {
+ //_mm512_mask_compressstoreu_ps(addr,mask,reg);
+ *addr = mm512_cvtss_f32(_mm512_mask_compress_ps(reg, mask, reg));
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat16 gather(const float* ptr, const vint16& index) {
+ return _mm512_i32gather_ps(index, ptr, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat16 gather(const vboolf16& mask, const float* ptr, const vint16& index) {
+ vfloat16 r = zero;
+ return _mm512_mask_i32gather_ps(r, mask, index, ptr, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(float* ptr, const vint16& index, const vfloat16& v) {
+ _mm512_i32scatter_ps(ptr, index, v, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, float* ptr, const vint16& index, const vfloat16& v) {
+ _mm512_mask_i32scatter_ps(ptr, mask, index, v, scale);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float& operator [](size_t index) { assert(index < 16); return f[index]; }
+ __forceinline const float& operator [](size_t index) const { assert(index < 16); return f[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 asFloat(const vint16& a) { return _mm512_castsi512_ps(a); }
+ __forceinline vint16 asInt (const vfloat16& a) { return _mm512_castps_si512(a); }
+ __forceinline vuint16 asUInt (const vfloat16& a) { return _mm512_castps_si512(a); }
+
+ __forceinline vint16 toInt (const vfloat16& a) { return vint16(a); }
+ __forceinline vfloat16 toFloat(const vint16& a) { return vfloat16(a); }
+
+ __forceinline vfloat16 operator +(const vfloat16& a) { return a; }
+ __forceinline vfloat16 operator -(const vfloat16& a) { return _mm512_mul_ps(a,vfloat16(-1)); }
+
+ __forceinline vfloat16 abs (const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x7FFFFFFF))); }
+ __forceinline vfloat16 signmsk(const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x80000000))); }
+
+ __forceinline vfloat16 rcp(const vfloat16& a) {
+#if defined(__AVX512ER__)
+ return _mm512_rcp28_ps(a);
+#else
+ const vfloat16 r = _mm512_rcp14_ps(a);
+ return _mm512_mul_ps(r, _mm512_fnmadd_ps(r, a, vfloat16(2.0f)));
+#endif
+ }
+
+ __forceinline vfloat16 sqr (const vfloat16& a) { return _mm512_mul_ps(a,a); }
+ __forceinline vfloat16 sqrt(const vfloat16& a) { return _mm512_sqrt_ps(a); }
+
+ __forceinline vfloat16 rsqrt(const vfloat16& a)
+ {
+#if defined(__AVX512VL__)
+ const vfloat16 r = _mm512_rsqrt14_ps(a);
+ return _mm512_fmadd_ps(_mm512_set1_ps(1.5f), r,
+ _mm512_mul_ps(_mm512_mul_ps(_mm512_mul_ps(a, _mm512_set1_ps(-0.5f)), r), _mm512_mul_ps(r, r)));
+#else
+ return _mm512_rsqrt28_ps(a);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 operator +(const vfloat16& a, const vfloat16& b) { return _mm512_add_ps(a, b); }
+ __forceinline vfloat16 operator +(const vfloat16& a, float b) { return a + vfloat16(b); }
+ __forceinline vfloat16 operator +(float a, const vfloat16& b) { return vfloat16(a) + b; }
+
+ __forceinline vfloat16 operator -(const vfloat16& a, const vfloat16& b) { return _mm512_sub_ps(a, b); }
+ __forceinline vfloat16 operator -(const vfloat16& a, float b) { return a - vfloat16(b); }
+ __forceinline vfloat16 operator -(float a, const vfloat16& b) { return vfloat16(a) - b; }
+
+ __forceinline vfloat16 operator *(const vfloat16& a, const vfloat16& b) { return _mm512_mul_ps(a, b); }
+ __forceinline vfloat16 operator *(const vfloat16& a, float b) { return a * vfloat16(b); }
+ __forceinline vfloat16 operator *(float a, const vfloat16& b) { return vfloat16(a) * b; }
+
+ __forceinline vfloat16 operator /(const vfloat16& a, const vfloat16& b) { return _mm512_div_ps(a,b); }
+ __forceinline vfloat16 operator /(const vfloat16& a, float b) { return a/vfloat16(b); }
+ __forceinline vfloat16 operator /(float a, const vfloat16& b) { return vfloat16(a)/b; }
+
+ __forceinline vfloat16 operator &(const vfloat16& a, const vfloat16& b) { return _mm512_and_ps(a,b); }
+ __forceinline vfloat16 operator |(const vfloat16& a, const vfloat16& b) { return _mm512_or_ps(a,b); }
+ __forceinline vfloat16 operator ^(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_xor_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b)));
+ }
+
+ __forceinline vfloat16 min(const vfloat16& a, const vfloat16& b) {
+ return _mm512_min_ps(a,b);
+ }
+ __forceinline vfloat16 min(const vfloat16& a, float b) {
+ return _mm512_min_ps(a,vfloat16(b));
+ }
+ __forceinline vfloat16 min(const float& a, const vfloat16& b) {
+ return _mm512_min_ps(vfloat16(a),b);
+ }
+
+ __forceinline vfloat16 max(const vfloat16& a, const vfloat16& b) {
+ return _mm512_max_ps(a,b);
+ }
+ __forceinline vfloat16 max(const vfloat16& a, float b) {
+ return _mm512_max_ps(a,vfloat16(b));
+ }
+ __forceinline vfloat16 max(const float& a, const vfloat16& b) {
+ return _mm512_max_ps(vfloat16(a),b);
+ }
+
+ __forceinline vfloat16 mask_add(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) { return _mm512_mask_add_ps (c,mask,a,b); }
+ __forceinline vfloat16 mask_min(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) {
+ return _mm512_mask_min_ps(c,mask,a,b);
+ };
+ __forceinline vfloat16 mask_max(const vboolf16& mask, const vfloat16& c, const vfloat16& a, const vfloat16& b) {
+ return _mm512_mask_max_ps(c,mask,a,b);
+ };
+
+ __forceinline vfloat16 mini(const vfloat16& a, const vfloat16& b) {
+#if !defined(__AVX512ER__) // SKX
+ const vint16 ai = _mm512_castps_si512(a);
+ const vint16 bi = _mm512_castps_si512(b);
+ const vint16 ci = _mm512_min_epi32(ai,bi);
+ return _mm512_castsi512_ps(ci);
+#else // KNL
+ return min(a,b);
+#endif
+ }
+
+ __forceinline vfloat16 maxi(const vfloat16& a, const vfloat16& b) {
+#if !defined(__AVX512ER__) // SKX
+ const vint16 ai = _mm512_castps_si512(a);
+ const vint16 bi = _mm512_castps_si512(b);
+ const vint16 ci = _mm512_max_epi32(ai,bi);
+ return _mm512_castsi512_ps(ci);
+#else // KNL
+ return max(a,b);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 madd (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_ps(a,b,c); }
+ __forceinline vfloat16 msub (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
+ __forceinline vfloat16 nmadd(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(a,b,c); }
+ __forceinline vfloat16 nmsub(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmsub_ps(a,b,c); }
+
+ __forceinline vfloat16 mask_msub(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_ps(a,mask,b,c); }
+
+ __forceinline vfloat16 madd231 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_ps(c,b,a); }
+ __forceinline vfloat16 msub213 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
+ __forceinline vfloat16 msub231 (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(c,b,a); }
+ __forceinline vfloat16 msubr231(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(c,b,a); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Operators with rounding
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 madd_round_down(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_round_ps(a,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 madd_round_up (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_round_ps(a,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 mul_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_mul_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 mul_round_up (const vfloat16& a, const vfloat16& b) { return _mm512_mul_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 add_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_add_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 add_round_up (const vfloat16& a, const vfloat16& b) { return _mm512_add_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 sub_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_sub_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 sub_round_up (const vfloat16& a, const vfloat16& b) { return _mm512_sub_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 div_round_down(const vfloat16& a, const vfloat16& b) { return _mm512_div_round_ps(a,b,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 div_round_up (const vfloat16& a, const vfloat16& b) { return _mm512_div_round_ps(a,b,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 mask_msub_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 mask_msub_round_up (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_fmsub_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 mask_mul_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_mul_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 mask_mul_round_up (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_mul_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+ __forceinline vfloat16 mask_sub_round_down(const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_sub_round_ps(a,mask,b,c,_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); }
+ __forceinline vfloat16 mask_sub_round_up (const vboolf16& mask,const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_mask_sub_round_ps(a,mask,b,c,_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16& operator +=(vfloat16& a, const vfloat16& b) { return a = a + b; }
+ __forceinline vfloat16& operator +=(vfloat16& a, float b) { return a = a + b; }
+
+ __forceinline vfloat16& operator -=(vfloat16& a, const vfloat16& b) { return a = a - b; }
+ __forceinline vfloat16& operator -=(vfloat16& a, float b) { return a = a - b; }
+
+ __forceinline vfloat16& operator *=(vfloat16& a, const vfloat16& b) { return a = a * b; }
+ __forceinline vfloat16& operator *=(vfloat16& a, float b) { return a = a * b; }
+
+ __forceinline vfloat16& operator /=(vfloat16& a, const vfloat16& b) { return a = a / b; }
+ __forceinline vfloat16& operator /=(vfloat16& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vfloat16& a, float b) { return a == vfloat16(b); }
+ __forceinline vboolf16 operator ==(float a, const vfloat16& b) { return vfloat16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vfloat16& a, float b) { return a != vfloat16(b); }
+ __forceinline vboolf16 operator !=(float a, const vfloat16& b) { return vfloat16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vfloat16& a, float b) { return a < vfloat16(b); }
+ __forceinline vboolf16 operator < (float a, const vfloat16& b) { return vfloat16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vfloat16& a, float b) { return a >= vfloat16(b); }
+ __forceinline vboolf16 operator >=(float a, const vfloat16& b) { return vfloat16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vfloat16& a, float b) { return a > vfloat16(b); }
+ __forceinline vboolf16 operator > (float a, const vfloat16& b) { return vfloat16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vfloat16& a, float b) { return a <= vfloat16(b); }
+ __forceinline vboolf16 operator <=(float a, const vfloat16& b) { return vfloat16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboolf16 eq(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vfloat16 select(const vboolf16& s, const vfloat16& t, const vfloat16& f) {
+ return _mm512_mask_blend_ps(s, f, t);
+ }
+
+ __forceinline vfloat16 lerp(const vfloat16& a, const vfloat16& b, const vfloat16& t) {
+ return madd(t,b-a,a);
+ }
+
+ __forceinline void xchg(vboolf16 m, vfloat16& a, vfloat16& b)
+ {
+ vfloat16 c = a;
+ a = select(m,b,a);
+ b = select(m,c,b);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 floor(const vfloat16& a) {
+ return _mm512_floor_ps(a);
+ }
+ __forceinline vfloat16 ceil (const vfloat16& a) {
+ return _mm512_ceil_ps(a);
+ }
+ __forceinline vfloat16 round (const vfloat16& a) {
+ return _mm512_roundscale_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
+ }
+ __forceinline vint16 floori (const vfloat16& a) {
+ return _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 unpacklo(const vfloat16& a, const vfloat16& b) { return _mm512_unpacklo_ps(a, b); }
+ __forceinline vfloat16 unpackhi(const vfloat16& a, const vfloat16& b) { return _mm512_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vfloat16 shuffle(const vfloat16& v) {
+ return _mm512_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat16 shuffle(const vfloat16& v) {
+ return _mm512_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i>
+ __forceinline vfloat16 shuffle4(const vfloat16& v) {
+ return _mm512_shuffle_f32x4(v, v ,_MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat16 shuffle4(const vfloat16& v) {
+ return _mm512_shuffle_f32x4(v, v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ __forceinline vfloat16 interleave_even(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_shuffle_epi32(_mm512_castps_si512(a), mm512_int2mask(0xaaaa), _mm512_castps_si512(b), (_MM_PERM_ENUM)0xb1));
+ }
+
+ __forceinline vfloat16 interleave_odd(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_shuffle_epi32(_mm512_castps_si512(b), mm512_int2mask(0x5555), _mm512_castps_si512(a), (_MM_PERM_ENUM)0xb1));
+ }
+
+ __forceinline vfloat16 interleave2_even(const vfloat16& a, const vfloat16& b) {
+ /* mask should be 8-bit but is 16-bit to reuse for interleave_even */
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xaaaa), _mm512_castps_si512(b), (_MM_PERM_ENUM)0xb1));
+ }
+
+ __forceinline vfloat16 interleave2_odd(const vfloat16& a, const vfloat16& b) {
+ /* mask should be 8-bit but is 16-bit to reuse for interleave_odd */
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(b), mm512_int2mask(0x5555), _mm512_castps_si512(a), (_MM_PERM_ENUM)0xb1));
+ }
+
+ __forceinline vfloat16 interleave4_even(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xcc), _mm512_castps_si512(b), (_MM_PERM_ENUM)0x4e));
+ }
+
+ __forceinline vfloat16 interleave4_odd(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(b), mm512_int2mask(0x33), _mm512_castps_si512(a), (_MM_PERM_ENUM)0x4e));
+ }
+
+ __forceinline vfloat16 permute(vfloat16 v, __m512i index) {
+ return _mm512_castsi512_ps(_mm512_permutexvar_epi32(index, _mm512_castps_si512(v)));
+ }
+
+ __forceinline vfloat16 reverse(const vfloat16& v) {
+ return permute(v,_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0));
+ }
+
+ template<int i>
+ __forceinline vfloat16 align_shift_right(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_alignr_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b),i));
+ };
+
+ template<int i>
+ __forceinline vfloat16 mask_align_shift_right(const vboolf16& mask, vfloat16& c, const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_alignr_epi32(_mm512_castps_si512(c),mask,_mm512_castps_si512(a),_mm512_castps_si512(b),i));
+ };
+
+ __forceinline vfloat16 shift_left_1(const vfloat16& a) {
+ vfloat16 z = zero;
+ return mask_align_shift_right<15>(0xfffe,z,a,a);
+ }
+
+ __forceinline vfloat16 shift_right_1(const vfloat16& x) {
+ return align_shift_right<1>(zero,x);
+ }
+
+ __forceinline float toScalar(const vfloat16& v) { return mm512_cvtss_f32(v); }
+
+
+ template<int i> __forceinline vfloat16 insert4(const vfloat16& a, const vfloat4& b) { return _mm512_insertf32x4(a, b, i); }
+
+ template<int N, int i>
+ vfloat<N> extractN(const vfloat16& v);
+
+ template<> __forceinline vfloat4 extractN<4,0>(const vfloat16& v) { return _mm512_castps512_ps128(v); }
+ template<> __forceinline vfloat4 extractN<4,1>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 1); }
+ template<> __forceinline vfloat4 extractN<4,2>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 2); }
+ template<> __forceinline vfloat4 extractN<4,3>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 3); }
+
+ template<> __forceinline vfloat8 extractN<8,0>(const vfloat16& v) { return _mm512_castps512_ps256(v); }
+ template<> __forceinline vfloat8 extractN<8,1>(const vfloat16& v) { return _mm512_extractf32x8_ps(v, 1); }
+
+ template<int i> __forceinline vfloat4 extract4 (const vfloat16& v) { return _mm512_extractf32x4_ps(v, i); }
+ template<> __forceinline vfloat4 extract4<0>(const vfloat16& v) { return _mm512_castps512_ps128(v); }
+
+ template<int i> __forceinline vfloat8 extract8 (const vfloat16& v) { return _mm512_extractf32x8_ps(v, i); }
+ template<> __forceinline vfloat8 extract8<0>(const vfloat16& v) { return _mm512_castps512_ps256(v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
+ {
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+ vfloat16 a0a1_c0c1 = interleave_even(r0, r1);
+ vfloat16 a2a3_c2c3 = interleave_even(r2, r3);
+ vfloat16 b0b1_d0d1 = interleave_odd (r0, r1);
+ vfloat16 b2b3_d2d3 = interleave_odd (r2, r3);
+
+ c0 = interleave2_even(a0a1_c0c1, a2a3_c2c3);
+ c1 = interleave2_even(b0b1_d0d1, b2b3_d2d3);
+ c2 = interleave2_odd (a0a1_c0c1, a2a3_c2c3);
+ c3 = interleave2_odd (b0b1_d0d1, b2b3_d2d3);
+#else
+ vfloat16 a0a2_b0b2 = unpacklo(r0, r2);
+ vfloat16 c0c2_d0d2 = unpackhi(r0, r2);
+ vfloat16 a1a3_b1b3 = unpacklo(r1, r3);
+ vfloat16 c1c3_d1d3 = unpackhi(r1, r3);
+
+ c0 = unpacklo(a0a2_b0b2, a1a3_b1b3);
+ c1 = unpackhi(a0a2_b0b2, a1a3_b1b3);
+ c2 = unpacklo(c0c2_d0d2, c1c3_d1d3);
+ c3 = unpackhi(c0c2_d0d2, c1c3_d1d3);
+#endif
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3,
+ const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ const vfloat4& r8, const vfloat4& r9, const vfloat4& r10, const vfloat4& r11,
+ const vfloat4& r12, const vfloat4& r13, const vfloat4& r14, const vfloat4& r15,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
+ {
+ return transpose(vfloat16(r0, r4, r8, r12), vfloat16(r1, r5, r9, r13), vfloat16(r2, r6, r10, r14), vfloat16(r3, r7, r11, r15),
+ c0, c1, c2, c3);
+ }
+
+ __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
+ const vfloat16& r4, const vfloat16& r5, const vfloat16& r6, const vfloat16& r7,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3,
+ vfloat16& c4, vfloat16& c5, vfloat16& c6, vfloat16& c7)
+ {
+ vfloat16 a0a1a2a3_e0e1e2e3, b0b1b2b3_f0f1f2f3, c0c1c2c3_g0g1g2g3, d0d1d2d3_h0h1h2h3;
+ transpose(r0, r1, r2, r3, a0a1a2a3_e0e1e2e3, b0b1b2b3_f0f1f2f3, c0c1c2c3_g0g1g2g3, d0d1d2d3_h0h1h2h3);
+
+ vfloat16 a4a5a6a7_e4e5e6e7, b4b5b6b7_f4f5f6f7, c4c5c6c7_g4g5g6g7, d4d5d6d7_h4h5h6h7;
+ transpose(r4, r5, r6, r7, a4a5a6a7_e4e5e6e7, b4b5b6b7_f4f5f6f7, c4c5c6c7_g4g5g6g7, d4d5d6d7_h4h5h6h7);
+
+ c0 = interleave4_even(a0a1a2a3_e0e1e2e3, a4a5a6a7_e4e5e6e7);
+ c1 = interleave4_even(b0b1b2b3_f0f1f2f3, b4b5b6b7_f4f5f6f7);
+ c2 = interleave4_even(c0c1c2c3_g0g1g2g3, c4c5c6c7_g4g5g6g7);
+ c3 = interleave4_even(d0d1d2d3_h0h1h2h3, d4d5d6d7_h4h5h6h7);
+ c4 = interleave4_odd (a0a1a2a3_e0e1e2e3, a4a5a6a7_e4e5e6e7);
+ c5 = interleave4_odd (b0b1b2b3_f0f1f2f3, b4b5b6b7_f4f5f6f7);
+ c6 = interleave4_odd (c0c1c2c3_g0g1g2g3, c4c5c6c7_g4g5g6g7);
+ c7 = interleave4_odd (d0d1d2d3_h0h1h2h3, d4d5d6d7_h4h5h6h7);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3,
+ const vfloat8& r4, const vfloat8& r5, const vfloat8& r6, const vfloat8& r7,
+ const vfloat8& r8, const vfloat8& r9, const vfloat8& r10, const vfloat8& r11,
+ const vfloat8& r12, const vfloat8& r13, const vfloat8& r14, const vfloat8& r15,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3,
+ vfloat16& c4, vfloat16& c5, vfloat16& c6, vfloat16& c7)
+ {
+ return transpose(vfloat16(r0, r8), vfloat16(r1, r9), vfloat16(r2, r10), vfloat16(r3, r11),
+ vfloat16(r4, r12), vfloat16(r5, r13), vfloat16(r6, r14), vfloat16(r7, r15),
+ c0, c1, c2, c3, c4, c5, c6, c7);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 vreduce_add2(vfloat16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vfloat16 vreduce_add4(vfloat16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vfloat16 vreduce_add8(vfloat16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vfloat16 vreduce_add (vfloat16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline vfloat16 vreduce_min2(vfloat16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_min4(vfloat16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vfloat16 vreduce_min8(vfloat16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_min (vfloat16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vfloat16 vreduce_max2(vfloat16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_max4(vfloat16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vfloat16 vreduce_max8(vfloat16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_max (vfloat16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline float reduce_add(const vfloat16& v) { return toScalar(vreduce_add(v)); }
+ __forceinline float reduce_min(const vfloat16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat16& v) { return toScalar(vreduce_max(v)); }
+
+ __forceinline size_t select_min(const vfloat16& v) {
+ return bsf(_mm512_kmov(_mm512_cmp_epi32_mask(_mm512_castps_si512(v),_mm512_castps_si512(vreduce_min(v)),_MM_CMPINT_EQ)));
+ }
+
+ __forceinline size_t select_max(const vfloat16& v) {
+ return bsf(_mm512_kmov(_mm512_cmp_epi32_mask(_mm512_castps_si512(v),_mm512_castps_si512(vreduce_max(v)),_MM_CMPINT_EQ)));
+ }
+
+ __forceinline size_t select_min(const vboolf16& valid, const vfloat16& v)
+ {
+ const vfloat16 a = select(valid,v,vfloat16(pos_inf));
+ const vbool16 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+
+ __forceinline size_t select_max(const vboolf16& valid, const vfloat16& v)
+ {
+ const vfloat16 a = select(valid,v,vfloat16(neg_inf));
+ const vbool16 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+ __forceinline vfloat16 prefix_sum(const vfloat16& a)
+ {
+ const vfloat16 z(zero);
+ vfloat16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vfloat16 reverse_prefix_sum(const vfloat16& a)
+ {
+ const vfloat16 z(zero);
+ vfloat16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ __forceinline vfloat16 prefix_min(const vfloat16& a)
+ {
+ const vfloat16 z(pos_inf);
+ vfloat16 v = a;
+ v = min(v,align_shift_right<16-1>(v,z));
+ v = min(v,align_shift_right<16-2>(v,z));
+ v = min(v,align_shift_right<16-4>(v,z));
+ v = min(v,align_shift_right<16-8>(v,z));
+ return v;
+ }
+
+ __forceinline vfloat16 prefix_max(const vfloat16& a)
+ {
+ const vfloat16 z(neg_inf);
+ vfloat16 v = a;
+ v = max(v,align_shift_right<16-1>(v,z));
+ v = max(v,align_shift_right<16-2>(v,z));
+ v = max(v,align_shift_right<16-4>(v,z));
+ v = max(v,align_shift_right<16-8>(v,z));
+ return v;
+ }
+
+
+ __forceinline vfloat16 reverse_prefix_min(const vfloat16& a)
+ {
+ const vfloat16 z(pos_inf);
+ vfloat16 v = a;
+ v = min(v,align_shift_right<1>(z,v));
+ v = min(v,align_shift_right<2>(z,v));
+ v = min(v,align_shift_right<4>(z,v));
+ v = min(v,align_shift_right<8>(z,v));
+ return v;
+ }
+
+ __forceinline vfloat16 reverse_prefix_max(const vfloat16& a)
+ {
+ const vfloat16 z(neg_inf);
+ vfloat16 v = a;
+ v = max(v,align_shift_right<1>(z,v));
+ v = max(v,align_shift_right<2>(z,v));
+ v = max(v,align_shift_right<4>(z,v));
+ v = max(v,align_shift_right<8>(z,v));
+ return v;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 loadAOS4to16f(const float& x, const float& y, const float& z)
+ {
+ vfloat16 f = zero;
+ f = select(0x1111,vfloat16::broadcast(&x),f);
+ f = select(0x2222,vfloat16::broadcast(&y),f);
+ f = select(0x4444,vfloat16::broadcast(&z),f);
+ return f;
+ }
+
+ __forceinline vfloat16 loadAOS4to16f(unsigned int index,
+ const vfloat16& x,
+ const vfloat16& y,
+ const vfloat16& z)
+ {
+ vfloat16 f = zero;
+ f = select(0x1111,vfloat16::broadcast((float*)&x + index),f);
+ f = select(0x2222,vfloat16::broadcast((float*)&y + index),f);
+ f = select(0x4444,vfloat16::broadcast((float*)&z + index),f);
+ return f;
+ }
+
+ __forceinline vfloat16 loadAOS4to16f(unsigned int index,
+ const vfloat16& x,
+ const vfloat16& y,
+ const vfloat16& z,
+ const vfloat16& fill)
+ {
+ vfloat16 f = fill;
+ f = select(0x1111,vfloat16::broadcast((float*)&x + index),f);
+ f = select(0x2222,vfloat16::broadcast((float*)&y + index),f);
+ f = select(0x4444,vfloat16::broadcast((float*)&z + index),f);
+ return f;
+ }
+
+ __forceinline vfloat16 rcp_safe(const vfloat16& a) {
+ return rcp(select(a != vfloat16(zero), a, vfloat16(min_rcp_input)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vfloat4_sse2.h b/thirdparty/embree-aarch64/common/simd/vfloat4_sse2.h
new file mode 100644
index 0000000000..5732c0fbc8
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vfloat4_sse2.h
@@ -0,0 +1,925 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide SSE float type */
+ template<>
+ struct vfloat<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128 v; float f[4]; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat4& other) { v = other.v; }
+ __forceinline vfloat4& operator =(const vfloat4& other) { v = other.v; return *this; }
+
+ __forceinline vfloat(__m128 a) : v(a) {}
+ __forceinline operator const __m128&() const { return v; }
+ __forceinline operator __m128&() { return v; }
+
+ __forceinline vfloat(float a) : v(_mm_set1_ps(a)) {}
+ __forceinline vfloat(float a, float b, float c, float d) : v(_mm_set_ps(d, c, b, a)) {}
+
+ __forceinline explicit vfloat(const vint4& a) : v(_mm_cvtepi32_ps(a)) {}
+#if defined(__aarch64__)
+ __forceinline explicit vfloat(const vuint4& x) {
+ v = vcvtq_f32_u32(vreinterpretq_u32_s32(x.v));
+ }
+#else
+ __forceinline explicit vfloat(const vuint4& x) {
+ const __m128i a = _mm_and_si128(x,_mm_set1_epi32(0x7FFFFFFF));
+ const __m128i b = _mm_and_si128(_mm_srai_epi32(x,31),_mm_set1_epi32(0x4F000000)); //0x4F000000 = 2^31
+ const __m128 af = _mm_cvtepi32_ps(a);
+ const __m128 bf = _mm_castsi128_ps(b);
+ v = _mm_add_ps(af,bf);
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f)) {}
+ __forceinline vfloat(NaNTy) : v(_mm_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat4 load (const void* a) { return _mm_load_ps((float*)a); }
+ static __forceinline vfloat4 loadu(const void* a) { return _mm_loadu_ps((float*)a); }
+
+ static __forceinline void store (void* ptr, const vfloat4& v) { _mm_store_ps((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat4& v) { _mm_storeu_ps((float*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vfloat4 compact(const vboolf4& mask, vfloat4 &v) {
+ return _mm_mask_compress_ps(v, mask, v);
+ }
+ static __forceinline vfloat4 compact(const vboolf4& mask, vfloat4 &a, const vfloat4& b) {
+ return _mm_mask_compress_ps(a, mask, b);
+ }
+
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_ps (_mm_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_ps(_mm_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_mask_storeu_ps((float*)ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_maskload_ps((float*)ptr,mask); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_maskload_ps((float*)ptr,mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,v); }
+#else
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_and_ps(_mm_load_ps ((float*)ptr),mask); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_and_ps(_mm_loadu_ps((float*)ptr),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { store (ptr,select(mask,v,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { storeu(ptr,select(mask,v,loadu(ptr))); }
+#endif
+
+#if defined(__AVX__)
+ static __forceinline vfloat4 broadcast(const void* a) { return _mm_broadcast_ss((float*)a); }
+#else
+ static __forceinline vfloat4 broadcast(const void* a) { return _mm_set1_ps(*(float*)a); }
+#endif
+
+ static __forceinline vfloat4 load_nt (const float* ptr) {
+#if defined (__SSE4_1__)
+ return _mm_castsi128_ps(_mm_stream_load_si128((__m128i*)ptr));
+#else
+ return _mm_load_ps(ptr);
+#endif
+ }
+
+#if defined(__aarch64__)
+ static __forceinline vfloat4 load(const int8_t* ptr) {
+ return __m128(_mm_load4epi8_f32(((__m128i*)ptr)));
+ }
+#elif defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const int8_t* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const int8_t* ptr) {
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+#if defined(__aarch64__)
+ static __forceinline vfloat4 load(const uint8_t* ptr) {
+ return __m128(_mm_load4epu8_f32(((__m128i*)ptr)));
+ }
+#elif defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const uint8_t* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const uint8_t* ptr) {
+ //return _mm_cvtpu8_ps(*(__m64*)ptr); // don't enable, will use MMX instructions
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+#if defined(__aarch64__)
+ static __forceinline vfloat4 load(const short* ptr) {
+ return __m128(_mm_load4epi16_f32(((__m128i*)ptr)));
+ }
+#elif defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const short* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const short* ptr) {
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+ static __forceinline vfloat4 load(const unsigned short* ptr) {
+ return _mm_mul_ps(vfloat4(vint4::load(ptr)),vfloat4(1.0f/65535.0f));
+ }
+
+ static __forceinline void store_nt(void* ptr, const vfloat4& v)
+ {
+#if defined (__SSE4_1__)
+#if defined(__aarch64__)
+ _mm_stream_ps((float*)ptr,vreinterpretq_s32_f32(v.v));
+#else
+ _mm_stream_ps((float*)ptr,v);
+#endif
+#else
+ _mm_store_ps((float*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat4 gather(const float* ptr, const vint4& index) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_i32gather_ps(ptr, index, scale);
+#else
+ return vfloat4(
+ *(float*)(((int8_t*)ptr)+scale*index[0]),
+ *(float*)(((int8_t*)ptr)+scale*index[1]),
+ *(float*)(((int8_t*)ptr)+scale*index[2]),
+ *(float*)(((int8_t*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat4 gather(const vboolf4& mask, const float* ptr, const vint4& index) {
+ vfloat4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_ps(r, mask, index, ptr, scale);
+#elif defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_mask_i32gather_ps(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(float*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(float*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(float*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(float*)(((int8_t*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint4& index, const vfloat4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_i32scatter_ps((float*)ptr, index, v, scale);
+#else
+ *(float*)(((int8_t*)ptr)+scale*index[0]) = v[0];
+ *(float*)(((int8_t*)ptr)+scale*index[1]) = v[1];
+ *(float*)(((int8_t*)ptr)+scale*index[2]) = v[2];
+ *(float*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf4& mask, void* ptr, const vint4& index, const vfloat4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_mask_i32scatter_ps((float*)ptr ,mask, index, v, scale);
+#else
+ if (likely(mask[0])) *(float*)(((int8_t*)ptr)+scale*index[0]) = v[0];
+ if (likely(mask[1])) *(float*)(((int8_t*)ptr)+scale*index[1]) = v[1];
+ if (likely(mask[2])) *(float*)(((int8_t*)ptr)+scale*index[2]) = v[2];
+ if (likely(mask[3])) *(float*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ static __forceinline void store(const vboolf4& mask, int8_t* ptr, const vint4& ofs, const vfloat4& v) {
+ scatter<1>(mask,ptr,ofs,v);
+ }
+ static __forceinline void store(const vboolf4& mask, float* ptr, const vint4& ofs, const vfloat4& v) {
+ scatter<4>(mask,ptr,ofs,v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator [](size_t index) const { assert(index < 4); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < 4); return f[index]; }
+
+ friend __forceinline vfloat4 select(const vboolf4& m, const vfloat4& t, const vfloat4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_ps(m, f, t);
+#elif defined(__SSE4_1__) || (defined(__aarch64__))
+ return _mm_blendv_ps(f, t, m);
+#else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+#endif
+ }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 asFloat(const vint4& a) { return _mm_castsi128_ps(a); }
+ __forceinline vint4 asInt (const vfloat4& a) { return _mm_castps_si128(a); }
+ __forceinline vuint4 asUInt (const vfloat4& a) { return _mm_castps_si128(a); }
+
+ __forceinline vint4 toInt (const vfloat4& a) { return vint4(a); }
+ __forceinline vfloat4 toFloat(const vint4& a) { return vfloat4(a); }
+
+ __forceinline vfloat4 operator +(const vfloat4& a) { return a; }
+#if defined(__aarch64__)
+ __forceinline vfloat4 operator -(const vfloat4& a) {
+ return vnegq_f32(a);
+ }
+#else
+ __forceinline vfloat4 operator -(const vfloat4& a) { return _mm_xor_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
+#endif
+
+#if defined(__aarch64__)
+ __forceinline vfloat4 abs(const vfloat4& a) { return _mm_abs_ps(a); }
+#else
+ __forceinline vfloat4 abs(const vfloat4& a) { return _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))); }
+#endif
+
+#if defined(__AVX512VL__)
+ __forceinline vfloat4 sign(const vfloat4& a) { return _mm_mask_blend_ps(_mm_cmp_ps_mask(a, vfloat4(zero), _CMP_LT_OQ), vfloat4(one), -vfloat4(one)); }
+#else
+ __forceinline vfloat4 sign(const vfloat4& a) { return blendv_ps(vfloat4(one), -vfloat4(one), _mm_cmplt_ps(a, vfloat4(zero))); }
+#endif
+
+#if defined(__aarch64__)
+ __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a, vreinterpretq_f32_u32(v0x80000000)); }
+#else
+ __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a,_mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
+#endif
+
+ __forceinline vfloat4 rcp(const vfloat4& a)
+ {
+#if defined(__aarch64__)
+#if defined(BUILD_IOS)
+ return vfloat4(vdivq_f32(vdupq_n_f32(1.0f),a.v));
+#else //BUILD_IOS
+ __m128 reciprocal = _mm_rcp_ps(a);
+ reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
+ reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
+ // +1 round since NEON's reciprocal estimate instruction has less accuracy than SSE2's rcp.
+ reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
+ return (const vfloat4)reciprocal;
+#endif // BUILD_IOS
+#else
+
+#if defined(__AVX512VL__)
+ const vfloat4 r = _mm_rcp14_ps(a);
+#else
+ const vfloat4 r = _mm_rcp_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm_mul_ps(r,_mm_fnmadd_ps(r, a, vfloat4(2.0f)));
+#else
+ return _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
+#endif
+
+#endif //defined(__aarch64__)
+ }
+ __forceinline vfloat4 sqr (const vfloat4& a) { return _mm_mul_ps(a,a); }
+ __forceinline vfloat4 sqrt(const vfloat4& a) { return _mm_sqrt_ps(a); }
+
+ __forceinline vfloat4 rsqrt(const vfloat4& a)
+ {
+#if defined(__aarch64__)
+ vfloat4 r = _mm_rsqrt_ps(a);
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
+ r = vmulq_f32(r, vrsqrtsq_f32(vmulq_f32(a, r), r));
+ return r;
+#else
+
+#if defined(__AVX512VL__)
+ const vfloat4 r = _mm_rsqrt14_ps(a);
+#else
+ const vfloat4 r = _mm_rsqrt_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm_fmadd_ps(_mm_set1_ps(1.5f), r,
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#else
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r),
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#endif
+
+#endif
+ }
+
+ __forceinline vboolf4 isnan(const vfloat4& a) {
+#if defined(__aarch64__)
+ const vfloat4 b = _mm_and_ps(a, vreinterpretq_f32_u32(v0x7fffffff));
+#else
+ const vfloat4 b = _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
+#endif
+#if defined(__AVX512VL__)
+ return _mm_cmp_epi32_mask(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000), _MM_CMPINT_GT);
+#else
+ return _mm_castsi128_ps(_mm_cmpgt_epi32(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000)));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 operator +(const vfloat4& a, const vfloat4& b) { return _mm_add_ps(a, b); }
+ __forceinline vfloat4 operator +(const vfloat4& a, float b) { return a + vfloat4(b); }
+ __forceinline vfloat4 operator +(float a, const vfloat4& b) { return vfloat4(a) + b; }
+
+ __forceinline vfloat4 operator -(const vfloat4& a, const vfloat4& b) { return _mm_sub_ps(a, b); }
+ __forceinline vfloat4 operator -(const vfloat4& a, float b) { return a - vfloat4(b); }
+ __forceinline vfloat4 operator -(float a, const vfloat4& b) { return vfloat4(a) - b; }
+
+ __forceinline vfloat4 operator *(const vfloat4& a, const vfloat4& b) { return _mm_mul_ps(a, b); }
+ __forceinline vfloat4 operator *(const vfloat4& a, float b) { return a * vfloat4(b); }
+ __forceinline vfloat4 operator *(float a, const vfloat4& b) { return vfloat4(a) * b; }
+
+ __forceinline vfloat4 operator /(const vfloat4& a, const vfloat4& b) { return _mm_div_ps(a,b); }
+ __forceinline vfloat4 operator /(const vfloat4& a, float b) { return a/vfloat4(b); }
+ __forceinline vfloat4 operator /(float a, const vfloat4& b) { return vfloat4(a)/b; }
+
+ __forceinline vfloat4 operator &(const vfloat4& a, const vfloat4& b) { return _mm_and_ps(a,b); }
+ __forceinline vfloat4 operator |(const vfloat4& a, const vfloat4& b) { return _mm_or_ps(a,b); }
+ __forceinline vfloat4 operator ^(const vfloat4& a, const vfloat4& b) { return _mm_xor_ps(a,b); }
+ __forceinline vfloat4 operator ^(const vfloat4& a, const vint4& b) { return _mm_xor_ps(a,_mm_castsi128_ps(b)); }
+
+ __forceinline vfloat4 min(const vfloat4& a, const vfloat4& b) { return _mm_min_ps(a,b); }
+ __forceinline vfloat4 min(const vfloat4& a, float b) { return _mm_min_ps(a,vfloat4(b)); }
+ __forceinline vfloat4 min(float a, const vfloat4& b) { return _mm_min_ps(vfloat4(a),b); }
+
+ __forceinline vfloat4 max(const vfloat4& a, const vfloat4& b) { return _mm_max_ps(a,b); }
+ __forceinline vfloat4 max(const vfloat4& a, float b) { return _mm_max_ps(a,vfloat4(b)); }
+ __forceinline vfloat4 max(float a, const vfloat4& b) { return _mm_max_ps(vfloat4(a),b); }
+
+#if defined(__SSE4_1__) || defined(__aarch64__)
+
+ __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 maxi(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 minui(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epu32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 maxui(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epu32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#else
+ __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
+ return min(a,b);
+ }
+
+ __forceinline vfloat4 maxi(const vfloat4& a, const vfloat4& b) {
+ return max(a,b);
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmadd_ps(a,b,c); }
+ __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmsub_ps(a,b,c); }
+ __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmadd_ps(a,b,c); }
+ __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmsub_ps(a,b,c); }
+#else
+
+#if defined(__aarch64__)
+ __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) {
+ return _mm_madd_ps(a, b, c); //a*b+c;
+ }
+ __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) {
+ return _mm_msub_ps(a, b, c); //-a*b+c;
+ }
+ __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) {
+ return vnegq_f32(vfmaq_f32(c,a, b));
+ }
+#else
+ __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b+c; }
+ __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b+c;}
+ __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b-c; }
+#endif
+ __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b-c; }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4& operator +=(vfloat4& a, const vfloat4& b) { return a = a + b; }
+ __forceinline vfloat4& operator +=(vfloat4& a, float b) { return a = a + b; }
+
+ __forceinline vfloat4& operator -=(vfloat4& a, const vfloat4& b) { return a = a - b; }
+ __forceinline vfloat4& operator -=(vfloat4& a, float b) { return a = a - b; }
+
+ __forceinline vfloat4& operator *=(vfloat4& a, const vfloat4& b) { return a = a * b; }
+ __forceinline vfloat4& operator *=(vfloat4& a, float b) { return a = a * b; }
+
+ __forceinline vfloat4& operator /=(vfloat4& a, const vfloat4& b) { return a = a / b; }
+ __forceinline vfloat4& operator /=(vfloat4& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmpeq_ps (a, b); }
+ __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmpneq_ps(a, b); }
+ __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmplt_ps (a, b); }
+#if defined(__aarch64__)
+ __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpge_ps (a, b); }
+ __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpgt_ps (a, b); }
+#else
+ __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpnlt_ps(a, b); }
+ __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpnle_ps(a, b); }
+#endif
+ __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmple_ps (a, b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vfloat4& a, float b) { return a == vfloat4(b); }
+ __forceinline vboolf4 operator ==(float a, const vfloat4& b) { return vfloat4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vfloat4& a, float b) { return a != vfloat4(b); }
+ __forceinline vboolf4 operator !=(float a, const vfloat4& b) { return vfloat4(a) != b; }
+
+ __forceinline vboolf4 operator < (const vfloat4& a, float b) { return a < vfloat4(b); }
+ __forceinline vboolf4 operator < (float a, const vfloat4& b) { return vfloat4(a) < b; }
+
+ __forceinline vboolf4 operator >=(const vfloat4& a, float b) { return a >= vfloat4(b); }
+ __forceinline vboolf4 operator >=(float a, const vfloat4& b) { return vfloat4(a) >= b; }
+
+ __forceinline vboolf4 operator > (const vfloat4& a, float b) { return a > vfloat4(b); }
+ __forceinline vboolf4 operator > (float a, const vfloat4& b) { return vfloat4(a) > b; }
+
+ __forceinline vboolf4 operator <=(const vfloat4& a, float b) { return a <= vfloat4(b); }
+ __forceinline vboolf4 operator <=(float a, const vfloat4& b) { return vfloat4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vfloat4& a, const vfloat4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vfloat4& a, const vfloat4& b) { return a != b; }
+ __forceinline vboolf4 lt(const vfloat4& a, const vfloat4& b) { return a < b; }
+ __forceinline vboolf4 ge(const vfloat4& a, const vfloat4& b) { return a >= b; }
+ __forceinline vboolf4 gt(const vfloat4& a, const vfloat4& b) { return a > b; }
+ __forceinline vboolf4 le(const vfloat4& a, const vfloat4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a != b); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a < b); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a >= b); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a > b); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vfloat4 select(const vfloat4& t, const vfloat4& f)
+ {
+#if defined(__SSE4_1__)
+ return _mm_blend_ps(f, t, mask);
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+#if defined(__aarch64__)
+ template<> __forceinline vfloat4 select<0>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vzero));
+ }
+ template<> __forceinline vfloat4 select<1>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v000F));
+ }
+ template<> __forceinline vfloat4 select<2>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v00F0));
+ }
+ template<> __forceinline vfloat4 select<3>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v00FF));
+ }
+ template<> __forceinline vfloat4 select<4>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0F00));
+ }
+ template<> __forceinline vfloat4 select<5>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0F0F));
+ }
+ template<> __forceinline vfloat4 select<6>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0FF0));
+ }
+ template<> __forceinline vfloat4 select<7>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(v0FFF));
+ }
+ template<> __forceinline vfloat4 select<8>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF000));
+ }
+ template<> __forceinline vfloat4 select<9>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF00F));
+ }
+ template<> __forceinline vfloat4 select<10>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF0F0));
+ }
+ template<> __forceinline vfloat4 select<11>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vF0FF));
+ }
+ template<> __forceinline vfloat4 select<12>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFF00));
+ }
+ template<> __forceinline vfloat4 select<13>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFF0F));
+ }
+ template<> __forceinline vfloat4 select<14>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFFF0));
+ }
+ template<> __forceinline vfloat4 select<15>(const vfloat4& t, const vfloat4& f) {
+ return _mm_blendv_ps(f, t, vreinterpretq_f32_u32(vFFFF));
+ }
+#endif
+
+ __forceinline vfloat4 lerp(const vfloat4& a, const vfloat4& b, const vfloat4& t) {
+ return madd(t,b-a,a);
+ }
+
+ __forceinline bool isvalid(const vfloat4& v) {
+ return all((v > vfloat4(-FLT_LARGE)) & (v < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite(const vfloat4& a) {
+ return all((a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
+ }
+
+ __forceinline bool is_finite(const vboolf4& valid, const vfloat4& a) {
+ return all(valid, (a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+ __forceinline vfloat4 floor(const vfloat4& a) { return vrndmq_f32(a.v); } // towards -inf
+ __forceinline vfloat4 ceil (const vfloat4& a) { return vrndpq_f32(a.v); } // toward +inf
+ __forceinline vfloat4 trunc(const vfloat4& a) { return vrndq_f32(a.v); } // towards 0
+ __forceinline vfloat4 round(const vfloat4& a) { return vrndnq_f32(a.v); } // to nearest, ties to even. NOTE(LTE): arm clang uses vrndnq, old gcc uses vrndqn?
+#elif defined (__SSE4_1__)
+ __forceinline vfloat4 floor(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline vfloat4 ceil (const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+ __forceinline vfloat4 trunc(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_ZERO ); }
+ __forceinline vfloat4 round(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); } // (even) https://www.felixcloutier.com/x86/roundpd
+#else
+ __forceinline vfloat4 floor(const vfloat4& a) { return vfloat4(floorf(a[0]),floorf(a[1]),floorf(a[2]),floorf(a[3])); }
+ __forceinline vfloat4 ceil (const vfloat4& a) { return vfloat4(ceilf (a[0]),ceilf (a[1]),ceilf (a[2]),ceilf (a[3])); }
+ __forceinline vfloat4 trunc(const vfloat4& a) { return vfloat4(truncf(a[0]),truncf(a[1]),truncf(a[2]),truncf(a[3])); }
+ __forceinline vfloat4 round(const vfloat4& a) { return vfloat4(roundf(a[0]),roundf(a[1]),roundf(a[2]),roundf(a[3])); }
+#endif
+ __forceinline vfloat4 frac(const vfloat4& a) { return a-floor(a); }
+
+ __forceinline vint4 floori(const vfloat4& a) {
+#if defined(__aarch64__)
+ return vcvtq_s32_f32(floor(a));
+#elif defined(__SSE4_1__)
+ return vint4(floor(a));
+#else
+ return vint4(a-vfloat4(0.5f));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 unpacklo(const vfloat4& a, const vfloat4& b) { return _mm_unpacklo_ps(a, b); }
+ __forceinline vfloat4 unpackhi(const vfloat4& a, const vfloat4& b) { return _mm_unpackhi_ps(a, b); }
+
+#if defined(__aarch64__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& v) {
+ return vreinterpretq_f32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
+ }
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
+ return vreinterpretq_f32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
+ }
+#else
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& v) {
+ return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+#endif
+
+#if defined (__SSSE3__)
+ __forceinline vfloat4 shuffle8(const vfloat4& a, const vint4& shuf) {
+ return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf));
+ }
+#endif
+
+#if defined(__aarch64__)
+ template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v0022 )); }
+ template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v1133)); }
+ template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return __m128(vqtbl1q_u8( uint8x16_t(v.v), v0101)); }
+#elif defined(__SSE3__)
+ template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return _mm_moveldup_ps(v); }
+ template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return _mm_movehdup_ps(v); }
+ template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return _mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vfloat4 shuffle(const vfloat4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+#if defined(__aarch64__)
+ template<int i> __forceinline float extract(const vfloat4& a);
+ template<> __forceinline float extract<0>(const vfloat4& b) {
+ return b[0];
+ }
+ template<> __forceinline float extract<1>(const vfloat4& b) {
+ return b[1];
+ }
+ template<> __forceinline float extract<2>(const vfloat4& b) {
+ return b[2];
+ }
+ template<> __forceinline float extract<3>(const vfloat4& b) {
+ return b[3];
+ }
+#elif defined (__SSE4_1__) && !defined(__GNUC__)
+ template<int i> __forceinline float extract(const vfloat4& a) { return _mm_cvtss_f32(_mm_extract_ps(a,i)); }
+ template<> __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
+#else
+ template<int i> __forceinline float extract(const vfloat4& a) { return _mm_cvtss_f32(shuffle<i,i,i,i>(a)); }
+ template<> __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
+#endif
+
+
+#if defined(__aarch64__)
+ template<int dst> __forceinline vfloat4 insert(const vfloat4& a, float b);
+ template<> __forceinline vfloat4 insert<0>(const vfloat4& a, float b)
+ {
+ vfloat4 c = a;
+ c[0] = b;
+ return c;
+ }
+ template<> __forceinline vfloat4 insert<1>(const vfloat4& a, float b)
+ {
+ vfloat4 c = a;
+ c[1] = b;
+ return c;
+ }
+ template<> __forceinline vfloat4 insert<2>(const vfloat4& a, float b)
+ {
+ vfloat4 c = a;
+ c[2] = b;
+ return c;
+ }
+ template<> __forceinline vfloat4 insert<3>(const vfloat4& a, float b)
+ {
+ vfloat4 c = a;
+ c[3] = b;
+ return c;
+ }
+#elif defined (__SSE4_1__)
+ template<int dst, int src, int clr> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
+ template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return insert<dst, src, 0>(a, b); }
+ template<int dst> __forceinline vfloat4 insert(const vfloat4& a, const float b) { return insert<dst, 0>(a, _mm_set_ss(b)); }
+#else
+ template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { vfloat4 c = a; c[dst&3] = b[src&3]; return c; }
+ template<int dst> __forceinline vfloat4 insert(const vfloat4& a, float b) { vfloat4 c = a; c[dst&3] = b; return c; }
+#endif
+
+#if defined(__aarch64__)
+ __forceinline float toScalar(const vfloat4& v) {
+ return v[0];
+ }
+#else
+ __forceinline float toScalar(const vfloat4& v) { return _mm_cvtss_f32(v); }
+#endif
+ __forceinline vfloat4 broadcast4f(const vfloat4& a, size_t k) {
+ return vfloat4::broadcast(&a[k]);
+ }
+
+ __forceinline vfloat4 shift_right_1(const vfloat4& x) {
+ return _mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(x), 4));
+ }
+
+#if defined (__AVX2__)
+ __forceinline vfloat4 permute(const vfloat4 &a, const __m128i &index) {
+ return _mm_permutevar_ps(a,index);
+ }
+
+ __forceinline vfloat4 broadcast1f(const void* a) { return _mm_broadcast_ss((float*)a); }
+
+#endif
+
+#if defined(__AVX512VL__)
+ template<int i>
+ __forceinline vfloat4 align_shift_right(const vfloat4& a, const vfloat4& b) {
+ return _mm_castsi128_ps(_mm_alignr_epi32(_mm_castps_si128(a), _mm_castps_si128(b), i));
+ }
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting Network
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 sort_ascending(const vfloat4& v)
+ {
+ const vfloat4 a0 = v;
+ const vfloat4 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat4 c0 = min(a0,b0);
+ const vfloat4 d0 = max(a0,b0);
+ const vfloat4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vfloat4 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat4 c1 = min(a1,b1);
+ const vfloat4 d1 = max(a1,b1);
+ const vfloat4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vfloat4 b2 = shuffle<0,2,1,3>(a2);
+ const vfloat4 c2 = min(a2,b2);
+ const vfloat4 d2 = max(a2,b2);
+ const vfloat4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ __forceinline vfloat4 sort_descending(const vfloat4& v)
+ {
+ const vfloat4 a0 = v;
+ const vfloat4 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat4 c0 = max(a0,b0);
+ const vfloat4 d0 = min(a0,b0);
+ const vfloat4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vfloat4 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat4 c1 = max(a1,b1);
+ const vfloat4 d1 = min(a1,b1);
+ const vfloat4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vfloat4 b2 = shuffle<0,2,1,3>(a2);
+ const vfloat4 c2 = max(a2,b2);
+ const vfloat4 d2 = min(a2,b2);
+ const vfloat4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, vfloat4& c0, vfloat4& c1, vfloat4& c2, vfloat4& c3)
+ {
+ vfloat4 l02 = unpacklo(r0,r2);
+ vfloat4 h02 = unpackhi(r0,r2);
+ vfloat4 l13 = unpacklo(r1,r3);
+ vfloat4 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ c3 = unpackhi(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, vfloat4& c0, vfloat4& c1, vfloat4& c2)
+ {
+ vfloat4 l02 = unpacklo(r0,r2);
+ vfloat4 h02 = unpackhi(r0,r2);
+ vfloat4 l13 = unpacklo(r1,r3);
+ vfloat4 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+#if defined(__aarch64__)
+ __forceinline vfloat4 vreduce_min(const vfloat4& v) { float h = vminvq_f32(v); return vdupq_n_f32(h); }
+ __forceinline vfloat4 vreduce_max(const vfloat4& v) { float h = vmaxvq_f32(v); return vdupq_n_f32(h); }
+ __forceinline vfloat4 vreduce_add(const vfloat4& v) { float h = vaddvq_f32(v); return vdupq_n_f32(h); }
+#else
+ __forceinline vfloat4 vreduce_min(const vfloat4& v) { vfloat4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vfloat4 vreduce_max(const vfloat4& v) { vfloat4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vfloat4 vreduce_add(const vfloat4& v) { vfloat4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+#endif
+
+#if defined(__aarch64__)
+ __forceinline float reduce_min(const vfloat4& v) { return vminvq_f32(v); }
+ __forceinline float reduce_max(const vfloat4& v) { return vmaxvq_f32(v); }
+ __forceinline float reduce_add(const vfloat4& v) { return vaddvq_f32(v); }
+#else
+ __forceinline float reduce_min(const vfloat4& v) { return _mm_cvtss_f32(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat4& v) { return _mm_cvtss_f32(vreduce_max(v)); }
+ __forceinline float reduce_add(const vfloat4& v) { return _mm_cvtss_f32(vreduce_add(v)); }
+#endif
+
+ __forceinline size_t select_min(const vboolf4& valid, const vfloat4& v)
+ {
+ const vfloat4 a = select(valid,v,vfloat4(pos_inf));
+ const vbool4 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+ __forceinline size_t select_max(const vboolf4& valid, const vfloat4& v)
+ {
+ const vfloat4 a = select(valid,v,vfloat4(neg_inf));
+ const vbool4 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float dot(const vfloat4& a, const vfloat4& b) {
+ return reduce_add(a*b);
+ }
+
+ __forceinline vfloat4 cross(const vfloat4& a, const vfloat4& b)
+ {
+ const vfloat4 a0 = a;
+ const vfloat4 b0 = shuffle<1,2,0,3>(b);
+ const vfloat4 a1 = shuffle<1,2,0,3>(a);
+ const vfloat4 b1 = b;
+ return shuffle<1,2,0,3>(prod_diff(a0,b0,a1,b1));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vfloat8_avx.h b/thirdparty/embree-aarch64/common/simd/vfloat8_avx.h
new file mode 100644
index 0000000000..3c7e4a8cdc
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vfloat8_avx.h
@@ -0,0 +1,847 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX float type */
+ template<>
+ struct vfloat<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { __m256 v; float f[8]; int i[8]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat8& other) { v = other.v; }
+ __forceinline vfloat8& operator =(const vfloat8& other) { v = other.v; return *this; }
+
+ __forceinline vfloat(__m256 a) : v(a) {}
+ __forceinline operator const __m256&() const { return v; }
+ __forceinline operator __m256&() { return v; }
+
+ __forceinline explicit vfloat(const vfloat4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
+ __forceinline vfloat(const vfloat4& a, const vfloat4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
+
+ __forceinline explicit vfloat(const int8_t* a) : v(_mm256_loadu_ps((const float*)a)) {}
+ __forceinline vfloat(float a) : v(_mm256_set1_ps(a)) {}
+ __forceinline vfloat(float a, float b) : v(_mm256_set_ps(b, a, b, a, b, a, b, a)) {}
+ __forceinline vfloat(float a, float b, float c, float d) : v(_mm256_set_ps(d, c, b, a, d, c, b, a)) {}
+ __forceinline vfloat(float a, float b, float c, float d, float e, float f, float g, float h) : v(_mm256_set_ps(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vfloat(__m256i a) : v(_mm256_cvtepi32_ps(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm256_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm256_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm256_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm256_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f)) {}
+ __forceinline vfloat(NaNTy) : v(_mm256_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm256_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat8 broadcast(const void* a) {
+ return _mm256_broadcast_ss((float*)a);
+ }
+
+ static __forceinline vfloat8 broadcast2(const float* a, const float* b) {
+#if defined(__INTEL_COMPILER)
+ const vfloat8 v0 = _mm256_broadcast_ss(a);
+ const vfloat8 v1 = _mm256_broadcast_ss(b);
+ return _mm256_blend_ps(v1, v0, 0xf);
+#else
+ return _mm256_set_ps(*b,*b,*b,*b,*a,*a,*a,*a);
+#endif
+ }
+
+ static __forceinline vfloat8 broadcast4f(const vfloat4* ptr) {
+ return _mm256_broadcast_ps((__m128*)ptr);
+ }
+
+ static __forceinline vfloat8 load(const int8_t* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load(const uint8_t* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load(const short* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load (const void* ptr) { return _mm256_load_ps((float*)ptr); }
+ static __forceinline vfloat8 loadu(const void* ptr) { return _mm256_loadu_ps((float*)ptr); }
+
+ static __forceinline void store (void* ptr, const vfloat8& v) { return _mm256_store_ps((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat8& v) { return _mm256_storeu_ps((float*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vfloat8 compact(const vboolf8& mask, vfloat8 &v) {
+ return _mm256_mask_compress_ps(v, mask, v);
+ }
+ static __forceinline vfloat8 compact(const vboolf8& mask, vfloat8 &a, const vfloat8& b) {
+ return _mm256_mask_compress_ps(a, mask, b);
+ }
+
+ static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_ps (_mm256_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_ps(_mm256_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_storeu_ps((float*)ptr,mask,v); }
+#elif defined(__aarch64__)
+ static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask.v); }
+ static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask.v); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,v); }
+#else
+ static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
+ static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,v); }
+#endif
+
+#if defined(__AVX2__)
+ static __forceinline vfloat8 load_nt(void* ptr) {
+ return _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)ptr));
+ }
+#endif
+
+ static __forceinline void store_nt(void* ptr, const vfloat8& v) {
+ _mm256_stream_ps((float*)ptr,v);
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat8 gather(const float* ptr, const vint8& index) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _mm256_i32gather_ps(ptr, index ,scale);
+#else
+ return vfloat8(
+ *(float*)(((int8_t*)ptr)+scale*index[0]),
+ *(float*)(((int8_t*)ptr)+scale*index[1]),
+ *(float*)(((int8_t*)ptr)+scale*index[2]),
+ *(float*)(((int8_t*)ptr)+scale*index[3]),
+ *(float*)(((int8_t*)ptr)+scale*index[4]),
+ *(float*)(((int8_t*)ptr)+scale*index[5]),
+ *(float*)(((int8_t*)ptr)+scale*index[6]),
+ *(float*)(((int8_t*)ptr)+scale*index[7]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat8 gather(const vboolf8& mask, const float* ptr, const vint8& index) {
+ vfloat8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_ps(r, mask, index, ptr, scale);
+#elif defined(__AVX2__) && !defined(__aarch64__)
+ return _mm256_mask_i32gather_ps(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(float*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(float*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(float*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(float*)(((int8_t*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(float*)(((int8_t*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(float*)(((int8_t*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(float*)(((int8_t*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(float*)(((int8_t*)ptr)+scale*index[7]);
+ return r;
+ #endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vfloat8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_ps((float*)ptr, ofs, v, scale);
+#else
+ *(float*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ *(float*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ *(float*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ *(float*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ *(float*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ *(float*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ *(float*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ *(float*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vfloat8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_ps((float*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(float*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(float*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(float*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(float*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(float*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(float*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(float*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(float*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ static __forceinline void store(const vboolf8& mask, int8_t* ptr, const vint8& ofs, const vfloat8& v) {
+ scatter<1>(mask,ptr,ofs,v);
+ }
+ static __forceinline void store(const vboolf8& mask, float* ptr, const vint8& ofs, const vfloat8& v) {
+ scatter<4>(mask,ptr,ofs,v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator [](size_t index) const { assert(index < 8); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < 8); return f[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 asFloat(const vint8& a) { return _mm256_castsi256_ps(a); }
+ __forceinline vint8 asInt (const vfloat8& a) { return _mm256_castps_si256(a); }
+
+ __forceinline vint8 toInt (const vfloat8& a) { return vint8(a); }
+ __forceinline vfloat8 toFloat(const vint8& a) { return vfloat8(a); }
+
+ __forceinline vfloat8 operator +(const vfloat8& a) { return a; }
+#if !defined(__aarch64__)
+ __forceinline vfloat8 operator -(const vfloat8& a) {
+ const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000));
+ return _mm256_xor_ps(a, mask);
+ }
+#else
+ __forceinline vfloat8 operator -(const vfloat8& a) {
+ __m256 res;
+ res.lo = vnegq_f32(a.v.lo);
+ res.hi = vnegq_f32(a.v.hi);
+ return res;
+}
+#endif
+
+#if !defined(__aarch64__)
+__forceinline vfloat8 abs(const vfloat8& a) {
+ const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff));
+ return _mm256_and_ps(a, mask);
+}
+#else
+__forceinline vfloat8 abs(const vfloat8& a) {
+ __m256 res;
+ res.lo = vabsq_f32(a.v.lo);
+ res.hi = vabsq_f32(a.v.hi);
+ return res;
+}
+#endif
+
+#if !defined(__aarch64__)
+ __forceinline vfloat8 sign (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmp_ps(a, vfloat8(zero), _CMP_NGE_UQ)); }
+#else
+ __forceinline vfloat8 sign (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmplt_ps(a, vfloat8(zero))); }
+#endif
+ __forceinline vfloat8 signmsk(const vfloat8& a) { return _mm256_and_ps(a,_mm256_castsi256_ps(_mm256_set1_epi32(0x80000000))); }
+
+
+ static __forceinline vfloat8 rcp(const vfloat8& a)
+ {
+#if defined(BUILD_IOS) && defined(__aarch64__)
+ // ios devices are faster doing full divide, no need for NR fixup
+ vfloat8 ret;
+ const float32x4_t one = vdupq_n_f32(1.0f);
+ ret.v.lo = vdivq_f32(one, a.v.lo);
+ ret.v.hi = vdivq_f32(one, a.v.hi);
+ return ret;
+#endif
+
+#if defined(__AVX512VL__)
+ const vfloat8 r = _mm256_rcp14_ps(a);
+#else
+ const vfloat8 r = _mm256_rcp_ps(a);
+#endif
+
+#if defined(__AVX2__) //&& !defined(aarch64)
+ return _mm256_mul_ps(r, _mm256_fnmadd_ps(r, a, vfloat8(2.0f)));
+#else
+ return _mm256_mul_ps(r, _mm256_sub_ps(vfloat8(2.0f), _mm256_mul_ps(r, a)));
+#endif
+ }
+ __forceinline vfloat8 sqr (const vfloat8& a) { return _mm256_mul_ps(a,a); }
+ __forceinline vfloat8 sqrt(const vfloat8& a) { return _mm256_sqrt_ps(a); }
+
+ static __forceinline vfloat8 rsqrt(const vfloat8& a)
+ {
+#if defined(__AVX512VL__)
+ const vfloat8 r = _mm256_rsqrt14_ps(a);
+#else
+ const vfloat8 r = _mm256_rsqrt_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm256_fmadd_ps(_mm256_set1_ps(1.5f), r,
+ _mm256_mul_ps(_mm256_mul_ps(_mm256_mul_ps(a, _mm256_set1_ps(-0.5f)), r), _mm256_mul_ps(r, r)));
+#else
+ return _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(1.5f), r),
+ _mm256_mul_ps(_mm256_mul_ps(_mm256_mul_ps(a, _mm256_set1_ps(-0.5f)), r), _mm256_mul_ps(r, r)));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 operator +(const vfloat8& a, const vfloat8& b) { return _mm256_add_ps(a, b); }
+ __forceinline vfloat8 operator +(const vfloat8& a, float b) { return a + vfloat8(b); }
+ __forceinline vfloat8 operator +(float a, const vfloat8& b) { return vfloat8(a) + b; }
+
+ __forceinline vfloat8 operator -(const vfloat8& a, const vfloat8& b) { return _mm256_sub_ps(a, b); }
+ __forceinline vfloat8 operator -(const vfloat8& a, float b) { return a - vfloat8(b); }
+ __forceinline vfloat8 operator -(float a, const vfloat8& b) { return vfloat8(a) - b; }
+
+ __forceinline vfloat8 operator *(const vfloat8& a, const vfloat8& b) { return _mm256_mul_ps(a, b); }
+ __forceinline vfloat8 operator *(const vfloat8& a, float b) { return a * vfloat8(b); }
+ __forceinline vfloat8 operator *(float a, const vfloat8& b) { return vfloat8(a) * b; }
+
+ __forceinline vfloat8 operator /(const vfloat8& a, const vfloat8& b) { return _mm256_div_ps(a, b); }
+ __forceinline vfloat8 operator /(const vfloat8& a, float b) { return a / vfloat8(b); }
+ __forceinline vfloat8 operator /(float a, const vfloat8& b) { return vfloat8(a) / b; }
+
+ __forceinline vfloat8 operator &(const vfloat8& a, const vfloat8& b) { return _mm256_and_ps(a,b); }
+ __forceinline vfloat8 operator |(const vfloat8& a, const vfloat8& b) { return _mm256_or_ps(a,b); }
+ __forceinline vfloat8 operator ^(const vfloat8& a, const vfloat8& b) { return _mm256_xor_ps(a,b); }
+ __forceinline vfloat8 operator ^(const vfloat8& a, const vint8& b) { return _mm256_xor_ps(a,_mm256_castsi256_ps(b)); }
+
+ __forceinline vfloat8 min(const vfloat8& a, const vfloat8& b) { return _mm256_min_ps(a, b); }
+ __forceinline vfloat8 min(const vfloat8& a, float b) { return _mm256_min_ps(a, vfloat8(b)); }
+ __forceinline vfloat8 min(float a, const vfloat8& b) { return _mm256_min_ps(vfloat8(a), b); }
+
+ __forceinline vfloat8 max(const vfloat8& a, const vfloat8& b) { return _mm256_max_ps(a, b); }
+ __forceinline vfloat8 max(const vfloat8& a, float b) { return _mm256_max_ps(a, vfloat8(b)); }
+ __forceinline vfloat8 max(float a, const vfloat8& b) { return _mm256_max_ps(vfloat8(a), b); }
+
+ /* need "static __forceinline for MSVC, otherwise we'll link the wrong version in debug mode */
+#if defined(__AVX2__)
+
+ static __forceinline vfloat8 mini(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_min_epi32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 maxi(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_max_epi32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 minui(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_min_epu32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 maxui(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_max_epu32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+#else
+
+ static __forceinline vfloat8 mini(const vfloat8& a, const vfloat8& b) {
+ return asFloat(min(asInt(a),asInt(b)));
+ }
+
+ static __forceinline vfloat8 maxi(const vfloat8& a, const vfloat8& b) {
+ return asFloat(max(asInt(a),asInt(b)));
+ }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ static __forceinline vfloat8 madd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fmadd_ps(a,b,c); }
+ static __forceinline vfloat8 msub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fmsub_ps(a,b,c); }
+ static __forceinline vfloat8 nmadd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fnmadd_ps(a,b,c); }
+ static __forceinline vfloat8 nmsub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fnmsub_ps(a,b,c); }
+#else
+ static __forceinline vfloat8 madd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return a*b+c; }
+ static __forceinline vfloat8 msub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return a*b-c; }
+ static __forceinline vfloat8 nmadd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return -a*b+c;}
+ static __forceinline vfloat8 nmsub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return -a*b-c; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8& operator +=(vfloat8& a, const vfloat8& b) { return a = a + b; }
+ __forceinline vfloat8& operator +=(vfloat8& a, float b) { return a = a + b; }
+
+ __forceinline vfloat8& operator -=(vfloat8& a, const vfloat8& b) { return a = a - b; }
+ __forceinline vfloat8& operator -=(vfloat8& a, float b) { return a = a - b; }
+
+ __forceinline vfloat8& operator *=(vfloat8& a, const vfloat8& b) { return a = a * b; }
+ __forceinline vfloat8& operator *=(vfloat8& a, float b) { return a = a * b; }
+
+ __forceinline vfloat8& operator /=(vfloat8& a, const vfloat8& b) { return a = a / b; }
+ __forceinline vfloat8& operator /=(vfloat8& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_LE); }
+
+ static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+ return _mm256_mask_blend_ps(m, f, t);
+ }
+#elif !defined(__aarch64__)
+ __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_EQ_OQ); }
+ __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NEQ_UQ); }
+ __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS); }
+ __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
+ __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
+ __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LE_OS); }
+
+ __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+ return _mm256_blendv_ps(f, t, m);
+ }
+#else
+ __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmpeq_ps(a, b); }
+ __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmpneq_ps(a, b); }
+ __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmplt_ps(a, b); }
+ __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmpge_ps(a, b); }
+ __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmpgt_ps(a, b); }
+ __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmple_ps(a, b); }
+
+ __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+ return _mm256_blendv_ps(f, t, m);
+ }
+
+#endif
+
+ template<int mask>
+ __forceinline vfloat8 select(const vfloat8& t, const vfloat8& f) {
+ return _mm256_blend_ps(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vfloat8& a, const float& b) { return a == vfloat8(b); }
+ __forceinline vboolf8 operator ==(const float& a, const vfloat8& b) { return vfloat8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vfloat8& a, const float& b) { return a != vfloat8(b); }
+ __forceinline vboolf8 operator !=(const float& a, const vfloat8& b) { return vfloat8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vfloat8& a, const float& b) { return a < vfloat8(b); }
+ __forceinline vboolf8 operator < (const float& a, const vfloat8& b) { return vfloat8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vfloat8& a, const float& b) { return a >= vfloat8(b); }
+ __forceinline vboolf8 operator >=(const float& a, const vfloat8& b) { return vfloat8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vfloat8& a, const float& b) { return a > vfloat8(b); }
+ __forceinline vboolf8 operator > (const float& a, const vfloat8& b) { return vfloat8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vfloat8& a, const float& b) { return a <= vfloat8(b); }
+ __forceinline vboolf8 operator <=(const float& a, const vfloat8& b) { return vfloat8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vfloat8& a, const vfloat8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vfloat8& a, const vfloat8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vfloat8& a, const vfloat8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vfloat8& a, const vfloat8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vfloat8& a, const vfloat8& b) { return a > b; }
+ __forceinline vboolf8 le(const vfloat8& a, const vfloat8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a == b); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a != b); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a < b); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a >= b); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a > b); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a <= b); }
+#endif
+
+ __forceinline vfloat8 lerp(const vfloat8& a, const vfloat8& b, const vfloat8& t) {
+ return madd(t,b-a,a);
+ }
+
+ __forceinline bool isvalid (const vfloat8& v) {
+ return all((v > vfloat8(-FLT_LARGE)) & (v < vfloat8(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite (const vfloat8& a) {
+ return all((a >= vfloat8(-FLT_MAX)) & (a <= vfloat8(+FLT_MAX)));
+ }
+
+ __forceinline bool is_finite (const vboolf8& valid, const vfloat8& a) {
+ return all(valid, (a >= vfloat8(-FLT_MAX)) & (a <= vfloat8(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(__aarch64__)
+ __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+ __forceinline vfloat8 trunc(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_ZERO ); }
+ __forceinline vfloat8 round(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
+#else
+ __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_floor_ps(a); }
+ __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_ceil_ps(a); }
+#endif
+
+
+ __forceinline vfloat8 frac (const vfloat8& a) { return a-floor(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 unpacklo(const vfloat8& a, const vfloat8& b) { return _mm256_unpacklo_ps(a, b); }
+ __forceinline vfloat8 unpackhi(const vfloat8& a, const vfloat8& b) { return _mm256_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vfloat8 shuffle(const vfloat8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1>
+ __forceinline vfloat8 shuffle4(const vfloat8& v) {
+ return _mm256_permute2f128_ps(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vfloat8 shuffle4(const vfloat8& a, const vfloat8& b) {
+ return _mm256_permute2f128_ps(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat8 shuffle(const vfloat8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat8 shuffle(const vfloat8& a, const vfloat8& b) {
+ return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+#if !defined(__aarch64__)
+ template<> __forceinline vfloat8 shuffle<0, 0, 2, 2>(const vfloat8& v) { return _mm256_moveldup_ps(v); }
+ template<> __forceinline vfloat8 shuffle<1, 1, 3, 3>(const vfloat8& v) { return _mm256_movehdup_ps(v); }
+ template<> __forceinline vfloat8 shuffle<0, 1, 0, 1>(const vfloat8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
+#endif
+
+ __forceinline vfloat8 broadcast(const float* ptr) { return _mm256_broadcast_ss(ptr); }
+ template<size_t i> __forceinline vfloat8 insert4(const vfloat8& a, const vfloat4& b) { return _mm256_insertf128_ps(a, b, i); }
+ template<size_t i> __forceinline vfloat4 extract4 (const vfloat8& a) { return _mm256_extractf128_ps(a, i); }
+ template<> __forceinline vfloat4 extract4<0>(const vfloat8& a) { return _mm256_castps256_ps128(a); }
+
+ __forceinline float toScalar(const vfloat8& v) { return _mm_cvtss_f32(_mm256_castps256_ps128(v)); }
+
+ __forceinline vfloat8 assign(const vfloat4& a) { return _mm256_castps128_ps256(a); }
+
+#if defined (__AVX2__) && !defined(__aarch64__)
+ __forceinline vfloat8 permute(const vfloat8& a, const __m256i& index) {
+ return _mm256_permutevar8x32_ps(a, index);
+ }
+#endif
+
+#if defined(__AVX512VL__)
+ template<int i>
+ static __forceinline vfloat8 align_shift_right(const vfloat8& a, const vfloat8& b) {
+ return _mm256_castsi256_ps(_mm256_alignr_epi32(_mm256_castps_si256(a), _mm256_castps_si256(b), i));
+ }
+#endif
+
+#if defined (__AVX_I__)
+ template<const int mode>
+ static __forceinline vint4 convert_to_hf16(const vfloat8& a) {
+ return _mm256_cvtps_ph(a, mode);
+ }
+
+ static __forceinline vfloat8 convert_from_hf16(const vint4& a) {
+ return _mm256_cvtph_ps(a);
+ }
+#endif
+
+ __forceinline vfloat4 broadcast4f(const vfloat8& a, const size_t k) {
+ return vfloat4::broadcast(&a[k]);
+ }
+
+ __forceinline vfloat8 broadcast8f(const vfloat8& a, const size_t k) {
+ return vfloat8::broadcast(&a[k]);
+ }
+
+#if defined(__AVX512VL__)
+ static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
+ return align_shift_right<1>(zero,x);
+ }
+#else
+ static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
+ const vfloat8 t0 = shuffle<1,2,3,0>(x);
+ const vfloat8 t1 = shuffle4<1,0>(t0);
+ return _mm256_blend_ps(t0,t1,0x88);
+ }
+#endif
+
+ __forceinline vint8 floori(const vfloat8& a) {
+ return vint8(floor(a));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3)
+ {
+ vfloat8 l02 = unpacklo(r0,r2);
+ vfloat8 h02 = unpackhi(r0,r2);
+ vfloat8 l13 = unpacklo(r1,r3);
+ vfloat8 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ c3 = unpackhi(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, vfloat8& c0, vfloat8& c1, vfloat8& c2)
+ {
+ vfloat8 l02 = unpacklo(r0,r2);
+ vfloat8 h02 = unpackhi(r0,r2);
+ vfloat8 l13 = unpacklo(r1,r3);
+ vfloat8 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, const vfloat8& r4, const vfloat8& r5, const vfloat8& r6, const vfloat8& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3, vfloat8& c4, vfloat8& c5, vfloat8& c6, vfloat8& c7)
+ {
+ vfloat8 h0,h1,h2,h3; transpose(r0,r1,r2,r3,h0,h1,h2,h3);
+ vfloat8 h4,h5,h6,h7; transpose(r4,r5,r6,r7,h4,h5,h6,h7);
+ c0 = shuffle4<0,2>(h0,h4);
+ c1 = shuffle4<0,2>(h1,h5);
+ c2 = shuffle4<0,2>(h2,h6);
+ c3 = shuffle4<0,2>(h3,h7);
+ c4 = shuffle4<1,3>(h0,h4);
+ c5 = shuffle4<1,3>(h1,h5);
+ c6 = shuffle4<1,3>(h2,h6);
+ c7 = shuffle4<1,3>(h3,h7);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3)
+ {
+ transpose(vfloat8(r0,r4), vfloat8(r1,r5), vfloat8(r2,r6), vfloat8(r3,r7), c0, c1, c2, c3);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2)
+ {
+ transpose(vfloat8(r0,r4), vfloat8(r1,r5), vfloat8(r2,r6), vfloat8(r3,r7), c0, c1, c2);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+#if !defined(__aarch64__)
+ __forceinline vfloat8 vreduce_min2(const vfloat8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vfloat8 vreduce_min4(const vfloat8& v) { vfloat8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vfloat8 vreduce_min (const vfloat8& v) { vfloat8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vfloat8 vreduce_max2(const vfloat8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vfloat8 vreduce_max4(const vfloat8& v) { vfloat8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vfloat8 vreduce_max (const vfloat8& v) { vfloat8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vfloat8 vreduce_add2(const vfloat8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vfloat8 vreduce_add4(const vfloat8& v) { vfloat8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vfloat8 vreduce_add (const vfloat8& v) { vfloat8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline float reduce_min(const vfloat8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline float reduce_add(const vfloat8& v) { return toScalar(vreduce_add(v)); }
+#else
+ __forceinline float reduce_min(const vfloat8& v) { return vminvq_f32(_mm_min_ps(v.v.lo,v.v.hi)); }
+ __forceinline float reduce_max(const vfloat8& v) { return vmaxvq_f32(_mm_max_ps(v.v.lo,v.v.hi)); }
+ __forceinline vfloat8 vreduce_min(const vfloat8& v) { return vfloat8(reduce_min(v)); }
+ __forceinline vfloat8 vreduce_max(const vfloat8& v) { return vfloat8(reduce_max(v)); }
+ __forceinline float reduce_add(const vfloat8& v) { return vaddvq_f32(_mm_add_ps(v.v.lo,v.v.hi)); }
+
+#endif
+ __forceinline size_t select_min(const vboolf8& valid, const vfloat8& v)
+ {
+ const vfloat8 a = select(valid,v,vfloat8(pos_inf));
+ const vbool8 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+
+ __forceinline size_t select_max(const vboolf8& valid, const vfloat8& v)
+ {
+ const vfloat8 a = select(valid,v,vfloat8(neg_inf));
+ const vbool8 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators (pairs of Vec3fa's)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vfloat8 dot(const vfloat8& a, const vfloat8& b) {
+ // return vreduce_add4(a*b);
+ //}
+
+ __forceinline vfloat8 dot(const vfloat8& a, const vfloat8& b) {
+ return _mm256_dp_ps(a,b,0x7F);
+ }
+
+ __forceinline vfloat8 cross(const vfloat8& a, const vfloat8& b)
+ {
+ const vfloat8 a0 = a;
+ const vfloat8 b0 = shuffle<1,2,0,3>(b);
+ const vfloat8 a1 = shuffle<1,2,0,3>(a);
+ const vfloat8 b1 = b;
+ return shuffle<1,2,0,3>(msub(a0,b0,a1*b1));
+ }
+
+ //__forceinline float sqr_length (const vfloat<8>& a) { return dot(a,a); }
+ //__forceinline float rcp_length (const vfloat<8>& a) { return rsqrt(dot(a,a)); }
+ //__forceinline float rcp_length2(const vfloat<8>& a) { return rcp(dot(a,a)); }
+ //__forceinline float length (const vfloat<8>& a) { return sqrt(dot(a,a)); }
+ __forceinline vfloat<8> normalize(const vfloat<8>& a) { return a*rsqrt(dot(a,a)); }
+ //__forceinline float distance(const vfloat<8>& a, const vfloat<8>& b) { return length(a-b); }
+ //__forceinline float halfArea(const vfloat<8>& d) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ //__forceinline float area (const vfloat<8>& d) { return 2.0f*halfArea(d); }
+ //__forceinline vfloat<8> reflect(const vfloat<8>& V, const vfloat<8>& N) { return 2.0f*dot(V,N)*N-V; }
+
+ //__forceinline vfloat<8> normalize_safe(const vfloat<8>& a) {
+ // const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ //}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// In Register Sorting
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 sort_ascending(const vfloat8& v)
+ {
+ const vfloat8 a0 = v;
+ const vfloat8 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat8 c0 = min(a0,b0);
+ const vfloat8 d0 = max(a0,b0);
+ const vfloat8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vfloat8 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat8 c1 = min(a1,b1);
+ const vfloat8 d1 = max(a1,b1);
+ const vfloat8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vfloat8 b2 = shuffle<1,0,3,2>(a2);
+ const vfloat8 c2 = min(a2,b2);
+ const vfloat8 d2 = max(a2,b2);
+ const vfloat8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vfloat8 b3 = shuffle4<1,0>(a3);
+ const vfloat8 c3 = min(a3,b3);
+ const vfloat8 d3 = max(a3,b3);
+ const vfloat8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vfloat8 b4 = shuffle<2,3,0,1>(a4);
+ const vfloat8 c4 = min(a4,b4);
+ const vfloat8 d4 = max(a4,b4);
+ const vfloat8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vfloat8 b5 = shuffle<1,0,3,2>(a5);
+ const vfloat8 c5 = min(a5,b5);
+ const vfloat8 d5 = max(a5,b5);
+ const vfloat8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ __forceinline vfloat8 sort_descending(const vfloat8& v)
+ {
+ const vfloat8 a0 = v;
+ const vfloat8 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat8 c0 = max(a0,b0);
+ const vfloat8 d0 = min(a0,b0);
+ const vfloat8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vfloat8 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat8 c1 = max(a1,b1);
+ const vfloat8 d1 = min(a1,b1);
+ const vfloat8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vfloat8 b2 = shuffle<1,0,3,2>(a2);
+ const vfloat8 c2 = max(a2,b2);
+ const vfloat8 d2 = min(a2,b2);
+ const vfloat8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vfloat8 b3 = shuffle4<1,0>(a3);
+ const vfloat8 c3 = max(a3,b3);
+ const vfloat8 d3 = min(a3,b3);
+ const vfloat8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vfloat8 b4 = shuffle<2,3,0,1>(a4);
+ const vfloat8 c4 = max(a4,b4);
+ const vfloat8 d4 = min(a4,b4);
+ const vfloat8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vfloat8 b5 = shuffle<1,0,3,2>(a5);
+ const vfloat8 c5 = max(a5,b5);
+ const vfloat8 d5 = min(a5,b5);
+ const vfloat8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vint16_avx512.h b/thirdparty/embree-aarch64/common/simd/vint16_avx512.h
new file mode 100644
index 0000000000..3249bc2b45
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vint16_avx512.h
@@ -0,0 +1,490 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 16-wide AVX-512 integer type */
+ template<>
+ struct vint<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint16& t) { v = t.v; }
+ __forceinline vint16& operator =(const vint16& f) { v = f.v; return *this; }
+
+ __forceinline vint(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vint(int i) {
+ v = _mm512_set1_epi32(i);
+ }
+
+ __forceinline vint(int a, int b, int c, int d) {
+ v = _mm512_set4_epi32(d,c,b,a);
+ }
+
+ __forceinline vint(int a0 , int a1 , int a2 , int a3,
+ int a4 , int a5 , int a6 , int a7,
+ int a8 , int a9 , int a10, int a11,
+ int a12, int a13, int a14, int a15)
+ {
+ v = _mm512_set_epi32(a15,a14,a13,a12,a11,a10,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline vint(const vint4& i) {
+ v = _mm512_broadcast_i32x4(i);
+ }
+
+ __forceinline vint(const vint4& a, const vint4& b, const vint4& c, const vint4& d) {
+ v = _mm512_castsi128_si512(a);
+ v = _mm512_inserti32x4(v, b, 1);
+ v = _mm512_inserti32x4(v, c, 2);
+ v = _mm512_inserti32x4(v, d, 3);
+ }
+
+ __forceinline vint(const vint8& i) {
+ v = _mm512_castps_si512(_mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castsi256_pd(i))));
+ }
+
+ __forceinline vint(const vint8& a, const vint8& b) {
+ v = _mm512_castsi256_si512(a);
+ v = _mm512_inserti64x4(v, b, 1);
+ }
+
+ __forceinline explicit vint(const __m512& f) {
+ v = _mm512_cvtps_epi32(f);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vint(OneTy) : v(_mm512_set1_epi32(1)) {}
+ __forceinline vint(PosInfTy) : v(_mm512_set1_epi32(pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm512_set1_epi32(neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint16 load (const void* addr) { return _mm512_load_si512((int*)addr); }
+
+ static __forceinline vint16 load(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vint16 load(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_load_si256((__m256i*)ptr)); }
+
+ static __forceinline vint16 loadu(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+ static __forceinline vint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
+
+ static __forceinline vint16 loadu(const void* addr) { return _mm512_loadu_si512(addr); }
+
+ static __forceinline vint16 load (const vboolf16& mask, const void* addr) { return _mm512_mask_load_epi32 (_mm512_setzero_epi32(),mask,addr); }
+ static __forceinline vint16 loadu(const vboolf16& mask, const void* addr) { return _mm512_mask_loadu_epi32(_mm512_setzero_epi32(),mask,addr); }
+
+ static __forceinline void store (void* ptr, const vint16& v) { _mm512_store_si512 (ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint16& v) { _mm512_storeu_si512(ptr,v); }
+
+ static __forceinline void store (const vboolf16& mask, void* addr, const vint16& v2) { _mm512_mask_store_epi32(addr,mask,v2); }
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vint16& f) { _mm512_mask_storeu_epi32((int*)ptr,mask,f); }
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vint16& a) { _mm512_stream_si512((__m512i*)ptr,a); }
+
+ /* pass by value to avoid compiler generating inefficient code */
+ static __forceinline void storeu_compact(const vboolf16 mask, void* addr, vint16 reg) {
+ _mm512_mask_compressstoreu_epi32(addr,mask,reg);
+ }
+
+ static __forceinline void storeu_compact_single(const vboolf16 mask, void* addr, vint16 reg) {
+ //_mm512_mask_compressstoreu_epi32(addr,mask,reg);
+ *(float*)addr = mm512_cvtss_f32(_mm512_mask_compress_ps(_mm512_castsi512_ps(reg),mask,_mm512_castsi512_ps(reg)));
+ }
+
+ static __forceinline vint16 compact64bit(const vboolf16& mask, vint16 &v) {
+ return _mm512_mask_compress_epi64(v,mask,v);
+ }
+
+ static __forceinline vint16 compact(const vboolf16& mask, vint16 &v) {
+ return _mm512_mask_compress_epi32(v,mask,v);
+ }
+
+ static __forceinline vint16 compact(const vboolf16& mask, const vint16 &a, vint16 &b) {
+ return _mm512_mask_compress_epi32(a,mask,b);
+ }
+
+ static __forceinline vint16 expand(const vboolf16& mask, const vint16& a, vint16& b) {
+ return _mm512_mask_expand_epi32(b,mask,a);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const int* ptr, const vint16& index) {
+ return _mm512_i32gather_epi32(index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const vboolf16& mask, const int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(_mm512_undefined_epi32(),mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const vboolf16& mask, vint16& dest, const int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(dest,mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(int* ptr, const vint16& index, const vint16& v) {
+ _mm512_i32scatter_epi32((int*)ptr,index,v,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, int* ptr, const vint16& index, const vint16& v) {
+ _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
+ }
+
+ static __forceinline vint16 broadcast64bit(size_t v) {
+ return _mm512_set1_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int& operator [](size_t index) { assert(index < 16); return i[index]; }
+ __forceinline const int& operator [](size_t index) const { assert(index < 16); return i[index]; }
+
+ __forceinline unsigned int uint (size_t index) const { assert(index < 16); return ((unsigned int*)i)[index]; }
+ __forceinline size_t& uint64_t(size_t index) const { assert(index < 8); return ((size_t*)i)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 asBool(const vint16& a) { return _mm512_movepi32_mask(a); }
+
+ __forceinline vint16 operator +(const vint16& a) { return a; }
+ __forceinline vint16 operator -(const vint16& a) { return _mm512_sub_epi32(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 operator +(const vint16& a, const vint16& b) { return _mm512_add_epi32(a, b); }
+ __forceinline vint16 operator +(const vint16& a, int b) { return a + vint16(b); }
+ __forceinline vint16 operator +(int a, const vint16& b) { return vint16(a) + b; }
+
+ __forceinline vint16 operator -(const vint16& a, const vint16& b) { return _mm512_sub_epi32(a, b); }
+ __forceinline vint16 operator -(const vint16& a, int b) { return a - vint16(b); }
+ __forceinline vint16 operator -(int a, const vint16& b) { return vint16(a) - b; }
+
+ __forceinline vint16 operator *(const vint16& a, const vint16& b) { return _mm512_mullo_epi32(a, b); }
+ __forceinline vint16 operator *(const vint16& a, int b) { return a * vint16(b); }
+ __forceinline vint16 operator *(int a, const vint16& b) { return vint16(a) * b; }
+
+ __forceinline vint16 operator &(const vint16& a, const vint16& b) { return _mm512_and_epi32(a, b); }
+ __forceinline vint16 operator &(const vint16& a, int b) { return a & vint16(b); }
+ __forceinline vint16 operator &(int a, const vint16& b) { return vint16(a) & b; }
+
+ __forceinline vint16 operator |(const vint16& a, const vint16& b) { return _mm512_or_epi32(a, b); }
+ __forceinline vint16 operator |(const vint16& a, int b) { return a | vint16(b); }
+ __forceinline vint16 operator |(int a, const vint16& b) { return vint16(a) | b; }
+
+ __forceinline vint16 operator ^(const vint16& a, const vint16& b) { return _mm512_xor_epi32(a, b); }
+ __forceinline vint16 operator ^(const vint16& a, int b) { return a ^ vint16(b); }
+ __forceinline vint16 operator ^(int a, const vint16& b) { return vint16(a) ^ b; }
+
+ __forceinline vint16 operator <<(const vint16& a, int n) { return _mm512_slli_epi32(a, n); }
+ __forceinline vint16 operator >>(const vint16& a, int n) { return _mm512_srai_epi32(a, n); }
+
+ __forceinline vint16 operator <<(const vint16& a, const vint16& n) { return _mm512_sllv_epi32(a, n); }
+ __forceinline vint16 operator >>(const vint16& a, const vint16& n) { return _mm512_srav_epi32(a, n); }
+
+ __forceinline vint16 sll (const vint16& a, int b) { return _mm512_slli_epi32(a, b); }
+ __forceinline vint16 sra (const vint16& a, int b) { return _mm512_srai_epi32(a, b); }
+ __forceinline vint16 srl (const vint16& a, int b) { return _mm512_srli_epi32(a, b); }
+
+ __forceinline vint16 min(const vint16& a, const vint16& b) { return _mm512_min_epi32(a, b); }
+ __forceinline vint16 min(const vint16& a, int b) { return min(a,vint16(b)); }
+ __forceinline vint16 min(int a, const vint16& b) { return min(vint16(a),b); }
+
+ __forceinline vint16 max(const vint16& a, const vint16& b) { return _mm512_max_epi32(a, b); }
+ __forceinline vint16 max(const vint16& a, int b) { return max(a,vint16(b)); }
+ __forceinline vint16 max(int a, const vint16& b) { return max(vint16(a),b); }
+
+ __forceinline vint16 umin(const vint16& a, const vint16& b) { return _mm512_min_epu32(a, b); }
+ __forceinline vint16 umax(const vint16& a, const vint16& b) { return _mm512_max_epu32(a, b); }
+
+ __forceinline vint16 mask_add(const vboolf16& mask, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_add_epi32(c,mask,a,b); }
+ __forceinline vint16 mask_sub(const vboolf16& mask, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_sub_epi32(c,mask,a,b); }
+
+ __forceinline vint16 mask_and(const vboolf16& m, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_and_epi32(c,m,a,b); }
+ __forceinline vint16 mask_or (const vboolf16& m, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_or_epi32(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16& operator +=(vint16& a, const vint16& b) { return a = a + b; }
+ __forceinline vint16& operator +=(vint16& a, int b) { return a = a + b; }
+
+ __forceinline vint16& operator -=(vint16& a, const vint16& b) { return a = a - b; }
+ __forceinline vint16& operator -=(vint16& a, int b) { return a = a - b; }
+
+ __forceinline vint16& operator *=(vint16& a, const vint16& b) { return a = a * b; }
+ __forceinline vint16& operator *=(vint16& a, int b) { return a = a * b; }
+
+ __forceinline vint16& operator &=(vint16& a, const vint16& b) { return a = a & b; }
+ __forceinline vint16& operator &=(vint16& a, int b) { return a = a & b; }
+
+ __forceinline vint16& operator |=(vint16& a, const vint16& b) { return a = a | b; }
+ __forceinline vint16& operator |=(vint16& a, int b) { return a = a | b; }
+
+ __forceinline vint16& operator <<=(vint16& a, int b) { return a = a << b; }
+ __forceinline vint16& operator >>=(vint16& a, int b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vint16& a, int b) { return a == vint16(b); }
+ __forceinline vboolf16 operator ==(int a, const vint16& b) { return vint16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vint16& a, int b) { return a != vint16(b); }
+ __forceinline vboolf16 operator !=(int a, const vint16& b) { return vint16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vint16& a, int b) { return a < vint16(b); }
+ __forceinline vboolf16 operator < (int a, const vint16& b) { return vint16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vint16& a, int b) { return a >= vint16(b); }
+ __forceinline vboolf16 operator >=(int a, const vint16& b) { return vint16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vint16& a, int b) { return a > vint16(b); }
+ __forceinline vboolf16 operator > (int a, const vint16& b) { return vint16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vint16& a, int b) { return a <= vint16(b); }
+ __forceinline vboolf16 operator <=(int a, const vint16& b) { return vint16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_le(const vint16& a, const vint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_gt(const vint16& a, const vint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+
+ __forceinline vboolf16 eq(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_le(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_gt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GT); }
+
+
+ __forceinline vint16 select(const vboolf16& m, const vint16& t, const vint16& f) {
+ return _mm512_mask_or_epi32(f,m,t,t);
+ }
+
+ __forceinline void xchg(const vboolf16& m, vint16& a, vint16& b) {
+ const vint16 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboolf16 test(const vboolf16& m, const vint16& a, const vint16& b) {
+ return _mm512_mask_test_epi32_mask(m,a,b);
+ }
+
+ __forceinline vboolf16 test(const vint16& a, const vint16& b) {
+ return _mm512_test_epi32_mask(a,b);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 unpacklo(const vint16& a, const vint16& b) { return _mm512_unpacklo_epi32(a, b); }
+ __forceinline vint16 unpackhi(const vint16& a, const vint16& b) { return _mm512_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vint16 shuffle(const vint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint16 shuffle(const vint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vint16 shuffle4(const vint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint16 shuffle4(const vint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vint16 align_shift_right(const vint16& a, const vint16& b) {
+ return _mm512_alignr_epi32(a, b, i);
+ };
+
+ __forceinline int toScalar(const vint16& v) {
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(v));
+ }
+
+ template<int i> __forceinline vint16 insert4(const vint16& a, const vint4& b) { return _mm512_inserti32x4(a, b, i); }
+
+ __forceinline size_t extract64bit(const vint16& v) {
+ return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
+ }
+
+ template<int N, int i>
+ vint<N> extractN(const vint16& v);
+
+ template<> __forceinline vint4 extractN<4,0>(const vint16& v) { return _mm512_castsi512_si128(v); }
+ template<> __forceinline vint4 extractN<4,1>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 1); }
+ template<> __forceinline vint4 extractN<4,2>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 2); }
+ template<> __forceinline vint4 extractN<4,3>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 3); }
+
+ template<> __forceinline vint8 extractN<8,0>(const vint16& v) { return _mm512_castsi512_si256(v); }
+ template<> __forceinline vint8 extractN<8,1>(const vint16& v) { return _mm512_extracti32x8_epi32(v, 1); }
+
+ template<int i> __forceinline vint4 extract4 (const vint16& v) { return _mm512_extracti32x4_epi32(v, i); }
+ template<> __forceinline vint4 extract4<0>(const vint16& v) { return _mm512_castsi512_si128(v); }
+
+ template<int i> __forceinline vint8 extract8 (const vint16& v) { return _mm512_extracti32x8_epi32(v, i); }
+ template<> __forceinline vint8 extract8<0>(const vint16& v) { return _mm512_castsi512_si256(v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 vreduce_min2(vint16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_min4(vint16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vint16 vreduce_min8(vint16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_min (vint16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vint16 vreduce_max2(vint16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_max4(vint16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vint16 vreduce_max8(vint16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_max (vint16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vint16 vreduce_and2(vint16 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_and4(vint16 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_and8(vint16 x) { x = vreduce_and4(x); return x & shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_and (vint16 x) { x = vreduce_and8(x); return x & shuffle4<2,3,0,1>(x); }
+
+ __forceinline vint16 vreduce_or2(vint16 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_or4(vint16 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_or8(vint16 x) { x = vreduce_or4(x); return x | shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_or (vint16 x) { x = vreduce_or8(x); return x | shuffle4<2,3,0,1>(x); }
+
+ __forceinline vint16 vreduce_add2(vint16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_add4(vint16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_add8(vint16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_add (vint16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline int reduce_min(const vint16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint16& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_and(const vint16& v) { return toScalar(vreduce_and(v)); }
+ __forceinline int reduce_or (const vint16& v) { return toScalar(vreduce_or (v)); }
+ __forceinline int reduce_add(const vint16& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 conflict(const vint16& index)
+ {
+ return _mm512_conflict_epi32(index);
+ }
+
+ __forceinline vint16 conflict(const vboolf16& mask, vint16& dest, const vint16& index)
+ {
+ return _mm512_mask_conflict_epi32(dest,mask,index);
+ }
+
+ __forceinline vint16 convert_uint32_t(const __m512& f) {
+ return _mm512_cvtps_epu32(f);
+ }
+
+ __forceinline vint16 permute(vint16 v, vint16 index) {
+ return _mm512_permutexvar_epi32(index,v);
+ }
+
+ __forceinline vint16 reverse(const vint16 &a) {
+ return permute(a,vint16(reverse_step));
+ }
+
+ __forceinline vint16 prefix_sum(const vint16& a)
+ {
+ const vint16 z(zero);
+ vint16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vint16 reverse_prefix_sum(const vint16& a)
+ {
+ const vint16 z(zero);
+ vint16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ /* this should use a vbool8 and a vint8_64...*/
+ template<int scale = 1, int hint = _MM_HINT_T0>
+ __forceinline void gather_prefetch64(const void* base_addr, const vbool16& mask, const vint16& offset)
+ {
+#if defined(__AVX512PF__)
+ _mm512_mask_prefetch_i64gather_pd(offset, mask, base_addr, scale, hint);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vint4_sse2.h b/thirdparty/embree-aarch64/common/simd/vint4_sse2.h
new file mode 100644
index 0000000000..96f105a7c5
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vint4_sse2.h
@@ -0,0 +1,681 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+namespace embree
+{
+ /* 4-wide SSE integer type */
+ template<>
+ struct vint<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128i v; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint4& a) { v = a.v; }
+ __forceinline vint4& operator =(const vint4& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m128i a) : v(a) {}
+ __forceinline operator const __m128i&() const { return v; }
+ __forceinline operator __m128i&() { return v; }
+
+ __forceinline vint(int a) : v(_mm_set1_epi32(a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm_set_epi32(d, c, b, a)) {}
+
+ __forceinline explicit vint(__m128 a) : v(_mm_cvtps_epi32(a)) {}
+#if defined(__AVX512VL__)
+ __forceinline explicit vint(const vboolf4& a) : v(_mm_movm_epi32(a)) {}
+#else
+ __forceinline explicit vint(const vboolf4& a) : v(_mm_castps_si128((__m128)a)) {}
+#endif
+
+ __forceinline vint(long long a, long long b) : v(_mm_set_epi64x(b,a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm_setzero_si128()) {}
+ __forceinline vint(OneTy) : v(_mm_set_epi32(1, 1, 1, 1)) {}
+ __forceinline vint(PosInfTy) : v(_mm_set_epi32(pos_inf, pos_inf, pos_inf, pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm_set_epi32(neg_inf, neg_inf, neg_inf, neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm_set_epi32(3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm_set_epi32(0, 1, 2, 3)) {}
+
+ __forceinline vint(TrueTy) { v = _mm_cmpeq_epi32(v,v); }
+ __forceinline vint(UndefinedTy) : v(_mm_castps_si128(_mm_undefined_ps())) {}
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint4 load (const void* a) { return _mm_load_si128((__m128i*)a); }
+ static __forceinline vint4 loadu(const void* a) { return _mm_loadu_si128((__m128i*)a); }
+
+ static __forceinline void store (void* ptr, const vint4& v) { _mm_store_si128((__m128i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vint4 compact(const vboolf4& mask, vint4 &v) {
+ return _mm_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vint4 compact(const vboolf4& mask, vint4 &a, const vint4& b) {
+ return _mm_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vint4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_epi32 (_mm_setzero_si128(),mask,ptr); }
+ static __forceinline vint4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_epi32(_mm_setzero_si128(),mask,ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& v) { _mm_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& v) { _mm_mask_storeu_epi32(ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vint4 load (const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+ static __forceinline vint4 loadu(const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+#else
+ static __forceinline vint4 load (const vbool4& mask, const void* a) { return _mm_and_si128(_mm_load_si128 ((__m128i*)a),mask); }
+ static __forceinline vint4 loadu(const vbool4& mask, const void* a) { return _mm_and_si128(_mm_loadu_si128((__m128i*)a),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& i) { store (ptr,select(mask,i,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
+#endif
+
+
+#if defined(__aarch64__)
+ static __forceinline vint4 load(const uint8_t* ptr) {
+ return _mm_load4epu8_epi32(((__m128i*)ptr));
+ }
+ static __forceinline vint4 loadu(const uint8_t* ptr) {
+ return _mm_load4epu8_epi32(((__m128i*)ptr));
+ }
+#elif defined(__SSE4_1__)
+ static __forceinline vint4 load(const uint8_t* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+ static __forceinline vint4 loadu(const uint8_t* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+#else
+
+ static __forceinline vint4 load(const uint8_t* ptr) {
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+
+ static __forceinline vint4 loadu(const uint8_t* ptr) {
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+
+#endif
+
+ static __forceinline vint4 load(const unsigned short* ptr) {
+#if defined(__aarch64__)
+ return __m128i(vmovl_u16(vld1_u16(ptr)));
+#elif defined (__SSE4_1__)
+ return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
+#else
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+#endif
+ }
+
+ static __forceinline void store(uint8_t* ptr, const vint4& v) {
+#if defined(__aarch64__)
+ int32x4_t x = v;
+ uint16x4_t y = vqmovn_u32(uint32x4_t(x));
+ uint8x8_t z = vqmovn_u16(vcombine_u16(y, y));
+ vst1_lane_u32((uint32_t *)ptr,uint32x2_t(z), 0);
+#elif defined(__SSE4_1__)
+ __m128i x = v;
+ x = _mm_packus_epi32(x, x);
+ x = _mm_packus_epi16(x, x);
+ *(int*)ptr = _mm_cvtsi128_si32(x);
+#else
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (uint8_t)v[i];
+#endif
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint4& v) {
+#if defined(__aarch64__)
+ uint32x4_t x = uint32x4_t(v.v);
+ uint16x4_t y = vqmovn_u32(x);
+ vst1_u16(ptr, y);
+#else
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (unsigned short)v[i];
+#endif
+ }
+
+ static __forceinline vint4 load_nt(void* ptr) {
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ return _mm_stream_load_si128((__m128i*)ptr);
+#else
+ return _mm_load_si128((__m128i*)ptr);
+#endif
+ }
+
+ static __forceinline void store_nt(void* ptr, const vint4& v) {
+#if !defined(__aarch64__) && defined(__SSE4_1__)
+ _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v));
+#else
+ _mm_store_si128((__m128i*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vint4 gather(const int* ptr, const vint4& index) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_i32gather_epi32(ptr, index, scale);
+#else
+ return vint4(
+ *(int*)(((int8_t*)ptr)+scale*index[0]),
+ *(int*)(((int8_t*)ptr)+scale*index[1]),
+ *(int*)(((int8_t*)ptr)+scale*index[2]),
+ *(int*)(((int8_t*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vint4 gather(const vboolf4& mask, const int* ptr, const vint4& index) {
+ vint4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#elif defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_mask_i32gather_epi32(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(int*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(int*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(int*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(int*)(((int8_t*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint4& index, const vint4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_i32scatter_epi32((int*)ptr, index, v, scale);
+#else
+ *(int*)(((int8_t*)ptr)+scale*index[0]) = v[0];
+ *(int*)(((int8_t*)ptr)+scale*index[1]) = v[1];
+ *(int*)(((int8_t*)ptr)+scale*index[2]) = v[2];
+ *(int*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf4& mask, void* ptr, const vint4& index, const vint4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_mask_i32scatter_epi32((int*)ptr, mask, index, v, scale);
+#else
+ if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*index[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*index[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*index[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+#if defined(__x86_64__) || defined(__aarch64__)
+ static __forceinline vint4 broadcast64(long long a) { return _mm_set1_epi64x(a); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 4); return i[index]; }
+
+ friend __forceinline vint4 select(const vboolf4& m, const vint4& t, const vint4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
+#elif defined(__aarch64__)
+ return _mm_castps_si128(_mm_blendv_ps((__m128)f.v,(__m128) t.v, (__m128)m.v));
+#elif defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f));
+#endif
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 asBool(const vint4& a) { return _mm_movepi32_mask(a); }
+#else
+ __forceinline vboolf4 asBool(const vint4& a) { return _mm_castsi128_ps(a); }
+#endif
+
+ __forceinline vint4 operator +(const vint4& a) { return a; }
+ __forceinline vint4 operator -(const vint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
+#if defined(__aarch64__)
+ __forceinline vint4 abs(const vint4& a) { return vabsq_s32(a.v); }
+#elif defined(__SSSE3__)
+ __forceinline vint4 abs(const vint4& a) { return _mm_abs_epi32(a); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4 operator +(const vint4& a, const vint4& b) { return _mm_add_epi32(a, b); }
+ __forceinline vint4 operator +(const vint4& a, int b) { return a + vint4(b); }
+ __forceinline vint4 operator +(int a, const vint4& b) { return vint4(a) + b; }
+
+ __forceinline vint4 operator -(const vint4& a, const vint4& b) { return _mm_sub_epi32(a, b); }
+ __forceinline vint4 operator -(const vint4& a, int b) { return a - vint4(b); }
+ __forceinline vint4 operator -(int a, const vint4& b) { return vint4(a) - b; }
+
+#if (defined(__aarch64__)) || defined(__SSE4_1__)
+ __forceinline vint4 operator *(const vint4& a, const vint4& b) { return _mm_mullo_epi32(a, b); }
+#else
+ __forceinline vint4 operator *(const vint4& a, const vint4& b) { return vint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
+#endif
+ __forceinline vint4 operator *(const vint4& a, int b) { return a * vint4(b); }
+ __forceinline vint4 operator *(int a, const vint4& b) { return vint4(a) * b; }
+
+ __forceinline vint4 operator &(const vint4& a, const vint4& b) { return _mm_and_si128(a, b); }
+ __forceinline vint4 operator &(const vint4& a, int b) { return a & vint4(b); }
+ __forceinline vint4 operator &(int a, const vint4& b) { return vint4(a) & b; }
+
+ __forceinline vint4 operator |(const vint4& a, const vint4& b) { return _mm_or_si128(a, b); }
+ __forceinline vint4 operator |(const vint4& a, int b) { return a | vint4(b); }
+ __forceinline vint4 operator |(int a, const vint4& b) { return vint4(a) | b; }
+
+ __forceinline vint4 operator ^(const vint4& a, const vint4& b) { return _mm_xor_si128(a, b); }
+ __forceinline vint4 operator ^(const vint4& a, int b) { return a ^ vint4(b); }
+ __forceinline vint4 operator ^(int a, const vint4& b) { return vint4(a) ^ b; }
+
+ __forceinline vint4 operator <<(const vint4& a, const int n) { return _mm_slli_epi32(a, n); }
+ __forceinline vint4 operator >>(const vint4& a, const int n) { return _mm_srai_epi32(a, n); }
+
+ __forceinline vint4 sll (const vint4& a, int b) { return _mm_slli_epi32(a, b); }
+ __forceinline vint4 sra (const vint4& a, int b) { return _mm_srai_epi32(a, b); }
+ __forceinline vint4 srl (const vint4& a, int b) { return _mm_srli_epi32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4& operator +=(vint4& a, const vint4& b) { return a = a + b; }
+ __forceinline vint4& operator +=(vint4& a, int b) { return a = a + b; }
+
+ __forceinline vint4& operator -=(vint4& a, const vint4& b) { return a = a - b; }
+ __forceinline vint4& operator -=(vint4& a, int b) { return a = a - b; }
+
+#if (defined(__aarch64__)) || defined(__SSE4_1__)
+ __forceinline vint4& operator *=(vint4& a, const vint4& b) { return a = a * b; }
+ __forceinline vint4& operator *=(vint4& a, int b) { return a = a * b; }
+#endif
+
+ __forceinline vint4& operator &=(vint4& a, const vint4& b) { return a = a & b; }
+ __forceinline vint4& operator &=(vint4& a, int b) { return a = a & b; }
+
+ __forceinline vint4& operator |=(vint4& a, const vint4& b) { return a = a | b; }
+ __forceinline vint4& operator |=(vint4& a, int b) { return a = a | b; }
+
+ __forceinline vint4& operator <<=(vint4& a, int b) { return a = a << b; }
+ __forceinline vint4& operator >>=(vint4& a, int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf4 operator < (const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf4 operator >=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf4 operator > (const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf4 operator <=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+ __forceinline vboolf4 operator !=(const vint4& a, const vint4& b) { return !(a == b); }
+ __forceinline vboolf4 operator < (const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmplt_epi32(a, b)); }
+ __forceinline vboolf4 operator >=(const vint4& a, const vint4& b) { return !(a < b); }
+ __forceinline vboolf4 operator > (const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmpgt_epi32(a, b)); }
+ __forceinline vboolf4 operator <=(const vint4& a, const vint4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vint4& a, int b) { return a == vint4(b); }
+ __forceinline vboolf4 operator ==(int a, const vint4& b) { return vint4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vint4& a, int b) { return a != vint4(b); }
+ __forceinline vboolf4 operator !=(int a, const vint4& b) { return vint4(a) != b; }
+
+ __forceinline vboolf4 operator < (const vint4& a, int b) { return a < vint4(b); }
+ __forceinline vboolf4 operator < (int a, const vint4& b) { return vint4(a) < b; }
+
+ __forceinline vboolf4 operator >=(const vint4& a, int b) { return a >= vint4(b); }
+ __forceinline vboolf4 operator >=(int a, const vint4& b) { return vint4(a) >= b; }
+
+ __forceinline vboolf4 operator > (const vint4& a, int b) { return a > vint4(b); }
+ __forceinline vboolf4 operator > (int a, const vint4& b) { return vint4(a) > b; }
+
+ __forceinline vboolf4 operator <=(const vint4& a, int b) { return a <= vint4(b); }
+ __forceinline vboolf4 operator <=(int a, const vint4& b) { return vint4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vint4& a, const vint4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vint4& a, const vint4& b) { return a != b; }
+ __forceinline vboolf4 lt(const vint4& a, const vint4& b) { return a < b; }
+ __forceinline vboolf4 ge(const vint4& a, const vint4& b) { return a >= b; }
+ __forceinline vboolf4 gt(const vint4& a, const vint4& b) { return a > b; }
+ __forceinline vboolf4 le(const vint4& a, const vint4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a != b); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a < b); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a >= b); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a > b); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vint4 select(const vint4& t, const vint4& f) {
+#if defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+ __forceinline vint4 min(const vint4& a, const vint4& b) { return _mm_min_epi32(a, b); }
+ __forceinline vint4 max(const vint4& a, const vint4& b) { return _mm_max_epi32(a, b); }
+
+ __forceinline vint4 umin(const vint4& a, const vint4& b) { return _mm_min_epu32(a, b); }
+ __forceinline vint4 umax(const vint4& a, const vint4& b) { return _mm_max_epu32(a, b); }
+
+#else
+ __forceinline vint4 min(const vint4& a, const vint4& b) { return select(a < b,a,b); }
+ __forceinline vint4 max(const vint4& a, const vint4& b) { return select(a < b,b,a); }
+#endif
+
+ __forceinline vint4 min(const vint4& a, int b) { return min(a,vint4(b)); }
+ __forceinline vint4 min(int a, const vint4& b) { return min(vint4(a),b); }
+ __forceinline vint4 max(const vint4& a, int b) { return max(a,vint4(b)); }
+ __forceinline vint4 max(int a, const vint4& b) { return max(vint4(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4 unpacklo(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+ __forceinline vint4 unpackhi(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+
+#if defined(__aarch64__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& v) {
+ return vreinterpretq_s32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
+ }
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
+ return vreinterpretq_s32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
+ }
+#else
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& v) {
+ return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
+ return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+#endif
+#if defined(__SSE3__)
+ template<> __forceinline vint4 shuffle<0, 0, 2, 2>(const vint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vint4 shuffle<1, 1, 3, 3>(const vint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vint4 shuffle<0, 1, 0, 1>(const vint4& v) { return _mm_castpd_si128(_mm_movedup_pd (_mm_castsi128_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vint4 shuffle(const vint4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+#if defined(__aarch64__)
+ template<int src> __forceinline int extract(const vint4& b);
+ template<int dst> __forceinline vint4 insert(const vint4& a, const int b);
+#elif defined(__SSE4_1__)
+ template<int src> __forceinline int extract(const vint4& b) { return _mm_extract_epi32(b, src); }
+ template<int dst> __forceinline vint4 insert(const vint4& a, const int b) { return _mm_insert_epi32(a, b, dst); }
+#else
+ template<int src> __forceinline int extract(const vint4& b) { return b[src&3]; }
+ template<int dst> __forceinline vint4 insert(const vint4& a, int b) { vint4 c = a; c[dst&3] = b; return c; }
+#endif
+
+#if defined(__aarch64__)
+ template<> __forceinline int extract<0>(const vint4& b) {
+ return b.v[0];
+ }
+ template<> __forceinline int extract<1>(const vint4& b) {
+ return b.v[1];
+ }
+ template<> __forceinline int extract<2>(const vint4& b) {
+ return b.v[2];
+ }
+ template<> __forceinline int extract<3>(const vint4& b) {
+ return b.v[3];
+ }
+ template<> __forceinline vint4 insert<0>(const vint4& a, int b)
+ {
+ vint4 c = a;
+ c[0] = b;
+ return c;
+ }
+ template<> __forceinline vint4 insert<1>(const vint4& a, int b)
+ {
+ vint4 c = a;
+ c[1] = b;
+ return c;
+ }
+ template<> __forceinline vint4 insert<2>(const vint4& a, int b)
+ {
+ vint4 c = a;
+ c[2] = b;
+ return c;
+ }
+ template<> __forceinline vint4 insert<3>(const vint4& a, int b)
+ {
+ vint4 c = a;
+ c[3] = b;
+ return c;
+ }
+
+ __forceinline int toScalar(const vint4& v) {
+ return v[0];
+ }
+
+ __forceinline size_t toSizeT(const vint4& v) {
+ uint64x2_t x = uint64x2_t(v.v);
+ return x[0];
+ }
+#else
+ template<> __forceinline int extract<0>(const vint4& b) { return _mm_cvtsi128_si32(b); }
+
+ __forceinline int toScalar(const vint4& v) { return _mm_cvtsi128_si32(v); }
+
+ __forceinline size_t toSizeT(const vint4& v) {
+#if defined(__WIN32__) && !defined(__X86_64__) // win32 workaround
+ return toScalar(v);
+#elif defined(__ARM_NEON)
+ // FIXME(LTE): Do we need a swap(i.e. use lane 1)?
+ return vgetq_lane_u64(*(reinterpret_cast<const uint64x2_t *>(&v)), 0);
+#else
+ return _mm_cvtsi128_si64(v);
+#endif
+ }
+#endif
+
+#if defined(__AVX512VL__)
+
+ __forceinline vint4 permute(const vint4 &a, const vint4 &index) {
+ return _mm_castps_si128(_mm_permutevar_ps(_mm_castsi128_ps(a),index));
+ }
+
+ template<int i>
+ __forceinline vint4 align_shift_right(const vint4& a, const vint4& b) {
+ return _mm_alignr_epi32(a, b, i);
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__) || defined(__SSE4_1__)
+
+#if defined(__aarch64__)
+ __forceinline vint4 vreduce_min(const vint4& v) { int h = vminvq_s32(v); return vdupq_n_s32(h); }
+ __forceinline vint4 vreduce_max(const vint4& v) { int h = vmaxvq_s32(v); return vdupq_n_s32(h); }
+ __forceinline vint4 vreduce_add(const vint4& v) { int h = vaddvq_s32(v); return vdupq_n_s32(h); }
+
+ __forceinline int reduce_min(const vint4& v) { return vminvq_s32(v); }
+ __forceinline int reduce_max(const vint4& v) { return vmaxvq_s32(v); }
+ __forceinline int reduce_add(const vint4& v) { return vaddvq_s32(v); }
+#else
+ __forceinline vint4 vreduce_min(const vint4& v) { vint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vint4 vreduce_max(const vint4& v) { vint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vint4 vreduce_add(const vint4& v) { vint4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+
+ __forceinline int reduce_min(const vint4& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint4& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint4& v) { return toScalar(vreduce_add(v)); }
+#endif
+
+ __forceinline size_t select_min(const vint4& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint4& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf4& valid, const vint4& v) { const vint4 a = select(valid,v,vint4(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf4& valid, const vint4& v) { const vint4 a = select(valid,v,vint4(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+#else
+
+ __forceinline int reduce_min(const vint4& v) { return min(v[0],v[1],v[2],v[3]); }
+ __forceinline int reduce_max(const vint4& v) { return max(v[0],v[1],v[2],v[3]); }
+ __forceinline int reduce_add(const vint4& v) { return v[0]+v[1]+v[2]+v[3]; }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if (defined(__aarch64__)) || defined(__SSE4_1__)
+
+ __forceinline vint4 usort_ascending(const vint4& v)
+ {
+ const vint4 a0 = v;
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = umin(a0,b0);
+ const vint4 d0 = umax(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = umin(a1,b1);
+ const vint4 d1 = umax(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = umin(a2,b2);
+ const vint4 d2 = umax(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ __forceinline vint4 usort_descending(const vint4& v)
+ {
+ const vint4 a0 = v;
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = umax(a0,b0);
+ const vint4 d0 = umin(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = umax(a1,b1);
+ const vint4 d1 = umin(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = umax(a2,b2);
+ const vint4 d2 = umin(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+#else
+
+ __forceinline vint4 usort_ascending(const vint4& v)
+ {
+ const vint4 a0 = v-vint4(0x80000000);
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = min(a0,b0);
+ const vint4 d0 = max(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = min(a1,b1);
+ const vint4 d1 = max(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = min(a2,b2);
+ const vint4 d2 = max(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3+vint4(0x80000000);
+ }
+
+ __forceinline vint4 usort_descending(const vint4& v)
+ {
+ const vint4 a0 = v-vint4(0x80000000);
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = max(a0,b0);
+ const vint4 d0 = min(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = max(a1,b1);
+ const vint4 d1 = min(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = max(a2,b2);
+ const vint4 d2 = min(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3+vint4(0x80000000);
+ }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/common/simd/vint8_avx.h b/thirdparty/embree-aarch64/common/simd/vint8_avx.h
new file mode 100644
index 0000000000..25a771284d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vint8_avx.h
@@ -0,0 +1,464 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ struct { __m128i vl,vh; };
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint8& a) { v = a.v; }
+ __forceinline vint8& operator =(const vint8& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vint(const vint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vint(const vint4& a, const vint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vint(const __m128i& a, const __m128i& b) : vl(a), vh(b) {}
+
+ __forceinline explicit vint(const int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vint(int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vint(int a, int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d, int e, int f, int g, int vh) : v(_mm256_set_epi32(vh, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vint(OneTy) : v(_mm256_set_epi32(1,1,1,1,1,1,1,1)) {}
+ __forceinline vint(PosInfTy) : v(_mm256_set_epi32(pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm256_set_epi32(neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7)) {}
+ __forceinline vint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint8 load (const void* a) { return _mm256_castps_si256(_mm256_load_ps((float*)a)); }
+ static __forceinline vint8 loadu(const void* a) { return _mm256_castps_si256(_mm256_loadu_ps((float*)a)); }
+
+ static __forceinline vint8 load (const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (void* ptr, const vint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(void* ptr, const vint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+
+#if !defined(__aarch64__)
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+#else
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
+#endif
+
+ static __forceinline void store_nt(void* ptr, const vint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline vint8 load(const uint8_t* ptr) {
+ vint4 il = vint4::load(ptr+0);
+ vint4 ih = vint4::load(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 loadu(const uint8_t* ptr) {
+ vint4 il = vint4::loadu(ptr+0);
+ vint4 ih = vint4::loadu(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 load(const unsigned short* ptr) {
+ vint4 il = vint4::load(ptr+0);
+ vint4 ih = vint4::load(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 loadu(const unsigned short* ptr) {
+ vint4 il = vint4::loadu(ptr+0);
+ vint4 ih = vint4::loadu(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline void store(uint8_t* ptr, const vint8& i) {
+ vint4 il(i.vl);
+ vint4 ih(i.vh);
+ vint4::store(ptr + 0,il);
+ vint4::store(ptr + 4,ih);
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const int* ptr, const vint8& index) {
+ return vint8(
+ *(int*)(((int8_t*)ptr)+scale*index[0]),
+ *(int*)(((int8_t*)ptr)+scale*index[1]),
+ *(int*)(((int8_t*)ptr)+scale*index[2]),
+ *(int*)(((int8_t*)ptr)+scale*index[3]),
+ *(int*)(((int8_t*)ptr)+scale*index[4]),
+ *(int*)(((int8_t*)ptr)+scale*index[5]),
+ *(int*)(((int8_t*)ptr)+scale*index[6]),
+ *(int*)(((int8_t*)ptr)+scale*index[7]));
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const vboolf8& mask, const int* ptr, const vint8& index) {
+ vint8 r = zero;
+ if (likely(mask[0])) r[0] = *(int*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(int*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(int*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(int*)(((int8_t*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(int*)(((int8_t*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(int*)(((int8_t*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(int*)(((int8_t*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(int*)(((int8_t*)ptr)+scale*index[7]);
+ return r;
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
+ {
+ *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
+ {
+ if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+
+ static __forceinline vint8 broadcast64(const long long& a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 asBool(const vint8& a) { return _mm256_castsi256_ps(a); }
+
+ __forceinline vint8 operator +(const vint8& a) { return a; }
+ __forceinline vint8 operator -(const vint8& a) { return vint8(_mm_sub_epi32(_mm_setzero_si128(), a.vl), _mm_sub_epi32(_mm_setzero_si128(), a.vh)); }
+ __forceinline vint8 abs (const vint8& a) { return vint8(_mm_abs_epi32(a.vl), _mm_abs_epi32(a.vh)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 operator +(const vint8& a, const vint8& b) { return vint8(_mm_add_epi32(a.vl, b.vl), _mm_add_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator +(const vint8& a, int b) { return a + vint8(b); }
+ __forceinline vint8 operator +(int a, const vint8& b) { return vint8(a) + b; }
+
+ __forceinline vint8 operator -(const vint8& a, const vint8& b) { return vint8(_mm_sub_epi32(a.vl, b.vl), _mm_sub_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator -(const vint8& a, int b) { return a - vint8(b); }
+ __forceinline vint8 operator -(int a, const vint8& b) { return vint8(a) - b; }
+
+ __forceinline vint8 operator *(const vint8& a, const vint8& b) { return vint8(_mm_mullo_epi32(a.vl, b.vl), _mm_mullo_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator *(const vint8& a, int b) { return a * vint8(b); }
+ __forceinline vint8 operator *(int a, const vint8& b) { return vint8(a) * b; }
+
+ __forceinline vint8 operator &(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator &(const vint8& a, int b) { return a & vint8(b); }
+ __forceinline vint8 operator &(int a, const vint8& b) { return vint8(a) & b; }
+
+ __forceinline vint8 operator |(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_or_ps (_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator |(const vint8& a, int b) { return a | vint8(b); }
+ __forceinline vint8 operator |(int a, const vint8& b) { return vint8(a) | b; }
+
+ __forceinline vint8 operator ^(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator ^(const vint8& a, int b) { return a ^ vint8(b); }
+ __forceinline vint8 operator ^(int a, const vint8& b) { return vint8(a) ^ b; }
+
+ __forceinline vint8 operator <<(const vint8& a, int n) { return vint8(_mm_slli_epi32(a.vl, n), _mm_slli_epi32(a.vh, n)); }
+ __forceinline vint8 operator >>(const vint8& a, int n) { return vint8(_mm_srai_epi32(a.vl, n), _mm_srai_epi32(a.vh, n)); }
+
+ __forceinline vint8 sll (const vint8& a, int b) { return vint8(_mm_slli_epi32(a.vl, b), _mm_slli_epi32(a.vh, b)); }
+ __forceinline vint8 sra (const vint8& a, int b) { return vint8(_mm_srai_epi32(a.vl, b), _mm_srai_epi32(a.vh, b)); }
+ __forceinline vint8 srl (const vint8& a, int b) { return vint8(_mm_srli_epi32(a.vl, b), _mm_srli_epi32(a.vh, b)); }
+
+ __forceinline vint8 min(const vint8& a, const vint8& b) { return vint8(_mm_min_epi32(a.vl, b.vl), _mm_min_epi32(a.vh, b.vh)); }
+ __forceinline vint8 min(const vint8& a, int b) { return min(a,vint8(b)); }
+ __forceinline vint8 min(int a, const vint8& b) { return min(vint8(a),b); }
+
+ __forceinline vint8 max(const vint8& a, const vint8& b) { return vint8(_mm_max_epi32(a.vl, b.vl), _mm_max_epi32(a.vh, b.vh)); }
+ __forceinline vint8 max(const vint8& a, int b) { return max(a,vint8(b)); }
+ __forceinline vint8 max(int a, const vint8& b) { return max(vint8(a),b); }
+
+ __forceinline vint8 umin(const vint8& a, const vint8& b) { return vint8(_mm_min_epu32(a.vl, b.vl), _mm_min_epu32(a.vh, b.vh)); }
+ __forceinline vint8 umin(const vint8& a, int b) { return umin(a,vint8(b)); }
+ __forceinline vint8 umin(int a, const vint8& b) { return umin(vint8(a),b); }
+
+ __forceinline vint8 umax(const vint8& a, const vint8& b) { return vint8(_mm_max_epu32(a.vl, b.vl), _mm_max_epu32(a.vh, b.vh)); }
+ __forceinline vint8 umax(const vint8& a, int b) { return umax(a,vint8(b)); }
+ __forceinline vint8 umax(int a, const vint8& b) { return umax(vint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8& operator +=(vint8& a, const vint8& b) { return a = a + b; }
+ __forceinline vint8& operator +=(vint8& a, int b) { return a = a + b; }
+
+ __forceinline vint8& operator -=(vint8& a, const vint8& b) { return a = a - b; }
+ __forceinline vint8& operator -=(vint8& a, int b) { return a = a - b; }
+
+ __forceinline vint8& operator *=(vint8& a, const vint8& b) { return a = a * b; }
+ __forceinline vint8& operator *=(vint8& a, int b) { return a = a * b; }
+
+ __forceinline vint8& operator &=(vint8& a, const vint8& b) { return a = a & b; }
+ __forceinline vint8& operator &=(vint8& a, int b) { return a = a & b; }
+
+ __forceinline vint8& operator |=(vint8& a, const vint8& b) { return a = a | b; }
+ __forceinline vint8& operator |=(vint8& a, int b) { return a = a | b; }
+
+ __forceinline vint8& operator <<=(vint8& a, int b) { return a = a << b; }
+ __forceinline vint8& operator >>=(vint8& a, int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpeq_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpeq_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator ==(const vint8& a, int b) { return a == vint8(b); }
+ __forceinline vboolf8 operator ==(int a, const vint8& b) { return vint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return !(a == b); }
+ __forceinline vboolf8 operator !=(const vint8& a, int b) { return a != vint8(b); }
+ __forceinline vboolf8 operator !=(int a, const vint8& b) { return vint8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmplt_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmplt_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator < (const vint8& a, int b) { return a < vint8(b); }
+ __forceinline vboolf8 operator < (int a, const vint8& b) { return vint8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return !(a < b); }
+ __forceinline vboolf8 operator >=(const vint8& a, int b) { return a >= vint8(b); }
+ __forceinline vboolf8 operator >=(int a, const vint8& b) { return vint8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpgt_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpgt_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator > (const vint8& a, int b) { return a > vint8(b); }
+ __forceinline vboolf8 operator > (int a, const vint8& b) { return vint8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return !(a > b); }
+ __forceinline vboolf8 operator <=(const vint8& a, int b) { return a <= vint8(b); }
+ __forceinline vboolf8 operator <=(int a, const vint8& b) { return vint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vint8& a, const vint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vint8& a, const vint8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vint8& a, const vint8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vint8& a, const vint8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vint8& a, const vint8& b) { return a > b; }
+ __forceinline vboolf8 le(const vint8& a, const vint8& b) { return a <= b; }
+
+ __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a != b); }
+ __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a < b); }
+ __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a >= b); }
+ __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a > b); }
+ __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a <= b); }
+
+ __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+
+ __forceinline vint8 notand(const vboolf8& m, const vint8& f) {
+ return _mm256_castps_si256(_mm256_andnot_ps(m, _mm256_castsi256_ps(f)));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 unpacklo(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 unpackhi(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+
+ template<int i>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& a, const vint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& a, const vint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vint8 shuffle<0, 0, 2, 2>(const vint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<1, 1, 3, 3>(const vint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<0, 1, 0, 1>(const vint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vint8 broadcast(const int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+ template<int i> __forceinline vint8 insert4(const vint8& a, const vint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vint4 extract4(const vint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vint4 extract4<0>(const vint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 vreduce_min2(const vint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_min4(const vint8& v) { vint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_min (const vint8& v) { vint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_max2(const vint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_max4(const vint8& v) { vint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_max (const vint8& v) { vint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_add2(const vint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vint8 vreduce_add4(const vint8& v) { vint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vint8 vreduce_add (const vint8& v) { vint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline int reduce_min(const vint8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint8& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 usort_ascending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umin(a0,b0);
+ const vint8 d0 = umax(a0,b0);
+ const vint8 a1 = select(0x99 /* 0b10011001 */,c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umin(a1,b1);
+ const vint8 d1 = umax(a1,b1);
+ const vint8 a2 = select(0xc3 /* 0b11000011 */,c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umin(a2,b2);
+ const vint8 d2 = umax(a2,b2);
+ const vint8 a3 = select(0xa5 /* 0b10100101 */,c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umin(a3,b3);
+ const vint8 d3 = umax(a3,b3);
+ const vint8 a4 = select(0xf /* 0b00001111 */,c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umin(a4,b4);
+ const vint8 d4 = umax(a4,b4);
+ const vint8 a5 = select(0x33 /* 0b00110011 */,c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umin(a5,b5);
+ const vint8 d5 = umax(a5,b5);
+ const vint8 a6 = select(0x55 /* 0b01010101 */,c5,d5);
+ return a6;
+ }
+
+ __forceinline vint8 usort_descending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umax(a0,b0);
+ const vint8 d0 = umin(a0,b0);
+ const vint8 a1 = select(0x99 /* 0b10011001 */,c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umax(a1,b1);
+ const vint8 d1 = umin(a1,b1);
+ const vint8 a2 = select(0xc3 /* 0b11000011 */,c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umax(a2,b2);
+ const vint8 d2 = umin(a2,b2);
+ const vint8 a3 = select(0xa5 /* 0b10100101 */,c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umax(a3,b3);
+ const vint8 d3 = umin(a3,b3);
+ const vint8 a4 = select(0xf /* 0b00001111 */,c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umax(a4,b4);
+ const vint8 d4 = umin(a4,b4);
+ const vint8 a5 = select(0x33 /* 0b00110011 */,c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umax(a5,b5);
+ const vint8 d5 = umin(a5,b5);
+ const vint8 a6 = select(0x55 /* 0b01010101 */,c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vint8_avx2.h b/thirdparty/embree-aarch64/common/simd/vint8_avx2.h
new file mode 100644
index 0000000000..4937d972cf
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vint8_avx2.h
@@ -0,0 +1,512 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint8& a) { v = a.v; }
+ __forceinline vint8& operator =(const vint8& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vint(const vint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vint(const vint4& a, const vint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vint(const __m128i& a, const __m128i& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+
+ __forceinline explicit vint(const int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vint(int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vint(int a, int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d, int e, int f, int g, int h) : v(_mm256_set_epi32(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vint(const vboolf8& a) : v(_mm256_movm_epi32(a)) {}
+#else
+ __forceinline explicit vint(const vboolf8& a) : v(_mm256_castps_si256((__m256)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vint(PosInfTy) : v(_mm256_set1_epi32(pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm256_set1_epi32(neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7)) {}
+ __forceinline vint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint8 load(const uint8_t* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vint8 loadu(const uint8_t* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vint8 load(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+
+ static __forceinline vint8 load(const void* ptr) { return _mm256_load_si256((__m256i*)ptr); }
+ static __forceinline vint8 loadu(const void* ptr) { return _mm256_loadu_si256((__m256i*)ptr); }
+
+ static __forceinline void store (void* ptr, const vint8& v) { _mm256_store_si256((__m256i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint8& v) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(v)); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vint8 compact(const vboolf8& mask, vint8 &v) {
+ return _mm256_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vint8 compact(const vboolf8& mask, vint8 &a, const vint8& b) {
+ return _mm256_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vint8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_epi32 (_mm256_setzero_si256(),mask,ptr); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_epi32(_mm256_setzero_si256(),mask,ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& v) { _mm256_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& v) { _mm256_mask_storeu_epi32(ptr,mask,v); }
+#else
+ static __forceinline vint8 load (const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+#endif
+
+ static __forceinline vint8 load_nt(void* ptr) {
+ return _mm256_stream_load_si256((__m256i*)ptr);
+ }
+
+ static __forceinline void store_nt(void* ptr, const vint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline void store(uint8_t* ptr, const vint8& i)
+ {
+ for (size_t j=0; j<8; j++)
+ ptr[j] = i[j];
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const int *const ptr, const vint8& index) {
+ return _mm256_i32gather_epi32(ptr, index, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const vboolf8& mask, const int *const ptr, const vint8& index) {
+ vint8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#else
+ return _mm256_mask_i32gather_epi32(r, ptr, index, mask, scale);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
+#else
+ *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ static __forceinline vint8 broadcast64(const long long &a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 asBool(const vint8& a) { return _mm256_movepi32_mask(a); }
+#else
+ static __forceinline vboolf8 asBool(const vint8& a) { return _mm256_castsi256_ps(a); }
+#endif
+
+ __forceinline vint8 operator +(const vint8& a) { return a; }
+ __forceinline vint8 operator -(const vint8& a) { return _mm256_sub_epi32(_mm256_setzero_si256(), a); }
+ __forceinline vint8 abs (const vint8& a) { return _mm256_abs_epi32(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 operator +(const vint8& a, const vint8& b) { return _mm256_add_epi32(a, b); }
+ __forceinline vint8 operator +(const vint8& a, int b) { return a + vint8(b); }
+ __forceinline vint8 operator +(int a, const vint8& b) { return vint8(a) + b; }
+
+ __forceinline vint8 operator -(const vint8& a, const vint8& b) { return _mm256_sub_epi32(a, b); }
+ __forceinline vint8 operator -(const vint8& a, int b) { return a - vint8(b); }
+ __forceinline vint8 operator -(int a, const vint8& b) { return vint8(a) - b; }
+
+ __forceinline vint8 operator *(const vint8& a, const vint8& b) { return _mm256_mullo_epi32(a, b); }
+ __forceinline vint8 operator *(const vint8& a, int b) { return a * vint8(b); }
+ __forceinline vint8 operator *(int a, const vint8& b) { return vint8(a) * b; }
+
+ __forceinline vint8 operator &(const vint8& a, const vint8& b) { return _mm256_and_si256(a, b); }
+ __forceinline vint8 operator &(const vint8& a, int b) { return a & vint8(b); }
+ __forceinline vint8 operator &(int a, const vint8& b) { return vint8(a) & b; }
+
+ __forceinline vint8 operator |(const vint8& a, const vint8& b) { return _mm256_or_si256(a, b); }
+ __forceinline vint8 operator |(const vint8& a, int b) { return a | vint8(b); }
+ __forceinline vint8 operator |(int a, const vint8& b) { return vint8(a) | b; }
+
+ __forceinline vint8 operator ^(const vint8& a, const vint8& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vint8 operator ^(const vint8& a, int b) { return a ^ vint8(b); }
+ __forceinline vint8 operator ^(int a, const vint8& b) { return vint8(a) ^ b; }
+
+ __forceinline vint8 operator <<(const vint8& a, int n) { return _mm256_slli_epi32(a, n); }
+ __forceinline vint8 operator >>(const vint8& a, int n) { return _mm256_srai_epi32(a, n); }
+
+ __forceinline vint8 operator <<(const vint8& a, const vint8& n) { return _mm256_sllv_epi32(a, n); }
+ __forceinline vint8 operator >>(const vint8& a, const vint8& n) { return _mm256_srav_epi32(a, n); }
+
+ __forceinline vint8 sll(const vint8& a, int b) { return _mm256_slli_epi32(a, b); }
+ __forceinline vint8 sra(const vint8& a, int b) { return _mm256_srai_epi32(a, b); }
+ __forceinline vint8 srl(const vint8& a, int b) { return _mm256_srli_epi32(a, b); }
+
+ __forceinline vint8 sll(const vint8& a, const vint8& b) { return _mm256_sllv_epi32(a, b); }
+ __forceinline vint8 sra(const vint8& a, const vint8& b) { return _mm256_srav_epi32(a, b); }
+ __forceinline vint8 srl(const vint8& a, const vint8& b) { return _mm256_srlv_epi32(a, b); }
+
+ __forceinline vint8 min(const vint8& a, const vint8& b) { return _mm256_min_epi32(a, b); }
+ __forceinline vint8 min(const vint8& a, int b) { return min(a,vint8(b)); }
+ __forceinline vint8 min(int a, const vint8& b) { return min(vint8(a),b); }
+
+ __forceinline vint8 max(const vint8& a, const vint8& b) { return _mm256_max_epi32(a, b); }
+ __forceinline vint8 max(const vint8& a, int b) { return max(a,vint8(b)); }
+ __forceinline vint8 max(int a, const vint8& b) { return max(vint8(a),b); }
+
+ __forceinline vint8 umin(const vint8& a, const vint8& b) { return _mm256_min_epu32(a, b); }
+ __forceinline vint8 umax(const vint8& a, const vint8& b) { return _mm256_max_epu32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8& operator +=(vint8& a, const vint8& b) { return a = a + b; }
+ __forceinline vint8& operator +=(vint8& a, int b) { return a = a + b; }
+
+ __forceinline vint8& operator -=(vint8& a, const vint8& b) { return a = a - b; }
+ __forceinline vint8& operator -=(vint8& a, int b) { return a = a - b; }
+
+ __forceinline vint8& operator *=(vint8& a, const vint8& b) { return a = a * b; }
+ __forceinline vint8& operator *=(vint8& a, int b) { return a = a * b; }
+
+ __forceinline vint8& operator &=(vint8& a, const vint8& b) { return a = a & b; }
+ __forceinline vint8& operator &=(vint8& a, int b) { return a = a & b; }
+
+ __forceinline vint8& operator |=(vint8& a, const vint8& b) { return a = a | b; }
+ __forceinline vint8& operator |=(vint8& a, int b) { return a = a | b; }
+
+ __forceinline vint8& operator <<=(vint8& a, const int b) { return a = a << b; }
+ __forceinline vint8& operator >>=(vint8& a, const int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ static __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ static __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ static __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ static __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ static __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+
+ static __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_mask_blend_epi32(m, (__m256i)f, (__m256i)t);
+ }
+#else
+ static __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpeq_epi32(a, b)); }
+ static __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return !(a == b); }
+ static __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epi32(b, a)); }
+ static __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return !(a < b); }
+ static __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epi32(a, b)); }
+ static __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return !(a > b); }
+
+ static __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+#endif
+
+ template<int mask>
+ __forceinline vint8 select(const vint8& t, const vint8& f) {
+ return _mm256_blend_epi32(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vint8& a, int b) { return a == vint8(b); }
+ __forceinline vboolf8 operator ==(int a, const vint8& b) { return vint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vint8& a, int b) { return a != vint8(b); }
+ __forceinline vboolf8 operator !=(int a, const vint8& b) { return vint8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vint8& a, int b) { return a < vint8(b); }
+ __forceinline vboolf8 operator < (int a, const vint8& b) { return vint8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vint8& a, int b) { return a >= vint8(b); }
+ __forceinline vboolf8 operator >=(int a, const vint8& b) { return vint8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vint8& a, int b) { return a > vint8(b); }
+ __forceinline vboolf8 operator > (int a, const vint8& b) { return vint8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vint8& a, int b) { return a <= vint8(b); }
+ __forceinline vboolf8 operator <=(int a, const vint8& b) { return vint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vint8& a, const vint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vint8& a, const vint8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vint8& a, const vint8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vint8& a, const vint8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vint8& a, const vint8& b) { return a > b; }
+ __forceinline vboolf8 le(const vint8& a, const vint8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a == b); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a != b); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a < b); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a >= b); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a > b); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a <= b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 unpacklo(const vint8& a, const vint8& b) { return _mm256_unpacklo_epi32(a, b); }
+ __forceinline vint8 unpackhi(const vint8& a, const vint8& b) { return _mm256_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& a, const vint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& a, const vint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vint8 shuffle<0, 0, 2, 2>(const vint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<1, 1, 3, 3>(const vint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<0, 1, 0, 1>(const vint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vint8 broadcast(const int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+
+ template<int i> __forceinline vint8 insert4(const vint8& a, const vint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vint4 extract4(const vint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vint4 extract4<0>(const vint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+#if !defined(__aarch64__)
+
+__forceinline vint8 permute(const vint8& v, const __m256i& index) {
+ return _mm256_permutevar8x32_epi32(v, index);
+ }
+
+ __forceinline vint8 shuffle(const vint8& v, const __m256i& index) {
+ return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
+ }
+
+
+
+ template<int i>
+ static __forceinline vint8 align_shift_right(const vint8& a, const vint8& b) {
+#if defined(__AVX512VL__)
+ return _mm256_alignr_epi32(a, b, i);
+#else
+ return _mm256_alignr_epi8(a, b, 4*i);
+#endif
+ }
+
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 vreduce_min2(const vint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_min4(const vint8& v) { vint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_min (const vint8& v) { vint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_max2(const vint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_max4(const vint8& v) { vint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_max (const vint8& v) { vint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_add2(const vint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vint8 vreduce_add4(const vint8& v) { vint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vint8 vreduce_add (const vint8& v) { vint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline int reduce_min(const vint8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint8& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+
+ __forceinline vint8 assign(const vint4& a) { return _mm256_castsi128_si256(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 usort_ascending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umin(a0,b0);
+ const vint8 d0 = umax(a0,b0);
+ const vint8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umin(a1,b1);
+ const vint8 d1 = umax(a1,b1);
+ const vint8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umin(a2,b2);
+ const vint8 d2 = umax(a2,b2);
+ const vint8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umin(a3,b3);
+ const vint8 d3 = umax(a3,b3);
+ const vint8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umin(a4,b4);
+ const vint8 d4 = umax(a4,b4);
+ const vint8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umin(a5,b5);
+ const vint8 d5 = umax(a5,b5);
+ const vint8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ __forceinline vint8 usort_descending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umax(a0,b0);
+ const vint8 d0 = umin(a0,b0);
+ const vint8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umax(a1,b1);
+ const vint8 d1 = umin(a1,b1);
+ const vint8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umax(a2,b2);
+ const vint8 d2 = umin(a2,b2);
+ const vint8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umax(a3,b3);
+ const vint8 d3 = umin(a3,b3);
+ const vint8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umax(a4,b4);
+ const vint8 d4 = umin(a4,b4);
+ const vint8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umax(a5,b5);
+ const vint8 d5 = umin(a5,b5);
+ const vint8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vllong4_avx2.h b/thirdparty/embree-aarch64/common/simd/vllong4_avx2.h
new file mode 100644
index 0000000000..de3ebc16a7
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vllong4_avx2.h
@@ -0,0 +1,358 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 4-wide AVX2 64-bit long long type */
+ template<>
+ struct vllong<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ long long i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong() {}
+ __forceinline vllong(const vllong4& t) { v = t.v; }
+ __forceinline vllong4& operator =(const vllong4& f) { v = f.v; return *this; }
+
+ __forceinline vllong(const __m256i& t) { v = t; }
+ __forceinline operator __m256i() const { return v; }
+ __forceinline operator __m256d() const { return _mm256_castsi256_pd(v); }
+
+
+ __forceinline vllong(long long i) {
+ v = _mm256_set1_epi64x(i);
+ }
+
+ __forceinline vllong(long long a, long long b, long long c, long long d) {
+ v = _mm256_set_epi64x(d,c,b,a);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vllong(OneTy) : v(_mm256_set1_epi64x(1)) {}
+ __forceinline vllong(StepTy) : v(_mm256_set_epi64x(3,2,1,0)) {}
+ __forceinline vllong(ReverseStepTy) : v(_mm256_set_epi64x(0,1,2,3)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vllong4& a) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(a));
+ }
+
+ static __forceinline vllong4 loadu(const void* addr)
+ {
+ return _mm256_loadu_si256((__m256i*)addr);
+ }
+
+ static __forceinline vllong4 load(const vllong4* addr) {
+ return _mm256_load_si256((__m256i*)addr);
+ }
+
+ static __forceinline vllong4 load(const long long* addr) {
+ return _mm256_load_si256((__m256i*)addr);
+ }
+
+ static __forceinline void store(void* ptr, const vllong4& v) {
+ _mm256_store_si256((__m256i*)ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vllong4& v) {
+ _mm256_storeu_si256((__m256i*)ptr,v);
+ }
+
+ static __forceinline void storeu(const vboold4& mask, long long* ptr, const vllong4& f) {
+#if defined(__AVX512VL__)
+ _mm256_mask_storeu_epi64(ptr,mask,f);
+#else
+ _mm256_maskstore_pd((double*)ptr,mask,_mm256_castsi256_pd(f));
+#endif
+ }
+
+ static __forceinline void store(const vboold4& mask, void* ptr, const vllong4& f) {
+#if defined(__AVX512VL__)
+ _mm256_mask_store_epi64(ptr,mask,f);
+#else
+ _mm256_maskstore_pd((double*)ptr,mask,_mm256_castsi256_pd(f));
+#endif
+ }
+
+ static __forceinline vllong4 broadcast64bit(size_t v) {
+ return _mm256_set1_epi64x(v);
+ }
+
+ static __forceinline size_t extract64bit(const vllong4& v)
+ {
+ return _mm_cvtsi128_si64(_mm256_castsi256_si128(v));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline long long& operator [](size_t index) { assert(index < 4); return i[index]; }
+ __forceinline const long long& operator [](size_t index) const { assert(index < 4); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4 select(const vboold4& m, const vllong4& t, const vllong4& f) {
+ #if defined(__AVX512VL__)
+ return _mm256_mask_blend_epi64(m, f, t);
+ #else
+ return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(f), _mm256_castsi256_pd(t), m));
+ #endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 asBool(const vllong4& a) { return _mm256_movepi64_mask(a); }
+#else
+ __forceinline vboold4 asBool(const vllong4& a) { return _mm256_castsi256_pd(a); }
+#endif
+
+ __forceinline vllong4 operator +(const vllong4& a) { return a; }
+ __forceinline vllong4 operator -(const vllong4& a) { return _mm256_sub_epi64(_mm256_setzero_si256(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4 operator +(const vllong4& a, const vllong4& b) { return _mm256_add_epi64(a, b); }
+ __forceinline vllong4 operator +(const vllong4& a, long long b) { return a + vllong4(b); }
+ __forceinline vllong4 operator +(long long a, const vllong4& b) { return vllong4(a) + b; }
+
+ __forceinline vllong4 operator -(const vllong4& a, const vllong4& b) { return _mm256_sub_epi64(a, b); }
+ __forceinline vllong4 operator -(const vllong4& a, long long b) { return a - vllong4(b); }
+ __forceinline vllong4 operator -(long long a, const vllong4& b) { return vllong4(a) - b; }
+
+ /* only low 32bit part */
+ __forceinline vllong4 operator *(const vllong4& a, const vllong4& b) { return _mm256_mul_epi32(a, b); }
+ __forceinline vllong4 operator *(const vllong4& a, long long b) { return a * vllong4(b); }
+ __forceinline vllong4 operator *(long long a, const vllong4& b) { return vllong4(a) * b; }
+
+ __forceinline vllong4 operator &(const vllong4& a, const vllong4& b) { return _mm256_and_si256(a, b); }
+ __forceinline vllong4 operator &(const vllong4& a, long long b) { return a & vllong4(b); }
+ __forceinline vllong4 operator &(long long a, const vllong4& b) { return vllong4(a) & b; }
+
+ __forceinline vllong4 operator |(const vllong4& a, const vllong4& b) { return _mm256_or_si256(a, b); }
+ __forceinline vllong4 operator |(const vllong4& a, long long b) { return a | vllong4(b); }
+ __forceinline vllong4 operator |(long long a, const vllong4& b) { return vllong4(a) | b; }
+
+ __forceinline vllong4 operator ^(const vllong4& a, const vllong4& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vllong4 operator ^(const vllong4& a, long long b) { return a ^ vllong4(b); }
+ __forceinline vllong4 operator ^(long long a, const vllong4& b) { return vllong4(a) ^ b; }
+
+ __forceinline vllong4 operator <<(const vllong4& a, long long n) { return _mm256_slli_epi64(a, (int)n); }
+ //__forceinline vllong4 operator >>(const vllong4& a, long long n) { return _mm256_srai_epi64(a, n); }
+
+ __forceinline vllong4 operator <<(const vllong4& a, const vllong4& n) { return _mm256_sllv_epi64(a, n); }
+ //__forceinline vllong4 operator >>(const vllong4& a, const vllong4& n) { return _mm256_srav_epi64(a, n); }
+ //__forceinline vllong4 sra(const vllong4& a, long long b) { return _mm256_srai_epi64(a, b); }
+
+ __forceinline vllong4 srl(const vllong4& a, long long b) { return _mm256_srli_epi64(a, (int)b); }
+
+ //__forceinline vllong4 min(const vllong4& a, const vllong4& b) { return _mm256_min_epi64(a, b); }
+ //__forceinline vllong4 min(const vllong4& a, long long b) { return min(a,vllong4(b)); }
+ //__forceinline vllong4 min(long long a, const vllong4& b) { return min(vllong4(a),b); }
+
+ //__forceinline vllong4 max(const vllong4& a, const vllong4& b) { return _mm256_max_epi64(a, b); }
+ //__forceinline vllong4 max(const vllong4& a, long long b) { return max(a,vllong4(b)); }
+ //__forceinline vllong4 max(long long a, const vllong4& b) { return max(vllong4(a),b); }
+
+#if defined(__AVX512VL__)
+ __forceinline vllong4 mask_and(const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return _mm256_mask_and_epi64(c,m,a,b); }
+ __forceinline vllong4 mask_or (const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return _mm256_mask_or_epi64(c,m,a,b); }
+#else
+ __forceinline vllong4 mask_and(const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return select(m, a & b, c); }
+ __forceinline vllong4 mask_or (const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return select(m, a | b, c); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4& operator +=(vllong4& a, const vllong4& b) { return a = a + b; }
+ __forceinline vllong4& operator +=(vllong4& a, long long b) { return a = a + b; }
+
+ __forceinline vllong4& operator -=(vllong4& a, const vllong4& b) { return a = a - b; }
+ __forceinline vllong4& operator -=(vllong4& a, long long b) { return a = a - b; }
+
+ __forceinline vllong4& operator *=(vllong4& a, const vllong4& b) { return a = a * b; }
+ __forceinline vllong4& operator *=(vllong4& a, long long b) { return a = a * b; }
+
+ __forceinline vllong4& operator &=(vllong4& a, const vllong4& b) { return a = a & b; }
+ __forceinline vllong4& operator &=(vllong4& a, long long b) { return a = a & b; }
+
+ __forceinline vllong4& operator |=(vllong4& a, const vllong4& b) { return a = a | b; }
+ __forceinline vllong4& operator |=(vllong4& a, long long b) { return a = a | b; }
+
+ __forceinline vllong4& operator <<=(vllong4& a, long long b) { return a = a << b; }
+ //__forceinline vllong4& operator >>=(vllong4& a, long long b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 operator ==(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold4 operator !=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold4 operator < (const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold4 operator >=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold4 operator > (const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold4 operator <=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 operator ==(const vllong4& a, const vllong4& b) { return _mm256_cmpeq_epi64(a,b); }
+ __forceinline vboold4 operator !=(const vllong4& a, const vllong4& b) { return !(a == b); }
+ __forceinline vboold4 operator > (const vllong4& a, const vllong4& b) { return _mm256_cmpgt_epi64(a,b); }
+ __forceinline vboold4 operator < (const vllong4& a, const vllong4& b) { return _mm256_cmpgt_epi64(b,a); }
+ __forceinline vboold4 operator >=(const vllong4& a, const vllong4& b) { return !(a < b); }
+ __forceinline vboold4 operator <=(const vllong4& a, const vllong4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboold4 operator ==(const vllong4& a, long long b) { return a == vllong4(b); }
+ __forceinline vboold4 operator ==(long long a, const vllong4& b) { return vllong4(a) == b; }
+
+ __forceinline vboold4 operator !=(const vllong4& a, long long b) { return a != vllong4(b); }
+ __forceinline vboold4 operator !=(long long a, const vllong4& b) { return vllong4(a) != b; }
+
+ __forceinline vboold4 operator > (const vllong4& a, long long b) { return a > vllong4(b); }
+ __forceinline vboold4 operator > (long long a, const vllong4& b) { return vllong4(a) > b; }
+
+ __forceinline vboold4 operator < (const vllong4& a, long long b) { return a < vllong4(b); }
+ __forceinline vboold4 operator < (long long a, const vllong4& b) { return vllong4(a) < b; }
+
+ __forceinline vboold4 operator >=(const vllong4& a, long long b) { return a >= vllong4(b); }
+ __forceinline vboold4 operator >=(long long a, const vllong4& b) { return vllong4(a) >= b; }
+
+ __forceinline vboold4 operator <=(const vllong4& a, long long b) { return a <= vllong4(b); }
+ __forceinline vboold4 operator <=(long long a, const vllong4& b) { return vllong4(a) <= b; }
+
+ __forceinline vboold4 eq(const vllong4& a, const vllong4& b) { return a == b; }
+ __forceinline vboold4 ne(const vllong4& a, const vllong4& b) { return a != b; }
+ __forceinline vboold4 lt(const vllong4& a, const vllong4& b) { return a < b; }
+ __forceinline vboold4 ge(const vllong4& a, const vllong4& b) { return a >= b; }
+ __forceinline vboold4 gt(const vllong4& a, const vllong4& b) { return a > b; }
+ __forceinline vboold4 le(const vllong4& a, const vllong4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 eq(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 ne(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 lt(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 ge(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 gt(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 eq(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a == b); }
+ __forceinline vboold4 ne(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a != b); }
+ __forceinline vboold4 lt(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a < b); }
+ __forceinline vboold4 ge(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a >= b); }
+ __forceinline vboold4 gt(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a > b); }
+ __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a <= b); }
+#endif
+
+ __forceinline void xchg(const vboold4& m, vllong4& a, vllong4& b) {
+ const vllong4 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboold4 test(const vllong4& a, const vllong4& b) {
+#if defined(__AVX512VL__)
+ return _mm256_test_epi64_mask(a,b);
+#else
+ return _mm256_testz_si256(a,b);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vllong4 shuffle(const vllong4& v) {
+ return _mm256_castpd_si256(_mm256_permute_pd(_mm256_castsi256_pd(v), (i1 << 3) | (i0 << 2) | (i1 << 1) | i0));
+ }
+
+ template<int i>
+ __forceinline vllong4 shuffle(const vllong4& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1>
+ __forceinline vllong4 shuffle2(const vllong4& v) {
+ return _mm256_castpd_si256(_mm256_permute2f128_pd(_mm256_castsi256_pd(v), _mm256_castsi256_pd(v), (i1 << 4) | i0));
+ }
+
+ __forceinline long long toScalar(const vllong4& v) {
+ return _mm_cvtsi128_si64(_mm256_castsi256_si128(v));
+ }
+
+#if defined(__AVX512VL__)
+ __forceinline vllong4 permute(const vllong4& a, const __m256i& index) {
+ // workaround for GCC 7.x
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+ return _mm256_permutex2var_epi64(a,index,a);
+#else
+ return _mm256_permutexvar_epi64(index,a);
+#endif
+ }
+
+ __forceinline vllong4 permutex2var(const vllong4& index, const vllong4& a, const vllong4& b) {
+ return _mm256_permutex2var_epi64(a,index,b);
+ }
+
+#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ __forceinline vllong4 vreduce_and2(const vllong4& x) { return x & shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_and (const vllong4& y) { const vllong4 x = vreduce_and2(y); return x & shuffle2<1,0>(x); }
+
+ __forceinline vllong4 vreduce_or2(const vllong4& x) { return x | shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_or (const vllong4& y) { const vllong4 x = vreduce_or2(y); return x | shuffle2<1,0>(x); }
+
+ __forceinline vllong4 vreduce_add2(const vllong4& x) { return x + shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_add (const vllong4& y) { const vllong4 x = vreduce_add2(y); return x + shuffle2<1,0>(x); }
+
+ __forceinline long long reduce_add(const vllong4& a) { return toScalar(vreduce_add(a)); }
+ __forceinline long long reduce_or (const vllong4& a) { return toScalar(vreduce_or(a)); }
+ __forceinline long long reduce_and(const vllong4& a) { return toScalar(vreduce_and(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vllong4& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<4; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vllong8_avx512.h b/thirdparty/embree-aarch64/common/simd/vllong8_avx512.h
new file mode 100644
index 0000000000..76dddd8991
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vllong8_avx512.h
@@ -0,0 +1,381 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX-512 64-bit long long type */
+ template<>
+ struct vllong<8>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboold8 Bool;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ long long i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong() {}
+ __forceinline vllong(const vllong8& t) { v = t.v; }
+ __forceinline vllong8& operator =(const vllong8& f) { v = f.v; return *this; }
+
+ __forceinline vllong(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vllong(long long i) {
+ v = _mm512_set1_epi64(i);
+ }
+
+ __forceinline vllong(long long a, long long b, long long c, long long d) {
+ v = _mm512_set4_epi64(d,c,b,a);
+ }
+
+ __forceinline vllong(long long a0, long long a1, long long a2, long long a3,
+ long long a4, long long a5, long long a6, long long a7)
+ {
+ v = _mm512_set_epi64(a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline vllong(const vllong<4>& i) {
+ v = _mm512_broadcast_i64x4(i);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vllong(OneTy) : v(_mm512_set1_epi64(1)) {}
+ __forceinline vllong(StepTy) : v(_mm512_set_epi64(7,6,5,4,3,2,1,0)) {}
+ __forceinline vllong(ReverseStepTy) : v(_mm512_setr_epi64(7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vllong8& a) {
+ _mm512_stream_si512((__m512i*)ptr,a);
+ }
+
+ static __forceinline vllong8 loadu(const void* addr) {
+ return _mm512_loadu_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const vllong8* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const long long* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const uint8_t* ptr) {
+ return _mm512_cvtepu8_epi64(*(__m128i*)ptr);
+ }
+
+ static __forceinline void store(void* ptr, const vllong8& v) {
+ _mm512_store_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vllong8& v) {
+ _mm512_storeu_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(const vboold8& mask, long long* ptr, const vllong8& f) {
+ _mm512_mask_storeu_epi64(ptr,mask,f);
+ }
+
+ static __forceinline void store(const vboold8& mask, void* addr, const vllong8& v2) {
+ _mm512_mask_store_epi64(addr,mask,v2);
+ }
+
+ /* pass by value to avoid compiler generating inefficient code */
+ static __forceinline void storeu_compact(const vboold8 mask, void* addr, const vllong8& reg) {
+ _mm512_mask_compressstoreu_epi64(addr,mask,reg);
+ }
+
+ static __forceinline vllong8 compact64bit(const vboold8& mask, vllong8& v) {
+ return _mm512_mask_compress_epi64(v,mask,v);
+ }
+
+ static __forceinline vllong8 compact64bit(const vboold8& mask, vllong8& dest, const vllong8& source) {
+ return _mm512_mask_compress_epi64(dest,mask,source);
+ }
+
+ static __forceinline vllong8 compact(const vboold8& mask, vllong8& v) {
+ return _mm512_mask_compress_epi64(v,mask,v);
+ }
+
+ static __forceinline vllong8 compact(const vboold8& mask, const vllong8& a, vllong8& b) {
+ return _mm512_mask_compress_epi64(a,mask,b);
+ }
+
+ static __forceinline vllong8 expand(const vboold8& mask, const vllong8& a, vllong8& b) {
+ return _mm512_mask_expand_epi64(b,mask,a);
+ }
+
+ static __forceinline vllong8 broadcast64bit(size_t v) {
+ return _mm512_set1_epi64(v);
+ }
+
+ static __forceinline size_t extract64bit(const vllong8& v)
+ {
+ return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline long long& operator [](size_t index) { assert(index < 8); return i[index]; }
+ __forceinline const long long& operator [](size_t index) const { assert(index < 8); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 asBool(const vllong8& a) { return _mm512_movepi64_mask(a); }
+
+ __forceinline vllong8 operator +(const vllong8& a) { return a; }
+ __forceinline vllong8 operator -(const vllong8& a) { return _mm512_sub_epi64(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 operator +(const vllong8& a, const vllong8& b) { return _mm512_add_epi64(a, b); }
+ __forceinline vllong8 operator +(const vllong8& a, long long b) { return a + vllong8(b); }
+ __forceinline vllong8 operator +(long long a, const vllong8& b) { return vllong8(a) + b; }
+
+ __forceinline vllong8 operator -(const vllong8& a, const vllong8& b) { return _mm512_sub_epi64(a, b); }
+ __forceinline vllong8 operator -(const vllong8& a, long long b) { return a - vllong8(b); }
+ __forceinline vllong8 operator -(long long a, const vllong8& b) { return vllong8(a) - b; }
+
+ __forceinline vllong8 operator *(const vllong8& a, const vllong8& b) { return _mm512_mullo_epi64(a, b); }
+ __forceinline vllong8 operator *(const vllong8& a, long long b) { return a * vllong8(b); }
+ __forceinline vllong8 operator *(long long a, const vllong8& b) { return vllong8(a) * b; }
+
+ __forceinline vllong8 operator &(const vllong8& a, const vllong8& b) { return _mm512_and_epi64(a, b); }
+ __forceinline vllong8 operator &(const vllong8& a, long long b) { return a & vllong8(b); }
+ __forceinline vllong8 operator &(long long a, const vllong8& b) { return vllong8(a) & b; }
+
+ __forceinline vllong8 operator |(const vllong8& a, const vllong8& b) { return _mm512_or_epi64(a, b); }
+ __forceinline vllong8 operator |(const vllong8& a, long long b) { return a | vllong8(b); }
+ __forceinline vllong8 operator |(long long a, const vllong8& b) { return vllong8(a) | b; }
+
+ __forceinline vllong8 operator ^(const vllong8& a, const vllong8& b) { return _mm512_xor_epi64(a, b); }
+ __forceinline vllong8 operator ^(const vllong8& a, long long b) { return a ^ vllong8(b); }
+ __forceinline vllong8 operator ^(long long a, const vllong8& b) { return vllong8(a) ^ b; }
+
+ __forceinline vllong8 operator <<(const vllong8& a, long long n) { return _mm512_slli_epi64(a, n); }
+ __forceinline vllong8 operator >>(const vllong8& a, long long n) { return _mm512_srai_epi64(a, n); }
+
+ __forceinline vllong8 operator <<(const vllong8& a, const vllong8& n) { return _mm512_sllv_epi64(a, n); }
+ __forceinline vllong8 operator >>(const vllong8& a, const vllong8& n) { return _mm512_srav_epi64(a, n); }
+
+ __forceinline vllong8 sll (const vllong8& a, long long b) { return _mm512_slli_epi64(a, b); }
+ __forceinline vllong8 sra (const vllong8& a, long long b) { return _mm512_srai_epi64(a, b); }
+ __forceinline vllong8 srl (const vllong8& a, long long b) { return _mm512_srli_epi64(a, b); }
+
+ __forceinline vllong8 min(const vllong8& a, const vllong8& b) { return _mm512_min_epi64(a, b); }
+ __forceinline vllong8 min(const vllong8& a, long long b) { return min(a,vllong8(b)); }
+ __forceinline vllong8 min(long long a, const vllong8& b) { return min(vllong8(a),b); }
+
+ __forceinline vllong8 max(const vllong8& a, const vllong8& b) { return _mm512_max_epi64(a, b); }
+ __forceinline vllong8 max(const vllong8& a, long long b) { return max(a,vllong8(b)); }
+ __forceinline vllong8 max(long long a, const vllong8& b) { return max(vllong8(a),b); }
+
+ __forceinline vllong8 mask_add(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_add_epi64(c,m,a,b); }
+ __forceinline vllong8 mask_sub(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_sub_epi64(c,m,a,b); }
+
+ __forceinline vllong8 mask_and(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_and_epi64(c,m,a,b); }
+ __forceinline vllong8 mask_or (const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_or_epi64(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8& operator +=(vllong8& a, const vllong8& b) { return a = a + b; }
+ __forceinline vllong8& operator +=(vllong8& a, long long b) { return a = a + b; }
+
+ __forceinline vllong8& operator -=(vllong8& a, const vllong8& b) { return a = a - b; }
+ __forceinline vllong8& operator -=(vllong8& a, long long b) { return a = a - b; }
+
+ __forceinline vllong8& operator *=(vllong8& a, const vllong8& b) { return a = a * b; }
+ __forceinline vllong8& operator *=(vllong8& a, long long b) { return a = a * b; }
+
+ __forceinline vllong8& operator &=(vllong8& a, const vllong8& b) { return a = a & b; }
+ __forceinline vllong8& operator &=(vllong8& a, long long b) { return a = a & b; }
+
+ __forceinline vllong8& operator |=(vllong8& a, const vllong8& b) { return a = a | b; }
+ __forceinline vllong8& operator |=(vllong8& a, long long b) { return a = a | b; }
+
+ __forceinline vllong8& operator <<=(vllong8& a, long long b) { return a = a << b; }
+ __forceinline vllong8& operator >>=(vllong8& a, long long b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator ==(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 operator ==(const vllong8& a, long long b) { return a == vllong8(b); }
+ __forceinline vboold8 operator ==(long long a, const vllong8& b) { return vllong8(a) == b; }
+
+ __forceinline vboold8 operator !=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 operator !=(const vllong8& a, long long b) { return a != vllong8(b); }
+ __forceinline vboold8 operator !=(long long a, const vllong8& b) { return vllong8(a) != b; }
+
+ __forceinline vboold8 operator < (const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 operator < (const vllong8& a, long long b) { return a < vllong8(b); }
+ __forceinline vboold8 operator < (long long a, const vllong8& b) { return vllong8(a) < b; }
+
+ __forceinline vboold8 operator >=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 operator >=(const vllong8& a, long long b) { return a >= vllong8(b); }
+ __forceinline vboold8 operator >=(long long a, const vllong8& b) { return vllong8(a) >= b; }
+
+ __forceinline vboold8 operator > (const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 operator > (const vllong8& a, long long b) { return a > vllong8(b); }
+ __forceinline vboold8 operator > (long long a, const vllong8& b) { return vllong8(a) > b; }
+
+ __forceinline vboold8 operator <=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboold8 operator <=(const vllong8& a, long long b) { return a <= vllong8(b); }
+ __forceinline vboold8 operator <=(long long a, const vllong8& b) { return vllong8(a) <= b; }
+
+ __forceinline vboold8 eq(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboold8 eq(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vllong8 select(const vboold8& m, const vllong8& t, const vllong8& f) {
+ return _mm512_mask_or_epi64(f,m,t,t);
+ }
+
+ __forceinline void xchg(const vboold8& m, vllong8& a, vllong8& b) {
+ const vllong8 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboold8 test(const vboold8& m, const vllong8& a, const vllong8& b) {
+ return _mm512_mask_test_epi64_mask(m,a,b);
+ }
+
+ __forceinline vboold8 test(const vllong8& a, const vllong8& b) {
+ return _mm512_test_epi64_mask(a,b);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return _mm512_castpd_si512(_mm512_permute_pd(_mm512_castsi512_pd(v), (i1 << 7) | (i0 << 6) | (i1 << 5) | (i0 << 4) | (i1 << 3) | (i0 << 2) | (i1 << 1) | i0));
+ }
+
+ template<int i>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return _mm512_permutex_epi64(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vllong8 shuffle4(const vllong8& v) {
+ return _mm512_shuffle_i64x2(v, v, _MM_SHUFFLE(i1*2+1, i1*2, i0*2+1, i0*2));
+ }
+
+ template<int i>
+ __forceinline vllong8 shuffle4(const vllong8& v) {
+ return shuffle4<i, i>(v);
+ }
+
+ template<int i>
+ __forceinline vllong8 align_shift_right(const vllong8& a, const vllong8& b) {
+ return _mm512_alignr_epi64(a, b, i);
+ };
+
+ __forceinline long long toScalar(const vllong8& v) {
+ return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
+ }
+
+ __forceinline vllong8 zeroExtend32Bit(const __m512i& a) {
+ return _mm512_cvtepu32_epi64(_mm512_castsi512_si256(a));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 vreduce_min2(vllong8 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vllong8 vreduce_min4(vllong8 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vllong8 vreduce_min (vllong8 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0>(x)); }
+
+ __forceinline vllong8 vreduce_max2(vllong8 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vllong8 vreduce_max4(vllong8 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vllong8 vreduce_max (vllong8 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0>(x)); }
+
+ __forceinline vllong8 vreduce_and2(vllong8 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_and4(vllong8 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_and (vllong8 x) { x = vreduce_and4(x); return x & shuffle4<1,0>(x); }
+
+ __forceinline vllong8 vreduce_or2(vllong8 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_or4(vllong8 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_or (vllong8 x) { x = vreduce_or4(x); return x | shuffle4<1,0>(x); }
+
+ __forceinline vllong8 vreduce_add2(vllong8 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_add4(vllong8 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_add (vllong8 x) { x = vreduce_add4(x); return x + shuffle4<1,0>(x); }
+
+ __forceinline long long reduce_min(const vllong8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline long long reduce_max(const vllong8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline long long reduce_and(const vllong8& v) { return toScalar(vreduce_and(v)); }
+ __forceinline long long reduce_or (const vllong8& v) { return toScalar(vreduce_or (v)); }
+ __forceinline long long reduce_add(const vllong8& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 permute(const vllong8& v, const vllong8& index) {
+ return _mm512_permutexvar_epi64(index,v);
+ }
+
+ __forceinline vllong8 reverse(const vllong8& a) {
+ return permute(a,vllong8(reverse_step));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vllong8& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<8; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vuint16_avx512.h b/thirdparty/embree-aarch64/common/simd/vuint16_avx512.h
new file mode 100644
index 0000000000..39752611bb
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vuint16_avx512.h
@@ -0,0 +1,443 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 16-wide AVX-512 unsigned integer type */
+ template<>
+ struct vuint<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vuint16 UInt;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ unsigned int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint16& t) { v = t.v; }
+ __forceinline vuint16& operator =(const vuint16& f) { v = f.v; return *this; }
+
+ __forceinline vuint(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vuint(unsigned int i) {
+ v = _mm512_set1_epi32(i);
+ }
+
+ __forceinline vuint(const vuint4& i) {
+ v = _mm512_broadcast_i32x4(i);
+ }
+
+ __forceinline vuint(const vuint8& i) {
+ v = _mm512_castps_si512(_mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castsi256_pd(i))));
+ }
+
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) {
+ v = _mm512_set4_epi32(d,c,b,a);
+ }
+
+ __forceinline vuint(unsigned int a0 , unsigned int a1 , unsigned int a2 , unsigned int a3,
+ unsigned int a4 , unsigned int a5 , unsigned int a6 , unsigned int a7,
+ unsigned int a8 , unsigned int a9 , unsigned int a10, unsigned int a11,
+ unsigned int a12, unsigned int a13, unsigned int a14, unsigned int a15)
+ {
+ v = _mm512_set_epi32(a15,a14,a13,a12,a11,a10,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline explicit vuint(const __m512& f) {
+ v = _mm512_cvtps_epu32(f);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vuint(OneTy) : v(_mm512_set1_epi32(1)) {}
+ __forceinline vuint(StepTy) : v(_mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vuint(ReverseStepTy) : v(_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vuint16& a) {
+ _mm512_stream_si512((__m512i*)ptr,a);
+ }
+
+ static __forceinline vuint16 loadu(const void* addr)
+ {
+ return _mm512_loadu_si512(addr);
+ }
+
+ static __forceinline vuint16 loadu(const uint8_t* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+ static __forceinline vuint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
+
+ static __forceinline vuint16 load(const vuint16* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vuint16 load(const unsigned int* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vuint16 load(unsigned short* ptr) { return _mm512_cvtepu16_epi32(*(__m256i*)ptr); }
+
+
+ static __forceinline void store(void* ptr, const vuint16& v) {
+ _mm512_store_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vuint16& v) {
+ _mm512_storeu_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vuint16& f) {
+ _mm512_mask_storeu_epi32(ptr,mask,f);
+ }
+
+ static __forceinline void store(const vboolf16& mask, void* addr, const vuint16& v2) {
+ _mm512_mask_store_epi32(addr,mask,v2);
+ }
+
+ /* pass by value to avoid compiler generating inefficient code */
+ static __forceinline void storeu_compact(const vboolf16 mask, void* addr, const vuint16 reg) {
+ _mm512_mask_compressstoreu_epi32(addr,mask,reg);
+ }
+
+ static __forceinline void storeu_compact_single(const vboolf16 mask, void* addr, vuint16 reg) {
+ //_mm512_mask_compressstoreu_epi32(addr,mask,reg);
+ *(float*)addr = mm512_cvtss_f32(_mm512_mask_compress_ps(_mm512_castsi512_ps(reg),mask,_mm512_castsi512_ps(reg)));
+ }
+
+ static __forceinline vuint16 compact64bit(const vboolf16& mask, vuint16& v) {
+ return _mm512_mask_compress_epi64(v,mask,v);
+ }
+
+ static __forceinline vuint16 compact(const vboolf16& mask, vuint16& v) {
+ return _mm512_mask_compress_epi32(v,mask,v);
+ }
+
+ static __forceinline vuint16 compact(const vboolf16& mask, const vuint16& a, vuint16& b) {
+ return _mm512_mask_compress_epi32(a,mask,b);
+ }
+
+ static __forceinline vuint16 expand(const vboolf16& mask, const vuint16& a, vuint16& b) {
+ return _mm512_mask_expand_epi32(b,mask,a);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const unsigned int* ptr, const vint16& index) {
+ return _mm512_i32gather_epi32(index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const vboolf16& mask, const unsigned int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(_mm512_undefined_epi32(),mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const vboolf16& mask, vuint16& dest, const unsigned int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(dest,mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(unsigned int* ptr, const vint16& index, const vuint16& v) {
+ _mm512_i32scatter_epi32((int*)ptr,index,v,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, unsigned int* ptr, const vint16& index, const vuint16& v) {
+ _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
+ }
+
+ static __forceinline vuint16 broadcast64bit(size_t v) {
+ return _mm512_set1_epi64(v);
+ }
+
+ static __forceinline size_t extract64bit(const vuint16& v)
+ {
+ return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 16); return i[index]; }
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 16); return i[index]; }
+
+ __forceinline unsigned int uint (size_t index) const { assert(index < 16); return ((unsigned int*)i)[index]; }
+ __forceinline size_t& uint64_t(size_t index) const { assert(index < 8); return ((size_t*)i)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 asBool(const vuint16& a) { return _mm512_movepi32_mask(a); }
+
+ __forceinline vuint16 operator +(const vuint16& a) { return a; }
+ __forceinline vuint16 operator -(const vuint16& a) { return _mm512_sub_epi32(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 operator +(const vuint16& a, const vuint16& b) { return _mm512_add_epi32(a, b); }
+ __forceinline vuint16 operator +(const vuint16& a, unsigned int b) { return a + vuint16(b); }
+ __forceinline vuint16 operator +(unsigned int a, const vuint16& b) { return vuint16(a) + b; }
+
+ __forceinline vuint16 operator -(const vuint16& a, const vuint16& b) { return _mm512_sub_epi32(a, b); }
+ __forceinline vuint16 operator -(const vuint16& a, unsigned int b) { return a - vuint16(b); }
+ __forceinline vuint16 operator -(unsigned int a, const vuint16& b) { return vuint16(a) - b; }
+
+ __forceinline vuint16 operator *(const vuint16& a, const vuint16& b) { return _mm512_mul_epu32(a, b); }
+ __forceinline vuint16 operator *(const vuint16& a, unsigned int b) { return a * vuint16(b); }
+ __forceinline vuint16 operator *(unsigned int a, const vuint16& b) { return vuint16(a) * b; }
+
+ __forceinline vuint16 operator &(const vuint16& a, const vuint16& b) { return _mm512_and_epi32(a, b); }
+ __forceinline vuint16 operator &(const vuint16& a, unsigned int b) { return a & vuint16(b); }
+ __forceinline vuint16 operator &(unsigned int a, const vuint16& b) { return vuint16(a) & b; }
+
+ __forceinline vuint16 operator |(const vuint16& a, const vuint16& b) { return _mm512_or_epi32(a, b); }
+ __forceinline vuint16 operator |(const vuint16& a, unsigned int b) { return a | vuint16(b); }
+ __forceinline vuint16 operator |(unsigned int a, const vuint16& b) { return vuint16(a) | b; }
+
+ __forceinline vuint16 operator ^(const vuint16& a, const vuint16& b) { return _mm512_xor_epi32(a, b); }
+ __forceinline vuint16 operator ^(const vuint16& a, unsigned int b) { return a ^ vuint16(b); }
+ __forceinline vuint16 operator ^(unsigned int a, const vuint16& b) { return vuint16(a) ^ b; }
+
+ __forceinline vuint16 operator <<(const vuint16& a, unsigned int n) { return _mm512_slli_epi32(a, n); }
+ __forceinline vuint16 operator >>(const vuint16& a, unsigned int n) { return _mm512_srli_epi32(a, n); }
+
+ __forceinline vuint16 operator <<(const vuint16& a, const vuint16& n) { return _mm512_sllv_epi32(a, n); }
+ __forceinline vuint16 operator >>(const vuint16& a, const vuint16& n) { return _mm512_srlv_epi32(a, n); }
+
+ __forceinline vuint16 sll (const vuint16& a, unsigned int b) { return _mm512_slli_epi32(a, b); }
+ __forceinline vuint16 sra (const vuint16& a, unsigned int b) { return _mm512_srai_epi32(a, b); }
+ __forceinline vuint16 srl (const vuint16& a, unsigned int b) { return _mm512_srli_epi32(a, b); }
+
+ __forceinline vuint16 min(const vuint16& a, const vuint16& b) { return _mm512_min_epu32(a, b); }
+ __forceinline vuint16 min(const vuint16& a, unsigned int b) { return min(a,vuint16(b)); }
+ __forceinline vuint16 min(unsigned int a, const vuint16& b) { return min(vuint16(a),b); }
+
+ __forceinline vuint16 max(const vuint16& a, const vuint16& b) { return _mm512_max_epu32(a, b); }
+ __forceinline vuint16 max(const vuint16& a, unsigned int b) { return max(a,vuint16(b)); }
+ __forceinline vuint16 max(unsigned int a, const vuint16& b) { return max(vuint16(a),b); }
+
+ __forceinline vuint16 mask_add(const vboolf16& mask, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_add_epi32(c,mask,a,b); }
+ __forceinline vuint16 mask_sub(const vboolf16& mask, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_sub_epi32(c,mask,a,b); }
+
+ __forceinline vuint16 mask_and(const vboolf16& m, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_and_epi32(c,m,a,b); }
+ __forceinline vuint16 mask_or (const vboolf16& m, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_or_epi32(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16& operator +=(vuint16& a, const vuint16& b) { return a = a + b; }
+ __forceinline vuint16& operator +=(vuint16& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint16& operator -=(vuint16& a, const vuint16& b) { return a = a - b; }
+ __forceinline vuint16& operator -=(vuint16& a, unsigned int b) { return a = a - b; }
+
+ __forceinline vuint16& operator *=(vuint16& a, const vuint16& b) { return a = a * b; }
+ __forceinline vuint16& operator *=(vuint16& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint16& operator &=(vuint16& a, const vuint16& b) { return a = a & b; }
+ __forceinline vuint16& operator &=(vuint16& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint16& operator |=(vuint16& a, const vuint16& b) { return a = a | b; }
+ __forceinline vuint16& operator |=(vuint16& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint16& operator <<=(vuint16& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint16& operator >>=(vuint16& a, unsigned int b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vuint16& a, unsigned int b) { return a == vuint16(b); }
+ __forceinline vboolf16 operator ==(unsigned int a, const vuint16& b) { return vuint16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vuint16& a, unsigned int b) { return a != vuint16(b); }
+ __forceinline vboolf16 operator !=(unsigned int a, const vuint16& b) { return vuint16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vuint16& a, unsigned int b) { return a < vuint16(b); }
+ __forceinline vboolf16 operator < (unsigned int a, const vuint16& b) { return vuint16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vuint16& a, unsigned int b) { return a >= vuint16(b); }
+ __forceinline vboolf16 operator >=(unsigned int a, const vuint16& b) { return vuint16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vuint16& a, unsigned int b) { return a > vuint16(b); }
+ __forceinline vboolf16 operator > (unsigned int a, const vuint16& b) { return vuint16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vuint16& a, unsigned int b) { return a <= vuint16(b); }
+ __forceinline vboolf16 operator <=(unsigned int a, const vuint16& b) { return vuint16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboolf16 eq(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LE); }
+
+
+ __forceinline vuint16 select(const vboolf16& m, const vuint16& t, const vuint16& f) {
+ return _mm512_mask_or_epi32(f,m,t,t);
+ }
+
+ __forceinline void xchg(const vboolf16& m, vuint16& a, vuint16& b) {
+ const vuint16 c = a; a = select(m,b,a); b = select(m,c,b);
+ }
+
+ __forceinline vboolf16 test(const vboolf16& m, const vuint16& a, const vuint16& b) {
+ return _mm512_mask_test_epi32_mask(m,a,b);
+ }
+
+ __forceinline vboolf16 test(const vuint16& a, const vuint16& b) {
+ return _mm512_test_epi32_mask(a,b);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i>
+ __forceinline vuint16 shuffle(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint16 shuffle(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vuint16 shuffle4(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v) ,_MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint16 shuffle4(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vuint16 align_shift_right(const vuint16& a, const vuint16& b) {
+ return _mm512_alignr_epi32(a, b, i);
+ };
+
+ __forceinline unsigned int toScalar(const vuint16& v) {
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 vreduce_min2(vuint16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_min4(vuint16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vuint16 vreduce_min8(vuint16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_min (vuint16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vuint16 vreduce_max2(vuint16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_max4(vuint16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vuint16 vreduce_max8(vuint16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_max (vuint16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vuint16 vreduce_and2(vuint16 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_and4(vuint16 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_and8(vuint16 x) { x = vreduce_and4(x); return x & shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_and (vuint16 x) { x = vreduce_and8(x); return x & shuffle4<2,3,0,1>(x); }
+
+ __forceinline vuint16 vreduce_or2(vuint16 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_or4(vuint16 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_or8(vuint16 x) { x = vreduce_or4(x); return x | shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_or (vuint16 x) { x = vreduce_or8(x); return x | shuffle4<2,3,0,1>(x); }
+
+ __forceinline vuint16 vreduce_add2(vuint16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_add4(vuint16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_add8(vuint16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_add (vuint16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline unsigned int reduce_min(const vuint16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline unsigned int reduce_max(const vuint16& v) { return toScalar(vreduce_max(v)); }
+ __forceinline unsigned int reduce_and(const vuint16& v) { return toScalar(vreduce_and(v)); }
+ __forceinline unsigned int reduce_or (const vuint16& v) { return toScalar(vreduce_or (v)); }
+ __forceinline unsigned int reduce_add(const vuint16& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 permute(vuint16 v, vuint16 index) {
+ return _mm512_permutexvar_epi32(index,v);
+ }
+
+ __forceinline vuint16 reverse(const vuint16& a) {
+ return permute(a,vuint16(reverse_step));
+ }
+
+ __forceinline vuint16 prefix_sum(const vuint16& a)
+ {
+ const vuint16 z(zero);
+ vuint16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vuint16 reverse_prefix_sum(const vuint16& a)
+ {
+ const vuint16 z(zero);
+ vuint16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vuint4_sse2.h b/thirdparty/embree-aarch64/common/simd/vuint4_sse2.h
new file mode 100644
index 0000000000..a3f393ebf2
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vuint4_sse2.h
@@ -0,0 +1,499 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+namespace embree
+{
+ /* 4-wide SSE integer type */
+ template<>
+ struct vuint<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vuint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128i v; unsigned int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint4& a) { v = a.v; }
+ __forceinline vuint4& operator =(const vuint4& a) { v = a.v; return *this; }
+
+ __forceinline vuint(const __m128i a) : v(a) {}
+ __forceinline operator const __m128i&() const { return v; }
+ __forceinline operator __m128i&() { return v; }
+
+
+ __forceinline vuint(unsigned int a) : v(_mm_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm_set_epi32(d, c, b, a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(__m128 a) : v(_mm_cvtps_epu32(a)) {}
+#endif
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(const vboolf4& a) : v(_mm_movm_epi32(a)) {}
+#else
+ __forceinline explicit vuint(const vboolf4& a) : v(_mm_castps_si128((__m128)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm_setzero_si128()) {}
+ __forceinline vuint(OneTy) : v(_mm_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm_set1_epi32(unsigned(pos_inf))) {}
+ __forceinline vuint(StepTy) : v(_mm_set_epi32(3, 2, 1, 0)) {}
+ __forceinline vuint(TrueTy) { v = _mm_cmpeq_epi32(v,v); }
+ __forceinline vuint(UndefinedTy) : v(_mm_castps_si128(_mm_undefined_ps())) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint4 load (const void* a) { return _mm_load_si128((__m128i*)a); }
+ static __forceinline vuint4 loadu(const void* a) { return _mm_loadu_si128((__m128i*)a); }
+
+ static __forceinline void store (void* ptr, const vuint4& v) { _mm_store_si128((__m128i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vuint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
+
+#if defined(__AVX512VL__)
+ static __forceinline vuint4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_epi32 (_mm_setzero_si128(),mask,ptr); }
+ static __forceinline vuint4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_epi32(_mm_setzero_si128(),mask,ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& v) { _mm_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& v) { _mm_mask_storeu_epi32(ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vuint4 load (const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+ static __forceinline vuint4 loadu(const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+#else
+ static __forceinline vuint4 load (const vbool4& mask, const void* a) { return _mm_and_si128(_mm_load_si128 ((__m128i*)a),mask); }
+ static __forceinline vuint4 loadu(const vbool4& mask, const void* a) { return _mm_and_si128(_mm_loadu_si128((__m128i*)a),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& i) { store (ptr,select(mask,i,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
+#endif
+
+#if defined(__aarch64__)
+ static __forceinline vuint4 load(const uint8_t* ptr) {
+ return _mm_load4epu8_epi32(((__m128i*)ptr));
+ }
+ static __forceinline vuint4 loadu(const uint8_t* ptr) {
+ return _mm_load4epu8_epi32(((__m128i*)ptr));
+ }
+#elif defined(__SSE4_1__)
+ static __forceinline vuint4 load(const uint8_t* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+ static __forceinline vuint4 loadu(const uint8_t* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+#endif
+
+ static __forceinline vuint4 load(const unsigned short* ptr) {
+#if defined(__aarch64__)
+ return _mm_load4epu16_epi32(((__m128i*)ptr));
+#elif defined (__SSE4_1__)
+ return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
+#else
+ return vuint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+#endif
+ }
+
+ static __forceinline void store_uint8(uint8_t* ptr, const vuint4& v) {
+#if defined(__aarch64__)
+ uint32x4_t x = uint32x4_t(v.v);
+ uint16x4_t y = vqmovn_u32(x);
+ uint8x8_t z = vqmovn_u16(vcombine_u16(y, y));
+ vst1_lane_u32((uint32_t *)ptr, uint32x2_t(z), 0);
+#elif defined(__SSE4_1__)
+ __m128i x = v;
+ x = _mm_packus_epi32(x, x);
+ x = _mm_packus_epi16(x, x);
+ *(unsigned*)ptr = _mm_cvtsi128_si32(x);
+#else
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (uint8_t)v[i];
+#endif
+ }
+
+ static __forceinline void store_uint8(unsigned short* ptr, const vuint4& v) {
+#if defined(__aarch64__)
+ uint32x4_t x = (uint32x4_t)v.v;
+ uint16x4_t y = vqmovn_u32(x);
+ vst1_u16(ptr, y);
+#else
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (unsigned short)v[i];
+#endif
+ }
+
+ static __forceinline vuint4 load_nt(void* ptr) {
+#if (defined(__aarch64__)) || defined(__SSE4_1__)
+ return _mm_stream_load_si128((__m128i*)ptr);
+#else
+ return _mm_load_si128((__m128i*)ptr);
+#endif
+ }
+
+ static __forceinline void store_nt(void* ptr, const vuint4& v) {
+#if !defined(__aarch64__) && defined(__SSE4_1__)
+ _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v));
+#else
+ _mm_store_si128((__m128i*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint4 gather(const unsigned int* ptr, const vint4& index) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_i32gather_epi32((const int*)ptr, index, scale);
+#else
+ return vuint4(
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[0]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[1]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[2]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint4 gather(const vboolf4& mask, const unsigned int* ptr, const vint4& index) {
+ vuint4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#elif defined(__AVX2__) && !defined(__aarch64__)
+ return _mm_mask_i32gather_epi32(r, (const int*)ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(unsigned int*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(unsigned int*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(unsigned int*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(unsigned int*)(((int8_t*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 4); return i[index]; }
+
+ friend __forceinline vuint4 select(const vboolf4& m, const vuint4& t, const vuint4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
+#elif defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f));
+#endif
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 asBool(const vuint4& a) { return _mm_movepi32_mask(a); }
+#else
+ __forceinline vboolf4 asBool(const vuint4& a) { return _mm_castsi128_ps(a); }
+#endif
+
+ __forceinline vuint4 operator +(const vuint4& a) { return a; }
+ __forceinline vuint4 operator -(const vuint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4 operator +(const vuint4& a, const vuint4& b) { return _mm_add_epi32(a, b); }
+ __forceinline vuint4 operator +(const vuint4& a, unsigned int b) { return a + vuint4(b); }
+ __forceinline vuint4 operator +(unsigned int a, const vuint4& b) { return vuint4(a) + b; }
+
+ __forceinline vuint4 operator -(const vuint4& a, const vuint4& b) { return _mm_sub_epi32(a, b); }
+ __forceinline vuint4 operator -(const vuint4& a, unsigned int b) { return a - vuint4(b); }
+ __forceinline vuint4 operator -(unsigned int a, const vuint4& b) { return vuint4(a) - b; }
+
+//#if defined(__SSE4_1__)
+// __forceinline vuint4 operator *(const vuint4& a, const vuint4& b) { return _mm_mullo_epu32(a, b); }
+//#else
+// __forceinline vuint4 operator *(const vuint4& a, const vuint4& b) { return vuint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
+//#endif
+// __forceinline vuint4 operator *(const vuint4& a, unsigned int b) { return a * vuint4(b); }
+// __forceinline vuint4 operator *(unsigned int a, const vuint4& b) { return vuint4(a) * b; }
+
+ __forceinline vuint4 operator &(const vuint4& a, const vuint4& b) { return _mm_and_si128(a, b); }
+ __forceinline vuint4 operator &(const vuint4& a, unsigned int b) { return a & vuint4(b); }
+ __forceinline vuint4 operator &(unsigned int a, const vuint4& b) { return vuint4(a) & b; }
+
+ __forceinline vuint4 operator |(const vuint4& a, const vuint4& b) { return _mm_or_si128(a, b); }
+ __forceinline vuint4 operator |(const vuint4& a, unsigned int b) { return a | vuint4(b); }
+ __forceinline vuint4 operator |(unsigned int a, const vuint4& b) { return vuint4(a) | b; }
+
+ __forceinline vuint4 operator ^(const vuint4& a, const vuint4& b) { return _mm_xor_si128(a, b); }
+ __forceinline vuint4 operator ^(const vuint4& a, unsigned int b) { return a ^ vuint4(b); }
+ __forceinline vuint4 operator ^(unsigned int a, const vuint4& b) { return vuint4(a) ^ b; }
+
+ __forceinline vuint4 operator <<(const vuint4& a, unsigned int n) { return _mm_slli_epi32(a, n); }
+ __forceinline vuint4 operator >>(const vuint4& a, unsigned int n) { return _mm_srli_epi32(a, n); }
+
+ __forceinline vuint4 sll (const vuint4& a, unsigned int b) { return _mm_slli_epi32(a, b); }
+ __forceinline vuint4 sra (const vuint4& a, unsigned int b) { return _mm_srai_epi32(a, b); }
+ __forceinline vuint4 srl (const vuint4& a, unsigned int b) { return _mm_srli_epi32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4& operator +=(vuint4& a, const vuint4& b) { return a = a + b; }
+ __forceinline vuint4& operator +=(vuint4& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint4& operator -=(vuint4& a, const vuint4& b) { return a = a - b; }
+ __forceinline vuint4& operator -=(vuint4& a, unsigned int b) { return a = a - b; }
+
+//#if defined(__SSE4_1__)
+// __forceinline vuint4& operator *=(vuint4& a, const vuint4& b) { return a = a * b; }
+// __forceinline vuint4& operator *=(vuint4& a, unsigned int b) { return a = a * b; }
+//#endif
+
+ __forceinline vuint4& operator &=(vuint4& a, const vuint4& b) { return a = a & b; }
+ __forceinline vuint4& operator &=(vuint4& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint4& operator |=(vuint4& a, const vuint4& b) { return a = a | b; }
+ __forceinline vuint4& operator |=(vuint4& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint4& operator <<=(vuint4& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint4& operator >>=(vuint4& a, unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ //__forceinline vboolf4 operator < (const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ //__forceinline vboolf4 operator >=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ //__forceinline vboolf4 operator > (const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ //__forceinline vboolf4 operator <=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+ __forceinline vboolf4 operator !=(const vuint4& a, const vuint4& b) { return !(a == b); }
+ //__forceinline vboolf4 operator < (const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmplt_epu32(a, b)); }
+ //__forceinline vboolf4 operator >=(const vuint4& a, const vuint4& b) { return !(a < b); }
+ //__forceinline vboolf4 operator > (const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmpgt_epu32(a, b)); }
+ //__forceinline vboolf4 operator <=(const vuint4& a, const vuint4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vuint4& a, unsigned int b) { return a == vuint4(b); }
+ __forceinline vboolf4 operator ==(unsigned int a, const vuint4& b) { return vuint4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vuint4& a, unsigned int b) { return a != vuint4(b); }
+ __forceinline vboolf4 operator !=(unsigned int a, const vuint4& b) { return vuint4(a) != b; }
+
+ //__forceinline vboolf4 operator < (const vuint4& a, unsigned int b) { return a < vuint4(b); }
+ //__forceinline vboolf4 operator < (unsigned int a, const vuint4& b) { return vuint4(a) < b; }
+
+ //__forceinline vboolf4 operator >=(const vuint4& a, unsigned int b) { return a >= vuint4(b); }
+ //__forceinline vboolf4 operator >=(unsigned int a, const vuint4& b) { return vuint4(a) >= b; }
+
+ //__forceinline vboolf4 operator > (const vuint4& a, unsigned int b) { return a > vuint4(b); }
+ //__forceinline vboolf4 operator > (unsigned int a, const vuint4& b) { return vuint4(a) > b; }
+
+ //__forceinline vboolf4 operator <=(const vuint4& a, unsigned int b) { return a <= vuint4(b); }
+ //__forceinline vboolf4 operator <=(unsigned int a, const vuint4& b) { return vuint4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vuint4& a, const vuint4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vuint4& a, const vuint4& b) { return a != b; }
+ //__forceinline vboolf4 lt(const vuint4& a, const vuint4& b) { return a < b; }
+ //__forceinline vboolf4 ge(const vuint4& a, const vuint4& b) { return a >= b; }
+ //__forceinline vboolf4 gt(const vuint4& a, const vuint4& b) { return a > b; }
+ //__forceinline vboolf4 le(const vuint4& a, const vuint4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_NE); }
+ //__forceinline vboolf4 lt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); }
+ //__forceinline vboolf4 ge(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GE); }
+ //__forceinline vboolf4 gt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GT); }
+ //__forceinline vboolf4 le(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a != b); }
+ //__forceinline vboolf4 lt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a < b); }
+ //__forceinline vboolf4 ge(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a >= b); }
+ //__forceinline vboolf4 gt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a > b); }
+ //__forceinline vboolf4 le(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vuint4 select(const vuint4& t, const vuint4& f) {
+#if defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+/*#if defined(__SSE4_1__)
+ __forceinline vuint4 min(const vuint4& a, const vuint4& b) { return _mm_min_epu32(a, b); }
+ __forceinline vuint4 max(const vuint4& a, const vuint4& b) { return _mm_max_epu32(a, b); }
+
+#else
+ __forceinline vuint4 min(const vuint4& a, const vuint4& b) { return select(a < b,a,b); }
+ __forceinline vuint4 max(const vuint4& a, const vuint4& b) { return select(a < b,b,a); }
+#endif
+
+ __forceinline vuint4 min(const vuint4& a, unsigned int b) { return min(a,vuint4(b)); }
+ __forceinline vuint4 min(unsigned int a, const vuint4& b) { return min(vuint4(a),b); }
+ __forceinline vuint4 max(const vuint4& a, unsigned int b) { return max(a,vuint4(b)); }
+ __forceinline vuint4 max(unsigned int a, const vuint4& b) { return max(vuint4(a),b); }*/
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4 unpacklo(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+ __forceinline vuint4 unpackhi(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+
+#if defined(__aarch64__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& v) {
+ return vreinterpretq_s32_u8(vqtbl1q_u8( (uint8x16_t)v.v, _MN_SHUFFLE(i0, i1, i2, i3)));
+ }
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
+ return vreinterpretq_s32_u8(vqtbl2q_u8( (uint8x16x2_t){(uint8x16_t)a.v, (uint8x16_t)b.v}, _MF_SHUFFLE(i0, i1, i2, i3)));
+ }
+#else
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& v) {
+ return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
+ return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+#endif
+#if defined(__SSE3__)
+ template<> __forceinline vuint4 shuffle<0, 0, 2, 2>(const vuint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vuint4 shuffle<1, 1, 3, 3>(const vuint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vuint4 shuffle<0, 1, 0, 1>(const vuint4& v) { return _mm_castpd_si128(_mm_movedup_pd (_mm_castsi128_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vuint4 shuffle(const vuint4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+#if defined(__aarch64__)
+ template<int src> __forceinline unsigned int extract(const vuint4& b);
+ template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b);
+#elif defined(__SSE4_1__)
+ template<int src> __forceinline unsigned int extract(const vuint4& b) { return _mm_extract_epi32(b, src); }
+ template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { return _mm_insert_epi32(a, b, dst); }
+#else
+ template<int src> __forceinline unsigned int extract(const vuint4& b) { return b[src&3]; }
+ template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { vuint4 c = a; c[dst&3] = b; return c; }
+#endif
+
+#if defined(__aarch64__)
+ template<> __forceinline unsigned int extract<0>(const vuint4& b) {
+ return b[0];
+ }
+ template<> __forceinline unsigned int extract<1>(const vuint4& b) {
+ return b[1];
+ }
+ template<> __forceinline unsigned int extract<2>(const vuint4& b) {
+ return b[2];
+ }
+ template<> __forceinline unsigned int extract<3>(const vuint4& b) {
+ return b[3];
+ }
+
+ template<> __forceinline vuint4 insert<0>(const vuint4& a, unsigned b){
+ vuint4 c = a;
+ c[0] = b;
+ return c;
+ }
+ template<> __forceinline vuint4 insert<1>(const vuint4& a, unsigned b){
+ vuint4 c = a;
+ c[1] = b;
+ return c;
+ }
+ template<> __forceinline vuint4 insert<2>(const vuint4& a, unsigned b){
+ vuint4 c = a;
+ c[2] = b;
+ return c;
+ }
+ template<> __forceinline vuint4 insert<3>(const vuint4& a, unsigned b){
+ vuint4 c = a;
+ c[3] = b;
+ return c;
+ }
+
+ __forceinline unsigned int toScalar(const vuint4& v) {
+ return v[0];
+ }
+#else
+ template<> __forceinline unsigned int extract<0>(const vuint4& b) { return _mm_cvtsi128_si32(b); }
+
+ __forceinline unsigned int toScalar(const vuint4& v) { return _mm_cvtsi128_si32(v); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+#if defined(__SSE4_1__)
+
+ __forceinline vuint4 vreduce_min(const vuint4& v) { vuint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vuint4 vreduce_max(const vuint4& v) { vuint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vuint4 vreduce_add(const vuint4& v) { vuint4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+
+ __forceinline unsigned int reduce_min(const vuint4& v) { return toScalar(vreduce_min(v)); }
+ __forceinline unsigned int reduce_max(const vuint4& v) { return toScalar(vreduce_max(v)); }
+ __forceinline unsigned int reduce_add(const vuint4& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vuint4& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vuint4& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf4& valid, const vuint4& v) { const vuint4 a = select(valid,v,vuint4(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf4& valid, const vuint4& v) { const vuint4 a = select(valid,v,vuint4(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+#else
+
+ __forceinline unsigned int reduce_min(const vuint4& v) { return min(v[0],v[1],v[2],v[3]); }
+ __forceinline unsigned int reduce_max(const vuint4& v) { return max(v[0],v[1],v[2],v[3]); }
+ __forceinline unsigned int reduce_add(const vuint4& v) { return v[0]+v[1]+v[2]+v[3]; }
+
+#endif
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/common/simd/vuint8_avx.h b/thirdparty/embree-aarch64/common/simd/vuint8_avx.h
new file mode 100644
index 0000000000..d4e86ae92d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vuint8_avx.h
@@ -0,0 +1,379 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vuint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vuint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ struct { __m128i vl,vh; };
+ unsigned int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint8& a) { v = a.v; }
+ __forceinline vuint8& operator =(const vuint8& a) { v = a.v; return *this; }
+
+ __forceinline vuint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vuint(const vuint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vuint(const vuint4& a, const vuint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vuint(const __m128i& a, const __m128i& b) : vl(a), vh(b) {}
+
+ __forceinline explicit vuint(const unsigned int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vuint(unsigned int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f, unsigned int g, unsigned int vh) : v(_mm256_set_epi32(vh, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vuint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vuint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm256_set1_epi32(0xFFFFFFFF)) {}
+ __forceinline vuint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vuint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint8 load (const void* a) { return _mm256_castps_si256(_mm256_load_ps((float*)a)); }
+ static __forceinline vuint8 loadu(const void* a) { return _mm256_castps_si256(_mm256_loadu_ps((float*)a)); }
+
+ static __forceinline vuint8 load (const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (void* ptr, const vuint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(void* ptr, const vuint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+
+#if !defined(__aarch64__)
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+#else
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask.v,_mm256_castsi256_ps(f)); }
+#endif
+ static __forceinline void store_nt(void* ptr, const vuint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline vuint8 load(const uint8_t* ptr) {
+ vuint4 il = vuint4::load(ptr+0);
+ vuint4 ih = vuint4::load(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 loadu(const uint8_t* ptr) {
+ vuint4 il = vuint4::loadu(ptr+0);
+ vuint4 ih = vuint4::loadu(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 load(const unsigned short* ptr) {
+ vuint4 il = vuint4::load(ptr+0);
+ vuint4 ih = vuint4::load(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 loadu(const unsigned short* ptr) {
+ vuint4 il = vuint4::loadu(ptr+0);
+ vuint4 ih = vuint4::loadu(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline void store(uint8_t* ptr, const vuint8& i) {
+ vuint4 il(i.vl);
+ vuint4 ih(i.vh);
+ vuint4::store(ptr + 0,il);
+ vuint4::store(ptr + 4,ih);
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vuint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const unsigned int* ptr, const vint8& index) {
+ return vuint8(
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[0]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[1]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[2]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[3]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[4]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[5]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[6]),
+ *(unsigned int*)(((int8_t*)ptr)+scale*index[7]));
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const vboolf8& mask, const unsigned int* ptr, const vint8& index) {
+ vuint8 r = zero;
+ if (likely(mask[0])) r[0] = *(unsigned int*)(((int8_t*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(unsigned int*)(((int8_t*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(unsigned int*)(((int8_t*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(unsigned int*)(((int8_t*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(unsigned int*)(((int8_t*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(unsigned int*)(((int8_t*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(unsigned int*)(((int8_t*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(unsigned int*)(((int8_t*)ptr)+scale*index[7]);
+ return r;
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vuint8& v)
+ {
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ *(unsigned int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vuint8& v)
+ {
+ if (likely(mask[0])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+
+ static __forceinline vuint8 broadcast64(const long long& a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_castsi256_ps(a); }
+
+ __forceinline vuint8 operator +(const vuint8& a) { return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 operator +(const vuint8& a, const vuint8& b) { return vuint8(_mm_add_epi32(a.vl, b.vl), _mm_add_epi32(a.vh, b.vh)); }
+ __forceinline vuint8 operator +(const vuint8& a, unsigned int b) { return a + vuint8(b); }
+ __forceinline vuint8 operator +(unsigned int a, const vuint8& b) { return vuint8(a) + b; }
+
+ __forceinline vuint8 operator -(const vuint8& a, const vuint8& b) { return vuint8(_mm_sub_epi32(a.vl, b.vl), _mm_sub_epi32(a.vh, b.vh)); }
+ __forceinline vuint8 operator -(const vuint8& a, unsigned int b) { return a - vuint8(b); }
+ __forceinline vuint8 operator -(unsigned int a, const vuint8& b) { return vuint8(a) - b; }
+
+ //__forceinline vuint8 operator *(const vuint8& a, const vuint8& b) { return vuint8(_mm_mullo_epu32(a.vl, b.vl), _mm_mullo_epu32(a.vh, b.vh)); }
+ //__forceinline vuint8 operator *(const vuint8& a, unsigned int b) { return a * vuint8(b); }
+ //__forceinline vuint8 operator *(unsigned int a, const vuint8& b) { return vuint8(a) * b; }
+
+ __forceinline vuint8 operator &(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator &(const vuint8& a, unsigned int b) { return a & vuint8(b); }
+ __forceinline vuint8 operator &(unsigned int a, const vuint8& b) { return vuint8(a) & b; }
+
+ __forceinline vuint8 operator |(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_or_ps (_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator |(const vuint8& a, unsigned int b) { return a | vuint8(b); }
+ __forceinline vuint8 operator |(unsigned int a, const vuint8& b) { return vuint8(a) | b; }
+
+ __forceinline vuint8 operator ^(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator ^(const vuint8& a, unsigned int b) { return a ^ vuint8(b); }
+ __forceinline vuint8 operator ^(unsigned int a, const vuint8& b) { return vuint8(a) ^ b; }
+
+ __forceinline vuint8 operator <<(const vuint8& a, unsigned int n) { return vuint8(_mm_slli_epi32(a.vl, n), _mm_slli_epi32(a.vh, n)); }
+ __forceinline vuint8 operator >>(const vuint8& a, unsigned int n) { return vuint8(_mm_srai_epi32(a.vl, n), _mm_srli_epi32(a.vh, n)); }
+
+ __forceinline vuint8 sll (const vuint8& a, unsigned int b) { return vuint8(_mm_slli_epi32(a.vl, b), _mm_slli_epi32(a.vh, b)); }
+ __forceinline vuint8 sra (const vuint8& a, unsigned int b) { return vuint8(_mm_srai_epi32(a.vl, b), _mm_srai_epi32(a.vh, b)); }
+ __forceinline vuint8 srl (const vuint8& a, unsigned int b) { return vuint8(_mm_srli_epi32(a.vl, b), _mm_srli_epi32(a.vh, b)); }
+
+ __forceinline vuint8 min(const vuint8& a, const vuint8& b) { return vuint8(_mm_min_epu32(a.vl, b.vl), _mm_min_epu32(a.vh, b.vh)); }
+ __forceinline vuint8 min(const vuint8& a, unsigned int b) { return min(a,vuint8(b)); }
+ __forceinline vuint8 min(unsigned int a, const vuint8& b) { return min(vuint8(a),b); }
+
+ __forceinline vuint8 max(const vuint8& a, const vuint8& b) { return vuint8(_mm_max_epu32(a.vl, b.vl), _mm_max_epu32(a.vh, b.vh)); }
+ __forceinline vuint8 max(const vuint8& a, unsigned int b) { return max(a,vuint8(b)); }
+ __forceinline vuint8 max(unsigned int a, const vuint8& b) { return max(vuint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8& operator +=(vuint8& a, const vuint8& b) { return a = a + b; }
+ __forceinline vuint8& operator +=(vuint8& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint8& operator -=(vuint8& a, const vuint8& b) { return a = a - b; }
+ __forceinline vuint8& operator -=(vuint8& a, unsigned int b) { return a = a - b; }
+
+ //__forceinline vuint8& operator *=(vuint8& a, const vuint8& b) { return a = a * b; }
+ //__forceinline vuint8& operator *=(vuint8& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint8& operator &=(vuint8& a, const vuint8& b) { return a = a & b; }
+ __forceinline vuint8& operator &=(vuint8& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint8& operator |=(vuint8& a, const vuint8& b) { return a = a | b; }
+ __forceinline vuint8& operator |=(vuint8& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint8& operator <<=(vuint8& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint8& operator >>=(vuint8& a, unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpeq_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpeq_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator ==(const vuint8& a, unsigned int b) { return a == vuint8(b); }
+ __forceinline vboolf8 operator ==(unsigned int a, const vuint8& b) { return vuint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return !(a == b); }
+ __forceinline vboolf8 operator !=(const vuint8& a, unsigned int b) { return a != vuint8(b); }
+ __forceinline vboolf8 operator !=(unsigned int a, const vuint8& b) { return vuint8(a) != b; }
+
+ //__forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmplt_epu32 (a.vl, b.vl)),
+ // _mm_castsi128_ps(_mm_cmplt_epu32 (a.vh, b.vh))); }
+ //__forceinline vboolf8 operator < (const vuint8& a, unsigned int b) { return a < vuint8(b); }
+ //__forceinline vboolf8 operator < (unsigned int a, const vuint8& b) { return vuint8(a) < b; }
+
+ //__forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return !(a < b); }
+ //__forceinline vboolf8 operator >=(const vuint8& a, unsigned int b) { return a >= vuint8(b); }
+ //__forceinline vboolf8 operator >=(unsigned int a, const vuint8& b) { return vuint8(a) >= b; }
+
+ //__forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpgt_epu32 (a.vl, b.vl)),
+ // _mm_castsi128_ps(_mm_cmpgt_epu32 (a.vh, b.vh))); }
+ //__forceinline vboolf8 operator > (const vuint8& a, unsigned int b) { return a > vuint8(b); }
+ //__forceinline vboolf8 operator > (unsigned int a, const vuint8& b) { return vuint8(a) > b; }
+
+ //__forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return !(a > b); }
+ //__forceinline vboolf8 operator <=(const vuint8& a, unsigned int b) { return a <= vuint8(b); }
+ //__forceinline vboolf8 operator <=(unsigned int a, const vuint8& b) { return vuint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vuint8& a, const vuint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vuint8& a, const vuint8& b) { return a != b; }
+
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a != b); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+
+ __forceinline vuint8 notand(const vboolf8& m, const vuint8& f) {
+ return _mm256_castps_si256(_mm256_andnot_ps(m, _mm256_castsi256_ps(f)));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 unpacklo(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 unpackhi(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+
+ template<int i>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& a, const vuint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& a, const vuint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vuint8 shuffle<0, 0, 2, 2>(const vuint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<1, 1, 3, 3>(const vuint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<0, 1, 0, 1>(const vuint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vuint8 broadcast(const unsigned int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+ template<int i> __forceinline vuint8 insert4(const vuint8& a, const vuint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vuint4 extract4(const vuint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vuint4 extract4<0>(const vuint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vuint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vuint8 vreduce_min2(const vuint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_min4(const vuint8& v) { vuint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_min (const vuint8& v) { vuint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ //__forceinline vuint8 vreduce_max2(const vuint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_max4(const vuint8& v) { vuint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_max (const vuint8& v) { vuint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vuint8 vreduce_add2(const vuint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vuint8 vreduce_add4(const vuint8& v) { vuint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vuint8 vreduce_add (const vuint8& v) { vuint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ //__forceinline int reduce_min(const vuint8& v) { return toScalar(vreduce_min(v)); }
+ //__forceinline int reduce_max(const vuint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vuint8& v) { return toScalar(vreduce_add(v)); }
+
+ //__forceinline size_t select_min(const vuint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ //__forceinline size_t select_max(const vuint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/simd/vuint8_avx2.h b/thirdparty/embree-aarch64/common/simd/vuint8_avx2.h
new file mode 100644
index 0000000000..b2a965448d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/simd/vuint8_avx2.h
@@ -0,0 +1,439 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vuint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vuint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ unsigned int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint8& a) { v = a.v; }
+ __forceinline vuint8& operator =(const vuint8& a) { v = a.v; return *this; }
+
+ __forceinline vuint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vuint(const vuint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vuint(const vuint4& a, const vuint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vuint(const __m128i& a, const __m128i& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+
+ __forceinline explicit vuint(const unsigned int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vuint(unsigned int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f, unsigned int g, unsigned int h) : v(_mm256_set_epi32(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vuint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(const vboolf8& a) : v(_mm256_movm_epi32(a)) {}
+#else
+ __forceinline explicit vuint(const vboolf8& a) : v(_mm256_castps_si256((__m256)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vuint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm256_set1_epi32(pos_inf)) {}
+ __forceinline vuint(NegInfTy) : v(_mm256_set1_epi32(neg_inf)) {}
+ __forceinline vuint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vuint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint8 load(const uint8_t* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vuint8 loadu(const uint8_t* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vuint8 load(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vuint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+
+ static __forceinline vuint8 load(const void* ptr) { return _mm256_load_si256((__m256i*)ptr); }
+ static __forceinline vuint8 loadu(const void* ptr) { return _mm256_loadu_si256((__m256i*)ptr); }
+
+ static __forceinline void store (void* ptr, const vuint8& v) { _mm256_store_si256((__m256i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vuint8& v) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(v)); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vuint8 compact(const vboolf8& mask, vuint8 &v) {
+ return _mm256_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vuint8 compact(const vboolf8& mask, vuint8 &a, const vuint8& b) {
+ return _mm256_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vuint8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_epi32 (_mm256_setzero_si256(),mask,ptr); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_epi32(_mm256_setzero_si256(),mask,ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_mask_storeu_epi32(ptr,mask,v); }
+#else
+ static __forceinline vuint8 load (const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+#endif
+
+ static __forceinline vuint8 load_nt(void* ptr) {
+ return _mm256_stream_load_si256((__m256i*)ptr);
+ }
+
+ static __forceinline void store_nt(void* ptr, const vuint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline void store(uint8_t* ptr, const vuint8& i)
+ {
+ for (size_t j=0; j<8; j++)
+ ptr[j] = i[j];
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vuint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const unsigned int *const ptr, const vint8& index) {
+ return _mm256_i32gather_epi32((const int*) ptr, index, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const vboolf8& mask, const unsigned int *const ptr, const vint8& index) {
+ vuint8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_epi32(r, mask, index, (const int*) ptr, scale);
+#else
+ return _mm256_mask_i32gather_epi32(r, (const int*) ptr, index, mask, scale);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vuint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
+#else
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[0]) = v[0];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[1]) = v[1];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[2]) = v[2];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[3]) = v[3];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[4]) = v[4];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[5]) = v[5];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[6]) = v[6];
+ *(unsigned int*)(((int8_t*)ptr) + scale * ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vuint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(unsigned int*)(((int8_t*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ static __forceinline vuint8 broadcast64(const long long &a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_movepi32_mask(a); }
+#else
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_castsi256_ps(a); }
+#endif
+
+ __forceinline vuint8 operator +(const vuint8& a) { return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 operator +(const vuint8& a, const vuint8& b) { return _mm256_add_epi32(a, b); }
+ __forceinline vuint8 operator +(const vuint8& a, unsigned int b) { return a + vuint8(b); }
+ __forceinline vuint8 operator +(unsigned int a, const vuint8& b) { return vuint8(a) + b; }
+
+ __forceinline vuint8 operator -(const vuint8& a, const vuint8& b) { return _mm256_sub_epi32(a, b); }
+ __forceinline vuint8 operator -(const vuint8& a, unsigned int b) { return a - vuint8(b); }
+ __forceinline vuint8 operator -(unsigned int a, const vuint8& b) { return vuint8(a) - b; }
+
+ //__forceinline vuint8 operator *(const vuint8& a, const vuint8& b) { return _mm256_mullo_epu32(a, b); }
+ //__forceinline vuint8 operator *(const vuint8& a, unsigned int b) { return a * vuint8(b); }
+ //__forceinline vuint8 operator *(unsigned int a, const vuint8& b) { return vuint8(a) * b; }
+
+ __forceinline vuint8 operator &(const vuint8& a, const vuint8& b) { return _mm256_and_si256(a, b); }
+ __forceinline vuint8 operator &(const vuint8& a, unsigned int b) { return a & vuint8(b); }
+ __forceinline vuint8 operator &(unsigned int a, const vuint8& b) { return vuint8(a) & b; }
+
+ __forceinline vuint8 operator |(const vuint8& a, const vuint8& b) { return _mm256_or_si256(a, b); }
+ __forceinline vuint8 operator |(const vuint8& a, unsigned int b) { return a | vuint8(b); }
+ __forceinline vuint8 operator |(unsigned int a, const vuint8& b) { return vuint8(a) | b; }
+
+ __forceinline vuint8 operator ^(const vuint8& a, const vuint8& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vuint8 operator ^(const vuint8& a, unsigned int b) { return a ^ vuint8(b); }
+ __forceinline vuint8 operator ^(unsigned int a, const vuint8& b) { return vuint8(a) ^ b; }
+
+ __forceinline vuint8 operator <<(const vuint8& a, unsigned int n) { return _mm256_slli_epi32(a, n); }
+ __forceinline vuint8 operator >>(const vuint8& a, unsigned int n) { return _mm256_srli_epi32(a, n); }
+
+ __forceinline vuint8 operator <<(const vuint8& a, const vuint8& n) { return _mm256_sllv_epi32(a, n); }
+ __forceinline vuint8 operator >>(const vuint8& a, const vuint8& n) { return _mm256_srlv_epi32(a, n); }
+
+ __forceinline vuint8 sll(const vuint8& a, unsigned int b) { return _mm256_slli_epi32(a, b); }
+ __forceinline vuint8 sra(const vuint8& a, unsigned int b) { return _mm256_srai_epi32(a, b); }
+ __forceinline vuint8 srl(const vuint8& a, unsigned int b) { return _mm256_srli_epi32(a, b); }
+
+ __forceinline vuint8 sll(const vuint8& a, const vuint8& b) { return _mm256_sllv_epi32(a, b); }
+ __forceinline vuint8 sra(const vuint8& a, const vuint8& b) { return _mm256_srav_epi32(a, b); }
+ __forceinline vuint8 srl(const vuint8& a, const vuint8& b) { return _mm256_srlv_epi32(a, b); }
+
+ __forceinline vuint8 min(const vuint8& a, const vuint8& b) { return _mm256_min_epu32(a, b); }
+ __forceinline vuint8 min(const vuint8& a, unsigned int b) { return min(a,vuint8(b)); }
+ __forceinline vuint8 min(unsigned int a, const vuint8& b) { return min(vuint8(a),b); }
+
+ __forceinline vuint8 max(const vuint8& a, const vuint8& b) { return _mm256_max_epu32(a, b); }
+ __forceinline vuint8 max(const vuint8& a, unsigned int b) { return max(a,vuint8(b)); }
+ __forceinline vuint8 max(unsigned int a, const vuint8& b) { return max(vuint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8& operator +=(vuint8& a, const vuint8& b) { return a = a + b; }
+ __forceinline vuint8& operator +=(vuint8& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint8& operator -=(vuint8& a, const vuint8& b) { return a = a - b; }
+ __forceinline vuint8& operator -=(vuint8& a, unsigned int b) { return a = a - b; }
+
+ //__forceinline vuint8& operator *=(vuint8& a, const vuint8& b) { return a = a * b; }
+ //__forceinline vuint8& operator *=(vuint8& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint8& operator &=(vuint8& a, const vuint8& b) { return a = a & b; }
+ __forceinline vuint8& operator &=(vuint8& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint8& operator |=(vuint8& a, const vuint8& b) { return a = a | b; }
+ __forceinline vuint8& operator |=(vuint8& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint8& operator <<=(vuint8& a, const unsigned int b) { return a = a << b; }
+ __forceinline vuint8& operator >>=(vuint8& a, const unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_mask_blend_epi32(m, (__m256i)f, (__m256i)t);
+ }
+#else
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpeq_epi32(a, b)); }
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return !(a == b); }
+ //__forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epu32(b, a)); }
+ //__forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return !(a < b); }
+ //__forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epu32(a, b)); }
+ //__forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return !(a > b); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+#endif
+
+ template<int mask>
+ __forceinline vuint8 select(const vuint8& t, const vuint8& f) {
+ return _mm256_blend_epi32(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vuint8& a, unsigned int b) { return a == vuint8(b); }
+ __forceinline vboolf8 operator ==(unsigned int a, const vuint8& b) { return vuint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vuint8& a, unsigned int b) { return a != vuint8(b); }
+ __forceinline vboolf8 operator !=(unsigned int a, const vuint8& b) { return vuint8(a) != b; }
+
+ //__forceinline vboolf8 operator < (const vuint8& a, unsigned int b) { return a < vuint8(b); }
+ //__forceinline vboolf8 operator < (unsigned int a, const vuint8& b) { return vuint8(a) < b; }
+
+ //__forceinline vboolf8 operator >=(const vuint8& a, unsigned int b) { return a >= vuint8(b); }
+ //__forceinline vboolf8 operator >=(unsigned int a, const vuint8& b) { return vuint8(a) >= b; }
+
+ //__forceinline vboolf8 operator > (const vuint8& a, unsigned int b) { return a > vuint8(b); }
+ //__forceinline vboolf8 operator > (unsigned int a, const vuint8& b) { return vuint8(a) > b; }
+
+ //__forceinline vboolf8 operator <=(const vuint8& a, unsigned int b) { return a <= vuint8(b); }
+ //__forceinline vboolf8 operator <=(unsigned int a, const vuint8& b) { return vuint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vuint8& a, const vuint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vuint8& a, const vuint8& b) { return a != b; }
+ //__forceinline vboolf8 lt(const vuint8& a, const vuint8& b) { return a < b; }
+ //__forceinline vboolf8 ge(const vuint8& a, const vuint8& b) { return a >= b; }
+ //__forceinline vboolf8 gt(const vuint8& a, const vuint8& b) { return a > b; }
+ //__forceinline vboolf8 le(const vuint8& a, const vuint8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf8 lt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf8 ge(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf8 gt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf8 le(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a != b); }
+ //__forceinline vboolf8 lt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a < b); }
+ //__forceinline vboolf8 ge(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a >= b); }
+ //__forceinline vboolf8 gt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a > b); }
+ //__forceinline vboolf8 le(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a <= b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 unpacklo(const vuint8& a, const vuint8& b) { return _mm256_unpacklo_epi32(a, b); }
+ __forceinline vuint8 unpackhi(const vuint8& a, const vuint8& b) { return _mm256_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& a, const vuint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& a, const vuint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vuint8 shuffle<0, 0, 2, 2>(const vuint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<1, 1, 3, 3>(const vuint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<0, 1, 0, 1>(const vuint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vuint8 broadcast(const unsigned int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+
+ template<int i> __forceinline vuint8 insert4(const vuint8& a, const vuint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vuint4 extract4(const vuint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vuint4 extract4<0>(const vuint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vuint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+#if !defined(__aarch64__)
+
+ __forceinline vuint8 permute(const vuint8& v, const __m256i& index) {
+ return _mm256_permutevar8x32_epi32(v, index);
+ }
+
+ __forceinline vuint8 shuffle(const vuint8& v, const __m256i& index) {
+ return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
+ }
+
+ template<int i>
+ __forceinline vuint8 align_shift_right(const vuint8& a, const vuint8& b) {
+#if defined(__AVX512VL__)
+ return _mm256_alignr_epi32(a, b, i);
+#else
+ return _mm256_alignr_epi8(a, b, 4*i);
+#endif
+ }
+
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vuint8 vreduce_min2(const vuint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_min4(const vuint8& v) { vuint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_min (const vuint8& v) { vuint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ //__forceinline vuint8 vreduce_max2(const vuint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_max4(const vuint8& v) { vuint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_max (const vuint8& v) { vuint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vuint8 vreduce_add2(const vuint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vuint8 vreduce_add4(const vuint8& v) { vuint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vuint8 vreduce_add (const vuint8& v) { vuint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ //__forceinline int reduce_min(const vuint8& v) { return toScalar(vreduce_min(v)); }
+ //__forceinline int reduce_max(const vuint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vuint8& v) { return toScalar(vreduce_add(v)); }
+
+ //__forceinline size_t select_min(const vuint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ //__forceinline size_t select_max(const vuint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ __forceinline vuint8 assign(const vuint4& a) { return _mm256_castsi128_si256(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/alloc.cpp b/thirdparty/embree-aarch64/common/sys/alloc.cpp
new file mode 100644
index 0000000000..12f143f131
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/alloc.cpp
@@ -0,0 +1,327 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "alloc.h"
+#include "intrinsics.h"
+#include "sysinfo.h"
+#include "mutex.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+namespace embree
+{
+ void* alignedMalloc(size_t size, size_t align)
+ {
+ if (size == 0)
+ return nullptr;
+
+ assert((align & (align-1)) == 0);
+ void* ptr = _mm_malloc(size,align);
+
+ if (size != 0 && ptr == nullptr)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return ptr;
+ }
+
+ void alignedFree(void* ptr)
+ {
+ if (ptr)
+ _mm_free(ptr);
+ }
+
+ static bool huge_pages_enabled = false;
+ static MutexSys os_init_mutex;
+
+ __forceinline bool isHugePageCandidate(const size_t bytes)
+ {
+ if (!huge_pages_enabled)
+ return false;
+
+ /* use huge pages only when memory overhead is low */
+ const size_t hbytes = (bytes+PAGE_SIZE_2M-1) & ~size_t(PAGE_SIZE_2M-1);
+ return 66*(hbytes-bytes) < bytes; // at most 1.5% overhead
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <malloc.h>
+
+namespace embree
+{
+ bool win_enable_selockmemoryprivilege (bool verbose)
+ {
+ HANDLE hToken;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) {
+ if (verbose) std::cout << "WARNING: OpenProcessToken failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;
+ return false;
+ }
+
+ TOKEN_PRIVILEGES tp;
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!LookupPrivilegeValueW(nullptr, L"SeLockMemoryPrivilege", &tp.Privileges[0].Luid)) {
+ if (verbose) std::cout << "WARNING: LookupPrivilegeValue failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;
+ return false;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, 0)) {
+ if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed while trying to enable SeLockMemoryPrivilege" << std::endl;
+ return false;
+ }
+
+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
+ if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed to enable SeLockMemoryPrivilege: Add SeLockMemoryPrivilege for current user and run process in elevated mode (Run as administrator)." << std::endl;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool os_init(bool hugepages, bool verbose)
+ {
+ Lock<MutexSys> lock(os_init_mutex);
+
+ if (!hugepages) {
+ huge_pages_enabled = false;
+ return true;
+ }
+
+ if (GetLargePageMinimum() != PAGE_SIZE_2M) {
+ huge_pages_enabled = false;
+ return false;
+ }
+
+ huge_pages_enabled = true;
+ return true;
+ }
+
+ void* os_malloc(size_t bytes, bool& hugepages)
+ {
+ if (bytes == 0) {
+ hugepages = false;
+ return nullptr;
+ }
+
+ /* try direct huge page allocation first */
+ if (isHugePageCandidate(bytes))
+ {
+ int flags = MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+ if (ptr != nullptr) {
+ hugepages = true;
+ return ptr;
+ }
+ }
+
+ /* fall back to 4k pages */
+ int flags = MEM_COMMIT | MEM_RESERVE;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+ // -- GODOT start --
+ // if (ptr == nullptr) throw std::bad_alloc();
+ if (ptr == nullptr) abort();
+ // -- GODOT end --
+ hugepages = false;
+ return ptr;
+ }
+
+ size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)
+ {
+ if (hugepages) // decommitting huge pages seems not to work under Windows
+ return bytesOld;
+
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
+ bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);
+ if (bytesNew >= bytesOld)
+ return bytesOld;
+
+ if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT))
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return bytesNew;
+ }
+
+ void os_free(void* ptr, size_t bytes, bool hugepages)
+ {
+ if (bytes == 0)
+ return;
+
+ if (!VirtualFree(ptr,0,MEM_RELEASE))
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+ }
+
+ void os_advise(void *ptr, size_t bytes)
+ {
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+#if defined(__MACOSX__)
+#include <mach/vm_statistics.h>
+#endif
+
+namespace embree
+{
+ bool os_init(bool hugepages, bool verbose)
+ {
+ Lock<MutexSys> lock(os_init_mutex);
+
+ if (!hugepages) {
+ huge_pages_enabled = false;
+ return true;
+ }
+
+#if defined(__LINUX__)
+
+ int hugepagesize = 0;
+
+ std::ifstream file;
+ file.open("/proc/meminfo",std::ios::in);
+ if (!file.is_open()) {
+ if (verbose) std::cout << "WARNING: Could not open /proc/meminfo. Huge page support cannot get enabled!" << std::endl;
+ huge_pages_enabled = false;
+ return false;
+ }
+
+ std::string line;
+ while (getline(file,line))
+ {
+ std::stringstream sline(line);
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string tag; getline(sline,tag,' ');
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string val; getline(sline,val,' ');
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string unit; getline(sline,unit,' ');
+ if (tag == "Hugepagesize:" && unit == "kB") {
+ hugepagesize = std::stoi(val)*1024;
+ break;
+ }
+ }
+
+ if (hugepagesize != PAGE_SIZE_2M)
+ {
+ if (verbose) std::cout << "WARNING: Only 2MB huge pages supported. Huge page support cannot get enabled!" << std::endl;
+ huge_pages_enabled = false;
+ return false;
+ }
+#endif
+
+ huge_pages_enabled = true;
+ return true;
+ }
+
+ void* os_malloc(size_t bytes, bool& hugepages)
+ {
+ if (bytes == 0) {
+ hugepages = false;
+ return nullptr;
+ }
+
+ /* try direct huge page allocation first */
+ if (isHugePageCandidate(bytes))
+ {
+#if defined(__MACOSX__)
+ void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
+ if (ptr != MAP_FAILED) {
+ hugepages = true;
+ return ptr;
+ }
+#elif defined(MAP_HUGETLB)
+ void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_HUGETLB, -1, 0);
+ if (ptr != MAP_FAILED) {
+ hugepages = true;
+ return ptr;
+ }
+#endif
+ }
+
+ /* fallback to 4k pages */
+ void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ // -- GODOT start --
+ // if (ptr == MAP_FAILED) throw std::bad_alloc();
+ if (ptr == MAP_FAILED) abort();
+ // -- GODOT end --
+ hugepages = false;
+
+ /* advise huge page hint for THP */
+ os_advise(ptr,bytes);
+ return ptr;
+ }
+
+ size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)
+ {
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
+ bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);
+ if (bytesNew >= bytesOld)
+ return bytesOld;
+
+ if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return bytesNew;
+ }
+
+ void os_free(void* ptr, size_t bytes, bool hugepages)
+ {
+ if (bytes == 0)
+ return;
+
+ /* for hugepages we need to also align the size */
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytes = (bytes+pageSize-1) & ~(pageSize-1);
+ if (munmap(ptr,bytes) == -1)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+ }
+
+ /* hint for transparent huge pages (THP) */
+ void os_advise(void* pptr, size_t bytes)
+ {
+#if defined(MADV_HUGEPAGE)
+ madvise(pptr,bytes,MADV_HUGEPAGE);
+#endif
+ }
+}
+
+#endif
diff --git a/thirdparty/embree-aarch64/common/sys/alloc.h b/thirdparty/embree-aarch64/common/sys/alloc.h
new file mode 100644
index 0000000000..5898ecda70
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/alloc.h
@@ -0,0 +1,164 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include <vector>
+#include <set>
+
+namespace embree
+{
+#define ALIGNED_STRUCT_(align) \
+ void* operator new(size_t size) { return alignedMalloc(size,align); } \
+ void operator delete(void* ptr) { alignedFree(ptr); } \
+ void* operator new[](size_t size) { return alignedMalloc(size,align); } \
+ void operator delete[](void* ptr) { alignedFree(ptr); }
+
+#define ALIGNED_CLASS_(align) \
+ public: \
+ ALIGNED_STRUCT_(align) \
+ private:
+
+ /*! aligned allocation */
+ void* alignedMalloc(size_t size, size_t align);
+ void alignedFree(void* ptr);
+
+ /*! allocator that performs aligned allocations */
+ template<typename T, size_t alignment>
+ struct aligned_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline pointer allocate( size_type n ) {
+ return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n ) {
+ return alignedFree(p);
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+ };
+
+ /*! allocates pages directly from OS */
+ bool win_enable_selockmemoryprivilege(bool verbose);
+ bool os_init(bool hugepages, bool verbose);
+ void* os_malloc (size_t bytes, bool& hugepages);
+ size_t os_shrink (void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages);
+ void os_free (void* ptr, size_t bytes, bool hugepages);
+ void os_advise (void* ptr, size_t bytes);
+
+ /*! allocator that performs OS allocations */
+ template<typename T>
+ struct os_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline os_allocator ()
+ : hugepages(false) {}
+
+ __forceinline pointer allocate( size_type n ) {
+ return (pointer) os_malloc(n*sizeof(value_type),hugepages);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n ) {
+ return os_free(p,n*sizeof(value_type),hugepages);
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+
+ bool hugepages;
+ };
+
+ /*! allocator for IDs */
+ template<typename T, size_t max_id>
+ struct IDPool
+ {
+ typedef T value_type;
+
+ IDPool ()
+ : nextID(0) {}
+
+ T allocate()
+ {
+ /* return ID from list */
+ if (!IDs.empty())
+ {
+ T id = *IDs.begin();
+ IDs.erase(IDs.begin());
+ return id;
+ }
+
+ /* allocate new ID */
+ else
+ {
+ if (size_t(nextID)+1 > max_id)
+ return -1;
+
+ return nextID++;
+ }
+ }
+
+ /* adds an ID provided by the user */
+ bool add(T id)
+ {
+ if (id > max_id)
+ return false;
+
+ /* check if ID should be in IDs set */
+ if (id < nextID) {
+ auto p = IDs.find(id);
+ if (p == IDs.end()) return false;
+ IDs.erase(p);
+ return true;
+ }
+
+ /* otherwise increase ID set */
+ else
+ {
+ for (T i=nextID; i<id; i++) {
+ IDs.insert(i);
+ }
+ nextID = id+1;
+ return true;
+ }
+ }
+
+ void deallocate( T id )
+ {
+ assert(id < nextID);
+ MAYBE_UNUSED auto done = IDs.insert(id).second;
+ assert(done);
+ }
+
+ private:
+ std::set<T> IDs; //!< stores deallocated IDs to be reused
+ T nextID; //!< next ID to use when IDs vector is empty
+ };
+}
+
diff --git a/thirdparty/embree-aarch64/common/sys/array.h b/thirdparty/embree-aarch64/common/sys/array.h
new file mode 100644
index 0000000000..77722a39f6
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/array.h
@@ -0,0 +1,222 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "alloc.h"
+
+namespace embree
+{
+ /*! static array with static size */
+ template<typename T, size_t N>
+ class array_t
+ {
+ public:
+
+ /********************** Iterators ****************************/
+
+ __forceinline T* begin() const { return items; };
+ __forceinline T* end () const { return items+N; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return N == 0; }
+ __forceinline size_t size () const { return N; }
+ __forceinline size_t max_size () const { return N; }
+
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < N); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < N); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < N); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < N); return items[i]; }
+
+ __forceinline T& front() const { assert(N > 0); return items[0]; };
+ __forceinline T& back () const { assert(N > 0); return items[N-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+ private:
+ T items[N];
+ };
+
+ /*! static array with dynamic size */
+ template<typename T, size_t N>
+ class darray_t
+ {
+ public:
+
+ __forceinline darray_t () : M(0) {}
+
+ __forceinline darray_t (const T& v) : M(0) {
+ for (size_t i=0; i<N; i++) items[i] = v;
+ }
+
+ /********************** Iterators ****************************/
+
+ __forceinline T* begin() const { return items; };
+ __forceinline T* end () const { return items+M; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return M == 0; }
+ __forceinline size_t size () const { return M; }
+ __forceinline size_t capacity () const { return N; }
+ __forceinline size_t max_size () const { return N; }
+
+ void resize(size_t new_size) {
+ assert(new_size < max_size());
+ M = new_size;
+ }
+
+ /******************** Modifiers **************************/
+
+ __forceinline void push_back(const T& v)
+ {
+ assert(M+1 < max_size());
+ items[M++] = v;
+ }
+
+ __forceinline void pop_back()
+ {
+ assert(!empty());
+ M--;
+ }
+
+ __forceinline void clear() {
+ M = 0;
+ }
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < M); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < M); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < M); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < M); return items[i]; }
+
+ __forceinline T& front() const { assert(M > 0); return items[0]; };
+ __forceinline T& back () const { assert(M > 0); return items[M-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+ private:
+ size_t M;
+ T items[N];
+ };
+
+ /*! dynamic sized array that is allocated on the stack */
+#define dynamic_large_stack_array(Ty,Name,N,max_stack_bytes) StackArray<Ty,max_stack_bytes> Name(N)
+ template<typename Ty, size_t max_stack_bytes>
+ struct __aligned(64) StackArray
+ {
+ __forceinline StackArray (const size_t N)
+ : N(N)
+ {
+ if (N*sizeof(Ty) <= max_stack_bytes)
+ data = &arr[0];
+ else
+ data = (Ty*) alignedMalloc(N*sizeof(Ty),64);
+ }
+
+ __forceinline ~StackArray () {
+ if (data != &arr[0]) alignedFree(data);
+ }
+
+ __forceinline operator Ty* () { return data; }
+ __forceinline operator const Ty* () const { return data; }
+
+ __forceinline Ty& operator[](const int i) { assert(i>=0 && i<N); return data[i]; }
+ __forceinline const Ty& operator[](const int i) const { assert(i>=0 && i<N); return data[i]; }
+
+ __forceinline Ty& operator[](const unsigned i) { assert(i<N); return data[i]; }
+ __forceinline const Ty& operator[](const unsigned i) const { assert(i<N); return data[i]; }
+
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline Ty& operator[](const size_t i) { assert(i<N); return data[i]; }
+ __forceinline const Ty& operator[](const size_t i) const { assert(i<N); return data[i]; }
+#endif
+
+ private:
+ Ty arr[max_stack_bytes/sizeof(Ty)];
+ Ty* data;
+ size_t N;
+
+ private:
+ StackArray (const StackArray& other) DELETED; // do not implement
+ StackArray& operator= (const StackArray& other) DELETED; // do not implement
+
+ };
+
+ /*! dynamic sized array that is allocated on the stack */
+ template<typename Ty, size_t max_stack_elements, size_t max_total_elements>
+ struct __aligned(64) DynamicStackArray
+ {
+ __forceinline DynamicStackArray ()
+ : data(&arr[0]) {}
+
+ __forceinline ~DynamicStackArray ()
+ {
+ if (!isStackAllocated())
+ delete[] data;
+ }
+
+ __forceinline bool isStackAllocated() const {
+ return data == &arr[0];
+ }
+
+ __forceinline size_t size() const
+ {
+ if (isStackAllocated()) return max_stack_elements;
+ else return max_total_elements;
+ }
+
+ __forceinline void resize(size_t M)
+ {
+ assert(M <= max_total_elements);
+ if (likely(M <= max_stack_elements)) return;
+ if (likely(!isStackAllocated())) return;
+
+ data = new Ty[max_total_elements];
+
+ for (size_t i=0; i<max_stack_elements; i++)
+ data[i] = arr[i];
+ }
+
+ __forceinline operator Ty* () { return data; }
+ __forceinline operator const Ty* () const { return data; }
+
+ __forceinline Ty& operator[](const int i) { assert(i>=0 && i<max_total_elements); resize(i+1); return data[i]; }
+ __forceinline Ty& operator[](const unsigned i) { assert(i<max_total_elements); resize(i+1); return data[i]; }
+
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline Ty& operator[](const size_t i) { assert(i<max_total_elements); resize(i+1); return data[i]; }
+#endif
+
+ __forceinline DynamicStackArray (const DynamicStackArray& other)
+ : data(&arr[0])
+ {
+ for (size_t i=0; i<other.size(); i++)
+ this->operator[] (i) = other[i];
+ }
+
+ DynamicStackArray& operator= (const DynamicStackArray& other)
+ {
+ for (size_t i=0; i<other.size(); i++)
+ this->operator[] (i) = other[i];
+
+ return *this;
+ }
+
+ private:
+ Ty arr[max_stack_elements];
+ Ty* data;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/sys/atomic.h b/thirdparty/embree-aarch64/common/sys/atomic.h
new file mode 100644
index 0000000000..ebfb8552c3
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/atomic.h
@@ -0,0 +1,59 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include "intrinsics.h"
+
+namespace embree
+{
+/* compiler memory barriers */
+#if defined(__INTEL_COMPILER)
+//#define __memory_barrier() __memory_barrier()
+#elif defined(__GNUC__) || defined(__clang__)
+# define __memory_barrier() asm volatile("" ::: "memory")
+#elif defined(_MSC_VER)
+# define __memory_barrier() _ReadWriteBarrier()
+#endif
+
+ template <typename T>
+ struct atomic : public std::atomic<T>
+ {
+ atomic () {}
+
+ atomic (const T& a)
+ : std::atomic<T>(a) {}
+
+ atomic (const atomic<T>& a) {
+ this->store(a.load());
+ }
+
+ atomic& operator=(const atomic<T>& other) {
+ this->store(other.load());
+ return *this;
+ }
+ };
+
+ template<typename T>
+ __forceinline void atomic_min(std::atomic<T>& aref, const T& bref)
+ {
+ const T b = bref.load();
+ while (true) {
+ T a = aref.load();
+ if (a <= b) break;
+ if (aref.compare_exchange_strong(a,b)) break;
+ }
+ }
+
+ template<typename T>
+ __forceinline void atomic_max(std::atomic<T>& aref, const T& bref)
+ {
+ const T b = bref.load();
+ while (true) {
+ T a = aref.load();
+ if (a >= b) break;
+ if (aref.compare_exchange_strong(a,b)) break;
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/barrier.cpp b/thirdparty/embree-aarch64/common/sys/barrier.cpp
new file mode 100644
index 0000000000..0061d18db2
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/barrier.cpp
@@ -0,0 +1,289 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "barrier.h"
+#include "condition.h"
+#include "regression.h"
+#include "thread.h"
+
+#if defined (__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ struct BarrierSysImplementation
+ {
+ __forceinline BarrierSysImplementation (size_t N)
+ : i(0), enterCount(0), exitCount(0), barrierSize(0)
+ {
+ events[0] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ events[1] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ init(N);
+ }
+
+ __forceinline ~BarrierSysImplementation ()
+ {
+ CloseHandle(events[0]);
+ CloseHandle(events[1]);
+ }
+
+ __forceinline void init(size_t N)
+ {
+ barrierSize = N;
+ enterCount.store(N);
+ exitCount.store(N);
+ }
+
+ __forceinline void wait()
+ {
+ /* every thread entering the barrier decrements this count */
+ size_t i0 = i;
+ size_t cnt0 = enterCount--;
+
+ /* all threads except the last one are wait in the barrier */
+ if (cnt0 > 1)
+ {
+ if (WaitForSingleObject(events[i0], INFINITE) != WAIT_OBJECT_0)
+ THROW_RUNTIME_ERROR("WaitForSingleObjects failed");
+ }
+
+ /* the last thread starts all threads waiting at the barrier */
+ else
+ {
+ i = 1-i;
+ enterCount.store(barrierSize);
+ if (SetEvent(events[i0]) == 0)
+ THROW_RUNTIME_ERROR("SetEvent failed");
+ }
+
+ /* every thread leaving the barrier decrements this count */
+ size_t cnt1 = exitCount--;
+
+ /* the last thread that left the barrier resets the event again */
+ if (cnt1 == 1)
+ {
+ exitCount.store(barrierSize);
+ if (ResetEvent(events[i0]) == 0)
+ THROW_RUNTIME_ERROR("ResetEvent failed");
+ }
+ }
+
+ public:
+ HANDLE events[2];
+ atomic<size_t> i;
+ atomic<size_t> enterCount;
+ atomic<size_t> exitCount;
+ size_t barrierSize;
+ };
+}
+
+#else
+
+namespace embree
+{
+ struct BarrierSysImplementation
+ {
+ __forceinline BarrierSysImplementation (size_t N)
+ : count(0), barrierSize(0)
+ {
+ init(N);
+ }
+
+ __forceinline void init(size_t N)
+ {
+ assert(count == 0);
+ count = 0;
+ barrierSize = N;
+ }
+
+ __forceinline void wait()
+ {
+ mutex.lock();
+ count++;
+
+ if (count == barrierSize) {
+ count = 0;
+ cond.notify_all();
+ mutex.unlock();
+ return;
+ }
+
+ cond.wait(mutex);
+ mutex.unlock();
+ return;
+ }
+
+ public:
+ MutexSys mutex;
+ ConditionSys cond;
+ volatile size_t count;
+ volatile size_t barrierSize;
+ };
+}
+
+#endif
+
+namespace embree
+{
+ BarrierSys::BarrierSys (size_t N) {
+ opaque = new BarrierSysImplementation(N);
+ }
+
+ BarrierSys::~BarrierSys () {
+ delete (BarrierSysImplementation*) opaque;
+ }
+
+ void BarrierSys::init(size_t count) {
+ ((BarrierSysImplementation*) opaque)->init(count);
+ }
+
+ void BarrierSys::wait() {
+ ((BarrierSysImplementation*) opaque)->wait();
+ }
+
+ LinearBarrierActive::LinearBarrierActive (size_t N)
+ : count0(nullptr), count1(nullptr), mode(0), flag0(0), flag1(0), threadCount(0)
+ {
+ if (N == 0) N = getNumberOfLogicalThreads();
+ init(N);
+ }
+
+ LinearBarrierActive::~LinearBarrierActive()
+ {
+ delete[] count0;
+ delete[] count1;
+ }
+
+ void LinearBarrierActive::init(size_t N)
+ {
+ if (threadCount != N) {
+ threadCount = N;
+ if (count0) delete[] count0; count0 = new unsigned char[N];
+ if (count1) delete[] count1; count1 = new unsigned char[N];
+ }
+ mode = 0;
+ flag0 = 0;
+ flag1 = 0;
+ for (size_t i=0; i<N; i++) count0[i] = 0;
+ for (size_t i=0; i<N; i++) count1[i] = 0;
+ }
+
+ void LinearBarrierActive::wait (const size_t threadIndex)
+ {
+ if (mode == 0)
+ {
+ if (threadIndex == 0)
+ {
+ for (size_t i=0; i<threadCount; i++)
+ count1[i] = 0;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ while (likely(count0[i] == 0))
+ pause_cpu();
+ }
+ mode = 1;
+ flag1 = 0;
+ __memory_barrier();
+ flag0 = 1;
+ }
+ else
+ {
+ count0[threadIndex] = 1;
+ {
+ while (likely(flag0 == 0))
+ pause_cpu();
+ }
+
+ }
+ }
+ else
+ {
+ if (threadIndex == 0)
+ {
+ for (size_t i=0; i<threadCount; i++)
+ count0[i] = 0;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ while (likely(count1[i] == 0))
+ pause_cpu();
+ }
+
+ mode = 0;
+ flag0 = 0;
+ __memory_barrier();
+ flag1 = 1;
+ }
+ else
+ {
+ count1[threadIndex] = 1;
+ {
+ while (likely(flag1 == 0))
+ pause_cpu();
+ }
+ }
+ }
+ }
+
+ struct barrier_sys_regression_test : public RegressionTest
+ {
+ BarrierSys barrier;
+ std::atomic<size_t> threadID;
+ std::atomic<size_t> numFailed;
+ std::vector<size_t> threadResults;
+
+ barrier_sys_regression_test()
+ : RegressionTest("barrier_sys_regression_test"), threadID(0), numFailed(0)
+ {
+ registerRegressionTest(this);
+ }
+
+ static void thread_alloc(barrier_sys_regression_test* This)
+ {
+ size_t tid = This->threadID++;
+ for (size_t j=0; j<1000; j++)
+ {
+ This->barrier.wait();
+ This->threadResults[tid] = tid;
+ This->barrier.wait();
+ }
+ }
+
+ bool run ()
+ {
+ threadID.store(0);
+ numFailed.store(0);
+
+ size_t numThreads = getNumberOfLogicalThreads();
+ threadResults.resize(numThreads);
+ barrier.init(numThreads+1);
+
+ /* create threads */
+ std::vector<thread_t> threads;
+ for (size_t i=0; i<numThreads; i++)
+ threads.push_back(createThread((thread_func)thread_alloc,this));
+
+ /* run test */
+ for (size_t i=0; i<1000; i++)
+ {
+ for (size_t i=0; i<numThreads; i++) threadResults[i] = 0;
+ barrier.wait();
+ barrier.wait();
+ for (size_t i=0; i<numThreads; i++) numFailed += threadResults[i] != i;
+ }
+
+ /* destroy threads */
+ for (size_t i=0; i<numThreads; i++)
+ join(threads[i]);
+
+ return numFailed == 0;
+ }
+ };
+
+ barrier_sys_regression_test barrier_sys_regression_test;
+}
+
+
diff --git a/thirdparty/embree-aarch64/common/sys/barrier.h b/thirdparty/embree-aarch64/common/sys/barrier.h
new file mode 100644
index 0000000000..89607b8685
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/barrier.h
@@ -0,0 +1,112 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "intrinsics.h"
+#include "sysinfo.h"
+#include "atomic.h"
+
+namespace embree
+{
+ /*! system barrier using operating system */
+ class BarrierSys
+ {
+ public:
+
+ /*! construction / destruction */
+ BarrierSys (size_t N = 0);
+ ~BarrierSys ();
+
+ private:
+ /*! class in non-copyable */
+ BarrierSys (const BarrierSys& other) DELETED; // do not implement
+ BarrierSys& operator= (const BarrierSys& other) DELETED; // do not implement
+
+ public:
+ /*! intializes the barrier with some number of threads */
+ void init(size_t count);
+
+ /*! lets calling thread wait in barrier */
+ void wait();
+
+ private:
+ void* opaque;
+ };
+
+ /*! fast active barrier using atomitc counter */
+ struct BarrierActive
+ {
+ public:
+ BarrierActive ()
+ : cntr(0) {}
+
+ void reset() {
+ cntr.store(0);
+ }
+
+ void wait (size_t numThreads)
+ {
+ cntr++;
+ while (cntr.load() != numThreads)
+ pause_cpu();
+ }
+
+ private:
+ std::atomic<size_t> cntr;
+ };
+
+ /*! fast active barrier that does not require initialization to some number of threads */
+ struct BarrierActiveAutoReset
+ {
+ public:
+ BarrierActiveAutoReset ()
+ : cntr0(0), cntr1(0) {}
+
+ void wait (size_t threadCount)
+ {
+ cntr0.fetch_add(1);
+ while (cntr0 != threadCount) pause_cpu();
+ cntr1.fetch_add(1);
+ while (cntr1 != threadCount) pause_cpu();
+ cntr0.fetch_add(-1);
+ while (cntr0 != 0) pause_cpu();
+ cntr1.fetch_add(-1);
+ while (cntr1 != 0) pause_cpu();
+ }
+
+ private:
+ std::atomic<size_t> cntr0;
+ std::atomic<size_t> cntr1;
+ };
+
+ class LinearBarrierActive
+ {
+ public:
+
+ /*! construction and destruction */
+ LinearBarrierActive (size_t threadCount = 0);
+ ~LinearBarrierActive();
+
+ private:
+ /*! class in non-copyable */
+ LinearBarrierActive (const LinearBarrierActive& other) DELETED; // do not implement
+ LinearBarrierActive& operator= (const LinearBarrierActive& other) DELETED; // do not implement
+
+ public:
+ /*! intializes the barrier with some number of threads */
+ void init(size_t threadCount);
+
+ /*! thread with threadIndex waits in the barrier */
+ void wait (const size_t threadIndex);
+
+ private:
+ volatile unsigned char* count0;
+ volatile unsigned char* count1;
+ volatile unsigned int mode;
+ volatile unsigned int flag0;
+ volatile unsigned int flag1;
+ volatile size_t threadCount;
+ };
+}
+
diff --git a/thirdparty/embree-aarch64/common/sys/condition.cpp b/thirdparty/embree-aarch64/common/sys/condition.cpp
new file mode 100644
index 0000000000..0e7ca7af39
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/condition.cpp
@@ -0,0 +1,81 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "condition.h"
+
+#if defined(__WIN32__) && !defined(PTHREADS_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ struct ConditionImplementation
+ {
+ __forceinline ConditionImplementation () {
+ InitializeConditionVariable(&cond);
+ }
+
+ __forceinline ~ConditionImplementation () {
+ }
+
+ __forceinline void wait(MutexSys& mutex_in) {
+ SleepConditionVariableCS(&cond, (LPCRITICAL_SECTION)mutex_in.mutex, INFINITE);
+ }
+
+ __forceinline void notify_all() {
+ WakeAllConditionVariable(&cond);
+ }
+
+ public:
+ CONDITION_VARIABLE cond;
+ };
+}
+#endif
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+#include <pthread.h>
+namespace embree
+{
+ struct ConditionImplementation
+ {
+ __forceinline ConditionImplementation () {
+ pthread_cond_init(&cond,nullptr);
+ }
+
+ __forceinline ~ConditionImplementation() {
+ pthread_cond_destroy(&cond);
+ }
+
+ __forceinline void wait(MutexSys& mutex) {
+ pthread_cond_wait(&cond, (pthread_mutex_t*)mutex.mutex);
+ }
+
+ __forceinline void notify_all() {
+ pthread_cond_broadcast(&cond);
+ }
+
+ public:
+ pthread_cond_t cond;
+ };
+}
+#endif
+
+namespace embree
+{
+ ConditionSys::ConditionSys () {
+ cond = new ConditionImplementation;
+ }
+
+ ConditionSys::~ConditionSys() {
+ delete (ConditionImplementation*) cond;
+ }
+
+ void ConditionSys::wait(MutexSys& mutex) {
+ ((ConditionImplementation*) cond)->wait(mutex);
+ }
+
+ void ConditionSys::notify_all() {
+ ((ConditionImplementation*) cond)->notify_all();
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/condition.h b/thirdparty/embree-aarch64/common/sys/condition.h
new file mode 100644
index 0000000000..7a3a05aa81
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/condition.h
@@ -0,0 +1,31 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "mutex.h"
+
+namespace embree
+{
+ class ConditionSys
+ {
+ public:
+ ConditionSys();
+ ~ConditionSys();
+ void wait( class MutexSys& mutex );
+ void notify_all();
+
+ template<typename Predicate>
+ __forceinline void wait( class MutexSys& mutex, const Predicate& pred )
+ {
+ while (!pred()) wait(mutex);
+ }
+
+ private:
+ ConditionSys (const ConditionSys& other) DELETED; // do not implement
+ ConditionSys& operator= (const ConditionSys& other) DELETED; // do not implement
+
+ protected:
+ void* cond;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/sys/filename.cpp b/thirdparty/embree-aarch64/common/sys/filename.cpp
new file mode 100644
index 0000000000..86182c1afb
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/filename.cpp
@@ -0,0 +1,138 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "filename.h"
+#include "sysinfo.h"
+
+namespace embree
+{
+#ifdef __WIN32__
+ const char path_sep = '\\';
+#else
+ const char path_sep = '/';
+#endif
+
+ /*! create an empty filename */
+ FileName::FileName () {}
+
+ /*! create a valid filename from a string */
+ FileName::FileName (const char* in) {
+ filename = in;
+ for (size_t i=0; i<filename.size(); i++)
+ if (filename[i] == '\\' || filename[i] == '/')
+ filename[i] = path_sep;
+ while (!filename.empty() && filename[filename.size()-1] == path_sep)
+ filename.resize(filename.size()-1);
+ }
+
+ /*! create a valid filename from a string */
+ FileName::FileName (const std::string& in) {
+ filename = in;
+ for (size_t i=0; i<filename.size(); i++)
+ if (filename[i] == '\\' || filename[i] == '/')
+ filename[i] = path_sep;
+ while (!filename.empty() && filename[filename.size()-1] == path_sep)
+ filename.resize(filename.size()-1);
+ }
+
+ /*! returns path to home folder */
+ FileName FileName::homeFolder()
+ {
+#ifdef __WIN32__
+ const char* home = getenv("UserProfile");
+#else
+ const char* home = getenv("HOME");
+#endif
+ if (home) return home;
+ return "";
+ }
+
+ /*! returns path to executable */
+ FileName FileName::executableFolder() {
+ return FileName(getExecutableFileName()).path();
+ }
+
+ /*! returns the path */
+ FileName FileName::path() const {
+ size_t pos = filename.find_last_of(path_sep);
+ if (pos == std::string::npos) return FileName();
+ return filename.substr(0,pos);
+ }
+
+ /*! returns the basename */
+ std::string FileName::base() const {
+ size_t pos = filename.find_last_of(path_sep);
+ if (pos == std::string::npos) return filename;
+ return filename.substr(pos+1);
+ }
+
+ /*! returns the extension */
+ std::string FileName::ext() const {
+ size_t pos = filename.find_last_of('.');
+ if (pos == std::string::npos) return "";
+ return filename.substr(pos+1);
+ }
+
+ /*! returns the extension */
+ FileName FileName::dropExt() const {
+ size_t pos = filename.find_last_of('.');
+ if (pos == std::string::npos) return filename;
+ return filename.substr(0,pos);
+ }
+
+ /*! returns the basename without extension */
+ std::string FileName::name() const {
+ size_t start = filename.find_last_of(path_sep);
+ if (start == std::string::npos) start = 0; else start++;
+ size_t end = filename.find_last_of('.');
+ if (end == std::string::npos || end < start) end = filename.size();
+ return filename.substr(start, end - start);
+ }
+
+ /*! replaces the extension */
+ FileName FileName::setExt(const std::string& ext) const {
+ size_t start = filename.find_last_of(path_sep);
+ if (start == std::string::npos) start = 0; else start++;
+ size_t end = filename.find_last_of('.');
+ if (end == std::string::npos || end < start) return FileName(filename+ext);
+ return FileName(filename.substr(0,end)+ext);
+ }
+
+ /*! adds the extension */
+ FileName FileName::addExt(const std::string& ext) const {
+ return FileName(filename+ext);
+ }
+
+ /*! concatenates two filenames to this/other */
+ FileName FileName::operator +( const FileName& other ) const {
+ if (filename == "") return FileName(other);
+ else return FileName(filename + path_sep + other.filename);
+ }
+
+ /*! concatenates two filenames to this/other */
+ FileName FileName::operator +( const std::string& other ) const {
+ return operator+(FileName(other));
+ }
+
+ /*! removes the base from a filename (if possible) */
+ FileName FileName::operator -( const FileName& base ) const {
+ size_t pos = filename.find_first_of(base);
+ if (pos == std::string::npos) return *this;
+ return FileName(filename.substr(pos+1));
+ }
+
+ /*! == operator */
+ bool operator== (const FileName& a, const FileName& b) {
+ return a.filename == b.filename;
+ }
+
+ /*! != operator */
+ bool operator!= (const FileName& a, const FileName& b) {
+ return a.filename != b.filename;
+ }
+
+ /*! output operator */
+ std::ostream& operator<<(std::ostream& cout, const FileName& filename) {
+ return cout << filename.filename;
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/filename.h b/thirdparty/embree-aarch64/common/sys/filename.h
new file mode 100644
index 0000000000..58f881b14d
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/filename.h
@@ -0,0 +1,81 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+namespace embree
+{
+ /*! Convenience class for handling file names and paths. */
+ class FileName
+ {
+ public:
+
+ /*! create an empty filename */
+ FileName ();
+
+ /*! create a valid filename from a string */
+ FileName (const char* filename);
+
+ /*! create a valid filename from a string */
+ FileName (const std::string& filename);
+
+ /*! returns path to home folder */
+ static FileName homeFolder();
+
+ /*! returns path to executable */
+ static FileName executableFolder();
+
+ /*! auto convert into a string */
+ operator std::string() const { return filename; }
+
+ /*! returns a string of the filename */
+ const std::string str() const { return filename; }
+
+ /*! returns a c-string of the filename */
+ const char* c_str() const { return filename.c_str(); }
+
+ /*! returns the path of a filename */
+ FileName path() const;
+
+ /*! returns the file of a filename */
+ std::string base() const;
+
+ /*! returns the base of a filename without extension */
+ std::string name() const;
+
+ /*! returns the file extension */
+ std::string ext() const;
+
+ /*! drops the file extension */
+ FileName dropExt() const;
+
+ /*! replaces the file extension */
+ FileName setExt(const std::string& ext = "") const;
+
+ /*! adds file extension */
+ FileName addExt(const std::string& ext = "") const;
+
+ /*! concatenates two filenames to this/other */
+ FileName operator +( const FileName& other ) const;
+
+ /*! concatenates two filenames to this/other */
+ FileName operator +( const std::string& other ) const;
+
+ /*! removes the base from a filename (if possible) */
+ FileName operator -( const FileName& base ) const;
+
+ /*! == operator */
+ friend bool operator==(const FileName& a, const FileName& b);
+
+ /*! != operator */
+ friend bool operator!=(const FileName& a, const FileName& b);
+
+ /*! output operator */
+ friend embree_ostream operator<<(embree_ostream cout, const FileName& filename);
+
+ private:
+ std::string filename;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/sys/intrinsics.h b/thirdparty/embree-aarch64/common/sys/intrinsics.h
new file mode 100644
index 0000000000..44cdbd8f0f
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/intrinsics.h
@@ -0,0 +1,559 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+#if defined(__WIN32__)
+#include <intrin.h>
+#endif
+
+#if defined(__ARM_NEON)
+#include "../math/SSE2NEON.h"
+#if defined(NEON_AVX2_EMULATION)
+#include "../math/AVX2NEON.h"
+#endif
+#else
+#include <immintrin.h>
+#endif
+
+#if defined(__BMI__) && defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ #if !defined(_tzcnt_u32)
+ #define _tzcnt_u32 __tzcnt_u32
+ #endif
+ #if !defined(_tzcnt_u64)
+ #define _tzcnt_u64 __tzcnt_u64
+ #endif
+#endif
+
+#if defined(__aarch64__)
+#if !defined(_lzcnt_u32)
+ #define _lzcnt_u32 __builtin_clz
+#endif
+#if !defined(_lzcnt_u32)
+ #define _lzcnt_u32 __builtin_clzll
+#endif
+#else
+#if defined(__LZCNT__)
+ #if !defined(_lzcnt_u32)
+ #define _lzcnt_u32 __lzcnt32
+ #endif
+ #if !defined(_lzcnt_u64)
+ #define _lzcnt_u64 __lzcnt64
+ #endif
+#endif
+#endif
+
+#if defined(__WIN32__)
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+#endif
+
+/* normally defined in pmmintrin.h, but we always need this */
+#if !defined(_MM_SET_DENORMALS_ZERO_MODE)
+#define _MM_DENORMALS_ZERO_ON (0x0040)
+#define _MM_DENORMALS_ZERO_OFF (0x0000)
+#define _MM_DENORMALS_ZERO_MASK (0x0040)
+#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
+#endif
+
+namespace embree
+{
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+ __forceinline size_t read_tsc()
+ {
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return (size_t)li.QuadPart;
+ }
+
+ __forceinline int bsf(int v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _tzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanForward(&r,v); return r;
+#endif
+ }
+
+ __forceinline unsigned bsf(unsigned v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _tzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanForward(&r,v); return r;
+#endif
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bsf(size_t v) {
+#if defined(__AVX2__)
+ return _tzcnt_u64(v);
+#else
+ unsigned long r = 0; _BitScanForward64(&r,v); return r;
+#endif
+ }
+#endif
+
+ __forceinline int bscf(int& v)
+ {
+ int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+ __forceinline unsigned bscf(unsigned& v)
+ {
+ unsigned i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bscf(size_t& v)
+ {
+ size_t i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+#endif
+
+ __forceinline int bsr(int v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return 31 - _lzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanReverse(&r,v); return r;
+#endif
+ }
+
+ __forceinline unsigned bsr(unsigned v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return 31 - _lzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanReverse(&r,v); return r;
+#endif
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bsr(size_t v) {
+#if defined(__AVX2__)
+ return 63 -_lzcnt_u64(v);
+#else
+ unsigned long r = 0; _BitScanReverse64(&r, v); return r;
+#endif
+ }
+#endif
+
+ __forceinline int lzcnt(const int x)
+ {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _lzcnt_u32(x);
+#else
+ if (unlikely(x == 0)) return 32;
+ return 31 - bsr(x);
+#endif
+ }
+
+ __forceinline int btc(int v, int i) {
+ long r = v; _bittestandcomplement(&r,i); return r;
+ }
+
+ __forceinline int bts(int v, int i) {
+ long r = v; _bittestandset(&r,i); return r;
+ }
+
+ __forceinline int btr(int v, int i) {
+ long r = v; _bittestandreset(&r,i); return r;
+ }
+
+#if defined(__X86_64__)
+
+ __forceinline size_t btc(size_t v, size_t i) {
+ size_t r = v; _bittestandcomplement64((__int64*)&r,i); return r;
+ }
+
+ __forceinline size_t bts(size_t v, size_t i) {
+ __int64 r = v; _bittestandset64(&r,i); return r;
+ }
+
+ __forceinline size_t btr(size_t v, size_t i) {
+ __int64 r = v; _bittestandreset64(&r,i); return r;
+ }
+
+#endif
+
+ __forceinline int32_t atomic_cmpxchg(volatile int32_t* p, const int32_t c, const int32_t v) {
+ return _InterlockedCompareExchange((volatile long*)p,v,c);
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#else
+
+#if defined(__i386__) && defined(__PIC__)
+
+ __forceinline void __cpuid(int out[4], int op)
+ {
+ asm volatile ("xchg{l}\t{%%}ebx, %1\n\t"
+ "cpuid\n\t"
+ "xchg{l}\t{%%}ebx, %1\n\t"
+ : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3])
+ : "0"(op));
+ }
+
+ __forceinline void __cpuid_count(int out[4], int op1, int op2)
+ {
+ asm volatile ("xchg{l}\t{%%}ebx, %1\n\t"
+ "cpuid\n\t"
+ "xchg{l}\t{%%}ebx, %1\n\t"
+ : "=a" (out[0]), "=r" (out[1]), "=c" (out[2]), "=d" (out[3])
+ : "0" (op1), "2" (op2));
+ }
+
+#else
+
+ __forceinline void __cpuid(int out[4], int op) {
+#if defined(__ARM_NEON)
+ if (op == 0) { // Get CPU name
+ out[0] = 0x41524d20;
+ out[1] = 0x41524d20;
+ out[2] = 0x41524d20;
+ out[3] = 0x41524d20;
+ }
+#else
+ asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op));
+#endif
+ }
+
+#if !defined(__ARM_NEON)
+ __forceinline void __cpuid_count(int out[4], int op1, int op2) {
+ asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op1), "c"(op2));
+ }
+#endif
+
+#endif
+
+ __forceinline uint64_t read_tsc() {
+#if defined(__ARM_NEON)
+ return 0; // FIXME(LTE): mimic rdtsc
+#else
+ uint32_t high,low;
+ asm volatile ("rdtsc" : "=d"(high), "=a"(low));
+ return (((uint64_t)high) << 32) + (uint64_t)low;
+#endif
+ }
+
+ __forceinline int bsf(int v) {
+#if defined(__ARM_NEON)
+ return __builtin_ctz(v);
+#else
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#else
+ int r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+#endif
+ }
+
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline unsigned bsf(unsigned v)
+ {
+#if defined(__ARM_NEON)
+ return __builtin_ctz(v);
+#else
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#else
+ unsigned r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+#endif
+ }
+#endif
+
+ __forceinline size_t bsf(size_t v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__X86_64__)
+ return _tzcnt_u64(v);
+#else
+ return _tzcnt_u32(v);
+#endif
+#elif defined(__ARM_NEON)
+ return __builtin_ctzl(v);
+#else
+ size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+ }
+
+ __forceinline int bscf(int& v)
+ {
+ int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline unsigned int bscf(unsigned int& v)
+ {
+ unsigned int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+#endif
+
+ __forceinline size_t bscf(size_t& v)
+ {
+ size_t i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+ __forceinline int bsr(int v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return 31 - _lzcnt_u32(v);
+#elif defined(__ARM_NEON)
+ return __builtin_clz(v)^31;
+#else
+ int r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+ }
+
+#if defined(__X86_64__) || defined(__aarch64__)
+ __forceinline unsigned bsr(unsigned v) {
+#if defined(__AVX2__)
+ return 31 - _lzcnt_u32(v);
+#elif defined(__ARM_NEON)
+ return __builtin_clz(v)^31;
+#else
+ unsigned r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+ }
+#endif
+
+ __forceinline size_t bsr(size_t v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__X86_64__)
+ return 63 - _lzcnt_u64(v);
+#else
+ return 31 - _lzcnt_u32(v);
+#endif
+#elif defined(__aarch64__)
+ return (sizeof(v) * 8 - 1) - __builtin_clzl(v);
+#else
+ size_t r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#endif
+ }
+
+ __forceinline int lzcnt(const int x)
+ {
+#if defined(__AVX2__) && !defined(__aarch64__)
+ return _lzcnt_u32(x);
+#else
+ if (unlikely(x == 0)) return 32;
+ return 31 - bsr(x);
+#endif
+ }
+
+ __forceinline size_t blsr(size_t v) {
+#if defined(__AVX2__) && !defined(__aarch64__)
+#if defined(__INTEL_COMPILER)
+ return _blsr_u64(v);
+#else
+#if defined(__X86_64__)
+ return __blsr_u64(v);
+#else
+ return __blsr_u32(v);
+#endif
+#endif
+#else
+ return v & (v-1);
+#endif
+ }
+
+ __forceinline int btc(int v, int i) {
+#if defined(__aarch64__)
+ // _bittestandcomplement(long *a, long b) {
+ // unsigned char x = (*a >> b) & 1;
+ // *a = *a ^ (1 << b);
+ // return x;
+
+ // We only need `*a`
+ return (v ^ (1 << i));
+#else
+ int r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r;
+#endif
+ }
+
+ __forceinline int bts(int v, int i) {
+#if defined(__aarch64__)
+ // _bittestandset(long *a, long b) {
+ // unsigned char x = (*a >> b) & 1;
+ // *a = *a | (1 << b);
+ // return x;
+ return (v | (v << i));
+#else
+ int r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#endif
+ }
+
+ __forceinline int btr(int v, int i) {
+#if defined(__aarch64__)
+ // _bittestandreset(long *a, long b) {
+ // unsigned char x = (*a >> b) & 1;
+ // *a = *a & ~(1 << b);
+ // return x;
+ return (v & ~(v << i));
+#else
+ int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#endif
+ }
+
+ __forceinline size_t btc(size_t v, size_t i) {
+#if defined(__aarch64__)
+ return (v ^ (1 << i));
+#else
+ size_t r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r;
+#endif
+ }
+
+ __forceinline size_t bts(size_t v, size_t i) {
+#if defined(__aarch64__)
+ return (v | (v << i));
+#else
+ size_t r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#endif
+ }
+
+ __forceinline size_t btr(size_t v, size_t i) {
+#if defined(__ARM_NEON)
+ return (v & ~(v << i));
+#else
+ size_t r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#endif
+ }
+
+ __forceinline int32_t atomic_cmpxchg(int32_t volatile* value, int32_t comparand, const int32_t input) {
+ return __sync_val_compare_and_swap(value, comparand, input);
+ }
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__clang__) || defined(__GNUC__)
+#if !defined(_mm_undefined_ps)
+ __forceinline __m128 _mm_undefined_ps() { return _mm_setzero_ps(); }
+#endif
+#if !defined(_mm_undefined_si128)
+ __forceinline __m128i _mm_undefined_si128() { return _mm_setzero_si128(); }
+#endif
+#if !defined(_mm256_undefined_ps) && defined(__AVX__)
+ __forceinline __m256 _mm256_undefined_ps() { return _mm256_setzero_ps(); }
+#endif
+#if !defined(_mm256_undefined_si256) && defined(__AVX__)
+ __forceinline __m256i _mm256_undefined_si256() { return _mm256_setzero_si256(); }
+#endif
+#if !defined(_mm512_undefined_ps) && defined(__AVX512F__)
+ __forceinline __m512 _mm512_undefined_ps() { return _mm512_setzero_ps(); }
+#endif
+#if !defined(_mm512_undefined_epi32) && defined(__AVX512F__)
+ __forceinline __m512i _mm512_undefined_epi32() { return _mm512_setzero_si512(); }
+#endif
+#endif
+
+#if defined(__SSE4_2__) || defined(__ARM_NEON)
+
+ __forceinline int popcnt(int in) {
+ return _mm_popcnt_u32(in);
+ }
+
+ __forceinline unsigned popcnt(unsigned in) {
+ return _mm_popcnt_u32(in);
+ }
+
+#if defined(__X86_64__) || defined(__ARM_NEON)
+ __forceinline size_t popcnt(size_t in) {
+ return _mm_popcnt_u64(in);
+ }
+#endif
+
+#endif
+
+ __forceinline uint64_t rdtsc()
+ {
+ int dummy[4];
+ __cpuid(dummy,0);
+ uint64_t clock = read_tsc();
+ __cpuid(dummy,0);
+ return clock;
+ }
+
+ __forceinline void pause_cpu(const size_t N = 8)
+ {
+ for (size_t i=0; i<N; i++)
+ _mm_pause();
+ }
+
+ /* prefetches */
+ __forceinline void prefetchL1 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T0); }
+ __forceinline void prefetchL2 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T1); }
+ __forceinline void prefetchL3 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T2); }
+ __forceinline void prefetchNTA(const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_NTA); }
+ __forceinline void prefetchEX (const void* ptr) {
+#if defined(__INTEL_COMPILER)
+ _mm_prefetch((const char*)ptr,_MM_HINT_ET0);
+#else
+ _mm_prefetch((const char*)ptr,_MM_HINT_T0);
+#endif
+ }
+
+ __forceinline void prefetchL1EX(const void* ptr) {
+ prefetchEX(ptr);
+ }
+
+ __forceinline void prefetchL2EX(const void* ptr) {
+ prefetchEX(ptr);
+ }
+#if defined(__AVX2__) && !defined(__aarch64__)
+ __forceinline unsigned int pext(unsigned int a, unsigned int b) { return _pext_u32(a, b); }
+ __forceinline unsigned int pdep(unsigned int a, unsigned int b) { return _pdep_u32(a, b); }
+#if defined(__X86_64__)
+ __forceinline size_t pext(size_t a, size_t b) { return _pext_u64(a, b); }
+ __forceinline size_t pdep(size_t a, size_t b) { return _pdep_u64(a, b); }
+#endif
+#endif
+
+#if defined(__AVX512F__)
+#if defined(__INTEL_COMPILER)
+ __forceinline float mm512_cvtss_f32(__m512 v) {
+ return _mm512_cvtss_f32(v);
+ }
+ __forceinline int mm512_mask2int(__mmask16 k1) {
+ return _mm512_mask2int(k1);
+ }
+ __forceinline __mmask16 mm512_int2mask(int mask) {
+ return _mm512_int2mask(mask);
+ }
+#else
+ __forceinline float mm512_cvtss_f32(__m512 v) { // FIXME: _mm512_cvtss_f32 neither supported by clang v4.0.0 nor GCC 6.3
+ return _mm_cvtss_f32(_mm512_castps512_ps128(v));
+ }
+ __forceinline int mm512_mask2int(__mmask16 k1) { // FIXME: _mm512_mask2int not yet supported by GCC 6.3
+ return (int)k1;
+ }
+ __forceinline __mmask16 mm512_int2mask(int mask) { // FIXME: _mm512_int2mask not yet supported by GCC 6.3
+ return (__mmask16)mask;
+ }
+#endif
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/sys/library.cpp b/thirdparty/embree-aarch64/common/sys/library.cpp
new file mode 100644
index 0000000000..899267a1e4
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/library.cpp
@@ -0,0 +1,83 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "library.h"
+#include "sysinfo.h"
+#include "filename.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ /* opens a shared library */
+ lib_t openLibrary(const std::string& file)
+ {
+ std::string fullName = file+".dll";
+ FileName executable = getExecutableFileName();
+ HANDLE handle = LoadLibrary((executable.path() + fullName).c_str());
+ return lib_t(handle);
+ }
+
+ /* returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym) {
+ return reinterpret_cast<void *>(GetProcAddress(HMODULE(lib),sym.c_str()));
+ }
+
+ /* closes the shared library */
+ void closeLibrary(lib_t lib) {
+ FreeLibrary(HMODULE(lib));
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <dlfcn.h>
+
+namespace embree
+{
+ /* opens a shared library */
+ lib_t openLibrary(const std::string& file)
+ {
+#if defined(__MACOSX__)
+ std::string fullName = "lib"+file+".dylib";
+#else
+ std::string fullName = "lib"+file+".so";
+#endif
+ void* lib = dlopen(fullName.c_str(), RTLD_NOW);
+ if (lib) return lib_t(lib);
+ FileName executable = getExecutableFileName();
+ lib = dlopen((executable.path() + fullName).c_str(),RTLD_NOW);
+ if (lib == nullptr) {
+ const char* error = dlerror();
+ if (error) {
+ THROW_RUNTIME_ERROR(error);
+ } else {
+ THROW_RUNTIME_ERROR("could not load library "+executable.str());
+ }
+ }
+ return lib_t(lib);
+ }
+
+ /* returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym) {
+ return dlsym(lib,sym.c_str());
+ }
+
+ /* closes the shared library */
+ void closeLibrary(lib_t lib) {
+ dlclose(lib);
+ }
+}
+#endif
diff --git a/thirdparty/embree-aarch64/common/sys/library.h b/thirdparty/embree-aarch64/common/sys/library.h
new file mode 100644
index 0000000000..c2164e9fbe
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/library.h
@@ -0,0 +1,21 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+namespace embree
+{
+ /*! type for shared library */
+ typedef struct opaque_lib_t* lib_t;
+
+ /*! loads a shared library */
+ lib_t openLibrary(const std::string& file);
+
+ /*! returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym);
+
+ /*! unloads a shared library */
+ void closeLibrary(lib_t lib);
+}
diff --git a/thirdparty/embree-aarch64/common/sys/mutex.cpp b/thirdparty/embree-aarch64/common/sys/mutex.cpp
new file mode 100644
index 0000000000..11779bc9b9
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/mutex.cpp
@@ -0,0 +1,58 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "mutex.h"
+#include "regression.h"
+
+#if defined(__WIN32__) && !defined(PTHREADS_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ MutexSys::MutexSys() { mutex = new CRITICAL_SECTION; InitializeCriticalSection((CRITICAL_SECTION*)mutex); }
+ MutexSys::~MutexSys() { DeleteCriticalSection((CRITICAL_SECTION*)mutex); delete (CRITICAL_SECTION*)mutex; }
+ void MutexSys::lock() { EnterCriticalSection((CRITICAL_SECTION*)mutex); }
+ bool MutexSys::try_lock() { return TryEnterCriticalSection((CRITICAL_SECTION*)mutex) != 0; }
+ void MutexSys::unlock() { LeaveCriticalSection((CRITICAL_SECTION*)mutex); }
+}
+#endif
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+#include <pthread.h>
+namespace embree
+{
+ /*! system mutex using pthreads */
+ MutexSys::MutexSys()
+ {
+ mutex = new pthread_mutex_t;
+ if (pthread_mutex_init((pthread_mutex_t*)mutex, nullptr) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_init failed");
+ }
+
+ MutexSys::~MutexSys()
+ {
+ MAYBE_UNUSED bool ok = pthread_mutex_destroy((pthread_mutex_t*)mutex) == 0;
+ assert(ok);
+ delete (pthread_mutex_t*)mutex;
+ mutex = nullptr;
+ }
+
+ void MutexSys::lock()
+ {
+ if (pthread_mutex_lock((pthread_mutex_t*)mutex) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_lock failed");
+ }
+
+ bool MutexSys::try_lock() {
+ return pthread_mutex_trylock((pthread_mutex_t*)mutex) == 0;
+ }
+
+ void MutexSys::unlock()
+ {
+ if (pthread_mutex_unlock((pthread_mutex_t*)mutex) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_unlock failed");
+ }
+};
+#endif
diff --git a/thirdparty/embree-aarch64/common/sys/mutex.h b/thirdparty/embree-aarch64/common/sys/mutex.h
new file mode 100644
index 0000000000..1164210f23
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/mutex.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "intrinsics.h"
+#include "atomic.h"
+
+namespace embree
+{
+ /*! system mutex */
+ class MutexSys {
+ friend struct ConditionImplementation;
+ public:
+ MutexSys();
+ ~MutexSys();
+
+ private:
+ MutexSys (const MutexSys& other) DELETED; // do not implement
+ MutexSys& operator= (const MutexSys& other) DELETED; // do not implement
+
+ public:
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ protected:
+ void* mutex;
+ };
+
+ /*! spinning mutex */
+ class SpinLock
+ {
+ public:
+
+ SpinLock ()
+ : flag(false) {}
+
+ __forceinline bool isLocked() {
+ return flag.load();
+ }
+
+ __forceinline void lock()
+ {
+ while (true)
+ {
+ while (flag.load())
+ {
+ _mm_pause();
+ _mm_pause();
+ }
+
+ bool expected = false;
+ if (flag.compare_exchange_strong(expected,true,std::memory_order_acquire))
+ break;
+ }
+ }
+
+ __forceinline bool try_lock()
+ {
+ bool expected = false;
+ if (flag.load() != expected) {
+ return false;
+ }
+ return flag.compare_exchange_strong(expected,true,std::memory_order_acquire);
+ }
+
+ __forceinline void unlock() {
+ flag.store(false,std::memory_order_release);
+ }
+
+ __forceinline void wait_until_unlocked()
+ {
+ while(flag.load())
+ {
+ _mm_pause();
+ _mm_pause();
+ }
+ }
+
+ public:
+ atomic<bool> flag;
+ };
+
+ /*! safe mutex lock and unlock helper */
+ template<typename Mutex> class Lock {
+ public:
+ Lock (Mutex& mutex) : mutex(mutex), locked(true) { mutex.lock(); }
+ Lock (Mutex& mutex, bool locked) : mutex(mutex), locked(locked) {}
+ ~Lock() { if (locked) mutex.unlock(); }
+ __forceinline void lock() { assert(!locked); locked = true; mutex.lock(); }
+ __forceinline bool isLocked() const { return locked; }
+ protected:
+ Mutex& mutex;
+ bool locked;
+ };
+}
diff --git a/thirdparty/embree-aarch64/common/sys/platform.h b/thirdparty/embree-aarch64/common/sys/platform.h
new file mode 100644
index 0000000000..737f14aa6e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/platform.h
@@ -0,0 +1,387 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <cstddef>
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <memory>
+#include <stdexcept>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <string>
+#include <cstring>
+#include <stdint.h>
+#include <functional>
+
+////////////////////////////////////////////////////////////////////////////////
+/// detect platform
+////////////////////////////////////////////////////////////////////////////////
+
+/* detect 32 or 64 platform */
+#if defined(__x86_64__) || defined(__ia64__) || defined(_M_X64)
+#define __X86_64__
+#endif
+
+/* detect Linux platform */
+#if defined(linux) || defined(__linux__) || defined(__LINUX__)
+# if !defined(__LINUX__)
+# define __LINUX__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect FreeBSD platform */
+#if defined(__FreeBSD__) || defined(__FREEBSD__)
+# if !defined(__FREEBSD__)
+# define __FREEBSD__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect Windows 95/98/NT/2000/XP/Vista/7/8/10 platform */
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(__CYGWIN__)
+# if !defined(__WIN32__)
+# define __WIN32__
+# endif
+#endif
+
+/* detect Cygwin platform */
+#if defined(__CYGWIN__)
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect MAC OS X platform */
+#if defined(__APPLE__) || defined(MACOSX) || defined(__MACOSX__)
+# if !defined(__MACOSX__)
+# define __MACOSX__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* try to detect other Unix systems */
+#if defined(__unix__) || defined (unix) || defined(__unix) || defined(_unix)
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Macros
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __WIN32__
+#define dll_export __declspec(dllexport)
+#define dll_import __declspec(dllimport)
+#else
+#define dll_export __attribute__ ((visibility ("default")))
+#define dll_import
+#endif
+
+#ifdef __WIN32__
+#if !defined(__noinline)
+#define __noinline __declspec(noinline)
+#endif
+//#define __forceinline __forceinline
+//#define __restrict __restrict
+#if defined(__INTEL_COMPILER)
+#define __restrict__ __restrict
+#else
+#define __restrict__ //__restrict // causes issues with MSVC
+#endif
+#if !defined(__thread)
+// NOTE: Require `-fms-extensions` for clang
+#define __thread __declspec(thread)
+#endif
+#if !defined(__aligned)
+#if defined(__MINGW32__)
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#else
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#endif
+#endif
+//#define __FUNCTION__ __FUNCTION__
+#define debugbreak() __debugbreak()
+
+#else
+#if !defined(__noinline)
+#define __noinline __attribute__((noinline))
+#endif
+#if !defined(__forceinline)
+#define __forceinline inline __attribute__((always_inline))
+#endif
+//#define __restrict __restrict
+//#define __thread __thread
+#if !defined(__aligned)
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+#if !defined(__FUNCTION__)
+#define __FUNCTION__ __PRETTY_FUNCTION__
+#endif
+#define debugbreak() asm ("int $3")
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+ #define MAYBE_UNUSED __attribute__((unused))
+#else
+ #define MAYBE_UNUSED
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900) // before VS2015 deleted functions are not supported properly
+ #define DELETED
+#else
+ #define DELETED = delete
+#endif
+
+// -- GODOT start --
+#ifndef likely
+// -- GODOT end --
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#else
+#define likely(expr) __builtin_expect((bool)(expr),true )
+#define unlikely(expr) __builtin_expect((bool)(expr),false)
+#endif
+// -- GODOT start --
+#endif
+// -- GODOT end --
+
+////////////////////////////////////////////////////////////////////////////////
+/// Error handling and debugging
+////////////////////////////////////////////////////////////////////////////////
+
+/* debug printing macros */
+#define STRING(x) #x
+#define TOSTRING(x) STRING(x)
+#define PING embree_cout << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << embree_endl
+#define PRINT(x) embree_cout << STRING(x) << " = " << (x) << embree_endl
+#define PRINT2(x,y) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << embree_endl
+#define PRINT3(x,y,z) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << embree_endl
+#define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl
+
+#if defined(DEBUG) // only report file and line in debug mode
+ // -- GODOT start --
+ // #define THROW_RUNTIME_ERROR(str)
+ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define THROW_RUNTIME_ERROR(str) \
+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ // -- GODOT end --
+#else
+ // -- GODOT start --
+ // #define THROW_RUNTIME_ERROR(str)
+ // throw std::runtime_error(str);
+ #define THROW_RUNTIME_ERROR(str) \
+ abort();
+ // -- GODOT end --
+#endif
+
+#define FATAL(x) THROW_RUNTIME_ERROR(x)
+#define WARNING(x) { std::cerr << "Warning: " << x << embree_endl << std::flush; }
+
+#define NOT_IMPLEMENTED FATAL(std::string(__FUNCTION__) + " not implemented")
+
+////////////////////////////////////////////////////////////////////////////////
+/// Basic types
+////////////////////////////////////////////////////////////////////////////////
+
+/* default floating-point type */
+namespace embree {
+ typedef float real;
+}
+
+/* windows does not have ssize_t */
+#if defined(__WIN32__)
+#if defined(__X86_64__) || defined(__aarch64__)
+typedef int64_t ssize_t;
+#else
+typedef int32_t ssize_t;
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Basic utility functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline std::string toString(long long value) {
+ return std::to_string(value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Disable some compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__INTEL_COMPILER)
+//#pragma warning(disable:265 ) // floating-point operation result is out of range
+//#pragma warning(disable:383 ) // value copied to temporary, reference to temporary used
+//#pragma warning(disable:869 ) // parameter was never referenced
+//#pragma warning(disable:981 ) // operands are evaluated in unspecified order
+//#pragma warning(disable:1418) // external function definition with no prior declaration
+//#pragma warning(disable:1419) // external declaration in primary source file
+//#pragma warning(disable:1572) // floating-point equality and inequality comparisons are unreliable
+//#pragma warning(disable:94 ) // the size of an array must be greater than zero
+//#pragma warning(disable:1599) // declaration hides parameter
+//#pragma warning(disable:424 ) // extra ";" ignored
+#pragma warning(disable:2196) // routine is both "inline" and "noinline"
+//#pragma warning(disable:177 ) // label was declared but never referenced
+//#pragma warning(disable:114 ) // function was referenced but not defined
+//#pragma warning(disable:819 ) // template nesting depth does not match the previous declaration of function
+#pragma warning(disable:15335) // was not vectorized: vectorization possible but seems inefficient
+#endif
+
+#if defined(_MSC_VER)
+//#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
+#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
+//#pragma warning(disable:4267) // '=' : conversion from 'size_t' to 'unsigned long', possible loss of data
+#pragma warning(disable:4244) // 'argument' : conversion from 'ssize_t' to 'unsigned int', possible loss of data
+//#pragma warning(disable:4355) // 'this' : used in base member initializer list
+//#pragma warning(disable:391 ) // '<=' : signed / unsigned mismatch
+//#pragma warning(disable:4018) // '<' : signed / unsigned mismatch
+//#pragma warning(disable:4305) // 'initializing' : truncation from 'double' to 'float'
+//#pragma warning(disable:4068) // unknown pragma
+//#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
+//#pragma warning(disable:4838) // conversion from 'unsigned int' to 'const int' requires a narrowing conversion)
+//#pragma warning(disable:4227) // anachronism used : qualifiers on reference are ignored
+#pragma warning(disable:4503) // decorated name length exceeded, name was truncated
+#pragma warning(disable:4180) // qualifier applied to function type has no meaning; ignored
+#pragma warning(disable:4258) // definition from the for loop is ignored; the definition from the enclosing scope is used
+
+# if _MSC_VER < 1910 // prior to Visual studio 2017 (V141)
+# pragma warning(disable:4101) // warning C4101: 'x': unreferenced local variable // a compiler bug issues wrong warnings
+# pragma warning(disable:4789) // buffer '' of size 8 bytes will be overrun; 32 bytes will be written starting at offset 0
+# endif
+
+#endif
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+//#pragma clang diagnostic ignored "-Wunknown-pragmas"
+//#pragma clang diagnostic ignored "-Wunused-variable"
+//#pragma clang diagnostic ignored "-Wreorder"
+//#pragma clang diagnostic ignored "-Wmicrosoft"
+//#pragma clang diagnostic ignored "-Wunused-private-field"
+//#pragma clang diagnostic ignored "-Wunused-local-typedef"
+//#pragma clang diagnostic ignored "-Wunused-function"
+//#pragma clang diagnostic ignored "-Wnarrowing"
+//#pragma clang diagnostic ignored "-Wc++11-narrowing"
+//#pragma clang diagnostic ignored "-Wdeprecated-register"
+//#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wpragmas"
+//#pragma GCC diagnostic ignored "-Wnarrowing"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+//#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+//#pragma GCC diagnostic ignored "-Warray-bounds"
+#pragma GCC diagnostic ignored "-Wattributes"
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wparentheses"
+#endif
+
+#if defined(__clang__) && defined(__WIN32__)
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wmicrosoft-cast"
+#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
+#pragma clang diagnostic ignored "-Wmicrosoft-include"
+#pragma clang diagnostic ignored "-Wunused-function"
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#endif
+
+/* disabling deprecated warning, please use only where use of deprecated Embree API functions is desired */
+#if defined(__WIN32__) && defined(__INTEL_COMPILER)
+#define DISABLE_DEPRECATED_WARNING __pragma(warning (disable: 1478)) // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING __pragma(warning (enable: 1478)) // warning: function was declared deprecated
+#elif defined(__INTEL_COMPILER)
+#define DISABLE_DEPRECATED_WARNING _Pragma("warning (disable: 1478)") // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("warning (enable : 1478)") // warning: function was declared deprecated
+#elif defined(__clang__)
+#define DISABLE_DEPRECATED_WARNING _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("clang diagnostic warning \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#elif defined(__GNUC__)
+#define DISABLE_DEPRECATED_WARNING _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#elif defined(_MSC_VER)
+#define DISABLE_DEPRECATED_WARNING __pragma(warning (disable: 4996)) // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING __pragma(warning (enable : 4996)) // warning: function was declared deprecated
+#endif
+
+/* embree output stream */
+#define embree_ostream std::ostream&
+#define embree_cout std::cout
+#define embree_cout_uniform std::cout
+#define embree_endl std::endl
+
+////////////////////////////////////////////////////////////////////////////////
+/// Some macros for static profiling
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__GNUC__)
+#define IACA_SSC_MARK( MARK_ID ) \
+__asm__ __volatile__ ( \
+ "\n\t movl $"#MARK_ID", %%ebx" \
+ "\n\t .byte 0x64, 0x67, 0x90" \
+ : : : "memory" );
+
+#define IACA_UD_BYTES __asm__ __volatile__ ("\n\t .byte 0x0F, 0x0B");
+
+#else
+#define IACA_UD_BYTES {__asm _emit 0x0F \
+ __asm _emit 0x0B}
+
+#define IACA_SSC_MARK(x) {__asm mov ebx, x\
+ __asm _emit 0x64 \
+ __asm _emit 0x67 \
+ __asm _emit 0x90 }
+
+#define IACA_VC64_START __writegsbyte(111, 111);
+#define IACA_VC64_END __writegsbyte(222, 222);
+
+#endif
+
+#define IACA_START {IACA_UD_BYTES \
+ IACA_SSC_MARK(111)}
+#define IACA_END {IACA_SSC_MARK(222) \
+ IACA_UD_BYTES}
+
+namespace embree
+{
+ template<typename Closure>
+ struct OnScopeExitHelper
+ {
+ OnScopeExitHelper (const Closure f) : active(true), f(f) {}
+ ~OnScopeExitHelper() { if (active) f(); }
+ void deactivate() { active = false; }
+ bool active;
+ const Closure f;
+ };
+
+ template <typename Closure>
+ OnScopeExitHelper<Closure> OnScopeExit(const Closure f) {
+ return OnScopeExitHelper<Closure>(f);
+ }
+
+#define STRING_JOIN2(arg1, arg2) DO_STRING_JOIN2(arg1, arg2)
+#define DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
+#define ON_SCOPE_EXIT(code) \
+ auto STRING_JOIN2(on_scope_exit_, __LINE__) = OnScopeExit([&](){code;})
+
+ template<typename Ty>
+ std::unique_ptr<Ty> make_unique(Ty* ptr) {
+ return std::unique_ptr<Ty>(ptr);
+ }
+
+}
diff --git a/thirdparty/embree-aarch64/common/sys/ref.h b/thirdparty/embree-aarch64/common/sys/ref.h
new file mode 100644
index 0000000000..24648e6234
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/ref.h
@@ -0,0 +1,122 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "atomic.h"
+
+namespace embree
+{
+ struct NullTy {
+ };
+
+ extern MAYBE_UNUSED NullTy null;
+
+ class RefCount
+ {
+ public:
+ RefCount(int val = 0) : refCounter(val) {}
+ virtual ~RefCount() {};
+
+ virtual RefCount* refInc() { refCounter.fetch_add(1); return this; }
+ virtual void refDec() { if (refCounter.fetch_add(-1) == 1) delete this; }
+ private:
+ std::atomic<size_t> refCounter;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reference to single object
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename Type>
+ class Ref
+ {
+ public:
+ Type* ptr;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Ref() : ptr(nullptr) {}
+ __forceinline Ref(NullTy) : ptr(nullptr) {}
+ __forceinline Ref(const Ref& input) : ptr(input.ptr) { if (ptr) ptr->refInc(); }
+ __forceinline Ref(Ref&& input) : ptr(input.ptr) { input.ptr = nullptr; }
+
+ __forceinline Ref(Type* const input) : ptr(input)
+ {
+ if (ptr)
+ ptr->refInc();
+ }
+
+ __forceinline ~Ref()
+ {
+ if (ptr)
+ ptr->refDec();
+ }
+
+ __forceinline Ref& operator =(const Ref& input)
+ {
+ if (input.ptr)
+ input.ptr->refInc();
+ if (ptr)
+ ptr->refDec();
+ ptr = input.ptr;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(Ref&& input)
+ {
+ if (ptr)
+ ptr->refDec();
+ ptr = input.ptr;
+ input.ptr = nullptr;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(Type* const input)
+ {
+ if (input)
+ input->refInc();
+ if (ptr)
+ ptr->refDec();
+ ptr = input;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(NullTy)
+ {
+ if (ptr)
+ ptr->refDec();
+ ptr = nullptr;
+ return *this;
+ }
+
+ __forceinline operator bool() const { return ptr != nullptr; }
+
+ __forceinline const Type& operator *() const { return *ptr; }
+ __forceinline Type& operator *() { return *ptr; }
+ __forceinline const Type* operator ->() const { return ptr; }
+ __forceinline Type* operator ->() { return ptr; }
+
+ template<typename TypeOut>
+ __forceinline Ref<TypeOut> cast() { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
+ template<typename TypeOut>
+ __forceinline const Ref<TypeOut> cast() const { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
+
+ template<typename TypeOut>
+ __forceinline Ref<TypeOut> dynamicCast() { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
+ template<typename TypeOut>
+ __forceinline const Ref<TypeOut> dynamicCast() const { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
+ };
+
+ template<typename Type> __forceinline bool operator < (const Ref<Type>& a, const Ref<Type>& b) { return a.ptr < b.ptr; }
+
+ template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, NullTy ) { return a.ptr == nullptr; }
+ template<typename Type> __forceinline bool operator ==(NullTy , const Ref<Type>& b) { return nullptr == b.ptr; }
+ template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr == b.ptr; }
+
+ template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, NullTy ) { return a.ptr != nullptr; }
+ template<typename Type> __forceinline bool operator !=(NullTy , const Ref<Type>& b) { return nullptr != b.ptr; }
+ template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr != b.ptr; }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/regression.cpp b/thirdparty/embree-aarch64/common/sys/regression.cpp
new file mode 100644
index 0000000000..d95ff8dfe0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/regression.cpp
@@ -0,0 +1,30 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "regression.h"
+
+namespace embree
+{
+ /* registerRegressionTest is invoked from static initializers, thus
+ * we cannot have the regression_tests variable as global static
+ * variable due to issues with static variable initialization
+ * order. */
+ std::vector<RegressionTest*>& get_regression_tests()
+ {
+ static std::vector<RegressionTest*> regression_tests;
+ return regression_tests;
+ }
+
+ void registerRegressionTest(RegressionTest* test)
+ {
+ get_regression_tests().push_back(test);
+ }
+
+ RegressionTest* getRegressionTest(size_t index)
+ {
+ if (index >= get_regression_tests().size())
+ return nullptr;
+
+ return get_regression_tests()[index];
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/regression.h b/thirdparty/embree-aarch64/common/sys/regression.h
new file mode 100644
index 0000000000..632f8d92cf
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/regression.h
@@ -0,0 +1,25 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+#include <vector>
+
+namespace embree
+{
+ /*! virtual interface for all regression tests */
+ struct RegressionTest
+ {
+ RegressionTest (std::string name) : name(name) {}
+ virtual bool run() = 0;
+ std::string name;
+ };
+
+ /*! registers a regression test */
+ void registerRegressionTest(RegressionTest* test);
+
+ /*! run all regression tests */
+ RegressionTest* getRegressionTest(size_t index);
+}
diff --git a/thirdparty/embree-aarch64/common/sys/string.cpp b/thirdparty/embree-aarch64/common/sys/string.cpp
new file mode 100644
index 0000000000..931244383e
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/string.cpp
@@ -0,0 +1,42 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "string.h"
+
+#include <algorithm>
+#include <ctype.h>
+
+namespace embree
+{
+ char to_lower(char c) { return char(tolower(int(c))); }
+ char to_upper(char c) { return char(toupper(int(c))); }
+ std::string toLowerCase(const std::string& s) { std::string dst(s); std::transform(dst.begin(), dst.end(), dst.begin(), to_lower); return dst; }
+ std::string toUpperCase(const std::string& s) { std::string dst(s); std::transform(dst.begin(), dst.end(), dst.begin(), to_upper); return dst; }
+
+ Vec2f string_to_Vec2f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next);
+ return Vec2f(x,y);
+ }
+
+ Vec3f string_to_Vec3f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next); str = str.substr(next+1);
+ const float z = std::stof(str,&next);
+ return Vec3f(x,y,z);
+ }
+
+ Vec4f string_to_Vec4f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next); str = str.substr(next+1);
+ const float z = std::stof(str,&next); str = str.substr(next+1);
+ const float w = std::stof(str,&next);
+ return Vec4f(x,y,z,w);
+ }
+}
diff --git a/thirdparty/embree-aarch64/common/sys/string.h b/thirdparty/embree-aarch64/common/sys/string.h
new file mode 100644
index 0000000000..2e9b0f88c3
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/string.h
@@ -0,0 +1,37 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "../math/vec2.h"
+#include "../math/vec3.h"
+#include "../math/vec4.h"
+
+namespace embree
+{
+ class IOStreamStateRestorer
+ {
+ public:
+ IOStreamStateRestorer(std::ostream& iostream)
+ : iostream(iostream), flags(iostream.flags()), precision(iostream.precision()) {
+ }
+
+ ~IOStreamStateRestorer() {
+ iostream.flags(flags);
+ iostream.precision(precision);
+ }
+
+ private:
+ std::ostream& iostream;
+ std::ios::fmtflags flags;
+ std::streamsize precision;
+ };
+
+ std::string toLowerCase(const std::string& s);
+ std::string toUpperCase(const std::string& s);
+
+ Vec2f string_to_Vec2f ( std::string str );
+ Vec3f string_to_Vec3f ( std::string str );
+ Vec4f string_to_Vec4f ( std::string str );
+}
diff --git a/thirdparty/embree-aarch64/common/sys/sysinfo.cpp b/thirdparty/embree-aarch64/common/sys/sysinfo.cpp
new file mode 100644
index 0000000000..1d11436770
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/sysinfo.cpp
@@ -0,0 +1,676 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sysinfo.h"
+#include "intrinsics.h"
+#include "string.h"
+#include "ref.h"
+#if defined(__FREEBSD__)
+#include <sys/cpuset.h>
+#include <pthread_np.h>
+typedef cpuset_t cpu_set_t;
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+namespace embree
+{
+ NullTy null;
+
+ std::string getPlatformName()
+ {
+#if defined(__LINUX__) && defined(__ANDROID__) && defined(__aarch64__) && defined(__ARM_NEON)
+ return "Android Linux (aarch64 / arm64)";
+#elif defined(__LINUX__) && defined(__ANDROID__) && defined(__X86_64__)
+ return "Android Linux (x64)";
+#elif defined(__LINUX__) && defined(__ANDROID__) && (defined(_X86_) || defined(__X86__) || defined(_M_IX86))
+ return "Android Linux (x86)";
+#elif defined(__LINUX__) && !defined(__X86_64__)
+ return "Linux (32bit)";
+#elif defined(__LINUX__) && defined(__X86_64__)
+ return "Linux (64bit)";
+#elif defined(__FREEBSD__) && !defined(__X86_64__)
+ return "FreeBSD (32bit)";
+#elif defined(__FREEBSD__) && defined(__X86_64__)
+ return "FreeBSD (64bit)";
+#elif defined(__CYGWIN__) && !defined(__X86_64__)
+ return "Cygwin (32bit)";
+#elif defined(__CYGWIN__) && defined(__X86_64__)
+ return "Cygwin (64bit)";
+#elif defined(__WIN32__) && !defined(__X86_64__)
+ return "Windows (32bit)";
+#elif defined(__WIN32__) && defined(__X86_64__)
+ return "Windows (64bit)";
+#elif defined(TARGET_IPHONE_SIMULATOR) && defined(__X86_64__)
+ return "iOS Simulator (x64)";
+#elif defined(TARGET_OS_IPHONE) && defined(__aarch64__) && defined(__ARM_NEON)
+ return "iOS (aarch64 / arm64)";
+#elif defined(__MACOSX__) && !defined(__X86_64__)
+ return "Mac OS X (32bit)";
+#elif defined(__MACOSX__) && defined(__X86_64__)
+ return "Mac OS X (64bit)";
+#elif defined(__UNIX__) && defined(__aarch64__)
+ return "Unix (aarch64)";
+#elif defined(__UNIX__) && !defined(__X86_64__)
+ return "Unix (32bit)";
+#elif defined(__UNIX__) && defined(__X86_64__)
+ return "Unix (64bit)";
+#else
+ return "Unknown";
+#endif
+ }
+
+ std::string getCompilerName()
+ {
+#if defined(__INTEL_COMPILER)
+ int icc_mayor = __INTEL_COMPILER / 100 % 100;
+ int icc_minor = __INTEL_COMPILER % 100;
+ std::string version = "Intel Compiler ";
+ version += toString(icc_mayor);
+ version += "." + toString(icc_minor);
+#if defined(__INTEL_COMPILER_UPDATE)
+ version += "." + toString(__INTEL_COMPILER_UPDATE);
+#endif
+ return version;
+#elif defined(__clang__)
+ return "CLANG " __clang_version__;
+#elif defined (__GNUC__)
+ return "GCC " __VERSION__;
+#elif defined(_MSC_VER)
+ std::string version = toString(_MSC_FULL_VER);
+ version.insert(4,".");
+ version.insert(9,".");
+ version.insert(2,".");
+ return "Visual C++ Compiler " + version;
+#else
+ return "Unknown Compiler";
+#endif
+ }
+
+ std::string getCPUVendor()
+ {
+ int cpuinfo[4];
+ __cpuid (cpuinfo, 0);
+ int name[4];
+ name[0] = cpuinfo[1];
+ name[1] = cpuinfo[3];
+ name[2] = cpuinfo[2];
+ name[3] = 0;
+ return (char*)name;
+ }
+
+ CPU getCPUModel()
+ {
+ if (getCPUVendor() != "GenuineIntel")
+ return CPU::UNKNOWN;
+
+ int out[4];
+ __cpuid(out, 0);
+ if (out[0] < 1) return CPU::UNKNOWN;
+ __cpuid(out, 1);
+
+ /* please see CPUID documentation for these formulas */
+ uint32_t family_ID = (out[0] >> 8) & 0x0F;
+ uint32_t extended_family_ID = (out[0] >> 20) & 0xFF;
+
+ uint32_t model_ID = (out[0] >> 4) & 0x0F;
+ uint32_t extended_model_ID = (out[0] >> 16) & 0x0F;
+
+ uint32_t DisplayFamily = family_ID;
+ if (family_ID == 0x0F)
+ DisplayFamily += extended_family_ID;
+
+ uint32_t DisplayModel = model_ID;
+ if (family_ID == 0x06 || family_ID == 0x0F)
+ DisplayModel += extended_model_ID << 4;
+
+ uint32_t DisplayFamily_DisplayModel = (DisplayFamily << 8) + (DisplayModel << 0);
+
+ // Data from Intel® 64 and IA-32 Architectures, Volume 4, Chapter 2, Table 2-1 (CPUID Signature Values of DisplayFamily_DisplayModel)
+ if (DisplayFamily_DisplayModel == 0x067D) return CPU::CORE_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x067E) return CPU::CORE_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x068C) return CPU::CORE_TIGER_LAKE;
+ if (DisplayFamily_DisplayModel == 0x06A5) return CPU::CORE_COMET_LAKE;
+ if (DisplayFamily_DisplayModel == 0x06A6) return CPU::CORE_COMET_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0666) return CPU::CORE_CANNON_LAKE;
+ if (DisplayFamily_DisplayModel == 0x068E) return CPU::CORE_KABY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x069E) return CPU::CORE_KABY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x066A) return CPU::XEON_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x066C) return CPU::XEON_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0655) return CPU::XEON_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x064E) return CPU::CORE_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x065E) return CPU::CORE_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0656) return CPU::XEON_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x064F) return CPU::XEON_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x0647) return CPU::CORE_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x063D) return CPU::CORE_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x063F) return CPU::XEON_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x063C) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x0645) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x0646) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x063E) return CPU::XEON_IVY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x063A) return CPU::CORE_IVY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062D) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062F) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062A) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062E) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x0625) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x062C) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061E) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061F) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061A) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061D) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x0617) return CPU::CORE2;
+ if (DisplayFamily_DisplayModel == 0x060F) return CPU::CORE2;
+ if (DisplayFamily_DisplayModel == 0x060E) return CPU::CORE1;
+
+ if (DisplayFamily_DisplayModel == 0x0685) return CPU::XEON_PHI_KNIGHTS_MILL;
+ if (DisplayFamily_DisplayModel == 0x0657) return CPU::XEON_PHI_KNIGHTS_LANDING;
+
+ return CPU::UNKNOWN;
+ }
+
+ std::string stringOfCPUModel(CPU model)
+ {
+ switch (model) {
+ case CPU::XEON_ICE_LAKE : return "Xeon Ice Lake";
+ case CPU::CORE_ICE_LAKE : return "Core Ice Lake";
+ case CPU::CORE_TIGER_LAKE : return "Core Tiger Lake";
+ case CPU::CORE_COMET_LAKE : return "Core Comet Lake";
+ case CPU::CORE_CANNON_LAKE : return "Core Cannon Lake";
+ case CPU::CORE_KABY_LAKE : return "Core Kaby Lake";
+ case CPU::XEON_SKY_LAKE : return "Xeon Sky Lake";
+ case CPU::CORE_SKY_LAKE : return "Core Sky Lake";
+ case CPU::XEON_PHI_KNIGHTS_MILL : return "Xeon Phi Knights Mill";
+ case CPU::XEON_PHI_KNIGHTS_LANDING: return "Xeon Phi Knights Landing";
+ case CPU::XEON_BROADWELL : return "Xeon Broadwell";
+ case CPU::CORE_BROADWELL : return "Core Broadwell";
+ case CPU::XEON_HASWELL : return "Xeon Haswell";
+ case CPU::CORE_HASWELL : return "Core Haswell";
+ case CPU::XEON_IVY_BRIDGE : return "Xeon Ivy Bridge";
+ case CPU::CORE_IVY_BRIDGE : return "Core Ivy Bridge";
+ case CPU::SANDY_BRIDGE : return "Sandy Bridge";
+ case CPU::NEHALEM : return "Nehalem";
+ case CPU::CORE2 : return "Core2";
+ case CPU::CORE1 : return "Core";
+ case CPU::ARM : return "Arm";
+ case CPU::UNKNOWN : return "Unknown CPU";
+ }
+ return "Unknown CPU (error)";
+ }
+
+#if !defined(__ARM_NEON)
+ /* constants to access destination registers of CPUID instruction */
+ static const int EAX = 0;
+ static const int EBX = 1;
+ static const int ECX = 2;
+ static const int EDX = 3;
+
+ /* cpuid[eax=1].ecx */
+ static const int CPU_FEATURE_BIT_SSE3 = 1 << 0;
+ static const int CPU_FEATURE_BIT_SSSE3 = 1 << 9;
+ static const int CPU_FEATURE_BIT_FMA3 = 1 << 12;
+ static const int CPU_FEATURE_BIT_SSE4_1 = 1 << 19;
+ static const int CPU_FEATURE_BIT_SSE4_2 = 1 << 20;
+ //static const int CPU_FEATURE_BIT_MOVBE = 1 << 22;
+ static const int CPU_FEATURE_BIT_POPCNT = 1 << 23;
+ //static const int CPU_FEATURE_BIT_XSAVE = 1 << 26;
+ static const int CPU_FEATURE_BIT_OXSAVE = 1 << 27;
+ static const int CPU_FEATURE_BIT_AVX = 1 << 28;
+ static const int CPU_FEATURE_BIT_F16C = 1 << 29;
+ static const int CPU_FEATURE_BIT_RDRAND = 1 << 30;
+
+ /* cpuid[eax=1].edx */
+ static const int CPU_FEATURE_BIT_SSE = 1 << 25;
+ static const int CPU_FEATURE_BIT_SSE2 = 1 << 26;
+
+ /* cpuid[eax=0x80000001].ecx */
+ static const int CPU_FEATURE_BIT_LZCNT = 1 << 5;
+
+ /* cpuid[eax=7,ecx=0].ebx */
+ static const int CPU_FEATURE_BIT_BMI1 = 1 << 3;
+ static const int CPU_FEATURE_BIT_AVX2 = 1 << 5;
+ static const int CPU_FEATURE_BIT_BMI2 = 1 << 8;
+ static const int CPU_FEATURE_BIT_AVX512F = 1 << 16; // AVX512F (foundation)
+ static const int CPU_FEATURE_BIT_AVX512DQ = 1 << 17; // AVX512DQ (doubleword and quadword instructions)
+ static const int CPU_FEATURE_BIT_AVX512PF = 1 << 26; // AVX512PF (prefetch gather/scatter instructions)
+ static const int CPU_FEATURE_BIT_AVX512ER = 1 << 27; // AVX512ER (exponential and reciprocal instructions)
+ static const int CPU_FEATURE_BIT_AVX512CD = 1 << 28; // AVX512CD (conflict detection instructions)
+ static const int CPU_FEATURE_BIT_AVX512BW = 1 << 30; // AVX512BW (byte and word instructions)
+ static const int CPU_FEATURE_BIT_AVX512VL = 1 << 31; // AVX512VL (vector length extensions)
+ static const int CPU_FEATURE_BIT_AVX512IFMA = 1 << 21; // AVX512IFMA (integer fused multiple-add instructions)
+
+ /* cpuid[eax=7,ecx=0].ecx */
+ static const int CPU_FEATURE_BIT_AVX512VBMI = 1 << 1; // AVX512VBMI (vector bit manipulation instructions)
+#endif
+
+#if !defined(__ARM_NEON)
+ __noinline int64_t get_xcr0()
+ {
+ // https://github.com/opencv/opencv/blob/master/modules/core/src/system.cpp#L466
+#if defined (__WIN32__) && defined(_XCR_XFEATURE_ENABLED_MASK)
+ int64_t xcr0 = 0; // int64_t is workaround for compiler bug under VS2013, Win32
+ xcr0 = _xgetbv(0);
+ return xcr0;
+#else
+ int xcr0 = 0;
+ __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
+ return xcr0;
+#endif
+ }
+#endif
+
+ int getCPUFeatures()
+ {
+#if defined(__ARM_NEON)
+ int cpu_features = CPU_FEATURE_NEON|CPU_FEATURE_SSE|CPU_FEATURE_SSE2;
+#if defined(NEON_AVX2_EMULATION)
+ cpu_features |= CPU_FEATURE_SSE3|CPU_FEATURE_SSSE3|CPU_FEATURE_SSE42;
+ cpu_features |= CPU_FEATURE_XMM_ENABLED;
+ cpu_features |= CPU_FEATURE_YMM_ENABLED;
+ cpu_features |= CPU_FEATURE_SSE41 | CPU_FEATURE_RDRAND | CPU_FEATURE_F16C;
+ cpu_features |= CPU_FEATURE_POPCNT;
+ cpu_features |= CPU_FEATURE_AVX;
+ cpu_features |= CPU_FEATURE_AVX2;
+ cpu_features |= CPU_FEATURE_FMA3;
+ cpu_features |= CPU_FEATURE_LZCNT;
+ cpu_features |= CPU_FEATURE_BMI1;
+ cpu_features |= CPU_FEATURE_BMI2;
+ cpu_features |= CPU_FEATURE_NEON_2X;
+
+
+
+#endif
+ return cpu_features;
+
+#else
+ /* cache CPU features access */
+ static int cpu_features = 0;
+ if (cpu_features)
+ return cpu_features;
+
+ /* get number of CPUID leaves */
+ int cpuid_leaf0[4];
+ __cpuid(cpuid_leaf0, 0x00000000);
+ unsigned nIds = cpuid_leaf0[EAX];
+
+ /* get number of extended CPUID leaves */
+ int cpuid_leafe[4];
+ __cpuid(cpuid_leafe, 0x80000000);
+ unsigned nExIds = cpuid_leafe[EAX];
+
+ /* get CPUID leaves for EAX = 1,7, and 0x80000001 */
+ int cpuid_leaf_1[4] = { 0,0,0,0 };
+ int cpuid_leaf_7[4] = { 0,0,0,0 };
+ int cpuid_leaf_e1[4] = { 0,0,0,0 };
+ if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001);
+#if _WIN32
+#if _MSC_VER && (_MSC_FULL_VER < 160040219)
+#else
+ if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0);
+#endif
+#else
+ if (nIds >= 7) __cpuid_count(cpuid_leaf_7,0x00000007,0);
+#endif
+ if (nExIds >= 0x80000001) __cpuid(cpuid_leaf_e1,0x80000001);
+
+ /* detect if OS saves XMM, YMM, and ZMM states */
+ bool xmm_enabled = true;
+ bool ymm_enabled = false;
+ bool zmm_enabled = false;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_OXSAVE) {
+ int64_t xcr0 = get_xcr0();
+ xmm_enabled = ((xcr0 & 0x02) == 0x02); /* checks if xmm are enabled in XCR0 */
+ ymm_enabled = xmm_enabled && ((xcr0 & 0x04) == 0x04); /* checks if ymm state are enabled in XCR0 */
+ zmm_enabled = ymm_enabled && ((xcr0 & 0xE0) == 0xE0); /* checks if OPMASK state, upper 256-bit of ZMM0-ZMM15 and ZMM16-ZMM31 state are enabled in XCR0 */
+ }
+ if (xmm_enabled) cpu_features |= CPU_FEATURE_XMM_ENABLED;
+ if (ymm_enabled) cpu_features |= CPU_FEATURE_YMM_ENABLED;
+ if (zmm_enabled) cpu_features |= CPU_FEATURE_ZMM_ENABLED;
+
+ if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE ) cpu_features |= CPU_FEATURE_SSE;
+ if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE2 ) cpu_features |= CPU_FEATURE_SSE2;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE3 ) cpu_features |= CPU_FEATURE_SSE3;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSSE3 ) cpu_features |= CPU_FEATURE_SSSE3;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_1) cpu_features |= CPU_FEATURE_SSE41;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_2) cpu_features |= CPU_FEATURE_SSE42;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_POPCNT) cpu_features |= CPU_FEATURE_POPCNT;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_AVX ) cpu_features |= CPU_FEATURE_AVX;
+
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_F16C ) cpu_features |= CPU_FEATURE_F16C;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_RDRAND) cpu_features |= CPU_FEATURE_RDRAND;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX2 ) cpu_features |= CPU_FEATURE_AVX2;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_FMA3 ) cpu_features |= CPU_FEATURE_FMA3;
+ if (cpuid_leaf_e1[ECX] & CPU_FEATURE_BIT_LZCNT) cpu_features |= CPU_FEATURE_LZCNT;
+ if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI1 ) cpu_features |= CPU_FEATURE_BMI1;
+ if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI2 ) cpu_features |= CPU_FEATURE_BMI2;
+
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512F ) cpu_features |= CPU_FEATURE_AVX512F;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512DQ ) cpu_features |= CPU_FEATURE_AVX512DQ;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512PF ) cpu_features |= CPU_FEATURE_AVX512PF;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512ER ) cpu_features |= CPU_FEATURE_AVX512ER;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512CD ) cpu_features |= CPU_FEATURE_AVX512CD;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512BW ) cpu_features |= CPU_FEATURE_AVX512BW;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512IFMA) cpu_features |= CPU_FEATURE_AVX512IFMA;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512VL ) cpu_features |= CPU_FEATURE_AVX512VL;
+ if (cpuid_leaf_7[ECX] & CPU_FEATURE_BIT_AVX512VBMI) cpu_features |= CPU_FEATURE_AVX512VBMI;
+
+ return cpu_features;
+#endif
+ }
+
+ std::string stringOfCPUFeatures(int features)
+ {
+ std::string str;
+ if (features & CPU_FEATURE_XMM_ENABLED) str += "XMM ";
+ if (features & CPU_FEATURE_YMM_ENABLED) str += "YMM ";
+ if (features & CPU_FEATURE_ZMM_ENABLED) str += "ZMM ";
+ if (features & CPU_FEATURE_SSE ) str += "SSE ";
+ if (features & CPU_FEATURE_SSE2 ) str += "SSE2 ";
+ if (features & CPU_FEATURE_SSE3 ) str += "SSE3 ";
+ if (features & CPU_FEATURE_SSSE3 ) str += "SSSE3 ";
+ if (features & CPU_FEATURE_SSE41 ) str += "SSE4.1 ";
+ if (features & CPU_FEATURE_SSE42 ) str += "SSE4.2 ";
+ if (features & CPU_FEATURE_POPCNT) str += "POPCNT ";
+ if (features & CPU_FEATURE_AVX ) str += "AVX ";
+ if (features & CPU_FEATURE_F16C ) str += "F16C ";
+ if (features & CPU_FEATURE_RDRAND) str += "RDRAND ";
+ if (features & CPU_FEATURE_AVX2 ) str += "AVX2 ";
+ if (features & CPU_FEATURE_FMA3 ) str += "FMA3 ";
+ if (features & CPU_FEATURE_LZCNT ) str += "LZCNT ";
+ if (features & CPU_FEATURE_BMI1 ) str += "BMI1 ";
+ if (features & CPU_FEATURE_BMI2 ) str += "BMI2 ";
+ if (features & CPU_FEATURE_AVX512F) str += "AVX512F ";
+ if (features & CPU_FEATURE_AVX512DQ) str += "AVX512DQ ";
+ if (features & CPU_FEATURE_AVX512PF) str += "AVX512PF ";
+ if (features & CPU_FEATURE_AVX512ER) str += "AVX512ER ";
+ if (features & CPU_FEATURE_AVX512CD) str += "AVX512CD ";
+ if (features & CPU_FEATURE_AVX512BW) str += "AVX512BW ";
+ if (features & CPU_FEATURE_AVX512VL) str += "AVX512VL ";
+ if (features & CPU_FEATURE_AVX512IFMA) str += "AVX512IFMA ";
+ if (features & CPU_FEATURE_AVX512VBMI) str += "AVX512VBMI ";
+ if (features & CPU_FEATURE_NEON) str += "NEON ";
+ if (features & CPU_FEATURE_NEON_2X) str += "2xNEON ";
+ return str;
+ }
+
+ std::string stringOfISA (int isa)
+ {
+ if (isa == SSE) return "SSE";
+ if (isa == SSE2) return "SSE2";
+ if (isa == SSE3) return "SSE3";
+ if (isa == SSSE3) return "SSSE3";
+ if (isa == SSE41) return "SSE4.1";
+ if (isa == SSE42) return "SSE4.2";
+ if (isa == AVX) return "AVX";
+ if (isa == AVX2) return "AVX2";
+ if (isa == AVX512KNL) return "AVX512KNL";
+ if (isa == AVX512SKX) return "AVX512SKX";
+ if (isa == NEON) return "NEON";
+ if (isa == NEON_2X) return "2xNEON";
+ return "UNKNOWN";
+ }
+
+ bool hasISA(int features, int isa) {
+ return (features & isa) == isa;
+ }
+
+ std::string supportedTargetList (int features)
+ {
+ std::string v;
+ if (hasISA(features,SSE)) v += "SSE ";
+ if (hasISA(features,SSE2)) v += "SSE2 ";
+ if (hasISA(features,SSE3)) v += "SSE3 ";
+ if (hasISA(features,SSSE3)) v += "SSSE3 ";
+ if (hasISA(features,SSE41)) v += "SSE4.1 ";
+ if (hasISA(features,SSE42)) v += "SSE4.2 ";
+ if (hasISA(features,AVX)) v += "AVX ";
+ if (hasISA(features,AVXI)) v += "AVXI ";
+ if (hasISA(features,AVX2)) v += "AVX2 ";
+ if (hasISA(features,AVX512KNL)) v += "AVX512KNL ";
+ if (hasISA(features,AVX512SKX)) v += "AVX512SKX ";
+ if (hasISA(features,NEON)) v += "NEON ";
+ if (hasISA(features,NEON_2X)) v += "2xNEON ";
+ return v;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <psapi.h>
+
+namespace embree
+{
+ std::string getExecutableFileName() {
+ char filename[1024];
+ if (!GetModuleFileName(nullptr, filename, sizeof(filename)))
+ return std::string();
+ return std::string(filename);
+ }
+
+ unsigned int getNumberOfLogicalThreads()
+ {
+ static int nThreads = -1;
+ if (nThreads != -1) return nThreads;
+
+ typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
+ typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
+ HMODULE hlib = LoadLibrary("Kernel32");
+ GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
+ GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc) GetProcAddress(hlib, "GetActiveProcessorCount");
+
+ if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount)
+ {
+ int groups = pGetActiveProcessorGroupCount();
+ int totalProcessors = 0;
+ for (int i = 0; i < groups; i++)
+ totalProcessors += pGetActiveProcessorCount(i);
+ nThreads = totalProcessors;
+ }
+ else
+ {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ nThreads = sysinfo.dwNumberOfProcessors;
+ }
+ assert(nThreads);
+ return nThreads;
+ }
+
+ int getTerminalWidth()
+ {
+ HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle == INVALID_HANDLE_VALUE) return 80;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ memset(&info,0,sizeof(info));
+ GetConsoleScreenBufferInfo(handle, &info);
+ return info.dwSize.X;
+ }
+
+ double getSeconds()
+ {
+ LARGE_INTEGER freq, val;
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&val);
+ return (double)val.QuadPart / (double)freq.QuadPart;
+ }
+
+ void sleepSeconds(double t) {
+ Sleep(DWORD(1000.0*t));
+ }
+
+ size_t getVirtualMemoryBytes()
+ {
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.QuotaPeakPagedPoolUsage;
+ }
+
+ size_t getResidentMemoryBytes()
+ {
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.WorkingSetSize;
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Linux Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__LINUX__)
+
+#include <stdio.h>
+#include <unistd.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ std::string pid = "/proc/" + toString(getpid()) + "/exe";
+ char buf[4096];
+ memset(buf,0,sizeof(buf));
+ if (readlink(pid.c_str(), buf, sizeof(buf)-1) == -1)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes()
+ {
+ size_t virt, resident, shared;
+ std::ifstream buffer("/proc/self/statm");
+ buffer >> virt >> resident >> shared;
+ return virt*sysconf(_SC_PAGE_SIZE);
+ }
+
+ size_t getResidentMemoryBytes()
+ {
+ size_t virt, resident, shared;
+ std::ifstream buffer("/proc/self/statm");
+ buffer >> virt >> resident >> shared;
+ return resident*sysconf(_SC_PAGE_SIZE);
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// FreeBSD Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__FreeBSD__)
+
+#include <sys/sysctl.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ char buf[4096];
+ memset(buf,0,sizeof(buf));
+ size_t len = sizeof(buf)-1;
+ if (sysctl(mib, 4, buf, &len, 0x0, 0) == -1)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes() {
+ return 0;
+ }
+
+ size_t getResidentMemoryBytes() {
+ return 0;
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Mac OS X Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__MACOSX__)
+
+#include <mach-o/dyld.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ char buf[4096];
+ uint32_t size = sizeof(buf);
+ if (_NSGetExecutablePath(buf, &size) != 0)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes() {
+ return 0;
+ }
+
+ size_t getResidentMemoryBytes() {
+ return 0;
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+namespace embree
+{
+ unsigned int getNumberOfLogicalThreads()
+ {
+ static int nThreads = -1;
+ if (nThreads != -1) return nThreads;
+
+#if defined(__MACOSX__) || defined(__ANDROID__)
+ nThreads = sysconf(_SC_NPROCESSORS_ONLN); // does not work in Linux LXC container
+ assert(nThreads);
+#else
+ cpu_set_t set;
+ if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0)
+ nThreads = CPU_COUNT(&set);
+#endif
+
+ assert(nThreads);
+ return nThreads;
+ }
+
+ int getTerminalWidth()
+ {
+ struct winsize info;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &info) < 0) return 80;
+ return info.ws_col;
+ }
+
+ double getSeconds() {
+ struct timeval tp; gettimeofday(&tp,nullptr);
+ return double(tp.tv_sec) + double(tp.tv_usec)/1E6;
+ }
+
+ void sleepSeconds(double t) {
+ usleep(1000000.0*t);
+ }
+}
+#endif
+
diff --git a/thirdparty/embree-aarch64/common/sys/sysinfo.h b/thirdparty/embree-aarch64/common/sys/sysinfo.h
new file mode 100644
index 0000000000..8e313a59b3
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/sysinfo.h
@@ -0,0 +1,192 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define CACHELINE_SIZE 64
+
+#if !defined(PAGE_SIZE)
+ #define PAGE_SIZE 4096
+#endif
+
+#define PAGE_SIZE_2M (2*1024*1024)
+#define PAGE_SIZE_4K (4*1024)
+
+#include "platform.h"
+
+/* define isa namespace and ISA bitvector */
+#if defined (__AVX512VL__)
+# define isa avx512skx
+# define ISA AVX512SKX
+# define ISA_STR "AVX512SKX"
+#elif defined (__AVX512F__)
+# define isa avx512knl
+# define ISA AVX512KNL
+# define ISA_STR "AVX512KNL"
+#elif defined (__AVX2__)
+# define isa avx2
+# define ISA AVX2
+# define ISA_STR "AVX2"
+#elif defined(__AVXI__)
+# define isa avxi
+# define ISA AVXI
+# define ISA_STR "AVXI"
+#elif defined(__AVX__)
+# define isa avx
+# define ISA AVX
+# define ISA_STR "AVX"
+#elif defined (__SSE4_2__)
+# define isa sse42
+# define ISA SSE42
+# define ISA_STR "SSE4.2"
+//#elif defined (__SSE4_1__) // we demote this to SSE2, MacOSX code compiles with SSE41 by default with XCode 11
+//# define isa sse41
+//# define ISA SSE41
+//# define ISA_STR "SSE4.1"
+//#elif defined(__SSSE3__) // we demote this to SSE2, MacOSX code compiles with SSSE3 by default with ICC
+//# define isa ssse3
+//# define ISA SSSE3
+//# define ISA_STR "SSSE3"
+//#elif defined(__SSE3__) // we demote this to SSE2, MacOSX code compiles with SSE3 by default with clang
+//# define isa sse3
+//# define ISA SSE3
+//# define ISA_STR "SSE3"
+#elif defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__)
+# define isa sse2
+# define ISA SSE2
+# define ISA_STR "SSE2"
+#elif defined(__SSE__)
+# define isa sse
+# define ISA SSE
+# define ISA_STR "SSE"
+#elif defined(__ARM_NEON)
+// NOTE(LTE): Use sse2 for `isa` for the compatibility at the moment.
+#define isa sse2
+#define ISA NEON
+#define ISA_STR "NEON"
+#else
+#error Unknown ISA
+#endif
+
+namespace embree
+{
+ enum class CPU
+ {
+ XEON_ICE_LAKE,
+ CORE_ICE_LAKE,
+ CORE_TIGER_LAKE,
+ CORE_COMET_LAKE,
+ CORE_CANNON_LAKE,
+ CORE_KABY_LAKE,
+ XEON_SKY_LAKE,
+ CORE_SKY_LAKE,
+ XEON_PHI_KNIGHTS_MILL,
+ XEON_PHI_KNIGHTS_LANDING,
+ XEON_BROADWELL,
+ CORE_BROADWELL,
+ XEON_HASWELL,
+ CORE_HASWELL,
+ XEON_IVY_BRIDGE,
+ CORE_IVY_BRIDGE,
+ SANDY_BRIDGE,
+ NEHALEM,
+ CORE2,
+ CORE1,
+ ARM,
+ UNKNOWN,
+ };
+
+ /*! get the full path to the running executable */
+ std::string getExecutableFileName();
+
+ /*! return platform name */
+ std::string getPlatformName();
+
+ /*! get the full name of the compiler */
+ std::string getCompilerName();
+
+ /*! return the name of the CPU */
+ std::string getCPUVendor();
+
+ /*! get microprocessor model */
+ CPU getCPUModel();
+
+ /*! converts CPU model into string */
+ std::string stringOfCPUModel(CPU model);
+
+ /*! CPU features */
+ static const int CPU_FEATURE_SSE = 1 << 0;
+ static const int CPU_FEATURE_SSE2 = 1 << 1;
+ static const int CPU_FEATURE_SSE3 = 1 << 2;
+ static const int CPU_FEATURE_SSSE3 = 1 << 3;
+ static const int CPU_FEATURE_SSE41 = 1 << 4;
+ static const int CPU_FEATURE_SSE42 = 1 << 5;
+ static const int CPU_FEATURE_POPCNT = 1 << 6;
+ static const int CPU_FEATURE_AVX = 1 << 7;
+ static const int CPU_FEATURE_F16C = 1 << 8;
+ static const int CPU_FEATURE_RDRAND = 1 << 9;
+ static const int CPU_FEATURE_AVX2 = 1 << 10;
+ static const int CPU_FEATURE_FMA3 = 1 << 11;
+ static const int CPU_FEATURE_LZCNT = 1 << 12;
+ static const int CPU_FEATURE_BMI1 = 1 << 13;
+ static const int CPU_FEATURE_BMI2 = 1 << 14;
+ static const int CPU_FEATURE_AVX512F = 1 << 16;
+ static const int CPU_FEATURE_AVX512DQ = 1 << 17;
+ static const int CPU_FEATURE_AVX512PF = 1 << 18;
+ static const int CPU_FEATURE_AVX512ER = 1 << 19;
+ static const int CPU_FEATURE_AVX512CD = 1 << 20;
+ static const int CPU_FEATURE_AVX512BW = 1 << 21;
+ static const int CPU_FEATURE_AVX512VL = 1 << 22;
+ static const int CPU_FEATURE_AVX512IFMA = 1 << 23;
+ static const int CPU_FEATURE_AVX512VBMI = 1 << 24;
+ static const int CPU_FEATURE_XMM_ENABLED = 1 << 25;
+ static const int CPU_FEATURE_YMM_ENABLED = 1 << 26;
+ static const int CPU_FEATURE_ZMM_ENABLED = 1 << 27;
+ static const int CPU_FEATURE_NEON = 1 << 28;
+ static const int CPU_FEATURE_NEON_2X = 1 << 29;
+
+ /*! get CPU features */
+ int getCPUFeatures();
+
+ /*! convert CPU features into a string */
+ std::string stringOfCPUFeatures(int features);
+
+ /*! creates a string of all supported targets that are supported */
+ std::string supportedTargetList (int isa);
+
+ /*! ISAs */
+ static const int SSE = CPU_FEATURE_SSE | CPU_FEATURE_XMM_ENABLED;
+ static const int SSE2 = SSE | CPU_FEATURE_SSE2;
+ static const int SSE3 = SSE2 | CPU_FEATURE_SSE3;
+ static const int SSSE3 = SSE3 | CPU_FEATURE_SSSE3;
+ static const int SSE41 = SSSE3 | CPU_FEATURE_SSE41;
+ static const int SSE42 = SSE41 | CPU_FEATURE_SSE42 | CPU_FEATURE_POPCNT;
+ static const int AVX = SSE42 | CPU_FEATURE_AVX | CPU_FEATURE_YMM_ENABLED;
+ static const int AVXI = AVX | CPU_FEATURE_F16C | CPU_FEATURE_RDRAND;
+ static const int AVX2 = AVXI | CPU_FEATURE_AVX2 | CPU_FEATURE_FMA3 | CPU_FEATURE_BMI1 | CPU_FEATURE_BMI2 | CPU_FEATURE_LZCNT;
+ static const int AVX512KNL = AVX2 | CPU_FEATURE_AVX512F | CPU_FEATURE_AVX512PF | CPU_FEATURE_AVX512ER | CPU_FEATURE_AVX512CD | CPU_FEATURE_ZMM_ENABLED;
+ static const int AVX512SKX = AVX2 | CPU_FEATURE_AVX512F | CPU_FEATURE_AVX512DQ | CPU_FEATURE_AVX512CD | CPU_FEATURE_AVX512BW | CPU_FEATURE_AVX512VL | CPU_FEATURE_ZMM_ENABLED;
+ static const int NEON = CPU_FEATURE_NEON | CPU_FEATURE_SSE | CPU_FEATURE_SSE2;
+ static const int NEON_2X = CPU_FEATURE_NEON_2X | AVX2;
+
+ /*! converts ISA bitvector into a string */
+ std::string stringOfISA(int features);
+
+ /*! return the number of logical threads of the system */
+ unsigned int getNumberOfLogicalThreads();
+
+ /*! returns the size of the terminal window in characters */
+ int getTerminalWidth();
+
+ /*! returns performance counter in seconds */
+ double getSeconds();
+
+ /*! sleeps the specified number of seconds */
+ void sleepSeconds(double t);
+
+ /*! returns virtual address space occupied by process */
+ size_t getVirtualMemoryBytes();
+
+ /*! returns resident memory required by process */
+ size_t getResidentMemoryBytes();
+}
diff --git a/thirdparty/embree-aarch64/common/sys/thread.cpp b/thirdparty/embree-aarch64/common/sys/thread.cpp
new file mode 100644
index 0000000000..f9ea5b7d96
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/thread.cpp
@@ -0,0 +1,429 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "thread.h"
+#include "sysinfo.h"
+#include "string.h"
+
+#include <iostream>
+#if defined(__ARM_NEON)
+#include "../math/SSE2NEON.h"
+#else
+#include <xmmintrin.h>
+#endif
+
+#if defined(PTHREADS_WIN32)
+#pragma comment (lib, "pthreadVC.lib")
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ /*! set the affinity of a given thread */
+ void setAffinity(HANDLE thread, ssize_t affinity)
+ {
+ typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
+ typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
+ typedef BOOL (WINAPI *SetThreadGroupAffinityFunc)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY);
+ typedef BOOL (WINAPI *SetThreadIdealProcessorExFunc)(HANDLE, PPROCESSOR_NUMBER, PPROCESSOR_NUMBER);
+ HMODULE hlib = LoadLibrary("Kernel32");
+ GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
+ GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc)GetProcAddress(hlib, "GetActiveProcessorCount");
+ SetThreadGroupAffinityFunc pSetThreadGroupAffinity = (SetThreadGroupAffinityFunc)GetProcAddress(hlib, "SetThreadGroupAffinity");
+ SetThreadIdealProcessorExFunc pSetThreadIdealProcessorEx = (SetThreadIdealProcessorExFunc)GetProcAddress(hlib, "SetThreadIdealProcessorEx");
+ if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && pSetThreadGroupAffinity && pSetThreadIdealProcessorEx)
+ {
+ int groups = pGetActiveProcessorGroupCount();
+ int totalProcessors = 0, group = 0, number = 0;
+ for (int i = 0; i<groups; i++) {
+ int processors = pGetActiveProcessorCount(i);
+ if (totalProcessors + processors > affinity) {
+ group = i;
+ number = (int)affinity - totalProcessors;
+ break;
+ }
+ totalProcessors += processors;
+ }
+
+ GROUP_AFFINITY groupAffinity;
+ groupAffinity.Group = (WORD)group;
+ groupAffinity.Mask = (KAFFINITY)(uint64_t(1) << number);
+ groupAffinity.Reserved[0] = 0;
+ groupAffinity.Reserved[1] = 0;
+ groupAffinity.Reserved[2] = 0;
+ if (!pSetThreadGroupAffinity(thread, &groupAffinity, nullptr))
+ WARNING("SetThreadGroupAffinity failed"); // on purpose only a warning
+
+ PROCESSOR_NUMBER processorNumber;
+ processorNumber.Group = group;
+ processorNumber.Number = number;
+ processorNumber.Reserved = 0;
+ if (!pSetThreadIdealProcessorEx(thread, &processorNumber, nullptr))
+ WARNING("SetThreadIdealProcessorEx failed"); // on purpose only a warning
+ }
+ else
+ {
+ if (!SetThreadAffinityMask(thread, DWORD_PTR(uint64_t(1) << affinity)))
+ WARNING("SetThreadAffinityMask failed"); // on purpose only a warning
+ if (SetThreadIdealProcessor(thread, (DWORD)affinity) == (DWORD)-1)
+ WARNING("SetThreadIdealProcessor failed"); // on purpose only a warning
+ }
+ }
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity) {
+ setAffinity(GetCurrentThread(), affinity);
+ }
+
+ struct ThreadStartupData
+ {
+ public:
+ ThreadStartupData (thread_func f, void* arg)
+ : f(f), arg(arg) {}
+ public:
+ thread_func f;
+ void* arg;
+ };
+
+ DWORD WINAPI threadStartup(LPVOID ptr)
+ {
+ ThreadStartupData* parg = (ThreadStartupData*) ptr;
+ _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
+ parg->f(parg->arg);
+ delete parg;
+ parg = nullptr;
+ return 0;
+ }
+
+#if !defined(PTHREADS_WIN32)
+
+ /*! creates a hardware thread running on specific core */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
+ {
+ HANDLE thread = CreateThread(nullptr, stack_size, threadStartup, new ThreadStartupData(f,arg), 0, nullptr);
+ if (thread == nullptr) FATAL("CreateThread failed");
+ if (threadID >= 0) setAffinity(thread, threadID);
+ return thread_t(thread);
+ }
+
+ /*! the thread calling this function gets yielded */
+ void yield() {
+ SwitchToThread();
+ }
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid) {
+ WaitForSingleObject(HANDLE(tid), INFINITE);
+ CloseHandle(HANDLE(tid));
+ }
+
+ /*! creates thread local storage */
+ tls_t createTls() {
+ return tls_t(size_t(TlsAlloc()));
+ }
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr) {
+ TlsSetValue(DWORD(size_t(tls)), ptr);
+ }
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls) {
+ return TlsGetValue(DWORD(size_t(tls)));
+ }
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls) {
+ TlsFree(DWORD(size_t(tls)));
+ }
+#endif
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Linux Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__LINUX__)
+
+#include <fstream>
+#include <sstream>
+#include <algorithm>
+
+#if defined(__ANDROID__)
+#include <pthread.h>
+#endif
+
+namespace embree
+{
+ static MutexSys mutex;
+ static std::vector<size_t> threadIDs;
+
+#if !defined(__ANDROID__) // TODO(LTE): Implement for Android target
+ /* changes thread ID mapping such that we first fill up all thread on one core */
+ size_t mapThreadID(size_t threadID)
+ {
+ Lock<MutexSys> lock(mutex);
+
+ if (threadIDs.size() == 0)
+ {
+ /* parse thread/CPU topology */
+ for (size_t cpuID=0;;cpuID++)
+ {
+ std::fstream fs;
+ std::string cpu = std::string("/sys/devices/system/cpu/cpu") + std::to_string((long long)cpuID) + std::string("/topology/thread_siblings_list");
+ fs.open (cpu.c_str(), std::fstream::in);
+ if (fs.fail()) break;
+
+ int i;
+ while (fs >> i)
+ {
+ if (std::none_of(threadIDs.begin(),threadIDs.end(),[&] (int id) { return id == i; }))
+ threadIDs.push_back(i);
+ if (fs.peek() == ',')
+ fs.ignore();
+ }
+ fs.close();
+ }
+
+#if 0
+ for (size_t i=0;i<threadIDs.size();i++)
+ std::cout << i << " -> " << threadIDs[i] << std::endl;
+#endif
+
+ /* verify the mapping and do not use it if the mapping has errors */
+ for (size_t i=0;i<threadIDs.size();i++) {
+ for (size_t j=0;j<threadIDs.size();j++) {
+ if (i != j && threadIDs[i] == threadIDs[j]) {
+ threadIDs.clear();
+ }
+ }
+ }
+ }
+
+ /* re-map threadIDs if mapping is available */
+ size_t ID = threadID;
+ if (threadID < threadIDs.size())
+ ID = threadIDs[threadID];
+
+ /* find correct thread to affinitize to */
+ cpu_set_t set;
+ if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0)
+ {
+ for (int i=0, j=0; i<CPU_SETSIZE; i++)
+ {
+ if (!CPU_ISSET(i,&set)) continue;
+
+ if (j == ID) {
+ ID = i;
+ break;
+ }
+ j++;
+ }
+ }
+
+ return ID;
+ }
+#endif
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+#if defined(__ANDROID__)
+ // TODO(LTE): Implement
+#else
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ size_t threadID = mapThreadID(affinity);
+ CPU_SET(threadID, &cset);
+
+ pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset);
+#endif
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// FreeBSD Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__FreeBSD__)
+
+#include <pthread_np.h>
+
+namespace embree
+{
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+ cpuset_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(affinity, &cset);
+
+ pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset);
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// MacOSX Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__MACOSX__)
+
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <mach/mach_init.h>
+
+namespace embree
+{
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+ thread_affinity_policy ap;
+ ap.affinity_tag = affinity;
+ if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(thread_policy_t)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS)
+ WARNING("setting thread affinity failed"); // on purpose only a warning
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+
+#include <pthread.h>
+#include <sched.h>
+
+#if defined(__USE_NUMA__)
+#include <numa.h>
+#endif
+
+namespace embree
+{
+ struct ThreadStartupData
+ {
+ public:
+ ThreadStartupData (thread_func f, void* arg, int affinity)
+ : f(f), arg(arg), affinity(affinity) {}
+ public:
+ thread_func f;
+ void* arg;
+ ssize_t affinity;
+ };
+
+ static void* threadStartup(ThreadStartupData* parg)
+ {
+ _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
+
+ /*! Mac OS X does not support setting affinity at thread creation time */
+#if defined(__MACOSX__)
+ if (parg->affinity >= 0)
+ setAffinity(parg->affinity);
+#endif
+
+ parg->f(parg->arg);
+ delete parg;
+ parg = nullptr;
+ return nullptr;
+ }
+
+ /*! creates a hardware thread running on specific core */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
+ {
+ /* set stack size */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size);
+
+ /* create thread */
+ pthread_t* tid = new pthread_t;
+ if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,new ThreadStartupData(f,arg,threadID)) != 0) {
+ pthread_attr_destroy(&attr);
+ delete tid;
+ FATAL("pthread_create failed");
+ }
+ pthread_attr_destroy(&attr);
+
+ /* set affinity */
+#if defined(__LINUX__) && !defined(__ANDROID__)
+ if (threadID >= 0) {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ threadID = mapThreadID(threadID);
+ CPU_SET(threadID, &cset);
+ pthread_setaffinity_np(*tid, sizeof(cset), &cset);
+ }
+#elif defined(__FreeBSD__)
+ if (threadID >= 0) {
+ cpuset_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(threadID, &cset);
+ pthread_setaffinity_np(*tid, sizeof(cset), &cset);
+ }
+#endif
+
+ return thread_t(tid);
+ }
+
+ /*! the thread calling this function gets yielded */
+ void yield() {
+ sched_yield();
+ }
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid) {
+ if (pthread_join(*(pthread_t*)tid, nullptr) != 0)
+ FATAL("pthread_join failed");
+ delete (pthread_t*)tid;
+ }
+
+ /*! creates thread local storage */
+ tls_t createTls()
+ {
+ pthread_key_t* key = new pthread_key_t;
+ if (pthread_key_create(key,nullptr) != 0) {
+ delete key;
+ FATAL("pthread_key_create failed");
+ }
+
+ return tls_t(key);
+ }
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls)
+ {
+ assert(tls);
+ return pthread_getspecific(*(pthread_key_t*)tls);
+ }
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr)
+ {
+ assert(tls);
+ if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0)
+ FATAL("pthread_setspecific failed");
+ }
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls)
+ {
+ assert(tls);
+ if (pthread_key_delete(*(pthread_key_t*)tls) != 0)
+ FATAL("pthread_key_delete failed");
+ delete (pthread_key_t*)tls;
+ }
+}
+
+#endif
diff --git a/thirdparty/embree-aarch64/common/sys/thread.h b/thirdparty/embree-aarch64/common/sys/thread.h
new file mode 100644
index 0000000000..45da6e6a70
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/thread.h
@@ -0,0 +1,46 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "mutex.h"
+#include "alloc.h"
+#include "vector.h"
+#include <vector>
+
+namespace embree
+{
+ /*! type for thread */
+ typedef struct opaque_thread_t* thread_t;
+
+ /*! signature of thread start function */
+ typedef void (*thread_func)(void*);
+
+ /*! creates a hardware thread running on specific logical thread */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size = 0, ssize_t threadID = -1);
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity);
+
+ /*! the thread calling this function gets yielded */
+ void yield();
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid);
+
+ /*! type for handle to thread local storage */
+ typedef struct opaque_tls_t* tls_t;
+
+ /*! creates thread local storage */
+ tls_t createTls();
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr);
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls);
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls);
+}
diff --git a/thirdparty/embree-aarch64/common/sys/vector.h b/thirdparty/embree-aarch64/common/sys/vector.h
new file mode 100644
index 0000000000..e41794de7c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/sys/vector.h
@@ -0,0 +1,242 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "alloc.h"
+#include <algorithm>
+
+namespace embree
+{
+ template<typename T, typename allocator>
+ class vector_t
+ {
+ public:
+ typedef T value_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ __forceinline vector_t ()
+ : size_active(0), size_alloced(0), items(nullptr) {}
+
+ __forceinline explicit vector_t (size_t sz)
+ : size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
+
+ template<typename M>
+ __forceinline explicit vector_t (M alloc, size_t sz)
+ : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
+
+ __forceinline ~vector_t() {
+ clear();
+ }
+
+ __forceinline vector_t (const vector_t& other)
+ {
+ size_active = other.size_active;
+ size_alloced = other.size_alloced;
+ items = alloc.allocate(size_alloced);
+ for (size_t i=0; i<size_active; i++)
+ ::new (&items[i]) value_type(other.items[i]);
+ }
+
+ __forceinline vector_t (vector_t&& other)
+ : alloc(std::move(other.alloc))
+ {
+ size_active = other.size_active; other.size_active = 0;
+ size_alloced = other.size_alloced; other.size_alloced = 0;
+ items = other.items; other.items = nullptr;
+ }
+
+ __forceinline vector_t& operator=(const vector_t& other)
+ {
+ resize(other.size_active);
+ for (size_t i=0; i<size_active; i++)
+ items[i] = value_type(other.items[i]);
+ return *this;
+ }
+
+ __forceinline vector_t& operator=(vector_t&& other)
+ {
+ clear();
+ alloc = std::move(other.alloc);
+ size_active = other.size_active; other.size_active = 0;
+ size_alloced = other.size_alloced; other.size_alloced = 0;
+ items = other.items; other.items = nullptr;
+ return *this;
+ }
+
+ /********************** Iterators ****************************/
+
+ __forceinline iterator begin() { return items; };
+ __forceinline const_iterator begin() const { return items; };
+
+ __forceinline iterator end () { return items+size_active; };
+ __forceinline const_iterator end () const { return items+size_active; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return size_active == 0; }
+ __forceinline size_t size () const { return size_active; }
+ __forceinline size_t capacity () const { return size_alloced; }
+
+
+ __forceinline void resize(size_t new_size) {
+ internal_resize(new_size,internal_grow_size(new_size));
+ }
+
+ __forceinline void reserve(size_t new_alloced)
+ {
+ /* do nothing if container already large enough */
+ if (new_alloced <= size_alloced)
+ return;
+
+ /* resize exact otherwise */
+ internal_resize(size_active,new_alloced);
+ }
+
+ __forceinline void shrink_to_fit() {
+ internal_resize(size_active,size_active);
+ }
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < size_active); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < size_active); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < size_active); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < size_active); return items[i]; }
+
+ __forceinline T& front() const { assert(size_active > 0); return items[0]; };
+ __forceinline T& back () const { assert(size_active > 0); return items[size_active-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+
+ /******************** Modifiers **************************/
+
+ __forceinline void push_back(const T& nt)
+ {
+ const T v = nt; // need local copy as input reference could point to this vector
+ internal_resize(size_active,internal_grow_size(size_active+1));
+ ::new (&items[size_active++]) T(v);
+ }
+
+ __forceinline void pop_back()
+ {
+ assert(!empty());
+ size_active--;
+ alloc.destroy(&items[size_active]);
+ }
+
+ __forceinline void clear()
+ {
+ /* destroy elements */
+ for (size_t i=0; i<size_active; i++)
+ alloc.destroy(&items[i]);
+
+ /* free memory */
+ alloc.deallocate(items,size_alloced);
+ items = nullptr;
+ size_active = size_alloced = 0;
+ }
+
+ /******************** Comparisons **************************/
+
+ friend bool operator== (const vector_t& a, const vector_t& b)
+ {
+ if (a.size() != b.size()) return false;
+ for (size_t i=0; i<a.size(); i++)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+
+ friend bool operator!= (const vector_t& a, const vector_t& b) {
+ return !(a==b);
+ }
+
+ private:
+
+ __forceinline void internal_resize_init(size_t new_active)
+ {
+ assert(size_active == 0);
+ assert(size_alloced == 0);
+ assert(items == nullptr);
+ if (new_active == 0) return;
+ items = alloc.allocate(new_active);
+ for (size_t i=0; i<new_active; i++) ::new (&items[i]) T();
+ size_active = new_active;
+ size_alloced = new_active;
+ }
+
+ __forceinline void internal_resize(size_t new_active, size_t new_alloced)
+ {
+ assert(new_active <= new_alloced);
+
+ /* destroy elements */
+ if (new_active < size_active)
+ {
+ for (size_t i=new_active; i<size_active; i++)
+ alloc.destroy(&items[i]);
+ size_active = new_active;
+ }
+
+ /* only reallocate if necessary */
+ if (new_alloced == size_alloced) {
+ for (size_t i=size_active; i<new_active; i++) ::new (&items[i]) T;
+ size_active = new_active;
+ return;
+ }
+
+ /* reallocate and copy items */
+ T* old_items = items;
+ items = alloc.allocate(new_alloced);
+ for (size_t i=0; i<size_active; i++) {
+ ::new (&items[i]) T(std::move(old_items[i]));
+ alloc.destroy(&old_items[i]);
+ }
+
+ for (size_t i=size_active; i<new_active; i++) {
+ ::new (&items[i]) T;
+ }
+
+ alloc.deallocate(old_items,size_alloced);
+ size_active = new_active;
+ size_alloced = new_alloced;
+ }
+
+ __forceinline size_t internal_grow_size(size_t new_alloced)
+ {
+ /* do nothing if container already large enough */
+ if (new_alloced <= size_alloced)
+ return size_alloced;
+
+ /* resize to next power of 2 otherwise */
+ size_t new_size_alloced = size_alloced;
+ while (new_size_alloced < new_alloced) {
+ new_size_alloced = std::max(size_t(1),2*new_size_alloced);
+ }
+ return new_size_alloced;
+ }
+
+ private:
+ allocator alloc;
+ size_t size_active; // number of valid items
+ size_t size_alloced; // number of items allocated
+ T* items; // data array
+ };
+
+ /*! vector class that performs standard allocations */
+ template<typename T>
+ using vector = vector_t<T,std::allocator<T>>;
+
+ /*! vector class that performs aligned allocations */
+ template<typename T>
+ using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >;
+
+ /*! vector class that performs OS allocations */
+ template<typename T>
+ using ovector = vector_t<T,os_allocator<T> >;
+}
diff --git a/thirdparty/embree-aarch64/common/tasking/taskscheduler.h b/thirdparty/embree-aarch64/common/tasking/taskscheduler.h
new file mode 100644
index 0000000000..9940e068d0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskscheduler.h
@@ -0,0 +1,17 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#if defined(TASKING_INTERNAL)
+# include "taskschedulerinternal.h"
+#elif defined(TASKING_GCD) && defined(BUILD_IOS)
+# include "taskschedulergcd.h"
+#elif defined(TASKING_TBB)
+# include "taskschedulertbb.h"
+#elif defined(TASKING_PPL)
+# include "taskschedulerppl.h"
+#else
+# error "no tasking system enabled"
+#endif
+
diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h b/thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h
new file mode 100644
index 0000000000..d31f8bb478
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskschedulergcd.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+
+#include <dispatch/dispatch.h>
+
+namespace embree
+{
+ struct TaskScheduler
+ {
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy() {}
+
+ /* returns the ID of the current thread */
+ static __forceinline size_t threadID()
+ {
+ return threadIndex();
+ }
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ static __forceinline size_t threadIndex()
+ {
+ currentThreadIndex = (currentThreadIndex + 1) % GCDNumThreads;
+ return currentThreadIndex;
+ }
+
+ /* returns the total number of threads */
+ static __forceinline size_t threadCount()
+ {
+ return GCDNumThreads;
+ }
+
+ private:
+ static size_t GCDNumThreads;
+ static size_t currentThreadIndex;
+
+ };
+
+};
+
diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp
new file mode 100644
index 0000000000..ebf656d1a0
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp
@@ -0,0 +1,426 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "taskschedulerinternal.h"
+#include "../math/math.h"
+#include "../sys/sysinfo.h"
+#include <algorithm>
+
+namespace embree
+{
+ RTC_NAMESPACE_BEGIN
+
+ static MutexSys g_mutex;
+ size_t TaskScheduler::g_numThreads = 0;
+ __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
+ std::vector<Ref<TaskScheduler>> g_instance_vector;
+ __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
+ TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;
+
+ template<typename Predicate, typename Body>
+ __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
+ {
+ while (true)
+ {
+ /*! some rounds that yield */
+ for (size_t i=0; i<32; i++)
+ {
+ /*! some spinning rounds */
+ const size_t threadCount = thread.threadCount();
+ for (size_t j=0; j<1024; j+=threadCount)
+ {
+ if (!pred()) return;
+ if (thread.scheduler->steal_from_other_threads(thread)) {
+ i=j=0;
+ body();
+ }
+ }
+ yield();
+ }
+ }
+ }
+
+ /*! run this task */
+ void TaskScheduler::Task::run_internal (Thread& thread) // FIXME: avoid as many dll_exports as possible
+ {
+ /* try to run if not already stolen */
+ if (try_switch_state(INITIALIZED,DONE))
+ {
+ Task* prevTask = thread.task;
+ thread.task = this;
+ // -- GODOT start --
+ // try {
+ // if (thread.scheduler->cancellingException == nullptr)
+ closure->execute();
+ // } catch (...) {
+ // if (thread.scheduler->cancellingException == nullptr)
+ // thread.scheduler->cancellingException = std::current_exception();
+ // }
+ // -- GODOT end --
+ thread.task = prevTask;
+ add_dependencies(-1);
+ }
+
+ /* steal until all dependencies have completed */
+ steal_loop(thread,
+ [&] () { return dependencies>0; },
+ [&] () { while (thread.tasks.execute_local_internal(thread,this)); });
+
+ /* now signal our parent task that we are finished */
+ if (parent)
+ parent->add_dependencies(-1);
+ }
+
+ /*! run this task */
+ dll_export void TaskScheduler::Task::run (Thread& thread) {
+ run_internal(thread);
+ }
+
+ bool TaskScheduler::TaskQueue::execute_local_internal(Thread& thread, Task* parent)
+ {
+ /* stop if we run out of local tasks or reach the waiting task */
+ if (right == 0 || &tasks[right-1] == parent)
+ return false;
+
+ /* execute task */
+ size_t oldRight = right;
+ tasks[right-1].run_internal(thread);
+ if (right != oldRight) {
+ THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
+ }
+
+ /* pop task and closure from stack */
+ right--;
+ if (tasks[right].stackPtr != size_t(-1))
+ stackPtr = tasks[right].stackPtr;
+
+ /* also move left pointer */
+ if (left >= right) left.store(right.load());
+
+ return right != 0;
+ }
+
+ dll_export bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent) {
+ return execute_local_internal(thread,parent);
+ }
+
+ bool TaskScheduler::TaskQueue::steal(Thread& thread)
+ {
+ size_t l = left;
+ size_t r = right;
+ if (l < r)
+ {
+ l = left++;
+ if (l >= r)
+ return false;
+ }
+ else
+ return false;
+
+ if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
+ return false;
+
+ thread.tasks.right++;
+ return true;
+ }
+
+ /* we steal from the left */
+ size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
+ {
+ if (left >= right) return 0;
+ return tasks[left].N;
+ }
+
+ void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
+ {
+ TaskScheduler::ThreadPool* pool = pair->first;
+ size_t threadIndex = pair->second;
+ delete pair;
+ pool->thread_loop(threadIndex);
+ }
+
+ TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
+ : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}
+
+ dll_export void TaskScheduler::ThreadPool::startThreads()
+ {
+ if (running) return;
+ setNumThreads(numThreads,true);
+ }
+
+ void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
+ {
+ Lock<MutexSys> lock(g_mutex);
+ assert(newNumThreads);
+ newNumThreads = min(newNumThreads, (size_t) getNumberOfLogicalThreads());
+
+ // We are observing a few % gain by increasing number threads by 2 on aarch64.
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ numThreads = newNumThreads*2;
+#else
+ numThreads = newNumThreads;
+#endif
+ numThreads = newNumThreads;
+ if (!startThreads && !running) return;
+ running = true;
+ size_t numThreadsActive = numThreadsRunning;
+
+ mutex.lock();
+ numThreadsRunning = newNumThreads;
+ mutex.unlock();
+ condition.notify_all();
+
+ /* start new threads */
+ for (size_t t=numThreadsActive; t<numThreads; t++)
+ {
+ if (t == 0) continue;
+ auto pair = new std::pair<TaskScheduler::ThreadPool*,size_t>(this,t);
+ threads.push_back(createThread((thread_func)threadPoolFunction,pair,4*1024*1024,set_affinity ? t : -1));
+ }
+
+ /* stop some threads if we reduce the number of threads */
+ for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
+ if (t == 0) continue;
+ embree::join(threads.back());
+ threads.pop_back();
+ }
+ }
+
+ TaskScheduler::ThreadPool::~ThreadPool()
+ {
+ /* leave all taskschedulers */
+ mutex.lock();
+ numThreadsRunning = 0;
+ mutex.unlock();
+ condition.notify_all();
+
+ /* wait for threads to terminate */
+ for (size_t i=0; i<threads.size(); i++)
+ embree::join(threads[i]);
+ }
+
+ dll_export void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
+ {
+ mutex.lock();
+ schedulers.push_back(scheduler);
+ mutex.unlock();
+ condition.notify_all();
+ }
+
+ dll_export void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
+ {
+ Lock<MutexSys> lock(mutex);
+ for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
+ if (scheduler == *it) {
+ schedulers.erase(it);
+ return;
+ }
+ }
+ }
+
+ void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
+ {
+ while (globalThreadIndex < numThreadsRunning)
+ {
+ Ref<TaskScheduler> scheduler = NULL;
+ ssize_t threadIndex = -1;
+ {
+ Lock<MutexSys> lock(mutex);
+ condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
+ if (globalThreadIndex >= numThreadsRunning) break;
+ scheduler = schedulers.front();
+ threadIndex = scheduler->allocThreadIndex();
+ }
+ scheduler->thread_loop(threadIndex);
+ }
+ }
+
+ TaskScheduler::TaskScheduler()
+ : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
+ {
+ threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the compatibility join mode with rtcCommitScene the worker threads also join. When disallowing rtcCommitScene to join a build we can remove the 2x.
+ for (size_t i=0; i<threadLocal.size(); i++)
+ threadLocal[i].store(nullptr);
+ }
+
+ TaskScheduler::~TaskScheduler()
+ {
+ assert(threadCounter == 0);
+ }
+
+ dll_export size_t TaskScheduler::threadID()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread) return thread->threadIndex;
+ else return 0;
+ }
+
+ dll_export size_t TaskScheduler::threadIndex()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread) return thread->threadIndex;
+ else return 0;
+ }
+
+ dll_export size_t TaskScheduler::threadCount() {
+ return threadPool->size();
+ }
+
+ dll_export TaskScheduler* TaskScheduler::instance()
+ {
+ if (g_instance == NULL) {
+ Lock<MutexSys> lock(g_mutex);
+ g_instance = new TaskScheduler;
+ g_instance_vector.push_back(g_instance);
+ }
+ return g_instance;
+ }
+
+ void TaskScheduler::create(size_t numThreads, bool set_affinity, bool start_threads)
+ {
+ if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
+ threadPool->setNumThreads(numThreads,start_threads);
+ }
+
+ void TaskScheduler::destroy() {
+ delete threadPool; threadPool = nullptr;
+ }
+
+ dll_export ssize_t TaskScheduler::allocThreadIndex()
+ {
+ size_t threadIndex = threadCounter++;
+ assert(threadIndex < threadLocal.size());
+ return threadIndex;
+ }
+
+ void TaskScheduler::join()
+ {
+ mutex.lock();
+ size_t threadIndex = allocThreadIndex();
+ condition.wait(mutex, [&] () { return hasRootTask.load(); });
+ mutex.unlock();
+ // -- GODOT start --
+ // std::exception_ptr except = thread_loop(threadIndex);
+ // if (except != nullptr) std::rethrow_exception(except);
+ thread_loop(threadIndex);
+ // -- GODOT end --
+ }
+
+ void TaskScheduler::reset() {
+ hasRootTask = false;
+ }
+
+ void TaskScheduler::wait_for_threads(size_t threadCount)
+ {
+ while (threadCounter < threadCount-1)
+ pause_cpu();
+ }
+
+ dll_export TaskScheduler::Thread* TaskScheduler::thread() {
+ return thread_local_thread;
+ }
+
+ dll_export TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
+ {
+ Thread* old = thread_local_thread;
+ thread_local_thread = thread;
+ return old;
+ }
+
+ dll_export bool TaskScheduler::wait()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread == nullptr) return true;
+ while (thread->tasks.execute_local_internal(*thread,thread->task)) {};
+ return thread->scheduler->cancellingException == nullptr;
+ }
+
+// -- GODOT start --
+// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
+ void TaskScheduler::thread_loop(size_t threadIndex)
+// -- GODOT end --
+ {
+ /* allocate thread structure */
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+ Thread& thread = *mthread;
+ threadLocal[threadIndex].store(&thread);
+ Thread* oldThread = swapThread(&thread);
+
+ /* main thread loop */
+ while (anyTasksRunning)
+ {
+ steal_loop(thread,
+ [&] () { return anyTasksRunning > 0; },
+ [&] () {
+ anyTasksRunning++;
+ while (thread.tasks.execute_local_internal(thread,nullptr));
+ anyTasksRunning--;
+ });
+ }
+ threadLocal[threadIndex].store(nullptr);
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+ // -- GODOT start --
+ // std::exception_ptr except = nullptr;
+ // if (cancellingException != nullptr) except = cancellingException;
+ // -- GODOT end --
+ /* wait for all threads to terminate */
+ threadCounter--;
+#if defined(__WIN32__)
+ size_t loopIndex = 1;
+#endif
+#define LOOP_YIELD_THRESHOLD (4096)
+ while (threadCounter > 0) {
+#if defined(__WIN32__)
+ if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
+ yield();
+ else
+ _mm_pause();
+ loopIndex++;
+#else
+ yield();
+#endif
+ }
+ // -- GODOT start --
+ // return except;
+ return;
+ // -- GODOT end --
+ }
+
+ bool TaskScheduler::steal_from_other_threads(Thread& thread)
+ {
+ const size_t threadIndex = thread.threadIndex;
+ const size_t threadCount = this->threadCounter;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ pause_cpu(32);
+ size_t otherThreadIndex = threadIndex+i;
+ if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;
+
+ Thread* othread = threadLocal[otherThreadIndex].load();
+ if (!othread)
+ continue;
+
+ if (othread->tasks.steal(thread))
+ return true;
+ }
+
+ return false;
+ }
+
+ dll_export void TaskScheduler::startThreads() {
+ threadPool->startThreads();
+ }
+
+ dll_export void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
+ threadPool->add(scheduler);
+ }
+
+ dll_export void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
+ threadPool->remove(scheduler);
+ }
+
+ RTC_NAMESPACE_END
+}
diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h
new file mode 100644
index 0000000000..8bd70b2b8c
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h
@@ -0,0 +1,386 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+#include "../sys/atomic.h"
+#include "../math/range.h"
+#include "../../include/embree3/rtcore.h"
+
+#include <list>
+
+namespace embree
+{
+
+ /* The tasking system exports some symbols to be used by the tutorials. Thus we
+ hide is also in the API namespace when requested. */
+ RTC_NAMESPACE_BEGIN
+
+ struct TaskScheduler : public RefCount
+ {
+ ALIGNED_STRUCT_(64);
+ friend class Device;
+
+ static const size_t TASK_STACK_SIZE = 4*1024; //!< task structure stack
+ static const size_t CLOSURE_STACK_SIZE = 512*1024; //!< stack for task closures
+
+ struct Thread;
+
+ /*! virtual interface for all tasks */
+ struct TaskFunction {
+ virtual void execute() = 0;
+ };
+
+ /*! builds a task interface from a closure */
+ template<typename Closure>
+ struct ClosureTaskFunction : public TaskFunction
+ {
+ Closure closure;
+ __forceinline ClosureTaskFunction (const Closure& closure) : closure(closure) {}
+ void execute() { closure(); };
+ };
+
+ struct __aligned(64) Task
+ {
+ /*! states a task can be in */
+ enum { DONE, INITIALIZED };
+
+ /*! switch from one state to another */
+ __forceinline void switch_state(int from, int to)
+ {
+ __memory_barrier();
+ MAYBE_UNUSED bool success = state.compare_exchange_strong(from,to);
+ assert(success);
+ }
+
+ /*! try to switch from one state to another */
+ __forceinline bool try_switch_state(int from, int to) {
+ __memory_barrier();
+ return state.compare_exchange_strong(from,to);
+ }
+
+ /*! increment/decrement dependency counter */
+ void add_dependencies(int n) {
+ dependencies+=n;
+ }
+
+ /*! initialize all tasks to DONE state by default */
+ __forceinline Task()
+ : state(DONE) {}
+
+ /*! construction of new task */
+ __forceinline Task (TaskFunction* closure, Task* parent, size_t stackPtr, size_t N)
+ : dependencies(1), stealable(true), closure(closure), parent(parent), stackPtr(stackPtr), N(N)
+ {
+ if (parent) parent->add_dependencies(+1);
+ switch_state(DONE,INITIALIZED);
+ }
+
+ /*! construction of stolen task, stealing thread will decrement initial dependency */
+ __forceinline Task (TaskFunction* closure, Task* parent)
+ : dependencies(1), stealable(false), closure(closure), parent(parent), stackPtr(-1), N(1)
+ {
+ switch_state(DONE,INITIALIZED);
+ }
+
+ /*! try to steal this task */
+ bool try_steal(Task& child)
+ {
+ if (!stealable) return false;
+ if (!try_switch_state(INITIALIZED,DONE)) return false;
+ new (&child) Task(closure, this);
+ return true;
+ }
+
+ /*! run this task */
+ dll_export void run(Thread& thread);
+
+ void run_internal(Thread& thread);
+
+ public:
+ std::atomic<int> state; //!< state this task is in
+ std::atomic<int> dependencies; //!< dependencies to wait for
+ std::atomic<bool> stealable; //!< true if task can be stolen
+ TaskFunction* closure; //!< the closure to execute
+ Task* parent; //!< parent task to signal when we are finished
+ size_t stackPtr; //!< stack location where closure is stored
+ size_t N; //!< approximative size of task
+ };
+
+ struct TaskQueue
+ {
+ TaskQueue ()
+ : left(0), right(0), stackPtr(0) {}
+
+ __forceinline void* alloc(size_t bytes, size_t align = 64)
+ {
+ size_t ofs = bytes + ((align - stackPtr) & (align-1));
+ if (stackPtr + ofs > CLOSURE_STACK_SIZE)
+ // -- GODOT start --
+ // throw std::runtime_error("closure stack overflow");
+ abort();
+ // -- GODOT end --
+ stackPtr += ofs;
+ return &stack[stackPtr-bytes];
+ }
+
+ template<typename Closure>
+ __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure)
+ {
+ if (right >= TASK_STACK_SIZE)
+ // -- GODOT start --
+ // throw std::runtime_error("task stack overflow");
+ abort();
+ // -- GODOT end --
+
+ /* allocate new task on right side of stack */
+ size_t oldStackPtr = stackPtr;
+ TaskFunction* func = new (alloc(sizeof(ClosureTaskFunction<Closure>))) ClosureTaskFunction<Closure>(closure);
+ /* gcc 8 or later fails to compile without explicit .load() */
+ new (&(tasks[right.load()])) Task(func,thread.task,oldStackPtr,size);
+ right++;
+
+ /* also move left pointer */
+ if (left >= right-1) left = right-1;
+ }
+
+ dll_export bool execute_local(Thread& thread, Task* parent);
+ bool execute_local_internal(Thread& thread, Task* parent);
+ bool steal(Thread& thread);
+ size_t getTaskSizeAtLeft();
+
+ bool empty() { return right == 0; }
+
+ public:
+
+ /* task stack */
+ Task tasks[TASK_STACK_SIZE];
+ __aligned(64) std::atomic<size_t> left; //!< threads steal from left
+ __aligned(64) std::atomic<size_t> right; //!< new tasks are added to the right
+
+ /* closure stack */
+ __aligned(64) char stack[CLOSURE_STACK_SIZE];
+ size_t stackPtr;
+ };
+
+ /*! thread local structure for each thread */
+ struct Thread
+ {
+ ALIGNED_STRUCT_(64);
+
+ Thread (size_t threadIndex, const Ref<TaskScheduler>& scheduler)
+ : threadIndex(threadIndex), task(nullptr), scheduler(scheduler) {}
+
+ __forceinline size_t threadCount() {
+ return scheduler->threadCounter;
+ }
+
+ size_t threadIndex; //!< ID of this thread
+ TaskQueue tasks; //!< local task queue
+ Task* task; //!< current active task
+ Ref<TaskScheduler> scheduler; //!< pointer to task scheduler
+ };
+
+ /*! pool of worker threads */
+ struct ThreadPool
+ {
+ ThreadPool (bool set_affinity);
+ ~ThreadPool ();
+
+ /*! starts the threads */
+ dll_export void startThreads();
+
+ /*! sets number of threads to use */
+ void setNumThreads(size_t numThreads, bool startThreads = false);
+
+ /*! adds a task scheduler object for scheduling */
+ dll_export void add(const Ref<TaskScheduler>& scheduler);
+
+ /*! remove the task scheduler object again */
+ dll_export void remove(const Ref<TaskScheduler>& scheduler);
+
+ /*! returns number of threads of the thread pool */
+ size_t size() const { return numThreads; }
+
+ /*! main loop for all threads */
+ void thread_loop(size_t threadIndex);
+
+ private:
+ std::atomic<size_t> numThreads;
+ std::atomic<size_t> numThreadsRunning;
+ bool set_affinity;
+ std::atomic<bool> running;
+ std::vector<thread_t> threads;
+
+ private:
+ MutexSys mutex;
+ ConditionSys condition;
+ std::list<Ref<TaskScheduler> > schedulers;
+ };
+
+ TaskScheduler ();
+ ~TaskScheduler ();
+
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /*! lets new worker threads join the tasking system */
+ void join();
+ void reset();
+
+ /*! let a worker thread allocate a thread index */
+ dll_export ssize_t allocThreadIndex();
+
+ /*! wait for some number of threads available (threadCount includes main thread) */
+ void wait_for_threads(size_t threadCount);
+
+ /*! thread loop for all worker threads */
+ // -- GODOT start --
+ // std::exception_ptr thread_loop(size_t threadIndex);
+ void thread_loop(size_t threadIndex);
+ // -- GODOT end --
+
+ /*! steals a task from a different thread */
+ bool steal_from_other_threads(Thread& thread);
+
+ template<typename Predicate, typename Body>
+ static void steal_loop(Thread& thread, const Predicate& pred, const Body& body);
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ void spawn_root(const Closure& closure, size_t size = 1, bool useThreadPool = true)
+ {
+ if (useThreadPool) startThreads();
+
+ size_t threadIndex = allocThreadIndex();
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+ Thread& thread = *mthread;
+ assert(threadLocal[threadIndex].load() == nullptr);
+ threadLocal[threadIndex] = &thread;
+ Thread* oldThread = swapThread(&thread);
+ thread.tasks.push_right(thread,size,closure);
+ {
+ Lock<MutexSys> lock(mutex);
+ anyTasksRunning++;
+ hasRootTask = true;
+ condition.notify_all();
+ }
+
+ if (useThreadPool) addScheduler(this);
+
+ while (thread.tasks.execute_local(thread,nullptr));
+ anyTasksRunning--;
+ if (useThreadPool) removeScheduler(this);
+
+ threadLocal[threadIndex] = nullptr;
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+ std::exception_ptr except = nullptr;
+ if (cancellingException != nullptr) except = cancellingException;
+
+ /* wait for all threads to terminate */
+ threadCounter--;
+ while (threadCounter > 0) yield();
+ cancellingException = nullptr;
+
+ /* re-throw proper exception */
+ if (except != nullptr)
+ std::rethrow_exception(except);
+ }
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ static __forceinline void spawn(size_t size, const Closure& closure)
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (likely(thread != nullptr)) thread->tasks.push_right(*thread,size,closure);
+ else instance()->spawn_root(closure,size);
+ }
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ static __forceinline void spawn(const Closure& closure) {
+ spawn(1,closure);
+ }
+
+ /* spawn a new task set */
+ template<typename Index, typename Closure>
+ static void spawn(const Index begin, const Index end, const Index blockSize, const Closure& closure)
+ {
+ spawn(end-begin, [=]()
+ {
+ if (end-begin <= blockSize) {
+ return closure(range<Index>(begin,end));
+ }
+ const Index center = (begin+end)/2;
+ spawn(begin,center,blockSize,closure);
+ spawn(center,end ,blockSize,closure);
+ wait();
+ });
+ }
+
+ /* work on spawned subtasks and wait until all have finished */
+ dll_export static bool wait();
+
+ /* returns the ID of the current thread */
+ dll_export static size_t threadID();
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ dll_export static size_t threadIndex();
+
+ /* returns the total number of threads */
+ dll_export static size_t threadCount();
+
+ private:
+
+ /* returns the thread local task list of this worker thread */
+ dll_export static Thread* thread();
+
+ /* sets the thread local task list of this worker thread */
+ dll_export static Thread* swapThread(Thread* thread);
+
+ /*! returns the taskscheduler object to be used by the master thread */
+ dll_export static TaskScheduler* instance();
+
+ /*! starts the threads */
+ dll_export static void startThreads();
+
+ /*! adds a task scheduler object for scheduling */
+ dll_export static void addScheduler(const Ref<TaskScheduler>& scheduler);
+
+ /*! remove the task scheduler object again */
+ dll_export static void removeScheduler(const Ref<TaskScheduler>& scheduler);
+
+ private:
+ std::vector<atomic<Thread*>> threadLocal;
+ std::atomic<size_t> threadCounter;
+ std::atomic<size_t> anyTasksRunning;
+ std::atomic<bool> hasRootTask;
+ std::exception_ptr cancellingException;
+ MutexSys mutex;
+ ConditionSys condition;
+
+ private:
+ static size_t g_numThreads;
+ static __thread TaskScheduler* g_instance;
+ static __thread Thread* thread_local_thread;
+ static ThreadPool* threadPool;
+ };
+
+ RTC_NAMESPACE_END
+
+#if defined(RTC_NAMESPACE)
+ using RTC_NAMESPACE::TaskScheduler;
+#endif
+}
diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulerppl.h b/thirdparty/embree-aarch64/common/tasking/taskschedulerppl.h
new file mode 100644
index 0000000000..776f98cdac
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskschedulerppl.h
@@ -0,0 +1,46 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+
+#if !defined(__WIN32__)
+#error PPL tasking system only available under windows
+#endif
+
+#include <ppl.h>
+
+namespace embree
+{
+ struct TaskScheduler
+ {
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /* returns the ID of the current thread */
+ static __forceinline size_t threadID() {
+ return GetCurrentThreadId();
+ }
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ /* FIXME: threadIndex is NOT supported by PPL! */
+ static __forceinline size_t threadIndex() {
+ return 0;
+ }
+
+ /* returns the total number of threads */
+ static __forceinline size_t threadCount() {
+ return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS) + 1;
+ }
+ };
+};
diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulertbb.h b/thirdparty/embree-aarch64/common/tasking/taskschedulertbb.h
new file mode 100644
index 0000000000..98dba26871
--- /dev/null
+++ b/thirdparty/embree-aarch64/common/tasking/taskschedulertbb.h
@@ -0,0 +1,67 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+
+#if defined(__WIN32__)
+# define NOMINMAX
+#endif
+
+// We need to define these to avoid implicit linkage against
+// tbb_debug.lib under Windows. When removing these lines debug build
+// under Windows fails.
+#define __TBB_NO_IMPLICIT_LINKAGE 1
+#define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1
+#define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+#define TBB_PREVIEW_ISOLATED_TASK_GROUP 1
+#include "tbb/tbb.h"
+#include "tbb/parallel_sort.h"
+
+namespace embree
+{
+ struct TaskScheduler
+ {
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /* returns the ID of the current thread */
+ static __forceinline size_t threadID()
+ {
+ return threadIndex();
+ }
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ static __forceinline size_t threadIndex()
+ {
+#if TBB_INTERFACE_VERSION >= 9100
+ return tbb::this_task_arena::current_thread_index();
+#elif TBB_INTERFACE_VERSION >= 9000
+ return tbb::task_arena::current_thread_index();
+#else
+ return 0;
+#endif
+ }
+
+ /* returns the total number of threads */
+ static __forceinline size_t threadCount() {
+#if TBB_INTERFACE_VERSION >= 9100
+ return tbb::this_task_arena::max_concurrency();
+#else
+ return tbb::task_scheduler_init::default_num_threads();
+#endif
+ }
+
+ };
+
+};
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore.h b/thirdparty/embree-aarch64/include/embree3/rtcore.h
new file mode 100644
index 0000000000..5830bb5880
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore.h
@@ -0,0 +1,14 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_config.h"
+#include "rtcore_common.h"
+#include "rtcore_device.h"
+#include "rtcore_buffer.h"
+#include "rtcore_ray.h"
+#include "rtcore_geometry.h"
+#include "rtcore_scene.h"
+#include "rtcore_builder.h"
+#include "rtcore_quaternion.h"
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_buffer.h b/thirdparty/embree-aarch64/include/embree3/rtcore_buffer.h
new file mode 100644
index 0000000000..400b604aa5
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_buffer.h
@@ -0,0 +1,51 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_device.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Types of buffers */
+enum RTCBufferType
+{
+ RTC_BUFFER_TYPE_INDEX = 0,
+ RTC_BUFFER_TYPE_VERTEX = 1,
+ RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE = 2,
+ RTC_BUFFER_TYPE_NORMAL = 3,
+ RTC_BUFFER_TYPE_TANGENT = 4,
+ RTC_BUFFER_TYPE_NORMAL_DERIVATIVE = 5,
+
+ RTC_BUFFER_TYPE_GRID = 8,
+
+ RTC_BUFFER_TYPE_FACE = 16,
+ RTC_BUFFER_TYPE_LEVEL = 17,
+ RTC_BUFFER_TYPE_EDGE_CREASE_INDEX = 18,
+ RTC_BUFFER_TYPE_EDGE_CREASE_WEIGHT = 19,
+ RTC_BUFFER_TYPE_VERTEX_CREASE_INDEX = 20,
+ RTC_BUFFER_TYPE_VERTEX_CREASE_WEIGHT = 21,
+ RTC_BUFFER_TYPE_HOLE = 22,
+
+ RTC_BUFFER_TYPE_FLAGS = 32
+};
+
+/* Opaque buffer type */
+typedef struct RTCBufferTy* RTCBuffer;
+
+/* Creates a new buffer. */
+RTC_API RTCBuffer rtcNewBuffer(RTCDevice device, size_t byteSize);
+
+/* Creates a new shared buffer. */
+RTC_API RTCBuffer rtcNewSharedBuffer(RTCDevice device, void* ptr, size_t byteSize);
+
+/* Returns a pointer to the buffer data. */
+RTC_API void* rtcGetBufferData(RTCBuffer buffer);
+
+/* Retains the buffer (increments the reference count). */
+RTC_API void rtcRetainBuffer(RTCBuffer buffer);
+
+/* Releases the buffer (decrements the reference count). */
+RTC_API void rtcReleaseBuffer(RTCBuffer buffer);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_builder.h b/thirdparty/embree-aarch64/include/embree3/rtcore_builder.h
new file mode 100644
index 0000000000..d62a7f72cc
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_builder.h
@@ -0,0 +1,125 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_scene.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque BVH type */
+typedef struct RTCBVHTy* RTCBVH;
+
+/* Input build primitives for the builder */
+struct RTC_ALIGN(32) RTCBuildPrimitive
+{
+ float lower_x, lower_y, lower_z;
+ unsigned int geomID;
+ float upper_x, upper_y, upper_z;
+ unsigned int primID;
+};
+
+/* Opaque thread local allocator type */
+typedef struct RTCThreadLocalAllocatorTy* RTCThreadLocalAllocator;
+
+/* Callback to create a node */
+typedef void* (*RTCCreateNodeFunction) (RTCThreadLocalAllocator allocator, unsigned int childCount, void* userPtr);
+
+/* Callback to set the pointer to all children */
+typedef void (*RTCSetNodeChildrenFunction) (void* nodePtr, void** children, unsigned int childCount, void* userPtr);
+
+/* Callback to set the bounds of all children */
+typedef void (*RTCSetNodeBoundsFunction) (void* nodePtr, const struct RTCBounds** bounds, unsigned int childCount, void* userPtr);
+
+/* Callback to create a leaf node */
+typedef void* (*RTCCreateLeafFunction) (RTCThreadLocalAllocator allocator, const struct RTCBuildPrimitive* primitives, size_t primitiveCount, void* userPtr);
+
+/* Callback to split a build primitive */
+typedef void (*RTCSplitPrimitiveFunction) (const struct RTCBuildPrimitive* primitive, unsigned int dimension, float position, struct RTCBounds* leftBounds, struct RTCBounds* rightBounds, void* userPtr);
+
+/* Build flags */
+enum RTCBuildFlags
+{
+ RTC_BUILD_FLAG_NONE = 0,
+ RTC_BUILD_FLAG_DYNAMIC = (1 << 0),
+};
+
+enum RTCBuildConstants
+{
+ RTC_BUILD_MAX_PRIMITIVES_PER_LEAF = 32
+};
+
+/* Input for builders */
+struct RTCBuildArguments
+{
+ size_t byteSize;
+
+ enum RTCBuildQuality buildQuality;
+ enum RTCBuildFlags buildFlags;
+ unsigned int maxBranchingFactor;
+ unsigned int maxDepth;
+ unsigned int sahBlockSize;
+ unsigned int minLeafSize;
+ unsigned int maxLeafSize;
+ float traversalCost;
+ float intersectionCost;
+
+ RTCBVH bvh;
+ struct RTCBuildPrimitive* primitives;
+ size_t primitiveCount;
+ size_t primitiveArrayCapacity;
+
+ RTCCreateNodeFunction createNode;
+ RTCSetNodeChildrenFunction setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds;
+ RTCCreateLeafFunction createLeaf;
+ RTCSplitPrimitiveFunction splitPrimitive;
+ RTCProgressMonitorFunction buildProgress;
+ void* userPtr;
+};
+
+/* Returns the default build settings. */
+RTC_FORCEINLINE struct RTCBuildArguments rtcDefaultBuildArguments()
+{
+ struct RTCBuildArguments args;
+ args.byteSize = sizeof(args);
+ args.buildQuality = RTC_BUILD_QUALITY_MEDIUM;
+ args.buildFlags = RTC_BUILD_FLAG_NONE;
+ args.maxBranchingFactor = 2;
+ args.maxDepth = 32;
+ args.sahBlockSize = 1;
+ args.minLeafSize = 1;
+ args.maxLeafSize = RTC_BUILD_MAX_PRIMITIVES_PER_LEAF;
+ args.traversalCost = 1.0f;
+ args.intersectionCost = 1.0f;
+ args.bvh = NULL;
+ args.primitives = NULL;
+ args.primitiveCount = 0;
+ args.primitiveArrayCapacity = 0;
+ args.createNode = NULL;
+ args.setNodeChildren = NULL;
+ args.setNodeBounds = NULL;
+ args.createLeaf = NULL;
+ args.splitPrimitive = NULL;
+ args.buildProgress = NULL;
+ args.userPtr = NULL;
+ return args;
+}
+
+/* Creates a new BVH. */
+RTC_API RTCBVH rtcNewBVH(RTCDevice device);
+
+/* Builds a BVH. */
+RTC_API void* rtcBuildBVH(const struct RTCBuildArguments* args);
+
+/* Allocates memory using the thread local allocator. */
+RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator allocator, size_t bytes, size_t align);
+
+/* Retains the BVH (increments reference count). */
+RTC_API void rtcRetainBVH(RTCBVH bvh);
+
+/* Releases the BVH (decrements reference count). */
+RTC_API void rtcReleaseBVH(RTCBVH bvh);
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_common.h b/thirdparty/embree-aarch64/include/embree3/rtcore_common.h
new file mode 100644
index 0000000000..890e06faa3
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_common.h
@@ -0,0 +1,326 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include "rtcore_config.h"
+
+RTC_NAMESPACE_BEGIN
+
+#if defined(_WIN32)
+#if defined(_M_X64)
+typedef long long ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+# define RTC_ALIGN(...) __declspec(align(__VA_ARGS__))
+#else
+# define RTC_ALIGN(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#if !defined (RTC_DEPRECATED)
+#ifdef __GNUC__
+ #define RTC_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+ #define RTC_DEPRECATED __declspec(deprecated)
+#else
+ #define RTC_DEPRECATED
+#endif
+#endif
+
+#if defined(_WIN32)
+# define RTC_FORCEINLINE __forceinline
+#else
+# define RTC_FORCEINLINE inline __attribute__((always_inline))
+#endif
+
+/* Invalid geometry ID */
+#define RTC_INVALID_GEOMETRY_ID ((unsigned int)-1)
+
+/* Maximum number of time steps */
+#define RTC_MAX_TIME_STEP_COUNT 129
+
+/* Formats of buffers and other data structures */
+enum RTCFormat
+{
+ RTC_FORMAT_UNDEFINED = 0,
+
+ /* 8-bit unsigned integer */
+ RTC_FORMAT_UCHAR = 0x1001,
+ RTC_FORMAT_UCHAR2,
+ RTC_FORMAT_UCHAR3,
+ RTC_FORMAT_UCHAR4,
+
+ /* 8-bit signed integer */
+ RTC_FORMAT_CHAR = 0x2001,
+ RTC_FORMAT_CHAR2,
+ RTC_FORMAT_CHAR3,
+ RTC_FORMAT_CHAR4,
+
+ /* 16-bit unsigned integer */
+ RTC_FORMAT_USHORT = 0x3001,
+ RTC_FORMAT_USHORT2,
+ RTC_FORMAT_USHORT3,
+ RTC_FORMAT_USHORT4,
+
+ /* 16-bit signed integer */
+ RTC_FORMAT_SHORT = 0x4001,
+ RTC_FORMAT_SHORT2,
+ RTC_FORMAT_SHORT3,
+ RTC_FORMAT_SHORT4,
+
+ /* 32-bit unsigned integer */
+ RTC_FORMAT_UINT = 0x5001,
+ RTC_FORMAT_UINT2,
+ RTC_FORMAT_UINT3,
+ RTC_FORMAT_UINT4,
+
+ /* 32-bit signed integer */
+ RTC_FORMAT_INT = 0x6001,
+ RTC_FORMAT_INT2,
+ RTC_FORMAT_INT3,
+ RTC_FORMAT_INT4,
+
+ /* 64-bit unsigned integer */
+ RTC_FORMAT_ULLONG = 0x7001,
+ RTC_FORMAT_ULLONG2,
+ RTC_FORMAT_ULLONG3,
+ RTC_FORMAT_ULLONG4,
+
+ /* 64-bit signed integer */
+ RTC_FORMAT_LLONG = 0x8001,
+ RTC_FORMAT_LLONG2,
+ RTC_FORMAT_LLONG3,
+ RTC_FORMAT_LLONG4,
+
+ /* 32-bit float */
+ RTC_FORMAT_FLOAT = 0x9001,
+ RTC_FORMAT_FLOAT2,
+ RTC_FORMAT_FLOAT3,
+ RTC_FORMAT_FLOAT4,
+ RTC_FORMAT_FLOAT5,
+ RTC_FORMAT_FLOAT6,
+ RTC_FORMAT_FLOAT7,
+ RTC_FORMAT_FLOAT8,
+ RTC_FORMAT_FLOAT9,
+ RTC_FORMAT_FLOAT10,
+ RTC_FORMAT_FLOAT11,
+ RTC_FORMAT_FLOAT12,
+ RTC_FORMAT_FLOAT13,
+ RTC_FORMAT_FLOAT14,
+ RTC_FORMAT_FLOAT15,
+ RTC_FORMAT_FLOAT16,
+
+ /* 32-bit float matrix (row-major order) */
+ RTC_FORMAT_FLOAT2X2_ROW_MAJOR = 0x9122,
+ RTC_FORMAT_FLOAT2X3_ROW_MAJOR = 0x9123,
+ RTC_FORMAT_FLOAT2X4_ROW_MAJOR = 0x9124,
+ RTC_FORMAT_FLOAT3X2_ROW_MAJOR = 0x9132,
+ RTC_FORMAT_FLOAT3X3_ROW_MAJOR = 0x9133,
+ RTC_FORMAT_FLOAT3X4_ROW_MAJOR = 0x9134,
+ RTC_FORMAT_FLOAT4X2_ROW_MAJOR = 0x9142,
+ RTC_FORMAT_FLOAT4X3_ROW_MAJOR = 0x9143,
+ RTC_FORMAT_FLOAT4X4_ROW_MAJOR = 0x9144,
+
+ /* 32-bit float matrix (column-major order) */
+ RTC_FORMAT_FLOAT2X2_COLUMN_MAJOR = 0x9222,
+ RTC_FORMAT_FLOAT2X3_COLUMN_MAJOR = 0x9223,
+ RTC_FORMAT_FLOAT2X4_COLUMN_MAJOR = 0x9224,
+ RTC_FORMAT_FLOAT3X2_COLUMN_MAJOR = 0x9232,
+ RTC_FORMAT_FLOAT3X3_COLUMN_MAJOR = 0x9233,
+ RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR = 0x9234,
+ RTC_FORMAT_FLOAT4X2_COLUMN_MAJOR = 0x9242,
+ RTC_FORMAT_FLOAT4X3_COLUMN_MAJOR = 0x9243,
+ RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR = 0x9244,
+
+ /* special 12-byte format for grids */
+ RTC_FORMAT_GRID = 0xA001
+};
+
+/* Build quality levels */
+enum RTCBuildQuality
+{
+ RTC_BUILD_QUALITY_LOW = 0,
+ RTC_BUILD_QUALITY_MEDIUM = 1,
+ RTC_BUILD_QUALITY_HIGH = 2,
+ RTC_BUILD_QUALITY_REFIT = 3,
+};
+
+/* Axis-aligned bounding box representation */
+struct RTC_ALIGN(16) RTCBounds
+{
+ float lower_x, lower_y, lower_z, align0;
+ float upper_x, upper_y, upper_z, align1;
+};
+
+/* Linear axis-aligned bounding box representation */
+struct RTC_ALIGN(16) RTCLinearBounds
+{
+ struct RTCBounds bounds0;
+ struct RTCBounds bounds1;
+};
+
+/* Intersection context flags */
+enum RTCIntersectContextFlags
+{
+ RTC_INTERSECT_CONTEXT_FLAG_NONE = 0,
+ RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT = (0 << 0), // optimize for incoherent rays
+ RTC_INTERSECT_CONTEXT_FLAG_COHERENT = (1 << 0) // optimize for coherent rays
+};
+
+/* Arguments for RTCFilterFunctionN */
+struct RTCFilterFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ struct RTCIntersectContext* context;
+ struct RTCRayN* ray;
+ struct RTCHitN* hit;
+ unsigned int N;
+};
+
+/* Filter callback function */
+typedef void (*RTCFilterFunctionN)(const struct RTCFilterFunctionNArguments* args);
+
+/* Intersection context passed to intersect/occluded calls */
+struct RTCIntersectContext
+{
+ enum RTCIntersectContextFlags flags; // intersection flags
+ RTCFilterFunctionN filter; // filter function to execute
+
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ unsigned int instStackSize; // Number of instances currently on the stack.
+#endif
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // The current stack of instance ids.
+
+#if RTC_MIN_WIDTH
+ float minWidthDistanceFactor; // curve radius is set to this factor times distance to ray origin
+#endif
+};
+
+/* Initializes an intersection context. */
+RTC_FORCEINLINE void rtcInitIntersectContext(struct RTCIntersectContext* context)
+{
+ unsigned l = 0;
+ context->flags = RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT;
+ context->filter = NULL;
+
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ context->instStackSize = 0;
+#endif
+ for (; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ context->instID[l] = RTC_INVALID_GEOMETRY_ID;
+
+#if RTC_MIN_WIDTH
+ context->minWidthDistanceFactor = 0.0f;
+#endif
+}
+
+/* Point query structure for closest point query */
+struct RTC_ALIGN(16) RTCPointQuery
+{
+ float x; // x coordinate of the query point
+ float y; // y coordinate of the query point
+ float z; // z coordinate of the query point
+ float time; // time of the point query
+ float radius; // radius of the point query
+};
+
+/* Structure of a packet of 4 query points */
+struct RTC_ALIGN(16) RTCPointQuery4
+{
+ float x[4]; // x coordinate of the query point
+ float y[4]; // y coordinate of the query point
+ float z[4]; // z coordinate of the query point
+ float time[4]; // time of the point query
+ float radius[4]; // radius of the point query
+};
+
+/* Structure of a packet of 8 query points */
+struct RTC_ALIGN(32) RTCPointQuery8
+{
+ float x[8]; // x coordinate of the query point
+ float y[8]; // y coordinate of the query point
+ float z[8]; // z coordinate of the query point
+ float time[8]; // time of the point query
+ float radius[8]; // radius ofr the point query
+};
+
+/* Structure of a packet of 16 query points */
+struct RTC_ALIGN(64) RTCPointQuery16
+{
+ float x[16]; // x coordinate of the query point
+ float y[16]; // y coordinate of the query point
+ float z[16]; // z coordinate of the query point
+ float time[16]; // time of the point quey
+ float radius[16]; // radius of the point query
+};
+
+struct RTCPointQueryN;
+
+struct RTC_ALIGN(16) RTCPointQueryContext
+{
+ // accumulated 4x4 column major matrices from world space to instance space.
+ // undefined if size == 0.
+ float world2inst[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+
+ // accumulated 4x4 column major matrices from instance space to world space.
+ // undefined if size == 0.
+ float inst2world[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+
+ // instance ids.
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT];
+
+ // number of instances currently on the stack.
+ unsigned int instStackSize;
+};
+
+/* Initializes an intersection context. */
+RTC_FORCEINLINE void rtcInitPointQueryContext(struct RTCPointQueryContext* context)
+{
+ context->instStackSize = 0;
+ context->instID[0] = RTC_INVALID_GEOMETRY_ID;
+}
+
+struct RTC_ALIGN(16) RTCPointQueryFunctionArguments
+{
+ // The (world space) query object that was passed as an argument of rtcPointQuery. The
+ // radius of the query can be decreased inside the callback to shrink the
+ // search domain. Increasing the radius or modifying the time or position of
+ // the query results in undefined behaviour.
+ struct RTCPointQuery* query;
+
+ // Used for user input/output data. Will not be read or modified internally.
+ void* userPtr;
+
+ // primitive and geometry ID of primitive
+ unsigned int primID;
+ unsigned int geomID;
+
+ // the context with transformation and instance ID stack
+ struct RTCPointQueryContext* context;
+
+ // If the current instance transform M (= context->world2inst[context->instStackSize])
+ // is a similarity matrix, i.e there is a constant factor similarityScale such that,
+ // for all x,y: dist(Mx, My) = similarityScale * dist(x, y),
+ // The similarity scale is 0, if the current instance transform is not a
+ // similarity transform and vice versa. The similarity scale allows to compute
+ // distance information in instance space and scale the distances into world
+ // space by dividing with the similarity scale, for example, to update the
+ // query radius. If the current instance transform is not a similarity
+ // transform (similarityScale = 0), the distance computation has to be
+ // performed in world space to ensure correctness. if there is no instance
+ // transform (context->instStackSize == 0), the similarity scale is 1.
+ float similarityScale;
+};
+
+typedef bool (*RTCPointQueryFunction)(struct RTCPointQueryFunctionArguments* args);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_config.h b/thirdparty/embree-aarch64/include/embree3/rtcore_config.h
new file mode 100644
index 0000000000..337d4e9487
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_config.h
@@ -0,0 +1,57 @@
+
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define RTC_VERSION_MAJOR 3
+#define RTC_VERSION_MINOR 12
+#define RTC_VERSION_PATCH 1
+#define RTC_VERSION 31201
+#define RTC_VERSION_STRING "3.12.1"
+
+#define RTC_MAX_INSTANCE_LEVEL_COUNT 1
+
+#define EMBREE_MIN_WIDTH 0
+#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+
+#define EMBREE_STATIC_LIB
+/* #undef EMBREE_API_NAMESPACE */
+
+#if defined(EMBREE_API_NAMESPACE)
+# define RTC_NAMESPACE
+# define RTC_NAMESPACE_BEGIN namespace {
+# define RTC_NAMESPACE_END }
+# define RTC_NAMESPACE_USE using namespace ;
+# define RTC_API_EXTERN_C
+# undef EMBREE_API_NAMESPACE
+#else
+# define RTC_NAMESPACE_BEGIN
+# define RTC_NAMESPACE_END
+# define RTC_NAMESPACE_USE
+# if defined(__cplusplus)
+# define RTC_API_EXTERN_C extern "C"
+# else
+# define RTC_API_EXTERN_C
+# endif
+#endif
+
+#if defined(ISPC)
+# define RTC_API_IMPORT extern "C" unmasked
+# define RTC_API_EXPORT extern "C" unmasked
+#elif defined(EMBREE_STATIC_LIB)
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C
+#elif defined(_WIN32)
+# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport)
+# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport)
+#else
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default")))
+#endif
+
+#if defined(RTC_EXPORT_API)
+# define RTC_API RTC_API_EXPORT
+#else
+# define RTC_API RTC_API_IMPORT
+#endif
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_device.h b/thirdparty/embree-aarch64/include/embree3/rtcore_device.h
new file mode 100644
index 0000000000..594e2b755d
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_device.h
@@ -0,0 +1,87 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque device type */
+typedef struct RTCDeviceTy* RTCDevice;
+
+/* Creates a new Embree device. */
+RTC_API RTCDevice rtcNewDevice(const char* config);
+
+/* Retains the Embree device (increments the reference count). */
+RTC_API void rtcRetainDevice(RTCDevice device);
+
+/* Releases an Embree device (decrements the reference count). */
+RTC_API void rtcReleaseDevice(RTCDevice device);
+
+/* Device properties */
+enum RTCDeviceProperty
+{
+ RTC_DEVICE_PROPERTY_VERSION = 0,
+ RTC_DEVICE_PROPERTY_VERSION_MAJOR = 1,
+ RTC_DEVICE_PROPERTY_VERSION_MINOR = 2,
+ RTC_DEVICE_PROPERTY_VERSION_PATCH = 3,
+
+ RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED = 32,
+ RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED = 33,
+ RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED = 34,
+ RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED = 35,
+
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED = 63,
+ RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED = 64,
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED = 65,
+ RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED = 66,
+ RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED = 67,
+ RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED = 68,
+
+ RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED = 96,
+ RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED = 97,
+ RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED = 98,
+ RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED = 99,
+ RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED = 100,
+ RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED = 101,
+
+ RTC_DEVICE_PROPERTY_TASKING_SYSTEM = 128,
+ RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED = 129,
+ RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED = 130
+};
+
+/* Gets a device property. */
+RTC_API ssize_t rtcGetDeviceProperty(RTCDevice device, enum RTCDeviceProperty prop);
+
+/* Sets a device property. */
+RTC_API void rtcSetDeviceProperty(RTCDevice device, const enum RTCDeviceProperty prop, ssize_t value);
+
+/* Error codes */
+enum RTCError
+{
+ RTC_ERROR_NONE = 0,
+ RTC_ERROR_UNKNOWN = 1,
+ RTC_ERROR_INVALID_ARGUMENT = 2,
+ RTC_ERROR_INVALID_OPERATION = 3,
+ RTC_ERROR_OUT_OF_MEMORY = 4,
+ RTC_ERROR_UNSUPPORTED_CPU = 5,
+ RTC_ERROR_CANCELLED = 6
+};
+
+/* Returns the error code. */
+RTC_API enum RTCError rtcGetDeviceError(RTCDevice device);
+
+/* Error callback function */
+typedef void (*RTCErrorFunction)(void* userPtr, enum RTCError code, const char* str);
+
+/* Sets the error callback function. */
+RTC_API void rtcSetDeviceErrorFunction(RTCDevice device, RTCErrorFunction error, void* userPtr);
+
+/* Memory monitor callback function */
+typedef bool (*RTCMemoryMonitorFunction)(void* ptr, ssize_t bytes, bool post);
+
+/* Sets the memory monitor callback function. */
+RTC_API void rtcSetDeviceMemoryMonitorFunction(RTCDevice device, RTCMemoryMonitorFunction memoryMonitor, void* userPtr);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_geometry.h b/thirdparty/embree-aarch64/include/embree3/rtcore_geometry.h
new file mode 100644
index 0000000000..c70f1b0e5c
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_geometry.h
@@ -0,0 +1,383 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_buffer.h"
+#include "rtcore_quaternion.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque scene type */
+typedef struct RTCSceneTy* RTCScene;
+
+/* Opaque geometry type */
+typedef struct RTCGeometryTy* RTCGeometry;
+
+/* Types of geometries */
+enum RTCGeometryType
+{
+ RTC_GEOMETRY_TYPE_TRIANGLE = 0, // triangle mesh
+ RTC_GEOMETRY_TYPE_QUAD = 1, // quad (triangle pair) mesh
+ RTC_GEOMETRY_TYPE_GRID = 2, // grid mesh
+
+ RTC_GEOMETRY_TYPE_SUBDIVISION = 8, // Catmull-Clark subdivision surface
+
+ RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE = 15, // Cone linear curves - discontinuous at edge boundaries
+ RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE = 16, // Round (rounded cone like) linear curves
+ RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE = 17, // flat (ribbon-like) linear curves
+
+ RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE = 24, // round (tube-like) Bezier curves
+ RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE = 25, // flat (ribbon-like) Bezier curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE = 26, // flat normal-oriented Bezier curves
+
+ RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE = 32, // round (tube-like) B-spline curves
+ RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE = 33, // flat (ribbon-like) B-spline curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE = 34, // flat normal-oriented B-spline curves
+
+ RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE = 40, // round (tube-like) Hermite curves
+ RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE = 41, // flat (ribbon-like) Hermite curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE = 42, // flat normal-oriented Hermite curves
+
+ RTC_GEOMETRY_TYPE_SPHERE_POINT = 50,
+ RTC_GEOMETRY_TYPE_DISC_POINT = 51,
+ RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT = 52,
+
+ RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE = 58, // round (tube-like) Catmull-Rom curves
+ RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE = 59, // flat (ribbon-like) Catmull-Rom curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE = 60, // flat normal-oriented Catmull-Rom curves
+
+ RTC_GEOMETRY_TYPE_USER = 120, // user-defined geometry
+ RTC_GEOMETRY_TYPE_INSTANCE = 121 // scene instance
+};
+
+/* Interpolation modes for subdivision surfaces */
+enum RTCSubdivisionMode
+{
+ RTC_SUBDIVISION_MODE_NO_BOUNDARY = 0,
+ RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY = 1,
+ RTC_SUBDIVISION_MODE_PIN_CORNERS = 2,
+ RTC_SUBDIVISION_MODE_PIN_BOUNDARY = 3,
+ RTC_SUBDIVISION_MODE_PIN_ALL = 4,
+};
+
+/* Curve segment flags */
+enum RTCCurveFlags
+{
+ RTC_CURVE_FLAG_NEIGHBOR_LEFT = (1 << 0), // left segments exists
+ RTC_CURVE_FLAG_NEIGHBOR_RIGHT = (1 << 1) // right segment exists
+};
+
+/* Arguments for RTCBoundsFunction */
+struct RTCBoundsFunctionArguments
+{
+ void* geometryUserPtr;
+ unsigned int primID;
+ unsigned int timeStep;
+ struct RTCBounds* bounds_o;
+};
+
+/* Bounding callback function */
+typedef void (*RTCBoundsFunction)(const struct RTCBoundsFunctionArguments* args);
+
+/* Arguments for RTCIntersectFunctionN */
+struct RTCIntersectFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ unsigned int primID;
+ struct RTCIntersectContext* context;
+ struct RTCRayHitN* rayhit;
+ unsigned int N;
+ unsigned int geomID;
+};
+
+/* Intersection callback function */
+typedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments* args);
+
+/* Arguments for RTCOccludedFunctionN */
+struct RTCOccludedFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ unsigned int primID;
+ struct RTCIntersectContext* context;
+ struct RTCRayN* ray;
+ unsigned int N;
+ unsigned int geomID;
+};
+
+/* Occlusion callback function */
+typedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments* args);
+
+/* Arguments for RTCDisplacementFunctionN */
+struct RTCDisplacementFunctionNArguments
+{
+ void* geometryUserPtr;
+ RTCGeometry geometry;
+ unsigned int primID;
+ unsigned int timeStep;
+ const float* u;
+ const float* v;
+ const float* Ng_x;
+ const float* Ng_y;
+ const float* Ng_z;
+ float* P_x;
+ float* P_y;
+ float* P_z;
+ unsigned int N;
+};
+
+/* Displacement mapping callback function */
+typedef void (*RTCDisplacementFunctionN)(const struct RTCDisplacementFunctionNArguments* args);
+
+/* Creates a new geometry of specified type. */
+RTC_API RTCGeometry rtcNewGeometry(RTCDevice device, enum RTCGeometryType type);
+
+/* Retains the geometry (increments the reference count). */
+RTC_API void rtcRetainGeometry(RTCGeometry geometry);
+
+/* Releases the geometry (decrements the reference count) */
+RTC_API void rtcReleaseGeometry(RTCGeometry geometry);
+
+/* Commits the geometry. */
+RTC_API void rtcCommitGeometry(RTCGeometry geometry);
+
+
+/* Enables the geometry. */
+RTC_API void rtcEnableGeometry(RTCGeometry geometry);
+
+/* Disables the geometry. */
+RTC_API void rtcDisableGeometry(RTCGeometry geometry);
+
+
+/* Sets the number of motion blur time steps of the geometry. */
+RTC_API void rtcSetGeometryTimeStepCount(RTCGeometry geometry, unsigned int timeStepCount);
+
+/* Sets the motion blur time range of the geometry. */
+RTC_API void rtcSetGeometryTimeRange(RTCGeometry geometry, float startTime, float endTime);
+
+/* Sets the number of vertex attributes of the geometry. */
+RTC_API void rtcSetGeometryVertexAttributeCount(RTCGeometry geometry, unsigned int vertexAttributeCount);
+
+/* Sets the ray mask of the geometry. */
+RTC_API void rtcSetGeometryMask(RTCGeometry geometry, unsigned int mask);
+
+/* Sets the build quality of the geometry. */
+RTC_API void rtcSetGeometryBuildQuality(RTCGeometry geometry, enum RTCBuildQuality quality);
+
+/* Sets the maximal curve or point radius scale allowed by min-width feature. */
+RTC_API void rtcSetGeometryMaxRadiusScale(RTCGeometry geometry, float maxRadiusScale);
+
+
+/* Sets a geometry buffer. */
+RTC_API void rtcSetGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, RTCBuffer buffer, size_t byteOffset, size_t byteStride, size_t itemCount);
+
+/* Sets a shared geometry buffer. */
+RTC_API void rtcSetSharedGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, const void* ptr, size_t byteOffset, size_t byteStride, size_t itemCount);
+
+/* Creates and sets a new geometry buffer. */
+RTC_API void* rtcSetNewGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, size_t byteStride, size_t itemCount);
+
+/* Returns the pointer to the data of a buffer. */
+RTC_API void* rtcGetGeometryBufferData(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot);
+
+/* Updates a geometry buffer. */
+RTC_API void rtcUpdateGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot);
+
+
+/* Sets the intersection filter callback function of the geometry. */
+RTC_API void rtcSetGeometryIntersectFilterFunction(RTCGeometry geometry, RTCFilterFunctionN filter);
+
+/* Sets the occlusion filter callback function of the geometry. */
+RTC_API void rtcSetGeometryOccludedFilterFunction(RTCGeometry geometry, RTCFilterFunctionN filter);
+
+/* Sets the user-defined data pointer of the geometry. */
+RTC_API void rtcSetGeometryUserData(RTCGeometry geometry, void* ptr);
+
+/* Gets the user-defined data pointer of the geometry. */
+RTC_API void* rtcGetGeometryUserData(RTCGeometry geometry);
+
+/* Set the point query callback function of a geometry. */
+RTC_API void rtcSetGeometryPointQueryFunction(RTCGeometry geometry, RTCPointQueryFunction pointQuery);
+
+/* Sets the number of primitives of a user geometry. */
+RTC_API void rtcSetGeometryUserPrimitiveCount(RTCGeometry geometry, unsigned int userPrimitiveCount);
+
+/* Sets the bounding callback function to calculate bounding boxes for user primitives. */
+RTC_API void rtcSetGeometryBoundsFunction(RTCGeometry geometry, RTCBoundsFunction bounds, void* userPtr);
+
+/* Set the intersect callback function of a user geometry. */
+RTC_API void rtcSetGeometryIntersectFunction(RTCGeometry geometry, RTCIntersectFunctionN intersect);
+
+/* Set the occlusion callback function of a user geometry. */
+RTC_API void rtcSetGeometryOccludedFunction(RTCGeometry geometry, RTCOccludedFunctionN occluded);
+
+/* Invokes the intersection filter from the intersection callback function. */
+RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs);
+
+/* Invokes the occlusion filter from the occlusion callback function. */
+RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs);
+
+
+/* Sets the instanced scene of an instance geometry. */
+RTC_API void rtcSetGeometryInstancedScene(RTCGeometry geometry, RTCScene scene);
+
+/* Sets the transformation of an instance for the specified time step. */
+RTC_API void rtcSetGeometryTransform(RTCGeometry geometry, unsigned int timeStep, enum RTCFormat format, const void* xfm);
+
+/* Sets the transformation quaternion of an instance for the specified time step. */
+RTC_API void rtcSetGeometryTransformQuaternion(RTCGeometry geometry, unsigned int timeStep, const struct RTCQuaternionDecomposition* qd);
+
+/* Returns the interpolated transformation of an instance for the specified time. */
+RTC_API void rtcGetGeometryTransform(RTCGeometry geometry, float time, enum RTCFormat format, void* xfm);
+
+
+/* Sets the uniform tessellation rate of the geometry. */
+RTC_API void rtcSetGeometryTessellationRate(RTCGeometry geometry, float tessellationRate);
+
+/* Sets the number of topologies of a subdivision surface. */
+RTC_API void rtcSetGeometryTopologyCount(RTCGeometry geometry, unsigned int topologyCount);
+
+/* Sets the subdivision interpolation mode. */
+RTC_API void rtcSetGeometrySubdivisionMode(RTCGeometry geometry, unsigned int topologyID, enum RTCSubdivisionMode mode);
+
+/* Binds a vertex attribute to a topology of the geometry. */
+RTC_API void rtcSetGeometryVertexAttributeTopology(RTCGeometry geometry, unsigned int vertexAttributeID, unsigned int topologyID);
+
+/* Sets the displacement callback function of a subdivision surface. */
+RTC_API void rtcSetGeometryDisplacementFunction(RTCGeometry geometry, RTCDisplacementFunctionN displacement);
+
+/* Returns the first half edge of a face. */
+RTC_API unsigned int rtcGetGeometryFirstHalfEdge(RTCGeometry geometry, unsigned int faceID);
+
+/* Returns the face the half edge belongs to. */
+RTC_API unsigned int rtcGetGeometryFace(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns next half edge. */
+RTC_API unsigned int rtcGetGeometryNextHalfEdge(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns previous half edge. */
+RTC_API unsigned int rtcGetGeometryPreviousHalfEdge(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns opposite half edge. */
+RTC_API unsigned int rtcGetGeometryOppositeHalfEdge(RTCGeometry geometry, unsigned int topologyID, unsigned int edgeID);
+
+
+/* Arguments for rtcInterpolate */
+struct RTCInterpolateArguments
+{
+ RTCGeometry geometry;
+ unsigned int primID;
+ float u;
+ float v;
+ enum RTCBufferType bufferType;
+ unsigned int bufferSlot;
+ float* P;
+ float* dPdu;
+ float* dPdv;
+ float* ddPdudu;
+ float* ddPdvdv;
+ float* ddPdudv;
+ unsigned int valueCount;
+};
+
+/* Interpolates vertex data to some u/v location and optionally calculates all derivatives. */
+RTC_API void rtcInterpolate(const struct RTCInterpolateArguments* args);
+
+/* Interpolates vertex data to some u/v location. */
+RTC_FORCEINLINE void rtcInterpolate0(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot, float* P, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = NULL;
+ args.dPdv = NULL;
+ args.ddPdudu = NULL;
+ args.ddPdvdv = NULL;
+ args.ddPdudv = NULL;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Interpolates vertex data to some u/v location and calculates first order derivatives. */
+RTC_FORCEINLINE void rtcInterpolate1(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot,
+ float* P, float* dPdu, float* dPdv, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = dPdu;
+ args.dPdv = dPdv;
+ args.ddPdudu = NULL;
+ args.ddPdvdv = NULL;
+ args.ddPdudv = NULL;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Interpolates vertex data to some u/v location and calculates first and second order derivatives. */
+RTC_FORCEINLINE void rtcInterpolate2(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = dPdu;
+ args.dPdv = dPdv;
+ args.ddPdudu = ddPdudu;
+ args.ddPdvdv = ddPdvdv;
+ args.ddPdudv = ddPdudv;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Arguments for rtcInterpolateN */
+struct RTCInterpolateNArguments
+{
+ RTCGeometry geometry;
+ const void* valid;
+ const unsigned int* primIDs;
+ const float* u;
+ const float* v;
+ unsigned int N;
+ enum RTCBufferType bufferType;
+ unsigned int bufferSlot;
+ float* P;
+ float* dPdu;
+ float* dPdv;
+ float* ddPdudu;
+ float* ddPdvdv;
+ float* ddPdudv;
+ unsigned int valueCount;
+};
+
+/* Interpolates vertex data to an array of u/v locations. */
+RTC_API void rtcInterpolateN(const struct RTCInterpolateNArguments* args);
+
+/* RTCGrid primitive for grid mesh */
+struct RTCGrid
+{
+ unsigned int startVertexID;
+ unsigned int stride;
+ unsigned short width,height; // max is a 32k x 32k grid
+};
+
+RTC_NAMESPACE_END
+
+
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_quaternion.h b/thirdparty/embree-aarch64/include/embree3/rtcore_quaternion.h
new file mode 100644
index 0000000000..449cdedfdc
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_quaternion.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/*
+ * Structure for transformation respresentation as a matrix decomposition using
+ * a quaternion
+ */
+struct RTC_ALIGN(16) RTCQuaternionDecomposition
+{
+ float scale_x;
+ float scale_y;
+ float scale_z;
+ float skew_xy;
+ float skew_xz;
+ float skew_yz;
+ float shift_x;
+ float shift_y;
+ float shift_z;
+ float quaternion_r;
+ float quaternion_i;
+ float quaternion_j;
+ float quaternion_k;
+ float translation_x;
+ float translation_y;
+ float translation_z;
+};
+
+RTC_FORCEINLINE void rtcInitQuaternionDecomposition(struct RTCQuaternionDecomposition* qdecomp)
+{
+ qdecomp->scale_x = 1.f;
+ qdecomp->scale_y = 1.f;
+ qdecomp->scale_z = 1.f;
+ qdecomp->skew_xy = 0.f;
+ qdecomp->skew_xz = 0.f;
+ qdecomp->skew_yz = 0.f;
+ qdecomp->shift_x = 0.f;
+ qdecomp->shift_y = 0.f;
+ qdecomp->shift_z = 0.f;
+ qdecomp->quaternion_r = 1.f;
+ qdecomp->quaternion_i = 0.f;
+ qdecomp->quaternion_j = 0.f;
+ qdecomp->quaternion_k = 0.f;
+ qdecomp->translation_x = 0.f;
+ qdecomp->translation_y = 0.f;
+ qdecomp->translation_z = 0.f;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetQuaternion(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float r, float i, float j, float k)
+{
+ qdecomp->quaternion_r = r;
+ qdecomp->quaternion_i = i;
+ qdecomp->quaternion_j = j;
+ qdecomp->quaternion_k = k;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetScale(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float scale_x, float scale_y, float scale_z)
+{
+ qdecomp->scale_x = scale_x;
+ qdecomp->scale_y = scale_y;
+ qdecomp->scale_z = scale_z;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetSkew(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float skew_xy, float skew_xz, float skew_yz)
+{
+ qdecomp->skew_xy = skew_xy;
+ qdecomp->skew_xz = skew_xz;
+ qdecomp->skew_yz = skew_yz;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetShift(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float shift_x, float shift_y, float shift_z)
+{
+ qdecomp->shift_x = shift_x;
+ qdecomp->shift_y = shift_y;
+ qdecomp->shift_z = shift_z;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetTranslation(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float translation_x, float translation_y, float translation_z)
+{
+ qdecomp->translation_x = translation_x;
+ qdecomp->translation_y = translation_y;
+ qdecomp->translation_z = translation_z;
+}
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_ray.h b/thirdparty/embree-aarch64/include/embree3/rtcore_ray.h
new file mode 100644
index 0000000000..1ae3309ef1
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_ray.h
@@ -0,0 +1,378 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Ray structure for a single ray */
+struct RTC_ALIGN(16) RTCRay
+{
+ float org_x; // x coordinate of ray origin
+ float org_y; // y coordinate of ray origin
+ float org_z; // z coordinate of ray origin
+ float tnear; // start of ray segment
+
+ float dir_x; // x coordinate of ray direction
+ float dir_y; // y coordinate of ray direction
+ float dir_z; // z coordinate of ray direction
+ float time; // time of this ray for motion blur
+
+ float tfar; // end of ray segment (set to hit distance)
+ unsigned int mask; // ray mask
+ unsigned int id; // ray ID
+ unsigned int flags; // ray flags
+};
+
+/* Hit structure for a single ray */
+struct RTC_ALIGN(16) RTCHit
+{
+ float Ng_x; // x coordinate of geometry normal
+ float Ng_y; // y coordinate of geometry normal
+ float Ng_z; // z coordinate of geometry normal
+
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+};
+
+/* Combined ray/hit structure for a single ray */
+struct RTCRayHit
+{
+ struct RTCRay ray;
+ struct RTCHit hit;
+};
+
+/* Ray structure for a packet of 4 rays */
+struct RTC_ALIGN(16) RTCRay4
+{
+ float org_x[4];
+ float org_y[4];
+ float org_z[4];
+ float tnear[4];
+
+ float dir_x[4];
+ float dir_y[4];
+ float dir_z[4];
+ float time[4];
+
+ float tfar[4];
+ unsigned int mask[4];
+ unsigned int id[4];
+ unsigned int flags[4];
+};
+
+/* Hit structure for a packet of 4 rays */
+struct RTC_ALIGN(16) RTCHit4
+{
+ float Ng_x[4];
+ float Ng_y[4];
+ float Ng_z[4];
+
+ float u[4];
+ float v[4];
+
+ unsigned int primID[4];
+ unsigned int geomID[4];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][4];
+};
+
+/* Combined ray/hit structure for a packet of 4 rays */
+struct RTCRayHit4
+{
+ struct RTCRay4 ray;
+ struct RTCHit4 hit;
+};
+
+/* Ray structure for a packet of 8 rays */
+struct RTC_ALIGN(32) RTCRay8
+{
+ float org_x[8];
+ float org_y[8];
+ float org_z[8];
+ float tnear[8];
+
+ float dir_x[8];
+ float dir_y[8];
+ float dir_z[8];
+ float time[8];
+
+ float tfar[8];
+ unsigned int mask[8];
+ unsigned int id[8];
+ unsigned int flags[8];
+};
+
+/* Hit structure for a packet of 8 rays */
+struct RTC_ALIGN(32) RTCHit8
+{
+ float Ng_x[8];
+ float Ng_y[8];
+ float Ng_z[8];
+
+ float u[8];
+ float v[8];
+
+ unsigned int primID[8];
+ unsigned int geomID[8];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][8];
+};
+
+/* Combined ray/hit structure for a packet of 8 rays */
+struct RTCRayHit8
+{
+ struct RTCRay8 ray;
+ struct RTCHit8 hit;
+};
+
+/* Ray structure for a packet of 16 rays */
+struct RTC_ALIGN(64) RTCRay16
+{
+ float org_x[16];
+ float org_y[16];
+ float org_z[16];
+ float tnear[16];
+
+ float dir_x[16];
+ float dir_y[16];
+ float dir_z[16];
+ float time[16];
+
+ float tfar[16];
+ unsigned int mask[16];
+ unsigned int id[16];
+ unsigned int flags[16];
+};
+
+/* Hit structure for a packet of 16 rays */
+struct RTC_ALIGN(64) RTCHit16
+{
+ float Ng_x[16];
+ float Ng_y[16];
+ float Ng_z[16];
+
+ float u[16];
+ float v[16];
+
+ unsigned int primID[16];
+ unsigned int geomID[16];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+};
+
+/* Combined ray/hit structure for a packet of 16 rays */
+struct RTCRayHit16
+{
+ struct RTCRay16 ray;
+ struct RTCHit16 hit;
+};
+
+/* Ray structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCRayNp
+{
+ float* org_x;
+ float* org_y;
+ float* org_z;
+ float* tnear;
+
+ float* dir_x;
+ float* dir_y;
+ float* dir_z;
+ float* time;
+
+ float* tfar;
+ unsigned int* mask;
+ unsigned int* id;
+ unsigned int* flags;
+};
+
+/* Hit structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCHitNp
+{
+ float* Ng_x;
+ float* Ng_y;
+ float* Ng_z;
+
+ float* u;
+ float* v;
+
+ unsigned int* primID;
+ unsigned int* geomID;
+ unsigned int* instID[RTC_MAX_INSTANCE_LEVEL_COUNT];
+};
+
+/* Combined ray/hit structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCRayHitNp
+{
+ struct RTCRayNp ray;
+ struct RTCHitNp hit;
+};
+
+struct RTCRayN;
+struct RTCHitN;
+struct RTCRayHitN;
+
+#if defined(__cplusplus)
+
+/* Helper functions to access ray packets of runtime size N */
+RTC_FORCEINLINE float& RTCRayN_org_x(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[0*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_org_y(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[1*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_org_z(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[2*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_tnear(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[3*N+i]; }
+
+RTC_FORCEINLINE float& RTCRayN_dir_x(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[4*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_dir_y(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[5*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_dir_z(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[6*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_time (RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[7*N+i]; }
+
+RTC_FORCEINLINE float& RTCRayN_tfar (RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[8*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_mask (RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[9*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_id (RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[10*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_flags(RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[11*N+i]; }
+
+/* Helper functions to access hit packets of runtime size N */
+RTC_FORCEINLINE float& RTCHitN_Ng_x(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[0*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_Ng_y(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[1*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_Ng_z(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[2*N+i]; }
+
+RTC_FORCEINLINE float& RTCHitN_u(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[3*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_v(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[4*N+i]; }
+
+RTC_FORCEINLINE unsigned int& RTCHitN_primID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[5*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCHitN_geomID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[6*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCHitN_instID(RTCHitN* hit, unsigned int N, unsigned int i, unsigned int l) { return ((unsigned*)hit)[7*N+i+N*l]; }
+
+/* Helper functions to extract RTCRayN and RTCHitN from RTCRayHitN */
+RTC_FORCEINLINE RTCRayN* RTCRayHitN_RayN(RTCRayHitN* rayhit, unsigned int N) { return (RTCRayN*)&((float*)rayhit)[0*N]; }
+RTC_FORCEINLINE RTCHitN* RTCRayHitN_HitN(RTCRayHitN* rayhit, unsigned int N) { return (RTCHitN*)&((float*)rayhit)[12*N]; }
+
+/* Helper structure for a ray packet of compile-time size N */
+template<int N>
+struct RTCRayNt
+{
+ float org_x[N];
+ float org_y[N];
+ float org_z[N];
+ float tnear[N];
+
+ float dir_x[N];
+ float dir_y[N];
+ float dir_z[N];
+ float time[N];
+
+ float tfar[N];
+ unsigned int mask[N];
+ unsigned int id[N];
+ unsigned int flags[N];
+};
+
+/* Helper structure for a hit packet of compile-time size N */
+template<int N>
+struct RTCHitNt
+{
+ float Ng_x[N];
+ float Ng_y[N];
+ float Ng_z[N];
+
+ float u[N];
+ float v[N];
+
+ unsigned int primID[N];
+ unsigned int geomID[N];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][N];
+};
+
+/* Helper structure for a combined ray/hit packet of compile-time size N */
+template<int N>
+struct RTCRayHitNt
+{
+ RTCRayNt<N> ray;
+ RTCHitNt<N> hit;
+};
+
+RTC_FORCEINLINE RTCRay rtcGetRayFromRayN(RTCRayN* rayN, unsigned int N, unsigned int i)
+{
+ RTCRay ray;
+ ray.org_x = RTCRayN_org_x(rayN,N,i);
+ ray.org_y = RTCRayN_org_y(rayN,N,i);
+ ray.org_z = RTCRayN_org_z(rayN,N,i);
+ ray.tnear = RTCRayN_tnear(rayN,N,i);
+ ray.dir_x = RTCRayN_dir_x(rayN,N,i);
+ ray.dir_y = RTCRayN_dir_y(rayN,N,i);
+ ray.dir_z = RTCRayN_dir_z(rayN,N,i);
+ ray.time = RTCRayN_time(rayN,N,i);
+ ray.tfar = RTCRayN_tfar(rayN,N,i);
+ ray.mask = RTCRayN_mask(rayN,N,i);
+ ray.id = RTCRayN_id(rayN,N,i);
+ ray.flags = RTCRayN_flags(rayN,N,i);
+ return ray;
+}
+
+RTC_FORCEINLINE RTCHit rtcGetHitFromHitN(RTCHitN* hitN, unsigned int N, unsigned int i)
+{
+ RTCHit hit;
+ hit.Ng_x = RTCHitN_Ng_x(hitN,N,i);
+ hit.Ng_y = RTCHitN_Ng_y(hitN,N,i);
+ hit.Ng_z = RTCHitN_Ng_z(hitN,N,i);
+ hit.u = RTCHitN_u(hitN,N,i);
+ hit.v = RTCHitN_v(hitN,N,i);
+ hit.primID = RTCHitN_primID(hitN,N,i);
+ hit.geomID = RTCHitN_geomID(hitN,N,i);
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ hit.instID[l] = RTCHitN_instID(hitN,N,i,l);
+ return hit;
+}
+
+RTC_FORCEINLINE void rtcCopyHitToHitN(RTCHitN* hitN, const RTCHit* hit, unsigned int N, unsigned int i)
+{
+ RTCHitN_Ng_x(hitN,N,i) = hit->Ng_x;
+ RTCHitN_Ng_y(hitN,N,i) = hit->Ng_y;
+ RTCHitN_Ng_z(hitN,N,i) = hit->Ng_z;
+ RTCHitN_u(hitN,N,i) = hit->u;
+ RTCHitN_v(hitN,N,i) = hit->v;
+ RTCHitN_primID(hitN,N,i) = hit->primID;
+ RTCHitN_geomID(hitN,N,i) = hit->geomID;
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ RTCHitN_instID(hitN,N,i,l) = hit->instID[l];
+}
+
+RTC_FORCEINLINE RTCRayHit rtcGetRayHitFromRayHitN(RTCRayHitN* rayhitN, unsigned int N, unsigned int i)
+{
+ RTCRayHit rh;
+
+ RTCRayN* ray = RTCRayHitN_RayN(rayhitN,N);
+ rh.ray.org_x = RTCRayN_org_x(ray,N,i);
+ rh.ray.org_y = RTCRayN_org_y(ray,N,i);
+ rh.ray.org_z = RTCRayN_org_z(ray,N,i);
+ rh.ray.tnear = RTCRayN_tnear(ray,N,i);
+ rh.ray.dir_x = RTCRayN_dir_x(ray,N,i);
+ rh.ray.dir_y = RTCRayN_dir_y(ray,N,i);
+ rh.ray.dir_z = RTCRayN_dir_z(ray,N,i);
+ rh.ray.time = RTCRayN_time(ray,N,i);
+ rh.ray.tfar = RTCRayN_tfar(ray,N,i);
+ rh.ray.mask = RTCRayN_mask(ray,N,i);
+ rh.ray.id = RTCRayN_id(ray,N,i);
+ rh.ray.flags = RTCRayN_flags(ray,N,i);
+
+ RTCHitN* hit = RTCRayHitN_HitN(rayhitN,N);
+ rh.hit.Ng_x = RTCHitN_Ng_x(hit,N,i);
+ rh.hit.Ng_y = RTCHitN_Ng_y(hit,N,i);
+ rh.hit.Ng_z = RTCHitN_Ng_z(hit,N,i);
+ rh.hit.u = RTCHitN_u(hit,N,i);
+ rh.hit.v = RTCHitN_v(hit,N,i);
+ rh.hit.primID = RTCHitN_primID(hit,N,i);
+ rh.hit.geomID = RTCHitN_geomID(hit,N,i);
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ rh.hit.instID[l] = RTCHitN_instID(hit,N,i,l);
+
+ return rh;
+}
+
+#endif
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree-aarch64/include/embree3/rtcore_scene.h b/thirdparty/embree-aarch64/include/embree3/rtcore_scene.h
new file mode 100644
index 0000000000..0cd6401593
--- /dev/null
+++ b/thirdparty/embree-aarch64/include/embree3/rtcore_scene.h
@@ -0,0 +1,160 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_device.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Forward declarations for ray structures */
+struct RTCRayHit;
+struct RTCRayHit4;
+struct RTCRayHit8;
+struct RTCRayHit16;
+struct RTCRayHitNp;
+
+/* Scene flags */
+enum RTCSceneFlags
+{
+ RTC_SCENE_FLAG_NONE = 0,
+ RTC_SCENE_FLAG_DYNAMIC = (1 << 0),
+ RTC_SCENE_FLAG_COMPACT = (1 << 1),
+ RTC_SCENE_FLAG_ROBUST = (1 << 2),
+ RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION = (1 << 3)
+};
+
+/* Creates a new scene. */
+RTC_API RTCScene rtcNewScene(RTCDevice device);
+
+/* Returns the device the scene got created in. The reference count of
+ * the device is incremented by this function. */
+RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene);
+
+/* Retains the scene (increments the reference count). */
+RTC_API void rtcRetainScene(RTCScene scene);
+
+/* Releases the scene (decrements the reference count). */
+RTC_API void rtcReleaseScene(RTCScene scene);
+
+
+/* Attaches the geometry to a scene. */
+RTC_API unsigned int rtcAttachGeometry(RTCScene scene, RTCGeometry geometry);
+
+/* Attaches the geometry to a scene using the specified geometry ID. */
+RTC_API void rtcAttachGeometryByID(RTCScene scene, RTCGeometry geometry, unsigned int geomID);
+
+/* Detaches the geometry from the scene. */
+RTC_API void rtcDetachGeometry(RTCScene scene, unsigned int geomID);
+
+/* Gets a geometry handle from the scene. */
+RTC_API RTCGeometry rtcGetGeometry(RTCScene scene, unsigned int geomID);
+
+
+/* Commits the scene. */
+RTC_API void rtcCommitScene(RTCScene scene);
+
+/* Commits the scene from multiple threads. */
+RTC_API void rtcJoinCommitScene(RTCScene scene);
+
+
+/* Progress monitor callback function */
+typedef bool (*RTCProgressMonitorFunction)(void* ptr, double n);
+
+/* Sets the progress monitor callback function of the scene. */
+RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunction progress, void* ptr);
+
+/* Sets the build quality of the scene. */
+RTC_API void rtcSetSceneBuildQuality(RTCScene scene, enum RTCBuildQuality quality);
+
+/* Sets the scene flags. */
+RTC_API void rtcSetSceneFlags(RTCScene scene, enum RTCSceneFlags flags);
+
+/* Returns the scene flags. */
+RTC_API enum RTCSceneFlags rtcGetSceneFlags(RTCScene scene);
+
+/* Returns the axis-aligned bounds of the scene. */
+RTC_API void rtcGetSceneBounds(RTCScene scene, struct RTCBounds* bounds_o);
+
+/* Returns the linear axis-aligned bounds of the scene. */
+RTC_API void rtcGetSceneLinearBounds(RTCScene scene, struct RTCLinearBounds* bounds_o);
+
+
+/* Perform a closest point query of the scene. */
+RTC_API bool rtcPointQuery(RTCScene scene, struct RTCPointQuery* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void* userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery4(const int* valid, RTCScene scene, struct RTCPointQuery4* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery8(const int* valid, RTCScene scene, struct RTCPointQuery8* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery16(const int* valid, RTCScene scene, struct RTCPointQuery16* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Intersects a single ray with the scene. */
+RTC_API void rtcIntersect1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit);
+
+/* Intersects a packet of 4 rays with the scene. */
+RTC_API void rtcIntersect4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit4* rayhit);
+
+/* Intersects a packet of 8 rays with the scene. */
+RTC_API void rtcIntersect8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit8* rayhit);
+
+/* Intersects a packet of 16 rays with the scene. */
+RTC_API void rtcIntersect16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit16* rayhit);
+
+/* Intersects a stream of M rays with the scene. */
+RTC_API void rtcIntersect1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit, unsigned int M, size_t byteStride);
+
+/* Intersects a stream of pointers to M rays with the scene. */
+RTC_API void rtcIntersect1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit** rayhit, unsigned int M);
+
+/* Intersects a stream of M ray packets of size N in SOA format with the scene. */
+RTC_API void rtcIntersectNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride);
+
+/* Intersects a stream of M ray packets of size N in SOA format with the scene. */
+RTC_API void rtcIntersectNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayHitNp* rayhit, unsigned int N);
+
+/* Tests a single ray for occlusion with the scene. */
+RTC_API void rtcOccluded1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray);
+
+/* Tests a packet of 4 rays for occlusion occluded with the scene. */
+RTC_API void rtcOccluded4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay4* ray);
+
+/* Tests a packet of 8 rays for occlusion with the scene. */
+RTC_API void rtcOccluded8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay8* ray);
+
+/* Tests a packet of 16 rays for occlusion with the scene. */
+RTC_API void rtcOccluded16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay16* ray);
+
+/* Tests a stream of M rays for occlusion with the scene. */
+RTC_API void rtcOccluded1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray, unsigned int M, size_t byteStride);
+
+/* Tests a stream of pointers to M rays for occlusion with the scene. */
+RTC_API void rtcOccluded1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay** ray, unsigned int M);
+
+/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */
+RTC_API void rtcOccludedNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride);
+
+/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */
+RTC_API void rtcOccludedNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayNp* ray, unsigned int N);
+
+/*! collision callback */
+struct RTCCollision { unsigned int geomID0; unsigned int primID0; unsigned int geomID1; unsigned int primID1; };
+typedef void (*RTCCollideFunc) (void* userPtr, struct RTCCollision* collisions, unsigned int num_collisions);
+
+/*! Performs collision detection of two scenes */
+RTC_API void rtcCollide (RTCScene scene0, RTCScene scene1, RTCCollideFunc callback, void* userPtr);
+
+#if defined(__cplusplus)
+
+/* Helper for easily combining scene flags */
+inline RTCSceneFlags operator|(RTCSceneFlags a, RTCSceneFlags b) {
+ return (RTCSceneFlags)((size_t)a | (size_t)b);
+}
+
+#endif
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree-aarch64/kernels/builders/bvh_builder_hair.h b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_hair.h
new file mode 100644
index 0000000000..755ce255fb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_hair.h
@@ -0,0 +1,411 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../geometry/primitive.h"
+#include "../builders/bvh_builder_sah.h"
+#include "../builders/heuristic_binning_array_aligned.h"
+#include "../builders/heuristic_binning_array_unaligned.h"
+#include "../builders/heuristic_strand_array.h"
+
+#define NUM_HAIR_OBJECT_BINS 32
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderHair
+ {
+ /*! settings for builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7), finished_range_threshold(inf) {}
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ size_t finished_range_threshold; //!< finished range threshold
+ };
+
+ template<typename NodeRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeFunc,
+ typename SetAABBNodeFunc,
+ typename CreateOBBNodeFunc,
+ typename SetOBBNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor,
+ typename ReportFinishedRangeFunc>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+ friend struct BVHBuilderHair;
+
+ typedef FastAllocator::CachedAllocator Allocator;
+ typedef HeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> HeuristicBinningSAH;
+ typedef UnalignedHeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> UnalignedHeuristicBinningSAH;
+ typedef HeuristicStrandSplit HeuristicStrandSplitSAH;
+
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+ static const size_t SINGLE_THREADED_THRESHOLD = 4096; //!< threshold to switch to single threaded build
+
+ static const size_t travCostAligned = 1;
+ static const size_t travCostUnaligned = 5;
+ static const size_t intCost = 6;
+
+ BuilderT (Scene* scene,
+ PrimRef* prims,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeFunc& createAABBNode,
+ const SetAABBNodeFunc& setAABBNode,
+ const CreateOBBNodeFunc& createOBBNode,
+ const SetOBBNodeFunc& setOBBNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const ReportFinishedRangeFunc& reportFinishedRange,
+ const Settings settings)
+
+ : cfg(settings),
+ prims(prims),
+ createAlloc(createAlloc),
+ createAABBNode(createAABBNode),
+ setAABBNode(setAABBNode),
+ createOBBNode(createOBBNode),
+ setOBBNode(setOBBNode),
+ createLeaf(createLeaf),
+ progressMonitor(progressMonitor),
+ reportFinishedRange(reportFinishedRange),
+ alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) {}
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const PrimInfoRange& range)
+ {
+ if (range.size() == 0) return true;
+ unsigned int firstGeomID = prims[range.begin()].geomID();
+ for (size_t i=range.begin()+1; i<range.end(); i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*! creates a large leaf that could be larger than supported by the BVH */
+ NodeRef createLargeLeaf(size_t depth, const PrimInfoRange& pinfo, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (pinfo.size() <= cfg.maxLeafSize && sameGeometry(pinfo))
+ return createLeaf(prims,pinfo,alloc);
+
+ /* fill all children by always splitting the largest one */
+ PrimInfoRange children[MAX_BRANCHING_FACTOR];
+ unsigned numChildren = 1;
+ children[0] = pinfo;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ int bestChild = -1;
+ size_t bestSize = 0;
+ for (unsigned i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && sameGeometry(children[i]))
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ __aligned(64) PrimInfoRange left, right;
+ if (!sameGeometry(children[bestChild])) {
+ alignedHeuristic.splitByGeometry(children[bestChild],left,right);
+ } else {
+ alignedHeuristic.splitFallback(children[bestChild],left,right);
+ }
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ /* create node */
+ auto node = createAABBNode(alloc);
+
+ for (size_t i=0; i<numChildren; i++) {
+ const NodeRef child = createLargeLeaf(depth+1,children[i],alloc);
+ setAABBNode(node,i,child,children[i].geomBounds);
+ }
+
+ return node;
+ }
+
+ /*! performs split */
+ __noinline void split(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo, bool& aligned) // FIXME: not inlined as ICC otherwise uses much stack
+ {
+ /* variable to track the SAH of the best splitting approach */
+ float bestSAH = inf;
+ const size_t blocks = (pinfo.size()+(1ull<<cfg.logBlockSize)-1ull) >> cfg.logBlockSize;
+ const float leafSAH = intCost*float(blocks)*halfArea(pinfo.geomBounds);
+
+ /* try standard binning in aligned space */
+ float alignedObjectSAH = inf;
+ HeuristicBinningSAH::Split alignedObjectSplit;
+ if (aligned) {
+ alignedObjectSplit = alignedHeuristic.find(pinfo,cfg.logBlockSize);
+ alignedObjectSAH = travCostAligned*halfArea(pinfo.geomBounds) + intCost*alignedObjectSplit.splitSAH();
+ bestSAH = min(alignedObjectSAH,bestSAH);
+ }
+
+ /* try standard binning in unaligned space */
+ UnalignedHeuristicBinningSAH::Split unalignedObjectSplit;
+ LinearSpace3fa uspace;
+ float unalignedObjectSAH = inf;
+ if (bestSAH > 0.7f*leafSAH) {
+ uspace = unalignedHeuristic.computeAlignedSpace(pinfo);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(pinfo,uspace);
+ unalignedObjectSplit = unalignedHeuristic.find(sinfo,cfg.logBlockSize,uspace);
+ unalignedObjectSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*unalignedObjectSplit.splitSAH();
+ bestSAH = min(unalignedObjectSAH,bestSAH);
+ }
+
+ /* try splitting into two strands */
+ HeuristicStrandSplitSAH::Split strandSplit;
+ float strandSAH = inf;
+ if (bestSAH > 0.7f*leafSAH && pinfo.size() <= 256) {
+ strandSplit = strandHeuristic.find(pinfo,cfg.logBlockSize);
+ strandSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*strandSplit.splitSAH();
+ bestSAH = min(strandSAH,bestSAH);
+ }
+
+ /* fallback if SAH heuristics failed */
+ if (unlikely(!std::isfinite(bestSAH)))
+ {
+ alignedHeuristic.deterministic_order(pinfo);
+ alignedHeuristic.splitFallback(pinfo,linfo,rinfo);
+ }
+
+ /* perform aligned split if this is best */
+ else if (bestSAH == alignedObjectSAH) {
+ alignedHeuristic.split(alignedObjectSplit,pinfo,linfo,rinfo);
+ }
+
+ /* perform unaligned split if this is best */
+ else if (bestSAH == unalignedObjectSAH) {
+ unalignedHeuristic.split(unalignedObjectSplit,uspace,pinfo,linfo,rinfo);
+ aligned = false;
+ }
+
+ /* perform strand split if this is best */
+ else if (bestSAH == strandSAH) {
+ strandHeuristic.split(strandSplit,pinfo,linfo,rinfo);
+ aligned = false;
+ }
+
+ /* can never happen */
+ else
+ assert(false);
+ }
+
+ /*! recursive build */
+ NodeRef recurse(size_t depth, const PrimInfoRange& pinfo, Allocator alloc, bool toplevel, bool alloc_barrier)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && pinfo.size() <= SINGLE_THREADED_THRESHOLD)
+ progressMonitor(pinfo.size());
+
+ PrimInfoRange children[MAX_BRANCHING_FACTOR];
+
+ /* create leaf node */
+ if (depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || pinfo.size() <= cfg.minLeafSize) {
+ alignedHeuristic.deterministic_order(pinfo);
+ return createLargeLeaf(depth,pinfo,alloc);
+ }
+
+ /* fill all children by always splitting the one with the largest surface area */
+ size_t numChildren = 1;
+ children[0] = pinfo;
+ bool aligned = true;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ ssize_t bestChild = -1;
+ float bestArea = neg_inf;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ if (area(children[i].geomBounds) > bestArea) {
+ bestArea = area(children[i].geomBounds);
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ PrimInfoRange left, right;
+ split(children[bestChild],left,right,aligned);
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ NodeRef node;
+
+ /* create aligned node */
+ if (aligned)
+ {
+ node = createAABBNode(alloc);
+
+ /* spawn tasks or ... */
+ if (pinfo.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setAABBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),children[i].geomBounds);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else {
+ for (size_t i=0; i<numChildren; i++) {
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setAABBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),children[i].geomBounds);
+ }
+ }
+ }
+
+ /* create unaligned node */
+ else
+ {
+ node = createOBBNode(alloc);
+
+ /* spawn tasks or ... */
+ if (pinfo.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
+ const OBBox3fa obounds(space,sinfo.geomBounds);
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setOBBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),obounds);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
+ const OBBox3fa obounds(space,sinfo.geomBounds);
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setOBBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),obounds);
+ }
+ }
+ }
+
+ /* reports a finished range of primrefs */
+ if (unlikely(alloc_barrier))
+ reportFinishedRange(pinfo);
+
+ return node;
+ }
+
+ private:
+ Settings cfg;
+ PrimRef* prims;
+ const CreateAllocFunc& createAlloc;
+ const CreateAABBNodeFunc& createAABBNode;
+ const SetAABBNodeFunc& setAABBNode;
+ const CreateOBBNodeFunc& createOBBNode;
+ const SetOBBNodeFunc& setOBBNode;
+ const CreateLeafFunc& createLeaf;
+ const ProgressMonitor& progressMonitor;
+ const ReportFinishedRangeFunc& reportFinishedRange;
+
+ private:
+ HeuristicBinningSAH alignedHeuristic;
+ UnalignedHeuristicBinningSAH unalignedHeuristic;
+ HeuristicStrandSplitSAH strandHeuristic;
+ };
+
+ template<typename NodeRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeFunc,
+ typename SetAABBNodeFunc,
+ typename CreateOBBNodeFunc,
+ typename SetOBBNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor,
+ typename ReportFinishedRangeFunc>
+
+ static NodeRef build (const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeFunc& createAABBNode,
+ const SetAABBNodeFunc& setAABBNode,
+ const CreateOBBNodeFunc& createOBBNode,
+ const SetOBBNodeFunc& setOBBNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const ReportFinishedRangeFunc& reportFinishedRange,
+ Scene* scene,
+ PrimRef* prims,
+ const PrimInfo& pinfo,
+ const Settings settings)
+ {
+ typedef BuilderT<NodeRef,
+ CreateAllocFunc,
+ CreateAABBNodeFunc,SetAABBNodeFunc,
+ CreateOBBNodeFunc,SetOBBNodeFunc,
+ CreateLeafFunc,ProgressMonitor,
+ ReportFinishedRangeFunc> Builder;
+
+ Builder builder(scene,prims,createAlloc,
+ createAABBNode,setAABBNode,
+ createOBBNode,setOBBNode,
+ createLeaf,progressMonitor,reportFinishedRange,settings);
+
+ NodeRef root = builder.recurse(1,pinfo,nullptr,true,false);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/bvh_builder_morton.h b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_morton.h
new file mode 100644
index 0000000000..92be2f7e65
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_morton.h
@@ -0,0 +1,501 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/builder.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderMorton
+ {
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree of we are that many levels before the maximum tree depth
+
+ /*! settings for morton builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), minLeafSize(1), maxLeafSize(7), singleThreadThreshold(1024) {}
+
+ /*! initialize settings from API settings */
+ Settings (const RTCBuildArguments& settings)
+ : branchingFactor(2), maxDepth(32), minLeafSize(1), maxLeafSize(7), singleThreadThreshold(1024)
+ {
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxBranchingFactor)) branchingFactor = settings.maxBranchingFactor;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxDepth )) maxDepth = settings.maxDepth;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize;
+
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ Settings (size_t branchingFactor, size_t maxDepth, size_t minLeafSize, size_t maxLeafSize, size_t singleThreadThreshold)
+ : branchingFactor(branchingFactor), maxDepth(maxDepth), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize), singleThreadThreshold(singleThreadThreshold)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ };
+
+ /*! Build primitive consisting of morton code and primitive ID. */
+ struct __aligned(8) BuildPrim
+ {
+ union {
+ struct {
+ unsigned int code; //!< morton code
+ unsigned int index; //!< i'th primitive
+ };
+ uint64_t t;
+ };
+
+ /*! interface for radix sort */
+ __forceinline operator unsigned() const { return code; }
+
+ /*! interface for standard sort */
+ __forceinline bool operator<(const BuildPrim &m) const { return code < m.code; }
+ };
+
+ /*! maps bounding box to morton code */
+ struct MortonCodeMapping
+ {
+ static const size_t LATTICE_BITS_PER_DIM = 10;
+ static const size_t LATTICE_SIZE_PER_DIM = size_t(1) << LATTICE_BITS_PER_DIM;
+
+ vfloat4 base;
+ vfloat4 scale;
+
+ __forceinline MortonCodeMapping(const BBox3fa& bounds)
+ {
+ base = (vfloat4)bounds.lower;
+ const vfloat4 diag = (vfloat4)bounds.upper - (vfloat4)bounds.lower;
+ scale = select(diag > vfloat4(1E-19f), rcp(diag) * vfloat4(LATTICE_SIZE_PER_DIM * 0.99f),vfloat4(0.0f));
+ }
+
+ __forceinline const vint4 bin (const BBox3fa& box) const
+ {
+ const vfloat4 lower = (vfloat4)box.lower;
+ const vfloat4 upper = (vfloat4)box.upper;
+ const vfloat4 centroid = lower+upper;
+ return vint4((centroid-base)*scale);
+ }
+
+ __forceinline unsigned int code (const BBox3fa& box) const
+ {
+ const vint4 binID = bin(box);
+ const unsigned int x = extract<0>(binID);
+ const unsigned int y = extract<1>(binID);
+ const unsigned int z = extract<2>(binID);
+ const unsigned int xyz = bitInterleave(x,y,z);
+ return xyz;
+ }
+ };
+
+#if defined (__AVX2__)
+
+ /*! for AVX2 there is a fast scalar bitInterleave */
+ struct MortonCodeGenerator
+ {
+ __forceinline MortonCodeGenerator(const MortonCodeMapping& mapping, BuildPrim* dest)
+ : mapping(mapping), dest(dest) {}
+
+ __forceinline void operator() (const BBox3fa& b, const unsigned index)
+ {
+ dest->index = index;
+ dest->code = mapping.code(b);
+ dest++;
+ }
+
+ public:
+ const MortonCodeMapping mapping;
+ BuildPrim* dest;
+ size_t currentID;
+ };
+
+#else
+
+ /*! before AVX2 is it better to use the SSE version of bitInterleave */
+ struct MortonCodeGenerator
+ {
+ __forceinline MortonCodeGenerator(const MortonCodeMapping& mapping, BuildPrim* dest)
+ : mapping(mapping), dest(dest), currentID(0), slots(0), ax(0), ay(0), az(0), ai(0) {}
+
+ __forceinline ~MortonCodeGenerator()
+ {
+ if (slots != 0)
+ {
+ const vint4 code = bitInterleave(ax,ay,az);
+ for (size_t i=0; i<slots; i++) {
+ dest[currentID-slots+i].index = ai[i];
+ dest[currentID-slots+i].code = code[i];
+ }
+ }
+ }
+
+ __forceinline void operator() (const BBox3fa& b, const unsigned index)
+ {
+ const vint4 binID = mapping.bin(b);
+ ax[slots] = extract<0>(binID);
+ ay[slots] = extract<1>(binID);
+ az[slots] = extract<2>(binID);
+ ai[slots] = index;
+ slots++;
+ currentID++;
+
+ if (slots == 4)
+ {
+ const vint4 code = bitInterleave(ax,ay,az);
+ vint4::storeu(&dest[currentID-4],unpacklo(code,ai));
+ vint4::storeu(&dest[currentID-2],unpackhi(code,ai));
+ slots = 0;
+ }
+ }
+
+ public:
+ const MortonCodeMapping mapping;
+ BuildPrim* dest;
+ size_t currentID;
+ size_t slots;
+ vint4 ax, ay, az, ai;
+ };
+
+#endif
+
+ template<
+ typename ReductionTy,
+ typename Allocator,
+ typename CreateAllocator,
+ typename CreateNodeFunc,
+ typename SetNodeBoundsFunc,
+ typename CreateLeafFunc,
+ typename CalculateBounds,
+ typename ProgressMonitor>
+
+ class BuilderT : private Settings
+ {
+ ALIGNED_CLASS_(16);
+
+ public:
+
+ BuilderT (CreateAllocator& createAllocator,
+ CreateNodeFunc& createNode,
+ SetNodeBoundsFunc& setBounds,
+ CreateLeafFunc& createLeaf,
+ CalculateBounds& calculateBounds,
+ ProgressMonitor& progressMonitor,
+ const Settings& settings)
+
+ : Settings(settings),
+ createAllocator(createAllocator),
+ createNode(createNode),
+ setBounds(setBounds),
+ createLeaf(createLeaf),
+ calculateBounds(calculateBounds),
+ progressMonitor(progressMonitor),
+ morton(nullptr) {}
+
+ ReductionTy createLargeLeaf(size_t depth, const range<unsigned>& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (depth > maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (current.size() <= maxLeafSize)
+ return createLeaf(current,alloc);
+
+ /* fill all children by always splitting the largest one */
+ range<unsigned> children[MAX_BRANCHING_FACTOR];
+ size_t numChildren = 1;
+ children[0] = current;
+
+ do {
+
+ /* find best child with largest number of primitives */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= maxLeafSize)
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == size_t(-1)) break;
+
+ /*! split best child into left and right child */
+ auto split = children[bestChild].split();
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = split.first;
+ children[numChildren+0] = split.second;
+ numChildren++;
+
+ } while (numChildren < branchingFactor);
+
+ /* create node */
+ auto node = createNode(alloc,numChildren);
+
+ /* recurse into each child */
+ ReductionTy bounds[MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<numChildren; i++)
+ bounds[i] = createLargeLeaf(depth+1,children[i],alloc);
+
+ return setBounds(node,bounds,numChildren);
+ }
+
+ /*! recreates morton codes when reaching a region where all codes are identical */
+ __noinline void recreateMortonCodes(const range<unsigned>& current) const
+ {
+ /* fast path for small ranges */
+ if (likely(current.size() < 1024))
+ {
+ /*! recalculate centroid bounds */
+ BBox3fa centBounds(empty);
+ for (size_t i=current.begin(); i<current.end(); i++)
+ centBounds.extend(center2(calculateBounds(morton[i])));
+
+ /* recalculate morton codes */
+ MortonCodeMapping mapping(centBounds);
+ for (size_t i=current.begin(); i<current.end(); i++)
+ morton[i].code = mapping.code(calculateBounds(morton[i]));
+
+ /* sort morton codes */
+ std::sort(morton+current.begin(),morton+current.end());
+ }
+ else
+ {
+ /*! recalculate centroid bounds */
+ auto calculateCentBounds = [&] ( const range<unsigned>& r ) {
+ BBox3fa centBounds = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ centBounds.extend(center2(calculateBounds(morton[i])));
+ return centBounds;
+ };
+ const BBox3fa centBounds = parallel_reduce(current.begin(), current.end(), unsigned(1024),
+ BBox3fa(empty), calculateCentBounds, BBox3fa::merge);
+
+ /* recalculate morton codes */
+ MortonCodeMapping mapping(centBounds);
+ parallel_for(current.begin(), current.end(), unsigned(1024), [&] ( const range<unsigned>& r ) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ morton[i].code = mapping.code(calculateBounds(morton[i]));
+ }
+ });
+
+ /*! sort morton codes */
+#if defined(TASKING_TBB)
+ tbb::parallel_sort(morton+current.begin(),morton+current.end());
+#else
+ radixsort32(morton+current.begin(),current.size());
+#endif
+ }
+ }
+
+ __forceinline void split(const range<unsigned>& current, range<unsigned>& left, range<unsigned>& right) const
+ {
+ const unsigned int code_start = morton[current.begin()].code;
+ const unsigned int code_end = morton[current.end()-1].code;
+ unsigned int bitpos = lzcnt(code_start^code_end);
+
+ /* if all items mapped to same morton code, then re-create new morton codes for the items */
+ if (unlikely(bitpos == 32))
+ {
+ recreateMortonCodes(current);
+ const unsigned int code_start = morton[current.begin()].code;
+ const unsigned int code_end = morton[current.end()-1].code;
+ bitpos = lzcnt(code_start^code_end);
+
+ /* if the morton code is still the same, goto fall back split */
+ if (unlikely(bitpos == 32)) {
+ current.split(left,right);
+ return;
+ }
+ }
+
+ /* split the items at the topmost different morton code bit */
+ const unsigned int bitpos_diff = 31-bitpos;
+ const unsigned int bitmask = 1 << bitpos_diff;
+
+ /* find location where bit differs using binary search */
+ unsigned begin = current.begin();
+ unsigned end = current.end();
+ while (begin + 1 != end) {
+ const unsigned mid = (begin+end)/2;
+ const unsigned bit = morton[mid].code & bitmask;
+ if (bit == 0) begin = mid; else end = mid;
+ }
+ unsigned center = end;
+#if defined(DEBUG)
+ for (unsigned int i=begin; i<center; i++) assert((morton[i].code & bitmask) == 0);
+ for (unsigned int i=center; i<end; i++) assert((morton[i].code & bitmask) == bitmask);
+#endif
+
+ left = make_range(current.begin(),center);
+ right = make_range(center,current.end());
+ }
+
+ ReductionTy recurse(size_t depth, const range<unsigned>& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAllocator();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /* create leaf node */
+ if (unlikely(depth+MIN_LARGE_LEAF_LEVELS >= maxDepth || current.size() <= minLeafSize))
+ return createLargeLeaf(depth,current,alloc);
+
+ /* fill all children by always splitting the one with the largest surface area */
+ range<unsigned> children[MAX_BRANCHING_FACTOR];
+ split(current,children[0],children[1]);
+ size_t numChildren = 2;
+
+ while (numChildren < branchingFactor)
+ {
+ /* find best child with largest number of primitives */
+ int bestChild = -1;
+ unsigned bestItems = 0;
+ for (unsigned int i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ if (children[i].size() > bestItems) {
+ bestItems = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ range<unsigned> left, right;
+ split(children[bestChild],left,right);
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+ }
+
+ /* create leaf node if no split is possible */
+ if (unlikely(numChildren == 1))
+ return createLeaf(current,alloc);
+
+ /* allocate node */
+ auto node = createNode(alloc,numChildren);
+
+ /* process top parts of tree parallel */
+ ReductionTy bounds[MAX_BRANCHING_FACTOR];
+ if (current.size() > singleThreadThreshold)
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ bounds[i] = recurse(depth+1,children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+
+ /* finish tree sequentially */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++)
+ bounds[i] = recurse(depth+1,children[i],alloc,false);
+ }
+
+ return setBounds(node,bounds,numChildren);
+ }
+
+ /* build function */
+ ReductionTy build(BuildPrim* src, BuildPrim* tmp, size_t numPrimitives)
+ {
+ /* sort morton codes */
+ morton = src;
+ radix_sort_u32(src,tmp,numPrimitives,singleThreadThreshold);
+
+ /* build BVH */
+ const ReductionTy root = recurse(1, range<unsigned>(0,(unsigned)numPrimitives), nullptr, true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ public:
+ CreateAllocator& createAllocator;
+ CreateNodeFunc& createNode;
+ SetNodeBoundsFunc& setBounds;
+ CreateLeafFunc& createLeaf;
+ CalculateBounds& calculateBounds;
+ ProgressMonitor& progressMonitor;
+
+ public:
+ BuildPrim* morton;
+ };
+
+
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetBoundsFunc,
+ typename CreateLeafFunc,
+ typename CalculateBoundsFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAllocator,
+ CreateNodeFunc createNode,
+ SetBoundsFunc setBounds,
+ CreateLeafFunc createLeaf,
+ CalculateBoundsFunc calculateBounds,
+ ProgressMonitor progressMonitor,
+ BuildPrim* src,
+ BuildPrim* tmp,
+ size_t numPrimitives,
+ const Settings& settings)
+ {
+ typedef BuilderT<
+ ReductionTy,
+ decltype(createAllocator()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ SetBoundsFunc,
+ CreateLeafFunc,
+ CalculateBoundsFunc,
+ ProgressMonitor> Builder;
+
+ Builder builder(createAllocator,
+ createNode,
+ setBounds,
+ createLeaf,
+ calculateBounds,
+ progressMonitor,
+ settings);
+
+ return builder.build(src,tmp,numPrimitives);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur.h b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur.h
new file mode 100644
index 0000000000..4c138dacdb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur.h
@@ -0,0 +1,692 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define MBLUR_NUM_TEMPORAL_BINS 2
+#define MBLUR_NUM_OBJECT_BINS 32
+
+#include "../bvh/bvh.h"
+#include "../common/primref_mb.h"
+#include "heuristic_binning_array_aligned.h"
+#include "heuristic_timesplit_array.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ struct SharedVector
+ {
+ __forceinline SharedVector() {}
+
+ __forceinline SharedVector(T* ptr, size_t refCount = 1)
+ : prims(ptr), refCount(refCount) {}
+
+ __forceinline void incRef() {
+ refCount++;
+ }
+
+ __forceinline void decRef()
+ {
+ if (--refCount == 0)
+ delete prims;
+ }
+
+ T* prims;
+ size_t refCount;
+ };
+
+ template<typename BuildRecord, int MAX_BRANCHING_FACTOR>
+ struct LocalChildListT
+ {
+ typedef SharedVector<mvector<PrimRefMB>> SharedPrimRefVector;
+
+ __forceinline LocalChildListT (const BuildRecord& record)
+ : numChildren(1), numSharedPrimVecs(1)
+ {
+ /* the local root will be freed in the ancestor where it was created (thus refCount is 2) */
+ children[0] = record;
+ primvecs[0] = new (&sharedPrimVecs[0]) SharedPrimRefVector(record.prims.prims, 2);
+ }
+
+ __forceinline ~LocalChildListT()
+ {
+ for (size_t i = 0; i < numChildren; i++)
+ primvecs[i]->decRef();
+ }
+
+ __forceinline BuildRecord& operator[] ( const size_t i ) {
+ return children[i];
+ }
+
+ __forceinline size_t size() const {
+ return numChildren;
+ }
+
+ __forceinline void split(ssize_t bestChild, const BuildRecord& lrecord, const BuildRecord& rrecord, std::unique_ptr<mvector<PrimRefMB>> new_vector)
+ {
+ SharedPrimRefVector* bsharedPrimVec = primvecs[bestChild];
+ if (lrecord.prims.prims == bsharedPrimVec->prims) {
+ primvecs[bestChild] = bsharedPrimVec;
+ bsharedPrimVec->incRef();
+ }
+ else {
+ primvecs[bestChild] = new (&sharedPrimVecs[numSharedPrimVecs++]) SharedPrimRefVector(lrecord.prims.prims);
+ }
+
+ if (rrecord.prims.prims == bsharedPrimVec->prims) {
+ primvecs[numChildren] = bsharedPrimVec;
+ bsharedPrimVec->incRef();
+ }
+ else {
+ primvecs[numChildren] = new (&sharedPrimVecs[numSharedPrimVecs++]) SharedPrimRefVector(rrecord.prims.prims);
+ }
+ bsharedPrimVec->decRef();
+ new_vector.release();
+
+ children[bestChild] = lrecord;
+ children[numChildren] = rrecord;
+ numChildren++;
+ }
+
+ public:
+ array_t<BuildRecord,MAX_BRANCHING_FACTOR> children;
+ array_t<SharedPrimRefVector*,MAX_BRANCHING_FACTOR> primvecs;
+ size_t numChildren;
+
+ array_t<SharedPrimRefVector,2*MAX_BRANCHING_FACTOR> sharedPrimVecs;
+ size_t numSharedPrimVecs;
+ };
+
+ template<typename Mesh>
+ struct RecalculatePrimRef
+ {
+ Scene* scene;
+
+ __forceinline RecalculatePrimRef (Scene* scene)
+ : scene(scene) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Mesh* mesh = scene->get<Mesh>(geomID);
+ const LBBox3fa lbounds = mesh->linearBounds(primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ // __noinline is workaround for ICC16 bug under MacOSX
+ __noinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Mesh* mesh = scene->get<Mesh>(geomID);
+ const LBBox3fa lbounds = mesh->linearBounds(space, primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ return scene->get<Mesh>(prim.geomID())->linearBounds(prim.primID(), time_range);
+ }
+
+ // __noinline is workaround for ICC16 bug under MacOSX
+ __noinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const {
+ return scene->get<Mesh>(prim.geomID())->linearBounds(space, prim.primID(), time_range);
+ }
+ };
+
+ struct VirtualRecalculatePrimRef
+ {
+ Scene* scene;
+
+ __forceinline VirtualRecalculatePrimRef (Scene* scene)
+ : scene(scene) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Geometry* mesh = scene->get(geomID);
+ const LBBox3fa lbounds = mesh->vlinearBounds(primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Geometry* mesh = scene->get(geomID);
+ const LBBox3fa lbounds = mesh->vlinearBounds(space, primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ return scene->get(prim.geomID())->vlinearBounds(prim.primID(), time_range);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const {
+ return scene->get(prim.geomID())->vlinearBounds(space, prim.primID(), time_range);
+ }
+ };
+
+ struct BVHBuilderMSMBlur
+ {
+ /*! settings for msmblur builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(8),
+ travCost(1.0f), intCost(1.0f), singleLeafTimeSegment(false),
+ singleThreadThreshold(1024) {}
+
+
+ Settings (size_t sahBlockSize, size_t minLeafSize, size_t maxLeafSize, float travCost, float intCost, size_t singleThreadThreshold)
+ : branchingFactor(2), maxDepth(32), logBlockSize(bsr(sahBlockSize)), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize),
+ travCost(travCost), intCost(intCost), singleThreadThreshold(singleThreadThreshold)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ float travCost; //!< estimated cost of one traversal step
+ float intCost; //!< estimated cost of one primitive intersection
+ bool singleLeafTimeSegment; //!< split time to single time range
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ };
+
+ struct BuildRecord
+ {
+ public:
+ __forceinline BuildRecord () {}
+
+ __forceinline BuildRecord (size_t depth)
+ : depth(depth) {}
+
+ __forceinline BuildRecord (const SetMB& prims, size_t depth)
+ : depth(depth), prims(prims) {}
+
+ __forceinline friend bool operator< (const BuildRecord& a, const BuildRecord& b) {
+ return a.prims.size() < b.prims.size();
+ }
+
+ __forceinline size_t size() const {
+ return prims.size();
+ }
+
+ public:
+ size_t depth; //!< Depth of the root of this subtree.
+ SetMB prims; //!< The list of primitives.
+ };
+
+ struct BuildRecordSplit : public BuildRecord
+ {
+ __forceinline BuildRecordSplit () {}
+
+ __forceinline BuildRecordSplit (size_t depth)
+ : BuildRecord(depth) {}
+
+ __forceinline BuildRecordSplit (const BuildRecord& record, const BinSplit<MBLUR_NUM_OBJECT_BINS>& split)
+ : BuildRecord(record), split(split) {}
+
+ BinSplit<MBLUR_NUM_OBJECT_BINS> split;
+ };
+
+ template<
+ typename NodeRef,
+ typename RecalculatePrimRef,
+ typename Allocator,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+ static const size_t MAX_BRANCHING_FACTOR = 16; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+ typedef BinSplit<MBLUR_NUM_OBJECT_BINS> Split;
+ typedef mvector<PrimRefMB>* PrimRefVector;
+ typedef SharedVector<mvector<PrimRefMB>> SharedPrimRefVector;
+ typedef LocalChildListT<BuildRecord,MAX_BRANCHING_FACTOR> LocalChildList;
+ typedef LocalChildListT<BuildRecordSplit,MAX_BRANCHING_FACTOR> LocalChildListSplit;
+
+ public:
+
+ BuilderT (MemoryMonitorInterface* device,
+ const RecalculatePrimRef recalculatePrimRef,
+ const CreateAllocFunc createAlloc,
+ const CreateNodeFunc createNode,
+ const SetNodeFunc setNode,
+ const CreateLeafFunc createLeaf,
+ const ProgressMonitor progressMonitor,
+ const Settings& settings)
+ : cfg(settings),
+ heuristicObjectSplit(),
+ heuristicTemporalSplit(device, recalculatePrimRef),
+ recalculatePrimRef(recalculatePrimRef), createAlloc(createAlloc), createNode(createNode), setNode(setNode), createLeaf(createLeaf),
+ progressMonitor(progressMonitor)
+ {
+ if (cfg.branchingFactor > MAX_BRANCHING_FACTOR)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
+ }
+
+ /*! finds the best split */
+ const Split find(const SetMB& set)
+ {
+ /* first try standard object split */
+ const Split object_split = heuristicObjectSplit.find(set,cfg.logBlockSize);
+ const float object_split_sah = object_split.splitSAH();
+
+ /* test temporal splits only when object split was bad */
+ const float leaf_sah = set.leafSAH(cfg.logBlockSize);
+ if (object_split_sah < 0.50f*leaf_sah)
+ return object_split;
+
+ /* do temporal splits only if the the time range is big enough */
+ if (set.time_range.size() > 1.01f/float(set.max_num_time_segments))
+ {
+ const Split temporal_split = heuristicTemporalSplit.find(set,cfg.logBlockSize);
+ const float temporal_split_sah = temporal_split.splitSAH();
+
+ /* take temporal split if it improved SAH */
+ if (temporal_split_sah < object_split_sah)
+ return temporal_split;
+ }
+
+ return object_split;
+ }
+
+ /*! array partitioning */
+ __forceinline std::unique_ptr<mvector<PrimRefMB>> split(const Split& split, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ /* perform object split */
+ if (likely(split.data == Split::SPLIT_OBJECT)) {
+ heuristicObjectSplit.split(split,set,lset,rset);
+ }
+ /* perform temporal split */
+ else if (likely(split.data == Split::SPLIT_TEMPORAL)) {
+ return heuristicTemporalSplit.split(split,set,lset,rset);
+ }
+ /* perform fallback split */
+ else if (unlikely(split.data == Split::SPLIT_FALLBACK)) {
+ set.deterministic_order();
+ splitFallback(set,lset,rset);
+ }
+ /* split by geometry */
+ else if (unlikely(split.data == Split::SPLIT_GEOMID)) {
+ set.deterministic_order();
+ splitByGeometry(set,lset,rset);
+ }
+ else
+ assert(false);
+
+ return std::unique_ptr<mvector<PrimRefMB>>();
+ }
+
+ /*! finds the best fallback split */
+ __noinline Split findFallback(const SetMB& set)
+ {
+ /* split if primitives are not from same geometry */
+ if (!sameGeometry(set))
+ return Split(0.0f,Split::SPLIT_GEOMID);
+
+ /* if a leaf can only hold a single time-segment, we might have to do additional temporal splits */
+ if (cfg.singleLeafTimeSegment)
+ {
+ /* test if one primitive has more than one time segment in time range, if so split time */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const PrimRefMB& prim = (*set.prims)[i];
+ const range<int> itime_range = prim.timeSegmentRange(set.time_range);
+ const int localTimeSegments = itime_range.size();
+ assert(localTimeSegments > 0);
+ if (localTimeSegments > 1) {
+ const int icenter = (itime_range.begin() + itime_range.end())/2;
+ const float splitTime = prim.timeStep(icenter);
+ return Split(0.0f,(unsigned)Split::SPLIT_TEMPORAL,0,splitTime);
+ }
+ }
+ }
+
+ /* otherwise return fallback split */
+ return Split(0.0f,Split::SPLIT_FALLBACK);
+ }
+
+ /*! performs fallback split */
+ void splitFallback(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfoMB linfo = empty;
+ for (size_t i=begin; i<center; i++)
+ linfo.add_primref(prims[i]);
+
+ PrimInfoMB rinfo = empty;
+ for (size_t i=center; i<end; i++)
+ rinfo.add_primref(prims[i]);
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const SetMB& set)
+ {
+ if (set.size() == 0) return true;
+ mvector<PrimRefMB>& prims = *set.prims;
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ unsigned int firstGeomID = prims[begin].geomID();
+ for (size_t i=begin+1; i<end; i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* split by geometry ID */
+ void splitByGeometry(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(set.size() > 1);
+
+ mvector<PrimRefMB>& prims = *set.prims;
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+
+ PrimInfoMB left(empty);
+ PrimInfoMB right(empty);
+ unsigned int geomID = prims[begin].geomID();
+ size_t center = serial_partitioning(prims.data(),begin,end,left,right,
+ [&] ( const PrimRefMB& prim ) { return prim.geomID() == geomID; },
+ [ ] ( PrimInfoMB& dst, const PrimRefMB& prim ) { dst.add_primref(prim); });
+
+ new (&lset) SetMB(left, set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ const NodeRecordMB4D createLargeLeaf(const BuildRecord& in, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (in.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* replace already found split by fallback split */
+ const BuildRecordSplit current(BuildRecord(in.prims,in.depth),findFallback(in.prims));
+
+ /* special case when directly creating leaf without any splits that could shrink time_range */
+ bool force_split = false;
+ if (current.depth == 1 && current.size() > 0)
+ {
+ BBox1f c = empty;
+ BBox1f p = current.prims.time_range;
+ for (size_t i=current.prims.begin(); i<current.prims.end(); i++) {
+ mvector<PrimRefMB>& prims = *current.prims.prims;
+ c.extend(prims[i].time_range);
+ }
+
+ force_split = c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create leaf for few primitives */
+ if (current.size() <= cfg.maxLeafSize && current.split.data < Split::SPLIT_ENFORCE && !force_split)
+ return createLeaf(current,alloc);
+
+ /* fill all children by always splitting the largest one */
+ bool hasTimeSplits = false;
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildListSplit children(current);
+
+ do {
+ /* find best child with largest bounding box area */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && children[i].split.data < Split::SPLIT_ENFORCE && !force_split)
+ continue;
+
+ force_split = false;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform best found split */
+ BuildRecordSplit& brecord = children[bestChild];
+ BuildRecordSplit lrecord(current.depth+1);
+ BuildRecordSplit rrecord(current.depth+1);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(brecord.split,brecord.prims,lrecord.prims,rrecord.prims);
+ hasTimeSplits |= new_vector != nullptr;
+
+ /* find new splits */
+ lrecord.split = findFallback(lrecord.prims);
+ rrecord.split = findFallback(rrecord.prims);
+ children.split(bestChild,lrecord,rrecord,std::move(new_vector));
+
+ } while (children.size() < cfg.branchingFactor);
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = in.prims.time_range;
+ hasTimeSplits |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create node */
+ auto node = createNode(children.children.data(),children.numChildren,alloc,hasTimeSplits);
+
+ /* recurse into each child and perform reduction */
+ LBBox3fa gbounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = createLargeLeaf(children[i],alloc);
+ gbounds.extend(values[i].lbounds);
+ }
+
+ setNode(current,children.children.data(),node,values,children.numChildren);
+
+ /* calculate geometry bounds of this node */
+ if (hasTimeSplits)
+ return NodeRecordMB4D(node,current.prims.linearBounds(recalculatePrimRef),current.prims.time_range);
+ else
+ return NodeRecordMB4D(node,gbounds,current.prims.time_range);
+ }
+
+ const NodeRecordMB4D recurse(const BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= cfg.singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /*! find best split */
+ const Split csplit = find(current.prims);
+
+ /*! compute leaf and split cost */
+ const float leafSAH = cfg.intCost*current.prims.leafSAH(cfg.logBlockSize);
+ const float splitSAH = cfg.travCost*current.prims.halfArea()+cfg.intCost*csplit.splitSAH();
+ assert((current.size() == 0) || ((leafSAH >= 0) && (splitSAH >= 0)));
+
+ /*! create a leaf node when threshold reached or SAH tells us to stop */
+ if (current.size() <= cfg.minLeafSize || current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || (current.size() <= cfg.maxLeafSize && leafSAH <= splitSAH)) {
+ current.prims.deterministic_order();
+ return createLargeLeaf(current,alloc);
+ }
+
+ /*! perform initial split */
+ SetMB lprims,rprims;
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(csplit,current.prims,lprims,rprims);
+ bool hasTimeSplits = new_vector != nullptr;
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildList children(current);
+ {
+ BuildRecord lrecord(lprims,current.depth+1);
+ BuildRecord rrecord(rprims,current.depth+1);
+ children.split(0,lrecord,rrecord,std::move(new_vector));
+ }
+
+ /*! split until node is full or SAH tells us to stop */
+ while (children.size() < cfg.branchingFactor)
+ {
+ /*! find best child to split */
+ float bestArea = neg_inf;
+ ssize_t bestChild = -1;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ if (children[i].size() <= cfg.minLeafSize) continue;
+ if (expectedApproxHalfArea(children[i].prims.geomBounds) > bestArea) {
+ bestChild = i; bestArea = expectedApproxHalfArea(children[i].prims.geomBounds);
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform split */
+ BuildRecord& brecord = children[bestChild];
+ BuildRecord lrecord(current.depth+1);
+ BuildRecord rrecord(current.depth+1);
+ Split csplit = find(brecord.prims);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(csplit,brecord.prims,lrecord.prims,rrecord.prims);
+ hasTimeSplits |= new_vector != nullptr;
+ children.split(bestChild,lrecord,rrecord,std::move(new_vector));
+ }
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ hasTimeSplits |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* sort buildrecords for simpler shadow ray traversal */
+ //std::sort(&children[0],&children[children.size()],std::greater<BuildRecord>()); // FIXME: reduces traversal performance of bvh8.triangle4 (need to verified) !!
+
+ /*! create an inner node */
+ auto node = createNode(children.children.data(), children.numChildren, alloc, hasTimeSplits);
+ LBBox3fa gbounds = empty;
+
+ /* spawn tasks */
+ if (unlikely(current.size() > cfg.singleThreadThreshold))
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ /*! merge bounding boxes */
+ for (size_t i=0; i<children.size(); i++)
+ gbounds.extend(values[i].lbounds);
+ }
+ /* recurse into each child */
+ else
+ {
+ //for (size_t i=0; i<children.size(); i++)
+ for (ssize_t i=children.size()-1; i>=0; i--) {
+ values[i] = recurse(children[i],alloc,false);
+ gbounds.extend(values[i].lbounds);
+ }
+ }
+
+ setNode(current,children.children.data(),node,values,children.numChildren);
+
+ /* calculate geometry bounds of this node */
+ if (unlikely(hasTimeSplits))
+ return NodeRecordMB4D(node,current.prims.linearBounds(recalculatePrimRef),current.prims.time_range);
+ else
+ return NodeRecordMB4D(node,gbounds,current.prims.time_range);
+ }
+
+ /*! builder entry function */
+ __forceinline const NodeRecordMB4D operator() (mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo)
+ {
+ const SetMB set(pinfo,&prims);
+ auto ret = recurse(BuildRecord(set,1),nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return ret;
+ }
+
+ private:
+ Settings cfg;
+ HeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> heuristicObjectSplit;
+ HeuristicMBlurTemporalSplit<PrimRefMB,RecalculatePrimRef,MBLUR_NUM_TEMPORAL_BINS> heuristicTemporalSplit;
+ const RecalculatePrimRef recalculatePrimRef;
+ const CreateAllocFunc createAlloc;
+ const CreateNodeFunc createNode;
+ const SetNodeFunc setNode;
+ const CreateLeafFunc createLeaf;
+ const ProgressMonitor progressMonitor;
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitorFunc>
+
+ static const BVHNodeRecordMB4D<NodeRef> build(mvector<PrimRefMB>& prims,
+ const PrimInfoMB& pinfo,
+ MemoryMonitorInterface* device,
+ const RecalculatePrimRef recalculatePrimRef,
+ const CreateAllocFunc createAlloc,
+ const CreateNodeFunc createNode,
+ const SetNodeFunc setNode,
+ const CreateLeafFunc createLeaf,
+ const ProgressMonitorFunc progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuilderT<
+ NodeRef,
+ RecalculatePrimRef,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ SetNodeFunc,
+ CreateLeafFunc,
+ ProgressMonitorFunc> Builder;
+
+ Builder builder(device,
+ recalculatePrimRef,
+ createAlloc,
+ createNode,
+ setNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+
+
+ return builder(prims,pinfo);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur_hair.h b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur_hair.h
new file mode 100644
index 0000000000..e477c313a3
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_msmblur_hair.h
@@ -0,0 +1,526 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../geometry/primitive.h"
+#include "../builders/bvh_builder_msmblur.h"
+#include "../builders/heuristic_binning_array_aligned.h"
+#include "../builders/heuristic_binning_array_unaligned.h"
+#include "../builders/heuristic_timesplit_array.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderHairMSMBlur
+ {
+ /*! settings for msmblur builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(8) {}
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ };
+
+ struct BuildRecord
+ {
+ public:
+ __forceinline BuildRecord () {}
+
+ __forceinline BuildRecord (size_t depth)
+ : depth(depth) {}
+
+ __forceinline BuildRecord (const SetMB& prims, size_t depth)
+ : depth(depth), prims(prims) {}
+
+ __forceinline size_t size() const {
+ return prims.size();
+ }
+
+ public:
+ size_t depth; //!< depth of the root of this subtree
+ SetMB prims; //!< the list of primitives
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeMBFunc,
+ typename SetAABBNodeMBFunc,
+ typename CreateOBBNodeMBFunc,
+ typename SetOBBNodeMBFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+ static const size_t SINGLE_THREADED_THRESHOLD = 4096; //!< threshold to switch to single threaded build
+
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ typedef FastAllocator::CachedAllocator Allocator;
+ typedef LocalChildListT<BuildRecord,MAX_BRANCHING_FACTOR> LocalChildList;
+
+ typedef HeuristicMBlurTemporalSplit<PrimRefMB,RecalculatePrimRef,MBLUR_NUM_TEMPORAL_BINS> HeuristicTemporal;
+ typedef HeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> HeuristicBinning;
+ typedef UnalignedHeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> UnalignedHeuristicBinning;
+
+ public:
+
+ BuilderT (Scene* scene,
+ const RecalculatePrimRef& recalculatePrimRef,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeMBFunc& createAABBNodeMB,
+ const SetAABBNodeMBFunc& setAABBNodeMB,
+ const CreateOBBNodeMBFunc& createOBBNodeMB,
+ const SetOBBNodeMBFunc& setOBBNodeMB,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings settings)
+
+ : cfg(settings),
+ scene(scene),
+ recalculatePrimRef(recalculatePrimRef),
+ createAlloc(createAlloc),
+ createAABBNodeMB(createAABBNodeMB), setAABBNodeMB(setAABBNodeMB),
+ createOBBNodeMB(createOBBNodeMB), setOBBNodeMB(setOBBNodeMB),
+ createLeaf(createLeaf),
+ progressMonitor(progressMonitor),
+ unalignedHeuristic(scene),
+ temporalSplitHeuristic(scene->device,recalculatePrimRef) {}
+
+ private:
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const SetMB& set)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+ unsigned int firstGeomID = prims[set.begin()].geomID();
+ for (size_t i=set.begin()+1; i<set.end(); i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*! performs some split if SAH approaches fail */
+ void splitFallback(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfoMB linfo = empty;
+ for (size_t i=begin; i<center; i++)
+ linfo.add_primref(prims[i]);
+
+ PrimInfoMB rinfo = empty;
+ for (size_t i=center; i<end; i++)
+ rinfo.add_primref(prims[i]);
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ void splitByGeometry(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(set.size() > 1);
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB linfo(empty);
+ PrimInfoMB rinfo(empty);
+ unsigned int geomID = (*set.prims)[begin].geomID();
+ size_t center = serial_partitioning(set.prims->data(),begin,end,linfo,rinfo,
+ [&] ( const PrimRefMB& prim ) { return prim.geomID() == geomID; },
+ [ ] ( PrimInfoMB& a, const PrimRefMB& ref ) { a.add_primref(ref); });
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ /*! creates a large leaf that could be larger than supported by the BVH */
+ NodeRecordMB4D createLargeLeaf(BuildRecord& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (current.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* special case when directly creating leaf without any splits that could shrink time_range */
+ bool force_split = false;
+ if (current.depth == 1 && current.size() > 0)
+ {
+ BBox1f c = empty;
+ BBox1f p = current.prims.time_range;
+ for (size_t i=current.prims.begin(); i<current.prims.end(); i++) {
+ mvector<PrimRefMB>& prims = *current.prims.prims;
+ c.extend(prims[i].time_range);
+ }
+
+ force_split = c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create leaf for few primitives */
+ if (current.size() <= cfg.maxLeafSize && sameGeometry(current.prims) && !force_split)
+ return createLeaf(current.prims,alloc);
+
+ /* fill all children by always splitting the largest one */
+ LocalChildList children(current);
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+
+ do {
+
+ /* find best child with largest bounding box area */
+ int bestChild = -1;
+ size_t bestSize = 0;
+ for (unsigned i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && sameGeometry(children[i].prims) && !force_split)
+ continue;
+
+ force_split = false;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ if (!sameGeometry(children[bestChild].prims)) {
+ splitByGeometry(children[bestChild].prims,left.prims,right.prims);
+ } else {
+ splitFallback(children[bestChild].prims,left.prims,right.prims);
+ }
+ children.split(bestChild,left,right,std::unique_ptr<mvector<PrimRefMB>>());
+
+ } while (children.size() < cfg.branchingFactor);
+
+
+ /* detect time_ranges that have shrunken */
+ bool timesplit = false;
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ timesplit |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create node */
+ NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,timesplit);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = createLargeLeaf(children[i],alloc);
+ bounds.extend(values[i].lbounds);
+ }
+
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+
+ if (timesplit)
+ bounds = current.prims.linearBounds(recalculatePrimRef);
+
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+
+ /*! performs split */
+ std::unique_ptr<mvector<PrimRefMB>> split(const BuildRecord& current, BuildRecord& lrecord, BuildRecord& rrecord, bool& aligned, bool& timesplit)
+ {
+ /* variable to track the SAH of the best splitting approach */
+ float bestSAH = inf;
+ const float leafSAH = current.prims.leafSAH(cfg.logBlockSize);
+
+ /* perform standard binning in aligned space */
+ HeuristicBinning::Split alignedObjectSplit = alignedHeuristic.find(current.prims,cfg.logBlockSize);
+ float alignedObjectSAH = alignedObjectSplit.splitSAH();
+ bestSAH = min(alignedObjectSAH,bestSAH);
+
+ /* perform standard binning in unaligned space */
+ UnalignedHeuristicBinning::Split unalignedObjectSplit;
+ LinearSpace3fa uspace;
+ float unalignedObjectSAH = inf;
+ if (alignedObjectSAH > 0.7f*leafSAH) {
+ uspace = unalignedHeuristic.computeAlignedSpaceMB(scene,current.prims);
+ const SetMB sset = current.prims.primInfo(recalculatePrimRef,uspace);
+ unalignedObjectSplit = unalignedHeuristic.find(sset,cfg.logBlockSize,uspace);
+ unalignedObjectSAH = 1.3f*unalignedObjectSplit.splitSAH(); // makes unaligned splits more expensive
+ bestSAH = min(unalignedObjectSAH,bestSAH);
+ }
+
+ /* do temporal splits only if previous approaches failed to produce good SAH and the the time range is large enough */
+ float temporal_split_sah = inf;
+ typename HeuristicTemporal::Split temporal_split;
+ if (bestSAH > 0.5f*leafSAH) {
+ if (current.prims.time_range.size() > 1.01f/float(current.prims.max_num_time_segments)) {
+ temporal_split = temporalSplitHeuristic.find(current.prims,cfg.logBlockSize);
+ temporal_split_sah = temporal_split.splitSAH();
+ bestSAH = min(temporal_split_sah,bestSAH);
+ }
+ }
+
+ /* perform fallback split if SAH heuristics failed */
+ if (unlikely(!std::isfinite(bestSAH))) {
+ current.prims.deterministic_order();
+ splitFallback(current.prims,lrecord.prims,rrecord.prims);
+ }
+ /* perform aligned split if this is best */
+ else if (likely(bestSAH == alignedObjectSAH)) {
+ alignedHeuristic.split(alignedObjectSplit,current.prims,lrecord.prims,rrecord.prims);
+ }
+ /* perform unaligned split if this is best */
+ else if (likely(bestSAH == unalignedObjectSAH)) {
+ unalignedHeuristic.split(unalignedObjectSplit,uspace,current.prims,lrecord.prims,rrecord.prims);
+ aligned = false;
+ }
+ /* perform temporal split if this is best */
+ else if (likely(bestSAH == temporal_split_sah)) {
+ timesplit = true;
+ return temporalSplitHeuristic.split(temporal_split,current.prims,lrecord.prims,rrecord.prims);
+ }
+ else
+ assert(false);
+
+ return std::unique_ptr<mvector<PrimRefMB>>();
+ }
+
+ /*! recursive build */
+ NodeRecordMB4D recurse(BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= SINGLE_THREADED_THRESHOLD)
+ progressMonitor(current.size());
+
+ /* create leaf node */
+ if (current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || current.size() <= cfg.minLeafSize) {
+ current.prims.deterministic_order();
+ return createLargeLeaf(current,alloc);
+ }
+
+ /* fill all children by always splitting the one with the largest surface area */
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildList children(current);
+ bool aligned = true;
+ bool timesplit = false;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ ssize_t bestChild = -1;
+ float bestArea = neg_inf;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ const float A = children[i].prims.halfArea();
+ if (A > bestArea) {
+ bestArea = children[i].prims.halfArea();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(children[bestChild],left,right,aligned,timesplit);
+ children.split(bestChild,left,right,std::move(new_vector));
+
+ } while (children.size() < cfg.branchingFactor);
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ timesplit |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create time split node */
+ if (timesplit)
+ {
+ const NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,true);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequential */
+ else {
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = recurse(children[i],alloc,false);
+ }
+ }
+
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+
+ const LBBox3fa bounds = current.prims.linearBounds(recalculatePrimRef);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+
+ /* create aligned node */
+ else if (aligned)
+ {
+ const NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,true);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ LBBox3fa cbounds[MAX_BRANCHING_FACTOR];
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ cbounds[i] = values[i].lbounds;
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++)
+ bounds.extend(cbounds[i]);
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ /* ... continue sequentially */
+ else
+ {
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = recurse(children[i],alloc,false);
+ bounds.extend(values[i].lbounds);
+ }
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ }
+
+ /* create unaligned node */
+ else
+ {
+ const NodeRef node = createOBBNodeMB(alloc);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpaceMB(scene,children[i].prims);
+ const LBBox3fa lbounds = children[i].prims.linearBounds(recalculatePrimRef,space);
+ const auto child = recurse(children[i],nullptr,true);
+ setOBBNodeMB(node,i,child.ref,space,lbounds,children[i].prims.time_range);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else
+ {
+ for (size_t i=0; i<children.size(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpaceMB(scene,children[i].prims);
+ const LBBox3fa lbounds = children[i].prims.linearBounds(recalculatePrimRef,space);
+ const auto child = recurse(children[i],alloc,false);
+ setOBBNodeMB(node,i,child.ref,space,lbounds,children[i].prims.time_range);
+ }
+ }
+
+ const LBBox3fa bounds = current.prims.linearBounds(recalculatePrimRef);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ }
+
+ public:
+
+ /*! entry point into builder */
+ NodeRecordMB4D operator() (mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo)
+ {
+ BuildRecord record(SetMB(pinfo,&prims),1);
+ auto root = recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ private:
+ Settings cfg;
+ Scene* scene;
+ const RecalculatePrimRef& recalculatePrimRef;
+ const CreateAllocFunc& createAlloc;
+ const CreateAABBNodeMBFunc& createAABBNodeMB;
+ const SetAABBNodeMBFunc& setAABBNodeMB;
+ const CreateOBBNodeMBFunc& createOBBNodeMB;
+ const SetOBBNodeMBFunc& setOBBNodeMB;
+ const CreateLeafFunc& createLeaf;
+ const ProgressMonitor& progressMonitor;
+
+ private:
+ HeuristicBinning alignedHeuristic;
+ UnalignedHeuristicBinning unalignedHeuristic;
+ HeuristicTemporal temporalSplitHeuristic;
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeMBFunc,
+ typename SetAABBNodeMBFunc,
+ typename CreateOBBNodeMBFunc,
+ typename SetOBBNodeMBFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ static BVHNodeRecordMB4D<NodeRef> build (Scene* scene, mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo,
+ const RecalculatePrimRef& recalculatePrimRef,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeMBFunc& createAABBNodeMB,
+ const SetAABBNodeMBFunc& setAABBNodeMB,
+ const CreateOBBNodeMBFunc& createOBBNodeMB,
+ const SetOBBNodeMBFunc& setOBBNodeMB,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings settings)
+ {
+ typedef BuilderT<NodeRef,RecalculatePrimRef,CreateAllocFunc,
+ CreateAABBNodeMBFunc,SetAABBNodeMBFunc,
+ CreateOBBNodeMBFunc,SetOBBNodeMBFunc,
+ CreateLeafFunc,ProgressMonitor> Builder;
+
+ Builder builder(scene,recalculatePrimRef,createAlloc,
+ createAABBNodeMB,setAABBNodeMB,
+ createOBBNodeMB,setOBBNodeMB,
+ createLeaf,progressMonitor,settings);
+
+ return builder(prims,pinfo);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/bvh_builder_sah.h b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_sah.h
new file mode 100644
index 0000000000..3f7e678a10
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/bvh_builder_sah.h
@@ -0,0 +1,669 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning_array_aligned.h"
+#include "heuristic_spatial_array.h"
+#include "heuristic_openmerge_array.h"
+
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+# define NUM_OBJECT_BINS 16
+# define NUM_SPATIAL_BINS 16
+#else
+# define NUM_OBJECT_BINS 32
+# define NUM_SPATIAL_BINS 16
+#endif
+
+namespace embree
+{
+ namespace isa
+ {
+ MAYBE_UNUSED static const float travCost = 1.0f;
+ MAYBE_UNUSED static const size_t DEFAULT_SINGLE_THREAD_THRESHOLD = 1024;
+
+ struct GeneralBVHBuilder
+ {
+ static const size_t MAX_BRANCHING_FACTOR = 16; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree of we are that many levels before the maximum tree depth
+
+
+ /*! settings for SAH builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7),
+ travCost(1.0f), intCost(1.0f), singleThreadThreshold(1024), primrefarrayalloc(inf) {}
+
+ /*! initialize settings from API settings */
+ Settings (const RTCBuildArguments& settings)
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7),
+ travCost(1.0f), intCost(1.0f), singleThreadThreshold(1024), primrefarrayalloc(inf)
+ {
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxBranchingFactor)) branchingFactor = settings.maxBranchingFactor;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxDepth )) maxDepth = settings.maxDepth;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,sahBlockSize )) logBlockSize = bsr(static_cast<size_t>(settings.sahBlockSize));
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,traversalCost )) travCost = settings.traversalCost;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,intersectionCost )) intCost = settings.intersectionCost;
+
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ Settings (size_t sahBlockSize, size_t minLeafSize, size_t maxLeafSize, float travCost, float intCost, size_t singleThreadThreshold, size_t primrefarrayalloc = inf)
+ : branchingFactor(2), maxDepth(32), logBlockSize(bsr(sahBlockSize)), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize),
+ travCost(travCost), intCost(intCost), singleThreadThreshold(singleThreadThreshold), primrefarrayalloc(primrefarrayalloc)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ float travCost; //!< estimated cost of one traversal step
+ float intCost; //!< estimated cost of one primitive intersection
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ size_t primrefarrayalloc; //!< builder uses prim ref array to allocate nodes and leaves when a subtree of that size is finished
+ };
+
+ /*! recursive state of builder */
+ template<typename Set, typename Split>
+ struct BuildRecordT
+ {
+ public:
+ __forceinline BuildRecordT () {}
+
+ __forceinline BuildRecordT (size_t depth)
+ : depth(depth), alloc_barrier(false), prims(empty) {}
+
+ __forceinline BuildRecordT (size_t depth, const Set& prims)
+ : depth(depth), alloc_barrier(false), prims(prims) {}
+
+ __forceinline BBox3fa bounds() const { return prims.geomBounds; }
+
+ __forceinline friend bool operator< (const BuildRecordT& a, const BuildRecordT& b) { return a.prims.size() < b.prims.size(); }
+ __forceinline friend bool operator> (const BuildRecordT& a, const BuildRecordT& b) { return a.prims.size() > b.prims.size(); }
+
+ __forceinline size_t size() const { return prims.size(); }
+
+ public:
+ size_t depth; //!< Depth of the root of this subtree.
+ bool alloc_barrier; //!< barrier used to reuse primref-array blocks to allocate nodes
+ Set prims; //!< The list of primitives.
+ };
+
+ template<typename PrimRef, typename Set>
+ struct DefaultCanCreateLeafFunc
+ {
+ __forceinline bool operator()(const PrimRef*, const Set&) const { return true; }
+ };
+
+ template<typename PrimRef, typename Set>
+ struct DefaultCanCreateLeafSplitFunc
+ {
+ __forceinline void operator()(PrimRef*, const Set&, Set&, Set&) const { }
+ };
+
+ template<typename BuildRecord,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename ReductionTy,
+ typename Allocator,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ friend struct GeneralBVHBuilder;
+
+ BuilderT (PrimRef* prims,
+ Heuristic& heuristic,
+ const CreateAllocFunc& createAlloc,
+ const CreateNodeFunc& createNode,
+ const UpdateNodeFunc& updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings) :
+ cfg(settings),
+ prims(prims),
+ heuristic(heuristic),
+ createAlloc(createAlloc),
+ createNode(createNode),
+ updateNode(updateNode),
+ createLeaf(createLeaf),
+ canCreateLeaf(canCreateLeaf),
+ canCreateLeafSplit(canCreateLeafSplit),
+ progressMonitor(progressMonitor)
+ {
+ if (cfg.branchingFactor > MAX_BRANCHING_FACTOR)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
+ }
+
+ const ReductionTy createLargeLeaf(const BuildRecord& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (current.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (current.prims.size() <= cfg.maxLeafSize && canCreateLeaf(prims,current.prims))
+ return createLeaf(prims,current.prims,alloc);
+
+ /* fill all children by always splitting the largest one */
+ ReductionTy values[MAX_BRANCHING_FACTOR];
+ BuildRecord children[MAX_BRANCHING_FACTOR];
+ size_t numChildren = 1;
+ children[0] = current;
+ do {
+
+ /* find best child with largest bounding box area */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].prims.size() <= cfg.maxLeafSize && canCreateLeaf(prims,children[i].prims))
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].prims.size() > bestSize) {
+ bestSize = children[i].prims.size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == (size_t)-1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ if (!canCreateLeaf(prims,children[bestChild].prims)) {
+ canCreateLeafSplit(prims,children[bestChild].prims,left.prims,right.prims);
+ } else {
+ heuristic.splitFallback(children[bestChild].prims,left.prims,right.prims);
+ }
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ /* set barrier for primrefarrayalloc */
+ if (unlikely(current.size() > cfg.primrefarrayalloc))
+ for (size_t i=0; i<numChildren; i++)
+ children[i].alloc_barrier = children[i].size() <= cfg.primrefarrayalloc;
+
+ /* create node */
+ auto node = createNode(children,numChildren,alloc);
+
+ /* recurse into each child and perform reduction */
+ for (size_t i=0; i<numChildren; i++)
+ values[i] = createLargeLeaf(children[i],alloc);
+
+ /* perform reduction */
+ return updateNode(current,children,node,values,numChildren);
+ }
+
+ const ReductionTy recurse(BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= cfg.singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /*! find best split */
+ auto split = heuristic.find(current.prims,cfg.logBlockSize);
+
+ /*! compute leaf and split cost */
+ const float leafSAH = cfg.intCost*current.prims.leafSAH(cfg.logBlockSize);
+ const float splitSAH = cfg.travCost*halfArea(current.prims.geomBounds)+cfg.intCost*split.splitSAH();
+ assert((current.prims.size() == 0) || ((leafSAH >= 0) && (splitSAH >= 0)));
+
+ /*! create a leaf node when threshold reached or SAH tells us to stop */
+ if (current.prims.size() <= cfg.minLeafSize || current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || (current.prims.size() <= cfg.maxLeafSize && leafSAH <= splitSAH)) {
+ heuristic.deterministic_order(current.prims);
+ return createLargeLeaf(current,alloc);
+ }
+
+ /*! perform initial split */
+ Set lprims,rprims;
+ heuristic.split(split,current.prims,lprims,rprims);
+
+ /*! initialize child list with initial split */
+ ReductionTy values[MAX_BRANCHING_FACTOR];
+ BuildRecord children[MAX_BRANCHING_FACTOR];
+ children[0] = BuildRecord(current.depth+1,lprims);
+ children[1] = BuildRecord(current.depth+1,rprims);
+ size_t numChildren = 2;
+
+ /*! split until node is full or SAH tells us to stop */
+ while (numChildren < cfg.branchingFactor)
+ {
+ /*! find best child to split */
+ float bestArea = neg_inf;
+ ssize_t bestChild = -1;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].prims.size() <= cfg.minLeafSize) continue;
+
+ /* find child with largest surface area */
+ if (halfArea(children[i].prims.geomBounds) > bestArea) {
+ bestChild = i;
+ bestArea = halfArea(children[i].prims.geomBounds);
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform best found split */
+ BuildRecord& brecord = children[bestChild];
+ BuildRecord lrecord(current.depth+1);
+ BuildRecord rrecord(current.depth+1);
+ auto split = heuristic.find(brecord.prims,cfg.logBlockSize);
+ heuristic.split(split,brecord.prims,lrecord.prims,rrecord.prims);
+ children[bestChild ] = lrecord;
+ children[numChildren] = rrecord;
+ numChildren++;
+ }
+
+ /* set barrier for primrefarrayalloc */
+ if (unlikely(current.size() > cfg.primrefarrayalloc))
+ for (size_t i=0; i<numChildren; i++)
+ children[i].alloc_barrier = children[i].size() <= cfg.primrefarrayalloc;
+
+ /* sort buildrecords for faster shadow ray traversal */
+ std::sort(&children[0],&children[numChildren],std::greater<BuildRecord>());
+
+ /*! create an inner node */
+ auto node = createNode(children,numChildren,alloc);
+
+ /* spawn tasks */
+ if (current.size() > cfg.singleThreadThreshold)
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) { // FIXME: no range here
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ return updateNode(current,children,node,values,numChildren);
+ }
+ /* recurse into each child */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++)
+ values[i] = recurse(children[i],alloc,false);
+
+ return updateNode(current,children,node,values,numChildren);
+ }
+ }
+
+ private:
+ Settings cfg;
+ PrimRef* prims;
+ Heuristic& heuristic;
+ const CreateAllocFunc& createAlloc;
+ const CreateNodeFunc& createNode;
+ const UpdateNodeFunc& updateNode;
+ const CreateLeafFunc& createLeaf;
+ const CanCreateLeafFunc& canCreateLeaf;
+ const CanCreateLeafSplitFunc& canCreateLeafSplit;
+ const ProgressMonitor& progressMonitor;
+ };
+
+ template<
+ typename ReductionTy,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ __noinline static ReductionTy build(Heuristic& heuristic,
+ PrimRef* prims,
+ const Set& set,
+ CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+
+ typedef BuilderT<
+ BuildRecord,
+ Heuristic,
+ Set,
+ PrimRef,
+ ReductionTy,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ UpdateNodeFunc,
+ CreateLeafFunc,
+ DefaultCanCreateLeafFunc<PrimRef, Set>,
+ DefaultCanCreateLeafSplitFunc<PrimRef, Set>,
+ ProgressMonitor> Builder;
+
+ /* instantiate builder */
+ Builder builder(prims,
+ heuristic,
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ DefaultCanCreateLeafFunc<PrimRef, Set>(),
+ DefaultCanCreateLeafSplitFunc<PrimRef, Set>(),
+ progressMonitor,
+ settings);
+
+ /* build hierarchy */
+ BuildRecord record(1,set);
+ const ReductionTy root = builder.recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ template<
+ typename ReductionTy,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ __noinline static ReductionTy build(Heuristic& heuristic,
+ PrimRef* prims,
+ const Set& set,
+ CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+
+ typedef BuilderT<
+ BuildRecord,
+ Heuristic,
+ Set,
+ PrimRef,
+ ReductionTy,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ UpdateNodeFunc,
+ CreateLeafFunc,
+ CanCreateLeafFunc,
+ CanCreateLeafSplitFunc,
+ ProgressMonitor> Builder;
+
+ /* instantiate builder */
+ Builder builder(prims,
+ heuristic,
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ canCreateLeaf,
+ canCreateLeafSplit,
+ progressMonitor,
+ settings);
+
+ /* build hierarchy */
+ BuildRecord record(1,set);
+ const ReductionTy root = builder.recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+ };
+
+ /* SAH builder that operates on an array of BuildRecords */
+ struct BVHBuilderBinnedSAH
+ {
+ typedef PrimInfoRange Set;
+ typedef HeuristicArrayBinningSAH<PrimRef,NUM_OBJECT_BINS> Heuristic;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ PrimRef* prims, const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ Heuristic heuristic(prims);
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoRange(0,pinfo.size(),pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+ }
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ PrimRef* prims, const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ Heuristic heuristic(prims);
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoRange(0,pinfo.size(),pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ canCreateLeaf,
+ canCreateLeafSplit,
+ progressMonitor,
+ settings);
+ }
+ };
+
+ /* Spatial SAH builder that operates on an double-buffered array of BuildRecords */
+ struct BVHBuilderBinnedFastSpatialSAH
+ {
+ typedef PrimInfoExtRange Set;
+ typedef Split2<BinSplit<NUM_OBJECT_BINS>,SpatialBinSplit<NUM_SPATIAL_BINS> > Split;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ static const unsigned int GEOMID_MASK = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ static const unsigned int SPLITS_MASK = 0xFFFFFFFF << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ template<typename ReductionTy, typename UserCreateLeaf>
+ struct CreateLeafExt
+ {
+ __forceinline CreateLeafExt (const UserCreateLeaf userCreateLeaf)
+ : userCreateLeaf(userCreateLeaf) {}
+
+ // __noinline is workaround for ICC2016 compiler bug
+ template<typename Allocator>
+ __noinline ReductionTy operator() (PrimRef* prims, const range<size_t>& range, Allocator alloc) const
+ {
+ for (size_t i=range.begin(); i<range.end(); i++)
+ prims[i].lower.u &= GEOMID_MASK;
+
+ return userCreateLeaf(prims,range,alloc);
+ }
+
+ const UserCreateLeaf userCreateLeaf;
+ };
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename SplitPrimitiveFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode,
+ UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ SplitPrimitiveFunc splitPrimitive,
+ ProgressMonitor progressMonitor,
+ PrimRef* prims,
+ const size_t extSize,
+ const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ typedef HeuristicArraySpatialSAH<SplitPrimitiveFunc,PrimRef,NUM_OBJECT_BINS,NUM_SPATIAL_BINS> Heuristic;
+ Heuristic heuristic(splitPrimitive,prims,pinfo);
+
+ /* calculate total surface area */ // FIXME: this sum is not deterministic
+ const float A = (float) parallel_reduce(size_t(0),pinfo.size(),0.0, [&] (const range<size_t>& r) -> double {
+
+ double A = 0.0f;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ A += area(prim.bounds());
+ }
+ return A;
+ },std::plus<double>());
+
+
+ /* calculate maximum number of spatial splits per primitive */
+ const unsigned int maxSplits = ((size_t)1 << RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)-1;
+ const float f = 10.0f;
+
+ const float invA = 1.0f / A;
+ parallel_for( size_t(0), pinfo.size(), [&](const range<size_t>& r) {
+
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ assert((prim.geomID() & SPLITS_MASK) == 0);
+ // FIXME: is there a better general heuristic ?
+ const float nf = ceilf(f*pinfo.size()*area(prim.bounds()) * invA);
+ unsigned int n = 4+min((int)maxSplits-4, max(1, (int)(nf)));
+ prim.lower.u |= n << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+ }
+ });
+
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoExtRange(0,pinfo.size(),extSize,pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ CreateLeafExt<ReductionTy,CreateLeafFunc>(createLeaf),
+ progressMonitor,
+ settings);
+ }
+ };
+
+ /* Open/Merge SAH builder that operates on an array of BuildRecords */
+ struct BVHBuilderBinnedOpenMergeSAH
+ {
+ static const size_t NUM_OBJECT_BINS_HQ = 32;
+ typedef PrimInfoExtRange Set;
+ typedef BinSplit<NUM_OBJECT_BINS_HQ> Split;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename BuildRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename NodeOpenerFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode,
+ UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ NodeOpenerFunc nodeOpenerFunc,
+ ProgressMonitor progressMonitor,
+ BuildRef* prims,
+ const size_t extSize,
+ const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ typedef HeuristicArrayOpenMergeSAH<NodeOpenerFunc,BuildRef,NUM_OBJECT_BINS_HQ> Heuristic;
+ Heuristic heuristic(nodeOpenerFunc,prims,settings.branchingFactor);
+
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,BuildRef>(
+ heuristic,
+ prims,
+ PrimInfoExtRange(0,pinfo.size(),extSize,pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_binning.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning.h
new file mode 100644
index 0000000000..a4d3b68e46
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning.h
@@ -0,0 +1,972 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "priminfo.h"
+#include "../../common/algorithms/parallel_reduce.h"
+#include "../../common/algorithms/parallel_partition.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! mapping into bins */
+ template<size_t BINS>
+ struct BinMapping
+ {
+ public:
+ __forceinline BinMapping() {}
+
+ /*! calculates the mapping */
+ __forceinline BinMapping(size_t N, const BBox3fa& centBounds)
+ {
+ num = min(BINS,size_t(4.0f + 0.05f*N));
+ assert(num >= 1);
+ const vfloat4 eps = 1E-34f;
+ const vfloat4 diag = max(eps, (vfloat4) centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) centBounds.lower;
+ }
+
+ /*! calculates the mapping */
+ __forceinline BinMapping(const BBox3fa& centBounds)
+ {
+ num = BINS;
+ const vfloat4 eps = 1E-34f;
+ const vfloat4 diag = max(eps, (vfloat4) centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) centBounds.lower;
+ }
+
+ /*! calculates the mapping */
+ template<typename PrimInfo>
+ __forceinline BinMapping(const PrimInfo& pinfo)
+ {
+ const vfloat4 eps = 1E-34f;
+ num = min(BINS,size_t(4.0f + 0.05f*pinfo.size()));
+ const vfloat4 diag = max(eps,(vfloat4) pinfo.centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) pinfo.centBounds.lower;
+ }
+
+ /*! returns number of bins */
+ __forceinline size_t size() const { return num; }
+
+ /*! slower but safe binning */
+ __forceinline Vec3ia bin(const Vec3fa& p) const
+ {
+ const vint4 i = floori((vfloat4(p)-ofs)*scale);
+#if 1
+ assert(i[0] >= 0 && (size_t)i[0] < num);
+ assert(i[1] >= 0 && (size_t)i[1] < num);
+ assert(i[2] >= 0 && (size_t)i[2] < num);
+ return Vec3ia(i);
+#else
+ return Vec3ia(clamp(i,vint4(0),vint4(num-1)));
+#endif
+ }
+
+ /*! faster but unsafe binning */
+ __forceinline Vec3ia bin_unsafe(const Vec3fa& p) const {
+ return Vec3ia(floori((vfloat4(p)-ofs)*scale));
+ }
+
+ /*! faster but unsafe binning */
+ template<typename PrimRef>
+ __forceinline Vec3ia bin_unsafe(const PrimRef& p) const {
+ return bin_unsafe(p.binCenter());
+ }
+
+ /*! faster but unsafe binning */
+ template<typename PrimRef, typename BinBoundsAndCenter>
+ __forceinline Vec3ia bin_unsafe(const PrimRef& p, const BinBoundsAndCenter& binBoundsAndCenter) const {
+ return bin_unsafe(binBoundsAndCenter.binCenter(p));
+ }
+
+ template<typename PrimRef>
+ __forceinline bool bin_unsafe(const PrimRef& ref,
+ const vint4& vSplitPos,
+ const vbool4& splitDimMask) const // FIXME: rename to isLeft
+ {
+ return any(((vint4)bin_unsafe(center2(ref.bounds())) < vSplitPos) & splitDimMask);
+ }
+ /*! calculates left spatial position of bin */
+ __forceinline float pos(const size_t bin, const size_t dim) const {
+ return madd(float(bin),1.0f / scale[dim],ofs[dim]);
+ }
+
+ /*! returns true if the mapping is invalid in some dimension */
+ __forceinline bool invalid(const size_t dim) const {
+ return scale[dim] == 0.0f;
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const BinMapping& mapping) {
+ return cout << "BinMapping { num = " << mapping.num << ", ofs = " << mapping.ofs << ", scale = " << mapping.scale << "}";
+ }
+
+ public:
+ size_t num;
+ vfloat4 ofs,scale; //!< linear function that maps to bin ID
+ };
+
+ /*! stores all information to perform some split */
+ template<size_t BINS>
+ struct BinSplit
+ {
+ enum
+ {
+ SPLIT_OBJECT = 0,
+ SPLIT_FALLBACK = 1,
+ SPLIT_ENFORCE = 2, // splits with larger ID are enforced in createLargeLeaf even if we could create a leaf already
+ SPLIT_TEMPORAL = 2,
+ SPLIT_GEOMID = 3,
+ };
+
+ /*! construct an invalid split by default */
+ __forceinline BinSplit()
+ : sah(inf), dim(-1), pos(0), data(0) {}
+
+ __forceinline BinSplit(float sah, unsigned data, int dim = 0, float fpos = 0)
+ : sah(sah), dim(dim), fpos(fpos), data(data) {}
+
+ /*! constructs specified split */
+ __forceinline BinSplit(float sah, int dim, int pos, const BinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), data(0), mapping(mapping) {}
+
+ /*! tests if this split is valid */
+ __forceinline bool valid() const { return dim != -1; }
+
+ /*! calculates surface area heuristic for performing the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const BinSplit& split) {
+ return cout << "BinSplit { sah = " << split.sah << ", dim = " << split.dim << ", pos = " << split.pos << "}";
+ }
+
+ public:
+ float sah; //!< SAH cost of the split
+ int dim; //!< split dimension
+ union { int pos; float fpos; }; //!< bin index for splitting
+ unsigned int data; //!< extra optional split data
+ BinMapping<BINS> mapping; //!< mapping into bins
+ };
+
+ /*! stores extended information about the split */
+ template<typename BBox>
+ struct SplitInfoT
+ {
+
+ __forceinline SplitInfoT () {}
+
+ __forceinline SplitInfoT (size_t leftCount, const BBox& leftBounds, size_t rightCount, const BBox& rightBounds)
+ : leftCount(leftCount), rightCount(rightCount), leftBounds(leftBounds), rightBounds(rightBounds) {}
+
+ public:
+ size_t leftCount,rightCount;
+ BBox leftBounds,rightBounds;
+ };
+
+ typedef SplitInfoT<BBox3fa> SplitInfo;
+ typedef SplitInfoT<LBBox3fa> SplitInfo2;
+
+ /*! stores all binning information */
+ template<size_t BINS, typename PrimRef, typename BBox>
+ struct __aligned(64) BinInfoT
+ {
+ typedef BinSplit<BINS> Split;
+ typedef vbool4 vbool;
+ typedef vint4 vint;
+ typedef vfloat4 vfloat;
+
+ __forceinline BinInfoT() {
+ }
+
+ __forceinline BinInfoT(EmptyTy) {
+ clear();
+ }
+
+ /*! bin access function */
+ __forceinline BBox &bounds(const size_t binID, const size_t dimID) { return _bounds[binID][dimID]; }
+ __forceinline const BBox &bounds(const size_t binID, const size_t dimID) const { return _bounds[binID][dimID]; }
+
+ __forceinline unsigned int &counts(const size_t binID, const size_t dimID) { return _counts[binID][dimID]; }
+ __forceinline const unsigned int &counts(const size_t binID, const size_t dimID) const { return _counts[binID][dimID]; }
+
+ __forceinline vuint4 &counts(const size_t binID) { return _counts[binID]; }
+ __forceinline const vuint4 &counts(const size_t binID) const { return _counts[binID]; }
+
+ /*! clears the bin info */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<BINS; i++) {
+ bounds(i,0) = bounds(i,1) = bounds(i,2) = empty;
+ counts(i) = vuint4(zero);
+ }
+ }
+
+ /*! bins an array of primitives */
+ __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<BINS>& mapping)
+ {
+ if (unlikely(N == 0)) return;
+ size_t i;
+ for (i=0; i<N-1; i+=2)
+ {
+ /*! map even and odd primitive to bin */
+ BBox prim0; Vec3fa center0;
+ prims[i+0].binBoundsAndCenter(prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ BBox prim1; Vec3fa center1;
+ prims[i+1].binBoundsAndCenter(prim1,center1);
+ const vint4 bin1 = (vint4)mapping.bin(center1);
+
+ /*! increase bounds for bins for even primitive */
+ const unsigned int b00 = extract<0>(bin0); bounds(b00,0).extend(prim0);
+ const unsigned int b01 = extract<1>(bin0); bounds(b01,1).extend(prim0);
+ const unsigned int b02 = extract<2>(bin0); bounds(b02,2).extend(prim0);
+ const unsigned int s0 = (unsigned int)prims[i+0].size();
+ counts(b00,0)+=s0;
+ counts(b01,1)+=s0;
+ counts(b02,2)+=s0;
+
+ /*! increase bounds of bins for odd primitive */
+ const unsigned int b10 = extract<0>(bin1); bounds(b10,0).extend(prim1);
+ const unsigned int b11 = extract<1>(bin1); bounds(b11,1).extend(prim1);
+ const unsigned int b12 = extract<2>(bin1); bounds(b12,2).extend(prim1);
+ const unsigned int s1 = (unsigned int)prims[i+1].size();
+ counts(b10,0)+=s1;
+ counts(b11,1)+=s1;
+ counts(b12,2)+=s1;
+ }
+ /*! for uneven number of primitives */
+ if (i < N)
+ {
+ /*! map primitive to bin */
+ BBox prim0; Vec3fa center0;
+ prims[i].binBoundsAndCenter(prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ /*! increase bounds of bins */
+ const unsigned int s0 = (unsigned int)prims[i].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+ }
+ }
+
+ /*! bins an array of primitives */
+ template<typename BinBoundsAndCenter>
+ __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<BINS>& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (N == 0) return;
+
+ size_t i;
+ for (i=0; i<N-1; i+=2)
+ {
+ /*! map even and odd primitive to bin */
+ BBox prim0; Vec3fa center0; binBoundsAndCenter.binBoundsAndCenter(prims[i+0],prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+ BBox prim1; Vec3fa center1; binBoundsAndCenter.binBoundsAndCenter(prims[i+1],prim1,center1);
+ const vint4 bin1 = (vint4)mapping.bin(center1);
+
+ /*! increase bounds for bins for even primitive */
+ const unsigned int s0 = prims[i+0].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+
+ /*! increase bounds of bins for odd primitive */
+ const unsigned int s1 = prims[i+1].size();
+ const int b10 = extract<0>(bin1); counts(b10,0)+=s1; bounds(b10,0).extend(prim1);
+ const int b11 = extract<1>(bin1); counts(b11,1)+=s1; bounds(b11,1).extend(prim1);
+ const int b12 = extract<2>(bin1); counts(b12,2)+=s1; bounds(b12,2).extend(prim1);
+ }
+
+ /*! for uneven number of primitives */
+ if (i < N)
+ {
+ /*! map primitive to bin */
+ BBox prim0; Vec3fa center0; binBoundsAndCenter.binBoundsAndCenter(prims[i+0],prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ /*! increase bounds of bins */
+ const unsigned int s0 = prims[i+0].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+ }
+ }
+
+ __forceinline void bin(const PrimRef* prims, size_t begin, size_t end, const BinMapping<BINS>& mapping) {
+ bin(prims+begin,end-begin,mapping);
+ }
+
+ template<typename BinBoundsAndCenter>
+ __forceinline void bin(const PrimRef* prims, size_t begin, size_t end, const BinMapping<BINS>& mapping, const BinBoundsAndCenter& binBoundsAndCenter) {
+ bin<BinBoundsAndCenter>(prims+begin,end-begin,mapping,binBoundsAndCenter);
+ }
+
+ /*! merges in other binning information */
+ __forceinline void merge (const BinInfoT& other, size_t numBins)
+ {
+
+ for (size_t i=0; i<numBins; i++)
+ {
+ counts(i) += other.counts(i);
+ bounds(i,0).extend(other.bounds(i,0));
+ bounds(i,1).extend(other.bounds(i,1));
+ bounds(i,2).extend(other.bounds(i,2));
+ }
+ }
+
+ /*! reduces binning information */
+ static __forceinline const BinInfoT reduce (const BinInfoT& a, const BinInfoT& b, const size_t numBins = BINS)
+ {
+ BinInfoT c;
+ for (size_t i=0; i<numBins; i++)
+ {
+ c.counts(i) = a.counts(i)+b.counts(i);
+ c.bounds(i,0) = embree::merge(a.bounds(i,0),b.bounds(i,0));
+ c.bounds(i,1) = embree::merge(a.bounds(i,1),b.bounds(i,1));
+ c.bounds(i,2) = embree::merge(a.bounds(i,2),b.bounds(i,2));
+ }
+ return c;
+ }
+
+ /*! finds the best split by scanning binning information */
+ __forceinline Split best(const BinMapping<BINS>& mapping, const size_t blocks_shift) const
+ {
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ vfloat4 rAreas[BINS];
+ vuint4 rCounts[BINS];
+ vuint4 count = 0; BBox bx = empty; BBox by = empty; BBox bz = empty;
+ for (size_t i=mapping.size()-1; i>0; i--)
+ {
+ count += counts(i);
+ rCounts[i] = count;
+ bx.extend(bounds(i,0)); rAreas[i][0] = expectedApproxHalfArea(bx);
+ by.extend(bounds(i,1)); rAreas[i][1] = expectedApproxHalfArea(by);
+ bz.extend(bounds(i,2)); rAreas[i][2] = expectedApproxHalfArea(bz);
+ rAreas[i][3] = 0.0f;
+ }
+ /* sweep from left to right and compute SAH */
+ vuint4 blocks_add = (1 << blocks_shift)-1;
+ vuint4 ii = 1; vfloat4 vbestSAH = pos_inf; vuint4 vbestPos = 0;
+ count = 0; bx = empty; by = empty; bz = empty;
+ for (size_t i=1; i<mapping.size(); i++, ii+=1)
+ {
+ count += counts(i-1);
+ bx.extend(bounds(i-1,0)); float Ax = expectedApproxHalfArea(bx);
+ by.extend(bounds(i-1,1)); float Ay = expectedApproxHalfArea(by);
+ bz.extend(bounds(i-1,2)); float Az = expectedApproxHalfArea(bz);
+ const vfloat4 lArea = vfloat4(Ax,Ay,Az,Az);
+ const vfloat4 rArea = rAreas[i];
+ const vuint4 lCount = (count +blocks_add) >> (unsigned int)(blocks_shift); // if blocks_shift >=1 then lCount < 4B and could be represented with an vint4, which would allow for faster vfloat4 conversions.
+ const vuint4 rCount = (rCounts[i]+blocks_add) >> (unsigned int)(blocks_shift);
+ const vfloat4 sah = madd(lArea,vfloat4(lCount),rArea*vfloat4(rCount));
+ //const vfloat4 sah = madd(lArea,vfloat4(vint4(lCount)),rArea*vfloat4(vint4(rCount)));
+
+ vbestPos = select(sah < vbestSAH,ii ,vbestPos);
+ vbestSAH = select(sah < vbestSAH,sah,vbestSAH);
+ }
+
+ /* find best dimension */
+ float bestSAH = inf;
+ int bestDim = -1;
+ int bestPos = 0;
+ for (int dim=0; dim<3; dim++)
+ {
+ /* ignore zero sized dimensions */
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ /* test if this is a better dimension */
+ if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) {
+ bestDim = dim;
+ bestPos = vbestPos[dim];
+ bestSAH = vbestSAH[dim];
+ }
+ }
+ return Split(bestSAH,bestDim,bestPos,mapping);
+ }
+
+ /*! calculates extended split information */
+ __forceinline void getSplitInfo(const BinMapping<BINS>& mapping, const Split& split, SplitInfoT<BBox>& info) const
+ {
+ if (split.dim == -1) {
+ new (&info) SplitInfoT<BBox>(0,empty,0,empty);
+ return;
+ }
+
+ size_t leftCount = 0;
+ BBox leftBounds = empty;
+ for (size_t i=0; i<(size_t)split.pos; i++) {
+ leftCount += counts(i,split.dim);
+ leftBounds.extend(bounds(i,split.dim));
+ }
+ size_t rightCount = 0;
+ BBox rightBounds = empty;
+ for (size_t i=split.pos; i<mapping.size(); i++) {
+ rightCount += counts(i,split.dim);
+ rightBounds.extend(bounds(i,split.dim));
+ }
+ new (&info) SplitInfoT<BBox>(leftCount,leftBounds,rightCount,rightBounds);
+ }
+
+ /*! gets the number of primitives left of the split */
+ __forceinline size_t getLeftCount(const BinMapping<BINS>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t leftCount = 0;
+ for (size_t i = 0; i < (size_t)split.pos; i++) {
+ leftCount += counts(i, split.dim);
+ }
+ return leftCount;
+ }
+
+ /*! gets the number of primitives right of the split */
+ __forceinline size_t getRightCount(const BinMapping<BINS>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t rightCount = 0;
+ for (size_t i = (size_t)split.pos; i<mapping.size(); i++) {
+ rightCount += counts(i, split.dim);
+ }
+ return rightCount;
+ }
+
+ private:
+ BBox _bounds[BINS][3]; //!< geometry bounds for each bin in each dimension
+ vuint4 _counts[BINS]; //!< counts number of primitives that map into the bins
+ };
+
+#if defined(__AVX512ER__) // KNL
+
+ /*! mapping into bins */
+ template<>
+ struct BinMapping<16>
+ {
+ public:
+ __forceinline BinMapping() {}
+
+ /*! calculates the mapping */
+ template<typename PrimInfo>
+ __forceinline BinMapping(const PrimInfo& pinfo)
+ {
+ num = 16;
+ const vfloat4 eps = 1E-34f;
+ const vfloat4 diag = max(eps,(vfloat4) pinfo.centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) pinfo.centBounds.lower;
+ scale16 = scale;
+ ofs16 = ofs;
+ }
+
+ /*! returns number of bins */
+ __forceinline size_t size() const { return num; }
+
+ __forceinline vint16 bin16(const Vec3fa& p) const {
+ return vint16(vint4(floori((vfloat4(p)-ofs)*scale)));
+ }
+
+ __forceinline vint16 bin16(const vfloat16& p) const {
+ return floori((p-ofs16)*scale16);
+ }
+
+ __forceinline int bin_unsafe(const PrimRef& ref,
+ const vint16& vSplitPos,
+ const vbool16& splitDimMask) const // FIXME: rename to isLeft
+ {
+ const vfloat16 lower(*(vfloat4*)&ref.lower);
+ const vfloat16 upper(*(vfloat4*)&ref.upper);
+ const vfloat16 p = lower + upper;
+ const vint16 i = floori((p-ofs16)*scale16);
+ return lt(splitDimMask,i,vSplitPos);
+ }
+
+ /*! returns true if the mapping is invalid in some dimension */
+ __forceinline bool invalid(const size_t dim) const {
+ return scale[dim] == 0.0f;
+ }
+
+ public:
+ size_t num;
+ vfloat4 ofs,scale; //!< linear function that maps to bin ID
+ vfloat16 ofs16,scale16; //!< linear function that maps to bin ID
+ };
+
+ /* 16 bins in-register binner */
+ template<typename PrimRef>
+ struct __aligned(64) BinInfoT<16,PrimRef,BBox3fa>
+ {
+ typedef BinSplit<16> Split;
+ typedef vbool16 vbool;
+ typedef vint16 vint;
+ typedef vfloat16 vfloat;
+
+ __forceinline BinInfoT() {
+ }
+
+ __forceinline BinInfoT(EmptyTy) {
+ clear();
+ }
+
+ /*! clears the bin info */
+ __forceinline void clear()
+ {
+ lower[0] = lower[1] = lower[2] = pos_inf;
+ upper[0] = upper[1] = upper[2] = neg_inf;
+ count[0] = count[1] = count[2] = 0;
+ }
+
+
+ static __forceinline vfloat16 prefix_area_rl(const vfloat16 min_x,
+ const vfloat16 min_y,
+ const vfloat16 min_z,
+ const vfloat16 max_x,
+ const vfloat16 max_y,
+ const vfloat16 max_z)
+ {
+ const vfloat16 r_min_x = reverse_prefix_min(min_x);
+ const vfloat16 r_min_y = reverse_prefix_min(min_y);
+ const vfloat16 r_min_z = reverse_prefix_min(min_z);
+ const vfloat16 r_max_x = reverse_prefix_max(max_x);
+ const vfloat16 r_max_y = reverse_prefix_max(max_y);
+ const vfloat16 r_max_z = reverse_prefix_max(max_z);
+ const vfloat16 dx = r_max_x - r_min_x;
+ const vfloat16 dy = r_max_y - r_min_y;
+ const vfloat16 dz = r_max_z - r_min_z;
+ const vfloat16 area_rl = madd(dx,dy,madd(dx,dz,dy*dz));
+ return area_rl;
+ }
+
+ static __forceinline vfloat16 prefix_area_lr(const vfloat16 min_x,
+ const vfloat16 min_y,
+ const vfloat16 min_z,
+ const vfloat16 max_x,
+ const vfloat16 max_y,
+ const vfloat16 max_z)
+ {
+ const vfloat16 r_min_x = prefix_min(min_x);
+ const vfloat16 r_min_y = prefix_min(min_y);
+ const vfloat16 r_min_z = prefix_min(min_z);
+ const vfloat16 r_max_x = prefix_max(max_x);
+ const vfloat16 r_max_y = prefix_max(max_y);
+ const vfloat16 r_max_z = prefix_max(max_z);
+ const vfloat16 dx = r_max_x - r_min_x;
+ const vfloat16 dy = r_max_y - r_min_y;
+ const vfloat16 dz = r_max_z - r_min_z;
+ const vfloat16 area_lr = madd(dx,dy,madd(dx,dz,dy*dz));
+ return area_lr;
+ }
+
+
+ /*! bins an array of primitives */
+ __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<16>& mapping)
+ {
+ if (unlikely(N == 0)) return;
+
+ const vfloat16 init_min(pos_inf);
+ const vfloat16 init_max(neg_inf);
+
+ vfloat16 min_x0,min_x1,min_x2;
+ vfloat16 min_y0,min_y1,min_y2;
+ vfloat16 min_z0,min_z1,min_z2;
+ vfloat16 max_x0,max_x1,max_x2;
+ vfloat16 max_y0,max_y1,max_y2;
+ vfloat16 max_z0,max_z1,max_z2;
+ vuint16 count0,count1,count2;
+
+ min_x0 = init_min;
+ min_x1 = init_min;
+ min_x2 = init_min;
+ min_y0 = init_min;
+ min_y1 = init_min;
+ min_y2 = init_min;
+ min_z0 = init_min;
+ min_z1 = init_min;
+ min_z2 = init_min;
+
+ max_x0 = init_max;
+ max_x1 = init_max;
+ max_x2 = init_max;
+ max_y0 = init_max;
+ max_y1 = init_max;
+ max_y2 = init_max;
+ max_z0 = init_max;
+ max_z1 = init_max;
+ max_z2 = init_max;
+
+ count0 = zero;
+ count1 = zero;
+ count2 = zero;
+
+ const vint16 step16(step);
+ size_t i;
+ for (i=0; i<N-1; i+=2)
+ {
+ /*! map even and odd primitive to bin */
+ const BBox3fa primA = prims[i+0].bounds();
+ const vfloat16 centerA = vfloat16((vfloat4)primA.lower) + vfloat16((vfloat4)primA.upper);
+ const vint16 binA = mapping.bin16(centerA);
+
+ const BBox3fa primB = prims[i+1].bounds();
+ const vfloat16 centerB = vfloat16((vfloat4)primB.lower) + vfloat16((vfloat4)primB.upper);
+ const vint16 binB = mapping.bin16(centerB);
+
+ /* A */
+ {
+ const vfloat16 b_min_x = prims[i+0].lower.x;
+ const vfloat16 b_min_y = prims[i+0].lower.y;
+ const vfloat16 b_min_z = prims[i+0].lower.z;
+ const vfloat16 b_max_x = prims[i+0].upper.x;
+ const vfloat16 b_max_y = prims[i+0].upper.y;
+ const vfloat16 b_max_z = prims[i+0].upper.z;
+
+ const vint16 bin0 = shuffle<0>(binA);
+ const vint16 bin1 = shuffle<1>(binA);
+ const vint16 bin2 = shuffle<2>(binA);
+
+ const vbool16 m_update_x = step16 == bin0;
+ const vbool16 m_update_y = step16 == bin1;
+ const vbool16 m_update_z = step16 == bin2;
+
+ assert(popcnt((size_t)m_update_x) == 1);
+ assert(popcnt((size_t)m_update_y) == 1);
+ assert(popcnt((size_t)m_update_z) == 1);
+
+ min_x0 = mask_min(m_update_x,min_x0,min_x0,b_min_x);
+ min_y0 = mask_min(m_update_x,min_y0,min_y0,b_min_y);
+ min_z0 = mask_min(m_update_x,min_z0,min_z0,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x0 = mask_max(m_update_x,max_x0,max_x0,b_max_x);
+ max_y0 = mask_max(m_update_x,max_y0,max_y0,b_max_y);
+ max_z0 = mask_max(m_update_x,max_z0,max_z0,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x1 = mask_min(m_update_y,min_x1,min_x1,b_min_x);
+ min_y1 = mask_min(m_update_y,min_y1,min_y1,b_min_y);
+ min_z1 = mask_min(m_update_y,min_z1,min_z1,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x1 = mask_max(m_update_y,max_x1,max_x1,b_max_x);
+ max_y1 = mask_max(m_update_y,max_y1,max_y1,b_max_y);
+ max_z1 = mask_max(m_update_y,max_z1,max_z1,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x2 = mask_min(m_update_z,min_x2,min_x2,b_min_x);
+ min_y2 = mask_min(m_update_z,min_y2,min_y2,b_min_y);
+ min_z2 = mask_min(m_update_z,min_z2,min_z2,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x2 = mask_max(m_update_z,max_x2,max_x2,b_max_x);
+ max_y2 = mask_max(m_update_z,max_y2,max_y2,b_max_y);
+ max_z2 = mask_max(m_update_z,max_z2,max_z2,b_max_z);
+ // ------------------------------------------------------------------------
+ count0 = mask_add(m_update_x,count0,count0,vuint16(1));
+ count1 = mask_add(m_update_y,count1,count1,vuint16(1));
+ count2 = mask_add(m_update_z,count2,count2,vuint16(1));
+ }
+
+
+ /* B */
+ {
+ const vfloat16 b_min_x = prims[i+1].lower.x;
+ const vfloat16 b_min_y = prims[i+1].lower.y;
+ const vfloat16 b_min_z = prims[i+1].lower.z;
+ const vfloat16 b_max_x = prims[i+1].upper.x;
+ const vfloat16 b_max_y = prims[i+1].upper.y;
+ const vfloat16 b_max_z = prims[i+1].upper.z;
+
+ const vint16 bin0 = shuffle<0>(binB);
+ const vint16 bin1 = shuffle<1>(binB);
+ const vint16 bin2 = shuffle<2>(binB);
+
+ const vbool16 m_update_x = step16 == bin0;
+ const vbool16 m_update_y = step16 == bin1;
+ const vbool16 m_update_z = step16 == bin2;
+
+ assert(popcnt((size_t)m_update_x) == 1);
+ assert(popcnt((size_t)m_update_y) == 1);
+ assert(popcnt((size_t)m_update_z) == 1);
+
+ min_x0 = mask_min(m_update_x,min_x0,min_x0,b_min_x);
+ min_y0 = mask_min(m_update_x,min_y0,min_y0,b_min_y);
+ min_z0 = mask_min(m_update_x,min_z0,min_z0,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x0 = mask_max(m_update_x,max_x0,max_x0,b_max_x);
+ max_y0 = mask_max(m_update_x,max_y0,max_y0,b_max_y);
+ max_z0 = mask_max(m_update_x,max_z0,max_z0,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x1 = mask_min(m_update_y,min_x1,min_x1,b_min_x);
+ min_y1 = mask_min(m_update_y,min_y1,min_y1,b_min_y);
+ min_z1 = mask_min(m_update_y,min_z1,min_z1,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x1 = mask_max(m_update_y,max_x1,max_x1,b_max_x);
+ max_y1 = mask_max(m_update_y,max_y1,max_y1,b_max_y);
+ max_z1 = mask_max(m_update_y,max_z1,max_z1,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x2 = mask_min(m_update_z,min_x2,min_x2,b_min_x);
+ min_y2 = mask_min(m_update_z,min_y2,min_y2,b_min_y);
+ min_z2 = mask_min(m_update_z,min_z2,min_z2,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x2 = mask_max(m_update_z,max_x2,max_x2,b_max_x);
+ max_y2 = mask_max(m_update_z,max_y2,max_y2,b_max_y);
+ max_z2 = mask_max(m_update_z,max_z2,max_z2,b_max_z);
+ // ------------------------------------------------------------------------
+ count0 = mask_add(m_update_x,count0,count0,vuint16(1));
+ count1 = mask_add(m_update_y,count1,count1,vuint16(1));
+ count2 = mask_add(m_update_z,count2,count2,vuint16(1));
+ }
+
+ }
+
+ if (i < N)
+ {
+ const BBox3fa prim0 = prims[i].bounds();
+ const vfloat16 center0 = vfloat16((vfloat4)prim0.lower) + vfloat16((vfloat4)prim0.upper);
+ const vint16 bin = mapping.bin16(center0);
+
+ const vfloat16 b_min_x = prims[i].lower.x;
+ const vfloat16 b_min_y = prims[i].lower.y;
+ const vfloat16 b_min_z = prims[i].lower.z;
+ const vfloat16 b_max_x = prims[i].upper.x;
+ const vfloat16 b_max_y = prims[i].upper.y;
+ const vfloat16 b_max_z = prims[i].upper.z;
+
+ const vint16 bin0 = shuffle<0>(bin);
+ const vint16 bin1 = shuffle<1>(bin);
+ const vint16 bin2 = shuffle<2>(bin);
+
+ const vbool16 m_update_x = step16 == bin0;
+ const vbool16 m_update_y = step16 == bin1;
+ const vbool16 m_update_z = step16 == bin2;
+
+ assert(popcnt((size_t)m_update_x) == 1);
+ assert(popcnt((size_t)m_update_y) == 1);
+ assert(popcnt((size_t)m_update_z) == 1);
+
+ min_x0 = mask_min(m_update_x,min_x0,min_x0,b_min_x);
+ min_y0 = mask_min(m_update_x,min_y0,min_y0,b_min_y);
+ min_z0 = mask_min(m_update_x,min_z0,min_z0,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x0 = mask_max(m_update_x,max_x0,max_x0,b_max_x);
+ max_y0 = mask_max(m_update_x,max_y0,max_y0,b_max_y);
+ max_z0 = mask_max(m_update_x,max_z0,max_z0,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x1 = mask_min(m_update_y,min_x1,min_x1,b_min_x);
+ min_y1 = mask_min(m_update_y,min_y1,min_y1,b_min_y);
+ min_z1 = mask_min(m_update_y,min_z1,min_z1,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x1 = mask_max(m_update_y,max_x1,max_x1,b_max_x);
+ max_y1 = mask_max(m_update_y,max_y1,max_y1,b_max_y);
+ max_z1 = mask_max(m_update_y,max_z1,max_z1,b_max_z);
+ // ------------------------------------------------------------------------
+ min_x2 = mask_min(m_update_z,min_x2,min_x2,b_min_x);
+ min_y2 = mask_min(m_update_z,min_y2,min_y2,b_min_y);
+ min_z2 = mask_min(m_update_z,min_z2,min_z2,b_min_z);
+ // ------------------------------------------------------------------------
+ max_x2 = mask_max(m_update_z,max_x2,max_x2,b_max_x);
+ max_y2 = mask_max(m_update_z,max_y2,max_y2,b_max_y);
+ max_z2 = mask_max(m_update_z,max_z2,max_z2,b_max_z);
+ // ------------------------------------------------------------------------
+ count0 = mask_add(m_update_x,count0,count0,vuint16(1));
+ count1 = mask_add(m_update_y,count1,count1,vuint16(1));
+ count2 = mask_add(m_update_z,count2,count2,vuint16(1));
+ }
+
+ lower[0] = Vec3vf16( min_x0, min_y0, min_z0 );
+ lower[1] = Vec3vf16( min_x1, min_y1, min_z1 );
+ lower[2] = Vec3vf16( min_x2, min_y2, min_z2 );
+
+ upper[0] = Vec3vf16( max_x0, max_y0, max_z0 );
+ upper[1] = Vec3vf16( max_x1, max_y1, max_z1 );
+ upper[2] = Vec3vf16( max_x2, max_y2, max_z2 );
+
+ count[0] = count0;
+ count[1] = count1;
+ count[2] = count2;
+ }
+
+ __forceinline void bin(const PrimRef* prims, size_t begin, size_t end, const BinMapping<16>& mapping) {
+ bin(prims+begin,end-begin,mapping);
+ }
+
+ /*! merges in other binning information */
+ __forceinline void merge (const BinInfoT& other, size_t numBins)
+ {
+ for (size_t i=0; i<3; i++)
+ {
+ lower[i] = min(lower[i],other.lower[i]);
+ upper[i] = max(upper[i],other.upper[i]);
+ count[i] += other.count[i];
+ }
+ }
+
+ /*! reducesr binning information */
+ static __forceinline const BinInfoT reduce (const BinInfoT& a, const BinInfoT& b)
+ {
+ BinInfoT c;
+ for (size_t i=0; i<3; i++)
+ {
+ c.counts[i] = a.counts[i] + b.counts[i];
+ c.lower[i] = min(a.lower[i],b.lower[i]);
+ c.upper[i] = max(a.upper[i],b.upper[i]);
+ }
+ return c;
+ }
+
+ /*! finds the best split by scanning binning information */
+ __forceinline Split best(const BinMapping<16>& mapping, const size_t blocks_shift) const
+ {
+ /* find best dimension */
+ float bestSAH = inf;
+ int bestDim = -1;
+ int bestPos = 0;
+ const vuint16 blocks_add = (1 << blocks_shift)-1;
+ const vfloat16 inf(pos_inf);
+ for (size_t dim=0; dim<3; dim++)
+ {
+ /* ignore zero sized dimensions */
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ const vfloat16 rArea16 = prefix_area_rl(lower[dim].x,lower[dim].y,lower[dim].z, upper[dim].x,upper[dim].y,upper[dim].z);
+ const vfloat16 lArea16 = prefix_area_lr(lower[dim].x,lower[dim].y,lower[dim].z, upper[dim].x,upper[dim].y,upper[dim].z);
+ const vuint16 lCount16 = prefix_sum(count[dim]);
+ const vuint16 rCount16 = reverse_prefix_sum(count[dim]);
+
+ /* compute best split in this dimension */
+ const vfloat16 leftArea = lArea16;
+ const vfloat16 rightArea = align_shift_right<1>(zero,rArea16);
+ const vuint16 lC = lCount16;
+ const vuint16 rC = align_shift_right<1>(zero,rCount16);
+ const vuint16 leftCount = ( lC + blocks_add) >> blocks_shift;
+ const vuint16 rightCount = ( rC + blocks_add) >> blocks_shift;
+ const vbool16 valid = (leftArea < inf) & (rightArea < inf) & vbool16(0x7fff); // handles inf entries
+ const vfloat16 sah = select(valid,madd(leftArea,vfloat16(leftCount),rightArea*vfloat16(rightCount)),vfloat16(pos_inf));
+ /* test if this is a better dimension */
+ if (any(sah < vfloat16(bestSAH)))
+ {
+ const size_t index = select_min(sah);
+ assert(index < 15);
+ assert(sah[index] < bestSAH);
+ bestDim = dim;
+ bestPos = index+1;
+ bestSAH = sah[index];
+ }
+ }
+
+ return Split(bestSAH,bestDim,bestPos,mapping);
+
+ }
+
+ /*! calculates extended split information */
+ __forceinline void getSplitInfo(const BinMapping<16>& mapping, const Split& split, SplitInfo& info) const
+ {
+ if (split.dim == -1) {
+ new (&info) SplitInfo(0,empty,0,empty);
+ return;
+ }
+ // FIXME: horizontal reduction!
+
+ size_t leftCount = 0;
+ BBox3fa leftBounds = empty;
+ for (size_t i=0; i<(size_t)split.pos; i++) {
+ leftCount += count[split.dim][i];
+ Vec3fa bounds_lower(lower[split.dim].x[i],lower[split.dim].y[i],lower[split.dim].z[i]);
+ Vec3fa bounds_upper(upper[split.dim].x[i],upper[split.dim].y[i],upper[split.dim].z[i]);
+ leftBounds.extend(BBox3fa(bounds_lower,bounds_upper));
+ }
+ size_t rightCount = 0;
+ BBox3fa rightBounds = empty;
+ for (size_t i=split.pos; i<mapping.size(); i++) {
+ rightCount += count[split.dim][i];
+ Vec3fa bounds_lower(lower[split.dim].x[i],lower[split.dim].y[i],lower[split.dim].z[i]);
+ Vec3fa bounds_upper(upper[split.dim].x[i],upper[split.dim].y[i],upper[split.dim].z[i]);
+ rightBounds.extend(BBox3fa(bounds_lower,bounds_upper));
+ }
+ new (&info) SplitInfo(leftCount,leftBounds,rightCount,rightBounds);
+ }
+
+ /*! gets the number of primitives left of the split */
+ __forceinline size_t getLeftCount(const BinMapping<16>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t leftCount = 0;
+ for (size_t i = 0; i < (size_t)split.pos; i++) {
+ leftCount += count[split.dim][i];
+ }
+ return leftCount;
+ }
+
+ /*! gets the number of primitives right of the split */
+ __forceinline size_t getRightCount(const BinMapping<16>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t rightCount = 0;
+ for (size_t i = (size_t)split.pos; i<mapping.size(); i++) {
+ rightCount += count[split.dim][i];
+ }
+ return rightCount;
+ }
+
+ private:
+ Vec3vf16 lower[3];
+ Vec3vf16 upper[3];
+ vuint16 count[3];
+ };
+#endif
+ }
+
+ template<typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, const BinMapping& mapping)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ binner.bin(prims,begin,end,mapping);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<typename BinBoundsAndCenter, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, const BinMapping& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ binner.bin(prims,begin,end,mapping,binBoundsAndCenter);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping, binBoundsAndCenter); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<bool parallel, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_serial_or_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, const BinMapping& mapping)
+ {
+ if (!parallel) {
+ binner.bin(prims,begin,end,mapping);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<bool parallel, typename BinBoundsAndCenter, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_serial_or_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, const BinMapping& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (!parallel) {
+ binner.bin(prims,begin,end,mapping,binBoundsAndCenter);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping, binBoundsAndCenter); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_aligned.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_aligned.h
new file mode 100644
index 0000000000..a4c272f015
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_aligned.h
@@ -0,0 +1,205 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct PrimInfoRange : public CentGeomBBox3fa, public range<size_t>
+ {
+ __forceinline PrimInfoRange () {
+ }
+
+ __forceinline PrimInfoRange(const PrimInfo& pinfo)
+ : CentGeomBBox3fa(pinfo), range<size_t>(pinfo.begin,pinfo.end) {}
+
+ __forceinline PrimInfoRange(EmptyTy)
+ : CentGeomBBox3fa(EmptyTy()), range<size_t>(0,0) {}
+
+ __forceinline PrimInfoRange (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeomBBox3fa(centGeomBounds), range<size_t>(begin,end) {}
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRef, size_t BINS>
+ struct HeuristicArrayBinningSAH
+ {
+ typedef BinSplit<BINS> Split;
+ typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
+ typedef range<size_t> Set;
+
+#if defined(__AVX512ER__) // KNL
+ static const size_t PARALLEL_THRESHOLD = 4*768;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 768;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 768;
+#else
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+#endif
+ __forceinline HeuristicArrayBinningSAH ()
+ : prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArrayBinningSAH (PrimRef* prims)
+ : prims(prims) {}
+
+ /*! finds the best split */
+ __noinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize)
+ {
+ if (likely(pinfo.size() < PARALLEL_THRESHOLD))
+ return find_template<false>(pinfo,logBlockSize);
+ else
+ return find_template<true>(pinfo,logBlockSize);
+ }
+
+ template<bool parallel>
+ __forceinline const Split find_template(const PrimInfoRange& pinfo, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<BINS> mapping(pinfo);
+ bin_serial_or_parallel<parallel>(binner,prims,pinfo.begin(),pinfo.end(),PARALLEL_FIND_BLOCK_SIZE,mapping);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ if (likely(pinfo.size() < PARALLEL_THRESHOLD))
+ split_template<false>(split,pinfo,linfo,rinfo);
+ else
+ split_template<true>(split,pinfo,linfo,rinfo);
+ }
+
+ template<bool parallel>
+ __forceinline void split_template(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename Binner::vint vSplitPos(splitPos);
+ const typename Binner::vbool vSplitMask(splitDimMask);
+ auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ size_t center = 0;
+ if (!parallel)
+ center = serial_partitioning(prims,begin,end,local_left,local_right,isLeft,
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
+ else
+ center = parallel_partitioning(
+ prims,begin,end,EmptyTy(),local_left,local_right,isLeft,
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
+ [] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const PrimInfoRange& pinfo)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[pinfo.begin()],&prims[pinfo.end()]);
+ }
+
+ void splitFallback(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ const size_t begin = pinfo.begin();
+ const size_t end = pinfo.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend_center2(prims[i]);
+ new (&linfo) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend_center2(prims[i]);
+ new (&rinfo) PrimInfoRange(center,end,right);
+ }
+
+ void splitByGeometry(const range<size_t>& range, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ assert(range.size() > 1);
+ CentGeomBBox3fa left(empty);
+ CentGeomBBox3fa right(empty);
+ unsigned int geomID = prims[range.begin()].geomID();
+ size_t center = serial_partitioning(prims,range.begin(),range.end(),left,right,
+ [&] ( const PrimRef& prim ) { return prim.geomID() == geomID; },
+ [ ] ( CentGeomBBox3fa& a, const PrimRef& ref ) { a.extend_center2(ref); });
+
+ new (&linfo) PrimInfoRange(range.begin(),center,left);
+ new (&rinfo) PrimInfoRange(center,range.end(),right);
+ }
+
+ private:
+ PrimRef* const prims;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, size_t BINS>
+ struct HeuristicArrayBinningMB
+ {
+ typedef BinSplit<BINS> Split;
+ typedef typename PrimRefMB::BBox BBox;
+ typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<BINS> mapping(set.size(),set.centBounds);
+ bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping);
+ Split osplit = binner.best(mapping,logBlockSize);
+ osplit.sah *= set.time_range.size();
+ if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return osplit;
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB left = empty;
+ PrimInfoMB right = empty;
+ const vint4 vSplitPos(split.pos);
+ const vbool4 vSplitMask(1 << split.dim);
+ auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref) < vSplitPos) & vSplitMask); };
+ auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
+ auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
+ size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
+ new (&lset) SetMB(left, set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_unaligned.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_unaligned.h
new file mode 100644
index 0000000000..1370244586
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_binning_array_unaligned.h
@@ -0,0 +1,302 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename PrimRef, size_t BINS>
+ struct UnalignedHeuristicArrayBinningSAH
+ {
+ typedef BinSplit<BINS> Split;
+ typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
+ typedef range<size_t> Set;
+
+ __forceinline UnalignedHeuristicArrayBinningSAH () // FIXME: required?
+ : scene(nullptr), prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline UnalignedHeuristicArrayBinningSAH (Scene* scene, PrimRef* prims)
+ : scene(scene), prims(prims) {}
+
+ const LinearSpace3fa computeAlignedSpace(const range<size_t>& set)
+ {
+ Vec3fa axis(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /*! find curve with minimum ID that defines valid direction */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const unsigned int geomID = prims[i].geomID();
+ const unsigned int primID = prims[i].primID();
+ const uint64_t geomprimID = prims[i].ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+ const Vec3fa axis1 = scene->get(geomID)->computeDirection(primID);
+ if (sqr_length(axis1) > 1E-18f) {
+ axis = normalize(axis1);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+ return frame(axis).transposed();
+ }
+
+ const PrimInfo computePrimInfo(const range<size_t>& set, const LinearSpace3fa& space)
+ {
+ auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
+ {
+ CentGeomBBox3fa bounds(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ Geometry* mesh = scene->get(prims[i].geomID());
+ bounds.extend(mesh->vbounds(space,prims[i].primID()));
+ }
+ return bounds;
+ };
+
+ const CentGeomBBox3fa bounds = parallel_reduce(set.begin(), set.end(), size_t(1024), size_t(4096),
+ CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
+
+ return PrimInfo(set.begin(),set.end(),bounds);
+ }
+
+ struct BinBoundsAndCenter
+ {
+ __forceinline BinBoundsAndCenter(Scene* scene, const LinearSpace3fa& space)
+ : scene(scene), space(space) {}
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter(const PrimRef& ref) const
+ {
+ Geometry* mesh = (Geometry*) scene->get(ref.geomID());
+ BBox3fa bounds = mesh->vbounds(space,ref.primID());
+ return embree::center2(bounds);
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(const PrimRef& ref, BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ Geometry* mesh = (Geometry*) scene->get(ref.geomID());
+ BBox3fa bounds = mesh->vbounds(space,ref.primID());
+ bounds_o = bounds;
+ center_o = embree::center2(bounds);
+ }
+
+ private:
+ Scene* scene;
+ const LinearSpace3fa space;
+ };
+
+ /*! finds the best split */
+ __forceinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ if (likely(pinfo.size() < 10000))
+ return find_template<false>(pinfo,logBlockSize,space);
+ else
+ return find_template<true>(pinfo,logBlockSize,space);
+ }
+
+ /*! finds the best split */
+ template<bool parallel>
+ const Split find_template(const PrimInfoRange& set, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ Binner binner(empty);
+ const BinMapping<BINS> mapping(set);
+ BinBoundsAndCenter binBoundsAndCenter(scene,space);
+ bin_serial_or_parallel<parallel>(binner,prims,set.begin(),set.end(),size_t(4096),mapping,binBoundsAndCenter);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (likely(set.size() < 10000))
+ split_template<false>(split,space,set,lset,rset);
+ else
+ split_template<true>(split,space,set,lset,rset);
+ }
+
+ /*! array partitioning */
+ template<bool parallel>
+ __forceinline void split_template(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+ const int splitPos = split.pos;
+ const int splitDim = split.dim;
+ BinBoundsAndCenter binBoundsAndCenter(scene,space);
+
+ size_t center = 0;
+ if (likely(set.size() < 10000))
+ center = serial_partitioning(prims,begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
+ else
+ center = parallel_partitioning(prims,begin,end,EmptyTy(),local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
+ [] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
+ 128);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const range<size_t>& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[set.begin()],&prims[set.end()]);
+ }
+
+ void splitFallback(const range<size_t>& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend_center2(prims[i]);
+ new (&lset) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend_center2(prims[i]);
+ new (&rset) PrimInfoRange(center,end,right);
+ }
+
+ private:
+ Scene* const scene;
+ PrimRef* const prims;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, size_t BINS>
+ struct UnalignedHeuristicArrayBinningMB
+ {
+ typedef BinSplit<BINS> Split;
+ typedef typename PrimRefMB::BBox BBox;
+ typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
+
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ UnalignedHeuristicArrayBinningMB(Scene* scene)
+ : scene(scene) {}
+
+ const LinearSpace3fa computeAlignedSpaceMB(Scene* scene, const SetMB& set)
+ {
+ Vec3fa axis0(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /*! find curve with minimum ID that defines valid direction */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const PrimRefMB& prim = (*set.prims)[i];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const uint64_t geomprimID = prim.ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+
+ const Geometry* mesh = scene->get(geomID);
+ const range<int> tbounds = mesh->timeSegmentRange(set.time_range);
+ if (tbounds.size() == 0) continue;
+
+ const size_t t = (tbounds.begin()+tbounds.end())/2;
+ const Vec3fa axis1 = mesh->computeDirection(primID,t);
+ if (sqr_length(axis1) > 1E-18f) {
+ axis0 = normalize(axis1);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ return frame(axis0).transposed();
+ }
+
+ struct BinBoundsAndCenter
+ {
+ __forceinline BinBoundsAndCenter(Scene* scene, BBox1f time_range, const LinearSpace3fa& space)
+ : scene(scene), time_range(time_range), space(space) {}
+
+ /*! returns center for binning */
+ template<typename PrimRef>
+ __forceinline Vec3fa binCenter(const PrimRef& ref) const
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ return center2(lbounds.interpolate(0.5f));
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __noinline void binBoundsAndCenter (const PrimRefMB& ref, BBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ bounds_o = lbounds.interpolate(0.5f);
+ center_o = center2(bounds_o);
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __noinline void binBoundsAndCenter (const PrimRefMB& ref, LBBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ bounds_o = lbounds;
+ center_o = center2(lbounds.interpolate(0.5f));
+ }
+
+ private:
+ Scene* scene;
+ BBox1f time_range;
+ const LinearSpace3fa space;
+ };
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
+ ObjectBinner binner(empty);
+ const BinMapping<BINS> mapping(set.size(),set.centBounds);
+ bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping,binBoundsAndCenter);
+ Split osplit = binner.best(mapping,logBlockSize);
+ osplit.sah *= set.time_range.size();
+ if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return osplit;
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const LinearSpace3fa& space, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB left = empty;
+ PrimInfoMB right = empty;
+ const vint4 vSplitPos(split.pos);
+ const vbool4 vSplitMask(1 << split.dim);
+ auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref,binBoundsAndCenter) < vSplitPos) & vSplitMask); };
+ auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
+ auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
+ size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
+ new (&lset) SetMB(left,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ private:
+ Scene* scene;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_openmerge_array.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_openmerge_array.h
new file mode 100644
index 0000000000..21f18c0208
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_openmerge_array.h
@@ -0,0 +1,443 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+// TODO:
+// - adjust parallel build thresholds
+// - openNodesBasedOnExtend should consider max extended size
+
+#pragma once
+
+#include "heuristic_binning.h"
+#include "heuristic_spatial.h"
+
+/* stop opening of all bref.geomIDs are the same */
+#define EQUAL_GEOMID_STOP_CRITERIA 1
+
+/* 10% spatial extend threshold */
+#define MAX_EXTEND_THRESHOLD 0.1f
+
+/* maximum is 8 children */
+#define MAX_OPENED_CHILD_NODES 8
+
+/* open until all build refs are below threshold size in one step */
+#define USE_LOOP_OPENING 0
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename NodeOpenerFunc, typename PrimRef, size_t OBJECT_BINS>
+ struct HeuristicArrayOpenMergeSAH
+ {
+ typedef BinSplit<OBJECT_BINS> Split;
+ typedef BinInfoT<OBJECT_BINS,PrimRef,BBox3fa> Binner;
+
+ static const size_t PARALLEL_THRESHOLD = 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 512;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ static const size_t MOVE_STEP_SIZE = 64;
+ static const size_t CREATE_SPLITS_STEP_SIZE = 128;
+
+ __forceinline HeuristicArrayOpenMergeSAH ()
+ : prims0(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArrayOpenMergeSAH (const NodeOpenerFunc& nodeOpenerFunc, PrimRef* prims0, size_t max_open_size)
+ : prims0(prims0), nodeOpenerFunc(nodeOpenerFunc), max_open_size(max_open_size)
+ {
+ assert(max_open_size <= MAX_OPENED_CHILD_NODES);
+ }
+
+ struct OpenHeuristic
+ {
+ __forceinline OpenHeuristic( const PrimInfoExtRange& pinfo )
+ {
+ const Vec3fa diag = pinfo.geomBounds.size();
+ dim = maxDim(diag);
+ assert(diag[dim] > 0.0f);
+ inv_max_extend = 1.0f / diag[dim];
+ }
+
+ __forceinline bool operator () ( PrimRef& prim ) const {
+ return !prim.node.isLeaf() && prim.bounds().size()[dim] * inv_max_extend > MAX_EXTEND_THRESHOLD;
+ }
+
+ private:
+ size_t dim;
+ float inv_max_extend;
+ };
+
+ /*! compute extended ranges */
+ __forceinline void setExtentedRanges(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset, const size_t lweight, const size_t rweight)
+ {
+ assert(set.ext_range_size() > 0);
+ const float left_factor = (float)lweight / (lweight + rweight);
+ const size_t ext_range_size = set.ext_range_size();
+ const size_t left_ext_range_size = min((size_t)(floorf(left_factor * ext_range_size)),ext_range_size);
+ const size_t right_ext_range_size = ext_range_size - left_ext_range_size;
+ lset.set_ext_range(lset.end() + left_ext_range_size);
+ rset.set_ext_range(rset.end() + right_ext_range_size);
+ }
+
+ /*! move ranges */
+ __forceinline void moveExtentedRange(const PrimInfoExtRange& set, const PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t left_ext_range_size = lset.ext_range_size();
+ const size_t right_size = rset.size();
+
+ /* has the left child an extended range? */
+ if (left_ext_range_size > 0)
+ {
+ /* left extended range smaller than right range ? */
+ if (left_ext_range_size < right_size)
+ {
+ /* only move a small part of the beginning of the right range to the end */
+ parallel_for( rset.begin(), rset.begin()+left_ext_range_size, MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+right_size] = prims0[i];
+ });
+ }
+ else
+ {
+ /* no overlap, move entire right range to new location, can be made fully parallel */
+ parallel_for( rset.begin(), rset.end(), MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+left_ext_range_size] = prims0[i];
+ });
+ }
+ /* update right range */
+ assert(rset.ext_end() + left_ext_range_size == set.ext_end());
+ rset.move_right(left_ext_range_size);
+ }
+ }
+
+ /* estimates the extra space required when opening, and checks if all primitives are from same geometry */
+ __noinline std::pair<size_t,bool> getProperties(const PrimInfoExtRange& set)
+ {
+ const OpenHeuristic heuristic(set);
+ const unsigned int geomID = prims0[set.begin()].geomID();
+
+ auto body = [&] (const range<size_t>& r) -> std::pair<size_t,bool> {
+ bool commonGeomID = true;
+ size_t opens = 0;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ commonGeomID &= prims0[i].geomID() == geomID;
+ if (heuristic(prims0[i]))
+ opens += prims0[i].node.getN()-1; // coarse approximation
+ }
+ return std::pair<size_t,bool>(opens,commonGeomID);
+ };
+ auto reduction = [&] (const std::pair<size_t,bool>& b0, const std::pair<size_t,bool>& b1) -> std::pair<size_t,bool> {
+ return std::pair<size_t,bool>(b0.first+b1.first,b0.second && b1.second);
+ };
+ return parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,std::pair<size_t,bool>(0,true),body,reduction);
+ }
+
+ // FIXME: should consider maximum available extended size
+ __noinline void openNodesBasedOnExtend(PrimInfoExtRange& set)
+ {
+ const OpenHeuristic heuristic(set);
+ const size_t ext_range_start = set.end();
+
+ if (false && set.size() < PARALLEL_THRESHOLD)
+ {
+ size_t extra_elements = 0;
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ assert(extra_elements + n-1 <= set.ext_range_size());
+ for (size_t j=0; j<n; j++)
+ set.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1; j<n; j++)
+ prims0[ext_range_start+extra_elements+j-1] = tmp[j];
+ extra_elements += n-1;
+ }
+ }
+ set._end += extra_elements;
+ }
+ else
+ {
+ std::atomic<size_t> ext_elements;
+ ext_elements.store(0);
+ PrimInfo info = parallel_reduce( set.begin(), set.end(), CREATE_SPLITS_STEP_SIZE, PrimInfo(empty), [&](const range<size_t>& r) -> PrimInfo {
+ PrimInfo info(empty);
+ for (size_t i=r.begin(); i<r.end(); i++)
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ const size_t ID = ext_elements.fetch_add(n-1);
+ assert(ID + n-1 <= set.ext_range_size());
+
+ for (size_t j=0; j<n; j++)
+ info.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1; j<n; j++)
+ prims0[ext_range_start+ID+j-1] = tmp[j];
+ }
+ return info;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+ set.centBounds.extend(info.centBounds);
+ assert(ext_elements.load() <= set.ext_range_size());
+ set._end += ext_elements.load();
+ }
+ }
+
+ __noinline void openNodesBasedOnExtendLoop(PrimInfoExtRange& set, const size_t est_new_elements)
+ {
+ const OpenHeuristic heuristic(set);
+ size_t next_iteration_extra_elements = est_new_elements;
+
+ while (next_iteration_extra_elements <= set.ext_range_size())
+ {
+ next_iteration_extra_elements = 0;
+ size_t extra_elements = 0;
+ const size_t ext_range_start = set.end();
+
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ assert(extra_elements + n-1 <= set.ext_range_size());
+ for (size_t j=0;j<n;j++)
+ set.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1;j<n;j++)
+ prims0[ext_range_start+extra_elements+j-1] = tmp[j];
+ extra_elements += n-1;
+
+ for (size_t j=0; j<n; j++)
+ if (heuristic(tmp[j]))
+ next_iteration_extra_elements += tmp[j].node.getN()-1; // coarse approximation
+
+ }
+ }
+ assert( extra_elements <= set.ext_range_size());
+ set._end += extra_elements;
+
+ for (size_t i=set.begin();i<set.end();i++)
+ assert(prims0[i].numPrimitives() > 0);
+
+ if (unlikely(next_iteration_extra_elements == 0)) break;
+ }
+ }
+
+ __noinline const Split find(PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ /* single element */
+ if (set.size() <= 1)
+ return Split();
+
+ /* disable opening if there is no overlap */
+ const size_t D = 4;
+ if (unlikely(set.has_ext_range() && set.size() <= D))
+ {
+ bool disjoint = true;
+ for (size_t j=set.begin(); j<set.end()-1; j++) {
+ for (size_t i=set.begin()+1; i<set.end(); i++) {
+ if (conjoint(prims0[j].bounds(),prims0[i].bounds())) {
+ disjoint = false; break;
+ }
+ }
+ }
+ if (disjoint) set.set_ext_range(set.end()); /* disables opening */
+ }
+
+ std::pair<size_t,bool> p(0,false);
+
+ /* disable opening when all primitives are from same geometry */
+ if (unlikely(set.has_ext_range()))
+ {
+ p = getProperties(set);
+#if EQUAL_GEOMID_STOP_CRITERIA == 1
+ if (p.second) set.set_ext_range(set.end()); /* disable opening */
+#endif
+ }
+
+ /* open nodes when we have sufficient space available */
+ if (unlikely(set.has_ext_range()))
+ {
+#if USE_LOOP_OPENING == 1
+ openNodesBasedOnExtendLoop(set,p.first);
+#else
+ if (p.first <= set.ext_range_size())
+ openNodesBasedOnExtend(set);
+#endif
+
+ /* disable opening when unsufficient space for opening a node available */
+ if (set.ext_range_size() < max_open_size-1)
+ set.set_ext_range(set.end()); /* disable opening */
+ }
+
+ /* find best split */
+ return object_find(set,logBlockSize);
+ }
+
+
+ /*! finds the best object split */
+ __forceinline const Split object_find(const PrimInfoExtRange& set,const size_t logBlockSize)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_object_find(set,logBlockSize);
+ else return parallel_object_find (set,logBlockSize);
+ }
+
+ /*! finds the best object split */
+ __noinline const Split sequential_object_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set.centBounds);
+ binner.bin(prims0,set.begin(),set.end(),mapping);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! finds the best split */
+ __noinline const Split parallel_object_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set.centBounds);
+ const BinMapping<OBJECT_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ auto body = [&] (const range<size_t>& r) -> Binner {
+ Binner binner(empty); binner.bin(prims0+r.begin(),r.size(),_mapping); return binner;
+ };
+ auto reduction = [&] (const Binner& b0, const Binner& b1) -> Binner {
+ Binner r = b0; r.merge(b1,_mapping.size()); return r;
+ };
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,body,reduction);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __noinline void split(const Split& split, const PrimInfoExtRange& set_i, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ PrimInfoExtRange set = set_i;
+
+ /* valid split */
+ if (unlikely(!split.valid())) {
+ deterministic_order(set);
+ splitFallback(set,lset,rset);
+ return;
+ }
+
+ std::pair<size_t,size_t> ext_weights(0,0);
+
+ /* object split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_object_split(split,set,lset,rset);
+ else
+ ext_weights = parallel_object_split(split,set,lset,rset);
+
+ /* if we have an extended range, set extended child ranges and move right split range */
+ if (unlikely(set.has_ext_range()))
+ {
+ setExtentedRanges(set,lset,rset,ext_weights.first,ext_weights.second);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ /*! array partitioning */
+ std::pair<size_t,size_t> sequential_object_split(const Split& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref); });
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(local_left.size(),local_right.size());
+ }
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_object_split(const Split& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+ auto isLeft = [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref); },
+ [] (PrimInfo& pinfo0,const PrimInfo& pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+
+ return std::pair<size_t,size_t>(left.size(),right.size());
+ }
+
+ void deterministic_order(const extended_range<size_t>& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims0[set.begin()],&prims0[set.end()]);
+ }
+
+ __forceinline void splitFallback(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfo left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.add_center2(prims0[i]);
+
+ const size_t lweight = left.end;
+
+ PrimInfo right(empty);
+ for (size_t i=center; i<end; i++)
+ right.add_center2(prims0[i]);
+
+ const size_t rweight = right.end;
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ /* if we have an extended range */
+ if (set.has_ext_range())
+ {
+ setExtentedRanges(set,lset,rset,lweight,rweight);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ private:
+ PrimRef* const prims0;
+ const NodeOpenerFunc& nodeOpenerFunc;
+ size_t max_open_size;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial.h
new file mode 100644
index 0000000000..d8ca6cb92c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial.h
@@ -0,0 +1,414 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "priminfo.h"
+
+namespace embree
+{
+ static const unsigned int RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS = 5;
+
+ namespace isa
+ {
+
+ /*! mapping into bins */
+ template<size_t BINS>
+ struct SpatialBinMapping
+ {
+ public:
+ __forceinline SpatialBinMapping() {}
+
+ /*! calculates the mapping */
+ __forceinline SpatialBinMapping(const CentGeomBBox3fa& pinfo)
+ {
+ const vfloat4 lower = (vfloat4) pinfo.geomBounds.lower;
+ const vfloat4 upper = (vfloat4) pinfo.geomBounds.upper;
+ const vfloat4 eps = 128.0f*vfloat4(ulp)*max(abs(lower),abs(upper));
+ const vfloat4 diag = max(eps,(vfloat4) pinfo.geomBounds.size());
+ scale = select(upper-lower <= eps,vfloat4(0.0f),vfloat4(BINS)/diag);
+ ofs = (vfloat4) pinfo.geomBounds.lower;
+ inv_scale = 1.0f / scale;
+ }
+
+ /*! slower but safe binning */
+ __forceinline vint4 bin(const Vec3fa& p) const
+ {
+ const vint4 i = floori((vfloat4(p)-ofs)*scale);
+ return clamp(i,vint4(0),vint4(BINS-1));
+ }
+
+ __forceinline std::pair<vint4,vint4> bin(const BBox3fa& b) const
+ {
+#if defined(__AVX__)
+ const vfloat8 ofs8(ofs);
+ const vfloat8 scale8(scale);
+ const vint8 lu = floori((vfloat8::loadu(&b)-ofs8)*scale8);
+ const vint8 c_lu = clamp(lu,vint8(zero),vint8(BINS-1));
+ return std::pair<vint4,vint4>(extract4<0>(c_lu),extract4<1>(c_lu));
+#else
+ const vint4 lower = floori((vfloat4(b.lower)-ofs)*scale);
+ const vint4 upper = floori((vfloat4(b.upper)-ofs)*scale);
+ const vint4 c_lower = clamp(lower,vint4(0),vint4(BINS-1));
+ const vint4 c_upper = clamp(upper,vint4(0),vint4(BINS-1));
+ return std::pair<vint4,vint4>(c_lower,c_upper);
+#endif
+ }
+
+
+ /*! calculates left spatial position of bin */
+ __forceinline float pos(const size_t bin, const size_t dim) const {
+ return madd(float(bin),inv_scale[dim],ofs[dim]);
+ }
+
+ /*! calculates left spatial position of bin */
+ template<size_t N>
+ __forceinline vfloat<N> posN(const vfloat<N> bin, const size_t dim) const {
+ return madd(bin,vfloat<N>(inv_scale[dim]),vfloat<N>(ofs[dim]));
+ }
+
+ /*! returns true if the mapping is invalid in some dimension */
+ __forceinline bool invalid(const size_t dim) const {
+ return scale[dim] == 0.0f;
+ }
+
+ public:
+ vfloat4 ofs,scale,inv_scale; //!< linear function that maps to bin ID
+ };
+
+ /*! stores all information required to perform some split */
+ template<size_t BINS>
+ struct SpatialBinSplit
+ {
+ /*! construct an invalid split by default */
+ __forceinline SpatialBinSplit()
+ : sah(inf), dim(-1), pos(0), left(-1), right(-1), factor(1.0f) {}
+
+ /*! constructs specified split */
+ __forceinline SpatialBinSplit(float sah, int dim, int pos, const SpatialBinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), left(-1), right(-1), factor(1.0f), mapping(mapping) {}
+
+ /*! constructs specified split */
+ __forceinline SpatialBinSplit(float sah, int dim, int pos, int left, int right, float factor, const SpatialBinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), left(left), right(right), factor(factor), mapping(mapping) {}
+
+ /*! tests if this split is valid */
+ __forceinline bool valid() const { return dim != -1; }
+
+ /*! calculates surface area heuristic for performing the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const SpatialBinSplit& split) {
+ return cout << "SpatialBinSplit { sah = " << split.sah << ", dim = " << split.dim << ", pos = " << split.pos << ", left = " << split.left << ", right = " << split.right << ", factor = " << split.factor << "}";
+ }
+
+ public:
+ float sah; //!< SAH cost of the split
+ int dim; //!< split dimension
+ int pos; //!< split position
+ int left; //!< number of elements on the left side
+ int right; //!< number of elements on the right side
+ float factor; //!< factor splitting the extended range
+ SpatialBinMapping<BINS> mapping; //!< mapping into bins
+ };
+
+ /*! stores all binning information */
+ template<size_t BINS, typename PrimRef>
+ struct __aligned(64) SpatialBinInfo
+ {
+ SpatialBinInfo() {
+ }
+
+ __forceinline SpatialBinInfo(EmptyTy) {
+ clear();
+ }
+
+ /*! clears the bin info */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<BINS; i++) {
+ bounds[i][0] = bounds[i][1] = bounds[i][2] = empty;
+ numBegin[i] = numEnd[i] = 0;
+ }
+ }
+
+ /*! adds binning data */
+ __forceinline void add(const size_t dim,
+ const size_t beginID,
+ const size_t endID,
+ const size_t binID,
+ const BBox3fa &b,
+ const size_t n = 1)
+ {
+ assert(beginID < BINS);
+ assert(endID < BINS);
+ assert(binID < BINS);
+
+ numBegin[beginID][dim]+=(unsigned int)n;
+ numEnd [endID][dim]+=(unsigned int)n;
+ bounds [binID][dim].extend(b);
+ }
+
+ /*! extends binning bounds */
+ __forceinline void extend(const size_t dim,
+ const size_t binID,
+ const BBox3fa &b)
+ {
+ assert(binID < BINS);
+ bounds [binID][dim].extend(b);
+ }
+
+ /*! bins an array of triangles */
+ template<typename SplitPrimitive>
+ __forceinline void bin(const SplitPrimitive& splitPrimitive, const PrimRef* prims, size_t N, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef prim = prims[i];
+ unsigned splits = prim.geomID() >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ if (unlikely(splits == 1))
+ {
+ const vint4 bin = mapping.bin(center(prim.bounds()));
+ for (size_t dim=0; dim<3; dim++)
+ {
+ assert(bin[dim] >= (int)0 && bin[dim] < (int)BINS);
+ numBegin[bin[dim]][dim]++;
+ numEnd [bin[dim]][dim]++;
+ bounds [bin[dim]][dim].extend(prim.bounds());
+ }
+ }
+ else
+ {
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ size_t bin;
+ PrimRef rest = prim;
+ size_t l = bin0[dim];
+ size_t r = bin1[dim];
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ numBegin[l][dim]++;
+ numEnd [l][dim]++;
+ bounds [l][dim].extend(prim.bounds());
+ continue;
+ }
+
+ for (bin=(size_t)bin0[dim]; bin<(size_t)bin1[dim]; bin++)
+ {
+ const float pos = mapping.pos(bin+1,dim);
+
+ PrimRef left,right;
+ splitPrimitive(rest,(int)dim,pos,left,right);
+ if (unlikely(left.bounds().empty())) l++;
+ bounds[bin][dim].extend(left.bounds());
+ rest = right;
+ }
+ if (unlikely(rest.bounds().empty())) r--;
+ numBegin[l][dim]++;
+ numEnd [r][dim]++;
+ bounds [bin][dim].extend(rest.bounds());
+ }
+ }
+ }
+ }
+
+ /*! bins a range of primitives inside an array */
+ template<typename SplitPrimitive>
+ void bin(const SplitPrimitive& splitPrimitive, const PrimRef* prims, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping) {
+ bin(splitPrimitive,prims+begin,end-begin,mapping);
+ }
+
+ /*! bins an array of primitives */
+ template<typename PrimitiveSplitterFactory>
+ __forceinline void bin2(const PrimitiveSplitterFactory& splitterFactory, const PrimRef* source, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=begin; i<end; i++)
+ {
+ const PrimRef &prim = source[i];
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ size_t bin;
+ size_t l = bin0[dim];
+ size_t r = bin1[dim];
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ add(dim,l,l,l,prim.bounds());
+ continue;
+ }
+ const size_t bin_start = bin0[dim];
+ const size_t bin_end = bin1[dim];
+ BBox3fa rest = prim.bounds();
+ const auto splitter = splitterFactory(prim);
+ for (bin=bin_start; bin<bin_end; bin++)
+ {
+ const float pos = mapping.pos(bin+1,dim);
+ BBox3fa left,right;
+ splitter(rest,dim,pos,left,right);
+ if (unlikely(left.empty())) l++;
+ extend(dim,bin,left);
+ rest = right;
+ }
+ if (unlikely(rest.empty())) r--;
+ add(dim,l,r,bin,rest);
+ }
+ }
+ }
+
+
+
+ /*! bins an array of primitives */
+ __forceinline void binSubTreeRefs(const PrimRef* source, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=begin; i<end; i++)
+ {
+ const PrimRef &prim = source[i];
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ const size_t l = bin0[dim];
+ const size_t r = bin1[dim];
+
+ const unsigned int n = prim.primID();
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ add(dim,l,l,l,prim.bounds(),n);
+ continue;
+ }
+ const size_t bin_start = bin0[dim];
+ const size_t bin_end = bin1[dim];
+ for (size_t bin=bin_start; bin<bin_end; bin++)
+ add(dim,l,r,bin,prim.bounds(),n);
+ }
+ }
+ }
+
+ /*! merges in other binning information */
+ void merge (const SpatialBinInfo& other)
+ {
+ for (size_t i=0; i<BINS; i++)
+ {
+ numBegin[i] += other.numBegin[i];
+ numEnd [i] += other.numEnd [i];
+ bounds[i][0].extend(other.bounds[i][0]);
+ bounds[i][1].extend(other.bounds[i][1]);
+ bounds[i][2].extend(other.bounds[i][2]);
+ }
+ }
+
+ /*! merges in other binning information */
+ static __forceinline const SpatialBinInfo reduce (const SpatialBinInfo& a, const SpatialBinInfo& b)
+ {
+ SpatialBinInfo c(empty);
+ for (size_t i=0; i<BINS; i++)
+ {
+ c.numBegin[i] += a.numBegin[i]+b.numBegin[i];
+ c.numEnd [i] += a.numEnd [i]+b.numEnd [i];
+ c.bounds[i][0] = embree::merge(a.bounds[i][0],b.bounds[i][0]);
+ c.bounds[i][1] = embree::merge(a.bounds[i][1],b.bounds[i][1]);
+ c.bounds[i][2] = embree::merge(a.bounds[i][2],b.bounds[i][2]);
+ }
+ return c;
+ }
+
+ /*! finds the best split by scanning binning information */
+ SpatialBinSplit<BINS> best(const SpatialBinMapping<BINS>& mapping, const size_t blocks_shift) const
+ {
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ vfloat4 rAreas[BINS];
+ vuint4 rCounts[BINS];
+ vuint4 count = 0; BBox3fa bx = empty; BBox3fa by = empty; BBox3fa bz = empty;
+ for (size_t i=BINS-1; i>0; i--)
+ {
+ count += numEnd[i];
+ rCounts[i] = count;
+ bx.extend(bounds[i][0]); rAreas[i][0] = halfArea(bx);
+ by.extend(bounds[i][1]); rAreas[i][1] = halfArea(by);
+ bz.extend(bounds[i][2]); rAreas[i][2] = halfArea(bz);
+ rAreas[i][3] = 0.0f;
+ }
+
+ /* sweep from left to right and compute SAH */
+ vuint4 blocks_add = (1 << blocks_shift)-1;
+ vuint4 ii = 1; vfloat4 vbestSAH = pos_inf; vuint4 vbestPos = 0; vuint4 vbestlCount = 0; vuint4 vbestrCount = 0;
+ count = 0; bx = empty; by = empty; bz = empty;
+ for (size_t i=1; i<BINS; i++, ii+=1)
+ {
+ count += numBegin[i-1];
+ bx.extend(bounds[i-1][0]); float Ax = halfArea(bx);
+ by.extend(bounds[i-1][1]); float Ay = halfArea(by);
+ bz.extend(bounds[i-1][2]); float Az = halfArea(bz);
+ const vfloat4 lArea = vfloat4(Ax,Ay,Az,Az);
+ const vfloat4 rArea = rAreas[i];
+ const vuint4 lCount = (count +blocks_add) >> (unsigned int)(blocks_shift);
+ const vuint4 rCount = (rCounts[i]+blocks_add) >> (unsigned int)(blocks_shift);
+ const vfloat4 sah = madd(lArea,vfloat4(lCount),rArea*vfloat4(rCount));
+ // const vfloat4 sah = madd(lArea,vfloat4(vint4(lCount)),rArea*vfloat4(vint4(rCount)));
+ const vbool4 mask = sah < vbestSAH;
+ vbestPos = select(mask,ii ,vbestPos);
+ vbestSAH = select(mask,sah,vbestSAH);
+ vbestlCount = select(mask,count,vbestlCount);
+ vbestrCount = select(mask,rCounts[i],vbestrCount);
+ }
+
+ /* find best dimension */
+ float bestSAH = inf;
+ int bestDim = -1;
+ int bestPos = 0;
+ unsigned int bestlCount = 0;
+ unsigned int bestrCount = 0;
+ for (int dim=0; dim<3; dim++)
+ {
+ /* ignore zero sized dimensions */
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ /* test if this is a better dimension */
+ if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) {
+ bestDim = dim;
+ bestPos = vbestPos[dim];
+ bestSAH = vbestSAH[dim];
+ bestlCount = vbestlCount[dim];
+ bestrCount = vbestrCount[dim];
+ }
+ }
+ assert(bestSAH >= 0.0f);
+
+ /* return invalid split if no split found */
+ if (bestDim == -1)
+ return SpatialBinSplit<BINS>(inf,-1,0,mapping);
+
+ /* return best found split */
+ return SpatialBinSplit<BINS>(bestSAH,bestDim,bestPos,bestlCount,bestrCount,1.0f,mapping);
+ }
+
+ private:
+ BBox3fa bounds[BINS][3]; //!< geometry bounds for each bin in each dimension
+ vuint4 numBegin[BINS]; //!< number of primitives starting in bin
+ vuint4 numEnd[BINS]; //!< number of primitives ending in bin
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial_array.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial_array.h
new file mode 100644
index 0000000000..911dcf950c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_spatial_array.h
@@ -0,0 +1,552 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+#include "heuristic_spatial.h"
+
+namespace embree
+{
+ namespace isa
+ {
+#if 0
+#define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.2f
+#define SPATIAL_ASPLIT_SAH_THRESHOLD 0.95f
+#define SPATIAL_ASPLIT_AREA_THRESHOLD 0.0f
+#else
+#define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.1f
+#define SPATIAL_ASPLIT_SAH_THRESHOLD 0.99f
+#define SPATIAL_ASPLIT_AREA_THRESHOLD 0.000005f
+#endif
+
+ struct PrimInfoExtRange : public CentGeomBBox3fa, public extended_range<size_t>
+ {
+ __forceinline PrimInfoExtRange() {
+ }
+
+ __forceinline PrimInfoExtRange(EmptyTy)
+ : CentGeomBBox3fa(EmptyTy()), extended_range<size_t>(0,0,0) {}
+
+ __forceinline PrimInfoExtRange(size_t begin, size_t end, size_t ext_end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeomBBox3fa(centGeomBounds), extended_range<size_t>(begin,end,ext_end) {}
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+ };
+
+ template<typename ObjectSplit, typename SpatialSplit>
+ struct Split2
+ {
+ __forceinline Split2 () {}
+
+ __forceinline Split2 (const Split2& other)
+ {
+ spatial = other.spatial;
+ sah = other.sah;
+ if (spatial) spatialSplit() = other.spatialSplit();
+ else objectSplit() = other.objectSplit();
+ }
+
+ __forceinline Split2& operator= (const Split2& other)
+ {
+ spatial = other.spatial;
+ sah = other.sah;
+ if (spatial) spatialSplit() = other.spatialSplit();
+ else objectSplit() = other.objectSplit();
+ return *this;
+ }
+
+ __forceinline ObjectSplit& objectSplit() { return *( ObjectSplit*)data; }
+ __forceinline const ObjectSplit& objectSplit() const { return *(const ObjectSplit*)data; }
+
+ __forceinline SpatialSplit& spatialSplit() { return *( SpatialSplit*)data; }
+ __forceinline const SpatialSplit& spatialSplit() const { return *(const SpatialSplit*)data; }
+
+ __forceinline Split2 (const ObjectSplit& objectSplit, float sah)
+ : spatial(false), sah(sah)
+ {
+ new (data) ObjectSplit(objectSplit);
+ }
+
+ __forceinline Split2 (const SpatialSplit& spatialSplit, float sah)
+ : spatial(true), sah(sah)
+ {
+ new (data) SpatialSplit(spatialSplit);
+ }
+
+ __forceinline float splitSAH() const {
+ return sah;
+ }
+
+ __forceinline bool valid() const {
+ return sah < float(inf);
+ }
+
+ public:
+ __aligned(64) char data[sizeof(ObjectSplit) > sizeof(SpatialSplit) ? sizeof(ObjectSplit) : sizeof(SpatialSplit)];
+ bool spatial;
+ float sah;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimitiveSplitterFactory, typename PrimRef, size_t OBJECT_BINS, size_t SPATIAL_BINS>
+ struct HeuristicArraySpatialSAH
+ {
+ typedef BinSplit<OBJECT_BINS> ObjectSplit;
+ typedef BinInfoT<OBJECT_BINS,PrimRef,BBox3fa> ObjectBinner;
+
+ typedef SpatialBinSplit<SPATIAL_BINS> SpatialSplit;
+ typedef SpatialBinInfo<SPATIAL_BINS,PrimRef> SpatialBinner;
+
+ //typedef extended_range<size_t> Set;
+ typedef Split2<ObjectSplit,SpatialSplit> Split;
+
+#if defined(__AVX512ER__) // KNL
+ static const size_t PARALLEL_THRESHOLD = 3*1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 768;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+#else
+ static const size_t PARALLEL_THRESHOLD = 3*1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+#endif
+
+ static const size_t MOVE_STEP_SIZE = 64;
+ static const size_t CREATE_SPLITS_STEP_SIZE = 64;
+
+ __forceinline HeuristicArraySpatialSAH ()
+ : prims0(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArraySpatialSAH (const PrimitiveSplitterFactory& splitterFactory, PrimRef* prims0, const CentGeomBBox3fa& root_info)
+ : prims0(prims0), splitterFactory(splitterFactory), root_info(root_info) {}
+
+
+ /*! compute extended ranges */
+ __noinline void setExtentedRanges(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset, const size_t lweight, const size_t rweight)
+ {
+ assert(set.ext_range_size() > 0);
+ const float left_factor = (float)lweight / (lweight + rweight);
+ const size_t ext_range_size = set.ext_range_size();
+ const size_t left_ext_range_size = min((size_t)(floorf(left_factor * ext_range_size)),ext_range_size);
+ const size_t right_ext_range_size = ext_range_size - left_ext_range_size;
+ lset.set_ext_range(lset.end() + left_ext_range_size);
+ rset.set_ext_range(rset.end() + right_ext_range_size);
+ }
+
+ /*! move ranges */
+ __noinline void moveExtentedRange(const PrimInfoExtRange& set, const PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t left_ext_range_size = lset.ext_range_size();
+ const size_t right_size = rset.size();
+
+ /* has the left child an extended range? */
+ if (left_ext_range_size > 0)
+ {
+ /* left extended range smaller than right range ? */
+ if (left_ext_range_size < right_size)
+ {
+ /* only move a small part of the beginning of the right range to the end */
+ parallel_for( rset.begin(), rset.begin()+left_ext_range_size, MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+right_size] = prims0[i];
+ });
+ }
+ else
+ {
+ /* no overlap, move entire right range to new location, can be made fully parallel */
+ parallel_for( rset.begin(), rset.end(), MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+left_ext_range_size] = prims0[i];
+ });
+ }
+ /* update right range */
+ assert(rset.ext_end() + left_ext_range_size == set.ext_end());
+ rset.move_right(left_ext_range_size);
+ }
+ }
+
+ /*! finds the best split */
+ const Split find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SplitInfo oinfo;
+ const ObjectSplit object_split = object_find(set,logBlockSize,oinfo);
+ const float object_split_sah = object_split.splitSAH();
+
+ if (unlikely(set.has_ext_range()))
+ {
+ const BBox3fa overlap = intersect(oinfo.leftBounds, oinfo.rightBounds);
+
+ /* do only spatial splits if the child bounds overlap */
+ if (safeArea(overlap) >= SPATIAL_ASPLIT_AREA_THRESHOLD*safeArea(root_info.geomBounds) &&
+ safeArea(overlap) >= SPATIAL_ASPLIT_OVERLAP_THRESHOLD*safeArea(set.geomBounds))
+ {
+ const SpatialSplit spatial_split = spatial_find(set, logBlockSize);
+ const float spatial_split_sah = spatial_split.splitSAH();
+
+ /* valid spatial split, better SAH and number of splits do not exceed extended range */
+ if (spatial_split_sah < SPATIAL_ASPLIT_SAH_THRESHOLD*object_split_sah &&
+ spatial_split.left + spatial_split.right - set.size() <= set.ext_range_size())
+ {
+ return Split(spatial_split,spatial_split_sah);
+ }
+ }
+ }
+
+ return Split(object_split,object_split_sah);
+ }
+
+ /*! finds the best object split */
+ __forceinline const ObjectSplit object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_object_find(set,logBlockSize,info);
+ else return parallel_object_find (set,logBlockSize,info);
+ }
+
+ /*! finds the best object split */
+ __noinline const ObjectSplit sequential_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set);
+ binner.bin(prims0,set.begin(),set.end(),mapping);
+ ObjectSplit s = binner.best(mapping,logBlockSize);
+ binner.getSplitInfo(mapping, s, info);
+ return s;
+ }
+
+ /*! finds the best split */
+ __noinline const ObjectSplit parallel_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set);
+ const BinMapping<OBJECT_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
+ [&] (const range<size_t>& r) -> ObjectBinner { ObjectBinner binner(empty); binner.bin(prims0+r.begin(),r.size(),_mapping); return binner; },
+ [&] (const ObjectBinner& b0, const ObjectBinner& b1) -> ObjectBinner { ObjectBinner r = b0; r.merge(b1,_mapping.size()); return r; });
+ ObjectSplit s = binner.best(mapping,logBlockSize);
+ binner.getSplitInfo(mapping, s, info);
+ return s;
+ }
+
+ /*! finds the best spatial split */
+ __forceinline const SpatialSplit spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_spatial_find(set, logBlockSize);
+ else return parallel_spatial_find (set, logBlockSize);
+ }
+
+ /*! finds the best spatial split */
+ __noinline const SpatialSplit sequential_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SpatialBinner binner(empty);
+ const SpatialBinMapping<SPATIAL_BINS> mapping(set);
+ binner.bin2(splitterFactory,prims0,set.begin(),set.end(),mapping);
+ /* todo: best spatial split not exeeding the extended range does not provide any benefit ?*/
+ return binner.best(mapping,logBlockSize); //,set.ext_size());
+ }
+
+ __noinline const SpatialSplit parallel_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SpatialBinner binner(empty);
+ const SpatialBinMapping<SPATIAL_BINS> mapping(set);
+ const SpatialBinMapping<SPATIAL_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
+ [&] (const range<size_t>& r) -> SpatialBinner {
+ SpatialBinner binner(empty);
+ binner.bin2(splitterFactory,prims0,r.begin(),r.end(),_mapping);
+ return binner; },
+ [&] (const SpatialBinner& b0, const SpatialBinner& b1) -> SpatialBinner { return SpatialBinner::reduce(b0,b1); });
+ /* todo: best spatial split not exeeding the extended range does not provide any benefit ?*/
+ return binner.best(mapping,logBlockSize); //,set.ext_size());
+ }
+
+
+ /*! subdivides primitives based on a spatial split */
+ __noinline void create_spatial_splits(PrimInfoExtRange& set, const SpatialSplit& split, const SpatialBinMapping<SPATIAL_BINS> &mapping)
+ {
+ assert(set.has_ext_range());
+ const size_t max_ext_range_size = set.ext_range_size();
+ const size_t ext_range_start = set.end();
+
+ /* atomic counter for number of primref splits */
+ std::atomic<size_t> ext_elements;
+ ext_elements.store(0);
+
+ const float fpos = split.mapping.pos(split.pos,split.dim);
+
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+
+ parallel_for( set.begin(), set.end(), CREATE_SPLITS_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin();i<r.end();i++)
+ {
+ const unsigned int splits = prims0[i].geomID() >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ if (likely(splits <= 1)) continue; /* todo: does this ever happen ? */
+
+ //int bin0 = split.mapping.bin(prims0[i].lower)[split.dim];
+ //int bin1 = split.mapping.bin(prims0[i].upper)[split.dim];
+ //if (unlikely(bin0 < split.pos && bin1 >= split.pos))
+ if (unlikely(prims0[i].lower[split.dim] < fpos && prims0[i].upper[split.dim] > fpos))
+ {
+ assert(splits > 1);
+
+ PrimRef left,right;
+ const auto splitter = splitterFactory(prims0[i]);
+ splitter(prims0[i],split.dim,fpos,left,right);
+
+ // no empty splits
+ if (unlikely(left.bounds().empty() || right.bounds().empty())) continue;
+
+ left.lower.u = (left.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ right.lower.u = (right.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+
+ const size_t ID = ext_elements.fetch_add(1);
+
+ /* break if the number of subdivided elements are greater than the maximum allowed size */
+ if (unlikely(ID >= max_ext_range_size))
+ break;
+
+ /* only write within the correct bounds */
+ assert(ID < max_ext_range_size);
+ prims0[i] = left;
+ prims0[ext_range_start+ID] = right;
+ }
+ }
+ });
+
+ const size_t numExtElements = min(max_ext_range_size,ext_elements.load());
+ assert(set.end()+numExtElements<=set.ext_end());
+ set._end += numExtElements;
+ }
+
+ /*! array partitioning */
+ void split(const Split& split, const PrimInfoExtRange& set_i, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ PrimInfoExtRange set = set_i;
+
+ /* valid split */
+ if (unlikely(!split.valid())) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ std::pair<size_t,size_t> ext_weights(0,0);
+
+ if (unlikely(split.spatial))
+ {
+ create_spatial_splits(set,split.spatialSplit(), split.spatialSplit().mapping);
+
+ /* spatial split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_spatial_split(split.spatialSplit(),set,lset,rset);
+ else
+ ext_weights = parallel_spatial_split(split.spatialSplit(),set,lset,rset);
+ }
+ else
+ {
+ /* object split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_object_split(split.objectSplit(),set,lset,rset);
+ else
+ ext_weights = parallel_object_split(split.objectSplit(),set,lset,rset);
+ }
+
+ /* if we have an extended range, set extended child ranges and move right split range */
+ if (unlikely(set.has_ext_range()))
+ {
+ setExtentedRanges(set,lset,rset,ext_weights.first,ext_weights.second);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ /*! array partitioning */
+ std::pair<size_t,size_t> sequential_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename ObjectBinner::vint vSplitPos(splitPos);
+ const typename ObjectBinner::vbool vSplitMask(splitDimMask);
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) {
+ return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask);
+ },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
+ const size_t left_weight = local_left.end;
+ const size_t right_weight = local_right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> sequential_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ /* init spatial mapping */
+ const SpatialBinMapping<SPATIAL_BINS> &mapping = split.mapping;
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) {
+ const Vec3fa c = ref.bounds().center();
+ return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask);
+ },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
+
+ const size_t left_weight = local_left.end;
+ const size_t right_weight = local_right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename ObjectBinner::vint vSplitPos(splitPos);
+ const typename ObjectBinner::vbool vSplitMask(splitDimMask);
+ auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
+ [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ const size_t left_weight = left.end;
+ const size_t right_weight = right.end;
+
+ left.begin = begin; left.end = center;
+ right.begin = center; right.end = end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ assert(area(left.geomBounds) >= 0.0f);
+ assert(area(right.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ /* init spatial mapping */
+ const SpatialBinMapping<SPATIAL_BINS>& mapping = split.mapping;
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ auto isLeft = [&] (const PrimRef &ref) {
+ const Vec3fa c = ref.bounds().center();
+ return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
+ [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ const size_t left_weight = left.end;
+ const size_t right_weight = right.end;
+
+ left.begin = begin; left.end = center;
+ right.begin = center; right.end = end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ assert(area(left.geomBounds) >= 0.0f);
+ assert(area(right.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+ void deterministic_order(const PrimInfoExtRange& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims0[set.begin()],&prims0[set.end()]);
+ }
+
+ void splitFallback(const PrimInfoExtRange& set,
+ PrimInfoExtRange& lset,
+ PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfo left(empty);
+ for (size_t i=begin; i<center; i++) {
+ left.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ }
+ const size_t lweight = left.end;
+
+ PrimInfo right(empty);
+ for (size_t i=center; i<end; i++) {
+ right.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ }
+ const size_t rweight = right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ /* if we have an extended range */
+ if (set.has_ext_range()) {
+ setExtentedRanges(set,lset,rset,lweight,rweight);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ private:
+ PrimRef* const prims0;
+ const PrimitiveSplitterFactory& splitterFactory;
+ const CentGeomBBox3fa& root_info;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_strand_array.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_strand_array.h
new file mode 100644
index 0000000000..ede0d04c78
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_strand_array.h
@@ -0,0 +1,188 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "priminfo.h"
+#include "../../common/algorithms/parallel_reduce.h"
+#include "../../common/algorithms/parallel_partition.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ struct HeuristicStrandSplit
+ {
+ typedef range<size_t> Set;
+
+ static const size_t PARALLEL_THRESHOLD = 10000;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 4096;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 64;
+
+ /*! stores all information to perform some split */
+ struct Split
+ {
+ /*! construct an invalid split by default */
+ __forceinline Split()
+ : sah(inf), axis0(zero), axis1(zero) {}
+
+ /*! constructs specified split */
+ __forceinline Split(const float sah, const Vec3fa& axis0, const Vec3fa& axis1)
+ : sah(sah), axis0(axis0), axis1(axis1) {}
+
+ /*! calculates standard surface area heuristic for the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! test if this split is valid */
+ __forceinline bool valid() const { return sah != float(inf); }
+
+ public:
+ float sah; //!< SAH cost of the split
+ Vec3fa axis0, axis1; //!< axis the two strands are aligned into
+ };
+
+ __forceinline HeuristicStrandSplit () // FIXME: required?
+ : scene(nullptr), prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicStrandSplit (Scene* scene, PrimRef* prims)
+ : scene(scene), prims(prims) {}
+
+ __forceinline const Vec3fa direction(const PrimRef& prim) {
+ return scene->get(prim.geomID())->computeDirection(prim.primID());
+ }
+
+ __forceinline const BBox3fa bounds(const PrimRef& prim) {
+ return scene->get(prim.geomID())->vbounds(prim.primID());
+ }
+
+ __forceinline const BBox3fa bounds(const LinearSpace3fa& space, const PrimRef& prim) {
+ return scene->get(prim.geomID())->vbounds(space,prim.primID());
+ }
+
+ /*! finds the best split */
+ const Split find(const range<size_t>& set, size_t logBlockSize)
+ {
+ Vec3fa axis0(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /* curve with minimum ID determines first axis */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const uint64_t geomprimID = prims[i].ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+ const Vec3fa axis = direction(prims[i]);
+ if (sqr_length(axis) > 1E-18f) {
+ axis0 = normalize(axis);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ /* find 2nd axis that is most misaligned with first axis and has minimum ID */
+ float bestCos = 1.0f;
+ Vec3fa axis1 = axis0;
+ bestGeomPrimID = -1;
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const uint64_t geomprimID = prims[i].ID64();
+ Vec3fa axisi = direction(prims[i]);
+ float leni = length(axisi);
+ if (leni == 0.0f) continue;
+ axisi /= leni;
+ float cos = abs(dot(axisi,axis0));
+ if ((cos == bestCos && (geomprimID < bestGeomPrimID)) || cos < bestCos) {
+ bestCos = cos; axis1 = axisi;
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ /* partition the two strands */
+ size_t lnum = 0, rnum = 0;
+ BBox3fa lbounds = empty, rbounds = empty;
+ const LinearSpace3fa space0 = frame(axis0).transposed();
+ const LinearSpace3fa space1 = frame(axis1).transposed();
+
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ const Vec3fa axisi = normalize(direction(prim));
+ const float cos0 = abs(dot(axisi,axis0));
+ const float cos1 = abs(dot(axisi,axis1));
+
+ if (cos0 > cos1) { lnum++; lbounds.extend(bounds(space0,prim)); }
+ else { rnum++; rbounds.extend(bounds(space1,prim)); }
+ }
+
+ /*! return an invalid split if we do not partition */
+ if (lnum == 0 || rnum == 0)
+ return Split(inf,axis0,axis1);
+
+ /*! calculate sah for the split */
+ const size_t lblocks = (lnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;
+ const size_t rblocks = (rnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;
+ const float sah = madd(float(lblocks),halfArea(lbounds),float(rblocks)*halfArea(rbounds));
+ return Split(sah,axis0,axis1);
+ }
+
+ /*! array partitioning */
+ void split(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+
+ auto primOnLeftSide = [&] (const PrimRef& prim) -> bool {
+ const Vec3fa axisi = normalize(direction(prim));
+ const float cos0 = abs(dot(axisi,split.axis0));
+ const float cos1 = abs(dot(axisi,split.axis1));
+ return cos0 > cos1;
+ };
+
+ auto mergePrimBounds = [this] (CentGeomBBox3fa& pinfo,const PrimRef& ref) {
+ pinfo.extend(bounds(ref));
+ };
+
+ size_t center = serial_partitioning(prims,begin,end,local_left,local_right,primOnLeftSide,mergePrimBounds);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const Set& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[set.begin()],&prims[set.end()]);
+ }
+
+ void splitFallback(const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend(bounds(prims[i]));
+ new (&lset) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend(bounds(prims[i]));
+ new (&rset) PrimInfoRange(center,end,right);
+ }
+
+ private:
+ Scene* const scene;
+ PrimRef* const prims;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/heuristic_timesplit_array.h b/thirdparty/embree-aarch64/kernels/builders/heuristic_timesplit_array.h
new file mode 100644
index 0000000000..c999941a11
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/heuristic_timesplit_array.h
@@ -0,0 +1,237 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/primref_mb.h"
+#include "../../common/algorithms/parallel_filter.h"
+
+#define MBLUR_TIME_SPLIT_THRESHOLD 1.25f
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, typename RecalculatePrimRef, size_t BINS>
+ struct HeuristicMBlurTemporalSplit
+ {
+ typedef BinSplit<MBLUR_NUM_OBJECT_BINS> Split;
+ typedef mvector<PrimRefMB>* PrimRefVector;
+ typedef typename PrimRefMB::BBox BBox;
+
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ HeuristicMBlurTemporalSplit (MemoryMonitorInterface* device, const RecalculatePrimRef& recalculatePrimRef)
+ : device(device), recalculatePrimRef(recalculatePrimRef) {}
+
+ struct TemporalBinInfo
+ {
+ __forceinline TemporalBinInfo () {
+ }
+
+ __forceinline TemporalBinInfo (EmptyTy)
+ {
+ for (size_t i=0; i<BINS-1; i++)
+ {
+ count0[i] = count1[i] = 0;
+ bounds0[i] = bounds1[i] = empty;
+ }
+ }
+
+ void bin(const PrimRefMB* prims, size_t begin, size_t end, BBox1f time_range, const SetMB& set, const RecalculatePrimRef& recalculatePrimRef)
+ {
+ for (int b=0; b<BINS-1; b++)
+ {
+ const float t = float(b+1)/float(BINS);
+ const float ct = lerp(time_range.lower,time_range.upper,t);
+ const float center_time = set.align_time(ct);
+ if (center_time <= time_range.lower) continue;
+ if (center_time >= time_range.upper) continue;
+ const BBox1f dt0(time_range.lower,center_time);
+ const BBox1f dt1(center_time,time_range.upper);
+
+ /* find linear bounds for both time segments */
+ for (size_t i=begin; i<end; i++)
+ {
+ if (prims[i].time_range_overlap(dt0))
+ {
+ const LBBox3fa bn0 = recalculatePrimRef.linearBounds(prims[i],dt0);
+#if MBLUR_BIN_LBBOX
+ bounds0[b].extend(bn0);
+#else
+ bounds0[b].extend(bn0.interpolate(0.5f));
+#endif
+ count0[b] += prims[i].timeSegmentRange(dt0).size();
+ }
+
+ if (prims[i].time_range_overlap(dt1))
+ {
+ const LBBox3fa bn1 = recalculatePrimRef.linearBounds(prims[i],dt1);
+#if MBLUR_BIN_LBBOX
+ bounds1[b].extend(bn1);
+#else
+ bounds1[b].extend(bn1.interpolate(0.5f));
+#endif
+ count1[b] += prims[i].timeSegmentRange(dt1).size();
+ }
+ }
+ }
+ }
+
+ __forceinline void bin_parallel(const PrimRefMB* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, BBox1f time_range, const SetMB& set, const RecalculatePrimRef& recalculatePrimRef)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ bin(prims,begin,end,time_range,set,recalculatePrimRef);
+ }
+ else
+ {
+ auto bin = [&](const range<size_t>& r) -> TemporalBinInfo {
+ TemporalBinInfo binner(empty); binner.bin(prims, r.begin(), r.end(), time_range, set, recalculatePrimRef); return binner;
+ };
+ *this = parallel_reduce(begin,end,blockSize,TemporalBinInfo(empty),bin,merge2);
+ }
+ }
+
+ /*! merges in other binning information */
+ __forceinline void merge (const TemporalBinInfo& other)
+ {
+ for (size_t i=0; i<BINS-1; i++)
+ {
+ count0[i] += other.count0[i];
+ count1[i] += other.count1[i];
+ bounds0[i].extend(other.bounds0[i]);
+ bounds1[i].extend(other.bounds1[i]);
+ }
+ }
+
+ static __forceinline const TemporalBinInfo merge2(const TemporalBinInfo& a, const TemporalBinInfo& b) {
+ TemporalBinInfo r = a; r.merge(b); return r;
+ }
+
+ Split best(int logBlockSize, BBox1f time_range, const SetMB& set)
+ {
+ float bestSAH = inf;
+ float bestPos = 0.0f;
+ for (int b=0; b<BINS-1; b++)
+ {
+ float t = float(b+1)/float(BINS);
+ float ct = lerp(time_range.lower,time_range.upper,t);
+ const float center_time = set.align_time(ct);
+ if (center_time <= time_range.lower) continue;
+ if (center_time >= time_range.upper) continue;
+ const BBox1f dt0(time_range.lower,center_time);
+ const BBox1f dt1(center_time,time_range.upper);
+
+ /* calculate sah */
+ const size_t lCount = (count0[b]+(size_t(1) << logBlockSize)-1) >> int(logBlockSize);
+ const size_t rCount = (count1[b]+(size_t(1) << logBlockSize)-1) >> int(logBlockSize);
+ float sah0 = expectedApproxHalfArea(bounds0[b])*float(lCount)*dt0.size();
+ float sah1 = expectedApproxHalfArea(bounds1[b])*float(rCount)*dt1.size();
+ if (unlikely(lCount == 0)) sah0 = 0.0f; // happens for initial splits when objects not alive over entire shutter time
+ if (unlikely(rCount == 0)) sah1 = 0.0f;
+ const float sah = sah0+sah1;
+ if (sah < bestSAH) {
+ bestSAH = sah;
+ bestPos = center_time;
+ }
+ }
+ return Split(bestSAH*MBLUR_TIME_SPLIT_THRESHOLD,(unsigned)Split::SPLIT_TEMPORAL,0,bestPos);
+ }
+
+ public:
+ size_t count0[BINS-1];
+ size_t count1[BINS-1];
+ BBox bounds0[BINS-1];
+ BBox bounds1[BINS-1];
+ };
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize)
+ {
+ assert(set.size() > 0);
+ TemporalBinInfo binner(empty);
+ binner.bin_parallel(set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,set.time_range,set,recalculatePrimRef);
+ Split tsplit = binner.best((int)logBlockSize,set.time_range,set);
+ if (!tsplit.valid()) tsplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return tsplit;
+ }
+
+ __forceinline std::unique_ptr<mvector<PrimRefMB>> split(const Split& tsplit, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(tsplit.sah != float(inf));
+ assert(tsplit.fpos > set.time_range.lower);
+ assert(tsplit.fpos < set.time_range.upper);
+
+ float center_time = tsplit.fpos;
+ const BBox1f time_range0(set.time_range.lower,center_time);
+ const BBox1f time_range1(center_time,set.time_range.upper);
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ /* calculate primrefs for first time range */
+ std::unique_ptr<mvector<PrimRefMB>> new_vector(new mvector<PrimRefMB>(device, set.size()));
+ PrimRefVector lprims = new_vector.get();
+
+ auto reduction_func0 = [&] (const range<size_t>& r) {
+ PrimInfoMB pinfo = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (likely(prims[i].time_range_overlap(time_range0)))
+ {
+ const PrimRefMB& prim = recalculatePrimRef(prims[i],time_range0);
+ (*lprims)[i-set.begin()] = prim;
+ pinfo.add_primref(prim);
+ }
+ else
+ {
+ (*lprims)[i-set.begin()] = prims[i];
+ }
+ }
+ return pinfo;
+ };
+ PrimInfoMB linfo = parallel_reduce(set.object_range,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD,PrimInfoMB(empty),reduction_func0,PrimInfoMB::merge2);
+
+ /* primrefs for first time range are in lprims[0 .. set.size()) */
+ /* some primitives may need to be filtered out */
+ if (linfo.size() != set.size())
+ linfo.object_range._end = parallel_filter(lprims->data(), size_t(0), set.size(), size_t(1024),
+ [&](const PrimRefMB& prim) { return prim.time_range_overlap(time_range0); });
+
+ lset = SetMB(linfo,lprims,time_range0);
+
+ /* calculate primrefs for second time range */
+ auto reduction_func1 = [&] (const range<size_t>& r) {
+ PrimInfoMB pinfo = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (likely(prims[i].time_range_overlap(time_range1)))
+ {
+ const PrimRefMB& prim = recalculatePrimRef(prims[i],time_range1);
+ prims[i] = prim;
+ pinfo.add_primref(prim);
+ }
+ }
+ return pinfo;
+ };
+ PrimInfoMB rinfo = parallel_reduce(set.object_range,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD,PrimInfoMB(empty),reduction_func1,PrimInfoMB::merge2);
+ rinfo.object_range = range<size_t>(set.begin(), set.begin() + rinfo.size());
+
+ /* primrefs for second time range are in prims[set.begin() .. set.end()) */
+ /* some primitives may need to be filtered out */
+ if (rinfo.size() != set.size())
+ rinfo.object_range._end = parallel_filter(prims.data(), set.begin(), set.end(), size_t(1024),
+ [&](const PrimRefMB& prim) { return prim.time_range_overlap(time_range1); });
+
+ rset = SetMB(rinfo,&prims,time_range1);
+
+ return new_vector;
+ }
+
+ private:
+ MemoryMonitorInterface* device; // device to report memory usage to
+ const RecalculatePrimRef recalculatePrimRef;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/priminfo.h b/thirdparty/embree-aarch64/kernels/builders/priminfo.h
new file mode 100644
index 0000000000..06c1388742
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/priminfo.h
@@ -0,0 +1,362 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+
+namespace embree
+{
+ // FIXME: maybe there's a better place for this util fct
+ __forceinline float areaProjectedTriangle(const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2)
+ {
+ const Vec3fa e0 = v1-v0;
+ const Vec3fa e1 = v2-v0;
+ const Vec3fa d = cross(e0,e1);
+ return fabs(d.x) + fabs(d.y) + fabs(d.z);
+ }
+
+ //namespace isa
+ //{
+ template<typename BBox>
+ class CentGeom
+ {
+ public:
+ __forceinline CentGeom () {}
+
+ __forceinline CentGeom (EmptyTy)
+ : geomBounds(empty), centBounds(empty) {}
+
+ __forceinline CentGeom (const BBox& geomBounds, const BBox3fa& centBounds)
+ : geomBounds(geomBounds), centBounds(centBounds) {}
+
+ template<typename PrimRef>
+ __forceinline void extend_primref(const PrimRef& prim)
+ {
+ BBox bounds; Vec3fa center;
+ prim.binBoundsAndCenter(bounds,center);
+ geomBounds.extend(bounds);
+ centBounds.extend(center);
+ }
+
+ template<typename PrimRef>
+ __forceinline void extend_center2(const PrimRef& prim)
+ {
+ BBox3fa bounds = prim.bounds();
+ geomBounds.extend(bounds);
+ centBounds.extend(bounds.center2());
+ }
+
+ __forceinline void extend(const BBox& geomBounds_) {
+ geomBounds.extend(geomBounds_);
+ centBounds.extend(center2(geomBounds_));
+ }
+
+ __forceinline void merge(const CentGeom& other)
+ {
+ geomBounds.extend(other.geomBounds);
+ centBounds.extend(other.centBounds);
+ }
+
+ static __forceinline const CentGeom merge2(const CentGeom& a, const CentGeom& b) {
+ CentGeom r = a; r.merge(b); return r;
+ }
+
+ public:
+ BBox geomBounds; //!< geometry bounds of primitives
+ BBox3fa centBounds; //!< centroid bounds of primitives
+ };
+
+ typedef CentGeom<BBox3fa> CentGeomBBox3fa;
+
+ /*! stores bounding information for a set of primitives */
+ template<typename BBox>
+ class PrimInfoT : public CentGeom<BBox>
+ {
+ public:
+ using CentGeom<BBox>::geomBounds;
+ using CentGeom<BBox>::centBounds;
+
+ __forceinline PrimInfoT () {}
+
+ __forceinline PrimInfoT (EmptyTy)
+ : CentGeom<BBox>(empty), begin(0), end(0) {}
+
+ __forceinline PrimInfoT (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeom<BBox>(centGeomBounds), begin(begin), end(end) {}
+
+ template<typename PrimRef>
+ __forceinline void add_primref(const PrimRef& prim)
+ {
+ CentGeom<BBox>::extend_primref(prim);
+ end++;
+ }
+
+ template<typename PrimRef>
+ __forceinline void add_center2(const PrimRef& prim) {
+ CentGeom<BBox>::extend_center2(prim);
+ end++;
+ }
+
+ template<typename PrimRef>
+ __forceinline void add_center2(const PrimRef& prim, const size_t i) {
+ CentGeom<BBox>::extend_center2(prim);
+ end+=i;
+ }
+
+ /*__forceinline void add(const BBox& geomBounds_) {
+ CentGeom<BBox>::extend(geomBounds_);
+ end++;
+ }
+
+ __forceinline void add(const BBox& geomBounds_, const size_t i) {
+ CentGeom<BBox>::extend(geomBounds_);
+ end+=i;
+ }*/
+
+ __forceinline void merge(const PrimInfoT& other)
+ {
+ CentGeom<BBox>::merge(other);
+ begin += other.begin;
+ end += other.end;
+ }
+
+ static __forceinline const PrimInfoT merge(const PrimInfoT& a, const PrimInfoT& b) {
+ PrimInfoT r = a; r.merge(b); return r;
+ }
+
+ /*! returns the number of primitives */
+ __forceinline size_t size() const {
+ return end-begin;
+ }
+
+ __forceinline float halfArea() {
+ return expectedApproxHalfArea(geomBounds);
+ }
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ //return halfArea(geomBounds)*blocks(num);
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ //return halfArea(geomBounds)*float((num+3) >> 2);
+ //return halfArea(geomBounds)*blocks(num);
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const PrimInfoT& pinfo) {
+ return cout << "PrimInfo { begin = " << pinfo.begin << ", end = " << pinfo.end << ", geomBounds = " << pinfo.geomBounds << ", centBounds = " << pinfo.centBounds << "}";
+ }
+
+ public:
+ size_t begin,end; //!< number of primitives
+ };
+
+ typedef PrimInfoT<BBox3fa> PrimInfo;
+ //typedef PrimInfoT<LBBox3fa> PrimInfoMB;
+
+ /*! stores bounding information for a set of primitives */
+ template<typename BBox>
+ class PrimInfoMBT : public CentGeom<BBox>
+ {
+ public:
+ using CentGeom<BBox>::geomBounds;
+ using CentGeom<BBox>::centBounds;
+
+ __forceinline PrimInfoMBT () {
+ }
+
+ __forceinline PrimInfoMBT (EmptyTy)
+ : CentGeom<BBox>(empty), object_range(0,0), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {}
+
+ __forceinline PrimInfoMBT (size_t begin, size_t end)
+ : CentGeom<BBox>(empty), object_range(begin,end), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {}
+
+ template<typename PrimRef>
+ __forceinline void add_primref(const PrimRef& prim)
+ {
+ CentGeom<BBox>::extend_primref(prim);
+ time_range.extend(prim.time_range);
+ object_range._end++;
+ num_time_segments += prim.size();
+ if (max_num_time_segments < prim.totalTimeSegments()) {
+ max_num_time_segments = prim.totalTimeSegments();
+ max_time_range = prim.time_range;
+ }
+ }
+
+ __forceinline void merge(const PrimInfoMBT& other)
+ {
+ CentGeom<BBox>::merge(other);
+ time_range.extend(other.time_range);
+ object_range._begin += other.object_range.begin();
+ object_range._end += other.object_range.end();
+ num_time_segments += other.num_time_segments;
+ if (max_num_time_segments < other.max_num_time_segments) {
+ max_num_time_segments = other.max_num_time_segments;
+ max_time_range = other.max_time_range;
+ }
+ }
+
+ static __forceinline const PrimInfoMBT merge2(const PrimInfoMBT& a, const PrimInfoMBT& b) {
+ PrimInfoMBT r = a; r.merge(b); return r;
+ }
+
+ __forceinline size_t begin() const {
+ return object_range.begin();
+ }
+
+ __forceinline size_t end() const {
+ return object_range.end();
+ }
+
+ /*! returns the number of primitives */
+ __forceinline size_t size() const {
+ return object_range.size();
+ }
+
+ __forceinline float halfArea() const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds);
+ }
+
+ __forceinline float leafSAH() const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds)*float(num_time_segments);
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds)*float((num_time_segments+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+
+ __forceinline float align_time(float ct) const
+ {
+ //return roundf(ct * float(numTimeSegments)) / float(numTimeSegments);
+ float t0 = (ct-max_time_range.lower)/max_time_range.size();
+ float t1 = roundf(t0 * float(max_num_time_segments)) / float(max_num_time_segments);
+ return t1*max_time_range.size()+max_time_range.lower;
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const PrimInfoMBT& pinfo)
+ {
+ return cout << "PrimInfo { " <<
+ "object_range = " << pinfo.object_range <<
+ ", time_range = " << pinfo.time_range <<
+ ", time_segments = " << pinfo.num_time_segments <<
+ ", geomBounds = " << pinfo.geomBounds <<
+ ", centBounds = " << pinfo.centBounds <<
+ "}";
+ }
+
+ public:
+ range<size_t> object_range; //!< primitive range
+ size_t num_time_segments; //!< total number of time segments of all added primrefs
+ size_t max_num_time_segments; //!< maximum number of time segments of a primitive
+ BBox1f max_time_range; //!< time range of primitive with max_num_time_segments
+ BBox1f time_range; //!< merged time range of primitives when merging prims, or additionally clipped with build time range when used in SetMB
+ };
+
+ typedef PrimInfoMBT<typename PrimRefMB::BBox> PrimInfoMB;
+
+ struct SetMB : public PrimInfoMB
+ {
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ typedef mvector<PrimRefMB>* PrimRefVector;
+
+ __forceinline SetMB() {}
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims)
+ : PrimInfoMB(pinfo_i), prims(prims) {}
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, range<size_t> object_range_in, BBox1f time_range_in)
+ : PrimInfoMB(pinfo_i), prims(prims)
+ {
+ object_range = object_range_in;
+ time_range = intersect(time_range,time_range_in);
+ }
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, BBox1f time_range_in)
+ : PrimInfoMB(pinfo_i), prims(prims)
+ {
+ time_range = intersect(time_range,time_range_in);
+ }
+
+ void deterministic_order() const
+ {
+ /* required as parallel partition destroys original primitive order */
+ PrimRefMB* prim = prims->data();
+ std::sort(&prim[object_range.begin()],&prim[object_range.end()]);
+ }
+
+ template<typename RecalculatePrimRef>
+ __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef) const
+ {
+ auto reduce = [&](const range<size_t>& r) -> LBBox3fa
+ {
+ LBBox3fa cbounds(empty);
+ for (size_t j = r.begin(); j < r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range);
+ cbounds.extend(bn);
+ };
+ return cbounds;
+ };
+
+ return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty),
+ reduce,
+ [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); });
+ }
+
+ template<typename RecalculatePrimRef>
+ __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const
+ {
+ auto reduce = [&](const range<size_t>& r) -> LBBox3fa
+ {
+ LBBox3fa cbounds(empty);
+ for (size_t j = r.begin(); j < r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range, space);
+ cbounds.extend(bn);
+ };
+ return cbounds;
+ };
+
+ return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty),
+ reduce,
+ [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); });
+ }
+
+ template<typename RecalculatePrimRef>
+ const SetMB primInfo(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const
+ {
+ auto computePrimInfo = [&](const range<size_t>& r) -> PrimInfoMB
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ PrimRefMB ref1 = recalculatePrimRef(ref,time_range,space);
+ pinfo.add_primref(ref1);
+ };
+ return pinfo;
+ };
+
+ const PrimInfoMB pinfo = parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD,
+ PrimInfoMB(empty), computePrimInfo, PrimInfoMB::merge2);
+
+ return SetMB(pinfo,prims,object_range,time_range);
+ }
+
+ public:
+ PrimRefVector prims;
+ };
+//}
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/primrefgen.cpp b/thirdparty/embree-aarch64/kernels/builders/primrefgen.cpp
new file mode 100644
index 0000000000..e23de3df28
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/primrefgen.cpp
@@ -0,0 +1,244 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primrefgen.h"
+#include "primrefgen_presplit.h"
+
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelPrefixSumState<PrimInfo> pstate;
+
+ /* first try */
+ progressMonitor(0);
+ PrimInfo pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,r.begin(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != prims.size())
+ {
+ progressMonitor(0);
+ pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,base.size(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,mblur);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != prims.size())
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime)
+ {
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,true);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArrayMB(prims,itime,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != prims.size())
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArrayMB(prims,itime,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1)
+ {
+ ParallelForForPrefixSumState<PrimInfoMB> pstate;
+ Scene::Iterator2 iter(scene,types,true);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfoMB pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfoMB {
+ return mesh->createPrimRefMBArray(prims,t0t1,r,k,(unsigned)geomID);
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != prims.size())
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB {
+ return mesh->createPrimRefMBArray(prims,t0t1,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+ }
+
+ /* the BVH starts with that time range, even though primitives might have smaller/larger time range */
+ pinfo.time_range = t0t1;
+ return pinfo;
+ }
+
+ template<typename Mesh>
+ size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor)
+ {
+ size_t numPrimitives = morton.size();
+
+ /* compute scene bounds */
+ std::pair<size_t,BBox3fa> cb_empty(0,empty);
+ auto cb = parallel_reduce
+ ( size_t(0), numPrimitives, size_t(1024), cb_empty, [&](const range<size_t>& r) -> std::pair<size_t,BBox3fa>
+ {
+ size_t num = 0;
+ BBox3fa bounds = empty;
+
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa prim_bounds = empty;
+ if (unlikely(!mesh->buildBounds(j,&prim_bounds))) continue;
+ bounds.extend(center2(prim_bounds));
+ num++;
+ }
+ return std::make_pair(num,bounds);
+ }, [] (const std::pair<size_t,BBox3fa>& a, const std::pair<size_t,BBox3fa>& b) {
+ return std::make_pair(a.first + b.first,merge(a.second,b.second));
+ });
+
+
+ size_t numPrimitivesGen = cb.first;
+ const BBox3fa centBounds = cb.second;
+
+ /* compute morton codes */
+ if (likely(numPrimitivesGen == numPrimitives))
+ {
+ /* fast path if all primitives were valid */
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_for( size_t(0), numPrimitives, size_t(1024), [&](const range<size_t>& r) -> void {
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[r.begin()]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ generator(mesh->bounds(j),unsigned(j));
+ });
+ }
+ else
+ {
+ /* slow path, fallback in case some primitives were invalid */
+ ParallelPrefixSumState<size_t> pstate;
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_prefix_sum( pstate, size_t(0), numPrimitives, size_t(1024), size_t(0), [&](const range<size_t>& r, const size_t base) -> size_t {
+ size_t num = 0;
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[r.begin()]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (unlikely(!mesh->buildBounds(j,&bounds))) continue;
+ generator(bounds,unsigned(j));
+ num++;
+ }
+ return num;
+ }, std::plus<size_t>());
+
+ parallel_prefix_sum( pstate, size_t(0), numPrimitives, size_t(1024), size_t(0), [&](const range<size_t>& r, const size_t base) -> size_t {
+ size_t num = 0;
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[base]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(j,&bounds)) continue;
+ generator(bounds,unsigned(j));
+ num++;
+ }
+ return num;
+ }, std::plus<size_t>());
+ }
+ return numPrimitivesGen;
+ }
+
+ // ====================================================================================================
+ // ====================================================================================================
+ // ====================================================================================================
+
+ // template for grid meshes
+
+#if 0
+ template<>
+ PrimInfo createPrimRefArray<GridMesh,false>(Scene* scene, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ PING;
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator<GridMesh,false> iter(scene);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k) -> PrimInfo
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,mesh->geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != prims.size())
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, const PrimInfo& base) -> PrimInfo
+ {
+ k = base.size();
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,mesh->geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+#endif
+
+ // ====================================================================================================
+ // ====================================================================================================
+ // ====================================================================================================
+
+ IF_ENABLED_TRIS (template size_t createMortonCodeArray<TriangleMesh>(TriangleMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_QUADS(template size_t createMortonCodeArray<QuadMesh>(QuadMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_USER (template size_t createMortonCodeArray<UserGeometry>(UserGeometry* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_INSTANCE (template size_t createMortonCodeArray<Instance>(Instance* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/primrefgen.h b/thirdparty/embree-aarch64/kernels/builders/primrefgen.h
new file mode 100644
index 0000000000..9919c945c3
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/primrefgen.h
@@ -0,0 +1,28 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+#include "priminfo.h"
+#include "bvh_builder_morton.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
+
+ PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
+
+ PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime = 0);
+
+ PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f));
+
+ template<typename Mesh>
+ size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor);
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/builders/primrefgen_presplit.h b/thirdparty/embree-aarch64/kernels/builders/primrefgen_presplit.h
new file mode 100644
index 0000000000..8bdb38b955
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/primrefgen_presplit.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../builders/primrefgen.h"
+#include "../builders/heuristic_spatial.h"
+#include "../builders/splitter.h"
+
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+#define DBG_PRESPLIT(x)
+#define CHECK_PRESPLIT(x)
+
+#define GRID_SIZE 1024
+#define MAX_PRESPLITS_PER_PRIMITIVE_LOG 5
+#define MAX_PRESPLITS_PER_PRIMITIVE (1<<MAX_PRESPLITS_PER_PRIMITIVE_LOG)
+#define PRIORITY_CUTOFF_THRESHOLD 1.0f
+#define PRIORITY_SPLIT_POS_WEIGHT 1.5f
+
+namespace embree
+{
+ namespace isa
+ {
+
+ struct PresplitItem
+ {
+ union {
+ float priority;
+ unsigned int data;
+ };
+ unsigned int index;
+
+ __forceinline operator unsigned() const
+ {
+ return reinterpret_cast<const unsigned&>(priority);
+ }
+ __forceinline bool operator < (const PresplitItem& item) const
+ {
+ return (priority < item.priority);
+ }
+
+ template<typename Mesh>
+ __forceinline static float compute_priority(const PrimRef &ref, Scene *scene, const Vec2i &mc)
+ {
+ const unsigned int geomID = ref.geomID();
+ const unsigned int primID = ref.primID();
+ const float area_aabb = area(ref.bounds());
+ const float area_prim = ((Mesh*)scene->get(geomID))->projectedPrimitiveArea(primID);
+ const unsigned int diff = 31 - lzcnt(mc.x^mc.y);
+ assert(area_prim <= area_aabb);
+ //const float priority = powf((area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff),1.0f/4.0f);
+ const float priority = sqrtf(sqrtf( (area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff) ));
+ assert(priority >= 0.0f && priority < FLT_LARGE);
+ return priority;
+ }
+
+
+ };
+
+ inline std::ostream &operator<<(std::ostream &cout, const PresplitItem& item) {
+ return cout << "index " << item.index << " priority " << item.priority;
+ };
+
+ template<typename SplitterFactory>
+ void splitPrimitive(SplitterFactory &Splitter,
+ const PrimRef &prim,
+ const unsigned int geomID,
+ const unsigned int primID,
+ const unsigned int split_level,
+ const Vec3fa &grid_base,
+ const float grid_scale,
+ const float grid_extend,
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE],
+ unsigned int& numSubPrims)
+ {
+ assert(split_level <= MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ if (split_level == 0)
+ {
+ assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE);
+ subPrims[numSubPrims++] = prim;
+ }
+ else
+ {
+ const Vec3fa lower = prim.lower;
+ const Vec3fa upper = prim.upper;
+ const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f);
+ const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f);
+ Vec3ia ilower(floor(glower));
+ Vec3ia iupper(floor(gupper));
+
+ /* this ignores dimensions that are empty */
+ iupper = (Vec3ia)(select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper)));
+
+ /* compute a morton code for the lower and upper grid coordinates. */
+ const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z);
+ const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z);
+
+ /* if all bits are equal then we cannot split */
+ if(unlikely(lower_code == upper_code))
+ {
+ assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE);
+ subPrims[numSubPrims++] = prim;
+ return;
+ }
+
+ /* compute octree level and dimension to perform the split in */
+ const unsigned int diff = 31 - lzcnt(lower_code^upper_code);
+ const unsigned int level = diff / 3;
+ const unsigned int dim = diff % 3;
+
+ /* now we compute the grid position of the split */
+ const unsigned int isplit = iupper[dim] & ~((1<<level)-1);
+
+ /* compute world space position of split */
+ const float inv_grid_size = 1.0f / GRID_SIZE;
+ const float fsplit = grid_base[dim] + isplit * inv_grid_size * grid_extend;
+
+ assert(prim.lower[dim] <= fsplit &&
+ prim.upper[dim] >= fsplit);
+
+ /* split primitive */
+ const auto splitter = Splitter(prim);
+ BBox3fa left,right;
+ splitter(prim.bounds(),dim,fsplit,left,right);
+ assert(!left.empty());
+ assert(!right.empty());
+
+
+ splitPrimitive(Splitter,PrimRef(left ,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ splitPrimitive(Splitter,PrimRef(right,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ }
+ }
+
+
+ template<typename Mesh, typename SplitterFactory>
+ PrimInfo createPrimRefArray_presplit(Geometry* geometry, unsigned int geomID, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelPrefixSumState<PrimInfo> pstate;
+
+ /* first try */
+ progressMonitor(0);
+ PrimInfo pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,r.begin(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,base.size(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ __forceinline Vec2i computeMC(const Vec3fa &grid_base, const float grid_scale, const PrimRef &ref)
+ {
+ const Vec3fa lower = ref.lower;
+ const Vec3fa upper = ref.upper;
+ const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f);
+ const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f);
+ Vec3ia ilower(floor(glower));
+ Vec3ia iupper(floor(gupper));
+
+ /* this ignores dimensions that are empty */
+ iupper = (Vec3ia)select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper));
+
+ /* compute a morton code for the lower and upper grid coordinates. */
+ const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z);
+ const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z);
+ return Vec2i(lower_code,upper_code);
+ }
+
+ template<typename Mesh, typename SplitterFactory>
+ PrimInfo createPrimRefArray_presplit(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ static const size_t MIN_STEP_SIZE = 128;
+
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,mblur);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+
+ /* use correct number of primitives */
+ size_t numPrimitives = pinfo.size();
+ const size_t alloc_numPrimitives = prims.size();
+ const size_t numSplitPrimitivesBudget = alloc_numPrimitives - numPrimitives;
+
+ /* set up primitive splitter */
+ SplitterFactory Splitter(scene);
+
+
+ DBG_PRESPLIT(
+ const size_t org_numPrimitives = pinfo.size();
+ PRINT(numPrimitives);
+ PRINT(alloc_numPrimitives);
+ PRINT(numSplitPrimitivesBudget);
+ );
+
+ /* allocate double buffer presplit items */
+ const size_t presplit_allocation_size = sizeof(PresplitItem)*alloc_numPrimitives;
+ PresplitItem *presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64);
+ PresplitItem *tmp_presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64);
+
+ /* compute grid */
+ const Vec3fa grid_base = pinfo.geomBounds.lower;
+ const Vec3fa grid_diag = pinfo.geomBounds.size();
+ const float grid_extend = max(grid_diag.x,max(grid_diag.y,grid_diag.z));
+ const float grid_scale = grid_extend == 0.0f ? 0.0f : GRID_SIZE / grid_extend;
+
+ /* init presplit items and get total sum */
+ const float psum = parallel_reduce( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), 0.0f, [&](const range<size_t>& r) -> float {
+ float sum = 0.0f;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ presplitItem[i].index = (unsigned int)i;
+ const Vec2i mc = computeMC(grid_base,grid_scale,prims[i]);
+ /* if all bits are equal then we cannot split */
+ presplitItem[i].priority = (mc.x != mc.y) ? PresplitItem::compute_priority<Mesh>(prims[i],scene,mc) : 0.0f;
+ /* FIXME: sum undeterministic */
+ sum += presplitItem[i].priority;
+ }
+ return sum;
+ },[](const float& a, const float& b) -> float { return a+b; });
+
+ /* compute number of splits per primitive */
+ const float inv_psum = 1.0f / psum;
+ parallel_for( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (presplitItem[i].priority > 0.0f)
+ {
+ const float rel_p = (float)numSplitPrimitivesBudget * presplitItem[i].priority * inv_psum;
+ if (rel_p >= PRIORITY_CUTOFF_THRESHOLD) // need at least a split budget that generates two sub-prims
+ {
+ presplitItem[i].priority = max(min(ceilf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG),1.0f);
+ //presplitItem[i].priority = min(floorf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ assert(presplitItem[i].priority >= 0.0f && presplitItem[i].priority <= (float)MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ }
+ else
+ presplitItem[i].priority = 0.0f;
+ }
+ }
+ });
+
+ auto isLeft = [&] (const PresplitItem &ref) { return ref.priority < PRIORITY_CUTOFF_THRESHOLD; };
+ size_t center = parallel_partitioning(presplitItem,0,numPrimitives,isLeft,1024);
+
+ /* anything to split ? */
+ if (center < numPrimitives)
+ {
+ const size_t numPrimitivesToSplit = numPrimitives - center;
+ assert(presplitItem[center].priority >= 1.0f);
+
+ /* sort presplit items in ascending order */
+ radix_sort_u32(presplitItem + center,tmp_presplitItem + center,numPrimitivesToSplit,1024);
+
+ CHECK_PRESPLIT(
+ parallel_for( size_t(center+1), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ assert(presplitItem[i-1].priority <= presplitItem[i].priority);
+ });
+ );
+
+ unsigned int *const primOffset0 = (unsigned int*)tmp_presplitItem;
+ unsigned int *const primOffset1 = (unsigned int*)tmp_presplitItem + numPrimitivesToSplit;
+
+ /* compute actual number of sub-primitives generated within the [center;numPrimitives-1] range */
+ const size_t totalNumSubPrims = parallel_reduce( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), size_t(0), [&](const range<size_t>& t) -> size_t {
+ size_t sum = 0;
+ for (size_t i=t.begin(); i<t.end(); i++)
+ {
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE];
+ assert(presplitItem[i].priority >= 1.0f);
+ const unsigned int primrefID = presplitItem[i].index;
+ const float prio = presplitItem[i].priority;
+ const unsigned int geomID = prims[primrefID].geomID();
+ const unsigned int primID = prims[primrefID].primID();
+ const unsigned int split_levels = (unsigned int)prio;
+ unsigned int numSubPrims = 0;
+ splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ assert(numSubPrims);
+ numSubPrims--; // can reuse slot
+ sum+=numSubPrims;
+ presplitItem[i].data = (numSubPrims << MAX_PRESPLITS_PER_PRIMITIVE_LOG) | split_levels;
+ primOffset0[i-center] = numSubPrims;
+ }
+ return sum;
+ },[](const size_t& a, const size_t& b) -> size_t { return a+b; });
+
+ /* if we are over budget, need to shrink the range */
+ if (totalNumSubPrims > numSplitPrimitivesBudget)
+ {
+ size_t new_center = numPrimitives-1;
+ size_t sum = 0;
+ for (;new_center>=center;new_center--)
+ {
+ const unsigned int numSubPrims = presplitItem[new_center].data >> MAX_PRESPLITS_PER_PRIMITIVE_LOG;
+ if (unlikely(sum + numSubPrims >= numSplitPrimitivesBudget)) break;
+ sum += numSubPrims;
+ }
+ new_center++;
+ center = new_center;
+ }
+
+ /* parallel prefix sum to compute offsets for storing sub-primitives */
+ const unsigned int offset = parallel_prefix_sum(primOffset0,primOffset1,numPrimitivesToSplit,(unsigned int)0,std::plus<unsigned int>());
+
+ /* iterate over range, and split primitives into sub primitives and append them to prims array */
+ parallel_for( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& rn) -> void {
+ for (size_t j=rn.begin(); j<rn.end(); j++)
+ {
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE];
+ const unsigned int primrefID = presplitItem[j].index;
+ const unsigned int geomID = prims[primrefID].geomID();
+ const unsigned int primID = prims[primrefID].primID();
+ const unsigned int split_levels = presplitItem[j].data & ((unsigned int)(1 << MAX_PRESPLITS_PER_PRIMITIVE_LOG)-1);
+
+ assert(split_levels);
+ assert(split_levels <= MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ unsigned int numSubPrims = 0;
+ splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ const size_t newID = numPrimitives + primOffset1[j-center];
+ assert(newID+numSubPrims <= alloc_numPrimitives);
+ prims[primrefID] = subPrims[0];
+ for (size_t i=1;i<numSubPrims;i++)
+ prims[newID+i-1] = subPrims[i];
+ }
+ });
+
+ numPrimitives += offset;
+ DBG_PRESPLIT(
+ PRINT(pinfo.size());
+ PRINT(numPrimitives);
+ PRINT((float)numPrimitives/org_numPrimitives));
+ }
+
+ /* recompute centroid bounding boxes */
+ pinfo = parallel_reduce(size_t(0),numPrimitives,size_t(MIN_STEP_SIZE),PrimInfo(empty),[&] (const range<size_t>& r) -> PrimInfo {
+ PrimInfo p(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ p.add_center2(prims[j]);
+ return p;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ assert(pinfo.size() == numPrimitives);
+
+ /* free double buffer presplit items */
+ alignedFree(tmp_presplitItem);
+ alignedFree(presplitItem);
+ return pinfo;
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/builders/splitter.h b/thirdparty/embree-aarch64/kernels/builders/splitter.h
new file mode 100644
index 0000000000..dbd6cf07c7
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/builders/splitter.h
@@ -0,0 +1,169 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/primref.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<size_t N>
+ __forceinline void splitPolygon(const BBox3fa& bounds,
+ const size_t dim,
+ const float pos,
+ const Vec3fa (&v)[N+1],
+ const Vec3fa (&inv_length)[N],
+ BBox3fa& left_o,
+ BBox3fa& right_o)
+ {
+ BBox3fa left = empty, right = empty;
+ /* clip triangle to left and right box by processing all edges */
+ for (size_t i=0; i<N; i++)
+ {
+ const Vec3fa &v0 = v[i];
+ const Vec3fa &v1 = v[i+1];
+ const float v0d = v0[dim];
+ const float v1d = v1[dim];
+
+ if (v0d <= pos) left. extend(v0); // this point is on left side
+ if (v0d >= pos) right.extend(v0); // this point is on right side
+
+ if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location
+ {
+ assert((v1d-v0d) != 0.0f);
+ const Vec3fa c = madd(Vec3fa((pos-v0d)*inv_length[i][dim]),v1-v0,v0);
+ left.extend(c);
+ right.extend(c);
+ }
+ }
+
+ /* clip against current bounds */
+ left_o = intersect(left,bounds);
+ right_o = intersect(right,bounds);
+ }
+
+ template<size_t N>
+ __forceinline void splitPolygon(const PrimRef& prim,
+ const size_t dim,
+ const float pos,
+ const Vec3fa (&v)[N+1],
+ PrimRef& left_o,
+ PrimRef& right_o)
+ {
+ BBox3fa left = empty, right = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const Vec3fa &v0 = v[i];
+ const Vec3fa &v1 = v[i+1];
+ const float v0d = v0[dim];
+ const float v1d = v1[dim];
+
+ if (v0d <= pos) left. extend(v0); // this point is on left side
+ if (v0d >= pos) right.extend(v0); // this point is on right side
+
+ if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location
+ {
+ assert((v1d-v0d) != 0.0f);
+ const float inv_length = 1.0f/(v1d-v0d);
+ const Vec3fa c = madd(Vec3fa((pos-v0d)*inv_length),v1-v0,v0);
+ left.extend(c);
+ right.extend(c);
+ }
+ }
+
+ /* clip against current bounds */
+ new (&left_o ) PrimRef(intersect(left ,prim.bounds()),prim.geomID(), prim.primID());
+ new (&right_o) PrimRef(intersect(right,prim.bounds()),prim.geomID(), prim.primID());
+ }
+
+ struct TriangleSplitter
+ {
+ __forceinline TriangleSplitter(const Scene* scene, const PrimRef& prim)
+ {
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ const TriangleMesh* mesh = (const TriangleMesh*) scene->get(prim.geomID() & mask );
+ TriangleMesh::Triangle tri = mesh->triangle(prim.primID());
+ v[0] = mesh->vertex(tri.v[0]);
+ v[1] = mesh->vertex(tri.v[1]);
+ v[2] = mesh->vertex(tri.v[2]);
+ v[3] = mesh->vertex(tri.v[0]);
+ inv_length[0] = Vec3fa(1.0f) / (v[1]-v[0]);
+ inv_length[1] = Vec3fa(1.0f) / (v[2]-v[1]);
+ inv_length[2] = Vec3fa(1.0f) / (v[0]-v[2]);
+ }
+
+ __forceinline void operator() (const PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const {
+ splitPolygon<3>(prim,dim,pos,v,left_o,right_o);
+ }
+
+ __forceinline void operator() (const BBox3fa& prim, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const {
+ splitPolygon<3>(prim,dim,pos,v,inv_length,left_o,right_o);
+ }
+
+ private:
+ Vec3fa v[4];
+ Vec3fa inv_length[3];
+ };
+
+ struct TriangleSplitterFactory
+ {
+ __forceinline TriangleSplitterFactory(const Scene* scene)
+ : scene(scene) {}
+
+ __forceinline TriangleSplitter operator() (const PrimRef& prim) const {
+ return TriangleSplitter(scene,prim);
+ }
+
+ private:
+ const Scene* scene;
+ };
+
+ struct QuadSplitter
+ {
+ __forceinline QuadSplitter(const Scene* scene, const PrimRef& prim)
+ {
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ const QuadMesh* mesh = (const QuadMesh*) scene->get(prim.geomID() & mask );
+ QuadMesh::Quad quad = mesh->quad(prim.primID());
+ v[0] = mesh->vertex(quad.v[0]);
+ v[1] = mesh->vertex(quad.v[1]);
+ v[2] = mesh->vertex(quad.v[2]);
+ v[3] = mesh->vertex(quad.v[3]);
+ v[4] = mesh->vertex(quad.v[0]);
+ inv_length[0] = Vec3fa(1.0f) / (v[1]-v[0]);
+ inv_length[1] = Vec3fa(1.0f) / (v[2]-v[1]);
+ inv_length[2] = Vec3fa(1.0f) / (v[3]-v[2]);
+ inv_length[3] = Vec3fa(1.0f) / (v[0]-v[3]);
+ }
+
+ __forceinline void operator() (const PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const {
+ splitPolygon<4>(prim,dim,pos,v,left_o,right_o);
+ }
+
+ __forceinline void operator() (const BBox3fa& prim, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const {
+ splitPolygon<4>(prim,dim,pos,v,inv_length,left_o,right_o);
+ }
+
+ private:
+ Vec3fa v[5];
+ Vec3fa inv_length[4];
+ };
+
+ struct QuadSplitterFactory
+ {
+ __forceinline QuadSplitterFactory(const Scene* scene)
+ : scene(scene) {}
+
+ __forceinline QuadSplitter operator() (const PrimRef& prim) const {
+ return QuadSplitter(scene,prim);
+ }
+
+ private:
+ const Scene* scene;
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh.cpp
new file mode 100644
index 0000000000..bd102bd6ef
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh.cpp
@@ -0,0 +1,190 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_statistics.h"
+
+namespace embree
+{
+ template<int N>
+ BVHN<N>::BVHN (const PrimitiveType& primTy, Scene* scene)
+ : AccelData((N==4) ? AccelData::TY_BVH4 : (N==8) ? AccelData::TY_BVH8 : AccelData::TY_UNKNOWN),
+ primTy(&primTy), device(scene->device), scene(scene),
+ root(emptyNode), alloc(scene->device,scene->isStaticAccel()), numPrimitives(0), numVertices(0)
+ {
+ }
+
+ template<int N>
+ BVHN<N>::~BVHN ()
+ {
+ for (size_t i=0; i<objects.size(); i++)
+ delete objects[i];
+ }
+
+ template<int N>
+ void BVHN<N>::clear()
+ {
+ set(BVHN::emptyNode,empty,0);
+ alloc.clear();
+ }
+
+ template<int N>
+ void BVHN<N>::set (NodeRef root, const LBBox3fa& bounds, size_t numPrimitives)
+ {
+ this->root = root;
+ this->bounds = bounds;
+ this->numPrimitives = numPrimitives;
+ }
+
+ template<int N>
+ void BVHN<N>::clearBarrier(NodeRef& node)
+ {
+ if (node.isBarrier())
+ node.clearBarrier();
+ else if (!node.isLeaf()) {
+ BaseNode* n = node.baseNode(); // FIXME: flags should be stored in BVH
+ for (size_t c=0; c<N; c++)
+ clearBarrier(n->child(c));
+ }
+ }
+
+ template<int N>
+ void BVHN<N>::layoutLargeNodes(size_t num)
+ {
+#if defined(__X86_64__) || defined(__aarch64__) // do not use tree rotations on 32 bit platforms, barrier bit in NodeRef will cause issues
+ struct NodeArea
+ {
+ __forceinline NodeArea() {}
+
+ __forceinline NodeArea(NodeRef& node, const BBox3fa& bounds)
+ : node(&node), A(node.isLeaf() ? float(neg_inf) : area(bounds)) {}
+
+ __forceinline bool operator< (const NodeArea& other) const {
+ return this->A < other.A;
+ }
+
+ NodeRef* node;
+ float A;
+ };
+ std::vector<NodeArea> lst;
+ lst.reserve(num);
+ lst.push_back(NodeArea(root,empty));
+
+ while (lst.size() < num)
+ {
+ std::pop_heap(lst.begin(), lst.end());
+ NodeArea n = lst.back(); lst.pop_back();
+ if (!n.node->isAABBNode()) break;
+ AABBNode* node = n.node->getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVHN::emptyNode) continue;
+ lst.push_back(NodeArea(node->child(i),node->bounds(i)));
+ std::push_heap(lst.begin(), lst.end());
+ }
+ }
+
+ for (size_t i=0; i<lst.size(); i++)
+ lst[i].node->setBarrier();
+
+ root = layoutLargeNodesRecursion(root,alloc.getCachedAllocator());
+#endif
+ }
+
+ template<int N>
+ typename BVHN<N>::NodeRef BVHN<N>::layoutLargeNodesRecursion(NodeRef& node, const FastAllocator::CachedAllocator& allocator)
+ {
+ if (node.isBarrier()) {
+ node.clearBarrier();
+ return node;
+ }
+ else if (node.isAABBNode())
+ {
+ AABBNode* oldnode = node.getAABBNode();
+ AABBNode* newnode = (BVHN::AABBNode*) allocator.malloc0(sizeof(BVHN::AABBNode),byteNodeAlignment);
+ *newnode = *oldnode;
+ for (size_t c=0; c<N; c++)
+ newnode->child(c) = layoutLargeNodesRecursion(oldnode->child(c),allocator);
+ return encodeNode(newnode);
+ }
+ else return node;
+ }
+
+ template<int N>
+ double BVHN<N>::preBuild(const std::string& builderName)
+ {
+ if (builderName == "")
+ return inf;
+
+ if (device->verbosity(2))
+ {
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "building BVH" << N << (builderName.find("MBlur") != std::string::npos ? "MB" : "") << "<" << primTy->name() << "> using " << builderName << " ..." << std::endl << std::flush;
+ }
+
+ double t0 = 0.0;
+ if (device->benchmark || device->verbosity(2)) t0 = getSeconds();
+ return t0;
+ }
+
+ template<int N>
+ void BVHN<N>::postBuild(double t0)
+ {
+ if (t0 == double(inf))
+ return;
+
+ double dt = 0.0;
+ if (device->benchmark || device->verbosity(2))
+ dt = getSeconds()-t0;
+
+ std::unique_ptr<BVHNStatistics<N>> stat;
+
+ /* print statistics */
+ if (device->verbosity(2))
+ {
+ if (!stat) stat.reset(new BVHNStatistics<N>(this));
+ const size_t usedBytes = alloc.getUsedBytes();
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "finished BVH" << N << "<" << primTy->name() << "> : " << 1000.0f*dt << "ms, " << 1E-6*double(numPrimitives)/dt << " Mprim/s, " << 1E-9*double(usedBytes)/dt << " GB/s" << std::endl;
+
+ if (device->verbosity(2))
+ std::cout << stat->str();
+
+ if (device->verbosity(2))
+ {
+ FastAllocator::AllStatistics stat(&alloc);
+ for (size_t i=0; i<objects.size(); i++)
+ if (objects[i])
+ stat = stat + FastAllocator::AllStatistics(&objects[i]->alloc);
+
+ stat.print(numPrimitives);
+ }
+
+ if (device->verbosity(3))
+ {
+ alloc.print_blocks();
+ for (size_t i=0; i<objects.size(); i++)
+ if (objects[i])
+ objects[i]->alloc.print_blocks();
+ }
+
+ std::cout << std::flush;
+ }
+
+ /* benchmark mode */
+ if (device->benchmark)
+ {
+ if (!stat) stat.reset(new BVHNStatistics<N>(this));
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "BENCHMARK_BUILD " << dt << " " << double(numPrimitives)/dt << " " << stat->sah() << " " << stat->bytesUsed() << " BVH" << N << "<" << primTy->name() << ">" << std::endl << std::flush;
+ }
+ }
+
+#if defined(__AVX__)
+ template class BVHN<8>;
+#endif
+
+#if !defined(__AVX__) || !defined(EMBREE_TARGET_SSE2) && !defined(EMBREE_TARGET_SSE42) || defined(__aarch64__)
+ template class BVHN<4>;
+#endif
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh.h b/thirdparty/embree-aarch64/kernels/bvh/bvh.h
new file mode 100644
index 0000000000..8fdf912e52
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh.h
@@ -0,0 +1,235 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+/* include all node types */
+#include "bvh_node_aabb.h"
+#include "bvh_node_aabb_mb.h"
+#include "bvh_node_aabb_mb4d.h"
+#include "bvh_node_obb.h"
+#include "bvh_node_obb_mb.h"
+#include "bvh_node_qaabb.h"
+
+namespace embree
+{
+ /*! flags used to enable specific node types in intersectors */
+ enum BVHNodeFlags
+ {
+ BVH_FLAG_ALIGNED_NODE = 0x00001,
+ BVH_FLAG_ALIGNED_NODE_MB = 0x00010,
+ BVH_FLAG_UNALIGNED_NODE = 0x00100,
+ BVH_FLAG_UNALIGNED_NODE_MB = 0x01000,
+ BVH_FLAG_QUANTIZED_NODE = 0x100000,
+ BVH_FLAG_ALIGNED_NODE_MB4D = 0x1000000,
+
+ /* short versions */
+ BVH_AN1 = BVH_FLAG_ALIGNED_NODE,
+ BVH_AN2 = BVH_FLAG_ALIGNED_NODE_MB,
+ BVH_AN2_AN4D = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D,
+ BVH_UN1 = BVH_FLAG_UNALIGNED_NODE,
+ BVH_UN2 = BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_MB = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D,
+ BVH_AN1_UN1 = BVH_FLAG_ALIGNED_NODE | BVH_FLAG_UNALIGNED_NODE,
+ BVH_AN2_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_AN2_AN4D_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D | BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_QN1 = BVH_FLAG_QUANTIZED_NODE
+ };
+
+ /*! Multi BVH with N children. Each node stores the bounding box of
+ * it's N children as well as N child references. */
+ template<int N>
+ class BVHN : public AccelData
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ /*! forward declaration of node ref type */
+ typedef NodeRefPtr<N> NodeRef;
+ typedef BaseNode_t<NodeRef,N> BaseNode;
+ typedef AABBNode_t<NodeRef,N> AABBNode;
+ typedef AABBNodeMB_t<NodeRef,N> AABBNodeMB;
+ typedef AABBNodeMB4D_t<NodeRef,N> AABBNodeMB4D;
+ typedef OBBNode_t<NodeRef,N> OBBNode;
+ typedef OBBNodeMB_t<NodeRef,N> OBBNodeMB;
+ typedef QuantizedBaseNode_t<N> QuantizedBaseNode;
+ typedef QuantizedBaseNodeMB_t<N> QuantizedBaseNodeMB;
+ typedef QuantizedNode_t<NodeRef,N> QuantizedNode;
+
+ /*! Number of bytes the nodes and primitives are minimally aligned to.*/
+ static const size_t byteAlignment = 16;
+ static const size_t byteNodeAlignment = 4*N;
+
+ /*! Empty node */
+ static const size_t emptyNode = NodeRef::emptyNode;
+
+ /*! Invalid node, used as marker in traversal */
+ static const size_t invalidNode = NodeRef::invalidNode;
+ static const size_t popRay = NodeRef::popRay;
+
+ /*! Maximum depth of the BVH. */
+ static const size_t maxBuildDepth = 32;
+ static const size_t maxBuildDepthLeaf = maxBuildDepth+8;
+ static const size_t maxDepth = 2*maxBuildDepthLeaf; // 2x because of two level builder
+
+ /*! Maximum number of primitive blocks in a leaf. */
+ static const size_t maxLeafBlocks = NodeRef::maxLeafBlocks;
+
+ public:
+
+ /*! Builder interface to create allocator */
+ struct CreateAlloc : public FastAllocator::Create {
+ __forceinline CreateAlloc (BVHN* bvh) : FastAllocator::Create(&bvh->alloc) {}
+ };
+
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ public:
+
+ /*! BVHN default constructor. */
+ BVHN (const PrimitiveType& primTy, Scene* scene);
+
+ /*! BVHN destruction */
+ ~BVHN ();
+
+ /*! clears the acceleration structure */
+ void clear();
+
+ /*! sets BVH members after build */
+ void set (NodeRef root, const LBBox3fa& bounds, size_t numPrimitives);
+
+ /*! Clears the barrier bits of a subtree. */
+ void clearBarrier(NodeRef& node);
+
+ /*! lays out num large nodes of the BVH */
+ void layoutLargeNodes(size_t num);
+ NodeRef layoutLargeNodesRecursion(NodeRef& node, const FastAllocator::CachedAllocator& allocator);
+
+ /*! called by all builders before build starts */
+ double preBuild(const std::string& builderName);
+
+ /*! called by all builders after build ended */
+ void postBuild(double t0);
+
+ /*! allocator class */
+ struct Allocator {
+ BVHN* bvh;
+ Allocator (BVHN* bvh) : bvh(bvh) {}
+ __forceinline void* operator() (size_t bytes) const {
+ return bvh->alloc._threadLocal()->malloc(&bvh->alloc,bytes);
+ }
+ };
+
+ /*! post build cleanup */
+ void cleanup() {
+ alloc.cleanup();
+ }
+
+ public:
+
+ /*! Encodes a node */
+ static __forceinline NodeRef encodeNode(AABBNode* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(AABBNodeMB* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(AABBNodeMB4D* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(OBBNode* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(OBBNodeMB* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeLeaf(void* tri, size_t num) { return NodeRef::encodeLeaf(tri,num); }
+ static __forceinline NodeRef encodeTypedLeaf(void* ptr, size_t ty) { return NodeRef::encodeTypedLeaf(ptr,ty); }
+
+ public:
+
+ /*! Prefetches the node this reference points to */
+ __forceinline static void prefetch(const NodeRef ref, int types=0)
+ {
+#if defined(__AVX512PF__) // MIC
+ if (types != BVH_FLAG_QUANTIZED_NODE) {
+ prefetchL2(((char*)ref.ptr)+0*64);
+ prefetchL2(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ prefetchL2(((char*)ref.ptr)+2*64);
+ prefetchL2(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ /* KNL still needs L2 prefetches for large nodes */
+ prefetchL2(((char*)ref.ptr)+4*64);
+ prefetchL2(((char*)ref.ptr)+5*64);
+ prefetchL2(((char*)ref.ptr)+6*64);
+ prefetchL2(((char*)ref.ptr)+7*64);
+ }
+ }
+ else
+ {
+ /* todo: reduce if 32bit offsets are enabled */
+ prefetchL2(((char*)ref.ptr)+0*64);
+ prefetchL2(((char*)ref.ptr)+1*64);
+ prefetchL2(((char*)ref.ptr)+2*64);
+ }
+#else
+ if (types != BVH_FLAG_QUANTIZED_NODE) {
+ prefetchL1(((char*)ref.ptr)+0*64);
+ prefetchL1(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ prefetchL1(((char*)ref.ptr)+2*64);
+ prefetchL1(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ /* deactivate for large nodes on Xeon, as it introduces regressions */
+ //prefetchL1(((char*)ref.ptr)+4*64);
+ //prefetchL1(((char*)ref.ptr)+5*64);
+ //prefetchL1(((char*)ref.ptr)+6*64);
+ //prefetchL1(((char*)ref.ptr)+7*64);
+ }
+ }
+ else
+ {
+ /* todo: reduce if 32bit offsets are enabled */
+ prefetchL1(((char*)ref.ptr)+0*64);
+ prefetchL1(((char*)ref.ptr)+1*64);
+ prefetchL1(((char*)ref.ptr)+2*64);
+ }
+#endif
+ }
+
+ __forceinline static void prefetchW(const NodeRef ref, int types=0)
+ {
+ embree::prefetchEX(((char*)ref.ptr)+0*64);
+ embree::prefetchEX(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ embree::prefetchEX(((char*)ref.ptr)+2*64);
+ embree::prefetchEX(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ embree::prefetchEX(((char*)ref.ptr)+4*64);
+ embree::prefetchEX(((char*)ref.ptr)+5*64);
+ embree::prefetchEX(((char*)ref.ptr)+6*64);
+ embree::prefetchEX(((char*)ref.ptr)+7*64);
+ }
+ }
+
+ /*! bvh type information */
+ public:
+ const PrimitiveType* primTy; //!< primitive type stored in the BVH
+
+ /*! bvh data */
+ public:
+ Device* device; //!< device pointer
+ Scene* scene; //!< scene pointer
+ NodeRef root; //!< root node
+ FastAllocator alloc; //!< allocator used to allocate nodes
+
+ /*! statistics data */
+ public:
+ size_t numPrimitives; //!< number of primitives the BVH is build over
+ size_t numVertices; //!< number of vertices the BVH references
+
+ /*! data arrays for special builders */
+ public:
+ std::vector<BVHN*> objects;
+ vector_t<char,aligned_allocator<char,32>> subdiv_patches;
+ };
+
+ typedef BVHN<4> BVH4;
+ typedef BVHN<8> BVH8;
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.cpp
new file mode 100644
index 0000000000..23f4f63d45
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.cpp
@@ -0,0 +1,1325 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh4_factory.h"
+#include "../bvh/bvh.h"
+
+#include "../geometry/curveNv.h"
+#include "../geometry/curveNi.h"
+#include "../geometry/curveNi_mb.h"
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/subdivpatch1.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+#include "../common/accelinstance.h"
+
+namespace embree
+{
+ DECLARE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
+
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4i,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8i,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4iMB,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8iMB,void);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1MB);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1MB);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH4Triangle4iIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH4Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1Intersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1MBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4VirtualIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4VirtualMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1Intersector4);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1MBIntersector4);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4VirtualIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4VirtualMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1Intersector8);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1MBIntersector8);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4VirtualIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4VirtualMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1Intersector16);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1MBIntersector16);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4VirtualIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4VirtualMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4IntersectorStreamPacketFallback);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4OBBCurve4iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve8iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1BuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1MBBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+
+ BVH4Factory::BVH4Factory(int bfeatures, int ifeatures)
+ {
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2(ifeatures,BVH4ColliderUserGeom);
+
+ selectBuilders(bfeatures);
+ selectIntersectors(ifeatures);
+ }
+
+ void BVH4Factory::selectBuilders(int features)
+ {
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelTriangle4MeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelTriangle4iMeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelTriangle4vMeshSAH));
+ IF_ENABLED_QUADS (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelQuadMeshSAH));
+ IF_ENABLED_USER (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelVirtualSAH));
+ IF_ENABLED_INSTANCE (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4BuilderTwoLevelInstanceSAH));
+
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4vBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4iBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4OBBCurve4iMBBuilder_OBB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH4Curve8iBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH4OBBCurve8iMBBuilder_OBB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4Triangle4SceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4Triangle4vSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4Triangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4iMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4vMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4QuantizedTriangle4iSceneBuilderSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4Quad4vSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4Quad4iSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4iMBSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4QuantizedQuad4iSceneBuilderSAH));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4SceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4vSceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4iSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4vSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4VirtualSceneBuilderSAH));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4VirtualMBSceneBuilderSAH));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4InstanceSceneBuilderSAH));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceMBSceneBuilderSAH));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridSceneBuilderSAH));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridMBSceneBuilderSAH));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4SubdivPatch1BuilderSAH));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,BVH4SubdivPatch1MBBuilderSAH));
+ }
+
+ void BVH4Factory::selectIntersectors(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector4i));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector8i));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector4v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector8v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector4iMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector8iMB));
+
+ /* select intersectors1 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector1MB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust1MB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4Intersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,BVH4Triangle4iIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,BVH4Triangle4vIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,BVH4Triangle4iIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector1Moeller));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,QBVH4Triangle4iIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,QBVH4Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1Intersector1));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1MBIntersector1));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4VirtualIntersector1));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4VirtualMBIntersector1));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4InstanceIntersector1));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4InstanceMBIntersector1));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector1Moeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridMBIntersector1Moeller))
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector1Pluecker));
+
+#if defined (EMBREE_RAY_PACKETS)
+
+ /* select intersectors4 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector4HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust4HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4Intersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4Intersector4HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iIntersector4HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector4HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector4HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1Intersector4));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1MBIntersector4));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4VirtualIntersector4Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4VirtualMBIntersector4Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4InstanceIntersector4Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4InstanceMBIntersector4Chunk));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector4HybridMoeller));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridMBIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector4HybridPluecker));
+
+ /* select intersectors8 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersector8HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust8HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4Intersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4Intersector8HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iIntersector8HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4vMBIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Triangle4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector8HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4vIntersector8HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4iIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4Quad4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1Intersector8));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4SubdivPatch1MBIntersector8));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4VirtualIntersector8Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4VirtualMBIntersector8Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4InstanceIntersector8Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4InstanceMBIntersector8Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4GridMBIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH4GridIntersector8HybridPluecker));
+
+ /* select intersectors16 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4OBBVirtualCurveIntersector16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4OBBVirtualCurveIntersector16HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4OBBVirtualCurveIntersectorRobust16HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4Intersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4Intersector16HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4iIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4vIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4iIntersector16HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4vMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4iMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4vMBIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Triangle4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersector16HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4iIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersector16HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4iIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4iMBIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4Quad4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4SubdivPatch1Intersector16));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4SubdivPatch1MBIntersector16));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4VirtualIntersector16Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4VirtualMBIntersector16Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4InstanceIntersector16Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4InstanceMBIntersector16Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4GridIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4GridMBIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH4GridIntersector16HybridPluecker));
+
+ /* select stream intersectors */
+ SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4IntersectorStreamPacketFallback);
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4IntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4IntersectorStreamMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4iIntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4vIntersectorStreamPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Triangle4iIntersectorStreamPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersectorStreamMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Quad4iIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Quad4vIntersectorStreamPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4Quad4iIntersectorStreamPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4VirtualIntersectorStream));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH4InstanceIntersectorStream));
+
+#endif
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4OBBVirtualCurveIntersectors(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4Hybrid();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8Hybrid();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16Hybrid();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersectorRobust1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4Hybrid();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8Hybrid();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16Hybrid();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4OBBVirtualCurveIntersectorsMB(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersector1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4HybridMB();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8HybridMB();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16HybridMB();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersectorRobust1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4HybridMB();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8HybridMB();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16HybridMB();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4Intersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::FAST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4Intersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH4Triangle4Intersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH4Triangle4Intersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH4Triangle4Intersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH4Triangle4Intersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH4Triangle4Intersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH4Triangle4Intersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH4Triangle4IntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH4Triangle4IntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4vIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::ROBUST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Triangle4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4iIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4Triangle4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Triangle4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4vMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4vIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4vIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH4Quad4vIntersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH4Quad4vIntersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH4Quad4vIntersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH4Quad4vIntersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH4Quad4vIntersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH4Quad4vIntersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH4Quad4vIntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH4Quad4vIntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Quad4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Quad4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4iIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Quad4iIntersector8HybridMoeller();
+ intersectors.intersector16= BVH4Quad4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4Quad4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4iIntersector8HybridPluecker();
+ intersectors.intersector16= BVH4Quad4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Quad4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridMoeller();
+ intersectors.intersector16= BVH4Quad4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridPluecker();
+ intersectors.intersector16= BVH4Quad4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::QBVH4Triangle4iIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH4Triangle4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::QBVH4Quad4iIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH4Quad4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4UserGeometryIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4VirtualIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4VirtualIntersector4Chunk();
+ intersectors.intersector8 = BVH4VirtualIntersector8Chunk();
+ intersectors.intersector16 = BVH4VirtualIntersector16Chunk();
+ intersectors.intersectorN = BVH4VirtualIntersectorStream();
+#endif
+ intersectors.collider = BVH4ColliderUserGeom();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4UserGeometryMBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4VirtualMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4VirtualMBIntersector4Chunk();
+ intersectors.intersector8 = BVH4VirtualMBIntersector8Chunk();
+ intersectors.intersector16 = BVH4VirtualMBIntersector16Chunk();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4InstanceIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4InstanceIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4InstanceIntersector4Chunk();
+ intersectors.intersector8 = BVH4InstanceIntersector8Chunk();
+ intersectors.intersector16 = BVH4InstanceIntersector16Chunk();
+ intersectors.intersectorN = BVH4InstanceIntersectorStream();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4InstanceMBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4InstanceMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4InstanceMBIntersector4Chunk();
+ intersectors.intersector8 = BVH4InstanceMBIntersector8Chunk();
+ intersectors.intersector16 = BVH4InstanceMBIntersector16Chunk();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4SubdivPatch1Intersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4SubdivPatch1Intersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4SubdivPatch1Intersector4();
+ intersectors.intersector8 = BVH4SubdivPatch1Intersector8();
+ intersectors.intersector16 = BVH4SubdivPatch1Intersector16();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4SubdivPatch1MBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4SubdivPatch1MBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4SubdivPatch1MBIntersector4();
+ intersectors.intersector8 = BVH4SubdivPatch1MBIntersector8();
+ intersectors.intersector16 = BVH4SubdivPatch1MBIntersector16();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4i(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4i::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector4i(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve4iBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve4iBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+#if defined(EMBREE_TARGET_SIMD8)
+ Accel* BVH4Factory::BVH4OBBVirtualCurve8i(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve8i::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector8i(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve8iBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve8iBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve8i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+#endif
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4v(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4v::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector4v(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve4vBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve4vBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4iMB::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector4iMB(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4OBBCurve4iMBBuilder_OBB(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4OBBCurve4iMBBuilder_OBB(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+#if defined(EMBREE_TARGET_SIMD8)
+ Accel* BVH4Factory::BVH4OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve8iMB::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector8iMB(), ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve8iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+#endif
+
+ Accel* BVH4Factory::BVH4Triangle4(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4Intersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4Intersectors(accel,IntersectVariant::FAST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4SceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4SceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4SceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4v::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4vIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4vIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser == "robust" ) intersectors = BVH4Triangle4vIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4iIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4iIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser == "robust" ) intersectors = BVH4Triangle4iIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4i>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default" ) {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4iSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4iSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser_mb == "default") intersectors = BVH4Triangle4iMBIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser_mb == "fast" ) intersectors = BVH4Triangle4iMBIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser_mb == "robust" ) intersectors = BVH4Triangle4iMBIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser_mb+" for BVH4<Triangle4iMB>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH4Triangle4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH4<Triangle4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4vMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4vMB::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser_mb == "default") intersectors = BVH4Triangle4vMBIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser_mb == "fast" ) intersectors = BVH4Triangle4vMBIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser_mb == "robust" ) intersectors = BVH4Triangle4vMBIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser_mb+" for BVH4<Triangle4vMB>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4vMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH4Triangle4vMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH4<Triangle4vMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4v::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4vIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelQuadMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Quad4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->quad_builder == "sah" ) builder = BVH4Quad4vSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->quad_builder == "sah_fast_spatial" ) builder = BVH4Quad4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->quad_builder == "dynamic" ) builder = BVH4BuilderTwoLevelQuadMeshSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH4<Quad4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else if (scene->device->quad_builder == "sah") builder = BVH4Quad4iSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH4<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->quad_builder_mb == "sah") builder = BVH4Quad4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder_mb+" for BVH4<Quad4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4QuantizedQuad4i(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Builder* builder = BVH4QuantizedQuad4iSceneBuilderSAH(accel,scene,0);
+ Accel::Intersectors intersectors = QBVH4Quad4iIntersectors(accel);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4QuantizedTriangle4i(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+ Builder* builder = BVH4QuantizedTriangle4iSceneBuilderSAH(accel,scene,0);
+ Accel::Intersectors intersectors = QBVH4Triangle4iIntersectors(accel);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4SubdivPatch1(Scene* scene)
+ {
+ BVH4* accel = new BVH4(SubdivPatch1::type,scene);
+ Accel::Intersectors intersectors = BVH4SubdivPatch1Intersectors(accel);
+ Builder* builder = BVH4SubdivPatch1BuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4SubdivPatch1MB(Scene* scene)
+ {
+ BVH4* accel = new BVH4(SubdivPatch1::type,scene);
+ Accel::Intersectors intersectors = BVH4SubdivPatch1MBIntersectors(accel);
+ Builder* builder = BVH4SubdivPatch1MBBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4UserGeometry(Scene* scene, BuildVariant bvariant)
+ {
+ BVH4* accel = new BVH4(Object::type,scene);
+ Accel::Intersectors intersectors = BVH4UserGeometryIntersectors(accel);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4VirtualSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelVirtualSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH4VirtualSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->object_builder == "dynamic") builder = BVH4BuilderTwoLevelVirtualSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4UserGeometryMB(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Object::type,scene);
+ Accel::Intersectors intersectors = BVH4UserGeometryMBIntersectors(accel);
+ Builder* builder = BVH4VirtualMBSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Instance(Scene* scene, bool isExpensive, BuildVariant bvariant)
+ {
+ BVH4* accel = new BVH4(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH4InstanceIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE_CHEAP;
+ // Builder* builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelInstanceSAH(accel,scene,gtype,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype);
+ else if (scene->device->object_builder == "dynamic") builder = BVH4BuilderTwoLevelInstanceSAH(accel,scene,gtype,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4InstanceMB(Scene* scene, bool isExpensive)
+ {
+ BVH4* accel = new BVH4(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH4InstanceMBIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE_CHEAP;
+ Builder* builder = BVH4InstanceMBSceneBuilderSAH(accel,scene,gtype);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4GridIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ if (ivariant == IntersectVariant::FAST)
+ {
+ intersectors.intersector1 = BVH4GridIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4GridIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4GridIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ }
+ else /* if (ivariant == IntersectVariant::ROBUST) */
+ {
+ intersectors.intersector1 = BVH4GridIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4GridIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4GridIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ }
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4GridMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4GridMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4GridMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4GridMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH4Factory::BVH4Grid(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(SubGridQBVH4::type,scene);
+ Accel::Intersectors intersectors = BVH4GridIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ builder = BVH4GridSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->grid_builder+" for BVH4<GridMesh>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4GridMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(SubGridQBVH4::type,scene);
+ Accel::Intersectors intersectors = BVH4GridMBIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ builder = BVH4GridMBSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->grid_builder+" for BVH4MB<GridMesh>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.h b/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.h
new file mode 100644
index 0000000000..a68227b41f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh4_factory.h
@@ -0,0 +1,316 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_factory.h"
+
+namespace embree
+{
+ /*! BVH4 instantiations */
+ class BVH4Factory : public BVHFactory
+ {
+ public:
+ BVH4Factory(int bfeatures, int ifeatures);
+
+ public:
+ Accel* BVH4OBBVirtualCurve4i(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve4v(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve8i(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve4iMB(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4i);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8i);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4iMB);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8iMB);
+
+ Accel* BVH4Triangle4 (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::ROBUST);
+ Accel* BVH4Triangle4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4vMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH4Quad4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Quad4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Quad4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH4QuantizedTriangle4i(Scene* scene);
+ Accel* BVH4QuantizedQuad4i(Scene* scene);
+
+ Accel* BVH4SubdivPatch1(Scene* scene);
+ Accel* BVH4SubdivPatch1MB(Scene* scene);
+
+ Accel* BVH4UserGeometry(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH4UserGeometryMB(Scene* scene);
+
+ Accel* BVH4Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH4InstanceMB(Scene* scene, bool isExpensive);
+
+ Accel* BVH4Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ private:
+ void selectBuilders(int features);
+ void selectIntersectors(int features);
+
+ private:
+ Accel::Intersectors BVH4OBBVirtualCurveIntersectors(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+ Accel::Intersectors BVH4OBBVirtualCurveIntersectorsMB(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH4Triangle4Intersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4vIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4iIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4vMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH4Quad4vIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Quad4iIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Quad4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors QBVH4Quad4iIntersectors(BVH4* bvh);
+ Accel::Intersectors QBVH4Triangle4iIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4UserGeometryIntersectors(BVH4* bvh);
+ Accel::Intersectors BVH4UserGeometryMBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4InstanceIntersectors(BVH4* bvh);
+ Accel::Intersectors BVH4InstanceMBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4SubdivPatch1Intersectors(BVH4* bvh);
+ Accel::Intersectors BVH4SubdivPatch1MBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4GridIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4GridMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ private:
+
+ DEFINE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1MB);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1MB);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH4Triangle4iIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH4Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1Intersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1MBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4VirtualIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4VirtualMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1Intersector4);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1MBIntersector4);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4VirtualIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4VirtualMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1Intersector8);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1MBIntersector8);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4VirtualIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4VirtualMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1Intersector16);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1MBIntersector16);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4VirtualIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4VirtualMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4IntersectorStreamPacketFallback);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream);
+
+ // SAH scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve4iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4OBBCurve4iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve8iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1BuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1MBBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ // spatial scene builder
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ // twolevel scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.cpp
new file mode 100644
index 0000000000..9fe057c392
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.cpp
@@ -0,0 +1,1165 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "../common/isa.h" // to define EMBREE_TARGET_SIMD8
+
+#if defined (EMBREE_TARGET_SIMD8)
+
+#include "bvh8_factory.h"
+#include "../bvh/bvh.h"
+
+#include "../geometry/curveNv.h"
+#include "../geometry/curveNi.h"
+#include "../geometry/curveNi_mb.h"
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/subdivpatch1.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+#include "../common/accelinstance.h"
+
+namespace embree
+{
+ DECLARE_SYMBOL2(Accel::Collider,BVH8ColliderUserGeom);
+
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8iMB,void);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1MB);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1MB);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Woop);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4iIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8VirtualIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8VirtualMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8VirtualIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8VirtualMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8VirtualIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8VirtualMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8VirtualIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8VirtualMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Curve8vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+
+ BVH8Factory::BVH8Factory(int bfeatures, int ifeatures)
+ {
+ SELECT_SYMBOL_INIT_AVX(ifeatures,BVH8ColliderUserGeom);
+
+ selectBuilders(bfeatures);
+ selectIntersectors(ifeatures);
+ }
+
+ void BVH8Factory::selectBuilders(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH8Curve8vBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH8OBBCurve8iMBBuilder_OBB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4SceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4vSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4iMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4vMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedTriangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedTriangle4SceneBuilderSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Quad4vSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Quad4iSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Quad4iMBSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedQuad4iSceneBuilderSAH));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX(features,BVH8VirtualSceneBuilderSAH));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX(features,BVH8VirtualMBSceneBuilderSAH));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceSceneBuilderSAH));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceMBSceneBuilderSAH));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridSceneBuilderSAH));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridMBSceneBuilderSAH));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4SceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Triangle4vSceneBuilderFastSpatialSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8Quad4vSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelTriangle4MeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelTriangle4vMeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelTriangle4iMeshSAH));
+ IF_ENABLED_QUADS (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelQuadMeshSAH));
+ IF_ENABLED_USER (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelVirtualSAH));
+ IF_ENABLED_INSTANCE (SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,BVH8BuilderTwoLevelInstanceSAH));
+ }
+
+ void BVH8Factory::selectIntersectors(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector8v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,VirtualCurveIntersector8iMB));
+
+ /* select intersectors1 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersector1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersector1MB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust1MB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4Intersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4vIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4vIntersector1Woop));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4vMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4vMBIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iMBIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iMBIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iMBIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,QBVH8Triangle4iIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,QBVH8Triangle4Intersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,QBVH8Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8VirtualIntersector1));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8VirtualMBIntersector1));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8InstanceIntersector1));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8InstanceMBIntersector1));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector1Moeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridMBIntersector1Moeller))
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector1Pluecker));
+
+#if defined (EMBREE_RAY_PACKETS)
+
+ /* select intersectors4 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersector4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersector4HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust4HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4Intersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4Intersector4HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iIntersector4HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vMBIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector4HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4iIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector4HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4iIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8VirtualIntersector4Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8VirtualMBIntersector4Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8InstanceIntersector4Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8InstanceMBIntersector4Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector4HybridPluecker));
+
+ /* select intersectors8 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersector8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersector8HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust8HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4Intersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4Intersector8HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iIntersector8HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4vMBIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Triangle4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector8HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4iIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4vIntersector8HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8Quad4iIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8VirtualIntersector8Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8VirtualMBIntersector8Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8InstanceIntersector8Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8InstanceMBIntersector8Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,BVH8GridIntersector8HybridPluecker));
+
+ /* select intersectors16 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersector16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersector16HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8OBBVirtualCurveIntersectorRobust16HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4Intersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4Intersector16HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4vIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersector16HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4vMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4iMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4vMBIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Triangle4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersector16HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersector16HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4iMBIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8Quad4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8VirtualIntersector16Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8VirtualMBIntersector16Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8InstanceIntersector16Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8InstanceMBIntersector16Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8GridIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,BVH8GridIntersector16HybridPluecker));
+
+ /* select stream intersectors */
+
+ SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8IntersectorStreamPacketFallback);
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4IntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4IntersectorStreamMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4vIntersectorStreamPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Triangle4iIntersectorStreamPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersectorStreamMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4vIntersectorStreamPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8Quad4iIntersectorStreamPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8VirtualIntersectorStream));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,BVH8InstanceIntersectorStream));
+
+#endif
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8OBBVirtualCurveIntersectors(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4Hybrid();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8Hybrid();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16Hybrid();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersectorRobust1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4Hybrid();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8Hybrid();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16Hybrid();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8OBBVirtualCurveIntersectorsMB(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersector1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4HybridMB();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8HybridMB();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16HybridMB();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersectorRobust1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4HybridMB();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8HybridMB();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16HybridMB();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4Intersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::FAST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4Intersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH8Triangle4Intersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH8Triangle4Intersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH8Triangle4Intersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH8Triangle4Intersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH8Triangle4Intersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH8Triangle4Intersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH8Triangle4IntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH8Triangle4IntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4vIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+#define ENABLE_WOOP_TEST 0
+#if ENABLE_WOOP_TEST == 0
+ //assert(ivariant == IntersectVariant::ROBUST);
+ intersectors.intersector1 = BVH8Triangle4vIntersector1Pluecker();
+#else
+ intersectors.intersector1 = BVH8Triangle4vIntersector1Woop();
+#endif
+
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Triangle4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4iIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8Triangle4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Triangle4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4vMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4vMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4vMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4vIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4vIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH8Quad4vIntersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH8Quad4vIntersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH8Quad4vIntersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH8Quad4vIntersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH8Quad4vIntersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH8Quad4vIntersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH8Quad4vIntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH8Quad4vIntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Quad4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4iIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Quad4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Quad4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8Quad4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Quad4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Triangle4iIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Triangle4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Triangle4Intersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Triangle4Intersector1Moeller();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Quad4iIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Quad4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8UserGeometryIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8VirtualIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8VirtualIntersector4Chunk();
+ intersectors.intersector8 = BVH8VirtualIntersector8Chunk();
+ intersectors.intersector16 = BVH8VirtualIntersector16Chunk();
+ intersectors.intersectorN = BVH8VirtualIntersectorStream();
+#endif
+ intersectors.collider = BVH8ColliderUserGeom();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8UserGeometryMBIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8VirtualMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8VirtualMBIntersector4Chunk();
+ intersectors.intersector8 = BVH8VirtualMBIntersector8Chunk();
+ intersectors.intersector16 = BVH8VirtualMBIntersector16Chunk();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8InstanceIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8InstanceIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8InstanceIntersector4Chunk();
+ intersectors.intersector8 = BVH8InstanceIntersector8Chunk();
+ intersectors.intersector16 = BVH8InstanceIntersector16Chunk();
+ intersectors.intersectorN = BVH8InstanceIntersectorStream();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8InstanceMBIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8InstanceMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8InstanceMBIntersector4Chunk();
+ intersectors.intersector8 = BVH8InstanceMBIntersector8Chunk();
+ intersectors.intersector16 = BVH8InstanceMBIntersector16Chunk();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH8Factory::BVH8OBBVirtualCurve8v(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Curve8v::type,scene);
+ Accel::Intersectors intersectors = BVH8OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector8v(),ivariant);
+ Builder* builder = BVH8Curve8vBuilder_OBB_New(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Curve8iMB::type,scene);
+ Accel::Intersectors intersectors = BVH8OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector8iMB(),ivariant);
+ Builder* builder = BVH8OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4Intersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial") builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH8Triangle4SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4v::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4vIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah_fast_spatial") builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4v>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Triangle4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Triangle4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") { // FIXME: implement
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH8Triangle4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH8<Triangle4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4vMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4vMB::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4vMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4vMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH8Triangle4vMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH8<Triangle4vMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedTriangle4i(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = QBVH8Triangle4iIntersectors(accel);
+ Builder* builder = BVH8QuantizedTriangle4iSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedTriangle4(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Triangle4::type,scene);
+ Accel::Intersectors intersectors = QBVH8Triangle4Intersectors(accel);
+ Builder* builder = BVH8QuantizedTriangle4SceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4v::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4vIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Quad4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->quad_builder == "dynamic" ) builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,false);
+ else if (scene->device->quad_builder == "morton" ) builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,true);
+ else if (scene->device->quad_builder == "sah_fast_spatial" ) builder = BVH8Quad4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH8<Quad4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH8<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder_mb+" for BVH8<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedQuad4i(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = QBVH8Quad4iIntersectors(accel);
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default" ) builder = BVH8QuantizedQuad4iSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for QBVH8<Quad4i>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8UserGeometry(Scene* scene, BuildVariant bvariant)
+ {
+ BVH8* accel = new BVH8(Object::type,scene);
+ Accel::Intersectors intersectors = BVH8UserGeometryIntersectors(accel);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8VirtualSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelVirtualSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH8VirtualSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->object_builder == "dynamic") builder = BVH8BuilderTwoLevelVirtualSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8UserGeometryMB(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Object::type,scene);
+ Accel::Intersectors intersectors = BVH8UserGeometryMBIntersectors(accel);
+ Builder* builder = BVH8VirtualMBSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Instance(Scene* scene, bool isExpensive, BuildVariant bvariant)
+ {
+ BVH8* accel = new BVH8(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH8InstanceIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE;
+ // Builder* builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);; break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelInstanceSAH(accel,scene,gtype,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);
+ else if (scene->device->object_builder == "dynamic") builder = BVH8BuilderTwoLevelInstanceSAH(accel,scene,gtype,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8InstanceMB(Scene* scene, bool isExpensive)
+ {
+ BVH8* accel = new BVH8(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH8InstanceMBIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE;
+ Builder* builder = BVH8InstanceMBSceneBuilderSAH(accel,scene,gtype);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ if (ivariant == IntersectVariant::FAST)
+ {
+ intersectors.intersector1 = BVH8GridIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8GridIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8GridIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8GridIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ }
+ else /* if (ivariant == IntersectVariant::ROBUST) */
+ {
+ intersectors.intersector1 = BVH8GridIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8GridIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8GridIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8GridIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ }
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8GridMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8GridMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = nullptr;
+ intersectors.intersector8 = nullptr;
+ intersectors.intersector16 = nullptr;
+ intersectors.intersectorN = nullptr;
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH8Factory::BVH8Grid(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(SubGridQBVH8::type,scene);
+ Accel::Intersectors intersectors = BVH8GridIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->grid_builder == "default") {
+ builder = BVH8GridSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<GridMesh>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8GridMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(SubGridQBVH8::type,scene);
+ Accel::Intersectors intersectors = BVH8GridMBIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->grid_builder_mb == "default") {
+ builder = BVH8GridMBSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8MB<GridMesh>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+}
+
+#endif
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.h b/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.h
new file mode 100644
index 0000000000..b92188e7d3
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh8_factory.h
@@ -0,0 +1,280 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_factory.h"
+
+namespace embree
+{
+ /*! BVH8 instantiations */
+ class BVH8Factory : public BVHFactory
+ {
+ public:
+ BVH8Factory(int bfeatures, int ifeatures);
+
+ public:
+ Accel* BVH8OBBVirtualCurve8v(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH8OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8iMB);
+
+ Accel* BVH8Triangle4 (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4vMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH8Quad4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Quad4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Quad4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH8QuantizedTriangle4i(Scene* scene);
+ Accel* BVH8QuantizedTriangle4(Scene* scene);
+ Accel* BVH8QuantizedQuad4i(Scene* scene);
+
+ Accel* BVH8UserGeometry(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH8UserGeometryMB(Scene* scene);
+
+ Accel* BVH8Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH8InstanceMB(Scene* scene, bool isExpensive);
+
+ Accel* BVH8Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ private:
+ void selectBuilders(int features);
+ void selectIntersectors(int features);
+
+ private:
+ Accel::Intersectors BVH8OBBVirtualCurveIntersectors(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+ Accel::Intersectors BVH8OBBVirtualCurveIntersectorsMB(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH8Triangle4Intersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4vIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4iIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4vMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH8Quad4vIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Quad4iIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Quad4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors QBVH8Triangle4iIntersectors(BVH8* bvh);
+ Accel::Intersectors QBVH8Triangle4Intersectors(BVH8* bvh);
+ Accel::Intersectors QBVH8Quad4iIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8UserGeometryIntersectors(BVH8* bvh);
+ Accel::Intersectors BVH8UserGeometryMBIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8InstanceIntersectors(BVH8* bvh);
+ Accel::Intersectors BVH8InstanceMBIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8GridMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ private:
+ DEFINE_SYMBOL2(Accel::Collider,BVH8ColliderUserGeom);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1MB);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1MB);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Woop);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4iIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8VirtualIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8VirtualMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8VirtualIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8VirtualMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8VirtualIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8VirtualMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8VirtualIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8VirtualMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream);
+
+ // SAH scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Curve8vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ // SAH spatial scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ // twolevel scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.cpp
new file mode 100644
index 0000000000..e832537ec5
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.cpp
@@ -0,0 +1,60 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_builder.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ typename BVHN<N>::NodeRef BVHNBuilderVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRef {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRef>
+ (FastAllocator::Create(allocator),typename BVH::AABBNode::Create2(),typename BVH::AABBNode::Set3(allocator,prims),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+
+ template<int N>
+ typename BVHN<N>::NodeRef BVHNBuilderQuantizedVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRef {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRef>
+ (FastAllocator::Create(allocator),typename BVH::QuantizedNode::Create2(),typename BVH::QuantizedNode::Set2(),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+ template<int N>
+ typename BVHN<N>::NodeRecordMB BVHNBuilderMblurVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRecordMB {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (FastAllocator::Create(allocator),typename BVH::AABBNodeMB::Create(),typename BVH::AABBNodeMB::SetTimeRange(timeRange),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+ template struct BVHNBuilderVirtual<4>;
+ template struct BVHNBuilderQuantizedVirtual<4>;
+ template struct BVHNBuilderMblurVirtual<4>;
+
+#if defined(__AVX__)
+ template struct BVHNBuilderVirtual<8>;
+ template struct BVHNBuilderQuantizedVirtual<8>;
+ template struct BVHNBuilderMblurVirtual<8>;
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.h
new file mode 100644
index 0000000000..1b86bb45ad
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder.h
@@ -0,0 +1,114 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "../builders/bvh_builder_sah.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N>
+ struct BVHNBuilderVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRef build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings);
+ virtual NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRef build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings);
+ }
+ };
+
+ template<int N>
+ struct BVHNBuilderQuantizedVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRef build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings);
+ virtual NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRef build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings);
+ }
+ };
+
+ template<int N>
+ struct BVHNBuilderMblurVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRecordMB build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange);
+ virtual NodeRecordMB createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRecordMB createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRecordMB build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings,timeRange);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_morton.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_morton.cpp
new file mode 100644
index 0000000000..64759c1294
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_morton.cpp
@@ -0,0 +1,531 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_statistics.h"
+#include "bvh_rotate.h"
+#include "../common/profile.h"
+#include "../../common/algorithms/parallel_prefix_sum.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/bvh_builder_morton.h"
+
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+#if defined(__X86_64__) || defined(__aarch64__)
+# define ROTATE_TREE 1 // specifies number of tree rotation rounds to perform
+#else
+# define ROTATE_TREE 0 // do not use tree rotations on 32 bit platforms, barrier bit in NodeRef will cause issues
+#endif
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ struct SetBVHNBounds
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+ typedef typename BVH::AABBNode AABBNode;
+
+ BVH* bvh;
+ __forceinline SetBVHNBounds (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRecord operator() (NodeRef ref, const NodeRecord* children, size_t num)
+ {
+ AABBNode* node = ref.getAABBNode();
+
+ BBox3fa res = empty;
+ for (size_t i=0; i<num; i++) {
+ const BBox3fa b = children[i].bounds;
+ res.extend(b);
+ node->setRef(i,children[i].ref);
+ node->setBounds(i,b);
+ }
+
+ BBox3fx result = (BBox3fx&)res;
+#if ROTATE_TREE
+ if (N == 4)
+ {
+ size_t n = 0;
+ for (size_t i=0; i<num; i++)
+ n += children[i].bounds.lower.a;
+
+ if (n >= 4096) {
+ for (size_t i=0; i<num; i++) {
+ if (children[i].bounds.lower.a < 4096) {
+ for (int j=0; j<ROTATE_TREE; j++)
+ BVHNRotate<N>::rotate(node->child(i));
+ node->child(i).setBarrier();
+ }
+ }
+ }
+ result.lower.a = unsigned(n);
+ }
+#endif
+
+ return NodeRecord(ref,result);
+ }
+ };
+
+ template<int N, typename Primitive>
+ struct CreateMortonLeaf;
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4* accel = (Triangle4*) alloc.malloc1(sizeof(Triangle4),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
+ const TriangleMesh* __restrict__ const mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+
+ Triangle4::store_nt(accel,Triangle4(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = unsigned(current.size());
+#endif
+ return NodeRecord(ref,box_o);
+ }
+
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4v>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4v* accel = (Triangle4v*) alloc.malloc1(sizeof(Triangle4v),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
+ const TriangleMesh* __restrict__ mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ Triangle4v::store_nt(accel,Triangle4v(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4i>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4i* accel = (Triangle4i*) alloc.malloc1(sizeof(Triangle4i),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+
+ vuint4 v0 = zero, v1 = zero, v2 = zero;
+ vuint4 vgeomID = -1, vprimID = -1;
+ const TriangleMesh* __restrict__ const mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID[i] = geomID_;
+ vprimID[i] = primID;
+ unsigned int int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = tri.v[0] * int_stride;
+ v1[i] = tri.v[1] * int_stride;
+ v2[i] = tri.v[2] * int_stride;
+ }
+
+ for (size_t i=items; i<4; i++)
+ {
+ vgeomID[i] = vgeomID[0];
+ vprimID[i] = -1;
+ v0[i] = 0;
+ v1[i] = 0;
+ v2[i] = 0;
+ }
+ Triangle4i::store_nt(accel,Triangle4i(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Quad4v>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (QuadMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Quad4v* accel = (Quad4v*) alloc.malloc1(sizeof(Quad4v),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+ const QuadMesh* __restrict__ mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const QuadMesh::Quad& tri = mesh->quad(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ const Vec3fa& p3 = mesh->vertex(tri.v[3]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ Quad4v::store_nt(accel,Quad4v(v0,v1,v2,v3,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ QuadMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Object>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (UserGeometry* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+
+ /* allocate leaf node */
+ Object* accel = (Object*) alloc.malloc1(items*sizeof(Object),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,items);
+ const UserGeometry* mesh = this->mesh;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int index = morton[start+i].index;
+ const unsigned int primID = index;
+ bounds.extend(mesh->bounds(primID));
+ new (&accel[i]) Object(geomID_,primID);
+ }
+
+ BBox3fx box_o = (BBox3fx&)bounds;
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ UserGeometry* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,InstancePrimitive>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (Instance* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items <= 1);
+
+ /* allocate leaf node */
+ InstancePrimitive* accel = (InstancePrimitive*) alloc.malloc1(items*sizeof(InstancePrimitive),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,items);
+ const Instance* instance = this->mesh;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ bounds.extend(instance->bounds(primID));
+ new (&accel[i]) InstancePrimitive(instance, geomID_);
+ }
+
+ BBox3fx box_o = (BBox3fx&)bounds;
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ Instance* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<typename Mesh>
+ struct CalculateMeshBounds
+ {
+ __forceinline CalculateMeshBounds (Mesh* mesh)
+ : mesh(mesh) {}
+
+ __forceinline const BBox3fa operator() (const BVHBuilderMorton::BuildPrim& morton) {
+ return mesh->bounds(morton.index);
+ }
+
+ private:
+ Mesh* mesh;
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNMeshBuilderMorton : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ public:
+
+ BVHNMeshBuilderMorton (BVH* bvh, Mesh* mesh, unsigned int geomID, const size_t minLeafSize, const size_t maxLeafSize, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD)
+ : bvh(bvh), mesh(mesh), morton(bvh->device,0), settings(N,BVH::maxBuildDepth,minLeafSize,min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks),singleThreadThreshold), geomID_(geomID) {}
+
+ /* build function */
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ morton.clear();
+ }
+ size_t numPrimitives = mesh->size();
+ numPreviousPrimitives = numPrimitives;
+
+ /* skip build for empty scene */
+ if (numPrimitives == 0) {
+ bvh->set(BVH::emptyNode,empty,0);
+ return;
+ }
+
+ /* preallocate arrays */
+ morton.resize(numPrimitives);
+ size_t bytesEstimated = numPrimitives*sizeof(AABBNode)/(4*N) + size_t(1.2f*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ size_t bytesMortonCodes = numPrimitives*sizeof(BVHBuilderMorton::BuildPrim);
+ bytesEstimated = max(bytesEstimated,bytesMortonCodes); // the first allocation block is reused to sort the morton codes
+ bvh->alloc.init(bytesMortonCodes,bytesMortonCodes,bytesEstimated);
+
+ /* create morton code array */
+ BVHBuilderMorton::BuildPrim* dest = (BVHBuilderMorton::BuildPrim*) bvh->alloc.specialAlloc(bytesMortonCodes);
+ size_t numPrimitivesGen = createMortonCodeArray<Mesh>(mesh,morton,bvh->scene->progressInterface);
+
+ /* create BVH */
+ SetBVHNBounds<N> setBounds(bvh);
+ CreateMortonLeaf<N,Primitive> createLeaf(mesh,geomID_,morton.data());
+ CalculateMeshBounds<Mesh> calculateBounds(mesh);
+ auto root = BVHBuilderMorton::build<NodeRecord>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create(),
+ setBounds,createLeaf,calculateBounds,bvh->scene->progressInterface,
+ morton.data(),dest,numPrimitivesGen,settings);
+
+ bvh->set(root.ref,LBBox3fa(root.bounds),numPrimitives);
+
+#if ROTATE_TREE
+ if (N == 4)
+ {
+ for (int i=0; i<ROTATE_TREE; i++)
+ BVHNRotate<N>::rotate(bvh->root);
+ bvh->clearBarrier(bvh->root);
+ }
+#endif
+
+ /* clear temporary data for static geometry */
+ if (bvh->scene->isStaticAccel()) {
+ morton.clear();
+ }
+ bvh->cleanup();
+ }
+
+ void clear() {
+ morton.clear();
+ }
+
+ private:
+ BVH* bvh;
+ Mesh* mesh;
+ mvector<BVHBuilderMorton::BuildPrim> morton;
+ BVHBuilderMorton::Settings settings;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+ };
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4> ((BVH4*)bvh,mesh,geomID,4,4); }
+ Builder* BVH4Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4v>((BVH4*)bvh,mesh,geomID,4,4); }
+ Builder* BVH4Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4i>((BVH4*)bvh,mesh,geomID,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4> ((BVH8*)bvh,mesh,geomID,4,4); }
+ Builder* BVH8Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4v>((BVH8*)bvh,mesh,geomID,4,4); }
+ Builder* BVH8Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4i>((BVH8*)bvh,mesh,geomID,4,4); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,QuadMesh,Quad4v>((BVH4*)bvh,mesh,geomID,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,QuadMesh,Quad4v>((BVH8*)bvh,mesh,geomID,4,4); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,UserGeometry,Object>((BVH4*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
+#if defined(__AVX__)
+ Builder* BVH8VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,UserGeometry,Object>((BVH8*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,Instance,InstancePrimitive>((BVH4*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
+#if defined(__AVX__)
+ Builder* BVH8InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,Instance,InstancePrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
+#endif
+#endif
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah.cpp
new file mode 100644
index 0000000000..cf5b2eb47f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah.cpp
@@ -0,0 +1,640 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+#include "../builders/primrefgen.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+#define PROFILE 0
+#define PROFILE_RUNS 20
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Primitive>
+ struct CreateLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeaf (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+
+ template<int N, typename Primitive>
+ struct CreateLeafQuantized
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafQuantized (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N, typename Primitive>
+ struct BVHNBuilderSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ Geometry* mesh;
+ mvector<PrimRef> prims;
+ GeneralBVHBuilder::Settings settings;
+ Geometry::GTypeMask gtype_;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max ();
+ bool primrefarrayalloc;
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize,
+ const Geometry::GTypeMask gtype, bool primrefarrayalloc = false)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0),
+ settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), primrefarrayalloc(primrefarrayalloc) {}
+
+ BVHNBuilderSAH (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID), primrefarrayalloc(false) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* if we use the primrefarray for allocations we have to take it back from the BVH */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.unshare(prims);
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(gtype_,false);
+ numPreviousPrimitives = numPrimitives;
+ if (numPrimitives == 0) {
+ bvh->clear();
+ prims.clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + "BuilderSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+
+ /* create primref array */
+ if (primrefarrayalloc) {
+ settings.primrefarrayalloc = numPrimitives/1000;
+ if (settings.primrefarrayalloc < 1000)
+ settings.primrefarrayalloc = inf;
+ }
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* initialize allocator */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+ prims.resize(numPrimitives);
+
+ PrimInfo pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,prims,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,gtype_,false,prims,bvh->scene->progressInterface);
+
+ /* pinfo might has zero size due to invalid geometry */
+ if (unlikely(pinfo.size() == 0))
+ {
+ bvh->clear();
+ prims.clear();
+ return;
+ }
+
+ /* call BVH builder */
+ NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeaf<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+#if PROFILE
+ });
+#endif
+
+ /* if we allocated using the primrefarray we have to keep it alive */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.share(prims);
+
+ /* for static geometries we can do some cleanups */
+ else if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N, typename Primitive>
+ struct BVHNBuilderSAHQuantized : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ Geometry* mesh;
+ mvector<PrimRef> prims;
+ GeneralBVHBuilder::Settings settings;
+ Geometry::GTypeMask gtype_;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAHQuantized (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype) {}
+
+ BVHNBuilderSAHQuantized (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(gtype_,false);
+ numPreviousPrimitives = numPrimitives;
+ if (numPrimitives == 0) {
+ prims.clear();
+ bvh->clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::QBVH" + toString(N) + "BuilderSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+ /* create primref array */
+ prims.resize(numPrimitives);
+ PrimInfo pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,prims,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,gtype_,false,prims,bvh->scene->progressInterface);
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* call BVH builder */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::QuantizedNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+ NodeRef root = BVHNBuilderQuantizedVirtual<N>::build(&bvh->alloc,CreateLeafQuantized<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ //bvh->layoutLargeNodes(pinfo.size()*0.005f); // FIXME: COPY LAYOUT FOR LARGE NODES !!!
+#if PROFILE
+ });
+#endif
+
+ /* clear temporary data for static geometry */
+ if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+
+ template<int N, typename Primitive>
+ struct CreateLeafGrid
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafGrid (BVH* bvh, const SubGridBuildData * const sgrids) : bvh(bvh),sgrids(sgrids) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = set.size(); //Primitive::blocks(n);
+ const size_t start = set.begin();
+
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridQBVHN<N>* accel = (SubGridQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,num_geomIDs);
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData& sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ bounds[pos] = prims[start+i].bounds();
+ pos++;
+ }
+ assert(pos <= N);
+ new (&accel[g]) SubGridQBVHN<N>(x,y,primID,bounds,geomIDs[g],pos);
+ }
+
+ return node;
+ }
+
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+
+
+ template<int N>
+ struct BVHNBuilderSAHGrid : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ GridMesh* mesh;
+ mvector<PrimRef> prims;
+ mvector<SubGridBuildData> sgrids;
+ GeneralBVHBuilder::Settings settings;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD) {}
+
+ BVHNBuilderSAHGrid (BVH* bvh, GridMesh* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), geomID_(geomID) {}
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* if we use the primrefarray for allocations we have to take it back from the BVH */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.unshare(prims);
+
+ const size_t numGridPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(GridMesh::geom_type,false);
+ numPreviousPrimitives = numGridPrimitives;
+
+ PrimInfo pinfo(empty);
+ size_t numPrimitives = 0;
+
+ if (!mesh)
+ {
+ /* first run to get #primitives */
+
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator<GridMesh,false> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+
+ /* iterate over all meshes in the scene */
+ pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,(unsigned)geomID,(unsigned)j);
+ if (!mesh->valid(j)) continue;
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ numPrimitives = pinfo.size();
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ k = base.size();
+ size_t p_index = k;
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,(unsigned)geomID,(unsigned)p_index);
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ assert(pinfo.size() == numPrimitives);
+ }
+ else
+ {
+ ParallelPrefixSumState<PrimInfo> pstate;
+ /* iterate over all grids in a single mesh */
+ pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,geomID_,unsigned(j));
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ numPrimitives = pinfo.size();
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo
+ {
+
+ size_t p_index = base.size();
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,geomID_,unsigned(p_index));
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ }
+
+ /* no primitives */
+ if (numPrimitives == 0) {
+ bvh->clear();
+ prims.clear();
+ sgrids.clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + "BuilderSAH");
+
+ /* create primref array */
+ settings.primrefarrayalloc = numPrimitives/1000;
+ if (settings.primrefarrayalloc < 1000)
+ settings.primrefarrayalloc = inf;
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* initialize allocator */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+
+ /* pinfo might has zero size due to invalid geometry */
+ if (unlikely(pinfo.size() == 0))
+ {
+ bvh->clear();
+ sgrids.clear();
+ prims.clear();
+ return;
+ }
+
+ /* call BVH builder */
+ NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeafGrid<N,SubGridQBVHN<N>>(bvh,sgrids.data()),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+ /* clear temporary array */
+ sgrids.clear();
+
+ /* if we allocated using the primrefarray we have to keep it alive */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.share(prims);
+
+ /* for static geometries we can do some cleanups */
+ else if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+ Builder* BVH4Triangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); }
+
+
+ Builder* BVH4QuantizedTriangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+ Builder* BVH8Triangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); }
+ Builder* BVH8QuantizedTriangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8QuantizedTriangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4iMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); }
+ Builder* BVH4QuantizedQuad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4QuantizedQuad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8Quad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); }
+ Builder* BVH8QuantizedQuad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8QuantizedQuad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+
+ Builder* BVH4VirtualSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_max_leaf_size;
+ return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type);
+ }
+
+ Builder* BVH4VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,UserGeometry::geom_type);
+ }
+#if defined(__AVX__)
+
+ Builder* BVH8VirtualSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_max_leaf_size;
+ return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type);
+ }
+
+ Builder* BVH8VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,UserGeometry::geom_type);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); }
+ Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,gtype);
+ }
+#if defined(__AVX__)
+ Builder* BVH8InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); }
+ Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,gtype);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ Builder* BVH4GridMeshBuilderSAH (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,4,mode); }
+ Builder* BVH4GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4,mode); } // FIXME: check whether cost factors are correct
+
+#if defined(__AVX__)
+ Builder* BVH8GridMeshBuilderSAH (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,mesh,geomID,8,1.0f,8,8,mode); }
+ Builder* BVH8GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8,mode); } // FIXME: check whether cost factors are correct
+#endif
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_mb.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_mb.cpp
new file mode 100644
index 0000000000..9c01553ec6
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_mb.cpp
@@ -0,0 +1,705 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+#include "../builders/bvh_builder_msmblur.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+
+// FIXME: remove after removing BVHNBuilderMBlurRootTimeSplitsSAH
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+
+namespace embree
+{
+ namespace isa
+ {
+
+#if 0
+ template<int N, typename Primitive>
+ struct CreateMBlurLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+
+ __forceinline CreateMBlurLeaf (BVH* bvh, PrimRef* prims, size_t time) : bvh(bvh), prims(prims), time(time) {}
+
+ __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t items = Primitive::blocks(set.size());
+ size_t start = set.begin();
+ for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ NodeRef node = bvh->encodeLeaf((char*)accel,items);
+
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<items; i++)
+ allBounds.extend(accel[i].fillMB(prims, start, set.end(), bvh->scene, time));
+
+ return NodeRecordMB(node,allBounds);
+ }
+
+ BVH* bvh;
+ PrimRef* prims;
+ size_t time;
+ };
+#endif
+
+ template<int N, typename Mesh, typename Primitive>
+ struct CreateMSMBlurLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB4D NodeRecordMB4D;
+
+ __forceinline CreateMSMBlurLeaf (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t items = Primitive::blocks(current.prims.size());
+ size_t start = current.prims.begin();
+ size_t end = current.prims.end();
+ for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteNodeAlignment);
+ NodeRef node = bvh->encodeLeaf((char*)accel,items);
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<items; i++)
+ allBounds.extend(accel[i].fillMB(current.prims.prims->data(), start, current.prims.end(), bvh->scene, current.prims.time_range));
+ return NodeRecordMB4D(node,allBounds,current.prims.time_range);
+ }
+
+ BVH* bvh;
+ };
+
+ /* Motion blur BVH with 4D nodes and internal time splits */
+ template<int N, typename Mesh, typename Primitive>
+ struct BVHNBuilderMBlurSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+ typedef typename BVHN<N>::NodeRecordMB NodeRecordMB;
+ typedef typename BVHN<N>::AABBNodeMB AABBNodeMB;
+
+ BVH* bvh;
+ Scene* scene;
+ const size_t sahBlockSize;
+ const float intCost;
+ const size_t minLeafSize;
+ const size_t maxLeafSize;
+ const Geometry::GTypeMask gtype_;
+
+ BVHNBuilderMBlurSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks)), gtype_(gtype) {}
+
+ void build()
+ {
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(gtype_,true);
+ if (numPrimitives == 0) { bvh->clear(); return; }
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderMBlurSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+
+ //const size_t numTimeSteps = scene->getNumTimeSteps<typename Mesh::type_t,true>();
+ //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1);
+
+ /*if (numTimeSegments == 1)
+ buildSingleSegment(numPrimitives);
+ else*/
+ buildMultiSegment(numPrimitives);
+
+#if PROFILE
+ });
+#endif
+
+ /* clear temporary data for static geometry */
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+#if 0 // No longer compatible when time_ranges are present for geometries. Would have to create temporal nodes sometimes, and put only a single geometry into leaf.
+ void buildSingleSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRef> prims(scene->device,numPrimitives);
+ const PrimInfo pinfo = createPrimRefArrayMBlur(scene,gtype_,prims,bvh->scene->progressInterface,0);
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root = BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (typename BVH::CreateAlloc(bvh),typename BVH::AABBNodeMB::Create(),typename BVH::AABBNodeMB::Set(),
+ CreateMBlurLeaf<N,Primitive>(bvh,prims.data(),0),bvh->scene->progressInterface,
+ prims.data(),pinfo,settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.size());
+ }
+#endif
+
+ void buildMultiSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRefMB> prims(scene->device,numPrimitives);
+ PrimInfoMB pinfo = createPrimRefArrayMSMBlur(scene,gtype_,prims,bvh->scene->progressInterface);
+
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ BVHBuilderMSMBlur::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxDepth;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleLeafTimeSegment = Primitive::singleTimeSegment;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root =
+ BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device,
+ RecalculatePrimRef<Mesh>(scene),
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB4D::Create(),
+ typename BVH::AABBNodeMB4D::Set(),
+ CreateMSMBlurLeaf<N,Mesh,Primitive>(bvh),
+ bvh->scene->progressInterface,
+ settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.num_time_segments);
+ }
+
+ void clear() {
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ struct GridRecalculatePrimRef
+ {
+ Scene* scene;
+ const SubGridBuildData * const sgrids;
+
+ __forceinline GridRecalculatePrimRef (Scene* scene, const SubGridBuildData * const sgrids)
+ : scene(scene), sgrids(sgrids) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned int geomID = prim.geomID();
+ const GridMesh* mesh = scene->get<GridMesh>(geomID);
+ const unsigned int buildID = prim.primID();
+ const SubGridBuildData &subgrid = sgrids[buildID];
+ const unsigned int primID = subgrid.primID;
+ const size_t x = subgrid.x();
+ const size_t y = subgrid.y();
+ const LBBox3fa lbounds = mesh->linearBounds(mesh->grid(primID),x,y,time_range);
+ const unsigned num_time_segments = mesh->numTimeSegments();
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, num_time_segments, geomID, buildID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ const unsigned int geomID = prim.geomID();
+ const GridMesh* mesh = scene->get<GridMesh>(geomID);
+ const unsigned int buildID = prim.primID();
+ const SubGridBuildData &subgrid = sgrids[buildID];
+ const unsigned int primID = subgrid.primID;
+ const size_t x = subgrid.x();
+ const size_t y = subgrid.y();
+ return mesh->linearBounds(mesh->grid(primID),x,y,time_range);
+ }
+
+ };
+
+ template<int N>
+ struct CreateMSMBlurLeafGrid
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB4D NodeRecordMB4D;
+
+ __forceinline CreateMSMBlurLeafGrid (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids) : scene(scene), bvh(bvh), sgrids(sgrids) {}
+
+ __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = current.prims.size();
+ const size_t start = current.prims.begin();
+
+ const PrimRefMB* prims = current.prims.prims->data();
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridMBQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs);
+
+ LBBox3fa allBounds = empty;
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]);
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds0[N];
+ BBox3fa bounds1[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ const size_t x = sgrid_bd.x();
+ const size_t y = sgrid_bd.y();
+ LBBox3fa newBounds = mesh->linearBounds(mesh->grid(sgrid_bd.primID),x,y,current.prims.time_range);
+ allBounds.extend(newBounds);
+ bounds0[pos] = newBounds.bounds0;
+ bounds1[pos] = newBounds.bounds1;
+ pos++;
+ }
+ assert(pos <= N);
+ new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],current.prims.time_range.lower,1.0f/current.prims.time_range.size(),pos);
+ }
+ return NodeRecordMB4D(node,allBounds,current.prims.time_range);
+ }
+
+ Scene *scene;
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+
+#if 0
+ template<int N>
+ struct CreateLeafGridMB
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+
+ __forceinline CreateLeafGridMB (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids)
+ : scene(scene), bvh(bvh), sgrids(sgrids) {}
+
+ __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = set.size();
+ const size_t start = set.begin();
+
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridMBQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs);
+
+ LBBox3fa allBounds = empty;
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]);
+
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds0[N];
+ BBox3fa bounds1[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ const size_t x = sgrid_bd.x();
+ const size_t y = sgrid_bd.y();
+ bool MAYBE_UNUSED valid0 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,0,bounds0[pos]);
+ bool MAYBE_UNUSED valid1 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,1,bounds1[pos]);
+ assert(valid0);
+ assert(valid1);
+ allBounds.extend(LBBox3fa(bounds0[pos],bounds1[pos]));
+ pos++;
+ }
+ new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],0.0f,1.0f,pos);
+ }
+ return NodeRecordMB(node,allBounds);
+ }
+
+ Scene *scene;
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+#endif
+
+
+ /* Motion blur BVH with 4D nodes and internal time splits */
+ template<int N>
+ struct BVHNBuilderMBlurSAHGrid : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+ typedef typename BVHN<N>::NodeRecordMB NodeRecordMB;
+ typedef typename BVHN<N>::AABBNodeMB AABBNodeMB;
+
+ BVH* bvh;
+ Scene* scene;
+ const size_t sahBlockSize;
+ const float intCost;
+ const size_t minLeafSize;
+ const size_t maxLeafSize;
+ mvector<SubGridBuildData> sgrids;
+
+
+ BVHNBuilderMBlurSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize)
+ : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,BVH::maxLeafBlocks)), sgrids(scene->device,0) {}
+
+
+ PrimInfo createPrimRefArrayMBlurGrid(Scene* scene, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime)
+ {
+ /* first run to get #primitives */
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator<GridMesh,true> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+
+ /* iterate over all meshes in the scene */
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j,range<size_t>(0,1))) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,unsigned(geomID),unsigned(j));
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ size_t numPrimitives = pinfo.size();
+ if (numPrimitives == 0) return pinfo;
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+
+ k = base.size();
+ size_t p_index = k;
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ const GridMesh::Grid &g = mesh->grid(j);
+ if (!mesh->valid(j,range<size_t>(0,1))) continue;
+
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,itime,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,unsigned(geomID),unsigned(p_index));
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ assert(pinfo.size() == numPrimitives);
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefArrayMSMBlurGrid(Scene* scene, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f))
+ {
+ /* first run to get #primitives */
+ ParallelForForPrefixSumState<PrimInfoMB> pstate;
+ Scene::Iterator<GridMesh,true> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+ /* iterate over all meshes in the scene */
+ PrimInfoMB pinfoMB = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t /*geomID*/) -> PrimInfoMB {
+
+ PrimInfoMB pinfoMB(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j, mesh->timeSegmentRange(t0t1))) continue;
+ LBBox3fa bounds(empty);
+ PrimInfoMB gridMB(0,mesh->getNumSubGrids(j));
+ pinfoMB.merge(gridMB);
+ }
+ return pinfoMB;
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ size_t numPrimitives = pinfoMB.size();
+ if (numPrimitives == 0) return pinfoMB;
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfoMB = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB {
+
+ k = base.size();
+ size_t p_index = k;
+ PrimInfoMB pinfoMB(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j, mesh->timeSegmentRange(t0t1))) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ const PrimRefMB prim(mesh->linearBounds(g,x,y,t0t1),mesh->numTimeSegments(),mesh->time_range,mesh->numTimeSegments(),unsigned(geomID),unsigned(p_index));
+ pinfoMB.add_primref(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfoMB;
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ assert(pinfoMB.size() == numPrimitives);
+ pinfoMB.time_range = t0t1;
+ return pinfoMB;
+ }
+
+ void build()
+ {
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(GridMesh::geom_type,true);
+ if (numPrimitives == 0) { bvh->clear(); return; }
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderMBlurSAHGrid");
+
+ //const size_t numTimeSteps = scene->getNumTimeSteps<GridMesh,true>();
+ //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1);
+ //if (numTimeSegments == 1)
+ // buildSingleSegment(numPrimitives);
+ //else
+ buildMultiSegment(numPrimitives);
+
+ /* clear temporary data for static geometry */
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+#if 0
+ void buildSingleSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRef> prims(scene->device,numPrimitives);
+ const PrimInfo pinfo = createPrimRefArrayMBlurGrid(scene,prims,bvh->scene->progressInterface,0);
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N);
+ //TODO: check leaf_bytes
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root = BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB::Create(),
+ typename BVH::AABBNodeMB::Set(),
+ CreateLeafGridMB<N>(scene,bvh,sgrids.data()),
+ bvh->scene->progressInterface,
+ prims.data(),pinfo,settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.size());
+ }
+#endif
+
+ void buildMultiSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRefMB> prims(scene->device,numPrimitives);
+ PrimInfoMB pinfo = createPrimRefArrayMSMBlurGrid(scene,prims,bvh->scene->progressInterface);
+
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+
+
+ GridRecalculatePrimRef recalculatePrimRef(scene,sgrids.data());
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N);
+ //FIXME: check leaf_bytes
+ //const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(SubGridQBVHN<N>));
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ BVHBuilderMSMBlur::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxDepth;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleLeafTimeSegment = false;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root =
+ BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device,
+ recalculatePrimRef,
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB4D::Create(),
+ typename BVH::AABBNodeMB4D::Set(),
+ CreateMSMBlurLeafGrid<N>(scene,bvh,sgrids.data()),
+ bvh->scene->progressInterface,
+ settings);
+ bvh->set(root.ref,root.lbounds,pinfo.num_time_segments);
+ }
+
+ void clear() {
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+ Builder* BVH4Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4vMB>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+ Builder* BVH8Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4vMB>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,QuadMesh,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); }
+#if defined(__AVX__)
+ Builder* BVH8Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,QuadMesh,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_mb_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_mb_max_leaf_size;
+ return new BVHNBuilderMBlurSAH<4,UserGeometry,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY);
+ }
+#if defined(__AVX__)
+ Builder* BVH8VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_mb_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_mb_max_leaf_size;
+ return new BVHNBuilderMBlurSAH<8,UserGeometry,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); }
+#if defined(__AVX__)
+ Builder* BVH8InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ Builder* BVH4GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8); }
+#endif
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_spatial.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_spatial.cpp
new file mode 100644
index 0000000000..285b38c39d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_sah_spatial.cpp
@@ -0,0 +1,201 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/primrefgen_presplit.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Primitive>
+ struct CreateLeafSpatial
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafSpatial (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+ template<int N, typename Mesh, typename Primitive, typename Splitter>
+ struct BVHNBuilderFastSpatialSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ BVH* bvh;
+ Scene* scene;
+ Mesh* mesh;
+ mvector<PrimRef> prims0;
+ GeneralBVHBuilder::Settings settings;
+ const float splitFactor;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderFastSpatialSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims0(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD),
+ splitFactor(scene->device->max_spatial_split_replications) {}
+
+ BVHNBuilderFastSpatialSAH (BVH* bvh, Mesh* mesh, const unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims0(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD),
+ splitFactor(scene->device->max_spatial_split_replications), geomID_(geomID) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* skip build for empty scene */
+ const size_t numOriginalPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(Mesh::geom_type,false);
+ numPreviousPrimitives = numOriginalPrimitives;
+ if (numOriginalPrimitives == 0) {
+ prims0.clear();
+ bvh->clear();
+ return;
+ }
+
+ const unsigned int maxGeomID = mesh ? geomID_ : scene->getMaxGeomID<Mesh,false>();
+ const bool usePreSplits = scene->device->useSpatialPreSplits || (maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)));
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + (usePreSplits ? "BuilderFastSpatialPresplitSAH" : "BuilderFastSpatialSAH"));
+
+ /* create primref array */
+ const size_t numSplitPrimitives = max(numOriginalPrimitives,size_t(splitFactor*numOriginalPrimitives));
+ prims0.resize(numSplitPrimitives);
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ NodeRef root(0);
+ PrimInfo pinfo;
+
+
+ if (likely(usePreSplits))
+ {
+ /* spatial presplit SAH BVH builder */
+ pinfo = mesh ?
+ createPrimRefArray_presplit<Mesh,Splitter>(mesh,maxGeomID,numOriginalPrimitives,prims0,bvh->scene->progressInterface) :
+ createPrimRefArray_presplit<Mesh,Splitter>(scene,Mesh::geom_type,false,numOriginalPrimitives,prims0,bvh->scene->progressInterface);
+
+ const size_t node_bytes = pinfo.size()*sizeof(typename BVH::AABBNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+
+ /* call BVH builder */
+ root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeafSpatial<N,Primitive>(bvh),bvh->scene->progressInterface,prims0.data(),pinfo,settings);
+ }
+ else
+ {
+ /* standard spatial split SAH BVH builder */
+ pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,/*numSplitPrimitives,*/prims0,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,Mesh::geom_type,false,/*numSplitPrimitives,*/prims0,bvh->scene->progressInterface);
+
+ Splitter splitter(scene);
+
+ const size_t node_bytes = pinfo.size()*sizeof(typename BVH::AABBNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+
+ /* call BVH builder */
+ root = BVHBuilderBinnedFastSpatialSAH::build<NodeRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+ CreateLeafSpatial<N,Primitive>(bvh),
+ splitter,
+ bvh->scene->progressInterface,
+ prims0.data(),
+ numSplitPrimitives,
+ pinfo,settings);
+
+ /* ==================== */
+ }
+
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+ /* clear temporary data for static geometry */
+ if (scene && scene->isStaticAccel()) {
+ prims0.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims0.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+
+ Builder* BVH4Triangle4SceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH4Triangle4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4v,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH4Triangle4iSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4i,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Triangle4SceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,TriangleMesh,Triangle4,TriangleSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH8Triangle4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,TriangleMesh,Triangle4v,TriangleSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,QuadMesh,Quad4v,QuadSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,QuadMesh,Quad4v,QuadSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+#endif
+
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.cpp
new file mode 100644
index 0000000000..1a78f347ac
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.cpp
@@ -0,0 +1,377 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_builder_twolevel.h"
+#include "bvh_statistics.h"
+#include "../builders/bvh_builder_sah.h"
+#include "../common/scene_line_segments.h"
+#include "../common/scene_triangle_mesh.h"
+#include "../common/scene_quad_mesh.h"
+
+#define PROFILE 0
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Mesh, typename Primitive>
+ BVHNBuilderTwoLevel<N,Mesh,Primitive>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder, const size_t singleThreadThreshold)
+ : bvh(bvh), scene(scene), refs(scene->device,0), prims(scene->device,0), singleThreadThreshold(singleThreadThreshold), gtype(gtype), useMortonBuilder_(useMortonBuilder) {}
+
+ template<int N, typename Mesh, typename Primitive>
+ BVHNBuilderTwoLevel<N,Mesh,Primitive>::~BVHNBuilderTwoLevel () {
+ }
+
+ // ===========================================================================
+ // ===========================================================================
+ // ===========================================================================
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::build()
+ {
+ /* delete some objects */
+ size_t num = scene->size();
+ if (num < bvh->objects.size()) {
+ parallel_for(num, bvh->objects.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ builders[i].reset();
+ delete bvh->objects[i]; bvh->objects[i] = nullptr;
+ }
+ });
+ }
+
+#if PROFILE
+ while(1)
+#endif
+ {
+ /* reset memory allocator */
+ bvh->alloc.reset();
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(gtype,false);
+
+ if (numPrimitives == 0) {
+ prims.resize(0);
+ bvh->set(BVH::emptyNode,empty,0);
+ return;
+ }
+
+ /* calculate the size of the entire BVH */
+ const size_t numLeafBlocks = Primitive::blocks(numPrimitives);
+ const size_t node_bytes = 2*numLeafBlocks*sizeof(typename BVH::AABBNode)/N;
+ const size_t leaf_bytes = size_t(1.2*numLeafBlocks*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderTwoLevel");
+
+ /* resize object array if scene got larger */
+ if (bvh->objects.size() < num) bvh->objects.resize(num);
+ if (builders.size() < num) builders.resize(num);
+ resizeRefsList ();
+ nextRef.store(0);
+
+ /* create acceleration structures */
+ parallel_for(size_t(0), num, [&] (const range<size_t>& r)
+ {
+ for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
+ {
+ Mesh* mesh = scene->getSafe<Mesh>(objectID);
+
+ /* ignore meshes we do not support */
+ if (mesh == nullptr || mesh->numTimeSteps != 1)
+ continue;
+
+ if (isSmallGeometry(mesh)) {
+ setupSmallBuildRefBuilder (objectID, mesh);
+ } else {
+ setupLargeBuildRefBuilder (objectID, mesh);
+ }
+ }
+ });
+
+ /* parallel build of acceleration structures */
+ parallel_for(size_t(0), num, [&] (const range<size_t>& r)
+ {
+ for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
+ {
+ /* ignore if no triangle mesh or not enabled */
+ Mesh* mesh = scene->getSafe<Mesh>(objectID);
+ if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1)
+ continue;
+
+ builders[objectID]->attachBuildRefs (this);
+ }
+ });
+
+
+#if PROFILE
+ double d0 = getSeconds();
+#endif
+ /* fast path for single geometry scenes */
+ if (nextRef == 1) {
+ bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);
+ }
+
+ else
+ {
+ /* open all large nodes */
+ refs.resize(nextRef);
+
+ /* this probably needs some more tuning */
+ const size_t extSize = max(max((size_t)SPLIT_MIN_EXT_SPACE,refs.size()*SPLIT_MEMORY_RESERVE_SCALE),size_t((float)numPrimitives / SPLIT_MEMORY_RESERVE_FACTOR));
+
+#if !ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+#if ENABLE_OPEN_SEQUENTIAL
+ open_sequential(extSize);
+#endif
+ /* compute PrimRefs */
+ prims.resize(refs.size());
+#endif
+
+#if defined(TASKING_TBB) && defined(__AVX512ER__) && USE_TASK_ARENA // KNL
+ tbb::task_arena limited(min(32,(int)TaskScheduler::threadCount()));
+ limited.execute([&]
+#endif
+ {
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+ const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ pinfo.add_center2(refs[i]);
+ }
+ return pinfo;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+
+#else
+ const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ pinfo.add_center2(refs[i]);
+ prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node);
+ }
+ return pinfo;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+#endif
+
+ /* skip if all objects where empty */
+ if (pinfo.size() == 0)
+ bvh->set(BVH::emptyNode,empty,0);
+
+ /* otherwise build toplevel hierarchy */
+ else
+ {
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(N);
+ settings.minLeafSize = 1;
+ settings.maxLeafSize = 1;
+ settings.travCost = 1.0f;
+ settings.intCost = 1.0f;
+ settings.singleThreadThreshold = singleThreadThreshold;
+
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+ refs.resize(extSize);
+
+ NodeRef root = BVHBuilderBinnedOpenMergeSAH::build<NodeRef,BuildRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+
+ [&] (const BuildRef* refs, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {
+ assert(range.size() == 1);
+ return (NodeRef) refs[range.begin()].node;
+ },
+ [&] (BuildRef &bref, BuildRef *refs) -> size_t {
+ return openBuildRef(bref,refs);
+ },
+ [&] (size_t dn) { bvh->scene->progressMonitor(0); },
+ refs.data(),extSize,pinfo,settings);
+#else
+ NodeRef root = BVHBuilderBinnedSAH::build<NodeRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+
+ [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {
+ assert(range.size() == 1);
+ return (NodeRef) prims[range.begin()].ID();
+ },
+ [&] (size_t dn) { bvh->scene->progressMonitor(0); },
+ prims.data(),pinfo,settings);
+#endif
+
+
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);
+ }
+ }
+#if defined(TASKING_TBB) && defined(__AVX512ER__) && USE_TASK_ARENA // KNL
+ );
+#endif
+
+ }
+
+ bvh->alloc.cleanup();
+ bvh->postBuild(t0);
+#if PROFILE
+ double d1 = getSeconds();
+ std::cout << "TOP_LEVEL OPENING/REBUILD TIME " << 1000.0*(d1-d0) << " ms" << std::endl;
+#endif
+ }
+
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::deleteGeometry(size_t geomID)
+ {
+ if (geomID >= bvh->objects.size()) return;
+ if (builders[geomID]) builders[geomID].reset();
+ delete bvh->objects [geomID]; bvh->objects [geomID] = nullptr;
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::clear()
+ {
+ for (size_t i=0; i<bvh->objects.size(); i++)
+ if (bvh->objects[i]) bvh->objects[i]->clear();
+
+ for (size_t i=0; i<builders.size(); i++)
+ if (builders[i]) builders[i].reset();
+
+ refs.clear();
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::open_sequential(const size_t extSize)
+ {
+ if (refs.size() == 0)
+ return;
+
+ refs.reserve(extSize);
+
+#if 1
+ for (size_t i=0;i<refs.size();i++)
+ {
+ NodeRef ref = refs[i].node;
+ if (ref.isAABBNode())
+ BVH::prefetch(ref);
+ }
+#endif
+
+ std::make_heap(refs.begin(),refs.end());
+ while (refs.size()+N-1 <= extSize)
+ {
+ std::pop_heap (refs.begin(),refs.end());
+ NodeRef ref = refs.back().node;
+ if (ref.isLeaf()) break;
+ refs.pop_back();
+
+ AABBNode* node = ref.getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVH::emptyNode) continue;
+ refs.push_back(BuildRef(node->bounds(i),node->child(i)));
+
+#if 1
+ NodeRef ref_pre = node->child(i);
+ if (ref_pre.isAABBNode())
+ ref_pre.prefetch();
+#endif
+ std::push_heap (refs.begin(),refs.end());
+ }
+ }
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupSmallBuildRefBuilder (size_t objectID, Mesh const * const /*mesh*/)
+ {
+ if (builders[objectID] == nullptr || // new mesh
+ dynamic_cast<RefBuilderSmall*>(builders[objectID].get()) == nullptr) // size change resulted in large->small change
+ {
+ builders[objectID].reset (new RefBuilderSmall(objectID));
+ }
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh)
+ {
+ if (bvh->objects[objectID] == nullptr || // new mesh
+ builders[objectID]->meshQualityChanged (mesh->quality) || // changed build quality
+ dynamic_cast<RefBuilderLarge*>(builders[objectID].get()) == nullptr) // size change resulted in small->large change
+ {
+ Builder* builder = nullptr;
+ delete bvh->objects[objectID];
+ createMeshAccel(objectID, builder);
+ builders[objectID].reset (new RefBuilderLarge(objectID, builder, mesh->quality));
+ }
+ }
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH4BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4v>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH4BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,QuadMesh,Quad4v>((BVH4*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,UserGeometry,Object>((BVH4*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder);
+ }
+#endif
+
+#if defined(__AVX__)
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH8BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH8BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4v>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH8BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,QuadMesh,Quad4v>((BVH8*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,UserGeometry,Object>((BVH8*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH8BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder);
+ }
+#endif
+
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.h
new file mode 100644
index 0000000000..8f57c3b406
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel.h
@@ -0,0 +1,263 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <type_traits>
+
+#include "bvh_builder_twolevel_internal.h"
+#include "bvh.h"
+#include "../common/primref.h"
+#include "../builders/priminfo.h"
+#include "../builders/primrefgen.h"
+
+/* new open/merge builder */
+#define ENABLE_DIRECT_SAH_MERGE_BUILDER 1
+#define ENABLE_OPEN_SEQUENTIAL 0
+#define SPLIT_MEMORY_RESERVE_FACTOR 1000
+#define SPLIT_MEMORY_RESERVE_SCALE 2
+#define SPLIT_MIN_EXT_SPACE 1000
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNBuilderTwoLevel : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline static bool isSmallGeometry(Mesh* mesh) {
+ return mesh->size() <= 4;
+ }
+
+ public:
+
+ typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+
+ struct BuildRef : public PrimRef
+ {
+ public:
+ __forceinline BuildRef () {}
+
+ __forceinline BuildRef (const BBox3fa& bounds, NodeRef node)
+ : PrimRef(bounds,(size_t)node), node(node)
+ {
+ if (node.isLeaf())
+ bounds_area = 0.0f;
+ else
+ bounds_area = area(this->bounds());
+ }
+
+ /* used by the open/merge bvh builder */
+ __forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)
+ : PrimRef(bounds,geomID,numPrimitives), node(node)
+ {
+ /* important for relative buildref ordering */
+ if (node.isLeaf())
+ bounds_area = 0.0f;
+ else
+ bounds_area = area(this->bounds());
+ }
+
+ __forceinline size_t size() const {
+ return primID();
+ }
+
+ friend bool operator< (const BuildRef& a, const BuildRef& b) {
+ return a.bounds_area < b.bounds_area;
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {
+ return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";
+ }
+
+ __forceinline unsigned int numPrimitives() const { return primID(); }
+
+ public:
+ NodeRef node;
+ float bounds_area;
+ };
+
+
+ __forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {
+ if (bref.node.isLeaf())
+ {
+ refs[0] = bref;
+ return 1;
+ }
+ NodeRef ref = bref.node;
+ unsigned int geomID = bref.geomID();
+ unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);
+ AABBNode* node = ref.getAABBNode();
+ size_t n = 0;
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVH::emptyNode) continue;
+ refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);
+ n++;
+ }
+ assert(n > 1);
+ return n;
+ }
+
+ /*! Constructor. */
+ BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);
+
+ /*! Destructor */
+ ~BVHNBuilderTwoLevel ();
+
+ /*! builder entry point */
+ void build();
+ void deleteGeometry(size_t geomID);
+ void clear();
+
+ void open_sequential(const size_t extSize);
+
+ private:
+
+ class RefBuilderBase {
+ public:
+ virtual ~RefBuilderBase () {}
+ virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;
+ virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;
+ };
+
+ class RefBuilderSmall : public RefBuilderBase {
+ public:
+
+ RefBuilderSmall (size_t objectID)
+ : objectID_ (objectID) {}
+
+ void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {
+
+ Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);
+ size_t meshSize = mesh->size();
+ assert(isSmallGeometry(mesh));
+
+ mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);
+ auto pinfo = createPrimRefArray(mesh,objectID_,prefs,topBuilder->bvh->scene->progressInterface);
+
+ size_t begin=0;
+ while (begin < pinfo.size())
+ {
+ Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);
+ accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);
+
+ /* create build primitive */
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);
+#else
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);
+#endif
+ }
+ assert(begin == pinfo.size());
+ }
+
+ bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {
+ return false;
+ }
+
+ size_t objectID_;
+ };
+
+ class RefBuilderLarge : public RefBuilderBase {
+ public:
+
+ RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)
+ : objectID_ (objectID), builder_ (builder), quality_ (quality) {}
+
+ void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)
+ {
+ BVH* object = topBuilder->getBVH(objectID_); assert(object);
+
+ /* build object if it got modified */
+ if (topBuilder->isGeometryModified(objectID_))
+ builder_->build();
+
+ /* create build primitive */
+ if (!object->getBounds().empty())
+ {
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+ Mesh* mesh = topBuilder->getMesh(objectID_);
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());
+#else
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
+#endif
+ }
+ }
+
+ bool meshQualityChanged (RTCBuildQuality currQuality) {
+ return currQuality != quality_;
+ }
+
+ private:
+ size_t objectID_;
+ Ref<Builder> builder_;
+ RTCBuildQuality quality_;
+ };
+
+ void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);
+ void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);
+
+ BVH* getBVH (size_t objectID) {
+ return this->bvh->objects[objectID];
+ }
+ Mesh* getMesh (size_t objectID) {
+ return this->scene->template getSafe<Mesh>(objectID);
+ }
+ bool isGeometryModified (size_t objectID) {
+ return this->scene->isGeometryModified(objectID);
+ }
+
+ void resizeRefsList ()
+ {
+ size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0),
+ [this](const range<size_t>& r)->size_t {
+ size_t c = 0;
+ for (auto i=r.begin(); i<r.end(); ++i) {
+ Mesh* mesh = scene->getSafe<Mesh>(i);
+ if (mesh == nullptr || mesh->numTimeSteps != 1)
+ continue;
+ size_t meshSize = mesh->size();
+ c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;
+ }
+ return c;
+ },
+ std::plus<size_t>()
+ );
+
+ if (refs.size() < num) {
+ refs.resize(num);
+ }
+ }
+
+ void createMeshAccel (size_t geomID, Builder*& builder)
+ {
+ bvh->objects[geomID] = new BVH(Primitive::type,scene);
+ BVH* accel = bvh->objects[geomID];
+ auto mesh = scene->getSafe<Mesh>(geomID);
+ if (nullptr == mesh) {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");
+ return;
+ }
+
+ __internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);
+ }
+
+ using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;
+
+ BuilderList builders;
+ BVH* bvh;
+ Scene* scene;
+ mvector<BuildRef> refs;
+ mvector<PrimRef> prims;
+ std::atomic<int> nextRef;
+ const size_t singleThreadThreshold;
+ Geometry::GTypeMask gtype;
+ bool useMortonBuilder_ = false;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel_internal.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel_internal.h
new file mode 100644
index 0000000000..1c1ae8d6a7
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_builder_twolevel_internal.h
@@ -0,0 +1,267 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+namespace embree
+{
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshBuilderMortonGeneral,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshBuilderSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshBuilderMortonGeneral,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshBuilderSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t)
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshBuilderMortonGeneral,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshBuilderSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshBuilderMortonGeneral,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshBuilderSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t)
+
+ namespace isa
+ {
+
+ namespace __internal_two_level_builder__ {
+
+ template<int N, typename Mesh, typename Primitive>
+ struct MortonBuilder {};
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4i> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,QuadMesh,Quad4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,UserGeometry,Object> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,Instance,InstancePrimitive> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4i> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,QuadMesh,Quad4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,UserGeometry,Object> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,Instance,InstancePrimitive> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct SAHBuilder {};
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4i> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,QuadMesh,Quad4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,UserGeometry,Object> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,Instance,InstancePrimitive> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4i> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,QuadMesh,Quad4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,UserGeometry,Object> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,Instance,InstancePrimitive> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct RefitBuilder {};
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4i> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,QuadMesh,Quad4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,UserGeometry,Object> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,Instance,InstancePrimitive> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4i> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,QuadMesh,Quad4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,UserGeometry,Object> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,Instance,InstancePrimitive> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct MeshBuilder {
+ MeshBuilder () {}
+ void operator () (void* bvh, Mesh* mesh, size_t geomID, Geometry::GTypeMask gtype, bool useMortonBuilder, Builder*& builder) {
+ if(useMortonBuilder) {
+ builder = MortonBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype);
+ return;
+ }
+ switch (mesh->quality) {
+ case RTC_BUILD_QUALITY_LOW: builder = MortonBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ case RTC_BUILD_QUALITY_MEDIUM:
+ case RTC_BUILD_QUALITY_HIGH: builder = SAHBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ case RTC_BUILD_QUALITY_REFIT: builder = RefitBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ default: throw_RTCError(RTC_ERROR_UNKNOWN,"invalid build quality");
+ }
+ }
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.cpp
new file mode 100644
index 0000000000..a27be8bae8
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.cpp
@@ -0,0 +1,375 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_collider.h"
+#include "../geometry/triangle_triangle_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+#define CSTAT(x)
+
+ size_t parallel_depth_threshold = 3;
+ CSTAT(std::atomic<size_t> bvh_collide_traversal_steps(0));
+ CSTAT(std::atomic<size_t> bvh_collide_leaf_pairs(0));
+ CSTAT(std::atomic<size_t> bvh_collide_leaf_iterations(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections1(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections2(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections3(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections4(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections5(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections(0));
+
+ struct Collision
+ {
+ __forceinline Collision() {}
+
+ __forceinline Collision (unsigned geomID0, unsigned primID0, unsigned geomID1, unsigned primID1)
+ : geomID0(geomID0), primID0(primID0), geomID1(geomID1), primID1(primID1) {}
+
+ unsigned geomID0;
+ unsigned primID0;
+ unsigned geomID1;
+ unsigned primID1;
+ };
+
+ template<int N>
+ __forceinline size_t overlap(const BBox3fa& box0, const typename BVHN<N>::AABBNode& node1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),node1.lower_x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),node1.lower_y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),node1.lower_z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),node1.upper_x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),node1.upper_y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),node1.upper_z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ template<int N>
+ __forceinline size_t overlap(const BBox3fa& box0, const BBox<Vec3<vfloat<N>>>& box1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),box1.lower.x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),box1.lower.y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),box1.lower.z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),box1.upper.x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),box1.upper.y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),box1.upper.z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ template<int N>
+ __forceinline size_t overlap(const BBox<Vec3<vfloat<N>>>& box0, size_t i, const BBox<Vec3<vfloat<N>>>& box1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x[i]),box1.lower.x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y[i]),box1.lower.y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z[i]),box1.lower.z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x[i]),box1.upper.x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y[i]),box1.upper.y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z[i]),box1.upper.z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ bool intersect_triangle_triangle (Scene* scene0, unsigned geomID0, unsigned primID0, Scene* scene1, unsigned geomID1, unsigned primID1)
+ {
+ CSTAT(bvh_collide_prim_intersections1++);
+ const TriangleMesh* mesh0 = scene0->get<TriangleMesh>(geomID0);
+ const TriangleMesh* mesh1 = scene1->get<TriangleMesh>(geomID1);
+ const TriangleMesh::Triangle& tri0 = mesh0->triangle(primID0);
+ const TriangleMesh::Triangle& tri1 = mesh1->triangle(primID1);
+
+ /* special culling for scene intersection with itself */
+ if (scene0 == scene1 && geomID0 == geomID1)
+ {
+ /* ignore self intersections */
+ if (primID0 == primID1)
+ return false;
+ }
+ CSTAT(bvh_collide_prim_intersections2++);
+
+ if (scene0 == scene1 && geomID0 == geomID1)
+ {
+ /* ignore intersection with topological neighbors */
+ const vint4 t0(tri0.v[0],tri0.v[1],tri0.v[2],tri0.v[2]);
+ if (any(vint4(tri1.v[0]) == t0)) return false;
+ if (any(vint4(tri1.v[1]) == t0)) return false;
+ if (any(vint4(tri1.v[2]) == t0)) return false;
+ }
+ CSTAT(bvh_collide_prim_intersections3++);
+
+ const Vec3fa a0 = mesh0->vertex(tri0.v[0]);
+ const Vec3fa a1 = mesh0->vertex(tri0.v[1]);
+ const Vec3fa a2 = mesh0->vertex(tri0.v[2]);
+ const Vec3fa b0 = mesh1->vertex(tri1.v[0]);
+ const Vec3fa b1 = mesh1->vertex(tri1.v[1]);
+ const Vec3fa b2 = mesh1->vertex(tri1.v[2]);
+
+ return TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);
+ }
+
+ template<int N>
+ __forceinline void BVHNColliderUserGeom<N>::processLeaf(NodeRef node0, NodeRef node1)
+ {
+ Collision collisions[16];
+ size_t num_collisions = 0;
+
+ size_t N0; Object* leaf0 = (Object*) node0.leaf(N0);
+ size_t N1; Object* leaf1 = (Object*) node1.leaf(N1);
+ for (size_t i=0; i<N0; i++) {
+ for (size_t j=0; j<N1; j++) {
+ const unsigned geomID0 = leaf0[i].geomID();
+ const unsigned primID0 = leaf0[i].primID();
+ const unsigned geomID1 = leaf1[j].geomID();
+ const unsigned primID1 = leaf1[j].primID();
+ if (this->scene0 == this->scene1 && geomID0 == geomID1 && primID0 == primID1) continue;
+ collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
+ if (num_collisions == 16) {
+ this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
+ num_collisions = 0;
+ }
+ }
+ }
+ if (num_collisions)
+ this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
+ }
+
+ template<int N>
+ void BVHNCollider<N>::collide_recurse(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth0, size_t depth1)
+ {
+ CSTAT(bvh_collide_traversal_steps++);
+ if (unlikely(ref0.isLeaf())) {
+ if (unlikely(ref1.isLeaf())) {
+ CSTAT(bvh_collide_leaf_pairs++);
+ processLeaf(ref0,ref1);
+ return;
+ } else goto recurse_node1;
+
+ } else {
+ if (unlikely(ref1.isLeaf())) {
+ goto recurse_node0;
+ } else {
+ if (area(bounds0) > area(bounds1)) {
+ goto recurse_node0;
+ }
+ else {
+ goto recurse_node1;
+ }
+ }
+ }
+
+ {
+ recurse_node0:
+ AABBNode* node0 = ref0.getAABBNode();
+ size_t mask = overlap<N>(bounds1,*node0);
+ //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ //for (size_t i=0; i<N; i++) {
+#if 0
+ if (depth0 < parallel_depth_threshold)
+ {
+ parallel_for(size_t(N), [&] ( size_t i ) {
+ if (mask & ( 1 << i)) {
+ BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
+ }
+ });
+ }
+ else
+#endif
+ {
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
+ }
+ }
+ return;
+ }
+
+ {
+ recurse_node1:
+ AABBNode* node1 = ref1.getAABBNode();
+ size_t mask = overlap<N>(bounds0,*node1);
+ //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ //for (size_t i=0; i<N; i++) {
+#if 0
+ if (depth1 < parallel_depth_threshold)
+ {
+ parallel_for(size_t(N), [&] ( size_t i ) {
+ if (mask & ( 1 << i)) {
+ BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
+ }
+ });
+ }
+ else
+#endif
+ {
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
+ }
+ }
+ return;
+ }
+ }
+
+ template<int N>
+ void BVHNCollider<N>::split(const CollideJob& job, jobvector& jobs)
+ {
+ if (unlikely(job.ref0.isLeaf())) {
+ if (unlikely(job.ref1.isLeaf())) {
+ jobs.push_back(job);
+ return;
+ } else goto recurse_node1;
+ } else {
+ if (unlikely(job.ref1.isLeaf())) {
+ goto recurse_node0;
+ } else {
+ if (area(job.bounds0) > area(job.bounds1)) {
+ goto recurse_node0;
+ }
+ else {
+ goto recurse_node1;
+ }
+ }
+ }
+
+ {
+ recurse_node0:
+ const AABBNode* node0 = job.ref0.getAABBNode();
+ size_t mask = overlap<N>(job.bounds1,*node0);
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ jobs.push_back(CollideJob(node0->child(i),node0->bounds(i),job.depth0+1,job.ref1,job.bounds1,job.depth1));
+ }
+ return;
+ }
+
+ {
+ recurse_node1:
+ const AABBNode* node1 = job.ref1.getAABBNode();
+ size_t mask = overlap<N>(job.bounds0,*node1);
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ jobs.push_back(CollideJob(job.ref0,job.bounds0,job.depth0,node1->child(i),node1->bounds(i),job.depth1+1));
+ }
+ return;
+ }
+ }
+
+ template<int N>
+ void BVHNCollider<N>::collide_recurse_entry(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1)
+ {
+ CSTAT(bvh_collide_traversal_steps = 0);
+ CSTAT(bvh_collide_leaf_pairs = 0);
+ CSTAT(bvh_collide_leaf_iterations = 0);
+ CSTAT(bvh_collide_prim_intersections1 = 0);
+ CSTAT(bvh_collide_prim_intersections2 = 0);
+ CSTAT(bvh_collide_prim_intersections3 = 0);
+ CSTAT(bvh_collide_prim_intersections4 = 0);
+ CSTAT(bvh_collide_prim_intersections5 = 0);
+ CSTAT(bvh_collide_prim_intersections = 0);
+#if 0
+ collide_recurse(ref0,bounds0,ref1,bounds1,0,0);
+#else
+ const int M = 2048;
+ jobvector jobs[2];
+ jobs[0].reserve(M);
+ jobs[1].reserve(M);
+ jobs[0].push_back(CollideJob(ref0,bounds0,0,ref1,bounds1,0));
+ int source = 0;
+ int target = 1;
+
+ /* try to split job until job list is full */
+ while (jobs[source].size()+8 <= M)
+ {
+ for (size_t i=0; i<jobs[source].size(); i++)
+ {
+ const CollideJob& job = jobs[source][i];
+ size_t remaining = jobs[source].size()-i;
+ if (jobs[target].size()+remaining+8 > M) {
+ jobs[target].push_back(job);
+ } else {
+ split(job,jobs[target]);
+ }
+ }
+
+ /* stop splitting jobs if we reached only leaves and cannot make progress anymore */
+ if (jobs[target].size() == jobs[source].size())
+ break;
+
+ jobs[source].resize(0);
+ std::swap(source,target);
+ }
+
+ /* parallel processing of all jobs */
+ parallel_for(size_t(jobs[source].size()), [&] ( size_t i ) {
+ CollideJob& j = jobs[source][i];
+ collide_recurse(j.ref0,j.bounds0,j.ref1,j.bounds1,j.depth0,j.depth1);
+ });
+
+
+#endif
+ CSTAT(PRINT(bvh_collide_traversal_steps));
+ CSTAT(PRINT(bvh_collide_leaf_pairs));
+ CSTAT(PRINT(bvh_collide_leaf_iterations));
+ CSTAT(PRINT(bvh_collide_prim_intersections1));
+ CSTAT(PRINT(bvh_collide_prim_intersections2));
+ CSTAT(PRINT(bvh_collide_prim_intersections3));
+ CSTAT(PRINT(bvh_collide_prim_intersections4));
+ CSTAT(PRINT(bvh_collide_prim_intersections5));
+ CSTAT(PRINT(bvh_collide_prim_intersections));
+ }
+
+ template<int N>
+ void BVHNColliderUserGeom<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)
+ {
+ BVHNColliderUserGeom<N>(bvh0->scene,bvh1->scene,callback,userPtr).
+ collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds());
+ }
+
+#if defined (EMBREE_LOWEST_ISA)
+ struct collision_regression_test : public RegressionTest
+ {
+ collision_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(-0.008815f, 0.041848f, -2.49875e-06f), Vec3fa(-0.008276f, 0.053318f, -2.49875e-06f), Vec3fa(0.003023f, 0.048969f, -2.49875e-06f),
+ Vec3fa(0.00245f, 0.037612f, -2.49875e-06f), Vec3fa(0.01434f, 0.042634f, -2.49875e-06f), Vec3fa(0.013499f, 0.031309f, -2.49875e-06f)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,1),Vec3fa(0,1,1)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,-0.1f),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,-0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(-0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa(-1,1,0) + Vec3fa(0,0,0),Vec3fa(-1,1,0) + Vec3fa(0.1f,0,0),Vec3fa(-1,1,0) + Vec3fa(0,0.1f,0)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa( 2,0.5f,0) + Vec3fa(0,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0.1f,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0,0.1f,0)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0.1f,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0.1f,0)) == false;
+ return passed;
+ }
+ };
+
+ collision_regression_test collision_regression("collision_regression_test");
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Collider Definitions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ DEFINE_COLLIDER(BVH4ColliderUserGeom,BVHNColliderUserGeom<4>);
+
+#if defined(__AVX__)
+ DEFINE_COLLIDER(BVH8ColliderUserGeom,BVHNColliderUserGeom<8>);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.h
new file mode 100644
index 0000000000..ac4f99c96a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_collider.h
@@ -0,0 +1,72 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/object.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNCollider
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+
+ struct CollideJob
+ {
+ CollideJob () {}
+
+ CollideJob (NodeRef ref0, const BBox3fa& bounds0, size_t depth0,
+ NodeRef ref1, const BBox3fa& bounds1, size_t depth1)
+ : ref0(ref0), bounds0(bounds0), depth0(depth0), ref1(ref1), bounds1(bounds1), depth1(depth1) {}
+
+ NodeRef ref0;
+ BBox3fa bounds0;
+ size_t depth0;
+ NodeRef ref1;
+ BBox3fa bounds1;
+ size_t depth1;
+ };
+
+ typedef vector_t<CollideJob, aligned_allocator<CollideJob,16>> jobvector;
+
+ void split(const CollideJob& job, jobvector& jobs);
+
+ public:
+ __forceinline BVHNCollider (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
+ : scene0(scene0), scene1(scene1), callback(callback), userPtr(userPtr) {}
+
+ public:
+ virtual void processLeaf(NodeRef leaf0, NodeRef leaf1) = 0;
+ void collide_recurse(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1, size_t depth0, size_t depth1);
+ void collide_recurse_entry(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1);
+
+ protected:
+ Scene* scene0;
+ Scene* scene1;
+ RTCCollideFunc callback;
+ void* userPtr;
+ };
+
+ template<int N>
+ class BVHNColliderUserGeom : public BVHNCollider<N>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+
+ __forceinline BVHNColliderUserGeom (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
+ : BVHNCollider<N>(scene0,scene1,callback,userPtr) {}
+
+ virtual void processLeaf(NodeRef leaf0, NodeRef leaf1);
+ public:
+ static void collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr);
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_factory.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_factory.h
new file mode 100644
index 0000000000..54021ca6eb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_factory.h
@@ -0,0 +1,21 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../common/isa.h"
+#include "../common/accel.h"
+#include "../common/scene.h"
+#include "../geometry/curve_intersector_virtual.h"
+
+namespace embree
+{
+ /*! BVH instantiations */
+ class BVHFactory
+ {
+ public:
+ enum class BuildVariant { STATIC, DYNAMIC, HIGH_QUALITY };
+ enum class IntersectVariant { FAST, ROBUST };
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.cpp
new file mode 100644
index 0000000000..ea6adc2717
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.cpp
@@ -0,0 +1,330 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_intersector1.h"
+#include "node_intersector1.h"
+#include "bvh_traverser1.h"
+
+#include "../geometry/intersector_iterators.h"
+#include "../geometry/triangle_intersector.h"
+#include "../geometry/trianglev_intersector.h"
+#include "../geometry/trianglev_mb_intersector.h"
+#include "../geometry/trianglei_intersector.h"
+#include "../geometry/quadv_intersector.h"
+#include "../geometry/quadi_intersector.h"
+#include "../geometry/curveNv_intersector.h"
+#include "../geometry/curveNi_intersector.h"
+#include "../geometry/curveNi_mb_intersector.h"
+#include "../geometry/linei_intersector.h"
+#include "../geometry/subdivpatch1_intersector.h"
+#include "../geometry/object_intersector.h"
+#include "../geometry/instance_intersector.h"
+#include "../geometry/subgrid_intersector.h"
+#include "../geometry/subgrid_mb_intersector.h"
+#include "../geometry/curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::intersect(const Accel::Intersectors* __restrict__ This,
+ RayHit& __restrict__ ray,
+ IntersectContext* __restrict__ context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* perform per ray precalculations required by the primitive intersector */
+ Precalculations pre(ray, bvh);
+
+ /* stack state */
+ StackItemT<NodeRef> stack[stackSize]; // stack of nodes
+ StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer
+ StackItemT<NodeRef>* stackEnd = stack+stackSize;
+ stack[0].ptr = bvh->root;
+ stack[0].dist = neg_inf;
+
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* filter out invalid rays */
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ if (!ray.valid()) return;
+#endif
+ /* verify correct input */
+ assert(ray.valid());
+ assert(ray.tnear() >= 0.0f);
+ assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));
+
+ /* load the ray into SIMD registers */
+ TravRay<N,Nx,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N, Nx, types> nodeTraverser;
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = NodeRef(stackPtr->ptr);
+
+ /* if popped node is too far, pop next one */
+#if defined(__AVX512ER__)
+ /* much faster on KNL */
+ if (unlikely(any(vfloat<Nx>(*(float*)&stackPtr->dist) > tray.tfar)))
+ continue;
+#else
+ if (unlikely(*(float*)&stackPtr->dist > ray.tfar))
+ continue;
+#endif
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<Nx> tNear;
+ STAT3(normal.trav_nodes,1,1,1);
+ bool nodeIntersected = BVHNNodeIntersector1<N, Nx, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);
+ if (unlikely(!nodeIntersected)) { STAT3(normal.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(normal.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ PrimitiveIntersector1::intersect(This, pre, ray, context, prim, num, tray, lazy_node);
+ tray.tfar = ray.tfar;
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ stackPtr->ptr = lazy_node;
+ stackPtr->dist = neg_inf;
+ stackPtr++;
+ }
+ }
+ }
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::occluded(const Accel::Intersectors* __restrict__ This,
+ Ray& __restrict__ ray,
+ IntersectContext* __restrict__ context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* early out for already occluded rays */
+ if (unlikely(ray.tfar < 0.0f))
+ return;
+
+ /* perform per ray precalculations required by the primitive intersector */
+ Precalculations pre(ray, bvh);
+
+ /* stack state */
+ NodeRef stack[stackSize]; // stack of nodes that still need to get traversed
+ NodeRef* stackPtr = stack+1; // current stack pointer
+ NodeRef* stackEnd = stack+stackSize;
+ stack[0] = bvh->root;
+
+ /* filter out invalid rays */
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ if (!ray.valid()) return;
+#endif
+
+ /* verify correct input */
+ assert(ray.valid());
+ assert(ray.tnear() >= 0.0f);
+ assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));
+
+ /* load the ray into SIMD registers */
+ TravRay<N,Nx,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N, Nx, types> nodeTraverser;
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = (NodeRef)*stackPtr;
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<Nx> tNear;
+ STAT3(shadow.trav_nodes,1,1,1);
+ bool nodeIntersected = BVHNNodeIntersector1<N, Nx, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);
+ if (unlikely(!nodeIntersected)) { STAT3(shadow.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseAnyHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(shadow.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ if (PrimitiveIntersector1::occluded(This, pre, ray, context, prim, num, tray, lazy_node)) {
+ ray.tfar = neg_inf;
+ break;
+ }
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ *stackPtr = (NodeRef)lazy_node;
+ stackPtr++;
+ }
+ }
+ }
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ struct PointQueryDispatch
+ {
+ typedef typename PrimitiveIntersector1::Precalculations Precalculations;
+ typedef typename PrimitiveIntersector1::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+
+ static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+
+ /* right now AVX512KNL SIMD extension only for standard node types */
+ static const size_t Nx = (types == BVH_AN1 || types == BVH_QN1) ? vextend<N>::size : N;
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return false;
+
+ /* stack state */
+ StackItemT<NodeRef> stack[stackSize]; // stack of nodes
+ StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer
+ StackItemT<NodeRef>* stackEnd = stack+stackSize;
+ stack[0].ptr = bvh->root;
+ stack[0].dist = neg_inf;
+
+ /* verify correct input */
+ assert(!(types & BVH_MB) || (query->time >= 0.0f && query->time <= 1.0f));
+
+ /* load the point query into SIMD registers */
+ TravPointQuery<N> tquery(query->p, context->query_radius);
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N, N, types> nodeTraverser;
+
+ bool changed = false;
+ float cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE
+ ? query->radius * query->radius
+ : dot(context->query_radius, context->query_radius);
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = NodeRef(stackPtr->ptr);
+
+ /* if popped node is too far, pop next one */
+ if (unlikely(*(float*)&stackPtr->dist > cull_radius))
+ continue;
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<N> tNear;
+ STAT3(point_query.trav_nodes,1,1,1);
+ bool nodeIntersected;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ nodeIntersected = BVHNNodePointQuerySphere1<N, types>::pointQuery(cur, tquery, query->time, tNear, mask);
+ } else {
+ nodeIntersected = BVHNNodePointQueryAABB1 <N, types>::pointQuery(cur, tquery, query->time, tNear, mask);
+ }
+ if (unlikely(!nodeIntersected)) { STAT3(point_query.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(point_query.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ if (PrimitiveIntersector1::pointQuery(This, query, context, prim, num, tquery, lazy_node))
+ {
+ changed = true;
+ tquery.rad = context->query_radius;
+ cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE
+ ? query->radius * query->radius
+ : dot(context->query_radius, context->query_radius);
+ }
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ stackPtr->ptr = lazy_node;
+ stackPtr->dist = neg_inf;
+ stackPtr++;
+ }
+ }
+ return changed;
+ }
+ };
+
+ /* disable point queries for not yet supported geometry types */
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, VirtualCurveIntersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, SubdivPatch1Intersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, SubdivPatch1MBIntersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ bool BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::pointQuery(
+ const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)
+ {
+ return PointQueryDispatch<N, types, robust, PrimitiveIntersector1>::pointQuery(This, query, context);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.h
new file mode 100644
index 0000000000..1a269c319a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1.h
@@ -0,0 +1,37 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH single ray intersector. */
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ class BVHNIntersector1
+ {
+ /* shortcuts for frequently used types */
+ typedef typename PrimitiveIntersector1::Precalculations Precalculations;
+ typedef typename PrimitiveIntersector1::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+
+ static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+
+ /* right now AVX512KNL SIMD extension only for standard node types */
+ static const size_t Nx = (types == BVH_AN1 || types == BVH_QN1) ? vextend<N>::size : N;
+
+ public:
+ static void intersect (const Accel::Intersectors* This, RayHit& ray, IntersectContext* context);
+ static void occluded (const Accel::Intersectors* This, Ray& ray, IntersectContext* context);
+ static bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context);
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1_bvh4.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1_bvh4.cpp
new file mode 100644
index 0000000000..989f7354fd
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector1_bvh4.cpp
@@ -0,0 +1,61 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_intersector1.cpp"
+
+namespace embree
+{
+ namespace isa
+ {
+ int getISA() {
+ return VerifyMultiTargetLinking::getISA();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// BVH4Intersector1 Definitions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersector1,BVHNIntersector1<4 COMMA BVH_AN1_UN1 COMMA false COMMA VirtualCurveIntersector1 >));
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersector1MB,BVHNIntersector1<4 COMMA BVH_AN2_AN4D_UN2 COMMA false COMMA VirtualCurveIntersector1 >));
+
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersectorRobust1,BVHNIntersector1<4 COMMA BVH_AN1_UN1 COMMA true COMMA VirtualCurveIntersector1 >));
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersectorRobust1MB,BVHNIntersector1<4 COMMA BVH_AN2_AN4D_UN2 COMMA true COMMA VirtualCurveIntersector1 >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4Intersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<TriangleMIntersector1Moeller <SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<TriangleMiIntersector1Moeller <SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<TriangleMvIntersector1Pluecker<SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<TriangleMiIntersector1Pluecker<SIMD_MODE(4) COMMA true> > >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<TriangleMvMBIntersector1Moeller <SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<TriangleMiMBIntersector1Moeller <SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<TriangleMvMBIntersector1Pluecker<SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<TriangleMiMBIntersector1Pluecker<SIMD_MODE(4) COMMA true> > >));
+
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4vIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<QuadMvIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<QuadMiIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4vIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<QuadMvIntersector1Pluecker<4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<QuadMiIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<QuadMiMBIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<QuadMiMBIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_SUBDIV(DEFINE_INTERSECTOR1(BVH4SubdivPatch1Intersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA SubdivPatch1Intersector1>));
+ IF_ENABLED_SUBDIV(DEFINE_INTERSECTOR1(BVH4SubdivPatch1MBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA SubdivPatch1MBIntersector1>));
+
+ IF_ENABLED_USER(DEFINE_INTERSECTOR1(BVH4VirtualIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<ObjectIntersector1<false>> >));
+ IF_ENABLED_USER(DEFINE_INTERSECTOR1(BVH4VirtualMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<ObjectIntersector1<true>> >));
+
+ IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<InstanceIntersector1> >));
+ IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<InstanceIntersector1MB> >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(QBVH4Triangle4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<TriangleMiIntersector1Pluecker<SIMD_MODE(4) COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(QBVH4Quad4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<QuadMiIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridIntersector1Moeller,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA SubGridIntersector1Moeller<4 COMMA true> >));
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridMBIntersector1Moeller,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA SubGridMBIntersector1Pluecker<4 COMMA true> >));
+
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA SubGridIntersector1Pluecker<4 COMMA true> >));
+ //IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA SubGridMBIntersector1Pluecker<4 COMMA true> >));
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_hybrid.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_hybrid.h
new file mode 100644
index 0000000000..d764cc928d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_hybrid.h
@@ -0,0 +1,61 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/stack_item.h"
+#include "node_intersector_frustum.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int K, bool robust>
+ struct TravRayK;
+
+ /*! BVH hybrid packet intersector. Switches between packet and single ray traversal (optional). */
+ template<int N, int K, int types, bool robust, typename PrimitiveIntersectorK, bool single = true>
+ class BVHNIntersectorKHybrid
+ {
+ /* right now AVX512KNL SIMD extension only for standard node types */
+ static const size_t Nx = types == BVH_AN1 ? vextend<N>::size : N;
+
+ /* shortcuts for frequently used types */
+ typedef typename PrimitiveIntersectorK::Precalculations Precalculations;
+ typedef typename PrimitiveIntersectorK::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+ typedef typename BVH::AABBNode AABBNode;
+
+ static const size_t stackSizeSingle = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+ static const size_t stackSizeChunk = 1+(N-1)*BVH::maxDepth;
+
+ static const size_t switchThresholdIncoherent = \
+ (K==4) ? 3 :
+ (K==8) ? ((N==4) ? 5 : 7) :
+ (K==16) ? 14 : // 14 seems to work best for KNL due to better ordered chunk traversal
+ 0;
+
+ private:
+ static void intersect1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre,
+ RayHitK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context);
+ static bool occluded1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre,
+ RayK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context);
+
+ public:
+ static void intersect(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context);
+ static void occluded (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context);
+
+ static void intersectCoherent(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context);
+ static void occludedCoherent (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context);
+
+ };
+
+ /*! BVH packet intersector. */
+ template<int N, int K, int types, bool robust, typename PrimitiveIntersectorK>
+ class BVHNIntersectorKChunk : public BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, false> {};
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream.h
new file mode 100644
index 0000000000..83d1fb4d3d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream.h
@@ -0,0 +1,295 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector_packet_stream.h"
+#include "node_intersector_frustum.h"
+#include "bvh_traverser_stream.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH ray stream intersector. */
+ template<int N, int Nx, int types, bool robust, typename PrimitiveIntersector>
+ class BVHNIntersectorStream
+ {
+ static const int Nxd = (Nx == N) ? N : Nx/2;
+
+ /* shortcuts for frequently used types */
+ template<int K> using PrimitiveIntersectorK = typename PrimitiveIntersector::template Type<K>;
+ template<int K> using PrimitiveK = typename PrimitiveIntersectorK<K>::PrimitiveK;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+
+ template<int K>
+ __forceinline static size_t initPacketsAndFrustum(RayK<K>** inputPackets, size_t numOctantRays,
+ TravRayKStream<K, robust>* packets, Frustum<robust>& frustum, bool& commonOctant)
+ {
+ const size_t numPackets = (numOctantRays+K-1)/K;
+
+ Vec3vf<K> tmp_min_rdir(pos_inf);
+ Vec3vf<K> tmp_max_rdir(neg_inf);
+ Vec3vf<K> tmp_min_org(pos_inf);
+ Vec3vf<K> tmp_max_org(neg_inf);
+ vfloat<K> tmp_min_dist(pos_inf);
+ vfloat<K> tmp_max_dist(neg_inf);
+
+ size_t m_active = 0;
+ for (size_t i = 0; i < numPackets; i++)
+ {
+ const vfloat<K> tnear = inputPackets[i]->tnear();
+ const vfloat<K> tfar = inputPackets[i]->tfar;
+ vbool<K> m_valid = (tnear <= tfar) & (tnear >= 0.0f);
+
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ m_valid &= inputPackets[i]->valid();
+#endif
+
+ m_active |= (size_t)movemask(m_valid) << (i*K);
+
+ vfloat<K> packet_min_dist = max(tnear, 0.0f);
+ vfloat<K> packet_max_dist = select(m_valid, tfar, neg_inf);
+ tmp_min_dist = min(tmp_min_dist, packet_min_dist);
+ tmp_max_dist = max(tmp_max_dist, packet_max_dist);
+
+ const Vec3vf<K>& org = inputPackets[i]->org;
+ const Vec3vf<K>& dir = inputPackets[i]->dir;
+
+ new (&packets[i]) TravRayKStream<K, robust>(org, dir, packet_min_dist, packet_max_dist);
+
+ tmp_min_rdir = min(tmp_min_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(pos_inf)));
+ tmp_max_rdir = max(tmp_max_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(neg_inf)));
+ tmp_min_org = min(tmp_min_org , select(m_valid,org , Vec3vf<K>(pos_inf)));
+ tmp_max_org = max(tmp_max_org , select(m_valid,org , Vec3vf<K>(neg_inf)));
+ }
+
+ m_active &= (numOctantRays == (8 * sizeof(size_t))) ? (size_t)-1 : (((size_t)1 << numOctantRays)-1);
+
+
+ const Vec3fa reduced_min_rdir(reduce_min(tmp_min_rdir.x),
+ reduce_min(tmp_min_rdir.y),
+ reduce_min(tmp_min_rdir.z));
+
+ const Vec3fa reduced_max_rdir(reduce_max(tmp_max_rdir.x),
+ reduce_max(tmp_max_rdir.y),
+ reduce_max(tmp_max_rdir.z));
+
+ const Vec3fa reduced_min_origin(reduce_min(tmp_min_org.x),
+ reduce_min(tmp_min_org.y),
+ reduce_min(tmp_min_org.z));
+
+ const Vec3fa reduced_max_origin(reduce_max(tmp_max_org.x),
+ reduce_max(tmp_max_org.y),
+ reduce_max(tmp_max_org.z));
+
+ commonOctant =
+ (reduced_max_rdir.x < 0.0f || reduced_min_rdir.x >= 0.0f) &&
+ (reduced_max_rdir.y < 0.0f || reduced_min_rdir.y >= 0.0f) &&
+ (reduced_max_rdir.z < 0.0f || reduced_min_rdir.z >= 0.0f);
+
+ const float frustum_min_dist = reduce_min(tmp_min_dist);
+ const float frustum_max_dist = reduce_max(tmp_max_dist);
+
+ frustum.init(reduced_min_origin, reduced_max_origin,
+ reduced_min_rdir, reduced_max_rdir,
+ frustum_min_dist, frustum_max_dist,
+ N);
+
+ return m_active;
+ }
+
+ template<int K>
+ __forceinline static size_t intersectAABBNodePacket(size_t m_active,
+ const TravRayKStream<K,robust>* packets,
+ const AABBNode* __restrict__ node,
+ size_t boxID,
+ const NearFarPrecalculations& nf)
+ {
+ assert(m_active);
+ const size_t startPacketID = bsf(m_active) / K;
+ const size_t endPacketID = bsr(m_active) / K;
+ size_t m_trav_active = 0;
+ for (size_t i = startPacketID; i <= endPacketID; i++)
+ {
+ const size_t m_hit = intersectNodeK<N>(node, boxID, packets[i], nf);
+ m_trav_active |= m_hit << (i*K);
+ }
+ return m_trav_active;
+ }
+
+ template<int K>
+ __forceinline static size_t traverseCoherentStream(size_t m_active,
+ TravRayKStream<K, robust>* packets,
+ const AABBNode* __restrict__ node,
+ const Frustum<robust>& frustum,
+ size_t* maskK,
+ vfloat<Nx>& dist)
+ {
+ size_t m_node_hit = intersectNodeFrustum<N,Nx>(node, frustum, dist);
+ const size_t first_index = bsf(m_active);
+ const size_t first_packetID = first_index / K;
+ const size_t first_rayID = first_index % K;
+ size_t m_first_hit = intersectNode1<N,Nx>(node, packets[first_packetID], first_rayID, frustum.nf);
+
+ /* this make traversal independent of the ordering of rays */
+ size_t m_node = m_node_hit ^ m_first_hit;
+ while (unlikely(m_node))
+ {
+ const size_t boxID = bscf(m_node);
+ const size_t m_current = m_active & intersectAABBNodePacket(m_active, packets, node, boxID, frustum.nf);
+ m_node_hit ^= m_current ? (size_t)0 : ((size_t)1 << boxID);
+ maskK[boxID] = m_current;
+ }
+ return m_node_hit;
+ }
+
+ // TODO: explicit 16-wide path for KNL
+ template<int K>
+ __forceinline static vint<Nx> traverseIncoherentStream(size_t m_active,
+ TravRayKStreamFast<K>* __restrict__ packets,
+ const AABBNode* __restrict__ node,
+ const NearFarPrecalculations& nf,
+ const int shiftTable[32])
+ {
+ const vfloat<Nx> bminX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<Nx> bminY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<Nx> bminZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<Nx> bmaxX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<Nx> bmaxY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<Nx> bmaxZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+ assert(m_active);
+ vint<Nx> vmask(zero);
+ do
+ {
+ STAT3(shadow.trav_nodes,1,1,1);
+ const size_t rayID = bscf(m_active);
+ assert(rayID < MAX_INTERNAL_STREAM_SIZE);
+ TravRayKStream<K,robust> &p = packets[rayID / K];
+ const size_t i = rayID % K;
+ const vint<Nx> bitmask(shiftTable[rayID]);
+
+#if defined (__aarch64__)
+ const vfloat<Nx> tNearX = madd(bminX, p.rdir.x[i], p.neg_org_rdir.x[i]);
+ const vfloat<Nx> tNearY = madd(bminY, p.rdir.y[i], p.neg_org_rdir.y[i]);
+ const vfloat<Nx> tNearZ = madd(bminZ, p.rdir.z[i], p.neg_org_rdir.z[i]);
+ const vfloat<Nx> tFarX = madd(bmaxX, p.rdir.x[i], p.neg_org_rdir.x[i]);
+ const vfloat<Nx> tFarY = madd(bmaxY, p.rdir.y[i], p.neg_org_rdir.y[i]);
+ const vfloat<Nx> tFarZ = madd(bmaxZ, p.rdir.z[i], p.neg_org_rdir.z[i]);
+#else
+ const vfloat<Nx> tNearX = msub(bminX, p.rdir.x[i], p.org_rdir.x[i]);
+ const vfloat<Nx> tNearY = msub(bminY, p.rdir.y[i], p.org_rdir.y[i]);
+ const vfloat<Nx> tNearZ = msub(bminZ, p.rdir.z[i], p.org_rdir.z[i]);
+ const vfloat<Nx> tFarX = msub(bmaxX, p.rdir.x[i], p.org_rdir.x[i]);
+ const vfloat<Nx> tFarY = msub(bmaxY, p.rdir.y[i], p.org_rdir.y[i]);
+ const vfloat<Nx> tFarZ = msub(bmaxZ, p.rdir.z[i], p.org_rdir.z[i]);
+#endif
+
+ const vfloat<Nx> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<Nx>(p.tnear[i]));
+ const vfloat<Nx> tFar = mini(tFarX , tFarY , tFarZ, vfloat<Nx>(p.tfar[i]));
+
+#if defined(__AVX512ER__)
+ const vboolx m_node((1 << N)-1);
+ const vbool<Nx> hit_mask = le(m_node, tNear, tFar);
+ vmask = mask_or(hit_mask, vmask, vmask, bitmask);
+#else
+ const vbool<Nx> hit_mask = tNear <= tFar;
+#if defined(__AVX2__)
+ vmask = vmask | (bitmask & vint<Nx>(hit_mask));
+#else
+ vmask = select(hit_mask, vmask | bitmask, vmask);
+#endif
+#endif
+ } while(m_active);
+ return vmask;
+ }
+
+ template<int K>
+ __forceinline static vint<Nx> traverseIncoherentStream(size_t m_active,
+ TravRayKStreamRobust<K>* __restrict__ packets,
+ const AABBNode* __restrict__ node,
+ const NearFarPrecalculations& nf,
+ const int shiftTable[32])
+ {
+ const vfloat<Nx> bminX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<Nx> bminY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<Nx> bminZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<Nx> bmaxX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<Nx> bmaxY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<Nx> bmaxZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+ assert(m_active);
+ vint<Nx> vmask(zero);
+ do
+ {
+ STAT3(shadow.trav_nodes,1,1,1);
+ const size_t rayID = bscf(m_active);
+ assert(rayID < MAX_INTERNAL_STREAM_SIZE);
+ TravRayKStream<K,robust> &p = packets[rayID / K];
+ const size_t i = rayID % K;
+ const vint<Nx> bitmask(shiftTable[rayID]);
+ const vfloat<Nx> tNearX = (bminX - p.org.x[i]) * p.rdir.x[i];
+ const vfloat<Nx> tNearY = (bminY - p.org.y[i]) * p.rdir.y[i];
+ const vfloat<Nx> tNearZ = (bminZ - p.org.z[i]) * p.rdir.z[i];
+ const vfloat<Nx> tFarX = (bmaxX - p.org.x[i]) * p.rdir.x[i];
+ const vfloat<Nx> tFarY = (bmaxY - p.org.y[i]) * p.rdir.y[i];
+ const vfloat<Nx> tFarZ = (bmaxZ - p.org.z[i]) * p.rdir.z[i];
+ const vfloat<Nx> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<Nx>(p.tnear[i]));
+ const vfloat<Nx> tFar = mini(tFarX , tFarY , tFarZ, vfloat<Nx>(p.tfar[i]));
+ const float round_down = 1.0f-2.0f*float(ulp);
+ const float round_up = 1.0f+2.0f*float(ulp);
+#if defined(__AVX512ER__)
+ const vboolx m_node((1 << N)-1);
+ const vbool<Nx> hit_mask = le(m_node, round_down*tNear, round_up*tFar);
+ vmask = mask_or(hit_mask, vmask, vmask, bitmask);
+#else
+ const vbool<Nx> hit_mask = round_down*tNear <= round_up*tFar;
+#if defined(__AVX2__)
+ vmask = vmask | (bitmask & vint<Nx>(hit_mask));
+#else
+ vmask = select(hit_mask, vmask | bitmask, vmask);
+#endif
+#endif
+ } while(m_active);
+ return vmask;
+ }
+
+
+ static const size_t stackSizeSingle = 1+(N-1)*BVH::maxDepth;
+
+ public:
+ static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context);
+ static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context);
+
+ private:
+ template<int K>
+ static void intersectCoherent(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedCoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedIncoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+ };
+
+
+ /*! BVH ray stream intersector with direct fallback to packets. */
+ template<int N, int Nx>
+ class BVHNIntersectorStreamPacketFallback
+ {
+ public:
+ static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context);
+ static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context);
+
+ private:
+ template<int K>
+ static void intersectK(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedK(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream_filters.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream_filters.h
new file mode 100644
index 0000000000..cdeb923637
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_intersector_stream_filters.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/ray.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class RayStreamFilter
+ {
+ public:
+ static void intersectAOS(Scene* scene, RTCRayHit* rays, size_t N, size_t stride, IntersectContext* context);
+ static void intersectAOP(Scene* scene, RTCRayHit** rays, size_t N, IntersectContext* context);
+ static void intersectSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+ static void intersectSOP(Scene* scene, const RTCRayHitNp* rays, size_t N, IntersectContext* context);
+
+ static void occludedAOS(Scene* scene, RTCRay* rays, size_t N, size_t stride, IntersectContext* context);
+ static void occludedAOP(Scene* scene, RTCRay** rays, size_t N, IntersectContext* context);
+ static void occludedSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+ static void occludedSOP(Scene* scene, const RTCRayNp* rays, size_t N, IntersectContext* context);
+
+ private:
+ template<int K, bool intersect>
+ static void filterAOS(Scene* scene, void* rays, size_t N, size_t stride, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterAOP(Scene* scene, void** rays, size_t N, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterSOP(Scene* scene, const void* rays, size_t N, IntersectContext* context);
+ };
+ }
+};
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb.h
new file mode 100644
index 0000000000..baa4a8d805
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb.h
@@ -0,0 +1,213 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! BVHN AABBNode */
+ template<typename NodeRef, int N>
+ struct AABBNode_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc, size_t numChildren = 0) const
+ {
+ AABBNode_t* node = (AABBNode_t*) alloc.malloc0(sizeof(AABBNode_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const BBox3fa& bounds) const {
+ node.getAABBNode()->setRef(i,child);
+ node.getAABBNode()->setBounds(i,bounds);
+ }
+ };
+
+ struct Create2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const
+ {
+ AABBNode_t* node = (AABBNode_t*) alloc.malloc0(sizeof(AABBNode_t), NodeRef::byteNodeAlignment); node->clear();
+ for (size_t i=0; i<num; i++) node->setBounds(i,children[i].bounds());
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ AABBNode_t* node = ref.getAABBNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+ return ref;
+ }
+ };
+
+ struct Set3
+ {
+ Set3 (FastAllocator* allocator, PrimRef* prims)
+ : allocator(allocator), prims(prims) {}
+
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ AABBNode_t* node = ref.getAABBNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+
+ if (unlikely(precord.alloc_barrier))
+ {
+ PrimRef* begin = &prims[precord.prims.begin()];
+ PrimRef* end = &prims[precord.prims.end()]; // FIXME: extended end for spatial split builder!!!!!
+ size_t bytes = (size_t)end - (size_t)begin;
+ allocator->addBlock(begin,bytes);
+ }
+
+ return ref;
+ }
+
+ FastAllocator* const allocator;
+ PrimRef* const prims;
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_x = lower_y = lower_z = pos_inf;
+ upper_x = upper_y = upper_z = neg_inf;
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const BBox3fa& bounds)
+ {
+ assert(i < N);
+ lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z;
+ upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRef& ref, const BBox3fa& bounds) {
+ setBounds(i,bounds);
+ children[i] = ref;
+ }
+
+ /*! Returns bounds of node. */
+ __forceinline BBox3fa bounds() const {
+ const Vec3fa lower(reduce_min(lower_x),reduce_min(lower_y),reduce_min(lower_z));
+ const Vec3fa upper(reduce_max(upper_x),reduce_max(upper_y),reduce_max(upper_z));
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ const Vec3fa lower(lower_x[i],lower_y[i],lower_z[i]);
+ const Vec3fa upper(upper_x[i],upper_y[i],upper_z[i]);
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extend(size_t i) const {
+ return bounds(i).size();
+ }
+
+ /*! Returns bounds of all children (implemented later as specializations) */
+ __forceinline void bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const;
+
+ /*! swap two children of the node */
+ __forceinline void swap(size_t i, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(children[i],children[j]);
+ std::swap(lower_x[i],lower_x[j]);
+ std::swap(lower_y[i],lower_y[j]);
+ std::swap(lower_z[i],lower_z[j]);
+ std::swap(upper_x[i],upper_x[j]);
+ std::swap(upper_y[i],upper_y[j]);
+ std::swap(upper_z[i],upper_z[j]);
+ }
+
+ /*! swap the children of two nodes */
+ __forceinline static void swap(AABBNode_t* a, size_t i, AABBNode_t* b, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(a->children[i],b->children[j]);
+ std::swap(a->lower_x[i],b->lower_x[j]);
+ std::swap(a->lower_y[i],b->lower_y[j]);
+ std::swap(a->lower_z[i],b->lower_z[j]);
+ std::swap(a->upper_x[i],b->upper_x[j]);
+ std::swap(a->upper_y[i],b->upper_y[j]);
+ std::swap(a->upper_z[i],b->upper_z[j]);
+ }
+
+ /*! compacts a node (moves empty children to the end) */
+ __forceinline static void compact(AABBNode_t* a)
+ {
+ /* find right most filled node */
+ ssize_t j=N;
+ for (j=j-1; j>=0; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+
+ /* replace empty nodes with filled nodes */
+ for (ssize_t i=0; i<j; i++) {
+ if (a->child(i) == NodeRef::emptyNode) {
+ a->swap(i,j);
+ for (j=j-1; j>i; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+ }
+ }
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! output operator */
+ friend embree_ostream operator<<(embree_ostream o, const AABBNode_t& n)
+ {
+ o << "AABBNode { " << embree_endl;
+ o << " lower_x " << n.lower_x << embree_endl;
+ o << " upper_x " << n.upper_x << embree_endl;
+ o << " lower_y " << n.lower_y << embree_endl;
+ o << " upper_y " << n.upper_y << embree_endl;
+ o << " lower_z " << n.lower_z << embree_endl;
+ o << " upper_z " << n.upper_z << embree_endl;
+ o << " children = ";
+ for (size_t i=0; i<N; i++) o << n.children[i] << " ";
+ o << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+
+ public:
+ vfloat<N> lower_x; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_x; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_y; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_y; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_z; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_z; //!< Z dimension of upper bounds of all N children.
+ };
+
+ template<>
+ __forceinline void AABBNode_t<NodeRefPtr<4>,4>::bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const {
+ transpose(lower_x,lower_y,lower_z,vfloat4(zero),bounds0.lower,bounds1.lower,bounds2.lower,bounds3.lower);
+ transpose(upper_x,upper_y,upper_z,vfloat4(zero),bounds0.upper,bounds1.upper,bounds2.upper,bounds3.upper);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb.h
new file mode 100644
index 0000000000..501f4bce5b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb.h
@@ -0,0 +1,247 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! Motion Blur AABBNode */
+ template<typename NodeRef, int N>
+ struct AABBNodeMB_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ struct Create
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const
+ {
+ AABBNodeMB_t* node = (AABBNodeMB_t*) alloc.malloc0(sizeof(AABBNodeMB_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const
+ {
+ AABBNodeMB_t* node = ref.getAABBNodeMB();
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++) {
+ node->setRef(i,children[i].ref);
+ node->setBounds(i,children[i].lbounds);
+ bounds.extend(children[i].lbounds);
+ }
+ return NodeRecordMB(ref,bounds);
+ }
+ };
+
+ struct SetTimeRange
+ {
+ __forceinline SetTimeRange(BBox1f tbounds) : tbounds(tbounds) {}
+
+ template<typename BuildRecord>
+ __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const
+ {
+ AABBNodeMB_t* node = ref.getAABBNodeMB();
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++) {
+ node->setRef(i, children[i].ref);
+ node->setBounds(i, children[i].lbounds, tbounds);
+ bounds.extend(children[i].lbounds);
+ }
+ return NodeRecordMB(ref,bounds);
+ }
+
+ BBox1f tbounds;
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_x = lower_y = lower_z = vfloat<N>(pos_inf);
+ upper_x = upper_y = upper_z = vfloat<N>(neg_inf);
+ lower_dx = lower_dy = lower_dz = vfloat<N>(0.0f);
+ upper_dx = upper_dy = upper_dz = vfloat<N>(0.0f);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, NodeRef ref) {
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const BBox3fa& bounds0_i, const BBox3fa& bounds1_i)
+ {
+ /*! for empty bounds we have to avoid inf-inf=nan */
+ BBox3fa bounds0(min(bounds0_i.lower,Vec3fa(+FLT_MAX)),max(bounds0_i.upper,Vec3fa(-FLT_MAX)));
+ BBox3fa bounds1(min(bounds1_i.lower,Vec3fa(+FLT_MAX)),max(bounds1_i.upper,Vec3fa(-FLT_MAX)));
+ bounds0 = bounds0.enlarge_by(4.0f*float(ulp));
+ bounds1 = bounds1.enlarge_by(4.0f*float(ulp));
+ Vec3fa dlower = bounds1.lower-bounds0.lower;
+ Vec3fa dupper = bounds1.upper-bounds0.upper;
+
+ lower_x[i] = bounds0.lower.x; lower_y[i] = bounds0.lower.y; lower_z[i] = bounds0.lower.z;
+ upper_x[i] = bounds0.upper.x; upper_y[i] = bounds0.upper.y; upper_z[i] = bounds0.upper.z;
+
+ lower_dx[i] = dlower.x; lower_dy[i] = dlower.y; lower_dz[i] = dlower.z;
+ upper_dx[i] = dupper.x; upper_dy[i] = dupper.y; upper_dz[i] = dupper.z;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds) {
+ setBounds(i, bounds.bounds0, bounds.bounds1);
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds, const BBox1f& tbounds) {
+ setBounds(i, bounds.global(tbounds));
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, NodeRef ref, const BBox3fa& bounds) {
+ lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z;
+ upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z;
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRecordMB4D& child)
+ {
+ setRef(i, child.ref);
+ setBounds(i, child.lbounds, child.dt);
+ }
+
+ /*! Return bounding box for time 0 */
+ __forceinline BBox3fa bounds0(size_t i) const {
+ return BBox3fa(Vec3fa(lower_x[i],lower_y[i],lower_z[i]),
+ Vec3fa(upper_x[i],upper_y[i],upper_z[i]));
+ }
+
+ /*! Return bounding box for time 1 */
+ __forceinline BBox3fa bounds1(size_t i) const {
+ return BBox3fa(Vec3fa(lower_x[i]+lower_dx[i],lower_y[i]+lower_dy[i],lower_z[i]+lower_dz[i]),
+ Vec3fa(upper_x[i]+upper_dx[i],upper_y[i]+upper_dy[i],upper_z[i]+upper_dz[i]));
+ }
+
+ /*! Returns bounds of node. */
+ __forceinline BBox3fa bounds() const {
+ return BBox3fa(Vec3fa(reduce_min(min(lower_x,lower_x+lower_dx)),
+ reduce_min(min(lower_y,lower_y+lower_dy)),
+ reduce_min(min(lower_z,lower_z+lower_dz))),
+ Vec3fa(reduce_max(max(upper_x,upper_x+upper_dx)),
+ reduce_max(max(upper_y,upper_y+upper_dy)),
+ reduce_max(max(upper_z,upper_z+upper_dz))));
+ }
+
+ /*! Return bounding box of child i */
+ __forceinline BBox3fa bounds(size_t i) const {
+ return merge(bounds0(i),bounds1(i));
+ }
+
+ /*! Return linear bounding box of child i */
+ __forceinline LBBox3fa lbounds(size_t i) const {
+ return LBBox3fa(bounds0(i),bounds1(i));
+ }
+
+ /*! Return bounding box of child i at specified time */
+ __forceinline BBox3fa bounds(size_t i, float time) const {
+ return lerp(bounds0(i),bounds1(i),time);
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i) const {
+ return lbounds(i).expectedHalfArea();
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i, const BBox1f& t0t1) const {
+ return lbounds(i).expectedHalfArea(t0t1);
+ }
+
+ /*! swap two children of the node */
+ __forceinline void swap(size_t i, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(children[i],children[j]);
+
+ std::swap(lower_x[i],lower_x[j]);
+ std::swap(upper_x[i],upper_x[j]);
+ std::swap(lower_y[i],lower_y[j]);
+ std::swap(upper_y[i],upper_y[j]);
+ std::swap(lower_z[i],lower_z[j]);
+ std::swap(upper_z[i],upper_z[j]);
+
+ std::swap(lower_dx[i],lower_dx[j]);
+ std::swap(upper_dx[i],upper_dx[j]);
+ std::swap(lower_dy[i],lower_dy[j]);
+ std::swap(upper_dy[i],upper_dy[j]);
+ std::swap(lower_dz[i],lower_dz[j]);
+ std::swap(upper_dz[i],upper_dz[j]);
+ }
+
+ /*! compacts a node (moves empty children to the end) */
+ __forceinline static void compact(AABBNodeMB_t* a)
+ {
+ /* find right most filled node */
+ ssize_t j=N;
+ for (j=j-1; j>=0; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+
+ /* replace empty nodes with filled nodes */
+ for (ssize_t i=0; i<j; i++) {
+ if (a->child(i) == NodeRef::emptyNode) {
+ a->swap(i,j);
+ for (j=j-1; j>i; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+ }
+ }
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! stream output operator */
+ friend embree_ostream operator<<(embree_ostream cout, const AABBNodeMB_t& n)
+ {
+ cout << "AABBNodeMB {" << embree_endl;
+ for (size_t i=0; i<N; i++)
+ {
+ const BBox3fa b0 = n.bounds0(i);
+ const BBox3fa b1 = n.bounds1(i);
+ cout << " child" << i << " { " << embree_endl;
+ cout << " bounds0 = " << b0 << ", " << embree_endl;
+ cout << " bounds1 = " << b1 << ", " << embree_endl;
+ cout << " }";
+ }
+ cout << "}";
+ return cout;
+ }
+
+ public:
+ vfloat<N> lower_x; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_x; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_y; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_y; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_z; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_z; //!< Z dimension of upper bounds of all N children.
+
+ vfloat<N> lower_dx; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_dx; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_dy; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_dy; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_dz; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_dz; //!< Z dimension of upper bounds of all N children.
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb4d.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb4d.h
new file mode 100644
index 0000000000..e968bbbc39
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_aabb_mb4d.h
@@ -0,0 +1,107 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_aabb_mb.h"
+
+namespace embree
+{
+ /*! Aligned 4D Motion Blur Node */
+ template<typename NodeRef, int N>
+ struct AABBNodeMB4D_t : public AABBNodeMB_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ using AABBNodeMB_t<NodeRef,N>::set;
+
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ struct Create
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord*, const size_t, const FastAllocator::CachedAllocator& alloc, bool hasTimeSplits = true) const
+ {
+ if (hasTimeSplits)
+ {
+ AABBNodeMB4D_t* node = (AABBNodeMB4D_t*) alloc.malloc0(sizeof(AABBNodeMB4D_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ else
+ {
+ AABBNodeMB_t<NodeRef,N>* node = (AABBNodeMB_t<NodeRef,N>*) alloc.malloc0(sizeof(AABBNodeMB_t<NodeRef,N>),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ }
+ };
+
+ struct Set
+ {
+ template<typename BuildRecord>
+ __forceinline void operator() (const BuildRecord&, const BuildRecord*, NodeRef ref, NodeRecordMB4D* children, const size_t num) const
+ {
+ if (likely(ref.isAABBNodeMB())) {
+ for (size_t i=0; i<num; i++)
+ ref.getAABBNodeMB()->set(i, children[i]);
+ } else {
+ for (size_t i=0; i<num; i++)
+ ref.getAABBNodeMB4D()->set(i, children[i]);
+ }
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_t = vfloat<N>(pos_inf);
+ upper_t = vfloat<N>(neg_inf);
+ AABBNodeMB_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds, const BBox1f& tbounds)
+ {
+ AABBNodeMB_t<NodeRef,N>::setBounds(i, bounds.global(tbounds));
+ lower_t[i] = tbounds.lower;
+ upper_t[i] = tbounds.upper == 1.0f ? 1.0f+float(ulp) : tbounds.upper;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRecordMB4D& child) {
+ AABBNodeMB_t<NodeRef,N>::setRef(i,child.ref);
+ setBounds(i, child.lbounds, child.dt);
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i) const {
+ return AABBNodeMB_t<NodeRef,N>::lbounds(i).expectedHalfArea(timeRange(i));
+ }
+
+ /*! returns time range for specified child */
+ __forceinline BBox1f timeRange(size_t i) const {
+ return BBox1f(lower_t[i],upper_t[i]);
+ }
+
+ /*! stream output operator */
+ friend embree_ostream operator<<(embree_ostream cout, const AABBNodeMB4D_t& n)
+ {
+ cout << "AABBNodeMB4D {" << embree_endl;
+ for (size_t i=0; i<N; i++)
+ {
+ const BBox3fa b0 = n.bounds0(i);
+ const BBox3fa b1 = n.bounds1(i);
+ cout << " child" << i << " { " << embree_endl;
+ cout << " bounds0 = " << lerp(b0,b1,n.lower_t[i]) << ", " << embree_endl;
+ cout << " bounds1 = " << lerp(b0,b1,n.upper_t[i]) << ", " << embree_endl;
+ cout << " time_bounds = " << n.lower_t[i] << ", " << n.upper_t[i] << embree_endl;
+ cout << " }";
+ }
+ cout << "}";
+ return cout;
+ }
+
+ public:
+ vfloat<N> lower_t; //!< time dimension of lower bounds of all N children
+ vfloat<N> upper_t; //!< time dimension of upper bounds of all N children
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_base.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_base.h
new file mode 100644
index 0000000000..8268f3b932
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_base.h
@@ -0,0 +1,43 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_ref.h"
+
+namespace embree
+{
+
+ /*! BVHN Base Node */
+ template<typename NodeRef, int N>
+ struct BaseNode_t
+ {
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<N; i++)
+ children[i] = NodeRef::emptyNode;
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! verifies the node */
+ __forceinline bool verify() const
+ {
+ for (size_t i=0; i<N; i++) {
+ if (child(i) == NodeRef::emptyNode) {
+ for (; i<N; i++) {
+ if (child(i) != NodeRef::emptyNode)
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+ NodeRef children[N]; //!< Pointer to the N children (can be a node or leaf)
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb.h
new file mode 100644
index 0000000000..fa7cc08211
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! Node with unaligned bounds */
+ template<typename NodeRef, int N>
+ struct OBBNode_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc) const
+ {
+ OBBNode_t* node = (OBBNode_t*) alloc.malloc0(sizeof(OBBNode_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const OBBox3fa& bounds) const {
+ node.ungetAABBNode()->setRef(i,child);
+ node.ungetAABBNode()->setBounds(i,bounds);
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ naabb.l.vx = Vec3fa(nan);
+ naabb.l.vy = Vec3fa(nan);
+ naabb.l.vz = Vec3fa(nan);
+ naabb.p = Vec3fa(nan);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box. */
+ __forceinline void setBounds(size_t i, const OBBox3fa& b)
+ {
+ assert(i < N);
+
+ AffineSpace3fa space = b.space;
+ space.p -= b.bounds.lower;
+ space = AffineSpace3fa::scale(1.0f/max(Vec3fa(1E-19f),b.bounds.upper-b.bounds.lower))*space;
+
+ naabb.l.vx.x[i] = space.l.vx.x;
+ naabb.l.vx.y[i] = space.l.vx.y;
+ naabb.l.vx.z[i] = space.l.vx.z;
+
+ naabb.l.vy.x[i] = space.l.vy.x;
+ naabb.l.vy.y[i] = space.l.vy.y;
+ naabb.l.vy.z[i] = space.l.vy.z;
+
+ naabb.l.vz.x[i] = space.l.vz.x;
+ naabb.l.vz.y[i] = space.l.vz.y;
+ naabb.l.vz.z[i] = space.l.vz.z;
+
+ naabb.p.x[i] = space.p.x;
+ naabb.p.y[i] = space.p.y;
+ naabb.p.z[i] = space.p.z;
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Returns the extent of the bounds of the ith child */
+ __forceinline Vec3fa extent(size_t i) const {
+ assert(i<N);
+ const Vec3fa vx(naabb.l.vx.x[i],naabb.l.vx.y[i],naabb.l.vx.z[i]);
+ const Vec3fa vy(naabb.l.vy.x[i],naabb.l.vy.y[i],naabb.l.vy.z[i]);
+ const Vec3fa vz(naabb.l.vz.x[i],naabb.l.vz.y[i],naabb.l.vz.z[i]);
+ return rsqrt(vx*vx + vy*vy + vz*vz);
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! output operator */
+ friend embree_ostream operator<<(embree_ostream o, const OBBNode_t& n)
+ {
+ o << "UnAABBNode { " << n.naabb << " } " << embree_endl;
+ return o;
+ }
+
+ public:
+ AffineSpace3vf<N> naabb; //!< non-axis aligned bounding boxes (bounds are [0,1] in specified space)
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb_mb.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb_mb.h
new file mode 100644
index 0000000000..834cf5ec28
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_obb_mb.h
@@ -0,0 +1,90 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ template<typename NodeRef, int N>
+ struct OBBNodeMB_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc) const
+ {
+ OBBNodeMB_t* node = (OBBNodeMB_t*) alloc.malloc0(sizeof(OBBNodeMB_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const LinearSpace3fa& space, const LBBox3fa& lbounds, const BBox1f dt) const {
+ node.ungetAABBNodeMB()->setRef(i,child);
+ node.ungetAABBNodeMB()->setBounds(i,space,lbounds.global(dt));
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ space0 = one;
+ //b0.lower = b0.upper = Vec3fa(nan);
+ b1.lower = b1.upper = Vec3fa(nan);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets space and bounding boxes. */
+ __forceinline void setBounds(size_t i, const AffineSpace3fa& space, const LBBox3fa& lbounds) {
+ setBounds(i,space,lbounds.bounds0,lbounds.bounds1);
+ }
+
+ /*! Sets space and bounding boxes. */
+ __forceinline void setBounds(size_t i, const AffineSpace3fa& s0, const BBox3fa& a, const BBox3fa& c)
+ {
+ assert(i < N);
+
+ AffineSpace3fa space = s0;
+ space.p -= a.lower;
+ Vec3fa scale = 1.0f/max(Vec3fa(1E-19f),a.upper-a.lower);
+ space = AffineSpace3fa::scale(scale)*space;
+ BBox3fa a1((a.lower-a.lower)*scale,(a.upper-a.lower)*scale);
+ BBox3fa c1((c.lower-a.lower)*scale,(c.upper-a.lower)*scale);
+
+ space0.l.vx.x[i] = space.l.vx.x; space0.l.vx.y[i] = space.l.vx.y; space0.l.vx.z[i] = space.l.vx.z;
+ space0.l.vy.x[i] = space.l.vy.x; space0.l.vy.y[i] = space.l.vy.y; space0.l.vy.z[i] = space.l.vy.z;
+ space0.l.vz.x[i] = space.l.vz.x; space0.l.vz.y[i] = space.l.vz.y; space0.l.vz.z[i] = space.l.vz.z;
+ space0.p .x[i] = space.p .x; space0.p .y[i] = space.p .y; space0.p .z[i] = space.p .z;
+
+ /*b0.lower.x[i] = a1.lower.x; b0.lower.y[i] = a1.lower.y; b0.lower.z[i] = a1.lower.z;
+ b0.upper.x[i] = a1.upper.x; b0.upper.y[i] = a1.upper.y; b0.upper.z[i] = a1.upper.z;*/
+
+ b1.lower.x[i] = c1.lower.x; b1.lower.y[i] = c1.lower.y; b1.lower.z[i] = c1.lower.z;
+ b1.upper.x[i] = c1.upper.x; b1.upper.y[i] = c1.upper.y; b1.upper.z[i] = c1.upper.z;
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Returns the extent of the bounds of the ith child */
+ __forceinline Vec3fa extent0(size_t i) const {
+ assert(i < N);
+ const Vec3fa vx(space0.l.vx.x[i],space0.l.vx.y[i],space0.l.vx.z[i]);
+ const Vec3fa vy(space0.l.vy.x[i],space0.l.vy.y[i],space0.l.vy.z[i]);
+ const Vec3fa vz(space0.l.vz.x[i],space0.l.vz.y[i],space0.l.vz.z[i]);
+ return rsqrt(vx*vx + vy*vy + vz*vz);
+ }
+
+ public:
+ AffineSpace3vf<N> space0;
+ //BBox3vf<N> b0; // these are the unit bounds
+ BBox3vf<N> b1;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_qaabb.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_qaabb.h
new file mode 100644
index 0000000000..5212821f3f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_qaabb.h
@@ -0,0 +1,265 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! BVHN Quantized Node */
+ template<int N>
+ struct __aligned(8) QuantizedBaseNode_t
+ {
+ typedef unsigned char T;
+ static const T MIN_QUAN = 0;
+ static const T MAX_QUAN = 255;
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ for (size_t i=0; i<N; i++) lower_x[i] = lower_y[i] = lower_z[i] = MAX_QUAN;
+ for (size_t i=0; i<N; i++) upper_x[i] = upper_y[i] = upper_z[i] = MIN_QUAN;
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ const Vec3fa lower(madd(scale.x,(float)lower_x[i],start.x),
+ madd(scale.y,(float)lower_y[i],start.y),
+ madd(scale.z,(float)lower_z[i],start.z));
+ const Vec3fa upper(madd(scale.x,(float)upper_x[i],start.x),
+ madd(scale.y,(float)upper_y[i],start.y),
+ madd(scale.z,(float)upper_z[i],start.z));
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extent(size_t i) const {
+ return bounds(i).size();
+ }
+
+ static __forceinline void init_dim(const vfloat<N> &lower,
+ const vfloat<N> &upper,
+ T lower_quant[N],
+ T upper_quant[N],
+ float &start,
+ float &scale)
+ {
+ /* quantize bounds */
+ const vbool<N> m_valid = lower != vfloat<N>(pos_inf);
+ const float minF = reduce_min(lower);
+ const float maxF = reduce_max(upper);
+ float diff = (1.0f+2.0f*float(ulp))*(maxF - minF);
+ float decode_scale = diff / float(MAX_QUAN);
+ if (decode_scale == 0.0f) decode_scale = 2.0f*FLT_MIN; // result may have been flushed to zero
+ assert(madd(decode_scale,float(MAX_QUAN),minF) >= maxF);
+ const float encode_scale = diff > 0 ? (float(MAX_QUAN) / diff) : 0.0f;
+ vint<N> ilower = max(vint<N>(floor((lower - vfloat<N>(minF))*vfloat<N>(encode_scale))),MIN_QUAN);
+ vint<N> iupper = min(vint<N>(ceil ((upper - vfloat<N>(minF))*vfloat<N>(encode_scale))),MAX_QUAN);
+
+ /* lower/upper correction */
+ vbool<N> m_lower_correction = (madd(vfloat<N>(ilower),decode_scale,minF)) > lower;
+ vbool<N> m_upper_correction = (madd(vfloat<N>(iupper),decode_scale,minF)) < upper;
+ ilower = max(select(m_lower_correction,ilower-1,ilower),MIN_QUAN);
+ iupper = min(select(m_upper_correction,iupper+1,iupper),MAX_QUAN);
+
+ /* disable invalid lanes */
+ ilower = select(m_valid,ilower,MAX_QUAN);
+ iupper = select(m_valid,iupper,MIN_QUAN);
+
+ /* store as uchar to memory */
+ vint<N>::store(lower_quant,ilower);
+ vint<N>::store(upper_quant,iupper);
+ start = minF;
+ scale = decode_scale;
+
+#if defined(DEBUG)
+ vfloat<N> extract_lower( vint<N>::loadu(lower_quant) );
+ vfloat<N> extract_upper( vint<N>::loadu(upper_quant) );
+ vfloat<N> final_extract_lower = madd(extract_lower,decode_scale,minF);
+ vfloat<N> final_extract_upper = madd(extract_upper,decode_scale,minF);
+ assert( (movemask(final_extract_lower <= lower ) & movemask(m_valid)) == movemask(m_valid));
+ assert( (movemask(final_extract_upper >= upper ) & movemask(m_valid)) == movemask(m_valid));
+#endif
+ }
+
+ __forceinline void init_dim(AABBNode_t<NodeRefPtr<N>,N>& node)
+ {
+ init_dim(node.lower_x,node.upper_x,lower_x,upper_x,start.x,scale.x);
+ init_dim(node.lower_y,node.upper_y,lower_y,upper_y,start.y,scale.y);
+ init_dim(node.lower_z,node.upper_z,lower_z,upper_z,start.z,scale.z);
+ }
+
+ __forceinline vbool<N> validMask() const { return vint<N>::loadu(lower_x) <= vint<N>::loadu(upper_x); }
+
+#if defined(__AVX512F__) // KNL
+ __forceinline vbool16 validMask16() const { return le(0xff,vint<16>::loadu(lower_x),vint<16>::loadu(upper_x)); }
+#endif
+ __forceinline vfloat<N> dequantizeLowerX() const { return madd(vfloat<N>(vint<N>::loadu(lower_x)),scale.x,vfloat<N>(start.x)); }
+
+ __forceinline vfloat<N> dequantizeUpperX() const { return madd(vfloat<N>(vint<N>::loadu(upper_x)),scale.x,vfloat<N>(start.x)); }
+
+ __forceinline vfloat<N> dequantizeLowerY() const { return madd(vfloat<N>(vint<N>::loadu(lower_y)),scale.y,vfloat<N>(start.y)); }
+
+ __forceinline vfloat<N> dequantizeUpperY() const { return madd(vfloat<N>(vint<N>::loadu(upper_y)),scale.y,vfloat<N>(start.y)); }
+
+ __forceinline vfloat<N> dequantizeLowerZ() const { return madd(vfloat<N>(vint<N>::loadu(lower_z)),scale.z,vfloat<N>(start.z)); }
+
+ __forceinline vfloat<N> dequantizeUpperZ() const { return madd(vfloat<N>(vint<N>::loadu(upper_z)),scale.z,vfloat<N>(start.z)); }
+
+ template <int M>
+ __forceinline vfloat<M> dequantize(const size_t offset) const { return vfloat<M>(vint<M>::loadu(all_planes+offset)); }
+
+#if defined(__AVX512F__)
+ __forceinline vfloat16 dequantizeLowerUpperX(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_x),p)),scale.x,vfloat16(start.x)); }
+ __forceinline vfloat16 dequantizeLowerUpperY(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_y),p)),scale.y,vfloat16(start.y)); }
+ __forceinline vfloat16 dequantizeLowerUpperZ(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_z),p)),scale.z,vfloat16(start.z)); }
+#endif
+
+ union {
+ struct {
+ T lower_x[N]; //!< 8bit discretized X dimension of lower bounds of all N children
+ T upper_x[N]; //!< 8bit discretized X dimension of upper bounds of all N children
+ T lower_y[N]; //!< 8bit discretized Y dimension of lower bounds of all N children
+ T upper_y[N]; //!< 8bit discretized Y dimension of upper bounds of all N children
+ T lower_z[N]; //!< 8bit discretized Z dimension of lower bounds of all N children
+ T upper_z[N]; //!< 8bit discretized Z dimension of upper bounds of all N children
+ };
+ T all_planes[6*N];
+ };
+
+ Vec3f start;
+ Vec3f scale;
+
+ friend embree_ostream operator<<(embree_ostream o, const QuantizedBaseNode_t& n)
+ {
+ o << "QuantizedBaseNode { " << embree_endl;
+ o << " start " << n.start << embree_endl;
+ o << " scale " << n.scale << embree_endl;
+ o << " lower_x " << vuint<N>::loadu(n.lower_x) << embree_endl;
+ o << " upper_x " << vuint<N>::loadu(n.upper_x) << embree_endl;
+ o << " lower_y " << vuint<N>::loadu(n.lower_y) << embree_endl;
+ o << " upper_y " << vuint<N>::loadu(n.upper_y) << embree_endl;
+ o << " lower_z " << vuint<N>::loadu(n.lower_z) << embree_endl;
+ o << " upper_z " << vuint<N>::loadu(n.upper_z) << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+
+ };
+
+ template<typename NodeRef, int N>
+ struct __aligned(8) QuantizedNode_t : public BaseNode_t<NodeRef, N>, QuantizedBaseNode_t<N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ using QuantizedBaseNode_t<N>::lower_x;
+ using QuantizedBaseNode_t<N>::upper_x;
+ using QuantizedBaseNode_t<N>::lower_y;
+ using QuantizedBaseNode_t<N>::upper_y;
+ using QuantizedBaseNode_t<N>::lower_z;
+ using QuantizedBaseNode_t<N>::upper_z;
+ using QuantizedBaseNode_t<N>::start;
+ using QuantizedBaseNode_t<N>::scale;
+ using QuantizedBaseNode_t<N>::init_dim;
+
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ struct Create2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t n, const FastAllocator::CachedAllocator& alloc) const
+ {
+ __aligned(64) AABBNode_t<NodeRef,N> node;
+ node.clear();
+ for (size_t i=0; i<n; i++) {
+ node.setBounds(i,children[i].bounds());
+ }
+ QuantizedNode_t *qnode = (QuantizedNode_t*) alloc.malloc0(sizeof(QuantizedNode_t), NodeRef::byteAlignment);
+ qnode->init(node);
+
+ return (size_t)qnode | NodeRef::tyQuantizedNode;
+ }
+ };
+
+ struct Set2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ QuantizedNode_t* node = ref.quantizedNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+ return ref;
+ }
+ };
+
+ __forceinline void init(AABBNode_t<NodeRef,N>& node)
+ {
+ for (size_t i=0;i<N;i++) children[i] = NodeRef::emptyNode;
+ init_dim(node);
+ }
+
+ };
+
+ /*! BVHN Quantized Node */
+ template<int N>
+ struct __aligned(8) QuantizedBaseNodeMB_t
+ {
+ QuantizedBaseNode_t<N> node0;
+ QuantizedBaseNode_t<N> node1;
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ node0.clear();
+ node1.clear();
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ BBox3fa bounds0 = node0.bounds(i);
+ BBox3fa bounds1 = node1.bounds(i);
+ bounds0.extend(bounds1);
+ return bounds0;
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extent(size_t i) const {
+ return bounds(i).size();
+ }
+
+ __forceinline vbool<N> validMask() const { return node0.validMask(); }
+
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerX(const T t) const { return lerp(node0.dequantizeLowerX(),node1.dequantizeLowerX(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperX(const T t) const { return lerp(node0.dequantizeUpperX(),node1.dequantizeUpperX(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerY(const T t) const { return lerp(node0.dequantizeLowerY(),node1.dequantizeLowerY(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperY(const T t) const { return lerp(node0.dequantizeUpperY(),node1.dequantizeUpperY(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerZ(const T t) const { return lerp(node0.dequantizeLowerZ(),node1.dequantizeLowerZ(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperZ(const T t) const { return lerp(node0.dequantizeUpperZ(),node1.dequantizeUpperZ(),t); }
+
+
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerX(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerX()[i]),vfloat<M>(node1.dequantizeLowerX()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperX(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperX()[i]),vfloat<M>(node1.dequantizeUpperX()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerY(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerY()[i]),vfloat<M>(node1.dequantizeLowerY()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperY(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperY()[i]),vfloat<M>(node1.dequantizeUpperY()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerZ(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerZ()[i]),vfloat<M>(node1.dequantizeLowerZ()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperZ(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperZ()[i]),vfloat<M>(node1.dequantizeUpperZ()[i]),t); }
+
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_node_ref.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_ref.h
new file mode 100644
index 0000000000..0f6d4dac7e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_node_ref.h
@@ -0,0 +1,242 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/alloc.h"
+#include "../common/accel.h"
+#include "../common/device.h"
+#include "../common/scene.h"
+#include "../geometry/primitive.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ /* BVH node reference with bounds */
+ template<typename NodeRef>
+ struct BVHNodeRecord
+ {
+ __forceinline BVHNodeRecord() {}
+ __forceinline BVHNodeRecord(NodeRef ref, const BBox3fa& bounds) : ref(ref), bounds((BBox3fx)bounds) {}
+ __forceinline BVHNodeRecord(NodeRef ref, const BBox3fx& bounds) : ref(ref), bounds(bounds) {}
+
+ NodeRef ref;
+ BBox3fx bounds;
+ };
+
+ template<typename NodeRef>
+ struct BVHNodeRecordMB
+ {
+ __forceinline BVHNodeRecordMB() {}
+ __forceinline BVHNodeRecordMB(NodeRef ref, const LBBox3fa& lbounds) : ref(ref), lbounds(lbounds) {}
+
+ NodeRef ref;
+ LBBox3fa lbounds;
+ };
+
+ template<typename NodeRef>
+ struct BVHNodeRecordMB4D
+ {
+ __forceinline BVHNodeRecordMB4D() {}
+ __forceinline BVHNodeRecordMB4D(NodeRef ref, const LBBox3fa& lbounds, const BBox1f& dt) : ref(ref), lbounds(lbounds), dt(dt) {}
+
+ NodeRef ref;
+ LBBox3fa lbounds;
+ BBox1f dt;
+ };
+
+ template<typename NodeRef, int N> struct BaseNode_t;
+ template<typename NodeRef, int N> struct AABBNode_t;
+ template<typename NodeRef, int N> struct AABBNodeMB_t;
+ template<typename NodeRef, int N> struct AABBNodeMB4D_t;
+ template<typename NodeRef, int N> struct OBBNode_t;
+ template<typename NodeRef, int N> struct OBBNodeMB_t;
+ template<typename NodeRef, int N> struct QuantizedNode_t;
+ template<typename NodeRef, int N> struct QuantizedNodeMB_t;
+
+ /*! Pointer that points to a node or a list of primitives */
+ template<int N>
+ struct NodeRefPtr
+ {
+ //template<int NN> friend class BVHN;
+
+ /*! Number of bytes the nodes and primitives are minimally aligned to.*/
+ static const size_t byteAlignment = 16;
+ static const size_t byteNodeAlignment = 4*N;
+
+ /*! highest address bit is used as barrier for some algorithms */
+ static const size_t barrier_mask = (1LL << (8*sizeof(size_t)-1));
+
+ /*! Masks the bits that store the number of items per leaf. */
+ static const size_t align_mask = byteAlignment-1;
+ static const size_t items_mask = byteAlignment-1;
+
+ /*! different supported node types */
+ static const size_t tyAABBNode = 0;
+ static const size_t tyAABBNodeMB = 1;
+ static const size_t tyAABBNodeMB4D = 6;
+ static const size_t tyOBBNode = 2;
+ static const size_t tyOBBNodeMB = 3;
+ static const size_t tyQuantizedNode = 5;
+ static const size_t tyLeaf = 8;
+
+ /*! Empty node */
+ static const size_t emptyNode = tyLeaf;
+
+ /*! Invalid node, used as marker in traversal */
+ static const size_t invalidNode = (((size_t)-1) & (~items_mask)) | (tyLeaf+0);
+ static const size_t popRay = (((size_t)-1) & (~items_mask)) | (tyLeaf+1);
+
+ /*! Maximum number of primitive blocks in a leaf. */
+ static const size_t maxLeafBlocks = items_mask-tyLeaf;
+
+ /*! Default constructor */
+ __forceinline NodeRefPtr () {}
+
+ /*! Construction from integer */
+ __forceinline NodeRefPtr (size_t ptr) : ptr(ptr) {}
+
+ /*! Cast to size_t */
+ __forceinline operator size_t() const { return ptr; }
+
+ /*! Sets the barrier bit. */
+ __forceinline void setBarrier() {
+#if defined(__X86_64__) || defined(__aarch64__)
+ assert(!isBarrier());
+ ptr |= barrier_mask;
+#else
+ assert(false);
+#endif
+ }
+
+ /*! Clears the barrier bit. */
+ __forceinline void clearBarrier() {
+#if defined(__X86_64__) || defined(__aarch64__)
+ ptr &= ~barrier_mask;
+#else
+ assert(false);
+#endif
+ }
+
+ /*! Checks if this is an barrier. A barrier tells the top level tree rotations how deep to enter the tree. */
+ __forceinline bool isBarrier() const { return (ptr & barrier_mask) != 0; }
+
+ /*! checks if this is a leaf */
+ __forceinline size_t isLeaf() const { return ptr & tyLeaf; }
+
+ /*! returns node type */
+ __forceinline int type() const { return ptr & (size_t)align_mask; }
+
+ /*! checks if this is a node */
+ __forceinline int isAABBNode() const { return (ptr & (size_t)align_mask) == tyAABBNode; }
+
+ /*! checks if this is a motion blur node */
+ __forceinline int isAABBNodeMB() const { return (ptr & (size_t)align_mask) == tyAABBNodeMB; }
+
+ /*! checks if this is a 4D motion blur node */
+ __forceinline int isAABBNodeMB4D() const { return (ptr & (size_t)align_mask) == tyAABBNodeMB4D; }
+
+ /*! checks if this is a node with unaligned bounding boxes */
+ __forceinline int isOBBNode() const { return (ptr & (size_t)align_mask) == tyOBBNode; }
+
+ /*! checks if this is a motion blur node with unaligned bounding boxes */
+ __forceinline int isOBBNodeMB() const { return (ptr & (size_t)align_mask) == tyOBBNodeMB; }
+
+ /*! checks if this is a quantized node */
+ __forceinline int isQuantizedNode() const { return (ptr & (size_t)align_mask) == tyQuantizedNode; }
+
+ /*! Encodes a node */
+ static __forceinline NodeRefPtr encodeNode(AABBNode_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node);
+ }
+
+ static __forceinline NodeRefPtr encodeNode(AABBNodeMB_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node | tyAABBNodeMB);
+ }
+
+ static __forceinline NodeRefPtr encodeNode(AABBNodeMB4D_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node | tyAABBNodeMB4D);
+ }
+
+ /*! Encodes an unaligned node */
+ static __forceinline NodeRefPtr encodeNode(OBBNode_t<NodeRefPtr,N>* node) {
+ return NodeRefPtr((size_t) node | tyOBBNode);
+ }
+
+ /*! Encodes an unaligned motion blur node */
+ static __forceinline NodeRefPtr encodeNode(OBBNodeMB_t<NodeRefPtr,N>* node) {
+ return NodeRefPtr((size_t) node | tyOBBNodeMB);
+ }
+
+ /*! Encodes a leaf */
+ static __forceinline NodeRefPtr encodeLeaf(void* tri, size_t num) {
+ assert(!((size_t)tri & align_mask));
+ assert(num <= maxLeafBlocks);
+ return NodeRefPtr((size_t)tri | (tyLeaf+min(num,(size_t)maxLeafBlocks)));
+ }
+
+ /*! Encodes a leaf */
+ static __forceinline NodeRefPtr encodeTypedLeaf(void* ptr, size_t ty) {
+ assert(!((size_t)ptr & align_mask));
+ return NodeRefPtr((size_t)ptr | (tyLeaf+ty));
+ }
+
+ /*! returns base node pointer */
+ __forceinline BaseNode_t<NodeRefPtr,N>* baseNode()
+ {
+ assert(!isLeaf());
+ return (BaseNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask);
+ }
+ __forceinline const BaseNode_t<NodeRefPtr,N>* baseNode() const
+ {
+ assert(!isLeaf());
+ return (const BaseNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask);
+ }
+
+ /*! returns node pointer */
+ __forceinline AABBNode_t<NodeRefPtr,N>* getAABBNode() { assert(isAABBNode()); return ( AABBNode_t<NodeRefPtr,N>*)ptr; }
+ __forceinline const AABBNode_t<NodeRefPtr,N>* getAABBNode() const { assert(isAABBNode()); return (const AABBNode_t<NodeRefPtr,N>*)ptr; }
+
+ /*! returns motion blur node pointer */
+ __forceinline AABBNodeMB_t<NodeRefPtr,N>* getAABBNodeMB() { assert(isAABBNodeMB() || isAABBNodeMB4D()); return ( AABBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const AABBNodeMB_t<NodeRefPtr,N>* getAABBNodeMB() const { assert(isAABBNodeMB() || isAABBNodeMB4D()); return (const AABBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns 4D motion blur node pointer */
+ __forceinline AABBNodeMB4D_t<NodeRefPtr,N>* getAABBNodeMB4D() { assert(isAABBNodeMB4D()); return ( AABBNodeMB4D_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const AABBNodeMB4D_t<NodeRefPtr,N>* getAABBNodeMB4D() const { assert(isAABBNodeMB4D()); return (const AABBNodeMB4D_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns unaligned node pointer */
+ __forceinline OBBNode_t<NodeRefPtr,N>* ungetAABBNode() { assert(isOBBNode()); return ( OBBNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const OBBNode_t<NodeRefPtr,N>* ungetAABBNode() const { assert(isOBBNode()); return (const OBBNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns unaligned motion blur node pointer */
+ __forceinline OBBNodeMB_t<NodeRefPtr,N>* ungetAABBNodeMB() { assert(isOBBNodeMB()); return ( OBBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const OBBNodeMB_t<NodeRefPtr,N>* ungetAABBNodeMB() const { assert(isOBBNodeMB()); return (const OBBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns quantized node pointer */
+ __forceinline QuantizedNode_t<NodeRefPtr,N>* quantizedNode() { assert(isQuantizedNode()); return ( QuantizedNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask ); }
+ __forceinline const QuantizedNode_t<NodeRefPtr,N>* quantizedNode() const { assert(isQuantizedNode()); return (const QuantizedNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask ); }
+
+ /*! returns leaf pointer */
+ __forceinline char* leaf(size_t& num) const {
+ assert(isLeaf());
+ num = (ptr & (size_t)items_mask)-tyLeaf;
+ return (char*)(ptr & ~(size_t)align_mask);
+ }
+
+ /*! clear all bit flags */
+ __forceinline void clearFlags() {
+ ptr &= ~(size_t)align_mask;
+ }
+
+ /*! returns the wideness */
+ __forceinline size_t getN() const { return N; }
+
+ public:
+ size_t ptr;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.cpp
new file mode 100644
index 0000000000..a273c21e8b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.cpp
@@ -0,0 +1,247 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_refit.h"
+#include "bvh_statistics.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ static const size_t SINGLE_THREAD_THRESHOLD = 4*1024;
+
+ template<int N>
+ __forceinline bool compare(const typename BVHN<N>::NodeRef* a, const typename BVHN<N>::NodeRef* b)
+ {
+ size_t sa = *(size_t*)&a->node()->lower_x;
+ size_t sb = *(size_t*)&b->node()->lower_x;
+ return sa < sb;
+ }
+
+ template<int N>
+ BVHNRefitter<N>::BVHNRefitter (BVH* bvh, const LeafBoundsInterface& leafBounds)
+ : bvh(bvh), leafBounds(leafBounds), numSubTrees(0)
+ {
+ }
+
+ template<int N>
+ void BVHNRefitter<N>::refit()
+ {
+ if (bvh->numPrimitives <= SINGLE_THREAD_THRESHOLD) {
+ bvh->bounds = LBBox3fa(recurse_bottom(bvh->root));
+ }
+ else
+ {
+ BBox3fa subTreeBounds[MAX_NUM_SUB_TREES];
+ numSubTrees = 0;
+ gather_subtree_refs(bvh->root,numSubTrees,0);
+ if (numSubTrees)
+ parallel_for(size_t(0), numSubTrees, size_t(1), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ NodeRef& ref = subTrees[i];
+ subTreeBounds[i] = recurse_bottom(ref);
+ }
+ });
+
+ numSubTrees = 0;
+ bvh->bounds = LBBox3fa(refit_toplevel(bvh->root,numSubTrees,subTreeBounds,0));
+ }
+ }
+
+ template<int N>
+ void BVHNRefitter<N>::gather_subtree_refs(NodeRef& ref,
+ size_t &subtrees,
+ const size_t depth)
+ {
+ if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)
+ {
+ assert(subtrees < MAX_NUM_SUB_TREES);
+ subTrees[subtrees++] = ref;
+ return;
+ }
+
+ if (ref.isAABBNode())
+ {
+ AABBNode* node = ref.getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ NodeRef& child = node->child(i);
+ if (unlikely(child == BVH::emptyNode)) continue;
+ gather_subtree_refs(child,subtrees,depth+1);
+ }
+ }
+ }
+
+ template<int N>
+ BBox3fa BVHNRefitter<N>::refit_toplevel(NodeRef& ref,
+ size_t &subtrees,
+ const BBox3fa *const subTreeBounds,
+ const size_t depth)
+ {
+ if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)
+ {
+ assert(subtrees < MAX_NUM_SUB_TREES);
+ assert(subTrees[subtrees] == ref);
+ return subTreeBounds[subtrees++];
+ }
+
+ if (ref.isAABBNode())
+ {
+ AABBNode* node = ref.getAABBNode();
+ BBox3fa bounds[N];
+
+ for (size_t i=0; i<N; i++)
+ {
+ NodeRef& child = node->child(i);
+
+ if (unlikely(child == BVH::emptyNode))
+ bounds[i] = BBox3fa(empty);
+ else
+ bounds[i] = refit_toplevel(child,subtrees,subTreeBounds,depth+1);
+ }
+
+ BBox3vf<N> boundsT = transpose<N>(bounds);
+
+ /* set new bounds */
+ node->lower_x = boundsT.lower.x;
+ node->lower_y = boundsT.lower.y;
+ node->lower_z = boundsT.lower.z;
+ node->upper_x = boundsT.upper.x;
+ node->upper_y = boundsT.upper.y;
+ node->upper_z = boundsT.upper.z;
+
+ return merge<N>(bounds);
+ }
+ else
+ return leafBounds.leafBounds(ref);
+ }
+
+ // =========================================================
+ // =========================================================
+ // =========================================================
+
+
+ template<int N>
+ BBox3fa BVHNRefitter<N>::recurse_bottom(NodeRef& ref)
+ {
+ /* this is a leaf node */
+ if (unlikely(ref.isLeaf()))
+ return leafBounds.leafBounds(ref);
+
+ /* recurse if this is an internal node */
+ AABBNode* node = ref.getAABBNode();
+
+ /* enable exclusive prefetch for >= AVX platforms */
+#if defined(__AVX__)
+ BVH::prefetchW(ref);
+#endif
+ BBox3fa bounds[N];
+
+ for (size_t i=0; i<N; i++)
+ if (unlikely(node->child(i) == BVH::emptyNode))
+ {
+ bounds[i] = BBox3fa(empty);
+ }
+ else
+ bounds[i] = recurse_bottom(node->child(i));
+
+ /* AOS to SOA transform */
+ BBox3vf<N> boundsT = transpose<N>(bounds);
+
+ /* set new bounds */
+ node->lower_x = boundsT.lower.x;
+ node->lower_y = boundsT.lower.y;
+ node->lower_z = boundsT.lower.z;
+ node->upper_x = boundsT.upper.x;
+ node->upper_y = boundsT.upper.y;
+ node->upper_z = boundsT.upper.z;
+
+ return merge<N>(bounds);
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ BVHNRefitT<N,Mesh,Primitive>::BVHNRefitT (BVH* bvh, Builder* builder, Mesh* mesh, size_t mode)
+ : bvh(bvh), builder(builder), refitter(new BVHNRefitter<N>(bvh,*(typename BVHNRefitter<N>::LeafBoundsInterface*)this)), mesh(mesh), topologyVersion(0) {}
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNRefitT<N,Mesh,Primitive>::clear()
+ {
+ if (builder)
+ builder->clear();
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNRefitT<N,Mesh,Primitive>::build()
+ {
+ if (mesh->topologyChanged(topologyVersion)) {
+ topologyVersion = mesh->getTopologyVersion();
+ builder->build();
+ }
+ else
+ refitter->refit();
+ }
+
+ template class BVHNRefitter<4>;
+#if defined(__AVX__)
+ template class BVHNRefitter<8>;
+#endif
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+
+ Builder* BVH4Triangle4MeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4> ((BVH4*)accel,BVH4Triangle4MeshBuilderSAH (accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH4Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4v>((BVH4*)accel,BVH4Triangle4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH4Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4i>((BVH4*)accel,BVH4Triangle4iMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+
+ Builder* BVH8Triangle4MeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4> ((BVH8*)accel,BVH8Triangle4MeshBuilderSAH (accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH8Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4v>((BVH8*)accel,BVH8Triangle4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH8Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4i>((BVH8*)accel,BVH8Triangle4iMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,QuadMesh,Quad4v>((BVH4*)accel,BVH4Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,QuadMesh,Quad4v>((BVH8*)accel,BVH8Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,UserGeometry,Object>((BVH4*)accel,BVH4VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,UserGeometry,Object>((BVH8*)accel,BVH8VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode);
+ Builder* BVH4InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,Instance,InstancePrimitive>((BVH4*)accel,BVH4InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode);
+ Builder* BVH8InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,Instance,InstancePrimitive>((BVH8*)accel,BVH8InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.h
new file mode 100644
index 0000000000..4aa9bdd7cc
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_refit.h
@@ -0,0 +1,95 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNRefitter
+ {
+ public:
+
+ /*! Type shortcuts */
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ struct LeafBoundsInterface {
+ virtual const BBox3fa leafBounds(NodeRef& ref) const = 0;
+ };
+
+ public:
+
+ /*! Constructor. */
+ BVHNRefitter (BVH* bvh, const LeafBoundsInterface& leafBounds);
+
+ /*! refits the BVH */
+ void refit();
+
+ private:
+ /* single-threaded subtree extraction based on BVH depth */
+ void gather_subtree_refs(NodeRef& ref,
+ size_t &subtrees,
+ const size_t depth = 0);
+
+ /* single-threaded top-level refit */
+ BBox3fa refit_toplevel(NodeRef& ref,
+ size_t &subtrees,
+ const BBox3fa *const subTreeBounds,
+ const size_t depth = 0);
+
+ /* single-threaded subtree refit */
+ BBox3fa recurse_bottom(NodeRef& ref);
+
+ public:
+ BVH* bvh; //!< BVH to refit
+ const LeafBoundsInterface& leafBounds; //!< calculates bounds of leaves
+
+ static const size_t MAX_SUB_TREE_EXTRACTION_DEPTH = (N==4) ? 4 : (N==8) ? 3 : 3;
+ static const size_t MAX_NUM_SUB_TREES = (N==4) ? 256 : (N==8) ? 512 : N*N*N; // N ^ MAX_SUB_TREE_EXTRACTION_DEPTH
+ size_t numSubTrees;
+ NodeRef subTrees[MAX_NUM_SUB_TREES];
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNRefitT : public Builder, public BVHNRefitter<N>::LeafBoundsInterface
+ {
+ public:
+
+ /*! Type shortcuts */
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ public:
+ BVHNRefitT (BVH* bvh, Builder* builder, Mesh* mesh, size_t mode);
+
+ virtual void build();
+
+ virtual void clear();
+
+ virtual const BBox3fa leafBounds (NodeRef& ref) const
+ {
+ size_t num; char* prim = ref.leaf(num);
+ if (unlikely(ref == BVH::emptyNode)) return empty;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++)
+ bounds.extend(((Primitive*)prim)[i].update(mesh));
+ return bounds;
+ }
+
+ private:
+ BVH* bvh;
+ std::unique_ptr<Builder> builder;
+ std::unique_ptr<BVHNRefitter<N>> refitter;
+ Mesh* mesh;
+ unsigned int topologyVersion;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.cpp
new file mode 100644
index 0000000000..2bb431bf0e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.cpp
@@ -0,0 +1,127 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_rotate.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Computes half surface area of box. */
+ __forceinline float halfArea3f(const BBox<vfloat4>& box) {
+ const vfloat4 d = box.size();
+ const vfloat4 a = d*shuffle<1,2,0,3>(d);
+ return a[0]+a[1]+a[2];
+ }
+
+ size_t BVHNRotate<4>::rotate(NodeRef parentRef, size_t depth)
+ {
+ /*! nothing to rotate if we reached a leaf node. */
+ if (parentRef.isBarrier()) return 0;
+ if (parentRef.isLeaf()) return 0;
+ AABBNode* parent = parentRef.getAABBNode();
+
+ /*! rotate all children first */
+ vint4 cdepth;
+ for (size_t c=0; c<4; c++)
+ cdepth[c] = (int)rotate(parent->child(c),depth+1);
+
+ /* compute current areas of all children */
+ vfloat4 sizeX = parent->upper_x-parent->lower_x;
+ vfloat4 sizeY = parent->upper_y-parent->lower_y;
+ vfloat4 sizeZ = parent->upper_z-parent->lower_z;
+ vfloat4 childArea = madd(sizeX,(sizeY + sizeZ),sizeY*sizeZ);
+
+ /*! get node bounds */
+ BBox<vfloat4> child1_0,child1_1,child1_2,child1_3;
+ parent->bounds(child1_0,child1_1,child1_2,child1_3);
+
+ /*! Find best rotation. We pick a first child (child1) and a sub-child
+ (child2child) of a different second child (child2), and swap child1
+ and child2child. We perform the best such swap. */
+ float bestArea = 0;
+ size_t bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1;
+ for (size_t c2=0; c2<4; c2++)
+ {
+ /*! ignore leaf nodes as we cannot descent into them */
+ if (parent->child(c2).isBarrier()) continue;
+ if (parent->child(c2).isLeaf()) continue;
+ AABBNode* child2 = parent->child(c2).getAABBNode();
+
+ /*! transpose child bounds */
+ BBox<vfloat4> child2c0,child2c1,child2c2,child2c3;
+ child2->bounds(child2c0,child2c1,child2c2,child2c3);
+
+ /*! put child1_0 at each child2 position */
+ float cost00 = halfArea3f(merge(child1_0,child2c1,child2c2,child2c3));
+ float cost01 = halfArea3f(merge(child2c0,child1_0,child2c2,child2c3));
+ float cost02 = halfArea3f(merge(child2c0,child2c1,child1_0,child2c3));
+ float cost03 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_0));
+ vfloat4 cost0 = vfloat4(cost00,cost01,cost02,cost03);
+ vfloat4 min0 = vreduce_min(cost0);
+ int pos0 = (int)bsf(movemask(min0 == cost0));
+
+ /*! put child1_1 at each child2 position */
+ float cost10 = halfArea3f(merge(child1_1,child2c1,child2c2,child2c3));
+ float cost11 = halfArea3f(merge(child2c0,child1_1,child2c2,child2c3));
+ float cost12 = halfArea3f(merge(child2c0,child2c1,child1_1,child2c3));
+ float cost13 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_1));
+ vfloat4 cost1 = vfloat4(cost10,cost11,cost12,cost13);
+ vfloat4 min1 = vreduce_min(cost1);
+ int pos1 = (int)bsf(movemask(min1 == cost1));
+
+ /*! put child1_2 at each child2 position */
+ float cost20 = halfArea3f(merge(child1_2,child2c1,child2c2,child2c3));
+ float cost21 = halfArea3f(merge(child2c0,child1_2,child2c2,child2c3));
+ float cost22 = halfArea3f(merge(child2c0,child2c1,child1_2,child2c3));
+ float cost23 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_2));
+ vfloat4 cost2 = vfloat4(cost20,cost21,cost22,cost23);
+ vfloat4 min2 = vreduce_min(cost2);
+ int pos2 = (int)bsf(movemask(min2 == cost2));
+
+ /*! put child1_3 at each child2 position */
+ float cost30 = halfArea3f(merge(child1_3,child2c1,child2c2,child2c3));
+ float cost31 = halfArea3f(merge(child2c0,child1_3,child2c2,child2c3));
+ float cost32 = halfArea3f(merge(child2c0,child2c1,child1_3,child2c3));
+ float cost33 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_3));
+ vfloat4 cost3 = vfloat4(cost30,cost31,cost32,cost33);
+ vfloat4 min3 = vreduce_min(cost3);
+ int pos3 = (int)bsf(movemask(min3 == cost3));
+
+ /*! find best other child */
+ vfloat4 area0123 = vfloat4(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)) - vfloat4(childArea[c2]);
+ int pos[4] = { pos0,pos1,pos2,pos3 };
+ const size_t mbd = BVH4::maxBuildDepth;
+ vbool4 valid = vint4(int(depth+1))+cdepth <= vint4(mbd); // only select swaps that fulfill depth constraints
+ valid &= vint4(int(c2)) != vint4(step);
+ if (none(valid)) continue;
+ size_t c1 = select_min(valid,area0123);
+ float area = area0123[c1];
+ if (c1 == c2) continue; // can happen if bounds are NANs
+
+ /*! accept a swap when it reduces cost and is not swapping a node with itself */
+ if (area < bestArea) {
+ bestArea = area;
+ bestChild1 = c1;
+ bestChild2 = c2;
+ bestChild2Child = pos[c1];
+ }
+ }
+
+ /*! if we did not find a swap that improves the SAH then do nothing */
+ if (bestChild1 == size_t(-1)) return 1+reduce_max(cdepth);
+
+ /*! perform the best found tree rotation */
+ AABBNode* child2 = parent->child(bestChild2).getAABBNode();
+ AABBNode::swap(parent,bestChild1,child2,bestChild2Child);
+ parent->setBounds(bestChild2,child2->bounds());
+ AABBNode::compact(parent);
+ AABBNode::compact(child2);
+
+ /*! This returned depth is conservative as the child that was
+ * pulled up in the tree could have been on the critical path. */
+ cdepth[bestChild1]++; // bestChild1 was pushed down one level
+ return 1+reduce_max(cdepth);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.h
new file mode 100644
index 0000000000..009bef339e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_rotate.h
@@ -0,0 +1,37 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNRotate
+ {
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ public:
+ static const bool enabled = false;
+
+ static __forceinline size_t rotate(NodeRef parentRef, size_t depth = 1) { return 0; }
+ static __forceinline void restructure(NodeRef ref, size_t depth = 1) {}
+ };
+
+ /* BVH4 tree rotations */
+ template<>
+ class BVHNRotate<4>
+ {
+ typedef BVH4::AABBNode AABBNode;
+ typedef BVH4::NodeRef NodeRef;
+
+ public:
+ static const bool enabled = true;
+
+ static size_t rotate(NodeRef parentRef, size_t depth = 1);
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp
new file mode 100644
index 0000000000..aa56035026
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp
@@ -0,0 +1,168 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_statistics.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ template<int N>
+ BVHNStatistics<N>::BVHNStatistics (BVH* bvh) : bvh(bvh)
+ {
+ double A = max(0.0f,bvh->getLinearBounds().expectedHalfArea());
+ stat = statistics(bvh->root,A,BBox1f(0.0f,1.0f));
+ }
+
+ template<int N>
+ std::string BVHNStatistics<N>::str()
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << " primitives = " << bvh->numPrimitives << ", vertices = " << bvh->numVertices << ", depth = " << stat.depth << std::endl;
+ size_t totalBytes = stat.bytes(bvh);
+ double totalSAH = stat.sah(bvh);
+ stream << " total : sah = " << std::setw(7) << std::setprecision(3) << totalSAH << " (100.00%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << totalBytes/1E6 << " MB (100.00%), ";
+ stream << "#nodes = " << std::setw(7) << stat.size() << " (" << std::setw(6) << std::setprecision(2) << 100.0*stat.fillRate(bvh) << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(totalBytes)/double(bvh->numPrimitives) << std::endl;
+ if (stat.statAABBNodes.numNodes ) stream << " getAABBNodes : " << stat.statAABBNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statOBBNodes.numNodes ) stream << " ungetAABBNodes : " << stat.statOBBNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statAABBNodesMB.numNodes ) stream << " getAABBNodesMB : " << stat.statAABBNodesMB.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statAABBNodesMB4D.numNodes) stream << " getAABBNodesMB4D : " << stat.statAABBNodesMB4D.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statOBBNodesMB.numNodes) stream << " ungetAABBNodesMB : " << stat.statOBBNodesMB.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statQuantizedNodes.numNodes ) stream << " quantizedNodes : " << stat.statQuantizedNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (true) stream << " leaves : " << stat.statLeaf.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (true) stream << " histogram : " << stat.statLeaf.histToString() << std::endl;
+ return stream.str();
+ }
+
+ template<int N>
+ typename BVHNStatistics<N>::Statistics BVHNStatistics<N>::statistics(NodeRef node, const double A, const BBox1f t0t1)
+ {
+ Statistics s;
+ assert(t0t1.size() > 0.0f);
+ double dt = max(0.0f,t0t1.size());
+ if (node.isAABBNode())
+ {
+ AABBNode* n = node.getAABBNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extend(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statAABBNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodes.numNodes++;
+ s.statAABBNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isOBBNode())
+ {
+ OBBNode* n = node.ungetAABBNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statOBBNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statOBBNodes.numNodes++;
+ s.statOBBNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isAABBNodeMB())
+ {
+ AABBNodeMB* n = node.getAABBNodeMB();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,n->expectedHalfArea(i,t0t1));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statAABBNodesMB.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodesMB.numNodes++;
+ s.statAABBNodesMB.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isAABBNodeMB4D())
+ {
+ AABBNodeMB4D* n = node.getAABBNodeMB4D();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const BBox1f t0t1i = intersect(t0t1,n->timeRange(i));
+ assert(!t0t1i.empty());
+ const double Ai = n->AABBNodeMB::expectedHalfArea(i,t0t1i);
+ Statistics s = statistics(n->child(i),Ai,t0t1i);
+ s.statAABBNodesMB4D.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodesMB4D.numNodes++;
+ s.statAABBNodesMB4D.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isOBBNodeMB())
+ {
+ OBBNodeMB* n = node.ungetAABBNodeMB();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent0(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statOBBNodesMB.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statOBBNodesMB.numNodes++;
+ s.statOBBNodesMB.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isQuantizedNode())
+ {
+ QuantizedNode* n = node.quantizedNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statQuantizedNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statQuantizedNodes.numNodes++;
+ s.statQuantizedNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isLeaf())
+ {
+ size_t num; const char* tri = node.leaf(num);
+ if (num)
+ {
+ for (size_t i=0; i<num; i++)
+ {
+ const size_t bytes = bvh->primTy->getBytes(tri);
+ s.statLeaf.numPrimsActive += bvh->primTy->sizeActive(tri);
+ s.statLeaf.numPrimsTotal += bvh->primTy->sizeTotal(tri);
+ s.statLeaf.numBytes += bytes;
+ tri+=bytes;
+ }
+ s.statLeaf.numLeaves++;
+ s.statLeaf.numPrimBlocks += num;
+ s.statLeaf.leafSAH += dt*A*num;
+ if (num-1 < Statistics::LeafStat::NHIST) {
+ s.statLeaf.numPrimBlocksHistogram[num-1]++;
+ }
+ }
+ }
+ else {
+ // -- GODOT start --
+ // throw std::runtime_error("not supported node type in bvh_statistics");
+ abort();
+ // -- GODOT end --
+ }
+ return s;
+ }
+
+#if defined(__AVX__)
+ template class BVHNStatistics<8>;
+#endif
+
+#if !defined(__AVX__) || (!defined(EMBREE_TARGET_SSE2) && !defined(EMBREE_TARGET_SSE42)) || defined(__aarch64__)
+ template class BVHNStatistics<4>;
+#endif
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.h
new file mode 100644
index 0000000000..73dfc6fbcc
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.h
@@ -0,0 +1,285 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include <sstream>
+
+namespace embree
+{
+ template<int N>
+ class BVHNStatistics
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::OBBNode OBBNode;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+ typedef typename BVH::OBBNodeMB OBBNodeMB;
+ typedef typename BVH::QuantizedNode QuantizedNode;
+
+ typedef typename BVH::NodeRef NodeRef;
+
+ struct Statistics
+ {
+ template<typename Node>
+ struct NodeStat
+ {
+ NodeStat ( double nodeSAH = 0,
+ size_t numNodes = 0,
+ size_t numChildren = 0)
+ : nodeSAH(nodeSAH),
+ numNodes(numNodes),
+ numChildren(numChildren) {}
+
+ double sah(BVH* bvh) const {
+ return nodeSAH/bvh->getLinearBounds().expectedHalfArea();
+ }
+
+ size_t bytes() const {
+ return numNodes*sizeof(Node);
+ }
+
+ size_t size() const {
+ return numNodes;
+ }
+
+ double fillRateNom () const { return double(numChildren); }
+ double fillRateDen () const { return double(numNodes*N); }
+ double fillRate () const { return fillRateNom()/fillRateDen(); }
+
+ __forceinline friend NodeStat operator+ ( const NodeStat& a, const NodeStat& b)
+ {
+ return NodeStat(a.nodeSAH + b.nodeSAH,
+ a.numNodes+b.numNodes,
+ a.numChildren+b.numChildren);
+ }
+
+ std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
+ stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << bytes()/1E6 << " MB ";
+ stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes())/double(bytesTotal) << "%), ";
+ stream << "#nodes = " << std::setw(7) << numNodes << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate() << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes())/double(bvh->numPrimitives);
+ return stream.str();
+ }
+
+ public:
+ double nodeSAH;
+ size_t numNodes;
+ size_t numChildren;
+ };
+
+ struct LeafStat
+ {
+ static const int NHIST = 8;
+
+ LeafStat ( double leafSAH = 0.0f,
+ size_t numLeaves = 0,
+ size_t numPrimsActive = 0,
+ size_t numPrimsTotal = 0,
+ size_t numPrimBlocks = 0,
+ size_t numBytes = 0)
+ : leafSAH(leafSAH),
+ numLeaves(numLeaves),
+ numPrimsActive(numPrimsActive),
+ numPrimsTotal(numPrimsTotal),
+ numPrimBlocks(numPrimBlocks),
+ numBytes(numBytes)
+ {
+ for (size_t i=0; i<NHIST; i++)
+ numPrimBlocksHistogram[i] = 0;
+ }
+
+ double sah(BVH* bvh) const {
+ return leafSAH/bvh->getLinearBounds().expectedHalfArea();
+ }
+
+ size_t bytes(BVH* bvh) const {
+ return numBytes;
+ }
+
+ size_t size() const {
+ return numLeaves;
+ }
+
+ double fillRateNom (BVH* bvh) const { return double(numPrimsActive); }
+ double fillRateDen (BVH* bvh) const { return double(numPrimsTotal); }
+ double fillRate (BVH* bvh) const { return fillRateNom(bvh)/fillRateDen(bvh); }
+
+ __forceinline friend LeafStat operator+ ( const LeafStat& a, const LeafStat& b)
+ {
+ LeafStat stat(a.leafSAH + b.leafSAH,
+ a.numLeaves+b.numLeaves,
+ a.numPrimsActive+b.numPrimsActive,
+ a.numPrimsTotal+b.numPrimsTotal,
+ a.numPrimBlocks+b.numPrimBlocks,
+ a.numBytes+b.numBytes);
+ for (size_t i=0; i<NHIST; i++) {
+ stat.numPrimBlocksHistogram[i] += a.numPrimBlocksHistogram[i];
+ stat.numPrimBlocksHistogram[i] += b.numPrimBlocksHistogram[i];
+ }
+ return stat;
+ }
+
+ std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
+ stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << double(bytes(bvh))/1E6 << " MB ";
+ stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes(bvh))/double(bytesTotal) << "%), ";
+ stream << "#nodes = " << std::setw(7) << numLeaves << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate(bvh) << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes(bvh))/double(bvh->numPrimitives);
+ return stream.str();
+ }
+
+ std::string histToString() const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ for (size_t i=0; i<NHIST; i++)
+ stream << std::setw(6) << std::setprecision(2) << 100.0f*float(numPrimBlocksHistogram[i])/float(numLeaves) << "% ";
+ return stream.str();
+ }
+
+ public:
+ double leafSAH; //!< SAH of the leaves only
+ size_t numLeaves; //!< Number of leaf nodes.
+ size_t numPrimsActive; //!< Number of active primitives (
+ size_t numPrimsTotal; //!< Number of active and inactive primitives
+ size_t numPrimBlocks; //!< Number of primitive blocks.
+ size_t numBytes; //!< Number of bytes of leaves.
+ size_t numPrimBlocksHistogram[8];
+ };
+
+ public:
+ Statistics (size_t depth = 0,
+ LeafStat statLeaf = LeafStat(),
+ NodeStat<AABBNode> statAABBNodes = NodeStat<AABBNode>(),
+ NodeStat<OBBNode> statOBBNodes = NodeStat<OBBNode>(),
+ NodeStat<AABBNodeMB> statAABBNodesMB = NodeStat<AABBNodeMB>(),
+ NodeStat<AABBNodeMB4D> statAABBNodesMB4D = NodeStat<AABBNodeMB4D>(),
+ NodeStat<OBBNodeMB> statOBBNodesMB = NodeStat<OBBNodeMB>(),
+ NodeStat<QuantizedNode> statQuantizedNodes = NodeStat<QuantizedNode>())
+
+ : depth(depth),
+ statLeaf(statLeaf),
+ statAABBNodes(statAABBNodes),
+ statOBBNodes(statOBBNodes),
+ statAABBNodesMB(statAABBNodesMB),
+ statAABBNodesMB4D(statAABBNodesMB4D),
+ statOBBNodesMB(statOBBNodesMB),
+ statQuantizedNodes(statQuantizedNodes) {}
+
+ double sah(BVH* bvh) const
+ {
+ return statLeaf.sah(bvh) +
+ statAABBNodes.sah(bvh) +
+ statOBBNodes.sah(bvh) +
+ statAABBNodesMB.sah(bvh) +
+ statAABBNodesMB4D.sah(bvh) +
+ statOBBNodesMB.sah(bvh) +
+ statQuantizedNodes.sah(bvh);
+ }
+
+ size_t bytes(BVH* bvh) const {
+ return statLeaf.bytes(bvh) +
+ statAABBNodes.bytes() +
+ statOBBNodes.bytes() +
+ statAABBNodesMB.bytes() +
+ statAABBNodesMB4D.bytes() +
+ statOBBNodesMB.bytes() +
+ statQuantizedNodes.bytes();
+ }
+
+ size_t size() const
+ {
+ return statLeaf.size() +
+ statAABBNodes.size() +
+ statOBBNodes.size() +
+ statAABBNodesMB.size() +
+ statAABBNodesMB4D.size() +
+ statOBBNodesMB.size() +
+ statQuantizedNodes.size();
+ }
+
+ double fillRate (BVH* bvh) const
+ {
+ double nom = statLeaf.fillRateNom(bvh) +
+ statAABBNodes.fillRateNom() +
+ statOBBNodes.fillRateNom() +
+ statAABBNodesMB.fillRateNom() +
+ statAABBNodesMB4D.fillRateNom() +
+ statOBBNodesMB.fillRateNom() +
+ statQuantizedNodes.fillRateNom();
+ double den = statLeaf.fillRateDen(bvh) +
+ statAABBNodes.fillRateDen() +
+ statOBBNodes.fillRateDen() +
+ statAABBNodesMB.fillRateDen() +
+ statAABBNodesMB4D.fillRateDen() +
+ statOBBNodesMB.fillRateDen() +
+ statQuantizedNodes.fillRateDen();
+ return nom/den;
+ }
+
+ friend Statistics operator+ ( const Statistics& a, const Statistics& b )
+ {
+ return Statistics(max(a.depth,b.depth),
+ a.statLeaf + b.statLeaf,
+ a.statAABBNodes + b.statAABBNodes,
+ a.statOBBNodes + b.statOBBNodes,
+ a.statAABBNodesMB + b.statAABBNodesMB,
+ a.statAABBNodesMB4D + b.statAABBNodesMB4D,
+ a.statOBBNodesMB + b.statOBBNodesMB,
+ a.statQuantizedNodes + b.statQuantizedNodes);
+ }
+
+ static Statistics add ( const Statistics& a, const Statistics& b ) {
+ return a+b;
+ }
+
+ public:
+ size_t depth;
+ LeafStat statLeaf;
+ NodeStat<AABBNode> statAABBNodes;
+ NodeStat<OBBNode> statOBBNodes;
+ NodeStat<AABBNodeMB> statAABBNodesMB;
+ NodeStat<AABBNodeMB4D> statAABBNodesMB4D;
+ NodeStat<OBBNodeMB> statOBBNodesMB;
+ NodeStat<QuantizedNode> statQuantizedNodes;
+ };
+
+ public:
+
+ /* Constructor gathers statistics. */
+ BVHNStatistics (BVH* bvh);
+
+ /*! Convert statistics into a string */
+ std::string str();
+
+ double sah() const {
+ return stat.sah(bvh);
+ }
+
+ size_t bytesUsed() const {
+ return stat.bytes(bvh);
+ }
+
+ private:
+ Statistics statistics(NodeRef node, const double A, const BBox1f dt);
+
+ private:
+ BVH* bvh;
+ Statistics stat;
+ };
+
+ typedef BVHNStatistics<4> BVH4Statistics;
+ typedef BVHNStatistics<8> BVH8Statistics;
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser1.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser1.h
new file mode 100644
index 0000000000..7f17084b81
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser1.h
@@ -0,0 +1,676 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "node_intersector1.h"
+#include "../common/stack_item.h"
+
+#define NEW_SORTING_CODE 1
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH regular node traversal for single rays. */
+ template<int N, int Nx, int types>
+ class BVHNNodeTraverser1Hit;
+
+ /*! Helper functions for fast sorting using AVX512 instructions. */
+#if defined(__AVX512ER__)
+
+ /* KNL code path */
+ __forceinline void isort_update(vfloat16 &dist, vllong8 &ptr, const vfloat16 &d, const vllong8 &p)
+ {
+ const vfloat16 dist_shift = align_shift_right<15>(dist,dist);
+ const vllong8 ptr_shift = align_shift_right<7>(ptr,ptr);
+ const vbool16 m_geq = d >= dist;
+ const vbool16 m_geq_shift = m_geq << 1;
+ dist = select(m_geq,d,dist);
+ ptr = select(vboold8(m_geq),p,ptr);
+ dist = select(m_geq_shift,dist_shift,dist);
+ ptr = select(vboold8(m_geq_shift),ptr_shift,ptr);
+ }
+
+ __forceinline void isort_quick_update(vfloat16 &dist, vllong8 &ptr, const vfloat16 &d, const vllong8 &p)
+ {
+ //dist = align_shift_right<15>(dist,d);
+ //ptr = align_shift_right<7>(ptr,p);
+ dist = align_shift_right<15>(dist,permute(d,vint16(zero)));
+ ptr = align_shift_right<7>(ptr,permute(p,vllong8(zero)));
+ }
+
+ template<int N, int Nx, int types, class NodeRef, class BaseNode>
+ __forceinline void traverseClosestHitAVX512(NodeRef& cur,
+ size_t mask,
+ const vfloat<Nx>& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ vllong8 children( vllong<N>::loadu((void*)node->children) );
+ children = vllong8::compact((int)mask,children);
+ vfloat16 distance = tNear;
+ distance = vfloat16::compact((int)mask,distance,tNear);
+
+ cur = toScalar(children);
+ BVHN<N>::prefetch(cur,types);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) return;
+
+ /* 2 hits: order A0 B0 */
+ const vllong8 c0(children);
+ const vfloat16 d0(distance);
+ children = align_shift_right<1>(children,children);
+ distance = align_shift_right<1>(distance,distance);
+ const vllong8 c1(children);
+ const vfloat16 d1(distance);
+
+ cur = toScalar(children);
+ BVHN<N>::prefetch(cur,types);
+
+ /* a '<' keeps the order for equal distances, scenes like powerplant largely benefit from it */
+ const vboolf16 m_dist = d0 < d1;
+ const vfloat16 dist_A0 = select(m_dist, d0, d1);
+ const vfloat16 dist_B0 = select(m_dist, d1, d0);
+ const vllong8 ptr_A0 = select(vboold8(m_dist), c0, c1);
+ const vllong8 ptr_B0 = select(vboold8(m_dist), c1, c0);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = toScalar(ptr_A0);
+ stackPtr[0].ptr = toScalar(ptr_B0);
+ *(float*)&stackPtr[0].dist = toScalar(dist_B0);
+ stackPtr++;
+ return;
+ }
+
+ /* 3 hits: order A1 B1 C1 */
+
+ children = align_shift_right<1>(children,children);
+ distance = align_shift_right<1>(distance,distance);
+
+ const vllong8 c2(children);
+ const vfloat16 d2(distance);
+
+ cur = toScalar(children);
+ BVHN<N>::prefetch(cur,types);
+
+ const vboolf16 m_dist1 = dist_A0 <= d2;
+ const vfloat16 dist_tmp_B1 = select(m_dist1, d2, dist_A0);
+ const vllong8 ptr_A1 = select(vboold8(m_dist1), ptr_A0, c2);
+ const vllong8 ptr_tmp_B1 = select(vboold8(m_dist1), c2, ptr_A0);
+
+ const vboolf16 m_dist2 = dist_B0 <= dist_tmp_B1;
+ const vfloat16 dist_B1 = select(m_dist2, dist_B0 , dist_tmp_B1);
+ const vfloat16 dist_C1 = select(m_dist2, dist_tmp_B1, dist_B0);
+ const vllong8 ptr_B1 = select(vboold8(m_dist2), ptr_B0, ptr_tmp_B1);
+ const vllong8 ptr_C1 = select(vboold8(m_dist2), ptr_tmp_B1, ptr_B0);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = toScalar(ptr_A1);
+ stackPtr[0].ptr = toScalar(ptr_C1);
+ *(float*)&stackPtr[0].dist = toScalar(dist_C1);
+ stackPtr[1].ptr = toScalar(ptr_B1);
+ *(float*)&stackPtr[1].dist = toScalar(dist_B1);
+ stackPtr+=2;
+ return;
+ }
+
+ /* 4 hits: order A2 B2 C2 D2 */
+
+ const vfloat16 dist_A1 = select(m_dist1, dist_A0, d2);
+
+ children = align_shift_right<1>(children,children);
+ distance = align_shift_right<1>(distance,distance);
+
+ const vllong8 c3(children);
+ const vfloat16 d3(distance);
+
+ cur = toScalar(children);
+ BVHN<N>::prefetch(cur,types);
+
+ const vboolf16 m_dist3 = dist_A1 <= d3;
+ const vfloat16 dist_tmp_B2 = select(m_dist3, d3, dist_A1);
+ const vllong8 ptr_A2 = select(vboold8(m_dist3), ptr_A1, c3);
+ const vllong8 ptr_tmp_B2 = select(vboold8(m_dist3), c3, ptr_A1);
+
+ const vboolf16 m_dist4 = dist_B1 <= dist_tmp_B2;
+ const vfloat16 dist_B2 = select(m_dist4, dist_B1 , dist_tmp_B2);
+ const vfloat16 dist_tmp_C2 = select(m_dist4, dist_tmp_B2, dist_B1);
+ const vllong8 ptr_B2 = select(vboold8(m_dist4), ptr_B1, ptr_tmp_B2);
+ const vllong8 ptr_tmp_C2 = select(vboold8(m_dist4), ptr_tmp_B2, ptr_B1);
+
+ const vboolf16 m_dist5 = dist_C1 <= dist_tmp_C2;
+ const vfloat16 dist_C2 = select(m_dist5, dist_C1 , dist_tmp_C2);
+ const vfloat16 dist_D2 = select(m_dist5, dist_tmp_C2, dist_C1);
+ const vllong8 ptr_C2 = select(vboold8(m_dist5), ptr_C1, ptr_tmp_C2);
+ const vllong8 ptr_D2 = select(vboold8(m_dist5), ptr_tmp_C2, ptr_C1);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = toScalar(ptr_A2);
+ stackPtr[0].ptr = toScalar(ptr_D2);
+ *(float*)&stackPtr[0].dist = toScalar(dist_D2);
+ stackPtr[1].ptr = toScalar(ptr_C2);
+ *(float*)&stackPtr[1].dist = toScalar(dist_C2);
+ stackPtr[2].ptr = toScalar(ptr_B2);
+ *(float*)&stackPtr[2].dist = toScalar(dist_B2);
+ stackPtr+=3;
+ return;
+ }
+
+ /* >=5 hits: reverse to descending order for writing to stack */
+
+ const size_t hits = 4 + popcnt(mask);
+ const vfloat16 dist_A2 = select(m_dist3, dist_A1, d3);
+ vfloat16 dist(neg_inf);
+ vllong8 ptr(zero);
+
+
+ isort_quick_update(dist,ptr,dist_A2,ptr_A2);
+ isort_quick_update(dist,ptr,dist_B2,ptr_B2);
+ isort_quick_update(dist,ptr,dist_C2,ptr_C2);
+ isort_quick_update(dist,ptr,dist_D2,ptr_D2);
+
+ do {
+
+ children = align_shift_right<1>(children,children);
+ distance = align_shift_right<1>(distance,distance);
+
+ cur = toScalar(children);
+ BVHN<N>::prefetch(cur,types);
+
+ const vfloat16 new_dist(permute(distance,vint16(zero)));
+ const vllong8 new_ptr(permute(children,vllong8(zero)));
+
+ mask &= mask-1;
+ isort_update(dist,ptr,new_dist,new_ptr);
+
+ } while(mask);
+
+ const vboold8 m_stack_ptr(0x55); // 10101010 (lsb -> msb)
+ const vboolf16 m_stack_dist(0x4444); // 0010001000100010 (lsb -> msb)
+
+ /* extract current noderef */
+ cur = toScalar(permute(ptr,vllong8(hits-1)));
+ /* rearrange pointers to beginning of 16 bytes block */
+ vllong8 stackElementA0;
+ stackElementA0 = vllong8::expand(m_stack_ptr,ptr,stackElementA0);
+ /* put distances in between */
+ vuint16 stackElementA1((__m512i)stackElementA0);
+ stackElementA1 = vuint16::expand(m_stack_dist,asUInt(dist),stackElementA1);
+ /* write out first 4 x 16 bytes block to stack */
+ vuint16::storeu(stackPtr,stackElementA1);
+ /* get upper half of dist and ptr */
+ dist = align_shift_right<4>(dist,dist);
+ ptr = align_shift_right<4>(ptr,ptr);
+ /* assemble and write out second block */
+ vllong8 stackElementB0;
+ stackElementB0 = vllong8::expand(m_stack_ptr,ptr,stackElementB0);
+ vuint16 stackElementB1((__m512i)stackElementB0);
+ stackElementB1 = vuint16::expand(m_stack_dist,asUInt(dist),stackElementB1);
+ vuint16::storeu(stackPtr + 4,stackElementB1);
+ /* increase stack pointer */
+ stackPtr += hits-1;
+ }
+#endif
+
+#if defined(__AVX512VL__) // SKX
+
+ template<int N>
+ __forceinline void isort_update(vint<N> &dist, const vint<N> &d)
+ {
+ const vint<N> dist_shift = align_shift_right<N-1>(dist,dist);
+ const vboolf<N> m_geq = d >= dist;
+ const vboolf<N> m_geq_shift = m_geq << 1;
+ dist = select(m_geq,d,dist);
+ dist = select(m_geq_shift,dist_shift,dist);
+ }
+
+ template<int N>
+ __forceinline void isort_quick_update(vint<N> &dist, const vint<N> &d) {
+ dist = align_shift_right<N-1>(dist,permute(d,vint<N>(zero)));
+ }
+
+ __forceinline size_t permuteExtract(const vint8& index, const vllong4& n0, const vllong4& n1) {
+ return toScalar(permutex2var((__m256i)index,n0,n1));
+ }
+
+ __forceinline float permuteExtract(const vint8& index, const vfloat8& n) {
+ return toScalar(permute(n,index));
+ }
+
+#endif
+
+ /* Specialization for BVH4. */
+ template<int Nx, int types>
+ class BVHNNodeTraverser1Hit<4, Nx, types>
+ {
+ typedef BVH4 BVH;
+ typedef BVH4::NodeRef NodeRef;
+ typedef BVH4::BaseNode BaseNode;
+
+
+ public:
+ /* Traverses a node with at least one hit child. Optimized for finding the closest hit (intersection). */
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t mask,
+ const vfloat<Nx>& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+#if defined(__AVX512ER__)
+ traverseClosestHitAVX512<4,Nx,types,NodeRef,BaseNode>(cur,mask,tNear,stackPtr,stackEnd);
+#else
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+ if (likely(mask == 0)) {
+ assert(cur != BVH::emptyNode);
+ return;
+ }
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ const unsigned int d0 = ((unsigned int*)&tNear)[r];
+ r = bscf(mask);
+ NodeRef c1 = node->child(r);
+ BVH::prefetch(c1,types);
+ const unsigned int d1 = ((unsigned int*)&tNear)[r];
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ assert(stackPtr < stackEnd);
+ if (d0 < d1) { stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; cur = c0; return; }
+ else { stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; cur = c1; return; }
+ }
+
+#if NEW_SORTING_CODE == 1
+ vint4 s0((size_t)c0,(size_t)d0);
+ vint4 s1((size_t)c1,(size_t)d1);
+ r = bscf(mask);
+ NodeRef c2 = node->child(r); BVH::prefetch(c2,types); unsigned int d2 = ((unsigned int*)&tNear)[r];
+ vint4 s2((size_t)c2,(size_t)d2);
+ /* 3 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort3(s0,s1,s2);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1;
+ cur = toSizeT(s2);
+ stackPtr+=2;
+ return;
+ }
+ r = bscf(mask);
+ NodeRef c3 = node->child(r); BVH::prefetch(c3,types); unsigned int d3 = ((unsigned int*)&tNear)[r];
+ vint4 s3((size_t)c3,(size_t)d3);
+ /* 4 hits */
+ StackItemT<NodeRef>::sort4(s0,s1,s2,s3);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2;
+ cur = toSizeT(s3);
+ stackPtr+=3;
+#else
+ /*! Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there. */
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++;
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++;
+
+ /*! three children are hit, push all onto stack and sort 3 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = ((unsigned int*)&tNear)[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+
+ /*! four children are hit, push all onto stack and sort 4 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3],stackPtr[-4]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#endif
+#endif
+ }
+
+ /* Traverses a node with at least one hit child. Optimized for finding any hit (occlusion). */
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t mask,
+ const vfloat<Nx>& tNear,
+ NodeRef*& stackPtr,
+ NodeRef* stackEnd)
+ {
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+
+ /* simpler in sequence traversal order */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r); BVH::prefetch(cur,types);
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+ }
+ }
+ };
+
+ /* Specialization for BVH8. */
+ template<int Nx, int types>
+ class BVHNNodeTraverser1Hit<8, Nx, types>
+ {
+ typedef BVH8 BVH;
+ typedef BVH8::NodeRef NodeRef;
+ typedef BVH8::BaseNode BaseNode;
+
+#if defined(__AVX512VL__)
+ template<class NodeRef, class BaseNode>
+ static __forceinline void traverseClosestHitAVX512VL8(NodeRef& cur,
+ size_t mask,
+ const vfloat8& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+ const vllong4 n0 = vllong4::loadu((vllong4*)&node->children[0]);
+ const vllong4 n1 = vllong4::loadu((vllong4*)&node->children[4]);
+ vint8 distance_i = (asInt(tNear) & 0xfffffff8) | vint8(step);
+ distance_i = vint8::compact((int)mask,distance_i,distance_i);
+ cur = permuteExtract(distance_i,n0,n1);
+ BVH::prefetch(cur,types);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) return;
+
+ /* 2 hits: order A0 B0 */
+ const vint8 d0(distance_i);
+ const vint8 d1(shuffle<1>(distance_i));
+ cur = permuteExtract(d1,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A0 = min(d0, d1);
+ const vint8 dist_B0 = max(d0, d1);
+ assert(dist_A0[0] < dist_B0[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A0,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_B0,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_B0,tNear);
+ stackPtr++;
+ return;
+ }
+
+ /* 3 hits: order A1 B1 C1 */
+
+ const vint8 d2(shuffle<2>(distance_i));
+ cur = permuteExtract(d2,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A1 = min(dist_A0,d2);
+ const vint8 dist_tmp_B1 = max(dist_A0,d2);
+ const vint8 dist_B1 = min(dist_B0,dist_tmp_B1);
+ const vint8 dist_C1 = max(dist_B0,dist_tmp_B1);
+ assert(dist_A1[0] < dist_B1[0]);
+ assert(dist_B1[0] < dist_C1[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A1,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_C1,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_C1,tNear);
+ stackPtr[1].ptr = permuteExtract(dist_B1,n0,n1);
+ *(float*)&stackPtr[1].dist = permuteExtract(dist_B1,tNear);
+ stackPtr+=2;
+ return;
+ }
+
+ /* 4 hits: order A2 B2 C2 D2 */
+
+ const vint8 d3(shuffle<3>(distance_i));
+ cur = permuteExtract(d3,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A2 = min(dist_A1,d3);
+ const vint8 dist_tmp_B2 = max(dist_A1,d3);
+ const vint8 dist_B2 = min(dist_B1,dist_tmp_B2);
+ const vint8 dist_tmp_C2 = max(dist_B1,dist_tmp_B2);
+ const vint8 dist_C2 = min(dist_C1,dist_tmp_C2);
+ const vint8 dist_D2 = max(dist_C1,dist_tmp_C2);
+ assert(dist_A2[0] < dist_B2[0]);
+ assert(dist_B2[0] < dist_C2[0]);
+ assert(dist_C2[0] < dist_D2[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A2,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_D2,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_D2,tNear);
+ stackPtr[1].ptr = permuteExtract(dist_C2,n0,n1);
+ *(float*)&stackPtr[1].dist = permuteExtract(dist_C2,tNear);
+ stackPtr[2].ptr = permuteExtract(dist_B2,n0,n1);
+ *(float*)&stackPtr[2].dist = permuteExtract(dist_B2,tNear);
+ stackPtr+=3;
+ return;
+ }
+
+ /* >=5 hits: reverse to descending order for writing to stack */
+
+ distance_i = align_shift_right<3>(distance_i,distance_i);
+ const size_t hits = 4 + popcnt(mask);
+ vint8 dist(INT_MIN); // this will work with -0.0f (0x80000000) as distance, isort_update uses >= to insert
+
+ isort_quick_update(dist,dist_A2);
+ isort_quick_update(dist,dist_B2);
+ isort_quick_update(dist,dist_C2);
+ isort_quick_update(dist,dist_D2);
+
+ do {
+
+ distance_i = align_shift_right<1>(distance_i,distance_i);
+ cur = permuteExtract(distance_i,n0,n1);
+ BVH::prefetch(cur,types);
+ const vint8 new_dist(permute(distance_i,vint8(zero)));
+ mask &= mask-1;
+ isort_update(dist,new_dist);
+
+ } while(mask);
+
+ for (size_t i=0; i<7; i++)
+ assert(dist[i+0]>=dist[i+1]);
+
+ for (size_t i=0;i<hits-1;i++)
+ {
+ stackPtr->ptr = permuteExtract(dist,n0,n1);
+ *(float*)&stackPtr->dist = permuteExtract(dist,tNear);
+ dist = align_shift_right<1>(dist,dist);
+ stackPtr++;
+ }
+ cur = permuteExtract(dist,n0,n1);
+ }
+#endif
+
+ public:
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t mask,
+ const vfloat<Nx>& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+#if defined(__AVX512ER__)
+ traverseClosestHitAVX512<8,Nx,types,NodeRef,BaseNode>(cur,mask,tNear,stackPtr,stackEnd);
+#elif defined(__AVX512VL__)
+ traverseClosestHitAVX512VL8<NodeRef,BaseNode>(cur,mask,tNear,stackPtr,stackEnd);
+#else
+
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+ if (likely(mask == 0)) {
+ assert(cur != BVH::emptyNode);
+ return;
+ }
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ const unsigned int d0 = ((unsigned int*)&tNear)[r];
+ r = bscf(mask);
+ NodeRef c1 = node->child(r);
+ BVH::prefetch(c1,types);
+ const unsigned int d1 = ((unsigned int*)&tNear)[r];
+
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ assert(stackPtr < stackEnd);
+ if (d0 < d1) { stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; cur = c0; return; }
+ else { stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; cur = c1; return; }
+ }
+#if NEW_SORTING_CODE == 1
+ vint4 s0((size_t)c0,(size_t)d0);
+ vint4 s1((size_t)c1,(size_t)d1);
+
+ r = bscf(mask);
+ NodeRef c2 = node->child(r); BVH::prefetch(c2,types); unsigned int d2 = ((unsigned int*)&tNear)[r];
+ vint4 s2((size_t)c2,(size_t)d2);
+ /* 3 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort3(s0,s1,s2);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1;
+ cur = toSizeT(s2);
+ stackPtr+=2;
+ return;
+ }
+ r = bscf(mask);
+ NodeRef c3 = node->child(r); BVH::prefetch(c3,types); unsigned int d3 = ((unsigned int*)&tNear)[r];
+ vint4 s3((size_t)c3,(size_t)d3);
+ /* 4 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort4(s0,s1,s2,s3);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2;
+ cur = toSizeT(s3);
+ stackPtr+=3;
+ return;
+ }
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2; *(vint4*)&stackPtr[3] = s3;
+ /*! fallback case if more than 4 children are hit */
+ StackItemT<NodeRef>* stackFirst = stackPtr;
+ stackPtr+=4;
+ while (1)
+ {
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = *(unsigned int*)&tNear[r];
+ const vint4 s((size_t)c,(size_t)d);
+ *(vint4*)stackPtr++ = s;
+ assert(c != BVH::emptyNode);
+ if (unlikely(mask == 0)) break;
+ }
+ sort(stackFirst,stackPtr);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#else
+ /*! Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there. */
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++;
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++;
+
+ /*! three children are hit, push all onto stack and sort 3 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = ((unsigned int*)&tNear)[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+
+ /*! four children are hit, push all onto stack and sort 4 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3],stackPtr[-4]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+ /*! fallback case if more than 4 children are hit */
+ StackItemT<NodeRef>* stackFirst = stackPtr-4;
+ while (1)
+ {
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (unlikely(mask == 0)) break;
+ }
+ sort(stackFirst,stackPtr);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#endif
+#endif
+ }
+
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t mask,
+ const vfloat<Nx>& tNear,
+ NodeRef*& stackPtr,
+ NodeRef* stackEnd)
+ {
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+
+ /* simpler in sequence traversal order */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r); BVH::prefetch(cur,types);
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser_stream.h b/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser_stream.h
new file mode 100644
index 0000000000..9c603babf0
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_traverser_stream.h
@@ -0,0 +1,154 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/stack_item.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, int Nx, int types>
+ class BVHNNodeTraverserStreamHitCoherent
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+
+ public:
+ template<class T>
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t& m_trav_active,
+ const vbool<Nx>& vmask,
+ const vfloat<Nx>& tNear,
+ const T* const tMask,
+ StackItemMaskCoherent*& stackPtr)
+ {
+ const NodeRef parent = cur;
+ size_t mask = movemask(vmask);
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ const size_t r0 = bscf(mask);
+ assert(r0 < 8);
+ cur = node->child(r0);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r0];
+ assert(cur != BVH::emptyNode);
+ if (unlikely(mask == 0)) return;
+
+ const unsigned int* const tNear_i = (unsigned int*)&tNear;
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ unsigned int d0 = tNear_i[r0];
+ const size_t r1 = bscf(mask);
+ assert(r1 < 8);
+ NodeRef c1 = node->child(r1);
+ BVHN<N>::prefetch(c1,types);
+ unsigned int d1 = tNear_i[r1];
+
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ if (d0 < d1) {
+ assert(tNear[r1] >= 0.0f);
+ stackPtr->mask = tMask[r1];
+ stackPtr->parent = parent;
+ stackPtr->child = c1;
+ stackPtr++;
+ cur = c0;
+ m_trav_active = tMask[r0];
+ return;
+ }
+ else {
+ assert(tNear[r0] >= 0.0f);
+ stackPtr->mask = tMask[r0];
+ stackPtr->parent = parent;
+ stackPtr->child = c0;
+ stackPtr++;
+ cur = c1;
+ m_trav_active = tMask[r1];
+ return;
+ }
+ }
+
+ /*! slow path for more than two hits */
+ size_t hits = movemask(vmask);
+ const vint<Nx> dist_i = select(vmask, (asInt(tNear) & 0xfffffff8) | vint<Nx>(step), 0);
+ #if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+ const vint<N> tmp = extractN<N,0>(dist_i);
+ const vint<Nx> dist_i_sorted = usort_descending(tmp);
+ #else
+ const vint<Nx> dist_i_sorted = usort_descending(dist_i);
+ #endif
+ const vint<Nx> sorted_index = dist_i_sorted & 7;
+
+ size_t i = 0;
+ for (;;)
+ {
+ const unsigned int index = sorted_index[i];
+ assert(index < 8);
+ cur = node->child(index);
+ m_trav_active = tMask[index];
+ assert(m_trav_active);
+ BVHN<N>::prefetch(cur,types);
+ bscf(hits);
+ if (unlikely(hits==0)) break;
+ i++;
+ assert(cur != BVH::emptyNode);
+ assert(tNear[index] >= 0.0f);
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+ }
+ }
+
+ template<class T>
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t& m_trav_active,
+ const vbool<Nx>& vmask,
+ const T* const tMask,
+ StackItemMaskCoherent*& stackPtr)
+ {
+ const NodeRef parent = cur;
+ size_t mask = movemask(vmask);
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r];
+
+ /* simple in order sequence */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r];
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/node_intersector.h b/thirdparty/embree-aarch64/kernels/bvh/node_intersector.h
new file mode 100644
index 0000000000..a978c0c459
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/node_intersector.h
@@ -0,0 +1,31 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct NearFarPrecalculations
+ {
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+
+ __forceinline NearFarPrecalculations() {}
+
+ __forceinline NearFarPrecalculations(const Vec3fa& dir, size_t N)
+ {
+ const size_t size = sizeof(float)*N;
+ nearX = (dir.x < 0.0f) ? 1*size : 0*size;
+ nearY = (dir.y < 0.0f) ? 3*size : 2*size;
+ nearZ = (dir.z < 0.0f) ? 5*size : 4*size;
+ farX = nearX ^ size;
+ farY = nearY ^ size;
+ farZ = nearZ ^ size;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/node_intersector1.h b/thirdparty/embree-aarch64/kernels/bvh/node_intersector1.h
new file mode 100644
index 0000000000..aa0d4ba4d7
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/node_intersector1.h
@@ -0,0 +1,1788 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+#if defined(__AVX2__)
+#define __FMA_X4__
+#endif
+
+#if defined(__aarch64__)
+#define __FMA_X4__
+#endif
+
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray structure used in single-ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx, bool robust>
+ struct TravRayBase;
+
+ /* Base (without tnear and tfar) */
+ template<int N, int Nx>
+ struct TravRayBase<N,Nx,false>
+ {
+ __forceinline TravRayBase() {}
+
+ __forceinline TravRayBase(const Vec3fa& ray_org, const Vec3fa& ray_dir)
+ : org_xyz(ray_org), dir_xyz(ray_dir)
+ {
+ const Vec3fa ray_rdir = rcp_safe(ray_dir);
+ org = Vec3vf<N>(ray_org.x,ray_org.y,ray_org.z);
+ dir = Vec3vf<N>(ray_dir.x,ray_dir.y,ray_dir.z);
+ rdir = Vec3vf<N>(ray_rdir.x,ray_rdir.y,ray_rdir.z);
+#if defined(__FMA_X4__)
+ const Vec3fa ray_org_rdir = ray_org*ray_rdir;
+#if !defined(__aarch64__)
+ org_rdir = Vec3vf<N>(ray_org_rdir.x,ray_org_rdir.y,ray_org_rdir.z);
+#else
+ //for aarch64, we do not have msub equal instruction, so we negeate orig and use madd
+ //x86 will use msub
+ neg_org_rdir = Vec3vf<N>(-ray_org_rdir.x,-ray_org_rdir.y,-ray_org_rdir.z);
+#endif
+#endif
+ nearX = ray_rdir.x >= 0.0f ? 0*sizeof(vfloat<N>) : 1*sizeof(vfloat<N>);
+ nearY = ray_rdir.y >= 0.0f ? 2*sizeof(vfloat<N>) : 3*sizeof(vfloat<N>);
+ nearZ = ray_rdir.z >= 0.0f ? 4*sizeof(vfloat<N>) : 5*sizeof(vfloat<N>);
+ farX = nearX ^ sizeof(vfloat<N>);
+ farY = nearY ^ sizeof(vfloat<N>);
+ farZ = nearZ ^ sizeof(vfloat<N>);
+
+#if defined(__AVX512ER__) // KNL+
+ /* optimization works only for 8-wide BVHs with 16-wide SIMD */
+ const vint<16> id(step);
+ const vint<16> id2 = align_shift_right<16/2>(id, id);
+ permX = select(vfloat<16>(dir.x) >= 0.0f, id, id2);
+ permY = select(vfloat<16>(dir.y) >= 0.0f, id, id2);
+ permZ = select(vfloat<16>(dir.z) >= 0.0f, id, id2);
+#endif
+
+ }
+
+ template<int K>
+ __forceinline TravRayBase(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ size_t flip = sizeof(vfloat<N>))
+ {
+ org = Vec3vf<Nx>(ray_org.x[k], ray_org.y[k], ray_org.z[k]);
+ dir = Vec3vf<Nx>(ray_dir.x[k], ray_dir.y[k], ray_dir.z[k]);
+ rdir = Vec3vf<Nx>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+#if defined(__FMA_X4__)
+#if !defined(__aarch64__)
+ org_rdir = org*rdir;
+#else
+ neg_org_rdir = -(org*rdir);
+#endif
+#endif
+ nearX = nearXYZ.x[k];
+ nearY = nearXYZ.y[k];
+ nearZ = nearXYZ.z[k];
+ farX = nearX ^ flip;
+ farY = nearY ^ flip;
+ farZ = nearZ ^ flip;
+
+#if defined(__AVX512ER__) // KNL+
+ /* optimization works only for 8-wide BVHs with 16-wide SIMD */
+ const vint<16> id(step);
+ const vint<16> id2 = align_shift_right<16/2>(id, id);
+ permX = select(vfloat<16>(dir.x) >= 0.0f, id, id2);
+ permY = select(vfloat<16>(dir.y) >= 0.0f, id, id2);
+ permZ = select(vfloat<16>(dir.z) >= 0.0f, id, id2);
+#endif
+ }
+
+ Vec3fa org_xyz, dir_xyz;
+ Vec3vf<Nx> org, dir, rdir;
+#if defined(__FMA_X4__)
+#if !defined(__aarch64__)
+ Vec3vf<Nx> org_rdir;
+#else
+ //aarch64 version are keeping negation of the org_rdir and use madd
+ //x86 uses msub
+ Vec3vf<Nx> neg_org_rdir;
+#endif
+#endif
+#if defined(__AVX512ER__) // KNL+
+ vint16 permX, permY, permZ;
+#endif
+
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+ };
+
+ /* Base (without tnear and tfar) */
+ template<int N, int Nx>
+ struct TravRayBase<N,Nx,true>
+ {
+ __forceinline TravRayBase() {}
+
+ __forceinline TravRayBase(const Vec3fa& ray_org, const Vec3fa& ray_dir)
+ : org_xyz(ray_org), dir_xyz(ray_dir)
+ {
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const Vec3fa ray_rdir = 1.0f/zero_fix(ray_dir);
+ const Vec3fa ray_rdir_near = round_down*ray_rdir;
+ const Vec3fa ray_rdir_far = round_up *ray_rdir;
+ org = Vec3vf<N>(ray_org.x,ray_org.y,ray_org.z);
+ dir = Vec3vf<N>(ray_dir.x,ray_dir.y,ray_dir.z);
+ rdir_near = Vec3vf<N>(ray_rdir_near.x,ray_rdir_near.y,ray_rdir_near.z);
+ rdir_far = Vec3vf<N>(ray_rdir_far .x,ray_rdir_far .y,ray_rdir_far .z);
+ nearX = ray_rdir_near.x >= 0.0f ? 0*sizeof(vfloat<N>) : 1*sizeof(vfloat<N>);
+ nearY = ray_rdir_near.y >= 0.0f ? 2*sizeof(vfloat<N>) : 3*sizeof(vfloat<N>);
+ nearZ = ray_rdir_near.z >= 0.0f ? 4*sizeof(vfloat<N>) : 5*sizeof(vfloat<N>);
+ farX = nearX ^ sizeof(vfloat<N>);
+ farY = nearY ^ sizeof(vfloat<N>);
+ farZ = nearZ ^ sizeof(vfloat<N>);
+
+#if defined(__AVX512ER__) // KNL+
+ /* optimization works only for 8-wide BVHs with 16-wide SIMD */
+ const vint<16> id(step);
+ const vint<16> id2 = align_shift_right<16/2>(id, id);
+ permX = select(vfloat<16>(dir.x) >= 0.0f, id, id2);
+ permY = select(vfloat<16>(dir.y) >= 0.0f, id, id2);
+ permZ = select(vfloat<16>(dir.z) >= 0.0f, id, id2);
+#endif
+ }
+
+ template<int K>
+ __forceinline TravRayBase(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ size_t flip = sizeof(vfloat<N>))
+ {
+ const vfloat<Nx> round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<Nx> round_up = 1.0f+3.0f*float(ulp);
+ org = Vec3vf<Nx>(ray_org.x[k], ray_org.y[k], ray_org.z[k]);
+ dir = Vec3vf<Nx>(ray_dir.x[k], ray_dir.y[k], ray_dir.z[k]);
+ rdir_near = round_down*Vec3vf<Nx>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+ rdir_far = round_up *Vec3vf<Nx>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+
+ nearX = nearXYZ.x[k];
+ nearY = nearXYZ.y[k];
+ nearZ = nearXYZ.z[k];
+ farX = nearX ^ flip;
+ farY = nearY ^ flip;
+ farZ = nearZ ^ flip;
+
+#if defined(__AVX512ER__) // KNL+
+ /* optimization works only for 8-wide BVHs with 16-wide SIMD */
+ const vint<16> id(step);
+ const vint<16> id2 = align_shift_right<16/2>(id, id);
+ permX = select(vfloat<16>(dir.x) >= 0.0f, id, id2);
+ permY = select(vfloat<16>(dir.y) >= 0.0f, id, id2);
+ permZ = select(vfloat<16>(dir.z) >= 0.0f, id, id2);
+#endif
+ }
+
+ Vec3fa org_xyz, dir_xyz;
+ Vec3vf<Nx> org, dir, rdir_near, rdir_far;
+#if defined(__AVX512ER__) // KNL+
+ vint16 permX, permY, permZ;
+#endif
+
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+ };
+
+ /* Full (with tnear and tfar) */
+ template<int N, int Nx, bool robust>
+ struct TravRay : TravRayBase<N,Nx,robust>
+ {
+ __forceinline TravRay() {}
+
+ __forceinline TravRay(const Vec3fa& ray_org, const Vec3fa& ray_dir, float ray_tnear, float ray_tfar)
+ : TravRayBase<N,Nx,robust>(ray_org, ray_dir),
+ tnear(ray_tnear), tfar(ray_tfar) {}
+
+ template<int K>
+ __forceinline TravRay(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ float ray_tnear, float ray_tfar,
+ size_t flip = sizeof(vfloat<N>))
+ : TravRayBase<N,Nx,robust>(k, ray_org, ray_dir, ray_rdir, nearXYZ, flip),
+ tnear(ray_tnear), tfar(ray_tfar) {}
+
+ vfloat<Nx> tnear;
+ vfloat<Nx> tfar;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Point Query structure used in single-ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ struct TravPointQuery
+ {
+ __forceinline TravPointQuery() {}
+
+ __forceinline TravPointQuery(const Vec3fa& query_org, const Vec3fa& query_rad)
+ {
+ org = Vec3vf<N>(query_org.x, query_org.y, query_org.z);
+ rad = Vec3vf<N>(query_rad.x, query_rad.y, query_rad.z);
+ }
+
+ __forceinline vfloat<N> const& tfar() const {
+ return rad.x;
+ }
+
+ Vec3vf<N> org, rad;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // point query
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t pointQuerySphereDistAndMask(
+ const TravPointQuery<N>& query, vfloat<N>& dist, vfloat<N> const& minX, vfloat<N> const& maxX,
+ vfloat<N> const& minY, vfloat<N> const& maxY, vfloat<N> const& minZ, vfloat<N> const& maxZ)
+ {
+ const vfloat<N> vX = min(max(query.org.x, minX), maxX) - query.org.x;
+ const vfloat<N> vY = min(max(query.org.y, minY), maxY) - query.org.y;
+ const vfloat<N> vZ = min(max(query.org.z, minZ), maxZ) - query.org.z;
+ dist = vX * vX + vY * vY + vZ * vZ;
+ const vbool<N> vmask = dist <= query.tfar()*query.tfar();
+ const vbool<N> valid = minX <= maxX;
+ return movemask(vmask) & movemask(valid);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::AABBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = vfloat<N>::load((float*)((const char*)&node->lower_x));
+ const vfloat<N> minY = vfloat<N>::load((float*)((const char*)&node->lower_y));
+ const vfloat<N> minZ = vfloat<N>::load((float*)((const char*)&node->lower_z));
+ const vfloat<N> maxX = vfloat<N>::load((float*)((const char*)&node->upper_x));
+ const vfloat<N> maxY = vfloat<N>::load((float*)((const char*)&node->upper_y));
+ const vfloat<N> maxZ = vfloat<N>::load((float*)((const char*)&node->upper_z));
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::AABBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pMinX = (const vfloat<N>*)((const char*)&node->lower_x);
+ const vfloat<N>* pMinY = (const vfloat<N>*)((const char*)&node->lower_y);
+ const vfloat<N>* pMinZ = (const vfloat<N>*)((const char*)&node->lower_z);
+ const vfloat<N>* pMaxX = (const vfloat<N>*)((const char*)&node->upper_x);
+ const vfloat<N>* pMaxY = (const vfloat<N>*)((const char*)&node->upper_y);
+ const vfloat<N>* pMaxZ = (const vfloat<N>*)((const char*)&node->upper_z);
+ const vfloat<N> minX = madd(time,pMinX[6],vfloat<N>(pMinX[0]));
+ const vfloat<N> minY = madd(time,pMinY[6],vfloat<N>(pMinY[0]));
+ const vfloat<N> minZ = madd(time,pMinZ[6],vfloat<N>(pMinZ[0]));
+ const vfloat<N> maxX = madd(time,pMaxX[6],vfloat<N>(pMaxX[0]));
+ const vfloat<N> maxY = madd(time,pMaxY[6],vfloat<N>(pMaxY[0]));
+ const vfloat<N> maxZ = madd(time,pMaxZ[6],vfloat<N>(pMaxZ[0]));
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphereMB4D(const typename BVHN<N>::NodeRef ref, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+ size_t mask = pointQueryNodeSphere(node, query, time, dist);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ const vbool<N> vmask = (node1->lower_t <= time) & (time < node1->upper_t);
+ mask &= movemask(vmask);
+ }
+
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> start_x(node->start.x);
+ const vfloat<N> scale_x(node->scale.x);
+ const vfloat<N> minX = madd(node->template dequantize<N>((0*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> maxX = madd(node->template dequantize<N>((1*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> start_y(node->start.y);
+ const vfloat<N> scale_y(node->scale.y);
+ const vfloat<N> minY = madd(node->template dequantize<N>((2*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> maxY = madd(node->template dequantize<N>((3*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> start_z(node->start.z);
+ const vfloat<N> scale_z(node->scale.z);
+ const vfloat<N> minZ = madd(node->template dequantize<N>((4*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ const vfloat<N> maxZ = madd(node->template dequantize<N>((5*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & movemask(node->validMask());
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = node->dequantizeLowerX(time);
+ const vfloat<N> maxX = node->dequantizeUpperX(time);
+ const vfloat<N> minY = node->dequantizeLowerY(time);
+ const vfloat<N> maxY = node->dequantizeUpperY(time);
+ const vfloat<N> minZ = node->dequantizeLowerZ(time);
+ const vfloat<N> maxZ = node->dequantizeUpperZ(time);
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & movemask(node->validMask());
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::OBBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::OBBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryAABBDistAndMask(
+ const TravPointQuery<N>& query, vfloat<N>& dist, vfloat<N> const& minX, vfloat<N> const& maxX,
+ vfloat<N> const& minY, vfloat<N> const& maxY, vfloat<N> const& minZ, vfloat<N> const& maxZ)
+ {
+ const vfloat<N> vX = min(max(query.org.x, minX), maxX) - query.org.x;
+ const vfloat<N> vY = min(max(query.org.y, minY), maxY) - query.org.y;
+ const vfloat<N> vZ = min(max(query.org.z, minZ), maxZ) - query.org.z;
+ dist = vX * vX + vY * vY + vZ * vZ;
+ const vbool<N> valid = minX <= maxX;
+ const vbool<N> vmask = !((maxX < query.org.x - query.rad.x) | (minX > query.org.x + query.rad.x) |
+ (maxY < query.org.y - query.rad.y) | (minY > query.org.y + query.rad.y) |
+ (maxZ < query.org.z - query.rad.z) | (minZ > query.org.z + query.rad.z));
+ return movemask(vmask) & movemask(valid);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::AABBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = vfloat<N>::load((float*)((const char*)&node->lower_x));
+ const vfloat<N> minY = vfloat<N>::load((float*)((const char*)&node->lower_y));
+ const vfloat<N> minZ = vfloat<N>::load((float*)((const char*)&node->lower_z));
+ const vfloat<N> maxX = vfloat<N>::load((float*)((const char*)&node->upper_x));
+ const vfloat<N> maxY = vfloat<N>::load((float*)((const char*)&node->upper_y));
+ const vfloat<N> maxZ = vfloat<N>::load((float*)((const char*)&node->upper_z));
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::AABBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pMinX = (const vfloat<N>*)((const char*)&node->lower_x);
+ const vfloat<N>* pMinY = (const vfloat<N>*)((const char*)&node->lower_y);
+ const vfloat<N>* pMinZ = (const vfloat<N>*)((const char*)&node->lower_z);
+ const vfloat<N>* pMaxX = (const vfloat<N>*)((const char*)&node->upper_x);
+ const vfloat<N>* pMaxY = (const vfloat<N>*)((const char*)&node->upper_y);
+ const vfloat<N>* pMaxZ = (const vfloat<N>*)((const char*)&node->upper_z);
+ const vfloat<N> minX = madd(time,pMinX[6],vfloat<N>(pMinX[0]));
+ const vfloat<N> minY = madd(time,pMinY[6],vfloat<N>(pMinY[0]));
+ const vfloat<N> minZ = madd(time,pMinZ[6],vfloat<N>(pMinZ[0]));
+ const vfloat<N> maxX = madd(time,pMaxX[6],vfloat<N>(pMaxX[0]));
+ const vfloat<N> maxY = madd(time,pMaxY[6],vfloat<N>(pMaxY[0]));
+ const vfloat<N> maxZ = madd(time,pMaxZ[6],vfloat<N>(pMaxZ[0]));
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABBMB4D(const typename BVHN<N>::NodeRef ref, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+ size_t mask = pointQueryNodeAABB(node, query, time, dist);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ const vbool<N> vmask = (node1->lower_t <= time) & (time < node1->upper_t);
+ mask &= movemask(vmask);
+ }
+
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat<N> start_x(node->start.x);
+ const vfloat<N> scale_x(node->scale.x);
+ const vfloat<N> minX = madd(node->template dequantize<N>((0*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> maxX = madd(node->template dequantize<N>((1*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> start_y(node->start.y);
+ const vfloat<N> scale_y(node->scale.y);
+ const vfloat<N> minY = madd(node->template dequantize<N>((2*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> maxY = madd(node->template dequantize<N>((3*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> start_z(node->start.z);
+ const vfloat<N> scale_z(node->scale.z);
+ const vfloat<N> minZ = madd(node->template dequantize<N>((4*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ const vfloat<N> maxZ = madd(node->template dequantize<N>((5*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & mvalid;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat<N> minX = node->dequantizeLowerX(time);
+ const vfloat<N> maxX = node->dequantizeUpperX(time);
+ const vfloat<N> minY = node->dequantizeLowerY(time);
+ const vfloat<N> maxY = node->dequantizeUpperY(time);
+ const vfloat<N> minZ = node->dequantizeLowerZ(time);
+ const vfloat<N> maxZ = node->dequantizeUpperZ(time);
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & mvalid;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::OBBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::OBBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::AABBNode* node, const TravRay<N,Nx,robust>& ray, vfloat<Nx>& dist);
+
+ template<>
+ __forceinline size_t intersectNode<4,4>(const typename BVH4::AABBNode* node, const TravRay<4,4,false>& ray, vfloat4& dist)
+ {
+#if defined(__FMA_X4__)
+#if defined(__aarch64__)
+ const vfloat4 tNearX = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat4 tNearY = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat4 tNearZ = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat4 tFarX = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat4 tFarY = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat4 tFarZ = madd(vfloat4::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat4 tNearX = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tNearY = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tNearZ = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.org_rdir.z);
+ const vfloat4 tFarX = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tFarY = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tFarZ = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat4 tNearX = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir.x;
+ const vfloat4 tNearY = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir.y;
+ const vfloat4 tNearZ = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir.z;
+ const vfloat4 tFarX = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir.x;
+ const vfloat4 tFarY = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir.y;
+ const vfloat4 tFarZ = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__aarch64__)
+ const vfloat4 tNear = maxi(tNearX, tNearY, tNearZ, ray.tnear);
+ const vfloat4 tFar = mini(tFarX, tFarY, tFarZ, ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#elif defined(__SSE4_1__) && !defined(__AVX512F__) // up to HSW
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<4)-1);
+#elif defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline size_t intersectNode<8,8>(const typename BVH8::AABBNode* node, const TravRay<8,8,false>& ray, vfloat8& dist)
+ {
+#if defined(__AVX2__)
+#if defined(__aarch64__)
+ const vfloat8 tNearX = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat8 tNearY = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat8 tNearZ = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat8 tFarX = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat8 tFarY = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat8 tFarZ = madd(vfloat8::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat8 tNearX = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tNearY = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tNearZ = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.org_rdir.z);
+ const vfloat8 tFarX = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tFarY = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tFarZ = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.org_rdir.z);
+#endif
+
+#else
+ const vfloat8 tNearX = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir.x;
+ const vfloat8 tNearY = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir.y;
+ const vfloat8 tNearZ = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir.z;
+ const vfloat8 tFarX = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir.x;
+ const vfloat8 tFarY = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir.y;
+ const vfloat8 tFarZ = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX2__) && !defined(__AVX512F__) // HSW
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<8)-1);
+#elif defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+#endif
+
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+
+ template<>
+ __forceinline size_t intersectNode<4,16>(const typename BVH4::AABBNode* node, const TravRay<4,16,false>& ray, vfloat16& dist)
+ {
+ const vfloat16 tNearX = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tNearY = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tNearZ = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tFarX = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tFarY = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tFarZ = msub(vfloat16(*(vfloat4*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat16 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool16 vmask = le(vbool16(0xf),tNear,tFar);
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<8,16>(const typename BVH8::AABBNode* node, const TravRay<8,16,false>& ray, vfloat16& dist)
+ {
+ const vllong8 invalid((size_t)BVH8::emptyNode);
+ const vboold8 m_valid(invalid != vllong8::loadu(node->children));
+ const vfloat16 bminmaxX = permute(vfloat16::load((const float*)&node->lower_x), ray.permX);
+ const vfloat16 bminmaxY = permute(vfloat16::load((const float*)&node->lower_y), ray.permY);
+ const vfloat16 bminmaxZ = permute(vfloat16::load((const float*)&node->lower_z), ray.permZ);
+ const vfloat16 tNearFarX = msub(bminmaxX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tNearFarY = msub(bminmaxY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tNearFarZ = msub(bminmaxZ, ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tNear = max(tNearFarX, tNearFarY, tNearFarZ, ray.tnear);
+ const vfloat16 tFar = min(tNearFarX, tNearFarY, tNearFarZ, ray.tfar);
+ const vbool16 vmask = le(vboolf16(m_valid),tNear,align_shift_right<8>(tFar, tFar));
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+#endif
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx>
+ __forceinline size_t intersectNodeRobust(const typename BVHN<N>::AABBNode* node, const TravRay<N,Nx,true>& ray, vfloat<Nx>& dist)
+ {
+ const vfloat<N> tNearX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tFarX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+
+ template<>
+ __forceinline size_t intersectNodeRobust<4,16>(const typename BVHN<4>::AABBNode* node, const TravRay<4,16,true>& ray, vfloat<16>& dist)
+ {
+ const vfloat16 tNearX = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir_near.x;
+ const vfloat16 tNearY = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir_near.y;
+ const vfloat16 tNearZ = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir_near.z;
+ const vfloat16 tFarX = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir_far.x;
+ const vfloat16 tFarY = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir_far.y;
+ const vfloat16 tFarZ = (vfloat16(*(vfloat<4>*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir_far.z;
+ const vfloat16 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat16 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool16 vmask = le((1 << 4)-1,tNear,tFar);
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ template<>
+ __forceinline size_t intersectNodeRobust<8,16>(const typename BVHN<8>::AABBNode* node, const TravRay<8,16,true>& ray, vfloat<16>& dist)
+ {
+ const vfloat16 tNearX = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir_near.x;
+ const vfloat16 tNearY = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir_near.y;
+ const vfloat16 tNearZ = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir_near.z;
+ const vfloat16 tFarX = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir_far.x;
+ const vfloat16 tFarY = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir_far.y;
+ const vfloat16 tFarZ = (vfloat16(*(vfloat<8>*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir_far.z;
+ const vfloat16 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat16 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool16 vmask = le((1 << 8)-1,tNear,tFar);
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+#endif
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNode(const typename BVHN<N>::AABBNodeMB* node, const TravRay<N,N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+#if defined(__FMA_X4__)
+#if defined(__aarch64__)
+ const vfloat<N> tNearX = madd(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tNearY = madd(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tNearZ = madd(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<N> tFarX = madd(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tFarY = madd(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tFarZ = madd(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat<N> tNearX = msub(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (madd(time,pFarX [6],vfloat<N>(pFarX [0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (madd(time,pFarY [6],vfloat<N>(pFarY [0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ [6],vfloat<N>(pFarZ [0])) - ray.org.z) * ray.rdir.z;
+#endif
+#if defined(__FMA_X4__) && !defined(__AVX512F__) // HSW
+ const vfloat<N> tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<N)-1);
+#elif defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vfloat<N> tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ const vbool<N> vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeRobust(const typename BVHN<N>::AABBNodeMB* node, const TravRay<N,N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+ const vfloat<N> tFarX = (madd(time,pFarX[6],vfloat<N>(pFarX[0])) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (madd(time,pFarY[6],vfloat<N>(pFarY[0])) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ[6],vfloat<N>(pFarZ[0])) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tFar = min(ray.tfar,tFarX,tFarY,tFarZ);
+ const size_t mask = movemask(tNear <= tFar);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeMB4D(const typename BVHN<N>::NodeRef ref, const TravRay<N,N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+#if defined (__FMA_X4__)
+#if defined(__aarch64__)
+ const vfloat<N> tNearX = madd(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tNearY = madd(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tNearZ = madd(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<N> tFarX = madd(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tFarY = madd(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tFarZ = madd(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat<N> tNearX = msub(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (madd(time,pFarX [6],vfloat<N>(pFarX [0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (madd(time,pFarY [6],vfloat<N>(pFarY [0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ [6],vfloat<N>(pFarZ [0])) - ray.org.z) * ray.rdir.z;
+#endif
+#if defined(__FMA_X4__) && !defined(__AVX512F__)
+ const vfloat<N> tNear = maxi(maxi(tNearX,tNearY),maxi(tNearZ,ray.tnear));
+ const vfloat<N> tFar = mini(mini(tFarX ,tFarY ),mini(tFarZ ,ray.tfar ));
+#else
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+#endif
+ vbool<N> vmask = tNear <= tFar;
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ vmask &= (node1->lower_t <= time) & (time < node1->upper_t);
+ }
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeMB4DRobust(const typename BVHN<N>::NodeRef ref, const TravRay<N,N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+ const vfloat<N> tFarX = (madd(time,pFarX[6],vfloat<N>(pFarX[0])) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (madd(time,pFarY[6],vfloat<N>(pFarY[0])) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ[6],vfloat<N>(pFarZ[0])) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tFar = min(ray.tfar,tFarX,tFarY,tFarZ);
+ vbool<N> vmask = tNear <= tFar;
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ vmask &= (node1->lower_t <= time) & (time < node1->upper_t);
+ }
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast QuantizedBaseNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,Nx,robust>& ray, vfloat<Nx>& dist);
+
+ template<>
+ __forceinline size_t intersectNode<4,4>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,4,false>& ray, vfloat4& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat4 start_x(node->start.x);
+ const vfloat4 scale_x(node->scale.x);
+ const vfloat4 lower_x = madd(node->dequantize<4>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat4 upper_x = madd(node->dequantize<4>(ray.farX >> 2),scale_x,start_x);
+ const vfloat4 start_y(node->start.y);
+ const vfloat4 scale_y(node->scale.y);
+ const vfloat4 lower_y = madd(node->dequantize<4>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat4 upper_y = madd(node->dequantize<4>(ray.farY >> 2),scale_y,start_y);
+ const vfloat4 start_z(node->start.z);
+ const vfloat4 scale_z(node->scale.z);
+ const vfloat4 lower_z = madd(node->dequantize<4>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat4 upper_z = madd(node->dequantize<4>(ray.farZ >> 2),scale_z,start_z);
+
+#if defined(__FMA_X4__)
+#if defined(__aarch64__)
+ const vfloat4 tNearX = madd(lower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat4 tNearY = madd(lower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat4 tNearZ = madd(lower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat4 tFarX = madd(upper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat4 tFarY = madd(upper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat4 tFarZ = madd(upper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat4 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat4 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat4 tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat4 tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat4 tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat4 tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat4 tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat4 tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if (defined(__aarch64__) && defined(BUILD_IOS)) || defined(__SSE4_1__) && !defined(__AVX512F__) // up to HSW
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<4)-1);
+#elif defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<4,4>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,4,true>& ray, vfloat4& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat4 start_x(node->start.x);
+ const vfloat4 scale_x(node->scale.x);
+ const vfloat4 lower_x = madd(node->dequantize<4>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat4 upper_x = madd(node->dequantize<4>(ray.farX >> 2),scale_x,start_x);
+ const vfloat4 start_y(node->start.y);
+ const vfloat4 scale_y(node->scale.y);
+ const vfloat4 lower_y = madd(node->dequantize<4>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat4 upper_y = madd(node->dequantize<4>(ray.farY >> 2),scale_y,start_y);
+ const vfloat4 start_z(node->start.z);
+ const vfloat4 scale_z(node->scale.z);
+ const vfloat4 lower_z = madd(node->dequantize<4>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat4 upper_z = madd(node->dequantize<4>(ray.farZ >> 2),scale_z,start_z);
+
+ const vfloat4 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat4 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat4 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat4 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat4 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat4 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline size_t intersectNode<8,8>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,8,false>& ray, vfloat8& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat8 start_x(node->start.x);
+ const vfloat8 scale_x(node->scale.x);
+ const vfloat8 lower_x = madd(node->dequantize<8>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat8 upper_x = madd(node->dequantize<8>(ray.farX >> 2),scale_x,start_x);
+ const vfloat8 start_y(node->start.y);
+ const vfloat8 scale_y(node->scale.y);
+ const vfloat8 lower_y = madd(node->dequantize<8>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat8 upper_y = madd(node->dequantize<8>(ray.farY >> 2),scale_y,start_y);
+ const vfloat8 start_z(node->start.z);
+ const vfloat8 scale_z(node->scale.z);
+ const vfloat8 lower_z = madd(node->dequantize<8>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat8 upper_z = madd(node->dequantize<8>(ray.farZ >> 2),scale_z,start_z);
+
+#if defined(__AVX2__)
+#if defined(__aarch64__)
+ const vfloat8 tNearX = madd(lower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat8 tNearY = madd(lower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat8 tNearZ = madd(lower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat8 tFarX = madd(upper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat8 tFarY = madd(upper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat8 tFarZ = madd(upper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat8 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat8 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat8 tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat8 tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat8 tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat8 tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat8 tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat8 tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX2__) && !defined(__AVX512F__) // HSW
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<8)-1);
+#elif defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<8,8>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,8,true>& ray, vfloat8& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat8 start_x(node->start.x);
+ const vfloat8 scale_x(node->scale.x);
+ const vfloat8 lower_x = madd(node->dequantize<8>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat8 upper_x = madd(node->dequantize<8>(ray.farX >> 2),scale_x,start_x);
+ const vfloat8 start_y(node->start.y);
+ const vfloat8 scale_y(node->scale.y);
+ const vfloat8 lower_y = madd(node->dequantize<8>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat8 upper_y = madd(node->dequantize<8>(ray.farY >> 2),scale_y,start_y);
+ const vfloat8 start_z(node->start.z);
+ const vfloat8 scale_z(node->scale.z);
+ const vfloat8 lower_z = madd(node->dequantize<8>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat8 upper_z = madd(node->dequantize<8>(ray.farZ >> 2),scale_z,start_z);
+
+ const vfloat8 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat8 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat8 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat8 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat8 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat8 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+
+#endif
+
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+
+ template<>
+ __forceinline size_t intersectNode<4,16>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,16,false>& ray, vfloat16& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat16 start_x(node->start.x);
+ const vfloat16 scale_x(node->scale.x);
+ const vfloat16 lower_x = madd(vfloat16(node->dequantize<4>(ray.nearX >> 2)),scale_x,start_x);
+ const vfloat16 upper_x = madd(vfloat16(node->dequantize<4>(ray.farX >> 2)),scale_x,start_x);
+ const vfloat16 start_y(node->start.y);
+ const vfloat16 scale_y(node->scale.y);
+ const vfloat16 lower_y = madd(vfloat16(node->dequantize<4>(ray.nearY >> 2)),scale_y,start_y);
+ const vfloat16 upper_y = madd(vfloat16(node->dequantize<4>(ray.farY >> 2)),scale_y,start_y);
+ const vfloat16 start_z(node->start.z);
+ const vfloat16 scale_z(node->scale.z);
+ const vfloat16 lower_z = madd(vfloat16(node->dequantize<4>(ray.nearZ >> 2)),scale_z,start_z);
+ const vfloat16 upper_z = madd(vfloat16(node->dequantize<4>(ray.farZ >> 2)),scale_z,start_z);
+
+ const vfloat16 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat16 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool16 vmask = le(vbool16(0xf),tNear,tFar);
+ const size_t mask = movemask(vmask) & mvalid;
+ dist = tNear;
+ return mask;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<4,16>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,16,true>& ray, vfloat16& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat16 start_x(node->start.x);
+ const vfloat16 scale_x(node->scale.x);
+ const vfloat16 lower_x = madd(vfloat16(node->dequantize<4>(ray.nearX >> 2)),scale_x,start_x);
+ const vfloat16 upper_x = madd(vfloat16(node->dequantize<4>(ray.farX >> 2)),scale_x,start_x);
+ const vfloat16 start_y(node->start.y);
+ const vfloat16 scale_y(node->scale.y);
+ const vfloat16 lower_y = madd(vfloat16(node->dequantize<4>(ray.nearY >> 2)),scale_y,start_y);
+ const vfloat16 upper_y = madd(vfloat16(node->dequantize<4>(ray.farY >> 2)),scale_y,start_y);
+ const vfloat16 start_z(node->start.z);
+ const vfloat16 scale_z(node->scale.z);
+ const vfloat16 lower_z = madd(vfloat16(node->dequantize<4>(ray.nearZ >> 2)),scale_z,start_z);
+ const vfloat16 upper_z = madd(vfloat16(node->dequantize<4>(ray.farZ >> 2)),scale_z,start_z);
+
+ const vfloat16 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat16 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat16 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat16 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat16 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat16 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat16 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat16 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool16 vmask = le(vbool16(0xf),tNear,tFar);
+ const size_t mask = movemask(vmask) & mvalid;
+ dist = tNear;
+ return mask;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<8,16>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,16,false>& ray, vfloat16& dist)
+ {
+ const vbool16 m_valid(node->validMask16());
+ const vfloat16 bminmaxX = node->dequantizeLowerUpperX(ray.permX);
+ const vfloat16 bminmaxY = node->dequantizeLowerUpperY(ray.permY);
+ const vfloat16 bminmaxZ = node->dequantizeLowerUpperZ(ray.permZ);
+ const vfloat16 tNearFarX = msub(bminmaxX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tNearFarY = msub(bminmaxY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tNearFarZ = msub(bminmaxZ, ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tNear = max(tNearFarX, tNearFarY, tNearFarZ, ray.tnear);
+ const vfloat16 tFar = min(tNearFarX, tNearFarY, tNearFarZ, ray.tfar);
+ const vbool16 vmask = le(m_valid,tNear,align_shift_right<8>(tFar, tFar));
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<8,16>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,16,true>& ray, vfloat16& dist)
+ {
+ const vbool16 m_valid(node->validMask16());
+ const vfloat16 bminmaxX = node->dequantizeLowerUpperX(ray.permX);
+ const vfloat16 bminmaxY = node->dequantizeLowerUpperY(ray.permY);
+ const vfloat16 bminmaxZ = node->dequantizeLowerUpperZ(ray.permZ);
+ const vfloat16 tNearFarX = (bminmaxX - ray.org.x) * ray.rdir_far.x; // FIXME: this is not conservative !!!!!!!!!
+ const vfloat16 tNearFarY = (bminmaxY - ray.org.y) * ray.rdir_far.y;
+ const vfloat16 tNearFarZ = (bminmaxZ - ray.org.z) * ray.rdir_far.z;
+ const vfloat16 tNear = max(tNearFarX, tNearFarY, tNearFarZ, ray.tnear);
+ const vfloat16 tFar = min(tNearFarX, tNearFarY, tNearFarZ, ray.tfar);
+ const vbool16 vmask = le(m_valid,tNear,align_shift_right<8>(tFar, tFar));
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+
+#endif
+
+
+ template<int N, int Nx>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,Nx,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const vboolf<N> mvalid = node->validMask();
+ const vfloat<N> lower_x = node->dequantizeLowerX(time);
+ const vfloat<N> upper_x = node->dequantizeUpperX(time);
+ const vfloat<N> lower_y = node->dequantizeLowerY(time);
+ const vfloat<N> upper_y = node->dequantizeUpperY(time);
+ const vfloat<N> lower_z = node->dequantizeLowerZ(time);
+ const vfloat<N> upper_z = node->dequantizeUpperZ(time);
+#if defined(__FMA_X4__)
+#if defined(__aarch64__)
+ const vfloat<N> tNearX = madd(lower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tNearY = madd(lower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tNearZ = madd(lower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<N> tFarX = madd(upper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<N> tFarY = madd(upper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<N> tFarZ = madd(upper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat<N> tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#endif
+#else
+ const vfloat<N> tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+ const vfloat<N> tminX = mini(tNearX,tFarX);
+ const vfloat<N> tmaxX = maxi(tNearX,tFarX);
+ const vfloat<N> tminY = mini(tNearY,tFarY);
+ const vfloat<N> tmaxY = maxi(tNearY,tFarY);
+ const vfloat<N> tminZ = mini(tNearZ,tFarZ);
+ const vfloat<N> tmaxZ = maxi(tNearZ,tFarZ);
+ const vfloat<N> tNear = maxi(tminX,tminY,tminZ,ray.tnear);
+ const vfloat<N> tFar = mini(tmaxX,tmaxY,tmaxZ,ray.tfar);
+#if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vbool<N> vmask = le(mvalid,asInt(tNear),asInt(tFar));
+#else
+ const vbool<N> vmask = (asInt(tNear) <= asInt(tFar)) & mvalid;
+#endif
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ template<int N, int Nx>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,Nx,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const vboolf<N> mvalid = node->validMask();
+ const vfloat<N> lower_x = node->dequantizeLowerX(time);
+ const vfloat<N> upper_x = node->dequantizeUpperX(time);
+ const vfloat<N> lower_y = node->dequantizeLowerY(time);
+ const vfloat<N> upper_y = node->dequantizeUpperY(time);
+ const vfloat<N> lower_z = node->dequantizeLowerZ(time);
+ const vfloat<N> upper_z = node->dequantizeUpperZ(time);
+ const vfloat<N> tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat<N> tminX = mini(tNearX,tFarX);
+ const vfloat<N> tmaxX = maxi(tNearX,tFarX);
+ const vfloat<N> tminY = mini(tNearY,tFarY);
+ const vfloat<N> tmaxY = maxi(tNearY,tFarY);
+ const vfloat<N> tminZ = mini(tNearZ,tFarZ);
+ const vfloat<N> tmaxZ = maxi(tNearZ,tFarZ);
+ const vfloat<N> tNear = maxi(tminX,tminY,tminZ,ray.tnear);
+ const vfloat<N> tFar = mini(tmaxX,tmaxY,tmaxZ,ray.tfar);
+#if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vbool<N> vmask = le(mvalid,asInt(tNear),asInt(tFar));
+#else
+ const vbool<N> vmask = (asInt(tNear) <= asInt(tFar)) & mvalid;
+#endif
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+
+#if defined(__AVX512ER__)
+ // for KNL
+ template<>
+ __forceinline size_t intersectNode<4,16>(const typename BVHN<4>::QuantizedBaseNodeMB* node, const TravRay<4,16,false>& ray, const float time, vfloat<4>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat16 lower_x = node->dequantizeLowerX(time);
+ const vfloat16 upper_x = node->dequantizeUpperX(time);
+ const vfloat16 lower_y = node->dequantizeLowerY(time);
+ const vfloat16 upper_y = node->dequantizeUpperY(time);
+ const vfloat16 lower_z = node->dequantizeLowerZ(time);
+ const vfloat16 upper_z = node->dequantizeUpperZ(time);
+
+ const vfloat16 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat16 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat16 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat16 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+
+ const vfloat16 tminX = min(tNearX,tFarX);
+ const vfloat16 tmaxX = max(tNearX,tFarX);
+ const vfloat16 tminY = min(tNearY,tFarY);
+ const vfloat16 tmaxY = max(tNearY,tFarY);
+ const vfloat16 tminZ = min(tNearZ,tFarZ);
+ const vfloat16 tmaxZ = max(tNearZ,tFarZ);
+ const vfloat16 tNear = max(tminX,tminY,tminZ,ray.tnear);
+ const vfloat16 tFar = min(tmaxX,tmaxY,tmaxZ,ray.tfar );
+ const vbool16 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask) & mvalid;
+ dist = extractN<4,0>(tNear);
+ return mask;
+ }
+
+
+ // for KNL
+ template<>
+ __forceinline size_t intersectNode<4,16>(const typename BVHN<4>::QuantizedBaseNodeMB* node, const TravRay<4,16,true>& ray, const float time, vfloat<4>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat16 lower_x = node->dequantizeLowerX(time);
+ const vfloat16 upper_x = node->dequantizeUpperX(time);
+ const vfloat16 lower_y = node->dequantizeLowerY(time);
+ const vfloat16 upper_y = node->dequantizeUpperY(time);
+ const vfloat16 lower_z = node->dequantizeLowerZ(time);
+ const vfloat16 upper_z = node->dequantizeUpperZ(time);
+
+ const vfloat16 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat16 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat16 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat16 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat16 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat16 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat16 tminX = min(tNearX,tFarX);
+ const vfloat16 tmaxX = max(tNearX,tFarX);
+ const vfloat16 tminY = min(tNearY,tFarY);
+ const vfloat16 tmaxY = max(tNearY,tFarY);
+ const vfloat16 tminZ = min(tNearZ,tFarZ);
+ const vfloat16 tmaxZ = max(tNearZ,tFarZ);
+ const vfloat16 tNear = max(tminX,tminY,tminZ,ray.tnear);
+ const vfloat16 tFar = min(tmaxX,tmaxY,tmaxZ,ray.tfar );
+ const vbool16 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask) & mvalid;
+ dist = extractN<4,0>(tNear);
+ return mask;
+ }
+
+#endif
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::OBBNode* node, const TravRay<N,N,robust>& ray, vfloat<N>& dist)
+ {
+ const Vec3vf<N> dir = xfmVector(node->naabb,ray.dir);
+ //const Vec3vf<N> nrdir = Vec3vf<N>(vfloat<N>(-1.0f))/dir;
+ const Vec3vf<N> nrdir = Vec3vf<N>(vfloat<N>(-1.0f))*rcp_safe(dir);
+ const Vec3vf<N> org = xfmPoint(node->naabb,ray.org);
+ const Vec3vf<N> tLowerXYZ = org * nrdir; // (Vec3fa(zero) - org) * rdir;
+ const Vec3vf<N> tUpperXYZ = tLowerXYZ - nrdir; // (Vec3fa(one ) - org) * rdir;
+
+ const vfloat<N> tNearX = mini(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tNearY = mini(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tNearZ = mini(tLowerXYZ.z,tUpperXYZ.z);
+ const vfloat<N> tFarX = maxi(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tFarY = maxi(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tFarZ = maxi(tLowerXYZ.z,tUpperXYZ.z);
+ vfloat<N> tNear = max(ray.tnear, tNearX,tNearY,tNearZ);
+ vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ if (robust) {
+ tNear = tNear*vfloat<N>(1.0f-3.0f*float(ulp));
+ tFar = tFar *vfloat<N>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<N> vmask = tNear <= tFar;
+ dist = tNear;
+ return movemask(vmask);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::OBBNodeMB* node, const TravRay<N,N,robust>& ray, const float time, vfloat<N>& dist)
+ {
+ const AffineSpace3vf<N> xfm = node->space0;
+ const Vec3vf<N> b0_lower = zero;
+ const Vec3vf<N> b0_upper = one;
+ const Vec3vf<N> lower = lerp(b0_lower,node->b1.lower,vfloat<N>(time));
+ const Vec3vf<N> upper = lerp(b0_upper,node->b1.upper,vfloat<N>(time));
+
+ const BBox3vf<N> bounds(lower,upper);
+ const Vec3vf<N> dir = xfmVector(xfm,ray.dir);
+ const Vec3vf<N> rdir = rcp_safe(dir);
+ const Vec3vf<N> org = xfmPoint(xfm,ray.org);
+
+ const Vec3vf<N> tLowerXYZ = (bounds.lower - org) * rdir;
+ const Vec3vf<N> tUpperXYZ = (bounds.upper - org) * rdir;
+
+ const vfloat<N> tNearX = mini(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tNearY = mini(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tNearZ = mini(tLowerXYZ.z,tUpperXYZ.z);
+ const vfloat<N> tFarX = maxi(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tFarY = maxi(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tFarZ = maxi(tLowerXYZ.z,tUpperXYZ.z);
+ vfloat<N> tNear = max(ray.tnear, tNearX,tNearY,tNearZ);
+ vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ if (robust) {
+ tNear = tNear*vfloat<N>(1.0f-3.0f*float(ulp));
+ tFar = tFar *vfloat<N>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<N> vmask = tNear <= tFar;
+ dist = tNear;
+ return movemask(vmask);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in point query raversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Computes traversal information for N nodes with 1 point query */
+ template<int N, int types>
+ struct BVHNNodePointQuerySphere1;
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere(node.getAABBNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere(node.getAABBNodeMB(), query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_AN4D>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphereMB4D<N>(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN1_UN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = pointQueryNodeSphere(node.getAABBNode(), query, dist);
+ else if (unlikely(node.isOBBNode())) mask = pointQueryNodeSphere(node.ungetAABBNode(), query, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = pointQueryNodeSphere(node.getAABBNodeMB(), query, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeSphere(node.ungetAABBNodeMB(), query, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_AN4D_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeSphere(node.ungetAABBNodeMB(), query, time, dist);
+ else mask = pointQueryNodeSphereMB4D(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_QN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNQuantizedBaseNodePointQuerySphere1
+ {
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ return pointQueryNodeSphere(node,query,dist);
+ }
+
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ return pointQueryNodeSphere(node,query,time,dist);
+ }
+ };
+
+ /*! Computes traversal information for N nodes with 1 point query */
+ template<int N, int types>
+ struct BVHNNodePointQueryAABB1;
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB(node.getAABBNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB(node.getAABBNodeMB(), query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_AN4D>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABBMB4D<N>(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN1_UN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = pointQueryNodeAABB(node.getAABBNode(), query, dist);
+ else if (unlikely(node.isOBBNode())) mask = pointQueryNodeAABB(node.ungetAABBNode(), query, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = pointQueryNodeAABB(node.getAABBNodeMB(), query, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeAABB(node.ungetAABBNodeMB(), query, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_AN4D_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeAABB(node.ungetAABBNodeMB(), query, time, dist);
+ else mask = pointQueryNodeAABBMB4D(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_QN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNQuantizedBaseNodePointQueryAABB1
+ {
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ return pointQueryNodeAABB(node,query,dist);
+ }
+
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ return pointQueryNodeAABB(node,query,time,dist);
+ }
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Intersects N nodes with 1 ray */
+ template<int N, int Nx, int types, bool robust>
+ struct BVHNNodeIntersector1;
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode(node.getAABBNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust(node.getAABBNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode(node.getAABBNodeMB(), ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust(node.getAABBNodeMB(), ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_AN4D, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeMB4D<N>(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_AN4D, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeMB4DRobust<N>(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN1_UN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = intersectNode(node.getAABBNode(), ray, dist);
+ else if (unlikely(node.isOBBNode())) mask = intersectNode(node.ungetAABBNode(), ray, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN1_UN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = intersectNodeRobust(node.getAABBNode(), ray, dist);
+ else if (unlikely(node.isOBBNode())) mask = intersectNode(node.ungetAABBNode(), ray, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = intersectNode(node.getAABBNodeMB(), ray, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = intersectNodeRobust(node.getAABBNodeMB(), ray, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_AN4D_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else mask = intersectNodeMB4D(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_AN2_AN4D_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else mask = intersectNodeMB4DRobust(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_QN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,false>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int Nx>
+ struct BVHNNodeIntersector1<N, Nx, BVH_QN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,Nx,true>& ray, float time, vfloat<Nx>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), ray, dist);
+ return true;
+ }
+ };
+
+ /*! Intersects N nodes with K rays */
+ template<int N, int Nx, bool robust>
+ struct BVHNQuantizedBaseNodeIntersector1;
+
+ template<int N, int Nx>
+ struct BVHNQuantizedBaseNodeIntersector1<N, Nx, false>
+ {
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,Nx,false>& ray, vfloat<Nx>& dist)
+ {
+ return intersectNode(node,ray,dist);
+ }
+
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,Nx,false>& ray, const float time, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,time,dist);
+ }
+
+ };
+
+ template<int N, int Nx>
+ struct BVHNQuantizedBaseNodeIntersector1<N, Nx, true>
+ {
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,Nx,true>& ray, vfloat<Nx>& dist)
+ {
+ return intersectNode(node,ray,dist);
+ }
+
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,Nx,true>& ray, const float time, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,time,dist);
+ }
+
+ };
+
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/node_intersector_frustum.h b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_frustum.h
new file mode 100644
index 0000000000..800ac8b478
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_frustum.h
@@ -0,0 +1,269 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Frustum structure used in hybrid and stream traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*
+ Optimized frustum test. We calculate t=(p-org)/dir in ray/box
+ intersection. We assume the rays are split by octant, thus
+ dir intervals are either positive or negative in each
+ dimension.
+
+ Case 1: dir.min >= 0 && dir.max >= 0:
+ t_min = (p_min - org_max) / dir_max = (p_min - org_max)*rdir_min = p_min*rdir_min - org_max*rdir_min
+ t_max = (p_max - org_min) / dir_min = (p_max - org_min)*rdir_max = p_max*rdir_max - org_min*rdir_max
+
+ Case 2: dir.min < 0 && dir.max < 0:
+ t_min = (p_max - org_min) / dir_min = (p_max - org_min)*rdir_max = p_max*rdir_max - org_min*rdir_max
+ t_max = (p_min - org_max) / dir_max = (p_min - org_max)*rdir_min = p_min*rdir_min - org_max*rdir_min
+ */
+
+ template<bool robust>
+ struct Frustum;
+
+ /* Fast variant */
+ template<>
+ struct Frustum<false>
+ {
+ __forceinline Frustum() {}
+
+ template<int K>
+ __forceinline Frustum(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(valid, org, rdir, ray_tnear, ray_tfar, N);
+ }
+
+ template<int K>
+ __forceinline void init(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ const Vec3fa reduced_min_org(reduce_min(select(valid, org.x, pos_inf)),
+ reduce_min(select(valid, org.y, pos_inf)),
+ reduce_min(select(valid, org.z, pos_inf)));
+
+ const Vec3fa reduced_max_org(reduce_max(select(valid, org.x, neg_inf)),
+ reduce_max(select(valid, org.y, neg_inf)),
+ reduce_max(select(valid, org.z, neg_inf)));
+
+ const Vec3fa reduced_min_rdir(reduce_min(select(valid, rdir.x, pos_inf)),
+ reduce_min(select(valid, rdir.y, pos_inf)),
+ reduce_min(select(valid, rdir.z, pos_inf)));
+
+ const Vec3fa reduced_max_rdir(reduce_max(select(valid, rdir.x, neg_inf)),
+ reduce_max(select(valid, rdir.y, neg_inf)),
+ reduce_max(select(valid, rdir.z, neg_inf)));
+
+ const float reduced_min_dist = reduce_min(select(valid, ray_tnear, vfloat<K>(pos_inf)));
+ const float reduced_max_dist = reduce_max(select(valid, ray_tfar , vfloat<K>(neg_inf)));
+
+ init(reduced_min_org, reduced_max_org, reduced_min_rdir, reduced_max_rdir, reduced_min_dist, reduced_max_dist, N);
+ }
+
+ __forceinline void init(const Vec3fa& reduced_min_org,
+ const Vec3fa& reduced_max_org,
+ const Vec3fa& reduced_min_rdir,
+ const Vec3fa& reduced_max_rdir,
+ float reduced_min_dist,
+ float reduced_max_dist,
+ int N)
+ {
+ const Vec3ba pos_rdir = ge_mask(reduced_min_rdir, Vec3fa(zero));
+
+ min_rdir = select(pos_rdir, reduced_min_rdir, reduced_max_rdir);
+ max_rdir = select(pos_rdir, reduced_max_rdir, reduced_min_rdir);
+
+#if defined (__aarch64__)
+ neg_min_org_rdir = -(min_rdir * select(pos_rdir, reduced_max_org, reduced_min_org));
+ neg_max_org_rdir = -(max_rdir * select(pos_rdir, reduced_min_org, reduced_max_org));
+#else
+ min_org_rdir = min_rdir * select(pos_rdir, reduced_max_org, reduced_min_org);
+ max_org_rdir = max_rdir * select(pos_rdir, reduced_min_org, reduced_max_org);
+#endif
+ min_dist = reduced_min_dist;
+ max_dist = reduced_max_dist;
+
+ nf = NearFarPrecalculations(min_rdir, N);
+ }
+
+ template<int K>
+ __forceinline void updateMaxDist(const vfloat<K>& ray_tfar)
+ {
+ max_dist = reduce_max(ray_tfar);
+ }
+
+ NearFarPrecalculations nf;
+
+ Vec3fa min_rdir;
+ Vec3fa max_rdir;
+
+#if defined (__aarch64__)
+ Vec3fa neg_min_org_rdir;
+ Vec3fa neg_max_org_rdir;
+#else
+ Vec3fa min_org_rdir;
+ Vec3fa max_org_rdir;
+#endif
+ float min_dist;
+ float max_dist;
+ };
+
+ typedef Frustum<false> FrustumFast;
+
+ /* Robust variant */
+ template<>
+ struct Frustum<true>
+ {
+ __forceinline Frustum() {}
+
+ template<int K>
+ __forceinline Frustum(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(valid, org, rdir, ray_tnear, ray_tfar, N);
+ }
+
+ template<int K>
+ __forceinline void init(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ const Vec3fa reduced_min_org(reduce_min(select(valid, org.x, pos_inf)),
+ reduce_min(select(valid, org.y, pos_inf)),
+ reduce_min(select(valid, org.z, pos_inf)));
+
+ const Vec3fa reduced_max_org(reduce_max(select(valid, org.x, neg_inf)),
+ reduce_max(select(valid, org.y, neg_inf)),
+ reduce_max(select(valid, org.z, neg_inf)));
+
+ const Vec3fa reduced_min_rdir(reduce_min(select(valid, rdir.x, pos_inf)),
+ reduce_min(select(valid, rdir.y, pos_inf)),
+ reduce_min(select(valid, rdir.z, pos_inf)));
+
+ const Vec3fa reduced_max_rdir(reduce_max(select(valid, rdir.x, neg_inf)),
+ reduce_max(select(valid, rdir.y, neg_inf)),
+ reduce_max(select(valid, rdir.z, neg_inf)));
+
+ const float reduced_min_dist = reduce_min(select(valid, ray_tnear, vfloat<K>(pos_inf)));
+ const float reduced_max_dist = reduce_max(select(valid, ray_tfar , vfloat<K>(neg_inf)));
+
+ init(reduced_min_org, reduced_max_org, reduced_min_rdir, reduced_max_rdir, reduced_min_dist, reduced_max_dist, N);
+ }
+
+ __forceinline void init(const Vec3fa& reduced_min_org,
+ const Vec3fa& reduced_max_org,
+ const Vec3fa& reduced_min_rdir,
+ const Vec3fa& reduced_max_rdir,
+ float reduced_min_dist,
+ float reduced_max_dist,
+ int N)
+ {
+ const Vec3ba pos_rdir = ge_mask(reduced_min_rdir, Vec3fa(zero));
+ min_rdir = select(pos_rdir, reduced_min_rdir, reduced_max_rdir);
+ max_rdir = select(pos_rdir, reduced_max_rdir, reduced_min_rdir);
+
+ min_org = select(pos_rdir, reduced_max_org, reduced_min_org);
+ max_org = select(pos_rdir, reduced_min_org, reduced_max_org);
+
+ min_dist = reduced_min_dist;
+ max_dist = reduced_max_dist;
+
+ nf = NearFarPrecalculations(min_rdir, N);
+ }
+
+ template<int K>
+ __forceinline void updateMaxDist(const vfloat<K>& ray_tfar)
+ {
+ max_dist = reduce_max(ray_tfar);
+ }
+
+ NearFarPrecalculations nf;
+
+ Vec3fa min_rdir;
+ Vec3fa max_rdir;
+
+ Vec3fa min_org;
+ Vec3fa max_org;
+
+ float min_dist;
+ float max_dist;
+ };
+
+ typedef Frustum<true> FrustumRobust;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx>
+ __forceinline size_t intersectNodeFrustum(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const FrustumFast& frustum, vfloat<Nx>& dist)
+ {
+ const vfloat<Nx> bminX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearX);
+ const vfloat<Nx> bminY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearY);
+ const vfloat<Nx> bminZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearZ);
+ const vfloat<Nx> bmaxX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farX);
+ const vfloat<Nx> bmaxY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farY);
+ const vfloat<Nx> bmaxZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farZ);
+
+#if defined (__aarch64__)
+ const vfloat<Nx> fminX = madd(bminX, vfloat<Nx>(frustum.min_rdir.x), vfloat<Nx>(frustum.neg_min_org_rdir.x));
+ const vfloat<Nx> fminY = madd(bminY, vfloat<Nx>(frustum.min_rdir.y), vfloat<Nx>(frustum.neg_min_org_rdir.y));
+ const vfloat<Nx> fminZ = madd(bminZ, vfloat<Nx>(frustum.min_rdir.z), vfloat<Nx>(frustum.neg_min_org_rdir.z));
+ const vfloat<Nx> fmaxX = madd(bmaxX, vfloat<Nx>(frustum.max_rdir.x), vfloat<Nx>(frustum.neg_max_org_rdir.x));
+ const vfloat<Nx> fmaxY = madd(bmaxY, vfloat<Nx>(frustum.max_rdir.y), vfloat<Nx>(frustum.neg_max_org_rdir.y));
+ const vfloat<Nx> fmaxZ = madd(bmaxZ, vfloat<Nx>(frustum.max_rdir.z), vfloat<Nx>(frustum.neg_max_org_rdir.z));
+#else
+ const vfloat<Nx> fminX = msub(bminX, vfloat<Nx>(frustum.min_rdir.x), vfloat<Nx>(frustum.min_org_rdir.x));
+ const vfloat<Nx> fminY = msub(bminY, vfloat<Nx>(frustum.min_rdir.y), vfloat<Nx>(frustum.min_org_rdir.y));
+ const vfloat<Nx> fminZ = msub(bminZ, vfloat<Nx>(frustum.min_rdir.z), vfloat<Nx>(frustum.min_org_rdir.z));
+ const vfloat<Nx> fmaxX = msub(bmaxX, vfloat<Nx>(frustum.max_rdir.x), vfloat<Nx>(frustum.max_org_rdir.x));
+ const vfloat<Nx> fmaxY = msub(bmaxY, vfloat<Nx>(frustum.max_rdir.y), vfloat<Nx>(frustum.max_org_rdir.y));
+ const vfloat<Nx> fmaxZ = msub(bmaxZ, vfloat<Nx>(frustum.max_rdir.z), vfloat<Nx>(frustum.max_org_rdir.z));
+#endif
+ const vfloat<Nx> fmin = maxi(fminX, fminY, fminZ, vfloat<Nx>(frustum.min_dist));
+ dist = fmin;
+ const vfloat<Nx> fmax = mini(fmaxX, fmaxY, fmaxZ, vfloat<Nx>(frustum.max_dist));
+ const vbool<Nx> vmask_node_hit = fmin <= fmax;
+ size_t m_node = movemask(vmask_node_hit) & (((size_t)1 << N)-1);
+ return m_node;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx>
+ __forceinline size_t intersectNodeFrustum(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const FrustumRobust& frustum, vfloat<Nx>& dist)
+ {
+ const vfloat<Nx> bminX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearX);
+ const vfloat<Nx> bminY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearY);
+ const vfloat<Nx> bminZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearZ);
+ const vfloat<Nx> bmaxX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farX);
+ const vfloat<Nx> bmaxY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farY);
+ const vfloat<Nx> bmaxZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farZ);
+
+ const vfloat<Nx> fminX = (bminX - vfloat<Nx>(frustum.min_org.x)) * vfloat<Nx>(frustum.min_rdir.x);
+ const vfloat<Nx> fminY = (bminY - vfloat<Nx>(frustum.min_org.y)) * vfloat<Nx>(frustum.min_rdir.y);
+ const vfloat<Nx> fminZ = (bminZ - vfloat<Nx>(frustum.min_org.z)) * vfloat<Nx>(frustum.min_rdir.z);
+ const vfloat<Nx> fmaxX = (bmaxX - vfloat<Nx>(frustum.max_org.x)) * vfloat<Nx>(frustum.max_rdir.x);
+ const vfloat<Nx> fmaxY = (bmaxY - vfloat<Nx>(frustum.max_org.y)) * vfloat<Nx>(frustum.max_rdir.y);
+ const vfloat<Nx> fmaxZ = (bmaxZ - vfloat<Nx>(frustum.max_org.z)) * vfloat<Nx>(frustum.max_rdir.z);
+
+ const float round_down = 1.0f-2.0f*float(ulp); // FIXME: use per instruction rounding for AVX512
+ const float round_up = 1.0f+2.0f*float(ulp);
+ const vfloat<Nx> fmin = max(fminX, fminY, fminZ, vfloat<Nx>(frustum.min_dist));
+ dist = fmin;
+ const vfloat<Nx> fmax = min(fmaxX, fmaxY, fmaxZ, vfloat<Nx>(frustum.max_dist));
+ const vbool<Nx> vmask_node_hit = (round_down*fmin <= round_up*fmax);
+ size_t m_node = movemask(vmask_node_hit) & (((size_t)1 << N)-1);
+ return m_node;
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet.h b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet.h
new file mode 100644
index 0000000000..0543e56f8e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet.h
@@ -0,0 +1,843 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray packet structure used in hybrid traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int K, bool robust>
+ struct TravRayK;
+
+ /* Fast variant */
+ template<int K>
+ struct TravRayK<K, false>
+ {
+ __forceinline TravRayK() {}
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ init(ray_org, ray_dir, N);
+ }
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(ray_org, ray_dir, N);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ org = ray_org;
+ dir = ray_dir;
+ rdir = rcp_safe(ray_dir);
+#if defined(__aarch64__)
+ neg_org_rdir = -(org * rdir);
+#elif defined(__AVX2__)
+ org_rdir = org * rdir;
+#endif
+ if (N)
+ {
+ const int size = sizeof(float)*N;
+ nearXYZ.x = select(rdir.x >= 0.0f, vint<K>(0*size), vint<K>(1*size));
+ nearXYZ.y = select(rdir.y >= 0.0f, vint<K>(2*size), vint<K>(3*size));
+ nearXYZ.z = select(rdir.z >= 0.0f, vint<K>(4*size), vint<K>(5*size));
+ }
+ }
+
+ Vec3vf<K> org;
+ Vec3vf<K> dir;
+ Vec3vf<K> rdir;
+#if defined(__aarch64__)
+ Vec3vf<K> neg_org_rdir;
+#elif defined(__AVX2__)
+ Vec3vf<K> org_rdir;
+#endif
+ Vec3vi<K> nearXYZ;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKFast = TravRayK<K, false>;
+
+ /* Robust variant */
+ template<int K>
+ struct TravRayK<K, true>
+ {
+ __forceinline TravRayK() {}
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ init(ray_org, ray_dir, N);
+ }
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(ray_org, ray_dir, N);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ org = ray_org;
+ dir = ray_dir;
+ rdir = vfloat<K>(1.0f)/(zero_fix(ray_dir));
+
+ if (N)
+ {
+ const int size = sizeof(float)*N;
+ nearXYZ.x = select(rdir.x >= 0.0f, vint<K>(0*size), vint<K>(1*size));
+ nearXYZ.y = select(rdir.y >= 0.0f, vint<K>(2*size), vint<K>(3*size));
+ nearXYZ.z = select(rdir.z >= 0.0f, vint<K>(4*size), vint<K>(5*size));
+ }
+ }
+
+ Vec3vf<K> org;
+ Vec3vf<K> dir;
+ Vec3vf<K> rdir;
+ Vec3vi<K> nearXYZ;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKRobust = TravRayK<K, true>;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::AABBNode* node, size_t i,
+ const TravRayKFast<K>& ray, vfloat<K>& dist)
+
+ {
+#if defined(__aarch64__)
+ const vfloat<K> lclipMinX = madd(node->lower_x[i], ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMinY = madd(node->lower_y[i], ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMinZ = madd(node->lower_z[i], ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> lclipMaxX = madd(node->upper_x[i], ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMaxY = madd(node->upper_y[i], ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMaxZ = madd(node->upper_z[i], ray.rdir.z, ray.neg_org_rdir.z);
+#elif defined(__AVX2__)
+ const vfloat<K> lclipMinX = msub(node->lower_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(node->lower_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(node->lower_z[i], ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(node->upper_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(node->upper_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(node->upper_z[i], ray.rdir.z, ray.org_rdir.z);
+ #else
+ const vfloat<K> lclipMinX = (node->lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (node->lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (node->lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (node->upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (node->upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (node->upper_z[i] - ray.org.z) * ray.rdir.z;
+ #endif
+
+ #if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+ #endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ #if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ #else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ #endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKRobust(const typename BVHN<N>::AABBNode* node, size_t i,
+ const TravRayKRobust<K>& ray, vfloat<K>& dist)
+ {
+ // FIXME: use per instruction rounding for AVX512
+ const vfloat<K> lclipMinX = (node->lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (node->lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (node->lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (node->upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (node->upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (node->upper_z[i] - ray.org.z) * ray.rdir.z;
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<K> lnearP = round_down*max(max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY)), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY)), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::AABBNodeMB* node, const size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+#if defined(__aarch64__)
+ const vfloat<K> lclipMinX = madd(vlower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMinY = madd(vlower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMinZ = madd(vlower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> lclipMaxX = madd(vupper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMaxY = madd(vupper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMaxZ = madd(vupper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#elif defined(__AVX2__)
+ const vfloat<K> lclipMinX = msub(vlower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(vlower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(vlower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(vupper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(vupper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(vupper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+#endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+#if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+#else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+#endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKRobust(const typename BVHN<N>::AABBNodeMB* node, const size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+#if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ if (K == 16)
+ {
+ const vfloat<K> lnearP = round_down*maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+ else
+#endif
+ {
+ const vfloat<K> lnearP = round_down*maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKMB4D(const typename BVHN<N>::NodeRef ref, const size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+#if defined(__aarch64__)
+ const vfloat<K> lclipMinX = madd(vlower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMinY = madd(vlower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMinZ = madd(vlower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> lclipMaxX = madd(vupper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMaxY = madd(vupper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMaxZ = madd(vupper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#elif defined(__AVX2__)
+ const vfloat<K> lclipMinX = msub(vlower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(vlower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(vlower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(vupper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(vupper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(vupper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+ const vfloat<K> lnearP = maxi(maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY)), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY)), maxi(lclipMinZ, lclipMaxZ));
+ vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ lhit = lhit & (vfloat<K>(node1->lower_t[i]) <= time) & (time < vfloat<K>(node1->upper_t[i]));
+ }
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKMB4DRobust(const typename BVHN<N>::NodeRef ref, const size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<K> lnearP = round_down*maxi(maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY)), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY)), maxi(lclipMinZ, lclipMaxZ));
+ vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ lhit = lhit & (vfloat<K>(node1->lower_t[i]) <= time) & (time < vfloat<K>(node1->upper_t[i]));
+ }
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K, bool robust>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::OBBNode* node, const size_t i,
+ const TravRayK<K,robust>& ray, vfloat<K>& dist)
+ {
+ const AffineSpace3vf<K> naabb(Vec3f(node->naabb.l.vx.x[i], node->naabb.l.vx.y[i], node->naabb.l.vx.z[i]),
+ Vec3f(node->naabb.l.vy.x[i], node->naabb.l.vy.y[i], node->naabb.l.vy.z[i]),
+ Vec3f(node->naabb.l.vz.x[i], node->naabb.l.vz.y[i], node->naabb.l.vz.z[i]),
+ Vec3f(node->naabb.p .x[i], node->naabb.p .y[i], node->naabb.p .z[i]));
+
+ const Vec3vf<K> dir = xfmVector(naabb, ray.dir);
+ const Vec3vf<K> nrdir = Vec3vf<K>(vfloat<K>(-1.0f)) * rcp_safe(dir); // FIXME: negate instead of mul with -1?
+ const Vec3vf<K> org = xfmPoint(naabb, ray.org);
+
+ const vfloat<K> lclipMinX = org.x * nrdir.x; // (Vec3fa(zero) - org) * rdir;
+ const vfloat<K> lclipMinY = org.y * nrdir.y;
+ const vfloat<K> lclipMinZ = org.z * nrdir.z;
+ const vfloat<K> lclipMaxX = lclipMinX - nrdir.x; // (Vec3fa(one) - org) * rdir;
+ const vfloat<K> lclipMaxY = lclipMinY - nrdir.y;
+ const vfloat<K> lclipMaxZ = lclipMinZ - nrdir.z;
+
+ vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ if (robust) {
+ lnearP = lnearP*vfloat<K>(1.0f-3.0f*float(ulp));
+ lfarP = lfarP *vfloat<K>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K, bool robust>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::OBBNodeMB* node, const size_t i,
+ const TravRayK<K,robust>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const AffineSpace3vf<K> xfm(Vec3f(node->space0.l.vx.x[i], node->space0.l.vx.y[i], node->space0.l.vx.z[i]),
+ Vec3f(node->space0.l.vy.x[i], node->space0.l.vy.y[i], node->space0.l.vy.z[i]),
+ Vec3f(node->space0.l.vz.x[i], node->space0.l.vz.y[i], node->space0.l.vz.z[i]),
+ Vec3f(node->space0.p .x[i], node->space0.p .y[i], node->space0.p .z[i]));
+
+ const Vec3vf<K> b0_lower = zero;
+ const Vec3vf<K> b0_upper = one;
+ const Vec3vf<K> b1_lower(node->b1.lower.x[i], node->b1.lower.y[i], node->b1.lower.z[i]);
+ const Vec3vf<K> b1_upper(node->b1.upper.x[i], node->b1.upper.y[i], node->b1.upper.z[i]);
+ const Vec3vf<K> lower = lerp(b0_lower, b1_lower, time);
+ const Vec3vf<K> upper = lerp(b0_upper, b1_upper, time);
+
+ const Vec3vf<K> dir = xfmVector(xfm, ray.dir);
+ const Vec3vf<K> rdir = rcp_safe(dir);
+ const Vec3vf<K> org = xfmPoint(xfm, ray.org);
+
+ const vfloat<K> lclipMinX = (lower.x - org.x) * rdir.x;
+ const vfloat<K> lclipMinY = (lower.y - org.y) * rdir.y;
+ const vfloat<K> lclipMinZ = (lower.z - org.z) * rdir.z;
+ const vfloat<K> lclipMaxX = (upper.x - org.x) * rdir.x;
+ const vfloat<K> lclipMaxY = (upper.y - org.y) * rdir.y;
+ const vfloat<K> lclipMaxZ = (upper.z - org.z) * rdir.z;
+
+ vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ if (robust) {
+ lnearP = lnearP*vfloat<K>(1.0f-3.0f*float(ulp));
+ lfarP = lfarP *vfloat<K>(1.0f+3.0f*float(ulp));
+ }
+
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // QuantizedBaseNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeK(const typename BVHN<N>::QuantizedBaseNode* node, size_t i,
+ const TravRayK<K,false>& ray, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+ const vfloat<N> lower_x = node->dequantizeLowerX();
+ const vfloat<N> upper_x = node->dequantizeUpperX();
+ const vfloat<N> lower_y = node->dequantizeLowerY();
+ const vfloat<N> upper_y = node->dequantizeUpperY();
+ const vfloat<N> lower_z = node->dequantizeLowerZ();
+ const vfloat<N> upper_z = node->dequantizeUpperZ();
+
+ #if defined(__aarch64__)
+ const vfloat<K> lclipMinX = madd(lower_x[i], ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMinY = madd(lower_y[i], ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMinZ = madd(lower_z[i], ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> lclipMaxX = madd(upper_x[i], ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMaxY = madd(upper_y[i], ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMaxZ = madd(upper_z[i], ray.rdir.z, ray.neg_org_rdir.z);
+ #elif defined(__AVX2__)
+ const vfloat<K> lclipMinX = msub(lower_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(lower_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(lower_z[i], ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(upper_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(upper_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(upper_z[i], ray.rdir.z, ray.org_rdir.z);
+ #else
+ const vfloat<K> lclipMinX = (lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z[i] - ray.org.z) * ray.rdir.z;
+ #endif
+
+ #if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+ #endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ #if defined(__AVX512F__) && !defined(__AVX512ER__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ #else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ #endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeK(const typename BVHN<N>::QuantizedBaseNode* node, size_t i,
+ const TravRayK<K,true>& ray, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+ const vfloat<N> lower_x = node->dequantizeLowerX();
+ const vfloat<N> upper_x = node->dequantizeUpperX();
+ const vfloat<N> lower_y = node->dequantizeLowerY();
+ const vfloat<N> upper_y = node->dequantizeUpperY();
+ const vfloat<N> lower_z = node->dequantizeLowerZ();
+ const vfloat<N> upper_z = node->dequantizeUpperZ();
+
+ const vfloat<K> lclipMinX = (lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z[i] - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+ const vfloat<K> lnearP = round_down*max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeMBK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,false>& ray, const vfloat<K>& time, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+
+ const vfloat<K> lower_x = node->dequantizeLowerX(i,time);
+ const vfloat<K> upper_x = node->dequantizeUpperX(i,time);
+ const vfloat<K> lower_y = node->dequantizeLowerY(i,time);
+ const vfloat<K> upper_y = node->dequantizeUpperY(i,time);
+ const vfloat<K> lower_z = node->dequantizeLowerZ(i,time);
+ const vfloat<K> upper_z = node->dequantizeUpperZ(i,time);
+
+#if defined(__aarch64__)
+ const vfloat<K> lclipMinX = madd(lower_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMinY = madd(lower_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMinZ = madd(lower_z, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> lclipMaxX = madd(upper_x, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> lclipMaxY = madd(upper_y, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> lclipMaxZ = madd(upper_z, ray.rdir.z, ray.neg_org_rdir.z);
+#elif defined(__AVX2__)
+ const vfloat<K> lclipMinX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z - ray.org.z) * ray.rdir.z;
+ #endif
+ const vfloat<K> lnearP = max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeMBK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,true>& ray, const vfloat<K>& time, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+
+ const vfloat<K> lower_x = node->dequantizeLowerX(i,time);
+ const vfloat<K> upper_x = node->dequantizeUpperX(i,time);
+ const vfloat<K> lower_y = node->dequantizeLowerY(i,time);
+ const vfloat<K> upper_y = node->dequantizeUpperY(i,time);
+ const vfloat<K> lower_z = node->dequantizeLowerZ(i,time);
+ const vfloat<K> upper_z = node->dequantizeUpperZ(i,time);
+
+ const vfloat<K> lclipMinX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+ const vfloat<K> lnearP = round_down*max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in hybrid traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Intersects N nodes with K rays */
+ template<int N, int K, int types, bool robust>
+ struct BVHNNodeIntersectorK;
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1, false>
+ {
+ /* vmask is both an input and an output parameter! Its initial value should be the parent node
+ hit mask, which is used for correctly computing the current hit mask. The parent hit mask
+ is actually required only for motion blur node intersections (because different rays may
+ have different times), so for regular nodes vmask is simply overwritten. */
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeK<N,K>(node.getAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeKRobust<N,K>(node.getAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeK<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeKRobust<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1_UN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNode())) vmask = intersectNodeK<N,K>(node.getAABBNode(), i, ray, dist);
+ else /*if (unlikely(node.isOBBNode()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1_UN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNode())) vmask = intersectNodeKRobust<N,K>(node.getAABBNode(), i, ray, dist);
+ else /*if (unlikely(node.isOBBNode()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB())) vmask = intersectNodeK<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ else /*if (unlikely(node.isOBBNodeMB()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB())) vmask = intersectNodeKRobust<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ else /*if (unlikely(node.isOBBNodeMB()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask &= intersectNodeKMB4D<N,K>(node, i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask &= intersectNodeKMB4DRobust<N,K>(node, i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB() || node.isAABBNodeMB4D())) {
+ vmask &= intersectNodeKMB4D<N,K>(node, i, ray, time, dist);
+ } else /*if (unlikely(node.isOBBNodeMB()))*/ {
+ assert(node.isOBBNodeMB());
+ vmask &= intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ }
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB() || node.isAABBNodeMB4D())) {
+ vmask &= intersectNodeKMB4DRobust<N,K>(node, i, ray, time, dist);
+ } else /*if (unlikely(node.isOBBNodeMB()))*/ {
+ assert(node.isOBBNodeMB());
+ vmask &= intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ }
+ return true;
+ }
+ };
+
+
+ /*! Intersects N nodes with K rays */
+ template<int N, int K, bool robust>
+ struct BVHNQuantizedBaseNodeIntersectorK;
+
+ template<int N, int K>
+ struct BVHNQuantizedBaseNodeIntersectorK<N, K, false>
+ {
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNode* node, const size_t i,
+ const TravRayK<K,false>& ray, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeK<N,K>(node,i,ray,dist);
+ }
+
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,false>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeMBK<N,K>(node,i,ray,time,dist);
+ }
+
+ };
+
+ template<int N, int K>
+ struct BVHNQuantizedBaseNodeIntersectorK<N, K, true>
+ {
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNode* node, const size_t i,
+ const TravRayK<K,true>& ray, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeK<N,K>(node,i,ray,dist);
+ }
+
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,true>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeMBK<N,K>(node,i,ray,time,dist);
+ }
+ };
+
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet_stream.h b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet_stream.h
new file mode 100644
index 0000000000..f379b57aea
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/bvh/node_intersector_packet_stream.h
@@ -0,0 +1,215 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray packet structure used in stream traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int K, bool robust>
+ struct TravRayKStream;
+
+ /* Fast variant */
+ template<int K>
+ struct TravRayKStream<K, false>
+ {
+ __forceinline TravRayKStream() {}
+
+ __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar)
+ {
+ init(ray_org, ray_dir);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir)
+ {
+ rdir = rcp_safe(ray_dir);
+#if defined(__aarch64__)
+ neg_org_rdir = -(ray_org * rdir);
+#else
+ org_rdir = ray_org * rdir;
+#endif
+ }
+
+ Vec3vf<K> rdir;
+#if defined(__aarch64__)
+ Vec3vf<K> neg_org_rdir;
+#else
+ Vec3vf<K> org_rdir;
+#endif
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKStreamFast = TravRayKStream<K, false>;
+
+ /* Robust variant */
+ template<int K>
+ struct TravRayKStream<K, true>
+ {
+ __forceinline TravRayKStream() {}
+
+ __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar)
+ {
+ init(ray_org, ray_dir);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir)
+ {
+ rdir = vfloat<K>(1.0f)/(zero_fix(ray_dir));
+ org = ray_org;
+ }
+
+ Vec3vf<K> rdir;
+ Vec3vf<K> org;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKStreamRobust = TravRayKStream<K, true>;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx, int K>
+ __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const TravRayKStreamFast<K>& ray, size_t k, const NearFarPrecalculations& nf)
+ {
+ const vfloat<Nx> bminX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<Nx> bminY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<Nx> bminZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<Nx> bmaxX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<Nx> bmaxY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<Nx> bmaxZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+
+#if defined (__aarch64__)
+ const vfloat<Nx> rminX = madd(bminX, vfloat<Nx>(ray.rdir.x[k]), vfloat<Nx>(ray.neg_org_rdir.x[k]));
+ const vfloat<Nx> rminY = madd(bminY, vfloat<Nx>(ray.rdir.y[k]), vfloat<Nx>(ray.neg_org_rdir.y[k]));
+ const vfloat<Nx> rminZ = madd(bminZ, vfloat<Nx>(ray.rdir.z[k]), vfloat<Nx>(ray.neg_org_rdir.z[k]));
+ const vfloat<Nx> rmaxX = madd(bmaxX, vfloat<Nx>(ray.rdir.x[k]), vfloat<Nx>(ray.neg_org_rdir.x[k]));
+ const vfloat<Nx> rmaxY = madd(bmaxY, vfloat<Nx>(ray.rdir.y[k]), vfloat<Nx>(ray.neg_org_rdir.y[k]));
+ const vfloat<Nx> rmaxZ = madd(bmaxZ, vfloat<Nx>(ray.rdir.z[k]), vfloat<Nx>(ray.neg_org_rdir.z[k]));
+#else
+ const vfloat<Nx> rminX = msub(bminX, vfloat<Nx>(ray.rdir.x[k]), vfloat<Nx>(ray.org_rdir.x[k]));
+ const vfloat<Nx> rminY = msub(bminY, vfloat<Nx>(ray.rdir.y[k]), vfloat<Nx>(ray.org_rdir.y[k]));
+ const vfloat<Nx> rminZ = msub(bminZ, vfloat<Nx>(ray.rdir.z[k]), vfloat<Nx>(ray.org_rdir.z[k]));
+ const vfloat<Nx> rmaxX = msub(bmaxX, vfloat<Nx>(ray.rdir.x[k]), vfloat<Nx>(ray.org_rdir.x[k]));
+ const vfloat<Nx> rmaxY = msub(bmaxY, vfloat<Nx>(ray.rdir.y[k]), vfloat<Nx>(ray.org_rdir.y[k]));
+ const vfloat<Nx> rmaxZ = msub(bmaxZ, vfloat<Nx>(ray.rdir.z[k]), vfloat<Nx>(ray.org_rdir.z[k]));
+#endif
+ const vfloat<Nx> rmin = maxi(rminX, rminY, rminZ, vfloat<Nx>(ray.tnear[k]));
+ const vfloat<Nx> rmax = mini(rmaxX, rmaxY, rmaxZ, vfloat<Nx>(ray.tfar[k]));
+
+ const vbool<Nx> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit) & (((size_t)1 << N)-1);
+ }
+
+ template<int N, int K>
+ __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i,
+ const TravRayKStreamFast<K>& ray, const NearFarPrecalculations& nf)
+ {
+ char* ptr = (char*)&node->lower_x + i*sizeof(float);
+ const vfloat<K> bminX = *(const float*)(ptr + nf.nearX);
+ const vfloat<K> bminY = *(const float*)(ptr + nf.nearY);
+ const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ);
+ const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX);
+ const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY);
+ const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ);
+
+#if defined (__aarch64__)
+ const vfloat<K> rminX = madd(bminX, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> rminY = madd(bminY, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> rminZ = madd(bminZ, ray.rdir.z, ray.neg_org_rdir.z);
+ const vfloat<K> rmaxX = madd(bmaxX, ray.rdir.x, ray.neg_org_rdir.x);
+ const vfloat<K> rmaxY = madd(bmaxY, ray.rdir.y, ray.neg_org_rdir.y);
+ const vfloat<K> rmaxZ = madd(bmaxZ, ray.rdir.z, ray.neg_org_rdir.z);
+#else
+ const vfloat<K> rminX = msub(bminX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> rminY = msub(bminY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> rminZ = msub(bminZ, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> rmaxX = msub(bmaxX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> rmaxY = msub(bmaxY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> rmaxZ = msub(bmaxZ, ray.rdir.z, ray.org_rdir.z);
+#endif
+
+ const vfloat<K> rmin = maxi(rminX, rminY, rminZ, ray.tnear);
+ const vfloat<K> rmax = mini(rmaxX, rmaxY, rmaxZ, ray.tfar);
+
+ const vbool<K> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int Nx, int K>
+ __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const TravRayKStreamRobust<K>& ray, size_t k, const NearFarPrecalculations& nf)
+ {
+ const vfloat<Nx> bminX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<Nx> bminY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<Nx> bminZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<Nx> bmaxX = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<Nx> bmaxY = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<Nx> bmaxZ = vfloat<Nx>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+
+ const vfloat<Nx> rminX = (bminX - vfloat<Nx>(ray.org.x[k])) * vfloat<Nx>(ray.rdir.x[k]);
+ const vfloat<Nx> rminY = (bminY - vfloat<Nx>(ray.org.y[k])) * vfloat<Nx>(ray.rdir.y[k]);
+ const vfloat<Nx> rminZ = (bminZ - vfloat<Nx>(ray.org.z[k])) * vfloat<Nx>(ray.rdir.z[k]);
+ const vfloat<Nx> rmaxX = (bmaxX - vfloat<Nx>(ray.org.x[k])) * vfloat<Nx>(ray.rdir.x[k]);
+ const vfloat<Nx> rmaxY = (bmaxY - vfloat<Nx>(ray.org.y[k])) * vfloat<Nx>(ray.rdir.y[k]);
+ const vfloat<Nx> rmaxZ = (bmaxZ - vfloat<Nx>(ray.org.z[k])) * vfloat<Nx>(ray.rdir.z[k]);
+ const float round_up = 1.0f+3.0f*float(ulp); // FIXME: use per instruction rounding for AVX512
+ const vfloat<Nx> rmin = max(rminX, rminY, rminZ, vfloat<Nx>(ray.tnear[k]));
+ const vfloat<Nx> rmax = round_up *min(rmaxX, rmaxY, rmaxZ, vfloat<Nx>(ray.tfar[k]));
+
+ const vbool<Nx> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit) & (((size_t)1 << N)-1);
+ }
+
+ template<int N, int K>
+ __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i,
+ const TravRayKStreamRobust<K>& ray, const NearFarPrecalculations& nf)
+ {
+ char *ptr = (char*)&node->lower_x + i*sizeof(float);
+ const vfloat<K> bminX = *(const float*)(ptr + nf.nearX);
+ const vfloat<K> bminY = *(const float*)(ptr + nf.nearY);
+ const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ);
+ const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX);
+ const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY);
+ const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ);
+
+ const vfloat<K> rminX = (bminX - ray.org.x) * ray.rdir.x;
+ const vfloat<K> rminY = (bminY - ray.org.y) * ray.rdir.y;
+ const vfloat<K> rminZ = (bminZ - ray.org.z) * ray.rdir.z;
+ const vfloat<K> rmaxX = (bmaxX - ray.org.x) * ray.rdir.x;
+ const vfloat<K> rmaxY = (bmaxY - ray.org.y) * ray.rdir.y;
+ const vfloat<K> rmaxZ = (bmaxZ - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const vfloat<K> rmin = max(rminX, rminY, rminZ, vfloat<K>(ray.tnear));
+ const vfloat<K> rmax = round_up * min(rmaxX, rmaxY, rmaxZ, vfloat<K>(ray.tfar));
+
+ const vbool<K> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/accel.h b/thirdparty/embree-aarch64/kernels/common/accel.h
new file mode 100644
index 0000000000..c038d3cf21
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/accel.h
@@ -0,0 +1,556 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "ray.h"
+#include "point_query.h"
+#include "context.h"
+
+namespace embree
+{
+ class Scene;
+
+ /*! Base class for the acceleration structure data. */
+ class AccelData : public RefCount
+ {
+ ALIGNED_CLASS_(16);
+ public:
+ enum Type { TY_UNKNOWN = 0, TY_ACCELN = 1, TY_ACCEL_INSTANCE = 2, TY_BVH4 = 3, TY_BVH8 = 4 };
+
+ public:
+ AccelData (const Type type)
+ : bounds(empty), type(type) {}
+
+ /*! notifies the acceleration structure about the deletion of some geometry */
+ virtual void deleteGeometry(size_t geomID) {};
+
+ /*! clears the acceleration structure data */
+ virtual void clear() = 0;
+
+ /*! returns normal bounds */
+ __forceinline BBox3fa getBounds() const {
+ return bounds.bounds();
+ }
+
+ /*! returns bounds for some time */
+ __forceinline BBox3fa getBounds(float t) const {
+ return bounds.interpolate(t);
+ }
+
+ /*! returns linear bounds */
+ __forceinline LBBox3fa getLinearBounds() const {
+ return bounds;
+ }
+
+ /*! checks if acceleration structure is empty */
+ __forceinline bool isEmpty() const {
+ return bounds.bounds0.lower.x == float(pos_inf);
+ }
+
+ public:
+ LBBox3fa bounds; // linear bounds
+ Type type;
+ };
+
+ /*! Base class for all intersectable and buildable acceleration structures. */
+ class Accel : public AccelData
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ struct Intersectors;
+
+ /*! Type of collide function */
+ typedef void (*CollideFunc)(void* bvh0, void* bvh1, RTCCollideFunc callback, void* userPtr);
+
+ /*! Type of point query function */
+ typedef bool(*PointQueryFunc)(Intersectors* This, /*!< this pointer to accel */
+ PointQuery* query, /*!< point query for lookup */
+ PointQueryContext* context); /*!< point query context */
+
+ /*! Type of intersect function pointer for single rays. */
+ typedef void (*IntersectFunc)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit& ray, /*!< ray to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 4. */
+ typedef void (*IntersectFunc4)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit4& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 8. */
+ typedef void (*IntersectFunc8)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit8& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 16. */
+ typedef void (*IntersectFunc16)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit16& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size N. */
+ typedef void (*IntersectFuncN)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayHitN** ray, /*!< ray stream to intersect */
+ const size_t N, /*!< number of rays in stream */
+ IntersectContext* context /*!< layout flags */);
+
+
+ /*! Type of occlusion function pointer for single rays. */
+ typedef void (*OccludedFunc) (Intersectors* This, /*!< this pointer to accel */
+ RTCRay& ray, /*!< ray to test occlusion */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 4. */
+ typedef void (*OccludedFunc4) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay4& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 8. */
+ typedef void (*OccludedFunc8) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay8& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 16. */
+ typedef void (*OccludedFunc16) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay16& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size N. */
+ typedef void (*OccludedFuncN)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayN** ray, /*!< ray stream to test occlusion */
+ const size_t N, /*!< number of rays in stream */
+ IntersectContext* context /*!< layout flags */);
+ typedef void (*ErrorFunc) ();
+
+ struct Collider
+ {
+ Collider (ErrorFunc error = nullptr)
+ : collide((CollideFunc)error), name(nullptr) {}
+
+ Collider (CollideFunc collide, const char* name)
+ : collide(collide), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ CollideFunc collide;
+ const char* name;
+ };
+
+ struct Intersector1
+ {
+ Intersector1 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc)error), occluded((OccludedFunc)error), name(nullptr) {}
+
+ Intersector1 (IntersectFunc intersect, OccludedFunc occluded, const char* name)
+ : intersect(intersect), occluded(occluded), pointQuery(nullptr), name(name) {}
+
+ Intersector1 (IntersectFunc intersect, OccludedFunc occluded, PointQueryFunc pointQuery, const char* name)
+ : intersect(intersect), occluded(occluded), pointQuery(pointQuery), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc intersect;
+ OccludedFunc occluded;
+ PointQueryFunc pointQuery;
+ const char* name;
+ };
+
+ struct Intersector4
+ {
+ Intersector4 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc4)error), occluded((OccludedFunc4)error), name(nullptr) {}
+
+ Intersector4 (IntersectFunc4 intersect, OccludedFunc4 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc4 intersect;
+ OccludedFunc4 occluded;
+ const char* name;
+ };
+
+ struct Intersector8
+ {
+ Intersector8 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc8)error), occluded((OccludedFunc8)error), name(nullptr) {}
+
+ Intersector8 (IntersectFunc8 intersect, OccludedFunc8 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc8 intersect;
+ OccludedFunc8 occluded;
+ const char* name;
+ };
+
+ struct Intersector16
+ {
+ Intersector16 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc16)error), occluded((OccludedFunc16)error), name(nullptr) {}
+
+ Intersector16 (IntersectFunc16 intersect, OccludedFunc16 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc16 intersect;
+ OccludedFunc16 occluded;
+ const char* name;
+ };
+
+ struct IntersectorN
+ {
+ IntersectorN (ErrorFunc error = nullptr)
+ : intersect((IntersectFuncN)error), occluded((OccludedFuncN)error), name(nullptr) {}
+
+ IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFuncN intersect;
+ OccludedFuncN occluded;
+ const char* name;
+ };
+
+ struct Intersectors
+ {
+ Intersectors()
+ : ptr(nullptr), leafIntersector(nullptr), collider(nullptr), intersector1(nullptr), intersector4(nullptr), intersector8(nullptr), intersector16(nullptr), intersectorN(nullptr) {}
+
+ Intersectors (ErrorFunc error)
+ : ptr(nullptr), leafIntersector(nullptr), collider(error), intersector1(error), intersector4(error), intersector8(error), intersector16(error), intersectorN(error) {}
+
+ void print(size_t ident)
+ {
+ if (collider.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "collider = " << collider.name << std::endl;
+ }
+ if (intersector1.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector1 = " << intersector1.name << std::endl;
+ }
+ if (intersector4.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector4 = " << intersector4.name << std::endl;
+ }
+ if (intersector8.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector8 = " << intersector8.name << std::endl;
+ }
+ if (intersector16.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector16 = " << intersector16.name << std::endl;
+ }
+ if (intersectorN.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersectorN = " << intersectorN.name << std::endl;
+ }
+ }
+
+ void select(bool filter)
+ {
+ if (intersector4_filter) {
+ if (filter) intersector4 = intersector4_filter;
+ else intersector4 = intersector4_nofilter;
+ }
+ if (intersector8_filter) {
+ if (filter) intersector8 = intersector8_filter;
+ else intersector8 = intersector8_nofilter;
+ }
+ if (intersector16_filter) {
+ if (filter) intersector16 = intersector16_filter;
+ else intersector16 = intersector16_nofilter;
+ }
+ if (intersectorN_filter) {
+ if (filter) intersectorN = intersectorN_filter;
+ else intersectorN = intersectorN_nofilter;
+ }
+ }
+
+ __forceinline bool pointQuery (PointQuery* query, PointQueryContext* context) {
+ assert(intersector1.pointQuery);
+ return intersector1.pointQuery(this,query,context);
+ }
+
+ /*! collides two scenes */
+ __forceinline void collide (Accel* scene0, Accel* scene1, RTCCollideFunc callback, void* userPtr) {
+ assert(collider.collide);
+ collider.collide(scene0->intersectors.ptr,scene1->intersectors.ptr,callback,userPtr);
+ }
+
+ /*! Intersects a single ray with the scene. */
+ __forceinline void intersect (RTCRayHit& ray, IntersectContext* context) {
+ assert(intersector1.intersect);
+ intersector1.intersect(this,ray,context);
+ }
+
+ /*! Intersects a packet of 4 rays with the scene. */
+ __forceinline void intersect4 (const void* valid, RTCRayHit4& ray, IntersectContext* context) {
+ assert(intersector4.intersect);
+ intersector4.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a packet of 8 rays with the scene. */
+ __forceinline void intersect8 (const void* valid, RTCRayHit8& ray, IntersectContext* context) {
+ assert(intersector8.intersect);
+ intersector8.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a packet of 16 rays with the scene. */
+ __forceinline void intersect16 (const void* valid, RTCRayHit16& ray, IntersectContext* context) {
+ assert(intersector16.intersect);
+ intersector16.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a stream of N rays in SOA layout with the scene. */
+ __forceinline void intersectN (RTCRayHitN** rayN, const size_t N, IntersectContext* context)
+ {
+ assert(intersectorN.intersect);
+ intersectorN.intersect(this,rayN,N,context);
+ }
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ __forceinline void intersect(const vbool4& valid, RayHitK<4>& ray, IntersectContext* context) {
+ const vint<4> mask = valid.mask32();
+ intersect4(&mask,(RTCRayHit4&)ray,context);
+ }
+#endif
+#if defined(__AVX__)
+ __forceinline void intersect(const vbool8& valid, RayHitK<8>& ray, IntersectContext* context) {
+ const vint<8> mask = valid.mask32();
+ intersect8(&mask,(RTCRayHit8&)ray,context);
+ }
+#endif
+#if defined(__AVX512F__)
+ __forceinline void intersect(const vbool16& valid, RayHitK<16>& ray, IntersectContext* context) {
+ const vint<16> mask = valid.mask32();
+ intersect16(&mask,(RTCRayHit16&)ray,context);
+ }
+#endif
+
+ template<int K>
+ __forceinline void intersectN (RayHitK<K>** rayN, const size_t N, IntersectContext* context)
+ {
+ intersectN((RTCRayHitN**)rayN,N,context);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void occluded (RTCRay& ray, IntersectContext* context) {
+ assert(intersector1.occluded);
+ intersector1.occluded(this,ray,context);
+ }
+
+ /*! Tests if a packet of 4 rays is occluded by the scene. */
+ __forceinline void occluded4 (const void* valid, RTCRay4& ray, IntersectContext* context) {
+ assert(intersector4.occluded);
+ intersector4.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a packet of 8 rays is occluded by the scene. */
+ __forceinline void occluded8 (const void* valid, RTCRay8& ray, IntersectContext* context) {
+ assert(intersector8.occluded);
+ intersector8.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a packet of 16 rays is occluded by the scene. */
+ __forceinline void occluded16 (const void* valid, RTCRay16& ray, IntersectContext* context) {
+ assert(intersector16.occluded);
+ intersector16.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a stream of N rays in SOA layout is occluded by the scene. */
+ __forceinline void occludedN (RTCRayN** rayN, const size_t N, IntersectContext* context)
+ {
+ assert(intersectorN.occluded);
+ intersectorN.occluded(this,rayN,N,context);
+ }
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+ __forceinline void occluded(const vbool4& valid, RayK<4>& ray, IntersectContext* context) {
+ const vint<4> mask = valid.mask32();
+ occluded4(&mask,(RTCRay4&)ray,context);
+ }
+#endif
+#if defined(__AVX__)
+ __forceinline void occluded(const vbool8& valid, RayK<8>& ray, IntersectContext* context) {
+ const vint<8> mask = valid.mask32();
+ occluded8(&mask,(RTCRay8&)ray,context);
+ }
+#endif
+#if defined(__AVX512F__)
+ __forceinline void occluded(const vbool16& valid, RayK<16>& ray, IntersectContext* context) {
+ const vint<16> mask = valid.mask32();
+ occluded16(&mask,(RTCRay16&)ray,context);
+ }
+#endif
+
+ template<int K>
+ __forceinline void occludedN (RayK<K>** rayN, const size_t N, IntersectContext* context)
+ {
+ occludedN((RTCRayN**)rayN,N,context);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void intersect(RTCRay& ray, IntersectContext* context) {
+ occluded(ray, context);
+ }
+
+ /*! Tests if a packet of K rays is occluded by the scene. */
+ template<int K>
+ __forceinline void intersect(const vbool<K>& valid, RayK<K>& ray, IntersectContext* context) {
+ occluded(valid, ray, context);
+ }
+
+ /*! Tests if a packet of N rays in SOA layout is occluded by the scene. */
+ template<int K>
+ __forceinline void intersectN(RayK<K>** rayN, const size_t N, IntersectContext* context) {
+ occludedN(rayN, N, context);
+ }
+
+ public:
+ AccelData* ptr;
+ void* leafIntersector;
+ Collider collider;
+ Intersector1 intersector1;
+ Intersector4 intersector4;
+ Intersector4 intersector4_filter;
+ Intersector4 intersector4_nofilter;
+ Intersector8 intersector8;
+ Intersector8 intersector8_filter;
+ Intersector8 intersector8_nofilter;
+ Intersector16 intersector16;
+ Intersector16 intersector16_filter;
+ Intersector16 intersector16_nofilter;
+ IntersectorN intersectorN;
+ IntersectorN intersectorN_filter;
+ IntersectorN intersectorN_nofilter;
+ };
+
+ public:
+
+ /*! Construction */
+ Accel (const AccelData::Type type)
+ : AccelData(type) {}
+
+ /*! Construction */
+ Accel (const AccelData::Type type, const Intersectors& intersectors)
+ : AccelData(type), intersectors(intersectors) {}
+
+ /*! Virtual destructor */
+ virtual ~Accel() {}
+
+ /*! makes the acceleration structure immutable */
+ virtual void immutable () {}
+
+ /*! build acceleration structure */
+ virtual void build () = 0;
+
+ public:
+ Intersectors intersectors;
+ };
+
+#define DEFINE_COLLIDER(symbol,collider) \
+ Accel::Collider symbol() { \
+ return Accel::Collider((Accel::CollideFunc)collider::collide, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR1(symbol,intersector) \
+ Accel::Intersector1 symbol() { \
+ return Accel::Intersector1((Accel::IntersectFunc )intersector::intersect, \
+ (Accel::OccludedFunc )intersector::occluded, \
+ (Accel::PointQueryFunc)intersector::pointQuery,\
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR4(symbol,intersector) \
+ Accel::Intersector4 symbol() { \
+ return Accel::Intersector4((Accel::IntersectFunc4)intersector::intersect, \
+ (Accel::OccludedFunc4)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR8(symbol,intersector) \
+ Accel::Intersector8 symbol() { \
+ return Accel::Intersector8((Accel::IntersectFunc8)intersector::intersect, \
+ (Accel::OccludedFunc8)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR16(symbol,intersector) \
+ Accel::Intersector16 symbol() { \
+ return Accel::Intersector16((Accel::IntersectFunc16)intersector::intersect, \
+ (Accel::OccludedFunc16)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTORN(symbol,intersector) \
+ Accel::IntersectorN symbol() { \
+ return Accel::IntersectorN((Accel::IntersectFuncN)intersector::intersect, \
+ (Accel::OccludedFuncN)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+ /* ray stream filter interface */
+ typedef void (*intersectStreamAOS_func)(Scene* scene, RTCRayHit* _rayN, const size_t N, const size_t stride, IntersectContext* context);
+ typedef void (*intersectStreamAOP_func)(Scene* scene, RTCRayHit** _rayN, const size_t N, IntersectContext* context);
+ typedef void (*intersectStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context);
+ typedef void (*intersectStreamSOP_func)(Scene* scene, const RTCRayHitNp* rayN, const size_t N, IntersectContext* context);
+
+ typedef void (*occludedStreamAOS_func)(Scene* scene, RTCRay* _rayN, const size_t N, const size_t stride, IntersectContext* context);
+ typedef void (*occludedStreamAOP_func)(Scene* scene, RTCRay** _rayN, const size_t N, IntersectContext* context);
+ typedef void (*occludedStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context);
+ typedef void (*occludedStreamSOP_func)(Scene* scene, const RTCRayNp* rayN, const size_t N, IntersectContext* context);
+
+ struct RayStreamFilterFuncs
+ {
+ RayStreamFilterFuncs()
+ : intersectAOS(nullptr), intersectAOP(nullptr), intersectSOA(nullptr), intersectSOP(nullptr),
+ occludedAOS(nullptr), occludedAOP(nullptr), occludedSOA(nullptr), occludedSOP(nullptr) {}
+
+ RayStreamFilterFuncs(void (*ptr) ())
+ : intersectAOS((intersectStreamAOS_func) ptr), intersectAOP((intersectStreamAOP_func) ptr), intersectSOA((intersectStreamSOA_func) ptr), intersectSOP((intersectStreamSOP_func) ptr),
+ occludedAOS((occludedStreamAOS_func) ptr), occludedAOP((occludedStreamAOP_func) ptr), occludedSOA((occludedStreamSOA_func) ptr), occludedSOP((occludedStreamSOP_func) ptr) {}
+
+ RayStreamFilterFuncs(intersectStreamAOS_func intersectAOS, intersectStreamAOP_func intersectAOP, intersectStreamSOA_func intersectSOA, intersectStreamSOP_func intersectSOP,
+ occludedStreamAOS_func occludedAOS, occludedStreamAOP_func occludedAOP, occludedStreamSOA_func occludedSOA, occludedStreamSOP_func occludedSOP)
+ : intersectAOS(intersectAOS), intersectAOP(intersectAOP), intersectSOA(intersectSOA), intersectSOP(intersectSOP),
+ occludedAOS(occludedAOS), occludedAOP(occludedAOP), occludedSOA(occludedSOA), occludedSOP(occludedSOP) {}
+
+ public:
+ intersectStreamAOS_func intersectAOS;
+ intersectStreamAOP_func intersectAOP;
+ intersectStreamSOA_func intersectSOA;
+ intersectStreamSOP_func intersectSOP;
+
+ occludedStreamAOS_func occludedAOS;
+ occludedStreamAOP_func occludedAOP;
+ occludedStreamSOA_func occludedSOA;
+ occludedStreamSOP_func occludedSOP;
+ };
+
+ typedef RayStreamFilterFuncs (*RayStreamFilterFuncsType)();
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/accelinstance.h b/thirdparty/embree-aarch64/kernels/common/accelinstance.h
new file mode 100644
index 0000000000..d74b96df3f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/accelinstance.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accel.h"
+#include "builder.h"
+
+namespace embree
+{
+ class AccelInstance : public Accel
+ {
+ public:
+ AccelInstance (AccelData* accel, Builder* builder, Intersectors& intersectors)
+ : Accel(AccelData::TY_ACCEL_INSTANCE,intersectors), accel(accel), builder(builder) {}
+
+ void immutable () {
+ builder.reset(nullptr);
+ }
+
+ public:
+ void build () {
+ if (builder) builder->build();
+ bounds = accel->bounds;
+ }
+
+ void deleteGeometry(size_t geomID) {
+ if (accel ) accel->deleteGeometry(geomID);
+ if (builder) builder->deleteGeometry(geomID);
+ }
+
+ void clear() {
+ if (accel) accel->clear();
+ if (builder) builder->clear();
+ }
+
+ private:
+ std::unique_ptr<AccelData> accel;
+ std::unique_ptr<Builder> builder;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/acceln.cpp b/thirdparty/embree-aarch64/kernels/common/acceln.cpp
new file mode 100644
index 0000000000..aadb4a64ef
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/acceln.cpp
@@ -0,0 +1,232 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "acceln.h"
+#include "ray.h"
+#include "../../include/embree3/rtcore_ray.h"
+#include "../../common/algorithms/parallel_for.h"
+
+namespace embree
+{
+ AccelN::AccelN()
+ : Accel(AccelData::TY_ACCELN), accels() {}
+
+ AccelN::~AccelN()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ delete accels[i];
+ }
+
+ void AccelN::accels_add(Accel* accel)
+ {
+ assert(accel);
+ accels.push_back(accel);
+ }
+
+ void AccelN::accels_init()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ delete accels[i];
+
+ accels.clear();
+ }
+
+ bool AccelN::pointQuery (Accel::Intersectors* This_in, PointQuery* query, PointQueryContext* context)
+ {
+ bool changed = false;
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ changed |= This->accels[i]->intersectors.pointQuery(query,context);
+ return changed;
+ }
+
+ void AccelN::intersect (Accel::Intersectors* This_in, RTCRayHit& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect(ray,context);
+ }
+
+ void AccelN::intersect4 (const void* valid, Accel::Intersectors* This_in, RTCRayHit4& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect4(valid,ray,context);
+ }
+
+ void AccelN::intersect8 (const void* valid, Accel::Intersectors* This_in, RTCRayHit8& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect8(valid,ray,context);
+ }
+
+ void AccelN::intersect16 (const void* valid, Accel::Intersectors* This_in, RTCRayHit16& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect16(valid,ray,context);
+ }
+
+ void AccelN::intersectN (Accel::Intersectors* This_in, RTCRayHitN** ray, const size_t N, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersectN(ray,N,context);
+ }
+
+ void AccelN::occluded (Accel::Intersectors* This_in, RTCRay& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded(ray,context);
+ if (ray.tfar < 0.0f) break;
+ }
+ }
+
+ void AccelN::occluded4 (const void* valid, Accel::Intersectors* This_in, RTCRay4& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded4(valid,ray,context);
+#if defined(__SSE2__) || defined(__ARM_NEON)
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ if (unlikely(none(valid0 & hit0))) break;
+#endif
+ }
+ }
+
+ void AccelN::occluded8 (const void* valid, Accel::Intersectors* This_in, RTCRay8& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded8(valid,ray,context);
+#if defined(__SSE2__) || defined(__ARM_NEON) // FIXME: use higher ISA
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ vbool4 valid1 = asBool(((vint4*)valid)[1]);
+ vbool4 hit1 = ((vfloat4*)ray.tfar)[1] >= vfloat4(zero);
+ if (unlikely((none((valid0 & hit0) | (valid1 & hit1))))) break;
+#endif
+ }
+ }
+
+ void AccelN::occluded16 (const void* valid, Accel::Intersectors* This_in, RTCRay16& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded16(valid,ray,context);
+#if defined(__SSE2__) || defined(__ARM_NEON) // FIXME: use higher ISA
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ vbool4 valid1 = asBool(((vint4*)valid)[1]);
+ vbool4 hit1 = ((vfloat4*)ray.tfar)[1] >= vfloat4(zero);
+ vbool4 valid2 = asBool(((vint4*)valid)[2]);
+ vbool4 hit2 = ((vfloat4*)ray.tfar)[2] >= vfloat4(zero);
+ vbool4 valid3 = asBool(((vint4*)valid)[3]);
+ vbool4 hit3 = ((vfloat4*)ray.tfar)[3] >= vfloat4(zero);
+ if (unlikely((none((valid0 & hit0) | (valid1 & hit1) | (valid2 & hit2) | (valid3 & hit3))))) break;
+#endif
+ }
+ }
+
+ void AccelN::occludedN (Accel::Intersectors* This_in, RTCRayN** ray, const size_t N, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ size_t M = N;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.occludedN(ray,M,context);
+ }
+
+ void AccelN::accels_print(size_t ident)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ {
+ for (size_t j=0; j<ident; j++) std::cout << " ";
+ std::cout << "accels[" << i << "]" << std::endl;
+ accels[i]->intersectors.print(ident+2);
+ }
+ }
+
+ void AccelN::accels_immutable()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->immutable();
+ }
+
+ void AccelN::accels_build ()
+ {
+ /* reduce memory consumption */
+ accels.shrink_to_fit();
+
+ /* build all acceleration structures in parallel */
+ parallel_for (accels.size(), [&] (size_t i) {
+ accels[i]->build();
+ });
+
+ /* create list of non-empty acceleration structures */
+ bool valid1 = true;
+ bool valid4 = true;
+ bool valid8 = true;
+ bool valid16 = true;
+ for (size_t i=0; i<accels.size(); i++) {
+ valid1 &= (bool) accels[i]->intersectors.intersector1;
+ valid4 &= (bool) accels[i]->intersectors.intersector4;
+ valid8 &= (bool) accels[i]->intersectors.intersector8;
+ valid16 &= (bool) accels[i]->intersectors.intersector16;
+ }
+
+ if (accels.size() == 1) {
+ type = accels[0]->type; // FIXME: should just assign entire Accel
+ bounds = accels[0]->bounds;
+ intersectors = accels[0]->intersectors;
+ }
+ else
+ {
+ type = AccelData::TY_ACCELN;
+ intersectors.ptr = this;
+ intersectors.intersector1 = Intersector1(&intersect,&occluded,&pointQuery,valid1 ? "AccelN::intersector1": nullptr);
+ intersectors.intersector4 = Intersector4(&intersect4,&occluded4,valid4 ? "AccelN::intersector4" : nullptr);
+ intersectors.intersector8 = Intersector8(&intersect8,&occluded8,valid8 ? "AccelN::intersector8" : nullptr);
+ intersectors.intersector16 = Intersector16(&intersect16,&occluded16,valid16 ? "AccelN::intersector16": nullptr);
+ intersectors.intersectorN = IntersectorN(&intersectN,&occludedN,"AccelN::intersectorN");
+
+ /*! calculate bounds */
+ bounds = empty;
+ for (size_t i=0; i<accels.size(); i++)
+ bounds.extend(accels[i]->bounds);
+ }
+ }
+
+ void AccelN::accels_select(bool filter)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->intersectors.select(filter);
+ }
+
+ void AccelN::accels_deleteGeometry(size_t geomID)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->deleteGeometry(geomID);
+ }
+
+ void AccelN::accels_clear()
+ {
+ for (size_t i=0; i<accels.size(); i++) {
+ accels[i]->clear();
+ }
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/common/acceln.h b/thirdparty/embree-aarch64/kernels/common/acceln.h
new file mode 100644
index 0000000000..2edd98f647
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/acceln.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accel.h"
+
+namespace embree
+{
+ /*! merges N acceleration structures together, by processing them in order */
+ class AccelN : public Accel
+ {
+ public:
+ AccelN ();
+ ~AccelN();
+
+ public:
+ void accels_add(Accel* accel);
+ void accels_init();
+
+ public:
+ static bool pointQuery (Accel::Intersectors* This, PointQuery* query, PointQueryContext* context);
+
+ public:
+ static void intersect (Accel::Intersectors* This, RTCRayHit& ray, IntersectContext* context);
+ static void intersect4 (const void* valid, Accel::Intersectors* This, RTCRayHit4& ray, IntersectContext* context);
+ static void intersect8 (const void* valid, Accel::Intersectors* This, RTCRayHit8& ray, IntersectContext* context);
+ static void intersect16 (const void* valid, Accel::Intersectors* This, RTCRayHit16& ray, IntersectContext* context);
+ static void intersectN (Accel::Intersectors* This, RTCRayHitN** ray, const size_t N, IntersectContext* context);
+
+ public:
+ static void occluded (Accel::Intersectors* This, RTCRay& ray, IntersectContext* context);
+ static void occluded4 (const void* valid, Accel::Intersectors* This, RTCRay4& ray, IntersectContext* context);
+ static void occluded8 (const void* valid, Accel::Intersectors* This, RTCRay8& ray, IntersectContext* context);
+ static void occluded16 (const void* valid, Accel::Intersectors* This, RTCRay16& ray, IntersectContext* context);
+ static void occludedN (Accel::Intersectors* This, RTCRayN** ray, const size_t N, IntersectContext* context);
+
+ public:
+ void accels_print(size_t ident);
+ void accels_immutable();
+ void accels_build ();
+ void accels_select(bool filter);
+ void accels_deleteGeometry(size_t geomID);
+ void accels_clear ();
+
+ public:
+ std::vector<Accel*> accels;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/accelset.cpp b/thirdparty/embree-aarch64/kernels/common/accelset.cpp
new file mode 100644
index 0000000000..79be1c4301
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/accelset.cpp
@@ -0,0 +1,17 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "accelset.h"
+#include "scene.h"
+
+namespace embree
+{
+ AccelSet::AccelSet (Device* device, Geometry::GType gtype, size_t numItems, size_t numTimeSteps)
+ : Geometry(device,gtype,(unsigned int)numItems,(unsigned int)numTimeSteps), boundsFunc(nullptr) {}
+
+ AccelSet::IntersectorN::IntersectorN (ErrorFunc error)
+ : intersect((IntersectFuncN)error), occluded((OccludedFuncN)error), name(nullptr) {}
+
+ AccelSet::IntersectorN::IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/accelset.h b/thirdparty/embree-aarch64/kernels/common/accelset.h
new file mode 100644
index 0000000000..3774b2accb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/accelset.h
@@ -0,0 +1,248 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "builder.h"
+#include "geometry.h"
+#include "ray.h"
+#include "hit.h"
+
+namespace embree
+{
+ struct IntersectFunctionNArguments;
+ struct OccludedFunctionNArguments;
+
+ typedef void (*ReportIntersectionFunc) (IntersectFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args);
+ typedef void (*ReportOcclusionFunc) (OccludedFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args);
+
+ struct IntersectFunctionNArguments : public RTCIntersectFunctionNArguments
+ {
+ IntersectContext* internal_context;
+ Geometry* geometry;
+ ReportIntersectionFunc report;
+ };
+
+ struct OccludedFunctionNArguments : public RTCOccludedFunctionNArguments
+ {
+ IntersectContext* internal_context;
+ Geometry* geometry;
+ ReportOcclusionFunc report;
+ };
+
+ /*! Base class for set of acceleration structures. */
+ class AccelSet : public Geometry
+ {
+ public:
+ typedef RTCIntersectFunctionN IntersectFuncN;
+ typedef RTCOccludedFunctionN OccludedFuncN;
+ typedef void (*ErrorFunc) ();
+
+ struct IntersectorN
+ {
+ IntersectorN (ErrorFunc error = nullptr) ;
+ IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name);
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFuncN intersect;
+ OccludedFuncN occluded;
+ const char* name;
+ };
+
+ public:
+
+ /*! construction */
+ AccelSet (Device* device, Geometry::GType gtype, size_t items, size_t numTimeSteps);
+
+ /*! makes the acceleration structure immutable */
+ virtual void immutable () {}
+
+ /*! build accel */
+ virtual void build () = 0;
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid_non_empty(bounds(i,itime))) return false;
+
+ return true;
+ }
+
+ /*! Calculates the bounds of an item */
+ __forceinline BBox3fa bounds(size_t i, size_t itime = 0) const
+ {
+ BBox3fa box;
+ assert(i < size());
+ RTCBoundsFunctionArguments args;
+ args.geometryUserPtr = userPtr;
+ args.primID = (unsigned int)i;
+ args.timeStep = (unsigned int)itime;
+ args.bounds_o = (RTCBounds*)&box;
+ boundsFunc(&args);
+ return box;
+ }
+
+ /*! calculates the linear bounds of the i'th item at the itime'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const
+ {
+ BBox3fa box[2];
+ assert(i < size());
+ RTCBoundsFunctionArguments args;
+ args.geometryUserPtr = userPtr;
+ args.primID = (unsigned int)i;
+ args.timeStep = (unsigned int)(itime+0);
+ args.bounds_o = (RTCBounds*)&box[0];
+ boundsFunc(&args);
+ args.timeStep = (unsigned int)(itime+1);
+ args.bounds_o = (RTCBounds*)&box[1];
+ boundsFunc(&args);
+ return LBBox3fa(box[0],box[1]);
+ }
+
+ /*! calculates the build bounds of the i'th item, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const BBox3fa b = bounds(i);
+ if (bbox) *bbox = b;
+ return isvalid_non_empty(b);
+ }
+
+ /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const LBBox3fa bounds = linearBounds(i,itime);
+ bbox = bounds.bounds0; // use bounding box of first timestep to build BVH
+ return isvalid_non_empty(bounds);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return numPrimitives;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return numPrimitives != otherVersion;
+ }
+
+ public:
+
+ /*! Intersects a single ray with the scene. */
+ __forceinline void intersect (RayHit& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportIntersectionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.intersect);
+
+ int mask = -1;
+ IntersectFunctionNArguments args;
+ args.valid = &mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.rayhit = (RTCRayHitN*)&ray;
+ args.N = 1;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.intersect(&args);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void occluded (Ray& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportOcclusionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.occluded);
+
+ int mask = -1;
+ OccludedFunctionNArguments args;
+ args.valid = &mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.N = 1;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.occluded(&args);
+ }
+
+ /*! Intersects a packet of K rays with the scene. */
+ template<int K>
+ __forceinline void intersect (const vbool<K>& valid, RayHitK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportIntersectionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.intersect);
+
+ vint<K> mask = valid.mask32();
+ IntersectFunctionNArguments args;
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.rayhit = (RTCRayHitN*)&ray;
+ args.N = K;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.intersect(&args);
+ }
+
+ /*! Tests if a packet of K rays is occluded by the scene. */
+ template<int K>
+ __forceinline void occluded (const vbool<K>& valid, RayK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportOcclusionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.occluded);
+
+ vint<K> mask = valid.mask32();
+ OccludedFunctionNArguments args;
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.N = K;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.occluded(&args);
+ }
+
+ public:
+ RTCBoundsFunction boundsFunc;
+ IntersectorN intersectorN;
+ };
+
+#define DEFINE_SET_INTERSECTORN(symbol,intersector) \
+ AccelSet::IntersectorN symbol() { \
+ return AccelSet::IntersectorN(intersector::intersect, \
+ intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/alloc.cpp b/thirdparty/embree-aarch64/kernels/common/alloc.cpp
new file mode 100644
index 0000000000..6fa406f03a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/alloc.cpp
@@ -0,0 +1,82 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "alloc.h"
+#include "../../common/sys/thread.h"
+#if defined(__aarch64__) && defined(BUILD_IOS)
+#include "../../common/sys/barrier.h"
+#endif
+
+namespace embree
+{
+ __thread FastAllocator::ThreadLocal2* FastAllocator::thread_local_allocator2 = nullptr;
+ SpinLock FastAllocator::s_thread_local_allocators_lock;
+ std::vector<std::unique_ptr<FastAllocator::ThreadLocal2>> FastAllocator::s_thread_local_allocators;
+
+ struct fast_allocator_regression_test : public RegressionTest
+ {
+ BarrierSys barrier;
+ std::atomic<size_t> numFailed;
+ std::unique_ptr<FastAllocator> alloc;
+
+ fast_allocator_regression_test()
+ : RegressionTest("fast_allocator_regression_test"), numFailed(0)
+ {
+ registerRegressionTest(this);
+ }
+
+ static void thread_alloc(fast_allocator_regression_test* This)
+ {
+ FastAllocator::CachedAllocator threadalloc = This->alloc->getCachedAllocator();
+
+ size_t* ptrs[1000];
+ for (size_t j=0; j<1000; j++)
+ {
+ This->barrier.wait();
+ for (size_t i=0; i<1000; i++) {
+ ptrs[i] = (size_t*) threadalloc.malloc0(sizeof(size_t)+(i%32));
+ *ptrs[i] = size_t(threadalloc.talloc0) + i;
+ }
+ for (size_t i=0; i<1000; i++) {
+ if (*ptrs[i] != size_t(threadalloc.talloc0) + i)
+ This->numFailed++;
+ }
+ This->barrier.wait();
+ }
+ }
+
+ bool run ()
+ {
+ alloc = make_unique(new FastAllocator(nullptr,false));
+ numFailed.store(0);
+
+ size_t numThreads = getNumberOfLogicalThreads();
+ barrier.init(numThreads+1);
+
+ /* create threads */
+ std::vector<thread_t> threads;
+ for (size_t i=0; i<numThreads; i++)
+ threads.push_back(createThread((thread_func)thread_alloc,this));
+
+ /* run test */
+ for (size_t i=0; i<1000; i++)
+ {
+ alloc->reset();
+ barrier.wait();
+ barrier.wait();
+ }
+
+ /* destroy threads */
+ for (size_t i=0; i<numThreads; i++)
+ join(threads[i]);
+
+ alloc = nullptr;
+
+ return numFailed == 0;
+ }
+ };
+
+ fast_allocator_regression_test fast_allocator_regression;
+}
+
+
diff --git a/thirdparty/embree-aarch64/kernels/common/alloc.h b/thirdparty/embree-aarch64/kernels/common/alloc.h
new file mode 100644
index 0000000000..488fa707ef
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/alloc.h
@@ -0,0 +1,1006 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "primref.h"
+
+#if defined(__aarch64__) && defined(BUILD_IOS)
+#include <mutex>
+#endif
+
+namespace embree
+{
+ class FastAllocator
+ {
+ /*! maximum supported alignment */
+ static const size_t maxAlignment = 64;
+
+ /*! maximum allocation size */
+
+ /* default settings */
+ //static const size_t defaultBlockSize = 4096;
+#define maxAllocationSize size_t(2*1024*1024-maxAlignment)
+
+ static const size_t MAX_THREAD_USED_BLOCK_SLOTS = 8;
+
+ public:
+
+ struct ThreadLocal2;
+ enum AllocationType { ALIGNED_MALLOC, EMBREE_OS_MALLOC, SHARED, ANY_TYPE };
+
+ /*! Per thread structure holding the current memory block. */
+ struct __aligned(64) ThreadLocal
+ {
+ ALIGNED_CLASS_(64);
+ public:
+
+ /*! Constructor for usage with ThreadLocalData */
+ __forceinline ThreadLocal (ThreadLocal2* parent)
+ : parent(parent), ptr(nullptr), cur(0), end(0), allocBlockSize(0), bytesUsed(0), bytesWasted(0) {}
+
+ /*! initialize allocator */
+ void init(FastAllocator* alloc)
+ {
+ ptr = nullptr;
+ cur = end = 0;
+ bytesUsed = 0;
+ bytesWasted = 0;
+ allocBlockSize = 0;
+ if (alloc) allocBlockSize = alloc->defaultBlockSize;
+ }
+
+ /* Allocate aligned memory from the threads memory block. */
+ __forceinline void* malloc(FastAllocator* alloc, size_t bytes, size_t align = 16)
+ {
+ /* bind the thread local allocator to the proper FastAllocator*/
+ parent->bind(alloc);
+
+ assert(align <= maxAlignment);
+ bytesUsed += bytes;
+
+ /* try to allocate in local block */
+ size_t ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* if allocation is too large allocate with parent allocator */
+ if (4*bytes > allocBlockSize) {
+ return alloc->malloc(bytes,maxAlignment,false);
+ }
+
+ /* get new partial block if allocation failed */
+ size_t blockSize = allocBlockSize;
+ ptr = (char*) alloc->malloc(blockSize,maxAlignment,true);
+ bytesWasted += end-cur;
+ cur = 0; end = blockSize;
+
+ /* retry allocation */
+ ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* get new full block if allocation failed */
+ blockSize = allocBlockSize;
+ ptr = (char*) alloc->malloc(blockSize,maxAlignment,false);
+ bytesWasted += end-cur;
+ cur = 0; end = blockSize;
+
+ /* retry allocation */
+ ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* should never happen as large allocations get handled specially above */
+ assert(false);
+ return nullptr;
+ }
+
+
+ /*! returns amount of used bytes */
+ __forceinline size_t getUsedBytes() const { return bytesUsed; }
+
+ /*! returns amount of free bytes */
+ __forceinline size_t getFreeBytes() const { return end-cur; }
+
+ /*! returns amount of wasted bytes */
+ __forceinline size_t getWastedBytes() const { return bytesWasted; }
+
+ private:
+ ThreadLocal2* parent;
+ char* ptr; //!< pointer to memory block
+ size_t cur; //!< current location of the allocator
+ size_t end; //!< end of the memory block
+ size_t allocBlockSize; //!< block size for allocations
+ size_t bytesUsed; //!< number of total bytes allocated
+ size_t bytesWasted; //!< number of bytes wasted
+ };
+
+ /*! Two thread local structures. */
+ struct __aligned(64) ThreadLocal2
+ {
+ ALIGNED_CLASS_(64);
+ public:
+
+ __forceinline ThreadLocal2()
+ : alloc(nullptr), alloc0(this), alloc1(this) {}
+
+ /*! bind to fast allocator */
+ __forceinline void bind(FastAllocator* alloc_i)
+ {
+ assert(alloc_i);
+ if (alloc.load() == alloc_i) return;
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(mutex);
+#else
+ Lock<SpinLock> lock(mutex);
+#endif
+ //if (alloc.load() == alloc_i) return; // not required as only one thread calls bind
+ if (alloc.load()) {
+ alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes();
+ alloc.load()->bytesFree += alloc0.getFreeBytes() + alloc1.getFreeBytes();
+ alloc.load()->bytesWasted += alloc0.getWastedBytes() + alloc1.getWastedBytes();
+ }
+ alloc0.init(alloc_i);
+ alloc1.init(alloc_i);
+ alloc.store(alloc_i);
+ alloc_i->join(this);
+ }
+
+ /*! unbind to fast allocator */
+ void unbind(FastAllocator* alloc_i)
+ {
+ assert(alloc_i);
+ if (alloc.load() != alloc_i) return;
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(mutex);
+#else
+ Lock<SpinLock> lock(mutex);
+#endif
+ if (alloc.load() != alloc_i) return; // required as a different thread calls unbind
+ alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes();
+ alloc.load()->bytesFree += alloc0.getFreeBytes() + alloc1.getFreeBytes();
+ alloc.load()->bytesWasted += alloc0.getWastedBytes() + alloc1.getWastedBytes();
+ alloc0.init(nullptr);
+ alloc1.init(nullptr);
+ alloc.store(nullptr);
+ }
+
+ public:
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::mutex mutex;
+#else
+ SpinLock mutex; //!< required as unbind is called from other threads
+#endif
+ std::atomic<FastAllocator*> alloc; //!< parent allocator
+ ThreadLocal alloc0;
+ ThreadLocal alloc1;
+ };
+
+ FastAllocator (Device* device, bool osAllocation)
+ : device(device), slotMask(0), usedBlocks(nullptr), freeBlocks(nullptr), use_single_mode(false), defaultBlockSize(PAGE_SIZE), estimatedSize(0),
+ growSize(PAGE_SIZE), maxGrowSize(maxAllocationSize), log2_grow_size_scale(0), bytesUsed(0), bytesFree(0), bytesWasted(0), atype(osAllocation ? EMBREE_OS_MALLOC : ALIGNED_MALLOC),
+ primrefarray(device,0)
+ {
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ assert(!slotMutex[i].isLocked());
+ }
+ }
+
+ ~FastAllocator () {
+ clear();
+ }
+
+ /*! returns the device attached to this allocator */
+ Device* getDevice() {
+ return device;
+ }
+
+ void share(mvector<PrimRef>& primrefarray_i) {
+ primrefarray = std::move(primrefarray_i);
+ }
+
+ void unshare(mvector<PrimRef>& primrefarray_o)
+ {
+ reset(); // this removes blocks that are allocated inside the shared primref array
+ primrefarray_o = std::move(primrefarray);
+ }
+
+ /*! returns first fast thread local allocator */
+ __forceinline ThreadLocal* _threadLocal() {
+ return &threadLocal2()->alloc0;
+ }
+
+ void setOSallocation(bool flag)
+ {
+ atype = flag ? EMBREE_OS_MALLOC : ALIGNED_MALLOC;
+ }
+
+ private:
+
+ /*! returns both fast thread local allocators */
+ __forceinline ThreadLocal2* threadLocal2()
+ {
+ ThreadLocal2* alloc = thread_local_allocator2;
+ if (alloc == nullptr) {
+ thread_local_allocator2 = alloc = new ThreadLocal2;
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(s_thread_local_allocators_lock);
+#else
+ Lock<SpinLock> lock(s_thread_local_allocators_lock);
+#endif
+ s_thread_local_allocators.push_back(make_unique(alloc));
+ }
+ return alloc;
+ }
+
+ public:
+
+ __forceinline void join(ThreadLocal2* alloc)
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(s_thread_local_allocators_lock);
+#else
+ Lock<SpinLock> lock(thread_local_allocators_lock);
+#endif
+ thread_local_allocators.push_back(alloc);
+ }
+
+ public:
+
+ struct CachedAllocator
+ {
+ __forceinline CachedAllocator(void* ptr)
+ : alloc(nullptr), talloc0(nullptr), talloc1(nullptr)
+ {
+ assert(ptr == nullptr);
+ }
+
+ __forceinline CachedAllocator(FastAllocator* alloc, ThreadLocal2* talloc)
+ : alloc(alloc), talloc0(&talloc->alloc0), talloc1(alloc->use_single_mode ? &talloc->alloc0 : &talloc->alloc1) {}
+
+ __forceinline operator bool () const {
+ return alloc != nullptr;
+ }
+
+ __forceinline void* operator() (size_t bytes, size_t align = 16) const {
+ return talloc0->malloc(alloc,bytes,align);
+ }
+
+ __forceinline void* malloc0 (size_t bytes, size_t align = 16) const {
+ return talloc0->malloc(alloc,bytes,align);
+ }
+
+ __forceinline void* malloc1 (size_t bytes, size_t align = 16) const {
+ return talloc1->malloc(alloc,bytes,align);
+ }
+
+ public:
+ FastAllocator* alloc;
+ ThreadLocal* talloc0;
+ ThreadLocal* talloc1;
+ };
+
+ __forceinline CachedAllocator getCachedAllocator() {
+ return CachedAllocator(this,threadLocal2());
+ }
+
+ /*! Builder interface to create thread local allocator */
+ struct Create
+ {
+ public:
+ __forceinline Create (FastAllocator* allocator) : allocator(allocator) {}
+ __forceinline CachedAllocator operator() () const { return allocator->getCachedAllocator(); }
+
+ private:
+ FastAllocator* allocator;
+ };
+
+ void internal_fix_used_blocks()
+ {
+ /* move thread local blocks to global block list */
+ for (size_t i = 0; i < MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ while (threadBlocks[i].load() != nullptr) {
+ Block* nextUsedBlock = threadBlocks[i].load()->next;
+ threadBlocks[i].load()->next = usedBlocks.load();
+ usedBlocks = threadBlocks[i].load();
+ threadBlocks[i] = nextUsedBlock;
+ }
+ threadBlocks[i] = nullptr;
+ }
+ }
+
+ static const size_t threadLocalAllocOverhead = 20; //! 20 means 5% parallel allocation overhead through unfilled thread local blocks
+#if defined(__AVX512ER__) // KNL
+ static const size_t mainAllocOverheadStatic = 15; //! 15 means 7.5% allocation overhead through unfilled main alloc blocks
+#else
+ static const size_t mainAllocOverheadStatic = 20; //! 20 means 5% allocation overhead through unfilled main alloc blocks
+#endif
+ static const size_t mainAllocOverheadDynamic = 8; //! 20 means 12.5% allocation overhead through unfilled main alloc blocks
+
+ /* calculates a single threaded threshold for the builders such
+ * that for small scenes the overhead of partly allocated blocks
+ * per thread is low */
+ size_t fixSingleThreadThreshold(size_t branchingFactor, size_t defaultThreshold, size_t numPrimitives, size_t bytesEstimated)
+ {
+ if (numPrimitives == 0 || bytesEstimated == 0)
+ return defaultThreshold;
+
+ /* calculate block size in bytes to fulfill threadLocalAllocOverhead constraint */
+ const size_t single_mode_factor = use_single_mode ? 1 : 2;
+ const size_t threadCount = TaskScheduler::threadCount();
+ const size_t singleThreadBytes = single_mode_factor*threadLocalAllocOverhead*defaultBlockSize;
+
+ /* if we do not have to limit number of threads use optimal thresdhold */
+ if ( (bytesEstimated+(singleThreadBytes-1))/singleThreadBytes >= threadCount)
+ return defaultThreshold;
+
+ /* otherwise limit number of threads by calculating proper single thread threshold */
+ else {
+ double bytesPerPrimitive = double(bytesEstimated)/double(numPrimitives);
+ return size_t(ceil(branchingFactor*singleThreadBytes/bytesPerPrimitive));
+ }
+ }
+
+ __forceinline size_t alignSize(size_t i) {
+ return (i+127)/128*128;
+ }
+
+ /*! initializes the grow size */
+ __forceinline void initGrowSizeAndNumSlots(size_t bytesEstimated, bool fast)
+ {
+ /* we do not need single thread local allocator mode */
+ use_single_mode = false;
+
+ /* calculate growSize such that at most mainAllocationOverhead gets wasted when a block stays unused */
+ size_t mainAllocOverhead = fast ? mainAllocOverheadDynamic : mainAllocOverheadStatic;
+ size_t blockSize = alignSize(bytesEstimated/mainAllocOverhead);
+ growSize = maxGrowSize = clamp(blockSize,size_t(1024),maxAllocationSize);
+
+ /* if we reached the maxAllocationSize for growSize, we can
+ * increase the number of allocation slots by still guaranteeing
+ * the mainAllocationOverhead */
+ slotMask = 0x0;
+
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 2 && bytesEstimated > 2*mainAllocOverhead*growSize) slotMask = 0x1;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 4 && bytesEstimated > 4*mainAllocOverhead*growSize) slotMask = 0x3;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 8 && bytesEstimated > 8*mainAllocOverhead*growSize) slotMask = 0x7;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 8 && bytesEstimated > 16*mainAllocOverhead*growSize) { growSize *= 2; } /* if the overhead is tiny, double the growSize */
+
+ /* set the thread local alloc block size */
+ size_t defaultBlockSizeSwitch = PAGE_SIZE+maxAlignment;
+
+ /* for sufficiently large scene we can increase the defaultBlockSize over the defaultBlockSizeSwitch size */
+#if 0 // we do not do this as a block size of 4160 if for some reason best for KNL
+ const size_t threadCount = TaskScheduler::threadCount();
+ const size_t single_mode_factor = use_single_mode ? 1 : 2;
+ const size_t singleThreadBytes = single_mode_factor*threadLocalAllocOverhead*defaultBlockSizeSwitch;
+ if (bytesEstimated+(singleThreadBytes-1))/singleThreadBytes >= threadCount)
+ defaultBlockSize = min(max(defaultBlockSizeSwitch,bytesEstimated/(single_mode_factor*threadLocalAllocOverhead*threadCount)),growSize);
+
+ /* otherwise we grow the defaultBlockSize up to defaultBlockSizeSwitch */
+ else
+#endif
+ defaultBlockSize = clamp(blockSize,size_t(1024),defaultBlockSizeSwitch);
+
+ if (bytesEstimated == 0) {
+ maxGrowSize = maxAllocationSize; // special mode if builder cannot estimate tree size
+ defaultBlockSize = defaultBlockSizeSwitch;
+ }
+ log2_grow_size_scale = 0;
+
+ if (device->alloc_main_block_size != 0) growSize = device->alloc_main_block_size;
+ if (device->alloc_num_main_slots >= 1 ) slotMask = 0x0;
+ if (device->alloc_num_main_slots >= 2 ) slotMask = 0x1;
+ if (device->alloc_num_main_slots >= 4 ) slotMask = 0x3;
+ if (device->alloc_num_main_slots >= 8 ) slotMask = 0x7;
+ if (device->alloc_thread_block_size != 0) defaultBlockSize = device->alloc_thread_block_size;
+ if (device->alloc_single_thread_alloc != -1) use_single_mode = device->alloc_single_thread_alloc;
+ }
+
+ /*! initializes the allocator */
+ void init(size_t bytesAllocate, size_t bytesReserve, size_t bytesEstimate)
+ {
+ internal_fix_used_blocks();
+ /* distribute the allocation to multiple thread block slots */
+ slotMask = MAX_THREAD_USED_BLOCK_SLOTS-1; // FIXME: remove
+ if (usedBlocks.load() || freeBlocks.load()) { reset(); return; }
+ if (bytesReserve == 0) bytesReserve = bytesAllocate;
+ freeBlocks = Block::create(device,bytesAllocate,bytesReserve,nullptr,atype);
+ estimatedSize = bytesEstimate;
+ initGrowSizeAndNumSlots(bytesEstimate,true);
+ }
+
+ /*! initializes the allocator */
+ void init_estimate(size_t bytesEstimate)
+ {
+ internal_fix_used_blocks();
+ if (usedBlocks.load() || freeBlocks.load()) { reset(); return; }
+ /* single allocator mode ? */
+ estimatedSize = bytesEstimate;
+ //initGrowSizeAndNumSlots(bytesEstimate,false);
+ initGrowSizeAndNumSlots(bytesEstimate,false);
+
+ }
+
+ /*! frees state not required after build */
+ __forceinline void cleanup()
+ {
+ internal_fix_used_blocks();
+
+ /* unbind all thread local allocators */
+ for (auto alloc : thread_local_allocators) alloc->unbind(this);
+ thread_local_allocators.clear();
+ }
+
+ /*! resets the allocator, memory blocks get reused */
+ void reset ()
+ {
+ internal_fix_used_blocks();
+
+ bytesUsed.store(0);
+ bytesFree.store(0);
+ bytesWasted.store(0);
+
+ /* reset all used blocks and move them to begin of free block list */
+ while (usedBlocks.load() != nullptr) {
+ usedBlocks.load()->reset_block();
+ Block* nextUsedBlock = usedBlocks.load()->next;
+ usedBlocks.load()->next = freeBlocks.load();
+ freeBlocks = usedBlocks.load();
+ usedBlocks = nextUsedBlock;
+ }
+
+ /* remove all shared blocks as they are re-added during build */
+ freeBlocks.store(Block::remove_shared_blocks(freeBlocks.load()));
+
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ }
+
+ /* unbind all thread local allocators */
+ for (auto alloc : thread_local_allocators) alloc->unbind(this);
+ thread_local_allocators.clear();
+ }
+
+ /*! frees all allocated memory */
+ __forceinline void clear()
+ {
+ cleanup();
+ bytesUsed.store(0);
+ bytesFree.store(0);
+ bytesWasted.store(0);
+ if (usedBlocks.load() != nullptr) usedBlocks.load()->clear_list(device); usedBlocks = nullptr;
+ if (freeBlocks.load() != nullptr) freeBlocks.load()->clear_list(device); freeBlocks = nullptr;
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++) {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ }
+ primrefarray.clear();
+ }
+
+ __forceinline size_t incGrowSizeScale()
+ {
+ size_t scale = log2_grow_size_scale.fetch_add(1)+1;
+ return size_t(1) << min(size_t(16),scale);
+ }
+
+ /*! thread safe allocation of memory */
+ void* malloc(size_t& bytes, size_t align, bool partial)
+ {
+ assert(align <= maxAlignment);
+
+ while (true)
+ {
+ /* allocate using current block */
+ size_t threadID = TaskScheduler::threadID();
+ size_t slot = threadID & slotMask;
+ Block* myUsedBlocks = threadUsedBlocks[slot];
+ if (myUsedBlocks) {
+ void* ptr = myUsedBlocks->malloc(device,bytes,align,partial);
+ if (ptr) return ptr;
+ }
+
+ /* throw error if allocation is too large */
+ if (bytes > maxAllocationSize)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"allocation is too large");
+
+ /* parallel block creation in case of no freeBlocks, avoids single global mutex */
+ if (likely(freeBlocks.load() == nullptr))
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(slotMutex[slot]);
+#else
+ Lock<SpinLock> lock(slotMutex[slot]);
+#endif
+ if (myUsedBlocks == threadUsedBlocks[slot]) {
+ const size_t alignedBytes = (bytes+(align-1)) & ~(align-1);
+ const size_t allocSize = max(min(growSize,maxGrowSize),alignedBytes);
+ assert(allocSize >= bytes);
+ threadBlocks[slot] = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,threadBlocks[slot],atype); // FIXME: a large allocation might throw away a block here!
+ // FIXME: a direct allocation should allocate inside the block here, and not in the next loop! a different thread could do some allocation and make the large allocation fail.
+ }
+ continue;
+ }
+
+ /* if this fails allocate new block */
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(mutex);
+#else
+ Lock<SpinLock> lock(mutex);
+#endif
+ if (myUsedBlocks == threadUsedBlocks[slot])
+ {
+ if (freeBlocks.load() != nullptr) {
+ Block* nextFreeBlock = freeBlocks.load()->next;
+ freeBlocks.load()->next = usedBlocks;
+ __memory_barrier();
+ usedBlocks = freeBlocks.load();
+ threadUsedBlocks[slot] = freeBlocks.load();
+ freeBlocks = nextFreeBlock;
+ } else {
+ const size_t allocSize = min(growSize*incGrowSizeScale(),maxGrowSize);
+ usedBlocks = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,usedBlocks,atype); // FIXME: a large allocation should get delivered directly, like above!
+ }
+ }
+ }
+ }
+ }
+
+ /*! add new block */
+ void addBlock(void* ptr, ssize_t bytes)
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(mutex);
+#else
+ Lock<SpinLock> lock(mutex);
+#endif
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ void* aptr = (void*) ((((size_t)ptr)+maxAlignment-1) & ~(maxAlignment-1));
+ size_t ofs = (size_t) aptr - (size_t) ptr;
+ bytes -= ofs;
+ if (bytes < 4096) return; // ignore empty or very small blocks
+ freeBlocks = new (aptr) Block(SHARED,bytes-sizeof_Header,bytes-sizeof_Header,freeBlocks,ofs);
+ }
+
+ /* special allocation only used from morton builder only a single time for each build */
+ void* specialAlloc(size_t bytes)
+ {
+ assert(freeBlocks.load() != nullptr && freeBlocks.load()->getBlockAllocatedBytes() >= bytes);
+ return freeBlocks.load()->ptr();
+ }
+
+ struct Statistics
+ {
+ Statistics ()
+ : bytesUsed(0), bytesFree(0), bytesWasted(0) {}
+
+ Statistics (size_t bytesUsed, size_t bytesFree, size_t bytesWasted)
+ : bytesUsed(bytesUsed), bytesFree(bytesFree), bytesWasted(bytesWasted) {}
+
+ Statistics (FastAllocator* alloc, AllocationType atype, bool huge_pages = false)
+ : bytesUsed(0), bytesFree(0), bytesWasted(0)
+ {
+ Block* usedBlocks = alloc->usedBlocks.load();
+ Block* freeBlocks = alloc->freeBlocks.load();
+ if (usedBlocks) bytesUsed += usedBlocks->getUsedBytes(atype,huge_pages);
+ if (freeBlocks) bytesFree += freeBlocks->getAllocatedBytes(atype,huge_pages);
+ if (usedBlocks) bytesFree += usedBlocks->getFreeBytes(atype,huge_pages);
+ if (freeBlocks) bytesWasted += freeBlocks->getWastedBytes(atype,huge_pages);
+ if (usedBlocks) bytesWasted += usedBlocks->getWastedBytes(atype,huge_pages);
+ }
+
+ std::string str(size_t numPrimitives)
+ {
+ std::stringstream str;
+ str.setf(std::ios::fixed, std::ios::floatfield);
+ str << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << "free = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesFree << " MB, "
+ << "wasted = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesWasted << " MB, "
+ << "total = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesAllocatedTotal() << " MB, "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesAllocatedTotal())/double(numPrimitives);
+ return str.str();
+ }
+
+ friend Statistics operator+ ( const Statistics& a, const Statistics& b)
+ {
+ return Statistics(a.bytesUsed+b.bytesUsed,
+ a.bytesFree+b.bytesFree,
+ a.bytesWasted+b.bytesWasted);
+ }
+
+ size_t bytesAllocatedTotal() const {
+ return bytesUsed + bytesFree + bytesWasted;
+ }
+
+ public:
+ size_t bytesUsed;
+ size_t bytesFree;
+ size_t bytesWasted;
+ };
+
+ Statistics getStatistics(AllocationType atype, bool huge_pages = false) {
+ return Statistics(this,atype,huge_pages);
+ }
+
+ size_t getUsedBytes() {
+ return bytesUsed;
+ }
+
+ size_t getWastedBytes() {
+ return bytesWasted;
+ }
+
+ struct AllStatistics
+ {
+ AllStatistics (FastAllocator* alloc)
+
+ : bytesUsed(alloc->bytesUsed),
+ bytesFree(alloc->bytesFree),
+ bytesWasted(alloc->bytesWasted),
+ stat_all(alloc,ANY_TYPE),
+ stat_malloc(alloc,ALIGNED_MALLOC),
+ stat_4K(alloc,EMBREE_OS_MALLOC,false),
+ stat_2M(alloc,EMBREE_OS_MALLOC,true),
+ stat_shared(alloc,SHARED) {}
+
+ AllStatistics (size_t bytesUsed,
+ size_t bytesFree,
+ size_t bytesWasted,
+ Statistics stat_all,
+ Statistics stat_malloc,
+ Statistics stat_4K,
+ Statistics stat_2M,
+ Statistics stat_shared)
+
+ : bytesUsed(bytesUsed),
+ bytesFree(bytesFree),
+ bytesWasted(bytesWasted),
+ stat_all(stat_all),
+ stat_malloc(stat_malloc),
+ stat_4K(stat_4K),
+ stat_2M(stat_2M),
+ stat_shared(stat_shared) {}
+
+ friend AllStatistics operator+ (const AllStatistics& a, const AllStatistics& b)
+ {
+ return AllStatistics(a.bytesUsed+b.bytesUsed,
+ a.bytesFree+b.bytesFree,
+ a.bytesWasted+b.bytesWasted,
+ a.stat_all + b.stat_all,
+ a.stat_malloc + b.stat_malloc,
+ a.stat_4K + b.stat_4K,
+ a.stat_2M + b.stat_2M,
+ a.stat_shared + b.stat_shared);
+ }
+
+ void print(size_t numPrimitives)
+ {
+ std::stringstream str0;
+ str0.setf(std::ios::fixed, std::ios::floatfield);
+ str0 << " alloc : "
+ << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << " "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesUsed)/double(numPrimitives);
+ std::cout << str0.str() << std::endl;
+
+ std::stringstream str1;
+ str1.setf(std::ios::fixed, std::ios::floatfield);
+ str1 << " alloc : "
+ << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << "free = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesFree << " MB, "
+ << "wasted = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesWasted << " MB, "
+ << "total = " << std::setw(7) << std::setprecision(3) << 1E-6f*(bytesUsed+bytesFree+bytesWasted) << " MB, "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesUsed+bytesFree+bytesWasted)/double(numPrimitives);
+ std::cout << str1.str() << std::endl;
+
+ std::cout << " total : " << stat_all.str(numPrimitives) << std::endl;
+ std::cout << " 4K : " << stat_4K.str(numPrimitives) << std::endl;
+ std::cout << " 2M : " << stat_2M.str(numPrimitives) << std::endl;
+ std::cout << " malloc: " << stat_malloc.str(numPrimitives) << std::endl;
+ std::cout << " shared: " << stat_shared.str(numPrimitives) << std::endl;
+ }
+
+ private:
+ size_t bytesUsed;
+ size_t bytesFree;
+ size_t bytesWasted;
+ Statistics stat_all;
+ Statistics stat_malloc;
+ Statistics stat_4K;
+ Statistics stat_2M;
+ Statistics stat_shared;
+ };
+
+ void print_blocks()
+ {
+ std::cout << " estimatedSize = " << estimatedSize << ", slotMask = " << slotMask << ", use_single_mode = " << use_single_mode << ", maxGrowSize = " << maxGrowSize << ", defaultBlockSize = " << defaultBlockSize << std::endl;
+
+ std::cout << " used blocks = ";
+ if (usedBlocks.load() != nullptr) usedBlocks.load()->print_list();
+ std::cout << "[END]" << std::endl;
+
+ std::cout << " free blocks = ";
+ if (freeBlocks.load() != nullptr) freeBlocks.load()->print_list();
+ std::cout << "[END]" << std::endl;
+ }
+
+ private:
+
+ struct Block
+ {
+ static Block* create(MemoryMonitorInterface* device, size_t bytesAllocate, size_t bytesReserve, Block* next, AllocationType atype)
+ {
+ /* We avoid using os_malloc for small blocks as this could
+ * cause a risk of fragmenting the virtual address space and
+ * reach the limit of vm.max_map_count = 65k under Linux. */
+ if (atype == EMBREE_OS_MALLOC && bytesAllocate < maxAllocationSize)
+ atype = ALIGNED_MALLOC;
+
+ /* we need to additionally allocate some header */
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ bytesAllocate = sizeof_Header+bytesAllocate;
+ bytesReserve = sizeof_Header+bytesReserve;
+
+ /* consume full 4k pages with using os_malloc */
+ if (atype == EMBREE_OS_MALLOC) {
+ bytesAllocate = ((bytesAllocate+PAGE_SIZE-1) & ~(PAGE_SIZE-1));
+ bytesReserve = ((bytesReserve +PAGE_SIZE-1) & ~(PAGE_SIZE-1));
+ }
+
+ /* either use alignedMalloc or os_malloc */
+ void *ptr = nullptr;
+ if (atype == ALIGNED_MALLOC)
+ {
+ /* special handling for default block size */
+ if (bytesAllocate == (2*PAGE_SIZE_2M))
+ {
+ const size_t alignment = maxAlignment;
+ if (device) device->memoryMonitor(bytesAllocate+alignment,false);
+ ptr = alignedMalloc(bytesAllocate,alignment);
+
+ /* give hint to transparently convert these pages to 2MB pages */
+ const size_t ptr_aligned_begin = ((size_t)ptr) & ~size_t(PAGE_SIZE_2M-1);
+ os_advise((void*)(ptr_aligned_begin + 0),PAGE_SIZE_2M); // may fail if no memory mapped before block
+ os_advise((void*)(ptr_aligned_begin + 1*PAGE_SIZE_2M),PAGE_SIZE_2M);
+ os_advise((void*)(ptr_aligned_begin + 2*PAGE_SIZE_2M),PAGE_SIZE_2M); // may fail if no memory mapped after block
+
+ return new (ptr) Block(ALIGNED_MALLOC,bytesAllocate-sizeof_Header,bytesAllocate-sizeof_Header,next,alignment);
+ }
+ else
+ {
+ const size_t alignment = maxAlignment;
+ if (device) device->memoryMonitor(bytesAllocate+alignment,false);
+ ptr = alignedMalloc(bytesAllocate,alignment);
+ return new (ptr) Block(ALIGNED_MALLOC,bytesAllocate-sizeof_Header,bytesAllocate-sizeof_Header,next,alignment);
+ }
+ }
+ else if (atype == EMBREE_OS_MALLOC)
+ {
+ if (device) device->memoryMonitor(bytesAllocate,false);
+ bool huge_pages; ptr = os_malloc(bytesReserve,huge_pages);
+ return new (ptr) Block(EMBREE_OS_MALLOC,bytesAllocate-sizeof_Header,bytesReserve-sizeof_Header,next,0,huge_pages);
+ }
+ else
+ assert(false);
+
+ return NULL;
+ }
+
+ Block (AllocationType atype, size_t bytesAllocate, size_t bytesReserve, Block* next, size_t wasted, bool huge_pages = false)
+ : cur(0), allocEnd(bytesAllocate), reserveEnd(bytesReserve), next(next), wasted(wasted), atype(atype), huge_pages(huge_pages)
+ {
+ assert((((size_t)&data[0]) & (maxAlignment-1)) == 0);
+ }
+
+ static Block* remove_shared_blocks(Block* head)
+ {
+ Block** prev_next = &head;
+ for (Block* block = head; block; block = block->next) {
+ if (block->atype == SHARED) *prev_next = block->next;
+ else prev_next = &block->next;
+ }
+ return head;
+ }
+
+ void clear_list(MemoryMonitorInterface* device)
+ {
+ Block* block = this;
+ while (block) {
+ Block* next = block->next;
+ block->clear_block(device);
+ block = next;
+ }
+ }
+
+ void clear_block (MemoryMonitorInterface* device)
+ {
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ const ssize_t sizeof_Alloced = wasted+sizeof_Header+getBlockAllocatedBytes();
+
+ if (atype == ALIGNED_MALLOC) {
+ alignedFree(this);
+ if (device) device->memoryMonitor(-sizeof_Alloced,true);
+ }
+
+ else if (atype == EMBREE_OS_MALLOC) {
+ size_t sizeof_This = sizeof_Header+reserveEnd;
+ os_free(this,sizeof_This,huge_pages);
+ if (device) device->memoryMonitor(-sizeof_Alloced,true);
+ }
+
+ else /* if (atype == SHARED) */ {
+ }
+ }
+
+ void* malloc(MemoryMonitorInterface* device, size_t& bytes_in, size_t align, bool partial)
+ {
+ size_t bytes = bytes_in;
+ assert(align <= maxAlignment);
+ bytes = (bytes+(align-1)) & ~(align-1);
+ if (unlikely(cur+bytes > reserveEnd && !partial)) return nullptr;
+ const size_t i = cur.fetch_add(bytes);
+ if (unlikely(i+bytes > reserveEnd && !partial)) return nullptr;
+ if (unlikely(i > reserveEnd)) return nullptr;
+ bytes_in = bytes = min(bytes,reserveEnd-i);
+
+ if (i+bytes > allocEnd) {
+ if (device) device->memoryMonitor(i+bytes-max(i,allocEnd),true);
+ }
+ return &data[i];
+ }
+
+ void* ptr() {
+ return &data[cur];
+ }
+
+ void reset_block ()
+ {
+ allocEnd = max(allocEnd,(size_t)cur);
+ cur = 0;
+ }
+
+ size_t getBlockUsedBytes() const {
+ return min(size_t(cur),reserveEnd);
+ }
+
+ size_t getBlockFreeBytes() const {
+ return getBlockAllocatedBytes() - getBlockUsedBytes();
+ }
+
+ size_t getBlockAllocatedBytes() const {
+ return min(max(allocEnd,size_t(cur)),reserveEnd);
+ }
+
+ size_t getBlockWastedBytes() const {
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ return sizeof_Header + wasted;
+ }
+
+ size_t getBlockReservedBytes() const {
+ return reserveEnd;
+ }
+
+ bool hasType(AllocationType atype_i, bool huge_pages_i) const
+ {
+ if (atype_i == ANY_TYPE ) return true;
+ else if (atype == EMBREE_OS_MALLOC) return atype_i == atype && huge_pages_i == huge_pages;
+ else return atype_i == atype;
+ }
+
+ size_t getUsedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockUsedBytes();
+ }
+ return bytes;
+ }
+
+ size_t getFreeBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockFreeBytes();
+ }
+ return bytes;
+ }
+
+ size_t getWastedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockWastedBytes();
+ }
+ return bytes;
+ }
+
+ size_t getAllocatedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockAllocatedBytes();
+ }
+ return bytes;
+ }
+
+ void print_list ()
+ {
+ for (const Block* block = this; block; block = block->next)
+ block->print_block();
+ }
+
+ void print_block() const
+ {
+ if (atype == ALIGNED_MALLOC) std::cout << "A";
+ else if (atype == EMBREE_OS_MALLOC) std::cout << "O";
+ else if (atype == SHARED) std::cout << "S";
+ if (huge_pages) std::cout << "H";
+ size_t bytesUsed = getBlockUsedBytes();
+ size_t bytesFree = getBlockFreeBytes();
+ size_t bytesWasted = getBlockWastedBytes();
+ std::cout << "[" << bytesUsed << ", " << bytesFree << ", " << bytesWasted << "] ";
+ }
+
+ public:
+ std::atomic<size_t> cur; //!< current location of the allocator
+ std::atomic<size_t> allocEnd; //!< end of the allocated memory region
+ std::atomic<size_t> reserveEnd; //!< end of the reserved memory region
+ Block* next; //!< pointer to next block in list
+ size_t wasted; //!< amount of memory wasted through block alignment
+ AllocationType atype; //!< allocation mode of the block
+ bool huge_pages; //!< whether the block uses huge pages
+ char align[maxAlignment-5*sizeof(size_t)-sizeof(AllocationType)-sizeof(bool)]; //!< align data to maxAlignment
+ char data[1]; //!< here starts memory to use for allocations
+ };
+
+ private:
+ Device* device;
+ SpinLock mutex;
+ size_t slotMask;
+ std::atomic<Block*> threadUsedBlocks[MAX_THREAD_USED_BLOCK_SLOTS];
+ std::atomic<Block*> usedBlocks;
+ std::atomic<Block*> freeBlocks;
+
+ std::atomic<Block*> threadBlocks[MAX_THREAD_USED_BLOCK_SLOTS];
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::mutex slotMutex[MAX_THREAD_USED_BLOCK_SLOTS];
+#else
+ SpinLock slotMutex[MAX_THREAD_USED_BLOCK_SLOTS];
+#endif
+
+ bool use_single_mode;
+ size_t defaultBlockSize;
+ size_t estimatedSize;
+ size_t growSize;
+ size_t maxGrowSize;
+ std::atomic<size_t> log2_grow_size_scale; //!< log2 of scaling factor for grow size // FIXME: remove
+ std::atomic<size_t> bytesUsed;
+ std::atomic<size_t> bytesFree;
+ std::atomic<size_t> bytesWasted;
+ static __thread ThreadLocal2* thread_local_allocator2;
+ static SpinLock s_thread_local_allocators_lock;
+ static std::vector<std::unique_ptr<ThreadLocal2>> s_thread_local_allocators;
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::mutex thread_local_allocators_lock;
+#else
+ SpinLock thread_local_allocators_lock;
+#endif
+ std::vector<ThreadLocal2*> thread_local_allocators;
+ AllocationType atype;
+ mvector<PrimRef> primrefarray; //!< primrefarray used to allocate nodes
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/buffer.h b/thirdparty/embree-aarch64/kernels/common/buffer.h
new file mode 100644
index 0000000000..02d319c59d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/buffer.h
@@ -0,0 +1,263 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+
+namespace embree
+{
+ /*! Implements an API data buffer object. This class may or may not own the data. */
+ class Buffer : public RefCount
+ {
+ public:
+ /*! Buffer construction */
+ Buffer()
+ : device(nullptr), ptr(nullptr), numBytes(0), shared(false) {}
+
+ /*! Buffer construction */
+ Buffer(Device* device, size_t numBytes_in, void* ptr_in = nullptr)
+ : device(device), numBytes(numBytes_in)
+ {
+ device->refInc();
+
+ if (ptr_in)
+ {
+ shared = true;
+ ptr = (char*)ptr_in;
+ }
+ else
+ {
+ shared = false;
+ alloc();
+ }
+ }
+
+ /*! Buffer destruction */
+ ~Buffer() {
+ free();
+ device->refDec();
+ }
+
+ /*! this class is not copyable */
+ private:
+ Buffer(const Buffer& other) DELETED; // do not implement
+ Buffer& operator =(const Buffer& other) DELETED; // do not implement
+
+ public:
+ /* inits and allocates the buffer */
+ void create(Device* device_in, size_t numBytes_in)
+ {
+ init(device_in, numBytes_in);
+ alloc();
+ }
+
+ /* inits the buffer */
+ void init(Device* device_in, size_t numBytes_in)
+ {
+ free();
+ device = device_in;
+ ptr = nullptr;
+ numBytes = numBytes_in;
+ shared = false;
+ }
+
+ /*! sets shared buffer */
+ void set(Device* device_in, void* ptr_in, size_t numBytes_in)
+ {
+ free();
+ device = device_in;
+ ptr = (char*)ptr_in;
+ if (numBytes_in != (size_t)-1)
+ numBytes = numBytes_in;
+ shared = true;
+ }
+
+ /*! allocated buffer */
+ void alloc()
+ {
+ if (device)
+ device->memoryMonitor(this->bytes(), false);
+ size_t b = (this->bytes()+15) & ssize_t(-16);
+ ptr = (char*)alignedMalloc(b,16);
+ }
+
+ /*! frees the buffer */
+ void free()
+ {
+ if (shared) return;
+ alignedFree(ptr);
+ if (device)
+ device->memoryMonitor(-ssize_t(this->bytes()), true);
+ ptr = nullptr;
+ }
+
+ /*! gets buffer pointer */
+ void* data()
+ {
+ /* report error if buffer is not existing */
+ if (!device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer specified");
+
+ /* return buffer */
+ return ptr;
+ }
+
+ /*! returns pointer to first element */
+ __forceinline char* getPtr() const {
+ return ptr;
+ }
+
+ /*! returns the number of bytes of the buffer */
+ __forceinline size_t bytes() const {
+ return numBytes;
+ }
+
+ /*! returns true of the buffer is not empty */
+ __forceinline operator bool() const {
+ return ptr;
+ }
+
+ public:
+ Device* device; //!< device to report memory usage to
+ char* ptr; //!< pointer to buffer data
+ size_t numBytes; //!< number of bytes in the buffer
+ bool shared; //!< set if memory is shared with application
+ };
+
+ /*! An untyped contiguous range of a buffer. This class does not own the buffer content. */
+ class RawBufferView
+ {
+ public:
+ /*! Buffer construction */
+ RawBufferView()
+ : ptr_ofs(nullptr), stride(0), num(0), format(RTC_FORMAT_UNDEFINED), modCounter(1), modified(true), userData(0) {}
+
+ public:
+ /*! sets the buffer view */
+ void set(const Ref<Buffer>& buffer_in, size_t offset_in, size_t stride_in, size_t num_in, RTCFormat format_in)
+ {
+ if ((offset_in + stride_in * num_in) > (stride_in * buffer_in->numBytes))
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "buffer range out of bounds");
+
+ ptr_ofs = buffer_in->ptr + offset_in;
+ stride = stride_in;
+ num = num_in;
+ format = format_in;
+ modCounter++;
+ modified = true;
+ buffer = buffer_in;
+ }
+
+ /*! returns pointer to the first element */
+ __forceinline char* getPtr() const {
+ return ptr_ofs;
+ }
+
+ /*! returns pointer to the i'th element */
+ __forceinline char* getPtr(size_t i) const
+ {
+ assert(i<num);
+ return ptr_ofs + i*stride;
+ }
+
+ /*! returns the number of elements of the buffer */
+ __forceinline size_t size() const {
+ return num;
+ }
+
+ /*! returns the number of bytes of the buffer */
+ __forceinline size_t bytes() const {
+ return num*stride;
+ }
+
+ /*! returns the buffer stride */
+ __forceinline unsigned getStride() const
+ {
+ assert(stride <= unsigned(inf));
+ return unsigned(stride);
+ }
+
+ /*! return the buffer format */
+ __forceinline RTCFormat getFormat() const {
+ return format;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline void setModified() {
+ modCounter++;
+ modified = true;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline bool isModified(unsigned int otherModCounter) const {
+ return modCounter > otherModCounter;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline bool isLocalModified() const {
+ return modified;
+ }
+
+ /*! clear local modified flag */
+ __forceinline void clearLocalModified() {
+ modified = false;
+ }
+
+ /*! returns true of the buffer is not empty */
+ __forceinline operator bool() const {
+ return ptr_ofs;
+ }
+
+ /*! checks padding to 16 byte check, fails hard */
+ __forceinline void checkPadding16() const
+ {
+ if (ptr_ofs && num)
+ volatile int MAYBE_UNUSED w = *((int*)getPtr(size()-1)+3); // FIXME: is failing hard avoidable?
+ }
+
+ public:
+ char* ptr_ofs; //!< base pointer plus offset
+ size_t stride; //!< stride of the buffer in bytes
+ size_t num; //!< number of elements in the buffer
+ RTCFormat format; //!< format of the buffer
+ unsigned int modCounter; //!< version ID of this buffer
+ bool modified; //!< local modified data
+ int userData; //!< special data
+ Ref<Buffer> buffer; //!< reference to the parent buffer
+ };
+
+ /*! A typed contiguous range of a buffer. This class does not own the buffer content. */
+ template<typename T>
+ class BufferView : public RawBufferView
+ {
+ public:
+ typedef T value_type;
+
+ /*! access to the ith element of the buffer */
+ __forceinline T& operator [](size_t i) { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
+ __forceinline const T& operator [](size_t i) const { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
+ };
+
+ template<>
+ class BufferView<Vec3fa> : public RawBufferView
+ {
+ public:
+ typedef Vec3fa value_type;
+
+ /*! access to the ith element of the buffer */
+ __forceinline const Vec3fa operator [](size_t i) const
+ {
+ assert(i<num);
+ return Vec3fa(vfloat4::loadu((float*)(ptr_ofs + i*stride)));
+ }
+
+ /*! writes the i'th element */
+ __forceinline void store(size_t i, const Vec3fa& v)
+ {
+ assert(i<num);
+ vfloat4::storeu((float*)(ptr_ofs + i*stride), (vfloat4)v);
+ }
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/builder.h b/thirdparty/embree-aarch64/kernels/common/builder.h
new file mode 100644
index 0000000000..d2a1cfe3ce
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/builder.h
@@ -0,0 +1,60 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "accel.h"
+
+namespace embree
+{
+#define MODE_HIGH_QUALITY (1<<8)
+
+ /*! virtual interface for all hierarchy builders */
+ class Builder : public RefCount {
+ public:
+
+ static const size_t DEFAULT_SINGLE_THREAD_THRESHOLD = 1024;
+
+ /*! initiates the hierarchy builder */
+ virtual void build() = 0;
+
+ /*! notifies the builder about the deletion of some geometry */
+ virtual void deleteGeometry(size_t geomID) {};
+
+ /*! clears internal builder state */
+ virtual void clear() = 0;
+ };
+
+ /*! virtual interface for progress monitor class */
+ struct BuildProgressMonitor {
+ virtual void operator() (size_t dn) const = 0;
+ };
+
+ /*! build the progress monitor interface from a closure */
+ template<typename Closure>
+ struct ProgressMonitorClosure : BuildProgressMonitor
+ {
+ public:
+ ProgressMonitorClosure (const Closure& closure) : closure(closure) {}
+ void operator() (size_t dn) const { closure(dn); }
+ private:
+ const Closure closure;
+ };
+ template<typename Closure> __forceinline const ProgressMonitorClosure<Closure> BuildProgressMonitorFromClosure(const Closure& closure) {
+ return ProgressMonitorClosure<Closure>(closure);
+ }
+
+ struct LineSegments;
+ struct TriangleMesh;
+ struct QuadMesh;
+ struct UserGeometry;
+
+ class Scene;
+
+ typedef void (*createLineSegmentsAccelTy)(Scene* scene, LineSegments* mesh, AccelData*& accel, Builder*& builder);
+ typedef void (*createTriangleMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+ typedef void (*createQuadMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+ typedef void (*createUserGeometryAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/context.h b/thirdparty/embree-aarch64/kernels/common/context.h
new file mode 100644
index 0000000000..d0185a74f2
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/context.h
@@ -0,0 +1,131 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "rtcore.h"
+#include "point_query.h"
+
+namespace embree
+{
+ class Scene;
+
+ struct IntersectContext
+ {
+ public:
+ __forceinline IntersectContext(Scene* scene, RTCIntersectContext* user_context)
+ : scene(scene), user(user_context) {}
+
+ __forceinline bool hasContextFilter() const {
+ return user->filter != nullptr;
+ }
+
+ __forceinline bool isCoherent() const {
+ return embree::isCoherent(user->flags);
+ }
+
+ __forceinline bool isIncoherent() const {
+ return embree::isIncoherent(user->flags);
+ }
+
+ public:
+ Scene* scene;
+ RTCIntersectContext* user;
+ };
+
+ template<int M, typename Geometry>
+ __forceinline Vec4vf<M> enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3vf<M>& ray_org, const Vec4vf<M>& v)
+ {
+#if RTC_MIN_WIDTH
+ const vfloat<M> d = length(Vec3vf<M>(v) - ray_org);
+ const vfloat<M> r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w);
+ return Vec4vf<M>(v.x,v.y,v.z,r);
+#else
+ return v;
+#endif
+ }
+
+ template<typename Geometry>
+ __forceinline Vec3ff enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3fa& ray_org, const Vec3ff& v)
+ {
+#if RTC_MIN_WIDTH
+ const float d = length(Vec3fa(v) - ray_org);
+ const float r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w);
+ return Vec3ff(v.x,v.y,v.z,r);
+#else
+ return v;
+#endif
+ }
+
+ enum PointQueryType
+ {
+ POINT_QUERY_TYPE_UNDEFINED = 0,
+ POINT_QUERY_TYPE_SPHERE = 1,
+ POINT_QUERY_TYPE_AABB = 2,
+ };
+
+ typedef bool (*PointQueryFunction)(struct RTCPointQueryFunctionArguments* args);
+
+ struct PointQueryContext
+ {
+ public:
+ __forceinline PointQueryContext(Scene* scene,
+ PointQuery* query_ws,
+ PointQueryType query_type,
+ PointQueryFunction func,
+ RTCPointQueryContext* userContext,
+ float similarityScale,
+ void* userPtr)
+ : scene(scene)
+ , query_ws(query_ws)
+ , query_type(query_type)
+ , func(func)
+ , userContext(userContext)
+ , similarityScale(similarityScale)
+ , userPtr(userPtr)
+ , primID(RTC_INVALID_GEOMETRY_ID)
+ , geomID(RTC_INVALID_GEOMETRY_ID)
+ , query_radius(query_ws->radius)
+ {
+ if (query_type == POINT_QUERY_TYPE_AABB) {
+ assert(similarityScale == 0.f);
+ updateAABB();
+ }
+ if (userContext->instStackSize == 0) {
+ assert(similarityScale == 1.f);
+ }
+ }
+
+ public:
+ __forceinline void updateAABB()
+ {
+ if (likely(query_ws->radius == (float)inf || userContext->instStackSize == 0)) {
+ query_radius = Vec3fa(query_ws->radius);
+ return;
+ }
+
+ const AffineSpace3fa m = AffineSpace3fa_load_unaligned((AffineSpace3fa*)userContext->world2inst[userContext->instStackSize-1]);
+ BBox3fa bbox(Vec3fa(-query_ws->radius), Vec3fa(query_ws->radius));
+ bbox = xfmBounds(m, bbox);
+ query_radius = 0.5f * (bbox.upper - bbox.lower);
+ }
+
+public:
+ Scene* scene;
+
+ PointQuery* query_ws; // the original world space point query
+ PointQueryType query_type;
+ PointQueryFunction func;
+ RTCPointQueryContext* userContext;
+ const float similarityScale;
+
+ void* userPtr;
+
+ unsigned int primID;
+ unsigned int geomID;
+
+ Vec3fa query_radius; // used if the query is converted to an AABB internally
+ };
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/common/default.h b/thirdparty/embree-aarch64/kernels/common/default.h
new file mode 100644
index 0000000000..709119163b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/default.h
@@ -0,0 +1,273 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/sys/platform.h"
+#include "../../common/sys/sysinfo.h"
+#include "../../common/sys/thread.h"
+#include "../../common/sys/alloc.h"
+#include "../../common/sys/ref.h"
+#include "../../common/sys/intrinsics.h"
+#include "../../common/sys/atomic.h"
+#include "../../common/sys/mutex.h"
+#include "../../common/sys/vector.h"
+#include "../../common/sys/array.h"
+#include "../../common/sys/string.h"
+#include "../../common/sys/regression.h"
+#include "../../common/sys/vector.h"
+
+#include "../../common/math/math.h"
+#include "../../common/math/transcendental.h"
+#include "../../common/simd/simd.h"
+#include "../../common/math/vec2.h"
+#include "../../common/math/vec3.h"
+#include "../../common/math/vec4.h"
+#include "../../common/math/vec2fa.h"
+#include "../../common/math/vec3fa.h"
+#include "../../common/math/interval.h"
+#include "../../common/math/bbox.h"
+#include "../../common/math/obbox.h"
+#include "../../common/math/lbbox.h"
+#include "../../common/math/linearspace2.h"
+#include "../../common/math/linearspace3.h"
+#include "../../common/math/affinespace.h"
+#include "../../common/math/range.h"
+#include "../../common/lexers/tokenstream.h"
+
+#include "../../common/tasking/taskscheduler.h"
+
+#define COMMA ,
+
+#include "../config.h"
+#include "isa.h"
+#include "stat.h"
+#include "profile.h"
+#include "rtcore.h"
+#include "vector.h"
+#include "state.h"
+#include "instance_stack.h"
+
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <sstream>
+
+#if !defined(_DEBUG) && defined(BUILD_IOS)
+#undef assert
+#define assert(_EXPR)
+#endif
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec2 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec2vf = Vec2<vfloat<N>>;
+ template<int N> using Vec2vd = Vec2<vdouble<N>>;
+ template<int N> using Vec2vr = Vec2<vreal<N>>;
+ template<int N> using Vec2vi = Vec2<vint<N>>;
+ template<int N> using Vec2vl = Vec2<vllong<N>>;
+ template<int N> using Vec2vb = Vec2<vbool<N>>;
+ template<int N> using Vec2vbf = Vec2<vboolf<N>>;
+ template<int N> using Vec2vbd = Vec2<vboold<N>>;
+
+ typedef Vec2<vfloat4> Vec2vf4;
+ typedef Vec2<vdouble4> Vec2vd4;
+ typedef Vec2<vreal4> Vec2vr4;
+ typedef Vec2<vint4> Vec2vi4;
+ typedef Vec2<vllong4> Vec2vl4;
+ typedef Vec2<vbool4> Vec2vb4;
+ typedef Vec2<vboolf4> Vec2vbf4;
+ typedef Vec2<vboold4> Vec2vbd4;
+
+ typedef Vec2<vfloat8> Vec2vf8;
+ typedef Vec2<vdouble8> Vec2vd8;
+ typedef Vec2<vreal8> Vec2vr8;
+ typedef Vec2<vint8> Vec2vi8;
+ typedef Vec2<vllong8> Vec2vl8;
+ typedef Vec2<vbool8> Vec2vb8;
+ typedef Vec2<vboolf8> Vec2vbf8;
+ typedef Vec2<vboold8> Vec2vbd8;
+
+ typedef Vec2<vfloat16> Vec2vf16;
+ typedef Vec2<vdouble16> Vec2vd16;
+ typedef Vec2<vreal16> Vec2vr16;
+ typedef Vec2<vint16> Vec2vi16;
+ typedef Vec2<vllong16> Vec2vl16;
+ typedef Vec2<vbool16> Vec2vb16;
+ typedef Vec2<vboolf16> Vec2vbf16;
+ typedef Vec2<vboold16> Vec2vbd16;
+
+ typedef Vec2<vfloatx> Vec2vfx;
+ typedef Vec2<vdoublex> Vec2vdx;
+ typedef Vec2<vrealx> Vec2vrx;
+ typedef Vec2<vintx> Vec2vix;
+ typedef Vec2<vllongx> Vec2vlx;
+ typedef Vec2<vboolx> Vec2vbx;
+ typedef Vec2<vboolfx> Vec2vbfx;
+ typedef Vec2<vbooldx> Vec2vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec3 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec3vf = Vec3<vfloat<N>>;
+ template<int N> using Vec3vd = Vec3<vdouble<N>>;
+ template<int N> using Vec3vr = Vec3<vreal<N>>;
+ template<int N> using Vec3vi = Vec3<vint<N>>;
+ template<int N> using Vec3vl = Vec3<vllong<N>>;
+ template<int N> using Vec3vb = Vec3<vbool<N>>;
+ template<int N> using Vec3vbf = Vec3<vboolf<N>>;
+ template<int N> using Vec3vbd = Vec3<vboold<N>>;
+
+ typedef Vec3<vfloat4> Vec3vf4;
+ typedef Vec3<vdouble4> Vec3vd4;
+ typedef Vec3<vreal4> Vec3vr4;
+ typedef Vec3<vint4> Vec3vi4;
+ typedef Vec3<vllong4> Vec3vl4;
+ typedef Vec3<vbool4> Vec3vb4;
+ typedef Vec3<vboolf4> Vec3vbf4;
+ typedef Vec3<vboold4> Vec3vbd4;
+
+ typedef Vec3<vfloat8> Vec3vf8;
+ typedef Vec3<vdouble8> Vec3vd8;
+ typedef Vec3<vreal8> Vec3vr8;
+ typedef Vec3<vint8> Vec3vi8;
+ typedef Vec3<vllong8> Vec3vl8;
+ typedef Vec3<vbool8> Vec3vb8;
+ typedef Vec3<vboolf8> Vec3vbf8;
+ typedef Vec3<vboold8> Vec3vbd8;
+
+ typedef Vec3<vfloat16> Vec3vf16;
+ typedef Vec3<vdouble16> Vec3vd16;
+ typedef Vec3<vreal16> Vec3vr16;
+ typedef Vec3<vint16> Vec3vi16;
+ typedef Vec3<vllong16> Vec3vl16;
+ typedef Vec3<vbool16> Vec3vb16;
+ typedef Vec3<vboolf16> Vec3vbf16;
+ typedef Vec3<vboold16> Vec3vbd16;
+
+ typedef Vec3<vfloatx> Vec3vfx;
+ typedef Vec3<vdoublex> Vec3vdx;
+ typedef Vec3<vrealx> Vec3vrx;
+ typedef Vec3<vintx> Vec3vix;
+ typedef Vec3<vllongx> Vec3vlx;
+ typedef Vec3<vboolx> Vec3vbx;
+ typedef Vec3<vboolfx> Vec3vbfx;
+ typedef Vec3<vbooldx> Vec3vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec4 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec4vf = Vec4<vfloat<N>>;
+ template<int N> using Vec4vd = Vec4<vdouble<N>>;
+ template<int N> using Vec4vr = Vec4<vreal<N>>;
+ template<int N> using Vec4vi = Vec4<vint<N>>;
+ template<int N> using Vec4vl = Vec4<vllong<N>>;
+ template<int N> using Vec4vb = Vec4<vbool<N>>;
+ template<int N> using Vec4vbf = Vec4<vboolf<N>>;
+ template<int N> using Vec4vbd = Vec4<vboold<N>>;
+
+ typedef Vec4<vfloat4> Vec4vf4;
+ typedef Vec4<vdouble4> Vec4vd4;
+ typedef Vec4<vreal4> Vec4vr4;
+ typedef Vec4<vint4> Vec4vi4;
+ typedef Vec4<vllong4> Vec4vl4;
+ typedef Vec4<vbool4> Vec4vb4;
+ typedef Vec4<vboolf4> Vec4vbf4;
+ typedef Vec4<vboold4> Vec4vbd4;
+
+ typedef Vec4<vfloat8> Vec4vf8;
+ typedef Vec4<vdouble8> Vec4vd8;
+ typedef Vec4<vreal8> Vec4vr8;
+ typedef Vec4<vint8> Vec4vi8;
+ typedef Vec4<vllong8> Vec4vl8;
+ typedef Vec4<vbool8> Vec4vb8;
+ typedef Vec4<vboolf8> Vec4vbf8;
+ typedef Vec4<vboold8> Vec4vbd8;
+
+ typedef Vec4<vfloat16> Vec4vf16;
+ typedef Vec4<vdouble16> Vec4vd16;
+ typedef Vec4<vreal16> Vec4vr16;
+ typedef Vec4<vint16> Vec4vi16;
+ typedef Vec4<vllong16> Vec4vl16;
+ typedef Vec4<vbool16> Vec4vb16;
+ typedef Vec4<vboolf16> Vec4vbf16;
+ typedef Vec4<vboold16> Vec4vbd16;
+
+ typedef Vec4<vfloatx> Vec4vfx;
+ typedef Vec4<vdoublex> Vec4vdx;
+ typedef Vec4<vrealx> Vec4vrx;
+ typedef Vec4<vintx> Vec4vix;
+ typedef Vec4<vllongx> Vec4vlx;
+ typedef Vec4<vboolx> Vec4vbx;
+ typedef Vec4<vboolfx> Vec4vbfx;
+ typedef Vec4<vbooldx> Vec4vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Other shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using BBox3vf = BBox<Vec3vf<N>>;
+ typedef BBox<Vec3vf4> BBox3vf4;
+ typedef BBox<Vec3vf8> BBox3vf8;
+ typedef BBox<Vec3vf16> BBox3vf16;
+
+ /* calculate time segment itime and fractional time ftime */
+ __forceinline int getTimeSegment(float time, float numTimeSegments, float& ftime)
+ {
+ const float timeScaled = time * numTimeSegments;
+ const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return int(itimef);
+ }
+
+ __forceinline int getTimeSegment(float time, float start_time, float end_time, float numTimeSegments, float& ftime)
+ {
+ const float timeScaled = (time-start_time)/(end_time-start_time) * numTimeSegments;
+ const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return int(itimef);
+ }
+
+ template<int N>
+ __forceinline vint<N> getTimeSegment(const vfloat<N>& time, const vfloat<N>& numTimeSegments, vfloat<N>& ftime)
+ {
+ const vfloat<N> timeScaled = time * numTimeSegments;
+ const vfloat<N> itimef = clamp(floor(timeScaled), vfloat<N>(zero), numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return vint<N>(itimef);
+ }
+
+ template<int N>
+ __forceinline vint<N> getTimeSegment(const vfloat<N>& time, const vfloat<N>& start_time, const vfloat<N>& end_time, const vfloat<N>& numTimeSegments, vfloat<N>& ftime)
+ {
+ const vfloat<N> timeScaled = (time-start_time)/(end_time-start_time) * numTimeSegments;
+ const vfloat<N> itimef = clamp(floor(timeScaled), vfloat<N>(zero), numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return vint<N>(itimef);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> getTimeSegmentRange(const BBox1f& time_range, float numTimeSegments)
+ {
+ const float round_up = 1.0f+2.0f*float(ulp); // corrects inaccuracies to precisely match time step
+ const float round_down = 1.0f-2.0f*float(ulp);
+ const int itime_lower = (int)max(floor(round_up *time_range.lower*numTimeSegments), 0.0f);
+ const int itime_upper = (int)min(ceil (round_down*time_range.upper*numTimeSegments), numTimeSegments);
+ return make_range(itime_lower, itime_upper);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> getTimeSegmentRange(const BBox1f& range, BBox1f time_range, float numTimeSegments)
+ {
+ const float lower = (range.lower-time_range.lower)/time_range.size();
+ const float upper = (range.upper-time_range.lower)/time_range.size();
+ return getTimeSegmentRange(BBox1f(lower,upper),numTimeSegments);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/device.cpp b/thirdparty/embree-aarch64/kernels/common/device.cpp
new file mode 100644
index 0000000000..16ec11b892
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/device.cpp
@@ -0,0 +1,567 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "device.h"
+#include "../hash.h"
+#include "scene_triangle_mesh.h"
+#include "scene_user_geometry.h"
+#include "scene_instance.h"
+#include "scene_curves.h"
+#include "scene_subdiv_mesh.h"
+
+#include "../subdiv/tessellation_cache.h"
+
+#include "acceln.h"
+#include "geometry.h"
+
+#include "../geometry/cylinder.h"
+
+#include "../bvh/bvh4_factory.h"
+#include "../bvh/bvh8_factory.h"
+
+#include "../../common/tasking/taskscheduler.h"
+#include "../../common/sys/alloc.h"
+
+namespace embree
+{
+ /*! some global variables that can be set via rtcSetParameter1i for debugging purposes */
+ ssize_t Device::debug_int0 = 0;
+ ssize_t Device::debug_int1 = 0;
+ ssize_t Device::debug_int2 = 0;
+ ssize_t Device::debug_int3 = 0;
+
+ DECLARE_SYMBOL2(RayStreamFilterFuncs,rayStreamFilterFuncs);
+
+ static MutexSys g_mutex;
+ static std::map<Device*,size_t> g_cache_size_map;
+ static std::map<Device*,size_t> g_num_threads_map;
+
+ Device::Device (const char* cfg)
+ {
+ /* check that CPU supports lowest ISA */
+ if (!hasISA(ISA)) {
+ throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support " ISA_STR);
+ }
+
+ /* set default frequency level for detected CPU */
+ switch (getCPUModel()) {
+ case CPU::UNKNOWN: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_TIGER_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_COMET_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_CANNON_LAKE:frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_KABY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::XEON_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::XEON_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::SANDY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::NEHALEM: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE2: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE1: frequency_level = FREQUENCY_SIMD128; break;
+ }
+
+ /* initialize global state */
+#if defined(EMBREE_CONFIG)
+ State::parseString(EMBREE_CONFIG);
+#endif
+ State::parseString(cfg);
+ if (!ignore_config_files && FileName::executableFolder() != FileName(""))
+ State::parseFile(FileName::executableFolder()+FileName(".embree" TOSTRING(RTC_VERSION_MAJOR)));
+ if (!ignore_config_files && FileName::homeFolder() != FileName(""))
+ State::parseFile(FileName::homeFolder()+FileName(".embree" TOSTRING(RTC_VERSION_MAJOR)));
+ State::verify();
+
+ /* check whether selected ISA is supported by the HW, as the user could have forced an unsupported ISA */
+ if (!checkISASupport()) {
+ throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support selected ISA");
+ }
+
+ /*! do some internal tests */
+ assert(isa::Cylinder::verify());
+
+ /*! enable huge page support if desired */
+#if defined(__WIN32__)
+ if (State::enable_selockmemoryprivilege)
+ State::hugepages_success &= win_enable_selockmemoryprivilege(State::verbosity(3));
+#endif
+ State::hugepages_success &= os_init(State::hugepages,State::verbosity(3));
+
+ /*! set tessellation cache size */
+ setCacheSize( State::tessellation_cache_size );
+
+ /*! enable some floating point exceptions to catch bugs */
+ if (State::float_exceptions)
+ {
+ int exceptions = _MM_MASK_MASK;
+ //exceptions &= ~_MM_MASK_INVALID;
+ exceptions &= ~_MM_MASK_DENORM;
+ exceptions &= ~_MM_MASK_DIV_ZERO;
+ //exceptions &= ~_MM_MASK_OVERFLOW;
+ //exceptions &= ~_MM_MASK_UNDERFLOW;
+ //exceptions &= ~_MM_MASK_INEXACT;
+ _MM_SET_EXCEPTION_MASK(exceptions);
+ }
+
+ /* print info header */
+ if (State::verbosity(1))
+ print();
+ if (State::verbosity(2))
+ State::print();
+
+ /* register all algorithms */
+ bvh4_factory = make_unique(new BVH4Factory(enabled_builder_cpu_features, enabled_cpu_features));
+
+#if defined(EMBREE_TARGET_SIMD8)
+ bvh8_factory = make_unique(new BVH8Factory(enabled_builder_cpu_features, enabled_cpu_features));
+#endif
+
+ /* setup tasking system */
+ initTaskingSystem(numThreads);
+
+ /* ray stream SOA to AOS conversion */
+#if defined(EMBREE_RAY_PACKETS)
+ RayStreamFilterFuncsType rayStreamFilterFuncs;
+ SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(enabled_cpu_features,rayStreamFilterFuncs);
+ rayStreamFilters = rayStreamFilterFuncs();
+#endif
+ }
+
+ Device::~Device ()
+ {
+ setCacheSize(0);
+ exitTaskingSystem();
+ }
+
+ std::string getEnabledTargets()
+ {
+ std::string v;
+#if defined(EMBREE_TARGET_SSE2)
+ v += "SSE2 ";
+#endif
+#if defined(EMBREE_TARGET_SSE42)
+ v += "SSE4.2 ";
+#endif
+#if defined(EMBREE_TARGET_AVX)
+ v += "AVX ";
+#endif
+#if defined(EMBREE_TARGET_AVX2)
+ v += "AVX2 ";
+#endif
+#if defined(EMBREE_TARGET_AVX512KNL)
+ v += "AVX512KNL ";
+#endif
+#if defined(EMBREE_TARGET_AVX512SKX)
+ v += "AVX512SKX ";
+#endif
+ return v;
+ }
+
+ std::string getEmbreeFeatures()
+ {
+ std::string v;
+#if defined(EMBREE_RAY_MASK)
+ v += "raymasks ";
+#endif
+#if defined (EMBREE_BACKFACE_CULLING)
+ v += "backfaceculling ";
+#endif
+#if defined (EMBREE_BACKFACE_CULLING_CURVES)
+ v += "backfacecullingcurves ";
+#endif
+#if defined(EMBREE_FILTER_FUNCTION)
+ v += "intersection_filter ";
+#endif
+#if defined (EMBREE_COMPACT_POLYS)
+ v += "compact_polys ";
+#endif
+ return v;
+ }
+
+ void Device::print()
+ {
+ const int cpu_features = getCPUFeatures();
+ std::cout << std::endl;
+ std::cout << "Embree Ray Tracing Kernels " << RTC_VERSION_STRING << " (" << RTC_HASH << ")" << std::endl;
+ std::cout << " Compiler : " << getCompilerName() << std::endl;
+ std::cout << " Build : ";
+#if defined(DEBUG)
+ std::cout << "Debug " << std::endl;
+#else
+ std::cout << "Release " << std::endl;
+#endif
+ std::cout << " Platform : " << getPlatformName() << std::endl;
+ std::cout << " CPU : " << stringOfCPUModel(getCPUModel()) << " (" << getCPUVendor() << ")" << std::endl;
+ std::cout << " Threads : " << getNumberOfLogicalThreads() << std::endl;
+ std::cout << " ISA : " << stringOfCPUFeatures(cpu_features) << std::endl;
+ std::cout << " Targets : " << supportedTargetList(cpu_features) << std::endl;
+ const bool hasFTZ = _mm_getcsr() & _MM_FLUSH_ZERO_ON;
+ const bool hasDAZ = _mm_getcsr() & _MM_DENORMALS_ZERO_ON;
+ std::cout << " MXCSR : " << "FTZ=" << hasFTZ << ", DAZ=" << hasDAZ << std::endl;
+ std::cout << " Config" << std::endl;
+ std::cout << " Threads : " << (numThreads ? toString(numThreads) : std::string("default")) << std::endl;
+ std::cout << " ISA : " << stringOfCPUFeatures(enabled_cpu_features) << std::endl;
+ std::cout << " Targets : " << supportedTargetList(enabled_cpu_features) << " (supported)" << std::endl;
+ std::cout << " " << getEnabledTargets() << " (compile time enabled)" << std::endl;
+ std::cout << " Features: " << getEmbreeFeatures() << std::endl;
+ std::cout << " Tasking : ";
+#if defined(TASKING_TBB)
+ std::cout << "TBB" << TBB_VERSION_MAJOR << "." << TBB_VERSION_MINOR << " ";
+ #if TBB_INTERFACE_VERSION >= 12002
+ std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << TBB_runtime_interface_version() << " ";
+ #else
+ std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << tbb::TBB_runtime_interface_version() << " ";
+ #endif
+#endif
+#if defined(TASKING_INTERNAL)
+ std::cout << "internal_tasking_system ";
+#endif
+#if defined(TASKING_GCD) && defined(BUILD_IOS)
+ std::cout << "GCD tasking system ";
+#endif
+#if defined(TASKING_PPL)
+ std::cout << "PPL ";
+#endif
+ std::cout << std::endl;
+
+ /* check of FTZ and DAZ flags are set in CSR */
+ if (!hasFTZ || !hasDAZ)
+ {
+#if !defined(_DEBUG)
+ if (State::verbosity(1))
+#endif
+ {
+ std::cout << std::endl;
+ std::cout << "================================================================================" << std::endl;
+ std::cout << " WARNING: \"Flush to Zero\" or \"Denormals are Zero\" mode not enabled " << std::endl
+ << " in the MXCSR control and status register. This can have a severe " << std::endl
+ << " performance impact. Please enable these modes for each application " << std::endl
+ << " thread the following way:" << std::endl
+ << std::endl
+ << " #include \"xmmintrin.h\"" << std::endl
+ << " #include \"pmmintrin.h\"" << std::endl
+ << std::endl
+ << " _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);" << std::endl
+ << " _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);" << std::endl;
+ std::cout << "================================================================================" << std::endl;
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+ }
+
+ void Device::setDeviceErrorCode(RTCError error)
+ {
+ RTCError* stored_error = errorHandler.error();
+ if (*stored_error == RTC_ERROR_NONE)
+ *stored_error = error;
+ }
+
+ RTCError Device::getDeviceErrorCode()
+ {
+ RTCError* stored_error = errorHandler.error();
+ RTCError error = *stored_error;
+ *stored_error = RTC_ERROR_NONE;
+ return error;
+ }
+
+ void Device::setThreadErrorCode(RTCError error)
+ {
+ RTCError* stored_error = g_errorHandler.error();
+ if (*stored_error == RTC_ERROR_NONE)
+ *stored_error = error;
+ }
+
+ RTCError Device::getThreadErrorCode()
+ {
+ RTCError* stored_error = g_errorHandler.error();
+ RTCError error = *stored_error;
+ *stored_error = RTC_ERROR_NONE;
+ return error;
+ }
+
+ void Device::process_error(Device* device, RTCError error, const char* str)
+ {
+ /* store global error code when device construction failed */
+ if (!device)
+ return setThreadErrorCode(error);
+
+ /* print error when in verbose mode */
+ if (device->verbosity(1))
+ {
+ switch (error) {
+ case RTC_ERROR_NONE : std::cerr << "Embree: No error"; break;
+ case RTC_ERROR_UNKNOWN : std::cerr << "Embree: Unknown error"; break;
+ case RTC_ERROR_INVALID_ARGUMENT : std::cerr << "Embree: Invalid argument"; break;
+ case RTC_ERROR_INVALID_OPERATION: std::cerr << "Embree: Invalid operation"; break;
+ case RTC_ERROR_OUT_OF_MEMORY : std::cerr << "Embree: Out of memory"; break;
+ case RTC_ERROR_UNSUPPORTED_CPU : std::cerr << "Embree: Unsupported CPU"; break;
+ default : std::cerr << "Embree: Invalid error code"; break;
+ };
+ if (str) std::cerr << ", (" << str << ")";
+ std::cerr << std::endl;
+ }
+
+ /* call user specified error callback */
+ if (device->error_function)
+ device->error_function(device->error_function_userptr,error,str);
+
+ /* record error code */
+ device->setDeviceErrorCode(error);
+ }
+
+ void Device::memoryMonitor(ssize_t bytes, bool post)
+ {
+ if (State::memory_monitor_function && bytes != 0) {
+ if (!State::memory_monitor_function(State::memory_monitor_userptr,bytes,post)) {
+ if (bytes > 0) { // only throw exception when we allocate memory to never throw inside a destructor
+ throw_RTCError(RTC_ERROR_OUT_OF_MEMORY,"memory monitor forced termination");
+ }
+ }
+ }
+ }
+
+ size_t getMaxNumThreads()
+ {
+ size_t maxNumThreads = 0;
+ for (std::map<Device*,size_t>::iterator i=g_num_threads_map.begin(); i != g_num_threads_map.end(); i++)
+ maxNumThreads = max(maxNumThreads, (*i).second);
+ if (maxNumThreads == 0)
+ maxNumThreads = std::numeric_limits<size_t>::max();
+ return maxNumThreads;
+ }
+
+ size_t getMaxCacheSize()
+ {
+ size_t maxCacheSize = 0;
+ for (std::map<Device*,size_t>::iterator i=g_cache_size_map.begin(); i!= g_cache_size_map.end(); i++)
+ maxCacheSize = max(maxCacheSize, (*i).second);
+ return maxCacheSize;
+ }
+
+ void Device::setCacheSize(size_t bytes)
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ Lock<MutexSys> lock(g_mutex);
+ if (bytes == 0) g_cache_size_map.erase(this);
+ else g_cache_size_map[this] = bytes;
+
+ size_t maxCacheSize = getMaxCacheSize();
+ resizeTessellationCache(maxCacheSize);
+#endif
+ }
+
+ void Device::initTaskingSystem(size_t numThreads)
+ {
+ Lock<MutexSys> lock(g_mutex);
+ if (numThreads == 0)
+ g_num_threads_map[this] = std::numeric_limits<size_t>::max();
+ else
+ g_num_threads_map[this] = numThreads;
+
+ /* create task scheduler */
+ size_t maxNumThreads = getMaxNumThreads();
+ TaskScheduler::create(maxNumThreads,State::set_affinity,State::start_threads);
+#if USE_TASK_ARENA
+ const size_t nThreads = min(maxNumThreads,TaskScheduler::threadCount());
+ const size_t uThreads = min(max(numUserThreads,(size_t)1),nThreads);
+ arena = make_unique(new tbb::task_arena((int)nThreads,(unsigned int)uThreads));
+#endif
+ }
+
+ void Device::exitTaskingSystem()
+ {
+ Lock<MutexSys> lock(g_mutex);
+ g_num_threads_map.erase(this);
+
+ /* terminate tasking system */
+ if (g_num_threads_map.size() == 0) {
+ TaskScheduler::destroy();
+ }
+ /* or configure new number of threads */
+ else {
+ size_t maxNumThreads = getMaxNumThreads();
+ TaskScheduler::create(maxNumThreads,State::set_affinity,State::start_threads);
+ }
+#if USE_TASK_ARENA
+ arena.reset();
+#endif
+ }
+
+ void Device::setProperty(const RTCDeviceProperty prop, ssize_t val)
+ {
+ /* hidden internal properties */
+ switch ((size_t)prop)
+ {
+ case 1000000: debug_int0 = val; return;
+ case 1000001: debug_int1 = val; return;
+ case 1000002: debug_int2 = val; return;
+ case 1000003: debug_int3 = val; return;
+ }
+
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown writable property");
+ }
+
+ ssize_t Device::getProperty(const RTCDeviceProperty prop)
+ {
+ size_t iprop = (size_t)prop;
+
+ /* get name of internal regression test */
+ if (iprop >= 2000000 && iprop < 3000000)
+ {
+ RegressionTest* test = getRegressionTest(iprop-2000000);
+ if (test) return (ssize_t) test->name.c_str();
+ else return 0;
+ }
+
+ /* run internal regression test */
+ if (iprop >= 3000000 && iprop < 4000000)
+ {
+ RegressionTest* test = getRegressionTest(iprop-3000000);
+ if (test) return test->run();
+ else return 0;
+ }
+
+ /* documented properties */
+ switch (prop)
+ {
+ case RTC_DEVICE_PROPERTY_VERSION_MAJOR: return RTC_VERSION_MAJOR;
+ case RTC_DEVICE_PROPERTY_VERSION_MINOR: return RTC_VERSION_MINOR;
+ case RTC_DEVICE_PROPERTY_VERSION_PATCH: return RTC_VERSION_PATCH;
+ case RTC_DEVICE_PROPERTY_VERSION : return RTC_VERSION;
+
+#if defined(EMBREE_TARGET_SIMD4) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return hasISA(SSE2);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_TARGET_SIMD8) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return hasISA(AVX);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_TARGET_SIMD16) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return hasISA(AVX512KNL) | hasISA(AVX512SKX);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_RAY_MASK)
+ case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_BACKFACE_CULLING)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_BACKFACE_CULLING_CURVES)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_COMPACT_POLYS)
+ case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 0;
+#endif
+
+#if defined(TASKING_INTERNAL)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 0;
+#endif
+
+#if defined(TASKING_TBB)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 1;
+#endif
+
+#if defined(TASKING_PPL)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 2;
+#endif
+
+#if defined(TASKING_GCD) && defined(BUILD_IOS)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 3;
+#endif
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(TASKING_PPL)
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
+#elif defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
+#else
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 1;
+#endif
+
+#if defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION
+ case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 0;
+#endif
+
+ default: throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown readable property"); break;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/device.h b/thirdparty/embree-aarch64/kernels/common/device.h
new file mode 100644
index 0000000000..e9a81bb109
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/device.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "state.h"
+#include "accel.h"
+
+namespace embree
+{
+ class BVH4Factory;
+ class BVH8Factory;
+
+ class Device : public State, public MemoryMonitorInterface
+ {
+ ALIGNED_CLASS_(16);
+
+ public:
+
+ /*! Device construction */
+ Device (const char* cfg);
+
+ /*! Device destruction */
+ virtual ~Device ();
+
+ /*! prints info about the device */
+ void print();
+
+ /*! sets the error code */
+ void setDeviceErrorCode(RTCError error);
+
+ /*! returns and clears the error code */
+ RTCError getDeviceErrorCode();
+
+ /*! sets the error code */
+ static void setThreadErrorCode(RTCError error);
+
+ /*! returns and clears the error code */
+ static RTCError getThreadErrorCode();
+
+ /*! processes error codes, do not call directly */
+ static void process_error(Device* device, RTCError error, const char* str);
+
+ /*! invokes the memory monitor callback */
+ void memoryMonitor(ssize_t bytes, bool post);
+
+ /*! sets the size of the software cache. */
+ void setCacheSize(size_t bytes);
+
+ /*! sets a property */
+ void setProperty(const RTCDeviceProperty prop, ssize_t val);
+
+ /*! gets a property */
+ ssize_t getProperty(const RTCDeviceProperty prop);
+
+ private:
+
+ /*! initializes the tasking system */
+ void initTaskingSystem(size_t numThreads);
+
+ /*! shuts down the tasking system */
+ void exitTaskingSystem();
+
+ /*! some variables that can be set via rtcSetParameter1i for debugging purposes */
+ public:
+ static ssize_t debug_int0;
+ static ssize_t debug_int1;
+ static ssize_t debug_int2;
+ static ssize_t debug_int3;
+
+ public:
+ std::unique_ptr<BVH4Factory> bvh4_factory;
+#if defined(EMBREE_TARGET_SIMD8)
+ std::unique_ptr<BVH8Factory> bvh8_factory;
+#endif
+
+#if USE_TASK_ARENA
+ std::unique_ptr<tbb::task_arena> arena;
+#endif
+
+ /* ray streams filter */
+ RayStreamFilterFuncs rayStreamFilters;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/geometry.cpp b/thirdparty/embree-aarch64/kernels/common/geometry.cpp
new file mode 100644
index 0000000000..b3aa8e3396
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/geometry.cpp
@@ -0,0 +1,259 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "geometry.h"
+#include "scene.h"
+
+namespace embree
+{
+ const char* Geometry::gtype_names[Geometry::GTY_END] =
+ {
+ "flat_linear_curve",
+ "round_linear_curve",
+ "oriented_linear_curve",
+ "",
+ "flat_bezier_curve",
+ "round_bezier_curve",
+ "oriented_bezier_curve",
+ "",
+ "flat_bspline_curve",
+ "round_bspline_curve",
+ "oriented_bspline_curve",
+ "",
+ "flat_hermite_curve",
+ "round_hermite_curve",
+ "oriented_hermite_curve",
+ "",
+ "flat_catmull_rom_curve",
+ "round_catmull_rom_curve",
+ "oriented_catmull_rom_curve",
+ "",
+ "triangles",
+ "quads",
+ "grid",
+ "subdivs",
+ "",
+ "sphere",
+ "disc",
+ "oriented_disc",
+ "",
+ "usergeom",
+ "instance_cheap",
+ "instance_expensive",
+ };
+
+ Geometry::Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps)
+ : device(device), userPtr(nullptr),
+ numPrimitives(numPrimitives), numTimeSteps(unsigned(numTimeSteps)), fnumTimeSegments(float(numTimeSteps-1)), time_range(0.0f,1.0f),
+ mask(-1),
+ gtype(gtype),
+ gsubtype(GTY_SUBTYPE_DEFAULT),
+ quality(RTC_BUILD_QUALITY_MEDIUM),
+ state((unsigned)State::MODIFIED),
+ enabled(true),
+ intersectionFilterN(nullptr), occlusionFilterN(nullptr), pointQueryFunc(nullptr)
+ {
+ device->refInc();
+ }
+
+ Geometry::~Geometry()
+ {
+ device->refDec();
+ }
+
+ void Geometry::setNumPrimitives(unsigned int numPrimitives_in)
+ {
+ if (numPrimitives_in == numPrimitives) return;
+
+ numPrimitives = numPrimitives_in;
+
+ Geometry::update();
+ }
+
+ void Geometry::setNumTimeSteps (unsigned int numTimeSteps_in)
+ {
+ if (numTimeSteps_in == numTimeSteps) {
+ return;
+ }
+
+ numTimeSteps = numTimeSteps_in;
+ fnumTimeSegments = float(numTimeSteps_in-1);
+
+ Geometry::update();
+ }
+
+ void Geometry::setTimeRange (const BBox1f range)
+ {
+ time_range = range;
+ Geometry::update();
+ }
+
+ void Geometry::update()
+ {
+ ++modCounter_; // FIXME: required?
+ state = (unsigned)State::MODIFIED;
+ }
+
+ void Geometry::commit()
+ {
+ ++modCounter_;
+ state = (unsigned)State::COMMITTED;
+ }
+
+ void Geometry::preCommit()
+ {
+ if (State::MODIFIED == (State)state)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"geometry not committed");
+ }
+
+ void Geometry::postCommit()
+ {
+ }
+
+ void Geometry::enable ()
+ {
+ if (isEnabled())
+ return;
+
+ enabled = true;
+ ++modCounter_;
+ }
+
+ void Geometry::disable ()
+ {
+ if (isDisabled())
+ return;
+
+ enabled = false;
+ ++modCounter_;
+ }
+
+ void Geometry::setUserData (void* ptr)
+ {
+ userPtr = ptr;
+ }
+
+ void Geometry::setIntersectionFilterFunctionN (RTCFilterFunctionN filter)
+ {
+ if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");
+
+ intersectionFilterN = filter;
+ }
+
+ void Geometry::setOcclusionFilterFunctionN (RTCFilterFunctionN filter)
+ {
+ if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");
+
+ occlusionFilterN = filter;
+ }
+
+ void Geometry::setPointQueryFunction (RTCPointQueryFunction func)
+ {
+ pointQueryFunc = func;
+ }
+
+ void Geometry::interpolateN(const RTCInterpolateNArguments* const args)
+ {
+ const void* valid_i = args->valid;
+ const unsigned* primIDs = args->primIDs;
+ const float* u = args->u;
+ const float* v = args->v;
+ unsigned int N = args->N;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ if (valueCount > 256) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximally 256 floating point values can be interpolated per vertex");
+ const int* valid = (const int*) valid_i;
+
+ __aligned(64) float P_tmp[256];
+ __aligned(64) float dPdu_tmp[256];
+ __aligned(64) float dPdv_tmp[256];
+ __aligned(64) float ddPdudu_tmp[256];
+ __aligned(64) float ddPdvdv_tmp[256];
+ __aligned(64) float ddPdudv_tmp[256];
+
+ float* Pt = P ? P_tmp : nullptr;
+ float* dPdut = nullptr, *dPdvt = nullptr;
+ if (dPdu) { dPdut = dPdu_tmp; dPdvt = dPdv_tmp; }
+ float* ddPdudut = nullptr, *ddPdvdvt = nullptr, *ddPdudvt = nullptr;
+ if (ddPdudu) { ddPdudut = ddPdudu_tmp; ddPdvdvt = ddPdvdv_tmp; ddPdudvt = ddPdudv_tmp; }
+
+ for (unsigned int i=0; i<N; i++)
+ {
+ if (valid && !valid[i]) continue;
+
+ RTCInterpolateArguments iargs;
+ iargs.primID = primIDs[i];
+ iargs.u = u[i];
+ iargs.v = v[i];
+ iargs.bufferType = bufferType;
+ iargs.bufferSlot = bufferSlot;
+ iargs.P = Pt;
+ iargs.dPdu = dPdut;
+ iargs.dPdv = dPdvt;
+ iargs.ddPdudu = ddPdudut;
+ iargs.ddPdvdv = ddPdvdvt;
+ iargs.ddPdudv = ddPdudvt;
+ iargs.valueCount = valueCount;
+ interpolate(&iargs);
+
+ if (likely(P)) {
+ for (unsigned int j=0; j<valueCount; j++)
+ P[j*N+i] = Pt[j];
+ }
+ if (likely(dPdu))
+ {
+ for (unsigned int j=0; j<valueCount; j++) {
+ dPdu[j*N+i] = dPdut[j];
+ dPdv[j*N+i] = dPdvt[j];
+ }
+ }
+ if (likely(ddPdudu))
+ {
+ for (unsigned int j=0; j<valueCount; j++) {
+ ddPdudu[j*N+i] = ddPdudut[j];
+ ddPdvdv[j*N+i] = ddPdvdvt[j];
+ ddPdudv[j*N+i] = ddPdudvt[j];
+ }
+ }
+ }
+ }
+
+ bool Geometry::pointQuery(PointQuery* query, PointQueryContext* context)
+ {
+ assert(context->primID < size());
+
+ RTCPointQueryFunctionArguments args;
+ args.query = (RTCPointQuery*)context->query_ws;
+ args.userPtr = context->userPtr;
+ args.primID = context->primID;
+ args.geomID = context->geomID;
+ args.context = context->userContext;
+ args.similarityScale = context->similarityScale;
+
+ bool update = false;
+ if(context->func) update |= context->func(&args);
+ if(pointQueryFunc) update |= pointQueryFunc(&args);
+
+ if (update && context->userContext->instStackSize > 0)
+ {
+ // update point query
+ if (context->query_type == POINT_QUERY_TYPE_AABB) {
+ context->updateAABB();
+ } else {
+ assert(context->similarityScale > 0.f);
+ query->radius = context->query_ws->radius * context->similarityScale;
+ }
+ }
+ return update;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/geometry.h b/thirdparty/embree-aarch64/kernels/common/geometry.h
new file mode 100644
index 0000000000..953974bfd2
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/geometry.h
@@ -0,0 +1,582 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "buffer.h"
+#include "../common/point_query.h"
+#include "../builders/priminfo.h"
+
+namespace embree
+{
+ class Scene;
+ class Geometry;
+
+ struct GeometryCounts
+ {
+ __forceinline GeometryCounts()
+ : numFilterFunctions(0),
+ numTriangles(0), numMBTriangles(0),
+ numQuads(0), numMBQuads(0),
+ numBezierCurves(0), numMBBezierCurves(0),
+ numLineSegments(0), numMBLineSegments(0),
+ numSubdivPatches(0), numMBSubdivPatches(0),
+ numUserGeometries(0), numMBUserGeometries(0),
+ numInstancesCheap(0), numMBInstancesCheap(0),
+ numInstancesExpensive(0), numMBInstancesExpensive(0),
+ numGrids(0), numMBGrids(0),
+ numPoints(0), numMBPoints(0) {}
+
+ __forceinline size_t size() const {
+ return numTriangles + numQuads + numBezierCurves + numLineSegments + numSubdivPatches + numUserGeometries + numInstancesCheap + numInstancesExpensive + numGrids + numPoints
+ + numMBTriangles + numMBQuads + numMBBezierCurves + numMBLineSegments + numMBSubdivPatches + numMBUserGeometries + numMBInstancesCheap + numMBInstancesExpensive + numMBGrids + numMBPoints;
+ }
+
+ __forceinline unsigned int enabledGeometryTypesMask() const
+ {
+ unsigned int mask = 0;
+ if (numTriangles) mask |= 1 << 0;
+ if (numQuads) mask |= 1 << 1;
+ if (numBezierCurves+numLineSegments) mask |= 1 << 2;
+ if (numSubdivPatches) mask |= 1 << 3;
+ if (numUserGeometries) mask |= 1 << 4;
+ if (numInstancesCheap) mask |= 1 << 5;
+ if (numInstancesExpensive) mask |= 1 << 6;
+ if (numGrids) mask |= 1 << 7;
+ if (numPoints) mask |= 1 << 8;
+
+ unsigned int maskMB = 0;
+ if (numMBTriangles) maskMB |= 1 << 0;
+ if (numMBQuads) maskMB |= 1 << 1;
+ if (numMBBezierCurves+numMBLineSegments) maskMB |= 1 << 2;
+ if (numMBSubdivPatches) maskMB |= 1 << 3;
+ if (numMBUserGeometries) maskMB |= 1 << 4;
+ if (numMBInstancesCheap) maskMB |= 1 << 5;
+ if (numMBInstancesExpensive) maskMB |= 1 << 6;
+ if (numMBGrids) maskMB |= 1 << 7;
+ if (numMBPoints) maskMB |= 1 << 8;
+
+ return (mask<<8) + maskMB;
+ }
+
+ __forceinline GeometryCounts operator+ (GeometryCounts const & rhs) const
+ {
+ GeometryCounts ret;
+ ret.numFilterFunctions = numFilterFunctions + rhs.numFilterFunctions;
+ ret.numTriangles = numTriangles + rhs.numTriangles;
+ ret.numMBTriangles = numMBTriangles + rhs.numMBTriangles;
+ ret.numQuads = numQuads + rhs.numQuads;
+ ret.numMBQuads = numMBQuads + rhs.numMBQuads;
+ ret.numBezierCurves = numBezierCurves + rhs.numBezierCurves;
+ ret.numMBBezierCurves = numMBBezierCurves + rhs.numMBBezierCurves;
+ ret.numLineSegments = numLineSegments + rhs.numLineSegments;
+ ret.numMBLineSegments = numMBLineSegments + rhs.numMBLineSegments;
+ ret.numSubdivPatches = numSubdivPatches + rhs.numSubdivPatches;
+ ret.numMBSubdivPatches = numMBSubdivPatches + rhs.numMBSubdivPatches;
+ ret.numUserGeometries = numUserGeometries + rhs.numUserGeometries;
+ ret.numMBUserGeometries = numMBUserGeometries + rhs.numMBUserGeometries;
+ ret.numInstancesCheap = numInstancesCheap + rhs.numInstancesCheap;
+ ret.numMBInstancesCheap = numMBInstancesCheap + rhs.numMBInstancesCheap;
+ ret.numInstancesExpensive = numInstancesExpensive + rhs.numInstancesExpensive;
+ ret.numMBInstancesExpensive = numMBInstancesExpensive + rhs.numMBInstancesExpensive;
+ ret.numGrids = numGrids + rhs.numGrids;
+ ret.numMBGrids = numMBGrids + rhs.numMBGrids;
+ ret.numPoints = numPoints + rhs.numPoints;
+ ret.numMBPoints = numMBPoints + rhs.numMBPoints;
+
+ return ret;
+ }
+
+ size_t numFilterFunctions; //!< number of geometries with filter functions enabled
+ size_t numTriangles; //!< number of enabled triangles
+ size_t numMBTriangles; //!< number of enabled motion blured triangles
+ size_t numQuads; //!< number of enabled quads
+ size_t numMBQuads; //!< number of enabled motion blurred quads
+ size_t numBezierCurves; //!< number of enabled curves
+ size_t numMBBezierCurves; //!< number of enabled motion blurred curves
+ size_t numLineSegments; //!< number of enabled line segments
+ size_t numMBLineSegments; //!< number of enabled line motion blurred segments
+ size_t numSubdivPatches; //!< number of enabled subdivision patches
+ size_t numMBSubdivPatches; //!< number of enabled motion blured subdivision patches
+ size_t numUserGeometries; //!< number of enabled user geometries
+ size_t numMBUserGeometries; //!< number of enabled motion blurred user geometries
+ size_t numInstancesCheap; //!< number of enabled cheap instances
+ size_t numMBInstancesCheap; //!< number of enabled motion blurred cheap instances
+ size_t numInstancesExpensive; //!< number of enabled expensive instances
+ size_t numMBInstancesExpensive; //!< number of enabled motion blurred expensive instances
+ size_t numGrids; //!< number of enabled grid geometries
+ size_t numMBGrids; //!< number of enabled motion blurred grid geometries
+ size_t numPoints; //!< number of enabled points
+ size_t numMBPoints; //!< number of enabled motion blurred points
+ };
+
+ /*! Base class all geometries are derived from */
+ class Geometry : public RefCount
+ {
+ friend class Scene;
+ public:
+
+ /*! type of geometry */
+ enum GType
+ {
+ GTY_FLAT_LINEAR_CURVE = 0,
+ GTY_ROUND_LINEAR_CURVE = 1,
+ GTY_ORIENTED_LINEAR_CURVE = 2,
+ GTY_CONE_LINEAR_CURVE = 3,
+
+ GTY_FLAT_BEZIER_CURVE = 4,
+ GTY_ROUND_BEZIER_CURVE = 5,
+ GTY_ORIENTED_BEZIER_CURVE = 6,
+
+ GTY_FLAT_BSPLINE_CURVE = 8,
+ GTY_ROUND_BSPLINE_CURVE = 9,
+ GTY_ORIENTED_BSPLINE_CURVE = 10,
+
+ GTY_FLAT_HERMITE_CURVE = 12,
+ GTY_ROUND_HERMITE_CURVE = 13,
+ GTY_ORIENTED_HERMITE_CURVE = 14,
+
+ GTY_FLAT_CATMULL_ROM_CURVE = 16,
+ GTY_ROUND_CATMULL_ROM_CURVE = 17,
+ GTY_ORIENTED_CATMULL_ROM_CURVE = 18,
+
+ GTY_TRIANGLE_MESH = 20,
+ GTY_QUAD_MESH = 21,
+ GTY_GRID_MESH = 22,
+ GTY_SUBDIV_MESH = 23,
+
+ GTY_SPHERE_POINT = 25,
+ GTY_DISC_POINT = 26,
+ GTY_ORIENTED_DISC_POINT = 27,
+
+ GTY_USER_GEOMETRY = 29,
+ GTY_INSTANCE_CHEAP = 30,
+ GTY_INSTANCE_EXPENSIVE = 31,
+ GTY_END = 32,
+
+ GTY_BASIS_LINEAR = 0,
+ GTY_BASIS_BEZIER = 4,
+ GTY_BASIS_BSPLINE = 8,
+ GTY_BASIS_HERMITE = 12,
+ GTY_BASIS_CATMULL_ROM = 16,
+ GTY_BASIS_MASK = 28,
+
+ GTY_SUBTYPE_FLAT_CURVE = 0,
+ GTY_SUBTYPE_ROUND_CURVE = 1,
+ GTY_SUBTYPE_ORIENTED_CURVE = 2,
+ GTY_SUBTYPE_MASK = 3,
+ };
+
+ enum GSubType
+ {
+ GTY_SUBTYPE_DEFAULT= 0,
+ GTY_SUBTYPE_INSTANCE_LINEAR = 0,
+ GTY_SUBTYPE_INSTANCE_QUATERNION = 1
+ };
+
+ enum GTypeMask
+ {
+ MTY_FLAT_LINEAR_CURVE = 1ul << GTY_FLAT_LINEAR_CURVE,
+ MTY_ROUND_LINEAR_CURVE = 1ul << GTY_ROUND_LINEAR_CURVE,
+ MTY_CONE_LINEAR_CURVE = 1ul << GTY_CONE_LINEAR_CURVE,
+ MTY_ORIENTED_LINEAR_CURVE = 1ul << GTY_ORIENTED_LINEAR_CURVE,
+
+ MTY_FLAT_BEZIER_CURVE = 1ul << GTY_FLAT_BEZIER_CURVE,
+ MTY_ROUND_BEZIER_CURVE = 1ul << GTY_ROUND_BEZIER_CURVE,
+ MTY_ORIENTED_BEZIER_CURVE = 1ul << GTY_ORIENTED_BEZIER_CURVE,
+
+ MTY_FLAT_BSPLINE_CURVE = 1ul << GTY_FLAT_BSPLINE_CURVE,
+ MTY_ROUND_BSPLINE_CURVE = 1ul << GTY_ROUND_BSPLINE_CURVE,
+ MTY_ORIENTED_BSPLINE_CURVE = 1ul << GTY_ORIENTED_BSPLINE_CURVE,
+
+ MTY_FLAT_HERMITE_CURVE = 1ul << GTY_FLAT_HERMITE_CURVE,
+ MTY_ROUND_HERMITE_CURVE = 1ul << GTY_ROUND_HERMITE_CURVE,
+ MTY_ORIENTED_HERMITE_CURVE = 1ul << GTY_ORIENTED_HERMITE_CURVE,
+
+ MTY_FLAT_CATMULL_ROM_CURVE = 1ul << GTY_FLAT_CATMULL_ROM_CURVE,
+ MTY_ROUND_CATMULL_ROM_CURVE = 1ul << GTY_ROUND_CATMULL_ROM_CURVE,
+ MTY_ORIENTED_CATMULL_ROM_CURVE = 1ul << GTY_ORIENTED_CATMULL_ROM_CURVE,
+
+ MTY_CURVE2 = MTY_FLAT_LINEAR_CURVE | MTY_ROUND_LINEAR_CURVE | MTY_CONE_LINEAR_CURVE | MTY_ORIENTED_LINEAR_CURVE,
+
+ MTY_CURVE4 = MTY_FLAT_BEZIER_CURVE | MTY_ROUND_BEZIER_CURVE | MTY_ORIENTED_BEZIER_CURVE |
+ MTY_FLAT_BSPLINE_CURVE | MTY_ROUND_BSPLINE_CURVE | MTY_ORIENTED_BSPLINE_CURVE |
+ MTY_FLAT_HERMITE_CURVE | MTY_ROUND_HERMITE_CURVE | MTY_ORIENTED_HERMITE_CURVE |
+ MTY_FLAT_CATMULL_ROM_CURVE | MTY_ROUND_CATMULL_ROM_CURVE | MTY_ORIENTED_CATMULL_ROM_CURVE,
+
+ MTY_SPHERE_POINT = 1ul << GTY_SPHERE_POINT,
+ MTY_DISC_POINT = 1ul << GTY_DISC_POINT,
+ MTY_ORIENTED_DISC_POINT = 1ul << GTY_ORIENTED_DISC_POINT,
+
+ MTY_POINTS = MTY_SPHERE_POINT | MTY_DISC_POINT | MTY_ORIENTED_DISC_POINT,
+
+ MTY_CURVES = MTY_CURVE2 | MTY_CURVE4 | MTY_POINTS,
+
+ MTY_TRIANGLE_MESH = 1ul << GTY_TRIANGLE_MESH,
+ MTY_QUAD_MESH = 1ul << GTY_QUAD_MESH,
+ MTY_GRID_MESH = 1ul << GTY_GRID_MESH,
+ MTY_SUBDIV_MESH = 1ul << GTY_SUBDIV_MESH,
+ MTY_USER_GEOMETRY = 1ul << GTY_USER_GEOMETRY,
+
+ MTY_INSTANCE_CHEAP = 1ul << GTY_INSTANCE_CHEAP,
+ MTY_INSTANCE_EXPENSIVE = 1ul << GTY_INSTANCE_EXPENSIVE,
+ MTY_INSTANCE = MTY_INSTANCE_CHEAP | MTY_INSTANCE_EXPENSIVE
+ };
+
+ static const char* gtype_names[GTY_END];
+
+ enum class State : unsigned {
+ MODIFIED = 0,
+ COMMITTED = 1,
+ };
+
+ public:
+
+ /*! Geometry constructor */
+ Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps);
+
+ /*! Geometry destructor */
+ virtual ~Geometry();
+
+ public:
+
+ /*! tests if geometry is enabled */
+ __forceinline bool isEnabled() const { return enabled; }
+
+ /*! tests if geometry is disabled */
+ __forceinline bool isDisabled() const { return !isEnabled(); }
+
+ /*! tests if that geometry has some filter function set */
+ __forceinline bool hasFilterFunctions () const {
+ return (intersectionFilterN != nullptr) || (occlusionFilterN != nullptr);
+ }
+
+ /*! returns geometry type */
+ __forceinline GType getType() const { return gtype; }
+
+ /*! returns curve type */
+ __forceinline GType getCurveType() const { return (GType)(gtype & GTY_SUBTYPE_MASK); }
+
+ /*! returns curve basis */
+ __forceinline GType getCurveBasis() const { return (GType)(gtype & GTY_BASIS_MASK); }
+
+ /*! returns geometry type mask */
+ __forceinline GTypeMask getTypeMask() const { return (GTypeMask)(1 << gtype); }
+
+ /*! returns number of primitives */
+ __forceinline size_t size() const { return numPrimitives; }
+
+ /*! sets the number of primitives */
+ virtual void setNumPrimitives(unsigned int numPrimitives_in);
+
+ /*! sets number of time steps */
+ virtual void setNumTimeSteps (unsigned int numTimeSteps_in);
+
+ /*! sets motion blur time range */
+ void setTimeRange (const BBox1f range);
+
+ /*! sets number of vertex attributes */
+ virtual void setVertexAttributeCount (unsigned int N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! sets number of topologies */
+ virtual void setTopologyCount (unsigned int N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! sets the build quality */
+ void setBuildQuality(RTCBuildQuality quality_in)
+ {
+ this->quality = quality_in;
+ Geometry::update();
+ }
+
+ /* calculate time segment itime and fractional time ftime */
+ __forceinline int timeSegment(float time, float& ftime) const {
+ return getTimeSegment(time,time_range.lower,time_range.upper,fnumTimeSegments,ftime);
+ }
+
+ template<int N>
+ __forceinline vint<N> timeSegment(const vfloat<N>& time, vfloat<N>& ftime) const {
+ return getTimeSegment(time,vfloat<N>(time_range.lower),vfloat<N>(time_range.upper),vfloat<N>(fnumTimeSegments),ftime);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,fnumTimeSegments);
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<(int)numTimeSteps);
+ return time_range.lower + time_range.size()*float(i)/fnumTimeSegments;
+ }
+
+ /*! for all geometries */
+ public:
+
+ /*! Enable geometry. */
+ virtual void enable();
+
+ /*! Update geometry. */
+ void update();
+
+ /*! commit of geometry */
+ virtual void commit();
+
+ /*! Update geometry buffer. */
+ virtual void updateBuffer(RTCBufferType type, unsigned int slot) {
+ update(); // update everything for geometries not supporting this call
+ }
+
+ /*! Disable geometry. */
+ virtual void disable();
+
+ /*! Verify the geometry */
+ virtual bool verify() { return true; }
+
+ /*! called before every build */
+ virtual void preCommit();
+
+ /*! called after every build */
+ virtual void postCommit();
+
+ virtual void addElementsToCount (GeometryCounts & counts) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ };
+
+ /*! sets constant tessellation rate for the geometry */
+ virtual void setTessellationRate(float N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets the maximal curve radius scale allowed by min-width feature. */
+ virtual void setMaxRadiusScale(float s) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set user data pointer. */
+ virtual void setUserData(void* ptr);
+
+ /*! Get user data pointer. */
+ __forceinline void* getUserData() const {
+ return userPtr;
+ }
+
+ /*! interpolates user data to the specified u/v location */
+ virtual void interpolate(const RTCInterpolateArguments* const args) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! interpolates user data to the specified u/v locations */
+ virtual void interpolateN(const RTCInterpolateNArguments* const args);
+
+ /* point query api */
+ bool pointQuery(PointQuery* query, PointQueryContext* context);
+
+ /*! for subdivision surfaces only */
+ public:
+ virtual void setSubdivisionMode (unsigned topologyID, RTCSubdivisionMode mode) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual void setVertexAttributeTopology(unsigned int vertexBufferSlot, unsigned int indexBufferSlot) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set displacement function. */
+ virtual void setDisplacementFunction (RTCDisplacementFunctionN filter) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getFirstHalfEdge(unsigned int faceID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getFace(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getNextHalfEdge(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getPreviousHalfEdge(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! get fast access to first vertex buffer if applicable */
+ virtual float * getCompactVertexArray () const {
+ return nullptr;
+ }
+
+ /*! Returns the modified counter - how many times the geo has been modified */
+ __forceinline unsigned int getModCounter () const {
+ return modCounter_;
+ }
+
+ /*! for triangle meshes and bezier curves only */
+ public:
+
+
+ /*! Sets ray mask. */
+ virtual void setMask(unsigned mask) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets specified buffer. */
+ virtual void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Gets specified buffer. */
+ virtual void* getBuffer(RTCBufferType type, unsigned int slot) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set intersection filter function for ray packets of size N. */
+ virtual void setIntersectionFilterFunctionN (RTCFilterFunctionN filterN);
+
+ /*! Set occlusion filter function for ray packets of size N. */
+ virtual void setOcclusionFilterFunctionN (RTCFilterFunctionN filterN);
+
+ /*! for instances only */
+ public:
+
+ /*! Sets the instanced scene */
+ virtual void setInstancedScene(const Ref<Scene>& scene) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets transformation of the instance */
+ virtual void setTransform(const AffineSpace3fa& transform, unsigned int timeStep) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets transformation of the instance */
+ virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Returns the transformation of the instance */
+ virtual AffineSpace3fa getTransform(float time) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! for user geometries only */
+ public:
+
+ /*! Set bounds function. */
+ virtual void setBoundsFunction (RTCBoundsFunction bounds, void* userPtr) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set intersect function for ray packets of size N. */
+ virtual void setIntersectFunctionN (RTCIntersectFunctionN intersect) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set occlusion function for ray packets of size N. */
+ virtual void setOccludedFunctionN (RTCOccludedFunctionN occluded) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set point query function. */
+ void setPointQueryFunction(RTCPointQueryFunction func);
+
+ /*! returns number of time segments */
+ __forceinline unsigned numTimeSegments () const {
+ return numTimeSteps-1;
+ }
+
+ public:
+
+ virtual PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefArray not implemented for this geometry");
+ }
+
+ virtual PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry");
+ }
+
+ virtual PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry");
+ }
+
+ virtual LinearSpace3fa computeAlignedSpace(const size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeAlignedSpace not implemented for this geometry");
+ }
+
+ virtual LinearSpace3fa computeAlignedSpaceMB(const size_t primID, const BBox1f time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeAlignedSpace not implemented for this geometry");
+ }
+
+ virtual Vec3fa computeDirection(unsigned int primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeDirection not implemented for this geometry");
+ }
+
+ virtual Vec3fa computeDirection(unsigned int primID, size_t time) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeDirection not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(const LinearSpace3fa& space, size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ public:
+ __forceinline bool hasIntersectionFilter() const { return intersectionFilterN != nullptr; }
+ __forceinline bool hasOcclusionFilter() const { return occlusionFilterN != nullptr; }
+
+ public:
+ Device* device; //!< device this geometry belongs to
+
+ void* userPtr; //!< user pointer
+ unsigned int numPrimitives; //!< number of primitives of this geometry
+
+ unsigned int numTimeSteps; //!< number of time steps
+ float fnumTimeSegments; //!< number of time segments (precalculation)
+ BBox1f time_range; //!< motion blur time range
+
+ unsigned int mask; //!< for masking out geometry
+ unsigned int modCounter_ = 1; //!< counter for every modification - used to rebuild scenes when geo is modified
+
+ struct {
+ GType gtype : 8; //!< geometry type
+ GSubType gsubtype : 8; //!< geometry subtype
+ RTCBuildQuality quality : 3; //!< build quality for geometry
+ unsigned state : 2;
+ bool enabled : 1; //!< true if geometry is enabled
+ };
+
+ RTCFilterFunctionN intersectionFilterN;
+ RTCFilterFunctionN occlusionFilterN;
+ RTCPointQueryFunction pointQueryFunc;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/hit.h b/thirdparty/embree-aarch64/kernels/common/hit.h
new file mode 100644
index 0000000000..32a198cdfe
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/hit.h
@@ -0,0 +1,114 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "ray.h"
+#include "instance_stack.h"
+
+namespace embree
+{
+ /* Hit structure for K hits */
+ template<int K>
+ struct HitK
+ {
+ /* Default construction does nothing */
+ __forceinline HitK() {}
+
+ /* Constructs a hit */
+ __forceinline HitK(const RTCIntersectContext* context, const vuint<K>& geomID, const vuint<K>& primID, const vfloat<K>& u, const vfloat<K>& v, const Vec3vf<K>& Ng)
+ : Ng(Ng), u(u), v(v), primID(primID), geomID(geomID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ instance_id_stack::copy(context->instID, instID);
+ }
+
+ /* Returns the size of the hit */
+ static __forceinline size_t size() { return K; }
+
+ public:
+ Vec3vf<K> Ng; // geometry normal
+ vfloat<K> u; // barycentric u coordinate of hit
+ vfloat<K> v; // barycentric v coordinate of hit
+ vuint<K> primID; // primitive ID
+ vuint<K> geomID; // geometry ID
+ vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Specialization for a single hit */
+ template<>
+ struct __aligned(16) HitK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline HitK() {}
+
+ /* Constructs a hit */
+ __forceinline HitK(const RTCIntersectContext* context, unsigned int geomID, unsigned int primID, float u, float v, const Vec3fa& Ng)
+ : Ng(Ng.x,Ng.y,Ng.z), u(u), v(v), primID(primID), geomID(geomID)
+ {
+ instance_id_stack::copy(context->instID, instID);
+ }
+
+ /* Returns the size of the hit */
+ static __forceinline size_t size() { return 1; }
+
+ public:
+ Vec3<float> Ng; // geometry normal
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Shortcuts */
+ typedef HitK<1> Hit;
+ typedef HitK<4> Hit4;
+ typedef HitK<8> Hit8;
+ typedef HitK<16> Hit16;
+
+ /* Outputs hit to stream */
+ template<int K>
+ __forceinline embree_ostream operator<<(embree_ostream cout, const HitK<K>& ray)
+ {
+ cout << "{ " << embree_endl
+ << " Ng = " << ray.Ng << embree_endl
+ << " u = " << ray.u << embree_endl
+ << " v = " << ray.v << embree_endl
+ << " primID = " << ray.primID << embree_endl
+ << " geomID = " << ray.geomID << embree_endl
+ << " instID =";
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ {
+ cout << " " << ray.instID[l];
+ }
+ cout << embree_endl;
+ return cout << "}";
+ }
+
+ template<typename Hit>
+ __forceinline void copyHitToRay(RayHit& ray, const Hit& hit)
+ {
+ ray.Ng = hit.Ng;
+ ray.u = hit.u;
+ ray.v = hit.v;
+ ray.primID = hit.primID;
+ ray.geomID = hit.geomID;
+ instance_id_stack::copy(hit.instID, ray.instID);
+ }
+
+ template<int K>
+ __forceinline void copyHitToRay(const vbool<K> &mask, RayHitK<K> &ray, const HitK<K> &hit)
+ {
+ vfloat<K>::storeu(mask,&ray.Ng.x, hit.Ng.x);
+ vfloat<K>::storeu(mask,&ray.Ng.y, hit.Ng.y);
+ vfloat<K>::storeu(mask,&ray.Ng.z, hit.Ng.z);
+ vfloat<K>::storeu(mask,&ray.u, hit.u);
+ vfloat<K>::storeu(mask,&ray.v, hit.v);
+ vuint<K>::storeu(mask,&ray.primID, hit.primID);
+ vuint<K>::storeu(mask,&ray.geomID, hit.geomID);
+ instance_id_stack::copy(hit.instID, ray.instID, mask);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/instance_stack.h b/thirdparty/embree-aarch64/kernels/common/instance_stack.h
new file mode 100644
index 0000000000..d7e3637f7b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/instance_stack.h
@@ -0,0 +1,199 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore.h"
+
+namespace embree {
+namespace instance_id_stack {
+
+static_assert(RTC_MAX_INSTANCE_LEVEL_COUNT > 0,
+ "RTC_MAX_INSTANCE_LEVEL_COUNT must be greater than 0.");
+
+/*******************************************************************************
+ * Instance ID stack manipulation.
+ * This is used from the instance intersector.
+ ******************************************************************************/
+
+/*
+ * Push an instance to the stack.
+ */
+RTC_FORCEINLINE bool push(RTCIntersectContext* context,
+ unsigned instanceId)
+{
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ const bool spaceAvailable = context->instStackSize < RTC_MAX_INSTANCE_LEVEL_COUNT;
+ /* We assert here because instances are silently dropped when the stack is full.
+ This might be quite hard to find in production. */
+ assert(spaceAvailable);
+ if (likely(spaceAvailable))
+ context->instID[context->instStackSize++] = instanceId;
+ return spaceAvailable;
+#else
+ const bool spaceAvailable = (context->instID[0] == RTC_INVALID_GEOMETRY_ID);
+ assert(spaceAvailable);
+ if (likely(spaceAvailable))
+ context->instID[0] = instanceId;
+ return spaceAvailable;
+#endif
+}
+
+
+/*
+ * Pop the last instance pushed to the stack.
+ * Do not call on an empty stack.
+ */
+RTC_FORCEINLINE void pop(RTCIntersectContext* context)
+{
+ assert(context);
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ assert(context->instStackSize > 0);
+ context->instID[--context->instStackSize] = RTC_INVALID_GEOMETRY_ID;
+#else
+ assert(context->instID[0] != RTC_INVALID_GEOMETRY_ID);
+ context->instID[0] = RTC_INVALID_GEOMETRY_ID;
+#endif
+}
+
+/*******************************************************************************
+ * Optimized instance id stack copy.
+ * The copy() function at the bottom of this block will either copy full
+ * stacks or copy only until the last valid element has been copied, depending
+ * on RTC_MAX_INSTANCE_LEVEL_COUNT.
+ ******************************************************************************/
+
+/*
+ * Plain array assignment. This works for scalar->scalar,
+ * scalar->vector, and vector->vector.
+ */
+template <class Src, class Tgt>
+RTC_FORCEINLINE void level_copy(unsigned level, Src* src, Tgt* tgt)
+{
+ tgt[level] = src[level];
+}
+
+/*
+ * Masked SIMD vector->vector store.
+ */
+template <int K>
+RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, vuint<K>* tgt, const vbool<K>& mask)
+{
+ vuint<K>::storeu(mask, tgt + level, src[level]);
+}
+
+/*
+ * Masked scalar->SIMD vector store.
+ */
+template <int K>
+RTC_FORCEINLINE void level_copy(unsigned level, const unsigned* src, vuint<K>* tgt, const vbool<K>& mask)
+{
+ vuint<K>::store(mask, tgt + level, src[level]);
+}
+
+/*
+ * Indexed assign from vector to scalar.
+ */
+template <int K>
+RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, unsigned* tgt, const size_t& idx)
+{
+ tgt[level] = src[level][idx];
+}
+
+/*
+ * Indexed assign from scalar to vector.
+ */
+template <int K>
+RTC_FORCEINLINE void level_copy(unsigned level, const unsigned* src, vuint<K>* tgt, const size_t& idx)
+{
+ tgt[level][idx] = src[level];
+}
+
+/*
+ * Indexed assign from vector to vector.
+ */
+template <int K>
+RTC_FORCEINLINE void level_copy(unsigned level, const vuint<K>* src, vuint<K>* tgt, const size_t& i, const size_t& j)
+{
+ tgt[level][j] = src[level][i];
+}
+
+/*
+ * Check if the given stack level is valid.
+ * These are only used for large max stack sizes.
+ */
+RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack)
+{
+ return stack[level] != RTC_INVALID_GEOMETRY_ID;
+}
+RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack, const size_t& /*i*/)
+{
+ return stack[level] != RTC_INVALID_GEOMETRY_ID;
+}
+template <int K>
+RTC_FORCEINLINE bool level_valid(unsigned level, const unsigned* stack, const vbool<K>& /*mask*/)
+{
+ return stack[level] != RTC_INVALID_GEOMETRY_ID;
+}
+
+template <int K>
+RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack)
+{
+ return any(stack[level] != RTC_INVALID_GEOMETRY_ID);
+}
+template <int K>
+RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const vbool<K>& mask)
+{
+ return any(mask & (stack[level] != RTC_INVALID_GEOMETRY_ID));
+}
+
+template <int K>
+RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const size_t& i)
+{
+ return stack[level][i] != RTC_INVALID_GEOMETRY_ID;
+}
+template <int K>
+RTC_FORCEINLINE bool level_valid(unsigned level, const vuint<K>* stack, const size_t& i, const size_t& /*j*/)
+{
+ return stack[level][i] != RTC_INVALID_GEOMETRY_ID;
+}
+
+/*
+ * Copy an instance ID stack.
+ *
+ * This function automatically selects a LevelFunctor from the above Assign
+ * structs.
+ */
+template <class Src, class Tgt, class... Args>
+RTC_FORCEINLINE void copy(Src src, Tgt tgt, Args&&... args)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ /*
+ * Avoid all loops for only one level.
+ */
+ level_copy(0, src, tgt, std::forward<Args>(args)...);
+
+#elif (RTC_MAX_INSTANCE_LEVEL_COUNT <= 4)
+ /*
+ * It is faster to avoid the valid test for low level counts.
+ * Just copy the whole stack.
+ */
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ level_copy(l, src, tgt, std::forward<Args>(args)...);
+
+#else
+ /*
+ * For general stack sizes, it pays off to test for validity.
+ */
+ bool valid = true;
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT && valid; ++l)
+ {
+ level_copy(l, src, tgt, std::forward<Args>(args)...);
+ valid = level_valid(l, src, std::forward<Args>(args)...);
+ }
+#endif
+}
+
+} // namespace instance_id_stack
+} // namespace embree
+
diff --git a/thirdparty/embree-aarch64/kernels/common/isa.h b/thirdparty/embree-aarch64/kernels/common/isa.h
new file mode 100644
index 0000000000..63fb8d3351
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/isa.h
@@ -0,0 +1,271 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/sys/platform.h"
+#include "../../common/sys/sysinfo.h"
+
+namespace embree
+{
+#define DEFINE_SYMBOL2(type,name) \
+ typedef type (*name##Func)(); \
+ name##Func name;
+
+#define DECLARE_SYMBOL2(type,name) \
+ namespace sse2 { extern type name(); } \
+ namespace sse42 { extern type name(); } \
+ namespace avx { extern type name(); } \
+ namespace avx2 { extern type name(); } \
+ namespace avx512knl { extern type name(); } \
+ namespace avx512skx { extern type name(); } \
+ void name##_error2() { throw_RTCError(RTC_ERROR_UNKNOWN,"internal error in ISA selection for " TOSTRING(name)); } \
+ type name##_error() { return type(name##_error2); } \
+ type name##_zero() { return type(nullptr); }
+
+#define DECLARE_ISA_FUNCTION(type,symbol,args) \
+ namespace sse2 { extern type symbol(args); } \
+ namespace sse42 { extern type symbol(args); } \
+ namespace avx { extern type symbol(args); } \
+ namespace avx2 { extern type symbol(args); } \
+ namespace avx512knl { extern type symbol(args); } \
+ namespace avx512skx { extern type symbol(args); } \
+ inline type symbol##_error(args) { throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"function " TOSTRING(symbol) " not supported by your CPU"); } \
+ typedef type (*symbol##Ty)(args); \
+
+#define DEFINE_ISA_FUNCTION(type,symbol,args) \
+ typedef type (*symbol##Func)(args); \
+ symbol##Func symbol;
+
+#define ZERO_SYMBOL(features,intersector) \
+ intersector = intersector##_zero;
+
+#define INIT_SYMBOL(features,intersector) \
+ intersector = decltype(intersector)(intersector##_error);
+
+#define SELECT_SYMBOL_DEFAULT(features,intersector) \
+ intersector = isa::intersector;
+
+#if defined(__SSE__) || defined(__ARM_NEON)
+#if !defined(EMBREE_TARGET_SIMD4)
+#define EMBREE_TARGET_SIMD4
+#endif
+#endif
+
+#if defined(EMBREE_TARGET_SSE42)
+#define SELECT_SYMBOL_SSE42(features,intersector) \
+ if ((features & SSE42) == SSE42) intersector = sse42::intersector;
+#else
+#define SELECT_SYMBOL_SSE42(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX) || defined(__AVX__)
+#if !defined(EMBREE_TARGET_SIMD8)
+#define EMBREE_TARGET_SIMD8
+#endif
+#if defined(__AVX__) // if default ISA is >= AVX we treat AVX target as default target
+#define SELECT_SYMBOL_AVX(features,intersector) \
+ if ((features & ISA) == ISA) intersector = isa::intersector;
+#else
+#define SELECT_SYMBOL_AVX(features,intersector) \
+ if ((features & AVX) == AVX) intersector = avx::intersector;
+#endif
+#else
+#define SELECT_SYMBOL_AVX(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX2)
+#if !defined(EMBREE_TARGET_SIMD8)
+#define EMBREE_TARGET_SIMD8
+#endif
+#define SELECT_SYMBOL_AVX2(features,intersector) \
+ if ((features & AVX2) == AVX2) intersector = avx2::intersector;
+#else
+#define SELECT_SYMBOL_AVX2(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX512KNL)
+#if !defined(EMBREE_TARGET_SIMD16)
+#define EMBREE_TARGET_SIMD16
+#endif
+#define SELECT_SYMBOL_AVX512KNL(features,intersector) \
+ if ((features & AVX512KNL) == AVX512KNL) intersector = avx512knl::intersector;
+#else
+#define SELECT_SYMBOL_AVX512KNL(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX512SKX)
+#if !defined(EMBREE_TARGET_SIMD16)
+#define EMBREE_TARGET_SIMD16
+#endif
+#define SELECT_SYMBOL_AVX512SKX(features,intersector) \
+ if ((features & AVX512SKX) == AVX512SKX) intersector = avx512skx::intersector;
+#else
+#define SELECT_SYMBOL_AVX512SKX(features,intersector)
+#endif
+
+#define SELECT_SYMBOL_DEFAULT_SSE42(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2_AVX512SKX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_SSE42_AVX_AVX2(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX512KNL(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX512KNL_AVX512SKX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_ZERO_SSE42_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ ZERO_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX512KNL_AVX512SKX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX512KNL(features,intersector); \
+ SELECT_SYMBOL_AVX512SKX(features,intersector);
+
+#define SELECT_SYMBOL_SSE42_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+ struct VerifyMultiTargetLinking {
+ static __noinline int getISA(int depth = 5) {
+ if (depth == 0) return ISA;
+ else return getISA(depth-1);
+ }
+ };
+ namespace sse2 { int getISA(); };
+ namespace sse42 { int getISA(); };
+ namespace avx { int getISA(); };
+ namespace avx2 { int getISA(); };
+ namespace avx512knl { int getISA(); };
+ namespace avx512skx { int getISA(); };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/motion_derivative.h b/thirdparty/embree-aarch64/kernels/common/motion_derivative.h
new file mode 100644
index 0000000000..82953f0e89
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/motion_derivative.h
@@ -0,0 +1,325 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/math/affinespace.h"
+#include "../../common/math/interval.h"
+
+#include <functional>
+
+namespace embree {
+
+#define MOTION_DERIVATIVE_ROOT_EPSILON 1e-4f
+
+static void motion_derivative_coefficients(const float *p, float *coeff);
+
+struct MotionDerivativeCoefficients
+{
+ float theta;
+ float coeffs[3*8*7];
+
+ MotionDerivativeCoefficients() {}
+
+ // xfm0 and xfm1 are interpret as quaternion decomposition
+ MotionDerivativeCoefficients(AffineSpace3ff const& xfm0, AffineSpace3ff const& xfm1)
+ {
+ // cosTheta of the two quaternions
+ const float cosTheta = min(1.f, max(-1.f,
+ xfm0.l.vx.w * xfm1.l.vx.w
+ + xfm0.l.vy.w * xfm1.l.vy.w
+ + xfm0.l.vz.w * xfm1.l.vz.w
+ + xfm0.p.w * xfm1.p.w));
+
+ theta = std::acos(cosTheta);
+ Vec4f qperp(xfm1.p.w, xfm1.l.vx.w, xfm1.l.vy.w, xfm1.l.vz.w);
+ if (cosTheta < 0.995f) {
+ // compute perpendicular quaternion
+ qperp.x = xfm1.p.w - cosTheta * xfm0.p.w;
+ qperp.y = xfm1.l.vx.w - cosTheta * xfm0.l.vx.w;
+ qperp.z = xfm1.l.vy.w - cosTheta * xfm0.l.vy.w;
+ qperp.w = xfm1.l.vz.w - cosTheta * xfm0.l.vz.w;
+ qperp = normalize(qperp);
+ }
+ const float p[33] = {
+ theta,
+ xfm0.l.vx.y, xfm0.l.vx.z, xfm0.l.vy.z, // translation component of xfm0
+ xfm1.l.vx.y, xfm1.l.vx.z, xfm1.l.vy.z, // translation component of xfm1
+ xfm0.p.w, xfm0.l.vx.w, xfm0.l.vy.w, xfm0.l.vz.w, // quaternion of xfm0
+ qperp.x, qperp.y, qperp.z, qperp.w,
+ xfm0.l.vx.x, xfm0.l.vy.x, xfm0.l.vz.x, xfm0.p.x, // scale/skew component of xfm0
+ xfm0.l.vy.y, xfm0.l.vz.y, xfm0.p.y,
+ xfm0.l.vz.z, xfm0.p.z,
+ xfm1.l.vx.x, xfm1.l.vy.x, xfm1.l.vz.x, xfm1.p.x, // scale/skew component of xfm1
+ xfm1.l.vy.y, xfm1.l.vz.y, xfm1.p.y,
+ xfm1.l.vz.z, xfm1.p.z
+ };
+ motion_derivative_coefficients(p, coeffs);
+ }
+};
+
+struct MotionDerivative
+{
+ float twoTheta;
+ float c[8];
+
+ MotionDerivative(MotionDerivativeCoefficients const& mdc,
+ int dim, Vec3fa const& p0, Vec3fa const& p1)
+ : twoTheta(2.f*mdc.theta)
+ {
+ const float p[7] = { 1, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z };
+ for (int i = 0; i < 8; ++i) {
+ c[i] = 0;
+ for (int j = 0; j < 7; ++j) {
+ c[i] += mdc.coeffs[8*7*dim + i*7 + j] * p[j];
+ }
+ }
+ }
+
+ template<typename T>
+ struct EvalMotionDerivative
+ {
+ MotionDerivative const& md;
+ float offset;
+
+ EvalMotionDerivative(MotionDerivative const& md, float offset) : md(md), offset(offset) {}
+
+ T operator()(T const& time) const {
+ return md.c[0] + md.c[1] * time
+ + (md.c[2] + md.c[3] * time + md.c[4] * time * time) * cos(md.twoTheta * time)
+ + (md.c[5] + md.c[6] * time + md.c[7] * time * time) * sin(md.twoTheta * time)
+ + offset;
+ }
+ };
+
+ unsigned int findRoots(
+ Interval1f const& interval,
+ float offset,
+ float* roots,
+ unsigned int maxNumRoots)
+ {
+ unsigned int numRoots = 0;
+ EvalMotionDerivative<Interval1f> eval(*this, offset);
+ findRoots(eval, interval, numRoots, roots, maxNumRoots);
+ return numRoots;
+ }
+
+ template<typename Eval>
+ static void findRoots(
+
+ Eval const& eval,
+ Interval1f const& interval,
+ unsigned int& numRoots,
+ float* roots,
+ unsigned int maxNumRoots)
+ {
+ Interval1f range = eval(interval);
+ if (range.lower > 0 || range.upper < 0 || range.lower >= range.upper) return;
+
+ const float split = 0.5f * (interval.upper + interval.lower);
+ if (interval.upper-interval.lower < 1e-7f || abs(split-interval.lower) < 1e-7f || abs(split-interval.upper) < 1e-7f)
+ {
+ // check if the root already exists
+ for (unsigned int k = 0; k < numRoots && k < maxNumRoots; ++k) {
+ if (abs(roots[k]-split) < MOTION_DERIVATIVE_ROOT_EPSILON)
+ return;
+ }
+ if (numRoots < maxNumRoots) {
+ roots[numRoots++] = split;
+ }
+ if (numRoots > maxNumRoots) {
+ printf("error: more roots than expected\n"); // FIXME: workaround for ICC2019.4 compiler bug under macOS
+ return;
+ }
+ return;
+ }
+
+ findRoots(eval, Interval1f(interval.lower, split), numRoots, roots, maxNumRoots);
+ findRoots(eval, Interval1f(split, interval.upper), numRoots, roots, maxNumRoots);
+ }
+};
+
+/******************************************************************************
+ * Code generated with sympy 1.4 *
+ * See http://www.sympy.org/ for more information. *
+ * *
+ * see *
+ * *
+ * scripts/generate_motion_derivative_coefficients.py *
+ * *
+ * for how this code is generated *
+ * *
+ ******************************************************************************/
+static void motion_derivative_coefficients(const float *p, float *coeff)
+{
+ coeff[0] = -p[1] + p[4] - p[7]*p[9]*p[23] + p[7]*p[9]*p[32] + p[7]*p[10]*p[21] - p[7]*p[10]*p[30] - p[8]*p[9]*p[21] + p[8]*p[9]*p[30] - p[8]*p[10]*p[23] + p[8]*p[10]*p[32] + p[9]*p[9]*p[18] - p[9]*p[9]*p[27] + p[10]*p[10]*p[18] - p[10]*p[10]*p[27] - p[11]*p[13]*p[23] + p[11]*p[13]*p[32] + p[11]*p[14]*p[21] - p[11]*p[14]*p[30] - p[12]*p[13]*p[21] + p[12]*p[13]*p[30] - p[12]*p[14]*p[23] + p[12]*p[14]*p[32] + p[13]*p[13]*p[18] - p[13]*p[13]*p[27] + p[14]*p[14]*p[18] - p[14]*p[14]*p[27] - p[18] + p[27];
+ coeff[1] = 2*p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - p[14]*p[14]*p[24] - 2*p[15] + p[24];
+ coeff[2] = 2*p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - p[14]*p[14]*p[25] - 2*p[16] + p[25];
+ coeff[3] = -2*p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - p[14]*p[14]*p[26] - 2*p[17] + p[26];
+ coeff[4] = (-p[9]*p[9] - p[10]*p[10] - p[13]*p[13] - p[14]*p[14] + 1)*p[15];
+ coeff[5] = -p[7]*p[10]*p[19] + p[8]*p[9]*p[19] - p[9]*p[9]*p[16] - p[10]*p[10]*p[16] - p[11]*p[14]*p[19] + p[12]*p[13]*p[19] - p[13]*p[13]*p[16] - p[14]*p[14]*p[16] + p[16];
+ coeff[6] = p[7]*p[9]*p[22] - p[7]*p[10]*p[20] + p[8]*p[9]*p[20] + p[8]*p[10]*p[22] - p[9]*p[9]*p[17] - p[10]*p[10]*p[17] + p[11]*p[13]*p[22] - p[11]*p[14]*p[20] + p[12]*p[13]*p[20] + p[12]*p[14]*p[22] - p[13]*p[13]*p[17] - p[14]*p[14]*p[17] + p[17];
+ coeff[7] = 0;
+ coeff[8] = -2*p[9]*p[9]*p[15] + 2*p[9]*p[9]*p[24] - 2*p[10]*p[10]*p[15] + 2*p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + 2*p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + 2*p[14]*p[14]*p[24] + 2*p[15] - 2*p[24];
+ coeff[9] = -2*p[7]*p[10]*p[19] + 2*p[7]*p[10]*p[28] + 2*p[8]*p[9]*p[19] - 2*p[8]*p[9]*p[28] - 2*p[9]*p[9]*p[16] + 2*p[9]*p[9]*p[25] - 2*p[10]*p[10]*p[16] + 2*p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + 2*p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - 2*p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + 2*p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + 2*p[14]*p[14]*p[25] + 2*p[16] - 2*p[25];
+ coeff[10] = 2*p[7]*p[9]*p[22] - 2*p[7]*p[9]*p[31] - 2*p[7]*p[10]*p[20] + 2*p[7]*p[10]*p[29] + 2*p[8]*p[9]*p[20] - 2*p[8]*p[9]*p[29] + 2*p[8]*p[10]*p[22] - 2*p[8]*p[10]*p[31] - 2*p[9]*p[9]*p[17] + 2*p[9]*p[9]*p[26] - 2*p[10]*p[10]*p[17] + 2*p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - 2*p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + 2*p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - 2*p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - 2*p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + 2*p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + 2*p[14]*p[14]*p[26] + 2*p[17] - 2*p[26];
+ coeff[11] = 2*p[9]*p[9]*p[15] - 2*p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - 2*p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - 2*p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - 2*p[14]*p[14]*p[24] - 2*p[15] + 2*p[24];
+ coeff[12] = 2*p[7]*p[10]*p[19] - 2*p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + 2*p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - 2*p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - 2*p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - 2*p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + 2*p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - 2*p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - 2*p[14]*p[14]*p[25] - 2*p[16] + 2*p[25];
+ coeff[13] = -2*p[7]*p[9]*p[22] + 2*p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - 2*p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + 2*p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + 2*p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - 2*p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - 2*p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + 2*p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - 2*p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + 2*p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + 2*p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - 2*p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - 2*p[14]*p[14]*p[26] - 2*p[17] + 2*p[26];
+ coeff[14] = 2*p[0]*p[7]*p[11]*p[18] + 2*p[0]*p[7]*p[13]*p[23] - 2*p[0]*p[7]*p[14]*p[21] + 2*p[0]*p[8]*p[12]*p[18] + 2*p[0]*p[8]*p[13]*p[21] + 2*p[0]*p[8]*p[14]*p[23] + 2*p[0]*p[9]*p[11]*p[23] + 2*p[0]*p[9]*p[12]*p[21] - 2*p[0]*p[9]*p[13]*p[18] - 2*p[0]*p[10]*p[11]*p[21] + 2*p[0]*p[10]*p[12]*p[23] - 2*p[0]*p[10]*p[14]*p[18] - p[7]*p[9]*p[23] + p[7]*p[9]*p[32] + p[7]*p[10]*p[21] - p[7]*p[10]*p[30] - p[8]*p[9]*p[21] + p[8]*p[9]*p[30] - p[8]*p[10]*p[23] + p[8]*p[10]*p[32] + p[9]*p[9]*p[18] - p[9]*p[9]*p[27] + p[10]*p[10]*p[18] - p[10]*p[10]*p[27] + p[11]*p[13]*p[23] - p[11]*p[13]*p[32] - p[11]*p[14]*p[21] + p[11]*p[14]*p[30] + p[12]*p[13]*p[21] - p[12]*p[13]*p[30] + p[12]*p[14]*p[23] - p[12]*p[14]*p[32] - p[13]*p[13]*p[18] + p[13]*p[13]*p[27] - p[14]*p[14]*p[18] + p[14]*p[14]*p[27];
+ coeff[15] = 2*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[8]*p[12]*p[15] - 2*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[10]*p[14]*p[15] + 2*p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + p[14]*p[14]*p[24];
+ coeff[16] = 2*p[0]*p[7]*p[11]*p[16] - 2*p[0]*p[7]*p[14]*p[19] + 2*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[9]*p[12]*p[19] - 2*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[14]*p[16] + 2*p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + p[14]*p[14]*p[25];
+ coeff[17] = 2*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[13]*p[22] - 2*p[0]*p[7]*p[14]*p[20] + 2*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[12]*p[20] - 2*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[10]*p[11]*p[20] + 2*p[0]*p[10]*p[12]*p[22] - 2*p[0]*p[10]*p[14]*p[17] - 2*p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + p[14]*p[14]*p[26];
+ coeff[18] = (-p[9]*p[9] - p[10]*p[10] + p[13]*p[13] + p[14]*p[14])*p[15];
+ coeff[19] = -p[7]*p[10]*p[19] + p[8]*p[9]*p[19] - p[9]*p[9]*p[16] - p[10]*p[10]*p[16] + p[11]*p[14]*p[19] - p[12]*p[13]*p[19] + p[13]*p[13]*p[16] + p[14]*p[14]*p[16];
+ coeff[20] = p[7]*p[9]*p[22] - p[7]*p[10]*p[20] + p[8]*p[9]*p[20] + p[8]*p[10]*p[22] - p[9]*p[9]*p[17] - p[10]*p[10]*p[17] - p[11]*p[13]*p[22] + p[11]*p[14]*p[20] - p[12]*p[13]*p[20] - p[12]*p[14]*p[22] + p[13]*p[13]*p[17] + p[14]*p[14]*p[17];
+ coeff[21] = 2*(-p[7]*p[11]*p[18] + p[7]*p[11]*p[27] - p[7]*p[13]*p[23] + p[7]*p[13]*p[32] + p[7]*p[14]*p[21] - p[7]*p[14]*p[30] - p[8]*p[12]*p[18] + p[8]*p[12]*p[27] - p[8]*p[13]*p[21] + p[8]*p[13]*p[30] - p[8]*p[14]*p[23] + p[8]*p[14]*p[32] - p[9]*p[11]*p[23] + p[9]*p[11]*p[32] - p[9]*p[12]*p[21] + p[9]*p[12]*p[30] + p[9]*p[13]*p[18] - p[9]*p[13]*p[27] + p[10]*p[11]*p[21] - p[10]*p[11]*p[30] - p[10]*p[12]*p[23] + p[10]*p[12]*p[32] + p[10]*p[14]*p[18] - p[10]*p[14]*p[27])*p[0];
+ coeff[22] = -4*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[7]*p[11]*p[24] - 4*p[0]*p[8]*p[12]*p[15] + 2*p[0]*p[8]*p[12]*p[24] + 4*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[9]*p[13]*p[24] + 4*p[0]*p[10]*p[14]*p[15] - 2*p[0]*p[10]*p[14]*p[24] - 2*p[9]*p[9]*p[15] + 2*p[9]*p[9]*p[24] - 2*p[10]*p[10]*p[15] + 2*p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - 2*p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - 2*p[14]*p[14]*p[24];
+ coeff[23] = -4*p[0]*p[7]*p[11]*p[16] + 2*p[0]*p[7]*p[11]*p[25] + 4*p[0]*p[7]*p[14]*p[19] - 2*p[0]*p[7]*p[14]*p[28] - 4*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[12]*p[25] - 4*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[8]*p[13]*p[28] - 4*p[0]*p[9]*p[12]*p[19] + 2*p[0]*p[9]*p[12]*p[28] + 4*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[9]*p[13]*p[25] + 4*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[11]*p[28] + 4*p[0]*p[10]*p[14]*p[16] - 2*p[0]*p[10]*p[14]*p[25] - 2*p[7]*p[10]*p[19] + 2*p[7]*p[10]*p[28] + 2*p[8]*p[9]*p[19] - 2*p[8]*p[9]*p[28] - 2*p[9]*p[9]*p[16] + 2*p[9]*p[9]*p[25] - 2*p[10]*p[10]*p[16] + 2*p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - 2*p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + 2*p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - 2*p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - 2*p[14]*p[14]*p[25];
+ coeff[24] = -4*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[11]*p[26] - 4*p[0]*p[7]*p[13]*p[22] + 2*p[0]*p[7]*p[13]*p[31] + 4*p[0]*p[7]*p[14]*p[20] - 2*p[0]*p[7]*p[14]*p[29] - 4*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[12]*p[26] - 4*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[13]*p[29] - 4*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[8]*p[14]*p[31] - 4*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[11]*p[31] - 4*p[0]*p[9]*p[12]*p[20] + 2*p[0]*p[9]*p[12]*p[29] + 4*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[9]*p[13]*p[26] + 4*p[0]*p[10]*p[11]*p[20] - 2*p[0]*p[10]*p[11]*p[29] - 4*p[0]*p[10]*p[12]*p[22] + 2*p[0]*p[10]*p[12]*p[31] + 4*p[0]*p[10]*p[14]*p[17] - 2*p[0]*p[10]*p[14]*p[26] + 2*p[7]*p[9]*p[22] - 2*p[7]*p[9]*p[31] - 2*p[7]*p[10]*p[20] + 2*p[7]*p[10]*p[29] + 2*p[8]*p[9]*p[20] - 2*p[8]*p[9]*p[29] + 2*p[8]*p[10]*p[22] - 2*p[8]*p[10]*p[31] - 2*p[9]*p[9]*p[17] + 2*p[9]*p[9]*p[26] - 2*p[10]*p[10]*p[17] + 2*p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + 2*p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - 2*p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + 2*p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + 2*p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - 2*p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - 2*p[14]*p[14]*p[26];
+ coeff[25] = 2*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[8]*p[12]*p[15] - 2*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[10]*p[14]*p[15] + 2*p[9]*p[9]*p[15] - 2*p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - 2*p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + 2*p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + 2*p[14]*p[14]*p[24];
+ coeff[26] = 2*p[0]*p[7]*p[11]*p[16] - 2*p[0]*p[7]*p[14]*p[19] + 2*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[9]*p[12]*p[19] - 2*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[14]*p[16] + 2*p[7]*p[10]*p[19] - 2*p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + 2*p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - 2*p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - 2*p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + 2*p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - 2*p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + 2*p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + 2*p[14]*p[14]*p[25];
+ coeff[27] = 2*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[13]*p[22] - 2*p[0]*p[7]*p[14]*p[20] + 2*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[12]*p[20] - 2*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[10]*p[11]*p[20] + 2*p[0]*p[10]*p[12]*p[22] - 2*p[0]*p[10]*p[14]*p[17] - 2*p[7]*p[9]*p[22] + 2*p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - 2*p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + 2*p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + 2*p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - 2*p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - 2*p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - 2*p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + 2*p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - 2*p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - 2*p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + 2*p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + 2*p[14]*p[14]*p[26];
+ coeff[28] = 0;
+ coeff[29] = 2*(p[7]*p[11]*p[15] - p[7]*p[11]*p[24] + p[8]*p[12]*p[15] - p[8]*p[12]*p[24] - p[9]*p[13]*p[15] + p[9]*p[13]*p[24] - p[10]*p[14]*p[15] + p[10]*p[14]*p[24])*p[0];
+ coeff[30] = 2*(p[7]*p[11]*p[16] - p[7]*p[11]*p[25] - p[7]*p[14]*p[19] + p[7]*p[14]*p[28] + p[8]*p[12]*p[16] - p[8]*p[12]*p[25] + p[8]*p[13]*p[19] - p[8]*p[13]*p[28] + p[9]*p[12]*p[19] - p[9]*p[12]*p[28] - p[9]*p[13]*p[16] + p[9]*p[13]*p[25] - p[10]*p[11]*p[19] + p[10]*p[11]*p[28] - p[10]*p[14]*p[16] + p[10]*p[14]*p[25])*p[0];
+ coeff[31] = 2*(p[7]*p[11]*p[17] - p[7]*p[11]*p[26] + p[7]*p[13]*p[22] - p[7]*p[13]*p[31] - p[7]*p[14]*p[20] + p[7]*p[14]*p[29] + p[8]*p[12]*p[17] - p[8]*p[12]*p[26] + p[8]*p[13]*p[20] - p[8]*p[13]*p[29] + p[8]*p[14]*p[22] - p[8]*p[14]*p[31] + p[9]*p[11]*p[22] - p[9]*p[11]*p[31] + p[9]*p[12]*p[20] - p[9]*p[12]*p[29] - p[9]*p[13]*p[17] + p[9]*p[13]*p[26] - p[10]*p[11]*p[20] + p[10]*p[11]*p[29] + p[10]*p[12]*p[22] - p[10]*p[12]*p[31] - p[10]*p[14]*p[17] + p[10]*p[14]*p[26])*p[0];
+ coeff[32] = 2*(-p[7]*p[11]*p[15] + p[7]*p[11]*p[24] - p[8]*p[12]*p[15] + p[8]*p[12]*p[24] + p[9]*p[13]*p[15] - p[9]*p[13]*p[24] + p[10]*p[14]*p[15] - p[10]*p[14]*p[24])*p[0];
+ coeff[33] = 2*(-p[7]*p[11]*p[16] + p[7]*p[11]*p[25] + p[7]*p[14]*p[19] - p[7]*p[14]*p[28] - p[8]*p[12]*p[16] + p[8]*p[12]*p[25] - p[8]*p[13]*p[19] + p[8]*p[13]*p[28] - p[9]*p[12]*p[19] + p[9]*p[12]*p[28] + p[9]*p[13]*p[16] - p[9]*p[13]*p[25] + p[10]*p[11]*p[19] - p[10]*p[11]*p[28] + p[10]*p[14]*p[16] - p[10]*p[14]*p[25])*p[0];
+ coeff[34] = 2*(-p[7]*p[11]*p[17] + p[7]*p[11]*p[26] - p[7]*p[13]*p[22] + p[7]*p[13]*p[31] + p[7]*p[14]*p[20] - p[7]*p[14]*p[29] - p[8]*p[12]*p[17] + p[8]*p[12]*p[26] - p[8]*p[13]*p[20] + p[8]*p[13]*p[29] - p[8]*p[14]*p[22] + p[8]*p[14]*p[31] - p[9]*p[11]*p[22] + p[9]*p[11]*p[31] - p[9]*p[12]*p[20] + p[9]*p[12]*p[29] + p[9]*p[13]*p[17] - p[9]*p[13]*p[26] + p[10]*p[11]*p[20] - p[10]*p[11]*p[29] - p[10]*p[12]*p[22] + p[10]*p[12]*p[31] + p[10]*p[14]*p[17] - p[10]*p[14]*p[26])*p[0];
+ coeff[35] = -2*p[0]*p[7]*p[9]*p[23] + 2*p[0]*p[7]*p[10]*p[21] - 2*p[0]*p[8]*p[9]*p[21] - 2*p[0]*p[8]*p[10]*p[23] + 2*p[0]*p[9]*p[9]*p[18] + 2*p[0]*p[10]*p[10]*p[18] + 2*p[0]*p[11]*p[13]*p[23] - 2*p[0]*p[11]*p[14]*p[21] + 2*p[0]*p[12]*p[13]*p[21] + 2*p[0]*p[12]*p[14]*p[23] - 2*p[0]*p[13]*p[13]*p[18] - 2*p[0]*p[14]*p[14]*p[18] - p[7]*p[11]*p[18] + p[7]*p[11]*p[27] - p[7]*p[13]*p[23] + p[7]*p[13]*p[32] + p[7]*p[14]*p[21] - p[7]*p[14]*p[30] - p[8]*p[12]*p[18] + p[8]*p[12]*p[27] - p[8]*p[13]*p[21] + p[8]*p[13]*p[30] - p[8]*p[14]*p[23] + p[8]*p[14]*p[32] - p[9]*p[11]*p[23] + p[9]*p[11]*p[32] - p[9]*p[12]*p[21] + p[9]*p[12]*p[30] + p[9]*p[13]*p[18] - p[9]*p[13]*p[27] + p[10]*p[11]*p[21] - p[10]*p[11]*p[30] - p[10]*p[12]*p[23] + p[10]*p[12]*p[32] + p[10]*p[14]*p[18] - p[10]*p[14]*p[27];
+ coeff[36] = 2*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[10]*p[10]*p[15] - 2*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[14]*p[14]*p[15] - 2*p[7]*p[11]*p[15] + p[7]*p[11]*p[24] - 2*p[8]*p[12]*p[15] + p[8]*p[12]*p[24] + 2*p[9]*p[13]*p[15] - p[9]*p[13]*p[24] + 2*p[10]*p[14]*p[15] - p[10]*p[14]*p[24];
+ coeff[37] = 2*p[0]*p[7]*p[10]*p[19] - 2*p[0]*p[8]*p[9]*p[19] + 2*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[16] - 2*p[0]*p[11]*p[14]*p[19] + 2*p[0]*p[12]*p[13]*p[19] - 2*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[16] - 2*p[7]*p[11]*p[16] + p[7]*p[11]*p[25] + 2*p[7]*p[14]*p[19] - p[7]*p[14]*p[28] - 2*p[8]*p[12]*p[16] + p[8]*p[12]*p[25] - 2*p[8]*p[13]*p[19] + p[8]*p[13]*p[28] - 2*p[9]*p[12]*p[19] + p[9]*p[12]*p[28] + 2*p[9]*p[13]*p[16] - p[9]*p[13]*p[25] + 2*p[10]*p[11]*p[19] - p[10]*p[11]*p[28] + 2*p[10]*p[14]*p[16] - p[10]*p[14]*p[25];
+ coeff[38] = -2*p[0]*p[7]*p[9]*p[22] + 2*p[0]*p[7]*p[10]*p[20] - 2*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[10]*p[22] + 2*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[11]*p[13]*p[22] - 2*p[0]*p[11]*p[14]*p[20] + 2*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[14]*p[22] - 2*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[14]*p[14]*p[17] - 2*p[7]*p[11]*p[17] + p[7]*p[11]*p[26] - 2*p[7]*p[13]*p[22] + p[7]*p[13]*p[31] + 2*p[7]*p[14]*p[20] - p[7]*p[14]*p[29] - 2*p[8]*p[12]*p[17] + p[8]*p[12]*p[26] - 2*p[8]*p[13]*p[20] + p[8]*p[13]*p[29] - 2*p[8]*p[14]*p[22] + p[8]*p[14]*p[31] - 2*p[9]*p[11]*p[22] + p[9]*p[11]*p[31] - 2*p[9]*p[12]*p[20] + p[9]*p[12]*p[29] + 2*p[9]*p[13]*p[17] - p[9]*p[13]*p[26] + 2*p[10]*p[11]*p[20] - p[10]*p[11]*p[29] - 2*p[10]*p[12]*p[22] + p[10]*p[12]*p[31] + 2*p[10]*p[14]*p[17] - p[10]*p[14]*p[26];
+ coeff[39] = (p[7]*p[11] + p[8]*p[12] - p[9]*p[13] - p[10]*p[14])*p[15];
+ coeff[40] = p[7]*p[11]*p[16] - p[7]*p[14]*p[19] + p[8]*p[12]*p[16] + p[8]*p[13]*p[19] + p[9]*p[12]*p[19] - p[9]*p[13]*p[16] - p[10]*p[11]*p[19] - p[10]*p[14]*p[16];
+ coeff[41] = p[7]*p[11]*p[17] + p[7]*p[13]*p[22] - p[7]*p[14]*p[20] + p[8]*p[12]*p[17] + p[8]*p[13]*p[20] + p[8]*p[14]*p[22] + p[9]*p[11]*p[22] + p[9]*p[12]*p[20] - p[9]*p[13]*p[17] - p[10]*p[11]*p[20] + p[10]*p[12]*p[22] - p[10]*p[14]*p[17];
+ coeff[42] = 2*(p[7]*p[9]*p[23] - p[7]*p[9]*p[32] - p[7]*p[10]*p[21] + p[7]*p[10]*p[30] + p[8]*p[9]*p[21] - p[8]*p[9]*p[30] + p[8]*p[10]*p[23] - p[8]*p[10]*p[32] - p[9]*p[9]*p[18] + p[9]*p[9]*p[27] - p[10]*p[10]*p[18] + p[10]*p[10]*p[27] - p[11]*p[13]*p[23] + p[11]*p[13]*p[32] + p[11]*p[14]*p[21] - p[11]*p[14]*p[30] - p[12]*p[13]*p[21] + p[12]*p[13]*p[30] - p[12]*p[14]*p[23] + p[12]*p[14]*p[32] + p[13]*p[13]*p[18] - p[13]*p[13]*p[27] + p[14]*p[14]*p[18] - p[14]*p[14]*p[27])*p[0];
+ coeff[43] = -4*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[9]*p[9]*p[24] - 4*p[0]*p[10]*p[10]*p[15] + 2*p[0]*p[10]*p[10]*p[24] + 4*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[13]*p[13]*p[24] + 4*p[0]*p[14]*p[14]*p[15] - 2*p[0]*p[14]*p[14]*p[24] + 2*p[7]*p[11]*p[15] - 2*p[7]*p[11]*p[24] + 2*p[8]*p[12]*p[15] - 2*p[8]*p[12]*p[24] - 2*p[9]*p[13]*p[15] + 2*p[9]*p[13]*p[24] - 2*p[10]*p[14]*p[15] + 2*p[10]*p[14]*p[24];
+ coeff[44] = -4*p[0]*p[7]*p[10]*p[19] + 2*p[0]*p[7]*p[10]*p[28] + 4*p[0]*p[8]*p[9]*p[19] - 2*p[0]*p[8]*p[9]*p[28] - 4*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[9]*p[9]*p[25] - 4*p[0]*p[10]*p[10]*p[16] + 2*p[0]*p[10]*p[10]*p[25] + 4*p[0]*p[11]*p[14]*p[19] - 2*p[0]*p[11]*p[14]*p[28] - 4*p[0]*p[12]*p[13]*p[19] + 2*p[0]*p[12]*p[13]*p[28] + 4*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[13]*p[13]*p[25] + 4*p[0]*p[14]*p[14]*p[16] - 2*p[0]*p[14]*p[14]*p[25] + 2*p[7]*p[11]*p[16] - 2*p[7]*p[11]*p[25] - 2*p[7]*p[14]*p[19] + 2*p[7]*p[14]*p[28] + 2*p[8]*p[12]*p[16] - 2*p[8]*p[12]*p[25] + 2*p[8]*p[13]*p[19] - 2*p[8]*p[13]*p[28] + 2*p[9]*p[12]*p[19] - 2*p[9]*p[12]*p[28] - 2*p[9]*p[13]*p[16] + 2*p[9]*p[13]*p[25] - 2*p[10]*p[11]*p[19] + 2*p[10]*p[11]*p[28] - 2*p[10]*p[14]*p[16] + 2*p[10]*p[14]*p[25];
+ coeff[45] = 4*p[0]*p[7]*p[9]*p[22] - 2*p[0]*p[7]*p[9]*p[31] - 4*p[0]*p[7]*p[10]*p[20] + 2*p[0]*p[7]*p[10]*p[29] + 4*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[9]*p[29] + 4*p[0]*p[8]*p[10]*p[22] - 2*p[0]*p[8]*p[10]*p[31] - 4*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[9]*p[9]*p[26] - 4*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[10]*p[10]*p[26] - 4*p[0]*p[11]*p[13]*p[22] + 2*p[0]*p[11]*p[13]*p[31] + 4*p[0]*p[11]*p[14]*p[20] - 2*p[0]*p[11]*p[14]*p[29] - 4*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[13]*p[29] - 4*p[0]*p[12]*p[14]*p[22] + 2*p[0]*p[12]*p[14]*p[31] + 4*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[13]*p[13]*p[26] + 4*p[0]*p[14]*p[14]*p[17] - 2*p[0]*p[14]*p[14]*p[26] + 2*p[7]*p[11]*p[17] - 2*p[7]*p[11]*p[26] + 2*p[7]*p[13]*p[22] - 2*p[7]*p[13]*p[31] - 2*p[7]*p[14]*p[20] + 2*p[7]*p[14]*p[29] + 2*p[8]*p[12]*p[17] - 2*p[8]*p[12]*p[26] + 2*p[8]*p[13]*p[20] - 2*p[8]*p[13]*p[29] + 2*p[8]*p[14]*p[22] - 2*p[8]*p[14]*p[31] + 2*p[9]*p[11]*p[22] - 2*p[9]*p[11]*p[31] + 2*p[9]*p[12]*p[20] - 2*p[9]*p[12]*p[29] - 2*p[9]*p[13]*p[17] + 2*p[9]*p[13]*p[26] - 2*p[10]*p[11]*p[20] + 2*p[10]*p[11]*p[29] + 2*p[10]*p[12]*p[22] - 2*p[10]*p[12]*p[31] - 2*p[10]*p[14]*p[17] + 2*p[10]*p[14]*p[26];
+ coeff[46] = 2*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[10]*p[10]*p[15] - 2*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[14]*p[14]*p[15] - 2*p[7]*p[11]*p[15] + 2*p[7]*p[11]*p[24] - 2*p[8]*p[12]*p[15] + 2*p[8]*p[12]*p[24] + 2*p[9]*p[13]*p[15] - 2*p[9]*p[13]*p[24] + 2*p[10]*p[14]*p[15] - 2*p[10]*p[14]*p[24];
+ coeff[47] = 2*p[0]*p[7]*p[10]*p[19] - 2*p[0]*p[8]*p[9]*p[19] + 2*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[16] - 2*p[0]*p[11]*p[14]*p[19] + 2*p[0]*p[12]*p[13]*p[19] - 2*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[16] - 2*p[7]*p[11]*p[16] + 2*p[7]*p[11]*p[25] + 2*p[7]*p[14]*p[19] - 2*p[7]*p[14]*p[28] - 2*p[8]*p[12]*p[16] + 2*p[8]*p[12]*p[25] - 2*p[8]*p[13]*p[19] + 2*p[8]*p[13]*p[28] - 2*p[9]*p[12]*p[19] + 2*p[9]*p[12]*p[28] + 2*p[9]*p[13]*p[16] - 2*p[9]*p[13]*p[25] + 2*p[10]*p[11]*p[19] - 2*p[10]*p[11]*p[28] + 2*p[10]*p[14]*p[16] - 2*p[10]*p[14]*p[25];
+ coeff[48] = -2*p[0]*p[7]*p[9]*p[22] + 2*p[0]*p[7]*p[10]*p[20] - 2*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[10]*p[22] + 2*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[11]*p[13]*p[22] - 2*p[0]*p[11]*p[14]*p[20] + 2*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[14]*p[22] - 2*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[14]*p[14]*p[17] - 2*p[7]*p[11]*p[17] + 2*p[7]*p[11]*p[26] - 2*p[7]*p[13]*p[22] + 2*p[7]*p[13]*p[31] + 2*p[7]*p[14]*p[20] - 2*p[7]*p[14]*p[29] - 2*p[8]*p[12]*p[17] + 2*p[8]*p[12]*p[26] - 2*p[8]*p[13]*p[20] + 2*p[8]*p[13]*p[29] - 2*p[8]*p[14]*p[22] + 2*p[8]*p[14]*p[31] - 2*p[9]*p[11]*p[22] + 2*p[9]*p[11]*p[31] - 2*p[9]*p[12]*p[20] + 2*p[9]*p[12]*p[29] + 2*p[9]*p[13]*p[17] - 2*p[9]*p[13]*p[26] + 2*p[10]*p[11]*p[20] - 2*p[10]*p[11]*p[29] - 2*p[10]*p[12]*p[22] + 2*p[10]*p[12]*p[31] + 2*p[10]*p[14]*p[17] - 2*p[10]*p[14]*p[26];
+ coeff[49] = 0;
+ coeff[50] = 2*(p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + p[10]*p[10]*p[15] - p[10]*p[10]*p[24] - p[13]*p[13]*p[15] + p[13]*p[13]*p[24] - p[14]*p[14]*p[15] + p[14]*p[14]*p[24])*p[0];
+ coeff[51] = 2*(p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + p[10]*p[10]*p[16] - p[10]*p[10]*p[25] - p[11]*p[14]*p[19] + p[11]*p[14]*p[28] + p[12]*p[13]*p[19] - p[12]*p[13]*p[28] - p[13]*p[13]*p[16] + p[13]*p[13]*p[25] - p[14]*p[14]*p[16] + p[14]*p[14]*p[25])*p[0];
+ coeff[52] = 2*(-p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + p[10]*p[10]*p[17] - p[10]*p[10]*p[26] + p[11]*p[13]*p[22] - p[11]*p[13]*p[31] - p[11]*p[14]*p[20] + p[11]*p[14]*p[29] + p[12]*p[13]*p[20] - p[12]*p[13]*p[29] + p[12]*p[14]*p[22] - p[12]*p[14]*p[31] - p[13]*p[13]*p[17] + p[13]*p[13]*p[26] - p[14]*p[14]*p[17] + p[14]*p[14]*p[26])*p[0];
+ coeff[53] = 2*(-p[9]*p[9]*p[15] + p[9]*p[9]*p[24] - p[10]*p[10]*p[15] + p[10]*p[10]*p[24] + p[13]*p[13]*p[15] - p[13]*p[13]*p[24] + p[14]*p[14]*p[15] - p[14]*p[14]*p[24])*p[0];
+ coeff[54] = 2*(-p[7]*p[10]*p[19] + p[7]*p[10]*p[28] + p[8]*p[9]*p[19] - p[8]*p[9]*p[28] - p[9]*p[9]*p[16] + p[9]*p[9]*p[25] - p[10]*p[10]*p[16] + p[10]*p[10]*p[25] + p[11]*p[14]*p[19] - p[11]*p[14]*p[28] - p[12]*p[13]*p[19] + p[12]*p[13]*p[28] + p[13]*p[13]*p[16] - p[13]*p[13]*p[25] + p[14]*p[14]*p[16] - p[14]*p[14]*p[25])*p[0];
+ coeff[55] = 2*(p[7]*p[9]*p[22] - p[7]*p[9]*p[31] - p[7]*p[10]*p[20] + p[7]*p[10]*p[29] + p[8]*p[9]*p[20] - p[8]*p[9]*p[29] + p[8]*p[10]*p[22] - p[8]*p[10]*p[31] - p[9]*p[9]*p[17] + p[9]*p[9]*p[26] - p[10]*p[10]*p[17] + p[10]*p[10]*p[26] - p[11]*p[13]*p[22] + p[11]*p[13]*p[31] + p[11]*p[14]*p[20] - p[11]*p[14]*p[29] - p[12]*p[13]*p[20] + p[12]*p[13]*p[29] - p[12]*p[14]*p[22] + p[12]*p[14]*p[31] + p[13]*p[13]*p[17] - p[13]*p[13]*p[26] + p[14]*p[14]*p[17] - p[14]*p[14]*p[26])*p[0];
+ coeff[56] = -p[2] + p[5] + p[7]*p[8]*p[23] - p[7]*p[8]*p[32] - p[7]*p[10]*p[18] + p[7]*p[10]*p[27] + p[8]*p[8]*p[21] - p[8]*p[8]*p[30] - p[8]*p[9]*p[18] + p[8]*p[9]*p[27] - p[9]*p[10]*p[23] + p[9]*p[10]*p[32] + p[10]*p[10]*p[21] - p[10]*p[10]*p[30] + p[11]*p[12]*p[23] - p[11]*p[12]*p[32] - p[11]*p[14]*p[18] + p[11]*p[14]*p[27] + p[12]*p[12]*p[21] - p[12]*p[12]*p[30] - p[12]*p[13]*p[18] + p[12]*p[13]*p[27] - p[13]*p[14]*p[23] + p[13]*p[14]*p[32] + p[14]*p[14]*p[21] - p[14]*p[14]*p[30] - p[21] + p[30];
+ coeff[57] = -2*p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + p[12]*p[13]*p[24];
+ coeff[58] = -2*p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - p[14]*p[14]*p[28] - 2*p[19] + p[28];
+ coeff[59] = 2*p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - p[14]*p[14]*p[29] - 2*p[20] + p[29];
+ coeff[60] = (p[7]*p[10] + p[8]*p[9] + p[11]*p[14] + p[12]*p[13])*p[15];
+ coeff[61] = p[7]*p[10]*p[16] - p[8]*p[8]*p[19] + p[8]*p[9]*p[16] - p[10]*p[10]*p[19] + p[11]*p[14]*p[16] - p[12]*p[12]*p[19] + p[12]*p[13]*p[16] - p[14]*p[14]*p[19] + p[19];
+ coeff[62] = -p[7]*p[8]*p[22] + p[7]*p[10]*p[17] - p[8]*p[8]*p[20] + p[8]*p[9]*p[17] + p[9]*p[10]*p[22] - p[10]*p[10]*p[20] - p[11]*p[12]*p[22] + p[11]*p[14]*p[17] - p[12]*p[12]*p[20] + p[12]*p[13]*p[17] + p[13]*p[14]*p[22] - p[14]*p[14]*p[20] + p[20];
+ coeff[63] = 0;
+ coeff[64] = 2*p[7]*p[10]*p[15] - 2*p[7]*p[10]*p[24] + 2*p[8]*p[9]*p[15] - 2*p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - 2*p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - 2*p[12]*p[13]*p[24];
+ coeff[65] = 2*p[7]*p[10]*p[16] - 2*p[7]*p[10]*p[25] - 2*p[8]*p[8]*p[19] + 2*p[8]*p[8]*p[28] + 2*p[8]*p[9]*p[16] - 2*p[8]*p[9]*p[25] - 2*p[10]*p[10]*p[19] + 2*p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - 2*p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + 2*p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - 2*p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + 2*p[14]*p[14]*p[28] + 2*p[19] - 2*p[28];
+ coeff[66] = -2*p[7]*p[8]*p[22] + 2*p[7]*p[8]*p[31] + 2*p[7]*p[10]*p[17] - 2*p[7]*p[10]*p[26] - 2*p[8]*p[8]*p[20] + 2*p[8]*p[8]*p[29] + 2*p[8]*p[9]*p[17] - 2*p[8]*p[9]*p[26] + 2*p[9]*p[10]*p[22] - 2*p[9]*p[10]*p[31] - 2*p[10]*p[10]*p[20] + 2*p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + 2*p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - 2*p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + 2*p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - 2*p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - 2*p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + 2*p[14]*p[14]*p[29] + 2*p[20] - 2*p[29];
+ coeff[67] = -2*p[7]*p[10]*p[15] + 2*p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + 2*p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + 2*p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + 2*p[12]*p[13]*p[24];
+ coeff[68] = -2*p[7]*p[10]*p[16] + 2*p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - 2*p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + 2*p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - 2*p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + 2*p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - 2*p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + 2*p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - 2*p[14]*p[14]*p[28] - 2*p[19] + 2*p[28];
+ coeff[69] = 2*p[7]*p[8]*p[22] - 2*p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + 2*p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - 2*p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + 2*p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + 2*p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - 2*p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - 2*p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + 2*p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - 2*p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + 2*p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + 2*p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - 2*p[14]*p[14]*p[29] - 2*p[20] + 2*p[29];
+ coeff[70] = 2*p[0]*p[7]*p[11]*p[21] - 2*p[0]*p[7]*p[12]*p[23] + 2*p[0]*p[7]*p[14]*p[18] - 2*p[0]*p[8]*p[11]*p[23] - 2*p[0]*p[8]*p[12]*p[21] + 2*p[0]*p[8]*p[13]*p[18] + 2*p[0]*p[9]*p[12]*p[18] + 2*p[0]*p[9]*p[13]*p[21] + 2*p[0]*p[9]*p[14]*p[23] + 2*p[0]*p[10]*p[11]*p[18] + 2*p[0]*p[10]*p[13]*p[23] - 2*p[0]*p[10]*p[14]*p[21] + p[7]*p[8]*p[23] - p[7]*p[8]*p[32] - p[7]*p[10]*p[18] + p[7]*p[10]*p[27] + p[8]*p[8]*p[21] - p[8]*p[8]*p[30] - p[8]*p[9]*p[18] + p[8]*p[9]*p[27] - p[9]*p[10]*p[23] + p[9]*p[10]*p[32] + p[10]*p[10]*p[21] - p[10]*p[10]*p[30] - p[11]*p[12]*p[23] + p[11]*p[12]*p[32] + p[11]*p[14]*p[18] - p[11]*p[14]*p[27] - p[12]*p[12]*p[21] + p[12]*p[12]*p[30] + p[12]*p[13]*p[18] - p[12]*p[13]*p[27] + p[13]*p[14]*p[23] - p[13]*p[14]*p[32] - p[14]*p[14]*p[21] + p[14]*p[14]*p[30];
+ coeff[71] = 2*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[10]*p[11]*p[15] - 2*p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - p[12]*p[13]*p[24];
+ coeff[72] = 2*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[14]*p[16] - 2*p[0]*p[8]*p[12]*p[19] + 2*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[10]*p[11]*p[16] - 2*p[0]*p[10]*p[14]*p[19] - 2*p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + p[14]*p[14]*p[28];
+ coeff[73] = 2*p[0]*p[7]*p[11]*p[20] - 2*p[0]*p[7]*p[12]*p[22] + 2*p[0]*p[7]*p[14]*p[17] - 2*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[12]*p[20] + 2*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[13]*p[22] - 2*p[0]*p[10]*p[14]*p[20] + 2*p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + p[14]*p[14]*p[29];
+ coeff[74] = (p[7]*p[10] + p[8]*p[9] - p[11]*p[14] - p[12]*p[13])*p[15];
+ coeff[75] = p[7]*p[10]*p[16] - p[8]*p[8]*p[19] + p[8]*p[9]*p[16] - p[10]*p[10]*p[19] - p[11]*p[14]*p[16] + p[12]*p[12]*p[19] - p[12]*p[13]*p[16] + p[14]*p[14]*p[19];
+ coeff[76] = -p[7]*p[8]*p[22] + p[7]*p[10]*p[17] - p[8]*p[8]*p[20] + p[8]*p[9]*p[17] + p[9]*p[10]*p[22] - p[10]*p[10]*p[20] + p[11]*p[12]*p[22] - p[11]*p[14]*p[17] + p[12]*p[12]*p[20] - p[12]*p[13]*p[17] - p[13]*p[14]*p[22] + p[14]*p[14]*p[20];
+ coeff[77] = 2*(-p[7]*p[11]*p[21] + p[7]*p[11]*p[30] + p[7]*p[12]*p[23] - p[7]*p[12]*p[32] - p[7]*p[14]*p[18] + p[7]*p[14]*p[27] + p[8]*p[11]*p[23] - p[8]*p[11]*p[32] + p[8]*p[12]*p[21] - p[8]*p[12]*p[30] - p[8]*p[13]*p[18] + p[8]*p[13]*p[27] - p[9]*p[12]*p[18] + p[9]*p[12]*p[27] - p[9]*p[13]*p[21] + p[9]*p[13]*p[30] - p[9]*p[14]*p[23] + p[9]*p[14]*p[32] - p[10]*p[11]*p[18] + p[10]*p[11]*p[27] - p[10]*p[13]*p[23] + p[10]*p[13]*p[32] + p[10]*p[14]*p[21] - p[10]*p[14]*p[30])*p[0];
+ coeff[78] = -4*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[7]*p[14]*p[24] - 4*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[8]*p[13]*p[24] - 4*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[9]*p[12]*p[24] - 4*p[0]*p[10]*p[11]*p[15] + 2*p[0]*p[10]*p[11]*p[24] + 2*p[7]*p[10]*p[15] - 2*p[7]*p[10]*p[24] + 2*p[8]*p[9]*p[15] - 2*p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + 2*p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + 2*p[12]*p[13]*p[24];
+ coeff[79] = -4*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[11]*p[28] - 4*p[0]*p[7]*p[14]*p[16] + 2*p[0]*p[7]*p[14]*p[25] + 4*p[0]*p[8]*p[12]*p[19] - 2*p[0]*p[8]*p[12]*p[28] - 4*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[8]*p[13]*p[25] - 4*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[12]*p[25] - 4*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[9]*p[13]*p[28] - 4*p[0]*p[10]*p[11]*p[16] + 2*p[0]*p[10]*p[11]*p[25] + 4*p[0]*p[10]*p[14]*p[19] - 2*p[0]*p[10]*p[14]*p[28] + 2*p[7]*p[10]*p[16] - 2*p[7]*p[10]*p[25] - 2*p[8]*p[8]*p[19] + 2*p[8]*p[8]*p[28] + 2*p[8]*p[9]*p[16] - 2*p[8]*p[9]*p[25] - 2*p[10]*p[10]*p[19] + 2*p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + 2*p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - 2*p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + 2*p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - 2*p[14]*p[14]*p[28];
+ coeff[80] = -4*p[0]*p[7]*p[11]*p[20] + 2*p[0]*p[7]*p[11]*p[29] + 4*p[0]*p[7]*p[12]*p[22] - 2*p[0]*p[7]*p[12]*p[31] - 4*p[0]*p[7]*p[14]*p[17] + 2*p[0]*p[7]*p[14]*p[26] + 4*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[11]*p[31] + 4*p[0]*p[8]*p[12]*p[20] - 2*p[0]*p[8]*p[12]*p[29] - 4*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[8]*p[13]*p[26] - 4*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[12]*p[26] - 4*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[13]*p[29] - 4*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[9]*p[14]*p[31] - 4*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[11]*p[26] - 4*p[0]*p[10]*p[13]*p[22] + 2*p[0]*p[10]*p[13]*p[31] + 4*p[0]*p[10]*p[14]*p[20] - 2*p[0]*p[10]*p[14]*p[29] - 2*p[7]*p[8]*p[22] + 2*p[7]*p[8]*p[31] + 2*p[7]*p[10]*p[17] - 2*p[7]*p[10]*p[26] - 2*p[8]*p[8]*p[20] + 2*p[8]*p[8]*p[29] + 2*p[8]*p[9]*p[17] - 2*p[8]*p[9]*p[26] + 2*p[9]*p[10]*p[22] - 2*p[9]*p[10]*p[31] - 2*p[10]*p[10]*p[20] + 2*p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - 2*p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + 2*p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - 2*p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + 2*p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + 2*p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - 2*p[14]*p[14]*p[29];
+ coeff[81] = 2*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[10]*p[11]*p[15] - 2*p[7]*p[10]*p[15] + 2*p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + 2*p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - 2*p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - 2*p[12]*p[13]*p[24];
+ coeff[82] = 2*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[14]*p[16] - 2*p[0]*p[8]*p[12]*p[19] + 2*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[10]*p[11]*p[16] - 2*p[0]*p[10]*p[14]*p[19] - 2*p[7]*p[10]*p[16] + 2*p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - 2*p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + 2*p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - 2*p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - 2*p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + 2*p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - 2*p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + 2*p[14]*p[14]*p[28];
+ coeff[83] = 2*p[0]*p[7]*p[11]*p[20] - 2*p[0]*p[7]*p[12]*p[22] + 2*p[0]*p[7]*p[14]*p[17] - 2*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[12]*p[20] + 2*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[13]*p[22] - 2*p[0]*p[10]*p[14]*p[20] + 2*p[7]*p[8]*p[22] - 2*p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + 2*p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - 2*p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + 2*p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + 2*p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - 2*p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + 2*p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - 2*p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + 2*p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - 2*p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - 2*p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + 2*p[14]*p[14]*p[29];
+ coeff[84] = 0;
+ coeff[85] = 2*(p[7]*p[14]*p[15] - p[7]*p[14]*p[24] + p[8]*p[13]*p[15] - p[8]*p[13]*p[24] + p[9]*p[12]*p[15] - p[9]*p[12]*p[24] + p[10]*p[11]*p[15] - p[10]*p[11]*p[24])*p[0];
+ coeff[86] = 2*(p[7]*p[11]*p[19] - p[7]*p[11]*p[28] + p[7]*p[14]*p[16] - p[7]*p[14]*p[25] - p[8]*p[12]*p[19] + p[8]*p[12]*p[28] + p[8]*p[13]*p[16] - p[8]*p[13]*p[25] + p[9]*p[12]*p[16] - p[9]*p[12]*p[25] + p[9]*p[13]*p[19] - p[9]*p[13]*p[28] + p[10]*p[11]*p[16] - p[10]*p[11]*p[25] - p[10]*p[14]*p[19] + p[10]*p[14]*p[28])*p[0];
+ coeff[87] = 2*(p[7]*p[11]*p[20] - p[7]*p[11]*p[29] - p[7]*p[12]*p[22] + p[7]*p[12]*p[31] + p[7]*p[14]*p[17] - p[7]*p[14]*p[26] - p[8]*p[11]*p[22] + p[8]*p[11]*p[31] - p[8]*p[12]*p[20] + p[8]*p[12]*p[29] + p[8]*p[13]*p[17] - p[8]*p[13]*p[26] + p[9]*p[12]*p[17] - p[9]*p[12]*p[26] + p[9]*p[13]*p[20] - p[9]*p[13]*p[29] + p[9]*p[14]*p[22] - p[9]*p[14]*p[31] + p[10]*p[11]*p[17] - p[10]*p[11]*p[26] + p[10]*p[13]*p[22] - p[10]*p[13]*p[31] - p[10]*p[14]*p[20] + p[10]*p[14]*p[29])*p[0];
+ coeff[88] = 2*(-p[7]*p[14]*p[15] + p[7]*p[14]*p[24] - p[8]*p[13]*p[15] + p[8]*p[13]*p[24] - p[9]*p[12]*p[15] + p[9]*p[12]*p[24] - p[10]*p[11]*p[15] + p[10]*p[11]*p[24])*p[0];
+ coeff[89] = 2*(-p[7]*p[11]*p[19] + p[7]*p[11]*p[28] - p[7]*p[14]*p[16] + p[7]*p[14]*p[25] + p[8]*p[12]*p[19] - p[8]*p[12]*p[28] - p[8]*p[13]*p[16] + p[8]*p[13]*p[25] - p[9]*p[12]*p[16] + p[9]*p[12]*p[25] - p[9]*p[13]*p[19] + p[9]*p[13]*p[28] - p[10]*p[11]*p[16] + p[10]*p[11]*p[25] + p[10]*p[14]*p[19] - p[10]*p[14]*p[28])*p[0];
+ coeff[90] = 2*(-p[7]*p[11]*p[20] + p[7]*p[11]*p[29] + p[7]*p[12]*p[22] - p[7]*p[12]*p[31] - p[7]*p[14]*p[17] + p[7]*p[14]*p[26] + p[8]*p[11]*p[22] - p[8]*p[11]*p[31] + p[8]*p[12]*p[20] - p[8]*p[12]*p[29] - p[8]*p[13]*p[17] + p[8]*p[13]*p[26] - p[9]*p[12]*p[17] + p[9]*p[12]*p[26] - p[9]*p[13]*p[20] + p[9]*p[13]*p[29] - p[9]*p[14]*p[22] + p[9]*p[14]*p[31] - p[10]*p[11]*p[17] + p[10]*p[11]*p[26] - p[10]*p[13]*p[22] + p[10]*p[13]*p[31] + p[10]*p[14]*p[20] - p[10]*p[14]*p[29])*p[0];
+ coeff[91] = 2*p[0]*p[7]*p[8]*p[23] - 2*p[0]*p[7]*p[10]*p[18] + 2*p[0]*p[8]*p[8]*p[21] - 2*p[0]*p[8]*p[9]*p[18] - 2*p[0]*p[9]*p[10]*p[23] + 2*p[0]*p[10]*p[10]*p[21] - 2*p[0]*p[11]*p[12]*p[23] + 2*p[0]*p[11]*p[14]*p[18] - 2*p[0]*p[12]*p[12]*p[21] + 2*p[0]*p[12]*p[13]*p[18] + 2*p[0]*p[13]*p[14]*p[23] - 2*p[0]*p[14]*p[14]*p[21] - p[7]*p[11]*p[21] + p[7]*p[11]*p[30] + p[7]*p[12]*p[23] - p[7]*p[12]*p[32] - p[7]*p[14]*p[18] + p[7]*p[14]*p[27] + p[8]*p[11]*p[23] - p[8]*p[11]*p[32] + p[8]*p[12]*p[21] - p[8]*p[12]*p[30] - p[8]*p[13]*p[18] + p[8]*p[13]*p[27] - p[9]*p[12]*p[18] + p[9]*p[12]*p[27] - p[9]*p[13]*p[21] + p[9]*p[13]*p[30] - p[9]*p[14]*p[23] + p[9]*p[14]*p[32] - p[10]*p[11]*p[18] + p[10]*p[11]*p[27] - p[10]*p[13]*p[23] + p[10]*p[13]*p[32] + p[10]*p[14]*p[21] - p[10]*p[14]*p[30];
+ coeff[92] = -2*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[8]*p[9]*p[15] + 2*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[12]*p[13]*p[15] - 2*p[7]*p[14]*p[15] + p[7]*p[14]*p[24] - 2*p[8]*p[13]*p[15] + p[8]*p[13]*p[24] - 2*p[9]*p[12]*p[15] + p[9]*p[12]*p[24] - 2*p[10]*p[11]*p[15] + p[10]*p[11]*p[24];
+ coeff[93] = -2*p[0]*p[7]*p[10]*p[16] + 2*p[0]*p[8]*p[8]*p[19] - 2*p[0]*p[8]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[11]*p[14]*p[16] - 2*p[0]*p[12]*p[12]*p[19] + 2*p[0]*p[12]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[19] - 2*p[7]*p[11]*p[19] + p[7]*p[11]*p[28] - 2*p[7]*p[14]*p[16] + p[7]*p[14]*p[25] + 2*p[8]*p[12]*p[19] - p[8]*p[12]*p[28] - 2*p[8]*p[13]*p[16] + p[8]*p[13]*p[25] - 2*p[9]*p[12]*p[16] + p[9]*p[12]*p[25] - 2*p[9]*p[13]*p[19] + p[9]*p[13]*p[28] - 2*p[10]*p[11]*p[16] + p[10]*p[11]*p[25] + 2*p[10]*p[14]*p[19] - p[10]*p[14]*p[28];
+ coeff[94] = 2*p[0]*p[7]*p[8]*p[22] - 2*p[0]*p[7]*p[10]*p[17] + 2*p[0]*p[8]*p[8]*p[20] - 2*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[9]*p[10]*p[22] + 2*p[0]*p[10]*p[10]*p[20] - 2*p[0]*p[11]*p[12]*p[22] + 2*p[0]*p[11]*p[14]*p[17] - 2*p[0]*p[12]*p[12]*p[20] + 2*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[13]*p[14]*p[22] - 2*p[0]*p[14]*p[14]*p[20] - 2*p[7]*p[11]*p[20] + p[7]*p[11]*p[29] + 2*p[7]*p[12]*p[22] - p[7]*p[12]*p[31] - 2*p[7]*p[14]*p[17] + p[7]*p[14]*p[26] + 2*p[8]*p[11]*p[22] - p[8]*p[11]*p[31] + 2*p[8]*p[12]*p[20] - p[8]*p[12]*p[29] - 2*p[8]*p[13]*p[17] + p[8]*p[13]*p[26] - 2*p[9]*p[12]*p[17] + p[9]*p[12]*p[26] - 2*p[9]*p[13]*p[20] + p[9]*p[13]*p[29] - 2*p[9]*p[14]*p[22] + p[9]*p[14]*p[31] - 2*p[10]*p[11]*p[17] + p[10]*p[11]*p[26] - 2*p[10]*p[13]*p[22] + p[10]*p[13]*p[31] + 2*p[10]*p[14]*p[20] - p[10]*p[14]*p[29];
+ coeff[95] = (p[7]*p[14] + p[8]*p[13] + p[9]*p[12] + p[10]*p[11])*p[15];
+ coeff[96] = p[7]*p[11]*p[19] + p[7]*p[14]*p[16] - p[8]*p[12]*p[19] + p[8]*p[13]*p[16] + p[9]*p[12]*p[16] + p[9]*p[13]*p[19] + p[10]*p[11]*p[16] - p[10]*p[14]*p[19];
+ coeff[97] = p[7]*p[11]*p[20] - p[7]*p[12]*p[22] + p[7]*p[14]*p[17] - p[8]*p[11]*p[22] - p[8]*p[12]*p[20] + p[8]*p[13]*p[17] + p[9]*p[12]*p[17] + p[9]*p[13]*p[20] + p[9]*p[14]*p[22] + p[10]*p[11]*p[17] + p[10]*p[13]*p[22] - p[10]*p[14]*p[20];
+ coeff[98] = 2*(-p[7]*p[8]*p[23] + p[7]*p[8]*p[32] + p[7]*p[10]*p[18] - p[7]*p[10]*p[27] - p[8]*p[8]*p[21] + p[8]*p[8]*p[30] + p[8]*p[9]*p[18] - p[8]*p[9]*p[27] + p[9]*p[10]*p[23] - p[9]*p[10]*p[32] - p[10]*p[10]*p[21] + p[10]*p[10]*p[30] + p[11]*p[12]*p[23] - p[11]*p[12]*p[32] - p[11]*p[14]*p[18] + p[11]*p[14]*p[27] + p[12]*p[12]*p[21] - p[12]*p[12]*p[30] - p[12]*p[13]*p[18] + p[12]*p[13]*p[27] - p[13]*p[14]*p[23] + p[13]*p[14]*p[32] + p[14]*p[14]*p[21] - p[14]*p[14]*p[30])*p[0];
+ coeff[99] = 4*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[7]*p[10]*p[24] + 4*p[0]*p[8]*p[9]*p[15] - 2*p[0]*p[8]*p[9]*p[24] - 4*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[11]*p[14]*p[24] - 4*p[0]*p[12]*p[13]*p[15] + 2*p[0]*p[12]*p[13]*p[24] + 2*p[7]*p[14]*p[15] - 2*p[7]*p[14]*p[24] + 2*p[8]*p[13]*p[15] - 2*p[8]*p[13]*p[24] + 2*p[9]*p[12]*p[15] - 2*p[9]*p[12]*p[24] + 2*p[10]*p[11]*p[15] - 2*p[10]*p[11]*p[24];
+ coeff[100] = 4*p[0]*p[7]*p[10]*p[16] - 2*p[0]*p[7]*p[10]*p[25] - 4*p[0]*p[8]*p[8]*p[19] + 2*p[0]*p[8]*p[8]*p[28] + 4*p[0]*p[8]*p[9]*p[16] - 2*p[0]*p[8]*p[9]*p[25] - 4*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[10]*p[10]*p[28] - 4*p[0]*p[11]*p[14]*p[16] + 2*p[0]*p[11]*p[14]*p[25] + 4*p[0]*p[12]*p[12]*p[19] - 2*p[0]*p[12]*p[12]*p[28] - 4*p[0]*p[12]*p[13]*p[16] + 2*p[0]*p[12]*p[13]*p[25] + 4*p[0]*p[14]*p[14]*p[19] - 2*p[0]*p[14]*p[14]*p[28] + 2*p[7]*p[11]*p[19] - 2*p[7]*p[11]*p[28] + 2*p[7]*p[14]*p[16] - 2*p[7]*p[14]*p[25] - 2*p[8]*p[12]*p[19] + 2*p[8]*p[12]*p[28] + 2*p[8]*p[13]*p[16] - 2*p[8]*p[13]*p[25] + 2*p[9]*p[12]*p[16] - 2*p[9]*p[12]*p[25] + 2*p[9]*p[13]*p[19] - 2*p[9]*p[13]*p[28] + 2*p[10]*p[11]*p[16] - 2*p[10]*p[11]*p[25] - 2*p[10]*p[14]*p[19] + 2*p[10]*p[14]*p[28];
+ coeff[101] = -4*p[0]*p[7]*p[8]*p[22] + 2*p[0]*p[7]*p[8]*p[31] + 4*p[0]*p[7]*p[10]*p[17] - 2*p[0]*p[7]*p[10]*p[26] - 4*p[0]*p[8]*p[8]*p[20] + 2*p[0]*p[8]*p[8]*p[29] + 4*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[8]*p[9]*p[26] + 4*p[0]*p[9]*p[10]*p[22] - 2*p[0]*p[9]*p[10]*p[31] - 4*p[0]*p[10]*p[10]*p[20] + 2*p[0]*p[10]*p[10]*p[29] + 4*p[0]*p[11]*p[12]*p[22] - 2*p[0]*p[11]*p[12]*p[31] - 4*p[0]*p[11]*p[14]*p[17] + 2*p[0]*p[11]*p[14]*p[26] + 4*p[0]*p[12]*p[12]*p[20] - 2*p[0]*p[12]*p[12]*p[29] - 4*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[12]*p[13]*p[26] - 4*p[0]*p[13]*p[14]*p[22] + 2*p[0]*p[13]*p[14]*p[31] + 4*p[0]*p[14]*p[14]*p[20] - 2*p[0]*p[14]*p[14]*p[29] + 2*p[7]*p[11]*p[20] - 2*p[7]*p[11]*p[29] - 2*p[7]*p[12]*p[22] + 2*p[7]*p[12]*p[31] + 2*p[7]*p[14]*p[17] - 2*p[7]*p[14]*p[26] - 2*p[8]*p[11]*p[22] + 2*p[8]*p[11]*p[31] - 2*p[8]*p[12]*p[20] + 2*p[8]*p[12]*p[29] + 2*p[8]*p[13]*p[17] - 2*p[8]*p[13]*p[26] + 2*p[9]*p[12]*p[17] - 2*p[9]*p[12]*p[26] + 2*p[9]*p[13]*p[20] - 2*p[9]*p[13]*p[29] + 2*p[9]*p[14]*p[22] - 2*p[9]*p[14]*p[31] + 2*p[10]*p[11]*p[17] - 2*p[10]*p[11]*p[26] + 2*p[10]*p[13]*p[22] - 2*p[10]*p[13]*p[31] - 2*p[10]*p[14]*p[20] + 2*p[10]*p[14]*p[29];
+ coeff[102] = -2*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[8]*p[9]*p[15] + 2*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[12]*p[13]*p[15] - 2*p[7]*p[14]*p[15] + 2*p[7]*p[14]*p[24] - 2*p[8]*p[13]*p[15] + 2*p[8]*p[13]*p[24] - 2*p[9]*p[12]*p[15] + 2*p[9]*p[12]*p[24] - 2*p[10]*p[11]*p[15] + 2*p[10]*p[11]*p[24];
+ coeff[103] = -2*p[0]*p[7]*p[10]*p[16] + 2*p[0]*p[8]*p[8]*p[19] - 2*p[0]*p[8]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[11]*p[14]*p[16] - 2*p[0]*p[12]*p[12]*p[19] + 2*p[0]*p[12]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[19] - 2*p[7]*p[11]*p[19] + 2*p[7]*p[11]*p[28] - 2*p[7]*p[14]*p[16] + 2*p[7]*p[14]*p[25] + 2*p[8]*p[12]*p[19] - 2*p[8]*p[12]*p[28] - 2*p[8]*p[13]*p[16] + 2*p[8]*p[13]*p[25] - 2*p[9]*p[12]*p[16] + 2*p[9]*p[12]*p[25] - 2*p[9]*p[13]*p[19] + 2*p[9]*p[13]*p[28] - 2*p[10]*p[11]*p[16] + 2*p[10]*p[11]*p[25] + 2*p[10]*p[14]*p[19] - 2*p[10]*p[14]*p[28];
+ coeff[104] = 2*p[0]*p[7]*p[8]*p[22] - 2*p[0]*p[7]*p[10]*p[17] + 2*p[0]*p[8]*p[8]*p[20] - 2*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[9]*p[10]*p[22] + 2*p[0]*p[10]*p[10]*p[20] - 2*p[0]*p[11]*p[12]*p[22] + 2*p[0]*p[11]*p[14]*p[17] - 2*p[0]*p[12]*p[12]*p[20] + 2*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[13]*p[14]*p[22] - 2*p[0]*p[14]*p[14]*p[20] - 2*p[7]*p[11]*p[20] + 2*p[7]*p[11]*p[29] + 2*p[7]*p[12]*p[22] - 2*p[7]*p[12]*p[31] - 2*p[7]*p[14]*p[17] + 2*p[7]*p[14]*p[26] + 2*p[8]*p[11]*p[22] - 2*p[8]*p[11]*p[31] + 2*p[8]*p[12]*p[20] - 2*p[8]*p[12]*p[29] - 2*p[8]*p[13]*p[17] + 2*p[8]*p[13]*p[26] - 2*p[9]*p[12]*p[17] + 2*p[9]*p[12]*p[26] - 2*p[9]*p[13]*p[20] + 2*p[9]*p[13]*p[29] - 2*p[9]*p[14]*p[22] + 2*p[9]*p[14]*p[31] - 2*p[10]*p[11]*p[17] + 2*p[10]*p[11]*p[26] - 2*p[10]*p[13]*p[22] + 2*p[10]*p[13]*p[31] + 2*p[10]*p[14]*p[20] - 2*p[10]*p[14]*p[29];
+ coeff[105] = 0;
+ coeff[106] = 2*(-p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - p[8]*p[9]*p[15] + p[8]*p[9]*p[24] + p[11]*p[14]*p[15] - p[11]*p[14]*p[24] + p[12]*p[13]*p[15] - p[12]*p[13]*p[24])*p[0];
+ coeff[107] = 2*(-p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + p[10]*p[10]*p[19] - p[10]*p[10]*p[28] + p[11]*p[14]*p[16] - p[11]*p[14]*p[25] - p[12]*p[12]*p[19] + p[12]*p[12]*p[28] + p[12]*p[13]*p[16] - p[12]*p[13]*p[25] - p[14]*p[14]*p[19] + p[14]*p[14]*p[28])*p[0];
+ coeff[108] = 2*(p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + p[10]*p[10]*p[20] - p[10]*p[10]*p[29] - p[11]*p[12]*p[22] + p[11]*p[12]*p[31] + p[11]*p[14]*p[17] - p[11]*p[14]*p[26] - p[12]*p[12]*p[20] + p[12]*p[12]*p[29] + p[12]*p[13]*p[17] - p[12]*p[13]*p[26] + p[13]*p[14]*p[22] - p[13]*p[14]*p[31] - p[14]*p[14]*p[20] + p[14]*p[14]*p[29])*p[0];
+ coeff[109] = 2*(p[7]*p[10]*p[15] - p[7]*p[10]*p[24] + p[8]*p[9]*p[15] - p[8]*p[9]*p[24] - p[11]*p[14]*p[15] + p[11]*p[14]*p[24] - p[12]*p[13]*p[15] + p[12]*p[13]*p[24])*p[0];
+ coeff[110] = 2*(p[7]*p[10]*p[16] - p[7]*p[10]*p[25] - p[8]*p[8]*p[19] + p[8]*p[8]*p[28] + p[8]*p[9]*p[16] - p[8]*p[9]*p[25] - p[10]*p[10]*p[19] + p[10]*p[10]*p[28] - p[11]*p[14]*p[16] + p[11]*p[14]*p[25] + p[12]*p[12]*p[19] - p[12]*p[12]*p[28] - p[12]*p[13]*p[16] + p[12]*p[13]*p[25] + p[14]*p[14]*p[19] - p[14]*p[14]*p[28])*p[0];
+ coeff[111] = 2*(-p[7]*p[8]*p[22] + p[7]*p[8]*p[31] + p[7]*p[10]*p[17] - p[7]*p[10]*p[26] - p[8]*p[8]*p[20] + p[8]*p[8]*p[29] + p[8]*p[9]*p[17] - p[8]*p[9]*p[26] + p[9]*p[10]*p[22] - p[9]*p[10]*p[31] - p[10]*p[10]*p[20] + p[10]*p[10]*p[29] + p[11]*p[12]*p[22] - p[11]*p[12]*p[31] - p[11]*p[14]*p[17] + p[11]*p[14]*p[26] + p[12]*p[12]*p[20] - p[12]*p[12]*p[29] - p[12]*p[13]*p[17] + p[12]*p[13]*p[26] - p[13]*p[14]*p[22] + p[13]*p[14]*p[31] + p[14]*p[14]*p[20] - p[14]*p[14]*p[29])*p[0];
+ coeff[112] = -p[3] + p[6] - p[7]*p[8]*p[21] + p[7]*p[8]*p[30] + p[7]*p[9]*p[18] - p[7]*p[9]*p[27] + p[8]*p[8]*p[23] - p[8]*p[8]*p[32] - p[8]*p[10]*p[18] + p[8]*p[10]*p[27] + p[9]*p[9]*p[23] - p[9]*p[9]*p[32] - p[9]*p[10]*p[21] + p[9]*p[10]*p[30] - p[11]*p[12]*p[21] + p[11]*p[12]*p[30] + p[11]*p[13]*p[18] - p[11]*p[13]*p[27] + p[12]*p[12]*p[23] - p[12]*p[12]*p[32] - p[12]*p[14]*p[18] + p[12]*p[14]*p[27] + p[13]*p[13]*p[23] - p[13]*p[13]*p[32] - p[13]*p[14]*p[21] + p[13]*p[14]*p[30] - p[23] + p[32];
+ coeff[113] = 2*p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + p[12]*p[14]*p[24];
+ coeff[114] = -2*p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + p[13]*p[14]*p[28];
+ coeff[115] = -2*p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + p[13]*p[14]*p[29] - 2*p[22] + p[31];
+ coeff[116] = (-p[7]*p[9] + p[8]*p[10] - p[11]*p[13] + p[12]*p[14])*p[15];
+ coeff[117] = p[7]*p[8]*p[19] - p[7]*p[9]*p[16] + p[8]*p[10]*p[16] + p[9]*p[10]*p[19] + p[11]*p[12]*p[19] - p[11]*p[13]*p[16] + p[12]*p[14]*p[16] + p[13]*p[14]*p[19];
+ coeff[118] = p[7]*p[8]*p[20] - p[7]*p[9]*p[17] - p[8]*p[8]*p[22] + p[8]*p[10]*p[17] - p[9]*p[9]*p[22] + p[9]*p[10]*p[20] + p[11]*p[12]*p[20] - p[11]*p[13]*p[17] - p[12]*p[12]*p[22] + p[12]*p[14]*p[17] - p[13]*p[13]*p[22] + p[13]*p[14]*p[20] + p[22];
+ coeff[119] = 0;
+ coeff[120] = -2*p[7]*p[9]*p[15] + 2*p[7]*p[9]*p[24] + 2*p[8]*p[10]*p[15] - 2*p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + 2*p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - 2*p[12]*p[14]*p[24];
+ coeff[121] = 2*p[7]*p[8]*p[19] - 2*p[7]*p[8]*p[28] - 2*p[7]*p[9]*p[16] + 2*p[7]*p[9]*p[25] + 2*p[8]*p[10]*p[16] - 2*p[8]*p[10]*p[25] + 2*p[9]*p[10]*p[19] - 2*p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - 2*p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + 2*p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - 2*p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - 2*p[13]*p[14]*p[28];
+ coeff[122] = 2*p[7]*p[8]*p[20] - 2*p[7]*p[8]*p[29] - 2*p[7]*p[9]*p[17] + 2*p[7]*p[9]*p[26] - 2*p[8]*p[8]*p[22] + 2*p[8]*p[8]*p[31] + 2*p[8]*p[10]*p[17] - 2*p[8]*p[10]*p[26] - 2*p[9]*p[9]*p[22] + 2*p[9]*p[9]*p[31] + 2*p[9]*p[10]*p[20] - 2*p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - 2*p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + 2*p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + 2*p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - 2*p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + 2*p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - 2*p[13]*p[14]*p[29] + 2*p[22] - 2*p[31];
+ coeff[123] = 2*p[7]*p[9]*p[15] - 2*p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + 2*p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - 2*p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + 2*p[12]*p[14]*p[24];
+ coeff[124] = -2*p[7]*p[8]*p[19] + 2*p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - 2*p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + 2*p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + 2*p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + 2*p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - 2*p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + 2*p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + 2*p[13]*p[14]*p[28];
+ coeff[125] = -2*p[7]*p[8]*p[20] + 2*p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - 2*p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - 2*p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + 2*p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - 2*p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + 2*p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + 2*p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - 2*p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - 2*p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + 2*p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - 2*p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + 2*p[13]*p[14]*p[29] - 2*p[22] + 2*p[31];
+ coeff[126] = 2*p[0]*p[7]*p[11]*p[23] + 2*p[0]*p[7]*p[12]*p[21] - 2*p[0]*p[7]*p[13]*p[18] + 2*p[0]*p[8]*p[11]*p[21] - 2*p[0]*p[8]*p[12]*p[23] + 2*p[0]*p[8]*p[14]*p[18] - 2*p[0]*p[9]*p[11]*p[18] - 2*p[0]*p[9]*p[13]*p[23] + 2*p[0]*p[9]*p[14]*p[21] + 2*p[0]*p[10]*p[12]*p[18] + 2*p[0]*p[10]*p[13]*p[21] + 2*p[0]*p[10]*p[14]*p[23] - p[7]*p[8]*p[21] + p[7]*p[8]*p[30] + p[7]*p[9]*p[18] - p[7]*p[9]*p[27] + p[8]*p[8]*p[23] - p[8]*p[8]*p[32] - p[8]*p[10]*p[18] + p[8]*p[10]*p[27] + p[9]*p[9]*p[23] - p[9]*p[9]*p[32] - p[9]*p[10]*p[21] + p[9]*p[10]*p[30] + p[11]*p[12]*p[21] - p[11]*p[12]*p[30] - p[11]*p[13]*p[18] + p[11]*p[13]*p[27] - p[12]*p[12]*p[23] + p[12]*p[12]*p[32] + p[12]*p[14]*p[18] - p[12]*p[14]*p[27] - p[13]*p[13]*p[23] + p[13]*p[13]*p[32] + p[13]*p[14]*p[21] - p[13]*p[14]*p[30];
+ coeff[127] = -2*p[0]*p[7]*p[13]*p[15] + 2*p[0]*p[8]*p[14]*p[15] - 2*p[0]*p[9]*p[11]*p[15] + 2*p[0]*p[10]*p[12]*p[15] + 2*p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - p[12]*p[14]*p[24];
+ coeff[128] = 2*p[0]*p[7]*p[12]*p[19] - 2*p[0]*p[7]*p[13]*p[16] + 2*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[14]*p[16] - 2*p[0]*p[9]*p[11]*p[16] + 2*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[13]*p[19] - 2*p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - p[13]*p[14]*p[28];
+ coeff[129] = 2*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[12]*p[20] - 2*p[0]*p[7]*p[13]*p[17] + 2*p[0]*p[8]*p[11]*p[20] - 2*p[0]*p[8]*p[12]*p[22] + 2*p[0]*p[8]*p[14]*p[17] - 2*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[13]*p[22] + 2*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[14]*p[22] - 2*p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - p[13]*p[14]*p[29];
+ coeff[130] = (-p[7]*p[9] + p[8]*p[10] + p[11]*p[13] - p[12]*p[14])*p[15];
+ coeff[131] = p[7]*p[8]*p[19] - p[7]*p[9]*p[16] + p[8]*p[10]*p[16] + p[9]*p[10]*p[19] - p[11]*p[12]*p[19] + p[11]*p[13]*p[16] - p[12]*p[14]*p[16] - p[13]*p[14]*p[19];
+ coeff[132] = p[7]*p[8]*p[20] - p[7]*p[9]*p[17] - p[8]*p[8]*p[22] + p[8]*p[10]*p[17] - p[9]*p[9]*p[22] + p[9]*p[10]*p[20] - p[11]*p[12]*p[20] + p[11]*p[13]*p[17] + p[12]*p[12]*p[22] - p[12]*p[14]*p[17] + p[13]*p[13]*p[22] - p[13]*p[14]*p[20];
+ coeff[133] = 2*(-p[7]*p[11]*p[23] + p[7]*p[11]*p[32] - p[7]*p[12]*p[21] + p[7]*p[12]*p[30] + p[7]*p[13]*p[18] - p[7]*p[13]*p[27] - p[8]*p[11]*p[21] + p[8]*p[11]*p[30] + p[8]*p[12]*p[23] - p[8]*p[12]*p[32] - p[8]*p[14]*p[18] + p[8]*p[14]*p[27] + p[9]*p[11]*p[18] - p[9]*p[11]*p[27] + p[9]*p[13]*p[23] - p[9]*p[13]*p[32] - p[9]*p[14]*p[21] + p[9]*p[14]*p[30] - p[10]*p[12]*p[18] + p[10]*p[12]*p[27] - p[10]*p[13]*p[21] + p[10]*p[13]*p[30] - p[10]*p[14]*p[23] + p[10]*p[14]*p[32])*p[0];
+ coeff[134] = 4*p[0]*p[7]*p[13]*p[15] - 2*p[0]*p[7]*p[13]*p[24] - 4*p[0]*p[8]*p[14]*p[15] + 2*p[0]*p[8]*p[14]*p[24] + 4*p[0]*p[9]*p[11]*p[15] - 2*p[0]*p[9]*p[11]*p[24] - 4*p[0]*p[10]*p[12]*p[15] + 2*p[0]*p[10]*p[12]*p[24] - 2*p[7]*p[9]*p[15] + 2*p[7]*p[9]*p[24] + 2*p[8]*p[10]*p[15] - 2*p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - 2*p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + 2*p[12]*p[14]*p[24];
+ coeff[135] = -4*p[0]*p[7]*p[12]*p[19] + 2*p[0]*p[7]*p[12]*p[28] + 4*p[0]*p[7]*p[13]*p[16] - 2*p[0]*p[7]*p[13]*p[25] - 4*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[11]*p[28] - 4*p[0]*p[8]*p[14]*p[16] + 2*p[0]*p[8]*p[14]*p[25] + 4*p[0]*p[9]*p[11]*p[16] - 2*p[0]*p[9]*p[11]*p[25] - 4*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[9]*p[14]*p[28] - 4*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[12]*p[25] - 4*p[0]*p[10]*p[13]*p[19] + 2*p[0]*p[10]*p[13]*p[28] + 2*p[7]*p[8]*p[19] - 2*p[7]*p[8]*p[28] - 2*p[7]*p[9]*p[16] + 2*p[7]*p[9]*p[25] + 2*p[8]*p[10]*p[16] - 2*p[8]*p[10]*p[25] + 2*p[9]*p[10]*p[19] - 2*p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + 2*p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - 2*p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + 2*p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + 2*p[13]*p[14]*p[28];
+ coeff[136] = -4*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[11]*p[31] - 4*p[0]*p[7]*p[12]*p[20] + 2*p[0]*p[7]*p[12]*p[29] + 4*p[0]*p[7]*p[13]*p[17] - 2*p[0]*p[7]*p[13]*p[26] - 4*p[0]*p[8]*p[11]*p[20] + 2*p[0]*p[8]*p[11]*p[29] + 4*p[0]*p[8]*p[12]*p[22] - 2*p[0]*p[8]*p[12]*p[31] - 4*p[0]*p[8]*p[14]*p[17] + 2*p[0]*p[8]*p[14]*p[26] + 4*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[11]*p[26] + 4*p[0]*p[9]*p[13]*p[22] - 2*p[0]*p[9]*p[13]*p[31] - 4*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[9]*p[14]*p[29] - 4*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[12]*p[26] - 4*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[13]*p[29] - 4*p[0]*p[10]*p[14]*p[22] + 2*p[0]*p[10]*p[14]*p[31] + 2*p[7]*p[8]*p[20] - 2*p[7]*p[8]*p[29] - 2*p[7]*p[9]*p[17] + 2*p[7]*p[9]*p[26] - 2*p[8]*p[8]*p[22] + 2*p[8]*p[8]*p[31] + 2*p[8]*p[10]*p[17] - 2*p[8]*p[10]*p[26] - 2*p[9]*p[9]*p[22] + 2*p[9]*p[9]*p[31] + 2*p[9]*p[10]*p[20] - 2*p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + 2*p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - 2*p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - 2*p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + 2*p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - 2*p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + 2*p[13]*p[14]*p[29];
+ coeff[137] = -2*p[0]*p[7]*p[13]*p[15] + 2*p[0]*p[8]*p[14]*p[15] - 2*p[0]*p[9]*p[11]*p[15] + 2*p[0]*p[10]*p[12]*p[15] + 2*p[7]*p[9]*p[15] - 2*p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + 2*p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + 2*p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - 2*p[12]*p[14]*p[24];
+ coeff[138] = 2*p[0]*p[7]*p[12]*p[19] - 2*p[0]*p[7]*p[13]*p[16] + 2*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[14]*p[16] - 2*p[0]*p[9]*p[11]*p[16] + 2*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[13]*p[19] - 2*p[7]*p[8]*p[19] + 2*p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - 2*p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + 2*p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + 2*p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - 2*p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + 2*p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - 2*p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - 2*p[13]*p[14]*p[28];
+ coeff[139] = 2*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[12]*p[20] - 2*p[0]*p[7]*p[13]*p[17] + 2*p[0]*p[8]*p[11]*p[20] - 2*p[0]*p[8]*p[12]*p[22] + 2*p[0]*p[8]*p[14]*p[17] - 2*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[13]*p[22] + 2*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[14]*p[22] - 2*p[7]*p[8]*p[20] + 2*p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - 2*p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - 2*p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + 2*p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - 2*p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + 2*p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - 2*p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + 2*p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + 2*p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - 2*p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + 2*p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - 2*p[13]*p[14]*p[29];
+ coeff[140] = 0;
+ coeff[141] = 2*(-p[7]*p[13]*p[15] + p[7]*p[13]*p[24] + p[8]*p[14]*p[15] - p[8]*p[14]*p[24] - p[9]*p[11]*p[15] + p[9]*p[11]*p[24] + p[10]*p[12]*p[15] - p[10]*p[12]*p[24])*p[0];
+ coeff[142] = 2*(p[7]*p[12]*p[19] - p[7]*p[12]*p[28] - p[7]*p[13]*p[16] + p[7]*p[13]*p[25] + p[8]*p[11]*p[19] - p[8]*p[11]*p[28] + p[8]*p[14]*p[16] - p[8]*p[14]*p[25] - p[9]*p[11]*p[16] + p[9]*p[11]*p[25] + p[9]*p[14]*p[19] - p[9]*p[14]*p[28] + p[10]*p[12]*p[16] - p[10]*p[12]*p[25] + p[10]*p[13]*p[19] - p[10]*p[13]*p[28])*p[0];
+ coeff[143] = 2*(p[7]*p[11]*p[22] - p[7]*p[11]*p[31] + p[7]*p[12]*p[20] - p[7]*p[12]*p[29] - p[7]*p[13]*p[17] + p[7]*p[13]*p[26] + p[8]*p[11]*p[20] - p[8]*p[11]*p[29] - p[8]*p[12]*p[22] + p[8]*p[12]*p[31] + p[8]*p[14]*p[17] - p[8]*p[14]*p[26] - p[9]*p[11]*p[17] + p[9]*p[11]*p[26] - p[9]*p[13]*p[22] + p[9]*p[13]*p[31] + p[9]*p[14]*p[20] - p[9]*p[14]*p[29] + p[10]*p[12]*p[17] - p[10]*p[12]*p[26] + p[10]*p[13]*p[20] - p[10]*p[13]*p[29] + p[10]*p[14]*p[22] - p[10]*p[14]*p[31])*p[0];
+ coeff[144] = 2*(p[7]*p[13]*p[15] - p[7]*p[13]*p[24] - p[8]*p[14]*p[15] + p[8]*p[14]*p[24] + p[9]*p[11]*p[15] - p[9]*p[11]*p[24] - p[10]*p[12]*p[15] + p[10]*p[12]*p[24])*p[0];
+ coeff[145] = 2*(-p[7]*p[12]*p[19] + p[7]*p[12]*p[28] + p[7]*p[13]*p[16] - p[7]*p[13]*p[25] - p[8]*p[11]*p[19] + p[8]*p[11]*p[28] - p[8]*p[14]*p[16] + p[8]*p[14]*p[25] + p[9]*p[11]*p[16] - p[9]*p[11]*p[25] - p[9]*p[14]*p[19] + p[9]*p[14]*p[28] - p[10]*p[12]*p[16] + p[10]*p[12]*p[25] - p[10]*p[13]*p[19] + p[10]*p[13]*p[28])*p[0];
+ coeff[146] = 2*(-p[7]*p[11]*p[22] + p[7]*p[11]*p[31] - p[7]*p[12]*p[20] + p[7]*p[12]*p[29] + p[7]*p[13]*p[17] - p[7]*p[13]*p[26] - p[8]*p[11]*p[20] + p[8]*p[11]*p[29] + p[8]*p[12]*p[22] - p[8]*p[12]*p[31] - p[8]*p[14]*p[17] + p[8]*p[14]*p[26] + p[9]*p[11]*p[17] - p[9]*p[11]*p[26] + p[9]*p[13]*p[22] - p[9]*p[13]*p[31] - p[9]*p[14]*p[20] + p[9]*p[14]*p[29] - p[10]*p[12]*p[17] + p[10]*p[12]*p[26] - p[10]*p[13]*p[20] + p[10]*p[13]*p[29] - p[10]*p[14]*p[22] + p[10]*p[14]*p[31])*p[0];
+ coeff[147] = -2*p[0]*p[7]*p[8]*p[21] + 2*p[0]*p[7]*p[9]*p[18] + 2*p[0]*p[8]*p[8]*p[23] - 2*p[0]*p[8]*p[10]*p[18] + 2*p[0]*p[9]*p[9]*p[23] - 2*p[0]*p[9]*p[10]*p[21] + 2*p[0]*p[11]*p[12]*p[21] - 2*p[0]*p[11]*p[13]*p[18] - 2*p[0]*p[12]*p[12]*p[23] + 2*p[0]*p[12]*p[14]*p[18] - 2*p[0]*p[13]*p[13]*p[23] + 2*p[0]*p[13]*p[14]*p[21] - p[7]*p[11]*p[23] + p[7]*p[11]*p[32] - p[7]*p[12]*p[21] + p[7]*p[12]*p[30] + p[7]*p[13]*p[18] - p[7]*p[13]*p[27] - p[8]*p[11]*p[21] + p[8]*p[11]*p[30] + p[8]*p[12]*p[23] - p[8]*p[12]*p[32] - p[8]*p[14]*p[18] + p[8]*p[14]*p[27] + p[9]*p[11]*p[18] - p[9]*p[11]*p[27] + p[9]*p[13]*p[23] - p[9]*p[13]*p[32] - p[9]*p[14]*p[21] + p[9]*p[14]*p[30] - p[10]*p[12]*p[18] + p[10]*p[12]*p[27] - p[10]*p[13]*p[21] + p[10]*p[13]*p[30] - p[10]*p[14]*p[23] + p[10]*p[14]*p[32];
+ coeff[148] = 2*p[0]*p[7]*p[9]*p[15] - 2*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[11]*p[13]*p[15] + 2*p[0]*p[12]*p[14]*p[15] + 2*p[7]*p[13]*p[15] - p[7]*p[13]*p[24] - 2*p[8]*p[14]*p[15] + p[8]*p[14]*p[24] + 2*p[9]*p[11]*p[15] - p[9]*p[11]*p[24] - 2*p[10]*p[12]*p[15] + p[10]*p[12]*p[24];
+ coeff[149] = -2*p[0]*p[7]*p[8]*p[19] + 2*p[0]*p[7]*p[9]*p[16] - 2*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[9]*p[10]*p[19] + 2*p[0]*p[11]*p[12]*p[19] - 2*p[0]*p[11]*p[13]*p[16] + 2*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[13]*p[14]*p[19] - 2*p[7]*p[12]*p[19] + p[7]*p[12]*p[28] + 2*p[7]*p[13]*p[16] - p[7]*p[13]*p[25] - 2*p[8]*p[11]*p[19] + p[8]*p[11]*p[28] - 2*p[8]*p[14]*p[16] + p[8]*p[14]*p[25] + 2*p[9]*p[11]*p[16] - p[9]*p[11]*p[25] - 2*p[9]*p[14]*p[19] + p[9]*p[14]*p[28] - 2*p[10]*p[12]*p[16] + p[10]*p[12]*p[25] - 2*p[10]*p[13]*p[19] + p[10]*p[13]*p[28];
+ coeff[150] = -2*p[0]*p[7]*p[8]*p[20] + 2*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[8]*p[8]*p[22] - 2*p[0]*p[8]*p[10]*p[17] + 2*p[0]*p[9]*p[9]*p[22] - 2*p[0]*p[9]*p[10]*p[20] + 2*p[0]*p[11]*p[12]*p[20] - 2*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[12]*p[12]*p[22] + 2*p[0]*p[12]*p[14]*p[17] - 2*p[0]*p[13]*p[13]*p[22] + 2*p[0]*p[13]*p[14]*p[20] - 2*p[7]*p[11]*p[22] + p[7]*p[11]*p[31] - 2*p[7]*p[12]*p[20] + p[7]*p[12]*p[29] + 2*p[7]*p[13]*p[17] - p[7]*p[13]*p[26] - 2*p[8]*p[11]*p[20] + p[8]*p[11]*p[29] + 2*p[8]*p[12]*p[22] - p[8]*p[12]*p[31] - 2*p[8]*p[14]*p[17] + p[8]*p[14]*p[26] + 2*p[9]*p[11]*p[17] - p[9]*p[11]*p[26] + 2*p[9]*p[13]*p[22] - p[9]*p[13]*p[31] - 2*p[9]*p[14]*p[20] + p[9]*p[14]*p[29] - 2*p[10]*p[12]*p[17] + p[10]*p[12]*p[26] - 2*p[10]*p[13]*p[20] + p[10]*p[13]*p[29] - 2*p[10]*p[14]*p[22] + p[10]*p[14]*p[31];
+ coeff[151] = (-p[7]*p[13] + p[8]*p[14] - p[9]*p[11] + p[10]*p[12])*p[15];
+ coeff[152] = p[7]*p[12]*p[19] - p[7]*p[13]*p[16] + p[8]*p[11]*p[19] + p[8]*p[14]*p[16] - p[9]*p[11]*p[16] + p[9]*p[14]*p[19] + p[10]*p[12]*p[16] + p[10]*p[13]*p[19];
+ coeff[153] = p[7]*p[11]*p[22] + p[7]*p[12]*p[20] - p[7]*p[13]*p[17] + p[8]*p[11]*p[20] - p[8]*p[12]*p[22] + p[8]*p[14]*p[17] - p[9]*p[11]*p[17] - p[9]*p[13]*p[22] + p[9]*p[14]*p[20] + p[10]*p[12]*p[17] + p[10]*p[13]*p[20] + p[10]*p[14]*p[22];
+ coeff[154] = 2*(p[7]*p[8]*p[21] - p[7]*p[8]*p[30] - p[7]*p[9]*p[18] + p[7]*p[9]*p[27] - p[8]*p[8]*p[23] + p[8]*p[8]*p[32] + p[8]*p[10]*p[18] - p[8]*p[10]*p[27] - p[9]*p[9]*p[23] + p[9]*p[9]*p[32] + p[9]*p[10]*p[21] - p[9]*p[10]*p[30] - p[11]*p[12]*p[21] + p[11]*p[12]*p[30] + p[11]*p[13]*p[18] - p[11]*p[13]*p[27] + p[12]*p[12]*p[23] - p[12]*p[12]*p[32] - p[12]*p[14]*p[18] + p[12]*p[14]*p[27] + p[13]*p[13]*p[23] - p[13]*p[13]*p[32] - p[13]*p[14]*p[21] + p[13]*p[14]*p[30])*p[0];
+ coeff[155] = -4*p[0]*p[7]*p[9]*p[15] + 2*p[0]*p[7]*p[9]*p[24] + 4*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[8]*p[10]*p[24] + 4*p[0]*p[11]*p[13]*p[15] - 2*p[0]*p[11]*p[13]*p[24] - 4*p[0]*p[12]*p[14]*p[15] + 2*p[0]*p[12]*p[14]*p[24] - 2*p[7]*p[13]*p[15] + 2*p[7]*p[13]*p[24] + 2*p[8]*p[14]*p[15] - 2*p[8]*p[14]*p[24] - 2*p[9]*p[11]*p[15] + 2*p[9]*p[11]*p[24] + 2*p[10]*p[12]*p[15] - 2*p[10]*p[12]*p[24];
+ coeff[156] = 4*p[0]*p[7]*p[8]*p[19] - 2*p[0]*p[7]*p[8]*p[28] - 4*p[0]*p[7]*p[9]*p[16] + 2*p[0]*p[7]*p[9]*p[25] + 4*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[8]*p[10]*p[25] + 4*p[0]*p[9]*p[10]*p[19] - 2*p[0]*p[9]*p[10]*p[28] - 4*p[0]*p[11]*p[12]*p[19] + 2*p[0]*p[11]*p[12]*p[28] + 4*p[0]*p[11]*p[13]*p[16] - 2*p[0]*p[11]*p[13]*p[25] - 4*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[12]*p[14]*p[25] - 4*p[0]*p[13]*p[14]*p[19] + 2*p[0]*p[13]*p[14]*p[28] + 2*p[7]*p[12]*p[19] - 2*p[7]*p[12]*p[28] - 2*p[7]*p[13]*p[16] + 2*p[7]*p[13]*p[25] + 2*p[8]*p[11]*p[19] - 2*p[8]*p[11]*p[28] + 2*p[8]*p[14]*p[16] - 2*p[8]*p[14]*p[25] - 2*p[9]*p[11]*p[16] + 2*p[9]*p[11]*p[25] + 2*p[9]*p[14]*p[19] - 2*p[9]*p[14]*p[28] + 2*p[10]*p[12]*p[16] - 2*p[10]*p[12]*p[25] + 2*p[10]*p[13]*p[19] - 2*p[10]*p[13]*p[28];
+ coeff[157] = 4*p[0]*p[7]*p[8]*p[20] - 2*p[0]*p[7]*p[8]*p[29] - 4*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[7]*p[9]*p[26] - 4*p[0]*p[8]*p[8]*p[22] + 2*p[0]*p[8]*p[8]*p[31] + 4*p[0]*p[8]*p[10]*p[17] - 2*p[0]*p[8]*p[10]*p[26] - 4*p[0]*p[9]*p[9]*p[22] + 2*p[0]*p[9]*p[9]*p[31] + 4*p[0]*p[9]*p[10]*p[20] - 2*p[0]*p[9]*p[10]*p[29] - 4*p[0]*p[11]*p[12]*p[20] + 2*p[0]*p[11]*p[12]*p[29] + 4*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[11]*p[13]*p[26] + 4*p[0]*p[12]*p[12]*p[22] - 2*p[0]*p[12]*p[12]*p[31] - 4*p[0]*p[12]*p[14]*p[17] + 2*p[0]*p[12]*p[14]*p[26] + 4*p[0]*p[13]*p[13]*p[22] - 2*p[0]*p[13]*p[13]*p[31] - 4*p[0]*p[13]*p[14]*p[20] + 2*p[0]*p[13]*p[14]*p[29] + 2*p[7]*p[11]*p[22] - 2*p[7]*p[11]*p[31] + 2*p[7]*p[12]*p[20] - 2*p[7]*p[12]*p[29] - 2*p[7]*p[13]*p[17] + 2*p[7]*p[13]*p[26] + 2*p[8]*p[11]*p[20] - 2*p[8]*p[11]*p[29] - 2*p[8]*p[12]*p[22] + 2*p[8]*p[12]*p[31] + 2*p[8]*p[14]*p[17] - 2*p[8]*p[14]*p[26] - 2*p[9]*p[11]*p[17] + 2*p[9]*p[11]*p[26] - 2*p[9]*p[13]*p[22] + 2*p[9]*p[13]*p[31] + 2*p[9]*p[14]*p[20] - 2*p[9]*p[14]*p[29] + 2*p[10]*p[12]*p[17] - 2*p[10]*p[12]*p[26] + 2*p[10]*p[13]*p[20] - 2*p[10]*p[13]*p[29] + 2*p[10]*p[14]*p[22] - 2*p[10]*p[14]*p[31];
+ coeff[158] = 2*p[0]*p[7]*p[9]*p[15] - 2*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[11]*p[13]*p[15] + 2*p[0]*p[12]*p[14]*p[15] + 2*p[7]*p[13]*p[15] - 2*p[7]*p[13]*p[24] - 2*p[8]*p[14]*p[15] + 2*p[8]*p[14]*p[24] + 2*p[9]*p[11]*p[15] - 2*p[9]*p[11]*p[24] - 2*p[10]*p[12]*p[15] + 2*p[10]*p[12]*p[24];
+ coeff[159] = -2*p[0]*p[7]*p[8]*p[19] + 2*p[0]*p[7]*p[9]*p[16] - 2*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[9]*p[10]*p[19] + 2*p[0]*p[11]*p[12]*p[19] - 2*p[0]*p[11]*p[13]*p[16] + 2*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[13]*p[14]*p[19] - 2*p[7]*p[12]*p[19] + 2*p[7]*p[12]*p[28] + 2*p[7]*p[13]*p[16] - 2*p[7]*p[13]*p[25] - 2*p[8]*p[11]*p[19] + 2*p[8]*p[11]*p[28] - 2*p[8]*p[14]*p[16] + 2*p[8]*p[14]*p[25] + 2*p[9]*p[11]*p[16] - 2*p[9]*p[11]*p[25] - 2*p[9]*p[14]*p[19] + 2*p[9]*p[14]*p[28] - 2*p[10]*p[12]*p[16] + 2*p[10]*p[12]*p[25] - 2*p[10]*p[13]*p[19] + 2*p[10]*p[13]*p[28];
+ coeff[160] = -2*p[0]*p[7]*p[8]*p[20] + 2*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[8]*p[8]*p[22] - 2*p[0]*p[8]*p[10]*p[17] + 2*p[0]*p[9]*p[9]*p[22] - 2*p[0]*p[9]*p[10]*p[20] + 2*p[0]*p[11]*p[12]*p[20] - 2*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[12]*p[12]*p[22] + 2*p[0]*p[12]*p[14]*p[17] - 2*p[0]*p[13]*p[13]*p[22] + 2*p[0]*p[13]*p[14]*p[20] - 2*p[7]*p[11]*p[22] + 2*p[7]*p[11]*p[31] - 2*p[7]*p[12]*p[20] + 2*p[7]*p[12]*p[29] + 2*p[7]*p[13]*p[17] - 2*p[7]*p[13]*p[26] - 2*p[8]*p[11]*p[20] + 2*p[8]*p[11]*p[29] + 2*p[8]*p[12]*p[22] - 2*p[8]*p[12]*p[31] - 2*p[8]*p[14]*p[17] + 2*p[8]*p[14]*p[26] + 2*p[9]*p[11]*p[17] - 2*p[9]*p[11]*p[26] + 2*p[9]*p[13]*p[22] - 2*p[9]*p[13]*p[31] - 2*p[9]*p[14]*p[20] + 2*p[9]*p[14]*p[29] - 2*p[10]*p[12]*p[17] + 2*p[10]*p[12]*p[26] - 2*p[10]*p[13]*p[20] + 2*p[10]*p[13]*p[29] - 2*p[10]*p[14]*p[22] + 2*p[10]*p[14]*p[31];
+ coeff[161] = 0;
+ coeff[162] = 2*(p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - p[8]*p[10]*p[15] + p[8]*p[10]*p[24] - p[11]*p[13]*p[15] + p[11]*p[13]*p[24] + p[12]*p[14]*p[15] - p[12]*p[14]*p[24])*p[0];
+ coeff[163] = 2*(-p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - p[9]*p[10]*p[19] + p[9]*p[10]*p[28] + p[11]*p[12]*p[19] - p[11]*p[12]*p[28] - p[11]*p[13]*p[16] + p[11]*p[13]*p[25] + p[12]*p[14]*p[16] - p[12]*p[14]*p[25] + p[13]*p[14]*p[19] - p[13]*p[14]*p[28])*p[0];
+ coeff[164] = 2*(-p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - p[9]*p[10]*p[20] + p[9]*p[10]*p[29] + p[11]*p[12]*p[20] - p[11]*p[12]*p[29] - p[11]*p[13]*p[17] + p[11]*p[13]*p[26] - p[12]*p[12]*p[22] + p[12]*p[12]*p[31] + p[12]*p[14]*p[17] - p[12]*p[14]*p[26] - p[13]*p[13]*p[22] + p[13]*p[13]*p[31] + p[13]*p[14]*p[20] - p[13]*p[14]*p[29])*p[0];
+ coeff[165] = 2*(-p[7]*p[9]*p[15] + p[7]*p[9]*p[24] + p[8]*p[10]*p[15] - p[8]*p[10]*p[24] + p[11]*p[13]*p[15] - p[11]*p[13]*p[24] - p[12]*p[14]*p[15] + p[12]*p[14]*p[24])*p[0];
+ coeff[166] = 2*(p[7]*p[8]*p[19] - p[7]*p[8]*p[28] - p[7]*p[9]*p[16] + p[7]*p[9]*p[25] + p[8]*p[10]*p[16] - p[8]*p[10]*p[25] + p[9]*p[10]*p[19] - p[9]*p[10]*p[28] - p[11]*p[12]*p[19] + p[11]*p[12]*p[28] + p[11]*p[13]*p[16] - p[11]*p[13]*p[25] - p[12]*p[14]*p[16] + p[12]*p[14]*p[25] - p[13]*p[14]*p[19] + p[13]*p[14]*p[28])*p[0];
+ coeff[167] = 2*(p[7]*p[8]*p[20] - p[7]*p[8]*p[29] - p[7]*p[9]*p[17] + p[7]*p[9]*p[26] - p[8]*p[8]*p[22] + p[8]*p[8]*p[31] + p[8]*p[10]*p[17] - p[8]*p[10]*p[26] - p[9]*p[9]*p[22] + p[9]*p[9]*p[31] + p[9]*p[10]*p[20] - p[9]*p[10]*p[29] - p[11]*p[12]*p[20] + p[11]*p[12]*p[29] + p[11]*p[13]*p[17] - p[11]*p[13]*p[26] + p[12]*p[12]*p[22] - p[12]*p[12]*p[31] - p[12]*p[14]*p[17] + p[12]*p[14]*p[26] + p[13]*p[13]*p[22] - p[13]*p[13]*p[31] - p[13]*p[14]*p[20] + p[13]*p[14]*p[29])*p[0];
+}
+
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/common/point_query.h b/thirdparty/embree-aarch64/kernels/common/point_query.h
new file mode 100644
index 0000000000..27d158ca3a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/point_query.h
@@ -0,0 +1,136 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /* Point query structure for closest point query */
+ template<int K>
+ struct RTC_ALIGN(16) PointQueryK
+ {
+ /* Default construction does nothing */
+ __forceinline PointQueryK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline PointQueryK(const Vec3vf<K>& p, const vfloat<K>& radius = inf, const vfloat<K>& time = zero)
+ : p(p), time(time), radius(radius) {}
+
+ /* Returns the size of the ray */
+ static __forceinline size_t size() { return K; }
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline vbool<K> valid() const
+ {
+ const vbool<K> vx = (abs(p.x) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vy = (abs(p.y) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vz = (abs(p.z) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vn = radius >= vfloat<K>(0);
+ const vbool<K> vf = abs(time) < vfloat<K>(inf);
+ return vx & vy & vz & vn & vf;
+ }
+
+ __forceinline void get(PointQueryK<1>* ray) const;
+ __forceinline void get(size_t i, PointQueryK<1>& ray) const;
+ __forceinline void set(const PointQueryK<1>* ray);
+ __forceinline void set(size_t i, const PointQueryK<1>& ray);
+
+ Vec3vf<K> p; // location of the query point
+ vfloat<K> time; // time for motion blur
+ vfloat<K> radius; // radius for the point query
+ };
+
+ /* Specialization for a single point query */
+ template<>
+ struct RTC_ALIGN(16) PointQueryK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline PointQueryK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline PointQueryK(const Vec3fa& p, float radius = inf, float time = zero)
+ : p(p), time(time), radius(radius) {}
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline bool valid() const {
+ return all(le_mask(abs(Vec3fa(p)), Vec3fa(FLT_LARGE)) & le_mask(Vec3fa(0.f), Vec3fa(radius))) && abs(time) < float(inf);
+ }
+
+ Vec3f p;
+ float time;
+ float radius;
+ };
+
+ /* Converts point query packet to single point query */
+ template<int K>
+ __forceinline void PointQueryK<K>::get(PointQueryK<1>* query) const
+ {
+ for (size_t i = 0; i < K; i++) // FIXME: use SIMD transpose
+ {
+ query[i].p.x = p.x[i];
+ query[i].p.y = p.y[i];
+ query[i].p.z = p.z[i];
+ query[i].time = time[i];
+ query[i].radius = radius[i];
+ }
+ }
+
+ /* Extracts a single point query out of a point query packet*/
+ template<int K>
+ __forceinline void PointQueryK<K>::get(size_t i, PointQueryK<1>& query) const
+ {
+ query.p.x = p.x[i];
+ query.p.y = p.y[i];
+ query.p.z = p.z[i];
+ query.radius = radius[i];
+ query.time = time[i];
+ }
+
+ /* Converts single point query to point query packet */
+ template<int K>
+ __forceinline void PointQueryK<K>::set(const PointQueryK<1>* query)
+ {
+ for (size_t i = 0; i < K; i++)
+ {
+ p.x[i] = query[i].p.x;
+ p.y[i] = query[i].p.y;
+ p.z[i] = query[i].p.z;
+ radius[i] = query[i].radius;
+ time[i] = query[i].time;
+ }
+ }
+
+ /* inserts a single point query into a point query packet element */
+ template<int K>
+ __forceinline void PointQueryK<K>::set(size_t i, const PointQueryK<1>& query)
+ {
+ p.x[i] = query.p.x;
+ p.y[i] = query.p.y;
+ p.z[i] = query.p.z;
+ radius[i] = query.radius;
+ time[i] = query.time;
+ }
+
+ /* Shortcuts */
+ typedef PointQueryK<1> PointQuery;
+ typedef PointQueryK<4> PointQuery4;
+ typedef PointQueryK<8> PointQuery8;
+ typedef PointQueryK<16> PointQuery16;
+ struct PointQueryN;
+
+ /* Outputs point query to stream */
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const PointQueryK<K>& query)
+ {
+ cout << "{ " << embree_endl
+ << " p = " << query.p << embree_endl
+ << " r = " << query.radius << embree_endl
+ << " time = " << query.time << embree_endl
+ << "}";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/primref.h b/thirdparty/embree-aarch64/kernels/common/primref.h
new file mode 100644
index 0000000000..ce75c982bb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/primref.h
@@ -0,0 +1,138 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct __aligned(32) PrimRef
+ {
+ __forceinline PrimRef () {}
+
+#if defined(__AVX__)
+ __forceinline PrimRef(const PrimRef& v) {
+ vfloat8::store((float*)this,vfloat8::load((float*)&v));
+ }
+ __forceinline PrimRef& operator=(const PrimRef& v) {
+ vfloat8::store((float*)this,vfloat8::load((float*)&v)); return *this;
+ }
+#endif
+
+ __forceinline PrimRef (const BBox3fa& bounds, unsigned int geomID, unsigned int primID)
+ {
+ lower = Vec3fx(bounds.lower, geomID);
+ upper = Vec3fx(bounds.upper, primID);
+ }
+
+ __forceinline PrimRef (const BBox3fa& bounds, size_t id)
+ {
+#if defined(__X86_64__) || defined(__aarch64__)
+ lower = Vec3fx(bounds.lower, (unsigned)(id & 0xFFFFFFFF));
+ upper = Vec3fx(bounds.upper, (unsigned)((id >> 32) & 0xFFFFFFFF));
+#else
+ lower = Vec3fx(bounds.lower, (unsigned)id);
+ upper = Vec3fx(bounds.upper, (unsigned)0);
+#endif
+ }
+
+ /*! calculates twice the center of the primitive */
+ __forceinline const Vec3fa center2() const {
+ return lower+upper;
+ }
+
+ /*! return the bounding box of the primitive */
+ __forceinline const BBox3fa bounds() const {
+ return BBox3fa(lower,upper);
+ }
+
+ /*! size for bin heuristic is 1 */
+ __forceinline unsigned size() const {
+ return 1;
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = embree::center2(bounds_o);
+ }
+
+ __forceinline unsigned& geomIDref() { // FIXME: remove !!!!!!!
+ return lower.u;
+ }
+ __forceinline unsigned& primIDref() { // FIXME: remove !!!!!!!
+ return upper.u;
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned geomID() const {
+ return lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned primID() const {
+ return upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__X86_64__) || defined(__aarch64__)
+ return size_t(lower.u) + (size_t(upper.u) << 32);
+#else
+ return size_t(lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRef& p0, const PrimRef& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRef& ref) {
+ return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << " }";
+ }
+
+ public:
+ Vec3fx lower; //!< lower bounds and geomID
+ Vec3fx upper; //!< upper bounds and primID
+ };
+
+ /*! fast exchange for PrimRefs */
+ __forceinline void xchg(PrimRef& a, PrimRef& b)
+ {
+#if defined(__AVX__)
+ const vfloat8 aa = vfloat8::load((float*)&a);
+ const vfloat8 bb = vfloat8::load((float*)&b);
+ vfloat8::store((float*)&a,bb);
+ vfloat8::store((float*)&b,aa);
+#else
+ std::swap(a,b);
+#endif
+ }
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ struct SubGridBuildData {
+ unsigned short sx,sy;
+ unsigned int primID;
+
+ __forceinline SubGridBuildData() {};
+ __forceinline SubGridBuildData(const unsigned int sx, const unsigned int sy, const unsigned int primID) : sx(sx), sy(sy), primID(primID) {};
+
+ __forceinline size_t x() const { return (size_t)sx & 0x7fff; }
+ __forceinline size_t y() const { return (size_t)sy & 0x7fff; }
+
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/primref_mb.h b/thirdparty/embree-aarch64/kernels/common/primref_mb.h
new file mode 100644
index 0000000000..b6c1ad5712
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/primref_mb.h
@@ -0,0 +1,262 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+#define MBLUR_BIN_LBBOX 1
+
+namespace embree
+{
+#if MBLUR_BIN_LBBOX
+
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct PrimRefMB
+ {
+ typedef LBBox3fa BBox;
+
+ __forceinline PrimRefMB () {}
+
+ __forceinline PrimRefMB (const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, unsigned int geomID, unsigned int primID)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+ lbounds.bounds0.lower.a = geomID;
+ lbounds.bounds0.upper.a = primID;
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ __forceinline PrimRefMB (EmptyTy empty, const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__X86_64__) || defined(__aarch64__)
+ lbounds.bounds0.lower.a = id & 0xFFFFFFFF;
+ lbounds.bounds0.upper.a = (id >> 32) & 0xFFFFFFFF;
+#else
+ lbounds.bounds0.lower.a = id;
+ lbounds.bounds0.upper.a = 0;
+#endif
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ __forceinline PrimRefMB (const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__X86_64__) || defined(__aarch64__)
+ lbounds.bounds0.lower.u = id & 0xFFFFFFFF;
+ lbounds.bounds0.upper.u = (id >> 32) & 0xFFFFFFFF;
+#else
+ lbounds.bounds0.lower.u = id;
+ lbounds.bounds0.upper.u = 0;
+#endif
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ /*! returns bounds for binning */
+ __forceinline LBBox3fa bounds() const {
+ return lbounds;
+ }
+
+ /*! returns the number of time segments of this primref */
+ __forceinline unsigned size() const {
+ return lbounds.bounds1.lower.a;
+ }
+
+ __forceinline unsigned totalTimeSegments() const {
+ return lbounds.bounds1.upper.a;
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,float(totalTimeSegments()));
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<=(int)totalTimeSegments());
+ return time_range.lower + time_range.size()*float(i)/float(totalTimeSegments());
+ }
+
+ /*! checks if time range overlaps */
+ __forceinline bool time_range_overlap(const BBox1f& range) const
+ {
+ if (0.9999f*time_range.upper <= range.lower) return false;
+ if (1.0001f*time_range.lower >= range.upper) return false;
+ return true;
+ }
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter() const {
+ return center2(lbounds.interpolate(0.5f));
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(LBBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = binCenter();
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned geomID() const {
+ return lbounds.bounds0.lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned primID() const {
+ return lbounds.bounds0.upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__X86_64__) || defined(__aarch64__)
+ return size_t(lbounds.bounds0.lower.u) + (size_t(lbounds.bounds0.upper.u) << 32);
+#else
+ return size_t(lbounds.bounds0.lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRefMB& p0, const PrimRefMB& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRefMB& ref) {
+ return cout << "{ time_range = " << ref.time_range << ", bounds = " << ref.bounds() << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << ", active_segments = " << ref.size() << ", total_segments = " << ref.totalTimeSegments() << " }";
+ }
+
+ public:
+ LBBox3fx lbounds;
+ BBox1f time_range; // entire geometry time range
+ };
+
+#else
+
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct __aligned(16) PrimRefMB
+ {
+ typedef BBox3fa BBox;
+
+ __forceinline PrimRefMB () {}
+
+ __forceinline PrimRefMB (const LBBox3fa& bounds, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, unsigned int geomID, unsigned int primID)
+ : bbox(bounds.interpolate(0.5f)), _activeTimeSegments(activeTimeSegments), _totalTimeSegments(totalTimeSegments), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+ bbox.lower.a = geomID;
+ bbox.upper.a = primID;
+ }
+
+ __forceinline PrimRefMB (EmptyTy empty, const LBBox3fa& bounds, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : bbox(bounds.interpolate(0.5f)), _activeTimeSegments(activeTimeSegments), _totalTimeSegments(totalTimeSegments), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__X86_64__) || defined(__aarch64__)
+ bbox.lower.u = id & 0xFFFFFFFF;
+ bbox.upper.u = (id >> 32) & 0xFFFFFFFF;
+#else
+ bbox.lower.u = id;
+ bbox.upper.u = 0;
+#endif
+ }
+
+ /*! returns bounds for binning */
+ __forceinline BBox3fa bounds() const {
+ return bbox;
+ }
+
+ /*! returns the number of time segments of this primref */
+ __forceinline unsigned int size() const {
+ return _activeTimeSegments;
+ }
+
+ __forceinline unsigned int totalTimeSegments() const {
+ return _totalTimeSegments;
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,float(_totalTimeSegments));
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<=(int)_totalTimeSegments);
+ return time_range.lower + time_range.size()*float(i)/float(_totalTimeSegments);
+ }
+
+ /*! checks if time range overlaps */
+ __forceinline bool time_range_overlap(const BBox1f& range) const
+ {
+ if (0.9999f*time_range.upper <= range.lower) return false;
+ if (1.0001f*time_range.lower >= range.upper) return false;
+ return true;
+ }
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter() const {
+ return center2(bounds());
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = center2(bounds());
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned int geomID() const {
+ return bbox.lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned int primID() const {
+ return bbox.upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__X86_64__) || defined(__aarch64__)
+ return size_t(bbox.lower.u) + (size_t(bbox.upper.u) << 32);
+#else
+ return size_t(bbox.lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRefMB& p0, const PrimRefMB& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRefMB& ref) {
+ return cout << "{ bounds = " << ref.bounds() << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << ", active_segments = " << ref.size() << ", total_segments = " << ref.totalTimeSegments() << " }";
+ }
+
+ public:
+ BBox3fa bbox; // bounds, geomID, primID
+ unsigned int _activeTimeSegments;
+ unsigned int _totalTimeSegments;
+ BBox1f time_range; // entire geometry time range
+ };
+
+#endif
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/profile.h b/thirdparty/embree-aarch64/kernels/common/profile.h
new file mode 100644
index 0000000000..a7de36414d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/profile.h
@@ -0,0 +1,159 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! helper structure for the implementation of the profile functions below */
+ struct ProfileTimer
+ {
+ static const size_t N = 20;
+
+ ProfileTimer () {}
+
+ ProfileTimer (const size_t numSkip) : i(0), j(0), maxJ(0), numSkip(numSkip), t0(0)
+ {
+ for (size_t i=0; i<N; i++) names[i] = nullptr;
+ for (size_t i=0; i<N; i++) dt_fst[i] = 0.0;
+ for (size_t i=0; i<N; i++) dt_min[i] = pos_inf;
+ for (size_t i=0; i<N; i++) dt_avg[i] = 0.0;
+ for (size_t i=0; i<N; i++) dt_max[i] = neg_inf;
+ }
+
+ __forceinline void begin()
+ {
+ j=0;
+ t0 = tj = getSeconds();
+ }
+
+ __forceinline void end() {
+ absolute("total");
+ i++;
+ }
+
+ __forceinline void operator() (const char* name) {
+ relative(name);
+ }
+
+ __forceinline void absolute (const char* name)
+ {
+ const double t1 = getSeconds();
+ const double dt = t1-t0;
+ assert(names[j] == nullptr || names[j] == name);
+ names[j] = name;
+ if (i == 0) dt_fst[j] = dt;
+ if (i>=numSkip) {
+ dt_min[j] = min(dt_min[j],dt);
+ dt_avg[j] = dt_avg[j] + dt;
+ dt_max[j] = max(dt_max[j],dt);
+ }
+ j++;
+ maxJ = max(maxJ,j);
+ }
+
+ __forceinline void relative (const char* name)
+ {
+ const double t1 = getSeconds();
+ const double dt = t1-tj;
+ tj = t1;
+ assert(names[j] == nullptr || names[j] == name);
+ names[j] = name;
+ if (i == 0) dt_fst[j] = dt;
+ if (i>=numSkip) {
+ dt_min[j] = min(dt_min[j],dt);
+ dt_avg[j] = dt_avg[j] + dt;
+ dt_max[j] = max(dt_max[j],dt);
+ }
+ j++;
+ maxJ = max(maxJ,j);
+ }
+
+ void print(size_t numElements)
+ {
+ for (size_t k=0; k<N; k++)
+ dt_avg[k] /= double(i-numSkip);
+
+ printf(" profile [M/s]:\n");
+ for (size_t j=0; j<maxJ; j++)
+ printf("%20s: fst = %7.2f M/s, min = %7.2f M/s, avg = %7.2f M/s, max = %7.2f M/s\n",
+ names[j],numElements/dt_fst[j]*1E-6,numElements/dt_max[j]*1E-6,numElements/dt_avg[j]*1E-6,numElements/dt_min[j]*1E-6);
+
+ printf(" profile [ms]:\n");
+ for (size_t j=0; j<maxJ; j++)
+ printf("%20s: fst = %7.2f ms, min = %7.2f ms, avg = %7.2f ms, max = %7.2fms\n",
+ names[j],1000.0*dt_fst[j],1000.0*dt_min[j],1000.0*dt_avg[j],1000.0*dt_max[j]);
+ }
+
+ void print()
+ {
+ printf(" profile:\n");
+
+ for (size_t k=0; k<N; k++)
+ dt_avg[k] /= double(i-numSkip);
+
+ for (size_t j=0; j<maxJ; j++) {
+ printf("%20s: fst = %7.2f ms, min = %7.2f ms, avg = %7.2f ms, max = %7.2fms\n",
+ names[j],1000.0*dt_fst[j],1000.0*dt_min[j],1000.0*dt_avg[j],1000.0*dt_max[j]);
+ }
+ }
+
+ double avg() {
+ return dt_avg[maxJ-1]/double(i-numSkip);
+ }
+
+ private:
+ size_t i;
+ size_t j;
+ size_t maxJ;
+ size_t numSkip;
+ double t0;
+ double tj;
+ const char* names[N];
+ double dt_fst[N];
+ double dt_min[N];
+ double dt_avg[N];
+ double dt_max[N];
+ };
+
+ /*! This function executes some code block multiple times and measured sections of it.
+ Use the following way:
+
+ profile(1,10,1000,[&](ProfileTimer& timer) {
+ // code
+ timer("A");
+ // code
+ timer("B");
+ });
+ */
+ template<typename Closure>
+ void profile(const size_t numSkip, const size_t numIter, const size_t numElements, const Closure& closure)
+ {
+ ProfileTimer timer(numSkip);
+
+ for (size_t i=0; i<numSkip+numIter; i++)
+ {
+ timer.begin();
+ closure(timer);
+ timer.end();
+ }
+ timer.print(numElements);
+ }
+
+ /*! similar as the function above, but the timer object comes externally */
+ template<typename Closure>
+ void profile(ProfileTimer& timer, const size_t numSkip, const size_t numIter, const size_t numElements, const Closure& closure)
+ {
+ timer = ProfileTimer(numSkip);
+
+ for (size_t i=0; i<numSkip+numIter; i++)
+ {
+ timer.begin();
+ closure(timer);
+ timer.end();
+ }
+ timer.print(numElements);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/ray.h b/thirdparty/embree-aarch64/kernels/common/ray.h
new file mode 100644
index 0000000000..336d48942c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/ray.h
@@ -0,0 +1,1517 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "instance_stack.h"
+
+// FIXME: if ray gets seperated into ray* and hit, uload4 needs to be adjusted
+
+namespace embree
+{
+ static const size_t MAX_INTERNAL_STREAM_SIZE = 32;
+
+ /* Ray structure for K rays */
+ template<int K>
+ struct RayK
+ {
+ /* Default construction does nothing */
+ __forceinline RayK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayK(const Vec3vf<K>& org, const Vec3vf<K>& dir,
+ const vfloat<K>& tnear = zero, const vfloat<K>& tfar = inf,
+ const vfloat<K>& time = zero, const vint<K>& mask = -1, const vint<K>& id = 0, const vint<K>& flags = 0)
+ : org(org), dir(dir), _tnear(tnear), tfar(tfar), _time(time), mask(mask), id(id), flags(flags) {}
+
+ /* Returns the size of the ray */
+ static __forceinline size_t size() { return K; }
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline vbool<K> valid() const
+ {
+ const vbool<K> vx = (abs(org.x) <= vfloat<K>(FLT_LARGE)) & (abs(dir.x) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vy = (abs(org.y) <= vfloat<K>(FLT_LARGE)) & (abs(dir.y) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vz = (abs(org.z) <= vfloat<K>(FLT_LARGE)) & (abs(dir.z) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vn = abs(tnear()) <= vfloat<K>(inf);
+ const vbool<K> vf = abs(tfar) <= vfloat<K>(inf);
+ return vx & vy & vz & vn & vf;
+ }
+
+ __forceinline void get(RayK<1>* ray) const;
+ __forceinline void get(size_t i, RayK<1>& ray) const;
+ __forceinline void set(const RayK<1>* ray);
+ __forceinline void set(size_t i, const RayK<1>& ray);
+
+ __forceinline void copy(size_t dest, size_t source);
+
+ __forceinline vint<K> octant() const
+ {
+ return select(dir.x < 0.0f, vint<K>(1), vint<K>(zero)) |
+ select(dir.y < 0.0f, vint<K>(2), vint<K>(zero)) |
+ select(dir.z < 0.0f, vint<K>(4), vint<K>(zero));
+ }
+
+ /* Ray data */
+ Vec3vf<K> org; // ray origin
+ vfloat<K> _tnear; // start of ray segment
+ Vec3vf<K> dir; // ray direction
+ vfloat<K> _time; // time of this ray for motion blur
+ vfloat<K> tfar; // end of ray segment
+ vint<K> mask; // used to mask out objects during traversal
+ vint<K> id;
+ vint<K> flags;
+
+ __forceinline vfloat<K>& tnear() { return _tnear; }
+ __forceinline vfloat<K>& time() { return _time; }
+ __forceinline const vfloat<K>& tnear() const { return _tnear; }
+ __forceinline const vfloat<K>& time() const { return _time; }
+ };
+
+ /* Ray+hit structure for K rays */
+ template<int K>
+ struct RayHitK : RayK<K>
+ {
+ using RayK<K>::org;
+ using RayK<K>::_tnear;
+ using RayK<K>::dir;
+ using RayK<K>::_time;
+ using RayK<K>::tfar;
+ using RayK<K>::mask;
+ using RayK<K>::id;
+ using RayK<K>::flags;
+
+ using RayK<K>::tnear;
+ using RayK<K>::time;
+
+ /* Default construction does nothing */
+ __forceinline RayHitK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayHitK(const Vec3vf<K>& org, const Vec3vf<K>& dir,
+ const vfloat<K>& tnear = zero, const vfloat<K>& tfar = inf,
+ const vfloat<K>& time = zero, const vint<K>& mask = -1, const vint<K>& id = 0, const vint<K>& flags = 0)
+ : RayK<K>(org, dir, tnear, tfar, time, mask, id, flags),
+ geomID(RTC_INVALID_GEOMETRY_ID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ __forceinline RayHitK(const RayK<K>& ray)
+ : RayK<K>(ray),
+ geomID(RTC_INVALID_GEOMETRY_ID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ __forceinline RayHitK<K>& operator =(const RayK<K>& ray)
+ {
+ org = ray.org;
+ _tnear = ray._tnear;
+ dir = ray.dir;
+ _time = ray._time;
+ tfar = ray.tfar;
+ mask = ray.mask;
+ id = ray.id;
+ flags = ray.flags;
+
+ geomID = RTC_INVALID_GEOMETRY_ID;
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+
+ return *this;
+ }
+
+ /* Calculates if the hit is valid */
+ __forceinline void verifyHit(const vbool<K>& valid0) const
+ {
+ vbool<K> valid = valid0 & geomID != vuint<K>(RTC_INVALID_GEOMETRY_ID);
+ const vbool<K> vt = (abs(tfar) <= vfloat<K>(FLT_LARGE)) | (tfar == vfloat<K>(neg_inf));
+ const vbool<K> vu = (abs(u) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vv = (abs(u) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vnx = abs(Ng.x) <= vfloat<K>(FLT_LARGE);
+ const vbool<K> vny = abs(Ng.y) <= vfloat<K>(FLT_LARGE);
+ const vbool<K> vnz = abs(Ng.z) <= vfloat<K>(FLT_LARGE);
+ if (any(valid & !vt)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid t");
+ if (any(valid & !vu)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid u");
+ if (any(valid & !vv)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid v");
+ if (any(valid & !vnx)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.x");
+ if (any(valid & !vny)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.y");
+ if (any(valid & !vnz)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.z");
+ }
+
+ __forceinline void get(RayHitK<1>* ray) const;
+ __forceinline void get(size_t i, RayHitK<1>& ray) const;
+ __forceinline void set(const RayHitK<1>* ray);
+ __forceinline void set(size_t i, const RayHitK<1>& ray);
+
+ __forceinline void copy(size_t dest, size_t source);
+
+ /* Hit data */
+ Vec3vf<K> Ng; // geometry normal
+ vfloat<K> u; // barycentric u coordinate of hit
+ vfloat<K> v; // barycentric v coordinate of hit
+ vuint<K> primID; // primitive ID
+ vuint<K> geomID; // geometry ID
+ vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Specialization for a single ray */
+ template<>
+ struct RayK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline RayK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayK(const Vec3fa& org, const Vec3fa& dir, float tnear = zero, float tfar = inf, float time = zero, int mask = -1, int id = 0, int flags = 0)
+ : org(org,tnear), dir(dir,time), tfar(tfar), mask(mask), id(id), flags(flags) {}
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline bool valid() const {
+ return all(le_mask(abs(Vec3fa(org)), Vec3fa(FLT_LARGE)) & le_mask(abs(Vec3fa(dir)), Vec3fa(FLT_LARGE))) && abs(tnear()) <= float(inf) && abs(tfar) <= float(inf);
+ }
+
+ /* Ray data */
+ Vec3ff org; // 3 floats for ray origin, 1 float for tnear
+ //float tnear; // start of ray segment
+ Vec3ff dir; // 3 floats for ray direction, 1 float for time
+ // float time;
+ float tfar; // end of ray segment
+ int mask; // used to mask out objects during traversal
+ int id; // ray ID
+ int flags; // ray flags
+
+ __forceinline float& tnear() { return org.w; };
+ __forceinline const float& tnear() const { return org.w; };
+
+ __forceinline float& time() { return dir.w; };
+ __forceinline const float& time() const { return dir.w; };
+
+ };
+
+ template<>
+ struct RayHitK<1> : RayK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline RayHitK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayHitK(const Vec3fa& org, const Vec3fa& dir, float tnear = zero, float tfar = inf, float time = zero, int mask = -1, int id = 0, int flags = 0)
+ : RayK<1>(org, dir, tnear, tfar, time, mask, id, flags),
+ geomID(RTC_INVALID_GEOMETRY_ID) {}
+
+ __forceinline RayHitK(const RayK<1>& ray)
+ : RayK<1>(ray),
+ geomID(RTC_INVALID_GEOMETRY_ID) {}
+
+ __forceinline RayHitK<1>& operator =(const RayK<1>& ray)
+ {
+ org = ray.org;
+ dir = ray.dir;
+ tfar = ray.tfar;
+ mask = ray.mask;
+ id = ray.id;
+ flags = ray.flags;
+
+ geomID = RTC_INVALID_GEOMETRY_ID;
+
+ return *this;
+ }
+
+ /* Calculates if the hit is valid */
+ __forceinline void verifyHit() const
+ {
+ if (geomID == RTC_INVALID_GEOMETRY_ID) return;
+ const bool vt = (abs(tfar) <= FLT_LARGE) || (tfar == float(neg_inf));
+ const bool vu = (abs(u) <= FLT_LARGE);
+ const bool vv = (abs(u) <= FLT_LARGE);
+ const bool vnx = abs(Ng.x) <= FLT_LARGE;
+ const bool vny = abs(Ng.y) <= FLT_LARGE;
+ const bool vnz = abs(Ng.z) <= FLT_LARGE;
+ if (!vt) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid t");
+ if (!vu) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid u");
+ if (!vv) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid v");
+ if (!vnx) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.x");
+ if (!vny) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.y");
+ if (!vnz) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.z");
+ }
+
+ /* Hit data */
+ Vec3f Ng; // not normalized geometry normal
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Converts ray packet to single rays */
+ template<int K>
+ __forceinline void RayK<K>::get(RayK<1>* ray) const
+ {
+ for (size_t i = 0; i < K; i++) // FIXME: use SIMD transpose
+ {
+ ray[i].org.x = org.x[i]; ray[i].org.y = org.y[i]; ray[i].org.z = org.z[i]; ray[i].tnear() = tnear()[i];
+ ray[i].dir.x = dir.x[i]; ray[i].dir.y = dir.y[i]; ray[i].dir.z = dir.z[i]; ray[i].time() = time()[i];
+ ray[i].tfar = tfar[i]; ray[i].mask = mask[i]; ray[i].id = id[i]; ray[i].flags = flags[i];
+ }
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::get(RayHitK<1>* ray) const
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ get(i, ray[i]);
+ }
+
+ /* Extracts a single ray out of a ray packet*/
+ template<int K>
+ __forceinline void RayK<K>::get(size_t i, RayK<1>& ray) const
+ {
+ ray.org.x = org.x[i]; ray.org.y = org.y[i]; ray.org.z = org.z[i]; ray.tnear() = tnear()[i];
+ ray.dir.x = dir.x[i]; ray.dir.y = dir.y[i]; ray.dir.z = dir.z[i]; ray.time() = time()[i];
+ ray.tfar = tfar[i]; ray.mask = mask[i]; ray.id = id[i]; ray.flags = flags[i];
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::get(size_t i, RayHitK<1>& ray) const
+ {
+ ray.org.x = org.x[i]; ray.org.y = org.y[i]; ray.org.z = org.z[i]; ray.tnear() = tnear()[i];
+ ray.dir.x = dir.x[i]; ray.dir.y = dir.y[i]; ray.dir.z = dir.z[i]; ray.tfar = tfar[i]; ray.time() = time()[i];
+ ray.mask = mask[i]; ray.id = id[i]; ray.flags = flags[i];
+ ray.Ng.x = Ng.x[i]; ray.Ng.y = Ng.y[i]; ray.Ng.z = Ng.z[i];
+ ray.u = u[i]; ray.v = v[i];
+ ray.primID = primID[i]; ray.geomID = geomID[i];
+
+ instance_id_stack::copy(instID, ray.instID, i);
+ }
+
+ /* Converts single rays to ray packet */
+ template<int K>
+ __forceinline void RayK<K>::set(const RayK<1>* ray)
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ set(i, ray[i]);
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::set(const RayHitK<1>* ray)
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ set(i, ray[i]);
+ }
+
+ /* inserts a single ray into a ray packet element */
+ template<int K>
+ __forceinline void RayK<K>::set(size_t i, const RayK<1>& ray)
+ {
+ org.x[i] = ray.org.x; org.y[i] = ray.org.y; org.z[i] = ray.org.z; tnear()[i] = ray.tnear();
+ dir.x[i] = ray.dir.x; dir.y[i] = ray.dir.y; dir.z[i] = ray.dir.z; time()[i] = ray.time();
+ tfar[i] = ray.tfar; mask[i] = ray.mask; id[i] = ray.id; flags[i] = ray.flags;
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::set(size_t i, const RayHitK<1>& ray)
+ {
+ org.x[i] = ray.org.x; org.y[i] = ray.org.y; org.z[i] = ray.org.z; tnear()[i] = ray.tnear();
+ dir.x[i] = ray.dir.x; dir.y[i] = ray.dir.y; dir.z[i] = ray.dir.z; time()[i] = ray.time();
+ tfar[i] = ray.tfar; mask[i] = ray.mask; id[i] = ray.id; flags[i] = ray.flags;
+ Ng.x[i] = ray.Ng.x; Ng.y[i] = ray.Ng.y; Ng.z[i] = ray.Ng.z;
+ u[i] = ray.u; v[i] = ray.v;
+ primID[i] = ray.primID; geomID[i] = ray.geomID;
+
+ instance_id_stack::copy(ray.instID, instID, i);
+ }
+
+ /* copies a ray packet element into another element*/
+ template<int K>
+ __forceinline void RayK<K>::copy(size_t dest, size_t source)
+ {
+ org.x[dest] = org.x[source]; org.y[dest] = org.y[source]; org.z[dest] = org.z[source]; tnear()[dest] = tnear()[source];
+ dir.x[dest] = dir.x[source]; dir.y[dest] = dir.y[source]; dir.z[dest] = dir.z[source]; time()[dest] = time()[source];
+ tfar [dest] = tfar[source]; mask[dest] = mask[source]; id[dest] = id[source]; flags[dest] = flags[source];
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::copy(size_t dest, size_t source)
+ {
+ org.x[dest] = org.x[source]; org.y[dest] = org.y[source]; org.z[dest] = org.z[source]; tnear()[dest] = tnear()[source];
+ dir.x[dest] = dir.x[source]; dir.y[dest] = dir.y[source]; dir.z[dest] = dir.z[source]; time()[dest] = time()[source];
+ tfar [dest] = tfar[source]; mask[dest] = mask[source]; id[dest] = id[source]; flags[dest] = flags[source];
+ Ng.x[dest] = Ng.x[source]; Ng.y[dest] = Ng.y[source]; Ng.z[dest] = Ng.z[source];
+ u[dest] = u[source]; v[dest] = v[source];
+ primID[dest] = primID[source]; geomID[dest] = geomID[source];
+
+ instance_id_stack::copy(instID, instID, source, dest);
+ }
+
+ /* Shortcuts */
+ typedef RayK<1> Ray;
+ typedef RayK<4> Ray4;
+ typedef RayK<8> Ray8;
+ typedef RayK<16> Ray16;
+ struct RayN;
+
+ typedef RayHitK<1> RayHit;
+ typedef RayHitK<4> RayHit4;
+ typedef RayHitK<8> RayHit8;
+ typedef RayHitK<16> RayHit16;
+ struct RayHitN;
+
+ template<int K, bool intersect>
+ struct RayTypeHelper;
+
+ template<int K>
+ struct RayTypeHelper<K, true>
+ {
+ typedef RayHitK<K> Ty;
+ };
+
+ template<int K>
+ struct RayTypeHelper<K, false>
+ {
+ typedef RayK<K> Ty;
+ };
+
+ template<bool intersect>
+ using RayType = typename RayTypeHelper<1, intersect>::Ty;
+
+ template<int K, bool intersect>
+ using RayTypeK = typename RayTypeHelper<K, intersect>::Ty;
+
+ /* Outputs ray to stream */
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const RayK<K>& ray)
+ {
+ return cout << "{ " << embree_endl
+ << " org = " << ray.org << embree_endl
+ << " dir = " << ray.dir << embree_endl
+ << " near = " << ray.tnear() << embree_endl
+ << " far = " << ray.tfar << embree_endl
+ << " time = " << ray.time() << embree_endl
+ << " mask = " << ray.mask << embree_endl
+ << " id = " << ray.id << embree_endl
+ << " flags = " << ray.flags << embree_endl
+ << "}";
+ }
+
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const RayHitK<K>& ray)
+ {
+ cout << "{ " << embree_endl
+ << " org = " << ray.org << embree_endl
+ << " dir = " << ray.dir << embree_endl
+ << " near = " << ray.tnear() << embree_endl
+ << " far = " << ray.tfar << embree_endl
+ << " time = " << ray.time() << embree_endl
+ << " mask = " << ray.mask << embree_endl
+ << " id = " << ray.id << embree_endl
+ << " flags = " << ray.flags << embree_endl
+ << " Ng = " << ray.Ng
+ << " u = " << ray.u << embree_endl
+ << " v = " << ray.v << embree_endl
+ << " primID = " << ray.primID << embree_endl
+ << " geomID = " << ray.geomID << embree_endl
+ << " instID =";
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ {
+ cout << " " << ray.instID[l];
+ }
+ cout << embree_endl;
+ return cout << "}";
+ }
+
+ struct RayStreamSOA
+ {
+ __forceinline RayStreamSOA(void* rays, size_t N)
+ : ptr((char*)rays), N(N) {}
+
+ /* ray data access functions */
+ __forceinline float* org_x(size_t offset = 0) { return (float*)&ptr[0*4*N+offset]; } // x coordinate of ray origin
+ __forceinline float* org_y(size_t offset = 0) { return (float*)&ptr[1*4*N+offset]; } // y coordinate of ray origin
+ __forceinline float* org_z(size_t offset = 0) { return (float*)&ptr[2*4*N+offset]; }; // z coordinate of ray origin
+ __forceinline float* tnear(size_t offset = 0) { return (float*)&ptr[3*4*N+offset]; }; // start of ray segment
+
+ __forceinline float* dir_x(size_t offset = 0) { return (float*)&ptr[4*4*N+offset]; }; // x coordinate of ray direction
+ __forceinline float* dir_y(size_t offset = 0) { return (float*)&ptr[5*4*N+offset]; }; // y coordinate of ray direction
+ __forceinline float* dir_z(size_t offset = 0) { return (float*)&ptr[6*4*N+offset]; }; // z coordinate of ray direction
+ __forceinline float* time (size_t offset = 0) { return (float*)&ptr[7*4*N+offset]; }; // time of this ray for motion blur
+
+ __forceinline float* tfar (size_t offset = 0) { return (float*)&ptr[8*4*N+offset]; }; // end of ray segment (set to hit distance)
+ __forceinline int* mask (size_t offset = 0) { return (int*)&ptr[9*4*N+offset]; }; // used to mask out objects during traversal (optional)
+ __forceinline int* id (size_t offset = 0) { return (int*)&ptr[10*4*N+offset]; }; // id
+ __forceinline int* flags(size_t offset = 0) { return (int*)&ptr[11*4*N+offset]; }; // flags
+
+ /* hit data access functions */
+ __forceinline float* Ng_x(size_t offset = 0) { return (float*)&ptr[12*4*N+offset]; }; // x coordinate of geometry normal
+ __forceinline float* Ng_y(size_t offset = 0) { return (float*)&ptr[13*4*N+offset]; }; // y coordinate of geometry normal
+ __forceinline float* Ng_z(size_t offset = 0) { return (float*)&ptr[14*4*N+offset]; }; // z coordinate of geometry normal
+
+ __forceinline float* u(size_t offset = 0) { return (float*)&ptr[15*4*N+offset]; }; // barycentric u coordinate of hit
+ __forceinline float* v(size_t offset = 0) { return (float*)&ptr[16*4*N+offset]; }; // barycentric v coordinate of hit
+
+ __forceinline unsigned int* primID(size_t offset = 0) { return (unsigned int*)&ptr[17*4*N+offset]; }; // primitive ID
+ __forceinline unsigned int* geomID(size_t offset = 0) { return (unsigned int*)&ptr[18*4*N+offset]; }; // geometry ID
+ __forceinline unsigned int* instID(size_t level, size_t offset = 0) { return (unsigned int*)&ptr[19*4*N+level*4*N+offset]; }; // instance ID
+
+ __forceinline Ray getRayByOffset(size_t offset)
+ {
+ Ray ray;
+ ray.org.x = org_x(offset)[0];
+ ray.org.y = org_y(offset)[0];
+ ray.org.z = org_z(offset)[0];
+ ray.tnear() = tnear(offset)[0];
+ ray.dir.x = dir_x(offset)[0];
+ ray.dir.y = dir_y(offset)[0];
+ ray.dir.z = dir_z(offset)[0];
+ ray.time() = time(offset)[0];
+ ray.tfar = tfar(offset)[0];
+ ray.mask = mask(offset)[0];
+ ray.id = id(offset)[0];
+ ray.flags = flags(offset)[0];
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(org_x(offset));
+ ray.org.y = vfloat<K>::loadu(org_y(offset));
+ ray.org.z = vfloat<K>::loadu(org_z(offset));
+ ray.tnear = vfloat<K>::loadu(tnear(offset));
+ ray.dir.x = vfloat<K>::loadu(dir_x(offset));
+ ray.dir.y = vfloat<K>::loadu(dir_y(offset));
+ ray.dir.z = vfloat<K>::loadu(dir_z(offset));
+ ray.time = vfloat<K>::loadu(time(offset));
+ ray.tfar = vfloat<K>::loadu(tfar(offset));
+ ray.mask = vint<K>::loadu(mask(offset));
+ ray.id = vint<K>::loadu(id(offset));
+ ray.flags = vint<K>::loadu(flags(offset));
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(valid, org_x(offset));
+ ray.org.y = vfloat<K>::loadu(valid, org_y(offset));
+ ray.org.z = vfloat<K>::loadu(valid, org_z(offset));
+ ray.tnear() = vfloat<K>::loadu(valid, tnear(offset));
+ ray.dir.x = vfloat<K>::loadu(valid, dir_x(offset));
+ ray.dir.y = vfloat<K>::loadu(valid, dir_y(offset));
+ ray.dir.z = vfloat<K>::loadu(valid, dir_z(offset));
+ ray.time() = vfloat<K>::loadu(valid, time(offset));
+ ray.tfar = vfloat<K>::loadu(valid, tfar(offset));
+
+#if !defined(__AVX__)
+ /* SSE: some ray members must be loaded with scalar instructions to ensure that we don't cause memory faults,
+ because the SSE masked loads always access the entire vector */
+ if (unlikely(!all(valid)))
+ {
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ ray.mask[k] = mask(offset)[k];
+ ray.id[k] = id(offset)[k];
+ ray.flags[k] = flags(offset)[k];
+ }
+ }
+ }
+ else
+#endif
+ {
+ ray.mask = vint<K>::loadu(valid, mask(offset));
+ ray.id = vint<K>::loadu(valid, id(offset));
+ ray.flags = vint<K>::loadu(valid, flags(offset));
+ }
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayHitK<K>& ray)
+ {
+ /*
+ * valid_i: stores which of the input rays exist (do not access nonexistent rays!)
+ * valid: stores which of the rays actually hit something.
+ */
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ vfloat<K>::storeu(valid, tfar(offset), ray.tfar);
+ vfloat<K>::storeu(valid, Ng_x(offset), ray.Ng.x);
+ vfloat<K>::storeu(valid, Ng_y(offset), ray.Ng.y);
+ vfloat<K>::storeu(valid, Ng_z(offset), ray.Ng.z);
+ vfloat<K>::storeu(valid, u(offset), ray.u);
+ vfloat<K>::storeu(valid, v(offset), ray.v);
+
+#if !defined(__AVX__)
+ /* SSE: some ray members must be stored with scalar instructions to ensure that we don't cause memory faults,
+ because the SSE masked stores always access the entire vector */
+ if (unlikely(!all(valid_i)))
+ {
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ primID(offset)[k] = ray.primID[k];
+ geomID(offset)[k] = ray.geomID[k];
+
+ instID(0, offset)[k] = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ instID(l, offset)[k] = ray.instID[l][k];
+#endif
+ }
+ }
+ }
+ else
+#endif
+ {
+ vuint<K>::storeu(valid, primID(offset), ray.primID);
+ vuint<K>::storeu(valid, geomID(offset), ray.geomID);
+
+ vuint<K>::storeu(valid, instID(0, offset), ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::storeu(valid, instID(l, offset), ray.instID[l]);
+#endif
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ vfloat<K>::storeu(valid, tfar(offset), ray.tfar);
+ }
+
+ __forceinline size_t getOctantByOffset(size_t offset)
+ {
+ const float dx = dir_x(offset)[0];
+ const float dy = dir_y(offset)[0];
+ const float dz = dir_z(offset)[0];
+ const size_t octantID = (dx < 0.0f ? 1 : 0) + (dy < 0.0f ? 2 : 0) + (dz < 0.0f ? 4 : 0);
+ return octantID;
+ }
+
+ __forceinline bool isValidByOffset(size_t offset)
+ {
+ const float nnear = tnear(offset)[0];
+ const float ffar = tfar(offset)[0];
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ RayK<K> ray;
+
+#if defined(__AVX2__)
+ ray.org.x = vfloat<K>::template gather<1>(valid, org_x(), offset);
+ ray.org.y = vfloat<K>::template gather<1>(valid, org_y(), offset);
+ ray.org.z = vfloat<K>::template gather<1>(valid, org_z(), offset);
+ ray.tnear() = vfloat<K>::template gather<1>(valid, tnear(), offset);
+ ray.dir.x = vfloat<K>::template gather<1>(valid, dir_x(), offset);
+ ray.dir.y = vfloat<K>::template gather<1>(valid, dir_y(), offset);
+ ray.dir.z = vfloat<K>::template gather<1>(valid, dir_z(), offset);
+ ray.time() = vfloat<K>::template gather<1>(valid, time(), offset);
+ ray.tfar = vfloat<K>::template gather<1>(valid, tfar(), offset);
+ ray.mask = vint<K>::template gather<1>(valid, mask(), offset);
+ ray.id = vint<K>::template gather<1>(valid, id(), offset);
+ ray.flags = vint<K>::template gather<1>(valid, flags(), offset);
+#else
+ ray.org = zero;
+ ray.tnear() = zero;
+ ray.dir = zero;
+ ray.time() = zero;
+ ray.tfar = zero;
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ const size_t ofs = offset[k];
+
+ ray.org.x[k] = *org_x(ofs);
+ ray.org.y[k] = *org_y(ofs);
+ ray.org.z[k] = *org_z(ofs);
+ ray.tnear()[k] = *tnear(ofs);
+ ray.dir.x[k] = *dir_x(ofs);
+ ray.dir.y[k] = *dir_y(ofs);
+ ray.dir.z[k] = *dir_z(ofs);
+ ray.time()[k] = *time(ofs);
+ ray.tfar[k] = *tfar(ofs);
+ ray.mask[k] = *mask(ofs);
+ ray.id[k] = *id(ofs);
+ ray.flags[k] = *flags(ofs);
+ }
+ }
+#endif
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar(), offset, ray.tfar);
+ vfloat<K>::template scatter<1>(valid, Ng_x(), offset, ray.Ng.x);
+ vfloat<K>::template scatter<1>(valid, Ng_y(), offset, ray.Ng.y);
+ vfloat<K>::template scatter<1>(valid, Ng_z(), offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, u(), offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, v(), offset, ray.v);
+ vuint<K>::template scatter<1>(valid, primID(), offset, ray.primID);
+ vuint<K>::template scatter<1>(valid, geomID(), offset, ray.geomID);
+
+ vuint<K>::template scatter<1>(valid, instID(0), offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, instID(l), offset, ray.instID[l]);
+#endif
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *tfar(ofs) = ray.tfar[k];
+
+ *Ng_x(ofs) = ray.Ng.x[k];
+ *Ng_y(ofs) = ray.Ng.y[k];
+ *Ng_z(ofs) = ray.Ng.z[k];
+ *u(ofs) = ray.u[k];
+ *v(ofs) = ray.v[k];
+ *primID(ofs) = ray.primID[k];
+ *geomID(ofs) = ray.geomID[k];
+
+ *instID(0, ofs) = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *instID(l, ofs) = ray.instID[l][k];
+#endif
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar(), offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *tfar(ofs) = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ char* __restrict__ ptr;
+ size_t N;
+ };
+
+ template<size_t MAX_K>
+ struct StackRayStreamSOA : public RayStreamSOA
+ {
+ __forceinline StackRayStreamSOA(size_t K)
+ : RayStreamSOA(data, K) { assert(K <= MAX_K); }
+
+ char data[MAX_K / 4 * sizeof(RayHit4)];
+ };
+
+
+ struct RayStreamSOP
+ {
+ template<class T>
+ __forceinline void init(T& t)
+ {
+ org_x = (float*)&t.org.x;
+ org_y = (float*)&t.org.y;
+ org_z = (float*)&t.org.z;
+ tnear = (float*)&t.tnear;
+ dir_x = (float*)&t.dir.x;
+ dir_y = (float*)&t.dir.y;
+ dir_z = (float*)&t.dir.z;
+ time = (float*)&t.time;
+ tfar = (float*)&t.tfar;
+ mask = (unsigned int*)&t.mask;
+ id = (unsigned int*)&t.id;
+ flags = (unsigned int*)&t.flags;
+
+ Ng_x = (float*)&t.Ng.x;
+ Ng_y = (float*)&t.Ng.y;
+ Ng_z = (float*)&t.Ng.z;
+ u = (float*)&t.u;
+ v = (float*)&t.v;
+ primID = (unsigned int*)&t.primID;
+ geomID = (unsigned int*)&t.geomID;
+
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = (unsigned int*)&t.instID[l];
+ }
+
+ __forceinline Ray getRayByOffset(size_t offset)
+ {
+ Ray ray;
+ ray.org.x = *(float* __restrict__)((char*)org_x + offset);
+ ray.org.y = *(float* __restrict__)((char*)org_y + offset);
+ ray.org.z = *(float* __restrict__)((char*)org_z + offset);
+ ray.dir.x = *(float* __restrict__)((char*)dir_x + offset);
+ ray.dir.y = *(float* __restrict__)((char*)dir_y + offset);
+ ray.dir.z = *(float* __restrict__)((char*)dir_z + offset);
+ ray.tfar = *(float* __restrict__)((char*)tfar + offset);
+ ray.tnear() = tnear ? *(float* __restrict__)((char*)tnear + offset) : 0.0f;
+ ray.time() = time ? *(float* __restrict__)((char*)time + offset) : 0.0f;
+ ray.mask = mask ? *(unsigned int* __restrict__)((char*)mask + offset) : -1;
+ ray.id = id ? *(unsigned int* __restrict__)((char*)id + offset) : -1;
+ ray.flags = flags ? *(unsigned int* __restrict__)((char*)flags + offset) : -1;
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_x + offset));
+ ray.org.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_y + offset));
+ ray.org.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_z + offset));
+ ray.dir.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_x + offset));
+ ray.dir.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_y + offset));
+ ray.dir.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_z + offset));
+ ray.tfar = vfloat<K>::loadu(valid, (float* __restrict__)((char*)tfar + offset));
+ ray.tnear() = tnear ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)tnear + offset)) : 0.0f;
+ ray.time() = time ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)time + offset)) : 0.0f;
+ ray.mask = mask ? vint<K>::loadu(valid, (const void* __restrict__)((char*)mask + offset)) : -1;
+ ray.id = id ? vint<K>::loadu(valid, (const void* __restrict__)((char*)id + offset)) : -1;
+ ray.flags = flags ? vint<K>::loadu(valid, (const void* __restrict__)((char*)flags + offset)) : -1;
+ return ray;
+ }
+
+ template<int K>
+ __forceinline Vec3vf<K> getDirByOffset(const vbool<K>& valid, size_t offset)
+ {
+ Vec3vf<K> dir;
+ dir.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_x + offset));
+ dir.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_y + offset));
+ dir.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_z + offset));
+ return dir;
+ }
+
+ __forceinline void setHitByOffset(size_t offset, const RayHit& ray)
+ {
+ if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
+ {
+ *(float* __restrict__)((char*)tfar + offset) = ray.tfar;
+
+ if (likely(Ng_x)) *(float* __restrict__)((char*)Ng_x + offset) = ray.Ng.x;
+ if (likely(Ng_y)) *(float* __restrict__)((char*)Ng_y + offset) = ray.Ng.y;
+ if (likely(Ng_z)) *(float* __restrict__)((char*)Ng_z + offset) = ray.Ng.z;
+ *(float* __restrict__)((char*)u + offset) = ray.u;
+ *(float* __restrict__)((char*)v + offset) = ray.v;
+ *(unsigned int* __restrict__)((char*)geomID + offset) = ray.geomID;
+ *(unsigned int* __restrict__)((char*)primID + offset) = ray.primID;
+
+ if (likely(instID[0])) {
+ *(unsigned int* __restrict__)((char*)instID[0] + offset) = ray.instID[0];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *(unsigned int* __restrict__)((char*)instID[l] + offset) = ray.instID[l];
+#endif
+ }
+ }
+ }
+
+ __forceinline void setHitByOffset(size_t offset, const Ray& ray)
+ {
+ *(float* __restrict__)((char*)tfar + offset) = ray.tfar;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)tfar + offset), ray.tfar);
+
+ if (likely(Ng_x)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_x + offset), ray.Ng.x);
+ if (likely(Ng_y)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_y + offset), ray.Ng.y);
+ if (likely(Ng_z)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_z + offset), ray.Ng.z);
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)u + offset), ray.u);
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)v + offset), ray.v);
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)primID + offset), ray.primID);
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)geomID + offset), ray.geomID);
+
+ if (likely(instID[0])) {
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[0] + offset), ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[l] + offset), ray.instID[l]);
+#endif
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)tfar + offset), ray.tfar);
+ }
+
+ __forceinline size_t getOctantByOffset(size_t offset)
+ {
+ const float dx = *(float* __restrict__)((char*)dir_x + offset);
+ const float dy = *(float* __restrict__)((char*)dir_y + offset);
+ const float dz = *(float* __restrict__)((char*)dir_z + offset);
+ const size_t octantID = (dx < 0.0f ? 1 : 0) + (dy < 0.0f ? 2 : 0) + (dz < 0.0f ? 4 : 0);
+ return octantID;
+ }
+
+ __forceinline bool isValidByOffset(size_t offset)
+ {
+ const float nnear = tnear ? *(float* __restrict__)((char*)tnear + offset) : 0.0f;
+ const float ffar = *(float* __restrict__)((char*)tfar + offset);
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline vbool<K> isValidByOffset(const vbool<K>& valid, size_t offset)
+ {
+ const vfloat<K> nnear = tnear ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)tnear + offset)) : 0.0f;
+ const vfloat<K> ffar = vfloat<K>::loadu(valid, (float* __restrict__)((char*)tfar + offset));
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ RayK<K> ray;
+
+#if defined(__AVX2__)
+ ray.org.x = vfloat<K>::template gather<1>(valid, org_x, offset);
+ ray.org.y = vfloat<K>::template gather<1>(valid, org_y, offset);
+ ray.org.z = vfloat<K>::template gather<1>(valid, org_z, offset);
+ ray.dir.x = vfloat<K>::template gather<1>(valid, dir_x, offset);
+ ray.dir.y = vfloat<K>::template gather<1>(valid, dir_y, offset);
+ ray.dir.z = vfloat<K>::template gather<1>(valid, dir_z, offset);
+ ray.tfar = vfloat<K>::template gather<1>(valid, tfar, offset);
+ ray.tnear() = tnear ? vfloat<K>::template gather<1>(valid, tnear, offset) : vfloat<K>(zero);
+ ray.time() = time ? vfloat<K>::template gather<1>(valid, time, offset) : vfloat<K>(zero);
+ ray.mask = mask ? vint<K>::template gather<1>(valid, (int*)mask, offset) : vint<K>(-1);
+ ray.id = id ? vint<K>::template gather<1>(valid, (int*)id, offset) : vint<K>(-1);
+ ray.flags = flags ? vint<K>::template gather<1>(valid, (int*)flags, offset) : vint<K>(-1);
+#else
+ ray.org = zero;
+ ray.tnear() = zero;
+ ray.dir = zero;
+ ray.tfar = zero;
+ ray.time() = zero;
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ const size_t ofs = offset[k];
+
+ ray.org.x[k] = *(float* __restrict__)((char*)org_x + ofs);
+ ray.org.y[k] = *(float* __restrict__)((char*)org_y + ofs);
+ ray.org.z[k] = *(float* __restrict__)((char*)org_z + ofs);
+ ray.dir.x[k] = *(float* __restrict__)((char*)dir_x + ofs);
+ ray.dir.y[k] = *(float* __restrict__)((char*)dir_y + ofs);
+ ray.dir.z[k] = *(float* __restrict__)((char*)dir_z + ofs);
+ ray.tfar[k] = *(float* __restrict__)((char*)tfar + ofs);
+ ray.tnear()[k] = tnear ? *(float* __restrict__)((char*)tnear + ofs) : 0.0f;
+ ray.time()[k] = time ? *(float* __restrict__)((char*)time + ofs) : 0.0f;
+ ray.mask[k] = mask ? *(int* __restrict__)((char*)mask + ofs) : -1;
+ ray.id[k] = id ? *(int* __restrict__)((char*)id + ofs) : -1;
+ ray.flags[k] = flags ? *(int* __restrict__)((char*)flags + ofs) : -1;
+ }
+ }
+#endif
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar, offset, ray.tfar);
+
+ if (likely(Ng_x)) vfloat<K>::template scatter<1>(valid, Ng_x, offset, ray.Ng.x);
+ if (likely(Ng_y)) vfloat<K>::template scatter<1>(valid, Ng_y, offset, ray.Ng.y);
+ if (likely(Ng_z)) vfloat<K>::template scatter<1>(valid, Ng_z, offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, u, offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, v, offset, ray.v);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)geomID, offset, ray.geomID);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)primID, offset, ray.primID);
+
+ if (likely(instID[0])) {
+ vuint<K>::template scatter<1>(valid, (unsigned int*)instID[0], offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, (unsigned int*)instID[l], offset, ray.instID[l]);
+#endif
+ }
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *(float* __restrict__)((char*)tfar + ofs) = ray.tfar[k];
+
+ if (likely(Ng_x)) *(float* __restrict__)((char*)Ng_x + ofs) = ray.Ng.x[k];
+ if (likely(Ng_y)) *(float* __restrict__)((char*)Ng_y + ofs) = ray.Ng.y[k];
+ if (likely(Ng_z)) *(float* __restrict__)((char*)Ng_z + ofs) = ray.Ng.z[k];
+ *(float* __restrict__)((char*)u + ofs) = ray.u[k];
+ *(float* __restrict__)((char*)v + ofs) = ray.v[k];
+ *(unsigned int* __restrict__)((char*)primID + ofs) = ray.primID[k];
+ *(unsigned int* __restrict__)((char*)geomID + ofs) = ray.geomID[k];
+
+ if (likely(instID[0])) {
+ *(unsigned int* __restrict__)((char*)instID[0] + ofs) = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *(unsigned int* __restrict__)((char*)instID[l] + ofs) = ray.instID[l][k];
+#endif
+ }
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar, offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *(float* __restrict__)((char*)tfar + ofs) = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ /* ray data */
+ float* __restrict__ org_x; // x coordinate of ray origin
+ float* __restrict__ org_y; // y coordinate of ray origin
+ float* __restrict__ org_z; // z coordinate of ray origin
+ float* __restrict__ tnear; // start of ray segment (optional)
+
+ float* __restrict__ dir_x; // x coordinate of ray direction
+ float* __restrict__ dir_y; // y coordinate of ray direction
+ float* __restrict__ dir_z; // z coordinate of ray direction
+ float* __restrict__ time; // time of this ray for motion blur (optional)
+
+ float* __restrict__ tfar; // end of ray segment (set to hit distance)
+ unsigned int* __restrict__ mask; // used to mask out objects during traversal (optional)
+ unsigned int* __restrict__ id; // ray ID
+ unsigned int* __restrict__ flags; // ray flags
+
+ /* hit data */
+ float* __restrict__ Ng_x; // x coordinate of geometry normal (optional)
+ float* __restrict__ Ng_y; // y coordinate of geometry normal (optional)
+ float* __restrict__ Ng_z; // z coordinate of geometry normal (optional)
+
+ float* __restrict__ u; // barycentric u coordinate of hit
+ float* __restrict__ v; // barycentric v coordinate of hit
+
+ unsigned int* __restrict__ primID; // primitive ID
+ unsigned int* __restrict__ geomID; // geometry ID
+ unsigned int* __restrict__ instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID (optional)
+ };
+
+
+ struct RayStreamAOS
+ {
+ __forceinline RayStreamAOS(void* rays)
+ : ptr((Ray*)rays) {}
+
+ __forceinline Ray& getRayByOffset(size_t offset)
+ {
+ return *(Ray*)((char*)ptr + offset);
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vint<K>& offset);
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ const vint<K> valid_offset = select(valid, offset, vintx(zero));
+ return getRayByOffset(valid_offset);
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, &ptr->tfar, offset, ray.tfar);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.x, offset, ray.Ng.x);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.y, offset, ray.Ng.y);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.z, offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->u, offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->v, offset, ray.v);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->primID, offset, ray.primID);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->geomID, offset, ray.geomID);
+
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[0], offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[l], offset, ray.instID[l]);
+#endif
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ RayHit* __restrict__ ray_k = (RayHit*)((char*)ptr + offset[k]);
+ ray_k->tfar = ray.tfar[k];
+ ray_k->Ng.x = ray.Ng.x[k];
+ ray_k->Ng.y = ray.Ng.y[k];
+ ray_k->Ng.z = ray.Ng.z[k];
+ ray_k->u = ray.u[k];
+ ray_k->v = ray.v[k];
+ ray_k->primID = ray.primID[k];
+ ray_k->geomID = ray.geomID[k];
+
+ instance_id_stack::copy(ray.instID, ray_k->instID, k);
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, &ptr->tfar, offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ Ray* __restrict__ ray_k = (Ray*)((char*)ptr + offset[k]);
+ ray_k->tfar = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ Ray* __restrict__ ptr;
+ };
+
+ template<>
+ __forceinline Ray4 RayStreamAOS::getRayByOffset(const vint4& offset)
+ {
+ Ray4 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear */
+ const vfloat4 a0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->org);
+ const vfloat4 a1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->org);
+ const vfloat4 a2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->org);
+ const vfloat4 a3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->org);
+
+ transpose(a0,a1,a2,a3, ray.org.x, ray.org.y, ray.org.z, ray.tnear());
+
+ /* load and transpose: dir.x, dir.y, dir.z, time */
+ const vfloat4 b0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->dir);
+ const vfloat4 b1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->dir);
+ const vfloat4 b2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->dir);
+ const vfloat4 b3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->dir);
+
+ transpose(b0,b1,b2,b3, ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->tfar);
+
+ vfloat4 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Ray8 RayStreamAOS::getRayByOffset(const vint8& offset)
+ {
+ Ray8 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[0]))->org);
+ const vfloat8 ab1 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[1]))->org);
+ const vfloat8 ab2 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[2]))->org);
+ const vfloat8 ab3 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[3]))->org);
+ const vfloat8 ab4 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[4]))->org);
+ const vfloat8 ab5 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[5]))->org);
+ const vfloat8 ab6 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[6]))->org);
+ const vfloat8 ab7 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[7]))->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7, ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[4]))->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[5]))->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[6]))->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[7]))->tfar);
+
+ vfloat8 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<>
+ __forceinline Ray16 RayStreamAOS::getRayByOffset(const vint16& offset)
+ {
+ Ray16 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 0]))->org);
+ const vfloat8 ab1 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 1]))->org);
+ const vfloat8 ab2 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 2]))->org);
+ const vfloat8 ab3 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 3]))->org);
+ const vfloat8 ab4 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 4]))->org);
+ const vfloat8 ab5 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 5]))->org);
+ const vfloat8 ab6 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 6]))->org);
+ const vfloat8 ab7 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 7]))->org);
+ const vfloat8 ab8 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 8]))->org);
+ const vfloat8 ab9 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 9]))->org);
+ const vfloat8 ab10 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[10]))->org);
+ const vfloat8 ab11 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[11]))->org);
+ const vfloat8 ab12 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[12]))->org);
+ const vfloat8 ab13 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[13]))->org);
+ const vfloat8 ab14 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[14]))->org);
+ const vfloat8 ab15 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[15]))->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7,ab8,ab9,ab10,ab11,ab12,ab13,ab14,ab15,
+ ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 3]))->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 4]))->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 5]))->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 6]))->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 7]))->tfar);
+ const vfloat4 c8 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 8]))->tfar);
+ const vfloat4 c9 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 9]))->tfar);
+ const vfloat4 c10 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[10]))->tfar);
+ const vfloat4 c11 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[11]))->tfar);
+ const vfloat4 c12 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[12]))->tfar);
+ const vfloat4 c13 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[13]))->tfar);
+ const vfloat4 c14 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[14]))->tfar);
+ const vfloat4 c15 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[15]))->tfar);
+
+ vfloat16 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,
+ ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+
+ struct RayStreamAOP
+ {
+ __forceinline RayStreamAOP(void* rays)
+ : ptr((Ray**)rays) {}
+
+ __forceinline Ray& getRayByIndex(size_t index)
+ {
+ return *ptr[index];
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByIndex(const vint<K>& index);
+
+ template<int K>
+ __forceinline RayK<K> getRayByIndex(const vbool<K>& valid, const vint<K>& index)
+ {
+ const vint<K> valid_index = select(valid, index, vintx(zero));
+ return getRayByIndex(valid_index);
+ }
+
+ template<int K>
+ __forceinline void setHitByIndex(const vbool<K>& valid_i, const vint<K>& index, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ RayHit* __restrict__ ray_k = (RayHit*)ptr[index[k]];
+
+ ray_k->tfar = ray.tfar[k];
+ ray_k->Ng.x = ray.Ng.x[k];
+ ray_k->Ng.y = ray.Ng.y[k];
+ ray_k->Ng.z = ray.Ng.z[k];
+ ray_k->u = ray.u[k];
+ ray_k->v = ray.v[k];
+ ray_k->primID = ray.primID[k];
+ ray_k->geomID = ray.geomID[k];
+ instance_id_stack::copy(ray.instID, ray_k->instID, k);
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByIndex(const vbool<K>& valid_i, const vint<K>& index, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ Ray* __restrict__ ray_k = ptr[index[k]];
+
+ ray_k->tfar = ray.tfar[k];
+ }
+ }
+ }
+
+ Ray** __restrict__ ptr;
+ };
+
+ template<>
+ __forceinline Ray4 RayStreamAOP::getRayByIndex(const vint4& index)
+ {
+ Ray4 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear */
+ const vfloat4 a0 = vfloat4::loadu(&ptr[index[0]]->org);
+ const vfloat4 a1 = vfloat4::loadu(&ptr[index[1]]->org);
+ const vfloat4 a2 = vfloat4::loadu(&ptr[index[2]]->org);
+ const vfloat4 a3 = vfloat4::loadu(&ptr[index[3]]->org);
+
+ transpose(a0,a1,a2,a3, ray.org.x, ray.org.y, ray.org.z, ray.tnear());
+
+ /* load and transpose: dir.x, dir.y, dir.z, time */
+ const vfloat4 b0 = vfloat4::loadu(&ptr[index[0]]->dir);
+ const vfloat4 b1 = vfloat4::loadu(&ptr[index[1]]->dir);
+ const vfloat4 b2 = vfloat4::loadu(&ptr[index[2]]->dir);
+ const vfloat4 b3 = vfloat4::loadu(&ptr[index[3]]->dir);
+
+ transpose(b0,b1,b2,b3, ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+
+ vfloat4 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Ray8 RayStreamAOP::getRayByIndex(const vint8& index)
+ {
+ Ray8 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&ptr[index[0]]->org);
+ const vfloat8 ab1 = vfloat8::loadu(&ptr[index[1]]->org);
+ const vfloat8 ab2 = vfloat8::loadu(&ptr[index[2]]->org);
+ const vfloat8 ab3 = vfloat8::loadu(&ptr[index[3]]->org);
+ const vfloat8 ab4 = vfloat8::loadu(&ptr[index[4]]->org);
+ const vfloat8 ab5 = vfloat8::loadu(&ptr[index[5]]->org);
+ const vfloat8 ab6 = vfloat8::loadu(&ptr[index[6]]->org);
+ const vfloat8 ab7 = vfloat8::loadu(&ptr[index[7]]->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7, ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&ptr[index[4]]->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&ptr[index[5]]->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&ptr[index[6]]->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&ptr[index[7]]->tfar);
+
+ vfloat8 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<>
+ __forceinline Ray16 RayStreamAOP::getRayByIndex(const vint16& index)
+ {
+ Ray16 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&ptr[index[0]]->org);
+ const vfloat8 ab1 = vfloat8::loadu(&ptr[index[1]]->org);
+ const vfloat8 ab2 = vfloat8::loadu(&ptr[index[2]]->org);
+ const vfloat8 ab3 = vfloat8::loadu(&ptr[index[3]]->org);
+ const vfloat8 ab4 = vfloat8::loadu(&ptr[index[4]]->org);
+ const vfloat8 ab5 = vfloat8::loadu(&ptr[index[5]]->org);
+ const vfloat8 ab6 = vfloat8::loadu(&ptr[index[6]]->org);
+ const vfloat8 ab7 = vfloat8::loadu(&ptr[index[7]]->org);
+ const vfloat8 ab8 = vfloat8::loadu(&ptr[index[8]]->org);
+ const vfloat8 ab9 = vfloat8::loadu(&ptr[index[9]]->org);
+ const vfloat8 ab10 = vfloat8::loadu(&ptr[index[10]]->org);
+ const vfloat8 ab11 = vfloat8::loadu(&ptr[index[11]]->org);
+ const vfloat8 ab12 = vfloat8::loadu(&ptr[index[12]]->org);
+ const vfloat8 ab13 = vfloat8::loadu(&ptr[index[13]]->org);
+ const vfloat8 ab14 = vfloat8::loadu(&ptr[index[14]]->org);
+ const vfloat8 ab15 = vfloat8::loadu(&ptr[index[15]]->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7,ab8,ab9,ab10,ab11,ab12,ab13,ab14,ab15,
+ ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&ptr[index[4]]->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&ptr[index[5]]->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&ptr[index[6]]->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&ptr[index[7]]->tfar);
+ const vfloat4 c8 = vfloat4::loadu(&ptr[index[8]]->tfar);
+ const vfloat4 c9 = vfloat4::loadu(&ptr[index[9]]->tfar);
+ const vfloat4 c10 = vfloat4::loadu(&ptr[index[10]]->tfar);
+ const vfloat4 c11 = vfloat4::loadu(&ptr[index[11]]->tfar);
+ const vfloat4 c12 = vfloat4::loadu(&ptr[index[12]]->tfar);
+ const vfloat4 c13 = vfloat4::loadu(&ptr[index[13]]->tfar);
+ const vfloat4 c14 = vfloat4::loadu(&ptr[index[14]]->tfar);
+ const vfloat4 c15 = vfloat4::loadu(&ptr[index[15]]->tfar);
+
+ vfloat16 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,
+ ray.tfar, maskf, idf, flagsf);
+
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/rtcore.cpp b/thirdparty/embree-aarch64/kernels/common/rtcore.cpp
new file mode 100644
index 0000000000..625fbf6d4f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/rtcore.cpp
@@ -0,0 +1,1799 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_EXPORT_API
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "context.h"
+#include "../../include/embree3/rtcore_ray.h"
+
+#if defined(__aarch64__) && defined(BUILD_IOS)
+#include <mutex>
+#endif
+
+using namespace embree;
+
+RTC_NAMESPACE_BEGIN;
+
+ /* mutex to make API thread safe */
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ static std::mutex g_mutex;
+#else
+ static MutexSys g_mutex;
+#endif
+
+ RTC_API RTCDevice rtcNewDevice(const char* config)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewDevice);
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ Device* device = new Device(config);
+ return (RTCDevice) device->refInc();
+ RTC_CATCH_END(nullptr);
+ return (RTCDevice) nullptr;
+ }
+
+ RTC_API void rtcRetainDevice(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainDevice);
+ RTC_VERIFY_HANDLE(hdevice);
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ device->refInc();
+ RTC_CATCH_END(nullptr);
+ }
+
+ RTC_API void rtcReleaseDevice(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseDevice);
+ RTC_VERIFY_HANDLE(hdevice);
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ device->refDec();
+ RTC_CATCH_END(nullptr);
+ }
+
+ RTC_API ssize_t rtcGetDeviceProperty(RTCDevice hdevice, RTCDeviceProperty prop)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetDeviceProperty);
+ RTC_VERIFY_HANDLE(hdevice);
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ return device->getProperty(prop);
+ RTC_CATCH_END(device);
+ return 0;
+ }
+
+ RTC_API void rtcSetDeviceProperty(RTCDevice hdevice, const RTCDeviceProperty prop, ssize_t val)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceProperty);
+ const bool internal_prop = (size_t)prop >= 1000000 && (size_t)prop < 1000004;
+ if (!internal_prop) RTC_VERIFY_HANDLE(hdevice); // allow NULL device for special internal settings
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ device->setProperty(prop,val);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API RTCError rtcGetDeviceError(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetDeviceError);
+ if (device == nullptr) return Device::getThreadErrorCode();
+ else return device->getDeviceErrorCode();
+ RTC_CATCH_END(device);
+ return RTC_ERROR_UNKNOWN;
+ }
+
+ RTC_API void rtcSetDeviceErrorFunction(RTCDevice hdevice, RTCErrorFunction error, void* userPtr)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceErrorFunction);
+ RTC_VERIFY_HANDLE(hdevice);
+ device->setErrorFunction(error, userPtr);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API void rtcSetDeviceMemoryMonitorFunction(RTCDevice hdevice, RTCMemoryMonitorFunction memoryMonitor, void* userPtr)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceMemoryMonitorFunction);
+ device->setMemoryMonitorFunction(memoryMonitor, userPtr);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API RTCBuffer rtcNewBuffer(RTCDevice hdevice, size_t byteSize)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewBuffer);
+ RTC_VERIFY_HANDLE(hdevice);
+ Buffer* buffer = new Buffer((Device*)hdevice, byteSize);
+ return (RTCBuffer)buffer->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API RTCBuffer rtcNewSharedBuffer(RTCDevice hdevice, void* ptr, size_t byteSize)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewSharedBuffer);
+ RTC_VERIFY_HANDLE(hdevice);
+ Buffer* buffer = new Buffer((Device*)hdevice, byteSize, ptr);
+ return (RTCBuffer)buffer->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API void* rtcGetBufferData(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetBufferData);
+ RTC_VERIFY_HANDLE(hbuffer);
+ return buffer->data();
+ RTC_CATCH_END2(buffer);
+ return nullptr;
+ }
+
+ RTC_API void rtcRetainBuffer(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainBuffer);
+ RTC_VERIFY_HANDLE(hbuffer);
+ buffer->refInc();
+ RTC_CATCH_END2(buffer);
+ }
+
+ RTC_API void rtcReleaseBuffer(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseBuffer);
+ RTC_VERIFY_HANDLE(hbuffer);
+ buffer->refDec();
+ RTC_CATCH_END2(buffer);
+ }
+
+ RTC_API RTCScene rtcNewScene (RTCDevice hdevice)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewScene);
+ RTC_VERIFY_HANDLE(hdevice);
+ Scene* scene = new Scene((Device*)hdevice);
+ return (RTCScene) scene->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneDevice);
+ RTC_VERIFY_HANDLE(hscene);
+ return (RTCDevice)scene->device->refInc(); // user will own one additional device reference
+ RTC_CATCH_END2(scene);
+ return (RTCDevice)nullptr;
+ }
+
+ RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene hscene, RTCProgressMonitorFunction progress, void* ptr)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneProgressMonitorFunction);
+ RTC_VERIFY_HANDLE(hscene);
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(g_mutex);
+#else
+ Lock<MutexSys> lock(g_mutex);
+#endif
+ scene->setProgressMonitorFunction(progress,ptr);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetSceneBuildQuality (RTCScene hscene, RTCBuildQuality quality)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneBuildQuality);
+ RTC_VERIFY_HANDLE(hscene);
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH)
+ // -- GODOT start --
+ // throw std::runtime_error("invalid build quality");
+ abort();
+ // -- GODOT end --
+ scene->setBuildQuality(quality);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetSceneFlags (RTCScene hscene, RTCSceneFlags flags)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneFlags);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->setSceneFlags(flags);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API RTCSceneFlags rtcGetSceneFlags(RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneFlags);
+ RTC_VERIFY_HANDLE(hscene);
+ return scene->getSceneFlags();
+ RTC_CATCH_END2(scene);
+ return RTC_SCENE_FLAG_NONE;
+ }
+
+ RTC_API void rtcCommitScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCommitScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->commit(false);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcJoinCommitScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcJoinCommitScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->commit(true);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcGetSceneBounds(RTCScene hscene, RTCBounds* bounds_o)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneBounds);
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ BBox3fa bounds = scene->bounds.bounds();
+ bounds_o->lower_x = bounds.lower.x;
+ bounds_o->lower_y = bounds.lower.y;
+ bounds_o->lower_z = bounds.lower.z;
+ bounds_o->align0 = 0;
+ bounds_o->upper_x = bounds.upper.x;
+ bounds_o->upper_y = bounds.upper.y;
+ bounds_o->upper_z = bounds.upper.z;
+ bounds_o->align1 = 0;
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcGetSceneLinearBounds(RTCScene hscene, RTCLinearBounds* bounds_o)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneBounds);
+ RTC_VERIFY_HANDLE(hscene);
+ if (bounds_o == nullptr)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid destination pointer");
+ if (scene->isModified())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+
+ bounds_o->bounds0.lower_x = scene->bounds.bounds0.lower.x;
+ bounds_o->bounds0.lower_y = scene->bounds.bounds0.lower.y;
+ bounds_o->bounds0.lower_z = scene->bounds.bounds0.lower.z;
+ bounds_o->bounds0.align0 = 0;
+ bounds_o->bounds0.upper_x = scene->bounds.bounds0.upper.x;
+ bounds_o->bounds0.upper_y = scene->bounds.bounds0.upper.y;
+ bounds_o->bounds0.upper_z = scene->bounds.bounds0.upper.z;
+ bounds_o->bounds0.align1 = 0;
+ bounds_o->bounds1.lower_x = scene->bounds.bounds1.lower.x;
+ bounds_o->bounds1.lower_y = scene->bounds.bounds1.lower.y;
+ bounds_o->bounds1.lower_z = scene->bounds.bounds1.lower.z;
+ bounds_o->bounds1.align0 = 0;
+ bounds_o->bounds1.upper_x = scene->bounds.bounds1.upper.x;
+ bounds_o->bounds1.upper_y = scene->bounds.bounds1.upper.y;
+ bounds_o->bounds1.upper_z = scene->bounds.bounds1.upper.z;
+ bounds_o->bounds1.align1 = 0;
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcCollide (RTCScene hscene0, RTCScene hscene1, RTCCollideFunc callback, void* userPtr)
+ {
+ Scene* scene0 = (Scene*) hscene0;
+ Scene* scene1 = (Scene*) hscene1;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCollide);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene0);
+ RTC_VERIFY_HANDLE(hscene1);
+ if (scene0->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (scene1->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (scene0->device != scene1->device) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scenes are from different devices");
+ auto nUserPrims0 = scene0->getNumPrimitives (Geometry::MTY_USER_GEOMETRY, false);
+ auto nUserPrims1 = scene1->getNumPrimitives (Geometry::MTY_USER_GEOMETRY, false);
+ if (scene0->numPrimitives() != nUserPrims0 && scene1->numPrimitives() != nUserPrims1) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scenes must only contain user geometries with a single timestep");
+#endif
+ scene0->intersectors.collide(scene0,scene1,callback,userPtr);
+ RTC_CATCH_END(scene0->device);
+ }
+
+ inline bool pointQuery(Scene* scene, RTCPointQuery* query, RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void* userPtr)
+ {
+ bool changed = false;
+ if (userContext->instStackSize > 0)
+ {
+ const AffineSpace3fa transform = AffineSpace3fa_load_unaligned((AffineSpace3fa*)userContext->world2inst[userContext->instStackSize-1]);
+
+ float similarityScale = 0.f;
+ const bool similtude = similarityTransform(transform, &similarityScale);
+ assert((similtude && similarityScale > 0) || (!similtude && similarityScale == 0.f));
+
+ PointQuery query_inst;
+ query_inst.p = xfmPoint(transform, Vec3fa(query->x, query->y, query->z));
+ query_inst.radius = query->radius * similarityScale;
+ query_inst.time = query->time;
+
+ PointQueryContext context_inst(scene, (PointQuery*)query,
+ similtude ? POINT_QUERY_TYPE_SPHERE : POINT_QUERY_TYPE_AABB,
+ queryFunc, userContext, similarityScale, userPtr);
+ changed = scene->intersectors.pointQuery((PointQuery*)&query_inst, &context_inst);
+ }
+ else
+ {
+ PointQueryContext context(scene, (PointQuery*)query,
+ POINT_QUERY_TYPE_SPHERE, queryFunc, userContext, 1.f, userPtr);
+ changed = scene->intersectors.pointQuery((PointQuery*)query, &context);
+ }
+ return changed;
+ }
+
+ RTC_API bool rtcPointQuery(RTCScene hscene, RTCPointQuery* query, RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void* userPtr)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(userContext);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+ if (((size_t)userContext) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "context not aligned to 16 bytes");
+#endif
+
+ return pointQuery(scene, query, userContext, queryFunc, userPtr);
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery4 (const int* valid, RTCScene hscene, RTCPointQuery4* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery4* query4 = (PointQuery4*)query;
+ PointQuery query1;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ query4->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query4->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery8 (const int* valid, RTCScene hscene, RTCPointQuery8* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery8* query8 = (PointQuery8*)query;
+ PointQuery query1;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ query8->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query8->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery16 (const int* valid, RTCScene hscene, RTCPointQuery16* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery16* query16 = (PointQuery16*)query;
+ PointQuery query1;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ PointQuery query1; query16->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query16->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API void rtcIntersect1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ STAT3(normal.travs,1,1,1);
+ IntersectContext context(scene,user_context);
+ scene->intersectors.intersect(*rayhit,&context);
+#if defined(DEBUG)
+ ((RayHit*)rayhit)->verifyHit();
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit4* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)rayhit) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit4* rayhit4 = (RayHit4*)rayhit;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; rayhit4->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ rayhit4->set(i,ray1);
+ }
+#else
+ scene->intersectors.intersect4(valid,*rayhit,&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit8* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 32 bytes");
+ if (((size_t)rayhit) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 32 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit8* rayhit8 = (RayHit8*) rayhit;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; rayhit8->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ rayhit8->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector8))
+ scene->intersectors.intersect8(valid,*rayhit,&context);
+ else
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,8,1,sizeof(RTCRayHit8),&context);
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit16* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 64 bytes");
+ if (((size_t)rayhit) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 64 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit16* rayhit16 = (RayHit16*) rayhit;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; rayhit16->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ rayhit16->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector16))
+ scene->intersectors.intersect16(valid,*rayhit,&context);
+ else
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,16,1,sizeof(RTCRayHit16),&context);
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect1M (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1M);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit ) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for single rays */
+ if (likely(M == 1)) {
+ if (likely(rayhit->ray.tnear <= rayhit->ray.tfar))
+ scene->intersectors.intersect(*rayhit,&context);
+ }
+
+ /* codepath for streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOS(scene,rayhit,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1M not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect1Mp (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit** rn, unsigned int M)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1Mp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rn) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for single rays */
+ if (likely(M == 1)) {
+ if (likely(rn[0]->ray.tnear <= rn[0]->ray.tfar))
+ scene->intersectors.intersect(*rn[0],&context);
+ }
+
+ /* codepath for streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOP(scene,rn,M,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1Mp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersectNM (RTCScene hscene, RTCIntersectContext* user_context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersectNM);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,N*M,N*M,N*M);
+ IntersectContext context(scene,user_context);
+
+ /* code path for single ray streams */
+ if (likely(N == 1))
+ {
+ /* fast code path for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(((RTCRayHit*)rayhit)->ray.tnear <= ((RTCRayHit*)rayhit)->ray.tfar))
+ scene->intersectors.intersect(*(RTCRayHit*)rayhit,&context);
+ }
+ /* normal codepath for single ray streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOS(scene,(RTCRayHit*)rayhit,M,byteStride,&context);
+ }
+ }
+ /* code path for ray packet streams */
+ else {
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,N,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNM not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersectNp (RTCScene hscene, RTCIntersectContext* user_context, const RTCRayHitNp* rayhit, unsigned int N)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersectNp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit->ray.org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_y not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_z not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_y not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_z not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.tnear not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.time not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.mask not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_x not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_y not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_z not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.u ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.u not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.v ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.v not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.geomID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.geomID not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.primID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.primID not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.instID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.instID not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,N,N,N);
+ IntersectContext context(scene,user_context);
+ scene->device->rayStreamFilters.intersectSOP(scene,rayhit,N,&context);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1);
+ STAT3(shadow.travs,1,1,1);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ IntersectContext context(scene,user_context);
+ scene->intersectors.occluded(*ray,&context);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay4* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray4* ray4 = (Ray4*) ray;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ Ray ray1; ray4->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray4->set(i,ray1);
+ }
+#else
+ scene->intersectors.occluded4(valid,*ray,&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay8* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 32 bytes");
+ if (((size_t)ray) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 32 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray8* ray8 = (Ray8*) ray;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ Ray ray1; ray8->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray8->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector8))
+ scene->intersectors.occluded8(valid,*ray,&context);
+ else
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,8,1,sizeof(RTCRay8),&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay16* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 64 bytes");
+ if (((size_t)ray) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 64 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray16* ray16 = (Ray16*) ray;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ Ray ray1; ray16->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray16->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector16))
+ scene->intersectors.occluded16(valid,*ray,&context);
+ else
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,16,1,sizeof(RTCRay16),&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1M(RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1M);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+ /* fast codepath for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(ray->tnear <= ray->tfar))
+ scene->intersectors.occluded (*ray,&context);
+ }
+ /* codepath for normal streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOS(scene,ray,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1M not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1Mp(RTCScene hscene, RTCIntersectContext* user_context, RTCRay** ray, unsigned int M)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1Mp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(ray[0]->tnear <= ray[0]->tfar))
+ scene->intersectors.occluded (*ray[0],&context);
+ }
+ /* codepath for normal streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOP(scene,ray,M,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1Mp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccludedNM(RTCScene hscene, RTCIntersectContext* user_context, RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccludedNM);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (byteStride < sizeof(RTCRayHit)) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"byteStride too small");
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,N*M,N*N,N*N);
+ IntersectContext context(scene,user_context);
+
+ /* codepath for single rays */
+ if (likely(N == 1))
+ {
+ /* fast path for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(((RTCRay*)ray)->tnear <= ((RTCRay*)ray)->tfar))
+ scene->intersectors.occluded (*(RTCRay*)ray,&context);
+ }
+ /* codepath for normal ray streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOS(scene,(RTCRay*)ray,M,byteStride,&context);
+ }
+ }
+ /* code path for ray packet streams */
+ else {
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,N,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNM not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccludedNp(RTCScene hscene, RTCIntersectContext* user_context, const RTCRayNp* ray, unsigned int N)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccludedNp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray->org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_x not aligned to 4 bytes");
+ if (((size_t)ray->org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_y not aligned to 4 bytes");
+ if (((size_t)ray->org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_z not aligned to 4 bytes");
+ if (((size_t)ray->dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes");
+ if (((size_t)ray->dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_y not aligned to 4 bytes");
+ if (((size_t)ray->dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_z not aligned to 4 bytes");
+ if (((size_t)ray->tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes");
+ if (((size_t)ray->tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "tnear not aligned to 4 bytes");
+ if (((size_t)ray->time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "time not aligned to 4 bytes");
+ if (((size_t)ray->mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,N,N,N);
+ IntersectContext context(scene,user_context);
+ scene->device->rayStreamFilters.occludedSOP(scene,ray,N,&context);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcRetainScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->refInc();
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcReleaseScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->refDec();
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetGeometryInstancedScene(RTCGeometry hgeometry, RTCScene hscene)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ Ref<Scene> scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryInstancedScene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ geometry->setInstancedScene(scene);
+ RTC_CATCH_END2(geometry);
+ }
+
+ AffineSpace3fa loadTransform(RTCFormat format, const float* xfm)
+ {
+ AffineSpace3fa space = one;
+ switch (format)
+ {
+ case RTC_FORMAT_FLOAT3X4_ROW_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 4], xfm[ 8]),
+ Vec3fa(xfm[ 1], xfm[ 5], xfm[ 9]),
+ Vec3fa(xfm[ 2], xfm[ 6], xfm[10]),
+ Vec3fa(xfm[ 3], xfm[ 7], xfm[11]));
+ break;
+
+ case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 1], xfm[ 2]),
+ Vec3fa(xfm[ 3], xfm[ 4], xfm[ 5]),
+ Vec3fa(xfm[ 6], xfm[ 7], xfm[ 8]),
+ Vec3fa(xfm[ 9], xfm[10], xfm[11]));
+ break;
+
+ case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 1], xfm[ 2]),
+ Vec3fa(xfm[ 4], xfm[ 5], xfm[ 6]),
+ Vec3fa(xfm[ 8], xfm[ 9], xfm[10]),
+ Vec3fa(xfm[12], xfm[13], xfm[14]));
+ break;
+
+ default:
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format");
+ break;
+ }
+ return space;
+ }
+
+ void storeTransform(const AffineSpace3fa& space, RTCFormat format, float* xfm)
+ {
+ switch (format)
+ {
+ case RTC_FORMAT_FLOAT3X4_ROW_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vy.x; xfm[ 2] = space.l.vz.x; xfm[ 3] = space.p.x;
+ xfm[ 4] = space.l.vx.y; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vz.y; xfm[ 7] = space.p.y;
+ xfm[ 8] = space.l.vx.z; xfm[ 9] = space.l.vy.z; xfm[10] = space.l.vz.z; xfm[11] = space.p.z;
+ break;
+
+ case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z;
+ xfm[ 3] = space.l.vy.x; xfm[ 4] = space.l.vy.y; xfm[ 5] = space.l.vy.z;
+ xfm[ 6] = space.l.vz.x; xfm[ 7] = space.l.vz.y; xfm[ 8] = space.l.vz.z;
+ xfm[ 9] = space.p.x; xfm[10] = space.p.y; xfm[11] = space.p.z;
+ break;
+
+ case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; xfm[ 3] = 0.f;
+ xfm[ 4] = space.l.vy.x; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vy.z; xfm[ 7] = 0.f;
+ xfm[ 8] = space.l.vz.x; xfm[ 9] = space.l.vz.y; xfm[10] = space.l.vz.z; xfm[11] = 0.f;
+ xfm[12] = space.p.x; xfm[13] = space.p.y; xfm[14] = space.p.z; xfm[15] = 1.f;
+ break;
+
+ default:
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format");
+ break;
+ }
+ }
+
+ RTC_API void rtcSetGeometryTransform(RTCGeometry hgeometry, unsigned int timeStep, RTCFormat format, const void* xfm)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTransform);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(xfm);
+ const AffineSpace3fa transform = loadTransform(format, (const float*)xfm);
+ geometry->setTransform(transform, timeStep);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTransformQuaternion(RTCGeometry hgeometry, unsigned int timeStep, const RTCQuaternionDecomposition* qd)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTransformQuaternion);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(qd);
+
+ AffineSpace3fx transform;
+ transform.l.vx.x = qd->scale_x;
+ transform.l.vy.y = qd->scale_y;
+ transform.l.vz.z = qd->scale_z;
+ transform.l.vy.x = qd->skew_xy;
+ transform.l.vz.x = qd->skew_xz;
+ transform.l.vz.y = qd->skew_yz;
+ transform.l.vx.y = qd->translation_x;
+ transform.l.vx.z = qd->translation_y;
+ transform.l.vy.z = qd->translation_z;
+ transform.p.x = qd->shift_x;
+ transform.p.y = qd->shift_y;
+ transform.p.z = qd->shift_z;
+
+ // normalize quaternion
+ Quaternion3f q(qd->quaternion_r, qd->quaternion_i, qd->quaternion_j, qd->quaternion_k);
+ q = normalize(q);
+ transform.l.vx.w = q.i;
+ transform.l.vy.w = q.j;
+ transform.l.vz.w = q.k;
+ transform.p.w = q.r;
+
+ geometry->setQuaternionDecomposition(transform, timeStep);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcGetGeometryTransform(RTCGeometry hgeometry, float time, RTCFormat format, void* xfm)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryTransform);
+ const AffineSpace3fa transform = geometry->getTransform(time);
+ storeTransform(transform, format, (float*)xfm);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args)
+ {
+ IntersectFunctionNArguments* args = (IntersectFunctionNArguments*) args_i;
+ args->report(args,filter_args);
+ }
+
+ RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args)
+ {
+ OccludedFunctionNArguments* args = (OccludedFunctionNArguments*) args_i;
+ args->report(args,filter_args);
+ }
+
+ RTC_API RTCGeometry rtcNewGeometry (RTCDevice hdevice, RTCGeometryType type)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewGeometry);
+ RTC_VERIFY_HANDLE(hdevice);
+
+ switch (type)
+ {
+ case RTC_GEOMETRY_TYPE_TRIANGLE:
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ createTriangleMeshTy createTriangleMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createTriangleMesh);
+ Geometry* geom = createTriangleMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_TRIANGLE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_QUAD:
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ createQuadMeshTy createQuadMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createQuadMesh);
+ Geometry* geom = createQuadMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_QUAD is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_SPHERE_POINT:
+ case RTC_GEOMETRY_TYPE_DISC_POINT:
+ case RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT:
+ {
+#if defined(EMBREE_GEOMETRY_POINT)
+ createPointsTy createPoints = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_builder_cpu_features, createPoints);
+
+ Geometry *geom;
+ switch(type) {
+ case RTC_GEOMETRY_TYPE_SPHERE_POINT:
+ geom = createPoints(device, Geometry::GTY_SPHERE_POINT);
+ break;
+ case RTC_GEOMETRY_TYPE_DISC_POINT:
+ geom = createPoints(device, Geometry::GTY_DISC_POINT);
+ break;
+ case RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT:
+ geom = createPoints(device, Geometry::GTY_ORIENTED_DISC_POINT);
+ break;
+ default:
+ geom = nullptr;
+ break;
+ }
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_POINT is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE:
+ case RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE:
+ {
+#if defined(EMBREE_GEOMETRY_CURVE)
+ createLineSegmentsTy createLineSegments = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createLineSegments);
+ createCurvesTy createCurves = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createCurves);
+
+ Geometry* geom;
+ switch (type) {
+ case RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_CONE_LINEAR_CURVE); break;
+ case RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_ROUND_LINEAR_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_FLAT_LINEAR_CURVE); break;
+ //case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_ORIENTED_LINEAR_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_BEZIER_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_BEZIER_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_BEZIER_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_BSPLINE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_BSPLINE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_BSPLINE_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_HERMITE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_HERMITE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_HERMITE_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_CATMULL_ROM_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_CATMULL_ROM_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_CATMULL_ROM_CURVE); break;
+ default: geom = nullptr; break;
+ }
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_CURVE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_SUBDIVISION:
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ createSubdivMeshTy createSubdivMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX(device->enabled_cpu_features,createSubdivMesh);
+ //SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createSubdivMesh); // FIXME: this does not work for some reason?
+ Geometry* geom = createSubdivMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_SUBDIVISION is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_USER:
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ createUserGeometryTy createUserGeometry = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createUserGeometry);
+ Geometry* geom = createUserGeometry(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_USER is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_INSTANCE:
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ createInstanceTy createInstance = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createInstance);
+ Geometry* geom = createInstance(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_INSTANCE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_GRID:
+ {
+#if defined(EMBREE_GEOMETRY_GRID)
+ createGridMeshTy createGridMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512KNL_AVX512SKX(device->enabled_cpu_features,createGridMesh);
+ Geometry* geom = createGridMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_GRID is not supported");
+#endif
+ }
+
+ default:
+ throw_RTCError(RTC_ERROR_UNKNOWN,"invalid geometry type");
+ }
+
+ RTC_CATCH_END(device);
+ return nullptr;
+ }
+
+ RTC_API void rtcSetGeometryUserPrimitiveCount(RTCGeometry hgeometry, unsigned int userPrimitiveCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryUserPrimitiveCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (unlikely(geometry->getType() != Geometry::GTY_USER_GEOMETRY))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation only allowed for user geometries");
+
+ geometry->setNumPrimitives(userPrimitiveCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTimeStepCount(RTCGeometry hgeometry, unsigned int timeStepCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTimeStepCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (timeStepCount > RTC_MAX_TIME_STEP_COUNT)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"number of time steps is out of range");
+
+ geometry->setNumTimeSteps(timeStepCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTimeRange(RTCGeometry hgeometry, float startTime, float endTime)
+ {
+ Ref<Geometry> geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTimeRange);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (startTime > endTime)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"startTime has to be smaller or equal to the endTime");
+
+ geometry->setTimeRange(BBox1f(startTime,endTime));
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryVertexAttributeCount(RTCGeometry hgeometry, unsigned int N)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryVertexAttributeCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setVertexAttributeCount(N);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTopologyCount(RTCGeometry hgeometry, unsigned int N)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTopologyCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setTopologyCount(N);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryBuildQuality (RTCGeometry hgeometry, RTCBuildQuality quality)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBuildQuality);
+ RTC_VERIFY_HANDLE(hgeometry);
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH &&
+ quality != RTC_BUILD_QUALITY_REFIT)
+ // -- GODOT start --
+ // throw std::runtime_error("invalid build quality");
+ abort();
+ // -- GODOT end --
+ geometry->setBuildQuality(quality);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryMaxRadiusScale(RTCGeometry hgeometry, float maxRadiusScale)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryMaxRadiusScale);
+ RTC_VERIFY_HANDLE(hgeometry);
+#if RTC_MIN_WIDTH
+ if (maxRadiusScale < 1.0f) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximal radius scale has to be larger or equal to 1");
+ geometry->setMaxRadiusScale(maxRadiusScale);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"min-width feature is not enabled");
+#endif
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryMask (RTCGeometry hgeometry, unsigned int mask)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryMask);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setMask(mask);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometrySubdivisionMode (RTCGeometry hgeometry, unsigned topologyID, RTCSubdivisionMode mode)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometrySubdivisionMode);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setSubdivisionMode(topologyID,mode);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryVertexAttributeTopology(RTCGeometry hgeometry, unsigned int vertexAttributeID, unsigned int topologyID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryVertexAttributeTopology);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setVertexAttributeTopology(vertexAttributeID, topologyID);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, RTCBuffer hbuffer, size_t byteOffset, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ Ref<Buffer> buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(hbuffer);
+
+ if (geometry->device != buffer->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ geometry->setBuffer(type, slot, format, buffer, byteOffset, byteStride, (unsigned int)itemCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetSharedGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, const void* ptr, size_t byteOffset, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSharedGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ Ref<Buffer> buffer = new Buffer(geometry->device, itemCount*byteStride, (char*)ptr + byteOffset);
+ geometry->setBuffer(type, slot, format, buffer, 0, byteStride, (unsigned int)itemCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void* rtcSetNewGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetNewGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ /* vertex buffers need to get overallocated slightly as elements are accessed using SSE loads */
+ size_t bytes = itemCount*byteStride;
+ if (type == RTC_BUFFER_TYPE_VERTEX || type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ bytes += (16 - (byteStride%16))%16;
+
+ Ref<Buffer> buffer = new Buffer(geometry->device, bytes);
+ geometry->setBuffer(type, slot, format, buffer, 0, byteStride, (unsigned int)itemCount);
+ return buffer->data();
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void* rtcGetGeometryBufferData(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryBufferData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->getBuffer(type, slot);
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void rtcEnableGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcEnableGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->enable();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcUpdateGeometryBuffer (RTCGeometry hgeometry, RTCBufferType type, unsigned int slot)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcUpdateGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->updateBuffer(type, slot);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcDisableGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcDisableGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->disable();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTessellationRate (RTCGeometry hgeometry, float tessellationRate)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTessellationRate);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setTessellationRate(tessellationRate);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryUserData (RTCGeometry hgeometry, void* ptr)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryUserData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setUserData(ptr);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void* rtcGetGeometryUserData (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry; // no ref counting here!
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryUserData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->getUserData();
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void rtcSetGeometryBoundsFunction (RTCGeometry hgeometry, RTCBoundsFunction bounds, void* userPtr)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBoundsFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setBoundsFunction(bounds,userPtr);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryDisplacementFunction (RTCGeometry hgeometry, RTCDisplacementFunctionN displacement)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryDisplacementFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setDisplacementFunction(displacement);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryIntersectFunction (RTCGeometry hgeometry, RTCIntersectFunctionN intersect)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryIntersectFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setIntersectFunctionN(intersect);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryPointQueryFunction(RTCGeometry hgeometry, RTCPointQueryFunction pointQuery)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryPointQueryFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setPointQueryFunction(pointQuery);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API unsigned int rtcGetGeometryFirstHalfEdge(RTCGeometry hgeometry, unsigned int faceID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryFirstHalfEdge);
+ return geometry->getFirstHalfEdge(faceID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryFace(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryFace);
+ return geometry->getFace(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryNextHalfEdge(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryNextHalfEdge);
+ return geometry->getNextHalfEdge(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryPreviousHalfEdge(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryPreviousHalfEdge);
+ return geometry->getPreviousHalfEdge(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryOppositeHalfEdge(RTCGeometry hgeometry, unsigned int topologyID, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryOppositeHalfEdge);
+ return geometry->getOppositeHalfEdge(topologyID,edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API void rtcSetGeometryOccludedFunction (RTCGeometry hgeometry, RTCOccludedFunctionN occluded)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetOccludedFunctionN);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setOccludedFunctionN(occluded);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryIntersectFilterFunction (RTCGeometry hgeometry, RTCFilterFunctionN filter)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryIntersectFilterFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setIntersectionFilterFunctionN(filter);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryOccludedFilterFunction (RTCGeometry hgeometry, RTCFilterFunctionN filter)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryOccludedFilterFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setOcclusionFilterFunctionN(filter);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcInterpolate(const RTCInterpolateArguments* const args)
+ {
+ Geometry* geometry = (Geometry*) args->geometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcInterpolate);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(args->geometry);
+#endif
+ geometry->interpolate(args);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcInterpolateN(const RTCInterpolateNArguments* const args)
+ {
+ Geometry* geometry = (Geometry*) args->geometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcInterpolateN);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(args->geometry);
+#endif
+ geometry->interpolateN(args);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcCommitGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCommitGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->commit();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API unsigned int rtcAttachGeometry (RTCScene hscene, RTCGeometry hgeometry)
+ {
+ Scene* scene = (Scene*) hscene;
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcAttachGeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ if (scene->device != geometry->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+ return scene->bind(RTC_INVALID_GEOMETRY_ID,geometry);
+ RTC_CATCH_END2(scene);
+ return -1;
+ }
+
+ RTC_API void rtcAttachGeometryByID (RTCScene hscene, RTCGeometry hgeometry, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcAttachGeometryByID);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_GEOMID(geomID);
+ if (scene->device != geometry->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+ scene->bind(geomID,geometry);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcDetachGeometry (RTCScene hscene, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcDetachGeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_GEOMID(geomID);
+ scene->detachGeometry(geomID);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcRetainGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->refInc();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcReleaseGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->refDec();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API RTCGeometry rtcGetGeometry (RTCScene hscene, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometry);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_GEOMID(geomID);
+#endif
+ return (RTCGeometry) scene->get(geomID);
+ RTC_CATCH_END2(scene);
+ return nullptr;
+ }
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree-aarch64/kernels/common/rtcore.h b/thirdparty/embree-aarch64/kernels/common/rtcore.h
new file mode 100644
index 0000000000..4b070e122b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/rtcore.h
@@ -0,0 +1,142 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../include/embree3/rtcore.h"
+RTC_NAMESPACE_USE
+
+namespace embree
+{
+ /*! decoding of intersection flags */
+ __forceinline bool isCoherent (RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_COHERENT; }
+ __forceinline bool isIncoherent(RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT; }
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR >= 8)
+# define USE_TASK_ARENA 1
+#else
+# define USE_TASK_ARENA 0
+#endif
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION >= 11009) // TBB 2019 Update 9
+# define TASKING_TBB_USE_TASK_ISOLATION 1
+#else
+# define TASKING_TBB_USE_TASK_ISOLATION 0
+#endif
+
+/*! Macros used in the rtcore API implementation */
+// -- GODOT start --
+// #define RTC_CATCH_BEGIN try {
+#define RTC_CATCH_BEGIN
+
+// #define RTC_CATCH_END(device) \
+// } catch (std::bad_alloc&) { \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// } catch (rtcore_error& e) { \
+// Device::process_error(device,e.error,e.what()); \
+// } catch (std::exception& e) { \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// } catch (...) { \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// }
+#define RTC_CATCH_END(device)
+
+// #define RTC_CATCH_END2(scene) \
+// } catch (std::bad_alloc&) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// } catch (rtcore_error& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,e.error,e.what()); \
+// } catch (std::exception& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// } catch (...) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// }
+#define RTC_CATCH_END2(scene)
+
+// #define RTC_CATCH_END2_FALSE(scene) \
+// } catch (std::bad_alloc&) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// return false; \
+// } catch (rtcore_error& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,e.error,e.what()); \
+// return false; \
+// } catch (std::exception& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// return false; \
+// } catch (...) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// return false; \
+// }
+#define RTC_CATCH_END2_FALSE(scene) return false;
+// -- GODOT end --
+
+#define RTC_VERIFY_HANDLE(handle) \
+ if (handle == nullptr) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_GEOMID(id) \
+ if (id == RTC_INVALID_GEOMETRY_ID) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_UPPER(id,upper) \
+ if (id > upper) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_RANGE(id,lower,upper) \
+ if (id < lower || id > upper) \
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"argument out of bounds");
+
+#if 0 // enable to debug print all API calls
+#define RTC_TRACE(x) std::cout << #x << std::endl;
+#else
+#define RTC_TRACE(x)
+#endif
+
+// -- GODOT begin --
+// /*! used to throw embree API errors */
+// struct rtcore_error : public std::exception
+// {
+// __forceinline rtcore_error(RTCError error, const std::string& str)
+// : error(error), str(str) {}
+//
+// ~rtcore_error() throw() {}
+//
+// const char* what () const throw () {
+// return str.c_str();
+// }
+//
+// RTCError error;
+// std::string str;
+// };
+// -- GODOT end --
+
+#if defined(DEBUG) // only report file and line in debug mode
+ // -- GODOT begin --
+ // #define throw_RTCError(error,str) \
+ // throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define throw_RTCError(error,str) \
+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ // -- GODOT end --
+#else
+ // -- GODOT begin --
+ // #define throw_RTCError(error,str) \
+ // throw rtcore_error(error,str);
+ #define throw_RTCError(error,str) \
+ abort();
+ // -- GODOT end --
+#endif
+
+#define RTC_BUILD_ARGUMENTS_HAS(settings,member) \
+ (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member)))
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/rtcore_builder.cpp b/thirdparty/embree-aarch64/kernels/common/rtcore_builder.cpp
new file mode 100644
index 0000000000..6bb96bba07
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/rtcore_builder.cpp
@@ -0,0 +1,442 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_EXPORT_API
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "context.h"
+#include "alloc.h"
+
+#include "../builders/bvh_builder_sah.h"
+#include "../builders/bvh_builder_morton.h"
+
+namespace embree
+{
+ namespace isa // FIXME: support more ISAs for builders
+ {
+ struct BVH : public RefCount
+ {
+ BVH (Device* device)
+ : device(device), allocator(device,true), morton_src(device,0), morton_tmp(device,0)
+ {
+ device->refInc();
+ }
+
+ ~BVH() {
+ device->refDec();
+ }
+
+ public:
+ Device* device;
+ FastAllocator allocator;
+ mvector<BVHBuilderMorton::BuildPrim> morton_src;
+ mvector<BVHBuilderMorton::BuildPrim> morton_tmp;
+ };
+
+ void* rtcBuildBVHMorton(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims_i = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* initialize temporary arrays for morton builder */
+ PrimRef* prims = (PrimRef*) prims_i;
+ mvector<BVHBuilderMorton::BuildPrim>& morton_src = bvh->morton_src;
+ mvector<BVHBuilderMorton::BuildPrim>& morton_tmp = bvh->morton_tmp;
+ morton_src.resize(primitiveCount);
+ morton_tmp.resize(primitiveCount);
+
+ /* compute centroid bounds */
+ const BBox3fa centBounds = parallel_reduce ( size_t(0), primitiveCount, BBox3fa(empty), [&](const range<size_t>& r) -> BBox3fa {
+
+ BBox3fa bounds(empty);
+ for (size_t i=r.begin(); i<r.end(); i++)
+ bounds.extend(prims[i].bounds().center2());
+ return bounds;
+ }, BBox3fa::merge);
+
+ /* compute morton codes */
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_for ( size_t(0), primitiveCount, [&](const range<size_t>& r) {
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton_src[r.begin()]);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ generator(prims[i].bounds(),(unsigned) i);
+ }
+ });
+
+ /* start morton build */
+ std::pair<void*,BBox3fa> root = BVHBuilderMorton::build<std::pair<void*,BBox3fa>>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that allocates BVH nodes */
+ [&] ( const FastAllocator::CachedAllocator& alloc, size_t N ) -> void* {
+ return createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ },
+
+ /* lambda function that sets bounds */
+ [&] (void* node, const std::pair<void*,BBox3fa>* children, size_t N) -> std::pair<void*,BBox3fa>
+ {
+ BBox3fa bounds = empty;
+ void* childptrs[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
+ const RTCBounds* cbounds[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) {
+ bounds.extend(children[i].second);
+ childptrs[i] = children[i].first;
+ cbounds[i] = (const RTCBounds*)&children[i].second;
+ }
+ setNodeBounds(node,cbounds,(unsigned int)N,userPtr);
+ setNodeChildren(node,childptrs, (unsigned int)N,userPtr);
+ return std::make_pair(node,bounds);
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&]( const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc) -> std::pair<void*,BBox3fa>
+ {
+ RTCBuildPrimitive localBuildPrims[RTC_BUILD_MAX_PRIMITIVES_PER_LEAF];
+ BBox3fa bounds = empty;
+ for (size_t i=0;i<current.size();i++)
+ {
+ const size_t id = morton_src[current.begin()+i].index;
+ bounds.extend(prims[id].bounds());
+ localBuildPrims[i] = prims_i[id];
+ }
+ void* node = createLeaf((RTCThreadLocalAllocator)&alloc,localBuildPrims,current.size(),userPtr);
+ return std::make_pair(node,bounds);
+ },
+
+ /* lambda that calculates the bounds for some primitive */
+ [&] (const BVHBuilderMorton::BuildPrim& morton) -> BBox3fa {
+ return prims[morton.index].bounds();
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ morton_src.data(),morton_tmp.data(),primitiveCount,
+ *arguments);
+
+ bvh->allocator.cleanup();
+ return root.first;
+ }
+
+ void* rtcBuildBVHBinnedSAH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* calculate priminfo */
+ auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
+ {
+ CentGeomBBox3fa bounds(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ bounds.extend((BBox3fa&)prims[j]);
+ return bounds;
+ };
+ const CentGeomBBox3fa bounds =
+ parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
+
+ const PrimInfo pinfo(0,primitiveCount,bounds);
+
+ /* build BVH */
+ void* root = BVHBuilderBinnedSAH::build<void*>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that creates BVH nodes */
+ [&](BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
+ {
+ void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
+ setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that updates BVH nodes */
+ [&](const BVHBuilderBinnedSAH::BuildRecord& precord, const BVHBuilderBinnedSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
+ setNodeChildren(node,children, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&](const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
+ return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ (PrimRef*)prims,pinfo,*arguments);
+
+ bvh->allocator.cleanup();
+ return root;
+ }
+
+ static __forceinline const std::pair<CentGeomBBox3fa,unsigned int> mergePair(const std::pair<CentGeomBBox3fa,unsigned int>& a, const std::pair<CentGeomBBox3fa,unsigned int>& b) {
+ CentGeomBBox3fa centBounds = CentGeomBBox3fa::merge2(a.first,b.first);
+ unsigned int maxGeomID = max(a.second,b.second);
+ return std::pair<CentGeomBBox3fa,unsigned int>(centBounds,maxGeomID);
+ }
+
+ void* rtcBuildBVHSpatialSAH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCSplitPrimitiveFunction splitPrimitive = arguments->splitPrimitive;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* calculate priminfo */
+
+ auto computeBounds = [&](const range<size_t>& r) -> std::pair<CentGeomBBox3fa,unsigned int>
+ {
+ CentGeomBBox3fa bounds(empty);
+ unsigned maxGeomID = 0;
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ bounds.extend((BBox3fa&)prims[j]);
+ maxGeomID = max(maxGeomID,prims[j].geomID);
+ }
+ return std::pair<CentGeomBBox3fa,unsigned int>(bounds,maxGeomID);
+ };
+
+
+ const std::pair<CentGeomBBox3fa,unsigned int> pair =
+ parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),std::pair<CentGeomBBox3fa,unsigned int>(CentGeomBBox3fa(empty),0), computeBounds, mergePair);
+
+ CentGeomBBox3fa bounds = pair.first;
+ const unsigned int maxGeomID = pair.second;
+
+ if (unlikely(maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS))))
+ {
+ /* fallback code for max geomID larger than threshold */
+ return rtcBuildBVHBinnedSAH(arguments);
+ }
+
+ const PrimInfo pinfo(0,primitiveCount,bounds);
+
+ /* function that splits a build primitive */
+ struct Splitter
+ {
+ Splitter (RTCSplitPrimitiveFunction splitPrimitive, unsigned geomID, unsigned primID, void* userPtr)
+ : splitPrimitive(splitPrimitive), geomID(geomID), primID(primID), userPtr(userPtr) {}
+
+ __forceinline void operator() (PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const
+ {
+ prim.geomIDref() &= BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK;
+ splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
+ left_o.geomIDref() = geomID; left_o.primIDref() = primID;
+ right_o.geomIDref() = geomID; right_o.primIDref() = primID;
+ }
+
+ __forceinline void operator() (const BBox3fa& box, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const
+ {
+ PrimRef prim(box,geomID & BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK,primID);
+ splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
+ }
+
+ RTCSplitPrimitiveFunction splitPrimitive;
+ unsigned geomID;
+ unsigned primID;
+ void* userPtr;
+ };
+
+ /* build BVH */
+ void* root = BVHBuilderBinnedFastSpatialSAH::build<void*>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that creates BVH nodes */
+ [&] (BVHBuilderBinnedFastSpatialSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
+ {
+ void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
+ setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that updates BVH nodes */
+ [&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& precord, const BVHBuilderBinnedFastSpatialSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
+ setNodeChildren(node,children, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
+ return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
+ },
+
+ /* returns the splitter */
+ [&] ( const PrimRef& prim ) -> Splitter {
+ return Splitter(splitPrimitive,prim.geomID(),prim.primID(),userPtr);
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ (PrimRef*)prims,
+ arguments->primitiveArrayCapacity,
+ pinfo,*arguments);
+
+ bvh->allocator.cleanup();
+ return root;
+ }
+ }
+}
+
+using namespace embree;
+using namespace embree::isa;
+
+RTC_NAMESPACE_BEGIN
+
+ RTC_API RTCBVH rtcNewBVH(RTCDevice device)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewAllocator);
+ RTC_VERIFY_HANDLE(device);
+ BVH* bvh = new BVH((Device*)device);
+ return (RTCBVH) bvh->refInc();
+ RTC_CATCH_END((Device*)device);
+ return nullptr;
+ }
+
+ RTC_API void* rtcBuildBVH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcBuildBVH);
+ RTC_VERIFY_HANDLE(bvh);
+ RTC_VERIFY_HANDLE(arguments);
+ RTC_VERIFY_HANDLE(arguments->createNode);
+ RTC_VERIFY_HANDLE(arguments->setNodeChildren);
+ RTC_VERIFY_HANDLE(arguments->setNodeBounds);
+ RTC_VERIFY_HANDLE(arguments->createLeaf);
+
+ if (arguments->primitiveArrayCapacity < arguments->primitiveCount)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")
+
+ /* initialize the allocator */
+ bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));
+ bvh->allocator.reset();
+
+ /* switch between differnet builders based on quality level */
+ if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)
+ return rtcBuildBVHMorton(arguments);
+ else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM)
+ return rtcBuildBVHBinnedSAH(arguments);
+ else if (arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) {
+ if (arguments->splitPrimitive == nullptr || arguments->primitiveArrayCapacity <= arguments->primitiveCount)
+ return rtcBuildBVHBinnedSAH(arguments);
+ else
+ return rtcBuildBVHSpatialSAH(arguments);
+ }
+ else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid build quality");
+
+ /* if we are in dynamic mode, then do not clear temporary data */
+ if (!(arguments->buildFlags & RTC_BUILD_FLAG_DYNAMIC))
+ {
+ bvh->morton_src.clear();
+ bvh->morton_tmp.clear();
+ }
+
+ RTC_CATCH_END(bvh->device);
+ return nullptr;
+ }
+
+ RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)
+ {
+ FastAllocator::CachedAllocator* alloc = (FastAllocator::CachedAllocator*) localAllocator;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcThreadLocalAlloc);
+ return alloc->malloc0(bytes,align);
+ RTC_CATCH_END(alloc->alloc->getDevice());
+ return nullptr;
+ }
+
+ RTC_API void rtcMakeStaticBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcStaticBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->morton_src.clear();
+ bvh->morton_tmp.clear();
+ RTC_CATCH_END(bvh->device);
+ }
+
+ RTC_API void rtcRetainBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ Device* device = bvh ? bvh->device : nullptr;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->refInc();
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API void rtcReleaseBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ Device* device = bvh ? bvh->device : nullptr;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->refDec();
+ RTC_CATCH_END(device);
+ }
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree-aarch64/kernels/common/scene.cpp b/thirdparty/embree-aarch64/kernels/common/scene.cpp
new file mode 100644
index 0000000000..1e23aeb415
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene.cpp
@@ -0,0 +1,976 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "scene.h"
+
+#include "../bvh/bvh4_factory.h"
+#include "../bvh/bvh8_factory.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ /* error raising rtcIntersect and rtcOccluded functions */
+ void missing_rtcCommit() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); }
+ void invalid_rtcIntersect1() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect and rtcOccluded not enabled"); }
+ void invalid_rtcIntersect4() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect4 and rtcOccluded4 not enabled"); }
+ void invalid_rtcIntersect8() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect8 and rtcOccluded8 not enabled"); }
+ void invalid_rtcIntersect16() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect16 and rtcOccluded16 not enabled"); }
+ void invalid_rtcIntersectN() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectN and rtcOccludedN not enabled"); }
+
+ Scene::Scene (Device* device)
+ : device(device),
+ flags_modified(true), enabled_geometry_types(0),
+ scene_flags(RTC_SCENE_FLAG_NONE),
+ quality_flags(RTC_BUILD_QUALITY_MEDIUM),
+ is_build(false), modified(true),
+ progressInterface(this), progress_monitor_function(nullptr), progress_monitor_ptr(nullptr), progress_monitor_counter(0)
+ {
+ device->refInc();
+
+ intersectors = Accel::Intersectors(missing_rtcCommit);
+
+ /* one can overwrite flags through device for debugging */
+ if (device->quality_flags != -1)
+ quality_flags = (RTCBuildQuality) device->quality_flags;
+ if (device->scene_flags != -1)
+ scene_flags = (RTCSceneFlags) device->scene_flags;
+ }
+
+ Scene::~Scene() noexcept
+ {
+ device->refDec();
+ }
+
+ void Scene::printStatistics()
+ {
+ /* calculate maximum number of time segments */
+ unsigned max_time_steps = 0;
+ for (size_t i=0; i<size(); i++) {
+ if (!get(i)) continue;
+ max_time_steps = max(max_time_steps,get(i)->numTimeSteps);
+ }
+
+ /* initialize vectors*/
+ std::vector<size_t> statistics[Geometry::GTY_END];
+ for (size_t i=0; i<Geometry::GTY_END; i++)
+ statistics[i].resize(max_time_steps);
+
+ /* gather statistics */
+ for (size_t i=0; i<size(); i++)
+ {
+ if (!get(i)) continue;
+ int ty = get(i)->getType();
+ assert(ty<Geometry::GTY_END);
+ int timesegments = get(i)->numTimeSegments();
+ assert((unsigned int)timesegments < max_time_steps);
+ statistics[ty][timesegments] += get(i)->size();
+ }
+
+ /* print statistics */
+ std::cout << std::setw(23) << "segments" << ": ";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << std::setw(10) << t;
+ std::cout << std::endl;
+
+ std::cout << "-------------------------";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << "----------";
+ std::cout << std::endl;
+
+ for (size_t p=0; p<Geometry::GTY_END; p++)
+ {
+ if (std::string(Geometry::gtype_names[p]) == "") continue;
+ std::cout << std::setw(23) << Geometry::gtype_names[p] << ": ";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << std::setw(10) << statistics[p][t];
+ std::cout << std::endl;
+ }
+ }
+
+ void Scene::createTriangleAccel()
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ if (device->tri_accel == "default")
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW)
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+
+ break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else /* dynamic */
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ }
+ else if (device->tri_accel == "bvh4.triangle4") accels_add(device->bvh4_factory->BVH4Triangle4 (this));
+ else if (device->tri_accel == "bvh4.triangle4v") accels_add(device->bvh4_factory->BVH4Triangle4v(this));
+ else if (device->tri_accel == "bvh4.triangle4i") accels_add(device->bvh4_factory->BVH4Triangle4i(this));
+ else if (device->tri_accel == "qbvh4.triangle4i") accels_add(device->bvh4_factory->BVH4QuantizedTriangle4i(this));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->tri_accel == "bvh8.triangle4") accels_add(device->bvh8_factory->BVH8Triangle4 (this));
+ else if (device->tri_accel == "bvh8.triangle4v") accels_add(device->bvh8_factory->BVH8Triangle4v(this));
+ else if (device->tri_accel == "bvh8.triangle4i") accels_add(device->bvh8_factory->BVH8Triangle4i(this));
+ else if (device->tri_accel == "qbvh8.triangle4i") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4i(this));
+ else if (device->tri_accel == "qbvh8.triangle4") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown triangle acceleration structure "+device->tri_accel);
+#endif
+ }
+
+ void Scene::createTriangleMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ if (device->tri_accel_mb == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // BVH8 reduces performance on AVX only-machines
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ else if (device->tri_accel_mb == "bvh4.triangle4imb") accels_add(device->bvh4_factory->BVH4Triangle4iMB(this));
+ else if (device->tri_accel_mb == "bvh4.triangle4vmb") accels_add(device->bvh4_factory->BVH4Triangle4vMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->tri_accel_mb == "bvh8.triangle4imb") accels_add(device->bvh8_factory->BVH8Triangle4iMB(this));
+ else if (device->tri_accel_mb == "bvh8.triangle4vmb") accels_add(device->bvh8_factory->BVH8Triangle4vMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur triangle acceleration structure "+device->tri_accel_mb);
+#endif
+ }
+
+ void Scene::createQuadAccel()
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ if (device->quad_accel == "default")
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW)
+ {
+ /* static */
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ break;
+
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else /* dynamic */
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ }
+ else if (device->quad_accel == "bvh4.quad4v") accels_add(device->bvh4_factory->BVH4Quad4v(this));
+ else if (device->quad_accel == "bvh4.quad4i") accels_add(device->bvh4_factory->BVH4Quad4i(this));
+ else if (device->quad_accel == "qbvh4.quad4i") accels_add(device->bvh4_factory->BVH4QuantizedQuad4i(this));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->quad_accel == "bvh8.quad4v") accels_add(device->bvh8_factory->BVH8Quad4v(this));
+ else if (device->quad_accel == "bvh8.quad4i") accels_add(device->bvh8_factory->BVH8Quad4i(this));
+ else if (device->quad_accel == "qbvh8.quad4i") accels_add(device->bvh8_factory->BVH8QuantizedQuad4i(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad acceleration structure "+device->quad_accel);
+#endif
+ }
+
+ void Scene::createQuadMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ if (device->quad_accel_mb == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ break;
+
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else if (device->quad_accel_mb == "bvh4.quad4imb") accels_add(device->bvh4_factory->BVH4Quad4iMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->quad_accel_mb == "bvh8.quad4imb") accels_add(device->bvh8_factory->BVH8Quad4iMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad motion blur acceleration structure "+device->quad_accel_mb);
+#endif
+ }
+
+ void Scene::createHairAccel()
+ {
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ if (device->hair_accel == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // only enable on HSW machines, for SNB this codepath is slower
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ else if (device->hair_accel == "bvh4obb.virtualcurve4v" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel == "bvh4obb.virtualcurve4i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->hair_accel == "bvh8obb.virtualcurve8v" ) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel == "bvh4obb.virtualcurve8i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown hair acceleration structure "+device->hair_accel);
+#endif
+ }
+
+ void Scene::createHairMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ if (device->hair_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // only enable on HSW machines, on SNB this codepath is slower
+ {
+ if (isRobustAccel()) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::ROBUST));
+ else accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (isRobustAccel()) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::ROBUST));
+ else accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
+ }
+ }
+ else if (device->hair_accel_mb == "bvh4.virtualcurve4imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->hair_accel_mb == "bvh4.virtualcurve8imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel_mb == "bvh8.virtualcurve8imb") accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur hair acceleration structure "+device->hair_accel_mb);
+#endif
+ }
+
+ void Scene::createSubdivAccel()
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ if (device->subdiv_accel == "default") {
+ accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ }
+ else if (device->subdiv_accel == "bvh4.grid.eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ else if (device->subdiv_accel == "bvh4.subdivpatch1eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv accel "+device->subdiv_accel);
+#endif
+ }
+
+ void Scene::createSubdivMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ if (device->subdiv_accel_mb == "default") {
+ accels_add(device->bvh4_factory->BVH4SubdivPatch1MB(this));
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv mblur accel "+device->subdiv_accel_mb);
+#endif
+ }
+
+ void Scene::createUserGeometryAccel()
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ else if (device->object_accel == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometry(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->object_accel == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometry(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry accel "+device->object_accel);
+#endif
+ }
+
+ void Scene::createUserGeometryMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ if (device->object_accel_mb == "default" ) {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
+ }
+ else if (device->object_accel_mb == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->object_accel_mb == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry mblur accel "+device->object_accel_mb);
+#endif
+ }
+
+ void Scene::createInstanceAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ // if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel()) {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
+#endif
+ }
+
+ void Scene::createInstanceMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ //if (device->instance_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8InstanceMB(this, false));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4InstanceMB(this, false));
+ }
+ //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
+#endif
+ }
+
+ void Scene::createInstanceExpensiveAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ // if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel()) {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
+#endif
+ }
+
+ void Scene::createInstanceExpensiveMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ //if (device->instance_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8InstanceMB(this, true));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4InstanceMB(this, true));
+ }
+ //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
+#endif
+ }
+
+ void Scene::createGridAccel()
+ {
+ BVHFactory::IntersectVariant ivariant = isRobustAccel() ? BVHFactory::IntersectVariant::ROBUST : BVHFactory::IntersectVariant::FAST;
+#if defined(EMBREE_GEOMETRY_GRID)
+ if (device->grid_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ {
+ accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+ }
+ else
+#endif
+ {
+ accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+ }
+ }
+ else if (device->grid_accel == "bvh4.grid") accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->grid_accel == "bvh8.grid") accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid accel "+device->grid_accel);
+#endif
+
+ }
+
+ void Scene::createGridMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_GRID)
+ if (device->grid_accel_mb == "default")
+ {
+ accels_add(device->bvh4_factory->BVH4GridMB(this,BVHFactory::BuildVariant::STATIC));
+ }
+ else if (device->grid_accel_mb == "bvh4mb.grid") accels_add(device->bvh4_factory->BVH4GridMB(this));
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid mb accel "+device->grid_accel);
+#endif
+
+ }
+
+ void Scene::clear() {
+ }
+
+ unsigned Scene::bind(unsigned geomID, Ref<Geometry> geometry)
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(geometriesMutex);
+#else
+ Lock<SpinLock> lock(geometriesMutex);
+#endif
+ if (geomID == RTC_INVALID_GEOMETRY_ID) {
+ geomID = id_pool.allocate();
+ if (geomID == RTC_INVALID_GEOMETRY_ID)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"too many geometries inside scene");
+ }
+ else
+ {
+ if (!id_pool.add(geomID))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID provided");
+ }
+ if (geomID >= geometries.size()) {
+ geometries.resize(geomID+1);
+ vertices.resize(geomID+1);
+ geometryModCounters_.resize(geomID+1);
+ }
+ geometries[geomID] = geometry;
+ geometryModCounters_[geomID] = 0;
+ if (geometry->isEnabled()) {
+ setModified ();
+ }
+ return geomID;
+ }
+
+ void Scene::detachGeometry(size_t geomID)
+ {
+#if defined(__aarch64__) && defined(BUILD_IOS)
+ std::scoped_lock lock(geometriesMutex);
+#else
+ Lock<SpinLock> lock(geometriesMutex);
+#endif
+
+ if (geomID >= geometries.size())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID");
+
+ Ref<Geometry>& geometry = geometries[geomID];
+ if (geometry == null)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry");
+
+ if (geometry->isEnabled()) {
+ setModified ();
+ }
+ accels_deleteGeometry(unsigned(geomID));
+ id_pool.deallocate((unsigned)geomID);
+ geometries[geomID] = null;
+ vertices[geomID] = nullptr;
+ geometryModCounters_[geomID] = 0;
+ }
+
+ void Scene::updateInterface()
+ {
+ is_build = true;
+ }
+
+ void Scene::commit_task ()
+ {
+ checkIfModifiedAndSet ();
+ if (!isModified()) {
+ return;
+ }
+
+ /* print scene statistics */
+ if (device->verbosity(2))
+ printStatistics();
+
+ progress_monitor_counter = 0;
+
+ /* gather scene stats and call preCommit function of each geometry */
+ this->world = parallel_reduce (size_t(0), geometries.size(), GeometryCounts (),
+ [this](const range<size_t>& r)->GeometryCounts
+ {
+ GeometryCounts c;
+ for (auto i=r.begin(); i<r.end(); ++i)
+ {
+ if (geometries[i] && geometries[i]->isEnabled())
+ {
+ geometries[i]->preCommit();
+ geometries[i]->addElementsToCount (c);
+ c.numFilterFunctions += (int) geometries[i]->hasFilterFunctions();
+ }
+ }
+ return c;
+ },
+ std::plus<GeometryCounts>()
+ );
+
+ /* select acceleration structures to build */
+ unsigned int new_enabled_geometry_types = world.enabledGeometryTypesMask();
+ if (flags_modified || new_enabled_geometry_types != enabled_geometry_types)
+ {
+ accels_init();
+
+ /* we need to make all geometries modified, otherwise two level builder will
+ not rebuild currently not modified geometries */
+ parallel_for(geometryModCounters_.size(), [&] ( const size_t i ) {
+ geometryModCounters_[i] = 0;
+ });
+
+ if (getNumPrimitives(TriangleMesh::geom_type,false)) createTriangleAccel();
+ if (getNumPrimitives(TriangleMesh::geom_type,true)) createTriangleMBAccel();
+ if (getNumPrimitives(QuadMesh::geom_type,false)) createQuadAccel();
+ if (getNumPrimitives(QuadMesh::geom_type,true)) createQuadMBAccel();
+ if (getNumPrimitives(GridMesh::geom_type,false)) createGridAccel();
+ if (getNumPrimitives(GridMesh::geom_type,true)) createGridMBAccel();
+ if (getNumPrimitives(SubdivMesh::geom_type,false)) createSubdivAccel();
+ if (getNumPrimitives(SubdivMesh::geom_type,true)) createSubdivMBAccel();
+ if (getNumPrimitives(Geometry::MTY_CURVES,false)) createHairAccel();
+ if (getNumPrimitives(Geometry::MTY_CURVES,true)) createHairMBAccel();
+ if (getNumPrimitives(UserGeometry::geom_type,false)) createUserGeometryAccel();
+ if (getNumPrimitives(UserGeometry::geom_type,true)) createUserGeometryMBAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,false)) createInstanceAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,true)) createInstanceMBAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,false)) createInstanceExpensiveAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,true)) createInstanceExpensiveMBAccel();
+
+ flags_modified = false;
+ enabled_geometry_types = new_enabled_geometry_types;
+ }
+
+ /* select fast code path if no filter function is present */
+ accels_select(hasFilterFunction());
+
+ /* build all hierarchies of this scene */
+ accels_build();
+
+ /* make static geometry immutable */
+ if (!isDynamicAccel()) {
+ accels_immutable();
+ flags_modified = true; // in non-dynamic mode we have to re-create accels
+ }
+
+ /* call postCommit function of each geometry */
+ parallel_for(geometries.size(), [&] ( const size_t i ) {
+ if (geometries[i] && geometries[i]->isEnabled()) {
+ geometries[i]->postCommit();
+ vertices[i] = geometries[i]->getCompactVertexArray();
+ geometryModCounters_[i] = geometries[i]->getModCounter();
+ }
+ });
+
+ updateInterface();
+
+ if (device->verbosity(2)) {
+ std::cout << "created scene intersector" << std::endl;
+ accels_print(2);
+ std::cout << "selected scene intersector" << std::endl;
+ intersectors.print(2);
+ }
+
+ setModified(false);
+ }
+
+ void Scene::setBuildQuality(RTCBuildQuality quality_flags_i)
+ {
+ if (quality_flags == quality_flags_i) return;
+ quality_flags = quality_flags_i;
+ flags_modified = true;
+ }
+
+ RTCBuildQuality Scene::getBuildQuality() const {
+ return quality_flags;
+ }
+
+ void Scene::setSceneFlags(RTCSceneFlags scene_flags_i)
+ {
+ if (scene_flags == scene_flags_i) return;
+ scene_flags = scene_flags_i;
+ flags_modified = true;
+ }
+
+ RTCSceneFlags Scene::getSceneFlags() const {
+ return scene_flags;
+ }
+
+#if defined(TASKING_INTERNAL)
+
+ void Scene::commit (bool join)
+ {
+ Lock<MutexSys> buildLock(buildMutex,false);
+
+ /* allocates own taskscheduler for each build */
+ Ref<TaskScheduler> scheduler = nullptr;
+ {
+ Lock<MutexSys> lock(schedulerMutex);
+ scheduler = this->scheduler;
+ if (scheduler == null) {
+ buildLock.lock();
+ this->scheduler = scheduler = new TaskScheduler;
+ }
+ }
+
+ /* worker threads join build */
+ if (!buildLock.isLocked())
+ {
+ if (!join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"use rtcJoinCommitScene to join a build operation");
+
+ scheduler->join();
+ return;
+ }
+
+ /* initiate build */
+ // -- GODOT start --
+ // try {
+ scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join);
+ // }
+ // catch (...) {
+ // accels_clear();
+ // updateInterface();
+ // Lock<MutexSys> lock(schedulerMutex);
+ // this->scheduler = nullptr;
+ // throw;
+ // }
+ // -- GODOT end --
+ }
+
+#endif
+
+#if defined(TASKING_TBB) || defined(TASKING_GCD)
+
+ void Scene::commit (bool join)
+ {
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
+ if (join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with this TBB version");
+#endif
+
+ /* try to obtain build lock */
+ Lock<MutexSys> lock(buildMutex,buildMutex.try_lock());
+
+ /* join hierarchy build */
+ if (!lock.isLocked())
+ {
+#if !TASKING_TBB_USE_TASK_ISOLATION
+ if (!join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invoking rtcCommitScene from multiple threads is not supported with this TBB version");
+#endif
+
+ do {
+
+#if defined(TASKING_GCD)
+ // Do Nothing
+#else
+#if USE_TASK_ARENA
+ if (join) {
+ device->arena->execute([&]{ group.wait(); });
+ }
+ else
+#endif
+ {
+ group.wait();
+ }
+#endif
+
+ pause_cpu();
+ yield();
+
+ } while (!buildMutex.try_lock());
+
+ buildMutex.unlock();
+ return;
+ }
+
+ /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
+ const unsigned int mxcsr = _mm_getcsr();
+ _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
+
+ try {
+#if defined(TASKING_TBB)
+#if TBB_INTERFACE_VERSION_MAJOR < 8
+ tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits);
+#else
+ tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits | tbb::task_group_context::fp_settings );
+#endif
+ //ctx.set_priority(tbb::priority_high);
+
+#if USE_TASK_ARENA
+ if (join)
+ {
+ device->arena->execute([&]{
+ group.run([&]{
+ tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
+ });
+ group.wait();
+ });
+ }
+ else
+#endif
+ {
+ group.run([&]{
+ tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
+ });
+ group.wait();
+ }
+
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+
+#elif defined(TASKING_GCD)
+
+ commit_task();
+
+#endif // #if defined(TASKING_TBB)
+
+ }
+ catch (...)
+ {
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+
+ accels_clear();
+ updateInterface();
+ throw;
+ }
+ }
+#endif
+
+#if defined(TASKING_PPL)
+
+ void Scene::commit (bool join)
+ {
+#if defined(TASKING_PPL)
+ if (join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with PPL");
+#endif
+
+ /* try to obtain build lock */
+ Lock<MutexSys> lock(buildMutex);
+
+ checkIfModifiedAndSet ();
+ if (!isModified()) {
+ return;
+ }
+
+ /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
+ const unsigned int mxcsr = _mm_getcsr();
+ _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
+
+ try {
+
+ group.run([&]{
+ concurrency::parallel_for(size_t(0), size_t(1), size_t(1), [&](size_t) { commit_task(); });
+ });
+ group.wait();
+
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+ }
+ catch (...)
+ {
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+
+ accels_clear();
+ updateInterface();
+ throw;
+ }
+ }
+#endif
+
+ void Scene::setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr)
+ {
+ progress_monitor_function = func;
+ progress_monitor_ptr = ptr;
+ }
+
+ void Scene::progressMonitor(double dn)
+ {
+ if (progress_monitor_function) {
+ size_t n = size_t(dn) + progress_monitor_counter.fetch_add(size_t(dn));
+ if (!progress_monitor_function(progress_monitor_ptr, n / (double(numPrimitives())))) {
+ throw_RTCError(RTC_ERROR_CANCELLED,"progress monitor forced termination");
+ }
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene.h b/thirdparty/embree-aarch64/kernels/common/scene.h
new file mode 100644
index 0000000000..b41c6cde91
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene.h
@@ -0,0 +1,390 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "builder.h"
+#include "../../common/algorithms/parallel_any_of.h"
+#include "scene_triangle_mesh.h"
+#include "scene_quad_mesh.h"
+#include "scene_user_geometry.h"
+#include "scene_instance.h"
+#include "scene_curves.h"
+#include "scene_line_segments.h"
+#include "scene_subdiv_mesh.h"
+#include "scene_grid_mesh.h"
+#include "scene_points.h"
+#include "../subdiv/tessellation_cache.h"
+
+#include "acceln.h"
+#include "geometry.h"
+
+namespace embree
+{
+ /*! Base class all scenes are derived from */
+ class Scene : public AccelN
+ {
+ ALIGNED_CLASS_(std::alignment_of<Scene>::value);
+
+ public:
+ template<typename Ty, bool mblur = false>
+ class Iterator
+ {
+ public:
+ Iterator () {}
+
+ Iterator (Scene* scene, bool all = false)
+ : scene(scene), all(all) {}
+
+ __forceinline Ty* at(const size_t i)
+ {
+ Geometry* geom = scene->geometries[i].ptr;
+ if (geom == nullptr) return nullptr;
+ if (!all && !geom->isEnabled()) return nullptr;
+ const size_t mask = geom->getTypeMask() & Ty::geom_type;
+ if (!(mask)) return nullptr;
+ if ((geom->numTimeSteps != 1) != mblur) return nullptr;
+ return (Ty*) geom;
+ }
+
+ __forceinline Ty* operator[] (const size_t i) {
+ return at(i);
+ }
+
+ __forceinline size_t size() const {
+ return scene->size();
+ }
+
+ __forceinline size_t numPrimitives() const {
+ return scene->getNumPrimitives(Ty::geom_type,mblur);
+ }
+
+ __forceinline size_t maxPrimitivesPerGeometry()
+ {
+ size_t ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,mesh->size());
+ }
+ return ret;
+ }
+
+ __forceinline unsigned int maxGeomID()
+ {
+ unsigned int ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,(unsigned int)i);
+ }
+ return ret;
+ }
+
+ __forceinline unsigned maxTimeStepsPerGeometry()
+ {
+ unsigned ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,mesh->numTimeSteps);
+ }
+ return ret;
+ }
+
+ private:
+ Scene* scene;
+ bool all;
+ };
+
+ class Iterator2
+ {
+ public:
+ Iterator2 () {}
+
+ Iterator2 (Scene* scene, Geometry::GTypeMask typemask, bool mblur)
+ : scene(scene), typemask(typemask), mblur(mblur) {}
+
+ __forceinline Geometry* at(const size_t i)
+ {
+ Geometry* geom = scene->geometries[i].ptr;
+ if (geom == nullptr) return nullptr;
+ if (!geom->isEnabled()) return nullptr;
+ if (!(geom->getTypeMask() & typemask)) return nullptr;
+ if ((geom->numTimeSteps != 1) != mblur) return nullptr;
+ return geom;
+ }
+
+ __forceinline Geometry* operator[] (const size_t i) {
+ return at(i);
+ }
+
+ __forceinline size_t size() const {
+ return scene->size();
+ }
+
+ private:
+ Scene* scene;
+ Geometry::GTypeMask typemask;
+ bool mblur;
+ };
+
+ public:
+
+ /*! Scene construction */
+ Scene (Device* device);
+
+ /*! Scene destruction */
+ ~Scene () noexcept;
+
+ private:
+ /*! class is non-copyable */
+ Scene (const Scene& other) DELETED; // do not implement
+ Scene& operator= (const Scene& other) DELETED; // do not implement
+
+ public:
+ void createTriangleAccel();
+ void createTriangleMBAccel();
+ void createQuadAccel();
+ void createQuadMBAccel();
+ void createHairAccel();
+ void createHairMBAccel();
+ void createSubdivAccel();
+ void createSubdivMBAccel();
+ void createUserGeometryAccel();
+ void createUserGeometryMBAccel();
+ void createInstanceAccel();
+ void createInstanceMBAccel();
+ void createInstanceExpensiveAccel();
+ void createInstanceExpensiveMBAccel();
+ void createGridAccel();
+ void createGridMBAccel();
+
+ /*! prints statistics about the scene */
+ void printStatistics();
+
+ /*! clears the scene */
+ void clear();
+
+ /*! detaches some geometry */
+ void detachGeometry(size_t geomID);
+
+ void setBuildQuality(RTCBuildQuality quality_flags);
+ RTCBuildQuality getBuildQuality() const;
+
+ void setSceneFlags(RTCSceneFlags scene_flags);
+ RTCSceneFlags getSceneFlags() const;
+
+ void commit (bool join);
+ void commit_task ();
+ void build () {}
+
+ void updateInterface();
+
+ /* return number of geometries */
+ __forceinline size_t size() const { return geometries.size(); }
+
+ /* bind geometry to the scene */
+ unsigned int bind (unsigned geomID, Ref<Geometry> geometry);
+
+ /* determines if scene is modified */
+ __forceinline bool isModified() const { return modified; }
+
+ /* sets modified flag */
+ __forceinline void setModified(bool f = true) {
+ modified = f;
+ }
+
+ __forceinline bool isGeometryModified(size_t geomID)
+ {
+ Ref<Geometry>& g = geometries[geomID];
+ if (!g) return false;
+ return g->getModCounter() > geometryModCounters_[geomID];
+ }
+
+ protected:
+
+ __forceinline void checkIfModifiedAndSet ()
+ {
+ if (isModified ()) return;
+
+ auto geometryIsModified = [this](size_t geomID)->bool {
+ return isGeometryModified(geomID);
+ };
+
+ if (parallel_any_of (size_t(0), geometries.size (), geometryIsModified)) {
+ setModified ();
+ }
+ }
+
+ public:
+
+ /* get mesh by ID */
+ __forceinline Geometry* get(size_t i) { assert(i < geometries.size()); return geometries[i].ptr; }
+ __forceinline const Geometry* get(size_t i) const { assert(i < geometries.size()); return geometries[i].ptr; }
+
+ template<typename Mesh>
+ __forceinline Mesh* get(size_t i) {
+ assert(i < geometries.size());
+ assert(geometries[i]->getTypeMask() & Mesh::geom_type);
+ return (Mesh*)geometries[i].ptr;
+ }
+ template<typename Mesh>
+ __forceinline const Mesh* get(size_t i) const {
+ assert(i < geometries.size());
+ assert(geometries[i]->getTypeMask() & Mesh::geom_type);
+ return (Mesh*)geometries[i].ptr;
+ }
+
+ template<typename Mesh>
+ __forceinline Mesh* getSafe(size_t i) {
+ assert(i < geometries.size());
+ if (geometries[i] == null) return nullptr;
+ if (!(geometries[i]->getTypeMask() & Mesh::geom_type)) return nullptr;
+ else return (Mesh*) geometries[i].ptr;
+ }
+
+ __forceinline Ref<Geometry> get_locked(size_t i) {
+ Lock<SpinLock> lock(geometriesMutex);
+ assert(i < geometries.size());
+ return geometries[i];
+ }
+
+ /* flag decoding */
+ __forceinline bool isFastAccel() const { return !isCompactAccel() && !isRobustAccel(); }
+ __forceinline bool isCompactAccel() const { return scene_flags & RTC_SCENE_FLAG_COMPACT; }
+ __forceinline bool isRobustAccel() const { return scene_flags & RTC_SCENE_FLAG_ROBUST; }
+ __forceinline bool isStaticAccel() const { return !(scene_flags & RTC_SCENE_FLAG_DYNAMIC); }
+ __forceinline bool isDynamicAccel() const { return scene_flags & RTC_SCENE_FLAG_DYNAMIC; }
+
+ __forceinline bool hasContextFilterFunction() const {
+ return scene_flags & RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION;
+ }
+
+ __forceinline bool hasGeometryFilterFunction() {
+ return world.numFilterFunctions != 0;
+ }
+
+ __forceinline bool hasFilterFunction() {
+ return hasContextFilterFunction() || hasGeometryFilterFunction();
+ }
+
+ /* test if scene got already build */
+ __forceinline bool isBuild() const { return is_build; }
+
+ public:
+ IDPool<unsigned,0xFFFFFFFE> id_pool;
+ vector<Ref<Geometry>> geometries; //!< list of all user geometries
+ vector<unsigned int> geometryModCounters_;
+ vector<float*> vertices;
+
+ public:
+ Device* device;
+
+ /* these are to detect if we need to recreate the acceleration structures */
+ bool flags_modified;
+ unsigned int enabled_geometry_types;
+
+ RTCSceneFlags scene_flags;
+ RTCBuildQuality quality_flags;
+ MutexSys buildMutex;
+ SpinLock geometriesMutex;
+ bool is_build;
+ private:
+ bool modified; //!< true if scene got modified
+
+ public:
+
+ /*! global lock step task scheduler */
+#if defined(TASKING_INTERNAL)
+ MutexSys schedulerMutex;
+ Ref<TaskScheduler> scheduler;
+#elif defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION
+ tbb::isolated_task_group group;
+#elif defined(TASKING_TBB)
+ tbb::task_group group;
+#elif defined(TASKING_PPL)
+ concurrency::task_group group;
+#endif
+
+ public:
+ struct BuildProgressMonitorInterface : public BuildProgressMonitor {
+ BuildProgressMonitorInterface(Scene* scene)
+ : scene(scene) {}
+ void operator() (size_t dn) const { scene->progressMonitor(double(dn)); }
+ private:
+ Scene* scene;
+ };
+ BuildProgressMonitorInterface progressInterface;
+ RTCProgressMonitorFunction progress_monitor_function;
+ void* progress_monitor_ptr;
+ std::atomic<size_t> progress_monitor_counter;
+ void progressMonitor(double nprims);
+ void setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr);
+
+ private:
+ GeometryCounts world; //!< counts for geometry
+
+ public:
+
+ __forceinline size_t numPrimitives() const {
+ return world.size();
+ }
+
+ __forceinline size_t getNumPrimitives(Geometry::GTypeMask mask, bool mblur) const
+ {
+ size_t count = 0;
+
+ if (mask & Geometry::MTY_TRIANGLE_MESH)
+ count += mblur ? world.numMBTriangles : world.numTriangles;
+
+ if (mask & Geometry::MTY_QUAD_MESH)
+ count += mblur ? world.numMBQuads : world.numQuads;
+
+ if (mask & Geometry::MTY_CURVE2)
+ count += mblur ? world.numMBLineSegments : world.numLineSegments;
+
+ if (mask & Geometry::MTY_CURVE4)
+ count += mblur ? world.numMBBezierCurves : world.numBezierCurves;
+
+ if (mask & Geometry::MTY_POINTS)
+ count += mblur ? world.numMBPoints : world.numPoints;
+
+ if (mask & Geometry::MTY_SUBDIV_MESH)
+ count += mblur ? world.numMBSubdivPatches : world.numSubdivPatches;
+
+ if (mask & Geometry::MTY_USER_GEOMETRY)
+ count += mblur ? world.numMBUserGeometries : world.numUserGeometries;
+
+ if (mask & Geometry::MTY_INSTANCE_CHEAP)
+ count += mblur ? world.numMBInstancesCheap : world.numInstancesCheap;
+
+ if (mask & Geometry::MTY_INSTANCE_EXPENSIVE)
+ count += mblur ? world.numMBInstancesExpensive : world.numInstancesExpensive;
+
+ if (mask & Geometry::MTY_GRID_MESH)
+ count += mblur ? world.numMBGrids : world.numGrids;
+
+ return count;
+ }
+
+ template<typename Mesh, bool mblur>
+ __forceinline unsigned getNumTimeSteps()
+ {
+ if (!mblur)
+ return 1;
+
+ Scene::Iterator<Mesh,mblur> iter(this);
+ return iter.maxTimeStepsPerGeometry();
+ }
+
+ template<typename Mesh, bool mblur>
+ __forceinline unsigned int getMaxGeomID()
+ {
+ Scene::Iterator<Mesh,mblur> iter(this);
+ return iter.maxGeomID();
+ }
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_curves.h b/thirdparty/embree-aarch64/kernels/common/scene_curves.h
new file mode 100644
index 0000000000..2649ab0e3e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_curves.h
@@ -0,0 +1,341 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! represents an array of bicubic bezier curves */
+ struct CurveGeometry : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_CURVE4;
+
+ public:
+
+ /*! bezier curve construction */
+ CurveGeometry (Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void setTessellationRate(float N);
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns the i'th curve */
+ __forceinline const unsigned int& curve(size_t i) const {
+ return curves[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th tangent of the first time step */
+ __forceinline Vec3ff tangent(size_t i) const {
+ return tangents0[i];
+ }
+
+ /*! returns i'th normal derivative of the first time step */
+ __forceinline Vec3fa dnormal(size_t i) const {
+ return dnormals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th tangent of itime'th timestep */
+ __forceinline Vec3ff tangent(size_t i, size_t itime) const {
+ return tangents[itime][i];
+ }
+
+ /*! returns i'th normal derivative of itime'th timestep */
+ __forceinline Vec3fa dnormal(size_t i, size_t itime) const {
+ return dnormals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! gathers the curve starting with i'th vertex */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i) const
+ {
+ p0 = vertex(i+0);
+ p1 = vertex(i+1);
+ p2 = vertex(i+2);
+ p3 = vertex(i+3);
+ }
+
+ /*! gathers the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, size_t itime) const
+ {
+ p0 = vertex(i+0,itime);
+ p1 = vertex(i+1,itime);
+ p2 = vertex(i+2,itime);
+ p3 = vertex(i+3,itime);
+ }
+
+ /*! gathers the curve starting with i'th vertex */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i) const
+ {
+ p0 = vertex(i+0);
+ p1 = vertex(i+1);
+ p2 = vertex(i+2);
+ p3 = vertex(i+3);
+ n0 = normal(i+0);
+ n1 = normal(i+1);
+ n2 = normal(i+2);
+ n3 = normal(i+3);
+ }
+
+ /*! gathers the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, size_t itime) const
+ {
+ p0 = vertex(i+0,itime);
+ p1 = vertex(i+1,itime);
+ p2 = vertex(i+2,itime);
+ p3 = vertex(i+3,itime);
+ n0 = normal(i+0,itime);
+ n1 = normal(i+1,itime);
+ n2 = normal(i+2,itime);
+ n3 = normal(i+3,itime);
+ }
+
+ /*! prefetches the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void prefetchL1_vertices(size_t i) const
+ {
+ prefetchL1(vertices0.getPtr(i)+0);
+ prefetchL1(vertices0.getPtr(i)+64);
+ }
+
+ /*! prefetches the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void prefetchL2_vertices(size_t i) const
+ {
+ prefetchL2(vertices0.getPtr(i)+0);
+ prefetchL2(vertices0.getPtr(i)+64);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+
+ const float t0 = 1.0f - ftime;
+ const float t1 = ftime;
+ Vec3ff a0,a1,a2,a3;
+ gather(a0,a1,a2,a3,i,itime);
+ Vec3ff b0,b1,b2,b3;
+ gather(b0,b1,b2,b3,i,itime+1);
+ p0 = madd(Vec3ff(t0),a0,t1*b0);
+ p1 = madd(Vec3ff(t0),a1,t1*b1);
+ p2 = madd(Vec3ff(t0),a2,t1*b2);
+ p3 = madd(Vec3ff(t0),a3,t1*b3);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+
+ const float t0 = 1.0f - ftime;
+ const float t1 = ftime;
+ Vec3ff a0,a1,a2,a3; Vec3fa an0,an1,an2,an3;
+ gather(a0,a1,a2,a3,an0,an1,an2,an3,i,itime);
+ Vec3ff b0,b1,b2,b3; Vec3fa bn0,bn1,bn2,bn3;
+ gather(b0,b1,b2,b3,bn0,bn1,bn2,bn3,i,itime+1);
+ p0 = madd(Vec3ff(t0),a0,t1*b0);
+ p1 = madd(Vec3ff(t0),a1,t1*b1);
+ p2 = madd(Vec3ff(t0),a2,t1*b2);
+ p3 = madd(Vec3ff(t0),a3,t1*b3);
+ n0 = madd(Vec3ff(t0),an0,t1*bn0);
+ n1 = madd(Vec3ff(t0),an1,t1*bn1);
+ n2 = madd(Vec3ff(t0),an2,t1*bn2);
+ n3 = madd(Vec3ff(t0),an3,t1*bn3);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
+ {
+ Vec3ff v0,v1,v2,v3; Vec3fa n0,n1,n2,n3;
+ unsigned int vertexID = curve(primID);
+ gather(v0,v1,v2,v3,n0,n1,n2,n3,vertexID,itime);
+ SourceCurve3ff ccurve(v0,v1,v2,v3);
+ SourceCurve3fa ncurve(n0,n1,n2,n3);
+ ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
+ return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+0);
+ const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+1);
+ return clerp(curve0,curve1,ftime);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i) const
+ {
+ p0 = vertex (i+0);
+ p1 = vertex (i+1);
+ t0 = tangent(i+0);
+ t1 = tangent(i+1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, size_t itime) const
+ {
+ p0 = vertex (i+0,itime);
+ p1 = vertex (i+1,itime);
+ t0 = tangent(i+0,itime);
+ t1 = tangent(i+1,itime);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const float f0 = 1.0f - ftime, f1 = ftime;
+ Vec3ff ap0,at0,ap1,at1;
+ gather_hermite(ap0,at0,ap1,at1,i,itime);
+ Vec3ff bp0,bt0,bp1,bt1;
+ gather_hermite(bp0,bt0,bp1,bt1,i,itime+1);
+ p0 = madd(Vec3ff(f0),ap0,f1*bp0);
+ t0 = madd(Vec3ff(f0),at0,f1*bt0);
+ p1 = madd(Vec3ff(f0),ap1,f1*bp1);
+ t1 = madd(Vec3ff(f0),at1,f1*bt1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i) const
+ {
+ p0 = vertex (i+0);
+ p1 = vertex (i+1);
+ t0 = tangent(i+0);
+ t1 = tangent(i+1);
+ n0 = normal(i+0);
+ n1 = normal(i+1);
+ dn0 = dnormal(i+0);
+ dn1 = dnormal(i+1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, size_t itime) const
+ {
+ p0 = vertex (i+0,itime);
+ p1 = vertex (i+1,itime);
+ t0 = tangent(i+0,itime);
+ t1 = tangent(i+1,itime);
+ n0 = normal(i+0,itime);
+ n1 = normal(i+1,itime);
+ dn0 = dnormal(i+0,itime);
+ dn1 = dnormal(i+1,itime);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3fa& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3fa& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const float f0 = 1.0f - ftime, f1 = ftime;
+ Vec3ff ap0,at0,ap1,at1; Vec3fa an0,adn0,an1,adn1;
+ gather_hermite(ap0,at0,an0,adn0,ap1,at1,an1,adn1,i,itime);
+ Vec3ff bp0,bt0,bp1,bt1; Vec3fa bn0,bdn0,bn1,bdn1;
+ gather_hermite(bp0,bt0,bn0,bdn0,bp1,bt1,bn1,bdn1,i,itime+1);
+ p0 = madd(Vec3ff(f0),ap0,f1*bp0);
+ t0 = madd(Vec3ff(f0),at0,f1*bt0);
+ n0 = madd(Vec3ff(f0),an0,f1*bn0);
+ dn0= madd(Vec3ff(f0),adn0,f1*bdn0);
+ p1 = madd(Vec3ff(f0),ap1,f1*bp1);
+ t1 = madd(Vec3ff(f0),at1,f1*bt1);
+ n1 = madd(Vec3ff(f0),an1,f1*bn1);
+ dn1= madd(Vec3ff(f0),adn1,f1*bdn1);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
+ {
+ Vec3ff v0,t0,v1,t1; Vec3fa n0,dn0,n1,dn1;
+ unsigned int vertexID = curve(primID);
+ gather_hermite(v0,t0,n0,dn0,v1,t1,n1,dn1,vertexID,itime);
+
+ SourceCurve3ff ccurve(v0,t0,v1,t1);
+ SourceCurve3fa ncurve(n0,dn0,n1,dn1);
+ ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
+ return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+0);
+ const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+1);
+ return clerp(curve0,curve1,ftime);
+ }
+
+ private:
+ void resizeBuffers(unsigned int numSteps);
+
+ public:
+ BufferView<unsigned int> curves; //!< array of curve indices
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ BufferView<Vec3ff> tangents0; //!< fast access to first tangent buffer
+ BufferView<Vec3fa> dnormals0; //!< fast access to first normal derivative buffer
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<Vec3ff>> tangents; //!< tangent array for each timestep
+ vector<BufferView<Vec3fa>> dnormals; //!< normal derivative array for each timestep
+ BufferView<char> flags; //!< start, end flag per segment
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ int tessellationRate; //!< tessellation rate for flat curve
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ DECLARE_ISA_FUNCTION(CurveGeometry*, createCurves, Device* COMMA Geometry::GType);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_grid_mesh.h b/thirdparty/embree-aarch64/kernels/common/scene_grid_mesh.h
new file mode 100644
index 0000000000..c08658466a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_grid_mesh.h
@@ -0,0 +1,215 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Grid Mesh */
+ struct GridMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_GRID_MESH;
+
+ /*! grid */
+ struct Grid
+ {
+ unsigned int startVtxID;
+ unsigned int lineVtxOffset;
+ unsigned short resX,resY;
+
+ /* border flags due to 3x3 vertex pattern */
+ __forceinline unsigned int get3x3FlagsX(const unsigned int x) const
+ {
+ return (x + 2 >= (unsigned int)resX) ? (1<<15) : 0;
+ }
+
+ /* border flags due to 3x3 vertex pattern */
+ __forceinline unsigned int get3x3FlagsY(const unsigned int y) const
+ {
+ return (y + 2 >= (unsigned int)resY) ? (1<<15) : 0;
+ }
+
+ /*! outputs grid structure */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Grid& t) {
+ return cout << "Grid { startVtxID " << t.startVtxID << ", lineVtxOffset " << t.lineVtxOffset << ", resX " << t.resX << ", resY " << t.resY << " }";
+ }
+ };
+
+ public:
+
+ /*! grid mesh construction */
+ GridMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ __forceinline unsigned int getNumSubGrids(const size_t gridID)
+ {
+ const Grid &g = grid(gridID);
+ return max((unsigned int)1,((unsigned int)g.resX >> 1) * ((unsigned int)g.resY >> 1));
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th grid*/
+ __forceinline const Grid& grid(size_t i) const {
+ return grids[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const Vec3fa vertex(size_t i) const { // FIXME: check if this does a unaligned load
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th vertex of the first timestep */
+ __forceinline size_t grid_vertex_index(const Grid& g, size_t x, size_t y) const {
+ assert(x < (size_t)g.resX);
+ assert(y < (size_t)g.resY);
+ return g.startVtxID + x + y * g.lineVtxOffset;
+ }
+
+ /*! returns i'th vertex of the first timestep */
+ __forceinline const Vec3fa grid_vertex(const Grid& g, size_t x, size_t y) const {
+ const size_t index = grid_vertex_index(g,x,y);
+ return vertex(index);
+ }
+
+ /*! returns i'th vertex of the itime'th timestep */
+ __forceinline const Vec3fa grid_vertex(const Grid& g, size_t x, size_t y, size_t itime) const {
+ const size_t index = grid_vertex_index(g,x,y);
+ return vertex(index,itime);
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(const Grid& g, size_t sx, size_t sy, BBox3fa& bbox) const
+ {
+ BBox3fa b(empty);
+ for (size_t t=0; t<numTimeSteps; t++)
+ {
+ for (size_t y=sy;y<min(sy+3,(size_t)g.resY);y++)
+ for (size_t x=sx;x<min(sx+3,(size_t)g.resX);x++)
+ {
+ const Vec3fa v = grid_vertex(g,x,y,t);
+ if (unlikely(!isvalid(v))) return false;
+ b.extend(v);
+ }
+ }
+
+ bbox = b;
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(const Grid& g, size_t sx, size_t sy, size_t itime, BBox3fa& bbox) const
+ {
+ assert(itime < numTimeSteps);
+ BBox3fa b0(empty);
+ for (size_t y=sy;y<min(sy+3,(size_t)g.resY);y++)
+ for (size_t x=sx;x<min(sx+3,(size_t)g.resX);x++)
+ {
+ const Vec3fa v = grid_vertex(g,x,y,itime);
+ if (unlikely(!isvalid(v))) return false;
+ b0.extend(v);
+ }
+
+ /* use bounds of first time step in builder */
+ bbox = b0;
+ return true;
+ }
+
+ __forceinline bool valid(size_t gridID, size_t itime=0) const {
+ return valid(gridID, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t gridID, const range<size_t>& itime_range) const
+ {
+ if (unlikely(gridID >= grids.size())) return false;
+ const Grid &g = grid(gridID);
+ if (unlikely(g.startVtxID + 0 >= vertices0.size())) return false;
+ if (unlikely(g.startVtxID + (g.resY-1)*g.lineVtxOffset + g.resX-1 >= vertices0.size())) return false;
+
+ for (size_t y=0;y<g.resY;y++)
+ for (size_t x=0;x<g.resX;x++)
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid(grid_vertex(g,x,y,itime))) return false;
+ return true;
+ }
+
+
+ __forceinline BBox3fa bounds(const Grid& g, size_t sx, size_t sy, size_t itime) const
+ {
+ BBox3fa box(empty);
+ buildBounds(g,sx,sy,itime,box);
+ return box;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Grid& g, size_t sx, size_t sy, size_t itime) const {
+ BBox3fa bounds0, bounds1;
+ buildBounds(g,sx,sy,itime+0,bounds0);
+ buildBounds(g,sx,sy,itime+1,bounds1);
+ return LBBox3fa(bounds0,bounds1);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const Grid& g, size_t sx, size_t sy, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(g,sx,sy,itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ public:
+ BufferView<Grid> grids; //!< array of triangles
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<RawBufferView> vertexAttribs; //!< vertex attributes
+ };
+
+ namespace isa
+ {
+ struct GridMeshISA : public GridMesh
+ {
+ GridMeshISA (Device* device)
+ : GridMesh(device) {}
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(GridMesh*, createGridMesh, Device*);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_instance.h b/thirdparty/embree-aarch64/kernels/common/scene_instance.h
new file mode 100644
index 0000000000..7ff82a4fb8
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_instance.h
@@ -0,0 +1,272 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "accel.h"
+
+namespace embree
+{
+ struct MotionDerivativeCoefficients;
+
+ /*! Instanced acceleration structure */
+ struct Instance : public Geometry
+ {
+ ALIGNED_STRUCT_(16);
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE;
+
+ public:
+ Instance (Device* device, Accel* object = nullptr, unsigned int numTimeSteps = 1);
+ ~Instance();
+
+ private:
+ Instance (const Instance& other) DELETED; // do not implement
+ Instance& operator= (const Instance& other) DELETED; // do not implement
+
+ private:
+ LBBox3fa nonlinearBounds(const BBox1f& time_range_in,
+ const BBox1f& geom_time_range,
+ float geom_time_segments) const;
+
+ BBox3fa boundSegment(size_t itime,
+ BBox3fa const& obbox0, BBox3fa const& obbox1,
+ BBox3fa const& bbox0, BBox3fa const& bbox1,
+ float t_min, float t_max) const;
+
+ /* calculates the (correct) interpolated bounds */
+ __forceinline BBox3fa bounds(size_t itime0, size_t itime1, float f) const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(slerp(local2world[itime0], local2world[itime1], f),
+ lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
+ return xfmBounds(lerp(local2world[itime0], local2world[itime1], f),
+ lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
+ }
+
+ public:
+ virtual void setNumTimeSteps (unsigned int numTimeSteps) override;
+ virtual void setInstancedScene(const Ref<Scene>& scene) override;
+ virtual void setTransform(const AffineSpace3fa& local2world, unsigned int timeStep) override;
+ virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) override;
+ virtual AffineSpace3fa getTransform(float time) override;
+ virtual void setMask (unsigned mask) override;
+ virtual void build() {}
+ virtual void addElementsToCount (GeometryCounts & counts) const override;
+ virtual void commit() override;
+
+ public:
+
+ /*! calculates the bounds of instance */
+ __forceinline BBox3fa bounds(size_t i) const {
+ assert(i == 0);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(quaternionDecompositionToAffineSpace(local2world[0]),object->bounds.bounds());
+ return xfmBounds(local2world[0],object->bounds.bounds());
+ }
+
+ /*! gets the bounds of the instanced scene */
+ __forceinline BBox3fa getObjectBounds(size_t itime) const {
+ return object->getBounds(timeStep(itime));
+ }
+
+ /*! calculates the bounds of instance */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const {
+ assert(i == 0);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(quaternionDecompositionToAffineSpace(local2world[itime]),getObjectBounds(itime));
+ return xfmBounds(local2world[itime],getObjectBounds(itime));
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t i, const BBox1f& dt) const {
+ assert(i == 0);
+ LBBox3fa lbbox = nonlinearBounds(dt, time_range, fnumTimeSegments);
+ return lbbox;
+ }
+
+ /*! calculates the build bounds of the i'th item, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ assert(i==0);
+ const BBox3fa b = bounds(i);
+ if (bbox) *bbox = b;
+ return isvalid(b);
+ }
+
+ /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ assert(i==0);
+ const LBBox3fa bounds = linearBounds(i,itime);
+ bbox = bounds.bounds ();
+ return isvalid(bounds);
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return numPrimitives;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return numPrimitives != otherVersion;
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ assert(i == 0);
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid(bounds(i,itime))) return false;
+
+ return true;
+ }
+
+ __forceinline AffineSpace3fa getLocal2World() const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return quaternionDecompositionToAffineSpace(local2world[0]);
+ return local2world[0];
+ }
+
+ __forceinline AffineSpace3fa getLocal2World(float t) const
+ {
+ float ftime; const unsigned int itime = timeSegment(t, ftime);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return slerp(local2world[itime+0],local2world[itime+1],ftime);
+ return lerp(local2world[itime+0],local2world[itime+1],ftime);
+ }
+
+ __forceinline AffineSpace3fa getWorld2Local() const {
+ return world2local0;
+ }
+
+ __forceinline AffineSpace3fa getWorld2Local(float t) const {
+ return rcp(getLocal2World(t));
+ }
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2Local(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return getWorld2LocalSlerp(valid, t);
+ return getWorld2LocalLerp(valid, t);
+ }
+
+ private:
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2LocalSlerp(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ vfloat<K> ftime;
+ const vint<K> itime_k = timeSegment(t, ftime);
+ assert(any(valid));
+ const size_t index = bsf(movemask(valid));
+ const int itime = itime_k[index];
+ if (likely(all(valid, itime_k == vint<K>(itime)))) {
+ return rcp(slerp(AffineSpace3vff<K>(local2world[itime+0]),
+ AffineSpace3vff<K>(local2world[itime+1]),
+ ftime));
+ }
+ else {
+ AffineSpace3vff<K> space0,space1;
+ vbool<K> valid1 = valid;
+ while (any(valid1)) {
+ vbool<K> valid2;
+ const int itime = next_unique(valid1, itime_k, valid2);
+ space0 = select(valid2, AffineSpace3vff<K>(local2world[itime+0]), space0);
+ space1 = select(valid2, AffineSpace3vff<K>(local2world[itime+1]), space1);
+ }
+ return rcp(slerp(space0, space1, ftime));
+ }
+ }
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2LocalLerp(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ vfloat<K> ftime;
+ const vint<K> itime_k = timeSegment(t, ftime);
+ assert(any(valid));
+ const size_t index = bsf(movemask(valid));
+ const int itime = itime_k[index];
+ if (likely(all(valid, itime_k == vint<K>(itime)))) {
+ return rcp(lerp(AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]),
+ AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]),
+ ftime));
+ } else {
+ AffineSpace3vf<K> space0,space1;
+ vbool<K> valid1 = valid;
+ while (any(valid1)) {
+ vbool<K> valid2;
+ const int itime = next_unique(valid1, itime_k, valid2);
+ space0 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]), space0);
+ space1 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]), space1);
+ }
+ return rcp(lerp(space0, space1, ftime));
+ }
+ }
+
+ public:
+ Accel* object; //!< pointer to instanced acceleration structure
+ AffineSpace3ff* local2world; //!< transformation from local space to world space for each timestep (either normal matrix or quaternion decomposition)
+ AffineSpace3fa world2local0; //!< transformation from world space to local space for timestep 0
+ };
+
+ namespace isa
+ {
+ struct InstanceISA : public Instance
+ {
+ InstanceISA (Device* device)
+ : Instance(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfo pinfo(empty);
+ BBox3fa b = empty;
+ if (!buildBounds(0,&b)) return pinfo;
+ // const BBox3fa b = bounds(0);
+ // if (!isvalid(b)) return pinfo;
+
+ const PrimRef prim(b,geomID,unsigned(0));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfo pinfo(empty);
+ BBox3fa b = empty;
+ if (!buildBounds(0,&b)) return pinfo;
+ // if (!valid(0,range<size_t>(itime))) return pinfo;
+ // const PrimRef prim(linearBounds(0,itime).bounds(),geomID,unsigned(0));
+ const PrimRef prim(b,geomID,unsigned(0));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfoMB pinfo(empty);
+ if (!valid(0, timeSegmentRange(t0t1))) return pinfo;
+ const PrimRefMB prim(linearBounds(0,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(0));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(Instance*, createInstance, Device*);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_line_segments.h b/thirdparty/embree-aarch64/kernels/common/scene_line_segments.h
new file mode 100644
index 0000000000..c0f9ee8f77
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_line_segments.h
@@ -0,0 +1,307 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! represents an array of line segments */
+ struct LineSegments : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_CURVE2;
+
+ public:
+
+ /*! line segments construction */
+ LineSegments (Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask (unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify ();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void setTessellationRate(float N);
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns the i'th segment */
+ __forceinline const unsigned int& segment(size_t i) const {
+ return segments[i];
+ }
+
+ /*! returns the segment to the left of the i'th segment */
+ __forceinline bool segmentLeftExists(size_t i) const {
+ assert (flags);
+ return (flags[i] & RTC_CURVE_FLAG_NEIGHBOR_LEFT) != 0;
+ }
+
+ /*! returns the segment to the right of the i'th segment */
+ __forceinline bool segmentRightExists(size_t i) const {
+ assert (flags);
+ return (flags[i] & RTC_CURVE_FLAG_NEIGHBOR_RIGHT) != 0;
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const Vec3ff& v0, const Vec3ff& v1) const
+ {
+ const BBox3ff b = merge(BBox3ff(v0),BBox3ff(v1));
+ return enlarge((BBox3fa)b,maxRadiusScale*Vec3fa(max(v0.w,v1.w)));
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0);
+ const Vec3ff v1 = vertex(index+1);
+ return bounds(v0,v1);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ return bounds(v0,v1);
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0);
+ const Vec3ff v1 = vertex(index+1);
+ const Vec3ff w0(xfmVector(space,(Vec3fa)v0),v0.w);
+ const Vec3ff w1(xfmVector(space,(Vec3fa)v1),v1.w);
+ return bounds(w0,w1);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i, size_t itime) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff w0(xfmVector(space,(Vec3fa)v0),v0.w);
+ const Vec3ff w1(xfmVector(space,(Vec3fa)v1),v1.w);
+ return bounds(w0,w1);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = segment(i);
+ if (index+1 >= numVertices()) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ const Vec3ff v0 = vertex(index+0,itime); if (unlikely(!isvalid4(v0))) return false;
+ const Vec3ff v1 = vertex(index+1,itime); if (unlikely(!isvalid4(v1))) return false;
+ if (min(v0.w,v1.w) < 0.0f) return false;
+ }
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox) const
+ {
+ if (!valid(i,0)) return false;
+ *bbox = bounds(i);
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ if (!valid(i,itime+0) || !valid(i,itime+1)) return false;
+ bbox = bounds(i,itime); // use bounds of first time step in builder
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(space, primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+ BufferView<unsigned int> segments; //!< array of line segment indices
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ BufferView<char> flags; //!< start, end flag per segment
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ int tessellationRate; //!< tessellation rate for bezier curve
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ namespace isa
+ {
+ struct LineSegmentsISA : public LineSegments
+ {
+ LineSegmentsISA (Device* device, Geometry::GType gtype)
+ : LineSegments(device,gtype) {}
+
+ Vec3fa computeDirection(unsigned int primID) const
+ {
+ const unsigned vtxID = segment(primID);
+ const Vec3fa v0 = vertex(vtxID+0);
+ const Vec3fa v1 = vertex(vtxID+1);
+ return v1-v0;
+ }
+
+ Vec3fa computeDirection(unsigned int primID, size_t time) const
+ {
+ const unsigned vtxID = segment(primID);
+ const Vec3fa v0 = vertex(vtxID+0,time);
+ const Vec3fa v1 = vertex(vtxID+1,time);
+ return v1-v0;
+ }
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ BBox3fa vbounds(size_t i) const {
+ return bounds(i);
+ }
+
+ BBox3fa vbounds(const LinearSpace3fa& space, size_t i) const {
+ return bounds(space,i);
+ }
+
+ LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const {
+ return linearBounds(primID,time_range);
+ }
+
+ LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ return linearBounds(space,primID,time_range);
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(LineSegments*, createLineSegments, Device* COMMA Geometry::GType);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_points.h b/thirdparty/embree-aarch64/kernels/common/scene_points.h
new file mode 100644
index 0000000000..1d39ed07ba
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_points.h
@@ -0,0 +1,282 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "buffer.h"
+#include "default.h"
+#include "geometry.h"
+
+namespace embree
+{
+ /*! represents an array of points */
+ struct Points : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_POINTS;
+
+ public:
+ /*! line segments construction */
+ Points(Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps(unsigned int numTimeSteps);
+ void setVertexAttributeCount(unsigned int N);
+ void setBuffer(RTCBufferType type,
+ unsigned int slot,
+ RTCFormat format,
+ const Ref<Buffer>& buffer,
+ size_t offset,
+ size_t stride,
+ unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const Vec3ff& v0) const {
+ return enlarge(BBox3fa(v0), maxRadiusScale*Vec3fa(v0.w));
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Vec3ff v0 = vertex(i);
+ return bounds(v0);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Vec3ff v0 = vertex(i, itime);
+ return bounds(v0);
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i) const
+ {
+ const Vec3ff v0 = vertex(i);
+ const Vec3ff w0(xfmVector(space, (Vec3fa)v0), v0.w);
+ return bounds(w0);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i, size_t itime) const
+ {
+ const Vec3ff v0 = vertex(i, itime);
+ const Vec3ff w0(xfmVector(space, (Vec3fa)v0), v0.w);
+ return bounds(w0);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = (unsigned int)i;
+ if (index >= numVertices())
+ return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++) {
+ const Vec3ff v0 = vertex(index + 0, itime);
+ if (unlikely(!isvalid4(v0)))
+ return false;
+ if (v0.w < 0.0f)
+ return false;
+ }
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i, itime + 0), bounds(i, itime + 1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox) const
+ {
+ if (!valid(i, 0))
+ return false;
+ *bbox = bounds(i);
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ if (!valid(i, itime + 0) || !valid(i, itime + 1))
+ return false;
+ bbox = bounds(i, itime); // use bounds of first time step in builder
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&](size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&](size_t itime) { return bounds(space, primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ namespace isa
+ {
+ struct PointsISA : public Points
+ {
+ PointsISA(Device* device, Geometry::GType gtype) : Points(device, gtype) {}
+
+ Vec3fa computeDirection(unsigned int primID) const
+ {
+ return Vec3fa(1, 0, 0);
+ }
+
+ Vec3fa computeDirection(unsigned int primID, size_t time) const
+ {
+ return Vec3fa(1, 0, 0);
+ }
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j, &bounds))
+ continue;
+ const PrimRef prim(bounds, geomID, unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j, itime, bounds))
+ continue;
+ const PrimRef prim(bounds, geomID, unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims,
+ const BBox1f& t0t1,
+ const range<size_t>& r,
+ size_t k,
+ unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ if (!valid(j, timeSegmentRange(t0t1)))
+ continue;
+ const PrimRefMB prim(linearBounds(j, t0t1), this->numTimeSegments(), this->time_range, this->numTimeSegments(), geomID, unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ BBox3fa vbounds(size_t i) const
+ {
+ return bounds(i);
+ }
+
+ BBox3fa vbounds(const LinearSpace3fa& space, size_t i) const
+ {
+ return bounds(space, i);
+ }
+
+ LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const
+ {
+ return linearBounds(primID, time_range);
+ }
+
+ LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const
+ {
+ return linearBounds(space, primID, time_range);
+ }
+ };
+ } // namespace isa
+
+ DECLARE_ISA_FUNCTION(Points*, createPoints, Device* COMMA Geometry::GType);
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_quad_mesh.h b/thirdparty/embree-aarch64/kernels/common/scene_quad_mesh.h
new file mode 100644
index 0000000000..d5bb054b14
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_quad_mesh.h
@@ -0,0 +1,277 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Quad Mesh */
+ struct QuadMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_QUAD_MESH;
+
+ /*! triangle indices */
+ struct Quad
+ {
+ uint32_t v[4];
+
+ /*! outputs triangle indices */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Quad& q) {
+ return cout << "Quad {" << q.v[0] << ", " << q.v[1] << ", " << q.v[2] << ", " << q.v[3] << " }";
+ }
+ };
+
+ public:
+
+ /*! quad mesh construction */
+ QuadMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th quad */
+ __forceinline const Quad& quad(size_t i) const {
+ return quads[i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! calculates the bounds of the i'th quad */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0]);
+ const Vec3fa v1 = vertex(q.v[1]);
+ const Vec3fa v2 = vertex(q.v[2]);
+ const Vec3fa v3 = vertex(q.v[3]);
+ return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
+ }
+
+ /*! calculates the bounds of the i'th quad at the itime'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0],itime);
+ const Vec3fa v1 = vertex(q.v[1],itime);
+ const Vec3fa v2 = vertex(q.v[2],itime);
+ const Vec3fa v3 = vertex(q.v[3],itime);
+ return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const Quad& q = quad(i);
+ if (unlikely(q.v[0] >= numVertices())) return false;
+ if (unlikely(q.v[1] >= numVertices())) return false;
+ if (unlikely(q.v[2] >= numVertices())) return false;
+ if (unlikely(q.v[3] >= numVertices())) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ if (!isvalid(vertex(q.v[0],itime))) return false;
+ if (!isvalid(vertex(q.v[1],itime))) return false;
+ if (!isvalid(vertex(q.v[2],itime))) return false;
+ if (!isvalid(vertex(q.v[3],itime))) return false;
+ }
+
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th quad at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const Quad& q = quad(i);
+ if (q.v[0] >= numVertices()) return false;
+ if (q.v[1] >= numVertices()) return false;
+ if (q.v[2] >= numVertices()) return false;
+ if (q.v[3] >= numVertices()) return false;
+
+ for (unsigned int t=0; t<numTimeSteps; t++)
+ {
+ const Vec3fa v0 = vertex(q.v[0],t);
+ const Vec3fa v1 = vertex(q.v[1],t);
+ const Vec3fa v2 = vertex(q.v[2],t);
+ const Vec3fa v3 = vertex(q.v[3],t);
+
+ if (unlikely(!isvalid(v0) || !isvalid(v1) || !isvalid(v2) || !isvalid(v3)))
+ return false;
+ }
+
+ if (bbox)
+ *bbox = bounds(i);
+
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const Quad& q = quad(i);
+ if (unlikely(q.v[0] >= numVertices())) return false;
+ if (unlikely(q.v[1] >= numVertices())) return false;
+ if (unlikely(q.v[2] >= numVertices())) return false;
+ if (unlikely(q.v[3] >= numVertices())) return false;
+
+ assert(itime+1 < numTimeSteps);
+ const Vec3fa a0 = vertex(q.v[0],itime+0); if (unlikely(!isvalid(a0))) return false;
+ const Vec3fa a1 = vertex(q.v[1],itime+0); if (unlikely(!isvalid(a1))) return false;
+ const Vec3fa a2 = vertex(q.v[2],itime+0); if (unlikely(!isvalid(a2))) return false;
+ const Vec3fa a3 = vertex(q.v[3],itime+0); if (unlikely(!isvalid(a3))) return false;
+ const Vec3fa b0 = vertex(q.v[0],itime+1); if (unlikely(!isvalid(b0))) return false;
+ const Vec3fa b1 = vertex(q.v[1],itime+1); if (unlikely(!isvalid(b1))) return false;
+ const Vec3fa b2 = vertex(q.v[2],itime+1); if (unlikely(!isvalid(b2))) return false;
+ const Vec3fa b3 = vertex(q.v[3],itime+1); if (unlikely(!isvalid(b3))) return false;
+
+ /* use bounds of first time step in builder */
+ bbox = BBox3fa(min(a0,a1,a2,a3),max(a0,a1,a2,a3));
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& dt, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(dt))) return false;
+ bbox = linearBounds(i, dt);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return quads.modCounter;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return quads.isModified(otherVersion); // || numPrimitivesChanged;
+ }
+
+ /* returns the projected area */
+ __forceinline float projectedPrimitiveArea(const size_t i) const {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0]);
+ const Vec3fa v1 = vertex(q.v[1]);
+ const Vec3fa v2 = vertex(q.v[2]);
+ const Vec3fa v3 = vertex(q.v[3]);
+ return areaProjectedTriangle(v0,v1,v3) +
+ areaProjectedTriangle(v1,v2,v3);
+ }
+
+ public:
+ BufferView<Quad> quads; //!< array of quads
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< vertex attribute buffers
+ };
+
+ namespace isa
+ {
+ struct QuadMeshISA : public QuadMesh
+ {
+ QuadMeshISA (Device* device)
+ : QuadMesh(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(QuadMesh*, createQuadMesh, Device*);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_subdiv_mesh.h b/thirdparty/embree-aarch64/kernels/common/scene_subdiv_mesh.h
new file mode 100644
index 0000000000..d0246009db
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_subdiv_mesh.h
@@ -0,0 +1,326 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+#include "../subdiv/half_edge.h"
+#include "../subdiv/tessellation_cache.h"
+#include "../subdiv/catmullclark_coefficients.h"
+#include "../subdiv/patch.h"
+#include "../../common/algorithms/parallel_map.h"
+#include "../../common/algorithms/parallel_set.h"
+
+namespace embree
+{
+ class SubdivMesh : public Geometry
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ typedef HalfEdge::Edge Edge;
+
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_SUBDIV_MESH;
+
+ /*! structure used to sort half edges using radix sort by their key */
+ struct KeyHalfEdge
+ {
+ KeyHalfEdge() {}
+
+ KeyHalfEdge (uint64_t key, HalfEdge* edge)
+ : key(key), edge(edge) {}
+
+ __forceinline operator uint64_t() const {
+ return key;
+ }
+
+ friend __forceinline bool operator<(const KeyHalfEdge& e0, const KeyHalfEdge& e1) {
+ return e0.key < e1.key;
+ }
+
+ public:
+ uint64_t key;
+ HalfEdge* edge;
+ };
+
+ public:
+
+ /*! subdiv mesh construction */
+ SubdivMesh(Device* device);
+
+ public:
+ void setMask (unsigned mask);
+ void setSubdivisionMode (unsigned int topologyID, RTCSubdivisionMode mode);
+ void setVertexAttributeTopology(unsigned int vertexAttribID, unsigned int topologyID);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setTopologyCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void setTessellationRate(float N);
+ bool verify();
+ void commit();
+ void addElementsToCount (GeometryCounts & counts) const;
+ void setDisplacementFunction (RTCDisplacementFunctionN func);
+ unsigned int getFirstHalfEdge(unsigned int faceID);
+ unsigned int getFace(unsigned int edgeID);
+ unsigned int getNextHalfEdge(unsigned int edgeID);
+ unsigned int getPreviousHalfEdge(unsigned int edgeID);
+ unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID);
+
+ public:
+
+ /*! return the number of faces */
+ size_t numFaces() const {
+ return faceVertices.size();
+ }
+
+ /*! return the number of edges */
+ size_t numEdges() const {
+ return topology[0].vertexIndices.size();
+ }
+
+ /*! return the number of vertices */
+ size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! calculates the bounds of the i'th subdivision patch at the j'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t j = 0) const {
+ return topology[0].getHalfEdge(i)->bounds(vertices[j]);
+ }
+
+ /*! check if the i'th primitive is valid */
+ __forceinline bool valid(size_t i) const {
+ return topology[0].valid(i) && !invalidFace(i);
+ }
+
+ /*! check if the i'th primitive is valid for the j'th time range */
+ __forceinline bool valid(size_t i, size_t j) const {
+ return topology[0].valid(i) && !invalidFace(i,j);
+ }
+
+ /*! prints some statistics */
+ void printStatistics();
+
+ /*! initializes the half edge data structure */
+ void initializeHalfEdgeStructures ();
+
+ public:
+
+ /*! returns the vertex buffer for some time step */
+ __forceinline const BufferView<Vec3fa>& getVertexBuffer( const size_t t = 0 ) const {
+ return vertices[t];
+ }
+
+ /* returns tessellation level of edge */
+ __forceinline float getEdgeLevel(const size_t i) const
+ {
+ if (levels) return clamp(levels[i],1.0f,4096.0f); // FIXME: do we want to limit edge level?
+ else return clamp(tessellationRate,1.0f,4096.0f); // FIXME: do we want to limit edge level?
+ }
+
+ public:
+ RTCDisplacementFunctionN displFunc; //!< displacement function
+
+ /*! all buffers in this section are provided by the application */
+ public:
+
+ /*! the topology contains all data that may differ when
+ * interpolating different user data buffers */
+ struct Topology
+ {
+ public:
+
+ /*! Default topology construction */
+ Topology () : halfEdges(nullptr,0) {}
+
+ /*! Topology initialization */
+ Topology (SubdivMesh* mesh);
+
+ /*! make the class movable */
+ public:
+ Topology (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
+ : mesh(std::move(other.mesh)),
+ vertexIndices(std::move(other.vertexIndices)),
+ subdiv_mode(std::move(other.subdiv_mode)),
+ halfEdges(std::move(other.halfEdges)),
+ halfEdges0(std::move(other.halfEdges0)),
+ halfEdges1(std::move(other.halfEdges1)) {}
+
+ Topology& operator= (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
+ {
+ mesh = std::move(other.mesh);
+ vertexIndices = std::move(other.vertexIndices);
+ subdiv_mode = std::move(other.subdiv_mode);
+ halfEdges = std::move(other.halfEdges);
+ halfEdges0 = std::move(other.halfEdges0);
+ halfEdges1 = std::move(other.halfEdges1);
+ return *this;
+ }
+
+ public:
+ /*! check if the i'th primitive is valid in this topology */
+ __forceinline bool valid(size_t i) const
+ {
+ if (unlikely(subdiv_mode == RTC_SUBDIVISION_MODE_NO_BOUNDARY)) {
+ if (getHalfEdge(i)->faceHasBorder()) return false;
+ }
+ return true;
+ }
+
+ /*! updates the interpolation mode for the topology */
+ void setSubdivisionMode (RTCSubdivisionMode mode);
+
+ /*! marks all buffers as modified */
+ void update ();
+
+ /*! verifies index array */
+ bool verify (size_t numVertices);
+
+ /*! initializes the half edge data structure */
+ void initializeHalfEdgeStructures ();
+
+ private:
+
+ /*! recalculates the half edges */
+ void calculateHalfEdges();
+
+ /*! updates half edges when recalculation is not necessary */
+ void updateHalfEdges();
+
+ /*! user input data */
+ public:
+
+ SubdivMesh* mesh;
+
+ /*! indices of the vertices composing each face */
+ BufferView<unsigned int> vertexIndices;
+
+ /*! subdiv interpolation mode */
+ RTCSubdivisionMode subdiv_mode;
+
+ /*! generated data */
+ public:
+
+ /*! returns the start half edge for face f */
+ __forceinline const HalfEdge* getHalfEdge ( const size_t f ) const {
+ return &halfEdges[mesh->faceStartEdge[f]];
+ }
+
+ /*! Half edge structure, generated by initHalfEdgeStructures */
+ mvector<HalfEdge> halfEdges;
+
+ /*! the following data is only required during construction of the
+ * half edge structure and can be cleared for static scenes */
+ private:
+
+ /*! two arrays used to sort the half edges */
+ std::vector<KeyHalfEdge> halfEdges0;
+ std::vector<KeyHalfEdge> halfEdges1;
+ };
+
+ /*! returns the start half edge for topology t and face f */
+ __forceinline const HalfEdge* getHalfEdge ( const size_t t , const size_t f ) const {
+ return topology[t].getHalfEdge(f);
+ }
+
+ /*! buffer containing the number of vertices for each face */
+ BufferView<unsigned int> faceVertices;
+
+ /*! array of topologies */
+ vector<Topology> topology;
+
+ /*! vertex buffer (one buffer for each time step) */
+ vector<BufferView<Vec3fa>> vertices;
+
+ /*! user data buffers */
+ vector<RawBufferView> vertexAttribs;
+
+ /*! edge crease buffer containing edges (pairs of vertices) that carry edge crease weights */
+ BufferView<Edge> edge_creases;
+
+ /*! edge crease weights for each edge of the edge_creases buffer */
+ BufferView<float> edge_crease_weights;
+
+ /*! vertex crease buffer containing all vertices that carry vertex crease weights */
+ BufferView<unsigned int> vertex_creases;
+
+ /*! vertex crease weights for each vertex of the vertex_creases buffer */
+ BufferView<float> vertex_crease_weights;
+
+ /*! subdivision level for each half edge of the vertexIndices buffer */
+ BufferView<float> levels;
+ float tessellationRate; // constant rate that is used when levels is not set
+
+ /*! buffer that marks specific faces as holes */
+ BufferView<unsigned> holes;
+
+ /*! all data in this section is generated by initializeHalfEdgeStructures function */
+ private:
+
+ /*! number of half edges used by faces */
+ size_t numHalfEdges;
+
+ /*! fast lookup table to find the first half edge for some face */
+ mvector<uint32_t> faceStartEdge;
+
+ /*! fast lookup table to find the face for some half edge */
+ mvector<uint32_t> halfEdgeFace;
+
+ /*! set with all holes */
+ parallel_set<uint32_t> holeSet;
+
+ /*! fast lookup table to detect invalid faces */
+ mvector<int8_t> invalid_face;
+
+ /*! test if face i is invalid in timestep j */
+ __forceinline int8_t& invalidFace(size_t i, size_t j = 0) { return invalid_face[i*numTimeSteps+j]; }
+ __forceinline const int8_t& invalidFace(size_t i, size_t j = 0) const { return invalid_face[i*numTimeSteps+j]; }
+
+ /*! interpolation cache */
+ public:
+ static __forceinline size_t numInterpolationSlots4(size_t stride) { return (stride+15)/16; }
+ static __forceinline size_t numInterpolationSlots8(size_t stride) { return (stride+31)/32; }
+ static __forceinline size_t interpolationSlot(size_t prim, size_t slot, size_t stride) {
+ const size_t slots = numInterpolationSlots4(stride);
+ assert(slot < slots);
+ return slots*prim+slot;
+ }
+ std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_buffer_tags;
+ std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_attrib_buffer_tags;
+ std::vector<Patch3fa::Ref> patch_eval_trees;
+
+ /*! the following data is only required during construction of the
+ * half edge structure and can be cleared for static scenes */
+ private:
+
+ /*! map with all vertex creases */
+ parallel_map<uint32_t,float> vertexCreaseMap;
+
+ /*! map with all edge creases */
+ parallel_map<uint64_t,float> edgeCreaseMap;
+
+ protected:
+
+ /*! counts number of geometry commits */
+ size_t commitCounter;
+ };
+
+ namespace isa
+ {
+ struct SubdivMeshISA : public SubdivMesh
+ {
+ SubdivMeshISA (Device* device)
+ : SubdivMesh(device) {}
+
+ void interpolate(const RTCInterpolateArguments* const args);
+ void interpolateN(const RTCInterpolateNArguments* const args);
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(SubdivMesh*, createSubdivMesh, Device*);
+};
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.cpp b/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.cpp
new file mode 100644
index 0000000000..d1c2750f14
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.cpp
@@ -0,0 +1,243 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "scene_triangle_mesh.h"
+#include "scene.h"
+
+namespace embree
+{
+#if defined(EMBREE_LOWEST_ISA)
+
+ TriangleMesh::TriangleMesh (Device* device)
+ : Geometry(device,GTY_TRIANGLE_MESH,0,1)
+ {
+ vertices.resize(numTimeSteps);
+ }
+
+ void TriangleMesh::setMask (unsigned mask)
+ {
+ this->mask = mask;
+ Geometry::update();
+ }
+
+ void TriangleMesh::setNumTimeSteps (unsigned int numTimeSteps)
+ {
+ vertices.resize(numTimeSteps);
+ Geometry::setNumTimeSteps(numTimeSteps);
+ }
+
+ void TriangleMesh::setVertexAttributeCount (unsigned int N)
+ {
+ vertexAttribs.resize(N);
+ Geometry::update();
+ }
+
+ void TriangleMesh::setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num)
+ {
+ /* verify that all accesses are 4 bytes aligned */
+ if (((size_t(buffer->getPtr()) + offset) & 0x3) || (stride & 0x3))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "data must be 4 bytes aligned");
+
+ if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (format != RTC_FORMAT_FLOAT3)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex buffer format");
+
+ /* if buffer is larger than 16GB the premultiplied index optimization does not work */
+ if (stride*num > 16ll*1024ll*1024ll*1024ll)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "vertex buffer can be at most 16GB large");
+
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid vertex buffer slot");
+
+ vertices[slot].set(buffer, offset, stride, num, format);
+ vertices[slot].checkPadding16();
+ vertices0 = vertices[0];
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (format < RTC_FORMAT_FLOAT || format > RTC_FORMAT_FLOAT16)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex attribute buffer format");
+
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex attribute buffer slot");
+
+ vertexAttribs[slot].set(buffer, offset, stride, num, format);
+ vertexAttribs[slot].checkPadding16();
+ }
+ else if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ if (format != RTC_FORMAT_UINT3)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid index buffer format");
+
+ triangles.set(buffer, offset, stride, num, format);
+ setNumPrimitives(num);
+ }
+ else
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ }
+
+ void* TriangleMesh::getBuffer(RTCBufferType type, unsigned int slot)
+ {
+ if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return triangles.getPtr();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return vertices[slot].getPtr();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return vertexAttribs[slot].getPtr();
+ }
+ else
+ {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ return nullptr;
+ }
+ }
+
+ void TriangleMesh::updateBuffer(RTCBufferType type, unsigned int slot)
+ {
+ if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ triangles.setModified();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ vertices[slot].setModified();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ vertexAttribs[slot].setModified();
+ }
+ else
+ {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ }
+
+ Geometry::update();
+ }
+
+ void TriangleMesh::commit()
+ {
+ /* verify that stride of all time steps are identical */
+ for (unsigned int t=0; t<numTimeSteps; t++)
+ if (vertices[t].getStride() != vertices[0].getStride())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"stride of vertex buffers have to be identical for each time step");
+
+ Geometry::commit();
+ }
+
+ void TriangleMesh::addElementsToCount (GeometryCounts & counts) const
+ {
+ if (numTimeSteps == 1) counts.numTriangles += numPrimitives;
+ else counts.numMBTriangles += numPrimitives;
+ }
+
+ bool TriangleMesh::verify()
+ {
+ /*! verify size of vertex arrays */
+ if (vertices.size() == 0) return false;
+ for (const auto& buffer : vertices)
+ if (buffer.size() != numVertices())
+ return false;
+
+ /*! verify size of user vertex arrays */
+ for (const auto& buffer : vertexAttribs)
+ if (buffer.size() != numVertices())
+ return false;
+
+ /*! verify triangle indices */
+ for (size_t i=0; i<size(); i++) {
+ if (triangles[i].v[0] >= numVertices()) return false;
+ if (triangles[i].v[1] >= numVertices()) return false;
+ if (triangles[i].v[2] >= numVertices()) return false;
+ }
+
+ /*! verify vertices */
+ for (const auto& buffer : vertices)
+ for (size_t i=0; i<buffer.size(); i++)
+ if (!isvalid(buffer[i]))
+ return false;
+
+ return true;
+ }
+
+ void TriangleMesh::interpolate(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ float v = args->v;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ for (unsigned int i=0; i<valueCount; i+=4)
+ {
+ size_t ofs = i*sizeof(float);
+ const float w = 1.0f-u-v;
+ const Triangle& tri = triangle(primID);
+ const vbool4 valid = vint4((int)i)+vint4(step) < vint4(int(valueCount));
+ const vfloat4 p0 = vfloat4::loadu(valid,(float*)&src[tri.v[0]*stride+ofs]);
+ const vfloat4 p1 = vfloat4::loadu(valid,(float*)&src[tri.v[1]*stride+ofs]);
+ const vfloat4 p2 = vfloat4::loadu(valid,(float*)&src[tri.v[2]*stride+ofs]);
+
+ if (P) {
+ vfloat4::storeu(valid,P+i,madd(w,p0,madd(u,p1,v*p2)));
+ }
+ if (dPdu) {
+ assert(dPdu); vfloat4::storeu(valid,dPdu+i,p1-p0);
+ assert(dPdv); vfloat4::storeu(valid,dPdv+i,p2-p0);
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); vfloat4::storeu(valid,ddPdudu+i,vfloat4(zero));
+ assert(ddPdvdv); vfloat4::storeu(valid,ddPdvdv+i,vfloat4(zero));
+ assert(ddPdudv); vfloat4::storeu(valid,ddPdudv+i,vfloat4(zero));
+ }
+ }
+ }
+
+#endif
+
+ namespace isa
+ {
+ TriangleMesh* createTriangleMesh(Device* device) {
+ return new TriangleMeshISA(device);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.h b/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.h
new file mode 100644
index 0000000000..eaf2e1799a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_triangle_mesh.h
@@ -0,0 +1,264 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Triangle Mesh */
+ struct TriangleMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_TRIANGLE_MESH;
+
+ /*! triangle indices */
+ struct Triangle
+ {
+ uint32_t v[3];
+
+ /*! outputs triangle indices */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Triangle& t) {
+ return cout << "Triangle { " << t.v[0] << ", " << t.v[1] << ", " << t.v[2] << " }";
+ }
+ };
+
+ public:
+
+ /*! triangle mesh construction */
+ TriangleMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th triangle*/
+ __forceinline const Triangle& triangle(size_t i) const {
+ return triangles[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const Vec3fa vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! calculates the bounds of the i'th triangle */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0]);
+ const Vec3fa v1 = vertex(tri.v[1]);
+ const Vec3fa v2 = vertex(tri.v[2]);
+ return BBox3fa(min(v0,v1,v2),max(v0,v1,v2));
+ }
+
+ /*! calculates the bounds of the i'th triangle at the itime'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0],itime);
+ const Vec3fa v1 = vertex(tri.v[1],itime);
+ const Vec3fa v2 = vertex(tri.v[2],itime);
+ return BBox3fa(min(v0,v1,v2),max(v0,v1,v2));
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ if (!isvalid(vertex(tri.v[0],itime))) return false;
+ if (!isvalid(vertex(tri.v[1],itime))) return false;
+ if (!isvalid(vertex(tri.v[2],itime))) return false;
+ }
+
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ for (size_t t=0; t<numTimeSteps; t++)
+ {
+ const Vec3fa v0 = vertex(tri.v[0],t);
+ const Vec3fa v1 = vertex(tri.v[1],t);
+ const Vec3fa v2 = vertex(tri.v[2],t);
+ if (unlikely(!isvalid(v0) || !isvalid(v1) || !isvalid(v2)))
+ return false;
+ }
+
+ if (likely(bbox))
+ *bbox = bounds(i);
+
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ assert(itime+1 < numTimeSteps);
+ const Vec3fa a0 = vertex(tri.v[0],itime+0); if (unlikely(!isvalid(a0))) return false;
+ const Vec3fa a1 = vertex(tri.v[1],itime+0); if (unlikely(!isvalid(a1))) return false;
+ const Vec3fa a2 = vertex(tri.v[2],itime+0); if (unlikely(!isvalid(a2))) return false;
+ const Vec3fa b0 = vertex(tri.v[0],itime+1); if (unlikely(!isvalid(b0))) return false;
+ const Vec3fa b1 = vertex(tri.v[1],itime+1); if (unlikely(!isvalid(b1))) return false;
+ const Vec3fa b2 = vertex(tri.v[2],itime+1); if (unlikely(!isvalid(b2))) return false;
+
+ /* use bounds of first time step in builder */
+ bbox = BBox3fa(min(a0,a1,a2),max(a0,a1,a2));
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& dt, LBBox3fa& bbox) const {
+ if (!valid(i, timeSegmentRange(dt))) return false;
+ bbox = linearBounds(i, dt);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return triangles.modCounter;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return triangles.isModified(otherVersion); // || numPrimitivesChanged;
+ }
+
+ /* returns the projected area */
+ __forceinline float projectedPrimitiveArea(const size_t i) const {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0]);
+ const Vec3fa v1 = vertex(tri.v[1]);
+ const Vec3fa v2 = vertex(tri.v[2]);
+ return areaProjectedTriangle(v0,v1,v2);
+ }
+
+ public:
+ BufferView<Triangle> triangles; //!< array of triangles
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<RawBufferView> vertexAttribs; //!< vertex attributes
+ };
+
+ namespace isa
+ {
+ struct TriangleMeshISA : public TriangleMesh
+ {
+ TriangleMeshISA (Device* device)
+ : TriangleMesh(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(TriangleMesh*, createTriangleMesh, Device*);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/scene_user_geometry.h b/thirdparty/embree-aarch64/kernels/common/scene_user_geometry.h
new file mode 100644
index 0000000000..8d11ed6986
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/scene_user_geometry.h
@@ -0,0 +1,77 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accelset.h"
+
+namespace embree
+{
+ /*! User geometry with user defined intersection functions */
+ struct UserGeometry : public AccelSet
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_USER_GEOMETRY;
+
+ public:
+ UserGeometry (Device* device, unsigned int items = 0, unsigned int numTimeSteps = 1);
+ virtual void setMask (unsigned mask);
+ virtual void setBoundsFunction (RTCBoundsFunction bounds, void* userPtr);
+ virtual void setIntersectFunctionN (RTCIntersectFunctionN intersect);
+ virtual void setOccludedFunctionN (RTCOccludedFunctionN occluded);
+ virtual void build() {}
+ virtual void addElementsToCount (GeometryCounts & counts) const;
+ };
+
+ namespace isa
+ {
+ struct UserGeometryISA : public UserGeometry
+ {
+ UserGeometryISA (Device* device)
+ : UserGeometry(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(UserGeometry*, createUserGeometry, Device*);
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/stack_item.h b/thirdparty/embree-aarch64/kernels/common/stack_item.h
new file mode 100644
index 0000000000..533c385365
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/stack_item.h
@@ -0,0 +1,125 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! An item on the stack holds the node ID and distance of that node. */
+ template<typename T>
+ struct __aligned(16) StackItemT
+ {
+ /*! assert that the xchg function works */
+ static_assert(sizeof(T) <= 12, "sizeof(T) <= 12 failed");
+
+ __forceinline StackItemT() {}
+
+ __forceinline StackItemT(T &ptr, unsigned &dist) : ptr(ptr), dist(dist) {}
+
+ /*! use SSE instructions to swap stack items */
+ __forceinline static void xchg(StackItemT& a, StackItemT& b)
+ {
+ const vfloat4 sse_a = vfloat4::load((float*)&a);
+ const vfloat4 sse_b = vfloat4::load((float*)&b);
+ vfloat4::store(&a,sse_b);
+ vfloat4::store(&b,sse_a);
+ }
+
+ /*! Sort 2 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2) {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ }
+
+ /*! Sort 3 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2, StackItemT& s3)
+ {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ if (s3.dist < s2.dist) xchg(s3,s2);
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ }
+
+ /*! Sort 4 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2, StackItemT& s3, StackItemT& s4)
+ {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ if (s4.dist < s3.dist) xchg(s4,s3);
+ if (s3.dist < s1.dist) xchg(s3,s1);
+ if (s4.dist < s2.dist) xchg(s4,s2);
+ if (s3.dist < s2.dist) xchg(s3,s2);
+ }
+
+ /*! use SSE instructions to swap stack items */
+ __forceinline static void cmp_xchg(vint4& a, vint4& b)
+ {
+#if defined(__AVX512VL__)
+ const vboolf4 mask(shuffle<2,2,2,2>(b) < shuffle<2,2,2,2>(a));
+#else
+ const vboolf4 mask0(b < a);
+ const vboolf4 mask(shuffle<2,2,2,2>(mask0));
+#endif
+ const vint4 c = select(mask,b,a);
+ const vint4 d = select(mask,a,b);
+ a = c;
+ b = d;
+ }
+
+ /*! Sort 3 stack items. */
+ __forceinline static void sort3(vint4& s1, vint4& s2, vint4& s3)
+ {
+ cmp_xchg(s2,s1);
+ cmp_xchg(s3,s2);
+ cmp_xchg(s2,s1);
+ }
+
+ /*! Sort 4 stack items. */
+ __forceinline static void sort4(vint4& s1, vint4& s2, vint4& s3, vint4& s4)
+ {
+ cmp_xchg(s2,s1);
+ cmp_xchg(s4,s3);
+ cmp_xchg(s3,s1);
+ cmp_xchg(s4,s2);
+ cmp_xchg(s3,s2);
+ }
+
+
+ /*! Sort N stack items. */
+ __forceinline friend void sort(StackItemT* begin, StackItemT* end)
+ {
+ for (StackItemT* i = begin+1; i != end; ++i)
+ {
+ const vfloat4 item = vfloat4::load((float*)i);
+ const unsigned dist = i->dist;
+ StackItemT* j = i;
+
+ while ((j != begin) && ((j-1)->dist < dist))
+ {
+ vfloat4::store(j, vfloat4::load((float*)(j-1)));
+ --j;
+ }
+
+ vfloat4::store(j, item);
+ }
+ }
+
+ public:
+ T ptr;
+ unsigned dist;
+ };
+
+ /*! An item on the stack holds the node ID and active ray mask. */
+ template<typename T>
+ struct __aligned(8) StackItemMaskT
+ {
+ T ptr;
+ size_t mask;
+ };
+
+ struct __aligned(8) StackItemMaskCoherent
+ {
+ size_t mask;
+ size_t parent;
+ size_t child;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/stat.cpp b/thirdparty/embree-aarch64/kernels/common/stat.cpp
new file mode 100644
index 0000000000..b73c3a8c76
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/stat.cpp
@@ -0,0 +1,128 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "stat.h"
+
+namespace embree
+{
+ Stat Stat::instance;
+
+ Stat::Stat () {
+ }
+
+ Stat::~Stat ()
+ {
+#ifdef EMBREE_STAT_COUNTERS
+ Stat::print(std::cout);
+#endif
+ }
+
+ void Stat::print(std::ostream& cout)
+ {
+ Counters& cntrs = instance.cntrs;
+ Counters::Data& data = instance.cntrs.code;
+ //Counters::Data& data = instance.cntrs.active;
+
+ /* print absolute numbers */
+ cout << "--------- ABSOLUTE ---------" << std::endl;
+ cout << " #normal_travs = " << float(data.normal.travs )*1E-6 << "M" << std::endl;
+ cout << " #nodes = " << float(data.normal.trav_nodes )*1E-6 << "M" << std::endl;
+ cout << " #nodes_xfm = " << float(data.normal.trav_xfm_nodes )*1E-6 << "M" << std::endl;
+ cout << " #leaves = " << float(data.normal.trav_leaves )*1E-6 << "M" << std::endl;
+ cout << " #prims = " << float(data.normal.trav_prims )*1E-6 << "M" << std::endl;
+ cout << " #prim_hits = " << float(data.normal.trav_prim_hits )*1E-6 << "M" << std::endl;
+
+ cout << " #stack nodes = " << float(data.normal.trav_stack_nodes )*1E-6 << "M" << std::endl;
+ cout << " #stack pop = " << float(data.normal.trav_stack_pop )*1E-6 << "M" << std::endl;
+
+ size_t normal_box_hits = 0;
+ size_t weighted_box_hits = 0;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) {
+ normal_box_hits += data.normal.trav_hit_boxes[i];
+ weighted_box_hits += data.normal.trav_hit_boxes[i]*i;
+ }
+ cout << " #hit_boxes = " << normal_box_hits << " (total) distribution: ";
+ float average = 0.0f;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++)
+ {
+ float value = 100.0f * data.normal.trav_hit_boxes[i] / normal_box_hits;
+ cout << "[" << i << "] " << value << " ";
+ average += (float)i*data.normal.trav_hit_boxes[i] / normal_box_hits;
+ }
+ cout << " average = " << average << std::endl;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.normal.trav_hit_boxes[i]*i / weighted_box_hits << " ";
+ cout << std::endl;
+
+ if (data.shadow.travs) {
+ cout << " #shadow_travs = " << float(data.shadow.travs )*1E-6 << "M" << std::endl;
+ cout << " #nodes = " << float(data.shadow.trav_nodes )*1E-6 << "M" << std::endl;
+ cout << " #nodes_xfm = " << float(data.shadow.trav_xfm_nodes)*1E-6 << "M" << std::endl;
+ cout << " #leaves = " << float(data.shadow.trav_leaves )*1E-6 << "M" << std::endl;
+ cout << " #prims = " << float(data.shadow.trav_prims )*1E-6 << "M" << std::endl;
+ cout << " #prim_hits = " << float(data.shadow.trav_prim_hits)*1E-6 << "M" << std::endl;
+
+ cout << " #stack nodes = " << float(data.shadow.trav_stack_nodes )*1E-6 << "M" << std::endl;
+ cout << " #stack pop = " << float(data.shadow.trav_stack_pop )*1E-6 << "M" << std::endl;
+
+ size_t shadow_box_hits = 0;
+ size_t weighted_shadow_box_hits = 0;
+
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) {
+ shadow_box_hits += data.shadow.trav_hit_boxes[i];
+ weighted_shadow_box_hits += data.shadow.trav_hit_boxes[i]*i;
+ }
+ cout << " #hit_boxes = ";
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.shadow.trav_hit_boxes[i] / shadow_box_hits << " ";
+ cout << std::endl;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.shadow.trav_hit_boxes[i]*i / weighted_shadow_box_hits << " ";
+ cout << std::endl;
+ }
+ cout << std::endl;
+
+ /* print per traversal numbers */
+ cout << "--------- PER TRAVERSAL ---------" << std::endl;
+ float active_normal_travs = float(cntrs.active.normal.travs )/float(cntrs.all.normal.travs );
+ float active_normal_trav_nodes = float(cntrs.active.normal.trav_nodes )/float(cntrs.all.normal.trav_nodes );
+ float active_normal_trav_xfm_nodes = float(cntrs.active.normal.trav_xfm_nodes )/float(cntrs.all.normal.trav_xfm_nodes );
+ float active_normal_trav_leaves = float(cntrs.active.normal.trav_leaves)/float(cntrs.all.normal.trav_leaves);
+ float active_normal_trav_prims = float(cntrs.active.normal.trav_prims )/float(cntrs.all.normal.trav_prims );
+ float active_normal_trav_prim_hits = float(cntrs.active.normal.trav_prim_hits )/float(cntrs.all.normal.trav_prim_hits );
+ float active_normal_trav_stack_pop = float(cntrs.active.normal.trav_stack_pop )/float(cntrs.all.normal.trav_stack_pop );
+
+ cout << " #normal_travs = " << float(cntrs.code.normal.travs )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_travs << "% active" << std::endl;
+ cout << " #nodes = " << float(cntrs.code.normal.trav_nodes )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_nodes << "% active" << std::endl;
+ cout << " #node_xfm = " << float(cntrs.code.normal.trav_xfm_nodes )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_xfm_nodes << "% active" << std::endl;
+ cout << " #leaves = " << float(cntrs.code.normal.trav_leaves)/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_leaves << "% active" << std::endl;
+ cout << " #prims = " << float(cntrs.code.normal.trav_prims )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_prims << "% active" << std::endl;
+ cout << " #prim_hits = " << float(cntrs.code.normal.trav_prim_hits )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_prim_hits << "% active" << std::endl;
+ cout << " #stack_pop = " << float(cntrs.code.normal.trav_stack_pop )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_stack_pop << "% active" << std::endl;
+
+ if (cntrs.all.shadow.travs) {
+ float active_shadow_travs = float(cntrs.active.shadow.travs )/float(cntrs.all.shadow.travs );
+ float active_shadow_trav_nodes = float(cntrs.active.shadow.trav_nodes )/float(cntrs.all.shadow.trav_nodes );
+ float active_shadow_trav_xfm_nodes = float(cntrs.active.shadow.trav_xfm_nodes )/float(cntrs.all.shadow.trav_xfm_nodes );
+ float active_shadow_trav_leaves = float(cntrs.active.shadow.trav_leaves)/float(cntrs.all.shadow.trav_leaves);
+ float active_shadow_trav_prims = float(cntrs.active.shadow.trav_prims )/float(cntrs.all.shadow.trav_prims );
+ float active_shadow_trav_prim_hits = float(cntrs.active.shadow.trav_prim_hits )/float(cntrs.all.shadow.trav_prim_hits );
+
+ cout << " #shadow_travs = " << float(cntrs.code.shadow.travs )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_travs << "% active" << std::endl;
+ cout << " #nodes = " << float(cntrs.code.shadow.trav_nodes )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_nodes << "% active" << std::endl;
+ cout << " #nodes_xfm = " << float(cntrs.code.shadow.trav_xfm_nodes )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_xfm_nodes << "% active" << std::endl;
+ cout << " #leaves = " << float(cntrs.code.shadow.trav_leaves)/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_leaves << "% active" << std::endl;
+ cout << " #prims = " << float(cntrs.code.shadow.trav_prims )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_prims << "% active" << std::endl;
+ cout << " #prim_hits = " << float(cntrs.code.shadow.trav_prim_hits )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_prim_hits << "% active" << std::endl;
+
+ }
+ cout << std::endl;
+
+ /* print user counters for performance tuning */
+ cout << "--------- USER ---------" << std::endl;
+ for (size_t i=0; i<10; i++)
+ cout << "#user" << i << " = " << float(cntrs.user[i])/float(cntrs.all.normal.travs+cntrs.all.shadow.travs) << " per traversal" << std::endl;
+
+ cout << "#user5/user3 " << 100.0f*float(cntrs.user[5])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << "#user6/user3 " << 100.0f*float(cntrs.user[6])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << "#user7/user3 " << 100.0f*float(cntrs.user[7])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << std::endl;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/stat.h b/thirdparty/embree-aarch64/kernels/common/stat.h
new file mode 100644
index 0000000000..3cda2bd014
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/stat.h
@@ -0,0 +1,116 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+/* Macros to gather statistics */
+#ifdef EMBREE_STAT_COUNTERS
+# define STAT(x) x
+# define STAT3(s,x,y,z) \
+ STAT(Stat::get().code .s+=x); \
+ STAT(Stat::get().active.s+=y); \
+ STAT(Stat::get().all .s+=z);
+# define STAT_USER(i,x) Stat::get().user[i]+=x;
+#else
+# define STAT(x)
+# define STAT3(s,x,y,z)
+# define STAT_USER(i,x)
+#endif
+
+namespace embree
+{
+ /*! Gathers ray tracing statistics. We count 1) how often a code
+ * location is reached, 2) how many SIMD lanes are active, 3) how
+ * many SIMD lanes reach the code location */
+ class Stat
+ {
+ public:
+
+ static const size_t SIZE_HISTOGRAM = 64+1;
+
+ /*! constructs stat counter class */
+ Stat ();
+
+ /*! destructs stat counter class */
+ ~Stat ();
+
+ class Counters
+ {
+ public:
+ Counters () {
+ clear();
+ }
+
+ void clear()
+ {
+ all.clear();
+ active.clear();
+ code.clear();
+ for (auto& u : user) u.store(0);
+ }
+
+ public:
+
+ /* per packet and per ray stastics */
+ struct Data
+ {
+ void clear () {
+ normal.clear();
+ shadow.clear();
+ point_query.clear();
+ }
+
+ /* normal and shadow ray statistics */
+ struct
+ {
+ void clear()
+ {
+ travs.store(0);
+ trav_nodes.store(0);
+ trav_leaves.store(0);
+ trav_prims.store(0);
+ trav_prim_hits.store(0);
+ for (auto& v : trav_hit_boxes) v.store(0);
+ trav_stack_pop.store(0);
+ trav_stack_nodes.store(0);
+ trav_xfm_nodes.store(0);
+ }
+
+ public:
+ std::atomic<size_t> travs;
+ std::atomic<size_t> trav_nodes;
+ std::atomic<size_t> trav_leaves;
+ std::atomic<size_t> trav_prims;
+ std::atomic<size_t> trav_prim_hits;
+ std::atomic<size_t> trav_hit_boxes[SIZE_HISTOGRAM+1];
+ std::atomic<size_t> trav_stack_pop;
+ std::atomic<size_t> trav_stack_nodes;
+ std::atomic<size_t> trav_xfm_nodes;
+
+ } normal, shadow, point_query;
+ } all, active, code;
+
+ std::atomic<size_t> user[10];
+ };
+
+ public:
+
+ static __forceinline Counters& get() {
+ return instance.cntrs;
+ }
+
+ static void clear() {
+ instance.cntrs.clear();
+ }
+
+ static void print(embree_ostream cout);
+
+ private:
+ Counters cntrs;
+
+ private:
+ static Stat instance;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/state.cpp b/thirdparty/embree-aarch64/kernels/common/state.cpp
new file mode 100644
index 0000000000..51fc9b7826
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/state.cpp
@@ -0,0 +1,543 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "state.h"
+#include "../../common/lexers/streamfilters.h"
+
+namespace embree
+{
+ MutexSys g_printMutex;
+
+ State::ErrorHandler State::g_errorHandler;
+
+ State::ErrorHandler::ErrorHandler()
+ : thread_error(createTls()) {}
+
+ State::ErrorHandler::~ErrorHandler()
+ {
+ Lock<MutexSys> lock(errors_mutex);
+ for (size_t i=0; i<thread_errors.size(); i++)
+ delete thread_errors[i];
+ destroyTls(thread_error);
+ thread_errors.clear();
+ }
+
+ RTCError* State::ErrorHandler::error()
+ {
+ RTCError* stored_error = (RTCError*) getTls(thread_error);
+ if (stored_error) return stored_error;
+
+ Lock<MutexSys> lock(errors_mutex);
+ stored_error = new RTCError(RTC_ERROR_NONE);
+ thread_errors.push_back(stored_error);
+ setTls(thread_error,stored_error);
+ return stored_error;
+ }
+
+ State::State ()
+ : enabled_cpu_features(getCPUFeatures()),
+ enabled_builder_cpu_features(enabled_cpu_features),
+ frequency_level(FREQUENCY_SIMD256)
+ {
+ tri_accel = "default";
+ tri_builder = "default";
+ tri_traverser = "default";
+
+ tri_accel_mb = "default";
+ tri_builder_mb = "default";
+ tri_traverser_mb = "default";
+
+ quad_accel = "default";
+ quad_builder = "default";
+ quad_traverser = "default";
+
+ quad_accel_mb = "default";
+ quad_builder_mb = "default";
+ quad_traverser_mb = "default";
+
+ line_accel = "default";
+ line_builder = "default";
+ line_traverser = "default";
+
+ line_accel_mb = "default";
+ line_builder_mb = "default";
+ line_traverser_mb = "default";
+
+ hair_accel = "default";
+ hair_builder = "default";
+ hair_traverser = "default";
+
+ hair_accel_mb = "default";
+ hair_builder_mb = "default";
+ hair_traverser_mb = "default";
+
+ object_accel = "default";
+ object_builder = "default";
+ object_accel_min_leaf_size = 1;
+ object_accel_max_leaf_size = 1;
+
+ object_accel_mb = "default";
+ object_builder_mb = "default";
+ object_accel_mb_min_leaf_size = 1;
+ object_accel_mb_max_leaf_size = 1;
+
+ max_spatial_split_replications = 1.2f;
+ useSpatialPreSplits = false;
+
+ tessellation_cache_size = 128*1024*1024;
+
+ subdiv_accel = "default";
+ subdiv_accel_mb = "default";
+
+ grid_accel = "default";
+ grid_builder = "default";
+ grid_accel_mb = "default";
+ grid_builder_mb = "default";
+
+ instancing_open_min = 0;
+ instancing_block_size = 0;
+ instancing_open_factor = 8.0f;
+ instancing_open_max_depth = 32;
+ instancing_open_max = 50000000;
+
+ ignore_config_files = false;
+ float_exceptions = false;
+ quality_flags = -1;
+ scene_flags = -1;
+ verbose = 0;
+ benchmark = 0;
+
+ numThreads = 0;
+ numUserThreads = 0;
+
+#if TASKING_INTERNAL
+ set_affinity = true;
+#else
+ set_affinity = false;
+#endif
+ /* per default enable affinity on KNL */
+ if (hasISA(AVX512KNL)) set_affinity = true;
+
+ start_threads = false;
+ enable_selockmemoryprivilege = false;
+#if defined(__LINUX__)
+ hugepages = true;
+#else
+ hugepages = false;
+#endif
+ hugepages_success = true;
+
+ alloc_main_block_size = 0;
+ alloc_num_main_slots = 0;
+ alloc_thread_block_size = 0;
+ alloc_single_thread_alloc = -1;
+
+ error_function = nullptr;
+ error_function_userptr = nullptr;
+
+ memory_monitor_function = nullptr;
+ memory_monitor_userptr = nullptr;
+ }
+
+ State::~State() {
+ }
+
+ bool State::hasISA(const int isa) {
+ return (enabled_cpu_features & isa) == isa;
+ }
+
+ bool State::checkISASupport() {
+#if defined(__ARM_NEON)
+ /*
+ * NEON CPU type is a mixture of NEON and SSE2
+ */
+
+ bool hasSSE2 = (getCPUFeatures() & enabled_cpu_features) & CPU_FEATURE_SSE2;
+
+ /* this will be true when explicitly initialize Device with `isa=neon` config */
+ bool hasNEON = (getCPUFeatures() & enabled_cpu_features) & CPU_FEATURE_NEON;
+
+ return hasSSE2 || hasNEON;
+#else
+ return (getCPUFeatures() & enabled_cpu_features) == enabled_cpu_features;
+#endif
+ }
+
+ void State::verify()
+ {
+ /* verify that calculations stay in range */
+ assert(rcp(min_rcp_input)*FLT_LARGE+FLT_LARGE < 0.01f*FLT_MAX);
+
+ /* here we verify that CPP files compiled for a specific ISA only
+ * call that same or lower ISA version of non-inlined class member
+ * functions */
+#if defined(DEBUG)
+#if defined(EMBREE_TARGET_SSE2)
+#if !defined(__ARM_NEON)
+ assert(sse2::getISA() <= SSE2);
+#endif
+#endif
+#if defined(EMBREE_TARGET_SSE42)
+ assert(sse42::getISA() <= SSE42);
+#endif
+#if defined(EMBREE_TARGET_AVX)
+ assert(avx::getISA() <= AVX);
+#endif
+#if defined(EMBREE_TARGET_AVX2)
+ assert(avx2::getISA() <= AVX2);
+#endif
+#if defined (EMBREE_TARGET_AVX512KNL)
+ assert(avx512knl::getISA() <= AVX512KNL);
+#endif
+#if defined (EMBREE_TARGET_AVX512SKX)
+ assert(avx512skx::getISA() <= AVX512SKX);
+#endif
+#endif
+ }
+
+ const char* symbols[3] = { "=", ",", "|" };
+
+ bool State::parseFile(const FileName& fileName)
+ {
+ FILE* f = fopen(fileName.c_str(),"r");
+ if (!f) return false;
+ Ref<Stream<int> > file = new FileStream(f,fileName);
+
+ std::vector<std::string> syms;
+ for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++)
+ syms.push_back(symbols[i]);
+
+ Ref<TokenStream> cin = new TokenStream(new LineCommentFilter(file,"#"),
+ TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
+ TokenStream::separators,syms);
+ parse(cin);
+ return true;
+ }
+
+ void State::parseString(const char* cfg)
+ {
+ if (cfg == nullptr) return;
+
+ std::vector<std::string> syms;
+ for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++)
+ syms.push_back(symbols[i]);
+
+ Ref<TokenStream> cin = new TokenStream(new StrStream(cfg),
+ TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
+ TokenStream::separators,syms);
+ parse(cin);
+ }
+
+ int string_to_cpufeatures(const std::string& isa)
+ {
+ if (isa == "sse" ) return SSE;
+ else if (isa == "sse2") return SSE2;
+ else if (isa == "sse3") return SSE3;
+ else if (isa == "ssse3") return SSSE3;
+ else if (isa == "sse41") return SSE41;
+ else if (isa == "sse4.1") return SSE41;
+ else if (isa == "sse42") return SSE42;
+ else if (isa == "sse4.2") return SSE42;
+ else if (isa == "avx") return AVX;
+ else if (isa == "avxi") return AVXI;
+ else if (isa == "avx2") return AVX2;
+ else if (isa == "avx512knl") return AVX512KNL;
+ else if (isa == "avx512skx") return AVX512SKX;
+ else return SSE2;
+ }
+
+ void State::parse(Ref<TokenStream> cin)
+ {
+ /* parse until end of stream */
+ while (cin->peek() != Token::Eof())
+ {
+ const Token tok = cin->get();
+
+ if (tok == Token::Id("threads") && cin->trySymbol("="))
+ numThreads = cin->get().Int();
+
+ else if (tok == Token::Id("user_threads")&& cin->trySymbol("="))
+ numUserThreads = cin->get().Int();
+
+ else if (tok == Token::Id("set_affinity")&& cin->trySymbol("="))
+ set_affinity = cin->get().Int();
+
+ else if (tok == Token::Id("affinity")&& cin->trySymbol("="))
+ set_affinity = cin->get().Int();
+
+ else if (tok == Token::Id("start_threads")&& cin->trySymbol("="))
+ start_threads = cin->get().Int();
+
+ else if (tok == Token::Id("isa") && cin->trySymbol("=")) {
+ std::string isa = toLowerCase(cin->get().Identifier());
+ enabled_cpu_features = string_to_cpufeatures(isa);
+ enabled_builder_cpu_features = enabled_cpu_features;
+ }
+
+ else if (tok == Token::Id("max_isa") && cin->trySymbol("=")) {
+ std::string isa = toLowerCase(cin->get().Identifier());
+ enabled_cpu_features &= string_to_cpufeatures(isa);
+ enabled_builder_cpu_features &= enabled_cpu_features;
+ }
+
+ else if (tok == Token::Id("max_builder_isa") && cin->trySymbol("=")) {
+ std::string isa = toLowerCase(cin->get().Identifier());
+ enabled_builder_cpu_features &= string_to_cpufeatures(isa);
+ }
+
+ else if (tok == Token::Id("frequency_level") && cin->trySymbol("=")) {
+ std::string freq = cin->get().Identifier();
+ if (freq == "simd128") frequency_level = FREQUENCY_SIMD128;
+ else if (freq == "simd256") frequency_level = FREQUENCY_SIMD256;
+ else if (freq == "simd512") frequency_level = FREQUENCY_SIMD512;
+ }
+
+ else if (tok == Token::Id("enable_selockmemoryprivilege") && cin->trySymbol("=")) {
+ enable_selockmemoryprivilege = cin->get().Int();
+ }
+ else if (tok == Token::Id("hugepages") && cin->trySymbol("=")) {
+ hugepages = cin->get().Int();
+ }
+
+ else if (tok == Token::Id("ignore_config_files") && cin->trySymbol("="))
+ ignore_config_files = cin->get().Int();
+ else if (tok == Token::Id("float_exceptions") && cin->trySymbol("="))
+ float_exceptions = cin->get().Int();
+
+ else if ((tok == Token::Id("tri_accel") || tok == Token::Id("accel")) && cin->trySymbol("="))
+ tri_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_builder") || tok == Token::Id("builder")) && cin->trySymbol("="))
+ tri_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_traverser") || tok == Token::Id("traverser")) && cin->trySymbol("="))
+ tri_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("tri_accel_mb") || tok == Token::Id("accel_mb")) && cin->trySymbol("="))
+ tri_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_builder_mb") || tok == Token::Id("builder_mb")) && cin->trySymbol("="))
+ tri_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_traverser_mb") || tok == Token::Id("traverser_mb")) && cin->trySymbol("="))
+ tri_traverser_mb = cin->get().Identifier();
+
+ else if ((tok == Token::Id("quad_accel")) && cin->trySymbol("="))
+ quad_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_builder")) && cin->trySymbol("="))
+ quad_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_traverser")) && cin->trySymbol("="))
+ quad_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("quad_accel_mb")) && cin->trySymbol("="))
+ quad_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_builder_mb")) && cin->trySymbol("="))
+ quad_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_traverser_mb")) && cin->trySymbol("="))
+ quad_traverser_mb = cin->get().Identifier();
+
+ else if ((tok == Token::Id("line_accel")) && cin->trySymbol("="))
+ line_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("line_builder")) && cin->trySymbol("="))
+ line_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("line_traverser")) && cin->trySymbol("="))
+ line_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("line_accel_mb")) && cin->trySymbol("="))
+ line_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("line_builder_mb")) && cin->trySymbol("="))
+ line_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("line_traverser_mb")) && cin->trySymbol("="))
+ line_traverser_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("hair_accel") && cin->trySymbol("="))
+ hair_accel = cin->get().Identifier();
+ else if (tok == Token::Id("hair_builder") && cin->trySymbol("="))
+ hair_builder = cin->get().Identifier();
+ else if (tok == Token::Id("hair_traverser") && cin->trySymbol("="))
+ hair_traverser = cin->get().Identifier();
+
+ else if (tok == Token::Id("hair_accel_mb") && cin->trySymbol("="))
+ hair_accel_mb = cin->get().Identifier();
+ else if (tok == Token::Id("hair_builder_mb") && cin->trySymbol("="))
+ hair_builder_mb = cin->get().Identifier();
+ else if (tok == Token::Id("hair_traverser_mb") && cin->trySymbol("="))
+ hair_traverser_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("object_accel") && cin->trySymbol("="))
+ object_accel = cin->get().Identifier();
+ else if (tok == Token::Id("object_builder") && cin->trySymbol("="))
+ object_builder = cin->get().Identifier();
+ else if (tok == Token::Id("object_accel_min_leaf_size") && cin->trySymbol("="))
+ object_accel_min_leaf_size = cin->get().Int();
+ else if (tok == Token::Id("object_accel_max_leaf_size") && cin->trySymbol("="))
+ object_accel_max_leaf_size = cin->get().Int();
+
+ else if (tok == Token::Id("object_accel_mb") && cin->trySymbol("="))
+ object_accel_mb = cin->get().Identifier();
+ else if (tok == Token::Id("object_builder_mb") && cin->trySymbol("="))
+ object_builder_mb = cin->get().Identifier();
+ else if (tok == Token::Id("object_accel_mb_min_leaf_size") && cin->trySymbol("="))
+ object_accel_mb_min_leaf_size = cin->get().Int();
+ else if (tok == Token::Id("object_accel_mb_max_leaf_size") && cin->trySymbol("="))
+ object_accel_mb_max_leaf_size = cin->get().Int();
+
+ else if (tok == Token::Id("instancing_open_min") && cin->trySymbol("="))
+ instancing_open_min = cin->get().Int();
+ else if (tok == Token::Id("instancing_block_size") && cin->trySymbol("=")) {
+ instancing_block_size = cin->get().Int();
+ instancing_open_factor = 0.0f;
+ }
+ else if (tok == Token::Id("instancing_open_max_depth") && cin->trySymbol("="))
+ instancing_open_max_depth = cin->get().Int();
+ else if (tok == Token::Id("instancing_open_factor") && cin->trySymbol("=")) {
+ instancing_block_size = 0;
+ instancing_open_factor = cin->get().Float();
+ }
+ else if (tok == Token::Id("instancing_open_max") && cin->trySymbol("="))
+ instancing_open_max = cin->get().Int();
+
+ else if (tok == Token::Id("subdiv_accel") && cin->trySymbol("="))
+ subdiv_accel = cin->get().Identifier();
+ else if (tok == Token::Id("subdiv_accel_mb") && cin->trySymbol("="))
+ subdiv_accel_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("grid_accel") && cin->trySymbol("="))
+ grid_accel = cin->get().Identifier();
+ else if (tok == Token::Id("grid_accel_mb") && cin->trySymbol("="))
+ grid_accel_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("verbose") && cin->trySymbol("="))
+ verbose = cin->get().Int();
+ else if (tok == Token::Id("benchmark") && cin->trySymbol("="))
+ benchmark = cin->get().Int();
+
+ else if (tok == Token::Id("quality")) {
+ if (cin->trySymbol("=")) {
+ Token flag = cin->get();
+ if (flag == Token::Id("low")) quality_flags = RTC_BUILD_QUALITY_LOW;
+ else if (flag == Token::Id("medium")) quality_flags = RTC_BUILD_QUALITY_MEDIUM;
+ else if (flag == Token::Id("high")) quality_flags = RTC_BUILD_QUALITY_HIGH;
+ }
+ }
+
+ else if (tok == Token::Id("scene_flags")) {
+ scene_flags = 0;
+ if (cin->trySymbol("=")) {
+ do {
+ Token flag = cin->get();
+ if (flag == Token::Id("dynamic") ) scene_flags |= RTC_SCENE_FLAG_DYNAMIC;
+ else if (flag == Token::Id("compact")) scene_flags |= RTC_SCENE_FLAG_COMPACT;
+ else if (flag == Token::Id("robust")) scene_flags |= RTC_SCENE_FLAG_ROBUST;
+ } while (cin->trySymbol("|"));
+ }
+ }
+
+ else if (tok == Token::Id("max_spatial_split_replications") && cin->trySymbol("="))
+ max_spatial_split_replications = cin->get().Float();
+
+ else if (tok == Token::Id("presplits") && cin->trySymbol("="))
+ useSpatialPreSplits = cin->get().Int() != 0 ? true : false;
+
+ else if (tok == Token::Id("tessellation_cache_size") && cin->trySymbol("="))
+ tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
+ else if (tok == Token::Id("cache_size") && cin->trySymbol("="))
+ tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
+
+ else if (tok == Token::Id("alloc_main_block_size") && cin->trySymbol("="))
+ alloc_main_block_size = cin->get().Int();
+ else if (tok == Token::Id("alloc_num_main_slots") && cin->trySymbol("="))
+ alloc_num_main_slots = cin->get().Int();
+ else if (tok == Token::Id("alloc_thread_block_size") && cin->trySymbol("="))
+ alloc_thread_block_size = cin->get().Int();
+ else if (tok == Token::Id("alloc_single_thread_alloc") && cin->trySymbol("="))
+ alloc_single_thread_alloc = cin->get().Int();
+
+ cin->trySymbol(","); // optional , separator
+ }
+ }
+
+ bool State::verbosity(size_t N) {
+ return N <= verbose;
+ }
+
+ void State::print()
+ {
+ std::cout << "general:" << std::endl;
+ std::cout << " build threads = " << numThreads << std::endl;
+ std::cout << " build user threads = " << numUserThreads << std::endl;
+ std::cout << " start_threads = " << start_threads << std::endl;
+ std::cout << " affinity = " << set_affinity << std::endl;
+ std::cout << " frequency_level = ";
+ switch (frequency_level) {
+ case FREQUENCY_SIMD128: std::cout << "simd128" << std::endl; break;
+ case FREQUENCY_SIMD256: std::cout << "simd256" << std::endl; break;
+ case FREQUENCY_SIMD512: std::cout << "simd512" << std::endl; break;
+ default: std::cout << "error" << std::endl; break;
+ }
+
+ std::cout << " hugepages = ";
+ if (!hugepages) std::cout << "disabled" << std::endl;
+ else if (hugepages_success) std::cout << "enabled" << std::endl;
+ else std::cout << "failed" << std::endl;
+
+ std::cout << " verbosity = " << verbose << std::endl;
+ std::cout << " cache_size = " << float(tessellation_cache_size)*1E-6 << " MB" << std::endl;
+ std::cout << " max_spatial_split_replications = " << max_spatial_split_replications << std::endl;
+
+ std::cout << "triangles:" << std::endl;
+ std::cout << " accel = " << tri_accel << std::endl;
+ std::cout << " builder = " << tri_builder << std::endl;
+ std::cout << " traverser = " << tri_traverser << std::endl;
+
+ std::cout << "motion blur triangles:" << std::endl;
+ std::cout << " accel = " << tri_accel_mb << std::endl;
+ std::cout << " builder = " << tri_builder_mb << std::endl;
+ std::cout << " traverser = " << tri_traverser_mb << std::endl;
+
+ std::cout << "quads:" << std::endl;
+ std::cout << " accel = " << quad_accel << std::endl;
+ std::cout << " builder = " << quad_builder << std::endl;
+ std::cout << " traverser = " << quad_traverser << std::endl;
+
+ std::cout << "motion blur quads:" << std::endl;
+ std::cout << " accel = " << quad_accel_mb << std::endl;
+ std::cout << " builder = " << quad_builder_mb << std::endl;
+ std::cout << " traverser = " << quad_traverser_mb << std::endl;
+
+ std::cout << "line segments:" << std::endl;
+ std::cout << " accel = " << line_accel << std::endl;
+ std::cout << " builder = " << line_builder << std::endl;
+ std::cout << " traverser = " << line_traverser << std::endl;
+
+ std::cout << "motion blur line segments:" << std::endl;
+ std::cout << " accel = " << line_accel_mb << std::endl;
+ std::cout << " builder = " << line_builder_mb << std::endl;
+ std::cout << " traverser = " << line_traverser_mb << std::endl;
+
+ std::cout << "hair:" << std::endl;
+ std::cout << " accel = " << hair_accel << std::endl;
+ std::cout << " builder = " << hair_builder << std::endl;
+ std::cout << " traverser = " << hair_traverser << std::endl;
+
+ std::cout << "motion blur hair:" << std::endl;
+ std::cout << " accel = " << hair_accel_mb << std::endl;
+ std::cout << " builder = " << hair_builder_mb << std::endl;
+ std::cout << " traverser = " << hair_traverser_mb << std::endl;
+
+ std::cout << "subdivision surfaces:" << std::endl;
+ std::cout << " accel = " << subdiv_accel << std::endl;
+
+ std::cout << "grids:" << std::endl;
+ std::cout << " accel = " << grid_accel << std::endl;
+ std::cout << " builder = " << grid_builder << std::endl;
+
+ std::cout << "motion blur grids:" << std::endl;
+ std::cout << " accel = " << grid_accel_mb << std::endl;
+ std::cout << " builder = " << grid_builder_mb << std::endl;
+
+ std::cout << "object_accel:" << std::endl;
+ std::cout << " min_leaf_size = " << object_accel_min_leaf_size << std::endl;
+ std::cout << " max_leaf_size = " << object_accel_max_leaf_size << std::endl;
+
+ std::cout << "object_accel_mb:" << std::endl;
+ std::cout << " min_leaf_size = " << object_accel_mb_min_leaf_size << std::endl;
+ std::cout << " max_leaf_size = " << object_accel_mb_max_leaf_size << std::endl;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/state.h b/thirdparty/embree-aarch64/kernels/common/state.h
new file mode 100644
index 0000000000..d0fccc023f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/state.h
@@ -0,0 +1,197 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /* mutex to make printing to cout thread safe */
+ extern MutexSys g_printMutex;
+
+ struct State : public RefCount
+ {
+ public:
+ /*! state construction */
+ State ();
+
+ /*! state destruction */
+ ~State();
+
+ /*! verifies that state is correct */
+ void verify();
+
+ /*! parses state from a configuration file */
+ bool parseFile(const FileName& fileName);
+
+ /*! parses the state from a string */
+ void parseString(const char* cfg);
+
+ /*! parses the state from a stream */
+ void parse(Ref<TokenStream> cin);
+
+ /*! prints the state */
+ void print();
+
+ /*! checks if verbosity level is at least N */
+ bool verbosity(size_t N);
+
+ /*! checks if some particular ISA is enabled */
+ bool hasISA(const int isa);
+
+ /*! check whether selected ISA is supported by the HW */
+ bool checkISASupport();
+
+ public:
+ std::string tri_accel; //!< acceleration structure to use for triangles
+ std::string tri_builder; //!< builder to use for triangles
+ std::string tri_traverser; //!< traverser to use for triangles
+
+ public:
+ std::string tri_accel_mb; //!< acceleration structure to use for motion blur triangles
+ std::string tri_builder_mb; //!< builder to use for motion blur triangles
+ std::string tri_traverser_mb; //!< traverser to use for triangles
+
+ public:
+ std::string quad_accel; //!< acceleration structure to use for quads
+ std::string quad_builder; //!< builder to use for quads
+ std::string quad_traverser; //!< traverser to use for quads
+
+ public:
+ std::string quad_accel_mb; //!< acceleration structure to use for motion blur quads
+ std::string quad_builder_mb; //!< builder to use for motion blur quads
+ std::string quad_traverser_mb; //!< traverser to use for motion blur quads
+
+ public:
+ std::string line_accel; //!< acceleration structure to use for line segments
+ std::string line_builder; //!< builder to use for line segments
+ std::string line_traverser; //!< traverser to use for line segments
+
+ public:
+ std::string line_accel_mb; //!< acceleration structure to use for motion blur line segments
+ std::string line_builder_mb; //!< builder to use for motion blur line segments
+ std::string line_traverser_mb; //!< traverser to use for motion blur line segments
+
+ public:
+ std::string hair_accel; //!< hair acceleration structure to use
+ std::string hair_builder; //!< builder to use for hair
+ std::string hair_traverser; //!< traverser to use for hair
+
+ public:
+ std::string hair_accel_mb; //!< acceleration structure to use for motion blur hair
+ std::string hair_builder_mb; //!< builder to use for motion blur hair
+ std::string hair_traverser_mb; //!< traverser to use for motion blur hair
+
+ public:
+ std::string object_accel; //!< acceleration structure for user geometries
+ std::string object_builder; //!< builder for user geometries
+ int object_accel_min_leaf_size; //!< minimum leaf size for object acceleration structure
+ int object_accel_max_leaf_size; //!< maximum leaf size for object acceleration structure
+
+ public:
+ std::string object_accel_mb; //!< acceleration structure for user geometries
+ std::string object_builder_mb; //!< builder for user geometries
+ int object_accel_mb_min_leaf_size; //!< minimum leaf size for mblur object acceleration structure
+ int object_accel_mb_max_leaf_size; //!< maximum leaf size for mblur object acceleration structure
+
+ public:
+ std::string subdiv_accel; //!< acceleration structure to use for subdivision surfaces
+ std::string subdiv_accel_mb; //!< acceleration structure to use for subdivision surfaces
+
+ public:
+ std::string grid_accel; //!< acceleration structure to use for grids
+ std::string grid_builder; //!< builder for grids
+ std::string grid_accel_mb; //!< acceleration structure to use for motion blur grids
+ std::string grid_builder_mb; //!< builder for motion blur grids
+
+ public:
+ float max_spatial_split_replications; //!< maximally replications*N many primitives in accel for spatial splits
+ bool useSpatialPreSplits; //!< use spatial pre-splits instead of the full spatial split builder
+ size_t tessellation_cache_size; //!< size of the shared tessellation cache
+
+ public:
+ size_t instancing_open_min; //!< instancing opens tree to minimally that number of subtrees
+ size_t instancing_block_size; //!< instancing opens tree up to average block size of primitives
+ float instancing_open_factor; //!< instancing opens tree up to x times the number of instances
+ size_t instancing_open_max_depth; //!< maximum open depth for geometries
+ size_t instancing_open_max; //!< instancing opens tree to maximally that number of subtrees
+
+ public:
+ bool ignore_config_files; //!< if true no more config files get parse
+ bool float_exceptions; //!< enable floating point exceptions
+ int quality_flags;
+ int scene_flags;
+ size_t verbose; //!< verbosity of output
+ size_t benchmark; //!< true
+
+ public:
+ size_t numThreads; //!< number of threads to use in builders
+ size_t numUserThreads; //!< number of user provided threads to use in builders
+ bool set_affinity; //!< sets affinity for worker threads
+ bool start_threads; //!< true when threads should be started at device creation time
+ int enabled_cpu_features; //!< CPU ISA features to use
+ int enabled_builder_cpu_features; //!< CPU ISA features to use for builders only
+ enum FREQUENCY_LEVEL {
+ FREQUENCY_SIMD128,
+ FREQUENCY_SIMD256,
+ FREQUENCY_SIMD512
+ } frequency_level; //!< frequency level the app wants to run on (default is SIMD256)
+ bool enable_selockmemoryprivilege; //!< configures the SeLockMemoryPrivilege under Windows to enable huge pages
+ bool hugepages; //!< true if huge pages should get used
+ bool hugepages_success; //!< status for enabling huge pages
+
+ public:
+ size_t alloc_main_block_size; //!< main allocation block size (shared between threads)
+ int alloc_num_main_slots; //!< number of such shared blocks to be used to allocate
+ size_t alloc_thread_block_size; //!< size of thread local allocator block size
+ int alloc_single_thread_alloc; //!< in single mode nodes and leaves use same thread local allocator
+
+ public:
+
+ /*! checks if we can use AVX */
+ bool canUseAVX() {
+ return hasISA(AVX) && frequency_level != FREQUENCY_SIMD128;
+ }
+
+ /*! checks if we can use AVX2 */
+ bool canUseAVX2() {
+ return hasISA(AVX2) && frequency_level != FREQUENCY_SIMD128;
+ }
+
+ struct ErrorHandler
+ {
+ public:
+ ErrorHandler();
+ ~ErrorHandler();
+ RTCError* error();
+
+ public:
+ tls_t thread_error;
+ std::vector<RTCError*> thread_errors;
+ MutexSys errors_mutex;
+ };
+ ErrorHandler errorHandler;
+ static ErrorHandler g_errorHandler;
+
+ public:
+ void setErrorFunction(RTCErrorFunction fptr, void* uptr)
+ {
+ error_function = fptr;
+ error_function_userptr = uptr;
+ }
+
+ RTCErrorFunction error_function;
+ void* error_function_userptr;
+
+ public:
+ void setMemoryMonitorFunction(RTCMemoryMonitorFunction fptr, void* uptr)
+ {
+ memory_monitor_function = fptr;
+ memory_monitor_userptr = uptr;
+ }
+
+ RTCMemoryMonitorFunction memory_monitor_function;
+ void* memory_monitor_userptr;
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/common/vector.h b/thirdparty/embree-aarch64/kernels/common/vector.h
new file mode 100644
index 0000000000..b478762240
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/common/vector.h
@@ -0,0 +1,76 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "default.h"
+
+namespace embree
+{
+ /*! invokes the memory monitor callback */
+ struct MemoryMonitorInterface {
+ virtual void memoryMonitor(ssize_t bytes, bool post) = 0;
+ };
+
+ /*! allocator that performs aligned monitored allocations */
+ template<typename T, size_t alignment = 64>
+ struct aligned_monitored_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline aligned_monitored_allocator(MemoryMonitorInterface* device)
+ : device(device), hugepages(false) {}
+
+ __forceinline pointer allocate( size_type n )
+ {
+ if (n) {
+ assert(device);
+ device->memoryMonitor(n*sizeof(T),false);
+ }
+ if (n*sizeof(value_type) >= 14 * PAGE_SIZE_2M)
+ {
+ pointer p = (pointer) os_malloc(n*sizeof(value_type),hugepages);
+ assert(p);
+ return p;
+ }
+ return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n )
+ {
+ if (p)
+ {
+ if (n*sizeof(value_type) >= 14 * PAGE_SIZE_2M)
+ os_free(p,n*sizeof(value_type),hugepages);
+ else
+ alignedFree(p);
+ }
+ else assert(n == 0);
+
+ if (n) {
+ assert(device);
+ device->memoryMonitor(-ssize_t(n)*sizeof(T),true);
+ }
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+
+ private:
+ MemoryMonitorInterface* device;
+ bool hugepages;
+ };
+
+ /*! monitored vector */
+ template<typename T>
+ using mvector = vector_t<T,aligned_monitored_allocator<T,std::alignment_of<T>::value> >;
+}
diff --git a/thirdparty/embree-aarch64/kernels/config.h b/thirdparty/embree-aarch64/kernels/config.h
new file mode 100644
index 0000000000..80a8ab2a56
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/config.h
@@ -0,0 +1,76 @@
+
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+/* #undef EMBREE_RAY_MASK */
+/* #undef EMBREE_STAT_COUNTERS */
+/* #undef EMBREE_BACKFACE_CULLING */
+/* #undef EMBREE_BACKFACE_CULLING_CURVES */
+#define EMBREE_FILTER_FUNCTION
+/* #undef EMBREE_IGNORE_INVALID_RAYS */
+#define EMBREE_GEOMETRY_TRIANGLE
+/* #undef EMBREE_GEOMETRY_QUAD */
+/* #undef EMBREE_GEOMETRY_CURVE */
+/* #undef EMBREE_GEOMETRY_SUBDIVISION */
+/* #undef EMBREE_GEOMETRY_USER */
+/* #undef EMBREE_GEOMETRY_INSTANCE */
+/* #undef EMBREE_GEOMETRY_GRID */
+/* #undef EMBREE_GEOMETRY_POINT */
+/* #undef EMBREE_RAY_PACKETS */
+/* #undef EMBREE_COMPACT_POLYS */
+
+#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ #define IF_ENABLED_TRIS(x) x
+#else
+ #define IF_ENABLED_TRIS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ #define IF_ENABLED_QUADS(x) x
+#else
+ #define IF_ENABLED_QUADS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_CURVES_OR_POINTS(x) x
+#else
+ #define IF_ENABLED_CURVES_OR_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ #define IF_ENABLED_CURVES(x) x
+#else
+ #define IF_ENABLED_CURVES(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_POINTS(x) x
+#else
+ #define IF_ENABLED_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ #define IF_ENABLED_SUBDIV(x) x
+#else
+ #define IF_ENABLED_SUBDIV(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ #define IF_ENABLED_USER(x) x
+#else
+ #define IF_ENABLED_USER(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ #define IF_ENABLED_INSTANCE(x) x
+#else
+ #define IF_ENABLED_INSTANCE(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ #define IF_ENABLED_GRIDS(x) x
+#else
+ #define IF_ENABLED_GRIDS(x)
+#endif
diff --git a/thirdparty/embree-aarch64/kernels/geometry/cone.h b/thirdparty/embree-aarch64/kernels/geometry/cone.h
new file mode 100644
index 0000000000..961ef86160
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/cone.h
@@ -0,0 +1,321 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct Cone
+ {
+ const Vec3fa p0; //!< start position of cone
+ const Vec3fa p1; //!< end position of cone
+ const float r0; //!< start radius of cone
+ const float r1; //!< end radius of cone
+
+ __forceinline Cone(const Vec3fa& p0, const float r0, const Vec3fa& p1, const float r1)
+ : p0(p0), p1(p1), r0(r0), r1(r1) {}
+
+ __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox1f& t_o,
+ float& u0_o, Vec3fa& Ng0_o,
+ float& u1_o, Vec3fa& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const Vec3fa v0 = p0-org;
+ const Vec3fa v1 = p1-org;
+
+ const float rl = rcp_length(v1-v0);
+ const Vec3fa P0 = v0, dP = (v1-v0)*rl;
+ const float dr = (r1-r0)*rl;
+ const Vec3fa O = -P0, dO = dir;
+
+ const float dOdO = dot(dO,dO);
+ const float OdO = dot(dO,O);
+ const float OO = dot(O,O);
+ const float dOz = dot(dP,dO);
+ const float Oz = dot(dP,O);
+
+ const float R = r0 + Oz*dr;
+ const float A = dOdO - sqr(dOz) * (1.0f+sqr(dr));
+ const float B = 2.0f * (OdO - dOz*(Oz + R*dr));
+ const float C = OO - (sqr(Oz) + sqr(R));
+
+ /* we miss the cone if determinant is smaller than zero */
+ const float D = B*B - 4.0f*A*C;
+ if (D < 0.0f) return false;
+
+ /* special case for rays that are "parallel" to the cone */
+ const float eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ if (unlikely(abs(A) < eps))
+ {
+ /* cylinder case */
+ if (abs(dr) < 16.0f*float(ulp)) {
+ if (C <= 0.0f) { t_o = BBox1f(neg_inf,pos_inf); return true; }
+ else { t_o = BBox1f(pos_inf,neg_inf); return false; }
+ }
+
+ /* cone case */
+ else
+ {
+ /* if we hit the negative cone there cannot be a hit */
+ const float t = -C/B;
+ const float z0 = Oz+t*dOz;
+ const float z0r = r0+z0*dr;
+ if (z0r < 0.0f) return false;
+
+ /* test if we start inside or outside the cone */
+ if (dOz*dr > 0.0f) t_o = BBox1f(t,pos_inf);
+ else t_o = BBox1f(neg_inf,t);
+ }
+ }
+
+ /* standard case for "non-parallel" rays */
+ else
+ {
+ const float Q = sqrt(D);
+ const float rcp_2A = rcp(2.0f*A);
+ t_o.lower = (-B-Q)*rcp_2A;
+ t_o.upper = (-B+Q)*rcp_2A;
+
+ /* standard case where both hits are on same cone */
+ if (likely(A > 0.0f)) {
+ const float z0 = Oz+t_o.lower*dOz;
+ const float z0r = r0+z0*dr;
+ if (z0r < 0.0f) return false;
+ }
+
+ /* special case where the hits are on the positive and negative cone */
+ else
+ {
+ /* depending on the ray direction and the open direction
+ * of the cone we have a hit from inside or outside the
+ * cone */
+ if (dOz*dr > 0) t_o.upper = pos_inf;
+ else t_o.lower = neg_inf;
+ }
+ }
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = (Oz+t_o.lower*dOz)*rl;
+ const Vec3fa Pr = t_o.lower*dir;
+ const Vec3fa Pl = v0 + u0_o*(v1-v0);
+ const Vec3fa R = normalize(Pr-Pl);
+ const Vec3fa U = (p1-p0)+(r1-r0)*R;
+ const Vec3fa V = cross(p1-p0,R);
+ Ng0_o = cross(V,U);
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = (Oz+t_o.upper*dOz)*rl;
+ const Vec3fa Pr = t_o.upper*dir;
+ const Vec3fa Pl = v0 + u1_o*(v1-v0);
+ const Vec3fa R = normalize(Pr-Pl);
+ const Vec3fa U = (p1-p0)+(r1-r0)*R;
+ const Vec3fa V = cross(p1-p0,R);
+ Ng1_o = cross(V,U);
+ }
+ return true;
+ }
+
+ __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir, BBox1f& t_o) const
+ {
+ float u0_o; Vec3fa Ng0_o; float u1_o; Vec3fa Ng1_o;
+ return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+
+ static bool verify(const size_t id, const Cone& cone, const Ray& ray, bool shouldhit, const float t0, const float t1)
+ {
+ float eps = 0.001f;
+ BBox1f t; bool hit;
+ hit = cone.intersect(ray.org,ray.dir,t);
+
+ bool failed = hit != shouldhit;
+ if (shouldhit) failed |= std::isinf(t0) ? t0 != t.lower : (t0 == -1E6) ? t.lower > -1E6f : abs(t0-t.lower) > eps;
+ if (shouldhit) failed |= std::isinf(t1) ? t1 != t.upper : (t1 == +1E6) ? t.upper < +1E6f : abs(t1-t.upper) > eps;
+ if (!failed) return true;
+ embree_cout << "Cone test " << id << " failed: cone = " << cone << ", ray = " << ray << ", hit = " << hit << ", t = " << t << embree_endl;
+ return false;
+ }
+
+ /* verify cone class */
+ static bool verify()
+ {
+ bool passed = true;
+ const Cone cone0(Vec3fa(0.0f,0.0f,0.0f),0.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(0,cone0,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,3.0f,pos_inf);
+ passed &= verify(1,cone0,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
+ passed &= verify(2,cone0,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(3,cone0,Ray(Vec3fa(+1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,3.0f);
+ passed &= verify(4,cone0,Ray(Vec3fa(-1.0f,0.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,1.0f,pos_inf);
+ passed &= verify(5,cone0,Ray(Vec3fa(+1.0f,0.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
+ passed &= verify(6,cone0,Ray(Vec3fa(+0.0f,0.0f,1.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,1.0f);
+ passed &= verify(7,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(8,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(+1.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.5f,+1E6);
+ passed &= verify(9,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,+1.0f,+0.0f),0.0f,float(inf)),true,-1E6,-0.5f);
+ const Cone cone1(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),0.0f);
+ passed &= verify(10,cone1,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,2.0f);
+ passed &= verify(11,cone1,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,0.0f,4.0f);
+ const Cone cylinder(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(12,cylinder,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(13,cylinder,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(14,cylinder,Ray(Vec3fa(+2.0f,1.0f,2.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(15,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(16,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(17,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ passed &= verify(18,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ return passed;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const Cone& c) {
+ return cout << "Cone { p0 = " << c.p0 << ", r0 = " << c.r0 << ", p1 = " << c.p1 << ", r1 = " << c.r1 << "}";
+ }
+ };
+
+ template<int N>
+ struct ConeN
+ {
+ typedef Vec3<vfloat<N>> Vec3vfN;
+
+ const Vec3vfN p0; //!< start position of cone
+ const Vec3vfN p1; //!< end position of cone
+ const vfloat<N> r0; //!< start radius of cone
+ const vfloat<N> r1; //!< end radius of cone
+
+ __forceinline ConeN(const Vec3vfN& p0, const vfloat<N>& r0, const Vec3vfN& p1, const vfloat<N>& r1)
+ : p0(p0), p1(p1), r0(r0), r1(r1) {}
+
+ __forceinline Cone operator[] (const size_t i) const
+ {
+ assert(i<N);
+ return Cone(Vec3fa(p0.x[i],p0.y[i],p0.z[i]),r0[i],Vec3fa(p1.x[i],p1.y[i],p1.z[i]),r1[i]);
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox<vfloat<N>>& t_o,
+ vfloat<N>& u0_o, Vec3vfN& Ng0_o,
+ vfloat<N>& u1_o, Vec3vfN& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const Vec3vfN v0 = p0-Vec3vfN(org);
+ const Vec3vfN v1 = p1-Vec3vfN(org);
+
+ const vfloat<N> rl = rcp_length(v1-v0);
+ const Vec3vfN P0 = v0, dP = (v1-v0)*rl;
+ const vfloat<N> dr = (r1-r0)*rl;
+ const Vec3vfN O = -P0, dO = dir;
+
+ const vfloat<N> dOdO = dot(dO,dO);
+ const vfloat<N> OdO = dot(dO,O);
+ const vfloat<N> OO = dot(O,O);
+ const vfloat<N> dOz = dot(dP,dO);
+ const vfloat<N> Oz = dot(dP,O);
+
+ const vfloat<N> R = r0 + Oz*dr;
+ const vfloat<N> A = dOdO - sqr(dOz) * (vfloat<N>(1.0f)+sqr(dr));
+ const vfloat<N> B = 2.0f * (OdO - dOz*(Oz + R*dr));
+ const vfloat<N> C = OO - (sqr(Oz) + sqr(R));
+
+ /* we miss the cone if determinant is smaller than zero */
+ const vfloat<N> D = B*B - 4.0f*A*C;
+ vbool<N> valid = D >= 0.0f;
+ if (none(valid)) return valid;
+
+ /* special case for rays that are "parallel" to the cone */
+ const vfloat<N> eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ const vbool<N> validt = valid & (abs(A) < eps);
+ const vbool<N> validf = valid & !(abs(A) < eps);
+ if (unlikely(any(validt)))
+ {
+ const vboolx validtt = validt & (abs(dr) < 16.0f*float(ulp));
+ const vboolx validtf = validt & (abs(dr) >= 16.0f*float(ulp));
+
+ /* cylinder case */
+ if (unlikely(any(validtt)))
+ {
+ t_o.lower = select(validtt, select(C <= 0.0f, vfloat<N>(neg_inf), vfloat<N>(pos_inf)), t_o.lower);
+ t_o.upper = select(validtt, select(C <= 0.0f, vfloat<N>(pos_inf), vfloat<N>(neg_inf)), t_o.upper);
+ valid &= !validtt | C <= 0.0f;
+ }
+
+ /* cone case */
+ if (any(validtf))
+ {
+ /* if we hit the negative cone there cannot be a hit */
+ const vfloat<N> t = -C/B;
+ const vfloat<N> z0 = Oz+t*dOz;
+ const vfloat<N> z0r = r0+z0*dr;
+ valid &= !validtf | z0r >= 0.0f;
+
+ /* test if we start inside or outside the cone */
+ t_o.lower = select(validtf, select(dOz*dr > 0.0f, t, vfloat<N>(neg_inf)), t_o.lower);
+ t_o.upper = select(validtf, select(dOz*dr > 0.0f, vfloat<N>(pos_inf), t), t_o.upper);
+ }
+ }
+
+ /* standard case for "non-parallel" rays */
+ if (likely(any(validf)))
+ {
+ const vfloat<N> Q = sqrt(D);
+ const vfloat<N> rcp_2A = 0.5f*rcp(A);
+ t_o.lower = select(validf, (-B-Q)*rcp_2A, t_o.lower);
+ t_o.upper = select(validf, (-B+Q)*rcp_2A, t_o.upper);
+
+ /* standard case where both hits are on same cone */
+ const vbool<N> validft = validf & A>0.0f;
+ const vbool<N> validff = validf & !(A>0.0f);
+ if (any(validft)) {
+ const vfloat<N> z0 = Oz+t_o.lower*dOz;
+ const vfloat<N> z0r = r0+z0*dr;
+ valid &= !validft | z0r >= 0.0f;
+ }
+
+ /* special case where the hits are on the positive and negative cone */
+ if (any(validff)) {
+ /* depending on the ray direction and the open direction
+ * of the cone we have a hit from inside or outside the
+ * cone */
+ t_o.lower = select(validff, select(dOz*dr > 0.0f, t_o.lower, float(neg_inf)), t_o.lower);
+ t_o.upper = select(validff, select(dOz*dr > 0.0f, float(pos_inf), t_o.upper), t_o.upper);
+ }
+ }
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = (Oz+t_o.lower*dOz)*rl;
+ const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
+ const Vec3vfN Pl = v0 + u0_o*(v1-v0);
+ const Vec3vfN R = normalize(Pr-Pl);
+ const Vec3vfN U = (p1-p0)+(r1-r0)*R;
+ const Vec3vfN V = cross(p1-p0,R);
+ Ng0_o = cross(V,U);
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = (Oz+t_o.upper*dOz)*rl;
+ const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
+ const Vec3vfN Pl = v0 + u1_o*(v1-v0);
+ const Vec3vfN R = normalize(Pr-Pl);
+ const Vec3vfN U = (p1-p0)+(r1-r0)*R;
+ const Vec3vfN V = cross(p1-p0,R);
+ Ng1_o = cross(V,U);
+ }
+ return valid;
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir, BBox<vfloat<N>>& t_o) const
+ {
+ vfloat<N> u0_o; Vec3vfN Ng0_o; vfloat<N> u1_o; Vec3vfN Ng1_o;
+ return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/geometry/coneline_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/coneline_intersector.h
new file mode 100644
index 0000000000..0902baff7d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/coneline_intersector.h
@@ -0,0 +1,209 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ namespace __coneline_internal
+ {
+ template<int M, typename Epilog, typename ray_tfar_func>
+ static __forceinline bool intersectCone(const vbool<M>& valid_i,
+ const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,
+ const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
+ const Vec4vf<M>& v0, const Vec4vf<M>& v1,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ /* move ray origin closer to make calculations numerically stable */
+ const vfloat<M> dOdO = sqr(ray_dir);
+ const vfloat<M> rcp_dOdO = rcp(dOdO);
+ const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());
+ const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;
+ const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;
+
+ const Vec3vf<M> dP = v1.xyz() - v0.xyz();
+ const Vec3vf<M> p0 = ray_org - v0.xyz();
+ const Vec3vf<M> p1 = ray_org - v1.xyz();
+
+ const vfloat<M> dPdP = sqr(dP);
+ const vfloat<M> dP0 = dot(p0,dP);
+ const vfloat<M> dP1 = dot(p1,dP);
+ const vfloat<M> dOdP = dot(ray_dir,dP);
+
+ // intersect cone body
+ const vfloat<M> dr = v0.w - v1.w;
+ const vfloat<M> hy = dPdP + sqr(dr);
+ const vfloat<M> dO0 = dot(ray_dir,p0);
+ const vfloat<M> OO = sqr(p0);
+ const vfloat<M> dPdP2 = sqr(dPdP);
+ const vfloat<M> dPdPr0 = dPdP*v0.w;
+
+ const vfloat<M> A = dPdP2 - sqr(dOdP)*hy;
+ const vfloat<M> B = dPdP2*dO0 - dP0*dOdP*hy + dPdPr0*(dr*dOdP);
+ const vfloat<M> C = dPdP2*OO - sqr(dP0)*hy + dPdPr0*(2.0f*dr*dP0 - dPdPr0);
+
+ const vfloat<M> D = B*B - A*C;
+ valid &= D >= 0.0f;
+ if (unlikely(none(valid))) {
+ return false;
+ }
+
+ /* standard case for "non-parallel" rays */
+ const vfloat<M> Q = sqrt(D);
+ const vfloat<M> rcp_A = rcp(A);
+ /* special case for rays that are "parallel" to the cone - assume miss */
+ const vbool<M> isParallel = abs(A) <= min_rcp_input;
+
+ vfloat<M> t_cone_lower = select (isParallel, neg_inf, (-B-Q)*rcp_A);
+ vfloat<M> t_cone_upper = select (isParallel, pos_inf, (-B+Q)*rcp_A);
+ const vfloat<M> y_lower = dP0 + t_cone_lower*dOdP;
+ const vfloat<M> y_upper = dP0 + t_cone_upper*dOdP;
+ t_cone_lower = select(valid & y_lower > 0.0f & y_lower < dPdP, t_cone_lower, pos_inf);
+ t_cone_upper = select(valid & y_upper > 0.0f & y_upper < dPdP, t_cone_upper, neg_inf);
+
+ const vbool<M> hitDisk0 = valid & cL;
+ const vbool<M> hitDisk1 = valid & cR;
+ const vfloat<M> rcp_dOdP = rcp(dOdP);
+ const vfloat<M> t_disk0 = select (hitDisk0, select (sqr(p0*dOdP-ray_dir*dP0)<(sqr(v0.w)*sqr(dOdP)), -dP0*rcp_dOdP, pos_inf), pos_inf);
+ const vfloat<M> t_disk1 = select (hitDisk1, select (sqr(p1*dOdP-ray_dir*dP1)<(sqr(v1.w)*sqr(dOdP)), -dP1*rcp_dOdP, pos_inf), pos_inf);
+ const vfloat<M> t_disk_lower = min(t_disk0, t_disk1);
+ const vfloat<M> t_disk_upper = max(t_disk0, t_disk1);
+
+ const vfloat<M> t_lower = min(t_cone_lower, t_disk_lower);
+ const vfloat<M> t_upper = max(t_cone_upper, select(t_lower==t_disk_lower,
+ select(t_disk_upper==vfloat<M>(pos_inf),neg_inf,t_disk_upper),
+ select(t_disk_lower==vfloat<M>(pos_inf),neg_inf,t_disk_lower)));
+
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_lower & dt+t_lower <= ray_tfar() & t_lower != vfloat<M>(pos_inf);
+ const vbool<M> valid_upper = valid & ray_tnear <= dt+t_upper & dt+t_upper <= ray_tfar() & t_upper != vfloat<M>(neg_inf);
+
+ const vbool<M> valid_first = valid_lower | valid_upper;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ const vfloat<M> t_first = select(valid_lower, t_lower, t_upper);
+ const vfloat<M> y_first = select(valid_lower, y_lower, y_upper);
+
+ const vfloat<M> rcp_dPdP = rcp(dPdP);
+ const Vec3vf<M> dP2drr0dP = dPdP*dr*v0.w*dP;
+ const Vec3vf<M> dPhy = dP*hy;
+ const vbool<M> cone_hit_first = valid & (t_first == t_cone_lower | t_first == t_cone_upper);
+ const vbool<M> disk0_hit_first = valid & (t_first == t_disk0);
+ const Vec3vf<M> Ng_first = select(cone_hit_first, dPdP2*(p0+t_first*ray_dir)+dP2drr0dP-dPhy*y_first, select(disk0_hit_first, -dP, dP));
+ const vfloat<M> u_first = select(cone_hit_first, y_first*rcp_dPdP, select(disk0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_upper;
+ const vfloat<M> y_second = y_upper;
+ const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_upper <= ray_tfar());
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;
+ const vbool<M> disk0_hit_second = t_second == t_disk0;
+ const Vec3vf<M> Ng_second = select(cone_hit_second, dPdP2*(p0+t_second*ray_dir)+dP2drr0dP-dPhy*y_second, select(disk0_hit_second, -dP, dP));
+ const vfloat<M> u_second = select(cone_hit_second, y_second*rcp_dPdP, select(disk0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+ }
+
+ template<int M>
+ struct ConeLineIntersectorHitM
+ {
+ __forceinline ConeLineIntersectorHitM() {}
+
+ __forceinline ConeLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct ConeCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ struct ray_tfar {
+ Ray& ray;
+ __forceinline ray_tfar(Ray& ray) : ray(ray) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> ray_tnear(ray.tnear());
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+ return __coneline_internal::intersectCone(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray),v0,v1,cL,cR,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct ConeCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ struct ray_tfar {
+ RayK<K>& ray;
+ size_t k;
+ __forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar[k]; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> ray_tnear = ray.tnear()[k];
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+ return __coneline_internal::intersectCone(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,cL,cR,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/conelinei_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/conelinei_intersector.h
new file mode 100644
index 0000000000..d47218eb8b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/conelinei_intersector.h
@@ -0,0 +1,141 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "coneline_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, int Mx, bool filter>
+ struct ConeCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ ConeCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return ConeCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct ConeCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ ConeCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return ConeCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct ConeCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ ConeCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return ConeCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct ConeCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ ConeCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return ConeCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNi.h b/thirdparty/embree-aarch64/kernels/geometry/curveNi.h
new file mode 100644
index 0000000000..51384f1959
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNi.h
@@ -0,0 +1,222 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNi
+ {
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNi) == 22+25*M, "internal data layout issue");
+ return f*sizeof(CurveNi) + (r!=0)*(22 + 25*r);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNi () {}
+
+ /*! fill curve from curve list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t _end, Scene* scene)
+ {
+ size_t end = min(begin+M,_end);
+ N = (uint8_t)(end-begin);
+ const unsigned int geomID0 = prims[begin].geomID();
+ this->geomID(N) = geomID0;
+ ty = (uint8_t) scene->get(geomID0)->getType();
+
+ /* encode all primitives */
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID(); assert(geomID == geomID0);
+ const unsigned int primID = prim.primID();
+ bounds.extend(scene->get(geomID)->vbounds(primID));
+ }
+
+ /* calculate offset and scale */
+ Vec3fa loffset = bounds.lower;
+ float lscale = reduce_min(256.0f/(bounds.size()*sqrt(3.0f)));
+ if (bounds.size() == Vec3fa(zero)) lscale = 0.0f;
+ *this->offset(N) = loffset;
+ *this->scale(N) = lscale;
+
+ /* encode all primitives */
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const LinearSpace3fa space2 = scene->get(geomID)->computeAlignedSpace(primID);
+
+ const LinearSpace3fa space3(trunc(126.0f*space2.vx),trunc(126.0f*space2.vy),trunc(126.0f*space2.vz));
+ const BBox3fa bounds = scene->get(geomID)->vbounds(loffset,lscale,max(length(space3.vx),length(space3.vy),length(space3.vz)),space3.transposed(),primID);
+
+ bounds_vx_x(N)[i] = (int8_t) space3.vx.x;
+ bounds_vx_y(N)[i] = (int8_t) space3.vx.y;
+ bounds_vx_z(N)[i] = (int8_t) space3.vx.z;
+ bounds_vx_lower(N)[i] = (short) clamp(floor(bounds.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper(N)[i] = (short) clamp(ceil (bounds.upper.x),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.x) && floor(bounds.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.x) && ceil (bounds.upper.x) <= 32767.0f);
+
+ bounds_vy_x(N)[i] = (int8_t) space3.vy.x;
+ bounds_vy_y(N)[i] = (int8_t) space3.vy.y;
+ bounds_vy_z(N)[i] = (int8_t) space3.vy.z;
+ bounds_vy_lower(N)[i] = (short) clamp(floor(bounds.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper(N)[i] = (short) clamp(ceil (bounds.upper.y),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.y) && floor(bounds.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.y) && ceil (bounds.upper.y) <= 32767.0f);
+
+ bounds_vz_x(N)[i] = (int8_t) space3.vz.x;
+ bounds_vz_y(N)[i] = (int8_t) space3.vz.y;
+ bounds_vz_z(N)[i] = (int8_t) space3.vz.z;
+ bounds_vz_lower(N)[i] = (short) clamp(floor(bounds.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper(N)[i] = (short) clamp(ceil (bounds.upper.z),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.z) && floor(bounds.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.z) && ceil (bounds.upper.z) <= 32767.0f);
+
+ this->primID(N)[i] = primID;
+ }
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = CurveNi::blocks(set.size());
+ size_t numbytes = CurveNi::bytes(set.size());
+ CurveNi* accel = (CurveNi*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((int8_t*)accel,items);
+ };
+
+ public:
+
+ // 27.6 - 46 bytes per primitive
+ uint8_t ty;
+ uint8_t N;
+ uint8_t data[4+25*M+16];
+
+ /*
+ struct Layout
+ {
+ unsigned int geomID;
+ unsigned int primID[N];
+
+ int8_t bounds_vx_x[N];
+ int8_t bounds_vx_y[N];
+ int8_t bounds_vx_z[N];
+ short bounds_vx_lower[N];
+ short bounds_vx_upper[N];
+
+ int8_t bounds_vy_x[N];
+ int8_t bounds_vy_y[N];
+ int8_t bounds_vy_z[N];
+ short bounds_vy_lower[N];
+ short bounds_vy_upper[N];
+
+ int8_t bounds_vz_x[N];
+ int8_t bounds_vz_y[N];
+ int8_t bounds_vz_z[N];
+ short bounds_vz_lower[N];
+ short bounds_vz_upper[N];
+
+ Vec3f offset;
+ float scale;
+ };
+ */
+
+ __forceinline unsigned int& geomID(size_t N) { return *(unsigned int*)((int8_t*)this+2); }
+ __forceinline const unsigned int& geomID(size_t N) const { return *(unsigned int*)((int8_t*)this+2); }
+
+ __forceinline unsigned int* primID(size_t N) { return (unsigned int*)((int8_t*)this+6); }
+ __forceinline const unsigned int* primID(size_t N) const { return (unsigned int*)((int8_t*)this+6); }
+
+ __forceinline int8_t* bounds_vx_x(size_t N) { return (int8_t*)((int8_t*)this+6+4*N); }
+ __forceinline const int8_t* bounds_vx_x(size_t N) const { return (int8_t*)((int8_t*)this+6+4*N); }
+
+ __forceinline int8_t* bounds_vx_y(size_t N) { return (int8_t*)((int8_t*)this+6+5*N); }
+ __forceinline const int8_t* bounds_vx_y(size_t N) const { return (int8_t*)((int8_t*)this+6+5*N); }
+
+ __forceinline int8_t* bounds_vx_z(size_t N) { return (int8_t*)((int8_t*)this+6+6*N); }
+ __forceinline const int8_t* bounds_vx_z(size_t N) const { return (int8_t*)((int8_t*)this+6+6*N); }
+
+ __forceinline short* bounds_vx_lower(size_t N) { return (short*)((int8_t*)this+6+7*N); }
+ __forceinline const short* bounds_vx_lower(size_t N) const { return (short*)((int8_t*)this+6+7*N); }
+
+ __forceinline short* bounds_vx_upper(size_t N) { return (short*)((int8_t*)this+6+9*N); }
+ __forceinline const short* bounds_vx_upper(size_t N) const { return (short*)((int8_t*)this+6+9*N); }
+
+ __forceinline int8_t* bounds_vy_x(size_t N) { return (int8_t*)((int8_t*)this+6+11*N); }
+ __forceinline const int8_t* bounds_vy_x(size_t N) const { return (int8_t*)((int8_t*)this+6+11*N); }
+
+ __forceinline int8_t* bounds_vy_y(size_t N) { return (int8_t*)((int8_t*)this+6+12*N); }
+ __forceinline const int8_t* bounds_vy_y(size_t N) const { return (int8_t*)((int8_t*)this+6+12*N); }
+
+ __forceinline int8_t* bounds_vy_z(size_t N) { return (int8_t*)((int8_t*)this+6+13*N); }
+ __forceinline const int8_t* bounds_vy_z(size_t N) const { return (int8_t*)((int8_t*)this+6+13*N); }
+
+ __forceinline short* bounds_vy_lower(size_t N) { return (short*)((int8_t*)this+6+14*N); }
+ __forceinline const short* bounds_vy_lower(size_t N) const { return (short*)((int8_t*)this+6+14*N); }
+
+ __forceinline short* bounds_vy_upper(size_t N) { return (short*)((int8_t*)this+6+16*N); }
+ __forceinline const short* bounds_vy_upper(size_t N) const { return (short*)((int8_t*)this+6+16*N); }
+
+ __forceinline int8_t* bounds_vz_x(size_t N) { return (int8_t*)((int8_t*)this+6+18*N); }
+ __forceinline const int8_t* bounds_vz_x(size_t N) const { return (int8_t*)((int8_t*)this+6+18*N); }
+
+ __forceinline int8_t* bounds_vz_y(size_t N) { return (int8_t*)((int8_t*)this+6+19*N); }
+ __forceinline const int8_t* bounds_vz_y(size_t N) const { return (int8_t*)((int8_t*)this+6+19*N); }
+
+ __forceinline int8_t* bounds_vz_z(size_t N) { return (int8_t*)((int8_t*)this+6+20*N); }
+ __forceinline const int8_t* bounds_vz_z(size_t N) const { return (int8_t*)((int8_t*)this+6+20*N); }
+
+ __forceinline short* bounds_vz_lower(size_t N) { return (short*)((int8_t*)this+6+21*N); }
+ __forceinline const short* bounds_vz_lower(size_t N) const { return (short*)((int8_t*)this+6+21*N); }
+
+ __forceinline short* bounds_vz_upper(size_t N) { return (short*)((int8_t*)this+6+23*N); }
+ __forceinline const short* bounds_vz_upper(size_t N) const { return (short*)((int8_t*)this+6+23*N); }
+
+ __forceinline Vec3f* offset(size_t N) { return (Vec3f*)((int8_t*)this+6+25*N); }
+ __forceinline const Vec3f* offset(size_t N) const { return (Vec3f*)((int8_t*)this+6+25*N); }
+
+ __forceinline float* scale(size_t N) { return (float*)((int8_t*)this+6+25*N+12); }
+ __forceinline const float* scale(size_t N) const { return (float*)((int8_t*)this+6+25*N+12); }
+
+ __forceinline int8_t* end(size_t N) { return (int8_t*)this+6+25*N+16; }
+ __forceinline const int8_t* end(size_t N) const { return (int8_t*)this+6+25*N+16; }
+ };
+
+ template<int M>
+ typename CurveNi<M>::Type CurveNi<M>::type;
+
+ typedef CurveNi<4> Curve4i;
+ typedef CurveNi<8> Curve8i;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNi_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/curveNi_intersector.h
new file mode 100644
index 0000000000..0f9038c9fc
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNi_intersector.h
@@ -0,0 +1,569 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNiIntersector1
+ {
+ typedef CurveNi<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+ const Vec3fa org1 = (ray.org-offset)*scale;
+ const Vec3fa dir1 = ray.dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> t_lower_x = (vfloat<M>::load(prim.bounds_vx_lower(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vfloat<M>::load(prim.bounds_vx_upper(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vfloat<M>::load(prim.bounds_vy_lower(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vfloat<M>::load(prim.bounds_vy_upper(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vfloat<M>::load(prim.bounds_vz_lower(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vfloat<M>::load(prim.bounds_vz_upper(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNiIntersectorK
+ {
+ typedef CurveNi<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ const Vec3fa org1 = (ray_org-offset)*scale;
+ const Vec3fa dir1 = ray_dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> t_lower_x = (vfloat<M>::load(prim.bounds_vx_lower(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vfloat<M>::load(prim.bounds_vx_upper(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vfloat<M>::load(prim.bounds_vy_lower(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vfloat<M>::load(prim.bounds_vy_upper(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vfloat<M>::load(prim.bounds_vz_lower(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vfloat<M>::load(prim.bounds_vz_upper(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()[k]));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar[k]));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb.h b/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb.h
new file mode 100644
index 0000000000..0cd8f833fd
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb.h
@@ -0,0 +1,278 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNiMB
+ {
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNiMB) == 6+37*M+24, "internal data layout issue");
+ return f*sizeof(CurveNiMB) + (r!=0)*(6+37*r+24);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNiMB () {}
+
+ /*! fill curve from curve list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t _end, Scene* scene, const BBox1f time_range)
+ {
+ size_t end = min(begin+M,_end);
+ N = (uint8_t)(end-begin);
+ const unsigned int geomID0 = prims[begin].geomID();
+ this->geomID(N) = geomID0;
+ ty = (uint8_t) scene->get(geomID0)->getType();
+
+ /* encode all primitives */
+ LBBox3fa lbounds = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRefMB& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID(); assert(geomID == geomID0);
+ const unsigned int primID = prim.primID();
+ lbounds.extend(scene->get(geomID)->vlinearBounds(primID,time_range));
+ }
+ BBox3fa bounds = lbounds.bounds();
+
+ /* calculate offset and scale */
+ Vec3fa loffset = bounds.lower;
+ float lscale = reduce_min(256.0f/(bounds.size()*sqrt(3.0f)));
+ if (bounds.size() == Vec3fa(zero)) lscale = 0.0f;
+ *this->offset(N) = loffset;
+ *this->scale(N) = lscale;
+ this->time_offset(N) = time_range.lower;
+ this->time_scale(N) = 1.0f/time_range.size();
+
+ /* encode all primitives */
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRefMB& prim = prims[begin];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const LinearSpace3fa space2 = scene->get(geomID)->computeAlignedSpaceMB(primID,time_range);
+
+ const LinearSpace3fa space3(trunc(126.0f*space2.vx),trunc(126.0f*space2.vy),trunc(126.0f*space2.vz));
+ const LBBox3fa bounds = scene->get(geomID)->vlinearBounds(loffset,lscale,max(length(space3.vx),length(space3.vy),length(space3.vz)),space3.transposed(),primID,time_range);
+
+ // NOTE: this weird (int8_t) (short) cast works around VS2015 Win32 compiler bug
+ bounds_vx_x(N)[i] = (int8_t) (short) space3.vx.x;
+ bounds_vx_y(N)[i] = (int8_t) (short) space3.vx.y;
+ bounds_vx_z(N)[i] = (int8_t) (short) space3.vx.z;
+ bounds_vx_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.x),-32767.0f,32767.0f);
+ bounds_vx_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.x),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.x) && floor(bounds.bounds0.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.x) && ceil (bounds.bounds0.upper.x) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.x) && floor(bounds.bounds1.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.x) && ceil (bounds.bounds1.upper.x) <= 32767.0f);
+
+ bounds_vy_x(N)[i] = (int8_t) (short) space3.vy.x;
+ bounds_vy_y(N)[i] = (int8_t) (short) space3.vy.y;
+ bounds_vy_z(N)[i] = (int8_t) (short) space3.vy.z;
+ bounds_vy_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.y),-32767.0f,32767.0f);
+ bounds_vy_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.y),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.y) && floor(bounds.bounds0.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.y) && ceil (bounds.bounds0.upper.y) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.y) && floor(bounds.bounds1.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.y) && ceil (bounds.bounds1.upper.y) <= 32767.0f);
+
+ bounds_vz_x(N)[i] = (int8_t) (short) space3.vz.x;
+ bounds_vz_y(N)[i] = (int8_t) (short) space3.vz.y;
+ bounds_vz_z(N)[i] = (int8_t) (short) space3.vz.z;
+ bounds_vz_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.z),-32767.0f,32767.0f);
+ bounds_vz_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.z),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.z) && floor(bounds.bounds0.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.z) && ceil (bounds.bounds0.upper.z) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.z) && floor(bounds.bounds1.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.z) && ceil (bounds.bounds1.upper.z) <= 32767.0f);
+
+ this->primID(N)[i] = primID;
+ }
+
+ return lbounds;
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.begin();
+ size_t end = prims.end();
+ size_t items = CurveNiMB::blocks(prims.size());
+ size_t numbytes = CurveNiMB::bytes(prims.size());
+ CurveNiMB* accel = (CurveNiMB*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ const typename BVH::NodeRef node = bvh->encodeLeaf((int8_t*)accel,items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(),start,end,bvh->scene,prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node,bounds,prims.time_range);
+ };
+
+
+ public:
+
+ // 27.6 - 46 bytes per primitive
+ uint8_t ty;
+ uint8_t N;
+ uint8_t data[4+37*M+24];
+
+ /*
+ struct Layout
+ {
+ unsigned int geomID;
+ unsigned int primID[N];
+
+ int8_t bounds_vx_x[N];
+ int8_t bounds_vx_y[N];
+ int8_t bounds_vx_z[N];
+ short bounds_vx_lower0[N];
+ short bounds_vx_upper0[N];
+ short bounds_vx_lower1[N];
+ short bounds_vx_upper1[N];
+
+ int8_t bounds_vy_x[N];
+ int8_t bounds_vy_y[N];
+ int8_t bounds_vy_z[N];
+ short bounds_vy_lower0[N];
+ short bounds_vy_upper0[N];
+ short bounds_vy_lower1[N];
+ short bounds_vy_upper1[N];
+
+ int8_t bounds_vz_x[N];
+ int8_t bounds_vz_y[N];
+ int8_t bounds_vz_z[N];
+ short bounds_vz_lower0[N];
+ short bounds_vz_upper0[N];
+ short bounds_vz_lower1[N];
+ short bounds_vz_upper1[N];
+
+ Vec3f offset;
+ float scale;
+
+ float time_offset;
+ float time_scale;
+ };
+ */
+
+ __forceinline unsigned int& geomID(size_t N) { return *(unsigned int*)((int8_t*)this+2); }
+ __forceinline const unsigned int& geomID(size_t N) const { return *(unsigned int*)((int8_t*)this+2); }
+
+ __forceinline unsigned int* primID(size_t N) { return (unsigned int*)((int8_t*)this+6); }
+ __forceinline const unsigned int* primID(size_t N) const { return (unsigned int*)((int8_t*)this+6); }
+
+ __forceinline int8_t* bounds_vx_x(size_t N) { return (int8_t*)((int8_t*)this+6+4*N); }
+ __forceinline const int8_t* bounds_vx_x(size_t N) const { return (int8_t*)((int8_t*)this+6+4*N); }
+
+ __forceinline int8_t* bounds_vx_y(size_t N) { return (int8_t*)((int8_t*)this+6+5*N); }
+ __forceinline const int8_t* bounds_vx_y(size_t N) const { return (int8_t*)((int8_t*)this+6+5*N); }
+
+ __forceinline int8_t* bounds_vx_z(size_t N) { return (int8_t*)((int8_t*)this+6+6*N); }
+ __forceinline const int8_t* bounds_vx_z(size_t N) const { return (int8_t*)((int8_t*)this+6+6*N); }
+
+ __forceinline short* bounds_vx_lower0(size_t N) { return (short*)((int8_t*)this+6+7*N); }
+ __forceinline const short* bounds_vx_lower0(size_t N) const { return (short*)((int8_t*)this+6+7*N); }
+
+ __forceinline short* bounds_vx_upper0(size_t N) { return (short*)((int8_t*)this+6+9*N); }
+ __forceinline const short* bounds_vx_upper0(size_t N) const { return (short*)((int8_t*)this+6+9*N); }
+
+ __forceinline short* bounds_vx_lower1(size_t N) { return (short*)((int8_t*)this+6+11*N); }
+ __forceinline const short* bounds_vx_lower1(size_t N) const { return (short*)((int8_t*)this+6+11*N); }
+
+ __forceinline short* bounds_vx_upper1(size_t N) { return (short*)((int8_t*)this+6+13*N); }
+ __forceinline const short* bounds_vx_upper1(size_t N) const { return (short*)((int8_t*)this+6+13*N); }
+
+ __forceinline int8_t* bounds_vy_x(size_t N) { return (int8_t*)((int8_t*)this+6+15*N); }
+ __forceinline const int8_t* bounds_vy_x(size_t N) const { return (int8_t*)((int8_t*)this+6+15*N); }
+
+ __forceinline int8_t* bounds_vy_y(size_t N) { return (int8_t*)((int8_t*)this+6+16*N); }
+ __forceinline const int8_t* bounds_vy_y(size_t N) const { return (int8_t*)((int8_t*)this+6+16*N); }
+
+ __forceinline int8_t* bounds_vy_z(size_t N) { return (int8_t*)((int8_t*)this+6+17*N); }
+ __forceinline const int8_t* bounds_vy_z(size_t N) const { return (int8_t*)((int8_t*)this+6+17*N); }
+
+ __forceinline short* bounds_vy_lower0(size_t N) { return (short*)((int8_t*)this+6+18*N); }
+ __forceinline const short* bounds_vy_lower0(size_t N) const { return (short*)((int8_t*)this+6+18*N); }
+
+ __forceinline short* bounds_vy_upper0(size_t N) { return (short*)((int8_t*)this+6+20*N); }
+ __forceinline const short* bounds_vy_upper0(size_t N) const { return (short*)((int8_t*)this+6+20*N); }
+
+ __forceinline short* bounds_vy_lower1(size_t N) { return (short*)((int8_t*)this+6+22*N); }
+ __forceinline const short* bounds_vy_lower1(size_t N) const { return (short*)((int8_t*)this+6+22*N); }
+
+ __forceinline short* bounds_vy_upper1(size_t N) { return (short*)((int8_t*)this+6+24*N); }
+ __forceinline const short* bounds_vy_upper1(size_t N) const { return (short*)((int8_t*)this+6+24*N); }
+
+ __forceinline int8_t* bounds_vz_x(size_t N) { return (int8_t*)((int8_t*)this+6+26*N); }
+ __forceinline const int8_t* bounds_vz_x(size_t N) const { return (int8_t*)((int8_t*)this+6+26*N); }
+
+ __forceinline int8_t* bounds_vz_y(size_t N) { return (int8_t*)((int8_t*)this+6+27*N); }
+ __forceinline const int8_t* bounds_vz_y(size_t N) const { return (int8_t*)((int8_t*)this+6+27*N); }
+
+ __forceinline int8_t* bounds_vz_z(size_t N) { return (int8_t*)((int8_t*)this+6+28*N); }
+ __forceinline const int8_t* bounds_vz_z(size_t N) const { return (int8_t*)((int8_t*)this+6+28*N); }
+
+ __forceinline short* bounds_vz_lower0(size_t N) { return (short*)((int8_t*)this+6+29*N); }
+ __forceinline const short* bounds_vz_lower0(size_t N) const { return (short*)((int8_t*)this+6+29*N); }
+
+ __forceinline short* bounds_vz_upper0(size_t N) { return (short*)((int8_t*)this+6+31*N); }
+ __forceinline const short* bounds_vz_upper0(size_t N) const { return (short*)((int8_t*)this+6+31*N); }
+
+ __forceinline short* bounds_vz_lower1(size_t N) { return (short*)((int8_t*)this+6+33*N); }
+ __forceinline const short* bounds_vz_lower1(size_t N) const { return (short*)((int8_t*)this+6+33*N); }
+
+ __forceinline short* bounds_vz_upper1(size_t N) { return (short*)((int8_t*)this+6+35*N); }
+ __forceinline const short* bounds_vz_upper1(size_t N) const { return (short*)((int8_t*)this+6+35*N); }
+
+ __forceinline Vec3f* offset(size_t N) { return (Vec3f*)((int8_t*)this+6+37*N); }
+ __forceinline const Vec3f* offset(size_t N) const { return (Vec3f*)((int8_t*)this+6+37*N); }
+
+ __forceinline float* scale(size_t N) { return (float*)((int8_t*)this+6+37*N+12); }
+ __forceinline const float* scale(size_t N) const { return (float*)((int8_t*)this+6+37*N+12); }
+
+ __forceinline float& time_offset(size_t N) { return *(float*)((int8_t*)this+6+37*N+16); }
+ __forceinline const float& time_offset(size_t N) const { return *(float*)((int8_t*)this+6+37*N+16); }
+
+ __forceinline float& time_scale(size_t N) { return *(float*)((int8_t*)this+6+37*N+20); }
+ __forceinline const float& time_scale(size_t N) const { return *(float*)((int8_t*)this+6+37*N+20); }
+
+ __forceinline int8_t* end(size_t N) { return (int8_t*)this+6+37*N+24; }
+ __forceinline const int8_t* end(size_t N) const { return (int8_t*)this+6+37*N+24; }
+ };
+
+ template<int M>
+ typename CurveNiMB<M>::Type CurveNiMB<M>::type;
+
+ typedef CurveNiMB<4> Curve4iMB;
+ typedef CurveNiMB<8> Curve8iMB;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb_intersector.h
new file mode 100644
index 0000000000..0cbc764668
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNi_mb_intersector.h
@@ -0,0 +1,516 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi_mb.h"
+#include "../subdiv/linear_bezier_patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNiMBIntersector1
+ {
+ typedef CurveNiMB<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+ const Vec3fa org1 = (ray.org-offset)*scale;
+ const Vec3fa dir1 = ray.dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> ltime = (ray.time()-prim.time_offset(N))*prim.time_scale(N);
+ const vfloat<M> vx_lower0 = vfloat<M>::load(prim.bounds_vx_lower0(N));
+ const vfloat<M> vx_lower1 = vfloat<M>::load(prim.bounds_vx_lower1(N));
+ const vfloat<M> vx_lower = madd(ltime,vx_lower1-vx_lower0,vx_lower0);
+ const vfloat<M> vx_upper0 = vfloat<M>::load(prim.bounds_vx_upper0(N));
+ const vfloat<M> vx_upper1 = vfloat<M>::load(prim.bounds_vx_upper1(N));
+ const vfloat<M> vx_upper = madd(ltime,vx_upper1-vx_upper0,vx_upper0);
+
+ const vfloat<M> vy_lower0 = vfloat<M>::load(prim.bounds_vy_lower0(N));
+ const vfloat<M> vy_lower1 = vfloat<M>::load(prim.bounds_vy_lower1(N));
+ const vfloat<M> vy_lower = madd(ltime,vy_lower1-vy_lower0,vy_lower0);
+ const vfloat<M> vy_upper0 = vfloat<M>::load(prim.bounds_vy_upper0(N));
+ const vfloat<M> vy_upper1 = vfloat<M>::load(prim.bounds_vy_upper1(N));
+ const vfloat<M> vy_upper = madd(ltime,vy_upper1-vy_upper0,vy_upper0);
+
+ const vfloat<M> vz_lower0 = vfloat<M>::load(prim.bounds_vz_lower0(N));
+ const vfloat<M> vz_lower1 = vfloat<M>::load(prim.bounds_vz_lower1(N));
+ const vfloat<M> vz_lower = madd(ltime,vz_lower1-vz_lower0,vz_lower0);
+ const vfloat<M> vz_upper0 = vfloat<M>::load(prim.bounds_vz_upper0(N));
+ const vfloat<M> vz_upper1 = vfloat<M>::load(prim.bounds_vz_upper1(N));
+ const vfloat<M> vz_upper = madd(ltime,vz_upper1-vz_upper0,vz_upper0);
+
+ const vfloat<M> t_lower_x = (vx_lower-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vx_upper-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vy_lower-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vy_upper-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vz_lower-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vz_upper-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time());
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time());
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time());
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ if (Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNiMBIntersectorK
+ {
+ typedef CurveNiMB<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ const Vec3fa org1 = (ray_org-offset)*scale;
+ const Vec3fa dir1 = ray_dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> ltime = (ray.time()[k]-prim.time_offset(N))*prim.time_scale(N);
+ const vfloat<M> vx_lower0 = vfloat<M>::load(prim.bounds_vx_lower0(N));
+ const vfloat<M> vx_lower1 = vfloat<M>::load(prim.bounds_vx_lower1(N));
+ const vfloat<M> vx_lower = madd(ltime,vx_lower1-vx_lower0,vx_lower0);
+ const vfloat<M> vx_upper0 = vfloat<M>::load(prim.bounds_vx_upper0(N));
+ const vfloat<M> vx_upper1 = vfloat<M>::load(prim.bounds_vx_upper1(N));
+ const vfloat<M> vx_upper = madd(ltime,vx_upper1-vx_upper0,vx_upper0);
+
+ const vfloat<M> vy_lower0 = vfloat<M>::load(prim.bounds_vy_lower0(N));
+ const vfloat<M> vy_lower1 = vfloat<M>::load(prim.bounds_vy_lower1(N));
+ const vfloat<M> vy_lower = madd(ltime,vy_lower1-vy_lower0,vy_lower0);
+ const vfloat<M> vy_upper0 = vfloat<M>::load(prim.bounds_vy_upper0(N));
+ const vfloat<M> vy_upper1 = vfloat<M>::load(prim.bounds_vy_upper1(N));
+ const vfloat<M> vy_upper = madd(ltime,vy_upper1-vy_upper0,vy_upper0);
+
+ const vfloat<M> vz_lower0 = vfloat<M>::load(prim.bounds_vz_lower0(N));
+ const vfloat<M> vz_lower1 = vfloat<M>::load(prim.bounds_vz_lower1(N));
+ const vfloat<M> vz_lower = madd(ltime,vz_lower1-vz_lower0,vz_lower0);
+ const vfloat<M> vz_upper0 = vfloat<M>::load(prim.bounds_vz_upper0(N));
+ const vfloat<M> vz_upper1 = vfloat<M>::load(prim.bounds_vz_upper1(N));
+ const vfloat<M> vz_upper = madd(ltime,vz_upper1-vz_upper0,vz_upper0);
+
+ const vfloat<M> t_lower_x = (vx_lower-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vx_upper-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vy_lower-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vy_upper-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vz_lower-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vz_upper-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()[k]));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar[k]));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time()[k]);
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time()[k]);
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time()[k]);
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNv.h b/thirdparty/embree-aarch64/kernels/geometry/curveNv.h
new file mode 100644
index 0000000000..6eb5e30b39
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNv.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNv : public CurveNi<M>
+ {
+ using CurveNi<M>::N;
+
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNv) == 22+25*M+4*16*M, "internal data layout issue");
+ return f*sizeof(CurveNv) + (r!=0)*(22 + 25*r + 4*16*r);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNv () {}
+
+ /*! fill curve from curve list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t _end, Scene* scene)
+ {
+ size_t end = min(begin+M,_end);
+ size_t N = end-begin;
+
+ /* encode all primitives */
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ CurveGeometry* mesh = (CurveGeometry*) scene->get(geomID);
+ const unsigned vtxID = mesh->curve(primID);
+ Vec3fa::storeu(&this->vertices(i,N)[0],mesh->vertex(vtxID+0));
+ Vec3fa::storeu(&this->vertices(i,N)[1],mesh->vertex(vtxID+1));
+ Vec3fa::storeu(&this->vertices(i,N)[2],mesh->vertex(vtxID+2));
+ Vec3fa::storeu(&this->vertices(i,N)[3],mesh->vertex(vtxID+3));
+ }
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ if (set.size() == 0)
+ return BVH::emptyNode;
+
+ /* fall back to CurveNi for oriented curves */
+ unsigned int geomID = prims[set.begin()].geomID();
+ if (bvh->scene->get(geomID)->getCurveType() == Geometry::GTY_SUBTYPE_ORIENTED_CURVE) {
+ return CurveNi<M>::createLeaf(bvh,prims,set,alloc);
+ }
+ if (bvh->scene->get(geomID)->getCurveBasis() == Geometry::GTY_BASIS_HERMITE) {
+ return CurveNi<M>::createLeaf(bvh,prims,set,alloc);
+ }
+
+ size_t start = set.begin();
+ size_t items = CurveNv::blocks(set.size());
+ size_t numbytes = CurveNv::bytes(set.size());
+ CurveNv* accel = (CurveNv*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ for (size_t i=0; i<items; i++) {
+ accel[i].CurveNv<M>::fill(prims,start,set.end(),bvh->scene);
+ accel[i].CurveNi<M>::fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel,items);
+ };
+
+ public:
+ unsigned char data[4*16*M];
+ __forceinline Vec3fa* vertices(size_t i, size_t N) { return (Vec3fa*)CurveNi<M>::end(N)+4*i; }
+ __forceinline const Vec3fa* vertices(size_t i, size_t N) const { return (Vec3fa*)CurveNi<M>::end(N)+4*i; }
+ };
+
+ template<int M>
+ typename CurveNv<M>::Type CurveNv<M>::type;
+
+ typedef CurveNv<4> Curve4v;
+ typedef CurveNv<8> Curve8v;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curveNv_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/curveNv_intersector.h
new file mode 100644
index 0000000000..e20da2882e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curveNv_intersector.h
@@ -0,0 +1,181 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNv.h"
+#include "curveNi_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNvIntersector1 : public CurveNiIntersector1<M>
+ {
+ typedef CurveNv<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNvIntersectorK : public CurveNiIntersectorK<M,K>
+ {
+ typedef CurveNv<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector.h
new file mode 100644
index 0000000000..204958f7cc
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../subdiv/bezier_curve.h"
+#include "../common/primref.h"
+#include "bezier_hair_intersector.h"
+#include "bezier_ribbon_intersector.h"
+#include "bezier_curve_intersector.h"
+#include "oriented_curve_intersector.h"
+#include "../bvh/node_intersector1.h"
+
+// FIXME: this file seems replicate of curve_intersector_virtual.h
+
+namespace embree
+{
+ namespace isa
+ {
+ struct VirtualCurveIntersector1
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<1>(&pre,&ray,context,prim);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<1>(&pre,&ray,context,prim);
+ }
+ };
+
+ template<int K>
+ struct VirtualCurveIntersectorK
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ size_t mask = movemask(valid_i);
+ while (mask) leafIntersector.intersect<K>(&pre,&ray,bscf(mask),context,prim);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ vbool<K> valid_o = false;
+ size_t mask = movemask(valid_i);
+ while (mask) {
+ size_t k = bscf(mask);
+ if (leafIntersector.occluded<K>(&pre,&ray,k,context,prim))
+ set(valid_o, k);
+ }
+ return valid_o;
+ }
+
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<K>(&pre,&ray,k,context,prim);
+ }
+
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<K>(&pre,&ray,k,context,prim);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_distance.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_distance.h
new file mode 100644
index 0000000000..343cc8ff28
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_distance.h
@@ -0,0 +1,129 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename NativeCurve3fa, int M>
+ struct DistanceCurveHit
+ {
+ __forceinline DistanceCurveHit() {}
+
+ __forceinline DistanceCurveHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N,
+ const NativeCurve3fa& curve3D)
+ : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {}
+
+ __forceinline void finalize()
+ {
+ vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N));
+ vv = V;
+ vt = T;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const {
+ return curve3D.eval_du(vu[i]);
+ }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ int i, N;
+ NativeCurve3fa curve3D;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ };
+
+ template<typename NativeCurve3fa>
+ struct DistanceCurve1Intersector1
+ {
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculations1& pre,Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+
+ /* transform control points into ray space */
+ const NativeCurve3fa curve3Di(v0,v1,v2,v3);
+ const NativeCurve3fa curve3D = enlargeRadiusToMinWidth(context,geom,ray.org,curve3Di);
+ const NativeCurve3fa curve2D = curve3D.xfm_pr(pre.ray_space,ray.org);
+
+ /* evaluate the bezier curve */
+ vboolx valid = vfloatx(step) < vfloatx(float(N));
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N);
+
+ /* approximative intersection with cone */
+ const Vec4vfx v = p1-p0;
+ const Vec4vfx w = -p0;
+ const vfloatx d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloatx d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloatx u = clamp(d0*rcp(d1),vfloatx(zero),vfloatx(one));
+ const Vec4vfx p = madd(u,v,p0);
+ const vfloatx t = p.z*pre.depth_scale;
+ const vfloatx d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloatx r = p.w;
+ const vfloatx r2 = r*r;
+ valid &= (d2 <= r2) & (vfloatx(ray.tnear()) <= t) & (t <= vfloatx(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*pre.depth_scale; // ignore self intersections
+
+ /* update hit information */
+ bool ishit = false;
+ if (unlikely(any(valid))) {
+ DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,0,N,curve3D);
+ ishit = ishit | epilog(valid,hit);
+ }
+
+ if (unlikely(VSIZEX < N))
+ {
+ /* process SIMD-size many segments per iteration */
+ for (int i=VSIZEX; i<N; i+=VSIZEX)
+ {
+ /* evaluate the bezier curve */
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N);
+
+ /* approximative intersection with cone */
+ const Vec4vfx v = p1-p0;
+ const Vec4vfx w = -p0;
+ const vfloatx d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloatx d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloatx u = clamp(d0*rcp(d1),vfloatx(zero),vfloatx(one));
+ const Vec4vfx p = madd(u,v,p0);
+ const vfloatx t = p.z*pre.depth_scale;
+ const vfloatx d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloatx r = p.w;
+ const vfloatx r2 = r*r;
+ valid &= (d2 <= r2) & (vfloatx(ray.tnear()) <= t) & (t <= vfloatx(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*pre.depth_scale; // ignore self intersections
+
+ /* update hit information */
+ if (unlikely(any(valid))) {
+ DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,i,N,curve3D);
+ ishit = ishit | epilog(valid,hit);
+ }
+ }
+ }
+ return ishit;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_oriented.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_oriented.h
new file mode 100644
index 0000000000..47531027fc
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_oriented.h
@@ -0,0 +1,417 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+#include "curve_intersector_sweep.h"
+#include "../subdiv/linear_bezier_patch.h"
+
+#define DBG(x)
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Ray, typename Epilog>
+ struct TensorLinearCubicBezierSurfaceIntersector
+ {
+ const LinearSpace3fa& ray_space;
+ Ray& ray;
+ TensorLinearCubicBezierSurface3fa curve3d;
+ TensorLinearCubicBezierSurface2fa curve2d;
+ float eps;
+ const Epilog& epilog;
+ bool isHit;
+
+ __forceinline TensorLinearCubicBezierSurfaceIntersector (const LinearSpace3fa& ray_space, Ray& ray, const TensorLinearCubicBezierSurface3fa& curve3d, const Epilog& epilog)
+ : ray_space(ray_space), ray(ray), curve3d(curve3d), epilog(epilog), isHit(false)
+ {
+ const TensorLinearCubicBezierSurface3fa curve3dray = curve3d.xfm(ray_space,ray.org);
+ curve2d = TensorLinearCubicBezierSurface2fa(CubicBezierCurve2fa(curve3dray.L),CubicBezierCurve2fa(curve3dray.R));
+ const BBox2fa b2 = curve2d.bounds();
+ eps = 8.0f*float(ulp)*reduce_max(max(abs(b2.lower),abs(b2.upper)));
+ }
+
+ __forceinline Interval1f solve_linear(const float u0, const float u1, const float& p0, const float& p1)
+ {
+ if (p1 == p0) {
+ if (p0 == 0.0f) return Interval1f(u0,u1);
+ else return Interval1f(empty);
+ }
+ const float t = -p0/(p1-p0);
+ const float tt = lerp(u0,u1,t);
+ return Interval1f(tt);
+ }
+
+ __forceinline void solve_linear(const float u0, const float u1, const Interval1f& p0, const Interval1f& p1, Interval1f& u)
+ {
+ if (sign(p0.lower) != sign(p0.upper)) u.extend(u0);
+ if (sign(p0.lower) != sign(p1.lower)) u.extend(solve_linear(u0,u1,p0.lower,p1.lower));
+ if (sign(p0.upper) != sign(p1.upper)) u.extend(solve_linear(u0,u1,p0.upper,p1.upper));
+ if (sign(p1.lower) != sign(p1.upper)) u.extend(u1);
+ }
+
+ __forceinline Interval1f bezier_clipping(const CubicBezierCurve<Interval1f>& curve)
+ {
+ Interval1f u = empty;
+ solve_linear(0.0f/3.0f,1.0f/3.0f,curve.v0,curve.v1,u);
+ solve_linear(0.0f/3.0f,2.0f/3.0f,curve.v0,curve.v2,u);
+ solve_linear(0.0f/3.0f,3.0f/3.0f,curve.v0,curve.v3,u);
+ solve_linear(1.0f/3.0f,2.0f/3.0f,curve.v1,curve.v2,u);
+ solve_linear(1.0f/3.0f,3.0f/3.0f,curve.v1,curve.v3,u);
+ solve_linear(2.0f/3.0f,3.0f/3.0f,curve.v2,curve.v3,u);
+ return intersect(u,Interval1f(0.0f,1.0f));
+ }
+
+ __forceinline Interval1f bezier_clipping(const LinearBezierCurve<Interval1f>& curve)
+ {
+ Interval1f v = empty;
+ solve_linear(0.0f,1.0f,curve.v0,curve.v1,v);
+ return intersect(v,Interval1f(0.0f,1.0f));
+ }
+
+ __forceinline void solve_bezier_clipping(BBox1f cu, BBox1f cv, const TensorLinearCubicBezierSurface2fa& curve2)
+ {
+ BBox2fa bounds = curve2.bounds();
+ if (bounds.upper.x < 0.0f) return;
+ if (bounds.upper.y < 0.0f) return;
+ if (bounds.lower.x > 0.0f) return;
+ if (bounds.lower.y > 0.0f) return;
+
+ if (max(cu.size(),cv.size()) < 1E-4f)
+ {
+ const float u = cu.center();
+ const float v = cv.center();
+ TensorLinearCubicBezierSurface1f curve_z = curve3d.xfm(ray_space.row2(),ray.org);
+ const float t = curve_z.eval(u,v);
+ if (ray.tnear() <= t && t <= ray.tfar) {
+ const Vec3fa Ng = cross(curve3d.eval_du(u,v),curve3d.eval_dv(u,v));
+ BezierCurveHit hit(t,u,v,Ng);
+ isHit |= epilog(hit);
+ }
+ return;
+ }
+
+ const Vec2fa dv = curve2.axis_v();
+ const TensorLinearCubicBezierSurface1f curve1v = curve2.xfm(dv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (!curve0v.hasRoot()) return;
+
+ const Interval1f v = bezier_clipping(curve0v);
+ if (isEmpty(v)) return;
+ TensorLinearCubicBezierSurface2fa curve2a = curve2.clip_v(v);
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+
+ const Vec2fa du = curve2.axis_u();
+ const TensorLinearCubicBezierSurface1f curve1u = curve2a.xfm(du);
+ CubicBezierCurve<Interval1f> curve0u = curve1u.reduce_v();
+ int roots = curve0u.maxRoots();
+ if (roots == 0) return;
+
+ if (roots == 1)
+ {
+ const Interval1f u = bezier_clipping(curve0u);
+ if (isEmpty(u)) return;
+ TensorLinearCubicBezierSurface2fa curve2b = curve2a.clip_u(u);
+ cu = BBox1f(lerp(cu.lower,cu.upper,u.lower),lerp(cu.lower,cu.upper,u.upper));
+ solve_bezier_clipping(cu,cv,curve2b);
+ return;
+ }
+
+ TensorLinearCubicBezierSurface2fa curve2l, curve2r;
+ curve2a.split_u(curve2l,curve2r);
+ solve_bezier_clipping(BBox1f(cu.lower,cu.center()),cv,curve2l);
+ solve_bezier_clipping(BBox1f(cu.center(),cu.upper),cv,curve2r);
+ }
+
+ __forceinline bool solve_bezier_clipping()
+ {
+ solve_bezier_clipping(BBox1f(0.0f,1.0f),BBox1f(0.0f,1.0f),curve2d);
+ return isHit;
+ }
+
+ __forceinline void solve_newton_raphson(BBox1f cu, BBox1f cv)
+ {
+ Vec2fa uv(cu.center(),cv.center());
+ const Vec2fa dfdu = curve2d.eval_du(uv.x,uv.y);
+ const Vec2fa dfdv = curve2d.eval_dv(uv.x,uv.y);
+ const LinearSpace2fa rcp_J = rcp(LinearSpace2fa(dfdu,dfdv));
+ solve_newton_raphson_loop(cu,cv,uv,dfdu,dfdv,rcp_J);
+ }
+
+ __forceinline void solve_newton_raphson_loop(BBox1f cu, BBox1f cv, const Vec2fa& uv_in, const Vec2fa& dfdu, const Vec2fa& dfdv, const LinearSpace2fa& rcp_J)
+ {
+ Vec2fa uv = uv_in;
+
+ for (size_t i=0; i<200; i++)
+ {
+ const Vec2fa f = curve2d.eval(uv.x,uv.y);
+ const Vec2fa duv = rcp_J*f;
+ uv -= duv;
+
+ if (max(abs(f.x),abs(f.y)) < eps)
+ {
+ const float u = uv.x;
+ const float v = uv.y;
+ if (!(u >= 0.0f && u <= 1.0f)) return; // rejects NaNs
+ if (!(v >= 0.0f && v <= 1.0f)) return; // rejects NaNs
+ const TensorLinearCubicBezierSurface1f curve_z = curve3d.xfm(ray_space.row2(),ray.org);
+ const float t = curve_z.eval(u,v);
+ if (!(ray.tnear() <= t && t <= ray.tfar)) return; // rejects NaNs
+ const Vec3fa Ng = cross(curve3d.eval_du(u,v),curve3d.eval_dv(u,v));
+ BezierCurveHit hit(t,u,v,Ng);
+ isHit |= epilog(hit);
+ return;
+ }
+ }
+ }
+
+ __forceinline bool clip_v(BBox1f& cu, BBox1f& cv)
+ {
+ const Vec2fa dv = curve2d.eval_dv(cu.lower,cv.lower);
+ const TensorLinearCubicBezierSurface1f curve1v = curve2d.xfm(dv).clip(cu,cv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (!curve0v.hasRoot()) return false;
+ Interval1f v = bezier_clipping(curve0v);
+ if (isEmpty(v)) return false;
+ v = intersect(v + Interval1f(-0.1f,+0.1f),Interval1f(0.0f,1.0f));
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+ return true;
+ }
+
+ __forceinline bool solve_krawczyk(bool very_small, BBox1f& cu, BBox1f& cv)
+ {
+ /* perform bezier clipping in v-direction to get tight v-bounds */
+ TensorLinearCubicBezierSurface2fa curve2 = curve2d.clip(cu,cv);
+ const Vec2fa dv = curve2.axis_v();
+ const TensorLinearCubicBezierSurface1f curve1v = curve2.xfm(dv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (unlikely(!curve0v.hasRoot())) return true;
+ Interval1f v = bezier_clipping(curve0v);
+ if (unlikely(isEmpty(v))) return true;
+ v = intersect(v + Interval1f(-0.1f,+0.1f),Interval1f(0.0f,1.0f));
+ curve2 = curve2.clip_v(v);
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+
+ /* perform one newton raphson iteration */
+ Vec2fa c(cu.center(),cv.center());
+ Vec2fa f,dfdu,dfdv; curve2d.eval(c.x,c.y,f,dfdu,dfdv);
+ const LinearSpace2fa rcp_J = rcp(LinearSpace2fa(dfdu,dfdv));
+ const Vec2fa c1 = c - rcp_J*f;
+
+ /* calculate bounds of derivatives */
+ const BBox2fa bounds_du = (1.0f/cu.size())*curve2.derivative_u().bounds();
+ const BBox2fa bounds_dv = (1.0f/cv.size())*curve2.derivative_v().bounds();
+
+ /* calculate krawczyk test */
+ LinearSpace2<Vec2<Interval1f>> I(Interval1f(1.0f), Interval1f(0.0f),
+ Interval1f(0.0f), Interval1f(1.0f));
+
+ LinearSpace2<Vec2<Interval1f>> G(Interval1f(bounds_du.lower.x,bounds_du.upper.x), Interval1f(bounds_dv.lower.x,bounds_dv.upper.x),
+ Interval1f(bounds_du.lower.y,bounds_du.upper.y), Interval1f(bounds_dv.lower.y,bounds_dv.upper.y));
+
+ const LinearSpace2<Vec2f> rcp_J2(rcp_J);
+ const LinearSpace2<Vec2<Interval1f>> rcp_Ji(rcp_J2);
+
+ const Vec2<Interval1f> x(cu,cv);
+ const Vec2<Interval1f> K = Vec2<Interval1f>(Vec2f(c1)) + (I - rcp_Ji*G)*(x-Vec2<Interval1f>(Vec2f(c)));
+
+ /* test if there is no solution */
+ const Vec2<Interval1f> KK = intersect(K,x);
+ if (unlikely(isEmpty(KK.x) || isEmpty(KK.y))) return true;
+
+ /* exit if convergence cannot get proven, but terminate if we are very small */
+ if (unlikely(!subset(K,x) && !very_small)) return false;
+
+ /* solve using newton raphson iteration of convergence is guarenteed */
+ solve_newton_raphson_loop(cu,cv,c1,dfdu,dfdv,rcp_J);
+ return true;
+ }
+
+ __forceinline void solve_newton_raphson_no_recursion(BBox1f cu, BBox1f cv)
+ {
+ if (!clip_v(cu,cv)) return;
+ return solve_newton_raphson(cu,cv);
+ }
+
+ __forceinline void solve_newton_raphson_recursion(BBox1f cu, BBox1f cv)
+ {
+ unsigned int sptr = 0;
+ const unsigned int stack_size = 4;
+ unsigned int mask_stack[stack_size];
+ BBox1f cu_stack[stack_size];
+ BBox1f cv_stack[stack_size];
+ goto entry;
+
+ /* terminate if stack is empty */
+ while (sptr)
+ {
+ /* pop from stack */
+ {
+ sptr--;
+ size_t mask = mask_stack[sptr];
+ cu = cu_stack[sptr];
+ cv = cv_stack[sptr];
+ const size_t i = bscf(mask);
+ mask_stack[sptr] = mask;
+ if (mask) sptr++; // there are still items on the stack
+
+ /* process next element recurse into each hit curve segment */
+ const float u0 = float(i+0)*(1.0f/(VSIZEX-1));
+ const float u1 = float(i+1)*(1.0f/(VSIZEX-1));
+ const BBox1f cui(lerp(cu.lower,cu.upper,u0),lerp(cu.lower,cu.upper,u1));
+ cu = cui;
+ }
+
+#if 0
+ solve_newton_raphson_no_recursion(cu,cv);
+ continue;
+
+#else
+ /* we assume convergence for small u ranges and verify using krawczyk */
+ if (cu.size() < 1.0f/6.0f) {
+ const bool very_small = cu.size() < 0.001f || sptr >= stack_size;
+ if (solve_krawczyk(very_small,cu,cv)) {
+ continue;
+ }
+ }
+#endif
+
+ entry:
+
+ /* split the curve into VSIZEX-1 segments in u-direction */
+ vboolx valid = true;
+ TensorLinearCubicBezierSurface<Vec2vfx> subcurves = curve2d.clip_v(cv).vsplit_u(valid,cu);
+
+ /* slabs test in u-direction */
+ Vec2vfx ndv = cross(subcurves.axis_v());
+ BBox<vfloatx> boundsv = subcurves.vxfm(ndv).bounds();
+ valid &= boundsv.lower <= eps;
+ valid &= boundsv.upper >= -eps;
+ if (none(valid)) continue;
+
+ /* slabs test in v-direction */
+ Vec2vfx ndu = cross(subcurves.axis_u());
+ BBox<vfloatx> boundsu = subcurves.vxfm(ndu).bounds();
+ valid &= boundsu.lower <= eps;
+ valid &= boundsu.upper >= -eps;
+ if (none(valid)) continue;
+
+ /* push valid segments to stack */
+ assert(sptr < stack_size);
+ mask_stack [sptr] = movemask(valid);
+ cu_stack [sptr] = cu;
+ cv_stack [sptr] = cv;
+ sptr++;
+ }
+ }
+
+ __forceinline bool solve_newton_raphson_main()
+ {
+ BBox1f vu(0.0f,1.0f);
+ BBox1f vv(0.0f,1.0f);
+ solve_newton_raphson_recursion(vu,vv);
+ return isHit;
+ }
+ };
+
+
+ template<template<typename Ty> class SourceCurve>
+ struct OrientedCurve1Intersector1
+ {
+ //template<typename Ty> using Curve = SourceCurve<Ty>;
+ typedef SourceCurve<Vec3ff> SourceCurve3ff;
+ typedef SourceCurve<Vec3fa> SourceCurve3fa;
+
+ __forceinline OrientedCurve1Intersector1() {}
+
+ __forceinline OrientedCurve1Intersector1(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i,
+ const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i,
+ const Epilog& epilog) const
+ {
+ STAT3(normal.trav_prims,1,1,1);
+
+ SourceCurve3ff ccurve(v0i,v1i,v2i,v3i);
+ SourceCurve3fa ncurve(n0i,n1i,n2i,n3i);
+ ccurve = enlargeRadiusToMinWidth(context,geom,ray.org,ccurve);
+ TensorLinearCubicBezierSurface3fa curve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main();
+ }
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const TensorLinearCubicBezierSurface3fa& curve, const Epilog& epilog) const
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main();
+ }
+ };
+
+ template<template<typename Ty> class SourceCurve, int K>
+ struct OrientedCurve1IntersectorK
+ {
+ //template<typename Ty> using Curve = SourceCurve<Ty>;
+ typedef SourceCurve<Vec3ff> SourceCurve3ff;
+ typedef SourceCurve<Vec3fa> SourceCurve3fa;
+
+ struct Ray1
+ {
+ __forceinline Ray1(RayK<K>& ray, size_t k)
+ : org(ray.org.x[k],ray.org.y[k],ray.org.z[k]), dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]), _tnear(ray.tnear()[k]), tfar(ray.tfar[k]) {}
+
+ Vec3fa org;
+ Vec3fa dir;
+ float _tnear;
+ float& tfar;
+
+ __forceinline float& tnear() { return _tnear; }
+ //__forceinline float& tfar() { return _tfar; }
+ __forceinline const float& tnear() const { return _tnear; }
+ //__forceinline const float& tfar() const { return _tfar; }
+ };
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i,
+ const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+ SourceCurve3ff ccurve(v0i,v1i,v2i,v3i);
+ SourceCurve3fa ncurve(n0i,n1i,n2i,n3i);
+ ccurve = enlargeRadiusToMinWidth(context,geom,ray.org,ccurve);
+ TensorLinearCubicBezierSurface3fa curve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_newton_raphson_main();
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const TensorLinearCubicBezierSurface3fa& curve,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_newton_raphson_main();
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_precalculations.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_precalculations.h
new file mode 100644
index 0000000000..6e9fc91925
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_precalculations.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/geometry.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct CurvePrecalculations1
+ {
+ float depth_scale;
+ LinearSpace3fa ray_space;
+
+ __forceinline CurvePrecalculations1() {}
+
+ __forceinline CurvePrecalculations1(const Ray& ray, const void* ptr)
+ {
+ depth_scale = rsqrt(dot(ray.dir,ray.dir));
+ LinearSpace3fa space = frame(depth_scale*ray.dir);
+ space.vz *= depth_scale;
+ ray_space = space.transposed();
+ }
+ };
+
+ template<int K>
+ struct CurvePrecalculationsK
+ {
+ vfloat<K> depth_scale;
+ LinearSpace3fa ray_space[K];
+
+ __forceinline CurvePrecalculationsK(const vbool<K>& valid, const RayK<K>& ray)
+ {
+ size_t mask = movemask(valid);
+ depth_scale = rsqrt(dot(ray.dir,ray.dir));
+ while (mask) {
+ size_t k = bscf(mask);
+ Vec3fa ray_dir_k = Vec3fa(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ LinearSpace3fa ray_space_k = frame(depth_scale[k]*ray_dir_k);
+ ray_space_k.vz *= depth_scale[k];
+ ray_space[k] = ray_space_k.transposed();
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_ribbon.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_ribbon.h
new file mode 100644
index 0000000000..a99cf99d56
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_ribbon.h
@@ -0,0 +1,214 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "quad_intersector.h"
+#include "curve_intersector_precalculations.h"
+
+#define Bezier1Intersector1 RibbonCurve1Intersector1
+#define Bezier1IntersectorK RibbonCurve1IntersectorK
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename NativeCurve3ff, int M>
+ struct RibbonHit
+ {
+ __forceinline RibbonHit() {}
+
+ __forceinline RibbonHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N,
+ const NativeCurve3ff& curve3D)
+ : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {}
+
+ __forceinline void finalize()
+ {
+ vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N));
+ vv = V;
+ vt = T;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const {
+ return curve3D.eval_du(vu[i]);
+ }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ int i, N;
+ NativeCurve3ff curve3D;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ };
+
+ /* calculate squared distance of point p0 to line p1->p2 */
+ __forceinline std::pair<vfloatx,vfloatx> sqr_point_line_distance(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2)
+ {
+ const vfloatx num = det(p2-p1,p1-p0);
+ const vfloatx den2 = dot(p2-p1,p2-p1);
+ return std::make_pair(num*num,den2);
+ }
+
+ /* performs culling against a cylinder */
+ __forceinline vboolx cylinder_culling_test(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2, const vfloatx& r)
+ {
+ const std::pair<vfloatx,vfloatx> d = sqr_point_line_distance(p0,p1,p2);
+ return d.first <= r*r*d.second;
+ }
+
+ template<typename NativeCurve3ff, typename Epilog>
+ __forceinline bool intersect_ribbon(const Vec3fa& ray_org, const Vec3fa& ray_dir, const float ray_tnear, const float& ray_tfar,
+ const LinearSpace3fa& ray_space, const float& depth_scale,
+ const NativeCurve3ff& curve3D, const int N,
+ const Epilog& epilog)
+ {
+ /* transform control points into ray space */
+ const NativeCurve3ff curve2D = curve3D.xfm_pr(ray_space,ray_org);
+ float eps = 4.0f*float(ulp)*reduce_max(max(abs(curve2D.v0),abs(curve2D.v1),abs(curve2D.v2),abs(curve2D.v3)));
+
+ /* evaluate the bezier curve */
+ bool ishit = false;
+ vboolx valid = vfloatx(step) < vfloatx(float(N));
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N);
+ valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
+
+ if (any(valid))
+ {
+ Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(0,N);
+ Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(0,N);
+ dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
+ dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
+ const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
+ const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
+ const Vec3vfx nn0 = normalize(n0);
+ const Vec3vfx nn1 = normalize(n1);
+ const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
+ const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
+
+ vfloatx vu,vv,vt;
+ vboolx valid0 = intersect_quad_backface_culling(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
+
+ if (any(valid0))
+ {
+ /* ignore self intersections */
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
+ vfloatx r = lerp(p0.w, p1.w, vu);
+ valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
+ }
+
+ if (any(valid0))
+ {
+ vv = madd(2.0f,vv,vfloatx(-1.0f));
+ RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,0,N,curve3D);
+ ishit |= epilog(bhit.valid,bhit);
+ }
+ }
+ }
+
+ if (unlikely(VSIZEX < N))
+ {
+ /* process SIMD-size many segments per iteration */
+ for (int i=VSIZEX; i<N; i+=VSIZEX)
+ {
+ /* evaluate the bezier curve */
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N);
+ valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
+ if (none(valid)) continue;
+
+ Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(i,N);
+ Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(i,N);
+ dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
+ dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
+ const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
+ const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
+ const Vec3vfx nn0 = normalize(n0);
+ const Vec3vfx nn1 = normalize(n1);
+ const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
+ const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
+
+ vfloatx vu,vv,vt;
+ vboolx valid0 = intersect_quad_backface_culling(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
+
+ if (any(valid0))
+ {
+ /* ignore self intersections */
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
+ vfloatx r = lerp(p0.w, p1.w, vu);
+ valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
+ }
+
+ if (any(valid0))
+ {
+ vv = madd(2.0f,vv,vfloatx(-1.0f));
+ RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,i,N,curve3D);
+ ishit |= epilog(bhit.valid,bhit);
+ }
+ }
+ }
+ }
+ return ishit;
+ }
+
+ template<template<typename Ty> class NativeCurve>
+ struct RibbonCurve1Intersector1
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+ NativeCurve3ff curve(v0,v1,v2,v3);
+ curve = enlargeRadiusToMinWidth(context,geom,ray.org,curve);
+ return intersect_ribbon<NativeCurve3ff>(ray.org,ray.dir,ray.tnear(),ray.tfar,
+ pre.ray_space,pre.depth_scale,
+ curve,N,
+ epilog);
+ }
+ };
+
+ template<template<typename Ty> class NativeCurve, int K>
+ struct RibbonCurve1IntersectorK
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ NativeCurve3ff curve(v0,v1,v2,v3);
+ curve = enlargeRadiusToMinWidth(context,geom,ray_org,curve);
+ return intersect_ribbon<NativeCurve3ff>(ray_org,ray_dir,ray.tnear()[k],ray.tfar[k],
+ pre.ray_space[k],pre.depth_scale[k],
+ curve,N,
+ epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_sweep.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_sweep.h
new file mode 100644
index 0000000000..883cedc3d2
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_sweep.h
@@ -0,0 +1,362 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "cylinder.h"
+#include "plane.h"
+#include "line_intersector.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ static const size_t numJacobianIterations = 5;
+#if defined(__AVX__)
+ static const size_t numBezierSubdivisions = 2;
+#else
+ static const size_t numBezierSubdivisions = 3;
+#endif
+
+ struct BezierCurveHit
+ {
+ __forceinline BezierCurveHit() {}
+
+ __forceinline BezierCurveHit(const float t, const float u, const Vec3fa& Ng)
+ : t(t), u(u), v(0.0f), Ng(Ng) {}
+
+ __forceinline BezierCurveHit(const float t, const float u, const float v, const Vec3fa& Ng)
+ : t(t), u(u), v(v), Ng(Ng) {}
+
+ __forceinline void finalize() {}
+
+ public:
+ float t;
+ float u;
+ float v;
+ Vec3fa Ng;
+ };
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ __forceinline bool intersect_bezier_iterative_debug(const Ray& ray, const float dt, const NativeCurve3ff& curve, size_t i,
+ const vfloatx& u, const BBox<vfloatx>& tp, const BBox<vfloatx>& h0, const BBox<vfloatx>& h1,
+ const Vec3vfx& Ng, const Vec4vfx& dP0du, const Vec4vfx& dP3du,
+ const Epilog& epilog)
+ {
+ if (tp.lower[i]+dt > ray.tfar) return false;
+ Vec3fa Ng_o = Vec3fa(Ng.x[i],Ng.y[i],Ng.z[i]);
+ if (h0.lower[i] == tp.lower[i]) Ng_o = -Vec3fa(dP0du.x[i],dP0du.y[i],dP0du.z[i]);
+ if (h1.lower[i] == tp.lower[i]) Ng_o = +Vec3fa(dP3du.x[i],dP3du.y[i],dP3du.z[i]);
+ BezierCurveHit hit(tp.lower[i]+dt,u[i],Ng_o);
+ return epilog(hit);
+ }
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ __forceinline bool intersect_bezier_iterative_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, float u, float t, const Epilog& epilog)
+ {
+ const Vec3fa org = zero;
+ const Vec3fa dir = ray.dir;
+ const float length_ray_dir = length(dir);
+
+ /* error of curve evaluations is propertional to largest coordinate */
+ const BBox3ff box = curve.bounds();
+ const float P_err = 16.0f*float(ulp)*reduce_max(max(abs(box.lower),abs(box.upper)));
+
+ for (size_t i=0; i<numJacobianIterations; i++)
+ {
+ const Vec3fa Q = madd(Vec3fa(t),dir,org);
+ //const Vec3fa dQdu = zero;
+ const Vec3fa dQdt = dir;
+ const float Q_err = 16.0f*float(ulp)*length_ray_dir*t; // works as org=zero here
+
+ Vec3ff P,dPdu,ddPdu; curve.eval(u,P,dPdu,ddPdu);
+ //const Vec3fa dPdt = zero;
+
+ const Vec3fa R = Q-P;
+ const float len_R = length(R); //reduce_max(abs(R));
+ const float R_err = max(Q_err,P_err);
+ const Vec3fa dRdu = /*dQdu*/-dPdu;
+ const Vec3fa dRdt = dQdt;//-dPdt;
+
+ const Vec3fa T = normalize(dPdu);
+ const Vec3fa dTdu = dnormalize(dPdu,ddPdu);
+ //const Vec3fa dTdt = zero;
+ const float cos_err = P_err/length(dPdu);
+
+ /* Error estimate for dot(R,T):
+
+ dot(R,T) = cos(R,T) |R| |T|
+ = (cos(R,T) +- cos_error) * (|R| +- |R|_err) * (|T| +- |T|_err)
+ = cos(R,T)*|R|*|T|
+ +- cos(R,T)*(|R|*|T|_err + |T|*|R|_err)
+ +- cos_error*(|R| + |T|)
+ +- lower order terms
+ with cos(R,T) being in [0,1] and |T| = 1 we get:
+ dot(R,T)_err = |R|*|T|_err + |R|_err = cos_error*(|R|+1)
+ */
+
+ const float f = dot(R,T);
+ const float f_err = len_R*P_err + R_err + cos_err*(1.0f+len_R);
+ const float dfdu = dot(dRdu,T) + dot(R,dTdu);
+ const float dfdt = dot(dRdt,T);// + dot(R,dTdt);
+
+ const float K = dot(R,R)-sqr(f);
+ const float dKdu = /*2.0f*/(dot(R,dRdu)-f*dfdu);
+ const float dKdt = /*2.0f*/(dot(R,dRdt)-f*dfdt);
+ const float rsqrt_K = rsqrt(K);
+
+ const float g = sqrt(K)-P.w;
+ const float g_err = R_err + f_err + 16.0f*float(ulp)*box.upper.w;
+ const float dgdu = /*0.5f*/dKdu*rsqrt_K-dPdu.w;
+ const float dgdt = /*0.5f*/dKdt*rsqrt_K;//-dPdt.w;
+
+ const LinearSpace2f J = LinearSpace2f(dfdu,dfdt,dgdu,dgdt);
+ const Vec2f dut = rcp(J)*Vec2f(f,g);
+ const Vec2f ut = Vec2f(u,t) - dut;
+ u = ut.x; t = ut.y;
+
+ if (abs(f) < f_err && abs(g) < g_err)
+ {
+ t+=dt;
+ if (!(ray.tnear() <= t && t <= ray.tfar)) return false; // rejects NaNs
+ if (!(u >= 0.0f && u <= 1.0f)) return false; // rejects NaNs
+ const Vec3fa R = normalize(Q-P);
+ const Vec3fa U = madd(Vec3fa(dPdu.w),R,dPdu);
+ const Vec3fa V = cross(dPdu,R);
+ BezierCurveHit hit(t,u,cross(V,U));
+ return epilog(hit);
+ }
+ }
+ return false;
+ }
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve,
+ float u0, float u1, unsigned int depth, const Epilog& epilog)
+ {
+#if defined(__AVX__)
+ typedef vbool8 vboolx; // maximally 8-wide to work around KNL issues
+ typedef vint8 vintx;
+ typedef vfloat8 vfloatx;
+#else
+ typedef vbool4 vboolx;
+ typedef vint4 vintx;
+ typedef vfloat4 vfloatx;
+#endif
+ typedef Vec3<vfloatx> Vec3vfx;
+ typedef Vec4<vfloatx> Vec4vfx;
+
+ unsigned int maxDepth = numBezierSubdivisions;
+ bool found = false;
+ const Vec3fa org = zero;
+ const Vec3fa dir = ray.dir;
+
+ unsigned int sptr = 0;
+ const unsigned int stack_size = numBezierSubdivisions+1; // +1 because of unstable workaround below
+ struct StackEntry {
+ vboolx valid;
+ vfloatx tlower;
+ float u0;
+ float u1;
+ unsigned int depth;
+ };
+ StackEntry stack[stack_size];
+ goto entry;
+
+ /* terminate if stack is empty */
+ while (sptr)
+ {
+ /* pop from stack */
+ {
+ sptr--;
+ vboolx valid = stack[sptr].valid;
+ const vfloatx tlower = stack[sptr].tlower;
+ valid &= tlower+dt <= ray.tfar;
+ if (none(valid)) continue;
+ u0 = stack[sptr].u0;
+ u1 = stack[sptr].u1;
+ depth = stack[sptr].depth;
+ const size_t i = select_min(valid,tlower); clear(valid,i);
+ stack[sptr].valid = valid;
+ if (any(valid)) sptr++; // there are still items on the stack
+
+ /* process next segment */
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
+ u0 = vu0[i+0];
+ u1 = vu0[i+1];
+ }
+ entry:
+
+ /* subdivide curve */
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(vfloatx::size-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
+ Vec4vfx P0, dP0du; curve.veval(vu0,P0,dP0du); dP0du = dP0du * Vec4vfx(dscale);
+ const Vec4vfx P3 = shift_right_1(P0);
+ const Vec4vfx dP3du = shift_right_1(dP0du);
+ const Vec4vfx P1 = P0 + dP0du;
+ const Vec4vfx P2 = P3 - dP3du;
+
+ /* calculate bounding cylinders */
+ const vfloatx rr1 = sqr_point_to_line_distance(Vec3vfx(dP0du),Vec3vfx(P3-P0));
+ const vfloatx rr2 = sqr_point_to_line_distance(Vec3vfx(dP3du),Vec3vfx(P3-P0));
+ const vfloatx maxr12 = sqrt(max(rr1,rr2));
+ const vfloatx one_plus_ulp = 1.0f+2.0f*float(ulp);
+ const vfloatx one_minus_ulp = 1.0f-2.0f*float(ulp);
+ vfloatx r_outer = max(P0.w,P1.w,P2.w,P3.w)+maxr12;
+ vfloatx r_inner = min(P0.w,P1.w,P2.w,P3.w)-maxr12;
+ r_outer = one_plus_ulp*r_outer;
+ r_inner = max(0.0f,one_minus_ulp*r_inner);
+ const CylinderN<vfloatx::size> cylinder_outer(Vec3vfx(P0),Vec3vfx(P3),r_outer);
+ const CylinderN<vfloatx::size> cylinder_inner(Vec3vfx(P0),Vec3vfx(P3),r_inner);
+ vboolx valid = true; clear(valid,vfloatx::size-1);
+
+ /* intersect with outer cylinder */
+ BBox<vfloatx> tc_outer; vfloatx u_outer0; Vec3vfx Ng_outer0; vfloatx u_outer1; Vec3vfx Ng_outer1;
+ valid &= cylinder_outer.intersect(org,dir,tc_outer,u_outer0,Ng_outer0,u_outer1,Ng_outer1);
+ if (none(valid)) continue;
+
+ /* intersect with cap-planes */
+ BBox<vfloatx> tp(ray.tnear()-dt,ray.tfar-dt);
+ tp = embree::intersect(tp,tc_outer);
+ BBox<vfloatx> h0 = HalfPlaneN<vfloatx::size>(Vec3vfx(P0),+Vec3vfx(dP0du)).intersect(org,dir);
+ tp = embree::intersect(tp,h0);
+ BBox<vfloatx> h1 = HalfPlaneN<vfloatx::size>(Vec3vfx(P3),-Vec3vfx(dP3du)).intersect(org,dir);
+ tp = embree::intersect(tp,h1);
+ valid &= tp.lower <= tp.upper;
+ if (none(valid)) continue;
+
+ /* clamp and correct u parameter */
+ u_outer0 = clamp(u_outer0,vfloatx(0.0f),vfloatx(1.0f));
+ u_outer1 = clamp(u_outer1,vfloatx(0.0f),vfloatx(1.0f));
+ u_outer0 = lerp(u0,u1,(vfloatx(step)+u_outer0)*(1.0f/float(vfloatx::size)));
+ u_outer1 = lerp(u0,u1,(vfloatx(step)+u_outer1)*(1.0f/float(vfloatx::size)));
+
+ /* intersect with inner cylinder */
+ BBox<vfloatx> tc_inner;
+ vfloatx u_inner0 = zero; Vec3vfx Ng_inner0 = zero; vfloatx u_inner1 = zero; Vec3vfx Ng_inner1 = zero;
+ const vboolx valid_inner = cylinder_inner.intersect(org,dir,tc_inner,u_inner0,Ng_inner0,u_inner1,Ng_inner1);
+
+ /* at the unstable area we subdivide deeper */
+ const vboolx unstable0 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner0)) < 0.3f);
+ const vboolx unstable1 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner1)) < 0.3f);
+
+ /* subtract the inner interval from the current hit interval */
+ BBox<vfloatx> tp0, tp1;
+ subtract(tp,tc_inner,tp0,tp1);
+ vboolx valid0 = valid & (tp0.lower <= tp0.upper);
+ vboolx valid1 = valid & (tp1.lower <= tp1.upper);
+ if (none(valid0 | valid1)) continue;
+
+ /* iterate over all first hits front to back */
+ const vintx termDepth0 = select(unstable0,vintx(maxDepth+1),vintx(maxDepth));
+ vboolx recursion_valid0 = valid0 & (depth < termDepth0);
+ valid0 &= depth >= termDepth0;
+
+ while (any(valid0))
+ {
+ const size_t i = select_min(valid0,tp0.lower); clear(valid0,i);
+ found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer0[i],tp0.lower[i],epilog);
+ //found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer0,tp0,h0,h1,Ng_outer0,dP0du,dP3du,epilog);
+ valid0 &= tp0.lower+dt <= ray.tfar;
+ }
+ valid1 &= tp1.lower+dt <= ray.tfar;
+
+ /* iterate over all second hits front to back */
+ const vintx termDepth1 = select(unstable1,vintx(maxDepth+1),vintx(maxDepth));
+ vboolx recursion_valid1 = valid1 & (depth < termDepth1);
+ valid1 &= depth >= termDepth1;
+ while (any(valid1))
+ {
+ const size_t i = select_min(valid1,tp1.lower); clear(valid1,i);
+ found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer1[i],tp1.upper[i],epilog);
+ //found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer1,tp1,h0,h1,Ng_outer1,dP0du,dP3du,epilog);
+ valid1 &= tp1.lower+dt <= ray.tfar;
+ }
+
+ /* push valid segments to stack */
+ recursion_valid0 &= tp0.lower+dt <= ray.tfar;
+ recursion_valid1 &= tp1.lower+dt <= ray.tfar;
+ const vboolx recursion_valid = recursion_valid0 | recursion_valid1;
+ if (any(recursion_valid))
+ {
+ assert(sptr < stack_size);
+ stack[sptr].valid = recursion_valid;
+ stack[sptr].tlower = select(recursion_valid0,tp0.lower,tp1.lower);
+ stack[sptr].u0 = u0;
+ stack[sptr].u1 = u1;
+ stack[sptr].depth = depth+1;
+ sptr++;
+ }
+ }
+ return found;
+ }
+
+ template<template<typename Ty> class NativeCurve>
+ struct SweepCurve1Intersector1
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+
+ /* move ray closer to make intersection stable */
+ NativeCurve3ff curve0(v0,v1,v2,v3);
+ curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
+ const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
+ const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
+ const NativeCurve3ff curve1 = curve0-ref;
+ return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog);
+ }
+ };
+
+ template<template<typename Ty> class NativeCurve, int K>
+ struct SweepCurve1IntersectorK
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ struct Ray1
+ {
+ __forceinline Ray1(RayK<K>& ray, size_t k)
+ : org(ray.org.x[k],ray.org.y[k],ray.org.z[k]), dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]), _tnear(ray.tnear()[k]), tfar(ray.tfar[k]) {}
+
+ Vec3fa org;
+ Vec3fa dir;
+ float _tnear;
+ float& tfar;
+
+ __forceinline float& tnear() { return _tnear; }
+ //__forceinline float& tfar() { return _tfar; }
+ __forceinline const float& tnear() const { return _tnear; }
+ //__forceinline const float& tfar() const { return _tfar; }
+
+ };
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+
+ /* move ray closer to make intersection stable */
+ NativeCurve3ff curve0(v0,v1,v2,v3);
+ curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
+ const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
+ const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
+ const NativeCurve3ff curve1 = curve0-ref;
+ return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual.h
new file mode 100644
index 0000000000..e1f4238130
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual.h
@@ -0,0 +1,671 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../subdiv/bezier_curve.h"
+#include "../common/primref.h"
+#include "curve_intersector_precalculations.h"
+#include "../bvh/node_intersector1.h"
+#include "../bvh/node_intersector_packet.h"
+
+#include "intersector_epilog.h"
+
+#include "../subdiv/bezier_curve.h"
+#include "../subdiv/bspline_curve.h"
+#include "../subdiv/hermite_curve.h"
+#include "../subdiv/catmullrom_curve.h"
+
+#include "spherei_intersector.h"
+#include "disci_intersector.h"
+
+#include "linei_intersector.h"
+#include "roundlinei_intersector.h"
+#include "conelinei_intersector.h"
+
+#include "curveNi_intersector.h"
+#include "curveNv_intersector.h"
+#include "curveNi_mb_intersector.h"
+
+#include "curve_intersector_distance.h"
+#include "curve_intersector_ribbon.h"
+#include "curve_intersector_oriented.h"
+#include "curve_intersector_sweep.h"
+
+namespace embree
+{
+ struct VirtualCurveIntersector
+ {
+ typedef void (*Intersect1Ty)(void* pre, void* ray, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded1Ty )(void* pre, void* ray, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect4Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded4Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect8Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded8Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect16Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded16Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ public:
+ struct Intersectors
+ {
+ Intersectors() {} // WARNING: Do not zero initialize this, as we otherwise get problems with thread unsafe local static variable initialization (e.g. on VS2013) in curve_intersector_virtual.cpp.
+
+ template<int K> void intersect(void* pre, void* ray, IntersectContext* context, const void* primitive);
+ template<int K> bool occluded (void* pre, void* ray, IntersectContext* context, const void* primitive);
+
+ template<int K> void intersect(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ template<int K> bool occluded (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ public:
+ Intersect1Ty intersect1;
+ Occluded1Ty occluded1;
+ Intersect4Ty intersect4;
+ Occluded4Ty occluded4;
+ Intersect8Ty intersect8;
+ Occluded8Ty occluded8;
+ Intersect16Ty intersect16;
+ Occluded16Ty occluded16;
+ };
+
+ Intersectors vtbl[Geometry::GTY_END];
+ };
+
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(intersect1); intersect1(pre,ray,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(occluded1); return occluded1(pre,ray,context,primitive); }
+
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<4>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect4); intersect4(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<4> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded4); return occluded4(pre,ray,k,context,primitive); }
+
+#if defined(__AVX__)
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<8>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect8); intersect8(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<8> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded8); return occluded8(pre,ray,k,context,primitive); }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<16>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect16); intersect16(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<16> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded16); return occluded16(pre,ray,k,context,primitive); }
+#endif
+
+ namespace isa
+ {
+ struct VirtualCurveIntersector1
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<1>(&pre,&ray,context,prim);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<1>(&pre,&ray,context,prim);
+ }
+ };
+
+ template<int K>
+ struct VirtualCurveIntersectorK
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ size_t mask = movemask(valid_i);
+ while (mask) leafIntersector.intersect<K>(&pre,&ray,bscf(mask),context,prim);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ vbool<K> valid_o = false;
+ size_t mask = movemask(valid_i);
+ while (mask) {
+ size_t k = bscf(mask);
+ if (leafIntersector.occluded<K>(&pre,&ray,k,context,prim))
+ set(valid_o, k);
+ }
+ return valid_o;
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<K>(&pre,&ray,k,context,prim);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<K>(&pre,&ray,k,context,prim);
+ }
+ };
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRoundConeNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &RoundLinearCurveMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &RoundLinearCurveMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &RoundLinearCurveMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &RoundLinearCurveMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&RoundLinearCurveMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &RoundLinearCurveMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&RoundLinearCurveMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &RoundLinearCurveMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearConeNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &ConeCurveMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &ConeCurveMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &ConeCurveMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &ConeCurveMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&ConeCurveMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &ConeCurveMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&ConeCurveMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &ConeCurveMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRoundConeNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &RoundLinearCurveMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &RoundLinearCurveMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &RoundLinearCurveMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &RoundLinearCurveMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&RoundLinearCurveMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &RoundLinearCurveMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&RoundLinearCurveMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &RoundLinearCurveMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearConeNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &ConeCurveMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &ConeCurveMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &ConeCurveMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &ConeCurveMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&ConeCurveMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &ConeCurveMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&ConeCurveMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &ConeCurveMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &FlatLinearCurveMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &FlatLinearCurveMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &FlatLinearCurveMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &FlatLinearCurveMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&FlatLinearCurveMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &FlatLinearCurveMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&FlatLinearCurveMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &FlatLinearCurveMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &FlatLinearCurveMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &FlatLinearCurveMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &FlatLinearCurveMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &FlatLinearCurveMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&FlatLinearCurveMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &FlatLinearCurveMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&FlatLinearCurveMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &FlatLinearCurveMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors SphereNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &SphereMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &SphereMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &SphereMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &SphereMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&SphereMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &SphereMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&SphereMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &SphereMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors SphereNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &SphereMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &SphereMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &SphereMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &SphereMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&SphereMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &SphereMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&SphereMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &SphereMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors DiscNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &DiscMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &DiscMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &DiscMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &DiscMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&DiscMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &DiscMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&DiscMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &DiscMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors DiscNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &DiscMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &DiscMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &DiscMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &DiscMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&DiscMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &DiscMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&DiscMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &DiscMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors OrientedDiscNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &OrientedDiscMiIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &OrientedDiscMiIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &OrientedDiscMiIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &OrientedDiscMiIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&OrientedDiscMiIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &OrientedDiscMiIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&OrientedDiscMiIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &OrientedDiscMiIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors OrientedDiscNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &OrientedDiscMiMBIntersector1<N,N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &OrientedDiscMiMBIntersector1<N,N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &OrientedDiscMiMBIntersectorK<N,N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &OrientedDiscMiMBIntersectorK<N,N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&OrientedDiscMiMBIntersectorK<N,N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &OrientedDiscMiMBIntersectorK<N,N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&OrientedDiscMiMBIntersectorK<N,N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &OrientedDiscMiMBIntersectorK<N,N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNiIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNvIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNvIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNvIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNvIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNvIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNvIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNvIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNvIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNvIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNiMBIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNvIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNvIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNvIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNvIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNvIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNvIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNvIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNvIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNvIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors OrientedCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_n<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_n <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_n<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_n <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_n<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_n <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_n<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_n <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors OrientedCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_n<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_n <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_n<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_n <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_n<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_n <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_n<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_n <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteRibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_h<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_h <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_h<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_h <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_h<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_h <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_h<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_h <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteRibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_h<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_h <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_h<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_h <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_h<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_h <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_h<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_h <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_h<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_h <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_h<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_h <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_h<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_h <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_h<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_h <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_h<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_h <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_h<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_h <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_h<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_h <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_h<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_h <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteOrientedCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_hn<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_hn <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_hn<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_hn <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_hn<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_hn <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_hn<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_hn <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteOrientedCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_hn<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_hn <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_hn<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_hn <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_hn<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_hn <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_hn<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_hn <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h
new file mode 100644
index 0000000000..69cf612275
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bezier_curve.h
@@ -0,0 +1,21 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurveBezierCurveInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBezierCurveInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBezierCurveInterector4iMB(VirtualCurveIntersector &prim);
+#if defined(__AVX__)
+ void AddVirtualCurveBezierCurveInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBezierCurveInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBezierCurveInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h
new file mode 100644
index 0000000000..d37e41098e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_bspline_curve.h
@@ -0,0 +1,21 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurveBSplineCurveInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBSplineCurveInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBSplineCurveInterector4iMB(VirtualCurveIntersector &prim);
+#if defined(__AVX__)
+ void AddVirtualCurveBSplineCurveInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBSplineCurveInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveBSplineCurveInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h
new file mode 100644
index 0000000000..a133a11d63
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_catmullrom_curve.h
@@ -0,0 +1,21 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurveCatmullRomCurveInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveCatmullRomCurveInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveCatmullRomCurveInterector4iMB(VirtualCurveIntersector &prim);
+#if defined(__AVX__)
+ void AddVirtualCurveCatmullRomCurveInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveCatmullRomCurveInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveCatmullRomCurveInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h
new file mode 100644
index 0000000000..9aec35da45
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_hermite_curve.h
@@ -0,0 +1,21 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurveHermiteCurveInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveHermiteCurveInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveHermiteCurveInterector4iMB(VirtualCurveIntersector &prim);
+#if defined(__AVX__)
+ void AddVirtualCurveHermiteCurveInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveHermiteCurveInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveHermiteCurveInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h
new file mode 100644
index 0000000000..dd37d194f5
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_linear_curve.h
@@ -0,0 +1,21 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurveLinearCurveInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveLinearCurveInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveLinearCurveInterector4iMB(VirtualCurveIntersector &prim);
+#if defined(__AVX__)
+ void AddVirtualCurveLinearCurveInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurveLinearCurveInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurveLinearCurveInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h
new file mode 100644
index 0000000000..fe5ceed840
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/curve_intersector_virtual_point.h
@@ -0,0 +1,22 @@
+// Copyright 2020 Light Transport Entertainment Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ void AddVirtualCurvePointInterector4i(VirtualCurveIntersector &prim);
+ void AddVirtualCurvePointInterector4v(VirtualCurveIntersector &prim);
+ void AddVirtualCurvePointInterector4iMB(VirtualCurveIntersector &prim);
+
+#if defined (__AVX__)
+ void AddVirtualCurvePointInterector8i(VirtualCurveIntersector &prim);
+ void AddVirtualCurvePointInterector8v(VirtualCurveIntersector &prim);
+ void AddVirtualCurvePointInterector8iMB(VirtualCurveIntersector &prim);
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/cylinder.h b/thirdparty/embree-aarch64/kernels/geometry/cylinder.h
new file mode 100644
index 0000000000..39a582864c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/cylinder.h
@@ -0,0 +1,223 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct Cylinder
+ {
+ const Vec3fa p0; //!< start location
+ const Vec3fa p1; //!< end position
+ const float rr; //!< squared radius of cylinder
+
+ __forceinline Cylinder(const Vec3fa& p0, const Vec3fa& p1, const float r)
+ : p0(p0), p1(p1), rr(sqr(r)) {}
+
+ __forceinline Cylinder(const Vec3fa& p0, const Vec3fa& p1, const float rr, bool)
+ : p0(p0), p1(p1), rr(rr) {}
+
+ __forceinline bool intersect(const Vec3fa& org,
+ const Vec3fa& dir,
+ BBox1f& t_o,
+ float& u0_o, Vec3fa& Ng0_o,
+ float& u1_o, Vec3fa& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const float rl = rcp_length(p1-p0);
+ const Vec3fa P0 = p0, dP = (p1-p0)*rl;
+ const Vec3fa O = org-P0, dO = dir;
+
+ const float dOdO = dot(dO,dO);
+ const float OdO = dot(dO,O);
+ const float OO = dot(O,O);
+ const float dOz = dot(dP,dO);
+ const float Oz = dot(dP,O);
+
+ const float A = dOdO - sqr(dOz);
+ const float B = 2.0f * (OdO - dOz*Oz);
+ const float C = OO - sqr(Oz) - rr;
+
+ /* we miss the cylinder if determinant is smaller than zero */
+ const float D = B*B - 4.0f*A*C;
+ if (D < 0.0f) {
+ t_o = BBox1f(pos_inf,neg_inf);
+ return false;
+ }
+
+ /* special case for rays that are parallel to the cylinder */
+ const float eps = 16.0f*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ if (abs(A) < eps)
+ {
+ if (C <= 0.0f) {
+ t_o = BBox1f(neg_inf,pos_inf);
+ return true;
+ } else {
+ t_o = BBox1f(pos_inf,neg_inf);
+ return false;
+ }
+ }
+
+ /* standard case for rays that are not parallel to the cylinder */
+ const float Q = sqrt(D);
+ const float rcp_2A = rcp(2.0f*A);
+ const float t0 = (-B-Q)*rcp_2A;
+ const float t1 = (-B+Q)*rcp_2A;
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = madd(t0,dOz,Oz)*rl;
+ const Vec3fa Pr = t0*dir;
+ const Vec3fa Pl = madd(u0_o,p1-p0,p0);
+ Ng0_o = Pr-Pl;
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = madd(t1,dOz,Oz)*rl;
+ const Vec3fa Pr = t1*dir;
+ const Vec3fa Pl = madd(u1_o,p1-p0,p0);
+ Ng1_o = Pr-Pl;
+ }
+
+ t_o.lower = t0;
+ t_o.upper = t1;
+ return true;
+ }
+
+ __forceinline bool intersect(const Vec3fa& org_i, const Vec3fa& dir, BBox1f& t_o) const
+ {
+ float u0_o; Vec3fa Ng0_o;
+ float u1_o; Vec3fa Ng1_o;
+ return intersect(org_i,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+
+ static bool verify(const size_t id, const Cylinder& cylinder, const RayHit& ray, bool shouldhit, const float t0, const float t1)
+ {
+ float eps = 0.001f;
+ BBox1f t; bool hit;
+ hit = cylinder.intersect(ray.org,ray.dir,t);
+
+ bool failed = hit != shouldhit;
+ if (shouldhit) failed |= std::isinf(t0) ? t0 != t.lower : abs(t0-t.lower) > eps;
+ if (shouldhit) failed |= std::isinf(t1) ? t1 != t.upper : abs(t1-t.upper) > eps;
+ if (!failed) return true;
+ embree_cout << "Cylinder test " << id << " failed: cylinder = " << cylinder << ", ray = " << ray << ", hit = " << hit << ", t = " << t << embree_endl;
+ return false;
+ }
+
+ /* verify cylinder class */
+ static bool verify()
+ {
+ bool passed = true;
+ const Cylinder cylinder(Vec3fa(0.0f,0.0f,0.0f),Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(0,cylinder,RayHit(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(1,cylinder,RayHit(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(2,cylinder,RayHit(Vec3fa(+2.0f,1.0f,2.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(3,cylinder,RayHit(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(4,cylinder,RayHit(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(5,cylinder,RayHit(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ passed &= verify(6,cylinder,RayHit(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ return passed;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const Cylinder& c) {
+ return cout << "Cylinder { p0 = " << c.p0 << ", p1 = " << c.p1 << ", r = " << sqrtf(c.rr) << "}";
+ }
+ };
+
+ template<int N>
+ struct CylinderN
+ {
+ const Vec3vf<N> p0; //!< start location
+ const Vec3vf<N> p1; //!< end position
+ const vfloat<N> rr; //!< squared radius of cylinder
+
+ __forceinline CylinderN(const Vec3vf<N>& p0, const Vec3vf<N>& p1, const vfloat<N>& r)
+ : p0(p0), p1(p1), rr(sqr(r)) {}
+
+ __forceinline CylinderN(const Vec3vf<N>& p0, const Vec3vf<N>& p1, const vfloat<N>& rr, bool)
+ : p0(p0), p1(p1), rr(rr) {}
+
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox<vfloat<N>>& t_o,
+ vfloat<N>& u0_o, Vec3vf<N>& Ng0_o,
+ vfloat<N>& u1_o, Vec3vf<N>& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const vfloat<N> rl = rcp_length(p1-p0);
+ const Vec3vf<N> P0 = p0, dP = (p1-p0)*rl;
+ const Vec3vf<N> O = Vec3vf<N>(org)-P0, dO = dir;
+
+ const vfloat<N> dOdO = dot(dO,dO);
+ const vfloat<N> OdO = dot(dO,O);
+ const vfloat<N> OO = dot(O,O);
+ const vfloat<N> dOz = dot(dP,dO);
+ const vfloat<N> Oz = dot(dP,O);
+
+ const vfloat<N> A = dOdO - sqr(dOz);
+ const vfloat<N> B = 2.0f * (OdO - dOz*Oz);
+ const vfloat<N> C = OO - sqr(Oz) - rr;
+
+ /* we miss the cylinder if determinant is smaller than zero */
+ const vfloat<N> D = B*B - 4.0f*A*C;
+ vbool<N> valid = D >= 0.0f;
+ if (none(valid)) {
+ t_o = BBox<vfloat<N>>(empty);
+ return valid;
+ }
+
+ /* standard case for rays that are not parallel to the cylinder */
+ const vfloat<N> Q = sqrt(D);
+ const vfloat<N> rcp_2A = rcp(2.0f*A);
+ const vfloat<N> t0 = (-B-Q)*rcp_2A;
+ const vfloat<N> t1 = (-B+Q)*rcp_2A;
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = madd(t0,dOz,Oz)*rl;
+ const Vec3vf<N> Pr = t0*Vec3vf<N>(dir);
+ const Vec3vf<N> Pl = madd(u0_o,p1-p0,p0);
+ Ng0_o = Pr-Pl;
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = madd(t1,dOz,Oz)*rl;
+ const Vec3vf<N> Pr = t1*Vec3vf<N>(dir);
+ const Vec3vf<N> Pl = madd(u1_o,p1-p0,p0);
+ Ng1_o = Pr-Pl;
+ }
+
+ t_o.lower = select(valid, t0, vfloat<N>(pos_inf));
+ t_o.upper = select(valid, t1, vfloat<N>(neg_inf));
+
+ /* special case for rays that are parallel to the cylinder */
+ const vfloat<N> eps = 16.0f*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ vbool<N> validt = valid & (abs(A) < eps);
+ if (unlikely(any(validt)))
+ {
+ vbool<N> inside = C <= 0.0f;
+ t_o.lower = select(validt,select(inside,vfloat<N>(neg_inf),vfloat<N>(pos_inf)),t_o.lower);
+ t_o.upper = select(validt,select(inside,vfloat<N>(pos_inf),vfloat<N>(neg_inf)),t_o.upper);
+ valid &= !validt | inside;
+ }
+ return valid;
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org_i, const Vec3fa& dir, BBox<vfloat<N>>& t_o) const
+ {
+ vfloat<N> u0_o; Vec3vf<N> Ng0_o;
+ vfloat<N> u1_o; Vec3vf<N> Ng1_o;
+ return intersect(org_i,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/geometry/disc_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/disc_intersector.h
new file mode 100644
index 0000000000..e8305780e5
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/disc_intersector.h
@@ -0,0 +1,216 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_points.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct DiscIntersectorHitM
+ {
+ __forceinline DiscIntersectorHitM() {}
+
+ __forceinline DiscIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng)
+ {
+ }
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv(const size_t i) const
+ {
+ return Vec2f(vu[i], vv[i]);
+ }
+ __forceinline float t(const size_t i) const
+ {
+ return vt[i];
+ }
+ __forceinline Vec3fa Ng(const size_t i) const
+ {
+ return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]);
+ }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct DiscIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+
+ valid &= (vfloat<M>(ray.tnear()) <= projC0) & (projC0 <= vfloat<M>(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= projC0 > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR) * radius * pre.depth_scale; // ignore self intersections
+ if (unlikely(none(valid)))
+ return false;
+
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
+ return epilog(valid, hit);
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Vec3vf<M>& normal,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ vfloat<M> divisor = dot(Vec3vf<M>((Vec3fa)ray.dir), normal);
+ const vbool<M> parallel = divisor == vfloat<M>(0.f);
+ valid &= !parallel;
+ divisor = select(parallel, 1.f, divisor); // prevent divide by zero
+
+ vfloat<M> t = dot(center - Vec3vf<M>((Vec3fa)ray.org), Vec3vf<M>(normal)) / divisor;
+
+ valid &= (vfloat<M>(ray.tnear()) <= t) & (t <= vfloat<M>(ray.tfar));
+ if (unlikely(none(valid)))
+ return false;
+
+ Vec3vf<M> intersection = Vec3vf<M>((Vec3fa)ray.org) + Vec3vf<M>((Vec3fa)ray.dir) * t;
+ vfloat<M> dist2 = dot(intersection - center, intersection - center);
+ valid &= dist2 < radius * radius;
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, t, normal);
+ return epilog(valid, hit);
+ }
+ };
+
+ template<int M, int K>
+ struct DiscIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray,
+ size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+
+ valid &= (vfloat<M>(ray.tnear()[k]) <= projC0) & (projC0 <= vfloat<M>(ray.tfar[k]));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= projC0 > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR) * radius * pre.depth_scale[k]; // ignore self intersections
+ if (unlikely(none(valid)))
+ return false;
+
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
+ return epilog(valid, hit);
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray,
+ size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Vec3vf<M>& normal,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ vfloat<M> divisor = dot(Vec3vf<M>(ray_dir), normal);
+ const vbool<M> parallel = divisor == vfloat<M>(0.f);
+ valid &= !parallel;
+ divisor = select(parallel, 1.f, divisor); // prevent divide by zero
+
+ vfloat<M> t = dot(center - Vec3vf<M>(ray_org), Vec3vf<M>(normal)) / divisor;
+
+ valid &= (vfloat<M>(ray.tnear()[k]) <= t) & (t <= vfloat<M>(ray.tfar[k]));
+ if (unlikely(none(valid)))
+ return false;
+
+ Vec3vf<M> intersection = Vec3vf<M>(ray_org) + Vec3vf<M>(ray_dir) * t;
+ vfloat<M> dist2 = dot(intersection - center, intersection - center);
+ valid &= dist2 < radius * radius;
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, t, normal);
+ return epilog(valid, hit);
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/geometry/disci_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/disci_intersector.h
new file mode 100644
index 0000000000..e1dc3aa98e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/disci_intersector.h
@@ -0,0 +1,277 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "disc_intersector.h"
+#include "intersector_epilog.h"
+#include "pointi.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, int Mx, bool filter>
+ struct DiscMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct DiscMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time());
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time());
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct DiscMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct DiscMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time()[k]);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time()[k]);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct OrientedDiscMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Intersect1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Occluded1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct OrientedDiscMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time());
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Intersect1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time());
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Occluded1EpilogM<M, Mx, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct OrientedDiscMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct OrientedDiscMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time()[k]);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time()[k]);
+ const vbool<Mx> valid = Disc.template valid<Mx>();
+ return DiscIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/geometry/filter.h b/thirdparty/embree-aarch64/kernels/geometry/filter.h
new file mode 100644
index 0000000000..4cdf7a395a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/filter.h
@@ -0,0 +1,204 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+#include "../common/ray.h"
+#include "../common/hit.h"
+#include "../common/context.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ __forceinline bool runIntersectionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ if (geometry->intersectionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ copyHitToRay(*(RayHit*)args->ray,*(Hit*)args->hit);
+ return true;
+ }
+
+ __forceinline bool runIntersectionFilter1(const Geometry* const geometry, RayHit& ray, IntersectContext* context, Hit& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ int mask = -1;
+ args.valid = &mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = 1;
+ return runIntersectionFilter1Helper(&args,geometry,context);
+ }
+
+ __forceinline void reportIntersection1(IntersectFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args)
+ {
+#if defined(EMBREE_FILTER_FUNCTION)
+ IntersectContext* MAYBE_UNUSED context = args->internal_context;
+ const Geometry* const geometry = args->geometry;
+ if (geometry->intersectionFilterN) {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(filter_args);
+ }
+
+ //if (args->valid[0] == 0)
+ // return;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(filter_args);
+ }
+#endif
+ }
+
+ __forceinline bool runOcclusionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ if (geometry->occlusionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+ return true;
+ }
+
+ __forceinline bool runOcclusionFilter1(const Geometry* const geometry, Ray& ray, IntersectContext* context, Hit& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ int mask = -1;
+ args.valid = &mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = 1;
+ return runOcclusionFilter1Helper(&args,geometry,context);
+ }
+
+ __forceinline void reportOcclusion1(OccludedFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args)
+ {
+#if defined(EMBREE_FILTER_FUNCTION)
+ IntersectContext* MAYBE_UNUSED context = args->internal_context;
+ const Geometry* const geometry = args->geometry;
+ if (geometry->occlusionFilterN) {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(filter_args);
+ }
+
+ //if (args->valid[0] == 0)
+ // return false;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(filter_args);
+ }
+#endif
+ }
+
+ template<int K>
+ __forceinline vbool<K> runIntersectionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ vint<K>* mask = (vint<K>*) args->valid;
+ if (geometry->intersectionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(args);
+ }
+
+ vbool<K> valid_o = *mask != vint<K>(zero);
+ if (none(valid_o)) return valid_o;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+ }
+
+ valid_o = *mask != vint<K>(zero);
+ if (none(valid_o)) return valid_o;
+
+ copyHitToRay(valid_o,*(RayHitK<K>*)args->ray,*(HitK<K>*)args->hit);
+ return valid_o;
+ }
+
+ template<int K>
+ __forceinline vbool<K> runIntersectionFilter(const vbool<K>& valid, const Geometry* const geometry, RayHitK<K>& ray, IntersectContext* context, HitK<K>& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ vint<K> mask = valid.mask32();
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = K;
+ return runIntersectionFilterHelper<K>(&args,geometry,context);
+ }
+
+ template<int K>
+ __forceinline vbool<K> runOcclusionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ vint<K>* mask = (vint<K>*) args->valid;
+ if (geometry->occlusionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(args);
+ }
+
+ vbool<K> valid_o = *mask != vint<K>(zero);
+
+ if (none(valid_o)) return valid_o;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+ }
+
+ valid_o = *mask != vint<K>(zero);
+
+ RayK<K>* ray = (RayK<K>*) args->ray;
+ ray->tfar = select(valid_o, vfloat<K>(neg_inf), ray->tfar);
+ return valid_o;
+ }
+
+ template<int K>
+ __forceinline vbool<K> runOcclusionFilter(const vbool<K>& valid, const Geometry* const geometry, RayK<K>& ray, IntersectContext* context, HitK<K>& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ vint<K> mask = valid.mask32();
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = K;
+ return runOcclusionFilterHelper<K>(&args,geometry,context);
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/grid_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/grid_intersector.h
new file mode 100644
index 0000000000..46a0af0827
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/grid_intersector.h
@@ -0,0 +1,99 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "grid_soa_intersector1.h"
+#include "grid_soa_intersector_packet.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ class SubdivPatch1Precalculations : public T
+ {
+ public:
+ __forceinline SubdivPatch1Precalculations (const Ray& ray, const void* ptr)
+ : T(ray,ptr) {}
+ };
+
+ template<int K, typename T>
+ class SubdivPatch1PrecalculationsK : public T
+ {
+ public:
+ __forceinline SubdivPatch1PrecalculationsK (const vbool<K>& valid, RayK<K>& ray)
+ : T(valid,ray) {}
+ };
+
+ class Grid1Intersector1
+ {
+ public:
+ typedef GridSOA Primitive;
+ typedef Grid1Precalculations<GridSOAIntersector1::Precalculations> Precalculations;
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ }
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ intersect(pre,ray,context,prim,ty,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ }
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ return occluded(pre,ray,context,prim,ty,lazy_node);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ assert(false && "not implemented");
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ assert(false && "not implemented");
+ return false;
+ }
+ };
+
+ template <int K>
+ struct GridIntersectorK
+ {
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations;
+
+
+ static __forceinline void intersect(const vbool<K>& valid, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ }
+ };
+
+ typedef Grid1IntersectorK<4> SubdivPatch1Intersector4;
+ typedef Grid1IntersectorK<8> SubdivPatch1Intersector8;
+ typedef Grid1IntersectorK<16> SubdivPatch1Intersector16;
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/grid_soa.h b/thirdparty/embree-aarch64/kernels/geometry/grid_soa.h
new file mode 100644
index 0000000000..d3b275586c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/grid_soa.h
@@ -0,0 +1,275 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_subdiv_mesh.h"
+#include "../bvh/bvh.h"
+#include "../subdiv/tessellation.h"
+#include "../subdiv/tessellation_cache.h"
+#include "subdivpatch1.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class GridSOA
+ {
+ public:
+
+ /*! GridSOA constructor */
+ GridSOA(const SubdivPatch1Base* patches, const unsigned time_steps,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ const SubdivMesh* const geom, const size_t totalBvhBytes, const size_t gridBytes, BBox3fa* bounds_o = nullptr);
+
+ /*! Subgrid creation */
+ template<typename Allocator>
+ static GridSOA* create(const SubdivPatch1Base* patches, const unsigned time_steps,
+ unsigned x0, unsigned x1, unsigned y0, unsigned y1,
+ const Scene* scene, Allocator& alloc, BBox3fa* bounds_o = nullptr)
+ {
+ const unsigned width = x1-x0+1;
+ const unsigned height = y1-y0+1;
+ const GridRange range(0,width-1,0,height-1);
+ size_t bvhBytes = 0;
+ if (time_steps == 1)
+ bvhBytes = getBVHBytes(range,sizeof(BVH4::AABBNode),0);
+ else {
+ bvhBytes = (time_steps-1)*getBVHBytes(range,sizeof(BVH4::AABBNodeMB),0);
+ bvhBytes += getTemporalBVHBytes(make_range(0,int(time_steps-1)),sizeof(BVH4::AABBNodeMB4D));
+ }
+ const size_t gridBytes = 4*size_t(width)*size_t(height)*sizeof(float);
+ size_t rootBytes = time_steps*sizeof(BVH4::NodeRef);
+#if !defined(__X86_64__) && !defined(__aarch64__)
+ rootBytes += 4; // We read 2 elements behind the grid. As we store at least 8 root bytes after the grid we are fine in 64 bit mode. But in 32 bit mode we have to do additional padding.
+#endif
+ void* data = alloc(offsetof(GridSOA,data)+bvhBytes+time_steps*gridBytes+rootBytes);
+ assert(data);
+ return new (data) GridSOA(patches,time_steps,x0,x1,y0,y1,patches->grid_u_res,patches->grid_v_res,scene->get<SubdivMesh>(patches->geomID()),bvhBytes,gridBytes,bounds_o);
+ }
+
+ /*! Grid creation */
+ template<typename Allocator>
+ static GridSOA* create(const SubdivPatch1Base* const patches, const unsigned time_steps,
+ const Scene* scene, const Allocator& alloc, BBox3fa* bounds_o = nullptr)
+ {
+ return create(patches,time_steps,0,patches->grid_u_res-1,0,patches->grid_v_res-1,scene,alloc,bounds_o);
+ }
+
+ /*! returns reference to root */
+ __forceinline BVH4::NodeRef& root(size_t t = 0) { return (BVH4::NodeRef&)data[rootOffset + t*sizeof(BVH4::NodeRef)]; }
+ __forceinline const BVH4::NodeRef& root(size_t t = 0) const { return (BVH4::NodeRef&)data[rootOffset + t*sizeof(BVH4::NodeRef)]; }
+
+ /*! returns pointer to BVH array */
+ __forceinline int8_t* bvhData() { return &data[0]; }
+ __forceinline const int8_t* bvhData() const { return &data[0]; }
+
+ /*! returns pointer to Grid array */
+ __forceinline float* gridData(size_t t = 0) { return (float*) &data[gridOffset + t*gridBytes]; }
+ __forceinline const float* gridData(size_t t = 0) const { return (float*) &data[gridOffset + t*gridBytes]; }
+
+ __forceinline void* encodeLeaf(size_t u, size_t v) {
+ return (void*) (16*(v * width + u + 1)); // +1 to not create empty leaf
+ }
+ __forceinline float* decodeLeaf(size_t t, const void* ptr) {
+ return gridData(t) + (((size_t) (ptr) >> 4) - 1);
+ }
+
+ /*! returns the size of the BVH over the grid in bytes */
+ static size_t getBVHBytes(const GridRange& range, const size_t nodeBytes, const size_t leafBytes);
+
+ /*! returns the size of the temporal BVH over the time range BVHs */
+ static size_t getTemporalBVHBytes(const range<int> time_range, const size_t nodeBytes);
+
+ /*! calculates bounding box of grid range */
+ __forceinline BBox3fa calculateBounds(size_t time, const GridRange& range) const
+ {
+ const float* const grid_array = gridData(time);
+ const float* const grid_x_array = grid_array + 0 * dim_offset;
+ const float* const grid_y_array = grid_array + 1 * dim_offset;
+ const float* const grid_z_array = grid_array + 2 * dim_offset;
+
+ /* compute the bounds just for the range! */
+ BBox3fa bounds( empty );
+ for (unsigned v = range.v_start; v<=range.v_end; v++)
+ {
+ for (unsigned u = range.u_start; u<=range.u_end; u++)
+ {
+ const float x = grid_x_array[ v * width + u];
+ const float y = grid_y_array[ v * width + u];
+ const float z = grid_z_array[ v * width + u];
+ bounds.extend( Vec3fa(x,y,z) );
+ }
+ }
+ assert(is_finite(bounds));
+ return bounds;
+ }
+
+ /*! Evaluates grid over patch and builds BVH4 tree over the grid. */
+ std::pair<BVH4::NodeRef,BBox3fa> buildBVH(BBox3fa* bounds_o);
+
+ /*! Create BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,BBox3fa> buildBVH(const GridRange& range, size_t& allocator);
+
+ /*! Evaluates grid over patch and builds MSMBlur BVH4 tree over the grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMSMBlurBVH(const range<int> time_range, BBox3fa* bounds_o);
+
+ /*! Create MBlur BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMBlurBVH(size_t time, const GridRange& range, size_t& allocator);
+
+ /*! Create MSMBlur BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMSMBlurBVH(const range<int> time_range, size_t& allocator, BBox3fa* bounds_o);
+
+ template<typename Loader>
+ struct MapUV
+ {
+ typedef typename Loader::vfloat vfloat;
+ const float* const grid_uv;
+ size_t line_offset;
+ size_t lines;
+
+ __forceinline MapUV(const float* const grid_uv, size_t line_offset, const size_t lines)
+ : grid_uv(grid_uv), line_offset(line_offset), lines(lines) {}
+
+ __forceinline void operator() (vfloat& u, vfloat& v) const {
+ const Vec3<vfloat> tri_v012_uv = Loader::gather(grid_uv,line_offset,lines);
+ const Vec2<vfloat> uv0 = GridSOA::decodeUV(tri_v012_uv[0]);
+ const Vec2<vfloat> uv1 = GridSOA::decodeUV(tri_v012_uv[1]);
+ const Vec2<vfloat> uv2 = GridSOA::decodeUV(tri_v012_uv[2]);
+ const Vec2<vfloat> uv = u * uv1 + v * uv2 + (1.0f-u-v) * uv0;
+ u = uv[0];v = uv[1];
+ }
+ };
+
+ struct Gather2x3
+ {
+ enum { M = 4 };
+ typedef vbool4 vbool;
+ typedef vint4 vint;
+ typedef vfloat4 vfloat;
+
+ static __forceinline const Vec3vf4 gather(const float* const grid, const size_t line_offset, const size_t lines)
+ {
+ vfloat4 r0 = vfloat4::loadu(grid + 0*line_offset);
+ vfloat4 r1 = vfloat4::loadu(grid + 1*line_offset); // this accesses 2 elements too much in case of 2x2 grid, but this is ok as we ensure enough padding after the grid
+ if (unlikely(line_offset == 2))
+ {
+ r0 = shuffle<0,1,1,1>(r0);
+ r1 = shuffle<0,1,1,1>(r1);
+ }
+ return Vec3vf4(unpacklo(r0,r1), // r00, r10, r01, r11
+ shuffle<1,1,2,2>(r0), // r01, r01, r02, r02
+ shuffle<0,1,1,2>(r1)); // r10, r11, r11, r12
+ }
+
+ static __forceinline void gather(const float* const grid_x,
+ const float* const grid_y,
+ const float* const grid_z,
+ const size_t line_offset,
+ const size_t lines,
+ Vec3vf4& v0_o,
+ Vec3vf4& v1_o,
+ Vec3vf4& v2_o)
+ {
+ const Vec3vf4 tri_v012_x = gather(grid_x,line_offset,lines);
+ const Vec3vf4 tri_v012_y = gather(grid_y,line_offset,lines);
+ const Vec3vf4 tri_v012_z = gather(grid_z,line_offset,lines);
+ v0_o = Vec3vf4(tri_v012_x[0],tri_v012_y[0],tri_v012_z[0]);
+ v1_o = Vec3vf4(tri_v012_x[1],tri_v012_y[1],tri_v012_z[1]);
+ v2_o = Vec3vf4(tri_v012_x[2],tri_v012_y[2],tri_v012_z[2]);
+ }
+ };
+
+#if defined (__AVX__)
+ struct Gather3x3
+ {
+ enum { M = 8 };
+ typedef vbool8 vbool;
+ typedef vint8 vint;
+ typedef vfloat8 vfloat;
+
+ static __forceinline const Vec3vf8 gather(const float* const grid, const size_t line_offset, const size_t lines)
+ {
+ vfloat4 ra = vfloat4::loadu(grid + 0*line_offset);
+ vfloat4 rb = vfloat4::loadu(grid + 1*line_offset); // this accesses 2 elements too much in case of 2x2 grid, but this is ok as we ensure enough padding after the grid
+ vfloat4 rc;
+ if (likely(lines > 2))
+ rc = vfloat4::loadu(grid + 2*line_offset);
+ else
+ rc = rb;
+
+ if (unlikely(line_offset == 2))
+ {
+ ra = shuffle<0,1,1,1>(ra);
+ rb = shuffle<0,1,1,1>(rb);
+ rc = shuffle<0,1,1,1>(rc);
+ }
+
+ const vfloat8 r0 = vfloat8(ra,rb);
+ const vfloat8 r1 = vfloat8(rb,rc);
+ return Vec3vf8(unpacklo(r0,r1), // r00, r10, r01, r11, r10, r20, r11, r21
+ shuffle<1,1,2,2>(r0), // r01, r01, r02, r02, r11, r11, r12, r12
+ shuffle<0,1,1,2>(r1)); // r10, r11, r11, r12, r20, r21, r21, r22
+ }
+
+ static __forceinline void gather(const float* const grid_x,
+ const float* const grid_y,
+ const float* const grid_z,
+ const size_t line_offset,
+ const size_t lines,
+ Vec3vf8& v0_o,
+ Vec3vf8& v1_o,
+ Vec3vf8& v2_o)
+ {
+ const Vec3vf8 tri_v012_x = gather(grid_x,line_offset,lines);
+ const Vec3vf8 tri_v012_y = gather(grid_y,line_offset,lines);
+ const Vec3vf8 tri_v012_z = gather(grid_z,line_offset,lines);
+ v0_o = Vec3vf8(tri_v012_x[0],tri_v012_y[0],tri_v012_z[0]);
+ v1_o = Vec3vf8(tri_v012_x[1],tri_v012_y[1],tri_v012_z[1]);
+ v2_o = Vec3vf8(tri_v012_x[2],tri_v012_y[2],tri_v012_z[2]);
+ }
+ };
+#endif
+
+ template<typename vfloat>
+ static __forceinline Vec2<vfloat> decodeUV(const vfloat& uv)
+ {
+ typedef typename vfloat::Int vint;
+ const vint iu = asInt(uv) & 0xffff;
+ const vint iv = srl(asInt(uv),16);
+ const vfloat u = (vfloat)iu * vfloat(8.0f/0x10000);
+ const vfloat v = (vfloat)iv * vfloat(8.0f/0x10000);
+ return Vec2<vfloat>(u,v);
+ }
+
+ __forceinline unsigned int geomID() const {
+ return _geomID;
+ }
+
+ __forceinline unsigned int primID() const {
+ return _primID;
+ }
+
+ public:
+ BVH4::NodeRef troot;
+#if !defined(__X86_64__) && !defined(__aarch64__)
+ unsigned align1;
+#endif
+ unsigned time_steps;
+ unsigned width;
+
+ unsigned height;
+ unsigned dim_offset;
+ unsigned _geomID;
+ unsigned _primID;
+
+ unsigned align2;
+ unsigned gridOffset;
+ unsigned gridBytes;
+ unsigned rootOffset;
+
+ int8_t data[1]; //!< after the struct we first store the BVH, then the grid, and finally the roots
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector1.h b/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector1.h
new file mode 100644
index 0000000000..2ed922a5ae
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector1.h
@@ -0,0 +1,207 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "../common/ray.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class GridSOAIntersector1
+ {
+ public:
+ typedef void Primitive;
+
+ class Precalculations
+ {
+ public:
+ __forceinline Precalculations (const Ray& ray, const void* ptr)
+ : grid(nullptr) {}
+
+ public:
+ GridSOA* grid;
+ int itime;
+ float ftime;
+ };
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHit& ray,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ intersector.intersect(ray,v0,v1,v2,mapUV,Intersect1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(Ray& ray,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> v0, v1, v2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ return intersector.intersect(ray,v0,v1,v2,mapUV,Occluded1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, context, grid_x , line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+
+ class GridSOAMBIntersector1
+ {
+ public:
+ typedef void Primitive;
+ typedef GridSOAIntersector1::Precalculations Precalculations;
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHit& ray, const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ intersector.intersect(ray,v0,v1,v2,mapUV,Intersect1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(Ray& ray, const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ return intersector.intersect(ray,v0,v1,v2,mapUV,Occluded1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(pre.itime,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(pre.itime,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector_packet.h b/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector_packet.h
new file mode 100644
index 0000000000..41d66e1e28
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/grid_soa_intersector_packet.h
@@ -0,0 +1,445 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "../common/ray.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int K>
+ struct MapUV0
+ {
+ const float* const grid_uv;
+ size_t ofs00, ofs01, ofs10, ofs11;
+
+ __forceinline MapUV0(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
+ : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
+
+ __forceinline void operator() (vfloat<K>& u, vfloat<K>& v) const {
+ const vfloat<K> uv00(grid_uv[ofs00]);
+ const vfloat<K> uv01(grid_uv[ofs01]);
+ const vfloat<K> uv10(grid_uv[ofs10]);
+ const vfloat<K> uv11(grid_uv[ofs11]);
+ const Vec2vf<K> uv0 = GridSOA::decodeUV(uv00);
+ const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
+ const Vec2vf<K> uv2 = GridSOA::decodeUV(uv10);
+ const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
+ u = uv[0]; v = uv[1];
+ }
+ };
+
+ template<int K>
+ struct MapUV1
+ {
+ const float* const grid_uv;
+ size_t ofs00, ofs01, ofs10, ofs11;
+
+ __forceinline MapUV1(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
+ : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
+
+ __forceinline void operator() (vfloat<K>& u, vfloat<K>& v) const {
+ const vfloat<K> uv00(grid_uv[ofs00]);
+ const vfloat<K> uv01(grid_uv[ofs01]);
+ const vfloat<K> uv10(grid_uv[ofs10]);
+ const vfloat<K> uv11(grid_uv[ofs11]);
+ const Vec2vf<K> uv0 = GridSOA::decodeUV(uv10);
+ const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
+ const Vec2vf<K> uv2 = GridSOA::decodeUV(uv11);
+ const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
+ u = uv[0]; v = uv[1];
+ }
+ };
+
+ template<int K>
+ class GridSOAIntersectorK
+ {
+ public:
+ typedef void Primitive;
+
+ class Precalculations
+ {
+#if defined(__AVX__)
+ static const int M = 8;
+#else
+ static const int M = 4;
+#endif
+
+ public:
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray)
+ : grid(nullptr), intersector(valid,ray) {}
+
+ public:
+ GridSOA* grid;
+ PlueckerIntersectorK<M,K> intersector; // FIXME: use quad intersector
+ };
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ const size_t ofs00 = (y+0)*line_offset+(x+0);
+ const size_t ofs01 = (y+0)*line_offset+(x+1);
+ const size_t ofs10 = (y+1)*line_offset+(x+0);
+ const size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+
+ pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+ }
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ vbool<K> valid = valid_i;
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ const size_t ofs00 = (y+0)*line_offset+(x+0);
+ const size_t ofs01 = (y+0)*line_offset+(x+1);
+ const size_t ofs10 = (y+1)*line_offset+(x+0);
+ const size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+
+ pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ }
+ }
+ return !valid;
+ }
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+
+ template<int K>
+ class GridSOAMBIntersectorK
+ {
+ public:
+ typedef void Primitive;
+ typedef typename GridSOAIntersectorK<K>::Precalculations Precalculations;
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ vfloat<K> vftime;
+ vint<K> vitime = getTimeSegment(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
+
+ vbool<K> valid1 = valid_i;
+ while (any(valid1)) {
+ const size_t j = bsf(movemask(valid1));
+ const int itime = vitime[j];
+ const vbool<K> valid2 = valid1 & (itime == vitime);
+ valid1 = valid1 & !valid2;
+ intersect(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
+ }
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ size_t ofs00 = (y+0)*line_offset+(x+0);
+ size_t ofs01 = (y+0)*line_offset+(x+1);
+ size_t ofs10 = (y+1)*line_offset+(x+0);
+ size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ ofs00 += grid_offset;
+ ofs01 += grid_offset;
+ ofs10 += grid_offset;
+ ofs11 += grid_offset;
+ const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ const Vec3vf<K> p00 = lerp(a00,b00,ftime);
+ const Vec3vf<K> p01 = lerp(a01,b01,ftime);
+ const Vec3vf<K> p10 = lerp(a10,b10,ftime);
+ const Vec3vf<K> p11 = lerp(a11,b11,ftime);
+
+ pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+ }
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ vfloat<K> vftime;
+ vint<K> vitime = getTimeSegment(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
+
+ vbool<K> valid_o = valid_i;
+ vbool<K> valid1 = valid_i;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int itime = vitime[j];
+ const vbool<K> valid2 = valid1 & (itime == vitime);
+ valid1 = valid1 & !valid2;
+ valid_o &= !valid2 | occluded(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
+ }
+ return !valid_o;
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ vbool<K> valid = valid_i;
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ size_t ofs00 = (y+0)*line_offset+(x+0);
+ size_t ofs01 = (y+0)*line_offset+(x+1);
+ size_t ofs10 = (y+1)*line_offset+(x+0);
+ size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ ofs00 += grid_offset;
+ ofs01 += grid_offset;
+ ofs10 += grid_offset;
+ ofs11 += grid_offset;
+ const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ const Vec3vf<K> p00 = lerp(a00,b00,ftime);
+ const Vec3vf<K> p01 = lerp(a01,b01,ftime);
+ const Vec3vf<K> p10 = lerp(a10,b10,ftime);
+ const Vec3vf<K> p11 = lerp(a11,b11,ftime);
+
+ pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ }
+ }
+ return valid;
+ }
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHitK<K>& ray, size_t k,
+ const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(RayK<K>& ray, size_t k,
+ const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ float ftime;
+ int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
+
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ float ftime;
+ int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
+
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/instance.h b/thirdparty/embree-aarch64/kernels/geometry/instance.h
new file mode 100644
index 0000000000..66893d581f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/instance.h
@@ -0,0 +1,78 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene_instance.h"
+
+namespace embree
+{
+ struct InstancePrimitive
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return N; }
+
+ public:
+
+ InstancePrimitive (const Instance* instance, unsigned int instID)
+ : instance(instance)
+ , instID_(instID)
+ {}
+
+ __forceinline void fill(const PrimRef* prims, size_t& i, size_t end, Scene* scene)
+ {
+ assert(end-i == 1);
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance, geomID);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& i, size_t end, Scene* scene, size_t itime)
+ {
+ assert(end-i == 1);
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance,geomID);
+ return instance->linearBounds(0,itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ assert(end-i == 1);
+ const PrimRefMB& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance,geomID);
+ return instance->linearBounds(0,time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(Instance* instance) {
+ return instance->bounds(0);
+ }
+
+ public:
+ const Instance* instance;
+ const unsigned int instID_ = std::numeric_limits<unsigned int>::max ();
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/instance_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/instance_intersector.h
new file mode 100644
index 0000000000..91731a39c5
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/instance_intersector.h
@@ -0,0 +1,84 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instance.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct InstanceIntersector1
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim);
+ static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim);
+ static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim);
+ };
+
+ struct InstanceIntersector1MB
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim);
+ static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim);
+ static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim);
+ };
+
+ template<int K>
+ struct InstanceIntersectorK
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim);
+ static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim);
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+
+ template<int K>
+ struct InstanceIntersectorKMB
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim);
+ static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim);
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/intersector_epilog.h b/thirdparty/embree-aarch64/kernels/geometry/intersector_epilog.h
new file mode 100644
index 0000000000..0df49dd6e9
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/intersector_epilog.h
@@ -0,0 +1,1074 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/context.h"
+#include "filter.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct UVIdentity {
+ __forceinline void operator() (vfloat<M>& u, vfloat<M>& v) const {}
+ };
+
+
+ template<bool filter>
+ struct Intersect1Epilog1
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1Epilog1(RayHit& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t;
+ bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ return found;
+ }
+ }
+#endif
+
+ /* update hit information */
+ ray.tfar = hit.t;
+ ray.Ng = hit.Ng;
+ ray.u = hit.u;
+ ray.v = hit.v;
+ ray.primID = primID;
+ ray.geomID = geomID;
+ instance_id_stack::copy(context->user->instID, ray.instID);
+ return true;
+ }
+ };
+
+ template<bool filter>
+ struct Occluded1Epilog1
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1Epilog1(Ray& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
+ HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t;
+ const bool found = runOcclusionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ return found;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int K, bool filter>
+ struct Intersect1KEpilog1
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t;
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ return found;
+ }
+ }
+#endif
+
+ /* update hit information */
+ ray.tfar[k] = hit.t;
+ ray.Ng.x[k] = hit.Ng.x;
+ ray.Ng.y[k] = hit.Ng.y;
+ ray.Ng.z[k] = hit.Ng.z;
+ ray.u[k] = hit.u;
+ ray.v[k] = hit.v;
+ ray.primID[k] = primID;
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy<const unsigned*, vuint<K>*, const size_t&>(context->user->instID, ray.instID, k);
+ return true;
+ }
+ };
+
+ template<int K, bool filter>
+ struct Occluded1KEpilog1
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
+ hit.finalize();
+ HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t;
+ const bool found = any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ return found;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct Intersect1EpilogM
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Intersect1EpilogM(RayHit& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<Mx>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ vbool<Mx> valid = valid_i;
+ if (Mx > M) valid &= (1<<M)-1;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+ unsigned int geomID = geomIDs[i];
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ bool foundhit = false;
+ goto entry;
+ while (true)
+ {
+ if (unlikely(none(valid))) return foundhit;
+ i = select_min(valid,hit.vt);
+
+ geomID = geomIDs[i];
+ entry:
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask) == 0) {
+ clear(valid,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* call intersection filter function */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ const Vec2f uv = hit.uv(i);
+ HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ const bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ foundhit |= found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ ray.tfar = hit.vt[i];
+ ray.Ng.x = hit.vNg.x[i];
+ ray.Ng.y = hit.vNg.y[i];
+ ray.Ng.z = hit.vNg.z[i];
+ ray.u = uv.x;
+ ray.v = uv.y;
+ ray.primID = primIDs[i];
+ ray.geomID = geomID;
+ instance_id_stack::copy(context->user->instID, ray.instID);
+ return true;
+
+ }
+ };
+
+#if 0 && defined(__AVX512F__) // do not enable, this reduced frequency for BVH4
+ template<int M, bool filter>
+ struct Intersect1EpilogM<M,16,filter>
+ {
+ static const size_t Mx = 16;
+ RayHit& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Intersect1EpilogM(RayHit& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<Mx>& valid_i, Hit& hit) const
+ {
+ Scene* MAYBE_UNUSED scene = context->scene;
+ vbool<Mx> valid = valid_i;
+ if (Mx > M) valid &= (1<<M)-1;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+ unsigned int geomID = geomIDs[i];
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ bool foundhit = false;
+ goto entry;
+ while (true)
+ {
+ if (unlikely(none(valid))) return foundhit;
+ i = select_min(valid,hit.vt);
+
+ geomID = geomIDs[i];
+ entry:
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask) == 0) {
+ clear(valid,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* call intersection filter function */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ const Vec2f uv = hit.uv(i);
+ HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ const bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ foundhit |= found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ vbool<Mx> finalMask(((unsigned int)1 << i));
+ ray.update(finalMask,hit.vt,hit.vu,hit.vv,hit.vNg.x,hit.vNg.y,hit.vNg.z,geomID,primIDs);
+ instance_id_stack::foreach([&](unsigned level)
+ {
+ ray.instID[level] = context->user->instID[level];
+ return (context->user->instID[level] != RTC_INVALID_GEOMETRY_ID);
+ });
+ return true;
+
+ }
+ };
+#endif
+
+ template<int M, int Mx, bool filter>
+ struct Occluded1EpilogM
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Occluded1EpilogM(Ray& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<Mx>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ if (unlikely(filter))
+ hit.finalize(); /* called only once */
+
+ vbool<Mx> valid = valid_i;
+ if (Mx > M) valid &= (1<<M)-1;
+ size_t m=movemask(valid);
+ goto entry;
+ while (true)
+ {
+ if (unlikely(m == 0)) return false;
+ entry:
+ size_t i=bsf(m);
+
+ const unsigned int geomID = geomIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask) == 0) {
+ m=btc(m,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* if we have no filter then the test passed */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ const Vec2f uv = hit.uv(i);
+ HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ if (runOcclusionFilter1(geometry,ray,context,h)) return true;
+ ray.tfar = old_t;
+ m=btc(m,i);
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ return true;
+ }
+ };
+
+ template<int M, bool filter>
+ struct Intersect1EpilogMU
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1EpilogMU(RayHit& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+
+ vbool<M> valid = valid_i;
+ hit.finalize();
+
+ size_t i = select_min(valid,hit.vt);
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
+ {
+ bool foundhit = false;
+ while (true)
+ {
+ /* call intersection filter function */
+ Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ const bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ foundhit |= found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
+ if (unlikely(none(valid))) break;
+ i = select_min(valid,hit.vt);
+ }
+ return foundhit;
+ }
+#endif
+
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ const Vec3fa Ng = hit.Ng(i);
+ ray.tfar = hit.t(i);
+ ray.Ng.x = Ng.x;
+ ray.Ng.y = Ng.y;
+ ray.Ng.z = Ng.z;
+ ray.u = uv.x;
+ ray.v = uv.y;
+ ray.primID = primID;
+ ray.geomID = geomID;
+ instance_id_stack::copy(context->user->instID, ray.instID);
+ return true;
+ }
+ };
+
+ template<int M, bool filter>
+ struct Occluded1EpilogMU
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1EpilogMU(Ray& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid, Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ hit.finalize();
+ for (size_t m=movemask(valid), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ if (runOcclusionFilter1(geometry,ray,context,h)) return true;
+ ray.tfar = old_t;
+ }
+ return false;
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct IntersectKEpilogM
+ {
+ RayHitK<K>& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+ const size_t i;
+
+ __forceinline IntersectKEpilogM(RayHitK<K>& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs,
+ size_t i)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ vbool<K> valid = valid_i;
+
+ std::tie(u,v,t,Ng) = hit();
+
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+ /* ray masking test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* occlusion filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(m_accept,ray.tfar,old_t);
+ return m_accept;
+ }
+ }
+#endif
+
+ /* update hit information */
+ vfloat<K>::store(valid,&ray.tfar,t);
+ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
+ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
+ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
+ vfloat<K>::store(valid,&ray.u,u);
+ vfloat<K>::store(valid,&ray.v,v);
+ vuint<K>::store(valid,&ray.primID,primID);
+ vuint<K>::store(valid,&ray.geomID,geomID);
+ instance_id_stack::copy<const unsigned*, vuint<K>*, const vbool<K>&>(context->user->instID, ray.instID, valid);
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OccludedKEpilogM
+ {
+ vbool<K>& valid0;
+ RayK<K>& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+ const size_t i;
+
+ __forceinline OccludedKEpilogM(vbool<K>& valid0,
+ RayK<K>& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs,
+ size_t i)
+ : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ vbool<K> valid = valid_i;
+
+ /* ray masking test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return valid;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ valid = runOcclusionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(valid,ray.tfar,old_t);
+ }
+ }
+#endif
+
+ /* update occlusion */
+ valid0 = valid0 & !valid;
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct IntersectKEpilogMU
+ {
+ RayHitK<K>& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline IntersectKEpilogMU(RayHitK<K>& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_org, const Hit& hit) const
+ {
+ vbool<K> valid = valid_org;
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+ /* ray masking test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(m_accept,ray.tfar,old_t);
+ return m_accept;
+ }
+ }
+#endif
+
+ /* update hit information */
+ vfloat<K>::store(valid,&ray.tfar,t);
+ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
+ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
+ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
+ vfloat<K>::store(valid,&ray.u,u);
+ vfloat<K>::store(valid,&ray.v,v);
+ vuint<K>::store(valid,&ray.primID,primID);
+ vuint<K>::store(valid,&ray.geomID,geomID);
+ instance_id_stack::copy<const unsigned*, vuint<K>*, const vbool<K>&>(context->user->instID, ray.instID, valid);
+
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OccludedKEpilogMU
+ {
+ vbool<K>& valid0;
+ RayK<K>& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline OccludedKEpilogMU(vbool<K>& valid0,
+ RayK<K>& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ vbool<K> valid = valid_i;
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* occlusion filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ valid = runOcclusionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(valid,ray.tfar,old_t);
+ }
+ }
+#endif
+
+ /* update occlusion */
+ valid0 = valid0 & !valid;
+ return valid;
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct Intersect1KEpilogM
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<Mx>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ vbool<Mx> valid = valid_i;
+ hit.finalize();
+ if (Mx > M) valid &= (1<<M)-1;
+ size_t i = select_min(valid,hit.vt);
+ assert(i<M);
+ unsigned int geomID = geomIDs[i];
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ bool foundhit = false;
+ goto entry;
+ while (true)
+ {
+ if (unlikely(none(valid))) return foundhit;
+ i = select_min(valid,hit.vt);
+ assert(i<M);
+ geomID = geomIDs[i];
+ entry:
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask[k]) == 0) {
+ clear(valid,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* call intersection filter function */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ assert(i<M);
+ const Vec2f uv = hit.uv(i);
+ HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ foundhit = foundhit | found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ assert(i<M);
+ /* update hit information */
+#if 0 && defined(__AVX512F__) // do not enable, this reduced frequency for BVH4
+ ray.updateK(i,k,hit.vt,hit.vu,hit.vv,vfloat<Mx>(hit.vNg.x),vfloat<Mx>(hit.vNg.y),vfloat<Mx>(hit.vNg.z),geomID,vuint<Mx>(primIDs));
+#else
+ const Vec2f uv = hit.uv(i);
+ ray.tfar[k] = hit.t(i);
+ ray.Ng.x[k] = hit.vNg.x[i];
+ ray.Ng.y[k] = hit.vNg.y[i];
+ ray.Ng.z[k] = hit.vNg.z[i];
+ ray.u[k] = uv.x;
+ ray.v[k] = uv.y;
+ ray.primID[k] = primIDs[i];
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy<const unsigned*, vuint<K>*, const size_t&>(context->user->instID, ray.instID, k);
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct Occluded1KEpilogM
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<Mx>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ if (unlikely(filter))
+ hit.finalize(); /* called only once */
+
+ vbool<Mx> valid = valid_i;
+ if (Mx > M) valid &= (1<<M)-1;
+ size_t m=movemask(valid);
+ goto entry;
+ while (true)
+ {
+ if (unlikely(m == 0)) return false;
+ entry:
+ size_t i=bsf(m);
+
+ const unsigned int geomID = geomIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask[k]) == 0) {
+ m=btc(m,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* execute occlusion filer */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
+ ray.tfar[k] = old_t;
+ m=btc(m,i);
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Intersect1KEpilogMU
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ /* ray mask test */
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* finalize hit calculation */
+ vbool<M> valid = valid_i;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
+ {
+ bool foundhit = false;
+ while (true)
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ foundhit = foundhit | found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
+ if (unlikely(none(valid))) break;
+ i = select_min(valid,hit.vt);
+ }
+ return foundhit;
+ }
+ }
+#endif
+
+ /* update hit information */
+#if 0 && defined(__AVX512F__) // do not enable, this reduced frequency for BVH4
+ const Vec3fa Ng = hit.Ng(i);
+ ray.updateK(i,k,hit.vt,hit.vu,hit.vv,vfloat<M>(Ng.x),vfloat<M>(Ng.y),vfloat<M>(Ng.z),geomID,vuint<M>(primID));
+#else
+ const Vec2f uv = hit.uv(i);
+ const Vec3fa Ng = hit.Ng(i);
+ ray.tfar[k] = hit.t(i);
+ ray.Ng.x[k] = Ng.x;
+ ray.Ng.y[k] = Ng.y;
+ ray.Ng.z[k] = Ng.z;
+ ray.u[k] = uv.x;
+ ray.v[k] = uv.y;
+ ray.primID[k] = primID;
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy<const unsigned*, vuint<K>*, const size_t&>(context->user->instID, ray.instID, k);
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Occluded1KEpilogMU
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ /* ray mask test */
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ hit.finalize();
+ for (size_t m=movemask(valid_i), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
+ ray.tfar[k] = old_t;
+ }
+ return false;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/intersector_iterators.h b/thirdparty/embree-aarch64/kernels/geometry/intersector_iterators.h
new file mode 100644
index 0000000000..5c1ba5cb61
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/intersector_iterators.h
@@ -0,0 +1,172 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+#include "../bvh/node_intersector1.h"
+#include "../bvh/node_intersector_packet.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Intersector>
+ struct ArrayIntersector1
+ {
+ typedef typename Intersector::Primitive Primitive;
+ typedef typename Intersector::Precalculations Precalculations;
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++)
+ Intersector::intersect(pre,ray,context,prim[i]);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ if (Intersector::occluded(pre,ray,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0; i<num; i++)
+ changed |= Intersector::pointQuery(query, context, prim[i]);
+ return changed;
+ }
+
+ template<int K>
+ static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ }
+
+ template<int K>
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ return valid;
+ }
+ };
+
+ template<int K, typename Intersector>
+ struct ArrayIntersectorK_1
+ {
+ typedef typename Intersector::Primitive Primitive;
+ typedef typename Intersector::Precalculations Precalculations;
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ Intersector::intersect(valid,pre,ray,context,prim[i]);
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ vbool<K> valid0 = valid;
+ for (size_t i=0; i<num; i++) {
+ valid0 &= !Intersector::occluded(valid0,pre,ray,context,prim[i]);
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ Intersector::intersect(pre,ray,k,context,prim[i]);
+ }
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ if (Intersector::occluded(pre,ray,k,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+ };
+
+ // =============================================================================================
+
+ template<int K, typename IntersectorK>
+ struct ArrayIntersectorKStream
+ {
+ typedef typename IntersectorK::Primitive PrimitiveK;
+ typedef typename IntersectorK::Precalculations PrecalculationsK;
+
+ static __forceinline void intersectK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(valid,ray); // FIXME: might cause trouble
+
+ for (size_t i=0; i<num; i++) {
+ IntersectorK::intersect(valid,pre,ray,context,prim[i]);
+ }
+ }
+
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(valid,ray); // FIXME: might cause trouble
+ vbool<K> valid0 = valid;
+ for (size_t i=0; i<num; i++) {
+ valid0 &= !IntersectorK::occluded(valid0,pre,ray,context,prim[i]);
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(const Accel::Intersectors* This, RayHitK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ for (size_t i=0; i<num; i++) {
+ IntersectorK::intersect(pre,ray,k,context,prim[i]);
+ }
+ }
+
+ static __forceinline bool occluded(const Accel::Intersectors* This, RayK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ for (size_t i=0; i<num; i++) {
+ if (IntersectorK::occluded(pre,ray,k,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+
+ static __forceinline size_t occluded(const Accel::Intersectors* This, size_t cur_mask, RayK<K>** __restrict__ inputPackets, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ size_t m_occluded = 0;
+ for (size_t i=0; i<num; i++) {
+ size_t bits = cur_mask & (~m_occluded);
+ for (; bits!=0; )
+ {
+ const size_t rayID = bscf(bits);
+ RayHitK<K> &ray = *inputPackets[rayID / K];
+ const size_t k = rayID % K;
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ if (IntersectorK::occluded(pre,ray,k,context,prim[i]))
+ {
+ m_occluded |= (size_t)1 << rayID;
+ ray.tfar[k] = neg_inf;
+ }
+ }
+ }
+ return m_occluded;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/line_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/line_intersector.h
new file mode 100644
index 0000000000..eef5b0b1fd
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/line_intersector.h
@@ -0,0 +1,141 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct LineIntersectorHitM
+ {
+ __forceinline LineIntersectorHitM() {}
+
+ __forceinline LineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct FlatLinearCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Epilog& epilog)
+ {
+ /* transform end points into ray space */
+ vbool<M> valid = valid_i;
+ vfloat<M> depth_scale = pre.depth_scale;
+ LinearSpace3<Vec3vf<M>> ray_space = pre.ray_space;
+
+ const Vec3vf<M> ray_org ((Vec3fa)ray.org);
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+
+ Vec4vf<M> p0(xfmVector(ray_space,v0.xyz()-ray_org), v0.w);
+ Vec4vf<M> p1(xfmVector(ray_space,v1.xyz()-ray_org), v1.w);
+
+ /* approximative intersection with cone */
+ const Vec4vf<M> v = p1-p0;
+ const Vec4vf<M> w = -p0;
+ const vfloat<M> d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloat<M> d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloat<M> u = clamp(d0*rcp(d1),vfloat<M>(zero),vfloat<M>(one));
+ const Vec4vf<M> p = madd(u,v,p0);
+ const vfloat<M> t = p.z;
+ const vfloat<M> d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloat<M> r = p.w;
+ const vfloat<M> r2 = r*r;
+ valid &= (d2 <= r2) & (vfloat<M>(ray.tnear()) <= t) & (t <= vfloat<M>(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; // ignore self intersections
+ if (unlikely(none(valid))) return false;
+
+ /* ignore denormalized segments */
+ const Vec3vf<M> T = v1.xyz()-v0.xyz();
+ valid &= (T.x != vfloat<M>(zero)) | (T.y != vfloat<M>(zero)) | (T.z != vfloat<M>(zero));
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ LineIntersectorHitM<M> hit(u,zero,t,T);
+ return epilog(valid,hit);
+ }
+ };
+
+ template<int M, int K>
+ struct FlatLinearCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Epilog& epilog)
+ {
+ /* transform end points into ray space */
+ vbool<M> valid = valid_i;
+ vfloat<M> depth_scale = pre.depth_scale[k];
+ LinearSpace3<Vec3vf<M>> ray_space = pre.ray_space[k];
+ const Vec3vf<M> ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+
+ Vec4vf<M> p0(xfmVector(ray_space,v0.xyz()-ray_org), v0.w);
+ Vec4vf<M> p1(xfmVector(ray_space,v1.xyz()-ray_org), v1.w);
+
+ /* approximative intersection with cone */
+ const Vec4vf<M> v = p1-p0;
+ const Vec4vf<M> w = -p0;
+ const vfloat<M> d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloat<M> d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloat<M> u = clamp(d0*rcp(d1),vfloat<M>(zero),vfloat<M>(one));
+ const Vec4vf<M> p = madd(u,v,p0);
+ const vfloat<M> t = p.z;
+ const vfloat<M> d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloat<M> r = p.w;
+ const vfloat<M> r2 = r*r;
+ valid &= (d2 <= r2) & (vfloat<M>(ray.tnear()[k]) <= t) & (t <= vfloat<M>(ray.tfar[k]));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; // ignore self intersections
+ if (unlikely(none(valid))) return false;
+
+ /* ignore denormalized segments */
+ const Vec3vf<M> T = v1.xyz()-v0.xyz();
+ valid &= (T.x != vfloat<M>(zero)) | (T.y != vfloat<M>(zero)) | (T.z != vfloat<M>(zero));
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ LineIntersectorHitM<M> hit(u,zero,t,T);
+ return epilog(valid,hit);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/linei.h b/thirdparty/embree-aarch64/kernels/geometry/linei.h
new file mode 100644
index 0000000000..a72029ca53
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/linei.h
@@ -0,0 +1,709 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ template<int M>
+ struct LineMi
+ {
+ /* Virtual interface to query information about the line segment type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored line segments */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N line segments */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ /* Returns required number of bytes for N line segments */
+ static __forceinline size_t bytes(size_t N) { return blocks(N)*sizeof(LineMi); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline LineMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline LineMi(const vuint<M>& v0, unsigned short leftExists, unsigned short rightExists, const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype)
+ : gtype((unsigned char)gtype), m((unsigned char)popcnt(vuint<M>(primIDs) != vuint<M>(-1))), sharedGeomID(geomIDs[0]), leftExists (leftExists), rightExists(rightExists), v0(v0), primIDs(primIDs)
+ {
+ assert(all(vuint<M>(geomID()) == geomIDs));
+ }
+
+ /* Returns a mask that tells which line segments are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns a mask that tells which line segments are valid */
+ template<int Mx>
+ __forceinline vbool<Mx> valid() const { return vuint<Mx>(primIDs) != vuint<Mx>(-1); }
+
+ /* Returns if the specified line segment is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored line segments */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ //template<class T>
+ //static __forceinline T unmask(T &index) { return index & 0x3fffffff; }
+
+ __forceinline unsigned int geomID(unsigned int i = 0) const { return sharedGeomID; }
+ //__forceinline vuint<M> geomID() { return unmask(geomIDs); }
+ //__forceinline const vuint<M> geomID() const { return unmask(geomIDs); }
+ //__forceinline unsigned int geomID(const size_t i) const { assert(i<M); return unmask(geomIDs[i]); }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* gather the line segments */
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom,
+ float time) const;
+
+ /* gather the line segments with lateral info */
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom,
+ float time) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom,
+ float time) const;
+
+ /* Calculate the bounds of the line segments */
+ __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID(i));
+ const Vec3ff& p0 = geom->vertex(v0[i]+0,itime);
+ const Vec3ff& p1 = geom->vertex(v0[i]+1,itime);
+ BBox3fa b = merge(BBox3fa(p0),BBox3fa(p1));
+ b = enlarge(b,Vec3fa(max(p0.w,p1.w)));
+ bounds.extend(b);
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0), bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps) {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID(i));
+ allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID((unsigned int)i));
+ allBounds.extend(geom->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill line segment from line segment list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
+ vuint<M> geomID, primID;
+ vuint<M> v0;
+ unsigned short leftExists = 0;
+ unsigned short rightExists = 0;
+ const PrimRefT* prim = &prims[begin];
+
+ for (size_t i=0; i<M; i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(prim->geomID());
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+ v0[i] = geom->segment(prim->primID());
+ leftExists |= geom->segmentLeftExists(primID[i]) << i;
+ rightExists |= geom->segmentRightExists(primID[i]) << i;
+ begin++;
+ } else {
+ assert(i);
+ if (i>0) {
+ geomID[i] = geomID[i-1];
+ primID[i] = -1;
+ v0[i] = v0[i-1];
+ }
+ }
+ if (begin<end) prim = &prims[begin]; // FIXME: remove this line
+ }
+ new (this) LineMi(v0,leftExists,rightExists,geomID,primID,gty); // FIXME: use non temporal store
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = LineMi::blocks(set.size());
+ size_t numbytes = LineMi::bytes(set.size());
+ LineMi* accel = (LineMi*) alloc.malloc1(numbytes,M*sizeof(float));
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel,items);
+ };
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims,begin,end,scene);
+ return linearBounds(scene,itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims,begin,end,scene);
+ return linearBounds(scene,time_range);
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.begin();
+ size_t end = prims.end();
+ size_t items = LineMi::blocks(prims.size());
+ size_t numbytes = LineMi::bytes(prims.size());
+ LineMi* accel = (LineMi*) alloc.malloc1(numbytes,M*sizeof(float));
+ const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(),start,end,bvh->scene,prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node,bounds,prims.time_range);
+ };
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(LineSegments* geom)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const Vec3ff& p0 = geom->vertex(v0[i]+0);
+ const Vec3ff& p1 = geom->vertex(v0[i]+1);
+ BBox3fa b = merge(BBox3fa(p0),BBox3fa(p1));
+ b = enlarge(b,Vec3fa(max(p0.w,p1.w)));
+ bounds.extend(b);
+ }
+ return bounds;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const LineMi& line) {
+ return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
+ }
+
+ public:
+ unsigned char gtype;
+ unsigned char m;
+ unsigned int sharedGeomID;
+ unsigned short leftExists, rightExists;
+ vuint<M> v0; // index of start vertex
+ private:
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf4 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom) const
+ {
+ gather(p0,p1,geom);
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ gatheri(p0,p1,geom,itime);
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf4 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1,itime)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1,itime)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1,itime)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1,itime)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2,itime)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2,itime)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2,itime)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2,itime)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1,aL,aR;
+ gatheri(a0,a1,aL,aR,geom,itime);
+ Vec4vf4 b0,b1,bL,bR;
+ gatheri(b0,b1,bL,bR,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ pL = lerp(aL,bL,vfloat4(ftime));
+ pR = lerp(aR,bR,vfloat4(ftime));
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4]));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5]));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6]));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7]));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4],itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5],itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6],itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7],itime));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1,itime));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1,itime));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1,itime));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1,itime));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf8 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4]));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5]));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6]));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7]));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1)) : vfloat4(inf);
+ const vfloat4 l4 = (leftExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]-1)) : vfloat4(inf);
+ const vfloat4 l5 = (leftExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]-1)) : vfloat4(inf);
+ const vfloat4 l6 = (leftExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]-1)) : vfloat4(inf);
+ const vfloat4 l7 = (leftExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]-1)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,l4,l5,l6,l7,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2)) : vfloat4(inf);
+ const vfloat4 r4 = (rightExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]+2)) : vfloat4(inf);
+ const vfloat4 r5 = (rightExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]+2)) : vfloat4(inf);
+ const vfloat4 r6 = (rightExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]+2)) : vfloat4(inf);
+ const vfloat4 r7 = (rightExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]+2)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,r4,r5,r6,r7,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4],itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5],itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6],itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7],itime));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1,itime));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1,itime));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1,itime));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1,itime));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1,itime)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1,itime)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1,itime)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1,itime)) : vfloat4(inf);
+ const vfloat4 l4 = (leftExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]-1,itime)) : vfloat4(inf);
+ const vfloat4 l5 = (leftExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]-1,itime)) : vfloat4(inf);
+ const vfloat4 l6 = (leftExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]-1,itime)) : vfloat4(inf);
+ const vfloat4 l7 = (leftExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]-1,itime)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,l4,l5,l6,l7,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2,itime)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2,itime)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2,itime)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2,itime)) : vfloat4(inf);
+ const vfloat4 r4 = (rightExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]+2,itime)) : vfloat4(inf);
+ const vfloat4 r5 = (rightExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]+2,itime)) : vfloat4(inf);
+ const vfloat4 r6 = (rightExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]+2,itime)) : vfloat4(inf);
+ const vfloat4 r7 = (rightExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]+2,itime)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,r4,r5,r6,r7,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1,aL,aR;
+ gatheri(a0,a1,aL,aR,geom,itime);
+ Vec4vf8 b0,b1,bL,bR;
+ gatheri(b0,b1,bL,bR,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ pL = lerp(aL,bL,vfloat8(ftime));
+ pR = lerp(aR,bR,vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom) const
+ {
+ gather(p0,p1,geom);
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ gatheri(p0,p1,geom,itime);
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf8 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+#endif
+
+ template<int M>
+ typename LineMi<M>::Type LineMi<M>::type;
+
+ typedef LineMi<4> Line4i;
+ typedef LineMi<8> Line8i;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/linei_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/linei_intersector.h
new file mode 100644
index 0000000000..a431796a88
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/linei_intersector.h
@@ -0,0 +1,124 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "linei.h"
+#include "line_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, int Mx, bool filter>
+ struct FlatLinearCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ FlatLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return FlatLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct FlatLinearCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ FlatLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return FlatLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct FlatLinearCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ FlatLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return FlatLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct FlatLinearCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ FlatLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return FlatLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/object.h b/thirdparty/embree-aarch64/kernels/geometry/object.h
new file mode 100644
index 0000000000..f26391de52
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/object.h
@@ -0,0 +1,84 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ struct Object
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return N; }
+
+ public:
+
+ /*! constructs a virtual object */
+ Object (unsigned geomID, unsigned primID)
+ : _geomID(geomID), _primID(primID) {}
+
+ __forceinline unsigned geomID() const {
+ return _geomID;
+ }
+
+ __forceinline unsigned primID() const {
+ return _primID;
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& i, size_t end, Scene* scene)
+ {
+ const PrimRef& prim = prims[i]; i++;
+ new (this) Object(prim.geomID(), prim.primID());
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& i, size_t end, Scene* scene, size_t itime)
+ {
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ new (this) Object(geomID, primID);
+ AccelSet* accel = (AccelSet*) scene->get(geomID);
+ return accel->linearBounds(primID,itime);
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ const PrimRefMB& prim = prims[i]; i++;
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ new (this) Object(geomID, primID);
+ AccelSet* accel = (AccelSet*) scene->get(geomID);
+ return accel->linearBounds(primID,time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(AccelSet* mesh) {
+ return mesh->bounds(primID());
+ }
+
+ private:
+ unsigned int _geomID; //!< geometry ID
+ unsigned int _primID; //!< primitive ID
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/object_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/object_intersector.h
new file mode 100644
index 0000000000..97882e0e59
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/object_intersector.h
@@ -0,0 +1,127 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "object.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<bool mblur>
+ struct ObjectIntersector1
+ {
+ typedef Object Primitive;
+
+ static const bool validIntersectorK = false;
+
+ struct Precalculations {
+ __forceinline Precalculations() {}
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ if ((ray.mask & accel->mask) == 0)
+ return;
+#endif
+
+ accel->intersect(ray,prim.geomID(),prim.primID(),context,reportIntersection1);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ if ((ray.mask & accel->mask) == 0)
+ return false;
+#endif
+
+ accel->occluded(ray,prim.geomID(),prim.primID(),context,&reportOcclusion1);
+ return ray.tfar < 0.0f;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*)context->scene->get(prim.geomID());
+ context->geomID = prim.geomID();
+ context->primID = prim.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<int K>
+ static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(false);
+ }
+
+ template<int K>
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(false);
+ return valid;
+ }
+ };
+
+ template<int K, bool mblur>
+ struct ObjectIntersectorK
+ {
+ typedef Object Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static __forceinline void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vbool<K> valid = valid_i;
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (ray.mask & accel->mask) != 0;
+ if (none(valid)) return;
+#endif
+ accel->intersect(valid,ray,prim.geomID(),prim.primID(),context,&reportIntersection1);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vbool<K> valid = valid_i;
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (ray.mask & accel->mask) != 0;
+ if (none(valid)) return false;
+#endif
+ accel->occluded(valid,ray,prim.geomID(),prim.primID(),context,&reportOcclusion1);
+ return ray.tfar < 0.0f;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+
+ typedef ObjectIntersectorK<4,false> ObjectIntersector4;
+ typedef ObjectIntersectorK<8,false> ObjectIntersector8;
+ typedef ObjectIntersectorK<16,false> ObjectIntersector16;
+
+ typedef ObjectIntersectorK<4,true> ObjectIntersector4MB;
+ typedef ObjectIntersectorK<8,true> ObjectIntersector8MB;
+ typedef ObjectIntersectorK<16,true> ObjectIntersector16MB;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/plane.h b/thirdparty/embree-aarch64/kernels/geometry/plane.h
new file mode 100644
index 0000000000..ebe45db558
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/plane.h
@@ -0,0 +1,57 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct HalfPlane
+ {
+ const Vec3fa P; //!< plane origin
+ const Vec3fa N; //!< plane normal
+
+ __forceinline HalfPlane(const Vec3fa& P, const Vec3fa& N)
+ : P(P), N(N) {}
+
+ __forceinline BBox1f intersect(const Vec3fa& ray_org, const Vec3fa& ray_dir) const
+ {
+ Vec3fa O = Vec3fa(ray_org) - P;
+ Vec3fa D = Vec3fa(ray_dir);
+ float ON = dot(O,N);
+ float DN = dot(D,N);
+ bool eps = abs(DN) < min_rcp_input;
+ float t = -ON*rcp(DN);
+ float lower = select(eps || DN < 0.0f, float(neg_inf), t);
+ float upper = select(eps || DN > 0.0f, float(pos_inf), t);
+ return BBox1f(lower,upper);
+ }
+ };
+
+ template<int M>
+ struct HalfPlaneN
+ {
+ const Vec3vf<M> P; //!< plane origin
+ const Vec3vf<M> N; //!< plane normal
+
+ __forceinline HalfPlaneN(const Vec3vf<M>& P, const Vec3vf<M>& N)
+ : P(P), N(N) {}
+
+ __forceinline BBox<vfloat<M>> intersect(const Vec3fa& ray_org, const Vec3fa& ray_dir) const
+ {
+ Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray_org) - P;
+ Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray_dir);
+ vfloat<M> ON = dot(O,N);
+ vfloat<M> DN = dot(D,N);
+ vbool<M> eps = abs(DN) < min_rcp_input;
+ vfloat<M> t = -ON*rcp(DN);
+ vfloat<M> lower = select(eps | DN < 0.0f, vfloat<M>(neg_inf), t);
+ vfloat<M> upper = select(eps | DN > 0.0f, vfloat<M>(pos_inf), t);
+ return BBox<vfloat<M>>(lower,upper);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/pointi.h b/thirdparty/embree-aarch64/kernels/geometry/pointi.h
new file mode 100644
index 0000000000..4ba298e86b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/pointi.h
@@ -0,0 +1,417 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ template<int M>
+ struct PointMi
+ {
+ /* Virtual interface to query information about the line segment type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored line segments */
+ static __forceinline size_t max_size()
+ {
+ return M;
+ }
+
+ /* Returns required number of primitive blocks for N line segments */
+ static __forceinline size_t blocks(size_t N)
+ {
+ return (N + max_size() - 1) / max_size();
+ }
+
+ /* Returns required number of bytes for N line segments */
+ static __forceinline size_t bytes(size_t N)
+ {
+ return blocks(N) * sizeof(PointMi);
+ }
+
+ public:
+ /* Default constructor */
+ __forceinline PointMi() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline PointMi(const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype, uint32_t numPrimitives)
+ : gtype((unsigned char)gtype),
+ numPrimitives(numPrimitives),
+ sharedGeomID(geomIDs[0]),
+ primIDs(primIDs)
+ {
+ assert(all(vuint<M>(geomID()) == geomIDs));
+ }
+
+ /* Returns a mask that tells which line segments are valid */
+ __forceinline vbool<M> valid() const {
+ return vint<M>(step) < vint<M>(numPrimitives);
+ }
+
+ /* Returns a mask that tells which line segments are valid */
+ template<int Mx> __forceinline vbool<Mx> valid() const {
+ return vint<Mx>(step) < vint<Mx>(numPrimitives);
+ }
+
+ /* Returns if the specified line segment is valid */
+ __forceinline bool valid(const size_t i) const
+ {
+ assert(i < M);
+ return i < numPrimitives;
+ }
+
+ /* Returns the number of stored line segments */
+ __forceinline size_t size() const {
+ return numPrimitives;
+ }
+
+ __forceinline unsigned int geomID(unsigned int i = 0) const {
+ return sharedGeomID;
+ }
+
+ __forceinline vuint<M>& primID() {
+ return primIDs;
+ }
+ __forceinline const vuint<M>& primID() const {
+ return primIDs;
+ }
+ __forceinline unsigned int primID(const size_t i) const {
+ assert(i < M);
+ return primIDs[i];
+ }
+
+ /* gather the line segments */
+ __forceinline void gather(Vec4vf<M>& p0, const Points* geom) const;
+ __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0, const Points* geom, const int itime) const;
+ __forceinline void gatheri(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0, const Points* geom, float time) const;
+ __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, float time) const;
+
+ /* Calculate the bounds of the line segments */
+ __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID(i));
+ bounds.extend(geom->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
+ return LBBox3fa(bounds(scene, itime + 0), bounds(scene, itime + 1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID(i));
+ allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID((unsigned int)i));
+ allBounds.extend(geom->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill line segment from line segment list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
+ vuint<M> geomID, primID;
+ vuint<M> v0;
+ const PrimRefT* prim = &prims[begin];
+
+ int numPrimitives = 0;
+ for (size_t i = 0; i < M; i++) {
+ if (begin < end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+ begin++;
+ numPrimitives++;
+ } else {
+ assert(i);
+ if (i > 0) {
+ geomID[i] = geomID[i - 1];
+ primID[i] = primID[i - 1];
+ }
+ }
+ if (begin < end)
+ prim = &prims[begin]; // FIXME: remove this line
+ }
+ new (this) PointMi(geomID, primID, gty, numPrimitives); // FIXME: use non temporal store
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf(BVH* bvh,
+ const PrimRef* prims,
+ const range<size_t>& set,
+ const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = PointMi::blocks(set.size());
+ size_t numbytes = PointMi::bytes(set.size());
+ PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
+ for (size_t i = 0; i < items; i++) {
+ accel[i].fill(prims, start, set.end(), bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel, items);
+ };
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(
+ const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.object_range.begin();
+ size_t end = prims.object_range.end();
+ size_t items = PointMi::blocks(prims.object_range.size());
+ size_t numbytes = PointMi::bytes(prims.object_range.size());
+ PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
+ const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel, items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i = 0; i < items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(), start, end, bvh->scene, prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node, bounds, prims.time_range);
+ };
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PointMi& line)
+ {
+ return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
+ }
+
+ public:
+ unsigned char gtype;
+ unsigned char numPrimitives;
+ unsigned int sharedGeomID;
+
+ private:
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
+ transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
+ transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0; gatheri(a0, geom, itime);
+ Vec4vf4 b0; gatheri(b0, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat4(ftime));
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0, b0;
+ Vec3vf4 norm0, norm1;
+ gatheri(a0, norm0, geom, itime);
+ gatheri(b0, norm1, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat4(ftime));
+ n0 = lerp(norm0, norm1, vfloat4(ftime));
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
+ const vfloat4 b4 = vfloat4(geom->normal(primID(4)));
+ const vfloat4 b5 = vfloat4(geom->normal(primID(5)));
+ const vfloat4 b6 = vfloat4(geom->normal(primID(6)));
+ const vfloat4 b7 = vfloat4(geom->normal(primID(7)));
+ transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
+ const vfloat4 b4 = vfloat4(geom->normal(primID(4), itime));
+ const vfloat4 b5 = vfloat4(geom->normal(primID(5), itime));
+ const vfloat4 b6 = vfloat4(geom->normal(primID(6), itime));
+ const vfloat4 b7 = vfloat4(geom->normal(primID(7), itime));
+ transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0;
+ gatheri(a0, geom, itime);
+ Vec4vf8 b0;
+ gatheri(b0, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0, b0;
+ Vec3vf8 norm0, norm1;
+ gatheri(a0, norm0, geom, itime);
+ gatheri(b0, norm1, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat8(ftime));
+ n0 = lerp(norm0, norm1, vfloat8(ftime));
+ }
+#endif
+
+ template<int M>
+ typename PointMi<M>::Type PointMi<M>::type;
+
+ typedef PointMi<4> Point4i;
+ typedef PointMi<8> Point8i;
+
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/geometry/primitive.h b/thirdparty/embree-aarch64/kernels/geometry/primitive.h
new file mode 100644
index 0000000000..41e5b2b304
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/primitive.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/scene.h"
+#include "../../common/simd/simd.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+
+namespace embree
+{
+ struct PrimitiveType
+ {
+ /*! returns name of this primitive type */
+ virtual const char* name() const = 0;
+
+ /*! Returns the number of stored active primitives in a block. */
+ virtual size_t sizeActive(const char* This) const = 0;
+
+ /*! Returns the number of stored active and inactive primitives in a block. */
+ virtual size_t sizeTotal(const char* This) const = 0;
+
+ /*! Returns the number of bytes of block. */
+ virtual size_t getBytes(const char* This) const = 0;
+ };
+
+ template<typename Primitive>
+ struct PrimitivePointQuery1
+ {
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim)
+ {
+ bool changed = false;
+ for (size_t i = 0; i < Primitive::max_size(); i++)
+ {
+ if (!prim.valid(i)) break;
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(prim.geomID(i));
+ context->geomID = prim.geomID(i);
+ context->primID = prim.primID(i);
+ changed |= accel->pointQuery(query, context);
+ }
+ return changed;
+ }
+
+ static __forceinline void pointQueryNoop(PointQuery* query, PointQueryContext* context, const Primitive& prim) { }
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/primitive4.cpp b/thirdparty/embree-aarch64/kernels/geometry/primitive4.cpp
new file mode 100644
index 0000000000..f93574c9c8
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/primitive4.cpp
@@ -0,0 +1,379 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primitive.h"
+#include "curveNv.h"
+#include "curveNi.h"
+#include "curveNi_mb.h"
+#include "linei.h"
+#include "triangle.h"
+#include "trianglev.h"
+#include "trianglev_mb.h"
+#include "trianglei.h"
+#include "quadv.h"
+#include "quadi.h"
+#include "subdivpatch1.h"
+#include "object.h"
+#include "instance.h"
+#include "subgrid.h"
+
+namespace embree
+{
+ /********************** Curve4v **************************/
+
+ template<>
+ const char* Curve4v::Type::name () const {
+ return "curve4v";
+ }
+
+ template<>
+ size_t Curve4v::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4v*)This)->N;
+ }
+
+ template<>
+ size_t Curve4v::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4v*)This)->N;
+ }
+
+ template<>
+ size_t Curve4v::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4v::bytes(sizeActive(This));
+ }
+
+ /********************** Curve4i **************************/
+
+ template<>
+ const char* Curve4i::Type::name () const {
+ return "curve4i";
+ }
+
+ template<>
+ size_t Curve4i::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4i*)This)->N;
+ }
+
+ template<>
+ size_t Curve4i::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4i*)This)->N;
+ }
+
+ template<>
+ size_t Curve4i::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4i::bytes(sizeActive(This));
+ }
+
+ /********************** Curve4iMB **************************/
+
+ template<>
+ const char* Curve4iMB::Type::name () const {
+ return "curve4imb";
+ }
+
+ template<>
+ size_t Curve4iMB::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4iMB*)This)->N;
+ }
+
+ template<>
+ size_t Curve4iMB::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4iMB*)This)->N;
+ }
+
+ template<>
+ size_t Curve4iMB::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4iMB::bytes(sizeActive(This));
+ }
+
+ /********************** Line4i **************************/
+
+ template<>
+ const char* Line4i::Type::name () const {
+ return "line4i";
+ }
+
+ template<>
+ size_t Line4i::Type::sizeActive(const char* This) const {
+ return ((Line4i*)This)->size();
+ }
+
+ template<>
+ size_t Line4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Line4i::Type::getBytes(const char* This) const {
+ return sizeof(Line4i);
+ }
+
+ /********************** Triangle4 **************************/
+
+ template<>
+ const char* Triangle4::Type::name () const {
+ return "triangle4";
+ }
+
+ template<>
+ size_t Triangle4::Type::sizeActive(const char* This) const {
+ return ((Triangle4*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4);
+ }
+
+ /********************** Triangle4v **************************/
+
+ template<>
+ const char* Triangle4v::Type::name () const {
+ return "triangle4v";
+ }
+
+ template<>
+ size_t Triangle4v::Type::sizeActive(const char* This) const {
+ return ((Triangle4v*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4v::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4v::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4v);
+ }
+
+ /********************** Triangle4i **************************/
+
+ template<>
+ const char* Triangle4i::Type::name () const {
+ return "triangle4i";
+ }
+
+ template<>
+ size_t Triangle4i::Type::sizeActive(const char* This) const {
+ return ((Triangle4i*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4i::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4i);
+ }
+
+ /********************** Triangle4vMB **************************/
+
+ template<>
+ const char* Triangle4vMB::Type::name () const {
+ return "triangle4vmb";
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::sizeActive(const char* This) const {
+ return ((Triangle4vMB*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4vMB);
+ }
+
+ /********************** Quad4v **************************/
+
+ template<>
+ const char* Quad4v::Type::name () const {
+ return "quad4v";
+ }
+
+ template<>
+ size_t Quad4v::Type::sizeActive(const char* This) const {
+ return ((Quad4v*)This)->size();
+ }
+
+ template<>
+ size_t Quad4v::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Quad4v::Type::getBytes(const char* This) const {
+ return sizeof(Quad4v);
+ }
+
+ /********************** Quad4i **************************/
+
+ template<>
+ const char* Quad4i::Type::name () const {
+ return "quad4i";
+ }
+
+ template<>
+ size_t Quad4i::Type::sizeActive(const char* This) const {
+ return ((Quad4i*)This)->size();
+ }
+
+ template<>
+ size_t Quad4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Quad4i::Type::getBytes(const char* This) const {
+ return sizeof(Quad4i);
+ }
+
+ /********************** SubdivPatch1 **************************/
+
+ const char* SubdivPatch1::Type::name () const {
+ return "subdivpatch1";
+ }
+
+ size_t SubdivPatch1::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t SubdivPatch1::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t SubdivPatch1::Type::getBytes(const char* This) const {
+ return sizeof(SubdivPatch1);
+ }
+
+ SubdivPatch1::Type SubdivPatch1::type;
+
+ /********************** Virtual Object **************************/
+
+ const char* Object::Type::name () const {
+ return "object";
+ }
+
+ size_t Object::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t Object::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t Object::Type::getBytes(const char* This) const {
+ return sizeof(Object);
+ }
+
+ Object::Type Object::type;
+
+ /********************** Instance **************************/
+
+ const char* InstancePrimitive::Type::name () const {
+ return "instance";
+ }
+
+ size_t InstancePrimitive::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t InstancePrimitive::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t InstancePrimitive::Type::getBytes(const char* This) const {
+ return sizeof(InstancePrimitive);
+ }
+
+ InstancePrimitive::Type InstancePrimitive::type;
+
+ /********************** SubGrid **************************/
+
+ const char* SubGrid::Type::name () const {
+ return "subgrid";
+ }
+
+ size_t SubGrid::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t SubGrid::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t SubGrid::Type::getBytes(const char* This) const {
+ return sizeof(SubGrid);
+ }
+
+ SubGrid::Type SubGrid::type;
+
+ /********************** SubGridQBVH4 **************************/
+
+ template<>
+ const char* SubGridQBVH4::Type::name () const {
+ return "SubGridQBVH4";
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::getBytes(const char* This) const {
+ return sizeof(SubGridQBVH4);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quad_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector.h
new file mode 100644
index 0000000000..57ff4e60e5
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector.h
@@ -0,0 +1,76 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects a ray with a quad with backface culling
+ * enabled. The quad v0,v1,v2,v3 is split into two triangles
+ * v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two
+ * triangles gets intersected. */
+ template<int N>
+ __forceinline vbool<N> intersect_quad_backface_culling(const vbool<N>& valid0,
+ const Vec3fa& ray_org,
+ const Vec3fa& ray_dir,
+ const float ray_tnear,
+ const float ray_tfar,
+ const Vec3vf<N>& quad_v0,
+ const Vec3vf<N>& quad_v1,
+ const Vec3vf<N>& quad_v2,
+ const Vec3vf<N>& quad_v3,
+ vfloat<N>& u_o,
+ vfloat<N>& v_o,
+ vfloat<N>& t_o)
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<N> valid = valid0;
+ const Vec3vf<N> O = Vec3vf<N>(ray_org);
+ const Vec3vf<N> D = Vec3vf<N>(ray_dir);
+ const Vec3vf<N> va = quad_v0-O;
+ const Vec3vf<N> vb = quad_v1-O;
+ const Vec3vf<N> vc = quad_v2-O;
+ const Vec3vf<N> vd = quad_v3-O;
+
+ const Vec3vf<N> edb = vb-vd;
+ const vfloat<N> WW = dot(cross(vd,edb),D);
+ const Vec3vf<N> v0 = select(WW <= 0.0f,va,vc);
+ const Vec3vf<N> v1 = select(WW <= 0.0f,vb,vd);
+ const Vec3vf<N> v2 = select(WW <= 0.0f,vd,vb);
+
+ /* calculate edges */
+ const Vec3vf<N> e0 = v2-v0;
+ const Vec3vf<N> e1 = v0-v1;
+
+ /* perform edge tests */
+ const vfloat<N> U = dot(cross(v0,e0),D);
+ const vfloat<N> V = dot(cross(v1,e1),D);
+ valid &= max(U,V) <= 0.0f;
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<N> Ng = cross(e1,e0);
+ const vfloat<N> den = dot(Ng,D);
+ const vfloat<N> rcpDen = rcp(den);
+
+ /* perform depth test */
+ const vfloat<N> t = rcpDen*dot(v0,Ng);
+ valid &= vfloat<N>(ray_tnear) <= t & t <= vfloat<N>(ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<N>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ t_o = t;
+ u_o = U * rcpDen;
+ v_o = V * rcpDen;
+ u_o = select(WW <= 0.0f,u_o,1.0f-u_o);
+ v_o = select(WW <= 0.0f,v_o,1.0f-v_o);
+ return valid;
+ }
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_moeller.h b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_moeller.h
new file mode 100644
index 0000000000..74e8c7720c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_moeller.h
@@ -0,0 +1,566 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadv.h"
+#include "triangle_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct QuadHitM
+ {
+ __forceinline QuadHitM() {}
+
+ __forceinline QuadHitM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& T,
+ const vfloat<M>& absDen,
+ const Vec3vf<M>& Ng,
+ const vbool<M>& flags)
+ : U(U), V(V), T(T), absDen(absDen), tri_Ng(Ng), valid(valid), flags(flags) {}
+
+ __forceinline void finalize()
+ {
+ const vfloat<M> rcpAbsDen = rcp(absDen);
+ vt = T * rcpAbsDen;
+ const vfloat<M> u = min(U * rcpAbsDen,1.0f);
+ const vfloat<M> v = min(V * rcpAbsDen,1.0f);
+ const vfloat<M> u1 = vfloat<M>(1.0f) - u;
+ const vfloat<M> v1 = vfloat<M>(1.0f) - v;
+#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
+ vu = select(flags,u1,u);
+ vv = select(flags,v1,v);
+ vNg = Vec3vf<M>(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+#else
+ const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
+ vv = select(flags,u1,v);
+ vu = select(flags,v1,u);
+ vNg = Vec3vf<M>(flip*tri_Ng.x,flip*tri_Ng.y,flip*tri_Ng.z);
+#endif
+ }
+
+ __forceinline Vec2f uv(const size_t i)
+ {
+ const float u = vu[i];
+ const float v = vv[i];
+ return Vec2f(u,v);
+ }
+
+ __forceinline float t(const size_t i) { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ vfloat<M> absDen;
+ Vec3vf<M> tri_Ng;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+
+ public:
+ const vbool<M> flags;
+ };
+
+ template<int K>
+ struct QuadHitK
+ {
+ __forceinline QuadHitK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& T,
+ const vfloat<K>& absDen,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags)
+ : U(U), V(V), T(T), absDen(absDen), flags(flags), tri_Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u0 = min(U * rcpAbsDen,1.0f);
+ const vfloat<K> v0 = min(V * rcpAbsDen,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> u = select(flags,u1,u0);
+ const vfloat<K> v = select(flags,v1,v0);
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+ };
+
+ /* ----------------------------- */
+ /* -- single ray intersectors -- */
+ /* ----------------------------- */
+
+
+ template<int M, bool filter>
+ struct QuadMIntersector1MoellerTrumbore;
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMIntersector1MoellerTrumbore
+ {
+ __forceinline QuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Intersect1EpilogM<M,M,filter> epilog(ray,context,geomID,primID);
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,hit))
+ epilog(hit.valid,hit);
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Occluded1EpilogM<M,M,filter> epilog(ray,context,geomID,primID);
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,hit))
+ {
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+ return false;
+ }
+ };
+
+#if defined(__AVX512ER__) // KNL
+
+ /*! Intersects 4 quads with 1 ray using AVX512 */
+ template<bool filter>
+ struct QuadMIntersector1MoellerTrumbore<4,filter>
+ {
+ __forceinline QuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf16 vtx0(select(0x0f0f,vfloat16(v0.x),vfloat16(v2.x)),
+ select(0x0f0f,vfloat16(v0.y),vfloat16(v2.y)),
+ select(0x0f0f,vfloat16(v0.z),vfloat16(v2.z)));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf16 vtx1(vfloat16(v1.x),vfloat16(v1.y),vfloat16(v1.z));
+ const Vec3vf16 vtx2(vfloat16(v3.x),vfloat16(v3.y),vfloat16(v3.z));
+#else
+ const Vec3vf16 vtx1(select(0x0f0f,vfloat16(v1.x),vfloat16(v3.x)),
+ select(0x0f0f,vfloat16(v1.y),vfloat16(v3.y)),
+ select(0x0f0f,vfloat16(v1.z),vfloat16(v3.z)));
+ const Vec3vf16 vtx2(select(0x0f0f,vfloat16(v3.x),vfloat16(v1.x)),
+ select(0x0f0f,vfloat16(v3.y),vfloat16(v1.y)),
+ select(0x0f0f,vfloat16(v3.z),vfloat16(v1.z)));
+#endif
+ const vbool16 flags(0xf0f0);
+
+ MoellerTrumboreHitM<16> hit;
+ MoellerTrumboreIntersector1<16> intersector(ray,nullptr);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,hit)))
+ {
+ vfloat16 U = hit.U, V = hit.V, absDen = hit.absDen;
+#if !defined(EMBREE_BACKFACE_CULLING)
+ hit.U = select(flags,absDen-V,U);
+ hit.V = select(flags,absDen-U,V);
+ hit.vNg *= select(flags,vfloat16(-1.0f),vfloat16(1.0f)); // FIXME: use XOR
+#else
+ hit.U = select(flags,absDen-U,U);
+ hit.V = select(flags,absDen-V,V);
+#endif
+ if (likely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,16,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,16,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#elif defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct QuadMIntersector1MoellerTrumbore<4,filter>
+ {
+ __forceinline QuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ MoellerTrumboreHitM<8> hit;
+ MoellerTrumboreIntersector1<8> intersector(ray,nullptr);
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,hit)))
+ {
+ vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
+
+#if !defined(EMBREE_BACKFACE_CULLING)
+ hit.U = select(flags,absDen-V,U);
+ hit.V = select(flags,absDen-U,V);
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f)); // FIXME: use XOR
+#else
+ hit.U = select(flags,absDen-U,U);
+ hit.V = select(flags,absDen-V,V);
+#endif
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+
+ struct MoellerTrumboreIntersector1KTriangleM
+ {
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Vec3vf<M>& tri_Ng,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate denominator */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
+ const Vec3vf<M> R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
+ const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ QuadHitM<M> hit(valid,U,V,T,absDen,tri_Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ const Vec3vf<M> Ng = cross(e2,e1);
+ return intersect(ray,k,v0,e1,e2,Ng,flags,epilog);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumboreBase
+ {
+ __forceinline QuadMIntersectorKMoellerTrumboreBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray.org;
+ const Vec3vf<K> R = cross(C,ray.dir);
+ const vfloat<K> den = dot(tri_Ng,ray.dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(R,tri_e2) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(R,tri_e1) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray.tnear() < T) & (T <= absDen*ray.tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ QuadHitK<K> hit(U,V,T,absDen,tri_Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray,tri_v0,e1,e2,Ng,flags,epilog);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),epilog);
+ return none(valid0);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumbore : public QuadMIntersectorKMoellerTrumboreBase<M,K,filter>
+ {
+ __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1KEpilogM<M,M,K,filter> epilog(ray,k,context,geomID,primID);
+ MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,v0,v1,v3,vbool<M>(false),epilog);
+ MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,v2,v3,v1,vbool<M>(true ),epilog);
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1KEpilogM<M,M,K,filter> epilog(ray,k,context,geomID,primID);
+ if (MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+
+#if defined(__AVX512ER__) // KNL
+
+ /*! Intersects 4 quads with 1 ray using AVX512 */
+ template<int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumbore<4,K,filter> : public QuadMIntersectorKMoellerTrumboreBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf16 vtx0(select(0x0f0f,vfloat16(v0.x),vfloat16(v2.x)),
+ select(0x0f0f,vfloat16(v0.y),vfloat16(v2.y)),
+ select(0x0f0f,vfloat16(v0.z),vfloat16(v2.z)));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf16 vtx1(vfloat16(v1.x),vfloat16(v1.y),vfloat16(v1.z));
+ const Vec3vf16 vtx2(vfloat16(v3.x),vfloat16(v3.y),vfloat16(v3.z));
+#else
+ const Vec3vf16 vtx1(select(0x0f0f,vfloat16(v1.x),vfloat16(v3.x)),
+ select(0x0f0f,vfloat16(v1.y),vfloat16(v3.y)),
+ select(0x0f0f,vfloat16(v1.z),vfloat16(v3.z)));
+ const Vec3vf16 vtx2(select(0x0f0f,vfloat16(v3.x),vfloat16(v1.x)),
+ select(0x0f0f,vfloat16(v3.y),vfloat16(v1.y)),
+ select(0x0f0f,vfloat16(v3.z),vfloat16(v1.z)));
+#endif
+ const vbool16 flags(0xf0f0);
+ return MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,16,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,16,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#elif defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumbore<4,K,filter> : public QuadMIntersectorKMoellerTrumboreBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ return MoellerTrumboreIntersector1KTriangleM::intersect1(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_pluecker.h b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_pluecker.h
new file mode 100644
index 0000000000..7ca3aed0a0
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quad_intersector_pluecker.h
@@ -0,0 +1,529 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quad_intersector_moeller.h"
+
+/*! Modified Pluecker ray/triangle intersector. The test first shifts
+ * the ray origin into the origin of the coordinate system and then
+ * uses Pluecker coordinates for the intersection. Due to the shift,
+ * the Pluecker coordinate calculation simplifies and the tests get
+ * numerically stable. The edge equations are watertight along the
+ * edge for neighboring triangles. */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct QuadHitPlueckerM
+ {
+ __forceinline QuadHitPlueckerM() {}
+
+ __forceinline QuadHitPlueckerM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& UVW,
+ const vfloat<M>& t,
+ const Vec3vf<M>& Ng,
+ const vbool<M>& flags)
+ : U(U), V(V), UVW(UVW), tri_Ng(Ng), valid(valid), vt(t), flags(flags) {}
+
+ __forceinline void finalize()
+ {
+ const vbool<M> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
+ const vfloat<M> u = min(U * rcpUVW,1.0f);
+ const vfloat<M> v = min(V * rcpUVW,1.0f);
+ const vfloat<M> u1 = vfloat<M>(1.0f) - u;
+ const vfloat<M> v1 = vfloat<M>(1.0f) - v;
+#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
+ vu = select(flags,u1,u);
+ vv = select(flags,v1,v);
+ vNg = Vec3vf<M>(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+#else
+ const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
+ vv = select(flags,u1,v);
+ vu = select(flags,v1,u);
+ vNg = Vec3vf<M>(flip*tri_Ng.x,flip*tri_Ng.y,flip*tri_Ng.z);
+#endif
+ }
+
+ __forceinline Vec2f uv(const size_t i)
+ {
+ const float u = vu[i];
+ const float v = vv[i];
+ return Vec2f(u,v);
+ }
+
+ __forceinline float t(const size_t i) { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> UVW;
+ Vec3vf<M> tri_Ng;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+
+ public:
+ const vbool<M> flags;
+ };
+
+ template<int K>
+ struct QuadHitPlueckerK
+ {
+ __forceinline QuadHitPlueckerK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& UVW,
+ const vfloat<K>& t,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags)
+ : U(U), V(V), UVW(UVW), t(t), flags(flags), tri_Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vbool<K> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
+ const vfloat<K> u0 = min(U * rcpUVW,1.0f);
+ const vfloat<K> v0 = min(V * rcpUVW,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> u = select(flags,u1,u0);
+ const vfloat<K> v = select(flags,v1,v0);
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> UVW;
+ const vfloat<K> t;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+ };
+
+ struct PlueckerIntersectorTriangle1
+ {
+ template<int M, typename Epilog>
+ static __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMIntersector1Pluecker
+ {
+ __forceinline QuadMIntersector1Pluecker() {}
+
+ __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1EpilogM<M,M,filter> epilog(ray,context,geomID,primID);
+ PlueckerIntersectorTriangle1::intersect(ray,v0,v1,v3,vbool<M>(false),epilog);
+ PlueckerIntersectorTriangle1::intersect(ray,v2,v3,v1,vbool<M>(true),epilog);
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1EpilogM<M,M,filter> epilog(ray,context,geomID,primID);
+ if (PlueckerIntersectorTriangle1::intersect(ray,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (PlueckerIntersectorTriangle1::intersect(ray,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+#if defined(__AVX512ER__) // KNL
+
+ /*! Intersects 4 quads with 1 ray using AVX512 */
+ template<bool filter>
+ struct QuadMIntersector1Pluecker<4,filter>
+ {
+ __forceinline QuadMIntersector1Pluecker() {}
+
+ __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf16 vtx0(select(0x0f0f,vfloat16(v0.x),vfloat16(v2.x)),
+ select(0x0f0f,vfloat16(v0.y),vfloat16(v2.y)),
+ select(0x0f0f,vfloat16(v0.z),vfloat16(v2.z)));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf16 vtx1(vfloat16(v1.x),vfloat16(v1.y),vfloat16(v1.z));
+ const Vec3vf16 vtx2(vfloat16(v3.x),vfloat16(v3.y),vfloat16(v3.z));
+#else
+ const Vec3vf16 vtx1(select(0x0f0f,vfloat16(v1.x),vfloat16(v3.x)),
+ select(0x0f0f,vfloat16(v1.y),vfloat16(v3.y)),
+ select(0x0f0f,vfloat16(v1.z),vfloat16(v3.z)));
+ const Vec3vf16 vtx2(select(0x0f0f,vfloat16(v3.x),vfloat16(v1.x)),
+ select(0x0f0f,vfloat16(v3.y),vfloat16(v1.y)),
+ select(0x0f0f,vfloat16(v3.z),vfloat16(v1.z)));
+#endif
+ const vbool16 flags(0xf0f0);
+ return PlueckerIntersectorTriangle1::intersect(ray,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,16,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,16,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#elif defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct QuadMIntersector1Pluecker<4,filter>
+ {
+ __forceinline QuadMIntersector1Pluecker() {}
+
+ __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ return PlueckerIntersectorTriangle1::intersect(ray,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ struct PlueckerIntersector1KTriangleM
+ {
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKPlueckerBase
+ {
+ __forceinline QuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> O = ray.org;
+ const Vec3vf<K> D = ray.dir;
+ const Vec3vf<K> v0 = tri_v0-O;
+ const Vec3vf<K> v1 = tri_v1-O;
+ const Vec3vf<K> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<K> e0 = v2-v0;
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
+ const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
+ const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
+ const vfloat<K> UVW = U+V+W;
+ const vfloat<K> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
+
+ /* perform depth test */
+ const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
+ const vfloat<K> t = rcp(den)*T;
+ valid &= ray.tnear() <= t & t <= ray.tfar;
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* calculate hit information */
+ QuadHitPlueckerK<K> hit(U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),epilog);
+ return none(valid0);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKPluecker : public QuadMIntersectorKPlueckerBase<M,K,filter>
+ {
+ __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1KEpilogM<M,M,K,filter> epilog(ray,k,context,geomID,primID);
+ PlueckerIntersector1KTriangleM::intersect1(ray,k,v0,v1,v3,vbool<M>(false),epilog);
+ PlueckerIntersector1KTriangleM::intersect1(ray,k,v2,v3,v1,vbool<M>(true ),epilog);
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1KEpilogM<M,M,K,filter> epilog(ray,k,context,geomID,primID);
+ if (PlueckerIntersector1KTriangleM::intersect1(ray,k,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (PlueckerIntersector1KTriangleM::intersect1(ray,k,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+#if defined(__AVX512ER__) // KNL
+
+ /*! Intersects 4 quads with 1 ray using AVX512 */
+ template<int K, bool filter>
+ struct QuadMIntersectorKPluecker<4,K,filter> : public QuadMIntersectorKPlueckerBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKPlueckerBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf16 vtx0(select(0x0f0f,vfloat16(v0.x),vfloat16(v2.x)),
+ select(0x0f0f,vfloat16(v0.y),vfloat16(v2.y)),
+ select(0x0f0f,vfloat16(v0.z),vfloat16(v2.z)));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf16 vtx1(vfloat16(v1.x),vfloat16(v1.y),vfloat16(v1.z));
+ const Vec3vf16 vtx2(vfloat16(v3.x),vfloat16(v3.y),vfloat16(v3.z));
+#else
+ const Vec3vf16 vtx1(select(0x0f0f,vfloat16(v1.x),vfloat16(v3.x)),
+ select(0x0f0f,vfloat16(v1.y),vfloat16(v3.y)),
+ select(0x0f0f,vfloat16(v1.z),vfloat16(v3.z)));
+ const Vec3vf16 vtx2(select(0x0f0f,vfloat16(v3.x),vfloat16(v1.x)),
+ select(0x0f0f,vfloat16(v3.y),vfloat16(v1.y)),
+ select(0x0f0f,vfloat16(v3.z),vfloat16(v1.z)));
+#endif
+
+ const vbool16 flags(0xf0f0);
+ return PlueckerIntersector1KTriangleM::intersect1(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,16,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,16,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#elif defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct QuadMIntersectorKPluecker<4,K,filter> : public QuadMIntersectorKPlueckerBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKPlueckerBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ return PlueckerIntersector1KTriangleM::intersect1(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quadi.h b/thirdparty/embree-aarch64/kernels/geometry/quadi.h
new file mode 100644
index 0000000000..741ec519ab
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quadi.h
@@ -0,0 +1,483 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ /* Stores M quads from an indexed face set */
+ template <int M>
+ struct QuadMi
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline QuadMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline QuadMi(const vuint<M>& v0,
+ const vuint<M>& v1,
+ const vuint<M>& v2,
+ const vuint<M>& v3,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+#if defined(EMBREE_COMPACT_POLYS)
+ : geomIDs(geomIDs), primIDs(primIDs) {}
+#else
+ : v0_(v0),v1_(v1), v2_(v2), v3_(v3), geomIDs(geomIDs), primIDs(primIDs) {}
+#endif
+
+ /* Returns a mask that tells which quads are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns if the specified quad is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored quads */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); assert(geomIDs[i] != -1); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the quads */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++) {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ bounds.extend(mesh->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill quad from quad list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> geomID = -1, primID = -1;
+ const PrimRefT* prim = &prims[begin];
+ vuint<M> v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+#if !defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(prim->geomID());
+ const QuadMesh::Quad& q = mesh->quad(prim->primID());
+ unsigned int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = q.v[0] * int_stride;
+ v1[i] = q.v[1] * int_stride;
+ v2[i] = q.v[2] * int_stride;
+ v3[i] = q.v[3] * int_stride;
+#endif
+ begin++;
+ } else {
+ assert(i);
+ if (likely(i > 0)) {
+ geomID[i] = geomID[0]; // always valid geomIDs
+ primID[i] = -1; // indicates invalid data
+ v0[i] = v0[0];
+ v1[i] = v0[0];
+ v2[i] = v0[0];
+ v3[i] = v0[0];
+ }
+ }
+ if (begin<end) prim = &prims[begin];
+ }
+ new (this) QuadMi(v0,v1,v2,v3,geomID,primID); // FIXME: use non temporal store
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const QuadMi& quad) {
+ return cout << "QuadMi<" << M << ">( "
+#if !defined(EMBREE_COMPACT_POLYS)
+ << "v0 = " << quad.v0_ << ", v1 = " << quad.v1_ << ", v2 = " << quad.v2_ << ", v3 = " << quad.v3_ << ", "
+#endif
+ << "geomID = " << quad.geomIDs << ", primID = " << quad.primIDs << " )";
+ }
+
+ protected:
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M> v0_; // 4 byte offset of 1st vertex
+ vuint<M> v1_; // 4 byte offset of 2nd vertex
+ vuint<M> v2_; // 4 byte offset of 3rd vertex
+ vuint<M> v3_; // 4 byte offset of 4th vertex
+#endif
+ vuint<M> geomIDs; // geometry ID of mesh
+ vuint<M> primIDs; // primitive ID of primitive inside mesh
+ };
+
+ namespace isa
+ {
+
+ template<int M>
+ struct QuadMi : public embree::QuadMi<M>
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ using embree::QuadMi<M>::v0_;
+ using embree::QuadMi<M>::v1_;
+ using embree::QuadMi<M>::v2_;
+ using embree::QuadMi<M>::v3_;
+#endif
+ using embree::QuadMi<M>::geomIDs;
+ using embree::QuadMi<M>::primIDs;
+ using embree::QuadMi<M>::geomID;
+ using embree::QuadMi<M>::primID;
+ using embree::QuadMi<M>::valid;
+
+ template<int vid>
+ __forceinline Vec3f getVertex(const size_t index, const Scene *const scene) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ return (Vec3f) mesh->vertices[0][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices = scene->vertices[geomID(index)];
+ return (Vec3f&) vertices[v[index]];
+#endif
+ }
+
+ template<int vid, typename T>
+ __forceinline Vec3<T> getVertex(const size_t index, const Scene *const scene, const size_t itime, const T& ftime) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime+0][quad.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime+1][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ const Vec3<T> p0(v0.x,v0.y,v0.z);
+ const Vec3<T> p1(v1.x,v1.y,v1.z);
+ return lerp(p0,p1,ftime);
+ }
+
+ template<int vid, int K, typename T>
+ __forceinline Vec3<T> getVertex(const vbool<K>& valid, const size_t index, const Scene *const scene, const vint<K>& itime, const T& ftime) const
+ {
+ Vec3<T> p0, p1;
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+
+ for (size_t mask=movemask(valid), i=bsf(mask); mask; mask=btc(mask,i), i=bsf(mask))
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime[i]+0][quad.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime[i]+1][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime[i]+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime[i]+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ p0.x[i] = v0.x; p0.y[i] = v0.y; p0.z[i] = v0.z;
+ p1.x[i] = v1.x; p1.y[i] = v1.y; p1.z[i] = v1.z;
+ }
+ return (T(one)-ftime)*p0 + ftime*p1;
+ }
+
+ struct Quad {
+ vfloat4 v0,v1,v2,v3;
+ };
+
+#if defined(EMBREE_COMPACT_POLYS)
+
+ __forceinline Quad loadQuad(const int i, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero, zero };
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices0[quad.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices0[quad.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices0[quad.v[2]];
+ const vfloat4 v3 = (vfloat4) mesh->vertices0[quad.v[3]];
+ return { v0, v1, v2, v3 };
+ }
+
+ __forceinline Quad loadQuad(const int i, const int itime, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero, zero };
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices[itime][quad.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices[itime][quad.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices[itime][quad.v[2]];
+ const vfloat4 v3 = (vfloat4) mesh->vertices[itime][quad.v[3]];
+ return { v0, v1, v2, v3 };
+ }
+
+#else
+
+ __forceinline Quad loadQuad(const int i, const Scene* const scene) const
+ {
+ const float* vertices = scene->vertices[geomID(i)];
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ const vfloat4 v3 = vfloat4::loadu(vertices + v3_[i]);
+ return { v0, v1, v2, v3 };
+ }
+
+ __forceinline Quad loadQuad(const int i, const int itime, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const float* vertices = (const float*) mesh->vertexPtr(0,itime);
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ const vfloat4 v3 = vfloat4::loadu(vertices + v3_[i]);
+ return { v0, v1, v2, v3 };
+ }
+
+#endif
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const Scene *const scene) const;
+
+#if defined(__AVX512F__)
+ __forceinline void gather(Vec3vf16& p0,
+ Vec3vf16& p1,
+ Vec3vf16& p2,
+ Vec3vf16& p3,
+ const Scene *const scene) const;
+#endif
+
+ template<int K>
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 2000) // workaround for compiler bug in ICC 2019
+ __noinline
+#else
+ __forceinline
+#endif
+ void gather(const vbool<K>& valid,
+ Vec3vf<K>& p0,
+ Vec3vf<K>& p1,
+ Vec3vf<K>& p2,
+ Vec3vf<K>& p3,
+ const size_t index,
+ const Scene* const scene,
+ const vfloat<K>& time) const
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment(time, ftime);
+
+ const size_t first = bsf(movemask(valid));
+ if (likely(all(valid,itime[first] == itime)))
+ {
+ p0 = getVertex<0>(index, scene, itime[first], ftime);
+ p1 = getVertex<1>(index, scene, itime[first], ftime);
+ p2 = getVertex<2>(index, scene, itime[first], ftime);
+ p3 = getVertex<3>(index, scene, itime[first], ftime);
+ }
+ else
+ {
+ p0 = getVertex<0>(valid, index, scene, itime, ftime);
+ p1 = getVertex<1>(valid, index, scene, itime, ftime);
+ p2 = getVertex<2>(valid, index, scene, itime, ftime);
+ p3 = getVertex<3>(valid, index, scene, itime, ftime);
+ }
+ }
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const QuadMesh* mesh,
+ const Scene *const scene,
+ const int itime) const;
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const Scene *const scene,
+ const float time) const;
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(QuadMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M; i++)
+ {
+ if (!valid(i)) break;
+ const unsigned primId = primID(i);
+ const QuadMesh::Quad& q = mesh->quad(primId);
+ const Vec3fa p0 = mesh->vertex(q.v[0]);
+ const Vec3fa p1 = mesh->vertex(q.v[1]);
+ const Vec3fa p2 = mesh->vertex(q.v[2]);
+ const Vec3fa p3 = mesh->vertex(q.v[3]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2),BBox3fa(p3)));
+ }
+ return bounds;
+ }
+
+ private:
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<int N> const vuint<M>& getVertexOffset() const;
+#endif
+ };
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<0>() const { return v0_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<1>() const { return v1_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<2>() const { return v2_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<3>() const { return v3_; }
+#endif
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene) const
+ {
+ prefetchL1(((char*)this)+0*64);
+ prefetchL1(((char*)this)+1*64);
+ const Quad tri0 = loadQuad(0,scene);
+ const Quad tri1 = loadQuad(1,scene);
+ const Quad tri2 = loadQuad(2,scene);
+ const Quad tri3 = loadQuad(3,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ transpose(tri0.v3,tri1.v3,tri2.v3,tri3.v3,p3.x,p3.y,p3.z);
+ }
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const QuadMesh* mesh,
+ const Scene *const scene,
+ const int itime) const
+ {
+ // FIXME: for trianglei there all geometries are identical, is this the case here too?
+
+ const Quad tri0 = loadQuad(0,itime,scene);
+ const Quad tri1 = loadQuad(1,itime,scene);
+ const Quad tri2 = loadQuad(2,itime,scene);
+ const Quad tri3 = loadQuad(3,itime,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ transpose(tri0.v3,tri1.v3,tri2.v3,tri3.v3,p3.x,p3.y,p3.z);
+ }
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene,
+ const float time) const
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(0)); // in mblur mode all geometries are identical
+
+ float ftime;
+ const int itime = mesh->timeSegment(time, ftime);
+
+ Vec3vf4 a0,a1,a2,a3; gather(a0,a1,a2,a3,mesh,scene,itime);
+ Vec3vf4 b0,b1,b2,b3; gather(b0,b1,b2,b3,mesh,scene,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ p2 = lerp(a2,b2,vfloat4(ftime));
+ p3 = lerp(a3,b3,vfloat4(ftime));
+ }
+ }
+
+ template<int M>
+ typename QuadMi<M>::Type QuadMi<M>::type;
+
+ typedef QuadMi<4> Quad4i;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quadi_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/quadi_intersector.h
new file mode 100644
index 0000000000..96cf7f1ca2
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quadi_intersector.h
@@ -0,0 +1,350 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadi.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiIntersector1Moeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiIntersectorKMoeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiIntersector1Pluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiIntersectorKPluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M motion blur quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiMBIntersector1Moeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M motion blur quads with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiMBIntersectorKMoeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M quads. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.gather(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,v3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M quads. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.gather(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ if (pre.intersectK(valid0,ray,v0,v1,v2,v3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M quads and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M quads. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M motion blur quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiMBIntersector1Pluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M motion blur quads with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiMBIntersectorKPluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M quads. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.gather(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,v3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M quads. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.gather(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ if (pre.intersectK(valid0,ray,v0,v1,v2,v3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M quads and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M quads. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quadv.h b/thirdparty/embree-aarch64/kernels/geometry/quadv.h
new file mode 100644
index 0000000000..0a1fe4d128
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quadv.h
@@ -0,0 +1,165 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M quads in struct of array layout */
+ template <int M>
+ struct QuadMv
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline QuadMv() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline QuadMv(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), v1(v1), v2(v2), v3(v3), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which quads are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified quad is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored quads */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M> primID() { return primIDs; }
+ __forceinline const vuint<M> primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the quads */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2,v3);
+ Vec3vf<M> upper = max(v0,v1,v2,v3);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(QuadMv* dst, const QuadMv& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->v1.x,src.v1.x);
+ vfloat<M>::store_nt(&dst->v1.y,src.v1.y);
+ vfloat<M>::store_nt(&dst->v1.z,src.v1.z);
+ vfloat<M>::store_nt(&dst->v2.x,src.v2.x);
+ vfloat<M>::store_nt(&dst->v2.y,src.v2.y);
+ vfloat<M>::store_nt(&dst->v2.z,src.v2.z);
+ vfloat<M>::store_nt(&dst->v3.x,src.v3.x);
+ vfloat<M>::store_nt(&dst->v3.y,src.v3.y);
+ vfloat<M>::store_nt(&dst->v3.z,src.v3.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill quad from quad list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const QuadMesh* __restrict__ const mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const Vec3fa& p0 = mesh->vertex(quad.v[0]);
+ const Vec3fa& p1 = mesh->vertex(quad.v[1]);
+ const Vec3fa& p2 = mesh->vertex(quad.v[2]);
+ const Vec3fa& p3 = mesh->vertex(quad.v[3]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ QuadMv::store_nt(this,QuadMv(v0,v1,v2,v3,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(QuadMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const QuadMesh::Quad& quad = mesh->quad(primId);
+ const Vec3fa p0 = mesh->vertex(quad.v[0]);
+ const Vec3fa p1 = mesh->vertex(quad.v[1]);
+ const Vec3fa p2 = mesh->vertex(quad.v[2]);
+ const Vec3fa p3 = mesh->vertex(quad.v[3]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2),BBox3fa(p3)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ new (this) QuadMv(v0,v1,v2,v3,vgeomID,vprimID);
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the quads
+ Vec3vf<M> v1; // 2nd vertex of the quads
+ Vec3vf<M> v2; // 3rd vertex of the quads
+ Vec3vf<M> v3; // 4rd vertex of the quads
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename QuadMv<M>::Type QuadMv<M>::type;
+
+ typedef QuadMv<4> Quad4v;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/quadv_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/quadv_intersector.h
new file mode 100644
index 0000000000..30a24b291a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/quadv_intersector.h
@@ -0,0 +1,181 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadv.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMvIntersector1Moeller
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMvIntersectorKMoeller
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMvIntersector1Pluecker
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMvIntersectorKPluecker
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/geometry/roundline_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/roundline_intersector.h
new file mode 100644
index 0000000000..cdf68f486b
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/roundline_intersector.h
@@ -0,0 +1,710 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+
+/*
+
+ This file implements the intersection of a ray with a round linear
+ curve segment. We define the geometry of such a round linear curve
+ segment from point p0 with radius r0 to point p1 with radius r1
+ using the cone that touches spheres p0/r0 and p1/r1 tangentially
+ plus the sphere p1/r1. We denote the tangentially touching cone from
+ p0/r0 to p1/r1 with cone(p0,r0,p1,r1) and the cone plus the ending
+ sphere with cone_sphere(p0,r0,p1,r1).
+
+ For multiple connected round linear curve segments this construction
+ yield a proper shape when viewed from the outside. Using the
+ following CSG we can also handle the interiour in most common cases:
+
+ round_linear_curve(pl,rl,p0,r0,p1,r1,pr,rr) =
+ cone_sphere(p0,r0,p1,r1) - cone(pl,rl,p0,r0) - cone(p1,r1,pr,rr)
+
+ Thus by subtracting the neighboring cone geometries, we cut away
+ parts of the center cone_sphere surface which lie inside the
+ combined curve. This approach works as long as geometry of the
+ current cone_sphere penetrates into direct neighbor segments only,
+ and not into segments further away.
+
+ To construct a cone that touches two spheres at p0 and p1 with r0
+ and r1, one has to increase the cone radius at r0 and r1 to obtain
+ larger radii w0 and w1, such that the infinite cone properly touches
+ the spheres. From the paper "Ray Tracing Generalized Tube
+ Primitives: Method and Applications"
+ (https://www.researchgate.net/publication/334378683_Ray_Tracing_Generalized_Tube_Primitives_Method_and_Applications)
+ one can derive the following equations for these increased
+ radii:
+
+ sr = 1.0f / sqrt(1-sqr(dr)/sqr(p1-p0))
+ w0 = sr*r0
+ w1 = sr*r1
+
+ Further, we want the cone to start where it touches the sphere at p0
+ and to end where it touches sphere at p1. Therefore, we need to
+ construct clipping locations y0 and y1 for the start and end of the
+ cone. These start and end clipping location of the cone can get
+ calculated as:
+
+ Y0 = - r0 * (r1-r0) / length(p1-p0)
+ Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
+
+ Where the cone starts a distance Y0 and ends a distance Y1 away of
+ point p0 along the cone center. The distance between Y1-Y0 can get
+ calculated as:
+
+ dY = length(p1-p0) - (r1-r0)^2 / length(p1-p0)
+
+ In the code below, Y will always be scaled by length(p1-p0) to
+ obtain y and you will find the terms r0*(r1-r0) and
+ (p1-p0)^2-(r1-r0)^2.
+
+ */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct RoundLineIntersectorHitM
+ {
+ __forceinline RoundLineIntersectorHitM() {}
+
+ __forceinline RoundLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ namespace __roundline_internal
+ {
+ template<int M>
+ struct ConeGeometry
+ {
+ ConeGeometry (const Vec4vf<M>& a, const Vec4vf<M>& b)
+ : p0(a.xyz()), p1(b.xyz()), dP(p1-p0), dPdP(dot(dP,dP)), r0(a.w), sqr_r0(sqr(r0)), r1(b.w), dr(r1-r0), drdr(dr*dr), r0dr (r0*dr), g(dPdP - drdr) {}
+
+ /*
+
+ This function tests if a point is accepted by first cone
+ clipping plane.
+
+ First, we need to project the point onto the line p0->p1:
+
+ Y = (p-p0)*(p1-p0)/length(p1-p0)
+
+ This value y is the distance to the projection point from
+ p0. The clip distances are calculated as:
+
+ Y0 = - r0 * (r1-r0) / length(p1-p0)
+ Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
+
+ Thus to test if the point p is accepted by the first
+ clipping plane we need to test Y > Y0 and to test if it
+ is accepted by the second clipping plane we need to test
+ Y < Y1.
+
+ By multiplying the calculations with length(p1-p0) these
+ calculation can get simplied to:
+
+ y = (p-p0)*(p1-p0)
+ y0 = - r0 * (r1-r0)
+ y1 = (p1-p0)^2 - r1 * (r1-r0)
+
+ and the test y > y0 and y < y1.
+
+ */
+
+ __forceinline vbool<M> isClippedByPlane (const vbool<M>& valid_i, const Vec3vf<M>& p) const
+ {
+ const Vec3vf<M> p0p = p - p0;
+ const vfloat<M> y = dot(p0p,dP);
+ const vfloat<M> cap0 = -r0dr;
+ const vbool<M> inside_cone = y > cap0;
+ return valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf)) & inside_cone;
+ }
+
+ /*
+
+ This function tests whether a point lies inside the capped cone
+ tangential to its ending spheres.
+
+ Therefore one has to check if the point is inside the
+ region defined by the cone clipping planes, which is
+ performed similar as in the previous function.
+
+ To perform the inside cone test we need to project the
+ point onto the line p0->p1:
+
+ dP = p1-p0
+ Y = (p-p0)*dP/length(dP)
+
+ This value Y is the distance to the projection point from
+ p0. To obtain a parameter value u going from 0 to 1 along
+ the line p0->p1 we calculate:
+
+ U = Y/length(dP)
+
+ The radii to use at points p0 and p1 are:
+
+ w0 = sr * r0
+ w1 = sr * r1
+ dw = w1-w0
+
+ Using these radii and u one can directly test if the point
+ lies inside the cone using the formula dP*dP < wy*wy with:
+
+ wy = w0 + u*dw
+ py = p0 + u*dP - p
+
+ By multiplying the calculations with length(p1-p0) and
+ inserting the definition of w can obtain simpler equations:
+
+ y = (p-p0)*dP
+ ry = r0 + y/dP^2 * dr
+ wy = sr*ry
+ py = p0 + y/dP^2*dP - p
+ y0 = - r0 * dr
+ y1 = dP^2 - r1 * dr
+
+ Thus for the in-cone test we get:
+
+ py^2 < wy^2
+ <=> py^2 < sr^2 * ry^2
+ <=> py^2 * ( dP^2 - dr^2 ) < dP^2 * ry^2
+
+ This can further get simplified to:
+
+ (p0-p)^2 * (dP^2 - dr^2) - y^2 < dP^2 * r0^2 + 2.0f*r0*dr*y;
+
+ */
+
+ __forceinline vbool<M> isInsideCappedCone (const vbool<M>& valid_i, const Vec3vf<M>& p) const
+ {
+ const Vec3vf<M> p0p = p - p0;
+ const vfloat<M> y = dot(p0p,dP);
+ const vfloat<M> cap0 = -r0dr+vfloat<M>(ulp);
+ const vfloat<M> cap1 = -r1*dr + dPdP;
+
+ vbool<M> inside_cone = valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf));
+ inside_cone &= y > cap0; // start clipping plane
+ inside_cone &= y < cap1; // end clipping plane
+ inside_cone &= sqr(p0p)*g - sqr(y) < dPdP * sqr_r0 + 2.0f*r0dr*y; // in cone test
+ return inside_cone;
+ }
+
+ protected:
+ Vec3vf<M> p0;
+ Vec3vf<M> p1;
+ Vec3vf<M> dP;
+ vfloat<M> dPdP;
+ vfloat<M> r0;
+ vfloat<M> sqr_r0;
+ vfloat<M> r1;
+ vfloat<M> dr;
+ vfloat<M> drdr;
+ vfloat<M> r0dr;
+ vfloat<M> g;
+ };
+
+ template<int M>
+ struct ConeGeometryIntersector : public ConeGeometry<M>
+ {
+ using ConeGeometry<M>::p0;
+ using ConeGeometry<M>::p1;
+ using ConeGeometry<M>::dP;
+ using ConeGeometry<M>::dPdP;
+ using ConeGeometry<M>::r0;
+ using ConeGeometry<M>::sqr_r0;
+ using ConeGeometry<M>::r1;
+ using ConeGeometry<M>::dr;
+ using ConeGeometry<M>::r0dr;
+ using ConeGeometry<M>::g;
+
+ ConeGeometryIntersector (const Vec3vf<M>& ray_org, const Vec3vf<M>& ray_dir, const vfloat<M>& dOdO, const vfloat<M>& rcp_dOdO, const Vec4vf<M>& a, const Vec4vf<M>& b)
+ : ConeGeometry<M>(a,b), org(ray_org), O(ray_org-p0), dO(ray_dir), dOdO(dOdO), rcp_dOdO(rcp_dOdO), OdP(dot(dP,O)), dOdP(dot(dP,dO)), yp(OdP + r0dr) {}
+
+ /*
+
+ This function intersects a ray with a cone that touches a
+ start sphere p0/r0 and end sphere p1/r1.
+
+ To find this ray/cone intersections one could just
+ calculate radii w0 and w1 as described above and use a
+ standard ray/cone intersection routine with these
+ radii. However, it turns out that calculations can get
+ simplified when deriving a specialized ray/cone
+ intersection for this special case. We perform
+ calculations relative to the cone origin p0 and define:
+
+ O = ray_org - p0
+ dO = ray_dir
+ dP = p1-p0
+ dr = r1-r0
+ dw = w1-w0
+
+ For some t we can compute the potential hit point h = O + t*dO and
+ project it onto the cone vector dP to obtain u = (h*dP)/(dP*dP). In
+ case of an intersection, the squared distance from the hit point
+ projected onto the cone center line to the hit point should be equal
+ to the squared cone radius at u:
+
+ (u*dP - h)^2 = (w0 + u*dw)^2
+
+ Inserting the definition of h, u, w0, and dw into this formula, then
+ factoring out all terms, and sorting by t^2, t^1, and t^0 terms
+ yields a quadratic equation to solve.
+
+ Inserting u:
+ ( (h*dP)*dP/dP^2 - h )^2 = ( w0 + (h*dP)*dw/dP^2 )^2
+
+ Multiplying by dP^4:
+ ( (h*dP)*dP - h*dP^2 )^2 = ( w0*dP^2 + (h*dP)*dw )^2
+
+ Inserting w0 and dw:
+ ( (h*dP)*dP - h*dP^2 )^2 = ( r0*dP^2 + (h*dP)*dr )^2 / (1-dr^2/dP^2)
+ ( (h*dP)*dP - h*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (h*dP)*dr )^2
+
+ Now one can insert the definition of h, factor out, and presort by t:
+ ( ((O + t*dO)*dP)*dP - (O + t*dO)*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + ((O + t*dO)*dP)*dr )^2
+ ( (O*dP)*dP-O*dP^2 + t*( (dO*dP)*dP - dO*dP^2 ) )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (O*dP)*dr + t*(dO*dP)*dr )^2
+
+ Factoring out further and sorting by t^2, t^1 and t^0 yields:
+
+ 0 = t^2 * [ ((dO*dP)*dP - dO-dP^2)^2 * (dP^2 - dr^2) - dP^2*(dO*dP)^2*dr^2 ]
+ + 2*t^1 * [ ((O*dP)*dP - O*dP^2) * ((dO*dP)*dP - dO*dP^2) * (dP^2 - dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)*(dO*dP)*dr ]
+ + t^0 * [ ( (O*dP)*dP - O*dP^2)^2 * (dP^2-dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)^2 ]
+
+ This can be simplified to:
+
+ 0 = t^2 * [ (dP^2 - dr^2)*dO^2 - (dO*dP)^2 ]
+ + 2*t^1 * [ (dP^2 - dr^2)*(O*dO) - (dO*dP)*(O*dP + r0*dr) ]
+ + t^0 * [ (dP^2 - dr^2)*O^2 - (O*dP)^2 - r0^2*dP^2 - 2.0f*r0*dr*(O*dP) ]
+
+ Solving this quadratic equation yields the values for t at which the
+ ray intersects the cone.
+
+ */
+
+ __forceinline bool intersectCone(vbool<M>& valid, vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* return no hit by default */
+ lower = pos_inf;
+ upper = neg_inf;
+
+ /* compute quadratic equation A*t^2 + B*t + C = 0 */
+ const vfloat<M> OO = dot(O,O);
+ const vfloat<M> OdO = dot(dO,O);
+ const vfloat<M> A = g * dOdO - sqr(dOdP);
+ const vfloat<M> B = 2.0f * (g*OdO - dOdP*yp);
+ const vfloat<M> C = g*OO - sqr(OdP) - sqr_r0*dPdP - 2.0f*r0dr*OdP;
+
+ /* we miss the cone if determinant is smaller than zero */
+ const vfloat<M> D = B*B - 4.0f*A*C;
+ valid &= (D >= 0.0f & g > 0.0f); // if g <= 0 then the cone is inside a sphere end
+
+ /* When rays are parallel to the cone surface, then the
+ * ray may be inside or outside the cone. We just assume a
+ * miss in that case, which is fine as rays inside the
+ * cone would anyway hit the ending spheres in that
+ * case. */
+ valid &= abs(A) > min_rcp_input;
+ if (unlikely(none(valid))) {
+ return false;
+ }
+
+ /* compute distance to front and back hit */
+ const vfloat<M> Q = sqrt(D);
+ const vfloat<M> rcp_2A = rcp(2.0f*A);
+ t_cone_front = (-B-Q)*rcp_2A;
+ y_cone_front = yp + t_cone_front*dOdP;
+ lower = select( (y_cone_front > -(float)ulp) & (y_cone_front <= g) & (g > 0.0f), t_cone_front, vfloat<M>(pos_inf));
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ t_cone_back = (-B+Q)*rcp_2A;
+ y_cone_back = yp + t_cone_back *dOdP;
+ upper = select( (y_cone_back > -(float)ulp) & (y_cone_back <= g) & (g > 0.0f), t_cone_back , vfloat<M>(neg_inf));
+#endif
+ return true;
+ }
+
+ /*
+ This function intersects the ray with the end sphere at
+ p1. We already clip away hits that are inside the
+ neighboring cone segment.
+
+ */
+
+ __forceinline void intersectEndSphere(vbool<M>& valid,
+ const ConeGeometry<M>& coneR,
+ vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* calculate front and back hit with end sphere */
+ const Vec3vf<M> O1 = org - p1;
+ const vfloat<M> O1dO = dot(O1,dO);
+ const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r1));
+ const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
+
+ /* clip away front hit if it is inside next cone segment */
+ t_sph1_front = (-O1dO - rhs1)*rcp_dOdO;
+ const Vec3vf<M> hit_front = org + t_sph1_front*dO;
+ vbool<M> valid_sph1_front = h2 >= 0.0f & yp + t_sph1_front*dOdP > g & !coneR.isClippedByPlane (valid, hit_front);
+ lower = select(valid_sph1_front, t_sph1_front, vfloat<M>(pos_inf));
+
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ /* clip away back hit if it is inside next cone segment */
+ t_sph1_back = (-O1dO + rhs1)*rcp_dOdO;
+ const Vec3vf<M> hit_back = org + t_sph1_back*dO;
+ vbool<M> valid_sph1_back = h2 >= 0.0f & yp + t_sph1_back*dOdP > g & !coneR.isClippedByPlane (valid, hit_back);
+ upper = select(valid_sph1_back, t_sph1_back, vfloat<M>(neg_inf));
+#else
+ upper = vfloat<M>(neg_inf);
+#endif
+ }
+
+ __forceinline void intersectBeginSphere(const vbool<M>& valid,
+ vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* calculate front and back hit with end sphere */
+ const Vec3vf<M> O1 = org - p0;
+ const vfloat<M> O1dO = dot(O1,dO);
+ const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r0));
+ const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
+
+ /* clip away front hit if it is inside next cone segment */
+ t_sph0_front = (-O1dO - rhs1)*rcp_dOdO;
+ vbool<M> valid_sph1_front = valid & h2 >= 0.0f & yp + t_sph0_front*dOdP < 0;
+ lower = select(valid_sph1_front, t_sph0_front, vfloat<M>(pos_inf));
+
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ /* clip away back hit if it is inside next cone segment */
+ t_sph0_back = (-O1dO + rhs1)*rcp_dOdO;
+ vbool<M> valid_sph1_back = valid & h2 >= 0.0f & yp + t_sph0_back*dOdP < 0;
+ upper = select(valid_sph1_back, t_sph0_back, vfloat<M>(neg_inf));
+#else
+ upper = vfloat<M>(neg_inf);
+#endif
+ }
+
+ /*
+
+ This function calculates the geometry normal of some cone hit.
+
+ For a given hit point h (relative to p0) with a cone
+ starting at p0 with radius w0 and ending at p1 with
+ radius w1 one normally calculates the geometry normal by
+ first calculating the parmetric u hit location along the
+ cone:
+
+ u = dot(h,dP)/dP^2
+
+ Using this value one can now directly calculate the
+ geometry normal by bending the connection vector (h-u*dP)
+ from hit to projected hit with some cone dependent value
+ dw/sqrt(dP^2) * normalize(dP):
+
+ Ng = normalize(h-u*dP) - dw/length(dP) * normalize(dP)
+
+ The length of the vector (h-u*dP) can also get calculated
+ by interpolating the radii as w0+u*dw which yields:
+
+ Ng = (h-u*dP)/(w0+u*dw) - dw/dP^2 * dP
+
+ Multiplying with (w0+u*dw) yield a scaled Ng':
+
+ Ng' = (h-u*dP) - (w0+u*dw)*dw/dP^2*dP
+
+ Inserting the definition of w0 and dw and refactoring
+ yield a furhter scaled Ng'':
+
+ Ng'' = (dP^2 - dr^2) (h-q) - (r0+u*dr)*dr*dP
+
+ Now inserting the definition of u gives and multiplying
+ with the denominator yields:
+
+ Ng''' = (dP^2-dr^2)*(dP^2*h-dot(h,dP)*dP) - (dP^2*r0+dot(h,dP)*dr)*dr*dP
+
+ Factoring out, cancelling terms, dividing by dP^2, and
+ factoring again yields finally:
+
+ Ng'''' = (dP^2-dr^2)*h - dP*(dot(h,dP) + r0*dr)
+
+ */
+
+ __forceinline Vec3vf<M> Ng_cone(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
+ const vfloat<M> t = select(front_hit, t_cone_front, t_cone_back);
+ const Vec3vf<M> h = O + t*dO;
+ return g*h-dP*y;
+#else
+ const Vec3vf<M> h = O + t_cone_front*dO;
+ return g*h-dP*y_cone_front;
+#endif
+ }
+
+ /* compute geometry normal of sphere hit as the difference
+ * vector from hit point to sphere center */
+
+ __forceinline Vec3vf<M> Ng_sphere1(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> t_sph1 = select(front_hit, t_sph1_front, t_sph1_back);
+ return org+t_sph1*dO-p1;
+#else
+ return org+t_sph1_front*dO-p1;
+#endif
+ }
+
+ __forceinline Vec3vf<M> Ng_sphere0(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> t_sph0 = select(front_hit, t_sph0_front, t_sph0_back);
+ return org+t_sph0*dO-p0;
+#else
+ return org+t_sph0_front*dO-p0;
+#endif
+ }
+
+ /*
+ This function calculates the u coordinate of a
+ hit. Therefore we use the hit distance y (which is zero
+ at the first cone clipping plane) and divide by distance
+ g between the clipping planes.
+
+ */
+
+ __forceinline vfloat<M> u_cone(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
+ return clamp(y*rcp(g));
+#else
+ return clamp(y_cone_front*rcp(g));
+#endif
+ }
+
+ private:
+ Vec3vf<M> org;
+ Vec3vf<M> O;
+ Vec3vf<M> dO;
+ vfloat<M> dOdO;
+ vfloat<M> rcp_dOdO;
+ vfloat<M> OdP;
+ vfloat<M> dOdP;
+
+ /* for ray/cone intersection */
+ private:
+ vfloat<M> yp;
+ vfloat<M> y_cone_front;
+ vfloat<M> t_cone_front;
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> y_cone_back;
+ vfloat<M> t_cone_back;
+#endif
+
+ /* for ray/sphere intersection */
+ private:
+ vfloat<M> t_sph1_front;
+ vfloat<M> t_sph0_front;
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> t_sph1_back;
+ vfloat<M> t_sph0_back;
+#endif
+ };
+
+
+ template<int M, typename Epilog, typename ray_tfar_func>
+ static __forceinline bool intersectConeSphere(const vbool<M>& valid_i,
+ const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,
+ const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
+ const Vec4vf<M>& v0, const Vec4vf<M>& v1,
+ const Vec4vf<M>& vL, const Vec4vf<M>& vR,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ /* move ray origin closer to make calculations numerically stable */
+ const vfloat<M> dOdO = sqr(ray_dir);
+ const vfloat<M> rcp_dOdO = rcp(dOdO);
+ const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());
+ const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;
+ const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;
+
+ /* intersect with cone from v0 to v1 */
+ vfloat<M> t_cone_lower, t_cone_upper;
+ ConeGeometryIntersector<M> cone (ray_org, ray_dir, dOdO, rcp_dOdO, v0, v1);
+ vbool<M> validCone = valid;
+ cone.intersectCone(validCone, t_cone_lower, t_cone_upper);
+
+ valid &= (validCone | (cone.g <= 0.0f)); // if cone is entirely in sphere end - check sphere
+ if (unlikely(none(valid)))
+ return false;
+
+ /* cone hits inside the neighboring capped cones are inside the geometry and thus ignored */
+ const ConeGeometry<M> coneL (v0, vL);
+ const ConeGeometry<M> coneR (v1, vR);
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const Vec3vf<M> hit_lower = ray_org + t_cone_lower*ray_dir;
+ const Vec3vf<M> hit_upper = ray_org + t_cone_upper*ray_dir;
+ t_cone_lower = select (!coneL.isInsideCappedCone (validCone, hit_lower) & !coneR.isInsideCappedCone (validCone, hit_lower), t_cone_lower, vfloat<M>(pos_inf));
+ t_cone_upper = select (!coneL.isInsideCappedCone (validCone, hit_upper) & !coneR.isInsideCappedCone (validCone, hit_upper), t_cone_upper, vfloat<M>(neg_inf));
+#endif
+
+ /* intersect ending sphere */
+ vfloat<M> t_sph1_lower, t_sph1_upper;
+ vfloat<M> t_sph0_lower = vfloat<M>(pos_inf);
+ vfloat<M> t_sph0_upper = vfloat<M>(neg_inf);
+ cone.intersectEndSphere(valid, coneR, t_sph1_lower, t_sph1_upper);
+
+ const vbool<M> isBeginPoint = valid & (vL[0] == vfloat<M>(pos_inf));
+ if (unlikely(any(isBeginPoint))) {
+ cone.intersectBeginSphere (isBeginPoint, t_sph0_lower, t_sph0_upper);
+ }
+
+ /* CSG union of cone and end sphere */
+ vfloat<M> t_sph_lower = min(t_sph0_lower, t_sph1_lower);
+ vfloat<M> t_cone_sphere_lower = min(t_cone_lower, t_sph_lower);
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> t_sph_upper = max(t_sph0_upper, t_sph1_upper);
+ vfloat<M> t_cone_sphere_upper = max(t_cone_upper, t_sph_upper);
+
+ /* filter out hits that are not in tnear/tfar range */
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
+ const vbool<M> valid_upper = valid & ray_tnear <= dt+t_cone_sphere_upper & dt+t_cone_sphere_upper <= ray_tfar() & t_cone_sphere_upper != vfloat<M>(neg_inf);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_lower | valid_upper;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> t_first = select(valid_lower, t_cone_sphere_lower, t_cone_sphere_upper);
+ const vbool<M> cone_hit_first = t_first == t_cone_lower | t_first == t_cone_upper;
+ const vbool<M> sph0_hit_first = t_first == t_sph0_lower | t_first == t_sph0_upper;
+ const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
+ const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_cone_sphere_upper;
+ const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_cone_sphere_upper <= ray_tfar());
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;
+ const vbool<M> sph0_hit_second = t_second == t_sph0_lower | t_second == t_sph0_upper;
+ const Vec3vf<M> Ng_second = select(cone_hit_second, cone.Ng_cone(false), select (sph0_hit_second, cone.Ng_sphere0(false), cone.Ng_sphere1(false)));
+ const vfloat<M> u_second = select(cone_hit_second, cone.u_cone(false), select (sph0_hit_second, vfloat<M>(zero), vfloat<M>(one)));
+
+ hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+#else
+ /* filter out hits that are not in tnear/tfar range */
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
+
+ /* check if there is a valid hit */
+ if (unlikely(none(valid_lower)))
+ return false;
+
+ /* construct first hit */
+ const vbool<M> cone_hit_first = t_cone_sphere_lower == t_cone_lower | t_cone_sphere_lower == t_cone_upper;
+ const vbool<M> sph0_hit_first = t_cone_sphere_lower == t_sph0_lower | t_cone_sphere_lower == t_sph0_upper;
+ const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
+ const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_cone_sphere_lower,Ng_first);
+ const bool is_hit_first = epilog(valid_lower, hit);
+
+ return is_hit_first;
+#endif
+ }
+
+ } // end namespace __roundline_internal
+
+ template<int M>
+ struct RoundLinearCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ struct ray_tfar {
+ Ray& ray;
+ __forceinline ray_tfar(Ray& ray) : ray(ray) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> ray_tnear(ray.tnear());
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+ const Vec4vf<M> vL = enlargeRadiusToMinWidth(context,geom,ray_org,vLi);
+ const Vec4vf<M> vR = enlargeRadiusToMinWidth(context,geom,ray_org,vRi);
+ return __roundline_internal::intersectConeSphere(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray),v0,v1,vL,vR,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct RoundLinearCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ struct ray_tfar {
+ RayK<K>& ray;
+ size_t k;
+ __forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar[k]; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> ray_tnear = ray.tnear()[k];
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth(context,geom,ray_org,v1i);
+ const Vec4vf<M> vL = enlargeRadiusToMinWidth(context,geom,ray_org,vLi);
+ const Vec4vf<M> vR = enlargeRadiusToMinWidth(context,geom,ray_org,vRi);
+ return __roundline_internal::intersectConeSphere(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,vL,vR,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/roundlinei_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/roundlinei_intersector.h
new file mode 100644
index 0000000000..079817335e
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/roundlinei_intersector.h
@@ -0,0 +1,136 @@
+// ======================================================================== //
+// Copyright 2009-2020 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#pragma once
+
+#include "roundline_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, int Mx, bool filter>
+ struct RoundLinearCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ RoundLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return RoundLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct RoundLinearCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ RoundLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time());
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return RoundLinearCurveIntersector1<Mx>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Occluded1EpilogM<M,Mx,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct RoundLinearCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ RoundLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return RoundLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct RoundLinearCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ RoundLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time()[k]);
+ const vbool<Mx> valid = line.template valid<Mx>();
+ return RoundLinearCurveIntersectorK<Mx,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/sphere_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/sphere_intersector.h
new file mode 100644
index 0000000000..3ab90c29ef
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/sphere_intersector.h
@@ -0,0 +1,183 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_points.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct SphereIntersectorHitM
+ {
+ __forceinline SphereIntersectorHitM() {}
+
+ __forceinline SphereIntersectorHitM(const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv(const size_t i) const {
+ return Vec2f(0.0f, 0.0f);
+ }
+ __forceinline float t(const size_t i) const {
+ return vt[i];
+ }
+ __forceinline Vec3fa Ng(const size_t i) const {
+ return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]);
+ }
+
+ public:
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct SphereIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i, Ray& ray,
+ const Precalculations& pre, const Vec4vf<M>& v0, const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const vfloat<M> rd2 = rcp(dot(ray.dir, ray.dir));
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ const vfloat<M> td = sqrt((r2 - l2) * rd2);
+ const vfloat<M> t_front = projC0 - td;
+ const vfloat<M> t_back = projC0 + td;
+
+ const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar);
+ const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front | valid_back;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> td_front = -td;
+ const vfloat<M> td_back = +td;
+ const vfloat<M> t_first = select(valid_front, t_front, t_back);
+ const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp;
+ SphereIntersectorHitM<M> hit(t_first, Ng_first);
+
+ /* invoke intersection filter for first hit */
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_back;
+ const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar);
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
+ hit = SphereIntersectorHitM<M> (t_second, Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i, Ray& ray, IntersectContext* context, const Points* geom,
+ const Precalculations& pre, const Vec4vf<M>& v0i, const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ return intersect(valid_i,ray,pre,v0,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct SphereIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ const vfloat<M> td = sqrt((r2 - l2) * rd2);
+ const vfloat<M> t_front = projC0 - td;
+ const vfloat<M> t_back = projC0 + td;
+
+ const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]);
+ const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front | valid_back;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> td_front = -td;
+ const vfloat<M> td_back = +td;
+ const vfloat<M> t_first = select(valid_front, t_front, t_back);
+ const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp;
+ SphereIntersectorHitM<M> hit(t_first, Ng_first);
+
+ /* invoke intersection filter for first hit */
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_back;
+ const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]);
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
+ hit = SphereIntersectorHitM<M> (t_second, Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/geometry/spherei_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/spherei_intersector.h
new file mode 100644
index 0000000000..1146847602
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/spherei_intersector.h
@@ -0,0 +1,156 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "intersector_epilog.h"
+#include "pointi.h"
+#include "sphere_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, int Mx, bool filter>
+ struct SphereMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ SphereIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, Mx, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ return SphereIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, Mx, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query,
+ PointQueryContext* context,
+ const Primitive& sphere)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, sphere);
+ }
+ };
+
+ template<int M, int Mx, bool filter>
+ struct SphereMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time());
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ SphereIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, Mx, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time());
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ return SphereIntersector1<Mx>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, Mx, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query,
+ PointQueryContext* context,
+ const Primitive& sphere)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, sphere);
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct SphereMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ SphereIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ return SphereIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+ };
+
+ template<int M, int Mx, int K, bool filter>
+ struct SphereMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time()[k]);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ SphereIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, Mx, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time()[k]);
+ const vbool<Mx> valid = sphere.template valid<Mx>();
+ return SphereIntersectorK<Mx, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, Mx, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1.h b/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1.h
new file mode 100644
index 0000000000..94ad46ad87
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1.h
@@ -0,0 +1,38 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../geometry/primitive.h"
+#include "../subdiv/subdivpatch1base.h"
+
+namespace embree
+{
+
+ struct __aligned(64) SubdivPatch1 : public SubdivPatch1Base
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+
+ static Type type;
+
+ public:
+
+ /*! constructor for cached subdiv patch */
+ SubdivPatch1 (const unsigned int gID,
+ const unsigned int pID,
+ const unsigned int subPatch,
+ const SubdivMesh *const mesh,
+ const size_t time,
+ const Vec2f uv[4],
+ const float edge_level[4],
+ const int subdiv[4],
+ const int simd_width)
+ : SubdivPatch1Base(gID,pID,subPatch,mesh,time,uv,edge_level,subdiv,simd_width) {}
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1_intersector.h
new file mode 100644
index 0000000000..74ec1de258
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subdivpatch1_intersector.h
@@ -0,0 +1,237 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subdivpatch1.h"
+#include "grid_soa.h"
+#include "grid_soa_intersector1.h"
+#include "grid_soa_intersector_packet.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ class SubdivPatch1Precalculations : public T
+ {
+ public:
+ __forceinline SubdivPatch1Precalculations (const Ray& ray, const void* ptr)
+ : T(ray,ptr) {}
+ };
+
+ template<int K, typename T>
+ class SubdivPatch1PrecalculationsK : public T
+ {
+ public:
+ __forceinline SubdivPatch1PrecalculationsK (const vbool<K>& valid, RayK<K>& ray)
+ : T(valid,ray) {}
+ };
+
+ class SubdivPatch1Intersector1
+ {
+ public:
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1Precalculations<GridSOAIntersector1::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ lazy_node = prim->root(0);
+ pre.grid = (Primitive*)prim;
+ return false;
+ }
+
+ /*! Intersect a ray with the primitive. */
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node) {
+ intersect(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node) {
+ return occluded(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ // TODO: PointQuery implement
+ assert(false && "not implemented");
+ return false;
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node) {
+ return pointQuery(This,query,context,prim,ty,tquery,lazy_node);
+ }
+ };
+
+ class SubdivPatch1MBIntersector1
+ {
+ public:
+ typedef SubdivPatch1 Primitive;
+ typedef GridSOAMBIntersector1::Precalculations Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node)
+ {
+ Primitive* prim = (Primitive*) prim_i;
+ GridSOA* grid = nullptr;
+ grid = (GridSOA*) prim->root_ref.get();
+ pre.itime = getTimeSegment(ray.time(), float(grid->time_steps-1), pre.ftime);
+ lazy_node = grid->root(pre.itime);
+ pre.grid = grid;
+ return false;
+ }
+
+ /*! Intersect a ray with the primitive. */
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,ray,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node) {
+ intersect(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,ray,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node) {
+ return occluded(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ // TODO: PointQuery implement
+ assert(false && "not implemented");
+ return false;
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node) {
+ return pointQuery(This,query,context,prim,ty,tquery,lazy_node);
+ }
+ };
+
+ template <int K>
+ struct SubdivPatch1IntersectorK
+ {
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ lazy_node = prim->root(0);
+ pre.grid = (Primitive*)prim;
+ return false;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+ };
+
+ typedef SubdivPatch1IntersectorK<4> SubdivPatch1Intersector4;
+ typedef SubdivPatch1IntersectorK<8> SubdivPatch1Intersector8;
+ typedef SubdivPatch1IntersectorK<16> SubdivPatch1Intersector16;
+
+ template <int K>
+ struct SubdivPatch1MBIntersectorK
+ {
+ typedef SubdivPatch1 Primitive;
+ //typedef GridSOAMBIntersectorK<K>::Precalculations Precalculations;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAMBIntersectorK<K>::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node)
+ {
+ Primitive* prim = (Primitive*) prim_i;
+ GridSOA* grid = (GridSOA*) prim->root_ref.get();
+ lazy_node = grid->troot;
+ pre.grid = grid;
+ return false;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+ };
+
+ typedef SubdivPatch1MBIntersectorK<4> SubdivPatch1MBIntersector4;
+ typedef SubdivPatch1MBIntersectorK<8> SubdivPatch1MBIntersector8;
+ typedef SubdivPatch1MBIntersectorK<16> SubdivPatch1MBIntersector16;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subgrid.h b/thirdparty/embree-aarch64/kernels/geometry/subgrid.h
new file mode 100644
index 0000000000..39fa6fb0f0
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subgrid.h
@@ -0,0 +1,517 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_grid_mesh.h"
+#include "../bvh/bvh.h"
+
+namespace embree
+{
+ /* Stores M quads from an indexed face set */
+ struct SubGrid
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline SubGrid() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGrid(const unsigned int x,
+ const unsigned int y,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : _x(x), _y(y), _geomID(geomID), _primID(primID)
+ {
+ }
+
+ __forceinline bool invalid3x3X() const { return (unsigned int)_x & (1<<15); }
+ __forceinline bool invalid3x3Y() const { return (unsigned int)_y & (1<<15); }
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const GridMesh* const mesh,
+ const GridMesh::Grid &g) const
+ {
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = vfloat4::loadu(mesh->vertexPtr(vtxID00));
+ const vfloat4 vtx01 = vfloat4::loadu(mesh->vertexPtr(vtxID01));
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = vfloat4::loadu(mesh->vertexPtr(vtxID10));
+ const vfloat4 vtx11 = vfloat4::loadu(mesh->vertexPtr(vtxID11));
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = vfloat4::loadu(mesh->vertexPtr(vtxID02));
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = vfloat4::loadu(mesh->vertexPtr(vtxID12));
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = vfloat4::loadu(mesh->vertexPtr(vtxID20));
+ const vfloat4 vtx21 = vfloat4::loadu(mesh->vertexPtr(vtxID21));
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = vfloat4::loadu(mesh->vertexPtr(vtxID22));
+
+ transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
+ transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
+ transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
+ transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
+ }
+
+ template<typename T>
+ __forceinline vfloat4 getVertexMB(const GridMesh* const mesh, const size_t offset, const size_t itime, const float ftime) const
+ {
+ const T v0 = T::loadu(mesh->vertexPtr(offset,itime+0));
+ const T v1 = T::loadu(mesh->vertexPtr(offset,itime+1));
+ return lerp(v0,v1,ftime);
+ }
+
+ /* Gather the quads */
+ __forceinline void gatherMB(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const GridMesh* const mesh,
+ const GridMesh::Grid &g,
+ const size_t itime,
+ const float ftime) const
+ {
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
+ const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
+ const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
+ const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
+
+ transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
+ transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
+ transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
+ transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
+ }
+
+
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene) const
+ {
+ const GridMesh* const mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+ gather(p0,p1,p2,p3,mesh,g);
+ }
+
+ /* Gather the quads in the motion blur case */
+ __forceinline void gatherMB(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene,
+ const size_t itime,
+ const float ftime) const
+ {
+ const GridMesh* const mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+ gatherMB(p0,p1,p2,p3,mesh,g,itime,ftime);
+ }
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3fa vtx[16], const Scene *const scene) const
+ {
+ const GridMesh* mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const Vec3fa vtx00 = Vec3fa::loadu(mesh->vertexPtr(vtxID00));
+ const Vec3fa vtx01 = Vec3fa::loadu(mesh->vertexPtr(vtxID01));
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const Vec3fa vtx10 = Vec3fa::loadu(mesh->vertexPtr(vtxID10));
+ const Vec3fa vtx11 = Vec3fa::loadu(mesh->vertexPtr(vtxID11));
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const Vec3fa vtx02 = Vec3fa::loadu(mesh->vertexPtr(vtxID02));
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const Vec3fa vtx12 = Vec3fa::loadu(mesh->vertexPtr(vtxID12));
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const Vec3fa vtx20 = Vec3fa::loadu(mesh->vertexPtr(vtxID20));
+ const Vec3fa vtx21 = Vec3fa::loadu(mesh->vertexPtr(vtxID21));
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const Vec3fa vtx22 = Vec3fa::loadu(mesh->vertexPtr(vtxID22));
+
+ vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
+ vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
+ vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
+ vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
+ }
+
+ /* Gather the quads */
+ __forceinline void gatherMB(vfloat4 vtx[16], const Scene *const scene, const size_t itime, const float ftime) const
+ {
+ const GridMesh* mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
+ const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
+ const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
+ const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
+
+ vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
+ vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
+ vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
+ vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
+ }
+
+
+ /* Calculate the bounds of the subgrid */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ FATAL("not implemented yet");
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const size_t itime)
+ {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ FATAL("not implemented yet");
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ FATAL("not implemented yet");
+ return allBounds;
+ }
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGrid& sg) {
+ return cout << "SubGrid " << " ( x " << sg.x() << ", y = " << sg.y() << ", geomID = " << sg.geomID() << ", primID = " << sg.primID() << " )";
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID() const { return _primID; }
+ __forceinline unsigned int x() const { return (unsigned int)_x & 0x7fff; }
+ __forceinline unsigned int y() const { return (unsigned int)_y & 0x7fff; }
+
+ private:
+ unsigned short _x;
+ unsigned short _y;
+ unsigned int _geomID; // geometry ID of mesh
+ unsigned int _primID; // primitive ID of primitive inside mesh
+ };
+
+ struct SubGridID {
+ unsigned short x;
+ unsigned short y;
+ unsigned int primID;
+
+ __forceinline SubGridID() {}
+ __forceinline SubGridID(const unsigned int x, const unsigned int y, const unsigned int primID) :
+ x(x), y(y), primID(primID) {}
+ };
+
+ /* QuantizedBaseNode as large subgrid leaf */
+ template<int N>
+ struct SubGridQBVHN
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ __forceinline size_t size() const
+ {
+ for (size_t i=0;i<N;i++)
+ if (primID(i) == -1) return i;
+ return N;
+ }
+
+ __forceinline void clear() {
+ for (size_t i=0;i<N;i++)
+ subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
+ qnode.clear();
+ }
+
+ /* Default constructor */
+ __forceinline SubGridQBVHN() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGridQBVHN(const unsigned int x[N],
+ const unsigned int y[N],
+ const unsigned int primID[N],
+ const BBox3fa * const subGridBounds,
+ const unsigned int geomID,
+ const unsigned int items)
+ {
+ clear();
+ _geomID = geomID;
+
+ __aligned(64) typename BVHN<N>::AABBNode node;
+ node.clear();
+ for (size_t i=0;i<items;i++)
+ {
+ subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
+ node.setBounds(i,subGridBounds[i]);
+ }
+ qnode.init_dim(node);
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
+ __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
+ __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
+
+ __forceinline SubGrid subgrid(const size_t i) const {
+ assert(i < N);
+ assert(primID(i) != -1);
+ return SubGrid(x(i),y(i),geomID(),primID(i));
+ }
+
+ public:
+ SubGridID subgridIDs[N];
+
+ typename BVHN<N>::QuantizedBaseNode qnode;
+
+ unsigned int _geomID; // geometry ID of mesh
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGridQBVHN& sg) {
+ cout << "SubGridQBVHN " << embree_endl;
+ for (size_t i=0;i<N;i++)
+ cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
+ cout << "geomID " << sg._geomID << embree_endl;
+ cout << "lowerX " << sg.qnode.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.dequantizeUpperZ() << embree_endl;
+ return cout;
+ }
+
+ };
+
+ template<int N>
+ typename SubGridQBVHN<N>::Type SubGridQBVHN<N>::type;
+
+ typedef SubGridQBVHN<4> SubGridQBVH4;
+ typedef SubGridQBVHN<8> SubGridQBVH8;
+
+
+ /* QuantizedBaseNode as large subgrid leaf */
+ template<int N>
+ struct SubGridMBQBVHN
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ __forceinline size_t size() const
+ {
+ for (size_t i=0;i<N;i++)
+ if (primID(i) == -1) return i;
+ return N;
+ }
+
+ __forceinline void clear() {
+ for (size_t i=0;i<N;i++)
+ subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
+ qnode.clear();
+ }
+
+ /* Default constructor */
+ __forceinline SubGridMBQBVHN() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGridMBQBVHN(const unsigned int x[N],
+ const unsigned int y[N],
+ const unsigned int primID[N],
+ const BBox3fa * const subGridBounds0,
+ const BBox3fa * const subGridBounds1,
+ const unsigned int geomID,
+ const float toffset,
+ const float tscale,
+ const unsigned int items)
+ {
+ clear();
+ _geomID = geomID;
+ time_offset = toffset;
+ time_scale = tscale;
+
+ __aligned(64) typename BVHN<N>::AABBNode node0,node1;
+ node0.clear();
+ node1.clear();
+ for (size_t i=0;i<items;i++)
+ {
+ subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
+ node0.setBounds(i,subGridBounds0[i]);
+ node1.setBounds(i,subGridBounds1[i]);
+ }
+ qnode.node0.init_dim(node0);
+ qnode.node1.init_dim(node1);
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
+ __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
+ __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
+
+ __forceinline SubGrid subgrid(const size_t i) const {
+ assert(i < N);
+ assert(primID(i) != -1);
+ return SubGrid(x(i),y(i),geomID(),primID(i));
+ }
+
+ __forceinline float adjustTime(const float t) const { return time_scale * (t-time_offset); }
+
+ template<int K>
+ __forceinline vfloat<K> adjustTime(const vfloat<K> &t) const { return time_scale * (t-time_offset); }
+
+ public:
+ SubGridID subgridIDs[N];
+
+ typename BVHN<N>::QuantizedBaseNodeMB qnode;
+
+ float time_offset;
+ float time_scale;
+ unsigned int _geomID; // geometry ID of mesh
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGridMBQBVHN& sg) {
+ cout << "SubGridMBQBVHN " << embree_endl;
+ for (size_t i=0;i<N;i++)
+ cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
+ cout << "geomID " << sg._geomID << embree_endl;
+ cout << "time_offset " << sg.time_offset << embree_endl;
+ cout << "time_scale " << sg.time_scale << embree_endl;
+ cout << "lowerX " << sg.qnode.node0.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.node0.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.node0.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.node0.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.node0.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.node0.dequantizeUpperZ() << embree_endl;
+ cout << "lowerX " << sg.qnode.node1.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.node1.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.node1.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.node1.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.node1.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.node1.dequantizeUpperZ() << embree_endl;
+ return cout;
+ }
+
+ };
+
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector.h
new file mode 100644
index 0000000000..045eee4329
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector.h
@@ -0,0 +1,518 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "subgrid_intersector_moeller.h"
+#include "subgrid_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ // =======================================================================================
+ // =================================== SubGridIntersectors ===============================
+ // =======================================================================================
+
+
+ template<int N, bool filter>
+ struct SubGridIntersector1Moeller
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1MoellerTrumbore<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
+ assert(accel);
+ context->geomID = subgrid.geomID();
+ context->primID = subgrid.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ } else {
+ mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ }
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+ changed |= pointQuery(query, context, prim[i].subgrid(ID));
+ }
+ }
+ return changed;
+ }
+ };
+
+ template<int N, bool filter>
+ struct SubGridIntersector1Pluecker
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
+ context->geomID = subgrid.geomID();
+ context->primID = subgrid.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ } else {
+ mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ }
+#if defined(__AVX__)
+ STAT3(point_query.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+ changed |= pointQuery(query, context, prim[i].subgrid(ID));
+ }
+ }
+ return changed;
+ }
+ };
+
+ template<int N, int K, bool filter>
+ struct SubGridIntersectorKMoeller
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+
+ template<int N, int K, bool filter>
+ struct SubGridIntersectorKPluecker
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h
new file mode 100644
index 0000000000..f65b4abf61
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_moeller.h
@@ -0,0 +1,493 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "quad_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ /* ----------------------------- */
+ /* -- single ray intersectors -- */
+ /* ----------------------------- */
+
+ template<int M>
+ __forceinline void interpolateUV(MoellerTrumboreHitM<M> &hit,const GridMesh::Grid &g, const SubGrid& subgrid)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vint<M> sx((int)subgrid.x());
+ const vint<M> sy((int)subgrid.y());
+ const vint<M> sxM(sx + vint<M>(0,1,1,0));
+ const vint<M> syM(sy + vint<M>(0,0,1,1));
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.U = (hit.U + (vfloat<M>)sxM * hit.absDen) * inv_resX;
+ hit.V = (hit.V + (vfloat<M>)syM * hit.absDen) * inv_resY;
+ }
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore;
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore
+ {
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid);
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid);
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid);
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid);
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+ return false;
+ }
+ };
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore<4,filter>
+ {
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ MoellerTrumboreHitM<8> hit;
+ MoellerTrumboreIntersector1<8> intersector(ray,nullptr);
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,hit)))
+ {
+ vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
+
+#if !defined(EMBREE_BACKFACE_CULLING)
+ hit.U = select(flags,absDen-V,U);
+ hit.V = select(flags,absDen-U,V);
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+#else
+ hit.U = select(flags,absDen-U,U);
+ hit.V = select(flags,absDen-V,V);
+#endif
+ /* correct U,V interpolation across the entire grid */
+ const vint8 sx((int)subgrid.x());
+ const vint8 sy((int)subgrid.y());
+ const vint8 sx8(sx + vint8(0,1,1,0,0,1,1,0));
+ const vint8 sy8(sy + vint8(0,0,1,1,0,0,1,1));
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.U = (hit.U + (vfloat8)sx8 * absDen) * inv_resX;
+ hit.V = (hit.V + (vfloat8)sy8 * absDen) * inv_resY;
+
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+ // ============================================================================================================================
+ // ============================================================================================================================
+ // ============================================================================================================================
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ template<int K>
+ struct SubGridQuadHitK
+ {
+ __forceinline SubGridQuadHitK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& T,
+ const vfloat<K>& absDen,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid& subgrid,
+ const unsigned int i)
+ : U(U), V(V), T(T), absDen(absDen), flags(flags), tri_Ng(Ng), g(g), subgrid(subgrid), i(i) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u0 = min(U * rcpAbsDen,1.0f);
+ const vfloat<K> v0 = min(V * rcpAbsDen,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> uu = select(flags,u1,u0);
+ const vfloat<K> vv = select(flags,v1,v0);
+ const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
+ const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
+ const float inv_resX = rcp((float)(int)(g.resX-1));
+ const float inv_resY = rcp((float)(int)(g.resY-1));
+ const vfloat<K> u = (uu + (float)(int)sx) * inv_resX;
+ const vfloat<K> v = (vv + (float)(int)sy) * inv_resY;
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+
+ const GridMesh::Grid &g;
+ const SubGrid& subgrid;
+ const size_t i;
+ };
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumboreBase
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumboreBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray.org;
+ const Vec3vf<K> R = cross(C,ray.dir);
+ const vfloat<K> den = dot(tri_Ng,ray.dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(R,tri_e2) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(R,tri_e1) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray.tnear() < T) & (T <= absDen*ray.tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ SubGridQuadHitK<K> hit(U,V,T,absDen,tri_Ng,flags,g,subgrid,i);
+ return epilog(valid,hit);
+ }
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray,tri_v0,e1,e2,Ng,flags,g,subgrid,i,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),g,subgrid,i,epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),g,subgrid,i,epilog);
+ return none(valid0);
+ }
+
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Vec3vf<M>& tri_Ng,
+ MoellerTrumboreHitM<M> &hit)
+ {
+ /* calculate denominator */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
+ const Vec3vf<M> R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
+ const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ new (&hit) MoellerTrumboreHitM<M>(valid,U,V,T,absDen,tri_Ng);
+ return true;
+ }
+
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ MoellerTrumboreHitM<M> &hit)
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ const Vec3vf<M> Ng = cross(e2,e1);
+ return intersect1(ray,k,v0,e1,e2,Ng,hit);
+ }
+
+ };
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumbore : public SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+
+ MoellerTrumboreHitM<4> hit;
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid);
+ epilog(hit.valid,hit);
+ }
+
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid);
+ epilog(hit.valid,hit);
+ }
+
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+
+ MoellerTrumboreHitM<4> hit;
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid);
+ if (epilog(hit.valid,hit)) return true;
+ }
+
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid);
+ if (epilog(hit.valid,hit)) return true;
+ }
+ return false;
+ }
+ };
+
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> : public SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid &subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+
+ MoellerTrumboreHitM<8> hit;
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<8,K,filter>::intersect1(ray,k,vtx0,vtx1,vtx2,hit))
+ {
+ vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
+#if !defined(EMBREE_BACKFACE_CULLING)
+ hit.U = select(flags,absDen-V,U);
+ hit.V = select(flags,absDen-U,V);
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+#else
+ hit.U = select(flags,absDen-U,U);
+ hit.V = select(flags,absDen-V,V);
+#endif
+
+ /* correct U,V interpolation across the entire grid */
+ const vint8 sx((int)subgrid.x());
+ const vint8 sy((int)subgrid.y());
+ const vint8 sx8(sx + vint8(0,1,1,0,0,1,1,0));
+ const vint8 sy8(sy + vint8(0,0,1,1,0,0,1,1));
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.U = (hit.U + (vfloat8)sx8 * absDen) * inv_resX;
+ hit.V = (hit.V + (vfloat8)sy8 * absDen) * inv_resY;
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+
+ }
+ return false;
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h
new file mode 100644
index 0000000000..1cd88aa799
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subgrid_intersector_pluecker.h
@@ -0,0 +1,508 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ template<int M>
+ struct SubGridQuadHitPlueckerM
+ {
+ __forceinline SubGridQuadHitPlueckerM() {}
+
+ __forceinline SubGridQuadHitPlueckerM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& UVW,
+ const vfloat<M>& t,
+ const Vec3vf<M>& Ng,
+ const vbool<M>& flags) : valid(valid), vt(t)
+ {
+ const vbool<M> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
+ const vfloat<M> u = min(U * rcpUVW,1.0f);
+ const vfloat<M> v = min(V * rcpUVW,1.0f);
+ const vfloat<M> u1 = vfloat<M>(1.0f) - u;
+ const vfloat<M> v1 = vfloat<M>(1.0f) - v;
+#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
+ vu = select(flags,u1,u);
+ vv = select(flags,v1,v);
+ vNg = Vec3vf<M>(Ng.x,Ng.y,Ng.z);
+#else
+ const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
+ vv = select(flags,u1,v);
+ vu = select(flags,v1,u);
+ vNg = Vec3vf<M>(flip*Ng.x,flip*Ng.y,flip*Ng.z);
+#endif
+ }
+
+ __forceinline void finalize()
+ {
+ }
+
+ __forceinline Vec2f uv(const size_t i)
+ {
+ const float u = vu[i];
+ const float v = vv[i];
+ return Vec2f(u,v);
+ }
+
+ __forceinline float t(const size_t i) { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ __forceinline void interpolateUV(SubGridQuadHitPlueckerM<M> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const vint<M> &stepX, const vint<M> &stepY)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vint<M> sx((int)subgrid.x());
+ const vint<M> sy((int)subgrid.y());
+ const vint<M> sxM(sx + stepX);
+ const vint<M> syM(sy + stepY);
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.vu = (hit.vu + vfloat<M>(sxM)) * inv_resX;
+ hit.vv = (hit.vv + vfloat<M>(syM)) * inv_resY;
+ }
+
+ template<int M>
+ __forceinline static bool intersectPluecker(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const vbool<M>& flags,
+ SubGridQuadHitPlueckerM<M> &hit)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ new (&hit) SubGridQuadHitPlueckerM<M>(valid,U,V,UVW,t,Ng,flags);
+ return true;
+ }
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1Pluecker;
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1Pluecker
+ {
+ __forceinline SubGridQuadMIntersector1Pluecker() {}
+
+ __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ SubGridQuadHitPlueckerM<M> hit;
+ Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersectPluecker(ray,v0,v1,v3,vbool<M>(false),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersectPluecker(ray,v2,v3,v1,vbool<M>(true),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ SubGridQuadHitPlueckerM<M> hit;
+ Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersectPluecker(ray,v0,v1,v3,vbool<M>(false),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersectPluecker(ray,v2,v3,v1,vbool<M>(true),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct SubGridQuadMIntersector1Pluecker<4,filter>
+ {
+ __forceinline SubGridQuadMIntersector1Pluecker() {}
+
+ __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ SubGridQuadHitPlueckerM<8> hit;
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersectPluecker(ray,vtx0,vtx1,vtx2,flags,hit)))
+ {
+ /* correct U,V interpolation across the entire grid */
+ interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ template<int K>
+ struct SubGridQuadHitPlueckerK
+ {
+ __forceinline SubGridQuadHitPlueckerK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& UVW,
+ const vfloat<K>& t,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid& subgrid,
+ const unsigned int i)
+ : U(U), V(V), UVW(UVW), t(t), flags(flags), tri_Ng(Ng), g(g), subgrid(subgrid), i(i) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vbool<K> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
+ const vfloat<K> u0 = min(U * rcpUVW,1.0f);
+ const vfloat<K> v0 = min(V * rcpUVW,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> uu = select(flags,u1,u0);
+ const vfloat<K> vv = select(flags,v1,v0);
+ const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
+ const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
+ const float inv_resX = rcp((float)(int)(g.resX-1));
+ const float inv_resY = rcp((float)(int)(g.resY-1));
+ const vfloat<K> u = (uu + (float)(int)sx) * inv_resX;
+ const vfloat<K> v = (vv + (float)(int)sy) * inv_resY;
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> UVW;
+ const vfloat<K> t;
+ const vfloat<K> absDen;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+
+ const GridMesh::Grid &g;
+ const SubGrid& subgrid;
+ const size_t i;
+ };
+
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKPlueckerBase
+ {
+ __forceinline SubGridQuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Vec3vf<K>& tri_Ng,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ /* calculate vertices relative to ray origin */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> O = ray.org;
+ const Vec3vf<K> D = ray.dir;
+ const Vec3vf<K> v0 = tri_v0-O;
+ const Vec3vf<K> v1 = tri_v1-O;
+ const Vec3vf<K> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<K> e0 = v2-v0;
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
+ const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
+ const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
+ const vfloat<K> UVW = U+V+W;
+ const vfloat<K> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
+
+ /* perform depth test */
+ const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
+ const vfloat<K> t = rcp(den)*T;
+ valid &= ray.tnear() <= t & t <= ray.tfar;
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* calculate hit information */
+ SubGridQuadHitPlueckerK<K> hit(U,V,UVW,t,tri_Ng,flags,g,subgrid,i);
+ return epilog(valid,hit);
+ }
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const vbool<K>& flags,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v2-v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray,v0,v1,v2,Ng,flags,g,subgrid,i,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),g,subgrid,i,epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),g,subgrid,i,epilog);
+ return none(valid0);
+ }
+
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const Vec3vf<M>& tri_Ng,
+ const vbool<M>& flags,
+ SubGridQuadHitPlueckerM<M> &hit)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps ;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ new (&hit) SubGridQuadHitPlueckerM<M>(valid,U,V,UVW,t,tri_Ng,flags);
+ return true;
+ }
+
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const vbool<M>& flags,
+ SubGridQuadHitPlueckerM<M> &hit)
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ const Vec3vf<M> Ng = cross(e2,e1); // FIXME: optimize!!!
+ return intersect1(ray,k,v0,v1,v2,Ng,flags,hit);
+ }
+
+ };
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKPluecker : public SubGridQuadMIntersectorKPlueckerBase<M,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+
+ SubGridQuadHitPlueckerM<4> hit;
+ if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,vboolf4(false),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,vboolf4(true),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+
+ SubGridQuadHitPlueckerM<4> hit;
+ if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v0,v1,v3,vboolf4(false),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+
+ if (SubGridQuadMIntersectorKPlueckerBase<4,K,filter>::intersect1(ray,k,v2,v3,v1,vboolf4(true),hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+ return false;
+ }
+ };
+
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/subgrid_mb_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/subgrid_mb_intersector.h
new file mode 100644
index 0000000000..400a88b985
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/subgrid_mb_intersector.h
@@ -0,0 +1,236 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, bool filter>
+ struct SubGridMBIntersector1Pluecker
+ {
+ typedef SubGridMBQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ float ftime;
+ const int itime = mesh->timeSegment(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime,ftime);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ float ftime;
+ const int itime = mesh->timeSegment(ray.time(), ftime);
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime,ftime);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, subgrid);
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<Nx> dist;
+ const float time = prim[i].adjustTime(ray.time());
+
+ assert(time <= 1.0f);
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ const float time = prim[i].adjustTime(ray.time());
+ assert(time <= 1.0f);
+ vfloat<Nx> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ assert(false && "not implemented");
+ return false;
+ }
+ };
+
+
+ template<int N, int K, bool filter>
+ struct SubGridMBIntersectorKPluecker
+ {
+ typedef SubGridMBQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ size_t m_valid = movemask(valid_i);
+ while(m_valid)
+ {
+ size_t ID = bscf(m_valid);
+ intersect(pre,ray,ID,context,subgrid);
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ size_t m_valid = movemask(valid_i);
+ while(m_valid)
+ {
+ size_t ID = bscf(m_valid);
+ if (occluded(pre,ray,ID,context,subgrid))
+ clear(valid0,ID);
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime[k],ftime[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime[k],ftime[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ const vfloat<K> time = prim[j].adjustTime(ray.time());
+
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,time,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ const vfloat<K> time = prim[j].adjustTime(ray.time());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,time,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ const float time = prim[i].adjustTime(ray.time()[k]);
+ assert(time <= 1.0f);
+
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<int Nx, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,Nx,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,Nx,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ const float time = prim[i].adjustTime(ray.time()[k]);
+ assert(time <= 1.0f);
+
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle.h b/thirdparty/embree-aarch64/kernels/geometry/triangle.h
new file mode 100644
index 0000000000..0dedf6dc4c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle.h
@@ -0,0 +1,162 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Precalculated representation for M triangles. Stores for each
+ triangle a base vertex, two edges, and the geometry normal to
+ speed up intersection calculations */
+ template<int M>
+ struct TriangleM
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleM() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleM(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), e1(v0-v1), e2(v2-v0), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangle */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> p0 = v0;
+ Vec3vf<M> p1 = v0-e1;
+ Vec3vf<M> p2 = v0+e2;
+ Vec3vf<M> lower = min(p0,p1,p2);
+ Vec3vf<M> upper = max(p0,p1,p2);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(TriangleM* dst, const TriangleM& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->e1.x,src.e1.x);
+ vfloat<M>::store_nt(&dst->e1.y,src.e1.y);
+ vfloat<M>::store_nt(&dst->e1.z,src.e1.z);
+ vfloat<M>::store_nt(&dst->e2.x,src.e2.x);
+ vfloat<M>::store_nt(&dst->e2.y,src.e2.y);
+ vfloat<M>::store_nt(&dst->e2.z,src.e2.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (unlikely(geomID(i) == -1)) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // base vertex of the triangles
+ Vec3vf<M> e1; // 1st edge of the triangles (v0-v1)
+ Vec3vf<M> e2; // 2nd edge of the triangles (v2-v0)
+ private:
+ vuint<M> geomIDs; // geometry IDs
+ vuint<M> primIDs; // primitive IDs
+ };
+
+ template<int M>
+ typename TriangleM<M>::Type TriangleM<M>::type;
+
+ typedef TriangleM<4> Triangle4;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector.h
new file mode 100644
index 0000000000..125a42c5fe
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector.h
@@ -0,0 +1,96 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "triangle_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMIntersector1Moeller
+ {
+ typedef TriangleM<M> Primitive;
+ typedef MoellerTrumboreIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMIntersectorKMoeller
+ {
+ typedef TriangleM<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT_USER(0,TriangleM<M>::max_size());
+ for (size_t i=0; i<TriangleM<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> e1 = broadcast<vfloat<K>>(tri.e1,i);
+ const Vec3vf<K> e2 = broadcast<vfloat<K>>(tri.e2,i);
+ pre.intersectEdgeK(valid_i,ray,p0,e1,e2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleM<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> e1 = broadcast<vfloat<K>>(tri.e1,i);
+ const Vec3vf<K> e2 = broadcast<vfloat<K>>(tri.e2,i);
+ pre.intersectEdgeK(valid0,ray,p0,e1,e2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_moeller.h b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_moeller.h
new file mode 100644
index 0000000000..b5a8519236
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_moeller.h
@@ -0,0 +1,403 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+/*! This intersector implements a modified version of the Moeller
+ * Trumbore intersector from the paper "Fast, Minimum Storage
+ * Ray-Triangle Intersection". In contrast to the paper we
+ * precalculate some factors and factor the calculations differently
+ * to allow precalculating the cross product e1 x e2. The resulting
+ * algorithm is similar to the fastest one of the paper "Optimizing
+ * Ray-Triangle Intersection via Automated Search". */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct MoellerTrumboreHitM
+ {
+ __forceinline MoellerTrumboreHitM() {}
+
+ __forceinline MoellerTrumboreHitM(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const vfloat<M>& absDen, const Vec3vf<M>& Ng)
+ : U(U), V(V), T(T), absDen(absDen), valid(valid), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ const vfloat<M> rcpAbsDen = rcp(absDen);
+ vt = T * rcpAbsDen;
+ vu = U * rcpAbsDen;
+ vv = V * rcpAbsDen;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ vfloat<M> absDen;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct MoellerTrumboreIntersector1
+ {
+ __forceinline MoellerTrumboreIntersector1() {}
+
+ __forceinline MoellerTrumboreIntersector1(const Ray& ray, const void* ptr) {}
+
+ __forceinline bool intersect(const vbool<M>& valid0,
+ Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Vec3vf<M>& tri_Ng,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ /* calculate denominator */
+ vbool<M> valid = valid0;
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
+ const Vec3vf<M> R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
+
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
+ const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ valid &= (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()) < T) & (T <= absDen*vfloat<M>(ray.tfar));
+ if (likely(none(valid))) return false;
+
+
+ /* update hit information */
+ new (&hit) MoellerTrumboreHitM<M>(valid,U,V,T,absDen,tri_Ng);
+
+ return true;
+ }
+
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ vbool<M> valid = true;
+ const Vec3<vfloat<M>> tri_Ng = cross(tri_e2,tri_e1);
+ return intersect(valid,ray,tri_v0,tri_e1,tri_e2,tri_Ng,hit);
+ }
+
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,v0,e1,e2,hit);
+ }
+
+ __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(valid,ray,v0,e1,e2,hit);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& e1,
+ const Vec3vf<M>& e2,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ if (likely(intersectEdge(ray,v0,e1,e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ if (likely(intersect(ray,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ if (likely(intersect(valid,ray,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+ };
+
+ template<int K>
+ struct MoellerTrumboreHitK
+ {
+ __forceinline MoellerTrumboreHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& T, const vfloat<K>& absDen, const Vec3vf<K>& Ng)
+ : U(U), V(V), T(T), absDen(absDen), Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u = U * rcpAbsDen;
+ const vfloat<K> v = V * rcpAbsDen;
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const Vec3vf<K> Ng;
+ };
+
+ template<int M, int K>
+ struct MoellerTrumboreIntersectorK
+ {
+ __forceinline MoellerTrumboreIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ //RayK<K>& ray,
+ const Vec3vf<K>& ray_org,
+ const Vec3vf<K>& ray_dir,
+ const vfloat<K>& ray_tnear,
+ const vfloat<K>& ray_tfar,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray_org;
+ const Vec3vf<K> R = cross(C,ray_dir);
+ const vfloat<K> den = dot(tri_Ng,ray_dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(tri_e2,R) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(tri_e1,R) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray_tnear < T) & (T <= absDen*ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ MoellerTrumboreHitK<K> hit(U,V,T,absDen,tri_Ng);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,epilog);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectEdgeK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> tri_Ng = cross(tri_e2,tri_e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,tri_e1,tri_e2,tri_Ng,epilog);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ /* calculate denominator */
+ typedef Vec3vf<M> Vec3vfM;
+ const Vec3vf<M> tri_Ng = cross(tri_e2,tri_e1);
+
+ const Vec3vfM O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vfM D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vfM C = Vec3vfM(tri_v0) - O;
+ const Vec3vfM R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vfM(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(Vec3vf<M>(tri_e2),R) ^ sgnDen;
+ const vfloat<M> V = dot(Vec3vf<M>(tri_e1),R) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ new (&hit) MoellerTrumboreHitM<M>(valid,U,V,T,absDen,tri_Ng);
+ return true;
+ }
+
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ MoellerTrumboreHitM<M>& hit) const
+ {
+ if (likely(intersect(ray,k,tri_v0,tri_e1,tri_e2,hit)))
+ {
+ hit.valid &= time_range.lower <= vfloat<M>(ray.time[k]);
+ hit.valid &= vfloat<M>(ray.time[k]) < time_range.upper;
+ return any(hit.valid);
+ }
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ if (likely(intersectEdge(ray,k,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M> hit;
+ if (likely(intersectEdge(ray,k,time_range,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,v0,e1,e2,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,time_range,v0,e1,e2,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_pluecker.h b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_pluecker.h
new file mode 100644
index 0000000000..f1de99d208
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_pluecker.h
@@ -0,0 +1,247 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "trianglev.h"
+#include "trianglev_mb.h"
+#include "intersector_epilog.h"
+
+/*! Modified Pluecker ray/triangle intersector. The test first shifts
+ * the ray origin into the origin of the coordinate system and then
+ * uses Pluecker coordinates for the intersection. Due to the shift,
+ * the Pluecker coordinate calculation simplifies and the tests get
+ * numerically stable. The edge equations are watertight along the
+ * edge for neighboring triangles. */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, typename UVMapper>
+ struct PlueckerHitM
+ {
+ __forceinline PlueckerHitM(const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& UVW, const vfloat<M>& t, const Vec3vf<M>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), UVW(UVW), mapUV(mapUV), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ const vbool<M> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
+ vu = U * rcpUVW;
+ vv = V * rcpUVW;
+ mapUV(vu,vv);
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ const vfloat<M> U;
+ const vfloat<M> V;
+ const vfloat<M> UVW;
+ const UVMapper& mapUV;
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct PlueckerIntersector1
+ {
+ __forceinline PlueckerIntersector1() {}
+
+ __forceinline PlueckerIntersector1(const Ray& ray, const void* ptr) {}
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ PlueckerHitM<M,UVMapper> hit(U,V,UVW,t,Ng,mapUV);
+ return epilog(valid,hit);
+ }
+ };
+
+ template<int K, typename UVMapper>
+ struct PlueckerHitK
+ {
+ __forceinline PlueckerHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& UVW, const vfloat<K>& t, const Vec3vf<K>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), UVW(UVW), t(t), Ng(Ng), mapUV(mapUV) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vbool<K> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
+ vfloat<K> u = U * rcpUVW;
+ vfloat<K> v = V * rcpUVW;
+ mapUV(u,v);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> UVW;
+ const vfloat<K> t;
+ const Vec3vf<K> Ng;
+ const UVMapper& mapUV;
+ };
+
+ template<int M, int K>
+ struct PlueckerIntersectorK
+ {
+ __forceinline PlueckerIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper, typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> O = ray.org;
+ const Vec3vf<K> D = ray.dir;
+ const Vec3vf<K> v0 = tri_v0-O;
+ const Vec3vf<K> v1 = tri_v1-O;
+ const Vec3vf<K> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<K> e0 = v2-v0;
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
+ const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
+ const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
+ const vfloat<K> UVW = U+V+W;
+ const vfloat<K> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
+
+ /* perform depth test */
+ const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
+ const vfloat<K> t = rcp(den)*T;
+ valid &= ray.tnear() <= t & t <= ray.tfar;
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* calculate hit information */
+ PlueckerHitK<K,UVMapper> hit(U,V,UVW,t,Ng,mapUV);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray, size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ PlueckerHitM<M,UVMapper> hit(U,V,UVW,t,Ng,mapUV);
+ return epilog(valid,hit);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_woop.h b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_woop.h
new file mode 100644
index 0000000000..63e649d8fb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle_intersector_woop.h
@@ -0,0 +1,418 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+/*! This intersector implements a modified version of the Woop's ray-triangle intersection test */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct WoopHitM
+ {
+ __forceinline WoopHitM() {}
+
+ __forceinline WoopHitM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& T,
+ const vfloat<M>& inv_det,
+ const Vec3vf<M>& Ng)
+ : U(U), V(V), T(T), inv_det(inv_det), valid(valid), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ vt = T;
+ vu = U*inv_det;
+ vv = V*inv_det;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ const vfloat<M> U;
+ const vfloat<M> V;
+ const vfloat<M> T;
+ const vfloat<M> inv_det;
+
+ public:
+ const vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct WoopPrecalculations1
+ {
+ unsigned int kx,ky,kz;
+ Vec3vf<M> org;
+ Vec3fa S;
+ __forceinline WoopPrecalculations1() {}
+
+ __forceinline WoopPrecalculations1(const Ray& ray, const void* ptr)
+ {
+ kz = maxDim(abs(ray.dir));
+ kx = (kz+1) % 3;
+ ky = (kx+1) % 3;
+ const float inv_dir_kz = rcp(ray.dir[kz]);
+ if (ray.dir[kz]) std::swap(kx,ky);
+ S.x = ray.dir[kx] * inv_dir_kz;
+ S.y = ray.dir[ky] * inv_dir_kz;
+ S.z = inv_dir_kz;
+ org = Vec3vf<M>(ray.org[kx],ray.org[ky],ray.org[kz]);
+ }
+ };
+
+
+ template<int M>
+ struct WoopIntersector1
+ {
+
+ typedef WoopPrecalculations1<M> Precalculations;
+
+ __forceinline WoopIntersector1() {}
+
+ __forceinline WoopIntersector1(const Ray& ray, const void* ptr) {}
+
+ static __forceinline bool intersect(const vbool<M>& valid0,
+ Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ WoopHitM<M>& hit)
+ {
+ vbool<M> valid = valid0;
+
+ /* vertices relative to ray origin */
+ const Vec3vf<M> org = Vec3vf<M>(pre.org.x,pre.org.y,pre.org.z);
+ const Vec3vf<M> A = Vec3vf<M>(tri_v0[pre.kx],tri_v0[pre.ky],tri_v0[pre.kz]) - org;
+ const Vec3vf<M> B = Vec3vf<M>(tri_v1[pre.kx],tri_v1[pre.ky],tri_v1[pre.kz]) - org;
+ const Vec3vf<M> C = Vec3vf<M>(tri_v2[pre.kx],tri_v2[pre.ky],tri_v2[pre.kz]) - org;
+
+ /* shear and scale vertices */
+ const vfloat<M> Ax = nmadd(A.z,pre.S.x,A.x);
+ const vfloat<M> Ay = nmadd(A.z,pre.S.y,A.y);
+ const vfloat<M> Bx = nmadd(B.z,pre.S.x,B.x);
+ const vfloat<M> By = nmadd(B.z,pre.S.y,B.y);
+ const vfloat<M> Cx = nmadd(C.z,pre.S.x,C.x);
+ const vfloat<M> Cy = nmadd(C.z,pre.S.y,C.y);
+
+ /* scaled barycentric */
+ const vfloat<M> U0 = Cx*By;
+ const vfloat<M> U1 = Cy*Bx;
+ const vfloat<M> V0 = Ax*Cy;
+ const vfloat<M> V1 = Ay*Cx;
+ const vfloat<M> W0 = Bx*Ay;
+ const vfloat<M> W1 = By*Ax;
+#if !defined(__AVX512F__)
+ valid &= (U0 >= U1) & (V0 >= V1) & (W0 >= W1) |
+ (U0 <= U1) & (V0 <= V1) & (W0 <= W1);
+#else
+ valid &= ge(ge(U0 >= U1,V0,V1),W0,W1) | le(le(U0 <= U1,V0,V1),W0,W1);
+#endif
+
+ if (likely(none(valid))) return false;
+ const vfloat<M> U = U0-U1;
+ const vfloat<M> V = V0-V1;
+ const vfloat<M> W = W0-W1;
+
+ const vfloat<M> det = U+V+W;
+
+ valid &= det != 0.0f;
+ const vfloat<M> inv_det = rcp(det);
+
+ const vfloat<M> Az = pre.S.z * A.z;
+ const vfloat<M> Bz = pre.S.z * B.z;
+ const vfloat<M> Cz = pre.S.z * C.z;
+ const vfloat<M> T = madd(U,Az,madd(V,Bz,W*Cz));
+ const vfloat<M> t = T * inv_det;
+ /* perform depth test */
+ valid &= (vfloat<M>(ray.tnear()) < t) & (t <= vfloat<M>(ray.tfar));
+ if (likely(none(valid))) return false;
+
+ const Vec3vf<M> tri_Ng = cross(tri_v2-tri_v0,tri_v0-tri_v1);
+
+ /* update hit information */
+ new (&hit) WoopHitM<M>(valid,U,V,t,inv_det,tri_Ng);
+ return true;
+ }
+
+ static __forceinline bool intersect(Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ WoopHitM<M>& hit)
+ {
+ vbool<M> valid = true;
+ return intersect(valid,ray,pre,v0,v1,v2,hit);
+ }
+
+
+ template<typename Epilog>
+ static __forceinline bool intersect(Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog)
+ {
+ WoopHitM<M> hit;
+ if (likely(intersect(ray,pre,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog)
+ {
+ WoopHitM<M> hit;
+ if (likely(intersect(valid,ray,pre,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+ };
+
+#if 0
+ template<int K>
+ struct WoopHitK
+ {
+ __forceinline WoopHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& T, const vfloat<K>& absDen, const Vec3vf<K>& Ng)
+ : U(U), V(V), T(T), absDen(absDen), Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u = U * rcpAbsDen;
+ const vfloat<K> v = V * rcpAbsDen;
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const Vec3vf<K> Ng;
+ };
+
+ template<int M, int K>
+ struct WoopIntersectorK
+ {
+ __forceinline WoopIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ //RayK<K>& ray,
+ const Vec3vf<K>& ray_org,
+ const Vec3vf<K>& ray_dir,
+ const vfloat<K>& ray_tnear,
+ const vfloat<K>& ray_tfar,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray_org;
+ const Vec3vf<K> R = cross(C,ray_dir);
+ const vfloat<K> den = dot(tri_Ng,ray_dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(tri_e2,R) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(tri_e1,R) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray_tnear < T) & (T <= absDen*ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ WoopHitK<K> hit(U,V,T,absDen,tri_Ng);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,epilog);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectEdgeK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> tri_Ng = cross(tri_e2,tri_e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,tri_e1,tri_e2,tri_Ng,epilog);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ WoopHitM<M>& hit) const
+ {
+ /* calculate denominator */
+ typedef Vec3vf<M> Vec3vfM;
+ const Vec3vf<M> tri_Ng = cross(tri_e2,tri_e1);
+
+ const Vec3vfM O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vfM D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vfM C = Vec3vfM(tri_v0) - O;
+ const Vec3vfM R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vfM(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(Vec3vf<M>(tri_e2),R) ^ sgnDen;
+ const vfloat<M> V = dot(Vec3vf<M>(tri_e1),R) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ new (&hit) WoopHitM<M>(valid,U,V,T,absDen,tri_Ng);
+ return true;
+ }
+
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ WoopHitM<M>& hit) const
+ {
+ if (likely(intersect(ray,k,tri_v0,tri_e1,tri_e2,hit)))
+ {
+ hit.valid &= time_range.lower <= vfloat<M>(ray.time[k]);
+ hit.valid &= vfloat<M>(ray.time[k]) < time_range.upper;
+ return any(hit.valid);
+ }
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ WoopHitM<M> hit;
+ if (likely(intersectEdge(ray,k,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ WoopHitM<M> hit;
+ if (likely(intersectEdge(ray,k,time_range,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,v0,e1,e2,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,time_range,v0,e1,e2,epilog);
+ }
+ };
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/triangle_triangle_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/triangle_triangle_intersector.h
new file mode 100644
index 0000000000..91b35c36f3
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/triangle_triangle_intersector.h
@@ -0,0 +1,132 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primitive.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct TriangleTriangleIntersector
+ {
+ __forceinline static float T(float pa0, float pa1, float da0, float da1) {
+ return pa0 + (pa1-pa0)*da0/(da0-da1);
+ }
+
+ __forceinline static bool point_line_side(const Vec2f& p, const Vec2f& a0, const Vec2f& a1) {
+ return det(p-a0,a0-a1) >= 0.0f;
+ }
+
+ __forceinline static bool point_inside_triangle(const Vec2f& p, const Vec2f& a, const Vec2f& b, const Vec2f& c)
+ {
+ const bool pab = point_line_side(p,a,b);
+ const bool pbc = point_line_side(p,b,c);
+ const bool pca = point_line_side(p,c,a);
+ return pab == pbc && pab == pca;
+ }
+
+ __forceinline static bool intersect_line_line(const Vec2f& a0, const Vec2f& a1, const Vec2f& b0, const Vec2f& b1)
+ {
+ const bool different_sides0 = point_line_side(b0,a0,a1) != point_line_side(b1,a0,a1);
+ const bool different_sides1 = point_line_side(a0,b0,b1) != point_line_side(a1,b0,b1);
+ return different_sides0 && different_sides1;
+ }
+
+ __forceinline static bool intersect_triangle_triangle (const Vec2f& a0, const Vec2f& a1, const Vec2f& a2,
+ const Vec2f& b0, const Vec2f& b1, const Vec2f& b2)
+ {
+ const bool a01_b01 = intersect_line_line(a0,a1,b0,b1);
+ if (a01_b01) return true;
+ const bool a01_b12 = intersect_line_line(a0,a1,b1,b2);
+ if (a01_b12) return true;
+ const bool a01_b20 = intersect_line_line(a0,a1,b2,b0);
+ if (a01_b20) return true;
+ const bool a12_b01 = intersect_line_line(a1,a2,b0,b1);
+ if (a12_b01) return true;
+ const bool a12_b12 = intersect_line_line(a1,a2,b1,b2);
+ if (a12_b12) return true;
+ const bool a12_b20 = intersect_line_line(a1,a2,b2,b0);
+ if (a12_b20) return true;
+ const bool a20_b01 = intersect_line_line(a2,a0,b0,b1);
+ if (a20_b01) return true;
+ const bool a20_b12 = intersect_line_line(a2,a0,b1,b2);
+ if (a20_b12) return true;
+ const bool a20_b20 = intersect_line_line(a2,a0,b2,b0);
+ if (a20_b20) return true;
+
+ bool a_in_b = point_inside_triangle(a0,b0,b1,b2) && point_inside_triangle(a1,b0,b1,b2) && point_inside_triangle(a2,b0,b1,b2);
+ if (a_in_b) return true;
+
+ bool b_in_a = point_inside_triangle(b0,a0,a1,a2) && point_inside_triangle(b1,a0,a1,a2) && point_inside_triangle(b2,a0,a1,a2);
+ if (b_in_a) return true;
+
+ return false;
+ }
+
+ static bool intersect_triangle_triangle (const Vec3fa& a0, const Vec3fa& a1, const Vec3fa& a2,
+ const Vec3fa& b0, const Vec3fa& b1, const Vec3fa& b2)
+ {
+ const float eps = 1E-5f;
+
+ /* calculate triangle planes */
+ const Vec3fa Na = cross(a1-a0,a2-a0);
+ const float Ca = dot(Na,a0);
+ const Vec3fa Nb = cross(b1-b0,b2-b0);
+ const float Cb = dot(Nb,b0);
+
+ /* project triangle A onto plane B */
+ const float da0 = dot(Nb,a0)-Cb;
+ const float da1 = dot(Nb,a1)-Cb;
+ const float da2 = dot(Nb,a2)-Cb;
+ if (max(da0,da1,da2) < -eps) return false;
+ if (min(da0,da1,da2) > +eps) return false;
+ //CSTAT(bvh_collide_prim_intersections4++);
+
+ /* project triangle B onto plane A */
+ const float db0 = dot(Na,b0)-Ca;
+ const float db1 = dot(Na,b1)-Ca;
+ const float db2 = dot(Na,b2)-Ca;
+ if (max(db0,db1,db2) < -eps) return false;
+ if (min(db0,db1,db2) > +eps) return false;
+ //CSTAT(bvh_collide_prim_intersections5++);
+
+ if (unlikely((std::fabs(da0) < eps && std::fabs(da1) < eps && std::fabs(da2) < eps) ||
+ (std::fabs(db0) < eps && std::fabs(db1) < eps && std::fabs(db2) < eps)))
+ {
+ const size_t dz = maxDim(Na);
+ const size_t dx = (dz+1)%3;
+ const size_t dy = (dx+1)%3;
+ const Vec2f A0(a0[dx],a0[dy]);
+ const Vec2f A1(a1[dx],a1[dy]);
+ const Vec2f A2(a2[dx],a2[dy]);
+ const Vec2f B0(b0[dx],b0[dy]);
+ const Vec2f B1(b1[dx],b1[dy]);
+ const Vec2f B2(b2[dx],b2[dy]);
+ return intersect_triangle_triangle(A0,A1,A2,B0,B1,B2);
+ }
+
+ const Vec3fa D = cross(Na,Nb);
+ const float pa0 = dot(D,a0);
+ const float pa1 = dot(D,a1);
+ const float pa2 = dot(D,a2);
+ const float pb0 = dot(D,b0);
+ const float pb1 = dot(D,b1);
+ const float pb2 = dot(D,b2);
+
+ BBox1f ba = empty;
+ if (min(da0,da1) <= 0.0f && max(da0,da1) >= 0.0f && abs(da0-da1) > 0.0f) ba.extend(T(pa0,pa1,da0,da1));
+ if (min(da1,da2) <= 0.0f && max(da1,da2) >= 0.0f && abs(da1-da2) > 0.0f) ba.extend(T(pa1,pa2,da1,da2));
+ if (min(da2,da0) <= 0.0f && max(da2,da0) >= 0.0f && abs(da2-da0) > 0.0f) ba.extend(T(pa2,pa0,da2,da0));
+
+ BBox1f bb = empty;
+ if (min(db0,db1) <= 0.0f && max(db0,db1) >= 0.0f && abs(db0-db1) > 0.0f) bb.extend(T(pb0,pb1,db0,db1));
+ if (min(db1,db2) <= 0.0f && max(db1,db2) >= 0.0f && abs(db1-db2) > 0.0f) bb.extend(T(pb1,pb2,db1,db2));
+ if (min(db2,db0) <= 0.0f && max(db2,db0) >= 0.0f && abs(db2-db0) > 0.0f) bb.extend(T(pb2,pb0,db2,db0));
+
+ return conjoint(ba,bb);
+ }
+ };
+ }
+}
+
+
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglei.h b/thirdparty/embree-aarch64/kernels/geometry/trianglei.h
new file mode 100644
index 0000000000..4f3118cc0c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglei.h
@@ -0,0 +1,442 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ /* Stores M triangles from an indexed face set */
+ template <int M>
+ struct TriangleMi
+ {
+ /* Virtual interface to query information about the triangle type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMi(const vuint<M>& v0,
+ const vuint<M>& v1,
+ const vuint<M>& v2,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+#if defined(EMBREE_COMPACT_POLYS)
+ : geomIDs(geomIDs), primIDs(primIDs) {}
+#else
+ : v0_(v0), v1_(v1), v2_(v2), geomIDs(geomIDs), primIDs(primIDs) {}
+#endif
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M> geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M> primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++) {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ bounds.extend(mesh->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Non-temporal store */
+ __forceinline static void store_nt(TriangleMi* dst, const TriangleMi& src)
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M>::store_nt(&dst->v0_,src.v0_);
+ vuint<M>::store_nt(&dst->v1_,src.v1_);
+ vuint<M>::store_nt(&dst->v2_,src.v2_);
+#endif
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> v0 = zero, v1 = zero, v2 = zero;
+ vuint<M> geomID = -1, primID = -1;
+ const PrimRefT* prim = &prims[begin];
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+#if !defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(prim->geomID());
+ const TriangleMesh::Triangle& tri = mesh->triangle(prim->primID());
+ unsigned int int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = tri.v[0] * int_stride;
+ v1[i] = tri.v[1] * int_stride;
+ v2[i] = tri.v[2] * int_stride;
+#endif
+ begin++;
+ } else {
+ assert(i);
+ if (likely(i > 0)) {
+ geomID[i] = geomID[0];
+ primID[i] = -1;
+ v0[i] = v0[0];
+ v1[i] = v0[0];
+ v2[i] = v0[0];
+ }
+ }
+ if (begin<end) prim = &prims[begin];
+ }
+ new (this) TriangleMi(v0,v1,v2,geomID,primID); // FIXME: use non temporal store
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned int primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ }
+ return bounds;
+ }
+
+ protected:
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M> v0_; // 4 byte offset of 1st vertex
+ vuint<M> v1_; // 4 byte offset of 2nd vertex
+ vuint<M> v2_; // 4 byte offset of 3rd vertex
+#endif
+ vuint<M> geomIDs; // geometry ID of mesh
+ vuint<M> primIDs; // primitive ID of primitive inside mesh
+ };
+
+ namespace isa
+ {
+
+ template<int M>
+ struct TriangleMi : public embree::TriangleMi<M>
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ using embree::TriangleMi<M>::v0_;
+ using embree::TriangleMi<M>::v1_;
+ using embree::TriangleMi<M>::v2_;
+#endif
+ using embree::TriangleMi<M>::geomIDs;
+ using embree::TriangleMi<M>::primIDs;
+ using embree::TriangleMi<M>::geomID;
+ using embree::TriangleMi<M>::primID;
+ using embree::TriangleMi<M>::valid;
+
+ /* loads a single vertex */
+ template<int vid>
+ __forceinline Vec3f getVertex(const size_t index, const Scene *const scene) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ return (Vec3f) mesh->vertices[0][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices = scene->vertices[geomID(index)];
+ return (Vec3f&) vertices[v[index]];
+#endif
+ }
+
+ template<int vid, typename T>
+ __forceinline Vec3<T> getVertex(const size_t index, const Scene *const scene, const size_t itime, const T& ftime) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime+0][tri.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime+1][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ const Vec3<T> p0(v0.x,v0.y,v0.z);
+ const Vec3<T> p1(v1.x,v1.y,v1.z);
+ return lerp(p0,p1,ftime);
+ }
+
+ template<int vid, int K, typename T>
+ __forceinline Vec3<T> getVertex(const vbool<K>& valid, const size_t index, const Scene *const scene, const vint<K>& itime, const T& ftime) const
+ {
+ Vec3<T> p0, p1;
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+
+ for (size_t mask=movemask(valid), i=bsf(mask); mask; mask=btc(mask,i), i=bsf(mask))
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime[i]+0][tri.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime[i]+1][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime[i]+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime[i]+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ p0.x[i] = v0.x; p0.y[i] = v0.y; p0.z[i] = v0.z;
+ p1.x[i] = v1.x; p1.y[i] = v1.y; p1.z[i] = v1.z;
+ }
+ return (T(one)-ftime)*p0 + ftime*p1;
+ }
+
+ struct Triangle {
+ vfloat4 v0,v1,v2;
+ };
+
+#if defined(EMBREE_COMPACT_POLYS)
+
+ __forceinline Triangle loadTriangle(const int i, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero };
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices0[tri.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices0[tri.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices0[tri.v[2]];
+ return { v0, v1, v2 };
+ }
+
+ __forceinline Triangle loadTriangle(const int i, const int itime, const TriangleMesh* const mesh) const
+ {
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero };
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices[itime][tri.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices[itime][tri.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices[itime][tri.v[2]];
+ return { v0, v1, v2 };
+ }
+
+#else
+
+ __forceinline Triangle loadTriangle(const int i, const Scene* const scene) const
+ {
+ const float* vertices = scene->vertices[geomID(i)];
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ return { v0, v1, v2 };
+ }
+
+ __forceinline Triangle loadTriangle(const int i, const int itime, const TriangleMesh* const mesh) const
+ {
+ const float* vertices = (const float*) mesh->vertexPtr(0,itime);
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ return { v0, v1, v2 };
+ }
+
+#endif
+
+ /* Gather the triangles */
+ __forceinline void gather(Vec3vf<M>& p0, Vec3vf<M>& p1, Vec3vf<M>& p2, const Scene* const scene) const;
+
+ template<int K>
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 2000) // workaround for compiler bug in ICC 2019
+ __noinline
+#else
+ __forceinline
+#endif
+ void gather(const vbool<K>& valid,
+ Vec3vf<K>& p0,
+ Vec3vf<K>& p1,
+ Vec3vf<K>& p2,
+ const size_t index,
+ const Scene* const scene,
+ const vfloat<K>& time) const
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment(time, ftime);
+
+ const size_t first = bsf(movemask(valid));
+ if (likely(all(valid,itime[first] == itime)))
+ {
+ p0 = getVertex<0>(index, scene, itime[first], ftime);
+ p1 = getVertex<1>(index, scene, itime[first], ftime);
+ p2 = getVertex<2>(index, scene, itime[first], ftime);
+ } else {
+ p0 = getVertex<0>(valid, index, scene, itime, ftime);
+ p1 = getVertex<1>(valid, index, scene, itime, ftime);
+ p2 = getVertex<2>(valid, index, scene, itime, ftime);
+ }
+ }
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ const TriangleMesh* mesh,
+ const Scene *const scene,
+ const int itime) const;
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ const Scene *const scene,
+ const float time) const;
+
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<int N> const vuint<M>& getVertexOffset() const;
+#endif
+ };
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<0>() const { return v0_; }
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<1>() const { return v1_; }
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<2>() const { return v2_; }
+#endif
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const Scene* const scene) const
+ {
+ const Triangle tri0 = loadTriangle(0,scene);
+ const Triangle tri1 = loadTriangle(1,scene);
+ const Triangle tri2 = loadTriangle(2,scene);
+ const Triangle tri3 = loadTriangle(3,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ }
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const TriangleMesh* mesh,
+ const Scene *const scene,
+ const int itime) const
+ {
+ const Triangle tri0 = loadTriangle(0,itime,mesh);
+ const Triangle tri1 = loadTriangle(1,itime,mesh);
+ const Triangle tri2 = loadTriangle(2,itime,mesh);
+ const Triangle tri3 = loadTriangle(3,itime,mesh);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ }
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const Scene *const scene,
+ const float time) const
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(0)); // in mblur mode all geometries are identical
+
+ float ftime;
+ const int itime = mesh->timeSegment(time, ftime);
+
+ Vec3vf4 a0,a1,a2; gather(a0,a1,a2,mesh,scene,itime);
+ Vec3vf4 b0,b1,b2; gather(b0,b1,b2,mesh,scene,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ p2 = lerp(a2,b2,vfloat4(ftime));
+ }
+ }
+
+ template<int M>
+ typename TriangleMi<M>::Type TriangleMi<M>::type;
+
+ typedef TriangleMi<4> Triangle4i;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglei_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/trianglei_intersector.h
new file mode 100644
index 0000000000..e2f106a62c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglei_intersector.h
@@ -0,0 +1,336 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "trianglei.h"
+#include "triangle_intersector_moeller.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMiIntersector1Moeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersector1<Mx> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,v0,v1,v2,/*UVIdentity<Mx>(),*/Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,v0,v1,v2,/*UVIdentity<Mx>(),*/Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMiIntersectorKMoeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<Mx,K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ const Scene* scene = context->scene;
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid_i,ray,v0,v1,v2,/*UVIdentity<K>(),*/IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ const Scene* scene = context->scene;
+
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid0,ray,v0,v1,v2,/*UVIdentity<K>(),*/OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,k,v0,v1,v2,/*UVIdentity<Mx>(),*/Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,k,v0,v1,v2,/*UVIdentity<Mx>(),*/Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMiIntersector1Pluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersector1<Mx> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMiIntersectorKPluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersectorK<Mx,K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ const Scene* scene = context->scene;
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ const Scene* scene = context->scene;
+
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMiMBIntersector1Moeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ pre.intersect(ray,v0,v1,v2,/*UVIdentity<Mx>(),*/Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ return pre.intersect(ray,v0,v1,v2,/*UVIdentity<Mx>(),*/Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMiMBIntersectorKMoeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2; tri.gather(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,/*UVIdentity<K>(),*/IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2; tri.gather(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid0,ray,v0,v1,v2,/*UVIdentity<K>(),*/OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ pre.intersect(ray,k,v0,v1,v2,/*UVIdentity<Mx>(),*/Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ return pre.intersect(ray,k,v0,v1,v2,/*UVIdentity<Mx>(),*/Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMiMBIntersector1Pluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ return pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMiMBIntersectorKPluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2; tri.gather(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2; tri.gather(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ return pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglev.h b/thirdparty/embree-aarch64/kernels/geometry/trianglev.h
new file mode 100644
index 0000000000..19af389e73
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglev.h
@@ -0,0 +1,157 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M triangles in struct of array layout */
+ template <int M>
+ struct TriangleMv
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMv() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMv(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), v1(v1), v2(v2), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2);
+ Vec3vf<M> upper = max(v0,v1,v2);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(TriangleMv* dst, const TriangleMv& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->v1.x,src.v1.x);
+ vfloat<M>::store_nt(&dst->v1.y,src.v1.y);
+ vfloat<M>::store_nt(&dst->v1.z,src.v1.z);
+ vfloat<M>::store_nt(&dst->v2.x,src.v2.x);
+ vfloat<M>::store_nt(&dst->v2.y,src.v2.y);
+ vfloat<M>::store_nt(&dst->v2.z,src.v2.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleMv::store_nt(this,TriangleMv(v0,v1,v2,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ new (this) TriangleMv(v0,v1,v2,vgeomID,vprimID);
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the triangles
+ Vec3vf<M> v1; // 2nd vertex of the triangles
+ Vec3vf<M> v2; // 3rd vertex of the triangles
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename TriangleMv<M>::Type TriangleMv<M>::type;
+
+ typedef TriangleMv<4> Triangle4v;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglev_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/trianglev_intersector.h
new file mode 100644
index 0000000000..6af0d5a11c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglev_intersector.h
@@ -0,0 +1,206 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "triangle_intersector_pluecker.h"
+#include "triangle_intersector_moeller.h"
+#include "triangle_intersector_woop.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMvIntersector1Moeller
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef MoellerTrumboreIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<Mx>(),*/Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<Mx>(),*/Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+
+ template<int M, int Mx, bool filter>
+ struct TriangleMvIntersector1Woop
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef WoopIntersector1<Mx> intersec;
+ typedef WoopPrecalculations1<M> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMvIntersectorKMoeller
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid_i,ray,v0,v1,v2,/*UVIdentity<K>(),*/IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid0,ray,v0,v1,v2,/*UVIdentity<K>(),*/OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<Mx>(),*/Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M,Mx
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<Mx>(),*/Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M,Mx
+ }
+ };
+
+ /*! Intersects M triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMvIntersector1Pluecker
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef PlueckerIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<Mx>(),Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<Mx>(),Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMvIntersectorKPluecker
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef PlueckerIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<Mx>(),Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M,Mx
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<Mx>(),Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M,Mx
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb.h b/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb.h
new file mode 100644
index 0000000000..63137aee16
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb.h
@@ -0,0 +1,201 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M triangles in struct of array layout */
+ template<int M>
+ struct TriangleMvMB
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+
+ static Type type;
+
+ public:
+
+ /* primitive supports single time segments */
+ static const bool singleTimeSegment = true;
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMvMB() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMvMB(const Vec3vf<M>& a0, const Vec3vf<M>& a1,
+ const Vec3vf<M>& b0, const Vec3vf<M>& b1,
+ const Vec3vf<M>& c0, const Vec3vf<M>& c1,
+ const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(a0), v1(b0), v2(c0), dv0(a1-a0), dv1(b1-b0), dv2(c1-c0), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles at t0 */
+ __forceinline BBox3fa bounds0() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2);
+ Vec3vf<M> upper = max(v0,v1,v2);
+ const vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Calculate the bounds of the triangles at t1 */
+ __forceinline BBox3fa bounds1() const
+ {
+ const Vec3vf<M> p0 = v0+dv0;
+ const Vec3vf<M> p1 = v1+dv1;
+ const Vec3vf<M> p2 = v2+dv2;
+ Vec3vf<M> lower = min(p0,p1,p2);
+ Vec3vf<M> upper = max(p0,p1,p2);
+ const vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds() const {
+ return LBBox3fa(bounds0(),bounds1());
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> va0 = zero, vb0 = zero, vc0 = zero;
+ Vec3vf<M> va1 = zero, vb1 = zero, vc1 = zero;
+
+ BBox3fa bounds0 = empty;
+ BBox3fa bounds1 = empty;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& a0 = mesh->vertex(tri.v[0],itime+0); bounds0.extend(a0);
+ const Vec3fa& a1 = mesh->vertex(tri.v[0],itime+1); bounds1.extend(a1);
+ const Vec3fa& b0 = mesh->vertex(tri.v[1],itime+0); bounds0.extend(b0);
+ const Vec3fa& b1 = mesh->vertex(tri.v[1],itime+1); bounds1.extend(b1);
+ const Vec3fa& c0 = mesh->vertex(tri.v[2],itime+0); bounds0.extend(c0);
+ const Vec3fa& c1 = mesh->vertex(tri.v[2],itime+1); bounds1.extend(c1);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ va0.x[i] = a0.x; va0.y[i] = a0.y; va0.z[i] = a0.z;
+ va1.x[i] = a1.x; va1.y[i] = a1.y; va1.z[i] = a1.z;
+ vb0.x[i] = b0.x; vb0.y[i] = b0.y; vb0.z[i] = b0.z;
+ vb1.x[i] = b1.x; vb1.y[i] = b1.y; vb1.z[i] = b1.z;
+ vc0.x[i] = c0.x; vc0.y[i] = c0.y; vc0.z[i] = c0.z;
+ vc1.x[i] = c1.x; vc1.y[i] = c1.y; vc1.z[i] = c1.z;
+ }
+ new (this) TriangleMvMB(va0,va1,vb0,vb1,vc0,vc1,vgeomID,vprimID);
+ return LBBox3fa(bounds0,bounds1);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> va0 = zero, vb0 = zero, vc0 = zero;
+ Vec3vf<M> va1 = zero, vb1 = zero, vc1 = zero;
+
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRefMB& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* const mesh = scene->get<TriangleMesh>(geomID);
+ const range<int> itime_range = mesh->timeSegmentRange(time_range);
+ assert(itime_range.size() == 1);
+ const int ilower = itime_range.begin();
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ allBounds.extend(mesh->linearBounds(primID, time_range));
+ const Vec3fa& a0 = mesh->vertex(tri.v[0],ilower+0);
+ const Vec3fa& a1 = mesh->vertex(tri.v[0],ilower+1);
+ const Vec3fa& b0 = mesh->vertex(tri.v[1],ilower+0);
+ const Vec3fa& b1 = mesh->vertex(tri.v[1],ilower+1);
+ const Vec3fa& c0 = mesh->vertex(tri.v[2],ilower+0);
+ const Vec3fa& c1 = mesh->vertex(tri.v[2],ilower+1);
+ const BBox1f time_range_v(mesh->timeStep(ilower+0),mesh->timeStep(ilower+1));
+ auto a01 = globalLinear(std::make_pair(a0,a1),time_range_v);
+ auto b01 = globalLinear(std::make_pair(b0,b1),time_range_v);
+ auto c01 = globalLinear(std::make_pair(c0,c1),time_range_v);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ va0.x[i] = a01.first .x; va0.y[i] = a01.first .y; va0.z[i] = a01.first .z;
+ va1.x[i] = a01.second.x; va1.y[i] = a01.second.y; va1.z[i] = a01.second.z;
+ vb0.x[i] = b01.first .x; vb0.y[i] = b01.first .y; vb0.z[i] = b01.first .z;
+ vb1.x[i] = b01.second.x; vb1.y[i] = b01.second.y; vb1.z[i] = b01.second.z;
+ vc0.x[i] = c01.first .x; vc0.y[i] = c01.first .y; vc0.z[i] = c01.first .z;
+ vc1.x[i] = c01.second.x; vc1.y[i] = c01.second.y; vc1.z[i] = c01.second.z;
+ }
+ new (this) TriangleMvMB(va0,va1,vb0,vb1,vc0,vc1,vgeomID,vprimID);
+ return allBounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the triangles
+ Vec3vf<M> v1; // 2nd vertex of the triangles
+ Vec3vf<M> v2; // 3rd vertex of the triangles
+ Vec3vf<M> dv0; // difference vector between time steps t0 and t1 for first vertex
+ Vec3vf<M> dv1; // difference vector between time steps t0 and t1 for second vertex
+ Vec3vf<M> dv2; // difference vector between time steps t0 and t1 for third vertex
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename TriangleMvMB<M>::Type TriangleMvMB<M>::type;
+
+ typedef TriangleMvMB<4> Triangle4vMB;
+}
diff --git a/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb_intersector.h b/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb_intersector.h
new file mode 100644
index 0000000000..35a260d826
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/geometry/trianglev_mb_intersector.h
@@ -0,0 +1,211 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMvMBIntersector1Moeller
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef MoellerTrumboreIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time());
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time());
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMvMBIntersectorKMoeller
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time()[k]);
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time()[k]);
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, int Mx, bool filter>
+ struct TriangleMvMBIntersector1Pluecker
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef PlueckerIntersector1<Mx> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time());
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Intersect1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time());
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ return pre.intersect(ray,v0,v1,v2,UVIdentity<Mx>(),Occluded1EpilogM<M,Mx,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int Mx, int K, bool filter>
+ struct TriangleMvMBIntersectorKPluecker
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef PlueckerIntersectorK<Mx,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time()[k]);
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Intersect1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<Mx> time(ray.time()[k]);
+ const Vec3vf<Mx> v0 = madd(time,Vec3vf<Mx>(tri.dv0),Vec3vf<Mx>(tri.v0));
+ const Vec3vf<Mx> v1 = madd(time,Vec3vf<Mx>(tri.dv1),Vec3vf<Mx>(tri.v1));
+ const Vec3vf<Mx> v2 = madd(time,Vec3vf<Mx>(tri.dv2),Vec3vf<Mx>(tri.v2));
+ return pre.intersect(ray,k,v0,v1,v2,UVIdentity<Mx>(),Occluded1KEpilogM<M,Mx,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/hash.h b/thirdparty/embree-aarch64/kernels/hash.h
new file mode 100644
index 0000000000..4abbe203d6
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/hash.h
@@ -0,0 +1,5 @@
+
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_HASH "6ef362f99af80c9dfe8dd2bfc582d9067897edc6"
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/bezier_curve.h b/thirdparty/embree-aarch64/kernels/subdiv/bezier_curve.h
new file mode 100644
index 0000000000..c0e78820f8
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/bezier_curve.h
@@ -0,0 +1,669 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/scene_curves.h"
+
+namespace embree
+{
+ class BezierBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = t0 * t0 * t0;
+ const T B1 = 3.0f * t1 * (t0 * t0);
+ const T B2 = 3.0f * (t1 * t1) * t0;
+ const T B3 = t1 * t1 * t1;
+ return Vec4<T>(B0,B1,B2,B3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = -(t0*t0);
+ const T B1 = madd(-2.0f,t0*t1,t0*t0);
+ const T B2 = msub(+2.0f,t0*t1,t1*t1);
+ const T B3 = +(t1*t1);
+ return T(3.0f)*Vec4<T>(B0,B1,B2,B3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = t0;
+ const T B1 = madd(-2.0f,t0,t1);
+ const T B2 = madd(-2.0f,t1,t0);
+ const T B3 = t1;
+ return T(6.0f)*Vec4<T>(B0,B1,B2,B3);
+ }
+ };
+
+ struct PrecomputedBezierBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedBezierBasis() {}
+ PrecomputedBezierBasis(int shift);
+
+ /* basis for bezier evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bezier derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedBezierBasis bezier_basis0;
+ extern PrecomputedBezierBasis bezier_basis1;
+
+
+ template<typename V>
+ struct LinearBezierCurve
+ {
+ V v0,v1;
+
+ __forceinline LinearBezierCurve () {}
+
+ __forceinline LinearBezierCurve (const LinearBezierCurve& other)
+ : v0(other.v0), v1(other.v1) {}
+
+ __forceinline LinearBezierCurve& operator= (const LinearBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; return *this;
+ }
+
+ __forceinline LinearBezierCurve (const V& v0, const V& v1)
+ : v0(v0), v1(v1) {}
+
+ __forceinline V begin() const { return v0; }
+ __forceinline V end () const { return v1; }
+
+ bool hasRoot() const;
+
+ friend embree_ostream operator<<(embree_ostream cout, const LinearBezierCurve& a) {
+ return cout << "LinearBezierCurve (" << a.v0 << ", " << a.v1 << ")";
+ }
+ };
+
+ template<> __forceinline bool LinearBezierCurve<Interval1f>::hasRoot() const {
+ return numRoots(v0,v1);
+ }
+
+ template<typename V>
+ struct QuadraticBezierCurve
+ {
+ V v0,v1,v2;
+
+ __forceinline QuadraticBezierCurve () {}
+
+ __forceinline QuadraticBezierCurve (const QuadraticBezierCurve& other)
+ : v0(other.v0), v1(other.v1), v2(other.v2) {}
+
+ __forceinline QuadraticBezierCurve& operator= (const QuadraticBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; v2 = other.v2; return *this;
+ }
+
+ __forceinline QuadraticBezierCurve (const V& v0, const V& v1, const V& v2)
+ : v0(v0), v1(v1), v2(v2) {}
+
+ __forceinline V begin() const { return v0; }
+ __forceinline V end () const { return v2; }
+
+ __forceinline V interval() const {
+ return merge(v0,v1,v2);
+ }
+
+ __forceinline BBox<V> bounds() const {
+ return merge(BBox<V>(v0),BBox<V>(v1),BBox<V>(v2));
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const QuadraticBezierCurve& a) {
+ return cout << "QuadraticBezierCurve ( (" << a.u.lower << ", " << a.u.upper << "), " << a.v0 << ", " << a.v1 << ", " << a.v2 << ")";
+ }
+ };
+
+
+ typedef QuadraticBezierCurve<float> QuadraticBezierCurve1f;
+ typedef QuadraticBezierCurve<Vec2fa> QuadraticBezierCurve2fa;
+ typedef QuadraticBezierCurve<Vec3fa> QuadraticBezierCurve3fa;
+
+ template<typename Vertex>
+ struct CubicBezierCurve
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline CubicBezierCurve() {}
+
+ template<typename T1>
+ __forceinline CubicBezierCurve (const CubicBezierCurve<T1>& other)
+ : v0(other.v0), v1(other.v1), v2(other.v2), v3(other.v3) {}
+
+ __forceinline CubicBezierCurve& operator= (const CubicBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; v2 = other.v2; v3 = other.v3; return *this;
+ }
+
+ __forceinline CubicBezierCurve(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return v0;
+ }
+
+ __forceinline Vertex end() const {
+ return v3;
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline Vertex begin_direction() const {
+ return v1-v0;
+ }
+
+ __forceinline Vertex end_direction() const {
+ return v3-v2;
+ }
+
+ __forceinline CubicBezierCurve<float> xfm(const Vertex& dx) const {
+ return CubicBezierCurve<float>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx));
+ }
+
+ __forceinline CubicBezierCurve<vfloatx> vxfm(const Vertex& dx) const {
+ return CubicBezierCurve<vfloatx>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx));
+ }
+
+ __forceinline CubicBezierCurve<float> xfm(const Vertex& dx, const Vertex& p) const {
+ return CubicBezierCurve<float>(dot(v0-p,dx),dot(v1-p,dx),dot(v2-p,dx),dot(v3-p,dx));
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space) const
+ {
+ const Vec3fa q0 = xfmVector(space,v0);
+ const Vec3fa q1 = xfmVector(space,v1);
+ const Vec3fa q2 = xfmVector(space,v2);
+ const Vec3fa q3 = xfmVector(space,v3);
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3fa q0 = xfmVector(space,v0-p);
+ const Vec3fa q1 = xfmVector(space,v1-p);
+ const Vec3fa q2 = xfmVector(space,v2-p);
+ const Vec3fa q3 = xfmVector(space,v3-p);
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,(Vec3fa)v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,(Vec3fa)v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,(Vec3fa)v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,(Vec3fa)v3-p), v3.w);
+ return CubicBezierCurve<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const
+ {
+ const Vec3fa q0 = xfmVector(space,s*(v0-p));
+ const Vec3fa q1 = xfmVector(space,s*(v1-p));
+ const Vec3fa q2 = xfmVector(space,s*(v2-p));
+ const Vec3fa q3 = xfmVector(space,s*(v3-p));
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline int maxRoots() const;
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend CubicBezierCurve operator +( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a.v0+b.v0,a.v1+b.v1,a.v2+b.v2,a.v3+b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve operator -( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a.v0-b.v0,a.v1-b.v1,a.v2-b.v2,a.v3-b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve operator -( const CubicBezierCurve& a, const Vertex& b ) {
+ return CubicBezierCurve(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline friend CubicBezierCurve operator *( const Vertex& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a*b.v0,a*b.v1,a*b.v2,a*b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve cmadd( const Vertex& a, const CubicBezierCurve& b, const CubicBezierCurve& c) {
+ return CubicBezierCurve(madd(a,b.v0,c.v0),madd(a,b.v1,c.v1),madd(a,b.v2,c.v2),madd(a,b.v3,c.v3));
+ }
+
+ __forceinline friend CubicBezierCurve clerp ( const CubicBezierCurve& a, const CubicBezierCurve& b, const Vertex& t ) {
+ return cmadd((Vertex(1.0f)-t),a,t*b);
+ }
+
+ __forceinline friend CubicBezierCurve merge ( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(merge(a.v0,b.v0),merge(a.v1,b.v1),merge(a.v2,b.v2),merge(a.v3,b.v3));
+ }
+
+ __forceinline void split(CubicBezierCurve& left, CubicBezierCurve& right, const float t = 0.5f) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ new (&left ) CubicBezierCurve(p00,p10,p20,p30);
+ new (&right) CubicBezierCurve(p30,p21,p12,p03);
+ }
+
+ __forceinline CubicBezierCurve<Vec2vfx> split() const
+ {
+ const float u0 = 0.0f, u1 = 1.0f;
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1)));
+ Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale);
+ const Vec2vfx P3 = shift_right_1(P0);
+ const Vec2vfx dP3du = shift_right_1(dP0du);
+ const Vec2vfx P1 = P0 + dP0du;
+ const Vec2vfx P2 = P3 - dP3du;
+ return CubicBezierCurve<Vec2vfx>(P0,P1,P2,P3);
+ }
+
+ __forceinline CubicBezierCurve<Vec2vfx> split(const BBox1f& u) const
+ {
+ const float u0 = u.lower, u1 = u.upper;
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1)));
+ Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale);
+ const Vec2vfx P3 = shift_right_1(P0);
+ const Vec2vfx dP3du = shift_right_1(dP0du);
+ const Vec2vfx P1 = P0 + dP0du;
+ const Vec2vfx P2 = P3 - dP3du;
+ return CubicBezierCurve<Vec2vfx>(P0,P1,P2,P3);
+ }
+
+ __forceinline void eval(float t, Vertex& p, Vertex& dp) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = Vertex(3.0f)*(p21-p20);
+ }
+
+#if 0
+ __forceinline Vertex eval(float t) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ return p30;
+ }
+#else
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+#endif
+
+ __forceinline Vertex eval_dt(float t) const
+ {
+ const Vertex p00 = v1-v0;
+ const Vertex p01 = v2-v1;
+ const Vertex p02 = v3-v2;
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ return Vertex(3.0f)*p20;
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void evalN(const vfloatx& t, Vec2vfx& p, Vec2vfx& dp) const
+ {
+ const Vec2vfx p00 = v0;
+ const Vec2vfx p01 = v1;
+ const Vec2vfx p02 = v2;
+ const Vec2vfx p03 = v3;
+
+ const Vec2vfx p10 = lerp(p00,p01,t);
+ const Vec2vfx p11 = lerp(p01,p02,t);
+ const Vec2vfx p12 = lerp(p02,p03,t);
+
+ const Vec2vfx p20 = lerp(p10,p11,t);
+ const Vec2vfx p21 = lerp(p11,p12,t);
+
+ const Vec2vfx p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = vfloatx(3.0f)*(p21-p20);
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+ p = p30;
+ dp = 3.0f*(p21-p20);
+ ddp = eval_dudu(t);
+ }
+
+ __forceinline CubicBezierCurve clip(const Interval1f& u1) const
+ {
+ Vertex f0,df0; eval(u1.lower,f0,df0);
+ Vertex f1,df1; eval(u1.upper,f1,df1);
+ float s = u1.upper-u1.lower;
+ return CubicBezierCurve(f0,f0+s*(1.0f/3.0f)*df0,f1-s*(1.0f/3.0f)*df1,f1);
+ }
+
+ __forceinline QuadraticBezierCurve<Vertex> derivative() const
+ {
+ const Vertex q0 = 3.0f*(v1-v0);
+ const Vertex q1 = 3.0f*(v2-v1);
+ const Vertex q2 = 3.0f*(v3-v2);
+ return QuadraticBezierCurve<Vertex>(q0,q1,q2);
+ }
+
+ __forceinline BBox<Vertex> derivative_bounds(const Interval1f& u1) const
+ {
+ Vertex f0,df0; eval(u1.lower,f0,df0);
+ Vertex f3,df3; eval(u1.upper,f3,df3);
+ const float s = u1.upper-u1.lower;
+ const Vertex f1 = f0+s*(1.0f/3.0f)*df0;
+ const Vertex f2 = f3-s*(1.0f/3.0f)*df3;
+ const Vertex q0 = s*df0;
+ const Vertex q1 = 3.0f*(f2-f1);
+ const Vertex q2 = s*df3;
+ return merge(BBox<Vertex>(q0),BBox<Vertex>(q1),BBox<Vertex>(q2));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ const Vec4vf<M> p00 = v0;
+ const Vec4vf<M> p01 = v1;
+ const Vec4vf<M> p02 = v2;
+ const Vec4vf<M> p03 = v3;
+
+ const Vec4vf<M> p10 = lerp(p00,p01,t);
+ const Vec4vf<M> p11 = lerp(p01,p02,t);
+ const Vec4vf<M> p12 = lerp(p02,p03,t);
+ const Vec4vf<M> p20 = lerp(p10,p11,t);
+ const Vec4vf<M> p21 = lerp(p11,p12,t);
+ const Vec4vf<M> p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = vfloat<M>(3.0f)*(p21-p20);
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis0.c0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis0.c1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis0.c2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis0.c3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis1.c0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis1.c1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis1.c2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis1.c3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis0.d0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis0.d1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis0.d2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis0.d3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis1.d0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis1.d1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis1.d2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis1.d3[size][ofs]) * Vec(v3))));
+ }
+
+ /* calculates bounds of bezier curve geometry */
+ __forceinline BBox3fa accurateBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec3vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec3vfx p = eval0<VSIZEX,Vec3vf<VSIZEX>>(i,N);
+ const Vec3vfx dp = derivative0<VSIZEX,Vec3vf<VSIZEX>>(i,N);
+ const Vec3vfx pm = p-Vec3vfx(scale)*select(vi!=vintx(0),dp,Vec3vfx(zero));
+ const Vec3vfx pp = p+Vec3vfx(scale)*select(vi!=vintx(N),dp,Vec3vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ return BBox3fa(lower,upper);
+ }
+
+ /* calculates bounds of bezier curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ return enlarge(BBox3fa(min(lower,v3),max(upper,v3)),max(upper_r,Vec3fa(abs(v3.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(min(lower,v3),max(upper,v3)),max(upper_r,Vec3fa(abs(v3.w))));
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const CubicBezierCurve& curve) {
+ return cout << "CubicBezierCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+#if defined(__AVX__)
+ template<>
+ __forceinline CubicBezierCurve<vfloat4> CubicBezierCurve<vfloat4>::clip(const Interval1f& u1) const
+ {
+ const vfloat8 p00 = vfloat8(v0);
+ const vfloat8 p01 = vfloat8(v1);
+ const vfloat8 p02 = vfloat8(v2);
+ const vfloat8 p03 = vfloat8(v3);
+
+ const vfloat8 t(vfloat4(u1.lower),vfloat4(u1.upper));
+ const vfloat8 p10 = lerp(p00,p01,t);
+ const vfloat8 p11 = lerp(p01,p02,t);
+ const vfloat8 p12 = lerp(p02,p03,t);
+ const vfloat8 p20 = lerp(p10,p11,t);
+ const vfloat8 p21 = lerp(p11,p12,t);
+ const vfloat8 p30 = lerp(p20,p21,t);
+
+ const vfloat8 f01 = p30;
+ const vfloat8 df01 = vfloat8(3.0f)*(p21-p20);
+
+ const vfloat4 f0 = extract4<0>(f01), f1 = extract4<1>(f01);
+ const vfloat4 df0 = extract4<0>(df01), df1 = extract4<1>(df01);
+ const float s = u1.upper-u1.lower;
+ return CubicBezierCurve(f0,f0+s*(1.0f/3.0f)*df0,f1-s*(1.0f/3.0f)*df1,f1);
+ }
+#endif
+
+ template<typename Vertex> using BezierCurveT = CubicBezierCurve<Vertex>;
+
+ typedef CubicBezierCurve<float> CubicBezierCurve1f;
+ typedef CubicBezierCurve<Vec2fa> CubicBezierCurve2fa;
+ typedef CubicBezierCurve<Vec3fa> CubicBezierCurve3fa;
+ typedef CubicBezierCurve<Vec3fa> BezierCurve3fa;
+
+ template<> __forceinline int CubicBezierCurve<float>::maxRoots() const
+ {
+ float eps = 1E-4f;
+ bool neg0 = v0 <= 0.0f; bool zero0 = fabs(v0) < eps;
+ bool neg1 = v1 <= 0.0f; bool zero1 = fabs(v1) < eps;
+ bool neg2 = v2 <= 0.0f; bool zero2 = fabs(v2) < eps;
+ bool neg3 = v3 <= 0.0f; bool zero3 = fabs(v3) < eps;
+ return (neg0 != neg1 || zero0) + (neg1 != neg2 || zero1) + (neg2 != neg3 || zero2 || zero3);
+ }
+
+ template<> __forceinline int CubicBezierCurve<Interval1f>::maxRoots() const {
+ return numRoots(v0,v1) + numRoots(v1,v2) + numRoots(v2,v3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CubicBezierCurve<Vec3ff>& curve)
+ {
+ return CubicBezierCurve<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/bezier_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/bezier_patch.h
new file mode 100644
index 0000000000..d87ed41ccb
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/bezier_patch.h
@@ -0,0 +1,372 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<class T, class S>
+ static __forceinline T deCasteljau(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3)
+ {
+ const T v0_1 = lerp(v0,v1,uu);
+ const T v1_1 = lerp(v1,v2,uu);
+ const T v2_1 = lerp(v2,v3,uu);
+ const T v0_2 = lerp(v0_1,v1_1,uu);
+ const T v1_2 = lerp(v1_1,v2_1,uu);
+ const T v0_3 = lerp(v0_2,v1_2,uu);
+ return v0_3;
+ }
+
+ template<class T, class S>
+ static __forceinline T deCasteljau_tangent(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3)
+ {
+ const T v0_1 = lerp(v0,v1,uu);
+ const T v1_1 = lerp(v1,v2,uu);
+ const T v2_1 = lerp(v2,v3,uu);
+ const T v0_2 = lerp(v0_1,v1_1,uu);
+ const T v1_2 = lerp(v1_1,v2_1,uu);
+ return S(3.0f)*(v1_2-v0_2);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeInnerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 36.0f * (16.0f * v[y][x] + 4.0f * (v[y-1][x] + v[y+1][x] + v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y+1][x+1] + v[y-1][x+1] + v[y+1][x-1]));
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeTopEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y-1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y-1][x+1]));
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeBottomEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y+1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + v[y+1][x-1] + v[y+1][x+1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeLeftEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x-1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x-1] + v[y+1][x-1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeRightEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x+1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x+1] + v[y+1][x+1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeCornerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x, const ssize_t delta_y, const ssize_t delta_x)
+ {
+ return 1.0f / 9.0f * (4.0f * v[y][x] + 2.0f * (v[y+delta_y][x] + v[y][x+delta_x]) + v[y+delta_y][x+delta_x]);
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ class __aligned(64) BezierPatchT
+ {
+ public:
+ Vertex matrix[4][4];
+
+ public:
+
+ __forceinline BezierPatchT() {}
+
+ __forceinline BezierPatchT (const HalfEdge* edge, const char* vertices, size_t stride);
+
+ __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch);
+
+ __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3);
+
+ __forceinline BezierPatchT(const BSplinePatchT<Vertex,Vertex_t>& source)
+ {
+ /* compute inner bezier control points */
+ matrix[0][0] = computeInnerBezierControlPoint(source.v,1,1);
+ matrix[0][3] = computeInnerBezierControlPoint(source.v,1,2);
+ matrix[3][3] = computeInnerBezierControlPoint(source.v,2,2);
+ matrix[3][0] = computeInnerBezierControlPoint(source.v,2,1);
+
+ /* compute top edge control points */
+ matrix[0][1] = computeRightEdgeBezierControlPoint(source.v,1,1);
+ matrix[0][2] = computeLeftEdgeBezierControlPoint(source.v,1,2);
+
+ /* compute buttom edge control points */
+ matrix[3][1] = computeRightEdgeBezierControlPoint(source.v,2,1);
+ matrix[3][2] = computeLeftEdgeBezierControlPoint(source.v,2,2);
+
+ /* compute left edge control points */
+ matrix[1][0] = computeBottomEdgeBezierControlPoint(source.v,1,1);
+ matrix[2][0] = computeTopEdgeBezierControlPoint(source.v,2,1);
+
+ /* compute right edge control points */
+ matrix[1][3] = computeBottomEdgeBezierControlPoint(source.v,1,2);
+ matrix[2][3] = computeTopEdgeBezierControlPoint(source.v,2,2);
+
+ /* compute corner control points */
+ matrix[1][1] = computeCornerBezierControlPoint(source.v,1,1, 1, 1);
+ matrix[1][2] = computeCornerBezierControlPoint(source.v,1,2, 1,-1);
+ matrix[2][2] = computeCornerBezierControlPoint(source.v,2,2,-1,-1);
+ matrix[2][1] = computeCornerBezierControlPoint(source.v,2,1,-1, 1);
+ }
+
+ static __forceinline Vertex_t bilinear(const Vec4f Bu, const Vertex matrix[4][4], const Vec4f Bv)
+ {
+ const Vertex_t M0 = madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3])));
+ const Vertex_t M1 = madd(Bu.x,matrix[1][0],madd(Bu.y,matrix[1][1],madd(Bu.z,matrix[1][2],Bu.w * matrix[1][3])));
+ const Vertex_t M2 = madd(Bu.x,matrix[2][0],madd(Bu.y,matrix[2][1],madd(Bu.z,matrix[2][2],Bu.w * matrix[2][3])));
+ const Vertex_t M3 = madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3])));
+ return madd(Bv.x,M0,madd(Bv.y,M1,madd(Bv.z,M2,Bv.w*M3)));
+ }
+
+ static __forceinline Vertex_t eval(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_du(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::derivative(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dudu(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative2(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dvdv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::derivative2(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dudv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative(uu);
+ const Vec4f Bv = BezierBasis::derivative(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t normal(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vertex_t dPdu = eval_du(matrix,uu,vv);
+ const Vertex_t dPdv = eval_dv(matrix,uu,vv);
+ return cross(dPdu,dPdv);
+ }
+
+ __forceinline Vertex_t normal(const float uu, const float vv)
+ {
+ const Vertex_t dPdu = eval_du(matrix,uu,vv);
+ const Vertex_t dPdv = eval_dv(matrix,uu,vv);
+ return cross(dPdu,dPdv);
+ }
+
+ __forceinline Vertex_t eval(const float uu, const float vv) const {
+ return eval(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_du(const float uu, const float vv) const {
+ return eval_du(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dv(const float uu, const float vv) const {
+ return eval_dv(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dudu(const float uu, const float vv) const {
+ return eval_dudu(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dvdv(const float uu, const float vv) const {
+ return eval_dvdv(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dudv(const float uu, const float vv) const {
+ return eval_dudv(matrix,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v, Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv, const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n) const
+ {
+ const vfloat curve0_x = v_n[0] * vfloat(matrix[0][0][i]) + v_n[1] * vfloat(matrix[1][0][i]) + v_n[2] * vfloat(matrix[2][0][i]) + v_n[3] * vfloat(matrix[3][0][i]);
+ const vfloat curve1_x = v_n[0] * vfloat(matrix[0][1][i]) + v_n[1] * vfloat(matrix[1][1][i]) + v_n[2] * vfloat(matrix[2][1][i]) + v_n[3] * vfloat(matrix[3][1][i]);
+ const vfloat curve2_x = v_n[0] * vfloat(matrix[0][2][i]) + v_n[1] * vfloat(matrix[1][2][i]) + v_n[2] * vfloat(matrix[2][2][i]) + v_n[3] * vfloat(matrix[3][2][i]);
+ const vfloat curve3_x = v_n[0] * vfloat(matrix[0][3][i]) + v_n[1] * vfloat(matrix[1][3][i]) + v_n[2] * vfloat(matrix[2][3][i]) + v_n[3] * vfloat(matrix[3][3][i]);
+ return u_n[0] * curve0_x + u_n[1] * curve1_x + u_n[2] * curve2_x + u_n[3] * curve3_x;
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv,u_n,v_n));
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdu+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdv+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudu+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdvdv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ }
+ }
+
+ template<typename T>
+ static __forceinline Vec3<T> eval(const Vertex matrix[4][4], const T& uu, const T& vv)
+ {
+ const T one_minus_uu = 1.0f - uu;
+ const T one_minus_vv = 1.0f - vv;
+
+ const T B0_u = one_minus_uu * one_minus_uu * one_minus_uu;
+ const T B0_v = one_minus_vv * one_minus_vv * one_minus_vv;
+ const T B1_u = 3.0f * (one_minus_uu * uu * one_minus_uu);
+ const T B1_v = 3.0f * (one_minus_vv * vv * one_minus_vv);
+ const T B2_u = 3.0f * (uu * one_minus_uu * uu);
+ const T B2_v = 3.0f * (vv * one_minus_vv * vv);
+ const T B3_u = uu * uu * uu;
+ const T B3_v = vv * vv * vv;
+
+ const T x =
+ madd(B0_v,madd(B0_u,matrix[0][0].x,madd(B1_u,matrix[0][1].x,madd(B2_u,matrix[0][2].x,B3_u*matrix[0][3].x))),
+ madd(B1_v,madd(B0_u,matrix[1][0].x,madd(B1_u,matrix[1][1].x,madd(B2_u,matrix[1][2].x,B3_u*matrix[1][3].x))),
+ madd(B2_v,madd(B0_u,matrix[2][0].x,madd(B1_u,matrix[2][1].x,madd(B2_u,matrix[2][2].x,B3_u*matrix[2][3].x))),
+ B3_v*madd(B0_u,matrix[3][0].x,madd(B1_u,matrix[3][1].x,madd(B2_u,matrix[3][2].x,B3_u*matrix[3][3].x))))));
+
+ const T y =
+ madd(B0_v,madd(B0_u,matrix[0][0].y,madd(B1_u,matrix[0][1].y,madd(B2_u,matrix[0][2].y,B3_u*matrix[0][3].y))),
+ madd(B1_v,madd(B0_u,matrix[1][0].y,madd(B1_u,matrix[1][1].y,madd(B2_u,matrix[1][2].y,B3_u*matrix[1][3].y))),
+ madd(B2_v,madd(B0_u,matrix[2][0].y,madd(B1_u,matrix[2][1].y,madd(B2_u,matrix[2][2].y,B3_u*matrix[2][3].y))),
+ B3_v*madd(B0_u,matrix[3][0].y,madd(B1_u,matrix[3][1].y,madd(B2_u,matrix[3][2].y,B3_u*matrix[3][3].y))))));
+
+ const T z =
+ madd(B0_v,madd(B0_u,matrix[0][0].z,madd(B1_u,matrix[0][1].z,madd(B2_u,matrix[0][2].z,B3_u*matrix[0][3].z))),
+ madd(B1_v,madd(B0_u,matrix[1][0].z,madd(B1_u,matrix[1][1].z,madd(B2_u,matrix[1][2].z,B3_u*matrix[1][3].z))),
+ madd(B2_v,madd(B0_u,matrix[2][0].z,madd(B1_u,matrix[2][1].z,madd(B2_u,matrix[2][2].z,B3_u*matrix[2][3].z))),
+ B3_v*madd(B0_u,matrix[3][0].z,madd(B1_u,matrix[3][1].z,madd(B2_u,matrix[3][2].z,B3_u*matrix[3][3].z))))));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const {
+ return eval(matrix,uu,vv);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> normal(const Vertex matrix[4][4], const T& uu, const T& vv)
+ {
+
+ const Vec3<T> matrix_00 = Vec3<T>(matrix[0][0].x,matrix[0][0].y,matrix[0][0].z);
+ const Vec3<T> matrix_01 = Vec3<T>(matrix[0][1].x,matrix[0][1].y,matrix[0][1].z);
+ const Vec3<T> matrix_02 = Vec3<T>(matrix[0][2].x,matrix[0][2].y,matrix[0][2].z);
+ const Vec3<T> matrix_03 = Vec3<T>(matrix[0][3].x,matrix[0][3].y,matrix[0][3].z);
+
+ const Vec3<T> matrix_10 = Vec3<T>(matrix[1][0].x,matrix[1][0].y,matrix[1][0].z);
+ const Vec3<T> matrix_11 = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> matrix_12 = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> matrix_13 = Vec3<T>(matrix[1][3].x,matrix[1][3].y,matrix[1][3].z);
+
+ const Vec3<T> matrix_20 = Vec3<T>(matrix[2][0].x,matrix[2][0].y,matrix[2][0].z);
+ const Vec3<T> matrix_21 = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+ const Vec3<T> matrix_22 = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> matrix_23 = Vec3<T>(matrix[2][3].x,matrix[2][3].y,matrix[2][3].z);
+
+ const Vec3<T> matrix_30 = Vec3<T>(matrix[3][0].x,matrix[3][0].y,matrix[3][0].z);
+ const Vec3<T> matrix_31 = Vec3<T>(matrix[3][1].x,matrix[3][1].y,matrix[3][1].z);
+ const Vec3<T> matrix_32 = Vec3<T>(matrix[3][2].x,matrix[3][2].y,matrix[3][2].z);
+ const Vec3<T> matrix_33 = Vec3<T>(matrix[3][3].x,matrix[3][3].y,matrix[3][3].z);
+
+ /* tangentU */
+ const Vec3<T> col0 = deCasteljau(vv, matrix_00, matrix_10, matrix_20, matrix_30);
+ const Vec3<T> col1 = deCasteljau(vv, matrix_01, matrix_11, matrix_21, matrix_31);
+ const Vec3<T> col2 = deCasteljau(vv, matrix_02, matrix_12, matrix_22, matrix_32);
+ const Vec3<T> col3 = deCasteljau(vv, matrix_03, matrix_13, matrix_23, matrix_33);
+
+ const Vec3<T> tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vec3<T> row0 = deCasteljau(uu, matrix_00, matrix_01, matrix_02, matrix_03);
+ const Vec3<T> row1 = deCasteljau(uu, matrix_10, matrix_11, matrix_12, matrix_13);
+ const Vec3<T> row2 = deCasteljau(uu, matrix_20, matrix_21, matrix_22, matrix_23);
+ const Vec3<T> row3 = deCasteljau(uu, matrix_30, matrix_31, matrix_32, matrix_33);
+
+ const Vec3<T> tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vec3<T> n = cross(tangentU,tangentV);
+ return n;
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {
+ return normal(matrix,uu,vv);
+ }
+ };
+
+ typedef BezierPatchT<Vec3fa,Vec3fa_t> BezierPatch3fa;
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/bilinear_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/bilinear_patch.h
new file mode 100644
index 0000000000..35748754bd
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/bilinear_patch.h
@@ -0,0 +1,191 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) BilinearPatchT
+ {
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ public:
+ Vertex v[4];
+
+ public:
+
+ __forceinline BilinearPatchT () {}
+
+ __forceinline BilinearPatchT (const HalfEdge* edge, const BufferView<Vertex>& vertices) {
+ init(edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline BilinearPatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(edge,vertices,stride);
+ }
+
+ __forceinline void init (const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ v[0] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[1] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[2] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[3] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ }
+
+ __forceinline BilinearPatchT (const CatmullClarkPatch& patch)
+ {
+ v[0] = patch.ring[0].getLimitVertex();
+ v[1] = patch.ring[1].getLimitVertex();
+ v[2] = patch.ring[2].getLimitVertex();
+ v[3] = patch.ring[3].getLimitVertex();
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+
+ BBox<Vertex> bounds (v[0]);
+ bounds.extend(v[1]);
+ bounds.extend(v[2]);
+ bounds.extend(v[3]);
+ return bounds;
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const {
+ return lerp(lerp(v[0],v[1],uu),lerp(v[3],v[2],uu),vv);
+ }
+
+ __forceinline Vertex eval_du(const float uu, const float vv) const {
+ return lerp(v[1]-v[0],v[2]-v[3],vv);
+ }
+
+ __forceinline Vertex eval_dv(const float uu, const float vv) const {
+ return lerp(v[3]-v[0],v[2]-v[1],uu);
+ }
+
+ __forceinline Vertex eval_dudu(const float uu, const float vv) const {
+ return Vertex(zero);
+ }
+
+ __forceinline Vertex eval_dvdv(const float uu, const float vv) const {
+ return Vertex(zero);
+ }
+
+ __forceinline Vertex eval_dudv(const float uu, const float vv) const {
+ return (v[2]-v[3]) - (v[1]-v[0]);
+ }
+
+ __forceinline Vertex normal(const float uu, const float vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(lerp(v[0].x,v[1].x,uu),lerp(v[3].x,v[2].x,uu),vv);
+ const vfloat y = lerp(lerp(v[0].y,v[1].y,uu),lerp(v[3].y,v[2].y,uu),vv);
+ const vfloat z = lerp(lerp(v[0].z,v[1].z,uu),lerp(v[3].z,v[2].z,uu),vv);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval_du(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(v[1].x-v[0].x,v[2].x-v[3].x,vv);
+ const vfloat y = lerp(v[1].y-v[0].y,v[2].y-v[3].y,vv);
+ const vfloat z = lerp(v[1].z-v[0].z,v[2].z-v[3].z,vv);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval_dv(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(v[3].x-v[0].x,v[2].x-v[1].x,uu);
+ const vfloat y = lerp(v[3].y-v[0].y,v[2].y-v[1].y,uu);
+ const vfloat z = lerp(v[3].z-v[0].z,v[2].z-v[1].z,uu);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(lerp(v[0][i],v[1][i],uu),lerp(v[3][i],v[2][i],uu),vv);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_du(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(v[1][i]-v[0][i],v[2][i]-v[3][i],vv);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(v[3][i]-v[0][i],v[2][i]-v[1][i],uu);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dudu(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return vfloat(zero);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dvdv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return vfloat(zero);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dudv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return (v[2][i]-v[3][i]) - (v[1][i]-v[0][i]);
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv));
+ }
+ if (dPdu) {
+ for (size_t i=0; i<N; i++) {
+ assert(dPdu); vfloat::store(valid,dPdu+i*dstride,eval_du(i,uu,vv)*dscale);
+ assert(dPdv); vfloat::store(valid,dPdv+i*dstride,eval_dv(i,uu,vv)*dscale);
+ }
+ }
+ if (ddPdudu) {
+ for (size_t i=0; i<N; i++) {
+ assert(ddPdudu); vfloat::store(valid,ddPdudu+i*dstride,eval_dudu(i,uu,vv)*sqr(dscale));
+ assert(ddPdvdv); vfloat::store(valid,ddPdvdv+i*dstride,eval_dvdv(i,uu,vv)*sqr(dscale));
+ assert(ddPdudv); vfloat::store(valid,ddPdudv+i*dstride,eval_dudv(i,uu,vv)*sqr(dscale));
+ }
+ }
+ }
+ };
+
+ typedef BilinearPatchT<Vec3fa,Vec3fa_t> BilinearPatch3fa;
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/bspline_curve.h b/thirdparty/embree-aarch64/kernels/subdiv/bspline_curve.h
new file mode 100644
index 0000000000..a325667328
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/bspline_curve.h
@@ -0,0 +1,319 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ class BSplineBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t = u;
+ const T s = T(1.0f) - u;
+ const T n0 = s*s*s;
+ const T n1 = (4.0f*(s*s*s)+(t*t*t)) + (12.0f*((s*t)*s) + 6.0f*((t*s)*t));
+ const T n2 = (4.0f*(t*t*t)+(s*s*s)) + (12.0f*((t*s)*t) + 6.0f*((s*t)*s));
+ const T n3 = t*t*t;
+ return T(1.0f/6.0f)*Vec4<T>(n0,n1,n2,n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = -s*s;
+ const T n1 = -t*t - 4.0f*(t*s);
+ const T n2 = s*s + 4.0f*(s*t);
+ const T n3 = t*t;
+ return T(0.5f)*Vec4<T>(n0,n1,n2,n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = s;
+ const T n1 = t - 2.0f*s;
+ const T n2 = s - 2.0f*t;
+ const T n3 = t;
+ return Vec4<T>(n0,n1,n2,n3);
+ }
+ };
+
+ struct PrecomputedBSplineBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedBSplineBasis() {}
+ PrecomputedBSplineBasis(int shift);
+
+ /* basis for bspline evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bspline derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedBSplineBasis bspline_basis0;
+ extern PrecomputedBSplineBasis bspline_basis1;
+
+ template<typename Vertex>
+ struct BSplineCurveT
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline BSplineCurveT() {}
+
+ __forceinline BSplineCurveT(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return madd(1.0f/6.0f,v0,madd(2.0f/3.0f,v1,1.0f/6.0f*v2));
+ }
+
+ __forceinline Vertex end() const {
+ return madd(1.0f/6.0f,v1,madd(2.0f/3.0f,v2,1.0f/6.0f*v3));
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend BSplineCurveT operator -( const BSplineCurveT& a, const Vertex& b ) {
+ return BSplineCurveT(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline BSplineCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,(Vec3fa)v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,(Vec3fa)v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,(Vec3fa)v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,(Vec3fa)v3-p), v3.w);
+ return BSplineCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ p = eval(t);
+ dp = eval_du(t);
+ ddp = eval_dudu(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ p = veval(t);
+ dp = veval_du(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis0.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis0.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis0.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis0.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis1.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis1.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis1.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis1.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis0.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis0.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis0.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis0.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis1.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis1.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis1.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis1.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ /* calculates bounds of bspline curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ const Vec3ff pe = end();
+ return enlarge(BBox3fa(min(lower,pe),max(upper,pe)),max(upper_r,Vec3fa(abs(pe.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) <= vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const BSplineCurveT& curve) {
+ return cout << "BSplineCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+ template<typename Vertex>
+ __forceinline void convert(const BezierCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve) {
+ ocurve = icurve;
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BSplineCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve) {
+ ocurve = icurve;
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BezierCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve)
+ {
+ const Vertex v0 = madd(6.0f,icurve.v0,madd(-7.0f,icurve.v1,2.0f*icurve.v2));
+ const Vertex v1 = msub(2.0f,icurve.v1,icurve.v2);
+ const Vertex v2 = msub(2.0f,icurve.v2,icurve.v1);
+ const Vertex v3 = madd(2.0f,icurve.v1,madd(-7.0f,icurve.v2,6.0f*icurve.v3));
+ ocurve = BSplineCurveT<Vertex>(v0,v1,v2,v3);
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BSplineCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve)
+ {
+ const Vertex v0 = madd(1.0f/6.0f,icurve.v0,madd(2.0f/3.0f,icurve.v1,1.0f/6.0f*icurve.v2));
+ const Vertex v1 = madd(2.0f/3.0f,icurve.v1,1.0f/3.0f*icurve.v2);
+ const Vertex v2 = madd(1.0f/3.0f,icurve.v1,2.0f/3.0f*icurve.v2);
+ const Vertex v3 = madd(1.0f/6.0f,icurve.v1,madd(2.0f/3.0f,icurve.v2,1.0f/6.0f*icurve.v3));
+ ocurve = BezierCurveT<Vertex>(v0,v1,v2,v3);
+ }
+
+ __forceinline BSplineCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const BSplineCurveT<Vec3ff>& curve)
+ {
+ return BSplineCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+
+ typedef BSplineCurveT<Vec3fa> BSplineCurve3fa;
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/bspline_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/bspline_patch.h
new file mode 100644
index 0000000000..9769bc17bd
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/bspline_patch.h
@@ -0,0 +1,449 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bspline_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) BSplinePatchT
+ {
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ public:
+
+ __forceinline BSplinePatchT () {}
+
+ __forceinline BSplinePatchT (const CatmullClarkPatch& patch) {
+ init(patch);
+ }
+
+ __forceinline BSplinePatchT(const CatmullClarkPatch& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3)
+ {
+ init(patch);
+ }
+
+ __forceinline BSplinePatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(edge,vertices,stride);
+ }
+
+ __forceinline Vertex hard_corner(const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ return 4.0f*v11 - 2.0f*(v12+v21) + v22;
+ }
+
+ __forceinline Vertex soft_convex_corner( const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ return -8.0f*v11 + 4.0f*(v12+v21) + v22;
+ }
+
+ __forceinline Vertex convex_corner(const float vertex_crease_weight,
+ const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ if (std::isinf(vertex_crease_weight)) return hard_corner(v01,v02,v10,v11,v12,v20,v21,v22);
+ else return soft_convex_corner(v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+
+ __forceinline Vertex load(const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Vertex_t::loadu(vertices+edge->getStartVertexIndex()*stride);
+ }
+
+ __forceinline void init_border(const CatmullClarkRing& edge0,
+ Vertex& v01, Vertex& v02,
+ const Vertex& v11, const Vertex& v12,
+ const Vertex& v21, const Vertex& v22)
+ {
+ if (likely(edge0.has_opposite_back(0)))
+ {
+ v01 = edge0.back(2);
+ v02 = edge0.back(1);
+ } else {
+ v01 = 2.0f*v11-v21;
+ v02 = 2.0f*v12-v22;
+ }
+ }
+
+ __forceinline void init_corner(const CatmullClarkRing& edge0,
+ Vertex& v00, const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ const bool MAYBE_UNUSED has_back1 = edge0.has_opposite_back(1);
+ const bool has_back0 = edge0.has_opposite_back(0);
+ const bool has_front1 = edge0.has_opposite_front(1);
+ const bool MAYBE_UNUSED has_front2 = edge0.has_opposite_front(2);
+
+ if (likely(has_back0)) {
+ if (likely(has_front1)) { assert(has_back1 && has_front2); v00 = edge0.back(3); }
+ else { assert(!has_back1); v00 = 2.0f*v01-v02; }
+ }
+ else {
+ if (likely(has_front1)) { assert(!has_front2); v00 = 2.0f*v10-v20; }
+ else v00 = convex_corner(edge0.vertex_crease_weight,v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+ }
+
+ void init(const CatmullClarkPatch& patch)
+ {
+ /* fill inner vertices */
+ const Vertex v11 = v[1][1] = patch.ring[0].vtx;
+ const Vertex v12 = v[1][2] = patch.ring[1].vtx;
+ const Vertex v22 = v[2][2] = patch.ring[2].vtx;
+ const Vertex v21 = v[2][1] = patch.ring[3].vtx;
+
+ /* fill border vertices */
+ init_border(patch.ring[0],v[0][1],v[0][2],v11,v12,v21,v22);
+ init_border(patch.ring[1],v[1][3],v[2][3],v12,v22,v11,v21);
+ init_border(patch.ring[2],v[3][2],v[3][1],v22,v21,v12,v11);
+ init_border(patch.ring[3],v[2][0],v[1][0],v21,v11,v22,v12);
+
+ /* fill corner vertices */
+ init_corner(patch.ring[0],v[0][0],v[0][1],v[0][2],v[1][0],v11,v12,v[2][0],v21,v22);
+ init_corner(patch.ring[1],v[0][3],v[1][3],v[2][3],v[0][2],v12,v22,v[0][1],v11,v21);
+ init_corner(patch.ring[2],v[3][3],v[3][2],v[3][1],v[2][3],v22,v21,v[1][3],v12,v11);
+ init_corner(patch.ring[3],v[3][0],v[2][0],v[1][0],v[3][1],v21,v11,v[3][2],v22,v12);
+ }
+
+ void init_border(const HalfEdge* edge0, const char* vertices, size_t stride,
+ Vertex& v01, Vertex& v02,
+ const Vertex& v11, const Vertex& v12,
+ const Vertex& v21, const Vertex& v22)
+ {
+ if (likely(edge0->hasOpposite()))
+ {
+ const HalfEdge* e = edge0->opposite()->next()->next();
+ v01 = load(e,vertices,stride);
+ v02 = load(e->next(),vertices,stride);
+ } else {
+ v01 = 2.0f*v11-v21;
+ v02 = 2.0f*v12-v22;
+ }
+ }
+
+ void init_corner(const HalfEdge* edge0, const char* vertices, size_t stride,
+ Vertex& v00, const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ const bool has_back0 = edge0->hasOpposite();
+ const bool has_front1 = edge0->prev()->hasOpposite();
+
+ if (likely(has_back0))
+ {
+ const HalfEdge* e = edge0->opposite()->next();
+ if (likely(has_front1))
+ {
+ assert(e->hasOpposite());
+ assert(edge0->prev()->opposite()->prev()->hasOpposite());
+ v00 = load(e->opposite()->prev(),vertices,stride);
+ }
+ else {
+ assert(!e->hasOpposite());
+ v00 = 2.0f*v01-v02;
+ }
+ }
+ else
+ {
+ if (likely(has_front1)) {
+ assert(!edge0->prev()->opposite()->prev()->hasOpposite());
+ v00 = 2.0f*v10-v20;
+ }
+ else {
+ assert(edge0->vertex_crease_weight == 0.0f || std::isinf(edge0->vertex_crease_weight));
+ v00 = convex_corner(edge0->vertex_crease_weight,v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+ }
+ }
+
+ void init(const HalfEdge* edge0, const char* vertices, size_t stride)
+ {
+ assert( edge0->isRegularFace() );
+
+ /* fill inner vertices */
+ const Vertex v11 = v[1][1] = load(edge0,vertices,stride); const HalfEdge* edge1 = edge0->next();
+ const Vertex v12 = v[1][2] = load(edge1,vertices,stride); const HalfEdge* edge2 = edge1->next();
+ const Vertex v22 = v[2][2] = load(edge2,vertices,stride); const HalfEdge* edge3 = edge2->next();
+ const Vertex v21 = v[2][1] = load(edge3,vertices,stride); assert(edge0 == edge3->next());
+
+ /* fill border vertices */
+ init_border(edge0,vertices,stride,v[0][1],v[0][2],v11,v12,v21,v22);
+ init_border(edge1,vertices,stride,v[1][3],v[2][3],v12,v22,v11,v21);
+ init_border(edge2,vertices,stride,v[3][2],v[3][1],v22,v21,v12,v11);
+ init_border(edge3,vertices,stride,v[2][0],v[1][0],v21,v11,v22,v12);
+
+ /* fill corner vertices */
+ init_corner(edge0,vertices,stride,v[0][0],v[0][1],v[0][2],v[1][0],v11,v12,v[2][0],v21,v22);
+ init_corner(edge1,vertices,stride,v[0][3],v[1][3],v[2][3],v[0][2],v12,v22,v[0][1],v11,v21);
+ init_corner(edge2,vertices,stride,v[3][3],v[3][2],v[3][1],v[2][3],v22,v21,v[1][3],v12,v11);
+ init_corner(edge3,vertices,stride,v[3][0],v[2][0],v[1][0],v[3][1],v21,v11,v[3][2],v22,v12);
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+ const Vertex* const cv = &v[0][0];
+ BBox<Vertex> bounds (cv[0]);
+ for (size_t i=1; i<16 ; i++)
+ bounds.extend( cv[i] );
+ return bounds;
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_du(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative2(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dvdv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative2(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dudv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex normal(const float uu, const float vv) const
+ {
+ const Vertex tu = eval_du(uu,vv);
+ const Vertex tv = eval_dv(uu,vv);
+ return cross(tu,tv);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv, const Vec4<T>& u_n, const Vec4<T>& v_n) const
+ {
+ const T curve0_x = madd(v_n[0],T(v[0][0].x),madd(v_n[1],T(v[1][0].x),madd(v_n[2],T(v[2][0].x),v_n[3] * T(v[3][0].x))));
+ const T curve1_x = madd(v_n[0],T(v[0][1].x),madd(v_n[1],T(v[1][1].x),madd(v_n[2],T(v[2][1].x),v_n[3] * T(v[3][1].x))));
+ const T curve2_x = madd(v_n[0],T(v[0][2].x),madd(v_n[1],T(v[1][2].x),madd(v_n[2],T(v[2][2].x),v_n[3] * T(v[3][2].x))));
+ const T curve3_x = madd(v_n[0],T(v[0][3].x),madd(v_n[1],T(v[1][3].x),madd(v_n[2],T(v[2][3].x),v_n[3] * T(v[3][3].x))));
+ const T x = madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+
+ const T curve0_y = madd(v_n[0],T(v[0][0].y),madd(v_n[1],T(v[1][0].y),madd(v_n[2],T(v[2][0].y),v_n[3] * T(v[3][0].y))));
+ const T curve1_y = madd(v_n[0],T(v[0][1].y),madd(v_n[1],T(v[1][1].y),madd(v_n[2],T(v[2][1].y),v_n[3] * T(v[3][1].y))));
+ const T curve2_y = madd(v_n[0],T(v[0][2].y),madd(v_n[1],T(v[1][2].y),madd(v_n[2],T(v[2][2].y),v_n[3] * T(v[3][2].y))));
+ const T curve3_y = madd(v_n[0],T(v[0][3].y),madd(v_n[1],T(v[1][3].y),madd(v_n[2],T(v[2][3].y),v_n[3] * T(v[3][3].y))));
+ const T y = madd(u_n[0],curve0_y,madd(u_n[1],curve1_y,madd(u_n[2],curve2_y,u_n[3] * curve3_y)));
+
+ const T curve0_z = madd(v_n[0],T(v[0][0].z),madd(v_n[1],T(v[1][0].z),madd(v_n[2],T(v[2][0].z),v_n[3] * T(v[3][0].z))));
+ const T curve1_z = madd(v_n[0],T(v[0][1].z),madd(v_n[1],T(v[1][1].z),madd(v_n[2],T(v[2][1].z),v_n[3] * T(v[3][1].z))));
+ const T curve2_z = madd(v_n[0],T(v[0][2].z),madd(v_n[1],T(v[1][2].z),madd(v_n[2],T(v[2][2].z),v_n[3] * T(v[3][2].z))));
+ const T curve3_z = madd(v_n[0],T(v[0][3].z),madd(v_n[1],T(v[1][3].z),madd(v_n[2],T(v[2][3].z),v_n[3] * T(v[3][3].z))));
+ const T z = madd(u_n[0],curve0_z,madd(u_n[1],curve1_z,madd(u_n[2],curve2_z,u_n[3] * curve3_z)));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_du(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dudu(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative2(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dvdv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative2(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dudv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> normal(const T& uu, const T& vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n) const
+ {
+ const vfloat curve0_x = madd(v_n[0],vfloat(v[0][0][i]),madd(v_n[1],vfloat(v[1][0][i]),madd(v_n[2],vfloat(v[2][0][i]),v_n[3] * vfloat(v[3][0][i]))));
+ const vfloat curve1_x = madd(v_n[0],vfloat(v[0][1][i]),madd(v_n[1],vfloat(v[1][1][i]),madd(v_n[2],vfloat(v[2][1][i]),v_n[3] * vfloat(v[3][1][i]))));
+ const vfloat curve2_x = madd(v_n[0],vfloat(v[0][2][i]),madd(v_n[1],vfloat(v[1][2][i]),madd(v_n[2],vfloat(v[2][2][i]),v_n[3] * vfloat(v[3][2][i]))));
+ const vfloat curve3_x = madd(v_n[0],vfloat(v[0][3][i]),madd(v_n[1],vfloat(v[1][3][i]),madd(v_n[2],vfloat(v[2][3][i]),v_n[3] * vfloat(v[3][3][i]))));
+ return madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+ }
+
+ template<typename vbool, typename vfloat>
+ void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv,u_n,v_n));
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdu+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdv+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudu+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdvdv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const BSplinePatchT& p)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ o << "[" << y << "][" << x << "] " << p.v[y][x] << embree_endl;
+ return o;
+ }
+
+ public:
+ Vertex v[4][4];
+ };
+
+ typedef BSplinePatchT<Vec3fa,Vec3fa_t> BSplinePatch3fa;
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_coefficients.h b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_coefficients.h
new file mode 100644
index 0000000000..05031cf6b9
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_coefficients.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+
+namespace embree
+{
+ static const size_t MAX_PATCH_VALENCE = 16; //!< maximum number of vertices of a patch
+ static const size_t MAX_RING_FACE_VALENCE = 64; //!< maximum number of faces per ring
+ static const size_t MAX_RING_EDGE_VALENCE = 2*64; //!< maximum number of edges per ring
+
+ class CatmullClarkPrecomputedCoefficients
+ {
+ private:
+
+ float table_cos_2PI_div_n[MAX_RING_FACE_VALENCE+1];
+
+ float* table_limittangent_a[MAX_RING_FACE_VALENCE+1];
+ float* table_limittangent_b[MAX_RING_FACE_VALENCE+1];
+ float table_limittangent_c[MAX_RING_FACE_VALENCE+1];
+
+ __forceinline float set_cos_2PI_div_n(const size_t n) {
+ if (unlikely(n == 0)) return 1.0f;
+ return cosf(2.0f*float(pi)/(float)n);
+ }
+
+ __forceinline float set_limittangent_a(const size_t i, const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ const float c0 = 1.0f/(float)n * 1.0f / sqrtf(4.0f + cosf(float(pi)/(float)n)*cosf(float(pi)/(float)n));
+ const float c1 = (1.0f/(float)n + cosf(float(pi)/(float)n) * c0);
+ return cosf(2.0f*float(pi)*(float)i/(float)n) * c1;
+ }
+
+ __forceinline float set_limittangent_b(const size_t i, const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ const float c0 = 1.0f/(float)n * 1.0f / sqrtf(4.0f + cosf(float(pi)/(float)n)*cosf(float(pi)/(float)n));
+ return cosf((2.0f*float(pi)*i+float(pi))/(float)n) * c0;
+ }
+
+ __forceinline float set_limittangent_c(const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ return 2.0f/16.0f * (5.0f + cosf(2.0f*float(pi)/(float)n) + cosf(float(pi)/(float)n) * sqrtf(18.0f+2.0f*cosf(2.0f*float(pi)/(float)n)));
+ }
+
+ public:
+
+ __forceinline float cos_2PI_div_n(const size_t n)
+ {
+ if (likely(n <= MAX_RING_FACE_VALENCE))
+ return table_cos_2PI_div_n[n];
+ else
+ return set_cos_2PI_div_n(n);
+ }
+
+ __forceinline float limittangent_a(const size_t i, const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ assert(i < n);
+ return table_limittangent_a[n][i];
+ }
+
+ __forceinline float limittangent_b(const size_t i, const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ assert(i < n);
+ return table_limittangent_b[n][i];
+ }
+
+ __forceinline float limittangent_c(const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ return table_limittangent_c[n];
+ }
+
+ static CatmullClarkPrecomputedCoefficients table;
+
+ CatmullClarkPrecomputedCoefficients();
+ ~CatmullClarkPrecomputedCoefficients();
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_patch.h
new file mode 100644
index 0000000000..ab1d63594a
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_patch.h
@@ -0,0 +1,562 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_ring.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) CatmullClarkPatchT
+ {
+ public:
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef typename CatmullClark1Ring::Type Type;
+
+ array_t<CatmullClark1RingT<Vertex,Vertex_t>,4> ring;
+
+ public:
+ __forceinline CatmullClarkPatchT () {}
+
+ __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const char* vertices, size_t stride) {
+ init(first_half_edge,vertices,stride);
+ }
+
+ __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {
+ init(first_half_edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline void init (const HalfEdge* first_half_edge, const char* vertices, size_t stride)
+ {
+ for (unsigned i=0; i<4; i++)
+ ring[i].init(first_half_edge+i,vertices,stride);
+
+ assert(verify());
+ }
+
+ __forceinline size_t bytes() const {
+ return ring[0].bytes()+ring[1].bytes()+ring[2].bytes()+ring[3].bytes();
+ }
+
+ __forceinline void serialize(void* ptr, size_t& ofs) const
+ {
+ for (size_t i=0; i<4; i++)
+ ring[i].serialize((char*)ptr,ofs);
+ }
+
+ __forceinline void deserialize(void* ptr)
+ {
+ size_t ofs = 0;
+ for (size_t i=0; i<4; i++)
+ ring[i].deserialize((char*)ptr,ofs);
+ }
+
+ __forceinline BBox3fa bounds() const
+ {
+ BBox3fa bounds (ring[0].bounds());
+ for (size_t i=1; i<4; i++)
+ bounds.extend(ring[i].bounds());
+ return bounds;
+ }
+
+ __forceinline Type type() const
+ {
+ const int ty0 = ring[0].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty1 = ring[1].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty2 = ring[2].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty3 = ring[3].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ return (Type) ((ty0 & ty1 & ty2 & ty3) ^ CatmullClark1Ring::TYPE_CREASES);
+ }
+
+ __forceinline bool isFinalResolution(float res) const {
+ return ring[0].isFinalResolution(res) && ring[1].isFinalResolution(res) && ring[2].isFinalResolution(res) && ring[3].isFinalResolution(res);
+ }
+
+ static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,
+ const CatmullClark1RingT<Vertex,Vertex_t>& p1,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest0,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest1)
+ {
+ assert(p1.face_valence > 2);
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 4;
+ dest1.edge_valence = dest0.edge_valence = 8;
+ dest1.border_index = dest0.border_index = -1;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;
+ dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];
+ dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];
+ dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 3;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,
+ const CatmullClark1RingT<Vertex,Vertex_t> &p1,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest0,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest1)
+ {
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 3;
+ dest1.edge_valence = dest0.edge_valence = 6;
+ dest0.border_index = 2;
+ dest1.border_index = 4;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 2;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_regular(const Vertex_t &center, const Vertex_t center_ring[8], const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)
+ {
+ dest.vertex_level = 0.0f;
+ dest.face_valence = 4;
+ dest.edge_valence = 8;
+ dest.border_index = -1;
+ dest.vtx = (Vertex_t)center;
+ dest.vertex_crease_weight = 0.0f;
+ for (size_t i=0; i<8; i++)
+ dest.ring[i] = (Vertex_t)center_ring[(offset+i)%8];
+ for (size_t i=0; i<4; i++)
+ dest.crease_weight[i] = 0.0f;
+
+ dest.eval_start_index = (8-offset)>>1;
+ if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;
+ assert( dest.eval_start_index < dest.face_valence );
+ dest.eval_unique_identifier = 0;
+ }
+
+ __noinline void subdivide(array_t<CatmullClarkPatchT,4>& patch) const
+ {
+ ring[0].subdivide(patch[0].ring[0]);
+ ring[1].subdivide(patch[1].ring[1]);
+ ring[2].subdivide(patch[2].ring[2]);
+ ring[3].subdivide(patch[3].ring[3]);
+
+ patch[0].ring[0].edge_level = 0.5f*ring[0].edge_level;
+ patch[0].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+ patch[0].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[0].ring[3].edge_level = 0.5f*ring[3].edge_level;
+
+ patch[1].ring[0].edge_level = 0.5f*ring[0].edge_level;
+ patch[1].ring[1].edge_level = 0.5f*ring[1].edge_level;
+ patch[1].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[1].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+
+ patch[2].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[2].ring[1].edge_level = 0.5f*ring[1].edge_level;
+ patch[2].ring[2].edge_level = 0.5f*ring[2].edge_level;
+ patch[2].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+
+ patch[3].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[3].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+ patch[3].ring[2].edge_level = 0.5f*ring[2].edge_level;
+ patch[3].ring[3].edge_level = 0.5f*ring[3].edge_level;
+
+ const bool regular0 = ring[0].has_last_face() && ring[1].face_valence > 2;
+ if (likely(regular0))
+ init_regular(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);
+ else
+ init_border(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);
+
+ const bool regular1 = ring[1].has_last_face() && ring[2].face_valence > 2;
+ if (likely(regular1))
+ init_regular(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);
+ else
+ init_border(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);
+
+ const bool regular2 = ring[2].has_last_face() && ring[3].face_valence > 2;
+ if (likely(regular2))
+ init_regular(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);
+ else
+ init_border(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);
+
+ const bool regular3 = ring[3].has_last_face() && ring[0].face_valence > 2;
+ if (likely(regular3))
+ init_regular(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);
+ else
+ init_border(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);
+
+ Vertex_t center = (ring[0].vtx + ring[1].vtx + ring[2].vtx + ring[3].vtx) * 0.25f;
+
+ Vertex_t center_ring[8];
+ center_ring[0] = (Vertex_t)patch[3].ring[3].ring[0];
+ center_ring[7] = (Vertex_t)patch[3].ring[3].vtx;
+ center_ring[6] = (Vertex_t)patch[2].ring[2].ring[0];
+ center_ring[5] = (Vertex_t)patch[2].ring[2].vtx;
+ center_ring[4] = (Vertex_t)patch[1].ring[1].ring[0];
+ center_ring[3] = (Vertex_t)patch[1].ring[1].vtx;
+ center_ring[2] = (Vertex_t)patch[0].ring[0].ring[0];
+ center_ring[1] = (Vertex_t)patch[0].ring[0].vtx;
+
+ init_regular(center,center_ring,0,patch[0].ring[2]);
+ init_regular(center,center_ring,2,patch[1].ring[3]);
+ init_regular(center,center_ring,4,patch[2].ring[0]);
+ init_regular(center,center_ring,6,patch[3].ring[1]);
+
+ assert(patch[0].verify());
+ assert(patch[1].verify());
+ assert(patch[2].verify());
+ assert(patch[3].verify());
+ }
+
+ bool verify() const {
+ return ring[0].hasValidPositions() && ring[1].hasValidPositions() && ring[2].hasValidPositions() && ring[3].hasValidPositions();
+ }
+
+ __forceinline void init( FinalQuad& quad ) const
+ {
+ quad.vtx[0] = (Vertex_t)ring[0].vtx;
+ quad.vtx[1] = (Vertex_t)ring[1].vtx;
+ quad.vtx[2] = (Vertex_t)ring[2].vtx;
+ quad.vtx[3] = (Vertex_t)ring[3].vtx;
+ };
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClarkPatchT &p)
+ {
+ o << "CatmullClarkPatch { " << embree_endl;
+ for (size_t i=0; i<4; i++)
+ o << "ring" << i << ": " << p.ring[i] << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+ };
+
+ typedef CatmullClarkPatchT<Vec3fa,Vec3fa_t> CatmullClarkPatch3fa;
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) GeneralCatmullClarkPatchT
+ {
+ public:
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ static const unsigned SIZE = MAX_PATCH_VALENCE;
+ DynamicStackArray<GeneralCatmullClark1RingT<Vertex,Vertex_t>,8,SIZE> ring;
+ unsigned N;
+
+ __forceinline GeneralCatmullClarkPatchT ()
+ : N(0) {}
+
+ GeneralCatmullClarkPatchT (const HalfEdge* h, const char* vertices, size_t stride) {
+ init(h,vertices,stride);
+ }
+
+ __forceinline GeneralCatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {
+ init(first_half_edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline void init (const HalfEdge* h, const char* vertices, size_t stride)
+ {
+ unsigned int i = 0;
+ const HalfEdge* edge = h;
+ do {
+ ring[i].init(edge,vertices,stride);
+ edge = edge->next();
+ i++;
+ } while ((edge != h) && (i < SIZE));
+ N = i;
+ }
+
+ __forceinline unsigned size() const {
+ return N;
+ }
+
+ __forceinline bool isQuadPatch() const {
+ return (N == 4) && ring[0].only_quads && ring[1].only_quads && ring[2].only_quads && ring[3].only_quads;
+ }
+
+ static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,
+ const CatmullClark1RingT<Vertex,Vertex_t>& p1,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest0,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest1)
+ {
+ assert(p1.face_valence > 2);
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 4;
+ dest1.edge_valence = dest0.edge_valence = 8;
+ dest1.border_index = dest0.border_index = -1;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;
+ dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];
+ dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];
+ dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 3;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+
+ static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,
+ const CatmullClark1RingT<Vertex,Vertex_t> &p1,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest0,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest1)
+ {
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 3;
+ dest1.edge_valence = dest0.edge_valence = 6;
+ dest0.border_index = 2;
+ dest1.border_index = 4;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 2;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_regular(const Vertex_t &center, const array_t<Vertex_t,2*SIZE>& center_ring, const float vertex_level, const unsigned int N, const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)
+ {
+ assert(N<(MAX_RING_FACE_VALENCE));
+ assert(2*N<(MAX_RING_EDGE_VALENCE));
+ dest.vertex_level = vertex_level;
+ dest.face_valence = N;
+ dest.edge_valence = 2*N;
+ dest.border_index = -1;
+ dest.vtx = (Vertex_t)center;
+ dest.vertex_crease_weight = 0.0f;
+ for (unsigned i=0; i<2*N; i++) {
+ dest.ring[i] = (Vertex_t)center_ring[(2*N+offset+i-1)%(2*N)];
+ assert(isvalid(dest.ring[i]));
+ }
+ for (unsigned i=0; i<N; i++)
+ dest.crease_weight[i] = 0.0f;
+
+ assert(offset <= 2*N);
+ dest.eval_start_index = (2*N-offset)>>1;
+ if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;
+
+ assert( dest.eval_start_index < dest.face_valence );
+ dest.eval_unique_identifier = 0;
+ }
+
+ __noinline void subdivide(array_t<CatmullClarkPatch,SIZE>& patch, unsigned& N_o) const
+ {
+ N_o = N;
+ assert( N );
+ for (unsigned i=0; i<N; i++) {
+ unsigned ip1 = (i+1)%N; // FIXME: %
+ ring[i].subdivide(patch[i].ring[0]);
+ patch[i] .ring[0].edge_level = 0.5f*ring[i].edge_level;
+ patch[ip1].ring[3].edge_level = 0.5f*ring[i].edge_level;
+
+ assert( patch[i].ring[0].hasValidPositions() );
+
+ }
+ assert(N < 2*SIZE);
+ Vertex_t center = Vertex_t(0.0f);
+ array_t<Vertex_t,2*SIZE> center_ring;
+ float center_vertex_level = 2.0f; // guarantees that irregular vertices get always isolated also for non-quads
+
+ for (unsigned i=0; i<N; i++)
+ {
+ unsigned ip1 = (i+1)%N; // FIXME: %
+ unsigned im1 = (i+N-1)%N; // FIXME: %
+ bool regular = ring[i].has_last_face() && ring[ip1].face_valence > 2;
+ if (likely(regular)) init_regular(patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);
+ else init_border (patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);
+
+ assert( patch[i].ring[1].hasValidPositions() );
+ assert( patch[ip1].ring[3].hasValidPositions() );
+
+ float level = 0.25f*(ring[im1].edge_level+ring[ip1].edge_level);
+ patch[i].ring[1].edge_level = patch[ip1].ring[2].edge_level = level;
+ center_vertex_level = max(center_vertex_level,level);
+
+ center += ring[i].vtx;
+ center_ring[2*i+0] = (Vertex_t)patch[i].ring[0].vtx;
+ center_ring[2*i+1] = (Vertex_t)patch[i].ring[0].ring[0];
+ }
+ center /= float(N);
+
+ for (unsigned int i=0; i<N; i++) {
+ init_regular(center,center_ring,center_vertex_level,N,2*i,patch[i].ring[2]);
+
+ assert( patch[i].ring[2].hasValidPositions() );
+ }
+ }
+
+ void init(CatmullClarkPatch& patch) const
+ {
+ assert(size() == 4);
+ ring[0].convert(patch.ring[0]);
+ ring[1].convert(patch.ring[1]);
+ ring[2].convert(patch.ring[2]);
+ ring[3].convert(patch.ring[3]);
+ }
+
+ static void fix_quad_ring_order (array_t<CatmullClarkPatch,GeneralCatmullClarkPatchT::SIZE>& patches)
+ {
+ CatmullClark1Ring patches1ring1 = patches[1].ring[1];
+ patches[1].ring[1] = patches[1].ring[0]; // FIXME: optimize these assignments
+ patches[1].ring[0] = patches[1].ring[3];
+ patches[1].ring[3] = patches[1].ring[2];
+ patches[1].ring[2] = patches1ring1;
+
+ CatmullClark1Ring patches2ring2 = patches[2].ring[2];
+ patches[2].ring[2] = patches[2].ring[0];
+ patches[2].ring[0] = patches2ring2;
+ CatmullClark1Ring patches2ring3 = patches[2].ring[3];
+ patches[2].ring[3] = patches[2].ring[1];
+ patches[2].ring[1] = patches2ring3;
+
+ CatmullClark1Ring patches3ring3 = patches[3].ring[3];
+ patches[3].ring[3] = patches[3].ring[0];
+ patches[3].ring[0] = patches[3].ring[1];
+ patches[3].ring[1] = patches[3].ring[2];
+ patches[3].ring[2] = patches3ring3;
+ }
+
+ __forceinline void getLimitBorder(BezierCurve curves[GeneralCatmullClarkPatchT::SIZE]) const
+ {
+ Vertex P0 = ring[0].getLimitVertex();
+ for (unsigned i=0; i<N; i++)
+ {
+ const unsigned i0 = i, i1 = i+1==N ? 0 : i+1;
+ const Vertex P1 = madd(1.0f/3.0f,ring[i0].getLimitTangent(),P0);
+ const Vertex P3 = ring[i1].getLimitVertex();
+ const Vertex P2 = madd(1.0f/3.0f,ring[i1].getSecondLimitTangent(),P3);
+ new (&curves[i]) BezierCurve(P0,P1,P2,P3);
+ P0 = P3;
+ }
+ }
+
+ __forceinline void getLimitBorder(BezierCurve curves[2], const unsigned subPatch) const
+ {
+ const unsigned i0 = subPatch;
+ const Vertex t0_p = ring[i0].getLimitTangent();
+ const Vertex t0_m = ring[i0].getSecondLimitTangent();
+
+ const unsigned i1 = subPatch+1 == N ? 0 : subPatch+1;
+ const Vertex t1_p = ring[i1].getLimitTangent();
+ const Vertex t1_m = ring[i1].getSecondLimitTangent();
+
+ const unsigned i2 = subPatch == 0 ? N-1 : subPatch-1;
+ const Vertex t2_p = ring[i2].getLimitTangent();
+ const Vertex t2_m = ring[i2].getSecondLimitTangent();
+
+ const Vertex b00 = ring[i0].getLimitVertex();
+ const Vertex b03 = ring[i1].getLimitVertex();
+ const Vertex b33 = ring[i2].getLimitVertex();
+
+ const Vertex b01 = madd(1.0/3.0f,t0_p,b00);
+ const Vertex b11 = madd(1.0/3.0f,t0_m,b00);
+
+ //const Vertex b13 = madd(1.0/3.0f,t1_p,b03);
+ const Vertex b02 = madd(1.0/3.0f,t1_m,b03);
+
+ const Vertex b22 = madd(1.0/3.0f,t2_p,b33);
+ const Vertex b23 = madd(1.0/3.0f,t2_m,b33);
+
+ new (&curves[0]) BezierCurve(b00,b01,b02,b03);
+ new (&curves[1]) BezierCurve(b33,b22,b11,b00);
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClarkPatchT &p)
+ {
+ o << "GeneralCatmullClarkPatch { " << embree_endl;
+ for (unsigned i=0; i<p.N; i++)
+ o << "ring" << i << ": " << p.ring[i] << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+ };
+
+ typedef GeneralCatmullClarkPatchT<Vec3fa,Vec3fa_t> GeneralCatmullClarkPatch3fa;
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_ring.h b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_ring.h
new file mode 100644
index 0000000000..73b41fd4ff
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/catmullclark_ring.h
@@ -0,0 +1,826 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+#include "../common/buffer.h"
+#include "half_edge.h"
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ struct __aligned(64) FinalQuad {
+ Vec3fa vtx[4];
+ };
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) CatmullClark1RingT
+ {
+ ALIGNED_STRUCT_(64);
+
+ int border_index; //!< edge index where border starts
+ unsigned int face_valence; //!< number of adjacent quad faces
+ unsigned int edge_valence; //!< number of adjacent edges (2*face_valence)
+ float vertex_crease_weight; //!< weight of vertex crease (0 if no vertex crease)
+ DynamicStackArray<float,16,MAX_RING_FACE_VALENCE> crease_weight; //!< edge crease weights for each adjacent edge
+ float vertex_level; //!< maximum level of all adjacent edges
+ float edge_level; //!< level of first edge
+ unsigned int eval_start_index; //!< topology dependent index to start evaluation
+ unsigned int eval_unique_identifier; //!< topology dependent unique identifier for this ring
+ Vertex vtx; //!< center vertex
+ DynamicStackArray<Vertex,32,MAX_RING_EDGE_VALENCE> ring; //!< ring of neighboring vertices
+
+ public:
+ CatmullClark1RingT ()
+ : eval_start_index(0), eval_unique_identifier(0) {} // FIXME: default constructor should be empty
+
+ /*! calculates number of bytes required to serialize this structure */
+ __forceinline size_t bytes() const
+ {
+ size_t ofs = 0;
+ ofs += sizeof(border_index);
+ ofs += sizeof(face_valence);
+ assert(2*face_valence == edge_valence);
+ ofs += sizeof(vertex_crease_weight);
+ ofs += face_valence*sizeof(float);
+ ofs += sizeof(vertex_level);
+ ofs += sizeof(edge_level);
+ ofs += sizeof(eval_start_index);
+ ofs += sizeof(eval_unique_identifier);
+ ofs += sizeof(vtx);
+ ofs += edge_valence*sizeof(Vertex);
+ return ofs;
+ }
+
+ template<typename Ty>
+ static __forceinline void store(char* ptr, size_t& ofs, const Ty& v) {
+ *(Ty*)&ptr[ofs] = v; ofs += sizeof(Ty);
+ }
+
+ template<typename Ty>
+ static __forceinline void load(char* ptr, size_t& ofs, Ty& v) {
+ v = *(Ty*)&ptr[ofs]; ofs += sizeof(Ty);
+ }
+
+ /*! serializes the ring to some memory location */
+ __forceinline void serialize(char* ptr, size_t& ofs) const
+ {
+ store(ptr,ofs,border_index);
+ store(ptr,ofs,face_valence);
+ store(ptr,ofs,vertex_crease_weight);
+ for (size_t i=0; i<face_valence; i++)
+ store(ptr,ofs,crease_weight[i]);
+ store(ptr,ofs,vertex_level);
+ store(ptr,ofs,edge_level);
+ store(ptr,ofs,eval_start_index);
+ store(ptr,ofs,eval_unique_identifier);
+ Vertex_t::storeu(&ptr[ofs],vtx); ofs += sizeof(Vertex);
+ for (size_t i=0; i<edge_valence; i++) {
+ Vertex_t::storeu(&ptr[ofs],ring[i]); ofs += sizeof(Vertex);
+ }
+ }
+
+ /*! deserializes the ring from some memory location */
+ __forceinline void deserialize(char* ptr, size_t& ofs)
+ {
+ load(ptr,ofs,border_index);
+ load(ptr,ofs,face_valence);
+ edge_valence = 2*face_valence;
+ load(ptr,ofs,vertex_crease_weight);
+ for (size_t i=0; i<face_valence; i++)
+ load(ptr,ofs,crease_weight[i]);
+ load(ptr,ofs,vertex_level);
+ load(ptr,ofs,edge_level);
+ load(ptr,ofs,eval_start_index);
+ load(ptr,ofs,eval_unique_identifier);
+ vtx = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
+ for (size_t i=0; i<edge_valence; i++) {
+ ring[i] = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
+ }
+ }
+
+ __forceinline bool hasBorder() const {
+ return border_index != -1;
+ }
+
+ __forceinline const Vertex& front(size_t i) const {
+ assert(edge_valence>i);
+ return ring[i];
+ }
+
+ __forceinline const Vertex& back(size_t i) const {
+ assert(edge_valence>=i);
+ return ring[edge_valence-i];
+ }
+
+ __forceinline bool has_last_face() const {
+ return (size_t)border_index != (size_t)edge_valence-2;
+ }
+
+ __forceinline bool has_opposite_front(size_t i) const {
+ return (size_t)border_index != 2*i;
+ }
+
+ __forceinline bool has_opposite_back(size_t i) const {
+ return (size_t)border_index != ((size_t)edge_valence-2-2*i);
+ }
+
+ __forceinline BBox3fa bounds() const
+ {
+ BBox3fa bounds ( vtx );
+ for (size_t i = 0; i<edge_valence ; i++)
+ bounds.extend( ring[i] );
+ return bounds;
+ }
+
+ /*! initializes the ring from the half edge structure */
+ __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
+ {
+ border_index = -1;
+ vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
+ vertex_crease_weight = h->vertex_crease_weight;
+
+ HalfEdge* p = (HalfEdge*) h;
+
+ unsigned i=0;
+ unsigned min_vertex_index = (unsigned)-1;
+ unsigned min_vertex_index_face = (unsigned)-1;
+ edge_level = p->edge_level;
+ vertex_level = 0.0f;
+
+ do
+ {
+ vertex_level = max(vertex_level,p->edge_level);
+ crease_weight[i/2] = p->edge_crease_weight;
+ assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
+
+ /* store first two vertices of face */
+ p = p->next();
+ const unsigned index0 = p->getStartVertexIndex();
+ ring[i++] = Vertex_t::loadu(vertices+index0*stride);
+ if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
+ p = p->next();
+
+ const unsigned index1 = p->getStartVertexIndex();
+ ring[i++] = Vertex_t::loadu(vertices+index1*stride);
+ p = p->next();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ /* find minimum start vertex */
+ const unsigned index0 = p->getStartVertexIndex();
+ if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
+
+ /*! mark first border edge and store dummy vertex for face between the two border edges */
+ border_index = i;
+ crease_weight[i/2] = inf;
+ ring[i++] = Vertex_t::loadu(vertices+index0*stride);
+ ring[i++] = vtx; // dummy vertex
+
+ /*! goto other side of border */
+ p = (HalfEdge*) h;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != h);
+
+ edge_valence = i;
+ face_valence = i >> 1;
+ eval_unique_identifier = min_vertex_index;
+ eval_start_index = min_vertex_index_face;
+
+ assert( hasValidPositions() );
+ }
+
+ __forceinline void subdivide(CatmullClark1RingT& dest) const
+ {
+ dest.edge_level = 0.5f*edge_level;
+ dest.vertex_level = 0.5f*vertex_level;
+ dest.face_valence = face_valence;
+ dest.edge_valence = edge_valence;
+ dest.border_index = border_index;
+ dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
+ dest.eval_start_index = eval_start_index;
+ dest.eval_unique_identifier = eval_unique_identifier;
+
+ /* calculate face points */
+ Vertex_t S = Vertex_t(0.0f);
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t face_index = i + eval_start_index; if (face_index >= face_valence) face_index -= face_valence; assert(face_index < face_valence);
+ size_t index0 = 2*face_index+0; if (index0 >= edge_valence) index0 -= edge_valence; assert(index0 < edge_valence);
+ size_t index1 = 2*face_index+1; if (index1 >= edge_valence) index1 -= edge_valence; assert(index1 < edge_valence);
+ size_t index2 = 2*face_index+2; if (index2 >= edge_valence) index2 -= edge_valence; assert(index2 < edge_valence);
+ S += dest.ring[index1] = ((vtx + ring[index1]) + (ring[index0] + ring[index2])) * 0.25f;
+ }
+
+ /* calculate new edge points */
+ size_t num_creases = 0;
+ array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
+
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t face_index = i + eval_start_index;
+ if (face_index >= face_valence) face_index -= face_valence;
+ const float edge_crease = crease_weight[face_index];
+ dest.crease_weight[face_index] = max(edge_crease-1.0f,0.0f);
+
+ size_t index = 2*face_index;
+ size_t prev_index = face_index == 0 ? edge_valence-1 : 2*face_index-1;
+ size_t next_index = 2*face_index+1;
+
+ const Vertex_t v = vtx + ring[index];
+ const Vertex_t f = dest.ring[prev_index] + dest.ring[next_index];
+ S += ring[index];
+
+ /* fast path for regular edge points */
+ if (likely(edge_crease <= 0.0f)) {
+ dest.ring[index] = (v+f) * 0.25f;
+ }
+
+ /* slower path for hard edge rule */
+ else {
+ crease_id[num_creases++] = face_index;
+ dest.ring[index] = v*0.5f;
+
+ /* even slower path for blended edge rule */
+ if (unlikely(edge_crease < 1.0f)) {
+ dest.ring[index] = lerp((v+f)*0.25f,v*0.5f,edge_crease);
+ }
+ }
+ }
+
+ /* compute new vertex using smooth rule */
+ const float inv_face_valence = 1.0f / (float)face_valence;
+ const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
+ dest.vtx = v_smooth;
+
+ /* compute new vertex using vertex_crease_weight rule */
+ if (unlikely(vertex_crease_weight > 0.0f))
+ {
+ if (vertex_crease_weight >= 1.0f) {
+ dest.vtx = vtx;
+ } else {
+ dest.vtx = lerp(v_smooth,vtx,vertex_crease_weight);
+ }
+ return;
+ }
+
+ /* no edge crease rule and dart rule */
+ if (likely(num_creases <= 1))
+ return;
+
+ /* compute new vertex using crease rule */
+ if (likely(num_creases == 2))
+ {
+ /* update vertex using crease rule */
+ const size_t crease0 = crease_id[0], crease1 = crease_id[1];
+ const Vertex_t v_sharp = (Vertex_t)(ring[2*crease0] + 6.0f*vtx + ring[2*crease1]) * (1.0f / 8.0f);
+ dest.vtx = v_sharp;
+
+ /* update crease_weights using chaikin rule */
+ const float crease_weight0 = crease_weight[crease0], crease_weight1 = crease_weight[crease1];
+ dest.crease_weight[crease0] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
+ dest.crease_weight[crease1] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
+
+ /* interpolate between sharp and smooth rule */
+ const float v_blend = 0.5f*(crease_weight0+crease_weight1);
+ if (unlikely(v_blend < 1.0f)) {
+ dest.vtx = lerp(v_smooth,v_sharp,v_blend);
+ }
+ }
+
+ /* compute new vertex using corner rule */
+ else {
+ dest.vtx = vtx;
+ }
+ }
+
+ __forceinline bool isRegular1() const
+ {
+ if (border_index == -1) {
+ if (face_valence == 4) return true;
+ } else {
+ if (face_valence < 4) return true;
+ }
+ return false;
+ }
+
+ __forceinline size_t numEdgeCreases() const
+ {
+ ssize_t numCreases = 0;
+ for (size_t i=0; i<face_valence; i++) {
+ numCreases += crease_weight[i] > 0.0f;
+ }
+ return numCreases;
+ }
+
+ enum Type {
+ TYPE_NONE = 0, //!< invalid type
+ TYPE_REGULAR = 1, //!< regular patch when ignoring creases
+ TYPE_REGULAR_CREASES = 2, //!< regular patch when considering creases
+ TYPE_GREGORY = 4, //!< gregory patch when ignoring creases
+ TYPE_GREGORY_CREASES = 8, //!< gregory patch when considering creases
+ TYPE_CREASES = 16 //!< patch has crease features
+ };
+
+ __forceinline Type type() const
+ {
+ /* check if there is an edge crease anywhere */
+ const size_t numCreases = numEdgeCreases();
+ const bool noInnerCreases = hasBorder() ? numCreases == 2 : numCreases == 0;
+
+ Type crease_mask = (Type) (TYPE_REGULAR | TYPE_GREGORY);
+ if (noInnerCreases ) crease_mask = (Type) (crease_mask | TYPE_REGULAR_CREASES | TYPE_GREGORY_CREASES);
+ if (numCreases != 0) crease_mask = (Type) (crease_mask | TYPE_CREASES);
+
+ /* calculate if this vertex is regular */
+ bool hasBorder = border_index != -1;
+ if (face_valence == 2 && hasBorder) {
+ if (vertex_crease_weight == 0.0f ) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else if (vertex_crease_weight == float(inf)) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else return TYPE_CREASES;
+ }
+ else if (vertex_crease_weight != 0.0f) return TYPE_CREASES;
+ else if (face_valence == 3 && hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else if (face_valence == 4 && !hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else return (Type) (crease_mask & (TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ }
+
+ __forceinline bool isFinalResolution(float res) const {
+ return vertex_level <= res;
+ }
+
+ /* computes the limit vertex */
+ __forceinline Vertex getLimitVertex() const
+ {
+ /* return hard corner */
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (4.0f * vtx + (ring[border_index] + ring[second_border_index])) * 1.0f/6.0f;
+ }
+
+ Vertex_t F( 0.0f );
+ Vertex_t E( 0.0f );
+
+ assert(eval_start_index < face_valence);
+
+ for (size_t i=0; i<face_valence; i++) {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+ F += ring[2*index+1];
+ E += ring[2*index];
+ }
+
+ const float n = (float)face_valence;
+ return (Vertex_t)(n*n*vtx+4.0f*E+F) / ((n+5.0f)*n);
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[0] */
+ __forceinline Vertex getLimitTangent() const
+ {
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return ring[0] - vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ if (border_index != (int)edge_valence-2 ) {
+ return ring[0] - vtx;
+ }
+ else
+ {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (ring[second_border_index] - ring[border_index]) * 0.5f;
+ }
+ }
+
+ Vertex_t alpha( 0.0f );
+ Vertex_t beta ( 0.0f );
+
+ const size_t n = face_valence;
+
+ assert(eval_start_index < face_valence);
+
+ Vertex_t q( 0.0f );
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+ const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(index,n);
+ const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(index,n);
+ alpha += a * ring[2*index];
+ beta += b * ring[2*index+1];
+ }
+
+ const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
+ return sigma * (alpha + beta);
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
+ __forceinline Vertex getSecondLimitTangent() const
+ {
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return ring[2] - vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ if (border_index != 2) {
+ return ring[2] - vtx;
+ }
+ else {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (ring[border_index] - ring[second_border_index]) * 0.5f;
+ }
+ }
+
+ Vertex_t alpha( 0.0f );
+ Vertex_t beta ( 0.0f );
+
+ const size_t n = face_valence;
+
+ assert(eval_start_index < face_valence);
+
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+
+ size_t prev_index = index == 0 ? face_valence-1 : index-1; // need to be bit-wise exact in cosf eval
+ const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(prev_index,n);
+ const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(prev_index,n);
+ alpha += a * ring[2*index];
+ beta += b * ring[2*index+1];
+ }
+
+ const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
+ return sigma* (alpha + beta);
+ }
+
+ /* gets surface normal */
+ const Vertex getNormal() const {
+ return cross(getLimitTangent(),getSecondLimitTangent());
+ }
+
+ /* returns center of the n-th quad in the 1-ring */
+ __forceinline Vertex getQuadCenter(const size_t index) const
+ {
+ const Vertex_t &p0 = vtx;
+ const Vertex_t &p1 = ring[2*index+0];
+ const Vertex_t &p2 = ring[2*index+1];
+ const Vertex_t &p3 = index == face_valence-1 ? ring[0] : ring[2*index+2];
+ const Vertex p = (p0+p1+p2+p3) * 0.25f;
+ return p;
+ }
+
+ /* returns center of the n-th edge in the 1-ring */
+ __forceinline Vertex getEdgeCenter(const size_t index) const {
+ return (vtx + ring[index*2]) * 0.5f;
+ }
+
+ bool hasValidPositions() const
+ {
+ for (size_t i=0; i<edge_valence; i++) {
+ if (!isvalid(ring[i]))
+ return false;
+ }
+ return true;
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClark1RingT &c)
+ {
+ o << "vtx " << c.vtx << " size = " << c.edge_valence << ", " <<
+ "hard_edge = " << c.border_index << ", face_valence " << c.face_valence <<
+ ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", eval_start_index: " << c.eval_start_index << ", ring: " << embree_endl;
+
+ for (unsigned int i=0; i<min(c.edge_valence,(unsigned int)MAX_RING_FACE_VALENCE); i++) {
+ o << i << " -> " << c.ring[i];
+ if (i % 2 == 0) o << " crease = " << c.crease_weight[i/2];
+ o << embree_endl;
+ }
+ return o;
+ }
+ };
+
+ typedef CatmullClark1RingT<Vec3fa,Vec3fa_t> CatmullClark1Ring3fa;
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) GeneralCatmullClark1RingT
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+
+ struct Face
+ {
+ __forceinline Face() {}
+ __forceinline Face (int size, float crease_weight)
+ : size(size), crease_weight(crease_weight) {}
+
+ // FIXME: add member that returns total number of vertices
+
+ int size; // number of vertices-2 of nth face in ring
+ float crease_weight;
+ };
+
+ Vertex vtx;
+ DynamicStackArray<Vertex,32,MAX_RING_EDGE_VALENCE> ring;
+ DynamicStackArray<Face,16,MAX_RING_FACE_VALENCE> faces;
+ unsigned int face_valence;
+ unsigned int edge_valence;
+ int border_face;
+ float vertex_crease_weight;
+ float vertex_level; //!< maximum level of adjacent edges
+ float edge_level; // level of first edge
+ bool only_quads; // true if all faces are quads
+ unsigned int eval_start_face_index;
+ unsigned int eval_start_vertex_index;
+ unsigned int eval_unique_identifier;
+
+ public:
+ GeneralCatmullClark1RingT()
+ : eval_start_face_index(0), eval_start_vertex_index(0), eval_unique_identifier(0) {}
+
+ __forceinline bool isRegular() const
+ {
+ if (border_face == -1 && face_valence == 4) return true;
+ return false;
+ }
+
+ __forceinline bool has_last_face() const {
+ return border_face != (int)face_valence-1;
+ }
+
+ __forceinline bool has_second_face() const {
+ return (border_face == -1) || (border_face >= 2);
+ }
+
+ bool hasValidPositions() const
+ {
+ for (size_t i=0; i<edge_valence; i++) {
+ if (!isvalid(ring[i]))
+ return false;
+ }
+ return true;
+ }
+
+ __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
+ {
+ only_quads = true;
+ border_face = -1;
+ vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
+ vertex_crease_weight = h->vertex_crease_weight;
+ HalfEdge* p = (HalfEdge*) h;
+
+ unsigned int e=0, f=0;
+ unsigned min_vertex_index = (unsigned)-1;
+ unsigned min_vertex_index_face = (unsigned)-1;
+ unsigned min_vertex_index_vertex = (unsigned)-1;
+ edge_level = p->edge_level;
+ vertex_level = 0.0f;
+ do
+ {
+ HalfEdge* p_prev = p->prev();
+ HalfEdge* p_next = p->next();
+ const float crease_weight = p->edge_crease_weight;
+ assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
+ vertex_level = max(vertex_level,p->edge_level);
+
+ /* find minimum start vertex */
+ unsigned vertex_index = p_next->getStartVertexIndex();
+ if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
+
+ /* store first N-2 vertices of face */
+ unsigned int vn = 0;
+ for (p = p_next; p!=p_prev; p=p->next()) {
+ ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
+ vn++;
+ }
+ faces[f++] = Face(vn,crease_weight);
+ only_quads &= (vn == 2);
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ /* find minimum start vertex */
+ unsigned vertex_index = p->getStartVertexIndex();
+ if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
+
+ /*! mark first border edge and store dummy vertex for face between the two border edges */
+ border_face = f;
+ faces[f++] = Face(2,inf);
+ ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
+ ring[e++] = vtx; // dummy vertex
+
+ /*! goto other side of border */
+ p = (HalfEdge*) h;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != h);
+
+ edge_valence = e;
+ face_valence = f;
+ eval_unique_identifier = min_vertex_index;
+ eval_start_face_index = min_vertex_index_face;
+ eval_start_vertex_index = min_vertex_index_vertex;
+
+ assert( hasValidPositions() );
+ }
+
+ __forceinline void subdivide(CatmullClark1Ring& dest) const
+ {
+ dest.edge_level = 0.5f*edge_level;
+ dest.vertex_level = 0.5f*vertex_level;
+ dest.face_valence = face_valence;
+ dest.edge_valence = 2*face_valence;
+ dest.border_index = border_face == -1 ? -1 : 2*border_face; // FIXME:
+ dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
+ dest.eval_start_index = eval_start_face_index;
+ dest.eval_unique_identifier = eval_unique_identifier;
+ assert(dest.face_valence <= MAX_RING_FACE_VALENCE);
+
+ /* calculate face points */
+ Vertex_t S = Vertex_t(0.0f);
+ for (size_t face=0, v=eval_start_vertex_index; face<face_valence; face++) {
+ size_t f = (face + eval_start_face_index)%face_valence;
+
+ Vertex_t F = vtx;
+ for (size_t k=v; k<=v+faces[f].size; k++) F += ring[k%edge_valence]; // FIXME: optimize
+ S += dest.ring[2*f+1] = F/float(faces[f].size+2);
+ v+=faces[f].size;
+ v%=edge_valence;
+ }
+
+ /* calculate new edge points */
+ size_t num_creases = 0;
+ array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
+ Vertex_t C = Vertex_t(0.0f);
+ for (size_t face=0, j=eval_start_vertex_index; face<face_valence; face++)
+ {
+ size_t i = (face + eval_start_face_index)%face_valence;
+
+ const Vertex_t v = vtx + ring[j];
+ Vertex_t f = dest.ring[2*i+1];
+ if (i == 0) f += dest.ring[dest.edge_valence-1];
+ else f += dest.ring[2*i-1];
+ S += ring[j];
+ dest.crease_weight[i] = max(faces[i].crease_weight-1.0f,0.0f);
+
+ /* fast path for regular edge points */
+ if (likely(faces[i].crease_weight <= 0.0f)) {
+ dest.ring[2*i] = (v+f) * 0.25f;
+ }
+
+ /* slower path for hard edge rule */
+ else {
+ C += ring[j]; crease_id[num_creases++] = i;
+ dest.ring[2*i] = v*0.5f;
+
+ /* even slower path for blended edge rule */
+ if (unlikely(faces[i].crease_weight < 1.0f)) {
+ dest.ring[2*i] = lerp((v+f)*0.25f,v*0.5f,faces[i].crease_weight);
+ }
+ }
+ j+=faces[i].size;
+ j%=edge_valence;
+ }
+
+ /* compute new vertex using smooth rule */
+ const float inv_face_valence = 1.0f / (float)face_valence;
+ const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
+ dest.vtx = v_smooth;
+
+ /* compute new vertex using vertex_crease_weight rule */
+ if (unlikely(vertex_crease_weight > 0.0f))
+ {
+ if (vertex_crease_weight >= 1.0f) {
+ dest.vtx = vtx;
+ } else {
+ dest.vtx = lerp(vtx,v_smooth,vertex_crease_weight);
+ }
+ return;
+ }
+
+ if (likely(num_creases <= 1))
+ return;
+
+ /* compute new vertex using crease rule */
+ if (likely(num_creases == 2)) {
+ const Vertex_t v_sharp = (Vertex_t)(C + 6.0f * vtx) * (1.0f / 8.0f);
+ const float crease_weight0 = faces[crease_id[0]].crease_weight;
+ const float crease_weight1 = faces[crease_id[1]].crease_weight;
+ dest.vtx = v_sharp;
+ dest.crease_weight[crease_id[0]] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
+ dest.crease_weight[crease_id[1]] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
+ const float v_blend = 0.5f*(crease_weight0+crease_weight1);
+ if (unlikely(v_blend < 1.0f)) {
+ dest.vtx = lerp(v_sharp,v_smooth,v_blend);
+ }
+ }
+
+ /* compute new vertex using corner rule */
+ else {
+ dest.vtx = vtx;
+ }
+ }
+
+ void convert(CatmullClark1Ring& dst) const
+ {
+ dst.edge_level = edge_level;
+ dst.vertex_level = vertex_level;
+ dst.vtx = vtx;
+ dst.face_valence = face_valence;
+ dst.edge_valence = 2*face_valence;
+ dst.border_index = border_face == -1 ? -1 : 2*border_face;
+ for (size_t i=0; i<face_valence; i++)
+ dst.crease_weight[i] = faces[i].crease_weight;
+ dst.vertex_crease_weight = vertex_crease_weight;
+ for (size_t i=0; i<edge_valence; i++) dst.ring[i] = ring[i];
+
+ dst.eval_start_index = eval_start_face_index;
+ dst.eval_unique_identifier = eval_unique_identifier;
+
+ assert( dst.hasValidPositions() );
+ }
+
+
+ /* gets limit tangent in the direction of egde vtx -> ring[0] */
+ __forceinline Vertex getLimitTangent() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ {
+ convert(cc_vtx);
+ return cc_vtx.getLimitTangent();
+ }
+
+ subdivide(cc_vtx);
+ return 2.0f * cc_vtx.getLimitTangent();
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
+ __forceinline Vertex getSecondLimitTangent() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ {
+ convert(cc_vtx);
+ return cc_vtx.getSecondLimitTangent();
+ }
+
+ subdivide(cc_vtx);
+ return 2.0f * cc_vtx.getSecondLimitTangent();
+ }
+
+
+ /* gets limit vertex */
+ __forceinline Vertex getLimitVertex() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ convert(cc_vtx);
+ else
+ subdivide(cc_vtx);
+ return cc_vtx.getLimitVertex();
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClark1RingT &c)
+ {
+ o << "vtx " << c.vtx << " size = " << c.edge_valence << ", border_face = " << c.border_face << ", " << " face_valence = " << c.face_valence <<
+ ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", ring: " << embree_endl;
+ for (size_t v=0, f=0; f<c.face_valence; v+=c.faces[f++].size) {
+ for (size_t i=v; i<v+c.faces[f].size; i++) {
+ o << i << " -> " << c.ring[i];
+ if (i == v) o << " crease = " << c.faces[f].crease_weight;
+ o << embree_endl;
+ }
+ }
+ return o;
+ }
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/catmullrom_curve.h b/thirdparty/embree-aarch64/kernels/subdiv/catmullrom_curve.h
new file mode 100644
index 0000000000..b244af481c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/catmullrom_curve.h
@@ -0,0 +1,296 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/scene_curves.h"
+
+/*
+
+ Implements Catmul Rom curves with control points p0, p1, p2, p3. At
+ t=0 the curve goes through p1, with tangent (p2-p0)/3, and for t=1
+ the curve goes through p2 with tangent (p3-p2)/2.
+
+ */
+
+namespace embree
+{
+ class CatmullRomBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t = u;
+ const T s = T(1.0f) - u;
+ const T n0 = - t * s * s;
+ const T n1 = 2.0f + t * t * (3.0f * t - 5.0f);
+ const T n2 = 2.0f + s * s * (3.0f * s - 5.0f);
+ const T n3 = - s * t * t;
+ return T(0.5f) * Vec4<T>(n0, n1, n2, n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = - s * s + 2.0f * s * t;
+ const T n1 = 2.0f * t * (3.0f * t - 5.0f) + 3.0f * t * t;
+ const T n2 = 2.0f * s * (3.0f * t + 2.0f) - 3.0f * s * s;
+ const T n3 = -2.0f * s * t + t * t;
+ return T(0.5f) * Vec4<T>(n0, n1, n2, n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t = u;
+ const T n0 = -3.0f * t + 2.0f;
+ const T n1 = 9.0f * t - 5.0f;
+ const T n2 = -9.0f * t + 4.0f;
+ const T n3 = 3.0f * t - 1.0f;
+ return Vec4<T>(n0, n1, n2, n3);
+ }
+ };
+
+ struct PrecomputedCatmullRomBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedCatmullRomBasis() {}
+ PrecomputedCatmullRomBasis(int shift);
+
+ /* basis for bspline evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bspline derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedCatmullRomBasis catmullrom_basis0;
+ extern PrecomputedCatmullRomBasis catmullrom_basis1;
+
+ template<typename Vertex>
+ struct CatmullRomCurveT
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline CatmullRomCurveT() {}
+
+ __forceinline CatmullRomCurveT(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return madd(1.0f/6.0f,v0,madd(2.0f/3.0f,v1,1.0f/6.0f*v2));
+ }
+
+ __forceinline Vertex end() const {
+ return madd(1.0f/6.0f,v1,madd(2.0f/3.0f,v2,1.0f/6.0f*v3));
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend CatmullRomCurveT operator -( const CatmullRomCurveT& a, const Vertex& b ) {
+ return CatmullRomCurveT(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline CatmullRomCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,v3-p), v3.w);
+ return CatmullRomCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ p = eval(t);
+ dp = eval_du(t);
+ ddp = eval_dudu(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ p = veval(t);
+ dp = veval_du(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis0.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis0.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis1.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis1.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis0.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis0.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis1.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis1.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ /* calculates bounds of catmull-rom curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ const Vec3ff pe = end();
+ return enlarge(BBox3fa(min(lower,pe),max(upper,pe)),max(upper_r,Vec3fa(abs(pe.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) <= vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const CatmullRomCurveT& curve) {
+ return cout << "CatmullRomCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+ __forceinline CatmullRomCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CatmullRomCurveT<Vec3ff>& curve)
+ {
+ return CatmullRomCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+
+ typedef CatmullRomCurveT<Vec3fa> CatmullRomCurve3fa;
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval.h b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval.h
new file mode 100644
index 0000000000..23f24c360c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval.h
@@ -0,0 +1,226 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct FeatureAdaptiveEval
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef BSplinePatchT<Vertex,Vertex_t> BSplinePatch;
+ typedef BezierPatchT<Vertex,Vertex_t> BezierPatch;
+ typedef GregoryPatchT<Vertex,Vertex_t> GregoryPatch;
+ typedef BilinearPatchT<Vertex,Vertex_t> BilinearPatch;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ public:
+
+ FeatureAdaptiveEval (const HalfEdge* edge, const char* vertices, size_t stride, const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: BilinearPatch(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: RegularPatchT(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: GregoryPatch(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ eval(patch,Vec2f(u,v),0);
+ break;
+ }
+ }
+ }
+
+ FeatureAdaptiveEval (CatmullClarkPatch& patch, const float u, const float v, float dscale, size_t depth,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ eval(patch,Vec2f(u,v),dscale,depth);
+ }
+
+ void eval_general_quad(const GeneralCatmullClarkPatch& patch, array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE>& patches, const Vec2f& uv, size_t depth)
+ {
+ float u = uv.x, v = uv.y;
+ if (v < 0.5f) {
+ if (u < 0.5f) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,0);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[0],Vec2f(2.0f*u,2.0f*v),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[0],Vec2f(2.0f*u,2.0f*v),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = dpdx; *dPdv = dpdy;
+ }
+ }
+ else {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,1);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[1],Vec2f(2.0f*v,2.0f-2.0f*u),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[1],Vec2f(2.0f*v,2.0f-2.0f*u),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = -dpdy; *dPdv = dpdx;
+ }
+ }
+ } else {
+ if (u > 0.5f) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,2);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[2],Vec2f(2.0f-2.0f*u,2.0f-2.0f*v),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[2],Vec2f(2.0f-2.0f*u,2.0f-2.0f*v),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = -dpdx; *dPdv = -dpdy;
+ }
+ }
+ else {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,3);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[3],Vec2f(2.0f-2.0f*v,2.0f*u),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[3],Vec2f(2.0f-2.0f*v,2.0f*u),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = dpdy; *dPdv = -dpdx;
+ }
+ }
+ }
+ }
+
+ __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const int max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=(size_t)max_eval_depth;
+//#else
+ return depth>=(size_t)max_eval_depth;
+//#endif
+ }
+
+ void eval(CatmullClarkPatch& patch, Vec2f uv, float dscale, size_t depth,
+ BezierCurve* border0 = nullptr, BezierCurve* border1 = nullptr, BezierCurve* border2 = nullptr, BezierCurve* border3 = nullptr)
+ {
+ while (true)
+ {
+ typename CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(234423,c,c,-1);
+ return;
+ } else {
+ IrregularFillPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(34534,c,-1,c);
+ return;
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0);
+ RegularPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(43524,c,c,-1);
+ return;
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0);
+ GregoryPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(23498,c,-1,c);
+ return;
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches); // FIXME: only have to generate one of the patches
+
+ const float u = uv.x, v = uv.y;
+ if (v < 0.5f) {
+ if (u < 0.5f) { patch = patches[0]; uv = Vec2f(2.0f*u,2.0f*v); dscale *= 2.0f; }
+ else { patch = patches[1]; uv = Vec2f(2.0f*u-1.0f,2.0f*v); dscale *= 2.0f; }
+ } else {
+ if (u > 0.5f) { patch = patches[2]; uv = Vec2f(2.0f*u-1.0f,2.0f*v-1.0f); dscale *= 2.0f; }
+ else { patch = patches[3]; uv = Vec2f(2.0f*u,2.0f*v-1.0f); dscale *= 2.0f; }
+ }
+ depth++;
+ }
+ }
+ }
+
+ void eval(const GeneralCatmullClarkPatch& patch, const Vec2f& uv, const size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return eval(qpatch,uv,1.0f,depth);
+ }
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,N); // FIXME: only have to generate one of the patches
+
+ /* parametrization for quads */
+ if (N == 4)
+ eval_general_quad(patch,patches,uv,depth);
+
+ /* parametrization for arbitrary polygons */
+ else
+ {
+ const unsigned l = (unsigned) floor(0.5f*uv.x); const float u = 2.0f*frac(0.5f*uv.x)-0.5f;
+ const unsigned h = (unsigned) floor(0.5f*uv.y); const float v = 2.0f*frac(0.5f*uv.y)-0.5f;
+ const unsigned i = 4*h+l; assert(i<N);
+ if (i >= N) return;
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,i);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[i],Vec2f(u,v),1.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[i],Vec2f(u,v),1.0f,depth+1);
+#endif
+ }
+ }
+
+ private:
+ Vertex* const P;
+ Vertex* const dPdu;
+ Vertex* const dPdv;
+ Vertex* const ddPdudu;
+ Vertex* const ddPdvdv;
+ Vertex* const ddPdudv;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_grid.h b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_grid.h
new file mode 100644
index 0000000000..76583b2e5d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_grid.h
@@ -0,0 +1,359 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "catmullclark_patch.h"
+#include "bspline_patch.h"
+#include "gregory_patch.h"
+#include "tessellation.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct FeatureAdaptiveEvalGrid
+ {
+ typedef CatmullClark1Ring3fa CatmullClarkRing;
+ typedef CatmullClarkPatch3fa CatmullClarkPatch;
+ typedef BilinearPatch3fa BilinearPatch;
+ typedef BSplinePatch3fa BSplinePatch;
+ typedef BezierPatch3fa BezierPatch;
+ typedef GregoryPatch3fa GregoryPatch;
+
+ private:
+ const unsigned x0,x1;
+ const unsigned y0,y1;
+ const unsigned swidth,sheight;
+ const float rcp_swidth, rcp_sheight;
+ float* const Px;
+ float* const Py;
+ float* const Pz;
+ float* const U;
+ float* const V;
+ float* const Nx;
+ float* const Ny;
+ float* const Nz;
+ const unsigned dwidth;
+ //const unsigned dheight;
+ unsigned count;
+
+
+ public:
+ FeatureAdaptiveEvalGrid (const GeneralCatmullClarkPatch3fa& patch, unsigned subPatch,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
+ {
+ assert(swidth < (2<<20) && sheight < (2<<20));
+ const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
+ const BBox2f erange(Vec2f((float)x0,(float)y0),Vec2f((float)x1,(float)y1));
+
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch3fa qpatch; patch.init(qpatch);
+ eval(qpatch, srange, erange, 0);
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ return;
+ }
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch3fa,GeneralCatmullClarkPatch3fa::SIZE> patches;
+ patch.subdivide(patches,N);
+
+ if (N == 4)
+ {
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve3fa borders[GeneralCatmullClarkPatch3fa::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve3fa border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve3fa border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve3fa border3l,border3r; borders[3].subdivide(border3l,border3r);
+ GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
+ eval(patches[0],srange0,intersect(srange0,erange),1,&border0l,nullptr,nullptr,&border3r);
+ eval(patches[1],srange1,intersect(srange1,erange),1,&border0r,&border1l,nullptr,nullptr);
+ eval(patches[2],srange2,intersect(srange2,erange),1,nullptr,&border1r,&border2l,nullptr);
+ eval(patches[3],srange3,intersect(srange3,erange),1,nullptr,nullptr,&border2r,&border3l);
+#else
+ GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
+ eval(patches[0],srange0,intersect(srange0,erange),1);
+ eval(patches[1],srange1,intersect(srange1,erange),1);
+ eval(patches[2],srange2,intersect(srange2,erange),1);
+ eval(patches[3],srange3,intersect(srange3,erange),1);
+#endif
+ }
+ else
+ {
+ assert(subPatch < N);
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve3fa borders[2]; patch.getLimitBorder(borders,subPatch);
+ BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve3fa border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[subPatch], srange, erange, 1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[subPatch], srange, erange, 1);
+#endif
+
+ }
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ }
+
+ FeatureAdaptiveEvalGrid (const CatmullClarkPatch3fa& patch,
+ const BBox2f& srange, const BBox2f& erange, const unsigned depth,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
+ {
+ eval(patch,srange,erange,depth);
+ }
+
+ template<typename Patch>
+ void evalLocalGrid(const Patch& patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
+ {
+ const float scale_x = rcp(srange.upper.x-srange.lower.x);
+ const float scale_y = rcp(srange.upper.y-srange.lower.y);
+ count += (lx1-lx0)*(ly1-ly0);
+
+#if 0
+ for (unsigned iy=ly0; iy<ly1; iy++) {
+ for (unsigned ix=lx0; ix<lx1; ix++) {
+ const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
+ const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
+ const Vec3fa p = patch.eval(lu,lv);
+ const float u = float(ix)*rcp_swidth;
+ const float v = float(iy)*rcp_sheight;
+ const int ofs = (iy-y0)*dwidth+(ix-x0);
+ Px[ofs] = p.x;
+ Py[ofs] = p.y;
+ Pz[ofs] = p.z;
+ U[ofs] = u;
+ V[ofs] = v;
+ }
+ }
+#else
+ foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
+ const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);
+ const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);
+ const Vec3vfx p = patch.eval(lu,lv);
+ Vec3vfx n = zero;
+ if (unlikely(Nx != nullptr)) n = normalize_safe(patch.normal(lu,lv));
+ const vfloatx u = vfloatx(ix)*rcp_swidth;
+ const vfloatx v = vfloatx(iy)*rcp_sheight;
+ const vintx ofs = (iy-y0)*dwidth+(ix-x0);
+ if (likely(all(valid)) && all(iy==iy[0])) {
+ const unsigned ofs2 = ofs[0];
+ vfloatx::storeu(Px+ofs2,p.x);
+ vfloatx::storeu(Py+ofs2,p.y);
+ vfloatx::storeu(Pz+ofs2,p.z);
+ vfloatx::storeu(U+ofs2,u);
+ vfloatx::storeu(V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(Nx+ofs2,n.x);
+ vfloatx::storeu(Ny+ofs2,n.y);
+ vfloatx::storeu(Nz+ofs2,n.z);
+ }
+ } else {
+ foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
+ const unsigned ofs2 = ofs[j]-j;
+ vfloatx::storeu(valid,Px+ofs2,p.x);
+ vfloatx::storeu(valid,Py+ofs2,p.y);
+ vfloatx::storeu(valid,Pz+ofs2,p.z);
+ vfloatx::storeu(valid,U+ofs2,u);
+ vfloatx::storeu(valid,V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(valid,Nx+ofs2,n.x);
+ vfloatx::storeu(valid,Ny+ofs2,n.y);
+ vfloatx::storeu(valid,Nz+ofs2,n.z);
+ }
+ });
+ }
+ });
+#endif
+ }
+
+ __forceinline bool final(const CatmullClarkPatch3fa& patch, const CatmullClarkRing::Type type, unsigned depth)
+ {
+ const unsigned max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ void eval(const CatmullClarkPatch3fa& patch, const BBox2f& srange, const BBox2f& erange, const unsigned depth,
+ const BezierCurve3fa* border0 = nullptr, const BezierCurve3fa* border1 = nullptr, const BezierCurve3fa* border2 = nullptr, const BezierCurve3fa* border3 = nullptr)
+ {
+ if (erange.empty())
+ return;
+
+ int lx0 = (int) ceilf(erange.lower.x);
+ int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
+ int ly0 = (int) ceilf(erange.lower.y);
+ int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
+ if (lx0 >= lx1 || ly0 >= ly1) return;
+
+ CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch rpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(rpatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ } else {
+ IrregularFillPatch ipatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(ipatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0);
+ RegularPatch rpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(rpatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0);
+ GregoryPatch gpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(gpatch,srange,lx0,lx1,ly0,ly1);
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch3fa,4> patches;
+ patch.subdivide(patches);
+
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+ eval(patches[0],srange0,intersect(srange0,erange),depth+1);
+ eval(patches[1],srange1,intersect(srange1,erange),depth+1);
+ eval(patches[2],srange2,intersect(srange2,erange),depth+1);
+ eval(patches[3],srange3,intersect(srange3,erange),depth+1);
+ }
+ }
+ };
+
+ template<typename Eval, typename Patch>
+ bool stitch_col(const Patch& patch, int subPatch,
+ const bool right, const unsigned y0, const unsigned y1, const int fine_y, const int coarse_y,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dx0, const unsigned dwidth, const unsigned dheight)
+ {
+ assert(coarse_y <= fine_y);
+ if (likely(fine_y == coarse_y))
+ return false;
+
+ const unsigned y0s = stitch(y0,fine_y,coarse_y);
+ const unsigned y1s = stitch(y1,fine_y,coarse_y);
+ const unsigned M = y1s-y0s+1 + VSIZEX;
+
+ dynamic_large_stack_array(float,px,M,64*sizeof(float));
+ dynamic_large_stack_array(float,py,M,64*sizeof(float));
+ dynamic_large_stack_array(float,pz,M,64*sizeof(float));
+ dynamic_large_stack_array(float,u,M,64*sizeof(float));
+ dynamic_large_stack_array(float,v,M,64*sizeof(float));
+ dynamic_large_stack_array(float,nx,M,64*sizeof(float));
+ dynamic_large_stack_array(float,ny,M,64*sizeof(float));
+ dynamic_large_stack_array(float,nz,M,64*sizeof(float));
+ const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
+ Eval(patch,subPatch, right,right, y0s,y1s, 2,coarse_y+1, px,py,pz,u,v,
+ has_Nxyz ? (float*)nx : nullptr,has_Nxyz ? (float*)ny : nullptr ,has_Nxyz ? (float*)nz : nullptr, 1,4097);
+
+ for (unsigned y=y0; y<=y1; y++)
+ {
+ const unsigned ys = stitch(y,fine_y,coarse_y)-y0s;
+ Px[(y-y0)*dwidth+dx0] = px[ys];
+ Py[(y-y0)*dwidth+dx0] = py[ys];
+ Pz[(y-y0)*dwidth+dx0] = pz[ys];
+ U [(y-y0)*dwidth+dx0] = u[ys];
+ V [(y-y0)*dwidth+dx0] = v[ys];
+ if (unlikely(has_Nxyz)) {
+ Nx[(y-y0)*dwidth+dx0] = nx[ys];
+ Ny[(y-y0)*dwidth+dx0] = ny[ys];
+ Nz[(y-y0)*dwidth+dx0] = nz[ys];
+ }
+ }
+ return true;
+ }
+
+ template<typename Eval, typename Patch>
+ bool stitch_row(const Patch& patch, int subPatch,
+ const bool bottom, const unsigned x0, const unsigned x1, const int fine_x, const int coarse_x,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dy0, const unsigned dwidth, const unsigned dheight)
+ {
+ assert(coarse_x <= fine_x);
+ if (likely(fine_x == coarse_x))
+ return false;
+
+ const unsigned x0s = stitch(x0,fine_x,coarse_x);
+ const unsigned x1s = stitch(x1,fine_x,coarse_x);
+ const unsigned M = x1s-x0s+1 + VSIZEX;
+
+ dynamic_large_stack_array(float,px,M,32*sizeof(float));
+ dynamic_large_stack_array(float,py,M,32*sizeof(float));
+ dynamic_large_stack_array(float,pz,M,32*sizeof(float));
+ dynamic_large_stack_array(float,u,M,32*sizeof(float));
+ dynamic_large_stack_array(float,v,M,32*sizeof(float));
+ dynamic_large_stack_array(float,nx,M,32*sizeof(float));
+ dynamic_large_stack_array(float,ny,M,32*sizeof(float));
+ dynamic_large_stack_array(float,nz,M,32*sizeof(float));
+ const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
+ Eval(patch,subPatch, x0s,x1s, bottom,bottom, coarse_x+1,2, px,py,pz,u,v,
+ has_Nxyz ? (float*)nx :nullptr, has_Nxyz ? (float*)ny : nullptr , has_Nxyz ? (float*)nz : nullptr, 4097,1);
+
+ for (unsigned x=x0; x<=x1; x++)
+ {
+ const unsigned xs = stitch(x,fine_x,coarse_x)-x0s;
+ Px[dy0*dwidth+x-x0] = px[xs];
+ Py[dy0*dwidth+x-x0] = py[xs];
+ Pz[dy0*dwidth+x-x0] = pz[xs];
+ U [dy0*dwidth+x-x0] = u[xs];
+ V [dy0*dwidth+x-x0] = v[xs];
+ if (unlikely(has_Nxyz)) {
+ Nx[dy0*dwidth+x-x0] = nx[xs];
+ Ny[dy0*dwidth+x-x0] = ny[xs];
+ Nz[dy0*dwidth+x-x0] = nz[xs];
+ }
+ }
+ return true;
+ }
+
+ template<typename Eval, typename Patch>
+ void feature_adaptive_eval_grid (const Patch& patch, unsigned subPatch, const float levels[4],
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dwidth, const unsigned dheight)
+ {
+ bool sl = false, sr = false, st = false, sb = false;
+ if (levels) {
+ sl = x0 == 0 && stitch_col<Eval,Patch>(patch,subPatch,0,y0,y1,sheight-1,int(levels[3]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
+ sr = x1 == swidth-1 && stitch_col<Eval,Patch>(patch,subPatch,1,y0,y1,sheight-1,int(levels[1]), Px,Py,Pz,U,V,Nx,Ny,Nz, x1-x0,dwidth,dheight);
+ st = y0 == 0 && stitch_row<Eval,Patch>(patch,subPatch,0,x0,x1,swidth-1,int(levels[0]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
+ sb = y1 == sheight-1 && stitch_row<Eval,Patch>(patch,subPatch,1,x0,x1,swidth-1,int(levels[2]), Px,Py,Pz,U,V,Nx,Ny,Nz, y1-y0,dwidth,dheight);
+ }
+ const unsigned ofs = st*dwidth+sl;
+ Eval(patch,subPatch,x0+sl,x1-sr,y0+st,y1-sb, swidth,sheight, Px+ofs,Py+ofs,Pz+ofs,U+ofs,V+ofs,Nx?Nx+ofs:nullptr,Ny?Ny+ofs:nullptr,Nz?Nz+ofs:nullptr, dwidth,dheight);
+ }
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_simd.h b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_simd.h
new file mode 100644
index 0000000000..fa3216730f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/feature_adaptive_eval_simd.h
@@ -0,0 +1,186 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename vbool, typename vint, typename vfloat, typename Vertex, typename Vertex_t = Vertex>
+ struct FeatureAdaptiveEvalSimd
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef BSplinePatchT<Vertex,Vertex_t> BSplinePatch;
+ typedef BezierPatchT<Vertex,Vertex_t> BezierPatch;
+ typedef GregoryPatchT<Vertex,Vertex_t> GregoryPatch;
+ typedef BilinearPatchT<Vertex,Vertex_t> BilinearPatch;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ FeatureAdaptiveEvalSimd (const HalfEdge* edge, const char* vertices, size_t stride, const vbool& valid, const vfloat& u, const vfloat& v,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: BilinearPatch(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: RegularPatchT(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: GregoryPatchT<Vertex,Vertex_t>(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ eval_direct(valid,patch,Vec2<vfloat>(u,v),0);
+ break;
+ }
+ }
+ }
+
+ FeatureAdaptiveEvalSimd (const CatmullClarkPatch& patch, const vbool& valid, const vfloat& u, const vfloat& v, float dscale, size_t depth,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ eval_direct(valid,patch,Vec2<vfloat>(u,v),dscale,depth);
+ }
+
+ template<size_t N>
+ __forceinline void eval_quad_direct(const vbool& valid, array_t<CatmullClarkPatch,N>& patches, const Vec2<vfloat>& uv, float dscale, size_t depth)
+ {
+ const vfloat u = uv.x, v = uv.y;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ }
+
+ template<size_t N>
+ __forceinline void eval_general_quad_direct(const vbool& valid, const GeneralCatmullClarkPatch& patch, array_t<CatmullClarkPatch,N>& patches, const Vec2<vfloat>& uv, float dscale, size_t depth)
+ {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve border3l,border3r; borders[3].subdivide(border3l,border3r);
+#endif
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ const vfloat u = uv.x, v = uv.y;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+#if PATCH_USE_GREGORY == 2
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1,&border0l,nullptr,nullptr,&border3r);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1,&border0r,&border1l,nullptr,nullptr);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1,nullptr,&border1r,&border2l,nullptr);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1,nullptr,nullptr,&border2r,&border3l);
+#else
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1);
+#endif
+ }
+
+ __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const size_t max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ void eval_direct(const vbool& valid, const CatmullClarkPatch& patch, const Vec2<vfloat>& uv, float dscale, size_t depth,
+ BezierCurve* border0 = nullptr, BezierCurve* border1 = nullptr, BezierCurve* border2 = nullptr, BezierCurve* border3 = nullptr)
+ {
+ typename CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ } else {
+ IrregularFillPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0); RegularPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0); GregoryPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches); // FIXME: only have to generate one of the patches
+ eval_quad_direct(valid,patches,uv,dscale,depth);
+ }
+ }
+
+ void eval_direct(const vbool& valid, const GeneralCatmullClarkPatch& patch, const Vec2<vfloat>& uv, const size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch())) {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return eval_direct(valid,qpatch,uv,1.0f,depth);
+ }
+
+ /* subdivide patch */
+ unsigned Nc;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,Nc); // FIXME: only have to generate one of the patches
+
+ /* parametrization for quads */
+ if (Nc == 4)
+ eval_general_quad_direct(valid,patch,patches,uv,1.0f,depth);
+
+ /* parametrization for arbitrary polygons */
+ else
+ {
+ const vint l = (vint)floor(0.5f*uv.x); const vfloat u = 2.0f*frac(0.5f*uv.x)-0.5f;
+ const vint h = (vint)floor(0.5f*uv.y); const vfloat v = 2.0f*frac(0.5f*uv.y)-0.5f;
+ const vint i = (h<<2)+l; assert(all(valid,i<Nc));
+ foreach_unique(valid,i,[&](const vbool& valid, const int i) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,i);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval_direct(valid,patches[i],Vec2<vfloat>(u,v),1.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval_direct(valid,patches[i],Vec2<vfloat>(u,v),1.0f,depth+1);
+#endif
+ });
+ }
+ }
+
+ private:
+ float* const P;
+ float* const dPdu;
+ float* const dPdv;
+ float* const ddPdudu;
+ float* const ddPdvdv;
+ float* const ddPdudv;
+ const size_t dstride;
+ const size_t N;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch.h
new file mode 100644
index 0000000000..2a7c4b1f2c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch.h
@@ -0,0 +1,893 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_patch.h"
+#include "bezier_curve.h"
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) GregoryPatchT
+ {
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ public:
+ Vertex v[4][4];
+ Vertex f[2][2];
+
+ __forceinline GregoryPatchT() {}
+
+ __forceinline GregoryPatchT(const CatmullClarkPatch& patch) {
+ init(patch);
+ }
+
+ __forceinline GregoryPatchT(const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ {
+ init_crackfix(patch,border0,border1,border2,border3);
+ }
+
+ __forceinline GregoryPatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(CatmullClarkPatch(edge,vertices,stride));
+ }
+
+ __forceinline Vertex& p0() { return v[0][0]; }
+ __forceinline Vertex& p1() { return v[0][3]; }
+ __forceinline Vertex& p2() { return v[3][3]; }
+ __forceinline Vertex& p3() { return v[3][0]; }
+
+ __forceinline Vertex& e0_p() { return v[0][1]; }
+ __forceinline Vertex& e0_m() { return v[1][0]; }
+ __forceinline Vertex& e1_p() { return v[1][3]; }
+ __forceinline Vertex& e1_m() { return v[0][2]; }
+ __forceinline Vertex& e2_p() { return v[3][2]; }
+ __forceinline Vertex& e2_m() { return v[2][3]; }
+ __forceinline Vertex& e3_p() { return v[2][0]; }
+ __forceinline Vertex& e3_m() { return v[3][1]; }
+
+ __forceinline Vertex& f0_p() { return v[1][1]; }
+ __forceinline Vertex& f1_p() { return v[1][2]; }
+ __forceinline Vertex& f2_p() { return v[2][2]; }
+ __forceinline Vertex& f3_p() { return v[2][1]; }
+ __forceinline Vertex& f0_m() { return f[0][0]; }
+ __forceinline Vertex& f1_m() { return f[0][1]; }
+ __forceinline Vertex& f2_m() { return f[1][1]; }
+ __forceinline Vertex& f3_m() { return f[1][0]; }
+
+ __forceinline const Vertex& p0() const { return v[0][0]; }
+ __forceinline const Vertex& p1() const { return v[0][3]; }
+ __forceinline const Vertex& p2() const { return v[3][3]; }
+ __forceinline const Vertex& p3() const { return v[3][0]; }
+
+ __forceinline const Vertex& e0_p() const { return v[0][1]; }
+ __forceinline const Vertex& e0_m() const { return v[1][0]; }
+ __forceinline const Vertex& e1_p() const { return v[1][3]; }
+ __forceinline const Vertex& e1_m() const { return v[0][2]; }
+ __forceinline const Vertex& e2_p() const { return v[3][2]; }
+ __forceinline const Vertex& e2_m() const { return v[2][3]; }
+ __forceinline const Vertex& e3_p() const { return v[2][0]; }
+ __forceinline const Vertex& e3_m() const { return v[3][1]; }
+
+ __forceinline const Vertex& f0_p() const { return v[1][1]; }
+ __forceinline const Vertex& f1_p() const { return v[1][2]; }
+ __forceinline const Vertex& f2_p() const { return v[2][2]; }
+ __forceinline const Vertex& f3_p() const { return v[2][1]; }
+ __forceinline const Vertex& f0_m() const { return f[0][0]; }
+ __forceinline const Vertex& f1_m() const { return f[0][1]; }
+ __forceinline const Vertex& f2_m() const { return f[1][1]; }
+ __forceinline const Vertex& f3_m() const { return f[1][0]; }
+
+ __forceinline Vertex initCornerVertex(const CatmullClarkPatch& irreg_patch, const size_t index) {
+ return irreg_patch.ring[index].getLimitVertex();
+ }
+
+ __forceinline Vertex initPositiveEdgeVertex(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx) {
+ return madd(1.0f/3.0f,irreg_patch.ring[index].getLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initNegativeEdgeVertex(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx) {
+ return madd(1.0f/3.0f,irreg_patch.ring[index].getSecondLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initPositiveEdgeVertex2(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx)
+ {
+ CatmullClark1Ring3fa r0,r1,r2;
+ irreg_patch.ring[index].subdivide(r0);
+ r0.subdivide(r1);
+ r1.subdivide(r2);
+ return madd(8.0f/3.0f,r2.getLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initNegativeEdgeVertex2(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx)
+ {
+ CatmullClark1Ring3fa r0,r1,r2;
+ irreg_patch.ring[index].subdivide(r0);
+ r0.subdivide(r1);
+ r1.subdivide(r2);
+ return madd(8.0f/3.0f,r2.getSecondLimitTangent(),p_vtx);
+ }
+
+ void initFaceVertex(const CatmullClarkPatch& irreg_patch,
+ const size_t index,
+ const Vertex& p_vtx,
+ const Vertex& e0_p_vtx,
+ const Vertex& e1_m_vtx,
+ const unsigned int face_valence_p1,
+ const Vertex& e0_m_vtx,
+ const Vertex& e3_p_vtx,
+ const unsigned int face_valence_p3,
+ Vertex& f_p_vtx,
+ Vertex& f_m_vtx)
+ {
+ const unsigned int face_valence = irreg_patch.ring[index].face_valence;
+ const unsigned int edge_valence = irreg_patch.ring[index].edge_valence;
+ const unsigned int border_index = irreg_patch.ring[index].border_index;
+
+ const Vertex& vtx = irreg_patch.ring[index].vtx;
+ const Vertex e_i = irreg_patch.ring[index].getEdgeCenter(0);
+ const Vertex c_i_m_1 = irreg_patch.ring[index].getQuadCenter(0);
+ const Vertex e_i_m_1 = irreg_patch.ring[index].getEdgeCenter(1);
+
+ Vertex c_i, e_i_p_1;
+ const bool hasHardEdge0 =
+ std::isinf(irreg_patch.ring[index].vertex_crease_weight) &&
+ std::isinf(irreg_patch.ring[index].crease_weight[0]);
+
+ if (unlikely((border_index == edge_valence-2) || hasHardEdge0))
+ {
+ /* mirror quad center and edge mid-point */
+ c_i = madd(2.0f, e_i - c_i_m_1, c_i_m_1);
+ e_i_p_1 = madd(2.0f, vtx - e_i_m_1, e_i_m_1);
+ }
+ else
+ {
+ c_i = irreg_patch.ring[index].getQuadCenter( face_valence-1 );
+ e_i_p_1 = irreg_patch.ring[index].getEdgeCenter( face_valence-1 );
+ }
+
+ Vertex c_i_m_2, e_i_m_2;
+ const bool hasHardEdge1 =
+ std::isinf(irreg_patch.ring[index].vertex_crease_weight) &&
+ std::isinf(irreg_patch.ring[index].crease_weight[1]);
+
+ if (unlikely(border_index == 2 || hasHardEdge1))
+ {
+ /* mirror quad center and edge mid-point */
+ c_i_m_2 = madd(2.0f, e_i_m_1 - c_i_m_1, c_i_m_1);
+ e_i_m_2 = madd(2.0f, vtx - e_i, + e_i);
+ }
+ else
+ {
+ c_i_m_2 = irreg_patch.ring[index].getQuadCenter( 1 );
+ e_i_m_2 = irreg_patch.ring[index].getEdgeCenter( 2 );
+ }
+
+ const float d = 3.0f;
+ //const float c = cosf(2.0f*M_PI/(float)face_valence);
+ //const float c_e_p = cosf(2.0f*M_PI/(float)face_valence_p1);
+ //const float c_e_m = cosf(2.0f*M_PI/(float)face_valence_p3);
+
+ const float c = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence);
+ const float c_e_p = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p1);
+ const float c_e_m = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p3);
+
+ const Vertex r_e_p = 1.0f/3.0f * (e_i_m_1 - e_i_p_1) + 2.0f/3.0f * (c_i_m_1 - c_i);
+ const Vertex r_e_m = 1.0f/3.0f * (e_i - e_i_m_2) + 2.0f/3.0f * (c_i_m_1 - c_i_m_2);
+
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ }
+
+ __noinline void init(const CatmullClarkPatch& patch)
+ {
+ assert( patch.ring[0].hasValidPositions() );
+ assert( patch.ring[1].hasValidPositions() );
+ assert( patch.ring[2].hasValidPositions() );
+ assert( patch.ring[3].hasValidPositions() );
+
+ p0() = initCornerVertex(patch,0);
+ p1() = initCornerVertex(patch,1);
+ p2() = initCornerVertex(patch,2);
+ p3() = initCornerVertex(patch,3);
+
+ e0_p() = initPositiveEdgeVertex(patch,0, p0());
+ e1_p() = initPositiveEdgeVertex(patch,1, p1());
+ e2_p() = initPositiveEdgeVertex(patch,2, p2());
+ e3_p() = initPositiveEdgeVertex(patch,3, p3());
+
+ e0_m() = initNegativeEdgeVertex(patch,0, p0());
+ e1_m() = initNegativeEdgeVertex(patch,1, p1());
+ e2_m() = initNegativeEdgeVertex(patch,2, p2());
+ e3_m() = initNegativeEdgeVertex(patch,3, p3());
+
+ const unsigned int face_valence_p0 = patch.ring[0].face_valence;
+ const unsigned int face_valence_p1 = patch.ring[1].face_valence;
+ const unsigned int face_valence_p2 = patch.ring[2].face_valence;
+ const unsigned int face_valence_p3 = patch.ring[3].face_valence;
+
+ initFaceVertex(patch,0,p0(),e0_p(),e1_m(),face_valence_p1,e0_m(),e3_p(),face_valence_p3,f0_p(),f0_m() );
+ initFaceVertex(patch,1,p1(),e1_p(),e2_m(),face_valence_p2,e1_m(),e0_p(),face_valence_p0,f1_p(),f1_m() );
+ initFaceVertex(patch,2,p2(),e2_p(),e3_m(),face_valence_p3,e2_m(),e1_p(),face_valence_p1,f2_p(),f2_m() );
+ initFaceVertex(patch,3,p3(),e3_p(),e0_m(),face_valence_p0,e3_m(),e2_p(),face_valence_p3,f3_p(),f3_m() );
+
+ }
+
+ __noinline void init_crackfix(const CatmullClarkPatch& patch,
+ const BezierCurve* border0,
+ const BezierCurve* border1,
+ const BezierCurve* border2,
+ const BezierCurve* border3)
+ {
+ assert( patch.ring[0].hasValidPositions() );
+ assert( patch.ring[1].hasValidPositions() );
+ assert( patch.ring[2].hasValidPositions() );
+ assert( patch.ring[3].hasValidPositions() );
+
+ p0() = initCornerVertex(patch,0);
+ p1() = initCornerVertex(patch,1);
+ p2() = initCornerVertex(patch,2);
+ p3() = initCornerVertex(patch,3);
+
+ e0_p() = initPositiveEdgeVertex(patch,0, p0());
+ e1_p() = initPositiveEdgeVertex(patch,1, p1());
+ e2_p() = initPositiveEdgeVertex(patch,2, p2());
+ e3_p() = initPositiveEdgeVertex(patch,3, p3());
+
+ e0_m() = initNegativeEdgeVertex(patch,0, p0());
+ e1_m() = initNegativeEdgeVertex(patch,1, p1());
+ e2_m() = initNegativeEdgeVertex(patch,2, p2());
+ e3_m() = initNegativeEdgeVertex(patch,3, p3());
+
+ if (unlikely(border0 != nullptr))
+ {
+ p0() = border0->v0;
+ e0_p() = border0->v1;
+ e1_m() = border0->v2;
+ p1() = border0->v3;
+ }
+
+ if (unlikely(border1 != nullptr))
+ {
+ p1() = border1->v0;
+ e1_p() = border1->v1;
+ e2_m() = border1->v2;
+ p2() = border1->v3;
+ }
+
+ if (unlikely(border2 != nullptr))
+ {
+ p2() = border2->v0;
+ e2_p() = border2->v1;
+ e3_m() = border2->v2;
+ p3() = border2->v3;
+ }
+
+ if (unlikely(border3 != nullptr))
+ {
+ p3() = border3->v0;
+ e3_p() = border3->v1;
+ e0_m() = border3->v2;
+ p0() = border3->v3;
+ }
+
+ const unsigned int face_valence_p0 = patch.ring[0].face_valence;
+ const unsigned int face_valence_p1 = patch.ring[1].face_valence;
+ const unsigned int face_valence_p2 = patch.ring[2].face_valence;
+ const unsigned int face_valence_p3 = patch.ring[3].face_valence;
+
+ initFaceVertex(patch,0,p0(),e0_p(),e1_m(),face_valence_p1,e0_m(),e3_p(),face_valence_p3,f0_p(),f0_m() );
+ initFaceVertex(patch,1,p1(),e1_p(),e2_m(),face_valence_p2,e1_m(),e0_p(),face_valence_p0,f1_p(),f1_m() );
+ initFaceVertex(patch,2,p2(),e2_p(),e3_m(),face_valence_p3,e2_m(),e1_p(),face_valence_p1,f2_p(),f2_m() );
+ initFaceVertex(patch,3,p3(),e3_p(),e0_m(),face_valence_p0,e3_m(),e2_p(),face_valence_p3,f3_p(),f3_m() );
+ }
+
+
+ void computeGregoryPatchFacePoints(const unsigned int face_valence,
+ const Vertex& r_e_p,
+ const Vertex& r_e_m,
+ const Vertex& p_vtx,
+ const Vertex& e0_p_vtx,
+ const Vertex& e1_m_vtx,
+ const unsigned int face_valence_p1,
+ const Vertex& e0_m_vtx,
+ const Vertex& e3_p_vtx,
+ const unsigned int face_valence_p3,
+ Vertex& f_p_vtx,
+ Vertex& f_m_vtx,
+ const float d = 3.0f)
+ {
+ //const float c = cosf(2.0*M_PI/(float)face_valence);
+ //const float c_e_p = cosf(2.0*M_PI/(float)face_valence_p1);
+ //const float c_e_m = cosf(2.0*M_PI/(float)face_valence_p3);
+
+ const float c = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence);
+ const float c_e_p = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p1);
+ const float c_e_m = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p3);
+
+
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ }
+
+ __noinline void init(const GeneralCatmullClarkPatch& patch)
+ {
+ assert(patch.size() == 4);
+#if 0
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ init(qpatch);
+#else
+ const float face_valence_p0 = patch.ring[0].face_valence;
+ const float face_valence_p1 = patch.ring[1].face_valence;
+ const float face_valence_p2 = patch.ring[2].face_valence;
+ const float face_valence_p3 = patch.ring[3].face_valence;
+
+ Vertex p0_r_p, p0_r_m;
+ patch.ring[0].computeGregoryPatchEdgePoints( p0(), e0_p(), e0_m(), p0_r_p, p0_r_m );
+
+ Vertex p1_r_p, p1_r_m;
+ patch.ring[1].computeGregoryPatchEdgePoints( p1(), e1_p(), e1_m(), p1_r_p, p1_r_m );
+
+ Vertex p2_r_p, p2_r_m;
+ patch.ring[2].computeGregoryPatchEdgePoints( p2(), e2_p(), e2_m(), p2_r_p, p2_r_m );
+
+ Vertex p3_r_p, p3_r_m;
+ patch.ring[3].computeGregoryPatchEdgePoints( p3(), e3_p(), e3_m(), p3_r_p, p3_r_m );
+
+ computeGregoryPatchFacePoints(face_valence_p0, p0_r_p, p0_r_m, p0(), e0_p(), e1_m(), face_valence_p1, e0_m(), e3_p(), face_valence_p3, f0_p(), f0_m() );
+ computeGregoryPatchFacePoints(face_valence_p1, p1_r_p, p1_r_m, p1(), e1_p(), e2_m(), face_valence_p2, e1_m(), e0_p(), face_valence_p0, f1_p(), f1_m() );
+ computeGregoryPatchFacePoints(face_valence_p2, p2_r_p, p2_r_m, p2(), e2_p(), e3_m(), face_valence_p3, e2_m(), e1_p(), face_valence_p1, f2_p(), f2_m() );
+ computeGregoryPatchFacePoints(face_valence_p3, p3_r_p, p3_r_m, p3(), e3_p(), e0_m(), face_valence_p0, e3_m(), e2_p(), face_valence_p3, f3_p(), f3_m() );
+
+#endif
+ }
+
+
+ __forceinline void convert_to_bezier()
+ {
+ f0_p() = (f0_p() + f0_m()) * 0.5f;
+ f1_p() = (f1_p() + f1_m()) * 0.5f;
+ f2_p() = (f2_p() + f2_m()) * 0.5f;
+ f3_p() = (f3_p() + f3_m()) * 0.5f;
+ f0_m() = Vertex( zero );
+ f1_m() = Vertex( zero );
+ f2_m() = Vertex( zero );
+ f3_m() = Vertex( zero );
+ }
+
+ static __forceinline void computeInnerVertices(const Vertex matrix[4][4], const Vertex f_m[2][2], const float uu, const float vv,
+ Vertex_t& matrix_11, Vertex_t& matrix_12, Vertex_t& matrix_22, Vertex_t& matrix_21)
+ {
+ if (unlikely(uu == 0.0f || uu == 1.0f || vv == 0.0f || vv == 1.0f))
+ {
+ matrix_11 = matrix[1][1];
+ matrix_12 = matrix[1][2];
+ matrix_22 = matrix[2][2];
+ matrix_21 = matrix[2][1];
+ }
+ else
+ {
+ const Vertex_t f0_p = matrix[1][1];
+ const Vertex_t f1_p = matrix[1][2];
+ const Vertex_t f2_p = matrix[2][2];
+ const Vertex_t f3_p = matrix[2][1];
+
+ const Vertex_t f0_m = f_m[0][0];
+ const Vertex_t f1_m = f_m[0][1];
+ const Vertex_t f2_m = f_m[1][1];
+ const Vertex_t f3_m = f_m[1][0];
+
+ matrix_11 = ( uu * f0_p + vv * f0_m)*rcp(uu+vv);
+ matrix_12 = ((1.0f-uu) * f1_m + vv * f1_p)*rcp(1.0f-uu+vv);
+ matrix_22 = ((1.0f-uu) * f2_p + (1.0f-vv) * f2_m)*rcp(2.0f-uu-vv);
+ matrix_21 = ( uu * f3_m + (1.0f-vv) * f3_p)*rcp(1.0f+uu-vv);
+ }
+ }
+
+ template<typename vfloat>
+ static __forceinline void computeInnerVertices(const Vertex v[4][4], const Vertex f[2][2],
+ size_t i, const vfloat& uu, const vfloat& vv, vfloat& matrix_11, vfloat& matrix_12, vfloat& matrix_22, vfloat& matrix_21)
+ {
+ const auto m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+
+ const vfloat f0_p = v[1][1][i];
+ const vfloat f1_p = v[1][2][i];
+ const vfloat f2_p = v[2][2][i];
+ const vfloat f3_p = v[2][1][i];
+
+ const vfloat f0_m = f[0][0][i];
+ const vfloat f1_m = f[0][1][i];
+ const vfloat f2_m = f[1][1][i];
+ const vfloat f3_m = f[1][0][i];
+
+ const vfloat one_minus_uu = vfloat(1.0f) - uu;
+ const vfloat one_minus_vv = vfloat(1.0f) - vv;
+
+ const vfloat f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const vfloat f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const vfloat f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const vfloat f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+ matrix_11 = select(m_border,f0_p,f0_i);
+ matrix_12 = select(m_border,f1_p,f1_i);
+ matrix_22 = select(m_border,f2_p,f2_i);
+ matrix_21 = select(m_border,f3_p,f3_i);
+ }
+
+ static __forceinline Vertex eval(const Vertex matrix[4][4], const Vertex f[2][2], const float& uu, const float& vv)
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_du(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::derivative(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dudu(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative2(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dvdv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::derivative2(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dudv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative(uu);
+ const Vec4<float> Bv = BezierBasis::derivative(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const {
+ return eval(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_du( const float uu, const float vv) const {
+ return eval_du(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dv( const float uu, const float vv) const {
+ return eval_dv(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dudu( const float uu, const float vv) const {
+ return eval_dudu(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dvdv( const float uu, const float vv) const {
+ return eval_dvdv(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dudv( const float uu, const float vv) const {
+ return eval_dudv(v,f,uu,vv);
+ }
+
+ static __forceinline Vertex normal(const Vertex matrix[4][4], const Vertex f_m[2][2], const float uu, const float vv) // FIXME: why not using basis functions
+ {
+ /* interpolate inner vertices */
+ Vertex_t matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(matrix,f_m,uu,vv,matrix_11, matrix_12, matrix_22, matrix_21);
+
+ /* tangentU */
+ const Vertex_t col0 = deCasteljau(vv, (Vertex_t)matrix[0][0], (Vertex_t)matrix[1][0], (Vertex_t)matrix[2][0], (Vertex_t)matrix[3][0]);
+ const Vertex_t col1 = deCasteljau(vv, (Vertex_t)matrix[0][1], (Vertex_t)matrix_11 , (Vertex_t)matrix_21 , (Vertex_t)matrix[3][1]);
+ const Vertex_t col2 = deCasteljau(vv, (Vertex_t)matrix[0][2], (Vertex_t)matrix_12 , (Vertex_t)matrix_22 , (Vertex_t)matrix[3][2]);
+ const Vertex_t col3 = deCasteljau(vv, (Vertex_t)matrix[0][3], (Vertex_t)matrix[1][3], (Vertex_t)matrix[2][3], (Vertex_t)matrix[3][3]);
+
+ const Vertex_t tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vertex_t row0 = deCasteljau(uu, (Vertex_t)matrix[0][0], (Vertex_t)matrix[0][1], (Vertex_t)matrix[0][2], (Vertex_t)matrix[0][3]);
+ const Vertex_t row1 = deCasteljau(uu, (Vertex_t)matrix[1][0], (Vertex_t)matrix_11 , (Vertex_t)matrix_12 , (Vertex_t)matrix[1][3]);
+ const Vertex_t row2 = deCasteljau(uu, (Vertex_t)matrix[2][0], (Vertex_t)matrix_21 , (Vertex_t)matrix_22 , (Vertex_t)matrix[2][3]);
+ const Vertex_t row3 = deCasteljau(uu, (Vertex_t)matrix[3][0], (Vertex_t)matrix[3][1], (Vertex_t)matrix[3][2], (Vertex_t)matrix[3][3]);
+
+ const Vertex_t tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vertex_t n = cross(tangentU,tangentV);
+
+ return n;
+ }
+
+ __forceinline Vertex normal( const float uu, const float vv) const {
+ return normal(v,f,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv,
+ Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ static __forceinline vfloat eval(const Vertex v[4][4], const Vertex f[2][2],
+ const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n,
+ vfloat& matrix_11, vfloat& matrix_12, vfloat& matrix_22, vfloat& matrix_21)
+ {
+ const vfloat curve0_x = madd(v_n[0],vfloat(v[0][0][i]),madd(v_n[1],vfloat(v[1][0][i]),madd(v_n[2],vfloat(v[2][0][i]),v_n[3] * vfloat(v[3][0][i]))));
+ const vfloat curve1_x = madd(v_n[0],vfloat(v[0][1][i]),madd(v_n[1],vfloat(matrix_11 ),madd(v_n[2],vfloat(matrix_21 ),v_n[3] * vfloat(v[3][1][i]))));
+ const vfloat curve2_x = madd(v_n[0],vfloat(v[0][2][i]),madd(v_n[1],vfloat(matrix_12 ),madd(v_n[2],vfloat(matrix_22 ),v_n[3] * vfloat(v[3][2][i]))));
+ const vfloat curve3_x = madd(v_n[0],vfloat(v[0][3][i]),madd(v_n[1],vfloat(v[1][3][i]),madd(v_n[2],vfloat(v[2][3][i]),v_n[3] * vfloat(v[3][3][i]))));
+ return madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+ }
+
+ template<typename vbool, typename vfloat>
+ static __forceinline void eval(const Vertex v[4][4], const Vertex f[2][2],
+ const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N)
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,P+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21));
+ }
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,dPdu+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*dscale);
+ }
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,dPdv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*dscale);
+ }
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdudu+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdvdv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdudv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ }
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const {
+ eval(v,f,valid,uu,vv,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> eval_t(const Vertex matrix[4][4], const Vec3<T> f[2][2], const T& uu, const T& vv)
+ {
+ typedef typename T::Bool M;
+ const M m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+
+ const Vec3<T> f0_p = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> f1_p = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> f2_p = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> f3_p = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+
+ const Vec3<T> f0_m = f[0][0];
+ const Vec3<T> f1_m = f[0][1];
+ const Vec3<T> f2_m = f[1][1];
+ const Vec3<T> f3_m = f[1][0];
+
+ const T one_minus_uu = T(1.0f) - uu;
+ const T one_minus_vv = T(1.0f) - vv;
+
+ const Vec3<T> f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const Vec3<T> f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const Vec3<T> f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const Vec3<T> f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+ const Vec3<T> F0( select(m_border,f0_p.x,f0_i.x), select(m_border,f0_p.y,f0_i.y), select(m_border,f0_p.z,f0_i.z) );
+ const Vec3<T> F1( select(m_border,f1_p.x,f1_i.x), select(m_border,f1_p.y,f1_i.y), select(m_border,f1_p.z,f1_i.z) );
+ const Vec3<T> F2( select(m_border,f2_p.x,f2_i.x), select(m_border,f2_p.y,f2_i.y), select(m_border,f2_p.z,f2_i.z) );
+ const Vec3<T> F3( select(m_border,f3_p.x,f3_i.x), select(m_border,f3_p.y,f3_i.y), select(m_border,f3_p.z,f3_i.z) );
+
+ const T B0_u = one_minus_uu * one_minus_uu * one_minus_uu;
+ const T B0_v = one_minus_vv * one_minus_vv * one_minus_vv;
+ const T B1_u = 3.0f * (one_minus_uu * uu * one_minus_uu);
+ const T B1_v = 3.0f * (one_minus_vv * vv * one_minus_vv);
+ const T B2_u = 3.0f * (uu * one_minus_uu * uu);
+ const T B2_v = 3.0f * (vv * one_minus_vv * vv);
+ const T B3_u = uu * uu * uu;
+ const T B3_v = vv * vv * vv;
+
+ const T x = madd(B0_v,madd(B0_u,matrix[0][0].x,madd(B1_u,matrix[0][1].x,madd(B2_u,matrix[0][2].x,B3_u * matrix[0][3].x))),
+ madd(B1_v,madd(B0_u,matrix[1][0].x,madd(B1_u,F0.x ,madd(B2_u,F1.x ,B3_u * matrix[1][3].x))),
+ madd(B2_v,madd(B0_u,matrix[2][0].x,madd(B1_u,F3.x ,madd(B2_u,F2.x ,B3_u * matrix[2][3].x))),
+ B3_v*madd(B0_u,matrix[3][0].x,madd(B1_u,matrix[3][1].x,madd(B2_u,matrix[3][2].x,B3_u * matrix[3][3].x))))));
+
+ const T y = madd(B0_v,madd(B0_u,matrix[0][0].y,madd(B1_u,matrix[0][1].y,madd(B2_u,matrix[0][2].y,B3_u * matrix[0][3].y))),
+ madd(B1_v,madd(B0_u,matrix[1][0].y,madd(B1_u,F0.y ,madd(B2_u,F1.y ,B3_u * matrix[1][3].y))),
+ madd(B2_v,madd(B0_u,matrix[2][0].y,madd(B1_u,F3.y ,madd(B2_u,F2.y ,B3_u * matrix[2][3].y))),
+ B3_v*madd(B0_u,matrix[3][0].y,madd(B1_u,matrix[3][1].y,madd(B2_u,matrix[3][2].y,B3_u * matrix[3][3].y))))));
+
+ const T z = madd(B0_v,madd(B0_u,matrix[0][0].z,madd(B1_u,matrix[0][1].z,madd(B2_u,matrix[0][2].z,B3_u * matrix[0][3].z))),
+ madd(B1_v,madd(B0_u,matrix[1][0].z,madd(B1_u,F0.z ,madd(B2_u,F1.z ,B3_u * matrix[1][3].z))),
+ madd(B2_v,madd(B0_u,matrix[2][0].z,madd(B1_u,F3.z ,madd(B2_u,F2.z ,B3_u * matrix[2][3].z))),
+ B3_v*madd(B0_u,matrix[3][0].z,madd(B1_u,matrix[3][1].z,madd(B2_u,matrix[3][2].z,B3_u * matrix[3][3].z))))));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv) const
+ {
+ Vec3<T> ff[2][2];
+ ff[0][0] = Vec3<T>(f[0][0]);
+ ff[0][1] = Vec3<T>(f[0][1]);
+ ff[1][1] = Vec3<T>(f[1][1]);
+ ff[1][0] = Vec3<T>(f[1][0]);
+ return eval_t(v,ff,uu,vv);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> normal_t(const Vertex matrix[4][4], const Vec3<T> f[2][2], const T& uu, const T& vv)
+ {
+ typedef typename T::Bool M;
+
+ const Vec3<T> f0_p = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> f1_p = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> f2_p = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> f3_p = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+
+ const Vec3<T> f0_m = f[0][0];
+ const Vec3<T> f1_m = f[0][1];
+ const Vec3<T> f2_m = f[1][1];
+ const Vec3<T> f3_m = f[1][0];
+
+ const T one_minus_uu = T(1.0f) - uu;
+ const T one_minus_vv = T(1.0f) - vv;
+
+ const Vec3<T> f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const Vec3<T> f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const Vec3<T> f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const Vec3<T> f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+#if 1
+ const M m_corner0 = (uu == 0.0f) & (vv == 0.0f);
+ const M m_corner1 = (uu == 1.0f) & (vv == 0.0f);
+ const M m_corner2 = (uu == 1.0f) & (vv == 1.0f);
+ const M m_corner3 = (uu == 0.0f) & (vv == 1.0f);
+ const Vec3<T> matrix_11( select(m_corner0,f0_p.x,f0_i.x), select(m_corner0,f0_p.y,f0_i.y), select(m_corner0,f0_p.z,f0_i.z) );
+ const Vec3<T> matrix_12( select(m_corner1,f1_p.x,f1_i.x), select(m_corner1,f1_p.y,f1_i.y), select(m_corner1,f1_p.z,f1_i.z) );
+ const Vec3<T> matrix_22( select(m_corner2,f2_p.x,f2_i.x), select(m_corner2,f2_p.y,f2_i.y), select(m_corner2,f2_p.z,f2_i.z) );
+ const Vec3<T> matrix_21( select(m_corner3,f3_p.x,f3_i.x), select(m_corner3,f3_p.y,f3_i.y), select(m_corner3,f3_p.z,f3_i.z) );
+#else
+ const M m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+ const Vec3<T> matrix_11( select(m_border,f0_p.x,f0_i.x), select(m_border,f0_p.y,f0_i.y), select(m_border,f0_p.z,f0_i.z) );
+ const Vec3<T> matrix_12( select(m_border,f1_p.x,f1_i.x), select(m_border,f1_p.y,f1_i.y), select(m_border,f1_p.z,f1_i.z) );
+ const Vec3<T> matrix_22( select(m_border,f2_p.x,f2_i.x), select(m_border,f2_p.y,f2_i.y), select(m_border,f2_p.z,f2_i.z) );
+ const Vec3<T> matrix_21( select(m_border,f3_p.x,f3_i.x), select(m_border,f3_p.y,f3_i.y), select(m_border,f3_p.z,f3_i.z) );
+#endif
+
+ const Vec3<T> matrix_00 = Vec3<T>(matrix[0][0].x,matrix[0][0].y,matrix[0][0].z);
+ const Vec3<T> matrix_10 = Vec3<T>(matrix[1][0].x,matrix[1][0].y,matrix[1][0].z);
+ const Vec3<T> matrix_20 = Vec3<T>(matrix[2][0].x,matrix[2][0].y,matrix[2][0].z);
+ const Vec3<T> matrix_30 = Vec3<T>(matrix[3][0].x,matrix[3][0].y,matrix[3][0].z);
+
+ const Vec3<T> matrix_01 = Vec3<T>(matrix[0][1].x,matrix[0][1].y,matrix[0][1].z);
+ const Vec3<T> matrix_02 = Vec3<T>(matrix[0][2].x,matrix[0][2].y,matrix[0][2].z);
+ const Vec3<T> matrix_03 = Vec3<T>(matrix[0][3].x,matrix[0][3].y,matrix[0][3].z);
+
+ const Vec3<T> matrix_31 = Vec3<T>(matrix[3][1].x,matrix[3][1].y,matrix[3][1].z);
+ const Vec3<T> matrix_32 = Vec3<T>(matrix[3][2].x,matrix[3][2].y,matrix[3][2].z);
+ const Vec3<T> matrix_33 = Vec3<T>(matrix[3][3].x,matrix[3][3].y,matrix[3][3].z);
+
+ const Vec3<T> matrix_13 = Vec3<T>(matrix[1][3].x,matrix[1][3].y,matrix[1][3].z);
+ const Vec3<T> matrix_23 = Vec3<T>(matrix[2][3].x,matrix[2][3].y,matrix[2][3].z);
+
+ /* tangentU */
+ const Vec3<T> col0 = deCasteljau(vv, matrix_00, matrix_10, matrix_20, matrix_30);
+ const Vec3<T> col1 = deCasteljau(vv, matrix_01, matrix_11, matrix_21, matrix_31);
+ const Vec3<T> col2 = deCasteljau(vv, matrix_02, matrix_12, matrix_22, matrix_32);
+ const Vec3<T> col3 = deCasteljau(vv, matrix_03, matrix_13, matrix_23, matrix_33);
+
+ const Vec3<T> tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vec3<T> row0 = deCasteljau(uu, matrix_00, matrix_01, matrix_02, matrix_03);
+ const Vec3<T> row1 = deCasteljau(uu, matrix_10, matrix_11, matrix_12, matrix_13);
+ const Vec3<T> row2 = deCasteljau(uu, matrix_20, matrix_21, matrix_22, matrix_23);
+ const Vec3<T> row3 = deCasteljau(uu, matrix_30, matrix_31, matrix_32, matrix_33);
+
+ const Vec3<T> tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vec3<T> n = cross(tangentU,tangentV);
+ return n;
+ }
+
+ template<class T>
+ __forceinline Vec3<T> normal(const T& uu, const T& vv) const
+ {
+ Vec3<T> ff[2][2];
+ ff[0][0] = Vec3<T>(f[0][0]);
+ ff[0][1] = Vec3<T>(f[0][1]);
+ ff[1][1] = Vec3<T>(f[1][1]);
+ ff[1][0] = Vec3<T>(f[1][0]);
+ return normal_t(v,ff,uu,vv);
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+ const Vertex *const cv = &v[0][0];
+ BBox<Vertex> bounds (cv[0]);
+ for (size_t i=1; i<16; i++)
+ bounds.extend( cv[i] );
+ bounds.extend(f[0][0]);
+ bounds.extend(f[1][0]);
+ bounds.extend(f[1][1]);
+ bounds.extend(f[1][1]);
+ return bounds;
+ }
+
+ friend embree_ostream operator<<(embree_ostream o, const GregoryPatchT& p)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ o << "v[" << y << "][" << x << "] " << p.v[y][x] << embree_endl;
+
+ for (size_t y=0; y<2; y++)
+ for (size_t x=0; x<2; x++)
+ o << "f[" << y << "][" << x << "] " << p.f[y][x] << embree_endl;
+ return o;
+ }
+ };
+
+ typedef GregoryPatchT<Vec3fa,Vec3fa_t> GregoryPatch3fa;
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT (const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ CatmullClarkPatchT<Vertex,Vertex_t> patch(edge,vertices,stride);
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch)
+ {
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3)
+ {
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch,border0,border1,border2,border3);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch_dense.h b/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch_dense.h
new file mode 100644
index 0000000000..85effd02cf
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/gregory_patch_dense.h
@@ -0,0 +1,113 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "gregory_patch.h"
+
+namespace embree
+{
+ class __aligned(64) DenseGregoryPatch3fa
+ {
+ typedef Vec3fa Vec3fa_4x4[4][4];
+ public:
+
+ __forceinline DenseGregoryPatch3fa (const GregoryPatch3fa& patch)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = Vec3ff(patch.v[y][x], 0.0f);
+
+ matrix[0][0].w = patch.f[0][0].x;
+ matrix[0][1].w = patch.f[0][0].y;
+ matrix[0][2].w = patch.f[0][0].z;
+ matrix[0][3].w = 0.0f;
+
+ matrix[1][0].w = patch.f[0][1].x;
+ matrix[1][1].w = patch.f[0][1].y;
+ matrix[1][2].w = patch.f[0][1].z;
+ matrix[1][3].w = 0.0f;
+
+ matrix[2][0].w = patch.f[1][1].x;
+ matrix[2][1].w = patch.f[1][1].y;
+ matrix[2][2].w = patch.f[1][1].z;
+ matrix[2][3].w = 0.0f;
+
+ matrix[3][0].w = patch.f[1][0].x;
+ matrix[3][1].w = patch.f[1][0].y;
+ matrix[3][2].w = patch.f[1][0].z;
+ matrix[3][3].w = 0.0f;
+ }
+
+ __forceinline void extract_f_m(Vec3fa f_m[2][2]) const
+ {
+ f_m[0][0] = Vec3fa( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3fa( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3fa( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3fa( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ }
+
+ __forceinline Vec3fa eval(const float uu, const float vv) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ return GregoryPatch3fa::eval(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ __forceinline Vec3fa normal(const float uu, const float vv) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ return GregoryPatch3fa::normal(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> eval(const T &uu, const T &vv) const
+ {
+ Vec3<T> f_m[2][2];
+ f_m[0][0] = Vec3<T>( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3<T>( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3<T>( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3<T>( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ return GregoryPatch3fa::eval_t(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> normal(const T &uu, const T &vv) const
+ {
+ Vec3<T> f_m[2][2];
+ f_m[0][0] = Vec3<T>( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3<T>( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3<T>( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3<T>( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ return GregoryPatch3fa::normal_t(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vec3fa* P, Vec3fa* dPdu, Vec3fa* dPdv, Vec3fa* ddPdudu, Vec3fa* ddPdvdv, Vec3fa* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ if (P) {
+ *P = GregoryPatch3fa::eval(*(Vec3fa_4x4*)&matrix,f_m,u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = GregoryPatch3fa::eval_du(*(Vec3fa_4x4*)&matrix,f_m,u,v)*dscale;
+ assert(dPdv); *dPdv = GregoryPatch3fa::eval_dv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = GregoryPatch3fa::eval_dudu(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = GregoryPatch3fa::eval_dvdv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = GregoryPatch3fa::eval_dudv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ }
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv, float* P, float* dPdu, float* dPdv, const float dscale, const size_t dstride, const size_t N) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ GregoryPatch3fa::eval(matrix,f_m,valid,uu,vv,P,dPdu,dPdv,dscale,dstride,N);
+ }
+
+ private:
+ Vec3ff matrix[4][4]; // f_p/m points are stored in 4th component
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/gridrange.h b/thirdparty/embree-aarch64/kernels/subdiv/gridrange.h
new file mode 100644
index 0000000000..4fd741c879
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/gridrange.h
@@ -0,0 +1,96 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+
+namespace embree
+{
+ struct __aligned(16) GridRange
+ {
+ unsigned int u_start;
+ unsigned int u_end;
+ unsigned int v_start;
+ unsigned int v_end;
+
+ __forceinline GridRange() {}
+
+ __forceinline GridRange(unsigned int u_start, unsigned int u_end, unsigned int v_start, unsigned int v_end)
+ : u_start(u_start), u_end(u_end), v_start(v_start), v_end(v_end) {}
+
+ __forceinline unsigned int width() const {
+ return u_end-u_start+1;
+ }
+
+ __forceinline unsigned int height() const {
+ return v_end-v_start+1;
+ }
+
+ __forceinline bool hasLeafSize() const
+ {
+ const unsigned int u_size = u_end-u_start+1;
+ const unsigned int v_size = v_end-v_start+1;
+ assert(u_size >= 1);
+ assert(v_size >= 1);
+ return u_size <= 3 && v_size <= 3;
+ }
+
+ static __forceinline unsigned int split(unsigned int start,unsigned int end)
+ {
+ const unsigned int center = (start+end)/2;
+ assert (center > start);
+ assert (center < end);
+ return center;
+ }
+
+ __forceinline void split(GridRange& r0, GridRange& r1) const
+ {
+ assert( hasLeafSize() == false );
+ const unsigned int u_size = u_end-u_start+1;
+ const unsigned int v_size = v_end-v_start+1;
+ r0 = *this;
+ r1 = *this;
+
+ if (u_size >= v_size)
+ {
+ const unsigned int u_mid = split(u_start,u_end);
+ r0.u_end = u_mid;
+ r1.u_start = u_mid;
+ }
+ else
+ {
+ const unsigned int v_mid = split(v_start,v_end);
+ r0.v_end = v_mid;
+ r1.v_start = v_mid;
+ }
+ }
+
+ __forceinline unsigned int splitIntoSubRanges(GridRange r[4]) const
+ {
+ assert( !hasLeafSize() );
+ unsigned int children = 0;
+ GridRange first,second;
+ split(first,second);
+
+ if (first.hasLeafSize()) {
+ r[0] = first;
+ children++;
+ }
+ else {
+ first.split(r[0],r[1]);
+ children += 2;
+ }
+
+ if (second.hasLeafSize()) {
+ r[children] = second;
+ children++;
+ }
+ else {
+ second.split(r[children+0],r[children+1]);
+ children += 2;
+ }
+ return children;
+ }
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/half_edge.h b/thirdparty/embree-aarch64/kernels/subdiv/half_edge.h
new file mode 100644
index 0000000000..fb350ca71f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/half_edge.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ class __aligned(32) HalfEdge
+ {
+ friend class SubdivMesh;
+ public:
+
+ enum PatchType : char {
+ BILINEAR_PATCH = 0, //!< a bilinear patch
+ REGULAR_QUAD_PATCH = 1, //!< a regular quad patch can be represented as a B-Spline
+ IRREGULAR_QUAD_PATCH = 2, //!< an irregular quad patch can be represented as a Gregory patch
+ COMPLEX_PATCH = 3 //!< these patches need subdivision and cannot be processed by the above fast code paths
+ };
+
+ enum VertexType : char {
+ REGULAR_VERTEX = 0, //!< regular vertex
+ NON_MANIFOLD_EDGE_VERTEX = 1, //!< vertex of a non-manifold edge
+ };
+
+ __forceinline friend PatchType max( const PatchType& ty0, const PatchType& ty1) {
+ return (PatchType) max((int)ty0,(int)ty1);
+ }
+
+ struct Edge
+ {
+ /*! edge constructor */
+ __forceinline Edge(const uint32_t v0, const uint32_t v1)
+ : v0(v0), v1(v1) {}
+
+ /*! create an 64 bit identifier that is unique for the not oriented edge */
+ __forceinline operator uint64_t() const
+ {
+ uint32_t p0 = v0, p1 = v1;
+ if (p0<p1) std::swap(p0,p1);
+ return (((uint64_t)p0) << 32) | (uint64_t)p1;
+ }
+
+ public:
+ uint32_t v0,v1; //!< start and end vertex of the edge
+ };
+
+ HalfEdge ()
+ : vtx_index(-1), next_half_edge_ofs(0), prev_half_edge_ofs(0), opposite_half_edge_ofs(0), edge_crease_weight(0),
+ vertex_crease_weight(0), edge_level(0), patch_type(COMPLEX_PATCH), vertex_type(REGULAR_VERTEX)
+ {
+ static_assert(sizeof(HalfEdge) == 32, "invalid half edge size");
+ }
+
+ __forceinline bool hasOpposite() const { return opposite_half_edge_ofs != 0; }
+ __forceinline void setOpposite(HalfEdge* opposite) { opposite_half_edge_ofs = int(opposite-this); }
+
+ __forceinline HalfEdge* next() { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
+ __forceinline const HalfEdge* next() const { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
+
+ __forceinline HalfEdge* prev() { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
+ __forceinline const HalfEdge* prev() const { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
+
+ __forceinline HalfEdge* opposite() { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
+ __forceinline const HalfEdge* opposite() const { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
+
+ __forceinline HalfEdge* rotate() { return opposite()->next(); }
+ __forceinline const HalfEdge* rotate() const { return opposite()->next(); }
+
+ __forceinline unsigned int getStartVertexIndex() const { return vtx_index; }
+ __forceinline unsigned int getEndVertexIndex () const { return next()->vtx_index; }
+ __forceinline Edge getEdge () const { return Edge(getStartVertexIndex(),getEndVertexIndex()); }
+
+
+ /*! tests if the start vertex of the edge is regular */
+ __forceinline PatchType vertexType() const
+ {
+ const HalfEdge* p = this;
+ size_t face_valence = 0;
+ bool hasBorder = false;
+
+ do
+ {
+ /* we need subdivision to handle edge creases */
+ if (p->hasOpposite() && p->edge_crease_weight > 0.0f)
+ return COMPLEX_PATCH;
+
+ face_valence++;
+
+ /* test for quad */
+ const HalfEdge* pp = p;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp != p) return COMPLEX_PATCH;
+
+ /* continue with next face */
+ p = p->prev();
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ face_valence++;
+ hasBorder = true;
+ p = this;
+ while (p->hasOpposite())
+ p = p->rotate();
+ }
+ } while (p != this);
+
+ /* calculate vertex type */
+ if (face_valence == 2 && hasBorder) {
+ if (vertex_crease_weight == 0.0f ) return REGULAR_QUAD_PATCH;
+ else if (vertex_crease_weight == float(inf)) return REGULAR_QUAD_PATCH;
+ else return COMPLEX_PATCH;
+ }
+ else if (vertex_crease_weight != 0.0f) return COMPLEX_PATCH;
+ else if (face_valence == 3 && hasBorder) return REGULAR_QUAD_PATCH;
+ else if (face_valence == 4 && !hasBorder) return REGULAR_QUAD_PATCH;
+ else return IRREGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if this edge is part of a bilinear patch */
+ __forceinline bool bilinearVertex() const {
+ return vertex_crease_weight == float(inf) && edge_crease_weight == float(inf);
+ }
+
+ /*! calculates the type of the patch */
+ __forceinline PatchType patchType() const
+ {
+ const HalfEdge* p = this;
+ PatchType ret = REGULAR_QUAD_PATCH;
+ bool bilinear = true;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) != this) return COMPLEX_PATCH;
+
+ if (bilinear) return BILINEAR_PATCH;
+ return ret;
+ }
+
+ /*! tests if the face is a regular b-spline face */
+ __forceinline bool isRegularFace() const {
+ return patch_type == REGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if the face can be diced (using bspline or gregory patch) */
+ __forceinline bool isGregoryFace() const {
+ return patch_type == IRREGULAR_QUAD_PATCH || patch_type == REGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if the base vertex of this half edge is a corner vertex */
+ __forceinline bool isCorner() const {
+ return !hasOpposite() && !prev()->hasOpposite();
+ }
+
+ /*! tests if the vertex is attached to any border */
+ __forceinline bool vertexHasBorder() const
+ {
+ const HalfEdge* p = this;
+ do {
+ if (!p->hasOpposite()) return true;
+ p = p->rotate();
+ } while (p != this);
+ return false;
+ }
+
+ /*! tests if the face this half edge belongs to has some border */
+ __forceinline bool faceHasBorder() const
+ {
+ const HalfEdge* p = this;
+ do {
+ if (p->vertexHasBorder()) return true;
+ p = p->next();
+ } while (p != this);
+ return false;
+ }
+
+ /*! calculates conservative bounds of a catmull clark subdivision face */
+ __forceinline BBox3fa bounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa bounds = this->get1RingBounds(vertices);
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next())
+ bounds.extend(p->get1RingBounds(vertices));
+ return bounds;
+ }
+
+ /*! tests if this is a valid patch */
+ __forceinline bool valid(const BufferView<Vec3fa>& vertices) const
+ {
+ size_t N = 1;
+ if (!this->validRing(vertices)) return false;
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++) {
+ if (!p->validRing(vertices)) return false;
+ }
+ return N >= 3 && N <= MAX_PATCH_VALENCE;
+ }
+
+ /*! counts number of polygon edges */
+ __forceinline unsigned int numEdges() const
+ {
+ unsigned int N = 1;
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++);
+ return N;
+ }
+
+ /*! calculates face and edge valence */
+ __forceinline void calculateFaceValenceAndEdgeValence(size_t& faceValence, size_t& edgeValence) const
+ {
+ faceValence = 0;
+ edgeValence = 0;
+
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ unsigned int numEdges = p->numEdges();
+ assert(numEdges >= 3);
+ edgeValence += numEdges-2;
+
+ faceValence++;
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ faceValence++;
+ edgeValence++;
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+ }
+
+ /*! stream output */
+ friend __forceinline std::ostream &operator<<(std::ostream &o, const HalfEdge &h)
+ {
+ return o << "{ " <<
+ "vertex = " << h.vtx_index << ", " << //" -> " << h.next()->vtx_index << ", " <<
+ "prev = " << h.prev_half_edge_ofs << ", " <<
+ "next = " << h.next_half_edge_ofs << ", " <<
+ "opposite = " << h.opposite_half_edge_ofs << ", " <<
+ "edge_crease = " << h.edge_crease_weight << ", " <<
+ "vertex_crease = " << h.vertex_crease_weight << ", " <<
+ //"edge_level = " << h.edge_level <<
+ " }";
+ }
+
+ private:
+
+ /*! calculates the bounds of the face associated with the half-edge */
+ __forceinline BBox3fa getFaceBounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa b = vertices[getStartVertexIndex()];
+ for (const HalfEdge* p = next(); p!=this; p=p->next()) {
+ b.extend(vertices[p->getStartVertexIndex()]);
+ }
+ return b;
+ }
+
+ /*! calculates the bounds of the 1-ring associated with the vertex of the half-edge */
+ __forceinline BBox3fa get1RingBounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa bounds = empty;
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ bounds.extend(p->getFaceBounds(vertices));
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+
+ return bounds;
+ }
+
+ /*! tests if this is a valid face */
+ __forceinline bool validFace(const BufferView<Vec3fa>& vertices, size_t& N) const
+ {
+ const Vec3fa v = vertices[getStartVertexIndex()];
+ if (!isvalid(v)) return false;
+ size_t n = 1;
+ for (const HalfEdge* p = next(); p!=this; p=p->next(), n++) {
+ const Vec3fa v = vertices[p->getStartVertexIndex()];
+ if (!isvalid(v)) return false;
+ }
+ N += n-2;
+ return n >= 3 && n <= MAX_PATCH_VALENCE;
+ }
+
+ /*! tests if this is a valid ring */
+ __forceinline bool validRing(const BufferView<Vec3fa>& vertices) const
+ {
+ size_t faceValence = 0;
+ size_t edgeValence = 0;
+
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ if (!p->validFace(vertices,edgeValence))
+ return false;
+
+ faceValence++;
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ faceValence++;
+ edgeValence++;
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+
+ return faceValence <= MAX_RING_FACE_VALENCE && edgeValence <= MAX_RING_EDGE_VALENCE;
+ }
+
+ private:
+ unsigned int vtx_index; //!< index of edge start vertex
+ int next_half_edge_ofs; //!< relative offset to next half edge of face
+ int prev_half_edge_ofs; //!< relative offset to previous half edge of face
+ int opposite_half_edge_ofs; //!< relative offset to opposite half edge
+
+ public:
+ float edge_crease_weight; //!< crease weight attached to edge
+ float vertex_crease_weight; //!< crease weight attached to start vertex
+ float edge_level; //!< subdivision factor for edge
+ PatchType patch_type; //!< stores type of subdiv patch
+ VertexType vertex_type; //!< stores type of the start vertex
+ char align[2];
+ };
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/hermite_curve.h b/thirdparty/embree-aarch64/kernels/subdiv/hermite_curve.h
new file mode 100644
index 0000000000..9fab79cf0c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/hermite_curve.h
@@ -0,0 +1,38 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex>
+ struct HermiteCurveT : BezierCurveT<Vertex>
+ {
+ __forceinline HermiteCurveT() {}
+
+ __forceinline HermiteCurveT(const BezierCurveT<Vertex>& curve)
+ : BezierCurveT<Vertex>(curve) {}
+
+ __forceinline HermiteCurveT(const Vertex& v0, const Vertex& t0, const Vertex& v1, const Vertex& t1)
+ : BezierCurveT<Vertex>(v0,madd(1.0f/3.0f,t0,v0),nmadd(1.0f/3.0f,t1,v1),v1) {}
+
+ __forceinline HermiteCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,this->v0-p), this->v0.w);
+ const Vec3ff q1(xfmVector(space,this->v1-p), this->v1.w);
+ const Vec3ff q2(xfmVector(space,this->v2-p), this->v2.w);
+ const Vec3ff q3(xfmVector(space,this->v3-p), this->v3.w);
+ return BezierCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+ };
+
+ __forceinline HermiteCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const HermiteCurveT<Vec3ff>& curve) {
+ return HermiteCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,BezierCurveT<Vec3ff>(curve)));
+ }
+
+ typedef HermiteCurveT<Vec3fa> HermiteCurve3fa;
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/linear_bezier_patch.h b/thirdparty/embree-aarch64/kernels/subdiv/linear_bezier_patch.h
new file mode 100644
index 0000000000..f4a854af7f
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/linear_bezier_patch.h
@@ -0,0 +1,403 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bezier_curve.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename V>
+ struct TensorLinearQuadraticBezierSurface
+ {
+ QuadraticBezierCurve<V> L;
+ QuadraticBezierCurve<V> R;
+
+ __forceinline TensorLinearQuadraticBezierSurface() {}
+
+ __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<V>& curve)
+ : L(curve.L), R(curve.R) {}
+
+ __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
+ L = other.L; R = other.R; return *this;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<V>& L, const QuadraticBezierCurve<V>& R)
+ : L(L), R(R) {}
+
+ __forceinline BBox<V> bounds() const {
+ return merge(L.bounds(),R.bounds());
+ }
+ };
+
+ template<>
+ struct TensorLinearQuadraticBezierSurface<Vec2fa>
+ {
+ QuadraticBezierCurve<vfloat4> LR;
+
+ __forceinline TensorLinearQuadraticBezierSurface() {}
+
+ __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<Vec2fa>& curve)
+ : LR(curve.LR) {}
+
+ __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
+ LR = other.LR; return *this;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<vfloat4>& LR)
+ : LR(LR) {}
+
+ __forceinline BBox<Vec2fa> bounds() const
+ {
+ const BBox<vfloat4> b = LR.bounds();
+ const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
+ const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
+ return merge(bl,br);
+ }
+ };
+
+ template<typename V>
+ struct TensorLinearCubicBezierSurface
+ {
+ CubicBezierCurve<V> L;
+ CubicBezierCurve<V> R;
+
+ __forceinline TensorLinearCubicBezierSurface() {}
+
+ __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
+ : L(curve.L), R(curve.R) {}
+
+ __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
+ L = other.L; R = other.R; return *this;
+ }
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<V>& L, const CubicBezierCurve<V>& R)
+ : L(L), R(R) {}
+
+ template<template<typename T> class SourceCurve>
+ __forceinline static TensorLinearCubicBezierSurface fromCenterAndNormalCurve(const SourceCurve<Vec3ff>& center, const SourceCurve<Vec3fa>& normal)
+ {
+ SourceCurve<Vec3ff> vcurve = center;
+ SourceCurve<Vec3fa> ncurve = normal;
+
+ /* here we construct a patch which follows the curve l(t) =
+ * p(t) +/- r(t)*normalize(cross(n(t),dp(t))) */
+
+ const Vec3ff p0 = vcurve.eval(0.0f);
+ const Vec3ff dp0 = vcurve.eval_du(0.0f);
+ const Vec3ff ddp0 = vcurve.eval_dudu(0.0f);
+
+ const Vec3fa n0 = ncurve.eval(0.0f);
+ const Vec3fa dn0 = ncurve.eval_du(0.0f);
+
+ const Vec3ff p1 = vcurve.eval(1.0f);
+ const Vec3ff dp1 = vcurve.eval_du(1.0f);
+ const Vec3ff ddp1 = vcurve.eval_dudu(1.0f);
+
+ const Vec3fa n1 = ncurve.eval(1.0f);
+ const Vec3fa dn1 = ncurve.eval_du(1.0f);
+
+ const Vec3fa bt0 = cross(n0,dp0);
+ const Vec3fa dbt0 = cross(dn0,dp0) + cross(n0,ddp0);
+
+ const Vec3fa bt1 = cross(n1,dp1);
+ const Vec3fa dbt1 = cross(dn1,dp1) + cross(n1,ddp1);
+
+ const Vec3fa k0 = normalize(bt0);
+ const Vec3fa dk0 = dnormalize(bt0,dbt0);
+
+ const Vec3fa k1 = normalize(bt1);
+ const Vec3fa dk1 = dnormalize(bt1,dbt1);
+
+ const Vec3fa l0 = p0 - p0.w*k0;
+ const Vec3fa dl0 = dp0 - (dp0.w*k0 + p0.w*dk0);
+
+ const Vec3fa r0 = p0 + p0.w*k0;
+ const Vec3fa dr0 = dp0 + (dp0.w*k0 + p0.w*dk0);
+
+ const Vec3fa l1 = p1 - p1.w*k1;
+ const Vec3fa dl1 = dp1 - (dp1.w*k1 + p1.w*dk1);
+
+ const Vec3fa r1 = p1 + p1.w*k1;
+ const Vec3fa dr1 = dp1 + (dp1.w*k1 + p1.w*dk1);
+
+ const float scale = 1.0f/3.0f;
+ CubicBezierCurve<V> L(l0,l0+scale*dl0,l1-scale*dl1,l1);
+ CubicBezierCurve<V> R(r0,r0+scale*dr0,r1-scale*dr1,r1);
+ return TensorLinearCubicBezierSurface(L,R);
+ }
+
+ __forceinline BBox<V> bounds() const {
+ return merge(L.bounds(),R.bounds());
+ }
+
+ __forceinline BBox3fa accurateBounds() const {
+ return merge(L.accurateBounds(),R.accurateBounds());
+ }
+
+ __forceinline CubicBezierCurve<Interval1f> reduce_v() const {
+ return merge(CubicBezierCurve<Interval<V>>(L),CubicBezierCurve<Interval<V>>(R));
+ }
+
+ __forceinline LinearBezierCurve<Interval1f> reduce_u() const {
+ return LinearBezierCurve<Interval1f>(L.bounds(),R.bounds());
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx) const {
+ return TensorLinearCubicBezierSurface<float>(L.xfm(dx),R.xfm(dx));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<vfloatx> vxfm(const V& dx) const {
+ return TensorLinearCubicBezierSurface<vfloatx>(L.vxfm(dx),R.vxfm(dx));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx, const V& p) const {
+ return TensorLinearCubicBezierSurface<float>(L.xfm(dx,p),R.xfm(dx,p));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space),R.xfm(space));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space,p),R.xfm(space,p));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space,p,s),R.xfm(space,p,s));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
+ return TensorLinearCubicBezierSurface(L.clip(u),R.clip(u));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const {
+ return TensorLinearCubicBezierSurface(clerp(L,R,V(v.lower)),clerp(L,R,V(v.upper)));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
+ return clip_v(v).clip_u(u);
+ }
+
+ __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
+ {
+ CubicBezierCurve<V> L0,L1; L.split(L0,L1,u);
+ CubicBezierCurve<V> R0,R1; R.split(R0,R1,u);
+ new (&left ) TensorLinearCubicBezierSurface(L0,R0);
+ new (&right) TensorLinearCubicBezierSurface(L1,R1);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
+ valid = true; clear(valid,VSIZEX-1);
+ return TensorLinearCubicBezierSurface<Vec2vfx>(L.split(u),R.split(u));
+ }
+
+ __forceinline V eval(const float u, const float v) const {
+ return clerp(L,R,V(v)).eval(u);
+ }
+
+ __forceinline V eval_du(const float u, const float v) const {
+ return clerp(L,R,V(v)).eval_dt(u);
+ }
+
+ __forceinline V eval_dv(const float u, const float v) const {
+ return (R-L).eval(u);
+ }
+
+ __forceinline void eval(const float u, const float v, V& p, V& dpdu, V& dpdv) const
+ {
+ V p0, dp0du; L.eval(u,p0,dp0du);
+ V p1, dp1du; R.eval(u,p1,dp1du);
+ p = lerp(p0,p1,v);
+ dpdu = lerp(dp0du,dp1du,v);
+ dpdv = p1-p0;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface<V> derivative_u() const {
+ return TensorLinearQuadraticBezierSurface<V>(L.derivative(),R.derivative());
+ }
+
+ __forceinline CubicBezierCurve<V> derivative_v() const {
+ return R-L;
+ }
+
+ __forceinline V axis_u() const {
+ return (L.end()-L.begin())+(R.end()-R.begin());
+ }
+
+ __forceinline V axis_v() const {
+ return (R.begin()-L.begin())+(R.end()-L.end());
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
+ {
+ return cout << "TensorLinearCubicBezierSurface" << embree_endl
+ << "{" << embree_endl
+ << " L = " << a.L << ", " << embree_endl
+ << " R = " << a.R << embree_endl
+ << "}";
+ }
+
+ friend __forceinline TensorLinearCubicBezierSurface clerp(const TensorLinearCubicBezierSurface& a, const TensorLinearCubicBezierSurface& b, const float t) {
+ return TensorLinearCubicBezierSurface(clerp(a.L,b.L,V(t)), clerp(a.R,b.R,V(t)));
+ }
+ };
+
+ template<>
+ struct TensorLinearCubicBezierSurface<Vec2fa>
+ {
+ CubicBezierCurve<vfloat4> LR;
+
+ __forceinline TensorLinearCubicBezierSurface() {}
+
+ __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
+ : LR(curve.LR) {}
+
+ __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
+ LR = other.LR; return *this;
+ }
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<vfloat4>& LR)
+ : LR(LR) {}
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<Vec2fa>& L, const CubicBezierCurve<Vec2fa>& R)
+ : LR(shuffle<0,1,0,1>(vfloat4(L.v0),vfloat4(R.v0)),shuffle<0,1,0,1>(vfloat4(L.v1),vfloat4(R.v1)),shuffle<0,1,0,1>(vfloat4(L.v2),vfloat4(R.v2)),shuffle<0,1,0,1>(vfloat4(L.v3),vfloat4(R.v3))) {}
+
+ __forceinline CubicBezierCurve<Vec2fa> getL() const {
+ return CubicBezierCurve<Vec2fa>(Vec2fa(LR.v0),Vec2fa(LR.v1),Vec2fa(LR.v2),Vec2fa(LR.v3));
+ }
+
+ __forceinline CubicBezierCurve<Vec2fa> getR() const {
+ return CubicBezierCurve<Vec2fa>(Vec2fa(shuffle<2,3,2,3>(LR.v0)),Vec2fa(shuffle<2,3,2,3>(LR.v1)),Vec2fa(shuffle<2,3,2,3>(LR.v2)),Vec2fa(shuffle<2,3,2,3>(LR.v3)));
+ }
+
+ __forceinline BBox<Vec2fa> bounds() const
+ {
+ const BBox<vfloat4> b = LR.bounds();
+ const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
+ const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
+ return merge(bl,br);
+ }
+
+ __forceinline BBox1f bounds(const Vec2fa& axis) const
+ {
+ const CubicBezierCurve<vfloat4> LRx = LR;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(axis)),LRx,shuffle<1>(vfloat4(axis))*LRy);
+ const BBox<vfloat4> Lb = LRa.bounds();
+ const BBox<vfloat4> Rb(shuffle<3>(Lb.lower),shuffle<3>(Lb.upper));
+ const BBox<vfloat4> b = merge(Lb,Rb);
+ return BBox1f(b.lower[0],b.upper[0]);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx) const
+ {
+ const CubicBezierCurve<vfloat4> LRx = LR;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
+ return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
+ CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx, const Vec2fa& p) const
+ {
+ const vfloat4 pxyxy = shuffle<0,1,0,1>(vfloat4(p));
+ const CubicBezierCurve<vfloat4> LRx = LR-pxyxy;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
+ return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
+ CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
+ return TensorLinearCubicBezierSurface(LR.clip(u));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const
+ {
+ const CubicBezierCurve<vfloat4> LL(shuffle<0,1,0,1>(LR.v0),shuffle<0,1,0,1>(LR.v1),shuffle<0,1,0,1>(LR.v2),shuffle<0,1,0,1>(LR.v3));
+ const CubicBezierCurve<vfloat4> RR(shuffle<2,3,2,3>(LR.v0),shuffle<2,3,2,3>(LR.v1),shuffle<2,3,2,3>(LR.v2),shuffle<2,3,2,3>(LR.v3));
+ return TensorLinearCubicBezierSurface(clerp(LL,RR,vfloat4(v.lower,v.lower,v.upper,v.upper)));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
+ return clip_v(v).clip_u(u);
+ }
+
+ __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
+ {
+ CubicBezierCurve<vfloat4> LR0,LR1; LR.split(LR0,LR1,u);
+ new (&left ) TensorLinearCubicBezierSurface(LR0);
+ new (&right) TensorLinearCubicBezierSurface(LR1);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
+ valid = true; clear(valid,VSIZEX-1);
+ return TensorLinearCubicBezierSurface<Vec2vfx>(getL().split(u),getR().split(u));
+ }
+
+ __forceinline Vec2fa eval(const float u, const float v) const
+ {
+ const vfloat4 p = LR.eval(u);
+ return Vec2fa(lerp(shuffle<0,1,0,1>(p),shuffle<2,3,2,3>(p),v));
+ }
+
+ __forceinline Vec2fa eval_du(const float u, const float v) const
+ {
+ const vfloat4 dpdu = LR.eval_dt(u);
+ return Vec2fa(lerp(shuffle<0,1,0,1>(dpdu),shuffle<2,3,2,3>(dpdu),v));
+ }
+
+ __forceinline Vec2fa eval_dv(const float u, const float v) const
+ {
+ const vfloat4 p = LR.eval(u);
+ return Vec2fa(shuffle<2,3,2,3>(p)-shuffle<0,1,0,1>(p));
+ }
+
+ __forceinline void eval(const float u, const float v, Vec2fa& p, Vec2fa& dpdu, Vec2fa& dpdv) const
+ {
+ vfloat4 p0, dp0du; LR.eval(u,p0,dp0du);
+ p = Vec2fa(lerp(shuffle<0,1,0,1>(p0),shuffle<2,3,2,3>(p0),v));
+ dpdu = Vec2fa(lerp(shuffle<0,1,0,1>(dp0du),shuffle<2,3,2,3>(dp0du),v));
+ dpdv = Vec2fa(shuffle<2,3,2,3>(p0)-shuffle<0,1,0,1>(p0));
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface<Vec2fa> derivative_u() const {
+ return TensorLinearQuadraticBezierSurface<Vec2fa>(LR.derivative());
+ }
+
+ __forceinline CubicBezierCurve<Vec2fa> derivative_v() const {
+ return getR()-getL();
+ }
+
+ __forceinline Vec2fa axis_u() const
+ {
+ const CubicBezierCurve<Vec2fa> L = getL();
+ const CubicBezierCurve<Vec2fa> R = getR();
+ return (L.end()-L.begin())+(R.end()-R.begin());
+ }
+
+ __forceinline Vec2fa axis_v() const
+ {
+ const CubicBezierCurve<Vec2fa> L = getL();
+ const CubicBezierCurve<Vec2fa> R = getR();
+ return (R.begin()-L.begin())+(R.end()-L.end());
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
+ {
+ return cout << "TensorLinearCubicBezierSurface" << embree_endl
+ << "{" << embree_endl
+ << " L = " << a.getL() << ", " << embree_endl
+ << " R = " << a.getR() << embree_endl
+ << "}";
+ }
+ };
+
+ typedef TensorLinearCubicBezierSurface<float> TensorLinearCubicBezierSurface1f;
+ typedef TensorLinearCubicBezierSurface<Vec2fa> TensorLinearCubicBezierSurface2fa;
+ typedef TensorLinearCubicBezierSurface<Vec3fa> TensorLinearCubicBezierSurface3fa;
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/patch.h b/thirdparty/embree-aarch64/kernels/subdiv/patch.h
new file mode 100644
index 0000000000..d58241b96d
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/patch.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bilinear_patch.h"
+#include "bspline_patch.h"
+#include "bezier_patch.h"
+#include "gregory_patch.h"
+#include "tessellation_cache.h"
+
+#if 1
+#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z)
+#else
+#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z) \
+ { \
+ size_t hex = (size_t)ptr; \
+ for (size_t i=0; i<4; i++) hex = hex ^ (hex >> 8); \
+ const float c = (float)(((hex >> 0) ^ (hex >> 4) ^ (hex >> 8) ^ (hex >> 12) ^ (hex >> 16))&0xf)/15.0f; \
+ if (P) *P = Vertex(0.5f+0.5f*x,0.5f+0.5f*y,0.5f+0.5f*z,0.0f); \
+ }
+#endif
+
+#define PATCH_MAX_CACHE_DEPTH 2
+//#define PATCH_MIN_RESOLUTION 1 // FIXME: not yet completely implemented
+#define PATCH_MAX_EVAL_DEPTH_IRREGULAR 10 // maximum evaluation depth at irregular vertices (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
+#define PATCH_MAX_EVAL_DEPTH_CREASE 10 // maximum evaluation depth at crease features (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
+#define PATCH_USE_GREGORY 1 // 0 = no gregory, 1 = fill, 2 = as early as possible
+
+#if PATCH_USE_GREGORY==2
+#define PATCH_USE_BEZIER_PATCH 1 // enable use of bezier instead of b-spline patches
+#else
+#define PATCH_USE_BEZIER_PATCH 0 // enable use of bezier instead of b-spline patches
+#endif
+
+#if PATCH_USE_BEZIER_PATCH
+# define RegularPatch BezierPatch
+# define RegularPatchT BezierPatchT<Vertex,Vertex_t>
+#else
+# define RegularPatch BSplinePatch
+# define RegularPatchT BSplinePatchT<Vertex,Vertex_t>
+#endif
+
+#if PATCH_USE_GREGORY
+#define IrregularFillPatch GregoryPatch
+#define IrregularFillPatchT GregoryPatchT<Vertex,Vertex_t>
+#else
+#define IrregularFillPatch BilinearPatch
+#define IrregularFillPatchT BilinearPatchT<Vertex,Vertex_t>
+#endif
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) PatchT
+ {
+ public:
+
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ enum Type {
+ INVALID_PATCH = 0,
+ BILINEAR_PATCH = 1,
+ BSPLINE_PATCH = 2,
+ BEZIER_PATCH = 3,
+ GREGORY_PATCH = 4,
+ SUBDIVIDED_GENERAL_PATCH = 7,
+ SUBDIVIDED_QUAD_PATCH = 8,
+ EVAL_PATCH = 9,
+ };
+
+ struct Ref
+ {
+ __forceinline Ref(void* p = nullptr)
+ : ptr((size_t)p) {}
+
+ __forceinline operator bool() const { return ptr != 0; }
+ __forceinline operator size_t() const { return ptr; }
+
+ __forceinline Ref (Type ty, void* in)
+ : ptr(((size_t)in)+ty) { assert((((size_t)in) & 0xF) == 0); }
+
+ __forceinline Type type () const { return (Type)(ptr & 0xF); }
+ __forceinline void* object() const { return (void*) (ptr & ~0xF); }
+
+ size_t ptr;
+ };
+
+ struct EvalPatch
+ {
+ /* creates EvalPatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch)
+ {
+ size_t ofs = 0, bytes = patch.bytes();
+ void* ptr = alloc(bytes);
+ patch.serialize(ptr,ofs);
+ assert(ofs == bytes);
+ return Ref(EVAL_PATCH, ptr);
+ }
+ };
+
+ struct BilinearPatch
+ {
+ /* creates BilinearPatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(patch));
+ }
+
+ __forceinline BilinearPatch (const CatmullClarkPatch& patch)
+ : patch(patch) {}
+
+ /* creates BilinearPatch from 4 vertices */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(edge,vertices,stride));
+ }
+
+ __forceinline BilinearPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ public:
+ BilinearPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct BSplinePatch
+ {
+ /* creates BSplinePatch from a half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(edge,vertices,stride));
+ }
+
+ __forceinline BSplinePatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ /* creates BSplinePatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline BSplinePatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ BSplinePatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct BezierPatch
+ {
+ /* creates BezierPatch from a half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(edge,vertices,stride));
+ }
+
+ __forceinline BezierPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ /* creates Bezier from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline BezierPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ BezierPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct GregoryPatch
+ {
+ /* creates GregoryPatch from half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(edge,vertices,stride));
+ }
+
+ __forceinline GregoryPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(CatmullClarkPatch(edge,vertices,stride)) {}
+
+ /* creates GregoryPatch from CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline GregoryPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ GregoryPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct SubdividedQuadPatch
+ {
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, Ref children[4]) {
+ return Ref(SUBDIVIDED_QUAD_PATCH, new (alloc(sizeof(SubdividedQuadPatch))) SubdividedQuadPatch(children));
+ }
+
+ __forceinline SubdividedQuadPatch(Ref children[4]) {
+ for (size_t i=0; i<4; i++) child[i] = children[i];
+ }
+
+ public:
+ Ref child[4];
+ };
+
+ struct SubdividedGeneralPatch
+ {
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, Ref* children, const unsigned N) {
+ return Ref(SUBDIVIDED_GENERAL_PATCH, new (alloc(sizeof(SubdividedGeneralPatch))) SubdividedGeneralPatch(children,N));
+ }
+
+ __forceinline SubdividedGeneralPatch(Ref* children, const unsigned N) : N(N) {
+ for (unsigned i=0; i<N; i++) child[i] = children[i];
+ }
+
+ unsigned N;
+ Ref child[MAX_PATCH_VALENCE];
+ };
+
+ /*! Default constructor. */
+ __forceinline PatchT () {}
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ if (PATCH_MAX_CACHE_DEPTH == 0)
+ return nullptr;
+
+ Ref child(0);
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: child = BilinearPatch::create(alloc,edge,vertices,stride); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: child = RegularPatch::create(alloc,edge,vertices,stride); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: child = GregoryPatch::create(alloc,edge,vertices,stride); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ child = PatchT::create(alloc,patch,edge,vertices,stride,0);
+ }
+ }
+ return child;
+ }
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, GeneralCatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return PatchT::create(alloc,qpatch,edge,vertices,stride,depth);
+ }
+
+ /* do only cache up to some depth */
+ if (depth >= PATCH_MAX_CACHE_DEPTH)
+ return nullptr;
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,N);
+
+ if (N == 4)
+ {
+ Ref child[4];
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve border3l,border3r; borders[3].subdivide(border3l,border3r);
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ child[0] = PatchT::create(alloc,patches[0],edge,vertices,stride,depth+1,&border0l,nullptr,nullptr,&border3r);
+ child[1] = PatchT::create(alloc,patches[1],edge,vertices,stride,depth+1,&border0r,&border1l,nullptr,nullptr);
+ child[2] = PatchT::create(alloc,patches[2],edge,vertices,stride,depth+1,nullptr,&border1r,&border2l,nullptr);
+ child[3] = PatchT::create(alloc,patches[3],edge,vertices,stride,depth+1,nullptr,nullptr,&border2r,&border3l);
+#else
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ for (size_t i=0; i<4; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+#endif
+ return SubdividedQuadPatch::create(alloc,child);
+ }
+ else
+ {
+ assert(N<MAX_PATCH_VALENCE);
+ Ref child[MAX_PATCH_VALENCE];
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE];
+ patch.getLimitBorder(borders);
+
+ for (size_t i0=0; i0<N; i0++) {
+ const size_t i2 = i0==0 ? N-1 : i0-1;
+ BezierCurve border0l,border0r; borders[i0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[i2].subdivide(border2l,border2r);
+ child[i0] = PatchT::create(alloc,patches[i0],edge,vertices,stride,depth+1, &border0l, nullptr, nullptr, &border2r);
+ }
+#else
+ for (size_t i=0; i<N; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+#endif
+ return SubdividedGeneralPatch::create(alloc,child,N);
+ }
+
+ return nullptr;
+ }
+
+ static __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const size_t max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, CatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth,
+ const BezierCurve* border0 = nullptr, const BezierCurve* border1 = nullptr, const BezierCurve* border2 = nullptr, const BezierCurve* border3 = nullptr)
+ {
+ const typename CatmullClarkPatch::Type ty = patch.type();
+ if (unlikely(final(patch,ty,depth))) {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
+ else return IrregularFillPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0); return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0); return GregoryPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+#endif
+ else if (depth >= PATCH_MAX_CACHE_DEPTH) {
+ return EvalPatch::create(alloc,patch);
+ }
+
+ else
+ {
+ Ref child[4];
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches);
+
+ for (size_t i=0; i<4; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+ return SubdividedQuadPatch::create(alloc,child);
+ }
+ }
+ };
+
+ typedef PatchT<Vec3fa,Vec3fa_t> Patch3fa;
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/patch_eval.h b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval.h
new file mode 100644
index 0000000000..482d015fa3
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval.h
@@ -0,0 +1,129 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct PatchEval
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ PatchEval (SharedLazyTessellationCache::CacheEntry& entry, size_t commitCounter,
+ const HalfEdge* edge, const char* vertices, size_t stride, const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ /* conservative time for the very first allocation */
+ auto time = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+
+ Ref patch = SharedLazyTessellationCache::lookup(entry,commitCounter,[&] () {
+ auto alloc = [&](size_t bytes) { return SharedLazyTessellationCache::malloc(bytes); };
+ return Patch::create(alloc,edge,vertices,stride);
+ },true);
+
+ auto curTime = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+ const bool allAllocationsValid = SharedLazyTessellationCache::validTime(time,curTime);
+
+ if (patch && allAllocationsValid && eval(patch,u,v,1.0f,0)) {
+ SharedLazyTessellationCache::unlock();
+ return;
+ }
+ SharedLazyTessellationCache::unlock();
+ FeatureAdaptiveEval<Vertex,Vertex_t>(edge,vertices,stride,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv);
+ PATCH_DEBUG_SUBDIVISION(edge,c,-1,-1);
+ }
+
+ __forceinline bool eval_quad(const typename Patch::SubdividedQuadPatch* This, const float u, const float v, const float dscale, const size_t depth)
+ {
+ if (v < 0.5f) {
+ if (u < 0.5f) return eval(This->child[0],2.0f*u,2.0f*v,2.0f*dscale,depth+1);
+ else return eval(This->child[1],2.0f*u-1.0f,2.0f*v,2.0f*dscale,depth+1);
+ } else {
+ if (u > 0.5f) return eval(This->child[2],2.0f*u-1.0f,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ else return eval(This->child[3],2.0f*u,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ }
+ }
+
+ bool eval_general(const typename Patch::SubdividedGeneralPatch* This, const float U, const float V, const size_t depth)
+ {
+ const unsigned l = (unsigned) floor(0.5f*U); const float u = 2.0f*frac(0.5f*U)-0.5f;
+ const unsigned h = (unsigned) floor(0.5f*V); const float v = 2.0f*frac(0.5f*V)-0.5f;
+ const unsigned i = 4*h+l; assert(i<This->N);
+ return eval(This->child[i],u,v,1.0f,depth+1);
+ }
+
+ bool eval(Ref This, const float& u, const float& v, const float dscale, const size_t depth)
+ {
+ if (!This) return false;
+ //PRINT(depth);
+ //PRINT2(u,v);
+
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ //PRINT("bilinear");
+ ((typename Patch::BilinearPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,c);
+ return true;
+ }
+ case Patch::BSPLINE_PATCH: {
+ //PRINT("bspline");
+ ((typename Patch::BSplinePatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,-1);
+ return true;
+ }
+ case Patch::BEZIER_PATCH: {
+ //PRINT("bezier");
+ ((typename Patch::BezierPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,-1);
+ return true;
+ }
+ case Patch::GREGORY_PATCH: {
+ //PRINT("gregory");
+ ((typename Patch::GregoryPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,-1,c);
+ return true;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH: {
+ //PRINT("subdivided quad");
+ return eval_quad(((typename Patch::SubdividedQuadPatch*)This.object()),u,v,dscale,depth);
+ }
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ //PRINT("general_patch");
+ assert(dscale == 1.0f);
+ return eval_general(((typename Patch::SubdividedGeneralPatch*)This.object()),u,v,depth);
+ }
+ case Patch::EVAL_PATCH: {
+ //PRINT("eval_patch");
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEval<Vertex,Vertex_t>(patch,u,v,dscale,depth,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv);
+ return true;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ private:
+ Vertex* const P;
+ Vertex* const dPdu;
+ Vertex* const dPdv;
+ Vertex* const ddPdudu;
+ Vertex* const ddPdvdv;
+ Vertex* const ddPdudv;
+ };
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_grid.h b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_grid.h
new file mode 100644
index 0000000000..c05db55f4c
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_grid.h
@@ -0,0 +1,245 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval_grid.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct PatchEvalGrid
+ {
+ typedef Patch3fa Patch;
+ typedef Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatch3fa GeneralCatmullClarkPatch;
+ typedef CatmullClarkPatch3fa CatmullClarkPatch;
+ typedef BSplinePatch3fa BSplinePatch;
+ typedef BezierPatch3fa BezierPatch;
+ typedef GregoryPatch3fa GregoryPatch;
+ typedef BilinearPatch3fa BilinearPatch;
+
+ private:
+ const unsigned x0,x1;
+ const unsigned y0,y1;
+ const unsigned swidth,sheight;
+ const float rcp_swidth, rcp_sheight;
+ float* const Px;
+ float* const Py;
+ float* const Pz;
+ float* const U;
+ float* const V;
+ float* const Nx;
+ float* const Ny;
+ float* const Nz;
+ const unsigned dwidth,dheight;
+ unsigned count;
+
+ public:
+
+ PatchEvalGrid (Ref patch, unsigned subPatch,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), dheight(dheight), count(0)
+ {
+ assert(swidth < (2<<20) && sheight < (2<<20));
+ const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
+ const BBox2f erange(Vec2f(float(x0),float(y0)),Vec2f((float)x1,(float)y1));
+ bool done MAYBE_UNUSED = eval(patch,subPatch,srange,erange);
+ assert(done);
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ }
+
+ template<typename Patch>
+ __forceinline void evalLocalGrid(const Patch* patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
+ {
+ const float scale_x = rcp(srange.upper.x-srange.lower.x);
+ const float scale_y = rcp(srange.upper.y-srange.lower.y);
+ count += (lx1-lx0)*(ly1-ly0);
+
+#if 0
+ for (unsigned iy=ly0; iy<ly1; iy++) {
+ for (unsigned ix=lx0; ix<lx1; ix++) {
+ const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
+ const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
+ const Vec3fa p = patch->patch.eval(lu,lv);
+ const float u = float(ix)*rcp_swidth;
+ const float v = float(iy)*rcp_sheight;
+ const int ofs = (iy-y0)*dwidth+(ix-x0);
+ Px[ofs] = p.x;
+ Py[ofs] = p.y;
+ Pz[ofs] = p.z;
+ U[ofs] = u;
+ V[ofs] = v;
+ }
+ }
+#else
+ foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
+ const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);
+ const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);
+ const Vec3vfx p = patch->patch.eval(lu,lv);
+ Vec3vfx n = zero;
+ if (unlikely(Nx != nullptr)) n = normalize_safe(patch->patch.normal(lu,lv));
+ const vfloatx u = vfloatx(ix)*rcp_swidth;
+ const vfloatx v = vfloatx(iy)*rcp_sheight;
+ const vintx ofs = (iy-y0)*dwidth+(ix-x0);
+ if (likely(all(valid)) && all(iy==iy[0])) {
+ const unsigned ofs2 = ofs[0];
+ vfloatx::storeu(Px+ofs2,p.x);
+ vfloatx::storeu(Py+ofs2,p.y);
+ vfloatx::storeu(Pz+ofs2,p.z);
+ vfloatx::storeu(U+ofs2,u);
+ vfloatx::storeu(V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(Nx+ofs2,n.x);
+ vfloatx::storeu(Ny+ofs2,n.y);
+ vfloatx::storeu(Nz+ofs2,n.z);
+ }
+ } else {
+ foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
+ const unsigned ofs2 = ofs[j]-j;
+ vfloatx::storeu(valid,Px+ofs2,p.x);
+ vfloatx::storeu(valid,Py+ofs2,p.y);
+ vfloatx::storeu(valid,Pz+ofs2,p.z);
+ vfloatx::storeu(valid,U+ofs2,u);
+ vfloatx::storeu(valid,V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(valid,Nx+ofs2,n.x);
+ vfloatx::storeu(valid,Ny+ofs2,n.y);
+ vfloatx::storeu(valid,Nz+ofs2,n.z);
+ }
+ });
+ }
+ });
+#endif
+ }
+
+ bool eval(Ref This, const BBox2f& srange, const BBox2f& erange, const unsigned depth)
+ {
+ if (erange.empty())
+ return true;
+
+ const int lx0 = (int) ceilf(erange.lower.x);
+ const int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
+ const int ly0 = (int) ceilf(erange.lower.y);
+ const int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
+ if (lx0 >= lx1 || ly0 >= ly1)
+ return true;
+
+ if (!This)
+ return false;
+
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ evalLocalGrid((Patch::BilinearPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::BSPLINE_PATCH: {
+ evalLocalGrid((Patch::BSplinePatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::BEZIER_PATCH: {
+ evalLocalGrid((Patch::BezierPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::GREGORY_PATCH: {
+ evalLocalGrid((Patch::GregoryPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH:
+ {
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+ Patch::SubdividedQuadPatch* patch = (Patch::SubdividedQuadPatch*)This.object();
+ eval(patch->child[0],srange0,intersect(srange0,erange),depth+1);
+ eval(patch->child[1],srange1,intersect(srange1,erange),depth+1);
+ eval(patch->child[2],srange2,intersect(srange2,erange),depth+1);
+ eval(patch->child[3],srange3,intersect(srange3,erange),depth+1);
+ return true;
+ }
+ case Patch::EVAL_PATCH: {
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEvalGrid(patch,srange,erange,depth,x0,x1,y0,y1,swidth,sheight,Px,Py,Pz,U,V,Nx,Ny,Nz,dwidth,dheight);
+ count += (lx1-lx0)*(ly1-ly0);
+ return true;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ bool eval(Ref This, unsigned subPatch, const BBox2f& srange, const BBox2f& erange)
+ {
+ if (!This)
+ return false;
+
+ switch (This.type())
+ {
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ Patch::SubdividedGeneralPatch* patch = (Patch::SubdividedGeneralPatch*)This.object();
+ assert(subPatch < patch->N);
+ return eval(patch->child[subPatch],srange,erange,1);
+ }
+ default:
+ assert(subPatch == 0);
+ return eval(This,srange,erange,0);
+ }
+ }
+ };
+
+ __forceinline unsigned patch_eval_subdivision_count (const HalfEdge* h)
+ {
+ const unsigned N = h->numEdges();
+ if (N == 4) return 1;
+ else return N;
+ }
+
+ template<typename Tessellator>
+ inline void patch_eval_subdivision (const HalfEdge* h, Tessellator tessellator)
+ {
+ const unsigned N = h->numEdges();
+ int neighborSubdiv[GeneralCatmullClarkPatch3fa::SIZE]; // FIXME: use array_t
+ float levels[GeneralCatmullClarkPatch3fa::SIZE];
+ for (unsigned i=0; i<N; i++) {
+ assert(i<GeneralCatmullClarkPatch3fa::SIZE);
+ neighborSubdiv[i] = h->hasOpposite() ? h->opposite()->numEdges() != 4 : 0;
+ levels[i] = h->edge_level;
+ h = h->next();
+ }
+ if (N == 4)
+ {
+ const Vec2f uv[4] = { Vec2f(0.0f,0.0f), Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f) };
+ tessellator(uv,neighborSubdiv,levels,0);
+ }
+ else
+ {
+ for (unsigned i=0; i<N; i++)
+ {
+ assert(i<MAX_PATCH_VALENCE);
+ static_assert(MAX_PATCH_VALENCE <= 16, "MAX_PATCH_VALENCE > 16");
+ const int h = (i >> 2) & 3, l = i & 3;
+ const Vec2f subPatchID((float)l,(float)h);
+ const Vec2f uv[4] = { 2.0f*subPatchID + (0.5f+Vec2f(0.0f,0.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(1.0f,0.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(1.0f,1.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(0.0f,1.0f)) };
+ const int neighborSubdiv1[4] = { 0,0,0,0 };
+ const float levels1[4] = { 0.5f*levels[(i+0)%N], 0.5f*levels[(i+0)%N], 0.5f*levels[(i+N-1)%N], 0.5f*levels[(i+N-1)%N] };
+ tessellator(uv,neighborSubdiv1,levels1,i);
+ }
+ }
+ }
+ }
+}
+
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_simd.h b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_simd.h
new file mode 100644
index 0000000000..28016d9e20
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/patch_eval_simd.h
@@ -0,0 +1,127 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval_simd.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename vbool, typename vint, typename vfloat, typename Vertex, typename Vertex_t = Vertex>
+ struct PatchEvalSimd
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ PatchEvalSimd (SharedLazyTessellationCache::CacheEntry& entry, size_t commitCounter,
+ const HalfEdge* edge, const char* vertices, size_t stride, const vbool& valid0, const vfloat& u, const vfloat& v,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ /* conservative time for the very first allocation */
+ auto time = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+
+ Ref patch = SharedLazyTessellationCache::lookup(entry,commitCounter,[&] () {
+ auto alloc = [](size_t bytes) { return SharedLazyTessellationCache::malloc(bytes); };
+ return Patch::create(alloc,edge,vertices,stride);
+ }, true);
+
+ auto curTime = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+ const bool allAllocationsValid = SharedLazyTessellationCache::validTime(time,curTime);
+
+ patch = allAllocationsValid ? patch : nullptr;
+
+ /* use cached data structure for calculations */
+ const vbool valid1 = patch ? eval(valid0,patch,u,v,1.0f,0) : vbool(false);
+ SharedLazyTessellationCache::unlock();
+ const vbool valid2 = valid0 & !valid1;
+ if (any(valid2)) {
+ FeatureAdaptiveEvalSimd<vbool,vint,vfloat,Vertex,Vertex_t>(edge,vertices,stride,valid2,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dstride,N);
+ }
+ }
+
+ vbool eval_quad(const vbool& valid, const typename Patch::SubdividedQuadPatch* This, const vfloat& u, const vfloat& v, const float dscale, const size_t depth)
+ {
+ vbool ret = false;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+ if (any(u0v0_mask)) ret |= eval(u0v0_mask,This->child[0],2.0f*u,2.0f*v,2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) ret |= eval(u1v0_mask,This->child[1],2.0f*u-1.0f,2.0f*v,2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) ret |= eval(u1v1_mask,This->child[2],2.0f*u-1.0f,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) ret |= eval(u0v1_mask,This->child[3],2.0f*u,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ return ret;
+ }
+
+ vbool eval_general(const vbool& valid, const typename Patch::SubdividedGeneralPatch* patch, const vfloat& U, const vfloat& V, const size_t depth)
+ {
+ vbool ret = false;
+ const vint l = (vint)floor(0.5f*U); const vfloat u = 2.0f*frac(0.5f*U)-0.5f;
+ const vint h = (vint)floor(0.5f*V); const vfloat v = 2.0f*frac(0.5f*V)-0.5f;
+ const vint i = (h<<2)+l; assert(all(valid,i<patch->N));
+ foreach_unique(valid,i,[&](const vbool& valid, const int i) {
+ ret |= eval(valid,patch->child[i],u,v,1.0f,depth+1);
+ });
+ return ret;
+ }
+
+ vbool eval(const vbool& valid, Ref This, const vfloat& u, const vfloat& v, const float dscale, const size_t depth)
+ {
+ if (!This) return false;
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ ((typename Patch::BilinearPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::BSPLINE_PATCH: {
+ ((typename Patch::BSplinePatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::BEZIER_PATCH: {
+ ((typename Patch::BezierPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::GREGORY_PATCH: {
+ ((typename Patch::GregoryPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH: {
+ return eval_quad(valid,((typename Patch::SubdividedQuadPatch*)This.object()),u,v,dscale,depth);
+ }
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ assert(dscale == 1.0f);
+ return eval_general(valid,((typename Patch::SubdividedGeneralPatch*)This.object()),u,v,depth);
+ }
+ case Patch::EVAL_PATCH: {
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEvalSimd<vbool,vint,vfloat,Vertex,Vertex_t>(patch,valid,u,v,dscale,depth,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dstride,N);
+ return valid;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ private:
+ float* const P;
+ float* const dPdu;
+ float* const dPdv;
+ float* const ddPdudu;
+ float* const ddPdvdv;
+ float* const ddPdudv;
+ const size_t dstride;
+ const size_t N;
+ };
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/subdivpatch1base.h b/thirdparty/embree-aarch64/kernels/subdiv/subdivpatch1base.h
new file mode 100644
index 0000000000..d5bc403cca
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/subdivpatch1base.h
@@ -0,0 +1,156 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../geometry/primitive.h"
+#include "bspline_patch.h"
+#include "bezier_patch.h"
+#include "gregory_patch.h"
+#include "gregory_patch_dense.h"
+#include "tessellation.h"
+#include "tessellation_cache.h"
+#include "gridrange.h"
+#include "patch_eval_grid.h"
+#include "feature_adaptive_eval_grid.h"
+#include "../common/scene_subdiv_mesh.h"
+
+namespace embree
+{
+ struct __aligned(64) SubdivPatch1Base
+ {
+ public:
+
+ enum Type {
+ INVALID_PATCH = 0,
+ BSPLINE_PATCH = 1,
+ BEZIER_PATCH = 2,
+ GREGORY_PATCH = 3,
+ EVAL_PATCH = 5,
+ BILINEAR_PATCH = 6,
+ };
+
+ enum Flags {
+ TRANSITION_PATCH = 16,
+ };
+
+ /*! Default constructor. */
+ __forceinline SubdivPatch1Base () {}
+
+ SubdivPatch1Base (const unsigned int gID,
+ const unsigned int pID,
+ const unsigned int subPatch,
+ const SubdivMesh *const mesh,
+ const size_t time,
+ const Vec2f uv[4],
+ const float edge_level[4],
+ const int subdiv[4],
+ const int simd_width);
+
+ __forceinline bool needsStitching() const {
+ return flags & TRANSITION_PATCH;
+ }
+
+ __forceinline Vec2f getUV(const size_t i) const {
+ return Vec2f((float)u[i],(float)v[i]) * (8.0f/0x10000);
+ }
+
+ static void computeEdgeLevels(const float edge_level[4], const int subdiv[4], float level[4]);
+ static Vec2i computeGridSize(const float level[4]);
+ bool updateEdgeLevels(const float edge_level[4], const int subdiv[4], const SubdivMesh *const mesh, const int simd_width);
+
+ public:
+
+ __forceinline size_t getGridBytes() const {
+ const size_t grid_size_xyzuv = (grid_size_simd_blocks * VSIZEX) * 4;
+ return 64*((grid_size_xyzuv+15) / 16);
+ }
+
+ __forceinline void write_lock() { mtx.lock(); }
+ __forceinline void write_unlock() { mtx.unlock(); }
+ __forceinline bool try_write_lock() { return mtx.try_lock(); }
+ //__forceinline bool try_read_lock() { return mtx.try_read_lock(); }
+
+ __forceinline void resetRootRef() {
+ //assert( mtx.hasInitialState() );
+ root_ref = SharedLazyTessellationCache::Tag();
+ }
+
+ __forceinline SharedLazyTessellationCache::CacheEntry& entry() {
+ return (SharedLazyTessellationCache::CacheEntry&) root_ref;
+ }
+
+ public:
+ __forceinline unsigned int geomID() const {
+ return geom;
+ }
+
+ __forceinline unsigned int primID() const {
+ return prim;
+ }
+
+ public:
+ SharedLazyTessellationCache::Tag root_ref;
+ SpinLock mtx;
+
+ unsigned short u[4]; //!< 16bit discretized u,v coordinates
+ unsigned short v[4];
+ float level[4];
+
+ unsigned char flags;
+ unsigned char type;
+ unsigned short grid_u_res;
+ unsigned int geom; //!< geometry ID of the subdivision mesh this patch belongs to
+ unsigned int prim; //!< primitive ID of this subdivision patch
+ unsigned short grid_v_res;
+
+ unsigned short grid_size_simd_blocks;
+ unsigned int time_;
+
+ struct PatchHalfEdge {
+ const HalfEdge* edge;
+ unsigned subPatch;
+ };
+
+ Vec3fa patch_v[4][4];
+
+ const HalfEdge *edge() const { return ((PatchHalfEdge*)patch_v)->edge; }
+ unsigned time() const { return time_; }
+ unsigned subPatch() const { return ((PatchHalfEdge*)patch_v)->subPatch; }
+
+ void set_edge(const HalfEdge *h) const { ((PatchHalfEdge*)patch_v)->edge = h; }
+ void set_subPatch(const unsigned s) const { ((PatchHalfEdge*)patch_v)->subPatch = s; }
+ };
+
+ namespace isa
+ {
+ Vec3fa patchEval(const SubdivPatch1Base& patch, const float uu, const float vv);
+ Vec3fa patchNormal(const SubdivPatch1Base& patch, const float uu, const float vv);
+
+ template<typename simdf>
+ Vec3<simdf> patchEval(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv);
+
+ template<typename simdf>
+ Vec3<simdf> patchNormal(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv);
+
+
+ /* eval grid over patch and stich edges when required */
+ void evalGrid(const SubdivPatch1Base& patch,
+ const unsigned x0, const unsigned x1,
+ const unsigned y0, const unsigned y1,
+ const unsigned swidth, const unsigned sheight,
+ float *__restrict__ const grid_x,
+ float *__restrict__ const grid_y,
+ float *__restrict__ const grid_z,
+ float *__restrict__ const grid_u,
+ float *__restrict__ const grid_v,
+ const SubdivMesh* const geom);
+
+ /* eval grid over patch and stich edges when required */
+ BBox3fa evalGridBounds(const SubdivPatch1Base& patch,
+ const unsigned x0, const unsigned x1,
+ const unsigned y0, const unsigned y1,
+ const unsigned swidth, const unsigned sheight,
+ const SubdivMesh* const geom);
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/tessellation.h b/thirdparty/embree-aarch64/kernels/subdiv/tessellation.h
new file mode 100644
index 0000000000..bda1e2d559
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/tessellation.h
@@ -0,0 +1,161 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* adjust discret tessellation level for feature-adaptive pre-subdivision */
+ __forceinline float adjustTessellationLevel(float l, const size_t sublevel)
+ {
+ for (size_t i=0; i<sublevel; i++) l *= 0.5f;
+ float r = ceilf(l);
+ for (size_t i=0; i<sublevel; i++) r *= 2.0f;
+ return r;
+ }
+
+ __forceinline int stitch(const int x, const int fine, const int coarse) {
+ return (2*x+1)*coarse/(2*fine);
+ }
+
+ __forceinline void stitchGridEdges(const unsigned int low_rate,
+ const unsigned int high_rate,
+ const unsigned int x0,
+ const unsigned int x1,
+ float * __restrict__ const uv_array,
+ const unsigned int uv_array_step)
+ {
+#if 1
+ const float inv_low_rate = rcp((float)(low_rate-1));
+ for (unsigned x=x0; x<=x1; x++) {
+ uv_array[(x-x0)*uv_array_step] = float(stitch(x,high_rate-1,low_rate-1))*inv_low_rate;
+ }
+ if (unlikely(x1 == high_rate-1))
+ uv_array[(x1-x0)*uv_array_step] = 1.0f;
+#else
+ assert(low_rate < high_rate);
+ assert(high_rate >= 2);
+
+ const float inv_low_rate = rcp((float)(low_rate-1));
+ const unsigned int dy = low_rate - 1;
+ const unsigned int dx = high_rate - 1;
+
+ int p = 2*dy-dx;
+
+ unsigned int offset = 0;
+ unsigned int y = 0;
+ float value = 0.0f;
+ for(unsigned int x=0;x<high_rate-1; x++) // '<=' would be correct but we will leave the 1.0f at the end
+ {
+ uv_array[offset] = value;
+
+ offset += uv_array_step;
+ if (unlikely(p > 0))
+ {
+ y++;
+ value = (float)y * inv_low_rate;
+ p -= 2*dx;
+ }
+ p += 2*dy;
+ }
+#endif
+ }
+
+ __forceinline void stitchUVGrid(const float edge_levels[4],
+ const unsigned int swidth,
+ const unsigned int sheight,
+ const unsigned int x0,
+ const unsigned int y0,
+ const unsigned int grid_u_res,
+ const unsigned int grid_v_res,
+ float * __restrict__ const u_array,
+ float * __restrict__ const v_array)
+ {
+ const unsigned int x1 = x0+grid_u_res-1;
+ const unsigned int y1 = y0+grid_v_res-1;
+ const unsigned int int_edge_points0 = (unsigned int)edge_levels[0] + 1;
+ const unsigned int int_edge_points1 = (unsigned int)edge_levels[1] + 1;
+ const unsigned int int_edge_points2 = (unsigned int)edge_levels[2] + 1;
+ const unsigned int int_edge_points3 = (unsigned int)edge_levels[3] + 1;
+
+ if (unlikely(y0 == 0 && int_edge_points0 < swidth))
+ stitchGridEdges(int_edge_points0,swidth,x0,x1,u_array,1);
+
+ if (unlikely(y1 == sheight-1 && int_edge_points2 < swidth))
+ stitchGridEdges(int_edge_points2,swidth,x0,x1,&u_array[(grid_v_res-1)*grid_u_res],1);
+
+ if (unlikely(x0 == 0 && int_edge_points1 < sheight))
+ stitchGridEdges(int_edge_points1,sheight,y0,y1,&v_array[grid_u_res-1],grid_u_res);
+
+ if (unlikely(x1 == swidth-1 && int_edge_points3 < sheight))
+ stitchGridEdges(int_edge_points3,sheight,y0,y1,v_array,grid_u_res);
+ }
+
+ __forceinline void gridUVTessellator(const float edge_levels[4],
+ const unsigned int swidth,
+ const unsigned int sheight,
+ const unsigned int x0,
+ const unsigned int y0,
+ const unsigned int grid_u_res,
+ const unsigned int grid_v_res,
+ float * __restrict__ const u_array,
+ float * __restrict__ const v_array)
+ {
+ assert( grid_u_res >= 1);
+ assert( grid_v_res >= 1);
+ assert( edge_levels[0] >= 1.0f );
+ assert( edge_levels[1] >= 1.0f );
+ assert( edge_levels[2] >= 1.0f );
+ assert( edge_levels[3] >= 1.0f );
+
+#if defined(__AVX__)
+ const vint8 grid_u_segments = vint8(swidth)-1;
+ const vint8 grid_v_segments = vint8(sheight)-1;
+
+ const vfloat8 inv_grid_u_segments = rcp(vfloat8(grid_u_segments));
+ const vfloat8 inv_grid_v_segments = rcp(vfloat8(grid_v_segments));
+
+ unsigned int index = 0;
+ vint8 v_i( zero );
+ for (unsigned int y=0;y<grid_v_res;y++,index+=grid_u_res,v_i += 1)
+ {
+ vint8 u_i ( step );
+
+ const vbool8 m_v = v_i < grid_v_segments;
+
+ for (unsigned int x=0;x<grid_u_res;x+=8, u_i += 8)
+ {
+ const vbool8 m_u = u_i < grid_u_segments;
+ const vfloat8 u = select(m_u, vfloat8(x0+u_i) * inv_grid_u_segments, 1.0f);
+ const vfloat8 v = select(m_v, vfloat8(y0+v_i) * inv_grid_v_segments, 1.0f);
+ vfloat8::storeu(&u_array[index + x],u);
+ vfloat8::storeu(&v_array[index + x],v);
+ }
+ }
+ #else
+ const vint4 grid_u_segments = vint4(swidth)-1;
+ const vint4 grid_v_segments = vint4(sheight)-1;
+
+ const vfloat4 inv_grid_u_segments = rcp(vfloat4(grid_u_segments));
+ const vfloat4 inv_grid_v_segments = rcp(vfloat4(grid_v_segments));
+
+ unsigned int index = 0;
+ vint4 v_i( zero );
+ for (unsigned int y=0;y<grid_v_res;y++,index+=grid_u_res,v_i += 1)
+ {
+ vint4 u_i ( step );
+
+ const vbool4 m_v = v_i < grid_v_segments;
+
+ for (unsigned int x=0;x<grid_u_res;x+=4, u_i += 4)
+ {
+ const vbool4 m_u = u_i < grid_u_segments;
+ const vfloat4 u = select(m_u, vfloat4(x0+u_i) * inv_grid_u_segments, 1.0f);
+ const vfloat4 v = select(m_v, vfloat4(y0+v_i) * inv_grid_v_segments, 1.0f);
+ vfloat4::storeu(&u_array[index + x],u);
+ vfloat4::storeu(&v_array[index + x],v);
+ }
+ }
+#endif
+ }
+}
diff --git a/thirdparty/embree-aarch64/kernels/subdiv/tessellation_cache.h b/thirdparty/embree-aarch64/kernels/subdiv/tessellation_cache.h
new file mode 100644
index 0000000000..5c215288b6
--- /dev/null
+++ b/thirdparty/embree-aarch64/kernels/subdiv/tessellation_cache.h
@@ -0,0 +1,325 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+
+/* force a complete cache invalidation when running out of allocation space */
+#define FORCE_SIMPLE_FLUSH 0
+
+#define THREAD_BLOCK_ATOMIC_ADD 4
+
+#if defined(DEBUG)
+#define CACHE_STATS(x)
+#else
+#define CACHE_STATS(x)
+#endif
+
+namespace embree
+{
+ class SharedTessellationCacheStats
+ {
+ public:
+ /* stats */
+ static std::atomic<size_t> cache_accesses;
+ static std::atomic<size_t> cache_hits;
+ static std::atomic<size_t> cache_misses;
+ static std::atomic<size_t> cache_flushes;
+ static size_t cache_num_patches;
+ __aligned(64) static SpinLock mtx;
+
+ /* print stats for debugging */
+ static void printStats();
+ static void clearStats();
+ };
+
+ void resizeTessellationCache(size_t new_size);
+ void resetTessellationCache();
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(64) ThreadWorkState
+ {
+ ALIGNED_STRUCT_(64);
+
+ std::atomic<size_t> counter;
+ ThreadWorkState* next;
+ bool allocated;
+
+ __forceinline ThreadWorkState(bool allocated = false)
+ : counter(0), next(nullptr), allocated(allocated)
+ {
+ assert( ((size_t)this % 64) == 0 );
+ }
+ };
+
+ class __aligned(64) SharedLazyTessellationCache
+ {
+ public:
+
+ static const size_t NUM_CACHE_SEGMENTS = 8;
+ static const size_t NUM_PREALLOC_THREAD_WORK_STATES = 512;
+ static const size_t COMMIT_INDEX_SHIFT = 32+8;
+#if defined(__X86_64__) || defined(__aarch64__)
+ static const size_t REF_TAG_MASK = 0xffffffffff;
+#else
+ static const size_t REF_TAG_MASK = 0x7FFFFFFF;
+#endif
+ static const size_t MAX_TESSELLATION_CACHE_SIZE = REF_TAG_MASK+1;
+ static const size_t BLOCK_SIZE = 64;
+
+
+ /*! Per thread tessellation ref cache */
+ static __thread ThreadWorkState* init_t_state;
+ static ThreadWorkState* current_t_state;
+
+ static __forceinline ThreadWorkState *threadState()
+ {
+ if (unlikely(!init_t_state))
+ /* sets init_t_state, can't return pointer due to macosx icc bug*/
+ SharedLazyTessellationCache::sharedLazyTessellationCache.getNextRenderThreadWorkState();
+ return init_t_state;
+ }
+
+ struct Tag
+ {
+ __forceinline Tag() : data(0) {}
+
+ __forceinline Tag(void* ptr, size_t combinedTime) {
+ init(ptr,combinedTime);
+ }
+
+ __forceinline Tag(size_t ptr, size_t combinedTime) {
+ init((void*)ptr,combinedTime);
+ }
+
+ __forceinline void init(void* ptr, size_t combinedTime)
+ {
+ if (ptr == nullptr) {
+ data = 0;
+ return;
+ }
+ int64_t new_root_ref = (int64_t) ptr;
+ new_root_ref -= (int64_t)SharedLazyTessellationCache::sharedLazyTessellationCache.getDataPtr();
+ assert( new_root_ref <= (int64_t)REF_TAG_MASK );
+ new_root_ref |= (int64_t)combinedTime << COMMIT_INDEX_SHIFT;
+ data = new_root_ref;
+ }
+
+ __forceinline int64_t get() const { return data.load(); }
+ __forceinline void set( int64_t v ) { data.store(v); }
+ __forceinline void reset() { data.store(0); }
+
+ private:
+ atomic<int64_t> data;
+ };
+
+ static __forceinline size_t extractCommitIndex(const int64_t v) { return v >> SharedLazyTessellationCache::COMMIT_INDEX_SHIFT; }
+
+ struct CacheEntry
+ {
+ Tag tag;
+ SpinLock mutex;
+ };
+
+ private:
+
+ float *data;
+ bool hugepages;
+ size_t size;
+ size_t maxBlocks;
+ ThreadWorkState *threadWorkState;
+
+ __aligned(64) std::atomic<size_t> localTime;
+ __aligned(64) std::atomic<size_t> next_block;
+ __aligned(64) SpinLock reset_state;
+ __aligned(64) SpinLock linkedlist_mtx;
+ __aligned(64) std::atomic<size_t> switch_block_threshold;
+ __aligned(64) std::atomic<size_t> numRenderThreads;
+
+
+ public:
+
+
+ SharedLazyTessellationCache();
+ ~SharedLazyTessellationCache();
+
+ void getNextRenderThreadWorkState();
+
+ __forceinline size_t maxAllocSize() const {
+ return switch_block_threshold;
+ }
+
+ __forceinline size_t getCurrentIndex() { return localTime.load(); }
+ __forceinline void addCurrentIndex(const size_t i=1) { localTime.fetch_add(i); }
+
+ __forceinline size_t getTime(const size_t globalTime) {
+ return localTime.load()+NUM_CACHE_SEGMENTS*globalTime;
+ }
+
+
+ __forceinline size_t lockThread (ThreadWorkState *const t_state, const ssize_t plus=1) { return t_state->counter.fetch_add(plus); }
+ __forceinline size_t unlockThread(ThreadWorkState *const t_state, const ssize_t plus=-1) { assert(isLocked(t_state)); return t_state->counter.fetch_add(plus); }
+
+ __forceinline bool isLocked(ThreadWorkState *const t_state) { return t_state->counter.load() != 0; }
+
+ static __forceinline void lock () { sharedLazyTessellationCache.lockThread(threadState()); }
+ static __forceinline void unlock() { sharedLazyTessellationCache.unlockThread(threadState()); }
+ static __forceinline bool isLocked() { return sharedLazyTessellationCache.isLocked(threadState()); }
+ static __forceinline size_t getState() { return threadState()->counter.load(); }
+ static __forceinline void lockThreadLoop() { sharedLazyTessellationCache.lockThreadLoop(threadState()); }
+
+ static __forceinline size_t getTCacheTime(const size_t globalTime) {
+ return sharedLazyTessellationCache.getTime(globalTime);
+ }
+
+ /* per thread lock */
+ __forceinline void lockThreadLoop (ThreadWorkState *const t_state)
+ {
+ while(1)
+ {
+ size_t lock = SharedLazyTessellationCache::sharedLazyTessellationCache.lockThread(t_state,1);
+ if (unlikely(lock >= THREAD_BLOCK_ATOMIC_ADD))
+ {
+ /* lock failed wait until sync phase is over */
+ sharedLazyTessellationCache.unlockThread(t_state,-1);
+ sharedLazyTessellationCache.waitForUsersLessEqual(t_state,0);
+ }
+ else
+ break;
+ }
+ }
+
+ static __forceinline void* lookup(CacheEntry& entry, size_t globalTime)
+ {
+ const int64_t subdiv_patch_root_ref = entry.tag.get();
+ CACHE_STATS(SharedTessellationCacheStats::cache_accesses++);
+
+ if (likely(subdiv_patch_root_ref != 0))
+ {
+ const size_t subdiv_patch_root = (subdiv_patch_root_ref & REF_TAG_MASK) + (size_t)sharedLazyTessellationCache.getDataPtr();
+ const size_t subdiv_patch_cache_index = extractCommitIndex(subdiv_patch_root_ref);
+
+ if (likely( sharedLazyTessellationCache.validCacheIndex(subdiv_patch_cache_index,globalTime) ))
+ {
+ CACHE_STATS(SharedTessellationCacheStats::cache_hits++);
+ return (void*) subdiv_patch_root;
+ }
+ }
+ CACHE_STATS(SharedTessellationCacheStats::cache_misses++);
+ return nullptr;
+ }
+
+ template<typename Constructor>
+ static __forceinline auto lookup (CacheEntry& entry, size_t globalTime, const Constructor constructor, const bool before=false) -> decltype(constructor())
+ {
+ ThreadWorkState *t_state = SharedLazyTessellationCache::threadState();
+
+ while (true)
+ {
+ sharedLazyTessellationCache.lockThreadLoop(t_state);
+ void* patch = SharedLazyTessellationCache::lookup(entry,globalTime);
+ if (patch) return (decltype(constructor())) patch;
+
+ if (entry.mutex.try_lock())
+ {
+ if (!validTag(entry.tag,globalTime))
+ {
+ auto timeBefore = sharedLazyTessellationCache.getTime(globalTime);
+ auto ret = constructor(); // thread is locked here!
+ assert(ret);
+ /* this should never return nullptr */
+ auto timeAfter = sharedLazyTessellationCache.getTime(globalTime);
+ auto time = before ? timeBefore : timeAfter;
+ __memory_barrier();
+ entry.tag = SharedLazyTessellationCache::Tag(ret,time);
+ __memory_barrier();
+ entry.mutex.unlock();
+ return ret;
+ }
+ entry.mutex.unlock();
+ }
+ SharedLazyTessellationCache::sharedLazyTessellationCache.unlockThread(t_state);
+ }
+ }
+
+ __forceinline bool validCacheIndex(const size_t i, const size_t globalTime)
+ {
+#if FORCE_SIMPLE_FLUSH == 1
+ return i == getTime(globalTime);
+#else
+ return i+(NUM_CACHE_SEGMENTS-1) >= getTime(globalTime);
+#endif
+ }
+
+ static __forceinline bool validTime(const size_t oldtime, const size_t newTime)
+ {
+ return oldtime+(NUM_CACHE_SEGMENTS-1) >= newTime;
+ }
+
+
+ static __forceinline bool validTag(const Tag& tag, size_t globalTime)
+ {
+ const int64_t subdiv_patch_root_ref = tag.get();
+ if (subdiv_patch_root_ref == 0) return false;
+ const size_t subdiv_patch_cache_index = extractCommitIndex(subdiv_patch_root_ref);
+ return sharedLazyTessellationCache.validCacheIndex(subdiv_patch_cache_index,globalTime);
+ }
+
+ void waitForUsersLessEqual(ThreadWorkState *const t_state,
+ const unsigned int users);
+
+ __forceinline size_t alloc(const size_t blocks)
+ {
+ if (unlikely(blocks >= switch_block_threshold))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"allocation exceeds size of tessellation cache segment");
+
+ assert(blocks < switch_block_threshold);
+ size_t index = next_block.fetch_add(blocks);
+ if (unlikely(index + blocks >= switch_block_threshold)) return (size_t)-1;
+ return index;
+ }
+
+ static __forceinline void* malloc(const size_t bytes)
+ {
+ size_t block_index = -1;
+ ThreadWorkState *const t_state = threadState();
+ while (true)
+ {
+ block_index = sharedLazyTessellationCache.alloc((bytes+BLOCK_SIZE-1)/BLOCK_SIZE);
+ if (block_index == (size_t)-1)
+ {
+ sharedLazyTessellationCache.unlockThread(t_state);
+ sharedLazyTessellationCache.allocNextSegment();
+ sharedLazyTessellationCache.lockThread(t_state);
+ continue;
+ }
+ break;
+ }
+ return sharedLazyTessellationCache.getBlockPtr(block_index);
+ }
+
+ __forceinline void *getBlockPtr(const size_t block_index)
+ {
+ assert(block_index < maxBlocks);
+ assert(data);
+ assert(block_index*16 <= size);
+ return (void*)&data[block_index*16];
+ }
+
+ __forceinline void* getDataPtr() { return data; }
+ __forceinline size_t getNumUsedBytes() { return next_block * BLOCK_SIZE; }
+ __forceinline size_t getMaxBlocks() { return maxBlocks; }
+ __forceinline size_t getSize() { return size; }
+
+ void allocNextSegment();
+ void realloc(const size_t newSize);
+
+ void reset();
+
+ static SharedLazyTessellationCache sharedLazyTessellationCache;
+ };
+}
diff --git a/thirdparty/embree-aarch64/patches/godot-changes.patch b/thirdparty/embree-aarch64/patches/godot-changes.patch
new file mode 100644
index 0000000000..86fbf226d2
--- /dev/null
+++ b/thirdparty/embree-aarch64/patches/godot-changes.patch
@@ -0,0 +1,630 @@
+diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_for.h b/thirdparty/embree-aarch64/common/algorithms/parallel_for.h
+index 76c6b740aa..51d296fb16 100644
+--- a/thirdparty/embree-aarch64/common/algorithms/parallel_for.h
++++ b/thirdparty/embree-aarch64/common/algorithms/parallel_for.h
+@@ -27,7 +27,10 @@ namespace embree
+ func(r.begin());
+ });
+ if (!TaskScheduler::wait())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ }
+ #elif defined(TASKING_GCD) && defined(BUILD_IOS)
+
+@@ -55,13 +58,19 @@ namespace embree
+ func(i);
+ },context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #elif defined(TASKING_PPL)
+@@ -81,7 +90,10 @@ namespace embree
+ #if defined(TASKING_INTERNAL)
+ TaskScheduler::spawn(first,last,minStepSize,func);
+ if (!TaskScheduler::wait())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+
+ #elif defined(TASKING_GCD) && defined(BUILD_IOS)
+
+@@ -109,13 +121,19 @@ namespace embree
+ func(range<Index>(r.begin(),r.end()));
+ },context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ });
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #elif defined(TASKING_PPL)
+@@ -147,13 +165,19 @@ namespace embree
+ func(i);
+ },tbb::simple_partitioner(),context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner());
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+ }
+
+@@ -168,13 +192,19 @@ namespace embree
+ func(i);
+ },ap,context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap);
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+ }
+
+diff --git a/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h
+index d444b6a2e4..0daf94e50e 100644
+--- a/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h
++++ b/thirdparty/embree-aarch64/common/algorithms/parallel_reduce.h
+@@ -58,15 +58,19 @@ namespace embree
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction,context);
+- if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // if (context.is_group_execution_cancelled())
++ // throw std::runtime_error("task cancelled");
++ // -- GODOT end --
+ return v;
+ #else
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction);
+- if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // if (tbb::task::self().is_cancelled())
++ // throw std::runtime_error("task cancelled");
++ // -- GODOT end --
+ return v;
+ #endif
+ #else // TASKING_PPL
+diff --git a/thirdparty/embree-aarch64/common/lexers/stringstream.cpp b/thirdparty/embree-aarch64/common/lexers/stringstream.cpp
+index 7e7b9faef8..98dc80ad59 100644
+--- a/thirdparty/embree-aarch64/common/lexers/stringstream.cpp
++++ b/thirdparty/embree-aarch64/common/lexers/stringstream.cpp
+@@ -39,7 +39,10 @@ namespace embree
+ std::vector<char> str; str.reserve(64);
+ while (cin->peek() != EOF && !isSeparator(cin->peek())) {
+ int c = cin->get();
+- if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
++ // -- GODOT start --
++ // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
++ if (!isValidChar(c)) abort();
++ // -- GODOT end --
+ str.push_back((char)c);
+ }
+ str.push_back(0);
+diff --git a/thirdparty/embree-aarch64/common/sys/alloc.cpp b/thirdparty/embree-aarch64/common/sys/alloc.cpp
+index 4e8928242e..12f143f131 100644
+--- a/thirdparty/embree-aarch64/common/sys/alloc.cpp
++++ b/thirdparty/embree-aarch64/common/sys/alloc.cpp
+@@ -21,7 +21,10 @@ namespace embree
+ void* ptr = _mm_malloc(size,align);
+
+ if (size != 0 && ptr == nullptr)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return ptr;
+ }
+@@ -128,7 +131,10 @@ namespace embree
+ /* fall back to 4k pages */
+ int flags = MEM_COMMIT | MEM_RESERVE;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+- if (ptr == nullptr) throw std::bad_alloc();
++ // -- GODOT start --
++ // if (ptr == nullptr) throw std::bad_alloc();
++ if (ptr == nullptr) abort();
++ // -- GODOT end --
+ hugepages = false;
+ return ptr;
+ }
+@@ -145,7 +151,10 @@ namespace embree
+ return bytesOld;
+
+ if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT))
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return bytesNew;
+ }
+@@ -156,7 +165,10 @@ namespace embree
+ return;
+
+ if (!VirtualFree(ptr,0,MEM_RELEASE))
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+ }
+
+ void os_advise(void *ptr, size_t bytes)
+@@ -260,7 +272,10 @@ namespace embree
+
+ /* fallback to 4k pages */
+ void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+- if (ptr == MAP_FAILED) throw std::bad_alloc();
++ // -- GODOT start --
++ // if (ptr == MAP_FAILED) throw std::bad_alloc();
++ if (ptr == MAP_FAILED) abort();
++ // -- GODOT end --
+ hugepages = false;
+
+ /* advise huge page hint for THP */
+@@ -277,7 +292,10 @@ namespace embree
+ return bytesOld;
+
+ if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return bytesNew;
+ }
+@@ -291,7 +309,10 @@ namespace embree
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytes = (bytes+pageSize-1) & ~(pageSize-1);
+ if (munmap(ptr,bytes) == -1)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+ }
+
+ /* hint for transparent huge pages (THP) */
+diff --git a/thirdparty/embree-aarch64/common/sys/platform.h b/thirdparty/embree-aarch64/common/sys/platform.h
+index 7914eb7a52..737f14aa6e 100644
+--- a/thirdparty/embree-aarch64/common/sys/platform.h
++++ b/thirdparty/embree-aarch64/common/sys/platform.h
+@@ -174,11 +174,19 @@
+ #define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl
+
+ #if defined(DEBUG) // only report file and line in debug mode
++ // -- GODOT start --
++ // #define THROW_RUNTIME_ERROR(str)
++ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define THROW_RUNTIME_ERROR(str) \
+- throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
++ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ // -- GODOT end --
+ #else
++ // -- GODOT start --
++ // #define THROW_RUNTIME_ERROR(str)
++ // throw std::runtime_error(str);
+ #define THROW_RUNTIME_ERROR(str) \
+- throw std::runtime_error(str);
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #define FATAL(x) THROW_RUNTIME_ERROR(x)
+diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp
+index 98d7fb9249..ebf656d1a0 100644
+--- a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp
++++ b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.cpp
+@@ -48,13 +48,15 @@ namespace embree
+ {
+ Task* prevTask = thread.task;
+ thread.task = this;
+- try {
+- if (thread.scheduler->cancellingException == nullptr)
++ // -- GODOT start --
++ // try {
++ // if (thread.scheduler->cancellingException == nullptr)
+ closure->execute();
+- } catch (...) {
+- if (thread.scheduler->cancellingException == nullptr)
+- thread.scheduler->cancellingException = std::current_exception();
+- }
++ // } catch (...) {
++ // if (thread.scheduler->cancellingException == nullptr)
++ // thread.scheduler->cancellingException = std::current_exception();
++ // }
++ // -- GODOT end --
+ thread.task = prevTask;
+ add_dependencies(-1);
+ }
+@@ -297,8 +299,11 @@ namespace embree
+ size_t threadIndex = allocThreadIndex();
+ condition.wait(mutex, [&] () { return hasRootTask.load(); });
+ mutex.unlock();
+- std::exception_ptr except = thread_loop(threadIndex);
+- if (except != nullptr) std::rethrow_exception(except);
++ // -- GODOT start --
++ // std::exception_ptr except = thread_loop(threadIndex);
++ // if (except != nullptr) std::rethrow_exception(except);
++ thread_loop(threadIndex);
++ // -- GODOT end --
+ }
+
+ void TaskScheduler::reset() {
+@@ -330,7 +335,10 @@ namespace embree
+ return thread->scheduler->cancellingException == nullptr;
+ }
+
+- std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
++// -- GODOT start --
++// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
++ void TaskScheduler::thread_loop(size_t threadIndex)
++// -- GODOT end --
+ {
+ /* allocate thread structure */
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+@@ -353,9 +361,10 @@ namespace embree
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+- std::exception_ptr except = nullptr;
+- if (cancellingException != nullptr) except = cancellingException;
+-
++ // -- GODOT start --
++ // std::exception_ptr except = nullptr;
++ // if (cancellingException != nullptr) except = cancellingException;
++ // -- GODOT end --
+ /* wait for all threads to terminate */
+ threadCounter--;
+ #if defined(__WIN32__)
+@@ -373,7 +382,10 @@ namespace embree
+ yield();
+ #endif
+ }
+- return except;
++ // -- GODOT start --
++ // return except;
++ return;
++ // -- GODOT end --
+ }
+
+ bool TaskScheduler::steal_from_other_threads(Thread& thread)
+diff --git a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h
+index c2a9391aea..8bd70b2b8c 100644
+--- a/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h
++++ b/thirdparty/embree-aarch64/common/tasking/taskschedulerinternal.h
+@@ -123,7 +123,10 @@ namespace embree
+ {
+ size_t ofs = bytes + ((align - stackPtr) & (align-1));
+ if (stackPtr + ofs > CLOSURE_STACK_SIZE)
+- throw std::runtime_error("closure stack overflow");
++ // -- GODOT start --
++ // throw std::runtime_error("closure stack overflow");
++ abort();
++ // -- GODOT end --
+ stackPtr += ofs;
+ return &stack[stackPtr-bytes];
+ }
+@@ -132,7 +135,10 @@ namespace embree
+ __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure)
+ {
+ if (right >= TASK_STACK_SIZE)
+- throw std::runtime_error("task stack overflow");
++ // -- GODOT start --
++ // throw std::runtime_error("task stack overflow");
++ abort();
++ // -- GODOT end --
+
+ /* allocate new task on right side of stack */
+ size_t oldStackPtr = stackPtr;
+@@ -239,7 +245,10 @@ namespace embree
+ void wait_for_threads(size_t threadCount);
+
+ /*! thread loop for all worker threads */
+- std::exception_ptr thread_loop(size_t threadIndex);
++ // -- GODOT start --
++ // std::exception_ptr thread_loop(size_t threadIndex);
++ void thread_loop(size_t threadIndex);
++ // -- GODOT end --
+
+ /*! steals a task from a different thread */
+ bool steal_from_other_threads(Thread& thread);
+diff --git a/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp
+index 20cdd2d320..aa56035026 100644
+--- a/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp
++++ b/thirdparty/embree-aarch64/kernels/bvh/bvh_statistics.cpp
+@@ -150,7 +150,10 @@ namespace embree
+ }
+ }
+ else {
+- throw std::runtime_error("not supported node type in bvh_statistics");
++ // -- GODOT start --
++ // throw std::runtime_error("not supported node type in bvh_statistics");
++ abort();
++ // -- GODOT end --
+ }
+ return s;
+ }
+diff --git a/thirdparty/embree-aarch64/kernels/common/rtcore.cpp b/thirdparty/embree-aarch64/kernels/common/rtcore.cpp
+index ee5c37b238..625fbf6d4f 100644
+--- a/thirdparty/embree-aarch64/kernels/common/rtcore.cpp
++++ b/thirdparty/embree-aarch64/kernels/common/rtcore.cpp
+@@ -230,7 +230,10 @@ RTC_NAMESPACE_BEGIN;
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH)
+- throw std::runtime_error("invalid build quality");
++ // -- GODOT start --
++ // throw std::runtime_error("invalid build quality");
++ abort();
++ // -- GODOT end --
+ scene->setBuildQuality(quality);
+ RTC_CATCH_END2(scene);
+ }
+@@ -1383,7 +1386,10 @@ RTC_NAMESPACE_BEGIN;
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH &&
+ quality != RTC_BUILD_QUALITY_REFIT)
+- throw std::runtime_error("invalid build quality");
++ // -- GODOT start --
++ // throw std::runtime_error("invalid build quality");
++ abort();
++ // -- GODOT end --
+ geometry->setBuildQuality(quality);
+ RTC_CATCH_END2(geometry);
+ }
+diff --git a/thirdparty/embree-aarch64/kernels/common/rtcore.h b/thirdparty/embree-aarch64/kernels/common/rtcore.h
+index 6583d12d57..4b070e122b 100644
+--- a/thirdparty/embree-aarch64/kernels/common/rtcore.h
++++ b/thirdparty/embree-aarch64/kernels/common/rtcore.h
+@@ -25,52 +25,58 @@ namespace embree
+ #endif
+
+ /*! Macros used in the rtcore API implementation */
+-#define RTC_CATCH_BEGIN try {
++// -- GODOT start --
++// #define RTC_CATCH_BEGIN try {
++#define RTC_CATCH_BEGIN
+
+-#define RTC_CATCH_END(device) \
+- } catch (std::bad_alloc&) { \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- } catch (rtcore_error& e) { \
+- Device::process_error(device,e.error,e.what()); \
+- } catch (std::exception& e) { \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- } catch (...) { \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- }
++// #define RTC_CATCH_END(device) \
++// } catch (std::bad_alloc&) { \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// } catch (rtcore_error& e) { \
++// Device::process_error(device,e.error,e.what()); \
++// } catch (std::exception& e) { \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// } catch (...) { \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// }
++#define RTC_CATCH_END(device)
+
+-#define RTC_CATCH_END2(scene) \
+- } catch (std::bad_alloc&) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- } catch (rtcore_error& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,e.error,e.what()); \
+- } catch (std::exception& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- } catch (...) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- }
++// #define RTC_CATCH_END2(scene) \
++// } catch (std::bad_alloc&) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// } catch (rtcore_error& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,e.error,e.what()); \
++// } catch (std::exception& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// } catch (...) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// }
++#define RTC_CATCH_END2(scene)
+
+-#define RTC_CATCH_END2_FALSE(scene) \
+- } catch (std::bad_alloc&) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- return false; \
+- } catch (rtcore_error& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,e.error,e.what()); \
+- return false; \
+- } catch (std::exception& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- return false; \
+- } catch (...) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- return false; \
+- }
++// #define RTC_CATCH_END2_FALSE(scene) \
++// } catch (std::bad_alloc&) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// return false; \
++// } catch (rtcore_error& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,e.error,e.what()); \
++// return false; \
++// } catch (std::exception& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// return false; \
++// } catch (...) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// return false; \
++// }
++#define RTC_CATCH_END2_FALSE(scene) return false;
++// -- GODOT end --
+
+ #define RTC_VERIFY_HANDLE(handle) \
+ if (handle == nullptr) { \
+@@ -97,28 +103,38 @@ namespace embree
+ #define RTC_TRACE(x)
+ #endif
+
+- /*! used to throw embree API errors */
+- struct rtcore_error : public std::exception
+- {
+- __forceinline rtcore_error(RTCError error, const std::string& str)
+- : error(error), str(str) {}
+-
+- ~rtcore_error() throw() {}
+-
+- const char* what () const throw () {
+- return str.c_str();
+- }
+-
+- RTCError error;
+- std::string str;
+- };
++// -- GODOT begin --
++// /*! used to throw embree API errors */
++// struct rtcore_error : public std::exception
++// {
++// __forceinline rtcore_error(RTCError error, const std::string& str)
++// : error(error), str(str) {}
++//
++// ~rtcore_error() throw() {}
++//
++// const char* what () const throw () {
++// return str.c_str();
++// }
++//
++// RTCError error;
++// std::string str;
++// };
++// -- GODOT end --
+
+ #if defined(DEBUG) // only report file and line in debug mode
++ // -- GODOT begin --
++ // #define throw_RTCError(error,str) \
++ // throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define throw_RTCError(error,str) \
+- throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
++ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ // -- GODOT end --
+ #else
++ // -- GODOT begin --
++ // #define throw_RTCError(error,str) \
++ // throw rtcore_error(error,str);
+ #define throw_RTCError(error,str) \
+- throw rtcore_error(error,str);
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #define RTC_BUILD_ARGUMENTS_HAS(settings,member) \
+diff --git a/thirdparty/embree-aarch64/kernels/common/scene.cpp b/thirdparty/embree-aarch64/kernels/common/scene.cpp
+index e75aa968f9..1e23aeb415 100644
+--- a/thirdparty/embree-aarch64/kernels/common/scene.cpp
++++ b/thirdparty/embree-aarch64/kernels/common/scene.cpp
+@@ -800,16 +800,18 @@ namespace embree
+ }
+
+ /* initiate build */
+- try {
++ // -- GODOT start --
++ // try {
+ scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join);
+- }
+- catch (...) {
+- accels_clear();
+- updateInterface();
+- Lock<MutexSys> lock(schedulerMutex);
+- this->scheduler = nullptr;
+- throw;
+- }
++ // }
++ // catch (...) {
++ // accels_clear();
++ // updateInterface();
++ // Lock<MutexSys> lock(schedulerMutex);
++ // this->scheduler = nullptr;
++ // throw;
++ // }
++ // -- GODOT end --
+ }
+
+ #endif
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 73fa3c62a2..189de6cc1f 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -46,6 +46,7 @@
class ENetGodotSocket {
public:
virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
+ virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) = 0;
virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
@@ -64,8 +65,7 @@ class ENetUDP : public ENetGodotSocket {
private:
Ref<NetSocket> sock;
- IP_Address address;
- uint16_t port = 0;
+ IP_Address local_address;
bool bound = false;
public:
@@ -80,10 +80,13 @@ public:
}
Error bind(IP_Address p_ip, uint16_t p_port) {
- address = p_ip;
- port = p_port;
+ local_address = p_ip;
bound = true;
- return sock->bind(address, port);
+ return sock->bind(p_ip, p_port);
+ }
+
+ Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ return sock->get_socket_address(r_ip, r_port);
}
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
@@ -142,6 +145,7 @@ public:
void close() {
sock->close();
+ local_address.clear();
}
};
@@ -153,6 +157,7 @@ class ENetDTLSClient : public ENetGodotSocket {
bool verify = false;
String for_hostname;
Ref<X509Certificate> cert;
+ IP_Address local_address;
public:
ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
@@ -161,9 +166,11 @@ public:
cert = p_cert;
udp.instance();
dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create());
- p_base->close();
if (p_base->bound) {
- bind(p_base->address, p_base->port);
+ uint16_t port;
+ p_base->get_socket_address(&local_address, &port);
+ p_base->close();
+ bind(local_address, port);
}
}
@@ -172,7 +179,17 @@ public:
}
Error bind(IP_Address p_ip, uint16_t p_port) {
- return udp->listen(p_port, p_ip);
+ local_address = p_ip;
+ return udp->bind(p_port, p_ip);
+ }
+
+ Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ if (!udp->is_bound()) {
+ return ERR_UNCONFIGURED;
+ }
+ *r_ip = local_address;
+ *r_port = udp->get_local_port();
+ return OK;
}
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
@@ -211,7 +228,7 @@ public:
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(p_len < r_read, ERR_OUT_OF_MEMORY);
- copymem(p_buffer, buffer, r_read);
+ memcpy(p_buffer, buffer, r_read);
r_ip = udp->get_packet_address();
r_port = udp->get_packet_port();
return err;
@@ -233,13 +250,16 @@ class ENetDTLSServer : public ENetGodotSocket {
Ref<UDPServer> udp_server;
Map<String, Ref<PacketPeerDTLS>> peers;
int last_service = 0;
+ IP_Address local_address;
public:
ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
udp_server.instance();
- p_base->close();
if (p_base->bound) {
- bind(p_base->address, p_base->port);
+ uint16_t port;
+ p_base->get_socket_address(&local_address, &port);
+ p_base->close();
+ bind(local_address, port);
}
server = Ref<DTLSServer>(DTLSServer::create());
server->setup(p_key, p_cert);
@@ -254,9 +274,19 @@ public:
}
Error bind(IP_Address p_ip, uint16_t p_port) {
+ local_address = p_ip;
return udp_server->listen(p_port, p_ip);
}
+ Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ if (!udp_server->is_listening()) {
+ return ERR_UNCONFIGURED;
+ }
+ *r_ip = local_address;
+ *r_port = udp_server->get_local_port();
+ return OK;
+ }
+
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
String key = String(p_ip) + ":" + itos(p_port);
ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
@@ -315,7 +345,7 @@ public:
Vector<String> s = E->key().rsplit(":", false, 1);
ERR_CONTINUE(s.size() != 2); // BUG!
- copymem(p_buffer, buffer, r_read);
+ memcpy(p_buffer, buffer, r_read);
r_ip = s[0];
r_port = s[1].to_int();
break; // err = OK
@@ -341,6 +371,7 @@ public:
peers.clear();
udp_server->stop();
server->stop();
+ local_address.clear();
}
};
@@ -493,15 +524,26 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
return read;
}
+int enet_socket_get_address (ENetSocket socket, ENetAddress * address) {
+ IP_Address ip;
+ uint16_t port;
+ ENetGodotSocket *sock = (ENetGodotSocket *)socket;
+
+ if (sock->get_socket_address(&ip, &port) != OK) {
+ return -1;
+ }
+
+ enet_address_set_ip(address, ip.get_ipv6(), 16);
+ address->port = port;
+
+ return 0;
+}
+
// Not implemented
int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) {
return 0; // do we need this function?
}
-int enet_socket_get_address(ENetSocket socket, ENetAddress *address) {
- return -1; // do we need this function?
-}
-
int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {
return -1;
}
diff --git a/thirdparty/etc2comp/AUTHORS b/thirdparty/etc2comp/AUTHORS
deleted file mode 100644
index e78a7f4d21..0000000000
--- a/thirdparty/etc2comp/AUTHORS
+++ /dev/null
@@ -1,7 +0,0 @@
-# This is the list of Etc2Comp authors for copyright purposes.
-#
-# This does not necessarily list everyone who has contributed code, since in
-# some cases, their employer may be the copyright holder. To see the full list
-# of contributors, see the revision history in source control.
-Google Inc.
-Blue Shift Inc.
diff --git a/thirdparty/etc2comp/Etc.cpp b/thirdparty/etc2comp/Etc.cpp
deleted file mode 100644
index a5ee706048..0000000000
--- a/thirdparty/etc2comp/Etc.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcConfig.h"
-#include "Etc.h"
-#include "EtcFilter.h"
-
-#include <string.h>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- // C-style inteface to the encoder
- //
- void Encode(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned char **a_ppaucEncodingBits,
- unsigned int *a_puiEncodingBitsBytes,
- unsigned int *a_puiExtendedWidth,
- unsigned int *a_puiExtendedHeight,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput)
- {
-
- Image image(a_pafSourceRGBA, a_uiSourceWidth,
- a_uiSourceHeight,
- a_eErrMetric);
- image.m_bVerboseOutput = a_bVerboseOutput;
- image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
-
- *a_ppaucEncodingBits = image.GetEncodingBits();
- *a_puiEncodingBitsBytes = image.GetEncodingBitsBytes();
- *a_puiExtendedWidth = image.GetExtendedWidth();
- *a_puiExtendedHeight = image.GetExtendedHeight();
- *a_piEncodingTime_ms = image.GetEncodingTimeMs();
- }
-
- void EncodeMipmaps(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned int a_uiMaxMipmaps,
- unsigned int a_uiMipFilterFlags,
- RawImage* a_pMipmapImages,
- int *a_piEncodingTime_ms,
- bool a_bVerboseOutput)
- {
- auto mipWidth = a_uiSourceWidth;
- auto mipHeight = a_uiSourceHeight;
- int totalEncodingTime = 0;
- for(unsigned int mip = 0; mip < a_uiMaxMipmaps && mipWidth >= 1 && mipHeight >= 1; mip++)
- {
- float* pImageData = nullptr;
- float* pMipImage = nullptr;
-
- if(mip == 0)
- {
- pImageData = a_pafSourceRGBA;
- }
- else
- {
- pMipImage = new float[mipWidth*mipHeight*4];
- if(FilterTwoPass(a_pafSourceRGBA, a_uiSourceWidth, a_uiSourceHeight, pMipImage, mipWidth, mipHeight, a_uiMipFilterFlags, Etc::FilterLanczos3) )
- {
- pImageData = pMipImage;
- }
- }
-
- if ( pImageData )
- {
-
- Image image(pImageData, mipWidth, mipHeight, a_eErrMetric);
-
- image.m_bVerboseOutput = a_bVerboseOutput;
- image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
-
- a_pMipmapImages[mip].paucEncodingBits = std::shared_ptr<unsigned char>(image.GetEncodingBits(), [](unsigned char *p) { delete[] p; });
- a_pMipmapImages[mip].uiEncodingBitsBytes = image.GetEncodingBitsBytes();
- a_pMipmapImages[mip].uiExtendedWidth = image.GetExtendedWidth();
- a_pMipmapImages[mip].uiExtendedHeight = image.GetExtendedHeight();
-
- totalEncodingTime += image.GetEncodingTimeMs();
- }
-
- if(pMipImage)
- {
- delete[] pMipImage;
- }
-
- if (!pImageData)
- {
- break;
- }
-
- mipWidth >>= 1;
- mipHeight >>= 1;
- }
-
- *a_piEncodingTime_ms = totalEncodingTime;
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/Etc.h b/thirdparty/etc2comp/Etc.h
deleted file mode 100644
index 439388d649..0000000000
--- a/thirdparty/etc2comp/Etc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcConfig.h"
-#include "EtcImage.h"
-#include "EtcColor.h"
-#include "EtcErrorMetric.h"
-#include <memory>
-
-#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f)
-#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f)
-#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f)
-
-namespace Etc
-{
- class Block4x4EncodingBits;
-
- struct RawImage
- {
- int uiExtendedWidth;
- int uiExtendedHeight;
- unsigned int uiEncodingBitsBytes;
- std::shared_ptr<unsigned char> paucEncodingBits;
- };
-
-
-
- // C-style inteface to the encoder
- void Encode(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uimaxJobs,
- unsigned char **a_ppaucEncodingBits,
- unsigned int *a_puiEncodingBitsBytes,
- unsigned int *a_puiExtendedWidth,
- unsigned int *a_puiExtendedHeight,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
-
- void EncodeMipmaps(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned int a_uiMaxMipmaps,
- unsigned int a_uiMipFilterFlags,
- RawImage* a_pMipmaps,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp
deleted file mode 100644
index 3082fe60db..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4.cpp
-
-Implements the state associated with each 4x4 block of pixels in an image
-
-Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an
-alpha of NAN
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcColor.h"
-#include "EtcImage.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcBlock4x4Encoding_RGBA8.h"
-#include "EtcBlock4x4Encoding_RGB8A1.h"
-#include "EtcBlock4x4Encoding_R11.h"
-#include "EtcBlock4x4Encoding_RG11.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
- // ETC pixels are scanned vertically.
- // this mapping is for when someone wants to scan the ETC pixels horizontally
- const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4::Block4x4(void)
- {
- m_pimageSource = nullptr;
- m_uiSourceH = 0;
- m_uiSourceV = 0;
-
- m_sourcealphamix = SourceAlphaMix::UNKNOWN;
- m_boolBorderPixels = false;
- m_boolPunchThroughPixels = false;
-
- m_pencoding = nullptr;
-
- m_errormetric = ErrorMetric::NUMERIC;
-
- }
- Block4x4::~Block4x4()
- {
- m_pimageSource = nullptr;
- if (m_pencoding)
- {
- delete m_pencoding;
- m_pencoding = nullptr;
- }
- }
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding from a source image
- // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
- // a_paucEncodingBits is the place to store the final encoding
- // a_errormetric is used for finding the best encoding
- //
- void Block4x4::InitFromSource(Image *a_pimageSource,
- unsigned int a_uiSourceH, unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric)
- {
-
- Block4x4();
-
- m_pimageSource = a_pimageSource;
- m_uiSourceH = a_uiSourceH;
- m_uiSourceV = a_uiSourceV;
- m_errormetric = a_errormetric;
-
- SetSourcePixels();
-
- // set block encoder function
- switch (m_pimageSource->GetFormat())
- {
- case Image::Format::ETC1:
- m_pencoding = new Block4x4Encoding_ETC1;
- break;
-
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_pencoding = new Block4x4Encoding_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- if (a_errormetric == RGBX)
- {
- m_pencoding = new Block4x4Encoding_RGBA8;
- }
- else
- {
- switch (m_sourcealphamix)
- {
- case SourceAlphaMix::OPAQUE:
- m_pencoding = new Block4x4Encoding_RGBA8_Opaque;
- break;
-
- case SourceAlphaMix::TRANSPARENT:
- m_pencoding = new Block4x4Encoding_RGBA8_Transparent;
- break;
-
- case SourceAlphaMix::TRANSLUCENT:
- m_pencoding = new Block4x4Encoding_RGBA8;
- break;
-
- default:
- assert(0);
- break;
- }
- break;
- }
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- switch (m_sourcealphamix)
- {
- case SourceAlphaMix::OPAQUE:
- m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
- break;
-
- case SourceAlphaMix::TRANSPARENT:
- m_pencoding = new Block4x4Encoding_RGB8A1_Transparent;
- break;
-
- case SourceAlphaMix::TRANSLUCENT:
- if (m_boolPunchThroughPixels)
- {
- m_pencoding = new Block4x4Encoding_RGB8A1;
- }
- else
- {
- m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
- }
- break;
-
- default:
- assert(0);
- break;
- }
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- m_pencoding = new Block4x4Encoding_R11;
- break;
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- m_pencoding = new Block4x4Encoding_RG11;
- break;
- default:
- assert(0);
- break;
- }
-
- m_pencoding->InitFromSource(this, m_afrgbaSource,
- a_paucEncodingBits, a_errormetric);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization of encoding state from a prior encoding using encoding bits
- // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
- // a_paucEncodingBits is the place to read the prior encoding
- // a_imageformat is used to determine how to interpret a_paucEncodingBits
- // a_errormetric was used for the prior encoding
- //
- void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat,
- unsigned int a_uiSourceH, unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- Image *a_pimageSource,
- ErrorMetric a_errormetric)
- {
- Block4x4();
-
- m_pimageSource = a_pimageSource;
- m_uiSourceH = a_uiSourceH;
- m_uiSourceV = a_uiSourceV;
- m_errormetric = a_errormetric;
-
- SetSourcePixels();
-
- // set block encoder function
- switch (a_imageformat)
- {
- case Image::Format::ETC1:
- m_pencoding = new Block4x4Encoding_ETC1;
- break;
-
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_pencoding = new Block4x4Encoding_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- m_pencoding = new Block4x4Encoding_RGBA8;
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- m_pencoding = new Block4x4Encoding_RGB8A1;
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- m_pencoding = new Block4x4Encoding_R11;
- break;
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- m_pencoding = new Block4x4Encoding_RG11;
- break;
- default:
- assert(0);
- break;
- }
-
- m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource,
- m_pimageSource->GetErrorMetric());
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set source pixels from m_pimageSource
- // set m_alphamix
- //
- void Block4x4::SetSourcePixels(void)
- {
-
- Image::Format imageformat = m_pimageSource->GetFormat();
-
- // alpha census
- unsigned int uiTransparentSourcePixels = 0;
- unsigned int uiOpaqueSourcePixels = 0;
-
- // copy source to consecutive memory locations
- // convert from image horizontal scan to block vertical scan
- unsigned int uiPixel = 0;
- for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++)
- {
- unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH;
-
- for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++)
- {
- unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV;
-
- ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV);
-
- // if pixel extends beyond source image because of block padding
- if (pfrgbaSource == nullptr)
- {
- m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel
- m_boolBorderPixels = true;
- uiTransparentSourcePixels++;
- }
- else
- {
- //get teh current pixel data, and store some of the attributes
- //before capping values to fit the encoder type
-
- m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA();
-
- if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
- {
- m_pimageSource->m_iNumOpaquePixels++;
- }
- else if (m_afrgbaSource[uiPixel].fA == 0.0f)
- {
- m_pimageSource->m_iNumTransparentPixels++;
- }
- else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f)
- {
- m_pimageSource->m_iNumTranslucentPixels++;
- }
- else
- {
- m_pimageSource->m_numOutOfRangeValues.fA++;
- }
-
- if (m_afrgbaSource[uiPixel].fR != 0.0f)
- {
- m_pimageSource->m_numColorValues.fR++;
- //make sure we are getting a float between 0-1
- if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fR++;
- }
- }
-
- if (m_afrgbaSource[uiPixel].fG != 0.0f)
- {
- m_pimageSource->m_numColorValues.fG++;
- if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fG++;
- }
- }
- if (m_afrgbaSource[uiPixel].fB != 0.0f)
- {
- m_pimageSource->m_numColorValues.fB++;
- if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fB++;
- }
- }
- // for formats with no alpha, set source alpha to 1
- if (imageformat == Image::Format::ETC1 ||
- imageformat == Image::Format::RGB8 ||
- imageformat == Image::Format::SRGB8)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- }
-
- if (imageformat == Image::Format::R11 ||
- imageformat == Image::Format::SIGNED_R11)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- m_afrgbaSource[uiPixel].fG = 0.0f;
- m_afrgbaSource[uiPixel].fB = 0.0f;
- }
-
- if (imageformat == Image::Format::RG11 ||
- imageformat == Image::Format::SIGNED_RG11)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- m_afrgbaSource[uiPixel].fB = 0.0f;
- }
-
-
- // for RGB8A1, set source alpha to 0.0 or 1.0
- // set punch through flag
- if (imageformat == Image::Format::RGB8A1 ||
- imageformat == Image::Format::SRGB8A1)
- {
- if (m_afrgbaSource[uiPixel].fA >= 0.5f)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- }
- else
- {
- m_afrgbaSource[uiPixel].fA = 0.0f;
- m_boolPunchThroughPixels = true;
- }
- }
-
- if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
- {
- uiOpaqueSourcePixels++;
- }
- else if (m_afrgbaSource[uiPixel].fA == 0.0f)
- {
- uiTransparentSourcePixels++;
- }
-
- }
-
- uiPixel += 1;
- }
- }
-
- if (uiOpaqueSourcePixels == PIXELS)
- {
- m_sourcealphamix = SourceAlphaMix::OPAQUE;
- }
- else if (uiTransparentSourcePixels == PIXELS)
- {
- m_sourcealphamix = SourceAlphaMix::TRANSPARENT;
- }
- else
- {
- m_sourcealphamix = SourceAlphaMix::TRANSLUCENT;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a name for the encoding mode
- //
- const char * Block4x4::GetEncodingModeName(void)
- {
-
- switch (m_pencoding->GetMode())
- {
- case Block4x4Encoding::MODE_ETC1:
- return "ETC1";
- case Block4x4Encoding::MODE_T:
- return "T";
- case Block4x4Encoding::MODE_H:
- return "H";
- case Block4x4Encoding::MODE_PLANAR:
- return "PLANAR";
- default:
- return "???";
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.h b/thirdparty/etc2comp/EtcBlock4x4.h
deleted file mode 100644
index 0fd30c598d..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColor.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcErrorMetric.h"
-#include "EtcImage.h"
-#include "EtcBlock4x4Encoding.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits;
-
- class Block4x4
- {
- public:
-
- static const unsigned int ROWS = 4;
- static const unsigned int COLUMNS = 4;
- static const unsigned int PIXELS = ROWS * COLUMNS;
-
- // the alpha mix for a 4x4 block of pixels
- enum class SourceAlphaMix
- {
- UNKNOWN,
- //
- OPAQUE, // all 1.0
- TRANSPARENT, // all 0.0 or NAN
- TRANSLUCENT // not all opaque or transparent
- };
-
- typedef void (Block4x4::*EncoderFunctionPtr)(void);
-
- Block4x4(void);
- ~Block4x4();
- void InitFromSource(Image *a_pimageSource,
- unsigned int a_uiSourceH,
- unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- void InitFromEtcEncodingBits(Image::Format a_imageformat,
- unsigned int a_uiSourceH,
- unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- Image *a_pimageSource,
- ErrorMetric a_errormetric);
-
- // return true if final iteration was performed
- inline void PerformEncodingIteration(float a_fEffort)
- {
- m_pencoding->PerformIteration(a_fEffort);
- }
-
- inline void SetEncodingBitsFromEncoding(void)
- {
- m_pencoding->SetEncodingBits();
- }
-
- inline unsigned int GetSourceH(void)
- {
- return m_uiSourceH;
- }
-
- inline unsigned int GetSourceV(void)
- {
- return m_uiSourceV;
- }
-
- inline float GetError(void)
- {
- return m_pencoding->GetError();
- }
-
- static const unsigned int s_auiPixelOrderHScan[PIXELS];
-
- inline ColorFloatRGBA * GetDecodedColors(void)
- {
- return m_pencoding->GetDecodedColors();
- }
-
- inline float * GetDecodedAlphas(void)
- {
- return m_pencoding->GetDecodedAlphas();
- }
-
- inline Block4x4Encoding::Mode GetEncodingMode(void)
- {
- return m_pencoding->GetMode();
- }
-
- inline bool GetFlip(void)
- {
- return m_pencoding->GetFlip();
- }
-
- inline bool IsDifferential(void)
- {
- return m_pencoding->IsDifferential();
- }
-
- inline ColorFloatRGBA * GetSource()
- {
- return m_afrgbaSource;
- }
-
- inline ErrorMetric GetErrorMetric()
- {
- return m_errormetric;
- }
-
- const char * GetEncodingModeName(void);
-
- inline Block4x4Encoding * GetEncoding(void)
- {
- return m_pencoding;
- }
-
- inline SourceAlphaMix GetSourceAlphaMix(void)
- {
- return m_sourcealphamix;
- }
-
- inline Image * GetImageSource(void)
- {
- return m_pimageSource;
- }
-
- inline bool HasBorderPixels(void)
- {
- return m_boolBorderPixels;
- }
-
- inline bool HasPunchThroughPixels(void)
- {
- return m_boolPunchThroughPixels;
- }
-
- private:
-
- void SetSourcePixels(void);
-
- Image *m_pimageSource;
- unsigned int m_uiSourceH;
- unsigned int m_uiSourceV;
- ErrorMetric m_errormetric;
- ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan
-
- SourceAlphaMix m_sourcealphamix;
- bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN)
- bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5
-
- Block4x4Encoding *m_pencoding;
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
deleted file mode 100644
index 7a9e68c4cf..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding.cpp
-
-Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a
-particular file format (e.g. ETC1, RGB8, RGBA8, R11)
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- //
- const float Block4x4Encoding::LUMA_WEIGHT = 3.0f;
- const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f;
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding::Block4x4Encoding(void)
- {
-
- m_pblockParent = nullptr;
-
- m_pafrgbaSource = nullptr;
-
- m_boolBorderPixels = false;
-
- m_fError = -1.0f;
-
- m_mode = MODE_UNKNOWN;
-
- m_uiEncodingIterations = 0;
- m_boolDone = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
- m_afDecodedAlphas[uiPixel] = -1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialize the generic encoding for a 4x4 block
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // init the decoded pixels to -1 to mark them as undefined
- // init the error to -1 to mark it as undefined
- //
- void Block4x4Encoding::Init(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pblockParent = a_pblockParent;
-
- m_pafrgbaSource = a_pafrgbaSource;
-
- m_boolBorderPixels = m_pblockParent->HasBorderPixels();
-
- m_fError = -1.0f;
-
- m_uiEncodingIterations = 0;
-
- m_errormetric = a_errormetric;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
- m_afDecodedAlphas[uiPixel] = -1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the error for the block by summing the pixel errors
- //
- void Block4x4Encoding::CalcBlockError(void)
- {
- m_fError = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the error between the source pixel and the decoded pixel
- // the error amount is base on the error metric
- //
- float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
- ColorFloatRGBA a_frgbaSourcePixel)
- {
-
- // if a border pixel
- if (isnan(a_frgbaSourcePixel.fA))
- {
- return 0.0f;
- }
-
- if (m_errormetric == ErrorMetric::RGBA)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR);
- float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG);
- float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB);
-
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
- }
- else if (m_errormetric == ErrorMetric::RGBX)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
- float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
- float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
- }
- else if (m_errormetric == ErrorMetric::REC709)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f;
- float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f)));
- float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f)));
-
- float fLuma2 = a_frgbaDecodedColor.fR*0.2126f +
- a_frgbaDecodedColor.fG*0.7152f +
- a_frgbaDecodedColor.fB*0.0722f;
- float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f)));
- float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f)));
-
- float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2;
- float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2;
- float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2;
-
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- // Favor Luma accuracy over Chroma, and Red over Blue
- return LUMA_WEIGHT*fDeltaL*fDeltaL +
- fDeltaCr*fDeltaCr +
- CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb +
- fDAlpha*fDAlpha;
- #if 0
- float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR;
- float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG;
- float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB;
- return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue;
-#endif
- }
- else if (m_errormetric == ErrorMetric::NORMALXYZ)
- {
- float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f;
- float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f;
- float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f;
-
- float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ);
-
- if (fDecodedLength < 0.5f)
- {
- return 1.0f;
- }
- else if (fDecodedLength == 0.0f)
- {
- fDecodedX = 1.0f;
- fDecodedY = 0.0f;
- fDecodedZ = 0.0f;
- }
- else
- {
- fDecodedX /= fDecodedLength;
- fDecodedY /= fDecodedLength;
- fDecodedZ /= fDecodedLength;
- }
-
- float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f;
- float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f;
- float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f;
-
- float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ);
-
- if (fSourceLength == 0.0f)
- {
- fSourceX = 1.0f;
- fSourceY = 0.0f;
- fSourceZ = 0.0f;
- }
- else
- {
- fSourceX /= fSourceLength;
- fSourceY /= fSourceLength;
- fSourceZ /= fSourceLength;
- }
-
- float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ;
- float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f);
- float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct;
-
- float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ;
- float fLength2Error = fabsf(1.0f - fLength2);
-
- float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
- float fErrorW = fDeltaW * fDeltaW;
-
- return fDotProductError + fLength2Error + fErrorW;
- }
- else // ErrorMetric::NUMERIC
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
- float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
- float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
- float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
-
- return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
-
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.h b/thirdparty/etc2comp/EtcBlock4x4Encoding.h
deleted file mode 100644
index c14c3b8616..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-#include "EtcErrorMetric.h"
-
-#include <assert.h>
-#include <float.h>
-
-namespace Etc
-{
- class Block4x4;
-
- // abstract base class for specific encodings
- class Block4x4Encoding
- {
- public:
-
- static const unsigned int ROWS = 4;
- static const unsigned int COLUMNS = 4;
- static const unsigned int PIXELS = ROWS * COLUMNS;
- static const float LUMA_WEIGHT;
- static const float CHROMA_BLUE_WEIGHT;
-
- typedef enum
- {
- MODE_UNKNOWN,
- //
- MODE_ETC1,
- MODE_T,
- MODE_H,
- MODE_PLANAR,
- MODE_R11,
- MODE_RG11,
- //
- MODES
- } Mode;
-
- Block4x4Encoding(void);
- //virtual ~Block4x4Encoding(void) =0;
- virtual ~Block4x4Encoding(void) {}
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0;
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric) = 0;
-
- // perform an iteration of the encoding
- // the first iteration must generate a complete, valid (if poor) encoding
- virtual void PerformIteration(float a_fEffort) = 0;
-
- void CalcBlockError(void);
-
- inline float GetError(void)
- {
- assert(m_fError >= 0.0f);
-
- return m_fError;
- }
-
- inline ColorFloatRGBA * GetDecodedColors(void)
- {
- return m_afrgbaDecodedColors;
- }
-
- inline float * GetDecodedAlphas(void)
- {
- return m_afDecodedAlphas;
- }
-
- virtual void SetEncodingBits(void) = 0;
-
- virtual bool GetFlip(void) = 0;
-
- virtual bool IsDifferential(void) = 0;
-
- virtual bool HasSeverelyBentDifferentialColors(void) const = 0;
-
- inline Mode GetMode(void)
- {
- return m_mode;
- }
-
- inline bool IsDone(void)
- {
- return m_boolDone;
- }
-
- inline void SetDoneIfPerfect()
- {
- if (GetError() == 0.0f)
- {
- m_boolDone = true;
- }
- }
-
- float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
- ColorFloatRGBA a_frgbaSourcePixel);
-
- protected:
-
- void Init(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- Block4x4 *m_pblockParent;
- ColorFloatRGBA *m_pafrgbaSource;
-
- bool m_boolBorderPixels; // if block has any border pixels
-
- ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha
- float m_afDecodedAlphas[PIXELS]; // decoded alpha component
- float m_fError; // error for RGBA relative to m_pafrgbaSource
-
- // intermediate encoding
- Mode m_mode;
-
- unsigned int m_uiEncodingIterations;
- bool m_boolDone; // all iterations have been done
- ErrorMetric m_errormetric;
-
- private:
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
deleted file mode 100644
index 4065700379..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ################################################################################
- // Block4x4EncodingBits
- // Base class for Block4x4EncodingBits_XXXX
- // ################################################################################
-
- class Block4x4EncodingBits
- {
- public:
-
- enum class Format
- {
- UNKNOWN,
- //
- RGB8,
- RGBA8,
- R11,
- RG11,
- RGB8A1,
- //
- FORMATS
- };
-
- static unsigned int GetBytesPerBlock(Format a_format)
- {
- switch (a_format)
- {
- case Format::RGB8:
- case Format::R11:
- case Format::RGB8A1:
- return 8;
- break;
-
- case Format::RGBA8:
- case Format::RG11:
- return 16;
- break;
-
- default:
- return 0;
- break;
- }
-
- }
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_RGB8
- // Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8
- // ################################################################################
-
- class Block4x4EncodingBits_RGB8
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
-
- inline Block4x4EncodingBits_RGB8(void)
- {
- assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK);
-
- for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++)
- {
- auc[uiByte] = 0;
- }
-
- }
-
- typedef struct
- {
- unsigned red2 : 4;
- unsigned red1 : 4;
- //
- unsigned green2 : 4;
- unsigned green1 : 4;
- //
- unsigned blue2 : 4;
- unsigned blue1 : 4;
- //
- unsigned flip : 1;
- unsigned diff : 1;
- unsigned cw2 : 3;
- unsigned cw1 : 3;
- //
- unsigned int selectors;
- } Individual;
-
- typedef struct
- {
- signed dred2 : 3;
- unsigned red1 : 5;
- //
- signed dgreen2 : 3;
- unsigned green1 : 5;
- //
- signed dblue2 : 3;
- unsigned blue1 : 5;
- //
- unsigned flip : 1;
- unsigned diff : 1;
- unsigned cw2 : 3;
- unsigned cw1 : 3;
- //
- unsigned int selectors;
- } Differential;
-
- typedef struct
- {
- unsigned red1b : 2;
- unsigned detect2 : 1;
- unsigned red1a : 2;
- unsigned detect1 : 3;
- //
- unsigned blue1 : 4;
- unsigned green1 : 4;
- //
- unsigned green2 : 4;
- unsigned red2 : 4;
- //
- unsigned db : 1;
- unsigned diff : 1;
- unsigned da : 2;
- unsigned blue2 : 4;
- //
- unsigned int selectors;
- } T;
-
- typedef struct
- {
- unsigned green1a : 3;
- unsigned red1 : 4;
- unsigned detect1 : 1;
- //
- unsigned blue1b : 2;
- unsigned detect3 : 1;
- unsigned blue1a : 1;
- unsigned green1b : 1;
- unsigned detect2 : 3;
- //
- unsigned green2a : 3;
- unsigned red2 : 4;
- unsigned blue1c : 1;
- //
- unsigned db : 1;
- unsigned diff : 1;
- unsigned da : 1;
- unsigned blue2 : 4;
- unsigned green2b : 1;
- //
- unsigned int selectors;
- } H;
-
- typedef struct
- {
- unsigned originGreen1 : 1;
- unsigned originRed : 6;
- unsigned detect1 : 1;
- //
- unsigned originBlue1 : 1;
- unsigned originGreen2 : 6;
- unsigned detect2 : 1;
- //
- unsigned originBlue3 : 2;
- unsigned detect4 : 1;
- unsigned originBlue2 : 2;
- unsigned detect3 : 3;
- //
- unsigned horizRed2 : 1;
- unsigned diff : 1;
- unsigned horizRed1 : 5;
- unsigned originBlue4 : 1;
- //
- unsigned horizBlue1: 1;
- unsigned horizGreen : 7;
- //
- unsigned vertRed1 : 3;
- unsigned horizBlue2 : 5;
- //
- unsigned vertGreen1 : 5;
- unsigned vertRed2 : 3;
- //
- unsigned vertBlue : 6;
- unsigned vertGreen2 : 2;
- } Planar;
-
- union
- {
- unsigned char auc[BYTES_PER_BLOCK];
- unsigned long int ul;
- Individual individual;
- Differential differential;
- T t;
- H h;
- Planar planar;
- };
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_A8
- // Encoding bits for the A portion of RGBA8
- // ################################################################################
-
- class Block4x4EncodingBits_A8
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
- static const unsigned int SELECTOR_BYTES = 6;
-
- typedef struct
- {
- unsigned base : 8;
- unsigned table : 4;
- unsigned multiplier : 4;
- unsigned selectors0 : 8;
- unsigned selectors1 : 8;
- unsigned selectors2 : 8;
- unsigned selectors3 : 8;
- unsigned selectors4 : 8;
- unsigned selectors5 : 8;
- } Data;
-
- Data data;
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_R11
- // Encoding bits for the R portion of R11
- // ################################################################################
-
- class Block4x4EncodingBits_R11
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
- static const unsigned int SELECTOR_BYTES = 6;
-
- typedef struct
- {
- unsigned base : 8;
- unsigned table : 4;
- unsigned multiplier : 4;
- unsigned selectors0 : 8;
- unsigned selectors1 : 8;
- unsigned selectors2 : 8;
- unsigned selectors3 : 8;
- unsigned selectors4 : 8;
- unsigned selectors5 : 8;
- } Data;
-
- Data data;
-
- };
-
- class Block4x4EncodingBits_RG11
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 16;
- static const unsigned int SELECTOR_BYTES = 12;
-
- typedef struct
- {
- //Red portion
- unsigned baseR : 8;
- unsigned tableIndexR : 4;
- unsigned multiplierR : 4;
- unsigned selectorsR0 : 8;
- unsigned selectorsR1 : 8;
- unsigned selectorsR2 : 8;
- unsigned selectorsR3 : 8;
- unsigned selectorsR4 : 8;
- unsigned selectorsR5 : 8;
- //Green portion
- unsigned baseG : 8;
- unsigned tableIndexG : 4;
- unsigned multiplierG : 4;
- unsigned selectorsG0 : 8;
- unsigned selectorsG1 : 8;
- unsigned selectorsG2 : 8;
- unsigned selectorsG3 : 8;
- unsigned selectorsG4 : 8;
- unsigned selectorsG5 : 8;
- } Data;
-
- Data data;
-
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
deleted file mode 100644
index a27f74c0d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_ETC1.cpp
-
-Block4x4Encoding_ETC1 is the encoder to use when targetting file format ETC1. This encoder is also
-used for the ETC1 subset of file format RGB8, RGBA8 and RGB8A1
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_ETC1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcDifferentialTrys.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // pixel processing order if the flip bit = 0 (horizontal split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip0[PIXELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
-
- // pixel processing order if the flip bit = 1 (vertical split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip1[PIXELS] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // pixel processing order for horizontal scan (ETC normally does a vertical scan)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
- // pixel indices for different block halves
- const unsigned int Block4x4Encoding_ETC1::s_auiLeftPixelMapping[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- const unsigned int Block4x4Encoding_ETC1::s_auiRightPixelMapping[8] = { 8, 9, 10, 11, 12, 13, 14, 15 };
- const unsigned int Block4x4Encoding_ETC1::s_auiTopPixelMapping[8] = { 0, 1, 4, 5, 8, 9, 12, 13 };
- const unsigned int Block4x4Encoding_ETC1::s_auiBottomPixelMapping[8] = { 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // CW ranges that the ETC1 decoders use
- // CW is basically a contrast for the different selector bits, since these values are offsets to the base color
- // the first axis in the array is indexed by the CW in the encoding bits
- // the second axis in the array is indexed by the selector bits
- float Block4x4Encoding_ETC1::s_aafCwTable[CW_RANGES][SELECTORS] =
- {
- { 2.0f / 255.0f, 8.0f / 255.0f, -2.0f / 255.0f, -8.0f / 255.0f },
- { 5.0f / 255.0f, 17.0f / 255.0f, -5.0f / 255.0f, -17.0f / 255.0f },
- { 9.0f / 255.0f, 29.0f / 255.0f, -9.0f / 255.0f, -29.0f / 255.0f },
- { 13.0f / 255.0f, 42.0f / 255.0f, -13.0f / 255.0f, -42.0f / 255.0f },
- { 18.0f / 255.0f, 60.0f / 255.0f, -18.0f / 255.0f, -60.0f / 255.0f },
- { 24.0f / 255.0f, 80.0f / 255.0f, -24.0f / 255.0f, -80.0f / 255.0f },
- { 33.0f / 255.0f, 106.0f / 255.0f, -33.0f / 255.0f, -106.0f / 255.0f },
- { 47.0f / 255.0f, 183.0f / 255.0f, -47.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_ETC1::Block4x4Encoding_ETC1(void)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = false;
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
- m_uiCW1 = 0;
- m_uiCW2 = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = 0;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_boolMostLikelyFlip = false;
-
- m_fError = -1.0f;
-
- m_fError1 = -1.0f;
- m_fError2 = -1.0f;
- m_boolSeverelyBentDifferentialColors = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- Block4x4Encoding_ETC1::~Block4x4Encoding_ETC1(void) {}
-
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_ETC1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_ETC1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = m_pencodingbitsRGB8->individual.diff;
- m_boolFlip = m_pencodingbitsRGB8->individual.flip;
- if (m_boolDiff)
- {
- int iR2 = (int)(m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2);
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = (int)(m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2);
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = (int)(m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2);
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- }
- else
- {
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red1, m_pencodingbitsRGB8->individual.green1, m_pencodingbitsRGB8->individual.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red2, m_pencodingbitsRGB8->individual.green2, m_pencodingbitsRGB8->individual.blue2);
- }
-
- m_uiCW1 = m_pencodingbitsRGB8->individual.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->individual.cw2;
-
- InitFromEncodingBits_Selectors();
-
- Decode();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // init the selectors from a prior encoding
- //
- void Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(void)
- {
-
- unsigned char *paucSelectors = (unsigned char *)&m_pencodingbitsRGB8->individual.selectors;
-
- for (unsigned int iPixel = 0; iPixel < PIXELS; iPixel++)
- {
- unsigned int uiByteMSB = (unsigned int)(1 - (iPixel / 8));
- unsigned int uiByteLSB = (unsigned int)(3 - (iPixel / 8));
- unsigned int uiShift = (unsigned int)(iPixel & 7);
-
- unsigned int uiSelectorMSB = (unsigned int)((paucSelectors[uiByteMSB] >> uiShift) & 1);
- unsigned int uiSelectorLSB = (unsigned int)((paucSelectors[uiByteLSB] >> uiShift) & 1);
-
- m_auiSelectors[iPixel] = (uiSelectorMSB << 1) + uiSelectorLSB;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_ETC1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryIndividual(m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryIndividual(!m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates1();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates2();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates3();
- if (a_fEffort <= 99.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_ETC1::PerformFirstIteration(void)
- {
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
-
- TryIndividual(m_boolMostLikelyFlip, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryIndividual(!m_boolMostLikelyFlip, 0);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // algorithm:
- // create a source average color for the Left, Right, Top and Bottom halves using the 8 pixels in each half
- // note: the "gray line" is the line of equal delta RGB that goes thru the average color
- // for each half:
- // see how close each of the 8 pixels are to the "gray line" that goes thru the source average color
- // create an error value that is the sum of the distances from the gray line
- // h_error is the sum of Left and Right errors
- // v_error is the sum of Top and Bottom errors
- //
- void Block4x4Encoding_ETC1::CalculateMostLikelyFlip(void)
- {
- static const bool DEBUG_PRINT = false;
-
- CalculateSourceAverages();
-
- float fLeftGrayErrorSum = 0.0f;
- float fRightGrayErrorSum = 0.0f;
- float fTopGrayErrorSum = 0.0f;
- float fBottomGrayErrorSum = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaLeft = &m_pafrgbaSource[uiPixel];
- ColorFloatRGBA *pfrgbaRight = &m_pafrgbaSource[uiPixel + 8];
- ColorFloatRGBA *pfrgbaTop = &m_pafrgbaSource[s_auiTopPixelMapping[uiPixel]];
- ColorFloatRGBA *pfrgbaBottom = &m_pafrgbaSource[s_auiBottomPixelMapping[uiPixel]];
-
- float fLeftGrayError = CalcGrayDistance2(*pfrgbaLeft, m_frgbaSourceAverageLeft);
- float fRightGrayError = CalcGrayDistance2(*pfrgbaRight, m_frgbaSourceAverageRight);
- float fTopGrayError = CalcGrayDistance2(*pfrgbaTop, m_frgbaSourceAverageTop);
- float fBottomGrayError = CalcGrayDistance2(*pfrgbaBottom, m_frgbaSourceAverageBottom);
-
- fLeftGrayErrorSum += fLeftGrayError;
- fRightGrayErrorSum += fRightGrayError;
- fTopGrayErrorSum += fTopGrayError;
- fBottomGrayErrorSum += fBottomGrayError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n%.2f %.2f\n", fLeftGrayErrorSum + fRightGrayErrorSum, fTopGrayErrorSum + fBottomGrayErrorSum);
- }
-
- m_boolMostLikelyFlip = (fTopGrayErrorSum + fBottomGrayErrorSum) < (fLeftGrayErrorSum + fRightGrayErrorSum);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate source pixel averages for each 2x2 quadrant in a 4x4 block
- // these are used to determine the averages for each of the 4 different halves (left, right, top, bottom)
- // ignore pixels that have alpha == NAN (these are border pixels outside of the source image)
- // weight the averages based on a pixel's alpha
- //
- void Block4x4Encoding_ETC1::CalculateSourceAverages(void)
- {
- static const bool DEBUG_PRINT = false;
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- if (m_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE || boolRGBX)
- {
- ColorFloatRGBA frgbaSumUL = m_pafrgbaSource[0] + m_pafrgbaSource[1] + m_pafrgbaSource[4] + m_pafrgbaSource[5];
- ColorFloatRGBA frgbaSumLL = m_pafrgbaSource[2] + m_pafrgbaSource[3] + m_pafrgbaSource[6] + m_pafrgbaSource[7];
- ColorFloatRGBA frgbaSumUR = m_pafrgbaSource[8] + m_pafrgbaSource[9] + m_pafrgbaSource[12] + m_pafrgbaSource[13];
- ColorFloatRGBA frgbaSumLR = m_pafrgbaSource[10] + m_pafrgbaSource[11] + m_pafrgbaSource[14] + m_pafrgbaSource[15];
-
- m_frgbaSourceAverageLeft = (frgbaSumUL + frgbaSumLL) * 0.125f;
- m_frgbaSourceAverageRight = (frgbaSumUR + frgbaSumLR) * 0.125f;
- m_frgbaSourceAverageTop = (frgbaSumUL + frgbaSumUR) * 0.125f;
- m_frgbaSourceAverageBottom = (frgbaSumLL + frgbaSumLR) * 0.125f;
- }
- else
- {
- float afSourceAlpha[PIXELS];
-
- // treat alpha NAN as 0.0f
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afSourceAlpha[uiPixel] = isnan(m_pafrgbaSource[uiPixel].fA) ?
- 0.0f :
- m_pafrgbaSource[uiPixel].fA;
- }
-
- ColorFloatRGBA afrgbaAlphaWeightedSource[PIXELS];
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afrgbaAlphaWeightedSource[uiPixel] = m_pafrgbaSource[uiPixel] * afSourceAlpha[uiPixel];
- }
-
- ColorFloatRGBA frgbaSumUL = afrgbaAlphaWeightedSource[0] +
- afrgbaAlphaWeightedSource[1] +
- afrgbaAlphaWeightedSource[4] +
- afrgbaAlphaWeightedSource[5];
-
- ColorFloatRGBA frgbaSumLL = afrgbaAlphaWeightedSource[2] +
- afrgbaAlphaWeightedSource[3] +
- afrgbaAlphaWeightedSource[6] +
- afrgbaAlphaWeightedSource[7];
-
- ColorFloatRGBA frgbaSumUR = afrgbaAlphaWeightedSource[8] +
- afrgbaAlphaWeightedSource[9] +
- afrgbaAlphaWeightedSource[12] +
- afrgbaAlphaWeightedSource[13];
-
- ColorFloatRGBA frgbaSumLR = afrgbaAlphaWeightedSource[10] +
- afrgbaAlphaWeightedSource[11] +
- afrgbaAlphaWeightedSource[14] +
- afrgbaAlphaWeightedSource[15];
-
- float fWeightSumUL = afSourceAlpha[0] +
- afSourceAlpha[1] +
- afSourceAlpha[4] +
- afSourceAlpha[5];
-
- float fWeightSumLL = afSourceAlpha[2] +
- afSourceAlpha[3] +
- afSourceAlpha[6] +
- afSourceAlpha[7];
-
- float fWeightSumUR = afSourceAlpha[8] +
- afSourceAlpha[9] +
- afSourceAlpha[12] +
- afSourceAlpha[13];
-
- float fWeightSumLR = afSourceAlpha[10] +
- afSourceAlpha[11] +
- afSourceAlpha[14] +
- afSourceAlpha[15];
-
- ColorFloatRGBA frgbaSumLeft = frgbaSumUL + frgbaSumLL;
- ColorFloatRGBA frgbaSumRight = frgbaSumUR + frgbaSumLR;
- ColorFloatRGBA frgbaSumTop = frgbaSumUL + frgbaSumUR;
- ColorFloatRGBA frgbaSumBottom = frgbaSumLL + frgbaSumLR;
-
- float fWeightSumLeft = fWeightSumUL + fWeightSumLL;
- float fWeightSumRight = fWeightSumUR + fWeightSumLR;
- float fWeightSumTop = fWeightSumUL + fWeightSumUR;
- float fWeightSumBottom = fWeightSumLL + fWeightSumLR;
-
- // check to see if there is at least 1 pixel with non-zero alpha
- // completely transparent block should not make it to this code
- assert((fWeightSumLeft + fWeightSumRight) > 0.0f);
- assert((fWeightSumTop + fWeightSumBottom) > 0.0f);
-
- if (fWeightSumLeft > 0.0f)
- {
- m_frgbaSourceAverageLeft = frgbaSumLeft * (1.0f/fWeightSumLeft);
- }
- if (fWeightSumRight > 0.0f)
- {
- m_frgbaSourceAverageRight = frgbaSumRight * (1.0f/fWeightSumRight);
- }
- if (fWeightSumTop > 0.0f)
- {
- m_frgbaSourceAverageTop = frgbaSumTop * (1.0f/fWeightSumTop);
- }
- if (fWeightSumBottom > 0.0f)
- {
- m_frgbaSourceAverageBottom = frgbaSumBottom * (1.0f/fWeightSumBottom);
- }
-
- if (fWeightSumLeft == 0.0f)
- {
- assert(fWeightSumRight > 0.0f);
- m_frgbaSourceAverageLeft = m_frgbaSourceAverageRight;
- }
- if (fWeightSumRight == 0.0f)
- {
- assert(fWeightSumLeft > 0.0f);
- m_frgbaSourceAverageRight = m_frgbaSourceAverageLeft;
- }
- if (fWeightSumTop == 0.0f)
- {
- assert(fWeightSumBottom > 0.0f);
- m_frgbaSourceAverageTop = m_frgbaSourceAverageBottom;
- }
- if (fWeightSumBottom == 0.0f)
- {
- assert(fWeightSumTop > 0.0f);
- m_frgbaSourceAverageBottom = m_frgbaSourceAverageTop;
- }
- }
-
-
-
- if (DEBUG_PRINT)
- {
- printf("\ntarget: [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f]\n",
- m_frgbaSourceAverageLeft.fR, m_frgbaSourceAverageLeft.fG, m_frgbaSourceAverageLeft.fB,
- m_frgbaSourceAverageRight.fR, m_frgbaSourceAverageRight.fG, m_frgbaSourceAverageRight.fB,
- m_frgbaSourceAverageTop.fR, m_frgbaSourceAverageTop.fG, m_frgbaSourceAverageTop.fB,
- m_frgbaSourceAverageBottom.fR, m_frgbaSourceAverageBottom.fG, m_frgbaSourceAverageBottom.fB);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // use a_iGrayOffset1 and a_iGrayOffset2 to offset the basecolor to search for degenerate encodings
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 individual mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryIndividual(bool a_boolFlip, unsigned int a_uiRadius)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- IndividualTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, a_uiRadius);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryIndividualHalf(&trys.m_half1);
- encodingTry.TryIndividualHalf(&trys.m_half2);
-
- // use the best of each half
- IndividualTrys::Try *ptryBest1 = trys.m_half1.m_ptryBest;
- IndividualTrys::Try *ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_fError = m_fError1 + m_fError2;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryIndividualHalf(IndividualTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 15);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 15);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 15);
-
- IndividualTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[IndividualTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best selector for each pixel based on a particular basecolor and CW that have been previously set
- // calculate the selectors for each half of the block separately
- // set the block error as the sum of each half's error
- //
- void Block4x4Encoding_ETC1::CalculateSelectors()
- {
- if (m_boolFlip)
- {
- CalculateHalfOfTheSelectors(0, s_auiTopPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiBottomPixelMapping);
- }
- else
- {
- CalculateHalfOfTheSelectors(0, s_auiLeftPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiRightPixelMapping);
- }
-
- m_fError = m_fError1 + m_fError2;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // choose best selectors for half of the block
- // calculate the error for half of the block
- //
- void Block4x4Encoding_ETC1::CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
- const unsigned int *pauiPixelMapping)
- {
- static const bool DEBUG_PRINT = false;
-
- ColorFloatRGBA *pfrgbaColor = a_uiHalf ? &m_frgbaColor2 : &m_frgbaColor1;
- unsigned int *puiCW = a_uiHalf ? &m_uiCW2 : &m_uiCW1;
-
- float *pfHalfError = a_uiHalf ? &m_fError2 : &m_fError1;
- *pfHalfError = FLT_MAX;
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- if (DEBUG_PRINT)
- {
- printf("\ncw=%u\n", uiCW);
- }
-
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- if (DEBUG_PRINT)
- {
- printf("\tsource [%.2f,%.2f,%.2f]\n", m_pafrgbaSource[pauiPixelMapping[uiPixel]].fR,
- m_pafrgbaSource[pauiPixelMapping[uiPixel]].fG, m_pafrgbaSource[pauiPixelMapping[uiPixel]].fB);
- }
-
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- float fDeltaRGB = s_aafCwTable[uiCW][uiSelector];
-
- frgbaDecodedPixel = (*pfrgbaColor + fDeltaRGB).ClampRGB();
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (DEBUG_PRINT)
- {
- printf("\tpixel %u, index %u [%.2f,%.2f,%.2f], error %.2f", uiPixel, uiSelector,
- frgbaDecodedPixel.fR,
- frgbaDecodedPixel.fG,
- frgbaDecodedPixel.fB,
- fPixelError);
- }
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- if (DEBUG_PRINT)
- {
- printf(" *");
- }
-
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n");
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
- if (DEBUG_PRINT)
- {
- printf("\terror %.2f\n", fCWError);
- }
-
- // if best CW so far
- if (fCWError < *pfHalfError)
- {
- *pfHalfError = fCWError;
- *puiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- m_auiSelectors[pauiPixelMapping[uiPixel]] = auiPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[pauiPixelMapping[uiPixel]] = afrgbaDecodedPixels[uiPixel];
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_ETC1::SetEncodingBits(void)
- {
- assert(m_mode == MODE_ETC1);
-
- if (m_boolDiff)
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = (unsigned int)iRed1;
- m_pencodingbitsRGB8->differential.green1 = (unsigned int)iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = (unsigned int)iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
- }
- else
- {
- m_pencodingbitsRGB8->individual.red1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->individual.red2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
- }
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- m_pencodingbitsRGB8->individual.diff = (unsigned int)m_boolDiff;
- m_pencodingbitsRGB8->individual.flip = (unsigned int)m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the selectors in the encoding bits
- //
- void Block4x4Encoding_ETC1::SetEncodingBits_Selectors(void)
- {
-
- m_pencodingbitsRGB8->individual.selectors = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiSelector = m_auiSelectors[uiPixel];
-
- // set index msb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector >> 1) << (uiPixel ^ 8);
-
- // set index lsb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector & 1) << ((16 + uiPixel) ^ 8);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_ETC1::Decode(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta = s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
deleted file mode 100644
index c0dc84d5d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcDifferentialTrys.h"
-#include "EtcIndividualTrys.h"
-
-namespace Etc
-{
-
- // base class for Block4x4Encoding_RGB8
- class Block4x4Encoding_ETC1 : public Block4x4Encoding
- {
- public:
-
- Block4x4Encoding_ETC1(void);
- virtual ~Block4x4Encoding_ETC1(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- inline virtual bool GetFlip(void)
- {
- return m_boolFlip;
- }
-
- inline virtual bool IsDifferential(void)
- {
- return m_boolDiff;
- }
-
- virtual void SetEncodingBits(void);
-
- void Decode(void);
-
- inline ColorFloatRGBA GetColor1(void) const
- {
- return m_frgbaColor1;
- }
-
- inline ColorFloatRGBA GetColor2(void) const
- {
- return m_frgbaColor2;
- }
-
- inline const unsigned int * GetSelectors(void) const
- {
- return m_auiSelectors;
- }
-
- inline unsigned int GetCW1(void) const
- {
- return m_uiCW1;
- }
-
- inline unsigned int GetCW2(void) const
- {
- return m_uiCW2;
- }
-
- inline bool HasSeverelyBentDifferentialColors(void) const
- {
- return m_boolSeverelyBentDifferentialColors;
- }
-
- protected:
-
- static const unsigned int s_auiPixelOrderFlip0[PIXELS];
- static const unsigned int s_auiPixelOrderFlip1[PIXELS];
- static const unsigned int s_auiPixelOrderHScan[PIXELS];
-
- static const unsigned int s_auiLeftPixelMapping[8];
- static const unsigned int s_auiRightPixelMapping[8];
- static const unsigned int s_auiTopPixelMapping[8];
- static const unsigned int s_auiBottomPixelMapping[8];
-
- static const unsigned int SELECTOR_BITS = 2;
- static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
-
- static const unsigned int CW_BITS = 3;
- static const unsigned int CW_RANGES = 1 << CW_BITS;
-
- static float s_aafCwTable[CW_RANGES][SELECTORS];
- static unsigned char s_aucDifferentialCwRange[256];
-
- static const int MAX_DIFFERENTIAL = 3;
- static const int MIN_DIFFERENTIAL = -4;
-
- void InitFromEncodingBits_Selectors(void);
-
- void PerformFirstIteration(void);
- void CalculateMostLikelyFlip(void);
-
- void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
- void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
-
- void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius);
- void TryIndividualHalf(IndividualTrys::Half *a_phalf);
-
- void TryDegenerates1(void);
- void TryDegenerates2(void);
- void TryDegenerates3(void);
- void TryDegenerates4(void);
-
- void CalculateSelectors();
- void CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
- const unsigned int *pauiPixelMapping);
-
- // calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line
- inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel,
- ColorFloatRGBA &r_frgbaTarget)
- {
- float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) +
- (r_frgbaPixel.fG - r_frgbaTarget.fG) +
- (r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f;
-
- ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB();
-
- float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR;
- float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG;
- float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB;
-
- return (fDR*fDR) + (fDG*fDG) + (fDB*fDB);
- }
-
- void SetEncodingBits_Selectors(void);
-
- // intermediate encoding
- bool m_boolDiff;
- bool m_boolFlip;
- ColorFloatRGBA m_frgbaColor1;
- ColorFloatRGBA m_frgbaColor2;
- unsigned int m_uiCW1;
- unsigned int m_uiCW2;
- unsigned int m_auiSelectors[PIXELS];
-
- // state shared between iterations
- ColorFloatRGBA m_frgbaSourceAverageLeft;
- ColorFloatRGBA m_frgbaSourceAverageRight;
- ColorFloatRGBA m_frgbaSourceAverageTop;
- ColorFloatRGBA m_frgbaSourceAverageBottom;
- bool m_boolMostLikelyFlip;
-
- // stats
- float m_fError1; // error for Etc1 half 1
- float m_fError2; // error for Etc1 half 2
- bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff;
-
- // final encoding
- Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8
-
- private:
-
- void CalculateSourceAverages(void);
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
deleted file mode 100644
index 4c012fbbf1..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_R11.cpp
-
-Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11).
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_R11.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // modifier values to use for R11, SR11, RG11 and SRG11
- float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]
- {
- { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
-
- { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
- { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
-
- { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
-
- { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
- { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
- { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_R11::Block4x4Encoding_R11(void)
- {
-
- m_pencodingbitsR11 = nullptr;
-
- }
-
- Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
- m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *)m_pencodingbitsR11,
- a_pafrgbaSource,
- a_errormetric);
-
- // init R11 portion
- {
- m_mode = MODE_R11;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base;
- }
- else
- {
- m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base;
- }
- m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier;
- m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table;
-
- unsigned long long int ulliSelectorBits = 0;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1);
- }
-
- // decode the red channel
- // calc red error
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fDecodedPixelData = 0.0f;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier,
- m_uiRedModifierTableIndex,
- m_auiRedSelectors[uiPixel]);
- }
- else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier,
- m_uiRedModifierTableIndex,
- m_auiRedSelectors[uiPixel]);
- }
- else
- {
- assert(0);
- }
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f);
- }
- CalcBlockError();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_R11::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
- m_mode = MODE_R11;
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- m_fError = FLT_MAX;
- m_fRedBlockError = FLT_MAX; // artificially high value
- CalculateR11(8, 0.0f, 0.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 1:
- CalculateR11(8, 2.0f, 1.0f);
- m_fError = m_fRedBlockError;
- if (a_fEffort <= 24.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 2:
- CalculateR11(8, 12.0f, 1.0f);
- m_fError = m_fRedBlockError;
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- CalculateR11(7, 6.0f, 1.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 4:
- CalculateR11(6, 3.0f, 1.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 5:
- CalculateR11(5, 1.0f, 0.0f);
- m_fError = m_fRedBlockError;
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base color, multiplier and selectors
- //
- // a_uiSelectorsUsed limits the number of selector combinations to try
- // a_fBaseRadius limits the range of base colors to try
- // a_fMultiplierRadius limits the range of multipliers to try
- //
- void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius)
- {
- // maps from virtual (monotonic) selector to ETC selector
- static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7};
-
- // find min/max red
- float fMinRed = 1.0f;
- float fMaxRed = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // ignore border pixels
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
- if (isnan(fAlpha))
- {
- continue;
- }
-
- float fRed = m_pafrgbaSource[uiPixel].fR;
-
- if (fRed < fMinRed)
- {
- fMinRed = fRed;
- }
- if (fRed > fMaxRed)
- {
- fMaxRed = fRed;
- }
- }
- assert(fMinRed <= fMaxRed);
-
- float fRedRange = (fMaxRed - fMinRed);
-
- // try each modifier table entry
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- for (unsigned int uiMinVirtualSelector = 0;
- uiMinVirtualSelector <= (8- a_uiSelectorsUsed);
- uiMinVirtualSelector++)
- {
- unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
-
- unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
- unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
- s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinRed + fCenterRatio*fRedRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
- float fRangeMultiplier = roundf(fRedRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 0.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestRedError[PIXELS];
- float afBestPixelRed[PIXELS];
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelRedError = FLT_MAX;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
-
- ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f);
-
- float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
-
- if (fPixelRedError < fBestPixelRedError)
- {
- fBestPixelRedError = fPixelRedError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestRedError[uiPixel] = fBestPixelRedError;
- afBestPixelRed[uiPixel] = fPixelRed;
- }
- }
- }
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestRedError[uiPixel];
- }
- if (fBlockError < m_fRedBlockError)
- {
- m_fRedBlockError = fBlockError;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_fRedBase = 255.0f * fBase;
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (fBase * 255) - 128;
- }
- else
- {
- assert(0);
- }
- m_fRedMultiplier = fMultiplier;
- m_uiRedModifierTableIndex = uiTableEntry;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel];
- float fBestPixelRed = afBestPixelRed[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f);
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
- }
- }
-
- }
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_R11::SetEncodingBits(void)
- {
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex;
- m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier);
-
- unsigned long long int ulliSelectorBits = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
- }
-
- m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40;
- m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32;
- m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24;
- m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16;
- m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8;
- m_pencodingbitsR11->data.selectors5 = ulliSelectorBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
deleted file mode 100644
index b40c1e0036..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_R11;
-
- // ################################################################################
- // Block4x4Encoding_R11
- // ################################################################################
-
- class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8
- {
- public:
-
- Block4x4Encoding_R11(void);
- virtual ~Block4x4Encoding_R11(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- inline float GetRedBase(void) const
- {
- return m_fRedBase;
- }
-
- inline float GetRedMultiplier(void) const
- {
- return m_fRedMultiplier;
- }
-
- inline int GetRedTableIndex(void) const
- {
- return m_uiRedModifierTableIndex;
- }
-
- inline const unsigned int * GetRedSelectors(void) const
- {
- return m_auiRedSelectors;
- }
-
- protected:
-
- static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
- static const unsigned int SELECTOR_BITS = 3;
- static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
-
- static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS];
-
- void CalculateR11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius);
-
-
-
-
- inline float DecodePixelRed(float a_fBase, float a_fMultiplier,
- unsigned int a_uiTableIndex, unsigned int a_uiSelector)
- {
- float fMultiplier = a_fMultiplier;
- if (fMultiplier <= 0.0f)
- {
- fMultiplier = 1.0f / 8.0f;
- }
-
- float fPixelRed = a_fBase * 8 + 4 +
- 8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255;
- fPixelRed /= 2047.0f;
-
- if (fPixelRed < 0.0f)
- {
- fPixelRed = 0.0f;
- }
- else if (fPixelRed > 1.0f)
- {
- fPixelRed = 1.0f;
- }
-
- return fPixelRed;
- }
-
- Block4x4EncodingBits_R11 *m_pencodingbitsR11;
-
- float m_fRedBase;
- float m_fRedMultiplier;
- float m_fRedBlockError;
- unsigned int m_uiRedModifierTableIndex;
- unsigned int m_auiRedSelectors[PIXELS];
-
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
deleted file mode 100644
index 417835db51..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RG11.cpp
-
-Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11).
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RG11.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RG11::Block4x4Encoding_RG11(void)
- {
- m_pencodingbitsRG11 = nullptr;
- }
-
- Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *)m_pencodingbitsRG11,
- a_pafrgbaSource,
- a_errormetric);
- m_fError = 0.0f;
-
- {
- m_mode = MODE_RG11;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR;
- m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG;
- }
- else
- {
- m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR;
- m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG;
- }
- m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR;
- m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG;
- m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR;
- m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG;
-
- unsigned long long int ulliSelectorBitsR = 0;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5;
-
- unsigned long long int ulliSelectorBitsG = 0;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5;
-
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1);
- m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1);
- }
-
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fRedDecodedData = 0.0f;
- float fGrnDecodedData = 0.0f;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
- fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
- }
- else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
- fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
- }
- else
- {
- assert(0);
- }
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f);
- }
-
- }
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RG11::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- m_fError = FLT_MAX;
- m_fGrnBlockError = FLT_MAX; // artificially high value
- m_fRedBlockError = FLT_MAX;
- CalculateR11(8, 0.0f, 0.0f);
- CalculateG11(8, 0.0f, 0.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 1:
- CalculateR11(8, 2.0f, 1.0f);
- CalculateG11(8, 2.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- if (a_fEffort <= 24.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 2:
- CalculateR11(8, 12.0f, 1.0f);
- CalculateG11(8, 12.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- CalculateR11(7, 6.0f, 1.0f);
- CalculateG11(7, 6.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 4:
- CalculateR11(6, 3.0f, 1.0f);
- CalculateG11(6, 3.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 5:
- CalculateR11(5, 1.0f, 0.0f);
- CalculateG11(5, 1.0f, 0.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base color, multiplier and selectors
- //
- // a_uiSelectorsUsed limits the number of selector combinations to try
- // a_fBaseRadius limits the range of base colors to try
- // a_fMultiplierRadius limits the range of multipliers to try
- //
- void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius)
- {
- // maps from virtual (monotonic) selector to etc selector
- static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 };
-
- // find min/max Grn
- float fMinGrn = 1.0f;
- float fMaxGrn = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // ignore border pixels
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
- if (isnan(fAlpha))
- {
- continue;
- }
-
- float fGrn = m_pafrgbaSource[uiPixel].fG;
-
- if (fGrn < fMinGrn)
- {
- fMinGrn = fGrn;
- }
- if (fGrn > fMaxGrn)
- {
- fMaxGrn = fGrn;
- }
- }
- assert(fMinGrn <= fMaxGrn);
-
- float fGrnRange = (fMaxGrn - fMinGrn);
-
- // try each modifier table entry
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- for (unsigned int uiMinVirtualSelector = 0;
- uiMinVirtualSelector <= (8 - a_uiSelectorsUsed);
- uiMinVirtualSelector++)
- {
- unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
-
- unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
- unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
- s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinGrn + fCenterRatio*fGrnRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
- float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 0.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestGrnError[PIXELS];
- float afBestPixelGrn[PIXELS];
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelGrnError = FLT_MAX;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- //DecodePixelRed is not red channel specific
- float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
-
- ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f);
-
- float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
-
- if (fPixelGrnError < fBestPixelGrnError)
- {
- fBestPixelGrnError = fPixelGrnError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestGrnError[uiPixel] = fBestPixelGrnError;
- afBestPixelGrn[uiPixel] = fPixelGrn;
- }
- }
- }
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestGrnError[uiPixel];
- }
-
- if (fBlockError < m_fGrnBlockError)
- {
- m_fGrnBlockError = fBlockError;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_fGrnBase = 255.0f * fBase;
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fGrnBase = (fBase * 255) - 128;
- }
- else
- {
- assert(0);
- }
- m_fGrnMultiplier = fMultiplier;
- m_uiGrnModifierTableIndex = uiTableEntry;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel];
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
- }
- }
-
- }
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RG11::SetEncodingBits(void)
- {
- unsigned long long int ulliSelectorBitsR = 0;
- unsigned long long int ulliSelectorBitsG = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
- ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift;
- }
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex;
- m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier);
-
- m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40;
- m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32;
- m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24;
- m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16;
- m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8;
- m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex;
- m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier);
-
- m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40;
- m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32;
- m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24;
- m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16;
- m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8;
- m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
deleted file mode 100644
index d4993b8c5f..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcBlock4x4Encoding_R11.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_RG11;
-
- // ################################################################################
- // Block4x4Encoding_RG11
- // ################################################################################
-
- class Block4x4Encoding_RG11 : public Block4x4Encoding_R11
- {
- float m_fGrnBase;
- float m_fGrnMultiplier;
- float m_fGrnBlockError;
- unsigned int m_auiGrnSelectors[PIXELS];
- unsigned int m_uiGrnModifierTableIndex;
- public:
-
- Block4x4Encoding_RG11(void);
- virtual ~Block4x4Encoding_RG11(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- Block4x4EncodingBits_RG11 *m_pencodingbitsRG11;
-
- void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius);
-
- inline float GetGrnBase(void) const
- {
- return m_fGrnBase;
- }
-
- inline float GetGrnMultiplier(void) const
- {
- return m_fGrnMultiplier;
- }
-
- inline int GetGrnTableIndex(void) const
- {
- return m_uiGrnModifierTableIndex;
- }
-
- inline const unsigned int * GetGrnSelectors(void) const
- {
- return m_auiGrnSelectors;
- }
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
deleted file mode 100644
index 5c7ebed788..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
+++ /dev/null
@@ -1,1730 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGB8.cpp
-
-Block4x4Encoding_RGB8 is the encoder to use for the ETC2 extensions when targetting file format RGB8.
-This encoder is also used for the ETC2 subset of file format RGBA8.
-
-Block4x4Encoding_ETC1 encodes the ETC1 subset of RGB8.
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-#include "EtcMath.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
- float Block4x4Encoding_RGB8::s_afTHDistanceTable[TH_DISTANCES] =
- {
- 3.0f / 255.0f,
- 6.0f / 255.0f,
- 11.0f / 255.0f,
- 16.0f / 255.0f,
- 23.0f / 255.0f,
- 32.0f / 255.0f,
- 41.0f / 255.0f,
- 64.0f / 255.0f
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8::Block4x4Encoding_RGB8(void)
- {
-
- m_pencodingbitsRGB8 = nullptr;
-
- }
-
- Block4x4Encoding_RGB8::~Block4x4Encoding_RGB8(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- // handle ETC1 modes
- Block4x4Encoding_ETC1::InitFromEncodingBits(a_pblockParent,
- a_paucEncodingBits, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- if (m_pencodingbitsRGB8->differential.diff)
- {
- int iRed1 = (int)m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = (int)m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = (int)m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- InitFromEncodingBits_Planar();
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_T(void)
- {
-
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_H(void)
- {
-
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if Planar mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(void)
- {
-
- m_mode = MODE_PLANAR;
-
- unsigned char ucOriginRed = m_pencodingbitsRGB8->planar.originRed;
- unsigned char ucOriginGreen = (unsigned char)((m_pencodingbitsRGB8->planar.originGreen1 << 6) +
- m_pencodingbitsRGB8->planar.originGreen2);
- unsigned char ucOriginBlue = (unsigned char)((m_pencodingbitsRGB8->planar.originBlue1 << 5) +
- (m_pencodingbitsRGB8->planar.originBlue2 << 3) +
- (m_pencodingbitsRGB8->planar.originBlue3 << 1) +
- m_pencodingbitsRGB8->planar.originBlue4);
-
- unsigned char ucHorizRed = (unsigned char)((m_pencodingbitsRGB8->planar.horizRed1 << 1) +
- m_pencodingbitsRGB8->planar.horizRed2);
- unsigned char ucHorizGreen = m_pencodingbitsRGB8->planar.horizGreen;
- unsigned char ucHorizBlue = (unsigned char)((m_pencodingbitsRGB8->planar.horizBlue1 << 5) +
- m_pencodingbitsRGB8->planar.horizBlue2);
-
- unsigned char ucVertRed = (unsigned char)((m_pencodingbitsRGB8->planar.vertRed1 << 3) +
- m_pencodingbitsRGB8->planar.vertRed2);
- unsigned char ucVertGreen = (unsigned char)((m_pencodingbitsRGB8->planar.vertGreen1 << 2) +
- m_pencodingbitsRGB8->planar.vertGreen2);
- unsigned char ucVertBlue = m_pencodingbitsRGB8->planar.vertBlue;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromR6G7B6(ucOriginRed, ucOriginGreen, ucOriginBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromR6G7B6(ucHorizRed, ucHorizGreen, ucHorizBlue);
- m_frgbaColor3 = ColorFloatRGBA::ConvertFromR6G7B6(ucVertRed, ucVertGreen, ucVertBlue);
-
- DecodePixels_Planar();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- Block4x4Encoding_ETC1::PerformFirstIteration();
- if (m_boolDone)
- {
- break;
- }
- TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- break;
- }
- TryTAndH(0);
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryIndividual(m_boolMostLikelyFlip, 1);
- break;
-
- case 3:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 4:
- Block4x4Encoding_ETC1::TryIndividual(!m_boolMostLikelyFlip, 1);
- break;
-
- case 5:
- TryPlanar(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryTAndH(1);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 9:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 10:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in Planar mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryPlanar(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- encodingTry.CalculatePlanarCornerColors();
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (a_uiRadius > 0)
- {
- encodingTry.TwiddlePlanar();
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode or H mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryTAndH(unsigned int a_uiRadius)
- {
-
- CalculateBaseColorsForTAndH();
-
- TryT(a_uiRadius);
-
- TryH(a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate original values for base colors
- // store them in m_frgbaOriginalColor1 and m_frgbaOriginalColor2
- //
- void Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(void)
- {
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- ColorFloatRGBA frgbaBlockAverage = (m_frgbaSourceAverageLeft + m_frgbaSourceAverageRight) * 0.5f;
-
- // find pixel farthest from average gray line
- unsigned int uiFarthestPixel = 0;
- float fFarthestGrayDistance2 = 0.0f;
- unsigned int uiTransparentPixels = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent
- if (m_pafrgbaSource[uiPixel].fA == 0.0f && !boolRGBX)
- {
- uiTransparentPixels++;
- }
- else
- {
- float fGrayDistance2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], frgbaBlockAverage);
-
- if (fGrayDistance2 > fFarthestGrayDistance2)
- {
- uiFarthestPixel = uiPixel;
- fFarthestGrayDistance2 = fGrayDistance2;
- }
- }
- }
- // a transparent block should not reach this method
- assert(uiTransparentPixels < PIXELS);
-
- // set the original base colors to:
- // half way to the farthest pixel and
- // the mirror color on the other side of the average
- ColorFloatRGBA frgbaOffset = (m_pafrgbaSource[uiFarthestPixel] - frgbaBlockAverage) * 0.5f;
- m_frgbaOriginalColor1_TAndH = (frgbaBlockAverage + frgbaOffset).QuantizeR4G4B4();
- m_frgbaOriginalColor2_TAndH = (frgbaBlockAverage - frgbaOffset).ClampRGB().QuantizeR4G4B4(); // the "other side" might be out of range
-
- // move base colors to find best fit
- for (unsigned int uiIteration = 0; uiIteration < 10; uiIteration++)
- {
- // find the center of pixels closest to each color
- float fPixelsCloserToColor1 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor1;
- float fPixelsCloserToColor2 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor2;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent pixels
- if (m_pafrgbaSource[uiPixel].fA == 0.0f)
- {
- continue;
- }
-
- float fGrayDistance2ToColor1 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor1_TAndH);
- float fGrayDistance2ToColor2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor2_TAndH);
-
- ColorFloatRGBA frgbaAlphaWeightedSource = m_pafrgbaSource[uiPixel] * m_pafrgbaSource[uiPixel].fA;
-
- if (fGrayDistance2ToColor1 <= fGrayDistance2ToColor2)
- {
- fPixelsCloserToColor1 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor1 = frgbSumPixelsCloserToColor1 + frgbaAlphaWeightedSource;
- }
- else
- {
- fPixelsCloserToColor2 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor2 = frgbSumPixelsCloserToColor2 + frgbaAlphaWeightedSource;
- }
- }
- if (fPixelsCloserToColor1 == 0.0f || fPixelsCloserToColor2 == 0.0f)
- {
- break;
- }
-
- ColorFloatRGBA frgbAvgColor1Pixels = (frgbSumPixelsCloserToColor1 * (1.0f / fPixelsCloserToColor1)).QuantizeR4G4B4();
- ColorFloatRGBA frgbAvgColor2Pixels = (frgbSumPixelsCloserToColor2 * (1.0f / fPixelsCloserToColor2)).QuantizeR4G4B4();
-
- if (frgbAvgColor1Pixels.fR == m_frgbaOriginalColor1_TAndH.fR &&
- frgbAvgColor1Pixels.fG == m_frgbaOriginalColor1_TAndH.fG &&
- frgbAvgColor1Pixels.fB == m_frgbaOriginalColor1_TAndH.fB &&
- frgbAvgColor2Pixels.fR == m_frgbaOriginalColor2_TAndH.fR &&
- frgbAvgColor2Pixels.fG == m_frgbaOriginalColor2_TAndH.fG &&
- frgbAvgColor2Pixels.fB == m_frgbaOriginalColor2_TAndH.fB)
- {
- break;
- }
-
- m_frgbaOriginalColor1_TAndH = frgbAvgColor1Pixels;
- m_frgbaOriginalColor2_TAndH = frgbAvgColor2Pixels;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = m_frgbaColor2;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryH_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // use linear regression to find the best fit for colors along the edges of the 4x4 block
- //
- void Block4x4Encoding_RGB8::CalculatePlanarCornerColors(void)
- {
- ColorFloatRGBA afrgbaRegression[MAX_PLANAR_REGRESSION_SIZE];
- ColorFloatRGBA frgbaSlope;
- ColorFloatRGBA frgbaOffset;
-
- // top edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[4];
- afrgbaRegression[2] = m_pafrgbaSource[8];
- afrgbaRegression[3] = m_pafrgbaSource[12];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = frgbaOffset;
- m_frgbaColor2 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // left edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[1];
- afrgbaRegression[2] = m_pafrgbaSource[2];
- afrgbaRegression[3] = m_pafrgbaSource[3];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = (m_frgbaColor1 + frgbaOffset) * 0.5f; // average with top edge
- m_frgbaColor3 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // right edge
- afrgbaRegression[0] = m_pafrgbaSource[12];
- afrgbaRegression[1] = m_pafrgbaSource[13];
- afrgbaRegression[2] = m_pafrgbaSource[14];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor2 = (m_frgbaColor2 + frgbaOffset) * 0.5f; // average with top edge
-
- // bottom edge
- afrgbaRegression[0] = m_pafrgbaSource[3];
- afrgbaRegression[1] = m_pafrgbaSource[7];
- afrgbaRegression[2] = m_pafrgbaSource[11];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor3 = (m_frgbaColor3 + frgbaOffset) * 0.5f; // average with left edge
-
- // quantize corner colors to 6/7/6
- m_frgbaColor1 = m_frgbaColor1.QuantizeR6G7B6();
- m_frgbaColor2 = m_frgbaColor2.QuantizeR6G7B6();
- m_frgbaColor3 = m_frgbaColor3.QuantizeR6G7B6();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R, G and B independently
- //
- // R, G and B decoding and errors are independent, so R, G and B twiddles can be independent
- //
- // return true if improvement
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanar(void)
- {
- bool boolImprovement = false;
-
- while (TwiddlePlanarR())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarG())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarB())
- {
- boolImprovement = true;
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarR()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginRed = encodingTry.m_frgbaColor1.IntRed(63.0f);
- int iHorizRed = encodingTry.m_frgbaColor2.IntRed(63.0f);
- int iVertRed = encodingTry.m_frgbaColor3.IntRed(63.0f);
-
- for (int iTryOriginRed = iOriginRed - 1; iTryOriginRed <= iOriginRed + 1; iTryOriginRed++)
- {
- // check for out of range
- if (iTryOriginRed < 0 || iTryOriginRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fR = ((iTryOriginRed << 2) + (iTryOriginRed >> 4)) / 255.0f;
-
- for (int iTryHorizRed = iHorizRed - 1; iTryHorizRed <= iHorizRed + 1; iTryHorizRed++)
- {
- // check for out of range
- if (iTryHorizRed < 0 || iTryHorizRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fR = ((iTryHorizRed << 2) + (iTryHorizRed >> 4)) / 255.0f;
-
- for (int iTryVertRed = iVertRed - 1; iTryVertRed <= iVertRed + 1; iTryVertRed++)
- {
- // check for out of range
- if (iTryVertRed < 0 || iTryVertRed > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginRed == iOriginRed && iTryHorizRed == iHorizRed && iTryVertRed == iVertRed)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fR = ((iTryVertRed << 2) + (iTryVertRed >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing G
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarG()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginGreen = encodingTry.m_frgbaColor1.IntGreen(127.0f);
- int iHorizGreen = encodingTry.m_frgbaColor2.IntGreen(127.0f);
- int iVertGreen = encodingTry.m_frgbaColor3.IntGreen(127.0f);
-
- for (int iTryOriginGreen = iOriginGreen - 1; iTryOriginGreen <= iOriginGreen + 1; iTryOriginGreen++)
- {
- // check for out of range
- if (iTryOriginGreen < 0 || iTryOriginGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fG = ((iTryOriginGreen << 1) + (iTryOriginGreen >> 6)) / 255.0f;
-
- for (int iTryHorizGreen = iHorizGreen - 1; iTryHorizGreen <= iHorizGreen + 1; iTryHorizGreen++)
- {
- // check for out of range
- if (iTryHorizGreen < 0 || iTryHorizGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fG = ((iTryHorizGreen << 1) + (iTryHorizGreen >> 6)) / 255.0f;
-
- for (int iTryVertGreen = iVertGreen - 1; iTryVertGreen <= iVertGreen + 1; iTryVertGreen++)
- {
- // check for out of range
- if (iTryVertGreen < 0 || iTryVertGreen > 127)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginGreen == iOriginGreen &&
- iTryHorizGreen == iHorizGreen &&
- iTryVertGreen == iVertGreen)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fG = ((iTryVertGreen << 1) + (iTryVertGreen >> 6)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing B
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarB()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginBlue = encodingTry.m_frgbaColor1.IntBlue(63.0f);
- int iHorizBlue = encodingTry.m_frgbaColor2.IntBlue(63.0f);
- int iVertBlue = encodingTry.m_frgbaColor3.IntBlue(63.0f);
-
- for (int iTryOriginBlue = iOriginBlue - 1; iTryOriginBlue <= iOriginBlue + 1; iTryOriginBlue++)
- {
- // check for out of range
- if (iTryOriginBlue < 0 || iTryOriginBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fB = ((iTryOriginBlue << 2) + (iTryOriginBlue >> 4)) / 255.0f;
-
- for (int iTryHorizBlue = iHorizBlue - 1; iTryHorizBlue <= iHorizBlue + 1; iTryHorizBlue++)
- {
- // check for out of range
- if (iTryHorizBlue < 0 || iTryHorizBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fB = ((iTryHorizBlue << 2) + (iTryHorizBlue >> 4)) / 255.0f;
-
- for (int iTryVertBlue = iVertBlue - 1; iTryVertBlue <= iVertBlue + 1; iTryVertBlue++)
- {
- // check for out of range
- if (iTryVertBlue < 0 || iTryVertBlue > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginBlue == iOriginBlue && iTryHorizBlue == iHorizBlue && iTryVertBlue == iVertBlue)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fB = ((iTryVertBlue << 2) + (iTryVertBlue >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8::SetEncodingBits(void)
- {
-
- switch (m_mode)
- {
- case MODE_ETC1:
- Block4x4Encoding_ETC1::SetEncodingBits();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for T mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- m_pencodingbitsRGB8->t.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- m_pencodingbitsRGB8->h.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_Planar(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_PLANAR);
- assert(m_boolDiff == true);
-
- unsigned int uiOriginRed = (unsigned int)m_frgbaColor1.IntRed(63.0f);
- unsigned int uiOriginGreen = (unsigned int)m_frgbaColor1.IntGreen(127.0f);
- unsigned int uiOriginBlue = (unsigned int)m_frgbaColor1.IntBlue(63.0f);
-
- unsigned int uiHorizRed = (unsigned int)m_frgbaColor2.IntRed(63.0f);
- unsigned int uiHorizGreen = (unsigned int)m_frgbaColor2.IntGreen(127.0f);
- unsigned int uiHorizBlue = (unsigned int)m_frgbaColor2.IntBlue(63.0f);
-
- unsigned int uiVertRed = (unsigned int)m_frgbaColor3.IntRed(63.0f);
- unsigned int uiVertGreen = (unsigned int)m_frgbaColor3.IntGreen(127.0f);
- unsigned int uiVertBlue = (unsigned int)m_frgbaColor3.IntBlue(63.0f);
-
- m_pencodingbitsRGB8->planar.originRed = uiOriginRed;
- m_pencodingbitsRGB8->planar.originGreen1 = uiOriginGreen >> 6;
- m_pencodingbitsRGB8->planar.originGreen2 = uiOriginGreen;
- m_pencodingbitsRGB8->planar.originBlue1 = uiOriginBlue >> 5;
- m_pencodingbitsRGB8->planar.originBlue2 = uiOriginBlue >> 3;
- m_pencodingbitsRGB8->planar.originBlue3 = uiOriginBlue >> 1;
- m_pencodingbitsRGB8->planar.originBlue4 = uiOriginBlue;
-
- m_pencodingbitsRGB8->planar.horizRed1 = uiHorizRed >> 1;
- m_pencodingbitsRGB8->planar.horizRed2 = uiHorizRed;
- m_pencodingbitsRGB8->planar.horizGreen = uiHorizGreen;
- m_pencodingbitsRGB8->planar.horizBlue1 = uiHorizBlue >> 5;
- m_pencodingbitsRGB8->planar.horizBlue2 = uiHorizBlue;
-
- m_pencodingbitsRGB8->planar.vertRed1 = uiVertRed >> 3;
- m_pencodingbitsRGB8->planar.vertRed2 = uiVertRed;
- m_pencodingbitsRGB8->planar.vertGreen1 = uiVertGreen >> 2;
- m_pencodingbitsRGB8->planar.vertGreen2 = uiVertGreen;
- m_pencodingbitsRGB8->planar.vertBlue = uiVertBlue;
-
- m_pencodingbitsRGB8->planar.diff = 1;
-
- // create valid RG differentials and an invalid B differential to trigger planar mode
- m_pencodingbitsRGB8->planar.detect1 = 0;
- m_pencodingbitsRGB8->planar.detect2 = 0;
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- int iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect1 = 1;
- }
- if (iGreen2 < 0 || iGreen2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect2 = 1;
- }
- if (iBlue2 >= 4)
- {
- m_pencodingbitsRGB8->planar.detect3 = 7;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
-
- // make sure red and green don't overflow and blue does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 >= 0 && iGreen2 <= 31);
- assert(iBlue2 < 0 || iBlue2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for T mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for H mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_Planar(void)
- {
-
- int iRO = (int)roundf(m_frgbaColor1.fR * 255.0f);
- int iGO = (int)roundf(m_frgbaColor1.fG * 255.0f);
- int iBO = (int)roundf(m_frgbaColor1.fB * 255.0f);
-
- int iRH = (int)roundf(m_frgbaColor2.fR * 255.0f);
- int iGH = (int)roundf(m_frgbaColor2.fG * 255.0f);
- int iBH = (int)roundf(m_frgbaColor2.fB * 255.0f);
-
- int iRV = (int)roundf(m_frgbaColor3.fR * 255.0f);
- int iGV = (int)roundf(m_frgbaColor3.fG * 255.0f);
- int iBV = (int)roundf(m_frgbaColor3.fB * 255.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- int iX = (int)(uiPixel >> 2);
- int iY = (int)(uiPixel & 3);
-
- int iR = (iX*(iRH - iRO) + iY*(iRV - iRO) + 4*iRO + 2) >> 2;
- int iG = (iX*(iGH - iGO) + iY*(iGV - iGO) + 4*iGO + 2) >> 2;
- int iB = (iX*(iBH - iBO) + iY*(iBV - iBO) + 4*iBO + 2) >> 2;
-
- ColorFloatRGBA frgba;
- frgba.fR = (float)iR / 255.0f;
- frgba.fG = (float)iG / 255.0f;
- frgba.fB = (float)iB / 255.0f;
- frgba.fA = 1.0f;
-
- m_afrgbaDecodedColors[uiPixel] = frgba.ClampRGB();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a linear regression for the a_uiPixels in a_pafrgbaPixels[]
- //
- // output the closest color line using a_pfrgbaSlope and a_pfrgbaOffset
- //
- void Block4x4Encoding_RGB8::ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
- ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset)
- {
- typedef struct
- {
- float f[4];
- } Float4;
-
- Float4 *paf4Pixels = (Float4 *)(a_pafrgbaPixels);
- Float4 *pf4Slope = (Float4 *)(a_pfrgbaSlope);
- Float4 *pf4Offset = (Float4 *)(a_pfrgbaOffset);
-
- float afX[MAX_PLANAR_REGRESSION_SIZE];
- float afY[MAX_PLANAR_REGRESSION_SIZE];
-
- // handle r, g and b separately. don't bother with a
- for (unsigned int uiComponent = 0; uiComponent < 3; uiComponent++)
- {
- for (unsigned int uiPixel = 0; uiPixel < a_uiPixels; uiPixel++)
- {
- afX[uiPixel] = (float)uiPixel;
- afY[uiPixel] = paf4Pixels[uiPixel].f[uiComponent];
-
- }
- Etc::Regression(afX, afY, a_uiPixels,
- &(pf4Slope->f[uiComponent]), &(pf4Offset->f[uiComponent]));
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
deleted file mode 100644
index 03754d5e3b..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_ETC1.h"
-
-namespace Etc
-{
-
- class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1
- {
- public:
-
- Block4x4Encoding_RGB8(void);
- virtual ~Block4x4Encoding_RGB8(void);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- inline ColorFloatRGBA GetColor3(void) const
- {
- return m_frgbaColor3;
- }
-
- protected:
-
- static const unsigned int PLANAR_CORNER_COLORS = 3;
- static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4;
- static const unsigned int TH_DISTANCES = 8;
-
- static float s_afTHDistanceTable[TH_DISTANCES];
-
- void TryPlanar(unsigned int a_uiRadius);
- void TryTAndH(unsigned int a_uiRadius);
-
- void InitFromEncodingBits_Planar(void);
-
- ColorFloatRGBA m_frgbaColor3; // used for planar
-
- void SetEncodingBits_T(void);
- void SetEncodingBits_H(void);
- void SetEncodingBits_Planar(void);
-
- // state shared between iterations
- ColorFloatRGBA m_frgbaOriginalColor1_TAndH;
- ColorFloatRGBA m_frgbaOriginalColor2_TAndH;
-
- void CalculateBaseColorsForTAndH(void);
- void TryT(unsigned int a_uiRadius);
- void TryT_BestSelectorCombination(void);
- void TryH(unsigned int a_uiRadius);
- void TryH_BestSelectorCombination(void);
-
- private:
-
- void InitFromEncodingBits_T(void);
- void InitFromEncodingBits_H(void);
-
- void CalculatePlanarCornerColors(void);
-
- void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
- ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset);
-
- bool TwiddlePlanar(void);
- bool TwiddlePlanarR();
- bool TwiddlePlanarG();
- bool TwiddlePlanarB();
-
- void DecodePixels_T(void);
- void DecodePixels_H(void);
- void DecodePixels_Planar(void);
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
deleted file mode 100644
index b94b64e68c..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
+++ /dev/null
@@ -1,1819 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGB8A1.cpp contains:
- Block4x4Encoding_RGB8A1
- Block4x4Encoding_RGB8A1_Opaque
- Block4x4Encoding_RGB8A1_Transparent
-
-These encoders are used when targetting file format RGB8A1.
-
-Block4x4Encoding_RGB8A1_Opaque is used when all pixels in the 4x4 block are opaque
-Block4x4Encoding_RGB8A1_Transparent is used when all pixels in the 4x4 block are transparent
-Block4x4Encoding_RGB8A1 is used when there is a mixture of alphas in the 4x4 block
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8A1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1
- // ####################################################################################################
-
- float Block4x4Encoding_RGB8A1::s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS] =
- {
- { 0.0f / 255.0f, 8.0f / 255.0f, 0.0f / 255.0f, -8.0f / 255.0f },
- { 0.0f / 255.0f, 17.0f / 255.0f, 0.0f / 255.0f, -17.0f / 255.0f },
- { 0.0f / 255.0f, 29.0f / 255.0f, 0.0f / 255.0f, -29.0f / 255.0f },
- { 0.0f / 255.0f, 42.0f / 255.0f, 0.0f / 255.0f, -42.0f / 255.0f },
- { 0.0f / 255.0f, 60.0f / 255.0f, 0.0f / 255.0f, -60.0f / 255.0f },
- { 0.0f / 255.0f, 80.0f / 255.0f, 0.0f / 255.0f, -80.0f / 255.0f },
- { 0.0f / 255.0f, 106.0f / 255.0f, 0.0f / 255.0f, -106.0f / 255.0f },
- { 0.0f / 255.0f, 183.0f / 255.0f, 0.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8A1::Block4x4Encoding_RGB8A1(void)
- {
- m_pencodingbitsRGB8 = nullptr;
- m_boolOpaque = false;
- m_boolTransparent = false;
- m_boolPunchThroughPixels = true;
-
- }
- Block4x4Encoding_RGB8A1::~Block4x4Encoding_RGB8A1(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RGB8A1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding_RGB8::InitFromSource(a_pblockParent,
- a_pafrgbaSource,
- a_paucEncodingBits,
- a_errormetric);
-
- m_boolOpaque = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE;
- m_boolTransparent = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::TRANSPARENT;
- m_boolPunchThroughPixels = a_pblockParent->HasPunchThroughPixels();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- if (m_pafrgbaSource[uiPixel].fA >= 0.5f)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- else
- {
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
-
- InitFromEncodingBits_ETC1(a_pblockParent,
- a_paucEncodingBits,
- a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- int iRed1 = m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- Block4x4Encoding_RGB8::InitFromEncodingBits_Planar();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding assuming the encoding is an ETC1 mode.
- // if it isn't an ETC1 mode, this will be overwritten later
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = m_pencodingbitsRGB8->differential.flip;
- m_boolOpaque = m_pencodingbitsRGB8->differential.diff;
-
- int iR2 = m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2;
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2;
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2;
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- m_uiCW1 = m_pencodingbitsRGB8->differential.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->differential.cw2;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- Decode_ETC1();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_T(void)
- {
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_H(void)
- {
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for ETC1 modes, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::Decode_ETC1(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta;
- if (m_boolOpaque)
- fDelta = Block4x4Encoding_ETC1::s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- else
- fDelta = s_aafCwOpaqueUnsetTable[uiCW][m_auiSelectors[uiPixel]];
-
- if (m_boolOpaque == false && m_auiSelectors[uiPixel] == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for T mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for H mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- // RGB8A1 can't use individual mode
- // RGB8A1 with transparent pixels can't use planar mode
- //
- void Block4x4Encoding_RGB8A1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolOpaque);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 39.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH();
- TryT(1);
- TryH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1::PerformFirstIteration(void)
- {
- Block4x4Encoding_ETC1::CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // Block4x4Encoding_RGB8A1 encodingTry = *this;
- //
- void Block4x4Encoding_RGB8A1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_RGB8A1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- m_fError = 0.0f;
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- if (uiSelector1 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel1] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel1] = 0.0f;
- }
- else
- {
- float fDeltaRGB1 = s_aafCwOpaqueUnsetTable[m_uiCW1][uiSelector1];
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afDecodedAlphas[uiPixel1] = 1.0f;
- }
-
- if (uiSelector2 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel2] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel2] = 0.0f;
- }
- else
- {
- float fDeltaRGB2 = s_aafCwOpaqueUnsetTable[m_uiCW2][uiSelector2];
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- m_afDecodedAlphas[uiPixel2] = 1.0f;
- }
-
- float fDeltaA1 = m_afDecodedAlphas[uiPixel1] - m_pafrgbaSource[uiPixel1].fA;
- m_fError += fDeltaA1 * fDeltaA1;
- float fDeltaA2 = m_afDecodedAlphas[uiPixel2] - m_pafrgbaSource[uiPixel2].fA;
- m_fError += fDeltaA2 * fDeltaA2;
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // uses s_aafCwOpaqueUnsetTable
- // color for selector set to 0,0,0,0
- //
- void Block4x4Encoding_RGB8A1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedColors[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = ColorFloatRGBA();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- if (pfrgbaSourcePixel->fA < 0.5f)
- {
- uiSelector = TRANSPARENT_SELECTOR;
- }
- else if (uiSelector == TRANSPARENT_SELECTOR)
- {
- continue;
- }
-
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedColors[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (uiSelector == TRANSPARENT_SELECTOR)
- {
- break;
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8A1::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in H mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8A1::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryH_BestSelectorCombination(void)
- {
-
- // abort if colors and CW will pose an encoding problem
- {
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(255.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(255.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(255.0f);
- unsigned int uiColorValue1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(255.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(255.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(255.0f);
- unsigned int uiColorValue2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- unsigned int uiCWLsb = m_uiCW1 & 1;
-
- if ((uiColorValue1 >= (uiColorValue2 & uiCWLsb)) == 0 ||
- (uiColorValue1 < (uiColorValue2 & uiCWLsb)) == 1)
- {
- return;
- }
- }
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits(void)
- {
- switch (m_mode)
- {
- case MODE_ETC1:
- SetEncodingBits_ETC1();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- Block4x4Encoding_RGB8::SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if ETC1 mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_ETC1(void)
- {
-
- // there is no individual mode in RGB8A1
- assert(m_boolDiff);
-
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = iRed1;
- m_pencodingbitsRGB8->differential.green1 = iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- m_pencodingbitsRGB8->individual.flip = m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if T mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_Opaque
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8A1_Opaque::PerformIteration(float a_fEffort)
- {
- assert(!m_boolPunchThroughPixels);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 3:
- Block4x4Encoding_RGB8::TryPlanar(1);
- break;
-
- case 4:
- Block4x4Encoding_RGB8::TryTAndH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1_Opaque::PerformFirstIteration(void)
- {
-
- // set decoded alphas
- // calculate alpha error
- m_fError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
-
- float fDeltaA = 1.0f - m_pafrgbaSource[uiPixel].fA;
- m_fError += fDeltaA * fDeltaA;
- }
-
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryTAndH(0);
- SetDoneIfPerfect();
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_Transparent
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8A1_Transparent::PerformIteration(float )
- {
- assert(!m_boolOpaque);
- assert(m_boolTransparent);
- assert(!m_boolDone);
- assert(m_uiEncodingIterations == 0);
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = false;
-
- m_uiCW1 = 0;
- m_uiCW2 = 0;
-
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = TRANSPARENT_SELECTOR;
-
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
-
- CalcBlockError();
-
- m_boolDone = true;
- m_uiEncodingIterations++;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
deleted file mode 100644
index ff26e462f8..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcErrorMetric.h"
-#include "EtcBlock4x4EncodingBits.h"
-
-namespace Etc
-{
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1
- // RGB8A1 if not completely opaque or transparent
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8
- {
- public:
-
- static const unsigned int TRANSPARENT_SELECTOR = 2;
-
- Block4x4Encoding_RGB8A1(void);
- virtual ~Block4x4Encoding_RGB8A1(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- void InitFromEncodingBits_T(void);
- void InitFromEncodingBits_H(void);
-
- void PerformFirstIteration(void);
-
- void Decode_ETC1(void);
- void DecodePixels_T(void);
- void DecodePixels_H(void);
- void SetEncodingBits_ETC1(void);
- void SetEncodingBits_T(void);
- void SetEncodingBits_H(void);
-
- protected:
-
- bool m_boolOpaque; // all source pixels have alpha >= 0.5
- bool m_boolTransparent; // all source pixels have alpha < 0.5
- bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5
-
- static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS];
-
- private:
-
- void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
- void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
-
- void TryT(unsigned int a_uiRadius);
- void TryT_BestSelectorCombination(void);
- void TryH(unsigned int a_uiRadius);
- void TryH_BestSelectorCombination(void);
-
- void TryDegenerates1(void);
- void TryDegenerates2(void);
- void TryDegenerates3(void);
- void TryDegenerates4(void);
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1_Opaque
- // RGB8A1 if all pixels have alpha==1
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- void PerformFirstIteration(void);
-
- private:
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1_Transparent
- // RGB8A1 if all pixels have alpha==0
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- private:
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
deleted file mode 100644
index 600c7ab405..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGBA8.cpp contains:
- Block4x4Encoding_RGBA8
- Block4x4Encoding_RGBA8_Opaque
- Block4x4Encoding_RGBA8_Transparent
-
-These encoders are used when targetting file format RGBA8.
-
-Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque
-Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent
-Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGBA8.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8
- // ####################################################################################################
-
- float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]
- {
- { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
-
- { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
- { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
-
- { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
-
- { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
- { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
- { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void)
- {
-
- m_pencodingbitsA8 = nullptr;
-
- }
- Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *) m_pencodingbitsRGB8,
- a_pafrgbaSource,
- a_errormetric);
-
- // init A8 portion
- // has to be done after InitFromEncodingBits()
- {
- m_fBase = m_pencodingbitsA8->data.base / 255.0f;
- m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier;
- m_uiModifierTableIndex = m_pencodingbitsA8->data.table;
-
- unsigned long long int ulliSelectorBits = 0;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1);
- }
-
- // decode the alphas
- // calc alpha error
- m_fError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier,
- m_uiModifierTableIndex,
- m_auiAlphaSelectors[uiPixel]);
-
- float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA;
- m_fError += fDeltaAlpha * fDeltaAlpha;
- }
- }
-
- // redo error calc to include alpha
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- // similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added
- //
- void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- if (m_uiEncodingIterations == 0)
- {
- if (a_fEffort < 24.9f)
- {
- CalculateA8(0.0f);
- }
- else if (a_fEffort < 49.9f)
- {
- CalculateA8(1.0f);
- }
- else
- {
- CalculateA8(2.0f);
- }
- }
-
- Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base alpga, multiplier and selectors
- //
- // a_fRadius limits the range of base alpha to try
- //
- void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius)
- {
-
- // find min/max alpha
- float fMinAlpha = 1.0f;
- float fMaxAlpha = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
-
- // ignore border pixels
- if (isnan(fAlpha))
- {
- continue;
- }
-
- if (fAlpha < fMinAlpha)
- {
- fMinAlpha = fAlpha;
- }
- if (fAlpha > fMaxAlpha)
- {
- fMaxAlpha = fAlpha;
- }
- }
- assert(fMinAlpha <= fMaxAlpha);
-
- float fAlphaRange = fMaxAlpha - fMinAlpha;
-
- // try each modifier table entry
- m_fError = FLT_MAX; // artificially high value
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- static const unsigned int MIN_VALUE_SELECTOR = 3;
- static const unsigned int MAX_VALUE_SELECTOR = 7;
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] -
- s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinAlpha + fCenterRatio*fAlphaRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
-
- float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 1.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestAlphaError[PIXELS];
- float afBestDecodedAlphas[PIXELS];
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelAlphaError = FLT_MAX;
- for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++)
- {
- float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector);
-
- // border pixels (NAN) should have zero error
- float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ?
- 0.0f :
- fDecodedAlpha - m_pafrgbaSource[uiPixel].fA;
-
- float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha;
-
- if (fPixelAlphaError < fBestPixelAlphaError)
- {
- fBestPixelAlphaError = fPixelAlphaError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestAlphaError[uiPixel] = fBestPixelAlphaError;
- afBestDecodedAlphas[uiPixel] = fDecodedAlpha;
- }
- }
- }
-
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestAlphaError[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- m_fBase = fBase;
- m_fMultiplier = fMultiplier;
- m_uiModifierTableIndex = uiTableEntry;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel];
- m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel];
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8::SetEncodingBits(void)
- {
-
- // set the RGB8 portion
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- {
- m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase);
- m_pencodingbitsA8->data.table = m_uiModifierTableIndex;
- m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier);
-
- unsigned long long int ulliSelectorBits = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift;
- }
-
- m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40;
- m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32;
- m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24;
- m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16;
- m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8;
- m_pencodingbitsA8->data.selectors5 = ulliSelectorBits;
- }
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8_Opaque
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- if (m_uiEncodingIterations == 0)
- {
- m_fError = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
-
- Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void)
- {
-
- // set the RGB8 portion
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- m_pencodingbitsA8->data.base = 255;
- m_pencodingbitsA8->data.table = 15;
- m_pencodingbitsA8->data.multiplier = 15;
- m_pencodingbitsA8->data.selectors0 = 0xFF;
- m_pencodingbitsA8->data.selectors1 = 0xFF;
- m_pencodingbitsA8->data.selectors2 = 0xFF;
- m_pencodingbitsA8->data.selectors3 = 0xFF;
- m_pencodingbitsA8->data.selectors4 = 0xFF;
- m_pencodingbitsA8->data.selectors5 = 0xFF;
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8_Transparent
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float )
- {
- assert(!m_boolDone);
- assert(m_uiEncodingIterations == 0);
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
-
- m_fError = 0.0f;
-
- m_boolDone = true;
- m_uiEncodingIterations++;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void)
- {
-
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- m_pencodingbitsA8->data.base = 0;
- m_pencodingbitsA8->data.table = 0;
- m_pencodingbitsA8->data.multiplier = 1;
- m_pencodingbitsA8->data.selectors0 = 0;
- m_pencodingbitsA8->data.selectors1 = 0;
- m_pencodingbitsA8->data.selectors2 = 0;
- m_pencodingbitsA8->data.selectors3 = 0;
- m_pencodingbitsA8->data.selectors4 = 0;
- m_pencodingbitsA8->data.selectors5 = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
deleted file mode 100644
index 5765d36b90..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_A8;
-
- // ################################################################################
- // Block4x4Encoding_RGBA8
- // RGBA8 if not completely opaque or transparent
- // ################################################################################
-
- class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8
- {
- public:
-
- Block4x4Encoding_RGBA8(void);
- virtual ~Block4x4Encoding_RGBA8(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- protected:
-
- static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
- static const unsigned int ALPHA_SELECTOR_BITS = 3;
- static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS;
-
- static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS];
-
- void CalculateA8(float a_fRadius);
-
- Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8
-
- float m_fBase;
- float m_fMultiplier;
- unsigned int m_uiModifierTableIndex;
- unsigned int m_auiAlphaSelectors[PIXELS];
-
- private:
-
- inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier,
- unsigned int a_uiTableIndex, unsigned int a_uiSelector)
- {
- float fPixelAlpha = a_fBase +
- a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector];
- if (fPixelAlpha < 0.0f)
- {
- fPixelAlpha = 0.0f;
- }
- else if (fPixelAlpha > 1.0f)
- {
- fPixelAlpha = 1.0f;
- }
-
- return fPixelAlpha;
- }
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGBA8_Opaque
- // RGBA8 if all pixels have alpha==1
- // ################################################################################
-
- class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGBA8_Transparent
- // RGBA8 if all pixels have alpha==0
- // ################################################################################
-
- class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcColor.h b/thirdparty/etc2comp/EtcColor.h
deleted file mode 100644
index 7ceae05b65..0000000000
--- a/thirdparty/etc2comp/EtcColor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <math.h>
-
-namespace Etc
-{
-
- inline float LogToLinear(float a_fLog)
- {
- static const float ALPHA = 0.055f;
- static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
-
- if (a_fLog <= 0.04045f)
- {
- return a_fLog / 12.92f;
- }
- else
- {
- return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f);
- }
- }
-
- inline float LinearToLog(float &a_fLinear)
- {
- static const float ALPHA = 0.055f;
- static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
-
- if (a_fLinear <= 0.0031308f)
- {
- return 12.92f * a_fLinear;
- }
- else
- {
- return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA;
- }
- }
-
- class ColorR8G8B8A8
- {
- public:
-
- unsigned char ucR;
- unsigned char ucG;
- unsigned char ucB;
- unsigned char ucA;
-
- };
-}
diff --git a/thirdparty/etc2comp/EtcColorFloatRGBA.h b/thirdparty/etc2comp/EtcColorFloatRGBA.h
deleted file mode 100644
index f2ca2c1f71..0000000000
--- a/thirdparty/etc2comp/EtcColorFloatRGBA.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcConfig.h"
-#include "EtcColor.h"
-
-#include <math.h>
-
-namespace Etc
-{
-
- class ColorFloatRGBA
- {
- public:
-
- ColorFloatRGBA(void)
- {
- fR = fG = fB = fA = 0.0f;
- }
-
- ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA)
- {
- fR = a_fR;
- fG = a_fG;
- fB = a_fB;
- fA = a_fA;
- }
-
- inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR + a_rfrgba.fR;
- frgba.fG = fG + a_rfrgba.fG;
- frgba.fB = fB + a_rfrgba.fB;
- frgba.fA = fA + a_rfrgba.fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator+(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR + a_f;
- frgba.fG = fG + a_f;
- frgba.fB = fB + a_f;
- frgba.fA = fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator-(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR - a_f;
- frgba.fG = fG - a_f;
- frgba.fB = fB - a_f;
- frgba.fA = fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR - a_rfrgba.fR;
- frgba.fG = fG - a_rfrgba.fG;
- frgba.fB = fB - a_rfrgba.fB;
- frgba.fA = fA - a_rfrgba.fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator*(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR * a_f;
- frgba.fG = fG * a_f;
- frgba.fB = fB * a_f;
- frgba.fA = fA;
-
- return frgba;
- }
-
- inline ColorFloatRGBA ScaleRGB(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = a_f * fR;
- frgba.fG = a_f * fG;
- frgba.fB = a_f * fB;
- frgba.fA = fA;
-
- return frgba;
- }
-
- inline ColorFloatRGBA RoundRGB(void)
- {
- ColorFloatRGBA frgba;
- frgba.fR = roundf(fR);
- frgba.fG = roundf(fG);
- frgba.fB = roundf(fB);
-
- return frgba;
- }
-
- inline ColorFloatRGBA ToLinear()
- {
- ColorFloatRGBA frgbaLinear;
- frgbaLinear.fR = LogToLinear(fR);
- frgbaLinear.fG = LogToLinear(fG);
- frgbaLinear.fB = LogToLinear(fB);
- frgbaLinear.fA = fA;
-
- return frgbaLinear;
- }
-
- inline ColorFloatRGBA ToLog(void)
- {
- ColorFloatRGBA frgbaLog;
- frgbaLog.fR = LinearToLog(fR);
- frgbaLog.fG = LinearToLog(fG);
- frgbaLog.fB = LinearToLog(fB);
- frgbaLog.fA = fA;
-
- return frgbaLog;
- }
-
- inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR,
- unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA)
- {
- ColorFloatRGBA frgba;
-
- frgba.fR = (float)a_ucR / 255.0f;
- frgba.fG = (float)a_ucG / 255.0f;
- frgba.fB = (float)a_ucB / 255.0f;
- frgba.fA = (float)a_ucA / 255.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4,
- unsigned char a_ucG4,
- unsigned char a_ucB4)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4);
- unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4);
- unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4);
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5,
- unsigned char a_ucG5,
- unsigned char a_ucB5)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2));
- unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2));
- unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2));
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6,
- unsigned char a_ucG7,
- unsigned char a_ucB6)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4));
- unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6));
- unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4));
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- // quantize to 4 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR4G4B4(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 4 bits
- frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB();
- unsigned int uiR4 = (unsigned int)frgba.fR;
- unsigned int uiG4 = (unsigned int)frgba.fG;
- unsigned int uiB4 = (unsigned int)frgba.fB;
-
- // expand to 8 bits
- frgba.fR = (float) ((uiR4 << 4) + uiR4);
- frgba.fG = (float) ((uiG4 << 4) + uiG4);
- frgba.fB = (float) ((uiB4 << 4) + uiB4);
-
- frgba = frgba.ScaleRGB(1.0f/255.0f);
-
- return frgba;
- }
-
- // quantize to 5 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR5G5B5(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 5 bits
- frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB();
- unsigned int uiR5 = (unsigned int)frgba.fR;
- unsigned int uiG5 = (unsigned int)frgba.fG;
- unsigned int uiB5 = (unsigned int)frgba.fB;
-
- // expand to 8 bits
- frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2));
- frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2));
- frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2));
-
- frgba = frgba.ScaleRGB(1.0f / 255.0f);
-
- return frgba;
- }
-
- // quantize to 6/7/6 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR6G7B6(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 6/7/6 bits
- ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB();
- ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB();
- unsigned int uiR6 = (unsigned int)frgba6.fR;
- unsigned int uiG7 = (unsigned int)frgba7.fG;
- unsigned int uiB6 = (unsigned int)frgba6.fB;
-
- // expand to 8 bits
- frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4));
- frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6));
- frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4));
-
- frgba = frgba.ScaleRGB(1.0f / 255.0f);
-
- return frgba;
- }
-
- inline ColorFloatRGBA ClampRGB(void)
- {
- ColorFloatRGBA frgba = *this;
- if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
- if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
- if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
- if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
- if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
- if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
-
- return frgba;
- }
-
- inline ColorFloatRGBA ClampRGBA(void)
- {
- ColorFloatRGBA frgba = *this;
- if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
- if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
- if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
- if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
- if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
- if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
- if (frgba.fA < 0.0f) { frgba.fA = 0.0f; }
- if (frgba.fA > 1.0f) { frgba.fA = 1.0f; }
-
- return frgba;
- }
-
- inline int IntRed(float a_fScale)
- {
- return (int)roundf(fR * a_fScale);
- }
-
- inline int IntGreen(float a_fScale)
- {
- return (int)roundf(fG * a_fScale);
- }
-
- inline int IntBlue(float a_fScale)
- {
- return (int)roundf(fB * a_fScale);
- }
-
- inline int IntAlpha(float a_fScale)
- {
- return (int)roundf(fA * a_fScale);
- }
-
- float fR, fG, fB, fA;
- };
-
-}
-
diff --git a/thirdparty/etc2comp/EtcConfig.h b/thirdparty/etc2comp/EtcConfig.h
deleted file mode 100644
index 3bfe1d99a8..0000000000
--- a/thirdparty/etc2comp/EtcConfig.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifdef _WIN32
-#define ETC_WINDOWS (1)
-#else
-#define ETC_WINDOWS (0)
-#endif
-
-#if __APPLE__
-#define ETC_OSX (1)
-#else
-#define ETC_OSX (0)
-#endif
-
-#if __unix__
-#define ETC_UNIX (1)
-#else
-#define ETC_UNIX (0)
-#endif
-
-
-// short names for common types
-#include <stdint.h>
-typedef int8_t i8;
-typedef int16_t i16;
-typedef int32_t i32;
-typedef int64_t i64;
-
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-
-typedef float f32;
-typedef double f64;
-
-// Keep asserts enabled in release builds during development
-#undef NDEBUG
-
-// 0=disable. stb_image can be used if you need to compress
-//other image formats like jpg
-#define USE_STB_IMAGE_LOAD 0
-
-#if ETC_WINDOWS
-#include <sdkddkver.h>
-#define _CRT_SECURE_NO_WARNINGS (1)
-#include <tchar.h>
-#endif
-
-#include <stdio.h>
-
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.cpp b/thirdparty/etc2comp/EtcDifferentialTrys.cpp
deleted file mode 100644
index ef4cd103d9..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcDifferentialTrys.cpp
-
-Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcDifferentialTrys.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct a list of trys (encoding attempts)
- //
- // a_frgbaColor1 is the basecolor for the first half
- // a_frgbaColor2 is the basecolor for the second half
- // a_pauiPixelMapping1 is the pixel order for the first half
- // a_pauiPixelMapping2 is the pixel order for the second half
- // a_uiRadius is the amount to vary the base colors
- //
- DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
- assert(a_uiRadius <= MAX_RADIUS);
-
- m_boolSeverelyBentColors = false;
-
- ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5();
- ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5();
-
- // quantize base colors
- // ensure that trys with a_uiRadius don't overflow
- int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius);
- int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius);
- int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius);
- int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius);
- int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius);
- int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius);
-
- int iDeltaRed = iRed2 - iRed1;
- int iDeltaGreen = iGreen2 - iGreen1;
- int iDeltaBlue = iBlue2 - iBlue1;
-
- // make sure components are within range
- {
- if (iDeltaRed > 3)
- {
- if (iDeltaRed > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iRed1 += (iDeltaRed - 3) / 2;
- iRed2 = iRed1 + 3;
- iDeltaRed = 3;
- }
- else if (iDeltaRed < -4)
- {
- if (iDeltaRed < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iRed1 += (iDeltaRed + 4) / 2;
- iRed2 = iRed1 - 4;
- iDeltaRed = -4;
- }
- assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius));
- assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaRed >= -4 && iDeltaRed <= 3);
-
- if (iDeltaGreen > 3)
- {
- if (iDeltaGreen > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iGreen1 += (iDeltaGreen - 3) / 2;
- iGreen2 = iGreen1 + 3;
- iDeltaGreen = 3;
- }
- else if (iDeltaGreen < -4)
- {
- if (iDeltaGreen < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iGreen1 += (iDeltaGreen + 4) / 2;
- iGreen2 = iGreen1 - 4;
- iDeltaGreen = -4;
- }
- assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius));
- assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaGreen >= -4 && iDeltaGreen <= 3);
-
- if (iDeltaBlue > 3)
- {
- if (iDeltaBlue > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iBlue1 += (iDeltaBlue - 3) / 2;
- iBlue2 = iBlue1 + 3;
- iDeltaBlue = 3;
- }
- else if (iDeltaBlue < -4)
- {
- if (iDeltaBlue < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iBlue1 += (iDeltaBlue + 4) / 2;
- iBlue2 = iBlue1 - 4;
- iDeltaBlue = -4;
- }
- assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius));
- assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaBlue >= -4 && iDeltaBlue <= 3);
- }
-
- m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
- m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
- {
-
- m_iRed = a_iRed;
- m_iGreen = a_iGreen;
- m_iBlue = a_iBlue;
-
- m_pauiPixelMapping = a_pauiPixelMapping;
- m_uiRadius = a_uiRadius;
-
- m_uiTrys = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.h b/thirdparty/etc2comp/EtcDifferentialTrys.h
deleted file mode 100644
index 71860908ff..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-namespace Etc
-{
-
- class DifferentialTrys
- {
- public:
-
- static const unsigned int MAX_RADIUS = 2;
-
- DifferentialTrys(ColorFloatRGBA a_frgbaColor1,
- ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
-
- inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
- {
- if (a_i < (0+ a_iDistance))
- {
- return (0 + a_iDistance);
- }
- else if (a_i > (31- a_iDistance))
- {
- return (31 - a_iDistance);
- }
-
- return a_i;
- }
-
- class Try
- {
- public :
- static const unsigned int SELECTORS = 8; // per half
-
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
- unsigned int m_uiCW;
- unsigned int m_auiSelectors[SELECTORS];
- float m_fError;
- };
-
- class Half
- {
- public:
-
- static const unsigned int MAX_TRYS = 125;
-
- void Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping,
- unsigned int a_uiRadius);
-
- // center of trys
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
-
- const unsigned int *m_pauiPixelMapping;
- unsigned int m_uiRadius;
-
- unsigned int m_uiTrys;
- Try m_atry[MAX_TRYS];
-
- Try *m_ptryBest;
- };
-
- Half m_half1;
- Half m_half2;
-
- bool m_boolSeverelyBentColors;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcErrorMetric.h b/thirdparty/etc2comp/EtcErrorMetric.h
deleted file mode 100644
index df4dcab4fb..0000000000
--- a/thirdparty/etc2comp/EtcErrorMetric.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace Etc
-{
-
- enum ErrorMetric
- {
- RGBA,
- RGBX,
- REC709,
- NUMERIC,
- NORMALXYZ,
- //
- ERROR_METRICS,
- //
- BT709 = REC709
- };
-
- inline const char *ErrorMetricToString(ErrorMetric errorMetric)
- {
- switch (errorMetric)
- {
- case RGBA:
- return "RGBA";
- case RGBX:
- return "RGBX";
- case REC709:
- return "REC709";
- case NUMERIC:
- return "NUMERIC";
- case NORMALXYZ:
- return "NORMALXYZ";
- case ERROR_METRICS:
- default:
- return "UNKNOWN";
- }
- }
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFile.cpp b/thirdparty/etc2comp/EtcFile.cpp
deleted file mode 100644
index 831a3aac45..0000000000
--- a/thirdparty/etc2comp/EtcFile.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef _WIN32
-#define _CRT_SECURE_NO_WARNINGS (1)
-#endif
-
-#include "EtcConfig.h"
-
-
-#include "EtcFile.h"
-
-#include "EtcFileHeader.h"
-#include "EtcColor.h"
-#include "Etc.h"
-#include "EtcBlock4x4EncodingBits.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-
-using namespace Etc;
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight)
-{
- if (a_pstrFilename == nullptr)
- {
- m_pstrFilename = const_cast<char *>("");
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- m_imageformat = a_imageformat;
-
- m_uiNumMipmaps = 1;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
- m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } );
- m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes;
- m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth;
- m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight;
-
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- switch (m_fileformat)
- {
- case Format::PKM:
- m_pheader = new FileHeader_Pkm(this);
- break;
-
- case Format::KTX:
- m_pheader = new FileHeader_Ktx(this);
- break;
-
- default:
- assert(0);
- break;
- }
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight)
-{
- if (a_pstrFilename == nullptr)
- {
- m_pstrFilename = const_cast<char *>("");
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- m_imageformat = a_imageformat;
-
- m_uiNumMipmaps = a_uiNumMipmaps;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
-
- for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
- {
- m_pMipmapImages[mip] = a_pMipmapImages[mip];
- }
-
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- switch (m_fileformat)
- {
- case Format::PKM:
- m_pheader = new FileHeader_Pkm(this);
- break;
-
- case Format::KTX:
- m_pheader = new FileHeader_Ktx(this);
- break;
-
- default:
- assert(0);
- break;
- }
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat)
-{
- if (a_pstrFilename == nullptr)
- {
- return;
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- FILE *pfile = fopen(m_pstrFilename, "rb");
- if (pfile == nullptr)
- {
- printf("ERROR: Couldn't open %s", m_pstrFilename);
- exit(1);
- }
- fseek(pfile, 0, SEEK_END);
- unsigned int fileSize = ftell(pfile);
- fseek(pfile, 0, SEEK_SET);
- size_t szResult;
-
- m_pheader = new FileHeader_Ktx(this);
- szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile);
- assert(szResult > 0);
-
- m_uiNumMipmaps = 1;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
-
- if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0)
- fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR);
- szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile);
- assert(szResult > 0);
-
- m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } );
- assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize);
- szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile);
- assert(szResult == m_pMipmapImages->uiEncodingBitsBytes);
-
- uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat;
- uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat;
-
- if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8)
- {
- m_imageformat = Image::Format::ETC1;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8)
- {
- m_imageformat = Image::Format::RGB8;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1)
- {
- m_imageformat = Image::Format::RGB8A1;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8)
- {
- m_imageformat = Image::Format::RGBA8;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
- {
- m_imageformat = Image::Format::R11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
- {
- m_imageformat = Image::Format::SIGNED_R11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
- {
- m_imageformat = Image::Format::RG11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
- {
- m_imageformat = Image::Format::SIGNED_RG11;
- }
- else
- {
- m_imageformat = Image::Format::UNKNOWN;
- }
-
- m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth;
- m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight;
- m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16;
- Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
- unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
- assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes);
-
- fclose(pfile);
-}
-
-File::~File()
-{
- if (m_pMipmapImages != nullptr)
- {
- delete [] m_pMipmapImages;
- }
-
- if(m_pstrFilename != nullptr)
- {
- delete[] m_pstrFilename;
- m_pstrFilename = nullptr;
- }
- if (m_pheader != nullptr)
- {
- delete m_pheader;
- m_pheader = nullptr;
- }
-}
-
-void File::UseSingleBlock(int a_iPixelX, int a_iPixelY)
-{
- if (a_iPixelX <= -1 || a_iPixelY <= -1)
- return;
- if (a_iPixelX >(int) m_uiSourceWidth)
- {
- //if we are using a ktx thats the size of a single block or less
- //then make sure we use the 4x4 image as the single block
- if (m_uiSourceWidth <= 4)
- {
- a_iPixelX = 0;
- }
- else
- {
- printf("blockAtHV: H coordinate out of range, capped to image width\n");
- a_iPixelX = m_uiSourceWidth - 1;
- }
- }
- if (a_iPixelY >(int) m_uiSourceHeight)
- {
- //if we are using a ktx thats the size of a single block or less
- //then make sure we use the 4x4 image as the single block
- if (m_uiSourceHeight <= 4)
- {
- a_iPixelY= 0;
- }
- else
- {
- printf("blockAtHV: V coordinate out of range, capped to image height\n");
- a_iPixelY = m_uiSourceHeight - 1;
- }
- }
-
- unsigned int origWidth = m_uiSourceWidth;
- unsigned int origHeight = m_uiSourceHeight;
-
- m_uiSourceWidth = 4;
- m_uiSourceHeight = 4;
-
- Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
- unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
-
- int numMipmaps = 1;
- RawImage* pMipmapImages = new RawImage[numMipmaps];
- pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
- pMipmapImages[0].uiEncodingBitsBytes = 0;
- pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; });
-
- //block position in pixels
- // remove the bottom 2 bits to get the block coordinates
- unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC);
- unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC);
-
- int numXBlocks = (origWidth / 4);
- int numYBlocks = (origHeight / 4);
-
-
- // block location
- //int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1;
- //int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1;
- //m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock;
-
-
- unsigned int num = numXBlocks*numYBlocks;
- unsigned int uiH = 0, uiV = 0;
- unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get();
- for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++)
- {
- if (uiH == iBlockPosX && uiV == iBlockPosY)
- {
- memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock);
- break;
- }
- pEncodingBits += uiEncodingBitsBytesPerBlock;
- uiH += 4;
-
- if (uiH >= origWidth)
- {
- uiH = 0;
- uiV += 4;
- }
- }
-
- delete [] m_pMipmapImages;
- m_pMipmapImages = pMipmapImages;
-}
-// ----------------------------------------------------------------------------------------------------
-//
-void File::Write()
-{
-
- FILE *pfile = fopen(m_pstrFilename, "wb");
- if (pfile == nullptr)
- {
- printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename);
- exit(1);
- }
-
- m_pheader->Write(pfile);
-
- for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
- {
- if(m_fileformat == Format::KTX)
- {
- // Write u32 image size
- uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes;
- uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile);
- assert(szBytesWritten == sizeof(u32ImageSize));
- }
-
- unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile);
- if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes)
- {
- printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename);
- exit(1);
- }
- }
-
- fclose(pfile);
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-
diff --git a/thirdparty/etc2comp/EtcFile.h b/thirdparty/etc2comp/EtcFile.h
deleted file mode 100644
index 69bf3b2d3a..0000000000
--- a/thirdparty/etc2comp/EtcFile.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-#include "EtcImage.h"
-#include "Etc.h"
-
-namespace Etc
-{
- class FileHeader;
- class SourceImage;
-
- class File
- {
- public:
-
- enum class Format
- {
- INFER_FROM_FILE_EXTENSION,
- PKM,
- KTX,
- };
-
- File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight);
-
- File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned int a_uiNumMipmaps, RawImage *pMipmapImages,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight );
-
- File(const char *a_pstrFilename, Format a_fileformat);
- ~File();
- const char *GetFilename(void) { return m_pstrFilename; }
-
- void Read(const char *a_pstrFilename);
- void Write(void);
-
- inline unsigned int GetSourceWidth(void)
- {
- return m_uiSourceWidth;
- }
-
- inline unsigned int GetSourceHeight(void)
- {
- return m_uiSourceHeight;
- }
-
- inline unsigned int GetExtendedWidth(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiExtendedWidth;
- }
- else
- {
- return 0;
- }
- }
-
- inline unsigned int GetExtendedHeight(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiExtendedHeight;
- }
- else
- {
- return 0;
- }
- }
-
- inline Image::Format GetImageFormat()
- {
- return m_imageformat;
- }
-
- inline unsigned int GetEncodingBitsBytes(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiEncodingBitsBytes;
- }
- else
- {
- return 0;
- }
- }
-
- inline unsigned char* GetEncodingBits(unsigned int mipmapIndex = 0)
- {
- if( mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].paucEncodingBits.get();
- }
- else
- {
- return nullptr;
- }
- }
-
- inline unsigned int GetNumMipmaps()
- {
- return m_uiNumMipmaps;
- }
-
- void UseSingleBlock(int a_iPixelX = -1, int a_iPixelY = -1);
- private:
-
- char *m_pstrFilename; // includes directory path and file extension
- Format m_fileformat;
- Image::Format m_imageformat;
- FileHeader *m_pheader;
- unsigned int m_uiNumMipmaps;
- RawImage* m_pMipmapImages;
- unsigned int m_uiSourceWidth;
- unsigned int m_uiSourceHeight;
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcFileHeader.cpp b/thirdparty/etc2comp/EtcFileHeader.cpp
deleted file mode 100644
index f02fcab011..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcFileHeader.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Pkm::FileHeader_Pkm(File *a_pfile)
- {
- m_pfile = a_pfile;
-
- static const char s_acMagicNumberData[4] = { 'P', 'K', 'M', ' ' };
- static const char s_acVersionData[2] = { '1', '0' };
-
- for (unsigned int ui = 0; ui < sizeof(s_acMagicNumberData); ui++)
- {
- m_data.m_acMagicNumber[ui] = s_acMagicNumberData[ui];
- }
-
- for (unsigned int ui = 0; ui < sizeof(s_acVersionData); ui++)
- {
- m_data.m_acVersion[ui] = s_acVersionData[ui];
- }
-
- m_data.m_ucDataType_msb = 0; // ETC1_RGB_NO_MIPMAPS
- m_data.m_ucDataType_lsb = 0;
-
- m_data.m_ucOriginalWidth_msb = (unsigned char)(m_pfile->GetSourceWidth() >> 8);
- m_data.m_ucOriginalWidth_lsb = m_pfile->GetSourceWidth() & 0xFF;
- m_data.m_ucOriginalHeight_msb = (unsigned char)(m_pfile->GetSourceHeight() >> 8);
- m_data.m_ucOriginalHeight_lsb = m_pfile->GetSourceHeight() & 0xFF;
-
- m_data.m_ucExtendedWidth_msb = (unsigned char)(m_pfile->GetExtendedWidth() >> 8);
- m_data.m_ucExtendedWidth_lsb = m_pfile->GetExtendedWidth() & 0xFF;
- m_data.m_ucExtendedHeight_msb = (unsigned char)(m_pfile->GetExtendedHeight() >> 8);
- m_data.m_ucExtendedHeight_lsb = m_pfile->GetExtendedHeight() & 0xFF;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void FileHeader_Pkm::Write(FILE *a_pfile)
- {
-
- fwrite(&m_data, sizeof(Data), 1, a_pfile);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Ktx::FileHeader_Ktx(File *a_pfile)
- {
- m_pfile = a_pfile;
-
- static const uint8_t s_au8Itentfier[12] =
- {
- 0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier
- 0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier
- 0x0D, 0x0A, 0x1A, 0x0A // final four bytes of Byte[12] identifier
- };
-
- for (unsigned int ui = 0; ui < sizeof(s_au8Itentfier); ui++)
- {
- m_data.m_au8Identifier[ui] = s_au8Itentfier[ui];
- }
-
- m_data.m_u32Endianness = 0x04030201;
- m_data.m_u32GlType = 0;
- m_data.m_u32GlTypeSize = 1;
- m_data.m_u32GlFormat = 0;
-
- switch (m_pfile->GetImageFormat())
- {
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGBA8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGBA8;
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8A1;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8A1;
- break;
-
- case Image::Format::R11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_R11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
- break;
-
- case Image::Format::SIGNED_R11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_R11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
- break;
-
- case Image::Format::RG11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RG11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
- break;
-
- case Image::Format::SIGNED_RG11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_RG11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
- break;
-
- default:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC1_RGB8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC1_RGB8;
- break;
- }
-
- m_data.m_u32PixelWidth = 0;
- m_data.m_u32PixelHeight = 0;
- m_data.m_u32PixelDepth = 0;
- m_data.m_u32NumberOfArrayElements = 0;
- m_data.m_u32NumberOfFaces = 0;
- m_data.m_u32BytesOfKeyValueData = 0;
-
- m_pkeyvaluepair = nullptr;
-
- m_u32Images = 0;
- m_u32KeyValuePairs = 0;
-
- m_data.m_u32PixelWidth = m_pfile->GetSourceWidth();
- m_data.m_u32PixelHeight = m_pfile->GetSourceHeight();
- m_data.m_u32PixelDepth = 0;
- m_data.m_u32NumberOfArrayElements = 0;
- m_data.m_u32NumberOfFaces = 1;
- m_data.m_u32NumberOfMipmapLevels = m_pfile->GetNumMipmaps();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void FileHeader_Ktx::Write(FILE *a_pfile)
- {
- size_t szBytesWritten;
-
- // Write header
- szBytesWritten = fwrite(&m_data, 1, sizeof(Data), a_pfile);
- assert(szBytesWritten == sizeof(Data));
-
- // Write KeyAndValuePairs
- if (m_u32KeyValuePairs)
- {
- fwrite(m_pkeyvaluepair, m_pkeyvaluepair->u32KeyAndValueByteSize, 1, a_pfile);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Ktx::Data *FileHeader_Ktx::GetData()
- {
- return &m_data;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFileHeader.h b/thirdparty/etc2comp/EtcFileHeader.h
deleted file mode 100644
index 55a9cb5d9d..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcFile.h"
-#include <stdio.h>
-#include <inttypes.h>
-
-namespace Etc
-{
-
- class Image;
-
- class FileHeader
- {
- public:
-
- virtual void Write(FILE *a_pfile) = 0;
- File GetFile();
- virtual ~FileHeader(void) {}
- protected:
-
- File *m_pfile;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- class FileHeader_Pkm : public FileHeader
- {
- public:
-
- FileHeader_Pkm(File *a_pfile);
-
- virtual void Write(FILE *a_pfile);
- virtual ~FileHeader_Pkm(void) {}
- private:
-
- typedef struct
- {
- char m_acMagicNumber[4];
- char m_acVersion[2];
- unsigned char m_ucDataType_msb; // e.g. ETC1_RGB_NO_MIPMAPS
- unsigned char m_ucDataType_lsb;
- unsigned char m_ucExtendedWidth_msb; // padded to 4x4 blocks
- unsigned char m_ucExtendedWidth_lsb;
- unsigned char m_ucExtendedHeight_msb; // padded to 4x4 blocks
- unsigned char m_ucExtendedHeight_lsb;
- unsigned char m_ucOriginalWidth_msb;
- unsigned char m_ucOriginalWidth_lsb;
- unsigned char m_ucOriginalHeight_msb;
- unsigned char m_ucOriginalHeight_lsb;
- } Data;
-
- Data m_data;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- class FileHeader_Ktx : public FileHeader
- {
- public:
-
- typedef struct
- {
- uint32_t u32KeyAndValueByteSize;
- } KeyValuePair;
-
- typedef struct
- {
- uint8_t m_au8Identifier[12];
- uint32_t m_u32Endianness;
- uint32_t m_u32GlType;
- uint32_t m_u32GlTypeSize;
- uint32_t m_u32GlFormat;
- uint32_t m_u32GlInternalFormat;
- uint32_t m_u32GlBaseInternalFormat;
- uint32_t m_u32PixelWidth;
- uint32_t m_u32PixelHeight;
- uint32_t m_u32PixelDepth;
- uint32_t m_u32NumberOfArrayElements;
- uint32_t m_u32NumberOfFaces;
- uint32_t m_u32NumberOfMipmapLevels;
- uint32_t m_u32BytesOfKeyValueData;
- } Data;
-
- enum class InternalFormat
- {
- ETC1_RGB8 = 0x8D64,
- ETC1_ALPHA8 = ETC1_RGB8,
- //
- ETC2_R11 = 0x9270,
- ETC2_SIGNED_R11 = 0x9271,
- ETC2_RG11 = 0x9272,
- ETC2_SIGNED_RG11 = 0x9273,
- ETC2_RGB8 = 0x9274,
- ETC2_SRGB8 = 0x9275,
- ETC2_RGB8A1 = 0x9276,
- ETC2_SRGB8_PUNCHTHROUGH_ALPHA1 = 0x9277,
- ETC2_RGBA8 = 0x9278
- };
-
- enum class BaseInternalFormat
- {
- ETC2_R11 = 0x1903,
- ETC2_RG11 = 0x8227,
- ETC1_RGB8 = 0x1907,
- ETC1_ALPHA8 = ETC1_RGB8,
- //
- ETC2_RGB8 = 0x1907,
- ETC2_RGB8A1 = 0x1908,
- ETC2_RGBA8 = 0x1908,
- };
-
- FileHeader_Ktx(File *a_pfile);
-
- virtual void Write(FILE *a_pfile);
- virtual ~FileHeader_Ktx(void) {}
-
- void AddKeyAndValue(KeyValuePair *a_pkeyvaluepair);
-
- Data* GetData();
-
- private:
-
- Data m_data;
- KeyValuePair *m_pkeyvaluepair;
-
- uint32_t m_u32Images;
- uint32_t m_u32KeyValuePairs;
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp
deleted file mode 100644
index 1ec8acdf3f..0000000000
--- a/thirdparty/etc2comp/EtcFilter.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-#include <stdlib.h>
-#include <math.h>
-#include "EtcFilter.h"
-
-
-namespace Etc
-{
-
-static const double PiConst = 3.14159265358979323846;
-
-inline double sinc(double x)
-{
- if ( x == 0.0 )
- {
- return 1.0;
- }
-
- return sin(PiConst * x) / (PiConst * x);
-}
-
-//inline float sincf( float x )
-//{
-// x *= F_PI;
-// if (x < 0.01f && x > -0.01f)
-// {
-// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
-// }
-//
-// return sinf(x)/x;
-//}
-//
-//double bessel0(double x)
-//{
-// const double EPSILON_RATIO = 1E-16;
-// double xh, sum, pow, ds;
-// int k;
-//
-// xh = 0.5 * x;
-// sum = 1.0;
-// pow = 1.0;
-// k = 0;
-// ds = 1.0;
-// while (ds > sum * EPSILON_RATIO)
-// {
-// ++k;
-// pow = pow * (xh / k);
-// ds = pow * pow;
-// sum = sum + ds;
-// }
-//
-// return sum;
-//}
-
-//**--------------------------------------------------------------------------
-//** Name: kaiser(double alpha, double half_width, double x)
-//** Returns:
-//** Description: Alpha controls shape of filter. We are using 4.
-//**--------------------------------------------------------------------------
-//inline double kaiser(double alpha, double half_width, double x)
-//{
-// double ratio = (x / half_width);
-// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
-//}
-//
-//float Filter_Lanczos4Sinc(float x)
-//{
-// if (x <= -4.0f || x >= 4.0f) // half-width of 4
-// {
-// return 0.0;
-// }
-//
-// return sinc(0.875f * x) * sinc(0.25f * x);
-//}
-//
-//double Filter_Kaiser4( double t )
-//{
-// return kaiser( 4.0, 3.0, t);
-//}
-//
-//double Filter_KaiserOptimal( double t )
-//{
-// return kaiser( 8.93, 3.0f, t);
-//}
-
-double FilterLanczos3( double t )
-{
- if ( t <= -3.0 || t >= 3.0 )
- {
- return 0.0;
- }
-
- return sinc( t ) * sinc( t / 3.0 );
-}
-
-double FilterBox( double t )
-{
- return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0;
-}
-
-double FilterLinear( double t )
-{
- if (t < 0.0) t = -t;
-
- return (t < 1.0) ? (1.0 - t) : 0.0;
-}
-
-
-//**--------------------------------------------------------------------------
-//** Name: CalcContributions( int srcSize,
-//** int destSize,
-//** double filterSize,
-//** bool wrap,
-//** double (*FilterProc)(double),
-//** FilterWeights contrib[] )
-//** Returns: void
-//** Description:
-//**--------------------------------------------------------------------------
-void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] )
-{
- double scale;
- double filterScale;
- double center;
- double totalWeight;
- double weight;
- int iRight;
- int iLeft;
- int iDest;
-
- scale = (double)destSize / srcSize;
- if ( scale < 1.0 )
- {
- filterSize = filterSize / scale;
- filterScale = scale;
- }
- else
- {
- filterScale = 1.0;
- }
-
- if ( filterSize > (double)MaxFilterSize )
- {
- filterSize = (double)MaxFilterSize;
- }
-
- for ( iDest = 0; iDest < destSize; ++iDest )
- {
- center = (double)iDest / scale;
-
- iLeft = (int)ceil(center - filterSize);
- iRight = (int)floor(center + filterSize);
-
- if ( !wrap )
- {
- if ( iLeft < 0 )
- {
- iLeft = 0;
- }
-
- if ( iRight >= srcSize )
- {
- iRight = srcSize - 1;
- }
- }
-
- int numWeights = iRight - iLeft + 1;
-
- contrib[iDest].first = iLeft;
- contrib[iDest].numWeights = numWeights;
-
- totalWeight = 0;
- double t = ((double)iLeft - center) * filterScale;
- for (int i = 0; i < numWeights; i++)
- {
- weight = (*FilterProc)(t) * filterScale;
- totalWeight += weight;
- contrib[iDest].weight[i] = weight;
- t += filterScale;
- }
-
- //**--------------------------------------------------------
- //** Normalize weights by dividing by the sum of the weights
- //**--------------------------------------------------------
- if ( totalWeight > 0.0 )
- {
- for ( int i = 0; i < numWeights; i++)
- {
- contrib[iDest].weight[i] /= totalWeight;
- }
- }
- }
-}
-
-//**-------------------------------------------------------------------------
-//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
-//** int srcWidth, int srcHeight,
-//** RGBCOLOR *pDestImage,
-//** int destWidth, int destHeight,
-//** double (*FilterProc)(double) )
-//** Returns: 0 on failure and 1 on success
-//** Description: Filters a 2d image with a two pass filter by averaging the
-//** weighted contributions of the pixels within the filter region. The
-//** contributions are determined by a weighting function parameter.
-//**-------------------------------------------------------------------------
-int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) )
-{
- FilterWeights *contrib;
- RGBCOLOR *pPixel;
- RGBCOLOR *pSrcPixel;
- RGBCOLOR *pTempImage;
- int iRow;
- int iCol;
- int iSrcCol;
- int iSrcRow;
- int iWeight;
- double dRed;
- double dGreen;
- double dBlue;
- double dAlpha;
- double filterSize = 3.0;
-
- int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight;
- contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights));
-
- //**------------------------------------------------------------------------
- //** Need to create a temporary image to stuff the horizontally scaled image
- //**------------------------------------------------------------------------
- pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) );
- if ( pTempImage == NULL )
- {
- // -- GODOT start --
- free( contrib );
- // -- GODOT end --
- return 0;
- }
-
- //**-------------------------------------------------------
- //** Horizontally filter the image into the temporary image
- //**-------------------------------------------------------
- bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
- CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib );
- for ( iRow = 0; iRow < srcHeight; iRow++ )
- {
- for ( iCol = 0; iCol < destWidth; iCol++ )
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ )
- {
- iSrcCol = iWeight + contrib[iCol].first;
- if (bWrapHorizontal)
- {
- iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol;
- }
- pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol;
- dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0];
- dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1];
- dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2];
- dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3];
- }
-
- pPixel = pTempImage + (iRow * destWidth) + iCol;
- pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed)));
- pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- //**-------------------------------------------------------
- //** Vertically filter the image into the destination image
- //**-------------------------------------------------------
- bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
- CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
- for ( iCol = 0; iCol < destWidth; iCol++ )
- {
- for ( iRow = 0; iRow < destHeight; iRow++ )
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ )
- {
- iSrcRow = iWeight + contrib[iRow].first;
- if (bWrapVertical)
- {
- iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
- }
- pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol;
- dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0];
- dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1];
- dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2];
- dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3];
- }
-
- pPixel = pDestImage + (iRow * destWidth) + iCol;
- pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed)));
- pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen)));
- pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue)));
- pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha)));
- }
- }
-
- free( pTempImage );
- free( contrib );
-
- return 1;
-}
-
-//**-------------------------------------------------------------------------
-//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
-//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight)
-//** Returns: 1
-//** Description: This function runs a 2d box filter over the srouce image
-//** to produce the destination image.
-//**-------------------------------------------------------------------------
-void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDstImage, int dstWidth, int dstHeight )
-{
- int iRow;
- int iCol;
- int iSampleRow;
- int iSampleCol;
- int iFirstSampleRow;
- int iFirstSampleCol;
- int iLastSampleRow;
- int iLastSampleCol;
- int red;
- int green;
- int blue;
- int alpha;
- int samples;
- float xScale;
- float yScale;
-
- RGBCOLOR *pSrcPixel;
- RGBCOLOR *pDstPixel;
-
- xScale = (float)srcWidth / dstWidth;
- yScale = (float)srcHeight / dstHeight;
-
- for ( iRow = 0; iRow < dstHeight; iRow++ )
- {
- for ( iCol = 0; iCol < dstWidth; iCol++ )
- {
- iFirstSampleRow = (int)(iRow * yScale);
- iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
- if ( iLastSampleRow >= srcHeight )
- {
- iLastSampleRow = srcHeight - 1;
- }
-
- iFirstSampleCol = (int)(iCol * xScale);
- iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
- if ( iLastSampleCol >= srcWidth )
- {
- iLastSampleCol = srcWidth - 1;
- }
-
- samples = 0;
- red = 0;
- green = 0;
- blue = 0;
- alpha = 0;
- for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ )
- {
- for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ )
- {
- pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol;
- red += pSrcPixel->rgba[0];
- green += pSrcPixel->rgba[1];
- blue += pSrcPixel->rgba[2];
- alpha += pSrcPixel->rgba[3];
-
- samples++;
- }
- }
-
- pDstPixel = pDstImage + iRow * dstWidth + iCol;
- if ( samples > 0 )
- {
- pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples);
- pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples);
- pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples);
- pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples);
- }
- else
- {
- pDstPixel->rgba[0] = static_cast<uint8_t>(red);
- pDstPixel->rgba[1] = static_cast<uint8_t>(green);
- pDstPixel->rgba[2] = static_cast<uint8_t>(blue);
- pDstPixel->rgba[3] = static_cast<uint8_t>(alpha);
- }
- }
- }
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcFilter.h b/thirdparty/etc2comp/EtcFilter.h
deleted file mode 100644
index fcf125c6df..0000000000
--- a/thirdparty/etc2comp/EtcFilter.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#pragma once
-#include <stdint.h>
-#include <algorithm>
-
-namespace Etc
-{
-
-enum FilterEnums
-{
- MaxFilterSize = 32
-};
-
-enum WrapFlags
-{
- FILTER_WRAP_NONE = 0,
- FILTER_WRAP_X = 0x1,
- FILTER_WRAP_Y = 0x2
-};
-
-typedef struct tagFilterWeights
-{
- int first;
- int numWeights;
- double weight[MaxFilterSize * 2 + 1];
-} FilterWeights;
-
-typedef struct tagRGBCOLOR
-{
- union
- {
- uint32_t ulColor;
- uint8_t rgba[4];
- };
-} RGBCOLOR;
-
-
-double FilterBox( double t );
-double FilterLinear( double t );
-double FilterLanczos3( double t );
-
-int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) );
-void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDstImage, int dstWidth, int dstHeight );
-
-
-void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]);
-
-template <typename T>
-void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight)
-{
- float xScale;
- float yScale;
-
- T *pSrcPixel;
- T *pDstPixel;
-
- xScale = (float)srcWidth / dstWidth;
- yScale = (float)srcHeight / dstHeight;
-
- for (int iRow = 0; iRow < dstHeight; iRow++)
- {
- for (int iCol = 0; iCol < dstWidth; iCol++)
- {
- int samples;
- int iFirstSampleRow;
- int iFirstSampleCol;
- int iLastSampleRow;
- int iLastSampleCol;
- float red;
- float green;
- float blue;
- float alpha;
-
- iFirstSampleRow = (int)(iRow * yScale);
- iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
- if (iLastSampleRow >= srcHeight)
- {
- iLastSampleRow = srcHeight - 1;
- }
-
- iFirstSampleCol = (int)(iCol * xScale);
- iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
- if (iLastSampleCol >= srcWidth)
- {
- iLastSampleCol = srcWidth - 1;
- }
-
- samples = 0;
- red = 0.f;
- green = 0.f;
- blue = 0.f;
- alpha = 0.f;
- for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++)
- {
- for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++)
- {
- pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4;
- red += static_cast<float>(pSrcPixel[0]);
- green += static_cast<float>(pSrcPixel[1]);
- blue += static_cast<float>(pSrcPixel[2]);
- alpha += static_cast<float>(pSrcPixel[3]);
-
- samples++;
- }
- }
-
- pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4;
- if (samples > 0)
- {
- pDstPixel[0] = static_cast<T>(red / samples);
- pDstPixel[1] = static_cast<T>(green / samples);
- pDstPixel[2] = static_cast<T>(blue / samples);
- pDstPixel[3] = static_cast<T>(alpha / samples);
- }
- else
- {
- pDstPixel[0] = static_cast<T>(red);
- pDstPixel[1] = static_cast<T>(green);
- pDstPixel[2] = static_cast<T>(blue);
- pDstPixel[3] = static_cast<T>(alpha);
- }
- }
- }
-
-}
-
-//**-------------------------------------------------------------------------
-//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
-//** int srcWidth, int srcHeight,
-//** RGBCOLOR *pDestImage,
-//** int destWidth, int destHeight,
-//** double (*FilterProc)(double) )
-//** Returns: 0 on failure and 1 on success
-//** Description: Filters a 2d image with a two pass filter by averaging the
-//** weighted contributions of the pixels within the filter region. The
-//** contributions are determined by a weighting function parameter.
-//**-------------------------------------------------------------------------
-template <typename T>
-int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight,
- T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double))
-{
- const int numComponents = 4;
- FilterWeights *contrib;
- T *pPixel;
- T *pTempImage;
- double dRed;
- double dGreen;
- double dBlue;
- double dAlpha;
- double filterSize = 3.0;
-
- int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight;
- contrib = new FilterWeights[maxDim];
-
- //**------------------------------------------------------------------------
- //** Need to create a temporary image to stuff the horizontally scaled image
- //**------------------------------------------------------------------------
- pTempImage = new T[destWidth * srcHeight * numComponents];
- if (pTempImage == NULL)
- {
- return 0;
- }
-
- //**-------------------------------------------------------
- //** Horizontally filter the image into the temporary image
- //**-------------------------------------------------------
- bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
- CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib);
- for (int iRow = 0; iRow < srcHeight; iRow++)
- {
- for (int iCol = 0; iCol < destWidth; iCol++)
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++)
- {
- int iSrcCol = iWeight + contrib[iCol].first;
- if(bWrapHorizontal)
- {
- iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol;
- }
- T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents;
- dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0];
- dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1];
- dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2];
- dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3];
- }
-
- pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents;
- pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
- pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- //**-------------------------------------------------------
- //** Vertically filter the image into the destination image
- //**-------------------------------------------------------
- bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
- CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
- for (int iCol = 0; iCol < destWidth; iCol++)
- {
- for (int iRow = 0; iRow < destHeight; iRow++)
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++)
- {
- int iSrcRow = iWeight + contrib[iRow].first;
- if (bWrapVertical)
- {
- iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
- }
- T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents;
- dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0];
- dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1];
- dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2];
- dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3];
- }
-
- pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents;
- pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
- pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- delete[] pTempImage;
- delete[] contrib;
-
- return 1;
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcImage.cpp b/thirdparty/etc2comp/EtcImage.cpp
deleted file mode 100644
index 7a1058844d..0000000000
--- a/thirdparty/etc2comp/EtcImage.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcImage.cpp
-
-Image is an array of 4x4 blocks that represent the encoding of the source image
-
-*/
-
-#include "EtcConfig.h"
-
-#include <stdlib.h>
-
-#include "EtcImage.h"
-
-#include "Etc.h"
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcSortedBlockList.h"
-
-#if ETC_WINDOWS
-#include <windows.h>
-#endif
-#include <ctime>
-#include <chrono>
-#include <future>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-// fix conflict with Block4x4::AlphaMix
-#ifdef OPAQUE
-#undef OPAQUE
-#endif
-#ifdef TRANSPARENT
-#undef TRANSPARENT
-#endif
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- //
- Image::Image(void)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_warningsToCapture = EncodingStatus::SUCCESS;
- m_pafrgbaSource = nullptr;
-
- m_pablock = nullptr;
-
- m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- m_uiEncodingBitsBytes = 0;
- m_paucEncodingBits = nullptr;
-
- m_format = Format::UNKNOWN;
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // constructor using source image
- // used to set state before Encode() is called
- //
- Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- ErrorMetric a_errormetric)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_warningsToCapture = EncodingStatus::SUCCESS;
- m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA;
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- m_uiBlockColumns = m_uiExtendedWidth >> 2;
- m_uiBlockRows = m_uiExtendedHeight >> 2;
-
- m_pablock = new Block4x4[GetNumberOfBlocks()];
- assert(m_pablock);
-
- m_format = Format::UNKNOWN;
-
- m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- m_uiEncodingBitsBytes = 0;
- m_paucEncodingBits = nullptr;
-
- m_errormetric = a_errormetric;
- m_fEffort = 0.0f;
-
- m_iEncodeTime_ms = -1;
-
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
- m_bVerboseOutput = false;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // constructor using encoding bits
- // recreates encoding state using a previously encoded image
- //
- Image::Image(Format a_format,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
- Image *a_pimageSource, ErrorMetric a_errormetric)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_pafrgbaSource = nullptr;
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- m_uiBlockColumns = m_uiExtendedWidth >> 2;
- m_uiBlockRows = m_uiExtendedHeight >> 2;
-
- unsigned int uiBlocks = GetNumberOfBlocks();
-
- m_pablock = new Block4x4[uiBlocks];
- assert(m_pablock);
-
- m_format = a_format;
-
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
-
- m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
- if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
- return;
- }
- m_uiEncodingBitsBytes = a_uiEncodingBitsBytes;
- m_paucEncodingBits = a_paucEncidingBits;
-
- m_errormetric = a_errormetric;
- m_fEffort = 0.0f;
- m_bVerboseOutput = false;
- m_iEncodeTime_ms = -1;
-
- unsigned char *paucEncodingBits = m_paucEncodingBits;
- unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
-
- unsigned int uiH = 0;
- unsigned int uiV = 0;
- for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++)
- {
- m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits,
- a_pimageSource, a_errormetric);
- paucEncodingBits += uiEncodingBitsBytesPerBlock;
- uiH += 4;
- if (uiH >= m_uiSourceWidth)
- {
- uiH = 0;
- uiV += 4;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- Image::~Image(void)
- {
- if (m_pablock != nullptr)
- {
- delete[] m_pablock;
- m_pablock = nullptr;
- }
-
- /*if (m_paucEncodingBits != nullptr)
- {
- delete[] m_paucEncodingBits;
- m_paucEncodingBits = nullptr;
- }*/
- }
-
- // ----------------------------------------------------------------------------------------------------
- // encode an image
- // create a set of encoding bits that conforms to a_format
- // find best fit using a_errormetric
- // explore a range of possible encodings based on a_fEffort (range = [0:100])
- // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs)
- //
- Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs)
- {
-
- auto start = std::chrono::steady_clock::now();
-
- m_encodingStatus = EncodingStatus::SUCCESS;
-
- m_format = a_format;
- m_errormetric = a_errormetric;
- m_fEffort = a_fEffort;
-
- if (m_errormetric < 0 || m_errormetric > ERROR_METRICS)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC);
- return m_encodingStatus;
- }
-
- if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL)
- {
- AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
- m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL;
- }
- else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL)
- {
- AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
- m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL;
- }
- if (a_uiJobs < 1)
- {
- a_uiJobs = 1;
- AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
- }
- else if (a_uiJobs > a_uiMaxJobs)
- {
- a_uiJobs = a_uiMaxJobs;
- AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
- }
-
- m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
-
- if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
- return m_encodingStatus;
- }
-
- assert(m_paucEncodingBits == nullptr);
- m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
- m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes];
-
- InitBlocksAndBlockSorter();
-
-
- std::future<void> *handle = new std::future<void>[a_uiMaxJobs];
-
- unsigned int uiNumThreadsNeeded = 0;
- unsigned int uiUnfinishedBlocks = GetNumberOfBlocks();
-
- uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded);
- }
-
- RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handle[i].get();
- }
-
- // perform effort-based encoding
- if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL)
- {
- unsigned int uiFinishedBlocks = 0;
- unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks()));
-
- if (m_bVerboseOutput)
- {
- printf("effortblocks = %d\n", uiTotalEffortBlocks);
- }
- unsigned int uiPass = 0;
- while (1)
- {
- if (m_bVerboseOutput)
- {
- uiPass++;
- printf("pass %u\n", uiPass);
- }
- m_psortedblocklist->Sort();
- uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks();
- uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks;
- if (m_bVerboseOutput)
- {
- printf(" %u unfinished blocks\n", uiUnfinishedBlocks);
- // m_psortedblocklist->Print();
- }
-
-
-
- //stop enocding when we did enough to satify the effort percentage
- if (uiFinishedBlocks >= uiTotalEffortBlocks)
- {
- if (m_bVerboseOutput)
- {
- printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks);
- }
- break;
- }
-
- unsigned int uiIteratedBlocks = 0;
- unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks);
- uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
-
- if (uiNumThreadsNeeded <= 1)
- {
- //since we already how many blocks each thread will process
- //cap the thread limit to do the proper amount of work, and not more
- uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1);
- }
- else
- {
- //we have a lot of work to do, so lets multi thread it
- std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1];
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded);
- }
- uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- uiIteratedBlocks += handleToBlockEncoders[i].get();
- }
-
- delete[] handleToBlockEncoders;
- }
-
- if (m_bVerboseOutput)
- {
- printf(" %u iterated blocks\n", uiIteratedBlocks);
- }
- }
- }
-
- // generate Etc2-compatible bit-format 4x4 blocks
- for (int i = 0; i < (int)a_uiJobs - 1; i++)
- {
- handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs);
- }
- SetEncodingBits(a_uiJobs - 1, a_uiJobs);
-
- for (int i = 0; i < (int)a_uiJobs - 1; i++)
- {
- handle[i].get();
- }
-
- auto end = std::chrono::steady_clock::now();
- std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
- m_iEncodeTime_ms = (int)elapsed.count();
-
- delete[] handle;
- delete m_psortedblocklist;
- return m_encodingStatus;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // iterate the encoding thru the blocks with the worst error
- // stop when a_uiMaxBlocks blocks have been iterated
- // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride
- //
- unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
- unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
- unsigned int uiIteratedBlocks = a_uiMultithreadingOffset;
-
- SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock();
- for (plink = plink->Advance(a_uiMultithreadingOffset);
- plink != nullptr;
- plink = plink->Advance(a_uiMultithreadingStride) )
- {
- if (uiIteratedBlocks >= a_uiMaxBlocks)
- {
- break;
- }
-
- plink->GetBlock()->PerformEncodingIteration(m_fEffort);
-
- uiIteratedBlocks += a_uiMultithreadingStride;
- }
-
- return uiIteratedBlocks;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // determine which warnings to check for during Encode() based on encoding format
- //
- void Image::FindEncodingWarningTypesForCurFormat()
- {
- TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1);
- switch (m_format)
- {
- case Image::Format::ETC1:
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
- break;
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
- TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- break;
-
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- break;
- case Image::Format::FORMATS:
- case Image::Format::UNKNOWN:
- default:
- assert(0);
- break;
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // examine source pixels to check for warnings
- //
- void Image::FindAndSetEncodingWarnings()
- {
- int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4);
- if (m_iNumOpaquePixels == numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS);
- }
- if (m_iNumOpaquePixels < numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS);
- }
- if (m_iNumTranslucentPixels > 0)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS);
- }
- if (m_iNumTransparentPixels == numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS);
- }
- if (m_numColorValues.fB > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- }
- if (m_numColorValues.fG > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
- }
-
- if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
- }
- if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a string name for a given image format
- //
- const char * Image::EncodingFormatToString(Image::Format a_format)
- {
- switch (a_format)
- {
- case Image::Format::ETC1:
- return "ETC1";
- case Image::Format::RGB8:
- return "RGB8";
- case Image::Format::SRGB8:
- return "SRGB8";
-
- case Image::Format::RGB8A1:
- return "RGB8A1";
- case Image::Format::SRGB8A1:
- return "SRGB8A1";
- case Image::Format::RGBA8:
- return "RGBA8";
- case Image::Format::SRGBA8:
- return "SRGBA8";
-
- case Image::Format::R11:
- return "R11";
- case Image::Format::SIGNED_R11:
- return "SIGNED_R11";
-
- case Image::Format::RG11:
- return "RG11";
- case Image::Format::SIGNED_RG11:
- return "SIGNED_RG11";
- case Image::Format::FORMATS:
- case Image::Format::UNKNOWN:
- default:
- return "UNKNOWN";
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a string name for the image's format
- //
- const char * Image::EncodingFormatToString(void)
- {
- return EncodingFormatToString(m_format);
- }
-
- // ----------------------------------------------------------------------------------------------------
- // init image blocks prior to encoding
- // init block sorter for subsequent sortings
- // check for encoding warnings
- //
- void Image::InitBlocksAndBlockSorter(void)
- {
-
- FindEncodingWarningTypesForCurFormat();
-
- // init each block
- Block4x4 *pblock = m_pablock;
- unsigned char *paucEncodingBits = m_paucEncodingBits;
- for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++)
- {
- unsigned int uiBlockV = uiBlockRow * 4;
-
- for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++)
- {
- unsigned int uiBlockH = uiBlockColumn * 4;
-
- pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric);
-
- paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
-
- pblock++;
- }
- }
-
- FindAndSetEncodingWarnings();
-
- // init block sorter
- {
- m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100);
-
- for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
- {
- pblock = &m_pablock[uiBlock];
- m_psortedblocklist->AddBlock(pblock);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // run the first pass of the encoder
- // the encoder generally finds a reasonable, fast encoding
- // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding
- //
- void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
-
- for (unsigned int uiBlock = a_uiMultithreadingOffset;
- uiBlock < GetNumberOfBlocks();
- uiBlock += a_uiMultithreadingStride)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- pblock->PerformEncodingIteration(m_fEffort);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits (for the output file) based on the best encoding for each block
- //
- void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
-
- for (unsigned int uiBlock = a_uiMultithreadingOffset;
- uiBlock < GetNumberOfBlocks();
- uiBlock += a_uiMultithreadingStride)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- pblock->SetEncodingBitsFromEncoding();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return the image error
- // image error is the sum of all block errors
- //
- float Image::GetError(void)
- {
- float fError = 0.0f;
-
- for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- fError += pblock->GetError();
- }
-
- return fError;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // determine the encoding bits format based on the encoding format
- // the encoding bits format is a family of bit encodings that are shared across various encoding formats
- //
- Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format)
- {
- Block4x4EncodingBits::Format encodingbitsformat;
-
- // determine encoding bits format from image format
- switch (a_format)
- {
- case Format::ETC1:
- case Format::RGB8:
- case Format::SRGB8:
- encodingbitsformat = Block4x4EncodingBits::Format::RGB8;
- break;
-
- case Format::RGBA8:
- case Format::SRGBA8:
- encodingbitsformat = Block4x4EncodingBits::Format::RGBA8;
- break;
-
- case Format::R11:
- case Format::SIGNED_R11:
- encodingbitsformat = Block4x4EncodingBits::Format::R11;
- break;
-
- case Format::RG11:
- case Format::SIGNED_RG11:
- encodingbitsformat = Block4x4EncodingBits::Format::RG11;
- break;
-
- case Format::RGB8A1:
- case Format::SRGB8A1:
- encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1;
- break;
-
- default:
- encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- break;
- }
-
- return encodingbitsformat;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcImage.h b/thirdparty/etc2comp/EtcImage.h
deleted file mode 100644
index bd807ac32e..0000000000
--- a/thirdparty/etc2comp/EtcImage.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-//#include "Etc.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcErrorMetric.h"
-
-
-namespace Etc
-{
- class Block4x4;
- class EncoderSpec;
- class SortedBlockList;
-
- class Image
- {
- public:
-
- //the differnt warning and errors that can come up during encoding
- enum EncodingStatus
- {
- SUCCESS = 0,
- //
- WARNING_THRESHOLD = 1 << 0,
- //
- WARNING_EFFORT_OUT_OF_RANGE = 1 << 1,
- WARNING_JOBS_OUT_OF_RANGE = 1 << 2,
- WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11
- WARNING_ALL_OPAQUE_PIXELS = 1 << 4,
- WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5,
- WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1
- WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7,
- WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8,
- WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9,
- //
- ERROR_THRESHOLD = 1 << 16,
- //
- ERROR_UNKNOWN_FORMAT = 1 << 17,
- ERROR_UNKNOWN_ERROR_METRIC = 1 << 18,
- ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19,
- //
- };
-
- enum class Format
- {
- UNKNOWN,
- //
- ETC1,
- //
- // ETC2 formats
- RGB8,
- SRGB8,
- RGBA8,
- SRGBA8,
- R11,
- SIGNED_R11,
- RG11,
- SIGNED_RG11,
- RGB8A1,
- SRGB8A1,
- //
- FORMATS,
- //
- DEFAULT = SRGB8
- };
-
- // constructor using source image
- Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- ErrorMetric a_errormetric);
-
- // constructor using encoding bits
- Image(Format a_format,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
- Image *a_pimageSource,
- ErrorMetric a_errormetric);
-
- ~Image(void);
-
- EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort,
- unsigned int a_uiJobs, unsigned int a_uiMaxJobs);
-
- inline void AddToEncodingStatus(EncodingStatus a_encStatus)
- {
- m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus);
- }
-
- inline unsigned int GetSourceWidth(void)
- {
- return m_uiSourceWidth;
- }
-
- inline unsigned int GetSourceHeight(void)
- {
- return m_uiSourceHeight;
- }
-
- inline unsigned int GetExtendedWidth(void)
- {
- return m_uiExtendedWidth;
- }
-
- inline unsigned int GetExtendedHeight(void)
- {
- return m_uiExtendedHeight;
- }
-
- inline unsigned int GetNumberOfBlocks()
- {
- return m_uiBlockColumns * m_uiBlockRows;
- }
-
- inline Block4x4 * GetBlocks()
- {
- return m_pablock;
- }
-
- inline unsigned char * GetEncodingBits(void)
- {
- return m_paucEncodingBits;
- }
-
- inline unsigned int GetEncodingBitsBytes(void)
- {
- return m_uiEncodingBitsBytes;
- }
-
- inline int GetEncodingTimeMs(void)
- {
- return m_iEncodeTime_ms;
- }
-
- float GetError(void);
-
- inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV)
- {
- if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight)
- {
- return nullptr;
- }
-
- return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH];
- }
-
- inline Format GetFormat(void)
- {
- return m_format;
- }
-
- static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format);
-
- inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension)
- {
- return (unsigned short)((a_ushOriginalDimension + 3) & ~3);
- }
-
- inline ErrorMetric GetErrorMetric(void)
- {
- return m_errormetric;
- }
-
- static const char * EncodingFormatToString(Image::Format a_format);
- const char * EncodingFormatToString(void);
- //used to get basic information about the image data
- int m_iNumOpaquePixels;
- int m_iNumTranslucentPixels;
- int m_iNumTransparentPixels;
-
- ColorFloatRGBA m_numColorValues;
- ColorFloatRGBA m_numOutOfRangeValues;
-
- bool m_bVerboseOutput;
- private:
- //add a warning or error to check for while encoding
- inline void TrackEncodingWarning(EncodingStatus a_encStatus)
- {
- m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus);
- }
-
- //report the warning if it is something we care about for this encoding
- inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus)
- {
- if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus)
- {
- AddToEncodingStatus(a_encStatus);
- }
- }
-
- Image(void);
- void FindEncodingWarningTypesForCurFormat();
- void FindAndSetEncodingWarnings();
-
- void InitBlocksAndBlockSorter(void);
-
- void RunFirstPass(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- void SetEncodingBits(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
- unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- // inputs
- ColorFloatRGBA *m_pafrgbaSource;
- unsigned int m_uiSourceWidth;
- unsigned int m_uiSourceHeight;
- unsigned int m_uiExtendedWidth;
- unsigned int m_uiExtendedHeight;
- unsigned int m_uiBlockColumns;
- unsigned int m_uiBlockRows;
- // intermediate data
- Block4x4 *m_pablock;
- // encoding
- Format m_format;
- Block4x4EncodingBits::Format m_encodingbitsformat;
- unsigned int m_uiEncodingBitsBytes; // for entire image
- unsigned char *m_paucEncodingBits;
- ErrorMetric m_errormetric;
- float m_fEffort;
- // stats
- int m_iEncodeTime_ms;
-
- SortedBlockList *m_psortedblocklist;
- //this will hold any warning or errors that happen during encoding
- EncodingStatus m_encodingStatus;
- //these will be the warnings we are tracking
- EncodingStatus m_warningsToCapture;
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.cpp b/thirdparty/etc2comp/EtcIndividualTrys.cpp
deleted file mode 100644
index 56ff4c65ec..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcIndividualTrys.cpp
-
-Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcIndividualTrys.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct a list of trys (encoding attempts)
- //
- // a_frgbaColor1 is the basecolor for the first half
- // a_frgbaColor2 is the basecolor for the second half
- // a_pauiPixelMapping1 is the pixel order for the first half
- // a_pauiPixelMapping2 is the pixel order for the second half
- // a_uiRadius is the amount to vary the base colors
- //
- IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius)
- {
- assert(a_uiRadius <= MAX_RADIUS);
-
- ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4();
- ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4();
-
- // quantize base colors
- // ensure that trys with a_uiRadius don't overflow
- int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius);
- int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius);
- int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius);
- int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius);
- int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius);
- int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius);
-
- m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
- m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
- {
-
- m_iRed = a_iRed;
- m_iGreen = a_iGreen;
- m_iBlue = a_iBlue;
-
- m_pauiPixelMapping = a_pauiPixelMapping;
- m_uiRadius = a_uiRadius;
-
- m_uiTrys = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.h b/thirdparty/etc2comp/EtcIndividualTrys.h
deleted file mode 100644
index 5fb12fbcf4..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-namespace Etc
-{
-
- class IndividualTrys
- {
- public:
-
- static const unsigned int MAX_RADIUS = 1;
-
- IndividualTrys(ColorFloatRGBA a_frgbaColor1,
- ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius);
-
- inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
- {
- if (a_i < (0+ a_iDistance))
- {
- return (0 + a_iDistance);
- }
- else if (a_i > (15- a_iDistance))
- {
- return (15 - a_iDistance);
- }
-
- return a_i;
- }
-
- class Try
- {
- public :
- static const unsigned int SELECTORS = 8; // per half
-
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
- unsigned int m_uiCW;
- unsigned int m_auiSelectors[SELECTORS];
- float m_fError;
- };
-
- class Half
- {
- public:
-
- static const unsigned int MAX_TRYS = 27;
-
- void Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping,
- unsigned int a_uiRadius);
-
- // center of trys
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
-
- const unsigned int *m_pauiPixelMapping;
- unsigned int m_uiRadius;
-
- unsigned int m_uiTrys;
- Try m_atry[MAX_TRYS];
-
- Try *m_ptryBest;
- };
-
- Half m_half1;
- Half m_half2;
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcMath.cpp b/thirdparty/etc2comp/EtcMath.cpp
deleted file mode 100644
index 096d5f7ab9..0000000000
--- a/thirdparty/etc2comp/EtcMath.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcConfig.h"
-#include "EtcMath.h"
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[]
- // use a_fSlope and a_fOffset to define that line
- //
- bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
- float *a_fSlope, float *a_fOffset)
- {
- float fPoints = (float)a_Points;
-
- float fSumX = 0.0f;
- float fSumY = 0.0f;
- float fSumXY = 0.0f;
- float fSumX2 = 0.0f;
-
- for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++)
- {
- fSumX += a_afX[uiPoint];
- fSumY += a_afY[uiPoint];
- fSumXY += a_afX[uiPoint] * a_afY[uiPoint];
- fSumX2 += a_afX[uiPoint] * a_afX[uiPoint];
- }
-
- float fDivisor = fPoints*fSumX2 - fSumX*fSumX;
-
- // if vertical line
- if (fDivisor == 0.0f)
- {
- *a_fSlope = 0.0f;
- *a_fOffset = 0.0f;
- return true;
- }
-
- *a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor;
- *a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints;
-
- return false;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcMath.h b/thirdparty/etc2comp/EtcMath.h
deleted file mode 100644
index c58c9a91bc..0000000000
--- a/thirdparty/etc2comp/EtcMath.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <math.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // return true if vertical line
- bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
- float *a_fSlope, float *a_fOffset);
-
- inline float ConvertMSEToPSNR(float a_fMSE)
- {
- if (a_fMSE == 0.0f)
- {
- return INFINITY;
- }
-
- return 10.0f * log10f(1.0f / a_fMSE);
- }
-
-
-}
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.cpp b/thirdparty/etc2comp/EtcSortedBlockList.cpp
deleted file mode 100644
index bfa6b7b3fa..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcSortedBlockList.cpp
-
-SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize
-the encoding of the 4x4 blocks.
-
-The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcSortedBlockList.h"
-
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct an empty list
- //
- // allocate enough memory to add all of the image's 4x4 blocks later
- // allocate enough buckets to sort the blocks
- //
- SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets)
- {
- m_uiImageBlocks = a_uiImageBlocks;
- m_iBuckets = (int)a_uiBuckets;
-
- m_uiAddedBlocks = 0;
- m_uiSortedBlocks = 0;
- m_palinkPool = new Link[m_uiImageBlocks];
- m_pabucket = new Bucket[m_iBuckets];
- m_fMaxError = 0.0f;
-
- InitBuckets();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- SortedBlockList::~SortedBlockList(void)
- {
- delete[] m_palinkPool;
- delete[] m_pabucket;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // add a 4x4 block to the list
- // the 4x4 block will be sorted later
- //
- void SortedBlockList::AddBlock(Block4x4 *a_pblock)
- {
- assert(m_uiAddedBlocks < m_uiImageBlocks);
- Link *plink = &m_palinkPool[m_uiAddedBlocks++];
- plink->Init(a_pblock);
- }
-
- // ----------------------------------------------------------------------------------------------------
- // sort all of the 4x4 blocks that have been added to the list
- //
- // first, determine the maximum error, then assign an error range to each bucket
- // next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error
- // add the 4x4 block to the appropriate bucket
- // lastly, walk thru the buckets and add each bucket to a sorted linked list
- //
- // the resultant sorting is an approximate sorting from most to least error
- //
- void SortedBlockList::Sort(void)
- {
- assert(m_uiAddedBlocks == m_uiImageBlocks);
- InitBuckets();
-
- // find max block error
- m_fMaxError = -1.0f;
-
- for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
- {
- Link *plinkBlock = &m_palinkPool[uiLink];
-
- float fBlockError = plinkBlock->GetBlock()->GetError();
- if (fBlockError > m_fMaxError)
- {
- m_fMaxError = fBlockError;
- }
- }
- // prevent divide by zero or divide by negative
- if (m_fMaxError <= 0.0f)
- {
- m_fMaxError = 1.0f;
- }
- //used for debugging
- //int numDone = 0;
- // put all of the blocks with unfinished encodings into the appropriate bucket
- m_uiSortedBlocks = 0;
- for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
- {
- Link *plinkBlock = &m_palinkPool[uiLink];
-
- // if the encoding is done, don't add it to the list
- if (plinkBlock->GetBlock()->GetEncoding()->IsDone())
- {
- //numDone++;
- continue;
- }
-
- // calculate the appropriate sort bucket
- float fBlockError = plinkBlock->GetBlock()->GetError();
- int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError);
- // clamp to bucket index
- iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket;
-
- // add block to bucket
- {
- Bucket *pbucket = &m_pabucket[iBucket];
- if (pbucket->plinkLast)
- {
- pbucket->plinkLast->SetNext(plinkBlock);
- pbucket->plinkLast = plinkBlock;
- }
- else
- {
- pbucket->plinkFirst = pbucket->plinkLast = plinkBlock;
- }
- plinkBlock->SetNext(nullptr);
- }
-
- m_uiSortedBlocks++;
-
- if (0)
- {
- printf("%u: e=%.3f\n", uiLink, fBlockError);
- Print();
- printf("\n\n\n");
- }
- }
- //printf("num blocks already done: %d\n",numDone);
- //link the blocks together across buckets
- m_plinkFirst = nullptr;
- m_plinkLast = nullptr;
- for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- if (pbucket->plinkFirst)
- {
- if (m_plinkFirst == nullptr)
- {
- m_plinkFirst = pbucket->plinkFirst;
- }
- else
- {
- assert(pbucket->plinkLast->GetNext() == nullptr);
- m_plinkLast->SetNext(pbucket->plinkFirst);
- }
-
- m_plinkLast = pbucket->plinkLast;
- }
- }
-
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // clear all of the buckets. normally done in preparation for a sort
- //
- void SortedBlockList::InitBuckets(void)
- {
- for (int iBucket = 0; iBucket < m_iBuckets; iBucket++)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- pbucket->plinkFirst = 0;
- pbucket->plinkLast = 0;
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // print out the list of sorted 4x4 blocks
- // normally used for debugging
- //
- void SortedBlockList::Print(void)
- {
- for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- unsigned int uiBlocks = 0;
- for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() )
- {
- uiBlocks++;
-
- if (plink == pbucket->plinkLast)
- {
- break;
- }
- }
-
- float fBucketError = m_fMaxError * iBucket / m_iBuckets;
- float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) );
- printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.h b/thirdparty/etc2comp/EtcSortedBlockList.h
deleted file mode 100644
index 960e8adc34..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace Etc
-{
- class Block4x4;
-
- class SortedBlockList
- {
- public:
-
- class Link
- {
- public:
-
- inline void Init(Block4x4 *a_pblock)
- {
- m_pblock = a_pblock;
- m_plinkNext = nullptr;
- }
-
- inline Block4x4 * GetBlock(void)
- {
- return m_pblock;
- }
-
- inline void SetNext(Link *a_plinkNext)
- {
- m_plinkNext = a_plinkNext;
- }
-
- inline Link * GetNext(void)
- {
- return m_plinkNext;
- }
-
- inline Link * Advance(unsigned int a_uiSteps = 1)
- {
- Link *plink = this;
-
- for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++)
- {
- if (plink == nullptr)
- {
- break;
- }
-
- plink = plink->m_plinkNext;
- }
-
- return plink;
- }
-
- private:
-
- Block4x4 *m_pblock;
- Link *m_plinkNext;
- };
-
- SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets);
- ~SortedBlockList(void);
-
- void AddBlock(Block4x4 *a_pblock);
-
- void Sort(void);
-
- inline Link * GetLinkToFirstBlock(void)
- {
- return m_plinkFirst;
- }
-
- inline unsigned int GetNumberOfAddedBlocks(void)
- {
- return m_uiAddedBlocks;
- }
-
- inline unsigned int GetNumberOfSortedBlocks(void)
- {
- return m_uiSortedBlocks;
- }
-
- void Print(void);
-
- private:
-
- void InitBuckets(void);
-
- class Bucket
- {
- public:
- Link *plinkFirst;
- Link *plinkLast;
- };
-
- unsigned int m_uiImageBlocks;
- int m_iBuckets;
-
- unsigned int m_uiAddedBlocks;
- unsigned int m_uiSortedBlocks;
- Link *m_palinkPool;
- Bucket *m_pabucket;
- float m_fMaxError;
-
- Link *m_plinkFirst;
- Link *m_plinkLast;
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/LICENSE b/thirdparty/etc2comp/LICENSE
deleted file mode 100644
index d645695673..0000000000
--- a/thirdparty/etc2comp/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/thirdparty/etc2comp/README.md b/thirdparty/etc2comp/README.md
deleted file mode 100644
index 2f4363d042..0000000000
--- a/thirdparty/etc2comp/README.md
+++ /dev/null
@@ -1,197 +0,0 @@
-# Etc2Comp - Texture to ETC2 compressor
-
-Etc2Comp is a command line tool that converts textures (e.g. bitmaps)
-into the [ETC2](https://en.wikipedia.org/wiki/Ericsson_Texture_Compression)
-format. The tool is built with a focus on encoding performance
-to reduce the amount of time required to compile asset heavy applications as
-well as reduce overall application size.
-
-This repo provides source code that can be compiled into a binary. The
-binary can then be used to convert textures to the ETC2 format.
-
-Important: This is not an official Google product. It is an experimental
-library published as-is. Please see the CONTRIBUTORS.md file for information
-about questions or issues.
-
-## Setup
-This project uses [CMake](https://cmake.org/) to generate platform-specific
-build files:
- - Linux: make files
- - OS X: Xcode workspace files
- - Microsoft Windows: Visual Studio solution files
- - Note: CMake supports other formats, but this doc only provides steps for
- one of each platform for brevity.
-
-Refer to each platform's setup section to setup your environment and build
-an Etc2Comp binary. Then skip to the usage section of this page for examples
-of how to use the library.
-
-### Setup for OS X
- build tested on this config:
- OS X 10.9.5 i7 16GB RAM
- Xcode 5.1.1
- cmake 3.2.3
-
-Start by downloading and installing the following components if they are not
-already installed on your development machine.
- - *Xcode* version 5.1.1, or greater
- - [CMake](https://cmake.org/download/) version 3.2.3, or greater
-
-To build the Etc2Comp binary:
- 1. Open a *Terminal* window and navigate to the project directory.
- 1. Run `mkdir build_xcode`
- 1. Run `cd build_xcode`
- 1. Run `cmake -G Xcode ../`
- 1. Open *Xcode* and import the `build_xcode/EtcTest.xcodeproj` file.
- 1. Open the Product menu and choose Build For -> Running.
- 1. Once the build succeeds the binary located at `build_xcode/EtcTool/Debug/EtcTool`
-can be executed.
-
-Optional
-Xcode EtcTool ‘Run’ preferences
-note: if the build_xcode/EtcTest.xcodeproj is manually deleted then some Xcode preferences
-will need to be set by hand after cmake is run (these prefs are retained across
-cmake updates if the .xcodeproj is not deleted/removed)
-
-1. Set the active scheme to ‘EtcTool’
-1. Edit the scheme
-1. Select option ‘Run EtcTool’, then tab ‘Arguments’.
-Add this launch argument: ‘-argfile ../../EtcTool/args.txt’
-1. Select tab ‘Options’ and set a custom working directory to: ‘$(SRCROOT)/Build_Xcode/EtcTool’
-
-### SetUp for Windows
-
-1. Open a *Terminal* window and navigate to the project directory.
-1. Run `mkdir build_vs`
-1. Run `cd build_vs`
-1. Run CMAKE, noting what build version you need, and pointing to the parent directory as the source root;
- For VS 2013 : `cmake -G "Visual Studio 12 2013 Win64" ../`
- For VS 2015 : `cmake -G "Visual Studio 14 2015 Win64" ../`
- NOTE: To see what supported Visual Studio outputs there are, run `cmake -G`
-1. open the 'EtcTest' solution
-1. make the 'EtcTool' project the start up project
-1. (optional) in the project properties, under 'Debugging ->command arguments'
-add the argfile textfile thats included in the EtcTool directory.
-example: -argfile C:\etc2\EtcTool\Args.txt
-
-### Setup For Linux
-The Linux build was tested on this config:
- Ubuntu desktop 14.04
- gcc/g++ 4.8
- cmake 2.8.12.2
-
-1. Verify linux has cmake and C++-11 capable g++ installed
-1. Open shell
-1. Run `mkdir build_linux`
-1. Run `cd build_linux`
-1. Run `cmake ../`
-1. Run `make`
-1. navigate to the newly created EtcTool directory `cd EtcTool`
-1. run the executable: `./EtcTool -argfile ../../EtcTool/args.txt`
-
-Skip to the <a href="#usage">Usage</a> section for more information about using the
-tool.
-
-## Usage
-
-### Command Line Usage
-EtcTool can be run from the command line with the following usage:
- etctool.exe source_image [options ...] -output encoded_image
-
-The encoder will use an array of RGBA floats read from the source_image to create
-an ETC1 or ETC2 encoded image in encoded_image. The RGBA floats should be in the
-range [0:1].
-
-Options:
-
- -analyze <analysis_folder>
- -argfile <arg_file> additional command line arguments read from a file
- -blockAtHV <H V> encodes a single block that contains the
- pixel specified by the H V coordinates
- -compare <comparison_image> compares source_image to comparison_image
- -effort <amount> number between 0 and 100 to specify the encoding quality
- (100 is the highest quality)
- -errormetric <error_metric> specify the error metric, the options are
- rgba, rgbx, rec709, numeric and normalxyz
- -format <etc_format> ETC1, RGB8, SRGB8, RGBA8, SRGB8, RGB8A1,
- SRGB8A1 or R11
- -help prints this message
- -jobs or -j <thread_count> specifies the number of threads (default=1)
- -normalizexyz normalize RGB to have a length of 1
- -verbose or -v shows status information during the encoding
- process
- -mipmaps or -m <mip_count> sets the maximum number of mipaps to generate (default=1)
- -mipwrap or -w <x|y|xy> sets the mipmap filter wrap mode (default=clamp)
-
-* -analyze will run an analysis of the encoding and place it in folder
-"analysis_folder" (e.g. ../analysis/kodim05). within the analysis_folder, a folder
-will be created with a name of the current date/time (e.g. 20151204_153306). this
-date/time folder is used to compare encodings of the same texture over time.
-within the date/time folder is a text file with several encoding stats and a 2x png
-image showing the encoding mode for each 4x4 block.
-
-* -argfile allows additional command line arguments to be placed in a text file
-
-* -blockAtHV selects the 4x4 pixel subset of the source image at position (H,V).
-This is mainly used for debugging
-
-* -compare compares the source image to the created encoded image. The encoding
-will dictate what error analysis is used in the comparison.
-
-* -effort uses an "amount" between 0 and 100 to determine how much additional effort
-to apply during the encoding.
-
-* -errormetric selects the fitting algorithm used by the encoder. "rgba" calculates
-RMS error using RGB components that are weighted by A. "rgbx" calculates RMS error
-using RGBA components, where A is treated as an additional data channel, instead of
-as alpha. "rec709" is similar to "rgba", except the RGB components are also weighted
-according to Rec709. "numeric" calculates RMS error using unweighted RGBA components.
-"normalize" calculates error based on dot product and vector length for RGB and RMS
-error for A.
-
-* -help prints out the usage message
-
-* -jobs enables multi-threading to speed up image encoding
-
-* -normalizexyz normalizes the source RGB to have a length of 1.
-
-* -verbose shows information on the current encoding process. It will then display the
-PSNR and time time it took to encode the image.
-
-* -mipmaps takes an argument that specifies how many mipmaps to generate from the
-source image. The mipmaps are generated with a lanczos3 filter using edge clamping.
-If the mipmaps option is not specified no mipmaps are created.
-
-* -mipwrap takes an argument that specifies the mipmap filter wrap mode. The options
-are "x", "y" and "xy" which specify wrapping in x only, y only or x and y respectively.
-The default options are clamping in both x and y.
-
-Note: Path names can use slashes or backslashes. The tool will convert the
-slashes to the appropriate polarity for the current platform.
-
-
-## API
-
-The library supports two different APIs - a C-like API that is not heavily
-class-based and a class-based API.
-
-main() in EtcTool.cpp contains an example of both APIs.
-
-The Encode() method now returns an EncodingStatus that contains bit flags for
-reporting various warnings and flags encountered when encoding.
-
-
-## Copyright
-Copyright 2015 Etc2Comp Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
deleted file mode 100644
index ea9b5640b6..0000000000
--- a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
+++ /dev/null
@@ -1,224 +0,0 @@
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-index 5656556db9..5c7ebed788 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-@@ -508,7 +508,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -519,7 +519,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -530,7 +530,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -545,7 +545,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -556,7 +556,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -567,7 +567,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -761,7 +761,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -772,7 +772,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -783,7 +783,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -798,7 +798,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -809,7 +809,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -820,7 +820,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-index ba2b42fb05..b94b64e68c 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-@@ -847,7 +847,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -858,7 +858,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -869,7 +869,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -884,7 +884,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -895,7 +895,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -906,7 +906,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -1108,7 +1108,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -1119,7 +1119,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -1130,7 +1130,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -1145,7 +1145,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -1156,7 +1156,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -1167,7 +1167,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
diff --git a/thirdparty/etcpak/AUTHORS.txt b/thirdparty/etcpak/AUTHORS.txt
new file mode 100644
index 0000000000..e7bae62c85
--- /dev/null
+++ b/thirdparty/etcpak/AUTHORS.txt
@@ -0,0 +1,3 @@
+Bartosz Taudul <wolf@nereid.pl>
+Daniel Jungmann <el.3d.source@gmail.com>
+Florian Penzkofer <fp@nullptr.de>
diff --git a/thirdparty/etcpak/Dither.cpp b/thirdparty/etcpak/Dither.cpp
new file mode 100644
index 0000000000..355686f26b
--- /dev/null
+++ b/thirdparty/etcpak/Dither.cpp
@@ -0,0 +1,120 @@
+#include <algorithm>
+#include <string.h>
+
+#include "Dither.hpp"
+#include "Math.hpp"
+#ifdef __SSE4_1__
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i l0 = _mm256_inserti128_si256( _mm256_castsi128_si256( px0 ), px1, 1 );
+ __m256i l1 = _mm256_inserti128_si256( _mm256_castsi128_si256( px2 ), px3, 1 );
+
+ __m256i a0 = _mm256_adds_epu8( l0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( l1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+
+}
+#endif
+
+void Dither( uint8_t* data )
+{
+#ifdef __AVX2__
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i px0 = _mm256_loadu_si256( (__m256i*)(data ) );
+ __m256i px1 = _mm256_loadu_si256( (__m256i*)(data+32) );
+
+ __m256i a0 = _mm256_adds_epu8( px0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( px1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+#else
+ static constexpr int8_t Bayer31[16] = {
+ ( 0-8)*2/3, ( 8-8)*2/3, ( 2-8)*2/3, (10-8)*2/3,
+ (12-8)*2/3, ( 4-8)*2/3, (14-8)*2/3, ( 6-8)*2/3,
+ ( 3-8)*2/3, (11-8)*2/3, ( 1-8)*2/3, ( 9-8)*2/3,
+ (15-8)*2/3, ( 7-8)*2/3, (13-8)*2/3, ( 5-8)*2/3
+ };
+ static constexpr int8_t Bayer63[16] = {
+ ( 0-8)*2/6, ( 8-8)*2/6, ( 2-8)*2/6, (10-8)*2/6,
+ (12-8)*2/6, ( 4-8)*2/6, (14-8)*2/6, ( 6-8)*2/6,
+ ( 3-8)*2/6, (11-8)*2/6, ( 1-8)*2/6, ( 9-8)*2/6,
+ (15-8)*2/6, ( 7-8)*2/6, (13-8)*2/6, ( 5-8)*2/6
+ };
+
+ for( int i=0; i<16; i++ )
+ {
+ uint32_t col;
+ memcpy( &col, data, 4 );
+ uint8_t r = col & 0xFF;
+ uint8_t g = ( col >> 8 ) & 0xFF;
+ uint8_t b = ( col >> 16 ) & 0xFF;
+
+ r = clampu8( r + Bayer31[i] );
+ g = clampu8( g + Bayer63[i] );
+ b = clampu8( b + Bayer31[i] );
+
+ col = r | ( g << 8 ) | ( b << 16 );
+ memcpy( data, &col, 4 );
+ data += 4;
+ }
+#endif
+}
diff --git a/thirdparty/etcpak/Dither.hpp b/thirdparty/etcpak/Dither.hpp
new file mode 100644
index 0000000000..e43ce5676d
--- /dev/null
+++ b/thirdparty/etcpak/Dither.hpp
@@ -0,0 +1,21 @@
+#ifndef __DITHER_HPP__
+#define __DITHER_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+void Dither( uint8_t* data );
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 );
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/ForceInline.hpp b/thirdparty/etcpak/ForceInline.hpp
new file mode 100644
index 0000000000..b6f012841b
--- /dev/null
+++ b/thirdparty/etcpak/ForceInline.hpp
@@ -0,0 +1,20 @@
+#ifndef __FORCEINLINE_HPP__
+#define __FORCEINLINE_HPP__
+
+#if defined(__GNUC__)
+# define etcpak_force_inline __attribute__((always_inline)) inline
+#elif defined(_MSC_VER)
+# define etcpak_force_inline __forceinline
+#else
+# define etcpak_force_inline inline
+#endif
+
+#if defined(__GNUC__)
+# define etcpak_no_inline __attribute__((noinline))
+#elif defined(_MSC_VER)
+# define etcpak_no_inline __declspec(noinline)
+#else
+# define etcpak_no_inline
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/LICENSE.txt b/thirdparty/etcpak/LICENSE.txt
new file mode 100644
index 0000000000..59e85d6ea5
--- /dev/null
+++ b/thirdparty/etcpak/LICENSE.txt
@@ -0,0 +1,26 @@
+etcpak, an extremely fast ETC compression utility (https://github.com/wolfpld/etcpak)
+
+Copyright (c) 2013-2021, Bartosz Taudul <wolf@nereid.pl>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/thirdparty/etcpak/Math.hpp b/thirdparty/etcpak/Math.hpp
new file mode 100644
index 0000000000..994e1ac4ea
--- /dev/null
+++ b/thirdparty/etcpak/Math.hpp
@@ -0,0 +1,92 @@
+#ifndef __DARKRL__MATH_HPP__
+#define __DARKRL__MATH_HPP__
+
+#include <algorithm>
+#include <cmath>
+#include <stdint.h>
+
+#include "ForceInline.hpp"
+
+template<typename T>
+static etcpak_force_inline T AlignPOT( T val )
+{
+ if( val == 0 ) return 1;
+ val--;
+ for( unsigned int i=1; i<sizeof( T ) * 8; i <<= 1 )
+ {
+ val |= val >> i;
+ }
+ return val + 1;
+}
+
+static etcpak_force_inline int CountSetBits( uint32_t val )
+{
+ val -= ( val >> 1 ) & 0x55555555;
+ val = ( ( val >> 2 ) & 0x33333333 ) + ( val & 0x33333333 );
+ val = ( ( val >> 4 ) + val ) & 0x0f0f0f0f;
+ val += val >> 8;
+ val += val >> 16;
+ return val & 0x0000003f;
+}
+
+static etcpak_force_inline int CountLeadingZeros( uint32_t val )
+{
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ return 32 - CountSetBits( val );
+}
+
+static etcpak_force_inline float sRGB2linear( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.04045f )
+ {
+ return v / 12.92f;
+ }
+ else
+ {
+ return pow( ( v + a ) / ( 1 + a ), 2.4f );
+ }
+}
+
+static etcpak_force_inline float linear2sRGB( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.0031308f )
+ {
+ return 12.92f * v;
+ }
+ else
+ {
+ return ( 1 + a ) * pow( v, 1/2.4f ) - a;
+ }
+}
+
+template<class T>
+static etcpak_force_inline T SmoothStep( T x )
+{
+ return x*x*(3-2*x);
+}
+
+static etcpak_force_inline uint8_t clampu8( int32_t val )
+{
+ if( ( val & ~0xFF ) == 0 ) return val;
+ return ( ( ~val ) >> 31 ) & 0xFF;
+}
+
+template<class T>
+static etcpak_force_inline T sq( T val )
+{
+ return val * val;
+}
+
+static etcpak_force_inline int mul8bit( int a, int b )
+{
+ int t = a*b + 128;
+ return ( t + ( t >> 8 ) ) >> 8;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessCommon.hpp b/thirdparty/etcpak/ProcessCommon.hpp
new file mode 100644
index 0000000000..657d68888f
--- /dev/null
+++ b/thirdparty/etcpak/ProcessCommon.hpp
@@ -0,0 +1,50 @@
+#ifndef __PROCESSCOMMON_HPP__
+#define __PROCESSCOMMON_HPP__
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+template<class T>
+static size_t GetLeastError( const T* err, size_t num )
+{
+ size_t idx = 0;
+ for( size_t i=1; i<num; i++ )
+ {
+ if( err[i] < err[idx] )
+ {
+ idx = i;
+ }
+ }
+ return idx;
+}
+
+static uint64_t FixByteOrder( uint64_t d )
+{
+ return ( ( d & 0x00000000FFFFFFFF ) ) |
+ ( ( d & 0xFF00000000000000 ) >> 24 ) |
+ ( ( d & 0x000000FF00000000 ) << 24 ) |
+ ( ( d & 0x00FF000000000000 ) >> 8 ) |
+ ( ( d & 0x0000FF0000000000 ) << 8 );
+}
+
+template<class T, class S>
+static uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id )
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return d;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessDxtc.cpp b/thirdparty/etcpak/ProcessDxtc.cpp
new file mode 100644
index 0000000000..508d55fd75
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.cpp
@@ -0,0 +1,956 @@
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "ProcessDxtc.hpp"
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#if defined __AVX__ && !defined __SSE4_1__
+# define __SSE4_1__
+#endif
+
+#if defined __SSE4_1__ || defined __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# ifndef _mm256_cvtsi256_si32
+# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )
+# endif
+# endif
+#endif
+
+
+static etcpak_force_inline uint16_t to565( uint8_t r, uint8_t g, uint8_t b )
+{
+ return ( ( r & 0xF8 ) << 8 ) | ( ( g & 0xFC ) << 3 ) | ( b >> 3 );
+}
+
+static etcpak_force_inline uint16_t to565( uint32_t c )
+{
+ return
+ ( ( c & 0xF80000 ) >> 19 ) |
+ ( ( c & 0x00FC00 ) >> 5 ) |
+ ( ( c & 0x0000F8 ) << 8 );
+}
+
+static const uint8_t DxtcIndexTable[256] = {
+ 85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80,
+ 117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112,
+ 101, 103, 102, 100, 109, 111, 110, 108, 105, 107, 106, 104, 97, 99, 98, 96,
+ 69, 71, 70, 68, 77, 79, 78, 76, 73, 75, 74, 72, 65, 67, 66, 64,
+ 213, 215, 214, 212, 221, 223, 222, 220, 217, 219, 218, 216, 209, 211, 210, 208,
+ 245, 247, 246, 244, 253, 255, 254, 252, 249, 251, 250, 248, 241, 243, 242, 240,
+ 229, 231, 230, 228, 237, 239, 238, 236, 233, 235, 234, 232, 225, 227, 226, 224,
+ 197, 199, 198, 196, 205, 207, 206, 204, 201, 203, 202, 200, 193, 195, 194, 192,
+ 149, 151, 150, 148, 157, 159, 158, 156, 153, 155, 154, 152, 145, 147, 146, 144,
+ 181, 183, 182, 180, 189, 191, 190, 188, 185, 187, 186, 184, 177, 179, 178, 176,
+ 165, 167, 166, 164, 173, 175, 174, 172, 169, 171, 170, 168, 161, 163, 162, 160,
+ 133, 135, 134, 132, 141, 143, 142, 140, 137, 139, 138, 136, 129, 131, 130, 128,
+ 21, 23, 22, 20, 29, 31, 30, 28, 25, 27, 26, 24, 17, 19, 18, 16,
+ 53, 55, 54, 52, 61, 63, 62, 60, 57, 59, 58, 56, 49, 51, 50, 48,
+ 37, 39, 38, 36, 45, 47, 46, 44, 41, 43, 42, 40, 33, 35, 34, 32,
+ 5, 7, 6, 4, 13, 15, 14, 12, 9, 11, 10, 8, 1, 3, 2, 0
+};
+
+static const uint8_t AlphaIndexTable_SSE[64] = {
+ 9, 15, 14, 13, 12, 11, 10, 8, 57, 63, 62, 61, 60, 59, 58, 56,
+ 49, 55, 54, 53, 52, 51, 50, 48, 41, 47, 46, 45, 44, 43, 42, 40,
+ 33, 39, 38, 37, 36, 35, 34, 32, 25, 31, 30, 29, 28, 27, 26, 24,
+ 17, 23, 22, 21, 20, 19, 18, 16, 1, 7, 6, 5, 4, 3, 2, 0,
+};
+
+static const uint16_t DivTable[255*3+1] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xcccc, 0xaaaa, 0x9249, 0x8000, 0x71c7, 0x6666, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000,
+ 0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000,
+ 0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555,
+ 0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000,
+ 0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc,
+ 0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa,
+ 0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924,
+ 0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800,
+ 0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c,
+ 0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666,
+ 0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1,
+ 0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555,
+ 0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec,
+ 0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492,
+ 0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444,
+ 0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400,
+ 0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3,
+ 0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e,
+ 0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e,
+ 0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333,
+ 0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c,
+ 0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8,
+ 0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8,
+ 0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa,
+ 0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f,
+ 0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276,
+ 0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e,
+ 0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249,
+ 0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234,
+ 0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222,
+ 0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210,
+ 0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200,
+ 0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0,
+ 0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1,
+ 0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4,
+ 0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7,
+ 0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba,
+ 0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af,
+ 0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4,
+ 0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199,
+ 0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f,
+ 0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186,
+ 0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d,
+ 0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174,
+ 0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c,
+ 0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164,
+ 0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,
+ 0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156
+};
+static const uint16_t DivTableNEON[255*3+1] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000,
+ 0x0f83, 0x0f0f, 0x0ea0, 0x0e38, 0x0dd6, 0x0d79, 0x0d20, 0x0ccc, 0x0c7c, 0x0c30, 0x0be8, 0x0ba2, 0x0b60, 0x0b21, 0x0ae4, 0x0aaa,
+ 0x0a72, 0x0a3d, 0x0a0a, 0x09d8, 0x09a9, 0x097b, 0x094f, 0x0924, 0x08fb, 0x08d3, 0x08ad, 0x0888, 0x0864, 0x0842, 0x0820, 0x0800,
+ 0x07e0, 0x07c1, 0x07a4, 0x0787, 0x076b, 0x0750, 0x0736, 0x071c, 0x0703, 0x06eb, 0x06d3, 0x06bc, 0x06a6, 0x0690, 0x067b, 0x0666,
+ 0x0652, 0x063e, 0x062b, 0x0618, 0x0606, 0x05f4, 0x05e2, 0x05d1, 0x05c0, 0x05b0, 0x05a0, 0x0590, 0x0581, 0x0572, 0x0563, 0x0555,
+ 0x0547, 0x0539, 0x052b, 0x051e, 0x0511, 0x0505, 0x04f8, 0x04ec, 0x04e0, 0x04d4, 0x04c8, 0x04bd, 0x04b2, 0x04a7, 0x049c, 0x0492,
+ 0x0487, 0x047d, 0x0473, 0x0469, 0x0460, 0x0456, 0x044d, 0x0444, 0x043b, 0x0432, 0x0429, 0x0421, 0x0418, 0x0410, 0x0408, 0x0400,
+ 0x03f8, 0x03f0, 0x03e8, 0x03e0, 0x03d9, 0x03d2, 0x03ca, 0x03c3, 0x03bc, 0x03b5, 0x03ae, 0x03a8, 0x03a1, 0x039b, 0x0394, 0x038e,
+ 0x0387, 0x0381, 0x037b, 0x0375, 0x036f, 0x0369, 0x0364, 0x035e, 0x0358, 0x0353, 0x034d, 0x0348, 0x0342, 0x033d, 0x0338, 0x0333,
+ 0x032e, 0x0329, 0x0324, 0x031f, 0x031a, 0x0315, 0x0310, 0x030c, 0x0307, 0x0303, 0x02fe, 0x02fa, 0x02f5, 0x02f1, 0x02ec, 0x02e8,
+ 0x02e4, 0x02e0, 0x02dc, 0x02d8, 0x02d4, 0x02d0, 0x02cc, 0x02c8, 0x02c4, 0x02c0, 0x02bc, 0x02b9, 0x02b5, 0x02b1, 0x02ae, 0x02aa,
+ 0x02a7, 0x02a3, 0x02a0, 0x029c, 0x0299, 0x0295, 0x0292, 0x028f, 0x028c, 0x0288, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276,
+ 0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0264, 0x0261, 0x025e, 0x025c, 0x0259, 0x0256, 0x0253, 0x0251, 0x024e, 0x024b, 0x0249,
+ 0x0246, 0x0243, 0x0241, 0x023e, 0x023c, 0x0239, 0x0237, 0x0234, 0x0232, 0x0230, 0x022d, 0x022b, 0x0229, 0x0226, 0x0224, 0x0222,
+ 0x021f, 0x021d, 0x021b, 0x0219, 0x0216, 0x0214, 0x0212, 0x0210, 0x020e, 0x020c, 0x020a, 0x0208, 0x0206, 0x0204, 0x0202, 0x0200,
+ 0x01fe, 0x01fc, 0x01fa, 0x01f8, 0x01f6, 0x01f4, 0x01f2, 0x01f0, 0x01ee, 0x01ec, 0x01ea, 0x01e9, 0x01e7, 0x01e5, 0x01e3, 0x01e1,
+ 0x01e0, 0x01de, 0x01dc, 0x01da, 0x01d9, 0x01d7, 0x01d5, 0x01d4, 0x01d2, 0x01d0, 0x01cf, 0x01cd, 0x01cb, 0x01ca, 0x01c8, 0x01c7,
+ 0x01c5, 0x01c3, 0x01c2, 0x01c0, 0x01bf, 0x01bd, 0x01bc, 0x01ba, 0x01b9, 0x01b7, 0x01b6, 0x01b4, 0x01b3, 0x01b2, 0x01b0, 0x01af,
+ 0x01ad, 0x01ac, 0x01aa, 0x01a9, 0x01a8, 0x01a6, 0x01a5, 0x01a4, 0x01a2, 0x01a1, 0x01a0, 0x019e, 0x019d, 0x019c, 0x019a, 0x0199,
+ 0x0198, 0x0197, 0x0195, 0x0194, 0x0193, 0x0192, 0x0190, 0x018f, 0x018e, 0x018d, 0x018b, 0x018a, 0x0189, 0x0188, 0x0187, 0x0186,
+ 0x0184, 0x0183, 0x0182, 0x0181, 0x0180, 0x017f, 0x017e, 0x017d, 0x017b, 0x017a, 0x0179, 0x0178, 0x0177, 0x0176, 0x0175, 0x0174,
+ 0x0173, 0x0172, 0x0171, 0x0170, 0x016f, 0x016e, 0x016d, 0x016c, 0x016b, 0x016a, 0x0169, 0x0168, 0x0167, 0x0166, 0x0165, 0x0164,
+ 0x0163, 0x0162, 0x0161, 0x0160, 0x015f, 0x015e, 0x015d, 0x015c, 0x015b, 0x015a, 0x0159, 0x0158, 0x0158, 0x0157, 0x0156, 0x0155,
+ 0x0154, 0x0153, 0x0152, 0x0151, 0x0150, 0x0150, 0x014f, 0x014e, 0x014d, 0x014c, 0x014b, 0x014a, 0x014a, 0x0149, 0x0148, 0x0147,
+ 0x0146, 0x0146, 0x0145, 0x0144, 0x0143, 0x0142, 0x0142, 0x0141, 0x0140, 0x013f, 0x013e, 0x013e, 0x013d, 0x013c, 0x013b, 0x013b,
+ 0x013a, 0x0139, 0x0138, 0x0138, 0x0137, 0x0136, 0x0135, 0x0135, 0x0134, 0x0133, 0x0132, 0x0132, 0x0131, 0x0130, 0x0130, 0x012f,
+ 0x012e, 0x012e, 0x012d, 0x012c, 0x012b, 0x012b, 0x012a, 0x0129, 0x0129, 0x0128, 0x0127, 0x0127, 0x0126, 0x0125, 0x0125, 0x0124,
+ 0x0123, 0x0123, 0x0122, 0x0121, 0x0121, 0x0120, 0x0120, 0x011f, 0x011e, 0x011e, 0x011d, 0x011c, 0x011c, 0x011b, 0x011b, 0x011a,
+ 0x0119, 0x0119, 0x0118, 0x0118, 0x0117, 0x0116, 0x0116, 0x0115, 0x0115, 0x0114, 0x0113, 0x0113, 0x0112, 0x0112, 0x0111, 0x0111,
+ 0x0110, 0x010f, 0x010f, 0x010e, 0x010e, 0x010d, 0x010d, 0x010c, 0x010c, 0x010b, 0x010a, 0x010a, 0x0109, 0x0109, 0x0108, 0x0108,
+ 0x0107, 0x0107, 0x0106, 0x0106, 0x0105, 0x0105, 0x0104, 0x0104, 0x0103, 0x0103, 0x0102, 0x0102, 0x0101, 0x0101, 0x0100, 0x0100,
+ 0x00ff, 0x00ff, 0x00fe, 0x00fe, 0x00fd, 0x00fd, 0x00fc, 0x00fc, 0x00fb, 0x00fb, 0x00fa, 0x00fa, 0x00f9, 0x00f9, 0x00f8, 0x00f8,
+ 0x00f7, 0x00f7, 0x00f6, 0x00f6, 0x00f5, 0x00f5, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f3, 0x00f2, 0x00f2, 0x00f1, 0x00f1, 0x00f0,
+ 0x00f0, 0x00f0, 0x00ef, 0x00ef, 0x00ee, 0x00ee, 0x00ed, 0x00ed, 0x00ed, 0x00ec, 0x00ec, 0x00eb, 0x00eb, 0x00ea, 0x00ea, 0x00ea,
+ 0x00e9, 0x00e9, 0x00e8, 0x00e8, 0x00e7, 0x00e7, 0x00e7, 0x00e6, 0x00e6, 0x00e5, 0x00e5, 0x00e5, 0x00e4, 0x00e4, 0x00e3, 0x00e3,
+ 0x00e3, 0x00e2, 0x00e2, 0x00e1, 0x00e1, 0x00e1, 0x00e0, 0x00e0, 0x00e0, 0x00df, 0x00df, 0x00de, 0x00de, 0x00de, 0x00dd, 0x00dd,
+ 0x00dd, 0x00dc, 0x00dc, 0x00db, 0x00db, 0x00db, 0x00da, 0x00da, 0x00da, 0x00d9, 0x00d9, 0x00d9, 0x00d8, 0x00d8, 0x00d7, 0x00d7,
+ 0x00d7, 0x00d6, 0x00d6, 0x00d6, 0x00d5, 0x00d5, 0x00d5, 0x00d4, 0x00d4, 0x00d4, 0x00d3, 0x00d3, 0x00d3, 0x00d2, 0x00d2, 0x00d2,
+ 0x00d1, 0x00d1, 0x00d1, 0x00d0, 0x00d0, 0x00d0, 0x00cf, 0x00cf, 0x00cf, 0x00ce, 0x00ce, 0x00ce, 0x00cd, 0x00cd, 0x00cd, 0x00cc,
+ 0x00cc, 0x00cc, 0x00cb, 0x00cb, 0x00cb, 0x00ca, 0x00ca, 0x00ca, 0x00c9, 0x00c9, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c8, 0x00c7,
+ 0x00c7, 0x00c7, 0x00c6, 0x00c6, 0x00c6, 0x00c5, 0x00c5, 0x00c5, 0x00c5, 0x00c4, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c3, 0x00c3,
+ 0x00c2, 0x00c2, 0x00c2, 0x00c1, 0x00c1, 0x00c1, 0x00c1, 0x00c0, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00bf, 0x00bf, 0x00be, 0x00be,
+ 0x00be, 0x00bd, 0x00bd, 0x00bd, 0x00bd, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00ba, 0x00ba,
+ 0x00b9, 0x00b9, 0x00b9, 0x00b9, 0x00b8, 0x00b8, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b6, 0x00b6,
+ 0x00b5, 0x00b5, 0x00b5, 0x00b5, 0x00b4, 0x00b4, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b2, 0x00b2,
+ 0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae,
+ 0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab,
+};
+
+static const uint16_t DivTableAlpha[256] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xe38e, 0xcccc, 0xba2e, 0xaaaa, 0x9d89, 0x9249, 0x8888, 0x8000,
+ 0x7878, 0x71c7, 0x6bca, 0x6666, 0x6186, 0x5d17, 0x590b, 0x5555, 0x51eb, 0x4ec4, 0x4bda, 0x4924, 0x469e, 0x4444, 0x4210, 0x4000,
+ 0x3e0f, 0x3c3c, 0x3a83, 0x38e3, 0x3759, 0x35e5, 0x3483, 0x3333, 0x31f3, 0x30c3, 0x2fa0, 0x2e8b, 0x2d82, 0x2c85, 0x2b93, 0x2aaa,
+ 0x29cb, 0x28f5, 0x2828, 0x2762, 0x26a4, 0x25ed, 0x253c, 0x2492, 0x23ee, 0x234f, 0x22b6, 0x2222, 0x2192, 0x2108, 0x2082, 0x2000,
+ 0x1f81, 0x1f07, 0x1e91, 0x1e1e, 0x1dae, 0x1d41, 0x1cd8, 0x1c71, 0x1c0e, 0x1bac, 0x1b4e, 0x1af2, 0x1a98, 0x1a41, 0x19ec, 0x1999,
+ 0x1948, 0x18f9, 0x18ac, 0x1861, 0x1818, 0x17d0, 0x178a, 0x1745, 0x1702, 0x16c1, 0x1681, 0x1642, 0x1605, 0x15c9, 0x158e, 0x1555,
+ 0x151d, 0x14e5, 0x14af, 0x147a, 0x1446, 0x1414, 0x13e2, 0x13b1, 0x1381, 0x1352, 0x1323, 0x12f6, 0x12c9, 0x129e, 0x1273, 0x1249,
+ 0x121f, 0x11f7, 0x11cf, 0x11a7, 0x1181, 0x115b, 0x1135, 0x1111, 0x10ec, 0x10c9, 0x10a6, 0x1084, 0x1062, 0x1041, 0x1020, 0x1000,
+ 0x0fe0, 0x0fc0, 0x0fa2, 0x0f83, 0x0f66, 0x0f48, 0x0f2b, 0x0f0f, 0x0ef2, 0x0ed7, 0x0ebb, 0x0ea0, 0x0e86, 0x0e6c, 0x0e52, 0x0e38,
+ 0x0e1f, 0x0e07, 0x0dee, 0x0dd6, 0x0dbe, 0x0da7, 0x0d90, 0x0d79, 0x0d62, 0x0d4c, 0x0d36, 0x0d20, 0x0d0b, 0x0cf6, 0x0ce1, 0x0ccc,
+ 0x0cb8, 0x0ca4, 0x0c90, 0x0c7c, 0x0c69, 0x0c56, 0x0c43, 0x0c30, 0x0c1e, 0x0c0c, 0x0bfa, 0x0be8, 0x0bd6, 0x0bc5, 0x0bb3, 0x0ba2,
+ 0x0b92, 0x0b81, 0x0b70, 0x0b60, 0x0b50, 0x0b40, 0x0b30, 0x0b21, 0x0b11, 0x0b02, 0x0af3, 0x0ae4, 0x0ad6, 0x0ac7, 0x0ab8, 0x0aaa,
+ 0x0a9c, 0x0a8e, 0x0a80, 0x0a72, 0x0a65, 0x0a57, 0x0a4a, 0x0a3d, 0x0a30, 0x0a23, 0x0a16, 0x0a0a, 0x09fd, 0x09f1, 0x09e4, 0x09d8,
+ 0x09cc, 0x09c0, 0x09b4, 0x09a9, 0x099d, 0x0991, 0x0986, 0x097b, 0x0970, 0x0964, 0x095a, 0x094f, 0x0944, 0x0939, 0x092f, 0x0924,
+ 0x091a, 0x090f, 0x0905, 0x08fb, 0x08f1, 0x08e7, 0x08dd, 0x08d3, 0x08ca, 0x08c0, 0x08b7, 0x08ad, 0x08a4, 0x089a, 0x0891, 0x0888,
+ 0x087f, 0x0876, 0x086d, 0x0864, 0x085b, 0x0853, 0x084a, 0x0842, 0x0839, 0x0831, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800,
+};
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i px1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i px2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i px3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ uint32_t c;
+ memcpy( &c, src, 4 );
+ return uint64_t( to565( c ) ) << 16;
+ }
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+#elif defined __ARM_NEON
+# ifdef __aarch64__
+ uint8x16x4_t px = vld4q_u8( src );
+
+ uint8x16_t lr = px.val[0];
+ uint8x16_t lg = px.val[1];
+ uint8x16_t lb = px.val[2];
+
+ uint8_t rmaxr = vmaxvq_u8( lr );
+ uint8_t rmaxg = vmaxvq_u8( lg );
+ uint8_t rmaxb = vmaxvq_u8( lb );
+
+ uint8_t rminr = vminvq_u8( lr );
+ uint8_t rming = vminvq_u8( lg );
+ uint8_t rminb = vminvq_u8( lb );
+
+ int rr = rmaxr - rminr;
+ int rg = rmaxg - rming;
+ int rb = rmaxb - rminb;
+
+ int vrange1 = rr + rg + rb;
+ uint16_t vrange2 = DivTableNEON[vrange1];
+
+ uint8_t insetr = rr >> 4;
+ uint8_t insetg = rg >> 4;
+ uint8_t insetb = rb >> 4;
+
+ uint8_t minr = rminr + insetr;
+ uint8_t ming = rming + insetg;
+ uint8_t minb = rminb + insetb;
+
+ uint8_t maxr = rmaxr - insetr;
+ uint8_t maxg = rmaxg - insetg;
+ uint8_t maxb = rmaxb - insetb;
+
+ uint8x16_t cr = vsubq_u8( lr, vdupq_n_u8( rminr ) );
+ uint8x16_t cg = vsubq_u8( lg, vdupq_n_u8( rming ) );
+ uint8x16_t cb = vsubq_u8( lb, vdupq_n_u8( rminb ) );
+
+ uint16x8_t is0l = vaddl_u8( vget_low_u8( cr ), vget_low_u8( cg ) );
+ uint16x8_t is0h = vaddl_u8( vget_high_u8( cr ), vget_high_u8( cg ) );
+ uint16x8_t is1l = vaddw_u8( is0l, vget_low_u8( cb ) );
+ uint16x8_t is1h = vaddw_u8( is0h, vget_high_u8( cb ) );
+
+ int16x8_t range = vdupq_n_s16( vrange2 );
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1l ), range ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1h ), range ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vp;
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( minr, ming, minb ) ) << 16 ) | to565( maxr, maxg, maxb ) | ( uint64_t( vp ) << 32 ) );
+# else
+ uint32x4_t px0 = vld1q_u32( (uint32_t*)src );
+ uint32x4_t px1 = vld1q_u32( (uint32_t*)src + 4 );
+ uint32x4_t px2 = vld1q_u32( (uint32_t*)src + 8 );
+ uint32x4_t px3 = vld1q_u32( (uint32_t*)src + 12 );
+
+ uint32x4_t smask = vdupq_n_u32( 0xF8FCF8 );
+ uint32x4_t sd0 = vandq_u32( smask, px0 );
+ uint32x4_t sd1 = vandq_u32( smask, px1 );
+ uint32x4_t sd2 = vandq_u32( smask, px2 );
+ uint32x4_t sd3 = vandq_u32( smask, px3 );
+
+ uint32x4_t sc = vdupq_n_u32( sd0[0] );
+
+ uint32x4_t sc0 = vceqq_u32( sd0, sc );
+ uint32x4_t sc1 = vceqq_u32( sd1, sc );
+ uint32x4_t sc2 = vceqq_u32( sd2, sc );
+ uint32x4_t sc3 = vceqq_u32( sd3, sc );
+
+ uint32x4_t sm0 = vandq_u32( sc0, sc1 );
+ uint32x4_t sm1 = vandq_u32( sc2, sc3 );
+ int64x2_t sm = vreinterpretq_s64_u32( vandq_u32( sm0, sm1 ) );
+
+ if( sm[0] == -1 && sm[1] == -1 )
+ {
+ return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
+ }
+
+ uint32x4_t mask = vdupq_n_u32( 0xFFFFFF );
+ uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) );
+ uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) );
+ uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) );
+ uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) );
+
+ uint8x16_t min0 = vminq_u8( l0, l1 );
+ uint8x16_t min1 = vminq_u8( l2, l3 );
+ uint8x16_t min2 = vminq_u8( min0, min1 );
+
+ uint8x16_t max0 = vmaxq_u8( l0, l1 );
+ uint8x16_t max1 = vmaxq_u8( l2, l3 );
+ uint8x16_t max2 = vmaxq_u8( max0, max1 );
+
+ uint8x16_t min3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( min2 ) ) );
+ uint8x16_t max3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( max2 ) ) );
+
+ uint8x16_t min4 = vminq_u8( min2, min3 );
+ uint8x16_t max4 = vmaxq_u8( max2, max3 );
+
+ uint8x16_t min5 = vcombine_u8( vget_high_u8( min4 ), vget_low_u8( min4 ) );
+ uint8x16_t max5 = vcombine_u8( vget_high_u8( max4 ), vget_low_u8( max4 ) );
+
+ uint8x16_t rmin = vminq_u8( min4, min5 );
+ uint8x16_t rmax = vmaxq_u8( max4, max5 );
+
+ uint8x16_t range1 = vsubq_u8( rmax, rmin );
+ uint8x8_t range2 = vget_low_u8( range1 );
+ uint8x8x2_t range3 = vzip_u8( range2, vdup_n_u8( 0 ) );
+ uint16x4_t range4 = vreinterpret_u16_u8( range3.val[0] );
+
+ uint16_t vrange1;
+ uint16x4_t range5 = vpadd_u16( range4, range4 );
+ uint16x4_t range6 = vpadd_u16( range5, range5 );
+ vst1_lane_u16( &vrange1, range6, 0 );
+
+ uint32_t vrange2 = ( 2 << 16 ) / uint32_t( vrange1 + 1 );
+ uint16x8_t range = vdupq_n_u16( vrange2 );
+
+ uint8x16_t inset = vshrq_n_u8( range1, 4 );
+ uint8x16_t min = vaddq_u8( rmin, inset );
+ uint8x16_t max = vsubq_u8( rmax, inset );
+
+ uint8x16_t c0 = vsubq_u8( l0, rmin );
+ uint8x16_t c1 = vsubq_u8( l1, rmin );
+ uint8x16_t c2 = vsubq_u8( l2, rmin );
+ uint8x16_t c3 = vsubq_u8( l3, rmin );
+
+ uint16x8_t is0 = vpaddlq_u8( c0 );
+ uint16x8_t is1 = vpaddlq_u8( c1 );
+ uint16x8_t is2 = vpaddlq_u8( c2 );
+ uint16x8_t is3 = vpaddlq_u8( c3 );
+
+ uint16x4_t is4 = vpadd_u16( vget_low_u16( is0 ), vget_high_u16( is0 ) );
+ uint16x4_t is5 = vpadd_u16( vget_low_u16( is1 ), vget_high_u16( is1 ) );
+ uint16x4_t is6 = vpadd_u16( vget_low_u16( is2 ), vget_high_u16( is2 ) );
+ uint16x4_t is7 = vpadd_u16( vget_low_u16( is3 ), vget_high_u16( is3 ) );
+
+ uint16x8_t s0 = vcombine_u16( is4, is5 );
+ uint16x8_t s1 = vcombine_u16( is6, is7 );
+
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s0 ), vreinterpretq_s16_u16( range ) ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s1 ), vreinterpretq_s16_u16( range ) ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vmin, vmax, vp;
+ vst1q_lane_u32( &vmin, vreinterpretq_u32_u8( min ), 0 );
+ vst1q_lane_u32( &vmax, vreinterpretq_u32_u8( max ), 0 );
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+# endif
+#else
+ uint32_t ref;
+ memcpy( &ref, src, 4 );
+ uint32_t refMask = ref & 0xF8FCF8;
+ auto stmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ uint32_t px;
+ memcpy( &px, stmp, 4 );
+ if( ( px & 0xF8FCF8 ) != refMask ) break;
+ stmp += 4;
+ }
+ if( stmp == src + 64 )
+ {
+ return uint64_t( to565( ref ) ) << 16;
+ }
+
+ uint8_t min[3] = { src[0], src[1], src[2] };
+ uint8_t max[3] = { src[0], src[1], src[2] };
+ auto tmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ if( tmp[j] < min[j] ) min[j] = tmp[j];
+ else if( tmp[j] > max[j] ) max[j] = tmp[j];
+ }
+ tmp += 4;
+ }
+
+ const uint32_t range = DivTable[max[0] - min[0] + max[1] - min[1] + max[2] - min[2]];
+ const uint32_t rmin = min[0] + min[1] + min[2];
+ for( int i=0; i<3; i++ )
+ {
+ const uint8_t inset = ( max[i] - min[i] ) >> 4;
+ min[i] += inset;
+ max[i] -= inset;
+ }
+
+ uint32_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const uint32_t c = src[0] + src[1] + src[2] - rmin;
+ const uint8_t idx = ( c * range ) >> 16;
+ data |= idx << (i*2);
+ src += 4;
+ }
+
+ return uint64_t( ( uint64_t( to565( min[0], min[1], min[2] ) ) << 16 ) | to565( max[0], max[1], max[2] ) | ( uint64_t( data ) << 32 ) );
+#endif
+}
+
+#ifdef __AVX2__
+static etcpak_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
+{
+ __m256i px0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i px1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+ __m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2);
+ __m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3);
+
+ __m256i smask = _mm256_set1_epi32( 0xF8FCF8 );
+ __m256i sd0 = _mm256_and_si256( px0, smask );
+ __m256i sd1 = _mm256_and_si256( px1, smask );
+ __m256i sd2 = _mm256_and_si256( px2, smask );
+ __m256i sd3 = _mm256_and_si256( px3, smask );
+
+ __m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m256i sc0 = _mm256_cmpeq_epi8(sd0, sc);
+ __m256i sc1 = _mm256_cmpeq_epi8(sd1, sc);
+ __m256i sc2 = _mm256_cmpeq_epi8(sd2, sc);
+ __m256i sc3 = _mm256_cmpeq_epi8(sd3, sc);
+
+ __m256i sm0 = _mm256_and_si256(sc0, sc1);
+ __m256i sm1 = _mm256_and_si256(sc2, sc3);
+ __m256i sm = _mm256_and_si256(sm0, sm1);
+
+ const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) );
+ const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) );
+
+ if( solid0 + solid1 == 0 )
+ {
+ const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) );
+ const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) );
+ memcpy( dst, &c0, 8 );
+ memcpy( dst+8, &c1, 8 );
+ dst += 16;
+ return;
+ }
+
+ __m256i min0 = _mm256_min_epu8( px0, px1 );
+ __m256i min1 = _mm256_min_epu8( px2, px3 );
+ __m256i min2 = _mm256_min_epu8( min0, min1 );
+
+ __m256i max0 = _mm256_max_epu8( px0, px1 );
+ __m256i max1 = _mm256_max_epu8( px2, px3 );
+ __m256i max2 = _mm256_max_epu8( max0, max1 );
+
+ __m256i min3 = _mm256_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i max3 = _mm256_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i min4 = _mm256_min_epu8( min2, min3 );
+ __m256i max4 = _mm256_max_epu8( max2, max3 );
+
+ __m256i min5 = _mm256_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i max5 = _mm256_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i rmin = _mm256_min_epu8( min4, min5 );
+ __m256i rmax = _mm256_max_epu8( max4, max5 );
+
+ __m256i range1 = _mm256_subs_epu8( rmax, rmin );
+ __m256i range2 = _mm256_sad_epu8( rmax, rmin );
+
+ uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1];
+ uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1];
+ __m256i range00 = _mm256_set1_epi16( vrange0 );
+ __m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 );
+
+ __m256i inset1 = _mm256_srli_epi16( range1, 4 );
+ __m256i inset = _mm256_and_si256( inset1, _mm256_set1_epi8( 0xF ) );
+ __m256i min = _mm256_adds_epu8( rmin, inset );
+ __m256i max = _mm256_subs_epu8( rmax, inset );
+
+ __m256i c0 = _mm256_subs_epu8( px0, rmin );
+ __m256i c1 = _mm256_subs_epu8( px1, rmin );
+ __m256i c2 = _mm256_subs_epu8( px2, rmin );
+ __m256i c3 = _mm256_subs_epu8( px3, rmin );
+
+ __m256i is0 = _mm256_maddubs_epi16( c0, _mm256_set1_epi8( 1 ) );
+ __m256i is1 = _mm256_maddubs_epi16( c1, _mm256_set1_epi8( 1 ) );
+ __m256i is2 = _mm256_maddubs_epi16( c2, _mm256_set1_epi8( 1 ) );
+ __m256i is3 = _mm256_maddubs_epi16( c3, _mm256_set1_epi8( 1 ) );
+
+ __m256i s0 = _mm256_hadd_epi16( is0, is1 );
+ __m256i s1 = _mm256_hadd_epi16( is2, is3 );
+
+ __m256i m0 = _mm256_mulhi_epu16( s0, range );
+ __m256i m1 = _mm256_mulhi_epu16( s1, range );
+
+ __m256i p0 = _mm256_packus_epi16( m0, m1 );
+
+ __m256i p1 = _mm256_or_si256( _mm256_srai_epi32( p0, 6 ), _mm256_srai_epi32( p0, 12 ) );
+ __m256i p2 = _mm256_or_si256( _mm256_srai_epi32( p0, 18 ), p0 );
+ __m256i p3 = _mm256_or_si256( p1, p2 );
+ __m256i p =_mm256_shuffle_epi8( p3, _mm256_set1_epi32( 0x0C080400 ) );
+
+ __m256i mm0 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), min );
+ __m256i mm1 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), max );
+ __m256i mm2 = _mm256_unpacklo_epi64( mm1, mm0 );
+ __m256i mmr = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 11 ), 11 );
+ __m256i mmg = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 26 ), 5 );
+ __m256i mmb = _mm256_srli_epi64( _mm256_slli_epi64( mm2, 16 ), 59 );
+ __m256i mm3 = _mm256_or_si256( mmr, mmg );
+ __m256i mm4 = _mm256_or_si256( mm3, mmb );
+ __m256i mm5 = _mm256_shuffle_epi8( mm4, _mm256_set1_epi32( 0x09080100 ) );
+
+ __m256i d0 = _mm256_unpacklo_epi32( mm5, p );
+ __m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) );
+ __m128i d2 = _mm256_castsi256_si128( d1 );
+
+ __m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 );
+ __m128i d3 = _mm_and_si128( d2, mask );
+ _mm_storeu_si128( (__m128i*)dst, d3 );
+
+ for( int j=4; j<8; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+ for( int j=12; j<16; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+
+ dst += 16;
+}
+#endif
+
+static const uint8_t AlphaIndexTable[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+
+static etcpak_force_inline uint64_t ProcessAlpha( const uint8_t* src )
+{
+ uint8_t solid8 = *src;
+ uint16_t solid16 = uint16_t( solid8 ) | ( uint16_t( solid8 ) << 8 );
+ uint32_t solid32 = uint32_t( solid16 ) | ( uint32_t( solid16 ) << 16 );
+ uint64_t solid64 = uint64_t( solid32 ) | ( uint64_t( solid32 ) << 32 );
+ if( memcmp( src, &solid64, 8 ) == 0 && memcmp( src+8, &solid64, 8 ) == 0 )
+ {
+ return solid8;
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = min;
+ for( int i=1; i<16; i++ )
+ {
+ const auto v = src[i];
+ if( v > max ) max = v;
+ else if( v < min ) min = v;
+ }
+
+ uint32_t range = ( 8 << 13 ) / ( 1 + max - min );
+ uint64_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ uint8_t a = src[i] - min;
+ uint64_t idx = AlphaIndexTable[( a * range ) >> 13];
+ data |= idx << (i*3);
+ }
+
+ return max | ( min << 8 ) | ( data << 16 );
+}
+
+#ifdef __SSE4_1__
+static etcpak_force_inline uint64_t ProcessRGB_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ return uint64_t( to565( _mm_cvtsi128_si32( px0 ) ) ) << 16;
+ }
+
+ px0 = _mm_and_si128( px0, _mm_set1_epi32( 0xFFFFFF ) );
+ px1 = _mm_and_si128( px1, _mm_set1_epi32( 0xFFFFFF ) );
+ px2 = _mm_and_si128( px2, _mm_set1_epi32( 0xFFFFFF ) );
+ px3 = _mm_and_si128( px3, _mm_set1_epi32( 0xFFFFFF ) );
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+}
+
+static etcpak_force_inline uint64_t ProcessAlpha_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i m0 = _mm_shuffle_epi8( px0, mask );
+ __m128i m1 = _mm_shuffle_epi8( px1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i m2 = _mm_shuffle_epi8( px2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i m3 = _mm_shuffle_epi8( px3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+ __m128i m4 = _mm_or_si128( m0, m1 );
+ __m128i m5 = _mm_or_si128( m2, m3 );
+ __m128i a = _mm_or_si128( m4, m5 );
+
+ __m128i solidCmp = _mm_shuffle_epi8( a, _mm_setzero_si128() );
+ __m128i cmpRes = _mm_cmpeq_epi8( a, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return _mm_cvtsi128_si32( a ) & 0xFF;
+ }
+
+ __m128i a1 = _mm_shuffle_epi32( a, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( a, a1 );
+ __m128i min1 = _mm_min_epu8( a, a1 );
+ __m128i amax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i amin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, amax2 );
+ __m128i min2 = _mm_min_epu8( min1, amin2 );
+ __m128i amax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i amin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, amax3 );
+ __m128i min3 = _mm_min_epu8( min2, amin3 );
+ __m128i amax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i amin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, amax4 );
+ __m128i min = _mm_min_epu8( min3, amin4 );
+ __m128i minmax = _mm_unpacklo_epi8( max, min );
+
+ __m128i r = _mm_sub_epi8( max, min );
+ int range = _mm_cvtsi128_si32( r ) & 0xFF;
+ __m128i rv = _mm_set1_epi16( DivTableAlpha[range] );
+
+ __m128i v = _mm_sub_epi8( a, min );
+
+ __m128i lo16 = _mm_unpacklo_epi8( v, _mm_setzero_si128() );
+ __m128i hi16 = _mm_unpackhi_epi8( v, _mm_setzero_si128() );
+
+ __m128i lomul = _mm_mulhi_epu16( lo16, rv );
+ __m128i himul = _mm_mulhi_epu16( hi16, rv );
+
+ __m128i p0 = _mm_packus_epi16( lomul, himul );
+ __m128i p1 = _mm_or_si128( _mm_and_si128( p0, _mm_set1_epi16( 0x3F ) ), _mm_srai_epi16( _mm_and_si128( p0, _mm_set1_epi16( 0x3F00 ) ), 5 ) );
+ __m128i p2 = _mm_packus_epi16( p1, p1 );
+
+ uint64_t pi = _mm_cvtsi128_si64( p2 );
+ uint64_t data = 0;
+ for( int i=0; i<8; i++ )
+ {
+ uint64_t idx = AlphaIndexTable_SSE[(pi>>(i*8)) & 0x3F];
+ data |= idx << (i*6);
+ }
+ return (uint64_t)(uint16_t)_mm_cvtsi128_si32( minmax ) | ( data << 16 );
+}
+#endif
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+#ifdef __AVX2__
+ if( width%8 == 0 )
+ {
+ blocks /= 2;
+ uint32_t buf[8*4];
+ int i = 0;
+ char* dst8 = (char*)dst;
+
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 8*4 );
+ memcpy( tmp + 8*4, src + width * 1, 8*4 );
+ memcpy( tmp + 16*4, src + width * 2, 8*4 );
+ memcpy( tmp + 24*4, src + width * 3, 8*4 );
+ src += 8;
+ if( ++i == width/8 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ ProcessRGB_AVX( (uint8_t*)buf, dst8 );
+ }
+ while( --blocks );
+ }
+ else
+#endif
+ {
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+ }
+}
+
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ Dither( (uint8_t*)buf );
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+}
+
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int i = 0;
+ auto ptr = dst;
+ do
+ {
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128( (__m128i*)( src + width * 0 ) );
+ __m128i px1 = _mm_loadu_si128( (__m128i*)( src + width * 1 ) );
+ __m128i px2 = _mm_loadu_si128( (__m128i*)( src + width * 2 ) );
+ __m128i px3 = _mm_loadu_si128( (__m128i*)( src + width * 3 ) );
+
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ *ptr++ = ProcessAlpha_SSE( px0, px1, px2, px3 );
+
+ const auto c = ProcessRGB_SSE( px0, px1, px2, px3 );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#else
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+
+ auto tmp = (char*)rgba;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ for( int i=0; i<16; i++ )
+ {
+ alpha[i] = rgba[i] >> 24;
+ rgba[i] &= 0xFFFFFF;
+ }
+ *ptr++ = ProcessAlpha( alpha );
+
+ const auto c = ProcessRGB( (uint8_t*)rgba );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#endif
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessDxtc.hpp b/thirdparty/etcpak/ProcessDxtc.hpp
new file mode 100644
index 0000000000..8e0b12e4bd
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.hpp
@@ -0,0 +1,11 @@
+#ifndef __PROCESSDXT1_HPP__
+#define __PROCESSDXT1_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp
new file mode 100644
index 0000000000..7f4524d105
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.cpp
@@ -0,0 +1,3100 @@
+#include <array>
+#include <string.h>
+#include <limits>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "Math.hpp"
+#include "ProcessCommon.hpp"
+#include "ProcessRGB.hpp"
+#include "Tables.hpp"
+#include "Vector.hpp"
+#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# define _bswap(x) _byteswap_ulong(x)
+# define _bswap64(x) _byteswap_uint64(x)
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifndef _bswap
+# define _bswap(x) __builtin_bswap32(x)
+# define _bswap64(x) __builtin_bswap64(x)
+#endif
+
+namespace
+{
+
+#if defined _MSC_VER && !defined __clang__
+static etcpak_force_inline unsigned long _bit_scan_forward( unsigned long mask )
+{
+ unsigned long ret;
+ _BitScanForward( &ret, mask );
+ return ret;
+}
+#endif
+
+typedef std::array<uint16_t, 4> v4i;
+
+#ifdef __AVX2__
+static etcpak_force_inline __m256i Sum4_AVX2( const uint8_t* data) noexcept
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m256i t0 = _mm256_cvtepu8_epi16(dm0);
+ __m256i t1 = _mm256_cvtepu8_epi16(dm1);
+ __m256i t2 = _mm256_cvtepu8_epi16(dm2);
+ __m256i t3 = _mm256_cvtepu8_epi16(dm3);
+
+ __m256i sum0 = _mm256_add_epi16(t0, t1);
+ __m256i sum1 = _mm256_add_epi16(t2, t3);
+
+ __m256i s0 = _mm256_permute2x128_si256(sum0, sum1, (0) | (3 << 4)); // 0, 0, 3, 3
+ __m256i s1 = _mm256_permute2x128_si256(sum0, sum1, (1) | (2 << 4)); // 1, 1, 2, 2
+
+ __m256i s2 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(1, 3, 0, 2));
+ __m256i s3 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(0, 2, 1, 3));
+ __m256i s4 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(3, 1, 0, 2));
+ __m256i s5 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(2, 0, 1, 3));
+
+ __m256i sum5 = _mm256_add_epi16(s2, s3); // 3, 0, 3, 0
+ __m256i sum6 = _mm256_add_epi16(s4, s5); // 2, 1, 1, 2
+ return _mm256_add_epi16(sum5, sum6); // 3+2, 0+1, 3+1, 3+2
+}
+
+static etcpak_force_inline __m256i Average_AVX2( const __m256i data) noexcept
+{
+ __m256i a = _mm256_add_epi16(data, _mm256_set1_epi16(4));
+
+ return _mm256_srli_epi16(a, 3);
+}
+
+static etcpak_force_inline __m128i CalcErrorBlock_AVX2( const __m256i data, const v4i a[8]) noexcept
+{
+ //
+ __m256i a0 = _mm256_load_si256((__m256i*)a[0].data());
+ __m256i a1 = _mm256_load_si256((__m256i*)a[4].data());
+
+ // err = 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ __m256i a4 = _mm256_madd_epi16(a0, a0);
+ __m256i a5 = _mm256_madd_epi16(a1, a1);
+
+ __m256i a6 = _mm256_hadd_epi32(a4, a5);
+ __m256i a7 = _mm256_slli_epi32(a6, 3);
+
+ __m256i a8 = _mm256_add_epi32(a7, _mm256_set1_epi32(0x3FFFFFFF)); // Big value to prevent negative values, but small enough to prevent overflow
+
+ // average is not swapped
+ // err -= block[0] * 2 * average[0];
+ // err -= block[1] * 2 * average[1];
+ // err -= block[2] * 2 * average[2];
+ __m256i a2 = _mm256_slli_epi16(a0, 1);
+ __m256i a3 = _mm256_slli_epi16(a1, 1);
+ __m256i b0 = _mm256_madd_epi16(a2, data);
+ __m256i b1 = _mm256_madd_epi16(a3, data);
+
+ __m256i b2 = _mm256_hadd_epi32(b0, b1);
+ __m256i b3 = _mm256_sub_epi32(a8, b2);
+ __m256i b4 = _mm256_hadd_epi32(b3, b3);
+
+ __m256i b5 = _mm256_permutevar8x32_epi32(b4, _mm256_set_epi32(0, 0, 0, 0, 5, 1, 4, 0));
+
+ return _mm256_castsi256_si128(b5);
+}
+
+static etcpak_force_inline void ProcessAverages_AVX2(const __m256i d, v4i a[8] ) noexcept
+{
+ __m256i t = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(31)), _mm256_set1_epi16(128));
+
+ __m256i c = _mm256_srli_epi16(_mm256_add_epi16(t, _mm256_srli_epi16(t, 8)), 8);
+
+ __m256i c1 = _mm256_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m256i diff = _mm256_sub_epi16(c, c1);
+ diff = _mm256_max_epi16(diff, _mm256_set1_epi16(-4));
+ diff = _mm256_min_epi16(diff, _mm256_set1_epi16(3));
+
+ __m256i co = _mm256_add_epi16(c1, diff);
+
+ c = _mm256_blend_epi16(co, c, 0xF0);
+
+ __m256i a0 = _mm256_or_si256(_mm256_slli_epi16(c, 3), _mm256_srli_epi16(c, 2));
+
+ _mm256_store_si256((__m256i*)a[4].data(), a0);
+
+ __m256i t0 = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(15)), _mm256_set1_epi16(128));
+ __m256i t1 = _mm256_srli_epi16(_mm256_add_epi16(t0, _mm256_srli_epi16(t0, 8)), 8);
+
+ __m256i t2 = _mm256_or_si256(t1, _mm256_slli_epi16(t1, 4));
+
+ _mm256_store_si256((__m256i*)a[0].data(), t2);
+}
+
+static etcpak_force_inline uint64_t EncodeAverages_AVX2( const v4i a[8], size_t idx ) noexcept
+{
+ uint64_t d = ( idx << 24 );
+ size_t base = idx << 1;
+
+ __m128i a0 = _mm_load_si128((const __m128i*)a[base].data());
+
+ __m128i r0, r1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ r0 = _mm_srli_epi16(a0, 4);
+
+ __m128i a1 = _mm_unpackhi_epi64(r0, r0);
+ r1 = _mm_slli_epi16(a1, 4);
+ }
+ else
+ {
+ __m128i a1 = _mm_and_si128(a0, _mm_set1_epi16(-8));
+
+ r0 = _mm_unpackhi_epi64(a1, a1);
+ __m128i a2 = _mm_sub_epi16(a1, r0);
+ __m128i a3 = _mm_srai_epi16(a2, 3);
+ r1 = _mm_and_si128(a3, _mm_set1_epi16(0x07));
+ }
+
+ __m128i r2 = _mm_or_si128(r0, r1);
+ // do missing swap for average values
+ __m128i r3 = _mm_shufflelo_epi16(r2, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128i r4 = _mm_packus_epi16(r3, _mm_setzero_si128());
+ d |= _mm_cvtsi128_si32(r4);
+
+ return d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid_AVX2( const uint8_t* src ) noexcept
+{
+ __m256i d0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i d1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+
+ __m256i c = _mm256_broadcastd_epi32(_mm256_castsi256_si128(d0));
+
+ __m256i c0 = _mm256_cmpeq_epi8(d0, c);
+ __m256i c1 = _mm256_cmpeq_epi8(d1, c);
+
+ __m256i m = _mm256_and_si256(c0, c1);
+
+ if (!_mm256_testc_si256(m, _mm256_set1_epi32(-1)))
+ {
+ return 0;
+ }
+
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const uint8_t* src) noexcept
+{
+ __m256i sum4 = Sum4_AVX2( src );
+
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const __m256i sum4) noexcept
+{
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline void FindBestFit_4x2_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ for (unsigned int j = 0; j < 2; ++j)
+ {
+ unsigned int bid = offset + 1 - j;
+
+ __m256i squareErrorSum = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[bid].data());
+ __m256i a1 = _mm256_broadcastq_epi64(a0);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 8; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a1, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is significant faster
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ data += 8 * 4;
+
+ _mm256_store_si256((__m256i*)terr[1 - j], squareErrorSum);
+ }
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline void FindBestFit_2x4_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ __m256i squareErrorSum0 = _mm256_setzero_si256();
+ __m256i squareErrorSum1 = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[offset + 1].data());
+ __m128i a1 = _mm_loadl_epi64((const __m128i*)a[offset + 0].data());
+
+ __m128i a2 = _mm_broadcastq_epi64(a0);
+ __m128i a3 = _mm_broadcastq_epi64(a1);
+ __m256i a4 = _mm256_insertf128_si256(_mm256_castsi128_si256(a2), a3, 1);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 16; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a4, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum0 = _mm256_add_epi32(squareErrorSum0, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum1 = _mm256_add_epi32(squareErrorSum1, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ _mm256_store_si256((__m256i*)terr[1], squareErrorSum0);
+ _mm256_store_si256((__m256i*)terr[0], squareErrorSum1);
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+static etcpak_force_inline __m128i r6g7b6_AVX2(__m128 cof, __m128 chf, __m128 cvf) noexcept
+{
+ __m128i co = _mm_cvttps_epi32(cof);
+ __m128i ch = _mm_cvttps_epi32(chf);
+ __m128i cv = _mm_cvttps_epi32(cvf);
+
+ __m128i coh = _mm_packus_epi32(co, ch);
+ __m128i cv0 = _mm_packus_epi32(cv, _mm_setzero_si128());
+
+ __m256i cohv0 = _mm256_inserti128_si256(_mm256_castsi128_si256(coh), cv0, 1);
+ __m256i cohv1 = _mm256_min_epu16(cohv0, _mm256_set1_epi16(1023));
+
+ __m256i cohv2 = _mm256_sub_epi16(cohv1, _mm256_set1_epi16(15));
+ __m256i cohv3 = _mm256_srai_epi16(cohv2, 1);
+
+ __m256i cohvrb0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(11));
+ __m256i cohvrb1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(4));
+ __m256i cohvg0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(9));
+ __m256i cohvg1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(6));
+
+ __m256i cohvrb2 = _mm256_srai_epi16(cohvrb0, 7);
+ __m256i cohvrb3 = _mm256_srai_epi16(cohvrb1, 7);
+ __m256i cohvg2 = _mm256_srai_epi16(cohvg0, 8);
+ __m256i cohvg3 = _mm256_srai_epi16(cohvg1, 8);
+
+ __m256i cohvrb4 = _mm256_sub_epi16(cohvrb0, cohvrb2);
+ __m256i cohvrb5 = _mm256_sub_epi16(cohvrb4, cohvrb3);
+ __m256i cohvg4 = _mm256_sub_epi16(cohvg0, cohvg2);
+ __m256i cohvg5 = _mm256_sub_epi16(cohvg4, cohvg3);
+
+ __m256i cohvrb6 = _mm256_srai_epi16(cohvrb5, 3);
+ __m256i cohvg6 = _mm256_srai_epi16(cohvg5, 2);
+
+ __m256i cohv4 = _mm256_blend_epi16(cohvg6, cohvrb6, 0x55);
+
+ __m128i cohv5 = _mm_packus_epi16(_mm256_castsi256_si128(cohv4), _mm256_extracti128_si256(cohv4, 1));
+ return _mm_shuffle_epi8(cohv5, _mm_setr_epi8(6, 5, 4, -1, 2, 1, 0, -1, 10, 9, 8, -1, -1, -1, -1, -1));
+}
+
+struct Plane
+{
+ uint64_t plane;
+ uint64_t error;
+ __m256i sum4;
+};
+
+static etcpak_force_inline Plane Planar_AVX2(const uint8_t* src)
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i rgb0 = _mm_shuffle_epi8(d0, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb1 = _mm_shuffle_epi8(d1, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb2 = _mm_shuffle_epi8(d2, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb3 = _mm_shuffle_epi8(d3, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+
+ __m128i rg0 = _mm_unpacklo_epi32(rgb0, rgb1);
+ __m128i rg1 = _mm_unpacklo_epi32(rgb2, rgb3);
+ __m128i b0 = _mm_unpackhi_epi32(rgb0, rgb1);
+ __m128i b1 = _mm_unpackhi_epi32(rgb2, rgb3);
+
+ // swap channels
+ __m128i b8 = _mm_unpacklo_epi64(rg0, rg1);
+ __m128i g8 = _mm_unpackhi_epi64(rg0, rg1);
+ __m128i r8 = _mm_unpacklo_epi64(b0, b1);
+
+ __m128i t0 = _mm_sad_epu8(r8, _mm_setzero_si128());
+ __m128i t1 = _mm_sad_epu8(g8, _mm_setzero_si128());
+ __m128i t2 = _mm_sad_epu8(b8, _mm_setzero_si128());
+
+ __m128i r8s = _mm_shuffle_epi8(r8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i g8s = _mm_shuffle_epi8(g8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i b8s = _mm_shuffle_epi8(b8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+
+ __m128i s0 = _mm_sad_epu8(r8s, _mm_setzero_si128());
+ __m128i s1 = _mm_sad_epu8(g8s, _mm_setzero_si128());
+ __m128i s2 = _mm_sad_epu8(b8s, _mm_setzero_si128());
+
+ __m256i sr0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t0), s0, 1);
+ __m256i sg0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t1), s1, 1);
+ __m256i sb0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t2), s2, 1);
+
+ __m256i sr1 = _mm256_slli_epi64(sr0, 32);
+ __m256i sg1 = _mm256_slli_epi64(sg0, 16);
+
+ __m256i srb = _mm256_or_si256(sr1, sb0);
+ __m256i srgb = _mm256_or_si256(srb, sg1);
+
+ __m128i t3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(t0), _mm_castsi128_ps(t1), _MM_SHUFFLE(2, 0, 2, 0)));
+ __m128i t4 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i t5 = _mm_hadd_epi32(t3, t4);
+ __m128i t6 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(1, 1, 1, 1));
+ __m128i t7 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(2, 2, 2, 2));
+
+ __m256i sr = _mm256_broadcastw_epi16(t5);
+ __m256i sg = _mm256_broadcastw_epi16(t6);
+ __m256i sb = _mm256_broadcastw_epi16(t7);
+
+ __m256i r08 = _mm256_cvtepu8_epi16(r8);
+ __m256i g08 = _mm256_cvtepu8_epi16(g8);
+ __m256i b08 = _mm256_cvtepu8_epi16(b8);
+
+ __m256i r16 = _mm256_slli_epi16(r08, 4);
+ __m256i g16 = _mm256_slli_epi16(g08, 4);
+ __m256i b16 = _mm256_slli_epi16(b08, 4);
+
+ __m256i difR0 = _mm256_sub_epi16(r16, sr);
+ __m256i difG0 = _mm256_sub_epi16(g16, sg);
+ __m256i difB0 = _mm256_sub_epi16(b16, sb);
+
+ __m256i difRyz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difGyz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difByz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+
+ __m256i difRxz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difGxz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difBxz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+
+ __m256i difRGyz = _mm256_hadd_epi32(difRyz, difGyz);
+ __m256i difByzxz = _mm256_hadd_epi32(difByz, difBxz);
+
+ __m256i difRGxz = _mm256_hadd_epi32(difRxz, difGxz);
+
+ __m128i sumRGyz = _mm_add_epi32(_mm256_castsi256_si128(difRGyz), _mm256_extracti128_si256(difRGyz, 1));
+ __m128i sumByzxz = _mm_add_epi32(_mm256_castsi256_si128(difByzxz), _mm256_extracti128_si256(difByzxz, 1));
+ __m128i sumRGxz = _mm_add_epi32(_mm256_castsi256_si128(difRGxz), _mm256_extracti128_si256(difRGxz, 1));
+
+ __m128i sumRGByz = _mm_hadd_epi32(sumRGyz, sumByzxz);
+ __m128i sumRGByzxz = _mm_hadd_epi32(sumRGxz, sumByzxz);
+
+ __m128i sumRGBxz = _mm_shuffle_epi32(sumRGByzxz, _MM_SHUFFLE(2, 3, 1, 0));
+
+ __m128 sumRGByzf = _mm_cvtepi32_ps(sumRGByz);
+ __m128 sumRGBxzf = _mm_cvtepi32_ps(sumRGBxz);
+
+ const float value = (255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f;
+
+ __m128 scale = _mm_set1_ps(-4.0f / value);
+
+ __m128 af = _mm_mul_ps(sumRGBxzf, scale);
+ __m128 bf = _mm_mul_ps(sumRGByzf, scale);
+
+ __m128 df = _mm_mul_ps(_mm_cvtepi32_ps(t5), _mm_set1_ps(4.0f / 16.0f));
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ __m128 cof0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 chf0 = _mm_fnmadd_ps(af, _mm_set1_ps( 425.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 cvf0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps( 425.0f), df));
+
+ // convert to r6g7b6
+ __m128i cohv = r6g7b6_AVX2(cof0, chf0, cvf0);
+
+ uint64_t rgbho = _mm_extract_epi64(cohv, 0);
+ uint32_t rgbv0 = _mm_extract_epi32(cohv, 2);
+
+ // Error calculation
+ auto ro0 = (rgbho >> 48) & 0x3F;
+ auto go0 = (rgbho >> 40) & 0x7F;
+ auto bo0 = (rgbho >> 32) & 0x3F;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ __m256i ro3 = _mm256_set1_epi16(ro2);
+ __m256i go3 = _mm256_set1_epi16(go2);
+ __m256i bo3 = _mm256_set1_epi16(bo2);
+
+ auto rh0 = (rgbho >> 16) & 0x3F;
+ auto gh0 = (rgbho >> 8) & 0x7F;
+ auto bh0 = (rgbho >> 0) & 0x3F;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ __m256i rh3 = _mm256_set1_epi16(rh2);
+ __m256i gh3 = _mm256_set1_epi16(gh2);
+ __m256i bh3 = _mm256_set1_epi16(bh2);
+
+ auto rv0 = (rgbv0 >> 16) & 0x3F;
+ auto gv0 = (rgbv0 >> 8) & 0x7F;
+ auto bv0 = (rgbv0 >> 0) & 0x3F;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ __m256i rv3 = _mm256_set1_epi16(rv2);
+ __m256i gv3 = _mm256_set1_epi16(gv2);
+ __m256i bv3 = _mm256_set1_epi16(bv2);
+
+ __m256i x = _mm256_set_epi16(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0);
+
+ __m256i rh4 = _mm256_mullo_epi16(rh3, x);
+ __m256i gh4 = _mm256_mullo_epi16(gh3, x);
+ __m256i bh4 = _mm256_mullo_epi16(bh3, x);
+
+ __m256i y = _mm256_set_epi16(3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0);
+
+ __m256i rv4 = _mm256_mullo_epi16(rv3, y);
+ __m256i gv4 = _mm256_mullo_epi16(gv3, y);
+ __m256i bv4 = _mm256_mullo_epi16(bv3, y);
+
+ __m256i rxy = _mm256_add_epi16(rh4, rv4);
+ __m256i gxy = _mm256_add_epi16(gh4, gv4);
+ __m256i bxy = _mm256_add_epi16(bh4, bv4);
+
+ __m256i rp0 = _mm256_add_epi16(rxy, ro3);
+ __m256i gp0 = _mm256_add_epi16(gxy, go3);
+ __m256i bp0 = _mm256_add_epi16(bxy, bo3);
+
+ __m256i rp1 = _mm256_srai_epi16(rp0, 2);
+ __m256i gp1 = _mm256_srai_epi16(gp0, 2);
+ __m256i bp1 = _mm256_srai_epi16(bp0, 2);
+
+ __m256i rp2 = _mm256_max_epi16(_mm256_min_epi16(rp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i gp2 = _mm256_max_epi16(_mm256_min_epi16(gp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i bp2 = _mm256_max_epi16(_mm256_min_epi16(bp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+
+ __m256i rdif = _mm256_sub_epi16(r08, rp2);
+ __m256i gdif = _mm256_sub_epi16(g08, gp2);
+ __m256i bdif = _mm256_sub_epi16(b08, bp2);
+
+ __m256i rerr = _mm256_mullo_epi16(rdif, _mm256_set1_epi16(38));
+ __m256i gerr = _mm256_mullo_epi16(gdif, _mm256_set1_epi16(76));
+ __m256i berr = _mm256_mullo_epi16(bdif, _mm256_set1_epi16(14));
+
+ __m256i sum0 = _mm256_add_epi16(rerr, gerr);
+ __m256i sum1 = _mm256_add_epi16(sum0, berr);
+
+ __m256i sum2 = _mm256_madd_epi16(sum1, sum1);
+
+ __m128i sum3 = _mm_add_epi32(_mm256_castsi256_si128(sum2), _mm256_extracti128_si256(sum2, 1));
+
+ uint32_t err0 = _mm_extract_epi32(sum3, 0);
+ uint32_t err1 = _mm_extract_epi32(sum3, 1);
+ uint32_t err2 = _mm_extract_epi32(sum3, 2);
+ uint32_t err3 = _mm_extract_epi32(sum3, 3);
+
+ uint64_t error = err0 + err1 + err2 + err3;
+ /**/
+
+ uint32_t rgbv = ( rgbv0 & 0x3F ) | ( ( rgbv0 >> 2 ) & 0x1FC0 ) | ( ( rgbv0 >> 3 ) & 0x7E000 );
+ uint64_t rgbho0_ = ( rgbho & 0x3F0000003F ) | ( ( rgbho >> 2 ) & 0x1FC000001FC0 ) | ( ( rgbho >> 3 ) & 0x7E0000007E000 );
+ uint64_t rgbho0 = ( rgbho0_ & 0x7FFFF ) | ( ( rgbho0_ >> 13 ) & 0x3FFFF80000 );
+
+ uint32_t hi = rgbv | ((rgbho0 & 0x1FFF) << 19);
+ rgbho0 >>= 13;
+ uint32_t lo = ( rgbho0 & 0x1 ) | ( ( rgbho0 & 0x1FE ) << 1 ) | ( ( rgbho0 & 0x600 ) << 2 ) | ( ( rgbho0 & 0x3F800 ) << 5 ) | ( ( rgbho0 & 0x1FC0000 ) << 6 );
+
+ uint32_t idx = ( ( rgbho >> 33 ) & 0xF ) | ( ( rgbho >> 41 ) & 0x10 ) | ( ( rgbho >> 48 ) & 0x20 );
+ lo |= g_flags[idx];
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ Plane plane;
+
+ plane.plane = result;
+ plane.error = error;
+ plane.sum4 = _mm256_permute4x64_epi64(srgb, _MM_SHUFFLE(2, 3, 0, 1));
+
+ return plane;
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate, const uint64_t value, const uint32_t error) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+#endif
+
+static etcpak_force_inline void Average( const uint8_t* data, v4i* a )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i d0l = _mm_unpacklo_epi8(d0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(d0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(d1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(d1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(d2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(d2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(d3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(d3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b2, b3), _mm_set1_epi32(4)), 3);
+ __m128i a1 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b1), _mm_set1_epi32(4)), 3);
+ __m128i a2 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b1, b3), _mm_set1_epi32(4)), 3);
+ __m128i a3 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b2), _mm_set1_epi32(4)), 3);
+
+ _mm_storeu_si128((__m128i*)&a[0], _mm_packus_epi32(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a1, _MM_SHUFFLE(3, 0, 1, 2))));
+ _mm_storeu_si128((__m128i*)&a[2], _mm_packus_epi32(_mm_shuffle_epi32(a2, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a3, _MM_SHUFFLE(3, 0, 1, 2))));
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ) ) ), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ) ) ), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b2, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a1 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b1), vdupq_n_u32(4)), 3);
+ uint32x4_t a2 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b1, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a3 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b2), vdupq_n_u32(4)), 3);
+
+ uint16x8_t o0 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a0 )), vqmovun_s32(vreinterpretq_s32_u32( a1 )));
+ uint16x8_t o1 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a2 )), vqmovun_s32(vreinterpretq_s32_u32( a3 )));
+
+ a[0] = v4i{o0[2], o0[1], o0[0], 0};
+ a[1] = v4i{o0[6], o0[5], o0[4], 0};
+ a[2] = v4i{o1[2], o1[1], o1[0], 0};
+ a[3] = v4i{o1[6], o1[5], o1[4], 0};
+#else
+ uint32_t r[4];
+ uint32_t g[4];
+ uint32_t b[4];
+
+ memset(r, 0, sizeof(r));
+ memset(g, 0, sizeof(g));
+ memset(b, 0, sizeof(b));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ b[index] += *data++;
+ g[index] += *data++;
+ r[index] += *data++;
+ data++;
+ }
+ }
+
+ a[0] = v4i{ uint16_t( (r[2] + r[3] + 4) / 8 ), uint16_t( (g[2] + g[3] + 4) / 8 ), uint16_t( (b[2] + b[3] + 4) / 8 ), 0};
+ a[1] = v4i{ uint16_t( (r[0] + r[1] + 4) / 8 ), uint16_t( (g[0] + g[1] + 4) / 8 ), uint16_t( (b[0] + b[1] + 4) / 8 ), 0};
+ a[2] = v4i{ uint16_t( (r[1] + r[3] + 4) / 8 ), uint16_t( (g[1] + g[3] + 4) / 8 ), uint16_t( (b[1] + b[3] + 4) / 8 ), 0};
+ a[3] = v4i{ uint16_t( (r[0] + r[2] + 4) / 8 ), uint16_t( (g[0] + g[2] + 4) / 8 ), uint16_t( (b[0] + b[2] + 4) / 8 ), 0};
+#endif
+}
+
+static etcpak_force_inline void CalcErrorBlock( const uint8_t* data, unsigned int err[4][4] )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m128i d0l = _mm_unpacklo_epi8(dm0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(dm0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(dm1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(dm1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(dm2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(dm2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(dm3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(dm3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_add_epi32(b2, b3);
+ __m128i a1 = _mm_add_epi32(b0, b1);
+ __m128i a2 = _mm_add_epi32(b1, b3);
+ __m128i a3 = _mm_add_epi32(b0, b2);
+
+ _mm_storeu_si128((__m128i*)&err[0], a0);
+ _mm_storeu_si128((__m128i*)&err[1], a1);
+ _mm_storeu_si128((__m128i*)&err[2], a2);
+ _mm_storeu_si128((__m128i*)&err[3], a3);
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ))), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ))), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ))), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ))), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b2, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a1 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b1) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a2 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b1, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a3 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b2) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+
+ vst1q_u32(err[0], a0);
+ vst1q_u32(err[1], a1);
+ vst1q_u32(err[2], a2);
+ vst1q_u32(err[3], a3);
+#else
+ unsigned int terr[4][4];
+
+ memset(terr, 0, 16 * sizeof(unsigned int));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ unsigned int d = *data++;
+ terr[index][0] += d;
+ d = *data++;
+ terr[index][1] += d;
+ d = *data++;
+ terr[index][2] += d;
+ data++;
+ }
+ }
+
+ for( int i=0; i<3; i++ )
+ {
+ err[0][i] = terr[2][i] + terr[3][i];
+ err[1][i] = terr[0][i] + terr[1][i];
+ err[2][i] = terr[1][i] + terr[3][i];
+ err[3][i] = terr[0][i] + terr[2][i];
+ }
+ for( int i=0; i<4; i++ )
+ {
+ err[i][3] = 0;
+ }
+#endif
+}
+
+static etcpak_force_inline unsigned int CalcError( const unsigned int block[4], const v4i& average )
+{
+ unsigned int err = 0x3FFFFFFF; // Big value to prevent negative values, but small enough to prevent overflow
+ err -= block[0] * 2 * average[2];
+ err -= block[1] * 2 * average[1];
+ err -= block[2] * 2 * average[0];
+ err += 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ return err;
+}
+
+static etcpak_force_inline void ProcessAverages( v4i* a )
+{
+#ifdef __SSE4_1__
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(31)), _mm_set1_epi16(128));
+
+ __m128i c = _mm_srli_epi16(_mm_add_epi16(t, _mm_srli_epi16(t, 8)), 8);
+
+ __m128i c1 = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m128i diff = _mm_sub_epi16(c, c1);
+ diff = _mm_max_epi16(diff, _mm_set1_epi16(-4));
+ diff = _mm_min_epi16(diff, _mm_set1_epi16(3));
+
+ __m128i co = _mm_add_epi16(c1, diff);
+
+ c = _mm_blend_epi16(co, c, 0xF0);
+
+ __m128i a0 = _mm_or_si128(_mm_slli_epi16(c, 3), _mm_srli_epi16(c, 2));
+
+ _mm_storeu_si128((__m128i*)a[4+i*2].data(), a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t0 = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(15)), _mm_set1_epi16(128));
+ __m128i t1 = _mm_srli_epi16(_mm_add_epi16(t0, _mm_srli_epi16(t0, 8)), 8);
+
+ __m128i t2 = _mm_or_si128(t1, _mm_slli_epi16(t1, 4));
+
+ _mm_storeu_si128((__m128i*)a[i*2].data(), t2);
+ }
+#elif defined __ARM_NEON
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+ int16x8_t t = vaddq_s16(vmulq_s16(d, vdupq_n_s16(31)), vdupq_n_s16(128));
+ int16x8_t c = vshrq_n_s16(vaddq_s16(t, vshrq_n_s16(t, 8)), 8);
+
+ int16x8_t c1 = vcombine_s16(vget_high_s16(c), vget_high_s16(c));
+ int16x8_t diff = vsubq_s16(c, c1);
+ diff = vmaxq_s16(diff, vdupq_n_s16(-4));
+ diff = vminq_s16(diff, vdupq_n_s16(3));
+
+ int16x8_t co = vaddq_s16(c1, diff);
+
+ c = vcombine_s16(vget_low_s16(co), vget_high_s16(c));
+
+ int16x8_t a0 = vorrq_s16(vshlq_n_s16(c, 3), vshrq_n_s16(c, 2));
+
+ vst1q_s16((int16_t*)&a[4+i*2], a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+
+ int16x8_t t0 = vaddq_s16(vmulq_s16(d, vdupq_n_s16(15)), vdupq_n_s16(128));
+ int16x8_t t1 = vshrq_n_s16(vaddq_s16(t0, vshrq_n_s16(t0, 8)), 8);
+
+ int16x8_t t2 = vorrq_s16(t1, vshlq_n_s16(t1, 4));
+
+ vst1q_s16((int16_t*)&a[i*2], t2);
+ }
+#else
+ for( int i=0; i<2; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ int32_t c1 = mul8bit( a[i*2+1][j], 31 );
+ int32_t c2 = mul8bit( a[i*2][j], 31 );
+
+ int32_t diff = c2 - c1;
+ if( diff > 3 ) diff = 3;
+ else if( diff < -4 ) diff = -4;
+
+ int32_t co = c1 + diff;
+
+ a[5+i*2][j] = ( c1 << 3 ) | ( c1 >> 2 );
+ a[4+i*2][j] = ( co << 3 ) | ( co >> 2 );
+ }
+ }
+
+ for( int i=0; i<4; i++ )
+ {
+ a[i][0] = g_avg2[mul8bit( a[i][0], 15 )];
+ a[i][1] = g_avg2[mul8bit( a[i][1], 15 )];
+ a[i][2] = g_avg2[mul8bit( a[i][2], 15 )];
+ }
+#endif
+}
+
+static etcpak_force_inline void EncodeAverages( uint64_t& _d, const v4i* a, size_t idx )
+{
+ auto d = _d;
+ d |= ( idx << 24 );
+ size_t base = idx << 1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+0][i] >> 4 ) << ( i*8 );
+ d |= uint64_t( a[base+1][i] >> 4 ) << ( i*8 + 4 );
+ }
+ }
+ else
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+1][i] & 0xF8 ) << ( i*8 );
+ int32_t c = ( ( a[base+0][i] & 0xF8 ) - ( a[base+1][i] & 0xF8 ) ) >> 3;
+ c &= ~0xFFFFFFF8;
+ d |= ((uint64_t)c) << ( i*8 );
+ }
+ }
+ _d = d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i c = _mm_shuffle_epi32(d0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i c0 = _mm_cmpeq_epi8(d0, c);
+ __m128i c1 = _mm_cmpeq_epi8(d1, c);
+ __m128i c2 = _mm_cmpeq_epi8(d2, c);
+ __m128i c3 = _mm_cmpeq_epi8(d3, c);
+
+ __m128i m0 = _mm_and_si128(c0, c1);
+ __m128i m1 = _mm_and_si128(c2, c3);
+ __m128i m = _mm_and_si128(m0, m1);
+
+ if (!_mm_testc_si128(m, _mm_set1_epi32(-1)))
+ {
+ return 0;
+ }
+#elif defined __ARM_NEON
+ int32x4_t d0 = vld1q_s32((int32_t*)src + 0);
+ int32x4_t d1 = vld1q_s32((int32_t*)src + 4);
+ int32x4_t d2 = vld1q_s32((int32_t*)src + 8);
+ int32x4_t d3 = vld1q_s32((int32_t*)src + 12);
+
+ int32x4_t c = vdupq_n_s32(d0[0]);
+
+ int32x4_t c0 = vreinterpretq_s32_u32(vceqq_s32(d0, c));
+ int32x4_t c1 = vreinterpretq_s32_u32(vceqq_s32(d1, c));
+ int32x4_t c2 = vreinterpretq_s32_u32(vceqq_s32(d2, c));
+ int32x4_t c3 = vreinterpretq_s32_u32(vceqq_s32(d3, c));
+
+ int32x4_t m0 = vandq_s32(c0, c1);
+ int32x4_t m1 = vandq_s32(c2, c3);
+ int64x2_t m = vreinterpretq_s64_s32(vandq_s32(m0, m1));
+
+ if (m[0] != -1 || m[1] != -1)
+ {
+ return 0;
+ }
+#else
+ const uint8_t* ptr = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ if( memcmp( src, ptr, 4 ) != 0 )
+ {
+ return 0;
+ }
+ ptr += 4;
+ }
+#endif
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline void PrepareAverages( v4i a[8], const uint8_t* src, unsigned int err[4] )
+{
+ Average( src, a );
+ ProcessAverages( a );
+
+ unsigned int errblock[4][4];
+ CalcErrorBlock( src, errblock );
+
+ for( int i=0; i<4; i++ )
+ {
+ err[i/2] += CalcError( errblock[i], a[i] );
+ err[2+i/2] += CalcError( errblock[i], a[i+4] );
+ }
+}
+
+static etcpak_force_inline void FindBestFit( uint64_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint64_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // Reference implementation
+
+ __m128i pix = _mm_set1_epi32(dr * 77 + dg * 151 + db * 28);
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ __m128i error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[0]));
+ __m128i error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[1]));
+ __m128i error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[0]));
+ __m128i error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[1]));
+
+ __m128i index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ __m128i minError0 = _mm_min_epi32(error0, error1);
+
+ __m128i index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ __m128i minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex0 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ __m128i minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m128i squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ __m128i minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ __m128i squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[2]));
+ error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[3]));
+ error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[2]));
+ error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[3]));
+
+ index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ minError0 = _mm_min_epi32(error0, error1);
+
+ index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex1 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 2));
+ _mm_storeu_si128(((__m128i*)ter) + 2, squareErrorLow);
+ minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 3));
+ _mm_storeu_si128(((__m128i*)ter) + 3, squareErrorHigh);
+ __m128i minIndex = _mm_packs_epi32(minIndex0, minIndex1);
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int32x4_t pix = vdupq_n_s32(dr * 77 + dg * 151 + db * 28);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ uint32x4_t error0 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error1 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[1])));
+ uint32x4_t error2 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error3 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[1])));
+
+ uint32x4_t index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ uint32x4_t minError0 = vminq_u32(error0, error1);
+
+ uint32x4_t index1 = vreinterpretq_u32_s32(vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))));
+ uint32x4_t minError1 = vminq_u32(error2, error3);
+
+ uint32x4_t blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex0 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ uint32x4_t minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ uint32x4_t squareErrorLow = vmulq_u32(minError, minError);
+ uint32x4_t squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError))), 1);
+ uint32x4x2_t squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ uint64x2x2_t squareError = { vreinterpretq_u64_u32(squareErrorZip.val[0]), vreinterpretq_u64_u32(squareErrorZip.val[1]) };
+ squareError.val[0] = vaddq_u64(squareError.val[0], vld1q_u64(ter + 0));
+ squareError.val[1] = vaddq_u64(squareError.val[1], vld1q_u64(ter + 2));
+ vst1q_u64(ter + 0, squareError.val[0]);
+ vst1q_u64(ter + 2, squareError.val[1]);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[2])));
+ error1 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[3])));
+ error2 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[2])));
+ error3 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[3])));
+
+ index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ minError0 = vminq_u32(error0, error1);
+
+ index1 = vreinterpretq_u32_s32( vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))) );
+ minError1 = vminq_u32(error2, error3);
+
+ blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex1 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ squareErrorLow = vmulq_u32(minError, minError);
+ squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32( vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError)) ), 1 );
+ squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ squareError.val[0] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[0] ), vld1q_u64(ter + 4));
+ squareError.val[1] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[1] ), vld1q_u64(ter + 6));
+ vst1q_u64(ter + 4, squareError.val[0]);
+ vst1q_u64(ter + 6, squareError.val[1]);
+
+ uint16x8_t minIndex = vcombine_u16(vqmovn_u32(minIndex0), vqmovn_u32(minIndex1));
+ vst1q_u16(sel, minIndex);
+#else
+ int pix = dr * 77 + dg * 151 + db * 28;
+
+ for( int t=0; t<8; t++ )
+ {
+ const int64_t* tab = g_table256[t];
+ unsigned int idx = 0;
+ uint64_t err = sq( tab[0] + pix );
+ for( int j=1; j<4; j++ )
+ {
+ uint64_t local = sq( tab[j] + pix );
+ if( local < err )
+ {
+ err = local;
+ idx = j;
+ }
+ }
+ *sel++ = idx;
+ *ter++ += err;
+ }
+#endif
+ }
+}
+
+#if defined __SSE4_1__ || defined __ARM_NEON
+// Non-reference implementation, but faster. Produces same results as the AVX2 version
+static etcpak_force_inline void FindBestFit( uint32_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint32_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m128i pixel = _mm_set1_epi16(dr * 38 + dg * 76 + db * 14);
+ __m128i pix = _mm_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m128i error0 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[0]));
+ __m128i error1 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[1]));
+
+ __m128i index = _mm_and_si128(_mm_cmplt_epi16(error1, error0), _mm_set1_epi16(1));
+ __m128i minError = _mm_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is needed to produce same results as AVX2 implementation
+ __m128i indexBit = _mm_andnot_si128(_mm_srli_epi16(pixel, 15), _mm_set1_epi8(-1));
+ __m128i minIndex = _mm_or_si128(index, _mm_add_epi16(indexBit, indexBit));
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i squareErrorLo = _mm_mullo_epi16(minError, minError);
+ __m128i squareErrorHi = _mm_mulhi_epi16(minError, minError);
+
+ __m128i squareErrorLow = _mm_unpacklo_epi16(squareErrorLo, squareErrorHi);
+ __m128i squareErrorHigh = _mm_unpackhi_epi16(squareErrorLo, squareErrorHi);
+
+ squareErrorLow = _mm_add_epi32(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ squareErrorHigh = _mm_add_epi32(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int16x8_t pixel = vdupq_n_s16( dr * 38 + dg * 76 + db * 14 );
+ int16x8_t pix = vabsq_s16( pixel );
+
+ int16x8_t error0 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[0] ) );
+ int16x8_t error1 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[1] ) );
+
+ int16x8_t index = vandq_s16( vreinterpretq_s16_u16( vcltq_s16( error1, error0 ) ), vdupq_n_s16( 1 ) );
+ int16x8_t minError = vminq_s16( error0, error1 );
+
+ int16x8_t indexBit = vandq_s16( vmvnq_s16( vshrq_n_s16( pixel, 15 ) ), vdupq_n_s16( -1 ) );
+ int16x8_t minIndex = vorrq_s16( index, vaddq_s16( indexBit, indexBit ) );
+
+ int16x4_t minErrorLow = vget_low_s16( minError );
+ int16x4_t minErrorHigh = vget_high_s16( minError );
+
+ int32x4_t squareErrorLow = vmull_s16( minErrorLow, minErrorLow );
+ int32x4_t squareErrorHigh = vmull_s16( minErrorHigh, minErrorHigh );
+
+ int32x4_t squareErrorSumLow = vaddq_s32( squareErrorLow, vld1q_s32( (int32_t*)ter ) );
+ int32x4_t squareErrorSumHigh = vaddq_s32( squareErrorHigh, vld1q_s32( (int32_t*)ter + 4 ) );
+
+ vst1q_s32( (int32_t*)ter, squareErrorSumLow );
+ vst1q_s32( (int32_t*)ter + 4, squareErrorSumHigh );
+
+ vst1q_s16( (int16_t*)sel, minIndex );
+#endif
+ }
+}
+#endif
+
+static etcpak_force_inline uint8_t convert6(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 11 - ((i + 11) >> 7) - ((i + 4) >> 7)) >> 3;
+}
+
+static etcpak_force_inline uint8_t convert7(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2;
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar(const uint8_t* src)
+{
+ int32_t r = 0;
+ int32_t g = 0;
+ int32_t b = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ b += src[i * 4 + 0];
+ g += src[i * 4 + 1];
+ r += src[i * 4 + 2];
+ }
+
+ int32_t difRyz = 0;
+ int32_t difGyz = 0;
+ int32_t difByz = 0;
+ int32_t difRxz = 0;
+ int32_t difGxz = 0;
+ int32_t difBxz = 0;
+
+ const int32_t scaling[] = { -255, -85, 85, 255 };
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t difB = (static_cast<int>(src[i * 4 + 0]) << 4) - b;
+ int32_t difG = (static_cast<int>(src[i * 4 + 1]) << 4) - g;
+ int32_t difR = (static_cast<int>(src[i * 4 + 2]) << 4) - r;
+
+ difRyz += difR * scaling[i % 4];
+ difGyz += difG * scaling[i % 4];
+ difByz += difB * scaling[i % 4];
+
+ difRxz += difR * scaling[i / 4];
+ difGxz += difG * scaling[i / 4];
+ difBxz += difB * scaling[i / 4];
+ }
+
+ const float scale = -4.0f / ((255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f);
+
+ float aR = difRxz * scale;
+ float aG = difGxz * scale;
+ float aB = difBxz * scale;
+
+ float bR = difRyz * scale;
+ float bG = difGyz * scale;
+ float bB = difByz * scale;
+
+ float dR = r * (4.0f / 16.0f);
+ float dG = g * (4.0f / 16.0f);
+ float dB = b * (4.0f / 16.0f);
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ float cofR = std::fma(aR, 255.0f, std::fma(bR, 255.0f, dR));
+ float cofG = std::fma(aG, 255.0f, std::fma(bG, 255.0f, dG));
+ float cofB = std::fma(aB, 255.0f, std::fma(bB, 255.0f, dB));
+ float chfR = std::fma(aR, -425.0f, std::fma(bR, 255.0f, dR));
+ float chfG = std::fma(aG, -425.0f, std::fma(bG, 255.0f, dG));
+ float chfB = std::fma(aB, -425.0f, std::fma(bB, 255.0f, dB));
+ float cvfR = std::fma(aR, 255.0f, std::fma(bR, -425.0f, dR));
+ float cvfG = std::fma(aG, 255.0f, std::fma(bG, -425.0f, dG));
+ float cvfB = std::fma(aB, 255.0f, std::fma(bB, -425.0f, dB));
+
+ // convert to r6g7b6
+ int32_t coR = convert6(cofR);
+ int32_t coG = convert7(cofG);
+ int32_t coB = convert6(cofB);
+ int32_t chR = convert6(chfR);
+ int32_t chG = convert7(chfG);
+ int32_t chB = convert6(chfB);
+ int32_t cvR = convert6(cvfR);
+ int32_t cvG = convert7(cvfG);
+ int32_t cvB = convert6(cvfB);
+
+ // Error calculation
+ auto ro0 = coR;
+ auto go0 = coG;
+ auto bo0 = coB;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ auto rh0 = chR;
+ auto gh0 = chG;
+ auto bh0 = chB;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ auto rv0 = cvR;
+ auto gv0 = cvG;
+ auto bv0 = cvB;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ uint64_t error = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t cR = clampu8((rh2 * (i / 4) + rv2 * (i % 4) + ro2) >> 2);
+ int32_t cG = clampu8((gh2 * (i / 4) + gv2 * (i % 4) + go2) >> 2);
+ int32_t cB = clampu8((bh2 * (i / 4) + bv2 * (i % 4) + bo2) >> 2);
+
+ int32_t difB = static_cast<int>(src[i * 4 + 0]) - cB;
+ int32_t difG = static_cast<int>(src[i * 4 + 1]) - cG;
+ int32_t difR = static_cast<int>(src[i * 4 + 2]) - cR;
+
+ int32_t dif = difR * 38 + difG * 76 + difB * 14;
+
+ error += dif * dif;
+ }
+
+ /**/
+ uint32_t rgbv = cvB | (cvG << 6) | (cvR << 13);
+ uint32_t rgbh = chB | (chG << 6) | (chR << 13);
+ uint32_t hi = rgbv | ((rgbh & 0x1FFF) << 19);
+ uint32_t lo = (chR & 0x1) | 0x2 | ((chR << 1) & 0x7C);
+ lo |= ((coB & 0x07) << 7) | ((coB & 0x18) << 8) | ((coB & 0x20) << 11);
+ lo |= ((coG & 0x3F) << 17) | ((coG & 0x40) << 18);
+ lo |= coR << 25;
+
+ const auto idx = (coR & 0x20) | ((coG & 0x20) >> 1) | ((coB & 0x1E) >> 1);
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ return std::make_pair(result, error);
+}
+
+#ifdef __ARM_NEON
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifXZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int32x4_t dif0 = vmull_n_s16( vget_low_s16( dif_lo ), -255 );
+ int32x4_t dif1 = vmull_n_s16( vget_high_s16( dif_lo ), -85 );
+ int32x4_t dif2 = vmull_n_s16( vget_low_s16( dif_hi ), 85 );
+ int32x4_t dif3 = vmull_n_s16( vget_high_s16( dif_hi ), 255 );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifYZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int16x4_t scaling = { -255, -85, 85, 255 };
+ int32x4_t dif0 = vmull_s16( vget_low_s16( dif_lo ), scaling );
+ int32x4_t dif1 = vmull_s16( vget_high_s16( dif_lo ), scaling );
+ int32x4_t dif2 = vmull_s16( vget_low_s16( dif_hi ), scaling );
+ int32x4_t dif3 = vmull_s16( vget_high_s16( dif_hi ), scaling );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t Planar_NEON_SumWide( uint8x16_t src )
+{
+ uint16x8_t accu8 = vpaddlq_u8( src );
+#ifndef __aarch64__
+ uint16x4_t accu4 = vpadd_u16( vget_low_u16( accu8 ), vget_high_u16( accu8 ) );
+ uint16x4_t accu2 = vpadd_u16( accu4, accu4 );
+ uint16x4_t accu1 = vpadd_u16( accu2, accu2 );
+ return vreinterpretq_s16_u16( vcombine_u16( accu1, accu1 ) );
+#else
+ return vdupq_n_s16( vaddvq_u16( accu8 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t convert6_NEON( int32x4_t lo, int32x4_t hi )
+{
+ uint16x8_t x = vcombine_u16( vqmovun_s32( lo ), vqmovun_s32( hi ) );
+ int16x8_t i = vreinterpretq_s16_u16( vshrq_n_u16( vqshlq_n_u16( x, 6 ), 6) ); // clamp 0-1023
+ i = vhsubq_s16( i, vdupq_n_s16( 15 ) );
+
+ int16x8_t ip11 = vaddq_s16( i, vdupq_n_s16( 11 ) );
+ int16x8_t ip4 = vaddq_s16( i, vdupq_n_s16( 4 ) );
+
+ return vshrq_n_s16( vsubq_s16( vsubq_s16( ip11, vshrq_n_s16( ip11, 7 ) ), vshrq_n_s16( ip4, 7) ), 3 );
+}
+
+static etcpak_force_inline int16x4_t convert7_NEON( int32x4_t x )
+{
+ int16x4_t i = vreinterpret_s16_u16( vshr_n_u16( vqshl_n_u16( vqmovun_s32( x ), 6 ), 6 ) ); // clamp 0-1023
+ i = vhsub_s16( i, vdup_n_s16( 15 ) );
+
+ int16x4_t p9 = vadd_s16( i, vdup_n_s16( 9 ) );
+ int16x4_t p6 = vadd_s16( i, vdup_n_s16( 6 ) );
+ return vshr_n_s16( vsub_s16( vsub_s16( p9, vshr_n_s16( p9, 8 ) ), vshr_n_s16( p6, 8 ) ), 2 );
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src )
+{
+ uint8x16x4_t srcBlock = vld4q_u8( src );
+
+ int16x8_t bSumWide = Planar_NEON_SumWide( srcBlock.val[0] );
+ int16x8_t gSumWide = Planar_NEON_SumWide( srcBlock.val[1] );
+ int16x8_t rSumWide = Planar_NEON_SumWide( srcBlock.val[2] );
+
+ int16x8_t dif_R_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[2] ), 4) ), rSumWide );
+ int16x8_t dif_R_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[2] ), 4) ), rSumWide );
+
+ int16x8_t dif_G_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+ int16x8_t dif_G_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+
+ int16x8_t dif_B_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[0] ), 4) ), bSumWide );
+ int16x8_t dif_B_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[0] ), 4) ), bSumWide );
+
+ int32x2x2_t dif_xz_z = vzip_s32( vzip_s32( Planar_NEON_DifXZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifXZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifXZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_xz = vcombine_s32( dif_xz_z.val[0], dif_xz_z.val[1] );
+ int32x2x2_t dif_yz_z = vzip_s32( vzip_s32( Planar_NEON_DifYZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifYZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifYZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_yz = vcombine_s32( dif_yz_z.val[0], dif_yz_z.val[1] );
+
+ const float fscale = -4.0f / ( (255 * 255 * 8.0f + 85 * 85 * 8.0f ) * 16.0f );
+ float32x4_t fa = vmulq_n_f32( vcvtq_f32_s32( dif_xz ), fscale );
+ float32x4_t fb = vmulq_n_f32( vcvtq_f32_s32( dif_yz ), fscale );
+ int16x4_t bgrgSum = vzip_s16( vzip_s16( vget_low_s16( bSumWide ), vget_low_s16( rSumWide ) ).val[0], vget_low_s16( gSumWide ) ).val[0];
+ float32x4_t fd = vmulq_n_f32( vcvtq_f32_s32( vmovl_s16( bgrgSum ) ), 4.0f / 16.0f);
+
+ float32x4_t cof = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, 255.0f );
+ float32x4_t chf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, -425.0f );
+ float32x4_t cvf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, -425.0f ), fa, 255.0f );
+
+ int32x4_t coi = vcvtq_s32_f32( cof );
+ int32x4_t chi = vcvtq_s32_f32( chf );
+ int32x4_t cvi = vcvtq_s32_f32( cvf );
+
+ int32x4x2_t tr_hv = vtrnq_s32( chi, cvi );
+ int32x4x2_t tr_o = vtrnq_s32( coi, coi );
+
+ int16x8_t c_hvoo_br_6 = convert6_NEON( tr_hv.val[0], tr_o.val[0] );
+ int16x4_t c_hvox_g_7 = convert7_NEON( vcombine_s32( vget_low_s32( tr_hv.val[1] ), vget_low_s32( tr_o.val[1] ) ) );
+ int16x8_t c_hvoo_br_8 = vorrq_s16( vshrq_n_s16( c_hvoo_br_6, 4 ), vshlq_n_s16( c_hvoo_br_6, 2 ) );
+ int16x4_t c_hvox_g_8 = vorr_s16( vshr_n_s16( c_hvox_g_7, 6 ), vshl_n_s16( c_hvox_g_7, 1 ) );
+
+ int16x4_t rec_gxbr_o = vext_s16( c_hvox_g_8, vget_high_s16( c_hvoo_br_8 ), 3 );
+
+ rec_gxbr_o = vadd_s16( vshl_n_s16( rec_gxbr_o, 2 ), vdup_n_s16( 2 ) );
+ int16x8_t rec_ro_wide = vdupq_lane_s16( rec_gxbr_o, 3 );
+ int16x8_t rec_go_wide = vdupq_lane_s16( rec_gxbr_o, 0 );
+ int16x8_t rec_bo_wide = vdupq_lane_s16( rec_gxbr_o, 1 );
+
+ int16x4_t br_hv2 = vsub_s16( vget_low_s16( c_hvoo_br_8 ), vget_high_s16( c_hvoo_br_8 ) );
+ int16x4_t gg_hv2 = vsub_s16( c_hvox_g_8, vdup_lane_s16( c_hvox_g_8, 2 ) );
+
+ int16x8_t scaleh_lo = { 0, 0, 0, 0, 1, 1, 1, 1 };
+ int16x8_t scaleh_hi = { 2, 2, 2, 2, 3, 3, 3, 3 };
+ int16x8_t scalev = { 0, 1, 2, 3, 0, 1, 2, 3 };
+
+ int16x8_t rec_r_1 = vmlaq_lane_s16( rec_ro_wide, scalev, br_hv2, 3 );
+ int16x8_t rec_r_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_lo, br_hv2, 2 ), 2 ) ) );
+ int16x8_t rec_r_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_hi, br_hv2, 2 ), 2 ) ) );
+
+ int16x8_t rec_b_1 = vmlaq_lane_s16( rec_bo_wide, scalev, br_hv2, 1 );
+ int16x8_t rec_b_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_lo, br_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_b_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_hi, br_hv2, 0 ), 2 ) ) );
+
+ int16x8_t rec_g_1 = vmlaq_lane_s16( rec_go_wide, scalev, gg_hv2, 1 );
+ int16x8_t rec_g_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_lo, gg_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_g_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_hi, gg_hv2, 0 ), 2 ) ) );
+
+ int16x8_t dif_r_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[2] ) ) ), rec_r_lo );
+ int16x8_t dif_r_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[2] ) ) ), rec_r_hi );
+
+ int16x8_t dif_g_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[1] ) ) ), rec_g_lo );
+ int16x8_t dif_g_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[1] ) ) ), rec_g_hi );
+
+ int16x8_t dif_b_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[0] ) ) ), rec_b_lo );
+ int16x8_t dif_b_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[0] ) ) ), rec_b_hi );
+
+ int16x8_t dif_lo = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_lo, 38 ), dif_g_lo, 76 ), dif_b_lo, 14 );
+ int16x8_t dif_hi = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_hi, 38 ), dif_g_hi, 76 ), dif_b_hi, 14 );
+
+ int16x4_t tmpDif = vget_low_s16( dif_lo );
+ int32x4_t difsq_0 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_lo );
+ int32x4_t difsq_1 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_low_s16( dif_hi );
+ int32x4_t difsq_2 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_hi );
+ int32x4_t difsq_3 = vmull_s16( tmpDif, tmpDif );
+
+ uint32x4_t difsq_5 = vaddq_u32( vreinterpretq_u32_s32( difsq_0 ), vreinterpretq_u32_s32( difsq_1 ) );
+ uint32x4_t difsq_6 = vaddq_u32( vreinterpretq_u32_s32( difsq_2 ), vreinterpretq_u32_s32( difsq_3) );
+
+ uint64x2_t difsq_7 = vaddl_u32( vget_low_u32( difsq_5 ), vget_high_u32( difsq_5 ) );
+ uint64x2_t difsq_8 = vaddl_u32( vget_low_u32( difsq_6 ), vget_high_u32( difsq_6 ) );
+
+ uint64x2_t difsq_9 = vaddq_u64( difsq_7, difsq_8 );
+
+#ifdef __aarch64__
+ uint64_t error = vaddvq_u64( difsq_9 );
+#else
+ uint64_t error = vgetq_lane_u64( difsq_9, 0 ) + vgetq_lane_u64( difsq_9, 1 );
+#endif
+
+ int32_t coR = c_hvoo_br_6[6];
+ int32_t coG = c_hvox_g_7[2];
+ int32_t coB = c_hvoo_br_6[4];
+
+ int32_t chR = c_hvoo_br_6[2];
+ int32_t chG = c_hvox_g_7[0];
+ int32_t chB = c_hvoo_br_6[0];
+
+ int32_t cvR = c_hvoo_br_6[3];
+ int32_t cvG = c_hvox_g_7[1];
+ int32_t cvB = c_hvoo_br_6[1];
+
+ uint32_t rgbv = cvB | ( cvG << 6 ) | ( cvR << 13 );
+ uint32_t rgbh = chB | ( chG << 6 ) | ( chR << 13 );
+ uint32_t hi = rgbv | ( ( rgbh & 0x1FFF ) << 19 );
+ uint32_t lo = ( chR & 0x1 ) | 0x2 | ( ( chR << 1 ) & 0x7C );
+ lo |= ( ( coB & 0x07 ) << 7 ) | ( ( coB & 0x18 ) << 8 ) | ( ( coB & 0x20 ) << 11 );
+ lo |= ( ( coG & 0x3F) << 17) | ( (coG & 0x40 ) << 18 );
+ lo |= coR << 25;
+
+ const auto idx = ( coR & 0x20 ) | ( ( coG & 0x20 ) >> 1 ) | ( ( coB & 0x1E ) >> 1 );
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>( _bswap(lo) );
+ result |= static_cast<uint64_t>( static_cast<uint32_t>( _bswap( hi ) ) ) << 32;
+
+ return std::make_pair( result, error );
+}
+
+#endif
+
+template<class T, class S>
+static etcpak_force_inline uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id, const uint64_t value, const uint64_t error)
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return FixByteOrder(d);
+}
+
+}
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, src );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ uint32_t idx = _bit_scan_forward(mask) >> 2;
+
+ d |= EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1 );
+#else
+ uint64_t d = CheckSolid( src );
+ if( d != 0 ) return d;
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return FixByteOrder( EncodeSelectors( d, terr, tsel, id ) );
+#endif
+}
+
+static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ auto plane = Planar_AVX2( src );
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, plane.sum4 );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ size_t idx = _bit_scan_forward(mask) >> 2;
+
+ d = EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1, plane.plane, plane.error );
+#else
+ uint64_t d = CheckSolid( src );
+ if (d != 0) return d;
+
+#ifdef __ARM_NEON
+ auto result = Planar_NEON( src );
+#else
+ auto result = Planar( src );
+#endif
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return EncodeSelectors( d, terr, tsel, id, result.first, result.second );
+#endif
+}
+
+#ifdef __SSE4_1__
+template<int K>
+static etcpak_force_inline __m128i Widen( const __m128i src )
+{
+ static_assert( K >= 0 && K <= 7, "Index out of range" );
+
+ __m128i tmp;
+ switch( K )
+ {
+ case 0:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 1:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 2:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 3:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 4:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 5:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 6:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 7:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ }
+}
+
+static etcpak_force_inline int GetMulSel( int sel )
+{
+ switch( sel )
+ {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ case 6:
+ case 7:
+ return 3;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ return 4;
+ case 14:
+ case 15:
+ return 5;
+ }
+}
+
+#endif
+
+#ifdef __ARM_NEON
+
+static constexpr etcpak_force_inline int GetMulSel(int sel)
+{
+ return ( sel < 1 ) ? 0 : ( sel < 4 ) ? 1 : ( sel < 5 ) ? 2 : ( sel < 8 ) ? 3 : ( sel < 14 ) ? 4 : 5;
+}
+
+static constexpr int ClampConstant( int x, int min, int max )
+{
+ return x < min ? min : x > max ? max : x;
+}
+
+template <int Index>
+etcpak_force_inline static uint16x8_t ErrorProbe_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint8x8_t srcValWide;
+#ifndef __aarch64__
+ if( Index < 8 )
+ srcValWide = vdup_lane_u8( vget_low_u8( alphaBlock ), ClampConstant( Index, 0, 8 ) );
+ else
+ srcValWide = vdup_lane_u8( vget_high_u8( alphaBlock ), ClampConstant( Index - 8, 0, 8 ) );
+#else
+ srcValWide = vdup_laneq_u8( alphaBlock, Index );
+#endif
+
+ uint8x8_t deltaVal = vabd_u8( srcValWide, recVal );
+ return vmull_u8( deltaVal, deltaVal );
+}
+
+etcpak_force_inline static uint16_t MinError_EAC_NEON( uint16x8_t errProbe )
+{
+#ifndef __aarch64__
+ uint16x4_t tmpErr = vpmin_u16( vget_low_u16( errProbe ), vget_high_u16( errProbe ) );
+ tmpErr = vpmin_u16( tmpErr, tmpErr );
+ return vpmin_u16( tmpErr, tmpErr )[0];
+#else
+ return vminvq_u16( errProbe );
+#endif
+}
+
+template <int Index>
+etcpak_force_inline static uint64_t MinErrorIndex_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint16x8_t errProbe = ErrorProbe_EAC_NEON<Index>( recVal, alphaBlock );
+ uint16x8_t minErrMask = vceqq_u16( errProbe, vdupq_n_u16( MinError_EAC_NEON( errProbe ) ) );
+ uint64_t idx = __builtin_ctzll( vget_lane_u64( vreinterpret_u64_u8( vqmovn_u16( minErrMask ) ), 0 ) );
+ idx >>= 3;
+ idx <<= 45 - Index * 3;
+
+ return idx;
+}
+
+template <int Index>
+etcpak_force_inline static int16x8_t WidenMultiplier_EAC_NEON( int16x8_t multipliers )
+{
+ constexpr int Lane = GetMulSel( Index );
+#ifndef __aarch64__
+ if( Lane < 4 )
+ return vdupq_lane_s16( vget_low_s16( multipliers ), ClampConstant( Lane, 0, 4 ) );
+ else
+ return vdupq_lane_s16( vget_high_s16( multipliers ), ClampConstant( Lane - 4, 0, 4 ) );
+#else
+ return vdupq_laneq_s16( multipliers, Lane );
+#endif
+}
+
+#endif
+
+static etcpak_force_inline uint64_t ProcessAlpha_ETC2( const uint8_t* src )
+{
+#if defined __SSE4_1__
+ // Check solid
+ __m128i s = _mm_loadu_si128( (__m128i*)src );
+ __m128i solidCmp = _mm_set1_epi8( src[0] );
+ __m128i cmpRes = _mm_cmpeq_epi8( s, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return src[0];
+ }
+
+ // Calculate min, max
+ __m128i s1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( s, s1 );
+ __m128i min1 = _mm_min_epu8( s, s1 );
+ __m128i smax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i smin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, smax2 );
+ __m128i min2 = _mm_min_epu8( min1, smin2 );
+ __m128i smax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i smin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, smax3 );
+ __m128i min3 = _mm_min_epu8( min2, smin3 );
+ __m128i smax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i smin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, smax4 );
+ __m128i min = _mm_min_epu8( min3, smin4 );
+ __m128i max16 = _mm_unpacklo_epi8( max, _mm_setzero_si128() );
+ __m128i min16 = _mm_unpacklo_epi8( min, _mm_setzero_si128() );
+
+ // src range, mid
+ __m128i srcRange = _mm_sub_epi16( max16, min16 );
+ __m128i srcRangeHalf = _mm_srli_epi16( srcRange, 1 );
+ __m128i srcMid = _mm_add_epi16( min16, srcRangeHalf );
+
+ // multiplier
+ __m128i mul1 = _mm_mulhi_epi16( srcRange, g_alphaRange_SIMD );
+ __m128i mul = _mm_add_epi16( mul1, _mm_set1_epi16( 1 ) );
+
+ // wide source
+ __m128i s16_1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 3, 2, 3, 2 ) );
+ __m128i s16[2] = { _mm_unpacklo_epi8( s, _mm_setzero_si128() ), _mm_unpacklo_epi8( s16_1, _mm_setzero_si128() ) };
+
+ __m128i sr[16] = {
+ Widen<0>( s16[0] ),
+ Widen<1>( s16[0] ),
+ Widen<2>( s16[0] ),
+ Widen<3>( s16[0] ),
+ Widen<4>( s16[0] ),
+ Widen<5>( s16[0] ),
+ Widen<6>( s16[0] ),
+ Widen<7>( s16[0] ),
+ Widen<0>( s16[1] ),
+ Widen<1>( s16[1] ),
+ Widen<2>( s16[1] ),
+ Widen<3>( s16[1] ),
+ Widen<4>( s16[1] ),
+ Widen<5>( s16[1] ),
+ Widen<6>( s16[1] ),
+ Widen<7>( s16[1] )
+ };
+
+#ifdef __AVX2__
+ __m256i srcRangeWide = _mm256_broadcastsi128_si256( srcRange );
+ __m256i srcMidWide = _mm256_broadcastsi128_si256( srcMid );
+
+ __m256i mulWide1 = _mm256_mulhi_epi16( srcRangeWide, g_alphaRange_AVX );
+ __m256i mulWide = _mm256_add_epi16( mulWide1, _mm256_set1_epi16( 1 ) );
+
+ __m256i modMul[8] = {
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ) ), _mm256_setzero_si256() ),
+ };
+
+ // find selector
+ __m256i mulErr = _mm256_setzero_si256();
+ for( int j=0; j<16; j++ )
+ {
+ __m256i s16Wide = _mm256_broadcastsi128_si256( sr[j] );
+ __m256i err1, err2;
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[0] );
+ __m256i localErr = _mm256_mullo_epi16( err1, err1 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[1] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[2] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[3] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[4] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[5] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[6] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[7] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ // note that this can overflow, but since we're looking for the smallest error, it shouldn't matter
+ mulErr = _mm256_adds_epu16( mulErr, localErr );
+ }
+ uint64_t minPos1 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_castsi256_si128( mulErr ) ) );
+ uint64_t minPos2 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_extracti128_si256( mulErr, 1 ) ) );
+ int sel = ( ( minPos1 & 0xFFFF ) < ( minPos2 & 0xFFFF ) ) ? ( minPos1 >> 16 ) : ( 8 + ( minPos2 >> 16 ) );
+
+ __m128i recVal16;
+ switch( sel )
+ {
+ case 0:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() );
+ break;
+ case 1:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() );
+ break;
+ case 2:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() );
+ break;
+ case 3:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() );
+ break;
+ case 4:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() );
+ break;
+ case 5:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() );
+ break;
+ case 6:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() );
+ break;
+ case 7:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() );
+ break;
+ case 8:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() );
+ break;
+ case 9:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() );
+ break;
+ case 10:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() );
+ break;
+ case 11:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() );
+ break;
+ case 12:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() );
+ break;
+ case 13:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() );
+ break;
+ case 14:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() );
+ break;
+ case 15:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() );
+ break;
+ default:
+ assert( false );
+ break;
+ }
+#else
+ // wide multiplier
+ __m128i rangeMul[16] = {
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() )
+ };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ for( int r=0; r<16; r++ )
+ {
+ __m128i err1, err2, minerr;
+ __m128i recVal16 = rangeMul[r];
+ int rangeErr;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr = _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if( err == 0 ) break;
+ }
+ }
+
+ __m128i recVal16 = rangeMul[sel];
+#endif
+
+ // find indices
+ __m128i err1, err2, minerr;
+ uint64_t idx = 0, tmp;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 15*3;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 14*3;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 13*3;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 12*3;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 11*3;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 10*3;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 9*3;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 8*3;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 7*3;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 6*3;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 5*3;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 4*3;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 3*3;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 2*3;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 1*3;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 0*3;
+
+ uint16_t rm[8];
+ _mm_storeu_si128( (__m128i*)rm, mul );
+ uint16_t sm = _mm_cvtsi128_si64( srcMid );
+
+ uint64_t d = ( uint64_t( sm ) << 56 ) |
+ ( uint64_t( rm[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48 ) |
+ idx;
+
+ return _bswap64( d );
+#elif defined __ARM_NEON
+
+ int16x8_t srcMidWide, multipliers;
+ int srcMid;
+ uint8x16_t srcAlphaBlock = vld1q_u8( src );
+ {
+ uint8_t ref = src[0];
+ uint8x16_t a0 = vdupq_n_u8( ref );
+ uint8x16_t r = vceqq_u8( srcAlphaBlock, a0 );
+ int64x2_t m = vreinterpretq_s64_u8( r );
+ if( m[0] == -1 && m[1] == -1 )
+ return ref;
+
+ // srcRange
+#ifdef __aarch64__
+ uint8_t min = vminvq_u8( srcAlphaBlock );
+ uint8_t max = vmaxvq_u8( srcAlphaBlock );
+ uint8_t srcRange = max - min;
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_n_s16( g_alphaRange_NEON, srcRange ), 1 ), vdupq_n_s16( 1 ) );
+ srcMid = min + srcRange / 2;
+ srcMidWide = vdupq_n_s16( srcMid );
+#else
+ uint8x8_t vmin = vpmin_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ uint8x8_t vmax = vpmax_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+
+ int16x8_t srcRangeWide = vreinterpretq_s16_u16( vsubl_u8( vmax, vmin ) );
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_s16( g_alphaRange_NEON, srcRangeWide ), 1 ), vdupq_n_s16( 1 ) );
+ srcMidWide = vsraq_n_s16( vreinterpretq_s16_u16(vmovl_u8(vmin)), srcRangeWide, 1);
+ srcMid = vgetq_lane_s16( srcMidWide, 0 );
+#endif
+ }
+
+ // calculate reconstructed values
+#define EAC_APPLY_16X( m ) m( 0 ) m( 1 ) m( 2 ) m( 3 ) m( 4 ) m( 5 ) m( 6 ) m( 7 ) m( 8 ) m( 9 ) m( 10 ) m( 11 ) m( 12 ) m( 13 ) m( 14 ) m( 15 )
+
+#define EAC_RECONSTRUCT_VALUE( n ) vqmovun_s16( vmlaq_s16( srcMidWide, g_alpha_NEON[n], WidenMultiplier_EAC_NEON<n>( multipliers ) ) ),
+ uint8x8_t recVals[16] = { EAC_APPLY_16X( EAC_RECONSTRUCT_VALUE ) };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel = 0;
+ for( int r = 0; r < 16; r++ )
+ {
+ uint8x8_t recVal = recVals[r];
+
+ int rangeErr = 0;
+#define EAC_ACCUMULATE_ERROR( n ) rangeErr += MinError_EAC_NEON( ErrorProbe_EAC_NEON<n>( recVal, srcAlphaBlock ) );
+ EAC_APPLY_16X( EAC_ACCUMULATE_ERROR )
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if ( err == 0 ) break;
+ }
+ }
+
+ // combine results
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( multipliers[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48);
+
+ // generate indices
+ uint8x8_t recVal = recVals[sel];
+#define EAC_INSERT_INDEX(n) d |= MinErrorIndex_EAC_NEON<n>( recVal, srcAlphaBlock );
+ EAC_APPLY_16X( EAC_INSERT_INDEX )
+
+ return _bswap64( d );
+
+#undef EAC_APPLY_16X
+#undef EAC_INSERT_INDEX
+#undef EAC_ACCUMULATE_ERROR
+#undef EAC_RECONSTRUCT_VALUE
+
+#else
+ {
+ bool solid = true;
+ const uint8_t* ptr = src + 1;
+ const uint8_t ref = *src;
+ for( int i=1; i<16; i++ )
+ {
+ if( ref != *ptr++ )
+ {
+ solid = false;
+ break;
+ }
+ }
+ if( solid )
+ {
+ return ref;
+ }
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = src[0];
+ for( int i=1; i<16; i++ )
+ {
+ if( min > src[i] ) min = src[i];
+ else if( max < src[i] ) max = src[i];
+ }
+ int srcRange = max - min;
+ int srcMid = min + srcRange / 2;
+
+ uint8_t buf[16][16];
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ int selmul;
+ for( int r=0; r<16; r++ )
+ {
+ int mul = ( ( srcRange * g_alphaRange[r] ) >> 16 ) + 1;
+
+ int rangeErr = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const auto srcVal = src[i];
+
+ int idx = 0;
+ const auto modVal = g_alpha[r][0] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ int localErr = sq( srcVal - recVal );
+
+ if( localErr != 0 )
+ {
+ for( int j=1; j<8; j++ )
+ {
+ const auto modVal = g_alpha[r][j] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ const auto errProbe = sq( srcVal - recVal );
+ if( errProbe < localErr )
+ {
+ localErr = errProbe;
+ idx = j;
+ }
+ }
+ }
+
+ buf[r][i] = idx;
+ rangeErr += localErr;
+ }
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ selmul = mul;
+ if( err == 0 ) break;
+ }
+ }
+
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( selmul ) << 52 ) |
+ ( uint64_t( sel ) << 48 );
+
+ int offset = 45;
+ auto ptr = buf[sel];
+ for( int i=0; i<16; i++ )
+ {
+ d |= uint64_t( *ptr++ ) << offset;
+ offset -= 3;
+ }
+
+ return _bswap64( d );
+#endif
+}
+
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+#include <chrono>
+#include <thread>
+
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+# ifdef __AVX2__
+ DitherAvx2( (uint8_t*)buf, _mm_castps_si128( px0 ), _mm_castps_si128( px1 ), _mm_castps_si128( px2 ), _mm_castps_si128( px3 ) );
+# else
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ Dither( (uint8_t*)buf );
+# endif
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ _mm_store_si128( (__m128i*)(rgba + 0), c0 );
+ _mm_store_si128( (__m128i*)(rgba + 4), c1 );
+ _mm_store_si128( (__m128i*)(rgba + 8), c2 );
+ _mm_store_si128( (__m128i*)(rgba + 12), c3 );
+
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i a0 = _mm_shuffle_epi8( c0, mask );
+ __m128i a1 = _mm_shuffle_epi8( c1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i a2 = _mm_shuffle_epi8( c2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i a3 = _mm_shuffle_epi8( c3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+
+ __m128i s0 = _mm_or_si128( a0, a1 );
+ __m128i s1 = _mm_or_si128( a2, a3 );
+ __m128i s2 = _mm_or_si128( s0, s1 );
+
+ _mm_store_si128( (__m128i*)alpha, s2 );
+
+ src += 4;
+#else
+ auto ptr = rgba;
+ auto ptr8 = alpha;
+ for( int x=0; x<4; x++ )
+ {
+ auto v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessAlpha_ETC2( alpha );
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)rgba );
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessRGB.hpp b/thirdparty/etcpak/ProcessRGB.hpp
new file mode 100644
index 0000000000..c5555a5bb1
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.hpp
@@ -0,0 +1,13 @@
+#ifndef __PROCESSRGB_HPP__
+#define __PROCESSRGB_HPP__
+
+#include <stdint.h>
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/Tables.cpp b/thirdparty/etcpak/Tables.cpp
new file mode 100644
index 0000000000..5c7fd9cf61
--- /dev/null
+++ b/thirdparty/etcpak/Tables.cpp
@@ -0,0 +1,221 @@
+#include "Tables.hpp"
+
+const int32_t g_table[8][4] = {
+ { 2, 8, -2, -8 },
+ { 5, 17, -5, -17 },
+ { 9, 29, -9, -29 },
+ { 13, 42, -13, -42 },
+ { 18, 60, -18, -60 },
+ { 24, 80, -24, -80 },
+ { 33, 106, -33, -106 },
+ { 47, 183, -47, -183 }
+};
+
+const int64_t g_table256[8][4] = {
+ { 2*256, 8*256, -2*256, -8*256 },
+ { 5*256, 17*256, -5*256, -17*256 },
+ { 9*256, 29*256, -9*256, -29*256 },
+ { 13*256, 42*256, -13*256, -42*256 },
+ { 18*256, 60*256, -18*256, -60*256 },
+ { 24*256, 80*256, -24*256, -80*256 },
+ { 33*256, 106*256, -33*256, -106*256 },
+ { 47*256, 183*256, -47*256, -183*256 }
+};
+
+const uint32_t g_id[4][16] = {
+ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 },
+ { 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 }
+};
+
+const uint32_t g_avg2[16] = {
+ 0x00,
+ 0x11,
+ 0x22,
+ 0x33,
+ 0x44,
+ 0x55,
+ 0x66,
+ 0x77,
+ 0x88,
+ 0x99,
+ 0xAA,
+ 0xBB,
+ 0xCC,
+ 0xDD,
+ 0xEE,
+ 0xFF
+};
+
+const uint32_t g_flags[64] = {
+ 0x80800402, 0x80800402, 0x80800402, 0x80800402,
+ 0x80800402, 0x80800402, 0x80800402, 0x8080E002,
+ 0x80800402, 0x80800402, 0x8080E002, 0x8080E002,
+ 0x80800402, 0x8080E002, 0x8080E002, 0x8080E002,
+ 0x80000402, 0x80000402, 0x80000402, 0x80000402,
+ 0x80000402, 0x80000402, 0x80000402, 0x8000E002,
+ 0x80000402, 0x80000402, 0x8000E002, 0x8000E002,
+ 0x80000402, 0x8000E002, 0x8000E002, 0x8000E002,
+ 0x00800402, 0x00800402, 0x00800402, 0x00800402,
+ 0x00800402, 0x00800402, 0x00800402, 0x0080E002,
+ 0x00800402, 0x00800402, 0x0080E002, 0x0080E002,
+ 0x00800402, 0x0080E002, 0x0080E002, 0x0080E002,
+ 0x00000402, 0x00000402, 0x00000402, 0x00000402,
+ 0x00000402, 0x00000402, 0x00000402, 0x0000E002,
+ 0x00000402, 0x00000402, 0x0000E002, 0x0000E002,
+ 0x00000402, 0x0000E002, 0x0000E002, 0x0000E002
+};
+
+const int32_t g_alpha[16][8] = {
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int32_t g_alphaRange[16] = {
+ 0x100FF / ( 1 + g_alpha[0][7] - g_alpha[0][3] ),
+ 0x100FF / ( 1 + g_alpha[1][7] - g_alpha[1][3] ),
+ 0x100FF / ( 1 + g_alpha[2][7] - g_alpha[2][3] ),
+ 0x100FF / ( 1 + g_alpha[3][7] - g_alpha[3][3] ),
+ 0x100FF / ( 1 + g_alpha[4][7] - g_alpha[4][3] ),
+ 0x100FF / ( 1 + g_alpha[5][7] - g_alpha[5][3] ),
+ 0x100FF / ( 1 + g_alpha[6][7] - g_alpha[6][3] ),
+ 0x100FF / ( 1 + g_alpha[7][7] - g_alpha[7][3] ),
+ 0x100FF / ( 1 + g_alpha[8][7] - g_alpha[8][3] ),
+ 0x100FF / ( 1 + g_alpha[9][7] - g_alpha[9][3] ),
+ 0x100FF / ( 1 + g_alpha[10][7] - g_alpha[10][3] ),
+ 0x100FF / ( 1 + g_alpha[11][7] - g_alpha[11][3] ),
+ 0x100FF / ( 1 + g_alpha[12][7] - g_alpha[12][3] ),
+ 0x100FF / ( 1 + g_alpha[13][7] - g_alpha[13][3] ),
+ 0x100FF / ( 1 + g_alpha[14][7] - g_alpha[14][3] ),
+ 0x100FF / ( 1 + g_alpha[15][7] - g_alpha[15][3] ),
+};
+
+#ifdef __SSE4_1__
+const __m128i g_table_SIMD[2] =
+{
+ _mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47),
+ _mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183)
+};
+const __m128i g_table128_SIMD[2] =
+{
+ _mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128),
+ _mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128)
+};
+const __m128i g_table256_SIMD[4] =
+{
+ _mm_setr_epi32( 2*256, 5*256, 9*256, 13*256),
+ _mm_setr_epi32( 8*256, 17*256, 29*256, 42*256),
+ _mm_setr_epi32( 18*256, 24*256, 33*256, 47*256),
+ _mm_setr_epi32( 60*256, 80*256, 106*256, 183*256)
+};
+
+const __m128i g_alpha_SIMD[16] = {
+ _mm_setr_epi16( g_alpha[ 0][0], g_alpha[ 0][1], g_alpha[ 0][2], g_alpha[ 0][3], g_alpha[ 0][4], g_alpha[ 0][5], g_alpha[ 0][6], g_alpha[ 0][7] ),
+ _mm_setr_epi16( g_alpha[ 1][0], g_alpha[ 1][1], g_alpha[ 1][2], g_alpha[ 1][3], g_alpha[ 1][4], g_alpha[ 1][5], g_alpha[ 1][6], g_alpha[ 1][7] ),
+ _mm_setr_epi16( g_alpha[ 2][0], g_alpha[ 2][1], g_alpha[ 2][2], g_alpha[ 2][3], g_alpha[ 2][4], g_alpha[ 2][5], g_alpha[ 2][6], g_alpha[ 2][7] ),
+ _mm_setr_epi16( g_alpha[ 3][0], g_alpha[ 3][1], g_alpha[ 3][2], g_alpha[ 3][3], g_alpha[ 3][4], g_alpha[ 3][5], g_alpha[ 3][6], g_alpha[ 3][7] ),
+ _mm_setr_epi16( g_alpha[ 4][0], g_alpha[ 4][1], g_alpha[ 4][2], g_alpha[ 4][3], g_alpha[ 4][4], g_alpha[ 4][5], g_alpha[ 4][6], g_alpha[ 4][7] ),
+ _mm_setr_epi16( g_alpha[ 5][0], g_alpha[ 5][1], g_alpha[ 5][2], g_alpha[ 5][3], g_alpha[ 5][4], g_alpha[ 5][5], g_alpha[ 5][6], g_alpha[ 5][7] ),
+ _mm_setr_epi16( g_alpha[ 6][0], g_alpha[ 6][1], g_alpha[ 6][2], g_alpha[ 6][3], g_alpha[ 6][4], g_alpha[ 6][5], g_alpha[ 6][6], g_alpha[ 6][7] ),
+ _mm_setr_epi16( g_alpha[ 7][0], g_alpha[ 7][1], g_alpha[ 7][2], g_alpha[ 7][3], g_alpha[ 7][4], g_alpha[ 7][5], g_alpha[ 7][6], g_alpha[ 7][7] ),
+ _mm_setr_epi16( g_alpha[ 8][0], g_alpha[ 8][1], g_alpha[ 8][2], g_alpha[ 8][3], g_alpha[ 8][4], g_alpha[ 8][5], g_alpha[ 8][6], g_alpha[ 8][7] ),
+ _mm_setr_epi16( g_alpha[ 9][0], g_alpha[ 9][1], g_alpha[ 9][2], g_alpha[ 9][3], g_alpha[ 9][4], g_alpha[ 9][5], g_alpha[ 9][6], g_alpha[ 9][7] ),
+ _mm_setr_epi16( g_alpha[10][0], g_alpha[10][1], g_alpha[10][2], g_alpha[10][3], g_alpha[10][4], g_alpha[10][5], g_alpha[10][6], g_alpha[10][7] ),
+ _mm_setr_epi16( g_alpha[11][0], g_alpha[11][1], g_alpha[11][2], g_alpha[11][3], g_alpha[11][4], g_alpha[11][5], g_alpha[11][6], g_alpha[11][7] ),
+ _mm_setr_epi16( g_alpha[12][0], g_alpha[12][1], g_alpha[12][2], g_alpha[12][3], g_alpha[12][4], g_alpha[12][5], g_alpha[12][6], g_alpha[12][7] ),
+ _mm_setr_epi16( g_alpha[13][0], g_alpha[13][1], g_alpha[13][2], g_alpha[13][3], g_alpha[13][4], g_alpha[13][5], g_alpha[13][6], g_alpha[13][7] ),
+ _mm_setr_epi16( g_alpha[14][0], g_alpha[14][1], g_alpha[14][2], g_alpha[14][3], g_alpha[14][4], g_alpha[14][5], g_alpha[14][6], g_alpha[14][7] ),
+ _mm_setr_epi16( g_alpha[15][0], g_alpha[15][1], g_alpha[15][2], g_alpha[15][3], g_alpha[15][4], g_alpha[15][5], g_alpha[15][6], g_alpha[15][7] ),
+};
+
+const __m128i g_alphaRange_SIMD = _mm_setr_epi16(
+ g_alphaRange[0],
+ g_alphaRange[1],
+ g_alphaRange[4],
+ g_alphaRange[5],
+ g_alphaRange[8],
+ g_alphaRange[14],
+ 0,
+ 0 );
+#endif
+
+#ifdef __AVX2__
+const __m256i g_alpha_AVX[8] = {
+ _mm256_setr_epi16( g_alpha[ 0][0], g_alpha[ 1][0], g_alpha[ 2][0], g_alpha[ 3][0], g_alpha[ 4][0], g_alpha[ 5][0], g_alpha[ 6][0], g_alpha[ 7][0], g_alpha[ 8][0], g_alpha[ 9][0], g_alpha[10][0], g_alpha[11][0], g_alpha[12][0], g_alpha[13][0], g_alpha[14][0], g_alpha[15][0] ),
+ _mm256_setr_epi16( g_alpha[ 0][1], g_alpha[ 1][1], g_alpha[ 2][1], g_alpha[ 3][1], g_alpha[ 4][1], g_alpha[ 5][1], g_alpha[ 6][1], g_alpha[ 7][1], g_alpha[ 8][1], g_alpha[ 9][1], g_alpha[10][1], g_alpha[11][1], g_alpha[12][1], g_alpha[13][1], g_alpha[14][1], g_alpha[15][1] ),
+ _mm256_setr_epi16( g_alpha[ 0][2], g_alpha[ 1][2], g_alpha[ 2][2], g_alpha[ 3][2], g_alpha[ 4][2], g_alpha[ 5][2], g_alpha[ 6][2], g_alpha[ 7][2], g_alpha[ 8][2], g_alpha[ 9][2], g_alpha[10][2], g_alpha[11][2], g_alpha[12][2], g_alpha[13][2], g_alpha[14][2], g_alpha[15][2] ),
+ _mm256_setr_epi16( g_alpha[ 0][3], g_alpha[ 1][3], g_alpha[ 2][3], g_alpha[ 3][3], g_alpha[ 4][3], g_alpha[ 5][3], g_alpha[ 6][3], g_alpha[ 7][3], g_alpha[ 8][3], g_alpha[ 9][3], g_alpha[10][3], g_alpha[11][3], g_alpha[12][3], g_alpha[13][3], g_alpha[14][3], g_alpha[15][3] ),
+ _mm256_setr_epi16( g_alpha[ 0][4], g_alpha[ 1][4], g_alpha[ 2][4], g_alpha[ 3][4], g_alpha[ 4][4], g_alpha[ 5][4], g_alpha[ 6][4], g_alpha[ 7][4], g_alpha[ 8][4], g_alpha[ 9][4], g_alpha[10][4], g_alpha[11][4], g_alpha[12][4], g_alpha[13][4], g_alpha[14][4], g_alpha[15][4] ),
+ _mm256_setr_epi16( g_alpha[ 0][5], g_alpha[ 1][5], g_alpha[ 2][5], g_alpha[ 3][5], g_alpha[ 4][5], g_alpha[ 5][5], g_alpha[ 6][5], g_alpha[ 7][5], g_alpha[ 8][5], g_alpha[ 9][5], g_alpha[10][5], g_alpha[11][5], g_alpha[12][5], g_alpha[13][5], g_alpha[14][5], g_alpha[15][5] ),
+ _mm256_setr_epi16( g_alpha[ 0][6], g_alpha[ 1][6], g_alpha[ 2][6], g_alpha[ 3][6], g_alpha[ 4][6], g_alpha[ 5][6], g_alpha[ 6][6], g_alpha[ 7][6], g_alpha[ 8][6], g_alpha[ 9][6], g_alpha[10][6], g_alpha[11][6], g_alpha[12][6], g_alpha[13][6], g_alpha[14][6], g_alpha[15][6] ),
+ _mm256_setr_epi16( g_alpha[ 0][7], g_alpha[ 1][7], g_alpha[ 2][7], g_alpha[ 3][7], g_alpha[ 4][7], g_alpha[ 5][7], g_alpha[ 6][7], g_alpha[ 7][7], g_alpha[ 8][7], g_alpha[ 9][7], g_alpha[10][7], g_alpha[11][7], g_alpha[12][7], g_alpha[13][7], g_alpha[14][7], g_alpha[15][7] ),
+};
+
+const __m256i g_alphaRange_AVX = _mm256_setr_epi16(
+ g_alphaRange[ 0], g_alphaRange[ 1], g_alphaRange[ 2], g_alphaRange[ 3], g_alphaRange[ 4], g_alphaRange[ 5], g_alphaRange[ 6], g_alphaRange[ 7],
+ g_alphaRange[ 8], g_alphaRange[ 9], g_alphaRange[10], g_alphaRange[11], g_alphaRange[12], g_alphaRange[13], g_alphaRange[14], g_alphaRange[15]
+);
+#endif
+
+#ifdef __ARM_NEON
+const int16x8_t g_table128_NEON[2] =
+{
+ { 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128 },
+ { 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128 }
+};
+
+const int32x4_t g_table256_NEON[4] =
+{
+ { 2*256, 5*256, 9*256, 13*256 },
+ { 8*256, 17*256, 29*256, 42*256 },
+ { 18*256, 24*256, 33*256, 47*256 },
+ { 60*256, 80*256, 106*256, 183*256 }
+};
+
+const int16x8_t g_alpha_NEON[16] =
+{
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int16x8_t g_alphaRange_NEON =
+{
+ (int16_t)g_alphaRange[0],
+ (int16_t)g_alphaRange[1],
+ (int16_t)g_alphaRange[4],
+ (int16_t)g_alphaRange[5],
+ (int16_t)g_alphaRange[8],
+ (int16_t)g_alphaRange[14],
+ 0,
+ 0
+};
+#endif
diff --git a/thirdparty/etcpak/Tables.hpp b/thirdparty/etcpak/Tables.hpp
new file mode 100644
index 0000000000..69d7e8aa07
--- /dev/null
+++ b/thirdparty/etcpak/Tables.hpp
@@ -0,0 +1,49 @@
+#ifndef __TABLES_HPP__
+#define __TABLES_HPP__
+
+#include <stdint.h>
+
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+#ifdef __SSE4_1__
+# include <smmintrin.h>
+#endif
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+extern const int32_t g_table[8][4];
+extern const int64_t g_table256[8][4];
+
+extern const uint32_t g_id[4][16];
+
+extern const uint32_t g_avg2[16];
+
+extern const uint32_t g_flags[64];
+
+extern const int32_t g_alpha[16][8];
+extern const int32_t g_alphaRange[16];
+
+#ifdef __SSE4_1__
+extern const __m128i g_table_SIMD[2];
+extern const __m128i g_table128_SIMD[2];
+extern const __m128i g_table256_SIMD[4];
+
+extern const __m128i g_alpha_SIMD[16];
+extern const __m128i g_alphaRange_SIMD;
+#endif
+
+#ifdef __AVX2__
+extern const __m256i g_alpha_AVX[8];
+extern const __m256i g_alphaRange_AVX;
+#endif
+
+#ifdef __ARM_NEON
+extern const int16x8_t g_table128_NEON[2];
+extern const int32x4_t g_table256_NEON[4];
+extern const int16x8_t g_alpha_NEON[16];
+extern const int16x8_t g_alphaRange_NEON;
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/Vector.hpp b/thirdparty/etcpak/Vector.hpp
new file mode 100644
index 0000000000..3370a88aea
--- /dev/null
+++ b/thirdparty/etcpak/Vector.hpp
@@ -0,0 +1,222 @@
+#ifndef __DARKRL__VECTOR_HPP__
+#define __DARKRL__VECTOR_HPP__
+
+#include <assert.h>
+#include <algorithm>
+#include <math.h>
+#include <stdint.h>
+
+#include "Math.hpp"
+
+template<class T>
+struct Vector2
+{
+ Vector2() : x( 0 ), y( 0 ) {}
+ Vector2( T v ) : x( v ), y( v ) {}
+ Vector2( T _x, T _y ) : x( _x ), y( _y ) {}
+
+ bool operator==( const Vector2<T>& rhs ) const { return x == rhs.x && y == rhs.y; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ Vector2<T>& operator+=( const Vector2<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator-=( const Vector2<T>& rhs )
+ {
+ x -= rhs.x;
+ y -= rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator*=( const Vector2<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ return *this;
+ }
+
+ T x, y;
+};
+
+template<class T>
+Vector2<T> operator+( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x + rhs.x, lhs.y + rhs.y );
+}
+
+template<class T>
+Vector2<T> operator-( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x - rhs.x, lhs.y - rhs.y );
+}
+
+template<class T>
+Vector2<T> operator*( const Vector2<T>& lhs, const float& rhs )
+{
+ return Vector2<T>( lhs.x * rhs, lhs.y * rhs );
+}
+
+template<class T>
+Vector2<T> operator/( const Vector2<T>& lhs, const T& rhs )
+{
+ return Vector2<T>( lhs.x / rhs, lhs.y / rhs );
+}
+
+
+typedef Vector2<int32_t> v2i;
+typedef Vector2<float> v2f;
+
+
+template<class T>
+struct Vector3
+{
+ Vector3() : x( 0 ), y( 0 ), z( 0 ) {}
+ Vector3( T v ) : x( v ), y( v ), z( v ) {}
+ Vector3( T _x, T _y, T _z ) : x( _x ), y( _y ), z( _z ) {}
+ template<class Y>
+ Vector3( const Vector3<Y>& v ) : x( T( v.x ) ), y( T( v.y ) ), z( T( v.z ) ) {}
+
+ T Luminance() const { return T( x * 0.3f + y * 0.59f + z * 0.11f ); }
+ void Clamp()
+ {
+ x = std::min( T(1), std::max( T(0), x ) );
+ y = std::min( T(1), std::max( T(0), y ) );
+ z = std::min( T(1), std::max( T(0), z ) );
+ }
+
+ bool operator==( const Vector3<T>& rhs ) const { return x == rhs.x && y == rhs.y && z == rhs.z; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ T& operator[]( unsigned int idx ) { assert( idx < 3 ); return ((T*)this)[idx]; }
+ const T& operator[]( unsigned int idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; }
+
+ Vector3<T> operator+=( const Vector3<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ z += rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const Vector3<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ z *= rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const float& rhs )
+ {
+ x *= rhs;
+ y *= rhs;
+ z *= rhs;
+ return *this;
+ }
+
+ T x, y, z;
+ T padding;
+};
+
+template<class T>
+Vector3<T> operator+( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z );
+}
+
+template<class T>
+Vector3<T> operator-( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const float& rhs )
+{
+ return Vector3<T>( T( lhs.x * rhs ), T( lhs.y * rhs ), T( lhs.z * rhs ) );
+}
+
+template<class T>
+Vector3<T> operator/( const Vector3<T>& lhs, const T& rhs )
+{
+ return Vector3<T>( lhs.x / rhs, lhs.y / rhs, lhs.z / rhs );
+}
+
+template<class T>
+bool operator<( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return lhs.Luminance() < rhs.Luminance();
+}
+
+typedef Vector3<int32_t> v3i;
+typedef Vector3<float> v3f;
+typedef Vector3<uint8_t> v3b;
+
+
+static inline v3b v3f_to_v3b( const v3f& v )
+{
+ return v3b( uint8_t( std::min( 1.f, v.x ) * 255 ), uint8_t( std::min( 1.f, v.y ) * 255 ), uint8_t( std::min( 1.f, v.z ) * 255 ) );
+}
+
+template<class T>
+Vector3<T> Mix( const Vector3<T>& v1, const Vector3<T>& v2, float amount )
+{
+ return v1 + ( v2 - v1 ) * amount;
+}
+
+template<>
+inline v3b Mix( const v3b& v1, const v3b& v2, float amount )
+{
+ return v3b( v3f( v1 ) + ( v3f( v2 ) - v3f( v1 ) ) * amount );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v )
+{
+ T l = v.Luminance();
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v, float mul )
+{
+ T l = T( v.Luminance() * mul );
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> pow( const Vector3<T>& base, float exponent )
+{
+ return Vector3<T>(
+ pow( base.x, exponent ),
+ pow( base.y, exponent ),
+ pow( base.z, exponent ) );
+}
+
+template<class T>
+Vector3<T> sRGB2linear( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ sRGB2linear( v.x ),
+ sRGB2linear( v.y ),
+ sRGB2linear( v.z ) );
+}
+
+template<class T>
+Vector3<T> linear2sRGB( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ linear2sRGB( v.x ),
+ linear2sRGB( v.y ),
+ linear2sRGB( v.z ) );
+}
+
+#endif
diff --git a/thirdparty/harfbuzz/NEWS b/thirdparty/harfbuzz/NEWS
index f09c2fafd1..321c550188 100644
--- a/thirdparty/harfbuzz/NEWS
+++ b/thirdparty/harfbuzz/NEWS
@@ -1,3 +1,18 @@
+Overview of changes leading to 2.8.0
+Tuesday, March 16, 2021
+====================================
+- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine.
+ Previously these were shaped using the generalized Arabic shaper. (David Corbett)
+- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett)
+- Update language tags. (David Corbett)
+- Variations: reduce error: do not round each interpolated delta. (Just van Rossum)
+- Documentation improvements. (Khaled Hosny, Nathan Willis)
+- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu)
+- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad)
+- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad)
+- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad)
+
+
Overview of changes leading to 2.7.4
Sunday, December 27, 2020
====================================
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
index 75d523f5fc..98ed20d8eb 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh
@@ -510,7 +510,7 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses))
- klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
+ klass = StateTable::CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -576,7 +576,7 @@ struct StateTable
if (unlikely (stop > states))
return_trace (false);
for (const HBUSHORT *p = states; stop < p; p--)
- num_entries = hb_max (num_entries, *(p - 1) + 1);
+ num_entries = hb_max (num_entries, *(p - 1) + 1u);
state_neg = min_state;
}
}
@@ -597,7 +597,7 @@ struct StateTable
if (unlikely (stop < states))
return_trace (false);
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
- num_entries = hb_max (num_entries, *p + 1);
+ num_entries = hb_max (num_entries, *p + 1u);
state_pos = max_state + 1;
}
}
@@ -729,7 +729,10 @@ struct ExtendedTypes
template <typename Types, typename EntryData>
struct StateTableDriver
{
- StateTableDriver (const StateTable<Types, EntryData> &machine_,
+ using StateTableT = StateTable<Types, EntryData>;
+ using EntryT = Entry<EntryData>;
+
+ StateTableDriver (const StateTableT &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
@@ -742,59 +745,101 @@ struct StateTableDriver
if (!c->in_place)
buffer->clear_output ();
- int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
+ int state = StateTableT::STATE_START_OF_TEXT;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
- (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
+ (unsigned) StateTableT::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
- const Entry<EntryData> &entry = machine.get_entry (state, klass);
+ const EntryT &entry = machine.get_entry (state, klass);
+ const int next_state = machine.new_state (entry.newState);
- /* Unsafe-to-break before this if not in state 0, as things might
- * go differently if we start from state 0 here.
+ /* Conditions under which it's guaranteed safe-to-break before current glyph:
*
- * Ugh. The indexing here is ugly... */
- if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
- {
- /* If there's no action and we're just epsilon-transitioning to state 0,
- * safe to break. */
- if (c->is_actionable (this, entry) ||
- !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
- entry.flags == context_t::DontAdvance))
- buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
- }
-
- /* Unsafe-to-break if end-of-text would kick in here. */
- if (buffer->idx + 2 <= buffer->len)
- {
- const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
- if (c->is_actionable (this, end_entry))
- buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
- }
+ * 1. There was no action in this transition; and
+ *
+ * 2. If we break before current glyph, the results will be the same. That
+ * is guaranteed if:
+ *
+ * 2a. We were already in start-of-text state; or
+ *
+ * 2b. We are epsilon-transitioning to start-of-text state; or
+ *
+ * 2c. Starting from start-of-text state seeing current glyph:
+ *
+ * 2c'. There won't be any actions; and
+ *
+ * 2c". We would end up in the same state that we were going to end up
+ * in now, including whether epsilon-transitioning.
+ *
+ * and
+ *
+ * 3. If we break before current glyph, there won't be any end-of-text action
+ * after previous glyph.
+ *
+ * This triples the transitions we need to look up, but is worth returning
+ * granular unsafe-to-break results. See eg.:
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/2860
+ */
+ const EntryT *wouldbe_entry;
+ bool safe_to_break =
+ /* 1. */
+ !c->is_actionable (this, entry)
+ &&
+ /* 2. */
+ (
+ /* 2a. */
+ state == StateTableT::STATE_START_OF_TEXT
+ ||
+ /* 2b. */
+ (
+ (entry.flags & context_t::DontAdvance) &&
+ next_state == StateTableT::STATE_START_OF_TEXT
+ )
+ ||
+ /* 2c. */
+ (
+ wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
+ ,
+ /* 2c'. */
+ !c->is_actionable (this, *wouldbe_entry)
+ &&
+ /* 2c". */
+ (
+ next_state == machine.new_state (wouldbe_entry->newState)
+ &&
+ (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
+ )
+ )
+ )
+ &&
+ /* 3. */
+ !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
+ ;
+
+ if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
+ buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (this, entry);
- state = machine.new_state (entry.newState);
+ state = next_state;
DEBUG_MSG (APPLY, nullptr, "s%d", state);
- if (buffer->idx == buffer->len)
+ if (buffer->idx == buffer->len || unlikely (!buffer->successful))
break;
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
if (!c->in_place)
- {
- for (; buffer->successful && buffer->idx < buffer->len;)
- buffer->next_glyph ();
buffer->swap_buffers ();
- }
}
public:
- const StateTable<Types, EntryData> &machine;
+ const StateTableT &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
index 04027a61be..e3bc268d26 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -337,9 +337,9 @@ struct ContextualSubtable
const EntryData &data = entries[i].data;
if (data.markIndex != 0xFFFF)
- num_lookups = hb_max (num_lookups, 1 + data.markIndex);
+ num_lookups = hb_max (num_lookups, 1u + data.markIndex);
if (data.currentIndex != 0xFFFF)
- num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
+ num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
}
return_trace (substitutionTables.sanitize (c, this, num_lookups));
@@ -499,7 +499,7 @@ struct LigatureSubtable
}
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
- buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
+ if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
action = *actionData;
@@ -525,25 +525,25 @@ struct LigatureSubtable
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
- buffer->replace_glyph (lig);
+ if (unlikely (!buffer->replace_glyph (lig))) return;
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
/* Now go and delete all subsequent components. */
while (match_length - 1u > cursor)
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
- buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
- buffer->replace_glyph (DELETED_GLYPH);
+ if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+ if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
- buffer->move_to (lig_end);
+ if (unlikely (!buffer->move_to (lig_end))) return;
buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
}
actionData++;
}
while (!(action & LigActionLast));
- buffer->move_to (end);
+ if (unlikely (!buffer->move_to (end))) return;
}
}
@@ -733,17 +733,16 @@ struct InsertionSubtable
bool before = flags & MarkedInsertBefore;
unsigned int end = buffer->out_len;
- buffer->move_to (mark);
+ if (unlikely (!buffer->move_to (mark))) return;
if (buffer->idx < buffer->len && !before)
- buffer->copy_glyph ();
+ if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
- for (unsigned int i = 0; i < count; i++)
- buffer->output_glyph (glyphs[i]);
+ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
- buffer->move_to (end + count);
+ if (unlikely (!buffer->move_to (end + count))) return;
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
}
@@ -764,10 +763,9 @@ struct InsertionSubtable
unsigned int end = buffer->out_len;
if (buffer->idx < buffer->len && !before)
- buffer->copy_glyph ();
+ if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
- for (unsigned int i = 0; i < count; i++)
- buffer->output_glyph (glyphs[i]);
+ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@@ -786,7 +784,7 @@ struct InsertionSubtable
*
* https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
*/
- buffer->move_to ((flags & DontAdvance) ? end : end + count);
+ if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
}
}
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.cc b/thirdparty/harfbuzz/src/hb-aat-layout.cc
index 74ebaa64ec..0e9f2b4954 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.cc
@@ -227,7 +227,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
*
* <note>Note: does not examine the `GSUB` table.</note>
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -294,7 +294,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
*
* <note>Note: does not examine the `GPOS` table.</note>
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -325,7 +325,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
* Tests whether the specified face includes any tracking information
* in the `trak` table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.3.0
*/
@@ -350,7 +350,7 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
* hb_aat_layout_get_feature_types:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first feature type to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature types to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature types to return;
* Output = the actual number of feature types returned (may be zero)
* @features: (out caller-allocates) (array length=feature_count): Array of feature types found
*
@@ -374,9 +374,9 @@ hb_aat_layout_get_feature_types (hb_face_t *face,
* @face: #hb_face_t to work upon
* @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
*
- * Fetches the name ID of the specified feature type in the face's `name` table.
+ * Fetches the name identifier of the specified feature type in the face's `name` table.
*
- * Return value: Name ID of the requested feature type
+ * Return value: Name identifier of the requested feature type
*
* Since: 2.2.0
*/
@@ -388,15 +388,15 @@ hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
}
/**
- * hb_aat_layout_feature_type_get_selectors:
+ * hb_aat_layout_feature_type_get_selector_infos:
* @face: #hb_face_t to work upon
* @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type
* @start_offset: offset of the first feature type to retrieve
- * @selector_count: (inout) (allow-none): Input = the maximum number of selectors to return;
+ * @selector_count: (inout) (optional): Input = the maximum number of selectors to return;
* Output = the actual number of selectors returned (may be zero)
- * @selectors: (out caller-allocates) (array length=selector_count): A buffer pointer.
- * The selectors available for the feature type queries.
- * @default_index: (out) (allow-none): The index of the feature's default selector, if any
+ * @selectors: (out caller-allocates) (array length=selector_count) (optional):
+ * A buffer pointer. The selectors available for the feature type queries.
+ * @default_index: (out) (optional): The index of the feature's default selector, if any
*
* Fetches a list of the selectors available for the specified feature in the given face.
*
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.h b/thirdparty/harfbuzz/src/hb-aat-layout.h
index dc1bf96573..9af2740088 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.h
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_AAT_H_IN
+#if !defined(HB_AAT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-aat.h> instead."
#endif
@@ -38,47 +38,47 @@ HB_BEGIN_DECLS
/**
* hb_aat_layout_feature_type_t:
* @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE:
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE:
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING: [Number Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type6)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE: [Smart Swash](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type8)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE: [Diacritics](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type9)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION: [Vertical Position](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type10)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS: [Fractions](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type11)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE: [Overlapping Characters](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type13)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS: [Typographic Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type14)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS: [Mathematical Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type15)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE: [Ornament Sets](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type16)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES: [Character Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type17)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE: [Design Complexity](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type18)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS: [Style Options](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type19)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE: [Character Shape](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type20)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE: [Number Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type21)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING: [Text Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type22)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION: [Transliteration](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type23)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE: [Annotation](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type24)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE: [Kana Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type25)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE: [Ideographic Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type26)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE: [Unicode Decomposition](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type27)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA: [Ruby Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type28)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE: [CJK Symbol Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type29)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE: [Ideographic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type30)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE: [CJK Vertical Roman Placement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type31)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN: [Italic CJK Roman](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type32)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT: [Case Sensitive Layout](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type33)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA: [Alternate Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type34)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES: [Stylistic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type35)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES: [Contextual Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type36)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE: [Lower Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type37)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE: [Upper Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type38)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE: [Language Tag](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type39)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE: [CJK Roman Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type103)
*
- * The possible feature types defined for AAT shaping.
+ * The possible feature types defined for AAT shaping, from Apple [Font Feature Registry](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html).
*
* Since: 2.2.0
*/
@@ -732,6 +732,14 @@ HB_EXTERN hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type);
+/**
+ * hb_aat_layout_feature_selector_info_t:
+ * @name_id: The selector's name identifier
+ * @enable: The value to turn the selector on
+ * @disable: The value to turn the selector off
+ *
+ * Structure representing a setting for an #hb_aat_layout_feature_type_t.
+ */
typedef struct hb_aat_layout_feature_selector_info_t {
hb_ot_name_id_t name_id;
hb_aat_layout_feature_selector_t enable;
diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh
index 98de61f3e8..bc170b0546 100644
--- a/thirdparty/harfbuzz/src/hb-algs.hh
+++ b/thirdparty/harfbuzz/src/hb-algs.hh
@@ -35,6 +35,132 @@
#include "hb-number.hh"
+/*
+ * Flags
+ */
+
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another... So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+ * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+ extern "C++" { \
+ static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
+ static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
+ static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
+ static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
+ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
+ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+ } \
+ static_assert (true, "")
+
+/* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+#define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
+#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
+#define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x))
+#define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
+#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
+
+
+/*
+ * Big-endian integers.
+ */
+
+/* Endian swap, used in Windows related backends */
+static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+template <typename Type, int Bytes = sizeof (Type)>
+struct BEInt;
+template <typename Type>
+struct BEInt<Type, 1>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t (V)} {}
+ constexpr operator Type () const { return v; }
+ private: uint8_t v;
+};
+template <typename Type>
+struct BEInt<Type, 2>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+
+ struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+ constexpr operator Type () const
+ {
+#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
+ defined(__BYTE_ORDER) && \
+ (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+ /* Spoon-feed the compiler a big-endian integer with alignment 1.
+ * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return __builtin_bswap16 (((packed_uint16_t *) this)->v);
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ return ((packed_uint16_t *) this)->v;
+#endif
+#else
+ return (v[0] << 8)
+ + (v[1] );
+#endif
+ }
+ private: uint8_t v[2];
+};
+template <typename Type>
+struct BEInt<Type, 3>
+{
+ static_assert (!hb_is_signed (Type), "");
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+
+ constexpr operator Type () const { return (v[0] << 16)
+ + (v[1] << 8)
+ + (v[2] ); }
+ private: uint8_t v[3];
+};
+template <typename Type>
+struct BEInt<Type, 4>
+{
+ public:
+ BEInt () = default;
+ constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
+ uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+ constexpr operator Type () const { return (v[0] << 24)
+ + (v[1] << 16)
+ + (v[2] << 8)
+ + (v[3] ); }
+ private: uint8_t v[4];
+};
+
+/* Floats. */
+
+/* We want our rounding towards +infinity. */
+static inline float
+_hb_roundf (float x) { return floorf (x + .5f); }
+#define roundf(x) _hb_roundf(x)
+
+
/* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits,
* values will be truncated / overlap, and might not decode exactly. */
#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
@@ -48,6 +174,7 @@
#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
+
struct
{
/* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
@@ -215,7 +342,9 @@ struct
template <typename Pred, typename Val> auto
impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
- (hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v)))
+ (
+ hb_deref (hb_forward<Pred> (p)).has (hb_forward<Val> (v))
+ )
template <typename Pred, typename Val> auto
impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
@@ -269,7 +398,9 @@ struct
template <typename Proj, typename Val> auto
impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
- (hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v)))
+ (
+ hb_deref (hb_forward<Proj> (f)).get (hb_forward<Val> (v))
+ )
template <typename Proj, typename Val> auto
impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
@@ -296,6 +427,40 @@ struct
}
HB_FUNCOBJ (hb_get);
+struct
+{
+ private:
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN
+ (
+ hb_forward<T2> (v2).cmp (hb_forward<T1> (v1)) == 0
+ )
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN
+ (
+ hb_forward<T1> (v1).cmp (hb_forward<T2> (v2)) == 0
+ )
+
+ template <typename T1, typename T2> auto
+ impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN
+ (
+ hb_forward<T1> (v1) == hb_forward<T2> (v2)
+ )
+
+ public:
+
+ template <typename T1, typename T2> auto
+ operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN
+ (
+ impl (hb_forward<T1> (v1),
+ hb_forward<T2> (v2),
+ hb_prioritize)
+ )
+}
+HB_FUNCOBJ (hb_equal);
+
template <typename T1, typename T2>
struct hb_pair_t
@@ -375,7 +540,7 @@ HB_FUNCOBJ (hb_clamp);
/* Return the number of 1 bits in v. */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_popcount (T v)
{
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
@@ -416,7 +581,7 @@ hb_popcount (T v)
/* Returns the number of bits needed to store number */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
@@ -490,7 +655,7 @@ hb_bit_storage (T v)
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
-static inline HB_CONST_FUNC unsigned int
+static inline unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return 8 * sizeof (T);
@@ -988,32 +1153,24 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
struct hb_bitwise_and
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = false;
- static constexpr bool passthru_right = false;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
}
HB_FUNCOBJ (hb_bitwise_and);
struct hb_bitwise_or
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = true;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
}
HB_FUNCOBJ (hb_bitwise_or);
struct hb_bitwise_xor
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = true;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
}
HB_FUNCOBJ (hb_bitwise_xor);
struct hb_bitwise_sub
{ HB_PARTIALIZE(2);
- static constexpr bool passthru_left = true;
- static constexpr bool passthru_right = false;
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
}
diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh
index 568cd02c79..02bd8d81c2 100644
--- a/thirdparty/harfbuzz/src/hb-array.hh
+++ b/thirdparty/harfbuzz/src/hb-array.hh
@@ -142,7 +142,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
bool lfind (const T &x, unsigned *pos = nullptr) const
{
for (unsigned i = 0; i < length; ++i)
- if (!this->arrayZ[i].cmp (x))
+ if (hb_equal (x, this->arrayZ[i]))
{
if (pos)
*pos = i;
diff --git a/thirdparty/harfbuzz/src/hb-atomic.hh b/thirdparty/harfbuzz/src/hb-atomic.hh
index b3fb296b4e..93265f655f 100644
--- a/thirdparty/harfbuzz/src/hb-atomic.hh
+++ b/thirdparty/harfbuzz/src/hb-atomic.hh
@@ -52,7 +52,7 @@
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
-/* C++11-style GCC primitives. */
+/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
#define _hb_memory_barrier() __sync_synchronize ()
@@ -73,7 +73,8 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
-#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
+
+#elif !defined(HB_NO_MT)
/* C++11 atomics. */
@@ -101,117 +102,6 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
-#elif !defined(HB_NO_MT) && defined(_WIN32)
-
-#include <windows.h>
-
-static inline void _hb_memory_barrier ()
-{
-#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
- /* MinGW has a convoluted history of supporting MemoryBarrier. */
- LONG dummy = 0;
- InterlockedExchange (&dummy, 1);
-#else
- MemoryBarrier ();
-#endif
-}
-#define _hb_memory_barrier() _hb_memory_barrier ()
-
-#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
-static_assert ((sizeof (LONG) == sizeof (int)), "");
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-#define _hb_memory_barrier() __sync_synchronize ()
-
-#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
-
-#include <atomic.h>
-#include <mbarrier.h>
-
-#define _hb_memory_r_barrier() __machine_r_barrier ()
-#define _hb_memory_w_barrier() __machine_w_barrier ()
-#define _hb_memory_barrier() __machine_rw_barrier ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
- _hb_memory_w_barrier ();
- int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
- _hb_memory_r_barrier ();
- return result;
-}
-static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
-{
- _hb_memory_w_barrier ();
- bool result = atomic_cas_ptr (P, O, N) == O;
- _hb_memory_r_barrier ();
- return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
-
-
-#elif !defined(HB_NO_MT) && defined(__APPLE__)
-
-#include <libkern/OSAtomic.h>
-#ifdef __MAC_OS_X_MIN_REQUIRED
-#include <AvailabilityMacros.h>
-#elif defined(__IPHONE_OS_MIN_REQUIRED)
-#include <Availability.h>
-#endif
-
-#define _hb_memory_barrier() OSMemoryBarrier ()
-
-#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
-
-#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
-#else
-#if __ppc64__ || __x86_64__ || __aarch64__
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
-#else
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
-#endif
-#endif
-
-
-#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
-
-#include <builtins.h>
-
-#define _hb_memory_barrier() __lwsync ()
-
-static inline int _hb_fetch_and_add (int *AI, int V)
-{
- _hb_memory_barrier ();
- int result = __fetch_and_add (AI, V);
- _hb_memory_barrier ();
- return result;
-}
-static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
-{
- _hb_memory_barrier ();
- bool result = __compare_and_swaplp (P, &O, N);
- _hb_memory_barrier ();
- return result;
-}
-
-#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
-
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N))
-static_assert ((sizeof (long) == sizeof (void *)), "");
-
-
#elif defined(HB_NO_MT)
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@@ -259,9 +149,11 @@ inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory
#endif
-#define HB_ATOMIC_INT_INIT(V) {V}
struct hb_atomic_int_t
{
+ hb_atomic_int_t () = default;
+ constexpr hb_atomic_int_t (int v) : v (v) {}
+
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
@@ -269,16 +161,17 @@ struct hb_atomic_int_t
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
- int v;
+ int v = 0;
};
-
-#define HB_ATOMIC_PTR_INIT(V) {V}
template <typename P>
struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
+ hb_atomic_ptr_t () = default;
+ constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
@@ -288,7 +181,7 @@ struct hb_atomic_ptr_t
T * operator -> () const { return get (); }
template <typename C> operator C * () const { return get (); }
- T *v;
+ T *v = nullptr;
};
diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc
index e340bc346d..71b1b1fc4f 100644
--- a/thirdparty/harfbuzz/src/hb-blob.cc
+++ b/thirdparty/harfbuzz/src/hb-blob.cc
@@ -35,9 +35,6 @@
#include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */
-#include <stdio.h>
-#include <stdlib.h>
-
/**
* SECTION: hb-blob
@@ -58,7 +55,7 @@
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
- * @destroy: (optional): Callback to call when @data is not needed anymore.
+ * @destroy: (nullable): Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
@@ -116,7 +113,7 @@ _hb_blob_destroy (void *data)
* @length: Length of sub-blob.
*
* Returns a blob that represents a range of bytes in @parent. The new
- * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * blob is always created with #HB_MEMORY_MODE_READONLY, meaning that it
* will never modify data in the parent blob. The parent data is not
* expected to be modified, and will result in undefined behavior if it
* is.
@@ -237,7 +234,7 @@ hb_blob_destroy (hb_blob_t *blob)
* @blob: An #hb_blob_t
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified blob.
@@ -299,7 +296,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
*
* Tests whether a blob is immutable.
*
- * Return value: %true if @blob is immutable, false otherwise
+ * Return value: %true if @blob is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -365,16 +362,14 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
{
- if (!blob->try_make_writable ()) {
- if (length)
- *length = 0;
-
+ if (hb_object_is_immutable (blob) ||
+ !blob->try_make_writable ())
+ {
+ if (length) *length = 0;
return nullptr;
}
- if (length)
- *length = blob->length;
-
+ if (length) *length = blob->length;
return const_cast<char *> (blob->data);
}
@@ -440,8 +435,8 @@ hb_blob_t::try_make_writable_inplace ()
bool
hb_blob_t::try_make_writable ()
{
- if (hb_object_is_immutable (this))
- return false;
+ if (unlikely (!length))
+ mode = HB_MEMORY_MODE_WRITABLE;
if (this->mode == HB_MEMORY_MODE_WRITABLE)
return true;
diff --git a/thirdparty/harfbuzz/src/hb-blob.h b/thirdparty/harfbuzz/src/hb-blob.h
index 00e41f3ce3..86f12788d2 100644
--- a/thirdparty/harfbuzz/src/hb-blob.h
+++ b/thirdparty/harfbuzz/src/hb-blob.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -38,10 +38,12 @@ HB_BEGIN_DECLS
/**
* hb_memory_mode_t:
- * @HB_MEMORY_MODE_DUPLICATE
- * @HB_MEMORY_MODE_READONLY
- * @HB_MEMORY_MODE_WRITABLE
- * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
+ * @HB_MEMORY_MODE_DUPLICATE: HarfBuzz immediately makes a copy of the data.
+ * @HB_MEMORY_MODE_READONLY: HarfBuzz client will never modify the data,
+ * and HarfBuzz will never modify the data.
+ * @HB_MEMORY_MODE_WRITABLE: HarfBuzz client made a copy of the data solely
+ * for HarfBuzz, so HarfBuzz may modify the data.
+ * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE: See above
*
* Data type holding the memory modes available to
* client programs.
diff --git a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
index f65bad45bb..6539b89640 100644
--- a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc
@@ -400,8 +400,8 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
- * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
@@ -514,8 +514,10 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
+ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
+ * to serialize.
*
* Serializes @buffer into a textual representation of its content,
* when the buffer contains Unicode codepoints (i.e., before shaping). This is
@@ -635,8 +637,8 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer,
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
- * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
- * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (nullable): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
@@ -724,15 +726,17 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
/**
* hb_buffer_deserialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
- * @buf: (array length=buf_len):
- * @buf_len:
- * @end_ptr: (out):
- * @font:
- * @format:
- *
+ * @buf: (array length=buf_len): string to deserialize
+ * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @end_ptr: (out) (optional): output pointer to the character after last
+ * consumed one.
+ * @font: (nullable): font for getting glyph IDs
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
*
+ * Deserializes glyphs @buffer from textual representation in the format
+ * produced by hb_buffer_serialize_glyphs().
*
- * Return value:
+ * Return value: %true if @buf is not fully consumed, %false otherwise.
*
* Since: 0.9.7
**/
@@ -795,14 +799,16 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
/**
* hb_buffer_deserialize_unicode:
* @buffer: an #hb_buffer_t buffer.
- * @buf: (array length=buf_len):
- * @buf_len:
- * @end_ptr: (out):
- * @format:
- *
+ * @buf: (array length=buf_len): string to deserialize
+ * @buf_len: the size of @buf, or -1 if it is %NULL-terminated
+ * @end_ptr: (out) (optional): output pointer to the character after last
+ * consumed one.
+ * @format: the #hb_buffer_serialize_format_t of the input @buf
*
+ * Deserializes Unicode @buffer from textual representation in the format
+ * produced by hb_buffer_serialize_unicode().
*
- * Return value:
+ * Return value: %true if @buf is not fully consumed, %false otherwise.
*
* Since: 2.7.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc
index 10063db050..8cad6ab8e6 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer.cc
@@ -218,9 +218,6 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
void
hb_buffer_t::reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
@@ -233,9 +230,6 @@ hb_buffer_t::reset ()
void
hb_buffer_t::clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
@@ -290,9 +284,6 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
void
hb_buffer_t::remove_output ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = false;
have_positions = false;
@@ -303,9 +294,6 @@ hb_buffer_t::remove_output ()
void
hb_buffer_t::clear_output ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = true;
have_positions = false;
@@ -316,9 +304,6 @@ hb_buffer_t::clear_output ()
void
hb_buffer_t::clear_positions ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
-
have_output = false;
have_positions = true;
@@ -333,15 +318,19 @@ hb_buffer_t::swap_buffers ()
{
if (unlikely (!successful)) return;
+ assert (idx <= len);
+ if (unlikely (!next_glyphs (len - idx))) return;
+
assert (have_output);
have_output = false;
if (out_info != info)
{
- hb_glyph_info_t *tmp_string;
- tmp_string = info;
+ hb_glyph_info_t *tmp;
+ tmp = info;
info = out_info;
- out_info = tmp_string;
+ out_info = tmp;
+
pos = (hb_glyph_position_t *) out_info;
}
@@ -353,31 +342,6 @@ hb_buffer_t::swap_buffers ()
idx = 0;
}
-
-void
-hb_buffer_t::replace_glyphs (unsigned int num_in,
- unsigned int num_out,
- const uint32_t *glyph_data)
-{
- if (unlikely (!make_room_for (num_in, num_out))) return;
-
- assert (idx + num_in <= len);
-
- merge_clusters (idx, idx + num_in);
-
- hb_glyph_info_t orig_info = info[idx];
- hb_glyph_info_t *pinfo = &out_info[out_len];
- for (unsigned int i = 0; i < num_out; i++)
- {
- *pinfo = orig_info;
- pinfo->codepoint = glyph_data[i];
- pinfo++;
- }
-
- idx += num_in;
- out_len += num_out;
-}
-
bool
hb_buffer_t::move_to (unsigned int i)
{
@@ -768,7 +732,7 @@ hb_buffer_destroy (hb_buffer_t *buffer)
* @buffer: An #hb_buffer_t
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified buffer.
@@ -795,7 +759,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
* Fetches the user data associated with the specified key,
* attached to the specified buffer.
*
- * Return value: (transfer-none): A pointer to the user data
+ * Return value: (transfer none): A pointer to the user data
*
* Since: 0.9.2
**/
@@ -1137,7 +1101,7 @@ hb_buffer_get_cluster_level (hb_buffer_t *buffer)
* Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
* when adding text to @buffer.
*
- * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
*
* Since: 0.9.31
**/
@@ -1222,6 +1186,9 @@ hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
void
hb_buffer_reset (hb_buffer_t *buffer)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
buffer->reset ();
}
@@ -1237,6 +1204,9 @@ hb_buffer_reset (hb_buffer_t *buffer)
void
hb_buffer_clear_contents (hb_buffer_t *buffer)
{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
buffer->clear ();
}
@@ -1321,7 +1291,7 @@ hb_buffer_set_length (hb_buffer_t *buffer,
if (unlikely (hb_object_is_immutable (buffer)))
return length == 0;
- if (!buffer->ensure (length))
+ if (unlikely (!buffer->ensure (length)))
return false;
/* Wipe the new space */
@@ -1501,20 +1471,20 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
*
* Sets unset buffer segment properties based on buffer Unicode
* contents. If buffer is not empty, it must have content type
- * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ * #HB_BUFFER_CONTENT_TYPE_UNICODE.
*
- * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it
* will be set to the Unicode script of the first character in
- * the buffer that has a script other than %HB_SCRIPT_COMMON,
- * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ * the buffer that has a script other than #HB_SCRIPT_COMMON,
+ * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN.
*
- * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID),
* it will be set to the natural horizontal direction of the
* buffer script as returned by hb_script_get_horizontal_direction().
- * If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID,
- * then %HB_DIRECTION_LTR is used.
+ * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID,
+ * then #HB_DIRECTION_LTR is used.
*
- * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID),
* it will be set to the process's default language as returned by
* hb_language_get_default(). This may change in the future by
* taking buffer script into consideration when choosing a language.
@@ -1551,7 +1521,10 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
if (item_length == -1)
item_length = text_length - item_offset;
- buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+ if (unlikely (item_length < 0 ||
+ item_length > INT_MAX / 8 ||
+ !buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
+ return;
/* If buffer is empty and pre-context provided, install it.
* This check is written this way, to make sure people can
@@ -1768,11 +1741,6 @@ hb_buffer_append (hb_buffer_t *buffer,
if (start == end)
return;
- if (!buffer->len)
- buffer->content_type = source->content_type;
- if (!buffer->have_positions && source->have_positions)
- buffer->clear_positions ();
-
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
{
buffer->successful = false;
@@ -1784,6 +1752,11 @@ hb_buffer_append (hb_buffer_t *buffer,
if (unlikely (!buffer->successful))
return;
+ if (!orig_len)
+ buffer->content_type = source->content_type;
+ if (!buffer->have_positions && source->have_positions)
+ buffer->clear_positions ();
+
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
@@ -1902,8 +1875,8 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
* @position_fuzz: allowed absolute difference in position values.
*
- * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
- * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
+ * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
+ * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
* callers if just comparing two buffers is needed.
*
* Since: 1.5.0
@@ -1994,11 +1967,11 @@ hb_buffer_diff (hb_buffer_t *buffer,
/**
* hb_buffer_set_message_func:
* @buffer: An #hb_buffer_t
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
+ * @func: (closure user_data) (destroy destroy) (scope notified): Callback function
+ * @user_data: (nullable): Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
+ * Sets the implementation function for #hb_buffer_message_func_t.
*
* Since: 1.1.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h
index b13757e68f..865ccb2273 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.h
+++ b/thirdparty/harfbuzz/src/hb-buffer.h
@@ -27,7 +27,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -90,6 +90,8 @@ typedef struct hb_glyph_info_t {
* breaking point only.
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
+ * Flags for #hb_glyph_info_t.
+ *
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
@@ -150,6 +152,11 @@ typedef struct hb_segment_properties_t {
void *reserved2;
} hb_segment_properties_t;
+/**
+ * HB_SEGMENT_PROPERTIES_DEFAULT:
+ *
+ * The default #hb_segment_properties_t of of freshly created #hb_buffer_t.
+ */
#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
HB_SCRIPT_INVALID, \
HB_LANGUAGE_INVALID, \
@@ -203,6 +210,8 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
* @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
* @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ *
+ * The type of #hb_buffer_t contents.
*/
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
@@ -288,6 +297,8 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
*
+ * Flags for #hb_buffer_t.
+ *
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
@@ -579,6 +590,35 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
* Compare buffers
*/
+/**
+ * hb_buffer_diff_flags_t:
+ * @HB_BUFFER_DIFF_FLAG_EQUAL: equal buffers.
+ * @HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH: buffers with different
+ * #hb_buffer_content_type_t.
+ * @HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH: buffers with differing length.
+ * @HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT: `.notdef` glyph is present in the
+ * reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT: dotted circle glyph is present
+ * in the reference buffer.
+ * @HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH: difference in #hb_glyph_info_t.codepoint
+ * @HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH: difference in #hb_glyph_info_t.cluster
+ * @HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH: difference in #hb_glyph_flags_t.
+ * @HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH: difference in #hb_glyph_position_t.
+ *
+ * Flags from comparing two #hb_buffer_t's.
+ *
+ * Buffer with different #hb_buffer_content_type_t cannot be meaningfully
+ * compared in any further detail.
+ *
+ * For buffers with differing length, the per-glyph comparison is not
+ * attempted, though we do still scan reference buffer for dotted circle and
+ * `.notdef` glyphs.
+ *
+ * If the buffers have the same length, we compare them glyph-by-glyph and
+ * report which aspect(s) of the glyph info/position are different.
+ *
+ * Since: 1.5.0
+ */
typedef enum { /*< flags >*/
HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000,
@@ -618,6 +658,23 @@ hb_buffer_diff (hb_buffer_t *buffer,
* Debugging.
*/
+/**
+ * hb_buffer_message_func_t:
+ * @buffer: An #hb_buffer_t to work upon
+ * @font: The #hb_font_t the @buffer is shaped with
+ * @message: %NULL-terminated message passed to the function
+ * @user_data: User data pointer passed by the caller
+ *
+ * A callback method for #hb_buffer_t. The method gets called with the
+ * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a
+ * message describing what step of the shaping process will be performed.
+ * Returning %false from this method will skip this shaping step and move to
+ * the next one.
+ *
+ * Return value: %true to perform the shaping step, %false to skip it.
+ *
+ * Since: 1.1.3
+ */
typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer,
hb_font_t *font,
const char *message,
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index 9cad5206e2..8b432b5f96 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -139,7 +139,7 @@ struct hb_buffer_t
/* Methods */
- bool in_error () const { return !successful; }
+ HB_NODISCARD bool in_error () const { return !successful; }
void allocate_var (unsigned int start, unsigned int count)
{
@@ -186,7 +186,7 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
- bool has_separate_output () const { return info != out_info; }
+ HB_NODISCARD bool has_separate_output () const { return info != out_info; }
HB_INTERNAL void reset ();
@@ -210,86 +210,89 @@ struct hb_buffer_t
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
- HB_INTERNAL void replace_glyphs (unsigned int num_in,
- unsigned int num_out,
- const hb_codepoint_t *glyph_data);
-
- void replace_glyph (hb_codepoint_t glyph_index)
+ template <typename T>
+ HB_NODISCARD bool replace_glyphs (unsigned int num_in,
+ unsigned int num_out,
+ const T *glyph_data)
{
- if (unlikely (out_info != info || out_len != idx)) {
- if (unlikely (!make_room_for (1, 1))) return;
- out_info[out_len] = info[idx];
- }
- out_info[out_len].codepoint = glyph_index;
+ if (unlikely (!make_room_for (num_in, num_out))) return false;
- idx++;
- out_len++;
- }
- /* Makes a copy of the glyph at idx to output and replace glyph_index */
- hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
- {
- if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t);
+ assert (idx + num_in <= len);
- if (unlikely (idx == len && !out_len))
- return Crap (hb_glyph_info_t);
+ merge_clusters (idx, idx + num_in);
- out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
- out_info[out_len].codepoint = glyph_index;
+ hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
- out_len++;
+ hb_glyph_info_t *pinfo = &out_info[out_len];
+ for (unsigned int i = 0; i < num_out; i++)
+ {
+ *pinfo = orig_info;
+ pinfo->codepoint = glyph_data[i];
+ pinfo++;
+ }
- return out_info[out_len - 1];
+ idx += num_in;
+ out_len += num_out;
+ return true;
}
- void output_info (const hb_glyph_info_t &glyph_info)
+
+ HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
+ { return replace_glyphs (1, 1, &glyph_index); }
+
+ /* Makes a copy of the glyph at idx to output and replace glyph_index */
+ HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
+ { return replace_glyphs (0, 1, &glyph_index); }
+
+ HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
{
- if (unlikely (!make_room_for (0, 1))) return;
+ if (unlikely (!make_room_for (0, 1))) return false;
out_info[out_len] = glyph_info;
out_len++;
+ return true;
}
/* Copies glyph at idx to output but doesn't advance idx */
- void copy_glyph ()
+ HB_NODISCARD bool copy_glyph ()
{
- if (unlikely (!make_room_for (0, 1))) return;
-
- out_info[out_len] = info[idx];
-
- out_len++;
+ /* Extra copy because cur()'s return can be freed within
+ * output_info() call if buffer reallocates. */
+ return output_info (hb_glyph_info_t (cur()));
}
+
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
- void
- next_glyph ()
+ HB_NODISCARD bool next_glyph ()
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
- if (unlikely (!make_room_for (1, 1))) return;
+ if (unlikely (!make_room_for (1, 1))) return false;
out_info[out_len] = info[idx];
}
out_len++;
}
idx++;
+ return true;
}
/* Copies n glyphs at idx to output and advance idx.
* If there's no output, just advance idx. */
- void
- next_glyphs (unsigned int n)
+ HB_NODISCARD bool next_glyphs (unsigned int n)
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
- if (unlikely (!make_room_for (n, n))) return;
+ if (unlikely (!make_room_for (n, n))) return false;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
}
idx += n;
+ return true;
}
/* Advance idx without copying to output. */
void skip_glyph () { idx++; }
@@ -329,14 +332,14 @@ struct hb_buffer_t
/* Internal methods */
- HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+ HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
- HB_INTERNAL bool enlarge (unsigned int size);
+ HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
- bool ensure (unsigned int size)
+ HB_NODISCARD bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
- bool ensure_inplace (unsigned int size)
+ HB_NODISCARD bool ensure_inplace (unsigned int size)
{ return likely (!size || size < allocated); }
void assert_glyphs ()
@@ -349,7 +352,7 @@ struct hb_buffer_t
assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
(!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
}
- bool ensure_glyphs ()
+ HB_NODISCARD bool ensure_glyphs ()
{
if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
{
@@ -360,7 +363,7 @@ struct hb_buffer_t
}
return true;
}
- bool ensure_unicode ()
+ HB_NODISCARD bool ensure_unicode ()
{
if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
{
@@ -372,8 +375,8 @@ struct hb_buffer_t
return true;
}
- HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
- HB_INTERNAL bool shift_forward (unsigned int count);
+ HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+ HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc
index ddbcaa064c..7bb878b217 100644
--- a/thirdparty/harfbuzz/src/hb-common.cc
+++ b/thirdparty/harfbuzz/src/hb-common.cc
@@ -675,8 +675,8 @@ hb_version_string ()
* Tests the library version against a minimum value,
* as three integer components.
*
- * Return value: True if the library is equal to or greater than
- * the test value, false otherwise
+ * Return value: %true if the library is equal to or greater than
+ * the test value, %false otherwise
*
* Since: 0.9.30
**/
@@ -1003,6 +1003,21 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation
/**
* hb_variation_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
+ * @variation: (out): the #hb_variation_t to initialize with the parsed values
+ *
+ * Parses a string into a #hb_variation_t.
+ *
+ * The format for specifying variation settings follows. All valid CSS
+ * font-variation-settings values other than 'normal' and 'inherited' are also
+ * accepted, though, not documented below.
+ *
+ * The format is a tag, optionally followed by an equals sign, followed by a
+ * number. For example `wght=500`, or `slnt=-7.5`.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise
*
* Since: 1.4.2
*/
@@ -1029,6 +1044,13 @@ hb_variation_from_string (const char *str, int len,
/**
* hb_variation_to_string:
+ * @variation: an #hb_variation_t to convert
+ * @buf: (array length=size) (out): output string
+ * @size: the allocated size of @buf
+ *
+ * Converts an #hb_variation_t into a %NULL-terminated string in the format
+ * understood by hb_variation_from_string(). The client in responsible for
+ * allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 1.4.2
*/
@@ -1055,9 +1077,11 @@ hb_variation_to_string (hb_variation_t *variation,
/**
* hb_color_get_alpha:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
*
- * Return value: Alpha channel value of the given color
+ * Fetches the alpha channel of the given @color.
+ *
+ * Return value: Alpha channel value
*
* Since: 2.1.0
*/
@@ -1069,9 +1093,11 @@ uint8_t
/**
* hb_color_get_red:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the red channel of the given @color.
*
- * Return value: Red channel value of the given color
+ * Return value: Red channel value
*
* Since: 2.1.0
*/
@@ -1083,9 +1109,11 @@ uint8_t
/**
* hb_color_get_green:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
*
- * Return value: Green channel value of the given color
+ * Fetches the green channel of the given @color.
+ *
+ * Return value: Green channel value
*
* Since: 2.1.0
*/
@@ -1097,9 +1125,11 @@ uint8_t
/**
* hb_color_get_blue:
- * color: a #hb_color_t we are interested in its channels.
+ * @color: an #hb_color_t we are interested in its channels.
+ *
+ * Fetches the blue channel of the given @color.
*
- * Return value: Blue channel value of the given color
+ * Return value: Blue channel value
*
* Since: 2.1.0
*/
diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h
index efe185cdfd..532fd428cb 100644
--- a/thirdparty/harfbuzz/src/hb-common.h
+++ b/thirdparty/harfbuzz/src/hb-common.h
@@ -26,7 +26,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -135,7 +135,7 @@ typedef union _hb_var_int_t {
/**
* hb_tag_t:
- *
+ *
* Data type for tag identifiers. Tags are four
* byte integers, each byte representing a character.
*
@@ -148,22 +148,48 @@ typedef uint32_t hb_tag_t;
/**
* HB_TAG:
+ * @c1: 1st character of the tag
+ * @c2: 2nd character of the tag
+ * @c3: 3rd character of the tag
+ * @c4: 4th character of the tag
*
- * Constructs an #hb_tag_t from four characters.
+ * Constructs an #hb_tag_t from four character literals.
*
**/
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
/**
* HB_UNTAG:
+ * @tag: an #hb_tag_t
+ *
+ * Extracts four character literals from an #hb_tag_t.
*
- * Extracts the characters from an #hb_tag_t.
+ * Since: 0.6.0
*
**/
#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
+/**
+ * HB_TAG_NONE:
+ *
+ * Unset #hb_tag_t.
+ */
#define HB_TAG_NONE HB_TAG(0,0,0,0)
+/**
+ * HB_TAG_MAX:
+ *
+ * Maximum possible unsigned #hb_tag_t.
+ *
+ * Since: 0.9.26
+ */
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+/**
+ * HB_TAG_MAX_SIGNED:
+ *
+ * Maximum possible signed #hb_tag_t.
+ *
+ * Since: 0.9.33
+ */
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
@@ -263,6 +289,13 @@ hb_direction_to_string (hb_direction_t direction);
/* hb_language_t */
+/**
+ * hb_language_t:
+ *
+ * Data type for languages. Each #hb_language_t corresponds to a BCP 47
+ * language tag.
+ *
+ */
typedef const struct hb_language_impl_t *hb_language_t;
HB_EXTERN hb_language_t
@@ -271,6 +304,13 @@ hb_language_from_string (const char *str, int len);
HB_EXTERN const char *
hb_language_to_string (hb_language_t language);
+/**
+ * HB_LANGUAGE_INVALID:
+ *
+ * An unset #hb_language_t.
+ *
+ * Since: 0.6.0
+ */
#define HB_LANGUAGE_INVALID ((hb_language_t) 0)
HB_EXTERN hb_language_t
@@ -279,160 +319,164 @@ hb_language_get_default (void);
/**
* hb_script_t:
- * @HB_SCRIPT_COMMON: HB_TAG ('Z','y','y','y')
- * @HB_SCRIPT_INHERITED: HB_TAG ('Z','i','n','h')
- * @HB_SCRIPT_UNKNOWN: HB_TAG ('Z','z','z','z')
- * @HB_SCRIPT_ARABIC
- * @HB_SCRIPT_ARMENIAN
- * @HB_SCRIPT_BENGALI
- * @HB_SCRIPT_CYRILLIC
- * @HB_SCRIPT_DEVANAGARI
- * @HB_SCRIPT_GEORGIAN
- * @HB_SCRIPT_GREEK
- * @HB_SCRIPT_GUJARATI
- * @HB_SCRIPT_GURMUKHI
- * @HB_SCRIPT_HANGUL
- * @HB_SCRIPT_HAN
- * @HB_SCRIPT_HEBREW
- * @HB_SCRIPT_HIRAGANA
- * @HB_SCRIPT_KANNADA
- * @HB_SCRIPT_KATAKANA
- * @HB_SCRIPT_LAO
- * @HB_SCRIPT_LATIN
- * @HB_SCRIPT_MALAYALAM
- * @HB_SCRIPT_ORIYA
- * @HB_SCRIPT_TAMIL
- * @HB_SCRIPT_TELUGU
- * @HB_SCRIPT_THAI
- * @HB_SCRIPT_TIBETAN
- * @HB_SCRIPT_BOPOMOFO
- * @HB_SCRIPT_BRAILLE
- * @HB_SCRIPT_CANADIAN_SYLLABICS
- * @HB_SCRIPT_CHEROKEE
- * @HB_SCRIPT_ETHIOPIC
- * @HB_SCRIPT_KHMER
- * @HB_SCRIPT_MONGOLIAN
- * @HB_SCRIPT_MYANMAR
- * @HB_SCRIPT_OGHAM
- * @HB_SCRIPT_RUNIC
- * @HB_SCRIPT_SINHALA
- * @HB_SCRIPT_SYRIAC
- * @HB_SCRIPT_THAANA
- * @HB_SCRIPT_YI
- * @HB_SCRIPT_DESERET
- * @HB_SCRIPT_GOTHIC
- * @HB_SCRIPT_OLD_ITALIC
- * @HB_SCRIPT_BUHID
- * @HB_SCRIPT_HANUNOO
- * @HB_SCRIPT_TAGALOG
- * @HB_SCRIPT_TAGBANWA
- * @HB_SCRIPT_CYPRIOT
- * @HB_SCRIPT_LIMBU
- * @HB_SCRIPT_LINEAR_B
- * @HB_SCRIPT_OSMANYA
- * @HB_SCRIPT_SHAVIAN
- * @HB_SCRIPT_TAI_LE
- * @HB_SCRIPT_UGARITIC
- * @HB_SCRIPT_BUGINESE
- * @HB_SCRIPT_COPTIC
- * @HB_SCRIPT_GLAGOLITIC
- * @HB_SCRIPT_KHAROSHTHI
- * @HB_SCRIPT_NEW_TAI_LUE
- * @HB_SCRIPT_OLD_PERSIAN
- * @HB_SCRIPT_SYLOTI_NAGRI
- * @HB_SCRIPT_TIFINAGH
- * @HB_SCRIPT_BALINESE
- * @HB_SCRIPT_CUNEIFORM
- * @HB_SCRIPT_NKO
- * @HB_SCRIPT_PHAGS_PA
- * @HB_SCRIPT_PHOENICIAN
- * @HB_SCRIPT_CARIAN
- * @HB_SCRIPT_CHAM
- * @HB_SCRIPT_KAYAH_LI
- * @HB_SCRIPT_LEPCHA
- * @HB_SCRIPT_LYCIAN
- * @HB_SCRIPT_LYDIAN
- * @HB_SCRIPT_OL_CHIKI
- * @HB_SCRIPT_REJANG
- * @HB_SCRIPT_SAURASHTRA
- * @HB_SCRIPT_SUNDANESE
- * @HB_SCRIPT_VAI
- * @HB_SCRIPT_AVESTAN
- * @HB_SCRIPT_BAMUM
- * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS
- * @HB_SCRIPT_IMPERIAL_ARAMAIC
- * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI
- * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN
- * @HB_SCRIPT_JAVANESE
- * @HB_SCRIPT_KAITHI
- * @HB_SCRIPT_LISU
- * @HB_SCRIPT_MEETEI_MAYEK
- * @HB_SCRIPT_OLD_SOUTH_ARABIAN
- * @HB_SCRIPT_OLD_TURKIC
- * @HB_SCRIPT_SAMARITAN
- * @HB_SCRIPT_TAI_THAM
- * @HB_SCRIPT_TAI_VIET
- * @HB_SCRIPT_BATAK
- * @HB_SCRIPT_BRAHMI
- * @HB_SCRIPT_MANDAIC
- * @HB_SCRIPT_CHAKMA
- * @HB_SCRIPT_MEROITIC_CURSIVE
- * @HB_SCRIPT_MEROITIC_HIEROGLYPHS
- * @HB_SCRIPT_MIAO
- * @HB_SCRIPT_SHARADA
- * @HB_SCRIPT_SORA_SOMPENG
- * @HB_SCRIPT_TAKRI
- * @HB_SCRIPT_BASSA_VAH
- * @HB_SCRIPT_CAUCASIAN_ALBANIAN
- * @HB_SCRIPT_DUPLOYAN
- * @HB_SCRIPT_ELBASAN
- * @HB_SCRIPT_GRANTHA
- * @HB_SCRIPT_KHOJKI
- * @HB_SCRIPT_KHUDAWADI
- * @HB_SCRIPT_LINEAR_A
- * @HB_SCRIPT_MAHAJANI
- * @HB_SCRIPT_MANICHAEAN
- * @HB_SCRIPT_MENDE_KIKAKUI
- * @HB_SCRIPT_MODI
- * @HB_SCRIPT_MRO
- * @HB_SCRIPT_NABATAEAN
- * @HB_SCRIPT_OLD_NORTH_ARABIAN
- * @HB_SCRIPT_OLD_PERMIC
- * @HB_SCRIPT_PAHAWH_HMONG
- * @HB_SCRIPT_PALMYRENE
- * @HB_SCRIPT_PAU_CIN_HAU
- * @HB_SCRIPT_PSALTER_PAHLAVI
- * @HB_SCRIPT_SIDDHAM
- * @HB_SCRIPT_TIRHUTA
- * @HB_SCRIPT_WARANG_CITI
- * @HB_SCRIPT_AHOM
- * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS
- * @HB_SCRIPT_HATRAN
- * @HB_SCRIPT_MULTANI
- * @HB_SCRIPT_OLD_HUNGARIAN
- * @HB_SCRIPT_SIGNWRITING
- * @HB_SCRIPT_ADLAM
- * @HB_SCRIPT_BHAIKSUKI
- * @HB_SCRIPT_MARCHEN
- * @HB_SCRIPT_OSAGE
- * @HB_SCRIPT_TANGUT
- * @HB_SCRIPT_NEWA
- * @HB_SCRIPT_MASARAM_GONDI
- * @HB_SCRIPT_NUSHU
- * @HB_SCRIPT_SOYOMBO
- * @HB_SCRIPT_ZANABAZAR_SQUARE
- * @HB_SCRIPT_DOGRA
- * @HB_SCRIPT_GUNJALA_GONDI
- * @HB_SCRIPT_HANIFI_ROHINGYA
- * @HB_SCRIPT_MAKASAR
- * @HB_SCRIPT_MEDEFAIDRIN
- * @HB_SCRIPT_OLD_SOGDIAN
- * @HB_SCRIPT_SOGDIAN
- * @HB_SCRIPT_ELYMAIC
- * @HB_SCRIPT_NANDINAGARI
- * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG
- * @HB_SCRIPT_WANCHO
- * @HB_SCRIPT_INVALID: #HB_TAG_NONE
+ * @HB_SCRIPT_COMMON: `Zyyy`
+ * @HB_SCRIPT_INHERITED: `Zinh`
+ * @HB_SCRIPT_UNKNOWN: `Zzzz`
+ * @HB_SCRIPT_ARABIC: `Arab`
+ * @HB_SCRIPT_ARMENIAN: `Armn`
+ * @HB_SCRIPT_BENGALI: `Beng`
+ * @HB_SCRIPT_CYRILLIC: `Cyrl`
+ * @HB_SCRIPT_DEVANAGARI: `Deva`
+ * @HB_SCRIPT_GEORGIAN: `Geor`
+ * @HB_SCRIPT_GREEK: `Grek`
+ * @HB_SCRIPT_GUJARATI: `Gujr`
+ * @HB_SCRIPT_GURMUKHI: `Guru`
+ * @HB_SCRIPT_HANGUL: `Hang`
+ * @HB_SCRIPT_HAN: `Hani`
+ * @HB_SCRIPT_HEBREW: `Hebr`
+ * @HB_SCRIPT_HIRAGANA: `Hira`
+ * @HB_SCRIPT_KANNADA: `Knda`
+ * @HB_SCRIPT_KATAKANA: `Kana`
+ * @HB_SCRIPT_LAO: `Laoo`
+ * @HB_SCRIPT_LATIN: `Latn`
+ * @HB_SCRIPT_MALAYALAM: `Mlym`
+ * @HB_SCRIPT_ORIYA: `Orya`
+ * @HB_SCRIPT_TAMIL: `Taml`
+ * @HB_SCRIPT_TELUGU: `Telu`
+ * @HB_SCRIPT_THAI: `Thai`
+ * @HB_SCRIPT_TIBETAN: `Tibt`
+ * @HB_SCRIPT_BOPOMOFO: `Bopo`
+ * @HB_SCRIPT_BRAILLE: `Brai`
+ * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans`
+ * @HB_SCRIPT_CHEROKEE: `Cher`
+ * @HB_SCRIPT_ETHIOPIC: `Ethi`
+ * @HB_SCRIPT_KHMER: `Khmr`
+ * @HB_SCRIPT_MONGOLIAN: `Mong`
+ * @HB_SCRIPT_MYANMAR: `Mymr`
+ * @HB_SCRIPT_OGHAM: `Ogam`
+ * @HB_SCRIPT_RUNIC: `Runr`
+ * @HB_SCRIPT_SINHALA: `Sinh`
+ * @HB_SCRIPT_SYRIAC: `Syrc`
+ * @HB_SCRIPT_THAANA: `Thaa`
+ * @HB_SCRIPT_YI: `Yiii`
+ * @HB_SCRIPT_DESERET: `Dsrt`
+ * @HB_SCRIPT_GOTHIC: `Goth`
+ * @HB_SCRIPT_OLD_ITALIC: `Ital`
+ * @HB_SCRIPT_BUHID: `Buhd`
+ * @HB_SCRIPT_HANUNOO: `Hano`
+ * @HB_SCRIPT_TAGALOG: `Tglg`
+ * @HB_SCRIPT_TAGBANWA: `Tagb`
+ * @HB_SCRIPT_CYPRIOT: `Cprt`
+ * @HB_SCRIPT_LIMBU: `Limb`
+ * @HB_SCRIPT_LINEAR_B: `Linb`
+ * @HB_SCRIPT_OSMANYA: `Osma`
+ * @HB_SCRIPT_SHAVIAN: `Shaw`
+ * @HB_SCRIPT_TAI_LE: `Tale`
+ * @HB_SCRIPT_UGARITIC: `Ugar`
+ * @HB_SCRIPT_BUGINESE: `Bugi`
+ * @HB_SCRIPT_COPTIC: `Copt`
+ * @HB_SCRIPT_GLAGOLITIC: `Glag`
+ * @HB_SCRIPT_KHAROSHTHI: `Khar`
+ * @HB_SCRIPT_NEW_TAI_LUE: `Talu`
+ * @HB_SCRIPT_OLD_PERSIAN: `Xpeo`
+ * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo`
+ * @HB_SCRIPT_TIFINAGH: `Tfng`
+ * @HB_SCRIPT_BALINESE: `Bali`
+ * @HB_SCRIPT_CUNEIFORM: `Xsux`
+ * @HB_SCRIPT_NKO: `Nkoo`
+ * @HB_SCRIPT_PHAGS_PA: `Phag`
+ * @HB_SCRIPT_PHOENICIAN: `Phnx`
+ * @HB_SCRIPT_CARIAN: `Cari`
+ * @HB_SCRIPT_CHAM: `Cham`
+ * @HB_SCRIPT_KAYAH_LI: `Kali`
+ * @HB_SCRIPT_LEPCHA: `Lepc`
+ * @HB_SCRIPT_LYCIAN: `Lyci`
+ * @HB_SCRIPT_LYDIAN: `Lydi`
+ * @HB_SCRIPT_OL_CHIKI: `Olck`
+ * @HB_SCRIPT_REJANG: `Rjng`
+ * @HB_SCRIPT_SAURASHTRA: `Saur`
+ * @HB_SCRIPT_SUNDANESE: `Sund`
+ * @HB_SCRIPT_VAI: `Vaii`
+ * @HB_SCRIPT_AVESTAN: `Avst`
+ * @HB_SCRIPT_BAMUM: `Bamu`
+ * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp`
+ * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi`
+ * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli`
+ * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti`
+ * @HB_SCRIPT_JAVANESE: `Java`
+ * @HB_SCRIPT_KAITHI: `Kthi`
+ * @HB_SCRIPT_LISU: `Lisu`
+ * @HB_SCRIPT_MEETEI_MAYEK: `Mtei`
+ * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb`
+ * @HB_SCRIPT_OLD_TURKIC: `Orkh`
+ * @HB_SCRIPT_SAMARITAN: `Samr`
+ * @HB_SCRIPT_TAI_THAM: `Lana`
+ * @HB_SCRIPT_TAI_VIET: `Tavt`
+ * @HB_SCRIPT_BATAK: `Batk`
+ * @HB_SCRIPT_BRAHMI: `Brah`
+ * @HB_SCRIPT_MANDAIC: `Mand`
+ * @HB_SCRIPT_CHAKMA: `Cakm`
+ * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc`
+ * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero`
+ * @HB_SCRIPT_MIAO: `Plrd`
+ * @HB_SCRIPT_SHARADA: `Shrd`
+ * @HB_SCRIPT_SORA_SOMPENG: `Sora`
+ * @HB_SCRIPT_TAKRI: `Takr`
+ * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30
+ * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30
+ * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30
+ * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30
+ * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30
+ * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30
+ * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30
+ * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30
+ * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30
+ * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30
+ * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30
+ * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30
+ * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30
+ * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30
+ * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30
+ * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30
+ * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30
+ * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30
+ * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30
+ * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30
+ * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30
+ * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30
+ * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30
+ * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30
+ * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30
+ * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30
+ * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30
+ * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0
+ * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0
+ * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0
+ * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0
+ * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0
+ * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0
+ * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0
+ * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0
+ * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0
+ * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0
+ * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0
+ * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0
+ * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0
+ * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0
+ * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0
+ * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0
+ * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0
+ * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0
+ * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0
+ * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0
+ * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0
+ * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7
+ * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
+ * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
+ * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
+ * @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
* to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/).
@@ -441,208 +485,208 @@ hb_language_get_default (void);
*
**/
-/* https://unicode.org/iso15924/ */
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
-/* Unicode Character Database property: Script (sc) */
typedef enum
{
- /*1.1*/ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'),
- /*1.1*/ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'),
- /*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'),
-
- /*1.1*/ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'),
- /*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'),
- /*1.1*/ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'),
- /*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'),
- /*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'),
- /*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'),
- /*1.1*/ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'),
- /*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'),
- /*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'),
- /*1.1*/ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'),
- /*1.1*/ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'),
- /*1.1*/ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'),
- /*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'),
- /*1.1*/ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'),
- /*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'),
- /*1.1*/ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'),
- /*1.1*/ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'),
- /*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'),
- /*1.1*/ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'),
- /*1.1*/ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'),
- /*1.1*/ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'),
- /*1.1*/ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'),
-
- /*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'),
-
- /*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'),
- /*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'),
- /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'),
- /*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'),
- /*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'),
- /*3.0*/ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'),
- /*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'),
- /*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'),
- /*3.0*/ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'),
- /*3.0*/ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'),
- /*3.0*/ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'),
- /*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'),
- /*3.0*/ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'),
- /*3.0*/ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'),
-
- /*3.1*/ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'),
- /*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'),
- /*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'),
-
- /*3.2*/ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'),
- /*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'),
- /*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'),
- /*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'),
-
- /*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'),
- /*4.0*/ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'),
- /*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'),
- /*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'),
- /*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'),
- /*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'),
- /*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'),
-
- /*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'),
- /*4.1*/ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'),
- /*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'),
- /*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'),
- /*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'),
- /*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'),
- /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'),
- /*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'),
-
- /*5.0*/ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'),
- /*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'),
- /*5.0*/ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'),
- /*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'),
- /*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'),
-
- /*5.1*/ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'),
- /*5.1*/ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'),
- /*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'),
- /*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'),
- /*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'),
- /*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'),
- /*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'),
- /*5.1*/ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'),
- /*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'),
- /*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'),
- /*5.1*/ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'),
-
- /*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'),
- /*5.2*/ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'),
- /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'),
- /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'),
- /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'),
- /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'),
- /*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'),
- /*5.2*/ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'),
- /*5.2*/ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'),
- /*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'),
- /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'),
- /*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'),
- /*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'),
- /*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'),
- /*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'),
-
- /*6.0*/ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'),
- /*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'),
- /*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'),
-
- /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'),
- /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'),
- /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'),
- /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'),
- /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'),
- /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
- /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
+ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/
+ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/
+ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/
+
+ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/
+ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/
+ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/
+ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/
+ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/
+ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/
+ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/
+ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/
+ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/
+ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/
+ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/
+ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/
+ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/
+ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/
+ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/
+ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/
+ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/
+ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/
+ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/
+ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/
+ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/
+ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/
+
+ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/
+
+ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/
+ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/
+ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/
+ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/
+ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/
+ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/
+ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/
+ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/
+ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/
+ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/
+ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/
+ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/
+ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/
+ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/
+
+ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/
+ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/
+ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/
+
+ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/
+ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/
+ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/
+ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/
+
+ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/
+ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/
+ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/
+ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/
+ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/
+ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/
+ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/
+
+ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/
+ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/
+ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/
+ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/
+ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/
+ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/
+ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/
+ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/
+
+ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/
+ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/
+ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/
+ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/
+ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/
+
+ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/
+ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/
+ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/
+ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/
+ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/
+ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/
+ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/
+ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/
+ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/
+ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/
+ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/
+
+ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/
+ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/
+ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/
+ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/
+ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/
+ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/
+ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/
+ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/
+ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/
+ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/
+ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/
+ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/
+ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/
+ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/
+ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/
+
+ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/
+ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/
+ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/
+
+ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/
+ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/
+ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/
+ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/
+ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/
+ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/
+ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/
/*
* Since: 0.9.30
*/
- /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
- /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
- /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
- /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'),
- /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'),
- /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'),
- /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'),
- /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'),
- /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'),
- /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'),
- /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'),
- /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'),
- /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'),
- /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'),
- /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'),
- /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'),
- /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'),
- /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'),
- /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'),
- /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'),
- /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'),
- /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
- /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
-
- /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
- /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
- /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
- /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
- /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
- /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
+ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/
+ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/
+ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/
+ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/
+ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/
+ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/
+ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/
+ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/
+ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/
+ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/
+ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/
+ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/
+ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/
+ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/
+ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/
+ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/
+ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/
+ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/
+ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/
+ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/
+ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/
+ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/
+ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/
+
+ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/
+ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/
+ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/
+ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/
+ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/
+ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/
/*
* Since 1.3.0
*/
- /*9.0*/ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'),
- /*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'),
- /*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'),
- /*9.0*/ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'),
- /*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'),
- /*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'),
+ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/
+ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/
+ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/
+ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/
+ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/
+ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/
/*
* Since 1.6.0
*/
- /*10.0*/HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'),
- /*10.0*/HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'),
- /*10.0*/HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'),
- /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'),
+ HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/
+ HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/
+ HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/
+ HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/
/*
* Since 1.8.0
*/
- /*11.0*/HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'),
- /*11.0*/HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'),
- /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'),
- /*11.0*/HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'),
- /*11.0*/HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'),
- /*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
- /*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
+ HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/
+ HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/
+ HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/
+ HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/
+ HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/
+ HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/
+ HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/
/*
* Since 2.4.0
*/
- /*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
- /*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
- /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
- /*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
+ HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/
+ HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/
+ HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/
+ HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/
/*
* Since 2.6.7
*/
- /*13.0*/HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'),
- /*13.0*/HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'),
- /*13.0*/HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'),
- /*13.0*/HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'),
+ HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/
+ HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/
+ HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
+ HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
/* No script set. */
- HB_SCRIPT_INVALID = HB_TAG_NONE,
+ HB_SCRIPT_INVALID = HB_TAG_NONE,
+
+ /*< private >*/
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. We have two, for historical reasons.
@@ -687,19 +731,33 @@ typedef struct hb_user_data_key_t {
char unused;
} hb_user_data_key_t;
+/**
+ * hb_destroy_func_t:
+ * @user_data: the data to be destroyed
+ *
+ * A virtual method for destroy user-data callbacks.
+ *
+ */
typedef void (*hb_destroy_func_t) (void *user_data);
/* Font features and variations. */
/**
- * HB_FEATURE_GLOBAL_START
+ * HB_FEATURE_GLOBAL_START:
+ *
+ * Special setting for #hb_feature_t.start to apply the feature from the start
+ * of the buffer.
*
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_START 0
+
/**
- * HB_FEATURE_GLOBAL_END
+ * HB_FEATURE_GLOBAL_END:
+ *
+ * Special setting for #hb_feature_t.end to apply the feature from to the end
+ * of the buffer.
*
* Since: 2.0.0
*/
@@ -717,7 +775,7 @@ typedef void (*hb_destroy_func_t) (void *user_data);
* The #hb_feature_t is the structure that holds information about requested
* feature application. The feature will be applied with the given value to all
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
- * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
+ * Setting start to #HB_FEATURE_GLOBAL_START and end to #HB_FEATURE_GLOBAL_END
* specifies that the feature always applies to the entire buffer.
*/
typedef struct hb_feature_t {
@@ -741,8 +799,8 @@ hb_feature_to_string (hb_feature_t *feature,
* @value: The value of the variation axis
*
* Data type for holding variation data. Registered OpenType
- * variation-axis tags are listed at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg
+ * variation-axis tags are listed in
+ * [OpenType Axis Tag Registry](https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg).
*
* Since: 1.4.2
*/
@@ -769,6 +827,17 @@ hb_variation_to_string (hb_variation_t *variation,
*/
typedef uint32_t hb_color_t;
+/**
+ * HB_COLOR:
+ * @b: blue channel value
+ * @g: green channel value
+ * @r: red channel value
+ * @a: alpha channel value
+ *
+ * Constructs an #hb_color_t from four integers.
+ *
+ * Since: 2.1.0
+ */
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
HB_EXTERN uint8_t
diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc
index 7b6b2bd5ef..461bd20e65 100644
--- a/thirdparty/harfbuzz/src/hb-coretext.cc
+++ b/thirdparty/harfbuzz/src/hb-coretext.cc
@@ -34,7 +34,6 @@
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
-#include <math.h>
/**
@@ -190,7 +189,10 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
+#pragma GCC diagnostic pop
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
@@ -346,7 +348,7 @@ retry:
const hb_coretext_font_data_t *data = font->data.coretext;
if (unlikely (!data)) return nullptr;
- if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
+ if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5)
{
/* XXX-MT-bug
* Note that evaluating condition above can be dangerous if another thread
@@ -402,7 +404,7 @@ hb_coretext_font_create (CTFontRef ct_font)
}
/**
- * hb_coretext_face_get_ct_font:
+ * hb_coretext_font_get_ct_font:
* @font: #hb_font_t to work upon
*
* Fetches the CTFontRef associated with the specified
@@ -858,7 +860,7 @@ resize_and_retry:
buffer->len = 0;
uint32_t status_and = ~0, status_or = 0;
- double advances_so_far = 0;
+ CGFloat advances_so_far = 0;
/* For right-to-left runs, CoreText returns the glyphs positioned such that
* any trailing whitespace is to the left of (0,0). Adjust coordinate system
* to fix for that. Test with any RTL string with trailing spaces.
@@ -880,10 +882,10 @@ resize_and_retry:
status_or |= run_status;
status_and &= run_status;
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
- double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
+ CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
run_advance = -run_advance;
- DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+ DEBUG_MSG (CORETEXT, run, "Run advance: %g", (double) run_advance);
/* CoreText does automatic font fallback (AKA "cascading") for characters
* not supported by the requested font, and provides no way to turn it off,
@@ -1062,7 +1064,7 @@ resize_and_retry:
hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
for (unsigned int j = 0; j < num_glyphs; j++)
{
- double advance;
+ CGFloat advance;
if (likely (j + 1 < num_glyphs))
advance = positions[j + 1].x - positions[j].x;
else /* last glyph */
@@ -1078,7 +1080,7 @@ resize_and_retry:
hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
for (unsigned int j = 0; j < num_glyphs; j++)
{
- double advance;
+ CGFloat advance;
if (likely (j + 1 < num_glyphs))
advance = positions[j + 1].y - positions[j].y;
else /* last glyph */
diff --git a/thirdparty/harfbuzz/src/hb-deprecated.h b/thirdparty/harfbuzz/src/hb-deprecated.h
index 43f89a4c4e..5f19125789 100644
--- a/thirdparty/harfbuzz/src/hb-deprecated.h
+++ b/thirdparty/harfbuzz/src/hb-deprecated.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -53,11 +53,50 @@ HB_BEGIN_DECLS
#ifndef HB_DISABLE_DEPRECATED
+/**
+ * HB_SCRIPT_CANADIAN_ABORIGINAL:
+ *
+ * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
+/**
+ * HB_BUFFER_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
+/**
+ * HB_BUFFER_SERIALIZE_FLAGS_DEFAULT:
+ *
+ * Use #HB_BUFFER_SERIALIZE_FLAG_DEFAULT instead.
+ *
+ * Deprecated: 0.9.20
+ */
#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+/**
+ * hb_font_get_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the glyph ID for a specified Unicode code point
+ * font, with an optional variation selector.
+ *
+ * Return value: %true if data found, %false otherwise
+ * Deprecated: 1.2.3
+ *
+ **/
typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
@@ -73,6 +112,11 @@ hb_set_invert (hb_set_t *set);
/**
* hb_unicode_eastasian_width_func_t:
+ * @ufuncs: A Unicode-functions structure
+ * @unicode: The code point to query
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_unicode_funcs_t structure.
*
* Deprecated: 2.0.0
*/
@@ -82,12 +126,12 @@ typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t
/**
* hb_unicode_funcs_set_eastasian_width_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: a Unicode-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- *
+ * Sets the implementation function for #hb_unicode_eastasian_width_func_t.
*
* Since: 0.9.2
* Deprecated: 2.0.0
@@ -99,6 +143,10 @@ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
/**
* hb_unicode_eastasian_width:
+ * @ufuncs: a Unicode-function structure
+ * @unicode: The code point to query
+ *
+ * Don't use. Not used by HarfBuzz.
*
* Since: 0.9.2
* Deprecated: 2.0.0
@@ -112,7 +160,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
* hb_unicode_decompose_compatibility_func_t:
* @ufuncs: a Unicode function structure
* @u: codepoint to decompose
- * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @decomposed: address of codepoint array (of length #HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
* @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
*
* Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
@@ -120,7 +168,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
*
* If @u has no compatibility decomposition, zero should be returned.
*
- * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * The Unicode standard guarantees that a buffer of length #HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
* compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations
* of this function type must ensure that they do not write past the provided array.
*
@@ -144,10 +192,12 @@ typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_
/**
* hb_unicode_funcs_set_decompose_compatibility_func:
- * @ufuncs: a Unicode function structure
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ufuncs: A Unicode-functions structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_unicode_decompose_compatibility_func_t.
*
*
*
@@ -165,16 +215,25 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *decomposed);
+/**
+ * hb_font_get_glyph_v_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for vertical text segments.
+ *
+ **/
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
/**
* hb_font_funcs_set_glyph_v_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- *
+ * Sets the implementation function for #hb_font_get_glyph_v_kerning_func_t.
*
* Since: 0.9.2
* Deprecated: 2.0.0
diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc
index 92c956c032..a07302159c 100644
--- a/thirdparty/harfbuzz/src/hb-directwrite.cc
+++ b/thirdparty/harfbuzz/src/hb-directwrite.cc
@@ -957,6 +957,8 @@ _hb_directwrite_font_release (void *data)
* hb_directwrite_face_create:
* @font_face: a DirectWrite IDWriteFontFace object.
*
+ * Constructs a new face object from the specified DirectWrite IDWriteFontFace.
+ *
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.4.0
@@ -974,6 +976,8 @@ hb_directwrite_face_create (IDWriteFontFace *font_face)
* hb_directwrite_face_get_font_face:
* @face: a #hb_face_t object
*
+* Gets the DirectWrite IDWriteFontFace associated with @face.
+*
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
*
* Since: 2.5.0
diff --git a/thirdparty/harfbuzz/src/hb-dispatch.hh b/thirdparty/harfbuzz/src/hb-dispatch.hh
index 7eace86e54..4b2b65a8de 100644
--- a/thirdparty/harfbuzz/src/hb-dispatch.hh
+++ b/thirdparty/harfbuzz/src/hb-dispatch.hh
@@ -38,7 +38,6 @@
template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
struct hb_dispatch_context_t
{
- hb_dispatch_context_t () : debug_depth (0) {}
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
const Context* thiz () const { return static_cast<const Context *> (this); }
@@ -54,7 +53,7 @@ struct hb_dispatch_context_t
{ return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
- unsigned debug_depth;
+ unsigned debug_depth = 0;
};
diff --git a/thirdparty/harfbuzz/src/hb-draw.h b/thirdparty/harfbuzz/src/hb-draw.h
index 98eccf4c0c..bddc876399 100644
--- a/thirdparty/harfbuzz/src/hb-draw.h
+++ b/thirdparty/harfbuzz/src/hb-draw.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 33a788e7c5..61bd4af7b1 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -89,8 +89,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
nullptr, /* destroy */
0, /* index */
- HB_ATOMIC_INT_INIT (1000), /* upem */
- HB_ATOMIC_INT_INIT (0), /* num_glyphs */
+ 1000, /* upem */
+ 0, /* num_glyphs */
/* Zero for the rest is fine. */
};
@@ -100,7 +100,7 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
* hb_face_create_for_tables:
* @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function
* @user_data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
*
* Variant of hb_face_create(), built for those cases where it is more
* convenient to provide data for individual tables instead of the whole font
@@ -235,7 +235,7 @@ hb_face_create (hb_blob_t *blob,
*
* Fetches the singleton empty face object.
*
- * Return value: (transfer full) The empty face object
+ * Return value: (transfer full): The empty face object
*
* Since: 0.9.2
**/
@@ -299,7 +299,7 @@ hb_face_destroy (hb_face_t *face)
* @face: A face object
* @key: The user-data key to set
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given face object.
@@ -360,7 +360,7 @@ hb_face_make_immutable (hb_face_t *face)
*
* Tests whether the given face object is immutable.
*
- * Return value: True is @face is immutable, false otherwise
+ * Return value: %true is @face is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -756,7 +756,7 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
- if (data->tables.in_error())
+ if (unlikely (data->tables.in_error()))
return false;
entry->tag = tag;
diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h
index 3b18f7eef9..6ef2f8b886 100644
--- a/thirdparty/harfbuzz/src/hb-face.h
+++ b/thirdparty/harfbuzz/src/hb-face.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -58,6 +58,19 @@ HB_EXTERN hb_face_t *
hb_face_create (hb_blob_t *blob,
unsigned int index);
+/**
+ * hb_reference_table_func_t:
+ * @face: an #hb_face_t to reference table for
+ * @tag: the tag of the table to reference
+ * @user_data: User data pointer passed by the caller
+ *
+ * Callback function for hb_face_create_for_tables().
+ *
+ * Return value: (transfer full): A pointer to the @tag table within @face
+ *
+ * Since: 0.9.2
+ */
+
typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
/* calls destroy() when not needing user_data anymore */
diff --git a/thirdparty/harfbuzz/src/hb-face.hh b/thirdparty/harfbuzz/src/hb-face.hh
index f1b472ccf3..765f272858 100644
--- a/thirdparty/harfbuzz/src/hb-face.hh
+++ b/thirdparty/harfbuzz/src/hb-face.hh
@@ -81,7 +81,7 @@ struct hb_face_t
return blob;
}
- HB_PURE_FUNC unsigned int get_upem () const
+ unsigned int get_upem () const
{
unsigned int ret = upem.get_relaxed ();
if (unlikely (!ret))
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index 5c8357ff28..37a0e7fe85 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -628,7 +628,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
* @ffuncs: The font-functions structure
* @key: The user-data key to set
* @data: A pointer to the user data set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified font-functions structure.
@@ -690,7 +690,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
*
* Tests whether a font-functions structure is immutable.
*
- * Return value: %true if @ffuncs is immutable, false otherwise
+ * Return value: %true if @ffuncs is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -753,10 +753,10 @@ hb_font_t::has_func (unsigned int i)
* @font: #hb_font_t to work upon
* @extents: (out): The font extents retrieved
*
- * Fetches the extents for a specified font, in horizontal
+ * Fetches the extents for a specified font, for horizontal
* text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.1.3
**/
@@ -772,10 +772,10 @@ hb_font_get_h_extents (hb_font_t *font,
* @font: #hb_font_t to work upon
* @extents: (out): The font extents retrieved
*
- * Fetches the extents for a specified font, in vertical
+ * Fetches the extents for a specified font, for vertical
* text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.1.3
**/
@@ -790,7 +790,7 @@ hb_font_get_v_extents (hb_font_t *font,
* hb_font_get_glyph:
* @font: #hb_font_t to work upon
* @unicode: The Unicode code point to query
- * @variation_selector: (optional): A variation-selector code point
+ * @variation_selector: A variation-selector code point
* @glyph: (out): The glyph ID retrieved
*
* Fetches the glyph ID for a Unicode code point in the specified
@@ -799,7 +799,7 @@ hb_font_get_v_extents (hb_font_t *font,
* If @variation_selector is 0, calls hb_font_get_nominal_glyph();
* otherwise calls hb_font_get_variation_glyph().
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -827,7 +827,7 @@ hb_font_get_glyph (hb_font_t *font,
* for code points modified by variation selectors. For variation-selector
* support, user hb_font_get_variation_glyph() or use hb_font_get_glyph().
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.2.3
**/
@@ -841,11 +841,17 @@ hb_font_get_nominal_glyph (hb_font_t *font,
/**
* hb_font_get_nominal_glyphs:
- * @font: a font.
- *
+ * @font: #hb_font_t to work upon
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @glyph_stride: The stride between successive glyph IDs
*
+ * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
+ * IDs must be returned in a #hb_codepoint_t output parameter.
*
- * Return value:
+ * Return value: the number of code points processed
*
* Since: 2.6.3
**/
@@ -873,7 +879,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font,
* by the specified variation-selector code point, in the specified
* font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.2.3
**/
@@ -931,7 +937,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
* @first_glyph: The first glyph ID to query
* @glyph_stride: The stride between successive glyph IDs
* @first_advance: (out): The first advance retrieved
- * @advance_stride: (out): The stride between successive advances
+ * @advance_stride: The stride between successive advances
*
* Fetches the advances for a sequence of glyph IDs in the specified
* font, for horizontal text segments.
@@ -983,7 +989,7 @@ hb_font_get_glyph_v_advances (hb_font_t* font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for horizontal text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1006,7 +1012,7 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
* Fetches the (X,Y) coordinates of the origin for a glyph ID
* in the specified font, for vertical text segments.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1026,7 +1032,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
* @right_glyph: The glyph ID of the right glyph in the glyph pair
*
* Fetches the kerning-adjustment value for a glyph-pair in
- * the specified font, in horizontal text segments.
+ * the specified font, for horizontal text segments.
*
* <note>It handles legacy kerning only (as returned by the corresponding
* #hb_font_funcs_t function).</note>
@@ -1051,7 +1057,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
* @bottom_glyph: The glyph ID of the bottom glyph in the glyph pair
*
* Fetches the kerning-adjustment value for a glyph-pair in
- * the specified font, in vertical text segments.
+ * the specified font, for vertical text segments.
*
* <note>It handles legacy kerning only (as returned by the corresponding
* #hb_font_funcs_t function).</note>
@@ -1079,7 +1085,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
* Fetches the #hb_glyph_extents_t data for a glyph ID
* in the specified font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1102,7 +1108,7 @@ hb_font_get_glyph_extents (hb_font_t *font,
* Fetches the (x,y) coordinates of a specified contour-point index
* in the specified glyph, within the specified font.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1125,7 +1131,7 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
*
* Fetches the glyph-name string for a glyph ID in the specified @font.
*
- * Return value: %true if data found, zero otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1149,7 +1155,7 @@ hb_font_get_glyph_name (hb_font_t *font,
*
* <note>Note: @len == -1 means the name string is null-terminated.</note>
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1169,7 +1175,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* hb_font_get_extents_for_direction:
* @font: #hb_font_t to work upon
* @direction: The direction of the text segment
- * @extents: (out): The #hb_glyph_extents_t retrieved
+ * @extents: (out): The #hb_font_extents_t retrieved
*
* Fetches the extents for a font in a text segment of the
* specified direction.
@@ -1364,7 +1370,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1393,7 +1399,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
* Calls the appropriate direction-specific variant (horizontal
* or vertical) depending on the value of @direction.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1444,7 +1450,7 @@ hb_font_glyph_to_string (hb_font_t *font,
*
* <note>Note: @len == -1 means the string is null-terminated.</note>
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.2
**/
@@ -1664,12 +1670,12 @@ hb_font_destroy (hb_font_t *font)
* @font: #hb_font_t to work upon
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified font object.
*
- * Return value:
+ * Return value: %true if success, %false otherwise
*
* Since: 0.9.2
**/
@@ -1728,7 +1734,7 @@ hb_font_make_immutable (hb_font_t *font)
*
* Tests whether a font object is immutable.
*
- * Return value: %true if @font is immutable, false otherwise
+ * Return value: %true if @font is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -1828,9 +1834,9 @@ hb_font_get_face (hb_font_t *font)
/**
* hb_font_set_funcs:
* @font: #hb_font_t to work upon
- * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @klass: (closure font_data) (destroy destroy) (scope notified): The font-functions structure.
* @font_data: Data to attach to @font
- * @destroy: (optional): The function to call when @font_data is not needed anymore
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
*
* Replaces the font-functions structure attached to a font, updating
* the font's user-data with @font-data and the @destroy callback.
@@ -1867,7 +1873,7 @@ hb_font_set_funcs (hb_font_t *font,
* hb_font_set_funcs_data:
* @font: #hb_font_t to work upon
* @font_data: (destroy destroy) (scope notified): Data to attach to @font
- * @destroy: (optional): The function to call when @font_data is not needed anymore
+ * @destroy: (nullable): The function to call when @font_data is not needed anymore
*
* Replaces the user data attached to a font, updating the font's
* @destroy callback.
@@ -2212,10 +2218,14 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
#ifdef HB_EXPERIMENTAL_API
/**
* hb_font_get_var_coords_design:
+ * @font: #hb_font_t to work upon
+ * @length: (out): number of coordinates
*
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
+ * Return value: coordinates array
+ *
* Since: EXPERIMENTAL
*/
const float *
@@ -2319,7 +2329,7 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font,
* @ffuncs: The font-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): callback function
* @user_data: data to pass to @func
- * @destroy: (optional): function to call when @user_data is not needed anymore
+ * @destroy: (nullable): function to call when @user_data is not needed anymore
*
* Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and
* hb_font_funcs_set_variation_glyph_func() instead.
diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h
index 05f6c03f47..15dc126523 100644
--- a/thirdparty/harfbuzz/src/hb-font.h
+++ b/thirdparty/harfbuzz/src/hb-font.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -37,7 +37,12 @@
HB_BEGIN_DECLS
-
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
typedef struct hb_font_t hb_font_t;
@@ -141,6 +146,16 @@ typedef struct hb_glyph_extents_t {
/* func types */
+/**
+ * hb_font_get_font_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @extents: (out): The font extents retrieved
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the extents for a font.
+ *
+ **/
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
hb_font_extents_t *extents,
void *user_data);
@@ -150,7 +165,7 @@ typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *fon
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
- * This method should retrieve the extents for a font, in horizontal-direction
+ * This method should retrieve the extents for a font, for horizontal-direction
* text segments. Extents must be returned in an #hb_glyph_extents output
* parameter.
*
@@ -162,7 +177,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
- * This method should retrieve the extents for a font, in vertical-direction
+ * This method should retrieve the extents for a font, for vertical-direction
* text segments. Extents must be returned in an #hb_glyph_extents output
* parameter.
*
@@ -172,12 +187,19 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
/**
* hb_font_get_nominal_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the nominal glyph ID for a specified Unicode code
* point. Glyph IDs must be returned in a #hb_codepoint_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode,
@@ -186,6 +208,12 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
/**
* hb_font_get_variation_glyph_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @unicode: The Unicode code point to query
+ * @variation_selector: The variation-selector code point to query
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -193,6 +221,8 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo
* followed by a specified Variation Selector code point. Glyph IDs must be
* returned in a #hb_codepoint_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@@ -202,12 +232,22 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *
/**
* hb_font_get_nominal_glyphs_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: number of code points to query
+ * @first_unicode: The first Unicode code point to query
+ * @unicode_stride: The stride between successive code points
+ * @first_glyph: (out): The first glyph ID retrieved
+ * @glyph_stride: The stride between successive glyph IDs
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the nominal glyph IDs for a sequence of
* Unicode code points. Glyph IDs must be returned in a #hb_codepoint_t
* output parameter.
+ *
+ * Return value: the number of code points processed
*
**/
typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
@@ -220,12 +260,18 @@ typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void
/**
* hb_font_get_glyph_advance_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the advance for a specified glyph. The
* method must return an #hb_position_t.
*
+ * Return value: The advance of @glyph within @font
+ *
**/
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -257,6 +303,14 @@ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
/**
* hb_font_get_glyph_advances_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @count: The number of glyph IDs in the sequence queried
+ * @first_glyph: The first glyph ID to query
+ * @glyph_stride: The stride between successive glyph IDs
+ * @first_advance: (out): The first advance retrieved
+ * @advance_stride: The stride between successive advances
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -295,12 +349,20 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
/**
* hb_font_get_glyph_origin_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @x: (out): The X coordinate of the origin
+ * @y: (out): The Y coordinate of the origin
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
* origin for a glyph. Each coordinate must be returned in an #hb_position_t
* output parameter.
+ *
+ * Return value: %true if data found, %false otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
@@ -314,7 +376,7 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
- * origin for a glyph, in horizontal-direction text segments. Each
+ * origin for a glyph, for horizontal-direction text segments. Each
* coordinate must be returned in an #hb_position_t output parameter.
*
**/
@@ -326,25 +388,53 @@ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the (X,Y) coordinates (in font units) of the
- * origin for a glyph, in vertical-direction text segments. Each coordinate
+ * origin for a glyph, for vertical-direction text segments. Each coordinate
* must be returned in an #hb_position_t output parameter.
*
**/
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
+/**
+ * hb_font_get_glyph_kerning_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @first_glyph: The glyph ID of the first glyph in the glyph pair
+ * @second_glyph: The glyph ID of the second glyph in the glyph pair
+ * @user_data: User data pointer passed by the caller
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
+/**
+ * hb_font_get_glyph_h_kerning_func_t:
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * This method should retrieve the kerning-adjustment value for a glyph-pair in
+ * the specified font, for horizontal text segments.
+ *
+ **/
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
/**
* hb_font_get_glyph_extents_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @extents: (out): The #hb_glyph_extents_t retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the extents for a specified glyph. Extents must be
* returned in an #hb_glyph_extents output parameter.
+ *
+ * Return value: %true if data found, %false otherwise
*
**/
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
@@ -354,6 +444,13 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
/**
* hb_font_get_glyph_contour_point_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @point_index: The contour-point index to query
+ * @x: (out): The X value retrieved for the contour point
+ * @y: (out): The Y value retrieved for the contour point
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
@@ -361,6 +458,8 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo
* specified contour point in a glyph. Each coordinate must be returned as
* an #hb_position_t output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph, unsigned int point_index,
@@ -370,12 +469,20 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo
/**
* hb_font_get_glyph_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @name: (out) (array length=size): Name string retrieved for the glyph ID
+ * @size: Length of the glyph-name string retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the glyph name that corresponds to a
* glyph ID. The name should be returned in a string output parameter.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -384,12 +491,20 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_
/**
* hb_font_get_glyph_from_name_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @name: (array length=len): The name string to query
+ * @len: The length of the name queried
+ * @glyph: (out): The glyph ID retrieved
+ * @user_data: User data pointer passed by the caller
*
* A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
*
* This method should retrieve the glyph ID that corresponds to a glyph-name
* string.
*
+ * Return value: %true if data found, %false otherwise
+ *
**/
typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
const char *name, int len, /* -1 means nul-terminated */
@@ -404,7 +519,7 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_font_h_extents_func_t.
*
@@ -420,7 +535,7 @@ hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_font_v_extents_func_t.
*
@@ -436,7 +551,7 @@ hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_nominal_glyph_func_t.
*
@@ -452,7 +567,7 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_nominal_glyphs_func_t.
*
@@ -468,7 +583,7 @@ hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_variation_glyph_func_t.
*
@@ -484,7 +599,7 @@ hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_advance_func_t.
*
@@ -500,7 +615,7 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_advance_func_t.
*
@@ -516,7 +631,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_advances_func_t.
*
@@ -532,7 +647,7 @@ hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_advances_func_t.
*
@@ -548,7 +663,7 @@ hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_h_origin_func_t.
*
@@ -564,7 +679,7 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_v_origin_func_t.
*
@@ -577,12 +692,12 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
/**
* hb_font_funcs_set_glyph_h_kerning_func:
- * @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
- *
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
+ * Sets the implementation function for #hb_font_get_glyph_h_kerning_func_t.
*
* Since: 0.9.2
**/
@@ -596,7 +711,7 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_extents_func_t.
*
@@ -612,7 +727,7 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_contour_point_func_t.
*
@@ -628,7 +743,7 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_name_func_t.
*
@@ -644,7 +759,7 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_font_get_glyph_from_name_func_t.
*
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index ab7d6146ce..b82c1a67bd 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -84,7 +84,7 @@ struct hb_ft_font_t
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
- mutable hb_atomic_int_t cached_x_scale;
+ mutable int cached_x_scale;
mutable hb_advance_cache_t advance_cache;
};
@@ -101,7 +101,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
- ft_font->cached_x_scale.set_relaxed (0);
+ ft_font->cached_x_scale = 0;
ft_font->advance_cache.init ();
return ft_font;
@@ -179,13 +179,13 @@ hb_ft_font_get_load_flags (hb_font_t *font)
}
/**
- * hb_ft_get_face:
+ * hb_ft_font_get_face:
* @font: #hb_font_t to work upon
*
* Fetches the FT_Face associated with the specified #hb_font_t
* font object.
*
- * Return value: the FT_Face found
+ * Return value: (nullable): the FT_Face found or %NULL
*
* Since: 0.9.2
**/
@@ -202,11 +202,12 @@ hb_ft_font_get_face (hb_font_t *font)
/**
* hb_ft_font_lock_face:
- * @font:
- *
+ * @font: #hb_font_t to work upon
*
+ * Gets the FT_Face associated with @font, This face will be kept around until
+ * you call hb_ft_font_unlock_face().
*
- * Return value:
+ * Return value: (nullable): the FT_Face associated with @font or %NULL
* Since: 2.6.5
**/
FT_Face
@@ -224,11 +225,10 @@ hb_ft_font_lock_face (hb_font_t *font)
/**
* hb_ft_font_unlock_face:
- * @font:
- *
+ * @font: #hb_font_t to work upon
*
+ * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
*
- * Return value:
* Since: 2.6.5
**/
void
@@ -335,10 +335,10 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
int load_flags = ft_font->load_flags;
int mult = font->x_scale < 0 ? -1 : +1;
- if (font->x_scale != ft_font->cached_x_scale.get ())
+ if (font->x_scale != ft_font->cached_x_scale)
{
ft_font->advance_cache.clear ();
- ft_font->cached_x_scale.set (font->x_scale);
+ ft_font->cached_x_scale = font->x_scale;
}
for (unsigned int i = 0; i < count; i++)
@@ -661,7 +661,7 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
/**
* hb_ft_face_create:
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
- * @destroy: (optional): A callback to call when the face object is not needed anymore
+ * @destroy: (nullable): A callback to call when the face object is not needed anymore
*
* Creates an #hb_face_t face object from the specified FT_Face.
*
@@ -771,13 +771,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
/**
* hb_ft_font_create:
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
- * @destroy: (optional): A callback to call when the font object is not needed anymore
+ * @destroy: (nullable): A callback to call when the font object is not needed anymore
*
* Creates an #hb_font_t font object from the specified FT_Face.
*
* <note>Note: You must set the face size on @ft_face before calling
- * hb_ft_font_create() on it. Otherwise, HarfBuzz will not pick up
- * the face size.</note>
+ * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
+ * access `size` member of FT_Face unconditionally.</note>
*
* This variant of the function does not provide any life-cycle management.
*
@@ -814,7 +814,7 @@ hb_ft_font_create (FT_Face ft_face,
}
/**
- * hb_ft_font_has_changed:
+ * hb_ft_font_changed:
* @font: #hb_font_t to work upon
*
* Refreshes the state of @font when the underlying FT_Face has changed.
@@ -884,8 +884,8 @@ hb_ft_font_changed (hb_font_t *font)
* Creates an #hb_font_t font object from the specified FT_Face.
*
* <note>Note: You must set the face size on @ft_face before calling
- * hb_ft_font_create_references() on it. Otherwise, HarfBuzz will not pick up
- * the face size.</note>
+ * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
+ * and will access `size` member of FT_Face unconditionally.</note>
*
* This is the preferred variant of the hb_ft_font_create*
* function family, because it calls FT_Reference_Face() on @ft_face,
diff --git a/thirdparty/harfbuzz/src/hb-gdi.cc b/thirdparty/harfbuzz/src/hb-gdi.cc
index 3a67cef160..dc4659c7f6 100644
--- a/thirdparty/harfbuzz/src/hb-gdi.cc
+++ b/thirdparty/harfbuzz/src/hb-gdi.cc
@@ -70,6 +70,8 @@ fail:
* hb_gdi_face_create:
* @hfont: a HFONT object.
*
+ * Constructs a new face object from the specified GDI HFONT.
+ *
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.6.0
diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.h b/thirdparty/harfbuzz/src/hb-gobject-structs.h
index 6fad8d7019..63467f80df 100644
--- a/thirdparty/harfbuzz/src/hb-gobject-structs.h
+++ b/thirdparty/harfbuzz/src/hb-gobject-structs.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_GOBJECT_H_IN
+#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-gobject.h> instead."
#endif
@@ -40,47 +40,22 @@ HB_BEGIN_DECLS
/* Object types */
-/**
- * hb_gobject_blob_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_blob_get_type (void);
#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
-/**
- * hb_gobject_buffer_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_buffer_get_type (void);
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
-/**
- * hb_gobject_face_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
-/**
- * hb_gobject_font_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_font_get_type (void);
#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
-/**
- * hb_gobject_font_funcs_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_font_funcs_get_type (void);
#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
@@ -97,11 +72,6 @@ HB_EXTERN GType
hb_gobject_shape_plan_get_type (void);
#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
-/**
- * hb_gobject_unicode_funcs_get_type:
- *
- * Since: 0.9.2
- **/
HB_EXTERN GType
hb_gobject_unicode_funcs_get_type (void);
#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc
index d8a72dc2f1..9dafe654c8 100644
--- a/thirdparty/harfbuzz/src/hb-graphite2.cc
+++ b/thirdparty/harfbuzz/src/hb-graphite2.cc
@@ -195,6 +195,11 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_graphite2_font_get_gr_font:
+ * @font: An #hb_font_t
+ *
+ * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead.
+ *
+ * Return value: (nullable): Graphite2 font associated with @font.
*
* Since: 0.9.10
* Deprecated: 1.4.2
@@ -284,7 +289,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
return true;
}
- buffer->ensure (glyph_count);
+ (void) buffer->ensure (glyph_count);
scratch = buffer->get_scratch_buffer (&scratch_size);
while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh
index 981c5c218c..f7018150e4 100644
--- a/thirdparty/harfbuzz/src/hb-iter.hh
+++ b/thirdparty/harfbuzz/src/hb-iter.hh
@@ -922,7 +922,7 @@ HB_FUNCOBJ (hb_none);
template <typename C, typename V,
hb_requires (hb_is_iterable (C))>
inline void
-hb_fill (C& c, const V &v)
+hb_fill (C&& c, const V &v)
{
for (auto i = hb_iter (c); i; i++)
*i = v;
diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh
index 54bc60d4c8..3bd5a979b0 100644
--- a/thirdparty/harfbuzz/src/hb-machinery.hh
+++ b/thirdparty/harfbuzz/src/hb-machinery.hh
@@ -80,6 +80,11 @@ static inline Type& StructAfter(TObject &X)
* Size checking
*/
+/* Size signifying variable-sized array */
+#ifndef HB_VAR_ARRAY
+#define HB_VAR_ARRAY 1
+#endif
+
/* Check _assertion in a method environment */
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
void _instance_assertion_on_line_##_line () const \
diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc
index f898bd8f92..f115da2bb8 100644
--- a/thirdparty/harfbuzz/src/hb-map.cc
+++ b/thirdparty/harfbuzz/src/hb-map.cc
@@ -117,7 +117,7 @@ hb_map_destroy (hb_map_t *map)
* @map: A map
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified map.
@@ -162,7 +162,7 @@ hb_map_get_user_data (hb_map_t *map,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, false otherwise
+ * Return value: %true if allocation succeeded, %false otherwise
*
* Since: 1.7.7
**/
@@ -230,7 +230,7 @@ hb_map_del (hb_map_t *map,
*
* Tests whether @key is an element of @map.
*
- * Return value: %true if @key is found in @map, false otherwise
+ * Return value: %true if @key is found in @map, %false otherwise
*
* Since: 1.7.7
**/
@@ -253,6 +253,9 @@ hb_map_has (const hb_map_t *map,
void
hb_map_clear (hb_map_t *map)
{
+ if (unlikely (hb_object_is_immutable (map)))
+ return;
+
return map->clear ();
}
diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h
index 0c19ac8fb5..6a45a7bdd5 100644
--- a/thirdparty/harfbuzz/src/hb-map.h
+++ b/thirdparty/harfbuzz/src/hb-map.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,7 +36,11 @@
HB_BEGIN_DECLS
-/*
+/**
+ * HB_MAP_VALUE_INVALID:
+ *
+ * Unset #hb_map_t value.
+ *
* Since: 1.7.7
*/
#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh
index 92c1bd67e5..84fe1d549b 100644
--- a/thirdparty/harfbuzz/src/hb-map.hh
+++ b/thirdparty/harfbuzz/src/hb-map.hh
@@ -97,8 +97,6 @@ struct hb_hashmap_t
void reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
successful = true;
clear ();
}
@@ -171,8 +169,6 @@ struct hb_hashmap_t
void clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
if (items)
for (auto &_ : hb_iter (items, mask + 1))
_.clear ();
@@ -181,6 +177,7 @@ struct hb_hashmap_t
}
bool is_empty () const { return population == 0; }
+ explicit operator bool () const { return !is_empty (); }
unsigned int get_population () const { return population; }
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 4c0898b1b7..e40d9fd178 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -49,6 +49,10 @@ template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
using hb_true_type = hb_bool_constant<true>;
using hb_false_type = hb_bool_constant<false>;
+/* Static-assert as expression. */
+template <bool cond> struct static_assert_expr;
+template <> struct static_assert_expr<true> : hb_false_type {};
+#define static_assert_expr(C) static_assert_expr<C>::value
/* Basic type SFINAE. */
@@ -220,6 +224,8 @@ struct hb_reference_wrapper<T&>
};
+/* Type traits */
+
template <typename T>
using hb_is_integral = hb_bool_constant<
hb_is_same (hb_decay<T>, char) ||
@@ -292,6 +298,15 @@ template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigne
#define hb_int_max(T) hb_int_max<T>::value
+/* Class traits. */
+
+#define HB_DELETE_COPY_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
+#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
+ TypeName() = delete; \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete
template <typename T, typename>
struct _hb_is_destructible : hb_false_type {};
diff --git a/thirdparty/harfbuzz/src/hb-mutex.hh b/thirdparty/harfbuzz/src/hb-mutex.hh
index 56392d049b..2fc8d7ee58 100644
--- a/thirdparty/harfbuzz/src/hb-mutex.hh
+++ b/thirdparty/harfbuzz/src/hb-mutex.hh
@@ -73,24 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
-
-#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
-# include <sched.h>
-# define HB_SCHED_YIELD() sched_yield ()
-#else
-# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
-#endif
-
-/* This actually is not a totally awful implementation. */
-typedef volatile int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT 0
-#define hb_mutex_impl_init(M) *(M) = 0
-#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
-#define hb_mutex_impl_unlock(M) __sync_lock_release (M)
-#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
-
-
#elif defined(HB_NO_MT)
typedef int hb_mutex_impl_t;
diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh
index 39845a70e7..f3048b1c3e 100644
--- a/thirdparty/harfbuzz/src/hb-object.hh
+++ b/thirdparty/harfbuzz/src/hb-object.hh
@@ -140,9 +140,7 @@ struct hb_lockable_set_t
* Reference-count.
*/
-#define HB_REFERENCE_COUNT_INERT_VALUE 0
-#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
-#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)}
+#define HB_REFERENCE_COUNT_INIT {0}
struct hb_reference_count_t
{
@@ -152,9 +150,9 @@ struct hb_reference_count_t
int get_relaxed () const { return ref_count.get_relaxed (); }
int inc () const { return ref_count.inc (); }
int dec () const { return ref_count.dec (); }
- void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
+ void fini () { ref_count.set_relaxed (-0x0000DEAD); }
- bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
+ bool is_inert () const { return !ref_count.get_relaxed (); }
bool is_valid () const { return ref_count.get_relaxed () > 0; }
};
@@ -197,15 +195,10 @@ struct hb_user_data_array_t
struct hb_object_header_t
{
hb_reference_count_t ref_count;
- mutable hb_atomic_int_t writable;
+ mutable hb_atomic_int_t writable = 0;
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
};
-#define HB_OBJECT_HEADER_STATIC \
- { \
- HB_REFERENCE_COUNT_INIT, \
- HB_ATOMIC_INT_INIT (false), \
- HB_ATOMIC_PTR_INIT (nullptr) \
- }
+#define HB_OBJECT_HEADER_STATIC {}
/*
diff --git a/thirdparty/harfbuzz/src/hb-open-file.hh b/thirdparty/harfbuzz/src/hb-open-file.hh
index ac13dd23c3..54c07ff13c 100644
--- a/thirdparty/harfbuzz/src/hb-open-file.hh
+++ b/thirdparty/harfbuzz/src/hb-open-file.hh
@@ -48,7 +48,7 @@ namespace OT {
*/
struct OpenTypeFontFile;
-struct OffsetTable;
+struct OpenTypeOffsetTable;
struct TTCHeader;
@@ -78,7 +78,7 @@ typedef struct TableRecord
DEFINE_SIZE_STATIC (16);
} OpenTypeTable;
-typedef struct OffsetTable
+typedef struct OpenTypeOffsetTable
{
friend struct OpenTypeFontFile;
@@ -218,7 +218,7 @@ struct TTCHeaderVersion1
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
- LArrayOf<LOffsetTo<OffsetTable>>
+ LArrayOf<LOffsetTo<OpenTypeOffsetTable>>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index 99634b76f0..dc0ae1d989 100644
--- a/thirdparty/harfbuzz/src/hb-open-type.hh
+++ b/thirdparty/harfbuzz/src/hb-open-type.hh
@@ -53,14 +53,19 @@ namespace OT {
*/
/* Integer types in big-endian order and no alignment requirement */
-template <typename Type, unsigned int Size>
+template <typename Type,
+ unsigned int Size = sizeof (Type)>
struct IntType
{
typedef Type type;
- typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
- IntType& operator = (wide_type i) { v = i; return *this; }
- operator wide_type () const { return v; }
+ IntType () = default;
+ explicit constexpr IntType (Type V) : v {V} {}
+ IntType& operator = (Type i) { v = i; return *this; }
+ /* For reason we define cast out operator for signed/unsigned, instead of Type, see:
+ * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */
+ operator hb_conditional<hb_is_signed (Type), signed, unsigned> () const { return v; }
+
bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
bool operator != (const IntType &o) const { return !(*this == o); }
@@ -80,14 +85,21 @@ struct IntType
return pb->cmp (*pa);
}
- template <typename Type2>
+ template <typename Type2,
+ hb_enable_if (hb_is_integral (Type2) &&
+ sizeof (Type2) < sizeof (int) &&
+ sizeof (Type) < sizeof (int))>
int cmp (Type2 a) const
{
Type b = v;
- if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int))
- return (int) a - (int) b;
- else
- return a < b ? -1 : a == b ? 0 : +1;
+ return (int) a - (int) b;
+ }
+ template <typename Type2,
+ hb_enable_if (hb_is_convertible (Type2, Type))>
+ int cmp (Type2 a) const
+ {
+ Type b = v;
+ return a < b ? -1 : a == b ? 0 : +1;
}
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -100,12 +112,12 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
-typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */
-typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */
-typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */
-typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */
-typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */
-typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */
+typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
+typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
+typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
+typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
+typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
+typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
* Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
@@ -163,8 +175,8 @@ struct Tag : HBUINT32
{
Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
/* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
- operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
- operator char* () { return reinterpret_cast<char *> (&this->v); }
+ operator const char* () const { return reinterpret_cast<const char *> (this); }
+ operator char* () { return reinterpret_cast<char *> (this); }
public:
DEFINE_SIZE_STATIC (4);
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
index e5286cd792..864a27f458 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh
@@ -183,7 +183,7 @@ struct CFFIndex
else
{
serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; }));
- for (const byte_str_t &_ : +it)
+ for (const auto &_ : +it)
_.copy (c);
}
return_trace (true);
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
index 66b9c8c907..3298fa35ae 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc
@@ -426,7 +426,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
else
{
extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
- extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
+ extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing;
}
if (bounds.min.y >= bounds.max.y)
{
@@ -436,7 +436,7 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
else
{
extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
- extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
+ extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing;
}
return true;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
index ac0feeee21..879b7cdb23 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc
@@ -127,7 +127,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
else
{
extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
- extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
+ extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing;
}
if (param.min_y >= param.max_y)
{
@@ -137,7 +137,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
else
{
extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
- extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
+ extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing;
}
return true;
diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
index cc48379bb8..878e02ff17 100644
--- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
@@ -95,7 +95,7 @@ struct CmapSubtableFormat4
HBUINT16 *endCode = c->start_embed<HBUINT16> ();
hb_codepoint_t prev_endcp = 0xFFFF;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first)
{
@@ -131,7 +131,7 @@ struct CmapSubtableFormat4
HBUINT16 *startCode = c->start_embed<HBUINT16> ();
hb_codepoint_t prev_cp = 0xFFFF;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (prev_cp == 0xFFFF || prev_cp + 1u != _.first)
{
@@ -170,7 +170,7 @@ struct CmapSubtableFormat4
if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size)
return nullptr;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (_.first == startCode[i])
{
@@ -696,7 +696,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
hb_codepoint_t glyphID = 0;
- for (const hb_item_type<Iterator> _ : +it)
+ for (const auto& _ : +it)
{
if (startCharCode == 0xFFFF)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
index aaa1c37c64..e285acec3d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
@@ -455,8 +455,8 @@ struct IndexSubtableRecord
unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;
// Set to invalid state to indicate filling glyphs is not yet started.
- if (unlikely (!records->resize (records->length + 1)))
- return_trace (c->serializer->check_success (false));
+ if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
+ return_trace (false);
(*records)[records->length - 1].firstGlyphIndex = 1;
(*records)[records->length - 1].lastGlyphIndex = 0;
@@ -567,8 +567,8 @@ struct IndexSubtableArray
hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
build_lookup (c, bitmap_size_context, &lookup);
- if (unlikely (lookup.in_error ()))
- return c->serializer->check_success (false);
+ if (unlikely (!c->serializer->propagate_error (lookup)))
+ return false;
bitmap_size_context->size = 0;
bitmap_size_context->num_tables = 0;
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
index 92a49bb4f4..e2a1ff4662 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
@@ -214,7 +214,7 @@ struct COLR
if (unlikely (!old_record))
return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
- BaseGlyphRecord new_record;
+ BaseGlyphRecord new_record = {};
new_record.glyphId = new_gid;
new_record.numLayers = old_record->numLayers;
return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
diff --git a/thirdparty/harfbuzz/src/hb-ot-color.cc b/thirdparty/harfbuzz/src/hb-ot-color.cc
index 0e7203a88b..4170b71317 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-color.cc
@@ -37,9 +37,6 @@
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
-#include <stdlib.h>
-#include <string.h>
-
/**
* SECTION:hb-ot-color
@@ -64,7 +61,7 @@
*
* Tests whether a face includes a `CPAL` color-palette table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
@@ -195,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
*
* Tests whether a face includes any `COLR` color layers.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
@@ -242,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
*
* Tests whether a face includes any `SVG` glyph images.
*
- * Return value: true if data found, false otherwise.
+ * Return value: %true if data found, %false otherwise.
*
* Since: 2.1.0
*/
@@ -280,7 +277,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
*
* Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.1.0
*/
diff --git a/thirdparty/harfbuzz/src/hb-ot-color.h b/thirdparty/harfbuzz/src/hb-ot-color.h
index 4f37a4386f..c23ce4de44 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color.h
+++ b/thirdparty/harfbuzz/src/hb-ot-color.h
@@ -26,7 +26,7 @@
* Google Author(s): Sascha Brawer, Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -66,6 +66,8 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
* palette is appropriate to use when displaying the font on a dark background such as black.
*
+ * Flags that describe the properties of color palette.
+ *
* Since: 2.1.0
*/
typedef enum { /*< flags >*/
@@ -95,6 +97,8 @@ hb_ot_color_has_layers (hb_face_t *face);
/**
* hb_ot_color_layer_t:
+ * @glyph: the glyph ID of the layer
+ * @color_index: the palette color index of the layer
*
* Pairs of glyph and color index.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-deprecated.h b/thirdparty/harfbuzz/src/hb-ot-deprecated.h
index 2e75deef2d..ce6b6fef11 100644
--- a/thirdparty/harfbuzz/src/hb-ot-deprecated.h
+++ b/thirdparty/harfbuzz/src/hb-ot-deprecated.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -41,6 +41,13 @@ HB_BEGIN_DECLS
/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
+/**
+ * HB_MATH_GLYPH_PART_FLAG_EXTENDER:
+ *
+ * Use #HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER instead.
+ *
+ * Deprecated: 2.5.1
+ */
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
@@ -71,6 +78,8 @@ hb_ot_tag_from_language (hb_language_t language);
/**
* HB_OT_VAR_NO_AXIS_INDEX:
*
+ * Do not use.
+ *
* Since: 1.4.2
* Deprecated: 2.2.0
*/
@@ -78,6 +87,13 @@ hb_ot_tag_from_language (hb_language_t language);
/**
* hb_ot_var_axis_t:
+ * @tag: axis tag
+ * @name_id: axis name identifier
+ * @min_value: minimum value of the axis
+ * @default_value: default value of the axis
+ * @max_value: maximum value of the axis
+ *
+ * Use #hb_ot_var_axis_info_t instead.
*
* Since: 1.4.2
* Deprecated: 2.2.0
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.h b/thirdparty/harfbuzz/src/hb-ot-font.h
index 80eaa54b1a..e7959d1ae2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.h
+++ b/thirdparty/harfbuzz/src/hb-ot-font.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
index 5470bd96da..5352156f02 100644
--- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
@@ -186,7 +186,7 @@ struct glyf
| hb_map (&SubsetGlyph::padded_size)
;
- if (c->serializer->in_error ()) return_trace (false);
+ if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
padded_offsets)));
}
@@ -944,9 +944,9 @@ struct glyf
return;
}
extents->x_bearing = font->em_scalef_x (min_x);
- extents->width = font->em_scalef_x (max_x - min_x);
+ extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
extents->y_bearing = font->em_scalef_y (max_y);
- extents->height = font->em_scalef_y (min_y - max_y);
+ extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
}
protected:
diff --git a/thirdparty/harfbuzz/src/hb-ot-head-table.hh b/thirdparty/harfbuzz/src/hb-ot-head-table.hh
index 5613a96dbf..ac588e3af6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-head-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-head-table.hh
@@ -43,7 +43,7 @@ namespace OT {
struct head
{
- friend struct OffsetTable;
+ friend struct OpenTypeOffsetTable;
static constexpr hb_tag_t tableTag = HB_OT_TAG_head;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 6ab950a322..0ba7e3c061 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -1128,7 +1128,7 @@ struct Lookup
out->lookupType = lookupType;
out->lookupFlag = lookupFlag;
- const hb_set_t *glyphset = c->plan->glyphset ();
+ const hb_set_t *glyphset = c->plan->glyphset_gsub ();
unsigned int lookup_type = get_type ();
+ hb_iter (get_subtables <TSubTable> ())
| hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
@@ -1251,8 +1251,9 @@ struct CoverageFormat1
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = glyphArray.len;
+ const HBGlyphID *arr = glyphArray.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (glyphs->has (glyphArray[i]))
+ if (glyphs->has (arr[i]))
return true;
return false;
}
@@ -1356,18 +1357,21 @@ struct CoverageFormat2
bool intersects (const hb_set_t *glyphs) const
{
/* TODO Speed up, using hb_set_next() and bsearch()? */
- unsigned int count = rangeRecord.len;
- for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].intersects (glyphs))
+ /* TODO(iter) Rewrite as dagger. */
+ unsigned count = rangeRecord.len;
+ const RangeRecord *arr = rangeRecord.arrayZ;
+ for (unsigned i = 0; i < count; i++)
+ if (arr[i].intersects (glyphs))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
- unsigned int i;
- unsigned int count = rangeRecord.len;
- for (i = 0; i < count; i++) {
- const RangeRecord &range = rangeRecord[i];
+ /* TODO(iter) Rewrite as dagger. */
+ unsigned count = rangeRecord.len;
+ const RangeRecord *arr = rangeRecord.arrayZ;
+ for (unsigned i = 0; i < count; i++) {
+ const RangeRecord &range = arr[i];
if (range.value <= index &&
index < (unsigned int) range.value + (range.last - range.first) &&
range.intersects (glyphs))
@@ -1502,7 +1506,7 @@ struct Coverage
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -1729,7 +1733,7 @@ struct ClassDefFormat1
hb_map_t *klass_map = nullptr /*OUT*/) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs;
@@ -1784,7 +1788,7 @@ struct ClassDefFormat1
}
template <typename set_t>
- bool collect_class (set_t *glyphs, unsigned int klass) const
+ bool collect_class (set_t *glyphs, unsigned klass) const
{
unsigned int count = classValue.len;
for (unsigned int i = 0; i < count; i++)
@@ -1802,7 +1806,7 @@ struct ClassDefFormat1
if (classValue[iter - start]) return true;
return false;
}
- bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+ bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
unsigned int count = classValue.len;
if (klass == 0)
@@ -1815,8 +1819,12 @@ struct ClassDefFormat1
if (hb_set_next (glyphs, &g)) return true;
/* Fall through. */
}
+ /* TODO Speed up, using set overlap first? */
+ /* TODO(iter) Rewrite as dagger. */
+ HBUINT16 k {klass};
+ const HBUINT16 *arr = classValue.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (classValue[i] == klass && glyphs->has (startGlyph + i))
+ if (arr[i] == k && glyphs->has (startGlyph + i))
return true;
return false;
}
@@ -1898,7 +1906,7 @@ struct ClassDefFormat2
hb_map_t *klass_map = nullptr /*OUT*/) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs;
@@ -1961,11 +1969,14 @@ struct ClassDefFormat2
/* TODO Speed up, using hb_set_next() and bsearch()? */
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].intersects (glyphs))
+ {
+ const auto& range = rangeRecord[i];
+ if (range.intersects (glyphs) && range.value)
return true;
+ }
return false;
}
- bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+ bool intersects_class (const hb_set_t *glyphs, uint16_t klass) const
{
unsigned int count = rangeRecord.len;
if (klass == 0)
@@ -1984,8 +1995,12 @@ struct ClassDefFormat2
return true;
/* Fall through. */
}
+ /* TODO Speed up, using set overlap first? */
+ /* TODO(iter) Rewrite as dagger. */
+ HBUINT16 k {klass};
+ const RangeRecord *arr = rangeRecord.arrayZ;
for (unsigned int i = 0; i < count; i++)
- if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
+ if (arr[i].value == k && arr[i].intersects (glyphs))
return true;
return false;
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
index 2217d298fb..f523e35c00 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -566,6 +566,26 @@ struct AnchorMatrix
return_trace (true);
}
+ bool subset (hb_subset_context_t *c,
+ unsigned cols,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+
+ auto indexes =
+ + hb_range (rows * cols)
+ | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % cols); })
+ ;
+
+ out->serialize (c->serializer,
+ (unsigned) rows,
+ this,
+ c->plan->layout_variation_idx_map,
+ indexes);
+ return_trace (true);
+ }
+
bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
{
TRACE_SANITIZE (this);
@@ -755,7 +775,7 @@ struct SinglePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -870,7 +890,7 @@ struct SinglePosFormat2
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned sub_length = valueFormat.get_len ();
@@ -1129,7 +1149,7 @@ struct PairSet
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->len = 0;
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned len1 = valueFormats[0].get_len ();
@@ -1250,7 +1270,7 @@ struct PairPosFormat1
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1441,7 +1461,7 @@ struct PairPosFormat2
})
;
- const hb_set_t &glyphset = *c->plan->_glyphset_gsub;
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -1728,7 +1748,7 @@ struct CursivePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1904,7 +1924,7 @@ struct MarkBasePosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -2025,10 +2045,37 @@ typedef AnchorMatrix LigatureAttach; /* component-major--
* mark-minor--
* ordered by class--zero-based. */
-typedef OffsetListOf<LigatureAttach> LigatureArray;
- /* Array of LigatureAttach
- * tables ordered by
- * LigatureCoverage Index */
+/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
+struct LigatureArray : OffsetListOf<LigatureAttach>
+{
+ template <typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool subset (hb_subset_context_t *c,
+ Iterator coverage,
+ unsigned class_count,
+ const hb_map_t *klass_mapping) const
+ {
+ TRACE_SUBSET (this);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ for (const auto _ : + hb_zip (coverage, *this)
+ | hb_filter (glyphset, hb_first))
+ {
+ auto *matrix = out->serialize_append (c->serializer);
+ if (unlikely (!matrix)) return_trace (false);
+
+ matrix->serialize_subset (c,
+ _.second,
+ this,
+ class_count,
+ klass_mapping);
+ }
+ return_trace (this->len);
+ }
+};
struct MarkLigPosFormat1
{
@@ -2130,8 +2177,56 @@ struct MarkLigPosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- // TODO(subset)
- return_trace (false);
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+ const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->format = format;
+
+ hb_map_t klass_mapping;
+ Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
+
+ if (!klass_mapping.get_population ()) return_trace (false);
+ out->classCount = klass_mapping.get_population ();
+
+ auto mark_iter =
+ + hb_zip (this+markCoverage, this+markArray)
+ | hb_filter (glyphset, hb_first)
+ ;
+
+ auto new_mark_coverage =
+ + mark_iter
+ | hb_map_retains_sorting (hb_first)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->markCoverage.serialize (c->serializer, out)
+ .serialize (c->serializer, new_mark_coverage))
+ return_trace (false);
+
+ out->markArray.serialize (c->serializer, out)
+ .serialize (c->serializer,
+ &klass_mapping,
+ c->plan->layout_variation_idx_map,
+ &(this+markArray),
+ + mark_iter
+ | hb_map (hb_second));
+
+ auto new_ligature_coverage =
+ + hb_iter (this + ligatureCoverage)
+ | hb_filter (glyphset)
+ | hb_map_retains_sorting (glyph_map)
+ ;
+
+ if (!out->ligatureCoverage.serialize (c->serializer, out)
+ .serialize (c->serializer, new_ligature_coverage))
+ return_trace (false);
+
+ out->ligatureArray.serialize_subset (c, ligatureArray, this,
+ hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
+
+ return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -2164,6 +2259,7 @@ struct MarkLigPosFormat1
DEFINE_SIZE_STATIC (12);
};
+
struct MarkLigPos
{
template <typename context_t, typename ...Ts>
@@ -2288,7 +2384,7 @@ struct MarkMarkPosFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
index 2f41d67819..5f10ecb7ee 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -356,7 +356,7 @@ struct Sequence
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset)) return_trace (false);
@@ -447,7 +447,7 @@ struct MultipleSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -582,7 +582,7 @@ struct AlternateSet
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
@@ -682,7 +682,7 @@ struct AlternateSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -840,7 +840,7 @@ struct Ligature
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
@@ -1058,7 +1058,7 @@ struct LigatureSubstFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index cb95e6dcd5..36a95ead15 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -89,7 +89,7 @@ struct hb_closure_context_t :
bool is_lookup_done (unsigned int lookup_index)
{
- if (done_lookups->in_error ())
+ if (unlikely (done_lookups->in_error ()))
return true;
/* Have we visited this lookup with the current set of glyphs? */
@@ -146,7 +146,6 @@ struct hb_closure_lookups_context_t :
if (is_lookup_visited (lookup_index))
return;
- set_lookup_visited (lookup_index);
nesting_level_left--;
recurse_func (this, lookup_index);
nesting_level_left++;
@@ -163,10 +162,10 @@ struct hb_closure_lookups_context_t :
bool is_lookup_visited (unsigned lookup_index)
{
- if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
+ if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
return true;
- if (visited_lookups->in_error ())
+ if (unlikely (visited_lookups->in_error ()))
return true;
return visited_lookups->has (lookup_index);
@@ -660,7 +659,7 @@ struct hb_ot_apply_context_t :
void replace_glyph (hb_codepoint_t glyph_index) const
{
_set_glyph_props (glyph_index);
- buffer->replace_glyph (glyph_index);
+ (void) buffer->replace_glyph (glyph_index);
}
void replace_glyph_inplace (hb_codepoint_t glyph_index) const
{
@@ -671,13 +670,13 @@ struct hb_ot_apply_context_t :
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess, true);
- buffer->replace_glyph (glyph_index);
+ (void) buffer->replace_glyph (glyph_index);
}
void output_glyph_for_component (hb_codepoint_t glyph_index,
unsigned int class_guess) const
{
_set_glyph_props (glyph_index, class_guess, false, true);
- buffer->output_glyph (glyph_index);
+ (void) buffer->output_glyph (glyph_index);
}
};
@@ -1044,7 +1043,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
hb_min (this_comp, last_num_components);
_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
@@ -1188,7 +1187,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
/* Don't recurse to ourself at same position.
* Note that this test is too naive, it doesn't catch longer loops. */
- if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+ if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
continue;
if (unlikely (!buffer->move_to (match_positions[idx])))
@@ -1226,7 +1225,8 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
* mean that n match positions where removed, as there might
* have been marks and default-ignorables in the sequence. We
* should instead drop match positions between current-position
- * and current-position + n instead.
+ * and current-position + n instead. Though, am not sure which
+ * one is better. Both cases have valid uses. Sigh.
*
* It should be possible to construct tests for both of these cases.
*/
@@ -1272,7 +1272,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
match_positions[next] += delta;
}
- buffer->move_to (end);
+ (void) buffer->move_to (end);
return_trace (true);
}
@@ -1389,9 +1389,11 @@ struct Rule
lookup_context);
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
+ if (!intersects (c->glyphs, lookup_context)) return;
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
@@ -1521,14 +1523,13 @@ struct RuleSet
;
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
-
- return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -1647,9 +1648,16 @@ struct ContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const
{
- + hb_iter (ruleSet)
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ nullptr
+ };
+
+ + hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second)
| hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -1700,7 +1708,7 @@ struct ContextFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -1791,10 +1799,24 @@ struct ContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!(this+coverage).intersects (c->glyphs))
+ return;
+
+ const ClassDef &class_def = this+classDef;
+
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ &class_def
+ };
+
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
- | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
- ;
+ | hb_enumerate
+ | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
+ { return class_def.intersects_class (c->glyphs, p.first); })
+ | hb_map (hb_second)
+ | hb_apply ([&] (const RuleSet & _)
+ { _.closure_lookups (c, lookup_context); });
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
@@ -1860,8 +1882,8 @@ struct ContextFormat2
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
bool ret = true;
int non_zero_index = 0, index = 0;
- for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _ : + hb_enumerate (ruleSet)
- | hb_filter (klass_map, hb_first))
+ for (const auto& _ : + hb_enumerate (ruleSet)
+ | hb_filter (klass_map, hb_first))
{
auto *o = out->ruleSet.serialize_append (c->serializer);
if (unlikely (!o))
@@ -1945,6 +1967,8 @@ struct ContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!intersects (c->glyphs))
+ return;
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
recurse_lookups (c, lookupCount, lookupRecord);
}
@@ -2010,6 +2034,7 @@ struct ContextFormat3
for (const OffsetTo<Coverage>& offset : coverages)
{
+ /* TODO(subset) This looks like should not be necessary to write this way. */
auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
if (unlikely (!o)) return_trace (false);
if (!o->serialize_subset (c, offset, this)) return_trace (false);
@@ -2238,9 +2263,11 @@ struct ChainRule
lookup_context);
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
+ if (!intersects (c->glyphs, lookup_context)) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
@@ -2296,11 +2323,7 @@ struct ChainRule
{
c->copy (len);
for (const auto g : it)
- {
- HBUINT16 gid;
- gid = g;
- c->copy (gid);
- }
+ c->copy ((HBUINT16) g);
}
ChainRule* copy (hb_serialize_context_t *c,
@@ -2328,12 +2351,19 @@ struct ChainRule
| hb_map (mapping));
const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
- HBUINT16 lookupCount;
- lookupCount = lookupRecord.len;
- if (!c->copy (lookupCount)) return_trace (nullptr);
- for (unsigned i = 0; i < (unsigned) lookupCount; i++)
+ HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
+ if (!lookupCount) return_trace (nullptr);
+
+ for (unsigned i = 0; i < lookupRecord.len; i++)
+ {
+ if (!lookup_map->has (lookupRecord[i].lookupListIndex))
+ {
+ (*lookupCount)--;
+ continue;
+ }
if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
+ }
return_trace (out);
}
@@ -2351,7 +2381,7 @@ struct ChainRule
if (!backtrack_map)
{
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
if (!hb_all (backtrack, glyphset) ||
!hb_all (input, glyphset) ||
!hb_all (lookahead, glyphset))
@@ -2424,14 +2454,14 @@ struct ChainRuleSet
;
}
- void closure_lookups (hb_closure_lookups_context_t *c) const
+ void closure_lookups (hb_closure_lookups_context_t *c,
+ ChainContextClosureLookupContext &lookup_context) const
{
if (unlikely (c->lookup_limit_exceeded ())) return;
- return
+ hb_iter (rule)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -2552,9 +2582,16 @@ struct ChainContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const
{
- + hb_iter (ruleSet)
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ {nullptr, nullptr, nullptr}
+ };
+
+ + hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
;
}
@@ -2604,7 +2641,7 @@ struct ChainContextFormat1
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- const hb_set_t &glyphset = *c->plan->glyphset ();
+ const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
@@ -2701,9 +2738,28 @@ struct ChainContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!(this+coverage).intersects (c->glyphs))
+ return;
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
- | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
+ | hb_enumerate
+ | hb_filter([&] (unsigned klass)
+ { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
+ | hb_map (hb_second)
+ | hb_apply ([&] (const ChainRuleSet &_)
+ { _.closure_lookups (c, lookup_context); })
;
}
@@ -2779,24 +2835,23 @@ struct ChainContextFormat2
out->coverage.serialize_subset (c, coverage, this);
hb_map_t backtrack_klass_map;
- out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
- if (unlikely (!c->serializer->check_success (!backtrack_klass_map.in_error ())))
- return_trace (false);
-
- // subset inputClassDef based on glyphs survived in Coverage subsetting
hb_map_t input_klass_map;
- out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
- if (unlikely (!c->serializer->check_success (!input_klass_map.in_error ())))
- return_trace (false);
-
hb_map_t lookahead_klass_map;
+
+ out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
+ // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
+ out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
- if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ())))
+
+ if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
+ input_klass_map,
+ lookahead_klass_map)))
return_trace (false);
- unsigned non_zero_index = 0, index = 0;
+ int non_zero_index = -1, index = 0;
bool ret = true;
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
+ auto last_non_zero = c->serializer->snapshot ();
for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
| hb_filter (input_klass_map, hb_first)
| hb_map (hb_second))
@@ -2812,19 +2867,20 @@ struct ChainContextFormat2
&backtrack_klass_map,
&input_klass_map,
&lookahead_klass_map))
+ {
+ last_non_zero = c->serializer->snapshot ();
non_zero_index = index;
+ }
index++;
}
if (!ret) return_trace (ret);
- //prune empty trailing ruleSets
- --index;
- while (index > non_zero_index)
- {
- out->ruleSet.pop ();
- index--;
+ // prune empty trailing ruleSets
+ if (index > non_zero_index) {
+ c->serializer->revert (last_non_zero);
+ out->ruleSet.len = non_zero_index + 1;
}
return_trace (bool (out->ruleSet));
@@ -2908,6 +2964,9 @@ struct ChainContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ if (!intersects (c->glyphs))
+ return;
+
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
@@ -2986,13 +3045,16 @@ struct ChainContextFormat3
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
- if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
+ if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+ return_trace (false);
- + it
- | hb_apply (subset_offset_array (c, *out, base))
- ;
+ for (auto& offset : it) {
+ auto *o = out->serialize_append (c->serializer);
+ if (unlikely (!o) || !o->serialize_subset (c, offset, base))
+ return_trace (false);
+ }
- return_trace (out->len);
+ return_trace (true);
}
bool subset (hb_subset_context_t *c) const
@@ -3113,6 +3175,24 @@ struct ExtensionFormat1
extensionLookupType != T::SubTable::Extension);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ out->format = format;
+ out->extensionLookupType = extensionLookupType;
+
+ const auto& src_offset =
+ reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset);
+ auto& dest_offset =
+ reinterpret_cast<LOffsetTo<typename T::SubTable> &> (out->extensionOffset);
+
+ return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
+ }
+
protected:
HBUINT16 format; /* Format identifier. Set to 1. */
HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
@@ -3143,6 +3223,18 @@ struct Extension
}
}
+ // Specialization of dispatch for subset. dispatch() normally just
+ // dispatches to the sub table this points too, but for subset
+ // we need to run subset on this subtable too.
+ template <typename ...Ts>
+ typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.subset (c);
+ default: return c->default_return_value ();
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -3320,20 +3412,34 @@ struct GSUBGPOS
return_trace (true);
}
- void closure_features (const hb_map_t *lookup_indexes, /* IN */
- hb_set_t *feature_indexes /* OUT */) const
+ void prune_features (const hb_map_t *lookup_indices, /* IN */
+ hb_set_t *feature_indices /* IN/OUT */) const
{
- unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
- for (unsigned i = 0; i < feature_count; i++)
+#ifndef HB_NO_VAR
+ // This is the set of feature indices which have alternate versions defined
+ // if the FeatureVariation's table and the alternate version(s) intersect the
+ // set of lookup indices.
+ hb_set_t alternate_feature_indices;
+ if (version.to_int () >= 0x00010001u)
+ (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
+ if (unlikely (alternate_feature_indices.in_error())) {
+ feature_indices->successful = false;
+ return;
+ }
+#endif
+
+ for (unsigned i : feature_indices->iter())
{
const Feature& f = get_feature (i);
- if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
- feature_indexes->add (i);
- }
+
+ if (f.featureParams.is_null ()
+ && !f.intersects_lookup_indexes (lookup_indices)
#ifndef HB_NO_VAR
- if (version.to_int () >= 0x00010001u)
- (this+featureVars).closure_features (lookup_indexes, feature_indexes);
+ && !alternate_feature_indices.has (i)
#endif
+ )
+ feature_indices->del (i);
+ }
}
unsigned int get_size () const
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index f25f0f9e23..89df949b26 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -76,7 +76,7 @@
* Tests whether a face includes any kerning data in the 'kern' table.
* Does NOT test for kerning lookups in the GPOS table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
bool
@@ -92,7 +92,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
* Tests whether a face includes any state-machine kerning in the 'kern' table.
* Does NOT examine the GPOS table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
bool
@@ -112,7 +112,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
*
* Does NOT examine the GPOS table.
*
- * Return value: %true is data found, false otherwise
+ * Return value: %true is data found, %false otherwise
*
**/
bool
@@ -268,7 +268,7 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
*
* Tests whether a face has any glyph classes defined in its GDEF table.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
hb_bool_t
@@ -322,7 +322,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
* @face: The #hb_face_t to work on
* @glyph: The #hb_codepoint_t code point to query
* @start_offset: offset of the first attachment point to retrieve
- * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return;
+ * @point_count: (inout) (optional): Input = the maximum number of attachment points to return;
* Output = the actual number of attachment points returned (may be zero)
* @point_array: (out) (array length=point_count): The array of attachment points found for the query
*
@@ -350,7 +350,7 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
* @direction: The #hb_direction_t text direction to use
* @glyph: The #hb_codepoint_t code point to query
* @start_offset: offset of the first caret position to retrieve
- * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return;
+ * @caret_count: (inout) (optional): Input = the maximum number of caret positions to return;
* Output = the actual number of caret positions returned (may be zero)
* @caret_array: (out) (array length=caret_count): The array of caret positions found for the query
*
@@ -410,9 +410,9 @@ get_gsubgpos_table (hb_face_t *face,
/**
* hb_ot_layout_table_get_script_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @start_offset: offset of the first script tag to retrieve
- * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return;
+ * @script_count: (inout) (optional): Input = the maximum number of script tags to return;
* Output = the actual number of script tags returned (may be zero)
* @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query
*
@@ -437,14 +437,14 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
/**
* hb_ot_layout_table_find_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_tag: #hb_tag_t of the script tag requested
* @script_index: (out): The index of the requested script tag
*
* Fetches the index if a given script tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the script is found, false otherwise
+ * Return value: %true if the script is found, %false otherwise
*
**/
hb_bool_t
@@ -481,7 +481,7 @@ hb_ot_layout_table_find_script (hb_face_t *face,
/**
* hb_ot_layout_table_choose_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_tags: Array of #hb_tag_t script tags
* @script_index: (out): The index of the requested script tag
* @chosen_script: (out): #hb_tag_t of the script tag requested
@@ -504,11 +504,22 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
/**
* hb_ot_layout_table_select_script:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_count: Number of script tags in the array
* @script_tags: Array of #hb_tag_t script tags
- * @script_index: (out): The index of the requested script
- * @chosen_script: (out): #hb_tag_t of the requested script
+ * @script_index: (out) (optional): The index of the requested script
+ * @chosen_script: (out) (optional): #hb_tag_t of the requested script
+ *
+ * Selects an OpenType script for @table_tag from the @script_tags array.
+ *
+ * If the table does not have any of the requested scripts, then `DFLT`,
+ * `dflt`, and `latn` tags are tried in that order. If the table still does not
+ * have any of these scripts, @script_index and @chosen_script are set to
+ * #HB_OT_LAYOUT_NO_SCRIPT_INDEX.
+ *
+ * Return value:
+ * %true if one of the requested scripts is selected, %false if a fallback
+ * script is selected or if no scripts are selected.
*
* Since: 2.0.0
**/
@@ -566,9 +577,9 @@ hb_ot_layout_table_select_script (hb_face_t *face,
/**
* hb_ot_layout_table_get_feature_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output = the actual number of feature tags returned (may be zero)
* @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table
*
@@ -591,14 +602,14 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
/**
* hb_ot_layout_table_find_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_tag: The #hb_tag_t og the requested feature tag
* @feature_index: (out): The index of the requested feature
*
* Fetches the index for a given feature tag in the specified face's GSUB table
* or GPOS table.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
**/
bool
hb_ot_layout_table_find_feature (hb_face_t *face,
@@ -626,10 +637,10 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
/**
* hb_ot_layout_script_get_language_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @start_offset: offset of the first language tag to retrieve
- * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return;
+ * @language_count: (inout) (optional): Input = the maximum number of language tags to return;
* Output = the actual number of language tags returned (may be zero)
* @language_tags: (out) (array length=language_count): Array of language tags found in the table
*
@@ -655,7 +666,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
/**
* hb_ot_layout_script_find_language:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_tag: The #hb_tag_t of the requested language
* @language_index: The index of the requested language
@@ -663,7 +674,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
* Fetches the index of a given language tag in the specified face's GSUB table
* or GPOS table, underneath the specified script tag.
*
- * Return value: %true if the language tag is found, false otherwise
+ * Return value: %true if the language tag is found, %false otherwise
*
* Since: ??
* Deprecated: ??
@@ -688,7 +699,7 @@ hb_ot_layout_script_find_language (hb_face_t *face,
/**
* hb_ot_layout_script_select_language:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_count: The number of languages in the specified script
* @language_tags: The array of language tags
@@ -697,7 +708,7 @@ hb_ot_layout_script_find_language (hb_face_t *face,
* Fetches the index of a given language tag in the specified face's GSUB table
* or GPOS table, underneath the specified script index.
*
- * Return value: %true if the language tag is found, false otherwise
+ * Return value: %true if the language tag is found, %false otherwise
*
* Since: 2.0.0
**/
@@ -731,7 +742,7 @@ hb_ot_layout_script_select_language (hb_face_t *face,
/**
* hb_ot_layout_language_get_required_feature_index:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_index: (out): The index of the requested feature
@@ -739,7 +750,7 @@ hb_ot_layout_script_select_language (hb_face_t *face,
* Fetches the index of a requested feature in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
**/
hb_bool_t
@@ -761,7 +772,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
/**
* hb_ot_layout_language_get_required_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_index: (out): The index of the requested feature
@@ -770,7 +781,7 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
* Fetches the tag of a requested feature index in the given face's GSUB or GPOS table,
* underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
* Since: 0.9.30
**/
@@ -796,11 +807,11 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
/**
* hb_ot_layout_language_get_feature_indexes:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output: the actual number of feature tags returned (may be zero)
* @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query
*
@@ -827,11 +838,11 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
/**
* hb_ot_layout_language_get_feature_tags:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @start_offset: offset of the first feature tag to retrieve
- * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return;
+ * @feature_count: (inout) (optional): Input = the maximum number of feature tags to return;
* Output = the actual number of feature tags returned (may be zero)
* @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query
*
@@ -868,7 +879,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
/**
* hb_ot_layout_language_find_feature:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @script_index: The index of the requested script tag
* @language_index: The index of the requested language tag
* @feature_tag: #hb_tag_t of the feature tag requested
@@ -877,7 +888,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
* Fetches the index of a given feature tag in the specified face's GSUB table
* or GPOS table, underneath the specified script and language.
*
- * Return value: %true if the feature is found, false otherwise
+ * Return value: %true if the feature is found, %false otherwise
*
**/
hb_bool_t
@@ -910,10 +921,10 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
/**
* hb_ot_layout_feature_get_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_index: The index of the requested feature
* @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
* Output = the actual number of lookups returned (may be zero)
* @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query
*
@@ -944,7 +955,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
/**
* hb_ot_layout_table_get_lookup_count:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
*
* Fetches the total number of lookups enumerated in the specified
* face's GSUB table or GPOS table.
@@ -1101,7 +1112,7 @@ script_collect_features (hb_collect_features_context_t *c,
/**
* hb_ot_layout_collect_features:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @scripts: The array of scripts to collect features for
* @languages: The array of languages to collect features for
* @features: The array of features to collect
@@ -1152,7 +1163,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
/**
* hb_ot_layout_collect_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @scripts: The array of scripts to collect lookups for
* @languages: The array of languages to collect lookups for
* @features: The array of features to collect lookups for
@@ -1191,7 +1202,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
/**
* hb_ot_layout_lookup_collect_glyphs:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @lookup_index: The index of the feature lookup to query
* @glyphs_before: (out): Array of glyphs preceding the substitution range
* @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup
@@ -1243,7 +1254,7 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
/**
* hb_ot_layout_table_find_feature_variations:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @coords: The variation coordinates to query
* @num_coords: The number of variation coordinates
* @variations_index: (out): The array of feature variations found for the query
@@ -1268,11 +1279,11 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
/**
* hb_ot_layout_feature_with_variations_get_lookups:
* @face: #hb_face_t to work upon
- * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
* @feature_index: The index of the feature to query
* @variations_index: The index of the feature variation to query
* @start_offset: offset of the first lookup to retrieve
- * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return;
+ * @lookup_count: (inout) (optional): Input = the maximum number of lookups to return;
* Output = the actual number of lookups returned (may be zero)
* @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query
*
@@ -1310,7 +1321,7 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
*
* Tests whether the specified face includes any GSUB substitutions.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
**/
hb_bool_t
@@ -1331,7 +1342,7 @@ hb_ot_layout_has_substitution (hb_face_t *face)
* Tests whether a specified lookup in the specified face would
* trigger a substitution on the given glyph sequence.
*
- * Return value: %true if a substitution would be triggered, false otherwise
+ * Return value: %true if a substitution would be triggered, %false otherwise
*
* Since: 0.9.7
**/
@@ -1488,7 +1499,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
* hb_ot_layout_has_positioning:
* @face: #hb_face_t to work upon
*
- * Return value: %true if the face has GPOS data, false otherwise
+ * Tests whether the specified face includes any GPOS positioning.
+ *
+ * Return value: %true if the face has GPOS data, %false otherwise
*
**/
hb_bool_t
@@ -1561,7 +1574,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
* For more information on this distinction, see the [`size` feature documentation](
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size).
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 0.9.10
**/
@@ -1610,22 +1623,22 @@ hb_ot_layout_get_size_params (hb_face_t *face,
* @face: #hb_face_t to work upon
* @table_tag: table tag to query, "GSUB" or "GPOS".
* @feature_index: index of feature to query.
- * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @label_id: (out) (optional): The ‘name’ table name ID that specifies a string
* for a user-interface label for this feature. (May be NULL.)
- * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * @tooltip_id: (out) (optional): The ‘name’ table name ID that specifies a string
* that an application can use for tooltip text for this
* feature. (May be NULL.)
- * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
+ * @sample_id: (out) (optional): The ‘name’ table name ID that specifies sample text
* that illustrates the effect of this feature. (May be NULL.)
- * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
- * @first_param_id: (out) (allow-none): The first ‘name’ table name ID used to specify
+ * @num_named_parameters: (out) (optional): Number of named parameters. (May be zero.)
+ * @first_param_id: (out) (optional): The first ‘name’ table name ID used to specify
* strings for user-interface labels for the feature
* parameters. (Must be zero if numParameters is zero.)
*
* Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
* "Character Variant" ('cvXX') features.
*
- * Return value: %true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.0.0
**/
@@ -1685,7 +1698,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face,
* @table_tag: table tag to query, "GSUB" or "GPOS".
* @feature_index: index of feature to query.
* @start_offset: offset of the first character to retrieve
- * @char_count: (inout) (allow-none): Input = the maximum number of characters to return;
+ * @char_count: (inout) (optional): Input = the maximum number of characters to return;
* Output = the actual number of characters returned (may be zero)
* @characters: (out caller-allocates) (array length=char_count): A buffer pointer.
* The Unicode codepoints of the characters for which this feature provides
@@ -1769,7 +1782,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
if (applied)
ret = true;
else
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
return ret;
}
@@ -1907,7 +1920,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
* @baseline_tag: a baseline tag
* @direction: text direction.
* @script_tag: script tag.
- * @language_tag: language tag.
+ * @language_tag: language tag, currently unused.
* @coord: (out): baseline value if found.
*
* Fetches a baseline value from the face.
@@ -1964,7 +1977,7 @@ struct hb_get_glyph_alternates_dispatch_t :
* @lookup_index: index of the feature lookup to query.
* @glyph: a glyph id.
* @start_offset: starting offset.
- * @alternate_count: (inout) (allow-none): Input = the maximum number of alternate glyphs to return;
+ * @alternate_count: (inout) (optional): Input = the maximum number of alternate glyphs to return;
* Output = the actual number of alternate glyphs returned (may be zero).
* @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer.
* Alternate glyphs associated with the glyph id.
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h
index 545d5f7fc4..d47ba0fc92 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.h
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -38,10 +38,35 @@
HB_BEGIN_DECLS
+/**
+ * HB_OT_TAG_BASE:
+ *
+ * OpenType [Baseline Table](https://docs.microsoft.com/en-us/typography/opentype/spec/base).
+ */
#define HB_OT_TAG_BASE HB_TAG('B','A','S','E')
+/**
+ * HB_OT_TAG_GDEF:
+ *
+ * OpenType [Glyph Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gdef).
+ */
#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
+/**
+ * HB_OT_TAG_GSUB:
+ *
+ * OpenType [Glyph Substitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub).
+ */
#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
+/**
+ * HB_OT_TAG_GPOS:
+ *
+ * OpenType [Glyph Positioning Table](https://docs.microsoft.com/en-us/typography/opentype/spec/gpos).
+ */
#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+/**
+ * HB_OT_TAG_JSTF:
+ *
+ * OpenType [Justification Table](https://docs.microsoft.com/en-us/typography/opentype/spec/jstf).
+ */
#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
@@ -49,18 +74,34 @@ HB_BEGIN_DECLS
* Script & Language tags.
*/
+/**
+ * HB_OT_TAG_DEFAULT_SCRIPT:
+ *
+ * OpenType script tag, `DFLT`, for features that are not script-specific.
+ *
+ */
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
+/**
+ * HB_OT_TAG_DEFAULT_LANGUAGE:
+ *
+ * OpenType language tag, `dflt`. Not a valid language tag, but some fonts
+ * mistakenly use it.
+ */
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
/**
* HB_OT_MAX_TAGS_PER_SCRIPT:
*
+ * Maximum number of OpenType tags that can correspond to a give #hb_script_t.
+ *
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_SCRIPT 3u
/**
* HB_OT_MAX_TAGS_PER_LANGUAGE:
*
+ * Maximum number of OpenType tags that can correspond to a give #hb_language_t.
+ *
* Since: 2.0.0
**/
#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u
@@ -144,9 +185,29 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS feature query and enumeration interface
*/
+/**
+ * HB_OT_LAYOUT_NO_SCRIPT_INDEX:
+ *
+ * Special value for script index indicating unsupported script.
+ */
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_FEATURE_INDEX:
+ *
+ * Special value for feature index indicating unsupported feature.
+ */
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX:
+ *
+ * Special value for language index indicating default or unsupported language.
+ */
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
+/**
+ * HB_OT_LAYOUT_NO_VARIATIONS_INDEX:
+ *
+ * Special value for variations index indicating unsupported variation.
+ */
#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int
@@ -433,7 +494,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered.
* In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered.
*
- * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags
+ * Baseline tags from [Baseline Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags) registry.
*
* Since: 2.6.0
*/
@@ -446,6 +507,7 @@ typedef enum {
HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'),
HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'),
+ /*< private >*/
_HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_layout_baseline_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh
index f3bb15581a..ac61bc70de 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh
@@ -315,12 +315,13 @@ _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
+static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info);
static inline bool
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
- !_hb_glyph_info_ligated (info);
+ !_hb_glyph_info_substituted (info);
}
static inline bool
_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
diff --git a/thirdparty/harfbuzz/src/hb-ot-math.cc b/thirdparty/harfbuzz/src/hb-ot-math.cc
index 9d8c6e735a..5781d25f2a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-math.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face has a `MATH` table.
*
- * Return value: true if the table is found, false otherwise
+ * Return value: %true if the table is found, %false otherwise
*
* Since: 1.3.3
**/
@@ -142,7 +142,7 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
*
* Tests whether the given glyph index is an extended shape in the face.
*
- * Return value: true if the glyph is an extended shape, false otherwise
+ * Return value: %true if the glyph is an extended shape, %false otherwise
*
* Since: 1.3.3
**/
diff --git a/thirdparty/harfbuzz/src/hb-ot-math.h b/thirdparty/harfbuzz/src/hb-ot-math.h
index ad864a762d..d3ffa19d85 100644
--- a/thirdparty/harfbuzz/src/hb-ot-math.h
+++ b/thirdparty/harfbuzz/src/hb-ot-math.h
@@ -24,7 +24,7 @@
* Igalia Author(s): Frédéric Wang
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -40,18 +40,89 @@ HB_BEGIN_DECLS
* MATH
*/
+/**
+ * HB_OT_TAG_MATH:
+ *
+ * OpenType [Mathematical Typesetting Table](https://docs.microsoft.com/en-us/typography/opentype/spec/math).
+ *
+ * Since: 1.3.3
+ */
#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
-/* Use with hb_buffer_set_script() for math shaping. */
+/**
+ * HB_OT_MATH_SCRIPT:
+ *
+ * OpenType script tag for math shaping, for use with
+ * Use with hb_buffer_set_script().
+ *
+ * Since: 1.3.3
+ */
#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
/* Types */
/**
* hb_ot_math_constant_t:
+ * @HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: scriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: scriptScriptPercentScaleDown
+ * @HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: delimitedSubFormulaMinHeight
+ * @HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: displayOperatorMinHeight
+ * @HB_OT_MATH_CONSTANT_MATH_LEADING: mathLeading
+ * @HB_OT_MATH_CONSTANT_AXIS_HEIGHT: axisHeight
+ * @HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: accentBaseHeight
+ * @HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: flattenedAccentBaseHeight
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: subscriptShiftDown
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: subscriptTopMax
+ * @HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: subscriptBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: superscriptShiftUp
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: superscriptShiftUpCramped
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: superscriptBottomMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: superscriptBaselineDropMax
+ * @HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: subSuperscriptGapMin
+ * @HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: superscriptBottomMaxWithSubscript
+ * @HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: spaceAfterScript
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: upperLimitGapMin
+ * @HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: upperLimitBaselineRiseMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: lowerLimitGapMin
+ * @HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: lowerLimitBaselineDropMin
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: stackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: stackTopDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: stackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: stackBottomDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_STACK_GAP_MIN: stackGapMin
+ * @HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: stackDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: stretchStackTopShiftUp
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: stretchStackBottomShiftDown
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: stretchStackGapAboveMin
+ * @HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: stretchStackGapBelowMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: fractionNumeratorShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: fractionNumeratorDisplayStyleShiftUp
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: fractionDenominatorShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: fractionDenominatorDisplayStyleShiftDown
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: fractionNumeratorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: fractionNumDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: fractionRuleThickness
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: fractionDenominatorGapMin
+ * @HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: fractionDenomDisplayStyleGapMin
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: skewedFractionHorizontalGap
+ * @HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: skewedFractionVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: overbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: overbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: overbarExtraAscender
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: underbarVerticalGap
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: underbarRuleThickness
+ * @HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: underbarExtraDescender
+ * @HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: radicalVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: radicalDisplayStyleVerticalGap
+ * @HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: radicalRuleThickness
+ * @HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: radicalExtraAscender
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: radicalKernBeforeDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: radicalKernAfterDegree
+ * @HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: radicalDegreeBottomRaisePercent
*
- * The 'MATH' table constants specified at
- * https://docs.microsoft.com/en-us/typography/opentype/spec/math
+ * The 'MATH' table constants, refer to
+ * [OpenType documentation](https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table)
+ * For more explanations.
*
* Since: 1.3.3
*/
@@ -116,6 +187,10 @@ typedef enum {
/**
* hb_ot_math_kern_t:
+ * @HB_OT_MATH_KERN_TOP_RIGHT: The top right corner of the glyph.
+ * @HB_OT_MATH_KERN_TOP_LEFT: The top left corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_RIGHT: The bottom right corner of the glyph.
+ * @HB_OT_MATH_KERN_BOTTOM_LEFT: The bottom left corner of the glyph.
*
* The math kerning-table types defined for the four corners
* of a glyph.
@@ -145,6 +220,8 @@ typedef struct hb_ot_math_glyph_variant_t {
/**
* hb_ot_math_glyph_part_flags_t:
+ * @HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER: This is an extender glyph part that
+ * can be repeated to reach the desired length.
*
* Flags for math glyph parts.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-meta.cc b/thirdparty/harfbuzz/src/hb-ot-meta.cc
index 54a0e10f9b..35c8eb523f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-meta.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-meta.cc
@@ -41,9 +41,11 @@
* hb_ot_meta_get_entry_tags:
* @face: a face object
* @start_offset: iteration's start offset
- * @entries_count:(inout) (allow-none): buffer size as input, filled size as output
+ * @entries_count:(inout) (optional): buffer size as input, filled size as output
* @entries: (out caller-allocates) (array length=entries_count): entries tags buffer
*
+ * Fetches all available feature types.
+ *
* Return value: Number of all available feature types.
*
* Since: 2.6.0
diff --git a/thirdparty/harfbuzz/src/hb-ot-meta.h b/thirdparty/harfbuzz/src/hb-ot-meta.h
index 0278d84148..7748eb4958 100644
--- a/thirdparty/harfbuzz/src/hb-ot-meta.h
+++ b/thirdparty/harfbuzz/src/hb-ot-meta.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -54,6 +54,7 @@ typedef enum {
HB_OT_META_TAG_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'),
HB_OT_META_TAG_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g'),
+ /*< private >*/
_HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_meta_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.cc b/thirdparty/harfbuzz/src/hb-ot-metrics.cc
index 3065ea2adf..72aeff82d6 100644
--- a/thirdparty/harfbuzz/src/hb-ot-metrics.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-metrics.cc
@@ -119,11 +119,11 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_position:
- * @font: a #hb_font_t object.
+ * @font: an #hb_font_t object.
* @metrics_tag: tag of metrics value you like to fetch.
* @position: (out) (optional): result of metrics value from the font.
*
- * It fetches metrics value corresponding to a given tag from a font.
+ * Fetches metrics value corresponding to @metrics_tag from @font.
*
* Returns: Whether found the requested metrics in the font.
* Since: 2.6.0
@@ -193,10 +193,13 @@ hb_ot_metrics_get_position (hb_font_t *font,
#ifndef HB_NO_VAR
/**
* hb_ot_metrics_get_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ *
+ * Fetches metrics value corresponding to @metrics_tag from @font with the
+ * current font variation settings applied.
*
- * Returns:
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
@@ -208,10 +211,13 @@ hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_x_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
*
- * Returns:
+ * Fetches horizontal metrics value corresponding to @metrics_tag from @font
+ * with the current font variation settings applied.
+ *
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
@@ -223,10 +229,13 @@ hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag)
/**
* hb_ot_metrics_get_y_variation:
- * @font:
- * @metrics_tag:
+ * @font: an #hb_font_t object.
+ * @metrics_tag: tag of metrics value you like to fetch.
+ *
+ * Fetches vertical metrics value corresponding to @metrics_tag from @font with
+ * the current font variation settings applied.
*
- * Returns:
+ * Returns: The requested metric value.
*
* Since: 2.6.0
**/
diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.h b/thirdparty/harfbuzz/src/hb-ot-metrics.h
index 42c7363c03..5841fc8b0f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-metrics.h
+++ b/thirdparty/harfbuzz/src/hb-ot-metrics.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -66,7 +66,8 @@ HB_BEGIN_DECLS
* @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size.
* @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset.
*
- * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags
+ * Metric tags corresponding to [MVAR Value
+ * Tags](https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags)
*
* Since: 2.6.0
**/
@@ -100,6 +101,7 @@ typedef enum {
HB_OT_METRICS_TAG_UNDERLINE_SIZE = HB_TAG ('u','n','d','s'),
HB_OT_METRICS_TAG_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o'),
+ /*< private >*/
_HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_metrics_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-ot-name.cc b/thirdparty/harfbuzz/src/hb-ot-name.cc
index 10122b8c2e..4588226e6e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-name.cc
@@ -46,7 +46,7 @@
/**
* hb_ot_name_list_names:
* @face: font face.
- * @num_entries: (out) (allow-none): number of returned entries.
+ * @num_entries: (out) (optional): number of returned entries.
*
* Enumerates all available name IDs and language combinations. Returned
* array is owned by the @face and should not be modified. It can be
@@ -150,7 +150,7 @@ hb_ot_name_get_utf (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
@@ -177,7 +177,7 @@ hb_ot_name_get_utf8 (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
@@ -203,7 +203,7 @@ hb_ot_name_get_utf16 (hb_face_t *face,
* @face: font face.
* @name_id: OpenType name identifier to fetch.
* @language: language to fetch the name for.
- * @text_size: (inout) (allow-none): input size of @text buffer, and output size of
+ * @text_size: (inout) (optional): input size of @text buffer, and output size of
* text written to buffer.
* @text: (out caller-allocates) (array length=text_size): buffer to write fetched name into.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-name.h b/thirdparty/harfbuzz/src/hb-ot-name.h
index 6f3fcd2427..9359014c8a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-name.h
+++ b/thirdparty/harfbuzz/src/hb-ot-name.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
index 7d31b712c4..8e98f87f4e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh
@@ -177,15 +177,14 @@ struct OS2
if (!c->plan->glyphs_requested->is_empty ())
{
hb_map_t unicode_glyphid_map;
-
+
OT::cmap::accelerator_t cmap;
cmap.init (c->plan->source);
cmap.collect_mapping (&unicodes, &unicode_glyphid_map);
cmap.fini ();
-
- if (c->plan->unicodes->is_empty ()) unicodes.clear ();
- else hb_set_set (&unicodes, c->plan->unicodes);
-
+
+ hb_set_set (&unicodes, c->plan->unicodes);
+
+ unicode_glyphid_map.iter ()
| hb_filter (c->plan->glyphs_requested, hb_second)
| hb_map (hb_first)
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index 8586331cd4..f22d6e244d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -87,7 +87,6 @@ struct post
if (unlikely (!post_prime)) return_trace (false);
serialize (c->serializer);
- if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
index b15e145f2f..41e3dd38ab 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -142,7 +142,7 @@
OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
- /* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+ /* static_assert_expr (len(FromGlyphs) == len(ToGlyphs)) */
#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
OT_SUBLOOKUP(Name, 1, \
@@ -151,7 +151,7 @@
OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
- /* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+ /* static_assert_expr (len(FirstGlyphs) == len(LigatureSetOffsets)) */
#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
index 1e93f0efd5..1f244f940c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -33,7 +33,7 @@
/* buffer var allocations */
-#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */
#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
index f5915f43ae..dbedd6af0c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
@@ -119,7 +119,7 @@ data_destroy_hangul (void *data)
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */
-#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */
static bool
is_zero_width_char (hb_font_t *font,
@@ -205,7 +205,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
- buffer->next_glyph ();
+ if (unlikely (!buffer->next_glyph ())) break;
if (!is_zero_width_char (font, u))
{
buffer->merge_out_clusters (start, end + 1);
@@ -218,23 +218,25 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
else
{
/* No valid syllable as base for tone mark; try to insert dotted circle. */
- if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
- font->has_glyph (0x25CCu))
+ if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) &&
+ font->has_glyph (0x25CCu))
{
hb_codepoint_t chars[2];
- if (!is_zero_width_char (font, u)) {
+ if (!is_zero_width_char (font, u))
+ {
chars[0] = u;
chars[1] = 0x25CCu;
- } else {
+ } else
+ {
chars[0] = 0x25CCu;
chars[1] = u;
}
- buffer->replace_glyphs (1, 2, chars);
+ (void) buffer->replace_glyphs (1, 2, chars);
}
else
{
/* No dotted circle available in the font; just leave tone mark untouched. */
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
start = end = buffer->out_len;
@@ -271,9 +273,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
if (font->has_glyph (s))
{
- buffer->replace_glyphs (t ? 3 : 2, 1, &s);
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->replace_glyphs (t ? 3 : 2, 1, &s);
end = start + 1;
continue;
}
@@ -285,17 +285,19 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
* Set jamo features on the individual glyphs, and advance past them.
*/
buffer->cur().hangul_shaping_feature() = LJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
buffer->cur().hangul_shaping_feature() = VJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (t)
{
buffer->cur().hangul_shaping_feature() = TJMO;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
end = start + 3;
}
else
end = start + 2;
+ if (unlikely (!buffer->successful))
+ break;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_out_clusters (start, end);
continue;
@@ -321,9 +323,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t new_s = s + new_tindex;
if (font->has_glyph (new_s))
{
- buffer->replace_glyphs (2, 1, &new_s);
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->replace_glyphs (2, 1, &new_s);
end = start + 1;
continue;
}
@@ -347,19 +347,18 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
(!tindex || font->has_glyph (decomposed[2])))
{
unsigned int s_len = tindex ? 3 : 2;
- buffer->replace_glyphs (1, s_len, decomposed);
+ (void) buffer->replace_glyphs (1, s_len, decomposed);
/* If we decomposed an LV because of a non-combining T following,
* we want to include this T in the syllable.
*/
if (has_glyph && !tindex)
{
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
s_len++;
}
-
if (unlikely (!buffer->successful))
- return;
+ break;
/* We decomposed S: apply jamo features to the individual glyphs
* that are now in buffer->out_info.
@@ -383,17 +382,15 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (has_glyph)
{
- /* We didn't decompose the S, so just advance past it. */
+ /* We didn't decompose the S, so just advance past it and fall through. */
end = start + 1;
- buffer->next_glyph ();
- continue;
}
}
/* Didn't find a recognizable syllable, so we leave end <= start;
* this will prevent tone-mark reordering happening.
*/
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
index 670b6bf486..74bf3ca0fa 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -31,8 +31,37 @@
#include "hb.hh"
+enum indic_syllable_type_t {
+ indic_consonant_syllable,
+ indic_vowel_syllable,
+ indic_standalone_cluster,
+ indic_symbol_cluster,
+ indic_broken_cluster,
+ indic_non_indic_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-indic-machine.hh"
+#line 45 "hb-ot-shape-complex-indic-machine.hh"
+#define indic_syllable_machine_ex_A 10u
+#define indic_syllable_machine_ex_C 1u
+#define indic_syllable_machine_ex_CM 17u
+#define indic_syllable_machine_ex_CS 19u
+#define indic_syllable_machine_ex_DOTTEDCIRCLE 12u
+#define indic_syllable_machine_ex_H 4u
+#define indic_syllable_machine_ex_M 7u
+#define indic_syllable_machine_ex_N 3u
+#define indic_syllable_machine_ex_PLACEHOLDER 11u
+#define indic_syllable_machine_ex_RS 13u
+#define indic_syllable_machine_ex_Ra 16u
+#define indic_syllable_machine_ex_Repha 15u
+#define indic_syllable_machine_ex_SM 8u
+#define indic_syllable_machine_ex_Symbol 18u
+#define indic_syllable_machine_ex_V 2u
+#define indic_syllable_machine_ex_ZWJ 6u
+#define indic_syllable_machine_ex_ZWNJ 5u
+
+
+#line 65 "hb-ot-shape-complex-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u,
@@ -384,18 +413,18 @@ static const int indic_syllable_machine_error = -1;
static const int indic_syllable_machine_en_main = 39;
-#line 36 "hb-ot-shape-complex-indic-machine.rl"
+#line 46 "hb-ot-shape-complex-indic-machine.rl"
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
+#line 102 "hb-ot-shape-complex-indic-machine.rl"
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -407,7 +436,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 411 "hb-ot-shape-complex-indic-machine.hh"
+#line 440 "hb-ot-shape-complex-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -415,7 +444,7 @@ find_syllables_indic (hb_buffer_t *buffer)
act = 0;
}
-#line 113 "hb-ot-shape-complex-indic-machine.rl"
+#line 122 "hb-ot-shape-complex-indic-machine.rl"
p = 0;
@@ -423,7 +452,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 427 "hb-ot-shape-complex-indic-machine.hh"
+#line 456 "hb-ot-shape-complex-indic-machine.hh"
{
int _slen;
int _trans;
@@ -437,7 +466,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 441 "hb-ot-shape-complex-indic-machine.hh"
+#line 470 "hb-ot-shape-complex-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -460,64 +489,64 @@ _eof_trans:
{te = p+1;}
break;
case 11:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (indic_non_indic_cluster); }}
break;
case 13:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_consonant_syllable); }}
break;
case 14:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_vowel_syllable); }}
break;
case 17:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_standalone_cluster); }}
break;
case 19:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_symbol_cluster); }}
break;
case 15:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_broken_cluster); }}
break;
case 16:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ found_syllable (non_indic_cluster); }}
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (indic_non_indic_cluster); }}
break;
case 1:
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }}
break;
case 3:
-#line 85 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
+#line 94 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }}
break;
case 7:
-#line 86 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
+#line 95 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }}
break;
case 8:
-#line 87 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }}
break;
case 4:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); }}
break;
case 6:
#line 1 "NONE"
{ switch( act ) {
case 1:
- {{p = ((te))-1;} found_syllable (consonant_syllable); }
+ {{p = ((te))-1;} found_syllable (indic_consonant_syllable); }
break;
case 5:
- {{p = ((te))-1;} found_syllable (broken_cluster); }
+ {{p = ((te))-1;} found_syllable (indic_broken_cluster); }
break;
case 6:
- {{p = ((te))-1;} found_syllable (non_indic_cluster); }
+ {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); }
break;
}
}
@@ -525,22 +554,22 @@ _eof_trans:
case 18:
#line 1 "NONE"
{te = p+1;}
-#line 84 "hb-ot-shape-complex-indic-machine.rl"
+#line 93 "hb-ot-shape-complex-indic-machine.rl"
{act = 1;}
break;
case 5:
#line 1 "NONE"
{te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 97 "hb-ot-shape-complex-indic-machine.rl"
{act = 5;}
break;
case 12:
#line 1 "NONE"
{te = p+1;}
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 98 "hb-ot-shape-complex-indic-machine.rl"
{act = 6;}
break;
-#line 544 "hb-ot-shape-complex-indic-machine.hh"
+#line 573 "hb-ot-shape-complex-indic-machine.hh"
}
_again:
@@ -549,7 +578,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 553 "hb-ot-shape-complex-indic-machine.hh"
+#line 582 "hb-ot-shape-complex-indic-machine.hh"
}
if ( ++p != pe )
@@ -565,7 +594,7 @@ _again:
}
-#line 121 "hb-ot-shape-complex-indic-machine.rl"
+#line 130 "hb-ot-shape-complex-indic-machine.rl"
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
index a150fd2486..dd204b23c1 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
@@ -82,7 +82,7 @@
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
-static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
+static const uint16_t indic_table[] = {
#define indic_offset_0x0028u 0
@@ -404,7 +404,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
}; /* Table items: 1792; occupancy: 70% */
-INDIC_TABLE_ELEMENT_TYPE
+uint16_t
hb_indic_get_categories (hb_codepoint_t u)
{
switch (u >> 12)
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
index 652ef47040..a4f2d9a847 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-indic.hh"
+#include "hb-ot-shape-complex-indic-machine.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
#include "hb-ot-layout.hh"
@@ -337,19 +338,6 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
return POS_BASE_C;
}
-
-enum indic_syllable_type_t {
- indic_consonant_syllable,
- indic_vowel_syllable,
- indic_standalone_cluster,
- indic_symbol_cluster,
- indic_broken_cluster,
- indic_non_indic_cluster,
-};
-
-#include "hb-ot-shape-complex-indic-machine.hh"
-
-
static void
setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -764,7 +752,28 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
* We could use buffer->sort() for this, if there was no special
* reordering of pre-base stuff happening later...
* We don't want to merge_clusters all of that, which buffer->sort()
- * would.
+ * would. Here's a concrete example:
+ *
+ * Assume there's a pre-base consonant and explicit Halant before base,
+ * followed by a prebase-reordering (left) Matra:
+ *
+ * C,H,ZWNJ,B,M
+ *
+ * At this point in reordering we would have:
+ *
+ * M,C,H,ZWNJ,B
+ *
+ * whereas in final reordering we will bring the Matra closer to Base:
+ *
+ * C,H,ZWNJ,M,B
+ *
+ * That's why we don't want to merge-clusters anything before the Base
+ * at this point. But if something moved from after Base to before it,
+ * we should merge clusters from base to them. In final-reordering, we
+ * only move things around before base, and merge-clusters up to base.
+ * These two merge-clusters from the two sides of base will interlock
+ * to merge things correctly. See:
+ * https://github.com/harfbuzz/harfbuzz/issues/2272
*/
if (indic_plan->is_old_spec || end - start > 127)
buffer->merge_clusters (base, end);
@@ -774,17 +783,18 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
for (unsigned int i = base; i < end; i++)
if (info[i].syllable() != 255)
{
+ unsigned int min = i;
unsigned int max = i;
unsigned int j = start + info[i].syllable();
while (j != i)
{
+ min = hb_min (min, j);
max = hb_max (max, j);
unsigned int next = start + info[j].syllable();
info[j].syllable() = 255; /* So we don't process j later again. */
j = next;
}
- if (i != max)
- buffer->merge_clusters (i, max + 1);
+ buffer->merge_clusters (hb_max (base, min), max + 1);
}
}
@@ -938,69 +948,6 @@ initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
}
}
-static inline void
-insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == indic_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_indic_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().indic_category() == OT_Repha)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
@@ -1008,11 +955,16 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan,
{
if (!buffer->message (font, "start reordering indic initial"))
return;
+
update_consonant_positions_indic (plan, font, buffer);
- insert_dotted_circles_indic (plan, font, buffer);
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ indic_broken_cluster,
+ OT_DOTTEDCIRCLE,
+ OT_Repha);
foreach_syllable (buffer, start, end)
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);
+
(void) buffer->message (font, "end reordering indic initial");
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
index 41bd8bd6cc..dcb28a4e84 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh
@@ -29,16 +29,14 @@
#include "hb.hh"
-#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape-complex-syllabic.hh"
/* buffer var allocations */
-#define indic_category() complex_var_u8_0() /* indic_category_t */
-#define indic_position() complex_var_u8_1() /* indic_position_t */
+#define indic_category() complex_var_u8_category() /* indic_category_t */
+#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */
-#define INDIC_TABLE_ELEMENT_TYPE uint16_t
-
/* Cateories used in the OpenType spec:
* https://docs.microsoft.com/en-us/typography/script-development/devanagari
*/
@@ -177,7 +175,7 @@ enum indic_matra_category_t {
#define INDIC_COMBINE_CATEGORIES(S,M) \
( \
- ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+ static_assert_expr (S < 255 && M < 255) + \
( S | \
( \
( \
@@ -194,7 +192,7 @@ enum indic_matra_category_t {
) \
)
-HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+HB_INTERNAL uint16_t
hb_indic_get_categories (hb_codepoint_t u);
@@ -307,17 +305,12 @@ static const hb_codepoint_t ra_chars[] = {
0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
-
- 0x179Au, /* Khmer */
};
static inline bool
is_ra (hb_codepoint_t u)
{
- for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
- if (u == ra_chars[i])
- return true;
- return false;
+ return hb_array (ra_chars).lfind (u);
}
static inline void
@@ -325,7 +318,7 @@ set_indic_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_category_t cat = (indic_category_t) (type & 0xFFu);
indic_position_t pos = (indic_position_t) (type >> 8);
@@ -370,6 +363,7 @@ set_indic_properties (hb_glyph_info_t &info)
else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N;
else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */
+ else if (unlikely (u == 0x0B55u)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/2849 */
else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */
else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
index a040318d34..82ab186a41 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
@@ -1,211 +1,179 @@
-
#line 1 "hb-ot-shape-complex-khmer-machine.rl"
/*
- * Copyright © 2011,2012 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
+* Copyright © 2011,2012 Google, Inc.
+*
+* This is part of HarfBuzz, a text shaping library.
+*
+* Permission is hereby granted, without written agreement and without
+* license or royalty fees, to use, copy, modify, and distribute this
+* software and its documentation for any purpose, provided that the
+* above copyright notice and the following two paragraphs appear in
+* all copies of this software.
+*
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*
+* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*
+* Google Author(s): Behdad Esfahbod
+*/
#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#include "hb.hh"
+enum khmer_syllable_type_t {
+ khmer_consonant_syllable,
+ khmer_broken_cluster,
+ khmer_non_khmer_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-khmer-machine.hh"
+#line 41 "hb-ot-shape-complex-khmer-machine.hh"
+#define khmer_syllable_machine_ex_C 1u
+#define khmer_syllable_machine_ex_Coeng 14u
+#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
+#define khmer_syllable_machine_ex_PLACEHOLDER 11u
+#define khmer_syllable_machine_ex_Ra 16u
+#define khmer_syllable_machine_ex_Robatic 20u
+#define khmer_syllable_machine_ex_V 2u
+#define khmer_syllable_machine_ex_VAbv 26u
+#define khmer_syllable_machine_ex_VBlw 27u
+#define khmer_syllable_machine_ex_VPre 28u
+#define khmer_syllable_machine_ex_VPst 29u
+#define khmer_syllable_machine_ex_Xgroup 21u
+#define khmer_syllable_machine_ex_Ygroup 22u
+#define khmer_syllable_machine_ex_ZWJ 6u
+#define khmer_syllable_machine_ex_ZWNJ 5u
+
+
+#line 59 "hb-ot-shape-complex-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
- 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
- 5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u,
- 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u,
- 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u,
- 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u,
- 0
+ 2u, 8u, 2u, 6u, 2u, 8u, 2u, 6u,
+ 0u, 0u, 2u, 6u, 2u, 8u, 2u, 6u,
+ 2u, 8u, 2u, 6u, 2u, 6u, 2u, 8u,
+ 2u, 6u, 0u, 0u, 2u, 6u, 2u, 8u,
+ 2u, 6u, 2u, 8u, 2u, 6u, 2u, 8u,
+ 0u, 11u, 2u, 11u, 2u, 11u, 2u, 11u,
+ 7u, 7u, 2u, 7u, 2u, 11u, 2u, 11u,
+ 2u, 11u, 0u, 0u, 2u, 8u, 2u, 11u,
+ 2u, 11u, 7u, 7u, 2u, 7u, 2u, 11u,
+ 2u, 11u, 0u, 0u, 2u, 11u, 2u, 11u,
+ 0u
};
-static const char _khmer_syllable_machine_key_spans[] = {
- 22, 17, 22, 17, 16, 17, 22, 17,
- 22, 17, 17, 22, 17, 16, 17, 22,
- 17, 22, 17, 22, 29, 25, 25, 25,
- 1, 18, 25, 25, 25, 16, 22, 25,
- 25, 1, 18, 25, 25, 16, 25, 25
+static const signed char _khmer_syllable_machine_char_class[] = {
+ 0, 0, 1, 1, 2, 2, 1, 1,
+ 1, 1, 3, 3, 1, 4, 1, 0,
+ 1, 1, 1, 5, 6, 7, 1, 1,
+ 1, 8, 9, 10, 11, 0
};
static const short _khmer_syllable_machine_index_offsets[] = {
- 0, 23, 41, 64, 82, 99, 117, 140,
- 158, 181, 199, 217, 240, 258, 275, 293,
- 316, 334, 357, 375, 398, 428, 454, 480,
- 506, 508, 527, 553, 579, 605, 622, 645,
- 671, 697, 699, 718, 744, 770, 787, 813
+ 0, 7, 12, 19, 24, 25, 30, 37,
+ 42, 49, 54, 59, 66, 71, 72, 77,
+ 84, 89, 96, 101, 108, 120, 130, 140,
+ 150, 151, 157, 167, 177, 187, 188, 195,
+ 205, 215, 216, 222, 232, 242, 243, 253,
+ 0
};
-static const char _khmer_syllable_machine_indicies[] = {
- 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 2,
- 3, 0, 0, 0, 0, 4, 0, 1,
- 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 3,
- 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 3, 0, 0, 0, 0, 4, 0,
- 5, 5, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 0, 6, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 6, 0, 7, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 0, 9, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 10, 0, 0,
- 0, 0, 4, 0, 9, 9, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 10, 0, 11, 11,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 12, 0,
- 0, 0, 0, 4, 0, 11, 11, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 0, 14,
- 14, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 15,
- 13, 14, 14, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 15, 16, 16, 16, 16, 17, 16,
- 18, 18, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 17, 16, 19, 19, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 19, 16, 20, 20, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 21, 16, 22, 22, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 23, 16, 16,
- 16, 16, 17, 16, 22, 22, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 23, 16, 24, 24,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 25, 16,
- 16, 16, 16, 17, 16, 24, 24, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 25, 16, 14,
- 14, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 26, 15,
- 16, 16, 16, 16, 17, 16, 28, 28,
- 27, 27, 29, 29, 27, 27, 27, 27,
- 2, 2, 27, 30, 27, 28, 27, 27,
- 27, 27, 15, 19, 27, 27, 27, 17,
- 23, 25, 21, 27, 32, 32, 31, 31,
- 31, 31, 31, 31, 31, 33, 31, 31,
- 31, 31, 31, 2, 3, 6, 31, 31,
- 31, 4, 10, 12, 8, 31, 34, 34,
- 31, 31, 31, 31, 31, 31, 31, 35,
- 31, 31, 31, 31, 31, 31, 3, 6,
- 31, 31, 31, 4, 10, 12, 8, 31,
- 5, 5, 31, 31, 31, 31, 31, 31,
- 31, 35, 31, 31, 31, 31, 31, 31,
- 4, 6, 31, 31, 31, 31, 31, 31,
- 8, 31, 6, 31, 7, 7, 31, 31,
- 31, 31, 31, 31, 31, 35, 31, 31,
- 31, 31, 31, 31, 8, 6, 31, 36,
- 36, 31, 31, 31, 31, 31, 31, 31,
- 35, 31, 31, 31, 31, 31, 31, 10,
- 6, 31, 31, 31, 4, 31, 31, 8,
- 31, 37, 37, 31, 31, 31, 31, 31,
- 31, 31, 35, 31, 31, 31, 31, 31,
- 31, 12, 6, 31, 31, 31, 4, 10,
- 31, 8, 31, 34, 34, 31, 31, 31,
- 31, 31, 31, 31, 33, 31, 31, 31,
- 31, 31, 31, 3, 6, 31, 31, 31,
- 4, 10, 12, 8, 31, 28, 28, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 28, 31, 14, 14,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 15, 38,
- 38, 38, 38, 17, 38, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 41, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 18,
- 18, 39, 39, 39, 39, 39, 39, 39,
- 41, 39, 39, 39, 39, 39, 39, 17,
- 19, 39, 39, 39, 39, 39, 39, 21,
- 39, 19, 39, 20, 20, 39, 39, 39,
- 39, 39, 39, 39, 41, 39, 39, 39,
- 39, 39, 39, 21, 19, 39, 42, 42,
- 39, 39, 39, 39, 39, 39, 39, 41,
- 39, 39, 39, 39, 39, 39, 23, 19,
- 39, 39, 39, 17, 39, 39, 21, 39,
- 43, 43, 39, 39, 39, 39, 39, 39,
- 39, 41, 39, 39, 39, 39, 39, 39,
- 25, 19, 39, 39, 39, 17, 23, 39,
- 21, 39, 44, 44, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 44, 39, 45, 45, 39, 39, 39,
- 39, 39, 39, 39, 30, 39, 39, 39,
- 39, 39, 26, 15, 19, 39, 39, 39,
- 17, 23, 25, 21, 39, 40, 40, 39,
- 39, 39, 39, 39, 39, 39, 30, 39,
- 39, 39, 39, 39, 39, 15, 19, 39,
- 39, 39, 17, 23, 25, 21, 39, 0
+static const signed char _khmer_syllable_machine_indicies[] = {
+ 1, 0, 0, 2, 3, 0, 4, 1,
+ 0, 0, 0, 3, 1, 0, 0, 0,
+ 3, 0, 4, 5, 0, 0, 0, 4,
+ 6, 7, 0, 0, 0, 8, 9, 0,
+ 0, 0, 10, 0, 4, 9, 0, 0,
+ 0, 10, 11, 0, 0, 0, 12, 0,
+ 4, 11, 0, 0, 0, 12, 14, 13,
+ 13, 13, 15, 14, 16, 16, 16, 15,
+ 16, 17, 18, 16, 16, 16, 17, 19,
+ 20, 16, 16, 16, 21, 22, 16, 16,
+ 16, 23, 16, 17, 22, 16, 16, 16,
+ 23, 24, 16, 16, 16, 25, 16, 17,
+ 24, 16, 16, 16, 25, 14, 16, 16,
+ 26, 15, 16, 17, 29, 28, 30, 2,
+ 31, 28, 15, 19, 17, 23, 25, 21,
+ 33, 32, 34, 2, 3, 6, 4, 10,
+ 12, 8, 35, 32, 36, 32, 3, 6,
+ 4, 10, 12, 8, 5, 32, 36, 32,
+ 4, 6, 32, 32, 32, 8, 6, 7,
+ 32, 36, 32, 8, 6, 37, 32, 36,
+ 32, 10, 6, 4, 32, 32, 8, 38,
+ 32, 36, 32, 12, 6, 4, 10, 32,
+ 8, 35, 32, 34, 32, 3, 6, 4,
+ 10, 12, 8, 29, 14, 39, 39, 39,
+ 15, 39, 17, 41, 40, 42, 40, 15,
+ 19, 17, 23, 25, 21, 18, 40, 42,
+ 40, 17, 19, 40, 40, 40, 21, 19,
+ 20, 40, 42, 40, 21, 19, 43, 40,
+ 42, 40, 23, 19, 17, 40, 40, 21,
+ 44, 40, 42, 40, 25, 19, 17, 23,
+ 40, 21, 45, 46, 40, 31, 26, 15,
+ 19, 17, 23, 25, 21, 41, 40, 31,
+ 40, 15, 19, 17, 23, 25, 21, 0
};
-static const char _khmer_syllable_machine_trans_targs[] = {
- 20, 1, 28, 22, 23, 3, 24, 5,
- 25, 7, 26, 9, 27, 20, 10, 31,
- 20, 32, 12, 33, 14, 34, 16, 35,
- 18, 36, 39, 20, 21, 30, 37, 20,
- 0, 29, 2, 4, 6, 8, 20, 20,
- 11, 13, 15, 17, 38, 19
+static const signed char _khmer_syllable_machine_index_defaults[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 13, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 28, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 39, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40,
+ 0
};
-static const char _khmer_syllable_machine_trans_actions[] = {
- 1, 0, 2, 2, 2, 0, 0, 0,
- 2, 0, 2, 0, 2, 3, 0, 4,
- 5, 2, 0, 0, 0, 2, 0, 2,
- 0, 2, 4, 8, 2, 9, 0, 10,
- 0, 0, 0, 0, 0, 0, 11, 12,
- 0, 0, 0, 0, 4, 0
+static const signed char _khmer_syllable_machine_cond_targs[] = {
+ 20, 1, 28, 22, 23, 3, 24, 5,
+ 25, 7, 26, 9, 27, 20, 10, 31,
+ 20, 32, 12, 33, 14, 34, 16, 35,
+ 18, 36, 39, 20, 20, 21, 30, 37,
+ 20, 0, 29, 2, 4, 6, 8, 20,
+ 20, 11, 13, 15, 17, 38, 19, 0
};
-static const char _khmer_syllable_machine_to_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+static const signed char _khmer_syllable_machine_cond_actions[] = {
+ 1, 0, 2, 2, 2, 0, 0, 0,
+ 2, 0, 2, 0, 2, 3, 0, 4,
+ 5, 2, 0, 0, 0, 2, 0, 2,
+ 0, 2, 4, 0, 8, 2, 9, 0,
+ 10, 0, 0, 0, 0, 0, 0, 11,
+ 12, 0, 0, 0, 0, 4, 0, 0
};
-static const char _khmer_syllable_machine_from_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+static const signed char _khmer_syllable_machine_to_state_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
};
-static const unsigned char _khmer_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 14, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 0, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 39, 40,
- 40, 40, 40, 40, 40, 40, 40, 40
+static const signed char _khmer_syllable_machine_from_state_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0
+};
+
+static const signed char _khmer_syllable_machine_eof_trans[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 14, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 28, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 40, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41,
+ 0
};
static const int khmer_syllable_machine_start = 20;
@@ -215,156 +183,271 @@ static const int khmer_syllable_machine_error = -1;
static const int khmer_syllable_machine_en_main = 20;
-#line 36 "hb-ot-shape-complex-khmer-machine.rl"
+#line 43 "hb-ot-shape-complex-khmer-machine.rl"
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+#line 86 "hb-ot-shape-complex-khmer-machine.rl"
#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
+HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
static void
find_syllables_khmer (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 242 "hb-ot-shape-complex-khmer-machine.hh"
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+#line 210 "hb-ot-shape-complex-khmer-machine.hh"
{
- cs = khmer_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
+ cs = (int)khmer_syllable_machine_start;
+ ts = 0;
+ te = 0;
+ act = 0;
}
-
-#line 100 "hb-ot-shape-complex-khmer-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
-
-#line 258 "hb-ot-shape-complex-khmer-machine.hh"
+
+#line 106 "hb-ot-shape-complex-khmer-machine.rl"
+
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int syllable_serial = 1;
+
+#line 226 "hb-ot-shape-complex-khmer-machine.hh"
{
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
- case 7:
+ unsigned int _trans = 0;
+ const unsigned char * _keys;
+ const signed char * _inds;
+ int _ic;
+ _resume: {}
+ if ( p == pe && p != eof )
+ goto _out;
+ switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
+ case 7: {
+ {
#line 1 "NONE"
- {ts = p;}
- break;
-#line 272 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- _keys = _khmer_syllable_machine_trans_keys + (cs<<1);
- _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
-
- _slen = _khmer_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
- ( info[p].khmer_category()) <= _keys[1] ?
- ( info[p].khmer_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _khmer_syllable_machine_trans_targs[_trans];
-
- if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
- case 2:
+ {ts = p;}}
+
+#line 241 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ if ( p == eof ) {
+ if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = (unsigned int)_khmer_syllable_machine_eof_trans[cs] - 1;
+ }
+ }
+ else {
+ _keys = ( _khmer_syllable_machine_trans_keys + ((cs<<1)));
+ _inds = ( _khmer_syllable_machine_indicies + (_khmer_syllable_machine_index_offsets[cs]));
+
+ if ( (info[p].khmer_category()) <= 29 && (info[p].khmer_category()) >= 1 ) {
+ _ic = (int)_khmer_syllable_machine_char_class[(int)(info[p].khmer_category()) - 1];
+ if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
+ _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
+ else
+ _trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
+ }
+ else {
+ _trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
+ }
+
+ }
+ cs = (int)_khmer_syllable_machine_cond_targs[_trans];
+
+ if ( _khmer_syllable_machine_cond_actions[_trans] != 0 ) {
+
+ switch ( _khmer_syllable_machine_cond_actions[_trans] ) {
+ case 2: {
+ {
#line 1 "NONE"
- {te = p+1;}
- break;
- case 8:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p+1;{ found_syllable (non_khmer_cluster); }}
- break;
- case 10:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
- break;
- case 12:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
- break;
- case 11:
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p;p--;{ found_syllable (non_khmer_cluster); }}
- break;
- case 1:
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
- break;
- case 5:
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
- break;
- case 3:
+ {te = p+1;}}
+
+#line 279 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 8: {
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p+1;{
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ }}
+
+#line 292 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 10: {
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_consonant_syllable); }
+ }}
+
+#line 305 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 12: {
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ }}
+
+#line 318 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 11: {
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {te = p;p = p - 1;{
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ }}
+
+#line 331 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 1: {
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ {p = ((te))-1;
+ {
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_consonant_syllable); }
+ }}
+
+#line 345 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 5: {
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {p = ((te))-1;
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ }}
+
+#line 359 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 3: {
+ {
#line 1 "NONE"
- { switch( act ) {
- case 2:
- {{p = ((te))-1;} found_syllable (broken_cluster); }
- break;
- case 3:
- {{p = ((te))-1;} found_syllable (non_khmer_cluster); }
- break;
- }
- }
- break;
- case 4:
+ {switch( act ) {
+ case 2: {
+ p = ((te))-1;
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_broken_cluster); }
+ break;
+ }
+ case 3: {
+ p = ((te))-1;
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ found_syllable (khmer_non_khmer_cluster); }
+ break;
+ }
+ }}
+ }
+
+#line 385 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 4: {
+ {
#line 1 "NONE"
- {te = p+1;}
-#line 75 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 2;}
- break;
- case 9:
+ {te = p+1;}}
+
+#line 395 "hb-ot-shape-complex-khmer-machine.hh"
+
+ {
+#line 81 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 2;}}
+
+#line 401 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ case 9: {
+ {
#line 1 "NONE"
- {te = p+1;}
-#line 76 "hb-ot-shape-complex-khmer-machine.rl"
- {act = 3;}
- break;
-#line 342 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
-_again:
- switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
- case 6:
+ {te = p+1;}}
+
+#line 411 "hb-ot-shape-complex-khmer-machine.hh"
+
+ {
+#line 82 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 3;}}
+
+#line 417 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ }
+
+ if ( p == eof ) {
+ if ( cs >= 20 )
+ goto _out;
+ }
+ else {
+ switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+ case 6: {
+ {
#line 1 "NONE"
- {ts = 0;}
- break;
-#line 351 "hb-ot-shape-complex-khmer-machine.hh"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _khmer_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
+ {ts = 0;}}
+
+#line 437 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+ break;
+ }
+ }
+
+ p += 1;
+ goto _resume;
+ }
+ _out: {}
}
-
- }
-
-#line 108 "hb-ot-shape-complex-khmer-machine.rl"
-
+
+#line 114 "hb-ot-shape-complex-khmer-machine.rl"
+
}
#undef found_syllable
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl
deleted file mode 100644
index e7f14533dd..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright © 2011,2012 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-
-#include "hb.hh"
-
-%%{
- machine khmer_syllable_machine;
- alphtype unsigned char;
- write data;
-}%%
-
-%%{
-
-# Same order as enum khmer_category_t. Not sure how to avoid duplication.
-C = 1;
-V = 2;
-ZWNJ = 5;
-ZWJ = 6;
-PLACEHOLDER = 11;
-DOTTEDCIRCLE = 12;
-Coeng= 14;
-Ra = 16;
-Robatic = 20;
-Xgroup = 21;
-Ygroup = 22;
-VAbv = 26;
-VBlw = 27;
-VPre = 28;
-VPst = 29;
-
-c = (C | Ra | V);
-cn = c.((ZWJ|ZWNJ)?.Robatic)?;
-joiner = (ZWJ | ZWNJ);
-xgroup = (joiner*.Xgroup)*;
-ygroup = Ygroup*;
-
-# This grammar was experimentally extracted from what Uniscribe allows.
-
-matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?;
-syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup;
-
-
-broken_cluster = (Coeng.cn)* (Coeng | syllable_tail);
-consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
-other = any;
-
-main := |*
- consonant_syllable => { found_syllable (consonant_syllable); };
- broken_cluster => { found_syllable (broken_cluster); };
- other => { found_syllable (non_khmer_cluster); };
-*|;
-
-
-}%%
-
-#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
- for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
-
-static void
-find_syllables_khmer (hb_buffer_t *buffer)
-{
- unsigned int p, pe, eof, ts, te, act HB_UNUSED;
- int cs;
- hb_glyph_info_t *info = buffer->info;
- %%{
- write init;
- getkey info[p].khmer_category();
- }%%
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int syllable_serial = 1;
- %%{
- write exec;
- }%%
-}
-
-#undef found_syllable
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
index d6fcd7c814..dddba142a3 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-khmer.hh"
+#include "hb-ot-shape-complex-khmer-machine.hh"
#include "hb-ot-layout.hh"
@@ -140,27 +141,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan)
struct khmer_shape_plan_t
{
- bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
- {
- hb_codepoint_t glyph = virama_glyph;
- if (unlikely (virama_glyph == (hb_codepoint_t) -1))
- {
- if (!font->get_nominal_glyph (0x17D2u, &glyph))
- glyph = 0;
- /* Technically speaking, the spec says we should apply 'locl' to virama too.
- * Maybe one day... */
-
- /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
- * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */
- virama_glyph = glyph;
- }
-
- *pglyph = glyph;
- return glyph != 0;
- }
-
- mutable hb_codepoint_t virama_glyph;
-
hb_mask_t mask_array[KHMER_NUM_FEATURES];
};
@@ -171,8 +151,6 @@ data_create_khmer (const hb_ot_shape_plan_t *plan)
if (unlikely (!khmer_plan))
return nullptr;
- khmer_plan->virama_glyph = (hb_codepoint_t) -1;
-
for (unsigned int i = 0; i < ARRAY_LENGTH (khmer_plan->mask_array); i++)
khmer_plan->mask_array[i] = (khmer_features[i].flags & F_GLOBAL) ?
0 : plan->map.get_1_mask (khmer_features[i].tag);
@@ -186,15 +164,6 @@ data_destroy_khmer (void *data)
free (data);
}
-
-enum khmer_syllable_type_t {
- khmer_consonant_syllable,
- khmer_broken_cluster,
- khmer_non_khmer_cluster,
-};
-
-#include "hb-ot-shape-complex-khmer-machine.hh"
-
static void
setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -321,76 +290,17 @@ reorder_syllable_khmer (const hb_ot_shape_plan_t *plan,
}
}
-static inline void
-insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == khmer_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_khmer_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().khmer_category() == OT_Repha)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_khmer (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering khmer")) {
- insert_dotted_circles_khmer (plan, font, buffer);
+ if (buffer->message (font, "start reordering khmer"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ khmer_broken_cluster,
+ OT_DOTTEDCIRCLE,
+ OT_Repha);
foreach_syllable (buffer, start, end)
reorder_syllable_khmer (plan, font->face, buffer, start, end);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
index 11a77bfd4b..e24d68a8b5 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh
@@ -54,7 +54,7 @@ set_khmer_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- khmer_category_t cat = (khmer_category_t) (type & 0x7Fu);
+ khmer_category_t cat = (khmer_category_t) (type & 0xFFu);
indic_position_t pos = (indic_position_t) (type >> 8);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh
deleted file mode 100644
index 9ec1f3eb7c..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-machine-index.hh
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright © 2019,2020 David Corbett
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH
-#define HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH
-
-#include "hb.hh"
-
-
-template <typename Iter>
-struct machine_index_t :
- hb_iter_with_fallback_t<machine_index_t<Iter>,
- typename Iter::item_t>
-{
- machine_index_t (const Iter& it) : it (it) {}
- machine_index_t (const machine_index_t& o) : it (o.it) {}
-
- static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
- static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
-
- typename Iter::item_t __item__ () const { return *it; }
- typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
- unsigned __len__ () const { return it.len (); }
- void __next__ () { ++it; }
- void __forward__ (unsigned n) { it += n; }
- void __prev__ () { --it; }
- void __rewind__ (unsigned n) { it -= n; }
- void operator = (unsigned n)
- { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
- void operator = (const machine_index_t& o) { *this = (*o.it).first; }
- bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
- bool operator != (const machine_index_t& o) const { return !(*this == o); }
-
- private:
- Iter it;
-};
-struct
-{
- template <typename Iter,
- hb_requires (hb_is_iterable (Iter))>
- machine_index_t<hb_iter_type<Iter>>
- operator () (Iter&& it) const
- { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
-}
-HB_FUNCOBJ (machine_index);
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_MACHINE_INDEX_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
index c2f4c0045c..c09497896d 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -31,8 +31,43 @@
#include "hb.hh"
+enum myanmar_syllable_type_t {
+ myanmar_consonant_syllable,
+ myanmar_punctuation_cluster,
+ myanmar_broken_cluster,
+ myanmar_non_myanmar_cluster,
+};
+
-#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 43 "hb-ot-shape-complex-myanmar-machine.hh"
+#define myanmar_syllable_machine_ex_A 10u
+#define myanmar_syllable_machine_ex_As 18u
+#define myanmar_syllable_machine_ex_C 1u
+#define myanmar_syllable_machine_ex_CS 19u
+#define myanmar_syllable_machine_ex_D 32u
+#define myanmar_syllable_machine_ex_D0 20u
+#define myanmar_syllable_machine_ex_DB 3u
+#define myanmar_syllable_machine_ex_GB 11u
+#define myanmar_syllable_machine_ex_H 4u
+#define myanmar_syllable_machine_ex_IV 2u
+#define myanmar_syllable_machine_ex_MH 21u
+#define myanmar_syllable_machine_ex_MR 22u
+#define myanmar_syllable_machine_ex_MW 23u
+#define myanmar_syllable_machine_ex_MY 24u
+#define myanmar_syllable_machine_ex_P 31u
+#define myanmar_syllable_machine_ex_PT 25u
+#define myanmar_syllable_machine_ex_Ra 16u
+#define myanmar_syllable_machine_ex_V 8u
+#define myanmar_syllable_machine_ex_VAbv 26u
+#define myanmar_syllable_machine_ex_VBlw 27u
+#define myanmar_syllable_machine_ex_VPre 28u
+#define myanmar_syllable_machine_ex_VPst 29u
+#define myanmar_syllable_machine_ex_VS 30u
+#define myanmar_syllable_machine_ex_ZWJ 6u
+#define myanmar_syllable_machine_ex_ZWNJ 5u
+
+
+#line 71 "hb-ot-shape-complex-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
@@ -293,18 +328,18 @@ static const int myanmar_syllable_machine_error = -1;
static const int myanmar_syllable_machine_en_main = 0;
-#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 44 "hb-ot-shape-complex-myanmar-machine.rl"
-#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 101 "hb-ot-shape-complex-myanmar-machine.rl"
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
- info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -316,7 +351,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 355 "hb-ot-shape-complex-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -324,7 +359,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
act = 0;
}
-#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 121 "hb-ot-shape-complex-myanmar-machine.rl"
p = 0;
@@ -332,7 +367,7 @@ find_syllables_myanmar (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 371 "hb-ot-shape-complex-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -346,7 +381,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 385 "hb-ot-shape-complex-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -365,38 +400,38 @@ _eof_trans:
switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
case 6:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 4:
-#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 94 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 10:
-#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (punctuation_cluster); }}
+#line 95 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_punctuation_cluster); }}
break;
case 8:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (broken_cluster); }}
+#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_broken_cluster); }}
break;
case 3:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
case 5:
-#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (consonant_syllable); }}
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }}
break;
case 7:
-#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
+#line 96 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_broken_cluster); }}
break;
case 9:
-#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
- {te = p;p--;{ found_syllable (non_myanmar_cluster); }}
+#line 97 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }}
break;
-#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 435 "hb-ot-shape-complex-myanmar-machine.hh"
}
_again:
@@ -405,7 +440,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 444 "hb-ot-shape-complex-myanmar-machine.hh"
}
if ( ++p != pe )
@@ -421,7 +456,7 @@ _again:
}
-#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 129 "hb-ot-shape-complex-myanmar-machine.rl"
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
index fe096ef28a..bc5dcb904c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -29,6 +29,7 @@
#ifndef HB_NO_OT_SHAPE
#include "hb-ot-shape-complex-myanmar.hh"
+#include "hb-ot-shape-complex-myanmar-machine.hh"
/*
@@ -97,17 +98,6 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
}
-
-enum myanmar_syllable_type_t {
- myanmar_consonant_syllable,
- myanmar_punctuation_cluster,
- myanmar_broken_cluster,
- myanmar_non_myanmar_cluster,
-};
-
-#include "hb-ot-shape-complex-myanmar-machine.hh"
-
-
static void
setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer,
@@ -265,70 +255,16 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
}
-static inline void
-insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- dottedcircle.codepoint = 0x25CCu;
- set_myanmar_properties (dottedcircle);
- dottedcircle.codepoint = dottedcircle_glyph;
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_myanmar (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering myanmar")) {
- insert_dotted_circles_myanmar (plan, font, buffer);
+ if (buffer->message (font, "start reordering myanmar"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ myanmar_broken_cluster,
+ OT_GB);
foreach_syllable (buffer, start, end)
reorder_syllable_myanmar (plan, font->face, buffer, start, end);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
index 7b9821e6ba..a6d68aae57 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh
@@ -64,7 +64,7 @@ set_myanmar_properties (hb_glyph_info_t &info)
{
hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u);
- unsigned int cat = type & 0x7Fu;
+ unsigned int cat = type & 0xFFu;
indic_position_t pos = (indic_position_t) (type >> 8);
/* Myanmar
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc
new file mode 100644
index 0000000000..46509abee2
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright © 2021 Behdad Esfahbod.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb.hh"
+
+#ifndef HB_NO_OT_SHAPE
+
+#include "hb-ot-shape-complex-syllabic.hh"
+
+
+void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int broken_syllable_type,
+ unsigned int dottedcircle_category,
+ int repha_category)
+{
+ if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
+ return;
+
+ /* Note: This loop is extra overhead, but should not be measurable.
+ * TODO Use a buffer scratch flag to remove the loop. */
+ bool has_broken_syllables = false;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if ((info[i].syllable() & 0x0F) == broken_syllable_type)
+ {
+ has_broken_syllables = true;
+ break;
+ }
+ if (likely (!has_broken_syllables))
+ return;
+
+
+ hb_codepoint_t dottedcircle_glyph;
+ if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ dottedcircle.complex_var_u8_category() = dottedcircle_category;
+ dottedcircle.codepoint = dottedcircle_glyph;
+
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+ while (buffer->idx < buffer->len && buffer->successful)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ if (unlikely (last_syllable != syllable && (syllable & 0x0F) == broken_syllable_type))
+ {
+ last_syllable = syllable;
+
+ hb_glyph_info_t ginfo = dottedcircle;
+ ginfo.cluster = buffer->cur().cluster;
+ ginfo.mask = buffer->cur().mask;
+ ginfo.syllable() = buffer->cur().syllable();
+
+ /* Insert dottedcircle after possible Repha. */
+ if (repha_category != -1)
+ {
+ while (buffer->idx < buffer->len && buffer->successful &&
+ last_syllable == buffer->cur().syllable() &&
+ buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
+ (void) buffer->next_glyph ();
+ }
+
+ (void) buffer->output_info (ginfo);
+ }
+ else
+ (void) buffer->next_glyph ();
+ }
+ buffer->swap_buffers ();
+}
+
+
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh
new file mode 100644
index 0000000000..c80b8fee1d
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2021 Behdad Esfahbod.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shape-complex.hh"
+
+
+HB_INTERNAL void
+hb_syllabic_insert_dotted_circles (hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int broken_syllable_type,
+ unsigned int dottedcircle_category,
+ int repha_category = -1);
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
index 347ea2e7ac..4c3068173b 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc
@@ -323,20 +323,19 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
unsigned int count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+ for (buffer->idx = 0; buffer->idx < count /* No need for: && buffer->successful */;)
{
hb_codepoint_t u = buffer->cur().codepoint;
- if (likely (!IS_SARA_AM (u))) {
- buffer->next_glyph ();
+ if (likely (!IS_SARA_AM (u)))
+ {
+ if (unlikely (!buffer->next_glyph ())) break;
continue;
}
/* Is SARA AM. Decompose and reorder. */
- hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
- _hb_glyph_info_set_continuation (&nikhahit);
- buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u));
- if (unlikely (!buffer->successful))
- return;
+ (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
+ _hb_glyph_info_set_continuation (&buffer->prev());
+ if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
/* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
unsigned int end = buffer->out_len;
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
index 144e7d3a40..b4b2b75100 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
@@ -1,300 +1,348 @@
-
#line 1 "hb-ot-shape-complex-use-machine.rl"
/*
- * Copyright © 2015 Mozilla Foundation.
- * Copyright © 2015 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
+* Copyright © 2015 Mozilla Foundation.
+* Copyright © 2015 Google, Inc.
+*
+* This is part of HarfBuzz, a text shaping library.
+*
+* Permission is hereby granted, without written agreement and without
+* license or royalty fees, to use, copy, modify, and distribute this
+* software and its documentation for any purpose, provided that the
+* above copyright notice and the following two paragraphs appear in
+* all copies of this software.
+*
+* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGE.
+*
+* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*
+* Mozilla Author(s): Jonathan Kew
+* Google Author(s): Behdad Esfahbod
+*/
#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#include "hb.hh"
-#include "hb-ot-shape-complex-machine-index.hh"
+#include "hb-ot-shape-complex-syllabic.hh"
+
+/* buffer var allocations */
+#define use_category() complex_var_u8_category()
+
+#define USE(Cat) use_syllable_machine_ex_##Cat
+
+enum use_syllable_type_t {
+ use_independent_cluster,
+ use_virama_terminated_cluster,
+ use_sakot_terminated_cluster,
+ use_standard_cluster,
+ use_number_joiner_terminated_cluster,
+ use_numeral_cluster,
+ use_symbol_cluster,
+ use_hieroglyph_cluster,
+ use_broken_cluster,
+ use_non_cluster,
+};
-#line 39 "hb-ot-shape-complex-use-machine.hh"
+
+#line 57 "hb-ot-shape-complex-use-machine.hh"
+#define use_syllable_machine_ex_B 1u
+#define use_syllable_machine_ex_CMAbv 31u
+#define use_syllable_machine_ex_CMBlw 32u
+#define use_syllable_machine_ex_CS 43u
+#define use_syllable_machine_ex_FAbv 24u
+#define use_syllable_machine_ex_FBlw 25u
+#define use_syllable_machine_ex_FMAbv 45u
+#define use_syllable_machine_ex_FMBlw 46u
+#define use_syllable_machine_ex_FMPst 47u
+#define use_syllable_machine_ex_FPst 26u
+#define use_syllable_machine_ex_G 49u
+#define use_syllable_machine_ex_GB 5u
+#define use_syllable_machine_ex_H 12u
+#define use_syllable_machine_ex_HN 13u
+#define use_syllable_machine_ex_HVM 44u
+#define use_syllable_machine_ex_J 50u
+#define use_syllable_machine_ex_MAbv 27u
+#define use_syllable_machine_ex_MBlw 28u
+#define use_syllable_machine_ex_MPre 30u
+#define use_syllable_machine_ex_MPst 29u
+#define use_syllable_machine_ex_N 4u
+#define use_syllable_machine_ex_O 0u
+#define use_syllable_machine_ex_R 18u
+#define use_syllable_machine_ex_S 19u
+#define use_syllable_machine_ex_SB 51u
+#define use_syllable_machine_ex_SE 52u
+#define use_syllable_machine_ex_SMAbv 41u
+#define use_syllable_machine_ex_SMBlw 42u
+#define use_syllable_machine_ex_SUB 11u
+#define use_syllable_machine_ex_Sk 48u
+#define use_syllable_machine_ex_VAbv 33u
+#define use_syllable_machine_ex_VBlw 34u
+#define use_syllable_machine_ex_VMAbv 37u
+#define use_syllable_machine_ex_VMBlw 38u
+#define use_syllable_machine_ex_VMPre 23u
+#define use_syllable_machine_ex_VMPst 39u
+#define use_syllable_machine_ex_VPre 22u
+#define use_syllable_machine_ex_VPst 35u
+#define use_syllable_machine_ex_ZWNJ 14u
+
+
+#line 99 "hb-ot-shape-complex-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 1u, 1u, 1u, 1u, 0u, 51u, 11u, 48u, 11u, 48u, 1u, 1u, 22u, 48u, 23u, 48u,
- 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u,
- 1u, 1u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u,
- 11u, 48u, 1u, 48u, 13u, 13u, 4u, 4u, 11u, 48u, 41u, 42u, 42u, 42u, 11u, 48u,
- 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u,
- 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u,
- 22u, 48u, 11u, 48u, 1u, 48u, 1u, 1u, 4u, 4u, 13u, 13u, 1u, 48u, 11u, 48u,
- 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, 0
+ 1u, 1u, 1u, 1u, 0u, 37u, 5u, 34u,
+ 5u, 34u, 1u, 1u, 10u, 34u, 11u, 34u,
+ 12u, 33u, 13u, 33u, 14u, 33u, 31u, 32u,
+ 32u, 32u, 12u, 34u, 12u, 34u, 12u, 34u,
+ 1u, 1u, 12u, 34u, 11u, 34u, 11u, 34u,
+ 11u, 34u, 10u, 34u, 10u, 34u, 10u, 34u,
+ 5u, 34u, 1u, 34u, 7u, 7u, 3u, 3u,
+ 5u, 34u, 27u, 28u, 28u, 28u, 5u, 34u,
+ 10u, 34u, 11u, 34u, 12u, 33u, 13u, 33u,
+ 14u, 33u, 31u, 32u, 32u, 32u, 12u, 34u,
+ 12u, 34u, 12u, 34u, 12u, 34u, 11u, 34u,
+ 11u, 34u, 11u, 34u, 10u, 34u, 10u, 34u,
+ 10u, 34u, 5u, 34u, 1u, 34u, 1u, 1u,
+ 3u, 3u, 7u, 7u, 1u, 34u, 5u, 34u,
+ 27u, 28u, 28u, 28u, 1u, 4u, 36u, 38u,
+ 35u, 38u, 35u, 37u, 0u
};
-static const char _use_syllable_machine_key_spans[] = {
- 1, 1, 52, 38, 38, 1, 27, 26,
- 24, 23, 22, 2, 1, 25, 25, 25,
- 1, 25, 26, 26, 26, 27, 27, 27,
- 38, 48, 1, 1, 38, 2, 1, 38,
- 27, 26, 24, 23, 22, 2, 1, 25,
- 25, 25, 25, 26, 26, 26, 27, 27,
- 27, 38, 48, 1, 1, 1, 48, 38,
- 2, 1, 5, 3, 4, 3
+static const signed char _use_syllable_machine_char_class[] = {
+ 0, 1, 2, 2, 3, 4, 2, 2,
+ 2, 2, 2, 5, 6, 7, 2, 2,
+ 2, 2, 8, 9, 2, 2, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 2, 24, 25, 26,
+ 2, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 0
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 2, 4, 57, 96, 135, 137, 165,
- 192, 217, 241, 264, 267, 269, 295, 321,
- 347, 349, 375, 402, 429, 456, 484, 512,
- 540, 579, 628, 630, 632, 671, 674, 676,
- 715, 743, 770, 795, 819, 842, 845, 847,
- 873, 899, 925, 951, 978, 1005, 1032, 1060,
- 1088, 1116, 1155, 1204, 1206, 1208, 1210, 1259,
- 1298, 1301, 1303, 1309, 1313, 1318
+ 0, 1, 2, 40, 70, 100, 101, 126,
+ 150, 172, 193, 213, 215, 216, 239, 262,
+ 285, 286, 309, 333, 357, 381, 406, 431,
+ 456, 486, 520, 521, 522, 552, 554, 555,
+ 585, 610, 634, 656, 677, 697, 699, 700,
+ 723, 746, 769, 792, 816, 840, 864, 889,
+ 914, 939, 969, 1003, 1004, 1005, 1006, 1040,
+ 1070, 1072, 1073, 1077, 1080, 1084, 0
+};
+
+static const signed char _use_syllable_machine_indicies[] = {
+ 1, 2, 4, 5, 6, 7, 8, 1,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 13, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 9, 36, 6, 37,
+ 39, 40, 38, 38, 38, 41, 42, 43,
+ 44, 45, 46, 47, 41, 48, 5, 49,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 56, 57, 58, 59, 40, 39, 40,
+ 38, 38, 38, 41, 42, 43, 44, 45,
+ 46, 47, 41, 48, 49, 49, 50, 51,
+ 52, 53, 54, 55, 38, 38, 38, 56,
+ 57, 58, 59, 40, 39, 41, 42, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 42, 57, 58, 59, 61, 42, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 53, 54, 55, 38, 38,
+ 38, 38, 57, 58, 59, 61, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 57, 58, 59, 44, 45, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 57, 58,
+ 59, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 57, 58, 59, 57, 58, 58,
+ 43, 44, 45, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 53, 54, 55, 38,
+ 38, 38, 38, 57, 58, 59, 61, 43,
+ 44, 45, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 54, 55, 38, 38,
+ 38, 38, 57, 58, 59, 61, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 55, 38, 38, 38,
+ 38, 57, 58, 59, 61, 63, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 50,
+ 51, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 51, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 42, 43, 44,
+ 45, 38, 38, 38, 38, 38, 38, 38,
+ 38, 52, 53, 54, 55, 38, 38, 38,
+ 42, 57, 58, 59, 61, 41, 42, 43,
+ 44, 45, 38, 47, 41, 38, 38, 38,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 42, 57, 58, 59, 61, 41, 42,
+ 43, 44, 45, 38, 38, 41, 38, 38,
+ 38, 50, 51, 52, 53, 54, 55, 38,
+ 38, 38, 42, 57, 58, 59, 61, 41,
+ 42, 43, 44, 45, 46, 47, 41, 38,
+ 38, 38, 50, 51, 52, 53, 54, 55,
+ 38, 38, 38, 42, 57, 58, 59, 61,
+ 39, 40, 38, 38, 38, 41, 42, 43,
+ 44, 45, 46, 47, 41, 48, 38, 49,
+ 50, 51, 52, 53, 54, 55, 38, 38,
+ 38, 56, 57, 58, 59, 40, 39, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60,
+ 42, 43, 44, 45, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 53, 54, 55,
+ 60, 60, 60, 60, 57, 58, 59, 61,
+ 65, 7, 39, 40, 38, 38, 38, 41,
+ 42, 43, 44, 45, 46, 47, 41, 48,
+ 5, 49, 50, 51, 52, 53, 54, 55,
+ 12, 67, 38, 56, 57, 58, 59, 40,
+ 12, 67, 67, 1, 70, 69, 69, 69,
+ 13, 14, 15, 16, 17, 18, 19, 13,
+ 20, 22, 22, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 32, 33, 34, 35,
+ 70, 13, 14, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 23, 24, 25, 26,
+ 27, 28, 69, 69, 69, 14, 33, 34,
+ 35, 71, 14, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 26,
+ 27, 28, 69, 69, 69, 69, 33, 34,
+ 35, 71, 15, 16, 17, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 33, 34, 35,
+ 16, 17, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 33, 34, 35, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 33, 34,
+ 35, 33, 34, 34, 15, 16, 17, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 26, 27, 28, 69, 69, 69, 69, 33,
+ 34, 35, 71, 15, 16, 17, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 27, 28, 69, 69, 69, 69, 33, 34,
+ 35, 71, 15, 16, 17, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 28, 69, 69, 69, 69, 33, 34, 35,
+ 71, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 23, 24, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 24, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 14, 15, 16, 17, 69, 69, 69, 69,
+ 69, 69, 69, 69, 25, 26, 27, 28,
+ 69, 69, 69, 14, 33, 34, 35, 71,
+ 13, 14, 15, 16, 17, 69, 19, 13,
+ 69, 69, 69, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 14, 33, 34, 35,
+ 71, 13, 14, 15, 16, 17, 69, 69,
+ 13, 69, 69, 69, 23, 24, 25, 26,
+ 27, 28, 69, 69, 69, 14, 33, 34,
+ 35, 71, 13, 14, 15, 16, 17, 18,
+ 19, 13, 69, 69, 69, 23, 24, 25,
+ 26, 27, 28, 69, 69, 69, 14, 33,
+ 34, 35, 71, 1, 70, 69, 69, 69,
+ 13, 14, 15, 16, 17, 18, 19, 13,
+ 20, 69, 22, 23, 24, 25, 26, 27,
+ 28, 69, 69, 69, 32, 33, 34, 35,
+ 70, 1, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 14, 15, 16, 17, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 26, 27, 28, 69, 69, 69, 69, 33,
+ 34, 35, 71, 1, 73, 10, 5, 69,
+ 69, 5, 1, 70, 10, 69, 69, 13,
+ 14, 15, 16, 17, 18, 19, 13, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 69, 32, 33, 34, 35, 70,
+ 1, 70, 69, 69, 69, 13, 14, 15,
+ 16, 17, 18, 19, 13, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 69, 69,
+ 69, 32, 33, 34, 35, 70, 29, 30,
+ 30, 5, 72, 72, 5, 75, 74, 36,
+ 36, 75, 74, 75, 36, 74, 37, 0
};
-static const char _use_syllable_machine_indicies[] = {
- 1, 0, 2, 0, 3, 4, 5, 5,
- 6, 7, 5, 5, 5, 5, 5, 1,
- 8, 9, 5, 5, 5, 5, 10, 11,
- 5, 5, 12, 13, 14, 15, 16, 17,
- 18, 12, 19, 20, 21, 22, 23, 24,
- 5, 25, 26, 27, 5, 28, 29, 30,
- 31, 32, 33, 34, 8, 35, 5, 36,
- 5, 38, 39, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 40, 41, 42, 43,
- 44, 45, 46, 40, 47, 4, 48, 49,
- 50, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 55, 56, 57, 58, 39, 37,
- 38, 39, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 40, 41, 42, 43, 44,
- 45, 46, 40, 47, 48, 48, 49, 50,
- 51, 37, 52, 53, 54, 37, 37, 37,
- 37, 55, 56, 57, 58, 39, 37, 38,
- 59, 40, 41, 42, 43, 44, 37, 37,
- 37, 37, 37, 37, 49, 50, 51, 37,
- 52, 53, 54, 37, 37, 37, 37, 41,
- 56, 57, 58, 60, 37, 41, 42, 43,
- 44, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 52, 53, 54, 37, 37,
- 37, 37, 37, 56, 57, 58, 60, 37,
- 42, 43, 44, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 56, 57, 58,
- 37, 43, 44, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 56, 57, 58,
- 37, 44, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 56, 57, 58, 37,
- 56, 57, 37, 57, 37, 42, 43, 44,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 52, 53, 54, 37, 37, 37,
- 37, 37, 56, 57, 58, 60, 37, 42,
- 43, 44, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 53, 54, 37,
- 37, 37, 37, 37, 56, 57, 58, 60,
- 37, 42, 43, 44, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 54, 37, 37, 37, 37, 37, 56, 57,
- 58, 60, 37, 62, 61, 42, 43, 44,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 56, 57, 58, 60, 37, 41,
- 42, 43, 44, 37, 37, 37, 37, 37,
- 37, 49, 50, 51, 37, 52, 53, 54,
- 37, 37, 37, 37, 41, 56, 57, 58,
- 60, 37, 41, 42, 43, 44, 37, 37,
- 37, 37, 37, 37, 37, 50, 51, 37,
- 52, 53, 54, 37, 37, 37, 37, 41,
- 56, 57, 58, 60, 37, 41, 42, 43,
- 44, 37, 37, 37, 37, 37, 37, 37,
- 37, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 41, 56, 57, 58, 60, 37,
- 40, 41, 42, 43, 44, 37, 46, 40,
- 37, 37, 37, 49, 50, 51, 37, 52,
- 53, 54, 37, 37, 37, 37, 41, 56,
- 57, 58, 60, 37, 40, 41, 42, 43,
- 44, 37, 37, 40, 37, 37, 37, 49,
- 50, 51, 37, 52, 53, 54, 37, 37,
- 37, 37, 41, 56, 57, 58, 60, 37,
- 40, 41, 42, 43, 44, 45, 46, 40,
- 37, 37, 37, 49, 50, 51, 37, 52,
- 53, 54, 37, 37, 37, 37, 41, 56,
- 57, 58, 60, 37, 38, 39, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 40,
- 41, 42, 43, 44, 45, 46, 40, 47,
- 37, 48, 49, 50, 51, 37, 52, 53,
- 54, 37, 37, 37, 37, 55, 56, 57,
- 58, 39, 37, 38, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 41, 42, 43, 44, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 52,
- 53, 54, 59, 59, 59, 59, 59, 56,
- 57, 58, 60, 59, 64, 63, 6, 65,
- 38, 39, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 40, 41, 42, 43, 44,
- 45, 46, 40, 47, 4, 48, 49, 50,
- 51, 37, 52, 53, 54, 37, 11, 66,
- 37, 55, 56, 57, 58, 39, 37, 11,
- 66, 67, 66, 67, 1, 69, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 21, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 68, 68, 68, 31, 32, 33,
- 34, 69, 68, 12, 13, 14, 15, 16,
- 68, 68, 68, 68, 68, 68, 22, 23,
- 24, 68, 25, 26, 27, 68, 68, 68,
- 68, 13, 32, 33, 34, 70, 68, 13,
- 14, 15, 16, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 25, 26, 27,
- 68, 68, 68, 68, 68, 32, 33, 34,
- 70, 68, 14, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 32,
- 33, 34, 68, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 32,
- 33, 34, 68, 16, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 32, 33,
- 34, 68, 32, 33, 68, 33, 68, 14,
- 15, 16, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 25, 26, 27, 68,
- 68, 68, 68, 68, 32, 33, 34, 70,
- 68, 14, 15, 16, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 26,
- 27, 68, 68, 68, 68, 68, 32, 33,
- 34, 70, 68, 14, 15, 16, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 27, 68, 68, 68, 68, 68,
- 32, 33, 34, 70, 68, 14, 15, 16,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 32, 33, 34, 70, 68, 13,
- 14, 15, 16, 68, 68, 68, 68, 68,
- 68, 22, 23, 24, 68, 25, 26, 27,
- 68, 68, 68, 68, 13, 32, 33, 34,
- 70, 68, 13, 14, 15, 16, 68, 68,
- 68, 68, 68, 68, 68, 23, 24, 68,
- 25, 26, 27, 68, 68, 68, 68, 13,
- 32, 33, 34, 70, 68, 13, 14, 15,
- 16, 68, 68, 68, 68, 68, 68, 68,
- 68, 24, 68, 25, 26, 27, 68, 68,
- 68, 68, 13, 32, 33, 34, 70, 68,
- 12, 13, 14, 15, 16, 68, 18, 12,
- 68, 68, 68, 22, 23, 24, 68, 25,
- 26, 27, 68, 68, 68, 68, 13, 32,
- 33, 34, 70, 68, 12, 13, 14, 15,
- 16, 68, 68, 12, 68, 68, 68, 22,
- 23, 24, 68, 25, 26, 27, 68, 68,
- 68, 68, 13, 32, 33, 34, 70, 68,
- 12, 13, 14, 15, 16, 17, 18, 12,
- 68, 68, 68, 22, 23, 24, 68, 25,
- 26, 27, 68, 68, 68, 68, 13, 32,
- 33, 34, 70, 68, 1, 69, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 68, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 68, 68, 68, 31, 32, 33,
- 34, 69, 68, 1, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 13, 14, 15, 16, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 25,
- 26, 27, 68, 68, 68, 68, 68, 32,
- 33, 34, 70, 68, 1, 71, 72, 68,
- 9, 68, 4, 68, 68, 68, 4, 68,
- 68, 68, 68, 68, 1, 69, 9, 68,
- 68, 68, 68, 68, 68, 68, 68, 12,
- 13, 14, 15, 16, 17, 18, 12, 19,
- 20, 21, 22, 23, 24, 68, 25, 26,
- 27, 68, 28, 29, 68, 31, 32, 33,
- 34, 69, 68, 1, 69, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 12, 13,
- 14, 15, 16, 17, 18, 12, 19, 20,
- 21, 22, 23, 24, 68, 25, 26, 27,
- 68, 68, 68, 68, 31, 32, 33, 34,
- 69, 68, 28, 29, 68, 29, 68, 4,
- 71, 71, 71, 4, 71, 74, 73, 35,
- 73, 35, 74, 73, 74, 73, 35, 73,
- 36, 73, 0
+static const signed char _use_syllable_machine_index_defaults[] = {
+ 0, 0, 6, 38, 38, 60, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 62, 38, 38, 38, 38, 38, 38, 38,
+ 38, 60, 64, 66, 38, 68, 68, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 72, 69, 69, 69, 69,
+ 69, 69, 72, 74, 74, 74, 0
};
-static const char _use_syllable_machine_trans_targs[] = {
- 2, 31, 42, 2, 3, 2, 26, 28,
- 51, 52, 54, 29, 32, 33, 34, 35,
- 36, 46, 47, 48, 55, 49, 43, 44,
- 45, 39, 40, 41, 56, 57, 58, 50,
- 37, 38, 2, 59, 61, 2, 4, 5,
- 6, 7, 8, 9, 10, 21, 22, 23,
- 24, 18, 19, 20, 13, 14, 15, 25,
- 11, 12, 2, 2, 16, 2, 17, 2,
- 27, 2, 30, 2, 2, 0, 1, 2,
- 53, 2, 60
+static const signed char _use_syllable_machine_cond_targs[] = {
+ 2, 31, 42, 2, 2, 3, 2, 26,
+ 28, 51, 52, 54, 29, 32, 33, 34,
+ 35, 36, 46, 47, 48, 55, 49, 43,
+ 44, 45, 39, 40, 41, 56, 57, 58,
+ 50, 37, 38, 2, 59, 61, 2, 4,
+ 5, 6, 7, 8, 9, 10, 21, 22,
+ 23, 24, 18, 19, 20, 13, 14, 15,
+ 25, 11, 12, 2, 2, 16, 2, 17,
+ 2, 27, 2, 30, 2, 2, 0, 1,
+ 2, 53, 2, 60, 0
};
-static const char _use_syllable_machine_trans_actions[] = {
- 1, 2, 2, 5, 0, 6, 0, 0,
- 0, 0, 2, 0, 2, 2, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 0, 0, 0, 2,
- 0, 0, 7, 0, 0, 8, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 9, 10, 0, 11, 0, 12,
- 0, 13, 0, 14, 15, 0, 0, 16,
- 0, 17, 0
+static const signed char _use_syllable_machine_cond_actions[] = {
+ 1, 2, 2, 0, 5, 0, 6, 0,
+ 0, 0, 0, 2, 0, 2, 2, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 0, 0, 0,
+ 2, 0, 0, 7, 0, 0, 8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 10, 0, 11, 0,
+ 12, 0, 13, 0, 14, 15, 0, 0,
+ 16, 0, 17, 0, 0
};
-static const char _use_syllable_machine_to_state_actions[] = {
- 0, 0, 3, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0
+static const signed char _use_syllable_machine_to_state_actions[] = {
+ 0, 0, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
};
-static const char _use_syllable_machine_from_state_actions[] = {
- 0, 0, 4, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0
+static const signed char _use_syllable_machine_from_state_actions[] = {
+ 0, 0, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
};
-static const short _use_syllable_machine_eof_trans[] = {
- 1, 1, 0, 38, 38, 60, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 62, 38, 38, 38, 38, 38, 38, 38,
- 38, 60, 64, 66, 38, 68, 68, 69,
- 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 72, 69, 69, 69, 69,
- 69, 69, 72, 74, 74, 74
+static const signed char _use_syllable_machine_eof_trans[] = {
+ 1, 1, 4, 39, 39, 61, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39,
+ 63, 39, 39, 39, 39, 39, 39, 39,
+ 39, 61, 65, 67, 39, 69, 69, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 73, 70, 70, 70, 70,
+ 70, 70, 73, 75, 75, 75, 0
};
static const int use_syllable_machine_start = 2;
@@ -304,185 +352,376 @@ static const int use_syllable_machine_error = -1;
static const int use_syllable_machine_en_main = 2;
-#line 39 "hb-ot-shape-complex-use-machine.rl"
+#line 59 "hb-ot-shape-complex-use-machine.rl"
-#line 154 "hb-ot-shape-complex-use-machine.rl"
+#line 176 "hb-ot-shape-complex-use-machine.rl"
#define found_syllable(syllable_type) \
- HB_STMT_START { \
- if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
- for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
- info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \
- syllable_serial++; \
- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
- } HB_STMT_END
+HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
+ for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+
+template <typename Iter>
+struct machine_index_t :
+hb_iter_with_fallback_t<machine_index_t<Iter>,
+typename Iter::item_t>
+{
+ machine_index_t (const Iter& it) : it (it) {}
+ machine_index_t (const machine_index_t& o) : it (o.it) {}
+
+ static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+ static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+
+ typename Iter::item_t __item__ () const { return *it; }
+ typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
+ unsigned __len__ () const { return it.len (); }
+ void __next__ () { ++it; }
+ void __forward__ (unsigned n) { it += n; }
+ void __prev__ () { --it; }
+ void __rewind__ (unsigned n) { it -= n; }
+ void operator = (unsigned n)
+ { unsigned index = (*it).first; if (index < n) it += n - index; else if (index > n) it -= index - n; }
+ void operator = (const machine_index_t& o) { *this = (*o.it).first; }
+ bool operator == (const machine_index_t& o) const { return (*it).first == (*o.it).first; }
+ bool operator != (const machine_index_t& o) const { return !(*this == o); }
+
+ private:
+ Iter it;
+};
+struct
+{
+ template <typename Iter,
+ hb_requires (hb_is_iterable (Iter))>
+ machine_index_t<hb_iter_type<Iter>>
+ operator () (Iter&& it) const
+ { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
+}
+HB_FUNCOBJ (machine_index);
+
+
static bool
not_standard_default_ignorable (const hb_glyph_info_t &i)
-{ return !(i.use_category() == USE_O && _hb_glyph_info_is_default_ignorable (&i)); }
+{ return !(i.use_category() == USE(O) && _hb_glyph_info_is_default_ignorable (&i)); }
-static void
+static inline void
find_syllables_use (hb_buffer_t *buffer)
{
- hb_glyph_info_t *info = buffer->info;
- auto p =
- + hb_iter (info, buffer->len)
- | hb_enumerate
- | hb_filter ([] (const hb_glyph_info_t &i) { return not_standard_default_ignorable (i); },
- hb_second)
- | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
- {
- if (p.second.use_category() == USE_ZWNJ)
- for (unsigned i = p.first + 1; i < buffer->len; ++i)
- if (not_standard_default_ignorable (info[i]))
- return !_hb_glyph_info_is_unicode_mark (&info[i]);
- return true;
- })
- | hb_enumerate
- | machine_index
- ;
- auto pe = p + p.len ();
- auto eof = +pe;
- auto ts = +p;
- auto te = +p;
- unsigned int act HB_UNUSED;
- int cs;
-
-#line 355 "hb-ot-shape-complex-use-machine.hh"
+ hb_glyph_info_t *info = buffer->info;
+ auto p =
+ + hb_iter (info, buffer->len)
+ | hb_enumerate
+ | hb_filter ([] (const hb_glyph_info_t &i) { return not_standard_default_ignorable (i); },
+ hb_second)
+ | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
+ {
+ if (p.second.use_category() == USE(ZWNJ))
+ for (unsigned i = p.first + 1; i < buffer->len; ++i)
+ if (not_standard_default_ignorable (info[i]))
+ return !_hb_glyph_info_is_unicode_mark (&info[i]);
+ return true;
+ })
+ | hb_enumerate
+ | machine_index
+ ;
+ auto pe = p + p.len ();
+ auto eof = +pe;
+ auto ts = +p;
+ auto te = +p;
+ unsigned int act HB_UNUSED;
+ int cs;
+
+#line 443 "hb-ot-shape-complex-use-machine.hh"
{
- cs = use_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
+ cs = (int)use_syllable_machine_start;
+ ts = 0;
+ te = 0;
}
-
-#line 198 "hb-ot-shape-complex-use-machine.rl"
-
-
- unsigned int syllable_serial = 1;
-
-#line 368 "hb-ot-shape-complex-use-machine.hh"
+
+#line 260 "hb-ot-shape-complex-use-machine.rl"
+
+
+ unsigned int syllable_serial = 1;
+
+#line 455 "hb-ot-shape-complex-use-machine.hh"
{
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _use_syllable_machine_from_state_actions[cs] ) {
- case 4:
+ unsigned int _trans = 0;
+ const unsigned char * _keys;
+ const signed char * _inds;
+ int _ic;
+ _resume: {}
+ if ( p == pe && p != eof )
+ goto _out;
+ switch ( _use_syllable_machine_from_state_actions[cs] ) {
+ case 4: {
+ {
#line 1 "NONE"
- {ts = p;}
- break;
-#line 382 "hb-ot-shape-complex-use-machine.hh"
- }
-
- _keys = _use_syllable_machine_trans_keys + (cs<<1);
- _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
-
- _slen = _use_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) &&
- ( (*p).second.second.use_category()) <= _keys[1] ?
- ( (*p).second.second.use_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _use_syllable_machine_trans_targs[_trans];
-
- if ( _use_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _use_syllable_machine_trans_actions[_trans] ) {
- case 2:
+ {ts = p;}}
+
+#line 470 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ if ( p == eof ) {
+ if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
+ _trans = (unsigned int)_use_syllable_machine_eof_trans[cs] - 1;
+ }
+ }
+ else {
+ _keys = ( _use_syllable_machine_trans_keys + ((cs<<1)));
+ _inds = ( _use_syllable_machine_indicies + (_use_syllable_machine_index_offsets[cs]));
+
+ if ( ((*p).second.second.use_category()) <= 52 ) {
+ _ic = (int)_use_syllable_machine_char_class[(int)((*p).second.second.use_category()) - 0];
+ if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
+ _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
+ else
+ _trans = (unsigned int)_use_syllable_machine_index_defaults[cs];
+ }
+ else {
+ _trans = (unsigned int)_use_syllable_machine_index_defaults[cs];
+ }
+
+ }
+ cs = (int)_use_syllable_machine_cond_targs[_trans];
+
+ if ( _use_syllable_machine_cond_actions[_trans] != 0 ) {
+
+ switch ( _use_syllable_machine_cond_actions[_trans] ) {
+ case 2: {
+ {
#line 1 "NONE"
- {te = p+1;}
- break;
- case 5:
-#line 141 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (independent_cluster); }}
- break;
- case 9:
-#line 144 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (standard_cluster); }}
- break;
- case 7:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (broken_cluster); }}
- break;
- case 6:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (non_cluster); }}
- break;
- case 10:
-#line 142 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (virama_terminated_cluster); }}
- break;
- case 11:
-#line 143 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (sakot_terminated_cluster); }}
- break;
- case 8:
-#line 144 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (standard_cluster); }}
- break;
- case 13:
-#line 145 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
- break;
- case 12:
-#line 146 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (numeral_cluster); }}
- break;
- case 14:
-#line 147 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (symbol_cluster); }}
- break;
- case 17:
-#line 148 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (hieroglyph_cluster); }}
- break;
- case 15:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (broken_cluster); }}
- break;
- case 16:
-#line 150 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (non_cluster); }}
- break;
- case 1:
-#line 149 "hb-ot-shape-complex-use-machine.rl"
- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
- break;
-#line 460 "hb-ot-shape-complex-use-machine.hh"
- }
-
-_again:
- switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 3:
+ {te = p+1;}}
+
+#line 508 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 5: {
+ {
+#line 163 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 163 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_independent_cluster); }
+ }}
+
+#line 521 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 9: {
+ {
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_standard_cluster); }
+ }}
+
+#line 534 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 7: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 547 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 6: {
+ {
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_non_cluster); }
+ }}
+
+#line 560 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 10: {
+ {
+#line 164 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 164 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_virama_terminated_cluster); }
+ }}
+
+#line 573 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 11: {
+ {
+#line 165 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 165 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_sakot_terminated_cluster); }
+ }}
+
+#line 586 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 8: {
+ {
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 166 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_standard_cluster); }
+ }}
+
+#line 599 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 13: {
+ {
+#line 167 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 167 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_number_joiner_terminated_cluster); }
+ }}
+
+#line 612 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 12: {
+ {
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 168 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_numeral_cluster); }
+ }}
+
+#line 625 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 14: {
+ {
+#line 169 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 169 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_symbol_cluster); }
+ }}
+
+#line 638 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 17: {
+ {
+#line 170 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 170 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_hieroglyph_cluster); }
+ }}
+
+#line 651 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 15: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 664 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 16: {
+ {
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p = p - 1;{
+#line 172 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_non_cluster); }
+ }}
+
+#line 677 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ case 1: {
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ {p = ((te))-1;
+ {
+#line 171 "hb-ot-shape-complex-use-machine.rl"
+ found_syllable (use_broken_cluster); }
+ }}
+
+#line 691 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ }
+
+ if ( p == eof ) {
+ if ( cs >= 2 )
+ goto _out;
+ }
+ else {
+ switch ( _use_syllable_machine_to_state_actions[cs] ) {
+ case 3: {
+ {
#line 1 "NONE"
- {ts = 0;}
- break;
-#line 469 "hb-ot-shape-complex-use-machine.hh"
+ {ts = 0;}}
+
+#line 711 "hb-ot-shape-complex-use-machine.hh"
+
+
+ break;
+ }
+ }
+
+ p += 1;
+ goto _resume;
+ }
+ _out: {}
}
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _use_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 203 "hb-ot-shape-complex-use-machine.rl"
-
+
+#line 265 "hb-ot-shape-complex-use-machine.rl"
+
}
#undef found_syllable
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
index df3652b18a..a35894ce81 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh
@@ -31,56 +31,57 @@
* UnicodeData.txt does not have a header.
*/
-#include "hb.hh"
+#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH
-#ifndef HB_NO_OT_SHAPE
+#include "hb.hh"
-#include "hb-ot-shape-complex-use.hh"
+#include "hb-ot-shape-complex-use-machine.hh"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
-#define B USE_B /* BASE */
-#define CS USE_CS /* CONS_WITH_STACKER */
-#define G USE_G /* HIEROGLYPH */
-#define GB USE_GB /* BASE_OTHER */
-#define H USE_H /* HALANT */
-#define HN USE_HN /* HALANT_NUM */
-#define HVM USE_HVM /* HALANT_OR_VOWEL_MODIFIER */
-#define J USE_J /* HIEROGLYPH_JOINER */
-#define N USE_N /* BASE_NUM */
-#define O USE_O /* OTHER */
-#define R USE_R /* REPHA */
-#define S USE_S /* SYM */
-#define SB USE_SB /* HIEROGLYPH_SEGMENT_BEGIN */
-#define SE USE_SE /* HIEROGLYPH_SEGMENT_END */
-#define SUB USE_SUB /* CONS_SUB */
-#define Sk USE_Sk /* SAKOT */
-#define ZWNJ USE_ZWNJ /* ZWNJ */
-#define CMAbv USE_CMAbv
-#define CMBlw USE_CMBlw
-#define FAbv USE_FAbv
-#define FBlw USE_FBlw
-#define FPst USE_FPst
-#define FMAbv USE_FMAbv
-#define FMBlw USE_FMBlw
-#define FMPst USE_FMPst
-#define MAbv USE_MAbv
-#define MBlw USE_MBlw
-#define MPst USE_MPst
-#define MPre USE_MPre
-#define SMAbv USE_SMAbv
-#define SMBlw USE_SMBlw
-#define VAbv USE_VAbv
-#define VBlw USE_VBlw
-#define VPst USE_VPst
-#define VPre USE_VPre
-#define VMAbv USE_VMAbv
-#define VMBlw USE_VMBlw
-#define VMPst USE_VMPst
-#define VMPre USE_VMPre
+#define B USE(B) /* BASE */
+#define CS USE(CS) /* CONS_WITH_STACKER */
+#define G USE(G) /* HIEROGLYPH */
+#define GB USE(GB) /* BASE_OTHER */
+#define H USE(H) /* HALANT */
+#define HN USE(HN) /* HALANT_NUM */
+#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */
+#define J USE(J) /* HIEROGLYPH_JOINER */
+#define N USE(N) /* BASE_NUM */
+#define O USE(O) /* OTHER */
+#define R USE(R) /* REPHA */
+#define S USE(S) /* SYM */
+#define SB USE(SB) /* HIEROGLYPH_SEGMENT_BEGIN */
+#define SE USE(SE) /* HIEROGLYPH_SEGMENT_END */
+#define SUB USE(SUB) /* CONS_SUB */
+#define Sk USE(Sk) /* SAKOT */
+#define ZWNJ USE(ZWNJ) /* ZWNJ */
+#define CMAbv USE(CMAbv)
+#define CMBlw USE(CMBlw)
+#define FAbv USE(FAbv)
+#define FBlw USE(FBlw)
+#define FPst USE(FPst)
+#define FMAbv USE(FMAbv)
+#define FMBlw USE(FMBlw)
+#define FMPst USE(FMPst)
+#define MAbv USE(MAbv)
+#define MBlw USE(MBlw)
+#define MPst USE(MPst)
+#define MPre USE(MPre)
+#define SMAbv USE(SMAbv)
+#define SMBlw USE(SMBlw)
+#define VAbv USE(VAbv)
+#define VBlw USE(VBlw)
+#define VPst USE(VPst)
+#define VPre USE(VPre)
+#define VMAbv USE(VMAbv)
+#define VMBlw USE(VMBlw)
+#define VMPst USE(VMPst)
+#define VMPre USE(VMPre)
#pragma GCC diagnostic pop
-static const USE_TABLE_ELEMENT_TYPE use_table[] = {
+static const uint8_t use_table[] = {
#define use_offset_0x0028u 0
@@ -767,7 +768,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11710 */ B, B, B, B, B, B, B, B, B, B, B, O, O, MBlw, MPre, MAbv,
- /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VMAbv, O, O, O, O,
+ /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
/* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
#define use_offset_0x11800u 5848
@@ -1066,7 +1067,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
}; /* Table items: 8824; occupancy: 79% */
-USE_TABLE_ELEMENT_TYPE
+static inline uint8_t
hb_use_get_category (hb_codepoint_t u)
{
switch (u >> 12)
@@ -1154,7 +1155,7 @@ hb_use_get_category (hb_codepoint_t u)
default:
break;
}
- return USE_O;
+ return USE(O);
}
#undef B
@@ -1198,5 +1199,5 @@ hb_use_get_category (hb_codepoint_t u)
#undef VMPre
-#endif
+#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
index 8ac569d8bf..0d0b7e771e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc
@@ -30,14 +30,12 @@
#ifndef HB_NO_OT_SHAPE
-#include "hb-ot-shape-complex-use.hh"
+#include "hb-ot-shape-complex-use-machine.hh"
+#include "hb-ot-shape-complex-use-table.hh"
#include "hb-ot-shape-complex-arabic.hh"
#include "hb-ot-shape-complex-arabic-joining-list.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
-/* buffer var allocations */
-#define use_category() complex_var_u8_1()
-
/*
* Universal Shaping Engine.
@@ -69,11 +67,11 @@ use_topographical_features[] =
};
/* Same order as use_topographical_features. */
enum joining_form_t {
- USE_ISOL,
- USE_INIT,
- USE_MEDI,
- USE_FINA,
- _USE_NONE
+ JOINING_FORM_ISOL,
+ JOINING_FORM_INIT,
+ JOINING_FORM_MEDI,
+ JOINING_FORM_FINA,
+ _JOINING_FORM_NONE
};
static const hb_tag_t
use_other_features[] =
@@ -186,22 +184,6 @@ data_destroy_use (void *data)
free (data);
}
-enum use_syllable_type_t {
- use_independent_cluster,
- use_virama_terminated_cluster,
- use_sakot_terminated_cluster,
- use_standard_cluster,
- use_number_joiner_terminated_cluster,
- use_numeral_cluster,
- use_symbol_cluster,
- use_hieroglyph_cluster,
- use_broken_cluster,
- use_non_cluster,
-};
-
-#include "hb-ot-shape-complex-use-machine.hh"
-
-
static void
setup_masks_use (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@@ -239,7 +221,7 @@ setup_rphf_mask (const hb_ot_shape_plan_t *plan,
foreach_syllable (buffer, start, end)
{
- unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
+ unsigned int limit = info[start].use_category() == USE(R) ? 1 : hb_min (3u, end - start);
for (unsigned int i = start; i < start + limit; i++)
info[i].mask |= mask;
}
@@ -253,7 +235,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
if (use_plan->arabic_plan)
return;
- static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
+ static_assert ((JOINING_FORM_INIT < 4 && JOINING_FORM_ISOL < 4 && JOINING_FORM_MEDI < 4 && JOINING_FORM_FINA < 4), "");
hb_mask_t masks[4], all_masks = 0;
for (unsigned int i = 0; i < 4; i++)
{
@@ -267,7 +249,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
hb_mask_t other_masks = ~all_masks;
unsigned int last_start = 0;
- joining_form_t last_form = _USE_NONE;
+ joining_form_t last_form = _JOINING_FORM_NONE;
hb_glyph_info_t *info = buffer->info;
foreach_syllable (buffer, start, end)
{
@@ -279,7 +261,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
case use_hieroglyph_cluster:
case use_non_cluster:
/* These don't join. Nothing to do. */
- last_form = _USE_NONE;
+ last_form = _JOINING_FORM_NONE;
break;
case use_virama_terminated_cluster:
@@ -289,18 +271,18 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
case use_numeral_cluster:
case use_broken_cluster:
- bool join = last_form == USE_FINA || last_form == USE_ISOL;
+ bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
if (join)
{
/* Fixup previous syllable's form. */
- last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
+ last_form = last_form == JOINING_FORM_FINA ? JOINING_FORM_MEDI : JOINING_FORM_INIT;
for (unsigned int i = last_start; i < start; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
}
/* Form for this syllable. */
- last_form = join ? USE_FINA : USE_ISOL;
+ last_form = join ? JOINING_FORM_FINA : JOINING_FORM_ISOL;
for (unsigned int i = start; i < end; i++)
info[i].mask = (info[i].mask & other_masks) | masks[last_form];
@@ -336,11 +318,11 @@ record_rphf_use (const hb_ot_shape_plan_t *plan,
foreach_syllable (buffer, start, end)
{
- /* Mark a substituted repha as USE_R. */
+ /* Mark a substituted repha as USE(R). */
for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
if (_hb_glyph_info_substituted (&info[i]))
{
- info[i].use_category() = USE_R;
+ info[i].use_category() = USE(R);
break;
}
}
@@ -359,7 +341,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_substituted (&info[i]))
{
- info[i].use_category() = USE_VPre;
+ info[i].use_category() = USE(VPre);
break;
}
}
@@ -368,7 +350,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
static inline bool
is_halant_use (const hb_glyph_info_t &info)
{
- return (info.use_category() == USE_H || info.use_category() == USE_HVM) &&
+ return (info.use_category() == USE(H) || info.use_category() == USE(HVM)) &&
!_hb_glyph_info_ligated (&info);
}
@@ -387,24 +369,24 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
hb_glyph_info_t *info = buffer->info;
-#define POST_BASE_FLAGS64 (FLAG64 (USE_FAbv) | \
- FLAG64 (USE_FBlw) | \
- FLAG64 (USE_FPst) | \
- FLAG64 (USE_MAbv) | \
- FLAG64 (USE_MBlw) | \
- FLAG64 (USE_MPst) | \
- FLAG64 (USE_MPre) | \
- FLAG64 (USE_VAbv) | \
- FLAG64 (USE_VBlw) | \
- FLAG64 (USE_VPst) | \
- FLAG64 (USE_VPre) | \
- FLAG64 (USE_VMAbv) | \
- FLAG64 (USE_VMBlw) | \
- FLAG64 (USE_VMPst) | \
- FLAG64 (USE_VMPre))
+#define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
+ FLAG64 (USE(FBlw)) | \
+ FLAG64 (USE(FPst)) | \
+ FLAG64 (USE(MAbv)) | \
+ FLAG64 (USE(MBlw)) | \
+ FLAG64 (USE(MPst)) | \
+ FLAG64 (USE(MPre)) | \
+ FLAG64 (USE(VAbv)) | \
+ FLAG64 (USE(VBlw)) | \
+ FLAG64 (USE(VPst)) | \
+ FLAG64 (USE(VPre)) | \
+ FLAG64 (USE(VMAbv)) | \
+ FLAG64 (USE(VMBlw)) | \
+ FLAG64 (USE(VMPst)) | \
+ FLAG64 (USE(VMPre)))
/* Move things forward. */
- if (info[start].use_category() == USE_R && end - start > 1)
+ if (info[start].use_category() == USE(R) && end - start > 1)
{
/* Got a repha. Reorder it towards the end, but before the first post-base
* glyph. */
@@ -441,7 +423,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
* shift things in between forward. */
j = i + 1;
}
- else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+ else if (((flag) & (FLAG (USE(VPre)) | FLAG (USE(VMPre)))) &&
/* Only move the first component of a MultipleSubst. */
0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
j < i)
@@ -454,76 +436,22 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
}
}
-static inline void
-insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
- hb_font_t *font,
- hb_buffer_t *buffer)
-{
- if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
- return;
-
- /* Note: This loop is extra overhead, but should not be measurable.
- * TODO Use a buffer scratch flag to remove the loop. */
- bool has_broken_syllables = false;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if ((info[i].syllable() & 0x0F) == use_broken_cluster)
- {
- has_broken_syllables = true;
- break;
- }
- if (likely (!has_broken_syllables))
- return;
-
- hb_glyph_info_t dottedcircle = {0};
- if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
- return;
- dottedcircle.use_category() = hb_use_get_category (0x25CC);
-
- buffer->clear_output ();
-
- buffer->idx = 0;
- unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len && buffer->successful)
- {
- unsigned int syllable = buffer->cur().syllable();
- use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
- if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
- {
- last_syllable = syllable;
-
- hb_glyph_info_t ginfo = dottedcircle;
- ginfo.cluster = buffer->cur().cluster;
- ginfo.mask = buffer->cur().mask;
- ginfo.syllable() = buffer->cur().syllable();
-
- /* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len && buffer->successful &&
- last_syllable == buffer->cur().syllable() &&
- buffer->cur().use_category() == USE_R)
- buffer->next_glyph ();
-
- buffer->output_info (ginfo);
- }
- else
- buffer->next_glyph ();
- }
- buffer->swap_buffers ();
-}
-
static void
reorder_use (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- if (buffer->message (font, "start reordering USE")) {
- insert_dotted_circles_use (plan, font, buffer);
+ if (buffer->message (font, "start reordering USE"))
+ {
+ hb_syllabic_insert_dotted_circles (font, buffer,
+ use_broken_cluster,
+ USE(B),
+ USE(R));
- foreach_syllable (buffer, start, end)
- reorder_syllable_use (buffer, start, end);
+ foreach_syllable (buffer, start, end)
+ reorder_syllable_use (buffer, start, end);
- (void) buffer->message (font, "end reordering USE");
+ (void) buffer->message (font, "end reordering USE");
}
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh
deleted file mode 100644
index 788fb6b6ac..0000000000
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.hh
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright © 2015 Mozilla Foundation.
- * Copyright © 2015 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Mozilla Author(s): Jonathan Kew
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_USE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_HH
-
-#include "hb.hh"
-
-
-#include "hb-ot-shape-complex.hh"
-
-
-#define USE_TABLE_ELEMENT_TYPE uint8_t
-
-/* Cateories used in the Universal Shaping Engine spec:
- * https://docs.microsoft.com/en-us/typography/script-development/use
- */
-/* Note: This enum is duplicated in the -machine.rl source file.
- * Not sure how to avoid duplication. */
-enum use_category_t {
- USE_O = 0, /* OTHER */
-
- USE_B = 1, /* BASE */
- USE_N = 4, /* BASE_NUM */
- USE_GB = 5, /* BASE_OTHER */
- USE_SUB = 11, /* CONS_SUB */
- USE_H = 12, /* HALANT */
-
- USE_HN = 13, /* HALANT_NUM */
- USE_ZWNJ = 14, /* Zero width non-joiner */
- USE_R = 18, /* REPHA */
- USE_S = 19, /* SYM */
- USE_CS = 43, /* CONS_WITH_STACKER */
-
- /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
- USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */
-
- USE_Sk = 48, /* SAKOT */
- USE_G = 49, /* HIEROGLYPH */
- USE_J = 50, /* HIEROGLYPH_JOINER */
- USE_SB = 51, /* HIEROGLYPH_SEGMENT_BEGIN */
- USE_SE = 52, /* HIEROGLYPH_SEGMENT_END */
-
- USE_FAbv = 24, /* CONS_FINAL_ABOVE */
- USE_FBlw = 25, /* CONS_FINAL_BELOW */
- USE_FPst = 26, /* CONS_FINAL_POST */
- USE_MAbv = 27, /* CONS_MED_ABOVE */
- USE_MBlw = 28, /* CONS_MED_BELOW */
- USE_MPst = 29, /* CONS_MED_POST */
- USE_MPre = 30, /* CONS_MED_PRE */
- USE_CMAbv = 31, /* CONS_MOD_ABOVE */
- USE_CMBlw = 32, /* CONS_MOD_BELOW */
- USE_VAbv = 33, /* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
- USE_VBlw = 34, /* VOWEL_BELOW / VOWEL_BELOW_POST */
- USE_VPst = 35, /* VOWEL_POST UIPC = Right */
- USE_VPre = 22, /* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
- USE_VMAbv = 37, /* VOWEL_MOD_ABOVE */
- USE_VMBlw = 38, /* VOWEL_MOD_BELOW */
- USE_VMPst = 39, /* VOWEL_MOD_POST */
- USE_VMPre = 23, /* VOWEL_MOD_PRE */
- USE_SMAbv = 41, /* SYM_MOD_ABOVE */
- USE_SMBlw = 42, /* SYM_MOD_BELOW */
- USE_FMAbv = 45, /* CONS_FINAL_MOD UIPC = Top */
- USE_FMBlw = 46, /* CONS_FINAL_MOD UIPC = Bottom */
- USE_FMPst = 47, /* CONS_FINAL_MOD UIPC = Not_Applicable */
-};
-
-HB_INTERNAL USE_TABLE_ELEMENT_TYPE
-hb_use_get_category (hb_codepoint_t u);
-
-#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
index 1af546e4fa..1037626998 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -23,15 +23,15 @@
static void
_output_dotted_circle (hb_buffer_t *buffer)
{
- hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
- _hb_glyph_info_reset_continuation (&dottedcircle);
+ (void) buffer->output_glyph (0x25CCu);
+ _hb_glyph_info_reset_continuation (&buffer->prev());
}
static void
_output_with_dotted_circle (hb_buffer_t *buffer)
{
_output_dotted_circle (buffer);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
void
@@ -51,7 +51,6 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
*
* https://github.com/harfbuzz/harfbuzz/issues/1019
*/
- bool processed = false;
buffer->clear_output ();
unsigned int count = buffer->len;
switch ((unsigned) buffer->props.script)
@@ -97,15 +96,14 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx + 2 < count &&
0x0907u == buffer->cur (2).codepoint)
{
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
matched = true;
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_BENGALI:
@@ -124,10 +122,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x09E2u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_GURMUKHI:
@@ -161,10 +158,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_GUJARATI:
@@ -186,10 +182,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0ABEu == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_ORIYA:
@@ -205,10 +200,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0B57u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TAMIL:
@@ -220,10 +214,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
{
matched = true;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TELUGU:
@@ -244,10 +237,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0C55u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_KANNADA:
@@ -263,10 +255,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x0CCCu == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_MALAYALAM:
@@ -290,10 +281,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_SINHALA:
@@ -326,10 +316,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_BRAHMI:
@@ -348,10 +337,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x11042u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_KHUDAWADI:
@@ -370,10 +358,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TIRHUTA:
@@ -397,10 +384,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_MODI:
@@ -418,10 +404,9 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
case HB_SCRIPT_TAKRI:
@@ -442,21 +427,15 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
matched = 0x116B2u == buffer->cur (1).codepoint;
break;
}
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
- processed = true;
break;
default:
break;
}
- if (processed)
- {
- if (buffer->idx < count)
- buffer->next_glyph ();
- buffer->swap_buffers ();
- }
+ buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
index a1a7a6a47b..19e24b9f30 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh
@@ -35,8 +35,8 @@
/* buffer var allocations, used by complex shapers */
-#define complex_var_u8_0() var2.u8[2]
-#define complex_var_u8_1() var2.u8[3]
+#define complex_var_u8_category() var2.u8[2]
+#define complex_var_u8_auxiliary() var2.u8[3]
#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32
@@ -186,27 +186,8 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_ARABIC:
/* Unicode-3.0 additions */
- case HB_SCRIPT_MONGOLIAN:
case HB_SCRIPT_SYRIAC:
- /* Unicode-5.0 additions */
- case HB_SCRIPT_NKO:
- case HB_SCRIPT_PHAGS_PA:
-
- /* Unicode-6.0 additions */
- case HB_SCRIPT_MANDAIC:
-
- /* Unicode-7.0 additions */
- case HB_SCRIPT_MANICHAEAN:
- case HB_SCRIPT_PSALTER_PAHLAVI:
-
- /* Unicode-9.0 additions */
- case HB_SCRIPT_ADLAM:
-
- /* Unicode-11.0 additions */
- case HB_SCRIPT_HANIFI_ROHINGYA:
- case HB_SCRIPT_SOGDIAN:
-
/* For Arabic script, use the Arabic shaper even if no OT script tag was found.
* This is because we do fallback shaping for Arabic script (and not others).
* But note that Arabic shaping is applicable only to horizontal layout; for
@@ -284,8 +265,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_myanmar;
- /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
+#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
case HB_SCRIPT_MYANMAR_ZAWGYI:
+ /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
return &_hb_ot_complex_shaper_myanmar_zawgyi;
@@ -294,7 +276,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_TIBETAN:
/* Unicode-3.0 additions */
- //case HB_SCRIPT_MONGOLIAN:
+ case HB_SCRIPT_MONGOLIAN:
//case HB_SCRIPT_SINHALA:
/* Unicode-3.2 additions */
@@ -315,8 +297,8 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-5.0 additions */
case HB_SCRIPT_BALINESE:
- //case HB_SCRIPT_NKO:
- //case HB_SCRIPT_PHAGS_PA:
+ case HB_SCRIPT_NKO:
+ case HB_SCRIPT_PHAGS_PA:
/* Unicode-5.1 additions */
case HB_SCRIPT_CHAM:
@@ -337,7 +319,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-6.0 additions */
case HB_SCRIPT_BATAK:
case HB_SCRIPT_BRAHMI:
- //case HB_SCRIPT_MANDAIC:
+ case HB_SCRIPT_MANDAIC:
/* Unicode-6.1 additions */
case HB_SCRIPT_CHAKMA:
@@ -351,10 +333,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_KHOJKI:
case HB_SCRIPT_KHUDAWADI:
case HB_SCRIPT_MAHAJANI:
- //case HB_SCRIPT_MANICHAEAN:
+ case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MODI:
case HB_SCRIPT_PAHAWH_HMONG:
- //case HB_SCRIPT_PSALTER_PAHLAVI:
+ case HB_SCRIPT_PSALTER_PAHLAVI:
case HB_SCRIPT_SIDDHAM:
case HB_SCRIPT_TIRHUTA:
@@ -363,7 +345,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_MULTANI:
/* Unicode-9.0 additions */
- //case HB_SCRIPT_ADLAM:
+ case HB_SCRIPT_ADLAM:
case HB_SCRIPT_BHAIKSUKI:
case HB_SCRIPT_MARCHEN:
case HB_SCRIPT_NEWA:
@@ -376,11 +358,11 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-11.0 additions */
case HB_SCRIPT_DOGRA:
case HB_SCRIPT_GUNJALA_GONDI:
- //case HB_SCRIPT_HANIFI_ROHINGYA:
+ case HB_SCRIPT_HANIFI_ROHINGYA:
case HB_SCRIPT_MAKASAR:
case HB_SCRIPT_MEDEFAIDRIN:
case HB_SCRIPT_OLD_SOGDIAN:
- //case HB_SCRIPT_SOGDIAN:
+ case HB_SCRIPT_SOGDIAN:
/* Unicode-12.0 additions */
case HB_SCRIPT_ELYMAIC:
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
index 3eabae1b45..778b5b8bd8 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -101,8 +101,9 @@ set_glyph (hb_glyph_info_t &info, hb_font_t *font)
static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
+ /* This is very confusing indeed. */
buffer->cur().glyph_index() = glyph;
- buffer->output_glyph (unichar); /* This is very confusing indeed. */
+ (void) buffer->output_glyph (unichar);
_hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
}
@@ -110,7 +111,7 @@ static inline void
next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
static inline void
@@ -229,30 +230,35 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
{
hb_codepoint_t unicode = buffer->cur().codepoint;
- buffer->replace_glyphs (2, 1, &unicode);
+ (void) buffer->replace_glyphs (2, 1, &unicode);
}
else
{
/* Just pass on the two characters separately, let GSUB do its magic. */
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
/* Skip any further variation selectors. */
- while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+ while (buffer->idx < end &&
+ buffer->successful &&
+ unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
{
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
- } else {
+ }
+ else
+ {
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
- if (likely (buffer->idx < end)) {
+ if (likely (buffer->idx < end))
+ {
set_glyph (buffer->cur(), font);
- buffer->next_glyph ();
+ (void) buffer->next_glyph ();
}
}
@@ -348,7 +354,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
sizeof (buffer->info[0]),
&buffer->cur().glyph_index(),
sizeof (buffer->info[0]));
- buffer->next_glyphs (done);
+ if (unlikely (!buffer->next_glyphs (done))) break;
}
while (buffer->idx < end && buffer->successful)
decompose_current_character (&c, might_short_circuit);
@@ -419,6 +425,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
/* Third round, recompose */
if (!all_simple &&
+ buffer->successful &&
(mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT))
{
@@ -428,8 +435,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
count = buffer->len;
unsigned int starter = 0;
- buffer->next_glyph ();
- while (buffer->idx < count && buffer->successful)
+ (void) buffer->next_glyph ();
+ while (buffer->idx < count /* No need for: && buffer->successful */)
{
hb_codepoint_t composed, glyph;
if (/* We don't try to compose a non-mark character with it's preceding starter.
@@ -451,9 +458,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
font->get_nominal_glyph (composed, &glyph))
{
/* Composes. */
- buffer->next_glyph (); /* Copy to out-buffer. */
- if (unlikely (!buffer->successful))
- return;
+ if (unlikely (!buffer->next_glyph ())) break; /* Copy to out-buffer. */
buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */
/* Modify starter and carry on. */
@@ -466,7 +471,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
}
/* Blocked, or doesn't compose. */
- buffer->next_glyph ();
+ if (unlikely (!buffer->next_glyph ())) break;
if (info_cc (buffer->prev()) == 0)
starter = buffer->out_len - 1;
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 7d90558458..86ab0b4268 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -534,9 +534,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
hb_glyph_info_t info = dottedcircle;
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
- buffer->output_info (info);
- while (buffer->idx < buffer->len && buffer->successful)
- buffer->next_glyph ();
+ (void) buffer->output_info (info);
buffer->swap_buffers ();
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.h b/thirdparty/harfbuzz/src/hb-ot-shape.h
index 7b1bcc0637..afdff72833 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.h
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
index f1c391cf0e..87830b5462 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2020-11-17 08:21 AM" />
- * File-Date: 2020-09-29
+ * <meta name="updated_at" content="2021-02-12 04:08 PM" />
+ * File-Date: 2021-03-05
*/
#ifndef HB_OT_TAG_TABLE_HH
@@ -169,6 +169,7 @@ static const LangTag ot_languages[] = {
{"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */
{"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */
{"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */
+ {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */
{"bli", HB_TAG_NONE }, /* Bolia != Baluchi */
{"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */
{"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */
@@ -358,6 +359,7 @@ static const LangTag ot_languages[] = {
{"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */
{"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
+/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */
{"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */
/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */
@@ -834,6 +836,7 @@ static const LangTag ot_languages[] = {
{"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */
{"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */
{"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */
+ {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */
{"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
{"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */
@@ -990,7 +993,7 @@ static const LangTag ot_languages[] = {
/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
{"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */
- {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni -> Sutu */
+ {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */
{"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */
{"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */
{"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */
@@ -1520,6 +1523,8 @@ static const LangTag ot_languages[] = {
{"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */
{"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */
{"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */
+ {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */
+ {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */
{"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */
/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */
{"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */
@@ -2808,6 +2813,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("hnd", -1); /* Southern Hindko */
case HB_TAG('H','Y','E',' '): /* Armenian */
return hb_language_from_string ("hyw", -1); /* Western Armenian */
+ case HB_TAG('I','B','A',' '): /* Iban */
+ return hb_language_from_string ("iba", -1); /* Iban */
case HB_TAG('I','J','O',' '): /* Ijo */
return hb_language_from_string ("ijo", -1); /* Ijo [family] */
case HB_TAG('I','N','U',' '): /* Inuktitut */
@@ -2892,6 +2899,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */
return hb_language_from_string ("sr", -1); /* Serbian */
+ case HB_TAG('S','X','T',' '): /* Sutu */
+ return hb_language_from_string ("xnj", -1); /* Ngoni (Tanzania) */
case HB_TAG('S','Y','R',' '): /* Syriac */
return hb_language_from_string ("syr", -1); /* Syriac [macrolanguage] */
case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc
index 19bd3639d3..fc145a41f7 100644
--- a/thirdparty/harfbuzz/src/hb-ot-tag.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc
@@ -164,6 +164,15 @@ hb_ot_all_tags_from_script (hb_script_t script,
*count = i;
}
+/**
+ * hb_ot_tag_to_script:
+ * @tag: a script tag
+ *
+ * Converts a script tag to an #hb_script_t.
+ *
+ * Return value: The #hb_script_t corresponding to @tag.
+ *
+ **/
hb_script_t
hb_ot_tag_to_script (hb_tag_t tag)
{
@@ -351,13 +360,13 @@ parse_private_use_subtag (const char *private_use_subtag,
* hb_ot_tags_from_script_and_language:
* @script: an #hb_script_t to convert.
* @language: an #hb_language_t to convert.
- * @script_count: (allow-none): maximum number of script tags to retrieve (IN)
+ * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
* and actual number of script tags retrieved (OUT)
- * @script_tags: (out) (allow-none): array of size at least @script_count to store the
+ * @script_tags: (out) (optional): array of size at least @script_count to store the
* script tag results
- * @language_count: (allow-none): maximum number of language tags to retrieve
+ * @language_count: (inout) (optional): maximum number of language tags to retrieve
* (IN) and actual number of language tags retrieved (OUT)
- * @language_tags: (out) (allow-none): array of size at least @language_count to store
+ * @language_tags: (out) (optional): array of size at least @language_count to store
* the language tag results
*
* Converts an #hb_script_t and an #hb_language_t to script and language tags.
@@ -424,10 +433,12 @@ hb_ot_tags_from_script_and_language (hb_script_t script,
/**
* hb_ot_tag_to_language:
+ * @tag: an language tag
*
+ * Converts a language tag to an #hb_language_t.
*
- *
- * Return value: (transfer none):
+ * Return value: (transfer none) (nullable):
+ * The #hb_language_t corresponding to @tag.
*
* Since: 0.9.2
**/
@@ -478,9 +489,9 @@ hb_ot_tag_to_language (hb_tag_t tag)
* hb_ot_tags_to_script_and_language:
* @script_tag: a script tag
* @language_tag: a language tag
- * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT).
- * @language: (allow-none): the #hb_language_t corresponding to @script_tag and
- * @language_tag (OUT).
+ * @script: (out) (optional): the #hb_script_t corresponding to @script_tag.
+ * @language: (out) (optional): the #hb_language_t corresponding to @script_tag and
+ * @language_tag.
*
* Converts a script tag and a language tag to an #hb_script_t and an
* #hb_language_t.
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
index 4d4e6dcae4..7e4eaaad95 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh
@@ -652,8 +652,8 @@ no_more_gaps:
/* apply specified / inferred deltas to points */
for (unsigned int i = 0; i < points.length; i++)
{
- points[i].x += roundf (deltas[i].x);
- points[i].y += roundf (deltas[i].y);
+ points[i].x += deltas[i].x;
+ points[i].y += deltas[i].y;
}
} while (iterator.move_to_next ());
diff --git a/thirdparty/harfbuzz/src/hb-ot-var.cc b/thirdparty/harfbuzz/src/hb-ot-var.cc
index 1fe57383c0..6b42b45cd9 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-var.cc
@@ -56,7 +56,7 @@
*
* Tests whether a face includes any OpenType variation data in the `fvar` table.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 1.4.2
**/
@@ -87,7 +87,7 @@ hb_ot_var_get_axis_count (hb_face_t *face)
* hb_ot_var_get_axes:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first lookup to retrieve
- * @axes_count: (inout) (allow-none): Input = the maximum number of variation axes to return;
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
* Output = the actual number of variation axes returned (may be zero)
* @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
*
@@ -133,7 +133,7 @@ hb_ot_var_find_axis (hb_face_t *face,
* hb_ot_var_get_axis_infos:
* @face: #hb_face_t to work upon
* @start_offset: offset of the first lookup to retrieve
- * @axes_count: (inout) (allow-none): Input = the maximum number of variation axes to return;
+ * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return;
* Output = the actual number of variation axes returned (may be zero)
* @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found
*
@@ -162,7 +162,7 @@ hb_ot_var_get_axis_infos (hb_face_t *face,
* Fetches the variation-axis information corresponding to the specified axis tag
* in the specified face.
*
- * Return value: true if data found, false otherwise
+ * Return value: %true if data found, %false otherwise
*
* Since: 2.2.0
**/
@@ -237,7 +237,7 @@ hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face,
* hb_ot_var_named_instance_get_design_coords:
* @face: The #hb_face_t to work on
* @instance_index: The index of the named instance to query
- * @coords_length: (inout) (allow-none): Input = the maximum number of coordinates to return;
+ * @coords_length: (inout) (optional): Input = the maximum number of coordinates to return;
* Output = the actual number of coordinates returned (may be zero)
* @coords: (out) (array length=coords_length): The array of coordinates found for the query
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-var.h b/thirdparty/harfbuzz/src/hb-ot-var.h
index ef2ca0a716..ce201d3b4f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var.h
+++ b/thirdparty/harfbuzz/src/hb-ot-var.h
@@ -24,7 +24,7 @@
* Red Hat Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_H_IN
+#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb-ot.h> instead."
#endif
@@ -36,34 +36,38 @@
HB_BEGIN_DECLS
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_ITALIC: Registered tag for the roman/italic axis
+ * HB_OT_TAG_VAR_AXIS_ITALIC:
+ *
+ * Registered tag for the roman/italic axis.
*/
#define HB_OT_TAG_VAR_AXIS_ITALIC HB_TAG('i','t','a','l')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE: Registered tag for the optical-size axis
+ * HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE:
*
+ * Registered tag for the optical-size axis.
* <note>Note: The optical-size axis supersedes the OpenType `size` feature.</note>
*/
#define HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE HB_TAG('o','p','s','z')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_SLANT: Registered tag for the slant axis
+ * HB_OT_TAG_VAR_AXIS_SLANT:
+ *
+ * Registered tag for the slant axis
*/
#define HB_OT_TAG_VAR_AXIS_SLANT HB_TAG('s','l','n','t')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_WIDTH: Registered tag for the width axis
+ * HB_OT_TAG_VAR_AXIS_WIDTH:
+ *
+ * Registered tag for the width axis.
*/
#define HB_OT_TAG_VAR_AXIS_WIDTH HB_TAG('w','d','t','h')
/**
- * hb_tag_t:
- * @HB_OT_TAG_VAR_AXIS_WEIGHT: Registered tag for the weight axis
+ * HB_OT_TAG_VAR_AXIS_WEIGHT:
+ *
+ * Registered tag for the weight axis.
*/
#define HB_OT_TAG_VAR_AXIS_WEIGHT HB_TAG('w','g','h','t')
@@ -88,11 +92,14 @@ hb_ot_var_get_axis_count (hb_face_t *face);
* hb_ot_var_axis_flags_t:
* @HB_OT_VAR_AXIS_FLAG_HIDDEN: The axis should not be exposed directly in user interfaces.
*
+ * Flags for #hb_ot_var_axis_info_t.
+ *
* Since: 2.2.0
*/
typedef enum { /*< flags >*/
HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u,
+ /*< private >*/
_HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/
} hb_ot_var_axis_flags_t;
diff --git a/thirdparty/harfbuzz/src/hb-sanitize.hh b/thirdparty/harfbuzz/src/hb-sanitize.hh
index 024b4d1c99..1675e8448a 100644
--- a/thirdparty/harfbuzz/src/hb-sanitize.hh
+++ b/thirdparty/harfbuzz/src/hb-sanitize.hh
@@ -73,7 +73,7 @@
* === The sanitize() contract ===
*
* The sanitize() method of each object type shall return true if it's safe to
- * call other methods of the object, and false otherwise.
+ * call other methods of the object, and %false otherwise.
*
* Note that what sanitize() checks for might align with what the specification
* describes as valid table data, but does not have to be. In particular, we
@@ -113,8 +113,8 @@
#ifndef HB_SANITIZE_MAX_OPS_MAX
#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
#endif
-#ifndef HB_SANITIZE_MAX_SUTABLES
-#define HB_SANITIZE_MAX_SUTABLES 0x4000
+#ifndef HB_SANITIZE_MAX_SUBTABLES
+#define HB_SANITIZE_MAX_SUBTABLES 0x4000
#endif
struct hb_sanitize_context_t :
@@ -139,7 +139,7 @@ struct hb_sanitize_context_t :
bool visit_subtables (unsigned count)
{
max_subtables += count;
- return max_subtables < HB_SANITIZE_MAX_SUTABLES;
+ return max_subtables < HB_SANITIZE_MAX_SUBTABLES;
}
private:
diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh
index 4566153a59..fe29bdf96e 100644
--- a/thirdparty/harfbuzz/src/hb-serialize.hh
+++ b/thirdparty/harfbuzz/src/hb-serialize.hh
@@ -256,10 +256,11 @@ struct hb_serialize_context_t
packed.push (obj);
- if (unlikely (packed.in_error ())) {
- // obj wasn't successfully added to packed, so clean it up otherwise it's
- // links will be leaked.
- propagate_error (packed);
+ if (unlikely (!propagate_error (packed)))
+ {
+ /* Obj wasn't successfully added to packed, so clean it up otherwise its
+ * links will be leaked. When we use constructor/destructors properly, we
+ * can remove these. */
obj->fini ();
return 0;
}
@@ -523,7 +524,7 @@ struct hb_serialize_context_t
template <typename T>
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
{
- auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
+ auto &off = * ((BEInt<T> *) (parent->head + link.position));
assert (0 == off);
check_assign (off, offset);
}
diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc
index 3b4059ad32..86bf70034c 100644
--- a/thirdparty/harfbuzz/src/hb-set.cc
+++ b/thirdparty/harfbuzz/src/hb-set.cc
@@ -117,7 +117,7 @@ hb_set_destroy (hb_set_t *set)
* @set: A set
* @key: The user-data key to set
* @data: A pointer to the user data to set
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified set.
@@ -162,7 +162,7 @@ hb_set_get_user_data (hb_set_t *set,
*
* Tests whether memory allocation for a set was successful.
*
- * Return value: %true if allocation succeeded, false otherwise
+ * Return value: %true if allocation succeeded, %false otherwise
*
* Since: 0.9.2
**/
@@ -183,6 +183,9 @@ hb_set_allocation_successful (const hb_set_t *set)
void
hb_set_clear (hb_set_t *set)
{
+ if (unlikely (hb_object_is_immutable (set)))
+ return;
+
set->clear ();
}
@@ -209,7 +212,7 @@ hb_set_is_empty (const hb_set_t *set)
*
* Tests whether @codepoint belongs to @set.
*
- * Return value: %true if @codepoint is in @set, false otherwise
+ * Return value: %true if @codepoint is in @set, %false otherwise
*
* Since: 0.9.2
**/
@@ -298,7 +301,7 @@ hb_set_del_range (hb_set_t *set,
* Tests whether @set and @other are equal (contain the same
* elements).
*
- * Return value: %TRUE if the two sets are equal, %FALSE otherwise.
+ * Return value: %true if the two sets are equal, %false otherwise.
*
* Since: 0.9.7
**/
@@ -316,7 +319,7 @@ hb_set_is_equal (const hb_set_t *set,
*
* Tests whether @set is a subset of @larger_set.
*
- * Return value: %TRUE if the @set is a subset of (or equal to) @larger_set, %FALSE otherwise.
+ * Return value: %true if the @set is a subset of (or equal to) @larger_set, %false otherwise.
*
* Since: 1.8.1
**/
@@ -447,7 +450,7 @@ hb_set_get_population (const hb_set_t *set)
*
* Finds the smallest element in the set.
*
- * Return value: minimum of @set, or %HB_SET_VALUE_INVALID if @set is empty.
+ * Return value: minimum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
*
* Since: 0.9.7
**/
@@ -463,7 +466,7 @@ hb_set_get_min (const hb_set_t *set)
*
* Finds the largest element in the set.
*
- * Return value: maximum of @set, or %HB_SET_VALUE_INVALID if @set is empty.
+ * Return value: maximum of @set, or #HB_SET_VALUE_INVALID if @set is empty.
*
* Since: 0.9.7
**/
@@ -481,9 +484,9 @@ hb_set_get_max (const hb_set_t *set)
*
* Fetches the next element in @set that is greater than current value of @codepoint.
*
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next value, false otherwise
+ * Return value: %true if there was a next value, %false otherwise
*
* Since: 0.9.2
**/
@@ -502,9 +505,9 @@ hb_set_next (const hb_set_t *set,
*
* Fetches the previous element in @set that is lower than current value of @codepoint.
*
- * Set @codepoint to %HB_SET_VALUE_INVALID to get started.
+ * Set @codepoint to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous value, false otherwise
+ * Return value: %true if there was a previous value, %false otherwise
*
* Since: 1.8.0
**/
@@ -525,9 +528,9 @@ hb_set_previous (const hb_set_t *set,
* Fetches the next consecutive range of elements in @set that
* are greater than current value of @last.
*
- * Set @last to %HB_SET_VALUE_INVALID to get started.
+ * Set @last to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a next range, false otherwise
+ * Return value: %true if there was a next range, %false otherwise
*
* Since: 0.9.7
**/
@@ -549,9 +552,9 @@ hb_set_next_range (const hb_set_t *set,
* Fetches the previous consecutive range of elements in @set that
* are greater than current value of @last.
*
- * Set @first to %HB_SET_VALUE_INVALID to get started.
+ * Set @first to #HB_SET_VALUE_INVALID to get started.
*
- * Return value: %true if there was a previous range, false otherwise
+ * Return value: %true if there was a previous range, %false otherwise
*
* Since: 1.8.0
**/
diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h
index cafc36dbad..0ad27f4bbd 100644
--- a/thirdparty/harfbuzz/src/hb-set.h
+++ b/thirdparty/harfbuzz/src/hb-set.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,7 +36,11 @@
HB_BEGIN_DECLS
-/*
+/**
+ * HB_SET_VALUE_INVALID:
+ *
+ * Unset #hb_set_t value.
+ *
* Since: 0.9.21
*/
#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh
index b6e2086a2e..ae8b5eb10f 100644
--- a/thirdparty/harfbuzz/src/hb-set.hh
+++ b/thirdparty/harfbuzz/src/hb-set.hh
@@ -244,7 +244,7 @@ struct hb_set_t
bool resize (unsigned int count)
{
- if (unlikely (!successful)) return false;
+ if (unlikely (count > pages.length && !successful)) return false;
if (!pages.resize (count) || !page_map.resize (count))
{
pages.resize (page_map.length);
@@ -256,19 +256,14 @@ struct hb_set_t
void reset ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
- clear ();
successful = true;
+ clear ();
}
void clear ()
{
- if (unlikely (hb_object_is_immutable (this)))
- return;
- population = 0;
- page_map.resize (0);
- pages.resize (0);
+ if (resize (0))
+ population = 0;
}
bool is_empty () const
{
@@ -278,6 +273,7 @@ struct hb_set_t
return false;
return true;
}
+ explicit operator bool () const { return !is_empty (); }
void dirty () { population = UINT_MAX; }
@@ -389,6 +385,11 @@ struct hb_set_t
{
if (ds <= de)
{
+ // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+ // before attempting to rewrite the page map.
+ hb_vector_t<unsigned> compact_workspace;
+ if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
unsigned int write_index = 0;
for (unsigned int i = 0; i < page_map.length; i++)
{
@@ -396,11 +397,12 @@ struct hb_set_t
if (m < ds || de < m)
page_map[write_index++] = page_map[i];
}
- compact (write_index);
+ compact (compact_workspace, write_index);
resize (write_index);
}
}
+
public:
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
@@ -512,20 +514,37 @@ struct hb_set_t
return true;
}
- void compact (unsigned int length)
+ bool allocate_compact_workspace(hb_vector_t<unsigned>& workspace)
+ {
+ if (unlikely(!workspace.resize (pages.length)))
+ {
+ successful = false;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /*
+ * workspace should be a pre-sized vector allocated to hold at exactly pages.length
+ * elements.
+ */
+ void compact (hb_vector_t<unsigned>& workspace,
+ unsigned int length)
{
- hb_vector_t<uint32_t> old_index_to_page_map_index;
- old_index_to_page_map_index.resize(pages.length);
- for (uint32_t i = 0; i < old_index_to_page_map_index.length; i++)
- old_index_to_page_map_index[i] = 0xFFFFFFFF;
+ assert(workspace.length == pages.length);
+ hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
- for (uint32_t i = 0; i < length; i++)
+ hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
+ /* TODO(iter) Rewrite as dagger? */
+ for (unsigned i = 0; i < length; i++)
old_index_to_page_map_index[page_map[i].index] = i;
compact_pages (old_index_to_page_map_index);
}
- void compact_pages (const hb_vector_t<uint32_t>& old_index_to_page_map_index)
+ void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
{
unsigned int write_index = 0;
for (unsigned int i = 0; i < pages.length; i++)
@@ -543,6 +562,9 @@ struct hb_set_t
template <typename Op>
void process (const Op& op, const hb_set_t *other)
{
+ const bool passthru_left = op (1, 0);
+ const bool passthru_right = op (0, 1);
+
if (unlikely (!successful)) return;
dirty ();
@@ -554,11 +576,17 @@ struct hb_set_t
unsigned int count = 0, newCount = 0;
unsigned int a = 0, b = 0;
unsigned int write_index = 0;
+
+ // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+ // before attempting to rewrite the page map.
+ hb_vector_t<unsigned> compact_workspace;
+ if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
for (; a < na && b < nb; )
{
if (page_map[a].major == other->page_map[b].major)
{
- if (!Op::passthru_left)
+ if (!passthru_left)
{
// Move page_map entries that we're keeping from the left side set
// to the front of the page_map vector. This isn't necessary if
@@ -575,27 +603,27 @@ struct hb_set_t
}
else if (page_map[a].major < other->page_map[b].major)
{
- if (Op::passthru_left)
+ if (passthru_left)
count++;
a++;
}
else
{
- if (Op::passthru_right)
+ if (passthru_right)
count++;
b++;
}
}
- if (Op::passthru_left)
+ if (passthru_left)
count += na - a;
- if (Op::passthru_right)
+ if (passthru_right)
count += nb - b;
- if (!Op::passthru_left)
+ if (!passthru_left)
{
na = write_index;
next_page = write_index;
- compact (write_index);
+ compact (compact_workspace, write_index);
}
if (!resize (count))
@@ -619,7 +647,7 @@ struct hb_set_t
else if (page_map[a - 1].major > other->page_map[b - 1].major)
{
a--;
- if (Op::passthru_left)
+ if (passthru_left)
{
count--;
page_map[count] = page_map[a];
@@ -628,7 +656,7 @@ struct hb_set_t
else
{
b--;
- if (Op::passthru_right)
+ if (passthru_right)
{
count--;
page_map[count].major = other->page_map[b].major;
@@ -637,14 +665,14 @@ struct hb_set_t
}
}
}
- if (Op::passthru_left)
+ if (passthru_left)
while (a)
{
a--;
count--;
page_map[count] = page_map [a];
}
- if (Op::passthru_right)
+ if (passthru_right)
while (b)
{
b--;
@@ -655,6 +683,9 @@ struct hb_set_t
}
assert (!count);
if (pages.length > newCount)
+ // This resize() doesn't need to be checked because we can't get here
+ // if the set is currently in_error() and this only resizes downwards
+ // which will always succeed if the set is not in_error().
resize (newCount);
}
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc
index 65a5fc4512..0d9eaddaa6 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc
@@ -329,12 +329,12 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
* @shape_plan: A shaping plan
* @key: The user-data key to set
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given shaping plan.
*
- * Return value:
+ * Return value: %true if success, %false otherwise.
*
* Since: 0.9.7
**/
@@ -439,7 +439,7 @@ _hb_shape_plan_execute_internal (hb_shape_plan_t *shape_plan,
* Executes the given shaping plan on the specified buffer, using
* the given @font and @features.
*
- * Return value:
+ * Return value: %true if success, %false otherwise.
*
* Since: 0.9.7
**/
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.h b/thirdparty/harfbuzz/src/hb-shape-plan.h
index 336524ee2f..fc7c041899 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.h
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc
index a3debce397..c442f4403b 100644
--- a/thirdparty/harfbuzz/src/hb-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-shape.cc
@@ -111,10 +111,10 @@ hb_shape_list_shapers ()
* hb_shape_full:
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @features: (array length=num_features) (nullable): an array of user
* specified #hb_feature_t or %NULL
* @num_features: the length of @features array
- * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
+ * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated
* array of shapers to use or %NULL
*
* See hb_shape() for details. If @shaper_list is not %NULL, the specified
@@ -146,7 +146,7 @@ hb_shape_full (hb_font_t *font,
* hb_shape:
* @font: an #hb_font_t to use for shaping
* @buffer: an #hb_buffer_t to shape
- * @features: (array length=num_features) (allow-none): an array of user
+ * @features: (array length=num_features) (nullable): an array of user
* specified #hb_feature_t or %NULL
* @num_features: the length of @features array
*
diff --git a/thirdparty/harfbuzz/src/hb-shape.h b/thirdparty/harfbuzz/src/hb-shape.h
index 39507ff744..922f8c011e 100644
--- a/thirdparty/harfbuzz/src/hb-shape.h
+++ b/thirdparty/harfbuzz/src/hb-shape.h
@@ -26,7 +26,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-style.cc b/thirdparty/harfbuzz/src/hb-style.cc
index 86b9f7da5f..2f45d119f9 100644
--- a/thirdparty/harfbuzz/src/hb-style.cc
+++ b/thirdparty/harfbuzz/src/hb-style.cc
@@ -65,6 +65,7 @@ typedef enum {
HB_STYLE_TAG_WIDTH = HB_TAG ('w','d','t','h'),
HB_STYLE_TAG_WEIGHT = HB_TAG ('w','g','h','t'),
+ /*< private >*/
_HB_STYLE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_style_tag_t;
diff --git a/thirdparty/harfbuzz/src/hb-style.h b/thirdparty/harfbuzz/src/hb-style.h
index 1209c79e94..f5776cee58 100644
--- a/thirdparty/harfbuzz/src/hb-style.h
+++ b/thirdparty/harfbuzz/src/hb-style.h
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 24beada3e8..d055783a4d 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -88,10 +88,17 @@ _gsub_closure_glyphs_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gsub_lookups);
- //closure features
+ // Collect and prune features
hb_set_t feature_indices;
- gsub->closure_features (gsub_lookups, &feature_indices);
+ hb_ot_layout_collect_features (face,
+ HB_OT_TAG_GSUB,
+ nullptr,
+ nullptr,
+ nullptr,
+ &feature_indices);
+ gsub->prune_features (gsub_lookups, &feature_indices);
_remap_indexes (&feature_indices, gsub_features);
+
gsub.destroy ();
}
@@ -114,9 +121,15 @@ _gpos_closure_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gpos_lookups);
- //closure features
+ // Collect and prune features
hb_set_t feature_indices;
- gpos->closure_features (gpos_lookups, &feature_indices);
+ hb_ot_layout_collect_features (face,
+ HB_OT_TAG_GPOS,
+ nullptr,
+ nullptr,
+ nullptr,
+ &feature_indices);
+ gpos->prune_features (gpos_lookups, &feature_indices);
_remap_indexes (&feature_indices, gpos_features);
gpos.destroy ();
}
@@ -243,7 +256,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR
if (close_over_gdef)
- _collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map);
+ _collect_layout_variation_indices (plan->source,
+ plan->_glyphset_gsub,
+ plan->gpos_lookups,
+ plan->layout_variation_indices,
+ plan->layout_variation_idx_map);
#endif
#ifndef HB_NO_SUBSET_CFF
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index e9f603dd1d..cc9cb7a1a2 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -172,12 +172,15 @@ struct hb_subset_plan_t
add_table (hb_tag_t tag,
hb_blob_t *contents)
{
- hb_blob_t *source_blob = source->reference_table (tag);
- DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
- HB_UNTAG(tag),
- hb_blob_get_length (contents),
- hb_blob_get_length (source_blob));
- hb_blob_destroy (source_blob);
+ if (HB_DEBUG_SUBSET)
+ {
+ hb_blob_t *source_blob = source->reference_table (tag);
+ DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
+ HB_UNTAG(tag),
+ hb_blob_get_length (contents),
+ hb_blob_get_length (source_blob));
+ hb_blob_destroy (source_blob);
+ }
return hb_face_builder_add_table (dest, tag, contents);
}
};
diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc
index d7f6a6e130..7470bb1b6e 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.cc
+++ b/thirdparty/harfbuzz/src/hb-unicode.cc
@@ -276,7 +276,7 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
* @ufuncs: The Unicode-functions structure
* @key: The user-data key
* @data: A pointer to the user data
- * @destroy: (optional): A callback to call when @data is not needed anymore
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the specified Unicode-functions structure.
@@ -340,7 +340,7 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
* Tests whether the specified Unicode-functions structure
* is immutable.
*
- * Return value: %true if @ufuncs is immutable, false otherwise
+ * Return value: %true if @ufuncs is immutable, %false otherwise
*
* Since: 0.9.2
**/
@@ -421,7 +421,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
* Calls the composition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @a and @b composed, false otherwise
+ * Return value: %true if @a and @b composed, %false otherwise
*
* Since: 0.9.2
**/
@@ -446,7 +446,7 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
* Calls the decomposition function of the specified
* Unicode-functions structure @ufuncs.
*
- * Return value: %true if @ab was decomposed, false otherwise
+ * Return value: %true if @ab was decomposed, %false otherwise
*
* Since: 0.9.2
**/
@@ -469,7 +469,7 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
* Fetches the compatibility decomposition of a Unicode
* code point. Deprecated.
*
- * Return value:
+ * Return value: length of @decomposed.
*
* Since: 0.9.2
* Deprecated: 2.0.0
diff --git a/thirdparty/harfbuzz/src/hb-unicode.h b/thirdparty/harfbuzz/src/hb-unicode.h
index 7ea0848c0f..c04ee15a09 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.h
+++ b/thirdparty/harfbuzz/src/hb-unicode.h
@@ -28,7 +28,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -41,7 +41,9 @@ HB_BEGIN_DECLS
/**
- * HB_UNICODE_MAX
+ * HB_UNICODE_MAX:
+ *
+ * Maximum valid Unicode code point.
*
* Since: 1.9.0
**/
@@ -427,7 +429,7 @@ typedef hb_script_t (*hb_unicode_script_func_t) (hb_unicode_funcs_t *ufuncs,
* The method must return an #hb_bool_t indicating the success
* of the composition.
*
- * Return value: True is @a,@b composed, false otherwise
+ * Return value: %true is @a,@b composed, %false otherwise
*
**/
typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -451,7 +453,7 @@ typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs,
* output parameters (if successful). The method must return an
* #hb_bool_t indicating the success of the composition.
*
- * Return value: True if @ab decomposed, false otherwise
+ * Return value: %true if @ab decomposed, %false otherwise
*
**/
typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -467,7 +469,7 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_combining_class_func_t.
*
@@ -483,7 +485,7 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_general_category_func_t.
*
@@ -499,7 +501,7 @@ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_mirroring_func_t.
*
@@ -515,7 +517,7 @@ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_script_func_t.
*
@@ -531,7 +533,7 @@ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_compose_func_t.
*
@@ -547,7 +549,7 @@ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
* @ufuncs: A Unicode-functions structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
- * @destroy: (optional): The function to call when @user_data is not needed anymore
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
*
* Sets the implementation function for #hb_unicode_decompose_func_t.
*
@@ -624,40 +626,12 @@ HB_EXTERN hb_script_t
hb_unicode_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
-/**
- * hb_unicode_compose:
- * @ufuncs: The Unicode-functions structure
- * @a: The first code point to compose
- * @b: The second code point to compose
- * @ab: (out): The composed code point
- *
- * Composes the code point sequence @a,@b by canonical equivalence into
- * code point @ab.
- *
- * Return value: True is @a,@b composed, false otherwise
- *
- * Since: 0.9.2
- **/
HB_EXTERN hb_bool_t
hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab);
-/**
- * hb_unicode_decompose:
- * @ufuncs: The Unicode-functions structure
- * @ab: The code point to decompose
- * @a: (out): The first decomposed code point
- * @b: (out): The second decomposed code point
- *
- * Decomposes code point @ab by canonical equivalence, into code points
- * @a and @b.
- *
- * Return value: True if @ab decomposed, false otherwise
- *
- * Since: 0.9.2
- **/
HB_EXTERN hb_bool_t
hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t ab,
diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh
index 079b94a6b4..13517a9c29 100644
--- a/thirdparty/harfbuzz/src/hb-vector.hh
+++ b/thirdparty/harfbuzz/src/hb-vector.hh
@@ -80,7 +80,12 @@ struct hb_vector_t
fini ();
}
- void reset () { resize (0); }
+ void reset ()
+ {
+ if (unlikely (in_error ()))
+ allocated = length; // Big hack!
+ resize (0);
+ }
hb_vector_t& operator = (const hb_vector_t &o)
{
@@ -181,7 +186,7 @@ struct hb_vector_t
/* Allocate for size but don't adjust length. */
bool alloc (unsigned int size)
{
- if (unlikely (allocated < 0))
+ if (unlikely (in_error ()))
return false;
if (likely (size <= (unsigned) allocated))
@@ -195,7 +200,7 @@ struct hb_vector_t
Type *new_array = nullptr;
bool overflows =
- (int) new_allocated < 0 ||
+ (int) in_error () ||
(new_allocated < (unsigned) allocated) ||
hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index da377b9df6..6db58c3f7c 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_H_IN
+#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR)
#error "Include <hb.h> instead."
#endif
@@ -36,12 +36,41 @@
HB_BEGIN_DECLS
+/**
+ * HB_VERSION_MAJOR:
+ *
+ * The major component of the library version available at compile-time.
+ */
#define HB_VERSION_MAJOR 2
-#define HB_VERSION_MINOR 7
-#define HB_VERSION_MICRO 4
+/**
+ * HB_VERSION_MINOR:
+ *
+ * The minor component of the library version available at compile-time.
+ */
+#define HB_VERSION_MINOR 8
+/**
+ * HB_VERSION_MICRO:
+ *
+ * The micro component of the library version available at compile-time.
+ */
+#define HB_VERSION_MICRO 0
-#define HB_VERSION_STRING "2.7.4"
+/**
+ * HB_VERSION_STRING:
+ *
+ * A string literal containing the library version available at compile-time.
+ */
+#define HB_VERSION_STRING "2.8.0"
+/**
+ * HB_VERSION_ATLEAST:
+ * @major: the major component of the version number
+ * @minor: the minor component of the version number
+ * @micro: the micro component of the version number
+ *
+ * Tests the library version at compile-time against a minimum value,
+ * as three integer components.
+ */
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh
index 274a0e98db..18516581c7 100644
--- a/thirdparty/harfbuzz/src/hb.hh
+++ b/thirdparty/harfbuzz/src/hb.hh
@@ -62,7 +62,6 @@
/* Error. Should never happen. */
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
-#pragma GCC diagnostic error "-Wc++11-narrowing"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
@@ -75,6 +74,7 @@
#pragma GCC diagnostic error "-Wmissing-braces"
#pragma GCC diagnostic error "-Wmissing-declarations"
#pragma GCC diagnostic error "-Wmissing-prototypes"
+#pragma GCC diagnostic error "-Wnarrowing"
#pragma GCC diagnostic error "-Wnested-externs"
#pragma GCC diagnostic error "-Wold-style-definition"
#pragma GCC diagnostic error "-Wpointer-arith"
@@ -126,6 +126,7 @@
#pragma GCC diagnostic ignored "-Wformat-zero-length"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang
+#pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it
@@ -175,15 +176,15 @@
#include "hb-aat.h"
#define HB_AAT_H_IN
-#include <limits.h>
-#include <math.h>
-#include <float.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdarg.h>
+#include <cassert>
+#include <cfloat>
+#include <climits>
+#include <cmath>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
#ifdef __MINGW32_VERSION
@@ -244,12 +245,8 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
-#define HB_PURE_FUNC __attribute__((pure))
-#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
-#define HB_PURE_FUNC
-#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
@@ -394,7 +391,7 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#ifndef HB_NO_ERRNO
-# include <errno.h>
+# include <cerrno>
#else
static int HB_UNUSED _hb_errno = 0;
# undef errno
@@ -440,181 +437,12 @@ static int HB_UNUSED _hb_errno = 0;
#define HB_STMT_START do
#define HB_STMT_END while (0)
-/* Static-assert as expression. */
-template <unsigned int cond> class hb_assert_constant_t;
-template <> class hb_assert_constant_t<1> {};
-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
-
/* Lets assert int types. Saves trouble down the road. */
-static_assert ((sizeof (int8_t) == 1), "");
-static_assert ((sizeof (uint8_t) == 1), "");
-static_assert ((sizeof (int16_t) == 2), "");
-static_assert ((sizeof (uint16_t) == 2), "");
-static_assert ((sizeof (int32_t) == 4), "");
-static_assert ((sizeof (uint32_t) == 4), "");
-static_assert ((sizeof (int64_t) == 8), "");
-static_assert ((sizeof (uint64_t) == 8), "");
static_assert ((sizeof (hb_codepoint_t) == 4), "");
static_assert ((sizeof (hb_position_t) == 4), "");
static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
-#define HB_DELETE_COPY_ASSIGN(TypeName) \
- TypeName(const TypeName&) = delete; \
- void operator=(const TypeName&) = delete
-#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
- TypeName() = delete; \
- TypeName(const TypeName&) = delete; \
- void operator=(const TypeName&) = delete
-
-
-/* Flags */
-
-/* Enable bitwise ops on enums marked as flags_t */
-/* To my surprise, looks like the function resolver is happy to silently cast
- * one enum to another... So this doesn't provide the type-checking that I
- * originally had in mind... :(.
- *
- * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
- */
-#ifdef _MSC_VER
-# pragma warning(disable:4200)
-# pragma warning(disable:4800)
-#endif
-#define HB_MARK_AS_FLAG_T(T) \
- extern "C++" { \
- static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
- static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
- static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
- static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
- static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
- static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
- static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
- } \
- static_assert (true, "")
-
-/* Useful for set-operations on small enums.
- * For example, for testing "x ∈ {x1, x2, x3}" use:
- * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
- */
-#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
-#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
-#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
-#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
-#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
-
-
-/* Size signifying variable-sized array */
-#ifndef HB_VAR_ARRAY
-#define HB_VAR_ARRAY 1
-#endif
-
-static inline float
-_hb_roundf (float x) { return floorf (x + .5f); }
-#define roundf(x) _hb_roundf(x)
-
-/* Endian swap, used in Windows related backends */
-static inline uint16_t hb_uint16_swap (const uint16_t v)
-{ return (v >> 8) | (v << 8); }
-static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
-
-/*
- * Big-endian integers. Here because fundamental.
- */
-
-template <typename Type, int Bytes> struct BEInt;
-
-template <typename Type>
-struct BEInt<Type, 1>
-{
- public:
- BEInt<Type, 1>& operator = (Type V)
- {
- v = V;
- return *this;
- }
- operator Type () const { return v; }
- private: uint8_t v;
-};
-template <typename Type>
-struct BEInt<Type, 2>
-{
- public:
- BEInt<Type, 2>& operator = (Type V)
- {
- v[0] = (V >> 8) & 0xFF;
- v[1] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
-#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
- struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- return __builtin_bswap16 (((packed_uint16_t *) this)->v);
-#else /* __BYTE_ORDER == __BIG_ENDIAN */
- return ((packed_uint16_t *) this)->v;
-#endif
-#endif
- return (v[0] << 8)
- + (v[1] );
- }
- private: uint8_t v[2];
-};
-template <typename Type>
-struct BEInt<Type, 3>
-{
- public:
- BEInt<Type, 3>& operator = (Type V)
- {
- v[0] = (V >> 16) & 0xFF;
- v[1] = (V >> 8) & 0xFF;
- v[2] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
- return (v[0] << 16)
- + (v[1] << 8)
- + (v[2] );
- }
- private: uint8_t v[3];
-};
-template <typename Type>
-struct BEInt<Type, 4>
-{
- public:
- BEInt<Type, 4>& operator = (Type V)
- {
- v[0] = (V >> 24) & 0xFF;
- v[1] = (V >> 16) & 0xFF;
- v[2] = (V >> 8) & 0xFF;
- v[3] = (V ) & 0xFF;
- return *this;
- }
- operator Type () const
- {
- return (v[0] << 24)
- + (v[1] << 16)
- + (v[2] << 8)
- + (v[3] );
- }
- private: uint8_t v[4];
-};
-
-
-/*
- * For lack of a better place, put Zawgyi script hack here.
- * https://github.com/harfbuzz/harfbuzz/issues/1162
- */
-
-#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
-
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
diff --git a/thirdparty/icu4c/APIChangeReport.md b/thirdparty/icu4c/APIChangeReport.md
deleted file mode 100644
index 5385904fd1..0000000000
--- a/thirdparty/icu4c/APIChangeReport.md
+++ /dev/null
@@ -1,396 +0,0 @@
-
-
-<!--
- Copyright © 2019 and later: Unicode, Inc. and others.
- License & terms of use: http://www.unicode.org/copyright.html
--->
-
-# ICU4C API Comparison: ICU 67 with ICU 68
-
-> _Note_ Markdown format of this document is new for ICU 65.
-
-- [Removed from ICU 67](#removed)
-- [Deprecated or Obsoleted in ICU 68](#deprecated)
-- [Changed in ICU 68](#changed)
-- [Promoted to stable in ICU 68](#promoted)
-- [Added in ICU 68](#added)
-- [Other existing drafts in ICU 68](#other)
-- [Signature Simplifications](#simplifications)
-
-## Removed
-
-Removed from ICU 67
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| fmtable.h | const UFormattable* icu::Formattable::toUFormattable() | StableICU 52 | (missing)
-| measunit.h | LocalArray&lt;MeasureUnit&gt; icu::MeasureUnit::splitToSingleUnits(int32_t&amp;, UErrorCode&amp;) const | InternalICU 67 | (missing)
-| measunit.h | int32_t icu::MeasureUnit::getIndex() const | Internal | (missing)
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::resolveUnitPerUnit(const MeasureUnit&amp;, const MeasureUnit&amp;, bool*) | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::getIndexCount() | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::internalGetIndexForTypeAndSubtype(const char*, const char*) | Internal | (missing)
-| nounit.h | UClassID icu::NoUnit::getDynamicClassID() const | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::NoUnit(const NoUnit&amp;) | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::~NoUnit() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::base() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::percent() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::permille() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> UClassID icu::NoUnit::getStaticClassID() | DraftICU 60 | (missing)
-| nounit.h | void* icu::NoUnit::clone() const | DraftICU 60 | (missing)
-| uniset.h | const USet* icu::UnicodeSet::toUSet() | StableICU 4.2 | (missing)
-
-## Deprecated
-
-Deprecated or Obsoleted in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-
-## Changed
-
-Changed in ICU 68 (old, new)
-
-
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Promoted
-
-Promoted to stable in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Added
-
-Added in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| dtitvfmt.h | UDisplayContext icu::DateIntervalFormat::getContext(UDisplayContextType, UErrorCode&amp;) const | (missing) | DraftICU 68
-| dtitvfmt.h | void icu::DateIntervalFormat::setContext(UDisplayContext, UErrorCode&amp;) | (missing) | DraftICU 68
-| dtptngen.h | <tt>static</tt> DateTimePatternGenerator* icu::DateTimePatternGenerator::createInstanceNoStdPat(const Locale&amp;, UErrorCode&amp;) | (missing) | Internal
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setMaxDistance(const Locale&amp;, const Locale&amp;) | (missing) | DraftICU 68
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setNoDefaultLocale() | (missing) | DraftICU 68
-| localematcher.h | UBool icu::LocaleMatcher::isMatch(const Locale&amp;, const Locale&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| measunit.h | int32_t icu::MeasureUnit::getOffset() const | (missing) | Internal
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getCandela() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoon() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoonImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDot() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDram() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDrop() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEarthRadius() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getGrain() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getJigger() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getLumen() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPinch() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getQuartImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createCandela(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoon(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoonImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDot(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDram(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDrop(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEarthRadius(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createGrain(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createJigger(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createLumen(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPinch(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createQuartImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | std::pair&lt; LocalArray&lt; MeasureUnit &gt;, int32_t &gt; icu::MeasureUnit::splitToSingleUnits(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece) const&amp; | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece)&amp;&amp; | (missing) | DraftICU 68
-| numberformatter.h | MeasureUnit icu::number::FormattedNumber::getOutputUnit(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | bool icu::number::impl::Usage::isSet() const | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::~Usage() | (missing) | Internal
-| numberformatter.h | int16_t icu::number::impl::Usage::length() const | (missing) | Internal
-| numberformatter.h | void icu::number::impl::Usage::set(StringPiece) | (missing) | Internal
-| numberrangeformatter.h | std::pair&lt; StringClass, StringClass &gt; icu::number::FormattedNumberRange::getDecimalNumbers(UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::FormattedNumberRange&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::impl::UFormattedNumberRangeData*, UErrorCode&amp;) const | (missing) | Internal
-| plurrule.h | int32_t icu::PluralRules::getSamples(const UnicodeString&amp;, FixedDecimal*, int32_t, UErrorCode&amp;) | (missing) | Internal
-| timezone.h | <tt>static</tt> TimeZone* icu::TimeZone::forLocaleOrDefault(const Locale&amp;) | (missing) | Internal
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_FORMAL_SYMBOL_NAME | (missing) | DraftICU 68
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_VARIANT_SYMBOL_NAME | (missing) | DraftICU 68
-| udateintervalformat.h | UDisplayContext udtitvfmt_getContext(const UDateIntervalFormat*, UDisplayContextType, UErrorCode*) | (missing) | DraftICU 68
-| udateintervalformat.h | void udtitvfmt_setContext(UDateIntervalFormat*, UDisplayContext, UErrorCode*) | (missing) | DraftICU 68
-| umachine.h | <tt>#define</tt> U_DEFINE_FALSE_AND_TRUE | (missing) | InternalICU 68
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_AUTO | (missing) | DraftICU 68
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_MIN2 | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_FORMAL | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_VARIANT | (missing) | DraftICU 68
-| unumberformatter.h | int32_t unumf_resultToDecimalNumber(const UFormattedNumber*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UFormattedNumberRange* unumrf_openResult(UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeFormatter* unumrf_openForSkeletonWithCollapseAndIdentityFallback(const UChar*, int32_t, UNumberRangeCollapse, UNumberRangeIdentityFallback, const char*, UParseError*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeIdentityResult unumrf_resultGetIdentityResult(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | const UFormattedValue* unumrf_resultAsValue(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_close(UNumberRangeFormatter*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_closeResult(UFormattedNumberRange*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDecimalRange(const UNumberRangeFormatter*, const char*, int32_t, const char*, int32_t, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDoubleRange(const UNumberRangeFormatter*, double, double, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| upluralrules.h | int32_t uplrules_selectForRange(const UPluralRules*, const struct UFormattedNumberRange*, UChar*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-
-## Other
-
-Other existing drafts in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestream.h | void icu::ByteSink::AppendU8(const char*, int32_t) | DraftICU 67 |
-| bytestream.h | void icu::ByteSink::AppendU8(const char8_t*, int32_t) | DraftICU 67 |
-| dtptngen.h | UDateFormatHourCycle icu::DateTimePatternGenerator::getDefaultHourCycle(UErrorCode&amp;) const | DraftICU 67 |
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDirection(ULocMatchDirection) | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_ONLY_TWO_WAY | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_WITH_ONE_WAY | DraftICU 67 |
-| locid.h | void icu::Locale::canonicalize(UErrorCode&amp;) | DraftICU 67 |
-| measfmt.h | void icu::MeasureFormat::parseObject(const UnicodeString&amp;, Formattable&amp;, ParsePosition&amp;) const | DraftICU 53 |
-| measunit.h | MeasureUnit icu::MeasureUnit::product(const MeasureUnit&amp;, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::reciprocal(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withDimensionality(int32_t, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withSIPrefix(UMeasureSIPrefix, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit&amp; icu::MeasureUnit::operator=(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | UMeasureSIPrefix icu::MeasureUnit::getSIPrefix(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | UMeasureUnitComplexity icu::MeasureUnit::getComplexity(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | const char* icu::MeasureUnit::getIdentifier() const | DraftICU 67 |
-| measunit.h | icu::MeasureUnit::MeasureUnit(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | int32_t icu::MeasureUnit::getDimensionality(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::forIdentifier(StringPiece, UErrorCode&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*, int32_t) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const std::u8string&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(std::nullptr_t) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::compare(StringPiece) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::find(StringPiece, int32_t) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*, int32_t) | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_11 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_12 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_23 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_24 | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatCalendarToResult(const UDateIntervalFormat*, UCalendar*, UCalendar*, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatToResult(const UDateIntervalFormat*, UDate, UDate, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udatpg.h | UDateFormatHourCycle udatpg_getDefaultHourCycle(const UDateTimePatternGenerator*, UErrorCode*) | DraftICU 67 |
-| uregex.h | <tt>enum</tt> URegexpFlag::UREGEX_CANON_EQ | DraftICU 2.4 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_BREAK_ENGINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_CHARACTER | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_LINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_SENTENCE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_TITLE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_WORD | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_START | DraftICU 67 |
-
-## Simplifications
-
-This section shows cases where the signature was "simplified" for the sake of comparison. The simplified form is in bold, followed by
- all possible variations in "original" form.
-
-
-## Colophon
-
-Contents generated by StableAPI tool on Fri Oct 23 11:32:42 PDT 2020
-
-Copyright © 2019 and later: Unicode, Inc. and others.
-License & terms of use: http://www.unicode.org/copyright.html
- \ No newline at end of file
diff --git a/thirdparty/icu4c/common/bytestriebuilder.cpp b/thirdparty/icu4c/common/bytestriebuilder.cpp
index ec1ab7d8f5..28256f272a 100644
--- a/thirdparty/icu4c/common/bytestriebuilder.cpp
+++ b/thirdparty/icu4c/common/bytestriebuilder.cpp
@@ -474,31 +474,39 @@ BytesTrieBuilder::writeDeltaTo(int32_t jumpTarget) {
U_ASSERT(i>=0);
if(i<=BytesTrie::kMaxOneByteDelta) {
return write(i);
+ } else {
+ char intBytes[5];
+ return write(intBytes, internalEncodeDelta(i, intBytes));
}
- char intBytes[5];
- int32_t length;
+}
+
+int32_t
+BytesTrieBuilder::internalEncodeDelta(int32_t i, char intBytes[]) {
+ U_ASSERT(i>=0);
+ if(i<=BytesTrie::kMaxOneByteDelta) {
+ intBytes[0]=(char)i;
+ return 1;
+ }
+ int32_t length=1;
if(i<=BytesTrie::kMaxTwoByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinTwoByteDeltaLead+(i>>8));
- length=1;
} else {
if(i<=BytesTrie::kMaxThreeByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinThreeByteDeltaLead+(i>>16));
- length=2;
} else {
if(i<=0xffffff) {
intBytes[0]=(char)BytesTrie::kFourByteDeltaLead;
- length=3;
} else {
intBytes[0]=(char)BytesTrie::kFiveByteDeltaLead;
intBytes[1]=(char)(i>>24);
- length=4;
+ length=2;
}
- intBytes[1]=(char)(i>>16);
+ intBytes[length++]=(char)(i>>16);
}
- intBytes[1]=(char)(i>>8);
+ intBytes[length++]=(char)(i>>8);
}
intBytes[length++]=(char)i;
- return write(intBytes, length);
+ return length;
}
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/charstr.cpp b/thirdparty/icu4c/common/charstr.cpp
index 318a185b3f..c35622882c 100644
--- a/thirdparty/icu4c/common/charstr.cpp
+++ b/thirdparty/icu4c/common/charstr.cpp
@@ -14,6 +14,8 @@
* created by: Markus W. Scherer
*/
+#include <cstdlib>
+
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
@@ -141,6 +143,38 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
return *this;
}
+CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
+ if (number < 0) {
+ this->append('-', status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ if (number == 0) {
+ this->append('0', status);
+ return *this;
+ }
+
+ int32_t numLen = 0;
+ while (number != 0) {
+ int32_t residue = number % 10;
+ number /= 10;
+ this->append(std::abs(residue) + '0', status);
+ numLen++;
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ int32_t start = this->length() - numLen, end = this->length() - 1;
+ while(start < end) {
+ std::swap(this->data()[start++], this->data()[end--]);
+ }
+
+ return *this;
+}
+
char *CharString::getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
int32_t &resultCapacity,
diff --git a/thirdparty/icu4c/common/charstr.h b/thirdparty/icu4c/common/charstr.h
index 6619faac61..175acd1c0a 100644
--- a/thirdparty/icu4c/common/charstr.h
+++ b/thirdparty/icu4c/common/charstr.h
@@ -127,6 +127,9 @@ public:
return append(s.data(), s.length(), errorCode);
}
CharString &append(const char *s, int32_t sLength, UErrorCode &status);
+
+ CharString &appendNumber(int32_t number, UErrorCode &status);
+
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* resultCapacity. Guarantees resultCapacity>=minCapacity if U_SUCCESS().
diff --git a/thirdparty/icu4c/common/cmemory.h b/thirdparty/icu4c/common/cmemory.h
index a9d9424b4e..f03b7dcce6 100644
--- a/thirdparty/icu4c/common/cmemory.h
+++ b/thirdparty/icu4c/common/cmemory.h
@@ -31,14 +31,63 @@
#include <stddef.h>
#include <string.h>
#include "unicode/localpointer.h"
+#include "uassert.h"
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
#include <stdio.h>
#endif
-
-#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
-#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
+// uprv_memcpy and uprv_memmove
+#if defined(__clang__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#elif defined(__GNUC__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#else
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#endif
/**
* \def UPRV_LENGTHOF
diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp
index b42cdf03fa..44285755f3 100644
--- a/thirdparty/icu4c/common/dictbe.cpp
+++ b/thirdparty/icu4c/common/dictbe.cpp
@@ -265,13 +265,9 @@ ThaiBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%THAI_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%THAI_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -503,13 +499,9 @@ LaoBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % LAO_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%LAO_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%LAO_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -699,13 +691,9 @@ BurmeseBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % BURMESE_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -908,13 +896,9 @@ KhmerBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % KHMER_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
diff --git a/thirdparty/icu4c/common/edits.cpp b/thirdparty/icu4c/common/edits.cpp
index 95f0c19a72..92ca36fb5d 100644
--- a/thirdparty/icu4c/common/edits.cpp
+++ b/thirdparty/icu4c/common/edits.cpp
@@ -86,6 +86,7 @@ Edits &Edits::moveArray(Edits &src) U_NOEXCEPT {
}
Edits &Edits::operator=(const Edits &other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
length = other.length;
delta = other.delta;
numChanges = other.numChanges;
diff --git a/thirdparty/icu4c/common/filteredbrk.cpp b/thirdparty/icu4c/common/filteredbrk.cpp
index c07128cbce..25080f9d33 100644
--- a/thirdparty/icu4c/common/filteredbrk.cpp
+++ b/thirdparty/icu4c/common/filteredbrk.cpp
@@ -20,6 +20,7 @@
#include "ubrkimpl.h" // U_ICUDATA_BRKITR
#include "uvector.h"
#include "cmemory.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
@@ -139,13 +140,30 @@ class SimpleFilteredSentenceBreakData : public UMemory {
public:
SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards )
: fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { }
- SimpleFilteredSentenceBreakData *incr() { refcount++; return this; }
- SimpleFilteredSentenceBreakData *decr() { if((--refcount) <= 0) delete this; return 0; }
- virtual ~SimpleFilteredSentenceBreakData();
+ SimpleFilteredSentenceBreakData *incr() {
+ umtx_atomic_inc(&refcount);
+ return this;
+ }
+ SimpleFilteredSentenceBreakData *decr() {
+ if(umtx_atomic_dec(&refcount) <= 0) {
+ delete this;
+ }
+ return 0;
+ }
+ virtual ~SimpleFilteredSentenceBreakData();
+
+ bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); }
+ bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); }
- LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
- LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
- int32_t refcount;
+ const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; }
+ const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; }
+
+private:
+ // These tries own their data arrays.
+ // They are shared and must therefore not be modified.
+ LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
+ LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
+ u_atomic_int32_t refcount;
};
SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {}
@@ -244,7 +262,13 @@ SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIt
fData(new SimpleFilteredSentenceBreakData(forwards, backwards)),
fDelegate(adopt)
{
- // all set..
+ if (fData == nullptr) {
+ delete forwards;
+ delete backwards;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
}
SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() {
@@ -261,59 +285,62 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t bestValue = -1;
// loops while 'n' points to an exception.
utext_setNativeIndex(fText.getAlias(), n); // from n..
- fData->fBackwardsTrie->reset();
- UChar32 uch;
//if(debug2) u_printf(" n@ %d\n", n);
// Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
- if((uch=utext_previous32(fText.getAlias()))==(UChar32)0x0020) { // TODO: skip a class of chars here??
+ if(utext_previous32(fText.getAlias())==u' ') { // TODO: skip a class of chars here??
// TODO only do this the 1st time?
//if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch);
} else {
//if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch);
- uch = utext_next32(fText.getAlias());
+ utext_next32(fText.getAlias());
//if(debug2) u_printf(" -> : |%C| \n", (UChar)uch);
}
- UStringTrieResult r = USTRINGTRIE_INTERMEDIATE_VALUE;
-
- while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL && // more to consume backwards and..
- USTRINGTRIE_HAS_NEXT(r=fData->fBackwardsTrie->nextForCodePoint(uch))) {// more in the trie
- if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
- bestPosn = utext_getNativeIndex(fText.getAlias());
- bestValue = fData->fBackwardsTrie->getValue();
- }
- //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ {
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getBackwardsTrie());
+ UChar32 uch;
+ while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL) { // more to consume backwards
+ UStringTrieResult r = iter.nextForCodePoint(uch);
+ if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
+ bestPosn = utext_getNativeIndex(fText.getAlias());
+ bestValue = iter.getValue();
+ }
+ if(!USTRINGTRIE_HAS_NEXT(r)) {
+ break;
+ }
+ //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ }
}
- if(USTRINGTRIE_MATCHES(r)) { // exact match?
- //if(debug2) u_printf("rev<?/%C/?end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- bestValue = fData->fBackwardsTrie->getValue();
- bestPosn = utext_getNativeIndex(fText.getAlias());
- //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- }
+ //if(bestValue >= 0) {
+ //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
+ //}
if(bestPosn>=0) {
//if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
//if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what?
- //int32_t bestValue = fBackwardsTrie->getValue();
+ //int32_t bestValue = iter.getValue();
////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue);
if(bestValue == kMATCH) { // exact match!
//if(debug2) u_printf(" exact backward match\n");
return kExceptionHere; // See if the next is another exception.
} else if(bestValue == kPARTIAL
- && fData->fForwardsPartialTrie.isValid()) { // make sure there's a forward trie
+ && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie
//if(debug2) u_printf(" partial backward match\n");
// We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie
// to see if it matches something going forward.
- fData->fForwardsPartialTrie->reset();
UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE;
utext_setNativeIndex(fText.getAlias(), bestPosn); // hope that's close ..
//if(debug2) u_printf("Retrying at %d\n", bestPosn);
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getForwardsPartialTrie());
+ UChar32 uch;
while((uch=utext_next32(fText.getAlias()))!=U_SENTINEL &&
- USTRINGTRIE_HAS_NEXT(rfwd=fData->fForwardsPartialTrie->nextForCodePoint(uch))) {
+ USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))) {
//if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias()));
}
if(USTRINGTRIE_MATCHES(rfwd)) {
@@ -339,7 +366,7 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
if(n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -369,7 +396,7 @@ SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) {
if(n == 0 || n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -420,7 +447,7 @@ SimpleFilteredSentenceBreakIterator::previous(void) {
UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) {
if (!fDelegate->isBoundary(offset)) return false; // no break to suppress
- if (fData->fBackwardsTrie.isNull()) return true; // no data = no suppressions
+ if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions
UErrorCode status = U_ZERO_ERROR;
resetState(status);
diff --git a/thirdparty/icu4c/common/hash.h b/thirdparty/icu4c/common/hash.h
index f02cb7087a..b927ddb3c3 100644
--- a/thirdparty/icu4c/common/hash.h
+++ b/thirdparty/icu4c/common/hash.h
@@ -85,16 +85,22 @@ public:
inline int32_t puti(const UnicodeString& key, int32_t value, UErrorCode& status);
+ inline int32_t putiAllowZero(const UnicodeString& key, int32_t value, UErrorCode& status);
+
inline void* get(const UnicodeString& key) const;
inline int32_t geti(const UnicodeString& key) const;
+ inline int32_t getiAndFound(const UnicodeString& key, UBool &found) const;
+
inline void* remove(const UnicodeString& key);
inline int32_t removei(const UnicodeString& key);
inline void removeAll(void);
+ inline UBool containsKey(const UnicodeString& key) const;
+
inline const UHashElement* find(const UnicodeString& key) const;
/**
@@ -203,6 +209,11 @@ inline int32_t Hashtable::puti(const UnicodeString& key, int32_t value, UErrorCo
return uhash_puti(hash, new UnicodeString(key), value, &status);
}
+inline int32_t Hashtable::putiAllowZero(const UnicodeString& key, int32_t value,
+ UErrorCode& status) {
+ return uhash_putiAllowZero(hash, new UnicodeString(key), value, &status);
+}
+
inline void* Hashtable::get(const UnicodeString& key) const {
return uhash_get(hash, &key);
}
@@ -211,6 +222,10 @@ inline int32_t Hashtable::geti(const UnicodeString& key) const {
return uhash_geti(hash, &key);
}
+inline int32_t Hashtable::getiAndFound(const UnicodeString& key, UBool &found) const {
+ return uhash_getiAndFound(hash, &key, &found);
+}
+
inline void* Hashtable::remove(const UnicodeString& key) {
return uhash_remove(hash, &key);
}
@@ -219,6 +234,10 @@ inline int32_t Hashtable::removei(const UnicodeString& key) {
return uhash_removei(hash, &key);
}
+inline UBool Hashtable::containsKey(const UnicodeString& key) const {
+ return uhash_containsKey(hash, &key);
+}
+
inline const UHashElement* Hashtable::find(const UnicodeString& key) const {
return uhash_find(hash, &key);
}
diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp
index 5795cbf87e..132aee290e 100644
--- a/thirdparty/icu4c/common/localematcher.cpp
+++ b/thirdparty/icu4c/common/localematcher.cpp
@@ -345,9 +345,8 @@ UBool compareLSRs(const UHashTok t1, const UHashTok t2) {
int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return suppLength; }
- int32_t index = uhash_geti(supportedLsrToIndex, &lsr);
- if (index == 0) {
- uhash_puti(supportedLsrToIndex, const_cast<LSR *>(&lsr), i + 1, &errorCode);
+ if (!uhash_containsKey(supportedLsrToIndex, &lsr)) {
+ uhash_putiAllowZero(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode);
if (U_SUCCESS(errorCode)) {
supportedLSRs[suppLength] = &lsr;
supportedIndexes[suppLength++] = i;
@@ -685,12 +684,11 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai
int32_t bestSupportedLsrIndex = -1;
for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) {
// Quick check for exact maximized LSR.
- // Returns suppIndex+1 where 0 means not found.
if (supportedLsrToIndex != nullptr) {
desiredLSR.setHashCode();
- int32_t index = uhash_geti(supportedLsrToIndex, &desiredLSR);
- if (index != 0) {
- int32_t suppIndex = index - 1;
+ UBool found = false;
+ int32_t suppIndex = uhash_getiAndFound(supportedLsrToIndex, &desiredLSR, &found);
+ if (found) {
if (remainingIter != nullptr) {
remainingIter->rememberCurrent(desiredIndex, errorCode);
}
diff --git a/thirdparty/icu4c/common/localeprioritylist.cpp b/thirdparty/icu4c/common/localeprioritylist.cpp
index 8916b121be..4455eedb75 100644
--- a/thirdparty/icu4c/common/localeprioritylist.cpp
+++ b/thirdparty/icu4c/common/localeprioritylist.cpp
@@ -187,17 +187,18 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
if (U_FAILURE(errorCode)) { return false; }
}
LocalPointer<Locale> clone;
- int32_t index = uhash_geti(map, &locale);
- if (index != 0) {
+ UBool found = false;
+ int32_t index = uhash_getiAndFound(map, &locale, &found);
+ if (found) {
// Duplicate: Remove the old item and append it anew.
- LocaleAndWeight &lw = list->array[index - 1];
+ LocaleAndWeight &lw = list->array[index];
clone.adoptInstead(lw.locale);
lw.locale = nullptr;
lw.weight = 0;
++numRemoved;
}
if (weight <= 0) { // do not add q=0
- if (index != 0) {
+ if (found) {
// Not strictly necessary but cleaner.
uhash_removei(map, &locale);
}
@@ -217,7 +218,7 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
return false;
}
}
- uhash_puti(map, clone.getAlias(), listLength + 1, &errorCode);
+ uhash_putiAllowZero(map, clone.getAlias(), listLength, &errorCode);
if (U_FAILURE(errorCode)) { return false; }
LocaleAndWeight &lw = list->array[listLength];
lw.locale = clone.orphan();
diff --git a/thirdparty/icu4c/common/locdispnames.cpp b/thirdparty/icu4c/common/locdispnames.cpp
index 47c0667417..96af3f9aa8 100644
--- a/thirdparty/icu4c/common/locdispnames.cpp
+++ b/thirdparty/icu4c/common/locdispnames.cpp
@@ -698,7 +698,7 @@ uloc_getDisplayName(const char *locale,
} /* end switch */
if (len>0) {
- /* we addeed a component, so add separator and write it if there's room. */
+ /* we added a component, so add separator and write it if there's room. */
if(len+sepLen<=cap) {
const UChar * plimit = p + len;
for (; p < plimit; p++) {
diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp
index 874e4a7055..0d506293a9 100644
--- a/thirdparty/icu4c/common/locid.cpp
+++ b/thirdparty/icu4c/common/locid.cpp
@@ -254,7 +254,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
Locale::~Locale()
{
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -466,7 +466,7 @@ Locale& Locale::operator=(const Locale& other) {
}
Locale& Locale::operator=(Locale&& other) U_NOEXCEPT {
- if (baseName != fullName) uprv_free(baseName);
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) uprv_free(baseName);
if (fullName != fullNameBuffer) uprv_free(fullName);
if (other.fullName == other.fullNameBuffer) {
@@ -524,7 +524,7 @@ static const char* const KNOWN_CANONICALIZED[] = {
"km", "km_KH", "kn", "kn_IN", "ko", "ko_KR", "ky", "ky_KG", "lo", "lo_LA",
"lt", "lt_LT", "lv", "lv_LV", "mk", "mk_MK", "ml", "ml_IN", "mn", "mn_MN",
"mr", "mr_IN", "ms", "ms_MY", "my", "my_MM", "nb", "nb_NO", "ne", "ne_NP",
- "nl", "nl_NL", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
+ "nl", "nl_NL", "no", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
"pt", "pt_BR", "pt_PT", "ro", "ro_RO", "ru", "ru_RU", "sd", "sd_IN", "si",
"si_LK", "sk", "sk_SK", "sl", "sl_SI", "so", "so_SO", "sq", "sq_AL", "sr",
"sr_Cyrl_RS", "sr_Latn", "sr_RS", "sv", "sv_SE", "sw", "sw_TZ", "ta",
@@ -627,6 +627,17 @@ private:
LocalMemory<const char*>& types,
LocalMemory<int32_t>& replacementIndexes,
int32_t &length, UErrorCode &status);
+
+ // Read the subdivisionAlias data from alias to
+ // strings+types+replacementIndexes
+ // Allocate length items for types, to store the type field.
+ // Allocate length items for replacementIndexes,
+ // to store the index in the strings for the replacement variant.
+ void readSubdivisionAlias(UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length, UErrorCode &status);
};
/**
@@ -647,6 +658,7 @@ public:
const CharStringMap& scriptMap() const { return script; }
const CharStringMap& territoryMap() const { return territory; }
const CharStringMap& variantMap() const { return variant; }
+ const CharStringMap& subdivisionMap() const { return subdivision; }
static void U_CALLCONV loadData(UErrorCode &status);
static UBool U_CALLCONV cleanup();
@@ -658,11 +670,13 @@ private:
CharStringMap scriptMap,
CharStringMap territoryMap,
CharStringMap variantMap,
+ CharStringMap subdivisionMap,
CharString* strings)
: language(std::move(languageMap)),
script(std::move(scriptMap)),
territory(std::move(territoryMap)),
variant(std::move(variantMap)),
+ subdivision(std::move(subdivisionMap)),
strings(strings) {
}
@@ -676,6 +690,7 @@ private:
CharStringMap script;
CharStringMap territory;
CharStringMap variant;
+ CharStringMap subdivision;
CharString* strings;
friend class AliasDataBuilder;
@@ -867,6 +882,34 @@ AliasDataBuilder::readVariantAlias(
}
/**
+ * Read the subdivisionAlias data from alias to strings+types+replacementIndexes.
+ * Allocate length items for types, to store the type field. Allocate length
+ * items for replacementIndexes, to store the index in the strings for the
+ * replacement regions.
+ */
+void
+AliasDataBuilder::readSubdivisionAlias(
+ UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length,
+ UErrorCode &status)
+{
+ return readAlias(
+ alias, strings, types, replacementIndexes, length,
+#if U_DEBUG
+ [](const char* type) {
+ U_ASSERT(uprv_strlen(type) >= 3 && uprv_strlen(type) <= 8);
+ },
+#else
+ [](const char*) {},
+#endif
+ [](const UnicodeString&) { },
+ status);
+}
+
+/**
* Initializes the alias data from the ICU resource bundles. The alias data
* contains alias of language, country, script and variants.
*
@@ -905,12 +948,14 @@ AliasDataBuilder::build(UErrorCode &status) {
ures_getByKey(metadataAlias.getAlias(), "territory", nullptr, &status));
LocalUResourceBundlePointer variantAlias(
ures_getByKey(metadataAlias.getAlias(), "variant", nullptr, &status));
+ LocalUResourceBundlePointer subdivisionAlias(
+ ures_getByKey(metadataAlias.getAlias(), "subdivision", nullptr, &status));
if (U_FAILURE(status)) {
return nullptr;
}
int32_t languagesLength = 0, scriptLength = 0, territoryLength = 0,
- variantLength = 0;
+ variantLength = 0, subdivisionLength = 0;
// Read the languageAlias into languageTypes, languageReplacementIndexes
// and strings
@@ -955,6 +1000,16 @@ AliasDataBuilder::build(UErrorCode &status) {
variantReplacementIndexes,
variantLength, status);
+ // Read the subdivisionAlias into subdivisionTypes, subdivisionReplacementIndexes
+ // and strings
+ LocalMemory<const char*> subdivisionTypes;
+ LocalMemory<int32_t> subdivisionReplacementIndexes;
+ readSubdivisionAlias(subdivisionAlias.getAlias(),
+ &strings,
+ subdivisionTypes,
+ subdivisionReplacementIndexes,
+ subdivisionLength, status);
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -994,6 +1049,14 @@ AliasDataBuilder::build(UErrorCode &status) {
status);
}
+ // Build the subdivisionMap from subdivisionTypes & subdivisionReplacementIndexes.
+ CharStringMap subdivisionMap(2, status);
+ for (int32_t i = 0; U_SUCCESS(status) && i < subdivisionLength; i++) {
+ subdivisionMap.put(subdivisionTypes[i],
+ strings.get(subdivisionReplacementIndexes[i]),
+ status);
+ }
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -1004,6 +1067,7 @@ AliasDataBuilder::build(UErrorCode &status) {
std::move(scriptMap),
std::move(territoryMap),
std::move(variantMap),
+ std::move(subdivisionMap),
strings.orphanCharStrings());
if (data == nullptr) {
@@ -1105,6 +1169,14 @@ private:
// Replace by using variantAlias.
bool replaceVariant(UErrorCode& status);
+
+ // Replace by using subdivisionAlias.
+ bool replaceSubdivision(StringPiece subdivision,
+ CharString& output, UErrorCode& status);
+
+ // Replace transformed extensions.
+ bool replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status);
};
CharString&
@@ -1294,7 +1366,6 @@ AliasReplacer::replaceLanguage(
}
}
if (replacedExtensions != nullptr) {
- // TODO(ICU-21292)
// DO NOTHING
// UTS35 does not specifiy what should we do if we have extensions in the
// replacement. Currently we know only the following 4 "BCP47 LegacyRules" have
@@ -1435,6 +1506,106 @@ AliasReplacer::replaceVariant(UErrorCode& status)
return false;
}
+bool
+AliasReplacer::replaceSubdivision(
+ StringPiece subdivision, CharString& output, UErrorCode& status)
+{
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ const char *replacement = data->subdivisionMap().get(subdivision.data());
+ if (replacement != nullptr) {
+ const char* firstSpace = uprv_strchr(replacement, ' ');
+ // Found replacement data for this subdivision.
+ size_t len = (firstSpace != nullptr) ?
+ (firstSpace - replacement) : uprv_strlen(replacement);
+ if (2 <= len && len <= 8) {
+ output.append(replacement, (int32_t)len, status);
+ if (2 == len) {
+ // Add 'zzzz' based on changes to UTS #35 for CLDR-14312.
+ output.append("zzzz", 4, status);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+AliasReplacer::replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status)
+{
+ // The content of the transformedExtensions will be modified in this
+ // function to NULL-terminating (tkey-tvalue) pairs.
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ int32_t len = transformedExtensions.length();
+ const char* str = transformedExtensions.data();
+ const char* tkey = ultag_getTKeyStart(str);
+ int32_t tlangLen = (tkey == str) ? 0 :
+ ((tkey == nullptr) ? len : static_cast<int32_t>((tkey - str - 1)));
+ CharStringByteSink sink(&output);
+ if (tlangLen > 0) {
+ Locale tlang = LocaleBuilder()
+ .setLanguageTag(StringPiece(str, tlangLen))
+ .build(status);
+ tlang.canonicalize(status);
+ tlang.toLanguageTag(sink, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ T_CString_toLowerCase(output.data());
+ }
+ if (tkey != nullptr) {
+ // We need to sort the tfields by tkey
+ UVector tfields(status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ do {
+ const char* tvalue = uprv_strchr(tkey, '-');
+ if (tvalue == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ const char* nextTKey = ultag_getTKeyStart(tvalue);
+ if (nextTKey != nullptr) {
+ *((char*)(nextTKey-1)) = '\0'; // NULL terminate tvalue
+ }
+ tfields.insertElementAt((void*)tkey, tfields.size(), status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ tkey = nextTKey;
+ } while (tkey != nullptr);
+ tfields.sort([](UElement e1, UElement e2) -> int8_t {
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
+ (const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
+ }, status);
+ for (int32_t i = 0; i < tfields.size(); i++) {
+ if (output.length() > 0) {
+ output.append('-', status);
+ }
+ const char* tfield = (const char*) tfields.elementAt(i);
+ const char* tvalue = uprv_strchr(tfield, '-');
+ // Split the "tkey-tvalue" pair string so that we can canonicalize the tvalue.
+ U_ASSERT(tvalue != nullptr);
+ *((char*)tvalue++) = '\0'; // NULL terminate tkey
+ output.append(tfield, status).append('-', status);
+ const char* bcpTValue = ulocimp_toBcpType(tfield, tvalue, nullptr, nullptr);
+ output.append((bcpTValue == nullptr) ? tvalue : bcpTValue, status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ return true;
+}
+
CharString&
AliasReplacer::outputToString(
CharString& out, UErrorCode status)
@@ -1453,8 +1624,12 @@ AliasReplacer::outputToString(
out.append(SEP_CHAR, status);
}
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
int32_t variantsStart = out.length();
for (int32_t i = 0; i < variants.size(); i++) {
@@ -1497,7 +1672,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
region = nullptr;
}
const char* variantsStr = locale.getVariant();
- const char* extensionsStr = locale_getKeywordsStart(locale.getName());
CharString variantsBuff(variantsStr, -1, status);
if (!variantsBuff.isEmpty()) {
if (U_FAILURE(status)) { return false; }
@@ -1516,8 +1690,12 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
// Sort the variants
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
// A changed count to assert when loop too many times.
@@ -1561,11 +1739,52 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
if (U_FAILURE(status)) { return false; }
// Nothing changed and we know the order of the vaiants are not change
// because we have no variant or only one.
- if (changed == 0 && variants.size() <= 1) {
+ const char* extensionsStr = locale_getKeywordsStart(locale.getName());
+ if (changed == 0 && variants.size() <= 1 && extensionsStr == nullptr) {
return false;
}
outputToString(out, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
if (extensionsStr != nullptr) {
+ changed = 0;
+ Locale temp(locale);
+ LocalPointer<icu::StringEnumeration> iter(locale.createKeywords(status));
+ if (U_SUCCESS(status) && !iter.isNull()) {
+ const char* key;
+ while ((key = iter->next(nullptr, status)) != nullptr) {
+ if (uprv_strcmp("sd", key) == 0 || uprv_strcmp("rg", key) == 0 ||
+ uprv_strcmp("t", key) == 0) {
+ CharString value;
+ CharStringByteSink valueSink(&value);
+ locale.getKeywordValue(key, valueSink, status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ CharString replacement;
+ if (uprv_strlen(key) == 2) {
+ if (replaceSubdivision(value.toStringPiece(), replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ } else {
+ U_ASSERT(uprv_strcmp(key, "t") == 0);
+ if (replaceTransformedExtensions(value, replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ }
+ }
+ }
+ if (changed != 0) {
+ extensionsStr = locale_getKeywordsStart(temp.getName());
+ }
out.append(extensionsStr, status);
}
if (U_FAILURE(status)) {
@@ -1573,8 +1792,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
}
// If the tag is not changed, return.
if (uprv_strcmp(out.data(), locale.getName()) == 0) {
- U_ASSERT(changed == 0);
- U_ASSERT(variants.size() > 1);
out.clear();
return false;
}
@@ -1636,7 +1853,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
{
fIsBogus = FALSE;
/* Free our current storage */
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -1672,6 +1889,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
+ U_ASSERT(baseName == nullptr);
/*Go to heap for the fullName if necessary*/
fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
if(fullName == 0) {
@@ -1825,7 +2043,7 @@ Locale::hashCode() const
void
Locale::setToBogus() {
/* Free our current storage */
- if(baseName != fullName) {
+ if((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp
index a031bfa587..aa592e6ea8 100644
--- a/thirdparty/icu4c/common/loclikelysubtags.cpp
+++ b/thirdparty/icu4c/common/loclikelysubtags.cpp
@@ -320,7 +320,8 @@ XLikelySubtags::~XLikelySubtags() {
LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const {
const char *name = locale.getName();
if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
- // Private use language tag x-subtag-subtag...
+ // Private use language tag x-subtag-subtag... which CLDR changes to
+ // und-x-subtag-subtag...
return LSR(name, "", "", LSR::EXPLICIT_LSR);
}
return makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(),
diff --git a/thirdparty/icu4c/common/norm2allmodes.h b/thirdparty/icu4c/common/norm2allmodes.h
index e8bd52c6ae..584835da57 100644
--- a/thirdparty/icu4c/common/norm2allmodes.h
+++ b/thirdparty/icu4c/common/norm2allmodes.h
@@ -38,7 +38,7 @@ public:
virtual UnicodeString &
normalize(const UnicodeString &src,
UnicodeString &dest,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
dest.setToBogus();
return dest;
@@ -64,13 +64,13 @@ public:
virtual UnicodeString &
normalizeSecondAndAppend(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, true, errorCode);
}
virtual UnicodeString &
append(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, false, errorCode);
}
UnicodeString &
@@ -107,7 +107,7 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0;
virtual UBool
- getDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[4];
int32_t length;
const UChar *d=impl.getDecomposition(c, buffer, length);
@@ -122,7 +122,7 @@ public:
return true;
}
virtual UBool
- getRawDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getRawDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[30];
int32_t length;
const UChar *d=impl.getRawDecomposition(c, buffer, length);
@@ -137,18 +137,18 @@ public:
return true;
}
virtual UChar32
- composePair(UChar32 a, UChar32 b) const {
+ composePair(UChar32 a, UChar32 b) const U_OVERRIDE {
return impl.composePair(a, b);
}
virtual uint8_t
- getCombiningClass(UChar32 c) const {
+ getCombiningClass(UChar32 c) const U_OVERRIDE {
return impl.getCC(impl.getNorm16(c));
}
// quick checks
virtual UBool
- isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+ isNormalized(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return false;
}
@@ -161,11 +161,11 @@ public:
return sLimit==spanQuickCheckYes(sArray, sLimit, errorCode);
}
virtual UNormalizationCheckResult
- quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+ quickCheck(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
return Normalizer2WithImpl::isNormalized(s, errorCode) ? UNORM_YES : UNORM_NO;
}
virtual int32_t
- spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return 0;
}
@@ -194,27 +194,57 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decompose(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decomposeAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
+
+ void
+ normalizeUTF8(uint32_t options, StringPiece src, ByteSink &sink,
+ Edits *edits, UErrorCode &errorCode) const U_OVERRIDE {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) {
+ edits->reset();
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(src.data());
+ impl.decomposeUTF8(options, s, s + src.length(), &sink, edits, errorCode);
+ sink.Flush();
+ }
+ virtual UBool
+ isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) const U_OVERRIDE {
+ if(U_FAILURE(errorCode)) {
+ return false;
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(sp.data());
+ const uint8_t *sLimit = s + sp.length();
+ return sLimit == impl.decomposeUTF8(0, s, sLimit, nullptr, nullptr, errorCode);
+ }
+
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.decompose(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const {
+ virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const U_OVERRIDE {
return impl.isDecompYes(impl.getNorm16(c)) ? UNORM_YES : UNORM_NO;
}
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasDecompBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasDecompBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isDecompInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isDecompInert(c);
+ }
};
class ComposeNormalizer2 : public Normalizer2WithImpl {
@@ -321,24 +351,30 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCD(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCDAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.makeFCD(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasFCDBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasFCDBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isFCDInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isFCDInert(c);
+ }
};
struct Norm2AllModes : public UMemory {
diff --git a/thirdparty/icu4c/common/normalizer2impl.cpp b/thirdparty/icu4c/common/normalizer2impl.cpp
index cbf6b4d980..c0ad5c69f3 100644
--- a/thirdparty/icu4c/common/normalizer2impl.cpp
+++ b/thirdparty/icu4c/common/normalizer2impl.cpp
@@ -731,9 +731,131 @@ UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
return buffer.append((const UChar *)mapping+1, length, TRUE, leadCC, trailCC, errorCode);
}
+// Dual functionality:
+// sink != nullptr: normalize
+// sink == nullptr: isNormalized/spanQuickCheckYes
+const uint8_t *
+Normalizer2Impl::decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const {
+ U_ASSERT(limit != nullptr);
+ UnicodeString s16;
+ uint8_t minNoLead = leadByteForCP(minDecompNoCP);
+
+ const uint8_t *prevBoundary = src;
+ // only for quick check
+ uint8_t prevCC = 0;
+
+ for (;;) {
+ // Fast path: Scan over a sequence of characters below the minimum "no" code point,
+ // or with (decompYes && ccc==0) properties.
+ const uint8_t *fastStart = src;
+ const uint8_t *prevSrc;
+ uint16_t norm16 = 0;
+
+ for (;;) {
+ if (src == limit) {
+ if (prevBoundary != limit && sink != nullptr) {
+ ByteSinkUtil::appendUnchanged(prevBoundary, limit,
+ *sink, options, edits, errorCode);
+ }
+ return src;
+ }
+ if (*src < minNoLead) {
+ ++src;
+ } else {
+ prevSrc = src;
+ UCPTRIE_FAST_U8_NEXT(normTrie, UCPTRIE_16, src, limit, norm16);
+ if (!isMostDecompYesAndZeroCC(norm16)) {
+ break;
+ }
+ }
+ }
+ // isMostDecompYesAndZeroCC(norm16) is false, that is, norm16>=minYesNo,
+ // and the current character at [prevSrc..src[ is not a common case with cc=0
+ // (MIN_NORMAL_MAYBE_YES or JAMO_VT).
+ // It could still be a maybeYes with cc=0.
+ if (prevSrc != fastStart) {
+ // The fast path looped over yes/0 characters before the current one.
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ prevCC = 0;
+ }
+
+ // Medium-fast path: Quick check.
+ if (isMaybeOrNonZeroCC(norm16)) {
+ // Does not decompose.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (prevCC <= cc || cc == 0) {
+ prevCC = cc;
+ if (cc <= 1) {
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = src;
+ }
+ continue;
+ }
+ }
+ if (sink == nullptr) {
+ return prevBoundary; // quick check: "no" or cc out of order
+ }
+
+ // Slow path
+ // Decompose up to and including the current character.
+ if (prevBoundary != prevSrc && norm16HasDecompBoundaryBefore(norm16)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ }
+ ReorderingBuffer buffer(*this, s16, errorCode);
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ decomposeShort(prevBoundary, src, STOP_AT_LIMIT, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ // Decompose until the next boundary.
+ if (buffer.getLastCC() > 1) {
+ src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ }
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals()
+ errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+ break;
+ }
+ // We already know there was a change if the original character decomposed;
+ // otherwise compare.
+ if (isMaybeOrNonZeroCC(norm16) && buffer.equals(prevBoundary, src)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ } else {
+ if (!ByteSinkUtil::appendChange(prevBoundary, src, buffer.getStart(), buffer.length(),
+ *sink, edits, errorCode)) {
+ break;
+ }
+ }
+ prevBoundary = src;
+ prevCC = 0;
+ }
+ return src;
+}
+
const uint8_t *
Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) {
return nullptr;
@@ -746,21 +868,28 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
UChar32 c = U_SENTINEL;
if (norm16 >= limitNoNo) {
if (isMaybeOrNonZeroCC(norm16)) {
- // No boundaries around this character.
+ // No comp boundaries around this character.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (cc == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
c = codePointFromValidUTF8(prevSrc, src);
- if (!buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode)) {
+ if (!buffer.append(c, cc, errorCode)) {
return nullptr;
}
+ if (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1) {
+ return src;
+ }
continue;
}
// Maps to an isCompYesAndZeroCC.
- if (stopAtCompBoundary) {
+ if (stopAt != STOP_AT_LIMIT) {
return prevSrc;
}
c = codePointFromValidUTF8(prevSrc, src);
c = mapAlgorithmic(c, norm16);
norm16 = getRawNorm16(c);
- } else if (stopAtCompBoundary && norm16 < minNoNoCompNoMaybeCC) {
+ } else if (stopAt != STOP_AT_LIMIT && norm16 < minNoNoCompNoMaybeCC) {
return prevSrc;
}
// norm16!=INERT guarantees that [prevSrc, src[ is valid UTF-8.
@@ -768,7 +897,8 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
// its norm16==INERT is normalization-inert,
// so it gets copied unchanged in the fast path,
// and we stop the slow path where invalid UTF-8 begins.
- U_ASSERT(norm16 != INERT);
+ // c >= 0 is the result of an algorithmic mapping.
+ U_ASSERT(c >= 0 || norm16 != INERT);
if (norm16 < minYesNo) {
if (c < 0) {
c = codePointFromValidUTF8(prevSrc, src);
@@ -798,11 +928,15 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
} else {
leadCC = 0;
}
+ if (leadCC == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
if (!buffer.append((const char16_t *)mapping+1, length, TRUE, leadCC, trailCC, errorCode)) {
return nullptr;
}
}
- if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) {
+ if ((stopAt == STOP_AT_COMP_BOUNDARY && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) ||
+ (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1)) {
return src;
}
}
@@ -1954,10 +2088,10 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
break;
}
// We know there is not a boundary here.
- decomposeShort(prevSrc, src, FALSE /* !stopAtCompBoundary */, onlyContiguous,
+ decomposeShort(prevSrc, src, STOP_AT_LIMIT, onlyContiguous,
buffer, errorCode);
// Decompose until the next boundary.
- src = decomposeShort(src, limit, TRUE /* stopAtCompBoundary */, onlyContiguous,
+ src = decomposeShort(src, limit, STOP_AT_COMP_BOUNDARY, onlyContiguous,
buffer, errorCode);
if (U_FAILURE(errorCode)) {
break;
diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h
index 4218a30a34..bdb6767a92 100644
--- a/thirdparty/icu4c/common/normalizer2impl.h
+++ b/thirdparty/icu4c/common/normalizer2impl.h
@@ -491,6 +491,12 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer,
UErrorCode &errorCode) const;
+
+ /** sink==nullptr: isNormalized()/spanQuickCheckYes() */
+ const uint8_t *decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const;
+
UBool compose(const UChar *src, const UChar *limit,
UBool onlyContiguous,
UBool doCompose,
@@ -649,6 +655,9 @@ private:
UChar32 minNeedDataCP,
ReorderingBuffer *buffer,
UErrorCode &errorCode) const;
+
+ enum StopAt { STOP_AT_LIMIT, STOP_AT_DECOMP_BOUNDARY, STOP_AT_COMP_BOUNDARY };
+
const UChar *decomposeShort(const UChar *src, const UChar *limit,
UBool stopAtCompBoundary, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
@@ -656,7 +665,7 @@ private:
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
const uint8_t *decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
static int32_t combine(const uint16_t *list, UChar32 trail);
diff --git a/thirdparty/icu4c/common/pluralmap.h b/thirdparty/icu4c/common/pluralmap.h
index d898ac4671..2a14a07af1 100644
--- a/thirdparty/icu4c/common/pluralmap.h
+++ b/thirdparty/icu4c/common/pluralmap.h
@@ -24,7 +24,7 @@ class U_COMMON_API PluralMapBase : public UMemory {
public:
/**
* The names of all the plural categories. NONE is not an actual plural
- * category, but rather represents the absense of a plural category.
+ * category, but rather represents the absence of a plural category.
*/
enum Category {
NONE = -1,
diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp
index 3ed6a05d22..ffcbbcce59 100644
--- a/thirdparty/icu4c/common/putil.cpp
+++ b/thirdparty/icu4c/common/putil.cpp
@@ -1139,7 +1139,7 @@ uprv_tzname(int n)
#endif
if (tzid != NULL && isValidOlsonID(tzid)
#if U_PLATFORM == U_PF_SOLARIS
- /* When TZ equals localtime on Solaris, check the /etc/localtime file. */
+ /* Don't misinterpret TZ "localtime" on Solaris as a time zone name. */
&& uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
#endif
) {
@@ -1361,7 +1361,7 @@ uprv_pathIsAbsolute(const char *path)
/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
(needed for some Darwin ICU build environments) */
-#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR
+#if U_PLATFORM_IS_DARWIN_BASED && defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
# define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
# endif
diff --git a/thirdparty/icu4c/common/putilimp.h b/thirdparty/icu4c/common/putilimp.h
index a325c6c359..5b95a68418 100644
--- a/thirdparty/icu4c/common/putilimp.h
+++ b/thirdparty/icu4c/common/putilimp.h
@@ -527,7 +527,7 @@ U_CAPI void * U_EXPORT2 uprv_maximumPtr(void *base);
* on the destination pointer and capacity cannot overflow.
*
* The pinned capacity must fulfill the following conditions (for positive capacities):
- * - dest + capacity is a valid pointer according to the machine arcitecture (AS/400, 64-bit, etc.)
+ * - dest + capacity is a valid pointer according to the machine architecture (AS/400, 64-bit, etc.)
* - (dest + capacity) >= dest
* - The size (in bytes) of T[capacity] does not exceed 0x7fffffff
*
diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp
index 9b7e70c3cf..b821ca4463 100644
--- a/thirdparty/icu4c/common/rbbi.cpp
+++ b/thirdparty/icu4c/common/rbbi.cpp
@@ -812,7 +812,7 @@ int32_t RuleBasedBreakIterator::handleNext() {
}
#endif
- // handleNext alway sets the break tag value.
+ // handleNext always sets the break tag value.
// Set the default for it.
fRuleStatusIndex = 0;
diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp
index 63ff3001c7..44f19d8697 100644
--- a/thirdparty/icu4c/common/rbbi_cache.cpp
+++ b/thirdparty/icu4c/common/rbbi_cache.cpp
@@ -258,7 +258,7 @@ void RuleBasedBreakIterator::BreakCache::preceding(int32_t startPos, UErrorCode
previous(status);
} else {
// seek() leaves the BreakCache positioned at the preceding boundary
- // if the requested position is between two bounaries.
+ // if the requested position is between two boundaries.
// current() pushes the BreakCache position out to the BreakIterator itself.
U_ASSERT(startPos > fTextIdx);
current();
diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp
index 9c406af671..45911b1cfe 100644
--- a/thirdparty/icu4c/common/rbbiscan.cpp
+++ b/thirdparty/icu4c/common/rbbiscan.cpp
@@ -284,7 +284,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doEndAssign:
{
- // We have reached the end of an assignement statement.
+ // We have reached the end of an assignment statement.
// Current scan char is the ';' that terminates the assignment.
// Terminate expression, leaves expression parse tree rooted in TOS node.
@@ -856,6 +856,10 @@ UChar32 RBBIRuleScanner::nextCharLL() {
return (UChar32)-1;
}
ch = fRB->fRules.char32At(fNextIndex);
+ if (U_IS_SURROGATE(ch)) {
+ error(U_ILLEGAL_CHAR_FOUND);
+ return U_SENTINEL;
+ }
fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1);
if (ch == chCR ||
diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp
index 70e260fc08..dd76337bc6 100644
--- a/thirdparty/icu4c/common/rbbitblb.cpp
+++ b/thirdparty/icu4c/common/rbbitblb.cpp
@@ -151,7 +151,7 @@ void RBBITableBuilder::buildForwardTable() {
//
// calculate the functions nullable, firstpos, lastpos and followpos on
// nodes in the parse tree.
- // See the alogrithm description in Aho.
+ // See the algorithm description in Aho.
// Understanding how this works by looking at the code alone will be
// nearly impossible.
//
diff --git a/thirdparty/icu4c/common/resource.h b/thirdparty/icu4c/common/resource.h
index 3795694412..48f5b9fa6e 100644
--- a/thirdparty/icu4c/common/resource.h
+++ b/thirdparty/icu4c/common/resource.h
@@ -274,8 +274,10 @@ public:
*
* @param key The key string of the enumeration-start resource.
* Empty if the enumeration starts at the top level of the bundle.
- * @param value Call getArray() or getTable() as appropriate.
- * Then reuse for output values from Array and Table getters.
+ * @param value Call getArray() or getTable() as appropriate. Then reuse for
+ * output values from Array and Table getters. Note: ResourceTable and
+ * ResourceArray instances must outlive the ResourceValue instance for
+ * ResourceTracer to be happy.
* @param noFallback true if the bundle has no parent;
* that is, its top-level table has the nofallback attribute,
* or it is the root bundle of a locale tree.
diff --git a/thirdparty/icu4c/common/restrace.cpp b/thirdparty/icu4c/common/restrace.cpp
index 5c6498850e..1f83372d68 100644
--- a/thirdparty/icu4c/common/restrace.cpp
+++ b/thirdparty/icu4c/common/restrace.cpp
@@ -54,6 +54,9 @@ void ResourceTracer::traceOpen() const {
CharString& ResourceTracer::getFilePath(CharString& output, UErrorCode& status) const {
if (fResB) {
+ // Note: if you get a segfault around here, check that ResourceTable and
+ // ResourceArray instances outlive ResourceValue instances referring to
+ // their contents:
output.append(fResB->fData->fPath, status);
output.append('/', status);
output.append(fResB->fData->fName, status);
diff --git a/thirdparty/icu4c/common/servnotf.h b/thirdparty/icu4c/common/servnotf.h
index 305570c1e6..73ce38c772 100644
--- a/thirdparty/icu4c/common/servnotf.h
+++ b/thirdparty/icu4c/common/servnotf.h
@@ -82,7 +82,7 @@ public:
/**
* Add a listener to be notified when notifyChanged is called.
* The listener must not be null. AcceptsListener must return
- * true for the listener. Attempts to concurrently
+ * true for the listener. Attempts to concurrently
* register the identical listener more than once will be
* silently ignored.
*/
@@ -90,7 +90,7 @@ public:
/**
* Stop notifying this listener. The listener must
- * not be null. Attemps to remove a listener that is
+ * not be null. Attempts to remove a listener that is
* not registered will be silently ignored.
*/
virtual void removeListener(const EventListener* l, UErrorCode& status);
diff --git a/thirdparty/icu4c/common/ubrk.cpp b/thirdparty/icu4c/common/ubrk.cpp
index f8bdf5a6b6..bb5bdd1b50 100644
--- a/thirdparty/icu4c/common/ubrk.cpp
+++ b/thirdparty/icu4c/common/ubrk.cpp
@@ -174,6 +174,18 @@ ubrk_safeClone(
return (UBreakIterator *)newBI;
}
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ BreakIterator *newBI = ((BreakIterator *)bi)->clone();
+ if (newBI == nullptr) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return (UBreakIterator *)newBI;
+}
U_CAPI void U_EXPORT2
diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp
index 2b142f5bc2..4f4c274d60 100644
--- a/thirdparty/icu4c/common/ucase.cpp
+++ b/thirdparty/icu4c/common/ucase.cpp
@@ -681,7 +681,7 @@ ucase_isCaseSensitive(UChar32 c) {
* - In [CoreProps], C has one of the properties Uppercase, or Lowercase
* - Given D = NFD(C), then it is not the case that:
* D = UCD_lower(D) = UCD_upper(D) = UCD_title(D)
- * (This third criterium does not add any characters to the list
+ * (This third criterion does not add any characters to the list
* for Unicode 3.2. Ignored.)
*
* D2. A character C is defined to be case-ignorable
diff --git a/thirdparty/icu4c/common/uchar.cpp b/thirdparty/icu4c/common/uchar.cpp
index eb14e4c75d..61e9c3d900 100644
--- a/thirdparty/icu4c/common/uchar.cpp
+++ b/thirdparty/icu4c/common/uchar.cpp
@@ -194,7 +194,7 @@ u_isISOControl(UChar32 c) {
/* Some control characters that are used as space. */
#define IS_THAT_CONTROL_SPACE(c) \
- (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
+ (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==0x85))
/* Java has decided that U+0085 New Line is not whitespace any more. */
#define IS_THAT_ASCII_CONTROL_SPACE(c) \
@@ -677,14 +677,14 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
sa->add(sa->set, CR+1); /* range TAB..CR */
sa->add(sa->set, 0x1c);
sa->add(sa->set, 0x1f+1);
- USET_ADD_CP_AND_NEXT(sa, NL);
+ USET_ADD_CP_AND_NEXT(sa, 0x85); // NEXT LINE (NEL)
/* add for u_isIDIgnorable() what was not added above */
- sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */
+ sa->add(sa->set, 0x7f); /* range DEL..NBSP-1, NBSP added below */
sa->add(sa->set, HAIRSP);
sa->add(sa->set, RLM+1);
- sa->add(sa->set, INHSWAP);
- sa->add(sa->set, NOMDIG+1);
+ sa->add(sa->set, 0x206a); // INHIBIT SYMMETRIC SWAPPING
+ sa->add(sa->set, 0x206f+1); // NOMINAL DIGIT SHAPES
USET_ADD_CP_AND_NEXT(sa, ZWNBSP);
/* add no-break spaces for u_isWhitespace() what was not added above */
@@ -693,23 +693,25 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
USET_ADD_CP_AND_NEXT(sa, NNBSP);
/* add for u_digit() */
- sa->add(sa->set, U_a);
- sa->add(sa->set, U_z+1);
- sa->add(sa->set, U_A);
- sa->add(sa->set, U_Z+1);
- sa->add(sa->set, U_FW_a);
- sa->add(sa->set, U_FW_z+1);
- sa->add(sa->set, U_FW_A);
- sa->add(sa->set, U_FW_Z+1);
+ sa->add(sa->set, u'a');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
+ // fullwidth
+ sa->add(sa->set, u'a');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
/* add for u_isxdigit() */
- sa->add(sa->set, U_f+1);
- sa->add(sa->set, U_F+1);
- sa->add(sa->set, U_FW_f+1);
- sa->add(sa->set, U_FW_F+1);
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
+ // fullwidth
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
/* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */
- sa->add(sa->set, WJ); /* range WJ..NOMDIG */
+ sa->add(sa->set, 0x2060); /* range 2060..206f */
sa->add(sa->set, 0xfff0);
sa->add(sa->set, 0xfffb+1);
sa->add(sa->set, 0xe0000);
diff --git a/thirdparty/icu4c/common/ucnv2022.cpp b/thirdparty/icu4c/common/ucnv2022.cpp
index 169ad4c526..1726440b94 100644
--- a/thirdparty/icu4c/common/ucnv2022.cpp
+++ b/thirdparty/icu4c/common/ucnv2022.cpp
@@ -820,7 +820,7 @@ getKey_2022(char c,int32_t* key,int32_t* offset){
return INVALID_2022;
}
-/*runs through a state machine to determine the escape sequence - codepage correspondance
+/*runs through a state machine to determine the escape sequence - codepage correspondence
*/
static void
changeState_2022(UConverter* _this,
@@ -1424,7 +1424,7 @@ toUnicodeCallback(UConverter *cnv,
* KSC5601 : alias to ibm-949 mapping table
* GB2312 : alias to ibm-1386 mapping table
* ISO-8859-1 : Algorithmic implemented as LATIN1 case
-* ISO-8859-7 : alisas to ibm-9409 mapping table
+* ISO-8859-7 : alias to ibm-9409 mapping table
*/
/* preference order of JP charsets */
@@ -2324,7 +2324,7 @@ endloop:
/***************************************************************
* Rules for ISO-2022-KR encoding
* i) The KSC5601 designator sequence should appear only once in a file,
-* at the begining of a line before any KSC5601 characters. This usually
+* at the beginning of a line before any KSC5601 characters. This usually
* means that it appears by itself on the first line of the file
* ii) There are only 2 shifting sequences SO to shift into double byte mode
* and SI to shift into single byte mode
diff --git a/thirdparty/icu4c/common/ucnv_bld.cpp b/thirdparty/icu4c/common/ucnv_bld.cpp
index 0e198892f1..d08eec7369 100644
--- a/thirdparty/icu4c/common/ucnv_bld.cpp
+++ b/thirdparty/icu4c/common/ucnv_bld.cpp
@@ -427,7 +427,7 @@ getAlgorithmicTypeFromName(const char *realName)
#define UCNV_CACHE_LOAD_FACTOR 2
/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
-/* Will always be called with the cnvCacheMutex alrady being held */
+/* Will always be called with the cnvCacheMutex already being held */
/* by the calling function. */
/* Stores the shared data in the SHARED_DATA_HASHTABLE
* @param data The shared data
diff --git a/thirdparty/icu4c/common/ucnv_err.cpp b/thirdparty/icu4c/common/ucnv_err.cpp
index 6b738face5..e1f2b934aa 100644
--- a/thirdparty/icu4c/common/ucnv_err.cpp
+++ b/thirdparty/icu4c/common/ucnv_err.cpp
@@ -321,7 +321,7 @@ UCNV_FROM_U_CALLBACK_ESCAPE (
case UCNV_PRV_ESCAPE_CSS2:
valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT; /* adding \ */
valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0);
- /* Always add space character, becase the next character might be whitespace,
+ /* Always add space character, because the next character might be whitespace,
which would erroneously be considered the termination of the escape sequence. */
valueString[valueStringLength++] = (UChar) UNICODE_SPACE_CODEPOINT;
break;
diff --git a/thirdparty/icu4c/common/ucnv_lmb.cpp b/thirdparty/icu4c/common/ucnv_lmb.cpp
index 168392837b..41317d1cc0 100644
--- a/thirdparty/icu4c/common/ucnv_lmb.cpp
+++ b/thirdparty/icu4c/common/ucnv_lmb.cpp
@@ -81,7 +81,7 @@
[G] D1 [D2]
That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2
- data bytes. The maximum size of a LMBCS chjaracter is 3 bytes:
+ data bytes. The maximum size of a LMBCS character is 3 bytes:
*/
#define ULMBCS_CHARSIZE_MAX 3
/*
@@ -164,7 +164,7 @@ beginning of internal 'system' range names: */
/* Then we needed a place to put all the other ansi control characters
that must be moved to different values because LMBCS reserves those
values for other purposes. To represent the control characters, we start
-with a first byte of 0xF & add the control chaarcter value as the
+with a first byte of 0xF & add the control character value as the
second byte */
#define ULMBCS_GRP_CTRL 0x0F
diff --git a/thirdparty/icu4c/common/ucnv_u7.cpp b/thirdparty/icu4c/common/ucnv_u7.cpp
index 87ba8cf37e..de9f3f42ec 100644
--- a/thirdparty/icu4c/common/ucnv_u7.cpp
+++ b/thirdparty/icu4c/common/ucnv_u7.cpp
@@ -814,7 +814,7 @@ const UConverterSharedData _UTF7Data=
* the use of "~" in some servers as a home directory indicator.
*
* 5) UTF-7 permits multiple alternate forms to represent the same
- * string; in particular, printable US-ASCII chararacters can be
+ * string; in particular, printable US-ASCII characters can be
* represented in encoded form.
*
* In modified UTF-7, printable US-ASCII characters except for "&"
diff --git a/thirdparty/icu4c/common/ucnvisci.cpp b/thirdparty/icu4c/common/ucnvisci.cpp
index 44a7c05a3c..ffb8c7ac3e 100644
--- a/thirdparty/icu4c/common/ucnvisci.cpp
+++ b/thirdparty/icu4c/common/ucnvisci.cpp
@@ -992,7 +992,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
if (converterData->currentDeltaFromUnicode == PNJ_DELTA) {
if (sourceChar == PNJ_TIPPI) {
- /* Make sure Tippi is converterd to Bindi. */
+ /* Make sure Tippi is converted to Bindi. */
sourceChar = PNJ_BINDI;
} else if (sourceChar == PNJ_ADHAK) {
/* This is for consonant cluster handling. */
@@ -1147,7 +1147,7 @@ static const uint16_t lookupTable[][2]={
/* is the code point valid in current script? */ \
if(sourceChar> ASCII_END && \
(validityTable[(targetUniChar & 0x7F)] & data->currentMaskToUnicode)==0){ \
- /* Vocallic RR is assigne in ISCII Telugu and Unicode */ \
+ /* Vocallic RR is assigned in ISCII Telugu and Unicode */ \
if(data->currentDeltaToUnicode!=(TELUGU_DELTA) || \
targetUniChar!=VOCALLIC_RR){ \
targetUniChar=missingCharMarker; \
@@ -1272,7 +1272,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
goto CALLBACK;
} else if (*contextCharToUnicode==ISCII_INV) {
if (sourceChar==ISCII_HALANT) {
- targetUniChar = 0x0020; /* replace with space accoding to Indic FAQ */
+ targetUniChar = 0x0020; /* replace with space according to Indic FAQ */
} else {
targetUniChar = ZWJ;
}
diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp
index 0e14cddcff..20bbd51488 100644
--- a/thirdparty/icu4c/common/ucurr.cpp
+++ b/thirdparty/icu4c/common/ucurr.cpp
@@ -844,7 +844,7 @@ typedef struct {
#endif
-// Comparason function used in quick sort.
+// Comparison function used in quick sort.
static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
@@ -1530,7 +1530,7 @@ uprv_parseCurrency(const char* locale,
int32_t max = 0;
int32_t matchIndex = -1;
- // case in-sensitive comparision against currency names
+ // case in-sensitive comparison against currency names
searchCurrencyName(currencyNames, total_currency_name_count,
upperText, textLen, partialMatchLen, &max, &matchIndex);
diff --git a/thirdparty/icu4c/common/uhash.cpp b/thirdparty/icu4c/common/uhash.cpp
index 86311ceb0b..67c7c36354 100644
--- a/thirdparty/icu4c/common/uhash.cpp
+++ b/thirdparty/icu4c/common/uhash.cpp
@@ -133,8 +133,10 @@ static const float RESIZE_POLICY_RATIO_TABLE[6] = {
* or a pointer. If a hint bit is zero, then the associated
* token is assumed to be an integer.
*/
+#define HINT_BOTH_INTEGERS (0)
#define HINT_KEY_POINTER (1)
#define HINT_VALUE_POINTER (2)
+#define HINT_ALLOW_ZERO (4)
/********************************************************************
* PRIVATE Implementation
@@ -479,8 +481,9 @@ _uhash_put(UHashtable *hash,
goto err;
}
U_ASSERT(hash != NULL);
- /* Cannot always check pointer here or iSeries sees NULL every time. */
- if ((hint & HINT_VALUE_POINTER) && value.pointer == NULL) {
+ if ((hint & HINT_VALUE_POINTER) ?
+ value.pointer == NULL :
+ value.integer == 0 && (hint & HINT_ALLOW_ZERO) == 0) {
/* Disallow storage of NULL values, since NULL is returned by
* get() to indicate an absent key. Storing NULL == removing.
*/
@@ -687,6 +690,28 @@ uhash_igeti(const UHashtable *hash,
return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer;
}
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
U_CAPI void* U_EXPORT2
uhash_put(UHashtable *hash,
void* key,
@@ -736,7 +761,34 @@ uhash_iputi(UHashtable *hash,
keyholder.integer = key;
valueholder.integer = value;
return _uhash_put(hash, keyholder, valueholder,
- 0, /* neither is a ptr */
+ HINT_BOTH_INTEGERS,
+ status).integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.pointer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_KEY_POINTER | HINT_ALLOW_ZERO,
+ status).integer;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.integer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_BOTH_INTEGERS | HINT_ALLOW_ZERO,
status).integer;
}
@@ -785,6 +837,29 @@ uhash_removeAll(UHashtable *hash) {
U_ASSERT(hash->count == 0);
}
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
U_CAPI const UHashElement* U_EXPORT2
uhash_find(const UHashtable *hash, const void* key) {
UHashTok keyholder;
diff --git a/thirdparty/icu4c/common/uhash.h b/thirdparty/icu4c/common/uhash.h
index b59d2711bb..af75999860 100644
--- a/thirdparty/icu4c/common/uhash.h
+++ b/thirdparty/icu4c/common/uhash.h
@@ -23,7 +23,7 @@
/**
* UHashtable stores key-value pairs and does moderately fast lookup
* based on keys. It provides a good tradeoff between access time and
- * storage space. As elements are added to it, it grows to accomodate
+ * storage space. As elements are added to it, it grows to accommodate
* them. By default, the table never shrinks, even if all elements
* are removed from it.
*
@@ -54,6 +54,13 @@
* uhash_remove() on that key. This keeps uhash_get(), uhash_count(),
* and uhash_nextElement() consistent with one another.
*
+ * Keys and values can be integers.
+ * Functions that work with an integer key have an "i" prefix.
+ * Functions that work with an integer value have an "i" suffix.
+ * As with putting a NULL value pointer, putting a zero value integer removes the item.
+ * Except, there are pairs of functions that allow setting zero values
+ * and fetching (value, found) pairs.
+ *
* To see everything in a hashtable, use uhash_nextElement() to
* iterate through its contents. Each call to this function returns a
* UHashElement pointer. A hash element contains a key, value, and
@@ -406,6 +413,44 @@ uhash_iputi(UHashtable *hash,
UErrorCode *status);
/**
+ * Put a (key=pointer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_getiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
+ * Put a (key=integer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_igetiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
* Retrieve a pointer value from a UHashtable using a pointer key,
* as previously stored by uhash_put().
* @param hash The target UHashtable.
@@ -449,6 +494,34 @@ uhash_igeti(const UHashtable *hash,
int32_t key);
/**
+ * Retrieves an integer value from a UHashtable using a pointer key,
+ * as previously stored by uhash_putiAllowZero() or uhash_puti().
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found);
+
+/**
+ * Retrieves an integer value from a UHashtable using an integer key,
+ * as previously stored by uhash_iputiAllowZero() or uhash_iputi().
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found);
+
+/**
* Remove an item from a UHashtable stored by uhash_put().
* @param hash The target UHashtable.
* @param key A key stored in a hashtable
@@ -496,6 +569,26 @@ U_CAPI void U_EXPORT2
uhash_removeAll(UHashtable *hash);
/**
+ * Returns true if the UHashtable contains an item with this pointer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key);
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key);
+
+/**
* Locate an element of a UHashtable. The caller must not modify the
* returned object. The primary use of this function is to obtain the
* stored key when it may not be identical to the search key. For
diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp
index ebfbb50650..d96e79b8fd 100644
--- a/thirdparty/icu4c/common/uloc.cpp
+++ b/thirdparty/icu4c/common/uloc.cpp
@@ -143,7 +143,7 @@ static const char * const LANGUAGES[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mg", "mga",
"mgh", "mgo", "mh", "mi", "mic", "min", "mis", "mk",
- "ml", "mn", "mnc", "mni", "mo",
+ "ml", "mn", "mnc", "mni",
"moh", "mos", "mr", "mrj",
"ms", "mt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"my", "mye", "myv", "mzn",
@@ -166,9 +166,9 @@ static const char * const LANGUAGES[] = {
"sl", "sli", "sly", "sm", "sma", "smj", "smn", "sms",
"sn", "snk", "so", "sog", "sq", "sr", "srn", "srr",
"ss", "ssy", "st", "stq", "su", "suk", "sus", "sux",
- "sv", "sw", "swb", "swc", "syc", "syr", "szl",
+ "sv", "sw", "swb", "syc", "syr", "szl",
"ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg",
- "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tl",
+ "th", "ti", "tig", "tiv", "tk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi",
"tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt",
"tum", "tvl", "tw", "twq", "ty", "tyv", "tzm",
@@ -181,7 +181,7 @@ static const char * const LANGUAGES[] = {
"za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu",
"zun", "zxx", "zza",
NULL,
- "in", "iw", "ji", "jw", "sh", /* obsolete language codes */
+ "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", /* obsolete language codes */
NULL
};
@@ -260,7 +260,7 @@ static const char * const LANGUAGES_3[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga",
"mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd",
- "mal", "mon", "mnc", "mni", "mol",
+ "mal", "mon", "mnc", "mni",
"moh", "mos", "mar", "mrj",
"msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"mya", "mye", "myv", "mzn",
@@ -283,9 +283,9 @@ static const char * const LANGUAGES_3[] = {
"slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms",
"sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr",
"ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux",
- "swe", "swa", "swb", "swc", "syc", "syr", "szl",
+ "swe", "swa", "swb", "syc", "syr", "szl",
"tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk",
- "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl",
+ "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi",
"tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt",
"tum", "tvl", "twi", "twq", "tah", "tyv", "tzm",
@@ -298,8 +298,8 @@ static const char * const LANGUAGES_3[] = {
"zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul",
"zun", "zxx", "zza",
NULL,
-/* "in", "iw", "ji", "jw", "sh", */
- "ind", "heb", "yid", "jaw", "srp",
+/* "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", */
+ "ind", "heb", "yid", "jaw", "mol", "srp", "swc", "tgl",
NULL
};
@@ -334,13 +334,13 @@ static const char * const COUNTRIES[] = {
"BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV",
"BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG",
"CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR",
- "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK",
- "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER",
+ "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK",
+ "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER",
"ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR",
"GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL",
"GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU",
"GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
- "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
+ "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
"IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI",
"KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
"LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU",
@@ -357,7 +357,7 @@ static const char * const COUNTRIES[] = {
"TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV",
"TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ",
"VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
- "WS", "YE", "YT", "ZA", "ZM", "ZW",
+ "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW",
NULL,
"AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR", /* obsolete country codes */
NULL
@@ -397,10 +397,10 @@ static const char * const COUNTRIES_3[] = {
"BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
/* "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", */
"CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
-/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", */
- "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
-/* "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", */
- "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
+/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", */
+ "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK",
+/* "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", */
+ "DMA", "DOM", "DZA", "XEA", "ECU", "EST", "EGY", "ESH", "ERI",
/* "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", */
"ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
/* "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", */
@@ -409,8 +409,8 @@ static const char * const COUNTRIES_3[] = {
"GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
/* "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", */
"GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
-/* "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
- "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
+/* "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
+ "XIC", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
/* "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", */
"ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
/* "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", */
@@ -443,8 +443,8 @@ static const char * const COUNTRIES_3[] = {
"TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
/* "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", */
"VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
-/* "WS", "YE", "YT", "ZA", "ZM", "ZW", */
- "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
+/* "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW", */
+ "WSM", "XXK", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
NULL,
/* "AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR" */
"ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR",
diff --git a/thirdparty/icu4c/common/uloc_keytype.cpp b/thirdparty/icu4c/common/uloc_keytype.cpp
index 019da058cf..c289ebe76f 100644
--- a/thirdparty/icu4c/common/uloc_keytype.cpp
+++ b/thirdparty/icu4c/common/uloc_keytype.cpp
@@ -271,7 +271,7 @@ initFromResourceBundle(UErrorCode& sts) {
if (U_FAILURE(sts)) {
break;
}
- // check if this is an alias of canoncal legacy type
+ // check if this is an alias of canonical legacy type
if (uprv_compareInvWithUChar(NULL, legacyTypeId, -1, to, toLen) == 0) {
const char* from = ures_getKey(typeAliasDataEntry.getAlias());
if (isTZ) {
diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp
index 7f7fd9119e..1235081bf3 100644
--- a/thirdparty/icu4c/common/uloc_tag.cpp
+++ b/thirdparty/icu4c/common/uloc_tag.cpp
@@ -129,7 +129,6 @@ static const char* const LEGACY[] = {
// Legacy tags with no preferred value in the IANA
// registry. Kept for now for the backward compatibility
// because ICU has mapped them this way.
- "cel-gaulish", "xtg-x-cel-gaulish",
"i-default", "en-x-i-default",
"i-enochian", "und-x-i-enochian",
"i-mingo", "see-x-i-mingo",
@@ -647,6 +646,22 @@ _isTKey(const char* s, int32_t len)
return FALSE;
}
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID) {
+ const char *result = localeID;
+ const char *sep;
+ while((sep = uprv_strchr(result, SEP)) != nullptr) {
+ if (_isTKey(result, static_cast<int32_t>(sep - result))) {
+ return result;
+ }
+ result = ++sep;
+ }
+ if (_isTKey(result, -1)) {
+ return result;
+ }
+ return nullptr;
+}
+
static UBool
_isTValue(const char* s, int32_t len)
{
@@ -671,9 +686,13 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len)
const int32_t kGotTKey = -1; // Got tkey, wait for tvalue. ERROR if stop here.
const int32_t kGotTValue = 6; // Got tvalue, wait for tkey, tvalue or end
+
+ if (len < 0) {
+ len = (int32_t)uprv_strlen(s);
+ }
switch (state) {
case kStart:
- if (ultag_isLanguageSubtag(s, len)) {
+ if (ultag_isLanguageSubtag(s, len) && len != 4) {
state = kGotLanguage;
return TRUE;
}
@@ -1775,11 +1794,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
return;
}
- /* Determine if variants already exists */
- if (ultag_getVariantsSize(langtag)) {
- posixVariant = TRUE;
- }
-
n = ultag_getExtensionsSize(langtag);
/* resolve locale keywords and reordering keys */
@@ -1787,6 +1801,11 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
key = ultag_getExtensionKey(langtag, i);
type = ultag_getExtensionValue(langtag, i);
if (*key == LDMLEXT) {
+ /* Determine if variants already exists */
+ if (ultag_getVariantsSize(langtag)) {
+ posixVariant = TRUE;
+ }
+
_appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status);
if (U_FAILURE(*status)) {
break;
@@ -2028,7 +2047,10 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- uprv_memcpy(tagBuf, tag, tagLen);
+
+ if (tagLen > 0) {
+ uprv_memcpy(tagBuf, tag, tagLen);
+ }
*(tagBuf + tagLen) = 0;
/* create a ULanguageTag */
@@ -2692,8 +2714,7 @@ ulocimp_toLanguageTag(const char* localeID,
if (U_SUCCESS(tmpStatus)) {
if (ultag_isPrivateuseValueSubtags(buf.data(), buf.length())) {
/* return private use only tag */
- static const char PREFIX[] = { PRIVATEUSE, SEP };
- sink.Append(PREFIX, sizeof(PREFIX));
+ sink.Append("und-x-", 6);
sink.Append(buf.data(), buf.length());
done = TRUE;
} else if (strict) {
diff --git a/thirdparty/icu4c/common/ulocimp.h b/thirdparty/icu4c/common/ulocimp.h
index 5691fe9a77..1f796aa213 100644
--- a/thirdparty/icu4c/common/ulocimp.h
+++ b/thirdparty/icu4c/common/ulocimp.h
@@ -286,6 +286,9 @@ ultag_isUnicodeLocaleType(const char* s, int32_t len);
U_CFUNC UBool
ultag_isVariantSubtags(const char* s, int32_t len);
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID);
+
U_CFUNC const char*
ulocimp_toBcpKey(const char* key);
diff --git a/thirdparty/icu4c/common/unicode/bytestream.h b/thirdparty/icu4c/common/unicode/bytestream.h
index 044f7a77e7..9735ee0bf8 100644
--- a/thirdparty/icu4c/common/unicode/bytestream.h
+++ b/thirdparty/icu4c/common/unicode/bytestream.h
@@ -71,7 +71,6 @@ public:
*/
virtual void Append(const char* bytes, int32_t n) = 0;
-#ifndef U_HIDE_DRAFT_API
/**
* Appends n bytes to this. Same as Append().
* Call AppendU8() with u8"string literals" which are const char * in C++11
@@ -81,7 +80,7 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char* bytes, int32_t n) {
Append(bytes, n);
@@ -97,13 +96,12 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char8_t* bytes, int32_t n) {
Append(reinterpret_cast<const char*>(bytes), n);
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
diff --git a/thirdparty/icu4c/common/unicode/bytestrie.h b/thirdparty/icu4c/common/unicode/bytestrie.h
index 85f802df42..271a81d1b4 100644
--- a/thirdparty/icu4c/common/unicode/bytestrie.h
+++ b/thirdparty/icu4c/common/unicode/bytestrie.h
@@ -30,6 +30,8 @@
#include "unicode/uobject.h"
#include "unicode/ustringtrie.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class ByteSink;
@@ -378,6 +380,7 @@ public:
private:
friend class BytesTrieBuilder;
+ friend class ::BytesTrieTest;
/**
* Constructs a BytesTrie reader instance.
diff --git a/thirdparty/icu4c/common/unicode/bytestriebuilder.h b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
index cae16e48b4..3cff89e443 100644
--- a/thirdparty/icu4c/common/unicode/bytestriebuilder.h
+++ b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
@@ -30,6 +30,8 @@
#include "unicode/stringpiece.h"
#include "unicode/stringtriebuilder.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class BytesTrieElement;
@@ -125,6 +127,8 @@ public:
BytesTrieBuilder &clear();
private:
+ friend class ::BytesTrieTest;
+
BytesTrieBuilder(const BytesTrieBuilder &other); // no copy constructor
BytesTrieBuilder &operator=(const BytesTrieBuilder &other); // no assignment operator
@@ -168,6 +172,7 @@ private:
virtual int32_t writeValueAndFinal(int32_t i, UBool isFinal);
virtual int32_t writeValueAndType(UBool hasValue, int32_t value, int32_t node);
virtual int32_t writeDeltaTo(int32_t jumpTarget);
+ static int32_t internalEncodeDelta(int32_t i, char intBytes[]);
CharString *strings; // Pointer not object so we need not #include internal charstr.h.
BytesTrieElement *elements;
diff --git a/thirdparty/icu4c/common/unicode/docmain.h b/thirdparty/icu4c/common/unicode/docmain.h
index edcb5d4e83..e82678c95f 100644
--- a/thirdparty/icu4c/common/unicode/docmain.h
+++ b/thirdparty/icu4c/common/unicode/docmain.h
@@ -15,7 +15,7 @@
* \file
* \brief (Non API- contains Doxygen definitions)
*
- * This file contains documentation for Doxygen and doesnot have
+ * This file contains documentation for Doxygen and does not have
* any significance with respect to C or C++ API
*/
@@ -74,7 +74,7 @@
* </tr>
* <tr>
* <td>Strings and Character Iteration</td>
- * <td>ustring.h, utf8.h, utf16.h, UText, UCharIterator</td>
+ * <td>ustring.h, utf8.h, utf16.h, icu::StringPiece, UText, UCharIterator, icu::ByteSink</td>
* <td>icu::UnicodeString, icu::CharacterIterator, icu::Appendable, icu::StringPiece,icu::ByteSink</td>
* </tr>
* <tr>
@@ -128,9 +128,9 @@
* <td>icu::Normalizer2</td>
* </tr>
* <tr>
- * <td>Calendars</td>
+ * <td>Calendars and Time Zones</td>
* <td>ucal.h</td>
- * <td>icu::Calendar</td>
+ * <td>icu::Calendar, icu::TimeZone</td>
* </tr>
* <tr>
* <td>Date and Time Formatting</td>
diff --git a/thirdparty/icu4c/common/unicode/icuplug.h b/thirdparty/icu4c/common/unicode/icuplug.h
index 52f810da57..205af360d4 100644
--- a/thirdparty/icu4c/common/unicode/icuplug.h
+++ b/thirdparty/icu4c/common/unicode/icuplug.h
@@ -117,14 +117,13 @@
/* === Basic types === */
#ifndef U_HIDE_INTERNAL_API
+struct UPlugData;
/**
* @{
- * Opaque structure passed to/from a plugin.
- * use the APIs to access it.
+ * Typedef for opaque structure passed to/from a plugin.
+ * Use the APIs to access it.
* @internal ICU 4.4 Technology Preview
*/
-
-struct UPlugData;
typedef struct UPlugData UPlugData;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/localematcher.h b/thirdparty/icu4c/common/unicode/localematcher.h
index 63a68b0b7f..0cd068ef32 100644
--- a/thirdparty/icu4c/common/unicode/localematcher.h
+++ b/thirdparty/icu4c/common/unicode/localematcher.h
@@ -91,8 +91,6 @@ enum ULocMatchDemotion {
typedef enum ULocMatchDemotion ULocMatchDemotion;
#endif
-#ifndef U_FORCE_HIDE_DRAFT_API
-
/**
* Builder option for whether to include or ignore one-way (fallback) match data.
* The LocaleMatcher uses CLDR languageMatch data which includes fallback (oneway=true) entries.
@@ -108,20 +106,20 @@ typedef enum ULocMatchDemotion ULocMatchDemotion;
* but not if it is merely a fallback.
*
* @see LocaleMatcher::Builder#setDirection(ULocMatchDirection)
- * @draft ICU 67
+ * @stable ICU 67
*/
enum ULocMatchDirection {
/**
* Locale matching includes one-way matches such as Breton→French. (default)
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_WITH_ONE_WAY,
/**
* Locale matching limited to two-way matches including e.g. Danish↔Norwegian
* but ignoring one-way matches.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_ONLY_TWO_WAY
};
@@ -129,8 +127,6 @@ enum ULocMatchDirection {
typedef enum ULocMatchDirection ULocMatchDirection;
#endif
-#endif // U_FORCE_HIDE_DRAFT_API
-
struct UHashtable;
U_NAMESPACE_BEGIN
@@ -463,14 +459,13 @@ public:
*/
Builder &setDemotionPerDesiredLocale(ULocMatchDemotion demotion);
-#ifndef U_HIDE_DRAFT_API
/**
* Option for whether to include or ignore one-way (fallback) match data.
* By default, they are included.
*
* @param direction the match direction to set.
* @return this Builder object
- * @draft ICU 67
+ * @stable ICU 67
*/
Builder &setDirection(ULocMatchDirection direction) {
if (U_SUCCESS(errorCode_)) {
@@ -478,7 +473,6 @@ public:
}
return *this;
}
-#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_DRAFT_API
/**
@@ -704,7 +698,7 @@ private:
LSR *lsrs;
int32_t supportedLocalesLength;
// These are in preference order: 1. Default locale 2. paradigm locales 3. others.
- UHashtable *supportedLsrToIndex; // Map<LSR, Integer> stores index+1 because 0 is "not found"
+ UHashtable *supportedLsrToIndex; // Map<LSR, Integer>
// Array versions of the supportedLsrToIndex keys and values.
// The distance lookup loops over the supportedLSRs and returns the index of the best match.
const LSR **supportedLSRs;
diff --git a/thirdparty/icu4c/common/unicode/locid.h b/thirdparty/icu4c/common/unicode/locid.h
index ba858d702a..81f4685d65 100644
--- a/thirdparty/icu4c/common/unicode/locid.h
+++ b/thirdparty/icu4c/common/unicode/locid.h
@@ -571,15 +571,13 @@ public:
*/
void minimizeSubtags(UErrorCode& status);
-#ifndef U_HIDE_DRAFT_API
/**
* Canonicalize the locale ID of this object according to CLDR.
* @param status the status code
- * @draft ICU 67
+ * @stable ICU 67
* @see createCanonical
*/
void canonicalize(UErrorCode& status);
-#endif // U_HIDE_DRAFT_API
/**
* Gets the list of keywords for the specified locale.
diff --git a/thirdparty/icu4c/common/unicode/normalizer2.h b/thirdparty/icu4c/common/unicode/normalizer2.h
index 5eb1d95caf..2d355250c2 100644
--- a/thirdparty/icu4c/common/unicode/normalizer2.h
+++ b/thirdparty/icu4c/common/unicode/normalizer2.h
@@ -225,10 +225,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for all built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -381,11 +379,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
@@ -543,10 +539,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for most built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -676,11 +670,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
diff --git a/thirdparty/icu4c/common/unicode/platform.h b/thirdparty/icu4c/common/unicode/platform.h
index 2bb2f8b318..cb3a833fef 100644
--- a/thirdparty/icu4c/common/unicode/platform.h
+++ b/thirdparty/icu4c/common/unicode/platform.h
@@ -880,6 +880,6 @@ namespace std {
#else
# define U_CALLCONV_FPTR
#endif
-/* @} */
+/** @} */
#endif // _PLATFORM_H
diff --git a/thirdparty/icu4c/common/unicode/stringpiece.h b/thirdparty/icu4c/common/unicode/stringpiece.h
index 7d7d871e1f..8c96789e73 100644
--- a/thirdparty/icu4c/common/unicode/stringpiece.h
+++ b/thirdparty/icu4c/common/unicode/stringpiece.h
@@ -75,12 +75,11 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a NUL-terminated const char8_t * pointer.
* @param str a NUL-terminated const char8_t * pointer
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str) : StringPiece(reinterpret_cast<const char*>(str)) {}
#endif
@@ -88,10 +87,9 @@ class U_COMMON_API StringPiece : public UMemory {
* Constructs an empty StringPiece.
* Needed for type disambiguation from multiple other overloads.
* @param p nullptr
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(std::nullptr_t p) : ptr_(p), length_(0) {}
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from a std::string.
@@ -99,17 +97,15 @@ class U_COMMON_API StringPiece : public UMemory {
*/
StringPiece(const std::string& str)
: ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_lib_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a std::u8string.
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const std::u8string& str)
: ptr_(reinterpret_cast<const char*>(str.data())),
length_(static_cast<int32_t>(str.size())) { }
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from some other implementation of a string piece class, from any
@@ -152,18 +148,16 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a const char8_t * pointer and a specified length.
* @param str a const char8_t * pointer (need not be terminated)
* @param len the length of the string; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str, int32_t len) :
StringPiece(reinterpret_cast<const char*>(str), len) {}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Substring of another StringPiece.
@@ -233,13 +227,12 @@ class U_COMMON_API StringPiece : public UMemory {
*/
void set(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Resets the stringpiece to refer to new data.
* @param xdata pointer the new string data. Need not be NUL-terminated.
* @param len the length of the new data
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* xdata, int32_t len) {
set(reinterpret_cast<const char*>(xdata), len);
@@ -248,13 +241,12 @@ class U_COMMON_API StringPiece : public UMemory {
/**
* Resets the stringpiece to refer to new data.
* @param str a pointer to a NUL-terminated string.
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* str) {
set(reinterpret_cast<const char*>(str));
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Removes the first n string units.
@@ -286,13 +278,12 @@ class U_COMMON_API StringPiece : public UMemory {
}
}
-#ifndef U_HIDE_DRAFT_API
/**
* Searches the StringPiece for the given search string (needle);
* @param needle The string for which to search.
* @param offset Where to start searching within this string (haystack).
* @return The offset of needle in haystack, or -1 if not found.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t find(StringPiece needle, int32_t offset);
@@ -301,10 +292,9 @@ class U_COMMON_API StringPiece : public UMemory {
* similar to std::string::compare().
* @param other The string to compare to.
* @return below zero if this < other; above zero if this > other; 0 if this == other.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t compare(StringPiece other);
-#endif // U_HIDE_DRAFT_API
/**
* Maximum integer, used as a default value for substring methods.
diff --git a/thirdparty/icu4c/common/unicode/ubrk.h b/thirdparty/icu4c/common/unicode/ubrk.h
index 37189a8598..1249b0b160 100644
--- a/thirdparty/icu4c/common/unicode/ubrk.h
+++ b/thirdparty/icu4c/common/unicode/ubrk.h
@@ -296,6 +296,8 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
const UChar * text, int32_t textLength,
UErrorCode * status);
+#ifndef U_HIDE_DEPRECATED_API
+
/**
* Thread safe cloning operation
* @param bi iterator to be cloned
@@ -312,7 +314,7 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
* @param status to indicate whether the operation went on smoothly or there were errors
* An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary.
* @return pointer to the new clone
- * @stable ICU 2.0
+ * @deprecated ICU 69 Use ubrk_clone() instead.
*/
U_CAPI UBreakIterator * U_EXPORT2
ubrk_safeClone(
@@ -321,6 +323,23 @@ ubrk_safeClone(
int32_t *pBufferSize,
UErrorCode *status);
+#endif /* U_HIDE_DEPRECATED_API */
+
+#ifndef U_HIDE_DRAFT_API
+
+/**
+ * Thread safe cloning operation.
+ * @param bi iterator to be cloned
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return pointer to the new clone
+ * @draft ICU 69
+ */
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi,
+ UErrorCode *status);
+
+#endif // U_HIDE_DRAFT_API
+
#ifndef U_HIDE_DEPRECATED_API
/**
diff --git a/thirdparty/icu4c/common/unicode/ucnv.h b/thirdparty/icu4c/common/unicode/ucnv.h
index 58f271cfb5..5d784990f2 100644
--- a/thirdparty/icu4c/common/unicode/ucnv.h
+++ b/thirdparty/icu4c/common/unicode/ucnv.h
@@ -1699,10 +1699,10 @@ ucnv_countAvailable(void);
/**
* Gets the canonical converter name of the specified converter from a list of
- * all available converters contaied in the alias file. All converters
+ * all available converters contained in the alias file. All converters
* in this list can be opened.
*
- * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvaiable()]</TT>)
+ * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvailable()]</TT>)
* @return a pointer a string (library owned), or <TT>NULL</TT> if the index is out of bounds.
* @see ucnv_countAvailable
* @stable ICU 2.0
diff --git a/thirdparty/icu4c/common/unicode/ucnvsel.h b/thirdparty/icu4c/common/unicode/ucnvsel.h
index 5e0a71cf35..3d7d3327f7 100644
--- a/thirdparty/icu4c/common/unicode/ucnvsel.h
+++ b/thirdparty/icu4c/common/unicode/ucnvsel.h
@@ -45,11 +45,11 @@
* from the serialized form.
*/
+struct UConverterSelector;
/**
* @{
- * The selector data structure
+ * Typedef for selector data structure.
*/
-struct UConverterSelector;
typedef struct UConverterSelector UConverterSelector;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/unifilt.h b/thirdparty/icu4c/common/unicode/unifilt.h
index 420e1a1905..7870b55939 100644
--- a/thirdparty/icu4c/common/unicode/unifilt.h
+++ b/thirdparty/icu4c/common/unicode/unifilt.h
@@ -40,8 +40,8 @@ U_NAMESPACE_BEGIN
*
* <code>UnicodeFilter</code> defines a protocol for selecting a
* subset of the full range (U+0000 to U+10FFFF) of Unicode characters.
- * Currently, filters are used in conjunction with classes like {@link
- * Transliterator} to only process selected characters through a
+ * Currently, filters are used in conjunction with classes like
+ * {@link Transliterator} to only process selected characters through a
* transformation.
*
* <p>Note: UnicodeFilter currently stubs out two pure virtual methods
diff --git a/thirdparty/icu4c/common/unicode/uniset.h b/thirdparty/icu4c/common/unicode/uniset.h
index 50b6360f3a..8403c4026c 100644
--- a/thirdparty/icu4c/common/unicode/uniset.h
+++ b/thirdparty/icu4c/common/unicode/uniset.h
@@ -178,8 +178,6 @@ class RuleCharacterIterator;
* Unicode property
* </table>
*
- * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p>
- *
* <p><b>Formal syntax</b></p>
*
* \htmlonly<blockquote>\endhtmlonly
@@ -601,7 +599,7 @@ public:
/**
* Make this object represent the range `start - end`.
- * If `end > start` then this object is set to an empty range.
+ * If `start > end` then this object is set to an empty range.
* A frozen set will not be modified.
*
* @param start first character in the set, inclusive
@@ -1077,7 +1075,7 @@ public:
/**
* Adds the specified range to this set if it is not already
* present. If this set already contains the specified range,
- * the call leaves this set unchanged. If <code>end > start</code>
+ * the call leaves this set unchanged. If <code>start > end</code>
* then an empty range is added, leaving the set unchanged.
* This is equivalent to a boolean logic OR, or a set UNION.
* A frozen set will not be modified.
@@ -1095,6 +1093,9 @@ public:
* present. If this set already contains the specified character,
* the call leaves this set unchanged.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& add(UChar32 c);
@@ -1104,8 +1105,8 @@ public:
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
* A frozen set will not be modified.
+ *
* @param s the source string
* @return this object, for chaining
* @stable ICU 2.4
@@ -1124,8 +1125,8 @@ public:
public:
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1135,7 +1136,6 @@ public:
/**
* Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1145,7 +1145,6 @@ public:
/**
* Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1155,7 +1154,6 @@ public:
/**
* Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1165,7 +1163,7 @@ public:
/**
* Makes a set from a multicharacter string. Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return a newly created set containing the given string.
* The caller owns the return object and is responsible for deleting it.
@@ -1185,15 +1183,13 @@ public:
/**
* Retain only the elements in this set that are contained in the
- * specified range. If <code>end > start</code> then an empty range is
+ * specified range. If <code>start > end</code> then an empty range is
* retained, leaving the set empty. This is equivalent to
* a boolean logic AND, or a set INTERSECTION.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& retain(UChar32 start, UChar32 end);
@@ -1202,14 +1198,31 @@ public:
/**
* Retain the specified character from this set if it is present.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& retain(UChar32 c);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param s the source string
+ * @return this object, for chaining
+ * @draft ICU 69
+ */
+ UnicodeSet& retain(const UnicodeString &s);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
- * returns. If <code>end > start</code> then an empty range is
+ * returns. If <code>start > end</code> then an empty range is
* removed, leaving the set unchanged.
* A frozen set will not be modified.
*
@@ -1226,6 +1239,9 @@ public:
* The set will not contain the specified range once the call
* returns.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& remove(UChar32 c);
@@ -1253,15 +1269,13 @@ public:
/**
* Complements the specified range in this set. Any character in
* the range will be removed if it is in this set, or will be
- * added if it is not in this set. If <code>end > start</code>
+ * added if it is not in this set. If <code>start > end</code>
* then an empty range is complemented, leaving the set unchanged.
* This is equivalent to a boolean logic XOR.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be removed
- * from this set.
- * @param end last character, inclusive, of range to be removed
- * from this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& complement(UChar32 start, UChar32 end);
@@ -1271,16 +1285,18 @@ public:
* will be removed if it is in this set, or will be added if it is
* not in this set.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& complement(UChar32 c);
/**
* Complement the specified string in this set.
- * The set will not contain the specified string once the call
- * returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
* A frozen set will not be modified.
+ *
* @param s the string to complement
* @return this object, for chaining
* @stable ICU 2.4
diff --git a/thirdparty/icu4c/common/unicode/unistr.h b/thirdparty/icu4c/common/unicode/unistr.h
index 456389f265..85bd964951 100644
--- a/thirdparty/icu4c/common/unicode/unistr.h
+++ b/thirdparty/icu4c/common/unicode/unistr.h
@@ -44,9 +44,10 @@ struct UConverter; // unicode/ucnv.h
#ifndef USTRING_H
/**
* \ingroup ustring_ustrlen
+ * @param s Pointer to sequence of UChars.
+ * @return Length of sequence.
*/
-U_CAPI int32_t U_EXPORT2
-u_strlen(const UChar *s);
+U_CAPI int32_t U_EXPORT2 u_strlen(const UChar *s);
#endif
U_NAMESPACE_BEGIN
@@ -2766,7 +2767,6 @@ public:
* @param options Options bit set, usually 0. See U_TITLECASE_NO_LOWERCASE,
* U_TITLECASE_NO_BREAK_ADJUSTMENT, U_TITLECASE_ADJUST_TO_CASED,
* U_TITLECASE_WHOLE_STRING, U_TITLECASE_SENTENCES.
- * @param options Options bit set, see ucasemap_open().
* @return A reference to this.
* @stable ICU 3.8
*/
@@ -3614,7 +3614,7 @@ private:
// turn a bogus string into an empty one
void unBogus();
- // implements assigment operator, copy constructor, and fastCopyFrom()
+ // implements assignment operator, copy constructor, and fastCopyFrom()
UnicodeString &copyFrom(const UnicodeString &src, UBool fastCopy=false);
// Copies just the fields without memory management.
diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h
index fe59fdd893..737f4b308e 100644
--- a/thirdparty/icu4c/common/unicode/urename.h
+++ b/thirdparty/icu4c/common/unicode/urename.h
@@ -482,6 +482,7 @@
#define ubiditransform_open U_ICU_ENTRY_POINT_RENAME(ubiditransform_open)
#define ubiditransform_transform U_ICU_ENTRY_POINT_RENAME(ubiditransform_transform)
#define ublock_getCode U_ICU_ENTRY_POINT_RENAME(ublock_getCode)
+#define ubrk_clone U_ICU_ENTRY_POINT_RENAME(ubrk_clone)
#define ubrk_close U_ICU_ENTRY_POINT_RENAME(ubrk_close)
#define ubrk_countAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_countAvailable)
#define ubrk_current U_ICU_ENTRY_POINT_RENAME(ubrk_current)
@@ -534,6 +535,7 @@
#define ucal_getTimeZoneDisplayName U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneDisplayName)
#define ucal_getTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneID)
#define ucal_getTimeZoneIDForWindowsID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneIDForWindowsID)
+#define ucal_getTimeZoneOffsetFromLocal U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneOffsetFromLocal)
#define ucal_getTimeZoneTransitionDate U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneTransitionDate)
#define ucal_getType U_ICU_ENTRY_POINT_RENAME(ucal_getType)
#define ucal_getWeekendTransition U_ICU_ENTRY_POINT_RENAME(ucal_getWeekendTransition)
@@ -962,6 +964,7 @@
#define uhash_compareScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_compareScriptSet)
#define uhash_compareUChars U_ICU_ENTRY_POINT_RENAME(uhash_compareUChars)
#define uhash_compareUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareUnicodeString)
+#define uhash_containsKey U_ICU_ENTRY_POINT_RENAME(uhash_containsKey)
#define uhash_count U_ICU_ENTRY_POINT_RENAME(uhash_count)
#define uhash_deleteHashtable U_ICU_ENTRY_POINT_RENAME(uhash_deleteHashtable)
#define uhash_deleteScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_deleteScriptSet)
@@ -970,6 +973,7 @@
#define uhash_find U_ICU_ENTRY_POINT_RENAME(uhash_find)
#define uhash_get U_ICU_ENTRY_POINT_RENAME(uhash_get)
#define uhash_geti U_ICU_ENTRY_POINT_RENAME(uhash_geti)
+#define uhash_getiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_getiAndFound)
#define uhash_hashCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashCaselessUnicodeString)
#define uhash_hashChars U_ICU_ENTRY_POINT_RENAME(uhash_hashChars)
#define uhash_hashIChars U_ICU_ENTRY_POINT_RENAME(uhash_hashIChars)
@@ -977,12 +981,15 @@
#define uhash_hashScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_hashScriptSet)
#define uhash_hashUChars U_ICU_ENTRY_POINT_RENAME(uhash_hashUChars)
#define uhash_hashUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashUnicodeString)
+#define uhash_icontainsKey U_ICU_ENTRY_POINT_RENAME(uhash_icontainsKey)
#define uhash_iget U_ICU_ENTRY_POINT_RENAME(uhash_iget)
#define uhash_igeti U_ICU_ENTRY_POINT_RENAME(uhash_igeti)
+#define uhash_igetiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_igetiAndFound)
#define uhash_init U_ICU_ENTRY_POINT_RENAME(uhash_init)
#define uhash_initSize U_ICU_ENTRY_POINT_RENAME(uhash_initSize)
#define uhash_iput U_ICU_ENTRY_POINT_RENAME(uhash_iput)
#define uhash_iputi U_ICU_ENTRY_POINT_RENAME(uhash_iputi)
+#define uhash_iputiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_iputiAllowZero)
#define uhash_iremove U_ICU_ENTRY_POINT_RENAME(uhash_iremove)
#define uhash_iremovei U_ICU_ENTRY_POINT_RENAME(uhash_iremovei)
#define uhash_nextElement U_ICU_ENTRY_POINT_RENAME(uhash_nextElement)
@@ -990,6 +997,7 @@
#define uhash_openSize U_ICU_ENTRY_POINT_RENAME(uhash_openSize)
#define uhash_put U_ICU_ENTRY_POINT_RENAME(uhash_put)
#define uhash_puti U_ICU_ENTRY_POINT_RENAME(uhash_puti)
+#define uhash_putiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_putiAllowZero)
#define uhash_remove U_ICU_ENTRY_POINT_RENAME(uhash_remove)
#define uhash_removeAll U_ICU_ENTRY_POINT_RENAME(uhash_removeAll)
#define uhash_removeElement U_ICU_ENTRY_POINT_RENAME(uhash_removeElement)
@@ -1150,6 +1158,8 @@
#define ultag_isUnicodeLocaleKey U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleKey)
#define ultag_isUnicodeLocaleType U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleType)
#define ultag_isVariantSubtags U_ICU_ENTRY_POINT_RENAME(ultag_isVariantSubtags)
+#define umeas_getPrefixBase U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixBase)
+#define umeas_getPrefixPower U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixPower)
#define umsg_applyPattern U_ICU_ENTRY_POINT_RENAME(umsg_applyPattern)
#define umsg_autoQuoteApostrophe U_ICU_ENTRY_POINT_RENAME(umsg_autoQuoteApostrophe)
#define umsg_clone U_ICU_ENTRY_POINT_RENAME(umsg_clone)
@@ -1672,6 +1682,9 @@
#define uset_compact U_ICU_ENTRY_POINT_RENAME(uset_compact)
#define uset_complement U_ICU_ENTRY_POINT_RENAME(uset_complement)
#define uset_complementAll U_ICU_ENTRY_POINT_RENAME(uset_complementAll)
+#define uset_complementAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_complementAllCodePoints)
+#define uset_complementRange U_ICU_ENTRY_POINT_RENAME(uset_complementRange)
+#define uset_complementString U_ICU_ENTRY_POINT_RENAME(uset_complementString)
#define uset_contains U_ICU_ENTRY_POINT_RENAME(uset_contains)
#define uset_containsAll U_ICU_ENTRY_POINT_RENAME(uset_containsAll)
#define uset_containsAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_containsAllCodePoints)
@@ -1695,12 +1708,15 @@
#define uset_openPatternOptions U_ICU_ENTRY_POINT_RENAME(uset_openPatternOptions)
#define uset_remove U_ICU_ENTRY_POINT_RENAME(uset_remove)
#define uset_removeAll U_ICU_ENTRY_POINT_RENAME(uset_removeAll)
+#define uset_removeAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_removeAllCodePoints)
#define uset_removeAllStrings U_ICU_ENTRY_POINT_RENAME(uset_removeAllStrings)
#define uset_removeRange U_ICU_ENTRY_POINT_RENAME(uset_removeRange)
#define uset_removeString U_ICU_ENTRY_POINT_RENAME(uset_removeString)
#define uset_resemblesPattern U_ICU_ENTRY_POINT_RENAME(uset_resemblesPattern)
#define uset_retain U_ICU_ENTRY_POINT_RENAME(uset_retain)
#define uset_retainAll U_ICU_ENTRY_POINT_RENAME(uset_retainAll)
+#define uset_retainAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_retainAllCodePoints)
+#define uset_retainString U_ICU_ENTRY_POINT_RENAME(uset_retainString)
#define uset_serialize U_ICU_ENTRY_POINT_RENAME(uset_serialize)
#define uset_serializedContains U_ICU_ENTRY_POINT_RENAME(uset_serializedContains)
#define uset_set U_ICU_ENTRY_POINT_RENAME(uset_set)
diff --git a/thirdparty/icu4c/common/unicode/uset.h b/thirdparty/icu4c/common/unicode/uset.h
index 502ea8dc14..1d0daf9d09 100644
--- a/thirdparty/icu4c/common/unicode/uset.h
+++ b/thirdparty/icu4c/common/unicode/uset.h
@@ -582,8 +582,8 @@ U_CAPI void U_EXPORT2
uset_addString(USet* set, const UChar* str, int32_t strLen);
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param set the object to which to add the character
* @param str the source string
@@ -628,6 +628,20 @@ uset_removeRange(USet* set, UChar32 start, UChar32 end);
U_CAPI void U_EXPORT2
uset_removeString(USet* set, const UChar* str, int32_t strLen);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Removes EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes from this set all of its elements that are contained in the
* specified set. This operation effectively modifies this
@@ -650,15 +664,41 @@ uset_removeAll(USet* set, const USet* removeSet);
* A frozen set will not be modified.
*
* @param set the object for which to retain only the specified range
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 3.2
*/
U_CAPI void U_EXPORT2
uset_retain(USet* set, UChar32 start, UChar32 end);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Retains only the elements in this set that are contained in the
* specified set. In other words, removes from this set all of
@@ -696,6 +736,49 @@ uset_compact(USet* set);
U_CAPI void U_EXPORT2
uset_complement(USet* set);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Complements the specified range in this set. Any character in
+ * the range will be removed if it is in this set, or will be
+ * added if it is not in this set. If <code>start > end</code>
+ * then an empty range is complemented, leaving the set unchanged.
+ * This is equivalent to a boolean logic XOR.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end);
+
+/**
+ * Complements the specified string in this set.
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Complements EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Complements in this set all elements contained in the specified
* set. Any character in the other set will be removed if it is
diff --git a/thirdparty/icu4c/common/unicode/ushape.h b/thirdparty/icu4c/common/unicode/ushape.h
index fed4869abd..14371edc8f 100644
--- a/thirdparty/icu4c/common/unicode/ushape.h
+++ b/thirdparty/icu4c/common/unicode/ushape.h
@@ -323,7 +323,7 @@ u_shapeArabic(const UChar *source, int32_t sourceLength,
#define U_SHAPE_PRESERVE_PRESENTATION 0x8000
/** Presentation form option:
* Replace Arabic Presentation Forms-A and Arabic Presentationo Forms-B with
- * their unshaped correspondants in range 0+06xx, before shaping.
+ * their unshaped correspondents in range 0+06xx, before shaping.
* @stable ICU 3.6
*/
#define U_SHAPE_PRESERVE_PRESENTATION_NOOP 0
diff --git a/thirdparty/icu4c/common/unicode/utrace.h b/thirdparty/icu4c/common/unicode/utrace.h
index 28c313c582..677486f473 100644
--- a/thirdparty/icu4c/common/unicode/utrace.h
+++ b/thirdparty/icu4c/common/unicode/utrace.h
@@ -173,24 +173,23 @@ typedef enum UTraceFunctionNumber {
UTRACE_RES_DATA_LIMIT,
#endif // U_HIDE_INTERNAL_API
-#ifndef U_HIDE_DRAFT_API
/**
* The lowest break iterator location.
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_START=0x4000,
/**
* Indicates that a character instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_CHARACTER = UTRACE_UBRK_START,
/**
* Indicates that a word instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_WORD,
@@ -200,21 +199,21 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the lb value ("",
* "loose", "strict", or "normal").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_LINE,
/**
* Indicates that a sentence instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_SENTENCE,
/**
* Indicates that a title instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_TITLE,
@@ -224,12 +223,10 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the script code of what
* the break engine cover ("Hani", "Khmr", "Laoo", "Mymr", or "Thai").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_BREAK_ENGINE,
-#endif // U_HIDE_DRAFT_API
-
#ifndef U_HIDE_INTERNAL_API
/**
* One more than the highest normal break iterator trace location.
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index a46481a3fe..b09d4943c1 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -60,13 +60,13 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_MAJOR_NUM 68
+#define U_ICU_VERSION_MAJOR_NUM 69
/** The current ICU minor version as an integer.
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_MINOR_NUM 2
+#define U_ICU_VERSION_MINOR_NUM 1
/** The current ICU patchlevel version as an integer.
* This value will change in the subsequent releases of ICU
@@ -86,7 +86,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SUFFIX _68
+#define U_ICU_VERSION_SUFFIX _69
/**
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
@@ -139,7 +139,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "68.2"
+#define U_ICU_VERSION "69.1"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -152,13 +152,13 @@
*
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SHORT "68"
+#define U_ICU_VERSION_SHORT "69"
#ifndef U_HIDE_INTERNAL_API
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "68.2"
+#define U_ICU_DATA_VERSION "69.1"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/common/uniset.cpp b/thirdparty/icu4c/common/uniset.cpp
index b73d612f24..461e5a7197 100644
--- a/thirdparty/icu4c/common/uniset.cpp
+++ b/thirdparty/icu4c/common/uniset.cpp
@@ -30,24 +30,6 @@
#include "bmpset.h"
#include "unisetspan.h"
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
// HIGH_VALUE > all valid values. 110000 for codepoints
#define UNICODESET_HIGH 0x0110000
@@ -444,7 +426,6 @@ UBool UnicodeSet::contains(UChar32 start, UChar32 end) const {
* @return <tt>true</tt> if this set contains the specified string
*/
UBool UnicodeSet::contains(const UnicodeString& s) const {
- if (s.length() == 0) return FALSE;
int32_t cp = getSingleCP(s);
if (cp < 0) {
return stringsContains(s);
@@ -559,11 +540,9 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
if (hasStrings()) {
for (i=0; i<strings->size(); ++i) {
const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i);
- //if (s.length() == 0) {
- // // Empty strings match everything
- // return TRUE;
- //}
- // assert(s.length() != 0); // We enforce this elsewhere
+ if (s.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar32 c = s.char32At(0);
if ((c & 0xFF) == v) {
return TRUE;
@@ -582,9 +561,6 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
int32_t limit,
UBool incremental) {
if (offset == limit) {
- // Strings, if any, have length != 0, so we don't worry
- // about them here. If we ever allow zero-length strings
- // we much check for them here.
if (contains(U_ETHER)) {
return incremental ? U_PARTIAL_MATCH : U_MATCH;
} else {
@@ -614,11 +590,9 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
for (i=0; i<strings->size(); ++i) {
const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i);
-
- //if (trial.length() == 0) {
- // return U_MATCH; // null-string always matches
- //}
- // assert(trial.length() != 0); // We ensure this elsewhere
+ if (trial.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar c = trial.charAt(forward ? 0 : trial.length() - 1);
@@ -971,12 +945,12 @@ UnicodeSet& UnicodeSet::add(UChar32 c) {
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (!stringsContains(s)) {
@@ -991,8 +965,7 @@ UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
/**
* Adds the given string, in order, to 'strings'. The given string
- * must have been checked by the caller to not be empty and to not
- * already be in 'strings'.
+ * must have been checked by the caller to not already be in 'strings'.
*/
void UnicodeSet::_add(const UnicodeString& s) {
if (isFrozen() || isBogus()) {
@@ -1021,16 +994,13 @@ void UnicodeSet::_add(const UnicodeString& s) {
* @param string to test
*/
int32_t UnicodeSet::getSingleCP(const UnicodeString& s) {
- //if (s.length() < 1) {
- // throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet");
- //}
- if (s.length() > 2) return -1;
- if (s.length() == 1) return s.charAt(0);
-
- // at this point, len = 2
- UChar32 cp = s.char32At(0);
- if (cp > 0xFFFF) { // is surrogate pair
- return cp;
+ int32_t sLength = s.length();
+ if (sLength == 1) return s.charAt(0);
+ if (sLength == 2) {
+ UChar32 cp = s.char32At(0);
+ if (cp > 0xFFFF) { // is surrogate pair
+ return cp;
+ }
}
return -1;
}
@@ -1150,6 +1120,26 @@ UnicodeSet& UnicodeSet::retain(UChar32 c) {
return retain(c, c);
}
+UnicodeSet& UnicodeSet::retain(const UnicodeString &s) {
+ if (isFrozen() || isBogus()) { return *this; }
+ UChar32 cp = getSingleCP(s);
+ if (cp < 0) {
+ bool isIn = stringsContains(s);
+ // Check for getRangeCount() first to avoid somewhat-expensive size()
+ // when there are single code points.
+ if (isIn && getRangeCount() == 0 && size() == 1) {
+ return *this;
+ }
+ clear();
+ if (isIn) {
+ _add(s);
+ }
+ } else {
+ retain(cp, cp);
+ }
+ return *this;
+}
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
@@ -1186,7 +1176,7 @@ UnicodeSet& UnicodeSet::remove(UChar32 c) {
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::remove(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (strings != nullptr && strings->removeElement((void*) &s)) {
@@ -1252,12 +1242,12 @@ UnicodeSet& UnicodeSet::complement(void) {
* Complement the specified string in this set.
* The set will not contain the specified string once the call
* returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the string to complement
* @return this object, for chaining
*/
UnicodeSet& UnicodeSet::complement(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (stringsContains(s)) {
@@ -2001,22 +1991,22 @@ escapeUnprintable) {
}
// Okay to let ':' pass through
switch (c) {
- case SET_OPEN:
- case SET_CLOSE:
- case HYPHEN:
- case COMPLEMENT:
- case INTERSECTION:
- case BACKSLASH:
- case OPEN_BRACE:
- case CLOSE_BRACE:
- case COLON:
+ case u'[':
+ case u']':
+ case u'-':
+ case u'^':
+ case u'&':
+ case u'\\':
+ case u'{':
+ case u'}':
+ case u':':
case SymbolTable::SYMBOL_REF:
- buf.append(BACKSLASH);
+ buf.append(u'\\');
break;
default:
// Escape whitespace
if (PatternProps::isWhiteSpace(c)) {
- buf.append(BACKSLASH);
+ buf.append(u'\\');
}
break;
}
@@ -2049,7 +2039,7 @@ UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
backslashCount = 0;
} else {
result.append(c);
- if (c == BACKSLASH) {
+ if (c == u'\\') {
++backslashCount;
} else {
backslashCount = 0;
@@ -2082,13 +2072,13 @@ UnicodeString& UnicodeSet::toPattern(UnicodeString& result,
UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
UBool escapeUnprintable) const
{
- result.append(SET_OPEN);
+ result.append(u'[');
// // Check against the predefined categories. We implicitly build
// // up ALL category sets the first time toPattern() is called.
// for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) {
// if (*this == getCategorySet(cat)) {
-// result.append(COLON);
+// result.append(u':');
// result.append(CATEGORY_NAMES, cat*2, 2);
// return result.append(CATEGORY_CLOSE);
// }
@@ -2104,7 +2094,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
getRangeEnd(count-1) == MAX_VALUE) {
// Emit the inverse
- result.append(COMPLEMENT);
+ result.append(u'^');
for (int32_t i = 1; i < count; ++i) {
UChar32 start = getRangeEnd(i-1)+1;
@@ -2112,7 +2102,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2127,7 +2117,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2136,14 +2126,14 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
if (strings != nullptr) {
for (int32_t i = 0; i<strings->size(); ++i) {
- result.append(OPEN_BRACE);
+ result.append(u'{');
_appendToPat(result,
*(const UnicodeString*) strings->elementAt(i),
escapeUnprintable);
- result.append(CLOSE_BRACE);
+ result.append(u'}');
}
}
- return result.append(SET_CLOSE);
+ return result.append(u']');
}
/**
diff --git a/thirdparty/icu4c/common/uniset_props.cpp b/thirdparty/icu4c/common/uniset_props.cpp
index 37277fcb75..8fde5abcdd 100644
--- a/thirdparty/icu4c/common/uniset_props.cpp
+++ b/thirdparty/icu4c/common/uniset_props.cpp
@@ -47,31 +47,6 @@
U_NAMESPACE_USE
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
-//static const UChar POSIX_OPEN[] = { SET_OPEN,COLON,0 }; // "[:"
-static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 }; // ":]"
-//static const UChar PERL_OPEN[] = { BACKSLASH,LOWER_P,0 }; // "\\p"
-//static const UChar PERL_CLOSE[] = { CLOSE_BRACE,0 }; // "}"
-//static const UChar NAME_OPEN[] = { BACKSLASH,UPPER_N,0 }; // "\\N"
-static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/
-
// Special property set IDs
static const char ANY[] = "ANY"; // [\u0000-\U0010FFFF]
static const char ASCII[] = "ASCII"; // [\u0000-\u007F]
@@ -81,12 +56,6 @@ static const char ASSIGNED[] = "Assigned"; // [:^Cn:]
#define NAME_PROP "na"
#define NAME_PROP_LENGTH 2
-/**
- * Delimiter string used in patterns to close a category reference:
- * ":]". Example: "[:Lu:]".
- */
-//static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */
-
// Cached sets ------------------------------------------------------------- ***
U_CDECL_BEGIN
@@ -140,27 +109,27 @@ uniset_getUnicode32Instance(UErrorCode &errorCode) {
static inline UBool
isPerlOpen(const UnicodeString &pattern, int32_t pos) {
UChar c;
- return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P);
+ return pattern.charAt(pos)==u'\\' && ((c=pattern.charAt(pos+1))==u'p' || c==u'P');
}
/*static inline UBool
isPerlClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==CLOSE_BRACE;
+ return pattern.charAt(pos)==u'}';
}*/
static inline UBool
isNameOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N;
+ return pattern.charAt(pos)==u'\\' && pattern.charAt(pos+1)==u'N';
}
static inline UBool
isPOSIXOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON;
+ return pattern.charAt(pos)==u'[' && pattern.charAt(pos+1)==u':';
}
/*static inline UBool
isPOSIXClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE;
+ return pattern.charAt(pos)==u':' && pattern.charAt(pos+1)==u']';
}*/
// TODO memory debugging provided inside uniset.cpp
@@ -326,9 +295,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (mode != 2 && !chars.atEnd()) {
U_ASSERT((lastItem == 0 && op == 0) ||
- (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) ||
- (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ ||
- op == INTERSECTION /*'&'*/)));
+ (lastItem == 1 && (op == 0 || op == u'-')) ||
+ (lastItem == 2 && (op == 0 || op == u'-' || op == u'&')));
UChar32 c = 0;
UBool literal = FALSE;
@@ -356,27 +324,27 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5B /*'['*/ && !literal) {
+ if (c == u'[' && !literal) {
if (mode == 1) {
chars.setPos(backup); // backup
setMode = 1;
} else {
// Handle opening '[' delimiter
mode = 1;
- patLocal.append((UChar) 0x5B /*'['*/);
+ patLocal.append(u'[');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5E /*'^'*/ && !literal) {
+ if (c == u'^' && !literal) {
invert = TRUE;
- patLocal.append((UChar) 0x5E /*'^'*/);
+ patLocal.append(u'^');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
}
// Fall through to handle special leading '-';
// otherwise restart loop for nested [], \p{}, etc.
- if (c == HYPHEN /*'-'*/) {
+ if (c == u'-') {
literal = TRUE;
// Fall through to handle literal '-' below
} else {
@@ -418,7 +386,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
op = 0;
}
- if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) {
+ if (op == u'-' || op == u'&') {
patLocal.append(op);
}
@@ -454,10 +422,10 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
}
switch (op) {
- case HYPHEN: /*'-'*/
+ case u'-':
removeAll(*nested);
break;
- case INTERSECTION: /*'&'*/
+ case u'&':
retainAll(*nested);
break;
case 0:
@@ -483,24 +451,24 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (!literal) {
switch (c) {
- case 0x5D /*']'*/:
+ case u']':
if (lastItem == 1) {
add(lastChar, lastChar);
_appendToPat(patLocal, lastChar, FALSE);
}
// Treat final trailing '-' as a literal
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
add(op, op);
patLocal.append(op);
- } else if (op == INTERSECTION /*'&'*/) {
+ } else if (op == u'&') {
// syntaxError(chars, "Trailing '&'");
ec = U_MALFORMED_SET;
return;
}
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
- case HYPHEN /*'-'*/:
+ case u'-':
if (op == 0) {
if (lastItem != 0) {
op = (UChar) c;
@@ -510,8 +478,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(c, c);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5D /*']'*/ && !literal) {
- patLocal.append(HYPHEN_RIGHT_BRACE, 2);
+ if (c == u']' && !literal) {
+ patLocal.append(u"-]", 2);
mode = 2;
continue;
}
@@ -520,7 +488,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'-' not after char or set");
ec = U_MALFORMED_SET;
return;
- case INTERSECTION /*'&'*/:
+ case u'&':
if (lastItem == 2 && op == 0) {
op = (UChar) c;
continue;
@@ -528,11 +496,11 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'&' not after set");
ec = U_MALFORMED_SET;
return;
- case 0x5E /*'^'*/:
+ case u'^':
// syntaxError(chars, "'^' not after '['");
ec = U_MALFORMED_SET;
return;
- case 0x7B /*'{'*/:
+ case u'{':
if (op != 0) {
// syntaxError(chars, "Missing operand after operator");
ec = U_MALFORMED_SET;
@@ -549,13 +517,13 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (!chars.atEnd()) {
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x7D /*'}'*/ && !literal) {
+ if (c == u'}' && !literal) {
ok = TRUE;
break;
}
buf.append(c);
}
- if (buf.length() < 1 || !ok) {
+ if (!ok) {
// syntaxError(chars, "Invalid multicharacter string");
ec = U_MALFORMED_SET;
return;
@@ -565,9 +533,9 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// we don't need to drop through to the further
// processing
add(buf);
- patLocal.append((UChar) 0x7B /*'{'*/);
+ patLocal.append(u'{');
_appendToPat(patLocal, buf, FALSE);
- patLocal.append((UChar) 0x7D /*'}'*/);
+ patLocal.append(u'}');
continue;
case SymbolTable::SYMBOL_REF:
// symbols nosymbols
@@ -580,7 +548,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
chars.getPos(backup);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- UBool anchor = (c == 0x5D /*']'*/ && !literal);
+ UBool anchor = (c == u']' && !literal);
if (symbols == 0 && !anchor) {
c = SymbolTable::SYMBOL_REF;
chars.setPos(backup);
@@ -594,7 +562,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(U_ETHER);
usePat = TRUE;
patLocal.append((UChar) SymbolTable::SYMBOL_REF);
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
}
@@ -617,7 +585,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
lastChar = c;
break;
case 1:
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
if (lastChar >= c) {
// Don't allow redundant (a-a) or empty (b-a) ranges;
// these are most likely typos.
@@ -1036,11 +1004,11 @@ UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
RuleCharacterIterator::Pos pos;
chars.getPos(pos);
UChar32 c = chars.next(iterOpts, literal, ec);
- if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) {
+ if (c == u'[' || c == u'\\') {
UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE,
literal, ec);
- result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) :
- (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/);
+ result = (c == u'[') ? (d == u':') :
+ (d == u'N' || d == u'p' || d == u'P');
}
chars.setPos(pos);
return result && U_SUCCESS(ec);
@@ -1071,17 +1039,17 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
posix = TRUE;
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) {
+ if (pos < pattern.length() && pattern.charAt(pos) == u'^') {
++pos;
invert = TRUE;
}
} else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
UChar c = pattern.charAt(pos+1);
- invert = (c == UPPER_P);
- isName = (c == UPPER_N);
+ invert = (c == u'P');
+ isName = (c == u'N');
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) {
+ if (pos == pattern.length() || pattern.charAt(pos++) != u'{') {
// Syntax error; "\p" or "\P" not followed by "{"
FAIL(ec);
}
@@ -1093,9 +1061,9 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for the matching close delimiter, either :] or }
int32_t close;
if (posix) {
- close = pattern.indexOf(POSIX_CLOSE, 2, pos);
+ close = pattern.indexOf(u":]", 2, pos);
} else {
- close = pattern.indexOf(CLOSE_BRACE, pos);
+ close = pattern.indexOf(u'}', pos);
}
if (close < 0) {
// Syntax error; close delimiter missing
@@ -1105,7 +1073,7 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for an '=' sign. If this is present, we will parse a
// medium \p{gc=Cf} or long \p{GeneralCategory=Format}
// pattern.
- int32_t equals = pattern.indexOf(EQUALS, pos);
+ int32_t equals = pattern.indexOf(u'=', pos);
UnicodeString propName, valueName;
if (equals >= 0 && equals < close && !isName) {
// Equals seen; parse medium/long pattern
diff --git a/thirdparty/icu4c/common/unisetspan.cpp b/thirdparty/icu4c/common/unisetspan.cpp
index 68e44d91ee..fe0d74f5b2 100644
--- a/thirdparty/icu4c/common/unisetspan.cpp
+++ b/thirdparty/icu4c/common/unisetspan.cpp
@@ -231,6 +231,9 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
UBool thisRelevant;
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
if(spanLength<length16) { // Relevant string.
@@ -312,7 +315,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
- if(spanLength<length16) { // Relevant string.
+ if(spanLength<length16 && length16>0) { // Relevant string.
if(which&UTF16) {
if(which&CONTAINED) {
if(which&FWD) {
@@ -362,7 +365,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
addToSpanNotSet(c);
}
}
- } else { // Irrelevant string.
+ } else { // Irrelevant string. (Also the empty string.)
if(which&UTF8) {
if(which&CONTAINED) { // Only necessary for LONGEST_MATCH.
uint8_t *s8=utf8+utf8Count;
@@ -653,11 +656,12 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -697,6 +701,9 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -817,11 +824,12 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanBackLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -863,6 +871,9 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -1358,11 +1369,12 @@ int32_t UnicodeSetStringSpan::spanNot(const UChar *s, int32_t length) const {
// Try to match the strings at pos.
for(i=0; i<stringsLength; ++i) {
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=rest && matches16CPB(s, pos, length, s16, length16)) {
return pos; // There is a set element at pos.
}
@@ -1401,11 +1413,12 @@ int32_t UnicodeSetStringSpan::spanNotBack(const UChar *s, int32_t length) const
// it is easier and we only need to know whether the string is irrelevant
// which is the same in either array.
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=pos && matches16CPB(s, pos-length16, length, s16, length16)) {
return pos; // There is a set element at pos.
}
diff --git a/thirdparty/icu4c/common/uprops.h b/thirdparty/icu4c/common/uprops.h
index 8bf929919f..09830bdeb9 100644
--- a/thirdparty/icu4c/common/uprops.h
+++ b/thirdparty/icu4c/common/uprops.h
@@ -310,55 +310,12 @@ u_isgraphPOSIX(UChar32 c);
U_CFUNC UBool
u_isprintPOSIX(UChar32 c);
-/** Turn a bit index into a bit flag. @internal */
-#define FLAG(n) ((uint32_t)1<<(n))
-
-/** Flags for general categories in the order of UCharCategory. @internal */
-#define _Cn FLAG(U_GENERAL_OTHER_TYPES)
-#define _Lu FLAG(U_UPPERCASE_LETTER)
-#define _Ll FLAG(U_LOWERCASE_LETTER)
-#define _Lt FLAG(U_TITLECASE_LETTER)
-#define _Lm FLAG(U_MODIFIER_LETTER)
-/* #define _Lo FLAG(U_OTHER_LETTER) -- conflicts with MS Visual Studio 9.0 xiosbase */
-#define _Mn FLAG(U_NON_SPACING_MARK)
-#define _Me FLAG(U_ENCLOSING_MARK)
-#define _Mc FLAG(U_COMBINING_SPACING_MARK)
-#define _Nd FLAG(U_DECIMAL_DIGIT_NUMBER)
-#define _Nl FLAG(U_LETTER_NUMBER)
-#define _No FLAG(U_OTHER_NUMBER)
-#define _Zs FLAG(U_SPACE_SEPARATOR)
-#define _Zl FLAG(U_LINE_SEPARATOR)
-#define _Zp FLAG(U_PARAGRAPH_SEPARATOR)
-#define _Cc FLAG(U_CONTROL_CHAR)
-#define _Cf FLAG(U_FORMAT_CHAR)
-#define _Co FLAG(U_PRIVATE_USE_CHAR)
-#define _Cs FLAG(U_SURROGATE)
-#define _Pd FLAG(U_DASH_PUNCTUATION)
-#define _Ps FLAG(U_START_PUNCTUATION)
-/* #define _Pe FLAG(U_END_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 xlocnum */
-/* #define _Pc FLAG(U_CONNECTOR_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-#define _Po FLAG(U_OTHER_PUNCTUATION)
-#define _Sm FLAG(U_MATH_SYMBOL)
-#define _Sc FLAG(U_CURRENCY_SYMBOL)
-#define _Sk FLAG(U_MODIFIER_SYMBOL)
-#define _So FLAG(U_OTHER_SYMBOL)
-#define _Pi FLAG(U_INITIAL_PUNCTUATION)
-/* #define _Pf FLAG(U_FINAL_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-
/** Some code points. @internal */
enum {
TAB =0x0009,
LF =0x000a,
FF =0x000c,
CR =0x000d,
- U_A =0x0041,
- U_F =0x0046,
- U_Z =0x005a,
- U_a =0x0061,
- U_f =0x0066,
- U_z =0x007a,
- DEL =0x007f,
- NL =0x0085,
NBSP =0x00a0,
CGJ =0x034f,
FIGURESP=0x2007,
@@ -367,15 +324,6 @@ enum {
ZWJ =0x200d,
RLM =0x200f,
NNBSP =0x202f,
- WJ =0x2060,
- INHSWAP =0x206a,
- NOMDIG =0x206f,
- U_FW_A =0xff21,
- U_FW_F =0xff26,
- U_FW_Z =0xff3a,
- U_FW_a =0xff41,
- U_FW_f =0xff46,
- U_FW_z =0xff5a,
ZWNBSP =0xfeff
};
diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp
index 2ece87897d..5ea4187100 100644
--- a/thirdparty/icu4c/common/uresbund.cpp
+++ b/thirdparty/icu4c/common/uresbund.cpp
@@ -92,6 +92,15 @@ static UBool chopLocale(char *name) {
}
/**
+ * Called to check whether a name without '_' needs to be checked for a parent.
+ * Some code had assumed that locale IDs with '_' could not have a non-root parent.
+ * We may want a better way of doing this.
+ */
+static UBool mayHaveParent(char *name) {
+ return (name[0] != 0 && uprv_strstr("nb nn",name) != nullptr);
+}
+
+/**
* Internal function
*/
static void entryIncrease(UResourceDataEntry *entry) {
@@ -529,8 +538,8 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
char name[], int32_t nameCapacity,
UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
if (U_FAILURE(*status)) { return FALSE; }
- UBool hasChopped = TRUE;
- while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback &&
+ UBool checkParent = TRUE;
+ while (checkParent && t1->fParent == NULL && !t1->fData.noFallback &&
res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
Resource parentRes = res_getResource(&t1->fData, "%%Parent");
if (parentRes != RES_BOGUS) { // An explicit parent was found.
@@ -573,7 +582,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
}
}
t1 = t2;
- hasChopped = chopLocale(name);
+ checkParent = chopLocale(name) || mayHaveParent(name);
}
return TRUE;
}
@@ -692,7 +701,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
}
}
}
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -716,7 +725,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
hasRealData = TRUE;
isDefault = TRUE;
// TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -1908,6 +1917,8 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
} else {
break;
}
+ } else if (res == RES_BOGUS) {
+ break;
}
} while(*myPath); /* Continue until the whole path is consumed */
}
@@ -3019,7 +3030,7 @@ ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
U_CAPI UBool U_EXPORT2
ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
if(res1==NULL || res2==NULL){
- return res1==res2; /* pointer comparision */
+ return res1==res2; /* pointer comparison */
}
if(res1->fKey==NULL|| res2->fKey==NULL){
return (res1->fKey==res2->fKey);
diff --git a/thirdparty/icu4c/common/uresdata.cpp b/thirdparty/icu4c/common/uresdata.cpp
index ae731e4544..9af081be40 100644
--- a/thirdparty/icu4c/common/uresdata.cpp
+++ b/thirdparty/icu4c/common/uresdata.cpp
@@ -960,14 +960,6 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch
if(URES_IS_TABLE(type)) {
*key = pathP;
t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
- if(t2 == RES_BOGUS) {
- /* if we fail to get the resource by key, maybe we got an index */
- indexR = uprv_strtol(pathP, &closeIndex, 10);
- if(indexR >= 0 && *closeIndex == 0 && (*pathP != '0' || closeIndex - pathP == 1)) {
- /* if we indeed have an index, try to get the item by index */
- t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
- } // else t2 is already RES_BOGUS
- }
} else if(URES_IS_ARRAY(type)) {
indexR = uprv_strtol(pathP, &closeIndex, 10);
if(indexR >= 0 && *closeIndex == 0) {
diff --git a/thirdparty/icu4c/common/uresimp.h b/thirdparty/icu4c/common/uresimp.h
index 69d82566fe..f038dedace 100644
--- a/thirdparty/icu4c/common/uresimp.h
+++ b/thirdparty/icu4c/common/uresimp.h
@@ -270,11 +270,13 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
* function can perform fallback on the sub-resources of the table.
* @param resB a resource
* @param inKey a key associated with the requested resource
+ * @param len if not NULL, used to return the length of the string
* @param status: fills in the outgoing error code
* could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
* could be a non-failing error
* e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
- * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @return returns a pointer to a zero-terminated UChar array which lives in a
+ * memory mapped/DLL file.
*/
U_CAPI const UChar* U_EXPORT2
ures_getStringByKeyWithFallback(const UResourceBundle *resB,
diff --git a/thirdparty/icu4c/common/uset.cpp b/thirdparty/icu4c/common/uset.cpp
index eae7981d52..a7e3046dbf 100644
--- a/thirdparty/icu4c/common/uset.cpp
+++ b/thirdparty/icu4c/common/uset.cpp
@@ -117,6 +117,12 @@ uset_removeString(USet* set, const UChar* str, int32_t strLen) {
}
U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::removeAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_removeAll(USet* set, const USet* remove) {
((UnicodeSet*) set)->UnicodeSet::removeAll(*(const UnicodeSet*)remove);
}
@@ -127,6 +133,18 @@ uset_retain(USet* set, UChar32 start, UChar32 end) {
}
U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retain(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retainAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_retainAll(USet* set, const USet* retain) {
((UnicodeSet*) set)->UnicodeSet::retainAll(*(const UnicodeSet*)retain);
}
@@ -142,6 +160,23 @@ uset_complement(USet* set) {
}
U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end) {
+ ((UnicodeSet*) set)->UnicodeSet::complement(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complement(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complementAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_complementAll(USet* set, const USet* complement) {
((UnicodeSet*) set)->UnicodeSet::complementAll(*(const UnicodeSet*)complement);
}
diff --git a/thirdparty/icu4c/common/usprep.cpp b/thirdparty/icu4c/common/usprep.cpp
index 8351a77370..874ffc63a8 100644
--- a/thirdparty/icu4c/common/usprep.cpp
+++ b/thirdparty/icu4c/common/usprep.cpp
@@ -575,7 +575,7 @@ usprep_map( const UStringPrepProfile* profile,
}
}else if(type==USPREP_DELETE){
- // just consume the codepoint and contine
+ // just consume the codepoint and continue
continue;
}
//copy the code point into destination
diff --git a/thirdparty/icu4c/common/ustr_wcs.cpp b/thirdparty/icu4c/common/ustr_wcs.cpp
index e9f278e969..89d0762480 100644
--- a/thirdparty/icu4c/common/ustr_wcs.cpp
+++ b/thirdparty/icu4c/common/ustr_wcs.cpp
@@ -364,7 +364,7 @@ _strFromWCS( UChar *dest,
}
/* we have found a null so convert the
- * chunk from begining of non-null char to null
+ * chunk from beginning of non-null char to null
*/
retVal = uprv_wcstombs(pCSrc,pSrc,remaining);
@@ -387,7 +387,7 @@ _strFromWCS( UChar *dest,
* null terminate it and convert wchar_ts to chars
*/
if(nulLen >= _STACK_BUFFER_CAPACITY){
- /* Should rarely occcur */
+ /* Should rarely occur */
/* allocate new buffer buffer */
pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1));
if(pWStack==NULL){
diff --git a/thirdparty/icu4c/common/utext.cpp b/thirdparty/icu4c/common/utext.cpp
index 763b6684fb..d79f8141bb 100644
--- a/thirdparty/icu4c/common/utext.cpp
+++ b/thirdparty/icu4c/common/utext.cpp
@@ -382,7 +382,7 @@ utext_previous32From(UText *ut, int64_t index) {
//
UChar32 cPrev; // The character preceding cCurr, which is what we will return.
- // Address the chunk containg the position preceding the incoming index
+ // Address the chunk containing the position preceding the incoming index
// A tricky edge case:
// We try to test the requested native index against the chunkNativeStart to determine
// whether the character preceding the one at the index is in the current chunk.
@@ -894,7 +894,7 @@ struct UTF8Buf {
// one for a supplementary starting in the last normal position,
// and one for an entry for the buffer limit position.
uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to
- // correspoding offset in filled part of buf.
+ // corresponding offset in filled part of buf.
int32_t align;
};
@@ -1545,7 +1545,7 @@ utf8TextMapOffsetToNative(const UText *ut) {
}
//
-// Map a native index to the corrsponding chunk offset
+// Map a native index to the corresponding chunk offset
//
static int32_t U_CALLCONV
utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
diff --git a/thirdparty/icu4c/common/util.h b/thirdparty/icu4c/common/util.h
index 9c3b76d9ed..b5fac383a2 100644
--- a/thirdparty/icu4c/common/util.h
+++ b/thirdparty/icu4c/common/util.h
@@ -13,10 +13,10 @@
#ifndef ICU_UTIL_H
#define ICU_UTIL_H
-#include "unicode/utypes.h"
-#include "unicode/uobject.h"
+#include "charstr.h"
#include "unicode/unistr.h"
-
+#include "unicode/uobject.h"
+#include "unicode/utypes.h"
//--------------------------------------------------------------------
// class ICU_Utility
// i18n utility functions, scoped into the class ICU_Utility.
diff --git a/thirdparty/icu4c/common/utracimp.h b/thirdparty/icu4c/common/utracimp.h
index f32fe1db39..945540d25a 100644
--- a/thirdparty/icu4c/common/utracimp.h
+++ b/thirdparty/icu4c/common/utracimp.h
@@ -193,7 +193,7 @@ UPRV_BLOCK_MACRO_BEGIN { \
* Trace statement for each exit point of a function that has a UTRACE_ENTRY()
* statement, and that returns a value.
*
- * @param val The function's return value, int32_t or comatible type.
+ * @param val The function's return value, int32_t or compatible type.
*
* @internal
*/
diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp
index cf19edf646..9c7e74c6d5 100644
--- a/thirdparty/icu4c/common/uvector.cpp
+++ b/thirdparty/icu4c/common/uvector.cpp
@@ -312,7 +312,7 @@ int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
} else {
for (i=startIndex; i<count; ++i) {
/* Pointers are not always the same size as ints so to perform
- * a valid comparision we need to know whether we are being
+ * a valid comparison we need to know whether we are being
* provided an int or a pointer. */
if (hint & HINT_KEY_POINTER) {
if (key.pointer == elements[i].pointer) {
@@ -518,7 +518,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right)
}
/**
- * Sort the vector, assuming it constains ints.
+ * Sort the vector, assuming it contains ints.
* (A more general sort would take a comparison function, but it's
* not clear whether UVector's UElementComparator or
* UComparator from uprv_sortAray would be more appropriate.)
diff --git a/thirdparty/icu4c/common/wintz.cpp b/thirdparty/icu4c/common/wintz.cpp
index 580cedadb6..ebf31650c2 100644
--- a/thirdparty/icu4c/common/wintz.cpp
+++ b/thirdparty/icu4c/common/wintz.cpp
@@ -124,10 +124,26 @@ uprv_detectWindowsTimeZone()
// No way to support when DST is turned off and the offset in minutes is not a multiple of 60.
if (utcOffsetMins % 60 == 0) {
char gmtOffsetTz[11] = {}; // "Etc/GMT+dd" is 11-char long with a terminal null.
- // Note '-' before 'utcOffsetMin'. The timezone ID's sign convention
- // is that a timezone ahead of UTC is Etc/GMT-<offset> and a timezone
- // behind UTC is Etc/GMT+<offset>.
- int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", -utcOffsetMins / 60);
+ // Important note on the sign convention for zones:
+ //
+ // From https://en.wikipedia.org/wiki/Tz_database#Area
+ // "In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed
+ // from the standard ISO 8601 convention. In the "Etc" area, zones west of GMT have a positive sign and those
+ // east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT)."
+ //
+ // Regarding the POSIX style, from https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ // "The offset specifies the time value you must add to the local time to get a Coordinated Universal Time value."
+ //
+ // However, the Bias value in DYNAMIC_TIME_ZONE_INFORMATION *already* follows the POSIX convention.
+ //
+ // From https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
+ // "The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and
+ // local time. All translations between UTC and local time are based on the following formula:
+ // UTC = local time + bias"
+ //
+ // For example, a time zone that is 3 hours ahead of UTC (UTC+03:00) would have a Bias value of -180, and the
+ // corresponding time zone ID would be "Etc/GMT-3". (So there is no need to negate utcOffsetMins below.)
+ int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", utcOffsetMins / 60);
if (ret > 0 && ret < UPRV_LENGTHOF(gmtOffsetTz)) {
return uprv_strdup(gmtOffsetTz);
}
diff --git a/thirdparty/icu4c/icudt68l.dat b/thirdparty/icu4c/icudt69l.dat
index 9ecea5d548..3101a49695 100644
--- a/thirdparty/icu4c/icudt68l.dat
+++ b/thirdparty/icu4c/icudt69l.dat
Binary files differ
diff --git a/thirdparty/mbedtls/include/mbedtls/config.h b/thirdparty/mbedtls/include/mbedtls/config.h
index e17bc7e306..610f5d1f50 100644
--- a/thirdparty/mbedtls/include/mbedtls/config.h
+++ b/thirdparty/mbedtls/include/mbedtls/config.h
@@ -1747,6 +1747,23 @@
//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT
/**
+ * \def MBEDTLS_TEST_HOOKS
+ *
+ * Enable features for invasive testing such as introspection functions and
+ * hooks for fault injection. This enables additional unit tests.
+ *
+ * Merely enabling this feature should not change the behavior of the product.
+ * It only adds new code, and new branching points where the default behavior
+ * is the same as when this feature is disabled.
+ * However, this feature increases the attack surface: there is an added
+ * risk of vulnerabilities, and more gadgets that can make exploits easier.
+ * Therefore this feature must never be enabled in production.
+ *
+ * Uncomment to enable invasive tests.
+ */
+//#define MBEDTLS_TEST_HOOKS
+
+/**
* \def MBEDTLS_THREADING_ALT
*
* Provide your own alternate threading implementation.
diff --git a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
index 278fbbbb7a..6c099adf4d 100644
--- a/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/ctr_drbg.h
@@ -214,6 +214,13 @@ typedef struct mbedtls_ctr_drbg_context
void *p_entropy; /*!< The context for the entropy function. */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized if and only if f_entropy != NULL.
+ * This means that the mutex is initialized during the initial seeding
+ * in mbedtls_ctr_drbg_seed() and freed in mbedtls_ctr_drbg_free().
+ *
+ * Note that this invariant may change without notice. Do not rely on it
+ * and do not access the mutex directly in application code.
+ */
mbedtls_threading_mutex_t mutex;
#endif
}
@@ -277,6 +284,15 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
* device.
*/
#endif
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
/**
* \param ctx The CTR_DRBG context to seed.
* It must have been initialized with
@@ -286,6 +302,8 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
* the same context unless you call
* mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
* again first.
+ * After a failed call to mbedtls_ctr_drbg_seed(),
+ * you must call mbedtls_ctr_drbg_free().
* \param f_entropy The entropy callback, taking as arguments the
* \p p_entropy context, the buffer to fill, and the
* length of the buffer.
@@ -377,6 +395,11 @@ void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
* \brief This function reseeds the CTR_DRBG context, that is
* extracts data from the entropy source.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The CTR_DRBG context.
* \param additional Additional data to add to the state. Can be \c NULL.
* \param len The length of the additional data.
@@ -394,6 +417,11 @@ int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
/**
* \brief This function updates the state of the CTR_DRBG context.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The CTR_DRBG context.
* \param additional The data to update the state with. This must not be
* \c NULL unless \p add_len is \c 0.
@@ -417,6 +445,11 @@ int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
@@ -445,8 +478,16 @@ int mbedtls_ctr_drbg_random_with_add( void *p_rng,
*
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
- *
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param p_rng The CTR_DRBG context. This must be a pointer to a
* #mbedtls_ctr_drbg_context structure.
* \param output The buffer to fill.
diff --git a/thirdparty/mbedtls/include/mbedtls/entropy.h b/thirdparty/mbedtls/include/mbedtls/entropy.h
index 1e1d3f56ec..1d6e9b821b 100644
--- a/thirdparty/mbedtls/include/mbedtls/entropy.h
+++ b/thirdparty/mbedtls/include/mbedtls/entropy.h
@@ -147,13 +147,15 @@ mbedtls_entropy_source_state;
*/
typedef struct mbedtls_entropy_context
{
- int accumulator_started;
+ int accumulator_started; /* 0 after init.
+ * 1 after the first update.
+ * -1 after free. */
#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
mbedtls_sha512_context accumulator;
#else
mbedtls_sha256_context accumulator;
#endif
- int source_count;
+ int source_count; /* Number of entries used in source. */
mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES];
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_state havege_data;
diff --git a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
index 970c033c15..5718e187a9 100644
--- a/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
+++ b/thirdparty/mbedtls/include/mbedtls/hmac_drbg.h
@@ -128,6 +128,14 @@ typedef struct mbedtls_hmac_drbg_context
void *p_entropy; /*!< context for the entropy function */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized if and only if
+ * md_ctx->md_info != NULL. This means that the mutex is initialized
+ * during the initial seeding in mbedtls_hmac_drbg_seed() or
+ * mbedtls_hmac_drbg_seed_buf() and freed in mbedtls_ctr_drbg_free().
+ *
+ * Note that this invariant may change without notice. Do not rely on it
+ * and do not access the mutex directly in application code.
+ */
mbedtls_threading_mutex_t mutex;
#endif
} mbedtls_hmac_drbg_context;
@@ -177,7 +185,17 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx );
* \note During the initial seeding, this function calls
* the entropy source to obtain a nonce
* whose length is half the entropy length.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_hmac_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param ctx HMAC_DRBG context to be seeded.
* \param md_info MD algorithm to use for HMAC_DRBG.
* \param f_entropy The entropy callback, taking as arguments the
@@ -216,7 +234,17 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
*
* This function is meant for use in algorithms that need a pseudorandom
* input such as deterministic ECDSA.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * after this function returns successfully,
+ * it is safe to call mbedtls_hmac_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param ctx HMAC_DRBG context to be initialised.
* \param md_info MD algorithm to use for HMAC_DRBG.
* \param data Concatenation of the initial entropy string and
@@ -279,6 +307,11 @@ void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx,
/**
* \brief This function updates the state of the HMAC_DRBG context.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The HMAC_DRBG context.
* \param additional The data to update the state with.
* If this is \c NULL, there is no additional data.
@@ -295,6 +328,11 @@ int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx,
* \brief This function reseeds the HMAC_DRBG context, that is
* extracts data from the entropy source.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param ctx The HMAC_DRBG context.
* \param additional Additional data to add to the state.
* If this is \c NULL, there is no additional data
@@ -320,6 +358,11 @@ int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
*
+ * \note This function is not thread-safe. It is not safe
+ * to call this function if another thread might be
+ * concurrently obtaining random numbers from the same
+ * context or updating or reseeding the same context.
+ *
* \param p_rng The HMAC_DRBG context. This must be a pointer to a
* #mbedtls_hmac_drbg_context structure.
* \param output The buffer to fill.
@@ -349,7 +392,16 @@ int mbedtls_hmac_drbg_random_with_add( void *p_rng,
*
* This function automatically reseeds if the reseed counter is exceeded
* or prediction resistance is enabled.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note When Mbed TLS is built with threading support,
+ * it is safe to call mbedtls_ctr_drbg_random()
+ * from multiple threads. Other operations, including
+ * reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
* \param p_rng The HMAC_DRBG context. This must be a pointer to a
* #mbedtls_hmac_drbg_context structure.
* \param output The buffer to fill.
diff --git a/thirdparty/mbedtls/include/mbedtls/net_sockets.h b/thirdparty/mbedtls/include/mbedtls/net_sockets.h
index 00fea7db19..c6e1a0270e 100644
--- a/thirdparty/mbedtls/include/mbedtls/net_sockets.h
+++ b/thirdparty/mbedtls/include/mbedtls/net_sockets.h
@@ -151,6 +151,7 @@ int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char
*
* \return 0 if successful, or one of:
* MBEDTLS_ERR_NET_SOCKET_FAILED,
+ * MBEDTLS_ERR_NET_UNKNOWN_HOST,
* MBEDTLS_ERR_NET_BIND_FAILED,
* MBEDTLS_ERR_NET_LISTEN_FAILED
*
@@ -170,6 +171,8 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
* can be NULL if client_ip is null
*
* \return 0 if successful, or
+ * MBEDTLS_ERR_NET_SOCKET_FAILED,
+ * MBEDTLS_ERR_NET_BIND_FAILED,
* MBEDTLS_ERR_NET_ACCEPT_FAILED, or
* MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small,
* MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to
@@ -182,6 +185,10 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
/**
* \brief Check and wait for the context to be ready for read/write
*
+ * \note The current implementation of this function uses
+ * select() and returns an error if the file descriptor
+ * is \c FD_SETSIZE or greater.
+ *
* \param ctx Socket to check
* \param rw Bitflag composed of MBEDTLS_NET_POLL_READ and
* MBEDTLS_NET_POLL_WRITE specifying the events
@@ -263,16 +270,21 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len );
* 'timeout' seconds. If no error occurs, the actual amount
* read is returned.
*
+ * \note The current implementation of this function uses
+ * select() and returns an error if the file descriptor
+ * is \c FD_SETSIZE or greater.
+ *
* \param ctx Socket
* \param buf The buffer to write to
* \param len Maximum length of the buffer
* \param timeout Maximum number of milliseconds to wait for data
* 0 means no timeout (wait forever)
*
- * \return the number of bytes received,
- * or a non-zero error code:
- * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out,
+ * \return The number of bytes received if successful.
+ * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out.
* MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal.
+ * Another negative error code (MBEDTLS_ERR_NET_xxx)
+ * for other failures.
*
* \note This function will block (until data becomes available or
* timeout is reached) even if the socket is set to
diff --git a/thirdparty/mbedtls/include/mbedtls/rsa.h b/thirdparty/mbedtls/include/mbedtls/rsa.h
index 188c37cf3a..b2f65334fe 100644
--- a/thirdparty/mbedtls/include/mbedtls/rsa.h
+++ b/thirdparty/mbedtls/include/mbedtls/rsa.h
@@ -124,7 +124,10 @@ extern "C" {
*/
typedef struct mbedtls_rsa_context
{
- int ver; /*!< Always 0.*/
+ int ver; /*!< Reserved for internal purposes.
+ * Do not set this field in application
+ * code. Its meaning might change without
+ * notice. */
size_t len; /*!< The size of \p N in Bytes. */
mbedtls_mpi N; /*!< The public modulus. */
@@ -154,6 +157,7 @@ typedef struct mbedtls_rsa_context
mask generating function used in the
EME-OAEP and EMSA-PSS encodings. */
#if defined(MBEDTLS_THREADING_C)
+ /* Invariant: the mutex is initialized iff ver != 0. */
mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex. */
#endif
}
diff --git a/thirdparty/mbedtls/include/mbedtls/threading.h b/thirdparty/mbedtls/include/mbedtls/threading.h
index a8183a6ef4..45161ce467 100644
--- a/thirdparty/mbedtls/include/mbedtls/threading.h
+++ b/thirdparty/mbedtls/include/mbedtls/threading.h
@@ -73,6 +73,9 @@ extern "C" {
typedef struct mbedtls_threading_mutex_t
{
pthread_mutex_t mutex;
+ /* is_valid is 0 after a failed init or a free, and nonzero after a
+ * successful init. This field is not considered part of the public
+ * API of Mbed TLS and may change without notice. */
char is_valid;
} mbedtls_threading_mutex_t;
#endif
diff --git a/thirdparty/mbedtls/include/mbedtls/version.h b/thirdparty/mbedtls/include/mbedtls/version.h
index 5f0a8f114c..bd5c730c1d 100644
--- a/thirdparty/mbedtls/include/mbedtls/version.h
+++ b/thirdparty/mbedtls/include/mbedtls/version.h
@@ -65,16 +65,16 @@
*/
#define MBEDTLS_VERSION_MAJOR 2
#define MBEDTLS_VERSION_MINOR 16
-#define MBEDTLS_VERSION_PATCH 9
+#define MBEDTLS_VERSION_PATCH 10
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x02100900
-#define MBEDTLS_VERSION_STRING "2.16.9"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.9"
+#define MBEDTLS_VERSION_NUMBER 0x02100A00
+#define MBEDTLS_VERSION_STRING "2.16.10"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.16.10"
#if defined(MBEDTLS_VERSION_C)
diff --git a/thirdparty/mbedtls/library/base64.c b/thirdparty/mbedtls/library/base64.c
index bfafb05353..692e11e3fa 100644
--- a/thirdparty/mbedtls/library/base64.c
+++ b/thirdparty/mbedtls/library/base64.c
@@ -97,6 +97,99 @@ static const unsigned char base64_dec_map[128] =
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
+ * Constant flow conditional assignment to unsigned char
+ */
+static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src,
+ unsigned char condition )
+{
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ /* Generate bitmask from condition, mask will either be 0xFF or 0 */
+ unsigned char mask = ( condition | -condition );
+ mask >>= 7;
+ mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow conditional assignment to uint_32
+ */
+static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src,
+ uint32_t condition )
+{
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
+ uint32_t mask = ( condition | -condition );
+ mask >>= 31;
+ mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ *dest = ( src & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow check for equality
+ */
+static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b )
+{
+ size_t difference = in_a ^ in_b;
+
+ /* MSVC has a warning about unary minus on unsigned integer types,
+ * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+ difference |= -difference;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+ /* cope with the varying size of size_t per platform */
+ difference >>= ( sizeof( difference ) * 8 - 1 );
+
+ return (unsigned char) ( 1 ^ difference );
+}
+
+/*
+ * Constant flow lookup into table.
+ */
+static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table,
+ const size_t table_size, const size_t table_index )
+{
+ size_t i;
+ unsigned char result = 0;
+
+ for( i = 0; i < table_size; ++i )
+ {
+ mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) );
+ }
+
+ return result;
+}
+
+/*
* Encode a buffer into base64 format
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
@@ -136,10 +229,17 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
C2 = *src++;
C3 = *src++;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
- *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
- *p++ = base64_enc_map[C3 & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( C1 >> 2 ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( C3 & 0x3F ) );
}
if( i < slen )
@@ -147,11 +247,15 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
C1 = *src++;
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
- *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
- *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( C1 >> 2 ) & 0x3F ) );
+
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
if( ( i + 1 ) < slen )
- *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+ *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+ ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
else *p++ = '=';
*p++ = '=';
@@ -172,6 +276,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
size_t i, n;
uint32_t j, x;
unsigned char *p;
+ unsigned char dec_map_lookup;
/* First pass: check for validity and get output length */
for( i = n = j = 0; i < slen; i++ )
@@ -202,10 +307,12 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
if( src[i] == '=' && ++j > 2 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
- if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+ dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
+
+ if( src[i] > 127 || dec_map_lookup == 127 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
- if( base64_dec_map[src[i]] < 64 && j != 0 )
+ if( dec_map_lookup < 64 && j != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
n++;
@@ -235,8 +342,10 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
if( *src == '\r' || *src == '\n' || *src == ' ' )
continue;
- j -= ( base64_dec_map[*src] == 64 );
- x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
+ dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src );
+
+ mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) );
+ x = ( x << 6 ) | ( dec_map_lookup & 0x3F );
if( ++n == 4 )
{
diff --git a/thirdparty/mbedtls/library/bignum.c b/thirdparty/mbedtls/library/bignum.c
index 2feb727d89..f133f6c13c 100644
--- a/thirdparty/mbedtls/library/bignum.c
+++ b/thirdparty/mbedtls/library/bignum.c
@@ -1354,6 +1354,12 @@ int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
for( n = B->n; n > 0; n-- )
if( B->p[n - 1] != 0 )
break;
+ if( n > A->n )
+ {
+ /* B >= (2^ciL)^n > A */
+ ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
+ goto cleanup;
+ }
carry = mpi_sub_hlp( n, X->p, B->p );
if( carry != 0 )
diff --git a/thirdparty/mbedtls/library/ctr_drbg.c b/thirdparty/mbedtls/library/ctr_drbg.c
index e92008bbe8..90264e844a 100644
--- a/thirdparty/mbedtls/library/ctr_drbg.c
+++ b/thirdparty/mbedtls/library/ctr_drbg.c
@@ -83,10 +83,6 @@ void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
/*
@@ -99,14 +95,13 @@ void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
return;
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* The mutex is initialized iff f_entropy is set. */
+ if( ctx->f_entropy != NULL )
+ mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_aes_free( &ctx->aes_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
@@ -422,6 +417,11 @@ int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
+ /* The mutex is initialized iff f_entropy is set. */
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
mbedtls_aes_init( &ctx->aes_ctx );
ctx->f_entropy = f_entropy;
diff --git a/thirdparty/mbedtls/library/ecdsa.c b/thirdparty/mbedtls/library/ecdsa.c
index da8df9cde2..2456238b17 100644
--- a/thirdparty/mbedtls/library/ecdsa.c
+++ b/thirdparty/mbedtls/library/ecdsa.c
@@ -247,6 +247,9 @@ static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx )
#endif /* MBEDTLS_ECP_RESTARTABLE */
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC) || \
+ !defined(MBEDTLS_ECDSA_SIGN_ALT) || \
+ !defined(MBEDTLS_ECDSA_VERIFY_ALT)
/*
* Derive a suitable integer for group grp from a buffer of length len
* SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
@@ -269,6 +272,7 @@ static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x,
cleanup:
return( ret );
}
+#endif /* ECDSA_DETERMINISTIC || !ECDSA_SIGN_ALT || !ECDSA_VERIFY_ALT */
#if !defined(MBEDTLS_ECDSA_SIGN_ALT)
/*
@@ -780,6 +784,8 @@ int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx,
(void) md_alg;
#if defined(MBEDTLS_ECDSA_SIGN_ALT)
+ (void) rs_ctx;
+
MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
hash, hlen, f_rng, p_rng ) );
#else
@@ -888,6 +894,8 @@ int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx,
goto cleanup;
}
#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
+ (void) rs_ctx;
+
if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
&ctx->Q, &r, &s ) ) != 0 )
goto cleanup;
diff --git a/thirdparty/mbedtls/library/ecjpake.c b/thirdparty/mbedtls/library/ecjpake.c
index f6e24580c7..0532a295e6 100644
--- a/thirdparty/mbedtls/library/ecjpake.c
+++ b/thirdparty/mbedtls/library/ecjpake.c
@@ -850,6 +850,8 @@ static const unsigned char ecjpake_test_password[] = {
0x65, 0x73, 0x74
};
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+
static const unsigned char ecjpake_test_x1[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
@@ -994,6 +996,8 @@ cleanup:
return( ret );
}
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
+
/* For tests we don't need a secure RNG;
* use the LGC from Numerical Recipes for simplicity */
static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
@@ -1089,6 +1093,12 @@ int mbedtls_ecjpake_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "passed\n" );
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+ /* 'reference handshake' tests can only be run against implementations
+ * for which we have 100% control over how the random ephemeral keys
+ * are generated. This is only the case for the internal mbed TLS
+ * implementation, so these tests are skipped in case the internal
+ * implementation is swapped out for an alternative one. */
if( verbose != 0 )
mbedtls_printf( " ECJPAKE test #2 (reference handshake): " );
@@ -1137,6 +1147,7 @@ int mbedtls_ecjpake_self_test( int verbose )
if( verbose != 0 )
mbedtls_printf( "passed\n" );
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
cleanup:
mbedtls_ecjpake_free( &cli );
diff --git a/thirdparty/mbedtls/library/entropy.c b/thirdparty/mbedtls/library/entropy.c
index 666c55654c..c5f414a010 100644
--- a/thirdparty/mbedtls/library/entropy.c
+++ b/thirdparty/mbedtls/library/entropy.c
@@ -146,6 +146,11 @@ void mbedtls_entropy_init( mbedtls_entropy_context *ctx )
void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
{
+ /* If the context was already free, don't call free() again.
+ * This is important for mutexes which don't allow double-free. */
+ if( ctx->accumulator_started == -1 )
+ return;
+
#if defined(MBEDTLS_HAVEGE_C)
mbedtls_havege_free( &ctx->havege_data );
#endif
@@ -162,7 +167,7 @@ void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
#endif
ctx->source_count = 0;
mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
- ctx->accumulator_started = 0;
+ ctx->accumulator_started = -1;
}
int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
diff --git a/thirdparty/mbedtls/library/hmac_drbg.c b/thirdparty/mbedtls/library/hmac_drbg.c
index 10cbd462ba..b45d61616f 100644
--- a/thirdparty/mbedtls/library/hmac_drbg.c
+++ b/thirdparty/mbedtls/library/hmac_drbg.c
@@ -84,10 +84,6 @@ void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
/*
@@ -159,6 +155,10 @@ int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
/*
* Set initial working state.
* Use the V memory location, which is currently all 0, to initialize the
@@ -284,6 +284,11 @@ int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
return( ret );
+ /* The mutex is initialized iff the md context is set up. */
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
+
md_size = mbedtls_md_get_size( md_info );
/*
@@ -451,14 +456,13 @@ void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
return;
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* The mutex is initialized iff the md context is set up. */
+ if( ctx->md_ctx.md_info != NULL )
+ mbedtls_mutex_free( &ctx->mutex );
#endif
mbedtls_md_free( &ctx->md_ctx );
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_init( &ctx->mutex );
-#endif
}
#if defined(MBEDTLS_FS_IO)
diff --git a/thirdparty/mbedtls/library/net_sockets.c b/thirdparty/mbedtls/library/net_sockets.c
index 1130408263..671115f15f 100644
--- a/thirdparty/mbedtls/library/net_sockets.c
+++ b/thirdparty/mbedtls/library/net_sockets.c
@@ -496,6 +496,13 @@ int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout )
if( fd < 0 )
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
+ /* A limitation of select() is that it only works with file descriptors
+ * that are strictly less than FD_SETSIZE. This is a limitation of the
+ * fd_set type. Error out early, because attempting to call FD_SET on a
+ * large file descriptor is a buffer overflow on typical platforms. */
+ if( fd >= FD_SETSIZE )
+ return( MBEDTLS_ERR_NET_POLL_FAILED );
+
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
/* Ensure that memory sanitizers consider read_fds and write_fds as
@@ -615,6 +622,13 @@ int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf,
if( fd < 0 )
return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
+ /* A limitation of select() is that it only works with file descriptors
+ * that are strictly less than FD_SETSIZE. This is a limitation of the
+ * fd_set type. Error out early, because attempting to call FD_SET on a
+ * large file descriptor is a buffer overflow on typical platforms. */
+ if( fd >= FD_SETSIZE )
+ return( MBEDTLS_ERR_NET_POLL_FAILED );
+
FD_ZERO( &read_fds );
FD_SET( fd, &read_fds );
diff --git a/thirdparty/mbedtls/library/pkwrite.c b/thirdparty/mbedtls/library/pkwrite.c
index 150626c147..a770dfb93e 100644
--- a/thirdparty/mbedtls/library/pkwrite.c
+++ b/thirdparty/mbedtls/library/pkwrite.c
@@ -455,7 +455,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1
* }
*/
-#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE
+#define RSA_PUB_DER_MAX_BYTES ( 38 + 2 * MBEDTLS_MPI_MAX_SIZE )
/*
* RSA private keys:
@@ -472,10 +472,10 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported)
* }
*/
-#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \
- MBEDTLS_MPI_MAX_SIZE % 2
-#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
- + 5 * MPI_MAX_SIZE_2
+#define MPI_MAX_SIZE_2 ( MBEDTLS_MPI_MAX_SIZE / 2 + \
+ MBEDTLS_MPI_MAX_SIZE % 2 )
+#define RSA_PRV_DER_MAX_BYTES ( 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
+ + 5 * MPI_MAX_SIZE_2 )
#else /* MBEDTLS_RSA_C */
@@ -496,7 +496,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* + 2 * ECP_MAX (coords) [1]
* }
*/
-#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PUB_DER_MAX_BYTES ( 30 + 2 * MBEDTLS_ECP_MAX_BYTES )
/*
* EC private keys:
@@ -507,7 +507,7 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
* publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above
* }
*/
-#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PRV_DER_MAX_BYTES ( 29 + 3 * MBEDTLS_ECP_MAX_BYTES )
#else /* MBEDTLS_ECP_C */
@@ -516,10 +516,10 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
#endif /* MBEDTLS_ECP_C */
-#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
- RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES
-#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
- RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES
+#define PUB_DER_MAX_BYTES ( RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES )
+#define PRV_DER_MAX_BYTES ( RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
+ RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES )
int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
diff --git a/thirdparty/mbedtls/library/rsa.c b/thirdparty/mbedtls/library/rsa.c
index a25c633bc6..c8c23dba8c 100644
--- a/thirdparty/mbedtls/library/rsa.c
+++ b/thirdparty/mbedtls/library/rsa.c
@@ -520,6 +520,9 @@ void mbedtls_rsa_init( mbedtls_rsa_context *ctx,
mbedtls_rsa_set_padding( ctx, padding, hash_id );
#if defined(MBEDTLS_THREADING_C)
+ /* Set ctx->ver to nonzero to indicate that the mutex has been
+ * initialized and will need to be freed. */
+ ctx->ver = 1;
mbedtls_mutex_init( &ctx->mutex );
#endif
}
@@ -567,9 +570,6 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
RSA_VALIDATE_RET( ctx != NULL );
RSA_VALIDATE_RET( f_rng != NULL );
- if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
- return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
/*
* If the modulus is 1024 bit long or shorter, then the security strength of
* the RSA algorithm is less than or equal to 80 bits and therefore an error
@@ -582,6 +582,12 @@ int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx,
mbedtls_mpi_init( &G );
mbedtls_mpi_init( &L );
+ if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
+ {
+ ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+ goto cleanup;
+ }
+
/*
* find primes P and Q with Q < P so that:
* 1. |P-Q| > 2^( nbits / 2 - 100 )
@@ -659,7 +665,9 @@ cleanup:
if( ret != 0 )
{
mbedtls_rsa_free( ctx );
- return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
+ if( ( -ret & ~0x7f ) == 0 )
+ ret = MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret;
+ return( ret );
}
return( 0 );
@@ -1106,10 +1114,10 @@ cleanup:
mbedtls_mpi_free( &C );
mbedtls_mpi_free( &I );
- if( ret != 0 )
+ if( ret != 0 && ret >= -0x007f )
return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
- return( 0 );
+ return( ret );
}
#if defined(MBEDTLS_PKCS1_V21)
@@ -2502,7 +2510,6 @@ int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src )
RSA_VALIDATE_RET( dst != NULL );
RSA_VALIDATE_RET( src != NULL );
- dst->ver = src->ver;
dst->len = src->len;
MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
@@ -2561,7 +2568,12 @@ void mbedtls_rsa_free( mbedtls_rsa_context *ctx )
#endif /* MBEDTLS_RSA_NO_CRT */
#if defined(MBEDTLS_THREADING_C)
- mbedtls_mutex_free( &ctx->mutex );
+ /* Free the mutex, but only if it hasn't been freed already. */
+ if( ctx->ver != 0 )
+ {
+ mbedtls_mutex_free( &ctx->mutex );
+ ctx->ver = 0;
+ }
#endif
}
diff --git a/thirdparty/mbedtls/library/threading.c b/thirdparty/mbedtls/library/threading.c
index f4f29cff5e..0dc5488c1a 100644
--- a/thirdparty/mbedtls/library/threading.c
+++ b/thirdparty/mbedtls/library/threading.c
@@ -98,6 +98,12 @@ static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
if( mutex == NULL )
return;
+ /* A nonzero value of is_valid indicates a successfully initialized
+ * mutex. This is a workaround for not being able to return an error
+ * code for this function. The lock/unlock functions return an error
+ * if is_valid is nonzero. The Mbed TLS unit test code uses this field
+ * to distinguish more states of the mutex; see helpers.function for
+ * details. */
mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0;
}
diff --git a/thirdparty/mbedtls/library/version_features.c b/thirdparty/mbedtls/library/version_features.c
index cbf38dc2c2..8c8e815e9d 100644
--- a/thirdparty/mbedtls/library/version_features.c
+++ b/thirdparty/mbedtls/library/version_features.c
@@ -553,6 +553,9 @@ static const char *features[] = {
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT)
"MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT",
#endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */
+#if defined(MBEDTLS_TEST_HOOKS)
+ "MBEDTLS_TEST_HOOKS",
+#endif /* MBEDTLS_TEST_HOOKS */
#if defined(MBEDTLS_THREADING_ALT)
"MBEDTLS_THREADING_ALT",
#endif /* MBEDTLS_THREADING_ALT */
diff --git a/thirdparty/meshoptimizer/LICENSE.md b/thirdparty/meshoptimizer/LICENSE.md
index 4fcd766d22..3c52415f62 100644
--- a/thirdparty/meshoptimizer/LICENSE.md
+++ b/thirdparty/meshoptimizer/LICENSE.md
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016-2020 Arseny Kapoulkine
+Copyright (c) 2016-2021 Arseny Kapoulkine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp
index f7d88c5136..f8aad7b49c 100644
--- a/thirdparty/meshoptimizer/clusterizer.cpp
+++ b/thirdparty/meshoptimizer/clusterizer.cpp
@@ -2,6 +2,7 @@
#include "meshoptimizer.h"
#include <assert.h>
+#include <float.h>
#include <math.h>
#include <string.h>
@@ -12,6 +13,68 @@
namespace meshopt
{
+// This must be <= 255 since index 0xff is used internally to indice a vertex that doesn't belong to a meshlet
+const size_t kMeshletMaxVertices = 255;
+
+// A reasonable limit is around 2*max_vertices or less
+const size_t kMeshletMaxTriangles = 512;
+
+struct TriangleAdjacency2
+{
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+};
+
+static void buildTriangleAdjacency(TriangleAdjacency2& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator)
+{
+ size_t face_count = index_count / 3;
+
+ // allocate arrays
+ adjacency.counts = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.offsets = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.data = allocator.allocate<unsigned int>(index_count);
+
+ // fill triangle counts
+ memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ assert(indices[i] < vertex_count);
+
+ adjacency.counts[indices[i]]++;
+ }
+
+ // fill offset table
+ unsigned int offset = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ adjacency.offsets[i] = offset;
+ offset += adjacency.counts[i];
+ }
+
+ assert(offset == index_count);
+
+ // fill triangle data
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+
+ adjacency.data[adjacency.offsets[a]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[b]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[c]++] = unsigned(i);
+ }
+
+ // fix offsets that have been disturbed by the previous pass
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ assert(adjacency.offsets[i] >= adjacency.counts[i]);
+
+ adjacency.offsets[i] -= adjacency.counts[i];
+ }
+}
+
static void computeBoundingSphere(float result[4], const float points[][3], size_t count)
{
assert(count > 0);
@@ -82,13 +145,310 @@ static void computeBoundingSphere(float result[4], const float points[][3], size
result[3] = radius;
}
+struct Cone
+{
+ float px, py, pz;
+ float nx, ny, nz;
+};
+
+static float getMeshletScore(float distance2, float spread, float cone_weight, float expected_radius)
+{
+ float cone = 1.f - spread * cone_weight;
+ float cone_clamped = cone < 1e-3f ? 1e-3f : cone;
+
+ return (1 + sqrtf(distance2) / expected_radius * (1 - cone_weight)) * cone_clamped;
+}
+
+static Cone getMeshletCone(const Cone& acc, unsigned int triangle_count)
+{
+ Cone result = acc;
+
+ float center_scale = triangle_count == 0 ? 0.f : 1.f / float(triangle_count);
+
+ result.px *= center_scale;
+ result.py *= center_scale;
+ result.pz *= center_scale;
+
+ float axis_length = result.nx * result.nx + result.ny * result.ny + result.nz * result.nz;
+ float axis_scale = axis_length == 0.f ? 0.f : 1.f / sqrtf(axis_length);
+
+ result.nx *= axis_scale;
+ result.ny *= axis_scale;
+ result.nz *= axis_scale;
+
+ return result;
+}
+
+static float computeTriangleCones(Cone* triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ (void)vertex_count;
+
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+ size_t face_count = index_count / 3;
+
+ float mesh_area = 0;
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ const float* p0 = vertex_positions + vertex_stride_float * a;
+ const float* p1 = vertex_positions + vertex_stride_float * b;
+ const float* p2 = vertex_positions + vertex_stride_float * c;
+
+ float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
+ float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
+
+ float normalx = p10[1] * p20[2] - p10[2] * p20[1];
+ float normaly = p10[2] * p20[0] - p10[0] * p20[2];
+ float normalz = p10[0] * p20[1] - p10[1] * p20[0];
+
+ float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);
+ float invarea = (area == 0.f) ? 0.f : 1.f / area;
+
+ triangles[i].px = (p0[0] + p1[0] + p2[0]) / 3.f;
+ triangles[i].py = (p0[1] + p1[1] + p2[1]) / 3.f;
+ triangles[i].pz = (p0[2] + p1[2] + p2[2]) / 3.f;
+
+ triangles[i].nx = normalx * invarea;
+ triangles[i].ny = normaly * invarea;
+ triangles[i].nz = normalz * invarea;
+
+ mesh_area += area;
+ }
+
+ return mesh_area;
+}
+
+static void finishMeshlet(meshopt_Meshlet& meshlet, unsigned char* meshlet_triangles)
+{
+ size_t offset = meshlet.triangle_offset + meshlet.triangle_count * 3;
+
+ // fill 4b padding with 0
+ while (offset & 3)
+ meshlet_triangles[offset++] = 0;
+}
+
+static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, unsigned char* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles)
+{
+ unsigned char& av = used[a];
+ unsigned char& bv = used[b];
+ unsigned char& cv = used[c];
+
+ bool result = false;
+
+ unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
+
+ if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
+ {
+ meshlets[meshlet_offset] = meshlet;
+
+ for (size_t j = 0; j < meshlet.vertex_count; ++j)
+ used[meshlet_vertices[meshlet.vertex_offset + j]] = 0xff;
+
+ finishMeshlet(meshlet, meshlet_triangles);
+
+ meshlet.vertex_offset += meshlet.vertex_count;
+ meshlet.triangle_offset += (meshlet.triangle_count * 3 + 3) & ~3; // 4b padding
+ meshlet.vertex_count = 0;
+ meshlet.triangle_count = 0;
+
+ result = true;
+ }
+
+ if (av == 0xff)
+ {
+ av = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = a;
+ }
+
+ if (bv == 0xff)
+ {
+ bv = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = b;
+ }
+
+ if (cv == 0xff)
+ {
+ cv = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = c;
+ }
+
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = av;
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = bv;
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = cv;
+ meshlet.triangle_count++;
+
+ return result;
+}
+
+struct KDNode
+{
+ union
+ {
+ float split;
+ unsigned int index;
+ };
+
+ // leaves: axis = 3, children = number of extra points after this one (0 if 'index' is the only point)
+ // branches: axis != 3, left subtree = skip 1, right subtree = skip 1+children
+ unsigned int axis : 2;
+ unsigned int children : 30;
+};
+
+static size_t kdtreePartition(unsigned int* indices, size_t count, const float* points, size_t stride, unsigned int axis, float pivot)
+{
+ size_t m = 0;
+
+ // invariant: elements in range [0, m) are < pivot, elements in range [m, i) are >= pivot
+ for (size_t i = 0; i < count; ++i)
+ {
+ float v = points[indices[i] * stride + axis];
+
+ // swap(m, i) unconditionally
+ unsigned int t = indices[m];
+ indices[m] = indices[i];
+ indices[i] = t;
+
+ // when v >= pivot, we swap i with m without advancing it, preserving invariants
+ m += v < pivot;
+ }
+
+ return m;
+}
+
+static size_t kdtreeBuildLeaf(size_t offset, KDNode* nodes, size_t node_count, unsigned int* indices, size_t count)
+{
+ assert(offset + count <= node_count);
+ (void)node_count;
+
+ KDNode& result = nodes[offset];
+
+ result.index = indices[0];
+ result.axis = 3;
+ result.children = unsigned(count - 1);
+
+ // all remaining points are stored in nodes immediately following the leaf
+ for (size_t i = 1; i < count; ++i)
+ {
+ KDNode& tail = nodes[offset + i];
+
+ tail.index = indices[i];
+ tail.axis = 3;
+ tail.children = ~0u >> 2; // bogus value to prevent misuse
+ }
+
+ return offset + count;
+}
+
+static size_t kdtreeBuild(size_t offset, KDNode* nodes, size_t node_count, const float* points, size_t stride, unsigned int* indices, size_t count, size_t leaf_size)
+{
+ assert(count > 0);
+ assert(offset < node_count);
+
+ if (count <= leaf_size)
+ return kdtreeBuildLeaf(offset, nodes, node_count, indices, count);
+
+ float mean[3] = {};
+ float vars[3] = {};
+ float runc = 1, runs = 1;
+
+ // gather statistics on the points in the subtree using Welford's algorithm
+ for (size_t i = 0; i < count; ++i, runc += 1.f, runs = 1.f / runc)
+ {
+ const float* point = points + indices[i] * stride;
+
+ for (int k = 0; k < 3; ++k)
+ {
+ float delta = point[k] - mean[k];
+ mean[k] += delta * runs;
+ vars[k] += delta * (point[k] - mean[k]);
+ }
+ }
+
+ // split axis is one where the variance is largest
+ unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1
+ : 2;
+
+ float split = mean[axis];
+ size_t middle = kdtreePartition(indices, count, points, stride, axis, split);
+
+ // when the partition is degenerate simply consolidate the points into a single node
+ if (middle <= leaf_size / 2 || middle >= count - leaf_size / 2)
+ return kdtreeBuildLeaf(offset, nodes, node_count, indices, count);
+
+ KDNode& result = nodes[offset];
+
+ result.split = split;
+ result.axis = axis;
+
+ // left subtree is right after our node
+ size_t next_offset = kdtreeBuild(offset + 1, nodes, node_count, points, stride, indices, middle, leaf_size);
+
+ // distance to the right subtree is represented explicitly
+ result.children = unsigned(next_offset - offset - 1);
+
+ return kdtreeBuild(next_offset, nodes, node_count, points, stride, indices + middle, count - middle, leaf_size);
+}
+
+static void kdtreeNearest(KDNode* nodes, unsigned int root, const float* points, size_t stride, const unsigned char* emitted_flags, const float* position, unsigned int& result, float& limit)
+{
+ const KDNode& node = nodes[root];
+
+ if (node.axis == 3)
+ {
+ // leaf
+ for (unsigned int i = 0; i <= node.children; ++i)
+ {
+ unsigned int index = nodes[root + i].index;
+
+ if (emitted_flags[index])
+ continue;
+
+ const float* point = points + index * stride;
+
+ float distance2 =
+ (point[0] - position[0]) * (point[0] - position[0]) +
+ (point[1] - position[1]) * (point[1] - position[1]) +
+ (point[2] - position[2]) * (point[2] - position[2]);
+ float distance = sqrtf(distance2);
+
+ if (distance < limit)
+ {
+ result = index;
+ limit = distance;
+ }
+ }
+ }
+ else
+ {
+ // branch; we order recursion to process the node that search position is in first
+ float delta = position[node.axis] - node.split;
+ unsigned int first = (delta <= 0) ? 0 : node.children;
+ unsigned int second = first ^ node.children;
+
+ kdtreeNearest(nodes, root + 1 + first, points, stride, emitted_flags, position, result, limit);
+
+ // only process the other node if it can have a match based on closest distance so far
+ if (fabsf(delta) <= limit)
+ kdtreeNearest(nodes, root + 1 + second, points, stride, emitted_flags, position, result, limit);
+ }
+}
+
} // namespace meshopt
size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles)
{
+ using namespace meshopt;
+
assert(index_count % 3 == 0);
- assert(max_vertices >= 3);
- assert(max_triangles >= 1);
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
+
+ (void)kMeshletMaxVertices;
+ (void)kMeshletMaxTriangles;
// meshlet construction is limited by max vertices and max triangles per meshlet
// the worst case is that the input is an unindexed stream since this equally stresses both limits
@@ -100,77 +460,226 @@ size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_
return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles;
}
-size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight)
{
+ using namespace meshopt;
+
assert(index_count % 3 == 0);
- assert(max_vertices >= 3);
- assert(max_triangles >= 1);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
meshopt_Allocator allocator;
- meshopt_Meshlet meshlet;
- memset(&meshlet, 0, sizeof(meshlet));
+ TriangleAdjacency2 adjacency = {};
+ buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator);
+
+ unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count);
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
+
+ size_t face_count = index_count / 3;
+
+ unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count);
+ memset(emitted_flags, 0, face_count);
+
+ // for each triangle, precompute centroid & normal to use for scoring
+ Cone* triangles = allocator.allocate<Cone>(face_count);
+ float mesh_area = computeTriangleCones(triangles, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+
+ // assuming each meshlet is a square patch, expected radius is sqrt(expected area)
+ float triangle_area_avg = face_count == 0 ? 0.f : mesh_area / float(face_count) * 0.5f;
+ float meshlet_expected_radius = sqrtf(triangle_area_avg * max_triangles) * 0.5f;
+
+ // build a kd-tree for nearest neighbor lookup
+ unsigned int* kdindices = allocator.allocate<unsigned int>(face_count);
+ for (size_t i = 0; i < face_count; ++i)
+ kdindices[i] = unsigned(i);
- assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0]));
- assert(max_triangles <= sizeof(meshlet.indices) / 3);
+ KDNode* nodes = allocator.allocate<KDNode>(face_count * 2);
+ kdtreeBuild(0, nodes, face_count * 2, &triangles[0].px, sizeof(Cone) / sizeof(float), kdindices, face_count, /* leaf_size= */ 8);
// index of the vertex in the meshlet, 0xff if the vertex isn't used
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
memset(used, -1, vertex_count);
- size_t offset = 0;
+ meshopt_Meshlet meshlet = {};
+ size_t meshlet_offset = 0;
- for (size_t i = 0; i < index_count; i += 3)
- {
- unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
- assert(a < vertex_count && b < vertex_count && c < vertex_count);
+ Cone meshlet_cone_acc = {};
- unsigned char& av = used[a];
- unsigned char& bv = used[b];
- unsigned char& cv = used[c];
+ for (;;)
+ {
+ unsigned int best_triangle = ~0u;
+ unsigned int best_extra = 5;
+ float best_score = FLT_MAX;
- unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
+ Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
- if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
+ for (size_t i = 0; i < meshlet.vertex_count; ++i)
{
- destination[offset++] = meshlet;
+ unsigned int index = meshlet_vertices[meshlet.vertex_offset + i];
+
+ unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
+ size_t neighbours_size = adjacency.counts[index];
+
+ for (size_t j = 0; j < neighbours_size; ++j)
+ {
+ unsigned int triangle = neighbours[j];
+ assert(!emitted_flags[triangle]);
+
+ unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
+
+ // triangles that don't add new vertices to meshlets are max. priority
+ if (extra != 0)
+ {
+ // artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
+ if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
+ extra = 0;
+
+ extra++;
+ }
+
+ // since topology-based priority is always more important than the score, we can skip scoring in some cases
+ if (extra > best_extra)
+ continue;
+
+ const Cone& tri_cone = triangles[triangle];
+
+ float distance2 =
+ (tri_cone.px - meshlet_cone.px) * (tri_cone.px - meshlet_cone.px) +
+ (tri_cone.py - meshlet_cone.py) * (tri_cone.py - meshlet_cone.py) +
+ (tri_cone.pz - meshlet_cone.pz) * (tri_cone.pz - meshlet_cone.pz);
- for (size_t j = 0; j < meshlet.vertex_count; ++j)
- used[meshlet.vertices[j]] = 0xff;
+ float spread = tri_cone.nx * meshlet_cone.nx + tri_cone.ny * meshlet_cone.ny + tri_cone.nz * meshlet_cone.nz;
- memset(&meshlet, 0, sizeof(meshlet));
+ float score = getMeshletScore(distance2, spread, cone_weight, meshlet_expected_radius);
+
+ // note that topology-based priority is always more important than the score
+ // this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
+ if (extra < best_extra || score < best_score)
+ {
+ best_triangle = triangle;
+ best_extra = extra;
+ best_score = score;
+ }
+ }
}
- if (av == 0xff)
+ if (best_triangle == ~0u)
{
- av = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = a;
+ float position[3] = {meshlet_cone.px, meshlet_cone.py, meshlet_cone.pz};
+ unsigned int index = ~0u;
+ float limit = FLT_MAX;
+
+ kdtreeNearest(nodes, 0, &triangles[0].px, sizeof(Cone) / sizeof(float), emitted_flags, position, index, limit);
+
+ best_triangle = index;
}
- if (bv == 0xff)
+ if (best_triangle == ~0u)
+ break;
+
+ unsigned int a = indices[best_triangle * 3 + 0], b = indices[best_triangle * 3 + 1], c = indices[best_triangle * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ // add meshlet to the output; when the current meshlet is full we reset the accumulated bounds
+ if (appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles))
{
- bv = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = b;
+ meshlet_offset++;
+ memset(&meshlet_cone_acc, 0, sizeof(meshlet_cone_acc));
}
- if (cv == 0xff)
+ live_triangles[a]--;
+ live_triangles[b]--;
+ live_triangles[c]--;
+
+ // remove emitted triangle from adjacency data
+ // this makes sure that we spend less time traversing these lists on subsequent iterations
+ for (size_t k = 0; k < 3; ++k)
{
- cv = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = c;
+ unsigned int index = indices[best_triangle * 3 + k];
+
+ unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
+ size_t neighbours_size = adjacency.counts[index];
+
+ for (size_t i = 0; i < neighbours_size; ++i)
+ {
+ unsigned int tri = neighbours[i];
+
+ if (tri == best_triangle)
+ {
+ neighbours[i] = neighbours[neighbours_size - 1];
+ adjacency.counts[index]--;
+ break;
+ }
+ }
}
- meshlet.indices[meshlet.triangle_count][0] = av;
- meshlet.indices[meshlet.triangle_count][1] = bv;
- meshlet.indices[meshlet.triangle_count][2] = cv;
- meshlet.triangle_count++;
+ // update aggregated meshlet cone data for scoring subsequent triangles
+ meshlet_cone_acc.px += triangles[best_triangle].px;
+ meshlet_cone_acc.py += triangles[best_triangle].py;
+ meshlet_cone_acc.pz += triangles[best_triangle].pz;
+ meshlet_cone_acc.nx += triangles[best_triangle].nx;
+ meshlet_cone_acc.ny += triangles[best_triangle].ny;
+ meshlet_cone_acc.nz += triangles[best_triangle].nz;
+
+ emitted_flags[best_triangle] = 1;
+ }
+
+ if (meshlet.triangle_count)
+ {
+ finishMeshlet(meshlet, meshlet_triangles);
+
+ meshlets[meshlet_offset++] = meshlet;
+ }
+
+ assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ return meshlet_offset;
+}
+
+size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
+
+ meshopt_Allocator allocator;
+
+ // index of the vertex in the meshlet, 0xff if the vertex isn't used
+ unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
+ memset(used, -1, vertex_count);
+
+ meshopt_Meshlet meshlet = {};
+ size_t meshlet_offset = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ // appends triangle to the meshlet and writes previous meshlet to the output if full
+ meshlet_offset += appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles);
}
if (meshlet.triangle_count)
- destination[offset++] = meshlet;
+ {
+ finishMeshlet(meshlet, meshlet_triangles);
- assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ meshlets[meshlet_offset++] = meshlet;
+ }
- return offset;
+ assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ return meshlet_offset;
}
meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
@@ -178,18 +687,17 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
using namespace meshopt;
assert(index_count % 3 == 0);
+ assert(index_count / 3 <= kMeshletMaxTriangles);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
- assert(index_count / 3 <= 256);
-
(void)vertex_count;
size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
// compute triangle normals and gather triangle corners
- float normals[256][3];
- float corners[256][3][3];
+ float normals[kMeshletMaxTriangles][3];
+ float corners[kMeshletMaxTriangles][3][3];
size_t triangles = 0;
for (size_t i = 0; i < index_count; i += 3)
@@ -327,25 +835,23 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
return bounds;
}
-meshopt_Bounds meshopt_computeMeshletBounds(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
+ using namespace meshopt;
+
+ assert(triangle_count <= kMeshletMaxTriangles);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
- unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])];
+ unsigned int indices[kMeshletMaxTriangles * 3];
- for (size_t i = 0; i < meshlet->triangle_count; ++i)
+ for (size_t i = 0; i < triangle_count * 3; ++i)
{
- unsigned int a = meshlet->vertices[meshlet->indices[i][0]];
- unsigned int b = meshlet->vertices[meshlet->indices[i][1]];
- unsigned int c = meshlet->vertices[meshlet->indices[i][2]];
-
- assert(a < vertex_count && b < vertex_count && c < vertex_count);
+ unsigned int index = meshlet_vertices[meshlet_triangles[i]];
+ assert(index < vertex_count);
- indices[i * 3 + 0] = a;
- indices[i * 3 + 1] = b;
- indices[i * 3 + 2] = c;
+ indices[i] = index;
}
- return meshopt_computeClusterBounds(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
+ return meshopt_computeClusterBounds(indices, triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
}
diff --git a/thirdparty/meshoptimizer/indexgenerator.cpp b/thirdparty/meshoptimizer/indexgenerator.cpp
index aa4a30efa4..f60db0dc4f 100644
--- a/thirdparty/meshoptimizer/indexgenerator.cpp
+++ b/thirdparty/meshoptimizer/indexgenerator.cpp
@@ -4,6 +4,8 @@
#include <assert.h>
#include <string.h>
+// This work is based on:
+// John McDonald, Mark Kilgard. Crack-Free Point-Normal Triangles using Adjacent Edge Normals. 2010
namespace meshopt
{
@@ -83,10 +85,49 @@ struct VertexStreamHasher
}
};
+struct EdgeHasher
+{
+ const unsigned int* remap;
+
+ size_t hash(unsigned long long edge) const
+ {
+ unsigned int e0 = unsigned(edge >> 32);
+ unsigned int e1 = unsigned(edge);
+
+ unsigned int h1 = remap[e0];
+ unsigned int h2 = remap[e1];
+
+ const unsigned int m = 0x5bd1e995;
+
+ // MurmurHash64B finalizer
+ h1 ^= h2 >> 18;
+ h1 *= m;
+ h2 ^= h1 >> 22;
+ h2 *= m;
+ h1 ^= h2 >> 17;
+ h1 *= m;
+ h2 ^= h1 >> 19;
+ h2 *= m;
+
+ return h2;
+ }
+
+ bool equal(unsigned long long lhs, unsigned long long rhs) const
+ {
+ unsigned int l0 = unsigned(lhs >> 32);
+ unsigned int l1 = unsigned(lhs);
+
+ unsigned int r0 = unsigned(rhs >> 32);
+ unsigned int r1 = unsigned(rhs);
+
+ return remap[l0] == remap[r0] && remap[l1] == remap[r1];
+ }
+};
+
static size_t hashBuckets(size_t count)
{
size_t buckets = 1;
- while (buckets < count)
+ while (buckets < count + count / 4)
buckets *= 2;
return buckets;
@@ -119,6 +160,26 @@ static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, c
return 0;
}
+static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)
+{
+ VertexHasher vertex_hasher = {reinterpret_cast<const unsigned char*>(vertex_positions), 3 * sizeof(float), vertex_positions_stride};
+
+ size_t vertex_table_size = hashBuckets(vertex_count);
+ unsigned int* vertex_table = allocator.allocate<unsigned int>(vertex_table_size);
+ memset(vertex_table, -1, vertex_table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int index = unsigned(i);
+ unsigned int* entry = hashLookup(vertex_table, vertex_table_size, vertex_hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ *entry = index;
+
+ remap[index] = *entry;
+ }
+}
+
} // namespace meshopt
size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
@@ -345,3 +406,146 @@ void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const uns
destination[i] = remap[index];
}
}
+
+void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ static const int next[4] = {1, 2, 0, 1};
+
+ // build position remap: for each vertex, which other (canonical) vertex does it map to?
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
+
+ // build edge set; this stores all triangle edges but we can look these up by any other wedge
+ EdgeHasher edge_hasher = {remap};
+
+ size_t edge_table_size = hashBuckets(index_count);
+ unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
+ unsigned int* edge_vertex_table = allocator.allocate<unsigned int>(edge_table_size);
+
+ memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
+ memset(edge_vertex_table, -1, edge_table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ unsigned int i2 = indices[i + next[e + 1]];
+ assert(i0 < vertex_count && i1 < vertex_count && i2 < vertex_count);
+
+ unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
+ unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ if (*entry == ~0ull)
+ {
+ *entry = edge;
+
+ // store vertex opposite to the edge
+ edge_vertex_table[entry - edge_table] = i2;
+ }
+ }
+ }
+
+ // build resulting index buffer: 6 indices for each input triangle
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int patch[6];
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ // note: this refers to the opposite edge!
+ unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
+ unsigned long long* oppe = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ patch[e * 2 + 0] = i0;
+ patch[e * 2 + 1] = (*oppe == ~0ull) ? i0 : edge_vertex_table[oppe - edge_table];
+ }
+
+ memcpy(destination + i * 2, patch, sizeof(patch));
+ }
+}
+
+void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ static const int next[3] = {1, 2, 0};
+
+ // build position remap: for each vertex, which other (canonical) vertex does it map to?
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
+
+ // build edge set; this stores all triangle edges but we can look these up by any other wedge
+ EdgeHasher edge_hasher = {remap};
+
+ size_t edge_table_size = hashBuckets(index_count);
+ unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
+ memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
+ unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ if (*entry == ~0ull)
+ *entry = edge;
+ }
+ }
+
+ // build resulting index buffer: 12 indices for each input triangle
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int patch[12];
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ // note: this refers to the opposite edge!
+ unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
+ unsigned long long oppe = *hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ // use the same edge if opposite edge doesn't exist (border)
+ oppe = (oppe == ~0ull) ? edge : oppe;
+
+ // triangle index (0, 1, 2)
+ patch[e] = i0;
+
+ // opposite edge (3, 4; 5, 6; 7, 8)
+ patch[3 + e * 2 + 0] = unsigned(oppe);
+ patch[3 + e * 2 + 1] = unsigned(oppe >> 32);
+
+ // dominant vertex (9, 10, 11)
+ patch[9 + e] = remap[i0];
+ }
+
+ memcpy(destination + i * 4, patch, sizeof(patch));
+ }
+}
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
index 1714000384..fe8d349731 100644
--- a/thirdparty/meshoptimizer/meshoptimizer.h
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
@@ -1,7 +1,7 @@
/**
- * meshoptimizer - version 0.15
+ * meshoptimizer - version 0.16
*
- * Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://github.com/zeux/meshoptimizer
*
* This library is distributed under the MIT License. See notice at the end of this file.
@@ -12,7 +12,7 @@
#include <stddef.h>
/* Version macro; major * 1000 + minor * 10 + patch */
-#define MESHOPTIMIZER_VERSION 150 /* 0.15 */
+#define MESHOPTIMIZER_VERSION 160 /* 0.16 */
/* If no API is defined, assume default */
#ifndef MESHOPTIMIZER_API
@@ -98,6 +98,35 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destinati
MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count);
/**
+ * Generate index buffer that can be used as a geometry shader input with triangle adjacency topology
+ * Each triangle is converted into a 6-vertex patch with the following layout:
+ * - 0, 2, 4: original triangle vertices
+ * - 1, 3, 5: vertices adjacent to edges 02, 24 and 40
+ * The resulting patch can be rendered with geometry shaders using e.g. VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY.
+ * This can be used to implement algorithms like silhouette detection/expansion and other forms of GS-driven rendering.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count*2 elements)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
+ * Generate index buffer that can be used for PN-AEN tessellation with crack-free displacement
+ * Each triangle is converted into a 12-vertex patch with the following layout:
+ * - 0, 1, 2: original triangle vertices
+ * - 3, 4: opposing edge for edge 0, 1
+ * - 5, 6: opposing edge for edge 1, 2
+ * - 7, 8: opposing edge for edge 2, 0
+ * - 9, 10, 11: dominant vertices for corners 0, 1, 2
+ * The resulting patch can be rendered with hardware tessellation using PN-AEN and displacement mapping.
+ * See "Tessellation on Any Budget" (John McDonald, GDC 2011) for implementation details.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count*4 elements)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
* Vertex transform cache optimizer
* Reorders indices to reduce the number of GPU vertex shader invocations
* If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
@@ -373,22 +402,31 @@ MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetc
struct meshopt_Meshlet
{
- unsigned int vertices[64];
- unsigned char indices[126][3];
- unsigned char triangle_count;
- unsigned char vertex_count;
+ /* offsets within meshlet_vertices and meshlet_triangles arrays with meshlet data */
+ unsigned int vertex_offset;
+ unsigned int triangle_offset;
+
+ /* number of vertices and triangles used in the meshlet; data is stored in consecutive range defined by offset and count */
+ unsigned int vertex_count;
+ unsigned int triangle_count;
};
/**
* Experimental: Meshlet builder
* Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer
* The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers.
- * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
+ * When using buildMeshlets, vertex positions need to be provided to minimize the size of the resulting clusters.
+ * When using buildMeshletsScan, for maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
*
- * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
- * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126)
+ * meshlets must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
+ * meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
+ * meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ * max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512)
+ * cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
*/
-MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsScan(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles);
struct meshopt_Bounds
@@ -426,10 +464,10 @@ struct meshopt_Bounds
* to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
*
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
- * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size)
+ * index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size)
*/
MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
-MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
/**
* Experimental: Spatial sorter
@@ -513,6 +551,10 @@ inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices,
template <typename T>
inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
template <typename T>
+inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
+inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count);
template <typename T>
inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count);
@@ -547,7 +589,9 @@ inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size
template <typename T>
inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
template <typename T>
-inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight);
+template <typename T>
+inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
template <typename T>
inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
template <typename T>
@@ -762,6 +806,24 @@ inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indi
}
template <typename T>
+inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count * 2);
+
+ meshopt_generateAdjacencyIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
+inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count * 4);
+
+ meshopt_generateTessellationIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count)
{
meshopt_IndexAdapter<T> in(0, indices, index_count);
@@ -908,11 +970,19 @@ inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices
}
template <typename T>
-inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_buildMeshlets(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, max_vertices, max_triangles, cone_weight);
+}
+
+template <typename T>
+inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
{
meshopt_IndexAdapter<T> in(0, indices, index_count);
- return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles);
+ return meshopt_buildMeshletsScan(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_count, max_vertices, max_triangles);
}
template <typename T>
@@ -934,7 +1004,7 @@ inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_
#endif
/**
- * Copyright (c) 2016-2020 Arseny Kapoulkine
+ * Copyright (c) 2016-2021 Arseny Kapoulkine
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
index 942db14461..b2cb589462 100644
--- a/thirdparty/meshoptimizer/simplifier.cpp
+++ b/thirdparty/meshoptimizer/simplifier.cpp
@@ -131,7 +131,7 @@ struct PositionHasher
static size_t hashBuckets2(size_t count)
{
size_t buckets = 1;
- while (buckets < count)
+ while (buckets < count + count / 4)
buckets *= 2;
return buckets;
diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp
index 2cbfaac367..5f3ec204ab 100644
--- a/thirdparty/meshoptimizer/vertexcodec.cpp
+++ b/thirdparty/meshoptimizer/vertexcodec.cpp
@@ -710,18 +710,12 @@ static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1)
SIMD_TARGET
static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1)
{
- v128_t mask_0 = wasm_v32x4_shuffle(mask, mask, 0, 2, 1, 3);
-
- uint64_t mask_1a = wasm_i64x2_extract_lane(mask_0, 0) & 0x0804020108040201ull;
- uint64_t mask_1b = wasm_i64x2_extract_lane(mask_0, 1) & 0x8040201080402010ull;
+ // magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00
+ const uint64_t magic = 0x000103070f1f3f80ull;
// TODO: This can use v8x16_bitmask in the future
- uint64_t mask_2 = mask_1a | mask_1b;
- uint64_t mask_4 = mask_2 | (mask_2 >> 16);
- uint64_t mask_8 = mask_4 | (mask_4 >> 8);
-
- mask0 = uint8_t(mask_8);
- mask1 = uint8_t(mask_8 >> 32);
+ mask0 = uint8_t((wasm_i64x2_extract_lane(mask, 0) * magic) >> 56);
+ mask1 = uint8_t((wasm_i64x2_extract_lane(mask, 1) * magic) >> 56);
}
SIMD_TARGET
diff --git a/thirdparty/miniupnpc/LICENSE b/thirdparty/miniupnpc/LICENSE
index 1460310752..6ddd381baa 100644
--- a/thirdparty/miniupnpc/LICENSE
+++ b/thirdparty/miniupnpc/LICENSE
@@ -1,5 +1,5 @@
-MiniUPnP Project
-Copyright (c) 2005-2019, Thomas BERNARD
+MiniUPnPc
+Copyright (c) 2005-2020, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -24,3 +24,4 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c
new file mode 100644
index 0000000000..7e586d7da2
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.c
@@ -0,0 +1,79 @@
+/* $Id: addr_is_reserved.c,v 1.4 2021/03/02 23:40:32 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project : miniupnp
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2021 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#ifdef _WIN32
+/* Win32 Specific includes and defines */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#if !defined(_MSC_VER)
+#include <stdint.h>
+#else /* !defined(_MSC_VER) */
+typedef unsigned long uint32_t;
+#endif /* !defined(_MSC_VER) */
+#else /* _WIN32 */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* _WIN32 */
+
+/* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */
+#define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+#define MSK(m) (32-(m))
+static const struct { uint32_t address; uint32_t rmask; } reserved[] = {
+ { IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */
+ { IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */
+ { IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */
+ { IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */
+ { IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */
+ { IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */
+ { IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */
+ { IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */
+ { IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */
+ { IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */
+ { IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */
+ { IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */
+ { IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */
+ { IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */
+ { IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */
+ { IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */
+ { IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */
+ { IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */
+};
+#undef IP
+#undef MSK
+
+/**
+ * @return 1 or 0
+ */
+int addr_is_reserved(const char * addr_str)
+{
+ uint32_t addr_n, address;
+ size_t i;
+
+#if defined(_WIN32) && (!defined(_WIN32_WINNT_VISTA) || (_WIN32_WINNT < _WIN32_WINNT_VISTA))
+ addr_n = inet_addr(addr_str);
+ if (addr_n == INADDR_NONE)
+ return 1;
+#else
+ /* was : addr_n = inet_addr(addr_str); */
+ if (inet_pton(AF_INET, addr_str, &addr_n) <= 0) {
+ /* error */
+ return 1;
+ }
+#endif
+
+ address = ntohl(addr_n);
+
+ for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) {
+ if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask))
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h
new file mode 100644
index 0000000000..f8b5d66a09
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/addr_is_reserved.h
@@ -0,0 +1,14 @@
+/* $Id: $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project: miniupnp
+ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * Author: Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
+ * This software is subjects to the conditions detailed
+ * in the LICENCE file provided within this distribution */
+#ifndef ADDR_IS_RESERVED_H_INCLUDED
+#define ADDR_IS_RESERVED_H_INCLUDED
+
+int addr_is_reserved(const char * addr_str);
+
+#endif /* ADDR_IS_RESERVED_H_INCLUDED */
diff --git a/thirdparty/miniupnpc/miniupnpc/connecthostport.c b/thirdparty/miniupnpc/miniupnpc/connecthostport.c
index f3982e1a77..79f832b8db 100644
--- a/thirdparty/miniupnpc/miniupnpc/connecthostport.c
+++ b/thirdparty/miniupnpc/miniupnpc/connecthostport.c
@@ -1,8 +1,8 @@
-/* $Id: connecthostport.c,v 1.22 2019/10/13 17:22:08 nanard Exp $ */
+/* $Id: connecthostport.c,v 1.24 2020/11/09 19:26:53 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
* Author : Thomas Bernard
- * Copyright (c) 2010-2019 Thomas Bernard
+ * Copyright (c) 2010-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -19,7 +19,7 @@
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define herror
#define socklen_t int
#else /* #ifdef _WIN32 */
diff --git a/thirdparty/miniupnpc/miniupnpc/listdevices.c b/thirdparty/miniupnpc/miniupnpc/listdevices.c
deleted file mode 100644
index bd9ba57efc..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/listdevices.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* $Id: listdevices.c,v 1.6 2015/07/23 20:40:08 nanard Exp $ */
-/* Project : miniupnp
- * Author : Thomas Bernard
- * Copyright (c) 2013-2015 Thomas Bernard
- * This software is subject to the conditions detailed in the
- * LICENCE file provided in this distribution. */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#endif /* _WIN32 */
-#include "miniupnpc.h"
-
-struct upnp_dev_list {
- struct upnp_dev_list * next;
- char * descURL;
- struct UPNPDev * * array;
- size_t count;
- size_t allocated_count;
-};
-
-#define ADD_DEVICE_COUNT_STEP 16
-
-void add_device(struct upnp_dev_list * * list_head, struct UPNPDev * dev)
-{
- struct upnp_dev_list * elt;
- size_t i;
-
- if(dev == NULL)
- return;
- for(elt = *list_head; elt != NULL; elt = elt->next) {
- if(strcmp(elt->descURL, dev->descURL) == 0) {
- for(i = 0; i < elt->count; i++) {
- if (strcmp(elt->array[i]->st, dev->st) == 0 && strcmp(elt->array[i]->usn, dev->usn) == 0) {
- return; /* already found */
- }
- }
- if(elt->count >= elt->allocated_count) {
- struct UPNPDev * * tmp;
- elt->allocated_count += ADD_DEVICE_COUNT_STEP;
- tmp = realloc(elt->array, elt->allocated_count * sizeof(struct UPNPDev *));
- if(tmp == NULL) {
- fprintf(stderr, "Failed to realloc(%p, %lu)\n", elt->array, (unsigned long)(elt->allocated_count * sizeof(struct UPNPDev *)));
- return;
- }
- elt->array = tmp;
- }
- elt->array[elt->count++] = dev;
- return;
- }
- }
- elt = malloc(sizeof(struct upnp_dev_list));
- if(elt == NULL) {
- fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)sizeof(struct upnp_dev_list));
- return;
- }
- elt->next = *list_head;
- elt->descURL = strdup(dev->descURL);
- if(elt->descURL == NULL) {
- fprintf(stderr, "Failed to strdup(%s)\n", dev->descURL);
- free(elt);
- return;
- }
- elt->allocated_count = ADD_DEVICE_COUNT_STEP;
- elt->array = malloc(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *));
- if(elt->array == NULL) {
- fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *)));
- free(elt->descURL);
- free(elt);
- return;
- }
- elt->array[0] = dev;
- elt->count = 1;
- *list_head = elt;
-}
-
-void free_device(struct upnp_dev_list * elt)
-{
- free(elt->descURL);
- free(elt->array);
- free(elt);
-}
-
-int main(int argc, char * * argv)
-{
- const char * searched_device = NULL;
- const char * * searched_devices = NULL;
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- int ipv6 = 0;
- unsigned char ttl = 2;
- int error = 0;
- struct UPNPDev * devlist = 0;
- struct UPNPDev * dev;
- struct upnp_dev_list * sorted_list = NULL;
- struct upnp_dev_list * dev_array;
- int i;
-
-#ifdef _WIN32
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if(nResult != NO_ERROR)
- {
- fprintf(stderr, "WSAStartup() failed.\n");
- return -1;
- }
-#endif
-
- for(i = 1; i < argc; i++) {
- if(strcmp(argv[i], "-6") == 0)
- ipv6 = 1;
- else if(strcmp(argv[i], "-d") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "%s option needs one argument\n", "-d");
- return 1;
- }
- searched_device = argv[i];
- } else if(strcmp(argv[i], "-t") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "%s option needs one argument\n", "-t");
- return 1;
- }
- ttl = (unsigned char)atoi(argv[i]);
- } else if(strcmp(argv[i], "-l") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "-l option needs at least one argument\n");
- return 1;
- }
- searched_devices = (const char * *)(argv + i);
- break;
- } else if(strcmp(argv[i], "-m") == 0) {
- if(++i >= argc) {
- fprintf(stderr, "-m option needs one argument\n");
- return 1;
- }
- multicastif = argv[i];
- } else {
- printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
- printf("options :\n");
- printf(" -6 : use IPv6\n");
- printf(" -m address/ifname : network interface to use for multicast\n");
- printf(" -d <device string> : search only for this type of device\n");
- printf(" -l <device1> <device2> ... : search only for theses types of device\n");
- printf(" -t ttl : set multicast TTL. Default value is 2.\n");
- printf(" -h : this help\n");
- return 1;
- }
- }
-
- if(searched_device) {
- printf("searching UPnP device type %s\n", searched_device);
- devlist = upnpDiscoverDevice(searched_device,
- 2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error);
- } else if(searched_devices) {
- printf("searching UPnP device types :\n");
- for(i = 0; searched_devices[i]; i++)
- printf("\t%s\n", searched_devices[i]);
- devlist = upnpDiscoverDevices(searched_devices,
- 2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error, 1);
- } else {
- printf("searching all UPnP devices\n");
- devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
- 0/*localport*/, ipv6, ttl, &error);
- }
- if(devlist) {
- for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
- printf("%3d: %-48s\n", i, dev->st);
- printf(" %s\n", dev->descURL);
- printf(" %s\n", dev->usn);
- add_device(&sorted_list, dev);
- }
- putchar('\n');
- for (dev_array = sorted_list; dev_array != NULL ; dev_array = dev_array->next) {
- printf("%s :\n", dev_array->descURL);
- for(i = 0; (unsigned)i < dev_array->count; i++) {
- printf("%2d: %s\n", i+1, dev_array->array[i]->st);
- printf(" %s\n", dev_array->array[i]->usn);
- }
- putchar('\n');
- }
- freeUPNPDevlist(devlist);
- while(sorted_list != NULL) {
- dev_array = sorted_list;
- sorted_list = sorted_list->next;
- free_device(dev_array);
- }
- } else {
- printf("no device found.\n");
- }
-
- return 0;
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/minisoap.c b/thirdparty/miniupnpc/miniupnpc/minisoap.c
index f92b36ce89..78606672d5 100644
--- a/thirdparty/miniupnpc/miniupnpc/minisoap.c
+++ b/thirdparty/miniupnpc/miniupnpc/minisoap.c
@@ -1,8 +1,8 @@
-/* $Id: minisoap.c,v 1.25 2017/04/21 10:03:24 nanard Exp $ */
+/* $Id: minisoap.c,v 1.30 2020/11/09 19:27:42 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
* Author : Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
*
@@ -13,7 +13,7 @@
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#else
#include <unistd.h>
#include <sys/types.h>
diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
index 36244dedec..5d3a0fd049 100644
--- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c
+++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
@@ -1,15 +1,15 @@
-/* $Id: minissdpc.c,v 1.40 2019/04/23 12:12:55 nanard Exp $ */
+/* $Id: minissdpc.c,v 1.47 2021/03/02 23:38:30 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2019 Thomas Bernard
+ * copyright (c) 2005-2021 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
-/*#include <syslog.h>*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <time.h>
#include <sys/types.h>
#if defined (__NetBSD__)
#include <net/if.h>
@@ -20,7 +20,7 @@
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#if !defined(_MSC_VER)
#include <stdint.h>
#else /* !defined(_MSC_VER) */
@@ -33,6 +33,12 @@ typedef unsigned short uint16_t;
#define strncasecmp memicmp
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#endif /* #ifndef strncasecmp */
+#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION)
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
+#define in6addr_any in6addr_any_init
+static const IN6_ADDR in6addr_any_init = {0};
+#endif
+#endif
#endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h>
@@ -66,7 +72,7 @@ struct sockaddr_un {
#define HAS_IP_MREQN
#endif
-#if !defined(HAS_IP_MREQN) && !defined(_WIN32)
+#ifndef _WIN32
#include <sys/ioctl.h>
#if defined(__sun) || defined(__HAIKU__)
#include <sys/sockio.h>
@@ -445,6 +451,36 @@ parseMSEARCHReply(const char * reply, int size,
}
}
+#if defined(CLOCK_MONOTONIC_FAST)
+#define UPNP_CLOCKID CLOCK_MONOTONIC_FAST
+#elif defined(CLOCK_MONOTONIC)
+#define UPNP_CLOCKID CLOCK_MONOTONIC
+#endif
+
+static int upnp_gettimeofday(struct timeval * tv)
+{
+#if defined(_WIN32)
+#if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ ULONGLONG ts = GetTickCount64();
+#else
+ DWORD ts = GetTickCount();
+#endif
+ tv->tv_sec = (long)(ts / 1000);
+ tv->tv_usec = (ts % 1000) * 1000;
+ return 0; /* success */
+#elif defined(CLOCK_MONOTONIC_FAST) || defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ int ret_code = clock_gettime(UPNP_CLOCKID, &ts);
+ if (ret_code == 0)
+ {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ret_code;
+#else
+ return gettimeofday(tv, NULL);
+#endif
+}
/* port upnp discover : SSDP protocol */
#define SSDP_PORT 1900
#define XSTR(s) STR(s)
@@ -540,12 +576,17 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6) {
DWORD ifbestidx;
+#if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA
+ // While we don't need IPv6 support, the IPv4 only funciton is not available in UWP apps.
SOCKADDR_IN destAddr;
memset(&destAddr, 0, sizeof(destAddr));
destAddr.sin_family = AF_INET;
destAddr.sin_addr.s_addr = inet_addr("223.255.255.255");
destAddr.sin_port = 0;
if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) {
+#else
+ if (GetBestInterface(inet_addr("223.255.255.255"), &ifbestidx) == NO_ERROR) {
+#endif
DWORD dwRetVal = NO_ERROR;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 15360;
@@ -672,6 +713,13 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
+ if(ifindex == 0)
+ {
+ if(error)
+ *error = MINISSDPC_INVALID_INPUT;
+ fprintf(stderr, "Invalid multicast interface name %s\n", multicastif);
+ goto error;
+ }
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF");
@@ -683,7 +731,18 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
#endif
} else {
struct in_addr mc_if;
- mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
+#if defined(_WIN32)
+#if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+ InetPtonA(AF_INET, multicastif, &mc_if);
+#else
+ mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */
+#endif
+#else
+ /* was : mc_if.s_addr = inet_addr(multicastif); */ /* ex: 192.168.x.x */
+ if (inet_pton(AF_INET, multicastif, &mc_if.s_addr) <= 0) {
+ mc_if.s_addr = INADDR_NONE;
+ }
+#endif
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
@@ -692,16 +751,11 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
}
} else {
-#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
+#ifndef _WIN32
+#ifdef HAS_IP_MREQN
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
- memset(&reqn, 0, sizeof(struct ip_mreqn));
- reqn.imr_ifindex = if_nametoindex(multicastif);
- if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
- {
- PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
- }
-#elif !defined(_WIN32)
+#endif
struct ifreq ifr;
int ifrlen = sizeof(ifr);
strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
@@ -709,12 +763,30 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
{
PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
+ goto error;
}
mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+#ifdef HAS_IP_MREQN
+ memset(&reqn, 0, sizeof(struct ip_mreqn));
+ reqn.imr_address.s_addr = mc_if.s_addr;
+ reqn.imr_ifindex = if_nametoindex(multicastif);
+ if(reqn.imr_ifindex == 0)
+ {
+ if(error)
+ *error = MINISSDPC_INVALID_INPUT;
+ fprintf(stderr, "Invalid multicast ip address / interface name %s\n", multicastif);
+ goto error;
+ }
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
+ {
+ PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
+ }
+#else
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
}
+#endif
#else /* _WIN32 */
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
@@ -838,73 +910,84 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
/* Waiting for SSDP REPLY packet to M-SEARCH
* if searchalltypes is set, enter the loop only
* when the last deviceType is reached */
- if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do {
- n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
- if (n < 0) {
- /* error */
- if(error)
- *error = MINISSDPC_SOCKET_ERROR;
- goto error;
- } else if (n == 0) {
- /* no data or Time Out */
-#ifdef DEBUG
- printf("NODATA or TIMEOUT\n");
-#endif /* DEBUG */
- if (devlist && !searchalltypes) {
- /* found some devices, stop now*/
+ if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) {
+ struct timeval start = {0, 0}, current = {0, 0};
+ upnp_gettimeofday(&start);
+ do {
+ n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
+ if (n < 0) {
+ /* error */
if(error)
- *error = MINISSDPC_SUCCESS;
+ *error = MINISSDPC_SOCKET_ERROR;
goto error;
- }
- } else {
- const char * descURL=NULL;
- int urlsize=0;
- const char * st=NULL;
- int stsize=0;
- const char * usn=NULL;
- int usnsize=0;
- parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
- if(st&&descURL) {
+ } else if (n == 0) {
+ /* no data or Time Out */
#ifdef DEBUG
- printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
- stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+ printf("NODATA or TIMEOUT\n");
#endif /* DEBUG */
- for(tmp=devlist; tmp; tmp = tmp->pNext) {
- if(strncmp(tmp->descURL, descURL, urlsize) == 0 &&
- tmp->descURL[urlsize] == '\0' &&
- strncmp(tmp->st, st, stsize) == 0 &&
- tmp->st[stsize] == '\0' &&
- (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) &&
- tmp->usn[usnsize] == '\0')
- break;
- }
- /* at the exit of the loop above, tmp is null if
- * no duplicate device was found */
- if(tmp)
- continue;
- tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
- if(!tmp) {
- /* memory allocation error */
+ if (devlist && !searchalltypes) {
+ /* found some devices, stop now*/
if(error)
- *error = MINISSDPC_MEMORY_ERROR;
+ *error = MINISSDPC_SUCCESS;
goto error;
}
- tmp->pNext = devlist;
- tmp->descURL = tmp->buffer;
- tmp->st = tmp->buffer + 1 + urlsize;
- tmp->usn = tmp->st + 1 + stsize;
- memcpy(tmp->buffer, descURL, urlsize);
- tmp->buffer[urlsize] = '\0';
- memcpy(tmp->st, st, stsize);
- tmp->buffer[urlsize+1+stsize] = '\0';
- if(usn != NULL)
- memcpy(tmp->usn, usn, usnsize);
- tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
- tmp->scope_id = scope_id;
- devlist = tmp;
+ } else {
+ const char * descURL=NULL;
+ int urlsize=0;
+ const char * st=NULL;
+ int stsize=0;
+ const char * usn=NULL;
+ int usnsize=0;
+ parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
+ if(st&&descURL) {
+#ifdef DEBUG
+ printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
+ stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+#endif /* DEBUG */
+ for(tmp=devlist; tmp; tmp = tmp->pNext) {
+ if(strncmp(tmp->descURL, descURL, urlsize) == 0 &&
+ tmp->descURL[urlsize] == '\0' &&
+ strncmp(tmp->st, st, stsize) == 0 &&
+ tmp->st[stsize] == '\0' &&
+ (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) &&
+ tmp->usn[usnsize] == '\0')
+ break;
+ }
+ /* at the exit of the loop above, tmp is null if
+ * no duplicate device was found */
+ if(tmp)
+ continue;
+ tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize+3);
+ if(!tmp) {
+ /* memory allocation error */
+ if(error)
+ *error = MINISSDPC_MEMORY_ERROR;
+ goto error;
+ }
+ tmp->pNext = devlist;
+ tmp->descURL = tmp->buffer;
+ tmp->st = tmp->buffer + 1 + urlsize;
+ tmp->usn = tmp->st + 1 + stsize;
+ memcpy(tmp->buffer, descURL, urlsize);
+ tmp->buffer[urlsize] = '\0';
+ memcpy(tmp->st, st, stsize);
+ tmp->buffer[urlsize+1+stsize] = '\0';
+ if(usn != NULL)
+ memcpy(tmp->usn, usn, usnsize);
+ tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+ tmp->scope_id = scope_id;
+ devlist = tmp;
+ }
+ if (upnp_gettimeofday(&current) >= 0) {
+ /* exit the loop if delay is reached */
+ long interval = (current.tv_sec - start.tv_sec) * 1000;
+ interval += (current.tv_usec - start.tv_usec) / 1000;
+ if (interval > (long)delay)
+ break;
+ }
}
- }
- } while(n > 0);
+ } while(n > 0);
+ }
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
@@ -919,4 +1002,3 @@ error:
closesocket(sudp);
return devlist;
}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc.c b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
index 95ab6cf56b..696af93237 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c
@@ -1,9 +1,9 @@
-/* $Id: miniupnpc.c,v 1.154 2019/04/23 12:12:13 nanard Exp $ */
+/* $Id: miniupnpc.c,v 1.159 2021/03/02 23:36:32 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2019 Thomas Bernard
+ * copyright (c) 2005-2021 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
@@ -15,7 +15,7 @@
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define strdup _strdup
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
@@ -61,6 +61,7 @@
#include "minixml.h"
#include "upnpcommands.h"
#include "connecthostport.h"
+#include "addr_is_reserved.h"
/* compare the beginning of a string with a constant string */
#define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1))
@@ -73,24 +74,6 @@
#define SERVICEPREFIX "u"
#define SERVICEPREFIX2 'u'
-/* check if an ip address is a private (LAN) address
- * see https://tools.ietf.org/html/rfc1918 */
-static int is_rfc1918addr(const char * addr)
-{
- /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
- if(COMPARE(addr, "192.168."))
- return 1;
- /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
- if(COMPARE(addr, "10."))
- return 1;
- /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
- if(COMPARE(addr, "172.")) {
- if((atoi(addr + 4) | 0x0f) == 0x1f)
- return 1;
- }
- return 0;
-}
-
/* root description parsing */
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
{
@@ -337,6 +320,8 @@ upnpDiscoverDevices(const char * const deviceTypes[],
return devlist;
}
}
+#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+ (void)minissdpdsock; /* unused */
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* direct discovery if minissdpd responses are not sufficient */
@@ -643,8 +628,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* checks that status is connected AND there is a external IP address assigned */
if(is_connected &&
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
- if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
- && (0 != strcmp(extIpAddr, "0.0.0.0")))
+ if(!addr_is_reserved(extIpAddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
@@ -665,8 +649,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
#endif
if(is_connected &&
(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) {
- if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
- && (0 != strcmp(extIpAddr, "0.0.0.0")))
+ if(!addr_is_reserved(extIpAddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
index 8ddc282bd1..3aef8ea443 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc.h
@@ -1,9 +1,9 @@
-/* $Id: miniupnpc.h,v 1.53 2018/05/07 11:05:16 nanard Exp $ */
+/* $Id: miniupnpc.h,v 1.58 2021/03/02 23:49:52 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2021 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
@@ -20,7 +20,7 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
-#define MINIUPNPC_VERSION "2.1"
+#define MINIUPNPC_VERSION "2.2.2"
#define MINIUPNPC_API_VERSION 17
/* Source port:
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
index d4f79a7bd6..5986e58c76 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h
@@ -7,7 +7,7 @@
#ifndef MINIUPNPC_SOCKETDEF_H_INCLUDED
#define MINIUPNPC_SOCKETDEF_H_INCLUDED
-#ifdef _MSC_VER
+#ifdef _WIN32
#define ISINVALID(s) (INVALID_SOCKET==(s))
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c b/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c
deleted file mode 100644
index d9341ab5bf..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c
+++ /dev/null
@@ -1,721 +0,0 @@
-/* $Id: miniupnpcmodule.c,v 1.34 2019/05/20 19:07:16 nanard Exp $*/
-/* vim: tabstop=4 shiftwidth=4 noexpandtab
- * Project : miniupnp
- * Author : Thomas BERNARD
- * website : https://miniupnp.tuxfamily.org/
- * copyright (c) 2007-2019 Thomas Bernard
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#include <Python.h>
-#define MINIUPNP_STATICLIB
-#include "structmember.h"
-#include "miniupnpc.h"
-#include "upnpcommands.h"
-#include "upnperrors.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-/* for compatibility with Python < 2.4 */
-#ifndef Py_RETURN_NONE
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#endif
-
-#ifndef Py_RETURN_TRUE
-#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
-#endif
-
-#ifndef Py_RETURN_FALSE
-#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
-#endif
-
-/* for compatibility with Python < 3.0 */
-#ifndef PyVarObject_HEAD_INIT
-#define PyVarObject_HEAD_INIT(type, size) \
- PyObject_HEAD_INIT(type) size,
-#endif
-
-#ifndef Py_TYPE
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
-#endif
-
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- struct UPNPDev * devlist;
- struct UPNPUrls urls;
- struct IGDdatas data;
- unsigned int discoverdelay; /* value passed to upnpDiscover() */
- unsigned int localport; /* value passed to upnpDiscover() */
- char lanaddr[40]; /* our ip address on the LAN */
- char * multicastif;
- char * minissdpdsocket;
-} UPnPObject;
-
-static PyMemberDef UPnP_members[] = {
- {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
- READONLY, "ip address on the LAN"
- },
- {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
- 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
- },
- {"localport", T_UINT, offsetof(UPnPObject, localport),
- 0/*READWRITE*/,
- "If localport is set to UPNP_LOCAL_PORT_SAME(1) "
- "SSDP packets will be sent from the source port "
- "1900 (same as destination port), if set to "
- "UPNP_LOCAL_PORT_ANY(0) system assign a source "
- "port, any other value will be attempted as the "
- "source port"
- },
- /* T_STRING is allways readonly :( */
- {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
- 0, "IP of the network interface to be used for multicast operations"
- },
- {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
- 0, "path of the MiniSSDPd unix socket"
- },
- {NULL}
-};
-
-
-static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
-{
- char* multicastif = NULL;
- char* minissdpdsocket = NULL;
- static char *kwlist[] = {
- "multicastif", "minissdpdsocket", "discoverdelay",
- "localport", NULL
- };
-
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
- &multicastif,
- &minissdpdsocket,
- &self->discoverdelay,
- &self->localport))
- return -1;
-
- if(self->localport>1 &&
- (self->localport>65534||self->localport<1024)) {
- PyErr_SetString(PyExc_Exception, "Invalid localport value");
- return -1;
- }
- if(multicastif)
- self->multicastif = strdup(multicastif);
- if(minissdpdsocket)
- self->minissdpdsocket = strdup(minissdpdsocket);
-
- return 0;
-}
-
-static void
-UPnPObject_dealloc(UPnPObject *self)
-{
- freeUPNPDevlist(self->devlist);
- FreeUPNPUrls(&self->urls);
- free(self->multicastif);
- free(self->minissdpdsocket);
- Py_TYPE(self)->tp_free((PyObject*)self);
-}
-
-static PyObject *
-UPnP_discover(UPnPObject *self)
-{
- struct UPNPDev * dev;
- int i;
- PyObject *res = NULL;
- if(self->devlist)
- {
- freeUPNPDevlist(self->devlist);
- self->devlist = 0;
- }
- Py_BEGIN_ALLOW_THREADS
- self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
- self->multicastif,
- self->minissdpdsocket,
- (int)self->localport,
- 0/*ip v6*/,
- 2/* TTL */,
- 0/*error */);
- Py_END_ALLOW_THREADS
- /* Py_RETURN_NONE ??? */
- for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
- i++;
- res = Py_BuildValue("i", i);
- return res;
-}
-
-static PyObject *
-UPnP_selectigd(UPnPObject *self)
-{
- int r;
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
- self->lanaddr, sizeof(self->lanaddr));
-Py_END_ALLOW_THREADS
- if(r)
- {
- return Py_BuildValue("s", self->urls.controlURL);
- }
- else
- {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_totalbytesent(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalbytereceived(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalpacketsent(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_totalpacketreceived(UPnPObject *self)
-{
- UNSIGNED_INTEGER i;
-Py_BEGIN_ALLOW_THREADS
- i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
- self->data.CIF.servicetype);
-Py_END_ALLOW_THREADS
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", i);
-#else
- return Py_BuildValue("i", (int)i);
-#endif
-}
-
-static PyObject *
-UPnP_statusinfo(UPnPObject *self)
-{
- char status[64];
- char lastconnerror[64];
- unsigned int uptime = 0;
- int r;
- status[0] = '\0';
- lastconnerror[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
- status, &uptime, lastconnerror);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
-#else
- return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
-#endif
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_connectiontype(UPnPObject *self)
-{
- char connectionType[64];
- int r;
- connectionType[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
- self->data.first.servicetype,
- connectionType);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("s", connectionType);
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_externalipaddress(UPnPObject *self)
-{
- char externalIPAddress[40];
- int r;
- externalIPAddress[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetExternalIPAddress(self->urls.controlURL,
- self->data.first.servicetype,
- externalIPAddress);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("s", externalIPAddress);
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
- * remoteHost, leaseDuration)
- * protocol is 'UDP' or 'TCP' */
-static PyObject *
-UPnP_addportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- char inPort[6];
- unsigned short iPort;
- const char * proto;
- const char * host;
- const char * desc;
- const char * remoteHost;
- unsigned int intLeaseDuration = 0;
- char strLeaseDuration[12];
- int r;
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto,
- &host, &iPort, &desc, &remoteHost, &intLeaseDuration))
-#else
- if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto,
- &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration))
-#endif
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- sprintf(inPort, "%hu", iPort);
- sprintf(strLeaseDuration, "%u", intLeaseDuration);
- r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, inPort, host, desc, proto,
- remoteHost, strLeaseDuration);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS)
- {
- Py_RETURN_TRUE;
- }
- else
- {
- // TODO: RAISE an Exception. See upnpcommands.h for errors codes.
- // upnperrors.c
- //Py_RETURN_FALSE;
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
- * remoteHost)
- * protocol is 'UDP' or 'TCP' */
-static PyObject *
-UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- char inPort[6];
- unsigned short iPort;
- char reservedPort[6];
- const char * proto;
- const char * host;
- const char * desc;
- const char * remoteHost;
- const char * leaseDuration = "0";
- int r;
- if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- sprintf(inPort, "%hu", iPort);
- r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, inPort, host, desc, proto,
- remoteHost, leaseDuration, reservedPort);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- return Py_BuildValue("i", atoi(reservedPort));
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-
-/* DeletePortMapping(extPort, proto, removeHost='')
- * proto = 'UDP', 'TCP' */
-static PyObject *
-UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- const char * proto;
- const char * remoteHost = "";
- int r;
- if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
- extPort, proto, remoteHost);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- Py_RETURN_TRUE;
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* DeletePortMappingRange(extPort, proto, removeHost='')
- * proto = 'UDP', 'TCP' */
-static PyObject *
-UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
-{
- char extPortStart[6];
- unsigned short ePortStart;
- char extPortEnd[6];
- unsigned short ePortEnd;
- const char * proto;
- unsigned char manage;
- char manageStr[6];
- int r;
- if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPortStart, "%hu", ePortStart);
- sprintf(extPortEnd, "%hu", ePortEnd);
- sprintf(manageStr, "%hu", (unsigned short)manage);
- r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
- extPortStart, extPortEnd, proto, manageStr);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
- Py_RETURN_TRUE;
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-static PyObject *
-UPnP_getportmappingnumberofentries(UPnPObject *self)
-{
- unsigned int n = 0;
- int r;
-Py_BEGIN_ALLOW_THREADS
- r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
- self->data.first.servicetype,
- &n);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS) {
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("I", n);
-#else
- return Py_BuildValue("i", (int)n);
-#endif
- } else {
- /* TODO: have our own exception type ! */
- PyErr_SetString(PyExc_Exception, strupnperror(r));
- return NULL;
- }
-}
-
-/* GetSpecificPortMapping(ePort, proto, remoteHost='')
- * proto = 'UDP' or 'TCP' */
-static PyObject *
-UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
-{
- char extPort[6];
- unsigned short ePort;
- const char * proto;
- const char * remoteHost = "";
- char intClient[40];
- char intPort[6];
- unsigned short iPort;
- char desc[80];
- char enabled[4];
- char leaseDuration[16];
- if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
- return NULL;
- extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
- desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
-Py_BEGIN_ALLOW_THREADS
- sprintf(extPort, "%hu", ePort);
- UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
- self->data.first.servicetype,
- extPort, proto, remoteHost,
- intClient, intPort,
- desc, enabled, leaseDuration);
-Py_END_ALLOW_THREADS
- if(intClient[0])
- {
- iPort = (unsigned short)atoi(intPort);
- return Py_BuildValue("(s,H,s,O,i)",
- intClient, iPort, desc,
- PyBool_FromLong(atoi(enabled)),
- atoi(leaseDuration));
- }
- else
- {
- Py_RETURN_NONE;
- }
-}
-
-/* GetGenericPortMapping(index) */
-static PyObject *
-UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
-{
- int i, r;
- char index[8];
- char intClient[40];
- char intPort[6];
- unsigned short iPort;
- char extPort[6];
- unsigned short ePort;
- char protocol[4];
- char desc[80];
- char enabled[6];
- char rHost[64];
- char duration[16]; /* lease duration */
- unsigned int dur;
- if(!PyArg_ParseTuple(args, "i", &i))
- return NULL;
-Py_BEGIN_ALLOW_THREADS
- snprintf(index, sizeof(index), "%d", i);
- rHost[0] = '\0'; enabled[0] = '\0';
- duration[0] = '\0'; desc[0] = '\0';
- extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
- r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
- self->data.first.servicetype,
- index,
- extPort, intClient, intPort,
- protocol, desc, enabled, rHost,
- duration);
-Py_END_ALLOW_THREADS
- if(r==UPNPCOMMAND_SUCCESS)
- {
- ePort = (unsigned short)atoi(extPort);
- iPort = (unsigned short)atoi(intPort);
- dur = (unsigned int)strtoul(duration, 0, 0);
-#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
- return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
- ePort, protocol, intClient, iPort,
- desc, enabled, rHost, dur);
-#else
- return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
- (int)ePort, protocol, intClient, (int)iPort,
- desc, enabled, rHost, (int)dur);
-#endif
- }
- else
- {
- Py_RETURN_NONE;
- }
-}
-
-/* miniupnpc.UPnP object Method Table */
-static PyMethodDef UPnP_methods[] = {
- {"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
- "discover UPnP IGD devices on the network"
- },
- {"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
- "select a valid UPnP IGD among discovered devices"
- },
- {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
- "return the total number of bytes sent by UPnP IGD"
- },
- {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
- "return the total number of bytes received by UPnP IGD"
- },
- {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
- "return the total number of packets sent by UPnP IGD"
- },
- {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
- "return the total number of packets received by UPnP IGD"
- },
- {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
- "return status and uptime"
- },
- {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
- "return IGD WAN connection type"
- },
- {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
- "return external IP address"
- },
- {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
- "add a port mapping"
- },
- {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
- "add a port mapping, IGD to select alternative if necessary"
- },
- {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
- "delete a port mapping"
- },
- {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
- "delete a range of port mappings"
- },
- {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
- "-- non standard --"
- },
- {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
- "get details about a specific port mapping entry"
- },
- {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
- "get all details about the port mapping at index"
- },
- {NULL} /* Sentinel */
-};
-
-static PyTypeObject UPnPType = {
- PyVarObject_HEAD_INIT(NULL,
- 0) /*ob_size*/
- "miniupnpc.UPnP", /*tp_name*/
- sizeof(UPnPObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)UPnPObject_dealloc,/*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- "UPnP objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- UPnP_methods, /* tp_methods */
- UPnP_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)UPnP_init, /* tp_init */
- 0, /* tp_alloc */
-#ifndef _WIN32
- PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
-#else
- 0,
-#endif
-};
-
-/* module methods */
-static PyMethodDef miniupnpc_methods[] = {
- {NULL} /* Sentinel */
-};
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "miniupnpc", /* m_name */
- "miniupnpc module.", /* m_doc */
- -1, /* m_size */
- miniupnpc_methods, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear */
- NULL, /* m_free */
-};
-#endif
-
-#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-
-PyMODINIT_FUNC
-#if PY_MAJOR_VERSION >= 3
-PyInit_miniupnpc(void)
-#else
-initminiupnpc(void)
-#endif
-{
- PyObject* m;
-
-#ifdef _WIN32
- /* initialize Winsock. */
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if (nResult != 0)
- {
- /* error code could be WSASYSNOTREADY WSASYSNOTREADY
- * WSASYSNOTREADY WSASYSNOTREADY WSASYSNOTREADY */
-#if PY_MAJOR_VERSION >= 3
- return 0;
-#else
- return;
-#endif
- }
-
- UPnPType.tp_new = PyType_GenericNew;
-#endif
- if (PyType_Ready(&UPnPType) < 0)
-#if PY_MAJOR_VERSION >= 3
- return 0;
-#else
- return;
-#endif
-
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&moduledef);
-#else
- m = Py_InitModule3("miniupnpc", miniupnpc_methods,
- "miniupnpc module.");
-#endif
-
- Py_INCREF(&UPnPType);
- PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
-
-#if PY_MAJOR_VERSION >= 3
- return m;
-#endif
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
index a718cc7bbf..7b3d04074a 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
+++ b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h
@@ -4,7 +4,7 @@
#include "core/version.h"
#define OS_STRING VERSION_NAME "/1.0"
-#define MINIUPNPC_VERSION_STRING "2.1"
+#define MINIUPNPC_VERSION_STRING "2.2.2"
#if 0
/* according to "UPnP Device Architecture 1.0" */
diff --git a/thirdparty/miniupnpc/miniupnpc/miniwget.c b/thirdparty/miniupnpc/miniupnpc/miniwget.c
index 5c135f4efd..d5b7970632 100644
--- a/thirdparty/miniupnpc/miniupnpc/miniwget.c
+++ b/thirdparty/miniupnpc/miniupnpc/miniwget.c
@@ -1,8 +1,8 @@
-/* $Id: miniwget.c,v 1.78 2018/03/13 23:22:18 nanard Exp $ */
+/* $Id: miniwget.c,v 1.82 2020/05/29 21:14:22 nanard Exp $ */
/* Project : miniupnp
- * Website : http://miniupnp.free.fr/
+ * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas Bernard
- * Copyright (c) 2005-2018 Thomas Bernard
+ * Copyright (c) 2005-2020 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -15,7 +15,7 @@
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
-#define snprintf _snprintf
+#include "win32_snprintf.h"
#define socklen_t int
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
@@ -176,11 +176,14 @@ getHTTPResponse(SOCKET s, int * size, int * status_code)
/* Status line
* HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
int sp;
- for(sp = 0; sp < i; sp++)
+ for(sp = 0; sp < i - 1; sp++)
if(header_buf[sp] == ' ')
{
if(*status_code < 0)
- *status_code = atoi(header_buf + sp + 1);
+ {
+ if (header_buf[sp+1] >= '1' && header_buf[sp+1] <= '9')
+ *status_code = atoi(header_buf + sp + 1);
+ }
else
{
#ifdef DEBUG
diff --git a/thirdparty/miniupnpc/miniupnpc/portlistingparse.c b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
index 18d967b877..162cf8b7ec 100644
--- a/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
+++ b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c
@@ -15,7 +15,7 @@
#if defined(__HAIKU__)
/* rename our private function because Haiku already defines a atoui() function */
#define atoui atoui2
-#endif
+#endif
/* list of the elements */
static const struct {
diff --git a/thirdparty/miniupnpc/miniupnpc/receivedata.c b/thirdparty/miniupnpc/miniupnpc/receivedata.c
index 7b9cc5b778..7f187f6e56 100644
--- a/thirdparty/miniupnpc/miniupnpc/receivedata.c
+++ b/thirdparty/miniupnpc/miniupnpc/receivedata.c
@@ -1,8 +1,8 @@
-/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */
+/* $Id: receivedata.c,v 1.10 2021/03/02 23:33:07 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
- * Copyright (c) 2011-2014 Thomas Bernard
+ * Copyright (c) 2011-2021 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@@ -92,7 +92,13 @@ receivedata(SOCKET socket,
#endif /* DEBUG */
if(scope_id)
*scope_id = src_addr6->sin6_scope_id;
+ } else {
+ if(scope_id)
+ *scope_id = 0;
}
+#else /* MINIUPNPC_GET_SRC_ADDR */
+ if(scope_id)
+ *scope_id = 0;
#endif /* MINIUPNPC_GET_SRC_ADDR */
return n;
}
diff --git a/thirdparty/miniupnpc/miniupnpc/upnpc.c b/thirdparty/miniupnpc/miniupnpc/upnpc.c
deleted file mode 100644
index cb7f18b5f6..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnpc.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/* $Id: upnpc.c,v 1.119 2018/03/13 23:34:46 nanard Exp $ */
-/* Project : miniupnp
- * Author : Thomas Bernard
- * Copyright (c) 2005-2020 Thomas Bernard
- * This software is subject to the conditions detailed in the
- * LICENCE file provided in this distribution. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#define snprintf _snprintf
-#else
-/* for IPPROTO_TCP / IPPROTO_UDP */
-#include <netinet/in.h>
-#endif
-#include <ctype.h>
-#include "miniwget.h"
-#include "miniupnpc.h"
-#include "upnpcommands.h"
-#include "portlistingparse.h"
-#include "upnperrors.h"
-#include "miniupnpcstrings.h"
-
-/* protofix() checks if protocol is "UDP" or "TCP"
- * returns NULL if not */
-const char * protofix(const char * proto)
-{
- static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
- static const char proto_udp[4] = { 'U', 'D', 'P', 0};
- int i, b;
- for(i=0, b=1; i<4; i++)
- b = b && ( (proto[i] == proto_tcp[i])
- || (proto[i] == (proto_tcp[i] | 32)) );
- if(b)
- return proto_tcp;
- for(i=0, b=1; i<4; i++)
- b = b && ( (proto[i] == proto_udp[i])
- || (proto[i] == (proto_udp[i] | 32)) );
- if(b)
- return proto_udp;
- return 0;
-}
-
-/* is_int() checks if parameter is an integer or not
- * 1 for integer
- * 0 for not an integer */
-int is_int(char const* s)
-{
- if(s == NULL)
- return 0;
- while(*s) {
- /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
- if(!isdigit(*s))
- return 0;
- s++;
- }
- return 1;
-}
-
-static void DisplayInfos(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- char externalIPAddress[40];
- char connectionType[64];
- char status[64];
- char lastconnerr[64];
- unsigned int uptime = 0;
- unsigned int brUp, brDown;
- time_t timenow, timestarted;
- int r;
- if(UPNP_GetConnectionTypeInfo(urls->controlURL,
- data->first.servicetype,
- connectionType) != UPNPCOMMAND_SUCCESS)
- printf("GetConnectionTypeInfo failed.\n");
- else
- printf("Connection Type : %s\n", connectionType);
- if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
- status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
- printf("GetStatusInfo failed.\n");
- else
- printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
- status, uptime, lastconnerr);
- if(uptime > 0) {
- timenow = time(NULL);
- timestarted = timenow - uptime;
- printf(" Time started : %s", ctime(&timestarted));
- }
- if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
- &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
- printf("GetLinkLayerMaxBitRates failed.\n");
- } else {
- printf("MaxBitRateDown : %u bps", brDown);
- if(brDown >= 1000000) {
- printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
- } else if(brDown >= 1000) {
- printf(" (%u Kbps)", brDown / 1000);
- }
- printf(" MaxBitRateUp %u bps", brUp);
- if(brUp >= 1000000) {
- printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
- } else if(brUp >= 1000) {
- printf(" (%u Kbps)", brUp / 1000);
- }
- printf("\n");
- }
- r = UPNP_GetExternalIPAddress(urls->controlURL,
- data->first.servicetype,
- externalIPAddress);
- if(r != UPNPCOMMAND_SUCCESS) {
- printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
- } else {
- printf("ExternalIPAddress = %s\n", externalIPAddress);
- }
-}
-
-static void GetConnectionStatus(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
- DisplayInfos(urls, data);
- bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
- bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
- packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
- packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
- printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
- printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
-}
-
-static void ListRedirections(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- int r;
- int i = 0;
- char index[6];
- char intClient[40];
- char intPort[6];
- char extPort[6];
- char protocol[4];
- char desc[80];
- char enabled[6];
- char rHost[64];
- char duration[16];
- /*unsigned int num=0;
- UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
- printf("PortMappingNumberOfEntries : %u\n", num);*/
- printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
- do {
- snprintf(index, 6, "%d", i);
- rHost[0] = '\0'; enabled[0] = '\0';
- duration[0] = '\0'; desc[0] = '\0';
- extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
- r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
- data->first.servicetype,
- index,
- extPort, intClient, intPort,
- protocol, desc, enabled,
- rHost, duration);
- if(r==0)
- /*
- printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
- " desc='%s' rHost='%s'\n",
- i, protocol, extPort, intClient, intPort,
- enabled, duration,
- desc, rHost);
- */
- printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
- i, protocol, extPort, intClient, intPort,
- desc, rHost, duration);
- else
- printf("GetGenericPortMappingEntry() returned %d (%s)\n",
- r, strupnperror(r));
- i++;
- } while(r==0);
-}
-
-static void NewListRedirections(struct UPNPUrls * urls,
- struct IGDdatas * data)
-{
- int r;
- int i = 0;
- struct PortMappingParserData pdata;
- struct PortMapping * pm;
-
- memset(&pdata, 0, sizeof(struct PortMappingParserData));
- r = UPNP_GetListOfPortMappings(urls->controlURL,
- data->first.servicetype,
- "0",
- "65535",
- "TCP",
- "1000",
- &pdata);
- if(r == UPNPCOMMAND_SUCCESS)
- {
- printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
- for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
- {
- printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
- i, pm->protocol, pm->externalPort, pm->internalClient,
- pm->internalPort,
- pm->description, pm->remoteHost,
- (unsigned)pm->leaseTime);
- i++;
- }
- FreePortListing(&pdata);
- }
- else
- {
- printf("GetListOfPortMappings() returned %d (%s)\n",
- r, strupnperror(r));
- }
- r = UPNP_GetListOfPortMappings(urls->controlURL,
- data->first.servicetype,
- "0",
- "65535",
- "UDP",
- "1000",
- &pdata);
- if(r == UPNPCOMMAND_SUCCESS)
- {
- for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
- {
- printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
- i, pm->protocol, pm->externalPort, pm->internalClient,
- pm->internalPort,
- pm->description, pm->remoteHost,
- (unsigned)pm->leaseTime);
- i++;
- }
- FreePortListing(&pdata);
- }
- else
- {
- printf("GetListOfPortMappings() returned %d (%s)\n",
- r, strupnperror(r));
- }
-}
-
-/* Test function
- * 1 - get connection type
- * 2 - get extenal ip address
- * 3 - Add port mapping
- * 4 - get this port mapping from the IGD */
-static int SetRedirectAndTest(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * iaddr,
- const char * iport,
- const char * eport,
- const char * proto,
- const char * leaseDuration,
- const char * remoteHost,
- const char * description,
- int addAny)
-{
- char externalIPAddress[40];
- char intClient[40];
- char intPort[6];
- char reservedPort[6];
- char duration[16];
- int r;
-
- if(!iaddr || !iport || !eport || !proto)
- {
- fprintf(stderr, "Wrong arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "invalid protocol\n");
- return -1;
- }
-
- r = UPNP_GetExternalIPAddress(urls->controlURL,
- data->first.servicetype,
- externalIPAddress);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetExternalIPAddress failed.\n");
- else
- printf("ExternalIPAddress = %s\n", externalIPAddress);
-
- if (addAny) {
- r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
- eport, iport, iaddr, description,
- proto, remoteHost, leaseDuration, reservedPort);
- if(r==UPNPCOMMAND_SUCCESS)
- eport = reservedPort;
- else
- printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
- eport, iport, iaddr, r, strupnperror(r));
- } else {
- r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
- eport, iport, iaddr, description,
- proto, remoteHost, leaseDuration);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
- eport, iport, iaddr, r, strupnperror(r));
- return -2;
- }
- }
-
- r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
- data->first.servicetype,
- eport, proto, remoteHost,
- intClient, intPort, NULL/*desc*/,
- NULL/*enabled*/, duration);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
- r, strupnperror(r));
- return -2;
- } else {
- printf("InternalIP:Port = %s:%s\n", intClient, intPort);
- printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
- externalIPAddress, eport, proto, intClient, intPort, duration);
- }
- return 0;
-}
-
-static int
-RemoveRedirect(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * eport,
- const char * proto,
- const char * remoteHost)
-{
- int r;
- if(!proto || !eport)
- {
- fprintf(stderr, "invalid arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "protocol invalid\n");
- return -1;
- }
- r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("UPNP_DeletePortMapping() failed with code : %d\n", r);
- return -2;
- }else {
- printf("UPNP_DeletePortMapping() returned : %d\n", r);
- }
- return 0;
-}
-
-static int
-RemoveRedirectRange(struct UPNPUrls * urls,
- struct IGDdatas * data,
- const char * ePortStart, char const * ePortEnd,
- const char * proto, const char * manage)
-{
- int r;
-
- if (!manage)
- manage = "0";
-
- if(!proto || !ePortStart || !ePortEnd)
- {
- fprintf(stderr, "invalid arguments\n");
- return -1;
- }
- proto = protofix(proto);
- if(!proto)
- {
- fprintf(stderr, "protocol invalid\n");
- return -1;
- }
- r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
- if(r!=UPNPCOMMAND_SUCCESS) {
- printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r);
- return -2;
- }else {
- printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
- }
- return 0;
-}
-
-/* IGD:2, functions for service WANIPv6FirewallControl:1 */
-static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
-{
- unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
- int firewallEnabled = 0, inboundPinholeAllowed = 0;
-
- UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
- printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
- printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
-
- bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
- bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
- packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
- packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
- printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
- printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
-}
-
-/* Test function
- * 1 - Add pinhole
- * 2 - Check if pinhole is working from the IGD side */
-static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * remoteaddr, const char * eport,
- const char * intaddr, const char * iport,
- const char * proto, const char * lease_time)
-{
- char uniqueID[8];
- /*int isWorking = 0;*/
- int r;
- char proto_tmp[8];
-
- if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
- if(atoi(proto) == 0)
- {
- const char * protocol;
- protocol = protofix(proto);
- if(protocol && (strcmp("TCP", protocol) == 0))
- {
- snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
- proto = proto_tmp;
- }
- else if(protocol && (strcmp("UDP", protocol) == 0))
- {
- snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
- proto = proto_tmp;
- }
- else
- {
- fprintf(stderr, "invalid protocol\n");
- return;
- }
- }
- r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
- remoteaddr, eport, intaddr, iport, r, strupnperror(r));
- else
- {
- printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
- remoteaddr, eport, intaddr, iport, uniqueID);
- /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
- }
-}
-
-/* Test function
- * 1 - Check if pinhole is working from the IGD side
- * 2 - Update pinhole */
-static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * uniqueID, const char * lease_time)
-{
- int isWorking = 0;
- int r;
-
- if(!uniqueID || !lease_time)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
- r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- if(isWorking || r==709)
- {
- r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
- printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
- }
-}
-
-/* Test function
- * Get pinhole timeout
- */
-static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
- const char * remoteaddr, const char * eport,
- const char * intaddr, const char * iport,
- const char * proto)
-{
- int timeout = 0;
- int r;
-
- if(!intaddr || !remoteaddr || !iport || !eport || !proto)
- {
- fprintf(stderr, "Wrong arguments\n");
- return;
- }
-
- r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
- intaddr, iport, remoteaddr, eport, r, strupnperror(r));
- else
- printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
-}
-
-static void
-GetPinholePackets(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r, pinholePackets = 0;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
- else
- printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
-}
-
-static void
-CheckPinhole(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r, isWorking = 0;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
- if(r!=UPNPCOMMAND_SUCCESS)
- printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
- else
- printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
-}
-
-static void
-RemovePinhole(struct UPNPUrls * urls,
- struct IGDdatas * data, const char * uniqueID)
-{
- int r;
- if(!uniqueID)
- {
- fprintf(stderr, "invalid arguments\n");
- return;
- }
- r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
- printf("UPNP_DeletePinhole() returned : %d\n", r);
-}
-
-
-/* sample upnp client program */
-int main(int argc, char ** argv)
-{
- char command = 0;
- char ** commandargv = 0;
- int commandargc = 0;
- struct UPNPDev * devlist = 0;
- char lanaddr[64] = "unset"; /* my ip address on the LAN */
- int i;
- const char * rootdescurl = 0;
- const char * multicastif = 0;
- const char * minissdpdpath = 0;
- int localport = UPNP_LOCAL_PORT_ANY;
- int retcode = 0;
- int error = 0;
- int ipv6 = 0;
- unsigned char ttl = 2; /* defaulting to 2 */
- const char * description = 0;
-
-#ifdef _WIN32
- WSADATA wsaData;
- int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
- if(nResult != NO_ERROR)
- {
- fprintf(stderr, "WSAStartup() failed.\n");
- return -1;
- }
-#endif
- printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
- printf(" (c) 2005-2020 Thomas Bernard.\n");
- printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
- "for more information.\n");
- /* command line processing */
- for(i=1; i<argc; i++)
- {
- if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
- {
- command = 0;
- break;
- }
- if(argv[i][0] == '-')
- {
- if(argv[i][1] == 'u')
- rootdescurl = argv[++i];
- else if(argv[i][1] == 'm')
- {
- multicastif = argv[++i];
- minissdpdpath = ""; /* Disable usage of minissdpd */
- }
- else if(argv[i][1] == 'z')
- {
- char junk;
- if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
- localport<0 || localport>65535 ||
- (localport >1 && localport < 1024))
- {
- fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
- localport = UPNP_LOCAL_PORT_ANY;
- break;
- }
- }
- else if(argv[i][1] == 'p')
- minissdpdpath = argv[++i];
- else if(argv[i][1] == '6')
- ipv6 = 1;
- else if(argv[i][1] == 'e')
- description = argv[++i];
- else if(argv[i][1] == 't')
- ttl = (unsigned char)atoi(argv[++i]);
- else
- {
- command = argv[i][1];
- i++;
- commandargv = argv + i;
- commandargc = argc - i;
- break;
- }
- }
- else
- {
- fprintf(stderr, "option '%s' invalid\n", argv[i]);
- }
- }
-
- if(!command
- || (command == 'a' && commandargc<4)
- || (command == 'd' && argc<2)
- || (command == 'r' && argc<2)
- || (command == 'A' && commandargc<6)
- || (command == 'U' && commandargc<2)
- || (command == 'D' && commandargc<1))
- {
- fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration] [remote host]\n\t\tAdd port redirection\n", argv[0]);
- fprintf(stderr, " \t%s [options] -d external_port protocol [remote host]\n\t\tDelete port redirection\n", argv[0]);
- fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
- fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
- fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration] [remote host]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
- fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
- fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
- fprintf(stderr, "\nprotocol is UDP or TCP\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -e description : set description for port mapping.\n");
- fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
- fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
- fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
- fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
- fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
- fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
- return 1;
- }
-
- if( rootdescurl
- || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
- localport, ipv6, ttl, &error)))
- {
- struct UPNPDev * device;
- struct UPNPUrls urls;
- struct IGDdatas data;
- if(devlist)
- {
- printf("List of UPNP devices found on the network :\n");
- for(device = devlist; device; device = device->pNext)
- {
- printf(" desc: %s\n st: %s\n\n",
- device->descURL, device->st);
- }
- }
- else if(!rootdescurl)
- {
- printf("upnpDiscover() error code=%d\n", error);
- }
- i = 1;
- if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
- || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
- {
- switch(i) {
- case 1:
- printf("Found valid IGD : %s\n", urls.controlURL);
- break;
- case 2:
- printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- break;
- case 3:
- printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- break;
- default:
- printf("Found device (igd ?) : %s\n", urls.controlURL);
- printf("Trying to continue anyway\n");
- }
- printf("Local LAN ip address : %s\n", lanaddr);
- #if 0
- printf("getting \"%s\"\n", urls.ipcondescURL);
- descXML = miniwget(urls.ipcondescURL, &descXMLsize);
- if(descXML)
- {
- /*fwrite(descXML, 1, descXMLsize, stdout);*/
- free(descXML); descXML = NULL;
- }
- #endif
-
- switch(command)
- {
- case 'l':
- DisplayInfos(&urls, &data);
- ListRedirections(&urls, &data);
- break;
- case 'L':
- NewListRedirections(&urls, &data);
- break;
- case 'a':
- if (SetRedirectAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- (commandargc > 4)&is_int(commandargv[4])?commandargv[4]:"0",
- (commandargc > 4)&!is_int(commandargv[4])?commandargv[4]:(commandargc > 5)?commandargv[5]:NULL,
- description, 0) < 0)
- retcode = 2;
- break;
- case 'd':
- if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
- commandargc > 2 ? commandargv[2] : NULL) < 0)
- retcode = 2;
- break;
- case 'n': /* aNy */
- if (SetRedirectAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- (commandargc > 4)&is_int(commandargv[4])?commandargv[4]:"0",
- (commandargc > 4)&!is_int(commandargv[4])?commandargv[4]:(commandargc > 5)?commandargv[5]:NULL,
- description, 1) < 0)
- retcode = 2;
- break;
- case 'N':
- if (commandargc < 3)
- fprintf(stderr, "too few arguments\n");
-
- if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
- commandargc > 3 ? commandargv[3] : NULL) < 0)
- retcode = 2;
- break;
- case 's':
- GetConnectionStatus(&urls, &data);
- break;
- case 'r':
- i = 0;
- while(i<commandargc)
- {
- if(!is_int(commandargv[i])) {
- /* 1st parameter not an integer : error */
- fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
- retcode = 1;
- break;
- } else if(is_int(commandargv[i+1])){
- /* 2nd parameter is an integer : <port> <external_port> <protocol> */
- if (SetRedirectAndTest(&urls, &data,
- lanaddr, commandargv[i],
- commandargv[i+1], commandargv[i+2], "0", NULL,
- description, 0) < 0)
- retcode = 2;
- i+=3; /* 3 parameters parsed */
- } else {
- /* 2nd parameter not an integer : <port> <protocol> */
- if (SetRedirectAndTest(&urls, &data,
- lanaddr, commandargv[i],
- commandargv[i], commandargv[i+1], "0", NULL,
- description, 0) < 0)
- retcode = 2;
- i+=2; /* 2 parameters parsed */
- }
- }
- break;
- case 'A':
- SetPinholeAndTest(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- commandargv[4], commandargv[5]);
- break;
- case 'U':
- GetPinholeAndUpdate(&urls, &data,
- commandargv[0], commandargv[1]);
- break;
- case 'C':
- for(i=0; i<commandargc; i++)
- {
- CheckPinhole(&urls, &data, commandargv[i]);
- }
- break;
- case 'K':
- for(i=0; i<commandargc; i++)
- {
- GetPinholePackets(&urls, &data, commandargv[i]);
- }
- break;
- case 'D':
- for(i=0; i<commandargc; i++)
- {
- RemovePinhole(&urls, &data, commandargv[i]);
- }
- break;
- case 'S':
- GetFirewallStatus(&urls, &data);
- break;
- case 'G':
- GetPinholeOutboundTimeout(&urls, &data,
- commandargv[0], commandargv[1],
- commandargv[2], commandargv[3],
- commandargv[4]);
- break;
- case 'P':
- printf("Presentation URL found:\n");
- printf(" %s\n", data.presentationurl);
- break;
- default:
- fprintf(stderr, "Unknown switch -%c\n", command);
- retcode = 1;
- }
-
- FreeUPNPUrls(&urls);
- }
- else
- {
- fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
- retcode = 1;
- }
- freeUPNPDevlist(devlist); devlist = 0;
- }
- else
- {
- fprintf(stderr, "No IGD UPnP Device found on the network !\n");
- retcode = 1;
- }
-#ifdef _WIN32
- nResult = WSACleanup();
- if(nResult != NO_ERROR) {
- fprintf(stderr, "WSACleanup() failed.\n");
- }
-#endif /* _WIN32 */
- return retcode;
-}
-
diff --git a/thirdparty/miniupnpc/miniupnpc/upnpdev.h b/thirdparty/miniupnpc/miniupnpc/upnpdev.h
index f4ae174426..9b2cb431ba 100644
--- a/thirdparty/miniupnpc/miniupnpc/upnpdev.h
+++ b/thirdparty/miniupnpc/miniupnpc/upnpdev.h
@@ -1,8 +1,8 @@
-/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* $Id: upnpdev.h,v 1.3 2020/05/29 15:57:42 nanard Exp $ */
/* Project : miniupnp
- * Web : http://miniupnp.free.fr/
+ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
- * copyright (c) 2005-2018 Thomas Bernard
+ * copyright (c) 2005-2020 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
@@ -20,7 +20,15 @@ struct UPNPDev {
char * st;
char * usn;
unsigned int scope_id;
- char buffer[3];
+#if defined(__STDC_VERSION) && __STDC_VERSION__ >= 199901L
+ /* C99 flexible array member */
+ char buffer[];
+#elif defined(__GNUC__)
+ char buffer[0];
+#else
+ /* Fallback to a hack */
+ char buffer[1];
+#endif
};
/* freeUPNPDevlist()
diff --git a/thirdparty/miniupnpc/miniupnpc/upnperrors.c b/thirdparty/miniupnpc/miniupnpc/upnperrors.c
deleted file mode 100644
index 4496e8622c..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnperrors.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id: upnperrors.c,v 1.10 2019/08/24 08:49:53 nanard Exp $ */
-/* vim: tabstop=4 shiftwidth=4 noexpandtab
- * Project : miniupnp
- * Author : Thomas BERNARD
- * copyright (c) 2007-2019 Thomas Bernard
- * All Right reserved.
- * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#include <string.h>
-#include "upnperrors.h"
-#include "upnpcommands.h"
-#include "miniupnpc.h"
-
-const char * strupnperror(int err)
-{
- const char * s = NULL;
- switch(err) {
- case UPNPCOMMAND_SUCCESS:
- s = "Success";
- break;
- case UPNPCOMMAND_UNKNOWN_ERROR:
- s = "Miniupnpc Unknown Error";
- break;
- case UPNPCOMMAND_INVALID_ARGS:
- s = "Miniupnpc Invalid Arguments";
- break;
- case UPNPCOMMAND_INVALID_RESPONSE:
- s = "Miniupnpc Invalid response";
- break;
- case UPNPCOMMAND_HTTP_ERROR:
- s = "Miniupnpc HTTP error";
- break;
- case UPNPDISCOVER_SOCKET_ERROR:
- s = "Miniupnpc Socket error";
- break;
- case UPNPDISCOVER_MEMORY_ERROR:
- case UPNPCOMMAND_MEM_ALLOC_ERROR:
- s = "Miniupnpc Memory allocation error";
- break;
- case 401:
- s = "Invalid Action";
- break;
- case 402:
- s = "Invalid Args";
- break;
- case 501:
- s = "Action Failed";
- break;
- case 606:
- s = "Action not authorized";
- break;
- case 701:
- s = "PinholeSpaceExhausted";
- break;
- case 702:
- s = "FirewallDisabled";
- break;
- case 703:
- s = "InboundPinholeNotAllowed";
- break;
- case 704:
- s = "NoSuchEntry";
- break;
- case 705:
- s = "ProtocolNotSupported";
- break;
- case 706:
- s = "InternalPortWildcardingNotAllowed";
- break;
- case 707:
- s = "ProtocolWildcardingNotAllowed";
- break;
- case 708:
- s = "InvalidLayer2Address";
- break;
- case 709:
- s = "NoPacketSent";
- break;
- case 713:
- s = "SpecifiedArrayIndexInvalid";
- break;
- case 714:
- s = "NoSuchEntryInArray";
- break;
- case 715:
- s = "WildCardNotPermittedInSrcIP";
- break;
- case 716:
- s = "WildCardNotPermittedInExtPort";
- break;
- case 718:
- s = "ConflictInMappingEntry";
- break;
- case 724:
- s = "SamePortValuesRequired";
- break;
- case 725:
- s = "OnlyPermanentLeasesSupported";
- break;
- case 726:
- s = "RemoteHostOnlySupportsWildcard";
- break;
- case 727:
- s = "ExternalPortOnlySupportsWildcard";
- break;
- default:
- s = "UnknownError";
- break;
- }
- return s;
-}
diff --git a/thirdparty/miniupnpc/miniupnpc/upnperrors.h b/thirdparty/miniupnpc/miniupnpc/upnperrors.h
deleted file mode 100644
index 8499d9a1c9..0000000000
--- a/thirdparty/miniupnpc/miniupnpc/upnperrors.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
-/* (c) 2007-2015 Thomas Bernard
- * All rights reserved.
- * MiniUPnP Project.
- * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * This software is subjet to the conditions detailed in the
- * provided LICENCE file. */
-#ifndef UPNPERRORS_H_INCLUDED
-#define UPNPERRORS_H_INCLUDED
-
-#include "miniupnpc_declspec.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* strupnperror()
- * Return a string description of the UPnP error code
- * or NULL for undefinded errors */
-MINIUPNP_LIBSPEC const char * strupnperror(int err);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h b/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h
new file mode 100644
index 0000000000..1fc284ecff
--- /dev/null
+++ b/thirdparty/miniupnpc/miniupnpc/win32_snprintf.h
@@ -0,0 +1,71 @@
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * MiniUPnP project
+ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
+ * (c) 2020 Pali Rohár
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution */
+
+#ifndef WIN32_SNPRINTF_H
+#define WIN32_SNPRINTF_H
+
+#ifdef _WIN32
+
+#include <stdio.h>
+
+/* snprintf is supported by:
+ * - Visual Studio 2015 or new
+ * - mingw32 with iso c ext
+ * - mingw-w64 with ansi stdio
+ * - mingw-w64 6.0.0 or new with ucrt
+ * - mingw-w64 8.0.0 or new with iso c ext
+ */
+#if ( \
+ (defined(_MSC_VER) && _MSC_VER < 1900) /* Visual Studio older than 2015 */ || \
+ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__NO_ISOCEXT)) /* mingw32 without iso c ext */ || \
+ (defined(__MINGW64_VERSION_MAJOR) && /* mingw-w64 not ... */ !( \
+ (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0)) /* ... with ansi stdio */ || \
+ (__MINGW64_VERSION_MAJOR >= 6 && defined(_UCRT)) /* ... at least 6.0.0 with ucrt */ || \
+ (__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT)) /* ... at least 8.0.0 with iso c ext */ || \
+ 0) || \
+0)
+
+/* _scprintf is supported by:
+ * - Visual Studio 2002 or new
+ * - msvcr70.dll or new
+ * - msvcrt.dll on Windows XP or new
+ */
+#if ( \
+ (defined(_MSC_VER) && _MSC_VER < 1300) /* Visual Studio older than 2002 */ || \
+ (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x700) /* msvcrt older than 7.0 */ || \
+0)
+#define CHECK_SCPRINTF 0
+#define IF_SCPRINTF(expr) 0
+#define ELSE_SCPRINTF(expr) expr
+#else
+#define CHECK_SCPRINTF 1
+#define IF_SCPRINTF(expr) expr
+#define ELSE_SCPRINTF(expr) 0
+#endif
+
+/* Emulation of snprintf for win32 */
+#define snprintf(buf, size, fmt, ...) ( \
+ (((size) != 0 && (buf) != NULL) ? ( /* _snprintf does not work with NULL buffer */ \
+ _snprintf((buf), (size), (fmt), __VA_ARGS__), /* _snprintf returns -1 on overflow, so ignore its value */ \
+ (((char *)buf)[(size_t)(size)-1] = 0), /* _snprintf does not fill nul byte on overflow */ \
+ 0) : 0), \
+ (CHECK_SCPRINTF ? IF_SCPRINTF( \
+ _scprintf((fmt), __VA_ARGS__) /* calculate return value for snprintf via _scprintf */ \
+ ) : ELSE_SCPRINTF( \
+ ((size) != 0 && (buf) != NULL) ? \
+ strlen((buf)) /* return just length of buffer */ \
+ : \
+ 1 /* no buffer, impossible to calculate, return just non-zero number */ \
+ ) \
+ ) \
+)
+
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* WIN32_SNPRINTF_H */
diff --git a/thirdparty/miniupnpc/windows_fix.diff b/thirdparty/miniupnpc/windows_fix.diff
deleted file mode 100644
index 460b596888..0000000000
--- a/thirdparty/miniupnpc/windows_fix.diff
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-index 29f8110155..ea9af02e1f 100644
---- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-+++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
-@@ -683,11 +683,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
- #endif
- } else {
- struct in_addr mc_if;
--#if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
-- InetPtonA(AF_INET, multicastif, &mc_if);
--#else
- mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
--#endif
- if(mc_if.s_addr != INADDR_NONE)
- {
- ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;